From a2791d843e1ec1d1a32810fadbb20cb3f9038fdd Mon Sep 17 00:00:00 2001 From: "laurence.muller" Date: Thu, 6 Nov 2008 23:27:06 +0000 Subject: [PATCH] Using standard SVN folder structure git-svn-id: http://pcsx2.googlecode.com/svn/trunk@398 96395faa-99c1-11dd-bbfe-3dabce05a288 --- INSTALL | 87 + bin/.pixmaps/pcsxAbout.bmp | Bin 0 -> 251192 bytes bin/A39517AB.xml | 183 + bin/Langs/ar_AR/LC_MESSAGES/pcsx2.mo | Bin 0 -> 6197 bytes bin/Langs/bg_BG/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11915 bytes bin/Langs/cz_CZ/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11085 bytes bin/Langs/de_DE/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11840 bytes bin/Langs/du_DU/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11583 bytes bin/Langs/el_EL/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11225 bytes bin/Langs/es_ES/LC_MESSAGES/pcsx2.mo | Bin 0 -> 10632 bytes bin/Langs/fr_FR/LC_MESSAGES/pcsx2.mo | Bin 0 -> 6176 bytes bin/Langs/hb_HB/LC_MESSAGES/pcsx2.mo | Bin 0 -> 6302 bytes bin/Langs/it_IT/LC_MESSAGES/pcsx2.mo | Bin 0 -> 5411 bytes bin/Langs/ja_JA/LC_MESSAGES/pcsx2.mo | Bin 0 -> 15213 bytes bin/Langs/pe_PE/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11165 bytes bin/Langs/pl_PL/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11183 bytes bin/Langs/po_BR/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11024 bytes bin/Langs/po_PO/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11385 bytes bin/Langs/ro_RO/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11443 bytes bin/Langs/ru_RU/LC_MESSAGES/pcsx2.mo | Bin 0 -> 11125 bytes bin/Langs/sh_SH/LC_MESSAGES/pcsx2.mo | Bin 0 -> 9723 bytes bin/Langs/sw_SW/LC_MESSAGES/other.po | 868 + bin/Langs/sw_SW/LC_MESSAGES/pcsx2.mo | Bin 0 -> 10929 bytes bin/Langs/tc_TC/LC_MESSAGES/Pcsx2.mo | Bin 0 -> 9723 bytes bin/Langs/tr_TR/LC_MESSAGES/pcsx2.mo | Bin 0 -> 10871 bytes bin/compat_list/compat_list.html | 27266 ++++++++++++++++ bin/compat_list/h_console.jpg | Bin 0 -> 544 bytes bin/compat_list/h_region.jpg | Bin 0 -> 486 bytes bin/compat_list/h_serial.jpg | Bin 0 -> 477 bytes bin/compat_list/h_status.jpg | Bin 0 -> 518 bytes bin/compat_list/h_title.jpg | Bin 0 -> 455 bytes bin/compat_list/h_version.jpg | Bin 0 -> 511 bytes bin/compat_list/sq_ingame.jpg | Bin 0 -> 304 bytes bin/compat_list/sq_intro.jpg | Bin 0 -> 305 bytes bin/compat_list/sq_menus.jpg | Bin 0 -> 305 bytes bin/compat_list/sq_nothing.jpg | Bin 0 -> 305 bytes bin/compat_list/sq_playable.jpg | Bin 0 -> 304 bytes bin/patches/013E349D.pnach | 4 + bin/patches/015314A2.pnach | 4 + bin/patches/034836F8.pnach | 13 + bin/patches/0442B1BD.pnach | 4 + bin/patches/05177ECE.pnach | 4 + bin/patches/0518D274.pnach | 4 + bin/patches/0518D275.pnach | 4 + bin/patches/06DE61E0.pnach | 4 + bin/patches/07AD79C9.pnach | 4 + bin/patches/0838D766.pnach | 6 + bin/patches/086273D2.pnach | 4 + bin/patches/08901101.pnach | 13 + bin/patches/08FB9DCF.pnach | 9 + bin/patches/0999F9DB.pnach | 13 + bin/patches/09D35D3F.pnach | 4 + bin/patches/0A342A88.pnach | 4 + bin/patches/0B359BBF.pnach | 5 + bin/patches/0C370E94.pnach | 4 + bin/patches/0F6B6315.pnach | 5 + bin/patches/1025D50A.pnach | 7 + bin/patches/116154AD.pnach | 8 + bin/patches/1248FE3A.pnach | 6 + bin/patches/129C8600.pnach | 8 + bin/patches/12AFF4D4.pnach | 23 + bin/patches/1468C474.pnach | 4 + bin/patches/1510E1D1.pnach | 7 + bin/patches/1629D655.pnach | 20 + bin/patches/163F0461.pnach | 18 + bin/patches/1738A5B0.pnach | 13 + bin/patches/19D145D7.pnach | 12 + bin/patches/1CAC8A56.pnach | 4 + bin/patches/1D2818AF.pnach | 13 + bin/patches/200BC0E6.pnach | 4 + bin/patches/2088950A.pnach | 4 + bin/patches/21068223.pnach | 5 + bin/patches/2251E14D.pnach | 4 + bin/patches/22C36E63.pnach | 4 + bin/patches/25433CBD.pnach | 9 + bin/patches/27E54B37.pnach | 16 + bin/patches/280DAC56.pnach | 16 + bin/patches/295D2F96.pnach | 6 + bin/patches/29D80A23.pnach | 9 + bin/patches/2B2E1535.pnach | 5 + bin/patches/2C728173.pnach | 4 + bin/patches/2CFFFA50.pnach | 9 + bin/patches/2D919421.pnach | 15 + bin/patches/2F56CBC9.pnach | 4 + bin/patches/302797DF.pnach | 5 + bin/patches/304C115C.pnach | 4 + bin/patches/32629F36.pnach | 9 + bin/patches/333F1F59.pnach | 3 + bin/patches/337B927C.pnach | 4 + bin/patches/339A0B8C.pnach | 4 + bin/patches/33F7D21A.pnach | 14 + bin/patches/36FEEE3A.pnach | 19 + bin/patches/37BA81B1.pnach | 4 + bin/patches/37C07E96.pnach | 3 + bin/patches/38F29E28.pnach | 4 + bin/patches/3BD85DA4.pnach | 7 + bin/patches/3CFE3B37.pnach | 6 + bin/patches/3DB65A75.pnach | 5 + bin/patches/3E0A256D.pnach | 4 + bin/patches/3E68955A.pnach | 5 + bin/patches/3EAD47FE.pnach | 4 + bin/patches/3F0452DE.pnach | 4 + bin/patches/3FB69323.pnach | 8 + bin/patches/4043F228.pnach | 4 + bin/patches/41A3191C.pnach | 4 + bin/patches/4321A427.pnach | 5 + bin/patches/4334E17D.pnach | 4 + bin/patches/44A61C8F.pnach | 4 + bin/patches/4691F6F7.pnach | 4 + bin/patches/46A7ECA4.pnach | 4 + bin/patches/472C9E70.pnach | 6 + bin/patches/48FE0C71.pnach | 20 + bin/patches/49DA19CE.pnach | 4 + bin/patches/4B6DDB6B.pnach | 3 + bin/patches/4C0C821D.pnach | 4 + bin/patches/4C4D7072.pnach | 11 + bin/patches/4C9EE7DF.pnach | 20 + bin/patches/4D228733.pnach | 5 + bin/patches/4D6DBB75.pnach | 4 + bin/patches/4DAC50C2.pnach | 5 + bin/patches/4F3D3CF0.pnach | 5 + bin/patches/506644B3.pnach | 5 + bin/patches/512B5046.pnach | 3 + bin/patches/5162BCCA.pnach | 5 + bin/patches/51D8A6A9.pnach | 20 + bin/patches/51F91783.pnach | 4 + bin/patches/53A803AF.pnach | 4 + bin/patches/53DF159B.pnach | 16 + bin/patches/54A548B4.pnach | 6 + bin/patches/54AD76D7.pnach | 8 + bin/patches/54D6BEE3.pnach | 4 + bin/patches/561BE340.pnach | 4 + bin/patches/582EED0D.pnach | 8 + bin/patches/586EA828.pnach | 7 + bin/patches/58EE1AFA.pnach | 4 + bin/patches/5A7635C1.pnach | 4 + bin/patches/5BBC2F40.pnach | 20 + bin/patches/5BC8C9E8.pnach | 3 + bin/patches/5BE3F481.pnach | 4 + bin/patches/5CCA0737.pnach | 7 + bin/patches/5D67AE48.pnach | 4 + bin/patches/5DFBE144.pnach | 8 + bin/patches/5E115FB6.pnach | 3 + bin/patches/5EB127E7.pnach | 4 + bin/patches/5F2A0E36.pnach | 7 + bin/patches/60013EBD.pnach | 5 + bin/patches/60FA8C69.pnach | 4 + bin/patches/6175FE7D.pnach | 4 + bin/patches/624F11F1.pnach | 5 + bin/patches/625AF967.pnach | 4 + bin/patches/627B8252.pnach | 9 + bin/patches/62F6F886.pnach | 4 + bin/patches/63F6B523.pnach | 4 + bin/patches/68EAF48F.pnach | 8 + bin/patches/6926B199.pnach | 4 + bin/patches/692CBA8E.pnach | 4 + bin/patches/6A4EFE60.pnach | 4 + bin/patches/6ADBC24B.pnach | 6 + bin/patches/6BA2F6B9.pnach | 4 + bin/patches/6D70F0E0.pnach | 4 + bin/patches/6EA9DDA9.pnach | 4 + bin/patches/6FB69282.pnach | 3 + bin/patches/7098BE76.pnach | 6 + bin/patches/7130C553.pnach | 5 + bin/patches/71584BAC.pnach | 4 + bin/patches/722BBD62.pnach | 4 + bin/patches/7377BC6F.pnach | 4 + bin/patches/763D3BF9.pnach | 8 + bin/patches/77ECAAA0.pnach | 4 + bin/patches/78168525.pnach | 3 + bin/patches/789D6B71.pnach | 4 + bin/patches/78E20421.pnach | 7 + bin/patches/7ABDBB5E.pnach | 4 + bin/patches/7BA0128E.pnach | 3 + bin/patches/7CD1CDCD.pnach | 12 + bin/patches/7D8F539A.pnach | 7 + bin/patches/7EBEEBBD.pnach | 4 + bin/patches/7F6319C7.pnach | 4 + bin/patches/7FD7A1B9.pnach | 8 + bin/patches/83261085.pnach | 15 + bin/patches/83D0CE43.pnach | 7 + bin/patches/844B58EE.pnach | 4 + bin/patches/848C6247.pnach | 3 + bin/patches/85AE91B3.pnach | 5 + bin/patches/85E92C92.pnach | 9 + bin/patches/8BC79F96.pnach | 9 + bin/patches/8BC95883.pnach | 4 + bin/patches/8BE3D7B2.pnach | 4 + bin/patches/8DC64680.pnach | 30 + bin/patches/8FDE8E16.pnach | 6 + bin/patches/901AAC09.pnach | 4 + bin/patches/93223BE4.pnach | 7 + bin/patches/934F9081.pnach | 4 + bin/patches/93F8A60B.pnach | 4 + bin/patches/941BB7D9.pnach | 29 + bin/patches/94C56923.pnach | 4 + bin/patches/950241D3.pnach | 4 + bin/patches/951555A0.pnach | 4 + bin/patches/95BB1901.pnach | 3 + bin/patches/96B2F56D.pnach | 7 + bin/patches/96B76E56.pnach | 9 + bin/patches/96C20D6F.pnach | 4 + bin/patches/9AAC5309.pnach | 4 + bin/patches/9AAC530D.pnach | 6 + bin/patches/9AC65D6A.pnach | 4 + bin/patches/9B1EE9EB.pnach | 4 + bin/patches/9BE3F92D.pnach | 4 + bin/patches/9D6F46F0.pnach | 4 + bin/patches/A029B109.pnach | 12 + bin/patches/A1B752C7.pnach | 4 + bin/patches/A36CFF6C.pnach | 3 + bin/patches/A39517AB.pnach | 16 + bin/patches/A3ACF3C7.pnach | 8 + bin/patches/A3D63039.pnach | 2 + bin/patches/A4E2C043.pnach | 8 + bin/patches/A5BF36A8.pnach | 3 + bin/patches/A63C896C.pnach | 6 + bin/patches/A719D130.pnach | 4 + bin/patches/A74F99CD.pnach | 4 + bin/patches/A7A2F7C5.pnach | 16 + bin/patches/A8083AE6.pnach | 4 + bin/patches/A88ACA28.pnach | 9 + bin/patches/A8A76AAC.pnach | 4 + bin/patches/A929A697.pnach | 3 + bin/patches/A9759015.pnach | 9 + bin/patches/AA31B5BF.pnach | 4 + bin/patches/AC7E88D9.pnach | 18 + bin/patches/ACB1989A.pnach | 10 + bin/patches/AD9D2B54.pnach | 4 + bin/patches/ADAA1256.pnach | 8 + bin/patches/AE0E098F.pnach | 6 + bin/patches/AE3EAA05.pnach | 14 + bin/patches/AE9EB9A0.pnach | 4 + bin/patches/AEDAEE99.pnach | 3 + bin/patches/AFAC88EF.pnach | 14 + bin/patches/B0621C55.pnach | 4 + bin/patches/B0AE1898.pnach | 6 + bin/patches/B130E5BA.pnach | 3 + bin/patches/B1BE3E51.pnach | 6 + bin/patches/B234036E.pnach | 4 + bin/patches/B2BDE9F3.pnach | 6 + bin/patches/B338676A.pnach | 6 + bin/patches/B34DA141.pnach | 8 + bin/patches/B36EE21E.pnach | 5 + bin/patches/B590CE04.pnach | 5 + bin/patches/B82E4C4B.pnach | 4 + bin/patches/B884B6E9.pnach | 4 + bin/patches/B99379B7.pnach | 4 + bin/patches/BB3D833A.pnach | 4 + bin/patches/BD3DBCF9.pnach | 4 + bin/patches/BF5D9AEC.pnach | 4 + bin/patches/C04FB5FD.pnach | 4 + bin/patches/C0D6A139.pnach | 4 + bin/patches/C1625F14.pnach | 9 + bin/patches/C1767D64.pnach | 5 + bin/patches/C1B141D6.pnach | 7 + bin/patches/C220951A.pnach | 5 + bin/patches/C398F477.pnach | 4 + bin/patches/C3D28EB9.pnach | 4 + bin/patches/C4467D30.pnach | 4 + bin/patches/C488EC04.pnach | 8 + bin/patches/C4A60986.pnach | 4 + bin/patches/C502AD6E.pnach | 8 + bin/patches/C5DEFEA0.pnach | 7 + bin/patches/C9246E9C.pnach | 4 + bin/patches/C9C145BF.pnach | 10 + bin/patches/CA295E61.pnach | 4 + bin/patches/CA6243B9.pnach | 9 + bin/patches/CB4EBD11.pnach | 7 + bin/patches/CBBC2E7F.pnach | 15 + bin/patches/CC4B9CDE.pnach | 6 + bin/patches/CC6AA742.pnach | 4 + bin/patches/CDE7C999.pnach | 22 + bin/patches/CF11CD83.pnach | 6 + bin/patches/CFB873AD.pnach | 6 + bin/patches/D03BEF2A.pnach | 13 + bin/patches/D08648B6.pnach | 3 + bin/patches/D0E17D26.pnach | 4 + bin/patches/D1ACD489.pnach | 5 + bin/patches/D4781770.pnach | 6 + bin/patches/D48A92E1.pnach | 10 + bin/patches/D4FB6049.pnach | 3 + bin/patches/D79F697A.pnach | 4 + bin/patches/DA0535FD.pnach | 4 + bin/patches/DAC14B26.pnach | 7 + bin/patches/DB719F5C.pnach | 7 + bin/patches/DC85FC8F.pnach | 4 + bin/patches/DCC4EEEA.pnach | 10 + bin/patches/DDA2FA6A.pnach | 4 + bin/patches/DEFA4763.pnach | 5 + bin/patches/E0127F2D.pnach | 5 + bin/patches/E0426FC6.pnach | 8 + bin/patches/E0DADD1A.pnach | 5 + bin/patches/E138094A.pnach | 7 + bin/patches/E1C5F607.pnach | 6 + bin/patches/E1FD9A2D.pnach | 6 + bin/patches/E2F1DB6B.pnach | 6 + bin/patches/E4A275B2.pnach | 4 + bin/patches/E677B8F1.pnach | 7 + bin/patches/E7A35274.pnach | 4 + bin/patches/E906EA37.pnach | 7 + bin/patches/EAD76247.pnach | 19 + bin/patches/EADE437E.pnach | 4 + bin/patches/EDD7E0FF.pnach | 4 + bin/patches/EE838B5C.pnach | 7 + bin/patches/EEC3B310.pnach | 9 + bin/patches/EEE2F6A3.pnach | 4 + bin/patches/EF5B6AAD.pnach | 4 + bin/patches/EF9E43EF.pnach | 5 + bin/patches/F1370E83.pnach | 4 + bin/patches/F22CDDAF.pnach | 4 + bin/patches/F266B00B.pnach | 4 + bin/patches/F4992CC1.pnach | 4 + bin/patches/F52FB2BE.pnach | 5 + bin/patches/F56C7948.pnach | 4 + bin/patches/F5C7B45F.pnach | 4 + bin/patches/F6DC728D.pnach | 5 + bin/patches/F6F9A91D.pnach | 4 + bin/patches/F758234F.pnach | 7 + bin/patches/F9E575D0.pnach | 4 + bin/patches/FA7E3081.pnach | 7 + bin/patches/FAC64195.pnach | 3 + bin/patches/FB0E6D72.pnach | 6 + bin/patches/FC618D82.pnach | 8 + bin/patches/FEA030CB.pnach | 23 + bin/patches/FF920E90.pnach | 8 + bin/patches/default.xml | 0 build.sh | 29 + fps2bios/FP2BLOGO | Bin 0 -> 256016 bytes fps2bios/IOPBTCONF | 27 + fps2bios/Makefile | 57 + fps2bios/doc/overview.doc | Bin 0 -> 144896 bytes fps2bios/fps2blogo.bmp | Bin 0 -> 192054 bytes fps2bios/intro/Makefile | 57 + fps2bios/intro/crt0.s | 111 + fps2bios/intro/eedebug.c | 31 + fps2bios/intro/include/eedebug.h | 12 + fps2bios/intro/include/romdir.h | 20 + fps2bios/intro/intro.c | 19 + fps2bios/intro/linkfile | 52 + fps2bios/intro/romdir.c | 43 + fps2bios/kernel/Makefile | 73 + fps2bios/kernel/eeload/Makefile | 61 + fps2bios/kernel/eeload/eedata.c | 198 + fps2bios/kernel/eeload/eedebug.c | 31 + fps2bios/kernel/eeload/eeelf.c | 423 + fps2bios/kernel/eeload/eeinit.c | 511 + fps2bios/kernel/eeload/eeirq.c | 336 + fps2bios/kernel/eeload/eekernel.c | 3619 ++ fps2bios/kernel/eeload/eeload.c | 34 + fps2bios/kernel/eeload/eeload.map | 1008 + fps2bios/kernel/eeload/include/eedebug.h | 12 + fps2bios/kernel/eeload/include/eeelf.h | 6 + fps2bios/kernel/eeload/include/eeinit.h | 8 + fps2bios/kernel/eeload/include/eeirq.h | 17 + fps2bios/kernel/eeload/include/eekernel.h | 447 + fps2bios/kernel/eeload/include/eeload.h | 4 + fps2bios/kernel/eeload/include/romdir.h | 20 + fps2bios/kernel/eeload/linkfile | 56 + fps2bios/kernel/eeload/romdir.c | 47 + fps2bios/kernel/eestart.c | 50 + fps2bios/kernel/iopload/Makefile | 67 + fps2bios/kernel/iopload/dmacman/Makefile | 60 + fps2bios/kernel/iopload/dmacman/dmacman.c | 923 + fps2bios/kernel/iopload/excepman/Makefile | 60 + fps2bios/kernel/iopload/excepman/ex_handler.s | 16 + fps2bios/kernel/iopload/excepman/excepman.c | 339 + fps2bios/kernel/iopload/heaplib/Makefile | 59 + fps2bios/kernel/iopload/heaplib/heaplib.c | 206 + fps2bios/kernel/iopload/include/err.h | 30 + fps2bios/kernel/iopload/include/errno.h | 143 + fps2bios/kernel/iopload/include/iopdebug.h | 11 + fps2bios/kernel/iopload/include/iopelf.h | 226 + fps2bios/kernel/iopload/include/iopload.h | 18 + fps2bios/kernel/iopload/include/kdmacman.h | 116 + fps2bios/kernel/iopload/include/kexcepman.h | 23 + fps2bios/kernel/iopload/include/kheaplib.h | 30 + fps2bios/kernel/iopload/include/kintrman.h | 38 + fps2bios/kernel/iopload/include/kioman.h | 56 + fps2bios/kernel/iopload/include/kloadcore.h | 89 + fps2bios/kernel/iopload/include/ksifcmd.h | 162 + fps2bios/kernel/iopload/include/ksifman.h | 57 + fps2bios/kernel/iopload/include/kstdio.h | 21 + fps2bios/kernel/iopload/include/ksysclib.h | 46 + fps2bios/kernel/iopload/include/ksysmem.h | 27 + fps2bios/kernel/iopload/include/kthbase.h | 19 + fps2bios/kernel/iopload/include/kthsemap.h | 17 + fps2bios/kernel/iopload/include/ktimrman.h | 48 + fps2bios/kernel/iopload/include/romdir.h | 115 + fps2bios/kernel/iopload/intrman/Makefile | 61 + fps2bios/kernel/iopload/intrman/int_handler.s | 373 + fps2bios/kernel/iopload/intrman/intrman.c | 705 + fps2bios/kernel/iopload/iopboot/Makefile | 59 + fps2bios/kernel/iopload/iopboot/iopboot.c | 252 + fps2bios/kernel/iopload/iopboot/iopirq.c | 17 + fps2bios/kernel/iopload/iopboot/linkfile | 16 + fps2bios/kernel/iopload/iopdebug.c | 279 + fps2bios/kernel/iopload/iopelf.c | 428 + .../kernel/iopload/libkernel/iop_cdvdman.s | 146 + .../kernel/iopload/libkernel/iop_dmacman.s | 52 + .../kernel/iopload/libkernel/iop_excepman.s | 58 + .../kernel/iopload/libkernel/iop_heaplib.s | 51 + .../kernel/iopload/libkernel/iop_intrman.s | 73 + fps2bios/kernel/iopload/libkernel/iop_ioman.s | 116 + fps2bios/kernel/iopload/libkernel/iop_libsd.s | 160 + .../kernel/iopload/libkernel/iop_loadcore.s | 65 + .../kernel/iopload/libkernel/iop_modload.s | 61 + .../kernel/iopload/libkernel/iop_sifcmd.s | 144 + .../kernel/iopload/libkernel/iop_sifman.s | 178 + fps2bios/kernel/iopload/libkernel/iop_stdio.s | 32 + .../kernel/iopload/libkernel/iop_sysclib.s | 219 + .../kernel/iopload/libkernel/iop_sysmem.s | 71 + .../kernel/iopload/libkernel/iop_thbase.s | 167 + .../kernel/iopload/libkernel/iop_thevent.s | 67 + .../kernel/iopload/libkernel/iop_thsemap.s | 68 + fps2bios/kernel/iopload/libkernel/iop_usbd.s | 113 + .../kernel/iopload/libkernel/iop_vblank.s | 53 + fps2bios/kernel/iopload/loadcore/Makefile | 59 + fps2bios/kernel/iopload/loadcore/loadcore.c | 1044 + fps2bios/kernel/iopload/romdir.c | 106 + fps2bios/kernel/iopload/sifcmd/Makefile | 62 + fps2bios/kernel/iopload/sifcmd/sifcmd.c | 798 + fps2bios/kernel/iopload/sifman/Makefile | 59 + fps2bios/kernel/iopload/sifman/sifman.c | 467 + fps2bios/kernel/iopload/sio2man/Makefile | 63 + fps2bios/kernel/iopload/sio2man/sio2man.c | 508 + fps2bios/kernel/iopload/ssbusc/Makefile | 59 + fps2bios/kernel/iopload/ssbusc/ssbusc.c | 178 + fps2bios/kernel/iopload/stdio/Makefile | 58 + fps2bios/kernel/iopload/stdio/stdio.c | 40 + fps2bios/kernel/iopload/sysclib/Makefile | 59 + fps2bios/kernel/iopload/sysclib/sysclib.c | 583 + fps2bios/kernel/iopload/sysmem/Makefile | 57 + fps2bios/kernel/iopload/sysmem/sysmem.c | 529 + fps2bios/kernel/iopload/threadman/Makefile | 59 + fps2bios/kernel/iopload/threadman/threadman.c | 654 + fps2bios/kernel/iopload/timrman/Makefile | 59 + fps2bios/kernel/iopload/timrman/timrman.c | 234 + fps2bios/kernel/iopload/vblank/Makefile | 61 + fps2bios/kernel/iopload/vblank/vblank.c | 300 + fps2bios/kernel/iopstart.c | 66 + fps2bios/kernel/linkfile | 53 + fps2bios/kernel/romdir.c | 43 + fps2bios/kernel/romdir.h | 20 + fps2bios/kernel/start.c | 30 + fps2bios/loader/Makefile | 57 + fps2bios/loader/crt0.s | 110 + fps2bios/loader/eedebug.c | 31 + fps2bios/loader/include/eedebug.h | 12 + fps2bios/loader/include/menu.h | 8 + fps2bios/loader/include/romdir.h | 20 + fps2bios/loader/linkfile | 52 + fps2bios/loader/loader.c | 14 + fps2bios/loader/menu.c | 20 + fps2bios/loader/romdir.c | 47 + fps2bios/ps2romgen.c | 80 + fps2bios/romdir.c | 81 + fps2bios/romver.c | 37 + fps2bios/set_vars.sh | 18 + pcsx2/CDVD.c | 1989 ++ pcsx2/CDVD.h | 144 + pcsx2/CDVDiso.c | 853 + pcsx2/CDVDiso.h | 149 + pcsx2/CDVDisodrv.c | 284 + pcsx2/CDVDisodrv.h | 39 + pcsx2/CDVDlib.h | 202 + pcsx2/COP0.c | 369 + pcsx2/COP0.h | 27 + pcsx2/Cache.c | 391 + pcsx2/Cache.h | 47 + pcsx2/CdRom.c | 1092 + pcsx2/CdRom.h | 92 + pcsx2/Common.h | 267 + pcsx2/Counters.c | 815 + pcsx2/Counters.h | 46 + pcsx2/DebugTools/Debug.h | 145 + pcsx2/DebugTools/DisASM.h | 54 + pcsx2/DebugTools/DisR3000A.c | 318 + pcsx2/DebugTools/DisR3000asm.c | 361 + pcsx2/DebugTools/DisR5900.c | 994 + pcsx2/DebugTools/DisR5900asm.c | 1679 + pcsx2/DebugTools/DisVU0Micro.c | 83 + pcsx2/DebugTools/DisVU1Micro.c | 123 + pcsx2/DebugTools/DisVUmicro.h | 209 + pcsx2/DebugTools/DisVUops.h | 197 + pcsx2/DebugTools/Makefile.am | 7 + pcsx2/DebugTools/cpuopsDebug.c | 1063 + pcsx2/DebugTools/cpuopsDebug.h | 456 + pcsx2/Decode_XA.c | 322 + pcsx2/Decode_XA.h | 43 + pcsx2/Docs/ChangeLog.txt | 2851 ++ pcsx2/Docs/License.txt | 342 + pcsx2/Docs/PCSX2 FAQ 0.9.4.rtf | 172 + pcsx2/Docs/PS2Edefs.txt | 443 + pcsx2/Docs/RemoteDebugging.txt | 105 + pcsx2/Docs/Translating.txt | 41 + pcsx2/Docs/devblog.txt | 273 + pcsx2/Docs/readme 0.9.4.txt | 146 + pcsx2/Docs/specs.tex | 159 + pcsx2/EEregs.h | 40 + pcsx2/Elfheader.c | 702 + pcsx2/Elfheader.h | 30 + pcsx2/FPU.c | 174 + pcsx2/FPU2.cpp | 42 + pcsx2/FiFo.c | 177 + pcsx2/GS.cpp | 1881 ++ pcsx2/GS.h | 233 + pcsx2/Hw.c | 1496 + pcsx2/Hw.h | 419 + pcsx2/IPU/IPU.c | 2040 ++ pcsx2/IPU/IPU.h | 203 + pcsx2/IPU/Makefile.am | 8 + pcsx2/IPU/acoroutine.S | 181 + pcsx2/IPU/acoroutine.asm | 140 + pcsx2/IPU/coroutine.c | 172 + pcsx2/IPU/coroutine.h | 39 + pcsx2/IPU/idct_mmx.obj | Bin 0 -> 11510 bytes pcsx2/IPU/mpeg2lib/Idct.c | 301 + pcsx2/IPU/mpeg2lib/Makefile.am | 4 + pcsx2/IPU/mpeg2lib/Mpeg.c | 1378 + pcsx2/IPU/mpeg2lib/Mpeg.h | 200 + pcsx2/IPU/mpeg2lib/Vlc.h | 446 + pcsx2/IPU/yuv2rgb.asm | 242 + pcsx2/IPU/yuv2rgb.c | 510 + pcsx2/IPU/yuv2rgb.h | 57 + pcsx2/InterTables.c | 224 + pcsx2/InterTables.h | 491 + pcsx2/Interpreter.c | 1061 + pcsx2/Linux/.pixmaps/pcsxAbout.xpm | 334 + pcsx2/Linux/Config.c | 151 + pcsx2/Linux/GtkGui.c | 1651 + pcsx2/Linux/Linux.h | 47 + pcsx2/Linux/LnxMain.c | 621 + pcsx2/Linux/Makefile.am | 21 + pcsx2/Linux/buildgui.sh | 27 + pcsx2/Linux/callbacks.h | 403 + pcsx2/Linux/interface.c | 2759 ++ pcsx2/Linux/interface.h | 34 + pcsx2/Linux/pcsx2.glade | 5235 +++ pcsx2/Linux/support.c | 161 + pcsx2/Linux/support.h | 86 + pcsx2/MMI.c | 1477 + pcsx2/Makefile.am | 29 + pcsx2/Mdec.c | 521 + pcsx2/Mdec.h | 31 + pcsx2/Memory.c | 3168 ++ pcsx2/Memory.h | 267 + pcsx2/Misc.c | 1153 + pcsx2/Misc.h | 346 + pcsx2/PS2Edefs.h | 880 + pcsx2/PS2Etypes.h | 105 + pcsx2/Patch.c | 638 + pcsx2/Patch.h | 98 + pcsx2/Paths.h | 18 + pcsx2/Plugins.c | 667 + pcsx2/Plugins.h | 32 + pcsx2/PsxBios.c | 300 + pcsx2/PsxBios.h | 35 + pcsx2/PsxBios2.h | 94 + pcsx2/PsxCommon.h | 53 + pcsx2/PsxCounters.c | 801 + pcsx2/PsxCounters.h | 56 + pcsx2/PsxDma.c | 289 + pcsx2/PsxDma.h | 42 + pcsx2/PsxHw.c | 1825 ++ pcsx2/PsxHw.h | 117 + pcsx2/PsxInterpreter.c | 804 + pcsx2/PsxMem.c | 794 + pcsx2/PsxMem.h | 119 + pcsx2/PsxSio2.c | 284 + pcsx2/PsxSio2.h | 100 + pcsx2/R3000A.c | 218 + pcsx2/R3000A.h | 213 + pcsx2/R5900.c | 633 + pcsx2/R5900.h | 304 + pcsx2/RDebug/Makefile.am | 7 + pcsx2/RDebug/deci2.c | 26 + pcsx2/RDebug/deci2.h | 70 + pcsx2/RDebug/deci2.txt | 27 + pcsx2/RDebug/deci2_dbgp.c | 414 + pcsx2/RDebug/deci2_dbgp.h | 28 + pcsx2/RDebug/deci2_dcmp.c | 83 + pcsx2/RDebug/deci2_dcmp.h | 28 + pcsx2/RDebug/deci2_drfp.c | 48 + pcsx2/RDebug/deci2_drfp.h | 27 + pcsx2/RDebug/deci2_iloadp.c | 106 + pcsx2/RDebug/deci2_iloadp.h | 27 + pcsx2/RDebug/deci2_netmp.c | 134 + pcsx2/RDebug/deci2_netmp.h | 27 + pcsx2/RDebug/deci2_ttyp.c | 41 + pcsx2/RDebug/deci2_ttyp.h | 28 + pcsx2/RDebug/iloadp.txt | 32 + pcsx2/SPR.c | 416 + pcsx2/SPR.h | 29 + pcsx2/Sif.c | 683 + pcsx2/Sif.h | 51 + pcsx2/Sifcmd.h | 193 + pcsx2/Sio.c | 672 + pcsx2/Sio.h | 118 + pcsx2/Stats.c | 73 + pcsx2/Stats.h | 43 + pcsx2/System.h | 64 + pcsx2/VU.h | 183 + pcsx2/VU0.c | 403 + pcsx2/VU0.h | 47 + pcsx2/VU0micro.c | 744 + pcsx2/VU1micro.c | 704 + pcsx2/VUflags.c | 95 + pcsx2/VUflags.h | 38 + pcsx2/VUmicro.h | 1266 + pcsx2/VUops.c | 2957 ++ pcsx2/VUops.h | 393 + pcsx2/Vif.c | 647 + pcsx2/Vif.h | 108 + pcsx2/VifDma.c | 2594 ++ pcsx2/VifDma.h | 98 + pcsx2/build.sh | 54 + pcsx2/cheatscpp.h | 48 + pcsx2/configure.ac | 145 + pcsx2/depcomp | 529 + pcsx2/install-sh | 323 + pcsx2/missing | 360 + pcsx2/mkinstalldirs | 158 + pcsx2/pcsxAbout.bmp | Bin 0 -> 251192 bytes pcsx2/tinyxml/Makefile.am | 5 + pcsx2/tinyxml/tinystr.cpp | 116 + pcsx2/tinyxml/tinystr.h | 319 + pcsx2/tinyxml/tinyxml.cpp | 1866 ++ pcsx2/tinyxml/tinyxml.h | 1776 + pcsx2/tinyxml/tinyxmlerror.cpp | 53 + pcsx2/tinyxml/tinyxmlparser.cpp | 1606 + pcsx2/windows/AboutDlg.c | 59 + pcsx2/windows/AboutDlg.h | 24 + pcsx2/windows/Cdrom02.ico | Bin 0 -> 12862 bytes pcsx2/windows/ConfigDlg.c | 502 + pcsx2/windows/CpuDlg.c | 168 + pcsx2/windows/DebugMemory.c | 239 + pcsx2/windows/Debugger.c | 677 + pcsx2/windows/Debugger.h | 54 + pcsx2/windows/Debugreg.c | 1483 + pcsx2/windows/McdsDlg.c | 126 + pcsx2/windows/McdsDlg.cpp | 1750 + pcsx2/windows/McdsDlg.h | 24 + pcsx2/windows/PatchBrowser.c | 353 + pcsx2/windows/RDebugger.c | 376 + pcsx2/windows/RDebugger.h | 26 + pcsx2/windows/VCprojects/pcsx2_2003.sln | 100 + pcsx2/windows/VCprojects/pcsx2_2003.vcproj | 1316 + pcsx2/windows/VCprojects/pcsx2_2005.sln | 100 + pcsx2/windows/VCprojects/pcsx2_2005.vcproj | 1433 + pcsx2/windows/VCprojects/pcsx2_2005_x64.sln | 214 + .../windows/VCprojects/pcsx2_2005_x64.vcproj | 2244 ++ pcsx2/windows/VCprojects/pcsx2_2008.sln | 100 + pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 1415 + .../windows/VCprojects/vsprops/common.vsprops | 28 + .../windows/VCprojects/vsprops/debug.vsprops | 18 + .../VCprojects/vsprops/devbuild.vsprops | 11 + .../VCprojects/vsprops/release.vsprops | 27 + .../VCprojects/vsprops/virtualmem.vsprops | 11 + pcsx2/windows/Win32.h | 49 + pcsx2/windows/WinMain.c | 1970 ++ pcsx2/windows/afxresmw.h | 23 + pcsx2/windows/cheats/browser.cpp | 1136 + pcsx2/windows/cheats/cheats.cpp | 618 + pcsx2/windows/cheats/cheats.h | 36 + pcsx2/windows/ini.c | 179 + pcsx2/windows/libs/gnu_gettext.lib | Bin 0 -> 2916 bytes pcsx2/windows/libs/libintlmsc.h | 116 + pcsx2/windows/libs/pthread.h | 1368 + pcsx2/windows/libs/pthreadVC2.lib | Bin 0 -> 29280 bytes pcsx2/windows/libs/sched.h | 178 + pcsx2/windows/libs/semaphore.h | 166 + pcsx2/windows/mingw/Makefile.win | 348 + pcsx2/windows/mingw/afxres.h | 23 + pcsx2/windows/mingw/pcsx2.dev | 2116 ++ pcsx2/windows/mingw/pcsx2.layout | 1424 + pcsx2/windows/mingw/pcsx2_private.h | 40 + pcsx2/windows/mingw/pcsx2_private.rc | 5 + pcsx2/windows/pcsx2.rc | 1589 + pcsx2/windows/ps2_silver.bmp | Bin 0 -> 37974 bytes pcsx2/windows/resource.h | 748 + pcsx2/x86/Makefile.am | 22 + pcsx2/x86/README | 12 + pcsx2/x86/aR3000A.S | 396 + pcsx2/x86/aVUzerorec.S | 155 + pcsx2/x86/aVif.S | 1632 + pcsx2/x86/aVif.asm | 1941 ++ pcsx2/x86/fast_routines.S | 349 + pcsx2/x86/fast_routines.cpp | 596 + pcsx2/x86/iCOP2.c | 885 + pcsx2/x86/iCP0.c | 365 + pcsx2/x86/iCP0.h | 41 + pcsx2/x86/iCore.cpp | 1480 + pcsx2/x86/iCore.h | 490 + pcsx2/x86/iFPU.c | 1511 + pcsx2/x86/iFPU.h | 60 + pcsx2/x86/iGS.cpp | 516 + pcsx2/x86/iHw.c | 1297 + pcsx2/x86/iMMI.c | 3376 ++ pcsx2/x86/iMMI.h | 133 + pcsx2/x86/iPsxHw.c | 1164 + pcsx2/x86/iPsxMem.c | 878 + pcsx2/x86/iR3000A.cpp | 1530 + pcsx2/x86/iR3000A.h | 99 + pcsx2/x86/iR3000Atables.cpp | 2053 ++ pcsx2/x86/iR5900.h | 254 + pcsx2/x86/iR5900Arit.h | 45 + pcsx2/x86/iR5900AritImm.h | 41 + pcsx2/x86/iR5900Branch.h | 47 + pcsx2/x86/iR5900Jump.h | 35 + pcsx2/x86/iR5900LoadStore.h | 90 + pcsx2/x86/iR5900Move.h | 33 + pcsx2/x86/iR5900MultDiv.h | 35 + pcsx2/x86/iR5900Shift.h | 47 + pcsx2/x86/iVU0micro.c | 782 + pcsx2/x86/iVU0micro.h | 229 + pcsx2/x86/iVU1micro.c | 218 + pcsx2/x86/iVU1micro.h | 31 + pcsx2/x86/iVUmicro.c | 5346 +++ pcsx2/x86/iVUmicro.h | 274 + pcsx2/x86/iVUops.h | 44 + pcsx2/x86/iVUzerorec.cpp | 4578 +++ pcsx2/x86/iVUzerorec.h | 49 + pcsx2/x86/iVif.cpp | 160 + pcsx2/x86/ir5900tables.c | 1285 + pcsx2/x86/ix86-32/aR5900-32.S | 211 + pcsx2/x86/ix86-32/aVif_proc-32.asm | 1839 ++ pcsx2/x86/ix86-32/iCore-32.cpp | 1227 + pcsx2/x86/ix86-32/iR5900-32.c | 3323 ++ pcsx2/x86/ix86-32/iR5900Arit.c | 2001 ++ pcsx2/x86/ix86-32/iR5900AritImm.c | 663 + pcsx2/x86/ix86-32/iR5900Branch.c | 1154 + pcsx2/x86/ix86-32/iR5900Jump.c | 136 + pcsx2/x86/ix86-32/iR5900LoadStore.c | 4297 +++ pcsx2/x86/ix86-32/iR5900Move.c | 841 + pcsx2/x86/ix86-32/iR5900MultDiv.c | 958 + pcsx2/x86/ix86-32/iR5900Shift.c | 1354 + pcsx2/x86/ix86-64/aR3000A-64.asm | 190 + pcsx2/x86/ix86-64/aR5900-64.S | 249 + pcsx2/x86/ix86-64/aR5900-64.asm | 261 + pcsx2/x86/ix86-64/aVUzerorec-64.asm | 126 + pcsx2/x86/ix86-64/aVif_proc-64.asm | 1827 ++ pcsx2/x86/ix86-64/fast_routines-64.asm | 294 + pcsx2/x86/ix86-64/iCore-64.cpp | 720 + pcsx2/x86/ix86-64/iR5900-64.c | 2754 ++ pcsx2/x86/ix86-64/iR5900Arit-64.c | 213 + pcsx2/x86/ix86-64/iR5900AritImm-64.c | 169 + pcsx2/x86/ix86-64/iR5900Branch-64.c | 537 + pcsx2/x86/ix86-64/iR5900Jump-64.c | 114 + pcsx2/x86/ix86-64/iR5900LoadStore-64.c | 423 + pcsx2/x86/ix86-64/iR5900Move-64.c | 85 + pcsx2/x86/ix86-64/iR5900MultDiv-64.c | 164 + pcsx2/x86/ix86-64/iR5900Shift-64.c | 264 + pcsx2/x86/ix86/Makefile.am | 9 + pcsx2/x86/ix86/ix86.c | 3277 ++ pcsx2/x86/ix86/ix86.h | 1810 + pcsx2/x86/ix86/ix86_3dnow.c | 205 + pcsx2/x86/ix86/ix86_cpudetect.c | 317 + pcsx2/x86/ix86/ix86_fpu.c | 291 + pcsx2/x86/ix86/ix86_mmx.c | 653 + pcsx2/x86/ix86/ix86_sse.c | 1543 + pcsx2/xmlpatchloader.cpp | 397 + pcsx2/zlib/ChangeLog | 722 + pcsx2/zlib/Makefile.am | 6 + pcsx2/zlib/README | 126 + pcsx2/zlib/adler32.c | 74 + pcsx2/zlib/compress.c | 79 + pcsx2/zlib/crc32.c | 311 + pcsx2/zlib/crc32.h | 441 + pcsx2/zlib/deflate.c | 1502 + pcsx2/zlib/deflate.h | 326 + pcsx2/zlib/gzio.c | 1005 + pcsx2/zlib/infback.c | 619 + pcsx2/zlib/inffast.c | 305 + pcsx2/zlib/inffast.h | 11 + pcsx2/zlib/inffixed.h | 94 + pcsx2/zlib/inflate.c | 1270 + pcsx2/zlib/inflate.h | 117 + pcsx2/zlib/inftrees.c | 321 + pcsx2/zlib/inftrees.h | 55 + pcsx2/zlib/trees.c | 1215 + pcsx2/zlib/trees.h | 128 + pcsx2/zlib/uncompr.c | 61 + pcsx2/zlib/zconf.h | 323 + pcsx2/zlib/zlib.h | 1200 + pcsx2/zlib/zutil.c | 319 + pcsx2/zlib/zutil.h | 258 + plugins/build.sh | 59 + plugins/cdvd/CDVDbin/readme.ps1.txt | 52 + plugins/cdvd/CDVDbin/readme.txt | 94 + plugins/cdvd/CDVDbin/src/CDVD.h | 90 + plugins/cdvd/CDVDbin/src/CDVDbin.c | 679 + plugins/cdvd/CDVDbin/src/CDVDbin.def | 29 + plugins/cdvd/CDVDbin/src/CDVDbin.dsp | 139 + plugins/cdvd/CDVDbin/src/CDVDbin.dsw | 29 + plugins/cdvd/CDVDbin/src/CDVDbin.ncb | Bin 0 -> 52224 bytes plugins/cdvd/CDVDbin/src/CDVDbin.rc | 151 + plugins/cdvd/CDVDbin/src/CDVDbin.sln | 21 + plugins/cdvd/CDVDbin/src/CDVDbin.sln.old | 21 + plugins/cdvd/CDVDbin/src/CDVDbin.suo | Bin 0 -> 8704 bytes plugins/cdvd/CDVDbin/src/CDVDbin.vcproj | 178 + plugins/cdvd/CDVDbin/src/CDVDbin.vcproj.old | 164 + plugins/cdvd/CDVDbin/src/CDVDbin_2003.sln | 21 + plugins/cdvd/CDVDbin/src/CDVDbin_2003.vcproj | 178 + .../CDVDbin/src/CDVDbin_vsnet2005beta1.sln | 26 + .../CDVDbin/src/CDVDbin_vsnet2005beta1.vcproj | 428 + plugins/cdvd/CDVDbin/src/CDVDbinro.rc | 141 + plugins/cdvd/CDVDbin/src/PS2Edefs.h | 723 + plugins/cdvd/CDVDbin/src/PS2Etypes.h | 43 + plugins/cdvd/CDVDbin/src/resource.h | 19 + plugins/cdvd/CDVDdraft/Src/AboutBox.cpp | 43 + plugins/cdvd/CDVDdraft/Src/AboutBox.h | 46 + plugins/cdvd/CDVDdraft/Src/Config.cpp | 172 + plugins/cdvd/CDVDdraft/Src/Config.h | 54 + plugins/cdvd/CDVDdraft/Src/PS2Edefs.h | 723 + plugins/cdvd/CDVDdraft/Src/PS2Etypes.h | 43 + plugins/cdvd/CDVDdraft/Src/ReadMe.txt | 66 + plugins/cdvd/CDVDdraft/Src/StdAfx.cpp | 8 + plugins/cdvd/CDVDdraft/Src/StdAfx.h | 41 + plugins/cdvd/CDVDdraft/Src/aspi.cpp | 842 + plugins/cdvd/CDVDdraft/Src/bitmap1.bmp | Bin 0 -> 3726 bytes plugins/cdvd/CDVDdraft/Src/cdvd.cpp | 616 + plugins/cdvd/CDVDdraft/Src/cdvd.h | 252 + plugins/cdvd/CDVDdraft/Src/cdvdcompat.cpp | 194 + plugins/cdvd/CDVDdraft/Src/cdvdcompat.h | 20 + plugins/cdvd/CDVDdraft/Src/cdvddraft.aps | Bin 0 -> 38612 bytes plugins/cdvd/CDVDdraft/Src/cdvddraft.clw | 48 + plugins/cdvd/CDVDdraft/Src/cdvddraft.cpp | 599 + plugins/cdvd/CDVDdraft/Src/cdvddraft.def | 49 + plugins/cdvd/CDVDdraft/Src/cdvddraft.dep | 138 + plugins/cdvd/CDVDdraft/Src/cdvddraft.dsp | 219 + plugins/cdvd/CDVDdraft/Src/cdvddraft.dsw | 29 + plugins/cdvd/CDVDdraft/Src/cdvddraft.h | 56 + plugins/cdvd/CDVDdraft/Src/cdvddraft.opt | Bin 0 -> 65024 bytes plugins/cdvd/CDVDdraft/Src/cdvddraft.plg | 68 + plugins/cdvd/CDVDdraft/Src/cdvddraft.rc | 227 + plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.sln | 21 + .../cdvd/CDVDdraft/Src/cdvddraft_2003.vcproj | 399 + plugins/cdvd/CDVDdraft/Src/cdvdmisc.cpp | 93 + plugins/cdvd/CDVDdraft/Src/cdvdmisc.h | 17 + plugins/cdvd/CDVDdraft/Src/constants.h | 109 + plugins/cdvd/CDVDdraft/Src/ioctl.cpp | 208 + plugins/cdvd/CDVDdraft/Src/res/CVS/Entries | 2 + .../cdvd/CDVDdraft/Src/res/CVS/Entries.Extra | 1 + plugins/cdvd/CDVDdraft/Src/res/CVS/Repository | 1 + plugins/cdvd/CDVDdraft/Src/res/CVS/Root | 1 + plugins/cdvd/CDVDdraft/Src/res/cdvddraft.rc2 | 13 + plugins/cdvd/CDVDdraft/Src/resource.h | 25 + plugins/cdvd/CDVDdraft/Src/typedefs.h | 125 + plugins/cdvd/CDVDdraft/Src/winaspi/scsidefs.h | 279 + plugins/cdvd/CDVDdraft/Src/winaspi/wnaspi32.h | 325 + plugins/cdvd/CDVDiso/ReadMe.txt | 78 + plugins/cdvd/CDVDiso/build.sh | 16 + plugins/cdvd/CDVDiso/src/CDVDiso.h | 80 + plugins/cdvd/CDVDiso/src/CDVDisop.c | 418 + plugins/cdvd/CDVDiso/src/Linux/CDVDiso.glade | 368 + plugins/cdvd/CDVDiso/src/Linux/Config.c | 59 + plugins/cdvd/CDVDiso/src/Linux/Config.h | 20 + plugins/cdvd/CDVDiso/src/Linux/Linux.c | 76 + plugins/cdvd/CDVDiso/src/Linux/Makefile | 33 + plugins/cdvd/CDVDiso/src/Linux/callbacks.c | 98 + plugins/cdvd/CDVDiso/src/Linux/callbacks.h | 46 + plugins/cdvd/CDVDiso/src/Linux/conf.c | 865 + plugins/cdvd/CDVDiso/src/Linux/interface.c | 253 + plugins/cdvd/CDVDiso/src/Linux/interface.h | 5 + plugins/cdvd/CDVDiso/src/Linux/support.c | 162 + plugins/cdvd/CDVDiso/src/Linux/support.h | 38 + plugins/cdvd/CDVDiso/src/PS2Edefs.h | 812 + plugins/cdvd/CDVDiso/src/PS2Etypes.h | 43 + .../CDVDiso/src/Win32/CDVDiso 2005 x64.sln | 17 + .../CDVDiso/src/Win32/CDVDiso 2005 x64.vcproj | 563 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.def | 29 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsp | 111 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsw | 30 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.rc | 134 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.sln | 18 + plugins/cdvd/CDVDiso/src/Win32/CDVDiso.vcproj | 258 + .../cdvd/CDVDiso/src/Win32/CDVDiso_2003.sln | 21 + .../CDVDiso/src/Win32/CDVDiso_2003.vcproj | 539 + .../cdvd/CDVDiso/src/Win32/CDVDiso_2005.sln | 20 + .../CDVDiso/src/Win32/CDVDiso_2005.vcproj | 538 + .../CDVDiso/src/Win32/CDVDiso_2008.vcproj | 537 + plugins/cdvd/CDVDiso/src/Win32/Config.c | 45 + plugins/cdvd/CDVDiso/src/Win32/Config.h | 3 + plugins/cdvd/CDVDiso/src/Win32/Makefile | 57 + plugins/cdvd/CDVDiso/src/Win32/Win32.c | 311 + plugins/cdvd/CDVDiso/src/Win32/afxresmw.h | 5 + plugins/cdvd/CDVDiso/src/Win32/plugin.def | 21 + plugins/cdvd/CDVDiso/src/Win32/resource.h | 28 + plugins/cdvd/CDVDiso/src/bzip2/LICENSE | 43 + plugins/cdvd/CDVDiso/src/bzip2/README | 205 + plugins/cdvd/CDVDiso/src/bzip2/blocksort.c | 1094 + plugins/cdvd/CDVDiso/src/bzip2/bzlib.c | 1571 + plugins/cdvd/CDVDiso/src/bzip2/bzlib.h | 282 + .../cdvd/CDVDiso/src/bzip2/bzlib_private.h | 503 + plugins/cdvd/CDVDiso/src/bzip2/compress.c | 672 + plugins/cdvd/CDVDiso/src/bzip2/crctable.c | 104 + plugins/cdvd/CDVDiso/src/bzip2/decompress.c | 626 + plugins/cdvd/CDVDiso/src/bzip2/huffman.c | 205 + plugins/cdvd/CDVDiso/src/bzip2/randtable.c | 84 + plugins/cdvd/CDVDiso/src/libiso.c | 933 + plugins/cdvd/CDVDiso/src/libiso.h | 65 + plugins/cdvd/CDVDiso/src/mkiso/Makefile | 26 + plugins/cdvd/CDVDiso/src/mkiso/Makefile.mingw | 31 + plugins/cdvd/CDVDiso/src/mkiso/mkiso.c | 153 + plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsp | 206 + plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsw | 29 + plugins/cdvd/CDVDiso/src/zlib/ChangeLog | 855 + plugins/cdvd/CDVDiso/src/zlib/README | 125 + plugins/cdvd/CDVDiso/src/zlib/adler32.c | 149 + plugins/cdvd/CDVDiso/src/zlib/compress.c | 79 + plugins/cdvd/CDVDiso/src/zlib/crc32.c | 423 + plugins/cdvd/CDVDiso/src/zlib/crc32.h | 441 + plugins/cdvd/CDVDiso/src/zlib/deflate.c | 1736 + plugins/cdvd/CDVDiso/src/zlib/deflate.h | 331 + plugins/cdvd/CDVDiso/src/zlib/gvmat32.obj | Bin 0 -> 10137 bytes plugins/cdvd/CDVDiso/src/zlib/gvmat32c.c | 62 + plugins/cdvd/CDVDiso/src/zlib/gvmat64.obj | Bin 0 -> 4215 bytes plugins/cdvd/CDVDiso/src/zlib/gzio.c | 1026 + plugins/cdvd/CDVDiso/src/zlib/infback.c | 623 + plugins/cdvd/CDVDiso/src/zlib/inffas32.obj | Bin 0 -> 14899 bytes plugins/cdvd/CDVDiso/src/zlib/inffas8664.c | 186 + plugins/cdvd/CDVDiso/src/zlib/inffast.c | 318 + plugins/cdvd/CDVDiso/src/zlib/inffast.h | 11 + plugins/cdvd/CDVDiso/src/zlib/inffasx64.obj | Bin 0 -> 5881 bytes plugins/cdvd/CDVDiso/src/zlib/inffixed.h | 94 + plugins/cdvd/CDVDiso/src/zlib/inflate.c | 1368 + plugins/cdvd/CDVDiso/src/zlib/inflate.h | 115 + plugins/cdvd/CDVDiso/src/zlib/inftrees.c | 329 + plugins/cdvd/CDVDiso/src/zlib/inftrees.h | 55 + plugins/cdvd/CDVDiso/src/zlib/trees.c | 1219 + plugins/cdvd/CDVDiso/src/zlib/trees.h | 128 + plugins/cdvd/CDVDiso/src/zlib/uncompr.c | 61 + plugins/cdvd/CDVDiso/src/zlib/zconf.h | 332 + plugins/cdvd/CDVDiso/src/zlib/zlib.h | 1357 + plugins/cdvd/CDVDiso/src/zlib/zutil.c | 318 + plugins/cdvd/CDVDiso/src/zlib/zutil.h | 269 + plugins/cdvd/CDVDisoEFP/ChangeLog.txt | 58 + plugins/cdvd/CDVDisoEFP/build.sh | 16 + plugins/cdvd/CDVDisoEFP/license.txt | 342 + plugins/cdvd/CDVDisoEFP/readme.txt | 55 + plugins/cdvd/CDVDisoEFP/src/Linux/CD.c | 367 + plugins/cdvd/CDVDisoEFP/src/Linux/CD.h | 46 + plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.c | 450 + plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.h | 29 + plugins/cdvd/CDVDisoEFP/src/Linux/DVD.c | 582 + plugins/cdvd/CDVDisoEFP/src/Linux/DVD.h | 45 + plugins/cdvd/CDVDisoEFP/src/Linux/Makefile | 91 + plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.c | 106 + .../cdvd/CDVDisoEFP/src/Linux/aboutbox.glade | 118 + plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.h | 39 + .../cdvd/CDVDisoEFP/src/Linux/actualfile.c | 222 + .../cdvd/CDVDisoEFP/src/Linux/actualfile.h | 50 + .../cdvd/CDVDisoEFP/src/Linux/comparisonbox.c | 415 + .../CDVDisoEFP/src/Linux/comparisonbox.glade | 227 + .../CDVDisoEFP/src/Linux/comparisondummy.c | 24 + plugins/cdvd/CDVDisoEFP/src/Linux/conf.c | 204 + plugins/cdvd/CDVDisoEFP/src/Linux/conf.h | 54 + .../cdvd/CDVDisoEFP/src/Linux/conversionbox.c | 388 + .../CDVDisoEFP/src/Linux/conversionbox.glade | 272 + .../cdvd/CDVDisoEFP/src/Linux/conversionbox.h | 47 + plugins/cdvd/CDVDisoEFP/src/Linux/device.c | 418 + plugins/cdvd/CDVDisoEFP/src/Linux/device.h | 69 + plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.c | 443 + .../cdvd/CDVDisoEFP/src/Linux/devicebox.glade | 345 + plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.h | 50 + plugins/cdvd/CDVDisoEFP/src/Linux/interface.c | 67 + plugins/cdvd/CDVDisoEFP/src/Linux/interface.h | 29 + plugins/cdvd/CDVDisoEFP/src/Linux/logfile.c | 90 + plugins/cdvd/CDVDisoEFP/src/Linux/logfile.h | 35 + plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.c | 324 + .../cdvd/CDVDisoEFP/src/Linux/mainbox.glade | 219 + plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.h | 50 + .../cdvd/CDVDisoEFP/src/Linux/messagebox.c | 113 + .../CDVDisoEFP/src/Linux/messagebox.glade | 76 + .../cdvd/CDVDisoEFP/src/Linux/messagebox.h | 43 + .../cdvd/CDVDisoEFP/src/Linux/progressbox.c | 144 + .../CDVDisoEFP/src/Linux/progressbox.glade | 95 + .../cdvd/CDVDisoEFP/src/Linux/progressbox.h | 55 + .../cdvd/CDVDisoEFP/src/Linux/selectionbox.c | 102 + .../CDVDisoEFP/src/Linux/selectionbox.glade | 44 + .../cdvd/CDVDisoEFP/src/Linux/selectionbox.h | 46 + .../cdvd/CDVDisoEFP/src/Linux/tablerebuild.c | 190 + .../cdvd/CDVDisoEFP/src/Linux/tablerebuild.h | 32 + plugins/cdvd/CDVDisoEFP/src/PS2Edefs.h | 812 + plugins/cdvd/CDVDisoEFP/src/PS2Etypes.h | 75 + plugins/cdvd/CDVDisoEFP/src/Win32/CD.c | 774 + plugins/cdvd/CDVDisoEFP/src/Win32/CD.h | 44 + plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.c | 570 + plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.h | 36 + plugins/cdvd/CDVDisoEFP/src/Win32/DVD.c | 796 + plugins/cdvd/CDVDisoEFP/src/Win32/DVD.h | 37 + .../CDVDisoEFP/src/Win32/Makefile.MinGW32 | 59 + .../CDVDisoEFP/src/Win32/Makefile.MinGW32.bak | 57 + .../cdvd/CDVDisoEFP/src/Win32/actualfile.c | 506 + .../cdvd/CDVDisoEFP/src/Win32/actualfile.h | 104 + plugins/cdvd/CDVDisoEFP/src/Win32/conf.c | 195 + plugins/cdvd/CDVDisoEFP/src/Win32/conf.h | 54 + .../cdvd/CDVDisoEFP/src/Win32/conversionbox.c | 750 + .../cdvd/CDVDisoEFP/src/Win32/conversionbox.h | 40 + plugins/cdvd/CDVDisoEFP/src/Win32/device.c | 586 + plugins/cdvd/CDVDisoEFP/src/Win32/device.h | 64 + plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.c | 818 + plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.h | 41 + plugins/cdvd/CDVDisoEFP/src/Win32/logfile.c | 119 + plugins/cdvd/CDVDisoEFP/src/Win32/logfile.h | 39 + plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.c | 309 + plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.h | 43 + plugins/cdvd/CDVDisoEFP/src/Win32/make.bat | 1 + .../cdvd/CDVDisoEFP/src/Win32/makeming.bat | 1 + plugins/cdvd/CDVDisoEFP/src/Win32/plugin.def | 21 + .../cdvd/CDVDisoEFP/src/Win32/progressbox.c | 340 + .../cdvd/CDVDisoEFP/src/Win32/progressbox.h | 89 + plugins/cdvd/CDVDisoEFP/src/Win32/screens.h | 37 + plugins/cdvd/CDVDisoEFP/src/Win32/screens.rc | 82 + .../cdvd/CDVDisoEFP/src/Win32/tablerebuild.c | 187 + .../cdvd/CDVDisoEFP/src/Win32/tablerebuild.h | 32 + plugins/cdvd/CDVDisoEFP/src/blockv2.c | 612 + plugins/cdvd/CDVDisoEFP/src/blockv2.h | 104 + plugins/cdvd/CDVDisoEFP/src/bzip2/LICENSE | 40 + plugins/cdvd/CDVDisoEFP/src/bzip2/README | 185 + plugins/cdvd/CDVDisoEFP/src/bzip2/blocksort.c | 1141 + plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.c | 1616 + plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.h | 323 + .../cdvd/CDVDisoEFP/src/bzip2/bzlib_private.h | 537 + plugins/cdvd/CDVDisoEFP/src/bzip2/compress.c | 716 + plugins/cdvd/CDVDisoEFP/src/bzip2/crctable.c | 144 + .../cdvd/CDVDisoEFP/src/bzip2/decompress.c | 666 + plugins/cdvd/CDVDisoEFP/src/bzip2/huffman.c | 245 + plugins/cdvd/CDVDisoEFP/src/bzip2/randtable.c | 124 + plugins/cdvd/CDVDisoEFP/src/bzip2v2.c | 1052 + plugins/cdvd/CDVDisoEFP/src/bzip2v2.h | 104 + plugins/cdvd/CDVDisoEFP/src/bzip2v3.c | 968 + plugins/cdvd/CDVDisoEFP/src/bzip2v3.h | 104 + plugins/cdvd/CDVDisoEFP/src/convert.c | 118 + plugins/cdvd/CDVDisoEFP/src/convert.h | 50 + plugins/cdvd/CDVDisoEFP/src/ecma119.c | 59 + plugins/cdvd/CDVDisoEFP/src/ecma119.h | 468 + plugins/cdvd/CDVDisoEFP/src/gzipv1.c | 844 + plugins/cdvd/CDVDisoEFP/src/gzipv1.h | 104 + plugins/cdvd/CDVDisoEFP/src/gzipv2.c | 980 + plugins/cdvd/CDVDisoEFP/src/gzipv2.h | 104 + plugins/cdvd/CDVDisoEFP/src/imagetype.c | 306 + plugins/cdvd/CDVDisoEFP/src/imagetype.h | 112 + plugins/cdvd/CDVDisoEFP/src/ini.c | 689 + plugins/cdvd/CDVDisoEFP/src/ini.h | 64 + plugins/cdvd/CDVDisoEFP/src/isocompress.c | 914 + plugins/cdvd/CDVDisoEFP/src/isocompress.h | 158 + plugins/cdvd/CDVDisoEFP/src/isofile.c | 1292 + plugins/cdvd/CDVDisoEFP/src/isofile.h | 246 + plugins/cdvd/CDVDisoEFP/src/multifile.c | 578 + plugins/cdvd/CDVDisoEFP/src/multifile.h | 106 + plugins/cdvd/CDVDisoEFP/src/toc.c | 358 + plugins/cdvd/CDVDisoEFP/src/toc.h | 84 + plugins/cdvd/CDVDisoEFP/src/version.c | 36 + plugins/cdvd/CDVDisoEFP/src/version.h | 43 + plugins/cdvd/CDVDisoEFP/src/zlib/ChangeLog | 722 + plugins/cdvd/CDVDisoEFP/src/zlib/README | 126 + plugins/cdvd/CDVDisoEFP/src/zlib/adler32.c | 74 + plugins/cdvd/CDVDisoEFP/src/zlib/compress.c | 79 + plugins/cdvd/CDVDisoEFP/src/zlib/crc32.c | 311 + plugins/cdvd/CDVDisoEFP/src/zlib/crc32.h | 441 + plugins/cdvd/CDVDisoEFP/src/zlib/deflate.c | 1502 + plugins/cdvd/CDVDisoEFP/src/zlib/deflate.h | 326 + plugins/cdvd/CDVDisoEFP/src/zlib/gzio.c | 1005 + plugins/cdvd/CDVDisoEFP/src/zlib/infback.c | 619 + plugins/cdvd/CDVDisoEFP/src/zlib/inffast.c | 305 + plugins/cdvd/CDVDisoEFP/src/zlib/inffast.h | 11 + plugins/cdvd/CDVDisoEFP/src/zlib/inffixed.h | 94 + plugins/cdvd/CDVDisoEFP/src/zlib/inflate.c | 1270 + plugins/cdvd/CDVDisoEFP/src/zlib/inflate.h | 117 + plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.c | 321 + plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.h | 55 + plugins/cdvd/CDVDisoEFP/src/zlib/trees.c | 1215 + plugins/cdvd/CDVDisoEFP/src/zlib/trees.h | 128 + plugins/cdvd/CDVDisoEFP/src/zlib/uncompr.c | 61 + plugins/cdvd/CDVDisoEFP/src/zlib/zconf.h | 323 + plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h | 1200 + plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h.bak | 1200 + plugins/cdvd/CDVDisoEFP/src/zlib/zutil.c | 319 + plugins/cdvd/CDVDisoEFP/src/zlib/zutil.h | 258 + plugins/cdvd/CDVDlinuz/ChangeLog.txt | 43 + plugins/cdvd/CDVDlinuz/License.txt | 342 + plugins/cdvd/CDVDlinuz/Src/Linux/CD.c | 367 + plugins/cdvd/CDVDlinuz/Src/Linux/CD.h | 46 + plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.c | 368 + plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.h | 31 + plugins/cdvd/CDVDlinuz/Src/Linux/DVD.c | 584 + plugins/cdvd/CDVDlinuz/Src/Linux/DVD.h | 45 + plugins/cdvd/CDVDlinuz/Src/Linux/Makefile | 71 + plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.c | 106 + plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.h | 39 + plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.c | 222 + plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.h | 50 + plugins/cdvd/CDVDlinuz/Src/Linux/conf.c | 184 + plugins/cdvd/CDVDlinuz/Src/Linux/conf.h | 57 + plugins/cdvd/CDVDlinuz/Src/Linux/device.c | 420 + plugins/cdvd/CDVDlinuz/Src/Linux/device.h | 69 + plugins/cdvd/CDVDlinuz/Src/Linux/interface.c | 57 + plugins/cdvd/CDVDlinuz/Src/Linux/logfile.c | 90 + plugins/cdvd/CDVDlinuz/Src/Linux/logfile.h | 35 + plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.c | 187 + plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.h | 41 + plugins/cdvd/CDVDlinuz/Src/PS2Edefs.h | 812 + plugins/cdvd/CDVDlinuz/Src/PS2Etypes.h | 43 + plugins/cdvd/CDVDlinuz/Src/Win32/CD.c | 387 + plugins/cdvd/CDVDlinuz/Src/Win32/CD.h | 44 + plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.c | 434 + plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.h | 40 + plugins/cdvd/CDVDlinuz/Src/Win32/DVD.c | 398 + plugins/cdvd/CDVDlinuz/Src/Win32/DVD.h | 37 + .../cdvd/CDVDlinuz/Src/Win32/Makefile.MinGW32 | 43 + plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.c | 253 + plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.h | 52 + plugins/cdvd/CDVDlinuz/Src/Win32/conf.c | 175 + plugins/cdvd/CDVDlinuz/Src/Win32/conf.h | 49 + plugins/cdvd/CDVDlinuz/Src/Win32/device.c | 583 + plugins/cdvd/CDVDlinuz/Src/Win32/device.h | 64 + plugins/cdvd/CDVDlinuz/Src/Win32/logfile.c | 119 + plugins/cdvd/CDVDlinuz/Src/Win32/logfile.h | 39 + plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.c | 173 + plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.h | 42 + plugins/cdvd/CDVDlinuz/Src/Win32/make.bat | 1 + plugins/cdvd/CDVDlinuz/Src/Win32/plugin.def | 21 + plugins/cdvd/CDVDlinuz/Src/Win32/screens.h | 9 + plugins/cdvd/CDVDlinuz/Src/Win32/screens.rc | 29 + plugins/cdvd/CDVDlinuz/Src/buffer.c | 525 + plugins/cdvd/CDVDlinuz/Src/buffer.h | 67 + plugins/cdvd/CDVDlinuz/Src/convert.c | 118 + plugins/cdvd/CDVDlinuz/Src/convert.h | 50 + plugins/cdvd/CDVDlinuz/Src/ini.c | 689 + plugins/cdvd/CDVDlinuz/Src/ini.h | 64 + plugins/cdvd/CDVDlinuz/Src/version.c | 36 + plugins/cdvd/CDVDlinuz/Src/version.h | 43 + plugins/cdvd/CDVDlinuz/build.sh | 16 + plugins/cdvd/CDVDlinuz/readme.txt | 37 + plugins/cdvd/CDVDnull/ReadMe.txt | 39 + plugins/cdvd/CDVDnull/Src/CDVD.c | 146 + plugins/cdvd/CDVDnull/Src/CDVD.h | 11 + plugins/cdvd/CDVDnull/Src/CDVDnull.def | 29 + plugins/cdvd/CDVDnull/Src/CDVDnull.dsp | 90 + plugins/cdvd/CDVDnull/Src/CDVDnull.dsw | 29 + plugins/cdvd/CDVDnull/Src/CDVDnull.opt | Bin 0 -> 53760 bytes plugins/cdvd/CDVDnull/Src/CDVDnull.plg | 34 + plugins/cdvd/CDVDnull/Src/CDVDnull.sln | 18 + plugins/cdvd/CDVDnull/Src/CDVDnull.vcproj | 101 + plugins/cdvd/CDVDnull/Src/CDVDnull_2003.sln | 18 + .../cdvd/CDVDnull/Src/CDVDnull_2003.vcproj | 109 + .../cdvd/CDVDnull/Src/CDVDnull_2005_x64.sln | 17 + .../CDVDnull/Src/CDVDnull_2005_x64.vcproj | 607 + .../CDVDnull/Src/CDVDnull_vsnet2005beta1.sln | 17 + .../Src/CDVDnull_vsnet2005beta1.vcproj | 418 + plugins/cdvd/CDVDnull/Src/Makefile | 50 + plugins/cdvd/CDVDnull/Src/PS2Edefs.h | 827 + plugins/cdvd/CDVDnull/Src/PS2Etypes.h | 76 + plugins/cdvd/CDVDnull/Src/plugin.def | 21 + plugins/cdvd/CDVDnull/build.sh | 12 + plugins/cdvd/CDVDpeops/CDVDiso.c | 822 + plugins/cdvd/CDVDpeops/CDVDiso.h | 131 + plugins/cdvd/CDVDpeops/CDVDisodrv.c | 264 + plugins/cdvd/CDVDpeops/CDVDisodrv.h | 22 + plugins/cdvd/CDVDpeops/CDVDlib.h | 189 + plugins/cdvd/CDVDpeops/CLEAN.BAT | 3 + plugins/cdvd/CDVDpeops/Cdr.c | 935 + plugins/cdvd/CDVDpeops/Cdr.c.bak | 848 + plugins/cdvd/CDVDpeops/Cfg.c | 527 + plugins/cdvd/CDVDpeops/CheckDiskType.c | 41 + plugins/cdvd/CDVDpeops/Ioctrl.c | 383 + plugins/cdvd/CDVDpeops/Makefile.win | 72 + plugins/cdvd/CDVDpeops/PS2Edefs.h | 789 + plugins/cdvd/CDVDpeops/PS2Etypes.h | 43 + plugins/cdvd/CDVDpeops/ReadMe.txt | 37 + plugins/cdvd/CDVDpeops/Scsi.c | 1134 + plugins/cdvd/CDVDpeops/StdAfx.c | 8 + plugins/cdvd/CDVDpeops/StdAfx.h | 82 + plugins/cdvd/CDVDpeops/build.sh | 16 + plugins/cdvd/CDVDpeops/cdda.c | 80 + plugins/cdvd/CDVDpeops/cdda.h | 28 + plugins/cdvd/CDVDpeops/cdr.h | 27 + plugins/cdvd/CDVDpeops/cdvdPeops.aps | Bin 0 -> 23964 bytes plugins/cdvd/CDVDpeops/cdvdPeops.c | 89 + plugins/cdvd/CDVDpeops/cdvdPeops.def | 30 + plugins/cdvd/CDVDpeops/cdvdPeops.def.bak | 30 + plugins/cdvd/CDVDpeops/cdvdPeops.dev | 418 + plugins/cdvd/CDVDpeops/cdvdPeops.dsp | 251 + plugins/cdvd/CDVDpeops/cdvdPeops.dsw | 29 + plugins/cdvd/CDVDpeops/cdvdPeops.h | 25 + plugins/cdvd/CDVDpeops/cdvdPeops.layout | 238 + plugins/cdvd/CDVDpeops/cdvdPeops.opt | Bin 0 -> 50688 bytes plugins/cdvd/CDVDpeops/cdvdPeops.plg | 96 + plugins/cdvd/CDVDpeops/cdvdPeops.rc | 235 + plugins/cdvd/CDVDpeops/cdvdPeops.sln | 21 + plugins/cdvd/CDVDpeops/cdvdPeops.vcproj | 492 + plugins/cdvd/CDVDpeops/cdvdPeops_2005.sln | 19 + plugins/cdvd/CDVDpeops/cdvdPeops_2005.vcproj | 649 + plugins/cdvd/CDVDpeops/cdvdPeops_private.h | 23 + plugins/cdvd/CDVDpeops/cdvdPeops_private.rc | 4 + plugins/cdvd/CDVDpeops/cdvdPeops_private.res | Bin 0 -> 4584 bytes plugins/cdvd/CDVDpeops/cfg.h | 47 + plugins/cdvd/CDVDpeops/changelog.txt | 19 + plugins/cdvd/CDVDpeops/defines.h | 212 + plugins/cdvd/CDVDpeops/defines.h.bak | 213 + plugins/cdvd/CDVDpeops/externals.h | 177 + plugins/cdvd/CDVDpeops/externals.h.bak | 175 + plugins/cdvd/CDVDpeops/filemap.txt | 52 + plugins/cdvd/CDVDpeops/generic.c | 386 + plugins/cdvd/CDVDpeops/generic.c.bak | 377 + plugins/cdvd/CDVDpeops/generic.h | 41 + plugins/cdvd/CDVDpeops/i386.asm | 32 + plugins/cdvd/CDVDpeops/ioctrl.h | 35 + plugins/cdvd/CDVDpeops/libiso.c | 732 + plugins/cdvd/CDVDpeops/libiso.h | 59 + plugins/cdvd/CDVDpeops/license.txt | 282 + plugins/cdvd/CDVDpeops/macros.inc | 40 + plugins/cdvd/CDVDpeops/mingw/afxres.h | 2 + plugins/cdvd/CDVDpeops/ppf.c | 353 + plugins/cdvd/CDVDpeops/ppf.h | 32 + plugins/cdvd/CDVDpeops/read.c | 910 + plugins/cdvd/CDVDpeops/read.h | 41 + plugins/cdvd/CDVDpeops/readme_1_2.txt | 198 + plugins/cdvd/CDVDpeops/resource.h | 56 + plugins/cdvd/CDVDpeops/scsi.h | 55 + plugins/cdvd/CDVDpeops/scsidefs.h | 579 + plugins/cdvd/CDVDpeops/sub.c | 321 + plugins/cdvd/CDVDpeops/sub.h | 30 + plugins/cdvd/CDVDpeops/toc.c | 105 + plugins/cdvd/CDVDpeops/toc.h | 28 + plugins/cdvd/CDVDpeops/version_1_2.txt | 61 + plugins/cdvd/CDVDpeops/wnaspi32.h | 354 + plugins/cdvd/build.sh | 39 + plugins/dev9/DEV9linuz/DEV9.c | 1292 + plugins/dev9/DEV9linuz/DEV9.h | 1157 + plugins/dev9/DEV9linuz/Linux/Config.c | 45 + plugins/dev9/DEV9linuz/Linux/Config.h | 2 + plugins/dev9/DEV9linuz/Linux/Linux.c | 76 + plugins/dev9/DEV9linuz/Linux/Makefile | 37 + plugins/dev9/DEV9linuz/Linux/callbacks.c | 34 + plugins/dev9/DEV9linuz/Linux/callbacks.h | 14 + plugins/dev9/DEV9linuz/Linux/conf.c | 165 + plugins/dev9/DEV9linuz/Linux/dev9linuz.glade | 300 + plugins/dev9/DEV9linuz/Linux/dev9net.c | 194 + plugins/dev9/DEV9linuz/Linux/interface.c | 219 + plugins/dev9/DEV9linuz/Linux/interface.h | 6 + plugins/dev9/DEV9linuz/Linux/socks.c | 73 + plugins/dev9/DEV9linuz/Linux/socks.h | 22 + plugins/dev9/DEV9linuz/Linux/support.c | 162 + plugins/dev9/DEV9linuz/Linux/support.h | 38 + plugins/dev9/DEV9linuz/PS2Edefs.h | 684 + plugins/dev9/DEV9linuz/PS2Etypes.h | 31 + plugins/dev9/DEV9linuz/Win32/Config.c | 52 + plugins/dev9/DEV9linuz/Win32/Config.h | 2 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.def | 29 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsp | 111 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsw | 29 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.rc | 135 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.sln | 18 + plugins/dev9/DEV9linuz/Win32/DEV9linuz.vcproj | 176 + plugins/dev9/DEV9linuz/Win32/Devioctl.h | 90 + plugins/dev9/DEV9linuz/Win32/Makefile | 52 + plugins/dev9/DEV9linuz/Win32/Ntddndis.h | 1400 + plugins/dev9/DEV9linuz/Win32/Packet.lib | Bin 0 -> 8180 bytes plugins/dev9/DEV9linuz/Win32/Packet32.h | 450 + plugins/dev9/DEV9linuz/Win32/Win32.c | 132 + plugins/dev9/DEV9linuz/Win32/afxresmw.h | 5 + plugins/dev9/DEV9linuz/Win32/libpacket.a | Bin 0 -> 23732 bytes plugins/dev9/DEV9linuz/Win32/plugin.def | 24 + plugins/dev9/DEV9linuz/Win32/resource.h | 25 + plugins/dev9/DEV9linuz/Win32/socks.c | 191 + plugins/dev9/DEV9linuz/Win32/socks.h | 12 + plugins/dev9/DEV9linuz/dvr.c | 67 + plugins/dev9/DEV9linuz/flash.c | 289 + plugins/dev9/build.sh | 14 + plugins/dev9/dev9ghzdrk/DEV9.cpp | 603 + plugins/dev9/dev9ghzdrk/DEV9.h | 629 + plugins/dev9/dev9ghzdrk/PS2Edefs.h | 684 + plugins/dev9/dev9ghzdrk/PS2Etypes.h | 31 + plugins/dev9/dev9ghzdrk/Win32/Config.cpp | 55 + plugins/dev9/dev9ghzdrk/Win32/Config.h | 2 + plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.aps | Bin 0 -> 35628 bytes plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.def | 28 + plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.dsw | 29 + plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.opt | Bin 0 -> 48640 bytes plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.plg | 53 + plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.rc | 126 + plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.sln | 20 + .../dev9/dev9ghzdrk/Win32/DEV9linuz.vcproj | 435 + .../dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.sln | 20 + .../Win32/DEV9linuz_vs2005_x64.vcproj | 435 + plugins/dev9/dev9ghzdrk/Win32/Devioctl.h | 90 + plugins/dev9/dev9ghzdrk/Win32/Makefile | 52 + plugins/dev9/dev9ghzdrk/Win32/Packet.lib | Bin 0 -> 8180 bytes plugins/dev9/dev9ghzdrk/Win32/Win32.cpp | 170 + plugins/dev9/dev9ghzdrk/Win32/_Ntddndis.h | 1400 + plugins/dev9/dev9ghzdrk/Win32/afxresmw.h | 5 + plugins/dev9/dev9ghzdrk/Win32/ata.cpp | 3442 ++ plugins/dev9/dev9ghzdrk/Win32/ata.h | 13 + plugins/dev9/dev9ghzdrk/Win32/icmp.cpp | 105 + plugins/dev9/dev9ghzdrk/Win32/libpacket.a | Bin 0 -> 23732 bytes plugins/dev9/dev9ghzdrk/Win32/mtfifo.h | 70 + plugins/dev9/dev9ghzdrk/Win32/net.cpp | 51 + plugins/dev9/dev9ghzdrk/Win32/net.h | 29 + plugins/dev9/dev9ghzdrk/Win32/packet32.h | 450 + plugins/dev9/dev9ghzdrk/Win32/pcap_io.h | 161 + plugins/dev9/dev9ghzdrk/Win32/plugin.def | 24 + plugins/dev9/dev9ghzdrk/Win32/resource.h | 25 + plugins/dev9/dev9ghzdrk/Win32/smap.cpp | 875 + plugins/dev9/dev9ghzdrk/Win32/smap.h | 13 + plugins/dev9/dev9ghzdrk/Win32/socket_io.cpp | 294 + plugins/dev9/dev9ghzdrk/Win32/socks.c | 191 + plugins/dev9/dev9ghzdrk/Win32/socks.h | 12 + plugins/dev9/dev9ghzdrk/Win32/tap-win32.cpp | 1080 + plugins/dev9/dev9ghzdrk/Win32/tap.h | 24 + plugins/dev9/dev9ghzdrk/Win32/vl.h | 1419 + .../dev9/dev9ghzdrk/Win32/wpcap_32/Packet.dll | Bin 0 -> 88696 bytes .../dev9/dev9ghzdrk/Win32/wpcap_32/Packet.lib | Bin 0 -> 8674 bytes .../dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.dll | Bin 0 -> 244336 bytes .../dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.lib | Bin 0 -> 17658 bytes .../dev9/dev9ghzdrk/Win32/wpcap_64/Packet.dll | Bin 0 -> 80384 bytes .../dev9/dev9ghzdrk/Win32/wpcap_64/Packet.lib | Bin 0 -> 8286 bytes .../dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.dll | Bin 0 -> 252416 bytes .../dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.lib | Bin 0 -> 17046 bytes plugins/dev9/dev9ghzdrk/flash.cpp | 251 + plugins/dev9/dev9ghzdrk/pcap_io.cpp | 419 + plugins/dev9/dev9null/ReadMe.txt | 32 + plugins/dev9/dev9null/build.sh | 9 + plugins/dev9/dev9null/src/DEV9.h | 17 + plugins/dev9/dev9null/src/Dev9null.sln | 18 + plugins/dev9/dev9null/src/Dev9null.vcproj | 100 + .../dev9null/src/Dev9null_2005_x64.vcproj | 382 + .../dev9null/src/Dev9null_vsnet2005beta1.sln | 26 + .../src/Dev9null_vsnet2005beta1.vcproj | 416 + plugins/dev9/dev9null/src/Makefile | 23 + plugins/dev9/dev9null/src/Makefile.mingw | 51 + plugins/dev9/dev9null/src/PS2Edefs.h | 848 + plugins/dev9/dev9null/src/PS2Etypes.h | 76 + plugins/dev9/dev9null/src/dev9null.c | 152 + plugins/dev9/dev9null/src/dev9null.def | 27 + plugins/fw/FWlinuz/FW.c | 285 + plugins/fw/FWlinuz/FW.h | 62 + plugins/fw/FWlinuz/License.txt | 342 + plugins/fw/FWlinuz/Linux/Config.c | 51 + plugins/fw/FWlinuz/Linux/Config.h | 20 + plugins/fw/FWlinuz/Linux/Linux.c | 75 + plugins/fw/FWlinuz/Linux/Makefile | 34 + plugins/fw/FWlinuz/Linux/callbacks.c | 34 + plugins/fw/FWlinuz/Linux/callbacks.h | 14 + plugins/fw/FWlinuz/Linux/conf.c | 136 + plugins/fw/FWlinuz/Linux/firewire.glade | 300 + plugins/fw/FWlinuz/Linux/interface.c | 219 + plugins/fw/FWlinuz/Linux/interface.h | 6 + plugins/fw/FWlinuz/Linux/support.c | 162 + plugins/fw/FWlinuz/Linux/support.h | 38 + plugins/fw/FWlinuz/PS2Edefs.h | 724 + plugins/fw/FWlinuz/PS2Etypes.h | 43 + plugins/fw/FWlinuz/ReadMe.txt | 25 + plugins/fw/FWlinuz/Win32/Config.c | 45 + plugins/fw/FWlinuz/Win32/FWlinuz.def | 19 + plugins/fw/FWlinuz/Win32/FWlinuz.rc | 123 + plugins/fw/FWlinuz/Win32/FWlinuz.sln | 18 + plugins/fw/FWlinuz/Win32/FireWireNull.ncb | Bin 0 -> 60416 bytes plugins/fw/FWlinuz/Win32/FireWireNull.sln | 18 + plugins/fw/FWlinuz/Win32/FireWireNull.suo | Bin 0 -> 8192 bytes plugins/fw/FWlinuz/Win32/FireWireNull.vcproj | 109 + plugins/fw/FWlinuz/Win32/Makefile | 52 + plugins/fw/FWlinuz/Win32/Win32.c | 80 + plugins/fw/FWlinuz/Win32/afxresmw.h | 5 + plugins/fw/FWlinuz/Win32/plugin.def | 15 + plugins/fw/FWlinuz/Win32/resource.h | 21 + plugins/fw/FWnull/FW.c | 147 + plugins/fw/FWnull/FW.h | 59 + plugins/fw/FWnull/License.txt | 342 + plugins/fw/FWnull/Linux/Config.c | 51 + plugins/fw/FWnull/Linux/Config.h | 20 + plugins/fw/FWnull/Linux/Linux.c | 75 + plugins/fw/FWnull/Linux/Makefile | 35 + plugins/fw/FWnull/Linux/callbacks.c | 34 + plugins/fw/FWnull/Linux/callbacks.h | 14 + plugins/fw/FWnull/Linux/conf.c | 136 + plugins/fw/FWnull/Linux/firewire.glade | 300 + plugins/fw/FWnull/Linux/interface.c | 219 + plugins/fw/FWnull/Linux/interface.h | 6 + plugins/fw/FWnull/Linux/support.c | 162 + plugins/fw/FWnull/Linux/support.h | 38 + plugins/fw/FWnull/PS2Edefs.h | 848 + plugins/fw/FWnull/PS2Etypes.h | 76 + plugins/fw/FWnull/ReadMe.txt | 34 + plugins/fw/FWnull/Win32/Config.c | 51 + plugins/fw/FWnull/Win32/FireWireNull.def | 19 + plugins/fw/FWnull/Win32/FireWireNull.rc | 123 + plugins/fw/FWnull/Win32/FireWireNull.sln | 18 + plugins/fw/FWnull/Win32/FireWireNull.suo | Bin 0 -> 7168 bytes plugins/fw/FWnull/Win32/FireWireNull.vcproj | 112 + .../FWnull/Win32/FireWireNull_2005_x64.vcproj | 400 + .../Win32/FireWireNull_vsnet2005beta1.sln | 26 + .../Win32/FireWireNull_vsnet2005beta1.vcproj | 433 + plugins/fw/FWnull/Win32/Makefile | 29 + plugins/fw/FWnull/Win32/Win32.c | 81 + plugins/fw/FWnull/Win32/afxresmw.h | 5 + plugins/fw/FWnull/Win32/resource.h | 21 + plugins/fw/FWnull/build.sh | 15 + plugins/fw/build.sh | 13 + plugins/gs/GSsoft/License.txt | 342 + plugins/gs/GSsoft/ReadMe.txt | 109 + plugins/gs/GSsoft/Src/Cache.c | 201 + plugins/gs/GSsoft/Src/Cache.h | 30 + plugins/gs/GSsoft/Src/Color.c | 1271 + plugins/gs/GSsoft/Src/Color.h | 40 + plugins/gs/GSsoft/Src/Draw.c | 530 + plugins/gs/GSsoft/Src/Draw.h | 36 + plugins/gs/GSsoft/Src/GS.c | 825 + plugins/gs/GSsoft/Src/GS.h | 575 + plugins/gs/GSsoft/Src/Linux-SDL/Conf.c | 65 + plugins/gs/GSsoft/Src/Linux-SDL/X11.c | 279 + plugins/gs/GSsoft/Src/Linux/Conf.c | 88 + plugins/gs/GSsoft/Src/Linux/Linux.c | 320 + plugins/gs/GSsoft/Src/Linux/Linux.h | 24 + plugins/gs/GSsoft/Src/Linux/Makefile | 46 + plugins/gs/GSsoft/Src/Linux/callbacks.c | 58 + plugins/gs/GSsoft/Src/Linux/callbacks.h | 26 + plugins/gs/GSsoft/Src/Linux/gssoft.glade | 791 + plugins/gs/GSsoft/Src/Linux/interface.c | 517 + plugins/gs/GSsoft/Src/Linux/interface.h | 7 + plugins/gs/GSsoft/Src/Linux/support.c | 162 + plugins/gs/GSsoft/Src/Linux/support.h | 38 + plugins/gs/GSsoft/Src/Mem.c | 174 + plugins/gs/GSsoft/Src/Mem.h | 59 + plugins/gs/GSsoft/Src/PS2Edefs.h | 696 + plugins/gs/GSsoft/Src/PS2Etypes.h | 43 + plugins/gs/GSsoft/Src/Page.c | 354 + plugins/gs/GSsoft/Src/Page.h | 33 + plugins/gs/GSsoft/Src/Prim.c | 390 + plugins/gs/GSsoft/Src/Rec.c | 285 + plugins/gs/GSsoft/Src/Rec.h | 27 + plugins/gs/GSsoft/Src/Regs.c | 1159 + plugins/gs/GSsoft/Src/Regs.h | 24 + plugins/gs/GSsoft/Src/SDL.c | 396 + plugins/gs/GSsoft/Src/SDL_gfxPrimitives.c | 2561 ++ plugins/gs/GSsoft/Src/SDL_gfxPrimitives.h | 125 + .../gs/GSsoft/Src/SDL_gfxPrimitives_font.h | 2567 ++ plugins/gs/GSsoft/Src/Soft.c | 1504 + plugins/gs/GSsoft/Src/Soft.h | 107 + plugins/gs/GSsoft/Src/System.h | 29 + plugins/gs/GSsoft/Src/Texts.c | 544 + plugins/gs/GSsoft/Src/Texts.h | 28 + plugins/gs/GSsoft/Src/Transfer.c | 1328 + plugins/gs/GSsoft/Src/Transfer.h | 27 + plugins/gs/GSsoft/Src/Win32/Conf.c | 110 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.def | 33 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsp | 202 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsw | 29 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.ncb | Bin 0 -> 273408 bytes plugins/gs/GSsoft/Src/Win32/GSsoftdx.rc | 174 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.sln | 18 + plugins/gs/GSsoft/Src/Win32/GSsoftdx.suo | Bin 0 -> 8192 bytes plugins/gs/GSsoft/Src/Win32/GSsoftdx.vcproj | 339 + plugins/gs/GSsoft/Src/Win32/Makefile | 58 + plugins/gs/GSsoft/Src/Win32/SDL.c | 225 + plugins/gs/GSsoft/Src/Win32/Win32.c | 274 + plugins/gs/GSsoft/Src/Win32/Win32.h | 4 + plugins/gs/GSsoft/Src/Win32/afxresmw.h | 5 + plugins/gs/GSsoft/Src/Win32/plugin.def | 31 + plugins/gs/GSsoft/Src/Win32/plugin.h | 18 + plugins/gs/GSsoft/Src/Win32/resource.h | 42 + plugins/gs/GSsoft/Src/avcodec.h | 1688 + plugins/gs/GSsoft/Src/common.h | 1142 + plugins/gs/GSsoft/Src/ffmpeg/avformat.h | 544 + plugins/gs/GSsoft/Src/ffmpeg/avio.h | 169 + plugins/gs/GSsoft/Src/ffmpeg/rtp.h | 40 + plugins/gs/GSsoft/Src/ffmpeg/rtsp.h | 90 + plugins/gs/GSsoft/Src/ffmpeg/rtspcodes.h | 11 + plugins/gs/GSsoft/Src/scale2x.c | 141 + plugins/gs/GSsoft/Src/scale2x.h | 17 + plugins/gs/GSsoft/Src/x86/ix86.h | 1020 + plugins/gs/GSsoft/Src/x86/ix86_cpudetect.c | 510 + plugins/gs/build.sh | 10 + plugins/gs/gsdx9/GS.cpp | 441 + plugins/gs/gsdx9/GS.h | 945 + plugins/gs/gsdx9/GSCapture.cpp | 309 + plugins/gs/gsdx9/GSCapture.h | 40 + plugins/gs/gsdx9/GSCaptureDlg.cpp | 230 + plugins/gs/gsdx9/GSCaptureDlg.h | 70 + plugins/gs/gsdx9/GSHash.cpp | 181 + plugins/gs/gsdx9/GSHash.h | 26 + plugins/gs/gsdx9/GSLocalMemory.cpp | 2859 ++ plugins/gs/gsdx9/GSLocalMemory.h | 321 + plugins/gs/gsdx9/GSPerfMon.cpp | 109 + plugins/gs/gsdx9/GSPerfMon.h | 52 + plugins/gs/gsdx9/GSRegs.cpp | 1033 + plugins/gs/gsdx9/GSRenderer.cpp | 23 + plugins/gs/gsdx9/GSRenderer.h | 95 + plugins/gs/gsdx9/GSRendererHW.cpp | 1310 + plugins/gs/gsdx9/GSRendererHW.h | 89 + plugins/gs/gsdx9/GSRendererNull.cpp | 101 + plugins/gs/gsdx9/GSRendererNull.h | 41 + plugins/gs/gsdx9/GSRendererSoft.cpp | 1113 + plugins/gs/gsdx9/GSRendererSoft.h | 112 + plugins/gs/gsdx9/GSSettingsDlg.cpp | 239 + plugins/gs/gsdx9/GSSettingsDlg.h | 58 + plugins/gs/gsdx9/GSSoftVertex.cpp | 27 + plugins/gs/gsdx9/GSSoftVertex.h | 309 + plugins/gs/gsdx9/GSSoftVertexFP.h | 259 + plugins/gs/gsdx9/GSSoftVertexFX.h | 377 + plugins/gs/gsdx9/GSState.cpp | 1135 + plugins/gs/gsdx9/GSState.h | 446 + plugins/gs/gsdx9/GSTables.cpp | 231 + plugins/gs/gsdx9/GSTables.h | 35 + plugins/gs/gsdx9/GSTextureCache.cpp | 1226 + plugins/gs/gsdx9/GSTextureCache.h | 133 + plugins/gs/gsdx9/GSTransfer.cpp | 216 + plugins/gs/gsdx9/GSUtil.cpp | 79 + plugins/gs/gsdx9/GSUtil.h | 26 + plugins/gs/gsdx9/GSVertexList.cpp | 23 + plugins/gs/gsdx9/GSVertexList.h | 82 + plugins/gs/gsdx9/GSWnd.cpp | 62 + plugins/gs/gsdx9/GSWnd.h | 37 + plugins/gs/gsdx9/GSdx9.cpp | 93 + plugins/gs/gsdx9/GSdx9.def | 31 + plugins/gs/gsdx9/GSdx9.h | 55 + plugins/gs/gsdx9/GSdx9.icproj | 539 + plugins/gs/gsdx9/GSdx9.rc | 220 + plugins/gs/gsdx9/GSdx9_vs2005.sln | 54 + plugins/gs/gsdx9/GSdx9_vs2005.vcproj | 1429 + plugins/gs/gsdx9/baseclasses/Amvideo.h | 433 + plugins/gs/gsdx9/baseclasses/activex.rcv | 142 + plugins/gs/gsdx9/baseclasses/activex.ver | 56 + plugins/gs/gsdx9/baseclasses/amaudio.h | 54 + plugins/gs/gsdx9/baseclasses/amextra.cpp | 111 + plugins/gs/gsdx9/baseclasses/amextra.h | 56 + plugins/gs/gsdx9/baseclasses/amfilter.cpp | 5203 +++ plugins/gs/gsdx9/baseclasses/amfilter.h | 1587 + plugins/gs/gsdx9/baseclasses/amvideo.cpp | 275 + plugins/gs/gsdx9/baseclasses/audevcod.h | 53 + .../gs/gsdx9/baseclasses/baseclasses.vcproj | 444 + ...asses.vcproj.REFRACTION.Administrator.user | 65 + plugins/gs/gsdx9/baseclasses/cache.h | 74 + plugins/gs/gsdx9/baseclasses/combase.cpp | 256 + plugins/gs/gsdx9/baseclasses/combase.h | 319 + plugins/gs/gsdx9/baseclasses/comlite.h | 26 + plugins/gs/gsdx9/baseclasses/cprop.cpp | 380 + plugins/gs/gsdx9/baseclasses/cprop.h | 95 + plugins/gs/gsdx9/baseclasses/ctlutil.cpp | 2531 ++ plugins/gs/gsdx9/baseclasses/ctlutil.h | 919 + plugins/gs/gsdx9/baseclasses/ddmm.cpp | 129 + plugins/gs/gsdx9/baseclasses/ddmm.h | 28 + plugins/gs/gsdx9/baseclasses/dllentry.cpp | 333 + plugins/gs/gsdx9/baseclasses/dllsetup.cpp | 727 + plugins/gs/gsdx9/baseclasses/dllsetup.h | 46 + plugins/gs/gsdx9/baseclasses/dshow.h | 83 + plugins/gs/gsdx9/baseclasses/dsschedule.h | 128 + plugins/gs/gsdx9/baseclasses/dvdevcod.h | 363 + plugins/gs/gsdx9/baseclasses/dvdmedia.h | 427 + plugins/gs/gsdx9/baseclasses/edevdefs.h | 531 + plugins/gs/gsdx9/baseclasses/errors.h | 47 + plugins/gs/gsdx9/baseclasses/evcode.h | 428 + plugins/gs/gsdx9/baseclasses/fourcc.h | 101 + plugins/gs/gsdx9/baseclasses/measure.h | 222 + plugins/gs/gsdx9/baseclasses/msgthrd.h | 120 + plugins/gs/gsdx9/baseclasses/mtype.cpp | 477 + plugins/gs/gsdx9/baseclasses/mtype.h | 89 + plugins/gs/gsdx9/baseclasses/outputq.cpp | 794 + plugins/gs/gsdx9/baseclasses/outputq.h | 137 + plugins/gs/gsdx9/baseclasses/pstream.cpp | 196 + plugins/gs/gsdx9/baseclasses/pstream.h | 114 + plugins/gs/gsdx9/baseclasses/pullpin.cpp | 527 + plugins/gs/gsdx9/baseclasses/pullpin.h | 152 + plugins/gs/gsdx9/baseclasses/refclock.cpp | 340 + plugins/gs/gsdx9/baseclasses/refclock.h | 171 + plugins/gs/gsdx9/baseclasses/reftime.h | 116 + plugins/gs/gsdx9/baseclasses/renbase.cpp | 2844 ++ plugins/gs/gsdx9/baseclasses/renbase.h | 478 + plugins/gs/gsdx9/baseclasses/schedule.cpp | 284 + plugins/gs/gsdx9/baseclasses/schedule.h | 128 + plugins/gs/gsdx9/baseclasses/seekpt.cpp | 83 + plugins/gs/gsdx9/baseclasses/seekpt.h | 30 + plugins/gs/gsdx9/baseclasses/source.cpp | 522 + plugins/gs/gsdx9/baseclasses/source.h | 172 + plugins/gs/gsdx9/baseclasses/streams.h | 190 + plugins/gs/gsdx9/baseclasses/strmctl.cpp | 401 + plugins/gs/gsdx9/baseclasses/strmctl.h | 157 + plugins/gs/gsdx9/baseclasses/strmiids.lib | Bin 0 -> 309056 bytes plugins/gs/gsdx9/baseclasses/sysclock.cpp | 74 + plugins/gs/gsdx9/baseclasses/sysclock.h | 39 + plugins/gs/gsdx9/baseclasses/transfrm.cpp | 1016 + plugins/gs/gsdx9/baseclasses/transfrm.h | 304 + plugins/gs/gsdx9/baseclasses/transip.cpp | 966 + plugins/gs/gsdx9/baseclasses/transip.h | 250 + plugins/gs/gsdx9/baseclasses/vfwmsgs.h | 1365 + plugins/gs/gsdx9/baseclasses/videoctl.cpp | 715 + plugins/gs/gsdx9/baseclasses/videoctl.h | 178 + plugins/gs/gsdx9/baseclasses/vtrans.cpp | 468 + plugins/gs/gsdx9/baseclasses/vtrans.h | 143 + plugins/gs/gsdx9/baseclasses/winctrl.cpp | 2050 ++ plugins/gs/gsdx9/baseclasses/winctrl.h | 224 + plugins/gs/gsdx9/baseclasses/winutil.cpp | 2681 ++ plugins/gs/gsdx9/baseclasses/winutil.h | 413 + plugins/gs/gsdx9/baseclasses/wxdebug.cpp | 1420 + plugins/gs/gsdx9/baseclasses/wxdebug.h | 393 + plugins/gs/gsdx9/baseclasses/wxlist.cpp | 885 + plugins/gs/gsdx9/baseclasses/wxlist.h | 543 + plugins/gs/gsdx9/baseclasses/wxutil.cpp | 1240 + plugins/gs/gsdx9/baseclasses/wxutil.h | 540 + plugins/gs/gsdx9/res/GSdx9.rc2 | 37 + plugins/gs/gsdx9/res/hlsl_merge.fx | 101 + plugins/gs/gsdx9/res/hlsl_rb.fx | 8 + plugins/gs/gsdx9/res/hlsl_tfx.fx | 379 + plugins/gs/gsdx9/res/logo1.bmp | Bin 0 -> 56002 bytes plugins/gs/gsdx9/res/ps11_en00.psh | 11 + plugins/gs/gsdx9/res/ps11_en01.psh | 12 + plugins/gs/gsdx9/res/ps11_en10.psh | 17 + plugins/gs/gsdx9/res/ps11_en11.psh | 19 + plugins/gs/gsdx9/res/ps11_tfx000.psh | 13 + plugins/gs/gsdx9/res/ps11_tfx010.psh | 13 + plugins/gs/gsdx9/res/ps11_tfx011.psh | 13 + plugins/gs/gsdx9/res/ps11_tfx1x0.psh | 13 + plugins/gs/gsdx9/res/ps11_tfx1x1.psh | 13 + plugins/gs/gsdx9/res/ps11_tfx200.psh | 14 + plugins/gs/gsdx9/res/ps11_tfx210.psh | 14 + plugins/gs/gsdx9/res/ps11_tfx211.psh | 15 + plugins/gs/gsdx9/res/ps11_tfx300.psh | 14 + plugins/gs/gsdx9/res/ps11_tfx310.psh | 14 + plugins/gs/gsdx9/res/ps11_tfx311.psh | 14 + plugins/gs/gsdx9/res/ps11_tfx4xx.psh | 4 + plugins/gs/gsdx9/res/ps14_en00.psh | 13 + plugins/gs/gsdx9/res/ps14_en01.psh | 16 + plugins/gs/gsdx9/res/ps14_en10.psh | 20 + plugins/gs/gsdx9/res/ps14_en11.psh | 23 + plugins/gs/gsdx9/resource.h | 55 + plugins/gs/gsdx9/stdafx.cpp | 7 + plugins/gs/gsdx9/stdafx.h | 95 + plugins/gs/gsdx9/x86-32.asm | 1335 + plugins/gs/gsdx9/x86-64.asm | 1418 + plugins/gs/gsdx9/x86.cpp | 836 + plugins/gs/gsdx9/x86.h | 238 + plugins/gs/zerogs/build.sh | 32 + plugins/gs/zerogs/dx/GS.h | 745 + plugins/gs/zerogs/dx/GSmain.cpp | 1078 + plugins/gs/zerogs/dx/Mem.cpp | 902 + plugins/gs/zerogs/dx/Mem.h | 486 + plugins/gs/zerogs/dx/PS2Edefs.h | 848 + plugins/gs/zerogs/dx/PS2Etypes.h | 76 + plugins/gs/zerogs/dx/README.txt | 13 + plugins/gs/zerogs/dx/Regs.cpp | 1113 + plugins/gs/zerogs/dx/Regs.h | 122 + plugins/gs/zerogs/dx/Win32/Conf.cpp | 117 + plugins/gs/zerogs/dx/Win32/GSsoftdx.def | 36 + plugins/gs/zerogs/dx/Win32/Win32.cpp | 269 + plugins/gs/zerogs/dx/Win32/Win32.h | 9 + plugins/gs/zerogs/dx/Win32/aviUtil.h | 484 + plugins/gs/zerogs/dx/Win32/copytopcsx2.bat | 4 + plugins/gs/zerogs/dx/Win32/plugin.def | 31 + plugins/gs/zerogs/dx/Win32/ps2fx.dat | Bin 0 -> 3457692 bytes plugins/gs/zerogs/dx/Win32/resource.h | 45 + plugins/gs/zerogs/dx/Win32/resrc1.h | 87 + plugins/gs/zerogs/dx/Win32/zerogs.bmp | Bin 0 -> 921654 bytes plugins/gs/zerogs/dx/Win32/zerogs.rc | 235 + plugins/gs/zerogs/dx/Win32/zerogs.sln | 24 + plugins/gs/zerogs/dx/Win32/zerogs.vcproj | 355 + plugins/gs/zerogs/dx/Win32/zerogs_2005.sln | 22 + plugins/gs/zerogs/dx/Win32/zerogs_2005.vcproj | 467 + .../gs/zerogs/dx/Win32/zerogs_2005_x64.vcproj | 743 + plugins/gs/zerogs/dx/Win32/zerogs_2008.vcproj | 465 + .../dx/ZeroGSShaders/ZeroGSShaders.vcproj | 185 + .../zerogs/dx/ZeroGSShaders/copytozerogs.bat | 1 + .../zerogs/dx/ZeroGSShaders/zerogsshaders.cpp | 407 + .../zerogs/dx/ZeroGSShaders/zerogsshaders.h | 118 + plugins/gs/zerogs/dx/backup.bat | 4 + plugins/gs/zerogs/dx/buildshaders.bat | 3 + plugins/gs/zerogs/dx/common.h | 1142 + plugins/gs/zerogs/dx/memcpy_amd.cpp | 479 + plugins/gs/zerogs/dx/ps2hw.fx | 993 + plugins/gs/zerogs/dx/ps2hw_ctx0.fx | 33 + plugins/gs/zerogs/dx/ps2hw_ctx1.fx | 32 + plugins/gs/zerogs/dx/targets.cpp | 3729 +++ plugins/gs/zerogs/dx/targets.h | 232 + plugins/gs/zerogs/dx/x86-32.asm | 1353 + plugins/gs/zerogs/dx/x86-64.asm | 1090 + plugins/gs/zerogs/dx/x86.cpp | 573 + plugins/gs/zerogs/dx/x86.h | 184 + plugins/gs/zerogs/dx/zerogs.cpp | 5064 +++ plugins/gs/zerogs/dx/zerogs.h | 512 + plugins/gs/zerogs/opengl/GS.h | 844 + plugins/gs/zerogs/opengl/GSmain.cpp | 1443 + plugins/gs/zerogs/opengl/Linux/Conf.cpp | 104 + plugins/gs/zerogs/opengl/Linux/Linux.cpp | 425 + plugins/gs/zerogs/opengl/Linux/Linux.h | 23 + plugins/gs/zerogs/opengl/Linux/Makefile.am | 6 + plugins/gs/zerogs/opengl/Linux/buildgui.sh | 9 + plugins/gs/zerogs/opengl/Linux/callbacks.c | 34 + plugins/gs/zerogs/opengl/Linux/callbacks.h | 14 + plugins/gs/zerogs/opengl/Linux/interface.c | 325 + plugins/gs/zerogs/opengl/Linux/interface.h | 6 + plugins/gs/zerogs/opengl/Linux/support.c | 144 + plugins/gs/zerogs/opengl/Linux/support.h | 69 + plugins/gs/zerogs/opengl/Linux/zerogs.glade | 674 + plugins/gs/zerogs/opengl/Makefile.am | 48 + plugins/gs/zerogs/opengl/Mem.cpp | 903 + plugins/gs/zerogs/opengl/Mem.h | 487 + plugins/gs/zerogs/opengl/PS2Edefs.h | 855 + plugins/gs/zerogs/opengl/PS2Etypes.h | 88 + plugins/gs/zerogs/opengl/README.txt | 13 + plugins/gs/zerogs/opengl/Regs.cpp | 1007 + plugins/gs/zerogs/opengl/Regs.h | 101 + plugins/gs/zerogs/opengl/Win32/Conf.cpp | 100 + plugins/gs/zerogs/opengl/Win32/Win32.cpp | 246 + plugins/gs/zerogs/opengl/Win32/Win32.h | 9 + plugins/gs/zerogs/opengl/Win32/aviUtil.h | 484 + .../gs/zerogs/opengl/Win32/copytopcsx2.bat | 4 + plugins/gs/zerogs/opengl/Win32/jconfig.h | 52 + plugins/gs/zerogs/opengl/Win32/jmorecfg.h | 363 + plugins/gs/zerogs/opengl/Win32/jpeglib.h | 1099 + plugins/gs/zerogs/opengl/Win32/libjpeg.lib | Bin 0 -> 470518 bytes plugins/gs/zerogs/opengl/Win32/libjpeg64.lib | Bin 0 -> 1010392 bytes plugins/gs/zerogs/opengl/Win32/ps2hw.dat | Bin 0 -> 106682 bytes plugins/gs/zerogs/opengl/Win32/resource.h | 45 + plugins/gs/zerogs/opengl/Win32/resrc1.h | 79 + plugins/gs/zerogs/opengl/Win32/zerogs.bmp | Bin 0 -> 921654 bytes plugins/gs/zerogs/opengl/Win32/zerogs.def | 36 + plugins/gs/zerogs/opengl/Win32/zerogs.rc | 228 + .../gs/zerogs/opengl/Win32/zerogsogl.vcproj | 437 + .../zerogs/opengl/Win32/zerogsogl_2005.vcproj | 583 + .../opengl/Win32/zerogsogl_2005_x64.vcproj | 874 + plugins/gs/zerogs/opengl/Win32/zlib/adler32.c | 74 + .../gs/zerogs/opengl/Win32/zlib/compress.c | 79 + plugins/gs/zerogs/opengl/Win32/zlib/crc32.c | 311 + plugins/gs/zerogs/opengl/Win32/zlib/crc32.h | 441 + plugins/gs/zerogs/opengl/Win32/zlib/deflate.c | 1502 + plugins/gs/zerogs/opengl/Win32/zlib/deflate.h | 326 + plugins/gs/zerogs/opengl/Win32/zlib/gzio.c | 1005 + plugins/gs/zerogs/opengl/Win32/zlib/infback.c | 619 + plugins/gs/zerogs/opengl/Win32/zlib/inffast.c | 305 + plugins/gs/zerogs/opengl/Win32/zlib/inffast.h | 11 + .../gs/zerogs/opengl/Win32/zlib/inffixed.h | 94 + plugins/gs/zerogs/opengl/Win32/zlib/inflate.c | 1270 + plugins/gs/zerogs/opengl/Win32/zlib/inflate.h | 117 + .../gs/zerogs/opengl/Win32/zlib/inftrees.c | 321 + .../gs/zerogs/opengl/Win32/zlib/inftrees.h | 55 + plugins/gs/zerogs/opengl/Win32/zlib/trees.c | 1215 + plugins/gs/zerogs/opengl/Win32/zlib/trees.h | 128 + plugins/gs/zerogs/opengl/Win32/zlib/uncompr.c | 61 + plugins/gs/zerogs/opengl/Win32/zlib/zconf.h | 323 + plugins/gs/zerogs/opengl/Win32/zlib/zlib.h | 1200 + plugins/gs/zerogs/opengl/Win32/zlib/zutil.c | 319 + plugins/gs/zerogs/opengl/Win32/zlib/zutil.h | 258 + .../zerogs/opengl/ZeroGSShaders/Makefile.am | 2 + .../gs/zerogs/opengl/ZeroGSShaders/ZLib.lib | Bin 0 -> 101154 bytes .../opengl/ZeroGSShaders/ZeroGSShaders.vcproj | 191 + .../ZeroGSShaders/ZeroGSShaders_2005.sln | 23 + .../ZeroGSShaders/ZeroGSShaders_2005.vcproj | 335 + .../opengl/ZeroGSShaders/copytozerogs.bat | 1 + .../opengl/ZeroGSShaders/zerogsshaders.cpp | 337 + .../opengl/ZeroGSShaders/zerogsshaders.h | 89 + .../zerogs/opengl/ZeroGSShaders/zlib/crc32.h | 441 + .../opengl/ZeroGSShaders/zlib/deflate.h | 331 + .../opengl/ZeroGSShaders/zlib/inffast.h | 11 + .../opengl/ZeroGSShaders/zlib/inffixed.h | 94 + .../opengl/ZeroGSShaders/zlib/inflate.h | 115 + .../opengl/ZeroGSShaders/zlib/inftrees.h | 55 + .../zerogs/opengl/ZeroGSShaders/zlib/trees.h | 128 + .../zerogs/opengl/ZeroGSShaders/zlib/zconf.h | 332 + .../opengl/ZeroGSShaders/zlib/zconf.in.h | 332 + .../zerogs/opengl/ZeroGSShaders/zlib/zlib.h | 1357 + .../zerogs/opengl/ZeroGSShaders/zlib/zutil.h | 269 + .../gs/zerogs/opengl/ZeroGSShaders/zpipe.cpp | 115 + .../gs/zerogs/opengl/ZeroGSShaders/zpipe.h | 7 + plugins/gs/zerogs/opengl/buildshaders.bat | 3 + plugins/gs/zerogs/opengl/common.h | 1142 + plugins/gs/zerogs/opengl/compile | 1 + plugins/gs/zerogs/opengl/configure | 6353 ++++ plugins/gs/zerogs/opengl/configure.ac | 149 + plugins/gs/zerogs/opengl/ctx0/ps2hw_ctx.fx | 24 + plugins/gs/zerogs/opengl/ctx1/ps2hw_ctx.fx | 23 + plugins/gs/zerogs/opengl/depcomp | 529 + plugins/gs/zerogs/opengl/glprocs.c | 17864 ++++++++++ plugins/gs/zerogs/opengl/glprocs.h | 2213 ++ plugins/gs/zerogs/opengl/install-sh | 323 + plugins/gs/zerogs/opengl/memcpy_amd.cpp | 479 + plugins/gs/zerogs/opengl/missing | 360 + plugins/gs/zerogs/opengl/mkinstalldirs | 158 + plugins/gs/zerogs/opengl/ps2hw.fx | 841 + plugins/gs/zerogs/opengl/rasterfont.cpp | 147 + plugins/gs/zerogs/opengl/rasterfont.h | 22 + plugins/gs/zerogs/opengl/targets.cpp | 3544 ++ plugins/gs/zerogs/opengl/targets.h | 160 + plugins/gs/zerogs/opengl/x86-32.S | 1002 + plugins/gs/zerogs/opengl/x86-32.asm | 652 + plugins/gs/zerogs/opengl/x86-64.S | 906 + plugins/gs/zerogs/opengl/x86-64.asm | 1091 + plugins/gs/zerogs/opengl/x86.cpp | 571 + plugins/gs/zerogs/opengl/x86.h | 182 + plugins/gs/zerogs/opengl/zerogs.cpp | 5946 ++++ plugins/gs/zerogs/opengl/zerogs.h | 555 + plugins/gs/zerogs/opengl/zerogsmath.h | 902 + plugins/gs/zerogs/opengl/zpipe.cpp | 115 + plugins/gs/zerogs/opengl/zpipe.h | 7 + plugins/pad/PADwin/ReadMe.txt | 89 + plugins/pad/PADwin/Src/Conf.c | 98 + plugins/pad/PADwin/Src/Linux.c | 210 + plugins/pad/PADwin/Src/Makefile | 25 + plugins/pad/PADwin/Src/Makefile.mingw | 29 + plugins/pad/PADwin/Src/PAD.c | 528 + plugins/pad/PADwin/Src/PAD.h | 107 + plugins/pad/PADwin/Src/PADwinKeyb.def | 22 + plugins/pad/PADwin/Src/PADwinKeyb.dsp | 114 + plugins/pad/PADwin/Src/PADwinKeyb.dsw | 29 + plugins/pad/PADwin/Src/PADwinKeyb.sln | 18 + plugins/pad/PADwin/Src/PADwinKeyb.suo | Bin 0 -> 9216 bytes plugins/pad/PADwin/Src/PADwinKeyb.vcproj | 125 + .../PADwin/Src/PADwinKeyb_vsnet2005beta1.sln | 26 + .../Src/PADwinKeyb_vsnet2005beta1.vcproj | 385 + plugins/pad/PADwin/Src/PADwnKeyb.rc | 150 + plugins/pad/PADwin/Src/PS2Edefs.h | 812 + plugins/pad/PADwin/Src/PS2Etypes.h | 75 + plugins/pad/PADwin/Src/Win32.c | 549 + plugins/pad/PADwin/Src/afxresmw.h | 5 + plugins/pad/PADwin/Src/callbacks.c | 58 + plugins/pad/PADwin/Src/callbacks.h | 26 + plugins/pad/PADwin/Src/controller.bmp | Bin 0 -> 490056 bytes plugins/pad/PADwin/Src/interface.c | 483 + plugins/pad/PADwin/Src/interface.h | 6 + plugins/pad/PADwin/Src/mingw/Makefile.win | 43 + plugins/pad/PADwin/Src/mingw/PADwinKeyb.dev | 156 + .../pad/PADwin/Src/mingw/PADwinKeyb.layout | 56 + plugins/pad/PADwin/Src/mingw/afxres.h | 5 + plugins/pad/PADwin/Src/plugin.def | 17 + plugins/pad/PADwin/Src/ps2pad.bmp | Bin 0 -> 320918 bytes plugins/pad/PADwin/Src/resource.h | 70 + plugins/pad/PADwin/Src/support.c | 162 + plugins/pad/PADwin/Src/support.h | 38 + plugins/pad/PADwin/build.sh | 15 + plugins/pad/SSSPSXPAD/PadSSSPSX.cpp | 1041 + plugins/pad/SSSPSXPAD/PadSSSPSX.def | 22 + plugins/pad/SSSPSXPAD/PadSSSPSX.h | 45 + plugins/pad/SSSPSXPAD/PadSSSPSX.rc | 152 + plugins/pad/SSSPSXPAD/PadSSSPSX.vcproj | 213 + .../pad/SSSPSXPAD/PadSSSPSX_2005_x64.vcproj | 490 + .../pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.sln | 26 + .../SSSPSXPAD/PadSSSPSX_vc2005beta2.vcproj | 488 + plugins/pad/SSSPSXPAD/PadSSSPSXres.h | 59 + plugins/pad/SSSPSXPAD/licence.txt | 1 + plugins/pad/SSSPSXPAD/readmewip.txt | 48 + plugins/pad/build.sh | 24 + plugins/pad/zeropad/Linux/callbacks.h | 46 + plugins/pad/zeropad/Linux/interface.c | 640 + plugins/pad/zeropad/Linux/interface.h | 6 + plugins/pad/zeropad/Linux/linux.cpp | 829 + plugins/pad/zeropad/Linux/support.c | 144 + plugins/pad/zeropad/Linux/support.h | 69 + plugins/pad/zeropad/Linux/zeropad.glade | 1194 + plugins/pad/zeropad/Makefile.am | 29 + plugins/pad/zeropad/PS2Edefs.h | 855 + plugins/pad/zeropad/PS2Etypes.h | 88 + plugins/pad/zeropad/Windows/ZeroPAD.def | 18 + plugins/pad/zeropad/Windows/ZeroPAD.rc | 136 + plugins/pad/zeropad/Windows/ZeroPAD.vcproj | 168 + .../pad/zeropad/Windows/ZeroPAD_2005.vcproj | 236 + .../zeropad/Windows/ZeroPAD_2005_x64.vcproj | 400 + .../pad/zeropad/Windows/ZeroPAD_2008.vcproj | 235 + plugins/pad/zeropad/Windows/libs/pthread.h | 1368 + .../pad/zeropad/Windows/libs/pthreadVC2.lib | Bin 0 -> 29280 bytes plugins/pad/zeropad/Windows/libs/sched.h | 178 + plugins/pad/zeropad/Windows/libs/semaphore.h | 166 + plugins/pad/zeropad/Windows/resource.h | 70 + plugins/pad/zeropad/Windows/win.cpp | 454 + plugins/pad/zeropad/build.sh | 30 + plugins/pad/zeropad/configure.ac | 103 + plugins/pad/zeropad/depcomp | 529 + plugins/pad/zeropad/mkinstalldirs | 158 + plugins/pad/zeropad/zeropad.cpp | 482 + plugins/pad/zeropad/zeropad.h | 135 + plugins/spu2/PeopsSPU2/Filemap.txt | 49 + plugins/spu2/PeopsSPU2/Makefile | 75 + plugins/spu2/PeopsSPU2/Makefile.win | 79 + plugins/spu2/PeopsSPU2/_bsc.txt | 17 + plugins/spu2/PeopsSPU2/adsr.c | 668 + plugins/spu2/PeopsSPU2/adsr.h | 28 + plugins/spu2/PeopsSPU2/alsa.c | 206 + plugins/spu2/PeopsSPU2/alsa.h | 30 + plugins/spu2/PeopsSPU2/build.sh | 20 + plugins/spu2/PeopsSPU2/cfg.c | 256 + plugins/spu2/PeopsSPU2/cfg.h | 36 + plugins/spu2/PeopsSPU2/clean.bat | 3 + plugins/spu2/PeopsSPU2/debug.c | 442 + plugins/spu2/PeopsSPU2/debug.h | 34 + plugins/spu2/PeopsSPU2/dma.c | 414 + plugins/spu2/PeopsSPU2/dma.h | 28 + plugins/spu2/PeopsSPU2/dsound.c | 268 + plugins/spu2/PeopsSPU2/dsound.h | 2357 ++ plugins/spu2/PeopsSPU2/dsoundoss.h | 36 + plugins/spu2/PeopsSPU2/externals.h | 364 + plugins/spu2/PeopsSPU2/freeze.c | 246 + plugins/spu2/PeopsSPU2/gauss_i.h | 162 + plugins/spu2/PeopsSPU2/mingw/afxres.h | 2 + plugins/spu2/PeopsSPU2/oss.c | 190 + plugins/spu2/PeopsSPU2/oss.h | 37 + plugins/spu2/PeopsSPU2/psemu.c | 0 plugins/spu2/PeopsSPU2/psemuxa.h | 28 + plugins/spu2/PeopsSPU2/record.c | 184 + plugins/spu2/PeopsSPU2/record.h | 12 + plugins/spu2/PeopsSPU2/registers.c | 2095 ++ plugins/spu2/PeopsSPU2/registers.h | 820 + plugins/spu2/PeopsSPU2/regs.h | 43 + plugins/spu2/PeopsSPU2/res/spu2PeopsSound.rc2 | 13 + plugins/spu2/PeopsSPU2/resource.h | 161 + plugins/spu2/PeopsSPU2/reverb.c | 420 + plugins/spu2/PeopsSPU2/reverb.h | 33 + plugins/spu2/PeopsSPU2/spu.c | 1311 + plugins/spu2/PeopsSPU2/spu.h | 33 + plugins/spu2/PeopsSPU2/spu2PeopsSound.aps | Bin 0 -> 51420 bytes plugins/spu2/PeopsSPU2/spu2PeopsSound.c | 44 + plugins/spu2/PeopsSPU2/spu2PeopsSound.def | 34 + plugins/spu2/PeopsSPU2/spu2PeopsSound.dev | 478 + plugins/spu2/PeopsSPU2/spu2PeopsSound.dsp | 282 + plugins/spu2/PeopsSPU2/spu2PeopsSound.dsw | 29 + plugins/spu2/PeopsSPU2/spu2PeopsSound.layout | 284 + plugins/spu2/PeopsSPU2/spu2PeopsSound.opt | Bin 0 -> 54784 bytes plugins/spu2/PeopsSPU2/spu2PeopsSound.plg | 81 + plugins/spu2/PeopsSPU2/spu2PeopsSound.rc | 372 + plugins/spu2/PeopsSPU2/spu2PeopsSound.sln | 21 + plugins/spu2/PeopsSPU2/spu2PeopsSound.vcproj | 476 + .../spu2/PeopsSPU2/spu2PeopsSound_2005.sln | 19 + .../spu2/PeopsSPU2/spu2PeopsSound_2005.vcproj | 620 + .../PeopsSPU2/spu2PeopsSound_2005_x64.sln | 20 + .../PeopsSPU2/spu2PeopsSound_2005_x64.vcproj | 1074 + .../spu2/PeopsSPU2/spu2PeopsSound_2008.vcproj | 619 + .../spu2/PeopsSPU2/spu2PeopsSound_private.h | 23 + .../spu2/PeopsSPU2/spu2PeopsSound_private.rc | 5 + .../spu2/PeopsSPU2/spu2PeopsSound_private.res | Bin 0 -> 10492 bytes plugins/spu2/PeopsSPU2/spunew.c | 1272 + plugins/spu2/PeopsSPU2/stdafx.c | 8 + plugins/spu2/PeopsSPU2/stdafx.h | 86 + plugins/spu2/PeopsSPU2/xa.c | 363 + plugins/spu2/PeopsSPU2/xa.h | 29 + plugins/spu2/SPU2null/License.txt | 342 + plugins/spu2/SPU2null/ReadMe.txt | 39 + plugins/spu2/SPU2null/Src/Changelog.txt | 30 + plugins/spu2/SPU2null/Src/Config.cpp | 51 + plugins/spu2/SPU2null/Src/Makefile | 25 + plugins/spu2/SPU2null/Src/Makefile.mingw | 51 + plugins/spu2/SPU2null/Src/PS2Edefs.h | 812 + plugins/spu2/SPU2null/Src/PS2Etypes.h | 76 + plugins/spu2/SPU2null/Src/SPU2.cpp | 1213 + plugins/spu2/SPU2null/Src/SPU2.h | 280 + plugins/spu2/SPU2null/Src/SPU2null.def | 31 + plugins/spu2/SPU2null/Src/SPU2null.ncb | Bin 0 -> 142336 bytes plugins/spu2/SPU2null/Src/SPU2null.rc | 129 + plugins/spu2/SPU2null/Src/SPU2null.sln | 21 + plugins/spu2/SPU2null/Src/SPU2null.vcproj | 165 + plugins/spu2/SPU2null/Src/SPU2null_2005.sln | 20 + .../spu2/SPU2null/Src/SPU2null_2005.vcproj | 234 + .../spu2/SPU2null/Src/SPU2null_2005_x64.sln | 20 + .../SPU2null/Src/SPU2null_2005_x64.vcproj | 398 + .../spu2/SPU2null/Src/SPU2null_2008.vcproj | 233 + plugins/spu2/SPU2null/Src/Win32.cpp | 80 + plugins/spu2/SPU2null/Src/mingw/Makefile.win | 43 + plugins/spu2/SPU2null/Src/mingw/SPU2null.dev | 148 + plugins/spu2/SPU2null/Src/mingw/afxres.h | 5 + plugins/spu2/SPU2null/Src/mingw/plugin.def | 22 + plugins/spu2/SPU2null/Src/resource.h | 21 + plugins/spu2/SPU2null/build.sh | 12 + plugins/spu2/build.sh | 31 + plugins/spu2/zerospu2/Linux.cpp | 362 + plugins/spu2/zerospu2/Makefile.am | 31 + plugins/spu2/zerospu2/PS2Edefs.h | 855 + plugins/spu2/zerospu2/PS2Etypes.h | 88 + .../spu2/zerospu2/SoundTouch/3dnow_win.cpp | 350 + plugins/spu2/zerospu2/SoundTouch/AAFilter.cpp | 184 + plugins/spu2/zerospu2/SoundTouch/AAFilter.h | 91 + plugins/spu2/zerospu2/SoundTouch/BPMDetect.h | 159 + .../zerospu2/SoundTouch/FIFOSampleBuffer.cpp | 252 + .../zerospu2/SoundTouch/FIFOSampleBuffer.h | 174 + .../spu2/zerospu2/SoundTouch/FIFOSamplePipe.h | 217 + .../spu2/zerospu2/SoundTouch/FIRFilter.cpp | 272 + plugins/spu2/zerospu2/SoundTouch/FIRFilter.h | 163 + plugins/spu2/zerospu2/SoundTouch/Makefile.am | 45 + .../zerospu2/SoundTouch/RateTransposer.cpp | 626 + .../spu2/zerospu2/SoundTouch/RateTransposer.h | 162 + plugins/spu2/zerospu2/SoundTouch/STTypes.h | 197 + .../spu2/zerospu2/SoundTouch/SoundTouch.cpp | 474 + plugins/spu2/zerospu2/SoundTouch/SoundTouch.h | 252 + .../spu2/zerospu2/SoundTouch/TDStretch.cpp | 940 + plugins/spu2/zerospu2/SoundTouch/TDStretch.h | 256 + plugins/spu2/zerospu2/SoundTouch/WavFile.cpp | 712 + plugins/spu2/zerospu2/SoundTouch/WavFile.h | 253 + plugins/spu2/zerospu2/SoundTouch/cpu_detect.h | 62 + .../SoundTouch/cpu_detect_x86_gcc.cpp | 138 + .../SoundTouch/cpu_detect_x86_win.cpp | 126 + .../zerospu2/SoundTouch/mmx_optimized.cpp | 305 + .../zerospu2/SoundTouch/sse_optimized.cpp | 484 + plugins/spu2/zerospu2/Win32.cpp | 343 + plugins/spu2/zerospu2/ZeroSPU2.def | 33 + plugins/spu2/zerospu2/ZeroSPU2.rc | 136 + plugins/spu2/zerospu2/ZeroSPU2.vcproj | 234 + plugins/spu2/zerospu2/ZeroSPU2_2005.vcproj | 324 + .../spu2/zerospu2/ZeroSPU2_2005_x64.vcproj | 476 + plugins/spu2/zerospu2/ZeroSPU2_2008.vcproj | 323 + plugins/spu2/zerospu2/build.sh | 28 + plugins/spu2/zerospu2/compile | 1 + plugins/spu2/zerospu2/configure.ac | 103 + plugins/spu2/zerospu2/depcomp | 529 + plugins/spu2/zerospu2/install-sh | 323 + plugins/spu2/zerospu2/missing | 360 + plugins/spu2/zerospu2/mkinstalldirs | 158 + plugins/spu2/zerospu2/resource.h | 28 + plugins/spu2/zerospu2/zerospu2.cpp | 2151 ++ plugins/spu2/zerospu2/zerospu2.h | 465 + plugins/usb/USBlinuz/License.txt | 342 + plugins/usb/USBlinuz/Linux/Config.c | 51 + plugins/usb/USBlinuz/Linux/Config.h | 20 + plugins/usb/USBlinuz/Linux/Linux.c | 75 + plugins/usb/USBlinuz/Linux/Makefile | 33 + plugins/usb/USBlinuz/Linux/callbacks.c | 34 + plugins/usb/USBlinuz/Linux/callbacks.h | 14 + plugins/usb/USBlinuz/Linux/conf.c | 136 + plugins/usb/USBlinuz/Linux/interface.c | 219 + plugins/usb/USBlinuz/Linux/interface.h | 6 + plugins/usb/USBlinuz/Linux/support.c | 162 + plugins/usb/USBlinuz/Linux/support.h | 38 + plugins/usb/USBlinuz/Linux/usblinuz.glade | 300 + plugins/usb/USBlinuz/PS2Edefs.h | 684 + plugins/usb/USBlinuz/PS2Etypes.h | 31 + plugins/usb/USBlinuz/ReadMe.txt | 36 + plugins/usb/USBlinuz/USB.c | 446 + plugins/usb/USBlinuz/USB.h | 197 + plugins/usb/USBlinuz/Win32/Config.c | 51 + plugins/usb/USBlinuz/Win32/USBlinuz.def | 27 + plugins/usb/USBlinuz/Win32/USBlinuz.dsp | 99 + plugins/usb/USBlinuz/Win32/USBlinuz.dsw | 29 + plugins/usb/USBlinuz/Win32/USBlinuz.rc | 120 + plugins/usb/USBlinuz/Win32/USBlinuz.sln | 18 + plugins/usb/USBlinuz/Win32/USBlinuz.suo | Bin 0 -> 8704 bytes plugins/usb/USBlinuz/Win32/USBlinuz.vcproj | 118 + .../usb/USBlinuz/Win32/USBlinuz_vc2002.sln | 21 + .../usb/USBlinuz/Win32/USBlinuz_vc2002.vcproj | 150 + .../usb/USBlinuz/Win32/USBlinuz_vc2003.ncb | Bin 0 -> 52224 bytes .../usb/USBlinuz/Win32/USBlinuz_vc2003.sln | 21 + .../usb/USBlinuz/Win32/USBlinuz_vc2003.suo | Bin 0 -> 8704 bytes .../usb/USBlinuz/Win32/USBlinuz_vc2003.vcproj | 164 + .../USBlinuz/Win32/USBlinuz_vc2005beta1.sln | 32 + .../Win32/USBlinuz_vc2005beta1.vcproj | 566 + plugins/usb/USBlinuz/Win32/Win32.c | 81 + plugins/usb/USBlinuz/Win32/resource.h | 21 + plugins/usb/USBnull/License.txt | 342 + plugins/usb/USBnull/Linux/Config.c | 59 + plugins/usb/USBnull/Linux/Config.h | 20 + plugins/usb/USBnull/Linux/Linux.c | 74 + plugins/usb/USBnull/Linux/Makefile | 35 + plugins/usb/USBnull/Linux/callbacks.c | 34 + plugins/usb/USBnull/Linux/callbacks.h | 14 + plugins/usb/USBnull/Linux/conf.c | 128 + plugins/usb/USBnull/Linux/interface.c | 219 + plugins/usb/USBnull/Linux/interface.h | 6 + plugins/usb/USBnull/Linux/support.c | 162 + plugins/usb/USBnull/Linux/support.h | 38 + plugins/usb/USBnull/Linux/usbnull.glade | 300 + plugins/usb/USBnull/PS2Edefs.h | 848 + plugins/usb/USBnull/PS2Etypes.h | 76 + plugins/usb/USBnull/ReadMe.txt | 34 + plugins/usb/USBnull/USB.c | 170 + plugins/usb/USBnull/USB.h | 66 + plugins/usb/USBnull/Win32/Config.c | 51 + plugins/usb/USBnull/Win32/Makefile | 53 + plugins/usb/USBnull/Win32/USBnull.def | 27 + plugins/usb/USBnull/Win32/USBnull.dsp | 85 + plugins/usb/USBnull/Win32/USBnull.dsw | 29 + plugins/usb/USBnull/Win32/USBnull.rc | 121 + .../usb/USBnull/Win32/USBnull_2005_x64.vcproj | 396 + plugins/usb/USBnull/Win32/USBnull_vc2003.sln | 21 + .../usb/USBnull/Win32/USBnull_vc2003.vcproj | 164 + .../usb/USBnull/Win32/USBnull_vc2005beta1.sln | 32 + .../USBnull/Win32/USBnull_vc2005beta1.vcproj | 530 + plugins/usb/USBnull/Win32/Win32.c | 80 + plugins/usb/USBnull/Win32/afxresmw.h | 5 + plugins/usb/USBnull/Win32/mingw/Makefile.win | 43 + plugins/usb/USBnull/Win32/mingw/USBnull.dev | 138 + .../usb/USBnull/Win32/mingw/USBnull.layout | 50 + plugins/usb/USBnull/Win32/mingw/afxres.h | 5 + plugins/usb/USBnull/Win32/resource.h | 21 + plugins/usb/USBnull/build.sh | 20 + plugins/usb/USBqemu/License-qemu.txt | 23 + plugins/usb/USBqemu/License.txt | 342 + plugins/usb/USBqemu/PS2Edefs.h | 809 + plugins/usb/USBqemu/PS2Etypes.h | 75 + plugins/usb/USBqemu/ReadMe.txt | 26 + plugins/usb/USBqemu/USB.cpp | 252 + plugins/usb/USBqemu/USB.h | 313 + plugins/usb/USBqemu/Win32/Config.cpp | 51 + plugins/usb/USBqemu/Win32/USBlinuz.aps | Bin 0 -> 35272 bytes plugins/usb/USBqemu/Win32/USBlinuz.def | 28 + plugins/usb/USBqemu/Win32/USBlinuz.rc | 156 + plugins/usb/USBqemu/Win32/USBlinuz_vc2005.sln | 25 + .../usb/USBqemu/Win32/USBlinuz_vc2005.vcproj | 669 + .../usb/USBqemu/Win32/USBlinuz_vc2005_x64.sln | 26 + .../USBqemu/Win32/USBlinuz_vc2005_x64.vcproj | 669 + .../usb/USBqemu/Win32/USBlinuz_vc2008b2.sln | 25 + .../USBqemu/Win32/USBlinuz_vc2008b2.vcproj | 669 + plugins/usb/USBqemu/Win32/Win32.cpp | 80 + plugins/usb/USBqemu/Win32/resource.h | 23 + plugins/usb/USBqemu/qemu-usb/usb-base.cpp | 193 + plugins/usb/USBqemu/qemu-usb/usb-hid.cpp | 551 + plugins/usb/USBqemu/qemu-usb/usb-hub.cpp | 565 + plugins/usb/USBqemu/qemu-usb/usb-kbd.cpp | 2115 ++ plugins/usb/USBqemu/qemu-usb/usb-msd.c | 402 + plugins/usb/USBqemu/qemu-usb/usb-ohci.cpp | 985 + plugins/usb/USBqemu/qemu-usb/usb.h | 175 + plugins/usb/USBqemu/qemu-usb/vl.cpp | 42 + plugins/usb/USBqemu/qemu-usb/vl.h | 102 + plugins/usb/USBqemu/usb-eyetoy/usb-eyetoy.cpp | 7873 +++++ plugins/usb/USBqemu/usb-mic/adcuser.h | 30 + plugins/usb/USBqemu/usb-mic/audio.h | 372 + plugins/usb/USBqemu/usb-mic/demo.h | 45 + plugins/usb/USBqemu/usb-mic/type.h | 22 + plugins/usb/USBqemu/usb-mic/usb-mic-dummy.cpp | 431 + plugins/usb/USBqemu/usb-mic/usb-mic.c | 626 + plugins/usb/USBqemu/usb-mic/usb.h | 230 + plugins/usb/USBqemu/usb-mic/usbcfg.h | 161 + plugins/usb/USBqemu/usb-mic/usbcore.h | 50 + plugins/usb/USBqemu/usb-mic/usbdesc.h | 36 + plugins/usb/USBqemu/usb-mic/usbhw.h | 107 + plugins/usb/USBqemu/usb-mic/usbreg.h | 195 + plugins/usb/USBqemu/usb-mic/usbuser.h | 74 + plugins/usb/build.sh | 15 + test.bat | 3 + test.cfg | 2 + test.sh | 28 + test_readme.txt | 6 + 2125 files changed, 640120 insertions(+) create mode 100644 INSTALL create mode 100644 bin/.pixmaps/pcsxAbout.bmp create mode 100644 bin/A39517AB.xml create mode 100644 bin/Langs/ar_AR/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/bg_BG/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/cz_CZ/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/de_DE/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/du_DU/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/el_EL/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/es_ES/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/fr_FR/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/hb_HB/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/it_IT/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/ja_JA/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/pe_PE/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/pl_PL/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/po_BR/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/po_PO/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/ro_RO/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/ru_RU/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/sh_SH/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/sw_SW/LC_MESSAGES/other.po create mode 100644 bin/Langs/sw_SW/LC_MESSAGES/pcsx2.mo create mode 100644 bin/Langs/tc_TC/LC_MESSAGES/Pcsx2.mo create mode 100644 bin/Langs/tr_TR/LC_MESSAGES/pcsx2.mo create mode 100644 bin/compat_list/compat_list.html create mode 100644 bin/compat_list/h_console.jpg create mode 100644 bin/compat_list/h_region.jpg create mode 100644 bin/compat_list/h_serial.jpg create mode 100644 bin/compat_list/h_status.jpg create mode 100644 bin/compat_list/h_title.jpg create mode 100644 bin/compat_list/h_version.jpg create mode 100644 bin/compat_list/sq_ingame.jpg create mode 100644 bin/compat_list/sq_intro.jpg create mode 100644 bin/compat_list/sq_menus.jpg create mode 100644 bin/compat_list/sq_nothing.jpg create mode 100644 bin/compat_list/sq_playable.jpg create mode 100644 bin/patches/013E349D.pnach create mode 100644 bin/patches/015314A2.pnach create mode 100644 bin/patches/034836F8.pnach create mode 100644 bin/patches/0442B1BD.pnach create mode 100644 bin/patches/05177ECE.pnach create mode 100644 bin/patches/0518D274.pnach create mode 100644 bin/patches/0518D275.pnach create mode 100644 bin/patches/06DE61E0.pnach create mode 100644 bin/patches/07AD79C9.pnach create mode 100644 bin/patches/0838D766.pnach create mode 100644 bin/patches/086273D2.pnach create mode 100644 bin/patches/08901101.pnach create mode 100644 bin/patches/08FB9DCF.pnach create mode 100644 bin/patches/0999F9DB.pnach create mode 100644 bin/patches/09D35D3F.pnach create mode 100644 bin/patches/0A342A88.pnach create mode 100644 bin/patches/0B359BBF.pnach create mode 100644 bin/patches/0C370E94.pnach create mode 100644 bin/patches/0F6B6315.pnach create mode 100644 bin/patches/1025D50A.pnach create mode 100644 bin/patches/116154AD.pnach create mode 100644 bin/patches/1248FE3A.pnach create mode 100644 bin/patches/129C8600.pnach create mode 100644 bin/patches/12AFF4D4.pnach create mode 100644 bin/patches/1468C474.pnach create mode 100644 bin/patches/1510E1D1.pnach create mode 100644 bin/patches/1629D655.pnach create mode 100644 bin/patches/163F0461.pnach create mode 100644 bin/patches/1738A5B0.pnach create mode 100644 bin/patches/19D145D7.pnach create mode 100644 bin/patches/1CAC8A56.pnach create mode 100644 bin/patches/1D2818AF.pnach create mode 100644 bin/patches/200BC0E6.pnach create mode 100644 bin/patches/2088950A.pnach create mode 100644 bin/patches/21068223.pnach create mode 100644 bin/patches/2251E14D.pnach create mode 100644 bin/patches/22C36E63.pnach create mode 100644 bin/patches/25433CBD.pnach create mode 100644 bin/patches/27E54B37.pnach create mode 100644 bin/patches/280DAC56.pnach create mode 100644 bin/patches/295D2F96.pnach create mode 100644 bin/patches/29D80A23.pnach create mode 100644 bin/patches/2B2E1535.pnach create mode 100644 bin/patches/2C728173.pnach create mode 100644 bin/patches/2CFFFA50.pnach create mode 100644 bin/patches/2D919421.pnach create mode 100644 bin/patches/2F56CBC9.pnach create mode 100644 bin/patches/302797DF.pnach create mode 100644 bin/patches/304C115C.pnach create mode 100644 bin/patches/32629F36.pnach create mode 100644 bin/patches/333F1F59.pnach create mode 100644 bin/patches/337B927C.pnach create mode 100644 bin/patches/339A0B8C.pnach create mode 100644 bin/patches/33F7D21A.pnach create mode 100644 bin/patches/36FEEE3A.pnach create mode 100644 bin/patches/37BA81B1.pnach create mode 100644 bin/patches/37C07E96.pnach create mode 100644 bin/patches/38F29E28.pnach create mode 100644 bin/patches/3BD85DA4.pnach create mode 100644 bin/patches/3CFE3B37.pnach create mode 100644 bin/patches/3DB65A75.pnach create mode 100644 bin/patches/3E0A256D.pnach create mode 100644 bin/patches/3E68955A.pnach create mode 100644 bin/patches/3EAD47FE.pnach create mode 100644 bin/patches/3F0452DE.pnach create mode 100644 bin/patches/3FB69323.pnach create mode 100644 bin/patches/4043F228.pnach create mode 100644 bin/patches/41A3191C.pnach create mode 100644 bin/patches/4321A427.pnach create mode 100644 bin/patches/4334E17D.pnach create mode 100644 bin/patches/44A61C8F.pnach create mode 100644 bin/patches/4691F6F7.pnach create mode 100644 bin/patches/46A7ECA4.pnach create mode 100644 bin/patches/472C9E70.pnach create mode 100644 bin/patches/48FE0C71.pnach create mode 100644 bin/patches/49DA19CE.pnach create mode 100644 bin/patches/4B6DDB6B.pnach create mode 100644 bin/patches/4C0C821D.pnach create mode 100644 bin/patches/4C4D7072.pnach create mode 100644 bin/patches/4C9EE7DF.pnach create mode 100644 bin/patches/4D228733.pnach create mode 100644 bin/patches/4D6DBB75.pnach create mode 100644 bin/patches/4DAC50C2.pnach create mode 100644 bin/patches/4F3D3CF0.pnach create mode 100644 bin/patches/506644B3.pnach create mode 100644 bin/patches/512B5046.pnach create mode 100644 bin/patches/5162BCCA.pnach create mode 100644 bin/patches/51D8A6A9.pnach create mode 100644 bin/patches/51F91783.pnach create mode 100644 bin/patches/53A803AF.pnach create mode 100644 bin/patches/53DF159B.pnach create mode 100644 bin/patches/54A548B4.pnach create mode 100644 bin/patches/54AD76D7.pnach create mode 100644 bin/patches/54D6BEE3.pnach create mode 100644 bin/patches/561BE340.pnach create mode 100644 bin/patches/582EED0D.pnach create mode 100644 bin/patches/586EA828.pnach create mode 100644 bin/patches/58EE1AFA.pnach create mode 100644 bin/patches/5A7635C1.pnach create mode 100644 bin/patches/5BBC2F40.pnach create mode 100644 bin/patches/5BC8C9E8.pnach create mode 100644 bin/patches/5BE3F481.pnach create mode 100644 bin/patches/5CCA0737.pnach create mode 100644 bin/patches/5D67AE48.pnach create mode 100644 bin/patches/5DFBE144.pnach create mode 100644 bin/patches/5E115FB6.pnach create mode 100644 bin/patches/5EB127E7.pnach create mode 100644 bin/patches/5F2A0E36.pnach create mode 100644 bin/patches/60013EBD.pnach create mode 100644 bin/patches/60FA8C69.pnach create mode 100644 bin/patches/6175FE7D.pnach create mode 100644 bin/patches/624F11F1.pnach create mode 100644 bin/patches/625AF967.pnach create mode 100644 bin/patches/627B8252.pnach create mode 100644 bin/patches/62F6F886.pnach create mode 100644 bin/patches/63F6B523.pnach create mode 100644 bin/patches/68EAF48F.pnach create mode 100644 bin/patches/6926B199.pnach create mode 100644 bin/patches/692CBA8E.pnach create mode 100644 bin/patches/6A4EFE60.pnach create mode 100644 bin/patches/6ADBC24B.pnach create mode 100644 bin/patches/6BA2F6B9.pnach create mode 100644 bin/patches/6D70F0E0.pnach create mode 100644 bin/patches/6EA9DDA9.pnach create mode 100644 bin/patches/6FB69282.pnach create mode 100644 bin/patches/7098BE76.pnach create mode 100644 bin/patches/7130C553.pnach create mode 100644 bin/patches/71584BAC.pnach create mode 100644 bin/patches/722BBD62.pnach create mode 100644 bin/patches/7377BC6F.pnach create mode 100644 bin/patches/763D3BF9.pnach create mode 100644 bin/patches/77ECAAA0.pnach create mode 100644 bin/patches/78168525.pnach create mode 100644 bin/patches/789D6B71.pnach create mode 100644 bin/patches/78E20421.pnach create mode 100644 bin/patches/7ABDBB5E.pnach create mode 100644 bin/patches/7BA0128E.pnach create mode 100644 bin/patches/7CD1CDCD.pnach create mode 100644 bin/patches/7D8F539A.pnach create mode 100644 bin/patches/7EBEEBBD.pnach create mode 100644 bin/patches/7F6319C7.pnach create mode 100644 bin/patches/7FD7A1B9.pnach create mode 100644 bin/patches/83261085.pnach create mode 100644 bin/patches/83D0CE43.pnach create mode 100644 bin/patches/844B58EE.pnach create mode 100644 bin/patches/848C6247.pnach create mode 100644 bin/patches/85AE91B3.pnach create mode 100644 bin/patches/85E92C92.pnach create mode 100644 bin/patches/8BC79F96.pnach create mode 100644 bin/patches/8BC95883.pnach create mode 100644 bin/patches/8BE3D7B2.pnach create mode 100644 bin/patches/8DC64680.pnach create mode 100644 bin/patches/8FDE8E16.pnach create mode 100644 bin/patches/901AAC09.pnach create mode 100644 bin/patches/93223BE4.pnach create mode 100644 bin/patches/934F9081.pnach create mode 100644 bin/patches/93F8A60B.pnach create mode 100644 bin/patches/941BB7D9.pnach create mode 100644 bin/patches/94C56923.pnach create mode 100644 bin/patches/950241D3.pnach create mode 100644 bin/patches/951555A0.pnach create mode 100644 bin/patches/95BB1901.pnach create mode 100644 bin/patches/96B2F56D.pnach create mode 100644 bin/patches/96B76E56.pnach create mode 100644 bin/patches/96C20D6F.pnach create mode 100644 bin/patches/9AAC5309.pnach create mode 100644 bin/patches/9AAC530D.pnach create mode 100644 bin/patches/9AC65D6A.pnach create mode 100644 bin/patches/9B1EE9EB.pnach create mode 100644 bin/patches/9BE3F92D.pnach create mode 100644 bin/patches/9D6F46F0.pnach create mode 100644 bin/patches/A029B109.pnach create mode 100644 bin/patches/A1B752C7.pnach create mode 100644 bin/patches/A36CFF6C.pnach create mode 100644 bin/patches/A39517AB.pnach create mode 100644 bin/patches/A3ACF3C7.pnach create mode 100644 bin/patches/A3D63039.pnach create mode 100644 bin/patches/A4E2C043.pnach create mode 100644 bin/patches/A5BF36A8.pnach create mode 100644 bin/patches/A63C896C.pnach create mode 100644 bin/patches/A719D130.pnach create mode 100644 bin/patches/A74F99CD.pnach create mode 100644 bin/patches/A7A2F7C5.pnach create mode 100644 bin/patches/A8083AE6.pnach create mode 100644 bin/patches/A88ACA28.pnach create mode 100644 bin/patches/A8A76AAC.pnach create mode 100644 bin/patches/A929A697.pnach create mode 100644 bin/patches/A9759015.pnach create mode 100644 bin/patches/AA31B5BF.pnach create mode 100644 bin/patches/AC7E88D9.pnach create mode 100644 bin/patches/ACB1989A.pnach create mode 100644 bin/patches/AD9D2B54.pnach create mode 100644 bin/patches/ADAA1256.pnach create mode 100644 bin/patches/AE0E098F.pnach create mode 100644 bin/patches/AE3EAA05.pnach create mode 100644 bin/patches/AE9EB9A0.pnach create mode 100644 bin/patches/AEDAEE99.pnach create mode 100644 bin/patches/AFAC88EF.pnach create mode 100644 bin/patches/B0621C55.pnach create mode 100644 bin/patches/B0AE1898.pnach create mode 100644 bin/patches/B130E5BA.pnach create mode 100644 bin/patches/B1BE3E51.pnach create mode 100644 bin/patches/B234036E.pnach create mode 100644 bin/patches/B2BDE9F3.pnach create mode 100644 bin/patches/B338676A.pnach create mode 100644 bin/patches/B34DA141.pnach create mode 100644 bin/patches/B36EE21E.pnach create mode 100644 bin/patches/B590CE04.pnach create mode 100644 bin/patches/B82E4C4B.pnach create mode 100644 bin/patches/B884B6E9.pnach create mode 100644 bin/patches/B99379B7.pnach create mode 100644 bin/patches/BB3D833A.pnach create mode 100644 bin/patches/BD3DBCF9.pnach create mode 100644 bin/patches/BF5D9AEC.pnach create mode 100644 bin/patches/C04FB5FD.pnach create mode 100644 bin/patches/C0D6A139.pnach create mode 100644 bin/patches/C1625F14.pnach create mode 100644 bin/patches/C1767D64.pnach create mode 100644 bin/patches/C1B141D6.pnach create mode 100644 bin/patches/C220951A.pnach create mode 100644 bin/patches/C398F477.pnach create mode 100644 bin/patches/C3D28EB9.pnach create mode 100644 bin/patches/C4467D30.pnach create mode 100644 bin/patches/C488EC04.pnach create mode 100644 bin/patches/C4A60986.pnach create mode 100644 bin/patches/C502AD6E.pnach create mode 100644 bin/patches/C5DEFEA0.pnach create mode 100644 bin/patches/C9246E9C.pnach create mode 100644 bin/patches/C9C145BF.pnach create mode 100644 bin/patches/CA295E61.pnach create mode 100644 bin/patches/CA6243B9.pnach create mode 100644 bin/patches/CB4EBD11.pnach create mode 100644 bin/patches/CBBC2E7F.pnach create mode 100644 bin/patches/CC4B9CDE.pnach create mode 100644 bin/patches/CC6AA742.pnach create mode 100644 bin/patches/CDE7C999.pnach create mode 100644 bin/patches/CF11CD83.pnach create mode 100644 bin/patches/CFB873AD.pnach create mode 100644 bin/patches/D03BEF2A.pnach create mode 100644 bin/patches/D08648B6.pnach create mode 100644 bin/patches/D0E17D26.pnach create mode 100644 bin/patches/D1ACD489.pnach create mode 100644 bin/patches/D4781770.pnach create mode 100644 bin/patches/D48A92E1.pnach create mode 100644 bin/patches/D4FB6049.pnach create mode 100644 bin/patches/D79F697A.pnach create mode 100644 bin/patches/DA0535FD.pnach create mode 100644 bin/patches/DAC14B26.pnach create mode 100644 bin/patches/DB719F5C.pnach create mode 100644 bin/patches/DC85FC8F.pnach create mode 100644 bin/patches/DCC4EEEA.pnach create mode 100644 bin/patches/DDA2FA6A.pnach create mode 100644 bin/patches/DEFA4763.pnach create mode 100644 bin/patches/E0127F2D.pnach create mode 100644 bin/patches/E0426FC6.pnach create mode 100644 bin/patches/E0DADD1A.pnach create mode 100644 bin/patches/E138094A.pnach create mode 100644 bin/patches/E1C5F607.pnach create mode 100644 bin/patches/E1FD9A2D.pnach create mode 100644 bin/patches/E2F1DB6B.pnach create mode 100644 bin/patches/E4A275B2.pnach create mode 100644 bin/patches/E677B8F1.pnach create mode 100644 bin/patches/E7A35274.pnach create mode 100644 bin/patches/E906EA37.pnach create mode 100644 bin/patches/EAD76247.pnach create mode 100644 bin/patches/EADE437E.pnach create mode 100644 bin/patches/EDD7E0FF.pnach create mode 100644 bin/patches/EE838B5C.pnach create mode 100644 bin/patches/EEC3B310.pnach create mode 100644 bin/patches/EEE2F6A3.pnach create mode 100644 bin/patches/EF5B6AAD.pnach create mode 100644 bin/patches/EF9E43EF.pnach create mode 100644 bin/patches/F1370E83.pnach create mode 100644 bin/patches/F22CDDAF.pnach create mode 100644 bin/patches/F266B00B.pnach create mode 100644 bin/patches/F4992CC1.pnach create mode 100644 bin/patches/F52FB2BE.pnach create mode 100644 bin/patches/F56C7948.pnach create mode 100644 bin/patches/F5C7B45F.pnach create mode 100644 bin/patches/F6DC728D.pnach create mode 100644 bin/patches/F6F9A91D.pnach create mode 100644 bin/patches/F758234F.pnach create mode 100644 bin/patches/F9E575D0.pnach create mode 100644 bin/patches/FA7E3081.pnach create mode 100644 bin/patches/FAC64195.pnach create mode 100644 bin/patches/FB0E6D72.pnach create mode 100644 bin/patches/FC618D82.pnach create mode 100644 bin/patches/FEA030CB.pnach create mode 100644 bin/patches/FF920E90.pnach create mode 100644 bin/patches/default.xml create mode 100644 build.sh create mode 100644 fps2bios/FP2BLOGO create mode 100644 fps2bios/IOPBTCONF create mode 100644 fps2bios/Makefile create mode 100644 fps2bios/doc/overview.doc create mode 100644 fps2bios/fps2blogo.bmp create mode 100644 fps2bios/intro/Makefile create mode 100644 fps2bios/intro/crt0.s create mode 100644 fps2bios/intro/eedebug.c create mode 100644 fps2bios/intro/include/eedebug.h create mode 100644 fps2bios/intro/include/romdir.h create mode 100644 fps2bios/intro/intro.c create mode 100644 fps2bios/intro/linkfile create mode 100644 fps2bios/intro/romdir.c create mode 100644 fps2bios/kernel/Makefile create mode 100644 fps2bios/kernel/eeload/Makefile create mode 100644 fps2bios/kernel/eeload/eedata.c create mode 100644 fps2bios/kernel/eeload/eedebug.c create mode 100644 fps2bios/kernel/eeload/eeelf.c create mode 100644 fps2bios/kernel/eeload/eeinit.c create mode 100644 fps2bios/kernel/eeload/eeirq.c create mode 100644 fps2bios/kernel/eeload/eekernel.c create mode 100644 fps2bios/kernel/eeload/eeload.c create mode 100644 fps2bios/kernel/eeload/eeload.map create mode 100644 fps2bios/kernel/eeload/include/eedebug.h create mode 100644 fps2bios/kernel/eeload/include/eeelf.h create mode 100644 fps2bios/kernel/eeload/include/eeinit.h create mode 100644 fps2bios/kernel/eeload/include/eeirq.h create mode 100644 fps2bios/kernel/eeload/include/eekernel.h create mode 100644 fps2bios/kernel/eeload/include/eeload.h create mode 100644 fps2bios/kernel/eeload/include/romdir.h create mode 100644 fps2bios/kernel/eeload/linkfile create mode 100644 fps2bios/kernel/eeload/romdir.c create mode 100644 fps2bios/kernel/eestart.c create mode 100644 fps2bios/kernel/iopload/Makefile create mode 100644 fps2bios/kernel/iopload/dmacman/Makefile create mode 100644 fps2bios/kernel/iopload/dmacman/dmacman.c create mode 100644 fps2bios/kernel/iopload/excepman/Makefile create mode 100644 fps2bios/kernel/iopload/excepman/ex_handler.s create mode 100644 fps2bios/kernel/iopload/excepman/excepman.c create mode 100644 fps2bios/kernel/iopload/heaplib/Makefile create mode 100644 fps2bios/kernel/iopload/heaplib/heaplib.c create mode 100644 fps2bios/kernel/iopload/include/err.h create mode 100644 fps2bios/kernel/iopload/include/errno.h create mode 100644 fps2bios/kernel/iopload/include/iopdebug.h create mode 100644 fps2bios/kernel/iopload/include/iopelf.h create mode 100644 fps2bios/kernel/iopload/include/iopload.h create mode 100644 fps2bios/kernel/iopload/include/kdmacman.h create mode 100644 fps2bios/kernel/iopload/include/kexcepman.h create mode 100644 fps2bios/kernel/iopload/include/kheaplib.h create mode 100644 fps2bios/kernel/iopload/include/kintrman.h create mode 100644 fps2bios/kernel/iopload/include/kioman.h create mode 100644 fps2bios/kernel/iopload/include/kloadcore.h create mode 100644 fps2bios/kernel/iopload/include/ksifcmd.h create mode 100644 fps2bios/kernel/iopload/include/ksifman.h create mode 100644 fps2bios/kernel/iopload/include/kstdio.h create mode 100644 fps2bios/kernel/iopload/include/ksysclib.h create mode 100644 fps2bios/kernel/iopload/include/ksysmem.h create mode 100644 fps2bios/kernel/iopload/include/kthbase.h create mode 100644 fps2bios/kernel/iopload/include/kthsemap.h create mode 100644 fps2bios/kernel/iopload/include/ktimrman.h create mode 100644 fps2bios/kernel/iopload/include/romdir.h create mode 100644 fps2bios/kernel/iopload/intrman/Makefile create mode 100644 fps2bios/kernel/iopload/intrman/int_handler.s create mode 100644 fps2bios/kernel/iopload/intrman/intrman.c create mode 100644 fps2bios/kernel/iopload/iopboot/Makefile create mode 100644 fps2bios/kernel/iopload/iopboot/iopboot.c create mode 100644 fps2bios/kernel/iopload/iopboot/iopirq.c create mode 100644 fps2bios/kernel/iopload/iopboot/linkfile create mode 100644 fps2bios/kernel/iopload/iopdebug.c create mode 100644 fps2bios/kernel/iopload/iopelf.c create mode 100644 fps2bios/kernel/iopload/libkernel/iop_cdvdman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_dmacman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_excepman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_heaplib.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_intrman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_ioman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_libsd.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_loadcore.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_modload.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_sifcmd.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_sifman.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_stdio.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_sysclib.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_sysmem.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_thbase.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_thevent.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_thsemap.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_usbd.s create mode 100644 fps2bios/kernel/iopload/libkernel/iop_vblank.s create mode 100644 fps2bios/kernel/iopload/loadcore/Makefile create mode 100644 fps2bios/kernel/iopload/loadcore/loadcore.c create mode 100644 fps2bios/kernel/iopload/romdir.c create mode 100644 fps2bios/kernel/iopload/sifcmd/Makefile create mode 100644 fps2bios/kernel/iopload/sifcmd/sifcmd.c create mode 100644 fps2bios/kernel/iopload/sifman/Makefile create mode 100644 fps2bios/kernel/iopload/sifman/sifman.c create mode 100644 fps2bios/kernel/iopload/sio2man/Makefile create mode 100644 fps2bios/kernel/iopload/sio2man/sio2man.c create mode 100644 fps2bios/kernel/iopload/ssbusc/Makefile create mode 100644 fps2bios/kernel/iopload/ssbusc/ssbusc.c create mode 100644 fps2bios/kernel/iopload/stdio/Makefile create mode 100644 fps2bios/kernel/iopload/stdio/stdio.c create mode 100644 fps2bios/kernel/iopload/sysclib/Makefile create mode 100644 fps2bios/kernel/iopload/sysclib/sysclib.c create mode 100644 fps2bios/kernel/iopload/sysmem/Makefile create mode 100644 fps2bios/kernel/iopload/sysmem/sysmem.c create mode 100644 fps2bios/kernel/iopload/threadman/Makefile create mode 100644 fps2bios/kernel/iopload/threadman/threadman.c create mode 100644 fps2bios/kernel/iopload/timrman/Makefile create mode 100644 fps2bios/kernel/iopload/timrman/timrman.c create mode 100644 fps2bios/kernel/iopload/vblank/Makefile create mode 100644 fps2bios/kernel/iopload/vblank/vblank.c create mode 100644 fps2bios/kernel/iopstart.c create mode 100644 fps2bios/kernel/linkfile create mode 100644 fps2bios/kernel/romdir.c create mode 100644 fps2bios/kernel/romdir.h create mode 100644 fps2bios/kernel/start.c create mode 100644 fps2bios/loader/Makefile create mode 100644 fps2bios/loader/crt0.s create mode 100644 fps2bios/loader/eedebug.c create mode 100644 fps2bios/loader/include/eedebug.h create mode 100644 fps2bios/loader/include/menu.h create mode 100644 fps2bios/loader/include/romdir.h create mode 100644 fps2bios/loader/linkfile create mode 100644 fps2bios/loader/loader.c create mode 100644 fps2bios/loader/menu.c create mode 100644 fps2bios/loader/romdir.c create mode 100644 fps2bios/ps2romgen.c create mode 100644 fps2bios/romdir.c create mode 100644 fps2bios/romver.c create mode 100755 fps2bios/set_vars.sh create mode 100644 pcsx2/CDVD.c create mode 100644 pcsx2/CDVD.h create mode 100644 pcsx2/CDVDiso.c create mode 100644 pcsx2/CDVDiso.h create mode 100644 pcsx2/CDVDisodrv.c create mode 100644 pcsx2/CDVDisodrv.h create mode 100644 pcsx2/CDVDlib.h create mode 100644 pcsx2/COP0.c create mode 100644 pcsx2/COP0.h create mode 100644 pcsx2/Cache.c create mode 100644 pcsx2/Cache.h create mode 100644 pcsx2/CdRom.c create mode 100644 pcsx2/CdRom.h create mode 100644 pcsx2/Common.h create mode 100644 pcsx2/Counters.c create mode 100644 pcsx2/Counters.h create mode 100644 pcsx2/DebugTools/Debug.h create mode 100644 pcsx2/DebugTools/DisASM.h create mode 100644 pcsx2/DebugTools/DisR3000A.c create mode 100644 pcsx2/DebugTools/DisR3000asm.c create mode 100644 pcsx2/DebugTools/DisR5900.c create mode 100644 pcsx2/DebugTools/DisR5900asm.c create mode 100644 pcsx2/DebugTools/DisVU0Micro.c create mode 100644 pcsx2/DebugTools/DisVU1Micro.c create mode 100644 pcsx2/DebugTools/DisVUmicro.h create mode 100644 pcsx2/DebugTools/DisVUops.h create mode 100644 pcsx2/DebugTools/Makefile.am create mode 100644 pcsx2/DebugTools/cpuopsDebug.c create mode 100644 pcsx2/DebugTools/cpuopsDebug.h create mode 100644 pcsx2/Decode_XA.c create mode 100644 pcsx2/Decode_XA.h create mode 100644 pcsx2/Docs/ChangeLog.txt create mode 100644 pcsx2/Docs/License.txt create mode 100644 pcsx2/Docs/PCSX2 FAQ 0.9.4.rtf create mode 100644 pcsx2/Docs/PS2Edefs.txt create mode 100644 pcsx2/Docs/RemoteDebugging.txt create mode 100644 pcsx2/Docs/Translating.txt create mode 100644 pcsx2/Docs/devblog.txt create mode 100644 pcsx2/Docs/readme 0.9.4.txt create mode 100644 pcsx2/Docs/specs.tex create mode 100644 pcsx2/EEregs.h create mode 100644 pcsx2/Elfheader.c create mode 100644 pcsx2/Elfheader.h create mode 100644 pcsx2/FPU.c create mode 100644 pcsx2/FPU2.cpp create mode 100644 pcsx2/FiFo.c create mode 100644 pcsx2/GS.cpp create mode 100644 pcsx2/GS.h create mode 100644 pcsx2/Hw.c create mode 100644 pcsx2/Hw.h create mode 100644 pcsx2/IPU/IPU.c create mode 100644 pcsx2/IPU/IPU.h create mode 100644 pcsx2/IPU/Makefile.am create mode 100644 pcsx2/IPU/acoroutine.S create mode 100644 pcsx2/IPU/acoroutine.asm create mode 100644 pcsx2/IPU/coroutine.c create mode 100644 pcsx2/IPU/coroutine.h create mode 100644 pcsx2/IPU/idct_mmx.obj create mode 100644 pcsx2/IPU/mpeg2lib/Idct.c create mode 100644 pcsx2/IPU/mpeg2lib/Makefile.am create mode 100644 pcsx2/IPU/mpeg2lib/Mpeg.c create mode 100644 pcsx2/IPU/mpeg2lib/Mpeg.h create mode 100644 pcsx2/IPU/mpeg2lib/Vlc.h create mode 100644 pcsx2/IPU/yuv2rgb.asm create mode 100644 pcsx2/IPU/yuv2rgb.c create mode 100644 pcsx2/IPU/yuv2rgb.h create mode 100644 pcsx2/InterTables.c create mode 100644 pcsx2/InterTables.h create mode 100644 pcsx2/Interpreter.c create mode 100644 pcsx2/Linux/.pixmaps/pcsxAbout.xpm create mode 100644 pcsx2/Linux/Config.c create mode 100644 pcsx2/Linux/GtkGui.c create mode 100644 pcsx2/Linux/Linux.h create mode 100644 pcsx2/Linux/LnxMain.c create mode 100644 pcsx2/Linux/Makefile.am create mode 100644 pcsx2/Linux/buildgui.sh create mode 100644 pcsx2/Linux/callbacks.h create mode 100644 pcsx2/Linux/interface.c create mode 100644 pcsx2/Linux/interface.h create mode 100644 pcsx2/Linux/pcsx2.glade create mode 100644 pcsx2/Linux/support.c create mode 100644 pcsx2/Linux/support.h create mode 100644 pcsx2/MMI.c create mode 100644 pcsx2/Makefile.am create mode 100644 pcsx2/Mdec.c create mode 100644 pcsx2/Mdec.h create mode 100644 pcsx2/Memory.c create mode 100644 pcsx2/Memory.h create mode 100644 pcsx2/Misc.c create mode 100644 pcsx2/Misc.h create mode 100644 pcsx2/PS2Edefs.h create mode 100644 pcsx2/PS2Etypes.h create mode 100644 pcsx2/Patch.c create mode 100644 pcsx2/Patch.h create mode 100644 pcsx2/Paths.h create mode 100644 pcsx2/Plugins.c create mode 100644 pcsx2/Plugins.h create mode 100644 pcsx2/PsxBios.c create mode 100644 pcsx2/PsxBios.h create mode 100644 pcsx2/PsxBios2.h create mode 100644 pcsx2/PsxCommon.h create mode 100644 pcsx2/PsxCounters.c create mode 100644 pcsx2/PsxCounters.h create mode 100644 pcsx2/PsxDma.c create mode 100644 pcsx2/PsxDma.h create mode 100644 pcsx2/PsxHw.c create mode 100644 pcsx2/PsxHw.h create mode 100644 pcsx2/PsxInterpreter.c create mode 100644 pcsx2/PsxMem.c create mode 100644 pcsx2/PsxMem.h create mode 100644 pcsx2/PsxSio2.c create mode 100644 pcsx2/PsxSio2.h create mode 100644 pcsx2/R3000A.c create mode 100644 pcsx2/R3000A.h create mode 100644 pcsx2/R5900.c create mode 100644 pcsx2/R5900.h create mode 100644 pcsx2/RDebug/Makefile.am create mode 100644 pcsx2/RDebug/deci2.c create mode 100644 pcsx2/RDebug/deci2.h create mode 100644 pcsx2/RDebug/deci2.txt create mode 100644 pcsx2/RDebug/deci2_dbgp.c create mode 100644 pcsx2/RDebug/deci2_dbgp.h create mode 100644 pcsx2/RDebug/deci2_dcmp.c create mode 100644 pcsx2/RDebug/deci2_dcmp.h create mode 100644 pcsx2/RDebug/deci2_drfp.c create mode 100644 pcsx2/RDebug/deci2_drfp.h create mode 100644 pcsx2/RDebug/deci2_iloadp.c create mode 100644 pcsx2/RDebug/deci2_iloadp.h create mode 100644 pcsx2/RDebug/deci2_netmp.c create mode 100644 pcsx2/RDebug/deci2_netmp.h create mode 100644 pcsx2/RDebug/deci2_ttyp.c create mode 100644 pcsx2/RDebug/deci2_ttyp.h create mode 100644 pcsx2/RDebug/iloadp.txt create mode 100644 pcsx2/SPR.c create mode 100644 pcsx2/SPR.h create mode 100644 pcsx2/Sif.c create mode 100644 pcsx2/Sif.h create mode 100644 pcsx2/Sifcmd.h create mode 100644 pcsx2/Sio.c create mode 100644 pcsx2/Sio.h create mode 100644 pcsx2/Stats.c create mode 100644 pcsx2/Stats.h create mode 100644 pcsx2/System.h create mode 100644 pcsx2/VU.h create mode 100644 pcsx2/VU0.c create mode 100644 pcsx2/VU0.h create mode 100644 pcsx2/VU0micro.c create mode 100644 pcsx2/VU1micro.c create mode 100644 pcsx2/VUflags.c create mode 100644 pcsx2/VUflags.h create mode 100644 pcsx2/VUmicro.h create mode 100644 pcsx2/VUops.c create mode 100644 pcsx2/VUops.h create mode 100644 pcsx2/Vif.c create mode 100644 pcsx2/Vif.h create mode 100644 pcsx2/VifDma.c create mode 100644 pcsx2/VifDma.h create mode 100644 pcsx2/build.sh create mode 100644 pcsx2/cheatscpp.h create mode 100644 pcsx2/configure.ac create mode 100644 pcsx2/depcomp create mode 100644 pcsx2/install-sh create mode 100644 pcsx2/missing create mode 100644 pcsx2/mkinstalldirs create mode 100644 pcsx2/pcsxAbout.bmp create mode 100644 pcsx2/tinyxml/Makefile.am create mode 100644 pcsx2/tinyxml/tinystr.cpp create mode 100644 pcsx2/tinyxml/tinystr.h create mode 100644 pcsx2/tinyxml/tinyxml.cpp create mode 100644 pcsx2/tinyxml/tinyxml.h create mode 100644 pcsx2/tinyxml/tinyxmlerror.cpp create mode 100644 pcsx2/tinyxml/tinyxmlparser.cpp create mode 100644 pcsx2/windows/AboutDlg.c create mode 100644 pcsx2/windows/AboutDlg.h create mode 100644 pcsx2/windows/Cdrom02.ico create mode 100644 pcsx2/windows/ConfigDlg.c create mode 100644 pcsx2/windows/CpuDlg.c create mode 100644 pcsx2/windows/DebugMemory.c create mode 100644 pcsx2/windows/Debugger.c create mode 100644 pcsx2/windows/Debugger.h create mode 100644 pcsx2/windows/Debugreg.c create mode 100644 pcsx2/windows/McdsDlg.c create mode 100644 pcsx2/windows/McdsDlg.cpp create mode 100644 pcsx2/windows/McdsDlg.h create mode 100644 pcsx2/windows/PatchBrowser.c create mode 100644 pcsx2/windows/RDebugger.c create mode 100644 pcsx2/windows/RDebugger.h create mode 100644 pcsx2/windows/VCprojects/pcsx2_2003.sln create mode 100644 pcsx2/windows/VCprojects/pcsx2_2003.vcproj create mode 100644 pcsx2/windows/VCprojects/pcsx2_2005.sln create mode 100644 pcsx2/windows/VCprojects/pcsx2_2005.vcproj create mode 100644 pcsx2/windows/VCprojects/pcsx2_2005_x64.sln create mode 100644 pcsx2/windows/VCprojects/pcsx2_2005_x64.vcproj create mode 100644 pcsx2/windows/VCprojects/pcsx2_2008.sln create mode 100644 pcsx2/windows/VCprojects/pcsx2_2008.vcproj create mode 100644 pcsx2/windows/VCprojects/vsprops/common.vsprops create mode 100644 pcsx2/windows/VCprojects/vsprops/debug.vsprops create mode 100644 pcsx2/windows/VCprojects/vsprops/devbuild.vsprops create mode 100644 pcsx2/windows/VCprojects/vsprops/release.vsprops create mode 100644 pcsx2/windows/VCprojects/vsprops/virtualmem.vsprops create mode 100644 pcsx2/windows/Win32.h create mode 100644 pcsx2/windows/WinMain.c create mode 100644 pcsx2/windows/afxresmw.h create mode 100644 pcsx2/windows/cheats/browser.cpp create mode 100644 pcsx2/windows/cheats/cheats.cpp create mode 100644 pcsx2/windows/cheats/cheats.h create mode 100644 pcsx2/windows/ini.c create mode 100644 pcsx2/windows/libs/gnu_gettext.lib create mode 100644 pcsx2/windows/libs/libintlmsc.h create mode 100644 pcsx2/windows/libs/pthread.h create mode 100644 pcsx2/windows/libs/pthreadVC2.lib create mode 100644 pcsx2/windows/libs/sched.h create mode 100644 pcsx2/windows/libs/semaphore.h create mode 100644 pcsx2/windows/mingw/Makefile.win create mode 100644 pcsx2/windows/mingw/afxres.h create mode 100644 pcsx2/windows/mingw/pcsx2.dev create mode 100644 pcsx2/windows/mingw/pcsx2.layout create mode 100644 pcsx2/windows/mingw/pcsx2_private.h create mode 100644 pcsx2/windows/mingw/pcsx2_private.rc create mode 100644 pcsx2/windows/pcsx2.rc create mode 100644 pcsx2/windows/ps2_silver.bmp create mode 100644 pcsx2/windows/resource.h create mode 100644 pcsx2/x86/Makefile.am create mode 100644 pcsx2/x86/README create mode 100644 pcsx2/x86/aR3000A.S create mode 100644 pcsx2/x86/aVUzerorec.S create mode 100644 pcsx2/x86/aVif.S create mode 100644 pcsx2/x86/aVif.asm create mode 100644 pcsx2/x86/fast_routines.S create mode 100644 pcsx2/x86/fast_routines.cpp create mode 100644 pcsx2/x86/iCOP2.c create mode 100644 pcsx2/x86/iCP0.c create mode 100644 pcsx2/x86/iCP0.h create mode 100644 pcsx2/x86/iCore.cpp create mode 100644 pcsx2/x86/iCore.h create mode 100644 pcsx2/x86/iFPU.c create mode 100644 pcsx2/x86/iFPU.h create mode 100644 pcsx2/x86/iGS.cpp create mode 100644 pcsx2/x86/iHw.c create mode 100644 pcsx2/x86/iMMI.c create mode 100644 pcsx2/x86/iMMI.h create mode 100644 pcsx2/x86/iPsxHw.c create mode 100644 pcsx2/x86/iPsxMem.c create mode 100644 pcsx2/x86/iR3000A.cpp create mode 100644 pcsx2/x86/iR3000A.h create mode 100644 pcsx2/x86/iR3000Atables.cpp create mode 100644 pcsx2/x86/iR5900.h create mode 100644 pcsx2/x86/iR5900Arit.h create mode 100644 pcsx2/x86/iR5900AritImm.h create mode 100644 pcsx2/x86/iR5900Branch.h create mode 100644 pcsx2/x86/iR5900Jump.h create mode 100644 pcsx2/x86/iR5900LoadStore.h create mode 100644 pcsx2/x86/iR5900Move.h create mode 100644 pcsx2/x86/iR5900MultDiv.h create mode 100644 pcsx2/x86/iR5900Shift.h create mode 100644 pcsx2/x86/iVU0micro.c create mode 100644 pcsx2/x86/iVU0micro.h create mode 100644 pcsx2/x86/iVU1micro.c create mode 100644 pcsx2/x86/iVU1micro.h create mode 100644 pcsx2/x86/iVUmicro.c create mode 100644 pcsx2/x86/iVUmicro.h create mode 100644 pcsx2/x86/iVUops.h create mode 100644 pcsx2/x86/iVUzerorec.cpp create mode 100644 pcsx2/x86/iVUzerorec.h create mode 100644 pcsx2/x86/iVif.cpp create mode 100644 pcsx2/x86/ir5900tables.c create mode 100644 pcsx2/x86/ix86-32/aR5900-32.S create mode 100644 pcsx2/x86/ix86-32/aVif_proc-32.asm create mode 100644 pcsx2/x86/ix86-32/iCore-32.cpp create mode 100644 pcsx2/x86/ix86-32/iR5900-32.c create mode 100644 pcsx2/x86/ix86-32/iR5900Arit.c create mode 100644 pcsx2/x86/ix86-32/iR5900AritImm.c create mode 100644 pcsx2/x86/ix86-32/iR5900Branch.c create mode 100644 pcsx2/x86/ix86-32/iR5900Jump.c create mode 100644 pcsx2/x86/ix86-32/iR5900LoadStore.c create mode 100644 pcsx2/x86/ix86-32/iR5900Move.c create mode 100644 pcsx2/x86/ix86-32/iR5900MultDiv.c create mode 100644 pcsx2/x86/ix86-32/iR5900Shift.c create mode 100644 pcsx2/x86/ix86-64/aR3000A-64.asm create mode 100644 pcsx2/x86/ix86-64/aR5900-64.S create mode 100644 pcsx2/x86/ix86-64/aR5900-64.asm create mode 100644 pcsx2/x86/ix86-64/aVUzerorec-64.asm create mode 100644 pcsx2/x86/ix86-64/aVif_proc-64.asm create mode 100644 pcsx2/x86/ix86-64/fast_routines-64.asm create mode 100644 pcsx2/x86/ix86-64/iCore-64.cpp create mode 100644 pcsx2/x86/ix86-64/iR5900-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900Arit-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900AritImm-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900Branch-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900Jump-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900LoadStore-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900Move-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900MultDiv-64.c create mode 100644 pcsx2/x86/ix86-64/iR5900Shift-64.c create mode 100644 pcsx2/x86/ix86/Makefile.am create mode 100644 pcsx2/x86/ix86/ix86.c create mode 100644 pcsx2/x86/ix86/ix86.h create mode 100644 pcsx2/x86/ix86/ix86_3dnow.c create mode 100644 pcsx2/x86/ix86/ix86_cpudetect.c create mode 100644 pcsx2/x86/ix86/ix86_fpu.c create mode 100644 pcsx2/x86/ix86/ix86_mmx.c create mode 100644 pcsx2/x86/ix86/ix86_sse.c create mode 100644 pcsx2/xmlpatchloader.cpp create mode 100644 pcsx2/zlib/ChangeLog create mode 100644 pcsx2/zlib/Makefile.am create mode 100644 pcsx2/zlib/README create mode 100644 pcsx2/zlib/adler32.c create mode 100644 pcsx2/zlib/compress.c create mode 100644 pcsx2/zlib/crc32.c create mode 100644 pcsx2/zlib/crc32.h create mode 100644 pcsx2/zlib/deflate.c create mode 100644 pcsx2/zlib/deflate.h create mode 100644 pcsx2/zlib/gzio.c create mode 100644 pcsx2/zlib/infback.c create mode 100644 pcsx2/zlib/inffast.c create mode 100644 pcsx2/zlib/inffast.h create mode 100644 pcsx2/zlib/inffixed.h create mode 100644 pcsx2/zlib/inflate.c create mode 100644 pcsx2/zlib/inflate.h create mode 100644 pcsx2/zlib/inftrees.c create mode 100644 pcsx2/zlib/inftrees.h create mode 100644 pcsx2/zlib/trees.c create mode 100644 pcsx2/zlib/trees.h create mode 100644 pcsx2/zlib/uncompr.c create mode 100644 pcsx2/zlib/zconf.h create mode 100644 pcsx2/zlib/zlib.h create mode 100644 pcsx2/zlib/zutil.c create mode 100644 pcsx2/zlib/zutil.h create mode 100644 plugins/build.sh create mode 100644 plugins/cdvd/CDVDbin/readme.ps1.txt create mode 100644 plugins/cdvd/CDVDbin/readme.txt create mode 100644 plugins/cdvd/CDVDbin/src/CDVD.h create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.c create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.def create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.dsp create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.dsw create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.ncb create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.rc create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.sln create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.sln.old create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.suo create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.vcproj create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin.vcproj.old create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin_2003.sln create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin_2003.vcproj create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.sln create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.vcproj create mode 100644 plugins/cdvd/CDVDbin/src/CDVDbinro.rc create mode 100644 plugins/cdvd/CDVDbin/src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDbin/src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDbin/src/resource.h create mode 100644 plugins/cdvd/CDVDdraft/Src/AboutBox.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/AboutBox.h create mode 100644 plugins/cdvd/CDVDdraft/Src/Config.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/Config.h create mode 100644 plugins/cdvd/CDVDdraft/Src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDdraft/Src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDdraft/Src/ReadMe.txt create mode 100644 plugins/cdvd/CDVDdraft/Src/StdAfx.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/StdAfx.h create mode 100644 plugins/cdvd/CDVDdraft/Src/aspi.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/bitmap1.bmp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvd.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvd.h create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvdcompat.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvdcompat.h create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.aps create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.clw create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.def create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.dep create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.dsp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.dsw create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.h create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.opt create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.plg create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft.rc create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.sln create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.vcproj create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvdmisc.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/cdvdmisc.h create mode 100644 plugins/cdvd/CDVDdraft/Src/constants.h create mode 100644 plugins/cdvd/CDVDdraft/Src/ioctl.cpp create mode 100644 plugins/cdvd/CDVDdraft/Src/res/CVS/Entries create mode 100644 plugins/cdvd/CDVDdraft/Src/res/CVS/Entries.Extra create mode 100644 plugins/cdvd/CDVDdraft/Src/res/CVS/Repository create mode 100644 plugins/cdvd/CDVDdraft/Src/res/CVS/Root create mode 100644 plugins/cdvd/CDVDdraft/Src/res/cdvddraft.rc2 create mode 100644 plugins/cdvd/CDVDdraft/Src/resource.h create mode 100644 plugins/cdvd/CDVDdraft/Src/typedefs.h create mode 100644 plugins/cdvd/CDVDdraft/Src/winaspi/scsidefs.h create mode 100644 plugins/cdvd/CDVDdraft/Src/winaspi/wnaspi32.h create mode 100644 plugins/cdvd/CDVDiso/ReadMe.txt create mode 100644 plugins/cdvd/CDVDiso/build.sh create mode 100644 plugins/cdvd/CDVDiso/src/CDVDiso.h create mode 100644 plugins/cdvd/CDVDiso/src/CDVDisop.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/CDVDiso.glade create mode 100644 plugins/cdvd/CDVDiso/src/Linux/Config.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/Config.h create mode 100644 plugins/cdvd/CDVDiso/src/Linux/Linux.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/Makefile create mode 100644 plugins/cdvd/CDVDiso/src/Linux/callbacks.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/callbacks.h create mode 100644 plugins/cdvd/CDVDiso/src/Linux/conf.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/interface.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/interface.h create mode 100644 plugins/cdvd/CDVDiso/src/Linux/support.c create mode 100644 plugins/cdvd/CDVDiso/src/Linux/support.h create mode 100644 plugins/cdvd/CDVDiso/src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDiso/src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.sln create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.vcproj create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.def create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsp create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsw create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.rc create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.sln create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso.vcproj create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.sln create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.vcproj create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.sln create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.vcproj create mode 100644 plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2008.vcproj create mode 100644 plugins/cdvd/CDVDiso/src/Win32/Config.c create mode 100644 plugins/cdvd/CDVDiso/src/Win32/Config.h create mode 100644 plugins/cdvd/CDVDiso/src/Win32/Makefile create mode 100644 plugins/cdvd/CDVDiso/src/Win32/Win32.c create mode 100644 plugins/cdvd/CDVDiso/src/Win32/afxresmw.h create mode 100644 plugins/cdvd/CDVDiso/src/Win32/plugin.def create mode 100644 plugins/cdvd/CDVDiso/src/Win32/resource.h create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/LICENSE create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/README create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/blocksort.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/bzlib.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/bzlib.h create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/bzlib_private.h create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/compress.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/crctable.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/decompress.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/huffman.c create mode 100644 plugins/cdvd/CDVDiso/src/bzip2/randtable.c create mode 100644 plugins/cdvd/CDVDiso/src/libiso.c create mode 100644 plugins/cdvd/CDVDiso/src/libiso.h create mode 100644 plugins/cdvd/CDVDiso/src/mkiso/Makefile create mode 100644 plugins/cdvd/CDVDiso/src/mkiso/Makefile.mingw create mode 100644 plugins/cdvd/CDVDiso/src/mkiso/mkiso.c create mode 100644 plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsp create mode 100644 plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsw create mode 100644 plugins/cdvd/CDVDiso/src/zlib/ChangeLog create mode 100644 plugins/cdvd/CDVDiso/src/zlib/README create mode 100644 plugins/cdvd/CDVDiso/src/zlib/adler32.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/compress.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/crc32.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/crc32.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/deflate.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/deflate.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/gvmat32.obj create mode 100644 plugins/cdvd/CDVDiso/src/zlib/gvmat32c.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/gvmat64.obj create mode 100644 plugins/cdvd/CDVDiso/src/zlib/gzio.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/infback.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffas32.obj create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffas8664.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffast.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffast.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffasx64.obj create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inffixed.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inflate.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inflate.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inftrees.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/inftrees.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/trees.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/trees.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/uncompr.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/zconf.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/zlib.h create mode 100644 plugins/cdvd/CDVDiso/src/zlib/zutil.c create mode 100644 plugins/cdvd/CDVDiso/src/zlib/zutil.h create mode 100644 plugins/cdvd/CDVDisoEFP/ChangeLog.txt create mode 100644 plugins/cdvd/CDVDisoEFP/build.sh create mode 100644 plugins/cdvd/CDVDisoEFP/license.txt create mode 100644 plugins/cdvd/CDVDisoEFP/readme.txt create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/CD.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/CD.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/DVD.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/DVD.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/Makefile create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/comparisondummy.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/conf.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/conf.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/device.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/device.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/interface.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/interface.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/logfile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/logfile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.glade create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/CD.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/CD.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/DVD.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/DVD.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32 create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/conf.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/conf.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/device.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/device.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/logfile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/logfile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/make.bat create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/makeming.bat create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/plugin.def create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/screens.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/screens.rc create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/blockv2.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/blockv2.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/LICENSE create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/README create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/blocksort.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib_private.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/compress.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/crctable.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/decompress.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/huffman.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2/randtable.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2v2.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2v2.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2v3.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/bzip2v3.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/convert.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/convert.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/ecma119.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/ecma119.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/gzipv1.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/gzipv1.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/gzipv2.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/gzipv2.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/imagetype.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/imagetype.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/ini.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/ini.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/isocompress.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/isocompress.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/isofile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/isofile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/multifile.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/multifile.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/toc.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/toc.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/version.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/version.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/ChangeLog create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/README create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/adler32.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/compress.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/crc32.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/crc32.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/deflate.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/deflate.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/gzio.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/infback.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inffast.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inffast.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inffixed.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inflate.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inflate.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/trees.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/trees.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/uncompr.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/zconf.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h.bak create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/zutil.c create mode 100644 plugins/cdvd/CDVDisoEFP/src/zlib/zutil.h create mode 100644 plugins/cdvd/CDVDlinuz/ChangeLog.txt create mode 100644 plugins/cdvd/CDVDlinuz/License.txt create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/CD.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/CD.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/DVD.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/DVD.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/Makefile create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/conf.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/conf.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/device.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/device.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/interface.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/logfile.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/logfile.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/CD.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/CD.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/DVD.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/DVD.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/Makefile.MinGW32 create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/conf.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/conf.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/device.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/device.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/logfile.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/logfile.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/make.bat create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/plugin.def create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/screens.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/Win32/screens.rc create mode 100644 plugins/cdvd/CDVDlinuz/Src/buffer.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/buffer.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/convert.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/convert.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/ini.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/ini.h create mode 100644 plugins/cdvd/CDVDlinuz/Src/version.c create mode 100644 plugins/cdvd/CDVDlinuz/Src/version.h create mode 100644 plugins/cdvd/CDVDlinuz/build.sh create mode 100644 plugins/cdvd/CDVDlinuz/readme.txt create mode 100644 plugins/cdvd/CDVDnull/ReadMe.txt create mode 100644 plugins/cdvd/CDVDnull/Src/CDVD.c create mode 100644 plugins/cdvd/CDVDnull/Src/CDVD.h create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.def create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.dsp create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.dsw create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.opt create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.plg create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.sln create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull.vcproj create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_2003.sln create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_2003.vcproj create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.sln create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.vcproj create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.sln create mode 100644 plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.vcproj create mode 100644 plugins/cdvd/CDVDnull/Src/Makefile create mode 100644 plugins/cdvd/CDVDnull/Src/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDnull/Src/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDnull/Src/plugin.def create mode 100644 plugins/cdvd/CDVDnull/build.sh create mode 100644 plugins/cdvd/CDVDpeops/CDVDiso.c create mode 100644 plugins/cdvd/CDVDpeops/CDVDiso.h create mode 100644 plugins/cdvd/CDVDpeops/CDVDisodrv.c create mode 100644 plugins/cdvd/CDVDpeops/CDVDisodrv.h create mode 100644 plugins/cdvd/CDVDpeops/CDVDlib.h create mode 100644 plugins/cdvd/CDVDpeops/CLEAN.BAT create mode 100644 plugins/cdvd/CDVDpeops/Cdr.c create mode 100644 plugins/cdvd/CDVDpeops/Cdr.c.bak create mode 100644 plugins/cdvd/CDVDpeops/Cfg.c create mode 100644 plugins/cdvd/CDVDpeops/CheckDiskType.c create mode 100644 plugins/cdvd/CDVDpeops/Ioctrl.c create mode 100644 plugins/cdvd/CDVDpeops/Makefile.win create mode 100644 plugins/cdvd/CDVDpeops/PS2Edefs.h create mode 100644 plugins/cdvd/CDVDpeops/PS2Etypes.h create mode 100644 plugins/cdvd/CDVDpeops/ReadMe.txt create mode 100644 plugins/cdvd/CDVDpeops/Scsi.c create mode 100644 plugins/cdvd/CDVDpeops/StdAfx.c create mode 100644 plugins/cdvd/CDVDpeops/StdAfx.h create mode 100644 plugins/cdvd/CDVDpeops/build.sh create mode 100644 plugins/cdvd/CDVDpeops/cdda.c create mode 100644 plugins/cdvd/CDVDpeops/cdda.h create mode 100644 plugins/cdvd/CDVDpeops/cdr.h create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.aps create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.c create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.def create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.def.bak create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.dev create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.dsp create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.dsw create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.h create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.layout create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.opt create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.plg create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.rc create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.sln create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops.vcproj create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops_2005.sln create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops_2005.vcproj create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops_private.h create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops_private.rc create mode 100644 plugins/cdvd/CDVDpeops/cdvdPeops_private.res create mode 100644 plugins/cdvd/CDVDpeops/cfg.h create mode 100644 plugins/cdvd/CDVDpeops/changelog.txt create mode 100644 plugins/cdvd/CDVDpeops/defines.h create mode 100644 plugins/cdvd/CDVDpeops/defines.h.bak create mode 100644 plugins/cdvd/CDVDpeops/externals.h create mode 100644 plugins/cdvd/CDVDpeops/externals.h.bak create mode 100644 plugins/cdvd/CDVDpeops/filemap.txt create mode 100644 plugins/cdvd/CDVDpeops/generic.c create mode 100644 plugins/cdvd/CDVDpeops/generic.c.bak create mode 100644 plugins/cdvd/CDVDpeops/generic.h create mode 100644 plugins/cdvd/CDVDpeops/i386.asm create mode 100644 plugins/cdvd/CDVDpeops/ioctrl.h create mode 100644 plugins/cdvd/CDVDpeops/libiso.c create mode 100644 plugins/cdvd/CDVDpeops/libiso.h create mode 100644 plugins/cdvd/CDVDpeops/license.txt create mode 100644 plugins/cdvd/CDVDpeops/macros.inc create mode 100644 plugins/cdvd/CDVDpeops/mingw/afxres.h create mode 100644 plugins/cdvd/CDVDpeops/ppf.c create mode 100644 plugins/cdvd/CDVDpeops/ppf.h create mode 100644 plugins/cdvd/CDVDpeops/read.c create mode 100644 plugins/cdvd/CDVDpeops/read.h create mode 100644 plugins/cdvd/CDVDpeops/readme_1_2.txt create mode 100644 plugins/cdvd/CDVDpeops/resource.h create mode 100644 plugins/cdvd/CDVDpeops/scsi.h create mode 100644 plugins/cdvd/CDVDpeops/scsidefs.h create mode 100644 plugins/cdvd/CDVDpeops/sub.c create mode 100644 plugins/cdvd/CDVDpeops/sub.h create mode 100644 plugins/cdvd/CDVDpeops/toc.c create mode 100644 plugins/cdvd/CDVDpeops/toc.h create mode 100644 plugins/cdvd/CDVDpeops/version_1_2.txt create mode 100644 plugins/cdvd/CDVDpeops/wnaspi32.h create mode 100644 plugins/cdvd/build.sh create mode 100644 plugins/dev9/DEV9linuz/DEV9.c create mode 100644 plugins/dev9/DEV9linuz/DEV9.h create mode 100644 plugins/dev9/DEV9linuz/Linux/Config.c create mode 100644 plugins/dev9/DEV9linuz/Linux/Config.h create mode 100644 plugins/dev9/DEV9linuz/Linux/Linux.c create mode 100644 plugins/dev9/DEV9linuz/Linux/Makefile create mode 100644 plugins/dev9/DEV9linuz/Linux/callbacks.c create mode 100644 plugins/dev9/DEV9linuz/Linux/callbacks.h create mode 100644 plugins/dev9/DEV9linuz/Linux/conf.c create mode 100644 plugins/dev9/DEV9linuz/Linux/dev9linuz.glade create mode 100644 plugins/dev9/DEV9linuz/Linux/dev9net.c create mode 100644 plugins/dev9/DEV9linuz/Linux/interface.c create mode 100644 plugins/dev9/DEV9linuz/Linux/interface.h create mode 100644 plugins/dev9/DEV9linuz/Linux/socks.c create mode 100644 plugins/dev9/DEV9linuz/Linux/socks.h create mode 100644 plugins/dev9/DEV9linuz/Linux/support.c create mode 100644 plugins/dev9/DEV9linuz/Linux/support.h create mode 100644 plugins/dev9/DEV9linuz/PS2Edefs.h create mode 100644 plugins/dev9/DEV9linuz/PS2Etypes.h create mode 100644 plugins/dev9/DEV9linuz/Win32/Config.c create mode 100644 plugins/dev9/DEV9linuz/Win32/Config.h create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.def create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsp create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsw create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.rc create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.sln create mode 100644 plugins/dev9/DEV9linuz/Win32/DEV9linuz.vcproj create mode 100644 plugins/dev9/DEV9linuz/Win32/Devioctl.h create mode 100644 plugins/dev9/DEV9linuz/Win32/Makefile create mode 100644 plugins/dev9/DEV9linuz/Win32/Ntddndis.h create mode 100644 plugins/dev9/DEV9linuz/Win32/Packet.lib create mode 100644 plugins/dev9/DEV9linuz/Win32/Packet32.h create mode 100644 plugins/dev9/DEV9linuz/Win32/Win32.c create mode 100644 plugins/dev9/DEV9linuz/Win32/afxresmw.h create mode 100644 plugins/dev9/DEV9linuz/Win32/libpacket.a create mode 100644 plugins/dev9/DEV9linuz/Win32/plugin.def create mode 100644 plugins/dev9/DEV9linuz/Win32/resource.h create mode 100644 plugins/dev9/DEV9linuz/Win32/socks.c create mode 100644 plugins/dev9/DEV9linuz/Win32/socks.h create mode 100644 plugins/dev9/DEV9linuz/dvr.c create mode 100644 plugins/dev9/DEV9linuz/flash.c create mode 100644 plugins/dev9/build.sh create mode 100644 plugins/dev9/dev9ghzdrk/DEV9.cpp create mode 100644 plugins/dev9/dev9ghzdrk/DEV9.h create mode 100644 plugins/dev9/dev9ghzdrk/PS2Edefs.h create mode 100644 plugins/dev9/dev9ghzdrk/PS2Etypes.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Config.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Config.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.aps create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.def create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.dsw create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.opt create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.plg create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.rc create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.sln create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.vcproj create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.sln create mode 100644 plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.vcproj create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Devioctl.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Makefile create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Packet.lib create mode 100644 plugins/dev9/dev9ghzdrk/Win32/Win32.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/_Ntddndis.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/afxresmw.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/ata.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/ata.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/icmp.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/libpacket.a create mode 100644 plugins/dev9/dev9ghzdrk/Win32/mtfifo.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/net.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/net.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/packet32.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/pcap_io.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/plugin.def create mode 100644 plugins/dev9/dev9ghzdrk/Win32/resource.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/smap.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/smap.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/socket_io.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/socks.c create mode 100644 plugins/dev9/dev9ghzdrk/Win32/socks.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/tap-win32.cpp create mode 100644 plugins/dev9/dev9ghzdrk/Win32/tap.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/vl.h create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.dll create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.lib create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.dll create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.lib create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.dll create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.lib create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.dll create mode 100644 plugins/dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.lib create mode 100644 plugins/dev9/dev9ghzdrk/flash.cpp create mode 100644 plugins/dev9/dev9ghzdrk/pcap_io.cpp create mode 100644 plugins/dev9/dev9null/ReadMe.txt create mode 100644 plugins/dev9/dev9null/build.sh create mode 100644 plugins/dev9/dev9null/src/DEV9.h create mode 100644 plugins/dev9/dev9null/src/Dev9null.sln create mode 100644 plugins/dev9/dev9null/src/Dev9null.vcproj create mode 100644 plugins/dev9/dev9null/src/Dev9null_2005_x64.vcproj create mode 100644 plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.sln create mode 100644 plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.vcproj create mode 100644 plugins/dev9/dev9null/src/Makefile create mode 100644 plugins/dev9/dev9null/src/Makefile.mingw create mode 100644 plugins/dev9/dev9null/src/PS2Edefs.h create mode 100644 plugins/dev9/dev9null/src/PS2Etypes.h create mode 100644 plugins/dev9/dev9null/src/dev9null.c create mode 100644 plugins/dev9/dev9null/src/dev9null.def create mode 100644 plugins/fw/FWlinuz/FW.c create mode 100644 plugins/fw/FWlinuz/FW.h create mode 100644 plugins/fw/FWlinuz/License.txt create mode 100644 plugins/fw/FWlinuz/Linux/Config.c create mode 100644 plugins/fw/FWlinuz/Linux/Config.h create mode 100644 plugins/fw/FWlinuz/Linux/Linux.c create mode 100644 plugins/fw/FWlinuz/Linux/Makefile create mode 100644 plugins/fw/FWlinuz/Linux/callbacks.c create mode 100644 plugins/fw/FWlinuz/Linux/callbacks.h create mode 100644 plugins/fw/FWlinuz/Linux/conf.c create mode 100644 plugins/fw/FWlinuz/Linux/firewire.glade create mode 100644 plugins/fw/FWlinuz/Linux/interface.c create mode 100644 plugins/fw/FWlinuz/Linux/interface.h create mode 100644 plugins/fw/FWlinuz/Linux/support.c create mode 100644 plugins/fw/FWlinuz/Linux/support.h create mode 100644 plugins/fw/FWlinuz/PS2Edefs.h create mode 100644 plugins/fw/FWlinuz/PS2Etypes.h create mode 100644 plugins/fw/FWlinuz/ReadMe.txt create mode 100644 plugins/fw/FWlinuz/Win32/Config.c create mode 100644 plugins/fw/FWlinuz/Win32/FWlinuz.def create mode 100644 plugins/fw/FWlinuz/Win32/FWlinuz.rc create mode 100644 plugins/fw/FWlinuz/Win32/FWlinuz.sln create mode 100644 plugins/fw/FWlinuz/Win32/FireWireNull.ncb create mode 100644 plugins/fw/FWlinuz/Win32/FireWireNull.sln create mode 100644 plugins/fw/FWlinuz/Win32/FireWireNull.suo create mode 100644 plugins/fw/FWlinuz/Win32/FireWireNull.vcproj create mode 100644 plugins/fw/FWlinuz/Win32/Makefile create mode 100644 plugins/fw/FWlinuz/Win32/Win32.c create mode 100644 plugins/fw/FWlinuz/Win32/afxresmw.h create mode 100644 plugins/fw/FWlinuz/Win32/plugin.def create mode 100644 plugins/fw/FWlinuz/Win32/resource.h create mode 100644 plugins/fw/FWnull/FW.c create mode 100644 plugins/fw/FWnull/FW.h create mode 100644 plugins/fw/FWnull/License.txt create mode 100644 plugins/fw/FWnull/Linux/Config.c create mode 100644 plugins/fw/FWnull/Linux/Config.h create mode 100644 plugins/fw/FWnull/Linux/Linux.c create mode 100644 plugins/fw/FWnull/Linux/Makefile create mode 100644 plugins/fw/FWnull/Linux/callbacks.c create mode 100644 plugins/fw/FWnull/Linux/callbacks.h create mode 100644 plugins/fw/FWnull/Linux/conf.c create mode 100644 plugins/fw/FWnull/Linux/firewire.glade create mode 100644 plugins/fw/FWnull/Linux/interface.c create mode 100644 plugins/fw/FWnull/Linux/interface.h create mode 100644 plugins/fw/FWnull/Linux/support.c create mode 100644 plugins/fw/FWnull/Linux/support.h create mode 100644 plugins/fw/FWnull/PS2Edefs.h create mode 100644 plugins/fw/FWnull/PS2Etypes.h create mode 100644 plugins/fw/FWnull/ReadMe.txt create mode 100644 plugins/fw/FWnull/Win32/Config.c create mode 100644 plugins/fw/FWnull/Win32/FireWireNull.def create mode 100644 plugins/fw/FWnull/Win32/FireWireNull.rc create mode 100644 plugins/fw/FWnull/Win32/FireWireNull.sln create mode 100644 plugins/fw/FWnull/Win32/FireWireNull.suo create mode 100644 plugins/fw/FWnull/Win32/FireWireNull.vcproj create mode 100644 plugins/fw/FWnull/Win32/FireWireNull_2005_x64.vcproj create mode 100644 plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.sln create mode 100644 plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.vcproj create mode 100644 plugins/fw/FWnull/Win32/Makefile create mode 100644 plugins/fw/FWnull/Win32/Win32.c create mode 100644 plugins/fw/FWnull/Win32/afxresmw.h create mode 100644 plugins/fw/FWnull/Win32/resource.h create mode 100644 plugins/fw/FWnull/build.sh create mode 100644 plugins/fw/build.sh create mode 100644 plugins/gs/GSsoft/License.txt create mode 100644 plugins/gs/GSsoft/ReadMe.txt create mode 100644 plugins/gs/GSsoft/Src/Cache.c create mode 100644 plugins/gs/GSsoft/Src/Cache.h create mode 100644 plugins/gs/GSsoft/Src/Color.c create mode 100644 plugins/gs/GSsoft/Src/Color.h create mode 100644 plugins/gs/GSsoft/Src/Draw.c create mode 100644 plugins/gs/GSsoft/Src/Draw.h create mode 100644 plugins/gs/GSsoft/Src/GS.c create mode 100644 plugins/gs/GSsoft/Src/GS.h create mode 100644 plugins/gs/GSsoft/Src/Linux-SDL/Conf.c create mode 100644 plugins/gs/GSsoft/Src/Linux-SDL/X11.c create mode 100644 plugins/gs/GSsoft/Src/Linux/Conf.c create mode 100644 plugins/gs/GSsoft/Src/Linux/Linux.c create mode 100644 plugins/gs/GSsoft/Src/Linux/Linux.h create mode 100644 plugins/gs/GSsoft/Src/Linux/Makefile create mode 100644 plugins/gs/GSsoft/Src/Linux/callbacks.c create mode 100644 plugins/gs/GSsoft/Src/Linux/callbacks.h create mode 100644 plugins/gs/GSsoft/Src/Linux/gssoft.glade create mode 100644 plugins/gs/GSsoft/Src/Linux/interface.c create mode 100644 plugins/gs/GSsoft/Src/Linux/interface.h create mode 100644 plugins/gs/GSsoft/Src/Linux/support.c create mode 100644 plugins/gs/GSsoft/Src/Linux/support.h create mode 100644 plugins/gs/GSsoft/Src/Mem.c create mode 100644 plugins/gs/GSsoft/Src/Mem.h create mode 100644 plugins/gs/GSsoft/Src/PS2Edefs.h create mode 100644 plugins/gs/GSsoft/Src/PS2Etypes.h create mode 100644 plugins/gs/GSsoft/Src/Page.c create mode 100644 plugins/gs/GSsoft/Src/Page.h create mode 100644 plugins/gs/GSsoft/Src/Prim.c create mode 100644 plugins/gs/GSsoft/Src/Rec.c create mode 100644 plugins/gs/GSsoft/Src/Rec.h create mode 100644 plugins/gs/GSsoft/Src/Regs.c create mode 100644 plugins/gs/GSsoft/Src/Regs.h create mode 100644 plugins/gs/GSsoft/Src/SDL.c create mode 100644 plugins/gs/GSsoft/Src/SDL_gfxPrimitives.c create mode 100644 plugins/gs/GSsoft/Src/SDL_gfxPrimitives.h create mode 100644 plugins/gs/GSsoft/Src/SDL_gfxPrimitives_font.h create mode 100644 plugins/gs/GSsoft/Src/Soft.c create mode 100644 plugins/gs/GSsoft/Src/Soft.h create mode 100644 plugins/gs/GSsoft/Src/System.h create mode 100644 plugins/gs/GSsoft/Src/Texts.c create mode 100644 plugins/gs/GSsoft/Src/Texts.h create mode 100644 plugins/gs/GSsoft/Src/Transfer.c create mode 100644 plugins/gs/GSsoft/Src/Transfer.h create mode 100644 plugins/gs/GSsoft/Src/Win32/Conf.c create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.def create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsp create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsw create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.ncb create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.rc create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.sln create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.suo create mode 100644 plugins/gs/GSsoft/Src/Win32/GSsoftdx.vcproj create mode 100644 plugins/gs/GSsoft/Src/Win32/Makefile create mode 100644 plugins/gs/GSsoft/Src/Win32/SDL.c create mode 100644 plugins/gs/GSsoft/Src/Win32/Win32.c create mode 100644 plugins/gs/GSsoft/Src/Win32/Win32.h create mode 100644 plugins/gs/GSsoft/Src/Win32/afxresmw.h create mode 100644 plugins/gs/GSsoft/Src/Win32/plugin.def create mode 100644 plugins/gs/GSsoft/Src/Win32/plugin.h create mode 100644 plugins/gs/GSsoft/Src/Win32/resource.h create mode 100644 plugins/gs/GSsoft/Src/avcodec.h create mode 100644 plugins/gs/GSsoft/Src/common.h create mode 100644 plugins/gs/GSsoft/Src/ffmpeg/avformat.h create mode 100644 plugins/gs/GSsoft/Src/ffmpeg/avio.h create mode 100644 plugins/gs/GSsoft/Src/ffmpeg/rtp.h create mode 100644 plugins/gs/GSsoft/Src/ffmpeg/rtsp.h create mode 100644 plugins/gs/GSsoft/Src/ffmpeg/rtspcodes.h create mode 100644 plugins/gs/GSsoft/Src/scale2x.c create mode 100644 plugins/gs/GSsoft/Src/scale2x.h create mode 100644 plugins/gs/GSsoft/Src/x86/ix86.h create mode 100644 plugins/gs/GSsoft/Src/x86/ix86_cpudetect.c create mode 100644 plugins/gs/build.sh create mode 100644 plugins/gs/gsdx9/GS.cpp create mode 100644 plugins/gs/gsdx9/GS.h create mode 100644 plugins/gs/gsdx9/GSCapture.cpp create mode 100644 plugins/gs/gsdx9/GSCapture.h create mode 100644 plugins/gs/gsdx9/GSCaptureDlg.cpp create mode 100644 plugins/gs/gsdx9/GSCaptureDlg.h create mode 100644 plugins/gs/gsdx9/GSHash.cpp create mode 100644 plugins/gs/gsdx9/GSHash.h create mode 100644 plugins/gs/gsdx9/GSLocalMemory.cpp create mode 100644 plugins/gs/gsdx9/GSLocalMemory.h create mode 100644 plugins/gs/gsdx9/GSPerfMon.cpp create mode 100644 plugins/gs/gsdx9/GSPerfMon.h create mode 100644 plugins/gs/gsdx9/GSRegs.cpp create mode 100644 plugins/gs/gsdx9/GSRenderer.cpp create mode 100644 plugins/gs/gsdx9/GSRenderer.h create mode 100644 plugins/gs/gsdx9/GSRendererHW.cpp create mode 100644 plugins/gs/gsdx9/GSRendererHW.h create mode 100644 plugins/gs/gsdx9/GSRendererNull.cpp create mode 100644 plugins/gs/gsdx9/GSRendererNull.h create mode 100644 plugins/gs/gsdx9/GSRendererSoft.cpp create mode 100644 plugins/gs/gsdx9/GSRendererSoft.h create mode 100644 plugins/gs/gsdx9/GSSettingsDlg.cpp create mode 100644 plugins/gs/gsdx9/GSSettingsDlg.h create mode 100644 plugins/gs/gsdx9/GSSoftVertex.cpp create mode 100644 plugins/gs/gsdx9/GSSoftVertex.h create mode 100644 plugins/gs/gsdx9/GSSoftVertexFP.h create mode 100644 plugins/gs/gsdx9/GSSoftVertexFX.h create mode 100644 plugins/gs/gsdx9/GSState.cpp create mode 100644 plugins/gs/gsdx9/GSState.h create mode 100644 plugins/gs/gsdx9/GSTables.cpp create mode 100644 plugins/gs/gsdx9/GSTables.h create mode 100644 plugins/gs/gsdx9/GSTextureCache.cpp create mode 100644 plugins/gs/gsdx9/GSTextureCache.h create mode 100644 plugins/gs/gsdx9/GSTransfer.cpp create mode 100644 plugins/gs/gsdx9/GSUtil.cpp create mode 100644 plugins/gs/gsdx9/GSUtil.h create mode 100644 plugins/gs/gsdx9/GSVertexList.cpp create mode 100644 plugins/gs/gsdx9/GSVertexList.h create mode 100644 plugins/gs/gsdx9/GSWnd.cpp create mode 100644 plugins/gs/gsdx9/GSWnd.h create mode 100644 plugins/gs/gsdx9/GSdx9.cpp create mode 100644 plugins/gs/gsdx9/GSdx9.def create mode 100644 plugins/gs/gsdx9/GSdx9.h create mode 100644 plugins/gs/gsdx9/GSdx9.icproj create mode 100644 plugins/gs/gsdx9/GSdx9.rc create mode 100644 plugins/gs/gsdx9/GSdx9_vs2005.sln create mode 100644 plugins/gs/gsdx9/GSdx9_vs2005.vcproj create mode 100644 plugins/gs/gsdx9/baseclasses/Amvideo.h create mode 100644 plugins/gs/gsdx9/baseclasses/activex.rcv create mode 100644 plugins/gs/gsdx9/baseclasses/activex.ver create mode 100644 plugins/gs/gsdx9/baseclasses/amaudio.h create mode 100644 plugins/gs/gsdx9/baseclasses/amextra.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/amextra.h create mode 100644 plugins/gs/gsdx9/baseclasses/amfilter.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/amfilter.h create mode 100644 plugins/gs/gsdx9/baseclasses/amvideo.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/audevcod.h create mode 100644 plugins/gs/gsdx9/baseclasses/baseclasses.vcproj create mode 100644 plugins/gs/gsdx9/baseclasses/baseclasses.vcproj.REFRACTION.Administrator.user create mode 100644 plugins/gs/gsdx9/baseclasses/cache.h create mode 100644 plugins/gs/gsdx9/baseclasses/combase.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/combase.h create mode 100644 plugins/gs/gsdx9/baseclasses/comlite.h create mode 100644 plugins/gs/gsdx9/baseclasses/cprop.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/cprop.h create mode 100644 plugins/gs/gsdx9/baseclasses/ctlutil.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/ctlutil.h create mode 100644 plugins/gs/gsdx9/baseclasses/ddmm.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/ddmm.h create mode 100644 plugins/gs/gsdx9/baseclasses/dllentry.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/dllsetup.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/dllsetup.h create mode 100644 plugins/gs/gsdx9/baseclasses/dshow.h create mode 100644 plugins/gs/gsdx9/baseclasses/dsschedule.h create mode 100644 plugins/gs/gsdx9/baseclasses/dvdevcod.h create mode 100644 plugins/gs/gsdx9/baseclasses/dvdmedia.h create mode 100644 plugins/gs/gsdx9/baseclasses/edevdefs.h create mode 100644 plugins/gs/gsdx9/baseclasses/errors.h create mode 100644 plugins/gs/gsdx9/baseclasses/evcode.h create mode 100644 plugins/gs/gsdx9/baseclasses/fourcc.h create mode 100644 plugins/gs/gsdx9/baseclasses/measure.h create mode 100644 plugins/gs/gsdx9/baseclasses/msgthrd.h create mode 100644 plugins/gs/gsdx9/baseclasses/mtype.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/mtype.h create mode 100644 plugins/gs/gsdx9/baseclasses/outputq.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/outputq.h create mode 100644 plugins/gs/gsdx9/baseclasses/pstream.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/pstream.h create mode 100644 plugins/gs/gsdx9/baseclasses/pullpin.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/pullpin.h create mode 100644 plugins/gs/gsdx9/baseclasses/refclock.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/refclock.h create mode 100644 plugins/gs/gsdx9/baseclasses/reftime.h create mode 100644 plugins/gs/gsdx9/baseclasses/renbase.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/renbase.h create mode 100644 plugins/gs/gsdx9/baseclasses/schedule.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/schedule.h create mode 100644 plugins/gs/gsdx9/baseclasses/seekpt.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/seekpt.h create mode 100644 plugins/gs/gsdx9/baseclasses/source.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/source.h create mode 100644 plugins/gs/gsdx9/baseclasses/streams.h create mode 100644 plugins/gs/gsdx9/baseclasses/strmctl.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/strmctl.h create mode 100644 plugins/gs/gsdx9/baseclasses/strmiids.lib create mode 100644 plugins/gs/gsdx9/baseclasses/sysclock.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/sysclock.h create mode 100644 plugins/gs/gsdx9/baseclasses/transfrm.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/transfrm.h create mode 100644 plugins/gs/gsdx9/baseclasses/transip.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/transip.h create mode 100644 plugins/gs/gsdx9/baseclasses/vfwmsgs.h create mode 100644 plugins/gs/gsdx9/baseclasses/videoctl.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/videoctl.h create mode 100644 plugins/gs/gsdx9/baseclasses/vtrans.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/vtrans.h create mode 100644 plugins/gs/gsdx9/baseclasses/winctrl.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/winctrl.h create mode 100644 plugins/gs/gsdx9/baseclasses/winutil.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/winutil.h create mode 100644 plugins/gs/gsdx9/baseclasses/wxdebug.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/wxdebug.h create mode 100644 plugins/gs/gsdx9/baseclasses/wxlist.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/wxlist.h create mode 100644 plugins/gs/gsdx9/baseclasses/wxutil.cpp create mode 100644 plugins/gs/gsdx9/baseclasses/wxutil.h create mode 100644 plugins/gs/gsdx9/res/GSdx9.rc2 create mode 100644 plugins/gs/gsdx9/res/hlsl_merge.fx create mode 100644 plugins/gs/gsdx9/res/hlsl_rb.fx create mode 100644 plugins/gs/gsdx9/res/hlsl_tfx.fx create mode 100644 plugins/gs/gsdx9/res/logo1.bmp create mode 100644 plugins/gs/gsdx9/res/ps11_en00.psh create mode 100644 plugins/gs/gsdx9/res/ps11_en01.psh create mode 100644 plugins/gs/gsdx9/res/ps11_en10.psh create mode 100644 plugins/gs/gsdx9/res/ps11_en11.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx000.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx010.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx011.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx1x0.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx1x1.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx200.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx210.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx211.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx300.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx310.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx311.psh create mode 100644 plugins/gs/gsdx9/res/ps11_tfx4xx.psh create mode 100644 plugins/gs/gsdx9/res/ps14_en00.psh create mode 100644 plugins/gs/gsdx9/res/ps14_en01.psh create mode 100644 plugins/gs/gsdx9/res/ps14_en10.psh create mode 100644 plugins/gs/gsdx9/res/ps14_en11.psh create mode 100644 plugins/gs/gsdx9/resource.h create mode 100644 plugins/gs/gsdx9/stdafx.cpp create mode 100644 plugins/gs/gsdx9/stdafx.h create mode 100644 plugins/gs/gsdx9/x86-32.asm create mode 100644 plugins/gs/gsdx9/x86-64.asm create mode 100644 plugins/gs/gsdx9/x86.cpp create mode 100644 plugins/gs/gsdx9/x86.h create mode 100644 plugins/gs/zerogs/build.sh create mode 100644 plugins/gs/zerogs/dx/GS.h create mode 100644 plugins/gs/zerogs/dx/GSmain.cpp create mode 100644 plugins/gs/zerogs/dx/Mem.cpp create mode 100644 plugins/gs/zerogs/dx/Mem.h create mode 100644 plugins/gs/zerogs/dx/PS2Edefs.h create mode 100644 plugins/gs/zerogs/dx/PS2Etypes.h create mode 100644 plugins/gs/zerogs/dx/README.txt create mode 100644 plugins/gs/zerogs/dx/Regs.cpp create mode 100644 plugins/gs/zerogs/dx/Regs.h create mode 100644 plugins/gs/zerogs/dx/Win32/Conf.cpp create mode 100644 plugins/gs/zerogs/dx/Win32/GSsoftdx.def create mode 100644 plugins/gs/zerogs/dx/Win32/Win32.cpp create mode 100644 plugins/gs/zerogs/dx/Win32/Win32.h create mode 100644 plugins/gs/zerogs/dx/Win32/aviUtil.h create mode 100644 plugins/gs/zerogs/dx/Win32/copytopcsx2.bat create mode 100644 plugins/gs/zerogs/dx/Win32/plugin.def create mode 100644 plugins/gs/zerogs/dx/Win32/ps2fx.dat create mode 100644 plugins/gs/zerogs/dx/Win32/resource.h create mode 100644 plugins/gs/zerogs/dx/Win32/resrc1.h create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs.bmp create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs.rc create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs.sln create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs.vcproj create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs_2005.sln create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs_2005.vcproj create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs_2005_x64.vcproj create mode 100644 plugins/gs/zerogs/dx/Win32/zerogs_2008.vcproj create mode 100644 plugins/gs/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj create mode 100644 plugins/gs/zerogs/dx/ZeroGSShaders/copytozerogs.bat create mode 100644 plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp create mode 100644 plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.h create mode 100644 plugins/gs/zerogs/dx/backup.bat create mode 100644 plugins/gs/zerogs/dx/buildshaders.bat create mode 100644 plugins/gs/zerogs/dx/common.h create mode 100644 plugins/gs/zerogs/dx/memcpy_amd.cpp create mode 100644 plugins/gs/zerogs/dx/ps2hw.fx create mode 100644 plugins/gs/zerogs/dx/ps2hw_ctx0.fx create mode 100644 plugins/gs/zerogs/dx/ps2hw_ctx1.fx create mode 100644 plugins/gs/zerogs/dx/targets.cpp create mode 100644 plugins/gs/zerogs/dx/targets.h create mode 100644 plugins/gs/zerogs/dx/x86-32.asm create mode 100644 plugins/gs/zerogs/dx/x86-64.asm create mode 100644 plugins/gs/zerogs/dx/x86.cpp create mode 100644 plugins/gs/zerogs/dx/x86.h create mode 100644 plugins/gs/zerogs/dx/zerogs.cpp create mode 100644 plugins/gs/zerogs/dx/zerogs.h create mode 100644 plugins/gs/zerogs/opengl/GS.h create mode 100644 plugins/gs/zerogs/opengl/GSmain.cpp create mode 100644 plugins/gs/zerogs/opengl/Linux/Conf.cpp create mode 100644 plugins/gs/zerogs/opengl/Linux/Linux.cpp create mode 100644 plugins/gs/zerogs/opengl/Linux/Linux.h create mode 100644 plugins/gs/zerogs/opengl/Linux/Makefile.am create mode 100644 plugins/gs/zerogs/opengl/Linux/buildgui.sh create mode 100644 plugins/gs/zerogs/opengl/Linux/callbacks.c create mode 100644 plugins/gs/zerogs/opengl/Linux/callbacks.h create mode 100644 plugins/gs/zerogs/opengl/Linux/interface.c create mode 100644 plugins/gs/zerogs/opengl/Linux/interface.h create mode 100644 plugins/gs/zerogs/opengl/Linux/support.c create mode 100644 plugins/gs/zerogs/opengl/Linux/support.h create mode 100644 plugins/gs/zerogs/opengl/Linux/zerogs.glade create mode 100644 plugins/gs/zerogs/opengl/Makefile.am create mode 100644 plugins/gs/zerogs/opengl/Mem.cpp create mode 100644 plugins/gs/zerogs/opengl/Mem.h create mode 100644 plugins/gs/zerogs/opengl/PS2Edefs.h create mode 100644 plugins/gs/zerogs/opengl/PS2Etypes.h create mode 100644 plugins/gs/zerogs/opengl/README.txt create mode 100644 plugins/gs/zerogs/opengl/Regs.cpp create mode 100644 plugins/gs/zerogs/opengl/Regs.h create mode 100644 plugins/gs/zerogs/opengl/Win32/Conf.cpp create mode 100644 plugins/gs/zerogs/opengl/Win32/Win32.cpp create mode 100644 plugins/gs/zerogs/opengl/Win32/Win32.h create mode 100644 plugins/gs/zerogs/opengl/Win32/aviUtil.h create mode 100644 plugins/gs/zerogs/opengl/Win32/copytopcsx2.bat create mode 100644 plugins/gs/zerogs/opengl/Win32/jconfig.h create mode 100644 plugins/gs/zerogs/opengl/Win32/jmorecfg.h create mode 100644 plugins/gs/zerogs/opengl/Win32/jpeglib.h create mode 100644 plugins/gs/zerogs/opengl/Win32/libjpeg.lib create mode 100644 plugins/gs/zerogs/opengl/Win32/libjpeg64.lib create mode 100644 plugins/gs/zerogs/opengl/Win32/ps2hw.dat create mode 100644 plugins/gs/zerogs/opengl/Win32/resource.h create mode 100644 plugins/gs/zerogs/opengl/Win32/resrc1.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogs.bmp create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogs.def create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogs.rc create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogsogl.vcproj create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogsogl_2005.vcproj create mode 100644 plugins/gs/zerogs/opengl/Win32/zerogsogl_2005_x64.vcproj create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/adler32.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/compress.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/crc32.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/crc32.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/deflate.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/deflate.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/gzio.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/infback.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inffast.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inffast.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inffixed.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inflate.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inflate.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inftrees.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/inftrees.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/trees.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/trees.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/uncompr.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/zconf.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/zlib.h create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/zutil.c create mode 100644 plugins/gs/zerogs/opengl/Win32/zlib/zutil.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/Makefile.am create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/ZLib.lib create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders.vcproj create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/copytozerogs.bat create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/crc32.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/deflate.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffast.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inflate.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/trees.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zlib.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zutil.h create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.cpp create mode 100644 plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.h create mode 100644 plugins/gs/zerogs/opengl/buildshaders.bat create mode 100644 plugins/gs/zerogs/opengl/common.h create mode 100644 plugins/gs/zerogs/opengl/compile create mode 100644 plugins/gs/zerogs/opengl/configure create mode 100644 plugins/gs/zerogs/opengl/configure.ac create mode 100644 plugins/gs/zerogs/opengl/ctx0/ps2hw_ctx.fx create mode 100644 plugins/gs/zerogs/opengl/ctx1/ps2hw_ctx.fx create mode 100644 plugins/gs/zerogs/opengl/depcomp create mode 100644 plugins/gs/zerogs/opengl/glprocs.c create mode 100644 plugins/gs/zerogs/opengl/glprocs.h create mode 100644 plugins/gs/zerogs/opengl/install-sh create mode 100644 plugins/gs/zerogs/opengl/memcpy_amd.cpp create mode 100644 plugins/gs/zerogs/opengl/missing create mode 100644 plugins/gs/zerogs/opengl/mkinstalldirs create mode 100644 plugins/gs/zerogs/opengl/ps2hw.fx create mode 100644 plugins/gs/zerogs/opengl/rasterfont.cpp create mode 100644 plugins/gs/zerogs/opengl/rasterfont.h create mode 100644 plugins/gs/zerogs/opengl/targets.cpp create mode 100644 plugins/gs/zerogs/opengl/targets.h create mode 100644 plugins/gs/zerogs/opengl/x86-32.S create mode 100644 plugins/gs/zerogs/opengl/x86-32.asm create mode 100644 plugins/gs/zerogs/opengl/x86-64.S create mode 100644 plugins/gs/zerogs/opengl/x86-64.asm create mode 100644 plugins/gs/zerogs/opengl/x86.cpp create mode 100644 plugins/gs/zerogs/opengl/x86.h create mode 100644 plugins/gs/zerogs/opengl/zerogs.cpp create mode 100644 plugins/gs/zerogs/opengl/zerogs.h create mode 100644 plugins/gs/zerogs/opengl/zerogsmath.h create mode 100644 plugins/gs/zerogs/opengl/zpipe.cpp create mode 100644 plugins/gs/zerogs/opengl/zpipe.h create mode 100644 plugins/pad/PADwin/ReadMe.txt create mode 100644 plugins/pad/PADwin/Src/Conf.c create mode 100644 plugins/pad/PADwin/Src/Linux.c create mode 100644 plugins/pad/PADwin/Src/Makefile create mode 100644 plugins/pad/PADwin/Src/Makefile.mingw create mode 100644 plugins/pad/PADwin/Src/PAD.c create mode 100644 plugins/pad/PADwin/Src/PAD.h create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.def create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.dsp create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.dsw create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.sln create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.suo create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb.vcproj create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.sln create mode 100644 plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.vcproj create mode 100644 plugins/pad/PADwin/Src/PADwnKeyb.rc create mode 100644 plugins/pad/PADwin/Src/PS2Edefs.h create mode 100644 plugins/pad/PADwin/Src/PS2Etypes.h create mode 100644 plugins/pad/PADwin/Src/Win32.c create mode 100644 plugins/pad/PADwin/Src/afxresmw.h create mode 100644 plugins/pad/PADwin/Src/callbacks.c create mode 100644 plugins/pad/PADwin/Src/callbacks.h create mode 100644 plugins/pad/PADwin/Src/controller.bmp create mode 100644 plugins/pad/PADwin/Src/interface.c create mode 100644 plugins/pad/PADwin/Src/interface.h create mode 100644 plugins/pad/PADwin/Src/mingw/Makefile.win create mode 100644 plugins/pad/PADwin/Src/mingw/PADwinKeyb.dev create mode 100644 plugins/pad/PADwin/Src/mingw/PADwinKeyb.layout create mode 100644 plugins/pad/PADwin/Src/mingw/afxres.h create mode 100644 plugins/pad/PADwin/Src/plugin.def create mode 100644 plugins/pad/PADwin/Src/ps2pad.bmp create mode 100644 plugins/pad/PADwin/Src/resource.h create mode 100644 plugins/pad/PADwin/Src/support.c create mode 100644 plugins/pad/PADwin/Src/support.h create mode 100644 plugins/pad/PADwin/build.sh create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX.cpp create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX.def create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX.h create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX.rc create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX.vcproj create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX_2005_x64.vcproj create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.sln create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.vcproj create mode 100644 plugins/pad/SSSPSXPAD/PadSSSPSXres.h create mode 100644 plugins/pad/SSSPSXPAD/licence.txt create mode 100644 plugins/pad/SSSPSXPAD/readmewip.txt create mode 100644 plugins/pad/build.sh create mode 100644 plugins/pad/zeropad/Linux/callbacks.h create mode 100644 plugins/pad/zeropad/Linux/interface.c create mode 100644 plugins/pad/zeropad/Linux/interface.h create mode 100644 plugins/pad/zeropad/Linux/linux.cpp create mode 100644 plugins/pad/zeropad/Linux/support.c create mode 100644 plugins/pad/zeropad/Linux/support.h create mode 100644 plugins/pad/zeropad/Linux/zeropad.glade create mode 100644 plugins/pad/zeropad/Makefile.am create mode 100644 plugins/pad/zeropad/PS2Edefs.h create mode 100644 plugins/pad/zeropad/PS2Etypes.h create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD.def create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD.rc create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD.vcproj create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD_2005.vcproj create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD_2005_x64.vcproj create mode 100644 plugins/pad/zeropad/Windows/ZeroPAD_2008.vcproj create mode 100644 plugins/pad/zeropad/Windows/libs/pthread.h create mode 100644 plugins/pad/zeropad/Windows/libs/pthreadVC2.lib create mode 100644 plugins/pad/zeropad/Windows/libs/sched.h create mode 100644 plugins/pad/zeropad/Windows/libs/semaphore.h create mode 100644 plugins/pad/zeropad/Windows/resource.h create mode 100644 plugins/pad/zeropad/Windows/win.cpp create mode 100644 plugins/pad/zeropad/build.sh create mode 100644 plugins/pad/zeropad/configure.ac create mode 100644 plugins/pad/zeropad/depcomp create mode 100644 plugins/pad/zeropad/mkinstalldirs create mode 100644 plugins/pad/zeropad/zeropad.cpp create mode 100644 plugins/pad/zeropad/zeropad.h create mode 100644 plugins/spu2/PeopsSPU2/Filemap.txt create mode 100644 plugins/spu2/PeopsSPU2/Makefile create mode 100644 plugins/spu2/PeopsSPU2/Makefile.win create mode 100644 plugins/spu2/PeopsSPU2/_bsc.txt create mode 100644 plugins/spu2/PeopsSPU2/adsr.c create mode 100644 plugins/spu2/PeopsSPU2/adsr.h create mode 100644 plugins/spu2/PeopsSPU2/alsa.c create mode 100644 plugins/spu2/PeopsSPU2/alsa.h create mode 100644 plugins/spu2/PeopsSPU2/build.sh create mode 100644 plugins/spu2/PeopsSPU2/cfg.c create mode 100644 plugins/spu2/PeopsSPU2/cfg.h create mode 100644 plugins/spu2/PeopsSPU2/clean.bat create mode 100644 plugins/spu2/PeopsSPU2/debug.c create mode 100644 plugins/spu2/PeopsSPU2/debug.h create mode 100644 plugins/spu2/PeopsSPU2/dma.c create mode 100644 plugins/spu2/PeopsSPU2/dma.h create mode 100644 plugins/spu2/PeopsSPU2/dsound.c create mode 100644 plugins/spu2/PeopsSPU2/dsound.h create mode 100644 plugins/spu2/PeopsSPU2/dsoundoss.h create mode 100644 plugins/spu2/PeopsSPU2/externals.h create mode 100644 plugins/spu2/PeopsSPU2/freeze.c create mode 100644 plugins/spu2/PeopsSPU2/gauss_i.h create mode 100644 plugins/spu2/PeopsSPU2/mingw/afxres.h create mode 100644 plugins/spu2/PeopsSPU2/oss.c create mode 100644 plugins/spu2/PeopsSPU2/oss.h create mode 100644 plugins/spu2/PeopsSPU2/psemu.c create mode 100644 plugins/spu2/PeopsSPU2/psemuxa.h create mode 100644 plugins/spu2/PeopsSPU2/record.c create mode 100644 plugins/spu2/PeopsSPU2/record.h create mode 100644 plugins/spu2/PeopsSPU2/registers.c create mode 100644 plugins/spu2/PeopsSPU2/registers.h create mode 100644 plugins/spu2/PeopsSPU2/regs.h create mode 100644 plugins/spu2/PeopsSPU2/res/spu2PeopsSound.rc2 create mode 100644 plugins/spu2/PeopsSPU2/resource.h create mode 100644 plugins/spu2/PeopsSPU2/reverb.c create mode 100644 plugins/spu2/PeopsSPU2/reverb.h create mode 100644 plugins/spu2/PeopsSPU2/spu.c create mode 100644 plugins/spu2/PeopsSPU2/spu.h create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.aps create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.c create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.def create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.dev create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.dsp create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.dsw create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.layout create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.opt create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.plg create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.rc create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.sln create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound.vcproj create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.sln create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.vcproj create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.sln create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.vcproj create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_2008.vcproj create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_private.h create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_private.rc create mode 100644 plugins/spu2/PeopsSPU2/spu2PeopsSound_private.res create mode 100644 plugins/spu2/PeopsSPU2/spunew.c create mode 100644 plugins/spu2/PeopsSPU2/stdafx.c create mode 100644 plugins/spu2/PeopsSPU2/stdafx.h create mode 100644 plugins/spu2/PeopsSPU2/xa.c create mode 100644 plugins/spu2/PeopsSPU2/xa.h create mode 100644 plugins/spu2/SPU2null/License.txt create mode 100644 plugins/spu2/SPU2null/ReadMe.txt create mode 100644 plugins/spu2/SPU2null/Src/Changelog.txt create mode 100644 plugins/spu2/SPU2null/Src/Config.cpp create mode 100644 plugins/spu2/SPU2null/Src/Makefile create mode 100644 plugins/spu2/SPU2null/Src/Makefile.mingw create mode 100644 plugins/spu2/SPU2null/Src/PS2Edefs.h create mode 100644 plugins/spu2/SPU2null/Src/PS2Etypes.h create mode 100644 plugins/spu2/SPU2null/Src/SPU2.cpp create mode 100644 plugins/spu2/SPU2null/Src/SPU2.h create mode 100644 plugins/spu2/SPU2null/Src/SPU2null.def create mode 100644 plugins/spu2/SPU2null/Src/SPU2null.ncb create mode 100644 plugins/spu2/SPU2null/Src/SPU2null.rc create mode 100644 plugins/spu2/SPU2null/Src/SPU2null.sln create mode 100644 plugins/spu2/SPU2null/Src/SPU2null.vcproj create mode 100644 plugins/spu2/SPU2null/Src/SPU2null_2005.sln create mode 100644 plugins/spu2/SPU2null/Src/SPU2null_2005.vcproj create mode 100644 plugins/spu2/SPU2null/Src/SPU2null_2005_x64.sln create mode 100644 plugins/spu2/SPU2null/Src/SPU2null_2005_x64.vcproj create mode 100644 plugins/spu2/SPU2null/Src/SPU2null_2008.vcproj create mode 100644 plugins/spu2/SPU2null/Src/Win32.cpp create mode 100644 plugins/spu2/SPU2null/Src/mingw/Makefile.win create mode 100644 plugins/spu2/SPU2null/Src/mingw/SPU2null.dev create mode 100644 plugins/spu2/SPU2null/Src/mingw/afxres.h create mode 100644 plugins/spu2/SPU2null/Src/mingw/plugin.def create mode 100644 plugins/spu2/SPU2null/Src/resource.h create mode 100644 plugins/spu2/SPU2null/build.sh create mode 100644 plugins/spu2/build.sh create mode 100644 plugins/spu2/zerospu2/Linux.cpp create mode 100644 plugins/spu2/zerospu2/Makefile.am create mode 100644 plugins/spu2/zerospu2/PS2Edefs.h create mode 100644 plugins/spu2/zerospu2/PS2Etypes.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/3dnow_win.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/AAFilter.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/AAFilter.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/BPMDetect.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/FIFOSamplePipe.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/FIRFilter.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/FIRFilter.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/Makefile.am create mode 100644 plugins/spu2/zerospu2/SoundTouch/RateTransposer.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/RateTransposer.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/STTypes.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/SoundTouch.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/SoundTouch.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/TDStretch.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/TDStretch.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/WavFile.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/WavFile.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/cpu_detect.h create mode 100644 plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_gcc.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_win.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/mmx_optimized.cpp create mode 100644 plugins/spu2/zerospu2/SoundTouch/sse_optimized.cpp create mode 100644 plugins/spu2/zerospu2/Win32.cpp create mode 100644 plugins/spu2/zerospu2/ZeroSPU2.def create mode 100644 plugins/spu2/zerospu2/ZeroSPU2.rc create mode 100644 plugins/spu2/zerospu2/ZeroSPU2.vcproj create mode 100644 plugins/spu2/zerospu2/ZeroSPU2_2005.vcproj create mode 100644 plugins/spu2/zerospu2/ZeroSPU2_2005_x64.vcproj create mode 100644 plugins/spu2/zerospu2/ZeroSPU2_2008.vcproj create mode 100644 plugins/spu2/zerospu2/build.sh create mode 100644 plugins/spu2/zerospu2/compile create mode 100644 plugins/spu2/zerospu2/configure.ac create mode 100644 plugins/spu2/zerospu2/depcomp create mode 100644 plugins/spu2/zerospu2/install-sh create mode 100644 plugins/spu2/zerospu2/missing create mode 100644 plugins/spu2/zerospu2/mkinstalldirs create mode 100644 plugins/spu2/zerospu2/resource.h create mode 100644 plugins/spu2/zerospu2/zerospu2.cpp create mode 100644 plugins/spu2/zerospu2/zerospu2.h create mode 100644 plugins/usb/USBlinuz/License.txt create mode 100644 plugins/usb/USBlinuz/Linux/Config.c create mode 100644 plugins/usb/USBlinuz/Linux/Config.h create mode 100644 plugins/usb/USBlinuz/Linux/Linux.c create mode 100644 plugins/usb/USBlinuz/Linux/Makefile create mode 100644 plugins/usb/USBlinuz/Linux/callbacks.c create mode 100644 plugins/usb/USBlinuz/Linux/callbacks.h create mode 100644 plugins/usb/USBlinuz/Linux/conf.c create mode 100644 plugins/usb/USBlinuz/Linux/interface.c create mode 100644 plugins/usb/USBlinuz/Linux/interface.h create mode 100644 plugins/usb/USBlinuz/Linux/support.c create mode 100644 plugins/usb/USBlinuz/Linux/support.h create mode 100644 plugins/usb/USBlinuz/Linux/usblinuz.glade create mode 100644 plugins/usb/USBlinuz/PS2Edefs.h create mode 100644 plugins/usb/USBlinuz/PS2Etypes.h create mode 100644 plugins/usb/USBlinuz/ReadMe.txt create mode 100644 plugins/usb/USBlinuz/USB.c create mode 100644 plugins/usb/USBlinuz/USB.h create mode 100644 plugins/usb/USBlinuz/Win32/Config.c create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.def create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.dsp create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.dsw create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.rc create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.sln create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.suo create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz.vcproj create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.sln create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.vcproj create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.ncb create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.sln create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.suo create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.vcproj create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.sln create mode 100644 plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.vcproj create mode 100644 plugins/usb/USBlinuz/Win32/Win32.c create mode 100644 plugins/usb/USBlinuz/Win32/resource.h create mode 100644 plugins/usb/USBnull/License.txt create mode 100644 plugins/usb/USBnull/Linux/Config.c create mode 100644 plugins/usb/USBnull/Linux/Config.h create mode 100644 plugins/usb/USBnull/Linux/Linux.c create mode 100644 plugins/usb/USBnull/Linux/Makefile create mode 100644 plugins/usb/USBnull/Linux/callbacks.c create mode 100644 plugins/usb/USBnull/Linux/callbacks.h create mode 100644 plugins/usb/USBnull/Linux/conf.c create mode 100644 plugins/usb/USBnull/Linux/interface.c create mode 100644 plugins/usb/USBnull/Linux/interface.h create mode 100644 plugins/usb/USBnull/Linux/support.c create mode 100644 plugins/usb/USBnull/Linux/support.h create mode 100644 plugins/usb/USBnull/Linux/usbnull.glade create mode 100644 plugins/usb/USBnull/PS2Edefs.h create mode 100644 plugins/usb/USBnull/PS2Etypes.h create mode 100644 plugins/usb/USBnull/ReadMe.txt create mode 100644 plugins/usb/USBnull/USB.c create mode 100644 plugins/usb/USBnull/USB.h create mode 100644 plugins/usb/USBnull/Win32/Config.c create mode 100644 plugins/usb/USBnull/Win32/Makefile create mode 100644 plugins/usb/USBnull/Win32/USBnull.def create mode 100644 plugins/usb/USBnull/Win32/USBnull.dsp create mode 100644 plugins/usb/USBnull/Win32/USBnull.dsw create mode 100644 plugins/usb/USBnull/Win32/USBnull.rc create mode 100644 plugins/usb/USBnull/Win32/USBnull_2005_x64.vcproj create mode 100644 plugins/usb/USBnull/Win32/USBnull_vc2003.sln create mode 100644 plugins/usb/USBnull/Win32/USBnull_vc2003.vcproj create mode 100644 plugins/usb/USBnull/Win32/USBnull_vc2005beta1.sln create mode 100644 plugins/usb/USBnull/Win32/USBnull_vc2005beta1.vcproj create mode 100644 plugins/usb/USBnull/Win32/Win32.c create mode 100644 plugins/usb/USBnull/Win32/afxresmw.h create mode 100644 plugins/usb/USBnull/Win32/mingw/Makefile.win create mode 100644 plugins/usb/USBnull/Win32/mingw/USBnull.dev create mode 100644 plugins/usb/USBnull/Win32/mingw/USBnull.layout create mode 100644 plugins/usb/USBnull/Win32/mingw/afxres.h create mode 100644 plugins/usb/USBnull/Win32/resource.h create mode 100644 plugins/usb/USBnull/build.sh create mode 100644 plugins/usb/USBqemu/License-qemu.txt create mode 100644 plugins/usb/USBqemu/License.txt create mode 100644 plugins/usb/USBqemu/PS2Edefs.h create mode 100644 plugins/usb/USBqemu/PS2Etypes.h create mode 100644 plugins/usb/USBqemu/ReadMe.txt create mode 100644 plugins/usb/USBqemu/USB.cpp create mode 100644 plugins/usb/USBqemu/USB.h create mode 100644 plugins/usb/USBqemu/Win32/Config.cpp create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz.aps create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz.def create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz.rc create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2005.sln create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2005.vcproj create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.sln create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.vcproj create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.sln create mode 100644 plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.vcproj create mode 100644 plugins/usb/USBqemu/Win32/Win32.cpp create mode 100644 plugins/usb/USBqemu/Win32/resource.h create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-base.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-hid.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-hub.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-kbd.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-msd.c create mode 100644 plugins/usb/USBqemu/qemu-usb/usb-ohci.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/usb.h create mode 100644 plugins/usb/USBqemu/qemu-usb/vl.cpp create mode 100644 plugins/usb/USBqemu/qemu-usb/vl.h create mode 100644 plugins/usb/USBqemu/usb-eyetoy/usb-eyetoy.cpp create mode 100644 plugins/usb/USBqemu/usb-mic/adcuser.h create mode 100644 plugins/usb/USBqemu/usb-mic/audio.h create mode 100644 plugins/usb/USBqemu/usb-mic/demo.h create mode 100644 plugins/usb/USBqemu/usb-mic/type.h create mode 100644 plugins/usb/USBqemu/usb-mic/usb-mic-dummy.cpp create mode 100644 plugins/usb/USBqemu/usb-mic/usb-mic.c create mode 100644 plugins/usb/USBqemu/usb-mic/usb.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbcfg.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbcore.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbdesc.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbhw.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbreg.h create mode 100644 plugins/usb/USBqemu/usb-mic/usbuser.h create mode 100644 plugins/usb/build.sh create mode 100644 test.bat create mode 100644 test.cfg create mode 100644 test.sh create mode 100644 test_readme.txt diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000000..61a151b9b3 --- /dev/null +++ b/INSTALL @@ -0,0 +1,87 @@ + Pcsx2 Compilation Guide + +Linux Users +----------- + +Make sure you have these packages: +gtk2 +opengl +libbz2 +libjpeg +glew-dev +libxxf86vm-dev +x11proto-xf86vidmode +automake and autoconf (verion >= 1.9) +Nvidia Cg-Toolkit (http://developer.nvidia.com/object/cg_toolkit.html) +libasound-dev +joystick + +When first building, the Pcsx2 programs need to configure the Makefiles for your specific OS. type: + +# sh build.sh all + +The program and all plugins will be installed in the pcsx2 bin dir. After that, just launch pcsx2 (make sure you have a PS2 bios dump in the bios directory). + +To rebuild any changes to the source code type: +# sh build.sh install + +Typeing sh build.sh without the install will just build the programs without copying them to the bin dirctory (bin/plugins for all plugins). + +To clean all object files type: +# sh build.sh clean + +If there is a plugin that is giving you errors and you want to skip it, modify the corresponding build.sh to skip it (otherwise execution of the script will stop until the error is resolved). + +Special Options (modify PCSX2OPTIONS in build.sh) + +--enable-debug {Build with symbols and no optimizations} +--enable-devbuild {Build with extra tests} +--disable-recbuild {Disables all architecture dependent recompilation code} +--enable-sse2 {Enables x86 SSE2 extensions} +--enable-sse3 {Force enables x86 SSE3 extensions} + +For plugin authors: Your Makefile should support the 'install' option. + +When debugging, make sure to add + +handle SIGSEGV noprint ignore pass + +to .gdbinit + +Windows Users +------------- + +Make sure you have: Nvidia Cg-Toolkit (for ZeroGS) + +Open the corresponding Visual Studio sln files for all projects, compile, and move the executables appropriately. Pcsx2 and some plugins require masm to assemble (ml for win32, ml64 for win64). + +At the moment, MinGW is not supported, however there's a good chance the cygwin toolset will work. + + +email zerofrog@gmail.com for any compilation/linking issues in any Linux/Windows distribution. + +Global defines +-------------- + +Pcsx2 uses global defines to detect the OS, architecture, and different compilation options. They are: + +_MSC_VER - used to detect Visual Studio's cl compiler + +_WIN32 - used to detect windows compilation + +__LINUX__ - used to detect linux compilation (a lot of times it is assumed that linux is running when _WIN32 is missing) + +__x86_64__ - defined for x86-64 architectures only. + +PCSX2_DEVBUILD - used to enable runtime debugging and developer specific features of pcsx2 (disabled on releases) + +PCSX2_VIRTUAL_MEM - switches the way pcsx2 handles memory. VM enabled builds are valid for both windows and linux and they speed up games. However, there are less stable than TLB builds. + +PCSX2_NORECBUILD - ignore all recompiler code so that Pcsx2 can be built for different architectures. Note that there are a couple of places that use asm code even in interpreter (coroutines in IPU). + +_DEBUG - build with extra debug information +NDEBUG - build without absolutely no debug information + +ZEROGS_SSE2 - controls sse2 usage in zerogs + +compile with -D_FILE_OFFSET_BITS=64 if iso is failing to load large files diff --git a/bin/.pixmaps/pcsxAbout.bmp b/bin/.pixmaps/pcsxAbout.bmp new file mode 100644 index 0000000000000000000000000000000000000000..da33bb08f4a3c365d835b0972a7dfbc43f8b01a2 GIT binary patch literal 251192 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
#6CXrR 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%0A&bFGJ^?ZxKwaSay%~z|BlTbA{G+_QCqA8wMysG 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 yT^R{P!VvN=U0F-&j tag is the traditional comment tag which displays in the console output, you can put + anything here, though it's recommended that the Author / Source Authors (eg; Cheat Author) names + are placed here. + + XML COMMENT: + You may notice that this piece of text is contained within XML comment tags, you can use these freely + to add notes, disable areas (so they don't show in the GUI) etc + + GROUP: + Acts as a 'folder', to contain groups, multi liner grouped patches and single line patches. A + allows you to enable or disable everything contained within it. If you wrap a around + -untitled- entries, it causes the grouped 'es to act as one - aka 'multi liner grouped' + (eg; patches that write multiple values to memory, but have one effect, such as 4 values to raise + character X's MP). + title="" + Gives the groups name that will be displayed in the GUI. + enabled="" + All patches are off by default, until turned on via the GUI via a tickbox, however by setting + enabled="true" in the patch, this overrides the default state, usefull for "Emulation Fixes" that + force the game to work! + + PATCH: + The core reason this whole thing exists! + title="" + If the patch only requires one address for data to be written to, the patch must have a name! This + allows it to show up in the GUI as "whatever title you gave it" and can be toggled on and off via + the GUI. If the patch needs multiple addresses it must have -no- title="" text and be wrapped in a + so that all enties are enabled at once. + applymode="" + Has two values "startup"/"vsync", exactly the same as the old patch=0/1, if set to "startup" the + patch will be applied when the ELF boots (or once if game is already running), if set to "vsync" + the patch is applied every vsync (50/60 + times per second). + Startup: is best used when the address only needs to be patched once and isn't effected anywhere by + the game. + Vsync: is best used when the value could be altered by the game, eg; INF money, INF HP etc. + address="FFFFFFFF" + Where are you putting the 'value'? + size="" + This can be set to 8,16,32,64 + 8 (Byte): Address can have any ending. Max 8bit value FF. + 16 (Short): Address must end with 0, 2, 4, 6, 8, a, c, e. Max 16bit value FFFF. + 32 (Word): Address must end with 0, 4, 8, c. Max 32bit value FFFFFFFF. + 64 (Double): Address must end with 0, 8. Max 64bit value FFFFFFFFFFFFFFFF. + value="FFFFFFFF" + What are you writing to 'address'? --> + + + patches by CKemu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bin/Langs/ar_AR/LC_MESSAGES/pcsx2.mo b/bin/Langs/ar_AR/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..ba54bcc53bebba601078989d2c1978128ba26874 GIT binary patch literal 6197 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/de_DE/LC_MESSAGES/pcsx2.mo b/bin/Langs/de_DE/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..9852dd0c6092222ad23ce5a03e6604eecacff5fe GIT binary patch literal 11840 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 SBc0hu{TBKXCbd07-v0w{)hjpv literal 0 HcmV?d00001 diff --git a/bin/Langs/du_DU/LC_MESSAGES/pcsx2.mo b/bin/Langs/du_DU/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..47541b89cb8c7c0dd7c3a47e001e1da7a1e12a94 GIT binary patch literal 11583 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 m*MQD8vP5+DNuENo>})+r*6J=mvu;-tG1 literal 0 HcmV?d00001 diff --git a/bin/Langs/el_EL/LC_MESSAGES/pcsx2.mo b/bin/Langs/el_EL/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..1de54a1232dfd4db9b180817500212cd9ebd5c47 GIT binary patch literal 11225 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/es_ES/LC_MESSAGES/pcsx2.mo b/bin/Langs/es_ES/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..d88a28cb79dca85584f1539e07df164d2ad7b303 GIT binary patch literal 10632 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/fr_FR/LC_MESSAGES/pcsx2.mo b/bin/Langs/fr_FR/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..113d30e1a514e7ea937adf9f5b9f6f020a0559f9 GIT binary patch literal 6176 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 ODR#E&oDUj0q5cQ(6W*Z! literal 0 HcmV?d00001 diff --git a/bin/Langs/hb_HB/LC_MESSAGES/pcsx2.mo b/bin/Langs/hb_HB/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..58bcfc6d0f7031218bef1ddbb690801405047be6 GIT binary patch literal 6302 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/it_IT/LC_MESSAGES/pcsx2.mo b/bin/Langs/it_IT/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..4f929ba5646ddb889baaafe00900cca1e0c6ca81 GIT binary patch literal 5411 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/ja_JA/LC_MESSAGES/pcsx2.mo b/bin/Langs/ja_JA/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..a8a4c5e87e8570439585ce4d8b22bdb6e3ceb492 GIT binary patch literal 15213 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 C8_nzh literal 0 HcmV?d00001 diff --git a/bin/Langs/pe_PE/LC_MESSAGES/pcsx2.mo b/bin/Langs/pe_PE/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0cec5a54a53bcc6769b0b065c27e9d423eb89fd GIT binary patch literal 11165 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 BIPm}g literal 0 HcmV?d00001 diff --git a/bin/Langs/po_BR/LC_MESSAGES/pcsx2.mo b/bin/Langs/po_BR/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..bad7bf6ca21b1cd4408f8d07d3c0d3da3debd6b9 GIT binary patch literal 11024 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/po_PO/LC_MESSAGES/pcsx2.mo b/bin/Langs/po_PO/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..752871e7c843d6a7072ecc84acf67731a5dc874f GIT binary patch literal 11385 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 literal 0 HcmV?d00001 diff --git a/bin/Langs/ro_RO/LC_MESSAGES/pcsx2.mo b/bin/Langs/ro_RO/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..bf318427d371b7e14b6c7848ee3f26f393d4db71 GIT binary patch literal 11443 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 E0hxca;s5{u literal 0 HcmV?d00001 diff --git a/bin/Langs/ru_RU/LC_MESSAGES/pcsx2.mo b/bin/Langs/ru_RU/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..ee50ae6b15e3bd4824b3fa44bebc77eef0f1007a GIT binary patch literal 11125 zcmb7|3v^sZd4MM*grF1(36DT1i~+Ch#*!^L526H!EUj!MdQ~eq5Gb%(T}d0S_AdLd z?C=Ospn*UOX-P;ZC4GehCv8t(^t3&v1Sf!-U^@=!gO)Z|j~lJ_akX0ckyJ|D@4t6e zS}O*-_vqj6&fK|k|M~xa{+ZGLTz1jd6xTz@TafOTEAvaX&eVU~@Cm~ODBrsrV~8HtLK$Bh6g_uA8P{#F6@J(}e*nt(A2j9fz%7*j z5~7;=nc+MXy`P8D-v#`<3BJy-3BHl?Zo`k5`u&FY7(NUoo_++S{WI`7cnV4!ZM!@e zZzmLe$00*g6HvbQN%&^?btrcI8z}n!BfJ(q3dJA)Yw9n0UGV;^AR(aM3ircCDDOXH zp8vTi|1*^Seh9^WM@;?GQ1tmPDE&L|CRl)Cm#bbMytf0kP`(k0Uv0xrK#9k@;UK&Z zNzKs2JbfI!%)UwgrfiJSvF=l7t*>-V9| z<0J4+I0a?=Q970WC!n;y6H0vC1*PAwK+)p?DBpV!iXFZUBk-@G^mFmX;Qh|e+V?@pZ?{2N&-TLKfFFYc@GzA5 zstFny&ka!Gp##c$1F#du;KlH}=J{Vi>F@hc#(fmN0{#q&-cwNGpbTYP7i#xffC1UQ0&?ZrJs)&jvJ;7_Zxl+UPQaQpnU(!@Dg|*lztzCq%!p|l>UAMWjsfq z#KSXC;%Nnn{olMLc)u4)zqdm1{|BMuSsUH}?}it`A46VMPrzY#95%ySe?8zAAXVz0 zATC!f#MG(*r?taocmYfya@~duAvxrakoO~Ubs%F%1M(13fBiOv_nC?h8D3)eE<=_> ze;iW08+ibkL_Upt9QjS;n@BhEE#zwC6Np^mZ;2JTWGuC-iyNkcf8E1x8u&Mp- z@n`Ll*xZSTtv-fqKt7CIgJ`4$5q~rxoruJq><{F!kb9BeM?Qt@Mt%(5`D3INkyw&^mqfmdL=c%Te}Y_#+=OgJ`j9ws z6*7QGE|n{cNSyW{uSDb;LB8SNu`a;RA=e`^A8e#{eT|#gC2u`rjmRH(xm z&Qa4DPf*yEj;6-rF*?|7B~mKX9ZinqqGLSi=KJzHHii~*GpRy7)(0x6;0f{n2b}+@f87+KyS7jP6gz?KGOH(10~zXD#h(5p+F}OH!Rn z>h_Lp9eX-dC=%U=0ueixM1x2+nx!Xy_`$Dyp)DO9j>pu_xSdfubBVENIv!1`_Rz?_ zk+eO*jh)Psl=j26RfXpkl` zD2KVHM{R0r&XbY1+quMu?xid75H{P> zq5Bg#OzD5z50-UpI>LLdKUbU1ThG-3ozL-|{wtwitK!8H>sR9 z0pAg__Fb=J;Om^;;n(M)30kHt-D8hfdUHqn7Tu_Oa*w?JDE73_eB%& z5j`2tj_aPmT@lrhBeGREwBL&5vXIZ#h8x7Lt1Z65@5Qg z=Y88Ek?J-e>H&Yv%RQuENdCw0DC_hiju=7B#Ih;T+TK~hK`F!kcGIA*^?o?uvG z%B?zs8)D;9o3(Y9SSXdY_%-jzER=^b5&dc4+hv39i|7<7O=seFSb8Ft$?9QCUwz9k zb2BX7>%4VcjC4lnVPrJ}ll9ukdXk0B6FwhHTjV7@mdTEDH`2hPiFo3G>ZF=9OVfBF zp_!EAM9mN;qDgv;CoLVVC2c=Xh|+v3mA1#y(TP@GOIx8^`SI^+H|R{nn2e@6X=#z; zC;Sv+ijlqX6d~A^)OLD=*g?lA#6WTy3E#wjLqAl(nkhmunTXd&|$O0 z{+6bO&QwN^#51Wx^Z>On(r`Aj+Q__@we2Q8Y$cftyCUoCx69&tNwvDR>`GhKUbWjA zPFs^|cYJJI?an1l%I+HV&EV^VAv2^`u^2v!1qpMU#X!8}`!KUro+g=(7*}RigX$u4 zO76conu;c^jHP_LV2MsU9a|kI);PloIzEbpY=62pDLhR0Y2VAuXOvoMrH!UgRn$f9PW`7ICOg5U% zZc)9~r1q!3>h=9(zzEtHWSyU|Hjd@H(TuORFlA>laWYDi>bphBd|l@Xs#?}pwMX99 zqQgBy4a)zl4(&|albImNn3~SGd`gy^ew4*SEX9mFn$-vFoSwupQJu>W%euX z9-v|rPmVJiGd#74dkMyY9BzS;#&+_R=p%V?og-wMV>}m~h*#tpsTD|Pi z^)N1IHJinLe{QWs(-|Q&lo?ighVn~O`*1fk=-nhb&h43cFn)MU31Xx!!dTUvRCP`V&l<07CY`>m*TIRGJ{x6 zR~z;2={ehTf5Em#b%uzLefPMe-E@#$vaF{p$_`ums@tO24_V+Y%SR^76F`!$X7cfD@j(b{}%iHtrhRkM_6A8H_`Y%QKni8E z*8c1^miKt_290;pB(`_A?`|82ga_AJiZ+~08pFw$Eh(>6ziT+2ZBTL^J@QujDYp|V_E@sF>^{k|Wo zEX{bXugOuTddhE`_bLpbsuwEWNq2FP5C3%5DZ1tI^1PlE#qwo7^kZjXiLZ*btGBEU z!D;rGccS882zfZYr48MloS<`kgJFrb8Jb8|))hobJ?r%Uf_OE-I|Z_GxPA_;I(= zpdNRsXi^SFN#>{xaxEf)J6;nD)qOvRLFvvv5iJzOC2J?)v$ph4Naxj(6VrLMV<_j< zPIhSL-LmEUTKXrh^ZL4+z+Td@Hs|~ZS$Ax%izNTt{Mhu;34MB&*dY8X?z8z)?d*I; zXqDaht-9>#s#jboczQ87IX~(Zi%xmg_wm8da*!QX6u0xt%WybYSIh~z;ugHpLcVyq z>Q(gSYQ>#eViv9*qYo|e`pTR)?cn%Ofykk#&a7SV=kO!tnPPt4|7dN-hx~~<<5nb; zOe$ki=^&Kz`T9t5&f1_ZfX?1vHEz!Scr{$k{q0GI8Uy9a`IC94n4crN=k=3y?s2winbL*gi>D+R>9V5_m8))Lq2g8@+;>(B zO1g0TMI-2cgMQMPE4dZzKhQ^x=~=J%tXtMolB2IKOp!|t`hj9j>vf@d);TUof60tN z_8N7K7QMMyiJP^v`%k=CmML}Anqq1_& z>%}04=eIVLu{s7_cKz3uMG5J|d9k{9T5q0OX7zMkbAVqw<+6kon1j!{s|}e#^1~k14^6Wm;tE!9PaSm2Oe4Skhl|C$UhwF@ zkS{e>J;~sw@@1#wdz2@$1?Lo71w31JbqTGidU_eNOX|kIThVl8*5RQyb%G_T6 zED9^9gH_>~1+zRDW6Eod`k23(t<-F^;t$W8#*%dwY+`v?+X3k2Gm91BPwV|(N3e0|>a5BxG;oAhB% zd*!@#pJ)0LZoxdtPy3On^#7wvj{oQGQ8SxsQG)$t(CGcfSenHmSH%vKpQBU$tVb=|n@*CusrD#Q*;{d?8Vefc^6p8`jw%HFi7wCHbj z)ssu5|1W`*f z2bZT@*{$lwkE)~20vq&2|NjH4g<$P>N_lmx=vC!E0s&hLcNku6c#ZNmtSqZep#6VL zyTSVXRGs?4e+4AMC1?6(U|Z)_9Q71|Dk1gXRlX)}6_fHm0d>%u!?0yPgH09P(lVL` z%6TPqG}yugDZ)?xYf)DwGn0)AEFFHrp})DZ<1%K6Q;dz38Z>FtnO>n%cIC?@_0&=& zNM~mp^y{pBcx@{@Jy-NfV(V#E4LR-CJzLvrzVytGCT!ciD$3|7caD+Hc*>mk>sL!N zue}9XM#+~;C9imj)!{`s>JyWGj<}b*eEDR4L2s&61q;O{e_ut4@$H33AJ2Yt$!Y&ZPAsfbtLOc5z0q8IWA#wKcJe<{}(i>1ls~k?-jjiiD|bWrYjR$>?Rp5d(j3Zi}S2E6&Gw)p4 jt+0MdHYYS$CmdYrCttn!1%hRcK$>Os(Isi*a`gW{^+84M literal 0 HcmV?d00001 diff --git a/bin/Langs/sh_SH/LC_MESSAGES/pcsx2.mo b/bin/Langs/sh_SH/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..33b36e000c948e93fa85f58b5b8659669cbe4f12 GIT binary patch literal 9723 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\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "%s: Error loading %s: %s" +msgstr "%s: Kan ej ladda %s: %s" + +msgid "&About..." +msgstr "&Om..." + +msgid "&Arguments" +msgstr "&Argument" + +msgid "&Config" +msgstr "&Konfiguration" + +msgid "&Configure" +msgstr "&Konfigurera" + +msgid "&Debug" +msgstr "&Debug" + +msgid "&File" +msgstr "&Arkiv" + +msgid "&Graphics" +msgstr "&Grafik" + +msgid "&Help" +msgstr "&Hjälp" + +msgid "&Language" +msgstr "&Språk" + +msgid "&Load" +msgstr "&Ladda" + +msgid "&Logging" +msgstr "&Loggar" + +msgid "&Low" +msgstr "&Låg" + +msgid "&Memcards" +msgstr "&Minneskort" + +msgid "&Misc" +msgstr "&Övrigt" + +msgid "&Open ELF File" +msgstr "&Öppna ELF fil" + +msgid "&Other..." +msgstr "&Annat..." + +msgid "&Patches" +msgstr "&Patchar" + +msgid "&Process Priority" +msgstr "&Process Prioritet" + +msgid "&Remote Debugging" +msgstr "&Fjärrstyrd Debug" + +msgid "&Run" +msgstr "&Kör" + +msgid "&Run CD" +msgstr "&Kör CD" + +msgid "&Save" +msgstr "&Spara" + +msgid "&Sound" +msgstr "&Ljud" + +msgid "&States" +msgstr "Sparpunkter" + +msgid "*PCSX2*: Error Loading State %d" +msgstr "*PCSX2*: Kan inte ladda sparpunkt %d" + +msgid "*PCSX2*: Error Loading State %s" +msgstr "*PCSX2*: Kan inte ladda sparpunkt %s" + +msgid "*PCSX2*: Error Saving State %d" +msgstr "*PCSX2*: Kan inte spara sparpunkt %d" + +msgid "*PCSX2*: Error Saving State %s" +msgstr "*PCSX2*: Kan inte spara sparpunkt %s" + +msgid "*PCSX2*: Loaded State %d" +msgstr "*PCSX2*: Sparpunkt laddad %d" + +msgid "*PCSX2*: Loaded State %s" +msgstr "*PCSX2*: Sparpunkt laddad %s" + +msgid "*PCSX2*: Saving State %d" +msgstr "*PCSX2*: Sparar punkt %d" + +msgid "*PCSX2*: Saving State %s" +msgstr "*PCSX2*: Sparar punkt %s" + +msgid "0x" +msgstr "0x" + +msgid "About" +msgstr "Om" + +msgid "About PCSX2" +msgstr "Om PCSX2" + +msgid "About..." +msgstr "Om..." + +msgid "Address " +msgstr "Address" + +msgid "All Files" +msgstr "Alla Filer" + +msgid "Arabic" +msgstr "Arabiska" + +msgid "Arguments" +msgstr "Argument" + +msgid "Bios" +msgstr "BIOS" + +msgid "Bios Log" +msgstr "BIOS Log" + +msgid "Bulgarian" +msgstr "Bulgariska" + +msgid "C&dvdrom" +msgstr "C&DVDROM" + +msgid "C&ontrollers" +msgstr "K&ontroller" + +msgid "C&pu" +msgstr "C&PU" + +msgid "CDVDinit error: %d" +msgstr "CDVD Initieringsfel: %d" + +msgid "Cancel" +msgstr "Avbryt" + +msgid "Cannot load '%s', wrong PS2E version (%x != %x)" +msgstr "Kan inte ladda '%s',Fel PS2E version (%x != %x)" + +msgid "Catalan" +msgstr "Kataloniska" + +msgid "Cdr Log" +msgstr "CDR Log" + +msgid "Cdvdrom" +msgstr "CDVDROM" + +msgid "Clear BPs" +msgstr "Rensa BPs" + +msgid "Close" +msgstr "Stäng" + +msgid "Conf" +msgstr "Konfiguration" + +msgid "Configuration" +msgstr "Konfiguration" + +msgid "Configure" +msgstr "Konfigurera" + +msgid "Configure..." +msgstr "Konfigurera" + +msgid "Controllers" +msgstr "Kontroller" + +msgid "Cop0 Log" +msgstr "COP0 Log" + +msgid "Could Not Load CDVD Plugin '%s': %s" +msgstr "Kunde inte ladda CDVD Plugin '%s': %s" + +msgid "Could Not Load DEV9 Plugin '%s': %s" +msgstr "Kunde inte ladda DEV9 Plugin '%s': %s" + +msgid "Could Not Load FW Plugin '%s': %s" +msgstr "Kunde inte ladda Firewire Plugin '%s': %s" + +msgid "Could Not Load GS Plugin '%s': %s" +msgstr "Kunde inte ladda Grafik Plugin '%s': %s" + +msgid "Could Not Load PAD1 Plugin '%s': %s" +msgstr "Kunde inte ladda PAD1 Plugin '%s': %s" + +msgid "Could Not Load PAD2 Plugin '%s': %s" +msgstr "Kunde inte ladda PAD2 Plugin '%s': %s" + +msgid "Could Not Load SPU2 Plugin '%s': %s" +msgstr "Kunde inte ladda SPU2 Plugin '%s': %s" + +msgid "Could Not Load USB Plugin '%s': %s" +msgstr "Kunde inte ladda USB Plugin '%s': %s" + +msgid "Could not create threads or event" +msgstr "Kunde inte skapa trådar eller händelse." + +msgid "Could not open '%s' directory" +msgstr "Kunde inte öppna mappen '%s'" + +msgid "Couldn't find pixmap file: %s" +msgstr "Kunde inte hitta pixmap filen: %s" + +msgid "Cpu" +msgstr "CPU" + +msgid "Cpu Config" +msgstr "CPU Konfiguration" + +msgid "Cpu Log" +msgstr "CPU Log" + +msgid "D&ev9" +msgstr "D&ev9" + +msgid "DEV9init error: %d" +msgstr "DEV9 Initieringsfel: %d" + +msgid "Data " +msgstr "Data" + +msgid "Debug" +msgstr "Debug" + +msgid "Dev9" +msgstr "Dev9" + +msgid "Disable Recompiler" +msgstr "Avaktivera Omkompilerare" + +msgid "Disable VUs recompilation" +msgstr "Inaktivera VUs omkompilation" + +msgid "Dma Log" +msgstr "DMA Log" + +msgid "Dump File = \"dump.txt\"" +msgstr "Dumpa Fil = \"dump.txt\"" + +msgid "Dump code" +msgstr "Dumpa kod" + +msgid "Dutch" +msgstr "Hollendska" + +msgid "E&xecute" +msgstr "K&ör" + +msgid "E&xit" +msgstr "&Avsluta" + +msgid "EE Debug Mode" +msgstr "EE Debug Läge" + +msgid "EE Logs" +msgstr "EE Logs" + +msgid "Elf Log" +msgstr "ELF Log" + +msgid "Emulator" +msgstr "Emulator" + +msgid "Enable Console Output" +msgstr "Aktivera konsol" + +msgid "Enable Patches" +msgstr "Aktivera patcher" + +msgid "Enable Reg Caching" +msgstr "Aktivera Reg Cachning" + +msgid "English" +msgstr "Engelska" + +msgid "Enter &Debugger..." +msgstr "Starta &Debugger..." + +msgid "Enter Debugger ..." +msgstr "Starta &Debugger" + +msgid "Error Loading Symbol" +msgstr "Kunde inte ladda symbol" + +msgid "Error Opening CDVD Plugin" +msgstr "Kunde inte öppna CD-ROM Plugin" + +msgid "Error Opening DEV9 Plugin" +msgstr "Kunde inte öppna DEV9 Plugin" + +msgid "Error Opening FW Plugin" +msgstr "Kunde inte öppna Firewire Plugin" + +msgid "Error Opening GS Plugin" +msgstr "Kunde inte öppna Grafik Plugin" + +msgid "Error Opening PAD1 Plugin" +msgstr "Kunde inte öppna PAD1 Plugin" + +msgid "Error Opening PAD2 Plugin" +msgstr "Kunde inte öppna PAD2 Plugin" + +msgid "Error Opening SPU2 Plugin" +msgstr "Kunde inte öppna SPU2 Plugin" + +msgid "Error Opening USB Plugin" +msgstr "Kunde inte öppna USB Plugin" + +msgid "Error allocating memory" +msgstr "Kunde inte allokollera minne" + +msgid "Error initializing Recompiler, switching to Interpreter" +msgstr "Kunde inte initiera omkompilerare, går till Interpreter" + +msgid "Error loading pixmap file: %s" +msgstr "Kunde inte öppna pixmap Fil: %s" + +msgid "Exit" +msgstr "Avsluta" + +msgid "FW" +msgstr "Firewire" + +msgid "FWinit error: %d" +msgstr "Firewire Initieringsfel: %d" + +msgid "Failed loading MemCard %s" +msgstr "Kunde inte ladda minneskort: %s" + +msgid "File" +msgstr "Arkiv" + +msgid "Fill in the command line arguments for opened program:" +msgstr "Fyll i kommando rads argumenten för det öppnade programmet:" + +msgid "Fire&Wire" +msgstr "Fire&Wire" + +msgid "First Controller" +msgstr "Första kontrollern" + +msgid "Fpu Log" +msgstr "FPU Log" + +msgid "French" +msgstr "Franska" + +msgid "From 0x" +msgstr "Från 0x" + +msgid "GIF Log" +msgstr "GIF Log" + +msgid "GPU Log" +msgstr "GPU Log" + +msgid "GSinit error: %d" +msgstr "Grafiska Syncen kunde inte initieras: %d" + +msgid "German" +msgstr "Tyska" + +msgid "Go" +msgstr "Starta" + +msgid "Graphics" +msgstr "Grafik" + +msgid "Greek" +msgstr "Grekiska" + +msgid "Greets to:" +msgstr "Hälsningar till:" + +msgid "" +"Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785, Raziel\n" +"Special thanks to: Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" +"Seta-San, Skarmeth, blackd_wd, _Demo_\n" +"Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n" +"Some betatester/support dudes: bositman, Seta-san, falcon4ever, jegHegy, Razorblade, CKemu, Belmont, parotaku, crushtest, ChaosCode" +msgstr "" +"Hälsningar till: Bobbi, Keith, CpUMasteR, Nave, Snake785, Raziel\n" +"Danke an: Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" +"Seta-San, Skarmeth, blackd_wd, _Demo_\n" +"Meriten: Hiryu && Sjeep fr Ihre libcdvd (ISO Parsing und Filesystem Treiber Code)\n" +"Einige Betatester/Hilfskrfte: bositman, Seta-san, falcon4ever, jegHegy, Razorblade, CKemu" + +msgid "Gte Log" +msgstr "GTE Log" + +msgid "Help" +msgstr "Hjälp" + +msgid "High" +msgstr "Hög" + +msgid "Hw Log" +msgstr "Hårdvaru Log" + +msgid "IOP Debug Mode" +msgstr "IOP Debug läge" + +msgid "IOP Log" +msgstr "IOP Log" + +msgid "IOP Logs" +msgstr "IOP Log" + +msgid "IPU Log" +msgstr "IPU Log" + +msgid "If you don't know what to write leave it blank" +msgstr "Om du inte vet vad du ska skriva, lämna den tom" + +msgid "" +"In debugger:\n" +"Put EE in stop state\n" +"and IOP in run state" +msgstr "" +"I Debugger: \n" +"Sätt EE i stoppad status\n" +"och IOP i pågående status" + +msgid "" +"In debugger:\n" +"Put IOP in stop state\n" +"and EE in run state" +msgstr "" +"I Debugger: \n" +"Sätt IOP i stoppad status\n" +"och EE i pågående status" + +msgid "Interpreter -The slowest but the most compatible cpu core" +msgstr "Interpreter -Den långsammaste men mest kompitabla cpu kärnan" + +msgid "Italian" +msgstr "Italienska" + +msgid "Japanese" +msgstr "Japanska" + +msgid "Language" +msgstr "Språk" + +msgid "Load" +msgstr "Ladda" + +msgid "Load Elf" +msgstr "Ladda Elf" + +msgid "Log" +msgstr "Log" + +msgid "Log On/Off" +msgstr "Loggning På/Av" + +msgid "Log to STDOUT" +msgstr "Logga till STDOUT" + +msgid "Logging" +msgstr "Loggning" + +msgid "MMI Log" +msgstr "MMI Log" + +msgid "Mem Log" +msgstr "Minnes Log" + +msgid "Memcard Manager" +msgstr "Minneskorts Skötare" + +msgid "Memory Card 1" +msgstr "Minneskort 1" + +msgid "Memory Card 2" +msgstr "Minneskort 2" + +msgid "Memory Dump" +msgstr "Minnesdump" + +msgid "" +"Nah, you have to be in\n" +"Interpreter Mode to debug" +msgstr "" +"Nej, du måste vara i\n" +"Interpreter läge för att debugga" + +msgid "New Patch" +msgstr "Ny Patch" + +msgid "Normal" +msgstr "Normal" + +msgid "Not enough params for inicommand\n" +msgstr "Inte tillräckligt med parametrar för inikommando\n" + +msgid "Note: this is intented for developers only." +msgstr "Notera: detta är endast menat för utvecklare." + +msgid "Notice on debugging EE" +msgstr "Notis på EE debug" + +msgid "Notice on debugging IOP" +msgstr "Notis på IOP debug" + +msgid "OK" +msgstr "Ok" + +msgid "Ok" +msgstr "Ok" + +msgid "Options" +msgstr "Alternativ" + +msgid "Other..." +msgstr "Annat..." + +msgid "PAD1init error: %d" +msgstr "Kunde inte initiera Pad1: %d" + +msgid "PAD2init error: %d" +msgstr "Kunde inte initiera pad2: %d" + +msgid "PCSX" +msgstr "PCSX" + +msgid "" +"PCSX2\r\r\r\n" +"Version x.x" +msgstr "" +"PCSX2\r\r\r\n" +"Version x.x" + +msgid "PCSX2 %s Compile Date - %s %s" +msgstr "PCSX2 %s Kompilerat: %s %s" + +msgid "PCSX2 Debugger" +msgstr "PCSX2 Debugger" + +msgid "PCSX2 EMU\n" +msgstr "PCSX2 Emulator\n" + +msgid "" +"PCSX2 For Linux\n" +"Version %s" +msgstr "" +"PCSX2 För Linux\n" +"Version %s" + +msgid "PCSX2 Msg" +msgstr "PCSX2 Meddelande" + +msgid "PCSX2 Quitting\n" +msgstr "PCSX2 Stänger\n" + +msgid "PCSX2 State Format" +msgstr "PCSX2 Sparpunktsformat" + +msgid "" +"PCSX2 a ps2 emulator\n" +"\n" +"written by:\n" +"linuzappz, shadow, florin,\n" +"alexey silinov, asadr, goldfinger,\n" +"nachbrenner, auMatt, loser\n" +"\n" +"Webmaster: Thorgal" +msgstr "" +"PCSX2 - En PS2 Emulator\n" +"\n" +"Skriven av:\n" +"linuzappz, shadow, florin,\n" +"alexey silinov, saqibakhtar, goldfinger,\n" +"Nachbrenner, auMatt, loser\n" +"\n" +"Webmaster: Thorgal" + +msgid "Pad Log" +msgstr "PAD Log" + +msgid "Patches Browser" +msgstr "Patch Utforskare" + +msgid "Pcsx About" +msgstr "PCSX om" + +msgid "Pcsx2 Msg" +msgstr "PCSX2 Meddelande" + +msgid "Pcsx2 needs to be configured" +msgstr "PCSX2 måste konfigureras" + +msgid "Plugins & Bios" +msgstr "Plugins & BIOS" + +msgid "Portuguese" +msgstr "Portugisiska" + +msgid "Processor doesn't supports MMX, can't run recompiler without that" +msgstr "Processorn är inte kompitabel med MMX, kan inte köra omkompilerare utan det." + +msgid "Program arguments" +msgstr "ProgramArgument" + +msgid "Ps2 Memory Card (*.ps2)" +msgstr "PS2 Minneskort (*.ps2)" + +msgid "Ps2 Output" +msgstr "PS2 Konsol" + +msgid "RPC Log" +msgstr "RPC Log" + +msgid "Raw Dump" +msgstr "Rådata dump" + +msgid "Re&set" +msgstr "&Starta om" + +msgid "Ready" +msgstr "Redo" + +msgid "Recompiler - Much faster than Intepreter(Needs MMX)" +msgstr "Omkompilerare - Mycket snabbare än Interpreter(Kräver MMX)" + +msgid "Recompiler Options" +msgstr "Omkompilerarens alternativ" + +msgid "Recompiler+VuRecs - The fastest setting (Needs SSE,SSE2)" +msgstr "Omkompilerare + VuRecs - Snabbaste alternativer (Kräver SSE,SSE2)" + +msgid "Refresh List" +msgstr "Uppdatera Lista" + +msgid "Reset" +msgstr "Starta om" + +msgid "Resetting..." +msgstr "Startar om..." + +msgid "Romanian" +msgstr "Rumenska" + +msgid "Run" +msgstr "Kör" + +msgid "Run CD" +msgstr "Kör CD" + +msgid "Russian" +msgstr "Ryska" + +msgid "SPR Log" +msgstr "SPR Log" + +msgid "SPU2init error: %d" +msgstr "Kunde inte initiera SPU2: %d" + +msgid "SYMs Log" +msgstr "SYMs Log" + +msgid "Save" +msgstr "Spara" + +msgid "Save Patch" +msgstr "Spara Patch" + +msgid "Search game name patch:" +msgstr "Sök efter spelpatch:" + +msgid "Second Controller" +msgstr "Andra kontrollern" + +msgid "Select Bios Dir" +msgstr "Välj BIOS mapp" + +msgid "Select Bios Directory" +msgstr "Välj BIOS mapp" + +msgid "Select Mcd" +msgstr "Välj Mcd" + +msgid "Select Plugins Dir" +msgstr "Välj plugin mapp" + +msgid "Select Plugins Directory" +msgstr "Välj pluginmapp" + +msgid "Select Psx Elf File" +msgstr "Välj PSX Elf Fil" + +msgid "Select State File" +msgstr "Välj sparpunktsfil" + +msgid "Set BP Addr" +msgstr "Set BP Address" + +msgid "Set BP Count" +msgstr "Set BP Räknare" + +msgid "Set Bios Directory" +msgstr "Set BIOS mapp" + +msgid "Set Dump Addr (in Hex):" +msgstr "Set Dump Address (i hexadecimalt tal):" + +msgid "Set New BP Address (in Hex):" +msgstr "Set ny BP Address (i hexadecimalt tal)" + +msgid "Set New BP Count (in Hex):" +msgstr "Set ny BP räkning (i hexadecimalt tal):" + +msgid "Set New PC Address (in Hex):" +msgstr "Set ny PC address (i hexadecimalt tal):" + +msgid "Set PC" +msgstr "Set PC" + +msgid "Set Plugins Directory" +msgstr "Set Plugin Mapp" + +msgid "SetBreakPoint Addr" +msgstr "Set BP Address" + +msgid "SetPCDlg" +msgstr "Set PC Dialog" + +msgid "Sif Log" +msgstr "SIF Log" + +msgid "Skip" +msgstr "Skippa" + +msgid "Slot &1" +msgstr "Slot &1" + +msgid "Slot &2" +msgstr "Slot &2" + +msgid "Slot &3" +msgstr "Slot &3" + +msgid "Slot &4" +msgstr "Slot &4" + +msgid "Slot &5" +msgstr "Slot &5" + +msgid "Slot 1" +msgstr "Slot 1" + +msgid "Slot 2" +msgstr "Slot 2" + +msgid "Slot 3" +msgstr "Slot 3" + +msgid "Slot 4" +msgstr "Slot 4" + +msgid "Slot 5" +msgstr "Slot 5" + +msgid "Sound" +msgstr "Ljud" + +msgid "Spanish" +msgstr "Spanska" + +msgid "States" +msgstr "Sparpunkter" + +msgid "Step" +msgstr "Steg" + +msgid "Test" +msgstr "Test" + +msgid "Test..." +msgstr "Test" + +msgid "This plugin reports that should not work correctly" +msgstr "Denna plugin rapporterar att den funkar bra" + +msgid "This plugin reports that should work correctly" +msgstr "Denna plugin rapporterar att den funkar bra" + +msgid "" +"Tip: If you don't know what to write\n" +"leave it blank" +msgstr "" +"Tips: Om du inte vet vad du ska skriva\n" +"lämna den tom" + +msgid "To 0x" +msgstr "Till 0x" + +msgid "Turkish" +msgstr "Turkiska" + +msgid "U&SB" +msgstr "U&SB" + +msgid "USBinit error: %d" +msgstr "Kunde inte initiera Usb: %d" + +msgid "Unable to hack in %s%s\n" +msgstr "" +"Kunde inte hacka %s%s \n" +"\n" + +msgid "Unable to load bios: '%s', PCSX2 can't run without that" +msgstr "Kunde inte ladda BIOS: '%s', PCSX2 Kan inte funka utan det!" + +msgid "Unrecoverable error while running recompiler" +msgstr "Ireparabelt fel under omkompilerarens körning" + +msgid "Usb" +msgstr "USB" + +msgid "VU Micro Log" +msgstr "VU Micro Log" + +msgid "VU0 Log" +msgstr "VU0 Log" + +msgid "Vif Log" +msgstr "VIF Log" + +msgid "button69" +msgstr "Knapp 69" + +msgid "button70" +msgstr "Knapp70" + +msgid "memWrite32" +msgstr "memWrite32" + +msgid "patch file for this game not found. Can't apply any patches\n" +msgstr "Hittade ingen patch för detta spel. Kan inte applicera patch. \n" + +msgid "written by..." +msgstr "Skrivet av..." + diff --git a/bin/Langs/sw_SW/LC_MESSAGES/pcsx2.mo b/bin/Langs/sw_SW/LC_MESSAGES/pcsx2.mo new file mode 100644 index 0000000000000000000000000000000000000000..d53edb0f45554734ad5bb87a03002253bd47420b GIT binary patch literal 10929 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

Pxox&d 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 + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
The Compatibility List Contains + 1814 Titles
+
99 235 120 645 715
0 Story SLPM 65002 JPS2Playable +
+
0.9.4
10,000 Bullets SLES 53481 EPS2Ingame +
+
0.9.4
18 Wheeler - American Pro Trucker SLES 50214 EPS2Ingame +
+
0.9.4
18 Wheeler - American Pro Trucker SLUS 20210 UPS2Playable +
+
0.9.4
187 Ride or Die SLUS 21116 UPS2Intro +
+
0.9.4
24 - The Game SLUS 21268 UPS2Ingame +
+
0.9.4
25 To Life SLUS 21016 UPS2Playable +
+
0.9.4
4x4 Evolution SLUS 20091 UPS2Intro +
+
0.9.4
7 Sins SLES 53280 EPS2Intro +
+
0.9.3
7 Sins SLES 53297 EPS2Nothing +
+
0.9.4
Ace Combat 4 - Shattered Skies PBPX 95201 JPS2Ingame +
+
0.9.4
Ace Combat 4 - Shattered Skies SLUS 20152 UPS2Menus +
+
0.9.4
Ace Combat 5 - The Unsung War SLUS 20851 UPS2Intro +
+
0.9.4
Ace Combat Zero - The Belkan War SLUS 21346 UPS2Intro +
+
0.9.4
Action Girlz Racing SLES 52956 EPS2Ingame +
+
0.9.2
Activision Anthology PBPX 95201 JPS2Playable +
+
0.9.4
Adventures Of Cookie And Cream, The SLUS 20170 UPS2Playable +
+
0.9.4
Aeon Flux SLUS 21205 UPS2Playable +
+
0.9.4
AFL Live 2003 SLES 51168 EPS2Playable +
+
0.9.2
Agassi - Tennis Generation SLUS 20446 UPS2Nothing +
+
0.9.4
Age of Empires II - The Age of Kings SLES 50282 EPS2Menus +
+
0.9.4
Aggressive Inline SLUS 20327 UPS2Playable +
+
0.9.4
Air Blade SCES 50246 EPS2Playable +
+
0.9.4
Airblade SLUS 20346 UPS2Playable +
+
0.9.4
Airborne Troops Countdown To DDay SLUS 21125 UPS2Menus +
+
0.9.4
Airforce Delta Strike SLKA 25133 JPS2Playable +
+
0.9.4
Akai ito SLPM 65732 JPS2Playable +
+
0.9.4
Akira Psycho Ball SLES 50919 EPS2Ingame +
+
0.9.4
Alex Ferguson's Player Manager 2001 SLES 50429 EPS2Ingame +
+
0.9.4
Alfa Romeo Racing Italiano SLUS 21321 UPS2Nothing +
+
0.9.4
Alias SLUS 20673 UPS2Ingame +
+
0.9.4
Alien Hominid SLES 53139 EPS2Playable +
+
0.9.2
Alien Hominid SLUS 21090 UPS2Playable +
+
0.9.4
Aliens VS Predator - Extinction SLUS 20147 UPS2Playable +
+
0.9.4
All Star Pro Wrestling 3 SLPM 65300 JPS2Intro +
+
0.9.4
Alone in the Dark 4 SLES 50185 EPS2Playable +
+
0.9.4
Alpine Racer 3 SCES 50887 EPS2Menus +
+
0.9.4
Alter Echo SLUS 20465 UPS2Ingame +
+
0.9.4
American Arcade PBPX 95201 JPS2Ingame +
+
0.9.4
American Chopper 2 SLUS 21288 UPS2Ingame +
+
0.9.4
AMF Xtreme Bowling SLUS 21347 UPS2Ingame +
+
0.9.4
Amplitude SCES 51706 EPS2Menus +
+
0.9.4
Amplitude SCUS 97258 UPS2Intro +
+
0.9.4
And1 Streetball SLUS 21237 UPS2Ingame +
+
0.9.2
Animaniacs - The Great Edgar Hunt SLES 52729 EPS2Ingame +
+
0.9.4
Another Century's Episode 2 SLPS 25623 JPS2Menus +
+
0.9.4
Ant Bully, The SLUS 21415 UPS2Menus +
+
0.9.4
Antz Extreme Racing SLUS 20392 UPS2Playable +
+
0.9.4
Anubis 2 SLES 53571 EPS2Playable +
+
0.9.4
Ape Escape - Million Monkeys SCPS 15115 JPS2Ingame +
+
0.9.2
Ape Escape - Pumped and Primed SLUS 21096 UPS2Intro +
+
0.9.4
Ape Escape 2 SLUS 20685 UPS2Playable +
+
0.9.4
Ape Escape 3 SCUS 97501 UPS2Nothing +
+
0.9.4
Aqua Aqua - Wetrix 2 PBPX 95201 JPS2Playable +
+
0.9.4
Aqua Aqua - Wetrix 2 SLES 50053 EPS2Intro +
+
0.9.4
Ar Tonelico - Melody Of Elemia SLUS 21445 UPS2Playable +
+
0.9.4
Arc The Lad - End of Darkness SLUS 21165 UPS2Ingame +
+
0.9.4
Arc the Lad - Twilight of the Spirits SCES 51910 EPS2Ingame +
+
0.9.2
Arc the Lad - Twilight of the Spirits SCUS 97231 UPS2Ingame +
+
0.9.2
Arcade USA SLES 53446 EPS2Intro +
+
0.9.4
Arcade, The SLES 52778 EPS2Playable +
+
0.9.4
Arcana Heart SLPM 66850 JPS2Playable +
+
0.9.4
Arctic Thunder SLUS 20217 UPS2Intro +
+
0.9.4
Area 51 SLES 52570 EPS2Intro +
+
0.9.2
Area 51 SLUS 20595 UPS2Intro +
+
0.9.4
Argos no Senshi SLPS 25178 JPS2Ingame +
+
0.9.4
Armored Core - Last Raven SLUS 21338 UPS2Menus +
+
0.9.4
Armored Core - Nine Breaker SLUS 21200 UPS2Playable +
+
0.9.4
Armored Core 2 - Another Age SLPS 25040 JPS2Playable +
+
0.9.2
Armored Core 2 SLUS 20014 UPS2Playable +
+
0.9.4
Armored Core 3 SLPS 25112 JPS2Playable +
+
0.9.2
Army Men - Green Rogue SLUS 20087 UPS2Ingame +
+
0.9.4
Army Men - Major Malfunction SLES 53996 EPS2Menus +
+
0.9.2
Army Men - Sarge's Heroes 2 SLES 50192 EPS2Menus +
+
0.9.2
Army Men - Sarge's Heroes 2 SLUS 20132 UPS2Intro +
+
0.9.4
Art Of Fighting Anthology SLUS 21487 UPS2Playable +
+
0.9.4
Artic Thunder SLUS 20217 UPS2Ingame +
+
0.9.2
Asterix And Obelix - Kick Buttix SLUS 20866 UPS2Intro +
+
0.9.4
Astro Boy SLUS 20867 UPS2Playable +
+
0.9.4
Atelier Iris - Eternal Mana SLUS 21113 UPS2Playable +
+
0.9.4
Atelier Iris - Grand Phantasm SLPM 66436 JPS2Menus +
+
0.9.2
Atelier Iris 2 - Azoth Of Destiny SLUS 21327 UPS2Playable +
+
0.9.4
Atelier Iris 3 - Grand Phantasm SLUS 21564 UPS2Menus +
+
0.9.4
Athens 2004 SCUS 97379 UPS2Playable +
+
0.9.4
ATV Offroad Fury 2 SCUS 97369 UPS2Menus +
+
0.9.4
ATV Offroad Fury 3 SCUS 97405 UPS2Ingame +
+
0.9.4
ATV Offroad Fury 4 SCUS 97479 UPS2Playable +
+
0.9.4
ATV Offroad Fury SCUS 97104 UPS2Menus +
+
0.9.4
ATV Quad Power Racing 2 SLUS 20570 UPS2Playable +
+
0.9.4
Auto Modellista SLES 51191 EPS2Playable +
+
0.9.4
Auto Modellista SLUS 20642 UPS2Playable +
+
0.9.4
Avatar - The Last Airbender - Burning Earth SLUS 21588 UPS2Ingame +
+
0.9.4
Avatar - The Last Airbender SLUS 21395 UPS2Playable +
+
0.9.4
Ayumi Hamasaki - A Visual Mix SLPM 65086 JPS2Menus +
+
0.9.4
Azur & Asmar SLES 54695 EPS2Ingame +
+
0.9.4
Backyard Football 2006 SLUS 20876 UPS2Playable +
+
0.9.4
Backyard Football 2008 SLUS 21670 UPS2Menus +
+
0.9.4
Backyard Wrestling SLUS 20638 UPS2Intro +
+
0.9.2
Bad Boys - Miami Takedown SLUS 20982 UPS2Ingame +
+
0.9.4
Baldurs Gate - Dark Alliance SLUS 20035 UPS2Menus +
+
0.9.4
Baphomets Fluch - Der Schlafende Drache SLES 51978 GPS2Playable +
+
0.9.2
Barbarian SLES 50972 EPS2Playable +
+
0.9.2
Barbarian SLUS 20136 UPS2Intro +
+
0.9.4
Barbie - The Island Princess SLUS 21684 UPS2Ingame +
+
0.9.4
Bard's Tale, The SLUS 20803 UPS2Intro +
+
0.9.4
Barnyard SLUS 21277 UPS2Intro +
+
0.9.2
Bass Strike SLUS 20325 UPS2Playable +
+
0.9.4
Batman - Rise Of Sin Tzu SLUS 20709 UPS2Intro +
+
0.9.4
Batman Begins SLUS 21198 UPS2Intro +
+
0.9.4
Batman Vengeance SLUS 20226 UPS2Intro +
+
0.9.4
Battle Assault 3 Featuring Gundam Seed SLUS 20929 UPS2Playable +
+
0.9.4
Battle Engine Aquila SLUS 20495 UPS2Intro +
+
0.9.4
Battle Stadium SLPS 25675 JPS2Playable +
+
0.9.4
Battlefield 2 - Modern Combat SLUS 21026 UPS2Ingame +
+
0.9.4
Battlestar Galactica SLUS 20421 UPS2Ingame +
+
0.9.4
Beach King Stunts Racer SLES 51383 EPS2Playable +
+
0.9.2
Beatdown - Fist of Vengeance SLUS 21150 UPS2Playable +
+
0.9.4
Beatmania IIDX 9th Style SLPM 65946 JPS2Playable +
+
0.9.4
Beatmania SLUS 21239 UPS2Playable +
+
0.9.4
Bee Movie Game SLUS 21622 UPS2Ingame +
+
0.9.4
Ben 10 - Protector Of Earth SLUS 21661 UPS2Playable +
+
0.9.4
Berserk SLPM 65688 JPS2Playable +
+
0.9.4
Beyond Good and Evil SLUS 20763 UPS2Intro +
+
0.9.4
Big Mutha Truckers 2 - Truck Me Harder SLUS 21086 UPS2Playable +
+
0.9.4
Big Mutha Truckers SLES 51355 EPS2Menus +
+
0.9.2
Big Mutha Truckers SLUS 20291 UPS2Nothing +
+
0.9.4
Bike Street Vert Dirt SLUS 20310 UPS2Playable +
+
0.9.4
Billiard Xciting SLES 51859 EPS2Nothing +
+
0.9.2
Biohazard 4 SLPM 66213 JPS2Playable +
+
0.9.4
Biohazard Code - Veronica SLPM 65022 JPS2Playable +
+
0.9.4
Bionicle Heroes SLUS 21428 UPS2Ingame +
+
0.9.4
Bionicle SLUS 20818 UPS2Ingame +
+
0.9.4
Black and Bruised SLUS 20506 UPS2Ingame +
+
0.9.4
Black Matrix 2 SLPS 20187 JPS2Ingame +
+
0.9.4
Black SLES 53886 EPS2Nothing +
+
0.9.2
Black SLUS 21376 UPS2Nothing +
+
0.9.4
Blade 2 SLUS 20360 UPS2Playable +
+
0.9.4
Blitz - The League SLUS 21128 UPS2Intro +
+
0.9.4
Blood Omen 2 SLUS 20024 UPS2Nothing +
+
0.9.4
Blood the Last Vampire - First Volume SCPS 15007 JPS2Playable +
+
0.9.4
Blood the Last Vampire - Second Volume SCPS 15008 JPS2Playable +
+
0.9.4
Blood+ Souyoku no Battle Rondo SCPS 15112 JPS2Playable +
+
0.9.4
BloodRayne 2 SLES 53831 EPS2Playable +
+
0.9.4
BloodRayne 2 SLUS 20862 UPS2Ingame +
+
0.9.4
Bloodrayne SLUS 20461 UPS2Playable +
+
0.9.4
Bloody Roar 3 SLES 50203 EPS2Ingame +
+
0.9.4
Bloody Roar 3 SLPM 62055 JPS2Ingame +
+
0.9.4
Bloody Roar 4 SLES 51877 EPS2Ingame +
+
0.9.2
Bloody Roar 4 SLUS 20795 UPS2Playable +
+
0.9.4
Blowout SLUS 20850 UPS2Playable +
+
0.9.4
BMX XXX SLES 50880 EPS2Playable +
+
0.9.2
BMX XXX SLUS 20415 UPS2Playable +
+
0.9.4
Bode Miller Alpine Skiing SLUS 21381 UPS2Nothing +
+
0.9.4
Boku to Mao SCPS 11008 JPS2Playable +
+
0.9.4
Bombastic SLES 51966 EPS2Menus +
+
0.9.4
Bombastic SLUS 20764 UPS2Menus +
+
0.9.4
Bomberman Hardball SLES 53301 EPS2Playable +
+
0.9.4
Bomberman Kart SLPM 62118 JPS2Playable +
+
0.9.2
Bouncer, The SCES 50241 EPS2Ingame +
+
0.9.2
Bouncer, The SLUS 20069 UPS2Ingame +
+
0.9.4
Brave - The Search For Spirit Dancer SLUS 21127 UPS2Menus +
+
0.9.4
Bravo Music SCPS 11013 JPS2Playable +
+
0.9.4
Breath of Fire - Dragon Quarter SLUS 20499 UPS2Ingame +
+
0.9.4
Brian Lara Cricket 2005 SLES 52717 EPS2Ingame +
+
0.9.3
Brian Lara International Cricket 2007 SLES 54230 EPS2Ingame +
+
0.9.4
Britney's Dance Beat SLUS 20402 UPS2Ingame +
+
0.9.4
Brothers In Arms - Earned In Blood SLUS 21310 UPS2Menus +
+
0.9.4
Brothers In Arms - Road To Hill 30 SLUS 21163 UPS2Menus +
+
0.9.4
Brunswick Pro Bowling SLUS 21566 UPS2Playable +
+
0.9.4
Buffy - Chaos Bleeds SLES 51890 EPS2Playable +
+
0.9.2
Buffy The Vampire Slayer - Chaos Bleeds SLUS 20566 UPS2Ingame +
+
0.9.4
Bujingai - The Forsaken City SLUS 20895 UPS2Playable +
+
0.9.4
Bully SLUS 21269 UPS2Ingame +
+
0.9.4
Burnout - Revenge SLES 53506 EPS2Nothing +
+
0.9.2
Burnout - Revenge SLUS 21242 UPS2Intro +
+
0.9.4
Burnout 2 SLUS 20497 UPS2Playable +
+
0.9.2
Burnout 3 - Takedown SLUS 21050 UPS2Intro +
+
0.9.4
Burnout Dominator SLUS 21596 UPS2Intro +
+
0.9.4
Burnout SLES 50445 EPS2Playable +
+
0.9.2
Burnout SLUS 20307 UPS2Playable +
+
0.9.4
Bust A Bloc SLES 51713 EPS2Ingame +
+
0.9.4
Butt Ugly Martians - Zoom Or Doom SLUS 20527 UPS2Ingame +
+
0.9.4
Buzz - The Big Quiz SCES 53925 EPS2Intro +
+
0.9.2
Cabelas - African Safari SLUS 21379 UPS2Ingame +
+
0.9.4
Cabelas - Alaskan Adventures SLUS 21384 UPS2Ingame +
+
0.9.4
Cabelas - Big Game Hunter SLUS 20534 UPS2Playable +
+
0.9.4
Cabelas - Dangerous Hunts 2 SLUS 21350 UPS2Playable +
+
0.9.4
Cabelas - Trophy Bucks SLUS 21624 UPS2Intro +
+
0.9.4
Call Of Duty - Finest Hour SLUS 20725 UPS2Intro +
+
0.9.4
Call Of Duty 2 - Big Red One SLUS 21228 UPS2Intro +
+
0.9.4
Call Of Duty 3 SLUS 21426 UPS2Intro +
+
0.9.4
Capcom Classics Collection Volume 2 SLUS 21473 UPS2Playable +
+
0.9.4
Capcom Fighting Jam SLES 52854 EPS2Playable +
+
0.9.4
Capcom Fighting Jam SLPM 65794 JPS2Playable +
+
0.9.4
Capcom VS. SNK 2 PBPX 95201 JPS2Playable +
+
0.9.4
Card Captor Sakura SLPS 20408 JPS2Ingame +
+
0.9.2
Carmen Sandiego - The Secret of The Stolen Drums SLES 52143 EPS2Ingame +
+
0.9.2
Carol Vordermans Sudoku SLUS 21495 UPS2Intro +
+
0.9.4
CART Fury Championship Racing SLUS 20141 UPS2Ingame +
+
0.9.4
Cartoon Network Racing SLUS 21438 UPS2Menus +
+
0.9.4
Casper - Spirit Dimensions SLUS 20205 UPS2Ingame +
+
0.9.4
Castle Shikigami 2 SLUS 20962 UPS2Nothing +
+
0.9.4
Castlevania - Curse of Darkness SLES 53755 EPS2Playable +
+
0.9.4
Castlevania - Curse of Darkness SLUS 21168 UPS2Playable +
+
0.9.4
Castlevania - Lament of Innocence SLUS 20733 UPS2Playable +
+
0.9.4
Castlevania SLES 52118 EPS2Menus +
+
0.9.2
Castlevania SLPM 65444 JPS2Playable +
+
0.9.4
Castleween SLES 51249 EPS2Ingame +
+
0.9.4
Catwoman SLUS 20992 UPS2Menus +
+
0.9.4
Celebrity Deathmatch SLUS 20604 UPS2Ingame +
+
0.9.4
Champions - Return To Arms SLUS 20973 UPS2Ingame +
+
0.9.4
Champions of Norrath - Realms of Everquest SLUS 20565 UPS2Ingame +
+
0.9.4
Chaos Legion SLUS 20695 UPS2Ingame +
+
0.9.4
Charlie and The Chocolate Factory SLES 53386 EPS2Playable +
+
0.9.2
Charlie and The Chocolate Factory SLUS 21246 UPS2Playable +
+
0.9.4
Charlie's Angels SLES 51750 EPS2Ingame +
+
0.9.2
Chess Challenger SLES 51630 EPS2Playable +
+
0.9.2
Chessmasters SLUS 20637 UPS2Nothing +
+
0.9.4
Choro Q SLUS 20930 UPS2Ingame +
+
0.9.4
Chou Aniki: Sei Naru Protein Densetsu SLPM 62403 JPS2Ingame +
+
0.9.4
Chronicles of Narnia, The - The Lion, The Witch and The Wardrobe SLES 53706 EPS2Intro +
+
0.9.2
Chronicles of Narnia, The - The Lion, The Witch and The Wardrobe SLUS 21082 UPS2Intro +
+
0.9.4
Chulip SLPS 20230 JPS2Playable +
+
0.9.4
Chulip SLUS 20742 UPS2Playable +
+
0.9.4
Clock Tower 3 SLES 51619 EPS2Playable +
+
0.9.4
Clock Tower 3 SLPM 65221 JPS2Playable +
+
0.9.4
Codename: Kids Next Door - Operation V.I.D.E.O.G.A.M.E SLES 53685 EPS2Ingame +
+
0.9.2
Cold Fear SLES 53158 EPS2Intro +
+
0.9.2
Cold Fear SLUS 21047 UPS2Playable +
+
0.9.4
Cold Winter SLUS 20845 UPS2Nothing +
+
0.9.4
Colin McRae 2005 SLES 52636 EPS2Ingame +
+
0.9.4
Colin McRae Rally 3 SLUS 20502 UPS2Ingame +
+
0.9.4
College Hoops 2006 SLUS 21232 UPS2Intro +
+
0.9.2
Colosseum - Road To Freedom SLUS 21179 UPS2Playable +
+
0.9.4
Combat Queen SLPM 65169 JPS2Playable +
+
0.9.4
Commandos - Strike Force SLUS 21103 UPS2Intro +
+
0.9.4
Commandos 2 SLUS 20086 UPS2Ingame +
+
0.9.4
Conflict - Desert Storm SLUS 20549 UPS2Ingame +
+
0.9.4
Conflict - Global Terror SLUS 21172 UPS2Ingame +
+
0.9.4
Conflict Desert Storm 2 - Back To Baghdad SLES 51523 EPS2Playable +
+
0.9.4
Conflict Zone SLUS 20240 UPS2Ingame +
+
0.9.4
Constantine SLUS 21142 UPS2Ingame +
+
0.9.4
Contra - Shattered Soldier SLUS 20306 UPS2Playable +
+
0.9.4
Cool Shot SLES 51785 EPS2Playable +
+
0.9.4
Cool Shot SLPS 20256 JPS2Playable +
+
0.9.4
Corvette Evolution GT SLUS 21499 UPS2Nothing +
+
0.9.4
Corvette SLUS 20858 UPS2Playable +
+
0.9.4
Crash Bandicoot - The Wrath of Cortex SLUS 20238 UPS2Playable +
+
0.9.4
Crash N Burn SLES 52339 EPS2Ingame +
+
0.9.2
Crash Nitro Karts SLUS 20649 UPS2Intro +
+
0.9.4
Crash Of The Titans SLUS 21583 UPS2Playable +
+
0.9.4
Crash Tag Team Racing SLUS 21191 UPS2Ingame +
+
0.9.4
Crash Twinsanity SLES 52568 EPS2Ingame +
+
0.9.2
Crash Twinsanity SLUS 20909 UPS2Playable +
+
0.9.4
Crazy Frog Racer SLES 53869 EPS2Nothing +
+
0.9.2
Crazy Taxi SLES 50215 EPS2Playable +
+
0.9.4
Crazy Taxi SLUS 20202 UPS2Playable +
+
0.9.2
Crimson Sea 2 SLUS 20877 UPS2Intro +
+
0.9.4
Crimson Tears SLPM 65575 JPS2Ingame +
+
0.9.2
Crimson Tears SLUS 20948 UPS2Playable +
+
0.9.4
Crouching Tiger Hidden Dragon SLUS 20523 UPS2Playable +
+
0.9.4
CSI: 3 Dimensions Of Murder SLUS 21655 UPS2Intro +
+
0.9.4
Culdcept SLUS 20774 UPS2Playable +
+
0.9.4
Curry House Coco Ichibanya SLPS 20367 JPS2Playable +
+
0.9.4
Cy Girls SLUS 20697 UPS2Ingame +
+
0.9.4
Cyclone Circus - Power Sail Racing SLES 52684 EPS2Nothing +
+
0.9.2
D1 Grand Prix SLUS 21416 UPS2Playable +
+
0.9.4
Da Vinci Code, The SLUS 21443 UPS2Ingame +
+
0.9.4
Dakar 2 SLES 50879 EPS2Ingame +
+
0.9.2
Dance Dance Revolution - Extreme 2 SLUS 21174 UPS2Ingame +
+
0.9.4
Dance Dance Revolution - Extreme SLPM 65358 JPS2Playable +
+
0.9.4
Dance Dance Revolution - Extreme SLUS 20916 UPS2Playable +
+
0.9.4
Dance Dance Revolution - Supernova 2 SLUS 21608 UPS2Playable +
+
0.9.4
Dance Dance Revolution - Supernova SLUS 21377 UPS2Ingame +
+
0.9.4
Dance Factory SLUS 21296 UPS2Menus +
+
0.9.4
Dance Summit 2001 - Bust A Move PBPX 95201 JPS2Intro +
+
0.9.4
Dancing Stage Fever MegaMix SLES 51510 EPS2Playable +
+
0.9.2
Dancing Stage Fever SLES 51757 EPS2Playable +
+
0.9.2
Dancing Stage Fusion SLES 52598 EPS2Playable +
+
0.9.4
Dancing With The Stars SLUS 21676 UPS2Playable +
+
0.9.4
Dark Angel - Vampire Apocalypse SLUS 20131 UPS2Ingame +
+
0.9.4
Dark Chronicle SCES 51190 EPS2Ingame +
+
0.9.4
Dark Cloud 2 SCUS 97213 UPS2Ingame +
+
0.9.4
Dark Cloud SCES 50295 EPS2Playable +
+
0.9.4
Dark Cloud SCUS 97111 UPS2Ingame +
+
0.9.4
Dark Summit SLUS 20300 UPS2Menus +
+
0.9.2
Darkwatch SLUS 21042 UPS2Playable +
+
0.9.4
Das Ding aus einer anderen Welt SLES 50976 GPS2Ingame +
+
0.9.3
Dave Mira Freestyle BMX 2 SLUS 20159 UPS2Playable +
+
0.9.4
Dawn Of Mana SLUS 21574 UPS2Ingame +
+
0.9.4
DDR Festival SLPM 65775 JPS2Playable +
+
0.9.4
DDR Max 2 SLPM 65277 JPS2Playable +
+
0.9.4
DDR Max SLPM 62154 JPS2Playable +
+
0.9.4
DDR Party Collection SLPM 62427 JPS2Ingame +
+
0.9.2
DDR Strike SLPM 66242 JPS2Playable +
+
0.9.4
DDRmax1 - Dance Dance Revolution SLUS 20437 UPS2Playable +
+
0.9.2
DDRmax2 - Dance Dance Revolution SLUS 20711 UPS2Playable +
+
0.9.2
Dead or Alive 2 - Hardcore PBPX 95201 JPS2Nothing +
+
0.9.2
Dead or Alive 2 - Hardcore SLUS 20071 UPS2Nothing +
+
0.9.4
Dead or Alive 2 SCES 50003 EPS2Nothing +
+
0.9.4
Dead or Alive 2 SLPS 25002 JPS2Nothing +
+
0.9.4
Dead Or Alive 2 SLUS 20071 UPS2Nothing +
+
0.9.4
Dead To Rights 2 SLUS 20843 UPS2Ingame +
+
0.9.4
Dead To Rights SLES 51581 EPS2Playable +
+
0.9.2
Dead To Rights SLUS 20220 UPS2Intro +
+
0.9.4
Death By Degrees SLUS 20934 UPS2Playable +
+
0.9.4
Defender SLUS 20191 UPS2Ingame +
+
0.9.4
Delta Force - Black Hawk Down SLUS 21124 UPS2Intro +
+
0.9.4
Delta Force - Black Hawk Down - Team Sabre SLUS21414 UPS2Intro +
+
0.9.4
Demento SLPM 65913 JPS2Playable +
+
0.9.4
Demolition Girl SLES 53403 EPS2Ingame +
+
0.9.4
Demonstone SLES 52669 EPS2Playable +
+
0.9.2
Destroy All Humans 2 - Make War Not Love SLUS 21439 UPS2Ingame +
+
0.9.4
Destroy All Humans SLUS 20945 UPS2Menus +
+
0.9.4
Destruction Derby Arenas SCES 50781 EPS2Ingame +
+
0.9.3
Destruction Derby Arenas SLUS 20855 UPS2Ingame +
+
0.9.4
Detonator SLES 52041 EPS2Ingame +
+
0.9.4
Deus Ex - The Conspiracy SLUS 20111 UPS2Menus +
+
0.9.4
Devil Kings SLUS 21297 UPS2Playable +
+
0.9.4
Devil May Cry 2 SLES 82011 EPS2Ingame +
+
0.9.4
Devil May Cry 2 SLPM 65232 JPS2Ingame +
+
0.9.4
Devil May Cry 2 SLUS 20484 UPS2Ingame +
+
0.9.4
Devil May Cry 3 - Special Edition SLPM 66160 JPS2Playable +
+
0.9.2
Devil May Cry 3 - Special Edition SLUS 21361 UPS2Playable +
+
0.9.4
Devil May Cry 3 SLES 53038 EPS2Playable +
+
0.9.2
Devil May Cry 3 SLPM 65880 JPS2Playable +
+
0.9.4
Devil May Cry 3 SLUS 20964 UPS2Intro +
+
0.9.2
Devil May Cry SLES 50358 EPS2Menus +
+
0.9.4
Devil May Cry SLPM 65038 JPS2Menus +
+
0.9.2
Devil May Cry SLUS 20216 UPS2Intro +
+
0.9.4
Dice SLUS 21181 UPS2Ingame +
+
0.9.4
Die Hard - Vendetta SLES 51347 EPS2Playable +
+
0.9.4
Die Hard - Vendetta SLES 51348 EPS2Ingame +
+
0.9.2
Digimon World - Data Squad SLUS 21598 UPS2Playable +
+
0.9.4
Digimon World 4 SLUS 20836 UPS2Playable +
+
0.9.4
Dino Crisis - Gun Survivor 3 SLPS 25026 JPS2Menus +
+
0.9.2
Dino Stalker SLUS 20485 UPS2Playable +
+
0.9.4
Dirge Of Cerberus - Final Fantasy VII SLES 54185 EPS2Ingame +
+
0.9.3
Dirge Of Cerberus - Final Fantasy VII SLPM 66271 JPS2Menus +
+
0.9.4
Dirge Of Cerberus - Final Fantasy VII SLUS 21419 UPS2Intro +
+
0.9.4
Disaster Report SLUS 20561 UPS2Playable +
+
0.9.4
Disgaea - Hour of Darkness SLUS 20666 UPS2Playable +
+
0.9.4
Disgaea 2 - Cursed Memories SLPS 25608 JPS2Playable +
+
0.9.2
Disgaea 2 - Cursed Memories SLUS 21397 UPS2Playable +
+
0.9.4
Disney Golf SLUS 20532 UPS2Intro +
+
0.9.4
Disney Pixar - Cars - Mater-National SLUS 21637 UPS2Ingame +
+
0.9.4
Disney Pixar - Cars SLES 53624 EPS2Playable +
+
0.9.2
Disney Princess - Enchanted Journey SLUS 21660 UPS2Ingame +
+
0.9.4
Disney's Extreme Skate Adventure SLUS 20607 UPS2Intro +
+
0.9.4
Disney's Stitch: Experiment 626 SCES 50960 EPS2Playable +
+
0.9.3
Disneys Pixar Cars SLUS 21151 UPS2Playable +
+
0.9.4
DNA Dark Native Apostle SLES 50202 EPS2Ingame +
+
0.9.3
Dodgeball SLES 53367 EPS2Playable +
+
0.9.2
Dog's Life SLUS 21018 UPS2Ingame +
+
0.9.4
Donald Duck Phantomias Platyrhynchos Kineticus SLES 50773 EPS2Ingame +
+
0.9.2
Donald Duck Quack Attack SLES 50048 EPS2Intro +
+
0.9.4
Dot Hack - Infection Part 1 SLUS 20267 UPS2Ingame +
+
0.9.4
Dot Hack - Mutation Part 2 SLES 52467 EPS2Ingame +
+
0.9.4
Dot Hack - Mutation Part 2 SLUS 20562 UPS2Ingame +
+
0.9.4
Dot Hack - Outbreak Part 3 SLUS 20563 UPS2Ingame +
+
0.9.4
Dot Hack - Quarantine Part 4 SLES 52468 EPS2Ingame +
+
0.9.4
Dot Hack GU Volume 1 - Rebirth - Terminal Disc SLUS 21480 UPS2Playable +
+
0.9.4
Dot Hack GU Volume 1 - Rebirth SLUS 21258 UPS2Ingame +
+
0.9.4
Dot Hack GU Volume 2 - Remnisce SLUS 21488 UPS2Ingame +
+
0.9.4
Dot Hack GU Volume 3 - Redemption SLUS 21489 UPS2Ingame +
+
0.9.4
Downforce SLES 50842 EPS2Ingame +
+
0.9.2
Downhill Domination SCUS 97177 UPS2Playable +
+
0.9.4
Dr. Muto SLUS 20458 UPS2Intro +
+
0.9.4
Dragon Quest VIII - Journey of the Cursed King SLES 53974 EPS2Playable +
+
0.9.2
Dragon Quest VIII SLUS 21207 UPS2Playable +
+
0.9.4
Dragonball Z Budokai 2 SLES 51839 EPS2Playable +
+
0.9.4
Dragonball Z Budokai 3 SLES 52730 EPS2Playable +
+
0.9.4
Dragonball Z Budokai Tenkaichi 2 SLUS 21441 UPS2Ingame +
+
0.9.4
Dragonball Z Budokai Tenkaichi SLES 53200 EPS2Ingame +
+
0.9.4
Dragonball Z Budokai Tenkaichi SLUS 21227 UPS2Playable +
+
0.9.4
Dragonball Z Budokai SLES 51233 EPS2Playable +
+
0.9.2
Dragonball Z Budokai SLUS 20591 UPS2Playable +
+
0.9.4
Dragonball Z Sagas SLUS 20874 UPS2Ingame +
+
0.9.4
Drakan - The Ancients Gate SCUS 97128 UPS2Intro +
+
0.9.4
Drakengard 2 SLUS 21373 UPS2Playable +
+
0.9.4
Drakengard SLUS 20732 UPS2Ingame +
+
0.9.4
DreamMix TV - World Fighters SLPM 65384 JPS2Playable +
+
0.9.4
Drive To Survive SLUS 21109 UPS2Intro +
+
0.9.4
Driver - Parallel Lines SLUS 21271 UPS2Ingame +
+
0.9.4
Driver 3 SLUS 20587 UPS2Ingame +
+
0.9.4
Driving Emotion Type-S SLPS 20007 JPS2Ingame +
+
0.9.2
Driving Emotion Type-S SLUS 20113 UPS2Ingame +
+
0.9.4
Drome Racers SLUS 20577 UPS2Ingame +
+
0.9.4
Dropship - United Peace Force SCES 50459 EPS2Intro +
+
0.9.2
Dropship - United Peace Force SLUS 20463 UPS2Menus +
+
0.9.4
DT Racer SLUS 21095 UPS2Intro +
+
0.9.4
DTM Race Driver 2 SLES 52638 EPS2Ingame +
+
0.9.2
DTM Race Driver SLES 50816 EPS2Playable +
+
0.9.2
Dual Hearts SLUS 20475 UPS2Menus +
+
0.9.4
Duel Masters SLUS 20924 UPS2Playable +
+
0.9.4
Dukes of Hazard SLUS 20959 UPS2Intro +
+
0.9.4
Dynasty Tactics 2 SLUS 20761 UPS2Intro +
+
0.9.4
Dynasty Warriors 3 SLES 50641 EPS2Playable +
+
0.9.4
Dynasty Warriors 3 SLUS 20277 UPS2Ingame +
+
0.9.4
Dynasty Warriors 4 - Empires SLUS 20653 UPS2Playable +
+
0.9.4
Dynasty Warriors 4 Xtreme Legends SLUS 20812 UPS2Playable +
+
0.9.4
Dynasty Warriors 4 SLUS 20653 UPS2Playable +
+
0.9.4
Dynasty Warriors 5 - Empires SLUS 21398 UPS2Ingame +
+
0.9.4
Dynasty Warriors 5 Xtreme Legends SLUS 21299 UPS2Playable +
+
0.9.4
Dynasty Warriors 5 SLUS 21153 UPS2Playable +
+
0.9.4
EA Arena Football SLUS 21337 UPS2Ingame +
+
0.9.4
EA Sports cricket 2004 SLES 52123 EPS2Ingame +
+
0.9.3
Eagle Eye Golf SLUS 21486 UPS2Playable +
+
0.9.4
Ecco the Dolphin - Defender of the Future SCES 50499 EPS2Intro +
+
0.9.4
Ecco the Dolphin - Defender of the Future SLUS 20394 UPS2Intro +
+
0.9.4
Echo Night Beyond SLUS 20928 UPS2Ingame +
+
0.9.4
Egg Mania - Eggstreme Madness SLUS 20452 UPS2Menus +
+
0.9.4
Eggomania SLES 51101 EPS2Playable +
+
0.9.2
Endgame SLUS 20389 UPS2Nothing +
+
0.9.4
Energy Airforce SLPM 65177 JPS2Playable +
+
0.9.2
Energy Airforce SLPS 25026 JPS2Playable +
+
0.9.4
Enter The Matrix SLES 51203 EPS2Playable +
+
0.9.4
Enter The Matrix SLUS 20454 UPS2Intro +
+
0.9.4
Enthusia Professional Racing SLUS 20967 UPS2Ingame +
+
0.9.4
Ephemeral Fantasia SLUS 20169 UPS2Menus +
+
0.9.4
Ephemeral Phantasia SLES 50110 EPS2Ingame +
+
0.9.2
Eragon SLUS 21322 UPS2Ingame +
+
0.9.4
Erementar Gerad SLPM 62623 JPS2Ingame +
+
0.9.2
Escape From Monkey Island SLUS 20181 UPS2Ingame +
+
0.9.4
Espgaluda SLPS 25352 JPS2Playable +
+
0.9.4
ESPN International Track And Field SLUS 20041 UPS2Playable +
+
0.9.4
ESPN NBA 2Night SLUS 20261 UPS2Menus +
+
0.9.2
ESPN NFL 2K5 SLUS 20919 UPS2Intro +
+
0.9.4
ESPN NHL Hockey SLUS 20728 UPS2Menus +
+
0.9.2
ESPN Winter X Games Snowboarding 2002 SLUS 20321 UPS2Playable +
+
0.9.4
Eternal Quest SLES 51624 EPS2Playable +
+
0.9.2
Eternal Ring SLUS 20015 UPS2Ingame +
+
0.9.4
Eureka Seven Volume 1 - The New Wave SLUS 21353 UPS2Ingame +
+
0.9.4
Euro Rally Champion SLES 52378 EPS2Ingame +
+
0.9.2
Eve Of Destruction SLUS 20270 UPS2Ingame +
+
0.9.4
Everblue 2 SLUS 20598 UPS2Intro +
+
0.9.4
Everblue SLES 50639 EPS2Playable +
+
0.9.2
Everblue SLPM 62081 JPS2Playable +
+
0.9.4
Evergrace SLES 50050 EPS2Playable +
+
0.9.2
Evergrace SLUS 20016 UPS2Ingame +
+
0.9.4
Everquest Online Adventures SCES 51725 EPS2Menus +
+
0.9.2
Evil Dead - A Fistful of Boomstick SLUS 20403 UPS2Ingame +
+
0.9.4
Evil Dead - Regeneration SLUS 21048 UPS2Playable +
+
0.9.4
Evil Twin - Cyprien's Chronicles SLES 50201 EPS2Playable +
+
0.9.4
Evil Twin PBPX 95201 EPS2Playable +
+
0.9.2
Evolution Snowboarding SLUS 20546 UPS2Intro +
+
0.9.4
Extermination SCUS 97112 UPS2Playable +
+
0.9.4
Eyetoy - Kinetic SCES 52883 EPS2Intro +
+
0.9.2
EyeToy - Monkey Mania SCES 52930 EPS2Intro +
+
0.9.4
Eyetoy - Play 2 SCES 52748 EPS2Intro +
+
0.9.2
Eyetoy - Sega Superstars SLES 52834 EPS2Nothing +
+
0.9.2
Eyetoy Play 2 SCUS 97468 UPS2Intro +
+
0.9.4
Eyetoy Play SCUS 97319 UPS2Intro +
+
0.9.4
F1 2001 SLES 50423 EPS2Intro +
+
0.9.2
F1 Career Challenge SLES 51584 EPS2Menus +
+
0.9.2
F1 Championship Season 2000 SLES 50017 EPS2Playable +
+
0.9.2
F1 Championship Season 2000 SLUS 20103 UPS2Ingame +
+
0.9.2
F1 Racing Championship SLES 50046 EPS2Ingame +
+
0.9.2
Family Feud SLUS 21446 UPS2Nothing +
+
0.9.4
Family Guy SLUS 21560 UPS2Playable +
+
0.9.4
Fantastic 4 SLUS 20615 UPS2Ingame +
+
0.9.4
Fantastic Four - Rise Of The Silver Surfer SLUS 21544 UPS2Ingame +
+
0.9.4
Fantavision SCPS 11002 JPS2Playable +
+
0.9.4
Fantavision SLUS 97015 UPS2Playable +
+
0.9.4
Fast and The Furious, The SLUS 21449 UPS2Ingame +
+
0.9.4
Fatal Frame 2 SLUS 20766 UPS2Menus +
+
0.9.4
Fatal Frame 3 SLUS 21244 UPS2Menus +
+
0.9.4
Fatal Frame SLUS 20388 UPS2Ingame +
+
0.9.4
Fatal Fury - Battle Archives 1 SLPS 25664 JPS2Playable +
+
0.9.2
Fatal Fury - Battle Archives Volume 1 SLUS 21537 UPS2Playable +
+
0.9.4
FC Barcelona Club Football SLES 51078 EPS2Ingame +
+
0.9.4
Ferrari F355 Challenge SCES 50956 EPS2Playable +
+
0.9.2
FIFA 07 SLES 54240 EPS2Ingame +
+
0.9.4
Fifa 2002 SLUS 20280 UPS2Intro +
+
0.9.2
Fifa 2005 SLUS 21051 UPS2Ingame +
+
0.9.4
FIFA Football 2003 SLES 51197 EPS2Ingame +
+
0.9.2
FIFA Soccer 2004 SLKA 25087 JPS2Ingame +
+
0.9.3
FIFA Street 2 SLES 53796 EPS2Ingame +
+
0.9.4
Fifa Street SLES 53064 EPS2Nothing +
+
0.9.3
Fifa World Cup 2002 SLES 50798 EPS2Intro +
+
0.9.2
Fight Club SLUS 20857 UPS2Ingame +
+
0.9.4
Fight Night - Round 3 SLUS 21383 UPS2Playable +
+
0.9.4
Fighter Maker 2 SLUS 20524 UPS2Playable +
+
0.9.4
Fighting Angels SLES 53408 EPS2Ingame +
+
0.9.4
Final Fantasy X - International Version SLPS 25088 JPS2Playable +
+
0.9.4
Final Fantasy X SCES 50490 EPS2Playable +
+
0.9.4
Final Fantasy X SCES 50492 GPS2Playable +
+
0.9.2
Final Fantasy X SLPS 25050 JPS2Playable +
+
0.9.4
Final Fantasy X SLUS 20312 UPS2Playable +
+
0.9.4
Final Fantasy X-2 International Version + Last Mission SLPM 65478 JPS2Playable +
+
0.9.4
Final Fantasy X-2 SLES 51815 EPS2Playable +
+
0.9.4
Final Fantasy X-2 SLES 51817 GPS2Ingame +
+
0.9.2
Final Fantasy X-2 SLUS 20672 UPS2Playable +
+
0.9.4
Final Fantasy XI Expansion Pack SCUS 97269 UPS2Intro +
+
0.9.4
Final Fantasy XI SCUS 97266 UPS2Menus +
+
0.9.4
Final Fantasy XI SLPS 25200 JPS2Menus +
+
0.9.4
Final Fantasy XII SLES 54354 EPS2Ingame +
+
0.9.4
Final Fantasy XII SLPM 66320 JPS2Playable +
+
0.9.4
Final Fantasy XII SLUS 20963 UPS2Ingame +
+
0.9.4
Final Fight - Streetwise SLUS 21238 UPS2Intro +
+
0.9.4
Finny The Fish & The Seven Waters SLUS 21072 UPS2Playable +
+
0.9.4
Fire Pro Wrestling Z SLPM 62342 JPS2Playable +
+
0.9.2
Fireblade SLUS 20198 UPS2Ingame +
+
0.9.2
Firefighter F.D. 18 SLUS 20724 UPS2Ingame +
+
0.9.4
Fisherman's Challenge SLES 51418 EPS2Nothing +
+
0.9.3
Fisherman's Challenge SLUS 20553 UPS2Intro +
+
0.9.4
Fishermans Bass Club SLUS 20428 UPS2Playable +
+
0.9.4
Flatout 2 SLES 54002 EPS2Ingame +
+
0.9.2
Flatout 2 SLUS 21251 UPS2Ingame +
+
0.9.4
Flatout SLUS 20901 UPS2Intro +
+
0.9.4
Flipnic SCPS 15050 JPS2Ingame +
+
0.9.4
Flipnic SLUS 21157 UPS2Intro +
+
0.9.4
Flow - Urban Dance Uprising SLES 53848 EPS2Ingame +
+
0.9.4
Flow - Urban Dance Uprising SLUS 21319 UPS2Intro +
+
0.9.4
Flucht von Monkey Island SLES 50227 GPS2Ingame +
+
0.9.2
Flushed Away SLUS 21484 UPS2Ingame +
+
0.9.4
Forbidden Siren SCES 52328 GPS2Ingame +
+
0.9.2
Ford Mustang - The Legend Lives SLES 53296 EPS2Ingame +
+
0.9.2
Forever Kingdom SLUS 20343 UPS2Menus +
+
0.9.4
Forgotten Realms - Demon Stone SLUS 20804 UPS2Ingame +
+
0.9.4
Formula 1 2006 SCES 53950 EPS2Intro +
+
0.9.4
Formula One 2001 SCES 50004 EPS2Ingame +
+
0.9.2
Formula One 2003 SCES 51592 EPS2Ingame +
+
0.9.2
Formula One 2005 SCES 53033 EPS2Intro +
+
0.9.2
Freak Out SLES 50310 EPS2Ingame +
+
0.9.4
Freaky Flyers SLUS 20284 UPS2Nothing +
+
0.9.4
Freedom Fighters SLUS 20658 UPS2Ingame +
+
0.9.4
Freestyle SLUS 20367 UPS2Ingame +
+
0.9.4
Frequency SCES 50791 EPS2Playable +
+
0.9.4
Frequency SCUS 97125 UPS2Playable +
+
0.9.4
Friends - The One With All The Trivia SLUS 21313 UPS2Playable +
+
0.9.4
Frogger - Ancient Shadows SLUS 21098 UPS2Nothing +
+
0.9.4
Froggers Adventures - The Rescue SLUS 20734 UPS2Playable +
+
0.9.4
Front Mission 4 SLUS 20888 UPS2Playable +
+
0.9.4
Fu-Un Bakumatsu-Den SLPM 65813 JPS2Menus +
+
0.9.2
Fugitive Hunter - War On Terror SLUS 20464 UPS2Ingame +
+
0.9.4
Full Metal Alchemist 2 - Curse of the Crimson Elixir SLUS 21166 UPS2Playable +
+
0.9.4
Full Metal Alchemist and The Broken Angel SLUS 20994 UPS2Playable +
+
0.9.4
Full Spectrum Warriors - Ten Hammers SLUS 21250 UPS2Intro +
+
0.9.4
Fur Fighters - Viggos Revenge SLUS 20088 UPS2Playable +
+
0.9.4
Futurama SLUS 20439 UPS2Playable +
+
0.9.4
Future Tactics - The Uprising SLUS 20859 UPS2Playable +
+
0.9.4
Gadget Racer SLUS 20225 UPS2Intro +
+
0.9.4
Galactic Wrestling SLUS 20822 UPS2Playable +
+
0.9.4
Galerians - Ash SLUS 20560 UPS2Ingame +
+
0.9.4
Gallop Racer 2006 SLUS 21393 UPS2Playable +
+
0.9.4
Gantz SLPM 65950 JPS2Playable +
+
0.9.2
Garfield 2 - Tale of Two Kitties SLES 54172 EPS2Ingame +
+
0.9.3
Gauntlet - Dark Legacy SLES 50211 EPS2Ingame +
+
0.9.3
Gauntlet - Dark Legacy SLUS 20047 UPS2Intro +
+
0.9.4
Gauntlet - Seven Sorrows SLUS 21077 UPS2Ingame +
+
0.9.4
Gegege no Kitaro SLPM 65337 JPS2Playable +
+
0.9.4
Gekibo 2 SLPS 20091 JPS2Playable +
+
0.9.4
Genji - Dawn of The Samurai SCUS 97471 UPS2Nothing +
+
0.9.4
Getaway - Black Monday, The SCUS 97408 UPS2Ingame +
+
0.9.4
Getaway, The SCES 51159 EPS2Ingame +
+
0.9.2
Ghost In The Shell - Stand Alone Complex SLUS 21006 UPS2Ingame +
+
0.9.4
Ghost Recon - Advanced Warfighter SLUS 21422 UPS2Intro +
+
0.9.4
Ghost Recon - Jungle Storm SLUS 20820 UPS2Playable +
+
0.9.4
Ghost Rider SLUS 21306 UPS2Intro +
+
0.9.4
Ghosthunter SCES 51463 EPS2Ingame +
+
0.9.4
Ghosthunter SLUS 20993 UPS2Intro +
+
0.9.4
Giants - Citizen Kabuto SLUS 20178 UPS2Nothing +
+
0.9.4
Gift SLES 50296 EPS2Ingame +
+
0.9.4
Girl Zone SLES 53190 EPS2Playable +
+
0.9.4
Gitaroo Man SLPM 65012 JPS2Playable +
+
0.9.4
Gitaroo Man SLUS 20294 UPS2Playable +
+
0.9.4
Gladiator - Sword of Vengeance SLUS 20793 UPS2Intro +
+
0.9.4
Gladius SLUS 20490 UPS2Playable +
+
0.9.4
Glass Rose SLPM 65373 JPS2Playable +
+
0.9.4
Goblin Commander - Unleash The Horde SLUS 20792 UPS2Playable +
+
0.9.4
God Hand SLPM 66550 JPS2Ingame +
+
0.9.4
God Hand SLUS 21503 UPS2Playable +
+
0.9.4
God Of War 2 SCUS 97481 UPS2Nothing +
+
0.9.4
God of War SCES 53133 EPS2Menus +
+
0.9.4
God of War SCUS 97399 UPS2Ingame +
+
0.9.4
GoDai Elemental Force SLES 50704 EPS2Ingame +
+
0.9.2
Godfather, The SLUS 21385 UPS2Intro +
+
0.9.4
Godzilla - Save The Earth SLUS 20809 UPS2Intro +
+
0.9.4
Goemon SLPM 65014 JPS2Nothing +
+
0.9.4
Golden Eye - Rogue Agent SLUS 21064 UPS2Nothing +
+
0.9.4
Gottlieb Pinball Classics SLES 54181 EPS2Playable +
+
0.9.4
Gradius 3 & 4 SLES 50038 EPS2Playable +
+
0.9.2
Gradius 3 & 4 SLPM 62007 JPS2Playable +
+
0.9.4
Gradius 3 & 4 SLUS 20040 UPS2Playable +
+
0.9.4
Gradius 5 SLPM 62462 JPS2Playable +
+
0.9.4
Gradius 5 SLUS 20712 UPS2Playable +
+
0.9.4
Graffiti Kingdom SLUS 21136 UPS2Playable +
+
0.9.4
Gran Turismo 3 A-spec SCES 50294 EPS2Ingame +
+
0.9.4
Gran Turismo 3 A-spec SCUS 97102 UPS2Ingame +
+
0.9.4
Gran Turismo 4 First Preview PCPX 96649 JPS2Ingame +
+
0.9.2
Gran Turismo 4 Prologue PBPX 95524 JPS2Ingame +
+
0.9.2
Gran Turismo 4 Prologue SCES 52438 EPS2Ingame +
+
0.9.2
Gran Turismo 4 SCAJ 30007 JPS2Ingame +
+
0.9.2
Gran Turismo 4 SCES 51719 EPS2Ingame +
+
0.9.4
Gran Turismo 4 SCUS 97328 UPS2Intro +
+
0.9.4
Gran Turismo Concept 2001 Tokyo SCPS 15010 JPS2Ingame +
+
0.9.2
Gran Turismo Concept 2002 Tokyo-Geneva SCES 50858 EPS2Menus +
+
0.9.4
Grand Prix Challenge SLES 51296 EPS2Ingame +
+
0.9.2
Grand Prix Challenge SLUS 20630 UPS2Nothing +
+
0.9.4
Grand Theft Auto - Liberty City Stories SLES 54135 EPS2Ingame +
+
0.9.4
Grand Theft Auto - Liberty City Stories SLUS 21423 UPS2Intro +
+
0.9.4
Grand Theft Auto - San Andreas SLES 52541 EPS2Ingame +
+
0.9.4
Grand Theft Auto - San Andreas SLUS 20946 UPS2Playable +
+
0.9.4
Grand Theft Auto - Vice City Stories SLUS 21590 UPS2Ingame +
+
0.9.4
Grand Theft Auto - Vice City SLES 51061-T EPS2Intro +
+
0.9.2
Grand Theft Auto - Vice City SLES 51061 EPS2Intro +
+
0.9.3
Grand Theft Auto - Vice City SLUS 20552 UPS2Intro +
+
0.9.4
Grand Theft Auto III SLES 50330-T EPS2Ingame +
+
0.9.2
Grand Theft Auto III SLUS 20062 UPS2Intro +
+
0.9.4
Grand Tour Racing 400 SLES 52045 EPS2Ingame +
+
0.9.4
Grandia 3 SLUS 21334 UPS2Ingame +
+
0.9.4
Grandia II SLUS 20194 UPS2Ingame +
+
0.9.4
Grandia III SLPM 65976 JPS2Ingame +
+
0.9.4
Grandia Xtreme SLUS 20417 UPS2Playable +
+
0.9.4
Great Escape, The SLES 51315 EPS2Ingame +
+
0.9.2
Great Escape, The SLUS 20670 UPS2Ingame +
+
0.9.4
Greg Hastings Tournament Paintball Max'd SLUS 21539 UPS2Ingame +
+
0.9.4
Gretzky NHL 06 SCUS 97466 UPS2Ingame +
+
0.9.4
Grim Adventures Of Billy And Mandy SLUS 21451 UPS2Playable +
+
0.9.4
Grim Grimoire SLPS 25771 JPS2Playable +
+
0.9.4
Grim Grimoire SLUS 21604 UPS2Playable +
+
0.9.4
Growlanser - Heritage of War SLUS 21571 UPS2Playable +
+
0.9.4
Growlanser 3 - The Dual Darkness SLUS 20759 UPS2Ingame +
+
0.9.4
Growlanser Generation SLUS 20758 UPS2Intro +
+
0.9.4
GT Racers SLES 52602 EPS2Ingame +
+
0.9.2
GTC Africa SLES 50472 EPS2Playable +
+
0.9.2
Guilty Gear Isuka SLES 53284 EPS2Playable +
+
0.9.2
Guilty Gear X Plus "By Your Side" SLPM 64525 JPS2Playable +
+
0.9.2
Guilty Gear X2 Reload SLES 52967 EPS2Playable +
+
0.9.2
Guilty Gear X2 SLUS 20436 UPS2Playable +
+
0.9.4
Guilty Gear XX - Accent Core SLPM 66746 JPS2Playable +
+
0.9.4
Guilty Gear XX - Accent Core SLUS 21652 UPS2Playable +
+
0.9.4
Guilty Gear XX - Slash Midnight Carnival SLPM 66333 JPS2Playable +
+
0.9.4
Guilty Gear XX SLPS 25184 JPS2Playable +
+
0.9.4
Guitar Freak 3 & Drummania 2 SLPM 65011 JPS2Playable +
+
0.9.4
Guitar Freak 4 & Drummania 3 SLPM 65052 JPS2Playable +
+
0.9.4
Guitar Freak and Drummania - Masterpiece Silver SLPM 66484 JPS2Ingame +
+
0.9.4
Guitar Hero - Rocks The 80's SLUS 21586 UPS2Playable +
+
0.9.4
Guitar Hero II SLES 54442 EPS2Ingame +
+
0.9.2
Guitar Hero II SLUS 21447 UPS2Ingame +
+
0.9.4
Guitar Hero III - Legends Of Rock SLUS 21672 UPS2Intro +
+
0.9.4
Guitar Hero SLES 54132 EPS2Ingame +
+
0.9.2
Guitar Hero SLUS 21224 UPS2Ingame +
+
0.9.4
Gumball 3000 SLES 50984 EPS2Menus +
+
0.9.3
Gun SLUS 21139 UPS2Intro +
+
0.9.4
Gunbird 1 & 2 SLPM 62469 JPS2Playable +
+
0.9.2
Gunbird Special Edition SLES 53021 EPS2Playable +
+
0.9.2
Gundam - Journey To Jaburo SLUS 20175 UPS2Playable +
+
0.9.4
Gungrave Overdose SLUS 21020 UPS2Ingame +
+
0.9.4
Gungrave SLUS 20493 UPS2Playable +
+
0.9.4
Gungriffon Blaze SLUS 20080 UPS2Playable +
+
0.9.4
Guy Game, The SLUS 21074 UPS2Playable +
+
0.9.4
Habitrail Hamster Ball SLES 52749 EPS2Playable +
+
0.9.4
Half Life SLUS 20066 UPS2Playable +
+
0.9.4
Half-Life SLES 50504 EPS2Ingame +
+
0.9.2
Half-Life SLES 50505 GPS2Playable +
+
0.9.2
Hanjuku Hero 4 SLPM 65839 JPS2Ingame +
+
0.9.4
Hanjuku Hero vs 3D SLPM 65315 JPS2Ingame +
+
0.9.4
Happy Feet SLES 54421 EPS2Ingame +
+
0.9.4
Happy Feet SLUS 21455 UPS2Intro +
+
0.9.4
Hard Rock Casino SLUS 21102 UPS2Playable +
+
0.9.4
Harley Davidson SLUS 21573 UPS2Ingame +
+
0.9.4
Harry Potter And The Order Of The Phoenix SLUS 21619 UPS2Intro +
+
0.9.4
Harvest Fishing SLES 53282 EPS2Playable +
+
0.9.2
Harvest Moon - A Wonderful Life SLUS 21171 UPS2Ingame +
+
0.9.4
Harvest Moon - Save The Homeland SLUS 20251 UPS2Playable +
+
0.9.4
Haunted Mansion SLUS 20681 UPS2Intro +
+
0.9.4
Haunting Ground SLUS 21075 UPS2Playable +
+
0.9.4
Haven - Call of The King SLES 51209 EPS2Menus +
+
0.9.2
Haven - Call of The King SLUS 20517 UPS2Ingame +
+
0.9.4
Headhunter - Redemption SLUS 20817 UPS2Ingame +
+
0.9.4
Heatseeker SLUS 21570 UPS2Ingame +
+
0.9.4
Heavy Metal Thunder SLPM 66030 JPS2Ingame +
+
0.9.4
Herdy Gerdy SLES 50751 EPS2Intro +
+
0.9.4
Herdy Gerdy SLUS 20231 UPS2Ingame +
+
0.9.4
Heroes of Might and Magic - Quest for the Dragon Bone Staff SLUS 20158 UPS2Playable +
+
0.9.4
Hidden Invasion SLUS 20301 UPS2Ingame +
+
0.9.4
High Rollers Casino SLUS 21014 UPS2Playable +
+
0.9.4
Hisshou Pachinko Pachi-Slot Kouryoku Series Vol. 7 - Fever Powerful + Zero SLPS 25697PS2Ingame +
+
0.9.3
History Channel's Civil War - The Game - Great Battles SLUS 21474 UPS2Ingame +
+
0.9.4
Hitman - Blood Money SLUS 21108 UPS2Intro +
+
0.9.4
Hitman - Contracts SLUS 20882 UPS2Intro +
+
0.9.4
Hitman 2 - Silent Assassin SLES 50992 EPS2Ingame +
+
0.9.4
Hitman 2 - Silent Assassin SLUS 20374 UPS2Ingame +
+
0.9.4
Hobbit, The SLUS 20655 UPS2Playable +
+
0.9.4
Hokuto no Ken SLPM 66660 JPS2Ingame +
+
0.9.4
Homura SLPM 62685 JPS2Ingame +
+
0.9.2
Horsez SLUS 21563 UPS2Menus +
+
0.9.4
Hot Shots Golf - Fore! SCUS 97401 UPS2Ingame +
+
0.9.4
Hot Shots Golf 3 SCUS 97130 UPS2Menus +
+
0.9.4
Hot Shots Tennis SCUS 97610 UPS2Playable +
+
0.9.4
Hot Wheels - Beat That SLUS 21628 UPS2Playable +
+
0.9.4
Hot Wheels - Stunt Track Challenge SLUS 20954 UPS2Playable +
+
0.9.4
Hot Wheels Velocity X - Maximum Justice SLUS 20412 UPS2Ingame +
+
0.9.4
Hot Wheels World Race SLUS 20737 UPS2Nothing +
+
0.9.4
Hummer Badlands SLUS 21357 UPS2Ingame +
+
0.9.4
Hungry Ghosts SCPS 15046 JPS2Playable +
+
0.9.4
Hunter - The Reckoning Wayward SLUS 20511 UPS2Intro +
+
0.9.4
Hustle, The - Detroit Streets SLUS 21335 UPS2Playable +
+
0.9.4
I-Ninja SLUS 20705 UPS2Ingame +
+
0.9.4
Ice Age 2 - The Meltdown SLUS 21307 UPS2Intro +
+
0.9.4
Ico SCES 50760 EPS2Ingame +
+
0.9.4
Ico SCPS 11003 JPS2Ingame +
+
0.9.4
Ico SCUS 97113 UPS2Ingame +
+
0.9.4
IGPX SLUS 21430 UPS2Ingame +
+
0.9.4
IHRA Drag Racing - Sportsman Edition SLUS 21256 UPS2Ingame +
+
0.9.4
IHRA Motor Sports Drag Racing 2 SLUS 20586 UPS2Playable +
+
0.9.4
Ikusa Gami SLKA 25320 KPS2Intro +
+
0.9.4
In The Groove SLUS 21177 UPS2Playable +
+
0.9.4
Incredible Hulk, The - Ultimate Destruction SLUS 20941 UPS2Ingame +
+
0.9.4
Incredibles, The - Rise of The Underminers SLUS 21217 UPS2Ingame +
+
0.9.4
Indiana Jones and The Emporers Tomb SLUS 20508 UPS2Intro +
+
0.9.4
Indiana Jones und die Legende der Kaisergruft SLES 50838 GPS2Menus +
+
0.9.2
Indigo Prophecy SLUS 21196 UPS2Nothing +
+
0.9.4
IndyCar Series SLUS 20641 UPS2Ingame +
+
0.9.3
Inspector Gadget - Mad Robots Invasion SLES 51247 EPS2Playable +
+
0.9.4
International Track and Field PBPX 95201 EPS2Playable +
+
0.9.4
Inuyasha - Feudal Combat SLUS 21193 UPS2Intro +
+
0.9.4
Inuyasha: Secret of The Cursed Mask SLUS 20913 UPS2Playable +
+
0.9.4
IQ Remix Plus SCPS 11001 JPS2Playable +
+
0.9.4
Island Xtreme Stunts SLUS 20575 UPS2Ingame +
+
0.9.4
ISS Pro 2000 PBPX 95201 UPS2Ingame +
+
0.9.2
Itudaki Street Special SLPM 65797 JPS2Playable +
+
0.9.4
Jackass - The Game SLUS 21627 UPS2Ingame +
+
0.9.4
Jade Cocoon 2 SLES 50735 EPS2Playable +
+
0.9.3
Jade Cocoon 2 SLUS 20309 UPS2Playable +
+
0.9.4
Jak 1 - The Precursor Legacy SCUS 97124 UPS2Ingame +
+
0.9.4
Jak 2 SCUS 97265 UPS2Intro +
+
0.9.4
Jak 3 SCUS 97330 UPS2Intro +
+
0.9.4
Jak and Daxter: the Precursor Legacy SCES 50361 EPS2Intro +
+
0.9.2
Jak X Combat Racing SCUS 97429 UPS2Nothing +
+
0.9.4
James Bond 007 - Agent Under Fire SLUS 20265 UPS2Intro +
+
0.9.4
James Bond 007 - Everything or Nothing SLES 52005 EPS2Intro +
+
0.9.4
James Bond 007 - Everything or Nothing SLUS 20751 UPS2Ingame +
+
0.9.4
James Bond 007 - From Russia With Love SLUS 21282 UPS2Intro +
+
0.9.4
James Bond 007 - Nightfire SLUS 20579 UPS2Nothing +
+
0.9.4
James Bond 007 Nightfire SLES 51260 EPS2Ingame +
+
0.9.2
James Cameron's Dark Angel SLES 51333 EPS2Ingame +
+
0.9.2
James Pond - Codename Robocod SLES 53682 EPS2Playable +
+
0.9.4
Jaws Unleashed SLUS 21062 UPS2Intro +
+
0.9.4
Jeapordy SLUS 20789 UPS2Playable +
+
0.9.4
Jikkyou Powerful Pro Yakyuu 13 SLPM 66450 JPS2Playable +
+
0.9.2
Judge Dredd - Dredd VS Death SLUS 20869 UPS2Intro +
+
0.9.4
Juiced 2 - Hot Import Nights SLUS 21593 UPS2Ingame +
+
0.9.4
Juiced SLES 53044 EPS2Playable +
+
0.9.2
Juiced SLUS 20872 UPS2Ingame +
+
0.9.4
Jumanji SLES 54382 EPS2Playable +
+
0.9.4
Junior Board Games SLES 52776 EPS2Intro +
+
0.9.2
Just Cause SLUS 21436 UPS2Ingame +
+
0.9.4
Justice League Heroes SLUS 21304 UPS2Ingame +
+
0.9.4
K1 World Grand Prix SLUS 20682 UPS2Ingame +
+
0.9.4
Ka SCPS 11009 JPS2Ingame +
+
0.9.4
Kaena SLPS 25295 JPS2Playable +
+
0.9.2
Kamen Rider 555 SLPS 20329 JPS2Ingame +
+
0.9.2
Kamen Rider Blade SLPS 20402 JPS2Ingame +
+
0.9.2
Kao The Kangaroo - Round 2 SLUS 20296 UPS2Playable +
+
0.9.4
Karaoke Revolution - American Idol SLUS 21540 UPS2Menus +
+
0.9.4
Karaoke Revolution - Country SLUS 21329 UPS2Menus +
+
0.9.4
Karaoke Revolution - Love and Ballad SLPM 62382 JPS2Ingame +
+
0.9.4
Karaoke Revolution Party SLUS 21223 UPS2Menus +
+
0.9.4
Katamari Damacy SLPS 25360 JPS2Ingame +
+
0.9.4
Katamari Damacy SLUS 21008 UPS2Ingame +
+
0.9.4
Kelly Slater Pro Surfer SLUS 20334 UPS2Playable +
+
0.9.4
Kengo - Master of Bushido SLES 50114 EPS2Playable +
+
0.9.2
Kengo - Master of Bushido SLUS 20021 UPS2Playable +
+
0.9.4
Kengo 2 SLPS 25107 JPS2Nothing +
+
0.9.4
Kensetsu Juuki Kenka Battle - Buchigire Kongou!! SLPS 25004 JPS2Ingame +
+
0.9.4
Keroro Gunsou: MeroMero Battle Royale Z SLPS 25575 JPS2Intro +
+
0.9.2
Kessen 2 SLUS 20275 UPS2Playable +
+
0.9.4
Kessen 3 SLES 53121 GPS2Nothing +
+
0.9.2
Kessen 3 SLUS 21119 UPS2Playable +
+
0.9.4
Kessen SLUS 20098 UPS2Playable +
+
0.9.4
Kill Switch SLUS 20706 UPS2Nothing +
+
0.9.4
Killer 7 SLES 53366 EPS2Playable +
+
0.9.4
Killer 7 SLUS 21154 UPS2Playable +
+
0.9.4
Killzone SCUS 97402 UPS2Ingame +
+
0.9.4
Kinetica SCUS 97132 UPS2Nothing +
+
0.9.4
King Arthur SLUS 21046 UPS2Ingame +
+
0.9.4
King Kong SLES 53703 EPS2Intro +
+
0.9.4
King Kong SLUS 21311 UPS2Ingame +
+
0.9.4
King of Colosseum II SLPM 65602 JPS2Ingame +
+
0.9.4
King of Fighters - Maximum Impact SLUS 20923 UPS2Playable +
+
0.9.4
King of Fighters - Neowave SLPS 25525 JPS2Playable +
+
0.9.2
King of Fighters 2000 SLUS 20834 UPS2Playable +
+
0.9.2
King of Fighters 2001, The SLUS 20839 UPS2Playable +
+
0.9.2
King of Fighters 2006 SLUS 21365 UPS2Playable +
+
0.9.4
King of Fighters XI, The SLPS 25660 JPS2Playable +
+
0.9.4
King's Field - The Ancient City SLUS 20318 UPS2Playable +
+
0.9.4
King's Field 4 SLES 50920 EPS2Playable +
+
0.9.2
Kingdom Hearts - Final Mix SLPS 25198 JPS2Playable +
+
0.9.4
Kingdom Hearts II Final Mix SLPM 66675 JPS2Ingame +
+
0.9.4
Kingdom Hearts II SLES 54114 EPS2Ingame +
+
0.9.4
Kingdom Hearts II SLPM 66233 JPS2Ingame +
+
0.9.4
Kingdom Hearts II SLUS 21005 UPS2Ingame +
+
0.9.4
Kingdom Hearts SCES 50967 EPS2Playable +
+
0.9.2
Kingdom Hearts SCES 50968 FPS2Playable +
+
0.9.2
Kingdom Hearts SCES 50969 GPS2Playable +
+
0.9.2
Kingdom Hearts SLUS 20370 UPS2Playable +
+
0.9.4
Klonoa 2 - Lunatea's Veil SCES 50354 EPS2Playable +
+
0.9.4
Klonoa 2 - Lunatea's Veil SLUS 20151 UPS2Playable +
+
0.9.4
Knight Rider 2 SLES 52836 EPS2Playable +
+
0.9.4
Knight Rider SLES 51011 EPS2Playable +
+
0.9.4
Knights of the Temple II SLES 53645 EPS2Menus +
+
0.9.2
Knockout Kings 2002 SLUS 20369 UPS2Ingame +
+
0.9.4
Konohana 4 SLPM 65690 JPS2Playable +
+
0.9.2
Kunoichi SLPM 65447 JPS2Ingame +
+
0.9.4
Kuon SLPS 25329 JPS2Ingame +
+
0.9.4
Kuon SLUS 21007 UPS2Playable +
+
0.9.4
Kuri Kuri Mix SLES 50224 EPS2Playable +
+
0.9.4
Kya - Dark Lineage SLUS 20440 UPS2Intro +
+
0.9.4
L.A. Rush SLUS 21112 UPS2Ingame +
+
0.9.4
La Petite Princess - Twinkle Star Spirits SLPS 25534 JPS2Intro +
+
0.9.4
La Pucelle Tactics SLUS 20847 UPS2Playable +
+
0.9.4
Lake Masters EX SLES 50351 EPS2Playable +
+
0.9.4
Lara Croft Tomb Raider - The Angel of Darkness SLES 51227 EPS2Ingame +
+
0.9.4
Largo Winch SLES 51093 EPS2Nothing +
+
0.9.2
Last Blade 1 & 2 SLPS 25503 JPS2Intro +
+
0.9.4
Le Mans 24 Hours SLES 50131 EPS2Playable +
+
0.9.4
League Series Baseball SLES 51718 EPS2Playable +
+
0.9.2
Legaia 2 - Duel Saga SLUS 20414 UPS2Playable +
+
0.9.4
Legend Of Alon Dar SLUS 20045 UPS2Playable +
+
0.9.4
Legend of Kay, The SLES 52931 EPS2Menus +
+
0.9.2
Legend of Kay, The SLUS 21248 UPS2Ingame +
+
0.9.4
Legend of Spyro - A New Beginning SLUS 21372 UPS2Ingame +
+
0.9.4
Legend Of The Dragon SLUS 21612 UPS2Playable +
+
0.9.4
Legends Of Wrestling 2 SLUS 20507 UPS2Playable +
+
0.9.4
Legion - Legend of Excalibur SLUS 20048 UPS2Playable +
+
0.9.4
Lego Racers 2 SLUS 20042 UPS2Ingame +
+
0.9.4
Lego Soccer Mania SLUS 20456 UPS2Playable +
+
0.9.4
Lego Star Wars SLUS 21083 UPS2Ingame +
+
0.9.4
Leisure Suit Larry SLUS 20956 UPS2Playable +
+
0.9.4
Lemmings SCES 54145 EPS2Playable +
+
0.9.4
Lemony Snickets - A Series Of Unfortunate Events SLUS 21078 UPS2Intro +
+
0.9.4
Lethal Skies - Elite Pilot Team SW SLUS 20386 UPS2Playable +
+
0.9.4
Lethal Skies 2 SLUS 20735 UPS2Nothing +
+
0.9.4
Lifeline SLUS 20848 UPS2Intro +
+
0.9.4
London Racer - Police Madness SLES 53536 EPS2Playable +
+
0.9.4
London Racer 2 SLES 50955 EPS2Ingame +
+
0.9.2
Looney Tunes - Acme Arsenal SLUS 21636 UPS2Playable +
+
0.9.4
Looney Tunes - Back In Action SLUS 20853 UPS2Ingame +
+
0.9.4
Looney Tunes Back in Action SLES 51794 EPS2Ingame +
+
0.9.2
Looney Tunes Space Race SLES 50487 EPS2Playable +
+
0.9.4
Lord of the Rings - The Return of the King SLES 52017 EPS2Ingame +
+
0.9.4
Lord of the Rings - The Return of the King SLPM 65503 JPS2Ingame +
+
0.9.4
Lord of the Rings - The Two Towers SLES 51252 EPS2Ingame +
+
0.9.2
Lord of the Rings - The Two Towers SLPS 29004 JPS2Intro +
+
0.9.4
Lotus Challenge SLES 50230 EPS2Ingame +
+
0.9.2
Love Com - Punch de Court SLPM 66470 JPS2Playable +
+
0.9.4
Lowrider SLUS 20676 UPS2Ingame +
+
0.9.4
Lucinda Green's Equestrain Challenge SLUS 21401 UPS2Ingame +
+
0.9.4
Lumines Plus Puzzle Fusion SLUS 21553 UPS2Playable +
+
0.9.4
Lumines Plus SLES 54336 EPS2Playable +
+
0.9.4
Mace Griffin - Bounty Hunter SLUS 20505 UPS2Ingame +
+
0.9.4
Mad Maestro SLUS 20376 UPS2Playable +
+
0.9.4
Madagascar SLES 53226 EPS2Intro +
+
0.9.2
Madden NFL 2005 SLUS 21000 UPS2Ingame +
+
0.9.4
Madden NFL 2006 SLUS 21213 UPS2Ingame +
+
0.9.4
Madden NFL 2007 SLUS 21476 UPS2Ingame +
+
0.9.4
Madden NFL 2008 SLUS 21638 UPS2Ingame +
+
0.9.4
Made Men: Confessions Of The Family Blood SLUS 21587 UPS2Playable +
+
0.9.4
Mafia SLUS 20671 UPS2Nothing +
+
0.9.4
Magic Pengel - The Quest for Color SLUS 20593 UPS2Playable +
+
0.9.4
MAGIX Music Maker SLUS 20609 UPS2Intro +
+
0.9.4
Magna Carta - Tears of Blood SLUS 21221 UPS2Ingame +
+
0.9.4
Mahjong Party: Swim Suit Beauty SCAJ 10010 JPS2Playable +
+
0.9.4
Makai Kingdom SLUS 21170 UPS2Playable +
+
0.9.4
Malice SLES 52413 EPS2Ingame +
+
0.9.2
Malice SLUS 20358 UPS2Intro +
+
0.9.4
Manhunt 2 SLUS 21613 UPS2Ingame +
+
0.9.4
Manhunt SLUS 20827 UPS2Menus +
+
0.9.4
Marc Ecko's Getting Up - Contents Under Pressure SLUS 21032 UPS2Ingame +
+
0.9.4
Mark Of Kri SCUS 97140 UPS2Ingame +
+
0.9.4
Marvel - Ultimate Alliance SLUS 21374 UPS2Playable +
+
0.9.4
Marvel Nemesis - Rise of the Imperfects SLES 53585 EPS2Menus +
+
0.9.2
Marvel Nemesis - Rise of the Imperfects SLUS 21281 UPS2Menus +
+
0.9.4
Marvel vs Capcom 2 SLPM 62227 JPS2Playable +
+
0.9.4
Marvel vs Capcom 2 SLUS 20486 UPS2Playable +
+
0.9.4
Master Chess SLES 52295 EPS2Playable +
+
0.9.2
Masters of The Universe - He-Man - Defender of Grayskull SLES 53035 EPS2Menus +
+
0.9.2
Matching Maker SLPS 20469 JPS2Nothing +
+
0.9.4
Matrix, The - Path of Neo SLUS 21273 UPS2Ingame +
+
0.9.4
Matt Hoffman - Pro BMX 2 SLUS 20335 UPS2Playable +
+
0.9.4
Max Payne 2 - The Fall of Max Payne SLES 52336 EPS2Ingame +
+
0.9.2
Max Payne 2 - The Fall of Max Payne SLUS 20814 UPS2Intro +
+
0.9.4
Max Payne SLES 50325 EPS2Ingame +
+
0.9.2
Max Payne SLUS 20230 UPS2Playable +
+
0.9.4
Maximo - Ghosts To Glory SLUS 20017 UPS2Nothing +
+
0.9.4
Maximo Machine Monster no Yabou SLPM 65367 JPS2Ingame +
+
0.9.4
Maximo Vs Army of Zin SLUS 20722 UPS2Intro +
+
0.9.4
Maximo SLPM 62127 JPS2Ingame +
+
0.9.4
Medal Of Honor - European Assault SLUS 21199 UPS2Ingame +
+
0.9.4
Medal of Honor - Frontline SLUS 20368 UPS2Menus +
+
0.9.4
Medal Of Honor - Rising Sun SLES 51873 EPS2Ingame +
+
0.9.3
Medal Of Honor - Rising Sun SLUS 20753 UPS2Playable +
+
0.9.4
Medal Of Honor - Vanguard SLUS 21597 UPS2Ingame +
+
0.9.4
Meet The Robinsons SLUS 21453 UPS2Ingame +
+
0.9.4
Megaman Anniversary Collection SLUS 20833 UPS2Playable +
+
0.9.4
Megaman X - Command Mission SLUS 20903 UPS2Playable +
+
0.9.4
Megaman X Collection SLUS 21370 UPS2Playable +
+
0.9.4
Megaman X7 SLUS 20487 UPS2Intro +
+
0.9.2
Megaman X8 SLUS 20960 UPS2Playable +
+
0.9.4
Meiwaku Seijin - Panic Maker SLPM 65642 JPS2Playable +
+
0.9.4
Melty Blood - Act Cadenza - SLPM 66438 JPS2Playable +
+
0.9.4
Men In Black 2 - Alien Escape SLUS 20373 UPS2Intro +
+
0.9.4
Mercenaries - Playground of Destruction SLUS 20932 UPS2Intro +
+
0.9.4
Mercury Meltdown Remix SLES 54432 EPS2Playable +
+
0.9.4
Mercury Meltdown Remix SLUS 21548 UPS2Playable +
+
0.9.4
Metal Arms - Glitch In The System SLUS 20786 UPS2Nothing +
+
0.9.4
Metal Gear Sold 2, Document of SLES 82010 EPS2Ingame +
+
0.9.4
Metal Gear Sold 2, Document of SLUS 20543 UPS2Ingame +
+
0.9.4
Metal Gear Solid 2 - Sons of Liberty SLES 50383 EPS2Ingame +
+
0.9.3
Metal Gear Solid 2 - Sons of Liberty SLUS 20144 UPS2Ingame +
+
0.9.4
Metal Gear Solid 2 - Substance SLES 82009 EPS2Nothing +
+
0.9.4
Metal Gear Solid 2 - Substance SLUS 20554 UPS2Nothing +
+
0.9.4
Metal Gear Solid 3 - Snake Eater SLES 82013 EPS2Ingame +
+
0.9.4
Metal Gear Solid 3 - Snake Eater SLUS 20915 UPS2Ingame +
+
0.9.4
Metal Gear Solid 3 - Subsistence SLUS 21359 UPS2Nothing +
+
0.9.4
Metal Saga SLUS 21293 UPS2Playable +
+
0.9.4
Metal Slug 3 SLPS 25209 JPS2Playable +
+
0.9.2
Metal Slug 4 SLPS 25376 JPS2Playable +
+
0.9.4
Metal Slug 4 SLUS 20971 UPS2Playable +
+
0.9.4
Metal Slug 5 SLES 53383 EPS2Playable +
+
0.9.2
Metal Slug 5 SLPS 25495 JPS2Playable +
+
0.9.2
Metal Slug 5 SLUS 20990 UPS2Playable +
+
0.9.4
Metal Slug 6 SLPS 25674 JPS2Playable +
+
0.9.4
Metal Slug Anthology SLUS 21550 UPS2Playable +
+
0.9.4
Metal Slug SLPS 25650 JPS2Playable +
+
0.9.2
Metropolismania SLUS 20377 UPS2Playable +
+
0.9.4
Micro Machines V4 SLUS 21402 UPS2Intro +
+
0.9.4
Midnight Club 3 Dub Edition Remix SLUS 21355 UPS2Ingame +
+
0.9.4
Midnight Club 3 Dub Edition SLUS 21029 UPS2Ingame +
+
0.9.4
Midnight Club II SLES 51054 EPS2Menus +
+
0.9.3
Midnight Club II SLUS 20209 UPS2Ingame +
+
0.9.4
Midnight Club SLUS 20063 UPS2Playable +
+
0.9.4
Midway Arcade Treasures 2 SLUS 20997 UPS2Playable +
+
0.9.4
Midway Arcade Treasures 3 SLUS 21094 UPS2Menus +
+
0.9.4
Mike Tyson Heavy Weight Boxing SLES 50396 EPS2Ingame +
+
0.9.4
Minna Daisuki Katamari Damacy SLPS 25467 JPS2Ingame +
+
0.9.4
Minority Report - Everybody Runs SLUS 20331 UPS2Playable +
+
0.9.2
Mission Impossible - Operation Surma SLUS 20400 UPS2Ingame +
+
0.9.4
Mister Mosquito SLUS 20375 UPS2Ingame +
+
0.9.4
Mobile Light Force 2 SLUS 20608 UPS2Playable +
+
0.9.4
Mobile Suit Gundam - Encounters In Space SLUS 20740 UPS2Playable +
+
0.9.4
Mobile Suit Gundam - Gundam VS Zeta Gundam SLUS 20821 UPS2Playable +
+
0.9.4
Mobile Suit Gundam Seed - Never Ending Tomorrow SLUS 21140 UPS2Playable +
+
0.9.4
Mobile Suit Gundam Zeonic Front SLUS 20233 UPS2Playable +
+
0.9.4
Mojib-ribon SCPS 11033 JPS2Intro +
+
0.9.4
Mojo! SLES 52111 EPS2Ingame +
+
0.9.4
Monochrome SLPM 66195 JPS2Playable +
+
0.9.4
Monopoly Party SLUS 20348 UPS2Ingame +
+
0.9.4
Monster House SLES 54215 EPS2Ingame +
+
0.9.4
Monster House SLUS 21400 UPS2Intro +
+
0.9.4
Monster Hunter 2 SLPM 66280 JPS2Playable +
+
0.9.4
Monster Hunter G SLPM 65869 JPS2Playable +
+
0.9.4
Monster Hunter SLES 52707 EPS2Playable +
+
0.9.4
Monster Hunter SLUS 20896 UPS2Playable +
+
0.9.4
Monster Rancher 3 SLUS 20190 UPS2Playable +
+
0.9.4
Monster Rancher EVO SLUS 21330 UPS2Playable +
+
0.9.4
Monster Trux Extreme - Arena Edition SLES 52750 EPS2Playable +
+
0.9.4
Monster World Complete Collection SLPM 62760 JPS2Playable +
+
0.9.4
Monsters Inc SCUS 97123 UPS2Playable +
+
0.9.4
Mortal Kombat - Armageddon SLUS 21410 UPS2Playable +
+
0.9.4
Mortal Kombat - Deadly Alliance SLUS 20423 UPS2Playable +
+
0.9.2
Mortal Kombat - Deception SLES 52705 EPS2Ingame +
+
0.9.2
Mortal Kombat - Deception SLUS 20881 UPS2Playable +
+
0.9.4
Mortal Kombat - Shaolin Monks SLUS 21087 UPS2Menus +
+
0.9.4
Mortal Kombat 1 - Deception Premium Pack Bonus Disc SLUS 21081 UPS2Playable +
+
0.9.4
Motocross Mania 3 SLUS 21229 UPS2Ingame +
+
0.9.4
MotoGP 07 SLUS 21688 UPS2Nothing +
+
0.9.4
MotoGP 2 SLUS 20285 UPS2Ingame +
+
0.9.2
MotoGP 3 SCES 50982 EPS2Ingame +
+
0.9.2
MotoGP 4 SCES 52892 EPS2Ingame +
+
0.9.2
MotoGP 4 SLUS 21159 UPS2Playable +
+
0.9.4
MotoGP SCES 50034 EPS2Ingame +
+
0.9.2
Motorbike King SLES 52518 EPS2Playable +
+
0.9.2
Mouse Police, The SLES 52370 EPS2Playable +
+
0.9.2
MS Saga - A New Dawn SLUS 21270 UPS2Playable +
+
0.9.4
MTV Music Generator 3 SLUS 20861 UPS2Playable +
+
0.9.4
MTX Mototrax SLUS 20399 UPS2Intro +
+
0.9.4
Mummy Returns, The SLES 50510 EPS2Ingame +
+
0.9.2
Mummy Returns, The SLUS 20253 UPS2Ingame +
+
0.9.4
Muppets Party Cruise SLUS 20635 UPS2Intro +
+
0.9.4
Musashi Samurai Legend SLUS 20983 UPS2Intro +
+
0.9.4
Mushihimesama SLPM 66056 JPS2Playable +
+
0.9.2
MX 2002 SLUS 20072 UPS2Playable +
+
0.9.2
MX Unleashed SLUS 20767 UPS2Playable +
+
0.9.4
MX VS ATV Unleashed SLUS 21104 UPS2Playable +
+
0.9.4
My Street SCUS 97212 UPS2Intro +
+
0.9.4
Myst 3 - Exile SLUS 20434 UPS2Playable +
+
0.9.4
Mystic Heroes SLUS 20521 UPS2Menus +
+
0.9.4
Namco Museum - 50th Anniversary SLUS 20273 UPS2Playable +
+
0.9.4
Namco Museum SLUS 20273 UPS2Playable +
+
0.9.4
Namco X Capcom SLPS 25505 JPS2Playable +
+
0.9.2
Nano Breaker SLKA 25263 JPS2Ingame +
+
0.9.2
Nano Breaker SLUS 21010 UPS2Ingame +
+
0.9.4
Narc SLUS 20730 UPS2Intro +
+
0.9.4
Naruto - Narutimett Hero SLPS 25293 JPS2Ingame +
+
0.9.4
Naruto - Ultimate Ninja 2 SLUS 21575 UPS2Playable +
+
0.9.4
Naruto - Ultimate Ninja SLUS 21358 UPS2Ingame +
+
0.9.4
Naruto Uzumaki Chronicles SLUS 21498 UPS2Ingame +
+
0.9.4
Naruto Uzumaki Ninden SLPS 25542 JPS2Ingame +
+
0.9.4
Nascar - Dirt To Daytona SLPS 25026 UPS2Playable +
+
0.9.4
Nascar 08 SLUS 21639 UPS2Intro +
+
0.9.4
NASCAR 2001 SLUS 20101 UPS2Nothing +
+
0.9.2
Nascar 2006 - Total Team Control SLUS 21266 UPS2Ingame +
+
0.9.4
Nascar 2007 SLUS 21461 UPS2Ingame +
+
0.9.4
NASCAR Thunder 2002 SLUS 20266 UPS2Ingame +
+
0.9.2
Naval Ops - Warship Gunner SLUS 20663 UPS2Intro +
+
0.9.4
Naval Ops Commander SLUS 20871 UPS2Intro +
+
0.9.4
NBA Street 2 SLES 51481 EPS2Playable +
+
0.9.2
Nebula Echo Night SLPS 25314 JPS2Ingame +
+
0.9.4
Need For Speed - Carbon SLUS 21493 UPS2Menus +
+
0.9.4
Need For Speed - Hot Pursuit 2 SLES 50731 EPS2Ingame +
+
0.9.3
Need For Speed - Hot Pursuit 2 SLUS 20362 UPS2Ingame +
+
0.9.4
Need For Speed - Most Wanted Black Edition SLUS 21351 UPS2Ingame +
+
0.9.4
Need For Speed - Most Wanted SLES 53557 EPS2Ingame +
+
0.9.2
Need For Speed - Most Wanted SLUS 21267 UPS2Ingame +
+
0.9.4
Need For Speed Underground 2 SLES 52725 EPS2Ingame +
+
0.9.4
Need For Speed Underground 2 SLUS 21065 UPS2Menus +
+
0.9.4
Need For Speed Underground SLES 51967 EPS2Ingame +
+
0.9.3
Need For Speed Underground SLUS 20811 UPS2Nothing +
+
0.9.4
Neo Contra SLES 52510 EPS2Ingame +
+
0.9.4
Neo Contra SLUS 20961 UPS2Ingame +
+
0.9.4
Neon Genesis Evangelion - The Iron Maiden 2nd SLPM 65867 JPS2Playable +
+
0.9.2
Neopets - The Darkest Faerie SCUS 97367 UPS2Ingame +
+
0.9.4
NFL GameDay 2002 SCUS 97131 UPS2Ingame +
+
0.9.2
NFL Headcoach SLUS 21407 UPS2Ingame +
+
0.9.4
NFL Street 2 SLUS 21118 UPS2Intro +
+
0.9.4
NFL Street 3 SLUS 21482 UPS2Ingame +
+
0.9.4
NHL 2006 SLUS 21241 UPS2Ingame +
+
0.9.4
NHL 2007 SLUS 21458 UPS2Ingame +
+
0.9.4
NHL 2008 SLUS 21647 UPS2Intro +
+
0.9.4
NHL 2K6 SLUS 21234 UPS2Intro +
+
0.9.4
NHL 2K7 SLUS 21425 UPS2Intro +
+
0.9.4
NHL 2K8 SLUS 21632 UPS2Intro +
+
0.9.4
NHL Hitz 2003 SLUS 20438 UPS2Menus +
+
0.9.4
NHL Hitz Pro SLUS 20691 UPS2Ingame +
+
0.9.4
NHRA - Countdown To The Championship SLUS 21547 UPS2Menus +
+
0.9.4
NHRA Championship Drag Racing SLUS 21114 UPS2Playable +
+
0.9.4
Nicktoons - Battle For Volcano Island SLUS 21469 UPS2Ingame +
+
0.9.4
Nightmare Before Christmas - Oogie's Revenge SLPM 65739 JPS2Playable +
+
0.9.4
Nightmare Before Christmas - Oogie's Revenge SLUS 20860 UPS2Ingame +
+
0.9.4
Nightmare of Druaga - Fushigino Dungeon SLUS 21071 UPS2Playable +
+
0.9.4
Nightshade SLUS 20810 UPS2Nothing +
+
0.9.4
Ninja Assault SLUS 20492 UPS2Ingame +
+
0.9.4
Ninjabread Man SLES 53570 EPS2Ingame +
+
0.9.2
NRA Gun Club SLUS 21432 UPS2Menus +
+
0.9.4
NTRA Breeders Cup - World Thoroughbred Championship SLUS 21195 UPS2Intro +
+
0.9.4
Obscure 2 SLES 54782 EPS2Playable +
+
0.9.4
Obscure SLES 52738 EPS2Playable +
+
0.9.4
Obscure SLUS 20777 UPS2Playable +
+
0.9.4
Odin Sphere SLUS 21577 UPS2Playable +
+
0.9.4
Odin's Sphere SLPM 66474 JPS2Playable +
+
0.9.4
Off-Road Wide Open SLES 50232 EPS2Playable +
+
0.9.2
Okage - Shadow King SCUS 97129 UPS2Ingame +
+
0.9.2
Okami SLPM 66375 JPS2Ingame +
+
0.9.2
Okami SLUS 21115 UPS2Ingame +
+
0.9.4
One Piece - Grand Adventure SLUS 21435 UPS2Ingame +
+
0.9.4
One Piece - Grand Battle 3 SLPS 25315 JPS2Playable +
+
0.9.3
One Piece - Grand Battle SLUS 20975 UPS2Ingame +
+
0.9.4
One Piece - Pirates Carnival SLUS 21364 UPS2Ingame +
+
0.9.4
Oni PBPX 95201 UPS2Intro +
+
0.9.2
Oni SLES 50177 GPS2Ingame +
+
0.9.2
Onimusha - Blade Warriors SLUS 20710 UPS2Nothing +
+
0.9.4
Onimusha - Dawn of Dreams SLPM 66275 JPS2Playable +
+
0.9.3
Onimusha - Dawn of Dreams SLUS 21180 UPS2Ingame +
+
0.9.4
Onimusha - Warlords SLES 50247 EPS2Menus +
+
0.9.2
Onimusha 2 - Samurai's Destiny SLES 50978 EPS2Playable +
+
0.9.4
Onimusha 2 - Samurai's Destiny SLUS 20393 UPS2Playable +
+
0.9.4
Onimusha 3 - Demon Siege SLES 51914 EPS2Playable +
+
0.9.2
Onimusha 3 - Demon Siege SLUS 20694 UPS2Ingame +
+
0.9.4
Onimusha Buraiden SLPM 65411 JPS2Ingame +
+
0.9.4
Onimusha SLPM 65010 JPS2Ingame +
+
0.9.4
Onimusha SLUS 20018 UPS2Ingame +
+
0.9.4
Open Season SLUS 21467 UPS2Intro +
+
0.9.4
Operation Winback SLES 50155 EPS2Ingame +
+
0.9.2
Operative, The - No One Lives Forver SLUS 20028 UPS2Ingame +
+
0.9.4
Oretachi Geasen Zoku Sono 15: Akumajou Dracula SLPM 62729 JPS2Playable +
+
0.9.2
Orphen Scion Of Sorcery SLUS 20011 UPS2Nothing +
+
0.9.4
Otostaz SCPS 11024 JPS2Ingame +
+
0.9.4
Outlaw Golf 2 SLES 52965 EPS2Menus +
+
0.9.4
Outlaw Golf 2 SLUS 21030 UPS2Menus +
+
0.9.4
Outlaw Tennis SLUS 21190 UPS2Ingame +
+
0.9.4
Outlaw Volleyball Remix SLUS 21049 UPS2Ingame +
+
0.9.4
Outrun 2 SP SLPM 66628 JPS2Nothing +
+
0.9.4
Outrun 2006 - Coast 2 Coast SLUS 21274 UPS2Nothing +
+
0.9.4
Over the Hedge SLUS 21300 UPS2Intro +
+
0.9.4
Pac Man World 2 SLUS 20224 UPS2Playable +
+
0.9.4
Pac Man World 3 SLUS 21219 UPS2Ingame +
+
0.9.4
Pacman Fever SLUS 20197 UPS2Ingame +
+
0.9.4
Pacman World Rally SLUS 21328 UPS2Ingame +
+
0.9.4
Paparazzi SLES 53489 EPS2Playable +
+
0.9.2
Parappa The Rapper 2 SCES 50408 EPS2Playable +
+
0.9.4
Parappa The Rapper 2 SCUS 97167 UPS2Playable +
+
0.9.4
Paris-Dakar Rally SLES 50212 EPS2Menus +
+
0.9.2
Party Girls SLES 53406 EPS2Ingame +
+
0.9.4
PC Genjin SLPM 62418 JPS2Playable +
+
0.9.2
Peter Pan - The Legend Of Neverland SLES 50522 EPS2Ingame +
+
0.9.4
Phantasy Star Universe SLES 54308 EPS2Playable +
+
0.9.4
Phantasy Star Universe SLUS 21194 UPS2Ingame +
+
0.9.4
Phantom Brave SLES 52951 EPS2Playable +
+
0.9.2
Phantom Brave SLUS 20955 UPS2Playable +
+
0.9.4
Pinball Hall of Fame SLES 52863 EPS2Playable +
+
0.9.2
Pink Pong SLES 52519 EPS2Ingame +
+
0.9.4
Pipo Saru 2001 SCPS 11014 JPS2Intro +
+
0.9.4
Pirates - Legend of The Black Buccaneer SLUS 21478 UPS2Ingame +
+
0.9.4
Pirates - The Legend of Black Cat SLES 50680 EPS2Ingame +
+
0.9.2
Pirates - The Legend Of Black Kat SLUS 20365 UPS2Playable +
+
0.9.4
Pirates of the Caribbean - The Legend of Jack Sparrow SLES 54237 EPS2Ingame +
+
0.9.2
Pirates of The Caribbean - The Legend of Jack Sparrow SLUS 21110 UPS2Ingame +
+
0.9.4
Pitfall - The Lost Expedition SLUS 20408 UPS2Intro +
+
0.9.4
Pk - Out Of The Shadows SLUS 20478 UPS2Intro +
+
0.9.4
Play it Pinball SLES 51555 EPS2Playable +
+
0.9.4
Playboy: The Mansion SLUS 20988 UPS2Ingame +
+
0.9.4
Pochi to Nyaa SLPS 20323 JPS2Playable +
+
0.9.2
Polar Express SLUS 20989 UPS2Playable +
+
0.9.4
Police 24-7 SLES 50285 EPS2Ingame +
+
0.9.4
Pool Master SLES 50052 EPS2Ingame +
+
0.9.4
Pool Paradise SLES 52246 EPS2Playable +
+
0.9.2
Pool Paradise SLUS 20987 UPS2Ingame +
+
0.9.4
Pop'n Music 12 SLPM 66314 JPS2Playable +
+
0.9.4
Pop'n Music 14 - Forever SLPM 66742 JPS2Ingame +
+
0.9.4
Pop'n Taisen Puzzle-Dama Online SLPM 62464 JPS2Playable +
+
0.9.4
Portal Runner SLUS 20003 UPS2Ingame +
+
0.9.4
Power Rangers - Dino Thunder SLUS 20944 UPS2Playable +
+
0.9.4
Power Rangers - Super Legends SLUS 21679 UPS2Ingame +
+
0.9.4
Power Smash 2 SLPM 62236 JPS2Ingame +
+
0.9.2
Powerpuff Girls, The - Relish Rampage SLES 51134 EPS2Ingame +
+
0.9.2
PowerShot Pinball SLES 54084 EPS2Ingame +
+
0.9.2
Predator - Concrete Jungle SLUS 20875 UPS2Playable +
+
0.9.4
Primal SCES 51135 EPS2Ingame +
+
0.9.4
Primal SCUS 97142 UPS2Menus +
+
0.9.4
Prince of Persia - The Two Thrones SLES 53777 EPS2Ingame +
+
0.9.2
Prince of Persia - The Two Thrones SLUS 21287 UPS2Intro +
+
0.9.4
Prince of Persia - Warrior Within SLUS 21022 UPS2Menus +
+
0.9.4
Prince of Persia : Sands of Time SLES 51918 EPS2Ingame +
+
0.9.4
Pro Evolution Soccer 4 SLES 52760 EPS2Playable +
+
0.9.3
Pro Evolution Soccer 5 SLES 53544 EPS2Intro +
+
0.9.2
Pro Race Driver SLUS 20329 UPS2Playable +
+
0.9.4
Pro Rally 2002 SLES 50637 EPS2Playable +
+
0.9.2
Pro Stroke Golf - World Tour 2007 SLUS 21496 UPS2Ingame +
+
0.9.4
Project Altered Beast SLES 53024 EPS2Playable +
+
0.9.4
Project Eden SLES 50553 EPS2Playable +
+
0.9.2
Project Eden SLUS 20164 UPS2Intro +
+
0.9.4
Project Snowblind SLUS 21037 UPS2Menus +
+
0.9.4
Project Zero 3 - Shisei No Koe SLPS 25544 JPS2Menus +
+
0.9.4
Project Zero II - Akai Chou SLPS 25303 JPS2Menus +
+
0.9.2
Project Zero II - Crimson Butterfly SLES 52384 EPS2Menus +
+
0.9.2
Project Zero SLES 50821 EPS2Ingame +
+
0.9.2
Project Zero SLPS 25074 JPS2Ingame +
+
0.9.4
Pryzm - Chapter One - The Dark Unicorn SLES 50721 EPS2Playable +
+
0.9.2
Pryzm Chapter 1 - The Dark Unicorn SLUS 20172 UPS2Playable +
+
0.9.4
Psi-Ops - The Mindgate Conspiracy SLUS 20688 UPS2Ingame +
+
0.9.4
Psychonauts SLUS 21120 UPS2Playable +
+
0.9.4
Psyvariar Complete Edition SLPM 62139 JPS2Playable +
+
0.9.2
Psyvariar Revision SLPM 62371 JPS2Playable +
+
0.9.4
Pump It Up - Exceed SLUS 21131 UPS2Ingame +
+
0.9.4
Punisher, The SLUS 20864 UPS2Playable +
+
0.9.4
Puzzle Challenge - Crosswords and More SLUS 21339 UPS2Playable +
+
0.9.4
Q Ball - Billiards Master PBPX 95201 JPS2Playable +
+
0.9.4
Quake 3 - Revolution PBPX 95201 UPS2Intro +
+
0.9.4
R-type Final SLPS 25247 JPS2Playable +
+
0.9.4
R-Type Final SLUS 20780 UPS2Playable +
+
0.9.4
R: Racing Evolution SLUS 20721 UPS2Ingame +
+
0.9.4
R: Racing SLES 52309 EPS2Ingame +
+
0.9.4
Radiata Stories SLUS 21262 UPS2Nothing +
+
0.9.4
Radirgy Precious SLPM 66405 JPS2Playable +
+
0.9.4
Raiden III SLES 53829 EPS2Playable +
+
0.9.4
Raiden III SLUS 21465 UPS2Playable +
+
0.9.4
Rakugaki Onkoku SLPM 65097 JPS2Playable +
+
0.9.2
Rally Championship SLES 50763 EPS2Playable +
+
0.9.2
Rally Fusion SLUS 20361 UPS2Intro +
+
0.9.4
Rampage - Total Destruction SLUS 21323 UPS2Playable +
+
0.9.4
Ratatouille SLUS 21541 UPS2Ingame +
+
0.9.4
Ratchet - Deadlocked SCUS 97465 UPS2Ingame +
+
0.9.4
Ratchet And Clank 3 - Up Your Arsenal SCUS 97353 UPS2Ingame +
+
0.9.4
Raw Danger SLUS 21501 UPS2Nothing +
+
0.9.4
Rayman - Raving Rabbids SLUS 21576 UPS2Ingame +
+
0.9.4
Rayman 3 - Hoodlum Havoc SLUS 20601 UPS2Intro +
+
0.9.4
Rayman Arena SLUS 20272 UPS2Playable +
+
0.9.4
Rayman M SLES 50457 EPS2Playable +
+
0.9.4
Rayman Revolution SLUS 20138 UPS2Ingame +
+
0.9.4
RC Revenge Pro SLUS 20153 UPS2Menus +
+
0.9.4
Ready To Rumble - Round 2 SLUS 20054 UPS2Menus +
+
0.9.4
Real Fishing 3 SLUS 20555 UPS2Intro +
+
0.9.4
Rebel Raiders - Operation Nighthawk SLUS 21303 UPS2Playable +
+
0.9.4
Red Card Soccer 2003 SLUS 20354 UPS2Playable +
+
0.9.2
Red Dead Revolver SLUS 20500 UPS2Intro +
+
0.9.4
Red Faction 2 SLUS 20442 UPS2Ingame +
+
0.9.4
Red Faction II SLES 51133 EPS2Ingame +
+
0.9.2
Red Faction SLES 50279 GPS2Playable +
+
0.9.2
Red Faction SLUS 20073 UPS2Nothing +
+
0.9.4
Red Ninja - End of Honor SLUS 20714 UPS2Intro +
+
0.9.4
Red Star SLUS 20885 UPS2Ingame +
+
0.9.4
Reservoir Dogs SLUS 21479 UPS2Ingame +
+
0.9.4
Resident Evil - Code Veronica X SLES 50306 EPS2Ingame +
+
0.9.2
Resident Evil - Code Veronica X SLUS 20184 UPS2Playable +
+
0.9.4
Resident Evil 4 SLES 53702 EPS2Playable +
+
0.9.4
Resident Evil 4 SLUS 21134 UPS2Playable +
+
0.9.4
Resident Evil Dead Aim SLUS 20669 UPS2Playable +
+
0.9.4
Resident Evil Outbreak 2 SLUS 20984 UPS2Playable +
+
0.9.4
Resident Evil Outbreak SLUS 20765 UPS2Playable +
+
0.9.4
Resident Evil Survivor 2: Code Veronica SLES 50650 UPS2Playable +
+
0.9.4
Return To Castle Wolfenstein - Operation Resurrection SLUS 20297 UPS2Playable +
+
0.9.4
Rez SLPM 62101 JPS2Ingame +
+
0.9.4
Rez SLUS 20344 UPS2Ingame +
+
0.9.4
Ridge Racer 5 SCES 50000 EPS2Ingame +
+
0.9.3
Ridge Racer 5 SLUS 20002 UPS2Ingame +
+
0.9.4
Riding Spirits II SLES 52277 EPS2Playable +
+
0.9.3
Riding Spirits SLUS 20429 UPS2Playable +
+
0.9.4
Rig Racer 2 SLES 53572 EPS2Ingame +
+
0.9.2
Rimokokoron SCPS 11012 JPS2Nothing +
+
0.9.4
Ring Of Red SLUS 20145 UPS2Nothing +
+
0.9.4
Rise of the Kasai SCUS 97416 UPS2Ingame +
+
0.9.4
Rise To Honor SCUS 97279 UPS2Playable +
+
0.9.4
Risk - Global Domination SLUS 20390 UPS2Playable +
+
0.9.4
River King - A Wonderful Journey SLUS 21275 UPS2Playable +
+
0.9.4
Roadkill SLUS 20687 UPS2Playable +
+
0.9.4
Robin Hood - Defender Of The Crown SLES 51946 EPS2Intro +
+
0.9.4
Robocop SLES 51374 EPS2Playable +
+
0.9.4
Robot Alchemic Drive SLUS 20445 UPS2Playable +
+
0.9.4
Robotech Invasion SLUS 20823 UPS2Intro +
+
0.9.4
Robots SLUS 20942 UPS2Menus +
+
0.9.4
Rocket Power Beach Bandits SLUS 20473 UPS2Nothing +
+
0.9.4
Rockman 7 SLES 51885 EPS2Playable +
+
0.9.2
Rocky Legends SLES 52761 EPS2Playable +
+
0.9.2
Rocky Legends SLUS 20890 UPS2Ingame +
+
0.9.4
Rocky SLUS 20559 UPS2Menus +
+
0.9.4
Rogue Galaxy SCUS 97490 UPS2Ingame +
+
0.9.4
Rogue Trooper SLUS 21320 UPS2Intro +
+
0.9.4
Roland Garros 2005 SCES 53310 EPS2Ingame +
+
0.9.4
Romance of The Three Kingdoms IX SLUS 20879 UPS2Intro +
+
0.9.4
Romance of The Three Kingdoms VII SLUS 20720 UPS2Playable +
+
0.9.4
Romance of The Three Kingdoms X SLUS 21202 UPS2Intro +
+
0.9.4
Romance Of The Tree Kingdoms XI SLUS 21584 UPS2Playable +
+
0.9.4
Romancing Saga SLUS 21263 UPS2Menus +
+
0.9.4
RPG Maker 3 SLUS 21178 UPS2Playable +
+
0.9.4
RPM Tuning SLES 52190 EPS2Intro +
+
0.9.2
RTX Red Rock SLES 51071 EPS2Ingame +
+
0.9.2
Ruff Trigger - The Vanocore Conspiracy SLUS 21314 UPS2Nothing +
+
0.9.4
Rule of Rose SCPS 15093 JPS2Ingame +
+
0.9.4
Rule of Rose SLUS 21448 UPS2Menus +
+
0.9.4
Rumble Fish, The SLPM 65919 JPS2Playable +
+
0.9.4
Rumble Racing SLES 50120 EPS2Ingame +
+
0.9.4
Rumble Roses SLES 52535 EPS2Playable +
+
0.9.2
Rumble Roses SLUS 20970 UPS2Playable +
+
0.9.4
Run Like Hell SLUS 20037 UPS2Playable +
+
0.9.4
Rune - Viking Warlord SLUS 20109 UPS2Ingame +
+
0.9.4
Rygar - Legendary Adventure SLUS 20471 UPS2Ingame +
+
0.9.4
Saikyou Toudai Shogi Special SLPS 20161 JPS2Playable +
+
0.9.2
Saint Seiya Chapter Sanctuary SLES 53201 EPS2Playable +
+
0.9.2
Samurai Champloo - Sidetracked SLUS 21343 UPS2Playable +
+
0.9.4
Samurai Jack - The Shadow Of Aku SLUS 20899 UPS2Intro +
+
0.9.4
Samurai Showdown V SLES 53059 EPS2Playable +
+
0.9.4
Samurai Spirits Tenkaichi Kenkakuten SLPS 25559 JPS2Playable +
+
0.9.4
Samurai Warriors 2 SLUS 21462 UPS2Playable +
+
0.9.4
Samurai Warriors Xtreme Legends SLUS 21080 UPS2Playable +
+
0.9.2
Samurai Warriors SLUS 20878 UPS2Playable +
+
0.9.4
Samurai Western SLES 53234 EPS2Playable +
+
0.9.2
Samurai Western SLUS 21187 UPS2Playable +
+
0.9.4
Sanyo Pachinko Paradise 14 SLPS 25787 JPS2Nothing +
+
0.9.4
Saru Gechu 2 SCPS 15025 JPS2Ingame +
+
0.9.4
Savage Skies SLUS 20430 UPS2Menus +
+
0.9.4
Scaler SLES 52917 EPS2Ingame +
+
0.9.4
Scaler SLUS 20957 UPS2Ingame +
+
0.9.4
Scarface - The World Is Yours SLUS 21111 UPS2Ingame +
+
0.9.4
School Rumble 2 SLPS 25669 JPS2Playable +
+
0.9.4
Scooby Doo - Night Of 100 Frights SLUS 20349 UPS2Playable +
+
0.9.4
Scooby Doo - Unmasked SLUS 21091 UPS2Intro +
+
0.9.4
Scorpion King - Rise of the Akkadian SLUS 20424 UPS2Playable +
+
0.9.4
Second Sight SLES 52670 EPS2Ingame +
+
0.9.2
Second Sight SLUS 21033 UPS2Playable +
+
0.9.4
Secret Weapons Over Normandy SLUS 20762 UPS2Intro +
+
0.9.4
Seek And Destroy SLUS 20606 UPS2Playable +
+
0.9.4
SEGA Ages 2500 - Vol. 11 - Fist of the North Star SLPM 62462 JPS2Intro +
+
0.9.2
Sega Ages 2500 Volume 01 - Phantasy Star generation:1 SLPM 62362 JPS2Playable +
+
0.9.2
Sega Ages 2500 Volume 03 - Fantasy Zone SLPM 62366 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 05 - Golden Axe SLPM 62385 JPS2Playable +
+
0.9.2
Sega Ages 2500 Volume 06 - Bonanza Bros SLPM 62433 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 07 - Columns SLPM 62425 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 08 - Virtua Racing - Flat Out SLPM 62443 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 09 - Gain Ground SLPM 62445 JPS2Playable +
+
0.9.2
Sega Ages 2500 Volume 10 - After Burner II SLPM 62446 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 16 - Virtua Fighter 2 SLPM 62547 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 17 - Phantasy Star Generation 2 SLPM 62553 JPS2Playable +
+
0.9.4
Sega Ages 2500 Volume 20 - Space Harrier SLPM 62691 JPS2Menus +
+
0.9.2
Sega Bass Fishing Duel SLUS 20339 UPS2Playable +
+
0.9.4
Sega Classics Collection SLES 53461 EPS2Ingame +
+
0.9.4
Sega Classics Collection SLUS 21009 UPS2Playable +
+
0.9.4
Sega Genesis Collection SLUS 21542 UPS2Playable +
+
0.9.4
Sega Rally 2006 SLPM 66212 JPS2Playable +
+
0.9.2
Sega Rally 95 SLPM 62703 JPS2Nothing +
+
0.9.4
Sega Soccer Slam SLUS 20509 UPS2Ingame +
+
0.9.4
Sega Sports Tennis SLUS 20480 UPS2Playable +
+
0.9.4
Seitoushi Seiya Seiiki Juunikyuu Hen SLPS 25476 JPS2Playable +
+
0.9.4
Sengoku Basara 2 SLPM 66447 JPS2Playable +
+
0.9.2
Sensible Soccer 2006 SLES 53810 UPS2Ingame +
+
0.9.2
Serious Sam - Next Encounter SLUS 20907 UPS2Playable +
+
0.9.4
Seven - Molmorth no Kiheitai SLPS 25025 JPS2Intro +
+
0.9.4
Seven Samurai SLUS 20621 UPS2Playable +
+
0.9.4
Shadow Hearts - Covenant SLUS 21041 UPS2Nothing +
+
0.9.4
Shadow Hearts - From The New World SLPM 66071 JPS2Ingame +
+
0.9.2
Shadow Hearts - From The New World SLUS 21326 UPS2Ingame +
+
0.9.4
Shadow Hearts SLES 50677 EPS2Playable +
+
0.9.4
Shadow Hearts SLUS 20347 UPS2Playable +
+
0.9.4
Shadow Of Destiny SLUS 20146 UPS2Ingame +
+
0.9.4
Shadow of Memories SLPM 65013 JPS2Ingame +
+
0.9.4
Shadow of Rome SLUS 20902 UPS2Playable +
+
0.9.4
Shadow of The Colossus SCES 53326 EPS2Ingame +
+
0.9.2
Shadow of The Colossus SCUS 97472 UPS2Ingame +
+
0.9.4
Shadow The Hedgehog SLUS 21261 UPS2Ingame +
+
0.9.4
Shadow Tower Abyss SLPS 25217 JPS2Ingame +
+
0.9.2
Shadowman - 2econd Coming SLUS 20413 UPS2Intro +
+
0.9.4
Shadowman - The Second Coming SLES 50446 EPS2Menus +
+
0.9.4
Shaman King - Power Of Spirit SLUS 20953 UPS2Playable +
+
0.9.4
Shark Tales SLUS 20925 UPS2Intro +
+
0.9.4
Shellshock Nam '67 SLUS 20828 UPS2Ingame +
+
0.9.4
Shield, The SLUS 21040 UPS2Playable +
+
0.9.4
Shikigami no Shiro 2 SLPM 62461 JPS2Ingame +
+
0.9.4
Shikigami no Shiro Nanayozuki Genshou Kyoku SLPM 66069 JPS2Playable +
+
0.9.4
Shikigami no Shiro SLPM 62165 JPS2Playable +
+
0.9.2
Shin Megami Tensei - Devil Summoner SLUS 21431 UPS2Playable +
+
0.9.4
Shin Megami Tensei - Digital Devil Saga 2 SLUS 21152 UPS2Ingame +
+
0.9.4
Shin Megami Tensei - Digital Devil Saga SLES 53458 EPS2Playable +
+
0.9.2
Shin Megami Tensei - Digital Devil Saga SLUS 20974 UPS2Ingame +
+
0.9.4
Shin Megami Tensei - Nocturne SLUS 20911 UPS2Playable +
+
0.9.4
Shin Megami Tensei - Persona 3 SLMP 66445 JPS2Playable +
+
0.9.4
Shin Megami Tensei - Persona 3 SLUS 21569 UPS2Playable +
+
0.9.4
Shin Sangoku Musou 2 SLPM 65053 JPS2Playable +
+
0.9.2
Shining Force EXA SLUS 21567 UPS2Ingame +
+
0.9.4
Shining Force Neo SLUS 21206 UPS2Playable +
+
0.9.4
Shining Tears SLUS 21063 UPS2Playable +
+
0.9.4
Shinobi SLUS 20459 UPS2Nothing +
+
0.9.4
Shinobido - Way of The Ninja SCES 53931 EPS2Playable +
+
0.9.4
Shougi, The SLPM 62180 JPS2Playable +
+
0.9.2
Shox SLES 51144 EPS2Ingame +
+
0.9.3
Shox SLES 51250 EPS2Intro +
+
0.9.2
Shrek 2 SLUS 20745 UPS2Playable +
+
0.9.4
Shrek Smash N Crash Racing SLUS 21392 UPS2Intro +
+
0.9.4
Shrek Super Party SLUS 20516 UPS2Ingame +
+
0.9.4
Shrek Superslam SLUS 21197 UPS2Intro +
+
0.9.4
Shrek The Third SLUS 21454 UPS2Menus +
+
0.9.4
Sidewinder V SLPS 25271 JPS2Ingame +
+
0.9.3
Silent Hill 2 - Saigo no Uta SLPM 65098 JPS2Nothing +
+
0.9.2
Silent Hill 2 SLPM 65051 JPS2Nothing +
+
0.9.2
Silent Hill 3 SLPM 65257 JPS2Nothing +
+
0.9.2
Silent Hill 3 SLUS 20622 UPS2Ingame +
+
0.9.4
Silent Hill 4 - The Room SLES 52445 EPS2Playable +
+
0.9.4
Silent Hill 4 - The Room SLPM 65574 JPS2Ingame +
+
0.9.2
Silent Hill 4 - The Room SLUS 20873 UPS2Playable +
+
0.9.4
Silent Line - Armored Core SLES 52203 EPS2Playable +
+
0.9.2
Silent Scope 2 SLUS 20243 UPS2Nothing +
+
0.9.4
Silpheed - The Lost Planet SLES 50193 EPS2Playable +
+
0.9.2
Silpheed - The Lost Planet SLUS 20085 UPS2Playable +
+
0.9.4
Silpheed the Lost Planet SLPM 62015 JPS2Playable +
+
0.9.2
Simple 2000 Series - Vol. 81 - The Chikyuu Boueigun 2 SLPM 62652 JPS2Nothing +
+
0.9.4
Simple 2000 Series - Vol.69 - The Board Games Collection SLPM 62580 JPS2Playable +
+
0.9.2
Simple 2000 Series ULTIMATE - Vol. 22: Stylish Mahjongg SLPM 62571 JPS2Playable +
+
0.9.2
Simple Series 2000 - Vol. 116 - The Neko Mura no Ninnin SLPS 20493 JPS2Ingame +
+
0.9.4
Simple Series 2000 - Vol. 16 - The Sniper 2 SLPM 62459 JPS2Playable +
+
0.9.2
Simple Series 2000 - Vol. 55 - The Catfight - Joneko Densetsu SLPM 62494 JPS2Ingame +
+
0.9.4
Simple Series 2000 - Vol. 59 - The Uchuujin to Hanashi Sou! SLPM 62524 JPS2Playable +
+
0.9.2
Simple Series 2000 - Vol. 60 - The Tokusatsu Henshin Hero SLPM 62510 JPS2Ingame +
+
0.9.2
Simple Series 2000 - Vol. 61 - The Oane Chapara SLPM 62525 JPS2Ingame +
+
0.9.4
Simple Series 2000 - Vol. 63 - The Suieitaikai SLPM 62534 JPS2Ingame +
+
0.9.4
Simple Series 2000 - Vol. 64 - The Splatter Action SLPM 62545 JPS2Menus +
+
0.9.2
Simple Series 2000 - Vol. 91 - The ALL STAR Fighting SLPS 20430 JPS2Intro +
+
0.9.4
Simple Series 2000 - Vol. 99 - The Genshijin SLPS 20461 JPS2Nothing +
+
0.9.4
Simple Series 2000 - Vol.106 - The Block Kuzushi Quest SLPS 20468 JPS2Playable +
+
0.9.4
Simply... The Best For Less - Vol. 6 Ultimate Casino SLES 52515 EPS2Ingame +
+
0.9.3
Simpsons Hit & Run, The SLES 51897 EPS2Playable +
+
0.9.4
Simpsons Hit & Run, The SLUS 20624 UPS2Intro +
+
0.9.4
Simpsons Road Rage, The SLUS 20305 UPS2Ingame +
+
0.9.4
Simpsons Skateboarding SLUS 20114 UPS2Playable +
+
0.9.4
Sims - Bustin' Out, The SLUS 20842 UPS2Intro +
+
0.9.4
Sims - The Urbz, The SLES 52908 EPS2Playable +
+
0.9.2
Sims 2 - Castaway SLUS 21664 UPS2Nothing +
+
0.9.4
Sims 2 - Pets SLUS 21536 UPS2Nothing +
+
0.9.4
Sims 2 SLUS 21265 UPS2Ingame +
+
0.9.4
Sims Bustin Out, The SLES 52047 EPS2Playable +
+
0.9.2
Sims SLUS 20573 UPS2Intro +
+
0.9.4
Singstar 80's SCUS 97616 UPS2Menus +
+
0.9.4
Singstar Amped SCUS 97611 UPS2Menus +
+
0.9.4
Singstar Anthems SCES 54131 EPS2Menus +
+
0.9.2
Singstar Rocks SCUS 97571 UPS2Menus +
+
0.9.4
Siren 2 SCPS 15106 JPS2Ingame +
+
0.9.4
Siren SCPS 15053 JPS2Ingame +
+
0.9.4
Siren SCUS 97355 UPS2Playable +
+
0.9.4
Ski Doo Snow X Racing SLUS 21591 UPS2Intro +
+
0.9.4
Sky Odyssey SLUS 20134 UPS2Playable +
+
0.9.4
Skygunner SCPS 11006 JPS2Ingame +
+
0.9.2
Skygunner SLUS 20384 UPS2Playable +
+
0.9.4
Sled Storm SLUS 20363 UPS2Playable +
+
0.9.4
Slotter Up Core 4 SLPS 20378 JPS2Playable +
+
0.9.4
Sly 2 - Band of Thieves SCES 52529 EPS2Ingame +
+
0.9.2
Sly 2 - Band of Thieves SCUS 97316 UPS2Menus +
+
0.9.4
Sly 3 - Honor Among Thieves SCUS 97464 UPS2Ingame +
+
0.9.4
Sly Cooper And The Thievious Raccoonus SCUS 97198 UPS2Playable +
+
0.9.4
Smackdown - Here Comes The Pain SLUS 20787 UPS2Playable +
+
0.9.4
Smackdown - Just Bring It SLUS 20316 UPS2Playable +
+
0.9.4
Smackdown - Shut Your Mouth SLUS 20483 UPS2Ingame +
+
0.9.4
Smash Court Tennis Pro - Tournament 2 SLUS 20933 UPS2Ingame +
+
0.9.4
Smuggler's Run SLES 50061 EPS2Playable +
+
0.9.2
Smugglers Run 2 SLUS 20204 UPS2Menus +
+
0.9.4
Smugglers Run SLUS 2065 UPS2Playable +
+
0.9.4
Sniper 2, the SLES 51623 EPS2Playable +
+
0.9.3
Sniper Elite SLUS 21231 UPS2Ingame +
+
0.9.4
SNK vs Capcom - SVC Chaos SLES 53065 EPS2Ingame +
+
0.9.4
SNK vs Capcom - SVC Chaos SLPS 25316 JPS2Playable +
+
0.9.3
SnoCross 2 - Featuring Blair Morgan SLUS 21130 UPS2Ingame +
+
0.9.4
Snoopy Vs The Red Baron SLUS 21380 UPS2Ingame +
+
0.9.4
Socom - US Navy Seals 2 SCUS 97275 UPS2Ingame +
+
0.9.4
Socom - US Navy Seals 3 SCUS 97474 UPS2Ingame +
+
0.9.4
Socom US Navy Seals - Combined Assault SCES 54477 EPS2Ingame +
+
0.9.4
Socom US Navy Seals - Combined Assault SCUS 97545 UPS2Ingame +
+
0.9.4
Sol Divide SLES 53873 EPS2Ingame +
+
0.9.4
Soldier of Fortune 2 SLUS 20084 UPS2Ingame +
+
0.9.3
Sonic Gems Collection SLES 53350 EPS2Playable +
+
0.9.2
Sonic Gems Collection SLPM 66074 JPS2Playable +
+
0.9.4
Sonic Heroes SLUS 20718 UPS2Intro +
+
0.9.4
Sonic Mega Collection Plus SLES 52998 EPS2Playable +
+
0.9.2
Sonic Mega Collection SLUS 20917 UPS2Playable +
+
0.9.4
Sonic Riders SLES 53560 EPS2Playable +
+
0.9.4
Sonic Riders SLUS 21331 UPS2Playable +
+
0.9.4
Sopranos - Road To Respect SLUS 21388 UPS2Ingame +
+
0.9.4
Soul Calibur II SLES 51799 EPS2Menus +
+
0.9.4
Soul Calibur II SLPS 25230 JPS2Ingame +
+
0.9.2
Soul Calibur II SLUS 20643 UPS2Ingame +
+
0.9.4
Soul Calibur III SCES 53312 EPS2Ingame +
+
0.9.4
Soul Calibur III SLPS 25577 JPS2Intro +
+
0.9.2
Soul Calibur III SLUS 21216 UPS2Intro +
+
0.9.4
Soul Nomad SLUS 21603 UPS2Ingame +
+
0.9.4
Space Channel 5 - Special Edition SLUS 20806 UPS2Playable +
+
0.9.4
Space Channel 5 Part 2 SLPM 65096 JPS2Playable +
+
0.9.2
Space Fishermen SCPS 11025 JPS2Ingame +
+
0.9.2
Space Invaders - Invasion Day SLES 51746 EPS2Playable +
+
0.9.2
Spartan - Total Warrior SLUS 21212 UPS2Ingame +
+
0.9.4
Spawn - Armageddon SLUS 20707 UPS2Playable +
+
0.9.4
Speed Kings SLUS 20584 UPS2Intro +
+
0.9.4
Sphinx And The Cursed Mummy SLUS 20482 UPS2Playable +
+
0.9.4
Spider-Man SLES 50814 GPS2Playable +
+
0.9.2
Spiderman - Friend Or Foe SLUS 21600 UPS2Menus +
+
0.9.4
Spiderman 2 SLUS 20776 UPS2Menus +
+
0.9.4
Spiderman 3 SLES 54723 EPS2Intro +
+
0.9.4
Spiderman 3 SLUS 21552 UPS2Intro +
+
0.9.4
Spiderman SLUS 20336 UPS2Ingame +
+
0.9.4
Splashdown - Rides Gone Wild SLUS 20686 UPS2Ingame +
+
0.9.4
Splashdown SLUS 20223 UPS2Menus +
+
0.9.4
Splinter Cell - Chaos Theory SLUS 21137 UPS2Ingame +
+
0.9.4
Splinter Cell - Double Agent SLUS 21356 UPS2Intro +
+
0.9.4
Splinter Cell - Pandora Tomorrow SLUS 20958 UPS2Ingame +
+
0.9.4
Splinter Cell SLUS 20652 UPS2Ingame +
+
0.9.4
Spongebob Schwammkopf - Schlacht um Bikini Bottom SLES 51970 GPS2Playable +
+
0.9.2
Spongebob Squarepants - Battle For Bikini Bottom SLUS 20680 UPS2Playable +
+
0.9.4
Spongebob Squarepants - Creature From The Krusty Krab SLUS 21391 UPS2Ingame +
+
0.9.4
Spongebob Squarepants - Revenge of the Flying Dutchman SLES 51285 EPS2Menus +
+
0.9.2
Spongebob Squarepants - Revenge of the Flying Dutchman SLUS 20425 UPS2Intro +
+
0.9.4
Spongebobs Atlantis Squarepantis SLUS 21644 UPS2Ingame +
+
0.9.4
Sprint Cars - The Road to Knoxville SLUS 21418 UPS2Ingame +
+
0.9.4
Spy Fiction SLUS 20856 UPS2Playable +
+
0.9.4
Spy Hunter - Nowhere To Run SLUS 21421 UPS2Ingame +
+
0.9.4
Spy Hunter 2 SLUS 20590 UPS2Intro +
+
0.9.4
Spy VS Spy SLES 53078 EPS2Ingame +
+
0.9.4
Spyro - A Hero's Tale SLES 52569 EPS2Playable +
+
0.9.2
Spyro - A Hero's Tale SLUS 20884 UPS2Playable +
+
0.9.4
Spyro - Enter The Dragonfly SLUS 20315 UPS2Intro +
+
0.9.4
Spyro - The Eternal Night SLUS 21607 UPS2Ingame +
+
0.9.4
SSX - On Tour SLUS 21278 UPS2Ingame +
+
0.9.4
SSX 3 SLUS 20772 UPS2Ingame +
+
0.9.4
SSX Tricky SLUS 20326 UPS2Playable +
+
0.9.4
SSX PBPX 95201 UPS2Playable +
+
0.9.4
Stacked SLUS 21259 UPS2Intro +
+
0.9.4
Star Ocean - Till the End of Time SLUS 20488 UPS2Nothing +
+
0.9.2
Star Trek - Elite Force SLPS 25026 UPS2Intro +
+
0.9.4
Star Trek - Encounters SLUS 21396 UPS2Playable +
+
0.9.4
Star Trek - Shattered Universe SLUS 20112 UPS2Playable +
+
0.9.4
Star Trek Voyager - Elite Force SLES 50738 EPS2Intro +
+
0.9.2
Star Wars - Battlefront 2 SLUS 21240 UPS2Ingame +
+
0.9.4
Star Wars - Bounty Hunter SLUS 20420 UPS2Playable +
+
0.9.4
Star Wars - Clone Wars SLUS 20510 UPS2Ingame +
+
0.9.4
Star Wars - Jedi Starfighter SLUS 20293 UPS2Playable +
+
0.9.4
Star Wars - Racer Revenge SLUS 20268 UPS2Ingame +
+
0.9.4
Star Wars - Starfighter SLUS 20044 UPS2Ingame +
+
0.9.4
Star Wars - Super Bombad Racing PBPX 95201 UPS2Ingame +
+
0.9.4
Star Wars Episode 3 - Revenge of the Sith SLES 53155 EPS2Ingame +
+
0.9.2
Star Wars Episode 3 - Revenge of The Sith SLUS 21143 UPS2Ingame +
+
0.9.4
Starsky & Hutch SLES 51783 EPS2Ingame +
+
0.9.2
State of Emergency 2 SLUS 20966 UPS2Ingame +
+
0.9.4
State of Emergency SLUS 20214 UPS2Playable +
+
0.9.4
Steambot Chronicles SLUS 21344 UPS2Nothing +
+
0.9.4
Steamboy SLPS 25502 JPS2Playable +
+
0.9.2
Steel Dragon EX SLES 52482 EPS2Playable +
+
0.9.4
Steel Lancer Arena International SLUS 20969 UPS2Playable +
+
0.9.4
Stella Deus SLUS 21132 UPS2Playable +
+
0.9.4
Stitch - Experiment 626 SCUS 97145 UPS2Playable +
+
0.9.4
Stock Car Crash SLES 53972 EPS2Ingame +
+
0.9.2
Stolen SLES 52882 EPS2Menus +
+
0.9.4
Stolen SLUS 21099 UPS2Ingame +
+
0.9.4
Street Fighter - Alpha Anthology SLUS 21317 UPS2Ingame +
+
0.9.4
Street Fighter EX3 PBPX 95201 UPS2Playable +
+
0.9.2
Street Fighter EX3 SLES 50072 EPS2Ingame +
+
0.9.4
Street Fighter EX3 SLUS 20130 UPS2Playable +
+
0.9.4
Street Fighter Zero - Fighters Generation SLPM 66409 JPS2Playable +
+
0.9.2
Street Racing Syndicate SLES 53045 EPS2Menus +
+
0.9.4
Street Racing Syndicate SLUS 20582 UPS2Nothing +
+
0.9.4
Strikers 1945 I & II SLPM 62515 JPS2Playable +
+
0.9.2
Strikers 1945 III SLKA 15005 JPS2Playable +
+
0.9.2
Stuntman - Ignition SLUS 21626 UPS2Intro +
+
0.9.4
Stuntman Ignition SLES 54820 EPS2Ingame +
+
0.9.4
Stuntman SLES 50288 EPS2Ingame +
+
0.9.2
Stuntman SLPS 25026 UPS2Ingame +
+
0.9.4
Suffering, The - Ties That Bind SLUS 21189 UPS2Ingame +
+
0.9.4
Suffering, The SLUS 20636 UPS2Ingame +
+
0.9.4
Suikoden III SLUS 20387 UPS2Playable +
+
0.9.4
Suikoden IV SLES 52913 EPS2Playable +
+
0.9.2
Suikoden IV SLUS 20979 UPS2Playable +
+
0.9.4
Suikoden Tactics SLUS 21245 UPS2Ingame +
+
0.9.4
Suikoden V SLUS 21291 UPS2Ingame +
+
0.9.4
Sum of All Fears, The SLES 51180 EPS2Playable +
+
0.9.2
Summer Heat Beach Volleyball SLES 51778 EPS2Ingame +
+
0.9.2
Summer Heat Beach Volleyball SLUS 20634 UPS2Playable +
+
0.9.4
Summoner 1 SLES 82005 GPS2Ingame +
+
0.9.2
Summoner 1 SLUS 20074 UPS2Ingame +
+
0.9.4
Summoner 2 SLES 51142 GPS2Playable +
+
0.9.2
Sunny Garcia Surfing SLUS 20208 UPS2Nothing +
+
0.9.4
Super Bust-A-Move 2 SLUS 20460 UPS2Intro +
+
0.9.4
Super Bust-A-Move PBPX 95201 UPS2Playable +
+
0.9.4
Super Bust-A-Move SLES 50076 EPS2Playable +
+
0.9.2
Super Bust-A-Move SLUS 20115 UPS2Playable +
+
0.9.2
Super Dimensional Fortress Macross SLPM 65405 JPS2Nothing +
+
0.9.4
Super Dragon Ball Z SLUS 21442 UPS2Playable +
+
0.9.4
Super Monkey Ball Adventure SLES 53701 EPS2Intro +
+
0.9.2
Super Monkey Ball Adventure SLUS 21272 UPS2Ingame +
+
0.9.4
Super Puzzle Bobble SLPM 62016 JPS2Playable +
+
0.9.2
Super Robot Wars 3 SLPS 25537 JPS2Playable +
+
0.9.4
Super Shanghai 2005 SLPM 62552 JPS2Playable +
+
0.9.2
Super Trucks SLES 50897 EPS2Ingame +
+
0.9.3
Superior Defender Gundam Force Showdown! SLUS 20698 UPS2Ingame +
+
0.9.2
Superman - Shadow of Apokolips SLUS 20235 UPS2Ingame +
+
0.9.4
Superman Returns SLUS 21434 UPS2Ingame +
+
0.9.4
Surfs Up SLUS 21572 UPS2Playable +
+
0.9.4
Suzuki TT Superbikes SLUS 20912 UPS2Ingame +
+
0.9.4
Sven Göran Eriksson's World Manager 2002 SLES 50794 EPS2Ingame +
+
0.9.4
SWAT - Global Strike Team SLES 52097 EPS2Ingame +
+
0.9.2
SWAT - Global Strike Team SLUS 20433 UPS2Ingame +
+
0.9.4
Swing Away Golf SLUS 20096 UPS2Intro +
+
0.9.4
Switch SLPM 65121 JPS2Playable +
+
0.9.2
Sword of Etheria SLES 53768 EPS2Ingame +
+
0.9.2
Sword of The Berserk - Gut's Rage SLPM 65688 JPS2Playable +
+
0.9.2
Swords of Destiny SLES 53699 EPS2Playable +
+
0.9.2
SX Superstars SLES 51495 EPS2Ingame +
+
0.9.2
Syberia SLES 51393 EPS2Ingame +
+
0.9.3
Syphon Filter - Dark Mirror SCUS 97362 UPS2Ingame +
+
0.9.4
Syphon Filter - The Omega Strain SCES 52033 GPS2Menus +
+
0.9.2
Syphon Filter - The Omega Strain SCUS 97264 UPS2Ingame +
+
0.9.4
Taiko no Tatsujin: Doki! Shinkyoku Darake no Haru Matsuri SLPS 20272 JPS2Playable +
+
0.9.4
Taisho Mononoke Ibunroku SLPM 65228 JPS2Playable +
+
0.9.4
Taito Legends SLES 53438 EPS2Playable +
+
0.9.2
Tak - The Great Juju Challenge SLUS 21218 UPS2Ingame +
+
0.9.4
Tales of Legendia SLPS 25533 JPS2Ingame +
+
0.9.4
Tales of Legendia SLUS 21201 UPS2Ingame +
+
0.9.4
Tales of The Abyss SLUS 21386 UPS2Playable +
+
0.9.4
TamTam Paradise SLPM 62073 JPS2Ingame +
+
0.9.2
Tarzan Untamed SLUS 20076 UPS2Nothing +
+
0.9.4
Taz Wanted SLES 50649 EPS2Intro +
+
0.9.4
TD overdrive - The Brotherhood Of Speed SLES 50778 EPS2Intro +
+
0.9.2
Technic Beat SLUS 21019 UPS2Playable +
+
0.9.4
Technictix SLPS 20055 JPS2Playable +
+
0.9.4
Teen Titans SLUS 21183 UPS2Menus +
+
0.9.4
Teenage Mutant Ninja Turtles 2 - Battle Nemesis SLUS 20981 UPS2Ingame +
+
0.9.4
Teenage Mutant Ninja Turtles SLES 51931 EPS2Playable +
+
0.9.2
Teenage Mutant Ninja Turtles SLUS 21595 UPS2Intro +
+
0.9.4
Tekken 4 SCES 50878 EPS2Playable +
+
0.9.4
Tekken 4 SLUS 20328 UPS2Playable +
+
0.9.4
Tekken 5 SCES 53202 EPS2Intro +
+
0.9.2
Tekken 5 SLPS 25510 JPS2Ingame +
+
0.9.4
Tekken 5 SLUS 21059 UPS2Ingame +
+
0.9.4
Tekken Tag Tournament PBPX 95201 UPS2Playable +
+
0.9.4
Tekken Tag Tournament SCES 50001 EPS2Ingame +
+
0.9.4
Tekken Tag Tournament SLPS 20015 JPS2Ingame +
+
0.9.2
Tenchu - Fatal Shadows SLUS 21129 UPS2Ingame +
+
0.9.4
Tenchu - Wrath of Heaven SLES 51402 GPS2Ingame +
+
0.9.3
Tenchu - Wrath of Heaven SLUS 20397 UPS2Ingame +
+
0.9.4
Tennis Court Smash SLES 51860 EPS2Menus +
+
0.9.2
Terminator 3 - Rise Of The Machines SLUS 20799 UPS2Ingame +
+
0.9.4
Terminator 3 - The Redemption SLUS 20852 UPS2Intro +
+
0.9.4
Terminator, The - Dawn Of Fate SLUS 20391 UPS2Ingame +
+
0.9.4
Test Drive - Eve of Destruction SLUS 20910 UPS2Menus +
+
0.9.4
Test Drive Offroad - Wide Open SLUS 20177 UPS2Playable +
+
0.9.4
Test Drive Unlimited SLES 54466 EPS2Intro +
+
0.9.4
Test Drive Unlimited SLUS 21490 UPS2Nothing +
+
0.9.4
Test Drive SLUS 20213 UPS2Intro +
+
0.9.4
Tetris Worlds SLUS 20247 UPS2Playable +
+
0.9.4
Th3 Plan SLUS 21466 UPS2Playable +
+
0.9.4
Theme Park - Rollercoaster SLUS 20099 UPS2Ingame +
+
0.9.4
Theme Park World SLES 50032 EPS2Playable +
+
0.9.4
Thing, The SLES 50975 EPS2Menus +
+
0.9.4
Thing, The SLUS 20371 UPS2Menus +
+
0.9.4
Thrillville - Off The Rails SLUS 21611 UPS2Intro +
+
0.9.4
Thrillville SLUS 21413 UPS2Menus +
+
0.9.4
Tiger Woods PGA Tour 2003 SLUS 20572 UPS2Ingame +
+
0.9.4
Tiger Woods PGA Tour 2005 SLUS 21002 UPS2Ingame +
+
0.9.4
Tiger Woods PGA Tour 2006 SLUS 21264 UPS2Intro +
+
0.9.4
Tiger Woods PGA Tour 2007 SLUS 21483 UPS2Intro +
+
0.9.4
Tiger Woods PGA Tour 2008 SLUS 21646 UPS2Ingame +
+
0.9.4
Time Crisis - Crisis Zone SLUS 20927 UPS2Playable +
+
0.9.4
Time Crisis 2 SLUS 20219 UPS2Nothing +
+
0.9.4
Time Crisis 3 SLUS 20645 UPS2Nothing +
+
0.9.4
Timesplitters 2 SLES 50877 EPS2Nothing +
+
0.9.2
Timesplitters 2 SLUS 20314 UPS2Playable +
+
0.9.4
Timesplitters 3 SLUS 21148 UPS2Ingame +
+
0.9.4
Timesplitters PBPX 95201 UPS2Playable +
+
0.9.4
Timesplitters SLES 50078 EPS2Playable +
+
0.9.2
Timesplitters SLUS 20090 UPS2Playable +
+
0.9.4
Toca Race Driver 2 SLUS 21039 UPS2Ingame +
+
0.9.4
Toca Race Driver 3 SLUS 21182 UPS2Ingame +
+
0.9.4
Tokimeki Memorial 3 SLPM 65080 JPS2Ingame +
+
0.9.4
Tokobot Plus - Mysteries Of The Karakuri SLUS 21471 UPS2Ingame +
+
0.9.4
Tokyo Bus Guide 2 SLPM 65982 UPS2Intro +
+
0.9.4
Tokyo Etreme Racer Zero SLUS 20189 UPS2Ingame +
+
0.9.4
Tokyo Extreme Racer 3 SLUS 20831 UPS2Ingame +
+
0.9.4
Tokyo Extreme Racer Drift 2 SLUS 21394 UPS2Playable +
+
0.9.4
Tokyo Extreme Racer Drift SLUS 21236 UPS2Ingame +
+
0.9.4
Tokyo Road Race SLES 50954 EPS2Ingame +
+
0.9.2
Tom And Jerry - War Of The Whiskers SLUS 20355 UPS2Ingame +
+
0.9.4
Tom Clancy's Rainbow Six - Lockdown SLUS 21144 UPS2Ingame +
+
0.9.4
Tom Clancy's Rainbow Six 3 SLUS20883 UPS2Playable +
+
0.9.4
Tom Clancy's Splinter Cell Chaos Theory SLES 53007 EPS2Ingame +
+
0.9.2
Tomb Raider - Angel of Darkness SLUS 20467 UPS2Nothing +
+
0.9.4
Tomb Raider Anniversary SLUS 21555 UPS2Ingame +
+
0.9.4
Tomb Raider Legend SLES 53908 EPS2Ingame +
+
0.9.2
Tomb Raider Legend SLUS 21203 UPS2Ingame +
+
0.9.4
Tony Hawk's American Wasteland SLUS 21208 UPS2Intro +
+
0.9.4
Tony Hawk's Pro Skater 3 SLUS 20013 UPS2Ingame +
+
0.9.4
Tony Hawk's Underground 2 SLUS 20965 UPS2Intro +
+
0.9.4
Tony Hawk's Underground SLES 51852 GPS2Intro +
+
0.9.2
Tony Hawks Downhill Jam SLUS 21456 UPS2Intro +
+
0.9.4
Tony Hawks Project 8 SLUS 21444 UPS2Intro +
+
0.9.4
Tony Hawks Proving Ground SLUS 21616 UPS2Intro +
+
0.9.4
Tony Hawks Underground SLUS 20731 UPS2Intro +
+
0.9.4
Top Spin SLUS 21222 UPS2Intro +
+
0.9.4
Torino 2006 SLES 53901 EPS2Ingame +
+
0.9.2
Total Immersion Racing SLES 51128 EPS2Playable +
+
0.9.2
Total Immersion Racing SLUS 20409 UPS2Ingame +
+
0.9.4
Total Overdose - A Gunslinger's Tale In Mexico SLUS 21283 UPS2Ingame +
+
0.9.4
Tourist Trophy - Real Riding Simulator SCAJ 20170 JPS2Intro +
+
0.9.2
Tourist Trophy SCUS 97502 UPS2Ingame +
+
0.9.4
Transformers - The Game SLES 54755 EPS2Ingame +
+
0.9.4
Transformers - The Game SLUS 21602 UPS2Ingame +
+
0.9.4
Transformers Tataki SLPM 65407 JPS2Ingame +
+
0.9.4
Transformers SLES 52388 EPS2Ingame +
+
0.9.2
Transformers SLUS 20668 UPS2Intro +
+
0.9.4
Transworld Surf SLUS 20356 UPS2Playable +
+
0.9.4
Trapt SLUS 21255 UPS2Ingame +
+
0.9.4
Tribes - Aerial Assault SLUS 20149 UPS2Playable +
+
0.9.4
Trigger Man SLUS 20931 UPS2Playable +
+
0.9.4
Trivial Pursuit Unhinged SLUS 20791 UPS2Intro +
+
0.9.4
True Crime - New York City SLUS 21106 UPS2Menus +
+
0.9.4
True Crimes - Streets Of L.A. SLUS 20550 UPS2Menus +
+
0.9.4
Tsugunai Atonement SLUS 20292 UPS2Ingame +
+
0.9.4
Tsukiyo Ni Saraba SLPM 65826 JPS2Ingame +
+
0.9.2
Turok - Evolution SLES 51124 GPS2Ingame +
+
0.9.3
Turok - Evolution SLUS 20333 UPS2Ingame +
+
0.9.4
TVDJ SCPS 15002 JPS2Ingame +
+
0.9.4
Twenty 2 Party SLES 53369 EPS2Playable +
+
0.9.4
Twin Caliber SLES 51226 EPS2Playable +
+
0.9.2
Twisted Metal - Black SCUS 97101 UPS2Ingame +
+
0.9.4
Ty The Tasmanian Tiger SLUS 20571 UPS2Intro +
+
0.9.4
Ty The Tazmanian Tiger 3 SLUS 21253 UPS2Ingame +
+
0.9.4
UEFA Champions League 2006-2007 SLUS 21581 UPS2Ingame +
+
0.9.4
UFC - Sudden Impact SLUS 20596 UPS2Ingame +
+
0.9.4
UFC Throwdown SLUS 20252 UPS2Ingame +
+
0.9.4
Ultimate Board Game Collection SLUS 21366 UPS2Nothing +
+
0.9.4
Ultimate Pro pinball SLES 53508 EPS2Ingame +
+
0.9.4
Ultimate Spiderman SLUS 20870 UPS2Ingame +
+
0.9.4
Under The Skin SLES 52719 EPS2Playable +
+
0.9.4
Unison SLPS 25010 JPS2Playable +
+
0.9.4
Unlimited Saga SLUS 20678 UPS2Ingame +
+
0.9.4
Unreal Tournament PBPX 95201 JPS2Intro +
+
0.9.4
Unreal Tournament SLES 50074 EPS2Playable +
+
0.9.2
Unrun Quest SLPM 66028 JPS2Ingame +
+
0.9.4
Urban Chaos - Riot Response SLUS 21390 UPS2Ingame +
+
0.9.4
Urban Reign SCES 53688 EPS2Ingame +
+
0.9.4
Urban Reign SLUS 21209 UPS2Ingame +
+
0.9.4
Urbz - Sims In The City SLUS 21066 UPS2Ingame +
+
0.9.4
V-Rally 3 SLES 50725 EPS2Ingame +
+
0.9.2
Valkyrie Profile 2 - Silmeria SLPM 66419 JPS2Nothing +
+
0.9.2
Valkyrie Profile 2 - Slimeria SLUS 21452 UPS2Nothing +
+
0.9.4
Vampire Darkstalkers Collection SLPM 65998 JPS2Ingame +
+
0.9.4
Vampire Night SCES 50411 EPS2Playable +
+
0.9.4
Vampire Night SLPS 25077 JPS2Playable +
+
0.9.2
Vampire Night SLUS 20221 UPS2Playable +
+
0.9.4
Van Helsing SLES 51908 EPS2Ingame +
+
0.9.4
Van Helsing SLUS 20738 UPS2Playable +
+
0.9.4
Venus & Braves SLPS 25195 JPS2Ingame +
+
0.9.2
Vexx SLES 50481 EPS2Menus +
+
0.9.2
Vexx SLUS 20383 UPS2Ingame +
+
0.9.4
Victorious Boxers - Ippo's Road To Victory SLUS 20282 UPS2Playable +
+
0.9.4
Victorious Boxers 2 - Fighting Spirits SLUS 21204 UPS2Playable +
+
0.9.4
Vietcong - Purple Haze SLUS 21068 UPS2Ingame +
+
0.9.4
Viewtiful Joe 2 SLPM 65824 JPS2Playable +
+
0.9.2
Viewtiful Joe SLPM 65699 JPS2Playable +
+
0.9.2
Viewtiful Joe SLUS 20951 UPS2Playable +
+
0.9.4
Virtua Cop Elite Edition SLES 51229 EPS2Playable +
+
0.9.2
Virtua Cop Re-Birth SLPM 62205 JPS2Playable +
+
0.9.2
Virtua Fighter 4 - Evolution SLES 51616 EPS2Playable +
+
0.9.4
Virtua Fighter 4 - Evolution SLUS 20616 UPS2Playable +
+
0.9.2
Virtua Fighter 4 SCES 50759 EPS2Playable +
+
0.9.4
Virtua Fighter 4 SLPM 62130 JPS2Playable +
+
0.9.2
Virtua Fighter 4 SLUS 20323 UPS2Playable +
+
0.9.4
Virtua Quest SLUS 20977 UPS2Ingame +
+
0.9.4
Virtua Tennis 2 SLES 51232 EPS2Playable +
+
0.9.4
Virtual On - Mars SLUS 20674 UPS2Playable +
+
0.9.4
Volleyball Xciting SLES 51765 EPS2Playable +
+
0.9.4
Wakeboarding Unleashed SLUS 20418 UPS2Intro +
+
0.9.4
WakuWaku Volley 2 SLPM 62285 JPS2Playable +
+
0.9.4
Wallace & Gromit in Project Zoo SLES 51989 EPS2Ingame +
+
0.9.4
Wallace & Grommit in Projekt Zoo SLES 52026 GPS2Ingame +
+
0.9.3
Wanda to Kyozou SCPS 15097 JPS2Ingame +
+
0.9.4
War Of The Monsters SCUS 97197 UPS2Playable +
+
0.9.4
Warhammer 40,000 - Fire Warrior SLUS 20597 UPS2Ingame +
+
0.9.4
Warriors Orochi SLUS 21662 UPS2Playable +
+
0.9.4
Warriors, The SLUS 21215 UPS2Ingame +
+
0.9.4
Warship Gunner 2 SLUS 21387 UPS2Nothing +
+
0.9.4
Way of The Samurai SLUS 20407 UPS2Ingame +
+
0.9.4
Way of The Samurai 2 SLES 52275 EPS2Playable +
+
0.9.2
Way of The Samurai 2 SLUS 20893 UPS2Ingame +
+
0.9.4
We Love Katamari SLUS 21230 UPS2Ingame +
+
0.9.4
Wheel of Fortune SLUS 20790 UPS2Playable +
+
0.9.4
Whiplash SLES 51958 EPS2Ingame +
+
0.9.2
Whiplash SLUS 20684 UPS2Ingame +
+
0.9.4
Wild Arms 3 SCUS 97203 UPS2Ingame +
+
0.9.4
Wild Arms 4 SLUS 21292 UPS2Playable +
+
0.9.4
Wild Arms 5 SLUS 21615 UPS2Nothing +
+
0.9.4
Wild Arms Alter Code - F SLUS 20937 UPS2Playable +
+
0.9.4
Wild Wild Racing SLES 50009 EPS2Playable +
+
0.9.4
Winback 2 - Project Poseidon SLUS 20947 UPS2Ingame +
+
0.9.4
Winning Eleven 10 SLPM 66374 JPS2Playable +
+
0.9.3
Winning Eleven 6 SLPM 62268 JPS2Playable +
+
0.9.3
Winning Eleven 7 SLPM 62356 JPS2Playable +
+
0.9.3
Winning Eleven 9 International SLUS 21220 UPS2Playable +
+
0.9.4
Winning Eleven 9 SLPM 66009 JPS2Ingame +
+
0.9.2
Winning Eleven Pro Evolution Soccer 2007 SLUS 21464 UPS2Playable +
+
0.9.4
WipEout Fusion SCES 50005 EPS2Playable +
+
0.9.4
Wipeout Fusion SLUS 20462 UPS2Playable +
+
0.9.4
Without Warning SLUS 21156 UPS2Intro +
+
0.9.4
Wizardry - Tale Of The Forsaken Lands SLUS 20259 UPS2Ingame +
+
0.9.4
Woody Woodpecker - Escape From Buzz Buzzard Park SLUS 20341 UPS2Playable +
+
0.9.4
Woody Woodpecker PBPX 95201 JPS2Playable +
+
0.9.2
Woody Woodpecker SLES 50613 EPS2Ingame +
+
0.9.2
Worimagesoundplay SLPM 65484 JPS2Ingame +
+
0.9.4
World Championship Poker - All In SLUS 21412 UPS2Nothing +
+
0.9.4
World Championship Poker 2 SLUS 21176 UPS2Playable +
+
0.9.4
World Championship Pool 2004 SLUS 20760 UPS2Playable +
+
0.9.4
World Destruction League - Thunder Tanks PBPX 95201 UPS2Playable +
+
0.9.4
World Destruction League - War Jets SLUS 20007 UPS2Playable +
+
0.9.4
World Poker Tour SLUS 21333 UPS2Intro +
+
0.9.4
World Rally Championship 3 SLPM 65583 JPS2Ingame +
+
0.9.2
World Rally Championship 4 SCES 52389 EPS2Ingame +
+
0.9.3
World Rally Championship SCES 50139 EPS2Nothing +
+
0.9.2
World Series Of Poker - Battle For The Bracelets SLUS 21686 UPS2Ingame +
+
0.9.4
World Series of Poker - Tournament of Champions SLUS 21491 UPS2Playable +
+
0.9.4
World Series Of Poker SLUS 21301 UPS2Playable +
+
0.9.4
Worms 3D SLUS 20894 UPS2Playable +
+
0.9.4
Worms 4 - Mayhem SLES 53096 EPS2Ingame +
+
0.9.4
Worms Forts Under Siege SLES 52342 EPS2Playable +
+
0.9.3
Wrath Unleashed SLUS 20840 UPS2Intro +
+
0.9.4
WRC Rally Evolved SCES 53247 EPS2Ingame +
+
0.9.3
Wrestle Kingdom SLPM 66401 JPS2Playable +
+
0.9.4
WTA Tennis Tour USA SLPM 62046 JPS2Playable +
+
0.9.4
WWE Crush Hour SLUS 20385 UPS2Playable +
+
0.9.4
WWE Smackdown VS Raw 2006 SLES 53676 EPS2Playable +
+
0.9.3
WWE Smackdown VS Raw 2006 SLUS 21286 UPS2Playable +
+
0.9.4
WWE Smackdown VS Raw 2007 SLES 54489 EPS2Playable +
+
0.9.3
WWE Smackdown VS Raw 2007 SLUS 21427 UPS2Playable +
+
0.9.4
WWE Smackdown VS Raw SLUS 21060 UPS2Playable +
+
0.9.4
WWE Smackdown! Here Comes the Pain SLUS 20787 UPS2Playable +
+
0.9.2
X-Files, The - Resist or Serve SLUS 20179 UPS2Ingame +
+
0.9.4
X-Men 3 - The Official Game SLUS 21107 UPS2Ingame +
+
0.9.4
X-Men Legends 2 - Rise of The Apocalypse SLUS 21138 UPS2Playable +
+
0.9.4
X-Men Legends SLUS 20656 UPS2Playable +
+
0.9.4
X-Squad SLES 50031 EPS2Intro +
+
0.9.4
X-Treme Quads SLES 53141 EPS2Ingame +
+
0.9.4
X2 - Wolverine's Revenge SLUS 20337 UPS2Ingame +
+
0.9.4
Xena - Warrior Princess SLES 54541 EPS2Playable +
+
0.9.4
Xenosaga Episode 3 - Also Sprach Zarathustra SLPS 25640 JPS2Ingame +
+
0.9.2
Xenosaga Episode I - Der Wille zur Macht SCAJ 30001 JPS2Playable +
+
0.9.4
Xenosaga Episode I - Der Wille zur Macht SLUS 20469 UPS2Ingame +
+
0.9.4
Xenosaga Episode II - Jenseits von Gut und Bose SLUS 20892 UPS2Ingame +
+
0.9.4
Xenosaga Episode III - Also Sprach Zarathustra SLUS 21389 UPS2Ingame +
+
0.9.4
XGIII - Extreme G Racing SLES 50210 EPS2Ingame +
+
0.9.4
XGRA - Extreme G Racing Association SLUS 20632 UPS2Playable +
+
0.9.4
Xiaolin Showdown SLUS 21405 UPS2Ingame +
+
0.9.4
XIII SLES 51244 EPS2Ingame +
+
0.9.2
XIII SLUS 20677 UPS2Menus +
+
0.9.4
Yakuza SLES 54171 EPS2Menus +
+
0.9.2
Yakuza SLUS 21348 UPS2Ingame +
+
0.9.4
Yamasa Digi World SP Giant Pulsar SLPS 20475 JPS2Playable +
+
0.9.2
Yoshinoya SLPM 62489 JPS2Playable +
+
0.9.4
Ys 3 - Wanderer's From Ys SLPM 62532 JPS2Intro +
+
0.9.4
Ys: Ark Of Napishtim SLUS 20980 UPS2Playable +
+
0.9.4
Yu-Gi-Oh! Capsule Monster Coliseum SLUS 20940 UPS2Playable +
+
0.9.3
Yu-Gi-Oh! The Duelists of the Roses SLUS 20515 UPS2Playable +
+
0.9.4
Zatch Bell - Mamodo Battles SLUS 21254 UPS2Playable +
+
0.9.4
Zatch Bell - Mamodo Fury SLUS 21363 UPS2Nothing +
+
0.9.4
Zathura SLES 53696 EPS2Playable +
+
0.9.2
Zathura SLUS 21336 UPS2Playable +
+
0.9.4
Zettai Zetsumei Toshi SLPS 25113 JPS2Playable +
+
0.9.4
Zone Of The Enders - The 2nd Runner SLES 51113 EPS2Playable +
+
0.9.2
Zone Of The Enders - The 2nd Runner SLUS 20545 UPS2Nothing +
+
0.9.4
Zone of the Enders SLPM 65019 JPS2Ingame +
+
0.9.2
Zone of The Enders SLUS 20148 UPS2Ingame +
+
0.9.4
Zooo SLPM 62466 JPS2Ingame +
+
0.9.2
diff --git a/bin/compat_list/h_console.jpg b/bin/compat_list/h_console.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c589631fae6448736182f3030663a4d8a1e89ab6 GIT binary patch literal 544 zcmex=iF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMov=hM7^2fk}{&S&;Gn5r#wt zMj!yX5)N3Inb=W9KvDt>j4X`IKq;6yMkZz!RzU_KVMP%(Wl_V#LM5XhRY4S!KuZ7L zV&GwB1lq?e$Y9U#rbNHO>4Cv&%_Whd`ct(gE2@E z^lsi($k3Bv| zmQ^@8P%Qeq!?fCkv!(tsgzS3U$*H>|=452h#);P*`e)n=^KXrNW0`9$;-kB7tJQ1Y p^wxClXy*!fU&fky`fq=}ORR4Dll%USMa9S8>2+`ZY?1$e69BBKj57cL literal 0 HcmV?d00001 diff --git a/bin/compat_list/h_region.jpg b/bin/compat_list/h_region.jpg new file mode 100644 index 0000000000000000000000000000000000000000..515ea4f33bd96e9647997e24ca7ff5716ccda75f GIT binary patch literal 486 zcmex=iF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMouVpP5mRfk}{&S&;Gn5r!BB z24+T}Bar|z3p*p45Cek%0}~S?Gczk(9U~Jn3oC=5p`xR3qL7jZn;?dk|F;-;fMzoZ zG7B=;GhEAhv}O+1)7%wN`##0p30t#ug3VDzfsGNCFVD;EV#@q@+;XBM=WEvJOWKw1 zV%h>F5-%pVKinXbp>f*3MKb%fYDZ(p$}eGOX9pZhGE~|BcppDvdLD8NV@C-q!s8CIFiF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMouVmzhzJfk}{&S&;Gn5r!BB zMn*=UBN2d=g&j=(86|xzpEk#(7^*NiglYP$GKP&f>X|vZ8ImwR;oSJ>OX* z>5_Q(aB}+>2ipvx*}}={^Y&;Q7o9c1J-m6|-5r5_tx?g3{GKx3-t&TgtMxw3w<~SV zbw4^TIrZo|z4vXC9$k8WB0h7$qHEg9U3S-duj+CF)G)|FS0F%uS*@ZR!oxuE%7 c{`tPu2R{XVud+5iF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMov=l$lYGfk}{&S&;Gn5r#yd zvzZxzu7m?tW)?PfMie2CoB#t86B8pd6FW?Xk%^f_kX495QP_~pG0@0KSwxgw5GDyX z?f)$X9-#S5g3N*p_6#rYZ+4qfIjt)Ex%>M=Umt2u`XSN7>a)U@ZF}j0YxX-!JHi6C z-#UFOFsYO$$l!E?4C`U}?Xs-WRo2sMk8WyP6X?t8vZiC3Zd7}RVU>Q%yvXBqu`EK_ z4`=`RC);u?xQgY$q&1g%m{XcKc$mv9-e1t&Y_&c=*JS^cs|%tod!iF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMouVg_%*1fk}{&S&;Gn5r#wt z1}0{pBN2d+iJ6t1kr5#PVF@rWurf2Tvckm~1(}#xgoIfcL<}88*~AnR3yp#VF|_@^ z#lXYN2(*t`kinkeUQMy^)7@Tix8H0x`!2-w_Ena3`{C)lOj^vs8zrBobaxlY>^#-8 zWY^=84h0swF3$<=j2B#f8yHH+=sel6P3X@Izq6%zJ2nU`aCI_WnIgAm3-g}h87Dt% ze0O--<&91W+kRbnz1E~GOl9j9(T17~t@ma7{cX?aEsPA_eiF;o{=v;^GnD0RsUZK7IjyJ|1CV5fNcw z8EI*08F@HhWM^mR<>8eO5Ri}(6%>_%OAyQWe}F-dgMov=f|*f}fk}{&S&;Gn5r#wt zMj!yX5)N3InAuT9KvDt>jLb}|ER3u$b&O2REP|{IibBGohDIV{g-XiBs%(NNCV`ax zzs11A%m}oPS&+e=;q9FXU+cI}*d30wQ(L@0_V20ikIz3gXg+^?>}R1k`(u`6#hqb) zPWJ4Q=8{z1R@cRNnPKv^nc~)8963&~p^lrGC#*{|Iuah`_Pj$Ms78)xHD+_xMmO}6f{xlvyyu!Lz1fq@K zV_^6OhG#D30lApXXCMb?Y+#;H)BSpT0D%D*S@l9PX?Cj(n${XJcO1bPV;$<9{de}j}@5dr8q%6u@?(|r=(D-L0eILYcK`qY literal 0 HcmV?d00001 diff --git a/bin/compat_list/sq_intro.jpg b/bin/compat_list/sq_intro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7b8a3cc44c0567642c30c47ce6498590faeeb71 GIT binary patch literal 305 zcma)$O$x#=5QX2^G^uIYCZvU81ur6qAmYz0w60vZa^c>Cb>SiWS?B@8E5zVJP&a;$ zf#Dk%o;$i5^lUsGgIYlC19yiRZI|mE2n;~qs|V6yy;-bKH{OuDU=Pk13mFeX-sXPd zi1R2`QpQp$tzKxAW;#oiwRvuBx2mdc?+pnd5|xx%mz}~Co%iA2#WgSyd;&6P843)! g1LnT=CxYlpaiPBqV1A4{Lj~kN2L=O-Cdt*Eo}fV{4FCWD literal 0 HcmV?d00001 diff --git a/bin/compat_list/sq_menus.jpg b/bin/compat_list/sq_menus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f2defa6a2a5eabf284222fb90b9f35d91ba33a1 GIT binary patch literal 305 zcma)$Jqp4=5QX2E{fV13?y?3#B8c}8M38`b3yqb9m4&?rOW`5>X*_^|tI)W+{I zFnj~U^Cy3UnOCz4)B@@d_&e-$x7zGMU;suzJ&;c7?Q)H}35NU?2MER(XM%Il7GaWD zh&a(oB}!?dUl^TsO*hrf^?J_r%d+eb-jI~CqdU1Vd6C(ycpv^SyCVn;z|g1{qH(=nZ&5eKkiO#t&KPqTcO2g1 zW&)3MFA%;T_`Z$;%`b1Cy8Q(4g+{#|qn<-x=z1xt~w gNT0DVwZGv+J;hwvGl2Rr`UYW>`D`nUu|Gjy-+QDbpa1{> literal 0 HcmV?d00001 diff --git a/bin/patches/013E349D.pnach b/bin/patches/013E349D.pnach new file mode 100644 index 0000000000..ca24695584 --- /dev/null +++ b/bin/patches/013E349D.pnach @@ -0,0 +1,4 @@ +gametitle= Resident Evil 4 [SLUS 21134] (U) +comment= +//ZeroGS Patch - GAME_NOTARGETCLUT +zerogs=00001000 \ No newline at end of file diff --git a/bin/patches/015314A2.pnach b/bin/patches/015314A2.pnach new file mode 100644 index 0000000000..a03a6a2e3d --- /dev/null +++ b/bin/patches/015314A2.pnach @@ -0,0 +1,4 @@ +gametitle= Sims - The Urbz, The [SLES 52908] (E) +comment= +//ZeroGS Patch - GAME_NOQUICKRESOLVE +zerogs=00000800 \ No newline at end of file diff --git a/bin/patches/034836F8.pnach b/bin/patches/034836F8.pnach new file mode 100644 index 0000000000..6bbc24dcd6 --- /dev/null +++ b/bin/patches/034836F8.pnach @@ -0,0 +1,13 @@ +gametitle=Driving Emotion Type-S [SLPS 20007] (J) +comment= patches by Nachbrenner +//Skip OP_MOVIE +//patch=0,EE,001c1818,word,1000000c +//MTGS: fix GS_CSR in "sceGsExecStoreImage" +patch=0,EE,00276ad0,word,34420002 +patch=0,EE,00276aa0,word,34630002 +//MTGS: fix GS_CSR in custom function +patch=0,EE,00251ac4,word,00000000 +//disable BGM +patch=0,EE,00221914,word,24020000 +patch=0,EE,002218c8,word,03e00008 +patch=0,EE,002218cc,word,00000000 \ No newline at end of file diff --git a/bin/patches/0442B1BD.pnach b/bin/patches/0442B1BD.pnach new file mode 100644 index 0000000000..2d7a18a206 --- /dev/null +++ b/bin/patches/0442B1BD.pnach @@ -0,0 +1,4 @@ +gametitle=Samurai Warriors Xtreme Legends +comment=Skips Videos by bositman +//Skip Videos +patch=0,EE,00126bb0,word,24020001 \ No newline at end of file diff --git a/bin/patches/05177ECE.pnach b/bin/patches/05177ECE.pnach new file mode 100644 index 0000000000..ea287ab894 --- /dev/null +++ b/bin/patches/05177ECE.pnach @@ -0,0 +1,4 @@ +gametitle=Tomb Raider Legend [SLES 53908] (E) [05177ECE] +comment=Patch by CKemu +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00369988,word,24020001 \ No newline at end of file diff --git a/bin/patches/0518D274.pnach b/bin/patches/0518D274.pnach new file mode 100644 index 0000000000..748dfdc23f --- /dev/null +++ b/bin/patches/0518D274.pnach @@ -0,0 +1,4 @@ +gametitle=Need For Speed Most Wanted Black Edition(SLUS_213.51) +comment=Skips Video - deny file By General Plot +//Skip Videos +patch=0,EE,00242418,word,00000000 \ No newline at end of file diff --git a/bin/patches/0518D275.pnach b/bin/patches/0518D275.pnach new file mode 100644 index 0000000000..89686a2c30 --- /dev/null +++ b/bin/patches/0518D275.pnach @@ -0,0 +1,4 @@ +gametitle=Need For Speed Most Wanted (SLUS_212.67) +comment=Skips Video - deny file By General Plot +//Skip Videos +patch=0,EE,00242414,word,00000000 \ No newline at end of file diff --git a/bin/patches/06DE61E0.pnach b/bin/patches/06DE61E0.pnach new file mode 100644 index 0000000000..c9dbb3bc87 --- /dev/null +++ b/bin/patches/06DE61E0.pnach @@ -0,0 +1,4 @@ +gametitle= Guilty Gear XX - Slash Midnight Carnival [SLPM 66333] (J) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,002743d8,word,24020001 \ No newline at end of file diff --git a/bin/patches/07AD79C9.pnach b/bin/patches/07AD79C9.pnach new file mode 100644 index 0000000000..74fa49547b --- /dev/null +++ b/bin/patches/07AD79C9.pnach @@ -0,0 +1,4 @@ +gametitle=Yu-Gi-Oh The Duelists Of The Roses (U) +comment= +//Skip Videos +patch=0,EE,0018ee60,word,24020001 \ No newline at end of file diff --git a/bin/patches/0838D766.pnach b/bin/patches/0838D766.pnach new file mode 100644 index 0000000000..79d1f54315 --- /dev/null +++ b/bin/patches/0838D766.pnach @@ -0,0 +1,6 @@ +gametitle=Raiden III [SLES 53829] (E) +comment=patches by Nachbrenner, made with Phaste 1.20 +//Infinite Lives +patch=1,EE,002d7458,byte,08 +//Infinite Bombs +patch=1,EE,002d74bc,byte,08 \ No newline at end of file diff --git a/bin/patches/086273D2.pnach b/bin/patches/086273D2.pnach new file mode 100644 index 0000000000..5abbf3cd0d --- /dev/null +++ b/bin/patches/086273D2.pnach @@ -0,0 +1,4 @@ +gametitle=Metal Gear Solid 3 - Snake Eater [SLES 82013] (E) [086273D2] +comment=Patch By CKemu +//ZeroGS Patch - Required fixes to visuals +zerogs=06018000 \ No newline at end of file diff --git a/bin/patches/08901101.pnach b/bin/patches/08901101.pnach new file mode 100644 index 0000000000..9041aa2124 --- /dev/null +++ b/bin/patches/08901101.pnach @@ -0,0 +1,13 @@ +gametitle=Neo Contra [SLUS 20961] (U) +comment= Patches By Nachbrenner +//disable BGM (for blockdump) +// patch=0,EE,0012bf20,word,03e00008 +// patch=0,EE,0012bf24,word,00000000 +//fix IPU busy! ingame +patch=0,EE,003a9538,word,03e00008 +patch=0,EE,003a953c,word,00000000 +patch=0,EE,003a9460,word,03e00008 +patch=0,EE,003a9464,word,00000000 +// +//no 3D = no DMA error +// patch=0,EE,00122b60,word,00000000 \ No newline at end of file diff --git a/bin/patches/08FB9DCF.pnach b/bin/patches/08FB9DCF.pnach new file mode 100644 index 0000000000..ac07a947a2 --- /dev/null +++ b/bin/patches/08FB9DCF.pnach @@ -0,0 +1,9 @@ +gametitle= Card Captor Sakura [SLPS 20408] (J) +comment=patches by Nachbrenner +//skip eyetoy check +patch=0,EE,013385b0,word,00000000 +//skip MC & Start screen +patch=0,EE,01337c20,word,00000000 +//activate 1st for food scene, both for telephone scene +// patch=0,EE,01337c2c,word,00000000 // food scene +// patch=0,EE,01337c3c,word,00000000 // telephone scene \ No newline at end of file diff --git a/bin/patches/0999F9DB.pnach b/bin/patches/0999F9DB.pnach new file mode 100644 index 0000000000..6492054e50 --- /dev/null +++ b/bin/patches/0999F9DB.pnach @@ -0,0 +1,13 @@ +gametitle=Rally Championship [SLES 50763] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,001ADE48,word,03E00008 +patch=0,EE,001CC840,word,24020001 +//Skip sceGsExecStoreImage +patch=0,EE,001c4af0,word,03e00008 +patch=0,EE,001c4af4,word,00000000 +//Begin New Career With Loads Of Money +patch=0,EE,001A05C0,word,3C0505F5 +patch=0,EE,001A05DC,word,34A5E0FF +//Enable Cheat (ASM) +patch=0,EE,0018DEB8,word,24020001 \ No newline at end of file diff --git a/bin/patches/09D35D3F.pnach b/bin/patches/09D35D3F.pnach new file mode 100644 index 0000000000..4223ec165e --- /dev/null +++ b/bin/patches/09D35D3F.pnach @@ -0,0 +1,4 @@ +gametitle=The Urbz: Sims In The City [SLUS 21066] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,004226d0,word,24020001 \ No newline at end of file diff --git a/bin/patches/0A342A88.pnach b/bin/patches/0A342A88.pnach new file mode 100644 index 0000000000..5d3ae4f4c9 --- /dev/null +++ b/bin/patches/0A342A88.pnach @@ -0,0 +1,4 @@ +gametitle=Futurama ( U ) +comment=patch by Refraction +//skip movies +patch=0,EE,002fc474,word,00000000 \ No newline at end of file diff --git a/bin/patches/0B359BBF.pnach b/bin/patches/0B359BBF.pnach new file mode 100644 index 0000000000..d3fd069c76 --- /dev/null +++ b/bin/patches/0B359BBF.pnach @@ -0,0 +1,5 @@ +gametitle= Kamen Rider 555 [SLPS 20329] (J) +comment=patches by Nachbrenner +//skip "PlayMpeg" +patch=0,EE,0022f590,word,03e00008 +patch=0,EE,0022f594,word,00000000 \ No newline at end of file diff --git a/bin/patches/0C370E94.pnach b/bin/patches/0C370E94.pnach new file mode 100644 index 0000000000..4e9ba42975 --- /dev/null +++ b/bin/patches/0C370E94.pnach @@ -0,0 +1,4 @@ +gametitle=Simple Series 2000 - Vol.106 - The Block Kuzushi Quest (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,0019a880,word,24020001 \ No newline at end of file diff --git a/bin/patches/0F6B6315.pnach b/bin/patches/0F6B6315.pnach new file mode 100644 index 0000000000..b3b8d33225 --- /dev/null +++ b/bin/patches/0F6B6315.pnach @@ -0,0 +1,5 @@ +gametitle= Kingdom Hearts [SLUS 20370] (U) +comment= +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory diff --git a/bin/patches/1025D50A.pnach b/bin/patches/1025D50A.pnach new file mode 100644 index 0000000000..f705d0d512 --- /dev/null +++ b/bin/patches/1025D50A.pnach @@ -0,0 +1,7 @@ +gametitle= Godzilla - Save The Earth [SLUS 20809] (U) +comment=patches by nachbrenner +//EEREC fix: borked memory write +patch=0,EE,0028b2d0,word,00000000 +//DMA fix menus +patch=0,EE,0022c568,word,00000000 +patch=0,EE,0022c540,word,00000000 \ No newline at end of file diff --git a/bin/patches/116154AD.pnach b/bin/patches/116154AD.pnach new file mode 100644 index 0000000000..1798b7eedb --- /dev/null +++ b/bin/patches/116154AD.pnach @@ -0,0 +1,8 @@ +gametitle=CART Fury Championship Racing [SLUS 20141] (U) +comment=patches by Nachbrenner +//skip PSX2_Mpeg_PlayFile__FPc +patch=0,EE,00107a00,word,03e00008 +patch=0,EE,00107a04,word,24020001 +//skip SuperSync__Fi +patch=0,EE,00100eb0,word,03e00008 +patch=0,EE,00100eb4,word,24020001 \ No newline at end of file diff --git a/bin/patches/1248FE3A.pnach b/bin/patches/1248FE3A.pnach new file mode 100644 index 0000000000..0ebca0f2d4 --- /dev/null +++ b/bin/patches/1248FE3A.pnach @@ -0,0 +1,6 @@ +gametitle=Baphomets Fluch - Der Schlafende Drache [SLES 51978] (G) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,00243fa0,word,24020001 +//Fix obscure infinite loop +patch=0,EE,00216764,word,00000000 \ No newline at end of file diff --git a/bin/patches/129C8600.pnach b/bin/patches/129C8600.pnach new file mode 100644 index 0000000000..6c5e010aa0 --- /dev/null +++ b/bin/patches/129C8600.pnach @@ -0,0 +1,8 @@ +gametitle=DTM Race Driver [SLES 50816] (E) +comment=patches by nachbrenner +//Skip Videos +patch=0,EE,003876c8,word,24020001 +//All Boni unlocked +patch=1,EE,0046a120,word,0000ffff +patch=0,EE,00306e5c,word,3445ffff +patch=0,EE,00306e94,word,3446ffff \ No newline at end of file diff --git a/bin/patches/12AFF4D4.pnach b/bin/patches/12AFF4D4.pnach new file mode 100644 index 0000000000..376621e301 --- /dev/null +++ b/bin/patches/12AFF4D4.pnach @@ -0,0 +1,23 @@ +gametitle= Gunbird 1 & 2 [SLPM 62469] (J) +comment=patches by nachbrenner +//Disable Autosave (001E5AF2) +//patch=0,EE,00107f6c,word,a4400012 +// +//Gunbird 1 Codes +// +//Infinite Lives +patch=0,EE,0018b06c,word,24020005 +//Infinite Bombs +patch=0,EE,0018AF30,word,24020006 +//Invincible +patch=0,EE,0018AF60,word,340203E8 +patch=0,EE,00199b78,word,00000000 +// +//Gunbird 2 Codes +// +//Infinite Lives +patch=0,EE,00134900,word,34020008 +//Infinite Bombs +patch=0,EE,00133db4,word,34020009 +//Invincible +patch=0,EE,00133a60,word,340303E7 \ No newline at end of file diff --git a/bin/patches/1468C474.pnach b/bin/patches/1468C474.pnach new file mode 100644 index 0000000000..48e1348357 --- /dev/null +++ b/bin/patches/1468C474.pnach @@ -0,0 +1,4 @@ +gametitle=Madagascar +comment=Keep thread alive +//Sleepthread syscall +patch=0,EE,002f8e44,word,00000000 \ No newline at end of file diff --git a/bin/patches/1510E1D1.pnach b/bin/patches/1510E1D1.pnach new file mode 100644 index 0000000000..2210ccb0ca --- /dev/null +++ b/bin/patches/1510E1D1.pnach @@ -0,0 +1,7 @@ +gametitle=Crash Twinsanity [SLES 52568] (E) +comment= patches by Nachbrenner +//Skip Videos +patch=0,EE,002b85d0,word,24020001 +// fix VU0REC 17.10.06 (obsolete) +//patch=0,EE,00189ab4,word,00000000 +//patch=0,EE,00189b78,word,00000000 \ No newline at end of file diff --git a/bin/patches/1629D655.pnach b/bin/patches/1629D655.pnach new file mode 100644 index 0000000000..a4555a1026 --- /dev/null +++ b/bin/patches/1629D655.pnach @@ -0,0 +1,20 @@ +gametitle=Red Faction II [SLES 51133] (E) +comment=comment=patches by Nachbrenner +//Skip Videos +//patch=0,EE,001afbc8,word,24020001 +//Boot Language Modifier (use only one of these) +//English +//patch=0,EE,0015bca8,word,24020001 +//Français +//patch=0,EE,0015bca8,word,24020002 +//Deutsch +//patch=0,EE,0015bca8,word,24020004 +//obsolete: +//skip borked VU0 stuff +//patch=0,EE,0020a464,word,00000000 +//patch=0,EE,00180eb0,word,03e00008 //slerp_src +//patch=0,EE,00180eb4,word,00000000 +//new VU0 fix: ctc2 t0, CMSAR0 -> li t0,0 +//patch=0,EE,00180df8,word,24080000 +//patch=0,EE,00181738,word,24080000 +//patch=0,EE,001811ac,word,24080000 diff --git a/bin/patches/163F0461.pnach b/bin/patches/163F0461.pnach new file mode 100644 index 0000000000..4acce85108 --- /dev/null +++ b/bin/patches/163F0461.pnach @@ -0,0 +1,18 @@ +gametitle=V-Rally 3 [SLES 50725] (E) +comment= patches by Nachbrenner +// skip network check (obsolete) +//patch=0,EE,002a4278,word,00103528 // GameInit_edNet__Fv +//IPU DMA fix +patch=0,EE,0012655c,word,00000000 // gcc2_compiled. +//Skip Videos (obsolete) +//patch=0,EE,00267810,word,00000000 // FE_MovieRefresh__Fv +//patch=0,EE,002677d0,word,00000000 // FE_MovieInstall__Fv +//patch=0,EE,002677f0,word,00000000 // FE_MovieInit__Fv +// disable menu music ( Vr3SoundMidiInstall__FP10_vr3_midi_) +patch=0,EE,002698fc,word,00000000 +//skip edSoundFlush__Fv +patch=0,EE,00197530,word,03e00008 +patch=0,EE,00197534,word,00000000 +//skip edDspSetCommand__Fii +patch=0,EE,001ab6b0,word,03e00008 +patch=0,EE,001ab6b4,word,00000000 \ No newline at end of file diff --git a/bin/patches/1738A5B0.pnach b/bin/patches/1738A5B0.pnach new file mode 100644 index 0000000000..4a8e83d993 --- /dev/null +++ b/bin/patches/1738A5B0.pnach @@ -0,0 +1,13 @@ +gametitle=Super Shanghai 2005 [SLPM 62552] (J) +comment=patches by Nachbrenner +//Infinite time +patch=1,EE,00AADAD8,word,0000face +//Skip STAR.PSS +//patch=0,EE,001064c8,word,00000000 +//Skip TITLDEMO.PSS +//patch=0,EE,0010d01c,word,00000000 +//boot with BGM off +patch=0,EE,0011fdac,word,adcf0008 +//Skip BGM Start +patch=0,EE,00116d58,word,03e00008 +patch=0,EE,00116d5c,word,00000000 \ No newline at end of file diff --git a/bin/patches/19D145D7.pnach b/bin/patches/19D145D7.pnach new file mode 100644 index 0000000000..b8c6e6b9ad --- /dev/null +++ b/bin/patches/19D145D7.pnach @@ -0,0 +1,12 @@ +gametitle=Kuri Kuri Mix [SLES 50224] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,001f41b4,word,00000000 +//Start with 600 seconds +patch=0,EE,0012cc60,word,24027530 +//Freeze countdown timer +patch=0,EE,0012d1f8,word,00000000 +//Don't lose time on getting hurt +patch=0,EE,0012e86c,word,00000000 +//Low total time +patch=0,EE,0012d1fc,word,24030001 \ No newline at end of file diff --git a/bin/patches/1CAC8A56.pnach b/bin/patches/1CAC8A56.pnach new file mode 100644 index 0000000000..96760c8036 --- /dev/null +++ b/bin/patches/1CAC8A56.pnach @@ -0,0 +1,4 @@ +gametitle=Venus & braves NTSC-J +comment= +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,003e86a0,word,24020001 \ No newline at end of file diff --git a/bin/patches/1D2818AF.pnach b/bin/patches/1D2818AF.pnach new file mode 100644 index 0000000000..9a4c6c0c78 --- /dev/null +++ b/bin/patches/1D2818AF.pnach @@ -0,0 +1,13 @@ +gametitle=Need For Speed - Hot Pursuit 2 [SLES 50731] (E) +comment=patches by Nachbrenner +//for blockdump: +//disable sound streaming +patch=0,EE,00274080,word,03e00008 +patch=0,EE,00274084,word,00000000 +//Skip Logo and Intro AVI +patch=0,EE,0016f094,word,00000000 +//Skip AVI streaming +patch=0,EE,0016ce30,word,03e00008 +patch=0,EE,0016ce34,word,00000000 +//American Mode (Skip language select menu) +patch=0,EE,0012EF78,word,00000000 \ No newline at end of file diff --git a/bin/patches/200BC0E6.pnach b/bin/patches/200BC0E6.pnach new file mode 100644 index 0000000000..76492e1ed3 --- /dev/null +++ b/bin/patches/200BC0E6.pnach @@ -0,0 +1,4 @@ +gametitle=XIII [SLES 51244] (E) +comment=patches by nachbrenner +//Skip Videos (sceMpegIsEnd) +patch=0,EE,001114a0,word,24020001 \ No newline at end of file diff --git a/bin/patches/2088950A.pnach b/bin/patches/2088950A.pnach new file mode 100644 index 0000000000..fc136e364b --- /dev/null +++ b/bin/patches/2088950A.pnach @@ -0,0 +1,4 @@ +gametitle= Xenosaga Episode III - Also Sprach Zarathustra [SLUS 21389] (U) +comment= +//ZeroGS Patch - GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE +zerogs=00018000 \ No newline at end of file diff --git a/bin/patches/21068223.pnach b/bin/patches/21068223.pnach new file mode 100644 index 0000000000..c7e282630e --- /dev/null +++ b/bin/patches/21068223.pnach @@ -0,0 +1,5 @@ +gametitle=Okami [US] +//fix sceSifDmaStat loop +patch=0,EE,00214f90,word,24020001 +//ZeroGS Patch -GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE +zerogs=00058000 \ No newline at end of file diff --git a/bin/patches/2251E14D.pnach b/bin/patches/2251E14D.pnach new file mode 100644 index 0000000000..63d63ecaf9 --- /dev/null +++ b/bin/patches/2251E14D.pnach @@ -0,0 +1,4 @@ +gametitle=Tekken 4 [SCES 50878] (E) [2251E14D] +comment=Patch By CKemu +//ZeroGS Patch - Stops characters appearing as wigs on GeForce 8x00 series cards (Disable Alpha Testing) +zerogs=00080000 \ No newline at end of file diff --git a/bin/patches/22C36E63.pnach b/bin/patches/22C36E63.pnach new file mode 100644 index 0000000000..e09b627f6f --- /dev/null +++ b/bin/patches/22C36E63.pnach @@ -0,0 +1,4 @@ +gametitle=Toca Race Driver 2 [SLUS 21039] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00452a48,word,24020001 \ No newline at end of file diff --git a/bin/patches/25433CBD.pnach b/bin/patches/25433CBD.pnach new file mode 100644 index 0000000000..5a151f529f --- /dev/null +++ b/bin/patches/25433CBD.pnach @@ -0,0 +1,9 @@ +gametitle=Flipnic [SCPS15050](J) +comment= patches by Nachbrenner +// fix D3_CHCR (might be redundant) +patch=0,EE,0011c1b8,word,00000000 +// skip sceIpuSync +patch=0,EE,00208eb0,word,03e00008 +patch=0,EE,00208eb4,word,00000000 +// fix sceIpuRestartDMA +patch=0,EE,00208e04,word,00000000 \ No newline at end of file diff --git a/bin/patches/27E54B37.pnach b/bin/patches/27E54B37.pnach new file mode 100644 index 0000000000..5768df2acc --- /dev/null +++ b/bin/patches/27E54B37.pnach @@ -0,0 +1,16 @@ +gametitle=Syphon Filter - The Omega Strain [SCES 52033] (G) +comment= patches by Nachbrenner +//Skip FMV (for blockdump) +patch=0,EE,0041743c,word,00000000 +patch=0,EE,00417444,word,00000000 +//Boot Language Fix +patch=0,EE,0042020c,word,24020004 //german +// Playername = PCSX2 +patch=1,EE,008b945c,word,58534350 +patch=1,EE,008b9460,word,00000032 +// +//brute force fix GS_CSR (obsolete) +//patch=0,EE,0039ca3c,word,00000000 +//patch=0,EE,0039caec,word,00000000 +//brute force fix VIF1_STAT (obsolete) +//patch=0,EE,0039c8e0,word,10000019 \ No newline at end of file diff --git a/bin/patches/280DAC56.pnach b/bin/patches/280DAC56.pnach new file mode 100644 index 0000000000..21507086eb --- /dev/null +++ b/bin/patches/280DAC56.pnach @@ -0,0 +1,16 @@ +gametitle=Super Trucks [SLES 50897] (E) +comment=patches by nachbrenner +//Skip Intro Video +patch=0,EE,00100060,word,00000000 +//always use music "BUG.SPU" (for blockdumping) +patch=0,EE,001b5308,word,00209460 +patch=0,EE,001b530c,word,00209460 +patch=0,EE,001b5310,word,00209460 +patch=0,EE,001b5314,word,00209460 +patch=0,EE,001b5318,word,00209460 +patch=0,EE,001b531c,word,00209460 +patch=0,EE,001b5320,word,00209460 +// Disable "PAD_CheckForUSBDevices" +//patch=0,EE,00135118,word,00000000 +//Disable "lgDevInit" +//patch=0,EE,001339fc,word,00000000 \ No newline at end of file diff --git a/bin/patches/295D2F96.pnach b/bin/patches/295D2F96.pnach new file mode 100644 index 0000000000..b2f9716540 --- /dev/null +++ b/bin/patches/295D2F96.pnach @@ -0,0 +1,6 @@ +gametitle=Spider-Man [SLES 50814] (G) +comment=patches by Nachbrenner +//Skip Videos +//patch=0,EE,0039A9D0,word,03E00008 +//patch=0,EE,0039A9D4,word,00000000 +//patch=0,EE,004a3540,word,24020001 \ No newline at end of file diff --git a/bin/patches/29D80A23.pnach b/bin/patches/29D80A23.pnach new file mode 100644 index 0000000000..db783032b1 --- /dev/null +++ b/bin/patches/29D80A23.pnach @@ -0,0 +1,9 @@ +gametitle=Sidewinder V [SLPS 25271] (J) +comment=patches by Nachbrenner +//Language = English +patch=1,EE,0039b484,word,00000001 +//Skip Videos (sceMpegIsEnd) +//patch=0,EE,00280398,word,24020001 +//Skip DualBgmOn +//patch=0,EE,002439f8,word,03e00008 +//patch=0,EE,002439fc,word,00000000 \ No newline at end of file diff --git a/bin/patches/2B2E1535.pnach b/bin/patches/2B2E1535.pnach new file mode 100644 index 0000000000..bb73e07db7 --- /dev/null +++ b/bin/patches/2B2E1535.pnach @@ -0,0 +1,5 @@ + +gametitle=Arc the Lad +comment=Skips Video by Rudy_x +//Skip introVideo(s) +patch=0,EE,001d7df8,word,24020001 diff --git a/bin/patches/2C728173.pnach b/bin/patches/2C728173.pnach new file mode 100644 index 0000000000..5580939418 --- /dev/null +++ b/bin/patches/2C728173.pnach @@ -0,0 +1,4 @@ +gametitle=Fast and The Furious +comment= Skip Videos By Refraction +//Skip Videos +patch=0,EE,003d2570,word,24020001 \ No newline at end of file diff --git a/bin/patches/2CFFFA50.pnach b/bin/patches/2CFFFA50.pnach new file mode 100644 index 0000000000..e513700e16 --- /dev/null +++ b/bin/patches/2CFFFA50.pnach @@ -0,0 +1,9 @@ +gametitle=Buffy: Chaos Bleeds [SLES 51890] (E) +comment= patches by Nachbrenner +//Skip Videos +// patch=0,EE,002A3960,word,24020001 +//Video modifier (use only one of these) +//INTRO1 -> SPIKE_VO +//patch=0,EE,002efb70,word,002efab0 +//INTRO1 -> OUTTAKES +//patch=0,EE,002efb70,word,002efaf0 \ No newline at end of file diff --git a/bin/patches/2D919421.pnach b/bin/patches/2D919421.pnach new file mode 100644 index 0000000000..2c754784a2 --- /dev/null +++ b/bin/patches/2D919421.pnach @@ -0,0 +1,15 @@ +Gametitle=Charlie's Angels [SLES 51750] (E) +comment=patches by nachbrenner +//Skip Delay on Screen 1+2 0x00208818 +patch=0,EE,001915b4,word,ad608818 +patch=0,EE,00191604,word,ac600100 +patch=0,EE,001916ac,word,ac408818 +patch=0,EE,001916c8,word,24020000 +patch=0,EE,0019592c,word,ae000100 +//Skip Videos +patch=0,EE,00191320,word,03E00008 +patch=0,EE,00191324,word,00000000 +patch=0,EE,001aa810,word,24020001 +//Unlock All Boni +patch=0,EE,00194a68,word,2401FFFF +patch=0,EE,00194a6c,word,FCE10148 \ No newline at end of file diff --git a/bin/patches/2F56CBC9.pnach b/bin/patches/2F56CBC9.pnach new file mode 100644 index 0000000000..c9e2bc1422 --- /dev/null +++ b/bin/patches/2F56CBC9.pnach @@ -0,0 +1,4 @@ +gametitle= Klonoa 2 - Lunatea's Veil [SLUS 20151] (U) +comment=patches by nachbrenner +//Skip sceIpuSync +patch=0,EE,00305b90,word,03e00008 \ No newline at end of file diff --git a/bin/patches/302797DF.pnach b/bin/patches/302797DF.pnach new file mode 100644 index 0000000000..068a62759b --- /dev/null +++ b/bin/patches/302797DF.pnach @@ -0,0 +1,5 @@ +gametitle=CYGirls +comment= +//patches by Refraction +//Skip Videos +patch=0,EE,00135130,word,00000000 \ No newline at end of file diff --git a/bin/patches/304C115C.pnach b/bin/patches/304C115C.pnach new file mode 100644 index 0000000000..e5294930ad --- /dev/null +++ b/bin/patches/304C115C.pnach @@ -0,0 +1,4 @@ +gametitle= Harvest Moon - A Wonderful Life [SLUS 21171] (U) +comment= +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/32629F36.pnach b/bin/patches/32629F36.pnach new file mode 100644 index 0000000000..fea149d6c3 --- /dev/null +++ b/bin/patches/32629F36.pnach @@ -0,0 +1,9 @@ +gametitle=Oni [SLES 50177] (G) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,001c67d8,word,03e00008 +patch=0,EE,001c67dc,word,00000000 +//skip "branch if copro 0 condition false" +patch=0,EE,001cef7c,word,00000000 // bc0f $001cef7c +//skip sceGsExecStoreImage +patch=0,EE,001d4454,word,00000000 \ No newline at end of file diff --git a/bin/patches/333F1F59.pnach b/bin/patches/333F1F59.pnach new file mode 100644 index 0000000000..e6593663a4 --- /dev/null +++ b/bin/patches/333F1F59.pnach @@ -0,0 +1,3 @@ +gametitle=Simple 2000: The neko mura NTSC JAP +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,00109420,word,24020001 \ No newline at end of file diff --git a/bin/patches/337B927C.pnach b/bin/patches/337B927C.pnach new file mode 100644 index 0000000000..fdd027f2f4 --- /dev/null +++ b/bin/patches/337B927C.pnach @@ -0,0 +1,4 @@ +gametitle=We Love Katamari (SLUS 21230) (U) +comment=Video Skip +//Skip Videos +patch=0,EE,0010ec5c,word,10000041 \ No newline at end of file diff --git a/bin/patches/339A0B8C.pnach b/bin/patches/339A0B8C.pnach new file mode 100644 index 0000000000..d3b94fa615 --- /dev/null +++ b/bin/patches/339A0B8C.pnach @@ -0,0 +1,4 @@ +gametitle= Fatal Frame [SLUS 20388] (U) NTSC +comment= Video Skip by Refraction +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00232f00,word,24020001 \ No newline at end of file diff --git a/bin/patches/33F7D21A.pnach b/bin/patches/33F7D21A.pnach new file mode 100644 index 0000000000..866a7525d0 --- /dev/null +++ b/bin/patches/33F7D21A.pnach @@ -0,0 +1,14 @@ +gametitle= Dirge Of Cerberus - Final Fantasy VII [SLES 54185] (E) +comment=patches by nachbrenner +//Fix "**** SQTHREAD ERROR : BAD LOCK STATE" +patch=0,EE,0042d768,word,00000000 +//Skip mcDelayThread (calls SleepThread) +patch=0,EE,00458008,word,00000000 +//Skip Videos (for blockdump) +patch=0,EE,00241bac,word,00000000 +//override sceScfGetLanguage +//patch=0,EE,002486d8,word,24020000 //japanese +patch=0,EE,002486d8,word,24020001 //english +//patch=0,EE,002486d8,word,24020004 //german +//intro 3D - fix DMA0 vs. VU0REC +patch=0,EE,0026f960,word,10000020 \ No newline at end of file diff --git a/bin/patches/36FEEE3A.pnach b/bin/patches/36FEEE3A.pnach new file mode 100644 index 0000000000..a29efec175 --- /dev/null +++ b/bin/patches/36FEEE3A.pnach @@ -0,0 +1,19 @@ +gametitle=Knockout Kings 2002 [SLUS 20369] (U) +comment= patches by Nachbrenner +//fix DMA loop +patch=0,EE,001d8020,word,1000000f +//VU0 crash fix (obsolete) +//patch=0,EE,001fb144,word,00000000 +// +// for blockdump: +// +//Skip MPC videos +patch=0,EE,0018c0a8,word,03e00008 +patch=0,EE,0018c0ac,word,24020001 +//Fight commentary off +patch=1,EE,00273380,word,00000000 +//Music vol.=0 +patch=1,EE,002721A4,word,00000000 +//Skip sound streaming +patch=0,EE,00138b68,word,03e00008 +patch=0,EE,00138b6c,word,00000000 \ No newline at end of file diff --git a/bin/patches/37BA81B1.pnach b/bin/patches/37BA81B1.pnach new file mode 100644 index 0000000000..888d3499c3 --- /dev/null +++ b/bin/patches/37BA81B1.pnach @@ -0,0 +1,4 @@ +gametitle= Kamen Rider Blade [SLPS 20402] (J) +comment=patches by Nachbrenner +//skip "PlayMpeg" +patch=0,EE,00158dec,word,00000000 \ No newline at end of file diff --git a/bin/patches/37C07E96.pnach b/bin/patches/37C07E96.pnach new file mode 100644 index 0000000000..1fcc1626c7 --- /dev/null +++ b/bin/patches/37C07E96.pnach @@ -0,0 +1,3 @@ +gametitle=Simple2000 Vol.91 : The ALL STAR fighting [SLPS 20430] (J) +//Skip Movies +patch=0,EE,0010b720,word,24020001 \ No newline at end of file diff --git a/bin/patches/38F29E28.pnach b/bin/patches/38F29E28.pnach new file mode 100644 index 0000000000..920844b597 --- /dev/null +++ b/bin/patches/38F29E28.pnach @@ -0,0 +1,4 @@ +gametitle=7 cavalry of molmoth NTSC JAPAN +comment=skips pss intro +//Skip Videos +patch=0,EE,00284b58,word,24020001 \ No newline at end of file diff --git a/bin/patches/3BD85DA4.pnach b/bin/patches/3BD85DA4.pnach new file mode 100644 index 0000000000..34e39f52a9 --- /dev/null +++ b/bin/patches/3BD85DA4.pnach @@ -0,0 +1,7 @@ +gametitle=Ghosthunter [SCES 51463] (E) +comment=patches by nachbrenner +//fix VU0/DMA crap +patch=0,EE,003e8928,word,03e00008 +patch=0,EE,003e892c,word,00000000 +patch=0,EE,003831c8,word,00000000 +patch=0,EE,003831d4,word,00000000 \ No newline at end of file diff --git a/bin/patches/3CFE3B37.pnach b/bin/patches/3CFE3B37.pnach new file mode 100644 index 0000000000..4edde5e667 --- /dev/null +++ b/bin/patches/3CFE3B37.pnach @@ -0,0 +1,6 @@ +gametitle=Powershot Pinball [SLES 54084] (E) +comment=patches by auMatt +//Skip Video +patch=0,EE,0029c990,word,24020001 +//ZeroGS Patch - GAME_AUTORESET +zerogs=00000002 \ No newline at end of file diff --git a/bin/patches/3DB65A75.pnach b/bin/patches/3DB65A75.pnach new file mode 100644 index 0000000000..3fc6279161 --- /dev/null +++ b/bin/patches/3DB65A75.pnach @@ -0,0 +1,5 @@ +gametitle=Megaman Anniversary Collection [SLUS 20833] (U) +//fix GS_CSR +//patch=0,EE,0012d938,word,00000000 +//Skip videos +//patch=0,EE,0014e548,word,24020001 \ No newline at end of file diff --git a/bin/patches/3E0A256D.pnach b/bin/patches/3E0A256D.pnach new file mode 100644 index 0000000000..1cb94b5549 --- /dev/null +++ b/bin/patches/3E0A256D.pnach @@ -0,0 +1,4 @@ +//skip FMV (sceMpegIsEnd) +patch=0,EE,001eccc8,word,24020001 +//fix AudioReset (Peops SPU2 4.11.06) +patch=0,EE,00120a94,word,00000000 \ No newline at end of file diff --git a/bin/patches/3E68955A.pnach b/bin/patches/3E68955A.pnach new file mode 100644 index 0000000000..fffbc37805 --- /dev/null +++ b/bin/patches/3E68955A.pnach @@ -0,0 +1,5 @@ +gametitle=Kingdom Hearts - Final Mix [SLPS 25198] (J) +comment= +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory \ No newline at end of file diff --git a/bin/patches/3EAD47FE.pnach b/bin/patches/3EAD47FE.pnach new file mode 100644 index 0000000000..b43294ef84 --- /dev/null +++ b/bin/patches/3EAD47FE.pnach @@ -0,0 +1,4 @@ +gametitle=Britney's Dance Beat [SLUS 20402] (U) +comment=Kill BNE +//Patch made by CKemu +patch=0,EE,0022581c,word,00000000 \ No newline at end of file diff --git a/bin/patches/3F0452DE.pnach b/bin/patches/3F0452DE.pnach new file mode 100644 index 0000000000..24e78de9a6 --- /dev/null +++ b/bin/patches/3F0452DE.pnach @@ -0,0 +1,4 @@ +gametitle= FlatOut 2 [SLES 54002] (E) +comment= Video Skip by Refraction +//Skip Videos (sceMpegIsEnd) +patch=0,EE,003dd1d0,word,24020001 \ No newline at end of file diff --git a/bin/patches/3FB69323.pnach b/bin/patches/3FB69323.pnach new file mode 100644 index 0000000000..83b25e97b5 --- /dev/null +++ b/bin/patches/3FB69323.pnach @@ -0,0 +1,8 @@ +gametitle=Gran Turismo 4 Prologue [SCES 52438] (E) +//fix IPU DMA +patch=1,EE,00175018,word,00000000 +patch=1,EE,0046bba8,word,00000000 +patch=1,EE,0046bbe4,word,00000000 +//Skip Videos +patch=1,EE,0020c790,word,03e00008 +patch=1,EE,0020c794,word,00000000 \ No newline at end of file diff --git a/bin/patches/4043F228.pnach b/bin/patches/4043F228.pnach new file mode 100644 index 0000000000..c0198bd179 --- /dev/null +++ b/bin/patches/4043F228.pnach @@ -0,0 +1,4 @@ +gametitle= PC Genjin [SLPM 62418] (J) [4043F228] +comment= +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,0020f9e0,word,24020001 \ No newline at end of file diff --git a/bin/patches/41A3191C.pnach b/bin/patches/41A3191C.pnach new file mode 100644 index 0000000000..2bcbb660f8 --- /dev/null +++ b/bin/patches/41A3191C.pnach @@ -0,0 +1,4 @@ +gametitle=Simple Series 2000 - Vol. 99 - The Genshijin [SLPS 20461] (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00109e40,word,24020001 \ No newline at end of file diff --git a/bin/patches/4321A427.pnach b/bin/patches/4321A427.pnach new file mode 100644 index 0000000000..0ee28273ec --- /dev/null +++ b/bin/patches/4321A427.pnach @@ -0,0 +1,5 @@ +gametitle=World Soccer Winning Eleven 10 [SLPM 66374] (J) +comment=patches by fullcodes +//Skip PSS +// patch=0,EE,00131260,word,03e00008 +// patch=0,EE,00131264,word,00000000 \ No newline at end of file diff --git a/bin/patches/4334E17D.pnach b/bin/patches/4334E17D.pnach new file mode 100644 index 0000000000..d9455584c1 --- /dev/null +++ b/bin/patches/4334E17D.pnach @@ -0,0 +1,4 @@ +gametitle=Disgaea 2 - Cursed Memories [SLPS 25608] (J) +comment= +//ZeroGS Patch - GAME_NODEPTHRESOLVE +zerogs=00008000 \ No newline at end of file diff --git a/bin/patches/44A61C8F.pnach b/bin/patches/44A61C8F.pnach new file mode 100644 index 0000000000..cf21334ce4 --- /dev/null +++ b/bin/patches/44A61C8F.pnach @@ -0,0 +1,4 @@ +gametitle=Gran Turismo 4 [SCES 51719] (E) [44A61C8F] +comment=patches by nachbrenner +//skip Videos +patch=1,EE,00100D84,word,24100001 diff --git a/bin/patches/4691F6F7.pnach b/bin/patches/4691F6F7.pnach new file mode 100644 index 0000000000..e974348b3e --- /dev/null +++ b/bin/patches/4691F6F7.pnach @@ -0,0 +1,4 @@ +gametitle=The Sum Of All Fears [SLES 51180] (E) +comment= patches by Nachbrenner +//Skip sceIpuSync +//patch=0,EE,002aa098,word,03e00008 \ No newline at end of file diff --git a/bin/patches/46A7ECA4.pnach b/bin/patches/46A7ECA4.pnach new file mode 100644 index 0000000000..fc630c4cb4 --- /dev/null +++ b/bin/patches/46A7ECA4.pnach @@ -0,0 +1,4 @@ +gametitle=Guilty Gear Isuka [SLES 53284] (E) [46A7ECA4] +comment=Patch By CKemu +//Skip Videos +patch=0,EE,00107f10,word,24020001 \ No newline at end of file diff --git a/bin/patches/472C9E70.pnach b/bin/patches/472C9E70.pnach new file mode 100644 index 0000000000..a63e3a8719 --- /dev/null +++ b/bin/patches/472C9E70.pnach @@ -0,0 +1,6 @@ +gametitle=Kengo: Master Of Bushido [SLES 50114] (E) +comment=patches by nachbrenner +//start with 5 minutes time limit +patch=0,EE,002999b8,word,00003A98 //single_game_time_limit_table +//skip videos +patch=0,EE,0018d738,word,24020001 \ No newline at end of file diff --git a/bin/patches/48FE0C71.pnach b/bin/patches/48FE0C71.pnach new file mode 100644 index 0000000000..6e9b50c15a --- /dev/null +++ b/bin/patches/48FE0C71.pnach @@ -0,0 +1,20 @@ +gametitle=FFX-2 US +comment= +// InvalidDCache | SyncDCache +patch=0,EE,003498b0,word,03e00008 +patch=0,EE,003498b4,word,00000000 +//skip "INIT SOUND" +patch=0,EE,00132868,word,00000000 +//skip "INIT VOICE" +patch=0,EE,0013287c,word,00000000 +//skip AC3+PCM start (NOPs whole subroutine) +patch=0,EE,0017ac70,word,00000000 +//Skip Videos +//patch=0,EE,003338e0,word,24020001 +//skip "decode MPEG2" +patch=0,EE,0017aaa0,word,03e00008 +patch=0,EE,0017aaa4,word,00000000 +patch=0,EE,0017a9e8,word,03e00008 +patch=0,EE,0017a9ec,word,00000000 +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/49DA19CE.pnach b/bin/patches/49DA19CE.pnach new file mode 100644 index 0000000000..872ef01c18 --- /dev/null +++ b/bin/patches/49DA19CE.pnach @@ -0,0 +1,4 @@ +gametitle=Carmen Sandiego-The Secret Of The Stolen Drums [SLES52143] (E) +comment= patches by Nachbrenner +//Skip MpegPlay +patch=0,EE,0011efd0,word,03e00008 \ No newline at end of file diff --git a/bin/patches/4B6DDB6B.pnach b/bin/patches/4B6DDB6B.pnach new file mode 100644 index 0000000000..f98f21ff4c --- /dev/null +++ b/bin/patches/4B6DDB6B.pnach @@ -0,0 +1,3 @@ +gametitle=Guilty Gear XX NTSC JPN +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,00245418,word,24020001 \ No newline at end of file diff --git a/bin/patches/4C0C821D.pnach b/bin/patches/4C0C821D.pnach new file mode 100644 index 0000000000..5245a29414 --- /dev/null +++ b/bin/patches/4C0C821D.pnach @@ -0,0 +1,4 @@ +gametitle=Demolition Girl [SLES 53403] (E) [4C0C821D] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,0020b5c0,word,24020001 \ No newline at end of file diff --git a/bin/patches/4C4D7072.pnach b/bin/patches/4C4D7072.pnach new file mode 100644 index 0000000000..202d920379 --- /dev/null +++ b/bin/patches/4C4D7072.pnach @@ -0,0 +1,11 @@ +gametitle=Tom Clancy's Splinter Cell Chaos Theory [SLES 53007] (E) +comment=patches by Nachbrenner +//fix sceIpuStopDMA +patch=0,EE,0020b884,word,00000000 +// +// load SC3_OFF.ELF manually to go ingame +// d7a4b7af.pnach +// gametitle=Tom Clancy's Splinter Cell Chaos Theory [SC3_OFF.ELF] (E) +// Skip sceIpuRestartDMA +// patch=1,EE,001116e0,word,03e00008 +// patch=1,EE,001116e4,word,00000000 \ No newline at end of file diff --git a/bin/patches/4C9EE7DF.pnach b/bin/patches/4C9EE7DF.pnach new file mode 100644 index 0000000000..ef6746e68d --- /dev/null +++ b/bin/patches/4C9EE7DF.pnach @@ -0,0 +1,20 @@ +gametitle=Crazy Taxi [SLUS 20202] (U) +comment= patches by Nachbrenner +//skip movie "PlaySega" +patch=0,EE,001a1950,word,03e00008 +patch=0,EE,001a1954,word,00000000 +//skip movie "PlayAcclaim" +patch=0,EE,001a1ae8,word,03e00008 +patch=0,EE,001a1aec,word,00000000 +//skip music.str (for blockdump) +// patch=0,EE,001a0bb0,word,0000000 +//skip voice.str (for blockdump) +// patch=0,EE,001a0b9c,word,0000000 +//Infinite arcade time +patch=1,EE,002F0C64,word,00000e00 +//Japanese mode +//patch=0,EE,00118514,word,af8095a4 +//controller setting B +patch=1,EE,002152DF,byte,01 +//skip nlWaitVSync / TaxiBlankInterrupt (obsolete) +//patch=0,EE,0019a590,word,03e00008 \ No newline at end of file diff --git a/bin/patches/4D228733.pnach b/bin/patches/4D228733.pnach new file mode 100644 index 0000000000..a91012bd45 --- /dev/null +++ b/bin/patches/4D228733.pnach @@ -0,0 +1,5 @@ +gametitle=Marvel vs Capcom 2 [SLUS 20486] (U) +comment= +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory \ No newline at end of file diff --git a/bin/patches/4D6DBB75.pnach b/bin/patches/4D6DBB75.pnach new file mode 100644 index 0000000000..8533e66368 --- /dev/null +++ b/bin/patches/4D6DBB75.pnach @@ -0,0 +1,4 @@ +gametitle=bloody roar 3 NTSC JAPAN +comment=skips intro +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,001dc9f8,word,24020001 \ No newline at end of file diff --git a/bin/patches/4DAC50C2.pnach b/bin/patches/4DAC50C2.pnach new file mode 100644 index 0000000000..648401b2d9 --- /dev/null +++ b/bin/patches/4DAC50C2.pnach @@ -0,0 +1,5 @@ +gametitle=Starsky & Hutch DE/FR [SLES 51783] (E) +comment=patches by Nachbrenner +//Skip videos +//patch=1,EE,0021FAC4,word,00000000 +//patch=1,EE,00151750,word,24020001 \ No newline at end of file diff --git a/bin/patches/4F3D3CF0.pnach b/bin/patches/4F3D3CF0.pnach new file mode 100644 index 0000000000..36fa809d56 --- /dev/null +++ b/bin/patches/4F3D3CF0.pnach @@ -0,0 +1,5 @@ +gametitle=Simply... The Best For Less - Vol. 6 Ultimate Casino [SLES 52515] (E) +comment=patches by Nachbrenner +//Skip logo.pss +patch=0,EE,00115778,word,24020001 +patch=0,EE,0012eb90,word,00000000 \ No newline at end of file diff --git a/bin/patches/506644B3.pnach b/bin/patches/506644B3.pnach new file mode 100644 index 0000000000..ea628e26a5 --- /dev/null +++ b/bin/patches/506644B3.pnach @@ -0,0 +1,5 @@ +gametitle=Big Mutha Truckers [SLES 51355] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,002d1438,word,24020001 //sceMpegIsEnd +patch=0,EE,001ca00c,word,00000000 //sceMpegGetPicture \ No newline at end of file diff --git a/bin/patches/512B5046.pnach b/bin/patches/512B5046.pnach new file mode 100644 index 0000000000..1833b8ba0a --- /dev/null +++ b/bin/patches/512B5046.pnach @@ -0,0 +1,3 @@ +gametitle=minna daisuki katamari damashi NTSC JAP +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,001ce5d8,word,24020001 \ No newline at end of file diff --git a/bin/patches/5162BCCA.pnach b/bin/patches/5162BCCA.pnach new file mode 100644 index 0000000000..692831fa11 --- /dev/null +++ b/bin/patches/5162BCCA.pnach @@ -0,0 +1,5 @@ + +gametitle=Beach King Stunts Racer +comment=Skips Video by Rudy_x(sceMpegIsEnd) +//Skip Video +patch=0,EE,00197988,word,24020001 diff --git a/bin/patches/51D8A6A9.pnach b/bin/patches/51D8A6A9.pnach new file mode 100644 index 0000000000..cd5c2b3d6b --- /dev/null +++ b/bin/patches/51D8A6A9.pnach @@ -0,0 +1,20 @@ +gametitle=GTC Africa [SLES 50472] (E) +comment=since beta 01/MAR/2004 PLAYABLE!!! +//Unlock All Challenges +patch=0,EE,0010a8bc,word,ac23a588 +patch=0,EE,0010a8d4,word,ac23a588 +//Unlock All Championships +//patch=0,EE,0010a8dc,word,ac23a594 +//Unlock All Single Races +patch=0,EE,0010a8e4,word,ac23a598 +//"-no_music" +//patch=0,EE,0010a7e4,word,ac20a534 +//@1234 PlayMPEGFile +patch=0,EE,0010a824,word,ac20a554 +//@1242 DrawDebugText +patch=0,EE,0010a87c,word,ac20a578 +//Disable HUDRender +patch=0,EE,001996c0,word,03e00008 +patch=0,EE,001996c4,word,00000000 +//wm: fix VIF0_STAT (obsolete) +//patch=0,EE,001f027c,word,00000000 \ No newline at end of file diff --git a/bin/patches/51F91783.pnach b/bin/patches/51F91783.pnach new file mode 100644 index 0000000000..b0e5d58aeb --- /dev/null +++ b/bin/patches/51F91783.pnach @@ -0,0 +1,4 @@ +gametitle=Kaena [SLPS 25295] (J) +comment= +//ZeroGS Patch - Fix refresh bug +zerogs=00000010 diff --git a/bin/patches/53A803AF.pnach b/bin/patches/53A803AF.pnach new file mode 100644 index 0000000000..f1247c1588 --- /dev/null +++ b/bin/patches/53A803AF.pnach @@ -0,0 +1,4 @@ +gametitle=Kessen 2 [SLUS 20275] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos by General Plot +patch=0,EE,00108970,word,24020001 \ No newline at end of file diff --git a/bin/patches/53DF159B.pnach b/bin/patches/53DF159B.pnach new file mode 100644 index 0000000000..2e1120a337 --- /dev/null +++ b/bin/patches/53DF159B.pnach @@ -0,0 +1,16 @@ +gametitle=Max Payne MAIN_P.RUN [SLES 50325] (E) +comment=load ELF MAIN_P.RUN manually! +//deny video ELFs +patch=0,EE,0014BF5C,word,00000000 +patch=0,EE,0014E718,word,00000000 +//obsolete: +// don't flood console with bad VIF1_MARK messages +//patch=0,EE,0052f40c,word,00000000 +//WM: fix DMA1 +//patch=0,EE,00542ca8,word,1000000f +//skip bc0f +//patch=0,EE,00542e48,word,00000000 +//patch=0,EE,00542e74,word,00000000 +//WM: fix DMA9 +//patch=0,EE,005272e4,word,00000000 +//patch=0,EE,00527780,word,00000000 \ No newline at end of file diff --git a/bin/patches/54A548B4.pnach b/bin/patches/54A548B4.pnach new file mode 100644 index 0000000000..90b62039b1 --- /dev/null +++ b/bin/patches/54A548B4.pnach @@ -0,0 +1,6 @@ +gametitle= Crash N Burn +comment= Mpegisend +//Skip Videos +//patch=0,EE,0039fd50,word,24020001 +//ZeroGS Patch - GAME_EXACTCOLOR +zerogs=00000020 \ No newline at end of file diff --git a/bin/patches/54AD76D7.pnach b/bin/patches/54AD76D7.pnach new file mode 100644 index 0000000000..533d66fddc --- /dev/null +++ b/bin/patches/54AD76D7.pnach @@ -0,0 +1,8 @@ +gametitle=Lara Croft Tomb Raider - The Angel of Darkness [SLES 51227] (E) +comment= patches by nachbrenner +//Skip videos +patch=0,EE,00104de0,word,03E00008 +patch=0,EE,00104de4,word,24020001 +patch=0,EE,00104d60,word,03E00008 +patch=0,EE,00104d64,word,24020001 +patch=0,EE,0021bf68,word,24020001 \ No newline at end of file diff --git a/bin/patches/54D6BEE3.pnach b/bin/patches/54D6BEE3.pnach new file mode 100644 index 0000000000..9ec605ae7b --- /dev/null +++ b/bin/patches/54D6BEE3.pnach @@ -0,0 +1,4 @@ +gametitle=Swords of Destiny [SLES 53699] (E) +comment=patch by Refraction +//skip movies - brute force +patch=0,EE,00235440,word,10000003 diff --git a/bin/patches/561BE340.pnach b/bin/patches/561BE340.pnach new file mode 100644 index 0000000000..e6414cce66 --- /dev/null +++ b/bin/patches/561BE340.pnach @@ -0,0 +1,4 @@ +gametitle=Simple Series 2000 - Vol. 55 - The Catfight - Joneko Densetsu [SLPM 62494] (J) [561BE340] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00191560,word,24020001 \ No newline at end of file diff --git a/bin/patches/582EED0D.pnach b/bin/patches/582EED0D.pnach new file mode 100644 index 0000000000..d5ab4847f2 --- /dev/null +++ b/bin/patches/582EED0D.pnach @@ -0,0 +1,8 @@ +gametitle=Contra - Shattered Soldier [SLUS 20306] (U) +comment=patches by nachbrenner +//skip FMV (sceMpegIsEnd) +patch=0,EE,0063d950,word,24020001 +//suppress message "Gifstat write value = 4" +//patch=0,EE,0041be6c,word,00000000 +//suppress message "Gifstat write value = 0" +//patch=0,EE,0041bf1c,word,00000000 \ No newline at end of file diff --git a/bin/patches/586EA828.pnach b/bin/patches/586EA828.pnach new file mode 100644 index 0000000000..83aaf31ac8 --- /dev/null +++ b/bin/patches/586EA828.pnach @@ -0,0 +1,7 @@ +gametitle=MotoGP 2 [SLUS 20285] (U) +comment=patches by nachbrenner +//skip FMV +//patch=0,EE,00171fe8,word,24020001 +//All challenges complete +patch=0,EE,00133e54,word,20020002 +patch=0,EE,00133e58,word,a0a20000 \ No newline at end of file diff --git a/bin/patches/58EE1AFA.pnach b/bin/patches/58EE1AFA.pnach new file mode 100644 index 0000000000..5f35d8e6a1 --- /dev/null +++ b/bin/patches/58EE1AFA.pnach @@ -0,0 +1,4 @@ +gametitle=Breath Of Fire V: Drangon Quarter USA +comment=Skips videos +//Skip Videos +patch=0,EE,0010a758,word,24020001 \ No newline at end of file diff --git a/bin/patches/5A7635C1.pnach b/bin/patches/5A7635C1.pnach new file mode 100644 index 0000000000..84224a5e4d --- /dev/null +++ b/bin/patches/5A7635C1.pnach @@ -0,0 +1,4 @@ +gametitle=NRA Gun Club SLUS 21432 (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,001091c0,word,24020001 \ No newline at end of file diff --git a/bin/patches/5BBC2F40.pnach b/bin/patches/5BBC2F40.pnach new file mode 100644 index 0000000000..a8af9d2980 --- /dev/null +++ b/bin/patches/5BBC2F40.pnach @@ -0,0 +1,20 @@ +gametitle=Ridge Racer V [SCES 50000] (E) +comment= patches by Nachbrenner +// disable foreground 3D on car selection +//patch=0,EE,00201e3c,word,00000000 +// disable background 3D on car selection +//patch=0,EE,00227254,word,00000000 +//patch=0,EE,0027fac0,word,00000000 +//patch=0,EE,0027fbf4,word,00000000 +// +//skip VU0 Matrices (3D car select) +//patch=0,EE,0025a728,word,03e00008 +//patch=0,EE,0025a72c,word,00000000 +//patch=0,EE,0025aab8,word,03e00008 +//patch=0,EE,0025aabc,word,00000000 +//patch=0,EE,0025a6f8,word,03e00008 +//patch=0,EE,0025a6fc,word,00000000 +//patch=0,EE,00201540,word,03e00008 // ingame +//patch=0,EE,00201544,word,00000000 +//skip FlushCache before VU0 Sub/Scale/Copy Vector +//patch=0,EE,002a1298,word,00000000 \ No newline at end of file diff --git a/bin/patches/5BC8C9E8.pnach b/bin/patches/5BC8C9E8.pnach new file mode 100644 index 0000000000..a2c5166b69 --- /dev/null +++ b/bin/patches/5BC8C9E8.pnach @@ -0,0 +1,3 @@ +gametitle= Marvel Vs. Capcom 2 NTSC-J +comment= +fastmemory \ No newline at end of file diff --git a/bin/patches/5BE3F481.pnach b/bin/patches/5BE3F481.pnach new file mode 100644 index 0000000000..efa32a8924 --- /dev/null +++ b/bin/patches/5BE3F481.pnach @@ -0,0 +1,4 @@ +gametitle=James Cameron's Dark Angel [SLES 51333] (E) +comment= patches by Nachbrenner +//Skip FMV +// patch=0,EE,0021CC24,word,00000000 \ No newline at end of file diff --git a/bin/patches/5CCA0737.pnach b/bin/patches/5CCA0737.pnach new file mode 100644 index 0000000000..5e64e74a87 --- /dev/null +++ b/bin/patches/5CCA0737.pnach @@ -0,0 +1,7 @@ +gametitle=Barbarian [SLES 50972] (E) +comment=patches by Nachbrenner +//Skip SAMPLE.PSS +patch=0,EE,0010afc8,word,00000000 +//skip audio streams +//patch=0,EE,0016fb40,word,03e00008 +//patch=0,EE,0016fb44,word,00000000 \ No newline at end of file diff --git a/bin/patches/5D67AE48.pnach b/bin/patches/5D67AE48.pnach new file mode 100644 index 0000000000..5f01866529 --- /dev/null +++ b/bin/patches/5D67AE48.pnach @@ -0,0 +1,4 @@ +gametitle=Simple Series 2000 - Vol. 61 - The Oane Chapara [SLPM 62525] (J) [5D67AE48] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,001de758,word,24020001 \ No newline at end of file diff --git a/bin/patches/5DFBE144.pnach b/bin/patches/5DFBE144.pnach new file mode 100644 index 0000000000..4ebdb28054 --- /dev/null +++ b/bin/patches/5DFBE144.pnach @@ -0,0 +1,8 @@ +gametitle=The Getaway [SCES 51159] (E) +comment= patches by Nachbrenner +//skip IPU videos (for blockdump) +patch=0,EE,00296c14,word,00000000 +patch=0,EE,00223bc8,word,03e00008 +patch=0,EE,00223bcc,word,00000000 +patch=0,EE,002218a8,word,03e00008 +patch=0,EE,002218ac,word,00000000 \ No newline at end of file diff --git a/bin/patches/5E115FB6.pnach b/bin/patches/5E115FB6.pnach new file mode 100644 index 0000000000..abc56f22b5 --- /dev/null +++ b/bin/patches/5E115FB6.pnach @@ -0,0 +1,3 @@ +gametitle=GTA3 +//Skip Intro Videos ("InitMPEGPlayer__Fv") +patch=0,EE,0027ef00,word,1000000b \ No newline at end of file diff --git a/bin/patches/5EB127E7.pnach b/bin/patches/5EB127E7.pnach new file mode 100644 index 0000000000..95d24184d0 --- /dev/null +++ b/bin/patches/5EB127E7.pnach @@ -0,0 +1,4 @@ +gametitle= Gradius 3 & 4 [SLPM 62007] (J) +comment= +//ZeroGS Patch - GAME_INTERLACE2X +zerogs=00000004 \ No newline at end of file diff --git a/bin/patches/5F2A0E36.pnach b/bin/patches/5F2A0E36.pnach new file mode 100644 index 0000000000..5e72933c51 --- /dev/null +++ b/bin/patches/5F2A0E36.pnach @@ -0,0 +1,7 @@ +gametitle= Armored Core 2 - Another Age [SLPS 25040] (J) +//Skip Videos (sceMpegIsEnd) +// patch=0,EE,002c8a10,word,24020001 +// Skip Intros +// patch=0,EE,00100230,word,00000000 +// Lots of credits +// patch=1,EE,00319f00,word,00C0FFEE \ No newline at end of file diff --git a/bin/patches/60013EBD.pnach b/bin/patches/60013EBD.pnach new file mode 100644 index 0000000000..4b38998bf3 --- /dev/null +++ b/bin/patches/60013EBD.pnach @@ -0,0 +1,5 @@ +gametitle= Gran Turismo Concept 2002 Tokyo-Geneva [SCES 50858] (E) +comment= patches by Nachbrenner +//Skip Video +patch=1,EE,00129600,word,03e00008 +patch=1,EE,00129604,word,00000000 \ No newline at end of file diff --git a/bin/patches/60FA8C69.pnach b/bin/patches/60FA8C69.pnach new file mode 100644 index 0000000000..4850027a5a --- /dev/null +++ b/bin/patches/60FA8C69.pnach @@ -0,0 +1,4 @@ +gametitle=Biohazard 4 [SLPM 66213] (J) +comment= +//ZeroGS Patch - GAME_NOTARGETCLUT +zerogs=00001000 \ No newline at end of file diff --git a/bin/patches/6175FE7D.pnach b/bin/patches/6175FE7D.pnach new file mode 100644 index 0000000000..7f432472ab --- /dev/null +++ b/bin/patches/6175FE7D.pnach @@ -0,0 +1,4 @@ +gametitle=Guilty Gear XX - Accent Core [SLPM 66746] (J) [6175FE7D] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,002bcc48,word,24020001 \ No newline at end of file diff --git a/bin/patches/624F11F1.pnach b/bin/patches/624F11F1.pnach new file mode 100644 index 0000000000..ef96786c79 --- /dev/null +++ b/bin/patches/624F11F1.pnach @@ -0,0 +1,5 @@ +gametitle=Star Trek Voyager - Elite Force [SLES 50738] (E) +//Skip Videos +patch=0,EE,002945E8,word,24020001 +//suppress message: SPR0 stall 1 +patch=0,EE,0027fd18,byte,49 // 0027fd20: sw v0, $0000(v1) (D_CTRL) \ No newline at end of file diff --git a/bin/patches/625AF967.pnach b/bin/patches/625AF967.pnach new file mode 100644 index 0000000000..99e9073984 --- /dev/null +++ b/bin/patches/625AF967.pnach @@ -0,0 +1,4 @@ +gametitle= Nightmare Before Christmas - Oogie's Revenge [SLPM 65739] (J) +comment= +//ZeroGS Patch - GAME_TEXAHACK +zerogs=00000008 \ No newline at end of file diff --git a/bin/patches/627B8252.pnach b/bin/patches/627B8252.pnach new file mode 100644 index 0000000000..9941c7976f --- /dev/null +++ b/bin/patches/627B8252.pnach @@ -0,0 +1,9 @@ +gametitle=Garfield 2 - Tale of Two Kitties [SLES 54172] (E) +comment=patches by Nachbrenner +fastmemory +//Skip Videos (for blockdump) +patch=0,EE,00225bc0,word,03e00008 +patch=0,EE,00225bc4,word,00000000 +//Skip Music (for blockdump) +patch=0,EE,0033e270,word,03e00008 +patch=0,EE,0033e274,word,00000000 \ No newline at end of file diff --git a/bin/patches/62F6F886.pnach b/bin/patches/62F6F886.pnach new file mode 100644 index 0000000000..35787607bc --- /dev/null +++ b/bin/patches/62F6F886.pnach @@ -0,0 +1,4 @@ +gametitle=Die Hard - Vendetta Germany&Australia [SLES 51348] (E) +comment= patches by Nachbrenner +//Skip Videos +patch=0,EE,002570FC,word,00000000 \ No newline at end of file diff --git a/bin/patches/63F6B523.pnach b/bin/patches/63F6B523.pnach new file mode 100644 index 0000000000..6b4e3e6101 --- /dev/null +++ b/bin/patches/63F6B523.pnach @@ -0,0 +1,4 @@ +gametitle=Yu Gi Oh! Capsule Monster Coliseum (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00280f30,word,24020001 \ No newline at end of file diff --git a/bin/patches/68EAF48F.pnach b/bin/patches/68EAF48F.pnach new file mode 100644 index 0000000000..6b3c4b1656 --- /dev/null +++ b/bin/patches/68EAF48F.pnach @@ -0,0 +1,8 @@ +gametitle=Clock tower 3 NTSC japan +comment= +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,01818cb8,word,24020001 +//skip MovieEndCheck +//patch=0,EE,019415c8,word,70001428 +//skip MoviePlayCheck +//patch=0,EE,019415cc,word,70001428 \ No newline at end of file diff --git a/bin/patches/6926B199.pnach b/bin/patches/6926B199.pnach new file mode 100644 index 0000000000..a17be646b6 --- /dev/null +++ b/bin/patches/6926B199.pnach @@ -0,0 +1,4 @@ +gametitle=7 Sins [SLES 53280] (E) +comment=patch by Nachbrenner & Refraction +//fix "SleepThread vs. RTFSSIOP.IRX" +patch=0,EE,004afc7c,word,00000000 \ No newline at end of file diff --git a/bin/patches/692CBA8E.pnach b/bin/patches/692CBA8E.pnach new file mode 100644 index 0000000000..4958322c75 --- /dev/null +++ b/bin/patches/692CBA8E.pnach @@ -0,0 +1,4 @@ +gametitle=Need For Speed Most Wanted (SLES_535.57) +comment=Skips Video - deny file By Refraction +//Skip Videos +patch=0,EE,00242414,word,00000000 \ No newline at end of file diff --git a/bin/patches/6A4EFE60.pnach b/bin/patches/6A4EFE60.pnach new file mode 100644 index 0000000000..42b16ef9b7 --- /dev/null +++ b/bin/patches/6A4EFE60.pnach @@ -0,0 +1,4 @@ +gametitle=Final Fantasy X [SLPS 25050] (J) +comment= +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/6ADBC24B.pnach b/bin/patches/6ADBC24B.pnach new file mode 100644 index 0000000000..f39a15aec0 --- /dev/null +++ b/bin/patches/6ADBC24B.pnach @@ -0,0 +1,6 @@ +gametitle=Gradius III & IV [SLES 50038] (E) +comment=patches by nachbrenner +//Skip videos +patch=0,EE,001009e4,word,00000000 +//ZeroGS Patch - GAME_INTERLACE2X +zerogs=00000004 \ No newline at end of file diff --git a/bin/patches/6BA2F6B9.pnach b/bin/patches/6BA2F6B9.pnach new file mode 100644 index 0000000000..e8914822f5 --- /dev/null +++ b/bin/patches/6BA2F6B9.pnach @@ -0,0 +1,4 @@ +gametitle=Resident Evil 4 [SLES 53702] (E) +comment= +//ZeroGS Patch - Speed Up +zerogs=00200010 \ No newline at end of file diff --git a/bin/patches/6D70F0E0.pnach b/bin/patches/6D70F0E0.pnach new file mode 100644 index 0000000000..105934e88f --- /dev/null +++ b/bin/patches/6D70F0E0.pnach @@ -0,0 +1,4 @@ +gametitle=Anubis 2 [SLES 53571] (E) [6D70F0E0] +comment=Patch by CKemu +//Skip Videos (scempegisend) +patch=0,EE,002DAFD0,word,24020001 \ No newline at end of file diff --git a/bin/patches/6EA9DDA9.pnach b/bin/patches/6EA9DDA9.pnach new file mode 100644 index 0000000000..7a0d5c8756 --- /dev/null +++ b/bin/patches/6EA9DDA9.pnach @@ -0,0 +1,4 @@ +gametitle= Resident Evil: Code Veronica X [SLES 50306] (E) +comment= patches by Nachbrenner +//Skip Videos (sceMpegIsEnd) +//patch=0,EE,00109d48,word,24020001 \ No newline at end of file diff --git a/bin/patches/6FB69282.pnach b/bin/patches/6FB69282.pnach new file mode 100644 index 0000000000..1b8b628cb4 --- /dev/null +++ b/bin/patches/6FB69282.pnach @@ -0,0 +1,3 @@ +gametitle=GodHand [SLUS 21503] (U) +//fix DMA loop +patch=0,EE,002be3d8,word,24020001 \ No newline at end of file diff --git a/bin/patches/7098BE76.pnach b/bin/patches/7098BE76.pnach new file mode 100644 index 0000000000..82add338fa --- /dev/null +++ b/bin/patches/7098BE76.pnach @@ -0,0 +1,6 @@ +gametitle=Nano Breaker [SLKA 25263] (J) +comment=patches by Nachbrenner +//Skip Videos (sceMpegIsEnd) +patch=0,EE,0010a330,word,24020001 +//fix psxUNK crash: skip RotateThreadReadyQueue +patch=0,EE,0019f708,word,00000000 \ No newline at end of file diff --git a/bin/patches/7130C553.pnach b/bin/patches/7130C553.pnach new file mode 100644 index 0000000000..2a8454c4eb --- /dev/null +++ b/bin/patches/7130C553.pnach @@ -0,0 +1,5 @@ +gametitle=Guitaroo man +comment=Skip Videos +roundmode=DOWN,CHOP +//Skip Videos +patch=0,EE,0012aa28,word,24020001 \ No newline at end of file diff --git a/bin/patches/71584BAC.pnach b/bin/patches/71584BAC.pnach new file mode 100644 index 0000000000..5872a1a294 --- /dev/null +++ b/bin/patches/71584BAC.pnach @@ -0,0 +1,4 @@ +gametitle=Blowout [SLUS 20850] (U) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,002c4a18,word,03e00008 \ No newline at end of file diff --git a/bin/patches/722BBD62.pnach b/bin/patches/722BBD62.pnach new file mode 100644 index 0000000000..f627600cba --- /dev/null +++ b/bin/patches/722BBD62.pnach @@ -0,0 +1,4 @@ +gametitle=FIFA Football 2003 [SLES 51197] (E) +comment=patches by nachbrenner +// fix WaitForDMACompletion__Q212EAGLInternal6DmaMgr +patch=0,EE,0037b310,word,00000000 \ No newline at end of file diff --git a/bin/patches/7377BC6F.pnach b/bin/patches/7377BC6F.pnach new file mode 100644 index 0000000000..1bb1c190da --- /dev/null +++ b/bin/patches/7377BC6F.pnach @@ -0,0 +1,4 @@ +gametitle= Naruto Ultimate Ninja [SLUS 21358] (U) +comment= Video Skip by Refraction +//Skip Videos (sceMpegIsEnd) +patch=0,EE,0011bbb0,word,24020001 diff --git a/bin/patches/763D3BF9.pnach b/bin/patches/763D3BF9.pnach new file mode 100644 index 0000000000..500291d0f6 --- /dev/null +++ b/bin/patches/763D3BF9.pnach @@ -0,0 +1,8 @@ +gametitle=Spongebob Schwammkopf - Schlacht um Bikini Bottom German [SLES 51970] (E) +comment= patches by Nachbrenner +// skip FMV (sceMpegIsEnd) +patch=0,EE,001284a0,word,24020001 +//Have All Tasks Completed +patch=0,EE,0019D9F8,word,8D810020 +patch=0,EE,0019D9FC,word,24060002 +patch=0,EE,00194A04,word,A4260014 \ No newline at end of file diff --git a/bin/patches/77ECAAA0.pnach b/bin/patches/77ECAAA0.pnach new file mode 100644 index 0000000000..18579d17bd --- /dev/null +++ b/bin/patches/77ECAAA0.pnach @@ -0,0 +1,4 @@ +gametitle= Freestyle [SLUS 20367] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00107808,word,24020001 \ No newline at end of file diff --git a/bin/patches/78168525.pnach b/bin/patches/78168525.pnach new file mode 100644 index 0000000000..fd4758e9d2 --- /dev/null +++ b/bin/patches/78168525.pnach @@ -0,0 +1,3 @@ +gametitle=Off-Road Wide Open [SLES 50232] (E) +//skip FMV +patch=0,EE,002953f0,word,24020001 \ No newline at end of file diff --git a/bin/patches/789D6B71.pnach b/bin/patches/789D6B71.pnach new file mode 100644 index 0000000000..a3db4c0e4b --- /dev/null +++ b/bin/patches/789D6B71.pnach @@ -0,0 +1,4 @@ +gametitle=The Thing/Das Ding [SLES 50976] (G) +comment= patches by nachbrenner +//Skip videos (for blockdump) +patch=0,EE,006ef130,word,03e00008 \ No newline at end of file diff --git a/bin/patches/78E20421.pnach b/bin/patches/78E20421.pnach new file mode 100644 index 0000000000..6ca4472d83 --- /dev/null +++ b/bin/patches/78E20421.pnach @@ -0,0 +1,7 @@ +gametitle=Crimson Tears [SLPM 65575] (J) +comment=patches by Nachbrenner, ported from CMX' US codes +//Funds Increase When Buying Items From Shop +patch=0,EE,0029b8fc,word,00641821 +//Infinite Health +patch=0,EE,0028581c,word,C60101FC +patch=0,EE,00285820,word,E6010200 \ No newline at end of file diff --git a/bin/patches/7ABDBB5E.pnach b/bin/patches/7ABDBB5E.pnach new file mode 100644 index 0000000000..8335357d52 --- /dev/null +++ b/bin/patches/7ABDBB5E.pnach @@ -0,0 +1,4 @@ +gametitle=Gran Turismo 4 Chinese [SCAJ 30007] (J) +comment=patches by nachbrenner +//skip Videos +patch=1,EE,00100D84,word,24100001 \ No newline at end of file diff --git a/bin/patches/7BA0128E.pnach b/bin/patches/7BA0128E.pnach new file mode 100644 index 0000000000..7c20610151 --- /dev/null +++ b/bin/patches/7BA0128E.pnach @@ -0,0 +1,3 @@ +gametitle=play it - Chess Challenger [SLES 51630] (E) +comment=patches by nachbrenner +//skip "cdrom0:\DATA\FW_LOGO.PSS \ No newline at end of file diff --git a/bin/patches/7CD1CDCD.pnach b/bin/patches/7CD1CDCD.pnach new file mode 100644 index 0000000000..53f92ce462 --- /dev/null +++ b/bin/patches/7CD1CDCD.pnach @@ -0,0 +1,12 @@ +gametitle=Simple 2000 Series - Vol. 81 - The Chikyuu Boueigun 2 [SLPM 62652] (J) +comment= patches by Nachbrenner +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,0015f990,word,24020001 +//fix "utPs2HgsControl::SynchronizeDma(Timeout...)" +patch=0,EE,0012d114,word,10000012 +//skip IPU dither +patch=0,EE,00131f30,word,00000000 +// skip sceIpuSync +patch=0,EE,00164570,word,03e00008 +// fix infinite loop (iFlushCache / D_STAT related) +patch=0,EE,00126b30,word,00000000 \ No newline at end of file diff --git a/bin/patches/7D8F539A.pnach b/bin/patches/7D8F539A.pnach new file mode 100644 index 0000000000..eee8a0702a --- /dev/null +++ b/bin/patches/7D8F539A.pnach @@ -0,0 +1,7 @@ +gametitle=Devil May Cry PAL [SLES 50358] (U) [7D8F539A] +comment= +//Skip Videos +patch=0,EE,0015BC78,word,00000000 +patch=0,EE,001CE340,word,03E00008 +patch=0,EE,001CE344,word,00000000 +patch=0,EE,001CE8EC,word,70001428 \ No newline at end of file diff --git a/bin/patches/7EBEEBBD.pnach b/bin/patches/7EBEEBBD.pnach new file mode 100644 index 0000000000..bbc25b42b9 --- /dev/null +++ b/bin/patches/7EBEEBBD.pnach @@ -0,0 +1,4 @@ +gametitle= Klonoa 2 - Lunatea's Veil [SCES 50354] (E) [7EBEEBBD] +comment=Patch By CKemu +//Skips IUP blitz +patch=0,EE,003078F4,word,00000000 \ No newline at end of file diff --git a/bin/patches/7F6319C7.pnach b/bin/patches/7F6319C7.pnach new file mode 100644 index 0000000000..e73287db0f --- /dev/null +++ b/bin/patches/7F6319C7.pnach @@ -0,0 +1,4 @@ +gametitle=James Pond (E) +comment= patches by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00137cf0,word,24020001 \ No newline at end of file diff --git a/bin/patches/7FD7A1B9.pnach b/bin/patches/7FD7A1B9.pnach new file mode 100644 index 0000000000..87fad752d5 --- /dev/null +++ b/bin/patches/7FD7A1B9.pnach @@ -0,0 +1,8 @@ +gametitle=Jade Cocoon 2 [SLES 50735] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,00118110,word,24020001 +//Music off +patch=0,EE,00290eac,byte,00 +//Start new game with 10000 Yen +patch=0,EE,00291258,word,24022710 \ No newline at end of file diff --git a/bin/patches/83261085.pnach b/bin/patches/83261085.pnach new file mode 100644 index 0000000000..f7d0488c4d --- /dev/null +++ b/bin/patches/83261085.pnach @@ -0,0 +1,15 @@ +gametitle=Tenchu - Wrath Of Heaven [SLES 51402] (G) +comment= patches by Nachbrenner +//fix _waitIpuIdle for intro videos +patch=0,EE,00107a10,word,00000000 +//fix D3_CHCR for tutorial's mini-videos +patch=0,EE,00310dc4,word,00000000 +// +//obsolete: +//Skip sceIpuSync +//patch=0,EE,0010c810,word,03e00008 +//Skip sceDmaSendI | sceDmaSendN +//patch=0,EE,00176824,word,24020001 +//Skip Videos +//patch=0,EE,0010B288,word,24020001 //sceMpegIsEnd +//patch=0,EE,002fe2f0,word,00000000 //xref of sceMpegGetPicture \ No newline at end of file diff --git a/bin/patches/83D0CE43.pnach b/bin/patches/83D0CE43.pnach new file mode 100644 index 0000000000..d766b0efd6 --- /dev/null +++ b/bin/patches/83D0CE43.pnach @@ -0,0 +1,7 @@ +gametitle=Haven - Call of the King [SLES 51209] (E) +comment= patches by Nachbrenner +//disable 3D for menus and mashed music +patch=1,EE,00114c90,word,03e00008 +patch=1,EE,00114c94,word,00000000 +patch=1,EE,0010a980,word,03e00008 +patch=1,EE,0010a984,word,00000000 \ No newline at end of file diff --git a/bin/patches/844B58EE.pnach b/bin/patches/844B58EE.pnach new file mode 100644 index 0000000000..792dc2a316 --- /dev/null +++ b/bin/patches/844B58EE.pnach @@ -0,0 +1,4 @@ +gametitle=Tekken Tag Tournament (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,004b7220,word,24020001 \ No newline at end of file diff --git a/bin/patches/848C6247.pnach b/bin/patches/848C6247.pnach new file mode 100644 index 0000000000..733a947a4b --- /dev/null +++ b/bin/patches/848C6247.pnach @@ -0,0 +1,3 @@ +gametitle=Taiko no Tatsujin: Doki! NTSC JAP +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,001e7728,word,24020001 \ No newline at end of file diff --git a/bin/patches/85AE91B3.pnach b/bin/patches/85AE91B3.pnach new file mode 100644 index 0000000000..99915ba91f --- /dev/null +++ b/bin/patches/85AE91B3.pnach @@ -0,0 +1,5 @@ +gametitle= Gran Turismo 3 A-spec [SCUS 97102] (U) +comment=patches by nachbrenner +//Skip Opening Video +patch=1,EE,001287a8,word,03e00008 +patch=1,EE,001287ac,word,00000000 \ No newline at end of file diff --git a/bin/patches/85E92C92.pnach b/bin/patches/85E92C92.pnach new file mode 100644 index 0000000000..29e792e6e3 --- /dev/null +++ b/bin/patches/85E92C92.pnach @@ -0,0 +1,9 @@ +gametitle=The uchuujin NTSC J +comment= +//Skip Videos ("sceMpegIsEnd") +//patch=0,EE,00108fa0,word,24020001 +//Skip videos (custom) +patch=0,EE,001b4cd8,word,00000000 +//Skip videos (custom) +patch=0,EE,001b4c90,word,03e00008 +patch=0,EE,001b4c94,word,00000000 \ No newline at end of file diff --git a/bin/patches/8BC79F96.pnach b/bin/patches/8BC79F96.pnach new file mode 100644 index 0000000000..125fb2bb30 --- /dev/null +++ b/bin/patches/8BC79F96.pnach @@ -0,0 +1,9 @@ +gametitle=Formula One 2001 [SCES 50004] (E) +comment=patches by Nachbrenner +//Skip F1_Intro Video +//patch=0,EE,0010A1EC,word,00000000 +//Skip Credits Video +//patch=0,EE,0021A038,word,00000000 +//Skip FIA/ANIM256.FLC +//patch=0,EE,00162570,word,03e00008 +//patch=0,EE,00162574,word,00000000 \ No newline at end of file diff --git a/bin/patches/8BC95883.pnach b/bin/patches/8BC95883.pnach new file mode 100644 index 0000000000..f4c4125a6e --- /dev/null +++ b/bin/patches/8BC95883.pnach @@ -0,0 +1,4 @@ +gametitle= Sly 3 - Honor Among Thieves [SCUS 97464] (U) [8BC95883] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,002aa040,word,24020001 \ No newline at end of file diff --git a/bin/patches/8BE3D7B2.pnach b/bin/patches/8BE3D7B2.pnach new file mode 100644 index 0000000000..ed2bf4d930 --- /dev/null +++ b/bin/patches/8BE3D7B2.pnach @@ -0,0 +1,4 @@ +gametitle= Shadow Hearts [SLUS 20347] (U) +comment= +//ZeroGS Patch - GAME_NODEPTHUPDATE|GAME_AUTORESET|GAME_NOQUICKRESOLVE +zerogs=00000A02 \ No newline at end of file diff --git a/bin/patches/8DC64680.pnach b/bin/patches/8DC64680.pnach new file mode 100644 index 0000000000..2660e812b7 --- /dev/null +++ b/bin/patches/8DC64680.pnach @@ -0,0 +1,30 @@ +gametitle=Red Faction 1 [SLES 50279] (G) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,0024b488,word,24020001 +patch=0,EE,002044d0,word,03e00008 +patch=0,EE,002044d4,word,24020001 +// skip IDEC error +patch=0,EE,002146b8,word,00000000 +//patch=0,EE,001b1d78,word,24020001 +//Skip THQ Logo +patch=0,EE,001B0A78,word,24020001 +//Skip RF Trailer +patch=0,EE,0027D19C,word,24020001 +// Unendlich Gesundheit (Inf. health) +patch=0,EE,200C0220,word,3C0142C8 +patch=0,EE,200C0224,word,44810000 +patch=0,EE,200C0228,word,03E00008 +patch=0,EE,200C022C,word,E6000034 +patch=0,EE,2016937C,word,0C030088 +// Unendlich Schutzanzug (Inf. flak jacket) +patch=0,EE,200C0230,word,3C0142C8 +patch=0,EE,200C0234,word,44811000 +patch=0,EE,200C0238,word,03E00008 +patch=0,EE,200C023C,word,E6020038 +patch=0,EE,201693E0,word,0C03008C +// Unendlich Munition (Inf. Ammo) +patch=0,EE,20154854,word,24630000 +patch=0,EE,20154890,word,24630000 +// Unendlich Sprengladungen (Inf. Explosives) +patch=0,EE,201A19BC,word,24420000 \ No newline at end of file diff --git a/bin/patches/8FDE8E16.pnach b/bin/patches/8FDE8E16.pnach new file mode 100644 index 0000000000..7a1202332a --- /dev/null +++ b/bin/patches/8FDE8E16.pnach @@ -0,0 +1,6 @@ +gametitle= Spongebob Squarepants - Revenge of the Flying Dutchman [SLES 51285] (E) +comment=patches by Nachbrenner +//skip "SBPlayLogoMovie" +//patch=0,EE,004531bc,word,00000000 +//skip "SBPlayDemoMovie" +//patch=0,EE,004531e0,word,00000000 \ No newline at end of file diff --git a/bin/patches/901AAC09.pnach b/bin/patches/901AAC09.pnach new file mode 100644 index 0000000000..8a6a0dcba5 --- /dev/null +++ b/bin/patches/901AAC09.pnach @@ -0,0 +1,4 @@ + +gametitle=Haunting Ground [SLUS 21075] (U) +comment=ZeroGS fixes +zerogs=00018000 \ No newline at end of file diff --git a/bin/patches/93223BE4.pnach b/bin/patches/93223BE4.pnach new file mode 100644 index 0000000000..42abd09e6c --- /dev/null +++ b/bin/patches/93223BE4.pnach @@ -0,0 +1,7 @@ +gametitle=Formula 1 2003 [SCES 51592] (E) +comment=patches by Nachbrenner +//skip sceIpuSync +patch=0,EE,00379f78,word,03e00008 +//skip Videos +patch=0,EE,00376f80,word,03e00008 +patch=0,EE,00376f84,word,00000000 \ No newline at end of file diff --git a/bin/patches/934F9081.pnach b/bin/patches/934F9081.pnach new file mode 100644 index 0000000000..ceea700199 --- /dev/null +++ b/bin/patches/934F9081.pnach @@ -0,0 +1,4 @@ +gametitle= Neopets - The Darkest Faerie [SCUS 97367] (U) +comment= +//ZeroGS Patch - GAME_RESOLVEPROMOTED|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE +zerogs=00038000 \ No newline at end of file diff --git a/bin/patches/93F8A60B.pnach b/bin/patches/93F8A60B.pnach new file mode 100644 index 0000000000..eb5a07dc3c --- /dev/null +++ b/bin/patches/93F8A60B.pnach @@ -0,0 +1,4 @@ +gametitle=Kingdom Hearts II [SLPM 66233] (J) +// no depth resolves +zerogs=00008000 +fastmemory \ No newline at end of file diff --git a/bin/patches/941BB7D9.pnach b/bin/patches/941BB7D9.pnach new file mode 100644 index 0000000000..653d69738e --- /dev/null +++ b/bin/patches/941BB7D9.pnach @@ -0,0 +1,29 @@ +gametitle=Final Fantasy X Deutsch [SCES 50492] (G) +comment=patches by Nachbrenner +//crash fix: sceDmaSend +patch=0,EE,002dbacc,word,00000000 +patch=0,EE,002dbab8,word,00000000 +//fix DMA error: 0c0f0f00 - ipu1dma NULL! +patch=0,EE,0015ff68,word,00000000 +//Skip Videos +patch=0,EE,0015d1c0,word,100000b2 +//Skip sceIpuSync +//patch=0,EE,002e2530,word,03e00008 +//Use american savegames +//patch=0,EE,0024144c,word,24a56e60 +// +//Max GIL +patch=0,EE,201BE554,word,ACA3D218 +//Max HP +patch=0,EE,201C97B8,word,2402270F +patch=0,EE,201C97BC,word,AC620290 +//Max MP +patch=0,EE,201C97CC,word,2402270F +patch=0,EE,201C97D0,word,AC620294 +//No random battles +patch=0,EE,001be880,byte,00 +patch=0,EE,001bf2bc,byte,00 +//Hypermode +patch=0,EE,001164d0,word,3c014280 +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/94C56923.pnach b/bin/patches/94C56923.pnach new file mode 100644 index 0000000000..dbe41895dc --- /dev/null +++ b/bin/patches/94C56923.pnach @@ -0,0 +1,4 @@ +gametitle=Spyro: A Hero's Tale [SLUS 20884] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,003faaf0,word,24020001 \ No newline at end of file diff --git a/bin/patches/950241D3.pnach b/bin/patches/950241D3.pnach new file mode 100644 index 0000000000..47a2ade1f5 --- /dev/null +++ b/bin/patches/950241D3.pnach @@ -0,0 +1,4 @@ +gametitle=Fu-Un Bakumatsu-Den [SLPM 65813] (J) +comment= patches by nachbrenner +//Skip Videos +// patch=0,EE,00112f20,word,24020001 \ No newline at end of file diff --git a/bin/patches/951555A0.pnach b/bin/patches/951555A0.pnach new file mode 100644 index 0000000000..d54d9c627e --- /dev/null +++ b/bin/patches/951555A0.pnach @@ -0,0 +1,4 @@ +gametitle=Disgaea 2 - Cursed Memories [SLUS 21397] (U) +comment= +//ZeroGS Patch - GAME_NODEPTHRESOLVE +zerogs=00008000 \ No newline at end of file diff --git a/bin/patches/95BB1901.pnach b/bin/patches/95BB1901.pnach new file mode 100644 index 0000000000..f9f3163c9c --- /dev/null +++ b/bin/patches/95BB1901.pnach @@ -0,0 +1,3 @@ +gametitle= MX VS ATV Unleashed [SLUS 21104] (U) +//Skip Movies +patch=0,EE,00339bc0,word,24020001 \ No newline at end of file diff --git a/bin/patches/96B2F56D.pnach b/bin/patches/96B2F56D.pnach new file mode 100644 index 0000000000..a58502713f --- /dev/null +++ b/bin/patches/96B2F56D.pnach @@ -0,0 +1,7 @@ +gametitle=Devil May Cry [SLPM 65038] (J) +comment=Skips Movies +//skip Movie_Set +patch=0,EE,001cdea0,word,03e00008 +patch=0,EE,001cdea4,word,03e00008 +//skip MovieEndCheck +patch=0,EE,001ce44c,word,70001428 \ No newline at end of file diff --git a/bin/patches/96B76E56.pnach b/bin/patches/96B76E56.pnach new file mode 100644 index 0000000000..219d549519 --- /dev/null +++ b/bin/patches/96B76E56.pnach @@ -0,0 +1,9 @@ +gametitle=SX Superstars [SLES 51495](E) +comment= patches by Nachbrenner +//Skip Intro Movies (for blockdump) +patch=0,EE,002f1088,word,03e00008 +patch=0,EE,002f108c,word,00000000 +//No ingame music (for blockdump) +patch=0,EE,00223cac,word,00000000 +//fix IPU DMA for "MAINMENU.IPU" (enable to go ingame) +patch=0,EE,003befe4,word,001003e0 \ No newline at end of file diff --git a/bin/patches/96C20D6F.pnach b/bin/patches/96C20D6F.pnach new file mode 100644 index 0000000000..6423d90a16 --- /dev/null +++ b/bin/patches/96C20D6F.pnach @@ -0,0 +1,4 @@ +gametitle=Dynasty Warriors 4 Xtreme Legends +comment=Skips Videos by bositman +//Skip Videos +patch=0,EE,0010ab70,word,24020001 diff --git a/bin/patches/9AAC5309.pnach b/bin/patches/9AAC5309.pnach new file mode 100644 index 0000000000..5b0e191e64 --- /dev/null +++ b/bin/patches/9AAC5309.pnach @@ -0,0 +1,4 @@ +gametitle=Final Fantasy X-2 [SLES 51815] (E) +comment= +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/9AAC530D.pnach b/bin/patches/9AAC530D.pnach new file mode 100644 index 0000000000..6a7d91c363 --- /dev/null +++ b/bin/patches/9AAC530D.pnach @@ -0,0 +1,6 @@ +gametitle=Final Fantasy X-2 [SLES 51817] (G) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,0017e1e4,word,1000000d +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/9AC65D6A.pnach b/bin/patches/9AC65D6A.pnach new file mode 100644 index 0000000000..536ad772cd --- /dev/null +++ b/bin/patches/9AC65D6A.pnach @@ -0,0 +1,4 @@ +gametitle=Atelier Iris 2 +comment=Skips Video by bositman +//Skip Videos +patch=0,EE,002bdbb8,word,24020001 \ No newline at end of file diff --git a/bin/patches/9B1EE9EB.pnach b/bin/patches/9B1EE9EB.pnach new file mode 100644 index 0000000000..f4047b5c24 --- /dev/null +++ b/bin/patches/9B1EE9EB.pnach @@ -0,0 +1,4 @@ +gametitle=DNA - Dark Native Apostle [SLES 50202] (E) +comment=patches by Nachbrenner +//Skip PSSPLAY.ELF +patch=1,EE,001691F0,word,00000000 \ No newline at end of file diff --git a/bin/patches/9BE3F92D.pnach b/bin/patches/9BE3F92D.pnach new file mode 100644 index 0000000000..1bec0f42d0 --- /dev/null +++ b/bin/patches/9BE3F92D.pnach @@ -0,0 +1,4 @@ +gametitle=Psyvariar Complete Edition [SLPM62139] (J) +comment=patch by Nachbrenner +//skip movie +patch=0,EE,0010019c,word,00000000 \ No newline at end of file diff --git a/bin/patches/9D6F46F0.pnach b/bin/patches/9D6F46F0.pnach new file mode 100644 index 0000000000..848d09fd9d --- /dev/null +++ b/bin/patches/9D6F46F0.pnach @@ -0,0 +1,4 @@ +gametitle=GoDai Elemental Force [SLES 50704] (E) +comment= patches by Nachbrenner +//Skip Videos +patch=0,EE,00211c90,word,24020001 \ No newline at end of file diff --git a/bin/patches/A029B109.pnach b/bin/patches/A029B109.pnach new file mode 100644 index 0000000000..f55485ad24 --- /dev/null +++ b/bin/patches/A029B109.pnach @@ -0,0 +1,12 @@ +gametitle=Grand Prix Challenge [SLES 51296] (E) +comment=patches by Nachbrenner +//g_dmaMaximumWaitTime (default=40400000) +patch=0,EE,00484f88,word,00000000 +// +//for blockdump: +//Don't stream videos (press 3 times X after FIA logo) +patch=0,EE,003a6fc0,word,03e00008 // UpdateInternal__12fmvStreamPS2Fv +patch=0,EE,003a6fc4,word,00000000 +//skip Play__13slMusicStreamFv +patch=0,EE,002ea300,word,03e00008 +patch=0,EE,002ea304,word,00000000 \ No newline at end of file diff --git a/bin/patches/A1B752C7.pnach b/bin/patches/A1B752C7.pnach new file mode 100644 index 0000000000..e5e65c99b7 --- /dev/null +++ b/bin/patches/A1B752C7.pnach @@ -0,0 +1,4 @@ +gametitle=Sensible Soccer 2006 +comment=Patch By Refraction +//Skip Videos +patch=0,EE,0036b0a0,word,24020001 \ No newline at end of file diff --git a/bin/patches/A36CFF6C.pnach b/bin/patches/A36CFF6C.pnach new file mode 100644 index 0000000000..7a37c561c3 --- /dev/null +++ b/bin/patches/A36CFF6C.pnach @@ -0,0 +1,3 @@ +gametitle=Castlevania NTSC JPN +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,007296b0,word,24020001 \ No newline at end of file diff --git a/bin/patches/A39517AB.pnach b/bin/patches/A39517AB.pnach new file mode 100644 index 0000000000..ecd2924513 --- /dev/null +++ b/bin/patches/A39517AB.pnach @@ -0,0 +1,16 @@ +gametitle=Final Fantasy X [SCES 50490] (E) [A39517AB] +comment=Patch By CKemu +// +//Emulation Fixes +//Skip Videos [No longer required: 0.9.2-0715-i] +//patch=0,EE,0015d1c0,word,100000b2 +//Kill INIT SOUND [No longer required: 0.9.2-0715-i] +//patch=0,EE,00126074,word,00000000 +//Kill INIT VOICE [No longer required: 0.9.2-0715-i] +//patch=0,EE,00126088,word,00000000 +// +//Misc Patches +//Use (U) gamesaves [SLUS 20312] +//patch=0,EE,00241434,word,24a56e60 +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/A3ACF3C7.pnach b/bin/patches/A3ACF3C7.pnach new file mode 100644 index 0000000000..4760dedd3d --- /dev/null +++ b/bin/patches/A3ACF3C7.pnach @@ -0,0 +1,8 @@ +gametitle=Project Eden [SLES 50553] (E) +comment=patches by Nachbrenner +//Skip EC_LOGO Video +patch=0,EE,0013af54,word,00000000 +patch=0,EE,0013af60,word,00000000 +//Skip INTRO Video +patch=0,EE,0013b060,word,00000000 +patch=0,EE,0013b06c,word,00000000 \ No newline at end of file diff --git a/bin/patches/A3D63039.pnach b/bin/patches/A3D63039.pnach new file mode 100644 index 0000000000..5e1f3c79ee --- /dev/null +++ b/bin/patches/A3D63039.pnach @@ -0,0 +1,2 @@ +gametitle=Xenosaga Episode I - Der Wille zur Macht [SCAJ 30001] (J) +fastmemory diff --git a/bin/patches/A4E2C043.pnach b/bin/patches/A4E2C043.pnach new file mode 100644 index 0000000000..e29021c245 --- /dev/null +++ b/bin/patches/A4E2C043.pnach @@ -0,0 +1,8 @@ +gametitle=Homura [SLPM 62685] (J) +comment=patches by Nachbrenner +//Infinite Lives 00310758 +patch=0,EE,00225714,word,24030005 +//Infinite Health +patch=0,EE,00213884,word,00000000 +//Infinite Bombs 0031075C +patch=0,EE,00227174,word,24030005 \ No newline at end of file diff --git a/bin/patches/A5BF36A8.pnach b/bin/patches/A5BF36A8.pnach new file mode 100644 index 0000000000..07eb85777c --- /dev/null +++ b/bin/patches/A5BF36A8.pnach @@ -0,0 +1,3 @@ +gametitle=Paris-Dakar Rally [SLES 50212] (E) +//Skip Videos +patch=0,EE,001098e8,word,24020001 \ No newline at end of file diff --git a/bin/patches/A63C896C.pnach b/bin/patches/A63C896C.pnach new file mode 100644 index 0000000000..c9ff6f79a6 --- /dev/null +++ b/bin/patches/A63C896C.pnach @@ -0,0 +1,6 @@ +gametitle=Tsukyo Ni Saraba [SLPM 65826] (J) +comment=patches by Nachbrenner +//infinite ammo +patch=0,EE,003620b4,word,24040000 +//crash fix (nukes AI) +patch=0,EE,0025328c,word,00000000 \ No newline at end of file diff --git a/bin/patches/A719D130.pnach b/bin/patches/A719D130.pnach new file mode 100644 index 0000000000..99254094af --- /dev/null +++ b/bin/patches/A719D130.pnach @@ -0,0 +1,4 @@ +gametitle=Dynasty Warriors 5 XL +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,0011a240,word,24020001 \ No newline at end of file diff --git a/bin/patches/A74F99CD.pnach b/bin/patches/A74F99CD.pnach new file mode 100644 index 0000000000..9022547630 --- /dev/null +++ b/bin/patches/A74F99CD.pnach @@ -0,0 +1,4 @@ +gametitle=Psyvariar Revision [SLPM 62371] (J) +comment= +//Skip Videos +patch=0,EE,00155938,word,00000000 \ No newline at end of file diff --git a/bin/patches/A7A2F7C5.pnach b/bin/patches/A7A2F7C5.pnach new file mode 100644 index 0000000000..6b647345a7 --- /dev/null +++ b/bin/patches/A7A2F7C5.pnach @@ -0,0 +1,16 @@ +gametitle=Disney's Stitch: Experiment 626 [SCES 50960] (E) +comment=patches by Nachbrenner +//Skip Videos +//patch=0,EE,001edbe4,word,00000000 +//Skip music +patch=0,EE,001d1de0,word,03e00008 +patch=0,EE,001d1de4,word,00000000 +patch=1,EE,00A02FAC,word,00000000 +//MTGS vs. GS_CSR +//patch=0,EE,00269e00,word,00000000 +//patch=0,EE,00269de4,word,00000000 +//patch=0,EE,002e3d54,word,00000000 +//patch=0,EE,00269fdc,word,00000000 +//patch=0,EE,0026a018,word,00000000 +//sceGsExecStoreImage +//patch=0,EE,002e22ec,word,00000000 \ No newline at end of file diff --git a/bin/patches/A8083AE6.pnach b/bin/patches/A8083AE6.pnach new file mode 100644 index 0000000000..018be7b1be --- /dev/null +++ b/bin/patches/A8083AE6.pnach @@ -0,0 +1,4 @@ +gametitle=RC Revenge Pro [SLUS 20153] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,001ceaf8,word,24020001 \ No newline at end of file diff --git a/bin/patches/A88ACA28.pnach b/bin/patches/A88ACA28.pnach new file mode 100644 index 0000000000..e238e20ffe --- /dev/null +++ b/bin/patches/A88ACA28.pnach @@ -0,0 +1,9 @@ +gametitle=Codename: Kids Next Door - Operation V.I.D.E.O.G.A.M.E [SLES 53685] (E) +comment=patches by nachbrenner +// MMI fix: replace PINTH with PINTEH (obsolete) +//patch=0,EE,0037eef8,word,700212a9 +// skip SFD movies +patch=0,EE,00208220,word,03e00008 +patch=0,EE,00208224,word,00000000 +patch=0,EE,00208190,word,03e00008 +patch=0,EE,00208194,word,00000000 \ No newline at end of file diff --git a/bin/patches/A8A76AAC.pnach b/bin/patches/A8A76AAC.pnach new file mode 100644 index 0000000000..c62b917e8f --- /dev/null +++ b/bin/patches/A8A76AAC.pnach @@ -0,0 +1,4 @@ +gametitle=Guilty Gear XX - Accent Core [SLUS 21652] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,002bdb88,word,24020001 \ No newline at end of file diff --git a/bin/patches/A929A697.pnach b/bin/patches/A929A697.pnach new file mode 100644 index 0000000000..fcd8217b47 --- /dev/null +++ b/bin/patches/A929A697.pnach @@ -0,0 +1,3 @@ +gametitle=Turok: Evolution [SLES 51124] (G) +//Skip Videos (sceMpegIsEnd) +patch=0,EE,001cf280,word,24020001 \ No newline at end of file diff --git a/bin/patches/A9759015.pnach b/bin/patches/A9759015.pnach new file mode 100644 index 0000000000..6ac48fade0 --- /dev/null +++ b/bin/patches/A9759015.pnach @@ -0,0 +1,9 @@ +gametitle=Flucht von Monkey Island [SLES 50227] (G) +comment=patches by nachbrenner +//Skip Videos +//patch=0,EE,001c5220,word,24020001 +//patch=0,EE,0018b850,word,03E00008 +//patch=0,EE,0018b854,word,00000000 +//fix MTGS loop at GS_CSR in sceGsExecStoreImage +//patch=0,EE,001bb858,word,34630002 +//patch=0,EE,001bb888,word,34420002 \ No newline at end of file diff --git a/bin/patches/AA31B5BF.pnach b/bin/patches/AA31B5BF.pnach new file mode 100644 index 0000000000..6f5c0148ea --- /dev/null +++ b/bin/patches/AA31B5BF.pnach @@ -0,0 +1,4 @@ +gametitle=Metal Gear Solid 3 - Snake Eater [SLES 82013] (E) [086273D2] +comment=Patch By CKemu +//ZeroGS Patch - Required fixes to visuals +zerogs=06018000 \ No newline at end of file diff --git a/bin/patches/AC7E88D9.pnach b/bin/patches/AC7E88D9.pnach new file mode 100644 index 0000000000..6946863eb5 --- /dev/null +++ b/bin/patches/AC7E88D9.pnach @@ -0,0 +1,18 @@ +gametitle=Silpheed - The Lost Planet [SLES 50193] (E) +comment=patches by Nachbrenner +//default player name = PCSX2 +patch=0,EE,008c7a48,word,58534350 +patch=0,EE,008c7a4c,word,00000032 +//Skip SOLONT.PSS +patch=0,EE,0019561c,word,00000000 +//Skip ?PART.MOV +patch=0,EE,0019556c,word,00000000 +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,0025c3f8,word,24020001 +//Have All Weapons +patch=0,EE,0015a488,word,340201ff +patch=0,EE,0015b2f4,word,340201ff +// Inf. Shield (ASM) +patch=0,EE,0013DA0C,word,00000000 +//BGM off (for blockdump) +//patch=0,EE,008ac334,word,00000000 diff --git a/bin/patches/ACB1989A.pnach b/bin/patches/ACB1989A.pnach new file mode 100644 index 0000000000..b7bc8831ba --- /dev/null +++ b/bin/patches/ACB1989A.pnach @@ -0,0 +1,10 @@ +gametitle=Midnight Club II [SLES 51054] (E) +comment=patches by Nachbrenner +//skip videos (for blockdump) +//patch=0,EE,0013DB58,word,00000000 +//skip network check "BT_ok_to_initialize_networking" +//patch=0,EE,00123efc,word,00000000 +//music off (for blockdump) +//patch=1,EE,004ABB1C,word,00000000 +//crash fix SVN november (obsolete) +//patch=0,EE,0016c9a4,word,10000068 \ No newline at end of file diff --git a/bin/patches/AD9D2B54.pnach b/bin/patches/AD9D2B54.pnach new file mode 100644 index 0000000000..275e20dbf6 --- /dev/null +++ b/bin/patches/AD9D2B54.pnach @@ -0,0 +1,4 @@ +gametitle=worldtvfighters NTSC JPN +comment=skip intro pss +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,002d8df8,word,24020001 \ No newline at end of file diff --git a/bin/patches/ADAA1256.pnach b/bin/patches/ADAA1256.pnach new file mode 100644 index 0000000000..9dcb3ed3bb --- /dev/null +++ b/bin/patches/ADAA1256.pnach @@ -0,0 +1,8 @@ +gametitle=Steel Dragon EX [SLES 52482] (E) +comment=patches by Nachbrenner +//Disable BGM +//patch=0,EE,0015bcf8,word,00000000 +//Disable SE +//patch=0,EE,0015bcf0,word,00000000 +//Skip Memory Card check +patch=0,EE,0015bd00,word,00000000 \ No newline at end of file diff --git a/bin/patches/AE0E098F.pnach b/bin/patches/AE0E098F.pnach new file mode 100644 index 0000000000..0f363aaff5 --- /dev/null +++ b/bin/patches/AE0E098F.pnach @@ -0,0 +1,6 @@ +gametitle=Indiana Jones und die Legende der Kaisergruft [SLES 50838] (G) +comment=patches by Nachbrenner +//Skip Videos +//patch=1,EE,00100624,word,24020000 // legal.pss +//patch=1,EE,0012c414,word,24020000 // leclogo.pss +//patch=1,EE,00100674,word,24020000 // cslogo.pss \ No newline at end of file diff --git a/bin/patches/AE3EAA05.pnach b/bin/patches/AE3EAA05.pnach new file mode 100644 index 0000000000..f49aa73313 --- /dev/null +++ b/bin/patches/AE3EAA05.pnach @@ -0,0 +1,14 @@ +gametitle=Kingdom Hearts German [SCES 50969] (G) +comment=patches by Nachbrenner +//Size modifier +// default = 1 (3f800000) +// patch=0,EE,001243BC,word,3c014000 //double size +//Hypermode +// default = 1.2 (3f999999) +// max =5 (40a00000) +//Don't use "Hypermode" in cutscenes. +//patch=0,EE,0011007c,word,3c0140a0 +//patch=0,EE,00110080,word,34210000 +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory \ No newline at end of file diff --git a/bin/patches/AE9EB9A0.pnach b/bin/patches/AE9EB9A0.pnach new file mode 100644 index 0000000000..ce1dc32b43 --- /dev/null +++ b/bin/patches/AE9EB9A0.pnach @@ -0,0 +1,4 @@ +gametitle=TD overdrive - The Brotherhood Of Speed [SLES 50778] (E) +comment= patches by Nachbrenner +// skip FMV sceMpegIsEnd +// patch=1,EE,0030aad0,word,24020001 \ No newline at end of file diff --git a/bin/patches/AEDAEE99.pnach b/bin/patches/AEDAEE99.pnach new file mode 100644 index 0000000000..6430aa7a2f --- /dev/null +++ b/bin/patches/AEDAEE99.pnach @@ -0,0 +1,3 @@ +gametitle=GodHand [SLPM 66550] (J) +//fix DMA loop +patch=0,EE,002bdd28,word,24020001 \ No newline at end of file diff --git a/bin/patches/AFAC88EF.pnach b/bin/patches/AFAC88EF.pnach new file mode 100644 index 0000000000..4d1594a88e --- /dev/null +++ b/bin/patches/AFAC88EF.pnach @@ -0,0 +1,14 @@ +gametitle= Dirge Of Cerberus - Final Fantasy VII [SLPM 66271] (J) +comment=patches by Nachbrenner +//Fix "**** SQTHREAD ERROR : BAD LOCK STATE" +patch=0,EE,0047d228,word,00000000 +//Skip Videos +// patch=0,EE,00255264,word,00000000 +//fix ingame DMA0 +patch=0,EE,00283060,word,10000020 +//fix ingame DMA8 +//patch=0,EE,0031d714,word,00000000 +//fix ingame VIF1_STAT +//patch=0,EE,004a184c,word,00000000 +//Skip mcDelayThread +//patch=0,EE,004b7c88,word,00000000 \ No newline at end of file diff --git a/bin/patches/B0621C55.pnach b/bin/patches/B0621C55.pnach new file mode 100644 index 0000000000..44f0cf38cd --- /dev/null +++ b/bin/patches/B0621C55.pnach @@ -0,0 +1,4 @@ +gametitle=Fighting Angels [SLES 53408] (E) [B0621C55] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00192a38,word,24020001 \ No newline at end of file diff --git a/bin/patches/B0AE1898.pnach b/bin/patches/B0AE1898.pnach new file mode 100644 index 0000000000..4c5335f3f9 --- /dev/null +++ b/bin/patches/B0AE1898.pnach @@ -0,0 +1,6 @@ +gametitle=smackdown shut your mouth +comment=patched by prafull +//skip sceipusync +patch=0,EE,0010b880,word,00000000 +patch=0,EE,0010b798,word,00000000 +patch=0,EE,0010b7c8,word,00000000 \ No newline at end of file diff --git a/bin/patches/B130E5BA.pnach b/bin/patches/B130E5BA.pnach new file mode 100644 index 0000000000..96c8abad25 --- /dev/null +++ b/bin/patches/B130E5BA.pnach @@ -0,0 +1,3 @@ +gametitle=katamari damashi NTSC JAP +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,0018d798,word,24020001 \ No newline at end of file diff --git a/bin/patches/B1BE3E51.pnach b/bin/patches/B1BE3E51.pnach new file mode 100644 index 0000000000..47cf390a3d --- /dev/null +++ b/bin/patches/B1BE3E51.pnach @@ -0,0 +1,6 @@ +gametitle=Whiplash [SLES 51958] (E) +comment=patches by nachbrenner +//Skip error printing +//patch=0,EE,00252d88,word,00000000 +//fix jalr crash +patch=0,EE,0040db84,word,0010c370 \ No newline at end of file diff --git a/bin/patches/B234036E.pnach b/bin/patches/B234036E.pnach new file mode 100644 index 0000000000..c8d3f50980 --- /dev/null +++ b/bin/patches/B234036E.pnach @@ -0,0 +1,4 @@ +gametitle=Guilty Gear X2 Reload [SLES 52967] (E) [B234036E] +comment=Patch By CKemu +//Skip Videos +patch=0,EE,00250418,word,24020001 \ No newline at end of file diff --git a/bin/patches/B2BDE9F3.pnach b/bin/patches/B2BDE9F3.pnach new file mode 100644 index 0000000000..b3053be360 --- /dev/null +++ b/bin/patches/B2BDE9F3.pnach @@ -0,0 +1,6 @@ +gametitle=Hisshou Pachinko Pachi-Slot Kouryoku Series Vol. 7 - Fever Powerful Zero [SLPS 25697] (J) +//Skip sceIpuSync +patch=0,EE,00100dd8,word,03e00008 +//IPU VQ fix +patch=0,EE,0021b2cc,word,00000000 // ? +patch=0,EE,0021b08c,word,00000000 // _pictureData0 \ No newline at end of file diff --git a/bin/patches/B338676A.pnach b/bin/patches/B338676A.pnach new file mode 100644 index 0000000000..015616c412 --- /dev/null +++ b/bin/patches/B338676A.pnach @@ -0,0 +1,6 @@ +gametitle=Summoner 2 [SLES 51142] (G) +comment=patches by Nachbrenner +//skip FMV (sceMpegIsEnd) +// patch=0,EE,001c6638,word,24020001 +//brute force fix GS_CSR +// patch=0,EE,00188604,word,fc620000 // sd v0, $0000(v1) diff --git a/bin/patches/B34DA141.pnach b/bin/patches/B34DA141.pnach new file mode 100644 index 0000000000..b6bfb87561 --- /dev/null +++ b/bin/patches/B34DA141.pnach @@ -0,0 +1,8 @@ +gametitle=The Mouse Police [SLES 52370] (E) +comment=patches by Nachbrenner +//Skip LOGO.PSS +//patch=0,EE,0012945c,word,24020001 +//Skip INTRO.PSS +//patch=0,EE,001293f8,word,24020001 +//Skip DALAMATIO.PSS +//patch=0,EE,0012a69c,word,00000000 \ No newline at end of file diff --git a/bin/patches/B36EE21E.pnach b/bin/patches/B36EE21E.pnach new file mode 100644 index 0000000000..3bb63f76de --- /dev/null +++ b/bin/patches/B36EE21E.pnach @@ -0,0 +1,5 @@ +gametitle=IndyCar Series [SLUS 20641] (U) +//skip BjMediaVideoPlay +patch=0,EE,00204b38,word,24020001 +patch=0,EE,001ea500,word,03e00008 +patch=0,EE,001ea504,word,00000000 \ No newline at end of file diff --git a/bin/patches/B590CE04.pnach b/bin/patches/B590CE04.pnach new file mode 100644 index 0000000000..d26b8bbd29 --- /dev/null +++ b/bin/patches/B590CE04.pnach @@ -0,0 +1,5 @@ +gametitle=Gran Turismo 3 A-Spec [SCES 50294] (E) [B590CE04] +comment= patches by Nachbrenner +//Skip Intro Videos +patch=1,EE,00128c60,word,03e00008 +patch=1,EE,00128c64,word,00000000 \ No newline at end of file diff --git a/bin/patches/B82E4C4B.pnach b/bin/patches/B82E4C4B.pnach new file mode 100644 index 0000000000..f0e3ab08ef --- /dev/null +++ b/bin/patches/B82E4C4B.pnach @@ -0,0 +1,4 @@ +gametitle=Play it Pinball (E) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,002b29d0,word,24020001 \ No newline at end of file diff --git a/bin/patches/B884B6E9.pnach b/bin/patches/B884B6E9.pnach new file mode 100644 index 0000000000..788cbc1e06 --- /dev/null +++ b/bin/patches/B884B6E9.pnach @@ -0,0 +1,4 @@ +gametitle=Gottlieb Pinball Classics (E) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00107ce0,word,24020001 \ No newline at end of file diff --git a/bin/patches/B99379B7.pnach b/bin/patches/B99379B7.pnach new file mode 100644 index 0000000000..d30bb15652 --- /dev/null +++ b/bin/patches/B99379B7.pnach @@ -0,0 +1,4 @@ +gametitle=Erementar Gerad [SLPM 62623] (J) +comment=patches by Nachbrenner +//Skip Videos (sceMpegIsEnd) +patch=0,EE,002861c8,word,24020001 \ No newline at end of file diff --git a/bin/patches/BB3D833A.pnach b/bin/patches/BB3D833A.pnach new file mode 100644 index 0000000000..b36fce72bc --- /dev/null +++ b/bin/patches/BB3D833A.pnach @@ -0,0 +1,4 @@ +gametitle= Final Fantasy X [SLUS 20312] (U) +comment= +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/BD3DBCF9.pnach b/bin/patches/BD3DBCF9.pnach new file mode 100644 index 0000000000..169e6b5ba6 --- /dev/null +++ b/bin/patches/BD3DBCF9.pnach @@ -0,0 +1,4 @@ +gametitle=Dynasty Warriors 4 - Empires +comment=Skips Video +//Skip Video +patch=0,EE,00211544,word,00000000 \ No newline at end of file diff --git a/bin/patches/BF5D9AEC.pnach b/bin/patches/BF5D9AEC.pnach new file mode 100644 index 0000000000..94f6564ce3 --- /dev/null +++ b/bin/patches/BF5D9AEC.pnach @@ -0,0 +1,4 @@ +gametitle=Gungrave US/C NTSC +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,001c07b0,word,24020001 \ No newline at end of file diff --git a/bin/patches/C04FB5FD.pnach b/bin/patches/C04FB5FD.pnach new file mode 100644 index 0000000000..640b1bb039 --- /dev/null +++ b/bin/patches/C04FB5FD.pnach @@ -0,0 +1,4 @@ +gametitle=Superior Defender Gundam Force Showdown! [SLUS 20698] (U) +comment= Captain Gundam The Secret Defender Of Neotopia +//Skip Videos +patch=0,EE,0010c660,word,24020001 \ No newline at end of file diff --git a/bin/patches/C0D6A139.pnach b/bin/patches/C0D6A139.pnach new file mode 100644 index 0000000000..29d1452360 --- /dev/null +++ b/bin/patches/C0D6A139.pnach @@ -0,0 +1,4 @@ +gametitle=Romance Of The Three Kingdoms XI [SLUS 21584] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,0010b690,word,24020001 \ No newline at end of file diff --git a/bin/patches/C1625F14.pnach b/bin/patches/C1625F14.pnach new file mode 100644 index 0000000000..44adb215b1 --- /dev/null +++ b/bin/patches/C1625F14.pnach @@ -0,0 +1,9 @@ +gametitle=Midnight Club II [SLUS20209] (U) +comment=patches by Nachbrenner +//skip videos +patch=0,EE,0013D5E0,word,00000000 +//skip sceIpuSync +patch=0,EE,003ef4e8,word,03e00008 +patch=0,EE,003ef4ec,word,00000000 +//skip network check "BT_ok_to_initialize_networking" +patch=0,EE,00123c70,word,00000000 \ No newline at end of file diff --git a/bin/patches/C1767D64.pnach b/bin/patches/C1767D64.pnach new file mode 100644 index 0000000000..3498d7ece8 --- /dev/null +++ b/bin/patches/C1767D64.pnach @@ -0,0 +1,5 @@ +gametitle=Gitaroo man (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,0012ea48,word,24020001 +roundmode=DOWN,CHOP \ No newline at end of file diff --git a/bin/patches/C1B141D6.pnach b/bin/patches/C1B141D6.pnach new file mode 100644 index 0000000000..b75485c8f3 --- /dev/null +++ b/bin/patches/C1B141D6.pnach @@ -0,0 +1,7 @@ +gametitle= 25 To Life [SLUS 21016] (U) +comment=patches by Nachbrenner and Refraction +//Skip Videos (for blockdump) +// patch=0,EE,0040ade4,word,00000000 +//fix EEREC: LQ qw align +// patch=0,EE,0043b31c,word,78c40020 // intro (fixed) +patch=0,EE,0022d3d0,word,79050020 // ingame (still borked) \ No newline at end of file diff --git a/bin/patches/C220951A.pnach b/bin/patches/C220951A.pnach new file mode 100644 index 0000000000..64923c4f0c --- /dev/null +++ b/bin/patches/C220951A.pnach @@ -0,0 +1,5 @@ +gametitle= Gran Turismo Concept 2001 Tokyo [SCPS 15010] (J) +comment= patches by Nachbrenner +//Skip Video +patch=1,EE,001295b8,word,03e00008 +patch=1,EE,001295bc,word,00000000 \ No newline at end of file diff --git a/bin/patches/C398F477.pnach b/bin/patches/C398F477.pnach new file mode 100644 index 0000000000..3a722e70d3 --- /dev/null +++ b/bin/patches/C398F477.pnach @@ -0,0 +1,4 @@ +gametitle=Kingdom Hearts II [SLES 54114] (E) +// no depth resolves +zerogs=00008000 +fastmemory \ No newline at end of file diff --git a/bin/patches/C3D28EB9.pnach b/bin/patches/C3D28EB9.pnach new file mode 100644 index 0000000000..15b7fcfeae --- /dev/null +++ b/bin/patches/C3D28EB9.pnach @@ -0,0 +1,4 @@ +gametitle=Shadow Hearts - From The New World +comment=Skips Video,by bositman +//Skip Videos +patch=0,EE,00208b68,word,24020001 \ No newline at end of file diff --git a/bin/patches/C4467D30.pnach b/bin/patches/C4467D30.pnach new file mode 100644 index 0000000000..35049d9921 --- /dev/null +++ b/bin/patches/C4467D30.pnach @@ -0,0 +1,4 @@ +gametitle=World Rally Championship 3 [SLPM 65583] (J) +comment= patch by Nachbrenner +//Skip sceIpuSync +patch=1,EE,0027c808,word,03e00008 \ No newline at end of file diff --git a/bin/patches/C488EC04.pnach b/bin/patches/C488EC04.pnach new file mode 100644 index 0000000000..3be542cd3f --- /dev/null +++ b/bin/patches/C488EC04.pnach @@ -0,0 +1,8 @@ +gametitle=Ninjabread Man [SLES 53570] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,00169e78,word,03e00008 +//Skip Music (for blockdumps) +//patch=0,EE,00106d6c,word,00000000 +//patch=0,EE,0014352c,word,00000000 +//patch=0,EE,00151738,word,00000000 \ No newline at end of file diff --git a/bin/patches/C4A60986.pnach b/bin/patches/C4A60986.pnach new file mode 100644 index 0000000000..76e3f134a8 --- /dev/null +++ b/bin/patches/C4A60986.pnach @@ -0,0 +1,4 @@ +gametitle=Sega Ages 2500 Volume 01 - Phantasy Star generation:1 (J) +comment=patches by Nachbrenner +//Get money for buying wares +patch=0,EE,0010e690,word,00a2282d \ No newline at end of file diff --git a/bin/patches/C502AD6E.pnach b/bin/patches/C502AD6E.pnach new file mode 100644 index 0000000000..ee561afdf0 --- /dev/null +++ b/bin/patches/C502AD6E.pnach @@ -0,0 +1,8 @@ +gametitle=Wallace & Grommit in Projekt Zoo [SLES 52026] (G) +comment=patches by Nachbrenner +//skip FMV (for blockdump) +//patch=0,EE,0046bf70,word,24020001 +//skip sceIpuSync +patch=0,EE,00472c78,word,03e00008 +//Disable Music & Speech (for blockdump) +//patch=0,EE,005767ac,word,001001d0 \ No newline at end of file diff --git a/bin/patches/C5DEFEA0.pnach b/bin/patches/C5DEFEA0.pnach new file mode 100644 index 0000000000..93734b5964 --- /dev/null +++ b/bin/patches/C5DEFEA0.pnach @@ -0,0 +1,7 @@ +gametitle=Okami [SLPM 66375] (J) +//fix sceSifDmaStat loop +patch=0,EE,00212a78,word,24020001 +//ZeroGS Patch - GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE +zerogs=00058000 +//alternate ZeroGS Patch for speed VS pretty GFX - disable all lighting|blur effects +//zerogs=01000000 \ No newline at end of file diff --git a/bin/patches/C9246E9C.pnach b/bin/patches/C9246E9C.pnach new file mode 100644 index 0000000000..cb4b99874f --- /dev/null +++ b/bin/patches/C9246E9C.pnach @@ -0,0 +1,4 @@ +gametitle=Tetris Worlds NTSC +comment=Skips videos +//Skip Videos +patch=0,EE,002cea30,word,24020001 \ No newline at end of file diff --git a/bin/patches/C9C145BF.pnach b/bin/patches/C9C145BF.pnach new file mode 100644 index 0000000000..0c9ae7878a --- /dev/null +++ b/bin/patches/C9C145BF.pnach @@ -0,0 +1,10 @@ +gametitle=Crazy Taxi [SLES 50215] (E) +comment= patches by Nachbrenner +//skip movie "PlaySega" +patch=0,EE,001a42d0,word,03e00008 +patch=0,EE,001a42d4,word,00000000 +//skip movie "PlayAcclaim" +patch=0,EE,001a4468,word,03e00008 +patch=0,EE,001a446c,word,00000000 +//skip nlWaitVSync / TaxiBlankInterrupt +//patch=0,EE,0019cf10,word,03e00008 \ No newline at end of file diff --git a/bin/patches/CA295E61.pnach b/bin/patches/CA295E61.pnach new file mode 100644 index 0000000000..01f54701d2 --- /dev/null +++ b/bin/patches/CA295E61.pnach @@ -0,0 +1,4 @@ +gametitle= Atelier Iris Grand Phantasm [SLPM 66436] (J) +comment= Video Skip before MCD screen by Refraction +//Nop out IPU routine +patch=0,EE,00135cdc,word,00000000 \ No newline at end of file diff --git a/bin/patches/CA6243B9.pnach b/bin/patches/CA6243B9.pnach new file mode 100644 index 0000000000..83ae2208da --- /dev/null +++ b/bin/patches/CA6243B9.pnach @@ -0,0 +1,9 @@ +gametitle=Gran Turismo 4 Prologue China [PBPX 95524] (J) +comment=patches by Nachbrenner +//fix IPU DMA +patch=1,EE,00166814,word,00000000 +patch=1,EE,003a36b8,word,00000000 +patch=1,EE,003a36f4,word,00000000 +//Skip Videos +patch=1,EE,001e3718,word,03e00008 +patch=1,EE,001e371c,word,00000000 diff --git a/bin/patches/CB4EBD11.pnach b/bin/patches/CB4EBD11.pnach new file mode 100644 index 0000000000..ec94b28e1a --- /dev/null +++ b/bin/patches/CB4EBD11.pnach @@ -0,0 +1,7 @@ +gametitle=Dakar 2 [SLES 50879] (E) +comment= patches by Nachbrenner +//Skip Intro Videos +patch=0,EE,00139188,word,10000029 +//KOSMOS fix +patch=0,EE,00171874,word,00000000 // D1_CHCR +patch=0,EE,001718c4,word,00000000 // GS_CSR \ No newline at end of file diff --git a/bin/patches/CBBC2E7F.pnach b/bin/patches/CBBC2E7F.pnach new file mode 100644 index 0000000000..9b587c326d --- /dev/null +++ b/bin/patches/CBBC2E7F.pnach @@ -0,0 +1,15 @@ +gametitle= WRC Rally Evolved [SCES 53247] (E) +comment=patches by Nachbrenner +//fix delay slot violation (obsolete) +//patch=1,EE,003cc890,word,19c0004d +//patch=1,EE,003cc894,word,01ad6826 +//patch=1,EE,003cbc78,word,01ce7026 +//patch=1,EE,003cbc7c,word,19a0006c +//patch=1,EE,003cc528,word,01ce7026 +//patch=1,EE,003cc52c,word,19a0000c +//patch=1,EE,003cc46c,word,01ce7026 +//patch=1,EE,003cc470,word,19a0000f +//patch=1,EE,003cc704,word,01ce7026 +//patch=1,EE,003cc708,word,19a0000f +//patch=1,EE,003ccbb4,word,01ce7026 +//patch=1,EE,003ccbb8,word,19a00011 \ No newline at end of file diff --git a/bin/patches/CC4B9CDE.pnach b/bin/patches/CC4B9CDE.pnach new file mode 100644 index 0000000000..f1cd3dc816 --- /dev/null +++ b/bin/patches/CC4B9CDE.pnach @@ -0,0 +1,6 @@ +gametitle=Samurai Warriors 2 [SLUS 21462] (U) +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,0013CD10,word,24020001 +//ZeroGS patches +zerogs=00000002 \ No newline at end of file diff --git a/bin/patches/CC6AA742.pnach b/bin/patches/CC6AA742.pnach new file mode 100644 index 0000000000..5f5e24886b --- /dev/null +++ b/bin/patches/CC6AA742.pnach @@ -0,0 +1,4 @@ +gametitle=FIFA Soccer 2004 [SLKA 25087] (J) +comment=patches by Nachbrenner +//boot with english texts +patch=0,EE,00329b7c,word,24709430 \ No newline at end of file diff --git a/bin/patches/CDE7C999.pnach b/bin/patches/CDE7C999.pnach new file mode 100644 index 0000000000..d44a0fea0b --- /dev/null +++ b/bin/patches/CDE7C999.pnach @@ -0,0 +1,22 @@ +gametitle= World Rally Championship 4 [SCES 52389] (E) +comment=patches by Nachbrenner +//fix caching issue +patch=1,EE,004007e0,word,0080f809 +// +//skip STR videos (for blockdump) +patch=1,EE,00354850,word,00000000 +//Skip sceIpuSync +patch=1,EE,003811f0,word,03e00008 +//Disable video rendering (for speedy menus) +//patch=1,EE,00353960,word,00000000 +//fix delay slot violations (obsolete) +//patch=1,EE,002d8328,word,01ce7026 +//patch=1,EE,002d832c,word,19a0006c +//patch=1,EE,002d8c8c,word,01ce7026 +//patch=1,EE,002d8c90,word,19a0000f +//patch=1,EE,002d8f14,word,01ce7026 +//patch=1,EE,002d8f18,word,19a0000f +//patch=1,EE,002d8d48,word,01ce7026 +//patch=1,EE,002d8d4c,word,19a0000c +//patch=1,EE,002d9770,word,01ce7026 +//patch=1,EE,002d9774,word,19a00011 \ No newline at end of file diff --git a/bin/patches/CF11CD83.pnach b/bin/patches/CF11CD83.pnach new file mode 100644 index 0000000000..a05bc62ee9 --- /dev/null +++ b/bin/patches/CF11CD83.pnach @@ -0,0 +1,6 @@ +gametitle=Samurai Warriors +comment=Skips Video,by bositman +//Skip Videos +patch=0,EE,00126af0,word,24020001 +//ZeroGS patch - GAME_AUTORESET +zerogs=00000002 \ No newline at end of file diff --git a/bin/patches/CFB873AD.pnach b/bin/patches/CFB873AD.pnach new file mode 100644 index 0000000000..a1f4bfc877 --- /dev/null +++ b/bin/patches/CFB873AD.pnach @@ -0,0 +1,6 @@ +gametitle=Need For Speed Underground 2 [SLES52725] (E) +comment= patches by Nachbrenner +//Skip videos +patch=0,EE,0042b400,word,24020001 +//skip "RCMPDecodeBuffer" causing cputlbmiss +patch=0,EE,0025a970,word,00000000 \ No newline at end of file diff --git a/bin/patches/D03BEF2A.pnach b/bin/patches/D03BEF2A.pnach new file mode 100644 index 0000000000..f7d3ae2ad3 --- /dev/null +++ b/bin/patches/D03BEF2A.pnach @@ -0,0 +1,13 @@ +gametitle=Max Payne 2 - The Fall Of Max Payne [SLES 52336] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,002c8650,word,03e00008 +patch=0,EE,002c8654,word,00000000 +//fix obscure inf. loop +patch=0,EE,001aa610,word,03e00008 +patch=0,EE,001aa614,word,24020000 +//Language Modifier (sceScfGetLanguage) +patch=0,EE,00445ce4,word,24020001 // english +//patch=0,EE,00445ce4,word,24020004 // deutsch +//fix "SleepThread vs. RTFSSIOP.IRX" +patch=0,EE,001b3208,word,00000000 \ No newline at end of file diff --git a/bin/patches/D08648B6.pnach b/bin/patches/D08648B6.pnach new file mode 100644 index 0000000000..e6d7127a74 --- /dev/null +++ b/bin/patches/D08648B6.pnach @@ -0,0 +1,3 @@ +gametitle=Robocop [SLES 51374] (E) +//Skip Videos +patch=0,EE,002ebf70,word,24020001 \ No newline at end of file diff --git a/bin/patches/D0E17D26.pnach b/bin/patches/D0E17D26.pnach new file mode 100644 index 0000000000..054c61e9e9 --- /dev/null +++ b/bin/patches/D0E17D26.pnach @@ -0,0 +1,4 @@ +gametitle=rtype final japan +comment= +//Skip Videos ("sceMpegIsEnd") +patch=0,EE,00116b88,word,24020001 \ No newline at end of file diff --git a/bin/patches/D1ACD489.pnach b/bin/patches/D1ACD489.pnach new file mode 100644 index 0000000000..f571d8e3d9 --- /dev/null +++ b/bin/patches/D1ACD489.pnach @@ -0,0 +1,5 @@ +gametitle=Syberia [SLES 51393] (E) +//Skip Videos +// patch=0,EE,0013E608,word,24020001 +//skip video "INTRO_MICROIDS.BIK" +// patch=0,EE,00297780,word,00000000 \ No newline at end of file diff --git a/bin/patches/D4781770.pnach b/bin/patches/D4781770.pnach new file mode 100644 index 0000000000..349fdaeb04 --- /dev/null +++ b/bin/patches/D4781770.pnach @@ -0,0 +1,6 @@ +gametitle=Donald Duck Phantomias Platyrhynchos Kineticus [SLES 50773] (E) +comment=patches by Nachbrenner +//Skip Videos +// patch=0,EE,00108ef0,word,24020001 // (sceMpegIsEnd) +//fix inf. loop on video playback +patch=0,EE,002d8b94,word,00000000 \ No newline at end of file diff --git a/bin/patches/D48A92E1.pnach b/bin/patches/D48A92E1.pnach new file mode 100644 index 0000000000..18b0cf3d89 --- /dev/null +++ b/bin/patches/D48A92E1.pnach @@ -0,0 +1,10 @@ +gametitle=Lotus Challenge [SLES 50230] (E) +comment=patches by nachbrenner +//skip Videos +//patch=0,EE,001cc5dc,word,00000000 +//recheck_wheel_connection__10cPauseMenuFv +patch=0,EE,001fef50,word,03e00008 +patch=0,EE,001fef54,word,00000000 +//getClosestPoint__FP11sGameSplineP8sVector4PiPScPi +patch=0,EE,00198d40,word,03e00008 +patch=0,EE,00198d44,word,00000000 \ No newline at end of file diff --git a/bin/patches/D4FB6049.pnach b/bin/patches/D4FB6049.pnach new file mode 100644 index 0000000000..ecbe60f9d3 --- /dev/null +++ b/bin/patches/D4FB6049.pnach @@ -0,0 +1,3 @@ +gametitle=Pryzm - Chapter One: The Dark Unicorn PAL +//Skip Videos +patch=0,EE,0036aa60,word,24020001 \ No newline at end of file diff --git a/bin/patches/D79F697A.pnach b/bin/patches/D79F697A.pnach new file mode 100644 index 0000000000..8a6c607417 --- /dev/null +++ b/bin/patches/D79F697A.pnach @@ -0,0 +1,4 @@ +gametitle=Capcom VS. SNK 2 [PBPX 95201] (J) [D79F697A] +comment= +//Fix for PCSX2 VM Build Speed Issue +fastmemory \ No newline at end of file diff --git a/bin/patches/DA0535FD.pnach b/bin/patches/DA0535FD.pnach new file mode 100644 index 0000000000..8e8053c59c --- /dev/null +++ b/bin/patches/DA0535FD.pnach @@ -0,0 +1,4 @@ +gametitle=Kingdom Hearts II [SLUS 21005] (U) +// no depth resolves +zerogs=00008000 +fastmemory \ No newline at end of file diff --git a/bin/patches/DAC14B26.pnach b/bin/patches/DAC14B26.pnach new file mode 100644 index 0000000000..7b3786a230 --- /dev/null +++ b/bin/patches/DAC14B26.pnach @@ -0,0 +1,7 @@ +gametitle=SWAT - Global Strike Team Germany/Australia [SLES 52097] (E) +comment=patches by nachbrenner +//multi-ELF fix / skip videos +patch=0,EE,004721B4,word,00100100 +patch=0,EE,004738C4,word,00100100 +//Enable Gore +patch=0,EE,00274AAC,word,24040001 \ No newline at end of file diff --git a/bin/patches/DB719F5C.pnach b/bin/patches/DB719F5C.pnach new file mode 100644 index 0000000000..3f1c3ff476 --- /dev/null +++ b/bin/patches/DB719F5C.pnach @@ -0,0 +1,7 @@ +gametitle=Gumball 3000 [SLES 50984] (E) +comment=patches by Nachbrenner +//skip FMV +// patch=0,EE,00209c00,word,03e00008 +// patch=0,EE,00209c04,word,00000000 +//go ingame w/o 3D +//patch=0,EE,00167da0,word,00000000 \ No newline at end of file diff --git a/bin/patches/DC85FC8F.pnach b/bin/patches/DC85FC8F.pnach new file mode 100644 index 0000000000..c615044aab --- /dev/null +++ b/bin/patches/DC85FC8F.pnach @@ -0,0 +1,4 @@ +gametitle=Worms 4 - Mayhem [SLES 53096] (E) [DC85FC8F] +comment=Patch by CKemu +//Skip SceMpegIsEnd +patch=0,EE,00520d40,word,24020001 \ No newline at end of file diff --git a/bin/patches/DCC4EEEA.pnach b/bin/patches/DCC4EEEA.pnach new file mode 100644 index 0000000000..793e3feccb --- /dev/null +++ b/bin/patches/DCC4EEEA.pnach @@ -0,0 +1,10 @@ +gametitle=Primal [SCES 51135] (E) +comment=patches by Nachbrenner +//Skip Videos +patch=0,EE,003ec7d4,word,00000000 +patch=0,EE,003ec4e0,word,00000000 +//Skip custom IPU routine +patch=0,EE,003c44ac,word,00000000 +patch=0,EE,003c4568,word,00000000 +//fix VU wm 25.06.06 +patch=0,EE,00391efc,word,00000000 \ No newline at end of file diff --git a/bin/patches/DDA2FA6A.pnach b/bin/patches/DDA2FA6A.pnach new file mode 100644 index 0000000000..66b2077f2b --- /dev/null +++ b/bin/patches/DDA2FA6A.pnach @@ -0,0 +1,4 @@ +gametitle=Rayman M [SLES 50457] (E) [DDA2FA6A] +comment=Patch by CKemu +//Kill '002FA6A0 1060FFFA: beq v1, zero, 0x002FA68C' (IPU) +patch=0,EE,002FA6A0,word,00000000 \ No newline at end of file diff --git a/bin/patches/DEFA4763.pnach b/bin/patches/DEFA4763.pnach new file mode 100644 index 0000000000..91645d6612 --- /dev/null +++ b/bin/patches/DEFA4763.pnach @@ -0,0 +1,5 @@ + +gametitle=Shadow Hearts [SLES 50677] (E) +comment= +//ZeroGS patches +zerogs=00008812 \ No newline at end of file diff --git a/bin/patches/E0127F2D.pnach b/bin/patches/E0127F2D.pnach new file mode 100644 index 0000000000..a0549a59b7 --- /dev/null +++ b/bin/patches/E0127F2D.pnach @@ -0,0 +1,5 @@ +gametitle=Flatout +comment=Skip Videos sceMpegIsEnd +//patch by refraction +//Skip Videos +patch=0,EE,002b2490,word,24020001 \ No newline at end of file diff --git a/bin/patches/E0426FC6.pnach b/bin/patches/E0426FC6.pnach new file mode 100644 index 0000000000..c82fdc79f0 --- /dev/null +++ b/bin/patches/E0426FC6.pnach @@ -0,0 +1,8 @@ +gametitle=Okage Shadow King [SCUS 97129](U) +comment= patches by Nachbrenner +// kill menu 3D (obsolete) +//patch=0,EE,00100fb8,word,24030000 +//LP=99 +patch=1,EE,005c1be0,word,00000063 +//Lots of Money +patch=1,EE,005c1b6c,word,07F819A0 \ No newline at end of file diff --git a/bin/patches/E0DADD1A.pnach b/bin/patches/E0DADD1A.pnach new file mode 100644 index 0000000000..c1ad2d82bb --- /dev/null +++ b/bin/patches/E0DADD1A.pnach @@ -0,0 +1,5 @@ + +gametitle=ESPN NBA 2night +comment=Skips Video by Rudy_x (sceMpegIsEnd) +//Skip Videos +patch=0,EE,00129c60,word,24020001 diff --git a/bin/patches/E138094A.pnach b/bin/patches/E138094A.pnach new file mode 100644 index 0000000000..383f714d96 --- /dev/null +++ b/bin/patches/E138094A.pnach @@ -0,0 +1,7 @@ +gametitle=F1 Championship Season 2000 [SLUS 20103] (U) +comment=patches by nachbrenner +//Skip Intro Videos +patch=0,EE,00221a14,word,00000000 +//Skip All Videos +patch=0,EE,00241bc0,word,03E00008 +patch=0,EE,00241bc4,word,00000000 \ No newline at end of file diff --git a/bin/patches/E1C5F607.pnach b/bin/patches/E1C5F607.pnach new file mode 100644 index 0000000000..1d50d09442 --- /dev/null +++ b/bin/patches/E1C5F607.pnach @@ -0,0 +1,6 @@ +gametitle= Pirates of the Caribbean +comment=by Refraction +//"Data/Movies/%s" +patch=0,EE,0031ed84,word,00000000 +//"Data/Movies/%s/%s" +patch=0,EE,0031edac,word,00000000 diff --git a/bin/patches/E1FD9A2D.pnach b/bin/patches/E1FD9A2D.pnach new file mode 100644 index 0000000000..e6231813d9 --- /dev/null +++ b/bin/patches/E1FD9A2D.pnach @@ -0,0 +1,6 @@ +gametitle=FFX-2 International + Last Mission +comment=Skip videos by General Plot +//Skip Videos +patch=0,EE,003338a0,word,24020001 +//ZeroGS Patch - GAME_FFXHACK +zerogs=00000080 \ No newline at end of file diff --git a/bin/patches/E2F1DB6B.pnach b/bin/patches/E2F1DB6B.pnach new file mode 100644 index 0000000000..7c1ad233ef --- /dev/null +++ b/bin/patches/E2F1DB6B.pnach @@ -0,0 +1,6 @@ +gametitle=GT Racers [SLES 52602] (E) +comment=patches by nachbrenner +//Skip INTRO.PSS +patch=0,EE,00160a2c,word,00000000 +//fix "sound end command" +patch=0,EE,00167f14,word,00000000 \ No newline at end of file diff --git a/bin/patches/E4A275B2.pnach b/bin/patches/E4A275B2.pnach new file mode 100644 index 0000000000..4c8f12f583 --- /dev/null +++ b/bin/patches/E4A275B2.pnach @@ -0,0 +1,4 @@ +gametitle=Glass rose (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,0010c1c0,word,24020001 diff --git a/bin/patches/E677B8F1.pnach b/bin/patches/E677B8F1.pnach new file mode 100644 index 0000000000..7a4406b314 --- /dev/null +++ b/bin/patches/E677B8F1.pnach @@ -0,0 +1,7 @@ +gametitle=Pirates - The Legend Of Black Cat [SLES 50680] (E) +comment= patches by Nachbrenner +//skip MPC videos +//patch=0,EE,00101504,word,24020000 // intro videos +//patch=0,EE,00100aa4,word,10000013 // amulett video +//fix IPU Wait Time Out +//patch=0,EE,001a7854,word,00000000 \ No newline at end of file diff --git a/bin/patches/E7A35274.pnach b/bin/patches/E7A35274.pnach new file mode 100644 index 0000000000..ef59911b2a --- /dev/null +++ b/bin/patches/E7A35274.pnach @@ -0,0 +1,4 @@ +gametitle=WE7 +comment= patch by Prafull +//skip movie "WE7_OP" +patch=0,EE,012ba4a0,word,00000000 \ No newline at end of file diff --git a/bin/patches/E906EA37.pnach b/bin/patches/E906EA37.pnach new file mode 100644 index 0000000000..097dfd2cfb --- /dev/null +++ b/bin/patches/E906EA37.pnach @@ -0,0 +1,7 @@ +gametitle=Gran Turismo 4 First Preview [PCPX 96649] (J) +comment=patches by mdr61 +//Timelimit counter stop +patch=0,EE,002EF740,word,00000000 +//Pause counter stop +patch=0,EE,002C7394,word,00000000 +patch=0,EE,002F1F40,word,00000000 \ No newline at end of file diff --git a/bin/patches/EAD76247.pnach b/bin/patches/EAD76247.pnach new file mode 100644 index 0000000000..28d8035b42 --- /dev/null +++ b/bin/patches/EAD76247.pnach @@ -0,0 +1,19 @@ +gametitle= Transformers [SLES 52388] (E) +comment=patches by Nachbrenner +//skip loops: DMA1 vs. VIF1_FBRST vs. mfc0 v0, Count +patch=0,EE,0025d660,word,00000000 +patch=0,EE,0025d7bc,word,00000000 +patch=0,EE,0025d75c,word,00000000 +//skip loop at "warp gate animation" (cop2 BC2T called) +patch=0,EE,0026eee8,word,00000000 +// +//skip FMV (for blockdump) +patch=0,EE,00134070,word,24020001 +patch=0,EE,0034d630,word,00000000 +//skip sound streaming partially (for blockdump) +patch=0,EE,002e75c0,word,03e00008 +patch=0,EE,002e75c4,word,00000000 +patch=0,EE,00281780,word,03e00008 +patch=0,EE,00281784,word,00000000 +patch=0,EE,001f05f8,word,00000000 +patch=1,EE,008F9AC0,word,00000000 \ No newline at end of file diff --git a/bin/patches/EADE437E.pnach b/bin/patches/EADE437E.pnach new file mode 100644 index 0000000000..8f339ed4ec --- /dev/null +++ b/bin/patches/EADE437E.pnach @@ -0,0 +1,4 @@ +//fix inf. $GP loop +//patch=0,EE,00165068,word,24020000 +//fix GS_IMR crash = no 3D gfx +//patch=0,EE,00174360,word,3403ff00 \ No newline at end of file diff --git a/bin/patches/EDD7E0FF.pnach b/bin/patches/EDD7E0FF.pnach new file mode 100644 index 0000000000..a30078988f --- /dev/null +++ b/bin/patches/EDD7E0FF.pnach @@ -0,0 +1,4 @@ +gametitle=F1 Racing Championship DE/FR [SLES 50046] (E) +comment= patches by Nachbrenner +//Skip Videos +patch=0,EE,0024ddc0,word,24020001 \ No newline at end of file diff --git a/bin/patches/EE838B5C.pnach b/bin/patches/EE838B5C.pnach new file mode 100644 index 0000000000..c16a57f4c0 --- /dev/null +++ b/bin/patches/EE838B5C.pnach @@ -0,0 +1,7 @@ +gametitle= Boku to mao (aka Okage Shadow King) [SCPS 11008] (J) +comment= patches by Nachbrenner +// ee838b5c.pnach +//Skip OP.PSS +patch=0,EE,001d6258,word,24020001 +// Money=9999 +patch=0,EE,00124bf4,word,2403270f \ No newline at end of file diff --git a/bin/patches/EEC3B310.pnach b/bin/patches/EEC3B310.pnach new file mode 100644 index 0000000000..7248440e28 --- /dev/null +++ b/bin/patches/EEC3B310.pnach @@ -0,0 +1,9 @@ +gametitle=Shin Sangoku Musou 2 [SLPM 65053] (J) +comment=patches by nachbrenner +//Skip Videos +patch=0,EE,0019d360,word,24020001 +//Skip Intro +patch=0,EE,00160ac0,word,03E00008 +patch=0,EE,00160ac4,word,00000000 +//GS_CSR fix +patch=0,EE,0017647c,word,34840001 diff --git a/bin/patches/EEE2F6A3.pnach b/bin/patches/EEE2F6A3.pnach new file mode 100644 index 0000000000..d7b600b0e3 --- /dev/null +++ b/bin/patches/EEE2F6A3.pnach @@ -0,0 +1,4 @@ +gametitle=Neo Contra [SLES 52510] (E) [EEE2F6A3] +comment=Skips Video (sceMpegIsEnd) +//Skip Videos +patch=0,EE,003b8050,word,24020001 \ No newline at end of file diff --git a/bin/patches/EF5B6AAD.pnach b/bin/patches/EF5B6AAD.pnach new file mode 100644 index 0000000000..90d038e1fc --- /dev/null +++ b/bin/patches/EF5B6AAD.pnach @@ -0,0 +1,4 @@ +gametitle= Graffiti Kingdom [SLUS 21136] (U) +comment= Video Skip by Refraction +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00108590,word,24020001 \ No newline at end of file diff --git a/bin/patches/EF9E43EF.pnach b/bin/patches/EF9E43EF.pnach new file mode 100644 index 0000000000..d540d2e8ce --- /dev/null +++ b/bin/patches/EF9E43EF.pnach @@ -0,0 +1,5 @@ +gametitle= Ys: Ark Of Napishtim [SLUS 20980] (U) +comment=Skips Videos +//patches by Refraction +//Skip Videos +patch=0,EE,00224620,word,00000000 \ No newline at end of file diff --git a/bin/patches/F1370E83.pnach b/bin/patches/F1370E83.pnach new file mode 100644 index 0000000000..9c02d65fd6 --- /dev/null +++ b/bin/patches/F1370E83.pnach @@ -0,0 +1,4 @@ +gametitle=Enter the matrix +comment=Skips Video (sceMpegIsEnd)/bored +//Skip Videos +patch=0,EE,003d07c0,word,24020001 \ No newline at end of file diff --git a/bin/patches/F22CDDAF.pnach b/bin/patches/F22CDDAF.pnach new file mode 100644 index 0000000000..a989ec5514 --- /dev/null +++ b/bin/patches/F22CDDAF.pnach @@ -0,0 +1,4 @@ +gametitle= Gradius 3 & 4 [SLUS 20040] (U) +comment= +//ZeroGS Patch - GAME_INTERLACE2X +zerogs=00000004 \ No newline at end of file diff --git a/bin/patches/F266B00B.pnach b/bin/patches/F266B00B.pnach new file mode 100644 index 0000000000..386f8c2cdb --- /dev/null +++ b/bin/patches/F266B00B.pnach @@ -0,0 +1,4 @@ +gametitle=Kingdom Hearts II Final Mix [SLPM 66675] (J) +// no depth resolves +zerogs=00008000 +fastmemory \ No newline at end of file diff --git a/bin/patches/F4992CC1.pnach b/bin/patches/F4992CC1.pnach new file mode 100644 index 0000000000..dc79ad2d3f --- /dev/null +++ b/bin/patches/F4992CC1.pnach @@ -0,0 +1,4 @@ +gametitle=switch (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00108ce8,word,24020001 \ No newline at end of file diff --git a/bin/patches/F52FB2BE.pnach b/bin/patches/F52FB2BE.pnach new file mode 100644 index 0000000000..d260513ef5 --- /dev/null +++ b/bin/patches/F52FB2BE.pnach @@ -0,0 +1,5 @@ +gametitle=Kingdom Hearts [SCES 50967] (E) +comment= +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory \ No newline at end of file diff --git a/bin/patches/F56C7948.pnach b/bin/patches/F56C7948.pnach new file mode 100644 index 0000000000..830b3ecea5 --- /dev/null +++ b/bin/patches/F56C7948.pnach @@ -0,0 +1,4 @@ +gametitle=heavy metal thunder (J) +comment= patch by parotaku +//Skip Videos (sceMpegIsEnd) +patch=0,EE,00108890,word,24020001 diff --git a/bin/patches/F5C7B45F.pnach b/bin/patches/F5C7B45F.pnach new file mode 100644 index 0000000000..7bff741c3e --- /dev/null +++ b/bin/patches/F5C7B45F.pnach @@ -0,0 +1,4 @@ +gametitle=Need For Speed Underground 2 +comment=Video Skip by Refraction +//Skip videos +patch=0,EE,00293538,word,00000000 \ No newline at end of file diff --git a/bin/patches/F6DC728D.pnach b/bin/patches/F6DC728D.pnach new file mode 100644 index 0000000000..ed5a878393 --- /dev/null +++ b/bin/patches/F6DC728D.pnach @@ -0,0 +1,5 @@ +gametitle= Kingdom Hearts [SCES 50968] (F) +comment= +//ZeroGS Patch - GAME_QUICKRESOLVE1 +zerogs=00000400 +fastmemory \ No newline at end of file diff --git a/bin/patches/F6F9A91D.pnach b/bin/patches/F6F9A91D.pnach new file mode 100644 index 0000000000..99ad41eea7 --- /dev/null +++ b/bin/patches/F6F9A91D.pnach @@ -0,0 +1,4 @@ +gametitle= The Thing (pal) +comment= +//Skip Videos +patch=0,EE,00131dc0,word,24020001 \ No newline at end of file diff --git a/bin/patches/F758234F.pnach b/bin/patches/F758234F.pnach new file mode 100644 index 0000000000..a791dff918 --- /dev/null +++ b/bin/patches/F758234F.pnach @@ -0,0 +1,7 @@ +//skip BGM (for blockdump) +patch=0,EE,002cc1f0,word,03e00008 +patch=0,EE,002cc1f4,word,00000000 +patch=0,EE,002cc610,word,03e00008 +patch=0,EE,002cc614,word,00000000 +patch=0,EE,002cc430,word,03e00008 +patch=0,EE,002cc434,word,00000000 \ No newline at end of file diff --git a/bin/patches/F9E575D0.pnach b/bin/patches/F9E575D0.pnach new file mode 100644 index 0000000000..54c3edce90 --- /dev/null +++ b/bin/patches/F9E575D0.pnach @@ -0,0 +1,4 @@ +gametitle=Die Hard - Vendetta [SLES 51348] (E) +comment= patches by Nachbrenner +//Skip Videos +patch=0,EE,002570FC,word,00000000 \ No newline at end of file diff --git a/bin/patches/FA7E3081.pnach b/bin/patches/FA7E3081.pnach new file mode 100644 index 0000000000..a252a14454 --- /dev/null +++ b/bin/patches/FA7E3081.pnach @@ -0,0 +1,7 @@ +gametitle=kata +comment= +//Skip Intro Videos +patch=0,EE,0018e9e8,word,24020001 +//0018e4c8 +//0018e11c +//0018e020 \ No newline at end of file diff --git a/bin/patches/FAC64195.pnach b/bin/patches/FAC64195.pnach new file mode 100644 index 0000000000..19cd26fbc5 --- /dev/null +++ b/bin/patches/FAC64195.pnach @@ -0,0 +1,3 @@ +gametitle=Dead To Rights [SLES 51581] (E) +//Skip Movies +// patch=0,EE,002201a0,word,24020001 \ No newline at end of file diff --git a/bin/patches/FB0E6D72.pnach b/bin/patches/FB0E6D72.pnach new file mode 100644 index 0000000000..600a838630 --- /dev/null +++ b/bin/patches/FB0E6D72.pnach @@ -0,0 +1,6 @@ +gametitle=God Of War [SCES 53133] (E) +comment=patches by Nachbrenner +//D_STAT fix for Kosmos 0.95.7+ +patch=0,EE,0026dce8,word,00000000 +//crash fix ingame (breaks hero's legs) +patch=0,EE,00111604,word,24060000 \ No newline at end of file diff --git a/bin/patches/FC618D82.pnach b/bin/patches/FC618D82.pnach new file mode 100644 index 0000000000..feec7d2025 --- /dev/null +++ b/bin/patches/FC618D82.pnach @@ -0,0 +1,8 @@ +gametitle=Energy Airforce [SLPM 65177] (J) +comment=patches by Nachbrenner +//Skip Videos +//patch=0,EE,00109f48,word,24020001 +//Lots of fuel +patch=0,EE,002ef328,word,47110000 +//Infinite fuel +patch=0,EE,00195964,word,00000000 \ No newline at end of file diff --git a/bin/patches/FEA030CB.pnach b/bin/patches/FEA030CB.pnach new file mode 100644 index 0000000000..70dc28e417 --- /dev/null +++ b/bin/patches/FEA030CB.pnach @@ -0,0 +1,23 @@ +gametitle=Le Mans 24 Hours (24 Heures Du Mans) [SLES 50131] (E) +comment=patches by Nachbrenner +//Skip Video Mode Menu +patch=0,EE,00248238,word,24020000 +//Skip Videos +patch=0,EE,001152c8,word,24020001 +//g_showOnScreenRenderStats (debug mode) +//patch=0,EE,0024875c,word,24020001 +//RenderFrameRateIndicator__Fv +//patch=0,EE,0033d35c,word,00000000 +//g_ps2RenderTestPattern +//patch=1,EE,004123d4,word,00000001 +//Boot Language Modifier (use only one of these) +//English +patch=0,EE,001fe060,word,24020001 +//Francais +//patch=0,EE,001fe060,word,24020002 +//Espanol +//patch=0,EE,001fe060,word,24020003 +//Deutsch +//patch=0,EE,001fe060,word,24020004 +//Italiano +//patch=0,EE,001fe060,word,24020005 \ No newline at end of file diff --git a/bin/patches/FF920E90.pnach b/bin/patches/FF920E90.pnach new file mode 100644 index 0000000000..ac5e9e7bef --- /dev/null +++ b/bin/patches/FF920E90.pnach @@ -0,0 +1,8 @@ +gametitle=Pro Rally 2002 [SLES 50637] (E) +comment= patches by nachbrenner +//Skip Videos (sceMpegIsEnd) +//patch=0,EE,0010cbd0,word,24020001 +//Skip sceIpuSync +//patch=1,EE,0010e174,word,00000000 +//Skip "HX sound" IOP modules (obsolete) +// patch=1,EE,002029e0,word,00000000 \ No newline at end of file diff --git a/bin/patches/default.xml b/bin/patches/default.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..658e8b2e96 --- /dev/null +++ b/build.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Usage: sh build.sh [option] +# option can be all (rebuilds everything), clean, or nothing (incremental build) +# Modify the individual build.sh for specific program options like debug symbols +export PCSX2OPTIONS="--enable-devbuild --enable-sse2 --prefix `pwd`" +export PCSX2PLUGINS="`pwd`/bin/plugins" +curdir=`pwd` + +cd ${curdir}/plugins +sh build.sh $@ + +if [ $? -ne 0 ] +then +echo Error with building plugins +exit 1 +fi + +cd ${curdir}/pcsx2 +#mkdir debugdev +#cd debugdev +#sh ../build.sh $@ +sh build.sh $@ + +if [ $? -ne 0 ] +then +echo Error with building pcsx2 +exit 1 +fi diff --git a/fps2bios/FP2BLOGO b/fps2bios/FP2BLOGO new file mode 100644 index 0000000000000000000000000000000000000000..dd4a347599762fcd3f885e4be97c2891faab097c GIT binary patch literal 256016 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

c(s8(@)6PbmbG&m@8zJeGT#!>2*Px^Ir%hMa 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 Sd;e5CaQ2re`WVz=E&m@udT3(+ literal 0 HcmV?d00001 diff --git a/fps2bios/IOPBTCONF b/fps2bios/IOPBTCONF new file mode 100644 index 0000000000..c904b11b01 --- /dev/null +++ b/fps2bios/IOPBTCONF @@ -0,0 +1,27 @@ +@800 +SYSMEM +LOADCORE +EXCEPMAN +INTRMAN +SSBUSC +DMACMAN +TIMRMAN +SYSCLIB +HEAPLIB +THREADMAN +VBLANK +IOMAN +MODLOAD +ROMDRV +STDIO +SIFMAN +IGREETING +SIFCMD +REBOOT +LOADFILE +CDVDMAN +CDVDFSV +SIFINIT +FILEIO +SECRMAN +EESYNC diff --git a/fps2bios/Makefile b/fps2bios/Makefile new file mode 100644 index 0000000000..ce6478f8fa --- /dev/null +++ b/fps2bios/Makefile @@ -0,0 +1,57 @@ +# +# + +all: ps2romgen_exe romdir_exe romver_exe fps2bios + +VERSION = 0 +BUILD = 1 + +CC = gcc +RM = rm -f +STRIP = strip + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math +CFLAGS = -Wall ${OPTIMIZE} -I. +DIRS = kernel intro loader +FILES = RESET ROMDIR EXTINFO ROMVER IOPBOOT EELOAD \ + SYSMEM LOADCORE EXCEPMAN INTRMAN SSBUSC DMACMAN \ + TIMRMAN SYSCLIB HEAPLIB THREADMAN VBLANK STDIO \ + SIFMAN SIFCMD SIO2MAN LOADER INTRO IOPBTCONF FP2BLOGO \ + IOMAN MODLOAD ROMDRV IGREETING REBOOT LOADFILE CDVDMAN \ + CDVDFSV SIFINIT FILEIO SECRMAN EESYNC + +ps2romgen_exe: ps2romgen.o + ${CC} ${CFLAGS} ps2romgen.o -o build/ps2romgen_exe + +romdir_exe: romdir.o + ${CC} ${CFLAGS} romdir.o -o build/romdir_exe + +romver_exe: romver.o + ${CC} ${CFLAGS} romver.o -o build/romver_exe + +fps2bios: + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + cp -f used/* build + cp -f FP2BLOGO build + cp -f IOPBTCONF build/ + (cd build; \ + ./romver_exe $(VERSION) $(BUILD); \ + ./romdir_exe $(FILES); \ + ./ps2romgen_exe fps2bios; \ + cd ..) + cp build/fps2bios ../bin/bios + +.PHONY: clean ps2romgen_exe romdir_exe fps2bios + +clean: + ${RM} *.o build/* + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< + + diff --git a/fps2bios/doc/overview.doc b/fps2bios/doc/overview.doc new file mode 100644 index 0000000000000000000000000000000000000000..9d68b93d46ad982e5ac1528180ece0cc85729801 GIT binary patch literal 144896 zcmeI531Ae}{rD#bgdmp)2#By8A|Qki0)h$x0R$_DBzOxh$tGFYWW#O(!80fdTD4jg z#d=k3)p``KR;|^F_X%31ibdh4tp^@RDO!u<|M|W*vpc)l$$^A_>dwL^GdpkId*AoI z@B4kn%4ver^V3?jXqFF(ADd+u9gGDF7c3lg+^FMpp#5(~dN(6? zT8eSx4Vi&iBYAAKBXXtz+@qE^@&9bZDh_Mu(iYD+qdm z@W0cvt@Ahh!Z3Dm{Pra}UPIgSmg@83x3fqmm7o*Z%BL~g0i5^3RfbVY#H?!!<37Gu z5x=V>5cjd_!^$@<*szW}Z6#g%$4bxITIIIRk?-&GeOc+m zrz`bi|5)kRk2PlBDqlnCS?ODHSlh$?@M0{6imD_tuot9~S( z+2m{0v$eJIx4v6jE56g#Ixl`}wMT2~6yG{N4!NWqHuQks9F&47kd2VmA+81x6tPa z2T6m3yq@Ba&*vF*-0TwudqTd70D&r&r0gm5mU|ZXJVm}GzCf_TSL7)UhCEea9|?JU zWmN%hWiS->gsYI(8}`i3%ReP2%X4z6FC-aMg~+EcSmg8gs=Z|u0gC1&pv1q#S3Xoq zKsq5`u`eVtOM!|j!Z{24K@zmZ^_CY&y~sIKgC`jBm-x#mYJQM!lDaOwzZ}uZys9P( zgXNW8e>vhJrV^$U=@$5WNzVID#>c!zJQZ0 z{U&ND#eS*I3UA>eRZ6KGPnfn5pcVym_jPkTS)Wugnf&veC4#QIVwA)NI4^1 z=?zs%LF9`xUsa1%wuQcMSRGIeTPjJiL$*r4H$V-bAl(Yfd}YDVGLN^YC`1%bcJ-vG zdD-&OLYpO^E~~_tB$2RBHP1@1YAc#(+*j=@tWqsfiRLSk6eLp=5UN5`6m3DUvQ!B? zWs0h}>9c05t+G#1rmA({Qcr*e6_(N|iz@eNfs6emQgK1rtZs;Tv*$|sg;k*twvQVy zg%G!aNDD&VaP=AjC%6r{4TRBfvYR8S%Q5&yGHX;12>j!Gj3EosB}C1n_%I(eHq z2m}kg;%ud@sK!7VC(N2SSzLzIemu0>5^W=aptlIcnR>>;;~U8s)kLI`Ojqs$|ERQY zW}yVb$g`{E#1WC!ROAm)JZW!HK_#!KsbauZo0ejV$`HIrHE^Y!EYD234J9;fWRY&! zQV6sbO@6gLz_AeKL$0d5`^0NvNm63UN)Ms^Au)a7!jOLfr+F6y#RpKVGVdaa6P5<2 z`VNVOQvIRDSwT;5!9q$RO+}=Tc-oCx2BAwXwWQjFN`T0!u+d1WftY=qt**2~w6_$~ zX-3bHoad|Pg9hU~M7zrWn|bJFDj6wFis<>L=FgZiLu)_cM3i@k>OG=Ff2Gt(vFcSY zEEHA|q&L-VUm8x{tT|Im_o!M`xyniE0kf0Xwpdo%z#-6C>IN4{!+u`KhhHoYtKQNh z>L<`gk4v}gD=(r8kn#j8JWIW}F-%-6NW!WMeHG$(vf59dbBa<3p~`+D*^~u~sZ)iN-384Qhv}^T@egXRjSI$^nP(wxf&mduNLo0K^ZLJz)HPKR70^W zO%B`YjuwkVcDdzjL2M;suZ1ZsHQgMN>Wk;Q*yIz!sZA>YS3OLsXnXhR8KL3S28)OeS6)7d;Fp5`TG3%st!Eo zw9l*>nUkqp%hByKolYB4?yIgOylTYg%q6sMRB3*riTGr9Or{8Y`j|8MvLxs)${bQ$ zQ5g!Kp3Q;tj&9#xk2$pqL&)sv+!2N1YqYab=jvt{pd!^^N2!Y1w3J6h`9h3Ul;1$H zUeC$=bll1!0&8H2Dgf500ehOMwVlCG2X=Q!4h{WMR5bs__z zI<*q6tXg2!iuRdyudd8mv>j6jv$}lI>N2~)unZ9K0_E6;X$qdlV5y&8%;}^+=|FG{GSX3vSh*f)u%eBinns``5-r3_ zM&=mUt@b@C{!#`vDzcR!g+I<$d4ivDP-xi{@#6(ztdUlrrv*|+agK5*ImvuXH-BX_ zR+=h-7;}(5rjQW`{ZZ9|quOU?Eyb`hrBUiyjvR^XRIAz_kv)PV-f*GcpV`k!q@NrL z_)E$&bK0|85(q8`WF{&^W@djHe)h=ri2{*gVdj95q#y8S4#*zr8QH$QDON-X-C_dX z1-?MyS}F?SGh{Mms|8VujFRZ$e1T$5bevHnQ&!VMnzO7yXxel!gFPd4-x=_GlsLF| zZ874+OwOJVy2{K7h(=%M~0$?Y)61}>pI(q%97pl;>;Jqt0ovX}~9s;0&2sMNAd#HCNC zkk)w3oJVPkxA{ra7e;DIjck>kn4MLr?%fnwE6MD2@hQdr>iJsaFhexe$1|EN4K9^6 z20D_X+B2Z?#GGdNQ0;Vw5S#u{O&2X?4ne@d=d}0m5oKl$@f9DfzL}@VL1l)XA;n=G zqH{KC-ukoRa$ahP1_D=>;D%&#<`<}{2 zmqVRe?7^t?faVx2pFJfxC6dv&L4yX-8xM{Y@^mxind8Uj3|5Jcl+>qA9qc*RGks?M z{Ntk;o#*idSg(l+8Jn~^d(Qkh6KyeU<=5p7cuT^bbH`0RVd8P~r_Y!@Yfi!Z6X#Bu zJ7uztqzAhmbaGz%_A~VGRBV?Pq=v3~E}UbHG9%+_rX%K1UfPt^FzI`Wu_9^Q$Q`vb z7OP|_K(CQW@;=6T+5%+oE6r8+LyVzFS)UmIU4hf z$Qm(NDIqeo(DMUM7avJJ;)2Z%+^jRvhB4GBOhPD;ZOO|SVP%r;PlL#^1R!b+cu4j(+S;L`9=*vX#iU3Q1k_Vn% zjhanwZM6c`0ce+u(=jJjG$@&Wsi~NnNt;QkAy$I3NJO+%s+T1zgC#z)rtZpF5%aUA zSt%=S3F%YQ0QUq*|I-wm zIkm#JRu@0Tq7r6lpO!Jzoc+nGnt^%hAjwslsI7N0gFHjbmZF6i z6_d_vQ}^|xCn;M^q`}lj$D~e`d8+~x$ZWHgu#pZlv4}^SiLlNT_SK2p=#q}HC$l%A z=;c0H?+8^@R7Sni^qB>7;+<2Dc1{Rqo~`@|2DYHeA7J`W#R7*i_OLIs#E(0*27ErN zax8ZyPDWaXDR1(olqLHPIW8$(5uFhfbFY9{PwqNXTH7mp6b_7Wvrd zWdNC;F%9>GnPbW2ixR7j5UFsHxx8#Maw$b+X~@T7rCHlqN@Wpw%twkE&M;1|d}JB4BpznC!uHMdH7wGaN4erJ5434y8uLBu@{(0*b6-TeZ8dJql&w z;!^o!yU)ncZfK<5#5#!SoNt*MaidxuD!bB8;wmK3()lvlw0e`F9_7-8cta(z?n2q3 zW1{+8ZTwTpWjZRSDyKvqX5&ykP}}xoe>m|;TDl=YOs3LXsgu=qoL5n0kEMggDibHj zmZ=VzsQsywQ2emj0_SJvn(lOxL--goJkLrQhde#6V9p8V@yXV4Ge=v{6o(}9%&1e9 zo?4TzQeIFb2n-A^yV3P(YPpgzhmoX^t<(rm; z#Rtrw_wcJy>o8NRjMIZG5}S!n(iNJg1U2`frRBnMy!W&g#?$siK)8;JLiAwm{#)u!(`Z*JJfk%H!%4FuW)3fc35N zU{#5_a#xCdsy>7@5iaD&HC36>(6NwurMg^8(mv$~%pq><8PZiT8V$3$tS?U>guY;A z$?Uh>hV(@GVpOzi@KKhj}nCS}T{q>&C(4c7xpy~~*H>wH$r zC^nJ_{ie0#<5}YOsy@{nVk6?)oNbNR~LF%e-AG8l*!EvC|!?mqt{iJuqLMlwpvZH3MuV_ zX_n4YiJ>c2`ckzNL>lHD6>@_BH&w_IPr0YW#}cbIpes)|%-FtHw=<@PNH|E1r`63N zgVmfuF5NJ55LGg)4*8eJIzJkg{yAF3X4B5{9LFM$jD_^-sx%ZqjD3El=;EqHxksv2Gqd-y}Yd0^dM=DmV*>3dXO}al!KHhaxgbLBVVK(L6PLBNST|PkuOq? zpg`uC92}FuJxCms^62Os%*)7EVoHImgQG}N#LSTbMGlgth?ye=iX0?O5i>^$6gfzm zB4&;h$T~QhqBFc5kYg{cACr+cYj(CL zzhGj)-29lBc^Ok?=V3e;oLtZ_=WWqb+W(lF&fK^yrv|vse^wjA@U%6Ie()RaL~h-| zFlNFja2AZ{Xc###66W!AzGn_m{_fwmzrFMA4R3FF`gc!nczVOm z-(I(}W@T_?&2JZ#nDyDZTWSCNt0+OY(n||C=;>OzHu$*Ft@PDCM;Up?cQ$4npJtp0 z^T5k@qg_`Orq3{X)^jFlNh}0*axY$_jt${-DWxG$)22lPQfQ?+pp~owOuv+S{-j@j@niXztcEe zp7ZEy>b~>nJcQDU)LSGmJbD#iLz$Wl@XIuakPz9^t=kRBE3U)zS z55@*?1zZhl;W2m{Hp3^d4ZehL;9Ka{lRgH9z$7>xyif+azuWd5eDcvo{=N0lD<8eE z?$LGku6t|Uck6Ch_vp3!yG;F+J^t0Lp9Dub(|2}i71MJY9J{!9aO|<}T}vNtvyi^` z%}y7^hH$oo*!zBiv*o-5XVX_pi1gXYG1I3@-`q|8oi-$eTmp+sxffpymGHGTx{|eVCh=)^fZW$=D=BSHe3#(GtrmmNc1B*5q*d*?u92| zGkgMHLgzymfk8j$54-Gj{f+(07klxA!A6Fb?TW zp8&Ujrw{R; z);#}$%NW6@GJ;QK1kW?FwBlRa->bIc3yx6Rcl#fuM#W$DT}=%6t1U?4%K2?PN2;xa zh*irr#zHt&$DW;Sml;F6UnrZF*(MA!x|gte&PW(LIyXq{FYL1ir}U#~=riI=WXafD z>@o*dqO(=-M-ZJI3YNZxm^wR_?F9Hfsv5&^?!y~-nsWlqqxD6031Ut&1I}Z{StR@2 z2BaK3AZ2>7JSv&GdaBWCWA}9S6VYa4wvl>m?TWPB%!;CrPuh+b+8}x$EeZgLjcnclpzEBi3ou3Wr2@dqsB-jqc`dY;B~pB9hu^n-(y< zlEkvg>YO(64076l6w0j&?H!O(QY6Q9|F4?8nggi4cB0RTAoh41%!L>~T`gs@J^^b- zwlSyK16snqV=btb;X}maYZ;lU(7IVzZ9?=eIzI{KLpdyl5S#;-!R2rTTnX2}1Mquz z1a`ri@G>t`6t;azwS zzTWorCgHVB{89h^^t)|euUQpgMa{W2)s@v1D~!kokH6b@pz`=xnM2j~>;itTg5#%m z`A%&M7OqlTWf1smF&5p|*!zXZic#bYIj{aRq|eDazEj+)6DuikX(Tvux3SU z39IJ}N~iie&g@xnU_ECJv2=er`V+k`kJKDHRrW72wr>w;k^6Pqdi@@O`B4&j1S8F| z^`+=uY&==@KRhKl^&juolU4uMCaM18`|@Pf|9_HH|Mu~ljNOt||MOCl)BoGY>oQhP zR{cMlr24nd&$cA7{s*ysl6)%yMw;k+E699Y=Hkg}|5qfb{_X281?XSaS;GAdqY}=A zt01OLoNL%VOKtl`sBvG4?Wdh)|I*m~L^F9==16q>!{c(zl~1+IqgFokp4=~?mVDHT z;EuGUwEs4u?+`k+bT0b77Vd((;Tc#5FTu;O9yY*Xtc4GR6JZWi!4kL|?tuqj9Xt!q z!OQS>*bE=QN3a`yfIX0Q7)#*L3l4?e&>wPP6pV(WVHV7W6X7H%gCJDEVps~*u=~56 zpX}Ti|L^%nc5bxz?ehd%Uv5|_=gPX=^iu+?m$h4VZsN5)*5&F8lh{scf;wessP&&w zUmAKf&oPb2l`=Ua{z{n~lXXvP{nKc>(ikQBz8ZcB*FcP||76zx#Nr*jgR=jV)055q zRdYxaor}G%0kQdH)&G-8s(;JR-;eIa*C(s~`?g9>`?vb{7ty`+@yV+HOOjOo*0}Bs zbT4DOWYzz+B-Ot)o_`13%a}e{^*@{EAd+kSN00xkdE61`UgmPis{comRR7le{bY16 zbNFP{f6t8Mw0~>e<{We{Yd6WN{|k~-|MvAdS*uG{{ePUK`nRvo%GzwQ>VG;nNGId? z&%PcnYw^jd{|Ay(|Dtp2`ioq5Nml(Iq;D8bqGv_){Lg-^O|G*gtNyE#RR8vCt8!g6 zS@pj;N%e2PmM+)OlU4td+9v1t&$@473A&eiCz4hFcO|L*t@~xpL-*$=vHsifyGO}5 z|C4*AMDG{C3b-BafIHzHcphGW7vVMd9Jaw1@C~#d$ZvH)N9Y1az%a;y;gAbIgBdUr zW0*}Gt@FKhfFT<IkD!-ues-}TdCY4nDCA)!X7{5aL2HFI&@AP7P*UT)!<(yK7*7U!-y>@cT-Pp zCX_33hNA@B<)w!AoGDx9v~uja7riH||6iP>_HVa!vGZir|HdTMzumWsUr$#3AIC8_@HV>cPIC9D2h@q4GqX#b*fYn(naiS@rQN%b!}x8`IrA4^vI zU!SDgt*yzrnyjfMtN!;Sss62X)Hl$* ztf3~W{tJ1xMKbz-(fI~=2X_Bt^?zkxS_9AjzLezpe+%8eZMK8|nr-0+wzZIQIKQ0> zt)Vyc0T1+p0dN@1gjp~f=0E|=g-WP`rEn=+2K@&c#^LbU5U$z4cGwL+K*|yPTm!U$ z-Cu24|JC|e`TJ)!_ig#rpMSMm|Goa2>wkXz@=E?yczbm%T{Pwmu5rj;`}Gp<@mVw0w(sGM?Xiu5*lEV85f=J)|jr^;=b}Uk{Zd@;d=?)yVm}O7x8St}Z>- zp-YU!k>42Q`i(SMNkw13k#F|0Mb2#C8kJ)_^9s>Gv3b$6=vVam)Aauh+y5|rl{Fdt zzh%o}!(zWbP5n3g`wzcNQvF*#TYR15Uaw@Iph(fJaP{#p9w5dHF}^uy9OOTR3A z@*b##n6|NRe+R1A{@YJ6KMED|MW2=Emt1D{J|y7?@0fu*&EJ1g9e29C2TSkC??0(u zf>OW#at6PRlZ5`it?1QYtR>^FRQQ)&5uez<9BTg}`!CBo7M^Kpy{$4@%R3gTJHFP{ z)2p)IOM?=>YhmXB@!1)z3tI2XV?W~E4QaW9=57V8Ap>Om9n%&*x7Ym#jr;PJ{WN!fZ)+ft_MEgWTFq3h z%zDp*lm3-wY%O}ugbvURM%jg=FNl6T(OuhK6Y^62qJZ~BHp$Pr{({<8uB93Lg^_00 ze^;{&c-Z!Z!7v1dLN1JgaWEbxz%-Z+C&C;!1I~nbumB3d2Mb{l1fUGcAqW)^f-o$F zYB(D%fErj17s5rb0(NiPyzPy3fB4NCf3W_nS+#rfw#{d63#^iVdVlk(&AiWpd2#1S z6CLNwS-oyf9L9`WOsno{LS)9>jb8vfbW}`iwbBrY`Q(H@$AsEr#)qkxq$qjX=lAM( z{VN-kFg{i!r^vd2;~C8VC2WY;yy#l=EczAQicUqJqRW^*;75On8Bo}~h`YOQYM`k- zg^^*|tJtd8Xmk7jPh9^m@A`5a6z<>gqLCoRNtcrl1SZlsyJ#=LKgb|0qFWcyFI z`d{gLrO$0{`#<|2cl_6q>|b;)V=Nh8T>`7Xwf}u+lKVBOrrW>h{bE!1D^2}h%JvGl z60U;lU^QG1H^3UW5qud;lN97T5~^fPccL@Fjc& zU&D6z26k-y>(=!^My8pNQw)kxE)y-}Hx4HJ; zqUL|1bLpFu`eWDr_n}Gd*QA*iy4>N1J{j0T3(YdMrf17RK zTekm&-LMDJhH{S>w1U=<0d1fy8~`1m6Lf}yp*!?|o^S~Cg5J;v`ojPi2t#2QWWjLA zh7m9la$yXNg`;62OoBX^3{zk#OoQq0GnfH0VK$ruC&MXlDx3zV!a8ZT}Y>?2i9h()iEnr=^cR6r_)K?SH=-?LN$`U6bwK8k5O*OvYi&ZU3FQ^Ub~f z+j6e|T4Qe+cjthNyIuR=hbFmSlWNyw`?uyW+H1P&29ftnJub_U4Wm}~$0&?NV3Qtg^- z|JGV)A$ku$bKC!`uKl;D{$JL?7l7#B2a7=3K^c@o5Go)9VOR>)a5mJya<~vKf)#Kv ztb|o?Ia~q1fa_p2Tn{(E8n_W|f}7#ja68-y+;9EYbr0UbzguN@tKPl3=IX!J1ikz_ zlU?=8PHG8@HTd}FG3{&cvi#MpRL---GRV2I)J7nNLwRbR9s;P~R$jvtB8v z=l<^jmaaw5i$V14`v3jvwD)0V?V9ZWExQ(*7F%v^|39y%JN|1)<3G!Pi|@V!#CN;) zzYk4vzb4hL$@Xvc)zVK(|NP_ZUpmS}GRSfLdqLm0_TQq$f7X~x#$&$%8ILv6{$ozt zug%=etcf+?Xp`yI_*=%__d;{q{|X#|d;O;+T>nu%IZftUzcY1zKidajEj$R1!XMx< zcnY3|XJ8#X3(vvx@B+L7ufpr_S9lvX!r$Oscn>zg`|u%bf&YU~;WO9zJ(uP4;aJvy*fyRG)RXXTQ{uR@YLF^Yt@e9?(J8v-EnozI{uj!)ZiUb(cj>8 zoWIpGzml0@eX~cU1kP#h8LZQNW+TMr?*q~O??H4Q{|1EvD z^x4gA|G#tXzlF^IwEc_D-vJq`$v92MXfcM}$S+N7knZXGwFcTb+P^g>m+`oa!<*aw z$MG}L?)P8^pM%W5WbP&Nu11=C%xU|zIlGxPu?E^X+P^i=mN~Y}t$&>T*ZW)3 z>i3^Fxc1+o`hU@REy$XRtf$CYN{nGUe{p~Rvx!#N{HM1|VCS-ImFT#h|BJp`L0dQo zn%n*hd%OLA%b5R5yD-u${b!nOpdH)JW?SgWwi_G_-Ju8cgx=5x`oiHb2!_BBFcgMC z77T}xkPD;X7#Ih~!UUKIlOPW!!!(!$o<|`tm&;I@kAm@}%#yI$Q7RF)26j z>yf1FD3^KX(nzuSE+D!VJ&TT=U4Bf6>;IeIp*JyyM1H=0|8Lo}*t6JibNl~YuK#Z# z<3H{HMdyP-{I~dS@!K(0?)=5I|0Y^z^Pk>y`?vaO>7%7@Zf^U(w2wRfYf0lj(fN3g zF`10VWGv=v@-ZQ<{WrfsH!+8%+rKsTmT|X?x0~DkdwE>@Z%OuV&9P*Dbu!5OD#ps4 zzqt0_MC)w+)0=Mp)_hv#(lUo`Zu|eeYyT~3{BNzBEJXJKCz}&s=AYX(=LOXJSvbBvuzsulx7m=p zHXB}dlO^zkPX+exs_xp<>u00eEKhXOp?clUAvBVLEcP<3G{)YPcS50O`k_O+F^Xwg2Wf=qBdSbo;l)Z8Bz)@mh1+e`!Cr|8GhCzcoge z@%ddKDw_ zybQ0v8?YYUgty?Y@HV^y8{u#8F1!bu;C=WIw!r_vNANNH1O5r0z^CvzY=f_1JM4ge z!A|%$?1FFMJNO>{3$X_+x*}T^^Y$XZB4YhV=D=;LY8w_ zZQ`{++i!e1KBZmH3R@%A=YHH;<&RoL9BJuWbS-)o9mjZi=P$1RZ=!c@{?nW8|1Fyq zdlp-6ZvWqRfb0KTlK&T-i|-b{Ek0ZPwX?~`gt+$K{07~`9GY(bR{t!0v-Hb9&i-FM z_R56Mn#ghe`(KZ^_TQrBf1-04hshZ1GmtS@jFmfoaqYi}*4g~0H{JfNF}IAjWvt!Y z_J7=AZvWqs`hU^6%&lZz^&gOVm9xpmgt+$K{07~`9GY(b);wC~&@z8+Zu{Tl+JB4c z|3&BRp#yY;PH-S}hJ&CBbcG(!6S819WWxx^fsv34qhK@~31eU^s5Kb5Z)?YE{8P7T z@#Xm@w(Dd#y_0Wf7;#l;%25?d&V1A8v-ZL)&)OFz_FbEw)(`q$ zby=$cSCyw9wwB+9So?fxcW8IjbE*5NWw^<-fEp-_`8B?j)thSjE-_L|Q$}rUWu&BS zPh*>snpQoa{}Ll*ds_b`DXG;1jykEMk-B=S(YBInx+z_Dr7%Spozi_*8eK?Sv}Kjm zIc*F#6Sul(>u&3E?Ig}W?6q5wpFV1Kx8i2fBv5BqTbJ9q+}73b zfZMeb*G^nJaqVOu&*NRU(lXu3)rl5xTE{Qo>^y*#nbfqjg4S%)()BjImEN{$%{Dp{ z+j&6$C8@0oTE~|+Eq8F@WgeZlB(khhE;PC#C0Yz~Yst1`=(Z)-;$&gj^-K1b;g}1g zuJ=~GmD{1HL9FX4U01nZU8VeDSqmG&xgs@Y?CsW4V`|Brp}4i=&UW3gcT4NzT)*V{ zCD$*xerf;S6nIH$C!@2GV%%hOG`LmQ{6zPxBktC%f#$4%$-ENqo7z-kve7Qm_}Uox zMy263%8erahWN`nN})SH)YILVKP@HQ%eHJ z-;D)^j}*e(GgivhZxoZV$H*bH6KA&`kaEzS+l?-F9%D=xnBp-;wOOuyv%8lu>-bdT zL^z|(@-y2kpU0l}_+G|5BTeNpPvz3D?T&hL8L4tfi_Imqr{t1%d{288I{luUAN?F} zOf+`X{@OU+XxGX*+Jj>YD2DQ(jNdZ!gfymC0zIDnM1jYY=J+Gp4r5h)Ka zenu*O^e3sFz+MhvS*c=%R9aGIo>Vd9 z0@XnqKiyM~?PIxPDMd*_OePl;;G<$>1p&Sk%Ta zmckuv`DJ_90B^!J_!bVPIu3(u7zZ=qM3@5)!Nc$|`~!Y~S~!3Qw~m0ZFd6cp2#TQu zCbZ}6Oz1XjW?;09O&Pj%wgzMwmmJqON$v*B{M z0@lJO@Fg7FnKyKT7w&~8VKaOJUqa`D48sHcpg-im$}YSi0R9NQx*5iy(Dz`@fgvy+ zj)e&@5hlTLFc(gO(_t}$U@2SySHd;$0Q?>vfnD$|?1qBw#D~*h4crK~!WP&H|AYZO z&u#@XgC^X!-;SbRKQ|b z0!yJ9&V%#e0$2fez@2apyZ|r4Yp@NzfN!7!Z)ofYT_6jFLoUpOSx^9rAOMTudbj~@ zhKJ!1cpP4Wm*EXq4;$be*bP5GDsO`810FaGX2EQj3stZLmcnHa>dP<0_2U;xU_1N( zd!QDK{@4PfLK>t)D`*WF&;~N019XGFFa$=yc$f}z;7phYg|G<9AP9>g1YxL#8n_Tv zz$LH>E(Q5z!_{yD+z2i^Z4)?-+a6kMW*207E2Y4F(0?)v+@I1T#ufp5#4s3*XVH3O$Ti`SJ9Jaxi@HK3Q zf5RTA1>-Q<8l*!jXbT5H7w8HHLl5W)eP9p_h9NK%vS2vm!Z;WY$HGL&gUK)*=0HBo zg_GeFI2GnW36#P@2tXN>Ll`cA8dwe&!bPwGE`{r0HCzujz#6y_ZiU<74)_h+1$V|2HW9Z z@Nf7Q{sZ5`f5D)?ZU-Hp6Lf|y&=q>Za2Nq2VH6w*W8i4Gf#@Q1h$c})TFM=2BT@#6SgK%*#1uQZe*`hcC!p-SVB4PGvg&H zL&Exut(SypHm2;7twUYAX-ehrsWI#Nf2=-Z?OnFV9p zyMu3Sa+_}sU+1QoxP4k<%tXGtzP`h)&lX&tD6_^k2a3^cY*?&qnqdk1_t;9)+}X6*;`rmHeNI6!7W3R?aysX4nE6mOKw}*SK~9c zExB#UZA;Pdplc7VJ-GJZ+5?lsy`LYs^9Px5^QjRcYk973b$x5JP5iiZMYk=vZOLs* zKP}(7m+Q1Gs-Jet&@%jzs|QyP`>KC%+tNO6OZ8o&m1%?1^XKxsxzjV|@=SR{&yUNU z<@V>kt!KIae>}(S^lWxZdmg(bJcHfP^VjlRwLDYZ(6iI>+_XG1o#=UKr)Q;|o|ATZ zM%wB5Xs2hRot}$!dM4WGd1$9+p`D(Cc6tWd>G@};XP^HUo_ltB=D91+Tr~Z1eS`k?6T*r)Qd-o@b7KmRX)-c6x@{>G@@+ zXP2A$-0~Awauu_acy;w;i;-?_U%Tg)jK|`_q7Mt#q}an!%{Y<FGi;-<6 zYjD8&#Kf~5SMgMu=9%$fH%=fRrk~^cc6G9nGs9MfRvc~v-(7ZRoiHh%{^&AT@uUob z{=}9qUKV@Vn-Z3=469U*O3n_pGRT9{@;fr=TXh-iVNyQ*(Q;a0BEOT463N-wmS23D z_Aq;$B`ia>lBQ03F@{FIMz2=J=~_2rjx!vuAb{!_z7 z%tuwgZ7K0`rbgwgH>{yF+uF*0P$W%{O0&K&k1d|6Gn<@Nm@d1nX~WQEu)^Z%y1}yB zo;01p8cK6`J!v|H)t9E&ZK5`R_ZKfJ z+qA;s^qz5pt;rklZQhoq#Ix(jo?l#8f;8_{x!g1ZnVR3Tm zXU|kB{HYO$ZMAt@nsKtIKF*$|y$lVN-Kh;q8JxlzO4F$gN}5h#4W;SS1|?0Wu!hof zYJ-xdQ&>Z3<~X%^(sT-ID9uszr0EpaP?}@vNz*B;p)`-KCrziYhSD5gPnu3)4W&8J zw6S9eINs^VnbxQ<@kjEJt%T`$hYqWd06r2n5f;lAL#G)Vrc)#=?Fs60Z^A?m*4Rx_%ZQd; z&5sYe9^EFmScF2lHJnyT#kI?P@MsWY3ujwwT2n3BaRU!pL6E>(Rb?5Ic?Zc_2= zbElb+Fxn?&PaIFrkLtuT+o!~<6Q**%Ek)|nAxz0){RXYbIW{88O=*&*H8zdYt&%fw zyx4hMB%V!9hcuO(R+z{VZ)5zVtNKXTkq&Z7m`#65&cyLz<&4BjAZH{@<*w_~E~h;| zscU`)R(&Mis5m(t#^p-R#PPJ8b>i9NtP`ek*K#_9DZT482W?{`nk}E$J27w ziD#3uPMA$jhcG24Kf9_vQlBH@z7qW!PxSvaiY@`8kw9)k_^&_CXmo{{+hL@lT)(+y2+fkjPea`_ygM zET7nI{Fr^JEv$FMrq`(Xrq$*pp514Ott5`8eNUZumfhOqj7u}d#^S=153#SU^@_+j zSIK#NJ-$3~Jde6QRwtfK&N^YLp7a>gAxz0R(^j87i9NtP^IF(;-aBXi9N ztP^IFGv8Kcc6*RHYJSC??n3A);umv_bJH^TAu%@bHafqkF9O5ZC9m15H^@YiLr+ma`b%@HT z;yJ9-Dp{Q3iQXOJDLEa&>djBu=Rzf=ma|<{PNjE;wO=KtLp)vAiQBc3(N7T;UZZ9`S;?6=>=u=#UYFIfWJYCCbyi}^l4wlp z5Kq;aLp&vmLzphRsujJ)Y+DmoVO3_B)LFD%v`yESrbE1DlXIC(&Q^`APiZd>@%CCy z)g}_xry7TxXOlB6BBx#_a;i^B(;;57$obfnTt_$Ew`^=}LXB-Y+QOoBeVYnfZY!Vd zT1dTNZ6=tJA{#PL7rs0xPaun7vxmqjMok8S858)W-?E;(6Nm-B_xf?K#$mkkWgz$U zu@JNZzJYl|dG`^d5956`@C3BWV!a!>lOV6RGI$k~(HA(~7!N-K>67J}UJ+ElQn(N< zht+T^hzuVe#QTD}@d_vwM<*bMygO)b-QY}E1R4byRZemf?beK9k+$<&>M!qNSFlE z;AA)x0uX}buo70oO>i%)g{R?pcpEmsXYe)b0ny<>&;tfR7L0>Dm;)?900oK5c@GH0pZiZXnHuyE%4tIdq zw&=VkyB)cUSaia{?cMpC+D7-?DePOMvOmG-{Y@vf`Yn#NMomqP@vXexv!ju^T?Fc6 zwAoHv9VuNBPTMYxffwIyAEb_FZkGh&KdDAr6^~iA(TYGhe-hiy=J6DcGfKp19k9JO zyH6ukC*xI-&8X#X8zVg}ll^1Uv|B!KyF^gIY+vNd8?Y5Vhg~4qgy38_gsSKVM?)T* z0%yUi@KqhgTPP<{!$DS3Z542HomFcBufNg%JI48wVF0o(z9gm&n)1C+xO2vPM_ zunK+-yCCI2TpAn#hr%Ej48vg@SiBB+EVPz~q9a##&Fz%6h){08oV zd*EK!1>eCQNbQW)AcoW`+_hBpiA8Z484Q4G!zv_X$FaVB#EEo&N z!UUKO@~X@;VIG_Z=feuP7_J0)edg_O2Rs3Pf~VklcoklQcR*gP`5Al;ZSc{V&=ER8 z510k{P>wBEfxJd@Ej$QMfxI&FU3d?^fG=S??1oxs-HWuq1N}i>tCo{M7*I^ULt2YP2;gAFJ z`pxlhEX)9Tz2-_-1*_pE_%+C@Ht&P`;R$#eo&$O9=6cuwAHc`(8OSR*cf!9R6?c*W z?Lc0;c`}>=r68}~tb{7K2v)#KSOwRCypHoW_%*DBr{HFX+*}2CIh~ zPj58|tRBpuw@L%62OG-%a5xIa!4#Md1#k*1p;uZ8R!{XkJy0sWfb>8fuzDJ+hmjs- z6CkiLF9NX=Xf@=9rWopj{&&u0H4uV9vb!+PbiRWf=Vf<+Y&JD?sISpSl)XQL@I8-sm&q zQ1`Zt}g)aXo(${lZ zgL%R7A;#LmKE{2^`WU%~^fMkm6;8~DEXiPsPU|cgkY@9i8nbB_9xyBPMRevqz<>Btj!m&I?CN1%0;rrs{ z;PpM=?!FM*eIdB}Lhzr?3&Evhkv=+=r5NEBbGyIySCel`kmLVX`CD?n@w&0vinX=N zZXL6>ZdlZ|tU8gcTQ6?C*xSQTrA>&hsGX2flVZ$azAL0}I4MQe{AFK0);5)u1@#%r zgmr>kE#ObBTq|JuIG3w8iy+8V&vJECItS~c&yurgMAo$q+rCUZkLz|7Nu{Q?PHUCk zDm5*A<=KXZ!!=eqDkBaQaP6p!>q%jPXR=+&b`JTLalNUW@KL0bYP4#VlA4myI<=Kv zD-da;pBmZC=UP%3*QbK&`qRjPD)$3gr>DxtG53jFnevlUfE11$rQ&3yWu~UKN=t4%`*W!*xu%Fze|qcTfpfY%S}glV$RFdFR$R^X$fXxn zU5Js^X=%95w`ISX^*(+2w5#YQ+uD|;ER?g8N*Ka-Gr|oO&tH2Hl zv3ei%B=O5RJIJ1-5mw(z)Va}ET8b3Hg}wjm!FOQbbrMM7$d-$5-SMAUrJe4*x{Yzf z;Sax;&9Tb~5C zo^bz@y2D%UNWBxdo5;8iWFG$r$UOc@;NcD9Igok(YanTNCvp4yz6-}@hnTdhxpV%q zaHX#-%rThX6GMATmzFfnX`M1o|yMoN=%_mXSJs~;ba2fm@E{7}NO85m_1y{o_;TpIWu7lNZJ=_3m z;70fr+ypnnEpRK`2ET^e;SRVH_Ha|qZ`s}jcf&pKJGd9_gZtqD_&uzJ2jL-j7#@K~ z;Scafcnl=HC)oZ8o`gTcQ}8tW1)hO*@GLwB&%+DwBD@4I!z=JAyauns8?YWWz?<+E z{1x7YcVHv@4c>+KU=zF#e}~QR0elEsU@QC|d;}lEKj5G63498l!RN3IzJM>`EBG3= z!#A)4{slYX->?h5h40`$@ICw&cEb;_2WmkUzfwSMz?6DQXWI%|Lk7tGI+@TGB)lEl z_Rs<3muNb{fzTNw{0AEco5$q1;C@H(HEUvNWQ! z&P-Ji|DvN$)f@eH!s#7z`nT^f=an9c)4wKKx)P4xhKbdVI-dpa+6+JZe)06zA##=#S z^Ov-9r-{@OFJI*<_xy_Pr;~fJl1YwO_bjSY6aE>r7xkYeS$EROwW?F{rpYsg{L@KF z$}XRTLdG3Dz?OdsJ-^)XTtSb%K=rh7CpYl5GovS+v;Nz_>5<^Yk-ZI z{@GrG$+e$?_S4#G`-%76eP|mA?^zu-Ik>2*%vWBirUoC{;wv#PRmbyrvGCc4oChz21jpr!%N49OW1AaLdh zK<>Z!$K5v|_y7LjJObwh_8jgb%znbm+#{=J_MDCKGQW23cdway+%K-VhsX!74*sn; z#K!^tZ{z=2VQA?8!oDyxgBB0i|L?|-{#!vCH~k+f6tqPXl+@U2oHbS&Ml&BAIm*E? z4}($G5GKZvD;w&A%^hiEep^qxqJkisn1Iip6jlvPI|LM( zG59|?h7eZDm8cjw$mxXW@RN%|uonb{RX-cTT|(lB4jy2cnKAS~v<#+zbo97Hgg8KE z_!uN;;y_XT*4}XjMq?*UEJaQNLpW>-rXZR`2;|w??ofsV4|VbZc~CK0-ZvjJ+T##m zFLertog=L1aiR#rk#8x z&@n^|F)s~A04y3VixYzfjUrG^Fw4?Y8BLy{V_GjuP}piG%6O;^7zMYNEkU2_6s5v& z*~DT5MvIT+cnJo(;KT)!RF;!T=G0KgW;*~Hu!Lg~z$mobyo+H%*NCVTE{-B)XmY;L zWOL4A>=y&Zy%4FB&RAYO7<@2fz~usja}ahmBy%n-b@=aRGX@<5Qfp0i=F<%As}`_< z@@lu>$sl+b;IoQ06Kock!4%MKm|N5&D?A{xO(q=$yHY|(5g0_UWD3p>B1dEB9g#^0 zF&UT-+T&Q3^Loc2Oqg)ULIkkmyS1mlcA-Kh56Wo9gq;o~uZenl(L1N1To?*WRNw@I zkdP28hgUGUgfNOQfE*k>jpm^l%78eN;G49XMy{9P8NriO1Ud?5u;U~-Kad?$AY-y< zxhVk?!X}W$3eDR}XuJs#2F+;(9HYCZY7=!ypOZ6DQ_8zsc9eSnF#6qbP@&v&1sGl0QPWU(C9)vz#&UASc*U^{i#4pQK5pPmDbB-7?E-@m`Xnq5?#rR zXh#o0wR~eYg%Zx@0gMMyJO>j-{SYe3+*8HP`@{}=4s;_DUUYODkBbqklAhft1e4s= zL?k%qIMzBKGyxQ5%g|aaX6@&wA zt#T)}+{b4m8{3lO#KZ_e!cGU88;BE#_z*J}*48u-y2gCNh&qKb(-=onQmJoW28_sn z$)Lf@3gR^!yOQY%G2tZ}mU+S|fW3&fLQ46^#_^M$YPkl7o2)5X8Y&6) zQkdixVp3_(*m`fAO#z^AY4Ry}b{GS(gPPHD5wo$NjQY5jf7FM85&|S1h$oN_6g{MiBYlH11(ywtw|uBfRw^?2^EkxEN7OdDgPBICUMl{SAT4E^rS&kY<4~~i- zC>{ZH@eHB>aL`1-SO&4AQH-%NsD-Dykrp@uJz}&lZCMF+G>0$-a9bttxyxZfaA^Xp z$PvRFte0cZL{l1w5%jQzL82FhWD2Obi*e95#*Wc^dH*&hXbeolT=vWLg-LNdD!Q2_ zVuL0hIl&?(7zd9c@0gc4M(pR$?cfOPMU*XiBBb(3&V`9!JH(cI$yS6Y+Hu?jlN`W4 zglGyb>RN|aaw7*?bYhS&w_KMRqSZ>U2Cczik`ZHlvW9L9km5vmh;2OyXoCcZ-qPT- z<^b0FplGp47>>)JdPEI6RAvTRGmT*ATf-iu3?4=oEKM~j4Gw4pF(#E)Ms`38lC5+Q zDxxVw)9AL+m?BuOHq217a>%4fcx$rw=tp0Un3rRSOqoID_IB6qa!g)9h=&uLqM2C! zj}OUtMKEY?5tMnP6Ov#FlL-hHBgTF1NQGmZ_y{6)lHxwb2xeLHXDsI)T)Y#W;@}|| zo*~f>ov<9urW73=gg_%B-mYPOQf2^;3*|RXKzcYPyoJwqcpLbyooaSJXx5IZ@Uen&-y{^^J#S&v-;$q&cr>i7t-EHin{c&^NPs3ei_RIU4W&rBIF* zgA*ul7BfcU1gK3>DCc`LB!CTSgJ@IK`*0jH$qo$&&qF@AhUVx{r`ITBqA3L-%A*h- zF-Us)$@z&(^gPLRsf_9k_ zk~{e}&V)Lh!2E&O82rL69-8NBuff16LWt=oxt3>4TS}Px#L_sKGM=RnPzW{=YJpZM zquPB=E`X&FNR1q_Aco613m9VsP3$@d1Mt6EPg2JvRWJoivIZ=7Y3MM+7{@Wg3!35s z$xU%hB8U{C#$pH}vqrC^4-=9L!(I~H zjk8VO5b_g&xI~p-~3lzMPLllDEaiWrrp0mcKS~yG~J(5V1H}CBz7h)nV$qeGKLV6&F zMX2oXV;l!}m=GifGv0FuvbYw8h|@K|({Yd#$`b&9o2E@#nUU5+-qA$|WUIk;40<7` z0XH=bA{7L!1$$lY!as5u?nI)iX|StVF_Z-Xh*4y=DY(I!WSSC3l%prWq2x$_d?8rA zEVwV&0KkscBeWh46~>A#!4`M6ayD-Pl6%C)y}_|(U-v?^*g=G3rL0HL#ct3hTM}}< z(6JX!k-G+__@SGQ!eF)EIF#`rreQf8#T0>K$M8}1p6Upr2w6zB+L9*0WDfx?=i4mE z+fxdjoC!n^#7?g3aWgBW?7W4^NNKOsGKyous(@+!7LcD5kf_LbJ=l{n8&na}#G;2# zMhbwwvmH8zMH}j-iJ)VLvJ{boX*7C8;vyB`;ZnF5&YS$hio4cphav1L)lP86?2n5JMg@1fQuW zr%8unw+UWJP$}gn%_bwe$Ri zp%)#(K}pOaunS++IEVl{vSA*P2QHICQ8p?PK{4c~IKTr*8tQIU!b3?%L`zlJnxV*X zn>1kt5g6npf3cZv3eFNNfiaDYGt4wbMqfu@o7X68X7cnfQeMwq)Ii8#43jZnsF81` zqz4}iqKBig?@a-NDf*%t@Y)60NOwF#y9MXiiD>RMAGRr=mAP(&2lvn&aL6L#=<>L% z8v_PSgyqBJ!3aW#V8loWUCVf0Iu1f{vq^FmHbu@mMtp$5WM>W;Q(dDQ zV3D>MEfd42G^R&B+Q3W%rd1=S#E4vOAAO2Zb&Lb(7%vpleNj z4wUgu<~fUs2Z5qFBAZ5D6s>Poo~#=jDXT%u&VJYEVx*$hM}A2Zd6T zv^va013|+mdJI_IkykM1p4>RFT!oA=WU<$vJ_QM5<*m6%hRGL2ASoR%JP+_p2B|VdZb&MlA?&q7<1SlEc_9VNK!hbA?a>sJ12)+8kTL>ux}<^- z!%ECeCcwEP+-8Aso`Zsh?BSlzEm}Su@^b44#0VEmDY(K2uID!!FpeC(=olZ6-KCI1 zg(x8+;W-z`A;O>#U`F}~J&H8~dz5fo3Y%%v1wj~J?C`Jv1nR})4|)J2TN6Ergx;sl z6oU+yl+>G95HufFNd*bqblv0>A^>;*JhXz)r7%>EW!e$&5&;c^LoWbj3FtaFN7v@* z;UpvsG=QO{p!s-uM5chARXPwy8&ooaPa}dukZffzStBnZCBVmCz(@++pbt8M4X~%& zQ*+r8F>#-OF@N+KDuq&Is9YPWGz!&LVYpjpjul&z#nx1@Jy+;17DtwfV=IM; z_2TqSdG1gbU+iENsO>5f6s+D}b4TfdW%R8P7bB$aIKQ;zTs7fR`1TL|*7Y zAJ=PR0>$FRFHPbdLK((^96yc%Orn)t9h=#HKN87#qdTo{O(#w9r7g3Mj8au>I_mo;`A2R*uI(q|Ei^_;&GBM;s??b&HYW(HcS?gR)x~9w{`&hK5Jc78(=9=6C^HV|=JFS!mA;wP%Mq3qvDUhDMhQ zqicn+jiHIHp^4q0nd`-c!|M83bLVNLJy{$cLGV(wRjf4%wR)jcEf&FKJj7Y0tEV5B z6^X{vqRJJ{j|nB}A*I1D-~)Y3NtmLNFGJYGP=+;Cqb9(jJ}}YLLj(n(3r=KGIzl8h zF_v=xgk@y4c_9TMH(`w~#^cx__+W!zn3b``Q%pRbYM(3%N&_kki;19AVp8b8Tp|)0 zYX$6xPVpasnPPgb$XWr!8m(b{us;G0=6)oISv!OWX%U=o;jXWH#>RLRqBV z7y-T!W(e>Q%tyPRm6IX~ly!v;$8MOODXM+;47FDTWZ|S|Tt2&{La|z`)QeTnwo?Le zz}Y5><4mzTUmRI1cIFG^dTDsH)LkfbW{d6VVr!z<7za;_wa!qvF;pHd6skk0%PhoP zbmHYe(+PAdm5L?M4_S)r1{2G}#Y(eS>z3+c8fdOCx>}gNT3tG9Zr&f+c~Bo;;wwgL zqSPEK4R_16W~o{)mMbj73=)npj=|gpXK~;d0xdBTIHJ=&vYRg8lrZ2j>1;e;n7S9k z$;+!{xdi&i7Yk;tqIL4ZtAX^CBY7z+rU9IZ2J+n8QmH{xH&}Im8J_1BHwA4`7@a-n(nZ0EjyWbT8jRpB{9N4~wD2PEsB~O)y6v zDUv!^qcQV+%gc~3?Pzrz_rmA_r(HZ1=nxZdMzHm8jtL{qDlkTcR$ao}x2t4&Nsp7y zP~m@uvKD;Qv@n6!5AEDL$*~5VlJ4dx;b8IvPzP<-Nn+#{7|V1eF@$6OaY_@ zZR?{fvb8p7J5;J+l}qyECzzWG%6hR>E`fUGO1Xs9Hqy9KEY>srwq`)y(#+M`(qU`k zZg=~9Wc$1^vr+EMmQnW`t^%COng+Y}_tVA?2E>eRDuUhHsr7SiDBA8-I zY?G1nQI~=#83jfFUeQQZBPE!;R7O1oZFErtj0+9tW|Q2lF(8|OU{D5Mx!W3!!b3-Z zm3U@xbOE3jEEuk`+8fx7403;aU~z zXDo@aY_7Gi#>Vw*p;%#k4P)~Kfd{L+;)?@HCCOVUm8<1StyHO^^j1i>a=BP5ml~zo zNU1q9G`d!vz1mpbZ>^uSH^JXC@V7bFD|copo#|?OyaN8#n#F3BHC*}W^u}OLdmIg` zm=4@LV(Sby%}pY;fsBz>@WpjQP>MTrjAhp}bTsHIIA=B~K8}R|XdD4;v@&2xcp=SA zzuJVkiItFH;_HuLQu^pPF>Q!Xn7e~8obNoC-Ei`iWl9Ms`3#}ehB$tbl9J~wVI<2T z;EkpW9n_Pc=UGh*m^1+#Jg82Z3_}$k!Gs`h#WBEbgy(fZ&YK`3PHmrvm7bP_? zw=-WHT`YCxhssr4-jcakErYqJxww)Y?havrUBzk{HMioLn<9tda9F77q%9sSyOnCK zTCLS;b+(mKwN$7TOSM9+TIrUXvxV{X>ipHl((TsDVH^D2IPGlS?`+*~EZr=(Cu-fP zYJ03Q+$qp(hP< zvb#VAy$Bm%Vwo8Ys{sL~AW1_(lQ%I#{G7%!p%qF`KnDUj9Wv*Su0tig$eS=eSNX1G zK2u8U0B|Pye9DwknosUvdc!3>{EQQz2-e$$at?Xfls7u(-5M8L2k=y*ZeT1bHTr-x zKb!nO2F2k9T;7I7vrmyn2{TE@bxF`nIJnLvT_PX}VG0Csqdo_-(i&O}gO3IDaRFLZ z&8@2D4v!4+&eCL|GgIiy;X1c~>s-~`Vs{R!Wz^h)Yc5vH)pnsWTqxCf+gX>I9vsoh z8f99!Sg4eX^-6iTUTM~=?MA)ZZj5!C(_@|K@y^_MdtsuvFjik2Esd3%)yCWq$UEC_ zF5PS`-)^rSw$_eNe_I>(T3ct$)uYOAyV{woG)K$zHWtriydLPxAmKwMJAswGAO(^$ zP)S+MiVQ*Z5pqT)!^95YxgHQlLTkK~sHzwddUKxwN~%q2$yNh$N@Exq?v9`lp$U_5 zH%(ZoQ54}-1th{>K|Gl@pK1eiK`jj?XuLT9teOc``Aau`4d z4nLhe&d`UP4m@_#d<;PAN0?6z&yyCkgiwrN&md^@G!ZNmYcAHYT(zQ*H7n&#tuj)t zjty5P8kNa*b-G=h;brOY=umf|hzrujWT`%02Bz2=9;!ERW2;hXRSF}`%2=y5-mXn` z>$79c#mV-{Y))gbMClz<^GM8i-XM1`_KFl;veH&jiAZ;`7&dFvH8)AUxCSOqbWU*IpiTNPGWtOZc=e;s)&Z4*q)-}My%3y3XcVk8anrV5 zEP{X|mC|^vJUv{VZ&sE&mGw?#XSBLIR=qx18)?;-8m-lKeWhJp?Uq(Y3QOIgrP1Qj zcy(#Au{7OWnHjkzIbD2Y5&^#$=>$) zQUCFs>o3o5y?MO<@$=&^Uf=!B`}e;3@a_*jI{nj+PyYPF!*^~?SG()8o42PnZcnW5 zjjZi;R}aMBlji1GYxBId{Qyh!YHO_0;NqFLzql-CLb_#gDxZ<$7DyA-gz*Qg;Pgi5BQ0hHNZDAdY@Mx`)XFH8& zRxMR)CAJl?t5~TNQPk1$hE%oOY}6;mI}0=8t5>FXHx_U8R*!FPo*nd_+`azl?B@HA zZhrju=C_{S`26D9ldI#Uv8}ahr%V0gx!uEwt)uSRA^6)^KW%QFH@6?Pb}sNvR*j2i z+w z;HD~&<}%80RcuAqW1$Tg1dme+(|{>zIA;MoZFkxFZ~&744G74C68n5MC_{6Ju*iW3 z15b&}RbEq@8D#z<&7!-NN-iao267&zOrsE!(@H7cN=W9cvr;>C-8g=<za7g|Z8r^PxqIhklurpa$A1^GA z6y`dGsTNt^!p$ap42lssL>MSNp_qeSyK#9sT(6CES~HU)SLP-+mS=a@uYkfwH#YC> z_byKQFYonV-|v6?p#Rx<@9DM43ix~T?(((M`QGuw)^TU;sIhv|*tpl+I&be>w0AE` z?J3-OuGX66GVVNc@yv`>Hi9WBfvLpHRAdUX-7pCz3+WRRKJkdGG2^1uj&K16ajGJn z@gain4n;j8lo{C?au!{!r6JQ~V#c{4K9N$|C5#xA=)&ql$jdxxZ{}d?LJ&T*>YA0N zbKtC=EbEyPD!$B?_#{HW6U(R38s?6kYjmRkQ`+)5MkSLX*BU9M8v_ht4@t9ynk=1J9{ogCR6E1@Erze^*9`F3HdSr{EA_wfo~{(8P_ z<48UgxaW*}&5hyu*hqV3a&&2KYGY--x4Crt>iWs8?eoLllhgjoJN-A{@5BD*7yVba zW=4mXm#^Pj=%3E)9F1)pb=Hm>YbVW(`^~L~?cS4C?`e5_6^rKz?mXjtW4%+2oMcub zOI3v_K%>nGOj4LuCW5VC4JauSg~&k*2$BSZA}ftF>C^^aAR|44m*!(8lDq~-AuGW# zh>;!wGPXcf4N9v=*W@A7Dvil&;!{qXwV*gb55^fF!3>2dQ5C*qt6D4FWwt=Cmttor zG$yaRL5^t_vrAqv9h?+wm9)7uN% z;Q<1k@P;~o!8w!91{{b_`XpPETEpTT?3=X;ki#lou8(sLNVQNHuCV@&50jD$;BU9E z3I0wMuFn+qRe#rKI~$!E>+e)yV~lI;xprZ)RT!z0zZHILk%M{YOh`vsz@6uEb9i`s zq%%7?wz4q2xw>$5dui|L`swYR2Z#Mpnqvk63dk4k0xpUF#J!|z}RA+nDMypb*@olJ-qRMR~q>~?l=|<{VHm8vGk+TG7 z1AqjK`~o#hI#_AK1}|9$^nk%D0wAEU*6b@f+tDo?>5KKVqEW~VM_+8#h?w+>%7J;t zt7$94VaAh?l!3@`ISsw(Nxk_im%vl-F)B0WV(B8ipILh0d5%xC@#sPcnR-3r%!QZ_ z%rI-2AVDuF%F@$MF5a`N2VL#1_?c3nYzY9{@~r}<(eoC_G3q6CoNWkAE00UvoNhp` zjv_{6b}aFncsz&lxk}UKDdjLR0`_Sn38|M{AXteOD{2gbh zy*^vmpX2)Z`eJjj-n=?p*qtn_jTKOTXTjfQ;BS@d=P*8x1&=hO^jO{EUEWTsF*(+q zpB`ViGPAw5aD98_;OfR*@b{?y^tAu_UjM_h{vSN*fBB^U$(`lx#@N*Eow@#<$*tp& z4KALWSUhh(Z0|g2^`Ez|y{IqkSE>y!o>_*F(xN1iIisz3io7KYz>CC%ylg6=g*(_C z31#l&8Err)qY6moioA)K^eU0RY+=$sWGhJRt~3K(fzxW-E<7T5DO!I1=@5L3?gk|e zT)~0IhO>d!sB|{ag^Z^uDP4%sLP@J=NQ^di@!VM-WoQC_ReV#ILd4*i&vTp^8`B{P zR;4b}Rj|u-$4J;G|^SlYnfdac@RH>bu&=4U2W7iV|YuiV&P zJ-o(?-$%#&7kB#a-Q&eC7SG>(+W-9i+TP@FcjIJc=X8AQxV?7LSijT2;u&|YcAvGb zzU*9o7uUiSd}afSXS{3e#iWx~IUnv;nF8V(GSkar(!nHBo|7ZiMDl`+tj?~LxXu;7 zfN`B=YsNtkD@{FfnM8K9I0WTiqu?bdnkn%AG%L27Oo7jgBZqmP?c^;)glX-$ofF3wD@Uzyw8z|E_* zqZ?cIee(+Zz2E;t{QaY6{qH>5JejQyuN+NmpN?&u;FBA}xbuuVSG$i}z31)g?{;py z*V=uI_hE2n+quf*)CT4{Z&^&m(9pFkMg+oMVrW5B6hp4$UUl>vX(4cAt%S2Fy?> zNn|Ud43<$JyJot1&DLCwj1GEJSm_t?DrOo0As3WpkdbH3I=4L+X{-OTef@R&#{2DS?-nWz zymT;8V|s^tmd1%~Mo@2hrsP+JwUw8v0KlXz$t0RJ^7U11XjO&DO4VfuCN)~JSdQSY ztrQ{?$>Iv>4^051Q4$71p1+bAN|Pafu^FIghr^Fl4PBiCuS3jPliIQ=Y^o;a!qFOV z(0pg*)xsEED)oX)0naQL9lOR5>`l+Ul}ZpXX;ow{r-a~I^`qOMeI(jz#^D=!0} zkm2N%P=CSSD*1~`THIJ((p$hg6NMY#FX}J&yI7c-9NQQvqyB=wS2~3m*WX&Kzn+^9 z!~=K~Y6`eT+-eSw@#fX|GHzb2%wOMLKDf4V=hiMSeoy-E;^Ozb|E-7p?>y=M@$>!< zp6$HbZ#2iRk8a;>ub&RD-f3)}aq)~hS65%PufJ*E`ml5B1AM$Q)E)2(*^A2S4A+$` zGu(OZu4Gfd>>&Guw?G->5=}CFq#i;+8T6K6QlX?i!ZMCqqZT}+-W)gI9m)}M?j|V% zYVu*kDEo*!heTn%H0dZ{rJP!=L);B|voc3>uo9+Fe36IXud>lKH&8e(k^@Nr@J%i8 zH&fbCRwSD@CU#1;BqXKNSo)OtPE_Y`$mMrJ}o>(JuI-*W@`%KE`Wx!>yGg;0*a^KLh4ovlMU71POkon zzxS^c*5*%%+`&P`3MEY9q# z;j>sPhu61!@r#?!@16BO!8=Ef`dB>w;6?w(FLpn^Ju=zsbvN%e!Czeb@?#s1o4x0) zYwxsgzTdh1QTO&o#qI*q52>UMch! z+l%!E?n~qP7wc!-sUB+-+W3}ISU+>{Fo8IP72t2ZUhB47lVc+bGZX&g#?9Te;~U#& zhyBOLeCPN5`&>MKaY6q6@MZtcU-iCyJb9(Ei7)&PuiY75yVte-T$;axq%c#)*-`Pd7Y(9U~J~ENE(vd)G#~X<;?_%3?*4iJ+F{$1y40f#%?jU zUJ^IWViD8iHDS$Jv=kK9?1t5w2Qob!Iisq)f(b)oGMWz$M6|Uj9aqp_BCk#YPlffl z%L-^fz0iu1c_JexNo|oglOu)sjuN(1tW#R*`6spGHjszTjs#XFGo|xcBdaornW^+t zE6LF^eM&Rq=n)^$M2iQ?Ss2mdMp!iF_VncAe*p<*!H6?B9+8Kj(xFo8h?iz%WiC{R zrkI`tAu$N{ILRIqLajvpa{b&Qe|`PCJ5jif`&V;?qxk~r@8N25tk7ls9pOD{Tq%>k zRr1&M*RiuH#6CV8g->3Mc3RW8c{Mw=u{77;;5)y#_&vvmCr|pX?)Be4>wgw6e*ffE z|7Y*?zPdl#t1Q*m?hdctYi!}t!)d=ZOhz~{l|ih9-A(CXH`l|hph)h@?w z6QfOPEvnPSGExYsMcOLIC}?wvU2c;}UV)Xlw0F8X^XVJ?vClu)wd$=lGet;p4AJCk zzs&RvlID`;mH-mq9wHc^7Ag**X{Y!W(E4CgYkx0VG*S#02TBnbQ2!Z3Rv!pj+=Rea z{_qhjeuT22>tC#&M+-aSg{!K+M+=4fOSlDHt=7jkMu)&|d`1f^?XltT;YmD?e1y2% zrx`-V$19rnh{N-gKu>YKgTa}khaJ-r8koBQUW{So!j7u zvmLBKEn^El!Ueu=&0;V@^Z`CFH?o*~Gy$WA9JEpa!^&Blg^5Il)dIqr;95K<6Gj2R z^9-^=K~Bm`f{(&Vw;6f$!sV{pL}8pL$XGlNP}N+H@4lJ8W~CR^prN~HDSOkEFYaHl zK%0zFK-c%R2K27iN^EAG(?i+r)TPe)Xd*~DsVN1)dUc(^hUME7P1pg)0Zl%l4W32P zCqY*91{GPKM{NuQ;Zhfd%qv=fy$tgN1W*9?d3xz@y#u+M4Gv5J^%rmBj>hZXrH^Y+nozHC*9-M`;KP%ia2yni=PEvV)xgcG_UzR7 z%0m3)#&x~(d(?l9i(kF-%f<84{tsVZ@!bFVb^p(wEIpd*7O&i?Z{W)JqM^le3wNGx zviNonKJOfUQD47@Y&30=$;f#mE$Dz2l(dQL5JRaHH7IDya|ar;)#N3=iXxzDE|Aoe zhlaHhW>*6xJxn04Ft5GYV9$9c;?#z}h(kOsOuoJR^{Fc^^5r2zRZ z<7f^RJbLhoGgp)lgwb+yHa-Q!>9RZ!!4q&axif;5{t5%Wy^HJLI&Vzj_ADiS|3Ev#VJ!f`jZ>@*z>0k`d>WmfA4Ak$1nRoeYgM1H~n9{Tzj!RTw6f>ebCsxX!ddE znRl+*w?1m`{XysO%kI&aD9X6=##=oqrlc@ZRLPIzL{@_iRGI}6nC(e0O$<;=qQ$Nm z%C;0~Yx2gD8dl4Rn32MP#inXvD69ysE*#C`z-14O765P3gn8=ds5g0KqU=Lcn_iKU z0AI+UUU(f-H<8zDb=Um0oDtTS#;UVain+evWzCIxGEr=$GRoGlD>}0^ua$4^I)Ry` zatvLiv~$x5Y=ARgnU%{cCYK)af)oHzVpl5bGpn3J^Okl%p-$2yAqB9;B+4cUZJZLP zprZ~mkpnf>(;SE&TnwgKj}$8OrMJ5x#FUL5dyJow~Qr`?*Kz{T&x`qEr){mShg z-}!xjcYbm4i+6tS_dk2UcYeSBy#FUJ`#*cH|Eo9szj(d*W~17gy;I+0@oimw(Zu5U z)`wkQ`F;!J?H+!+*?(2S%Yzad8JO)M#V2E0fu}l1c+on4|#IL3YuKoDxS& zPhtdvp1hL@vYAdL#!4n2ZIV~;geL3&zsnADrIYSA^) z0#1ct5OC~)yf_JwzZT427T;Ko0fr2!QW?u@U~b~CSZprCM26-!kTks=EUQx&c>&H^ zW|~C8Qe$4nG|@OIhp2`9<08Mh0zur-7(YsLReqA`0yxQLVFvUNj^f1!@L$ z2|~dg4=0%Mc^_i}GRATj$4-UZ-G(^`Mx){ffml9pVxi~tFTR3QDvnf(Q^UpCR&lvo z+!!nFj2C(TYPN8)P&ivET&xtXtxir?Tg%-cet9tW;YmJ03h0(m*H%j{My3P{b64Z~FiKgZ^K>+5X~Yd1B&tc>8f< z_qpEoeXoNn-@VT|hu`iV{~;*cy7@t|(sH6AfsveMXe!4{V5GD%*@`Hi~?cMh>3hz$Xl(~5Y$JuQV;QiwsmasaOBTtFj&wGQ2TE|{HPRr@Su>QGsPu5! zq%MWQE%c*ODHa+;$gGfa4_lHV87at?1S^b8u;fUvJlx7PGg{(-$Y8;kgrtD~0eWd4 zLkp9Tj00fuioQV^tzkI9pu_t|;r^Ar0*udZY>XCr6UFOO#l6|$$wKkoQt{DB@pxmj zTbhJ*wly@-81jcF@#P~Ah@IlG^|TS$pS1(}z3XKOA1@9M-p=HSo4C7SA`{boM^MZRgI>w>!t* z=^TC8-utvLJkB&0PbtI%Mz)i%Vg&S|Zbo)M1FMx3pf}ed(V%I_*VJ=`b^T>4uuY*` z88W+JqM(XAtRcW|Vq&!93&Deu+L{BWp=sx-nv~`&OcWxL2V$Ozp*&=7P{tQDaye}R z2MYU5H&tE|S)8Rw3-65Ju^hWVv+~L%5Y~(qm%+zu@tl~eB1`7R>g?P@mN;RYu|ZZQ zF;2=QrIgc&x$Lg@^2r=&4iDmmbU%rM>M()m6n#^0DC~);dK-k&m_kF8oK02Wgb7np z99ry{bN6gGkQ|N4dqJN$8Kyq&KH*On3|ESsYH^}boNE=yUwwWOpTF8y{k^|fc(_tH z-)vM`3;2S+K73W|){71Nwgzrdr4c2hE`)NqgrD62f9H7fYI=Kh@#fCz(e=&yd%G7$ zy%#6FH}`v=KInb%sP{)tdp~~J`^me#U%uD-tB-nr`{C}N-s^7EZ`OC7H~TMn=lSLb zoqh24^Ul#9c2B;G65Kxc)=+1T8S8si$WrBh$l+MF$WV|)u#own3^)~8Y))B2DtXh| z7_!-CmXWjKW*}+edt@kr028cYZXmdjkomF@Ic`$3jqaSDMu)%=vBjfELU>UUk#VFx zu5`$mkSHuhyCQ>?c`k=;qHrw4`I}lU!6rB>Z(L4uAstuI4+?03v4t{k7yy)TX;85GDrMbBjtJ2w)&@sJ}ia zy(p2hxr)paBJz4!k`WfKZ?XPD36h%Bso?URxEz=BoDKR|i!Tuwsb%I`50Y{dc}Z>M zM^Gy9oQF)9n2cnXYhBa z_;|JWe7!JpWeo+|AD+Zl4(qJHA+|&2Tksb*ui7nsZE$fGUpt!ZZ7lib6+gLg+8uj)4KIB-!?k>66EFj z8QZ}ZrKuhBmx-;EMvFXm!m|Yhl+RwQ(j*uJ%N7EabDuA#|FB1<3WsfyVURb5X> z>eMxbRc!-d;VaIX`&OE>lr@RIr;@sTcH)@^-7^f>%C%a)FYvVp5hsum`d}9}^mF zM*0-NPQfty#`oj+{enVq*!8#0^)u@4+DLH+*T0j+{kh`FeDQ3#c(Gc1xlvqO-<+=1 zr<+6g@J72<)SE{!Y>FQzlYQ-XVgz3s+*qEwy1BI1TRXkUi(hs%38owxo*QILfY$OFP_<^ZIH<3qdAT|%&)7R!-=`>hBjob^H*u4gr^lI zXLT;kfK8@T^mD^8ie-QxOK5%u@xOz~j8c)CzLU*h^1{N200Gg=tK z&t&1vU;J`T4S%W#{)*|A1H}jaAOb!)iBCTBH?QWw-}$S!d4=EH*xP-Cn^*qi#<{+> zpm%P^e&qh&-sFz zr*NvjiNco)ab$X+u&;~b6*2gWv>=PMiUxnf=Q>Sh4+W} z+c~+1$JHG0qpril{N(e@#3(;Gxw>#|YvlmHxv|%~IPN_^?Y+6z`}Dl`0e?T<{!g#wU(Zih!Qbm2VDa42J4aYHQrLUD6psZsQq98|th8S>=UE%1iuZomE}VlQ)y& zYS|^2bvbTXYP=6ZjRxPP@!JXiylPyTAKn>u+8ye7ZK$T7KEM`El#kC$0T&`Qo?h>tFEq@QdM{ zr#1YzmM?yt?eVTusJ}}1z-1FwTqbQ{N@Nsa!+JQbiUCM;COyqfI97+qO|g>1tgvgr zEvag&!%7Y;_G<<7a)c6_IcpYks+yPuDzz%ecr7lI#X3^+6kw3oY{d$ha$G`NFeTBZ z^)tXO!JuTY>Owdv164)gJaeHZc_S-L%*5YJP?2R}%~6}lVuC9}EK?b;?@W`>3T!J| zXvHmCL&qAKY(*?0BgkF^OJ~6hbxga)0E4hBOo|r*U^i06-yj*DtTv`At=VdOq25^- zZsHIAL7uBMr>l*LN@J`%j6b;BE?2?8;Zg~?s^4mjB<4pi@T?VwOT|{X)TxxmYnADG zb+K7pY1g(o!`DWex5qli6C?L0CLT?XKboGrn3{exIeRfNe=)xJXl&`QbiKa%eB?^6 z(;DtnN)z?cTmzqwENzUIb|*?Vrb-91rQ`Y1*;46=u7BUTHQC+1H`y5CFHcs?UmbEh zO+0OWI`BGDF1Pr}=MKL1yLM$}cb#t@9qZ=vljGj2yS)$3dY?V)edlrSkDvAa>{ag< zuY3RD{odbv-1{x~`_abVzPIq@ZgYJ8+3?MeTDL!IAAH_DVeut@kNyx_`{3J+{yUWd zeuFaHj0)A(6o{>rrUUqxkwr4;ql!$bf>UV0$1=A-L($W8OC*Ir&T6R)nO(D3?ubC7 zL&-{vsOp#iWE)^lBaXzi^*qxyK)&&!Mn8nu_=y%O9!l8!I5gET(4D{jT$~?Jkn`SjI{7`%~$wg#hI%c zbGNq_POdIKxViZ3_T1~e=}!(PzBnHJ&T;1lCyhTnt$+7g^;+xk;-cn6dihSe-1LDZQ*@{H^Gd z&lC9M^UV1A5`VBAU;E|P1`m5rk9+Uj>3ww8`UL} z7r%eAx;Xi$ar4s_KlAK&j&$c4L_YdX3+w0gGp<@d2eB1x$ZfF_!~|Puihw{OkOHPs z%T>awH?Np3=~u9c*x-Njt9HJMCRDB(gmR$jxP!SoneEauCLWK)=v z7fjmFkCbqlgS(Fo<03eUFOD+Ren!|&rTo+pTWo82s#8!5b z$}XBlbPIcaO@53&6Nle*yoFzCT_|kMHa5By{MC~FbYXjnf9YUpv@qA@UpnxYBp8m1P_6)Q1MjgJ7V}%D10oq(Ws4%G^ZyzOS2=JS4OX|jU8=|pIx1Nd}HF(?THT$ zCq6x%cyqnEQM=W9^Yx93&u%{a@aEa;{;h+ZwT11e^6q%~#w7WBXTEg4SbDrl{=V5R z?i@TAE!FkmEB;{=9$7e#6xoZ1T&?n(3zK6V-h9^Aes70QPWGOj^j_cVeRSUY7CyQ0 zr1ygty`Q|JPi}nJpdiShx>r*bC@tp<1pu<7*&$LQh#whW zVIq04rQ!=g*TP^Tl;&(|S%|f<$VLI0OZ?5>XEu^l9po=G{Q0a%a|@|W$-|ryk0^K( zZ>Y53OfxJgZ9;3SQZX92cl?;60hR$`bc|?p5JFE=ifHo}zbJ*`dvlI|>0oQFu@3&u ziNE?wCEzcFZ6xnEZKf?vBCP9jVD2|v|B}mK zoTzQ)dO2<8(u6HCnsToALQno8FQP!%7%jP(GMBb=AuPRf3kd~SCQ}R#>)DBbAi9en z0Vt{tc9T~IGCH={b9yPlppfb>s;&9EIp0|CR8fDg&hRgYt*QRbcMH>P)?fUIll=O5 zFqozX6^GO*Di!goHJwfi{9TyCuTD*Gtxa)@KX~@~{MqXV&)+LdH1&;Z~g9r)!)23_w&=zLE)f!^AE68#?32S`TF9wLGn&I zX_3IpaNku1c~xOqiCk)9H&k1cMK7DhU(n4A3T0QsGzYWgu_)QHNwfuXF(UbkiwJC@ zEn3LtwSB3F7Y2%Ycp*5f5cm>-%`Yrw>)Wkfa4^GgP?4=T1hX};IClNo#XDL?CQ^&7 zB&;;%H8|@lU)E*STvAm<8HF{JV62~|WU1BH{6R^Rl$;fFsY#ovZ2-8!zEyn92)3qn zY(owW^4Bo8$ZoAPW8%kD4}Ek+H|?a;5RyXUA=yPS`blam1g>MwtFs?(YTe`hCFui#hX7OrhC z?e|xXuP@)fvGnNHm1lbk_qWF;hu2PCfA7)rcOE=>{@^jT7Z0Ai#P;y%J5OG|dHM3i zy^Z1fSIUo9%P&{UZ??+MkGD(HJ6sI#?_lyA`QCW=v)#H+F3k|G%JrM=sK1k&{_sYB zUEf^Td49a}-re1g&vw25e;@Ds==ttXUhVwq&F)`+u=|^jcK+_8^}lJ zt$ah@SqL9{{?733i*k;<$W>&xTb3}SuE-1SV1^(F364!vH6W|Mv5b;Uq7@kzNouZ9 z1JYr6EE7pr!Fy+ciKMVJfvu{lL6#%%09)fxpfUZ)Vh@UWN(r8Zb%N)N7DwS1A{_`9 z7&1W#!5>PYpi+w?wVc&r>1_pV!C$sglCx?3tn!+5RZlY(o7YhZJ?ShW2SLR&DY-%x zE7`j8#`??5gwjkD#uXX*Bm};QeU!y1r+F}`lbIqC>b#QOyo0+A6eF#AA97FrF$6cazTBVw(({lelopY z#~1e|Cr0MM-=&$I^@SU|c>5JA*v+%OjmP`z&yUs~UY(mQ&L6(`*7>8yXAd57dw6mG z;l=sG$LAMMFP^->w)K{B2q{9;Vm z>*p)8y#D2fulo3dN81k%$lup@cF5m{JKuW({_gzb<@PUMZ~yfNJHPpO`|m!)#qX70 zzcc$E9yFeIc89M1LF@2K-*X<;HE))vE;JylH_!osIV(nx&SC+Xk_0eR8#JtdVhsc+ z12Ih~^Dfd89E8HqOCR4f7O9{c2;X`k+D^ zkC!~f0lNN5_~9Ra^%uYV`rrTR>t|0MVM7;$MZ2}J`WL_Y8ru*4_$%-f0`yNW9{mc+ zUw*y0vHGiDe$C=5QbV(`vHIlV5xUSr_~Y+?wXwdM*b1dLC_&`!!@5S{@x>!-<}WnA z{N>l!V1)@0+`YJXgtT2>UH$%7Um;!B*H!^w_G-I$^oX#pzqWNP!jMj1fBm)VFWeym z1V`u*5MEF|f-enUuj=uY!h$2xu>o#vZS||KzJlGpP?}6`%_oy6(~ILaWy+x;aMSm% zTz~PG!Zyg?%1zwA!uolN>*tKW`mx9O#}52L!LHD^X;F$+Wyt+oxlEI`_~_B{^tFa-@Lo zgaSQ5F0qmYSEM6JwSjSFckrzZQHZ7hc3ATlCas)Zqdm0wjv*Y%4CTv+=uGlz;}JnX zYaz)lzNH~>6DFLB=T9D?4F$I}^gsT`|M>6!{a>*`_=kV^JzDS-Ehzkd{_{U!gZ%XI zqon`u|N5{0{LlXcB12>Hg58ioPw3G?{^x(97i91k+duq0!&(VGA2w;hmGi)6=6nCr5YhoIW_a_xR!cJBx+8)9uGg^_S}vT>pN0t$h97t6B+PH{_>D zNLqYLkbebGEh!8IxsAU~)NKvp%SVed-U!b=H0o!c`^A{7p)KHmYZ9jwvWEU$}94w4-JC9 zA;XctV5=%`;6kcjAg1qD#q~35qWNX6scSBqkFY`j49av#OQyd?WLQaCz+j4Tf=eVj z$?IqyG*(*^7GcS2&(^O$gH*-g@EBn-m(l7lk$C^xKl~m_3#71Ej4q1r_Qom%a2Bl} zSS@oEEv}*XLTO%uvrs~Y;EP`fu%ZNmdjIxs{|4C{gcsjnDh`3U*uYk^JI`ONjnf84 zun$W?2u6afrVPrcc{IRZWih}mvUbn-t3(fJ9&w<`184 z{^Z5xuioAIEAn^!Z{J(`+gG#y`T6)?T{J&mnHyjEV0iagsXm4~Gh8dWHCtnm4e2eW zIOkJKrbL230G-KS@yN{LvQ`xk$V5g{k`y*=MMDzSyoL*8ZNWwKB%M)np_i8f5`a0t zB&vp`wYsjhW^pE)v$;9r=rHqej9NVZNZdp{O+w-?YNGSg40X9gRsBEy_kVo5{*u4C z9OlKZx5!_|`EUR7FXnFwi!QeRpZpb@5`RHDGt?8docIfFnvCS8liro8FoXgMGQtZh zXHXIk0I=kS60bQ~{e@OV7D!tmcnttSMn=XK9vUcgAzM<5Cg>wJ@fYNn-nnyf4B8&;A0O_4yvGM5^4Z;h`tWe0T5sS}pvcLQ;qvrIV`-|hF+X;7b$V}W_H<|VtT*%c z+SIEXQy=V4e|9+a<>}P-?oR&j?&wd>N56j9`TAb%=LfZ)TpRn-{>1y!Yu%Z9_{^uv z2g$2sw!pHh+5~DqU>iS`VVVF;)}&2c6Bctbe@#_j0#yMP8PlaMSs9BjT&!n{C3Hk$ z;mrspI7|xe`1bXD_(CBUww{dV7O&RLVpG*GJCt>dR{FqqRAEtqgYfsi$N9mrBP~&X zpFYV}$k6<^|MoAg#p(JNO4nlZ7cIa1s{-xyGwLrec(@QlKn=xZGK9e2!Z+7n-g{9M z2J-Fti-HS%;xD?XG=qbtB$S4shJwJrlfT}S^SFS85=LL)LdFB+0&@`odR#RJN8w>L z=NupIURPLoiIwh>Vv@Y)=#jQ*AMRgG^4(r=7N6hP;`>MZ{KlpCkJ9Hi()u|cEyy_) zMAl#McLdkJql@$8FaG2o_eShWporT`<H* zBCOqm5F?Y7o`5HYIY0wBx0$d$5Xd-K%HD7}P#XGw{_Wqmey#+8FK)T@v-u0AgSp6F zl;E^x2FwigIvH2KByYTP<%Kj{%wJs3X8ipXZ)Cw_{^HFeQ}5FH+3W*_fyA|NvZ9-a z2_cl)oRBVi6AYL<4HMn$%Wh%l_rK@GI35;$``h12&3jf*k`w77cZlm}D53N9FN8~v zj6+F^0vSE{;QL4TGuc!8GoAP|VZQ&o(Jh0^Ma`vVm!Yr zsLh9mjM9kvS0f{=zgOlb*Oq5@H&}m}NTZ{V+3 zd<_1c9zD8ya5U9C9+^Fxn0Pur@_M!L@pko#Ugf)cweO#f{P_OZPtV7Gc0T&E^O2vQ zcYk))!I$p8z8L@dV)EzbBR@W^fA3cDi>u{Nwi@p)jXs;6c`!bA++EyjF7~U-Tg8>- z!s={weYC#TY;TlDHcI0g_34fF^jd53N^@+s(VZA>b?Oa#hpCKT$V7^A!*v|eSeLX& zc*;s|wCI9#WPw)5BsDaV8laNtOm2#>FtI+GhG^rWH*i*6fXPj@fxmh+$xj2TGJlLN-KHd7p2MK^xZ3Q+&4+*W zjqe|M{fs|0gx{;l^EVD6GRKZi-aENt{_Y>nQN9q!#eJlMZ`di3DV-r;ofs5^T;HSuJAON@u&OcAKw`MqutKu>*F6?nR#bs z@yY1QS$FlMwR*d@+Aptd71x#uYqOQLvElVrYrWE4FHEctvR+^Iw&9SNB&ggKX ziC^$Q@nwAxXGvJ)Ehx-F3?=w0nG`l1%w@3vbO4)J@4z4t7I;&PrX1JIWz(5Ni*!z; zqaaE)@!d(6+E}mQn^^^eCXC{)m&cexWP0FuoTO*Y7atu0X)D1kj@k!~Za91hJ_9oG zl})F}EpJIdFAdHcHp-VSb^1<3r{AloR2J>w3qf9OIIt)o2BKYq2-zK%2;i=-B_-6mdj%+!&5757T=jhXMDKX z96q?qlXfS8^ta-gu6uaUDPH8i@b9H?i;CHA2UdZsP} zm0D^7E~2;%~{IQfYdlS+#-L? zR-ZA*sH%z4TqMVJG6W*Ma<)?UpUF^vgkEe7oX!1#mB3}uHj$JJHL2AGUW!+ST)CV%*m z_n*bz-qw{{{ng`}oA*_JU*6q$|7_u>A&;k~2dhIw`-bFe) z-P@mRfxq`ACNJhjUM;si*r=22QpXEWy@J2b!s>%$Q_@1nvNx`usnK`gK?fwZSpc%2ilOBf5L{=$7cEd=Rr!VhudpOAXYo(9?%nkK7S8#phYtEwOpH&rY!S2LUkP&kB;mJX& zT5oy=3P-A%-R5tq%cd}SYN|#dRn@?25zR29G=!{8-I)2dx<^>llM4BcO?kwiHThAU zGg-`!Vx-^y#pfjb`3+qE;{H{5|2KaBDF6OZdsx5sh;!k?$&ZqTlYp_vU;WjgnaPo* zg~^Ro+<%VzJ=}SGvIG8p0RA4V&X&8^4)52N8mEIpX^tDe53K* zUGn$CD^u^x&pe%;c{nk9XLNS2Gk3Kyw^f;4DbCFn<|fK>?b=+eF;~EQQr)@c=yanq zR&TZH!?ju^SA3nx%3+cene4O|qrur!a7kNtMNHCD46>di5`csfr$9GzD)38qy11Uk zApb9I@8RIMapm~~APImufH^kFW@eM@oThV_?&+DHo}QeeW)v-1l7nn3*^({GRH%nWP)iO!Obxp5>eT}X)CaFnRVXmFytY|p%Y>?h zyuCX!33h~i+xXt54ey~kGu@H;gXL{mNZ2yb!o3o?46lVS`&JgRt0m9N!RFVBFskO{ zlY-WMeo@@WpMq<#rihKOm1IN8oZ4$58kJ;g@TAG6#Vq6~sCz_Pbz`t><7_HeXqj@c zi6k2Y6ERC}(qK`~xrI7$X{K7r_`6TCf1C70a=#861e-km3ZpeJ<_hCC_QpT=w_kCIX-&QlAxZ92PG&#Ic9{>wrqxV8Utxd5QiLV9wBM_Wo(*4FbGbqHEM2X9YR1V zf?*Gs^toIk-f0NXH zHG%#kygz95ADQDfMEmm|zoP!!k1Ctuo$!7*6$2^Yf6;$r%^jC+RdV1L^=Iby%v|I0 za^uWo3H)}ZmxpH-nxiv=ovD0tB3T`amwU-lJ6moP3)zIXlMc<))Lze7UyNkV3QT;h`X~5XY8K=_5a?+SHjEQix z7l=08(Lv3~xuS778gxY6uBhUPIRjC*KjQZI(T@!0%avz-nq!ZHGR%b;rJdunX%%u3 zf;(netbq*IRM{Jvo|nlLntSdNo7@a#lM7TuhY{(xsON}`2%>2%)J%!kWFCoe`xYU9 z#Q~5Sb}Et(XMSoC>m_hs0#@Pkj_oGJlYCEv^K+;5~_k$?mWVpy)7e*Bs4plSwv?I znuy_WxW@-^PC{ET7PLHrP}>W$4)-EK6MKga3O38JM)8IOa&QP#O$9NQ5^-*e=CK+5 z%D^1$(zHLZuqGIR3AVrl*&N}JkZK1eiv|6fh}-pN8oy!pAL0E4tN+&=eXSxgGBh|98k`OmM`U+gHX1&o8;wjB!V5L`^tjSpaJRM-1Gg*26Rp5g zUGFo)o@a*L&y8u%j;e$+1@(!JhuWWO!ONx4xnk&4Hnf@!&&5Jhk??RZT=zu=-Qm0| zoOFc4O4y@D99qQTLCra+>mI!OkM|=`@TkLxODWfxtvHo)QDV8A69pEqgpVMFg%sx? zcwz2XVQ&po1!aKC1Q45|bqm%g32V{jj4aThAo$(e6nms9w@5ON!4d*k-WQQ;@yiFy z{ugol9A4A!62bh9eVgW~5I>x0r8QhI6D?{f{G1C~ZGI8QnS`HZU_mQ8Xx_B>1zh&i zF8nNtHx{lfQ{{Po{h9d%DW>PO+NnS*X^QY&(V=tc(nV$vD6y+0$J$p(Mi!fKboml2 z7L{;3%{KK6(Dv-nsi*Pn41yx^}LOzR>E1Y-;% zJ^zON$prQPQvDgvzrz16O*T%>G`8m(SC$)F<3&9G4oxkO%q)W6a&NlOo=!HVjmmVe zIvc9t6DBhb&7%cVYB1sS#}r@E>n%ooL)pM|HF|2;vvxvRIOXeINtf;vQ%|--PYwm1 z=?0$e`kwCj9`E??6TkkeRsXr7e=8qY%?9R^{^?j?I1*?FgB1^2tO7}AAR+~Qa?t4t zDxQGm^=YcEIx+j6s57%?5hatp64+Omsj3MagoIrlBVckN*a2lU{#p1z(qYdl)||xz z7Rt^&gzY3mOa2vgOX;k8<)O=Y2AKQa@oyca}7Fpq&-p2e+(Xcd)YLYQmI{AeKJ z+*)O`Ot&&|?=oF2qbg33iLi*5z(XaWNkYr*0zls6HS-JZ>~aqU z9HdFTz=3rb2SJ070vKTyb!O;eScpxK$&&bE>RTdg+JOyPDfE~4i^~XGuoeN{D$zqwjJ6d@52^BK<^HS`g7Qyh|}E5)goTsBmX-yQe71MV({cu z!EZ+OwHN?P@mrk^R+!%t4yURG43{sUx_wT~<4|>n=2kR6TAY0T!9-|0 z8(A2PZ4Vh|$9x-$j@dK8&iQEL)=Im#^y8C&Lvh!(&S zFBY(f0AyQYdQZ4l*5R5k;+A7&eRig191QmPR#;$VN=01crFCBfa_o`ziwFaYxNx#i zV+kGq{(u`4B#f#V7n|nUz&R23D>^fbGoK~y%oQzENFrb@JW*RFDiQkpFXC{)a8+0k z$3rnnHTVU9tPCU}!NN$IE|n|KLWlWzBZjYOZPaOnAjGN zESUJ#LHp2jMe{hpwI|^XR70U|!kEvcw+p$;jo8kJzC58!&#FUnp6XI0w-`yy$D%XQ z$XGbk4F;QmK*i@TxP2+jYdE}q#iJ>1*{RcbYA2eVF}bBxRz*J%3Nsa2>zyNbH+m$5 zs{+ORv?!oJ;YSh;!4jLmhaQIos?0C1nOr385ht3Y_8}~AhJ_DJSpDc zwfO~l2>&47p+f|6&<8G1?c^l#vlhQBL2DJeSKG-#jw~<&rg#VzB1nxGVFng!+#H|- zWY|kWnPG=tMvE4d88NI;qL^O{kwS!Pxm*nfJEVqEZB?p~9dVYki^ph5F8&ak{1OHt zNYqpX1(>xD>EgwUl*;K=g#L;+B_L|WS&p?O;PgHJi}ove{-ydey?=zZXh^^{&7TvI zQGbs6ss8L&#rUiJ{+D)S1-46@^i_JN*Nyfo^#2O~TS^bv{lDV*cW1tFW3_P_<2O{| zcNovVqqCLXOs+khXiP_{Q>ZxytMdWWpFxxlbJ+&*N&@(WbEkVUSET?lBJ}RB(+QvH zLVvBBaQ0<%f7xqvL$T>_?1Yh8PDSU_fyuny$+_wSO0ghk@=7x8h$Wrjs3RCu{66}g zgBx>JqvlWW$_}p@$ERBGZ8d(rqgtZi7sZ=`z}Dnf0E=>tK#T~4&A32@m=y$(Hxz-f z1;6~XOE_CkyU@fYRg#6nWjt*vkpyySEwYfDjdO&JGs0p`2LlDj8DViVA$Uby0{0oZ z|5!ID+wD?>gSd&|huZtdSSCJTfDR*O34h94M;FNJSiP7;zHu zYt^4wQo(!r0%~64qC<`>AOaF>a*I=Wu!NzNklPDG4FzZ-j(~-^2FnDd@Yg7`P(Uu? z_p5#UTJUl?XEr$_m-~Kx83fj0*htbhMw*Wb3MPt3KD4mRP9Y0cIH1epH>m$NW!9g$ z|Cin$#P|*7m*=0f`L+D7y%&n`hGm`3iPe7;LHo0)Ka2J&eE43B-Yx8ZyE@rSi?h+7Z;q)r!FW*FJt6Hs6$}ZY+Kp)jc>O zlCTLRkwoO$go>UclUc4aizIr06_2aTFIuZ;^HBX6LO3|8Kg*{71zdzD-<&P~%bRq? zS&ln4BG${lV2zT1v#9-oEM^nENL&u7s>WG_8iY`W8c>2eM%+}h+Nj|sSqC6Phg_|V zPoMv#QZMpy{TYYB96-6BUuJ?2iTahS1$jXYt?=JkD9S<+Vey`VNV0V4FV~-W{091u zF#i?$k9hnB{4dYHVb32+?azJnXR&{A0JcTzNI1zU`hV&D-)Oji_U9trKgyZouO{l? z7lSA7tTlEfOK~OKomn28UTBZaR(sO}L({3obhJ7Zs-6f6e)0HA{Ca|@KRaFctONeh zRUmT3<=_iS67ig6UTAT-(OV7gj1N3urb^753HC967pmS=4@ceGr7Psq9X=&6AmzsO z>W)!=qLTmWSm2ctuGbfpFSKK=&?dgWfcJm#sWJ!VxtFM23xR1RaxG@rkpUBW{)G^0 z!5T?Kgn(tPc~c-}!pM|aa^lhQo20<4)5wlESF?paC(+9YBFVft*rtRvLe=uTd%#*C zLqfkr{DgxD_xV|_f$;2ACc+G|z!oI3!?nrf2=hyxSKy3`#S+w(aRng+uwY~#zk*Go z*y0!0lsEbMQe5b;yJUVb9@6F)24NP;%ooFpH8$A-%b^C)sH_T2B(XtMbh!X?b(*Wn zEWw)DWT>g&<5nQrqo6Fdh=_iEIV11OR)7-Z;y=JiX9hYmCcjjFo(l}l;2mEr5L12lUW6BMg%;EQQUupU+}`QRn$>CH zn%Nf!iqTZU_kX*9p%$)dM$$RZbyn8{_1n3@7rMsRW;8JS=8E*4Rp~qHwEo(Zdr6*i zV*bhAc~9pYJ|ybQk6{c8J1n#C3(rd+3y7#{ins_ICqLL9gqlgT;1n4FEHlg1X-XAO zvdBnsM%c29OAqyumMPxPFE|x07$*?? z+O*ofm=PvUh4bYT&Ul*sS3qZbWH1;t%&rz(K7Rg1DzRw+i(-!j5-9N6yxh3rR&^J( zXhxOm&v^J{pKe6LBo}m02@zb_2($l%hh?r=&cI^LKrx1;a)~xAa`yNo(-g{m{YMa> zR|wvg9-MiPLW>UxPr;mtG74UJN2XB7_EwgTscG(QFC8(n{|NIx+wITv{JXFHiu^B+ zzvAa#tNx7a2li`k(vO87bm9F$dj18!cz?fKF#RvyUsxE&dO<}SLU4GT9&@OM&T`Bi}f0BIKJUB~YwC?_ zzTpd=?m2JwoTs}Z`;sWimnwWT16I$ zh*W^g0Gg;;a`LuJG$Tao!?gfhbm6*6J@R=fR~Q=x|Y z46-1C?1)oymUYKKK5RnBmZ5{jF|uWvE#* zPK+#Uj?FG|{h9b}iuyBk0TaLIFw*_-zhRf|1Isi|owz5PMS2scg4uOJ?nzoBfLsJbzP%znUQ4C(=Y9AD zQg0Us!wWl-ZE{aGzgGPdn6Qw@Wm-8Rs?$J>$pSuvDg$mski<}%6azh|2`_AFT93@6 zAnpc~DgdO6Y)x!3t=J14jHnnBr`9(^>Buc?kxI;pDl{S-KqWMF$X-6EWeWZ3+>L$AA!xSIi*dkU$?vSSTW%e6cgyqu43d zG$ccepQM8j0V_l(kF{X$l*H+bgEjDyY_IJNu(Z`k`^ZJuK?)zh0TsLb3h(b@{+tPV z|A^+Fr24aXe*ygFj`Y96kT`sbSv%Q_LxScbyuXiccjEn{YzqFD-v1?jhcW+E9sNh= z7aDih8e0>^gcKhZ{0@!H)_T*W&UB_Z9ji`-!Ea?YP@Zz4M>ZID`NB@YFPfUE3yDvx zC^@+6QW0Y3E3P0?(f%EFr7DgBI*%?S%TF}oFHX2$o>N|5lHOb;Y}w&{8;}ZqiP@9V z+b5;(Spl1Gtw~=R3ygTz-6Pk$z4PAguD7$RmgX?^mI(rbEQnxO2qk7mFvZS}7!*Vk z!UAfnDbC!9HS=ha2ttJdTZ5(@?CkK%h?9L`)3hucG3^UC6NXpp7t9j2Oe+H`4w6u{ zfHe^ogqq}9gziJtA{3mOv|19r3VUn8CKF0RZ1QbZ$Z^%^A_}<~X9erE0=~qABx{N* zZeI7kxG53kus@Z-#F~Tx?Y%hj$U>&04^mPS)(}DA#+rgC^X5uOD2dg?nv+sYBwIN&@c-XIm5`Q9@i^XE2E`jA{cXBc=%0emu6kBF3R6rk-oJmy&=Mzf>~O_`2y0DCb{3=klx*tJ~&0;y$$J|O=9_#6Y7?C zTM7vbW`Gu0R=_+XyvkGr()BLTX$*h z{h_=TjI4ldVpiCsxQLK7J1zmAtT31tp>_vX~cuOsm+?eimJq5! zb8mOh#9;_I4va0+Ed`<9+j6gvPyovmMBUhIhGI7=5T@r`rWI>JD6z>3f=v*?5=89# zrx_6vj#H`##49Iy(qqPXowW{bJpY>Guf+HbdVf$XY}2;PQd9u9)^;PMcBD^6S?zb3Qkc(=wAond%TV`zE-xB0*OMkW_{oO_B zmsg};UY7p$g7mW;>4&GK@2^YfMH-Brp-*^o6}r3Y%8n2h0u2TSESQ^&j94>nkh9n0 zhfsnMLBP%cnpE~7NfL{F#2I1Y*J7CzY_m4DR)v|5jSfj5Oq^P@vXC2-5ofo{?v;Us z1n}CZvP&h0%bv6^f`Y)ll^C?+0x@hdi4?Je@NujRA+8}KOl3xFvJmmTNI%Yp)kLY@ z%WD-&lSFY0oJux1J9KQISZGN|Q|JgYW}LGN6&Cm13ak=umw8jolGCQWFEcm&fsohz z8A(KkMu8&yhvO{olL)an{>tqC#rH!+|IvZ>2lJ>u+wE7P|Ch%~u$^SOW#P380{+IZ@y3}}PtFbdx3b_ZS&)k`qUF=Q5|4t8fr}G$sRiBDr z2*==bpfu^yeC|+^yMW<~J^o_eKQ-o>+X;3b9}2uU>H6Bd^2!on``U{1`U;WD{F2WV z4(ofDxf4M9D%>}~tx3{GKyiMU>Z%Ch9l74ztdVf>;`jmUd zv8at)hyO(@7J^<|!LVrZykguhSD^_~_Qgz}g%xPBy)ASYMj}^$%ou`J4pfWAogg!! z4=(8C1$}VQ4$kz5s-XTM$QAW!$}9Xh-y-M$EKU)JZ>3EEHSsH2r~oO1R58ZdNi|`L zTaJ}Cfhzk}q8OBkDlVhSaqz{i5D^L%m?q9F5k(i}(AGhzAc#caBss@9ui%vJ?5PP& zQe(1MUl?Q~RL=WSS<@7<+{y?&G9m&g2)V6kOUN2aIU?4kaDQCv7^-ASWB&GRr%@d13}XJPlQYc=3(dzinr9}8L0@(0 z*4L&N*NNZJnM!xMfFaP}w=#{!XJ2u`sp3V%lA)Thf2umj3&W z^#ATi|8-mX=d03R?Mgq~lHOQ!o{tPU+t>Yg1n%zoy1P_`_QuJVS?xbWuHc2nXbGkW zF2N3Xp*ph&3^F-iMvsL8a3m3K$ZZVtU8Q|dS7ZPPbM+W&?2*wMPO2vW!WwV#w{9Fu}+; zBMY87vm>}V=x0Eu;eiE0B*8UfFO0CcI{`B9wEvKpVjzhm)5+qS$hfQe474X`p}6Xg z$S${p4mtGq_0^f#x7yCs92H}sitEl2aKx2iNGQ%_K$Jg1%qk&NPFN@u%yI~cr7sdq z9Trkre=1wEBrwegL&w}HlDIVXtxdBciOI2dM7dbgvdKp%4vIzM_$@V(Tl#!p=BBVn zd97tHF7!FY77BHtYQ_4p@-d3_p;Q*wc6e{-KdP|*74IKW{W-PQf5h)Ep#F^cC++ut zF&_oDKbr>oj>VSnr9{)Ds$mi-A4bBY6VXC0SuJJT;CE%OyM0NaHEKK* zqb>S{;m}ZU(>r!eRH4uNy63ckY3h05&KEF(anXWVNPrb{P4FUsul|T|k&K>M85a1n zvb(Z~lL~Ut<9}d*5J`GvkqlbZX6%Rq?Gy)twRqu?;U#QwGZ8gp_*^}l@}{cZY{Qdn zD!#N=_60DaMODy)41HX|qpQb#Y%(~|1Og^RD5xUf*z7XE5-xA15Pt*?^al&$&|k0B(}{Y&L}o$Wo-&w3u-IX+?O!Ye@M1v$|Z7ADolwu%g8b(advSGlq57w zWwCcoA+bmjnf6SvH8Ue`Se7~C-kNi=j=kQ$cUCS0ss3DxQg1KXoXP*D-1vTXH!1pm z@%`?IoD0dxfE@M6K~2Wse$_#BA7rN+uN@o|=SmR@0N2M*5yNYL9-l892_@puTsm1E z$Tlhiz1HAluRb@{T%K%h&NP>LMPIPGc=b8rcWQQMY^F9mQyiMgw5DQp%)c=i7#MZB z{qAtuY=YK3Gm+TWmt3!{$nd;?m;EnQo~@_dH^q<)sx5EG@1BxBI3<(M-Io6RoP^r) z-=l@S4Yd{9aUq_|fKyXlQ591?wfl^vX@ zEu%D2usof~uP9?IKTzDb#36~wHkUJA^M;U{f_=#(<6Qe9rmA@ilq3Qf@3${D%{>YY zvdyYOjW)$%?qYv-RPp<{tji9@V`D0`cHgg^|p=u$;<57H0)vv$DJoBjODP@g*~-;_^A8~EbRmVx?G5F7o60*|&JWHwKiYQwbVvD%UFCmVkpK3g z{12Dp|9M5mvn@Ga)SNAT(Pnkn1w-MJi&TY1FVc-n#of3XKrfPb1cnQiLOJqxV1(I0 zHC5nALh+gsB7~C7vH%vFCeh3_V=jC*&ghBpf}CyzeZvVyHzBoRQq_=(At~#ZF+;G7nGF1fL-#xIo(Pv5t2l8H zvI~;EN##yx+U1HQ;yi?PDw(+ zHb|Rd;fTF9)z}CWL;|OhI@=K$&6TCVdouu(g+kHiSfE->*m_jIeMx zeGWBgz_CsXal zO5ISQ>+po!(Y!m7)51v=ZvlIQs0=*lIbT5)dR3vYLhIKMS#!L;=6v&{^E(@^?`)`V zZK`jdQs3Uv-aF&@c-Qxn^PWGyr2qVq_Q_?}FRwa(eO>vto63LOMvxKyQ-nQ!h4Y0A zhU9-;rHAErPD)SKllk;cVC1sd3f(>DN_U7{Mn+J>EZfYIH)Jpcae&JVf@t#57PfXq z_uv99%`x?7_uwMkA8@Z=iiN`^&ns*)$k-`0Mo~|Y;*J*l#i>yHq}JFBg-6O#v8AU* zf}zofZ!E5jryV0nIqNhW;i@|`q$g`?binB~=*=wZr4z-;F1`H)$tr=6LGM60Bq9G7 zC6Mxo2y2RhDKxlH^4iWq+U85Wy~u>mcbbw(3P zG%QEGPQ#@|6<@-gtl*m_D1>S#;|wHFw49pvRLS+#747S*u9ucwFRfs$eq~wx>azOM ziuUrF_R6aE3f2_#SJ(8{*4=NM^1rha{P;rXr#qj#lFBP zu;s@V!d4JXYrH~|DES6wgPkp9a5e64SLK1OH#riFjRc~@f#^ukXz9s7xaVu0L??i! zJgX%e4xfRd!Ue}JB)n}3`%P zHtDY=5;^QGQ=5e1clGDki;Fx^z!^qPvP9anFwu&`rQnr$%*CjA6i-A6X60B-Nsl=O zmL0Vnf8~5Sd1}bJIPV(UHtM$ux%;)mlikoWqn;P1UC&P7`w0FA?eOh->_$0tF`wH` z6*r@UD}lxdy)~t`N1g4C(rzg2igT!_b@J|B+S`l!yTMS$V{~1yj-2c`lWj-5E=Njo zu%P%eE_dARiZl%Asaek#7q#aWRNOtDnbV#+p*=mPKQpI)aY6s$JcVcHwddxwFV1Pt z&+9KNdcLt9_|{hB?Vad{7h^xU68)>|#^2tE{Nt_gFK>l@bvyXacLKk;>;IR#zJI;z z{kOZG|8v*#+q?R|-_`!>p6lQ5I6k=~V>s69^RDecPww6bj9eguQHvhhmfaENg_*^g zJRqYALM@hwO_4~`L&l*cVeT{>`!us^5&lK%c zNJz?Zd()2C`Yh>_Qx<+o^P3w0jwcF#`%?a(sxOQVqyE(4inb7V{ zY4<0!yA%5TN&WtW{$NUfIPHGwgzv@W&^I=sZ)_*Nx10R%V&cb_6MuF!{^!@?e|0_f z^Xt*Sxe@*Qo5nxfiu~eM=zoFe+kxNQ@%{Fm=il$Ue|6LKvvZE`u1U8G#c=sjVDzHN zZ*SLOlo?EuVsM1HM}$iy7b%*mOkXJwMw~sbnZzt3NjPE%Ka*c5Fuzcyor>LoTnt6# z)?-@Bk~>iewALfD_nf156RFLHXL{VxnRK?NUCl|gF{#%QiDl2ko#5on0A7tO&Nu=o zzU*}6EsnSVpmRymyfSKKPB%$}6c}>ACPl1Vh?7JNm86K(OwFeDa6bq>j5U!b2RHnFBR>G7hz3sX+{op`@5l69mzN^wDI z?aHH%MFy{xV_ReD{IWiLGSFTRHr9f*^>B45P@i+RCbjmki~Mg>ZiC;7t6On)E3V$4 z*2B7_4d=ZA~ zmq2v<&#pxO@@n+2uSY()5&oaIg1^2K`0f3`Z|?bje%1SfZSA>kuo64%AG>N-q1F62 zTpmzjj({haqQ_p#^CF2HE*?k))C@bjPLhZ~yo&(2r#y$NcFglH_~m1{zVk53jA zX%pU95q0M1;#2;mFQp2XMzqCcy@yM%8EkF@8f$@CC9>ume&86rr}l0*%S%e6AiIOI z%Y$hF&C6^4apEz`X_TF@suIZ~uBd*xPY5qh1we%Uh#jZy2^1VlhqxBZGSRfz7kHEO zMHZ~F*l{*O+ai_Mlu81z7RK42keMq|5PGc1(*Ag#i9Jm-mt~)F?aO2Ck*ys_g(4jW zXQ2%N%bsfA=6;*D3bNDEmwHHG>k2g_^O@ud54P+KLXNX)S`(Vs;0Z?v#vAvpSk+mWb~d*h!?)Dd&3JxiFtXOuPK?Ntqw@HOJUpxnas7GFIRt*I&TiGw zt$|`hT-`xuudI?&F1v;*O1ZegrY=|21%!&aIH)dH z)b*OWUe`|6wGD)twppjJ)zHs%yw}EpcV~G{FD_iMro=(2Gop}3f z{M~c056?$`bkX?PmB`PpMLxM1`PH4szub@f>tm5mZiRnxG4RTwGAB=~!`A}*2#j8& z#ySS7z~2$Jf?0BlOtfGYY}!c#to3}#An#klS!2j}eheq}7=GR5Sr@%RNw)|hR~V$R z7Sx78o>vV-1MO3>mFJQd-Zh$!CiRWe-to&u`)aItCDFK?tWB%SvF3e$>z=Q1!=IcF zs5!4Qs-d;P9hLMDD2BtOEAI)r;&r_=rxj;Z9FxrcEZ) z5@MJK>tJmvTZIRkC_I$W&SGtv^1d=j87VxcY0OMlHkfBI5| zioMM#=9=saWzK7-v5?JCl4a1!CjN^3?qxA$w!l2FzHN%`S?k}WW$NI5#5PVNvf&sA zRnr6;66cLmSq?Fqu!Q2TsZ1(jN3=!)N}1-NdFKLAHCA%v$6bw0j3SmhH~r<^Wcp+& zcw*2qS#pmSwQkWhRCaX+;fPguVd9r@t~fe%soi!}N8F{UKz=5anUAHGTph-7*Hn%)Me>U-GKKax_ z;<@GcmsVq6TaUfA8GUmr`n_%A2fN0PE&yTUudf^bc+2>wd&a*!F#hq5@n=^e-`Vh9 z$riNgZUF69!_z#X$89Fzbm>F%C zE45sqXv9;YXfha0g_1?Ltm(2##Z+mOB$%ebWu3?6uV5@|8 zNc_}C%w5~KU6|L}y7+w2xjfLCOM;!s603L+xuTHttJ&p;%NmUIN9?$1yg$3WFU}(} z_OB=lZ}T6qZA$v}j*pAI>{AgYgt2|%&$V&XG3=SLV)#pJ9%a!?vd)98hErOop(Tw$+Nh^A6Ur^cQYX`itz2Yo&=t`Y`e0MiT~6qwxIPd=(26mw znoyfbwaM$GtCesKC0(5q#)Y~j^Xg*7v(*Y*7!F?_kKUO!9?eFdnUB7(WW2O$yn533 z_LlL^w(;RP;)^A~1i*P=x&*YlL;-OW?Vz>+^c6AO=Ly(0y9WVKUv0_35pW2oh*59{UWU}3>X zucs2Hi;>ec%*Nr%8Cp8*OoUvqpcV<}A-_B1)8auj6LO`4u1wI83pw&3M@T4ZPj>v!}ty(yledAqVbnkjK95Z{PMQ( zi`&LuTr)n{HNJepG2)!^cFy^SPWyrI@UFXb0zKx;BUKc^FPfpU9h?tLc64}w+@0-^ zKAi@i2cIjA6*0`)=$($w+}8ZZ@q5@>zvPooJ^}cpQi(2wEUyRaPevDBtG73%TafgB zMXNv8r^PY78=J!Lol#%Pk7syE!Y)2d|MSaX$6h{vE?W}^#zVnj1m(&MmPK2wKf;N9 z#ghau0#p5J$H#GQ>C=H?p_1IUJbd`@_`Ln8IET>h%WXxOCYxVzxQq-mY?Lf*^Dq5; z3pWypBNJIo93i6$Hm8UL+Oi`e&gT$95>v93SH%0a#o4w@QKA#?8M>XipQgt_D@wBE zNR7Kw(?)14?d#?AP6_pDN4qZ7J8F5tUzm$zR^rL6eDqv7Sk8u1K{Xk47(Pb;A7Rk& zPK}f1-O?NZT?uJ&M3)VZ9P`KtublEpg@7~|mYPv{Jfkj^-KQG<-EQdWsId>>HRH7n z| zh!NrCzyN06+`)ln*3n6 z-EC5x97X7`=J68D^Tr4d>c%m@=y)TCQ`yuXXb|YJ1(Y{(zMtcqQ{lAs&0knJd~C-{ zFbADIjWe6#(thOiI^Gm6hkZA|L6J3K5i1TXAp0z5uC3#@|FQyCKZsLSwvzeqNM>c{ zIBi;*bmkDZ!huazBNdT_wAhrDolVgeW@tto+v)c?BA6x8a1SQ*R#s~bDD}EhX}ii} z-ok7oyOd09W{tB&d{Q(LR+V(f34Z-Se@azNO#Sr6=V!k0&lTNB1(Gse^N#`D4pzsg?ttnov5;Y-F}UN!#iCe@$u zX#D!A@QuMxFuUPzZTMOnfzD}v=d2@=$Eh=$XavIeHCT?kf}G^bG%-6+7(RFQc3|wP zqjgRzZbXvvx#A!cjw}yH3Xj|cg!F|DNm`m{{pnMIyZfEw zZ0Zj;h!X-MRH8)N-7y9^Nt8H>;^h2J2i&iWc_#O)Sr&h%OJiHJZ$WI339?KISwD29 z(%v8X;q;#*dz5jyWn~|0!WySo`NTeLIncEd_%A7o7}*hl_r<&8wYfu)N<%lDvd^W2 zRD8U|oz}fMHB{1*RW;kv3ZvfKR4Ba=jh{?M&)|EY9k1dwz;D#A_&th_W*{`oQWrJd zkkJ=|mKMC=gO_Una!8d7x0LWmS)Wu4O0BqaJgd!>yzBMQnT~OB#JDkT+?zI@m@}SR zG`_N8ys~b*v1On+3(vx+NdLuE;`jYs<6B$CgPx-hI^l1g^f%Uh?F|fm&@x@~B|G7T z@%+n+eWm&%oD`e75}vr}>0Xj*+ipzOm6*?a$C^^JQm4A^k>%k?VZY`6I6MXHBopx; zPYjK;e^39*2K(Ja|1N&-IG+Jt|K3KB5!C}eHe7DY{T_GE6G#!SV7Fp_-vZlu&p zR!8!cdOqSB2stWYS2Ln_qn`0-0FTED$;f&pvQ-S8Z#v?sWGdi_`Q;$`lT`A(PD#G%2J>F}IZVNu`k7h+(E{eY)shs)jb&k+VGmj`-%J@jy7@7nY5e z){NITjkiu4@9!9Ya>4l1OU64p#%o)~Q`7pGqXp;dt1tT+YjDJ#!8!Dt(K}e&nPQ#Q z{wrn2`2r}79kp~Sm{~~}GXw6Cmegn~HH1pN356re!(OrJyM`zL@Cdf?{s>on-(Ga@ zOcnZa92Y%uzx@wu{q{Kyw|<<(Pe~I6iqZ}ngye9hBM%Ikd`@7Es*Ykg#vrTU=Nzd6 zZ`gmQf-#)iBT46bqq#q8zvkwr{DCRtI=tV5E*RNikZp>!d7}E`hjsxSlzepe$PQI; zxfPdJ(R~g*;Pl|tA-seX##gN!KD?WR&9Gja!Vr2-ebw7K<-xeS_Lir8nuE7}+S@+k zZk_fZKq%Jk_G$Of8CK9+r?H7RbVyFhdqHn+yW88op)--;oy^RY`ud&9&`3_a0q7xS)@CD*BvcD|~2ngcPfoCqi(yf>xM2yWbK+zuI@mv9ni0ugl9kUJK> zIH-{$PI@K0K3R>rI%&_ufPcOkUTqquJI47D1HDUd#E;Jz&%zO}8ZU1cZ=N>ZIct1) z-uUiWngNI$X$(%)DO+Q%Bwn z4%{>dSOhFqgb}v3`iu%SlB3X}0o8?`K#xQ7DSA*QV52U)FMx^9gIQ-J?+j%mjDn8W zFdEs3QSOPRBRS+qcU{>r4AOAnrMB9--aM_h&LC(aqP1ufYZ1=qZN#n6BsG;o6Z+e( z*0$C7^887;r z!E{hD@Gd$IAHA2Tfh#h+Ek;VPH{>7A6r+lb=VHGmMRXu6X9G$psx?!d;X+_~FuYVZ zHt-eUo^ff+xHV}!HfubyXuP;$ynIsBrOz7QK4W}!&3I}da=Pfj2=H`gHPT!N)E51< zWmhnR_nqmpO2n{vl8?OfoYwWld!9_!HHcZ|!7ttlLFhU^+yA11-F1*=k21C*qP^?L zGReMa6Tc|_(#g!rYtbh+9ZRc@**R%;MxLE;%#JBj-N076@OZ2Eg^~QzU4^FpIP9MK z2|fIaI8~EfcGMT|o;hoXsFsNLm_dJ$52IcyLTPQoQaz{7}rKRmMh zv-0QX_sBh(jrOo5iVK$+wtV=81`B*{O?6Q(Wn~jRP7orPvX>(p&A6q))XlZ#OyuhcbeidCKeda$TN9)p(wAH<Xz1DMNpzHY3yjWb>2!l-d$ z0>eCvrxy&=rN6#zeCw3)$|>WyW#i$zvDL`p zu*PTk$fCkYH9gw#M~8jMo<7iVRJx3?vsOL!`4@Ss^(M&e!C&ihmBQU@kS^_!zKP4& zTuHy;f9AaB{zdo7u6OpdKD(jKt~h7$q4OE{MlW@*RepA8@P#wll?~r8Ou@4pIPA~E zFDh+GIU00CH8tvV`EeIxase{2Y^@QY@cH-!=F}M{8V0%i9*GkC8V=iL{J_EUCKPx% z(w`n~k|JcREJrqWeVV^UCS;_%<{!(7_^=bc88I!F8%1Y2@M1{|S0UO{pMGm0;z_>zh@CVLD?52N;| zs6N^0!T4B34=bLS47$T5_-JQ-%2{3kyv#4)?W1^GZJ*VKcJ!h1dgp>?;&x#6VPy6} zdin9<>SLAF+tu0AiJ&9nmy2P!f_XyX^qmNNCy`z7=AeA8C6|ZBvH=O0!v%Zcf}K>G z(C~ROe1lkwW8`LGzJuW|jZ$HHVbQ1+*5!oXnUCnzq_>j~jt@rW>c(ozINcR>X&^iU zhf4^*v~GNH*|>kgxH)57?Dj%tVa{fzo^wbANI-9~hKu=d=*$Tu@C>XAH#-^D@qJ^AMS;PP!_ z_Ihyka$pt|Z@XtV97_wH^HZ^Vqxomn0(Y*tcDDTH)LRD*`}6SYb-0RJ6bOf8Lsjuk zmWRj{oHD<*JH{sYU-J%kM1>rC=TgdU+H}F91Rt&&K$)wupVR*yzB|E!{SeB9fqt5c8+StXDQ) z9F$NM^5NsG;Fl<7=PRCQY{}>3ms~Ka(BdNE*p8&{59gOXAR!`1K?F-bF^8{X|2bje zI18->(JW+BWX@WU@qo2`rl7Vz4<82cduRc?it14`zl=sIych3}E5W2IggP_1T`&t< zs6WH!0%1omjaSUb=lTS>fZY?;q65BxQGapNU+4u2J*?4s?9X?6xsES8W?zlew4cSUUcnC3BbGZcy{SQe(8R3 z`A&KMQalof<3ZJDJ_W-C<0*J5E6*3?)snnblkq7BSF|-?$my^g@yR~7ta3v%jl!o! zVO)I#+@H;JAY3pI=H@I^q-}(A1`zha3y+l}vo&L}X{-+!XL`oD5o34MI6G{tca62K zvC%a)yT(My8K}*V&8@X27Y9cc^4*0ua@+J(OTB< zz#D+eKvR_yZa0v2hA@)~xm{|lf-?=^2{$2mqL_|D(gL!}E4kdVL&wLv;BB4$SfsHS zA3Yl%-Hwl(iTAeR!y=5Fjw1|<(A$b3ko+_v7$RtNPa8e7FrPIhuNo&FV5EI~^XrMz zuNm`?$LAkrSD(l(J(gQ~kX^i&U%XwMzY>i`qBMF+&IRN_xL|{3yT#XvXHbhSh^OGL zKUA44iBBaagL2qQ4biAsP=AWfT7=9Of z1COF}odyjH`OM`QJDm40Zd{T>E_E^Eok^=B31>6vK=)kIC!wj|_P+#jpF94X`~qIO z17m_jQG$;=yg#P@1r!#%{m6XUucmWi=~;jGEcB=H*~9wq?a{s!kOhG}+2p|4gz0_( zixoG)tN5aFfZ#=|6nw5DT6W;67B6f2lM)_dF^QdundeZ(@#T6<39G4^TXlP#E|(h4 z1WMz<@>H-o8>!D5?bTR!gFqhHjt!qdKqM|AF-SNJpNWoa8^dRe;j_`Wk@3rs z(F?xvOt>bE{6?NiVYT`}YqyWosGSCChV z@~MhkY4?y+iptrL9QDZo?h6(}u|P2Tk*F95eo+`u63~#vI75y?g`&kHJ#b^f%LJ0@ zc6ofdKNtu{!Z9PBFtTZ*m^CUnqgF85C1a#wOatel-{&h%FKx^(ElpuAuc`S;bI5Q6 zeTt#GJ_o<5U(zF(BZywglcNbanpdM`yxP$o$JIHqphAeG(OULGVCr_F`(%0W*?Rue z{Achx+Zh;ZSCA3?6i2rI94?#(Bn$|bnFC4KM4K>@P}Nz@_*M#z6FGS_CDmi-o|B?p zYAPgh#Z8h}7AKq{G?;k`{2unvEKli_|gFfCMQjhfDd}0X@0WY(I zxYb5}#6jB7nMY=E%*Sb4;0XU5ULXFwwkakQ`^7>l(-s|7-xkGrp_(2ZcmqkaA@tv^}{VraJWFRfF0B=1haD#SpB}Z)FiCBqdt36zuWB5HWT)CTS-%Yo%zL#yTOdU5~ z3#KM8{!}#19=`J*E=z|cJXRr~xMNQ0K0eY2cfO3re5-kVsh~_}rA|T`j7S)B9>T|9 zK&uGw0W?_<$3IW~S&T>P}8eWH&e8J&^jx;+L5vkoN%kEPmN(;vnpWGc$mFsYf5iYdcMWg@H0<&~wPvVu1Qje0#!E*Kvy#@E(Ds6~tJ zU^GWlD;=7n9hkpb@?$u(==_bM|JNgBd{W+zu~^bzNUDaVT12X$p*!FxdeyW>X9u0j zsyiZi4N&X}8NqNEUqtok7@DSeja08YbauYA*^SN*C}UB7+h8Mx_vD?)*DP7uV1Z_^F6ZV_Asr7CG4B(TB@byVCP5= z$U1I^Bdof@ngef+V5l2DPpsinuXOt~Ydd&aA%4X}F`(w<@E##C)As*4a@X8=ixU1v z;8%dQ$8R4nhY!+rnv5H}$o*jcSQ!=<4{OsU6}0pWrTA8tFcj>dJ2=s^EA zCX;Z;C|8C~L!jYpF$#JhAffFRDQwcnXvToE-8_nr8H z2epLH;`a{7jf|dA7iYb@jofGSANj*E7(8BF;bL zaF%|4DP!Lc?muihj*%Nj4nBcp?!VqMz_$8~9uk~YK=zMhlwQU$ zlyWxHYBQzN=Ty@EN;Xu@$Lgh2qnc~fO2fUO*%Q+zH&0%?eDT4f$DaSnm%sk{H(!18 z&2N6^tvBEP{#)<9_s$0&yz_$(-~Hi7?|t;~`yc(u`yc=4gFpF`AAJ1r4?h0r2OoX- z{s-^8_wIMz`R?oAd-EGFJaM<;3q*2_un`Z(l4!p*QUlTKAS#j3LIdzd2U>1?EHvKH zBTa9h7S_uNXE7t?1{^7B?Fk1*qn??Rx;Wshw%V1T+D4D3ya!C2Yb=IfP0}8+nz4nT`E4i zp84uZ;H6plg^}RXZR26xxLq->mWDAo;X%c)T?fV6JAv2tCLg>wj@bhkyQIi9HS(&KD2Myc|}8#7sM$UyE5AUYp9p zHgSZe%|6U=fj;fz9Jas``zP2(hzJgV7HjwT%MwcVgXb|ERJx+$fZRLW5$i|={+F(_Jb>);oi(Tc~RL{vOP%cwBpMc`79 z-UY6Or3Rd@LGTVIr17*oUv!;p`nN|Dk8KTq_1fIq_ojbzul>_Y;g3(M@6LzcI$?Zs z-1yq4@nX+-wqrcrH15@m>x0IHLTo#gS&J0sJoRx$cgQuxr})#Z+F?2Cw;dyuatZNc z_+1)r-pgP%vEHTN#IA38tT}MJ{%58_;h3c&7oU=!c;5Bc8`-UPfcnLbJhsEX=tv2> zOO(dr>(8H)Umke~YjD1QH2=#Ki?wx2_^jt&ar%D0(}G+_o_s=;xaAe8h^>9P)E&bg zAEa@K5(ZCp;(}j%c`z#D>x9{Wob=Pjj{^3`kElmRR4v4s?2F)XscsLx4rnCP=|Z{O z80yZgoIH2!_QNlJ|q4O0V4-JlPM zjNrA1qJDBHa&@`!&z|_zvqQhWANkc)`IB?%&(FAjw(0%RYT$!~@ONj8 zZ%r95j~ibeHlFJmkGG8b4dYfRb}^gTj+ah`>Z`t?IVbf2VL7r4A1P%09;V`~)e%3k zFz~gW8>v0WHW2Xqd&3x+?tBLCuy$nSllPcaLs>PP#mu3uNDe`zkjEOIwQ&rtIToIk zpME)X>x1&CANMA|+$?jhBOgVN{9T8ITwOfgU4Bk}`NawpY`}{SLtYN=5fU@)c>l{a zXRPfiw3Y3!%{~7sbUv+yb2wwa1T_|G5BvXGzlEeCjunS~y>eJ?@SsF|yeuud{lPY> zkx3Gwn}+xe%4zste7sDTeX2|!A0&K*RbUI7qG^H~DA2~qfjVr^DWkcAVIx~8)>}iP z6O$*;Y+t|k;E89SfA!6`-+24o@4Wr}x8HvI8(({A^#nfetE=ekR|75w-qTezMbTY~ zThqK=zt69{TzXo)^9AMc zFYAxJmD&ACd+D#I#{Yh?@w2J+^?V)~v0#tC-!nDu+AKz&a*E)lVc%ZB>8I_B>*T0E z|FPPy>{3mRiGS)*2g$#}NhbsePI(6W7s)4Y7DK` z+O70?;U_f!+XpOFf+hl3@`>5Ln~7Bq(pB-i6SLxsg*>EyIk_9mBd@=_V!-g ztNXj|_dHK#RfsG?&b)HW9V>1S`8U3&83*{{EK@UxGd`t`fB|NXTj7A3?|M_9=F->@{{{mB2k z7x}-j-6xQL2ZW#3etpCI#g+KaF1UZWpZejc%(u3(f3lwaBI?r1*^iC0k4M=zdWDy3 zjpy?H=X1mqen)PZ1SRUY+w1ifqAUIWhw!*M+q@m$c`>>EYJTxibq3XGWQC%Bd|wdC zUY^Epy|8!;P8-umW*^kr}1Y|wUOi#Di96xMGj$fRoHQtH|h6Q=HK@T(hkoGGSX)4xS zs{LY4Nsk}oG`~2u;|d~yTKE*2_DqjCVwl1M3_N@o6cBi)4kpluw3**oFS?MAu9l+Z zoI6Nq^!}TR;?-E*f6Ex!W7GRD>@TXa!Y?t)dle6^o&@hY8tX6uh#<1I7nw!BF)4h%5e9D;_c4nJiJ)>t#tfpqzF%^B^X+13JzDEgEjqW9O)s|5X{@x_GFGZ8Oz?o(qLm_Au`nJ< z)v{iCH0oWwboR+BSN`PD{@=W_{L42=|K*PQs}~}_ej)OI+>QM9#mK+B9Ql`*XkB0| z>izHcBLDL~@rz{&f%E@(Df%xjXur8>{^F|rcNY?W4TSeH-`UQ7eIxtjRjNyWaz6VW z>eBrJR-L$8_;7w}&33iXF4xts0*2p- z=t&h6@#y0rzh`9lv`pkeArq=e3MpKqdAF47@jR#bMQ!1@0wnTmk)wK=i(Q0!ndpf0 zSlkf-`Ya7H(ODi8fF`U~-svU`;+N~sh{f1>*k4TkhCw>SFXrSxcLm>woD)& zw!%=s=mlLj?07tt0KeICAz!bQJB|9N+nyixmS+cxqb|Pi>}+pdI=gv#V}5;MurO+m zdd*rXSMajQWWsS>)6nAG9d~#p-rLg~8&}@6gSy zmbF&Lgt2N9P0;9p>or@;r+3esedYG~&)(nr=AG{MuUbF4sQmP*@}F-gKfe{liom~m zo)G@coyc$RME(WqdIt!T31)tQFmV2NAbcnGn_K2Dug3rWvisA6)Q?W3zlYc1t?XA; zxh}nsMZ5G{{laUFhTMx2Z>vPzbk;8G+vj52rLE78IVr@7$od zIBKrUG*@QZjTXK9;&)>8GJMFN2$3XQ&^s%7Z(W<&iY;zOH};L?tLfo$#nwyp@|PDH z|F|>$#pdFFT3P+k+~#BLmBqR5={J5EyY;uu%^#VY??&poy5X5h9K)W`&kDVrF}4~j z9m9jZdBy$dK8zUgOXh{<7mRd42_V({(@h$ zKZD*+B0~|xUmSrasNiUlz=5zQs(rHwOoz}SDS)T2K z-*_y#zOj1k+|H#l8wb0qds{2p8>^^hkH>TU!Km5k70P9$xDfB1a(a7Kdn;C5jTYvO zM*C>pf>>?HluQmp*S&J58<+ak%h0TMjw{Ki{cy-~u{mdt}lt128 zzjR9d`o8-8^U7adQGR+&`MaCZe|(M>^@bJ3I={cY8~N{d$pruFOA#y(OmD&9_d(=; zVS9zl@&9!%`mc9Xv}pbEy7dp29C{r-lm7m0_FLQ8uWe9W`m+n%s5PWM75E*$?~q8; zz5Lws$<=Gt_9cD$KqHE`L2-0@)N4WE#3CVPLXw9rDsNA#rov!}+KIV^bcb0T_v8)p z2ea!>jC(6{-!otMXXF0wQm_0be((jQb6&SgnC8>Mj1L-N3uXyn-T<%QEOzraboj^; z?&}$sXqsQi>ckU~+Bn|YU!RmkUcaNVo|Kc97)>_i>tE_>b>2yjjTegda=E z2|a=RqW}GfJVa;J&Z6P`?8TnXZE*}|TO=mCK&P405zlmtUiDs>6!i?fm zEV?t%g+l(k(J6ycZn&RcQJbQDU)}WmyR~kxiwFxm>+mXw}Mtc75D$FV6H9 zhi%W%78aMTo!h;5X7lXs+Uf1p?akHo^_At7mHEZx(cEHtFmkMFw6cOGXrsQW*H)s% z#h5p?ll`RC&czy)NTsb62N;EyOfMB;?M7j7`}Dapo3}P9cgD)gWA)WV^{o~4{dM(I zo9gFx)UTdWzXgOZs6W1}{-^8e&u>Tn@%hMq4QtVNBmevoBP{R2f^blgh9Um9m!rRX zQT^@n`mccS<@nFeCw{!2`meOBE*72O{9Texs17F3iI$ftjhJne&{FoMbtay!uoLID-L>D-R^1^;gIEgj@O z_&>cj|2=W-yXx>-%xxI46b9_ux(_TN9Qb{T8DV)RJ@N5^qmtk8k`IYQP4g?Chw#if zt}n;=AJBdklxuocFv9;k{K`{>pa{+s|H&^B-i5@33R5z{$JYQ8}DR{Mp3EO)N;qlqvO+JCb^z>_A2JthJL9NyD_8O znN{x3D{m|+@2n~xtgD~iR==>Pe(j9Q&t2*jF*Q3rlx`Y^(=Hg#6+z83CVvv`A?GY zae@r_Si%D$q=jGCv9qaUF_*1?-&(oftj_enZ+mIfu4LkanYn8hPF+5`eg4!s@w>UU zxi0*!%q}eTXXZ0eOffmH6z0{^f?ff_i;?_TOAq2sCy6CfVzqL#)YS4_D>IWwEoI!T zf_=JXoNL9d^wb+e_3l``KUUvZP~TZqf$*oclrQWlU)@)}aaQ@WOH`5mn`_EH+=~9< zcI1~#@vpfe{ZF9yZsd3O=ye#)S+u=OZ^7dK9lZ;yzoCk>`S(}iKZO-OoBF}2%(u6) zf4Z6d;@XGv`+Btx6Z{ZX7zn3UZrR&Zmo~PSMlD>)6U+RGCG$jK_-$e>oxxHv$Pnh> zX_orL93YfZt@qBV?E@`AHaD)J4WCTyWMh6sNX$+Lv7*v{1i#c-i$?+DES|xy7-;C6 zcsh{F@5CIY`Nbg%wt};yI-ci8_(c;m zW_K(_Fbl^xhebvr1259aMDPiz;zo+ZF9woeTIL8o0rQK-^izs<#)l9d4SD#FRy~6K z1;3e8qTpr7{#J{y3A4S%{Ghco>eTbeW^Z);!kH@vyXQ`A?C);uZmn;uudS`FEv~MP z7gqW+bDnOZ%}UABa^4!vn70@!%_*6Ynd~L(c2=twqLrFbY#ZJ%k)BH>*7Ejt#W>T5 zUFfJ+yUMMha%ZgGo2QEO+bimOYgCcOGALg@qkjFY`kiy?pI=h{>ME_!{kJzGe}6Ob z56?w@emg>yYT%4|HJYZmbsFwJy%+)4vi{w_gBroxnTeJAn|9XlHb}+ zQ!RS+!})zs=|8CUUaj`tsP$ecj9<(wKj&;-cQ#jN+qimvFu#BlmKQI@$fQ@xUv(Z{ z)}GIos6QtVKCzkWc;OU@lxkH^nyL$6F&+V%Z4jgcEE`;(+%Op0UwC4EpQvZFp5drY z+&kp>h4p9fD|nuGS^oF!FOCqqLx}~sQnJY-W%wy?A0NuE-&u6pym5xah3w4tN%$l; zJOcL6fgRSu>n+Av_qhq0W@jx$Z5JPA)bTXGi3oSWir^EHG-3IlfDdQIA=w|-r2VrO z`)j!IcqWxBcfJ%9T0!OnT+cW--R69BKTFRiT2Ev^p7 zi)cVIGjp-roKlzrxtK3nE6qi7BQ4pr;_bB2$f?zGwAj>gy*Ny8axv?y=dInUw%<_C zca*Dr<<>~KJ67(^DX%Rmk5-f?Ys$wq6x5|Zzo&lnwEB$$tj!IImA||i`SG>LUtNp* zLEC@68Tq?gk-r1lw<7;=+uz`)?Pm0EZzz9#Rr}F-^ZRG*Z|yl>+f06O zBmKuK8M!>qD4h4o-TSr91KQdT8l9I5qvz8L*W#8X@2V#)Bt&qLGShE9B{AeAH! zp*!T^036!F2zg@gGepvoJFPj9lCPd1etX~-_80Z%Vle(r~=#MTdKRh4%&c6Q5)7Dpa<6qo#KeOt7YKi8g!tWV{^Wt*l;!^eeQuPA1#p=O) z`SeVFd+1?Nn0kl0Q2t>*)3W=$?zN59JN212@=Nzq8~2i%_fwm%mPd>8v)P>AF#ZuU zht(sq3pUv$%Ny{Ek|0x;oa|!$Z7vrlwm8YVxg5hYE)kl)XbbvQ;dydg84m}^=Ogk9 z<>Sv2WE-}|#wn zY@!PXjbiYq+w)Q>TFp6qjN-`=zvv#^OhquYBPK$@2=@%xU#b-06A}&Sq%6Y?Uf<7W zLzQ`;L`o2Wvs zFRzmQot4tKyqg?8d6~=tgcW0EB=F|sE>cb`V9W+XBsGrzUKf9xReoy(zY31wt$~VtN zzkNRP?F*6b@b=w{(eE+TaK8i3c?FjG+vn78?`z*Ut9|{9{?$GG%e&_1x6RM4TOVJs z-(QNqy%2vmZ_AZGUfv*)sAst8LhZ_8_R2=*`ex_$cIWPH=f$1YosIIX#mto%>!7V{ z7OZi+&{vy-SbfH-EV$l!-rj3OE;Nig?#_eU%G2-zKNaWILSKn(U}2bMOAc7gZ)h>+`N}AgWpP_+b9j&H8hQ){c5IFGBec+=gwX` zz$c`wvwQ2Ow$^uu-?f$1H8erb%rDi88Q5PVOZFH1YDGr4G#kqgm2^*cTM4V4iB$^G zVol4n?M&ZI&Sm0Dd279-?bOsWP4%FqUhXQ_2g+@yUpl3I?Mw{YpPbgddP@JwDg8@(`WJW1FYK6~-!lJr)B5z9^~rUcQMDg0 z*>5e_59jRH$M(IE{qoR$zGpwzv9GqC#qWn!UvYOT?cuFT>2|sLT%mO%GjmSc-gK_b zmR}uKUmun3kMl2#v$y8mD~s`StLn~fgeG&oq|@Ba&$~OXWY!*)=fEts_gaJZ+O)mj z8hp?iT#a7pbw4oA{XoC-i{g|2r});tW^Vt;-gz%NykX>55>_jvVx}U`h^1}J2F|ns zUfS6H3dkq`_qW{U^!nJf#r~S>b50 zqv>6vk_`Fr-?VL|9G}wv4GDq&bcRR#;dPi`BiWtg5>SWbRm`i5E*uzz1pA9gr3%rR zl2tKW%<)M4X236Obfn})Fasp`O&Vx^RIth)+h61*`AuAT9Kq#{6BgwZc%z4b*fGFT!!Bl``rW;9rX7L2=j23^5!d6-PySyzM>bY31gcYDqYUFW%ubEEBC>o}Jh&iRV7UvW;Cob95so^#|%AHVe< zMIvc8w7Ernd%-$A=bW2&FU}{g%sb~7jop>V(yBgK(?)CR+)89^P2Jj5cTPuk&c}Ap zukyCN^HOs2jpE{y=I}l6%Lu<;GJN{BODYKhNCyp0WM0SpT`C zw_c8Qn;M>eULNy@VGedJjhTIfU$VK(Z)kkQ(xD80lyf<*BQ;M!31@m-;iF5!_g29B zQR>g(PXFM8mtzBla*wFMbMc4dqaSvt8RjFo!42{Y1?=HnuyaTbew&!o5ubp$2@Cwr zR}4?VCtwgwqk~bqMjKbfRSI!M+OJ@LiC+O#_7`MHyOtesgX5BuanE9O5nF# zXxB@Fc6Hou;Qe>pt*P3!JW3BTL)327bncX4G6pOD&(ik+O%QH9Qp@#QF1q{_2h zo-vE)IN8&4T`k+eoS8}rv-;GHc+Iw}u362h#RA6kVCfe#-8NGL)T?2aQ~1D?TFaz1 zv#H&D>Qp{;rj$BgNnWfbuhx^-8_8R(Cg;iyKMH#Q_ zgLQMT23H%b8H06Wu%QiC)$vMnWmVnWP-sb%bFrN(`p#_&Gqi8LURZjwItI3T&I`lV zyM@)S8JB;m-~FZg;?Fa8er8|%y0Z4J+rH7UR~GI1O3IsYy{_d|H4n2=J24Ma;8-!u z=a*-~K_gX2vAo#+VF-XYF*;(zai+i5l{um;m)DfktHQF%C$)khD8 zFYi>~C0}-*W~`r)vw!?knIK0$+o`NYG9~a6U|j<=VRf+*U&bGWv{a5c(Ino5Af@OZ=64M>CD!_EyW`W3_-LEV935acC5} zhSxIEbxd1Lt2Mc~n3IdfWl4yXYM{#C;=>o_q)bJVnP@tvri*I25=%FXRNG4REc60N z&AO=td^k?0mQ$&fOlkuY0(hyNLUKEw*eNE~^NIDGyP73V=Ta`lKFucGq3iY?w`;p~ z%dJ>$QOAy5FXp78jvI~Jk!RJPpK(JaO0FPig`Fi+3t-`4cMTMa2a?$AN_1&8x`CC9 zP=!9=D)i;pnRD8;UFZ4r+=FrRgUZ^UW={Pee(o>Si$Bs&eKvQFGxD4f8{x%d?Lr*iU}b(r?J=QzJdG7K=I z9UO^*r0fvC_yi35JLg3g(TlPeRrKH!aFzxrVHQw)0;VpM=z_)kiv2}ylsT>jZ^2W8 zcQn}(;uKBOY|Bczj+aiA3fWpI->#LwFFpY;jym&w%t&W!>>Y3ytgVAR@Jmh5Xu?`s zgZ*8dTUf@xI`q?^Cg>c!|HA%)U$Zi6m4|krXXaW)wvJ)wTC%9RImO9fAs8%0#8Xvc z+#t1IQuPXBFX(dwh7y|SN`?WEnCm^E5ZCEQ+Edd7C0&iBF`m6?(AKt79V^+f6D>1Q zHxdmqQ8N-HdPXF2N+PScX~j)MkO_Jy+GfNuA_i8F!o1j6|3Oz2Ok9s^fx6-!@I%6U zy$^l~Va-RF_%#S#+8F9JZDu99u%fK5D%+c}y*2aPigSIj@L;C>vBB);d-GpuE`Ou4 z@$LHJ7utglMx|GFV+Xf$gI9ar%N_4_!@E@R_6y#QhtVLVdbELA5#sT-Vb!qu3FbV& zNNjoAm1;9s4(rciI)Tscb!y;+3I~5<1-xj!7E}0pWg^Phb@=889sw^73Ab6w-H91u zzlat4EBl26nfzX7ArBwP3NCpB0rGK}n*~lhfD?t%2^51!CZ5{kzA zucqm?Z6y+JHk~ZxJ+i;G(t!BIIGXmtpqY;=3tI;_xC`a^z4g;O>l1#LSH=rVgW)Kx zSJ4Em!33iTt2ow5V@y|TmWEcbXXV-^7BRpa5~-4!$YT|lm_6!wPwQ22A9N*8tUNkOiBdkU-2 ze^_p0OnC-=;up7>SB!l|RzAEk0eArWGxVPp6&7>fazPKd9V+=xOZpV~;j|QzeFSp( zFS6+@u&9B20!D9V8bz2Vev`@MC= zoaZEaA8U$+4%i_3i!RXMx0uh?iaD{r(uES;eJg2mym9v0`BPW+x6Ykf-``!^+gjV& zMD=-fX?bOCVX@cmC(Q=zug>;YDToQ4wM#>@(6%E!Jwb#BoT>94H=ubA= zpTC@b^2omY<jASN)*a;4s%POYz8&5#YkFWf_;@Grwnc*LJs7H#dae<+=IAdRj-P3>*CNE3jH5e$6uK&m*hYH}k|V+ut%(Z?S%& zjr9;+EU6X+zbfu9W{~yo-NeH+E_?}*dkQ%?r^3LGalc>)%e>y1loRNnK*H3b+(P10 z92VN3FjHBTjcqafNP^OfNmDg+fr%wzre|wjGD?f5V9xfY=3)HQEG7cNm)w-MnJR8L z4XGrf!D>Yt;Z+xHSu2s1MRRW!@3U*o&+Jw|ecgHVwsY+Z&8_b* z4Y2*$M*Yus^FP@3zOm_jWz~DqY2S#iuh|!C^}FuyHD&EBd;Ou-zZfYkYrf4jj=t?O zxdd!jk)Hk>%>A6FJ5q`tE_t}~B>CCYh6Wdg8y7(;&*YIy6nF%1Tq1a=G9wSk;87{p zT%M4)^8RB%Zdm{??v6YM!lwbIU$USdJKy!dzS7cRL_fgMewV8U0%X$G2yLe zyv=lB!)>e@{S|En*e|oENS{Z`@Cu{iD{xw-&nJU+RI` zA27M(F89IjpDuLX^tLZ(x5xE2^K+k6_r8?4`mN-dPnh#}l*W#l>FGw!idckaU|Y!} zkje+&Ku$v5(0|g$`3S#)Ed%TGEAVn9xTf2<2>aNREb}H0ER($sD=ZVFDdSh zT=@ybxJLoPbSv2w6R^0&e3wIh$s?Rf{h3`Voh%GJKDoj#TrSWO3s*|FU&J{!WGRT8 zFc2zJ!V`afMyxocGo96RCQ~YYcCe~7{sc^)kh07#=1(qK4co>jLK?--U9e;nKe}*W zEetekU=%;DBpFx#Cp+YG4n>G&0p5Qx1j)n@2H4+p(jP)dT_~#~3}Jx%o$YignQU+C z+NE=s_qS1h#wg&uE#h~5WocnAr<--`1OciEh+Xl ztHuL=_{9<`{yp`PWc!OoPzi=mQ`ry`%tTZ15OTTjNXhXjW*gxbFvMbJaxQ6p zd1JH**uaCrNq!8Wjybeu3hXcVpxiTe~(9J%d<`{6g>%@6G_Yl z6Ht&pw7*Em<(Wz{G`W~dStl`kBBcM%`W;U)LFc4&{_Z%6cEUTN5FZAMeW!?ZIr$TC z51){-yeLTl^C#;CEdl$BPr%#-E5iInuqX*W>f;lVi~^RuOy$ly;1gw`zgJ+4mCj7d zbT9-M{N^*&avt;JbOU~uXS?01hgZVOSFT+>w|9ZMK(FtK{aszcG}N9mPAA5wKbzbI z3+-3b3!3WB#IIc%7&&}GB7XH`8LKG998a~Y3d{8c+!}c@`<|(LE%#kG zo%k6>DIPwOQgWnpadAQ{ikToEmN&l~qHqelY=}uHRpRf9K7B%p z)RWW&D;MV>NPZVey#EHd(0|zp8Rf~3j|>qgucm<^gz-!o@4r-kZdEaapN1ffF$8J0 zGpKtQm4E5>%hxWPxwyZ*zeio5(S>8aTPo|loHLtF%qCK^c>hHgN)=tO@?*RLW8zq= zJY!+*s{-5KbWKl{V^$h>9Bt@CF1`6;|7d(tX;u(^AXCK{cPhBQQUK`I2UX&Uhl>Xk zu!RK%MplfkFGq<&Lb!pQrCKzjN^T(ZEe@AkG*rhlSH-kZTz}3*y%N9w_Dr_Fs6VH? zUC%qndzZ@IjhgpD%e&w9-spR8jl4Izwfn`{TjuV8adWZuq&ffP^!|^HSN^&5!T($T z;D41K{5*5zPu#6X#^|zAUee+v3)6UlPyh=T#Ic944PgxV4QXXtOjHWIp=Q9cv_%un z*aB-i@d&g0{_C4yW?6upCKvWsE|DPYyTKL1Wu#{&1AEAwz8!32s{B{gf z<*6?3!bGtYDz0FoTnV9&qbO1kHU)k`nEeQn9F|vvD4+P&q*MD9_;tDdTv5HI>7jed z9NMoE-e%U@Nfmbz)eXD1qAbi?yS?<~M(ss!_?ET)8Rf#aGcW$E_UPB8m;WYr^Lwca zpNp?OFost!^Z+Z$VJbOlJ7SATObMQ1K;Z`b62dGDVISEf~Fw)k`{9D5-}zb7Gl3h8>~Xvz{MlUK@iWbj>xaqGLBQxt;s%{Ac!^ zcb3&hbLJZ(=Rr67a=rX~zI#0}e^K8)qh8q4E^Ij07QGjSl~-HM*DKwJ`N6|<@1E1Y zYxbXu4sS(!mm~FUOpdDN`dS)`%4Bt{?1nzvF_nst*aa>^C|6RnsHBNJ;1`7!#S%7! zh(5f5UrkHE{#r)P(ef#+l-6oly@hE=GR`=eSxx44?E3lG;FhxVioNr0`uu0o=l&>l z>SKxRx8ut%nX}im?pdX_j)z#x%9{~PZNMl6s1mb6Zpd!{nh)a?mGs&xV1_P3=OfJU z3X){9CFhWC&R=55Wqt)!@*mzH!F3R3>Eg&W;R*>|sDNL3)=g~`3@$Yx%zp8Z8#Yt0 z9}>aY_Xw>a#UZUzoT9{r{7U5+uuR~UBF&rTpMQs&hEl+Q!%(feE+ipioc9e8S@j5Xqc8!q{deJpX3B8&! zY7JxdgN^7H&Luvv75n&l^n*3^{U!a~Mf=IT`_63g?V0pjqs*Jb%%ef}Vc&b$%e~ev zK4_Ki*P1VtJ9qMfTgk=C#@2atZ$ElwSHG~DxH-=iAjnzm^|0^Kz^~7CyBb``lUk86zt&77ky71fI8_L4@>g_65K zC#e36SvdF;61pHzPb8mK$ylyMxC6vVG#+az7C5pT%;KI(dS0f8CaglHQOb0y*+DHc zZe(X_$&}GpdG2F3Z$EeC(uK9UH8d*SSfz^) zl_(DSEl5cgm#niCaxTf_=MoN=wy>QxAVR*JBCYTu%t8|Yf{Re-+fzx!XhQ;`ML&cW zsVE6Q2Pg@s6i!2OgCI2NfpAPt&lcXh9IzZeg!J%%8=M+qeQf!HO#E_v;4-1%L(j*V zEix`08Q&umL!T?m^=d^6l+l=dHA3BSuo{DMu!y+X$A_RF!Y4EfZw96R2}9wrDEmoaaLW-tF4^X zid(2oa~Dc5FwfvJ@Oe+9@ZsZ)svBn9aZ-r{x=x30XutiQixa1|O>m?@r1 zJfSW57#l1y8D$?~q4l`#`w(MyGVaT8dUTP{vSyrh+G> zPU?hQZVBO_@e1~r$b}q*Ry<6Z9~5gVF6#hTVu5iWoC9)2D7F=`A&KM>(8RC?cv9Us zkc9k_CsaTxHpdf4B{sxXatMMZ7XX1;uth@hFwr<2Vm5FO0V@de=}!Yoga#Wfm+u!& z16spcG%j_xN$Vn2o~J6(^l>5N7c2+WY2ljeOi)#xRG9g-m+0mwD#Yv;Qm7EKBn(bG z6c_Sz*uyzUe5gXfFy|?SFlDGol2DVQk?_bbW0L*F@ZN^2c2epP{Ces_F4iyT6~meF zRIILorfKN{jgQ5i9Z6Z#g#$N;Mg;^GHq4d|4*_3}-BazE>@O`Qh*eaaOfp_bJC$s_ zo{hJ1cCQd07VVjmQHd7&SKhyT@%(Dum~*^QoQAWtbg!o7D{27?`+6}l!3neB#9KCA zgcBXxu4wU8%*`9=lAWnonQ}j#ytnDSyqkLTl0=AFl5_sN`C>V%*ToWbuCp_mbVXC^EBK4N}h zg7>wxD5j(i3M5tVxEvC*!l|$f5*cljYRIMNhJNvg!3Ai7r<8wzS0uzH5QfX#iI5aH zI6;qtA|y9}4ymSv@XHf`6xh@XkD^bz;Dq7=*lCGxUgg2U*&Z^!d%>qqbu&|H{U0eAEO#2By_VgT_5+!Ai3gnbU zM!BV+6zs4(PlL>6S19lcIh!+rRHKAs+L!`xC!~`kVEHI?j5)=!L4*ryO8|0hSUi;R?u!$XQE}E(^=WL+~EvSAdmgU}$g= z6n|)Kg7t%0<(jjr^Mh5-T}->J_|jE=|fTN>6I z%bQg(MKx%d{DlgkoFSs_oU?Vk=#4r^@Zwl>5SR^6G5-pl6=xntN??vw^h; zjm5G)E^4EK-p?D|ywT2K!b+=INHmM-b~TTlVBJ;?OCpX2z47dDd46_falE-SySF-X zus*!BIk>XbyS>%AyH$O0v-Hw>?%rDZ{%YctCF9;`ECkWQ;Dln<51#;( z4{uN)O{p#O-X$R&366*NE5L?9!a2m2A6bCZ=a=P^3Nt_D=t+p@;Sm$eP0c>GLG_rh zns)6>GABB$>ntkCevGdcvLL zJ5gmFc0@glnM6$a!qgKPWleUJUJ~%qfNuU6=8kc4DyHtmXgS1E5H73X!aydS9oSqwR#hr%f){JB+md-1gtm37WTryTjt9eYbmcq;$g_cvqqM^NPt)DD+ z7qaGa%ZW>)_RdO7LM#+F9v zVqcr@YIB{~xD}gi>Z67>tm%V_)~jgUlGZ6}os!WmYR!Vy&g-q5(Zsa#d9{KmFLIH5 zQO#mjkRm1^h$Rb}i!Fx_&zhZ9O-yd!Vk#T-A*W@LCstUjn}9>G2#JET*j5Hjl8^!; zN$%7}IAfFgGb;$fA+WxOvm$tzUw@~8pMqk1nO_8PFyY}L2m?yMinSF#@MMn|Tp!_} z!c4+|Uox*pD$fD4h!R@;I)6KDM=XR zLmngzREX$l|5PAQW$68Ys0In}Kk!bJDMOz_-!nNuXvyv*Wsn{UxH6K8GL%e3Q(%>iv5i^SZZ9Ryq2}B*cUxq9S8MuGMV~9_GX!s} zozn^4v{6bK`J~|yyhg${925OBP{~I>ESwo0;LUmki}5CQ#zB6@Ueug*PL zjXvsD-sn^xG^+O-)t73O7pj$8<;tx}`9`U9wN$)RC|=AL&KB}#a=FvF+)g&TmC3B7 z)2lpP&wMgD#hpvxbR;O825JH_xlAt92wpa_$XTk&@Ek`K zQ6Z!us=_i{GQm@CyJTdiUw9G4Miz21wQ#vWk}E`WZ~`yg!->J2_R}5Z*q{gpL6LLO z76p!&qK2dVk{{$ig(FBZtx7p?SUluThb4_Dh+Gr`KgF|uO2FFFN%(+48umoWqR&Fe z=+VScl!6sb$Omi`pQkb#q!XLoeOs zlz|uUoNJ`wx@&2Usabjqb$;oQg2MyFG{KjD9CYkB1xQdg!F1L!nh`gq>l(g@T{^w~ ziH*p|##p)AdyM|c1MlH5`+6^XzngifleycYj-h!Yuu^_4hbqs9Ev!_P z3D_xvE6h%S4R8({sn8NAwPmuuY*Hu8a!`bXFb92#nO~t2E_ni$Cmz0=2+D0G5BsT1 zqF~aW?^0=J31l3{L2~#fslpH`1-~#V5c>avAmw(_?~qsmaM=_5KbB0?L@b)D>g$Un zID8WN5uAX}bfPIfxZy9j6cjTh7cU7#Q_hzIA|w|-B8ltcctMQWm>EJ>G1(Msw3EVH zxmQS5hv{11tMxHkl%8$ucVage68k+1Z@yd1uNdD^0j*?O$J3fw^wZKxNiCN!GA`cD zb%qx&>;M*r;_s5)A@HLk5JQZTfLD73#)1;`L+Ec981pK0~w@N>4cOU=PcR6KiT*jnOI(O*^&yvN1B=mXQ?m;%~OIiVLJ^k6G{|I zwV6G>*=0XHS_M+E#oY2N@Djfeaxp`R5}f@4#zoGTNbw8Qd|sdz6i)gt$$XJ7@I$N_ zs*5lz?Ib@M7YL^1!7&7JQ+q@d$3lHNMVK+g20Fe*sK*r#5(bjszb~5v**D3GGn8FG zD9PnN1%n@X`Pd{oiK0wMjvqim9h;hVXvxZ0+)(3A1dVA9TGg_JN~$)<)(3#M*yzPl zwX;3r>YRJJW9_tzjfTEb(-+FxxS$X7TGxv;G8)6H=M#F?)nR-Swr*1clY$i`PzJC^ z;*{(#Xr&DvU`!-aQGptaFJLErO?+=oC7(aL{E0>9z1b{2ExkF&zA?zW3V8eJmpTOR z^Uc)FM)F!MdAXXrP)?i$yk&xSJMV0G&I-djmyQo$d=pj&eNa$yw#-5RZ<1=x8aHrZ z&Rzlyyr9gJoy8{TP5T2FDN6L2G9(0^L|mXi60x~~L`W0`F~p=FJS8YrGUQ`G=0d2* z5k*0Hz2(ZY087H4smhmxFScxOL8Wh$kJOeKRRUSIz~BnS(*{@Uuh2>qGp!N~*_0p( z)kMPOktB4_rEE$84E%vm%IQ>r<&-R)2q!*K_cNgYM;(cmAod&T`H~~q2Epm%(|(TU zOe8CIagN9~%v{b6GLqvbuAhY4fwm1lf7Dl~eETRK0qu8iGNFupBwt!^$=jQNr_ zQ_%VzK2+h&7d2;Uzs|XOCaxuIEpEgt9raR-Gvr-TwV4)tft`g1KXwIS`00h0Ti0WN z7xp)o&AxPQ@q@Y4<5BjVQTEX=^Ljt?3Tn>XG#TGk`gS9Aqe1XqtR&7=5@#w2%o@F2 za5i$zisvk)Jh^QjUTHIlIVBex!Ijw%FuOjy2=a#D&Yv%#Kmgjd^xdSa`%cf<@;tH@WvN2@%fC6nlp@V*R`5) zvr27N^x8}CYGipWwC>@xmut>ML0ATHZn ziK5-{CK-l1g4{n6Q3wu<=iEv7gj~q6j|)<&XYJfIWx2z9jr7 zx|}k|%@-X?3t5=!q4*%e7xF(kD%SUfhj)h4q%s`F$$15?pOTY^4lypVQ^LssLm2K< z@(f*gct`Y~b0A%grJzX2!*y7i{SlRCy#Jy7Dvs}}m~1(T`JG{Z%~-b9L**I9w*-Eh zy>ujXdCt8!a(CpjQO#H=>$4@JpVw%G;IvjrYsI9VOThT*^yZ7Nv$~3!GnP}t{@C*3 z^_CeX+e;GuR^}fH*oOVpxaA7X)iA-OV&T<;;p5p1hBZALq#yLtuXNKdcT;!TspneB z8+EQZ*AnL|iL+(*RMFijI9qvV&5N&O;tT2cYzmgwhUINK=-5qd&Uw_FH9d{N45)3W zF?Vqs)auQJxmoh;@ zhSZn99|Yk6o)jw*@q{)vtR6G4VqPW51lTE@eQOJ-r}!0k302t+(<*b9`S3EoC`wY2 z!{Q_o5>6L6Du(nYMUF5JB%x3wl8O_vK5I@ZOBCfMKk-e%6o2GLl0a=b76(JWz@`7e zVROVuS+Rnj2noWC6Htbd1O5jm>nn#jvRty3t3e83!XQ?XOCn#HGx9Y9HBuly_>JL> z6a5;nra0Q4VSH`Ci^?t+e{(MklYiSLYK4LwAdf?^4ykXQNR8 z9X51~Kdhy+a#Eu=Uk7i#TEc?yjhXmngq>h_WPDL`mI}03UViK47h!n|h80G=8vJ7T zE*hUve=e6x5B9rn&1N2rGOrENuk;AsyPeeY?bMB?5ATJldr)ytW3iPy!Mh&3_M+xI zOj@Wpw_K|Rc;f~wdtgw_IRWE~5tle~3^oK2V$=cvQSyo302zU6+Bk-Of>ctmJ_VUF zQV_ZsJpw$0mpud{YXVr`FOn&j4vg~=1v0X7oPnJcLJ=#qWdvnA9`vyV$YPGUdOT^N zVwQzyLO8Ik#4MXv-vhriRdGS0dx{OpLAm8ZMG}7#1=bM>m%A{U)ab|me18xrF}}-* z**PSpK$t9u@ddn7KQ_<_{`;x~Meq|q5SkVSk$jp^W__GBJaXb9Apu8;N1{Z{*W@IW zTX;c4!a+Y1@w1LNoFylrltJ2XU(mnIpF zLo)V&7x=>O|42Bs5#6xOWPfSK0Q%MI_1Dfc9uCv5_hEcf_qwSU+o|VU$(v2Aqm-bU za}BS(?wJydud|hN)^hP>RGZWGT*e+I>>l8S<#k|rjUwRH^_1p+?KQDzGCeK`A0dS> z5o`l$h)v!O8A^^7Jds3fF=Zm}q>L)HDIqJ#C&-gf4K~6#+%<2A(7lU;~3Ic;YsR36>!F1#>DWzQH9A7okvs;tD^N zFDabjApsRk-{w+b^M70xIL>!`O+tXTP*V~}kYW)(73X{Lk29Z&@iUzK3lxs)9Ln%1 zYLpLtK`cDs^U6=o`NGe~;-3Yl;DmhGh^4DEeFQ;pBIj7jhodICBA3iU9cXdOGiG0p zpz=(0Ni0W8EmtWOlRG;_%_*g=LUT}Tknydz$^Nzy`jz?QUN^qcFqdlPeA$>OnZ3M$ zF4p|!tKrQzL&lfie05ci!OqgD5Vm4`xv81(#s29z4}QtTQNtzUjQVrThZmEIwAvkv zi2%H>4$}7p-j2YVyizB4VR`Y|OJ92nu)OhAFTRwG175uL;+>beYRK1K8()ji1(PhV zgHOHGqY^W0`#=%Dyot^AxeJ6)n@9vniDI;U+X|3b4f&8V;~A!spuign!yqLI_C#b+-y@2p zjTNMr!G(lwa8P>m=!Lt>Fbs22DkkyN5XJE7N3^xmY# zEAWfeJn-cgEzelWB!iZ#n1imEWiL@|4a&_ywb^TQdWBkRm{l*$C%0SnDvWQ{9GA>t z(d_2T2EO^G4ZQh!%x{8?FKW&-ehPb@!0T6-8CzX^aV#d>&RTL2`i}+qh6d9${0c`N$nV|)Iue8mTjn5Ti@nRW6QB(WPxE=bLN{uLBK1t`s7M6 zREpA4O43wCb`8`p1#of9a6^g-Gyuq$kX$?=aV&w5 z3@GOV$^&Yj|a%LCsA~8C4noG;8udZ5v7q7i&aK44E8u;2H*b#WiBai~R z06<9vi%A~V^j(p#S}2kI`i}_SDM`Y|h)57*W(in65@Hh@{2{QyugIrdK^4mI5Wftv z)Q1ICl7zw#UbeQl69O{1Aa@F06rMvt27wBol;@x*@_$H!AID0-k2{U!l}pXe^yZ85gZ+o_f?2Y#0xwR%H_h}Qp~FOJ;m=8; z!Uu;e;#l7FmBkoYUi7nS(g!1g7u9BIa7LSzz#Dum8Yby$5!$TK;9N4z0(v-;<<$W% zTG(;I{4r}{&Ik>mLlBc7Lx89B@_rFT zo?w$YGjbqQv5B1b0v!=fVnrvw*~gZ_gr>Z@hBns^hIq1qpbD1xc1)2gYH|np?%)QA zPFSYsmO+TvVDn3+=u1J9(iZrkNk9JQ`$fV@D0vVo|3!z&2mgZqK>*=kqyJ&_VUNf| z84^!4kK~I3kYf;e=u+TTCRXb9d=(RV zSX6oT%zDNoG&V9X81H@@FI8<}$p@D^86LoLoL&|FHRFf)1S;);Gig z#V?PQ=US=T?d0_)+N_djvpQQ&puu?;pLz>uaCVl_RRf=T@wJF7uibLc!`VVtjUvOF zMuW4e174geR(SytDBC_e3;cs?2NBOWPG{y>^uC}U|{_N6L|UX{S&9L&?xrk zP@nkq~%-bz8zE=S+UVAGEsyUZjz>AvmYBs)@rB0Hgqz^BSoO(DLu)Ib( zrn{;ZR~TOE=RM(9Kn7wyWdRXH5d4B(K(sU&0kjZ*a4k$hnXEAEDK_>KSwd*w#>Co& zY{J9JKFA^u4uJN;P>UN9Dh8GE{u}`Ka>U&x>E#!nefj0L;l^sMUbWqa@$GcG-A)HDk!MDUy?z3fXYkuEm>tim zXU%fj#5ln;4OPHQ(de*&9#(ijV2=c>kFa?B%CmngbVT_1M@R{vj5cwM_Hmghc)LTvLQ-d>oE#e-|1TTgsjL^>t1AEcK8DooVRGZDb!2^5Iy*Y*{ zIAU6a;GM9**b2OYgP=r`01)8_)WGA{as^LFScj4X=)prz9=4~H11F(}Kma459qI=; z(9=M+Fk!HFI#f<8$1FkFMJOR8`3d8@0i>ZEcY*wj9&`}&H=&hF1>Y$$xM3`p5Wf(T zpKp+Oq!5vWZWnFz3tS4aUj!T%MsifBFs&haVLoAyJ-#CU3sO%-g!zP?FnK5mJz-RE zED*>slZu=XM@=d6@pBGvXybqWnFbdDK~@Pe34@X?yPSBUAVEomx;N*_E~k|Y4+#S~ z9fJSmSI3wmj2YCp8StZsD=q-(-FM+HrfO5+XKJdwyn4av#ITlJ5MjacCTo) zb5=ELmXfB&{L-7R?)P@4X9Sw9{6DHP6RPw>3>-OB-y>%UWxSlCLljmNaVlDXs-#7Z_u zNSBL+VJ4C@$pW8v;Ibkg4*UIM3Dx{CA8;rPJQT_4Nx&YuDU>NXMN#7w#vDa8dih1; zRRVpU6$dK|Rt&dpx#*Hnryxz80mapB2Uy4aD-I&C2GlMd+tNovd^RYs%oAmu4uy-Wd(Jvh=V}5YPcY zpg_bO#!xIEV#$LIo&ZeZB@hyQfuC~Vy0@>-exg;9vx}h6O`dR%Y?LKPw6dlg5(Sx1 z$()Xs50#FA4_o-fDacun%NJNA5`;v8xc}tg5&;hd1LKP_A`&ViQe;?R5@exYt^z-T z^rJ#H`Gq0!1OenDzu-TGru`?xBAPYGIi`A45QfN%O%rs`mv2+Yo zkT+i(1bFmYo5kAlQ-k E+T(f9$k=6MZi>)u^LIT`h)=7FhEvlBk~FoVij8|LKemYA#lS$eywnE_#Zu5C5QG{o#)1jB zfSm9Y&_brzVuqYbEWs#7nLWf5v-ba2b|u6J7#m}{rfQa+?wUF? z)61#ubLRhlXzn8EDKe>9g76FJ>gq}n8IRl}V{}OKE9R-DF!lBL*@f&zQB6-)S5_F( z1R?nDRuhx66{~vYthAj3PR6`rHOB}JJ*O>BFdYq^9=Q_FGYGbCnm~L)PDc~sY-*>L zkp}qY<+)j)9hOcITe#oF8EQ0|&8KO%ffIU0dpxm56okQR3(yQOk5yG<&l%m@oe?Mo zq0z1Px3a>ppy~}oU^EdG(MrC=tNUNRc%|$6+TU%YblaR2z_^QTWA zZ_bYX^1F+FzS-fy^W&QhCisWT^_%BwJb3m8CReyZ4({sMCkssPb%F6Vt9I%(V>h^3 z&J4dgbcCP!I-4IqpU?2<7q33eUVQrXU+@15UoVR92J+paKk79rTv7wyEyBA+_=NKv zUvTETMSQDQ?-t>Ufw&$Jp5CJk&doa2bpm6881b}?IbsfGjVGhrF`*=47rEf@KLJfQ zrX$6Cgf#aV!kTxlbn7{<_(n!=IR~RvxR_-cX{b6!(J-?}%ayZFtC4ccz%l1!6o)s0 zZUr0Q5YO|_F8FmbAsQzS&p$2>?ST%BXweL*VniiKkq~N1LJ|feLvDCvFoY$TDL#;j zmY{Z1FbBX~3rw1}DO>DT2r+PQl&nI9j1rsT1WXVK1CBEnxs^$;bR05G%!q;jOA8-L z^0HTY{H#w-;$zSF&fvunuWgHWe(~fN_rG`7FK+ST6&^f4JYfFbe!Ts1b@Jz@i=RGh zpWflg@8;vn^}84AHy7*6(-l6mfzMp|!7~bB>T>pS(fbf84aYl31B*HXglEaPE*35V zi{B+WT^yY+Fn{N-mh&t8o)fND{riu6K+*YJtu`p~lPY7wf{`_54(9*jWB zwV@jXStRVAV!qvc_QZ*#n@~K#d4rY{2GnXPSt6&#IskNfvkf`srgGY+rTy)cclPW_`={4j{p|Or%U|s z;_-{+$;;IokJVo8a#NgppbJk#bEsax~Fm z!fIL>Ax$n)#&kB~`|DIdIqQ_#p3w=kt3BAh{1l|BZ5Wz{-V2O4y0&@PwMXF!*NsGu zSLB+e+azpqcm{Fl201MhQRj>7fhkHee}KZfh*QNitJOhIy#I{0p(?mgr@PJGgtkZ`#@a`yn zkeV0FIo@93I}6L*%^LIf^wZ6|Pxp^_?fLQX;pxlgSFf-C>2~w$H_YE19z5S&tv|fn z;0sDG&)4VrwvoQAfOCcmMy%|e3o3e72)K=kVV>g)`*`BKTOQ+AQ(vr)Uae1FuV>er z#r1OY^8WXK|KSqXqvQ3g@KKG+9iI03Tlu`C#@Pnf!|`Qc`GPaQ)r-lySU#KM_d{`> z^3F)}CC+NwIQezvd!lh9m1jE)&QMJ>yI=yLt=u5kRTc?0+MHra-iJ~jt~70jlzMQ7 z<}(T@jWn{NdjpOY$8Tcbe@lpKdREAUPSerWvG>_hw@2JGRA{#gPqc8ENw?Mvh~Xg# zPKkgek}%x{1sk6m^d(}0V=czJT7_h=v5e;SfC1nj#;guDx5L(Q2~%)jBT+n)Jyv1x zt#2-)wSyuNuN;%a87(Pl9h%+c+`>2N_2%!%#`727`F(N1`HTDC+tuzfe#7k3?WcP@ zc7FK!<^Ji*-TCF~KYZH#?c4dcce^id@v}zHPLc&vr}v?C$aN)w7rQt(i4`Yi9m_vv|MSzW)02uTSTHdVR{L zz5G@_t^~_>dwI{h*WeBcJT%0lf_1pmlFu5y7n6*XOLFjx9Zqp9Fqm0 zqdA%n0%iy8oHaJ;Zg(a%%swEjqKX)~YU1;b(h7QL&7yL7hYrJ|6IFr=dn=-)dXVKjw=m;1$Ic|+S2tKcNCbMx zRD$L&KD^;Ke`mb^#p7rEwhLZ-#{KWd&F=I0^6u{Q9UeRL!87OY=KSR^4`+Y>-TBko z?ZcZb9z0*a*j!y~@XpaG<}Y5k!n|bzdfC}`z-kmj>=R;i)QfCZxKJ&wXT>*+cKmK2p7!c8&Ug5g;`RFddi6%vV8L}-$IabirgB0gf&Tbk& zv^rF>6cH^rasy0038@f?>LjMKsz?7inmW|nwJ^M!2&DlL?zl#t0OcByNZc?yPHj;Z ze5Po_ac{A*z~b!D_S_J#IARJjCL|q3{z`b`@#tBt$GXgq@R_JX|7cNS>7v z3QoEv!HYvJ1F}XKHM1WsRS5xYIEWC5DH5(j1yVHU?+Gs$i*Fun@a8YBxpBPZC$I3y zXFPtsnBkSHJG}M#aR2mp|Lx1?Fn$E?*3|X`x5ha{px)4{B(uSOyWnf zagiK!0_nWGhNftA#;Uz>>@XJI`7UO=)d`>W;*s;_=na0TaW}i!%|Gsz?-%DcKm78i zyBXgw!o?)<$QhrL#B0vDj59Ar$H|KyP{7MvFBZ$Q1)uifku#pybAI5@=R8KNni_0R z^C(8mR!mGB{Ft7eL{9PaF+UZM$T_Rkwr^0EyYCplDghA<0aKcKVJ(Ck0kgI&iO*Nmq`?!pToa+53sU z`7CP*@*{MfkvBmuTxW@hO44;|A{qGmg-^V-re*Is*UHtpQ z+1Izb&sUq9%gyz3%-=PB8wHnV=aXN|Tb?I;;R>rd=f-_{|JZ*(xSPf=EZ~{%>~wkZ ze0_pnJ;vp>-fmCcZD+T;#og)h-R$|NAOGz?Z;pBAiw`;D-QJ7Mw=-Uk4%cAEN3Hm7 zFDCD7i926iNfQ5s@Tnwg=t$A>bg+?j%mwuXd#rr%jVor2_9f;!<|A=W%$mY5a;|xn zQAZP#u0!Q!sMjiffDo*C?FQ70OM}Cf)P{S*=xzfQ0nFSE0bQu@rbP zymZ5MAlmdOvy=$XINXvdP<6x*iJYobb}D4-dwgTkW!|*sp_Eo|(yf|G-LD7MlqkA( zkcAZXZ4vzotbHlNDx^!UG`l-M7fC7WyBsukn%mzq9)h|2@WCOIQ`{5-7^v4|)2V794;EOK;n(6-wMG2a`)Zgq$% z(fwnr9RY!dwN@Wek2=^Gv<;5v>OT|dUXGvO*4{qZbPHQY?Ru-J5*8zGlV_j zlJ1Z$zM~q=b!0Gw_E6XdxRojzr5lP+M5Bf_)=`Xu4DiYbTRH$Ep8QY}ZYDX1x>nJW zP#hCP3_e5AA-0@Gco;iB!ex;8Bd6yltIPTN^#Zea`+=`QZy%l?KV5GhZ(eQBU*6+E z^(nts`);#%v&QEu<`)ZGg%y{5=k=3uIVt{gQ>en(5sU7QyTiis8LsP&JKq`Zd|z#k z-t3-T?~d>j$+x@t-Pz*deD&t|?bAJae9f6(5A+xF{cf+`Fv7dN zyxNDJ_4?po^bF$u>Tq!yYAV%XAxHn;7{~o75pden)?v!0x;k_wn8WGTrlFO2_nji_ zK}B7H{7MmCeS#1TxLdbf&8u|ni*HAyu%b#h6gVBNCXf^~0TD%FEoB}W#i1saVq_rT zY$M^^DvW`vsZ)`?(BPy1w@%FT+z!UbQX4%bQd%c(*$~J3YQQ z!v~Z3?izM@x>0m ze~Rz+-r<+U`N(;VN6!AV#%{(>Yv2bY_!6%U6n9p8X_uppSb;nS0zI3CEgXl)Q_?hY zjN3r8%{%Uij$LpR0vILq|3IY!9u+m~nJWeV-x7TabXFkQ0Qs`1-;8jDfD_fZE`~kWY9&?TG)&#g5za{Bd$~@E>~i4e61i~m z;8^K<+~5S$JnJaew>YB*Y6hnnM7KC2C2pERLEek92`&_oO`3h( zi|YKweVsm>c!Vp^;)71Sn&V90ADSO6@nc8$;sC$e*L+qoAaX&vlnJ~ zPjHct4Ic3Cj+Yz!61OI=o}04YXw!}B;P8Y`oRcMIA0HvW&ZrF_-dT=bMWCING3KC{ z$YMojc`{m4xd^!;rzemq?P(~NxDtaYm*rBHmhD6;N?d$!$jYo?WMUAg6ijZMCD4H= zDnw-sE2U`2Q&AH*I_)6K86)Tf@ds#9Qj3xRYsJ#Kjr0upfFv)sCS|M1&8YTbIJpzQ zMPnOUIoNh`g7j=p`y2V66u6P9Yi^=+=7iDNaut2bloQ0*1v-s%PK;4 zNPfjlD=Ep2Y%`VU`$5-ox>LF1%Bn-eXw5`8n2fq3mZ<}k1mt<5xgry_G6k|4V_JbJ zw^Ce}eEel1!R)r|k|k118zMWMqX^y~sfKdt2h%EY$_$Rupu@##GUcgNhYWtt1{Ud= z$ZazJhfvVXOn%phoj25I)bu*)h}4b-{5{Fx4r_2yk2=+J2UQ@3Amrh~DZwlUy>VvQ z86C=l@8ObswnH~FLKj0?oe?=g%>Gd5TK?@6v*7fWmdMmF`CJASyWQDOxNm6 z28*EVKn!Ne&^@q3OthS=8{&nV2)9-s8Fh!X*Mu_^{8q>NMM^eVMzV6NM@>*5!Q_%v zx_Jo2QnUz+E^Gx8e5qL$+##MJf>?E0lAJ4rovSRn#1dp0eQs%L(+vUw%}L4uQwrqR zNM7W^^O8Q6jG#v zk>tWNk&wV*mdk*alClCYYKB&DxM@=9O`=TEQbr4B6G>nR*dEQxbb4-}8%?0=Bgs1A zGSy3PteMKWRgOv*G7MYgx4NO6CH{|FcCxoB(^waA%@|wQNF6J>L839yPi4y@RL6mO zd#(^Nbtr7eqsc{8T*|IR%rE8Yp`uK!TBRd|S--Wi2A9eOvF>*qVpMCn=DPcK zX-2Db4}`wY-y>!}p=v|OB3-T|IhC}9wz>qjKmWTq(jfIR@y@l(;WrMWR zmu-Y27U}FCUV#j0rDt0i-S%FDPW8-$+%;D)LX_G1+UnuW|LLYh{5*musDoDB0m!BonDzwi~br z16&*|O(FqhY;0*wf_AKvp&^=y6l}~O2r0M>iNz4$G}gUtR}R2|+sTo;+4>}{sAWjV zUJ+nKJT^&6mju}fL_2-MkU4I{R3oWx%tYFbiXT$y-?bR^nh6~smSo9LfJizcHECi* zQIm;y$t-xj>qP0oTnHg*T32I~Yx>2Ebd#Nxqjf_@4byhHK-E(=z>2C(BUkdZG9so~ zCXnTHqb6H~T9F$H6&3EznP*v#DL8NusvnAKal!N$$AS^H{+C6CEJ&{S%$g>4Z`h*k zm(YGqisrtArt_UE9!-POve8C{hNh8*!yG+(kBZHhj(j1m($ZUGV!EqAEX$e`uACyk zD_i6aR37xXIwqQJ*EP-A#3gBCg#66Qp}ynYc5cgzqNy^(VR_9^>_w?5%Jz~*DcD#l z1hZ^~Ob{lbKxdTxxZ5Q~i$!2sM21rpnI5{N#nucv!KMz=<#M3IrMCy$A%auBsLl?K zvZp$EG?eXl=(w6?BM}>;*+V3x$cPIeS9}|8J22xKOC$_!B4remlCyesAbTQ(Bp!7S zn{+Fkrd$FEx}`(JIBAd#Cya0lRg}ajl1U@o)*-7WcH0U>YS+q0^?fz@Na5n)gL+^yW@7%NK zZD9_MlJ;EF4RY*Z_tUCNAO;YlLlXp#>|rqgW&nG5D~Je#Q$h#!BkAW>g*e30aYFEG zO^&x_*6vg=+D@UMwH}$$m#I7Ta?fxm5YX7u%XSvWM31s8unga8SAwY! zrnuEQxfEa!cY0_kDCLo&P-imk#8%oE@vtN=qM#U*mlTsL++ro;HX@R(RurkU?Waz( znqDL(Xtk9k=YKQied|AWDs?j@urIBa_(F z6H5>W{FOaCacV$ytwDE6wq%izkrV{!rp+wd%BL;YAWcV&mkqq$6X~GqDjI`(b5TJq zfw4>Wj8QRrtFAzEV|)A}P}3D%iwVi?eNJiSgtBOnR4M8fv{5Mgw>pc46`XKgA5IZO zD`9xfB_(rWODNXdx(3G}r))J)xrJnB%8~#%QVg;@MFz)iRdGgu#c$P3psJM399dP# zxs_NvQOU~ChyZEnqA=(>6`?C9KO0Lw;3?YQ-K%= zRv=sYt-UZ2BUZjsqh+$QMsg%YG;*{W3H^g;0(oT0hoQwXkb(kj%4NW=7^X2eEYgg) z8QKR5=7enC3oFgZN;%Y#7KU+5LMSRS4GS2x+D)m7N{J|UP-Hhl+_Bns=Hy~BJQ&83 zOb@nj3p!3j9FL|&ZkBRtj49&uU{*P#WU`26X-qsI)g@MV8A*@EiUNXHBgMB-ZWM^L zfZd@+AR{BQxNUZr*d)k!y0wpyWW1u2Bz6-Ttp}o5GBE^Aa454XH^?I?d3_57CDcg6 zs|8!Ms)v9=0OPZKK(k>J94A~=WQ#~K{b>{-5R;X>*VRZ-0l2lgN+}1fjjO}tk_p~T zf>j!(ZH%%_XI8pScW&5@V)O?=<#LF6IknS`2n)oKr=cv$=BFZiCmANmZ*wzS3d$RH zV6A^w0UlKxinK0lNC?>xDuew5MVoZ6wHXbYQ|R|nisH;vO4*Q07h54kgF$-=+GS4i za!aK6Bw&GGy8}b3BYhMr$e9#zhMFw(b8$!|357_DI)wDYD7%_AV`YmtC6!XS@k6t6 z_NZ#OiwVe8%RN*QdJYiTV0cXNBKvMHFyxrwTO +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts((u8*)buf); + return ret; +} + diff --git a/fps2bios/intro/include/eedebug.h b/fps2bios/intro/include/eedebug.h new file mode 100644 index 0000000000..dfe853c609 --- /dev/null +++ b/fps2bios/intro/include/eedebug.h @@ -0,0 +1,12 @@ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/intro/include/romdir.h b/fps2bios/intro/include/romdir.h new file mode 100644 index 0000000000..8249989e78 --- /dev/null +++ b/fps2bios/intro/include/romdir.h @@ -0,0 +1,20 @@ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/intro/intro.c b/fps2bios/intro/intro.c new file mode 100644 index 0000000000..a9d54ca3d5 --- /dev/null +++ b/fps2bios/intro/intro.c @@ -0,0 +1,19 @@ + +#include +#include +#include +#include + +#include "eedebug.h" +#include "romdir.h" + + +int main() { + + __printf("INTRO start\n"); + + __printf("INTRO end\n"); + + return 0; +} + diff --git a/fps2bios/intro/linkfile b/fps2bios/intro/linkfile new file mode 100644 index 0000000000..221a16a68e --- /dev/null +++ b/fps2bios/intro/linkfile @@ -0,0 +1,52 @@ +_stack_size = 0x80000; +_heap_size = 1024*1024*10; + +ENTRY(_start); +SECTIONS { + + .text 0x00100008 : { + *(.text) + *(.rodata) + } + .reginfo ALIGN(128) : { + *(.reginfo) + } + .data ALIGN(128) : { + *(.data) + } + .rdata ALIGN(128) : { + *(.rdata) + } + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128) : { + *(.lit4) + } + .lit8 ALIGN(128) : { + *(.lit8) + } + .sdata ALIGN(128) : { + *(.sdata) + } + + .sbss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + _fbss = . ; + *(.scommon) + *(.sbss) + } + .bss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(.bss) + } + .COMMON ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(COMMON) + } + _end_bss = . - 4; + _stack = .; + . += _stack_size ; + _end_stack = . - 8*5; + _end = . ; + __lc_bh = . ; + . += _heap_size ; + __lc_eh = .; + +} + diff --git a/fps2bios/intro/romdir.c b/fps2bios/intro/romdir.c new file mode 100644 index 0000000000..2487288f0f --- /dev/null +++ b/fps2bios/intro/romdir.c @@ -0,0 +1,43 @@ +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; + struct romdir *base; + int i; + + base = romdirInit(); + if (base == NULL) return NULL; + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/Makefile b/fps2bios/kernel/Makefile new file mode 100644 index 0000000000..566a5dee9f --- /dev/null +++ b/fps2bios/kernel/Makefile @@ -0,0 +1,73 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 +EEINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: start + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +OBJS = eestart.o iopstart.o start.o romdir.o +DIRS = eeload iopload + +start: $(OBJS) + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + $(EELD) -Wl,--oformat,binary -T linkfile $(EECFLAGS) $(OBJS) -o ../build/RESET + +iopstart.o: iopstart.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +eestart.o: eestart.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + +romdir.o: romdir.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +start.o: start.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + + +clean: + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + rm -f $(OBJS) start + + + diff --git a/fps2bios/kernel/eeload/Makefile b/fps2bios/kernel/eeload/Makefile new file mode 100644 index 0000000000..c836b90d7d --- /dev/null +++ b/fps2bios/kernel/eeload/Makefile @@ -0,0 +1,61 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE --save-temps +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: eeload + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/ee/lib +LDADD = -lmc -lpad -lc -lkernel +OBJECTS = eeirq.o eedata.o eekernel.o eeinit.o eeload.o eeelf.o eedebug.o romdir.o + +eeload: $(OBJECTS) + $(EELD) -Wl,--oformat,binary,--Map,eeload.map -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../build/EELOAD + +# restrict all but the kernel registers +eeirq.o: eeirq.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -ffixed-2 -ffixed-3 -ffixed-4 -ffixed-5 -ffixed-6 -ffixed-7 -ffixed-8 -ffixed-9 -ffixed-10 -ffixed-11 -ffixed-12 -ffixed-13 -ffixed-14 -ffixed-15 -ffixed-16 -ffixed-17 -ffixed-18 -ffixed-19 -ffixed-20 -ffixed-21 -ffixed-22 -ffixed-23 -ffixed-24 -ffixed-25 -fcall-used-26 -fcall-used-27 -ffixed-30 -o $@ -c $< +%.o: %.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) eeload + + + diff --git a/fps2bios/kernel/eeload/eedata.c b/fps2bios/kernel/eeload/eedata.c new file mode 100644 index 0000000000..9343330287 --- /dev/null +++ b/fps2bios/kernel/eeload/eedata.c @@ -0,0 +1,198 @@ +// eedata.c - needed in order to assure +// that some of the kernel variables are as close to 0x80000000 as possible +// (ie, look in saveContext2) +//[made by] [RO]man, zerofrog + +#include +#include +#include + +#include "eekernel.h" +#include "eeirq.h" + +eeRegs SavedRegs __attribute((aligned(256))); +u128 SavedSP __attribute((aligned(16))); +u128 SavedRA __attribute((aligned(16))); +u128 SavedAT __attribute((aligned(16))); +u64 SavedT9 __attribute((aligned(16))); + +u32 _CpuConfig_0(u32); +u32 _CpuConfig_1(u32); +u32 _CpuConfig_2(u32); +u32 _CpuConfig_3(u32); +u32 _CpuConfig_4(u32); +u32 _CpuConfig_5(u32); +u32 (*table_CpuConfig[6])(u32) = {_CpuConfig_0, _CpuConfig_1, _CpuConfig_2, + _CpuConfig_3, _CpuConfig_4, _CpuConfig_5}; + +u32 dmac_CHCR[10] = { + 0xB0008000, + 0xB0009000, + 0xB000A000, + 0xB000B000, + 0xB000B400, + 0xB000C000, + 0xB000C400, + 0xB000C800, + 0xB000D000, + 0xB000D400, +}; + +void (*VCRTable[14])() = { + 0, 0, 0, 0, + 0, 0, 0, 0, + SyscException, 0, 0, 0, + 0, 0 +}; + +void (*VIntTable[8])() = { + 0, 0, DMACException, INTCException, + 0, 0, 0, TIMERException, +}; + +void _DummyINTCHandler(int); +void _DummyDMACHandler(int); + +void (*INTCTable[16])(int) = { + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler }; + +void (*DMACTable[16])(int) = { + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler }; + + +void (*table_SYSCALL[0x80])() = { + (void (*))_RFU___, // 0x00 + (void (*))_ResetEE, + (void (*))_SetGsCrt, + (void (*))_RFU___, + (void (*))_Exit, // 0x04 + (void (*))_RFU005, + (void (*))_LoadPS2Exe, + (void (*))_ExecPS2, + (void (*))_RFU___, // 0x08 + (void (*))_TlbWriteRandom, + (void (*))_AddSbusIntcHandler, + (void (*))_RemoveSbusIntcHandler, + (void (*))_Interrupt2Iop, // 0x0C + (void (*))_SetVTLBRefillHandler, + (void (*))_SetVCommonHandler, + (void (*))_SetVInterruptHandler, + (void (*))_AddIntcHandler, // 0x10 + (void (*))_RemoveIntcHandler, + (void (*))_AddDmacHandler, + (void (*))_RemoveDmacHandler, + (void (*))__EnableIntc, // 0x14 + (void (*))__DisableIntc, + (void (*))__EnableDmac, + (void (*))__DisableDmac, + (void (*))_SetAlarm, // 0x18 + (void (*))_ReleaseAlarm, + (void (*))__EnableIntc, + (void (*))__DisableIntc, + (void (*))__EnableDmac, // 0x1C + (void (*))__DisableDmac, + (void (*))_SetAlarm, + (void (*))_ReleaseAlarm, + (void (*))_CreateThread, // 0x20 + (void (*))_DeleteThread, + (void (*))_StartThread, + (void (*))_ExitThread, + (void (*))_ExitDeleteThread, // 0x24 + (void (*))_TerminateThread, + (void (*))_iTerminateThread, + (void (*))_DisableDispatchThread, + (void (*))_EnableDispatchThread, // 0x28 + (void (*))_ChangeThreadPriority, + (void (*))_iChangeThreadPriority, + (void (*))_RotateThreadReadyQueue, + (void (*))_iRotateThreadReadyQueue, // 0x2C + (void (*))_ReleaseWaitThread, + (void (*))_iReleaseWaitThread, + (void (*))_GetThreadId, + (void (*))_ReferThreadStatus, // 0x30 + (void (*))_ReferThreadStatus, + (void (*))_SleepThread, + (void (*))_WakeupThread, + (void (*))_iWakeupThread, + (void (*))_CancelWakeupThread, + (void (*))_CancelWakeupThread, + (void (*))_SuspendThread, + (void (*))_SuspendThread, + (void (*))_ResumeThread, + (void (*))_iResumeThread, + (void (*))_JoinThread, + (void (*))_InitializeMainThread, + (void (*))_InitializeHeapArea, + (void (*))_EndOfHeap, + (void (*))_RFU___, + (void (*))_CreateSema, // 0x40 + (void (*))_DeleteSema, + (void (*))_SignalSema, + (void (*))_iSignalSema, + (void (*))_WaitSema, + (void (*))_PollSema, + (void (*))_PollSema, + (void (*))_ReferSemaStatus, + (void (*))_ReferSemaStatus, + (void (*))_iDeleteSema, + (void (*))_SetOsdConfigParam, + (void (*))_GetOsdConfigParam, + (void (*))_GetGsHParam, + (void (*))_GetGsVParam, + (void (*))_SetGsHParam, + (void (*))_SetGsVParam, + (void (*))_CreateEventFlag, // 0x50 + (void (*))_DeleteEventFlag, + (void (*))_SetEventFlag, + (void (*))_iSetEventFlag, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_EnableIntcHandler, + (void (*))_DisableIntcHandler, + (void (*))_EnableDmacHandler, + (void (*))_DisableDmacHandler, + (void (*))_KSeg0, // 0x60 + (void (*))_EnableCache, + (void (*))_DisableCache, + (void (*))_GetCop0, + (void (*))_FlushCache, + (void (*))_105, + (void (*))_CpuConfig, + (void (*))_GetCop0, + (void (*))_FlushCache, + (void (*))_105, + (void (*))_CpuConfig, + (void (*))_SifStopDma, //_sceSifStopDma, + (void (*))_SetCPUTimerHandler, + (void (*))_SetCPUTimer, + (void (*))0,//_SetOsdConfigParam2, + (void (*))0,//_GetOsdConfigParam2, + (void (*))_GsGetIMR, // 0x70 + (void (*))_GsPutIMR, + (void (*))_SetPgifHandler, + (void (*))_SetVSyncFlag, + (void (*))_SetSYSCALL, + (void (*))_print, + (void (*))_SifDmaStat, + (void (*))_SifSetDma, + (void (*))_SifSetDChain, + (void (*))_SifSetReg, + (void (*))_SifGetReg, + (void (*))_ExecOSD, + (void (*))_RFU___, + (void (*))_PSMode, + (void (*))_MachineType, + (void (*))_GetMemorySize +}; diff --git a/fps2bios/kernel/eeload/eedebug.c b/fps2bios/kernel/eeload/eedebug.c new file mode 100644 index 0000000000..24bc361406 --- /dev/null +++ b/fps2bios/kernel/eeload/eedebug.c @@ -0,0 +1,31 @@ + +#include +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts(buf); + return ret; +} + diff --git a/fps2bios/kernel/eeload/eeelf.c b/fps2bios/kernel/eeload/eeelf.c new file mode 100644 index 0000000000..52dce53963 --- /dev/null +++ b/fps2bios/kernel/eeload/eeelf.c @@ -0,0 +1,423 @@ +#include "romdir.h" +#include "eedebug.h" + +typedef struct { + u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) + u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //Processor: 8=MIPS R3000 + u32 e_version; //Version: 1=current + u32 e_entry; //Entry point address + u32 e_phoff; //Start of program headers (offset from file start) + u32 e_shoff; //Start of section headers (offset from file start) + u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //Program headers entry size + u16 e_phnum; //Number of program headers + u16 e_shentsize; //Section headers entry size + u16 e_shnum; //Number of section headers + u16 e_shstrndx; //Section header stringtable index +} ELF_HEADER; + +typedef struct { + u32 p_type; //see notes1 + u32 p_offset; //Offset from file start to program segment. + u32 p_vaddr; //Virtual address of the segment + u32 p_paddr; //Physical address of the segment + u32 p_filesz; //Number of bytes in the file image of the segment + u32 p_memsz; //Number of bytes in the memory image of the segment + u32 p_flags; //Flags for segment + u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +} ELF_PHR; + +/* +notes1 +------ +0=Inactive +1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +2=Dynamic linking +3=Interpreter. The array element must specify a path name +4=Note. The array element must specify the location and size of aux. info +5=reserved +6=The array element must specify location and size of the program header table. +*/ + +typedef struct { + u32 sh_name; //No. to the index of the Section header stringtable index + u32 sh_type; //See notes2 + u32 sh_flags; //see notes3 + u32 sh_addr; //Section start address + u32 sh_offset; //Offset from start of file to section + u32 sh_size; //Size of section + u32 sh_link; //Section header table index link + u32 sh_info; //Info + u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //Fixed size entries. +} ELF_SHR; +/* +notes 2 +------- +Type: +0=Inactive +1=PROGBITS +2=SYMTAB symbol table +3=STRTAB string table +4=RELA relocation entries +5=HASH hash table +6=DYNAMIC dynamic linking information +7=NOTE +8=NOBITS +9=REL relocation entries +10=SHLIB +0x70000000=LOPROC processor specifc +0x7fffffff=HIPROC +0x80000000=LOUSER lower bound +0xffffffff=HIUSER upper bound + +notes 3 +------- +Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +1=Write section contains data the is be writeable during execution. +2=Alloc section occupies memory during execution +4=Exec section contains executable instructions +0xf0000000=Mask bits processor-specific +*/ + +typedef struct { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +} Elf32_Sym; + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +typedef struct { + u32 r_offset; + u32 r_info; +} Elf32_Rel; + +char *sections_names; + +ELF_HEADER *elfHeader; +ELF_PHR *elfProgH; +ELF_SHR *elfSectH; +u8 *elfdata; +int elfsize; + + +static void __memcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + + +int loadHeaders() { + elfHeader = (ELF_HEADER*)elfdata; + + if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { + return -1; + } + +#ifdef ELF_LOG + ELF_LOG( "type: " ); +#endif + switch( elfHeader->e_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", elfHeader->e_type ); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG( "no file type" ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG( "relocatable" ); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG( "executable" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); +#endif + switch ( elfHeader->e_machine ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown" ); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG( "mips_rs3000" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("version: %d\n",elfHeader->e_version); + ELF_LOG("entry: %08x\n",elfHeader->e_entry); + ELF_LOG("flags: %08x\n",elfHeader->e_flags); + ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); + ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); + ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); + ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); + ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); + ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); + ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); + ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); + + ELF_LOG("\n"); +#endif + + return 0; +} + + +int loadProgramHeaders() { + int i; + + if (elfHeader->e_phnum == 0) { + return 0; + } + + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { + return -1; + } + + elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; + + for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); +#endif + switch ( elfProgH[ i ].p_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("load"); +#endif +/* if ( elfHeader->e_shnum == 0 ) {*/ + if (elfProgH[ i ].p_offset < elfsize) { + int size; + + if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { + size = elfsize - elfProgH[ i ].p_offset; + } else { + size = elfProgH[ i ].p_filesz; + } +// __printf("loading program to %x\n", elfProgH[ i ].p_paddr + elfbase); + __memcpy(elfProgH[ i ].p_paddr, + &elfdata[elfProgH[ i ].p_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG("\t*LOADED*"); +#endif +// } + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); + ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); + ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); + ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); + ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); + ELF_LOG("palign: %08x\n",elfProgH[i].p_align); + ELF_LOG("\n"); +#endif + } + + return 0; +} + +int loadSectionHeaders() { + int i; + int i_st = -1; + int i_dt = -1; + + if (elfHeader->e_shnum == 0) { + return -1; + } + + elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; + + if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { + sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; + } + + for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); +#endif +/* if ( elfSectH[i].sh_flags & 0x2 ) { + if (elfSectH[i].sh_offset < elfsize) { + int size; + + if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { + size = elfsize - elfSectH[i].sh_offset; + } else { + size = elfSectH[i].sh_size; + } + memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], + &elfdata[elfSectH[i].sh_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG( "\t*LOADED*" ); +#endif + }*/ +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("type: "); +#endif + switch ( elfSectH[ i ].sh_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG("unknown %08x",elfSectH[i].sh_type); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG("null"); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("progbits"); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG("symtab"); +#endif + break; + + case 0x3: +#ifdef ELF_LOG + ELF_LOG("strtab"); +#endif + break; + + case 0x4: +#ifdef ELF_LOG + ELF_LOG("rela"); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG("no bits"); +#endif + break; + + case 0x9: +#ifdef ELF_LOG + ELF_LOG("rel"); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); + ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); + ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); + ELF_LOG("size: %08x\n", elfSectH[i].sh_size); + ELF_LOG("link: %08x\n", elfSectH[i].sh_link); + ELF_LOG("info: %08x\n", elfSectH[i].sh_info); + ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); + ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); +#endif + // dump symbol table + + if (elfSectH[i].sh_type == 0x02) { + i_st = i; i_dt = elfSectH[i].sh_link; + } +/* + if (elfSectH[i].sh_type == 0x01) { + int size = elfSectH[i].sh_size / 4; + u32 *ptr = (u32*)&psxM[(elfSectH[i].sh_addr + irx_addr) & 0x1fffff]; + + while (size) { + + if (*ptr == 0x41e00000) { // import func + int ret = iopSetImportFunc(ptr+1); + size-= ret; ptr+= ret; + } + + if (*ptr == 0x41c00000) { // export func + int ret = iopSetExportFunc(ptr+1); + size-= ret; ptr+= ret; + } + + size--; ptr++; + } + } +*/ +/* if (!strcmp(".data", §ions_names[elfSectH[i].sh_name])) { + // seems so.. + + psxRegs.GPR.n.gp = 0x8000 + irx_addr + elfSectH[i].sh_addr; + }*/ + } + + return 0; +} + + +u32 loadElfFile(char *filename, struct elfinfo *info) { + struct rominfo ri; + char str[256]; + char str2[256]; + int i; + + __printf("loadElfFile: %s\n", filename); + + if (romdirGetFile(filename, &ri) == NULL) { + __printf("file %s not found!!\n", filename); + return -1; + } + elfdata = (u8*)(0xbfc00000 + ri.fileOffset); + elfsize = ri.fileSize; + + loadHeaders(); + loadProgramHeaders(); + loadSectionHeaders(); + +// __printf("loadElfFile: e_entry=%x\n", elfHeader->e_entry); + return elfHeader->e_entry; +} + diff --git a/fps2bios/kernel/eeload/eeinit.c b/fps2bios/kernel/eeload/eeinit.c new file mode 100644 index 0000000000..c26a421edf --- /dev/null +++ b/fps2bios/kernel/eeload/eeinit.c @@ -0,0 +1,511 @@ +// EE initialization functions +// [made by] [RO]man, zerofrog +#include +#include + +#include "eekernel.h" +#include "eeirq.h" + +void InitializeGS(); +void InitializeGIF(); +void InitializeDMAC(int code); +void InitializeVU1(); +void InitializeVIF1(); +void InitializeIPU(); +void InitializeVIF0(); +void InitializeVU0(); +void InitializeFPU(); +void InitializeScratchPad(); +void InitializeUserMemory(u32 base); +void InitializeINTC(int a); +void InitializeTIMER(); + +//////////////////////////////////////////////////////////////////// +//8000AA60 +//////////////////////////////////////////////////////////////////// +void InitializeGS() +{ +} + +//////////////////////////////////////////////////////////////////// +//8000AB98 +//////////////////////////////////////////////////////////////////// +void InitializeGIF() +{ + GIF_CTRL = 1; + __asm__ ("sync\n"); + GIF_FIFO = 0; +} + +//////////////////////////////////////////////////////////////////// +//8000AD68 SYSCALL 001 ResetEE +//////////////////////////////////////////////////////////////////// +int _ResetEE(int init) +{ + if (init & 0x01) { __printf("# Initialize DMAC ...\n"); InitializeDMAC(0x31F); } + if (init & 0x02) { __printf("# Initialize VU1 ...\n"); InitializeVU1(); } + if (init & 0x04) { __printf("# Initialize VIF1 ...\n"); InitializeVIF1(); } + if (init & 0x08) { __printf("# Initialize GIF ...\n"); InitializeGIF(); } + if (init & 0x10) { __printf("# Initialize VU0 ...\n"); InitializeVU0(); } + if (init & 0x04) { __printf("# Initialize VIF0 ...\n"); InitializeVIF0(); } + if (init & 0x40) { __printf("# Initialize IPU ...\n"); InitializeIPU(); } + + InitializeINTC(0xC); +// return (*(int*)0x1000F410 &= 0xFFFBFFFF); code never reached :) +} + +//////////////////////////////////////////////////////////////////// +//8000AE88 +//////////////////////////////////////////////////////////////////// +int Initialize() +{ + __printf("# Initialize Start.\n"); + __printf("# Initialize GS ..."); + + InitializeGS(); + _SetGsCrt(1, 2, 1); + __printf("\n"); + + __printf("# Initialize INTC ...\n"); + InitializeINTC(0xFFFF); + + __printf("# Initialize TIMER ...\n"); + InitializeTIMER(); + + ResetEE(0x7F); + + __printf("# Initialize FPU ...\n"); + InitializeFPU(); + + __printf("# Initialize User Memory ...\n"); + InitializeUserMemory(0x80000); + + __printf("# Initialize Scratch Pad ...\n"); + InitializeScratchPad(); + + __printf("# Initialize Done.\n"); +} + +//////////////////////////////////////////////////////////////////// +//8000AF50 +//////////////////////////////////////////////////////////////////// +int Restart() +{ + __printf("# Restart.\n"); + __printf("# Initialize GS ..."); + + INTC_STAT = 4; + while (INTC_STAT & 4) { __asm__ ("nop\nnop\nnop\n"); } + INTC_STAT = 4; + + InitializeGS(); + _SetGsCrt(1, 2, 1); + __printf("\n"); + + __printf("# Initialize INTC ...\n"); + InitializeINTC(0xDFFD); + + __printf("# Initialize TIMER ...\n"); + InitializeTIMER(); + + ResetEE(0x7F); + + __printf("# Initialize FPU ...\n"); + InitializeFPU(); + + __printf("# Initialize User Memory ...\n"); + InitializeUserMemory(0x82000); + + __printf("# Initialize Scratch Pad ...\n"); + InitializeScratchPad(); + + __printf("# Restart Done.\n"); + + //wait for syncing IOP + while (SBUS_SMFLG & SBFLG_IOPSYNC) { __asm__ ("nop\nnop\nnop\n"); } + + SBUS_SMFLG=SBFLG_IOPSYNC; +} + +//////////////////////////////////////////////////////////////////// +//8000B0A0 +//////////////////////////////////////////////////////////////////// +void InitializeDMAC(int code) +{ + int i; + int *addr; + + for (i=0; i<10; i++) { + if (!(code & (1< 48) { + __printf("# TLB over flow (1)\n"); + } + + ptr = (u32*)(tlb_config[4] + 0x10); + for (i=1; i 48) { + __printf("# TLB over flow (2)\n"); + } + + if (tlb_config[1]) { + ptr = (u32*)(tlb_config[5]); + for (; i 48) { + __printf("# TLB over flow (3)\n"); + } + + ptr = (u32*)(tlb_config[6]); + for (; i> 16) | 0x8000; + code&= DMAC_STAT & 0xFFFF; + if (code & 0x80) { + //__printf("%s: code & 0x80\n", __FUNCTION__); + __asm__( + ".set noat\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n"); + __exception1(); + } + __asm__ ( + "mfc0 $26, $14\n" + "li $27, 0xFFFFFFE4\n" + "and $26, $27\n" + "mtc0 $26, $14\n" + "sync\n" + + LOAD_KERNELSTACK + "addiu $sp, -0x10\n" + "mfc0 $26, $14\n" + "sw $26, 0($sp)\n" + ); + saveContext2(); + + __asm__ ( + "plzcw %0, %1" + : "=r"(temp) : "r"(code) + ); + temp = 0x1e - (temp & 0xff); + DMAC_STAT = 1 << temp; + threadStatus = 0; + + DMACTable[temp](temp); + + restoreContext2(); + + __asm__ ( + ".set noat\n" + "lw $26, 0($sp)\n" + "mtc0 $26, $14\n" + "lui $26, %hi(SavedSP)\n" + "lq $sp, %lo(SavedSP)($26)\n" + "lui $26, %hi(SavedRA)\n" + "lq $31, %lo(SavedRA)($26)\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n" + ); + + if (!threadStatus) { + __asm__ ( + "mfc0 $26, $12\n" + "ori $26, 0x13\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + ); + } + __asm__(LOAD_KERNELSTACK); + threadStatus = 0; + + __ThreadHandler(); +} + +//////////////////////////////////////////////////////////////////// +//80000600 +//////////////////////////////////////////////////////////////////// +void TIMERException() +{ + +} + +//////////////////////////////////////////////////////////////////// +//80000700 +//////////////////////////////////////////////////////////////////// +void setINTCHandler(int n, void (*phandler)(int)) +{ + INTCTable[n] = phandler; +} + +//////////////////////////////////////////////////////////////////// +//80000780 +//////////////////////////////////////////////////////////////////// +void setDMACHandler(int n, void (*phandler)(int)) +{ + DMACTable[n] = phandler; +} diff --git a/fps2bios/kernel/eeload/eekernel.c b/fps2bios/kernel/eeload/eekernel.c new file mode 100644 index 0000000000..c6c3d54b63 --- /dev/null +++ b/fps2bios/kernel/eeload/eekernel.c @@ -0,0 +1,3619 @@ +//[module] KERNEL +//[processor] EE +//[type] RAW +//[size] 80880(0x13BF0) +//[bios] 10000(0xB3200-0xC6DF0) +//[iopboot] NA +//[loaded @] 80000000 +//[name] NA +//[version] NA +//[memory map] [too many, see mem.txt] +//[handlers] +//[entry point] ENTRYPOINT @ 0x80001000 +//[made by] [RO]man, zerofrog & others +#include +#include + +#include "eekernel.h" +#include "eeinit.h" +#include "eedebug.h" +#include "romdir.h" + +#define PS2_LOADADDR 0x82000 + +// internal functions +int InitPgifHandler(); +int InitPgifHandler2(); + +struct ll* LL_unlink(struct ll *l); +struct ll* LL_rotate(struct ll *l); +struct ll *LL_unlinkthis(struct ll *l); +void LL_add(struct ll *l, struct ll *new); + +extern int (*table_GetCop0[32])(int reg); // 124E8-12564 +extern int (*table_SetCop0[32])(int reg, int val); // 12568-125E4 + +void DefaultCPUTimerHandler(); +void _excepRet(u32 eretpc, u32 v1, u32 a, u32 a1, u32 a2); +int __ExitThread(); +int __ExitDeleteThread(); +int __SleepThread(); +int _iWaitSema(int sid); + +void saveContext(); +void restoreContext(); + +int _SemasInit(); + +void _ThreadHandler(u32 epc, u32 stack); +void _ChangeThread(u32 entry, u32 stack_res, int waitSema); + +int __DeleteThread(int tid); +int __StartThread(int tid, void *arg); +int __load_module(char *name, void (*entry)(void*), void *stack_res, int prio); +void* __ExecPS2(void * entry, void * gp, int argc, char ** argv); + +void releaseTCB(int tid); +void unsetTCB(int tid); +void thread_2_ready(int tid); + +void FlushInstructionCache(); +void FlushDataCache(); +void FlushSecondaryCache(); + +void SifDmaInit(); + +u32 excepRetPc=0;//124E4 +int threadId=0; // 125EC +int threadPrio=0; // 125F0 +int threadStatus=0; // 125F4 + +char threadArgStrBuffer[256]; // 12608 +u64 hvParam; + +u32 machineType; +u64 gsIMR; +u32 memorySize; + +u8 g_kernelstack[0x2000] __attribute((aligned(128))); +u32 g_kernelstackend; // hopefully this is right after g_kernelstack + +int _HandlersCount; + +int VSyncFlag0; +int VSyncFlag1; + +struct ll handler_ll_free, *ihandlers_last=NULL, *ihandlers_first=NULL; +struct HCinfo intcs_array[14]; +struct ll *dhandlers_last=NULL, *dhandlers_first=NULL; +struct HCinfo dmacs_array[15]; +struct IDhandl pgifhandlers_array[161]; +void (*sbus_handlers[32])(int ca); +void (*CPUTimerHandler)() = DefaultCPUTimerHandler; //12480 + +u64 _alarm_unk = 0; +u64 rcnt3Valid=0;//16A68 +int rcnt3Count = 0; //16A70 +u32 dword_80016A78, dword_80016A7C, dword_80016A84, dword_80016A88; +//u32 rcnt3gp; //16A80 +//u32 rcnt3Mode; //16A84 +int rcnt3TargetTable[0x142]={0};//16A80 +u8 rcnt3TargetNum[0x40];//16F78 +int threads_count=0; + +u32 excepRA=0;//16FC0 +u32 excepSP=0;//16FD0 + +struct ll thread_ll_free; +struct ll thread_ll_priorities[128]; +int semas_count=0; +struct kSema* semas_last=0; + +struct TCB threads_array[256]; +struct kSema semas_array[256]; + +char tagindex=0;//1E104 +short transferscount=0;//1E106 +struct TAG tadrptr[31] __attribute((aligned(16)));//1E140 +int extrastorage[(16/4) * 8][31] __attribute((aligned(16)));//1E340 + +int osdConfigParam;//1F340 + +u32 sifEEbuff[32] __attribute((aligned(16))); +u32 sifRegs[32] __attribute((aligned(16))); +u32 sifIOPbuff; +u32 sif1tagdata; + +void _eret() +{ + __asm__("mfc0 $26, $12\n" + "ori $26, 0x13\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + "nop\n"); +} + +#define eret() __asm__("j _eret\nnop\n"); + +//////////////////////////////////////////////////////////////////// +//800006C0 SYSCALL 116 RFU116_SetSYSCALL +//////////////////////////////////////////////////////////////////// +void _SetSYSCALL(int num, int address) +{ + table_SYSCALL[num] = (void (*)())address; +} + +//////////////////////////////////////////////////////////////////// +//80000740 SYSCALL 114 SetPgifHandler +//////////////////////////////////////////////////////////////////// +void _SetPgifHandler(void (*handler)(int)) +{ + INTCTable[15] = handler; +} + +//////////////////////////////////////////////////////////////////// +//800007C0 SYSCALL 108 SetCPUTimerHandler +//////////////////////////////////////////////////////////////////// +void _SetCPUTimerHandler(void (*handler)()) +{ + CPUTimerHandler = handler; +} + +//////////////////////////////////////////////////////////////////// +//80000800 SYSCALL 109 SetCPUTimer +//////////////////////////////////////////////////////////////////// +void _SetCPUTimer(int compval) +{ + if( compval < 0 ) { + u32 status; + __asm__("mfc0 %0, $12\n" : "=r"(status) : ); + __asm__("mtc0 %0, $12\n" + "mtc0 $0, $9\n" : : "r"(status|0x18001)); + } + else if( compval == 0 ) { + u32 compare, status; + __asm__("mfc0 %0, $12\n" + "mfc0 %1, $11\n" + : "=r"(status), "=r"(compare) : ); + __asm__("mtc0 %0, $12\n" + "mtc0 $0, $9\n" + "mtc0 %1, $11\n" + : : "r"(status&~0x8000), "r"(compare) ); + } + else { + __asm__("mtc0 $0, $9\n" // count + "mtc0 %0, $11\n" // compare + : : "r"(compval)); + } +} + +//////////////////////////////////////////////////////////////////// +//800008C0 SYSCALL 020 EnableIntc +//////////////////////////////////////////////////////////////////// +int __EnableIntc(int ch) +{ + int intbit; + + intbit = 0x1 << ch; + if ((INTC_MASK & intbit) != 0) return 0; + + INTC_MASK = intbit; + + return 1; +} + +//////////////////////////////////////////////////////////////////// +//80000900 SYSCALL 021 DisableIntc +//////////////////////////////////////////////////////////////////// +int __DisableIntc(int ch) +{ + int intbit; + + intbit = 0x1 << ch; + if ((INTC_MASK & intbit) == 0) return 0; + + INTC_MASK = intbit; + + return 1; +} + +//////////////////////////////////////////////////////////////////// +//80000940 SYSCALL 022 EnableDmac +//////////////////////////////////////////////////////////////////// +int __EnableDmac(int ch) +{ + int dmabit; + + dmabit = 0x10000 << ch; + if ((DMAC_STAT & dmabit) != 0) return 0; + + DMAC_STAT = dmabit; + + return 1; +} + +//////////////////////////////////////////////////////////////////// +//80000980 SYSCALL 023 DisableDmac +//////////////////////////////////////////////////////////////////// +int __DisableDmac(int ch) +{ + int dmabit; + + dmabit = 0x10000 << ch; + if ((DMAC_STAT & dmabit) == 0) return 0; + + DMAC_STAT = dmabit; + + return 1; +} + +//////////////////////////////////////////////////////////////////// +//800009C0 SYSCALL 013 SetVTLBRefillHandler +//////////////////////////////////////////////////////////////////// +void* _SetVTLBRefillHandler(int cause, void (*handler)()) +{ + if ((cause-1) >= 3) return 0; + + VCRTable[cause] = handler; + + return handler; +} + +//////////////////////////////////////////////////////////////////// +//80000A00 SYSCALL 014 SetVCommonHandler +//////////////////////////////////////////////////////////////////// +void* _SetVCommonHandler(int cause, void (*handler)()) +{ + if ((cause-4) >= 10) return 0; + + VCRTable[cause] = handler; + + return handler; +} + +//////////////////////////////////////////////////////////////////// +//80000A40 SYSCALL 015 SetVInterruptHandler +//////////////////////////////////////////////////////////////////// +void* _SetVInterruptHandler(int cause, void (*handler)()) +{ + if (cause >= 8) return 0; + + VIntTable[cause] = handler; + // no return value... +} + +//////////////////////////////////////////////////////////////////// +//80000A80 SYSCALL 102,106 CpuConfig +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig(u32 op) +{ + u32 cfg; + __asm__("mfc0 %0, $16\n" : "=r"(cfg) : ); + return table_CpuConfig[op](cfg); +} + +//////////////////////////////////////////////////////////////////// +//80000AB8 +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_0(u32 cfg) +{ + cfg |= 0x40000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000AD0 +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_1(u32 cfg) +{ + cfg |= 0x2000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000AEC +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_2(u32 cfg) +{ + cfg |= 0x1000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000B04 +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_3(u32 cfg) +{ + cfg &= ~0x40000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000B20 +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_4(u32 cfg) +{ + cfg &= ~0x2000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000B40 +//////////////////////////////////////////////////////////////////// +u32 _CpuConfig_5(u32 cfg) +{ + cfg &= ~0x1000; + __asm__("mtc0 %0, $16\n" + "sync\n": : "r"(cfg)); + return cfg; +} + +//////////////////////////////////////////////////////////////////// +//80000B80 SYSCALL 125 PSMode +//////////////////////////////////////////////////////////////////// +void _PSMode() +{ + machineType|= 0x8000; +} + +//////////////////////////////////////////////////////////////////// +//80000BC0 SYSCALL 126 MachineType +//////////////////////////////////////////////////////////////////// +u32 _MachineType() +{ + return machineType; +} + +//////////////////////////////////////////////////////////////////// +//80000C00 +//////////////////////////////////////////////////////////////////// +u32 _SetMemorySize(u32 size) +{ + memorySize = size; + return size; +} + +//////////////////////////////////////////////////////////////////// +//80000C40 SYSCALL 127 GetMemorySize +//////////////////////////////////////////////////////////////////// +u32 _GetMemorySize() +{ + return memorySize; +} + +//////////////////////////////////////////////////////////////////// +//80000D00 SYSCALL 112 GsGetIMR +//////////////////////////////////////////////////////////////////// +u64 _GsGetIMR() +{ + return gsIMR; +} + +//////////////////////////////////////////////////////////////////// +//80000D40 SYSCALL 113 GsPutIMR +//////////////////////////////////////////////////////////////////// +u64 _GsPutIMR(u64 val) +{ + GS_IMR = val; + gsIMR = val; + return val; +} + +//////////////////////////////////////////////////////////////////// +//80000D80 SYSCALL 002 Exit +//////////////////////////////////////////////////////////////////// +int _Exit() +{ + return _RFU004_Exit(); +} + +//////////////////////////////////////////////////////////////////// +//80001000 ENTRYPOINT +//////////////////////////////////////////////////////////////////// +void __attribute__((noreturn)) _start() +{ + __asm__("lui $sp, %hi(g_kernelstackend)\n" + "addiu $sp, %lo(g_kernelstackend)\n"); + + __puts("EEKERNEL start\n"); + + memorySize = 32*1024*1024; + machineType = 0; + //memorySize = *(int*)0x70003FF0; + //machineType = machine_type; + + __printf("TlbInit\n"); + TlbInit(); + __printf("InitPgifHandler\n"); + InitPgifHandler(); + __printf("Initialize\n"); + Initialize(); +// __load_module_EENULL(); + + __asm__ ( + "li $26, %0\n" + "lw $26, 0($26)\n" + "mtc0 $26, $12\n" + "li $26, %1\n" + "lw $26, 0($26)\n" + "mtc0 $26, $16\n" + : : "i"(SRInitVal), "i"(ConfigInitVal) + ); + +// ee_deci2_manager_init(); + SifDmaInit(); +// __init_unk(0x81FE0); + SetVSyncFlag(0, 0); + + // call directly instread of loading module, might need to + // set thread0 as used since soem code assumes thread 0 is always + // main thread + //eeload_start(); + //launch_thread(__load_module("EELOAD", 0x82000, 0x81000, 0)); + + for (;;); +} + +//////////////////////////////////////////////////////////////////// +//80001300 +//////////////////////////////////////////////////////////////////// +void saveContext2() { + __asm__ ( + ".set noat\n" + "lui $26, %hi(SavedRegs)\n" + "sq $2, %lo(SavedRegs+0x000)($26)\n" + "sq $3, %lo(SavedRegs+0x010)($26)\n" + "sq $4, %lo(SavedRegs+0x020)($26)\n" + "sq $5, %lo(SavedRegs+0x030)($26)\n" + "sq $6, %lo(SavedRegs+0x040)($26)\n" + "sq $7, %lo(SavedRegs+0x050)($26)\n" + "sq $8, %lo(SavedRegs+0x060)($26)\n" + "sq $9, %lo(SavedRegs+0x070)($26)\n" + "sq $10, %lo(SavedRegs+0x080)($26)\n" + "sq $11, %lo(SavedRegs+0x090)($26)\n" + "sq $12, %lo(SavedRegs+0x0A0)($26)\n" + "sq $13, %lo(SavedRegs+0x0B0)($26)\n" + "sq $14, %lo(SavedRegs+0x0C0)($26)\n" + "sq $15, %lo(SavedRegs+0x0D0)($26)\n" + "sq $16, %lo(SavedRegs+0x0E0)($26)\n" + "sq $17, %lo(SavedRegs+0x0F0)($26)\n" + "sq $18, %lo(SavedRegs+0x100)($26)\n" + "sq $19, %lo(SavedRegs+0x110)($26)\n" + "sq $20, %lo(SavedRegs+0x120)($26)\n" + "sq $21, %lo(SavedRegs+0x130)($26)\n" + "sq $22, %lo(SavedRegs+0x140)($26)\n" + "sq $23, %lo(SavedRegs+0x150)($26)\n" + "sq $24, %lo(SavedRegs+0x160)($26)\n" + "sq $25, %lo(SavedRegs+0x170)($26)\n" + "sq $gp, %lo(SavedRegs+0x180)($26)\n" + "sq $fp, %lo(SavedRegs+0x190)($26)\n" + + "mfhi $2\n" + "sd $2, %lo(SavedRegs+0x1A0)($26)\n" + "mfhi1 $2\n" + "sd $2, %lo(SavedRegs+0x1A8)($26)\n" + + "mflo $2\n" + "sd $2, %lo(SavedRegs+0x1B0)($26)\n" + "mflo1 $2\n" + "sd $2, %lo(SavedRegs+0x1B8)($26)\n" + + "mfsa $2\n" + "sd $2, %lo(SavedRegs+0x1C0)($26)\n" + "jr $31\n" + "nop\n" + ".set at\n" + ); +} + +//////////////////////////////////////////////////////////////////// +//800013C0 +//////////////////////////////////////////////////////////////////// +void restoreContext2() { + __asm__ ( + ".set noat\n" + "lui $26, %hi(SavedRegs)\n" + "lq $2, %lo(SavedRegs+0x000)($26)\n" + "lq $3, %lo(SavedRegs+0x010)($26)\n" + "lq $4, %lo(SavedRegs+0x020)($26)\n" + "lq $5, %lo(SavedRegs+0x030)($26)\n" + "lq $6, %lo(SavedRegs+0x040)($26)\n" + "lq $7, %lo(SavedRegs+0x050)($26)\n" + "lq $8, %lo(SavedRegs+0x060)($26)\n" + "lq $9, %lo(SavedRegs+0x070)($26)\n" + "lq $10, %lo(SavedRegs+0x080)($26)\n" + "lq $11, %lo(SavedRegs+0x090)($26)\n" + "lq $12, %lo(SavedRegs+0x0A0)($26)\n" + "lq $13, %lo(SavedRegs+0x0B0)($26)\n" + "lq $14, %lo(SavedRegs+0x0C0)($26)\n" + "lq $15, %lo(SavedRegs+0x0D0)($26)\n" + "lq $16, %lo(SavedRegs+0x0E0)($26)\n" + "lq $17, %lo(SavedRegs+0x0F0)($26)\n" + "lq $18, %lo(SavedRegs+0x100)($26)\n" + "lq $19, %lo(SavedRegs+0x110)($26)\n" + "lq $20, %lo(SavedRegs+0x120)($26)\n" + "lq $21, %lo(SavedRegs+0x130)($26)\n" + "lq $22, %lo(SavedRegs+0x140)($26)\n" + "lq $23, %lo(SavedRegs+0x150)($26)\n" + "lq $24, %lo(SavedRegs+0x160)($26)\n" + "lq $25, %lo(SavedRegs+0x170)($26)\n" + "lq $gp, %lo(SavedRegs+0x180)($26)\n" + "lq $fp, %lo(SavedRegs+0x190)($26)\n" + + "ld $1, %lo(SavedRegs+0x1A0)($26)\n" + "mthi $1\n" + "ld $1, %lo(SavedRegs+0x1A8)($26)\n" + "mthi1 $1\n" + + "ld $1, %lo(SavedRegs+0x1B0)($26)\n" + "mtlo $1\n" + "ld $1, %lo(SavedRegs+0x1B8)($26)\n" + "mtlo1 $1\n" + + "ld $1, %lo(SavedRegs+0x1C0)($26)\n" + "mtsa $1\n" + + "jr $31\n" + "nop\n" + ".set at\n" + ); +} + +//////////////////////////////////////////////////////////////////// +//80001460 +//////////////////////////////////////////////////////////////////// +void erase_cpu_regs() +{ + __asm__( + ".set noat\n" + "padduw $1, $0, $0\n" + "padduw $2, $0, $0\n" + "padduw $3, $0, $0\n" + "padduw $4, $0, $0\n" + "padduw $5, $0, $0\n" + "padduw $6, $0, $0\n" + "padduw $7, $0, $0\n" + "padduw $8, $0, $0\n" + "padduw $9, $0, $0\n" + "padduw $10, $0, $0\n" + "padduw $11, $0, $0\n" + "padduw $12, $0, $0\n" + "padduw $13, $0, $0\n" + "padduw $14, $0, $0\n" + "padduw $15, $0, $0\n" + "padduw $16, $0, $0\n" + "padduw $17, $0, $0\n" + "padduw $18, $0, $0\n" + "padduw $19, $0, $0\n" + "padduw $20, $0, $0\n" + "padduw $21, $0, $0\n" + "padduw $22, $0, $0\n" + "padduw $23, $0, $0\n" + "padduw $24, $0, $0\n" + "padduw $25, $0, $0\n" + "padduw $gp, $0, $0\n" + "jr $31\n" + "padduw $fp, $0, $0\n" + ".set at\n" + ); +} + +//////////////////////////////////////////////////////////////////// +//800014D8 dummy intc handler +//////////////////////////////////////////////////////////////////// +void _DummyINTCHandler(int n) +{ + __printf("# INT: INTC (%d)\n", n); + while(1) { __asm__ ("nop\nnop\nnop\nnop\n"); } +} + +//////////////////////////////////////////////////////////////////// +//80001508 dummy dmac handler +//////////////////////////////////////////////////////////////////// +void _DummyDMACHandler(int n) +{ + __printf("# INT: DMAC (%d)\n", n); + while(1) { __asm__ ("nop\nnop\nnop\nnop\n"); } +} + +//////////////////////////////////////////////////////////////////// +//80001508 +//////////////////////////////////////////////////////////////////// +void DefaultCPUTimerHandler() +{ + __printf("# INT: CPU Timer\n"); +} + +//////////////////////////////////////////////////////////////////// +//80001564 SYSCALL 000 RFU000_FullReset +//80001564 SYSCALL 003 RFU003 (also) +//80001564 SYSCALL 008 RFU008 (too) +//////////////////////////////////////////////////////////////////// +void _RFU___() +{ + register int syscnum __asm__("$3"); + __printf("# Syscall: undefined (%d)\n", syscnum>>2); +} + +//////////////////////////////////////////////////////////////////// +//80001588 +//////////////////////////////////////////////////////////////////// +void _SetVSyncFlag(int flag0, int flag1) +{ + VSyncFlag0 = flag0; + VSyncFlag1 = flag1; +} + +//////////////////////////////////////////////////////////////////// +//800015A0 +//////////////////////////////////////////////////////////////////// +struct ll* _AddHandler() +{ + struct ll *l; + + l = LL_unlink(&handler_ll_free); + if (l == NULL) return NULL; + + _HandlersCount++; + return l; +} + +//////////////////////////////////////////////////////////////////// +//800015E8 +//////////////////////////////////////////////////////////////////// +void _RemoveHandler(int n) +{ + LL_add(&handler_ll_free, (struct ll*)&pgifhandlers_array[n]); + _HandlersCount--; +} + +//////////////////////////////////////////////////////////////////// +//80001630 +//////////////////////////////////////////////////////////////////// +void DefaultINTCHandler(int n) +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80001798 +//////////////////////////////////////////////////////////////////// +void DefaultDMACHandler(int n) +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//800018B0 +//////////////////////////////////////////////////////////////////// +int __AddIntcHandler(int cause, int (*handler)(int), int next, void *arg, int flag) +{ + struct IDhandl *idh; + + if ((flag != 0) && (cause == INTC_SBUS)) return -1; + if (cause >= 15) return -1; + + idh = (struct IDhandl *)_AddHandler(); + if (idh == 0) return -1; + + idh->handler = handler; + __asm__ ("sw $gp, %0\n" : "=m"(idh->gp) : ); + idh->arg = arg; + idh->flag = flag; + + if (next==-1) //register_last + LL_add(&ihandlers_last[cause*12], (struct ll*)idh); + else if (next==0) //register_first + LL_add(&ihandlers_first[cause*12], (struct ll*)idh); + else{ + if (next>128) return -1; + if (pgifhandlers_array[next].flag==3) return -1; + LL_add((struct ll*)&pgifhandlers_array[next], (struct ll*)idh); + } + + intcs_array[cause].count++; + return (((u32)idh-(u32)&pgifhandlers_array) * 0xAAAAAAAB) / 8; +} + +//////////////////////////////////////////////////////////////////// +//80001A30 SYSCALL 016 AddIntcHandler +//////////////////////////////////////////////////////////////////// +int _AddIntcHandler(int cause, int (*handler)(int), int next, void *arg) +{ + __AddIntcHandler(cause, handler, next, arg, 2); +} + +//////////////////////////////////////////////////////////////////// +//80001A50 +//////////////////////////////////////////////////////////////////// +int _AddIntcHandler2(int cause, int (*handler)(int), int next, void *arg) +{ + __AddIntcHandler(cause, handler, next, arg, 0); +} + +//////////////////////////////////////////////////////////////////// +//80001AC8 SYSCALL 017 RemoveIntcHandler +//////////////////////////////////////////////////////////////////// +int _RemoveIntcHandler(int cause, int hid) +{ + if (hid >= 128) return -1; + + if (pgifhandlers_array[hid].flag == 3) return -1; + pgifhandlers_array[hid].flag = 3; + pgifhandlers_array[hid].handler = 0; + + LL_unlinkthis((struct ll*)&pgifhandlers_array[hid]); + _RemoveHandler(hid); + + intcs_array[cause].count--; +} + +//////////////////////////////////////////////////////////////////// +//80001B10 +//////////////////////////////////////////////////////////////////// +int __AddDmacHandler(int cause, int (*handler)(int), int next, void *arg, int flag) +{ + struct IDhandl *idh; + register int temp; + + if (cause >= 16) return -1; + + idh = (struct IDhandl *)_AddHandler(); + if (idh == 0) return -1; + + idh->handler = handler; + __asm__ ("sw $gp, %0\n" : "=m"(idh->gp) : ); + idh->arg = arg; + idh->flag = flag; + + if (next==-1) //register_last + LL_add(&dhandlers_last[cause*12], (struct ll*)idh); + else if (next==0) //register_first + LL_add(&dhandlers_first[cause*12], (struct ll*)idh); + else{ + if (next>128) return -1; + if (pgifhandlers_array[next].flag==3) return -1; + LL_add((struct ll*)&pgifhandlers_array[next], (struct ll*)idh); + } + + dmacs_array[cause].count++; + return (((u32)idh-(u32)&pgifhandlers_array) * 0xAAAAAAAB) / 8; +} + +//////////////////////////////////////////////////////////////////// +//80001C78 SYSCALL 018 AddDmacHandler +//////////////////////////////////////////////////////////////////// +int _AddDmacHandler(int cause, int (*handler)(int), int next, void *arg) +{ + __AddDmacHandler(cause, handler, next, arg, 2); +} + +//////////////////////////////////////////////////////////////////// +//80001C98 +//////////////////////////////////////////////////////////////////// +int _AddDmacHandler2(int cause, int (*handler)(int), int next, void *arg) +{ + __AddDmacHandler(cause, handler, next, arg, 0); +} + +//////////////////////////////////////////////////////////////////// +//80001CB8 SYSCALL 019 RemoveDmacHandler +//////////////////////////////////////////////////////////////////// +int _RemoveDmacHandler(int cause, int hid) +{ + if (hid >= 128) return -1; + + if (pgifhandlers_array[hid].flag == 3) return -1; + pgifhandlers_array[hid].flag = 3; + pgifhandlers_array[hid].handler = 0; + + LL_unlinkthis((struct ll*)&pgifhandlers_array[hid]); + _RemoveHandler(hid); + + dmacs_array[cause].count--; +} + +//////////////////////////////////////////////////////////////////// +//80001D58 +//////////////////////////////////////////////////////////////////// +void sbusHandler() +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80001E38 +//////////////////////////////////////////////////////////////////// +int __AddSbusIntcHandler(int cause, void (*handler)(int ca)) +{ + if (cause >= 32) return -1; + + if (sbus_handlers[cause] != 0) return -1; + + sbus_handlers[cause] = handler; + return cause; +} + +//////////////////////////////////////////////////////////////////// +//80001E78 SYSCALL 010 AddSbusIntcHandler +//////////////////////////////////////////////////////////////////// +int _AddSbusIntcHandler(int cause, void (*handler)(int ca)) +{ + if (cause < 16) return __AddSbusIntcHandler(cause, handler); + + return -1; +} + +//////////////////////////////////////////////////////////////////// +//80001EA8 +//////////////////////////////////////////////////////////////////// +int __RemoveSbusIntcHandler(int cause) +{ + if (cause >= 32) return -1; + + sbus_handlers[cause] = 0; + return cause; +} + +//////////////////////////////////////////////////////////////////// +//80001ED0 SYSCALL 011 RemoveSbusIntcHandler +//////////////////////////////////////////////////////////////////// +int _RemoveSbusIntcHandler(int cause) +{ + if (cause < 16) return __RemoveSbusIntcHandler(cause); + + return -1; +} + +//////////////////////////////////////////////////////////////////// +//80001F00 +//////////////////////////////////////////////////////////////////// +int __Interrupt2Iop(int cause) +{ + if (cause >= 32) { + return -1; + } + + SBUS_MSFLG = 1 << cause; + + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; + SBUS_F240 = 0x100; // eight times + + SBUS_F240 = 0x40100; + + return cause; +} + +//////////////////////////////////////////////////////////////////// +//80001F70 SYSCALL 012 Interrupt2Iop +//////////////////////////////////////////////////////////////////// +int _Interrupt2Iop(int cause) +{ + if (cause < 16) { + return _Interrupt2Iop(cause); + } else { + return -1; + } +} + +//////////////////////////////////////////////////////////////////// +//80001FA0 SYSCALL 092 EnableIntcHandler +//////////////////////////////////////////////////////////////////// +void _EnableIntcHandler(u32 id) +{ + pgifhandlers_array[id].flag = 2; +} + +//////////////////////////////////////////////////////////////////// +//80001FA0 SYSCALL 093 DisableIntcHandler +//////////////////////////////////////////////////////////////////// +void _DisableIntcHandler(u32 id) +{ + pgifhandlers_array[id].flag = 1; +} + +//////////////////////////////////////////////////////////////////// +//80001FA0 SYSCALL 094 EnableDmacHandler +//////////////////////////////////////////////////////////////////// +void _EnableDmacHandler(u32 id) +{ + pgifhandlers_array[id].flag = 2; +} + +//////////////////////////////////////////////////////////////////// +//80001FA0 SYSCALL 095 DisableDmacHandler +//////////////////////////////////////////////////////////////////// +void _DisableDmacHandler(u32 id) +{ + pgifhandlers_array[id].flag = 1; +} + +//////////////////////////////////////////////////////////////////// +//80002040 SYSCALL 083 iSetEventFlag +//////////////////////////////////////////////////////////////////// +int _iSetEventFlag(int ef, u32 bits) +{ + return _HandlersCount; //? +} + +//////////////////////////////////////////////////////////////////// +//800022D8 SYSCALL 24,30 +//////////////////////////////////////////////////////////////////// +int _SetAlarm(short a0, int a1, int a2) +{ + int mode = _alarm_unk & 0x1; + int i; + + i = 0; + while (mode) { + mode = (_alarm_unk >> i++) & 0x1; + if (i >= 64) { + return -1; + } + } + + _alarm_unk|= mode << i; + + __asm__("move %0, $gp\n" : "=r"(rcnt3TargetTable[0]) : ); + dword_80016A78 = a1; + dword_80016A7C = a2; + rcnt3TargetTable[1] = RCNT3_MODE; + i = RCNT3_MODE + a0; + if (i < -1) + i&= 0xffff; + dword_80016A88 = i; + + if (RCNT3_MODE < i) { + if (rcnt3Count <= 0) { + + } + } +} + +//////////////////////////////////////////////////////////////////// +//80002570 SYSCALL 25,31 ReleaseAlarm +//////////////////////////////////////////////////////////////////// +void _ReleaseAlarm() +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80002650 +//////////////////////////////////////////////////////////////////// +void rcnt3Handler() +{ + unsigned int i; + u32* ptr; + u32 storegp; + u32 addr; + + if (rcnt3Count < 2) { + RCNT3_MODE = 0x483; + } else { + RCNT3_MODE = 0x583; + RCNT3_TARGET = rcnt3TargetTable[2+rcnt3TargetNum[1] * 5]; + } + + for (;;) { + u32 id = (u32)rcnt3TargetNum[0]; + if (--rcnt3Count >= 0) { + // shift one down + for (i=0; i= 0) { + if (addr != rcnt3TargetTable[rcnt3TargetNum[0] * 5 + 2]) { + break; + } + } else break; + } +} + +//////////////////////////////////////////////////////////////////// +//800027F8 SYSCALL 082 SetEventFlag +//////////////////////////////////////////////////////////////////// +int _SetEventFlag(int ef, u32 bits) +{ + return rcnt3Count; //? +} + +//////////////////////////////////////////////////////////////////// +//800027F8 +//////////////////////////////////////////////////////////////////// +void _InitRCNT3() +{ + int i; + + rcnt3Count = 0; + rcnt3Valid = 0; + _alarm_unk = 0; + for (i=0; i<0x40; i++) rcnt3TargetNum[i] = 0; + + __EnableIntc(INTC_TIM3); +} + +//////////////////////////////////////////////////////////////////// +//80002840 +//////////////////////////////////////////////////////////////////// +void _excepRet(u32 eretpc, u32 v1, u32 a, u32 a1, u32 a2) +{ + __asm__("sw $31, %0\n" + "sw $sp, %1\n" + : "=m"(excepRA), "=m"(excepSP) : ); + __asm__("mtc0 $4, $14\n" + "sync\n" + "daddu $3, $5, $0\n" + "daddu $4, $6, $0\n" + "daddu $5, $7, $0\n" + "daddu $6, $8, $0\n" + "mfc0 $26, $12\n" + "ori $26, 0x12\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + "nop\n"); +} + +//////////////////////////////////////////////////////////////////// +//80002880 SYSCALL 005 RFU005 +//////////////////////////////////////////////////////////////////// +void _RFU005() +{ + __asm__ ( + ".set noat\n" + + "mfc0 $26, $12\n" + "ori $1, $0, 0xFFE4\n" + "and $26, $1\n" + "mtc0 $26, $12\n" + "sync\n" + + "lw $ra, excepRA\n" + "lw $sp, excepSP\n" + "jr $ra\n" + "nop\n" + + ".set at\n"); +} + +//////////////////////////////////////////////////////////////////// +//A00028C0 SYSCALL 097 EnableCache +//////////////////////////////////////////////////////////////////// +int _EnableCache(int cache) +{ + u32 cfg; + __asm__("mfc0 %0, $16\n" : "=r"(cfg) : ); + cfg |= ((cache&3)<<16); + __asm__("mtc0 %0, $16\n" + "sync\n" : : "r"(cfg) ); +} + +//////////////////////////////////////////////////////////////////// +//A0002980 SYSCALL 098 DisableCache +//////////////////////////////////////////////////////////////////// +int _DisableCache(int cache) +{ + u32 cfg; + __asm__("mfc0 %0, $16\n" : "=r"(cfg) : ); + cfg &= ~((cache&3)<<16); + __asm__("mtc0 %0, $16\n" + "sync\n" : : "r"(cfg) ); +} + +//////////////////////////////////////////////////////////////////// +//A0002A40 SYSCALL 100 FlushCache +//////////////////////////////////////////////////////////////////// +void _FlushCache(int op) +{ + if( op == 0 ) FlushInstructionCache(); + else if ( op == 1 ) FlushSecondaryCache(); + else if( op == 2 ) FlushDataCache(); + else { + FlushSecondaryCache(); + FlushDataCache(); + } +} + +//////////////////////////////////////////////////////////////////// +//80002AC0 +//////////////////////////////////////////////////////////////////// +void FlushInstructionCache() +{ +} + +//////////////////////////////////////////////////////////////////// +//80002A80 +//////////////////////////////////////////////////////////////////// +void FlushDataCache() +{ +} + +//////////////////////////////////////////////////////////////////// +//80002B00 +//////////////////////////////////////////////////////////////////// +void FlushSecondaryCache() +{ +} + +//////////////////////////////////////////////////////////////////// +//A0002B40 SYSCALL 101,105 _105 +//////////////////////////////////////////////////////////////////// +void _105(int op1, int op2) +{ + // flushing caches again +} + +//////////////////////////////////////////////////////////////////// +//A0002C00 SYSCALL 096 KSeg0 +//////////////////////////////////////////////////////////////////// +void _KSeg0(u32 arg) +{ + u32 cfg; + __asm__("mfc0 %0, $16\n" : "=r"(cfg) : ); + cfg = (arg&3)&((cfg>>3)<<3); // yes it is 0, don't ask + __asm__("mtc0 %0, $16\n" + "sync\n" : : "r"(cfg) ); +} + +//////////////////////////////////////////////////////////////////// +//80002C40 SYSCALL 099 GetCop0 +//////////////////////////////////////////////////////////////////// +int _GetCop0(int reg) +{ + return table_GetCop0[reg](reg); +} + +//////////////////////////////////////////////////////////////////// +//80002C58-80002D50 calls for table_GetCop0 +//////////////////////////////////////////////////////////////////// +int GetCop0_Index(int reg) { __asm__(" mfc0 $2, $0\n"); } +int GetCop0_Random(int reg) { __asm__(" mfc0 $2, $1\n"); } +int GetCop0_EntryLo0(int reg) { __asm__(" mfc0 $2, $2\n"); } +int GetCop0_EntryLo1(int reg) { __asm__(" mfc0 $2, $3\n"); } + +int GetCop0_Context(int reg) { __asm__(" mfc0 $2, $4\n"); } +int GetCop0_PageMask(int reg) { __asm__(" mfc0 $2, $5\n"); } +int GetCop0_Wired(int reg) { __asm__(" mfc0 $2, $6\n"); } +int GetCop0_Reg7(int reg) { return; } + +int GetCop0_BadVAddr(int reg) { __asm__(" mfc0 $2, $8\n"); } +int GetCop0_Count(int reg) { __asm__(" mfc0 $2, $9\n"); } +int GetCop0_EntryHi(int reg) { __asm__(" mfc0 $2, $10\n"); } +int GetCop0_Compare(int reg) { __asm__(" mfc0 $2, $11\n"); } + +int GetCop0_Status(int reg) { __asm__(" mfc0 $2, $12\n"); } +int GetCop0_Cause(int reg) { __asm__(" mfc0 $2, $13\n"); } +int GetCop0_ExceptPC(int reg) { __asm__(" mfc0 $2, $14\n"); } +int GetCop0_PRevID(int reg) { __asm__(" mfc0 $2, $15\n"); } + +int GetCop0_Config(int reg) { __asm__(" mfc0 $2, $16\n"); } +int GetCop0_Reg17(int reg) { return; } +int GetCop0_Reg18(int reg) { return; } +int GetCop0_Reg19(int reg) { return; } + +int GetCop0_Reg20(int reg) { return; } +int GetCop0_Reg21(int reg) { return; } +int GetCop0_Reg22(int reg) { return; } +int GetCop0_Reg23(int reg) { __asm__(" mfc0 $2, $23\n"); } + +int GetCop0_DebugReg24(int reg) { __asm__(" mfc0 $2, $24\n"); } +int GetCop0_Perf(int reg) { __asm__(" mfc0 $2, $25\n"); } +int GetCop0_Reg26(int reg) { return; } +int GetCop0_Reg27(int reg) { return; } + +int GetCop0_TagLo(int reg) { __asm__(" mfc0 $2, $28\n"); } +int GetCop0_TagHi(int reg) { __asm__(" mfc0 $2, $29\n"); } +int GetCop0_ErrorPC(int reg) { __asm__(" mfc0 $2, $30\n"); } +int GetCop0_Reg31(int reg) { return; } + +int (*table_GetCop0[32])(int reg) = { // 800124E8 + GetCop0_Index, GetCop0_Random, GetCop0_EntryLo0, GetCop0_EntryLo1, + GetCop0_Context, GetCop0_PageMask, GetCop0_Wired, GetCop0_Reg7, + GetCop0_BadVAddr, GetCop0_Count, GetCop0_EntryHi, GetCop0_Compare, + GetCop0_Status, GetCop0_Cause, GetCop0_ExceptPC, GetCop0_PRevID, + GetCop0_Config, GetCop0_Reg17, GetCop0_Reg18, GetCop0_Reg19, + GetCop0_Reg20, GetCop0_Reg21, GetCop0_Reg22, GetCop0_Reg23, + GetCop0_DebugReg24, GetCop0_Perf, GetCop0_Reg26, GetCop0_Reg27, + GetCop0_TagLo, GetCop0_TagHi, GetCop0_ErrorPC, GetCop0_Reg31 +}; + +//////////////////////////////////////////////////////////////////// +//80002D80 +//////////////////////////////////////////////////////////////////// +int SetCop0(int reg, int val) +{ + return table_SetCop0[reg](reg, val); +} + +//////////////////////////////////////////////////////////////////// +//80002D98-80002F74 calls for table_SetCop0 +//////////////////////////////////////////////////////////////////// +int SetCop0_Index(int reg, int val) { __asm__(" mfc0 $2, $0\nmtc0 %0, $0\nsync\n" : : "r"(val)); } +int SetCop0_Random(int reg, int val) { return -1; } +int SetCop0_EntryLo0(int reg, int val) { __asm__(" mfc0 $2, $2\nmtc0 %0, $2\nsync\n" : : "r"(val)); } +int SetCop0_EntryLo1(int reg, int val) { __asm__(" mfc0 $2, $3\nmtc0 %0, $3\nsync\n" : : "r"(val)); } + +int SetCop0_Context(int reg, int val) { __asm__(" mfc0 $2, $4\nmtc0 %0, $4\nsync\n" : : "r"(val)); } +int SetCop0_PageMask(int reg, int val) { __asm__(" mfc0 $2, $5\nmtc0 %0, $5\nsync\n" : : "r"(val)); } +int SetCop0_Wired(int reg, int val) { __asm__(" mfc0 $2, $6\nmtc0 %0, $6\nsync\n" : : "r"(val)); } +int SetCop0_Reg7(int reg, int val) { return -1; } + +int SetCop0_BadVAddr(int reg, int val) { return -1; } +int SetCop0_Count(int reg, int val) { __asm__(" mfc0 $2, $9\nmtc0 %0, $9\nsync\n" : : "r"(val)); } +int SetCop0_EntryHi(int reg, int val) { __asm__(" mfc0 $2, $10\nmtc0 %0, $10\nsync\n" : : "r"(val)); } +int SetCop0_Compare(int reg, int val) { __asm__(" mfc0 $2, $11\nmtc0 %0, $11\nsync\n" : : "r"(val)); } + +int SetCop0_Status(int reg, int val) { __asm__(" mfc0 $2, $12\nmtc0 %0, $12\nsync\n" : : "r"(val)); } +int SetCop0_Cause(int reg, int val) { return -1; } +int SetCop0_ExceptPC(int reg, int val) { __asm__(" mfc0 $2, $14\nmtc0 %0, $14\nsync\n" : : "r"(val)); } +int SetCop0_PRevID(int reg, int val) { return -1; } + +int SetCop0_Config(int reg, int val) { __asm__(" mfc0 $2, $16\nmtc0 %0, $16\nsync\n" : : "r"(val)); } +int SetCop0_Reg17(int reg, int val) { return -1; } +int SetCop0_Reg18(int reg, int val) { return -1; } +int SetCop0_Reg19(int reg, int val) { return -1; } + +int SetCop0_Reg20(int reg, int val) { return -1; } +int SetCop0_Reg21(int reg, int val) { return -1; } +int SetCop0_Reg22(int reg, int val) { return -1; } +int SetCop0_Reg23(int reg, int val) { __asm__(" mfc0 $2, $23\nmtc0 %0, $23\nsync\n" : : "r"(val)); } + +int SetCop0_DebugReg24(int reg, int val){ __asm__(" mfc0 $2, $24\nmtc0 %0, $24\nsync\n" : : "r"(val)); } +int SetCop0_Perf(int reg, int val) { __asm__(" mfc0 $2, $25\nmtc0 %0, $25\nsync\n" : : "r"(val)); } +int SetCop0_Reg26(int reg, int val) { return -1; } +int SetCop0_Reg27(int reg, int val) { return -1; } + +int SetCop0_TagLo(int reg, int val) { __asm__(" mfc0 $2, $28\nmtc0 %0, $28\nsync\n" : : "r"(val)); } +int SetCop0_TagHi(int reg, int val) { __asm__(" mfc0 $2, $29\nmtc0 %0, $29\nsync\n" : : "r"(val)); } +int SetCop0_ErrorPC(int reg, int val) { __asm__(" mfc0 $2, $30\nmtc0 %0, $30\nsync\n" : : "r"(val)); } +int SetCop0_Reg31(int reg, int val) { return -1; } + +int (*table_SetCop0[32])(int reg, int val) = { // 80012568 + SetCop0_Index, SetCop0_Random, SetCop0_EntryLo0, SetCop0_EntryLo1, + SetCop0_Context, SetCop0_PageMask, SetCop0_Wired, SetCop0_Reg7, + SetCop0_BadVAddr, SetCop0_Count, SetCop0_EntryHi, SetCop0_Compare, + SetCop0_Status, SetCop0_Cause, SetCop0_ExceptPC, SetCop0_PRevID, + SetCop0_Config, SetCop0_Reg17, SetCop0_Reg18, SetCop0_Reg19, + SetCop0_Reg20, SetCop0_Reg21, SetCop0_Reg22, SetCop0_Reg23, + SetCop0_DebugReg24, SetCop0_Perf, SetCop0_Reg26, SetCop0_Reg27, + SetCop0_TagLo, SetCop0_TagHi, SetCop0_ErrorPC, SetCop0_Reg31 +}; + +//////////////////////////////////////////////////////////////////// +//80002F80 SYSCALL 007 ExecPS2 +//////////////////////////////////////////////////////////////////// +int _ExecPS2(void * entry, void * gp, int argc, char ** argv) +{ + saveContext(); + __ExecPS2(entry, gp, argc, argv); + __asm__("mtc0 $2, $14\n" + "move $sp, %0\n" + "sd $2, 0x20($sp)\n" + : : "r"(SavedSP)); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80002FC0 SYSCALL 033 DeleteThread +//////////////////////////////////////////////////////////////////// +int _DeleteThread(int tid) +{ + register int ret __asm__("$2"); + register u32 curepc __asm__("$4"); + + saveContext(); + + ret = __DeleteThread(tid); + if (ret < 0) { + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + // make sure the return value is also stored + __asm__("sd $2, 0x20($sp)\n"); + + restoreContext(); + eret(); + } + + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); // EPC + _ThreadHandler(curepc, SavedSP); // returns entry in $3, stack in $4 + + __asm__("mtc0 $2, $14\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003040 SYSCALL 034 StartThread +//////////////////////////////////////////////////////////////////// +int _StartThread(int tid, void *arg) +{ + register int ret __asm__("$2"); + register u32 curepc __asm__("$4"); + + saveContext(); + + ret = __StartThread(tid, arg); + + if (ret < 0) { + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + // make sure the return value is also stored + __asm__("sd $2, 0x20($sp)\n"); + + restoreContext(); + eret(); + } + + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); // EPC + _ThreadHandler(curepc, SavedSP); // returns entry in $3, stack in $4 + + __asm__("mtc0 $2, $14\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800030C0 SYSCALL 035 ExitThread +//////////////////////////////////////////////////////////////////// +int _ExitThread() +{ + saveContext(); + + __ExitThread(); + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003100 SYSCALL 036 ExitDeleteThread +//////////////////////////////////////////////////////////////////// +int _ExitDeleteThread() +{ + saveContext(); + + __ExitDeleteThread(); + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003140 SYSCALL 037 TerminateThread +//////////////////////////////////////////////////////////////////// +int _TerminateThread(int tid) +{ + register int ret __asm__("$2"); + register u32 curepc __asm__("$4"); + + saveContext(); + + ret = _iTerminateThread(tid); + + if( ret < 0 ) { + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + // make sure the return value is also stored + __asm__("sd $2, 0x20($sp)\n"); + + restoreContext(); + eret(); + } + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); // EPC + _ThreadHandler(curepc, SavedSP); // returns entry in $3, stack in $4 + + __asm__("mtc0 $2, $14\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800031C0 SYSCALL 043 RotateThreadReadyQueue +//////////////////////////////////////////////////////////////////// +void _RotateThreadReadyQueue(int pri) +{ + register int ret __asm__("$2"); + register u32 curepc __asm__("$4"); + + ret = pri; + saveContext(); + + ret = _iRotateThreadReadyQueue(pri); + + if( ret < 0 ) { + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + // make sure the return value is also stored + __asm__("sd $2, 0x20($sp)\n"); + + restoreContext(); + eret(); + } + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); // EPC + _ThreadHandler(curepc, SavedSP); // returns entry in $3, stack in $4 + + __asm__("mtc0 $2, $14\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003240 SYSCALL 045 ReleaseWaitThread +//////////////////////////////////////////////////////////////////// +void _ReleaseWaitThread(int tid) +{ + register int ret __asm__("$2"); + register u32 curepc __asm__("$4"); + + ret = tid; + saveContext(); + + ret = _iReleaseWaitThread(tid); + + if( ret < 0 ) { + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + // make sure the return value is also stored + __asm__("sd $2, 0x20($sp)\n"); + + restoreContext(); + eret(); + } + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); // EPC + _ThreadHandler(curepc, SavedSP); // returns entry in $3, stack in $4 + + __asm__("mtc0 $2, $14\n" + "move $sp, $3\n"); + + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800032C0 SYSCALL 052 SleepThread +//////////////////////////////////////////////////////////////////// +int _SleepThread() +{ + register int ret __asm__("$2"); + + ret = threadId; + saveContext(); + + ret = __SleepThread(); + if (ret < 0) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ChangeThread(curepc, SavedSP, 1); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003340 SYSCALL 051 WakeupThread +//////////////////////////////////////////////////////////////////// +int _WakeupThread(int tid) +{ + register int ret __asm__("$2"); + + ret = tid; + saveContext(); + + ret = iWakeupThread(tid); + if( ret >= 0 ) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800033C0 SYSCALL 057 ResumeThread +//////////////////////////////////////////////////////////////////// +int _ResumeThread(int tid) +{ + register int ret __asm__("$2"); + + ret = tid; + saveContext(); + + ret = _iResumeThread(tid); + if( ret >= 0 ) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003440 SYSCALL 068 WaitSema +//////////////////////////////////////////////////////////////////// +int _WaitSema(int sid) +{ + register int ret __asm__("$2"); + + ret = sid; + saveContext(); + + ret = _iWaitSema(sid); + if( ret == 0xFFFFFFFE ) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ChangeThread(curepc, SavedSP, 2); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" : : "m"(SavedSP)); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800034C0 SYSCALL 066 SignalSema +//////////////////////////////////////////////////////////////////// +void _SignalSema(int sid) +{ + register int ret __asm__("$2"); + + ret = sid; + saveContext(); + + ret = _iSignalSema(sid); + if( ret >= 0 ) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003540 SYSCALL 065 DeleteSema +//////////////////////////////////////////////////////////////////// +int _DeleteSema(int sid) +{ + register int ret __asm__("$2"); + + ret = sid; + saveContext(); + + ret = _iDeleteSema(sid); + if( ret >= 0 ) { + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//800035C0 SYSCALL 041 ChangeThreadPriority +//return has to be void (even though it fills in v0) +//////////////////////////////////////////////////////////////////// +void _ChangeThreadPriority(int tid, int prio) +{ + register int ret __asm__("$2"); + + saveContext(); + ret = _iChangeThreadPriority(tid, prio); + + __asm__("lw $26, %0\n" + "sd %1, 0x20($26)\n" : : "m"(SavedSP), "r"(ret) ); + + if (ret>=0){ + register int curepc __asm__("$4"); + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); + } + + // why twice? + __asm__("lw $sp, %0\n" + "sd %1, 0x20($sp)\n" : : "m"(SavedSP), "r"(ret) ); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//8000363C +//////////////////////////////////////////////////////////////////// +void __ThreadHandler() +{ + register int curepc __asm__("$4"); + + saveContext(); + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + _ThreadHandler(curepc, SavedSP); + __asm__("mtc0 $2, $14\n" + "sync\n" + "move $sp, $3\n"); + restoreContext(); + eret(); +} + +//////////////////////////////////////////////////////////////////// +//80003680 +//////////////////////////////////////////////////////////////////// +void saveContext() +{ + __asm__ ( + "lui $26, %hi(SavedSP)\n" + "lq $26, %lo(SavedSP)($26)\n" + ); + __asm__ ( + "addiu $26, %0\n" + : : "i"(-sizeof(struct threadCtx)) + ); + __asm__ ( + ".set noat\n" + "lui $1, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($1)\n" + "sq $1, 0x000($26)\n" + "sq $2, 0x010($26)\n" + "sq $3, 0x020($26)\n" + "sq $4, 0x030($26)\n" + "sq $5, 0x040($26)\n" + "sq $6, 0x050($26)\n" + "sq $7, 0x060($26)\n" + "sq $8, 0x070($26)\n" + "sq $9, 0x080($26)\n" + "sq $10, 0x090($26)\n" + "sq $11, 0x0A0($26)\n" + "sq $12, 0x0B0($26)\n" + "sq $13, 0x0C0($26)\n" + "sq $14, 0x0D0($26)\n" + "sq $15, 0x0E0($26)\n" + "sq $16, 0x0F0($26)\n" + "sq $17, 0x100($26)\n" + "sq $18, 0x110($26)\n" + "sq $19, 0x120($26)\n" + "sq $20, 0x130($26)\n" + "sq $21, 0x140($26)\n" + "sq $22, 0x150($26)\n" + "sq $23, 0x160($26)\n" + "sq $24, 0x170($26)\n" + "sq $25, 0x180($26)\n" + "sq $gp, 0x190($26)\n" + "lui $1, %hi(SavedSP)\n" + "lq $sp, %lo(SavedSP)($1)\n" + "sq $sp, 0x1A0($26)\n" + "sq $fp, 0x1B0($26)\n" + "lui $1, %hi(SavedRA)\n" + "lq $1, %lo(SavedRA)($1)\n" + "sq $1, 0x1C0($26)\n" + + "swc1 $0, 0x200($26)\n" + "swc1 $1, 0x204($26)\n" + "swc1 $2, 0x208($26)\n" + "swc1 $3, 0x20C($26)\n" + "swc1 $4, 0x210($26)\n" + "swc1 $5, 0x214($26)\n" + "swc1 $6, 0x218($26)\n" + "swc1 $7, 0x21C($26)\n" + "swc1 $8, 0x220($26)\n" + "swc1 $9, 0x224($26)\n" + "swc1 $10, 0x228($26)\n" + "swc1 $11, 0x22C($26)\n" + "swc1 $12, 0x230($26)\n" + "swc1 $13, 0x234($26)\n" + "swc1 $14, 0x238($26)\n" + "swc1 $15, 0x23C($26)\n" + "swc1 $16, 0x240($26)\n" + "swc1 $17, 0x244($26)\n" + "swc1 $18, 0x248($26)\n" + "swc1 $19, 0x24C($26)\n" + "swc1 $20, 0x250($26)\n" + "swc1 $21, 0x254($26)\n" + "swc1 $22, 0x258($26)\n" + "swc1 $23, 0x25C($26)\n" + "swc1 $24, 0x260($26)\n" + "swc1 $25, 0x264($26)\n" + "swc1 $26, 0x268($26)\n" + "swc1 $27, 0x26C($26)\n" + "swc1 $28, 0x270($26)\n" + "swc1 $29, 0x274($26)\n" + "swc1 $30, 0x278($26)\n" + "swc1 $31, 0x27C($26)\n" + + "mfsa $1\n" + "sw $1, 0x1F0($26)\n" + + "cfc1 $1, $31\n" + "sw $1, 0x1F4($26)\n" + + "lui $1, 0x8000\n" + "mtc1 $1, $1\n" + "mtc1 $1, $0\n" + "madd.s $f0, $f0, $f1\n" + "swc1 $0, 0x1F8($26)\n" + + "mfhi $1\n" + "sd $1, 0x1D0($26)\n" + "mfhi1 $1\n" + "sd $1, 0x1D8($26)\n" + + "mflo $1\n" + "sd $1, 0x1E0($26)\n" + "mflo1 $1\n" + "sd $1, 0x1E8($26)\n" + + "lui $1, %hi(SavedSP)\n" + "sw $26, %lo(SavedSP)($1)\n" + + "jr $31\n" + "lui $1, 0x8000\n" + ".set at\n" + ); +} + +//////////////////////////////////////////////////////////////////// +//80003800 +//////////////////////////////////////////////////////////////////// +void restoreContext() +{ + __asm__ ( + ".set noat\n" + + "lui $26, 0x8000\n" + "mtc1 $26, $1\n" + "lwc1 $0, 0x1F8($sp)\n" + "adda.s $f0, $f1\n" + + "lw $26, 0x1F0($sp)\n" + "mtsa $26\n" + + "lw $26, 0x1F4($sp)\n" + "ctc1 $26, $31\n" + + "ld $26, 0x1D0($sp)\n" + "mthi $26\n" + "ld $26, 0x1D8($sp)\n" + "mthi1 $26\n" + + "ld $26, 0x1E0($sp)\n" + "mtlo $26\n" + "ld $26, 0x1E8($sp)\n" + "mtlo1 $26\n" + + "lq $1, 0x000($sp)\n" + "lq $2, 0x010($sp)\n" + "lq $3, 0x020($sp)\n" + "lq $4, 0x030($sp)\n" + "lq $5, 0x040($sp)\n" + "lq $6, 0x050($sp)\n" + "lq $7, 0x060($sp)\n" + "lq $8, 0x070($sp)\n" + "lq $9, 0x080($sp)\n" + "lq $10, 0x090($sp)\n" + "lq $11, 0x0A0($sp)\n" + "lq $12, 0x0B0($sp)\n" + "lq $13, 0x0C0($sp)\n" + "lq $14, 0x0D0($sp)\n" + "lq $15, 0x0E0($sp)\n" + "lq $16, 0x0F0($sp)\n" + "lq $17, 0x100($sp)\n" + "lq $18, 0x110($sp)\n" + "lq $19, 0x120($sp)\n" + "lq $20, 0x130($sp)\n" + "lq $21, 0x140($sp)\n" + "lq $22, 0x150($sp)\n" + "lq $23, 0x160($sp)\n" + "lq $24, 0x170($sp)\n" + "lq $25, 0x180($sp)\n" + "lq $gp, 0x190($sp)\n" + "lq $fp, 0x1B0($sp)\n" + + "lwc1 $0, 0x200($sp)\n" + "lwc1 $1, 0x204($sp)\n" + "lwc1 $2, 0x208($sp)\n" + "lwc1 $3, 0x20C($sp)\n" + "lwc1 $4, 0x210($sp)\n" + "lwc1 $5, 0x214($sp)\n" + "lwc1 $6, 0x218($sp)\n" + "lwc1 $7, 0x21C($sp)\n" + "lwc1 $8, 0x220($sp)\n" + "lwc1 $9, 0x224($sp)\n" + "lwc1 $10, 0x228($sp)\n" + "lwc1 $11, 0x22C($sp)\n" + "lwc1 $12, 0x230($sp)\n" + "lwc1 $13, 0x234($sp)\n" + "lwc1 $14, 0x238($sp)\n" + "lwc1 $15, 0x23C($sp)\n" + "lwc1 $16, 0x240($sp)\n" + "lwc1 $17, 0x244($sp)\n" + "lwc1 $18, 0x248($sp)\n" + "lwc1 $19, 0x24C($sp)\n" + "lwc1 $20, 0x250($sp)\n" + "lwc1 $21, 0x254($sp)\n" + "lwc1 $22, 0x258($sp)\n" + "lwc1 $23, 0x25C($sp)\n" + "lwc1 $24, 0x260($sp)\n" + "lwc1 $25, 0x264($sp)\n" + "lwc1 $26, 0x268($sp)\n" + "lwc1 $27, 0x26C($sp)\n" + "lwc1 $28, 0x270($sp)\n" + "lwc1 $29, 0x274($sp)\n" + "lwc1 $30, 0x278($sp)\n" + "lwc1 $31, 0x27C($sp)\n" + "daddu $26, $31, $0\n" + "lq $31, 0x1C0($sp)\n" + "jr $26\n" + "lq $sp, 0x1A0($sp)\n" + ".set at\n" + ); +} + +//////////////////////////////////////////////////////////////////// +//80003940 +//////////////////////////////////////////////////////////////////// +void _ThreadHandler(u32 epc, u32 stack) +{ + register int tid; + + threads_array[threadId].entry =(void*)epc; + threads_array[threadId].status =THS_READY; + threads_array[threadId].stack_res =(void*)stack; + + for ( ; threadPrio < 129; threadPrio++) + if ((thread_ll_priorities[threadPrio].next != + &thread_ll_priorities[threadPrio]) || + (thread_ll_priorities[threadPrio].prev != + &thread_ll_priorities[threadPrio])){ + tid=threadId=(( (u32)thread_ll_priorities[threadPrio].prev - + (u32)threads_array)*0x286BCA1B)>>2; + break; + } + + if (threadPrio>=129){ + __printf("# No active threads\n"); + Exit(1); + tid=0; + } + + threads_array[tid].status=THS_RUN; + + if (threads_array[tid].waitSema){ + threads_array[tid].waitSema=0; + *(u32*)((u32)threads_array[tid].stack_res + 0x20) = -1; + } + + __asm__("move $2, %0\n" + "move $3, %1\n" + : : "r"(threads_array[tid].entry), "r"(threads_array[tid].stack_res) ); +} + +//////////////////////////////////////////////////////////////////// +//80003A78 +//////////////////////////////////////////////////////////////////// +void _ChangeThread(u32 entry, u32 stack_res, int waitSema) +{ + struct TCB *th; + struct ll *l, *p; + int prio; + + th = &threads_array[threadId]; + th->status = THS_WAIT; + th->waitSema = waitSema; + th->entry = (void (*)(void*))entry; + th->stack_res = (void*)stack_res; + + prio = threadPrio; + for (l = &thread_ll_priorities[prio]; ; l++, prio++) { + if (prio >= 129) { + __printf("# No active threads\n"); + Exit(1); l = 0; break; + } + + if (l->next != l) { p = l->next; break; } + if (l->prev == l) continue; + p = l->prev; break; + } + + if (l) { + threadPrio = prio; + threadId = (((u32)p - (u32)threads_array) * 0x286BCA1B) / 4; + } + + th = &threads_array[threadId]; + th->status = THS_RUN; + if (th->waitSema) { + th->waitSema = 0; + *(s64*)((u32)th->stack_res+0x20) = -1; + } + + __asm__("move $2, %0\n" + "move $3, %1\n" + : : "r"(th->entry), "r"(th->stack_res) ); +} + +//////////////////////////////////////////////////////////////////// +//80003C50 SYSCALL 032 CreateThread +//////////////////////////////////////////////////////////////////// +int _CreateThread(struct ThreadParam *param) +{ + struct TCB *th; + struct threadCtx *thctx; + int index; + int *ptr; + + th = (struct TCB *)LL_unlink((struct ll*)&thread_ll_free); + if (th == NULL) { + __printf("%s: failed to get free thread\n", __FUNCTION__); + return -1; + } + + threads_count++; + index=(((u32)th-(u32)threads_array) * 0x286BCA1B)/4; + + th->entry = param->entry; + th->stack_res = param->stack + param->stackSize - STACK_RES; + th->status = THS_DORMANT; + th->gpReg = param->gpReg; + th->initPriority = param->initPriority; + th->argstring = 0; + th->wakeupCount = 0; + th->semaId = 0; + th->stack = param->stack; + th->argc = 0; + th->entry_ = param->entry; + th->heap_base = threads_array[threadId].heap_base; + th->stackSize = param->stackSize; + th->currentPriority = param->initPriority; + th->waitSema = 0; + th->root = threads_array[threadId].root; + + thctx = th->stack_res; + thctx->gp = (u32)param->gpReg; + thctx->sp = (u32)&thctx[1]; + thctx->fp = (u32)&thctx[1]; + thctx->ra = (u32)threads_array[threadId].root; + + return index; +} + +//////////////////////////////////////////////////////////////////// +//80003E00 SYSCALL 37 iTerminateThread +//////////////////////////////////////////////////////////////////// +int _iTerminateThread(int tid) +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80003F00 +//////////////////////////////////////////////////////////////////// +int __DeleteThread(int tid) +{ + if ((tid>=256) || (tid==threadId) || (threads_array[tid].status!=THS_DORMANT)) + return -1; + + releaseTCB(tid); + return tid; +} + +//////////////////////////////////////////////////////////////////// +//80003F70 +//////////////////////////////////////////////////////////////////// +int __StartThread(int tid, void *arg) +{ + if ((tid>=256) || (tid==threadId) || (threads_array[tid].status!=THS_DORMANT)) + return -1; + + threads_array[tid].argstring = arg; + ((void**)threads_array[tid].stack_res)[0x10] = arg; //a0 + thread_2_ready(tid); + return tid; +} + +//////////////////////////////////////////////////////////////////// +//80003FF8 +//////////////////////////////////////////////////////////////////// +int __ExitThread() +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80004110 +//////////////////////////////////////////////////////////////////// +int __ExitDeleteThread() +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80004228 SYSCALL 39 DisableDispatchThread +//////////////////////////////////////////////////////////////////// +int _DisableDispatchThread() +{ + __printf("# DisableDispatchThread is not supported in this version\n"); + return threadId; +} + +//////////////////////////////////////////////////////////////////// +//80004258 SYSCALL 40 EnableDispatchThread +//////////////////////////////////////////////////////////////////// +int _EnableDispatchThread() +{ + __printf("# EnableDispatchThread is not supported in this version\n"); + return threadId; +} + +//////////////////////////////////////////////////////////////////// +//80004288 SYSCALL 042 iChangeThreadPriority +//////////////////////////////////////////////////////////////////// +int _iChangeThreadPriority(int tid, int prio) +{ + short oldPrio; + + if ((tid >= 256) || (prio < 0) || (prio >= 128)) return -1; + + if (tid == 0) tid = threadId; + if (threads_array[tid].status == 0) return -1; + if ((0 < (threads_array[tid].status ^ 0x10)) == 0) return -1; + + oldPrio = threads_array[tid].currentPriority; + if ((tid != threadId) && (threads_array[tid].status != THS_READY)) { + threads_array[tid].currentPriority = prio; + return oldPrio; + } + + if (threadPrio < prio) threadStatus = 1; + + unsetTCB(tid); + threads_array[tid].currentPriority = prio; + thread_2_ready(tid); + + return oldPrio; +} + +//////////////////////////////////////////////////////////////////// +//80004388 SYSCALL 044 iRotateThreadReadyQueue +//////////////////////////////////////////////////////////////////// +int _iRotateThreadReadyQueue(int prio) +{ + if (prio >= 128) return -1; + + LL_rotate(&thread_ll_priorities[prio]); + return prio; +} + +//////////////////////////////////////////////////////////////////// +//800043D0 SYSCALL 046 iReleaseWaitThread +//////////////////////////////////////////////////////////////////// +int _iReleaseWaitThread(int tid) +{ + if( (u32)(tid-1) >= 255 ) + return -1; + + if( (u32)threads_array[tid].status >= 17 ) + return tid; + + switch(threads_array[tid].status) { + case 0: + return -1; + case THS_WAIT: { + //443C + if( threads_array[tid].waitSema == 2 ) { + LL_unlinkthis((struct ll*)&threads_array[tid]); + semas_array[threads_array[tid].semaId].wait_threads--; + } + + int threadPrioOld = threadPrio; + threads_array[tid].status = THS_READY; + thread_2_ready(tid); + + if( threadPrio < threadPrioOld ) { + threadStatus = 1; + } + break; + } + case (THS_WAIT|THS_SUSPEND): + threads_array[tid].status = THS_SUSPEND; + if( threads_array[tid].waitSema != 2 ) + return tid; + + LL_unlinkthis((struct ll*)&threads_array[tid]); + semas_array[threads_array[tid].semaId].wait_threads--; + break; + } + + return tid; +} + +//////////////////////////////////////////////////////////////////// +//80004548 SYSCALL 047 GetThreadId +//////////////////////////////////////////////////////////////////// +int _GetThreadId() +{ + return threadId; +} + +//////////////////////////////////////////////////////////////////// +//80004558 SYSCALL 048 ReferThreadStatus +//////////////////////////////////////////////////////////////////// +int _ReferThreadStatus(int tid, struct ThreadParam *info) +{ + if (tid >= 256) return -1; + if (tid == 0) tid = threadId; + + if (info != NULL) { + info->entry = threads_array[tid].entry; + info->status = threads_array[tid].status; + info->stack = threads_array[tid].stack; + info->stackSize = threads_array[tid].stackSize; + info->gpReg = threads_array[tid].gpReg; + info->initPriority = threads_array[tid].initPriority; + info->currentPriority = threads_array[tid].currentPriority; + info->attr = threads_array[tid].attr; + info->waitSema = threads_array[tid].waitSema; + info->option = threads_array[tid].option; + info->waitId = threads_array[tid].semaId; + info->wakeupCount = threads_array[tid].wakeupCount; + } + + return threads_array[tid].status; +} + +//////////////////////////////////////////////////////////////////// +//80004658 +//////////////////////////////////////////////////////////////////// +int __SleepThread() +{ + if (threads_array[threadId].wakeupCount <= 0) { + unsetTCB(threadId); + return -1; + } + + threads_array[threadId].wakeupCount--; + return threadId; +} + +//////////////////////////////////////////////////////////////////// +//800046B0 SYSCALL 052 iWakeupThread +//////////////////////////////////////////////////////////////////// +int _iWakeupThread(int tid) +{ + register int prio; + + if (tid>=256) return -1; + + if (tid==0) tid = threadId; + + switch (threads_array[tid].status){ + case THS_WAIT: + if (threads_array[tid].waitSema=1){ + prio=threadPrio; + thread_2_ready(tid); + if (threadPrio=256) return -1; + tid = tid ? tid : threadId; + ret=threads_array[tid].wakeupCount; + threads_array[tid].wakeupCount=0; + return ret; +} + +//////////////////////////////////////////////////////////////////// +//800049B0 SYSCALL 080 RFU080_CreateEventFlag +//////////////////////////////////////////////////////////////////// +int _CreateEventFlag() +{ + return threads_count; // CreateEventFlag, why!?! +} + +//////////////////////////////////////////////////////////////////// +//800049C0 SYSCALL 064 CreateSema +//////////////////////////////////////////////////////////////////// +int _CreateSema(struct SemaParam *sema) +{ + register struct kSema *crt=semas_last; + + if ((crt==NULL) || (sema->init_count<0)) return -1; + + crt->wait_prev = (struct TCB*)&crt->wait_next; + semas_count++; + crt->count =sema->init_count; + crt->wait_next =(struct TCB*)&crt->wait_next; + semas_last = crt->free; + crt->max_count =sema->max_count; + crt->free =NULL; + crt->attr =sema->attr; + crt->wait_threads=0; + crt->option =sema->option; + + return (crt-semas_array); //sizeof(kSema)==32 +} + +//////////////////////////////////////////////////////////////////// +//80004A48 SYSCALL 073 iDeleteSema +//////////////////////////////////////////////////////////////////// +int _iDeleteSema(int sid) +{ + register thid, thprio; + if ((sid>=MAX_SEMAS) || (semas_array[sid].count<0)) return -1; + + semas_count--; + while (semas_array[sid].wait_threads>0){ + thid=(((u32)LL_unlink((struct ll*)&semas_array[sid].wait_next)-(u32)threads_array) * 0x286BCA1B)/4; + LL_unlinkthis((struct ll*)&threads_array[thid]); + semas_array[sid].wait_threads--; + if (threads_array[thid].status==THS_WAIT){ + thprio=threadPrio; + thread_2_ready(thid); + if (threadPrio=MAX_SEMAS) || (semas_array[sid].count<0)) return -1; + + if (semas_array[sid].wait_threads>0){ + thid=(((u32)LL_unlink((struct ll*)&semas_array[sid].wait_next)-(u32)threads_array)*0x286BCA1B)/4; + + LL_unlinkthis((struct ll*)&threads_array[thid]); + + semas_array[sid].wait_threads--; + + if (threads_array[thid].status==THS_WAIT){ + prio=threadPrio; + thread_2_ready(thid); + if (threadPrio < prio) + threadStatus=THS_RUN; + threads_array[thid].waitSema=0; //just a guess:P + } + else if (threads_array[thid].status==(THS_WAIT|THS_SUSPEND)){ + threads_array[thid].status =THS_SUSPEND; + threads_array[thid].waitSema=0; + } + }else + semas_array[sid].count++; + return sid; +} + +//////////////////////////////////////////////////////////////////// +//80004CF8 +//////////////////////////////////////////////////////////////////// +int _iWaitSema(int sid) +{ + if ((sid>=MAX_SEMAS) || (semas_array[sid].count<0)) return -1; + + if (semas_array[sid].count>0){ + semas_array[sid].count--; + return sid; + } + + semas_array[sid].wait_threads++; + + unsetTCB(threadId); + LL_add((struct ll*)&semas_array[sid].wait_next, (struct ll*)&threads_array[threadId]); + threads_array[threadId].semaId=sid; + + return -2; +} + +//////////////////////////////////////////////////////////////////// +//80004DC8 SYSCALL 069 PollSema, 070 iPollSema +//////////////////////////////////////////////////////////////////// +int _PollSema(int sid) +{ + if ((sid>=MAX_SEMAS) || (semas_array[sid].count<=0)) return -1; + + semas_array[sid].count--; + + return sid; +} + +//////////////////////////////////////////////////////////////////// +//80004E00 SYSCALL 071 ReferSemaStatus, 072 iReferSemaStatus +//////////////////////////////////////////////////////////////////// +int _ReferSemaStatus(int sid, struct SemaParam *sema) +{ + if ((sid>=MAX_SEMAS) || (semas_array[sid].count<0)) return -1; + + sema->count =semas_array[sid].count; + sema->max_count =semas_array[sid].max_count; + sema->wait_threads =semas_array[sid].wait_threads; + sema->attr =semas_array[sid].attr; + sema->option =semas_array[sid].option; + + return sid; +} + +//////////////////////////////////////////////////////////////////// +//80004E58 SYSCALL 081 RFU081_DeleteEventFlag +//////////////////////////////////////////////////////////////////// +int _DeleteEventFlag() +{ + return semas_count; // DeleteEventFlag, why!?! +} + +//////////////////////////////////////////////////////////////////// +//80004E68 +//////////////////////////////////////////////////////////////////// +int _SemasInit() +{ + int i; + + for (i=0; i<256; i++) { + semas_array[i].free = &semas_array[i+1]; + semas_array[i].count = -1; + semas_array[i].wait_threads = 0; + semas_array[i].wait_next = (struct TCB*)&semas_array[i].wait_next; + semas_array[i].wait_prev = (struct TCB*)&semas_array[i].wait_next; + } + semas_array[255].free = 0; + + semas_last = semas_array; + semas_count = 0; + + return 256; +} + +//////////////////////////////////////////////////////////////////// +//80004EC8 +//////////////////////////////////////////////////////////////////// +void __load_module_EENULL() +{ + int i; + + thread_ll_free.prev = &thread_ll_free; + thread_ll_free.next = &thread_ll_free; + + for (i=0; i<128; i++) { + thread_ll_priorities[i].prev = &thread_ll_priorities[i]; + thread_ll_priorities[i].next = &thread_ll_priorities[i]; + } + + threads_count = 0; + threadId = 0; + threadPrio = 0; + + for (i=0; i<256; i++) { + threads_array[i].status = 0; + LL_add(&thread_ll_free, (struct ll*)&threads_array[i]); + } + + _SemasInit(); + + threadStatus = 0; + __load_module("EENULL", (void (*)(void*))0x81FC0, (void*)0x81000, 0x80); +} + +//////////////////////////////////////////////////////////////////// +//80004FB0 +// makes the args from argc & argstring; args is in bss of program +//////////////////////////////////////////////////////////////////// +void _InitArgs(char *argstring, ARGS *args, int argc) +{ + int i; + char *p = args->args; + + args->argc = argc; + for (i=0; iargv[i] = p; //copy string pointer + while (*argstring) //copy the string itself + *p++ = *argstring++; + *p++ = *argstring++; //copy the '\0' + } +} + +//////////////////////////////////////////////////////////////////// +//80005198 SYSCALL 060 _InitializeMainThread +//////////////////////////////////////////////////////////////////// +void *_InitializeMainThread(u32 gp, void *stack, int stack_size, char *args, int root) +{ + struct TCB *th; + struct threadCtx *ctx; + + if ((int)stack == -1) + stack = (void*)((_GetMemorySize() - 4*1024) - stack_size); + + ctx = (struct threadCtx*)((u32)stack + stack_size - STACK_RES/4); + ctx->gp = gp; //+1C0 + ctx->ra = root; //+1F0 + ctx->fp = (u32)ctx+0x280; //+1E0 <- &280 + ctx->sp = (u32)ctx+0x280; //+1D0 <- &280 + + th = &threads_array[threadId]; + th->gpReg = (void*)gp; + th->stackSize = stack_size; + th->stack_res = ctx; + th->stack = stack; + th->root = (void*)root; + _InitArgs(th->argstring, (ARGS*)args, th->argc); + th->argstring = args; + + return ctx; +} + +//////////////////////////////////////////////////////////////////// +//800052A0 SYSCALL 061 RFU061_InitializeHeapArea +//////////////////////////////////////////////////////////////////// +void* _InitializeHeapArea(void *heap_base, int heap_size) +{ + void *ret; + + if (heap_size < 0) { + ret = threads_array[threadId].stack; + } else { + ret = heap_base + heap_size; + } + + threads_array[threadId].heap_base = ret; + return ret; +} + +//////////////////////////////////////////////////////////////////// +//800052D8 SYSCALL 062 RFU062_EndOfHeap +//////////////////////////////////////////////////////////////////// +void* _EndOfHeap() +{ + return threads_array[threadId].heap_base; +} + +//////////////////////////////////////////////////////////////////// +//80005390 +//////////////////////////////////////////////////////////////////// +int __load_module(char *name, void (*entry)(void*), void *stack_res, int prio) +{ + struct TCB *th; + int index; + int *ptr; + struct rominfo ri; + + th = (struct TCB*)LL_unlink(&thread_ll_free); + if (th) { + threads_count++; + index = (((u32)th-(u32)threads_array) * 0x286BCA1B)/4; + } else { + index = -1; + } + + threadId = index; + th->wakeupCount = 0; + th->semaId = 0; + th->attr = 0; + th->stack_res = stack_res; + th->option = 0; + th->entry = entry; + th->gpReg = 0; + th->currentPriority = prio; + th->status = THS_DORMANT; + th->waitSema = 0; + th->entry_ = entry; + th->argc = 0; + th->argstring = 0; + th->initPriority = prio; + + thread_2_ready(index); + + if (romdirGetFile(name, &ri) == NULL) { + __printf("# panic ! '%s' not found\n", name); + _Exit(1); + } + + if (ri.fileSize > 0) { + int i; + int *src = (int*)(0xbfc00000+ri.fileOffset); + int *dst = (int*)entry; + + for (i=0; i 0 ) { + int i; + for(i = 0; i < argc; ++i) + pbuf = strcpy(pbuf, argv[i]); + } + + threads_array[threadId].argc = argc+2; + threads_array[threadId].argstring = threadArgStrBuffer; + _CancelWakeupThread(threadId); + _iChangeThreadPriority(threadId, 0); + + // search for RESET + // search for filename romdir entry + if( romdirGetFile(filename, &ri) == NULL ) { + __printf("# panic ! '%s' not found\n", filename); + _Exit(); + } + + // terminate threads + curthreadid = 1; // skip main thread? + curtcb = &threads_array[curthreadid]; + + while(curthreadid < 256) { + if( curtcb->status && threadId != curthreadid ) { + if( curtcb->status == THS_DORMANT ) { + _DeleteThread(curthreadid); + } + else { + iTerminateThread(curthreadid); + _DeleteThread(curthreadid); + } + } + ++curthreadid; + ++curtcb; + } + + _SemasInit(); + threadStatus = 0; + InitPgifHandler2(); + + Restart(); + + if( ri.fileSize > 0 ) { + // copy to PS2_LOADADDR + int i; + u32* psrc = (u32*)(0xbfc00000+ri.fileOffset); + u32* pdst = (u32*)PS2_LOADADDR; + for(i = 0; i < ri.fileSize; i += 4) + *pdst++ = *psrc++; + } + + FlushInstructionCache(); + FlushDataCache(); + + __asm__("mtc0 %0, $14\n" + "sync\n" : : "r"(PS2_LOADADDR)); + erase_cpu_regs(); + __asm__("di\n" + "eret\n"); +} + +//////////////////////////////////////////////////////////////////// +//800057E8 +//////////////////////////////////////////////////////////////////// +void* __ExecPS2(void * entry, void * gp, int argc, char ** argv) +{ + char* pbuf = threadArgStrBuffer; + int i; + + if( argc > 0 ) { + for(i = 0; i < argc; ++i) + pbuf = eestrcpy(pbuf, argv[i]); + } + + threads_array[threadId].entry = entry; //0C + threads_array[threadId].wakeupCount = 0; //24 + threads_array[threadId].gpReg = gp; //14 + threads_array[threadId].semaId = 0; //20 + threads_array[threadId].argstring = threadArgStrBuffer; //38 + threads_array[threadId].argc = argc; //34 + threads_array[threadId].entry_ = entry; //30 + threads_array[threadId].currentPriority = 0; //18 + threads_array[threadId].waitSema = 0; //1C + threads_array[threadId].initPriority = 0; + FlushInstructionCache(); + FlushDataCache(); + + return entry; +} + +//////////////////////////////////////////////////////////////////// +//800058E8 +//////////////////////////////////////////////////////////////////// +int _ExecOSD(int argc, char **argv) +{ + return _LoadPS2Exe("rom0:OSDSYS", argc, argv); +} + +//////////////////////////////////////////////////////////////////// +//80005900 +//////////////////////////////////////////////////////////////////// +int _RFU004_Exit() +{ + char *bb = "BootBrowser"; + return _LoadPS2Exe("rom0:OSDSYS", 1, &bb); +} + +//////////////////////////////////////////////////////////////////// +//80005938 +//////////////////////////////////////////////////////////////////// +void releaseTCB(int tid) +{ + threads_count--; + threads_array[tid].status=0; + LL_add(&thread_ll_free, (struct ll*)&threads_array[tid]); +} + +//////////////////////////////////////////////////////////////////// +//80005978 +//////////////////////////////////////////////////////////////////// +void unsetTCB(int tid) +{ + if ((threads_array[tid].status) <= THS_READY) + LL_unlinkthis((struct ll*)&threads_array[tid]); +} + +//////////////////////////////////////////////////////////////////// +//800059B8 +//////////////////////////////////////////////////////////////////// +void thread_2_ready(int tid) +{ + threads_array[tid].status=THS_READY; + if (threads_array[tid].initPriority < threadPrio) + threadPrio=(short)threads_array[tid].initPriority; + LL_add( &thread_ll_priorities[threads_array[tid].initPriority], (struct ll*)&threads_array[tid] ); +} + +//////////////////////////////////////////////////////////////////// +//80005A58 +//////////////////////////////////////////////////////////////////// +struct ll* LL_unlink(struct ll *l) +{ + struct ll *p; + + if ((l==l->next) && (l==l->prev)) + return 0; + p=l->prev; + p->prev->next=p->next; + p->next->prev=p->prev; + return p; +} + +//////////////////////////////////////////////////////////////////// +//80005A98 +//////////////////////////////////////////////////////////////////// +struct ll* LL_rotate(struct ll *l) +{ + struct ll *p; + + if (p=LL_unlink(l)){ + p->prev=l; + p->next=l->next; + l->next->prev=p; + l->next=p; + return l->prev; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +//80005AE8 +//////////////////////////////////////////////////////////////////// +struct ll *LL_unlinkthis(struct ll *l) +{ + l->prev->next=l->next; + l->next->prev=l->prev; + return l->next; +} + +//////////////////////////////////////////////////////////////////// +//80005B08 +//////////////////////////////////////////////////////////////////// +void LL_add(struct ll *l, struct ll *new) +{ + new->prev=l; + new->next=l->next; + l->next->prev=new; + l->next=new; +} + +//////////////////////////////////////////////////////////////////// +//80005B28 SYSCALL 9 (0x09) TlbWriteRandom +//////////////////////////////////////////////////////////////////// +int _TlbWriteRandom(u32 PageMask, u32 EntryHi, u32 EntryLo0, u32 EntryLo1) { + if ((EntryHi >> 24) != 4) return -1; + __asm__ ( + "mfc0 $2, $1\n" + "mtc0 $2, $0\n" + "mtc0 $4, $5\n" + "mtc0 $5, $10\n" + "mtc0 $6, $2\n" + "mtc0 $7, $3\n" + "sync\n" + "tlbwi\n" + "sync\n" + ); +} + +int _sifGetMSFLG() { + u32 msflg; + for (;;) { + msflg = SBUS_MSFLG; + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + + if (msflg == SBUS_MSFLG) return msflg; + } +} + +//////////////////////////////////////////////////////////////////// +//80005E58 +//////////////////////////////////////////////////////////////////// +int _sifGetSMFLG() { + u32 smflg; + for (;;) { + smflg = SBUS_SMFLG; + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); + + if (smflg == SBUS_SMFLG) return smflg; + } +} + +int _ResetSif1() +{ + sif1tagdata = 0xFFFF001E; + //*(int*)0xa0001e330 = 0x20000000; + //*(int*)0xa0001e334 = (u32)ptag&0x0fffffff; + D6_QWC = 0; + D6_TAG = (u32)&sif1tagdata&0x0fffffff; +} + +//////////////////////////////////////////////////////////////////// +//80006198 +//////////////////////////////////////////////////////////////////// +void SifDmaInit() +{ + int msflg; + memset(sifEEbuff, 0, sizeof(sifEEbuff)); + memset(sifRegs, 0, sizeof(sifRegs)); + + *(u32*)0xB000F260 = 0xFF; + D5_CHCR = 0; + D6_CHCR = 0; + + _SifSetDChain(); + *(u32*)0xB000F200 = (u32)sifEEbuff; + __printf("MSFLG = 0x10000\n"); + SBUS_MSFLG = 0x10000; + msflg = SBUS_MSFLG; + _ResetSif1(); + _SifSetReg(1, 0); + + while (!(_SifGetReg(4) & 0x10000)) { __asm__ ("nop\nnop\nnop\nnop\n"); } + + sifIOPbuff = *(u32*)0xB000F210; + + SBUS_MSFLG = 0x20000; + SBUS_MSFLG; +} + +//////////////////////////////////////////////////////////////////// +//800062A0 SYSCALL 120 (0x78) SifSetDChain +//////////////////////////////////////////////////////////////////// +void _SifSetDChain(){ + int var_10; + + D5_CHCR = 0; + D5_QWC = 0; + D5_CHCR = 0x184; // 0001 1000 0100 + var_10 = D5_CHCR; // read? +} + +//////////////////////////////////////////////////////////////////// +//800062D8 SYSCALL 107 (0x6B) SifStopDma +//////////////////////////////////////////////////////////////////// +void _SifStopDma(){ + int var_10; + + D5_CHCR = 0; + D5_QWC = 0; + var_10 = D5_CHCR; // read? +} + +//////////////////////////////////////////////////////////////////// +//80006370 +//////////////////////////////////////////////////////////////////// +void _SifDmaSend(void *src, void *dest, int size, int attr, int id) +{ + int qwc; + struct TAG* t1; + int *t3; + int tocopy; + + if (((++tagindex) & 0xFF) == 31){ + tagindex=0; + transferscount++; + } + + qwc=(size+15)/16; //rount up + + t1=(struct TAG*)KSEG1_ADDR(&tadrptr[tagindex]); + if (attr & SIF_DMA_TAG) { + t1->id_qwc = (id << 16) | qwc | + ((attr & SIF_DMA_INT_I) ? 0x80000000 : 0); //IRQ + t1->addr=(u32)src & 0x1FFFFFFF; + t3=(int*)KSEG1_ADDR(src); + qwc--; + } + else { + if (qwc >= 8){ //two transfers + tocopy=7; + t1->id_qwc=0x30000008; //(id)REF | (qwc)8; + t1->addr=(u32)&extrastorage[tagindex] | 0x1FFFFFFF; + t3=(int*)KSEG1_ADDR(&extrastorage[tagindex]); + + if (((++tagindex) & 0xff) == 31){ + tagindex=0; + transferscount++; + } + + t1=(struct TAG*)KSEG1_ADDR(&tadrptr[tagindex]); + t1->id_qwc=(id << 16) | (qwc - 7) | + ((attr & SIF_DMA_INT_I) ? 0x80000000 : 0);//IRQ + t1->addr=(u32)(src+112) | 0x1FFFFFFF; + } + else { + tocopy=qwc; + t1->id_qwc=(id << 16) | (qwc+1) | + ((attr & SIF_DMA_INT_I) ? 0x80000000 : 0);//IRQ + t1->addr=(u32)&extrastorage[tagindex] & 0x1FFFFFFF; + t3=(int*)KSEG1_ADDR(&extrastorage[tagindex]); + } + memcpy((char*)t3+16, (void*)KSEG1_ADDR(src), tocopy*16);//inline with qwords + } + t3[1]=qwc * 4; + t3[0]=(u32)((u32)dest & 0x00FFFFFF) | + ((((u32)(attr & SIF_DMA_INT_O)) ? 0x40000000 : 0) | + (((u32)(attr & SIF_DMA_ERT)) ? 0x80000000 : 0)); +} + +//////////////////////////////////////////////////////////////////// +//800065C8 +//////////////////////////////////////////////////////////////////// +int _SifDmaCount() +{ + register int count; + + count=((D6_TAG-(u32)tadrptr) & 0x1FFFFFFF) >> 4; + + count=count>0? count-1:30; + + if (count == tagindex) + return (D6_QWC ? 30 : 31); + + if (count < tagindex) + return count + 30 - tagindex; + + return count-tagindex-1; +} + +//////////////////////////////////////////////////////////////////// +//80006650 +//////////////////////////////////////////////////////////////////// +void _SifDmaPrepare(int count) +{ + register struct TAG *t0; + + if (count==31) return; + + t0=(struct TAG*)KSEG1_ADDR(&tadrptr[tagindex]); + if (count == 30){ + t0->id_qwc &= DMA_TAG_IRQ|DMA_TAG_PCE; //keep PCE|REFE|IRQ + t0->id_qwc |= DMA_TAG_REF<<28; + t0->id_qwc |= D6_QWC; + t0->addr = D6_MADR; + D6_QWC = 0; + D6_TAG = KUSEG_ADDR(t0); + }else + t0->id_qwc |= DMA_TAG_REF<<28; +} + +//////////////////////////////////////////////////////////////////// +//800066F8 SYSCALL 119 (0x77) SifSetDma +//////////////////////////////////////////////////////////////////// +u32 _SifSetDma(SifDmaTransfer_t *sdd, int len) +{ + int var_10; + int count, tmp; + int i, c, _len = len; + int nextindex; + + DMAC_ENABLEW = DMAC_ENABLER | 0x10000; //suspend + + D6_CHCR = 0; //kill any previous transfer?!? + var_10 = D6_CHCR; // read? + + DMAC_ENABLEW = DMAC_ENABLER & ~0x10000; //enable + + count = _SifDmaCount(); + +lenloop: + i=0; c=0; + while (_len > 0) { + if (!(sdd[i].attr & SIF_DMA_TAG)) { + if (sdd[i].size <= 112) c++; + else c+=2; + } else c++; + _len--; i++; + } + if (count < c) { count = 0; goto lenloop; } + + nextindex = ((tagindex+1) % 31) & 0xff; + if (nextindex == 0) + tmp = (transferscount + 1) & 0xFFFF; + else + tmp = transferscount; + + _SifDmaPrepare(count); + + while (len > 0) { + _SifDmaSend(sdd->src, sdd->dest, sdd->size, sdd->attr, DMA_TAG_REF<<12);//REF >> 16 + sdd++; len--; + } + + _SifDmaSend(sdd->src, sdd->dest, sdd->size, sdd->attr, DMA_TAG_REFE<<12);//REFE >> 16 + + D6_CHCR|= 0x184; + var_10 = D6_CHCR; // read? + return (tmp<<16)|(nextindex<<8)|c; +} + +//////////////////////////////////////////////////////////////////// +//800068B0 SYSCALL 118 (0x76) SifDmaStat +//////////////////////////////////////////////////////////////////// +int _SifDmaStat(int id) +{ + //TODO + return 0; +} + +//////////////////////////////////////////////////////////////////// +//80006B60 SYSCALL 121 (0x79) SifSetDma +//////////////////////////////////////////////////////////////////// +int _SifSetReg(int reg, u32 val) +{ + __printf("%s: reg=%d; val=%x\n", __FUNCTION__, reg, val); + + if (reg == 1) { + *(u32*)0xB000F200 = val; + return *(u32*)0xB000F200; + } else + if (reg == 3) { + SBUS_MSFLG = val; + return _sifGetMSFLG(); + } else + if (reg == 4) { + SBUS_SMFLG = val; + return _sifGetSMFLG(); + } else + if (reg >= 0) { + return 0; + } + + reg&= 0x7FFFFFFF; + if (reg >= 32) return 0; + + sifRegs[reg] = val; + return val; +} + +//////////////////////////////////////////////////////////////////// +//80006C18 SYSCALL 122 (0x7A) SifSetDma +//////////////////////////////////////////////////////////////////// +int _SifGetReg(int reg) +{ + //__printf("%s: reg=%x\n", __FUNCTION__, reg); + + if (reg == 1) { + return *(u32*)0xB000F200; + } else + if (reg == 2) { + return *(u32*)0xB000F210; + } else + if (reg == 3) { + return _sifGetMSFLG(); + } else + if (reg == 4) { + return _sifGetSMFLG(); + } else + if (reg >= 0) { + return 0; + } + + reg&= 0x7FFFFFFF; + if (reg >= 32) return 0; + + //__printf("ret=%x\n", sifRegs[reg]); + return sifRegs[reg]; +} + +//////////////////////////////////////////////////////////////////// +//80007428 SYSCALL 117 print +//////////////////////////////////////////////////////////////////// +void _print() +{ +} + +//////////////////////////////////////////////////////////////////// +//800074D8 +//////////////////////////////////////////////////////////////////// +void _SetGsCrt2() +{ + u32 tmp; + + tmp = *(int*)0x8001F344; + if (tmp == 0x40 || tmp == 0x60 || tmp == 0x61) { + *(char*)0xbf803218 = 0; + *(char*)0xbf803218 = 2; + return; + } + + *(short*)0xbf801470 = 0; + *(short*)0xbf801472 = 0; + *(short*)0xbf801472 = 1; +} + +//////////////////////////////////////////////////////////////////// +//800076B0 +//////////////////////////////////////////////////////////////////// +void _iJoinThread(int param) +{ + //TODO +} + +//////////////////////////////////////////////////////////////////// +//80008A60 +//////////////////////////////////////////////////////////////////// +void _SetGsCrt3(short arg0, short arg1, short arg2) +{ + __printf("_SetGsCrt3 unimplemented\n"); +} + +//////////////////////////////////////////////////////////////////// +//80009CE0 +//////////////////////////////////////////////////////////////////// +void _SetGsCrt4(short arg0, short arg1, short arg2) +{ + __printf("_SetGsCrt4 unimplemented\n"); +} + +//////////////////////////////////////////////////////////////////// +//8000A060 SYSCALL 002 SetGsCrt +//////////////////////////////////////////////////////////////////// +void _SetGsCrt(short arg0, short arg1, short arg2) +{ + u64 val, val2; + u64 tmp; + int count; + + if (arg1 == 0) { + tmp = (hvParam >> 3) & 0x7; + tmp^= 0x2; + if (tmp == 0) arg1 = 3; + else arg1 = 2; + } + + for (count=0x270f; count >= 0; count--) { + __asm__ ("nop\nnop\nnop\nnop\nnop\nnop\n"); + } + + *(int*)0x8001F344 = 0; + + if (arg1 == 2) { + if (arg0 != 0) { + val = 0x740834504LL; + val2 = 0x740814504LL; + + tmp = (hvParam & 0x1) << 25; + val|= tmp; + val2|= tmp; + + GS_SMODE1 = val; + GS_SYNCH1 = 0x7F5B61F06F040LL; + GS_SYNCH2 = 0x33A4D8; + GS_SYNCV = 0xC7800601A01801LL; + + GS_SMODE2 = (arg2 << 1) | 1; + GS_SRFSH = 8; + GS_SMODE1 = val2; + } else { + val = 0x740834504LL; + val2 = 0x740814504LL; + + tmp = (hvParam & 0x2) << 35; + val|= tmp; + val2|= tmp; + + tmp = (hvParam & 0x1) << 25; + val|= tmp; + val2|= tmp; + + GS_SMODE1 = val; + GS_SYNCH1 = 0x7F5B61F06F040LL; + GS_SYNCH2 = 0x33A4D8; + GS_SYNCV = 0xC7800601A01802LL; + GS_SMODE2 = 0; + GS_SRFSH = 8; + GS_SMODE1 = val2; + } + _SetGsCrt2(); + return; + } + + if (arg1 == 3) { + if (arg0 != 0) { + val = 0x740836504LL; + val2 = 0x740816504LL; + + tmp = (hvParam & 0x1) << 25; + val|= tmp; + val2|= tmp; + + GS_SMODE1 = val; + GS_SYNCH1 = 0x7F5C21FC83030LL; + GS_SYNCH2 = 0x3484BC; + GS_SYNCV = 0xA9000502101401LL; + + GS_SMODE2 = (arg2 << 1) | 1; + GS_SRFSH = 8; + GS_SMODE1 = val2; + } else { + val = 0x740836504LL; + val2 = 0x740816504LL; + + tmp = (hvParam & 0x2) << 35; + val|= tmp; + val2|= tmp; + + tmp = (hvParam & 0x1) << 25; + val|= tmp; + val2|= tmp; + + GS_SMODE1 = val; + GS_SYNCH1 = 0x7F5C21F683030LL; + GS_SYNCH2 = 0x3484BC; + GS_SYNCV = 0xA9000502101404LL; + GS_SMODE2 = 0; + GS_SRFSH = 8; + GS_SMODE1 = val2; + } + _SetGsCrt2(); + return; + } + + if (arg1 == 0x72) { + if (arg0 != 0) { + val = 0x740814504LL; + val|= (hvParam & 0x1) << 25; + + GS_SYNCH1 = 0x7F5B61F06F040LL; + GS_SYNCH2 = 0x33A4D8; + GS_SYNCV = 0xC7800601A01801LL; + + GS_SMODE2 = (arg2 << 1) | 1; + GS_SRFSH = 8; + GS_SMODE1 = val; + } else { + val = 0x740814504LL; + + val|= (hvParam & 0x2) << 35; + val|= (hvParam & 0x1) << 25; + + GS_SYNCH1 = 0x7F5B61F06F040LL; + GS_SYNCH2 = 0x33A4D8; + GS_SYNCV = 0xC7800601A01802LL; + GS_SMODE2 = 0; + GS_SRFSH = 8; + GS_SMODE1 = val; + } + return; + } + + if (arg1 == 0x73) { + if (arg0 != 0) { + val = 0x740816504LL; + val|= (hvParam & 0x1) << 25; + + GS_SYNCH1 = 0x7F5C21FC83030LL; + GS_SYNCH2 = 0x3484BC; + GS_SYNCV = 0xA9000502101401LL; + + GS_SMODE2 = (arg2 << 1) | 1; + GS_SRFSH = 8; + GS_SMODE1 = val; + } else { + val = 0x740816504; + + val|= (hvParam & 0x2) << 35; + val|= (hvParam & 0x1) << 25; + + GS_SYNCH1 = 0x7F5C21FC83030LL; + GS_SYNCH2 = 0x3484BC; + GS_SYNCV = 0xA9000502101404LL; + GS_SMODE2 = 0; + GS_SRFSH = 8; + GS_SMODE1 = val; + } + return; + } + + if ((u32)(arg1 - 26) >= 0x38) { + _SetGsCrt3(arg0, arg1, arg2); return; + } + + if (arg1 == 0x52) { + _SetGsCrt3(arg0, arg1, arg2); return; + } + + _SetGsCrt4(arg0, arg1, arg2); +} + +//////////////////////////////////////////////////////////////////// +//8000A768 SYSCALL 076 GetGsHParam +//////////////////////////////////////////////////////////////////// +void _GetGsHParam(int *p0, int *p1, int *p2, int *p3) +{ + u32 _hvParam = (u32)hvParam; + + *p0 = _hvParam >> 12; + *p1 = _hvParam >> 24; + *p2 = _hvParam >> 18; + *p3 = _hvParam >> 28; +} + +//////////////////////////////////////////////////////////////////// +//8000A7D0 SYSCALL 077 GetGsVParam +//////////////////////////////////////////////////////////////////// +int _GetGsVParam() +{ + return hvParam & 0x3; +} + +//////////////////////////////////////////////////////////////////// +//8000A800 SYSCALL 059 JoinThread +//////////////////////////////////////////////////////////////////// +void _JoinThread() +{ + _iJoinThread(0x87); +} + +//////////////////////////////////////////////////////////////////// +//8000A820 SYSCALL 078 SetGsHParam +//////////////////////////////////////////////////////////////////// +void _SetGsHParam(int a0, int a1, int a2, int a3) +{ + __printf("SetGsHParam(%x,%x,%x,%x)... probably will never be supported\n", a0, a1, a2, a3); + //write hvParam&1 to 12000010? +} + +//////////////////////////////////////////////////////////////////// +//8000A8F8 SYSCALL 079 SetGsVParam +//////////////////////////////////////////////////////////////////// +void _SetGsVParam(int VParam) +{ + hvParam&= ~0x1; + hvParam|= VParam & 0x1; +} + +//////////////////////////////////////////////////////////////////// +//8000A920 SYSCALL 075 GetOsdConfigParam +//////////////////////////////////////////////////////////////////// +void _GetOsdConfigParam(int *result) +{ + *result= (*result & 0xFFFFFFFE) | (osdConfigParam & 1); + *result= (*result & 0xFFFFFFF9) | (osdConfigParam & 6); + *result= (*result & 0xFFFFFFF7) | (osdConfigParam & 8); + *result= (*result & 0xFFFFFFEF) | (osdConfigParam & 0x10); + *result=((*result & 0xFFFFE01F) | (osdConfigParam & 0x1FE0)) & 0xFFFF1FFF; + ((u16*)result)[1]=((u16*)&osdConfigParam)[1]; +} + +//////////////////////////////////////////////////////////////////// +//8000A9C0 SYSCALL 074 SetOsdConfigParam +//////////////////////////////////////////////////////////////////// +void _SetOsdConfigParam(int *param) +{ + osdConfigParam= (osdConfigParam & 0xFFFFFFFE) | (*param & 1); + osdConfigParam= (osdConfigParam & 0xFFFFFFF9) | (*param & 6); + osdConfigParam= (osdConfigParam & 0xFFFFFFF7) | (*param & 8); + osdConfigParam= (osdConfigParam & 0xFFFFFFEF) | (*param & 0x10); + osdConfigParam=((osdConfigParam & 0xFFFFE01F) | (*param & 0x1FE0)) & 0xFFFF1FFF; + ((u16*)&osdConfigParam)[1]=((u16*)param)[1]; +} + +//////////////////////////////////////////////////////////////////// +//8000FCE8 +//////////////////////////////////////////////////////////////////// +void __exhandler(int a0) +{ +} + +//////////////////////////////////////////////////////////////////// +//80010F34 +//////////////////////////////////////////////////////////////////// +void __disableInterrupts() +{ + __asm__("mtc0 $0, $25\n" + "mtc0 $0, $24\n" + "li $3, 0xFFFFFFE0\n" + "mfc0 $2, $12\n" + "and $2, $3\n" + "mtc0 $2, $12\n" + "sync\n"); +} + +//////////////////////////////////////////////////////////////////// +//80010F58 +//////////////////////////////////////////////////////////////////// +void kSaveContext() +{ +} + +//////////////////////////////////////////////////////////////////// +//80011030 +//////////////////////////////////////////////////////////////////// +void kLoadContext() +{ +} + +//////////////////////////////////////////////////////////////////// +//800110F4 +//////////////////////////////////////////////////////////////////// +void kLoadDebug() +{ + kLoadContext(); + // lq $31, 0x1F0($27) + // lq $27, 0x1B0($27) + // j 80005020 - probably load debug services or restore prev program state +} + +//////////////////////////////////////////////////////////////////// +//80011108 +//////////////////////////////////////////////////////////////////// +int __exception() +{ + register u32 curepc __asm__("$2"); + int ret; + + __asm__("mfc0 %0, $14\n" : "=r"(curepc) : ); + + // check if epc is currently in the except handlers: + // _Deci2Handler, __exception1, and __exception + if (curepc >= (u32)__exception && curepc < (u32)__exception+0x300) { + __asm__("mfc0 %0, $13\n" : "=r"(ret) : ); + return (ret & 0x7C) >> 2; + } + + kSaveContext(); + + __disableInterrupts(); + __exhandler(1); + + kLoadContext(); + + __asm__("eret\n"); +} + +//////////////////////////////////////////////////////////////////// +//800111F0 +//////////////////////////////////////////////////////////////////// +void __exception1() +{ + kSaveContext(); + __disableInterrupts(); + //sub_8000CF68 + kLoadContext(); + __asm__("eret\n"); +} diff --git a/fps2bios/kernel/eeload/eeload.c b/fps2bios/kernel/eeload/eeload.c new file mode 100644 index 0000000000..1af03d441e --- /dev/null +++ b/fps2bios/kernel/eeload/eeload.c @@ -0,0 +1,34 @@ + +#include +#include + +#include "eeload.h" +#include "eeinit.h" +#include "eedebug.h" + +void __attribute__((noreturn)) eeload_start() { + void (*entry)(); + __puts("EELOAD start\n"); + + __printf("about to SifInitRpc(0)\n"); + SifInitRpc(0); + __printf("done rpc\n"); + + entry = (void (*)())loadElfFile("INTRO"); + entry(); + + entry = (void (*)())loadElfFile("LOADER"); + entry(); + + for (;;); +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + diff --git a/fps2bios/kernel/eeload/eeload.map b/fps2bios/kernel/eeload/eeload.map new file mode 100644 index 0000000000..2242c21a68 --- /dev/null +++ b/fps2bios/kernel/eeload/eeload.map @@ -0,0 +1,1008 @@ +Archive member included because of file (symbol) + +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memcpy.o) + eekernel.o (memcpy) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memset.o) + eekernel.o (memset) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strcpy.o) + eekernel.o (strcpy) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) + eedebug.o (vsnprintf) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) (vxprintf) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__sout.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) (__sout) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (free) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) (_ps2sdk_alloc_lock) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(isdigit.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (isdigit) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) (ps2_sbrk) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strlen.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (strlen) +/usr/local/ps2dev/ps2sdk/ee/lib/libc.a(malloc.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) (__alloc_heap_head) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(ResetEE.o) + eeinit.o (ResetEE) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(Exit.o) + eekernel.o (Exit) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iTerminateThread.o) + eekernel.o (iTerminateThread) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iWakeupThread.o) + eekernel.o (iWakeupThread) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EndOfHeap.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) (EndOfHeap) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(CreateSema.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) (CreateSema) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DeleteSema.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) (DeleteSema) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SignalSema.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) (SignalSema) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(WaitSema.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) (WaitSema) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SetVSyncFlag.o) + eekernel.o (SetVSyncFlag) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + eeload.o (SifInitRpc) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_rpc_get_fpacket.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (_rpc_get_fpacket) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(__iop_control_internals.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (_iop_reboot_count) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DIntr.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (DIntr) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EIntr.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (EIntr) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSignalSema.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (iSignalSema) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetReg.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (SifSetReg) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifGetReg.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (SifGetReg) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (SifSendCmd) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) (_sif_cmd_data) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_addhandler.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (SifAddCmdHandler) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_sreg_get.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) (SifGetSreg) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EnableDmac.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (EnableDmac) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DisableDmac.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (DisableDmac) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(AddDmacHandler.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (AddDmacHandler) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(RemoveDmacHandler.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (RemoveDmacHandler) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_EnableDmac.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EnableDmac.o) (_EnableDmac) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_DisableDmac.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DisableDmac.o) (_DisableDmac) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(FlushCache.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (FlushCache) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDma.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) (SifSetDma) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDma.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) (iSifSetDma) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDChain.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (SifSetDChain) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifWriteBackDCache.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) (SifWriteBackDCache) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_sif_cmd_int_handler.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) (_SifCmdIntHandler) +/usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDChain.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_sif_cmd_int_handler.o) (iSifSetDChain) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (__udivdi3) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (__umoddi3) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (dpadd) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (dpmul) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (dpcmp) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (litodp) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) (dptoli) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) (__thenan_df) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) (__clz_tab) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) (__pack_d) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) (__unpack_d) +/usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) (__fpcmp_parts_d) + +Allocating common symbols +Common symbol size file + +intcs_array 0xa8 eekernel.o +elfsize 0x4 eeelf.o +threadArgStrBuffer 0x100 eekernel.o +sifIOPbuff 0x4 eekernel.o +sifRegs 0x80 eekernel.o +rcnt3TargetNum 0x40 eekernel.o +dword_80016A84 0x4 eekernel.o +threads_array 0x4c00 eekernel.o +g_kernelstackend 0x4 eekernel.o +VSyncFlag1 0x4 eekernel.o +handler_ll_free 0x8 eekernel.o +gsIMR 0x8 eekernel.o +SavedRA 0x10 eedata.o +thread_ll_free 0x8 eekernel.o +semas_array 0x2000 eekernel.o +sifEEbuff 0x80 eekernel.o +SavedSP 0x10 eedata.o +dword_80016A7C 0x4 eekernel.o +machineType 0x4 eekernel.o +sections_names 0x4 eeelf.o +SavedT9 0x8 eedata.o +elfdata 0x4 eeelf.o +sbus_handlers 0x80 eekernel.o +thread_ll_priorities + 0x400 eekernel.o +tadrptr 0x1f0 eekernel.o +_HandlersCount 0x4 eekernel.o +sif1tagdata 0x4 eekernel.o +VSyncFlag0 0x4 eekernel.o +g_kernelstack 0x2000 eekernel.o +osdConfigParam 0x4 eekernel.o +dword_80016A88 0x4 eekernel.o +pgifhandlers_array 0xf18 eekernel.o +dmacs_array 0xb4 eekernel.o +SavedRegs 0x1d0 eedata.o +elfHeader 0x4 eeelf.o +hvParam 0x8 eekernel.o +dword_80016A78 0x4 eekernel.o +extrastorage 0xf80 eekernel.o +elfProgH 0x4 eeelf.o +memorySize 0x4 eekernel.o +SavedAT 0x10 eedata.o +elfSectH 0x4 eeelf.o + +Memory Configuration + +Name Origin Length Attributes +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +LOAD eeirq.o +LOAD eedata.o +LOAD eekernel.o +LOAD eeinit.o +LOAD eeload.o +LOAD eeelf.o +LOAD eedebug.o +LOAD romdir.o +LOAD /usr/local/ps2dev/ps2sdk/ee/lib/libmc.a +LOAD /usr/local/ps2dev/ps2sdk/ee/lib/libpad.a +LOAD /usr/local/ps2dev/ps2sdk/ee/lib/libc.a +LOAD /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a +LOAD /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a +LOAD /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a + 0x0000000000080000 _stack_size = 0x80000 + 0x0000000000a00000 _heap_size = 0xa00000 + +. 0x0000000080000000 0xefa + eeirq.o() + .text 0x0000000080000000 0x718 eeirq.o + 0x0000000080000280 SyscException + 0x00000000800006e8 setINTCHandler + 0x0000000080000180 CpuException + 0x00000000800003e0 INTCException + 0x00000000800003c0 _Deci2Call + 0x0000000080000200 CpuException2 + 0x00000000800006e0 TIMERException + 0x0000000080000578 DMACException + 0x0000000080000000 CpuException0 + 0x0000000080000700 setDMACHandler + .reginfo 0x0000000080000718 0x18 eeirq.o + .mdebug 0x0000000080000730 0x79c eeirq.o + *fill* 0x0000000080000ecc 0x4 00 + .rodata 0x0000000080000ed0 0x18 eeirq.o + .comment 0x0000000080000ee8 0x12 eeirq.o + +.text 0x0000000080001000 0xa910 + *(.text) + .text 0x0000000080001000 0x4ed8 eekernel.o + 0x0000000080005c68 _SetGsVParam + 0x0000000080001ac8 _AddDmacHandler + 0x0000000080002858 _TerminateThread + 0x0000000080002338 GetCop0_Reg19 + 0x0000000080003448 _iTerminateThread + 0x0000000080004240 _InitArgs + 0x0000000080001608 _DummyINTCHandler + 0x00000000800052a8 _SifSetReg + 0x0000000080002098 _excepRet + 0x00000000800024c0 SetCop0_EntryHi + 0x00000000800018f8 _RemoveIntcHandler + 0x0000000080003ab0 _SuspendThread + 0x00000000800023b8 GetCop0_ErrorPC + 0x0000000080002c38 _SignalSema + 0x0000000080001ae8 _AddDmacHandler2 + 0x00000000800020e0 _RFU005 + 0x00000000800012d8 _CpuConfig_4 + 0x0000000080002a90 _WakeupThread + 0x0000000080003700 _iReleaseWaitThread + 0x0000000080001350 _GsGetIMR + 0x0000000080005c88 _GetOsdConfigParam + 0x00000000800048d8 releaseTCB + 0x0000000080003f68 _iWaitSema + 0x00000000800025c0 SetCop0_Reg26 + 0x0000000080002350 GetCop0_Reg22 + 0x0000000080002390 GetCop0_Reg27 + 0x0000000080003860 _ReferThreadStatus + 0x0000000080002420 SetCop0_EntryLo0 + 0x0000000080002468 SetCop0_PageMask + 0x00000000800010d0 __EnableIntc + 0x0000000080002ba0 _WaitSema + 0x00000000800022f8 GetCop0_ExceptPC + 0x0000000080003920 __SleepThread + 0x0000000080004b80 _sifGetSMFLG + 0x00000000800043e0 _EndOfHeap + 0x0000000080001da0 _iSetEventFlag + 0x0000000080002158 _FlushCache + 0x0000000080002818 _ExitDeleteThread + 0x00000000800049d0 LL_unlink + 0x0000000080002620 _ExecPS2 + 0x00000000800054b8 _SetGsCrt4 + 0x0000000080002de8 __ThreadHandler + 0x0000000080001178 __DisableDmac + 0x0000000080001590 erase_cpu_regs + 0x0000000080002590 SetCop0_DebugReg24 + 0x0000000080002550 SetCop0_Reg18 + 0x0000000080005dd0 __disableInterrupts + 0x0000000080002978 _ReleaseWaitThread + 0x0000000080001e78 _ReleaseAlarm + 0x0000000080002378 GetCop0_Perf + 0x0000000080003210 _ChangeThread + 0x0000000080001ba0 sbusHandler + 0x0000000080002a08 _SleepThread + 0x0000000080003318 _CreateThread + 0x0000000080001000 _eret + 0x0000000080002030 _InitRCNT3 + 0x00000000800054d8 _SetGsCrt + 0x0000000080001be8 _AddSbusIntcHandler + 0x0000000080002510 SetCop0_ExceptPC + 0x0000000080001288 _CpuConfig_1 + 0x00000000800025e8 SetCop0_TagHi + 0x0000000080002600 SetCop0_ErrorPC + 0x00000000800022b8 GetCop0_EntryHi + 0x0000000080005448 _SetGsCrt2 + 0x00000000800040f0 _SemasInit + 0x0000000080001340 _GetMemorySize + 0x0000000080001058 _SetCPUTimer + 0x00000000800040e0 _DeleteEventFlag + 0x0000000080005050 _SifDmaPrepare + 0x0000000080002368 GetCop0_DebugReg24 + 0x0000000080003560 _DisableDispatchThread + 0x00000000800050f8 _SifSetDma + 0x0000000080004160 __load_module_EENULL + 0x0000000080005e08 kLoadContext + 0x0000000080004970 thread_2_ready + 0x0000000080005e30 __exception + 0x0000000080003588 _EnableDispatchThread + 0x0000000080002fa8 restoreContext + 0x00000000800035b0 _iChangeThreadPriority + 0x0000000080001db0 _SetAlarm + 0x0000000080001380 _Exit + 0x0000000080003978 _iWakeupThread + 0x0000000080003c40 _CreateEventFlag + 0x0000000080004388 _InitializeHeapArea + 0x0000000080001c50 _RemoveSbusIntcHandler + 0x0000000080003450 __DeleteThread + 0x0000000080005d28 _SetOsdConfigParam + 0x0000000080002328 GetCop0_Reg17 + 0x0000000080002398 GetCop0_TagLo + 0x0000000080005e00 kSaveContext + 0x0000000080001698 _RFU___ + 0x0000000080005dc8 __exhandler + 0x00000000800016d8 _AddHandler + 0x0000000080005c08 _JoinThread + 0x0000000080001320 _MachineType + 0x00000000800034c8 __StartThread + 0x0000000080002560 SetCop0_Reg20 + 0x0000000080001760 DefaultINTCHandler + 0x0000000080002400 SetCop0_Index + 0x0000000080004a68 LL_unlinkthis + 0x00000000800023c8 GetCop0_Reg31 + 0x00000000800024a0 SetCop0_BadVAddr + 0x00000000800021c0 FlushDataCache + 0x0000000080001640 _DummyDMACHandler + 0x0000000080004aa0 _TlbWriteRandom + 0x0000000080001140 __EnableDmac + 0x0000000080002528 SetCop0_PRevID + 0x00000000800027d8 _ExitThread + 0x00000000800024d8 SetCop0_Compare + 0x0000000080001770 __AddIntcHandler + 0x0000000080001330 _SetMemorySize + 0x0000000080002438 SetCop0_EntryLo1 + 0x00000000800012b8 _CpuConfig_3 + 0x0000000080001108 __DisableIntc + 0x0000000080002250 GetCop0_EntryLo1 + 0x00000000800018b8 _AddIntcHandler + 0x00000000800021f0 _GetCop0 + 0x00000000800024a8 SetCop0_Count + 0x0000000080005bf0 _GetGsVParam + 0x00000000800011b0 _SetVTLBRefillHandler + 0x0000000080004d70 _SifStopDma + 0x0000000080002340 GetCop0_Reg20 + 0x00000000800052a0 _SifDmaStat + 0x0000000080001718 _RemoveHandler + 0x0000000080003b40 _iResumeThread + 0x0000000080001d20 _EnableIntcHandler + 0x0000000080002d48 _ChangeThreadPriority + 0x0000000080003e48 _iSignalSema + 0x00000000800025a8 SetCop0_Perf + 0x0000000080002298 GetCop0_BadVAddr + 0x00000000800013a0 _start + 0x0000000080002270 GetCop0_PageMask + 0x0000000080002330 GetCop0_Reg18 + 0x0000000080001d60 _EnableDmacHandler + 0x0000000080001ba8 __AddSbusIntcHandler + 0x00000000800026a8 _DeleteThread + 0x0000000080001b08 _RemoveDmacHandler + 0x0000000080001768 DefaultDMACHandler + 0x00000000800025d0 SetCop0_TagLo + 0x0000000080002418 SetCop0_Random + 0x0000000080002480 SetCop0_Wired + 0x00000000800024f0 SetCop0_Status + 0x0000000080001038 _SetPgifHandler + 0x0000000080001450 saveContext2 + 0x0000000080002318 GetCop0_Config + 0x00000000800030e8 _ThreadHandler + 0x0000000080002348 GetCop0_Reg21 + 0x00000000800025c8 SetCop0_Reg27 + 0x0000000080002260 GetCop0_Context + 0x0000000080001d80 _DisableDmacHandler + 0x0000000080005e10 kLoadDebug + 0x0000000080004870 _ExecOSD + 0x0000000080004408 __load_module + 0x0000000080005c28 _SetGsHParam + 0x0000000080001e80 rcnt3Handler + 0x0000000080002240 GetCop0_EntryLo0 + 0x0000000080003850 _GetThreadId + 0x00000000800028e8 _RotateThreadReadyQueue + 0x0000000080002230 GetCop0_Random + 0x0000000080003558 __ExitDeleteThread + 0x0000000080001c20 __RemoveSbusIntcHandler + 0x0000000080005490 _iJoinThread + 0x00000000800045b0 _LoadPS2Exe + 0x0000000080001270 _CpuConfig_0 + 0x0000000080004790 __ExecPS2 + 0x0000000080004af8 _sifGetMSFLG + 0x0000000080002cc0 _DeleteSema + 0x0000000080002e30 saveContext + 0x0000000080001308 _PSMode + 0x00000000800011e0 _SetVCommonHandler + 0x0000000080004c48 SifDmaInit + 0x00000000800016c0 _SetVSyncFlag + 0x0000000080002548 SetCop0_Reg17 + 0x0000000080002578 SetCop0_Reg23 + 0x0000000080002280 GetCop0_Wired + 0x0000000080001048 _SetCPUTimerHandler + 0x00000000800022a8 GetCop0_Count + 0x00000000800012f0 _CpuConfig_5 + 0x00000000800023a8 GetCop0_TagHi + 0x00000000800021b8 FlushInstructionCache + 0x00000000800036b0 _iRotateThreadReadyQueue + 0x00000000800014f0 restoreContext2 + 0x00000000800023d0 SetCop0 + 0x0000000080002130 _DisableCache + 0x0000000080001cf0 _Interrupt2Iop + 0x00000000800021d0 _105 + 0x0000000080005ea8 __exception1 + 0x0000000080002530 SetCop0_Config + 0x0000000080002308 GetCop0_PRevID + 0x0000000080002450 SetCop0_Context + 0x0000000080001d40 _DisableIntcHandler + 0x0000000080002358 GetCop0_Reg23 + 0x00000000800048a0 _RFU004_Exit + 0x0000000080003c50 _CreateSema + 0x0000000080002618 SetCop0_Reg31 + 0x00000000800012a0 _CpuConfig_2 + 0x0000000080004c08 _ResetSif1 + 0x0000000080004d90 _SifDmaSend + 0x00000000800022c8 GetCop0_Compare + 0x0000000080005bb8 _GetGsHParam + 0x0000000080004040 _PollSema + 0x0000000080004a18 LL_rotate + 0x0000000080003550 __ExitThread + 0x0000000080001210 _SetVInterruptHandler + 0x0000000080002738 _StartThread + 0x00000000800042a0 _InitializeMainThread + 0x0000000080002508 SetCop0_Cause + 0x0000000080002110 _EnableCache + 0x0000000080005498 _SetGsCrt3 + 0x0000000080001678 DefaultCPUTimerHandler + 0x0000000080001020 _SetSYSCALL + 0x00000000800022d8 GetCop0_Status + 0x0000000080004080 _ReferSemaStatus + 0x0000000080005440 _print + 0x0000000080001990 __AddDmacHandler + 0x0000000080003bf8 _CancelWakeupThread + 0x0000000080002b18 _ResumeThread + 0x0000000080004a80 LL_add + 0x00000000800021d8 _KSeg0 + 0x0000000080004fd8 _SifDmaCount + 0x0000000080002568 SetCop0_Reg21 + 0x0000000080002570 SetCop0_Reg22 + 0x0000000080002290 GetCop0_Reg7 + 0x0000000080001c88 __Interrupt2Iop + 0x0000000080002388 GetCop0_Reg26 + 0x00000000800021c8 FlushSecondaryCache + 0x0000000080003cc8 _iDeleteSema + 0x0000000080002020 _SetEventFlag + 0x0000000080001238 _CpuConfig + 0x0000000080005388 _SifGetReg + 0x0000000080002498 SetCop0_Reg7 + 0x0000000080004d48 _SifSetDChain + 0x0000000080001360 _GsPutIMR + 0x00000000800018d8 _AddIntcHandler2 + 0x0000000080002220 GetCop0_Index + 0x0000000080004570 eestrcpy + 0x00000000800022e8 GetCop0_Cause + 0x0000000080002558 SetCop0_Reg19 + 0x0000000080004928 unsetTCB + .text 0x0000000080005ed8 0xc18 eeinit.o + 0x0000000080006430 InitializeScratchPad + 0x0000000080006998 InitPgifHandler2 + 0x0000000080005f08 _ResetEE + 0x0000000080006370 InitializeVU1 + 0x0000000080006808 InitPgifHandler + 0x0000000080006380 InitializeIPU + 0x0000000080006468 InitializeUserMemory + 0x0000000080006388 InitializeVIF0 + 0x00000000800064f0 InitializeTIMER + 0x0000000080006398 InitializeFPU + 0x00000000800065e0 _TlbSet + 0x00000000800064c0 InitializeINTC + 0x0000000080006108 Restart + 0x0000000080006618 TlbInit + 0x0000000080006390 InitializeVU0 + 0x0000000080006280 InitializeDMAC + 0x0000000080006378 InitializeVIF1 + 0x0000000080005ed8 InitializeGS + 0x0000000080006038 Initialize + 0x0000000080005ee0 InitializeGIF + .text 0x0000000080006af0 0xa0 eeload.o + 0x0000000080006af0 eeload_start + 0x0000000080006b60 Kmemcpy + .text 0x0000000080006b90 0x2d0 eeelf.o + 0x0000000080006d28 loadSectionHeaders + 0x0000000080006bc0 loadHeaders + 0x0000000080006bf8 loadProgramHeaders + 0x0000000080006dc0 loadElfFile + .text 0x0000000080006e60 0xf8 eedebug.o + 0x0000000080006ee8 __printf + 0x0000000080006ea0 __puts + 0x0000000080006e60 __putc + .text 0x0000000080006f58 0x1a0 romdir.o + 0x0000000080006f58 romdirInit + 0x0000000080006fe0 romdirGetFile + .text 0x00000000800070f8 0xac /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memcpy.o) + 0x00000000800070f8 memcpy + .text 0x00000000800071a4 0xac /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memset.o) + 0x00000000800071a4 memset + .text 0x0000000080007250 0x110 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strcpy.o) + 0x0000000080007250 strcpy + .text 0x0000000080007360 0x40 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) + 0x0000000080007360 vsnprintf + .text 0x00000000800073a0 0x1030 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + 0x0000000080007430 vxprintf + .text 0x00000000800083d0 0x88 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__sout.o) + 0x00000000800083d0 __sout + .text 0x0000000080008458 0xf8 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) + 0x0000000080008458 free + .text 0x0000000080008550 0xc0 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) + 0x0000000080008580 _ps2sdk_alloc_deinit + 0x0000000080008550 _ps2sdk_alloc_init + 0x00000000800085b0 _ps2sdk_alloc_lock + 0x00000000800085e0 _ps2sdk_alloc_unlock + .text 0x0000000080008610 0x18 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(isdigit.o) + 0x0000000080008610 isdigit + .text 0x0000000080008628 0x68 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) + 0x0000000080008628 ps2_sbrk + .text 0x0000000080008690 0x138 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strlen.o) + 0x0000000080008690 strlen + .text 0x00000000800087c8 0x1f0 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(malloc.o) + 0x0000000080008808 malloc + 0x00000000800087c8 _heap_mem_fit + *fill* 0x00000000800089b8 0x8 00 + .text 0x00000000800089c0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(ResetEE.o) + 0x00000000800089c0 ResetEE + .text 0x00000000800089d0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(Exit.o) + 0x00000000800089d0 Exit + .text 0x00000000800089e0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iTerminateThread.o) + 0x00000000800089e0 iTerminateThread + .text 0x00000000800089f0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iWakeupThread.o) + 0x00000000800089f0 iWakeupThread + .text 0x0000000080008a00 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EndOfHeap.o) + 0x0000000080008a00 EndOfHeap + .text 0x0000000080008a10 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(CreateSema.o) + 0x0000000080008a10 CreateSema + .text 0x0000000080008a20 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DeleteSema.o) + 0x0000000080008a20 DeleteSema + .text 0x0000000080008a30 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SignalSema.o) + 0x0000000080008a30 SignalSema + .text 0x0000000080008a40 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(WaitSema.o) + 0x0000000080008a40 WaitSema + .text 0x0000000080008a50 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SetVSyncFlag.o) + 0x0000000080008a50 SetVSyncFlag + .text 0x0000000080008a60 0x4f0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + 0x0000000080008d58 SifInitRpc + 0x0000000080008f28 SifExitRpc + .text 0x0000000080008f50 0x30 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_rpc_get_fpacket.o) + 0x0000000080008f50 _rpc_get_fpacket + .text 0x0000000080008f80 0x50 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DIntr.o) + 0x0000000080008f80 DIntr + .text 0x0000000080008fd0 0x18 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EIntr.o) + 0x0000000080008fd0 EIntr + *fill* 0x0000000080008fe8 0x8 00 + .text 0x0000000080008ff0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSignalSema.o) + 0x0000000080008ff0 iSignalSema + .text 0x0000000080009000 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetReg.o) + 0x0000000080009000 SifSetReg + .text 0x0000000080009010 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifGetReg.o) + 0x0000000080009010 SifGetReg + .text 0x0000000080009020 0x1b0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) + 0x0000000080009150 SifSendCmd + 0x0000000080009190 iSifSendCmd + .text 0x00000000800091d0 0x2a8 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + 0x0000000080009200 SifInitCmd + 0x0000000080009440 SifExitCmd + .text 0x0000000080009478 0x38 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_addhandler.o) + 0x0000000080009478 SifAddCmdHandler + .text 0x00000000800094b0 0x18 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_sreg_get.o) + 0x00000000800094b0 SifGetSreg + .text 0x00000000800094c8 0x78 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EnableDmac.o) + 0x00000000800094c8 EnableDmac + .text 0x0000000080009540 0x78 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DisableDmac.o) + 0x0000000080009540 DisableDmac + *fill* 0x00000000800095b8 0x8 00 + .text 0x00000000800095c0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(AddDmacHandler.o) + 0x00000000800095c0 AddDmacHandler + .text 0x00000000800095d0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(RemoveDmacHandler.o) + 0x00000000800095d0 RemoveDmacHandler + .text 0x00000000800095e0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_EnableDmac.o) + 0x00000000800095e0 _EnableDmac + .text 0x00000000800095f0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_DisableDmac.o) + 0x00000000800095f0 _DisableDmac + .text 0x0000000080009600 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(FlushCache.o) + 0x0000000080009600 FlushCache + .text 0x0000000080009610 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDma.o) + 0x0000000080009610 SifSetDma + .text 0x0000000080009620 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDma.o) + 0x0000000080009620 iSifSetDma + .text 0x0000000080009630 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDChain.o) + 0x0000000080009630 SifSetDChain + .text 0x0000000080009640 0xb0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifWriteBackDCache.o) + 0x0000000080009640 SifWriteBackDCache + .text 0x00000000800096f0 0xe0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_sif_cmd_int_handler.o) + 0x00000000800096f0 _SifCmdIntHandler + .text 0x00000000800097d0 0x10 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDChain.o) + 0x00000000800097d0 iSifSetDChain + .text 0x00000000800097e0 0x6c8 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + 0x00000000800097e0 __udivdi3 + .text 0x0000000080009ea8 0x6c8 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + 0x0000000080009ea8 __umoddi3 + .text 0x000000008000a570 0x308 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + 0x000000008000a808 dpsub + 0x000000008000a7a8 dpadd + .text 0x000000008000a878 0x2d0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + 0x000000008000a878 dpmul + .text 0x000000008000ab48 0x58 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + 0x000000008000ab48 dpcmp + .text 0x000000008000aba0 0xc0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + 0x000000008000aba0 litodp + .text 0x000000008000ac60 0xa0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + 0x000000008000ac60 dptoli + .text 0x000000008000ad00 0x190 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + 0x000000008000ad00 __pack_d + .text 0x000000008000ae90 0xe8 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + 0x000000008000ae90 __unpack_d + .text 0x000000008000af78 0x108 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + 0x000000008000af78 __fpcmp_parts_d + *(.rodata) + .rodata 0x000000008000b080 0x290 eekernel.o + .rodata 0x000000008000b310 0x208 eeinit.o + .rodata 0x000000008000b518 0x48 eeload.o + .rodata 0x000000008000b560 0x30 eeelf.o + .rodata 0x000000008000b590 0x188 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + .rodata 0x000000008000b718 0xe0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + .rodata 0x000000008000b7f8 0x18 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + 0x000000008000b7f8 __thenan_df + .rodata 0x000000008000b810 0x100 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + 0x000000008000b810 __clz_tab + +.reginfo + *(.reginfo) + +.data 0x000000008000b980 0xf88 + *(.data) + .data 0x000000008000b980 0x318 eedata.o + 0x000000008000b980 table_CpuConfig + 0x000000008000ba98 table_SYSCALL + 0x000000008000ba58 DMACTable + 0x000000008000b9f8 VIntTable + 0x000000008000b9c0 VCRTable + 0x000000008000b998 dmac_CHCR + 0x000000008000ba18 INTCTable + .data 0x000000008000bc98 0x660 eekernel.o + 0x000000008000bcac ihandlers_first + 0x000000008000bcb4 dhandlers_first + 0x000000008000bcb0 dhandlers_last + 0x000000008000bcd8 rcnt3TargetTable + 0x000000008000bcb8 CPUTimerHandler + 0x000000008000c1e0 threads_count + 0x000000008000c1f6 transferscount + 0x000000008000bc98 excepRetPc + 0x000000008000bca4 threadStatus + 0x000000008000c1ec semas_count + 0x000000008000c1f8 table_GetCop0 + 0x000000008000bca0 threadPrio + 0x000000008000bc9c threadId + 0x000000008000c1f0 semas_last + 0x000000008000c1e8 excepSP + 0x000000008000bca8 ihandlers_last + 0x000000008000c1f4 tagindex + 0x000000008000c1e4 excepRA + 0x000000008000c278 table_SetCop0 + 0x000000008000bcc0 _alarm_unk + 0x000000008000bcd0 rcnt3Count + 0x000000008000bcc8 rcnt3Valid + .data 0x000000008000c2f8 0x290 eeinit.o + 0x000000008000c568 tlb_config + 0x000000008000c4e8 tlb3_data + 0x000000008000c2f8 tlb1_data + 0x000000008000c3c8 tlb2_data + .data 0x000000008000c588 0x4 romdir.o + 0x000000008000c588 base + *fill* 0x000000008000c58c 0x4 00 + .data 0x000000008000c590 0x248 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + .data 0x000000008000c7d8 0x4 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) + .data 0x000000008000c7dc 0x4 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) + .data 0x000000008000c7e0 0xc /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(malloc.o) + 0x000000008000c7e4 __alloc_heap_head + 0x000000008000c7e0 __alloc_heap_base + 0x000000008000c7e8 __alloc_heap_tail + *fill* 0x000000008000c7ec 0x4 00 + .data 0x000000008000c7f0 0x38 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + 0x000000008000c7f0 _sif_rpc_data + .data 0x000000008000c828 0x4 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(__iop_control_internals.o) + 0x000000008000c828 _iop_reboot_count + *fill* 0x000000008000c82c 0x4 00 + .data 0x000000008000c830 0x30 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + 0x000000008000c830 _sif_cmd_data + .data 0x000000008000c860 0x54 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + 0x000000008000c860 _GLOBAL__F___udivdi3 + .data 0x000000008000c8b4 0x54 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + 0x000000008000c8b4 _GLOBAL__F___umoddi3 + +.rdata + *(.rdata) + 0x0000000080014970 _gp = (ALIGN (0x80) + 0x7ff0) + +.lit4 + *(.lit4) + +.lit8 + *(.lit8) + +.sdata + *(.sdata) + +.sbss 0x000000008000c980 0x0 + 0x000000008000c980 _fbss = . + *(.scommon) + *(.sbss) + +.bss 0x000000008000c980 0x1b40 + *(.bss) + .bss 0x000000008000c980 0x1800 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + .bss 0x000000008000e180 0x340 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + +.COMMON 0x000000008000e500 0xb88c + *(COMMON) + COMMON 0x000000008000e500 0x2e0 eedata.o + 0x0 (size before relaxing) + 0x000000008000e500 SavedRA + 0x000000008000e510 SavedSP + 0x000000008000e520 SavedT9 + 0x000000008000e600 SavedRegs + 0x000000008000e7d0 SavedAT + *fill* 0x000000008000e7e0 0x20 00 + COMMON 0x000000008000e800 0xb574 eekernel.o + 0x0 (size before relaxing) + 0x000000008000e800 intcs_array + 0x000000008000e8a8 threadArgStrBuffer + 0x000000008000e9a8 sifIOPbuff + 0x000000008000e9b0 sifRegs + 0x000000008000ea30 rcnt3TargetNum + 0x000000008000ea70 dword_80016A84 + 0x000000008000ea78 threads_array + 0x0000000080013678 g_kernelstackend + 0x000000008001367c VSyncFlag1 + 0x0000000080013680 handler_ll_free + 0x0000000080013688 gsIMR + 0x0000000080013690 thread_ll_free + 0x0000000080013698 semas_array + 0x00000000800156a0 sifEEbuff + 0x0000000080015720 dword_80016A7C + 0x0000000080015724 machineType + 0x0000000080015728 sbus_handlers + 0x00000000800157a8 thread_ll_priorities + 0x0000000080015bb0 tadrptr + 0x0000000080015da0 _HandlersCount + 0x0000000080015da4 sif1tagdata + 0x0000000080015da8 VSyncFlag0 + 0x0000000080015e00 g_kernelstack + 0x0000000080017e00 osdConfigParam + 0x0000000080017e04 dword_80016A88 + 0x0000000080017e08 pgifhandlers_array + 0x0000000080018d20 dmacs_array + 0x0000000080018dd8 hvParam + 0x0000000080018de0 dword_80016A78 + 0x0000000080018df0 extrastorage + 0x0000000080019d70 memorySize + COMMON 0x0000000080019d74 0x18 eeelf.o + 0x0 (size before relaxing) + 0x0000000080019d74 elfsize + 0x0000000080019d78 sections_names + 0x0000000080019d7c elfdata + 0x0000000080019d80 elfHeader + 0x0000000080019d84 elfProgH + 0x0000000080019d88 elfSectH + 0x0000000080019d88 _end_bss = (. - 0x4) + 0x0000000080019d8c _stack = . + 0x0000000080099d8c . = (. + _stack_size) + 0x0000000080099d64 _end_stack = (. - 0x28) + 0x0000000080099d8c _end = . + 0x0000000080099d8c __lc_bh = . + 0x0000000080a99d8c . = (. + _heap_size) + 0x0000000080a99d8c __lc_eh = . +OUTPUT(../../build/EELOAD binary) + +.mdebug 0x0000000000000000 0x32768 + .mdebug 0x0000000000000000 0xf54 eedata.o + .mdebug 0x0000000000000f54 0x81bc eekernel.o + .mdebug 0x0000000000009110 0xd7c eeinit.o + .mdebug 0x0000000000009e8c 0x228 eeload.o + .mdebug 0x000000000000a0b4 0x424 eeelf.o + .mdebug 0x000000000000a4d8 0x248 eedebug.o + .mdebug 0x000000000000a720 0x1e0 romdir.o + .mdebug 0x000000000000a900 0x340 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memcpy.o) + .mdebug 0x000000000000ac40 0x33c /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(memset.o) + .mdebug 0x000000000000af7c 0x350 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strcpy.o) + .mdebug 0x000000000000b2cc 0x180 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) + .mdebug 0x000000000000b44c 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + .mdebug 0x000000000000b768 0x148 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__sout.o) + .mdebug 0x000000000000b8b0 0x1e8 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) + .mdebug 0x000000000000ba98 0x3a0 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) + .mdebug 0x000000000000be38 0x148 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(isdigit.o) + .mdebug 0x000000000000bf80 0x1ac /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) + .mdebug 0x000000000000c12c 0x350 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(strlen.o) + .mdebug 0x000000000000c47c 0x28c /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(malloc.o) + .mdebug 0x000000000000c708 0x318 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(ResetEE.o) + .mdebug 0x000000000000ca20 0x310 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(Exit.o) + .mdebug 0x000000000000cd30 0x328 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iTerminateThread.o) + .mdebug 0x000000000000d058 0x324 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iWakeupThread.o) + .mdebug 0x000000000000d37c 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EndOfHeap.o) + .mdebug 0x000000000000d698 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(CreateSema.o) + .mdebug 0x000000000000d9b4 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DeleteSema.o) + .mdebug 0x000000000000dcd0 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SignalSema.o) + .mdebug 0x000000000000dfec 0x318 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(WaitSema.o) + .mdebug 0x000000000000e304 0x320 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SetVSyncFlag.o) + .mdebug 0x000000000000e624 0x7d8 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + .mdebug 0x000000000000edfc 0x15c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_rpc_get_fpacket.o) + .mdebug 0x000000000000ef58 0xfc /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(__iop_control_internals.o) + .mdebug 0x000000000000f054 0x144 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DIntr.o) + .mdebug 0x000000000000f198 0x144 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EIntr.o) + .mdebug 0x000000000000f2dc 0x320 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSignalSema.o) + .mdebug 0x000000000000f5fc 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetReg.o) + .mdebug 0x000000000000f918 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifGetReg.o) + .mdebug 0x000000000000fc34 0x2c0 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) + .mdebug 0x000000000000fef4 0x5c4 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + .mdebug 0x00000000000104b8 0x178 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_addhandler.o) + .mdebug 0x0000000000010630 0x170 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_sreg_get.o) + .mdebug 0x00000000000107a0 0x194 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EnableDmac.o) + .mdebug 0x0000000000010934 0x198 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DisableDmac.o) + .mdebug 0x0000000000010acc 0x324 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(AddDmacHandler.o) + .mdebug 0x0000000000010df0 0x32c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(RemoveDmacHandler.o) + .mdebug 0x000000000001111c 0x320 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_EnableDmac.o) + .mdebug 0x000000000001143c 0x320 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_DisableDmac.o) + .mdebug 0x000000000001175c 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(FlushCache.o) + .mdebug 0x0000000000011a78 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDma.o) + .mdebug 0x0000000000011d94 0x31c /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDma.o) + .mdebug 0x00000000000120b0 0x320 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifSetDChain.o) + .mdebug 0x00000000000123d0 0x3f4 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifWriteBackDCache.o) + .mdebug 0x00000000000127c4 0x1ac /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_sif_cmd_int_handler.o) + .mdebug 0x0000000000012970 0x324 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(iSifSetDChain.o) + .mdebug 0x0000000000012c94 0x3c7c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .mdebug 0x0000000000016910 0x3cd4 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .mdebug 0x000000000001a5e4 0x35f0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .mdebug 0x000000000001dbd4 0x3ccc /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .mdebug 0x00000000000218a0 0x1f0c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .mdebug 0x00000000000237ac 0x2118 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .mdebug 0x00000000000258c4 0x22dc /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .mdebug 0x0000000000027ba0 0x1be0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .mdebug 0x0000000000029780 0x1a8c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .mdebug 0x000000000002b20c 0x2968 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .mdebug 0x000000000002db74 0x2398 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .mdebug 0x000000000002ff0c 0x285c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.mdebug.eabi64 0x0000000000000000 0x0 + +.comment 0x0000000000000000 0x2be + .comment 0x0000000000000000 0x12 eedata.o + .comment 0x0000000000000012 0x12 eekernel.o + .comment 0x0000000000000024 0x12 eeinit.o + .comment 0x0000000000000036 0x12 eeload.o + .comment 0x0000000000000048 0x12 eeelf.o + .comment 0x000000000000005a 0x12 eedebug.o + .comment 0x000000000000006c 0x12 romdir.o + .comment 0x000000000000007e 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vsnprintf.o) + .comment 0x0000000000000090 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(vxprintf.o) + .comment 0x00000000000000a2 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__sout.o) + .comment 0x00000000000000b4 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(free.o) + .comment 0x00000000000000c6 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(__alloc_internals.o) + .comment 0x00000000000000d8 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(isdigit.o) + .comment 0x00000000000000ea 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(sbrk.o) + .comment 0x00000000000000fc 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libc.a(malloc.o) + .comment 0x000000000000010e 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(SifRpcMain.o) + .comment 0x0000000000000120 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_rpc_get_fpacket.o) + .comment 0x0000000000000132 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(__iop_control_internals.o) + .comment 0x0000000000000144 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DIntr.o) + .comment 0x0000000000000156 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EIntr.o) + .comment 0x0000000000000168 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_send.o) + .comment 0x000000000000017a 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_main.o) + .comment 0x000000000000018c 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_cmd_addhandler.o) + .comment 0x000000000000019e 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(sif_sreg_get.o) + .comment 0x00000000000001b0 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(EnableDmac.o) + .comment 0x00000000000001c2 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(DisableDmac.o) + .comment 0x00000000000001d4 0x12 /usr/local/ps2dev/ps2sdk/ee/lib/libkernel.a(_sif_cmd_int_handler.o) + .comment 0x00000000000001e6 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .comment 0x00000000000001f8 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .comment 0x000000000000020a 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .comment 0x000000000000021c 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .comment 0x000000000000022e 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .comment 0x0000000000000240 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .comment 0x0000000000000252 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .comment 0x0000000000000264 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .comment 0x0000000000000276 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .comment 0x0000000000000288 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .comment 0x000000000000029a 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .comment 0x00000000000002ac 0x12 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_abbrev 0x0000000000000000 0x1408 + .debug_abbrev 0x0000000000000000 0x1cd /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_abbrev 0x00000000000001cd 0x1dc /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_abbrev 0x00000000000003a9 0x20f /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_abbrev 0x00000000000005b8 0x22a /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_abbrev 0x00000000000007e2 0x180 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_abbrev 0x0000000000000962 0x180 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_abbrev 0x0000000000000ae2 0x1bf /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_abbrev 0x0000000000000ca1 0x146 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_abbrev 0x0000000000000de7 0x10d /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_abbrev 0x0000000000000ef4 0x1ca /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_abbrev 0x00000000000010be 0x19a /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_abbrev 0x0000000000001258 0x1b0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_info 0x0000000000000000 0x60b3 + .debug_info 0x0000000000000000 0xaeb /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_info 0x0000000000000aeb 0xaf8 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_info 0x00000000000015e3 0x91b /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_info 0x0000000000001efe 0x9a1 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_info 0x000000000000289f 0x6fd /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_info 0x0000000000002f9c 0x6c5 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_info 0x0000000000003661 0x778 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_info 0x0000000000003dd9 0x686 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_info 0x000000000000445f 0x5e2 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_info 0x0000000000004a41 0x791 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_info 0x00000000000051d2 0x6ee /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_info 0x00000000000058c0 0x7f3 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_line 0x0000000000000000 0x18ce + .debug_line 0x0000000000000000 0x3a4 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_line 0x00000000000003a4 0x3b4 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_line 0x0000000000000758 0x387 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_line 0x0000000000000adf 0x407 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_line 0x0000000000000ee6 0xc6 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_line 0x0000000000000fac 0x110 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_line 0x00000000000010bc 0x136 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_line 0x00000000000011f2 0x83 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_line 0x0000000000001275 0xd9 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_line 0x000000000000134e 0x232 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_line 0x0000000000001580 0x19e /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_line 0x000000000000171e 0x1b0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_frame 0x0000000000000000 0x210 + .debug_frame 0x0000000000000000 0x40 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_frame 0x0000000000000040 0x40 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_frame 0x0000000000000080 0x58 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_frame 0x00000000000000d8 0x3c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_frame 0x0000000000000114 0x2c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_frame 0x0000000000000140 0x28 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_frame 0x0000000000000168 0x28 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_frame 0x0000000000000190 0x10 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_frame 0x00000000000001a0 0x10 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_frame 0x00000000000001b0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_frame 0x00000000000001d0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_frame 0x00000000000001f0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_pubnames + 0x0000000000000000 0x180 + .debug_pubnames + 0x0000000000000000 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_pubnames + 0x0000000000000020 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_pubnames + 0x0000000000000040 0x26 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_pubnames + 0x0000000000000066 0x1c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_pubnames + 0x0000000000000082 0x1c /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_pubnames + 0x000000000000009e 0x1d /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_pubnames + 0x00000000000000bb 0x1d /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_pubnames + 0x00000000000000d8 0x22 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_pubnames + 0x00000000000000fa 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_pubnames + 0x000000000000011a 0x1f /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_pubnames + 0x0000000000000139 0x21 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_pubnames + 0x000000000000015a 0x26 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_aranges 0x0000000000000000 0x140 + .debug_aranges + 0x0000000000000000 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_aranges + 0x0000000000000020 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_aranges + 0x0000000000000040 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_aranges + 0x0000000000000060 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_aranges + 0x0000000000000080 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_aranges + 0x00000000000000a0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_aranges + 0x00000000000000c0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_aranges + 0x00000000000000e0 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_aranges + 0x0000000000000100 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_aranges + 0x0000000000000120 0x20 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) + +.debug_ranges 0x0000000000000000 0x2d0 + .debug_ranges 0x0000000000000000 0x100 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_ranges 0x0000000000000100 0x100 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_ranges 0x0000000000000200 0x18 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_ranges 0x0000000000000218 0xa0 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_ranges 0x00000000000002b8 0x18 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + +.debug_str 0x0000000000000000 0x5fd1 + .debug_str 0x0000000000000000 0x7d7 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_udivdi3.o) + .debug_str 0x00000000000007d7 0x7d7 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_umoddi3.o) + .debug_str 0x0000000000000fae 0x85e /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_addsub_df.o) + .debug_str 0x000000000000180c 0x848 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_mul_df.o) + .debug_str 0x0000000000002054 0x7f9 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_compare_df.o) + .debug_str 0x000000000000284d 0x7f4 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_si_to_df.o) + .debug_str 0x0000000000003041 0x807 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_df_to_si.o) + .debug_str 0x0000000000003848 0x7e7 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_thenan_df.o) + .debug_str 0x000000000000402f 0x79d /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_clz.o) + .debug_str 0x00000000000047cc 0x809 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_pack_df.o) + .debug_str 0x0000000000004fd5 0x7f2 /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_unpack_df.o) + .debug_str 0x00000000000057c7 0x80a /usr/local/ps2dev/ee/lib/gcc-lib/ee/3.2.2/libgcc.a(_fpcmp_parts_df.o) diff --git a/fps2bios/kernel/eeload/include/eedebug.h b/fps2bios/kernel/eeload/include/eedebug.h new file mode 100644 index 0000000000..dfe853c609 --- /dev/null +++ b/fps2bios/kernel/eeload/include/eedebug.h @@ -0,0 +1,12 @@ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/kernel/eeload/include/eeelf.h b/fps2bios/kernel/eeload/include/eeelf.h new file mode 100644 index 0000000000..8f5019bc4b --- /dev/null +++ b/fps2bios/kernel/eeload/include/eeelf.h @@ -0,0 +1,6 @@ +#ifndef __EEELF_H__ +#define __EEELF_H__ + +u32 loadElfFile(char *filename); + +#endif diff --git a/fps2bios/kernel/eeload/include/eeinit.h b/fps2bios/kernel/eeload/include/eeinit.h new file mode 100644 index 0000000000..19789ca566 --- /dev/null +++ b/fps2bios/kernel/eeload/include/eeinit.h @@ -0,0 +1,8 @@ +#ifndef __EEINIT_H__ +#define __EEINIT_H__ + +#include + +void TlbInit(); + +#endif /* __EEINIT_H__ */ diff --git a/fps2bios/kernel/eeload/include/eeirq.h b/fps2bios/kernel/eeload/include/eeirq.h new file mode 100644 index 0000000000..9fbccc0a0f --- /dev/null +++ b/fps2bios/kernel/eeload/include/eeirq.h @@ -0,0 +1,17 @@ +#ifndef __EEIRQ_H__ +#define __EEIRQ_H__ + +#include + +void CpuException0(); +void CpuException(); +void CpuException2(); +void SyscException(); +void _Deci2Call(); +void INTCException(); +void DMACException(); +void TIMERException(); +void setINTCHandler(int n, void (*phandler)(int)); +void setDMACHandler(int n, void (*phandler)(int)); + +#endif /* __EEIRQ_H__ */ diff --git a/fps2bios/kernel/eeload/include/eekernel.h b/fps2bios/kernel/eeload/include/eekernel.h new file mode 100644 index 0000000000..aedd830883 --- /dev/null +++ b/fps2bios/kernel/eeload/include/eekernel.h @@ -0,0 +1,447 @@ +#ifndef __EEKERNEL_H__ +#define __EEKERNEL_H__ + +#include +#include + + +#define RCNT0_COUNT *(volatile int*)0xB0000000 +#define RCNT0_MODE *(volatile int*)0xB0000010 +#define RCNT0_TARGET *(volatile int*)0xB0000020 +#define RCNT0_HOLD *(volatile int*)0xB0000030 + +#define RCNT1_COUNT *(volatile int*)0xB0000800 +#define RCNT1_MODE *(volatile int*)0xB0000810 +#define RCNT1_TARGET *(volatile int*)0xB0000820 +#define RCNT1_HOLD *(volatile int*)0xB0000830 + +#define RCNT2_COUNT *(volatile int*)0xB0001000 +#define RCNT2_MODE *(volatile int*)0xB0001010 +#define RCNT2_TARGET *(volatile int*)0xB0001020 + +#define RCNT3_COUNT *(volatile int*)0xB0001800 +#define RCNT3_MODE *(volatile int*)0xB0001810 +#define RCNT3_TARGET *(volatile int*)0xB0001820 + +#define GIF_CTRL *(volatile int*)0xB0003000 + +#define GIF_FIFO *(volatile u128*)0xB0006000 + +//SIF0 +#define D5_CHCR *(volatile int*)0xB000C000 +#define D5_MADR *(volatile int*)0xB000C010 +#define D5_QWC *(volatile int*)0xB000C020 + +//SIF1 +#define D6_CHCR *(volatile int*)0xB000C400 +#define D6_MADR *(volatile int*)0xB000C410 +#define D6_QWC *(volatile int*)0xB000C420 +#define D6_TAG *(volatile int*)0xB000C430 + +#define DMAC_CTRL *(volatile int*)0xB000E000 +#define DMAC_STAT *(volatile int*)0xB000E010 +#define DMAC_PCR *(volatile int*)0xB000E020 +#define DMAC_SQWC *(volatile int*)0xB000E030 +#define DMAC_RBSR *(volatile int*)0xB000E040 +#define DMAC_RBOR *(volatile int*)0xB000E050 +#define DMAC_STADR *(volatile int*)0xB000E060 + +#define INTC_STAT *(volatile int*)0xB000F000 +#define INTC_MASK *(volatile int*)0xB000F010 + +#define SBUS_MSFLG *(volatile int*)0xB000F220 +#define SBUS_SMFLG *(volatile int*)0xB000F230 +#define SBUS_F240 *(volatile int*)0xB000F240 + +#define DMAC_ENABLER *(volatile int*)0xB000F520 +#define DMAC_ENABLEW *(volatile int*)0xB000F590 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + +#define GS_PMODE *(volatile u64*)0xB2000000 +#define GS_SMODE1 *(volatile u64*)0xB2000010 +#define GS_SMODE2 *(volatile u64*)0xB2000020 +#define GS_SRFSH *(volatile u64*)0xB2000030 +#define GS_SYNCH1 *(volatile u64*)0xB2000040 +#define GS_SYNCH2 *(volatile u64*)0xB2000050 +#define GS_SYNCV *(volatile u64*)0xB2000060 +#define GS_DISPFB1 *(volatile u64*)0xB2000070 +#define GS_DISPLAY1 *(volatile u64*)0xB2000080 +#define GS_DISPFB2 *(volatile u64*)0xB2000090 +#define GS_DISPLAY2 *(volatile u64*)0xB20000A0 +#define GS_EXTBUF *(volatile u64*)0xB20000B0 +#define GS_EXTDATA *(volatile u64*)0xB20000C0 +#define GS_EXTWRITE *(volatile u64*)0xB20000D0 +#define GS_BGCOLOR *(volatile u64*)0xB20000E0 +#define GS_CSR *(volatile u64*)0xB2001000 +#define GS_IMR *(volatile u64*)0xB2001010 +#define GS_BUSDIR *(volatile u64*)0xB2001040 +#define GS_SIGLBLID *(volatile u64*)0xB2001080 + +#define INTC_GS 0 +#define INTC_SBUS 1 +#define INTC_VBLANK_S 2 +#define INTC_VBLANK_E 3 +#define INTC_VIF0 4 +#define INTC_VIF1 5 +#define INTC_VU0 6 +#define INTC_VU1 7 +#define INTC_IPU 8 +#define INTC_TIM0 9 +#define INTC_TIM1 10 +#define INTC_TIM2 11 +#define INTC_TIM3 12 //threads +//#define INTC_13 13 //not used +//#define INTC_14 14 //not used + +#define DMAC_VIF0 0 +#define DMAC_VIF1 1 +#define DMAC_GIF 2 +#define DMAC_FROM_IPU 3 +#define DMAC_TO_IPU 4 +#define DMAC_SIF0 5 +#define DMAC_SIF1 6 +#define DMAC_SIF2 7 +#define DMAC_FROM_SPR 8 +#define DMAC_TO_SPR 9 +//#define DMAC_10 10 //not used +//#define DMAC_11 11 //not used +//#define DMAC_12 12 //not used +//#define DMAC_13 13 //not used +//#define DMAC_14 14 //not used +#define DMAC_ERROR 15 + + /////////////////////// + // DMA TAG REGISTERS // + /////////////////////// + #define DMA_TAG_REFE 0x00 + #define DMA_TAG_CNT 0x01 + #define DMA_TAG_NEXT 0x02 + #define DMA_TAG_REF 0x03 + #define DMA_TAG_REFS 0x04 + #define DMA_TAG_CALL 0x05 + #define DMA_TAG_RET 0x06 + #define DMA_TAG_END 0x07 + +// Modes for DMA transfers +#define SIF_DMA_FROM_IOP 0x0 +#define SIF_DMA_TO_IOP 0x1 +#define SIF_DMA_FROM_EE 0x0 +#define SIF_DMA_TO_EE 0x1 + +#define SIF_DMA_INT_I 0x2 +#define SIF_DMA_INT_O 0x4 +#define SIF_DMA_SPR 0x8 +#define SIF_DMA_BSN 0x10 /* ? what is this? */ +#define SIF_DMA_TAG 0x20 +#define SIF_DMA_ERT 0x40 +#define DMA_TAG_IRQ 0x80000000 +#define DMA_TAG_PCE 0x0C000000 + +#define KSEG1_ADDR(x) (((u32)(x))|0xA0000000) +#define KUSEG_ADDR(x) (((u32)(x))&0x1FFFFFFF) + +#define MAX_SEMAS 256 +#define STACK_RES 0x2A0 + +//? +#define SRInitVal 0x70030C13 +#define ConfigInitVal 0x73003 + +enum { + THS_RUN = 0x01, + THS_READY = 0x02, + THS_WAIT = 0x04, + THS_SUSPEND = 0x08, + THS_DORMANT = 0x10, +}; + +typedef struct { + u128 gpr[24]; // v0-t9 (skip r0,at,k0-ra) + u128 gp; + u128 fp; + u128 hi; + u128 lo; + u32 sa; +} eeRegs; + +struct ThreadParam { + int status; + void (*entry)(void*); + void *stack; + int stackSize; + void *gpReg; + int initPriority; + int currentPriority; + u32 attr; + u32 option; + int waitSema; // waitType? + int waitId; + int wakeupCount; +}; + +struct TCB { //internal struct + struct TCB *next; //+00 + struct TCB *prev; //+04 + int status;//+08 + void (*entry)(void*); //+0C + void *stack_res; //+10 initial $sp + void *gpReg; //+14 + short currentPriority; //+18 + short initPriority; //+1A + int waitSema, //+1C waitType? + semaId, //+20 + wakeupCount, //+24 + attr, //+28 + option; //+2C + void (*entry_)(void*); //+30 + int argc; //+34 + char *argstring;//+38 + void *stack;//+3C + int stackSize; //+40 + int (*root)(); //+44 + void* heap_base; //+48 +}; + +struct threadCtx { + u128 gpr[25]; // at-t9, (skip r0,k0-ra) + u128 gp; //+190 + u128 sp; //+1A0 + u128 fp; //+1B0 + u128 ra; //+1C0 + u128 hi; //+1D0 + u128 lo; //+1E0 + u32 sa; //+1F0 + u32 cf31;//+1F4 + u32 acc; //+1F8 + u32 res; //+1FC + u32 fpr[32];//+200 +}; + +typedef struct tag_ARGS{ + int argc; + char *argv[16]; + char args[256]; +} ARGS; + +struct SemaParam { + int count; + int max_count; + int init_count; + int wait_threads; + int attr; + u32 option; +}; + +struct kSema { // internal struct + struct kSema *free;//+00 + int count;//+04 + int max_count;//+08 + int attr;//+0C + int option;//+10 + int wait_threads;//+14 + struct TCB *wait_next,//+18 + *wait_prev;//+1C +}; + +struct ll { struct ll *next, *prev; }; //linked list + +//internal struct +struct IDhandl { //intc dmac handler + struct ll *next, //+00 + *prev; //+04 + int (*handler)(int); //+08 + u32 gp; //+0C + void *arg; //+10 + int flag; //+14 +}; + +//internal struct +struct HCinfo{ //handler cause info + int count; + struct ll l; +}; + +extern u128 SavedSP; +extern u128 SavedRA; +extern u128 SavedAT; +extern u64 SavedT9; + +extern eeRegs SavedRegs; + +extern u32 excepRA; +extern u32 excepSP; + +extern u32 (*table_CpuConfig[6])(u32); +extern void (*table_SYSCALL[0x80])(); + +extern void (*VCRTable[14])(); +extern void (*VIntTable[8])(); +extern void (*INTCTable[16])(int); +extern void (*DMACTable[16])(int); + +extern int threadId; +extern int threadPrio; +extern int threadStatus; + +extern u64 hvParam; + +extern u32 machineType; +extern u64 gsIMR; +extern u32 memorySize; + +extern u32 g_kernelstackend; + +extern u32 dmac_CHCR[10]; + +extern int VSyncFlag0; +extern int VSyncFlag1; + +extern int _HandlersCount; +extern struct ll handler_ll_free, *ihandlers_last, *ihandlers_first; +extern struct HCinfo intcs_array[14]; +extern struct ll *dhandlers_last, *dhandlers_first; +extern struct HCinfo dmacs_array[15]; +extern struct IDhandl pgifhandlers_array[161]; +extern void (*sbus_handlers[32])(int ca); + +extern int rcnt3Code; +extern int rcnt3TargetTable[0x142]; +extern u8 rcnt3TargetNum[0x40]; +extern int threads_count; +extern struct ll thread_ll_free; +extern struct ll thread_ll_priorities[128]; +extern int semas_count; +extern struct kSema* semas_last; + +extern struct TCB threads_array[256]; +extern struct kSema semas_array[256]; + +extern char tagindex; +extern short transferscount; +extern struct TAG{ + int id_qwc; + int addr; + int unk[2]; +} tadrptr[31]; +extern int extrastorage[(16/4) * 8][31]; + +extern int osdConfigParam; + +// syscalls +// Every syscall is officially prefixed with _ (to avoid clashing with ps2sdk) +void _SetSYSCALL(int num, int address); +int __EnableIntc(int ch); +int __DisableIntc(int ch); +int __EnableDmac(int ch); +int __DisableDmac(int ch); +void *_SetVTLBRefillHandler(int cause, void (*handler)()); +void *_SetVCommonHandler(int cause, void (*handler)()); +void *_SetVInterruptHandler(int cause, void (*handler)()); +void _PSMode(); +u32 _MachineType(); +u32 _SetMemorySize(u32 size); +u32 _GetMemorySize(); +u64 _GsGetIMR(); +u64 _GsPutIMR(u64 val); +int _Exit(); // 3 +void _RFU___(); // 0 +void _SetVSyncFlag(int flag0, int flag1); +int _AddIntcHandler(int cause, int (*handler)(int), int next, void *arg); +int _AddIntcHandler2(int cause, int (*handler)(int), int next, void *arg); +int _RemoveIntcHandler(int cause, int hid); +int _AddDmacHandler(int cause, int (*handler)(int), int next, void *arg); +int _AddDmacHandler2(int cause, int (*handler)(int), int next, void *arg); +int _RemoveDmacHandler(int code, int hid); +int _AddSbusIntcHandler(int cause, void (*handler)(int ca)); +int _RemoveSbusIntcHandler(int cause); +int _Interrupt2Iop(int cause); +void _RFU005(); +int _GetCop0(int reg); +int _ExecPS2(void *, void *, int, char **); +int _DeleteThread(int tid); +int _StartThread(int tid, void *arg); +int _ExitThread(); +int _ExitDeleteThread(); +int _SleepThread(); +int _WakeupThread(int tid); +int _WaitSema(int sid); +void _ChangeThreadPriority(int tid, int prio); +int _CreateThread(struct ThreadParam *param); +int _iChangeThreadPriority(int tid, int prio); +int _GetThreadId(); +int _ReferThreadStatus(int tid, struct ThreadParam *info); +int _iWakeupThread(int tid); +int _SuspendThread(int thid); +int _iResumeThread(int tid); +int _CancelWakeupThread(int tid); +int _CreateEventFlag(); +int _CreateSema(struct SemaParam *sema); +int _RFU073(int sid); +int _iSignalSema(int sid); +int _PollSema(int sid); +int _ReferSemaStatus(int sid, struct SemaParam *sema); +int _DeleteEventFlag(); +void*_InitializeMainThread(u32 gp, void *stack, int stack_size, + char *args, int root); +void *_InitializeHeapArea(void *heap_base, int heap_size); +void *_EndOfHeap(); +int _LoadPS2Exe(char *filename, int argc, char **argv); +int _ExecOSD(int argc, char **argv); +void _SifSetDChain(); +void _SifStopDma(); +u32 _SifSetDma(SifDmaTransfer_t *sdd, int len); +void _SetGsCrt(short arg0, short arg1, short arg2); // 2 +void _GetGsHParam(int *p0, int *p1, int *p2, int *p3); +int _GetGsVParam(); +void _SetGsVParam(int VParam); +void _GetOsdConfigParam(int *result); +void _SetOsdConfigParam(int *param); +int _ResetEE(int init); // 1 +int _TlbWriteRandom(u32 PageMask, u32 EntryHi, u32 EntryLo0, u32 EntryLo1); +int _SetAlarm(short a0, int a1, int a2); +void _ReleaseAlarm(); +int _TerminateThread(int tid); +void _RotateThreadReadyQueue(int prio); +int _iTerminateThread(int tid); +int _DisableDispatchThread(); +int _EnableDispatchThread(); +int _iRotateThreadReadyQueue(int prio); +void _ReleaseWaitThread(int tid); +int _iReleaseWaitThread(int tid); +int _ResumeThread(int tid); +int _iResumeThread(int tid); +void _JoinThread(); +int _DeleteSema(int sid); +int _iDeleteSema(int sid); +void _SignalSema(int sid); +void _SetGsHParam(int a0, int a1, int a2, int a3); +int _SetEventFlag(int ef, u32 bits); // bits is EF_X +int _iSetEventFlag(int ef, u32 bits); +void _EnableIntcHandler(u32 id); +void _DisableIntcHandler(u32 id); +void _EnableDmacHandler(u32 id); +void _DisableDmacHandler(u32 id); +void _KSeg0(u32 arg); +int _EnableCache(int cache); +int _DisableCache(int cache); +void _FlushCache(int op); +void _105(int op1, int op2); +u32 _CpuConfig(u32 op); +void _SetCPUTimerHandler(void (*handler)()); +void _SetCPUTimer(int compval); +void _SetPgifHandler(void (*handler)(int)); +void _print(); +int _SifDmaStat(int id); + +int _SifGetReg(int reg); +int _SifSetReg(int reg, u32 val); + +//////////////////////////////////////////////////////////////////// +// KERNEL BSS // +//////////////////////////////////////////////////////////////////// + + +#endif + diff --git a/fps2bios/kernel/eeload/include/eeload.h b/fps2bios/kernel/eeload/include/eeload.h new file mode 100644 index 0000000000..ba6af54200 --- /dev/null +++ b/fps2bios/kernel/eeload/include/eeload.h @@ -0,0 +1,4 @@ +#ifndef __EELOAD_H__ +#define __EELOAD_H__ + +#endif /* __EELOAD_H__ */ diff --git a/fps2bios/kernel/eeload/include/romdir.h b/fps2bios/kernel/eeload/include/romdir.h new file mode 100644 index 0000000000..8249989e78 --- /dev/null +++ b/fps2bios/kernel/eeload/include/romdir.h @@ -0,0 +1,20 @@ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/eeload/linkfile b/fps2bios/kernel/eeload/linkfile new file mode 100644 index 0000000000..b6c0668fe0 --- /dev/null +++ b/fps2bios/kernel/eeload/linkfile @@ -0,0 +1,56 @@ +_stack_size = 0x80000; +_heap_size = 1024*1024*10; + +ENTRY(_start); +SECTIONS { + + . 0x80000000 : { + eeirq.o + } + + .text 0x80001000 : { + *(.text) + *(.rodata) + } + .reginfo ALIGN(128) : { + *(.reginfo) + } + .data ALIGN(128) : { + *(.data) + } + .rdata ALIGN(128) : { + *(.rdata) + } + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128) : { + *(.lit4) + } + .lit8 ALIGN(128) : { + *(.lit8) + } + .sdata ALIGN(128) : { + *(.sdata) + } + + .sbss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + _fbss = . ; + *(.scommon) + *(.sbss) + } + .bss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(.bss) + } + .COMMON ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(COMMON) + } + _end_bss = . - 4; + _stack = .; + . += _stack_size ; + _end_stack = . - 8*5; + _end = . ; + __lc_bh = . ; + . += _heap_size ; + __lc_eh = .; + +} + diff --git a/fps2bios/kernel/eeload/romdir.c b/fps2bios/kernel/eeload/romdir.c new file mode 100644 index 0000000000..3494074eda --- /dev/null +++ b/fps2bios/kernel/eeload/romdir.c @@ -0,0 +1,47 @@ +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *base = NULL; + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; +// struct romdir *base; + int i; + + if (base == NULL) { + base = romdirInit(); + if (base == NULL) return NULL; + } + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/eestart.c b/fps2bios/kernel/eestart.c new file mode 100644 index 0000000000..edb1b6f5b5 --- /dev/null +++ b/fps2bios/kernel/eestart.c @@ -0,0 +1,50 @@ +#include +#include "romdir.h" + +static void Kputc(u8 c) { + *((u8*)0x1000f180) = c; +} + +static void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +static void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n > 0) { + *d++ = *s++; n--; + } +} + +void _eestart() { + struct rominfo ri; + u8 *str; + + romdirGetFile("ROMVER", &ri); + str = (u8*)(0xbfc00000 + ri.fileOffset); + Kputs("fps2bios v"); + Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); + + romdirGetFile("EELOAD", &ri); + + Kputs("loading EELOAD to 0x80000000\n"); + + Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); + + __asm__ ( + "li $26, 0x80001000\n" + "jr $26\n"); + for (;;); +} + +__asm__ ( + ".global eestart\n" + "eestart:\n" + "li $sp, 0x80010000\n" + "j _eestart\n"); + + diff --git a/fps2bios/kernel/iopload/Makefile b/fps2bios/kernel/iopload/Makefile new file mode 100644 index 0000000000..614a3983a3 --- /dev/null +++ b/fps2bios/kernel/iopload/Makefile @@ -0,0 +1,67 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: iopload + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = romdir.o iopelf.o iopdebug.o +DIRS = iopboot sysmem loadcore excepman intrman stdio timrman \ + dmacman sifman sifcmd ssbusc sysclib heaplib \ + vblank threadman sio2man + +iopload: $(OBJECTS) + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/dmacman/Makefile b/fps2bios/kernel/iopload/dmacman/Makefile new file mode 100644 index 0000000000..51769e589a --- /dev/null +++ b/fps2bios/kernel/iopload/dmacman/Makefile @@ -0,0 +1,60 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: dmacman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = dmacman.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sysmem.o + +dmacman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/DMACMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/dmacman/dmacman.c b/fps2bios/kernel/iopload/dmacman/dmacman.c new file mode 100644 index 0000000000..db60e3acfe --- /dev/null +++ b/fps2bios/kernel/iopload/dmacman/dmacman.c @@ -0,0 +1,923 @@ +//[module] DMACMAN +//[processor] IOP +//[type] ELF-IRX +//[name] dmacman +//[version] 0x101 +//[memory map] 0xBF801080,0xBF801084,0xBF801088, 00 mdec in +// 0xBF801090,0xBF801094,0xBF801098, 01 mdec out +// 0xBF8010A0,0xBF8010A4,0xBF8010A8, 02 gpu +// 0xBF8010B0,0xBF8010B4,0xBF8010B8, 03 cdrom/dvd +// 0xBF8010C0,0xBF8010C4,0xBF8010C8, 0xBF8010CC, 04 spu +// 0xBF8010D0,0xBF8010D4,0xBF8010D8, 05 pio +// 0xBF8010E0,0xBF8010E4,0xBF8010E8, 06 gpu otc +// +// 0xBF8010F0,0xBF8010F4, +// +// 0xBF801500,0xBF801504,0xBF801508, 07 SPU2 +// 0xBF801510,0xBF801514,0xBF801518, 08 +// 0xBF801520,0xBF801524,0xBF801528, 0xBF80152C, 09 SIF0 +// 0xBF801530,0xBF801534,0xBF801538, 10 SIF1 +// 0xBF801540,0xBF801544,0xBF801548, 11 SIO2in +// 0xBF801550,0xBF801554,0xBF801558, 12 SIO2out +// +// 0xBF801560,0xBF801564,0xBF801568, //sifman +// sif0 sif1 spu +// +// 0xBF801570, 0xBF801574,0xBF801578,0xBF80157C, //sifman +// 0xBF8015F0 +//[handlers] - +//[entry point] dmacman_start, dmacman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include + +#include "kloadcore.h" +#include "kintrman.h" +#include "kdmacman.h" + + +int _start(int argc, char* argv[]); + +/////////////////////////////////////////////////////////////////////// +void _setBF801080(unsigned int ch, int value){ + *(int*)0xBF801080=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801090(unsigned int ch, int value){ + *(int*)0xBF801090=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A0(unsigned int ch, int value){ + *(int*)0xBF8010A0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B0(unsigned int ch, int value){ + *(int*)0xBF8010B0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C0(unsigned int ch, int value){ + *(int*)0xBF8010C0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D0(unsigned int ch, int value){ + *(int*)0xBF8010D0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E0(unsigned int ch, int value){ + *(int*)0xBF8010E0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801500(unsigned int ch, int value){ + *(int*)0xBF801500=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801510(unsigned int ch, int value){ + *(int*)0xBF801510=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801520(unsigned int ch, int value){ + *(int*)0xBF801520=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801530(unsigned int ch, int value){ + *(int*)0xBF801530=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801540(unsigned int ch, int value){ + *(int*)0xBF801540=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801550(unsigned int ch, int value){ + *(int*)0xBF801550=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801080(unsigned int ch){ + return *(int*)0xBF801080; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801090(unsigned int ch){ + return *(int*)0xBF801090; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A0(unsigned int ch){ + return *(int*)0xBF8010A0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B0(unsigned int ch){ + return *(int*)0xBF8010B0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C0(unsigned int ch){ + return *(int*)0xBF8010C0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D0(unsigned int ch){ + return *(int*)0xBF8010D0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E0(unsigned int ch){ + return *(int*)0xBF8010E0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801500(unsigned int ch){ + return *(int*)0xBF801500; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801510(unsigned int ch){ + return *(int*)0xBF801510; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801520(unsigned int ch){ + return *(int*)0xBF801520; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801530(unsigned int ch){ + return *(int*)0xBF801530; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801540(unsigned int ch){ + return *(int*)0xBF801540; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801550(unsigned int ch){ + return *(int*)0xBF801550; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801084(unsigned int ch, int value){ + *(int*)0xBF801084=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801094(unsigned int ch, int value){ + *(int*)0xBF801094=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A4(unsigned int ch, int value){ + *(int*)0xBF8010A4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B4(unsigned int ch, int value){ + *(int*)0xBF8010B4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C4(unsigned int ch, int value){ + *(int*)0xBF8010C4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D4(unsigned int ch, int value){ + *(int*)0xBF8010D4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E4(unsigned int ch, int value){ + *(int*)0xBF8010E4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801504(unsigned int ch, int value){ + *(int*)0xBF801504=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801514(unsigned int ch, int value){ + *(int*)0xBF801514=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801524(unsigned int ch, int value){ + *(int*)0xBF801524=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801534(unsigned int ch, int value){ + *(int*)0xBF801534=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801544(unsigned int ch, int value){ + *(int*)0xBF801544=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801554(unsigned int ch, int value){ + *(int*)0xBF801554=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801084(unsigned int ch){ + return *(int*)0xBF801084; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801094(unsigned int ch){ + return *(int*)0xBF801094; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A4(unsigned int ch){ + return *(int*)0xBF8010A4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B4(unsigned int ch){ + return *(int*)0xBF8010B4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C4(unsigned int ch){ + return *(int*)0xBF8010C4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D4(unsigned int ch){ + return *(int*)0xBF8010D4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E4(unsigned int ch){ + return *(int*)0xBF8010E4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801504(unsigned int ch){ + return *(int*)0xBF801504; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801514(unsigned int ch){ + return *(int*)0xBF801514; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801524(unsigned int ch){ + return *(int*)0xBF801524; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801534(unsigned int ch){ + return *(int*)0xBF801534; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801544(unsigned int ch){ + return *(int*)0xBF801544; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801554(unsigned int ch){ + return *(int*)0xBF801554; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801088(unsigned int ch, int value){ + *(int*)0xBF801088=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801098(unsigned int ch, int value){ + *(int*)0xBF801098=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A8(unsigned int ch, int value){ + *(int*)0xBF8010A8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B8(unsigned int ch, int value){ + *(int*)0xBF8010B8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C8(unsigned int ch, int value){ + *(int*)0xBF8010C8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D8(unsigned int ch, int value){ + *(int*)0xBF8010D8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E8(unsigned int ch, int value){ + *(int*)0xBF8010E8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801508(unsigned int ch, int value){ + *(int*)0xBF801508=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801518(unsigned int ch, int value){ + *(int*)0xBF801518=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801528(unsigned int ch, int value){ + *(int*)0xBF801528=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801538(unsigned int ch, int value){ + *(int*)0xBF801538=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801548(unsigned int ch, int value){ + *(int*)0xBF801548=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801558(unsigned int ch, int value){ + *(int*)0xBF801558=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801088(unsigned int ch){ + return *(int*)0xBF801088; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801098(unsigned int ch){ + return *(int*)0xBF801098; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A8(unsigned int ch){ + return *(int*)0xBF8010A8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B8(unsigned int ch){ + return *(int*)0xBF8010B8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C8(unsigned int ch){ + return *(int*)0xBF8010C8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D8(unsigned int ch){ + return *(int*)0xBF8010D8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E8(unsigned int ch){ + return *(int*)0xBF8010E8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801508(unsigned int ch){ + return *(int*)0xBF801508; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801518(unsigned int ch){ + return *(int*)0xBF801518; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801528(unsigned int ch){ + return *(int*)0xBF801528; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801538(unsigned int ch){ + return *(int*)0xBF801538; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801548(unsigned int ch){ + return *(int*)0xBF801548; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801558(unsigned int ch){ + return *(int*)0xBF801558; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_TADR(unsigned int ch, int value){ + if (ch==DMAch_SPU) + *(int*)0xBF8010CC=value; else + if (ch==DMAch_SIF0) + *(int*)0xBF80152C=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_TADR(unsigned int ch){ + if (ch==DMAch_SPU) + return *(int*)0xBF8010CC; + if (ch==DMAch_SIF0) + return *(int*)0xBF80152C; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSet_4_9_A(unsigned int ch, int value){ + if (ch==DMAch_SPU) + *(int*)0xBF801568=value; else + if (ch==DMAch_SIF0) + *(int*)0xBF801560=value; else + if (ch==DMAch_SIF1) + *(int*)0xBF801564=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGet_4_9_A(unsigned int ch){ + if (ch==DMAch_SPU) + return *(int*)0xBF801568; + if (ch==DMAch_SIF0) + return *(int*)0xBF801560; + if (ch==DMAch_SIF1) + return *(int*)0xBF801564; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR(int value){ + *(int*)0xBF8010F0=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR(){ + return *(int*)0xBF8010F0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR2(int value){ + *(int*)0xBF801570=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR2(){ + return *(int*)0xBF801570; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR3(int value){ + *(int*)0xBF8015F0=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR3(){ + return *(int*)0xBF8015F0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDICR(int value){ + *(int*)0xBF8010F4=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDICR(){ + return *(int*)0xBF8010F4; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDICR2(int value){ + *(int*)0xBF801574=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDICR2(){ + return *(int*)0xBF801574; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetBF80157C(int value){ + *(int*)0xBF80157C=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetBF80157C(){ + return *(int*)0xBF80157C; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetBF801578(int value){ + *(int*)0xBF801578=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetBF801578(){ + return *(int*)0xBF801578; +} + +func setD_MADR[]={ + (func)_setBF801080, (func)_setBF801090, (func)_setBF8010A0, (func)_setBF8010B0, + (func)_setBF8010C0, (func)_setBF8010D0, (func)_setBF8010E0, + (func)_setBF801500, (func)_setBF801510, (func)_setBF801520, + (func)_setBF801530, (func)_setBF801540, (func)_setBF801550, 0 +}; + +func getD_MADR[]={ + (func)_getBF801080, (func)_getBF801090, (func)_getBF8010A0, (func)_getBF8010B0, + (func)_getBF8010C0, (func)_getBF8010D0, (func)_getBF8010E0, + (func)_getBF801500, (func)_getBF801510, (func)_getBF801520, + (func)_getBF801530, (func)_getBF801540, (func)_getBF801550, 0 +}; + +func setD_BCR[]={ + (func)_setBF801084, (func)_setBF801094, (func)_setBF8010A4, (func)_setBF8010B4, + (func)_setBF8010C4, (func)_setBF8010D4, (func)_setBF8010E4, + (func)_setBF801504, (func)_setBF801514, (func)_setBF801524, + (func)_setBF801534, (func)_setBF801544, (func)_setBF801554, 0 +}; + +func getD_BCR[]={ + (func)_getBF801084, (func)_getBF801094, (func)_getBF8010A4, (func)_getBF8010B4, + (func)_getBF8010C4, (func)_getBF8010D4, (func)_getBF8010E4, + (func)_getBF801504, (func)_getBF801514, (func)_getBF801524, + (func)_getBF801534, (func)_getBF801544, (func)_getBF801554, 0 +}; + +func setD_CHCR[]={ + (func)_setBF801088, (func)_setBF801098, (func)_setBF8010A8, (func)_setBF8010B8, + (func)_setBF8010C8, (func)_setBF8010D8, (func)_setBF8010E8, + (func)_setBF801508, (func)_setBF801518, (func)_setBF801528, + (func)_setBF801538, (func)_setBF801548, (func)_setBF801558, 0 +}; + +func getD_CHCR[]={ + (func)_getBF801088, (func)_getBF801098, (func)_getBF8010A8, (func)_getBF8010B8, + (func)_getBF8010C8, (func)_getBF8010D8, (func)_getBF8010E8, + (func)_getBF801508, (func)_getBF801518, (func)_getBF801528, + (func)_getBF801538, (func)_getBF801548, (func)_getBF801558, 0 +}; + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_MADR(unsigned int ch, int value){ + if (ch<13) + setD_MADR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_MADR(unsigned int ch){ + if (ch<13) + return getD_MADR[ch](ch); //function call + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_BCR(unsigned int ch, int value){ + if (ch<13) + setD_BCR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_BCR(unsigned int ch){ + if (ch<13) + return getD_BCR[ch](ch); //function call + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_CHCR(unsigned int ch, int value){ + if (ch<13) + setD_CHCR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_CHCR(unsigned int ch){ + if (ch<13) + return getD_CHCR[ch](ch); //function call + return 0; +} + + + + +/////////////////////////////////////////////////////////////////////// +int dmacDeinit(){ + int x; + register int ch, value; + + CpuSuspendIntr(&x); //intrman + + dmacSetBF801578(0); + for (ch=0; ch<13; ch++){ + value=dmacGetD_CHCR(ch); + if (value & DMAf_TR) //sysmem + Kprintf("WARNING:DMA %dch has been continued until shutdown\n", ch); + dmacSetD_CHCR(ch, value & 0xFEFFFFFF); + } + + CpuResumeIntr(x); //intrman + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA(int ch, int address, int size, int count, int dir){ + if (ch<13 && ch != DMAch_GPUotc){ + dmacSetD_MADR(ch, 0x00FFFFFF & address); + dmacSetD_BCR (ch, (count << 16) | (size & 0xFFFF)); + dmacSetD_CHCR(ch, (dir & DMAf_DR) | DMAf_CO | + (dir == 0 ? DMAf_30 : 0)); + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_chainedSPU_SIF0(int ch, int size, int tadr){ + if (ch != DMAch_SPU && ch != DMAch_SIF0) + return 0; + dmacSetD_BCR (ch, size & 0x0000FFFF); + dmacSetD_CHCR(ch, DMAf_LI | DMAf_CO | DMAf_DR); //0x601 + dmacSetD_TADR (ch, tadr & 0x00FFFFFF); + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_SIF0(int ch, int size, int tadr){ + if (ch != DMAch_SIF0) + return 0; + dmacSetD_BCR ( DMAch_SIF0, size & 0x0000FFFF); + dmacSetD_CHCR( DMAch_SIF0, DMAf_LI | DMAf_CO | DMAf_08 | DMAf_DR); //0x701 + dmacSetD_TADR ( DMAch_SIF0, tadr & 0x00FFFFFF); + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_SIF1(int ch, int size){ + if (ch != DMAch_SIF1) + return 0; + dmacSetD_BCR (DMAch_SIF1, size & 0x0000FFFF); + dmacSetD_CHCR(DMAch_SIF1, DMAf_30 | DMAf_CO | DMAf_08); //0x40000300 + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void dmacStartTransfer(int ch){ + if (ch < 15) + dmacSetD_CHCR(ch, DMAf_TR | dmacGetD_CHCR(ch)); +} + +/////////////////////////////////////////////////////////////////////// +// set 3-bit value of channel +void dmacSetVal(int ch, int value){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFF8FFF) | + (( value & 7) << 12)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFF8FFFF) | + (( value & 7) << 16)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() & 0xFF8FFFFF) | + (( value & 7) << 20)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() & 0xF8FFFFFF) | + (( value & 7) << 24)); break; + case DMAch_SPU2:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFF8FFF) | + (( value & 7) << 12)); break; + case DMAch_SIO2in: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFF8FFFF) | + (( value & 7) << 16)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFF8FFFFF) | + (( value & 7) << 20)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_67: dmacSetDPCR( + (dmacGetDPCR() & 0x8FFFFFFF) | + (( value & 7) << 28)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() & 0xF8FFFFFF) | + (( value & 7) << 24)); break; + } + + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +// set 4th bit of channel +void dmacEnableDMAch(int ch){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() | 0x00000008)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() | 0x00000080)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() | 0x00000800)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() | 0x00008000)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() | 0x00080000)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() | 0x00800000)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() | 0x08000000)); break; + case DMAch_SPU2: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000008)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000080)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000800)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00008000)); break; + case DMAch_SIO2in:dmacSetDPCR2( + (dmacGetDPCR2() | 0x00080000)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() | 0x00800000)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000008)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000080)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000800)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() | 0x08000000)); break; + } + + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +// reset 4th bit of channel +void dmacDisableDMAch(int ch){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFFF7)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFF7F)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFF7FF)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFF7FFF)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFF7FFFF)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() & 0xFF7FFFFF)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() & 0xF7FFFFFF)); break; + case DMAch_SPU2: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFFF7)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFF7F)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFF7FF)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFF7FFF)); break; + case DMAch_SIO2in:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFF7FFFF)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFF7FFFFF)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFFF7)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFF7F)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFF7FF)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() & 0xF7FFFFFF)); break; + } + + CpuResumeIntr(x); //intrman +} + +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export dmacman_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "dmacman", + (func)_start, // entrypoint + (func)_retonly, + (func)dmacDeinit, + (func)_retonly, + (func)dmacSetD_MADR, + (func)dmacGetD_MADR, + (func)dmacSetD_BCR, + (func)dmacGetD_BCR, + (func)dmacSetD_CHCR, + (func)dmacGetD_CHCR, + (func)dmacSetD_TADR, + (func)dmacGetD_TADR, + (func)dmacSet_4_9_A, + (func)dmacGet_4_9_A, + (func)dmacSetDPCR, + (func)dmacGetDPCR, + (func)dmacSetDPCR2, + (func)dmacGetDPCR2, + (func)dmacSetDPCR3, + (func)dmacGetDPCR3, + (func)dmacSetDICR, + (func)dmacGetDICR, + (func)dmacSetDICR2, + (func)dmacGetDICR2, + (func)dmacSetBF80157C, + (func)dmacGetBF80157C, + (func)dmacSetBF801578, + (func)dmacGetBF801578, + (func)dmacSetDMA, + (func)dmacSetDMA_chainedSPU_SIF0, + (func)dmacSetDMA_SIF0, + (func)dmacSetDMA_SIF1, + (func)dmacStartTransfer, + (func)dmacSetVal, + (func)dmacEnableDMAch, + (func)dmacDisableDMAch, + 0 +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int x; + register int ch; + + if (RegisterLibraryEntries(&dmacman_stub)) //loadcore + return 1; + + CpuSuspendIntr(&x); //intrman + + dmacSetDPCR(0x07777777); + dmacSetDPCR2(0x07777777); + dmacSetDPCR3(0x00000777); + for (ch=0; ch<13; ch++){ + dmacSetD_MADR(ch, 0); + dmacSetD_BCR (ch, 0); + dmacSetD_CHCR(ch, 0); + } + dmacSetD_TADR( DMAch_SPU, 0); + dmacSetD_TADR( DMAch_SIF0,0); + dmacSet_4_9_A( DMAch_SPU, 0); + dmacSet_4_9_A( DMAch_SIF0,0); + dmacSet_4_9_A( DMAch_SIF1,0); + dmacSetBF801578(1); + + CpuResumeIntr(x); //intrman + return 0; +} + diff --git a/fps2bios/kernel/iopload/excepman/Makefile b/fps2bios/kernel/iopload/excepman/Makefile new file mode 100644 index 0000000000..acc273fd9a --- /dev/null +++ b/fps2bios/kernel/iopload/excepman/Makefile @@ -0,0 +1,60 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: excepman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = +LDADD = +OBJECTS = excepman.o ../libkernel/iop_loadcore.o ex_handler.o ../iopdebug.o + +excepman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/EXCEPMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/excepman/ex_handler.s b/fps2bios/kernel/iopload/excepman/ex_handler.s new file mode 100644 index 0000000000..afdaf9b9b2 --- /dev/null +++ b/fps2bios/kernel/iopload/excepman/ex_handler.s @@ -0,0 +1,16 @@ + + .global defaultEH + .ent defaultEH +defaultEH: + .set noreorder + .set noat + .word 0 + .word 0 + + jal defaultEHfunc + nop + cop0 0x10 + nop + .end defaultEH + + diff --git a/fps2bios/kernel/iopload/excepman/excepman.c b/fps2bios/kernel/iopload/excepman/excepman.c new file mode 100644 index 0000000000..9ef451d150 --- /dev/null +++ b/fps2bios/kernel/iopload/excepman/excepman.c @@ -0,0 +1,339 @@ +/* + * The IOP exception manager module. + */ + + +#include + +#include "err.h" +#include "kexcepman.h" +#include "kloadcore.h" +#include "iopdebug.h" + +#define _dprintf(fmt, args...) \ + __printf("excepman: " fmt, ## args) + +int _start(); +int excepman_reinit(); +int excepman_deinit(); +void *GetExHandlersTable(); +int RegisterExceptionHandler(int code, struct exHandler *handler); +int RegisterPriorityExceptionHandler(int code, int priority, struct exHandler *handler); +int RegisterDefaultExceptionHandler(struct exHandler *handler); +int ReleaseExceptionHandler(int code, struct exHandler *handler); +int ReleaseDefaultExceptionHandler(struct exHandler *handler); + +struct export excepman_stub __attribute__((section(".text"))) ={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "excepman", + (func)_start, // entrypoint + (func)excepman_reinit, + (func)excepman_deinit, + (func)GetExHandlersTable, + (func)RegisterExceptionHandler, + (func)RegisterPriorityExceptionHandler, + (func)RegisterDefaultExceptionHandler, + (func)ReleaseExceptionHandler, + (func)ReleaseDefaultExceptionHandler, + 0 +}; + +void* *extable; +struct exHandler *handlers[16]; +void *defhandler; + +void iopException(); + +extern void defaultEH(); + +void defaultEHfunc() +{ + __printf("panic: excepman: %s\n", __FUNCTION__); + __printf("EPC=0x%x, cause: %x\n", *(u32*)0x404, *(u32*)0x40C); + __printf("EXECUTION HALTED\n"); + for (;;); +} + +/////////////////////////////////////////////////////////////////////// +void registerEH() { + int i; + + _dprintf("%s\n", __FUNCTION__); + + // Set up the chain of exception handlers, making sure that each used one is terminated by the + // default exception handler. + for (i=0; i<16; i++) { + if (handlers[i]) { + struct exHandler *eh = handlers[i]; + while(eh->next){ + struct exHandler *p_handler = (struct exHandler *)(eh->info & ~3); + struct exHandler *p_next_handler = (struct exHandler *)(((struct exHandler *)(eh->next))->info & ~3); + p_handler->next = (void*)p_next_handler + 8; + eh = eh->next; + } + { + struct exHandler *p_handler = (struct exHandler *)(eh->info & ~3); + p_handler->next = defhandler; + } + } + } + + for (i=0; i<16; i++) { + if (handlers[i]){ + extable[i]=(void*)((handlers[i]->info & ~3) + 8); + } else { + extable[i]=defhandler; + } + } +} + +//////////////////////////////entrypoint///////////////////////////////[00] +void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void Kprintnum(unsigned int n) +{ + int i = 0; + while(i < 8) { + u32 a = n>>28; + if( a < 10 ) Kputc('0'+a); + else Kputc('a'+(a-10)); + n <<= 4; + ++i; + } +} + +int _start() { + int *src, *dst; + int i; + + _dprintf("%s\n", __FUNCTION__); + + for (i=0; i<16; i++){ + handlers[i] = NULL; + } + defhandler=NULL; + extable = (void*)0x440; + + // Install the exception handler to address 0 + for (src=(int*)iopException, dst=0; (u32)dst<0x100; src++, dst++){ + *dst = *src; + } + + RegisterDefaultExceptionHandler((struct exHandler *)&defaultEH); + RegisterLibraryEntries(&excepman_stub); + + return 0; +} + +///////////////////////////////////////////////////////////////////////[02] +int excepman_deinit(){ + return 0; +} + +///////////////////////////////////////////////////////////////////////[01] +int excepman_reinit() { + excepman_deinit(); + return _start(); +} + +///////////////////////////////////////////////////////////////////////[04] +int RegisterExceptionHandler(int code, struct exHandler *handler) +{ + return RegisterPriorityExceptionHandler(code, 2, handler); +} + +// This is a pool of containers. They form a linked list. The info member of each points +// to a registered handler. +struct exHandler _list[32]; +struct exHandler *list = NULL; + + +void link(struct exHandler *e) { + e->next = list; + list = e; +} + +struct exHandler *unlink() { + struct exHandler *e; + if (list == NULL) { + int i; + + list = _list; + for (i=0; i<31; i++) { + list[i].next = &list[i+1]; + } + list[i].next = 0; + } + e = list; + list = e->next; + return e; +} + +///////////////////////////////////////////////////////////////////////[05] +int RegisterPriorityExceptionHandler(int code, int priority, struct exHandler *handler) +{ + struct exHandler *n, *p, *p_prev; + + _dprintf("%s: code = %d, pri = %d, (handler=%x)\n", __FUNCTION__, code, priority, handler); + if (code >= 16){ + _dprintf("%s ERROR_BAD_EXCODE\n", __FUNCTION__); + return ERROR_BAD_EXCODE; + } + if (handler->next){ + _dprintf("%s ERROR_USED_EXCODE\n", __FUNCTION__); + return ERROR_USED_EXCODE; + } + + n = unlink(); + + priority &= 3; + n->info = ((u32)handler & ~3) | priority; + n->next = NULL; + + p = handlers[code]; p_prev = NULL; + // walk along the chain starting at the handlers[code] root to find our place in the queue + while(p && ((p->info & 3) < priority)){ + p_prev = p; p = p->next; + } + n->next = p; + if (p_prev == NULL){ + handlers[code] = n; + } else { + p_prev->next = n; + } + + registerEH(); + return 0; +} + +///////////////////////////////////////////////////////////////////////[06] +int RegisterDefaultExceptionHandler(struct exHandler *handler) +{ + _dprintf("%s\n", __FUNCTION__); + if (handler->next){ + _dprintf("%s ERROR_USED_EXCODE\n", __FUNCTION__); + return ERROR_USED_EXCODE; + } + + handler->next = defhandler; + defhandler = &handler->funccode; + + registerEH(); + return 0; +} + +///////////////////////////////////////////////////////////////////////[07] +int ReleaseExceptionHandler(int code, struct exHandler *handler) +{ + struct exHandler *p, *p_prev; + + _dprintf("%s: %d\n", __FUNCTION__, code); + if (code>=16) return ERROR_BAD_EXCODE; + + p_prev = NULL; + for (p=handlers[code]; p != NULL; p_prev = p, p=p->next) { + if ((struct exHandler *)(p->info & ~3) == handler) { + // found it + // Mark the handler as no longer used + ((struct exHandler *)(p->info & ~3))->next = NULL; + + if (p == handlers[code]){ + // special case, no more list + handlers[code] = NULL; + } else { + // Remove container p from the list + p_prev->next = p->next; + } + + link(p); // Add the container back to the pool + registerEH(); + return 0; + } + } + return ERROR_EXCODE_NOTFOUND; +} + +///////////////////////////////////////////////////////////////////////[08] +int ReleaseDefaultExceptionHandler(struct exHandler *handler) +{ + struct exHandler *p; + + _dprintf("%s\n", __FUNCTION__); + for (p=defhandler; p->next; p=p->next-8) { + if (p->next == handler->funccode) { + p->next = handler->next; + handler->next = 0; + registerEH(); + return 0; + } + } + return ERROR_EXCODE_NOTFOUND; +} + +///////////////////////////////////////////////////////////////////////[03] +void *GetExHandlersTable() +{ + return extable; +} + +// 256 bytes of this code are copied to memory address 0 in order to install the exception handling code. +// Take careful note of the alignment of the code at 0x40 and 0x80 if you change it at all. +void iopException() { + __asm__ ( + ".set noat\n" + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + + /* 0x0040 */ + /* This the breakpoint exception vector location. */ + + "sw $26, 0x0420($0)\n" + "mfc0 $27, $14\n" + "mfc0 $26, $13\n" + "sw $27, 0x0424($0)\n" + "sw $26, 0x0428($0)\n" + "mfc0 $27, $12\n" + "mfc0 $26, $7\n" + "sw $27, 0x042C($0)\n" + "sw $26, 0x0430($0)\n" + "lw $27, 0x047C($0)\n" + "mtc0 $0, $7\n" + "jr $27\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + + /* 0x0080 */ + /* This is the general exception vector location. */ + "sw $1, 0x0400($0)\n" /* $1 saved at 0x400 */ + "sw $26, 0x0410($0)\n" /* $26 saved at 0x410 */ + "mfc0 $1, $14\n" + "mfc0 $26, $12\n" + "sw $1 , 0x0404($0)\n" /* EPC -> 0x404 */ + "sw $26, 0x0408($0)\n" /* STATUS -> 0x408 */ + "mfc0 $1, $13\n" + "sw $1, 0x040C($0)\n" /* CAUSE -> 0x40C */ + "andi $1, 0x3C\n" /* Isolate EXECODE */ + "lw $1, 0x0440($1)\n" + "jr $1\n" /* jump via EXECODE table at 0x440 */ + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + "nop\nnop\nnop\nnop\n" + ".set at\n" + ); +} diff --git a/fps2bios/kernel/iopload/heaplib/Makefile b/fps2bios/kernel/iopload/heaplib/Makefile new file mode 100644 index 0000000000..9af0f48679 --- /dev/null +++ b/fps2bios/kernel/iopload/heaplib/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: heaplib + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = heaplib.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_sysmem.o + +heaplib: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/HEAPLIB + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/heaplib/heaplib.c b/fps2bios/kernel/iopload/heaplib/heaplib.c new file mode 100644 index 0000000000..14793752b3 --- /dev/null +++ b/fps2bios/kernel/iopload/heaplib/heaplib.c @@ -0,0 +1,206 @@ +//[module] HEAPLIB +//[processor] IOP +//[type] ELF-IRX +//[name] Heap_lib +//[version] 0x101 +//[memory map] - +//[handlers] - +//[entry point] heaplib_start, heaplib_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) 26 January 2003 + +#include "sysmem.h" +#include "kloadcore.h" +#include "kheaplib.h" +#include "iopdebug.h" + +static int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("\033[0;32m" "heaplib: " "\033[0m" fmt, ## args) + +int _start(int argc, char* argv[]); + +/////////////////////////////////////////////////////////////////////// +void ll_reset(struct ll *l){ + l->prev=l->next=l; +} + +/////////////////////////////////////////////////////////////////////// +int ll_one(struct ll *l){ + return (l == l->next); +// return (l ^ l->next) < 1; //l==l->next +} + +/////////////////////////////////////////////////////////////////////// +void ll_remove(struct ll *l){ + l->next->prev=l->prev; + l->prev->next=l->next; +} + +/////////////////////////////////////////////////////////////////////// +/*int ll_one_two(struct ll *l){ + return (l->prev ^ l->next) < 1; //l->prev==l->next +}*/ + +/////////////////////////////////////////////////////////////////////// +void ll_add(struct ll *l, struct ll *n){ + n->next=l; + n->prev=l->prev; + l->prev=n; + n->prev->next=n; +} + +void HeapPrepare(void *mem, int size) { + struct Chunk *_chunk = (struct Chunk*)mem; + + if (mem == NULL || size < 41) return; + + _chunk->_mem=(long)mem-1; + _chunk->freesize=size; + _chunk->usedsize=0; + _chunk->mem_16 = (u32)mem+16; + _chunk->unk5=((size-16)>>3)-1; + _chunk->unk4=(long)_chunk+8+((size-16)&~7); + ((struct ll*)_chunk->unk4)->next=(void*)_chunk->mem_16; + ((struct ll*)_chunk->unk4)->prev=0; +} + +int HeapChunkSize(void *chunk) { +// int size = (chunk[1] - 16) >> 3; +// return ((size - chunk[2]) - 1) << 3; +} + +/////////////////////////////////////////////////////////////////////// +void* CreateHeap(int chunkSize, int memoryType){ + struct Heap *_heap; + + _dprintf("%s\n", __FUNCTION__); + chunkSize = (chunkSize+3) & ~3; + _heap = AllocSysMemory(memoryType & 2 ? ALLOC_LAST : ALLOC_FIRST, chunkSize, NULL); + if (_heap == NULL) return NULL; + + _heap->plus_one=(long)_heap + 1; + if (memoryType & 1) _heap->size2free=chunkSize; + else _heap->size2free=0; + _heap->size2free |= ((memoryType>>1) & 1); + ll_reset(&_heap->l); + + HeapPrepare(&_heap->mem, chunkSize-4*sizeof(int)); + return (void*)_heap; +} + +/////////////////////////////////////////////////////////////////////// +int DestroyHeap(void *heap){ + register struct ll *tmp, *p; + struct Heap *_heap = (struct Heap*)heap; + + if (_heap->plus_one != (long)_heap+1) return (long)_heap+1; + _heap->plus_one=0; + + for (p=&_heap->l; p != &_heap->l; p=tmp){ + tmp=p->next; + ((int*)p)[2]=0; //p->mem + FreeSysMemory(p); + } + _heap->mem=0; + return FreeSysMemory(_heap); +} + +/////////////////////////////////////////////////////////////////////// +void* HeapMalloc(void *heap, int size) { +#if 0 + struct Heap *_heap = (struct Heap*)heap; + void *p; + + if (_heap->plus_one != (long)_heap+1) return NULL; + + for (;;) { + p = HeapChunk13((u32)_heap->l.next+8, size); + if (p != NULL) return p; + + if (_heap->l.next->next == _heap->l.next) break; + } +#endif +} + +int HeapFree(void *heap, void *mem) { + struct Heap *_heap = (struct Heap*)heap; + struct Heap *h; + + if (heap == NULL || + _heap->plus_one != (long)_heap+1) return -4; + + for (h = (struct Heap*)_heap->l.next; h != &_heap->l; h = (struct Heap*)h->l.next) { + if (HeapChunk14(h->l, mem) != NULL) continue; + + break; + } + + if ((struct ll*)h == &_heap->l) return 0; + if (HeapChunk12() == 0) return 0; + ll_one(h); + h->l.next = 0; + FreeSysMemory(h); + + return 0; +} + +int HeapSize(void *heap) { + struct Heap *_heap = (struct Heap*)heap; + + if (heap == NULL || + _heap->plus_one != (long)_heap+1) return -4; + + for (;; _heap = _heap->plus_one) { + if (_heap->l.next == &_heap->l) + break; + } + + return HeapChunkSize(_heap->l.next+8); +} + +void HeapChunk12() { +} + +void HeapChunk13() { +} + +void HeapChunk14() { +} + +/////////////////////////////////////////////////////////////////////// +void _retonly(){} + +struct export heaplib_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "heaplib", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)CreateHeap, + (func)DestroyHeap, + (func)HeapMalloc, + (func)HeapFree, + (func)HeapSize, + (func)_retonly, + (func)_retonly, + (func)HeapPrepare, + (func)HeapChunk12, + (func)HeapChunk13, + (func)HeapChunk14, + (func)HeapChunkSize, + (func)_retonly, + (func)_retonly, + 0 +}; + + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + return RegisterLibraryEntries(&heaplib_stub); +} + diff --git a/fps2bios/kernel/iopload/include/err.h b/fps2bios/kernel/iopload/include/err.h new file mode 100644 index 0000000000..c93784ee98 --- /dev/null +++ b/fps2bios/kernel/iopload/include/err.h @@ -0,0 +1,30 @@ +#ifndef __ERR_H__ +#define __ERR_H__ + +//#define ERR_VER 0x + +#define ERROR_OK 0 +#define ERROR_UNK -1 +//bad exception code +#define ERROR_BAD_EXCODE -50 + +//no exception handler for that code +#define ERROR_EXCODE_NOTFOUND -51 + +//already used +#define ERROR_USED_EXCODE -52 +#define ERROR_INTR_CONTEXT -100 +#define ERROR_DOES_EXIST -104 +#define ERROR_DOESNOT_EXIST -105 +#define ERROR_NO_TIMER -150 +#define ERROR_NOT_IRX -201 +#define ERROR_FILE_NOT_FOUND -203 +#define ERROR_FILE_ERROR -204 +#define ERROR_NO_MEM -400 +#define ERROR_SEMACOUNT_ZERO -400 + +// what should these be? Used in intrman.c +#define ERROR_ILLEGAL_INTRCODE ERROR_UNK +#define ERROR_CPUDI ERROR_UNK + +#endif//__ERR_H__ diff --git a/fps2bios/kernel/iopload/include/errno.h b/fps2bios/kernel/iopload/include/errno.h new file mode 100644 index 0000000000..fa069caf3c --- /dev/null +++ b/fps2bios/kernel/iopload/include/errno.h @@ -0,0 +1,143 @@ +/* errno is not a global variable, because that would make using it + non-reentrant. Instead, its address is returned by the function + __errno. */ + +#ifndef _SYS_ERRNO_H_ +#ifdef __cplusplus +extern "C" { +#endif +#define _SYS_ERRNO_H_ + + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#define ECHRNG 37 /* Channel number out of range */ +#define EL2NSYNC 38 /* Level 2 not synchronized */ +#define EL3HLT 39 /* Level 3 halted */ +#define EL3RST 40 /* Level 3 reset */ +#define ELNRNG 41 /* Link number out of range */ +#define EUNATCH 42 /* Protocol driver not attached */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#define EDEADLK 45 /* Deadlock condition */ +#define ENOLCK 46 /* No record locks available */ +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#define EDEADLOCK 56 /* File locking deadlock error */ +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#define ENOSYS 88 /* Function not implemented */ +#define ENMFILE 89 /* No more files */ +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#define EPROCLIM 130 +#define EUSERS 131 +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EILSEQ 138 +#define EOVERFLOW 139 /* Value too large for defined data type */ + +/* From cygwin32. */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ + +#define __ELASTERROR 2000 /* Users can add values starting here */ + +#ifdef __cplusplus +} +#endif +#endif /* _SYS_ERRNO_H */ diff --git a/fps2bios/kernel/iopload/include/iopdebug.h b/fps2bios/kernel/iopload/include/iopdebug.h new file mode 100644 index 0000000000..c52e672334 --- /dev/null +++ b/fps2bios/kernel/iopload/include/iopdebug.h @@ -0,0 +1,11 @@ +#ifndef __IOPDEBUG_H__ +#define __IOPDEBUG_H__ + +#include + +void __putc(u8 c); +void __puts(u8 *s); +void __printf(char *fmt, ...); + + +#endif /* __IOPDEBUG_H__ */ diff --git a/fps2bios/kernel/iopload/include/iopelf.h b/fps2bios/kernel/iopload/include/iopelf.h new file mode 100644 index 0000000000..2f8933a1f6 --- /dev/null +++ b/fps2bios/kernel/iopload/include/iopelf.h @@ -0,0 +1,226 @@ +#ifndef __IOPELF_H__ +#define __IOPELF_H__ + +#include "romdir.h" + +#define MOD_TYPE_REL 1 +#define MOD_TYPE_2 2 +#define MOD_TYPE_DYN 3 +#define MOD_TYPE_CORE 4 + +typedef struct { + char *name; + short version; +} moduleInfo; + +// info about a module file +typedef struct module_info { + int type; // module type (MOD_TYPE_*) + int (*entry)(void*);// module entry point address + int gpValue; // module gp value + int progVAddr; // programs virtual address + int textSize; // size of text section + int dataSize; // size of data section + int bssSize; // size of bss section + int progMemSize; // size of program memory + int moduleInfo; // info about module ? +} MODULE_INFO; + +typedef struct { + u32 ei_magic; + u8 ei_class; + u8 ei_data; + u8 ei_version; + u8 ei_pad[9]; +} E_IDENT; + +typedef struct { + u8 e_ident[16]; //+00 0x7f,"ELF" (ELF file identifier), E_IDENT* + u16 e_type; //+10 ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //+12 Processor: 8=MIPS R3000 + u32 e_version; //+14 Version: 1=current + u32 e_entry; //+18 Entry point address + u32 e_phoff; //+1C Start of program headers (offset from file start) + u32 e_shoff; //+20 Start of section headers (offset from file start) + u32 e_flags; //+24 Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //+28 ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //+2A Program headers entry size + u16 e_phnum; //+2C Number of program headers + u16 e_shentsize; //+2E Section headers entry size + u16 e_shnum; //+30 Number of section headers + u16 e_shstrndx; //+32 Section header stringtable index +} ELF_HEADER; //+34=sizeof +#define ET_SCE_IOPRELEXEC 0xFF80 +#define PT_SCE_IOPMOD 0x70000080 +#define SHT_REL 9 +#define EM_MIPS 8 + +typedef struct tag_COFF_AOUTHDR { + short magic; //+00 + short vstamp; //+02 + int tsize; //+04 + int dsize; //+08 + int bsize; //+0C + int entry; //+10 + int text_start; //+14 + int data_start; //+18 + int bss_start; //+1C + int field_20; //+20 + int field_24; //+24 + int field_28; //+28 + int field_2C; //+2C + int moduleinfo; //+30 + int gp_value; //+34 +} COFF_AOUTHDR, COHDR; //=38 + +typedef struct tag_CHDR{ + short f_magic; //+00 + short f_nscns; //+02 + int f_timdat; //+04 + int f_symptr; //+08 + int f_nsyms; //+0C + short f_opthdr; //+10 + short f_flags; //+12 +} CHDR; //=14 + +typedef struct tag_COFF_HEADER{ //same header as above + short f_magic; //+00 + short f_nscns; //+02 + int f_timdat; //+04 + int f_symptr; //+08 + int f_nsyms; //+0C + short f_opthdr; //+10 + short f_flags; //+12 + COFF_AOUTHDR opthdr; //+14 +} COFF_HEADER; //=4C + +typedef struct tag_COFF_scnhdr +{ + char s_name[8]; //+00 + int s_paddr; //+08 + int s_vaddr; //+0C + int s_size; //+10 + int s_scnptr; //+14 + int s_relptr; //+18 + int s_lnnoptr; //+1C + short s_nreloc; //+20 + short s_nlnno; //+22 + int s_flags; //+24 +} COFF_scnhdr, SHDR; //=28 + +typedef struct _fileInfo +{ + u32 type, //+00 + entry, //+04 + gp_value, //+08 + p1_vaddr, //+0C + text_size, //+10 + data_size, //+14 + bss_size, //+18 + p1_memsz; //+1C + moduleInfo *moduleinfo; //+20 +} fileInfo; + +typedef struct { + u32 p_type; //+00 see notes1 + u32 p_offset; //+04 Offset from file start to program segment. + u32 p_vaddr; //+08 Virtual address of the segment + u32 p_paddr; //+0C Physical address of the segment + u32 p_filesz; //+10 Number of bytes in the file image of the segment + u32 p_memsz; //+14 Number of bytes in the memory image of the segment + u32 p_flags; //+18 Flags for segment + u32 p_align; //+1C Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +} ELF_PHR; + +//notes1 +//------ +//0=Inactive +//1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +//2=Dynamic linking +//3=Interpreter. The array element must specify a path name +//4=Note. The array element must specify the location and size of aux. info +//5=reserved +//6=The array element must specify location and size of the program header table. + +typedef struct { + u32 r_offset; + u32 r_info; +} ELF_REL; + +typedef struct { + char* moduleinfo; + u32 entry; //+04 + u32 gp_value; //+08 + u32 text_size; //+0C + u32 data_size; //+10 + u32 bss_size;//+14 + short moduleversion;//+18 + char* modulename; //+1A +} ELF_IOPMOD; + +typedef struct { + u32 sh_name; //+00 No. to the index of the Section header stringtable index + u32 sh_type; //+04 See notes2 + u32 sh_flags; //+08 see notes3 + u32 sh_addr; //+0C Section start address + u32 sh_offset; //+10 Offset from start of file to section + u32 sh_size; //+14 Size of section + u32 sh_link; //+18 Section header table index link + u32 sh_info; //+1C Info + u32 sh_addralign; //+20 Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //+24 Fixed size entries. +} ELF_SHR; + +//notes 2 +//------- +//Type: +//0=Inactive +//1=PROGBITS +//2=SYMTAB symbol table +//3=STRTAB string table +//4=RELA relocation entries +//5=HASH hash table +//6=DYNAMIC dynamic linking information +//7=NOTE +//8=NOBITS +//9=REL relocation entries +//10=SHLIB +//0x70000000=LOPROC processor specifc +//0x7fffffff=HIPROC +//0x80000000=LOUSER lower bound +//0xffffffff=HIUSER upper bound +// +//notes 3 +//------- +//Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +//1=Write section contains data the is be writeable during execution. +//2=Alloc section occupies memory during execution +//4=Exec section contains executable instructions +//0xf0000000=Mask bits processor-specific + + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +// special header for every iop module? +typedef struct { + u32 next; //+00 + char *name; //+04 + short version, //+08 + flags, //+0A + modid, //+0C + HE; //+0E + u32 entry, //+10 + gp_value, //+14 + p1_vaddr, //+18 + text_size, //+1C + data_size, //+20 + bss_size, //+24 + H28, //+28 + H2C; //+2C +} imageInfo; + +// pass in the memory to load the elf file from +// elfoffset - offset to load elf file to +void* loadElfFile(ROMFILE_INFO* ri, u32 elfoffset); + +#endif diff --git a/fps2bios/kernel/iopload/include/iopload.h b/fps2bios/kernel/iopload/include/iopload.h new file mode 100644 index 0000000000..42a2815153 --- /dev/null +++ b/fps2bios/kernel/iopload/include/iopload.h @@ -0,0 +1,18 @@ +#ifndef __IOPLOAD_H__ +#define __IOPLOAD_H__ + +#include + +extern char *iopModules[32]; + +void Kmemcpy(void *dest, const void *src, int n); + +#define SBUS_MSFLG *(volatile int*)0xBD00F220 +#define SBUS_SMFLG *(volatile int*)0xBD00F230 +#define SBUS_F240 *(volatile int*)0xBD00F240 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + + +#endif /* __IOPLOAD_H__ */ diff --git a/fps2bios/kernel/iopload/include/kdmacman.h b/fps2bios/kernel/iopload/include/kdmacman.h new file mode 100644 index 0000000000..efcf40bf8e --- /dev/null +++ b/fps2bios/kernel/iopload/include/kdmacman.h @@ -0,0 +1,116 @@ +#ifndef __DMACMAN_H__ +#define __DMACMAN_H__ + +#define DMACMAN_VER 0x101 + +////////////////////////////// D_CHCR - DMA Channel Control Register +#define DMAf_30 0x40000000 // unknown; set on 'to' direction +#define DMAf_TR 0x01000000 // DMA transfer +#define DMAf_LI 0x00000400 // Linked list GPU; also SPU & SIF0 +#define DMAf_CO 0x00000200 // Continuous stream +#define DMAf_08 0x00000100 // unknown +#define DMAf_DR 0x00000001 // Direction to=0/from=1 +// 31 24 23 16 15 8 7 0 +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³?³ ³ ³ ³ ³ ³Tº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³L³C³?º ³ ³ ³ ³ ³ ³ ³Dº +// º ³?³ ³ ³ ³ ³ ³Rº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³I³O³?º ³ ³ ³ ³ ³ ³ ³Rº +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// 30 24 10 9 8 0 + +////////////////////////////// DPCR - DMA Primary Control Register +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º 67 ³ DMA 6 º DMA 5 ³ DMA 4 º DMA 3 ³ DMA 2 º DMA 1 ³ DMA 0 º 0xBF8010F0 DPCR +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³ DMA85 º DMA12 ³ DMA11 º DMA10 ³ DMA 9 º DMA 8 ³ DMA 7 º 0xBF801570 DPCR_ +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³ º ³ º ³ DMA15 º DMA14 ³ DMA13 º 0xBF8015F0 DPCR__ +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ + +////////// DPCR +#define DMAch_MDECin 0 +#define DMAch_MDECout 1 +#define DMAch_GPU 2 // SIF2 both directions +#define DMAch_CD 3 +#define DMAch_SPU 4 +#define DMAch_PIO 5 +#define DMAch_GPUotc 6 + +#define DMAch_67 67 // strange + +////////// DPCR_ +#define DMAch_SPU2 7 +#define DMAch_8 8 +#define DMAch_SIF0 9 // SIFout IOP->EE +#define DMAch_SIF1 10 // SIFin EE->IOP +#define DMAch_SIO2in 11 +#define DMAch_SIO2out 12 + +#define DMAch_85 85 // stange, very strange + +////////// DPCR__ +#define DMAch_13 13 +#define DMAch_14 14 +#define DMAch_15 15 + +int dmacman_start(int argc, char* argv[]); // 0 +int dmacman_deinit(); // 2 + +void dmacman_call4_SetD_MADR(unsigned int ch, int value); // 4 +int dmacman_call5_GetD_MADR(unsigned int ch); // 5 +void dmacman_call6_SetD_BCR(unsigned int ch, int value); // 6 +int dmacman_call7_GetD_BCR(unsigned int ch); // 7 +void dmacman_call8_SetD_CHCR(unsigned int ch, int value); // 8 +int dmacman_call9_GetD_CHCR(unsigned int ch); // 9 +void dmacman_call10_SetD_TADR(unsigned int ch, int value); //10 +int dmacman_call11_GetD_TADR(unsigned int ch); //11 +void dmacman_call12_Set_4_9_A(unsigned int ch, int value); //12 +int dmacman_call13_Get_4_9_A(unsigned int ch); //13 +void dmacman_call14_SetDPCR(int value); //14 +int dmacman_call15_GetDPCR(); //15 +void dmacman_call16_SetDPCR2(int value); //16 +int dmacman_call17_GetDPCR2(); //17 +void dmacman_call18_SetDPCR3(int value); //18 +int dmacman_call19_GetDPCR3(); //19 +void dmacman_call20_SetDICR(int value); //20 +int dmacman_call21_GetDICR(); //21 +void dmacman_call22_SetDICR2(int value); //22 +int dmacman_call23_GetDICR2(); //23 +void dmacman_call24_setBF80157C(int value); //24 +int dmacman_call25_getBF80157C(); //25 +void dmacman_call26_setBF801578(int value); //26 +int dmacman_call27_getBF801578(); //27 +int dmacman_call28_SetDMA(int ch, int address, int size, int count, int dir); //28 +int dmacman_call29_SetDMA_chainedSPU_SIF0(int ch, int size, int c);//29 +int dmacman_call30_SetDMA_SIF0(int ch, int size, int c); //30 +int dmacman_call31_SetDMA_SIF1(int ch, int size); //31 +void dmacman_call32_StartTransfer(int ch); //32 +void dmacman_call33_SetVal(int ch, int value); //33 +void dmacman_call34_EnableDMAch(int ch); //34 +void dmacman_call35_DisableDMAch(int ch); //35 + +//SIF2 DMA ch 2 (GPU) +#define DMAch_SIF2_MADR (*(volatile int*)0xBF8010A0) +#define DMAch_SIF2_BCR (*(volatile int*)0xBF8010A4) +#define DMAch_SIF2_BCR_size (*(volatile short*)0xBF8010A4) +#define DMAch_SIF2_BCR_count (*(volatile short*)0xBF8010A6) +#define DMAch_SIF2_CHCR (*(volatile int*)0xBF8010A8) +//SIF0 DMA ch 9 +#define DMAch_SIF9_MADR (*(volatile int*)0xBF801520) +#define DMAch_SIF9_BCR (*(volatile int*)0xBF801524) +#define DMAch_SIF9_BCR_size (*(volatile short*)0xBF801524) +#define DMAch_SIF9_BCR_count (*(volatile short*)0xBF801526) +#define DMAch_SIF9_CHCR (*(volatile int*)0xBF801528) +#define DMAch_SIF9_TADR (*(volatile int*)0xBF80152C) +//SIF1 DMA ch 10 (0xA) +#define DMAch_SIFA_MADR (*(volatile int*)0xBF801530) +#define DMAch_SIFA_BCR (*(volatile int*)0xBF801534) +#define DMAch_SIFA_BCR_size (*(volatile short*)0xBF801534) +#define DMAch_SIFA_BCR_count (*(volatile short*)0xBF801536) +#define DMAch_SIFA_CHCR (*(volatile int*)0xBF801538) + +#define DMAch_DPCR (*(volatile int*)0xBF8010F0) +#define DMAch_DPCR2 (*(volatile int*)0xBF801570) + +#endif//__DMACMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kexcepman.h b/fps2bios/kernel/iopload/include/kexcepman.h new file mode 100644 index 0000000000..a29909c8b0 --- /dev/null +++ b/fps2bios/kernel/iopload/include/kexcepman.h @@ -0,0 +1,23 @@ +#ifndef __EXCEPMAN_H__ +#define __EXCEPMAN_H__ + +#define EXCEPMAN_VER 0x101 + +#define EXCEP_MAX 16 + +struct exHandler { + void *next; // next points to the next funccode :/ + int info; + u32 funccode[0]; +}; + +void *GetExHandlersTable(); // 3 + +int RegisterExceptionHandler(int code, struct exHandler *handler); // 4 +int RegisterPriorityExceptionHandler(int code, int priority, + struct exHandler *handler); // 5 +int RegisterDefaultExceptionHandler(struct exHandler *handler); // 6 +int ReleaseExceptionHandler(int excode, struct exHandler *handler); // 7 +int ReleaseDefaultExceptionHandler(struct exHandler *handler); // 8 + +#endif//__EXCEPMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kheaplib.h b/fps2bios/kernel/iopload/include/kheaplib.h new file mode 100644 index 0000000000..618cebd16b --- /dev/null +++ b/fps2bios/kernel/iopload/include/kheaplib.h @@ -0,0 +1,30 @@ +#ifndef __HEAPLIB_H__ +#define __HEAPLIB_H__ + +struct ll{ struct ll *next, *prev; }; //linked list + + +struct Heap { + long plus_one; + int size2free; + struct ll l; + void *mem; +}; + +struct Chunk { + u32 _mem; + int freesize; + int usedsize; + u32 mem_16; + u32 unk4; + u32 unk5; +}; + +void *CreateHeap(int chunkSize, int memoryType ); +int DestroyHeap(void *heap); + +void *HeapMalloc(void *heap, int size); +int HeapFree(void *heap, void * mem); +int HeapSize(void *heap); + +#endif /* __HEAPLIB_H__ */ diff --git a/fps2bios/kernel/iopload/include/kintrman.h b/fps2bios/kernel/iopload/include/kintrman.h new file mode 100644 index 0000000000..d12407c33b --- /dev/null +++ b/fps2bios/kernel/iopload/include/kintrman.h @@ -0,0 +1,38 @@ +#ifndef __INTRMAN_H__ +#define __INTRMAN_H__ + +#define INTRMAN_VER 0x102 + +#define INT_VBLANK 0x00 + +#define INT_CDROM 0x02 + +#define INT_RTC0 0x04 +#define INT_RTC1 0x05 +#define INT_RTC2 0x06 + +#define INT_EVBLANK 0x0B + +#define INT_RTC3 0x0E +#define INT_RTC4 0x0F +#define INT_RTC5 0x10 + +#define INT_DMA9 0x2A //sif0 +#define INT_DMA10 0x2B //sif1 + +#define IMODE_DMA_IRM 0x100 +#define IMODE_DMA_IQE 0x200 + +typedef int (*intrh_func)(void*); + +int RegisterIntrHandler(int interrupt, int, intrh_func intrh, void*); + //4 (13,18) +int ReleaseIntrHandler(int interrupt); //5 (18) +int EnableIntr(int interrupt); //6 (13,18) +int DisableIntr(int interrupt, int *oldstat); //7 (18) +int CpuEnableIntr(); //9 (18,21,26) +int CpuSuspendIntr(u32* ictrl); //17(05,06,07,13,14,18,26) +int CpuResumeIntr(u32 ictrl); //18(05,06,07,13,14,18,26) +int QueryIntrContext(); //23(07,13) + +#endif//__INTRMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kioman.h b/fps2bios/kernel/iopload/include/kioman.h new file mode 100644 index 0000000000..26cecd687e --- /dev/null +++ b/fps2bios/kernel/iopload/include/kioman.h @@ -0,0 +1,56 @@ +#ifndef __IOMAN_H__ +#define __IOMAN_H__ + +#define IOMAN_VER 0x102 + +#define STDIN 0 +#define STDOUT 1 + +struct ioman_FUNCS{ + int init(struct ioman_DRV *drv); //00 + void term(struct ioman_DRV *drv); //01 + int format(char *filename); //02 + int open(int fd, char *filename, int flag); //03 + int close(int fd); //04 + int read(int fd, void *buf, int nbyte); //05 + int write(int fd, void *buf, int nbyte); //06 + int lseek(int fd, int offset, int whence); //07 + int ioctl(int fd, int request, int arg); //08 + int remove(char *filename); //09 + int mkdir(char *filename); //10 + int rmdir(char *filename); //11 + int dopen(char *filename); //12 + int dclose(int fd); //13 + int dread(int fd, void *buf); //14 + int getstat(char *filename, void *buf); //15 + int chstat(char *filename, void *buf, unsigned int mask); //16 +}; + +struct ioman_DRV{ //struct fileio_driver from ps2lib + char *driver; //+00 + int unk1; //+04 + int version; //+08 + char *description; //+0C + struct ioman_FUNCS *f_list; //+10 +}; //=14 + +int open(char *filename, int flag); // 4(26) +int close(int fd); // 5(26) +int read(int fd, void *buf, long count); // 6(17,26) +int write(int fd, void *buf, long count); // 7(17,26) +int lseek(int fd, int offset, int whence); // 8(26) +int ioctl(int fd, int request, int arg); // 9(26) +int remove(char *filename); //10(26) +int mkdir(char *filename); //11(26) +int rmdir(char *filename); //12(26) +int dopen(char *filename); //13(26) +int dclose(int fd); //14(26) +int dread(int fd, void *buf); //15(26) +int getstat(char *filename, void *buf); //16(26) +int chstat(char *filename, void *buf, unsigned int mask); //17(26) +int format(char *filename); //18(26) +int AddDrv(struct ioman_DRV *drv); //20(26) +int DelDrv(char *device); //21(26) + +#endif//__IOMAN_H__ + diff --git a/fps2bios/kernel/iopload/include/kloadcore.h b/fps2bios/kernel/iopload/include/kloadcore.h new file mode 100644 index 0000000000..bac1206320 --- /dev/null +++ b/fps2bios/kernel/iopload/include/kloadcore.h @@ -0,0 +1,89 @@ +#ifndef __LOADCORE_H__ +#define __LOADCORE_H__ + +#include + +#define LOADCORE_VER 0x101 + +typedef int (*func)(); + +#define VER(major, minor) ((((major) & 0xFF)<<8) + ((minor) & 0xFF)) + +#define MODULE_RESIDENT_END 0 +#define MODULE_NO_RESIDENT_END 1 + +struct func_stub { + int jr_ra; //jump instruction + int addiu0; //addiu zero, number +}; + +// defined by irx.h in the sdk +//#define IMPORT_MAGIC 0x41E00000 +//#define EXPORT_MAGIC 0x41C00000 + +#define FLAG_EXPORT_QUEUED 1 +#define FLAG_IMPORT_QUEUED 2 + +#define FLAG_NO_AUTO_LINK 1 + +#define INS_JR 2 +#define INS_ADDIU 9 +#define INS_JR_RA 0x03E00008 +#define INS_J 0x08000000 + +enum tag_BOOTUPCB_PRIO{ + BOOTUPCB_FIRST = 0, + BOOTUPCB_RUN_UDNL = 1, + BOOTUPCB_NORMAL = 2, + BOOTUPCB_LAST = 3, + BOOTUPCB_PRIORITIES +} BOOTUPCB_PRIO; + +struct import { + u32 magic; //0x41E00000 + struct import *next; + short version; //mjmi (mj=major, mi=minor version numbers) + short flags; //=0 + char name[8]; + struct func_stub func[0]; //the last one is 0, 0 (i.e. nop, nop) +}; + +struct export { + u32 magic_link; //0x41C00000, prev + struct export *next; + short version; //mjmi (mj=major, mi=minor version numbers) + short flags; //=0 + char name[8]; + func func[45]; //usually module entry point (allways?) +// func1 +// func2 +// func3 +// funcs // more functions: the services provided my module +}; + +struct bootmode { + short unk0; + char id; + char len; + int data[0]; +}; + +typedef struct boot_params { + int ramMBSize; //+00/0 size of iop ram in megabytes (2 or 8) + int bootInfo; //+04/1 ==QueryBootMode(KEY_IOPbootinfo) + char* udnlString; //+08/2 points to the undl reboot string, NULL if no string + u32 firstModuleAddr;//+0C/3 the load address of the first module (sysmem) + int pos; //+10/4 + int size; //+14/5 + int numConfLines; //+18/6 number of lines in IOPBTCONF + u32** moduleAddrs; //+1C/7 pointer to an array of addresses to load modules from +} BOOT_PARAMS; //=20 + +void FlushIcache(); //4 (14) +void FlushDcache(); //5 (14,21,26) +int RegisterLibraryEntries(struct export*); //6 (05,06,07,13,14,17,18,28) +u32* QueryBootMode(int code); //12(11,21,25,26,28) +int loadcore_call20_registerFunc(int (*function)(int *, int), int a1, int *result); + //20(28) + +#endif//__LOADCORE_H__ diff --git a/fps2bios/kernel/iopload/include/ksifcmd.h b/fps2bios/kernel/iopload/include/ksifcmd.h new file mode 100644 index 0000000000..710a1385ba --- /dev/null +++ b/fps2bios/kernel/iopload/include/ksifcmd.h @@ -0,0 +1,162 @@ +#ifndef __SIFCMD_H__ +#define __SIFCMD_H__ + +#define SIFCMD_VER 0x101 + +#define SIF_CMDI_SYSTEM 0x80000000 // system function call +#define SIF_CMDC_CHANGE_SADDR ( SIF_CMDI_SYSTEM | 0x00000000) +#define SIF_CMDC_SET_SREG ( SIF_CMDI_SYSTEM | 0x00000001) +#define SIF_CMDC_INIT_CMD ( SIF_CMDI_SYSTEM | 0x00000002) +#define SIF_CMDC_RESET_CMD ( SIF_CMDI_SYSTEM | 0x00000003) + +#define SIF_CMDC_RPC_END ( SIF_CMDI_SYSTEM | 0x00000008) +#define SIF_CMDC_RPC_BIND ( SIF_CMDI_SYSTEM | 0x00000009) +#define SIF_CMDC_RPC_CALL ( SIF_CMDI_SYSTEM | 0x0000000A) +#define SIF_CMDC_RPC_RDATA ( SIF_CMDI_SYSTEM | 0x0000000C) + +typedef struct { + unsigned int psize:8; // packet size [16->112] + unsigned int dsize:24;// extra data size + unsigned int daddr; // extra data address + unsigned int fcode; // function code + unsigned int opt; // optional user parameter +} SifCmdHdr; + +typedef int (*cmdh_func) (SifCmdHdr*, void*); +typedef void *(*rpch_func)(u32 code, void *param1, int param2); + +typedef struct { + SifCmdHdr hdr; + void *newaddr; +} SifCmdCSData; + +typedef struct { + SifCmdHdr chdr; + int rno; + unsigned int value; +} SifCmdSRData; + +typedef struct { + SifCmdHdr chdr; + int size; + int flag; + char arg[80]; +} SifCmdResetData; + +struct sifcmd_RPC_SERVER_DATA{ //t_rpc_server_data + int command; /* 04 00 */ + + rpch_func func; /* 05 01 */ + void *buff; /* 06 02 */ + int size; /* 07 03 */ + + rpch_func cfunc; /* 08 04 */ + void *cbuff; /* 09 05 */ + int csize; /* 10 06 */ + + struct sifcmd_RPC_CLIENT_DATA*client; /* 11 07 */ + void *pkt_addr; /* 12 08 */ + int fno; /* 13 09 */ + + void *receive; /* 14 10 */ + int rsize; /* 15 11 */ + int rmode; /* 16 12 */ + int rid; /* 17 13 */ + + struct sifcmd_RPC_SERVER_DATA*link; /* 18 14 */ + struct sifcmd_RPC_SERVER_DATA*next; /* 19 15 */ + struct sifcmd_RPC_DATA_QUEUE *base; /* 20 16 */ +}; + + +struct sifcmd_RPC_HEADER{ //t_rpc_header + void *pkt_addr; /* 04 00 */ + u32 rpc_id; /* 05 01 */ + int tid; /* 06 02 */ + u32 mode; /* 07 03 */ +}; + + +struct sifcmd_RPC_CLIENT_DATA{ //t_rpc_client_data + struct sifcmd_RPC_HEADER hdr; + u32 command; /* 04 08 */ + void *buff, /* 05 09 */ + *cbuff; /* 06 10 */ + void (*func)(void*); /* 07 11 */ + void *param; /* 08 12*/ + struct sifcmd_RPC_SERVER_DATA*server; /* 09 13 */ +}; + +struct sifcmd_RPC_RECEIVE_DATA{ //t_rpc_receive_data + struct sifcmd_RPC_HEADER hdr; + void *src, /* 04 */ + *dest; /* 05 */ + int size; /* 06 */ +}; + +struct sifcmd_RPC_DATA_QUEUE{ //t_rpc_data_queue + int key, /* 00 */ + active; /* 01 */ + struct sifcmd_RPC_SERVER_DATA*link, /* 02 */ + *start, /* 03 */ + *end; /* 04 */ + struct sifcmd_RPC_DATA_QUEUE *next; /* 05 */ +}; + +typedef struct { + SifCmdHdr hdr; + u32 rec_id; + void *paddr; + u32 pid; +} RPC_PACKET; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + u32 command; + struct sifcmd_RPC_SERVER_DATA *server; + void *buff, *cbuff; +} RPC_PACKET_END; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + u32 fno; +} RPC_PACKET_BIND; + +typedef struct { + RPC_PACKET_BIND packet; + u32 size; + void *receive; + u32 rsize; + u32 rmode; + struct sifcmd_RPC_SERVER_DATA *server; +} RPC_PACKET_CALL; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + void *src; + void *dst; + u32 size; +} RPC_PACKET_RDATA; + + +typedef struct { + cmdh_func func; + void *data; +} SifCmdData; + +void SifInitCmd(); //4 (21) +void SifAddCmdHandler(int pos, cmdh_func func, void *data); //10(21) +void SifInitRpc(int mode); //14(26) +void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 cmd, + rpch_func func, void *buff, + rpch_func cfunc, void *cbuff, + struct sifcmd_RPC_DATA_QUEUE *dq); //17(26) +void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE* dq, int thid); //19(26) +void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE* dq); //22(26) +int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, + void *src, void *dst, int size, int mode); //23(26) + +#endif//__SIFCMD_H__ diff --git a/fps2bios/kernel/iopload/include/ksifman.h b/fps2bios/kernel/iopload/include/ksifman.h new file mode 100644 index 0000000000..89840cbb58 --- /dev/null +++ b/fps2bios/kernel/iopload/include/ksifman.h @@ -0,0 +1,57 @@ +#ifndef __SIFMAN_H__ +#define __SIFMAN_H__ + +#include + +#define SIFMAN_VER 0x101 + +#define SIF_FROM_IOP 0x0 +#define SIF_TO_IOP 0x1 +#define SIF_FROM_EE 0x0 +#define SIF_TO_EE 0x1 + +#define SIF_DMA_INT_I 0x2 +#define SIF_DMA_INT_O 0x4 +#define SIF_DMA_SPR 0x8 +#define SIF_DMA_BSN 0x10 +#define SIF_DMA_TAG 0x20 + +struct sifman_DMA { //t_sif_dma_transfer + void *data; + void *addr; + int size; + int attr; +}; + +void SifDeinit(); //2 + +void SifSIF2Init(); //4 +void SifInit(); //5 (21,25,26) +void SifSetDChain(); //6 +u32 SifSetDma(struct sifman_DMA* psd, int len); //7 (26) +int SifDmaStat(u32 id); //8 (26) +void SifSend(struct sifman_DMA sd); //9 +void SifSendSync(); //10 +int SifIsSending(); //11 +void SifSetSIF0DMA(void *data, int size, int attr); //12 +void SifSendSync0(); //13 +int SifIsSending0(); //14 +void SifSetSIF1DMA(void *data, int size, int attr); //15 +void SifSendSync1(); //16 +int SifIsSending1(); //17 +void SifSetSIF2DMA(void *data, int size, int attr); //18 +void SifSendSync2(); //19 +int SifIsSending2(); //20 +int SifGetEEIOPflags(); //21 +int SifSetEEIOPflags(int val); //22(21) +int SifGetIOPEEflags(); //23 +int SifSetIOPEEflags(int val); //24(28) +int SifGetEErcvaddr(); //25 +int SifGetIOPrcvaddr(); //26 +int SifSetIOPrcvaddr(int val); //27 +void SifSet1450_2(); //28 +int SifCheckInit(); //29(21,26) +void SifSet0CB(int (*_function)(int), int _param);//30 +void SifReset0CB(); //31 + +#endif /* __SIFMAN_H__ */ diff --git a/fps2bios/kernel/iopload/include/kstdio.h b/fps2bios/kernel/iopload/include/kstdio.h new file mode 100644 index 0000000000..0c392e3c77 --- /dev/null +++ b/fps2bios/kernel/iopload/include/kstdio.h @@ -0,0 +1,21 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +#define STDIO_VER 0x102 + +#define TAB 0x9 //\t +#define LF 0x10 //\n +#define CR 0x13 //\r + +void printf(const char *format, ...); // 4(21,25,26) +int getchar(); // 5 +//int putchar(int c); // 6 +int puts(char *s); // 7 +char *gets(char *s); // 8 +int fdprintf(int fd, const char *format, ...); // 9 +int fdgetc(int fd); //10 +int fdputc(int c, int fd); //11 +int fdputs(char *s, int fd); //12 +char *fdgets(char *buf, int fd); //13 + +#endif//__STDIO_H__ diff --git a/fps2bios/kernel/iopload/include/ksysclib.h b/fps2bios/kernel/iopload/include/ksysclib.h new file mode 100644 index 0000000000..bf7213cfdb --- /dev/null +++ b/fps2bios/kernel/iopload/include/ksysclib.h @@ -0,0 +1,46 @@ +#ifndef __SYSCLIB_H__ +#define __SYSCLIB_H__ + +#define SYSCLIB_VER 0x101 + +#include + +#define _U 01 +#define _L 02 +#define _N 04 +#define _S 010 +#define _P 020 +#define _C 040 +#define _X 0100 +#define _B 0200 + +extern const char _ctype_[]; + +#ifndef __cplusplus +#define isalpha(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L)) +#define isupper(c) ((_ctype_+1)[(unsigned)(c)]&_U) +#define islower(c) ((_ctype_+1)[(unsigned)(c)]&_L) +#define isdigit(c) ((_ctype_+1)[(unsigned)(c)]&_N) +#define isxdigit(c) ((_ctype_+1)[(unsigned)(c)]&(_X|_N)) +#define isspace(c) ((_ctype_+1)[(unsigned)(c)]&_S) +#define ispunct(c) ((_ctype_+1)[(unsigned)(c)]&_P) +#define isalnum(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L|_N)) +#define isprint(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N|_B)) +#define isgraph(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N)) +#define iscntrl(c) ((_ctype_+1)[(unsigned)(c)]&_C) +#endif /* !__cplusplus */ + +#define isascii(c) ((unsigned)(c)<=0177) +#define toascii(c) ((c)&0177) + +unsigned char look_ctype_table(int pos); +void* memset(void *s, int c, size_t n); +void bzero(void *s, size_t n); +int strcmp (const char *, const char *); +char* index (const char *s, int c); +int strlen (const char *); +char* strncpy(char *dest, const char *src, size_t n); +long int strtol(const char *nptr, char **endptr, int base); +//int prnt(void (*func)(void*, int), int *v, const char *format, ...); //18(17) + +#endif//__SYSCLIB_H__ diff --git a/fps2bios/kernel/iopload/include/ksysmem.h b/fps2bios/kernel/iopload/include/ksysmem.h new file mode 100644 index 0000000000..d6de342ac9 --- /dev/null +++ b/fps2bios/kernel/iopload/include/ksysmem.h @@ -0,0 +1,27 @@ +#ifndef __SYSMEM_H__ +#define __SYSMEM_H__ + +#include + +#define SYSMEM_VER 0x101 + +//allocation strategies +#define ALLOC_FIRST 0 +#define ALLOC_LAST 1 +#define ALLOC_LATER 2 + +// see QueryBlockTopAddress, QueryBlockSize +#define USED 0x00000000 +#define FREE 0x80000000 + +void *AllocSysMemory(int flags, int size, void *mem);//4 (11,26) +int FreeSysMemory(void *mem); //5 (26) +unsigned int QueryMemSize(); +unsigned int QueryMaxFreeMemSize(); +unsigned int QueryTotalFreeMemSize(); +void *QueryBlockTopAddress(void *address); +int QueryBlockSize(void *address); +char *Kprintf(const char *format,...); //14(06,14,26) +void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int unk, const char*, ...), unsigned int newunk); + +#endif //__SYSMEM_H__ diff --git a/fps2bios/kernel/iopload/include/kthbase.h b/fps2bios/kernel/iopload/include/kthbase.h new file mode 100644 index 0000000000..3b4000881b --- /dev/null +++ b/fps2bios/kernel/iopload/include/kthbase.h @@ -0,0 +1,19 @@ +#ifndef __THBASE_H__ +#define __THBASE_H__ + +#define THBASE_VER 0x101 + +struct thbase_thread{ + unsigned int attr; + unsigned int option; + int (*entry)(); + unsigned int stackSize; + unsigned int initPriority; +}; + +int CreateThread(struct thbase_thread*); //4 (21,26) //returns thid +void StartThread(int thid, int); //6 (21,26) +int GetThreadId(); //20(26) //returns thid? +int GetSystemStatusFlag(); //41(13,21) + +#endif//__THBASE_H__ diff --git a/fps2bios/kernel/iopload/include/kthsemap.h b/fps2bios/kernel/iopload/include/kthsemap.h new file mode 100644 index 0000000000..b89eed2b21 --- /dev/null +++ b/fps2bios/kernel/iopload/include/kthsemap.h @@ -0,0 +1,17 @@ +#ifndef __THSEMAP_H__ +#define __THSEMAP_H__ + +#define THSEMAP_VER 0x101 + +struct thsema_sema{ + unsigned int attr; + unsigned int option; + int initCount; + int maxCount; +}; + +int CreateSema(struct thsema_sema* sema); // 4(15) +int SignalSema(int semaid); // 6(15) +int WaitSema(int semaid); // 8(15) + +#endif//__THSEMAP_H__ diff --git a/fps2bios/kernel/iopload/include/ktimrman.h b/fps2bios/kernel/iopload/include/ktimrman.h new file mode 100644 index 0000000000..7a3b4a5ca5 --- /dev/null +++ b/fps2bios/kernel/iopload/include/ktimrman.h @@ -0,0 +1,48 @@ +#ifndef __TIMEMAN_H__ +#define __TIMEMAN_H__ + +#define TIMEMAN_VER 0x101 + +//timids << 2; use AllocHardTimer or ReferHardTimer to get one +#define RTC0 0xBF801100 +#define RTC1 0xBF801110 +#define RTC2 0xBF801120 + +#define RTC3 0xBF801480 +#define RTC4 0xBF801490 +#define RTC5 0xBF8014A0 + +#define RTC_HOLDREGS 0xBF8014B0 +#define RTC_HOLDMODE (*(volatile unsigned int*)0xBF8014C0) + +//source +#define TC_SYSCLOCK 1 +#define TC_PIXEL 2 +#define TC_HLINE 4 +#define TC_HOLD 8 + +//size +#define TIMER_SIZE_16 16 +#define TIMER_SIZE_32 32 + +//prescale +#define TIMER_PRESCALE_1 1 +#define TIMER_PRESCALE_8 8 +#define TIMER_PRESCALE_16 16 +#define TIMER_PRESCALE_256 256 + +int AllocHardTimer(int source, int size, int prescale); //4 +int ReferHardTimer(int source, int size, int mode, int modemask);//5 +int FreeHardTimer(int timid); //6 +void SetTimerMode(int timid, int mode); //7 +unsigned int GetTimerStatus(int timid); //8 +void SetTimerCounter(int timid, unsigned int count); //9 +unsigned int GetTimerCounter(int timid); //10 +void SetTimerCompare(int timid, unsigned int compare); //11 +unsigned int GetTimerCompare(int timid); //12 +void SetHoldMode(int holdnum, int mode); //13 +unsigned long GetHoldMode(int holdnum); //14 +unsigned long GetHoldReg(int holdnum); //15 +int GetHardTimerIntrCode(int timid); //16 + +#endif//__TIMEMAN_H__ \ No newline at end of file diff --git a/fps2bios/kernel/iopload/include/romdir.h b/fps2bios/kernel/iopload/include/romdir.h new file mode 100644 index 0000000000..e01eb98342 --- /dev/null +++ b/fps2bios/kernel/iopload/include/romdir.h @@ -0,0 +1,115 @@ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +// an entry in a romdir table. a romdir table is an array of these. +// gets filled in by searchRomDir() +typedef struct romdir_entry { + char name[10]; //+00 + short extSize; //+0A + int fileSize; //+0C +} __attribute__ ((packed)) ROMDIR_ENTRY; + + +// info about a file in a romdir +// gets filled in by searchFileInRom() +typedef struct { + ROMDIR_ENTRY* entry; // pointer to the file's ROMDIR_ENTRY + u32 fileData; // address of file contents + u32 extData; // address of file's ext info +} ROMFILE_INFO; + +// info about the location of a romdir table +typedef struct { + u32 romPtr; //+00 + ROMDIR_ENTRY* romdirPtr;//+04 + u32 extinfoPtr; //+08 +} ROMDIR_INFO; + +typedef struct romfs { + char* filename; //+00 + int fd; //+04 + int size; //+08 + ROMDIR_INFO romdirInfo; //+0C +} ROMFS; + +// rounds off a value to the next multiple +#define ROUND_UP(num, multiple) (((num)+multiple-1) & (~(multiple-1))) + +// searches between beginning and end addresses for a romdir structure. +// if found it returns info about it in romDirInfo. +// +// args: address to start searching from +// address to stop searching at +// gets filled in with info if found +// returns: a pointer to the filled in romDirInfo if successful +// NULL if error +extern ROMDIR_INFO* searchRomDir(const u32* searchStartAddr, const u32* searchEndAddr, ROMDIR_INFO* romDirInfo); + +// find a file in the romdir table and return info about it +// +// args: info about romdir to search through +// filename to search for +// structure to get info about file into +// returns: a pointer to fileinfo if successful +// NULL otherwise +extern ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo); + +// gets a hex number from *addr and updates the pointer +// +// args: pointer to string buffer containing a hex number +// returns: the value of the hex number +extern u32 getHexNumber(char** addr); + +/* +IOPBTCONF file format +===================== +each line is one of this: + +1. loading address of IOP kernel +Format: @ +Example: @800 +Default: 0 +Description: starting with (or 0 if not specified) the loader will + place modules in memory on 256 boundaries at +0x30 (the first 48 bytes are + reserved for info about the following module) + +2. address of function to be called while loading of IOP kernel +Format: !addr +Description: the code indicated by will be run on kernel loading + +3. name of (parent) included IOPBTCONF +Format: !include +Description: allow to have another file with same format to be loaded + recursively; support for this is limited because of the BUGGY parsing; +Note: you can have such option only at the begining of IOPBTCONF and the + inclusion can be made without getting stucked in recursion like this: + +ioprp1.img contains IOPBTCONF1 (!include IOPBTCON2) and IOPBTCONF11 +ioprp2.img contains IOPBTCONF2 (!include IOPBTCONF1) +ioprp.img contains IOPBTCONF (!include IOPBTCONF2!include IOPBTCONF11) +rom0 contains IOPBTCONF and IOPBTCON2 + +udnl cdrom0:ioprp1.img cdrom0:ioprp2.img cdrom0:ioprp.img + +the starting of the chain can be named IOPBTCONF only +also you can include only from the previous romz + +4. comment +Format: # +Example: #APPLOAD +Description: you can have comments on a line that starts with # + +5. modules that have to be loaded after a reset +Format: +Example: SYSMEM +Description: each line of IOPBTCONF usualy have a module name; the order the + modules appear in the list is the order they are loaded as IOP kernel +-------------------------------- +Notes: + - each line ends with , that is 0x0A + - in the final loading list the first 2 positions must be SYSMEM and LOADCORE +*/ + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/iopload/intrman/Makefile b/fps2bios/kernel/iopload/intrman/Makefile new file mode 100644 index 0000000000..2e84af2bd7 --- /dev/null +++ b/fps2bios/kernel/iopload/intrman/Makefile @@ -0,0 +1,61 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O0 -g -fomit-frame-pointer -nostartfiles -G0 --save-temps +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: intrman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = int_handler.o intrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_excepman.o + +intrman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/INTRMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.S + $(IOPAS) $(IOPASFLAGS) $< -o $@ +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/intrman/int_handler.s b/fps2bios/kernel/iopload/intrman/int_handler.s new file mode 100644 index 0000000000..c5a9446466 --- /dev/null +++ b/fps2bios/kernel/iopload/intrman/int_handler.s @@ -0,0 +1,373 @@ + +.set noreorder +.set noat + + .global EXCEP_Sys_handler + .ent EXCEP_Sys_handler +EXCEP_Sys_handler: + + .word 0 + .word 0 + + jal EXCEP_Sys_8 + nop # branch delay + + # restore status + lw $k0, EX_ST($0) + mtc0 $k0, $12 + + lw $k0, EX_PC($0) + add $k0, $k0, 4 + jr $k0 + cop0 0x10 + nop + .end EXCEP_Sys_handler + + +.equiv STACK_FRAME_SIZE, 0x90 +.equiv MODE0_ID, 0xAC0000FE +.equiv MODE1_ID, 0xFF00FFFE +.equiv MODE2_ID, 0xFFFFFFFE + +.equiv EX_AT, 0x400 +.equiv EX_PC, 0x404 +.equiv EX_ST, 0x408 +.equiv EX_CAUSE, 0x40C + +.equiv INTR_STACK_SIZE, 0x800 + +.equiv I_REG, 0x1070 +.equiv I_MASK, 0x1074 + +# ------------------------------------------------------------ +# This is installed as priority 3 - the end of the chain. +# does nothing. +# + .global EXCEP_Int_priority_exception_handler + .ent EXCEP_Int_priority_exception_handler +EXCEP_Int_priority_exception_handler: + + .word 0 + .word 0 + + lw $at, EX_AT($0) + + # restore status + lw $k0, EX_ST($0) + mtc0 $k0, $12 + + lw $k0, EX_PC($0) + jr $k0 + cop0 0x10 + nop + .end EXCEP_Int_priority_exception_handler + +# ------------------------------------------------------------ + + .global EXCEP_Int_handler + .ent EXCEP_Int_handler +EXCEP_Int_handler: + .word 0 + .word 0 + + # Initialise the mode 0 stack frame + sw $sp, 0x74-STACK_FRAME_SIZE($sp) + addiu $sp, $sp, -STACK_FRAME_SIZE + + lw $at, EX_AT($0) + sw $at, 0x04($sp) + sw $v0, 0x08($sp) + sw $v1, 0x0C($sp) + sw $a0, 0x10($sp) + sw $a1, 0x14($sp) + sw $a2, 0x18($sp) + sw $a3, 0x1C($sp) + sw $ra, 0x7C($sp) + mfhi $v0 + sw $v0, 0x80($sp) + mflo $v0 + sw $v0, 0x84($sp) + lw $v0, EX_ST($0) + sw $v0, 0x88($sp) + lw $v0, EX_PC($0) + sw $v0, 0x8C($sp) + la $v0, MODE0_ID + jal QueryIntrContext + sw $v0, 0x00($sp) # branch delay slot + + # Check whether this is a nested interrupt + # If it is not a nested interrupt then switch the stack to the interrupt context. + beq $v0, $0, $L_not_nested + or $v0, $sp, $sp # branch delay slot + # it is a nested interrupt + j $L1 + sub $sp, $sp, 0x0C # branch delay slot + +$L_not_nested: + # not a nested interrupt, so initialise to the top of the interrupt + # context stack. + la $sp, tempstack + addiu $sp, $sp, INTR_STACK_SIZE - 0x0C +$L1: + + sw $v0, 0x4($sp) # link the location of the previous stack frame + sw $0, 0x8($sp) # interrupt number (bit mask) + + lw $v0, EX_CAUSE($0) + andi $v0, $v0, 0x30 + bne $v0, $0, $L_SoftwareInt + nop + # The interrupt must have been caused by a hardware event + lui $k0, 0xBF80 + lw $a0, I_REG($k0) + lw $k0, I_MASK($k0) # k0 = I_MASK + and $a0, $a0, $k0 + lw $k1, soft_hw_intr_mask + and $a0, $a0, $k1 # a0 = I_REG & I_MASK & soft_hw_intr_mask + + beq $a0, $0, $L_ChainNextHandler # Interrupt is masked + nop + # The interrupt is not masked, so we should try and handle it + + # Figure out what interrupt is being handled. Look at the bits from the LSB and + # find the first one that is set. The LSB is interrupt 0 + la $a1, 0xFFFFFFFF # The interrupt being handled +$L_countInts: + addi $a1, $a1, 1 + andi $a2, $a0, 0x01 + beq $a2, $0, $L_countInts + srl $a0, 1 + + addiu $a0, $0, 0x1 + sllv $a0, $a0, $a1 # a0 = the bitmask of the int being handled + sw $a0, 0x8($sp) + nor $a0, $a0, $0 + and $k0, $a0, $k0 + lui $k1, 0xBF80 + sw $k0, I_MASK($k1) + sw $a0, I_REG($k1) + + sll $a0, $a1, 3 # Int num * 8 + lw $k0, intrtable + add $k0, $a0, $k0 + lw $a2, 0($k0) # handler + bne $a2, $0, $L_HandleInterrupt + lw $a3, 4($k0) # arg + +$L_ChainNextHandler: + + # Pass control to the next exception handler + lw $sp, 0x4($sp) # pop the value of the previous stack frame (could be a context switch) + + lw $at, 0x04($sp) + lw $v0, 0x08($sp) + lw $v1, 0x0C($sp) + lw $a0, 0x10($sp) + lw $a1, 0x14($sp) + lw $a2, 0x18($sp) + lw $a3, 0x1C($sp) + lw $ra, 0x7C($sp) + addiu $sp, $sp, STACK_FRAME_SIZE + lw $k0, EXCEP_Int_handler + jr $k0 + nop + +$L_SoftwareInt: + # $v0 = CAUSE & 0x30 is non-zero so the interrupt must have been caused by a software event + + andi $v0, $v0, 0x10 + bne $v0, $0, $L2 + addiu $a0, $0, 0x0100 # sw Int 1 + addiu $a0, $0, 0x0200 # sw Int 2 +$L2: + mfc0 $a1, $13 # cause + nor $a2, $a0, $0 + and $a1, $a1, $a2 # reset the relevent cause bit + mtc0 $a1, $13 + + srl $a0, $a0, 8 + addiu $a0, $a0, 0x2D # interrupt vector is 0x2E or 0x2F + sll $a0, $a0, 3 # Int num * 8 + lw $k0, intrtable + addu $k0, $a0, $k0 + lw $a2, 0($k0) # handler + beq $a2, $0, $L_ChainNextHandler # No handler defined + lw $a3, 4($k0) # arg + + # Both paths for SW and HW interrupts come together here. + # + # At this point: + # 0x8($sp) = int mask (0x01 << interrupt number) + # $a2 = handler + # $a3 = arg +$L_HandleInterrupt: + + andi $a0, $a2, 0x03 # $a0 = mode + srl $a2, $a2, 2 + beq $a0, $0, $L_Mode0 + sll $a2, $a2, 2 # $a2 = masked handler + + la $v1, MODE1_ID + srl $a0, $a0, 1 + beq $a0, $0, $L_Mode1 + lw $v0, 4($sp) + # Mode 2 or 3 (save t and s) + sw $s0, 0x40($v0) + sw $s1, 0x44($v0) + sw $s2, 0x48($v0) + sw $s3, 0x4C($v0) + sw $s4, 0x50($v0) + sw $s5, 0x54($v0) + sw $s6, 0x58($v0) + sw $s7, 0x5C($v0) + + la $v1, MODE2_ID + +$L_Mode1: + # Mode 1, save t + sw $t0, 0x20($v0) + sw $t1, 0x24($v0) + sw $t2, 0x28($v0) + sw $t3, 0x2C($v0) + sw $t4, 0x30($v0) + sw $t5, 0x34($v0) + sw $t6, 0x38($v0) + sw $t7, 0x3C($v0) + sw $t8, 0x60($v0) + sw $t9, 0x64($v0) + sw $gp, 0x70($v0) + sw $fp, 0x78($v0) + + sw $v1, 0x00($v0) # mark the current state of the stack + +$L_Mode0: + or $a0, $a3, $a3 + jalr $a2 # call the interrupt handler + mtc0 $0, $12 # status + beq $v0, $0, $L_NotHandled + lui $k0, 0xBF80 + + lw $a0, I_MASK($k0) + lw $a1, 0x08($sp) # interrupt mask + or $a0, $a0, $a1 + sw $a0, I_MASK($k0) + +$L_NotHandled: + + jal QueryIntrContext + nop + + bne $v0, $0, $L_afterContextSwitch + lw $a0, 4($sp) # previous stack frame + + # test if a context switch is pending. Returns true ($v0 != 0) if there is. + jal callContextSwitchRequiredHandler + nop + + beq $v0, $0, $L_afterContextSwitch + lw $a0, 4($sp) # previous stack frame + + lw $v0, 0($a0) # current stack context state + la $a1, MODE2_ID + beq $a1, $v0, $DoContextSwitch + nop + la $a1, MODE1_ID + beq $a1, $v0, $Mode1OnStack + nop + # stack state is currently mode 0 + sw $t0, 0x20($a0) + sw $t1, 0x24($a0) + sw $t2, 0x28($a0) + sw $t3, 0x2C($a0) + sw $t4, 0x30($a0) + sw $t5, 0x34($a0) + sw $t6, 0x38($a0) + sw $t7, 0x3C($a0) + sw $t8, 0x60($a0) + sw $t9, 0x64($a0) + sw $gp, 0x70($a0) + sw $fp, 0x78($a0) +$Mode1OnStack: + sw $s0, 0x40($a0) + sw $s1, 0x44($a0) + sw $s2, 0x48($a0) + sw $s3, 0x4C($a0) + sw $s4, 0x50($a0) + sw $s5, 0x54($a0) + sw $s6, 0x58($a0) + sw $s7, 0x5C($a0) + + la $v1, MODE2_ID + sw $v1, 0($a0) + +$DoContextSwitch: + la $v0, context_switch_handler + lw $v0, 0($v0) + jalr $v0 # do the context switch, returns the new stack in $v0 + nop + addu $a0, $v0, $0 + +$L_afterContextSwitch: + + # At this point: + # + # $a0 = stack frame to switch to + + or $sp, $a0, $a0 + lw $a0, 0($sp) + la $a1, MODE0_ID + + beq $a0, $a1, $L_RestoreMode0 + nop + + la $a1, MODE1_ID + beq $a0, $a1, $L_RestoreMode1 + nop + # mode 2, restore t and s + lw $s0, 0x40($sp) + lw $s1, 0x44($sp) + lw $s2, 0x48($sp) + lw $s3, 0x4C($sp) + lw $s4, 0x50($sp) + lw $s5, 0x54($sp) + lw $s6, 0x58($sp) + lw $s7, 0x5C($sp) + +$L_RestoreMode1: + # mode 1, restore t + lw $t0, 0x20($sp) + lw $t1, 0x24($sp) + lw $t2, 0x28($sp) + lw $t3, 0x2C($sp) + lw $t4, 0x30($sp) + lw $t5, 0x34($sp) + lw $t6, 0x38($sp) + lw $t7, 0x3C($sp) + lw $t8, 0x60($sp) + lw $t9, 0x64($sp) + lw $gp, 0x70($sp) + lw $fp, 0x78($sp) + +$L_RestoreMode0: + lw $a0, 0x80($sp) + mthi $a0 + lw $a0, 0x84($sp) + mtlo $a0 + lw $a0, 0x88($sp) + srl $a0, $a0, 1 + sll $a0, $a0, 1 + mtc0 $a0, $12 # status (reset bit 0) + lw $at, 0x04($sp) + lw $v0, 0x08($sp) + lw $v1, 0x0C($sp) + lw $a0, 0x10($sp) + lw $a1, 0x14($sp) + lw $a2, 0x18($sp) + lw $a3, 0x1C($sp) + lw $ra, 0x7C($sp) + lw $k0, 0x8C($sp) + lw $sp, 0x74($sp) + jr $k0 + cop0 0x10 # rfe + + .end EXCEP_Int_handler diff --git a/fps2bios/kernel/iopload/intrman/intrman.c b/fps2bios/kernel/iopload/intrman/intrman.c new file mode 100644 index 0000000000..d7e0449e6d --- /dev/null +++ b/fps2bios/kernel/iopload/intrman/intrman.c @@ -0,0 +1,705 @@ + +#define _GNU_SOURCE + +#include "kloadcore.h" +#include "kexcepman.h" +#include "kintrman.h" +#include "err.h" + +#define ICFG (*(volatile int*)0xbf801450) +#define IREG (*(volatile int*)0xbf801070) +#define IMASK (*(volatile int*)0xbf801074) +#define ICTRL (*(volatile int*)0xbf801078) +#define DMA_ICR (*(volatile int*)0xbf8010F4) +#define DMA_ICR2 (*(volatile int*)0xbf801574) + +#define EXCEP_CAUSE (*(volatile int*)0x40C) + +int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("intrman: " fmt, ## args) + +struct intrHandler { + u32 handler; + void *arg; +}; + +func context_switch_required_handler; +func context_switch_handler; + +// Additional interrupt mask applied after IMASK +u32 soft_hw_intr_mask; + +int unknown2[4]; //0x1280 up + +#define INTR_STACK_SIZE 0x800 +unsigned char tempstack[INTR_STACK_SIZE]; + +u32 *extable; +struct intrHandler *intrtable; + +extern struct export export_stub; + +int _start(); +int IntrHandler(); +void intrman_retonly(); + +/////////////////////////////syscalls////////////////////////////////// +__inline void syscall_0(); +void syscall_1_CpuDisableIntr(); +void syscall_2_CpuEnableIntr(); +void syscall_3_intrman_call14(); +void syscall_4_intrman_call17_19(); +void syscall_5_intrman_call18_20(); +void goto_EXCEP_Sys_handler(); +void syscall_8_threadman(); + +func syscall[] = { + (func)syscall_0, +/* (func)syscall_1_CpuDisableIntr, + (func)syscall_2_CpuEnableIntr, + (func)syscall_3_intrman_call14, + (func)syscall_4_intrman_call17_19, + (func)syscall_5_intrman_call18_20, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)syscall_8_threadman, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler, + (func)goto_EXCEP_Sys_handler*/ +}; + +/////////////////////////////////////////////////////////////////////// +int intrmanDeinit() { + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int intrman_call2() +{ + IMASK = 0x00; + DMA_ICR = 0x00; + DMA_ICR2 = 0x00; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int intrman_call3(){ + return (int)&unknown2; +} + +/////////////////////////////////////////////////////////////////////// +// +// interrupt values 0x2E - 0x3F are equivalent to 0x1E - 0x2F with a mode set +// interrupt values 0x20 - 0x2D have their mode forced to zero +// +// mode specifies what registers to save around the call +// 0 = don't save anything, handler will not change anything +// 1 = save t0 - t9, gp and fp +// 2 = save t0 - t9, gp, fp and s0 - s7 +// +// arg is the value passed to the interrupt handler when it is called +// +int RegisterIntrHandler(int interrupt, int mode, intrh_func handler, void *arg) +{ + u32 ictrl; + + _dprintf("%s interrupt=%x, mode=%x\n", __FUNCTION__, interrupt, mode); + if (QueryIntrContext()){ + // cannot be called from within an interrupt + _dprintf("%s ERROR_INTR_CONTEXT\n", __FUNCTION__); + return ERROR_INTR_CONTEXT; + } + CpuSuspendIntr(&ictrl); + + if (interrupt < 0 || interrupt > 0x3F) { + CpuResumeIntr(ictrl); + _dprintf("%s ERROR_ILLEGAL_INTRCODE\n", __FUNCTION__); + return ERROR_ILLEGAL_INTRCODE; + } + int real_interrupt = interrupt; + int real_mode = mode; + + if (interrupt >= 0x2E){ + real_interrupt -= 0x10; + } else if (interrupt >= 0x20){ + real_mode = 0; + } + + if (intrtable[real_interrupt].handler){ + CpuResumeIntr(ictrl); + _dprintf("%s ERROR_DOES_EXIST\n", __FUNCTION__); + return ERROR_DOES_EXIST; + } + intrtable[real_interrupt].handler = (mode & 0x03) | (u32)handler; + intrtable[real_interrupt].arg = arg; + CpuResumeIntr(ictrl); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int ReleaseIntrHandler(int interrupt) +{ + u32 ictrl; + + if (QueryIntrContext()){ + // Cannot be called from within an interrupt + return ERROR_INTR_CONTEXT; + } + CpuSuspendIntr(&ictrl); + + if (interrupt < 0 || interrupt >= 0x40) { + CpuResumeIntr(ictrl); + return ERROR_ILLEGAL_INTRCODE; + } + if (interrupt >= 0x2E){ + interrupt -= 0x10; + } + + if (intrtable[interrupt].handler){ + intrtable[interrupt].handler = 0; + CpuResumeIntr(ictrl); + return 0; + } + CpuResumeIntr(ictrl); + return ERROR_DOES_EXIST; +} + +/////////////////////////////////////////////////////////////////////// +int CpuSuspendIntr(u32 *ictrl) +{ + u32 rval = ICTRL; + if (ictrl) *ictrl = rval; + if (rval == 0) return ERROR_CPUDI; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int CpuResumeIntr(u32 ictrl) +{ + ICTRL = ictrl; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int CpuDisableIntr() +{ + if (ICTRL) return 0; + return ERROR_CPUDI; +} + +/////////////////////////////////////////////////////////////////////// +int CpuEnableIntr() +{ + //_dprintf("%s\n", __FUNCTION__); +// intrman_syscall_08(); +// _dprintf("syscall ok\n"); + CpuEnableICTRL(); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int CpuGetICTRL() +{ + return ICTRL; +} + +/////////////////////////////////////////////////////////////////////// +int CpuEnableICTRL() +{ + ICTRL = 1; + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void intrman_syscall_04() +{ + __asm__ ( + "li $3, 4\n" + "syscall\n" + ); +} + +/////////////////////////////////////////////////////////////////////// +void intrman_syscall_08() +{ + __asm__ ( + "li $3, 8\n" + "syscall\n" + ); +} + +/////////////////////////////////////////////////////////////////////// +void intrman_syscall_10() +{ + __asm__ ( + "li $3, 16\n" + "syscall\n" + ); +} + +/////////////////////////////////////////////////////////////////////// +void intrman_syscall_14() +{ + __asm__ ( + "li $3, 20\n" + "syscall\n" + ); +} + +/////////////////////////////////////////////////////////////////////// +void intrman_syscall_0C() +{ + __asm__ ( + "li $3, 12\n" + "syscall\n" + ); +} + +/////////////////////////////////////////////////////////////////////// +// +// Interrupt: +// 0 - 0x1F normal interrupt +// 0x20 - 0x26 +// 0x27 - 0x2D +// +// Return 0 for success, -101 for invalid interrupt number +// +#define ERROR_BAD_NUMBER -101 +#define INUM_DMA_0 0x20 +#define INUM_DMA_BERR 0x27 +#define INUM_DMA_7 0x28 +#define IMODE_DMA_IRM 0x100 +#define IMODE_DMA_IQE 0x200 +#define INUM_DMA 3 + +int EnableIntr(int interrupt) +{ + int retval = 0; + u32 low_irq = interrupt & 0xFF; + u32 high_irq = interrupt & 0xFFFFFF00; + + u32 ictrl; + CpuSuspendIntr(&ictrl); + + if( interrupt < 0 ) { + retval = ERROR_BAD_NUMBER; + } + else if (low_irq < INUM_DMA_0){ + IMASK |= (1 << low_irq); + } else if (low_irq < INUM_DMA_BERR){ + DMA_ICR = (DMA_ICR & ((~(1<<(low_irq-INUM_DMA_0)))&0x00FFFFFF)) + | (1 << (INUM_DMA_BERR-INUM_DMA_0 + 16)) + | (1<<(low_irq-INUM_DMA_0+0x10)) + | ((high_irq & IMODE_DMA_IRM) ? (1<<(low_irq-INUM_DMA_0)) : 0); + + DMA_ICR2 = (DMA_ICR2 & ((~(1<<(low_irq-INUM_DMA_0)))&0x00FFFFFF)) + | ((high_irq & IMODE_DMA_IQE) ? (1<<(low_irq-0x10)) : 0); + + IMASK |= 1<>(low_irq-0x20)) & 0x01) stat = low_irq | 0x100; + + if (DMA_ICR2 & (1<<(low_irq-0x20))) stat |= 0x200; + + DMA_ICR2 &= ~(1<<(low_irq-0x20)) & 0xFFFFFF; + + goto end; + } + + ret = -103; + goto end; + } + + if (low_irq<0x2E) + { + if (DMA_ICR2 & 0xFFFFFF & (1<<(low_irq-0x18))) + { + stat = low_irq; + + if (((DMA_ICR2 & 0xFFFFFF)>>(low_irq-0x21))&0x01) stat |= 0x200; + + DMA_ICR2 &= ~(1<<(low_irq-0x18)) & 0xFFFFFF; + + goto end; + } + + ret = -103; + goto end; + } + +end: + if (oldstat) *(volatile int*)oldstat = stat; + CpuResumeIntr(ictrl); + return ret; +} + +/////////////////////////////////////////////////////////////////////// +// Enable +void intrman_call16(int interrupt) +{ + u32 ictrl; + CpuSuspendIntr(&ictrl); + + interrupt &= 0xFF; + + if (interrupt < 0x20){ + soft_hw_intr_mask |= (1 << interrupt); + } else if (interrupt < 0x28){ + unknown2[1] |= 1 << (interrupt-0x08); + } else if (interrupt < 0x2E){ + unknown2[2] |= 1 << (interrupt-0x10); + } + + CpuResumeIntr(ictrl); +} + +/////////////////////////////////////////////////////////////////////// +// Disable +void intrman_call15(int interrupt) +{ + u32 ictrl; + CpuSuspendIntr(&ictrl); + + interrupt &= 0xFF; + + if (interrupt < 0x20){ + soft_hw_intr_mask &= ~(1 << interrupt); + } else if (interrupt < 0x28){ + unknown2[1] &= ~(1 << (interrupt-0x08)); + } else if (interrupt < 0x2E){ + unknown2[2] &= ~(1 << (interrupt-0x10)); + } + + CpuResumeIntr(ictrl); +} + +/////////////////////////////////////////////////////////////////////// +void intrman_call27(int arg0) +{ + unknown2[3]=arg0; +} + +/////////////////////////////////////////////////////////////////////// +// +int IntrHandler() +{ + u32 masked_icr = DMA_ICR & unknown2[1]; + + _dprintf("%s\n", __FUNCTION__); + + + while (masked_icr & 0x7F008000){ + int i; + if (masked_icr & 0x00008000){ + // Int 0x25 + func int_func = (func)(intrtable[0x25].handler & 0xFFFFFFFC); + DMA_ICR &= 0x00FF7FFF; + if (int_func){ + int_func(intrtable[0x25].arg); + } + } + // Check each DMA interrupt + // The bits 24 - 30 are set for DMA channels 0 - 6 (ints 0x20 - 0x26 respectively) + // The bits 16 - 23 are the corresponding mask bits - the interrupt is only generated if the mask bit is set. + for (i=0; i < 7; ++i){ + u32 ibit = 0x01000000 << i; + if (masked_icr & ibit){ + func int_func = (func)(intrtable[0x20+i].handler & 0xFFFFFFFC); + DMA_ICR &= (ibit | 0x00FFFFFF); + if (int_func){ + if (!int_func(intrtable[0x20+i].arg)){ + // Disable / mask the interrupt if it was not handled + DMA_ICR &= (~(0x00010000 << i) & 0x00FFFFFF); + } + } + } + } + } + DMA_ICR &= 0x007FFFFF; + while (DMA_ICR & 0x00800000){ + // do nothing + } + + { + u32 temp_icr = DMA_ICR; + temp_icr &= 0x007FFFFF; + temp_icr |= 0x00800000; + DMA_ICR = temp_icr; + } + + return 1; +} + +/////////////////////////////////////////////////////////////////////// +// +// Default context switch handler - does not switch context. +// +int default_ctx_switch_handler(u32 sp_in) +{ + return sp_in; +} + +/////////////////////////////////////////////////////////////////////// +// +// Default routine to request a context switch. Does not request one. +// +int default_ctx_switch_required_handler() +{ + return 0; +} + + +void SetCtxSwitchHandler(func handler){ + context_switch_handler = handler; +} + +void* ResetCtxSwitchHandler() +{ + context_switch_handler = default_ctx_switch_handler; + return &context_switch_handler; +} + +void SetCtxSwitchReqHandler(func handler) +{ + context_switch_required_handler = handler; +} + +int ResetCtxSwitchReqHandler() +{ + context_switch_required_handler = default_ctx_switch_required_handler; +} + +/////////////////////////////////////////////////////////////////////// +// Return non-zero if sp is in an interrupt context +int QueryIntrStack(unsigned char* sp) +{ + int retval = 0; + if ( (sp < tempstack + INTR_STACK_SIZE) && (sp > tempstack) ){ + retval = 1; + } + return retval; +} + +/////////////////////////////////////////////////////////////////////// +// Return non-zero is we're currently in a interrupt context +int QueryIntrContext() +{ + unsigned char* sp; + __asm__ ("move %0, $29\n" : "=r"(sp) :); + + return QueryIntrStack(sp); +} + +/////////////////////////////////////////////////////////////////////// +// +int iCatchMultiIntr() +{ + unsigned char* sp; + __asm__ ("move %0, $29\n" : "=r"(sp) :); + + if (QueryIntrStack(sp)){ + if (sp >= tempstack + 0x160){ + u32 SR; + __asm__ ("mfc0 %0, $12\n" : "=r"(SR)); + if (SR & 1 == 0){ + u32 set_SR = SR | 1; + __asm__ volatile ( + "mtc0 %0, $12\n" + "nop\n" + "nop\n" + "mtc0 %1, $12\n" : : "r"(set_SR), "r" (SR) + ); + } + return SR; + } + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////// +// called by EXCEP_Sys_handler +void EXCEP_Sys_8() { + _dprintf("%s\n", __FUNCTION__); +} +/////////////////////////////////////////////////////////////////////// +//not finished +void syscall_3_intrman_call14(){ +} + +/////////////////////////////////////////////////////////////////////// +//not finished +void syscall_4_intrman_call17_19(){ +} + +/////////////////////////////////////////////////////////////////////// +__inline void syscall_0(){ + func funct; + funct=(func)((*(volatile int*)(0x404))+4); + __asm__ ( + "jr %0\n" + "rfe\n" + : "=r" (funct) + ); +} + +/////////////////////////////////////////////////////////////////////// +void retonly(){} + +u32 callContextSwitchRequiredHandler() +{ + if (NULL != context_switch_required_handler){ + return context_switch_required_handler(); + } else { + return 0; + } +} + +//////////////////////////////entrypoint/////////////////////////////// +struct export export_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "intrman", + (func)_start, // entrypoint + (func)intrmanDeinit, + (func)intrman_call2, + (func)intrman_call3, + (func)RegisterIntrHandler, + (func)ReleaseIntrHandler, + (func)EnableIntr, + (func)DisableIntr, + (func)CpuDisableIntr, + (func)CpuEnableIntr, + (func)intrman_syscall_04, // 0x0A + (func)intrman_syscall_08, + (func)CpuGetICTRL, + (func)CpuEnableICTRL, + (func)intrman_syscall_0C, // 0x0E + (func)intrman_call15, + (func)intrman_call16, // 0x10 + (func)CpuSuspendIntr, + (func)CpuResumeIntr, + (func)CpuSuspendIntr, + (func)CpuResumeIntr, + (func)intrman_syscall_10, + (func)intrman_syscall_14, + (func)QueryIntrContext, // 0x17 + (func)QueryIntrStack, + (func)iCatchMultiIntr, + (func)retonly, + (func)intrman_call27, + (func)SetCtxSwitchHandler, // 0x1C (called by threadman) + (func)ResetCtxSwitchHandler, + (func)SetCtxSwitchReqHandler, // 0x1E (called by threadman) + (func)ResetCtxSwitchReqHandler, + 0 +}; + +extern struct exHandler EXCEP_Int_priority_exception_handler; +extern struct exHandler EXCEP_Int_handler; +extern struct exHandler EXCEP_Sys_handler; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(){ + int i; + + intrtable = (struct intrHandler*)(GetExHandlersTable() + 0x40); + + IMASK = 0x00; + DMA_ICR = 0x00; + DMA_ICR2 = 0x00; + + for (i=0; i < 0x2F; i++) { + intrtable[i].handler = 0; + intrtable[i].arg = 0; + } + + soft_hw_intr_mask = 0xFFFFFFFF; + unknown2[1] = -1; + unknown2[2] = -1; + unknown2[0] = (int)intrtable; + + RegisterExceptionHandler(0, &EXCEP_Int_handler); + RegisterPriorityExceptionHandler(0, 3, &EXCEP_Int_priority_exception_handler); + RegisterExceptionHandler(8, &EXCEP_Sys_handler); + RegisterIntrHandler(3, 1, &IntrHandler, 0); + RegisterLibraryEntries(&export_stub); + + return 0; +} + +void ijb_ping1() +{ + _dprintf("%s\n", __FUNCTION__); + unsigned char* x = tempstack; +} +void ijb_trace3(u32 a0, u32 a1, u32 a2, u32 a3) +{ + __printf("trace3: 0x%x, 0x%x, 0x%x\n", a0, a1, a2); +while (1){} +} diff --git a/fps2bios/kernel/iopload/iopboot/Makefile b/fps2bios/kernel/iopload/iopboot/Makefile new file mode 100644 index 0000000000..8450079bb4 --- /dev/null +++ b/fps2bios/kernel/iopload/iopboot/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: iopboot + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = iopboot.o ../iopdebug.o ../iopelf.o ../romdir.o + +iopboot: $(OBJECTS) + $(EELD) -Wl,--oformat,binary,--Map,iopboot.map -T linkfile $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/IOPBOOT + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/iopboot/iopboot.c b/fps2bios/kernel/iopload/iopboot/iopboot.c new file mode 100644 index 0000000000..481755eb9b --- /dev/null +++ b/fps2bios/kernel/iopload/iopboot/iopboot.c @@ -0,0 +1,252 @@ +// +// iopboot.c +// +// this is the c code for the iopboot file in the ps2 rom. +// this file is located at 0xBFC4A000 in the ps2 bios rom0. +// modload.irx also from the ps2 bios executes this direct from the rom +// (no loading to ram first) +// +// this is based on florin's disasm and converted to c code by xorloser and zerofrog +// + +#include +#include + +#include "iopload.h" +#include "iopdebug.h" +#include "iopelf.h" +#include "romdir.h" +#include "kloadcore.h" + +static void kstrcpy(char* dst, const char* src); +static int kstrlen(const char* src); + +//BOOT_PARAMS boot_params; +//u32* next_free_address[0x40]; // up to 64 modules + + +// this is the start point of execution at 0xBFC4A000 +// +// it loads the IOPBTCONF module list from rom0 and compiles a +// list of modules and their addresses. +// +// this list is then passed to loadcore as it is executed in order +// to then load the rest of the modules +// +// args: total size of IOP ram in MegaBytes +// bootinfo flags +// string containing the reboot image filepath +// ? doesnt seem to be used +void _start(int ramMBSize, int bootInfo, char* udnlString, int unk) +{ + ROMFS ri; + void *(*sysmem_entry)(u32 iopmemsize); + void (*loadcore_entry)(BOOT_PARAMS *init); + int i; + ROMDIR_INFO romdir_info; + ROMFILE_INFO romfile_info; + char conf_filename[10]; + int ram_byte_size, num_lines; + u32 module_load_addr; + u32** modules_ptr; + char* file_data_ptr, *file_data_end; + void* psysmemstart; + BOOT_PARAMS* boot_params; + + if( ramMBSize <= 2 ) + ram_byte_size = 2; + else + ram_byte_size = ramMBSize; + ram_byte_size <<= 20; + + // compile module list to send to loadcore + boot_params = (BOOT_PARAMS*)0x30000; // random address, has to be clear before loadcore call + boot_params->ramMBSize = ramMBSize; + boot_params->bootInfo = bootInfo; + boot_params->udnlString = NULL; + boot_params->moduleAddrs = (u32**)((u32)boot_params + sizeof(BOOT_PARAMS)); // right after + + // if a undl string is specified, get a copy of it and store a pointer to it + if(udnlString) + { + boot_params->udnlString = (char*)boot_params->moduleAddrs; + kstrcpy(boot_params->udnlString, udnlString); + boot_params->moduleAddrs = (u32**)((u32)boot_params->udnlString + ROUND_UP(kstrlen(udnlString) + 8, 4)); + } + + // find the romdir table in the rom + if( searchRomDir((u32*)0xBFC00000, (u32*)0xBFC10000, &romdir_info) == NULL ) + { + __printf("IOPBOOT: failed to find start of rom!\n"); + // error - cant find romdir! + while(1) *(u8*)0x80000000 = 0; + } + + // find the bootconf file in the romdir table + kstrcpy(conf_filename, "IOPBTCONF"); + conf_filename[8] = '0' + bootInfo; + if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) + { + kstrcpy(conf_filename, "IOPBTCONF"); + if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) + { + __printf("IOPBTCONF file not found!\n"); + // error - cant find conf file! + while(1) *(u8*)0x80000000 = 1; + } + } + + // count the number of lines in conf file + file_data_ptr = (char*)romfile_info.fileData; + file_data_end = (char*)romfile_info.fileData + romfile_info.entry->fileSize; + { + num_lines = 0; + while( file_data_ptr < file_data_end ) { + // loop until a "newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ < ' ') + break; + } + + // loop until a "non-newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ >= ' ') + break; + } + + num_lines++; + } + num_lines++; + } + + // get the addresses of each module + { + module_load_addr = 0; + boot_params->numConfLines = num_lines-1; + modules_ptr = boot_params->moduleAddrs; + char* file_data_ptr = (char*)romfile_info.fileData; + while( file_data_ptr < file_data_end ) { + if(*file_data_ptr == '@') { + file_data_ptr++; + module_load_addr = getHexNumber(&file_data_ptr); + } + else if(*file_data_ptr == '!') { + if( file_data_ptr[1] == 'a' && + file_data_ptr[2] == 'd' && + file_data_ptr[3] == 'd' && + file_data_ptr[4] == 'r' && + file_data_ptr[5] == ' ' ) { + file_data_ptr += 6; + *modules_ptr++ = (u32*)(getHexNumber(&file_data_ptr) * 4 + 1); + *modules_ptr++ = 0; + } + } + else if(*file_data_ptr != '#') { + // 'file_data_ptr' should be pointing to a filename + // this finds the address of that file in the rom + ROMFILE_INFO module_fileinfo; + char strmodule[16]; + for(i = 0; i < 16; ++i) { + if( file_data_ptr[i] < ' ' ) + break; + strmodule[i] = file_data_ptr[i]; + } + strmodule[i] = 0; + + if( searchFileInRom(&romdir_info, strmodule, &module_fileinfo) == NULL ) { + __printf("IOPBOOT: failed to find %s module\n", strmodule); + return; + } + + //__printf("mod: %s:%x\n", strmodule, module_fileinfo.fileData); + + *modules_ptr++ = (u32*)module_fileinfo.fileData; + *modules_ptr = 0; // don't increment + } + + // loop until a "newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ < ' ') + break; + } + + // loop until a "non-newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr >= ' ') + break; + file_data_ptr++; + } + } + } + + if( searchFileInRom(&romdir_info, "IOPBOOT", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find IOPBOOT module\n"); + return; + } + + // load sysmem module to memory and execute it + if( searchFileInRom(&romdir_info, "SYSMEM", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find SYSMEM module\n"); + return; + } + sysmem_entry = (void *(*)(u32))loadElfFile(&romfile_info, module_load_addr); + if( sysmem_entry == 0 ) + return; + + psysmemstart = sysmem_entry(ram_byte_size); + //FlushIcache(); + if( psysmemstart == 0 ) { + __printf("IOPBOOT: sysmem failed\n"); + return; + } + + __printf("SYSMEM success, start addr: %x, alloc start: %x\n", module_load_addr, psysmemstart); + + if( searchFileInRom(&romdir_info, "LOADCORE", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find SYSMEM module\n"); + return; + } + loadcore_entry = (void (*)())loadElfFile(&romfile_info, (u32)psysmemstart); + if( loadcore_entry == 0 ) + return; + + boot_params->firstModuleAddr = (u32)module_load_addr + 0x30; // skip elf? + if(0x1FC10000 < ram_byte_size) { + boot_params->pos = 0x1FC00000; + boot_params->size = 0x10100; + } + else { + boot_params->pos = 0; + boot_params->size = 0; + } + + __printf("executing LOADCORE entry at %p\n", loadcore_entry); + loadcore_entry(boot_params); + + __printf("iopboot error\n"); + + // error - loadcore shouldnt ever return + while(1) *(u8*)0x80000000 = 2; +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + +static void kstrcpy(char* dst, const char* src) +{ + while(*src) *dst++ = *src++; + *dst = 0; +} + +static int kstrlen(const char* src) +{ + int len = 0; + while(*src++) len++; + return len; +} diff --git a/fps2bios/kernel/iopload/iopboot/iopirq.c b/fps2bios/kernel/iopload/iopboot/iopirq.c new file mode 100644 index 0000000000..853d0b223f --- /dev/null +++ b/fps2bios/kernel/iopload/iopboot/iopirq.c @@ -0,0 +1,17 @@ + + +// Boiler plate exception handlers used at boot time. +// EXCEPMAN replaces these with something more useful. + +__asm__(".org 0x0000"); + +__asm__(".set noreorder"); +void CpuException0() { +} + +__asm__(".org 0x0080"); + +__asm__(".set noreorder"); +void CpuException() { +} + diff --git a/fps2bios/kernel/iopload/iopboot/linkfile b/fps2bios/kernel/iopload/iopboot/linkfile new file mode 100644 index 0000000000..07af75d528 --- /dev/null +++ b/fps2bios/kernel/iopload/iopboot/linkfile @@ -0,0 +1,16 @@ +_stack_size = 0x80000; +_heap_size = 1024*1024*10; + +ENTRY(_start); +SECTIONS { + .text 0xbfc008f0 : { + *(.text) + *(.data) + *(.rdata) + *(.sdata) + *(.rodata) + *(.bss) + *(.sbss) + } +} + diff --git a/fps2bios/kernel/iopload/iopdebug.c b/fps2bios/kernel/iopload/iopdebug.c new file mode 100644 index 0000000000..a5551a46e5 --- /dev/null +++ b/fps2bios/kernel/iopload/iopdebug.c @@ -0,0 +1,279 @@ +/* Debugging printf, for debugging the library itself. + + We don't assume stdio is working. + We do assume _write_r is working. +*/ + +#include "iopload.h" +#include "iopdebug.h" + +#ifdef __STDC__ +#include "stdarg.h" +#else +#include "varargs.h" +#endif + +static char *parse_number (); +static long get_number (); +static void print_number (); +static void write_char (char c); +static void write_string (char* s); + +/* Non-zero for big-endian systems. */ +static int big_endian_p; + +/* For now hardcode 2 (stderr) as the console file descriptor. + May wish to let the caller pass in a file descriptor or some such but + this is only for debugging purposes anyway. */ +#define CONSOLE_FD 2 + +/* Standalone printf routine. + + The format string has been enhanced so that multiple values can be dumped + without having to have a %-field for each one (say if you want to dump + 20 words at a certain address). A modifier of `N' says the next argument + is a count, and the one after that is a pointer. + + Example: __dprintf (stderr, "%Nx\n", 20, p); /-* print 20 ints at `p' *-/ + + Supported formats are: c d u x s p. + + All ints are retrieved a byte at a time so alignment issues are not + a problem. + + This routine is used in situations where the only debugging capability + is console output and was written to aid debugging newlib itself. We don't + use printf ourselves as we may be debugging it. We do assume _write_r is + working. +*/ + +void +#ifdef __STDC__ +__printf (char *fmt, ...) +#else +__printf (fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list args; + + /* Which endian are we? */ + { + short tmp = 1; + big_endian_p = *(char *) &tmp == 0; + } + +#ifdef __STDC__ + va_start (args, fmt); +#else + va_start (args); +#endif + + while (*fmt) + { + char c, *p; + int count; + long l; + + if (*fmt != '%' || *++fmt == '%') + { + write_char (*fmt++); + continue; + } + + if (*fmt == 'N') + { + count = va_arg (args, int); + p = va_arg (args, char *); + ++fmt; + c = *fmt++; + + while (--count >= 0) + { + switch (c) + { +// case 'c' : +// write_string (unctrl (*p++)); +// break; + case 'p' : + print_number (16, 1, get_number (p, sizeof (char *), 1)); + p += sizeof (char *); + break; + case 'd' : + case 'u' : + case 'x' : + print_number (c == 'x' ? 16 : 10, c != 'd', + get_number (p, sizeof (int), c != 'd')); + p += sizeof (int); + break; + case 's' : + write_string (*(char **) p); + p += sizeof (char *); + break; + } + if (count > 0) + write_char (' '); + } + } + else + { + switch (c = *fmt++) + { +// case 'c' : +// c = va_arg (args, int); +// write_string (unctrl (c)); +// break; + case 'p' : + l = (void *) va_arg (args, char *); + print_number (16, 1, l); + break; + case 'd' : + case 'u' : + case 'x' : + l = va_arg (args, int); + print_number (c == 'x' ? 16 : 10, c != 'd', l); + break; + case 's' : + p = va_arg (args, char *); + write_string (p); + break; + } + } + } + + va_end (args); +} + +static int isdigit(int c) { + if (c >= '0' && c <= '9') return 1; + return 0; +} + +/* Parse a positive decimal integer at S. + FIXME: Was used in earlier version, but not currently used. + Keep for now. */ + +static char * +parse_number (s, p) + char *s; + long *p; +{ + long x = 0; + + while (isdigit (*s)) + { + x = (x * 10) + (*s - '0'); + ++s; + } + + *p = x; + return s; +} + +/* Fetch the number at S of SIZE bytes. */ + +static long +get_number (s, size, unsigned_p) + char *s; + long size; + int unsigned_p; +{ + long x; + unsigned char *p = (unsigned char *) s; + + switch (size) + { + case 1 : + x = *p; + if (!unsigned_p) + x = (x ^ 0x80) - 0x80; + return x; + case 2 : + if (big_endian_p) + x = (p[0] << 8) | p[1]; + else + x = (p[1] << 8) | p[0]; + if (!unsigned_p) + x = (x ^ 0x8000) - 0x8000; + return x; + case 4 : + if (big_endian_p) + x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3]; + else + x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0]; + if (!unsigned_p) + x = (x ^ 0x80000000L) - 0x80000000L; + return x; +#if 0 /* FIXME: Is there a standard mechanism for knowing if + long longs exist? */ + case 8 : +#endif + default : + return 0; + } +} + +/* Print X in base BASE. */ + +static void +print_number (base, unsigned_p, n) + int base; + int unsigned_p; + long n; +{ + static char chars[16] = "0123456789abcdef"; + char *p, buf[32]; + unsigned long x; + + if (!unsigned_p && n < 0) + { + write_char ('-'); + x = -n; + } + else + x = n; + + p = buf + sizeof (buf); + *--p = '\0'; + do + { + *--p = chars[x % base]; + x /= base; + } + while (x != 0); + + write_string (p); +} + +/* Write C to the console. + We go through the file descriptor directly because we can't assume + stdio is working. */ + +static void +write_char (char c) +{ + __putc(c); +} + +/* Write S to the console. + We go through the file descriptor directly because we can't assume + stdio is working. */ + +static void +write_string (char *s) +{ + __puts(s); +} + + +void __putc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + diff --git a/fps2bios/kernel/iopload/iopelf.c b/fps2bios/kernel/iopload/iopelf.c new file mode 100644 index 0000000000..c277b2afad --- /dev/null +++ b/fps2bios/kernel/iopload/iopelf.c @@ -0,0 +1,428 @@ +#include "romdir.h" +#include "iopelf.h" + +typedef struct { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +} Elf32_Sym; + +char *sections_names; + +ELF_HEADER *elfHeader; +ELF_PHR *elfProgH; +ELF_SHR *elfSectH; +u8 *elfdata; +int elfsize; +u32 elfbase; +static int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("iopelf: " fmt, ## args) + +static void __memcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + + +int loadHeaders() { + elfHeader = (ELF_HEADER*)elfdata; + + if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { + return -1; + } + +#ifdef ELF_LOG + ELF_LOG( "type: " ); +#endif + switch( elfHeader->e_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", elfHeader->e_type ); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG( "no file type" ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG( "relocatable" ); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG( "executable" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); +#endif + switch ( elfHeader->e_machine ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown" ); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG( "mips_rs3000" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("version: %d\n",elfHeader->e_version); + ELF_LOG("entry: %08x\n",elfHeader->e_entry); + ELF_LOG("flags: %08x\n",elfHeader->e_flags); + ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); + ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); + ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); + ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); + ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); + ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); + ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); + ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); + + ELF_LOG("\n"); +#endif + + return 0; +} + + +int loadProgramHeaders() { + int i; + + if (elfHeader->e_phnum == 0) { + return 0; + } + + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { + return -1; + } + + elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; + + for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); +#endif + switch ( elfProgH[ i ].p_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("load"); +#endif +/* if ( elfHeader->e_shnum == 0 ) {*/ + if (elfProgH[ i ].p_offset < elfsize) { + int size; + + if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { + size = elfsize - elfProgH[ i ].p_offset; + } else { + size = elfProgH[ i ].p_filesz; + } + _dprintf("loading program at %x, size=%x\n", elfProgH[ i ].p_paddr + elfbase, size); + __memcpy((void*)(elfProgH[ i ].p_paddr + elfbase), + &elfdata[elfProgH[ i ].p_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG("\t*LOADED*"); +#endif +// } + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); + ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); + ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); + ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); + ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); + ELF_LOG("palign: %08x\n",elfProgH[i].p_align); + ELF_LOG("\n"); +#endif + } + + return 0; +} + +void _relocateElfSection(int i) { + ELF_REL *rel; + int size = elfSectH[i].sh_size / 4; + int r = 0; + u32 *ptr, *tmp; + ELF_SHR *rsec = &elfSectH[elfSectH[i].sh_info]; + u8 *mem = (u8*)(elfSectH[i].sh_addr + elfbase); + u32 imm; + int j; + + ptr = (u32*)(elfdata+elfSectH[i].sh_offset); + +// _dprintf("relocating section %s\n", §ions_names[rsec->sh_name]); +// __printf("sh_addr %x\n", elfSectH[i].sh_addr); + + while (size > 0) { + rel = (ELF_REL*)&ptr[r]; +// __printf("rel size=%x: offset=%x, info=%x\n", size, rel->r_offset, rel->r_info); + + tmp = (u32*)&mem[rel->r_offset]; + switch ((u8)rel->r_info) { + case 2: // R_MIPS_32 + *tmp+= elfbase; break; + + case 4: // R_MIPS_26 + *tmp = (*tmp & 0xfc000000) | + (((*tmp & 0x03ffffff) + (elfbase >> 2)) & 0x03ffffff); + break; + + case 5: // R_MIPS_HI16 + imm = (((*tmp & 0xffff) + (elfbase >> 16)) & 0xffff); + for (j=(r+2)/2; jr_info == 6) + break; +// if ((rel->r_info >> 8) == (((ELF_REL*)&ptr[j*2])->r_info >> 8)) +// break; + } + +/* if (j != elfSectH[i].sh_size / 4)*/ { + u32 *p; + + rel = (ELF_REL*)&ptr[j*2]; +// __printf("HI16: found match: %x\n", rel->r_offset); + p = (u32*)&mem[rel->r_offset]; +// __printf("%x + %x = %x\n", *p, elfbase, (*p & 0xffff) + (elfbase & 0xffff)); + if (((*p & 0xffff) + (elfbase & 0xffff)) & 0x8000) { +// __printf("found\n"); + imm++; + } + } + *tmp = (*tmp & 0xffff0000) | imm; + break; + + case 6: // R_MIPS_LO16 + *tmp = (*tmp & 0xffff0000) | + (((*tmp & 0xffff) + (elfbase & 0xffff)) & 0xffff); + break; + + default: + __printf("UNKNOWN R_MIPS REL!!\n"); + break; + } + + size-= 2; r+= 2; + } +} + +int loadSectionHeaders() { + int i; + int i_st = -1; + int i_dt = -1; + + if (elfHeader->e_shnum == 0) { + return -1; + } + + elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; + + if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { + sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; + } + + for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); +#endif +/* if ( elfSectH[i].sh_flags & 0x2 ) { + if (elfSectH[i].sh_offset < elfsize) { + int size; + + if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { + size = elfsize - elfSectH[i].sh_offset; + } else { + size = elfSectH[i].sh_size; + } + memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], + &elfdata[elfSectH[i].sh_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG( "\t*LOADED*" ); +#endif + }*/ +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("type: "); +#endif + switch ( elfSectH[ i ].sh_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG("unknown %08x",elfSectH[i].sh_type); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG("null"); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("progbits"); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG("symtab"); +#endif + break; + + case 0x3: +#ifdef ELF_LOG + ELF_LOG("strtab"); +#endif + break; + + case 0x4: +#ifdef ELF_LOG + ELF_LOG("rela"); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG("no bits"); +#endif + break; + + case 0x9: +#ifdef ELF_LOG + ELF_LOG("rel"); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); + ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); + ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); + ELF_LOG("size: %08x\n", elfSectH[i].sh_size); + ELF_LOG("link: %08x\n", elfSectH[i].sh_link); + ELF_LOG("info: %08x\n", elfSectH[i].sh_info); + ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); + ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); +#endif + // dump symbol table + + if (elfSectH[i].sh_type == 0x02) { + i_st = i; i_dt = elfSectH[i].sh_link; + } + } + + + // now that we have all the stuff loaded, relocate it + for (i = 0 ; i < elfHeader->e_shnum ; i++) { + if (elfSectH[i].sh_type == 0x09) { // relocations + _relocateElfSection(i); + } + } + + return 0; +} + +void* loadElfFile(ROMFILE_INFO* ri, u32 offset) +{ + imageInfo* ii; + ELF_PHR* ph; + ELF_IOPMOD* im; + + __printf("loadElfFile: base=%x, size=%x\n", ri->fileData, ri->entry->fileSize); + elfdata = (u8*)(ri->fileData); + elfsize = ri->entry->fileSize; + elfbase = offset+0x30; + + loadHeaders(); + + // fill the image info header + ph= (ELF_PHR*)((char*)elfHeader +elfHeader->e_phoff); + im= (ELF_IOPMOD*)((char*)elfHeader + ph[0].p_offset); + ii = (imageInfo*)offset; + + if( *(u16*)(elfHeader->e_ident+4) != 0x101 ) + return NULL; + if (elfHeader->e_machine != EM_MIPS) + return NULL; + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) + return NULL; + if (elfHeader->e_phnum != 2) + return NULL; + if (ph[0].p_type != PT_SCE_IOPMOD) + return NULL; + if (elfHeader->e_type != ET_SCE_IOPRELEXEC){ + if (elfHeader->e_type != elfHeader->e_phnum )//ET_EXEC) + return NULL; + //result->type=3; + } + //else result->type=4; + + ii->next =0; + ii->name =NULL; + ii->version =0; + ii->flags =0; + ii->modid =0; + if ((int)im->moduleinfo != -1) { + moduleInfo* minfo = (moduleInfo*)(im->moduleinfo+ph[1].p_vaddr); // probably wrong + ii->name = minfo->name; + ii->version = minfo->version; + } + else { + ii->name = NULL; + ii->version = 0; + } + ii->entry = im->entry; + ii->gp_value = im->gp_value; + ii->p1_vaddr = ph[1].p_vaddr; + ii->text_size = im->text_size; + ii->data_size = im->data_size; + ii->bss_size = im->bss_size; + + loadProgramHeaders(); + loadSectionHeaders(); + + _dprintf("loadElfFile: e_entry=%x, hdr=%x\n", elfHeader->e_entry, elfHeader); + return (void*)(elfbase+elfHeader->e_entry); +} + diff --git a/fps2bios/kernel/iopload/libkernel/iop_cdvdman.s b/fps2bios/kernel/iopload/libkernel/iop_cdvdman.s new file mode 100644 index 0000000000..42489ba358 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_cdvdman.s @@ -0,0 +1,146 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Nick Van Veen + ------------------------------------------------------------------------ + iop_cdvdman.s CDVD Manager Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### CDVDMAN STUB ####### */ +/* # Added by Sjeep, 24th June 2002 # */ + +.local cdvdman_stub +cdvdman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "cdvdman\0" + .align 2 + + .globl CdInit # 004 +CdInit: + j $31 + li $0, 4 + + .globl CdStandby # 005 +CdStandby: + j $31 + li $0, 5 + + .globl CdRead # 006 +CdRead: + j $31 + li $0, 6 + + .globl CdSeek # 007 +CdSeek: + j $31 + li $0, 7 + + .globl CdGetError # 008 +CdGetError: + j $31 + li $0, 8 + + .globl CdGetToc # 009 +CdGetToc: + j $31 + li $0, 9 + + .globl CdSearchFile # 010 +CdSearchFile: + j $31 + li $0, 10 + + .globl CdSync # 011 +CdSync: + j $31 + li $0, 11 + + .globl CdGetDiskType # 012 +CdGetDiskType: + j $31 + li $0, 12 + + .globl CdDiskReady # 013 +CdDiskReady: + j $31 + li $0, 13 + + .globl CdTrayReq # 014 +CdTrayReq: + j $31 + li $0, 14 + + .globl CdStop # 015 +CdStop: + j $31 + li $0, 15 + + .globl CdPosToInt # 016 +CdPosToInt: + j $31 + li $0, 16 + + .globl CdIntToPos # 017 +CdIntToPos: + j $31 + li $0, 17 + + .globl CdCheckCmd # 021 +CdCheckCmd: + j $31 + li $0, 21 + + .globl CdReadILinkID # 022 +CdReadILinkID: + j $31 + li $0, 22 + + .globl CdReadClock # 024 +CdReadClock: + j $31 + li $0, 24 + + .globl CdStatus # 028 +CdStatus: + j $31 + li $0, 28 + + .globl CdCallback # 037 +CdCallback: + j $31 + li $0, 37 + + .globl CdPause # 038 +CdPause: + j #31 + li $0, 38 + + .globl CdBreak # 039 +CdBreak: + j $31 + li $0, 39 + + .globl CdGetReadPos # 044 +CdGetReadPos: + j $31 + li $0, 44 + + .globl CdReadChain # 066 +CdReadChain: + j $31 + li $0, 66 + + .globl CdMmode +CdMmode: + j $31 + li $0, 75 + + .word 0 + .word 0 diff --git a/fps2bios/kernel/iopload/libkernel/iop_dmacman.s b/fps2bios/kernel/iopload/libkernel/iop_dmacman.s new file mode 100644 index 0000000000..2d702ec38e --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_dmacman.s @@ -0,0 +1,52 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_dmacman.s DMAC library function imports. + taken from dmacman in bios. +*/ + + .text + .set noreorder + + +/* ############################### DMACMAN STUB ######## */ + .local dmacman_stub +dmacman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "dmacman\0" + .align 2 + + .globl dmacSetDMA # 028 +dmacSetDMA: + j $31 + li $0, 28 + + .globl dmacStartTransfer # 032 +dmacStartTransfer: + j $31 + li $0, 32 + + .globl dmacSetVal # 033 +dmacSetVal: + j $31 + li $0, 33 + + .globl dmacEnableDMAch # 034 +dmacEnableDMAch: + j $31 + li $0, 34 + + .globl dmacDisableDMAch # 035 +dmacDisableDMAch: + j $31 + li $0, 35 + + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_excepman.s b/fps2bios/kernel/iopload/libkernel/iop_excepman.s new file mode 100644 index 0000000000..557692fc3b --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_excepman.s @@ -0,0 +1,58 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_excepman.s Exception Manager Functions. +*/ + + .text + .set noreorder + + +/* ############################### EXCEPMAN STUB ####### */ +/* # Added by linuzappz, 10th May 2004 # */ + + .local excepman_stub +excepman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "excepman" + .align 2 + + .globl GetExHandlersTable # 003 +GetExHandlersTable: + j $31 + li $0, 3 + + .globl RegisterExceptionHandler # 004 +RegisterExceptionHandler: + j $31 + li $0, 4 + + .globl RegisterPriorityExceptionHandler # 005 +RegisterPriorityExceptionHandler: + j $31 + li $0, 5 + + .globl RegisterDefaultExceptionHandler # 006 +RegisterDefaultExceptionHandler: + j $31 + li $0, 6 + + .globl ReleaseExceptionHandler # 007 +ReleaseExceptionHandler: + j $31 + li $0, 7 + + .globl ReleaseDefaultExceptionHandler # 008 +ReleaseDefaultExceptionHandler: + j $31 + li $0, 8 + + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_heaplib.s b/fps2bios/kernel/iopload/libkernel/iop_heaplib.s new file mode 100644 index 0000000000..83b233e705 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_heaplib.s @@ -0,0 +1,51 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_heaplib.s Heap library function imports. + taken from heaplib in bios. +*/ + + .text + .set noreorder + + +/* ############################### SYSMEM STUB ######## */ + .local sysmem_stub +sysmem_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "heaplib\0" + .align 2 + + .globl CreateHeap # 004 +CreateHeap: + j $31 + li $0, 4 + + .globl DestroyHeap # 005 +DestroyHeap: + j $31 + li $0, 5 + + .globl HeapMalloc # 006 +HeapMalloc: + j $31 + li $0, 6 + + .globl HeapFree # 007 +HeapFree: + j $31 + li $0, 7 + + .globl HeapSize # 008 +HeapSize: + j $31 + li $0, 8 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_intrman.s b/fps2bios/kernel/iopload/libkernel/iop_intrman.s new file mode 100644 index 0000000000..60efd2c2c3 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_intrman.s @@ -0,0 +1,73 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_intrman.s Interrupt Manager Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### INTRMAN STUB ####### */ +/* # Added by Oobles, 5th March 2002 # */ + + .local intrman_stub +intrman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000102 + .ascii "intrman\0" + .align 2 + + .globl RegisterIntrHandler # 004 +RegisterIntrHandler: + j $31 + li $0, 4 + + .globl ReleaseIntrHandler # 005 +ReleaseIntrHandler: + j $31 + li $0, 5 + + .globl EnableIntr # 006 +EnableIntr: + j $31 + li $0, 6 + + .globl DisableIntr # 007 +DisableIntr: + j $31 + li $0, 7 + + .globl CpuDisableIntr # 008 +CpuDisableIntr: + j $31 + li $0, 8 + + .globl CpuEnableIntr # 009 +CpuEnableIntr: + j $31 + li $0, 9 + + .globl CpuSuspendIntr # 0x11 +CpuSuspendIntr: + j $31 + li $0, 0x11 + + .globl CpuResumeIntr # 0x12 +CpuResumeIntr: + j $31 + li $0, 0x12 + + .globl QueryIntrContext # 0x17 +QueryIntrContext: + j $31 + li $0, 0x17 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_ioman.s b/fps2bios/kernel/iopload/libkernel/iop_ioman.s new file mode 100644 index 0000000000..c1414f4816 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_ioman.s @@ -0,0 +1,116 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Gustavo Scott(gustavo@scotti.com) + ------------------------------------------------------------------------ + iop_iooman.s + IOP Basic libraries. + took from .irx files with symbol table / string table +*/ + + .text + .set noreorder + + +/* ############################### IOMAN STUB ######## */ + .local ioman_stub +ioman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000102 + .ascii "ioman\0\0\0" + .align 2 + + .globl open # 004 +open: + j $31 + li $0, 4 + + .globl close # 005 +close: + j $31 + li $0, 5 + + .globl read # 006 +read: + j $31 + li $0, 6 + + .globl write # 007 +write: + j $31 + li $0, 7 + + .globl lseek # 008 +lseek: + j $31 + li $0, 8 + + .globl ioctl +ioctl: + j $31 + li $0, 9 + + .globl remove +remove: + j $31 + li $0, 10 + + .globl mkdir +mkdir: + j $31 + li $0, 11 + + .globl rmdir +rmdir: + j $31 + li $0, 12 + + .globl dopen +dopen: + j $31 + li $0, 13 + + .globl dclose +dclose: + j $31 + li $0, 14 + + .globl dread +dread: + j $31 + li $0, 15 + + .globl getstat +getstat: + j $31 + li $0, 16 + + .globl chstat +chstat: + j $31 + li $0, 17 + + .globl format +format: + j $31 + li $0, 18 + + .globl FILEIO_add # 020 + .globl AddDrv +FILEIO_add: +AddDrv: + j $31 + li $0, 20 + + .globl FILEIO_del # 021 + .globl DelDrv +FILEIO_del: +DelDrv: + j $31 + li $0, 21 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_libsd.s b/fps2bios/kernel/iopload/libkernel/iop_libsd.s new file mode 100644 index 0000000000..0a8657e550 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_libsd.s @@ -0,0 +1,160 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_libsd.s Sound Library + taken from .irx files with symbol table + Missing calls by Julian Tyler (lovely@crm114.net) +*/ + + .text + .set noreorder + + +/* ############################### LIBSD STUB ######### */ +/* # Added by Oobles, 7th March 2002 # */ + + .local libsd_stub +libsd_stub: + .word 0x41e00000 + .word 0 + .word 0x00000104 + .ascii "libsd\0\0" + .align 2 + +/* Added by Julian Tyler (lovely) */ + .globl SdQuit # 0x02 +SdQuit: + j $31 + li $0, 0x02 + + .globl SdInit # 0x04 +SdInit: + j $31 + li $0, 0x04 + + .globl SdSetParam # 0x05 +SdSetParam: + j $31 + li $0, 0x05 + + .globl SdGetParam # 0x06 +SdGetParam: + j $31 + li $0, 0x06 + + .globl SdSetSwitch # 0x07 +SdSetSwitch: + j $31 + li $0, 0x07 + +/* Added by Julian Tyler (lovely) */ + .globl SdGetSwitch # 0x08 +SdGetSwitch: + j $31 + li $0, 0x08 + + .globl SdSetAddr # 0x09 +SdSetAddr: + j $31 + li $0, 0x09 + + .globl SdGetAddr # 0x0a +SdGetAddr: + j $31 + li $0, 0x0a + + .globl SdSetCoreAttr # 0x0b +SdSetCoreAttr: + j $31 + li $0, 0x0b + +/* Added by Julian Tyler (lovely) 013-016 */ + .globl SdGetCoreAttr # 012 +SdGetCoreAttr: + j $31 + li $0, 0x0c + + .globl SdNote2Pitch # 013 +SdNote2Pitch: + j $31 + li $0, 0x0d + + .globl SdPitch2Note # 014 +SdPitch2Note: + j $31 + li $0, 0x0e + + .globl SdProcBatch # 015 +SdProcBatch: + j $31 + li $0, 0x0f + + .globl SdProcBatchEx # 016 +SdProcBatchEx: + j $31 + li $0, 0x10 + + .globl SdVoiceTrans # 0x11 +SdVoiceTrans: + j $31 + li $0, 0x11 + +/* Added by Julian Tyler (lovely) 018-022 */ + + .globl SdBlockTrans # 018 +SdBlockTrans: + j $31 + li $0, 0x12 + + .globl SdVoiceTransStatus # 019 +SdVoiceTransStatus: + j $31 + li $0, 0x13 + + .globl SdBlockTransStatus # 020 +SdBlockTransStatus: + j $31 + li $0, 0x14 + + .globl SdSetTransCallback # 021 +SdSetTransCallback: + j $31 + li $0, 0x15 + + .globl SdSetIRQCallback # 022 +SdSetIRQCallback: + j $31 + li $0, 0x16 + + .globl SdSetEffectAttr # 0x17 +SdSetEffectAttr: + j $31 + li $0, 0x17 + +/* Added by Julian Tyler (lovely) 024-025 */ + + .globl SdGetEffectAttr # 024 +SdGetEffectAttr: + j $31 + li $0, 0x18 + + .globl SdClearEffectWorkArea # 025 +SdClearEffectWorkArea: + j $31 + li $0, 0x19 + + .globl SdSetTransIntrHandler # 0x1a +SdSetTransIntrHandler: + j $31 + li $0, 0x1a + + .globl SdSetSpu2IntrHandler # 0x1b +SdSetSpu2IntrHandler: + j $31 + li $0, 0x1b + + .word 0 + .word 0 + diff --git a/fps2bios/kernel/iopload/libkernel/iop_loadcore.s b/fps2bios/kernel/iopload/libkernel/iop_loadcore.s new file mode 100644 index 0000000000..dc6e9e6301 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_loadcore.s @@ -0,0 +1,65 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_loadcore.s Core IOP Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + + +/* ############################### LOADCORE STUB ###### */ +/* # Added by Oobles, 5th March 2002 # */ + + .local loadcore_stub +loadcore_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "loadcore" + .align 2 + + .globl GetLibraryEntryTable # 0x03 +GetLibraryEntryTable: + j $31 + li $0, 3 + + .globl FlushIcache # 0x05 +FlushIcache: + j $31 + li $0, 4 + + .globl FlushDcache # 0x05 +FlushDcache: + j $31 + li $0, 5 + + .global RegisterLibraryEntries # 0x06 +RegisterLibraryEntries: + j $31 + li $0, 6 + + .global ReleaseLibraryEntries +ReleaseLibraryEntries: + j $31 + li $0, 7 + + .global QueryLibraryEntryTable +QueryLibraryEntryTable: + j $31 + li $0, 11 + + .globl QueryBootMode # 0x0c +QueryBootMode: + j $31 + li $0, 0x0c + + .word 0 + .word 0 + + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_modload.s b/fps2bios/kernel/iopload/libkernel/iop_modload.s new file mode 100644 index 0000000000..1b09af6ef6 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_modload.s @@ -0,0 +1,61 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Nick Van Veen (nickvv@xtra.co.nz) + ------------------------------------------------------------------------ + iop_modload.s Module Manager Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### MODLOAD STUB ####### */ +/* # Added by Sjeep, 28th March 2002 # */ + + .local modload_stub +modload_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "modload\0" + .align 2 + + .globl ReBootStart # 004 +ReBootStart: + jr $31 + li $0, 0x04 + + .globl LoadModuleAddress # 005 +LoadModuleAddress: + jr $31 + li $0, 0x05 + + .globl LoadModule # 006 +LoadModule: + jr $31 + li $0, 0x06 + + .globl LoadStartModule # 007 +LoadStartModule: + jr $31 + li $0, 0x07 + + .globl StartModule # 008 +StartModule: + jr $31 + li $0, 0x08 + + .globl LoadModuleBufferAddress # 009 +LoadModuleBufferAddress: + jr $31 + li $0, 0x09 + + .globl LoadModuleBuffer # 010 +LoadModuleBuffer: + jr $31 + li $0, 0x0A + + .word 0 + .word 0 diff --git a/fps2bios/kernel/iopload/libkernel/iop_sifcmd.s b/fps2bios/kernel/iopload/libkernel/iop_sifcmd.s new file mode 100644 index 0000000000..c28a63acc2 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_sifcmd.s @@ -0,0 +1,144 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_sifcmd.s Serial Interface Command Functions. + taken from .irx files with symbol table +*/ + + .text + .set noreorder + + +/* ############################### SIFCMD STUB ######## */ +/* # Added by Oobles, 5th March 2002 # */ + + .local sifcmd_stub +sifcmd_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "sifcmd\0\0" + .align 2 + + .globl SifInitCmd # 0x04 +SifInitCmd: + j $31 + li $0, 0x04 + + .globl SifExitCmd # 0x05 +SifExitCmd: + j $31 + li $0, 0x05 + + .globl SifGetSreg # 0x06 +SifGetSreg: + j $31 + li $0, 0x06 + + .globl SifSetSreg # 0x07 +SifSetSreg: + j $31 + li $0, 0x07 + + .globl SifSetCmdBuffer # 0x08 +SifSetCmdBuffer: + j $31 + li $0, 0x08 + + + .globl SifAddCmdHandler # 0x0a +SifAddCmdHandler: + j $31 + li $0, 0x0a + + .globl SifRemoveCmdHandler # 0x0b +SifRemoveCmdHandler: + j $31 + li $0, 0x0b + + .globl SifSendCmd # 0x0c +SifSendCmd: + j $31 + li $0, 0x0c + + .globl iSifSendCmd # 0x0d +iSifSendCmd: + j $31 + li $0, 0x0d + + .globl SifInitRpc # 0x0E +SifInitRpc: + j $31 + li $0, 0x0E + + .globl SifBindRpc # 0x0F +SifBindRpc: + j $31 + li $0, 0x0F + + .globl SifCallRpc # 0x10 +SifCallRpc: + j $31 + li $0, 0x10 + + .globl SifRegisterRpc # 0x11 +SifRegisterRpc: + j $31 + li $0, 0x11 + + .globl SifCheckStatRpc # 0x12 +SifCheckStatRpc: + j $31 + li $0, 0x12 + + .globl SifSetRpcQueue # 0x13 +SifSetRpcQueue: + j $31 + li $0, 0x13 + + .globl SifGetNextRequest # 0x14 +SifGetNextRequest: + j $31 + li $0, 0x14 + + .globl SifExecRequest # 0x15 +SifExecRequest: + j $31 + li $0, 0x15 + + .globl SifRpcLoop # 0x16 +SifRpcLoop: + j $31 + li $0, 0x16 + + .globl SifRpcGetOtherData # 0x17 +SifRpcGetOtherData: + j $31 + li $0, 0x17 + + .globl SifRemoveRpc # 0x18 +SifRemoveRpc: + j $31 + li $0, 0x18 + + .globl SifRemoveRpcQueue # 0x19 +SifRemoveRpcQueue: + j $31 + li $0, 0x19 + + .globl SifSendCmdIntr # 0x20 +SifSendCmdIntr: + j $31 + li $0, 0x20 + + .globl iSifSendCmdIntr # 0x21 +iSifSendCmdIntr: + j $31 + li $0, 0x21 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_sifman.s b/fps2bios/kernel/iopload/libkernel/iop_sifman.s new file mode 100644 index 0000000000..c38bfa0b08 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_sifman.s @@ -0,0 +1,178 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2001, Gustavo Scotti (gustavo@scotti.com) + ------------------------------------------------------------------------ + iop_sifman.s Serial Interface Manager Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### SIFMAN STUB ######## */ +/* # Added by Oobles, 7th March 2002 # */ + + .local sifman_stub +sifman_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "sifman\0\0" + .align 2 + + .globl SifDeinit # 0x03 +SifDeinit: + j $31 + li $0, 0x03 + + .globl SifSIF2Init # 0x04 +SifSIF2Init: + j $31 + li $0, 0x04 + + .globl SifInit # 0x05 +SifInit: + j $31 + li $0, 0x05 + + .globl SifSetDChain # 0x06 +SifSetDChain: + j $31 + li $0, 0x06 + + .globl SifSetDma # 0x07 +SifSetDma: + j $31 + li $0, 0x07 + + .globl SifDmaStat # 0x08 +SifDmaStat: + j $31 + li $0, 0x08 + + .globl SifSend # 0x09 +SifSend: + j $31 + li $0, 0x09 + + .globl SifSendSync # 0x0A +SifSendSync: + j $31 + li $0, 0x0A + + .globl SifIsSending # 0x0B +SifIsSending: + j $31 + li $0, 0x0B + + .globl SifSetSIF0DMA # 0x0C +SifSetSIF0DMA: + j $31 + li $0, 0x0C + + .globl SifSendSync0 # 0x0D +SifSendSync0: + j $31 + li $0, 0x0D + + .globl SifIsSending0 # 0x0E +SifIsSending0: + j $31 + li $0, 0x0E + + .globl SifSetSIF1DMA # 0x0F +SifSetSIF1DMA: + j $31 + li $0, 0x0F + + .globl SifSendSync1 # 0x10 +SifSendSync1: + j $31 + li $0, 0x10 + + .globl SifIsSending1 # 0x11 +SifIsSending1: + j $31 + li $0, 0x11 + + .globl SifSetSIF2DMA # 0x12 +SifSetSIF2DMA: + j $31 + li $0, 0x12 + + .globl SifSendSync2 # 0x13 +SifSendSync2: + j $31 + li $0, 0x13 + + .globl SifIsSending2 # 0x14 +SifIsSending2: + j $31 + li $0, 0x14 + + .globl SifGetEEIOPflags # 0x15 +SifGetEEIOPflags: + j $31 + li $0, 0x15 + + .globl SifSetEEIOPflags # 0x16 +SifSetEEIOPflags: + j $31 + li $0, 0x16 + + .globl SifGetIOPEEflags # 0x17 +SifGetIOPEEflags: + j $31 + li $0, 0x17 + + .globl SifSetIOPEEflags # 0x18 +SifSetIOPEEflags: + j $31 + li $0, 0x18 + + .globl SifGetEErcvaddr # 0x19 +SifGetEErcvaddr: + j $31 + li $0, 0x19 + + .globl SifGetIOPrcvaddr # 0x1A +SifGetIOPrcvaddr: + j $31 + li $0, 0x1A + + .globl SifSetIOPrcvaddr # 0x1B +SifSetIOPrcvaddr: + j $31 + li $0, 0x1B + + .globl SifSet1450_2 # 0x1C +SifSet1450_2: + j $31 + li $0, 0x1C + + .globl SifCheckInit # 0x1D +SifCheckInit: + j $31 + li $0, 0x1D + + .globl SifSet0CB # 0x1E +SifSet0CB: + j $31 + li $0, 0x1E + + .globl SifReset0CB # 0x1F +SifReset0CB: + j $31 + li $0, 0x1F + + .globl SifSetDmaIntr # 0x20 +SifSetDmaIntr: + j $31 + li $0, 0x20 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_stdio.s b/fps2bios/kernel/iopload/libkernel/iop_stdio.s new file mode 100644 index 0000000000..649e464724 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_stdio.s @@ -0,0 +1,32 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_stdio.s Stdio Import Library + taken from .irx files with symbol table +*/ + + .text + .set noreorder + + +/* ############################### STDIO STUB ######## */ + .local stdio_stub +stdio_stub: + .word 0x41e00000 + .word 0 + .word 0x00000102 + .ascii "stdio\0\0\0" + .align 2 + + .globl printf # 004 + +printf: + j $31 + li $0, 4 + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_sysclib.s b/fps2bios/kernel/iopload/libkernel/iop_sysclib.s new file mode 100644 index 0000000000..b2129c3809 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_sysclib.s @@ -0,0 +1,219 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_sysclib.a C Library Functions. + taken from .irx files with symbol table. + Additions from Herben's IRX Tool imports.txt +*/ + + .text + .set noreorder + + +/* ############################### SYSCLIB STUB ####### */ +/* # Added by Oobles, 5th March 2002 # */ + + .local sysclib_stub +sysclib_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "sysclib\0" + .align 2 + + .globl setjmp # 0x04 +setjmp: + j $31 + li $0, 0x04 + + .globl longjmp # 0x05 +longjmp: + j $31 + li $0, 0x05 + + .globl toupper # 0x06 +toupper: + j $31 + li $0, 0x06 + + .globl tolower # 0x07 +tolower: + j $31 + li $0, 0x07 + + .globl look_ctype_table # 0x08 +look_ctype_table: + j $31 + li $0, 0x08 + + .globl get_ctype_table # 0x09 +get_ctype_table: + j $31 + li $0, 0x09 + + .globl memchr # 0x0A +memchr: + j $31 + li $0, 0x0A + + .globl memcmp # 0x0B +memcmp: + j $31 + li $0, 0x0B + + .globl memcpy # 0x0C +memcpy: + j $31 + li $0, 0x0C + + .globl memmove # 0x0D +memmove: + j $31 + li $0, 0x0D + + .globl memset # 0x0E +memset: + j $31 + li $0, 0x0E + + .globl bcmp # 0x0F +bcmp: + j $31 + li $0, 0x0F + + .globl bcopy # 0x10 +bcopy: + j $31 + li $0, 0x10 + + .globl bzero # 0x11 +bzero: + j $31 + li $0, 0x11 + + .globl prnt # 0x12 +prnt: + j $31 + li $0, 0x12 + + .globl sprintf # 0x013 +sprintf: + j $31 + li $0, 0x13 + + .globl strcat # 0x14 +strcat: + j $31 + li $0, 0x14 + + .globl strchr # 0x15 +strchr: + j $31 + li $0, 0x15 + + .globl strcmp # 0x16 +strcmp: + j $31 + li $0, 0x16 + + .globl strcpy # 0x17 +strcpy: + j $31 + li $0, 0x17 + + .globl strcspn # 0x18 +strcspn: + j $31 + li $0, 0x18 + + .globl index # 0x19 +index: + j $31 + li $0, 0x19 + + .globl rindex # 0x1A +rindex: + j $31 + li $0, 0x1A + + .globl strlen # 0x1b +strlen: + j $31 + li $0, 0x1b + + .globl strncat # 0x1c +strncat: + j $31 + li $0, 0x1C + + .globl strncmp # 0x1d +strncmp: + j $31 + li $0, 0x1d + + .globl strncpy # 0x1E +strncpy: + j $31 + li $0, 0x1E + + .globl strpbrk # 0x1F +strpbrk: + j $31 + li $0, 0x1F + + .globl strrchr # 0x20 +strrchr: + j $31 + li $0, 0x20 + + .globl strspn # 0x21 +strspn: + j $31 + li $0, 0x21 + + .globl strstr # 0x22 +strstr: + j $31 + li $0, 0x22 + + .globl strtok # 0x23 +strtok: + j $31 + li $0, 0x23 + + .globl strtol # 0x24 +strtol: + j $31 + li $0, 0x24 + + .globl atob # 0x25 +atob: + j $31 + li $0, 0x25 + + .globl strtoul # 0x26 +strtoul: + j $31 + li $0, 0x26 + + .globl wmemcopy # 0x28 +wmemcopy: + j $31 + li $0, 0x28 + + .globl wmemset # 0x29 +wmemset: + j $31 + li $0, 0x29 + + .globl vsprintf # 0x2A +vsprintf: + j $31 + li $0, 0x2A + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_sysmem.s b/fps2bios/kernel/iopload/libkernel/iop_sysmem.s new file mode 100644 index 0000000000..ea7b8ac09b --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_sysmem.s @@ -0,0 +1,71 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2001, Gustavo Scotti (gustavo@scotti.com) + ------------------------------------------------------------------------ + iop_sysmem.s Memory Function import list. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### SYSMEM STUB ######## */ + .local sysmem_stub +sysmem_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "sysmem\0\0" + .align 2 + + .globl AllocSysMemory # 004 +AllocSysMemory: + j $31 + li $0, 0x04 + + .globl FreeSysMemory # 005 +FreeSysMemory: + j $31 + li $0, 0x05 + + .globl QueryMemSize # 006 +QueryMemSize: + j $31 + li $0, 0x06 + + .globl QueryMaxFreeMemSize # 007 +QueryMaxFreeMemSize: + j $31 + li $0, 0x07 + + .globl QueryTotalFreeMemSize # 008 +QueryTotalFreeMemSize: + j $31 + li $0, 0x08 + + .globl QueryBlockTopAddress # 009 +QueryBlockTopAddress: + j $31 + li $0, 0x09 + + .globl QueryBlockSize # 00A +QueryBlockSize: + j $31 + li $0, 0x0A + + .globl Kprintf # 0x0E +Kprintf: + j $31 + li $0, 0x0E + + .globl SetKprintf # 0x0F +SetKprintf: + j $31 + li $0, 0x0F + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_thbase.s b/fps2bios/kernel/iopload/libkernel/iop_thbase.s new file mode 100644 index 0000000000..5491e3467b --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_thbase.s @@ -0,0 +1,167 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_thbase.s Base Kernel Functions. + taken from .irx files with symbol table +*/ + + .text + .set noreorder + + +/* ############################### THBASE STUB ######## */ +/* # Added by Oobles, 5th March 2002 # */ + + .local thbase_stub +thbase_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "thbase\0\0" + .align 2 + + .globl CreateThread # 004 +CreateThread: + j $31 + li $0, 4 + + .globl DeleteThread # 005 +DeleteThread: + j $31 + li $0, 5 + + .globl StartThread # 006 +StartThread: + j $31 + li $0, 6 + + .globl StartThreadArgs # 007 +StartThreadArgs: + j $31 + li $0, 0x07 + + .globl ExitThread # 008 +ExitThread: + j $31 + li $0, 0x08 + + .globl ExitDeleteThread # 009 +ExitDeleteThread: + j $31 + li $0, 0x09 + + .globl TerminateThread # 010 +TerminateThread: + j $31 + li $0, 0x0A + + .globl iTerminateThread # 011 +iTerminateThread: + j $31 + li $0, 0x0B + + .globl DisableDispatchThread # 012 +DisableDispatchThread: + j $31 + li $0, 0x0C + + .globl EnableDispatchThread # 013 +EnableDispatchThread: + j $31 + li $0, 0x0D + + + .globl ChangeThreadPriority # 014 +ChangeThreadPriority: + j $31 + li $0, 0x0E + + .globl iChangeThreadPriority # 015 +iChangeThreadPriority: + j $31 + li $0, 0x0F + + + .globl ReleaseWaitThread # 018 +ReleaseWaitThread: + j $31 + li $0, 18 + + .globl iReleaseWaitThread # 019 +iReleaseWaitThread: + j $31 + li $0, 19 + + .globl GetThreadId # 0x14 +GetThreadId: + j $31 + li $0, 0x14 + + .globl SleepThread # 0x18 +SleepThread: + j $31 + li $0, 0x18 + + .globl WakeupThread # 0x19 +WakeupThread: + j $31 + li $0, 0x19 + + .globl iWakeupThread # 0x1A +iWakeupThread: + j $31 + li $0, 0x1A + + .globl DelayThread # 0x21 +DelayThread: + j $31 + li $0, 0x21 + + .globl GetSystemTime # 0x22 +GetSystemTime: + j $31 + li $0, 0x22 + + + .globl SetAlarm # 0x23 +SetAlarm: + j $31 + li $0, 0x23 + + .globl iSetAlarm # 0x24 +iSetAlarm: + j $31 + li $0, 0x24 + + .globl CancelAlarm # 0x25 +CancelAlarm: + j $31 + li $0, 0x25 + + .globl iCancelAlarm # 0x26 +iCancelAlarm: + j $31 + li $0, 0x26 + + .globl USec2SysClock # 0x27 +USec2SysClock: + j $31 + li $0, 0x27 + + .globl SysClock2USec # 0x28 +SysClock2USec: + j $31 + li $0, 0x28 + + .globl GetSystemStatusFlag # 0x29 +GetSystemStatusFlag: + j $31 + li $0, 0x29 + + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_thevent.s b/fps2bios/kernel/iopload/libkernel/iop_thevent.s new file mode 100644 index 0000000000..010ae37f62 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_thevent.s @@ -0,0 +1,67 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Florin Sasu (florinsasu@yahoo.com) + ------------------------------------------------------------------------ + iop_thevent.s Event Function Imports. +*/ + + .text + .set noreorder + + + .local thevent_stub +thevent_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "thevent\0" + .align 2 + + .globl CreateEventFlag # 004 +CreateEventFlag: + j $31 + li $0, 0x04 + + .globl DeleteEventFlag +DeleteEventFlag: + j $31 + li $0, 0x05 + + .globl SetEventFlag # 006 +SetEventFlag: + j $31 + li $0, 0x06 + + .globl iSetEventFlag # 007 +iSetEventFlag: + j $31 + li $0, 0x07 + + .globl ClearEventFlag # 008 +ClearEventFlag: + j $31 + li $0, 0x08 + + .globl iClearEventFlag # 009 +iClearEventFlag: + j $31 + li $0, 0x09 + + .globl WaitEventFlag # 00A +WaitEventFlag: + j $31 + li $0, 0x0A + + .word 0 + .word 0 + + .globl ReferEventFlagStatus # 00D +ReferEventFlagStatus: + j $31 + li $0, 0x0D + + .globl iReferEventFlagStatus # 00E +iReferEventFlagStatus: + j $31 + li $0, 0x0E diff --git a/fps2bios/kernel/iopload/libkernel/iop_thsemap.s b/fps2bios/kernel/iopload/libkernel/iop_thsemap.s new file mode 100644 index 0000000000..206fe52824 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_thsemap.s @@ -0,0 +1,68 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, David Ryan (Oobles@hotmail.com) + ------------------------------------------------------------------------ + iop_thsemap.s Semaphore Function Imports. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ############################### THSEMAP STUB ####### */ +/* # Added by Oobles, 5th March 2002 # */ + + .local thsemap_stub +thsemap_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "thsemap\0" + .align 2 + + .globl CreateSema # 004 +CreateSema: + j $31 + li $0, 4 + + .globl DeleteSema # 005 +DeleteSema: + j $31 + li $0, 5 + + .globl SignalSema # 006 +SignalSema: + j $31 + li $0, 6 + + .globl iSignalSema # 007 +iSignalSema: + j $31 + li $0, 7 + + .globl WaitSema # 008 +WaitSema: + j $31 + li $0, 8 + + .globl PollSema # 009 +PollSema: + j $31 + li $0, 0x09 + + .globl ReferSemaStatus # 00B +ReferSemaStatus: + j $31 + li $0, 0x0B + + .globl iReferSemaStatus # 00C +iReferSemaStatus: + j $31 + li $0, 0x0C + + .word 0 + .word 0 + + diff --git a/fps2bios/kernel/iopload/libkernel/iop_usbd.s b/fps2bios/kernel/iopload/libkernel/iop_usbd.s new file mode 100644 index 0000000000..4b1def3cbb --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_usbd.s @@ -0,0 +1,113 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Pedro J. Cabrera (rc5stint@yahoo.com) + ------------------------------------------------------------------------ + iop_usbd.s USB Driver Import functions. + + Figured out from IRX files with symbol tables in Unreal Tournament + and JamPak demo discs. +*/ + + .text + .set noreorder + + .local usbd_stub +usbd_stub: # Module Import Information + .word 0x41e00000 # Import Tag + .word 0x00000000 # Minor Version? + .word 0x00000101 # Major Version? + .ascii "usbd\0\0\0\0" # Library ID + .align 2 + + /* initialize USBD.IRX + * Note: UsbInit is automatically called first whenever USBD.IRX is loaded. + * There should never be a need to reinitialize the driver. In fact, it may + * not even work. But I'm providing the function hook anyhow. + */ + .globl UsbInit +UsbInit: + j $31 + li $0, 0x00 + + /* + * These two functions are used to register and unregister device drivers for + * listening for USB bus events. The events are device probe, connect, and disconnect. + */ + + # register a USB device driver + .globl UsbRegisterDriver +UsbRegisterDriver: + j $31 + li $0, 0x04 + + # unregister a USB device driver + .globl UsbUnregisterDriver +UsbUnregisterDriver: + j $31 + li $0, 0x05 + + /* + * This function is used to get the static descriptors for the specific USB + * device. These descriptors identify the device uniquely and help determine + * what type of device we are dealing with, and what its capabilities and + * features are. + */ + .globl UsbGetDeviceStaticDescriptor +UsbGetDeviceStaticDescriptor: + j $31 + li $0, 0x06 + + /* + * These two functions are used to assign relevant data to a specific device. + * The type of data is entirely up to the caller. For example, a particular + * USB device driver may store configuration data for each specific device + * under its control. + */ + + # set the private data pointer for a device + .globl UsbSetDevicePrivateData +UsbSetDevicePrivateData: + j $31 + li $0, 0x07 + + # get the private data pointer for a device + .globl UsbGetDevicePrivateData +UsbGetDevicePrivateData: + j $31 + li $0, 0x08 + + /* + * This function returns an endpoint ID for the device ID and endpoint descriptor + * passed in. This endpoint ID is then used when transfering data to the device, + * and to close the endpoint. + */ + .globl UsbOpenEndpoint +UsbOpenEndpoint: + j $31 + li $0, 0x09 + + # close an endpoint + .globl UsbCloseEndpoint +UsbCloseEndpoint: + j $31 + li $0, 0x0A + + /* + * This function is used for all types of USB data transfers. Which type of + * transfer is determined by the parameters that are passed in. The types are: + * control, isochronous, interrupt, and bulk transfers. More details can be + * found in usbd.h. + */ + .globl UsbTransfer +UsbTransfer: + j $31 + li $0, 0x0B + + .globl UsbOpenBulkEndpoint +UsbOpenBulkEndpoint: + j $31 + li $0, 0x0C + + .word 0 + .word 0 diff --git a/fps2bios/kernel/iopload/libkernel/iop_vblank.s b/fps2bios/kernel/iopload/libkernel/iop_vblank.s new file mode 100644 index 0000000000..267c844e86 --- /dev/null +++ b/fps2bios/kernel/iopload/libkernel/iop_vblank.s @@ -0,0 +1,53 @@ +/* + _____ ___ ____ + ____| | ____| PSX2 OpenSource Project + | ___| |____ (C)2002, Nick Van Veen (nickvv@xtra.co.nz) + ------------------------------------------------------------------------ + iop_vblank.s Vblank Manager Functions. + taken from .irx files with symbol table. +*/ + + .text + .set noreorder + + +/* ################################ VBLANK STUB ####### */ +/* # Added by Sjeep, 28th March 2002 # */ + + .local vblank_stub +vblank_stub: + .word 0x41e00000 + .word 0 + .word 0x00000101 + .ascii "vblank\0\0" + .align 2 + + .globl WaitVblankStart +WaitVblankStart: + jr $31 + li $0,4 + + .globl WaitVblankEnd +WaitVblankEnd: + jr $31 + li $0,5 + + .globl WaitVblank +WaitVblank: + jr $31 + li $0,6 + + .globl WaitNonVblank +WaitNonVblank: + jr $31 + li $0,7 + + .globl RegisterVblankHandler +RegisterVblankHandler: + jr $31 + li $0,8 + + .globl ReleaseVblankHandler +ReleaseVblankHandler: + jr $31 + li $0,9 diff --git a/fps2bios/kernel/iopload/loadcore/Makefile b/fps2bios/kernel/iopload/loadcore/Makefile new file mode 100644 index 0000000000..b7d1a95cbf --- /dev/null +++ b/fps2bios/kernel/iopload/loadcore/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: loadcore + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = loadcore.o ../iopdebug.o ../iopelf.o ../romdir.o ../libkernel/iop_sysmem.o + +loadcore: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/LOADCORE + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/loadcore/loadcore.c b/fps2bios/kernel/iopload/loadcore/loadcore.c new file mode 100644 index 0000000000..690215da08 --- /dev/null +++ b/fps2bios/kernel/iopload/loadcore/loadcore.c @@ -0,0 +1,1044 @@ + +#include + +#include "ksysmem.h" +#include "kloadcore.h" +#include "iopdebug.h" +#include "iopelf.h" +#include "romdir.h" +#include "irx.h" // ps2sdk file for IMPORT_MAGIC + +#define BOOTMODE_START *((volatile u32**)0x3F0) +#define BOOTMODE_END *((volatile u32**)0x3F4) + +void _start(BOOT_PARAMS *init); // has to be declared first! + +struct tag_LC_internals { + struct export* let_next, *let_prev; + struct export* mda_next, *mda_prev;//.prev==free + imageInfo *image_info; // 0x800?0x830? + int module_count; + int module_index; +} lc_internals; + +u32 free; +u32 sysmem_00; +u32 modules_count; +u32 module_index; +u32 *place; // addr of 8 * 31 = 8 * linesInIopbtconf //place[2][31] +u32 bootmodes[17]; // was 16? +u32 bootmodes_size; +int debug=0; + +u32 bm_end; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("loadcore:%d: " fmt, __LINE__, ## args) + +void retonly(); +struct tag_LC_internals* GetLibraryEntryTable(); +void FlushIcache(); +void FlushDcache(); +int RegisterLibraryEntries(struct export *es); +int ReleaseLibraryEntries(struct export *e); +int _LinkImports(u32 *addr, int size); +int _UnlinkImports(void *addr, int size); +int RegisterNonAutoLinkEntries(struct export *e); +int QueryLibraryEntryTable(struct export *e); +u32 *QueryBootMode(int id); +void RegisterBootMode(struct bootmode *b); +int SetNonAutoLinkFlag(struct export *e); +int UnsetNonAutoLinkFlag(struct export *e); +void _LinkModule(imageInfo *ii); +void _UnlinkModule(imageInfo *ii); +int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result); +void _SetCacheCtrl(u32 val); +int _ReadModuleHeader(void *image, fileInfo *result); +int _LoadModule(void *image, fileInfo *fi); +u32 _FindImageInfo(void *addr); + +struct export loadcore_stub __attribute__((section(".text"))) ={ + EXPORT_MAGIC, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "loadcore", + (func)_start, // entrypoint + (func)retonly, + (func)retonly, + (func)GetLibraryEntryTable, + (func)FlushIcache, + (func)FlushDcache, + (func)RegisterLibraryEntries, + (func)ReleaseLibraryEntries, + (func)_LinkImports, + (func)_UnlinkImports, + (func)RegisterNonAutoLinkEntries, + (func)QueryLibraryEntryTable, + (func)QueryBootMode, + (func)RegisterBootMode, + (func)SetNonAutoLinkFlag, + (func)UnsetNonAutoLinkFlag, + (func)_LinkModule, + (func)_UnlinkModule, + (func)retonly, + (func)retonly, + (func)_RegisterBootupCBFunc, + (func)_SetCacheCtrl, + (func)_ReadModuleHeader, + (func)_LoadModule, + (func)_FindImageInfo, + 0 +}; + +/////////////////////////////////////////////////////////////////////// +void retonly(){} + +/////////////////////////////////////////////////////////////////////// +void RegisterBootMode(struct bootmode *b) { + int i; + + _dprintf("%s\n", __FUNCTION__); + if (((b->len + 1) * 4) < (16-bootmodes_size)) { + u32 *p = &bootmodes[bootmodes_size]; + for (i=0; ilen + 1; i++) p[i]=((u32*)b)[i]; + p[i]=0; + bootmodes_size+= b->len + 1; + } +} + +/////////////////////////////////////////////////////////////////////// +u32 *QueryBootMode(int id) { + u32 *b; + + for (b = (u32*)&bootmodes[0]; *b; b += ((struct bootmode*)b)->len + 1) + if (id == ((struct bootmode*)b)->id) + return b; + return NULL; +} + +/////////////////////////////////////////////////////////////////////// +int match_name(struct export *src, struct export *dst){ + return (*(int*)(src->name+0) == *(int*)(dst->name+0)) && + (*(int*)(src->name+4) == *(int*)(dst->name+4)); +} + +/////////////////////////////////////////////////////////////////////// +int match_version_major(struct export *src, struct export *dst){ + return ((src->version>>8) - (dst->version>>8)); +} + +/////////////////////////////////////////////////////////////////////// +int match_version_minor(struct export *src, struct export *dst){ + return ((unsigned char)src->version - (unsigned char)dst->version); +} + +/////////////////////////////////////////////////////////////////////// +int fix_imports(struct import *imp, struct export *exp){ + func *ef; + struct func_stub *fs; + int count=0, ordinal; + + for (ef=exp->func; *ef; ef++){ + count++; //count number of exported functions + } + _dprintf("%s (%d functions)\n", __FUNCTION__, count); + + for (fs=imp->func; fs->jr_ra; fs++) { + if ((fs->addiu0 >> 26) != INS_ADDIU) break; + + ordinal = fs->addiu0 & 0xFFFF; + if (ordinal < count) { +// _dprintf("%s linking ordinal %d to %x\n", __FUNCTION__, ordinal, exp->func[ordinal]); + fs->jr_ra=(((u32)exp->func[ordinal]>>2) & 0x3FFFFFF) | INS_J; + } else { + fs->jr_ra=INS_JR_RA; + } + } + + imp->flags |=FLAG_IMPORT_QUEUED; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +// Check the structure of the import table. +// Return 0 if a bad or empty import table is detected. +// Return a non-zero value if a valid import table is detected. +// +int check_import_table(struct import* imp){ + struct func_stub *f; + + if (imp->magic != IMPORT_MAGIC) + return 0; + for (f=imp->func; f->jr_ra; f++){ + if (f->addiu0 >> 26 != INS_ADDIU) + return 0; + if ((f->jr_ra!=INS_JR_RA) && (f->jr_ra>26!=INS_JR)) + return 0; + } + if (f->addiu0) + return 0; + return (imp->func < f); +} + +///////////////////////////////////////////////////////////////////////[OK] + +// Return 0 if successful +int link_client(struct import *imp){ + struct export *e; + +// _dprintf("%s\n", __FUNCTION__); + for (e=lc_internals.let_next; e; e=(struct export*)e->magic_link) { + if (debug > 0){ + // Zero terminate the name before printing it + char ename[9], iname[9]; + *(int*)ename = *(int*)e->name; *(int*)(ename+4) = *(int*)(e->name+4); ename[8] = 0; + *(int*)iname = *(int*)imp->name; *(int*)(iname+4) = *(int*)(imp->name+4);iname[8] = 0; + + //__printf("loadcore: %s: %s, %s\n", __FUNCTION__, ename, iname); + } + + if (!(e->flags & FLAG_NO_AUTO_LINK)){ + if ( match_name(e, (struct export*)imp)){ + if (match_version_major(e, (struct export*)imp)==0) { + fix_imports(imp, e); + imp->next=(struct import*)e->next; + e->next=(struct export*)imp; + FlushIcache(); + return 0; + } else { +// _dprintf("%s: version does not match\n", __FUNCTION__); + } + } else { +// _dprintf("%s: name does not match\n", __FUNCTION__); + } + } else { +// _dprintf("%s: e->flags bit 0 is 0\n", __FUNCTION__); + } + } + _dprintf("%s: FAILED to find a match\n", __FUNCTION__); + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +int _LinkImports(u32 *addr, int size) +{ + struct import *p; + int i; + + _dprintf("%s: %x, %d\n", __FUNCTION__, addr, size); + for (i=0; imagic == IMPORT_MAGIC) && + check_import_table(p) && + ((p->flags & 7) == 0) && + link_client(p)) { + _UnlinkImports(p, size); + return -1; + } + } + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +int unlink_client(struct import *i1, struct import *i2){ + struct import *i, *tmp; + + if (i1->next == i2){ + i1->next=i2->next; + return 0; + } + for (i = i1->next; i->next;) { + tmp=i->next; + if (tmp==i2) { + i->next=tmp->next; + tmp->next=NULL; + return 0; + } + i=tmp; + } + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +void restore_imports(struct import* imp){ + struct func_stub *f; + + for (f=imp->func; (f->jr_ra) && ((f->addiu0 >> 26) == INS_ADDIU); f++) + f->jr_ra=INS_JR_RA; +} + +///////////////////////////////////////////////////////////////////////[OK] +int _UnlinkImports(void *addr, int size) +{ + struct export *e; + struct export *i; + struct export *tmp; + void *limit = addr + (size & ~0x3); + + for (e = (struct export*)lc_internals.let_next; e; e=(struct export*)e->magic_link){ + for (i = e->next; i; i=i->next) { + if (((u32)i >= (u32)addr) && ((u32)i < (u32)limit)) { + if (unlink_client((struct import*)e, (struct import*)i)) + return -1; + i->flags &= ~0x7; + restore_imports((struct import*)i); + } + } + if (((u32)e >= (u32)addr) && ((u32)e < (u32)limit)) + ReleaseLibraryEntries(e); + } +/* + for (i=let.mda; i->next; ) + if ((i->next >= addr) && (i->next < limit)){ + i->next->flags &= ~0x7; + restore_imports(i->next); + tmp = i->next->next; + i->next->next=NULL; + i->next=tmp; + }else + i=i->next; +*/ + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int SetNonAutoLinkFlag(struct export *e) +{ + return (e->flags |= FLAG_NO_AUTO_LINK); +} + +/////////////////////////////////////////////////////////////////////// +int UnsetNonAutoLinkFlag(struct export *e) +{ + return (e->flags &= ~FLAG_NO_AUTO_LINK); +} + +/////////////////////////////////////////////////////////////////////// +int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result) +{ + int x; + register int r; + if (place==NULL){ + x=1; + r=function(&x, 0); + if (result) *result=r; + return 0; + } + + __asm__("move %0, $gp\n" : "=r"(x) : ); + + place[0]=(u32)function + (priority & 3); + place[1]=x; + place[2]=0; + place+=2; + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void _LinkModule(imageInfo *ii) +{ + imageInfo* p; + for (p=lc_internals.image_info; p->next && (p->next < (u32)ii); p=(imageInfo*)p->next); + + ii->next=p->next; + p->next=(u32)ii; + + ii->modid=module_index++; + modules_count++; +} + +/////////////////////////////////////////////////////////////////////// +void _UnlinkModule(imageInfo *ii) +{ + imageInfo *p; + if (ii) + for (p=lc_internals.image_info; p->next; p=(imageInfo*)p->next) + if (p->next == (u32)ii){ + p->next=((imageInfo*)p->next)->next; + modules_count--; + return; + } +} + +u32 _FindImageInfo(void *addr) +{ + register imageInfo *ii; + for (ii=lc_internals.image_info; ii; ii=(imageInfo*)ii->next) + if(((u32)addr>=ii->p1_vaddr) && + ((u32)addr p1_vaddr + ii->text_size + ii->data_size + ii->bss_size)) + return (u32)ii; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int RegisterLibraryEntries(struct export *es){ + struct export *p; + struct export *plast; + struct export *pnext; + struct export *tmp; + struct export *snext; + + if ((es == NULL) || (es->magic_link != EXPORT_MAGIC)) + return -1; + + if (debug > 0){ + // Zero terminate the name before printing it + char ename[9]; + *(int*)ename = *(int*)es->name; + *(int*)(ename+4) = *(int*)(es->name+4); + ename[8] = 0; + + __printf("loadcore: %s (%x): %s, %x\n", __FUNCTION__, es, es->name, es->version); + } + + + plast=NULL; + for (p=(struct export*)lc_internals.let_next; p; p=(struct export*)p->magic_link) { + if (match_name(es, p) == 0 || + match_version_major(es, p) == 0) continue; + + if (match_version_minor(es, p) == 0) + return -1; + _dprintf("%s: found match\n", __FUNCTION__); + pnext = p->next; + p->next = NULL; + + for (tmp = pnext; tmp; ) { + if (tmp->flags & FLAG_NO_AUTO_LINK) { + pnext->magic_link = (u32)tmp; + pnext = tmp->next; + tmp->next = NULL; + } else { + tmp->next=plast; + plast=tmp; + } + tmp=tmp->next; + } + } + + if( lc_internals.mda_next ) { + for (tmp = lc_internals.mda_next; tmp->next; tmp=tmp->next) { //free + if ((match_name(es, tmp->next)) && + (match_version_major(es, tmp->next)==0)){ + _dprintf("%s: freeing module\n", __FUNCTION__); + snext=tmp->next->next; + tmp->next->next=plast; + plast=tmp->next; + tmp->next=snext; + } else tmp=tmp->next; + } + } + + es->next=0; + while (plast) { + snext=plast->next; + fix_imports((struct import*)plast, es); + plast->next=es->next; + es->next=plast; + plast=snext; + } + es->flags &= ~FLAG_NO_AUTO_LINK; + es->magic_link=(u32)lc_internals.let_next; + lc_internals.let_next=es; + FlushIcache(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int ReleaseLibraryEntries(struct export *e) +{ + register struct export *n, *p, *next, *prev; + + p = lc_internals.let_next; + while ((p) && (p!=e)){ + prev=p; + p=(struct export*)prev->magic_link; + } + if (p != e) // if (0 != e) + return -1; //japanese BUG for e==p==0 + + n =e->next; + e ->next =0; + + prev->magic_link=e->magic_link; + e ->magic_link=0x41C00000; + + while(n) { + next = n->next; + if (link_client((struct import*)n)){ + restore_imports((struct import*)n); + n->flags=(n->flags & ~2) | 4; + n->next = lc_internals.mda_prev; + lc_internals.mda_prev=n; + } + n=next; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int RegisterNonAutoLinkEntries(struct export *e) +{ + if ((e == NULL) || (e->magic_link != EXPORT_MAGIC)){ + return -1; + } + e->flags |= FLAG_NO_AUTO_LINK; + e->magic_link = (u32)lc_internals.let_next; // --add as first + lc_internals.let_next = e; // / + FlushIcache(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int QueryLibraryEntryTable(struct export *e) +{ + struct export *p = lc_internals.let_next; + while (p){ + if ((match_name(p, e)) && (match_version_major(p, e)==0)){ + return (int)p->func; + } + p=(struct export*)p->magic_link; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +struct tag_LC_internals* GetLibraryEntryTable(){ + return &lc_internals; +} + +/////////////////////////////////////////////////////////////////////// +void _FlushIcache() { + u32 status; + u32 s1450; + u32 s1578; + u32 icache; + u32 *p; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + s1450 = *(int*)0xBF801450; + *(int*)0xBF801450&= ~1; + *(int*)0xBF801450; + + s1578 = *(int*)0xBF801578; + *(int*)0xBF801578 = 0; + *(int*)0xBF801578; + + icache = *(int*)0xFFFE0130; + *(int*)0xFFFE0130 = 0xC04; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); + + for (p=0; p<(u32*)0x400; p+=4) // 4KB instruction cache + *p=0; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = icache; + *(int*)0xFFFE0130; + *(int*)0xBF801578 = s1578; + *(int*)0xBF801578; + *(int*)0xBF801450 = s1450; + *(int*)0xBF801450; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void FlushIcache() { + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_FlushIcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +void _FlushDcache() { + u32 status; + u32 s1450; + u32 s1578; + u32 icache; + u32 *p; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + s1450 = *(int*)0xBF801450; + *(int*)0xBF801450&= ~1; + *(int*)0xBF801450; + + s1578 = *(int*)0xBF801578; + *(int*)0xBF801578 = 0; + *(int*)0xBF801578; + + icache = *(int*)0xFFFE0130; + *(int*)0xFFFE0130 = 0xC4; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); + + for (p=0; p<(u32*)0x100; p+=4) // 1KB data cache + *p=0; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = icache; + *(int*)0xFFFE0130; + *(int*)0xBF801578 = s1578; + *(int*)0xBF801578; + *(int*)0xBF801450 = s1450; + *(int*)0xBF801450; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void FlushDcache(){ + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_FlushDcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +void _SetIcache(u32 val) { + u32 status; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = val; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void _SetCacheCtrl(u32 val) +{ + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_SetIcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +int _ReadModuleHeader(void *image, fileInfo *result) +{ + COFF_HEADER *coffhdr = image; + COFF_scnhdr *section = (COFF_scnhdr*)((char*)image+sizeof(COFF_HEADER));//0x4C + + if ((coffhdr->f_magic==0x162) && //COFF loading + (coffhdr->opthdr.magic == 0x107) && + (coffhdr->f_nscns < 32) && + ((coffhdr->f_opthdr & 0x2FFFF) == 0x20038) && + (section->s_paddr == coffhdr->opthdr.text_start)){ + + if (coffhdr->opthdr.vstamp == 0x7001) + return -1; + result->type =1; + result->entry =coffhdr->opthdr.entry; + result->gp_value =coffhdr->opthdr.gp_value; + result->p1_vaddr =coffhdr->opthdr.text_start; + result->text_size =coffhdr->opthdr.tsize; + result->data_size =coffhdr->opthdr.dsize; + result->bss_size =coffhdr->opthdr.bsize; + result->p1_memsz =coffhdr->opthdr.bss_start+coffhdr->opthdr.bsize-coffhdr->opthdr.text_start; + result->moduleinfo =(moduleInfo*)coffhdr->opthdr.moduleinfo; + return result->type; + }else{ + ELF_HEADER* eh = (ELF_HEADER*)image; + ELF_PHR* ph= (ELF_PHR*)((char*)eh +eh->e_phoff); + //if ((eh->e_ident[EI_CLASS] != ELFCLASS32) || + //(eh->e_ident[EI_DATA]) != ELFDATA2LSB)) return -1;//break + if( *(u16*)(eh->e_ident+4) != 0x101 ) + return -1; + if (eh->e_machine != EM_MIPS) + return -1;//break + if (eh->e_phentsize != sizeof(ELF_PHR)) + return -1;//break + if (eh->e_phnum != 2) + return -1;//break + if (ph[0].p_type != PT_SCE_IOPMOD) + return -1;//break + if (eh->e_type != ET_SCE_IOPRELEXEC){ + if (eh->e_type != eh->e_phnum )//ET_EXEC) + return -1;//only + result->type=3; + }else + result->type=4; + ELF_IOPMOD* im= (ELF_IOPMOD*)((char*)image + ph[0].p_offset); + result->entry =im->entry; + result->gp_value=im->gp_value; + result->p1_vaddr=ph[1].p_vaddr; + result->text_size=im->text_size; + result->data_size=im->data_size; + result->bss_size=im->bss_size; + result->p1_memsz=ph[1].p_memsz; + result->moduleinfo=( moduleInfo*)im->moduleinfo; + return result->type; + } + return result->type=-1; +} + +#define MODULE_TYPE_COFF 1 +#define MODULE_TYPE_2 2 +#define MODULE_TYPE_EXEC 3 +#define MODULE_TYPE_IOPRELEXEC 4 + +/////////////////////////////////////////////////////////////////////// +void setImageInfo(fileInfo *fi, imageInfo *ii) +{ + ii->next =0; + ii->name =NULL; + ii->version =0; + ii->flags =0; + ii->modid =0; + if ((int)fi->moduleinfo != -1){ + ii->name =fi->moduleinfo->name; + ii->version =fi->moduleinfo->version; + } + ii->entry =fi->entry; + ii->gp_value =fi->gp_value; + ii->p1_vaddr =fi->p1_vaddr; + ii->text_size =fi->text_size; + ii->data_size =fi->data_size; + ii->bss_size =fi->bss_size; +} + +/////////////////////////////////////////////////////////////////////// +void load_type_1(COFF_HEADER *image){ + SHDR* s0=(SHDR*)( (char*)image + *(int*)((char*)image+0x60) ); + lc_memcpy(s0, image->opthdr.text_start, image->opthdr.tsize); + lc_memcpy((char*)s0+image->opthdr.tsize, image->opthdr.data_start, image->opthdr.dsize); + if (image->opthdr.bss_start && image->opthdr.bsize) + lc_zeromem((void*)image->opthdr.bss_start, image->opthdr.bsize/4); +} + +/////////////////////////////////////////////////////////////////////// +void load_type_3(void *image){ + ELF_PHR *ph=(ELF_PHR*)((char*)image+((ELF_HEADER*)image)->e_phoff); + lc_memcpy(image+ph[1].p_offset, ph[1].p_vaddr, ph[1].p_filesz); + if (ph[1].p_filesz < ph[1].p_memsz) + lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz, + (ph[1].p_memsz-ph[1].p_filesz)/4); +} + +/////////////////////////////////////////////////////////////////////// +#define R_MIPS_32 2 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 + +void load_type_4(ELF_HEADER *image, fileInfo *fi) +{ + ELF_PHR *ph=(ELF_PHR*)((char*)image+image->e_phoff); + ELF_SHR* sh = (ELF_SHR*)((char*)image+image->e_shoff); + ELF_REL* rel; + int i,j,scount; + u32* b, *b2, tmp; + + //ph[0] - .iopmod, skip + fi->entry += fi->p1_vaddr; + fi->gp_value += fi->p1_vaddr; + if ((int)fi->moduleinfo != -1) + fi->moduleinfo = (moduleInfo*)((int)fi->moduleinfo + fi->p1_vaddr); + lc_memcpy((char*)image+ph[1].p_offset, fi->p1_vaddr, ph[1].p_filesz); + + if (ph[1].p_filesz < ph[1].p_memsz) { + lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz+fi->p1_vaddr, (ph[1].p_memsz-ph[1].p_filesz)); + } + + for (i=1; ie_shnum; i++) { + if (sh[i].sh_type==SHT_REL) { + ELF_REL* rel =(ELF_REL*)(sh[i].sh_offset + (char*)image); + scount=sh[i].sh_size / sh[i].sh_entsize; + for (j=0; jp1_vaddr + rel[j].r_offset); + switch((u8)rel[j].r_info){ + case R_MIPS_LO16: + *b=(*b & 0xFFFF0000) | (((*b & 0x0000FFFF) + fi->p1_vaddr) & 0xFFFF); + break; + case R_MIPS_32: + *b+=fi->p1_vaddr; + break; + case R_MIPS_26: + *b = (*b & 0xfc000000) | (((*b & 0x03ffffff) + (fi->p1_vaddr >> 2)) & 0x03ffffff); + break; + case R_MIPS_HI16: + b2 =(u32*)(rel[j+1].r_offset + fi->p1_vaddr); + ++j; + + tmp = (*b << 16) + (int)(*(s16*)b2) + fi->p1_vaddr; + *b = (*b&0xffff0000) | ((((tmp>>15)+1)>>1)&0xffff); + *b2 = (*b2&0xffff0000) | (tmp&0xffff); + break; + } + } + } + } +} + +int _LoadModule(void *image, fileInfo *fi) +{ + u32* ptr; + int i; + switch (fi->type){ + case MODULE_TYPE_COFF: load_type_1(image); break; + case MODULE_TYPE_EXEC: load_type_3(image); break; + case MODULE_TYPE_IOPRELEXEC: load_type_4(image, fi); break; + default: return -1; + } + + setImageInfo(fi, (imageInfo*)(fi->p1_vaddr-0x30)); + + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +int lc_memcpy(void *src,void *dest,int len){ + char* _src = (char*)src; + char* _dst = (char*)dest; + for (len=len; len>0; len--) + *_dst++=*_src++; +} + +///////////////////////////////////////////////////////////////////////[OK] +int lc_zeromem(void *addr,int len){ + for (; len>0; len--) *(char*)addr++=0; +} + +int lc_strlen(char *s) +{ + int len; + if (s==NULL) return 0; + for (len=0; *s++; len++); + return len; +} + +int recursive_set_a2(int* start, int* end, int val) +{ + *start++ = val; + if( start < end ) + return recursive_set_a2(start, end, val); + return 0; +} + +void* lc_memcpy_overlapping(char *dst,char *src,int len){ + if (dst==NULL) return 0; + + if (dst>=src) + while(--len>=0) + *(dst+len)=*(src+len); + else + while (len-->0) + *dst++=*src++; + + return dst; +} + +//////////////////////////////entrypoint/////////////////////////////// +void _start(BOOT_PARAMS *init) { + *(int*)0xFFFE0130 = 0x1e988; + __asm__ ( + "addiu $26, $0, 0\n" + "mtc0 $26, $12\n"); + //"move $fp, %0\n" + //"move $sp, %0\n" + //: : "r"((init->ramMBSize << 20) - 0x40)); + __asm__ ( + "j loadcore_start\n" + ); +} + +extern void* _ftext, *_etext, *_end; +typedef int (*IopEntryFn)(u32,void*,void*,void*); + +void loadcore_start(BOOT_PARAMS *pInitParams) +{ + fileInfo fi; + void (*entry)(); + u32 offset; + u32 status = 0x401; + int bm; + int i; + void** s0; // pointer in module list to current module? + BOOT_PARAMS params; + u32 s1, s2, s3, sp, a2; + + _dprintf("%s\n", __FUNCTION__); + + // Write 0x401 into the co-processor status register? + // This enables interrupts generally, and disables (masks) them all except hardware interrupt 0? + + lc_memcpy(pInitParams,¶ms,sizeof(BOOT_PARAMS)); + BOOTMODE_END = BOOTMODE_START = bootmodes; + + //_dprintf("module: %x\n", params.firstModuleAddr); + + lc_internals.let_next = (struct export*)params.firstModuleAddr; + lc_internals.let_prev = (struct export*)params.firstModuleAddr; + lc_internals.let_next->next = 0; + lc_internals.module_count = 2; // SYSMEM + LOADCORE + lc_internals.mda_prev = lc_internals.mda_next = NULL; + lc_internals.module_index = 3; // next available index + + for (i=0; i<17; i++){ + bootmodes[i]=0; + } + bootmodes_size=0; + + bm = params.bootInfo | 0x00040000; + RegisterBootMode((struct bootmode*)&bm); + + lc_internals.image_info = (imageInfo*)((u32)lc_internals.let_prev - 0x30); + lc_internals.image_info->modid = 1; // SYSMEM is the first module + lc_internals.image_info->next = (u32)&_ftext - 0x30; + ((imageInfo*)lc_internals.image_info->next)->modid = 2; // LOADCORE is the second module + + // find & fix LOADCORE imports (to SYSMEM) + _LinkImports((u32*)&_ftext, (u32)&_etext - (u32)&_ftext); + + RegisterLibraryEntries(&loadcore_stub); + + // reserve LOADCORE memory + AllocSysMemory(2, (u32)((u32)&_end - (((u32)&_ftext - 0x30) >> 8 << 8)), (void*)((((u32)&_ftext - 0x30) >> 8 << 8) & 0x1FFFFFFF)); + + if (params.pos) + params.pos = (u32)AllocSysMemory(2, params.size, (void*)params.pos); + + sp=(u32)alloca(0x10); + s0 = (void**)((sp - 0xDF0) & 0x1FFFFF00);//=0x001ff100 + recursive_set_a2((int*)s0, (void*)(sp+0x10), 0x11111111); + if ((u32)s0 < QueryMemSize()) + AllocSysMemory(2, QueryMemSize() - (u32)s0, s0); + + if (params.udnlString){ + int v0 = lc_strlen(params.udnlString); + int* v1 = (int*)alloca((v0 + 8 + 8) >> 3 << 3); + lc_memcpy_overlapping((char*)&v1[6], params.udnlString, v0+1); + params.udnlString = (char*)&v1[6]; + v1[4] = 0x01050000; + v1[5] = (int)&v1[6]; + RegisterBootMode((struct bootmode*)&v1[4]); // BTUPDATER bootmode 5 + } + + a2 = (params.numConfLines+1) * 4; + s0 = alloca((a2 + 7) >> 3 << 3) + 0x10; + lc_memcpy_overlapping((char*)s0, (char*)params.moduleAddrs, a2); //0x30020 + + s1 = 0; + params.moduleAddrs = (u32**)s0; + s2 = (u32)alloca(params.numConfLines << 3) + 0x10; + place = (u32*)s2; + *place = 0; + i = -1; + s3 = 1; + + _dprintf("loading modules: %d\n", params.numConfLines); + s0 += 2; // skip first two: SYSMEM, LOADCORE + for (; *s0; s0+=1) { + if ((u32)*s0 & 1){ + if (((u32)*s0 & 0xF) == s3) + s1 = (u32)*s0>>2; + }else{ + i += 1; + i &= 0xF; + + _dprintf("load module from %x\n", *s0); + switch(_ReadModuleHeader(*s0, &fi)){ + case MODULE_TYPE_COFF: + case MODULE_TYPE_EXEC: + a2 = ((fi.p1_vaddr - 0x30) >> 8 << 8) & 0x1FFFFFFF; + if (NULL == AllocSysMemory(2, fi.p1_memsz + fi.p1_vaddr - a2, (void*)a2)) + goto HALT; + break; + + case MODULE_TYPE_2: + case MODULE_TYPE_IOPRELEXEC: + if (fi.p1_vaddr = (u32)((s1 == 0) ? + AllocSysMemory(0, fi.p1_memsz+0x30, 0) : + AllocSysMemory(2, fi.p1_memsz+0x30, (void*)s1)) ) + fi.p1_vaddr += 0x30; + else + goto HALT; + break; + + default: + _dprintf("could not find module at %x\n", *s0); + goto HALT; + } + + _LoadModule(*s0, &fi); + _dprintf("loading module %s: at offset %x, memsz=%x, type=%x, entry=%x\n", fi.moduleinfo->name, fi.p1_vaddr, fi.p1_memsz, fi.type, fi.entry); + + if (0 == _LinkImports((u32*)fi.p1_vaddr, fi.text_size)) { + + FlushIcache(); + __asm__("move $gp, %0\n" : : "r"(fi.gp_value)); + // call the entry point + s1 = ((IopEntryFn)fi.entry)(0, NULL, s0, NULL); + + if ((s1 & 3) == 0){ + _LinkModule((imageInfo*)(fi.p1_vaddr - 0x30)); + if (s1 & ~3) + _RegisterBootupCBFunc((int (*)(int *, int))(s1 & ~3), BOOTUPCB_NORMAL, 0); + }else{ + _UnlinkImports((void*)fi.p1_vaddr, fi.text_size); + FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); + } + }else { + FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); + } + + s1 = 0; + } + } + + if (params.pos) + FreeSysMemory((void*)params.pos); + + for (i=BOOTUPCB_FIRST; iname[0] == 'R' && + dir_entry->name[1] == 'E' && + dir_entry->name[2] == 'S' && + dir_entry->name[3] == 'E' && + dir_entry->name[4] == 'T' && + dir_entry->name[5] == 0 && + (ROUND_UP(dir_entry->fileSize,16) == offset) ) + { + romDirInfo->romPtr = (u32)searchStartAddr; // start of rom + romDirInfo->romdirPtr = dir_entry; // start of romdir structure + romDirInfo->extinfoPtr = (u32)dir_entry + dir_entry[1].fileSize; // start of extinfo + return romDirInfo; + } + + dir_entry++; + offset += sizeof(ROMDIR_ENTRY); + } + + // not found + romDirInfo->romdirPtr = NULL; + return NULL; +} + +// find a file in the romdir table and return info about it +// +// args: info about romdir to search through +// filename to search for +// structure to get info about file into +// returns: a pointer to fileinfo if successful +// NULL otherwise +ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo) +{ + register ROMDIR_ENTRY* dir_entry; + register ext_offset=0, file_offset=0; + int i; + + for (dir_entry = romdirInfo->romdirPtr; dir_entry->name[0]; dir_entry++) { + + for(i = 0; i < 10; ++i) { + if( filename[i] == 0 ) + break; + if( dir_entry->name[i] != filename[i] ) { + i = -1; + break; + } + } + + if (i > 0 ) { + fileinfo->entry = dir_entry; + fileinfo->fileData = file_offset + romdirInfo->romPtr; // address of file in rom + fileinfo->extData = (u32)NULL; // address of extinfo in rom + + if (dir_entry->extSize) + fileinfo->extData = ext_offset + romdirInfo->extinfoPtr; // address of extinfo in rom + return fileinfo; + } + + file_offset += ROUND_UP(dir_entry->fileSize,16); + ext_offset += dir_entry->extSize; + } + + // error - file not found + return NULL; +} + +// gets a hex number from *addr and updates the pointer +// +// args: pointer to string buffer containing a hex number +// returns: the value of the hex number +u32 getHexNumber(char** addr) +{ + register char *p; //a1 + register u32 h = 0; //a2; + + for (p=*addr; *p >= '0'; p++) + { + int num; + if(*p <= '9') num = *p - '0'; + else if(*p >= 'a') num = *p - 'a' + 10; + else num = *p - 'A' + 10; + + h = h*16 + num; + } + + *addr = p; + return h; +} diff --git a/fps2bios/kernel/iopload/sifcmd/Makefile b/fps2bios/kernel/iopload/sifcmd/Makefile new file mode 100644 index 0000000000..2874d2ae4e --- /dev/null +++ b/fps2bios/kernel/iopload/sifcmd/Makefile @@ -0,0 +1,62 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sifcmd + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sifcmd.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sifman.o \ + ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o \ + ../libkernel/iop_stdio.o + +sifcmd: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFCMD + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sifcmd/sifcmd.c b/fps2bios/kernel/iopload/sifcmd/sifcmd.c new file mode 100644 index 0000000000..d944b51223 --- /dev/null +++ b/fps2bios/kernel/iopload/sifcmd/sifcmd.c @@ -0,0 +1,798 @@ +//[module] SIFCMD +//[processor] IOP +//[type] ELF-IRX +//[name] IOP_SIF_rpc_interface +//[version] 0x101 +//[memory map] +//[handlers] +//[entry point] sifcmd_start, sifcmd_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include "kloadcore.h" +#include "kintrman.h" +#include "ksifman.h" +#include "kthbase.h" +#include "ksifcmd.h" +#include "ksifman.h" + +#define _dprintf(fmt, args...) \ + __printf("sifcmd: " fmt, ## args) + +int sifInitRpc=0; + +// CMD data +char sif1_rcvBuffer[8*16]; //8 qwords +char b[4*16]; //not used +struct tag_cmd_common { + char *sif1_rcvBuffer, //+00 + *b, //+04 + *saddr; //+08 + SifCmdData *sysCmdBuffer; //+0C + int sysCmdBufferSize; //+10 + SifCmdData *cmdBuffer; //+14 + int cmdBufferSize, //+18 + *Sreg, //+1C + systemStatusFlag; //+20 + void (*func)(int); //+24 + int param, //+28 + _pad; //+2C +} cmd_common; //=30 +SifCmdData sysCmds[32]; +int Sreg[32]; + +// RPC data +int bufx[512], bufy[512]; +struct tag_rpc_common{ + int pid; + RPC_PACKET *paddr; + int size; + RPC_PACKET *paddr2; + int size2; + void *next; + int count; + int base; + void *queue; + int _pad0, + _pad1, + _pad2; +} rpc_common; + + +int _start(); + +/////////////////////////////////////////////////////////////////////// +//////////////////////////// CMD ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////// +void cmd80000001_SET_SREG(SifCmdSRData *packet, struct tag_cmd_common *common) { + common->Sreg[packet->rno]=packet->value; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000000_CHANGE_SADDR(SifCmdCSData *packet, struct tag_cmd_common *common) { + common->saddr=packet->newaddr; +} + +///////////////////////////////////////////////////////////////////////[06] +int SifGetSreg(int index){ + return Sreg[index]; +} + +///////////////////////////////////////////////////////////////////////[07] +int SifSetSreg(int index, unsigned int value){ + return Sreg[index]=value; +} + +/////////////////////////////////////////////////////////////////////// +void *getCmdCommon(){ + return &cmd_common; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000002_INIT_CMD(SifCmdCSData *packet, struct tag_cmd_common *common){ + __printf("cmd80000002_INIT_CMD\n"); + if (packet->hdr.opt==0){ + iSetEventFlag(common->systemStatusFlag, 0x100); + SifSetEEIOPflags(0x20000); + common->saddr=packet->newaddr; + }else + iSetEventFlag(common->systemStatusFlag, 0x800); +} + +///////////////////////////////////////////////////////////////////////[02] +int SifDeinitCmd(){ + int x; + DisableIntr(INT_DMA10, &x); + ReleaseIntrHandler(INT_DMA10); + SifDeinit(); + return 0; +} + +///////////////////////////////////////////////////////////////////////[04] +void SifInitCmd(){ + __printf("iopSifInitCmd\n"); + SifSetIOPEEflags(0x20000); + WaitEventFlag(cmd_common.systemStatusFlag, 0x100, 0, 0); +} + +///////////////////////////////////////////////////////////////////////[05] +void SifExitCmd(){ + int x; + DisableIntr(INT_DMA10, &x); + ReleaseIntrHandler(INT_DMA10); +} + +///////////////////////////////////////////////////////////////////////[08] +SifCmdData *SifSetCmdBuffer(SifCmdData *cmdBuffer, int size){ + register SifCmdData *old; + old=cmd_common.cmdBuffer; + cmd_common.cmdBuffer=cmdBuffer; + cmd_common.cmdBufferSize=size; + return old; +} + +///////////////////////////////////////////////////////////////////////[09] +SifCmdData *SifSetSysCmdBuffer(SifCmdData *sysCmdBuffer, int size){ + register SifCmdData *old; + old=cmd_common.sysCmdBuffer; + cmd_common.sysCmdBuffer=sysCmdBuffer; + cmd_common.sysCmdBufferSize=size; + return old; +} + +///////////////////////////////////////////////////////////////////////[0A] +void SifAddCmdHandler(int pos, cmdh_func f, void *data){ + if (pos<0){ + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=f; + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].data=data; + }else{ + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=f; + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].data=data; + } +} + +///////////////////////////////////////////////////////////////////////[0B] +void SifRemoveCmdHandler(unsigned int pos){ + if (pos<0) + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=0; + else + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=0; +} + +/////////////////////////////////////////////////////////////////////// +unsigned int sendCmd(unsigned int pos, int mode, SifCmdHdr *cp, int ps, void *src, void *dst, int size){ + u32 x; + struct sifman_DMA dma[2]; + register int count, y; + + if (ps<16 || ps>112) return 0; + + count=0; + if (size>0){ + count=1; + dma[0].addr=dst; + dma[0].size=size; + dma[0].attr=0; + dma[0].data=src; + cp->daddr=(u32)dst; + cp->dsize=size; + }else{ + cp->daddr=0; + cp->dsize=0; + } + count++; + cp->psize=ps; + cp->fcode=pos; + dma[count-1].data=cp; + dma[count-1].attr=SIF_DMA_INT_O; //calls SIF0 handler + dma[count-1].size=ps; //on EE side after transfer;) + dma[count-1].addr=cmd_common.saddr; + if (mode & 1) //interrupt mode + return SifSetDma(dma, count); + else{ + CpuSuspendIntr(&x); + y=SifSetDma(dma, count); + CpuResumeIntr(x); + return y; + } +} + +///////////////////////////////////////////////////////////////////////[0C] +unsigned int SifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ + return sendCmd(pos, 0, cp, ps, src, dst, size); +} + +///////////////////////////////////////////////////////////////////////[0D] +unsigned int iSifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ + return sendCmd(pos, 1, cp, ps, src, dst, size); +} + +///////////////////////////////////////////////////////////////////////[1A] +void SifSet1CB(void *func, int param){ + cmd_common.func =func; + cmd_common.param=param; +} + +///////////////////////////////////////////////////////////////////////[1B] +void SifReset1CB(){ + cmd_common.func =0; + cmd_common.param=0; +} + +/////////////////////////////////////////////////////////////////////// +int SIF1_handler(void *common){ + int buf[112/4]; + register int i, ps; + register SifCmdData *scd; + SifCmdHdr *packet; + struct tag_cmd_common *c = (struct tag_cmd_common *)common; + + if (c->func) + c->func(c->param); + + packet=(SifCmdHdr*)c->sif1_rcvBuffer; + + if ((ps=packet->psize & 0xFF)==0){ + SifSetDChain(); + return 1; + } + packet->psize=0; + + ps=(ps+3<0 ? ps+6 : ps+3)/4; + for (i=0; ifcode<0){ + if (packet->fcode & 0x7FFFFFFF>=c->sysCmdBufferSize) + return 1; + scd=&c->sysCmdBuffer[packet->fcode & 0x7FFFFFFF]; + }else{ + if (packet->fcode>=c->cmdBufferSize) + return 1; + scd=&c->cmdBuffer[packet->fcode]; + } + if (scd->func) + scd->func(packet, scd->data); + + return 1; +} + +/////////////////////////////////////////////////////////////////////// +//////////////////////////// RPC ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////// +RPC_PACKET *rpc_get_packet(struct tag_rpc_common *common){ + u32 x; + register int pid, i; + RPC_PACKET *packet; + + CpuSuspendIntr(&x); + + for (i=0, packet=common->paddr; isize; i++) + if (packet[i].rec_id & 2==0) goto found; + for (i=0, packet=common->paddr2; isize2; i++) + if (packet[i].rec_id & 2==0) goto found; + + CpuResumeIntr(x); + return 0; + +found: + packet[i].rec_id |= 2; + pid=++common->pid; + if (pid == 1) + common->pid++; + packet[i].pid=pid; + packet[i].paddr=&packet[i]; + CpuResumeIntr(x); + return &packet[i]; +} + +/////////////////////////////////////////////////////////////////////// +void rpc_free_packet(RPC_PACKET *packet){ + packet->pid = 0; + packet->rec_id &= 0xFFFFFFFD; //~2 +} + +/////////////////////////////////////////////////////////////////////// +RPC_PACKET *rpc_get_fpacket(struct tag_rpc_common *common){ + register int i; + + i=common->base % common->count; + common->base=i+1; + return (RPC_PACKET*)(((u8*)common->next)+i*64); +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000008_END(RPC_PACKET_END *packet, struct tag_rpc_common *common){ + if (packet->command==0x8000000A){ + if (packet->client->func) + packet->client->func(packet->client->param); + }else + if (packet->command==0x80000009){ + packet->client->server=packet->server; + packet->client->buff =packet->buff; + packet->client->cbuff =packet->cbuff; + } + + if (packet->client->hdr.tid>=0) + iWakeupThread(packet->client->hdr.tid); + + rpc_free_packet(packet->client->hdr.pkt_addr); + packet->client->hdr.pkt_addr=0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd8000000C_RDATA(RPC_PACKET_RDATA *packet, struct tag_rpc_common *common){ + RPC_PACKET_END *epacket; + + epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); + + epacket->packet.paddr = packet->packet.paddr; + epacket->command = 0x8000000C; + epacket->client = packet->client; + + iSifSendCmd(0x80000008, epacket, 0x40, packet->src, packet->dst, packet->size); +} + +///////////////////////////////////////////////////////////////////////[17] +int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, void *src, void *dst, int size, int mode){ + RPC_PACKET_RDATA *packet; + + if ((packet=(RPC_PACKET_RDATA *)rpc_get_packet(&rpc_common))==0) + return -1; + + rd->hdr.pkt_addr=packet; + rd->hdr.rpc_id =packet->packet.pid; + packet->packet.paddr=packet; + packet->client=(struct sifcmd_RPC_CLIENT_DATA*)rd; + packet->src=src; + packet->dst=dst; + packet->size=size; + + if (mode & 1==0){ + rd->hdr.tid=GetThreadId(); + if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) + return -2; + SleepThread(); + }else{ //async + rd->hdr.tid=-1; + if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) + return -2; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +struct sifcmd_RPC_SERVER_DATA *search_svdata(u32 command, struct tag_rpc_common *common){ + struct sifcmd_RPC_SERVER_DATA *q; + struct sifcmd_RPC_SERVER_DATA *s; + + for (q=common->queue; q; q=q->next) { + for (s=q->link; s; s=s->link) { + if (s->command==command) + return s; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000009_BIND(RPC_PACKET_BIND *packet, struct tag_rpc_common *common){ + RPC_PACKET_END *epacket; + struct sifcmd_RPC_SERVER_DATA *s; + + epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); + + epacket->packet.paddr=packet->packet.paddr; + epacket->command=0x80000009; + epacket->client=packet->client; + + s = search_svdata(packet->fno, common); + if (s == NULL){ + epacket->server=0; + epacket->buff =0; + epacket->cbuff =0; + }else{ + epacket->server=s; + epacket->buff =s->buff; + epacket->cbuff =s->cbuff; + } + iSifSendCmd(0x80000008, epacket, 0x40, 0, 0, 0); +} + +///////////////////////////////////////////////////////////////////////[0F] +int SifBindRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int number, unsigned int mode) { + RPC_PACKET_BIND *packet; + + client->command=0; + client->server=0; + + packet = (RPC_PACKET_BIND *)rpc_get_packet(&rpc_common); + if (packet==NULL) return -1; + + client->hdr.pkt_addr = packet; + client->hdr.rpc_id = packet->packet.pid; + packet->packet.paddr = packet; + packet->client = client; + packet->fno = number; + + if (mode & 1==0){ + client->hdr.tid=GetThreadId(); + if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) + return -2; + SleepThread(); + }else{ //async + client->hdr.tid=-1; + if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) + return -2; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd8000000A_CALL(RPC_PACKET_CALL *packet, struct tag_rpc_common *common){ + struct sifcmd_RPC_DATA_QUEUE *qd; + + qd = packet->server->base; + if (qd->start==0) qd->start=packet->server; + else qd->end->link=packet->server; + qd->end=packet->server; + packet->server->pkt_addr=packet->packet.packet.paddr; + packet->server->client=packet->packet.client; + packet->server->fno=packet->packet.fno; + packet->server->size=packet->size; + packet->server->receive=packet->receive; + packet->server->rsize=packet->rsize; + packet->server->rmode=packet->rmode; + if ((qd->key>=0) && (qd->active==0)) + iWakeupThread(qd->key); +} + +///////////////////////////////////////////////////////////////////////[10] +int SifCallRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int fno, unsigned int mode, void *send, int ssize, void *receive, int rsize, void (*end_func)(void*), void *end_para){ + RPC_PACKET_CALL *packet; + + if ((packet=(RPC_PACKET_CALL *)rpc_get_packet(&rpc_common))==0) + return -1; + client->hdr.pkt_addr=(void*)packet; + client->func = end_func; + client->param = end_para; + client->hdr.rpc_id= packet->packet.packet.pid; + + packet->packet.packet.paddr = packet; + packet->packet.client = client; + packet->packet.fno = fno; + packet->size = ssize; + packet->receive= receive; + packet->rsize = rsize; + packet->server = client->server; + + if (mode & 1){ + packet->rmode=(end_func!=0); + client->hdr.tid=-1; + if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)) + return 0; + return -2; + }else{ + packet->rmode=1; + client->hdr.tid=GetThreadId(); + if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)==0) + return -2; + SleepThread(); + return 0; + } +} + +///////////////////////////////////////////////////////////////////////[12] +int SifCheckStatRpc(struct sifcmd_RPC_HEADER *rd){ + RPC_PACKET *packet = (RPC_PACKET*)rd->pkt_addr; + return (rd->pkt_addr && + (rd->rpc_id==packet->pid) && + (packet->rec_id & 2)); +} + +///////////////////////////////////////////////////////////////////////[13] +void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd, int key){ + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q, *i; + + CpuSuspendIntr(&x); + qd->key=key; + qd->active=0; + qd->link=0; + qd->start=0; + qd->end=0; + qd->next=0; + q = (struct sifcmd_RPC_DATA_QUEUE *)&rpc_common.queue; + if (q) { + for (i=q->next; i; i=q->next) q=q->next; + } + rpc_common.queue = qd; + CpuResumeIntr(x); +} + +///////////////////////////////////////////////////////////////////////[11] +void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 command, + rpch_func func, void *buff, + rpch_func cfunc, void *cbuff, + struct sifcmd_RPC_DATA_QUEUE *qd) { + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q, *i; + + CpuSuspendIntr(&x); + sd->command=command; + sd->func=func; + sd->buff=buff; + sd->next=0; + sd->link=0; + sd->cfunc=cfunc; + sd->cbuff=cbuff; + sd->base=qd; + + if (qd->link==0) + qd->link=sd; + else{ + for (q=qd->link, i=q->link; i; i=q->link) + q=q->link; + q->link=sd; + } + CpuResumeIntr(x); +} + +///////////////////////////////////////////////////////////////////////[18] +struct sifcmd_RPC_SERVER_DATA *SifRemoveRpc(struct sifcmd_RPC_SERVER_DATA *sd, struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_SERVER_DATA *s; + + CpuSuspendIntr(&x); + + if ((s=qd->link)==sd) + qd->link=s->link; + else + for ( ; s; s=s->link) + if (s->link==sd){ + s->link=s->link->link; + break; + } + CpuResumeIntr(x); + return s; +} + +///////////////////////////////////////////////////////////////////////[19] +struct sifcmd_RPC_DATA_QUEUE *SifRemoveRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q; + + CpuSuspendIntr(&x); + + q=rpc_common.queue; + if (q==qd) { + rpc_common.queue=q->next; + } else { + for (; q; q=q->next) { + if (q->next==qd){ + q->next=q->next->next; + break; + } + } + } + CpuResumeIntr(x); + return q; +} + +///////////////////////////////////////////////////////////////////////[14] +struct sifcmd_RPC_SERVER_DATA *SifGetNextRequest(struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_SERVER_DATA *s; + + CpuSuspendIntr(&x); + + if ((s=qd->start)==0) + qd->active=0; + else{ + qd->active=1; + qd->start=qd->start->next; + } + + CpuResumeIntr(x); + return s; +} + +///////////////////////////////////////////////////////////////////////[15] +void SifExecRequest(struct sifcmd_RPC_SERVER_DATA *sd){ + u32 x; + register int size, id, count, i; + register void *buff; + RPC_PACKET_END *epacket; + struct sifman_DMA dma[2]; + + size=0; + if (buff=sd->func(sd->fno, sd->buff, sd->size)) + size=sd->rsize; + + CpuSuspendIntr(&x); + epacket=(RPC_PACKET_END *)rpc_get_fpacket(&rpc_common); + CpuResumeIntr(x); + + epacket->command=0x8000000A; + epacket->client=sd->client; + count=0; + if (sd->rmode){ + while (SifSendCmd(0x80000008, epacket, 0x40, buff, sd->receive, size)==0); + return; + }else{ + epacket->packet.pid=0; + epacket->packet.rec_id=0; + if (size>0){ + count=1; + dma[count-1].data=buff; + dma[count-1].size=size; + dma[count-1].attr=0; + dma[count-1].addr=sd->receive; + } + count++; + dma[count-1].data=epacket; + dma[count-1].size=0x40; + dma[count-1].attr=0; + dma[count-1].addr=sd->pkt_addr; + do{ + CpuSuspendIntr(&x); + id=SifSetDma(dma, count); + CpuResumeIntr(x); + if (id) break; + i=0xFFFF; do --i; while (i!=-1); + } while (id==0); + } +} + +///////////////////////////////////////////////////////////////////////[16] +void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE *qd){ + register struct sifcmd_RPC_SERVER_DATA *s; + + do{ + if (s=SifGetNextRequest(qd)) + SifExecRequest(s); + else + SleepThread(); + } while (1); +} + +///////////////////////////////////////////////////////////////////////[0E] +void SifInitRpc(int mode){ + u32 x; + _dprintf("%s\n", __FUNCTION__); + + SifInitCmd(); + CpuSuspendIntr(&x); + + if (sifInitRpc){ + CpuResumeIntr(x); + }else{ + sifInitRpc=1; + rpc_common.paddr=(RPC_PACKET*)bufx; + rpc_common.size=32; + rpc_common.paddr2=0; + rpc_common.size2=0; + rpc_common.next=(RPC_PACKET*)bufy; + rpc_common.count=32; + rpc_common.base=0; + rpc_common.pid=1; + + SifAddCmdHandler(0x80000008, (cmdh_func)cmd80000008_END, &rpc_common); + SifAddCmdHandler(0x80000009, (cmdh_func)cmd80000009_BIND, &rpc_common); + SifAddCmdHandler(0x8000000A, (cmdh_func)cmd8000000A_CALL, &rpc_common); + SifAddCmdHandler(0x8000000C, (cmdh_func)cmd8000000C_RDATA, &rpc_common); + + CpuResumeIntr(x); + + ((SifCmdSRData*)bufx)->rno =0; + ((SifCmdSRData*)bufx)->value=1; + SifSendCmd(0x80000001, (void*)bufx, sizeof(SifCmdSRData), 0, 0, 0); + } + WaitEventFlag(GetSystemStatusFlag(), 0x800, 0, 0); +} + +void _retonly() {} + +struct export sifcmd_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sifcmd", + (func)_start, // entrypoint + (func)_retonly, + (func)SifDeinitCmd, + (func)_retonly, + (func)SifInitCmd, + (func)SifExitCmd, + (func)SifGetSreg, + (func)SifSetSreg, + (func)SifSetCmdBuffer, + (func)SifSetSysCmdBuffer, + (func)SifAddCmdHandler, + (func)SifRemoveCmdHandler, + (func)SifSendCmd, + (func)iSifSendCmd, + (func)SifInitRpc, + (func)SifBindRpc, + (func)SifCallRpc, + (func)SifRegisterRpc, + (func)SifCheckStatRpc, + (func)SifSetRpcQueue, + (func)SifGetNextRequest, + (func)SifExecRequest, + (func)SifRpcLoop, + (func)SifGetOtherData, + (func)SifRemoveRpc, + (func)SifRemoveRpcQueue, + (func)SifSet1CB, + (func)SifReset1CB, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(){ + register int *v, i; + + _dprintf("%s\n", __FUNCTION__); + if (v=QueryBootMode(3)){ + _dprintf("bootmode: %x\n", v[1]); + if (v[1] & 1){ printf("%s No SIF service(sifcmd)\n", __FUNCTION__);return 1;} + if (v[1] & 2){ printf("%s No SIFCMD/RPC service\n", __FUNCTION__); return 1;} + } + + if (SifCheckInit()==0) + SifInit(); + + if (RegisterLibraryEntries(&sifcmd_stub)) return 1; + + cmd_common.sif1_rcvBuffer=sif1_rcvBuffer; + cmd_common.b=b; + cmd_common.sysCmdBuffer=sysCmds; + cmd_common.sysCmdBufferSize=32; + cmd_common.saddr=0; + cmd_common.cmdBuffer=0; + cmd_common.cmdBufferSize=0; + cmd_common.Sreg=Sreg; + cmd_common.func=0; + cmd_common.param=0; + + for (i=0; i<32; i++) { + sysCmds[i].func=0; + sysCmds[i].data=0; + } + for (i=0; i<32; i++) { + Sreg[i]=0; + } + + sysCmds[0].func=(cmdh_func)cmd80000000_CHANGE_SADDR; + sysCmds[0].data=&cmd_common; + + sysCmds[1].func=(cmdh_func)cmd80000001_SET_SREG; + sysCmds[1].data=&cmd_common; + + cmd_common.systemStatusFlag=GetSystemStatusFlag(); + + sysCmds[2].func=(cmdh_func)cmd80000002_INIT_CMD; + sysCmds[2].data=&cmd_common; + + RegisterIntrHandler(INT_DMA10, 1, SIF1_handler, (void*)&cmd_common); + EnableIntr(INT_DMA10 | IMODE_DMA_IQE); + + SifSetIOPrcvaddr((u32)sif1_rcvBuffer); + + return 0; +} + + + + diff --git a/fps2bios/kernel/iopload/sifman/Makefile b/fps2bios/kernel/iopload/sifman/Makefile new file mode 100644 index 0000000000..8b5f90731c --- /dev/null +++ b/fps2bios/kernel/iopload/sifman/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sifman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sifman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +sifman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sifman/sifman.c b/fps2bios/kernel/iopload/sifman/sifman.c new file mode 100644 index 0000000000..5ff46af2c4 --- /dev/null +++ b/fps2bios/kernel/iopload/sifman/sifman.c @@ -0,0 +1,467 @@ + +#include "kloadcore.h" +#include "kintrman.h" +#include "kdmacman.h" +#include "ksifman.h" + +#define min(a, b) ((a)<(b)?(a):(b)) +#define max(a, b) ((a)>(b)?(a):(b)) + +#define CONFIG_1450 (*(volatile int*)0xBF801450) + +#define BD0 (*(volatile int*)0xBD000000) //mscom +#define BD1 (*(volatile int*)0xBD000010) //smcom +#define BD2 (*(volatile int*)0xBD000020) //msflag +#define BD3 (*(volatile int*)0xBD000030) //smflag +#define BD4 (*(volatile int*)0xBD000040) +#define BD5 (*(volatile int*)0xBD000050) +#define BD6 (*(volatile int*)0xBD000060) +#define BD7 (*(volatile int*)0xBD000070) + + +int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("sifman: " fmt, ## args) + + +struct sifData{ + int data, + words, + count, + addr; +}; + +int sifSIF2Init =0, + sifInit =0; + +struct sm_internal{ + short id, //+000 some id...?!? + res1; //+002 not used + int index; //+004 current position in dma buffer + struct sifData *crtbuf; //+008 address of current used buffer + struct sifData buf1[32]; //+00C first buffer + struct sifData buf2[32]; //+20C second buffer + int (*function)(int);//+40C a function ?!? + int param; //+410 a parameter for function + int res2; //+414 not used +} vars; + +struct sifData one; +int res3, res4; + +int _start(int argc, char* argv); +void RegisterSif0Handler(); + + +/////////////////////////////////////////////////////////////////////// +int getBD2_loopchanging(){ + register int a, b; + a=BD2; + b=BD2; + while (a!=b) { + a=b; + b=BD2; + } + return a; +} + +/////////////////////////////////////////////////////////////////////// +int getBD3_loopchanging(){ + register int a, b; + a=BD3; + b=BD3; + while (a!=b) { + a=b; + b=BD3; + } + return a; +} + +///////////////////////////////////////////////////////////////////////[04] +void SifSIF2Init(){ + if (sifSIF2Init!=0) return; + + DMAch_SIF2_CHCR = 0; //reset ch. 2 + DMAch_DPCR|= 0x800; //enable dma ch. 2 + DMAch_DPCR; + sifSIF2Init =1; +} + +///////////////////////////////////////////////////////////////////////[05] +void SifInit(){ + u32 x, y; + u32 msflag; + + _dprintf("%s: sifInit=%d\n", __FUNCTION__, sifInit); + if (sifInit!=0) return; + + DMAch_DPCR2 |=0x8800; //enable dma ch. 9 and 10 + DMAch_SIF9_CHCR = 0; + DMAch_SIFA_CHCR = 0; + SifSIF2Init(); + + if (CONFIG_1450 & 0x10) + CONFIG_1450 |= 0x10; + CONFIG_1450 |= 0x1; + + RegisterSif0Handler(); + + CpuSuspendIntr(&x); //intrman + CpuEnableIntr(); //intrman + + _dprintf("%s: waiting EE...\n", __FUNCTION__); + do { //EE kernel sif ready + CpuSuspendIntr(&y); //intrman + msflag = getBD2_loopchanging(); + CpuResumeIntr(y); //intrman + } while(!(msflag & 0x10000)); + + _dprintf("%s: EE ready\n", __FUNCTION__); + CpuResumeIntr(x); //intrman + SifSetDChain(); + SifSetIOPrcvaddr(0); //sif1 receive buffer + BD3 = 0x10000; //IOPEE_sifman_init + BD3; + sifInit =1; + _dprintf("%s ok\n", __FUNCTION__); +} + +///////////////////////////////////////////////////////////////////////[02] +void SifDeinit(){ + int x; + + DisableIntr(INT_DMA9, &x); + ReleaseIntrHandler(INT_DMA9); + DMAch_SIF9_CHCR=0; + DMAch_SIFA_CHCR=0; + if (CONFIG_1450 & 0x10) + CONFIG_1450 |= 0x10; +} + +///////////////////////////////////////////////////////////////////////[29] +int SifCheckInit(){ + return sifInit; +} + +///////////////////////////////////////////////////////////////////////[06] +void SifSetDChain(){ + if ((BD4 & 0x40) == 0) BD4=0x40; + DMAch_SIFA_CHCR =0; + DMAch_SIFA_BCR_size =32; + DMAch_SIFA_CHCR =DMAf_08|DMAf_CO|DMAf_TR|DMAf_30;//EE->IOP (to memory) +} + +///////////////////////////////////////////////////////////////////////[30] +void SifSet0CB(int (*_function)(int), int _param){ + vars.function=_function; + vars.param=_param; +} + +///////////////////////////////////////////////////////////////////////[31] +void SifReset0CB(){ + vars.function=NULL; + vars.param=0; +} + +/////////////////////////////////////////////////////////////////////// +int Sif0Handler(void *common) { + struct sm_internal *vars = (struct sm_internal *)common; + int var_10; + if (vars->function) + vars->function(vars->param); + + if ((DMAch_SIF9_CHCR & DMAf_TR == 0) && (vars->index>0)) { + DMAch_SIF9_CHCR =0; + DMAch_SIF9_TADR =(int)vars->crtbuf; + DMAch_SIF9_BCR =32; + if (BD4 & 0x20 == 0) BD4 = 0x20; + vars->id++; + if (vars->crtbuf == vars->buf1){ + vars->index=0; + vars->crtbuf=vars->buf2; + }else + vars->crtbuf=vars->buf1; + DMAch_SIF9_CHCR = DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR;//IOP->EE (from memory) + var_10=DMAch_SIF9_CHCR; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void RegisterSif0Handler(){ + u32 x; + vars.index=0; + vars.crtbuf=vars.buf1; + vars.function=NULL; + vars.param=0; + CpuSuspendIntr(&x); //intrman + RegisterIntrHandler(INT_DMA9, 1, Sif0Handler, &vars); //intrman + EnableIntr(INT_DMA9); //intrman + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +void enqueue(struct sifman_DMA *psd){ + vars.crtbuf[vars.index].data=(u32)psd->data & 0xFFFFFF; //16MB addressability + if (psd->attr & SIF_DMA_INT_I) + vars.crtbuf[vars.index].data |= 0x40000000; + vars.crtbuf[vars.index].words=(psd->size + 3)/4 & 0xFFFFFF; + vars.crtbuf[vars.index].count = ((psd->size + 3)/16 + (((psd->size + 3)/4) & 3)) + | 0x10000000; + if (psd->attr & SIF_DMA_INT_O) + vars.crtbuf[vars.index].count |=0x80000000; + vars.crtbuf[vars.index].addr = (u32)psd->addr & 0x1FFFFFFF; //512MB addresability + vars.index++; +} + +///////////////////////////////////////////////////////////////////////[07] +u32 SifSetDma(struct sifman_DMA *psd, int len){ + int var_20; + register unsigned int ret; + int i; + + if (32-vars.index < len) return 0; //no place + + ret = vars.id; + ret = (ret << 16) | ((vars.index & 0xFF) << 8) | (len & 0xFF); + + if (vars.index) + vars.crtbuf[vars.index-1].data &= 0x7FFFFFFF; + for (i=0; iEE + var_20=DMAch_SIF9_CHCR; //?!? + } + return ret; +} + +///////////////////////////////////////////////////////////////////////[08] +int SifDmaStat(u32 id){ + if (DMAch_SIF9_CHCR & DMAf_TR){ + if (id>>16 == vars.id) return 1; //waiting in queue + if (id>>16+1 == vars.id) return 0; //running + } + return -1; //terminated +} + +///////////////////////////////////////////////////////////////////////[09] +void SifSend(struct sifman_DMA sd){ + sd.size = sd.size /4 + ((sd.size & 3) > 0); + one.data = ((u32)sd.data & 0xFFFFFF) | 0x80000000; + one.words= sd.size & 0xFFFFFF; + if (sd.attr & SIF_DMA_INT_I) one.data |= 0x40000000; + one.count = (sd.size/4 + ((sd.size & 3)>0)) | 0x10000000; + if (sd.attr & SIF_DMA_INT_O) one.count|= 0x80000000; + one.addr = (u32)sd.addr & 0xFFFFFFF; + + if (BD4 & 0x20 == 0) BD4=0x20; + + DMAch_SIF9_CHCR=0; + DMAch_SIF9_TADR=(u32)&one; + DMAch_SIF9_BCR_size=32; + DMAch_SIF9_CHCR=DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR; //IOP->EE + DMAch_SIF9_CHCR; +} + +///////////////////////////////////////////////////////////////////////[10] +void SifSendSync(){ + while (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[11] +int SifIsSending(){ + return (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[12] +void SifSetSIF0DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x20 == 0) BD4=0x20; + + DMAch_SIF9_CHCR=0; + DMAch_SIF9_MADR=(u32)data & 0xFFFFFF; + DMAch_SIF9_BCR_size=32; + DMAch_SIF9_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIF9_CHCR=DMAf_DR|DMAf_CO|DMAf_TR; + DMAch_SIF9_CHCR; +} + +///////////////////////////////////////////////////////////////////////[13] +void SifSendSync0(){ + while (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[14] +int SifIsSending0(){ + return (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[15] +void SifSetSIF1DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x40 == 0) BD4=0x40; + + DMAch_SIFA_CHCR=0; + DMAch_SIFA_MADR=(u32)data & 0xFFFFFF; + DMAch_SIFA_BCR_size=32; + DMAch_SIFA_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIFA_CHCR=DMAf_CO|DMAf_TR| + (attr & SIF_DMA_BSN?DMAf_30:0); + DMAch_SIFA_CHCR; +} + +///////////////////////////////////////////////////////////////////////[16] +void SifSendSync1(){ + while (DMAch_SIFA_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[17] +int SifIsSending1(){ + return (DMAch_SIFA_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[18] +void SifSetSIF2DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x80 == 0) BD4=0x80; + + DMAch_SIF2_CHCR=0; + DMAch_SIF2_MADR=(u32)data & 0xFFFFFF; + DMAch_SIF2_BCR_size=min(size, 32); + DMAch_SIF2_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIF2_CHCR=DMAf_CO |DMAf_TR| + ((attr & SIF_TO_EE ?DMAf_DR: + (attr & SIF_DMA_BSN?DMAf_30:0))); + DMAch_SIF2_CHCR; +} + +///////////////////////////////////////////////////////////////////////[19] +void SifSendSync2(){ + while (DMAch_SIF2_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[20] +int SifIsSending2(){ + return (DMAch_SIF2_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[21] +int SifGetEEIOPflags(){ + return getBD2_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[22] +int SifSetEEIOPflags(int val){ + BD2=val; + return getBD2_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[23] +int SifGetIOPEEflags(){ + return getBD3_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[24] +int SifSetIOPEEflags(int val){ + BD3=val; + return getBD3_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[25] +int SifGetEErcvaddr(){ + return BD0; +} + +///////////////////////////////////////////////////////////////////////[26] +int SifGetIOPrcvaddr(){ + return BD1; +} + +///////////////////////////////////////////////////////////////////////[27] +int SifSetIOPrcvaddr(int val){ + BD1=val; + return BD1; +} + +///////////////////////////////////////////////////////////////////////[28] +void SifSet1450_2(){ + CONFIG_1450 |= 2; + CONFIG_1450 &= ~2; + CONFIG_1450; +} + +///////////////////////////////////////////////////////////////////////[01,03,32,33,34,35] +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export sifman_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sifman", + (func)_start, // entrypoint + (func)_retonly, + (func)SifDeinit, + (func)_retonly, + (func)SifSIF2Init, + (func)SifInit, + (func)SifSetDChain, + (func)SifSetDma, + (func)SifDmaStat, + (func)SifSend, + (func)SifSendSync, + (func)SifIsSending, + (func)SifSetSIF0DMA, + (func)SifSendSync0, + (func)SifIsSending0, + (func)SifSetSIF1DMA, + (func)SifSendSync1, + (func)SifIsSending1, + (func)SifSetSIF2DMA, + (func)SifSendSync2, + (func)SifIsSending2, + (func)SifGetEEIOPflags, + (func)SifSetEEIOPflags, + (func)SifGetIOPEEflags, + (func)SifSetIOPEEflags, + (func)SifGetEErcvaddr, + (func)SifGetIOPrcvaddr, + (func)SifSetIOPrcvaddr, + (func)SifSet1450_2, + (func)SifCheckInit, + (func)SifSet0CB, + (func)SifReset0CB, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(int argc, char* argv){ + + return RegisterLibraryEntries(&sifman_stub) > 0; + +} + diff --git a/fps2bios/kernel/iopload/sio2man/Makefile b/fps2bios/kernel/iopload/sio2man/Makefile new file mode 100644 index 0000000000..593c41abc3 --- /dev/null +++ b/fps2bios/kernel/iopload/sio2man/Makefile @@ -0,0 +1,63 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sio2man + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sio2man.o ../iopdebug.o \ + ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o \ + ../libkernel/iop_dmacman.o ../libkernel/iop_thbase.o \ + ../libkernel/iop_thevent.o ../libkernel/iop_stdio.o \ + ../libkernel/iop_sysclib.o + +sio2man: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIO2MAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sio2man/sio2man.c b/fps2bios/kernel/iopload/sio2man/sio2man.c new file mode 100644 index 0000000000..11a5220dbc --- /dev/null +++ b/fps2bios/kernel/iopload/sio2man/sio2man.c @@ -0,0 +1,508 @@ +//[module] SIO2MAN +//[processor] IOP +//[type] ELF-IRX +//[size] ?(0x?) +//[bios] ?(0x?-0x?) +//[iopboot2] 21 +//[loaded @] ? +//[name] sio2man +//[version] 0x101 +//[memory map] 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, +// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, 16 entries +// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, array +// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, +// 0xBF808240,0xBF808244,0xBF808248,0xBF80824C, +// 0xBF808250,0xBF808254,0xBF808258,0xBF80825C, +// 0xBF808260, 0xBF808268,0xBF80826C, +// 0xBF808270,0xBF808274,0xBF808278,0xBF80827C, +// 0xBF808280 +//[handlers] - +//[entry point] _start, (export_stub) +//[made by] Herben + +#include +#include + +#include "kdmacman.h" +#include "kloadcore.h" +#include "kintrman.h" +#include +#include + +struct sio2_packet { + u32 recvVal1; // 0x00 + u32 sendArray1[4]; // 0x04-0x10 + u32 sendArray2[4]; // 0x14-0x20 + + u32 recvVal2; // 0x24 + + u32 sendArray3[16]; // 0x28-0x64 + + u32 recvVal3; // 0x68 + + int sendSize; // 0x6C + int recvSize; // 0x70 + + u8 *sendBuf; // 0x74 + u8 *recvBuf; // 0x78 + + u32 dmacAddress1; + u32 dmacSize1; + u32 dmacCount1; + u32 dmacAddress2; + u32 dmacSize2; + u32 dmacCount2; +}; + +struct sio2common { + int evid; + int thid; +}; + +struct sio2common common; +int sio2_initialized = 0; +struct sio2_packet *packetAddr; +int debug = 1; + +#define _dprintf(fmt, args...) if (debug > 0) printf(fmt, ## args) + +// if (debug > 0) printf("\033[0;32m" "sio2man: " "\033[0m" fmt, ## args) + +int _start(void); +void nullSub(void); +int sio2_init(void); +void sio2_deInit(void); +void sio2_setCtrl(u32 arg0); +u32 sio2_getCtrl(void); +u32 sio2_getRecv1(void); +void sio2_setSend1(int entryNum, u32 val); +u32 sio2_getSend1(int entryNum); +void sio2_setSend2(int entryNum, u32 val); +u32 sio2_getSend2(int entryNum); +u32 sio2_getRecv2(void); +void sio2_setSend3(int entryNum, u32 val); +u32 sio2_getSend3(int entryNum); +u32 sio2_getRecv3(void); +void sio2_set8278(u32 arg0); +u32 sio2_get8278(void); +void sio2_set827C(u32 arg0); +u32 sio2_get827C(void); +void sio2_datain(u8 arg0); +u8 sio2_dataout(void); +void sio2_setIntr(u32 arg0); +u32 sio2_getIntr(void); +void sio2_signalExchange1(void); +void sio2_signalExchange2(void); +int sio2_packetExchange(struct sio2_packet *packet); + +struct export sio2man_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "sio2man", + (func)_start, // 0 + (func)nullSub, + (func)sio2_deInit, + (func)nullSub, + (func)sio2_setCtrl, // 4 + (func)sio2_getCtrl, + (func)sio2_getRecv1, + (func)sio2_setSend1, + (func)sio2_getSend1, // 8 + (func)sio2_setSend2, + (func)sio2_getSend2, + (func)sio2_getRecv2, + (func)sio2_setSend3, // 12 + (func)sio2_getSend3, + (func)sio2_getRecv3, + (func)sio2_set8278, + (func)sio2_get8278, // 16 + (func)sio2_set827C, + (func)sio2_get827C, + (func)sio2_datain, + (func)sio2_dataout, // 20 + (func)sio2_setIntr, + (func)sio2_getIntr, + (func)sio2_signalExchange1, + (func)sio2_signalExchange2, // 24 + (func)sio2_packetExchange, + 0 +}; + +#define INUM_sio2 17 +#define HTYPE_C 1 + + +int _start(void) { + return sio2_init(); +} + +void nullSub(void) { return; } + +void sio2_setCtrl(u32 arg0) { + *(u32 *) (0xBF808268) = arg0; +} + +u32 sio2_getCtrl(void) { + return(*(u32 *) (0xBF808268)); +} + +u32 sio2_getRecv1(void) { + return(*(u32 *) (0xBF80826C)); +} + +void sio2_setSend1(int entryNum, u32 val) { + switch(entryNum) { + case 0: + *(u32 *) (0xBF808240) = val; + break; + case 1: + *(u32 *) (0xBF808248) = val; + break; + case 2: + *(u32 *) (0xBF808250) = val; + break; + case 3: + *(u32 *) (0xBF808258) = val; + break; + } +} + +u32 sio2_getSend1(int entryNum) { + switch(entryNum) { + case 0: + return(*(u32 *) (0xBF808240)); + case 1: + return(*(u32 *) (0xBF808248)); + case 2: + return(*(u32 *) (0xBF808250)); + case 3: + return(*(u32 *) (0xBF808258)); + } + + return(0); +} + +void sio2_setSend2(int entryNum, u32 val) { + switch(entryNum) { + case 0: + *(u32 *) (0xBF808244) = val; + break; + case 1: + *(u32 *) (0xBF80824C) = val; + break; + case 2: + *(u32 *) (0xBF808254) = val; + break; + case 3: + *(u32 *) (0xBF80825C) = val; + break; + } +} + +u32 sio2_getSend2(int entryNum) { + switch(entryNum) { + case 0: + return(*(u32 *) (0xBF808244)); + case 1: + return(*(u32 *) (0xBF80824C)); + case 2: + return(*(u32 *) (0xBF808254)); + case 3: + return(*(u32 *) (0xBF80825C)); + } + + return(0); +} + +u32 sio2_getRecv2(void) { + return(*(u32 *) (0xBF808270)); +} + +void sio2_setSend3(int entryNum, u32 val) { + if(entryNum < 16) + *(u32 *) (0xBF808200 + (entryNum * 4)) = val; +} + +u32 sio2_getSend3(int entryNum) { + if(entryNum < 16) + return(*(u32 *) (0xBF808200 + (entryNum * 4))); + + return(-1); +} + +u32 sio2_getRecv3(void) { + return(*(u32 *) (0xBF808274)); +} + +void sio2_set8278(u32 arg0) { + *(u32 *) (0xBF808278) = arg0; +} + +u32 sio2_get8278(void) { + return(*(u32 *) (0xBF808278)); +} + +void sio2_set827C(u32 arg0) { + *(u32 *) (0xBF80827C) = arg0; +} + +u32 sio2_get827C(void) { + return(*(u32 *) (0xBF80827C)); +} + +void sio2_datain(u8 arg0) { + *(u8 *) (0xBF808260) = arg0; +} + +u8 sio2_dataout(void) { + return(*(u8 *) (0xBF808264)); +} + +void sio2_setIntr(u32 arg0) { + *(u32 *) (0xBF808280) = arg0; +} + +u32 sio2_getIntr(void) { + return(*(u32 *) (0xBF808280)); +} + +int sio2_createEventFlag(void) { + iop_event_t param; + + param.attr = 2; + param.option = 0; + param.bits = 0; + return(CreateEventFlag(¶m)); +} + +void dumpbuf(u8 *buf, int size) { +/* char str[1024]; + char tmp[256]; + int i; + + str[0] = 0; + for(i = 0; i < size; i++) { + sprintf(tmp, "%x, ", buf[i]); + strcat(str, tmp); + } + printf("%s\n", str); + */ +} + +void sio2_sendPacket(struct sio2_packet *p) { + int i; + +// _dprintf("%s: sendSize=%d\n", __FUNCTION__, p->sendSize); + + for(i = 0; i < 4; i++) { + sio2_setSend1(i, p->sendArray1[i]); + sio2_setSend2(i, p->sendArray2[i]); + } + + for(i = 0; i < 16; i++) + sio2_setSend3(i, p->sendArray3[i]); + + if (p->sendSize) { + _dprintf("sendBuf: "); + dumpbuf(p->sendBuf, p->sendSize); + + for(i = 0; i < p->sendSize; i++) { + *(u8 *) (0xBF808260) = p->sendBuf[i]; + } + } + + if(p->dmacAddress1 != 0) { + _dprintf("dmaAddress1=%x, dmacSize1=%x, dmacCount1=%x\n", p->dmacAddress1, p->dmacSize1, p->dmacCount1); + dumpbuf((u8*)p->dmacAddress1, p->dmacSize1*p->dmacCount1); + dmacSetDMA(DMAch_SIO2in, p->dmacAddress1, p->dmacSize1, p->dmacCount1, 1); // from memory + dmacStartTransfer(DMAch_SIO2in); + } + + if(p->dmacAddress2 != 0) { + dmacSetDMA(DMAch_SIO2out, p->dmacAddress2, p->dmacSize2, p->dmacCount2, 0); // to memory + dmacStartTransfer(DMAch_SIO2out); + } +} + +void sio2_recvPacket(struct sio2_packet *p) { + int i; + +// _dprintf("%s: recvSize=%d\n", __FUNCTION__, p->recvSize); + + p->recvVal1 = *(u32 *) (0xBF80826C); + p->recvVal2 = *(u32 *) (0xBF808270); + p->recvVal3 = *(u32 *) (0xBF808274); + + if (p->recvSize) { + _dprintf("recvBuf: "); + for(i = 0; i < p->recvSize; i++) { + p->recvBuf[i] = *(u8 *) (0xBF808264); + printf("%x, ", p->recvBuf[i]); + } + // printf("\n"); + } + + if (p->dmacAddress2 != 0) { + dumpbuf((u8*)p->dmacAddress2, p->dmacSize2*p->dmacCount2); + } +} + +void sio2_basicThread(void* data) { + unsigned long result[4]; + + //_dprintf("%s\n", __FUNCTION__); + + while(1) { + WaitEventFlag(common.evid, 0x5, 0x01, result); + + if (result[0] & 0x01) { + ClearEventFlag(common.evid, ~0x1); + SetEventFlag(common.evid, 0x02); + } else + if (result[0] & 0x04) { + ClearEventFlag(common.evid, ~0x4); + SetEventFlag(common.evid, 0x08); + } else { + printf("sio2MAN: Woke up for unknown event(%08X)!\n", result[0]); + return; + } + +// Wait for application to call our export 25 + WaitEventFlag(common.evid, 0x10, 0, NULL); + ClearEventFlag(common.evid, ~0x10); + + *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x0C; + sio2_sendPacket(packetAddr); + *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x01; + +// Wait for the sio2 interrupt to occur + WaitEventFlag(common.evid, 0x80, 0, NULL); + ClearEventFlag(common.evid, ~0x80); + +// Recieve the reply packet + sio2_recvPacket(packetAddr); + + SetEventFlag(common.evid, 0x20); + + WaitEventFlag(common.evid, 0x40, 0, NULL); + ClearEventFlag(common.evid, ~0x40); + } +} + +int sio2_createBasicThread(void) { + iop_thread_t param; + + param.attr = TH_C; + param.option = 0; + param.thread = &sio2_basicThread; + param.stacksize = 0x2000; + param.priority = 0x18; + + return(CreateThread(¶m)); +} + + +int sio2_interruptHandler(struct sio2common *c) { + sio2_setIntr(sio2_getIntr()); + + iSetEventFlag(c->evid, 0x80); + + return(1); +} + +// Export 0 +int sio2_init(void) { + u32 oldStat; + +// _dprintf("%s\n", __FUNCTION__); + + if(RegisterLibraryEntries(&sio2man_stub) != 0) { + //printf("sio2MAN: Unable to register library entries!\n"); + return(MODULE_NO_RESIDENT_END);//==1 + } + + if(sio2_initialized != 0) { + //printf("sio2MAN: Already initialized!\n"); + return(MODULE_NO_RESIDENT_END); + } + + sio2_initialized = 1; + + *(u32 *) (0xBF808268) = 0x3BC; + + common.evid = sio2_createEventFlag(); + common.thid = sio2_createBasicThread(); + + CpuSuspendIntr(&oldStat); + + RegisterIntrHandler(INUM_sio2, HTYPE_C, &sio2_interruptHandler, &common); + EnableIntr(INUM_sio2); + + CpuResumeIntr(oldStat); + + dmacSetVal(DMAch_SIO2in, 0x03); + dmacSetVal(DMAch_SIO2out, 0x03); + dmacEnableDMAch(DMAch_SIO2in); + dmacEnableDMAch(DMAch_SIO2out); + + StartThread(common.thid, 0); // Start the "basicThread" + + return MODULE_RESIDENT_END; +} + +void sio2_deInit(void) { + u32 oldStat; + +// _dprintf("%s\n", __FUNCTION__); + + CpuSuspendIntr(&oldStat); + + DisableIntr(INUM_sio2, 0); + ReleaseIntrHandler(INUM_sio2); + + CpuResumeIntr(oldStat); + + dmacDisableDMAch(DMAch_SIO2in); + dmacDisableDMAch(DMAch_SIO2out); +} + +void sio2_signalExchange1(void) { +// _dprintf("%s\n", __FUNCTION__); + +// Signal the basic thread to let it know we want to do an exchange. + SetEventFlag(common.evid, 0x01); +// Wait for basic thread to acknowledge then clear the flag. + WaitEventFlag(common.evid, 0x02, 0, NULL); + ClearEventFlag(common.evid, ~0x2); +} + +void sio2_signalExchange2(void) { +// _dprintf("%s\n", __FUNCTION__); + +// Signal the basic thread to let it know we want to do an exchange. + SetEventFlag(common.evid, 0x04); +// Wait for basic thread to acknowledge then clear the flag. + WaitEventFlag(common.evid, 0x08, 0, NULL); + ClearEventFlag(common.evid, ~0x8); +} + +int sio2_packetExchange(struct sio2_packet *packet) { +// _dprintf("%s: %x\n", __FUNCTION__, packet); + +// Set the address of the packet. + packetAddr = packet; + +// Let the basic thread know we have the address set for the exchange. + SetEventFlag(common.evid, 0x10); + +// Wait for the basic thread to finish it's stuff. + WaitEventFlag(common.evid, 0x20, 0, NULL); + ClearEventFlag(common.evid, ~0x20); + + SetEventFlag(common.evid, 0x40); + + return 1; +} + diff --git a/fps2bios/kernel/iopload/ssbusc/Makefile b/fps2bios/kernel/iopload/ssbusc/Makefile new file mode 100644 index 0000000000..831351ae84 --- /dev/null +++ b/fps2bios/kernel/iopload/ssbusc/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: ssbusc + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = ssbusc.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +ssbusc: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SSBUSC + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/ssbusc/ssbusc.c b/fps2bios/kernel/iopload/ssbusc/ssbusc.c new file mode 100644 index 0000000000..98ebfd0f5f --- /dev/null +++ b/fps2bios/kernel/iopload/ssbusc/ssbusc.c @@ -0,0 +1,178 @@ +//[module] SSBUSC +//[processor] IOP +//[type] ELF-IRX +//[name] ssbus_service +//[version] 0x101 +//[memory map] 0xBF801000,0xBF801004,0xBF801008,0xBF80100C, (r/w) +// MDECin(T2),8(T2) ,MDECin(T1),MDECout(T1), +// +// 0xBF801010,0xBF801014,0xBF801018,0xBF80101C,0xBF801020 (r/w) +// GPU(SIF2)(T1),SPU(T1)spu_delay,PIO(T1),8(T1),SSBUSCconfig +// +// 0xBF801400,0xBF801404,0xBF801408,0xBF80140C, (r/w) +// MDECout(T2),SPU(T2) ,PIO(T2) ,SIF0(T2), +// +// 0xBF801410,0xBF801414,0xBF801418,0xBF80141C,0xBF801420 (r/w) +// SIO2in(T2),SIF0(T1) ,SIF1(T1) ,SIO2in(T1),SIO2out(T1) +// +//[handlers] - +//[entry point] start, export_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include "kloadcore.h" +#include "kintrman.h" + +int memmap_table[]={ + 0xBF801008, 0xBF80100C, 0xBF801010, 0, 0xBF801014,//spu_delay + 0xBF801018, 0, 0, 0xBF80101C, 0xBF801414, + 0xBF801418, 0xBF80141C, 0xBF801420 +}; + +int memmap_table_2[]={ + 0xBF801000, 0xBF801400, 0, 0, 0xBF801404, + 0xBF801408, 0, 0, 0xBF801004, 0xBF80140C, + 0, 0xBF801410, 0 +}; + +int _start(); + +/////////////////////////////////////////////////////////////////////// +int return_0(){ + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetTable1(int code, int value){ //set + int *v; + if ((code < 13) && (v=(int*)memmap_table[code])) + return *v=value; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetTable1(int code){ //get + int *v; + if ((code < 13) && (v=(int*)memmap_table[code])) + return *v; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetTable2(int code, int value){ //set + int *v; + if ((code < 13) && (v=(int*)memmap_table_2[code])) + return *v=value; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetTable2(int code){ //get + int *v; + if ((code < 13) && (v=(int*)memmap_table_2[code])) + return *v; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_1st(int a){ //set lowest nibble + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFFFF0) | + ( a & 0xF); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_1st(){ //get lowest nibble + return *(int*)(0xBF801020) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_2nd(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFFF0F) | + ( (a << 4) & 0xF0); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_2nd(){ //get + return *(unsigned char*)(0xBF801020) >> 4; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_3rd(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFF0FF) | + ( (a << 8) & 0xF00); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_3rd(){ //get + return (*(int*)(0xBF801020) >> 8) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_4th(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFF0FFF) | + ( (a << 12) & 0xF000); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_4th(){ //get + return (*(int*)(0xBF801020) >> 12) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY(int a){ //set + return *(int*)(0xBF801020) = a; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY(){ //get + return *(int*)(0xBF801020); +} + +/////////////////////////////////////////////////////////////////////// +void retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export export_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "ssbusc", + (func)_start, // entrypoint + (func)retonly, + (func)return_0, + (func)retonly, + (func)SSBUSsetTable1, + (func)SSBUSgetTable1, + (func)SSBUSsetTable2, + (func)SSBUSgetTable2, + (func)SSBUSsetCOM_DELAY_1st, + (func)SSBUSgetCOM_DELAY_1st, + (func)SSBUSsetCOM_DELAY_2nd, + (func)SSBUSgetCOM_DELAY_2nd, + (func)SSBUSsetCOM_DELAY_3rd, + (func)SSBUSgetCOM_DELAY_3rd, + (func)SSBUSsetCOM_DELAY_4th, + (func)SSBUSgetCOM_DELAY_4th, + (func)SSBUSsetCOM_DELAY, + (func)SSBUSgetCOM_DELAY, + 0 // end of list +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int x; + + CpuSuspendIntr(&x); + if (RegisterLibraryEntries(&export_stub)==0) { + CpuResumeIntr(x); + return 0; + } + + CpuResumeIntr(x); + return 1; +} + diff --git a/fps2bios/kernel/iopload/stdio/Makefile b/fps2bios/kernel/iopload/stdio/Makefile new file mode 100644 index 0000000000..d457ca18af --- /dev/null +++ b/fps2bios/kernel/iopload/stdio/Makefile @@ -0,0 +1,58 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(NEWLIB)/include #-I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: stdio + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = stdio.o + +stdio: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/STDIO + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/stdio/stdio.c b/fps2bios/kernel/iopload/stdio/stdio.c new file mode 100644 index 0000000000..dcbc7a9f20 --- /dev/null +++ b/fps2bios/kernel/iopload/stdio/stdio.c @@ -0,0 +1,40 @@ + +#include +//#include + +void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} +/* +int Kprintf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + Kputs(buf); + return ret; +} +*/ +void _start() { + Kputs("STDIO start\n"); +} + diff --git a/fps2bios/kernel/iopload/sysclib/Makefile b/fps2bios/kernel/iopload/sysclib/Makefile new file mode 100644 index 0000000000..2b9a33b90a --- /dev/null +++ b/fps2bios/kernel/iopload/sysclib/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sysclib + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = sysclib.o ../iopdebug.o ../libkernel/iop_loadcore.o + +sysclib: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSCLIB + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sysclib/sysclib.c b/fps2bios/kernel/iopload/sysclib/sysclib.c new file mode 100644 index 0000000000..75df9819df --- /dev/null +++ b/fps2bios/kernel/iopload/sysclib/sysclib.c @@ -0,0 +1,583 @@ +#include +#include +#include +#include + +#include "kloadcore.h" +#include "stdarg.h" +#include "ksysclib.h" + + +typedef struct _jmp_buf{ + int ra, + sp, + fp, + s0, + s1, + s2, + s3, + s4, + s5, + s6, + s7, + gp; +} *jmp_buf; + +int _start(int argc, char* argv[]); + + +unsigned char ctype_table[128]={ + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + + 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x20 +}; + +int setjmp (jmp_buf jb){ + asm __volatile__( + "sw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) + "sw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) + "sw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) + "sw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) + "sw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) + "sw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) + "sw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) + "sw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) + "sw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) + "sw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) + "sw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) + "sw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) + ); + return 0; +} + +int longjmp(void *jb, int u){ + asm __volatile__( + "lw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) + "lw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) + "lw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) + "lw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) + "lw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) + "lw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) + "lw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) + "lw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) + "lw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) + "lw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) + "lw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) + "lw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) + ); + return u; +} + +#define CHAR(a) (((a)<<24)>>24) +unsigned char look_ctype_table(int); + +int toupper (int ch){ + if (look_ctype_table(CHAR(ch)) & 0x0002) + return CHAR(ch-32); + return CHAR(ch); +} + +int tolower (int ch){ + if (look_ctype_table(CHAR(ch)) & 0x0001) + return CHAR(ch+32); + return CHAR(ch); +} + +unsigned char look_ctype_table(int pos){ + return ctype_table[pos]; +} + +void* get_ctype_table(){ + return ctype_table; +} + +void* memchr(void *s, int ch, int len){ + if (s && len>0) { + ch &= 0xFF; + do { + if (*(unsigned char*)s == ch) + return s; + } while(s++, --len>0); + + } + return NULL; +} + +int memcmp(const void *a, const void *b, size_t len){ + if (len == 0) return 0; + + do { + if (*(unsigned char*)a != *(unsigned char*)b) { + if (*(unsigned char*)a < *(unsigned char*)b) return 1; + else return -1; + } + } while (a++, b++, --len>0); + + return 0; +} + +void* memcpy(void *dest, const void *src, size_t len){ + void *temp; + + if (dest == NULL) return NULL; + +// if (((int)dest | (int)src | len) & 3 == 0) +// return wmemcopy(dest, src, len); + for(temp=dest; len>0; len--) + *(unsigned char*)temp++ = *(unsigned char*)src++; + return dest; +} + +void *memmove (void *dest, const void *src, size_t len){ + void *temp; + + if (dest==NULL) return NULL; + + temp=dest; + if (dest>=src) + for (len--; len>=0; len--) + *(unsigned char*)(temp+len)=*(unsigned char*)(src+len); + else + for ( ; len>0; len--) + *(unsigned char*)temp++ =*(unsigned char*)src++; + return dest; +} + +void *memset (void *dest, int ch, size_t len){ + void *temp; + + if (dest == NULL) return NULL; + +/* if ((ch==0) && (((int)dest | len) & 3 == 0)) + return wmemset(dest, 0, len); + else +*/ for (temp=dest; len>0; len--) + *(unsigned char*)temp++ = ch; + return dest; +} + +int bcmp (const void *a, const void *b, size_t len){ + return memcmp(a, b, len); +} + +void bcopy (const void *src, void *dest, size_t len){ + memmove(dest, src, len); +} + +void bzero (void *dest, size_t len){ + memset(dest, 0, len); +} + +char *strcat(char *dest, const char *src) { + char *s = dest; + + while (*dest) dest++; + while (*dest++ = *src++); + + return s; +} + +char *strncat(char *dest, const char *src, size_t n) { + char *s = dest; + + while (*dest) dest++; + while (n-- > 0 && (*dest++ = *src++)); + *dest = '\0'; + + return s; +} + +char *strchr(const char *s, int c) { + unsigned char _c = (unsigned int)c; + + while (*s && *s != c) s++; + if (*s != c) s = NULL; + + return (char *)s; +} + +char *strrchr(const char *s, int c) { + const char *last = NULL; + + if (c) { + while (s = strchr(s, c)) { + last = s++; + } + } else { + last = strchr(s, c); + } + + return (char *)last; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 != '\0' && *s1 == *s2) { + s1++; s2++; + } + + return (*(unsigned char *)s1) - (*(unsigned char *)s2); +} + +int strncmp(const char *s1, const char *s2, size_t n) { + if (n == 0) return 0; + + while (n-- != 0 && *s1 == *s2) { + if (n == 0 || *s1 == '\0') break; + s1++; s2++; + } + + return (*(unsigned char *)s1) - (*(unsigned char *)s2); +} + +char *strcpy(char *dest, const char *src) { + char *s = dest; + + while (*dest++ = *src++); + + return s; +} + +char *strncpy(char *dest, const char *src, size_t n) { + char *s = dest; + + while (*dest++ = *src++); + + return s; +} + +size_t strspn(const char *s, const char *accept) { + const char *_s = s; + const char *c; + + while (*s) { + for (c = accept; *c; c++) { + if (*s == *c) break; + } + if (*c == '\0') break; + s++; + } + + return s - _s; +} + +size_t strcspn(const char *s, const char *reject) { + const char *_s = s; + const char *c; + + while (*s) { + for (c = reject; *c; c++) { + if (*s == *c) break; + } + if (*c) break; + s++; + } + + return s - _s; +} + +char *index(const char *s, int c) { + return strchr(s, c); +} + +char *rindex(const char *s, int c) { + return strrchr(s, c); +} + +size_t strlen(const char *s) { + const char *start = s; + + while (*s) s++; + + return s - start; +} + +char *strpbrk(const char *s, const char *accept) { + const char *c = accept; + + if (!*s) return NULL; + + while (*s) { + for (c = accept; *c; c++) { + if (*s == *c) break; + } + if (*c) break; + s++; + } + + if (*c == '\0') s = NULL; + + return (char *)s; +} + +char *strstr(const char *haystack, const char *needle) { + if (*haystack == 0) { + if (*needle) return (char *) NULL; + return (char *) haystack; + } + + while (*haystack) { + size_t i; + i = 0; + + for (;;) { + if (needle[i] == 0) { + return (char *) haystack; + } + + if (needle[i] != haystack[i]) break; + i++; + } + haystack++; + } + + return (char *) NULL; +} + +#define _CTYPE_DATA_0_127 \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _S|_B, _P, _P, _P, _P, _P, _P, _P, \ + _P, _P, _P, _P, _P, _P, _P, _P, \ + _N, _N, _N, _N, _N, _N, _N, _N, \ + _N, _N, _P, _P, _P, _P, _P, _P, \ + _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, \ + _U, _U, _U, _U, _U, _U, _U, _U, \ + _U, _U, _U, _U, _U, _U, _U, _U, \ + _U, _U, _U, _P, _P, _P, _P, _P, \ + _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, \ + _L, _L, _L, _L, _L, _L, _L, _L, \ + _L, _L, _L, _L, _L, _L, _L, _L, \ + _L, _L, _L, _P, _P, _P, _P, _C + +#define _CTYPE_DATA_128_256 \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0 + + +const char _ctype_[1 + 256] = { + 0, + _CTYPE_DATA_0_127, + _CTYPE_DATA_128_256 +}; + +char *strtok(char *s, const char *delim) { +} + +long _strtol_r(const char *nptr, char **endptr, int base) { + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; +// rptr->_errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +long int strtol(const char *nptr, char **endptr, int base) { + return _strtol_r (nptr, endptr, base); +} + +unsigned long int strtoul(const char *nptr, char **endptr, int base) { +} + +void atob() { +} + +wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n) { +} + +wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) { +} + +void prnt() { +} + +int sprintf(char *str, const char *format, ...) { +} + +int vsprintf(char *str, const char *format, va_list ap) { +} + + + + +/////////////////////////////////////////////////////////////////////// +void _retonly(){} + +struct export sysclib_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sysclib", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)setjmp, + (func)longjmp, + (func)toupper, + (func)tolower, + (func)look_ctype_table, + (func)get_ctype_table, + (func)memchr, + (func)memcmp, + (func)memcpy, + (func)memmove, + (func)memset, + (func)bcmp, + (func)bcopy, + (func)bzero, + (func)prnt, + (func)sprintf, + (func)strcat, + (func)strchr, + (func)strcmp, + (func)strcpy, + (func)strcspn, + (func)index, + (func)rindex, + (func)strlen, + (func)strncat, + (func)strncmp, + (func)strncpy, + (func)strpbrk, + (func)strrchr, + (func)strspn, + (func)strstr, + (func)strtok, + (func)strtol, + (func)atob, + (func)strtoul, + (func)wmemcpy, + (func)wmemset, + (func)vsprintf, + 0 +}; + +struct export stdio_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "stdio", + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int ret = RegisterLibraryEntries(&sysclib_stub); + return RegisterLibraryEntries(&stdio_stub) + ret; +} + diff --git a/fps2bios/kernel/iopload/sysmem/Makefile b/fps2bios/kernel/iopload/sysmem/Makefile new file mode 100644 index 0000000000..03e3dd2b45 --- /dev/null +++ b/fps2bios/kernel/iopload/sysmem/Makefile @@ -0,0 +1,57 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sysmem + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = sysmem.o + +sysmem: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSMEM + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/sysmem/sysmem.c b/fps2bios/kernel/iopload/sysmem/sysmem.c new file mode 100644 index 0000000000..0aca682d45 --- /dev/null +++ b/fps2bios/kernel/iopload/sysmem/sysmem.c @@ -0,0 +1,529 @@ +//[module] SYSMEM +//[processor] IOP +//[type] ELF-IRX +//[name] System_Memory_Manager +//[version] 0x101 +//[memory map] 0x00001500(0x000015C3) in RAM +//[handlers] see fileio/80000003 +//[entry point] sysmem_start, sysmem_stub(it is handeled specialy by loadcore) +//[made by] [RO]man (roman_ps2dev@hotmail.com) september 2002 + +#define min(a, b) ((a)<(b)?(a):(b)) +#define max(a, b) ((a)>(b)?(a):(b)) + +#include + +#include "ksysmem.h" +#include "kloadcore.h" +#include "iopdebug.h" + +#define EIGHTMEGSm256 (8*1024*1024-256) //0x007FFF00 +#define ALIGN256 0xFFFFFF00 + +#define mALLOCATED(info) (info & 1) +#define mADDRESS(info) ((info >> 1) & 0x7FFF) +#define mSIZE(info) (info >> 17) +//[000000000000000 0 000000000000000 1] +//[ size of block |?|address of block|a]located +//upper 15bits are the size of block in 256bytes units [8MB addressability] +//unknown 1 bit +//15bits for address of block in 256bytes units [8MB addressability; 15+8 bits] +//the lower bit means that block is allocated or not (1/0) + +struct allocELEM{ //sizeof()=8 + struct allocELEM *next; +/* unsigned int size :15, + unknown :1, // info could be declared this way + addr :15, + allocated:1; */ + unsigned int info; // here is stored data about + // an allocable memory chunk +}; + +#define smFIRST 0 +#define smFIRSTF 2 //first one that can be freed +#define smCHECK 27 +#define smLAST 30 +#define smMAX (smLAST+1) //max number of elements = 31 + +struct allocTABLE{ //sizeof()=256=0x100 + struct allocTABLE *next; //+00 + struct allocELEM list[31]; //+04 8 * 31 = 248 = 0xF8; + int dummy; +}; + +char* (*_Kprintf)(unsigned int, ...); +unsigned int unk; + +/////////////////////////////////////////////////////////////////////// +unsigned int memsize; + +void *_start(u32 iopmemsize); +void *sysmem_init_memory(); +void sysmem_retonly(); +unsigned int *sysmem_return_addr_of_memsize(); + +//////////////////////////////entrypoint/////////////////////////////// +struct export sysmem_stub __attribute__((section(".text"))) = { + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sysmem", + (func)_start, // entrypoint + (func)sysmem_init_memory, + (func)sysmem_retonly, + (func)sysmem_return_addr_of_memsize, + (func)AllocSysMemory, + (func)FreeSysMemory, + (func)QueryMemSize, + (func)QueryMaxFreeMemSize, + (func)QueryTotalFreeMemSize, + (func)QueryBlockTopAddress, + (func)QueryBlockSize, + (func)sysmem_retonly, + (func)sysmem_retonly, + (func)sysmem_retonly, + (func)Kprintf, + (func)sysmem_call15_set_Kprintf, + 0 +}; + +struct allocTABLE *alloclist; +char _alloclist[0x200]; // temp buffer +//struct allocTABLE _alloclist; // has to be last!, also temp! + +void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +void Kprintnum(unsigned int n) +{ + char chars[16] = "0123456789abcdef"; + int i = 0; + while(i < 8) { + Kputc(chars[n>>28]); + n <<= 4; + ++i; + } +} + + +///////////////////////////////////////////////////////////////////////[OK] +void sysmem_retonly(){} + +//////////////////////////////entrypoint///////////////////////////////[OK] +void *_start(u32 iopmemsize) +{ + iopmemsize=min(EIGHTMEGSm256, iopmemsize); + + alloclist = (struct allocTABLE*)(((u32)&_alloclist + 255) & 0xFFFFFF00); // round up + memsize = iopmemsize & 0xFFFFFF00; + + //__printf("sysmem_start: %x, %x\n", memsize, ((u32)alloclist+sizeof(struct allocTABLE))); + //Kprintnum((int)alloclist); Kputs(" alloclist\n"); + //Kprintnum((int)&alloclist); Kputs(" &alloclist\n"); + + if (memsize >= ((u32)alloclist+sizeof(struct allocTABLE))) //alloctable must fit memory + return sysmem_init_memory(); + alloclist = NULL; + return NULL; +} + +/////////////////////////////////////////////////////////////////////// +extern void* _end; +void *sysmem_init_memory(){ //mark all mem as not allocated, available + unsigned int i; + struct allocELEM *p; + + //__printf("system_init_memory\n"); + + if (alloclist == NULL) return NULL; + + alloclist->next=NULL; + for (i=smFIRST; ilist[i].next=&alloclist->list[i+1]; + alloclist->list[i].info=0; + } + alloclist->list[smLAST].next=NULL; + + alloclist->list[smFIRST].info &= 0x0001FFFF; + alloclist->list[smFIRST].info |= (((memsize<0 ? + memsize+255:memsize) >> 8) << 17); + + // _end ~= alloclist + sizeof(struct alocTABLE); + + //this is not NULL! but the starting address of the first 0x1500 bytes allocated + if ( AllocSysMemory(ALLOC_FIRST, (int)alloclist, NULL)==0) { + if (alloclist==AllocSysMemory(ALLOC_FIRST, sizeof(struct allocTABLE)-4, NULL)){ //alloc allocated allocation table;-) + for (p=alloclist->list; p; p=p->next) { + if (!mALLOCATED(p->info)) { + return (void*)((mADDRESS(p->info))<<8);//next free block address + } + } + return NULL; + } + } + alloclist=NULL; + return NULL; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryMemSize(){ + if (alloclist) + return memsize;//2*1024*1024-256=0x001FFF00 + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryMaxFreeMemSize(){ + unsigned int maxfree=0; + struct allocELEM *p; + + if (alloclist) + for (p=alloclist->list; p; p=p->next) + if (!mALLOCATED(p->info)) + maxfree = max(maxfree, mSIZE(p->info)); + return maxfree<<8; // => 256bytes allocation units +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryTotalFreeMemSize(){ + unsigned int freesize=0; + struct allocELEM *p; + + if (alloclist) + for (p=alloclist->list; p; p=p->next) + if (!mALLOCATED(p->info)) + freesize+=mSIZE(p->info); + return freesize<<8; // => 256bytes allocation units +} + +void *alloc(int flags, int size, void *mem); +void maintain(); +///////////////////////////////////////////////////////////////////////[OK] +void *AllocSysMemory(int flags, int size, void *mem){ + if (alloclist && (flags<3)){ + void *r=alloc(flags, size, mem); + maintain(); + //Kprintnum((int)r); Kputs("\n"); + return (void*)r; + } + return NULL; +} + +int free(void *mem); +///////////////////////////////////////////////////////////////////////[OK] +int FreeSysMemory(void *mem){ + struct allocTABLE *table; + int r; + + for (table=alloclist; table; table=table->next) //must not be among + if (mem==table) //the allocation tables + return -1; + if (r=free(mem)) + return r; + maintain(); + return r; //r==0 ;-) +} + +struct allocELEM *findblock(void *a); +///////////////////////////////////////////////////////////////////////[OK] +void *QueryBlockTopAddress(void *address){ + struct allocELEM *p; + + if (p=findblock(address)) + return (void*)((mADDRESS(p->info) << 8) + + (mALLOCATED(p->info) ? USED : FREE)); + return (void*)-1; +} + +///////////////////////////////////////////////////////////////////////[OK] +int QueryBlockSize(void *address){ + struct allocELEM *p; + + if (p=findblock(address)) + return (mSIZE(p->info) << 8) | + (mALLOCATED(p->info) ? USED : FREE); + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int *sysmem_return_addr_of_memsize(){ + return &memsize; +} + +/////////////////////////////////////////////////////////////////////// +void *alloc(int flags, int size, void *mem){ + struct allocELEM *a, *last, *k; + unsigned int bsize, //block size in 256bytes units + baddress, //block address in 256bytes units + i, tmp; + void *address; + + bsize = (size+255) >> 8; // round to upper + if (bsize==0) return NULL; + + switch (flags){ + case ALLOC_FIRST: + for (a = alloclist->list; a; a=a->next) + if ((!mALLOCATED(a->info))) + if (mSIZE(a->info) >= bsize) + break; + if (a==NULL) return NULL; + + if (mSIZE(a->info) == bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); //all done, how quick! + } + + address = (void*)(mADDRESS(a->info) << 8); + i = a->info; + + a->info=((a->info | 1) & 0x1FFFF) | //alloc block + (bsize << 17); //of wanted size + + i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); + i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); + + a=a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + case ALLOC_LAST: + last=NULL; + for (a = alloclist->list; a; a=a->next) + if ((!mALLOCATED(a->info))) + if (mSIZE(a->info) >= bsize) + last=a; //use last one suitable + a = last; + if (a==0) return NULL; + + if (mSIZE(a->info) == bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); + } + + a->info = (a->info & 0x0001FFFF) | + ((mSIZE(a->info) - bsize) << 17); //put rest of block + + i = (((i & 0xFFFF0001)//this line has no use; this is stupid + | ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) //calculate address of block to use + & 0x0001FFFF) //keep only address (and alloc' state) + | (bsize << 17) //put size + | 1; //mark as allocated + a=a->next; + + address = (void*)(mADDRESS(i) << 8); //address in bytes + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + case ALLOC_LATER: + if ((unsigned int)mem & 0xFF) return NULL; + baddress = (unsigned int)mem >> 8; //addr in 256bytes units + for (a = alloclist->list; a ; a=a->next){ + if (baddress < mADDRESS(a->info)) return NULL;//cannot realloc + if ((!mALLOCATED(a->info)) && + (mSIZE(a->info) + mADDRESS(a->info) >= baddress + bsize)) + break; + } + if (a==0) return NULL; + + if (mADDRESS(a->info) < baddress){ + tmp = mADDRESS(a->info) + mSIZE(a->info) - baddress; + a->info= (a->info & 0x1FFFF) | + ((mSIZE(a->info) - tmp) << 17); + + i =(((i & 0xFFFF0001) | //stupid compiler + ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) + & 0x1FFFE) + | (tmp << 17); + + k = a = a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a=a->next; + } + a = k; + } + + if (mSIZE(a->info)==bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); + } + + address = (void*)(mADDRESS(a->info) << 8); + i = a->info; + + a->info=((a->info | 1) & 0x1FFFF) | //alloc block + (bsize << 17); + + i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); + i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); + + a=a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + } + + return NULL; +} +/***original while (mSIZE(i)>0){ + x=a->next; //stupid, n'est ce pas? + tmp=a->info; + a->next=z; //stupid, n'est ce pas? + a->info=i; + a->next=x; //stupid, n'est ce pas? + z=x; //stupid, n'est ce pas? + i=tmp; + a = a->next; + } ***/ + +///////////////////////////////////////////////////////////////////////[OK] +int free(void *mem){ + int skip; // counter (0,1,2) of elements to remove + struct allocELEM *a, // an element + *p, // prev + *n; // next + + if ((unsigned int)mem & 0xFF) return -1; // only 256byte multiple + + for (a=&alloclist->list[smFIRSTF], p=NULL; a; a=a->next){ + if ((mSIZE(a->info) && (mADDRESS(a->info)== + ((unsigned int)mem >> 8)))) // convert to 256byte units + break; + p=a; + } + + if (a==NULL) return -1; //block not found + + if (!mALLOCATED(a->info))return -1; //cannot free a freed block + + n=NULL; + skip=0; + + a->info&=0xFFFFFFFE; //free block + + if ((a->next) && (!mALLOCATED(a->next->info))){//bind with next free block + n = a->next; + skip = 1; + a->info = (a->info & 0x1FFFE) | + ((mSIZE(a->info) + mSIZE(a->next->info)) << 17); + } + + if (p && (!mALLOCATED(p->info))){ //bind with previous free block + n=a; + skip++; // or skip=2; + p->info=(p->info & 0x1FFFF) | + ((mSIZE(p->info) + mSIZE(a->info)) << 17); + } + + if (skip){ + a=n; + while (--skip!=-1) + a=a->next; + while (a){ + n->info=a->info; + a=a->next; + n=n->next; + } + } + return 0; +} +/***original while (a){ + t1=n->next; + t2=a->next; + t3=a->info; + n->next=t2; //stupid compiler, see above + n->info=t3; + n->next=t1; + a=a->next; + n=t1; + }***/ + +///////////////////////////////////////////////////////////////////////[OK] +void maintain(){ + struct allocTABLE *table, *new; + int i; + + for (table=alloclist; table->next; table = table->next) //+0x00 + ; //move to last non-NULL + if (mSIZE(table->list[smCHECK].info)>0) //+0xE0 //27 (i.e.28th) + // a new table is needed; alloc it + if (new=(struct allocTABLE*)alloc(0, sizeof(struct allocTABLE), 0)){ + table->next=new; // link it + table->list[smLAST].next=&new->list[smFIRST];// link it's table elements + table=table->next; // move to it + table->next=NULL; // mark as end of tables + for (i=0; ilist[i].next=&table->list[i+1]; + table->list[i].info=0; + } + table->list[smLAST].next=NULL; + } + + table=alloclist; + if (table->next){ + while (table->next->next) + table=table->next; + if (table->next) //redundant check + if (mSIZE(table->list[smCHECK].info)==0){ + struct allocTABLE *t=table->next; + table->list[smLAST].next=NULL; + table->next =NULL; + free(t); + } + } +} + +///////////////////////////////////////////////////////////////////////[OK] +struct allocELEM *findblock(void *a){ // it finds the block for a given address + struct allocELEM *p; + for (p = alloclist->list; p; p=p->next) + if (((unsigned int)a >= (mADDRESS(p->info) << 8)) && + ((unsigned int)a < (mADDRESS(p->info) << 8) + mSIZE(p->info))) + break; + return p; +} + +///////////////////////////////////////////////////////////////////////[OK] +char *Kprintf(const char *format,...){ + if (_Kprintf) + return _Kprintf(unk, format, (void*)(format+4));//it is not accurate since mips + // have the 2nd, 3rd & 4th parameters + // in regs and not in stack, + // but you got the idea + return NULL; +} + +///////////////////////////////////////////////////////////////////////[OK] +void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int, const char*, ...), unsigned int newunk){ + if (_Kprintf && newKprintf) + newKprintf(newunk, _Kprintf(0)); + unk = newunk; + _Kprintf = newKprintf; +} diff --git a/fps2bios/kernel/iopload/threadman/Makefile b/fps2bios/kernel/iopload/threadman/Makefile new file mode 100644 index 0000000000..825a93d649 --- /dev/null +++ b/fps2bios/kernel/iopload/threadman/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: threadman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = threadman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +threadman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/THREADMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/threadman/threadman.c b/fps2bios/kernel/iopload/threadman/threadman.c new file mode 100644 index 0000000000..d964bad648 --- /dev/null +++ b/fps2bios/kernel/iopload/threadman/threadman.c @@ -0,0 +1,654 @@ +//[module] THREADMAN +//[processor] IOP +//[type] ELF-IRX +//[name] Multi_Thread_Manager +//[version] 0x101 +//[memory map] 0xBF802070 +//[handlers] - +//[entry point] start, thbase_stub, thevent_stub, thsemap_stub, +// thmsgbx_stub, thfpool_stub, thvpool_stub, thrdman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) november 2002 - january 2003 + +#include "err.h" +#include "ksysmem.h" +#include "kloadcore.h" +#include "kintrman.h" +#include "kstdio.h" +#include "ksysclib.h" +#include "ktimrman.h" +#include "kheaplib.h" +#include "iopdebug.h" +#include "kthbase.h" + +int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("threadman:" fmt, ## args) + +int _start(); + + +void _retonly() {} + +struct export thbase_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thbase", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x10 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x18 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x20 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x28 + (func)_retonly, + 0 +}; + +struct export thevent_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thevent", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +struct export thsemap_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thsemap", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + + +int _start() { + int x; + + _dprintf("_start\n"); + +// if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; + if (RegisterLibraryEntries(&thbase_stub)) return 1; + + CpuSuspendIntr(&x); + + RegisterLibraryEntries(&thevent_stub); + RegisterLibraryEntries(&thsemap_stub); +// RegisterLibraryEntries(&thmsgbx_stub); +// RegisterLibraryEntries(&thfpool_stub); +// RegisterLibraryEntries(&thvpool_stub); + + CpuEnableIntr(); +} + +#if 0 +unsigned int ready; +unsigned int _263; +unsigned int _14; + +/////////////////////////////////////////////////////////////////////// +unsigned int *threadman_callx(){ + return &ready; +} + +/////////////////////////////////////////////////////////////////////// +int thbase_start(int argc, char* argv[]){ + int x; + + if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; + if (RegisterLibraryEntries(&thbase_stub)) return 1; + + CpuSuspendIntr(&x); + + RegisterLibraryEntries(&thevent_stub); + RegisterLibraryEntries(&thsemap_stub); + RegisterLibraryEntries(&thmsgbx_stub); + RegisterLibraryEntries(&thfpool_stub); + RegisterLibraryEntries(&thvpool_stub); + + memset(&ready, 0, 1220); //305 x 4 => zero all bss + + _unk3=8; + _2=NULL; + LL_reset(&a); + LL_reset(&b); + LL_reset(&c); + LL_reset(&d); + LL_reset(&e); + LL_reset(&f); + LL_reset(&g); + LL_reset(&h); + LL_reset(&i); + LL_reset(&threads_list); + + for (j=0; j<128; j++) + LL_reset(&prio_lists[j]); + hp=CreateHeap(0x800, 1); //s3=&hp + th=allocheap(0x7F01, sizeof(struct TCB)); + th->id=++ids;//short + th->thp_stackSize=512; + th->stack=AllocSysMemory(ALLOC_LAST, 512, 0); + th->prio=th->thp_priority=127;//LOWEST_PRIORITY+1 + th->thp_attr=TH_C; + th->status=THS_READY; + th->gp=gp; + th->thp_entry=infinite_call; + th->area=th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + memset(th->area, 0, 0xB8); + th->area->field_00=0xFFFFFFFE; + th->area->H78=th->area->H74==&th->area->regs; + th->area->ExitThread=ExitThread; + th->area->gp=th->gp; + th->area->attr=(th->attr & TH_COP) | 0x404; + th->area->attr|=th->attr & TH_UMODE; + th->area->entry=th->thp_entry; + th->area->ei=1; + _2.next=th; + _2.prev=th; + enqueue(th); + + th=allocheap(0x7F01, sizeof(struct TCB)); + th->id=++ids;//short + th->thp_stackSize=QueryBlockSize(&j); + th->stack=QueryBlockTopAddress(&j); + th->thp_priority=8; //MODULE_INIT_PRIORITY + th->prio=1; //HIGHEST_PRIORITY + th->thp_attr=0x2000000; + th->status=THS_RUN; + th->gp=gp; + th->next_2=_2.next; + _2.next=th; + ready.prev=ready.next=th; + th->next=NULL; + th->prev=NULL; + SetCtxSwitchHandler(handler1_switchcontexts); + SetCtxSwitchReqHandler(handler2_morethan1ready); + sub_50A0(); + + efp.attr=2; + efp.initPattern=0; + efp.option=0; + systemStatusFlag=CreateEventFlag(&efp); + + if (v0=QueryBootMode(4)) + SetEventFlag(systemStatusFlag, 1<<(v0->H0 & 3));//H0 short + + loadcore_call20_registerFunc(&lc20_2, 2, 0); + loadcore_call20_registerFunc(&lc20_3, 3, 0); + CpuEnableIntr(); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int lc20_2(){ + CpuEnableIntr(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int lc20_3(int a){ + _dprintf("%s\n", __FUNCTION__); + CpuEnableIntr(); + + ChangeThreadPriority(0, 126);//LOWEST_PRIORIT + if (a->H0 == 0) { + for (;;) { + DelayThread(1000000); //never exit + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void infinite_call(){ + infinite_call(); +} + +/////////////////////////////////////////////////////////////////////// +void syscall_32(){ + li $v0, 0x20 + syscall #0 +} + +/////////////////////////////////////////////////////////////////////// +void enqueue(struct TCB *th){ + flags[th->prio>>5] |= 1 << (th->prio & 0x1F); + LL_add_before(&prio_lists[th->prio], th); +} + +///////////////////////////////////////////////////////////////////////clone? +void enqueue2(struct TCB *th){ + flags[th->prio>>5] |= 1 << (th->prio & 0x1F); + LL_add_before(&prio_lists[th->prio], th); +} + +/////////////////////////////////////////////////////////////////////// +void unqueue(ll, prio){ + if (LL_0_1_elements(ll) + flags[prio>>5] &= ~(1 << (prio & 0x1F)) + LL_remove(ll); +} + +/////////////////////////////////////////////////////////////////////// +int run(struct TCB *th, int x){ + if (th->prio >= ready.next->prio){ + th->status=THS_READY; + enqueue(th); + CpuResumeIntr(x); + return KE_OK; + }else{ + ready.next->status=THS_READY; + enqueue2(ready.next); + th->status=THS_RUN; + ready->prev=th; + return syscall_32(0, 0, x, 0); + } +} + +/////////////////////////////////////////////////////////////////////// +int getHighestUsed(){ + int i; + for (i=0; i<4; i++) + if (flags[i]) + return (i<<5)+getHighestUsed_32(flags[i]); + return 128; //LOWEST_PRIORITY+2 +} + +/////////////////////////////////////////////////////////////////////// +void switch(){ + int hp; + + ready.prev=ready.next; + if (ready.next->status != THS_RUN){ + if (unk3 & 4) + Kprintf(" not THS_RUN "); + hp=getHighestUsed(); + if (hp<128){ + if (unk3 & 4) + Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", + &prio_lists[hp], prio_lists[hp].next, prio_lists[hp].next->id, hp); + unqueue(prio_lists[hp].next, hp); + prio_lists[hp].next->status=THS_RUN; + ready.prev=prio_lists[hp].next; + }else + Kprintf("Panic: not found executable Thread\n"); + }else + if ((hp=getHighestUsed())<128){ + if (unk3 & 4) + Kprintf(" THS_RUN cp=%d : hp=%d ", ready.next->prio, hp); + if (hpprio){ + if (unk3 & 4) + Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", + &prio_list[hp], prio_list[hp].next, prio_list[hp].next->id, hp); + unqueue(prio_list[hp].next, hp); + prio_list[hp].next->status=ready.next->status; + ready.prev=prio_lists[hp].next; + ready.next->status=THS_READY; + enqueue2(ready.next); + } + }else + Kprintf("Panic: not found ready Thread\n"); + if (unk3 & 4) + Kprintf("\n"); +} + +/////////////////////////////////////////////////////////////////////// +void stack_overflow(struct TCB *th){ + register ImageInfo ii; + register char *name; + Kprintf("\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n", + (th<<5) | ((th->id & 0x3F) << 1) | 1, th->id & 0xFFFF, th->stack, th->thp_stackSize, th->area); + if ((ii=loadcore_call24_findImageInfo(th->thp_entry)) && + (name=ii->H04)) + Kprintf(" Module Name = %s\n", name); + __asm break #0x400 +); + +/////////////////////////////////////////////////////////////////////// +struct TCB *handler1_switchcontexts(struct AREA *area){ + s0=&unk4; + unk4++; + if (unk3 & 3){ + if (1==unk3 & 3) + Kprintf("[%3d->", ready.next->id); + if (2==unk3 & 3) + Kprintf("switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n", + area, area->field_00, area->entry, area->ei, ready.next, ready.next->id); + } + ready.next->area=area; + if (area < ready.next->stack) + stack_overflow(ready.next); + if (ready.prev->next==NULL) + switch(); + if (ready.prev != ready.next){ + s0=GetTimerCounter(timid); + ready.next->field_30=moveregs(0, s0-www.prev, ready.next->field_30); + www.prev=s0; + } + if (unk3 & 3){ + if (unk3 & 3 == 1) + Kprintf("%3d]", ready.prev->id); + if (unk3 & 3 == 2) + Kprintf(" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n" + ready.prev->area, ready.prev->area->field_00, ready.prev->area->entry, + ready.prev->area->ei, ready.prev, ready.prev->id); + } + if (unk3 & 0x20){ + 0xBF802070=~(1 << ((ready.prev->id-1) & 7)); + } + return ready.prev; +} + +/////////////////////////////////////////////////////////////////////// +int handler2_morethan1ready(){ + return (0 < (ready.prev^ready.next)); + //return (ready.prev!=ready.next); +} + +/////////////////////////////////////////////////////////////////////// +void queue_on_prio(struct TCB *th, void *fld, int prio){ + register struct TCB *p; + + LL_remove(th); + for (p=fld->H14; p !=&fld->H14 && prio>=p->prio; p=p->next); + LL_add_before(p, th); +} + +///////////////////////////////////////////////////////////////////////[04] +int CreateThread(struct ThreadParam *param){ + int x; + register struct TCB *th; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (param->attr & 0x1CFFFFF7) return KE_ILLEGAL_ATTR; + if (param->initPriority-1>=126) return KE_ILLEGAL_PRIORITY; + if (param->entry & 3) return KE_ILLEGAL_ENTRY; + if (param->stackSize<0x130) return KE_ILLEGAL_STACK_SIZE; + + CpuSuspendIntr(&x); + if (th=allocheap(0x7F01, sizeof(struct TCB))){ //0x50 + param->stackSize = (param->stackSize+0xFF) & 0xFFFFFF00; + stack=AllocSysMemory(ALLOC_LAST, param->stackSize, NULL); + if (!stack) + freeheap(th); + } + if (!th || !stack){ + CpuResumeIntr(x); + return KE_NO_MEMORY; + } + th->id=++ids; + th->thp_entry=param->entry; + th->stack=stack; + th->thp_stackSize; + th->thp_priority=param->initPriority; + th->thp_attr=attr; + th->status=THS_DORMANT; + th->thp_option=param->option; + th->gp=$gp; + th->next_2=&_2; + _2.next=th; + LL_add_before(threads_list, th); + if (!(th->thp_attr & TH_NO_FILLSTACK)) + memset(th->stack, 0xFF, th->thp_stackSize-48); + CpuResumeIntr(x); + return ((int)th<<5) | ((th->id & 0x3F) << 1) | 1; +} + +///////////////////////////////////////////////////////////////////////[05] +int DeleteThread(int thid){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F)) || + (_2.prev == th)){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + FreeSysMemory(th->stack); + LL_remove(th); + + if (_2.next==th) + _2.next=th->next_2; + else + for (p=_2.next; p->next_2; p=p->next_2) + if (p->next_2==th){ + p->next_2=th->next_2; + break; + } + + freeheap(th); + CpuResumeIntr(x); + return KE_OK; +} + +/////////////////////////////////////////////////////////////////////// +int startThread(struct TCB *th,int x){ + th->field_1C=0; + th->field_20=0; + th->field_1E=0; + th->prio=thp_priority; + th->area->field_00=0xFFFFFFFE; + th->area->field_78=th->area->field_74=&th->area->regs; + th->area->ExitThread=ExitThread; + th->area->gp=th->gp; + th->area->attr=(th->attr & TH_COP) | 0x404; + th->area->attr|=th->attr & TH_UMODE; + th->area->entry->th->thp_entry; + th->ei=1; + LL_remove(th); + return run(th, x); +} + +///////////////////////////////////////////////////////////////////////[06] +int StartThread(int thid,u_long arg){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + memset(th->area, 0, 0xB8); + th->area->arg=arg; + return startThread(th, x); +} + +///////////////////////////////////////////////////////////////////////[07] +int StartThreadArgs(int thid,int args,void *argp){ + int x; + register struct TCB *th, *p; + register void *_argp; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + + _argp=th->stack + ((th->thp_stackSize >> 2) - ((args+3) >> 2)) << 2 + if (args>0 && argp) + memcpy(_argp, argp, args); + + memset(th->area, 0, 0xB8); //BUG: these instructions should be switched! + th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + + th->area->arg =args; + th->area->argp=_argp; + return startThread(th, x); +} + +///////////////////////////////////////////////////////////////////////[08] +int ExitThread(){ + th=ready->next; + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT + CpuSuspendIntr(&x); + th->status=THS_DORMANT; + LL_add_before(&threads_list, th); + a0=0; + do{ + ready.prev=0; + syscall_32(0, 0, x, 0); + Kprintf("panic ! Thread DORMANT !\n"); + __asm break #0x400 + while(1); +} + +///////////////////////////////////////////////////////////////////////[09] +int ExitDeleteThread(){ + return KE_ERROR; +} + +///////////////////////////////////////////////////////////////////////[10] +int TerminateThread(int thid){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if (ready.next==th){ + CpuResumeIntr(x); + return KE_ILLEGAL_THID; + } + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status == THS_DORMANT){ + CpuResumeIntr(x); + return KE_DORMANT; + } + LL_remove(th); + if (th->status==THS_WAIT) + if (th->field_1C==2) + CancelAlarm(alarmhandler, th); + else + if (th->field_1C>=2) && (th->field_1C<8) + th->field_20->H10--; + th->status=THS_DORMANT; + LL_add_before(&threads_list, th); + + CpuResumeIntr(x); + return KE_OK; +} + +/////////////////////////////////////////////////////////////////////// +void LL_add_before(struct ll *list, struct ll *new){ + new->next=list; + new->prev=list->prev; + list->prev=new; + new->prev->next=new; +} + +///////////////////////////////////////////////////////////////////////:) +int getHighestUsed_32(int flags_32){ + v=-4; + do{ + i=flags_32<<28; + flags_32>>=4; + v+=4; + }while(i==0); + return v + ((0x1020103 >> ((i>>26) & 0x1C)) & 0xF); +} + +#endif diff --git a/fps2bios/kernel/iopload/timrman/Makefile b/fps2bios/kernel/iopload/timrman/Makefile new file mode 100644 index 0000000000..1113b6c434 --- /dev/null +++ b/fps2bios/kernel/iopload/timrman/Makefile @@ -0,0 +1,59 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: timrman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = timrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +timrman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/TIMRMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/timrman/timrman.c b/fps2bios/kernel/iopload/timrman/timrman.c new file mode 100644 index 0000000000..63e0f23140 --- /dev/null +++ b/fps2bios/kernel/iopload/timrman/timrman.c @@ -0,0 +1,234 @@ +//[module] TIMEMANI +//[processor] IOP +//[type] ELF-IRX +//[name] Timer_Manager +//[version] 0x101 +//[memory map] 0xBF801100, 0xBF801110, 0xBF801120, +// 0xBF801450 +// 0xBF801480, 0xBF801490, 0xBF8014A0, +// 0xBF8014B0, 0xBF8014C0 +//[handlers] - +//[entry point] timrman_start, timrman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) 13 October 2002 + +#include + +#include "iopdebug.h" +#include "kloadcore.h" +#include "kintrman.h" + +#include "err.h" +#include "ktimrman.h" + +#define CONFIG_1450 (*(volatile int*)0xBF801450) + +struct TIMRMAN{ + int hwreg; + char source, size; + short prescale; + int allocated; +} t[6]={ +{RTC2, TC_SYSCLOCK, TIMER_SIZE_16, TIMER_PRESCALE_8, 0}, +{RTC5, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, +{RTC4, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, +{RTC3, TC_SYSCLOCK|TC_HLINE, TIMER_SIZE_32, TIMER_PRESCALE_1, 0}, +{RTC0, TC_SYSCLOCK|TC_PIXEL|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0}, +{RTC1, TC_SYSCLOCK|TC_HLINE|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0} +}; + +int _start(int argc, char* argv[]); + +///////////////////////////////////////////////////////////////////////[03] +void *GetTimersTable(){ + return t; //address of the array +} + +///////////////////////////////////////////////////////////////////////[04] +int AllocHardTimer(int source, int size, int prescale){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + CpuSuspendIntr(&x); //intrman + + for (i=0; i<6; i++) + if (!t[i].allocated && (t[i].source & source) && + (t[i].size==size) && (t[i].prescale>=prescale)){ + t[i].allocated++; //u8 + CpuResumeIntr(x); //intrman + return t[i].hwreg>>2; + } + + CpuResumeIntr(x); //intrman + return ERROR_NO_TIMER; +} + +///////////////////////////////////////////////////////////////////////[05] +int ReferHardTimer(int source, int size, int mode, int modemask){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + CpuSuspendIntr(&x); //intrman + + for (i=0; i<6; i++) + if (t[i].allocated && (t[i].source & source) && (t[i].size==size) && + (int)(GetTimerStatus(t[i].hwreg>>2) & modemask)==mode){ + t[i].allocated++; //u8 + CpuResumeIntr(x); //intrman + return t[i].hwreg>>2; + } + + CpuResumeIntr(x); //intrman + return ERROR_NO_TIMER; +} + +///////////////////////////////////////////////////////////////////////[10] +int GetHardTimerIntrCode(int timid){ + switch(timid<<2){ + case RTC2: return INT_RTC2; + case RTC0: return INT_RTC0; + case RTC1: return INT_RTC1; + + case RTC4: return INT_RTC4; + case RTC3: return INT_RTC3; + case RTC5: return INT_RTC5; + } + return ERROR_UNK; +} + +///////////////////////////////////////////////////////////////////////[06] +int FreeHardTimer(int timid){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + for (i=0; i<6; i++) + if (t[i].hwreg==(timid<<2)) + break; + + if ((i<6) && (t[i].allocated)){ + CpuSuspendIntr(&x); //intrman + t[i].allocated--; + CpuResumeIntr(x); //intrman + return ERROR_OK; + } + return ERROR_NO_TIMER; + +} + +///////////////////////////////////////////////////////////////////////[07] +void SetTimerMode(int timid, int mode){ + *(volatile short*)((timid<<2)+4) = mode; +} + +///////////////////////////////////////////////////////////////////////[08] +unsigned int GetTimerStatus(int timid){ + return *(volatile unsigned short*)((timid<<2)+4); +} + +///////////////////////////////////////////////////////////////////////[09] +void SetTimerCounter(int timid, unsigned int count){ + if ((timid<<2) < RTC3) + *(volatile short*)((timid<<2)+0)=count; + else + *(volatile int*)((timid<<2)+0)=count; +} + +///////////////////////////////////////////////////////////////////////[0A] +unsigned int GetTimerCounter(int timid){ + if ((timid<<2) < RTC3) + return *(volatile short*)((timid<<2)+0); + else + return *(volatile int*)((timid<<2)+0); +} + +///////////////////////////////////////////////////////////////////////[0B] +void SetTimerCompare(int timid, unsigned int compare){ + if ((timid<<2)+8 < RTC3) + *(volatile short*)((timid<<2)+8)=compare; + else + *(volatile int*)((timid<<2)+8)=compare; +} + +///////////////////////////////////////////////////////////////////////[0C] +unsigned int GetTimerCompare(int timid){ + if ((timid<<2)+8 < RTC3) + return *(volatile short*)((timid<<2)+8); + else + return *(volatile int*)((timid<<2)+8); +} + +///////////////////////////////////////////////////////////////////////[0D] +void SetHoldMode(int holdnum, int mode){ + RTC_HOLDMODE=(RTC_HOLDMODE & + ( ~(0xF << (holdnum*4)))) | + ((mode & 0xF) << (holdnum*4)); +} + +///////////////////////////////////////////////////////////////////////[0E] +unsigned long GetHoldMode(int holdnum){ + return (RTC_HOLDMODE >> (holdnum*4)) & 0xF; +} + +///////////////////////////////////////////////////////////////////////[0F] +unsigned long GetHoldReg(int holdnum){ + return *(volatile unsigned int*)(RTC_HOLDREGS + (holdnum*4)); +} + +///////////////////////////////////////////////////////////////////////[01,02] +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export timrman_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "timrman", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)GetTimersTable, + (func)AllocHardTimer, + (func)ReferHardTimer, + (func)FreeHardTimer, + (func)SetTimerMode, + (func)GetTimerStatus, + (func)SetTimerCounter, + (func)GetTimerCounter, + (func)SetTimerCompare, + (func)GetTimerCompare, + (func)SetHoldMode, + (func)GetHoldMode, + (func)GetHoldReg, + (func)GetHardTimerIntrCode, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(int argc, char* argv[]){ + int i; + u32 PRid; + + __asm__ ( + "mfc0 %0, $15\n" + : "=r"(PRid) : + ); + + + if ((PRid<0x10) || (CONFIG_1450 & 8)) return 1; + + for (i=5; i>=0; i--) t[i].allocated=0; + + if( RegisterLibraryEntries(&timrman_stub) > 0 ) + return 1; + + EnableIntr(INT_RTC5); + + return 0; //loadcore +} + diff --git a/fps2bios/kernel/iopload/vblank/Makefile b/fps2bios/kernel/iopload/vblank/Makefile new file mode 100644 index 0000000000..e947fc5dc3 --- /dev/null +++ b/fps2bios/kernel/iopload/vblank/Makefile @@ -0,0 +1,61 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: vblank + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = +LDADD = +OBJECTS = vblank.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sysclib.o \ + ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o + +vblank: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/VBLANK + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/vblank/vblank.c b/fps2bios/kernel/iopload/vblank/vblank.c new file mode 100644 index 0000000000..c093d63ba9 --- /dev/null +++ b/fps2bios/kernel/iopload/vblank/vblank.c @@ -0,0 +1,300 @@ +#include "kloadcore.h" +#include "kintrman.h" +#include "ksysclib.h" +#include "kthbase.h" +#include "thevent.h" +#include "err.h" + +#define _dprintf(fmt, args...) \ + __printf("vblank: " fmt, ## args) + +struct DCLL +{ + struct DCLL *next; + struct DCLL *prev; + int priority; + int (*function)(); + void *this; //'this' style pointer +}; //intrh_vblank, intrh_evblank, vblank_0, vblank_1 + //cannot access global v +struct VBHS +{ + int statusFlag; //set to 0 in 'start' function + int count; + struct DCLL list0; //sentinel, dummy list head (interrupt 0 vblank) + struct DCLL list11; //sentinel, dummy list head (interrupt 11 evblank) + struct DCLL free; //available blocks + struct DCLL items[16]; +} v; + +int _start(); +struct VBHS *return_v(); +int WaitVblankStart(); +int WaitVblankEnd(); +int WaitVblank(); +int WaitNonVblank(); +int RegisterVblankHandler(int number, int priority, int (*)(struct VBHS *), struct VBHS*); +int ReleaseVblankHandler(int number, int (*)(struct VBHS *)); + +void DCLL_del(struct DCLL *list); +void DCLL_add_before(struct DCLL *list, struct DCLL *new); +void DCLL_add_after(struct DCLL *list, struct DCLL *new); + +/////////////////////////////////////////////////////////////////////// +struct VBHS *return_v(){ + return &v; +} + +/////////////////////////////////////////////////////////////////////// +int RegisterVblankHandler(int number, int priority, int (*handler)(struct VBHS *), struct VBHS* this) +{ + struct DCLL *p, *list; + u32 x; + + if (QueryIntrContext()){ + _dprintf("%s - ERROR_INTR_CONTEXT\n", __FUNCTION__); + return ERROR_INTR_CONTEXT; + } + CpuSuspendIntr(&x); + + if (DCLL_is_only_sentinel(&v.free)){ + CpuResumeIntr(x); + _dprintf("%s - ERROR_NO_MEM\n", __FUNCTION__); + return ERROR_NO_MEM; + } + + list=(number? &v.list11 : &v.list0); //which list: 0 or 11? + p=list->next; + if (p != list){ //search for an existing instance in the list + do{ + if (p->function == handler){ + CpuResumeIntr(x); //intrman + return ERROR_DOES_EXIST;//already added + } + p=p->next; + }while(p != list); + p = list->next; + } + while (p != list){ // while we have elements in list ... + if (priority < p->priority) + break; //greater priority + p=p->next; + } + + struct DCLL* node = v.free.next; + DCLL_del(node); + node->function=handler; + node->this =this; + node->priority=priority; + DCLL_add_after(p, node); + + CpuResumeIntr(x); + return ERROR_OK; +} + +/////////////////////////////////////////////////////////////////////// +int ReleaseVblankHandler(int number, int (*handler)(struct VBHS *)){ + struct DCLL *p, *list; + u32 x; + + if (QueryIntrContext()) + return ERROR_INTR_CONTEXT; + CpuSuspendIntr(&x); + + for (list=(number?&v.list11:&v.list0), p=list->next; p!=list; p=p->next) + if (p->function == handler){ //bingo + DCLL_del(p); + DCLL_add_before(&v.free, p); + + CpuResumeIntr(x); + return ERROR_OK; + } + + CpuResumeIntr(x); + return ERROR_DOESNOT_EXIST; //not found +} + +/////////////////////////////////////////////////////////////////////// +int intrh_vblank(struct VBHS *m) +{ + struct DCLL *p; + struct DCLL *cp; + + if (m->count++ == 0){ + iSetEventFlag(GetSystemStatusFlag(), 0x200); + } + + for (p = m->list0.next; p != &(m->list0); p = cp){ + cp=p->next; + if ((p->function)(p->this)==0){ + DCLL_del(p); + DCLL_add_before(&m->free, p); + } + } + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int intrh_evblank(struct VBHS *m) +{ + struct DCLL *p, *cp; + _dprintf("%s\n", __FUNCTION__); + + for (p=m->list11.next; p != &m->list11; p=cp ){ + cp=p->next; + if ((p->function)(p->this)==0){ + DCLL_del(p); + DCLL_add_before(&m->free, p); + } + } + + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int vblankh_0(struct VBHS *m) +{ +// _dprintf("%s\n", __FUNCTION__); + + iSetEventFlag(m->statusFlag, 1); // 0001b //thevent + iSetEventFlag(m->statusFlag, 2); // 0010b //thevent + iClearEventFlag(m->statusFlag, ~(1|8));//~(1001b)=0xFFFFFFF6//thevent + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int vblankh_1(struct VBHS *m) +{ + _dprintf("%s\n", __FUNCTION__); + + iSetEventFlag(m->statusFlag, 4); // 0100b //thevent + iSetEventFlag(m->statusFlag, 8); // 1000b //thevent + iClearEventFlag(m->statusFlag, ~(2|4));//~(0110b)=0xFFFFFFF9//thevent + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int WaitVblankStart(){ + return WaitEventFlag(v.statusFlag, 1, 1, 0); //thevent +} + +/////////////////////////////////////////////////////////////////////// +int WaitVblankEnd(){ + return WaitEventFlag(v.statusFlag, 4, 1, 0); //thevent +} + +/////////////////////////////////////////////////////////////////////// +int WaitVblank(){ + return WaitEventFlag(v.statusFlag, 2, 1, 0); //thevent +} + +/////////////////////////////////////////////////////////////////////// +int WaitNonVblank(){ + return WaitEventFlag(v.statusFlag, 8, 1, 0); //thevent +} + +/////////////////////////////////////////////////////////////////////// +//static allocated Double Cyclic sentinel priority Linked List (whew)// +/////////////////////////////////////////////////////////////////////// +void DCLL_make_sentinel(struct DCLL *list){ + list->next=list; + list->prev=list; +} + +/////////////////////////////////////////////////////////////////////// +int DCLL_is_only_sentinel(struct DCLL *list){ + return (list->next == list); +} + +/////////////////////////////////////////////////////////////////////// +// x <-> list <-> y +// becomes +// x <-> y +void DCLL_del(struct DCLL *list) +{ + struct DCLL* x = list->prev; + struct DCLL* y = list->next; + x->next = y; + y->prev = x; +} + +/////////////////////////////////////////////////////////////////////// +void DCLL_add_before(struct DCLL *list, struct DCLL *new) +{ + new->next=list; + new->prev=list->prev; + list->prev=new; + new->prev->next=new; +} + +// +// list <-> x +// list <-> new <-> x +void DCLL_add_after(struct DCLL *list, struct DCLL *new) +{ + struct DCLL *x = list->next; + new->prev = list; + new->next = x; + list->next = new; + x->prev = new; +} + +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export export_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "vblank\0\0", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)return_v, + (func)WaitVblankStart, // 4 + (func)WaitVblankEnd, // 5 + (func)WaitVblank, // 6 + (func)WaitNonVblank, // 7 + (func)RegisterVblankHandler, // 8 + (func)ReleaseVblankHandler, // 9 + 0 // end of list +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(){ + iop_event_t e; + u32 x; + int i; + + CpuSuspendIntr(&x); + + if (RegisterLibraryEntries(&export_stub)){ + CpuResumeIntr(x); + return 1; + } + + memset(&v, 0, sizeof(struct VBHS)); // 352 //sysclib + DCLL_make_sentinel(&v.list0); + DCLL_make_sentinel(&v.list11); + DCLL_make_sentinel(&v.free); + for (i=0; i<16; i++){ //link 16 elements + DCLL_add_after(&v.free, &v.items[i]);//to 'available' list + } + + e.bits=0; + e.attr=2; + e.option=0; + CreateEventFlag(&e); //thevent + + v.statusFlag=0; + RegisterVblankHandler(0, 128, vblankh_0, &v); + RegisterVblankHandler(1, 128, vblankh_1, &v); + RegisterIntrHandler( 0, 1, (intrh_func)intrh_vblank, &v); + RegisterIntrHandler(11, 1, (intrh_func)intrh_evblank,&v); + EnableIntr(0); + EnableIntr(11); + + CpuResumeIntr(x); + return 0; +} diff --git a/fps2bios/kernel/iopstart.c b/fps2bios/kernel/iopstart.c new file mode 100644 index 0000000000..3b3da90522 --- /dev/null +++ b/fps2bios/kernel/iopstart.c @@ -0,0 +1,66 @@ +#include +#include "romdir.h" + +static void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +static void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +static void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + +static void _iopstart() { + struct rominfo ri; + u8 *str; + + // setup iop + *(char*)0xbf802070 = 9; + *(int*)0xfffe0130 = 0xcc4; + *(int*)0xfffe0130 = 0xcc0; + if( (*(int*)0xbf801450) & 8 ) + *(int*)0xfffe0130 = 0x1e988; + else + *(int*)0xfffe0130 = 0x1edd8; + + romdirGetFile("ROMVER", &ri); + str = (u8*)(0xbfc00000 + ri.fileOffset); + Kputs("iopstart: fps2bios v"); + Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); + + // note, IOPBOOT has to be linked at location ri.fileOffset=0x600!! + romdirGetFile("IOPBOOT", &ri); + + Kputs("_iopstart: loading IOPBOOT to 0xbfc0a180\n"); + //Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); + + __asm__ ( + "li $a0, 2\n" // 2Mb + "move $a1, $0\n" + "move $a2, $0\n" + "move $a3, $0\n" + "move $26, %0\n" + "jr $26\n" + "nop\n" : : "r"(0xbfc00000+ri.fileOffset)); + for (;;); +} + +__asm__ ( + ".global iopstart\n" + "iopstart:\n" + "li $sp, 0x001fffc0\n" // (2<<20)-0x40 + "move $fp, $sp\n" + "j _iopstart\n" + "nop\n"); + + diff --git a/fps2bios/kernel/linkfile b/fps2bios/kernel/linkfile new file mode 100644 index 0000000000..b8e9d859f4 --- /dev/null +++ b/fps2bios/kernel/linkfile @@ -0,0 +1,53 @@ +_stack_size = 0x80000; +_heap_size = 1024*1024*10; + +ENTRY(_start); +SECTIONS { + + .text 0xbfc00000 : { + start.o + *(.text) + *(.rodata) + } + .reginfo ALIGN(128) : { + *(.reginfo) + } + .data ALIGN(128) : { + *(.data) + } + .rdata ALIGN(128) : { + *(.rdata) + } + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128) : { + *(.lit4) + } + .lit8 ALIGN(128) : { + *(.lit8) + } + .sdata ALIGN(128) : { + *(.sdata) + } + + .sbss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + _fbss = . ; + *(.scommon) + *(.sbss) + } + .bss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(.bss) + } + .COMMON ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(COMMON) + } + _end_bss = . - 4; + _stack = .; + . += _stack_size ; + _end_stack = . - 8*5; + _end = . ; + __lc_bh = . ; + . += _heap_size ; + __lc_eh = .; + +} + diff --git a/fps2bios/kernel/romdir.c b/fps2bios/kernel/romdir.c new file mode 100644 index 0000000000..2487288f0f --- /dev/null +++ b/fps2bios/kernel/romdir.c @@ -0,0 +1,43 @@ +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; + struct romdir *base; + int i; + + base = romdirInit(); + if (base == NULL) return NULL; + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/romdir.h b/fps2bios/kernel/romdir.h new file mode 100644 index 0000000000..8249989e78 --- /dev/null +++ b/fps2bios/kernel/romdir.h @@ -0,0 +1,20 @@ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/start.c b/fps2bios/kernel/start.c new file mode 100644 index 0000000000..81277910f8 --- /dev/null +++ b/fps2bios/kernel/start.c @@ -0,0 +1,30 @@ +#include +void eestart() __attribute__ ((noreturn)); +void iopstart() __attribute__ ((noreturn)); + +__asm__ ( + ".org 0\n" + ".set noat\n" + + ".global _start\n" + "_start:\n" + "mfc0 $at, $15\n" + "sltiu $at, 0x59\n" + "bne $at, $0, __iopstart\n" + "j eestart\n" + "nop\n" + "__iopstart:\n" + "j iopstart\n" + "nop\n"); + + +/* +void _start() __attribute__ ((noreturn)); +void _start() { + register unsigned long PRid; + + __asm__ ("mfc0 %0, $15" : "=r"(PRid) : ); + if (PRid >= 0x59) eestart(); + else iopstart(); +}*/ + diff --git a/fps2bios/loader/Makefile b/fps2bios/loader/Makefile new file mode 100644 index 0000000000..6aab6f23dc --- /dev/null +++ b/fps2bios/loader/Makefile @@ -0,0 +1,57 @@ +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: loader + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/ee/lib -L$(NEWLIB)/lib -L$(LIBITO)/lib +LDADD = -lkernel -lmc -lkernel -lpad -lc -lkernel +OBJECTS = loader.o menu.o eedebug.o crt0.o romdir.o +DEST = ../build/LOADER + +loader: $(OBJECTS) + $(EELD) -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $(DEST) + +%.o: %.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + +%.o: %.s + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) $(DEST) + + + diff --git a/fps2bios/loader/crt0.s b/fps2bios/loader/crt0.s new file mode 100644 index 0000000000..f442788315 --- /dev/null +++ b/fps2bios/loader/crt0.s @@ -0,0 +1,110 @@ +.set noat +.set noreorder +.global _start + +.global FlushCache +.global Exit +.global SignalSema +.global _start +.global _exit + +.text + nop + nop +FlushCache: + li $3,100 + syscall + jr $31 + nop +Exit: + li $3,4 + syscall + jr $31 + nop +SignalSema: + li $3,66 + syscall + jr $31 + nop + + nop + nop +_start: + lui $2,%hi(_args_ptr) + addiu $2,$2, %lo(_args_ptr) + sw $4,($2) +# Clear bss +zerobss: + lui $2,%hi(_fbss) + lui $3,%hi(_end) + addiu $2,$2,%lo(_fbss) + addiu $3,$3,%lo(_end) +loop: + nop + nop + sq $0,($2) + sltu $1,$2,$3 + bne $1,$0,loop + addiu $2,$2,16 + +# Thread + lui $4,%hi(_gp) + addiu $4,$4,%lo(_gp) + lui $5,%hi(_stack) + addiu $5,$5,%lo(_stack) + lui $6,%hi(_stack_size) + addiu $6,$6,%lo(_stack_size) + lui $7,%hi(_args) + addiu $7,$7,%lo(_args) + lui $8,%hi(_root) + addiu $8,$8,%lo(_root) + move $28,$4 + addiu $3,$0,60 + syscall + move $29, $2 + +# Heap + addiu $3,$0,61 + lui $4,%hi(_end) + addiu $4,$4,%lo(_end) + lui $5,%hi(_heap_size) + addiu $5,$5,%lo(_heap_size) + syscall + nop + +# Cache + jal FlushCache + move $4,$0 + +# Jump main + ei + + lui $2,%hi(_args_ptr) + addiu $2,$2,%lo(_args_ptr) + lw $3,($2) + lui $2,%hi(_args) + addiu $2,$2,%lo(_args) + + lw $4, ($2) + jal main + addiu $5, $2, 4 +_root: +_exit: +# ??? + lui $2,%hi(_args_ptr) + addiu $2,$2,%lo(_args_ptr) + lw $3,($2) + jal SignalSema + lw $4,($3) +# Exit + addiu $3,$0,35 + syscall + nop + + .bss + .align 6 +_args: .space 256+16*4+4 + + .data +_args_ptr: + .space 4 diff --git a/fps2bios/loader/eedebug.c b/fps2bios/loader/eedebug.c new file mode 100644 index 0000000000..24bc361406 --- /dev/null +++ b/fps2bios/loader/eedebug.c @@ -0,0 +1,31 @@ + +#include +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts(buf); + return ret; +} + diff --git a/fps2bios/loader/include/eedebug.h b/fps2bios/loader/include/eedebug.h new file mode 100644 index 0000000000..dfe853c609 --- /dev/null +++ b/fps2bios/loader/include/eedebug.h @@ -0,0 +1,12 @@ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/loader/include/menu.h b/fps2bios/loader/include/menu.h new file mode 100644 index 0000000000..3e2d2e8848 --- /dev/null +++ b/fps2bios/loader/include/menu.h @@ -0,0 +1,8 @@ +#ifndef __MENU_H__ +#define __MENU_H__ + +#include + +int menuStart(); + +#endif /* __MENU_H__ */ diff --git a/fps2bios/loader/include/romdir.h b/fps2bios/loader/include/romdir.h new file mode 100644 index 0000000000..8249989e78 --- /dev/null +++ b/fps2bios/loader/include/romdir.h @@ -0,0 +1,20 @@ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/loader/linkfile b/fps2bios/loader/linkfile new file mode 100644 index 0000000000..714d24560c --- /dev/null +++ b/fps2bios/loader/linkfile @@ -0,0 +1,52 @@ +_stack_size = 0x80000; +_heap_size = 1024*1024*10; + +ENTRY(_start); +SECTIONS { + + .text 0x00082000 : { + *(.text) + *(.rodata) + } + .reginfo ALIGN(128) : { + *(.reginfo) + } + .data ALIGN(128) : { + *(.data) + } + .rdata ALIGN(128) : { + *(.rdata) + } + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128) : { + *(.lit4) + } + .lit8 ALIGN(128) : { + *(.lit8) + } + .sdata ALIGN(128) : { + *(.sdata) + } + + .sbss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + _fbss = . ; + *(.scommon) + *(.sbss) + } + .bss ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(.bss) + } + .COMMON ALIGN(128) (NOLOAD) : { /* uninitialized data */ + *(COMMON) + } + _end_bss = . - 4; + _stack = .; + . += _stack_size ; + _end_stack = . - 8*5; + _end = . ; + __lc_bh = . ; + . += _heap_size ; + __lc_eh = .; + +} + diff --git a/fps2bios/loader/loader.c b/fps2bios/loader/loader.c new file mode 100644 index 0000000000..45e9a47e4a --- /dev/null +++ b/fps2bios/loader/loader.c @@ -0,0 +1,14 @@ + +#include +#include +#include + +#include "eedebug.h" + + +void main() { + __printf("LOADER start\n"); + + menuStart(); +} + diff --git a/fps2bios/loader/menu.c b/fps2bios/loader/menu.c new file mode 100644 index 0000000000..00b336c274 --- /dev/null +++ b/fps2bios/loader/menu.c @@ -0,0 +1,20 @@ + +#include +#include +#include +#include + +#include "eedebug.h" +#include "romdir.h" + + +int menuStart() { + + + __printf("%s\n", __FUNCTION__); + + + + return 0; +} + diff --git a/fps2bios/loader/romdir.c b/fps2bios/loader/romdir.c new file mode 100644 index 0000000000..3494074eda --- /dev/null +++ b/fps2bios/loader/romdir.c @@ -0,0 +1,47 @@ +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *base = NULL; + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; +// struct romdir *base; + int i; + + if (base == NULL) { + base = romdirInit(); + if (base == NULL) return NULL; + } + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/ps2romgen.c b/fps2bios/ps2romgen.c new file mode 100644 index 0000000000..30c78b0f87 --- /dev/null +++ b/fps2bios/ps2romgen.c @@ -0,0 +1,80 @@ +// little prog for bios image repack by Florin Sasu 2002-10-03 + +#include +#include + +struct romdir{ + char name[10]; + short ext; + int size; +} rd[200]; //increase the number if needed; 200 is enough + +char buffer[10000]; + +#define min(a,b) (a0){ + fwrite(buffer, 1, min(size, 10000), f); + size-=10000; + } +} + +void writefile(FILE *f, char *name, int offset, int size){ + FILE *fi=fopen(name, "rb"); + if (fi) fseek(fi, 0, SEEK_END); + if ((!fi) || (ftell(fi)!=size)){ + printf("Could not find a file %s of %d bytes\n", name, size); + if (fi) fclose(fi); + return; + } + + printf("%10s\t%8X\t%8X\n", name, offset, size); + fillfile(f, offset-ftell(f), 0); + fseek(fi, 0, SEEK_SET); + while (size>0){ + fread(buffer, 1, min(10000, size), fi); + fwrite(buffer, 1, min(10000, size), f); + size-=10000; + } + + fclose(fi); +} + +int main(int argc, char* argv[]){ + int i, n, offset; + FILE *f; +////////////////////////////////// + printf("PS2 ROMGEN v0.1 Florin Sasu 2002-10-03 (florinsasu@yahoo.com) no padding\n"); + if (argc<2){ + printf("Usage: ps2biosgen \n\tfilename=name of the biosfile to create\n"); + printf("\n\tPut in the same directory with ps2romgen all the files from bios\n"); + return 1; + } +////////////////////////////////// + f=fopen("ROMDIR", "rb"); + if (!f){ + printf("Could not find the ROMDIR file\n"); + return 1; + } + + for (n=0; !feof(f) && (fread(&rd[n], 16, 1, f)==1) && rd[n].name[0]; n++); + + fclose(f); +////////////////////////////////// + printf("\n Name Offset(hex) Size(hex)" + "\n----------------------------------------\n"); + f=fopen(argv[1], "wb"); + + for (i=0, offset=0; i +#include +#include +#include +#include + +#define MAXFILES 200 +#define DIRENTRY_SIZE 16 +#define BUFFSIZE 16384 + +struct __attribute__ ((__packed__)) romdir { + /*following variable must place in designed order*/ + char fileName[10]; + unsigned short extInfoSize; + unsigned long fileSize; +} rd; + +int main(int argc, char *argv[]) { + struct stat buf; + FILE *romdir; + FILE *extinfo; + int i, j; + + printf("fps2bios romdir generator\n"); + if (argc < 2){ + printf("usage: %s infile1 [infile2...]\n", argv[0]); + return 1; + } + + romdir = fopen("ROMDIR", "wb"); + if (romdir == NULL) { + printf("failed to create ROMDIR\n"); + return 1; + } + + extinfo = fopen("EXTINFO", "wb"); + if (extinfo == NULL) { + printf("failed to create EXTINFO\n"); + return 1; + } + + for (i=1; i +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + char str[256]; + FILE *f; + time_t t; + int version; + int build; + + printf("fps2bios romver generator\n"); + if (argc < 3){ + printf("usage: %s version build\n", argv[0]); + return 1; + } + f = fopen("ROMVER", "wb"); + if (f == NULL) { + printf("failed to create ROMVER\n"); + return 1; + } + + t = time(NULL); + strftime(str, 256, "%Y%m%d", localtime(&t)); + version = strtol(argv[1], (char**)NULL, 0); + build = strtol(argv[2], (char**)NULL, 0); + fprintf(f, "%2.2d%2.2dPD%s\n", version, build, str); + fputc(0, f); + + fclose(f); + + return 0; +} diff --git a/fps2bios/set_vars.sh b/fps2bios/set_vars.sh new file mode 100755 index 0000000000..9d495ee7e7 --- /dev/null +++ b/fps2bios/set_vars.sh @@ -0,0 +1,18 @@ +# base-files version 3.7-1 + +# WARNING +# +# IF THIS bash IS MODIFIED IT WILL NOT BE UPDATED BY THE CYGWIN +# SETUP PROGRAM. IT BECOMES YOUR RESPONSIBILITY. +# +# The latest version as installed by the Cygwin Setup program can +# always be found at /etc/defaults/etc/bash.bashrc + +# System-wide .bashrc file +export PS2DEV=/usr/local/ps2dev +export PS2SDK=$PS2DEV/ps2sdk +export PS2LIB=$PS2SDK +export LIBITO=$PS2DEV/libito +export PATH=$PATH:$PS2DEV/bin:$PS2DEV/ee/bin:$PS2DEV/iop/bin +export PATH=$PATH:$PS2DEV/dvp/bin:$PS2SDK/bin + diff --git a/pcsx2/CDVD.c b/pcsx2/CDVD.c new file mode 100644 index 0000000000..c02bac57e7 --- /dev/null +++ b/pcsx2/CDVD.c @@ -0,0 +1,1989 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include "PsxCommon.h" +#include "CDVDiso.h" + +cdvdStruct cdvd; + +char *mg_zones[8] = {"Japan", "USA", "Europe", "Oceania", "Asia", "Russia", "China", "Mexico"}; + +char *nCmdName[0x100]= { + "CdSync", "CdNop", "CdStandby", "CdStop", + "CdPause", "CdSeek", "CdRead", "CdReadCDDA", + "CdReadDVDV", "CdGetToc", "", "NCMD_B", + "CdReadKey", "", "sceCdReadXCDDA", "sceCdChgSpdlCtrl", +}; + +char *sCmdName[0x100]= { + "", "sceCdGetDiscType", "sceCdReadSubQ", "subcommands",//sceCdGetMecaconVersion, read/write console id, read renewal date + "", "sceCdTrayState", "sceCdTrayCtrl", "", + "sceCdReadClock", "sceCdWriteClock", "sceCdReadNVM", "sceCdWriteNVM", + "sceCdSetHDMode", "", "", "sceCdPowerOff", + "", "", "sceCdReadILinkID", "sceCdWriteILinkID", /*10*/ + "sceAudioDigitalOut", "sceForbidDVDP", "sceAutoAdjustCtrl", "sceCdReadModelNumber", + "sceWriteModelNumber", "sceCdForbidCD", "sceCdBootCertify", "sceCdCancelPOffRdy", + "sceCdBlueLEDCtl", "", "sceRm2Read", "sceRemote2_7",//Rm2PortGetConnection? + "sceRemote2_6", "sceCdWriteWakeUpTime", "sceCdReadWakeUpTime", "", /*20*/ + "sceCdRcBypassCtl", "", "", "", + "", "sceCdNoticeGameStart", "", "", + "sceCdXBSPowerCtl", "sceCdXLEDCtl", "sceCdBuzzerCtl", "", + "", "sceCdSetMediumRemoval", "sceCdGetMediumRemoval", "sceCdXDVRPReset", /*30*/ + "", "", "__sceCdReadRegionParams", "__sceCdReadMAC", + "__sceCdWriteMAC", "", "", "", + "", "", "__sceCdWriteRegionParams", "", + "sceCdOpenConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdCloseConfig", /*40*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*50*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*60*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*70*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "mechacon_auth_0x80", "mechacon_auth_0x81", "mechacon_auth_0x82", "mechacon_auth_0x83", /*80*/ + "mechacon_auth_0x84", "mechacon_auth_0x85", "mechacon_auth_0x86", "mechacon_auth_0x87", + "mechacon_auth_0x88", "", "", "", + "", "sceMgWriteData", "sceMgReadData", "mechacon_auth_0x8F", + "sceMgWriteHeaderStart", "sceMgReadBITLength", "sceMgWriteDatainLength", "sceMgWriteDataoutLength", /*90*/ + "sceMgReadKbit", "sceMgReadKbit2", "sceMgReadKcon", "sceMgReadKcon2", + "sceMgReadIcvPs2", "", "", "", + "", "", "", "", + /*A0, no sCmds above?*/ +}; + +// NVM (eeprom) layout info +typedef struct { + u32 biosVer; // bios version that this eeprom layout is for + s32 config0; // offset of 1st config block + s32 config1; // offset of 2nd config block + s32 config2; // offset of 3rd config block + s32 consoleId; // offset of console id (?) + s32 ilinkId; // offset of ilink id (ilink mac address) + s32 modelNum; // offset of ps2 model number (eg "SCPH-70002") + s32 regparams; // offset of RegionParams for PStwo + s32 mac; // offset of the value written to 0xFFFE0188 and 0xFFFE018C on PStwo +} NVMLayout; + +#define NVM_FORMAT_MAX 2 +NVMLayout nvmlayouts[NVM_FORMAT_MAX] = +{ + {0x000, 0x280, 0x300, 0x200, 0x1C8, 0x1C0, 0x1A0, 0x180, 0x198}, // eeproms from bios v0.00 and up + {0x146, 0x270, 0x2B0, 0x200, 0x1C8, 0x1E0, 0x1B0, 0x180, 0x198}, // eeproms from bios v1.70 and up +}; + + +unsigned long cdvdReadTime=0; + +#define CDVDREAD_INT(eCycle) PSX_INT(19, eCycle) + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +#define SetResultSize(size) \ + cdvd.ResultC = size; cdvd.ResultP = 0; \ + cdvd.sDataIn&=~0x40; + + +/* is cdvd.Status only for NCMDS? (linuzappz) */ +enum cdvdStatus { + CDVD_STATUS_NONE = 0x00, // not sure ;) + CDVD_STATUS_SEEK_COMPLETE = 0x0A, +}; + +static int mg_BIToffset(u8 *buffer); + +FILE *_cdvdOpenMechaVer() { + char *ptr; + int i; + char file[256]; + char Bios[256]; + FILE* fd; + + // get the name of the bios file + strcpy(Bios, Config.BiosDir); + strcat(Bios, Config.Bios); + + // use the bios filename to get the name of the mecha ver file + sprintf(file, "%s", Bios); + ptr = file; i = (int)strlen(file); + while (i > 0) { if (ptr[i] == '.') break; i--; } + ptr[i+1] = '\0'; + strcat(file, "MEC"); + + // if file doesnt exist, create empty one + fd = fopen(file, "r+b"); + if (fd == NULL) { + SysPrintf("MEC File Not Found , Creating Blank File\n"); + fd = fopen(file, "wb"); + if (fd == NULL) { + SysMessage("_cdvdOpenMechaVer: Error creating %s", file); + exit(1); + } + fputc(0x03, fd); + fputc(0x06, fd); + fputc(0x02, fd); + fputc(0x00, fd); + } + return fd; +} +s32 cdvdGetMechaVer(u8* ver) +{ + FILE* fd = _cdvdOpenMechaVer(); + if (fd == NULL) return 1; + fseek(fd, 0, SEEK_SET); + fread(ver, 1, 4, fd); + fclose(fd); + return 0; +} + +FILE *_cdvdOpenNVM() { + char *ptr; + int i; + char Bios[256]; + char file[256]; + FILE* fd; + + // get the name of the bios file + strcpy(Bios, Config.BiosDir); + strcat(Bios, Config.Bios); + + // use the bios filename to get the name of the nvm file + sprintf(file, "%s", Bios); + ptr = file; i = (int)strlen(file); + while (i > 0) { if (ptr[i] == '.') break; i--; } + ptr[i+1] = '\0'; + strcat(file, "NVM"); + + // if file doesnt exist, create empty one + fd = fopen(file, "r+b"); + if (fd == NULL) { + SysPrintf("NVM File Not Found , Creating Blank File\n"); + fd = fopen(file, "wb"); + if (fd == NULL) { + SysMessage("_cdvdOpenNVM: Error creating %s", file); + exit(1); + } + for (i=0; i<1024; i++) fputc(0, fd); + } + return fd; +} + +// +// the following 'cdvd' functions all return 0 if successful +// + +s32 cdvdReadNVM(u8 *dst, int offset, int bytes) { + FILE* fd = _cdvdOpenNVM(); + if (fd == NULL) return 1; + fseek(fd, offset, SEEK_SET); + fread(dst, 1, bytes, fd); + fclose(fd); + return 0; +} +s32 cdvdWriteNVM(const u8 *src, int offset, int bytes) { + FILE* fd = _cdvdOpenNVM(); + if (fd == NULL) return 1; + fseek(fd, offset, SEEK_SET); + fwrite(src, 1, bytes, fd); + fclose(fd); + return 0; +} + +#define GET_NVM_DATA(buff, offset, size, fmtOffset) getNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) +#define SET_NVM_DATA(buff, offset, size, fmtOffset) setNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) + +s32 getNvmData(u8* buffer, s32 offset, s32 size, u32 biosVersion, s32 fmtOffset) +{ + // find the correct bios version + NVMLayout* nvmLayout = NULL; + s32 nvmIdx; + for(nvmIdx=0; nvmIdx= cdvd.CNumBlocks) + return 1; + else if( + ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| + ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| + ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) + ) + { + memset(config, 0, 16); + return 0; + } + + // get config data + if(cdvd.COffset == 0) + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else + if(cdvd.COffset == 2) + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); + else + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); +} +s32 cdvdWriteConfig(const u8* config) +{ + // make sure its in write mode + if(cdvd.CReadWrite != 1) + return 1; + // check if block index is in bounds + else if(cdvd.CBlockIndex >= cdvd.CNumBlocks) + return 1; + else if( + ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| + ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| + ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) + ) + return 0; + + // get config data + if(cdvd.COffset == 0) + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else + if(cdvd.COffset == 2) + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); + else + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); +} + + +void cdvdReadKey(u8 arg0, u16 arg1, u32 arg2, u8* key) { + char str[256]; + int numbers; + int letters; + unsigned int key_0_3; + unsigned char key_4; + unsigned char key_14; + char exeName[12]; + + // get main elf name + GetPS2ElfName(str); + sprintf(exeName, "%c%c%c%c%c%c%c%c%c%c%c",str[8],str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16],str[17],str[18]); + SysPrintf("exeName = %s\n",exeName); + + // convert the number characters to a real 32bit number + numbers = ((((exeName[5] - '0'))*10000) + + (((exeName[ 6] - '0'))*1000) + + (((exeName[ 7] - '0'))*100) + + (((exeName[ 9] - '0'))*10) + + (((exeName[10] - '0'))*1) ); + + // combine the lower 7 bits of each char + // to make the 4 letters fit into a single u32 + letters = (int)((exeName[3]&0x7F)<< 0) | + (int)((exeName[2]&0x7F)<< 7) | + (int)((exeName[1]&0x7F)<<14) | + (int)((exeName[0]&0x7F)<<21); + + // calculate magic numbers + key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80 + key_4 = ((numbers & 0x0001F) << 3) | ((0x0E000000 & letters) >> 25); // numbers = F8 letters = 07 + key_14 = ((numbers & 0x003E0) >> 2) | 0x04; // numbers = F8 extra = 04 unused = 03 + + // clear key values + memset(key, 0, 16); + + // store key values + key[ 0] = (key_0_3&0x000000FF)>> 0; + key[ 1] = (key_0_3&0x0000FF00)>> 8; + key[ 2] = (key_0_3&0x00FF0000)>>16; + key[ 3] = (key_0_3&0xFF000000)>>24; + key[ 4] = key_4; + + if(arg2 == 75) + { + key[14] = key_14; + key[15] = 0x05; + } + else if(arg2 == 3075) + { + key[15] = 0x01; + } + else if(arg2 == 4246) + { + // 0x0001F2F707 = sector 0x0001F2F7 dec 0x07 + key[ 0] = 0x07; + key[ 1] = 0xF7; + key[ 2] = 0xF2; + key[ 3] = 0x01; + key[ 4] = 0x00; + key[15] = 0x01; + } + else + { + key[15] = 0x01; + } + + SysPrintf("CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X\n",cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15]); +} + +s32 cdvdGetToc(void* toc) { + s32 ret = CDVDgetTOC(toc); + if(ret == -1) ret = 0x80; + return ret; +/* + cdvdTN diskInfo; + cdvdTD trackInfo; + u8 _time[3]; + u32 type; + int i, err; + + //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 + //the code below handles only CdGetToc! + //if(cdvd.Param[0]==0x01) + //{ + SysPrintf("CDGetToc Param[0]=%d, Param[1]=%d\n",cdvd.Param[0],cdvd.Param[1]); + //} + type = CDVDgetDiskType(); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + if (type == CDVD_TYPE_CDDA) { + PSXMu8(HW_DMA3_MADR+ 0) = 0x01; + } else + if (type == CDVD_TYPE_PS2DVD) { + if (trackInfo.lsn >= (2048*1024)) { // dual sided + PSXMu8(HW_DMA3_MADR+ 0) = 0x24; + } else { + PSXMu8(HW_DMA3_MADR+ 0) = 0x04; + } + } else + if (type == CDVD_TYPE_PS2CD) { + PSXMu8(HW_DMA3_MADR+ 0) = 0x41; + } + + if (PSXMu8(HW_DMA3_MADR+ 0) & 0x04) { + PSXMu8(HW_DMA3_MADR+ 1) = 0x02; + PSXMu8(HW_DMA3_MADR+ 2) = 0xF2; + PSXMu8(HW_DMA3_MADR+ 3) = 0x00; + + if (PSXMu8(HW_DMA3_MADR+ 0) & 0x20) { + PSXMu8(HW_DMA3_MADR+ 4) = 0x41; + PSXMu8(HW_DMA3_MADR+ 5) = 0x95; + } else { + PSXMu8(HW_DMA3_MADR+ 4) = 0x86; + PSXMu8(HW_DMA3_MADR+ 5) = 0x72; + } + PSXMu8(HW_DMA3_MADR+ 6) = 0x00; + PSXMu8(HW_DMA3_MADR+ 7) = 0x00; + PSXMu8(HW_DMA3_MADR+ 8) = 0x00; + PSXMu8(HW_DMA3_MADR+ 9) = 0x00; + PSXMu8(HW_DMA3_MADR+10) = 0x00; + PSXMu8(HW_DMA3_MADR+11) = 0x00; + + PSXMu8(HW_DMA3_MADR+12) = 0x00; + PSXMu8(HW_DMA3_MADR+13) = 0x00; + PSXMu8(HW_DMA3_MADR+14) = 0x00; + PSXMu8(HW_DMA3_MADR+15) = 0x00; + + PSXMu8(HW_DMA3_MADR+16) = 0x00; + PSXMu8(HW_DMA3_MADR+17) = 0x03; + PSXMu8(HW_DMA3_MADR+18) = 0x00; + PSXMu8(HW_DMA3_MADR+19) = 0x00; + + } else { + PSXMu8(HW_DMA3_MADR+ 1) = 0x00; + PSXMu8(HW_DMA3_MADR+ 2) = 0xA0; + PSXMu8(HW_DMA3_MADR+ 7) = itob(diskInfo.strack);//Number of FirstTrack + + PSXMu8(HW_DMA3_MADR+12) = 0xA1; + PSXMu8(HW_DMA3_MADR+17) = itob(diskInfo.etrack);//Number of LastTrack + + PSXMu8(HW_DMA3_MADR+22) = 0xA2;//DiskLength + LSNtoMSF(_time, trackInfo.lsn); + PSXMu8(HW_DMA3_MADR+27) = itob(_time[2]); + PSXMu8(HW_DMA3_MADR+28) = itob(_time[1]); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) { + err=CDVDgetTD(i, &trackInfo); + LSNtoMSF(_time, trackInfo.lsn); + PSXMu8(HW_DMA3_MADR+i*10+30) = trackInfo.type; + PSXMu8(HW_DMA3_MADR+i*10+32) = err == -1 ? 0 : itob(i); //number + PSXMu8(HW_DMA3_MADR+i*10+37) = itob(_time[2]); + PSXMu8(HW_DMA3_MADR+i*10+38) = itob(_time[1]); + PSXMu8(HW_DMA3_MADR+i*10+39) = itob(_time[0]); + } + } +*/ +} + +s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq) +{ + s32 ret = CDVDreadSubQ(lsn, subq); + if(ret == -1) ret = 0x80; + return ret; +} + +s32 cdvdCtrlTrayOpen() +{ + s32 ret = CDVDctrlTrayOpen(); + if(ret == -1) ret = 0x80; + return ret; +} + +s32 cdvdCtrlTrayClose() +{ + s32 ret = CDVDctrlTrayClose(); + if(ret == -1) ret = 0x80; + return ret; +} + +// Modified by (efp) - 16/01/2006 +// checks if tray was opened since last call to this func +s32 cdvdGetTrayStatus() +{ + s32 ret = CDVDgetTrayStatus(); + // get current tray state + if (cdCaseopen) return(CDVD_TRAY_OPEN); + + + if (ret == -1) return(CDVD_TRAY_CLOSE); + return(ret); +} +// Note: Is tray status being kept as a var here somewhere? +// cdvdNewDiskCB() can update it's status as well... +extern int needReset; +// Modified by (efp) - 16/01/2006 +s32 cdvdGetDiskType() { + // defs 0.9.0 + if(CDVDnewDiskCB) return(cdvd.Type); + + // defs.0.8.1 + if(cdvdGetTrayStatus() == CDVD_TRAY_OPEN) return(CDVD_TYPE_NODISC); + // Note: Hmmm. Need to modify cdvd.Type as well? + // or just throw it out. CDVDgetDiskType() sets type to "NODISC" anyway. + + cdvd.Type = CDVDgetDiskType(); + if (cdvd.Type == CDVD_TYPE_PS2CD && needReset == 1) { + char str[256]; + if (GetPS2ElfName(str) == 1) { + cdvd.Type = CDVD_TYPE_PSCD; + } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. + } // ENDIF- Is the type listed as a PS2 CD? + return(cdvd.Type); +} // END cdvdGetDiskType() + + +// check whether disc is single or dual layer +// if its dual layer, check what the disctype is and what sector number +// layer1 starts at +// +// args: gets value for dvd type (0=single layer, 1=ptp, 2=otp) +// gets value for start lsn of layer1 +// returns: 1 if on dual layer disc +// 0 if not on dual layer disc +s32 cdvdReadDvdDualInfo(s32* dualType, u32* layer1Start) +{ + u8 toc[2064]; + *dualType = 0; + *layer1Start = 0; + + // if error getting toc, settle for single layer disc ;) + if(cdvdGetToc(toc)) + return 0; + if(toc[14] & 0x60) + { + if(toc[14] & 0x10) + { + // otp dvd + *dualType = 2; + *layer1Start = (toc[25]<<16) + (toc[26]<<8) + (toc[27]) - 0x30000 + 1; + } + else + { + // ptp dvd + *dualType = 1; + *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; + } + } + else + { + // single layer dvd + *dualType = 0; + *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; + } + + return 1; +} + + +#include + +void cdvdReset() +{ +#ifdef _WIN32 + SYSTEMTIME st; + //Get and set the internal clock to time + GetSystemTime(&st); +#else + time_t traw; + struct tm* ptlocal; + time(&traw); + ptlocal = localtime(&traw); +#endif + + memset(&cdvd, 0, sizeof(cdvd)); + cdvd.sDataIn = 0x40; + cdvd.Ready = 0x4e; + cdCaseopen = 0; + cdvd.Speed = 4; + cdvd.BlockSize = 2064; + cdvdReadTimeRcnt(0); + + // any random valid date will do + cdvd.RTC.hour = 1; + cdvd.RTC.day = 25; + cdvd.RTC.month = 5; + cdvd.RTC.year = 2007; + +#ifndef _DEBUG +#ifdef _WIN32 + cdvd.RTC.second = (u8)(st.wSecond); + cdvd.RTC.minute = (u8)(st.wMinute); + cdvd.RTC.hour = (u8)(st.wHour+1)%24; + cdvd.RTC.day = (u8)(st.wDay); + cdvd.RTC.month = (u8)(st.wMonth); + cdvd.RTC.year = (u8)(st.wYear - 2000); +#else + cdvd.RTC.second = ptlocal->tm_sec; + cdvd.RTC.minute = ptlocal->tm_min; + cdvd.RTC.hour = ptlocal->tm_hour; + cdvd.RTC.day = ptlocal->tm_mday; + cdvd.RTC.month = ptlocal->tm_mon; + cdvd.RTC.year = ptlocal->tm_year; +#endif +#endif + +} +void cdvdReadTimeRcnt(int mode){ // Mode 0 is DVD, Mode 1 is CD + int readspeed = 0; // 1 Sector size + int amount = 0; // Total bytes transfered at 1x speed + //if(mode) amount = 153600; + //else + amount = cdvd.BlockSize; // in Bytes + if(mode == 0) + readspeed = ((PSXCLK /1382400)/* 1 Byte Time @ x1 */ * amount) / cdvd.Speed; //1350KB = dvd x 1 + else + readspeed = ((PSXCLK /153600)/* 1 Byte Time @ x1 */ * amount) / cdvd.Speed; //150KB = cd x 1 + + //amount = 1280000; + + + //readsize = amount / cdvd.BlockSize; // Time taken for 1 sector to be read + cdvdReadTime = readspeed; //(PSXCLK / readspeed); /// amount; + //SysPrintf("CDVD Cnt Time = %x\n", cdvdReadTime); +} + +int cdvdFreeze(gzFile f, int Mode) { + gzfreeze(&cdvd, sizeof(cdvd)); + if (Mode == FREEZE_LOAD) { + if (cdvd.Reading) { + cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + } + } + + return 0; +} + +int cdvdInterrupt() { + return 1; +} + +// Modified by (efp) - 16/01/2006 +void cdvdNewDiskCB() { + cdvd.Type = CDVDgetDiskType(); + if(cdvd.Type == CDVD_TYPE_PS2CD) { + char str[256]; + if(GetPS2ElfName(str) == 1) { + cdvd.Type = CDVD_TYPE_PSCD; + } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. + } // ENDIF- Is the type listed as a PS2 CD? +} // END cdvdNewDiskCB() + +void mechaDecryptBytes(unsigned char* buffer, int size) +{ + int i; + + int shiftAmount = (cdvd.decSet>>4) & 7; + int doXor = (cdvd.decSet) & 1; + int doShift = (cdvd.decSet) & 2; + unsigned char key = cdvd.Key[4]; + + for(i=0; i>shiftAmount) | (buffer[i]<<(8-shiftAmount)); + } +} + +int cdvdReadSector() { + s32 bcr; + +#ifdef CDR_LOG + CDR_LOG("SECTOR %d (BCR %x;%x)\n", cdvd.Sector, HW_DMA3_BCR_H16, HW_DMA3_BCR_L16); +#endif + bcr = (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4; + if (bcr < cdvd.BlockSize) { + //SysPrintf("*PCSX2*: cdvdReadSector: bcr < cdvd.BlockSize; %x < %x\n", bcr, cdvd.BlockSize); + if (HW_DMA3_CHCR & 0x01000000) { + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); + } + return -1; + } + FreezeMMXRegs(1); + // if raw dvd sector 'fill in the blanks' + if (cdvd.BlockSize == 2064) { + // get info on dvd type and layer1 start + u32 layer1Start; + s32 dualType; + s32 layerNum; + u32 lsn = cdvd.Sector; + cdvdReadDvdDualInfo(&dualType, &layer1Start); + + if((dualType == 1) && (lsn >= layer1Start)) { + // dual layer ptp disc + layerNum = 1; + lsn = lsn-layer1Start + 0x30000; + } else if((dualType == 2) && (lsn >= layer1Start)) { + // dual layer otp disc + layerNum = 1; + lsn = ~(layer1Start+0x30000 - 1); + } else { + // single layer disc + // or on first layer of dual layer disc + layerNum = 0; + lsn += 0x30000; + } // ENDLONGIF- Assumed the other dualType is 0. + + PSXMu8(HW_DMA3_MADR+0) = 0x20 | layerNum; + PSXMu8(HW_DMA3_MADR+1) = (u8)(lsn >> 16); + PSXMu8(HW_DMA3_MADR+2) = (u8)(lsn >> 8); + PSXMu8(HW_DMA3_MADR+3) = (u8)(lsn ); + + // sector IED (not calculated at present) + PSXMu8(HW_DMA3_MADR+4) = 0; + PSXMu8(HW_DMA3_MADR+5) = 0; + + // sector CPR_MAI (not calculated at present) + PSXMu8(HW_DMA3_MADR+ 6) = 0; + PSXMu8(HW_DMA3_MADR+ 7) = 0; + PSXMu8(HW_DMA3_MADR+ 8) = 0; + PSXMu8(HW_DMA3_MADR+ 9) = 0; + PSXMu8(HW_DMA3_MADR+10) = 0; + PSXMu8(HW_DMA3_MADR+11) = 0; + + // normal 2048 bytes of sector data + memcpy_fast(PSXM(HW_DMA3_MADR+12), cdr.pTransfer, 2048); + + // 4 bytes of edc (not calculated at present) + PSXMu8(HW_DMA3_MADR+2060) = 0; + PSXMu8(HW_DMA3_MADR+2061) = 0; + PSXMu8(HW_DMA3_MADR+2062) = 0; + PSXMu8(HW_DMA3_MADR+2063) = 0; + } else { + // normal read + memcpy_fast(PSXM(HW_DMA3_MADR), cdr.pTransfer, cdvd.BlockSize); + } + // decrypt sector's bytes + if(cdvd.decSet) + mechaDecryptBytes((unsigned char*)PSXM(HW_DMA3_MADR), cdvd.BlockSize); + +// SysPrintf("sector %x;%x;%x\n", PSXMu8(HW_DMA3_MADR+0), PSXMu8(HW_DMA3_MADR+1), PSXMu8(HW_DMA3_MADR+2)); + + HW_DMA3_BCR_H16-= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4)); + HW_DMA3_MADR+= cdvd.BlockSize; + FreezeMMXRegs(0); + + return 0; +} + +void cdvdReadInterrupt() { + + //SysPrintf("cdvdReadInterrupt %x %x %x %x %x\n", cpuRegs.interrupt, cdvd.Readed, cdvd.Reading, cdvd.nSectors, (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4); + cdvd.Ready = 0x00; + if (cdvd.Readed == 0) { + cdvd.RetryCntP = 0; + cdvd.Reading = 1; + cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + cdvd.Readed = 1; + cdvd.Status = CDVD_STATUS_SEEK_COMPLETE; + + CDVDREAD_INT(cdvdReadTime); + return; + } + + if (cdvd.Reading == 1) { + if (cdvd.RErr == 0) { + cdr.pTransfer = CDVDgetBuffer(); + } else cdr.pTransfer = NULL; + if (cdr.pTransfer == NULL) { + cdvd.RetryCntP++; + SysPrintf("READ ERROR %d\n", cdvd.Sector); + if (cdvd.RetryCntP <= cdvd.RetryCnt) { + cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + CDVDREAD_INT(cdvdReadTime); + return; + } + } + cdvd.Reading = 0; + } + if (cdvdReadSector() == -1) { + assert( (int)cdvdReadTime > 0 ); + CDVDREAD_INT(cdvdReadTime); + return; + } + + cdvd.Sector++; + + if (--cdvd.nSectors <= 0) { + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); + cdvd.Ready = 0x4e; + psxRegs.interrupt&= ~(1 << 19); + return; + } + + cdvd.RetryCntP = 0; + cdvd.Reading = 1; + cdr.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + CDVDREAD_INT(cdvdReadTime); + return; +} + +u8 monthmap[13] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +void cdvdVsync() { + cdvd.RTCcount++; + if (cdvd.RTCcount < ((Config.PsxType & 1) ? 50 : 60)) return; + cdvd.RTCcount = 0; + + cdvd.RTC.second++; + if (cdvd.RTC.second < 60) return; + cdvd.RTC.second = 0; + + cdvd.RTC.minute++; + if (cdvd.RTC.minute < 60) return; + cdvd.RTC.minute = 0; + + cdvd.RTC.hour++; + if (cdvd.RTC.hour < 24) return; + cdvd.RTC.hour = 0; + + cdvd.RTC.day++; + if (cdvd.RTC.day <= monthmap[cdvd.RTC.month-1]) return; + cdvd.RTC.day = 1; + + cdvd.RTC.month++; + if (cdvd.RTC.month < 12) return; + cdvd.RTC.month = 1; + + cdvd.RTC.year++; + if (cdvd.RTC.year < 100) return; + cdvd.RTC.year = 0; +} + + +u8 cdvdRead04(void) { // NCOMMAND +#ifdef CDR_LOG + CDR_LOG("cdvdRead04(NCMD) %x\n", cdvd.nCommand); +#endif + return cdvd.nCommand; +} + +u8 cdvdRead05(void) { // N-READY +#ifdef CDR_LOG + CDR_LOG("cdvdRead05(NReady) %x\n", cdvd.Ready); +#endif + return cdvd.Ready; +} + +u8 cdvdRead06(void) { // ERROR +#ifdef CDR_LOG + CDR_LOG("cdvdRead06(Error) %x\n", cdvd.Error); +#endif + + return cdvd.Error; +} + +u8 cdvdRead07(void) { // BREAK +#ifdef CDR_LOG + CDR_LOG("cdvdRead07(Break) %x\n", 0); +#endif + return 0; +} + +u8 cdvdRead08(void) { // INTR_STAT +#ifdef CDR_LOG + CDR_LOG("cdvdRead08(IntrReason) %x\n", cdvd.PwOff); +#endif + return cdvd.PwOff; +} + +u8 cdvdRead0A(void) { // STATUS +#ifdef CDR_LOG + CDR_LOG("cdvdRead0A(Status) %x\n", cdvd.Status); +#endif + return cdvd.Status; +} + +u8 cdvdRead0B(void) { // TRAY-STATE (if tray has been opened) + u8 tray = cdvdGetTrayStatus(); +#ifdef CDR_LOG + CDR_LOG("cdvdRead0B(Tray) %x\n", tray); +#endif + return tray; +} + +u8 cdvdRead0C(void) { // CRT MINUTE +#ifdef CDR_LOG + CDR_LOG("cdvdRead0C(Min) %x\n", itob((u8)(cdvd.Sector/(60*75)))); +#endif + return itob((u8)(cdvd.Sector/(60*75))); +} + +u8 cdvdRead0D(void) { // CRT SECOND +#ifdef CDR_LOG + CDR_LOG("cdvdRead0D(Sec) %x\n", itob((u8)((cdvd.Sector/75)%60)+2)); +#endif + return itob((u8)((cdvd.Sector/75)%60)+2); +} + +u8 cdvdRead0E(void) { // CRT FRAME +#ifdef CDR_LOG + CDR_LOG("cdvdRead0E(Frame) %x\n", itob((u8)(cdvd.Sector%75))); +#endif + return itob((u8)(cdvd.Sector%75)); +} + +u8 cdvdRead0F(void) { // TYPE + u8 type = cdvdGetDiskType(); +#ifdef CDR_LOG + CDR_LOG("cdvdRead0F(Disc Type) %x\n", type); +#endif + return type; +} + +u8 cdvdRead13(void) { // UNKNOWN +#ifdef CDR_LOG + CDR_LOG("cdvdRead13(Unknown) %x\n", 4); +#endif + return 4; +} + +u8 cdvdRead15(void) { // RSV +#ifdef CDR_LOG + CDR_LOG("cdvdRead15(RSV)\n"); +#endif + return 0x01; // | 0x80 for ATAPI mode +} + +u8 cdvdRead16(void) { // SCOMMAND +#ifdef CDR_LOG + CDR_LOG("cdvdRead16(SCMD) %x\n", cdvd.sCommand); +#endif + return cdvd.sCommand; +} + +u8 cdvdRead17(void) { // SREADY +#ifdef CDR_LOG + CDR_LOG("cdvdRead17(SReady) %x\n", cdvd.sDataIn); +#endif + return cdvd.sDataIn; +} + +u8 cdvdRead18(void) { // SDATAOUT + u8 ret=0; + + if ((cdvd.sDataIn & 0x40) == 0) { + if (cdvd.ResultP < cdvd.ResultC) { + cdvd.ResultP++; + if (cdvd.ResultP >= cdvd.ResultC) cdvd.sDataIn|= 0x40; + ret = cdvd.Result[cdvd.ResultP-1]; + } + } + +#ifdef CDR_LOG + CDR_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)\n", ret, cdvd.ResultC, cdvd.ResultP); +#endif + + return ret; +} + +u8 cdvdRead20(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead20(Key0) %x\n", cdvd.Key[0]); +#endif + return cdvd.Key[0]; +} + +u8 cdvdRead21(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead21(Key1) %x\n", cdvd.Key[1]); +#endif + return cdvd.Key[1]; +} + +u8 cdvdRead22(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead22(Key2) %x\n", cdvd.Key[2]); +#endif + return cdvd.Key[2]; +} + +u8 cdvdRead23(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead23(Key3) %x\n", cdvd.Key[3]); +#endif + return cdvd.Key[3]; +} + +u8 cdvdRead24(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead24(Key4) %x\n", cdvd.Key[4]); +#endif + return cdvd.Key[4]; +} + +u8 cdvdRead28(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead28(Key5) %x\n", cdvd.Key[5]); +#endif + return cdvd.Key[5]; +} + +u8 cdvdRead29(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead29(Key6) %x\n", cdvd.Key[6]); +#endif + return cdvd.Key[6]; +} + +u8 cdvdRead2A(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead2A(Key7) %x\n", cdvd.Key[7]); +#endif + return cdvd.Key[7]; +} + +u8 cdvdRead2B(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead2B(Key8) %x\n", cdvd.Key[8]); +#endif + return cdvd.Key[8]; +} + +u8 cdvdRead2C(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead2C(Key9) %x\n", cdvd.Key[9]); +#endif + return cdvd.Key[9]; +} + +u8 cdvdRead30(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead30(Key10) %x\n", cdvd.Key[10]); +#endif + return cdvd.Key[10]; +} + +u8 cdvdRead31(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead31(Key11) %x\n", cdvd.Key[11]); +#endif + return cdvd.Key[11]; +} + +u8 cdvdRead32(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead32(Key12) %x\n", cdvd.Key[12]); +#endif + return cdvd.Key[12]; +} + +u8 cdvdRead33(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead33(Key13) %x\n", cdvd.Key[13]); +#endif + return cdvd.Key[13]; +} + +u8 cdvdRead34(void) { +#ifdef CDR_LOG + CDR_LOG("cdvdRead34(Key14) %x\n", cdvd.Key[14]); +#endif + return cdvd.Key[14]; +} + +u8 cdvdRead38(void) { // valid parts of key data (first and last are valid) +#ifdef CDR_LOG + CDR_LOG("cdvdRead38(KeysValid) %x\n", cdvd.Key[15]); +#endif + return cdvd.Key[15]; +} + +u8 cdvdRead39(void) { // KEY-XOR +#ifdef CDR_LOG + CDR_LOG("cdvdRead39(KeyXor) %x\n", cdvd.KeyXor); +#endif + return cdvd.KeyXor; +} + +u8 cdvdRead3A(void) { // DEC_SET +#ifdef CDR_LOG + CDR_LOG("cdvdRead3A(DecSet) %x\n", cdvd.decSet); +#endif + SysPrintf("DecSet Read: %02X\n", cdvd.decSet); + return cdvd.decSet; +} + + + +void cdvdWrite04(u8 rt) { // NCOMMAND + +#ifdef CDR_LOG + CDR_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)\n", nCmdName[rt], rt, cdvd.ParamP); +#endif + cdvd.nCommand = rt; + cdvd.Status = CDVD_STATUS_NONE; + switch (rt) { + case 0x00: // CdNop + case 0x01: // CdNop_ + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + + // from an emulation point of view there is not much need to do anything for these + case 0x02: // CdStandby + case 0x03: // CdStop + case 0x04: // CdPause + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + // should we change the sector location here? + case 0x05: // CdSeek + cdvd.Sector = *(int*)(cdvd.Param+0); + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + + case 0x06: // CdRead + cdvd.Sector = *(int*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; + else cdvd.RetryCnt = cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + switch (cdvd.Param[9]) { + case 0x01: cdvd.Speed = 1; break; // CD + case 0x02: cdvd.Speed = 2; break; // CD + case 0x03: cdvd.Speed = 4; break; // CD + case 0x04: cdvd.Speed = 12; break; // CD + default: cdvd.Speed = 24; break; // CD + } + switch (cdvd.Param[10]) { + case 2: cdvd.ReadMode = CDVD_MODE_2340; cdvd.BlockSize = 2340; break; + case 1: cdvd.ReadMode = CDVD_MODE_2328; cdvd.BlockSize = 2328; break; + case 0: default: cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2048; break; + } + if(cdvd.Speed > 4) cdvdReadTimeRcnt(1); + else cdvdReadTimeRcnt(0); +#ifdef CDR_LOG + CDR_LOG( "CdRead: %d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); +#endif + SysPrintf("CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + + cdvd.Readed = 0; + cdvd.PwOff = 2;//cmdcmplt + CDVDREAD_INT(1); + + break; + + case 0x07: // CdReadCDDA + case 0x0E: // CdReadXCDDA + cdvd.Sector = *(int*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; + else cdvd.RetryCnt = cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + switch (cdvd.Param[9]) { + case 0x01: cdvd.Speed = 1; break; + case 0x02: cdvd.Speed = 2; break; + case 0x03: cdvd.Speed = 4; break; + case 0x04: cdvd.Speed = 12; break; + default: cdvd.Speed = 24; break; + } + switch (cdvd.Param[10]) { + case 1: cdvd.ReadMode = CDVD_MODE_2368; cdvd.BlockSize = 2368; break; + case 2: + case 0: cdvd.ReadMode = CDVD_MODE_2352; cdvd.BlockSize = 2352; break; + } + cdvdReadTimeRcnt(1); + SysPrintf("CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + + cdvd.Readed = 0; + cdvd.PwOff = 2;//cmdcmplt + CDVDREAD_INT(1); + break; + + case 0x08: // DvdRead + cdvd.Sector = *(int*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; + else cdvd.RetryCnt = cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + cdvd.Speed = 4; + cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2064; // Why oh why was it 2064 + cdvdReadTimeRcnt(0); +#ifdef CDR_LOG + CDR_LOG( "DvdRead: %d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); +#endif + SysPrintf("DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + cdvd.Readed = 0; + cdvd.PwOff = 2;//cmdcmplt + CDVDREAD_INT(1); + break; + + case 0x09: // CdGetToc & cdvdman_call19 + //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 + //the code below handles only CdGetToc! + //if(cdvd.Param[0]==0x01) + //{ + SysPrintf("CDGetToc Param[0]=%d, Param[1]=%d\n",cdvd.Param[0],cdvd.Param[1]); + //} + cdvdGetToc(PSXM(HW_DMA3_MADR)); + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); + break; + + case 0x0C: // CdReadKey + { + unsigned char arg0 = cdvd.Param[0]; + unsigned short arg1 = cdvd.Param[1] | (cdvd.Param[2]<<8); + unsigned int arg2 = cdvd.Param[3] | (cdvd.Param[4]<<8) | (cdvd.Param[5]<<16) | (cdvd.Param[6]<<24); + SysPrintf("cdvdReadKey(%d, %d, %d)\n", arg0, arg1, arg2); + cdvdReadKey(arg0, arg1, arg2, cdvd.Key); + cdvd.KeyXor = 0x00; + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + } + + case 0x0F: // CdChgSpdlCtrl + SysPrintf("sceCdChgSpdlCtrl(%d)\n", cdvd.Param[0]); + cdvd.PwOff = 2;//cmdcmplt + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + + default: + SysPrintf("NCMD Unknown %x\n", rt); + psxHu32(0x1070)|= 0x4; + //SBUS + hwIntcIrq(INTC_SBUS); + break; + } + cdvd.ParamP = 0; cdvd.ParamC = 0; +} + +void cdvdWrite05(u8 rt) { // NDATAIN +#ifdef CDR_LOG + CDR_LOG("cdvdWrite05(NDataIn) %x\n", rt); +#endif + if (cdvd.ParamP < 32) { + cdvd.Param[cdvd.ParamP++] = rt; + cdvd.ParamC++; + } +} + +void cdvdWrite06(u8 rt) { // HOWTO +#ifdef CDR_LOG + CDR_LOG("cdvdWrite06(HowTo) %x\n", rt); +#endif + cdvd.HowTo = rt; +} + +void cdvdWrite07(u8 rt) { // BREAK +#ifdef CDR_LOG + CDR_LOG("cdvdWrite07(Break) %x\n", rt); +#endif + SysPrintf("*PCSX2*: CDVD BREAK %x\n" , rt); +} + +/* +Interrupts + +0x00 No interrupt +0x01 Data Ready +0x02 Command Complete +0x03 Acknowledge (reserved) +0x04 End of Data Detected +0x05 Error Detected +0x06 Drive Not Ready +*/ + +void cdvdWrite08(u8 rt) { // INTR_STAT +#ifdef CDR_LOG + CDR_LOG("cdvdWrite08(IntrReason) = ACK(%x)\n", rt); +#endif + cdvd.PwOff &= ~rt; +} + +void cdvdWrite0A(u8 rt) { // STATUS +#ifdef CDR_LOG + CDR_LOG("cdvdWrite0A(Status) %x\n", rt); +#endif +} + +void cdvdWrite0F(u8 rt) { // TYPE +#ifdef CDR_LOG + CDR_LOG("cdvdWrite0F(Type) %x\n", rt); +#endif +SysPrintf("*PCSX2*: CDVD TYPE %x\n", rt); +} + +void cdvdWrite14(u8 rt) { // PS1 MODE?? + u32 cycle = psxRegs.cycle; + + if (rt == 0xFE) SysPrintf("*PCSX2*: go PS1 mode DISC SPEED = FAST\n"); + else SysPrintf("*PCSX2*: go PS1 mode DISC SPEED = %dX\n", rt); + + psxReset(); + psxHu32(0x1f801450) = 0x8; + psxHu32(0x1f801078) = 1; + psxRegs.cycle = cycle; + + // PS1 DEBUGGING +// varLog = 0x09a00000; + +#ifdef PCSX2_DEVBUILD + varLog|= 0x10000000;// | 0x00400000;// | 0x1fe00000; +#endif +} + +void cdvdWrite16(u8 rt) { // SCOMMAND +// cdvdTN diskInfo; +// cdvdTD trackInfo; +// int i, lbn, type, min, sec, frm, address; + int address; + u8 tmp; + +#ifdef CDR_LOG + CDR_LOG("cdvdWrite16: SCMD %s (%x) (ParamP = %x)\n", sCmdName[rt], rt, cdvd.ParamP); +#endif + cdvd.sCommand = rt; + switch (rt) { + +// case 0x01: // GetDiscType - from cdvdman (0:1) +// SetResultSize(1); +// cdvd.Result[0] = 0; +// break; + + case 0x02: // CdReadSubQ (0:11) + SetResultSize(11); + cdvd.Result[0] = cdvdReadSubQ(cdvd.Sector, (cdvdSubQ*)&cdvd.Result[1]); + break; + + case 0x03: // Mecacon-command + if(cdvd.Param[0]==0x00) { + // get mecha version (1:4) + SetResultSize(4); + cdvdGetMechaVer(&cdvd.Result[0]); + } + else if(cdvd.Param[0]==0x44) { + // write console ID (9:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteConsoleID(&cdvd.Param[1]); + } + else if(cdvd.Param[0]==0x45) { + // read console ID (1:9) + SetResultSize(9); + cdvd.Result[0] = cdvdReadConsoleID(&cdvd.Result[1]); + } + else if(cdvd.Param[0]==0xFD) { + // _sceCdReadRenewalDate (1:6) BCD + SetResultSize(6); + cdvd.Result[0] = 0; + cdvd.Result[1] = 0x04;//year + cdvd.Result[2] = 0x12;//month + cdvd.Result[3] = 0x10;//day + cdvd.Result[4] = 0x01;//hour + cdvd.Result[5] = 0x30;//min + } else { + SetResultSize(1); + cdvd.Result[0] = 0x80; + SysPrintf("*Unknown Mecacon Command param[0]=%02X\n", cdvd.Param[0]); + } + break; + + case 0x05: // CdTrayReqState (0:1) - resets the tray open detection + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x06: // CdTrayCtrl (1:1) + SetResultSize(1); + if(cdvd.Param[0] == 0) + cdvd.Result[0] = cdvdCtrlTrayOpen(); + else + cdvd.Result[0] = cdvdCtrlTrayClose(); + break; + + case 0x08: // CdReadRTC (0:8) + SetResultSize(8); + cdvd.Result[0] = 0; + cdvd.Result[1] = itob(cdvd.RTC.second); //Seconds + cdvd.Result[2] = itob(cdvd.RTC.minute); //Minutes + cdvd.Result[3] = itob((cdvd.RTC.hour+8) %24); //Hours + + cdvd.Result[4] = 0; //Nothing + cdvd.Result[5] = itob(cdvd.RTC.day); //Day + if(cdvd.Result[3] <= 7) cdvd.Result[5] += 1; + cdvd.Result[6] = itob(cdvd.RTC.month)+0x80; //Month + cdvd.Result[7] = itob(cdvd.RTC.year); //Year + /*SysPrintf("RTC Read Sec %x Min %x Hr %x Day %x Month %x Year %x\n", cdvd.Result[1], cdvd.Result[2], + cdvd.Result[3], cdvd.Result[5], cdvd.Result[6], cdvd.Result[7]); + SysPrintf("RTC Read Real Sec %d Min %d Hr %d Day %d Month %d Year %d\n", cdvd.RTC.second, cdvd.RTC.minute, + cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/ + + break; + + case 0x09: // sceCdWriteRTC (7:1) + + cdvd.Result[0] = 0; + cdvd.RTC.pad = 0; + + cdvd.RTC.second = btoi(cdvd.Param[cdvd.ParamP-7]); + cdvd.RTC.minute = btoi(cdvd.Param[cdvd.ParamP-6]) % 60; + cdvd.RTC.hour = (btoi(cdvd.Param[cdvd.ParamP-5])+16) % 24; + cdvd.RTC.day = btoi(cdvd.Param[cdvd.ParamP-3]); + if(cdvd.Param[cdvd.ParamP-5] <= 7) cdvd.RTC.day -= 1; + cdvd.RTC.month = btoi(cdvd.Param[cdvd.ParamP-2]-0x80); + cdvd.RTC.year = btoi(cdvd.Param[cdvd.ParamP-1]); + /*SysPrintf("RTC write incomming Sec %x Min %x Hr %x Day %x Month %x Year %x\n", cdvd.Param[cdvd.ParamP-7], cdvd.Param[cdvd.ParamP-6], + cdvd.Param[cdvd.ParamP-5], cdvd.Param[cdvd.ParamP-3], cdvd.Param[cdvd.ParamP-2], cdvd.Param[cdvd.ParamP-1]); + SysPrintf("RTC Write Sec %d Min %d Hr %d Day %d Month %d Year %d\n", cdvd.RTC.second, cdvd.RTC.minute, + cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/ + //memcpy_fast((u8*)&cdvd.RTC, cdvd.Param, 7); + SetResultSize(1); + break; + + case 0x0A: // sceCdReadNVM (2:3) + address = (cdvd.Param[0]<<8) | cdvd.Param[1]; + if (address < 512) { + SetResultSize(3); + cdvd.Result[0] = cdvdReadNVM(&cdvd.Result[1], address*2, 2); + // swap bytes around + tmp = cdvd.Result[1]; + cdvd.Result[1] = cdvd.Result[2]; + cdvd.Result[2] = tmp; + } else { + SetResultSize(1); + cdvd.Result[0] = 0xff; + } + break; + + case 0x0B: // sceCdWriteNVM (4:1) + address = (cdvd.Param[0]<<8) | cdvd.Param[1]; + SetResultSize(1); + if (address < 512) { + // swap bytes around + tmp = cdvd.Param[2]; + cdvd.Param[2] = cdvd.Param[3]; + cdvd.Param[3] = tmp; + cdvd.Result[0] = cdvdWriteNVM(&cdvd.Param[2], address*2, 2); + } else { + cdvd.Result[0] = 0xff; + } + break; + +// case 0x0C: // sceCdSetHDMode (1:1) +// break; + + + case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x12: // sceCdReadILinkId (0:9) + SetResultSize(9); + cdvd.Result[0] = cdvdReadILinkID(&cdvd.Result[1]); + break; + + case 0x13: // sceCdWriteILinkID (8:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteILinkID(&cdvd.Param[1]); + break; + + case 0x14: // CdCtrlAudioDigitalOut (1:1) + //parameter can be 2, 0, ... + SetResultSize(1); + cdvd.Result[0] = 0; //8 is a flag; not used + break; + + case 0x15: // sceCdForbidDVDP (0:1) + //SysPrintf("sceCdForbidDVDP\n"); + SetResultSize(1); + cdvd.Result[0] = 5; + break; + + case 0x16: // AutoAdjustCtrl - from cdvdman (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x17: // CdReadModelNumber (1:9) - from xcdvdman + SetResultSize(9); + cdvd.Result[0] = cdvdReadModelNumber(&cdvd.Result[1], cdvd.Param[0]); + break; + + case 0x18: // CdWriteModelNumber (9:1) - from xcdvdman + SetResultSize(1); + cdvd.Result[0] = cdvdWriteModelNumber(&cdvd.Param[1], cdvd.Param[0]); + break; + +// case 0x19: // sceCdForbidRead (0:1) - from xcdvdman +// break; + + case 0x1A: // sceCdBootCertify (4:1)//(4:16 in psx?) + SetResultSize(1);//on input there are 4 bytes: 1;?10;J;C for 18000; 1;60;E;C for 39002 from ROMVER + cdvd.Result[0]=1;//i guess that means okay + break; + + case 0x1B: // sceCdCancelPOffRdy (0:1) - Call73 from Xcdvdman (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x1C: // sceCdBlueLEDCtl (1:1) - Call72 from Xcdvdman + SetResultSize(1); + cdvd.Result[0] = 0; + break; + +// case 0x1D: // cdvdman_call116 (0:5) - In V10 Bios +// break; + + case 0x1E: // sceRemote2Read (0:5) - // 00 14 AA BB CC -> remote key code + SetResultSize(5); + cdvd.Result[0] = 0x00; + cdvd.Result[1] = 0x14; + cdvd.Result[2] = 0x00; + cdvd.Result[3] = 0x00; + cdvd.Result[4] = 0x00; + break; + +// case 0x1F: // sceRemote2_7 (2:1) - cdvdman_call117 +// break; + + case 0x20: // sceRemote2_6 (0:3) // 00 01 00 + SetResultSize(3); + cdvd.Result[0] = 0x00; + cdvd.Result[1] = 0x01; + cdvd.Result[2] = 0x00; + break; + +// case 0x21: // sceCdWriteWakeUpTime (8:1) +// break; + + case 0x22: // sceCdReadWakeUpTime (0:10) + SetResultSize(10); + cdvd.Result[0] = 0; + cdvd.Result[1] = 0; + cdvd.Result[2] = 0; + cdvd.Result[3] = 0; + cdvd.Result[4] = 0; + cdvd.Result[5] = 0; + cdvd.Result[6] = 0; + cdvd.Result[7] = 0; + cdvd.Result[8] = 0; + cdvd.Result[9] = 0; + break; + + case 0x24: // sceCdRCBypassCtrl (1:1) - In V10 Bios + // FIXME: because PRId<0x23, the bit 0 of sio2 don't get updated 0xBF808284 + SetResultSize(1); + cdvd.Result[0] = 0; + break; + +// case 0x25: // cdvdman_call120 (1:1) - In V10 Bios +// break; + +// case 0x26: // cdvdman_call128 (0,3) - In V10 Bios +// break; + +// case 0x27: // cdvdman_call148 (0:13) - In V10 Bios +// break; + +// case 0x28: // cdvdman_call150 (1:1) - In V10 Bios +// break; + + case 0x29: //sceCdNoticeGameStart (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + +// case 0x2C: //sceCdXBSPowerCtl (2:2) +// break; + +// case 0x2D: //sceCdXLEDCtl (2:2) +// break; + +// case 0x2E: //sceCdBuzzerCtl (0:1) +// break; + +// case 0x2F: //cdvdman_call167 (16:1) +// break; + +// case 0x30: //cdvdman_call169 (1:9) +// break; + + case 0x31: //sceCdSetMediumRemoval (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x32: //sceCdGetMediumRemoval (0:2) + SetResultSize(2); + cdvd.Result[0] = 0; + cdvd.Result[0] = 0; + break; + +// case 0x33: //sceCdXDVRPReset (1:1) +// break; + + case 0x36: //cdvdman_call189 [__sceCdReadRegionParams - made up name] (0:15) i think it is 16, not 15 + SetResultSize(15); + cdvdGetMechaVer(&cdvd.Result[1]); + cdvd.Result[0] = cdvdReadRegionParams(&cdvd.Result[3]);//size==8 + SysPrintf("REGION PARAMS = %s %s\n", mg_zones[cdvd.Result[1]], &cdvd.Result[3]); + cdvd.Result[1] = 1 << cdvd.Result[1]; //encryption zone; see offset 0x1C in encrypted headers + ////////////////////////////////////////// + cdvd.Result[2] = 0; //?? +// cdvd.Result[3] == ROMVER[4] == *0xBFC7FF04 +// cdvd.Result[4] == OSDVER[4] == CAP Jjpn, Aeng, Eeng, Heng, Reng, Csch, Kkor? +// cdvd.Result[5] == OSDVER[5] == small +// cdvd.Result[6] == OSDVER[6] == small +// cdvd.Result[7] == OSDVER[7] == small +// cdvd.Result[8] == VERSTR[0x22] == *0xBFC7FF52 +// cdvd.Result[9] == DVDID J U O E A R C M +// cdvd.Result[10]== 0; //?? + cdvd.Result[11] = 0; //?? + cdvd.Result[12] = 0; //?? + ////////////////////////////////////////// + cdvd.Result[13] = 0; //0xFF - 77001 + cdvd.Result[14] = 0; //?? + break; + + case 0x37: //called from EECONF [sceCdReadMAC - made up name] (0:9) + SetResultSize(9); + cdvd.Result[0] = cdvdReadMAC(&cdvd.Result[1]); + break; + + case 0x38: //used to fix the MAC back after accidentally trashed it :D [sceCdWriteMAC - made up name] (8:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteMAC(&cdvd.Param[0]); + break; + + case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1] + SetResultSize(1); + cdvd.Result[0] = cdvdWriteRegionParams(&cdvd.Param[2]); + break; + + case 0x40: // CdOpenConfig (3:1) + cdvd.CReadWrite = cdvd.Param[0]; + cdvd.COffset = cdvd.Param[1]; + cdvd.CNumBlocks = cdvd.Param[2]; + cdvd.CBlockIndex= 0; + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x41: // CdReadConfig (0:16) + SetResultSize(16); + cdvdReadConfig(&cdvd.Result[0]); + break; + + case 0x42: // CdWriteConfig (16:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteConfig(&cdvd.Param[0]); + break; + + case 0x43: // CdCloseConfig (0:1) + cdvd.CReadWrite = 0; + cdvd.COffset = 0; + cdvd.CNumBlocks = 0; + cdvd.CBlockIndex= 0; + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x80: // secrman: __mechacon_auth_0x80 + cdvd.mg_datatype = 0;//data + SetResultSize(1);//in:1 + cdvd.Result[0] = 0; + break; + + case 0x81: // secrman: __mechacon_auth_0x81 + cdvd.mg_datatype = 0;//data + SetResultSize(1);//in:1 + cdvd.Result[0] = 0; + break; + + case 0x82: // secrman: __mechacon_auth_0x82 + SetResultSize(1);//in:16 + cdvd.Result[0] = 0; + break; + + case 0x83: // secrman: __mechacon_auth_0x83 + SetResultSize(1);//in:8 + cdvd.Result[0] = 0; + break; + + case 0x84: // secrman: __mechacon_auth_0x84 + SetResultSize(1+8+4);//in:0 + cdvd.Result[0] = 0; + + cdvd.Result[1] = 0x21; + cdvd.Result[2] = 0xdc; + cdvd.Result[3] = 0x31; + cdvd.Result[4] = 0x96; + cdvd.Result[5] = 0xce; + cdvd.Result[6] = 0x72; + cdvd.Result[7] = 0xe0; + cdvd.Result[8] = 0xc8; + + cdvd.Result[9] = 0x69; + cdvd.Result[10] = 0xda; + cdvd.Result[11] = 0x34; + cdvd.Result[12] = 0x9b; + break; + + case 0x85: // secrman: __mechacon_auth_0x85 + SetResultSize(1+4+8);//in:0 + cdvd.Result[0] = 0; + + cdvd.Result[1] = 0xeb; + cdvd.Result[2] = 0x01; + cdvd.Result[3] = 0xc7; + cdvd.Result[4] = 0xa9; + + cdvd.Result[ 5] = 0x3f; + cdvd.Result[ 6] = 0x9c; + cdvd.Result[ 7] = 0x5b; + cdvd.Result[ 8] = 0x19; + cdvd.Result[ 9] = 0x31; + cdvd.Result[10] = 0xa0; + cdvd.Result[11] = 0xb3; + cdvd.Result[12] = 0xa3; + break; + + case 0x86: // secrman: __mechacon_auth_0x86 + SetResultSize(1);//in:16 + cdvd.Result[0] = 0; + break; + + case 0x87: // secrman: __mechacon_auth_0x87 + SetResultSize(1);//in:8 + cdvd.Result[0] = 0; + break; + + case 0x8D: // sceMgWriteData + SetResultSize(1);//in:length<=16 + if (cdvd.mg_size + cdvd.ParamC > cdvd.mg_maxsize) + cdvd.Result[0] = 0x80; + else{ + FreezeMMXRegs(1); + memcpy_fast(cdvd.mg_buffer + cdvd.mg_size, cdvd.Param, cdvd.ParamC); + FreezeMMXRegs(0); + cdvd.mg_size += cdvd.ParamC; + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + } + break; + + case 0x8E: // sceMgReadData + SetResultSize(min(16, cdvd.mg_size)); + FreezeMMXRegs(1); + memcpy_fast(cdvd.Result, cdvd.mg_buffer, cdvd.ResultC); + cdvd.mg_size -= cdvd.ResultC; + memcpy_fast(cdvd.mg_buffer, cdvd.mg_buffer+cdvd.ResultC, cdvd.mg_size); + FreezeMMXRegs(0); + break; + + case 0x88: // secrman: __mechacon_auth_0x88 //for now it is the same; so, fall;) + case 0x8F: // secrman: __mechacon_auth_0x8F + SetResultSize(1);//in:0 + if (cdvd.mg_datatype == 1){// header data + u64* psrc, *pdst; + int bit_ofs, i; + + if (cdvd.mg_maxsize != cdvd.mg_size) goto fail_pol_cal; + if (cdvd.mg_size < 0x20) goto fail_pol_cal; + if (cdvd.mg_size != *(u16*)&cdvd.mg_buffer[0x14]) goto fail_pol_cal; + SysPrintf("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=", + *(u32*)&cdvd.mg_buffer[0x10], *(u16*)&cdvd.mg_buffer[0x14], *(u16*)&cdvd.mg_buffer[0x16], + *(u16*)&cdvd.mg_buffer[0x18], *(u16*)&cdvd.mg_buffer[0x1A]); + for (i=0; i<8; i++) + if (cdvd.mg_buffer[0x1C] & (1<> 0) & 0xFF; + cdvd.Result[2] = (cdvd.mg_size >> 8) & 0xFF; + break; + + case 0x92: // sceMgWriteDatainLength + cdvd.mg_size = 0; + cdvd.mg_datatype = 0;//data (encrypted) + cdvd.mg_maxsize = cdvd.Param[0] | (((int)cdvd.Param[1])<<8); + SetResultSize(1);//in:2 + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + break; + + case 0x93: // sceMgWriteDataoutLength + SetResultSize(1);//in:2 + if (((cdvd.Param[0] | (((int)cdvd.Param[1])<<8)) == cdvd.mg_size) && (cdvd.mg_datatype == 0)){ + cdvd.mg_maxsize = 0; // don't allow any write + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + }else + cdvd.Result[0] = 0x80; + break; + + case 0x94: // sceMgReadKbit - read first half of BIT key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + + ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kbit)[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kbit)[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit, 8); + break; + + case 0x95: // sceMgReadKbit2 - read second half of BIT key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kbit+8))[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kbit+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit+8, 8); + break; + + case 0x96: // sceMgReadKcon - read first half of content key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kcon)[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kcon)[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon, 8); + break; + + case 0x97: // sceMgReadKcon2 - read second half of content key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kcon+8))[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kcon+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon+8, 8); + break; + + default: + // fake a 'correct' command + SysPrintf("SCMD Unknown %x\n", rt); + SetResultSize(1); //in:0 + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + break; + } + //SysPrintf("SCMD - %x\n", rt); + cdvd.ParamP = 0; cdvd.ParamC = 0; +} + +void cdvdWrite17(u8 rt) { // SDATAIN +#ifdef CDR_LOG + CDR_LOG("cdvdWrite17(SDataIn) %x\n", rt); +#endif + if (cdvd.ParamP < 32) { + cdvd.Param[cdvd.ParamP++] = rt; + cdvd.ParamC++; + } +} + +void cdvdWrite18(u8 rt) { // SDATAOUT +#ifdef CDR_LOG + CDR_LOG("cdvdWrite18(SDataOut) %x\n", rt); +#endif + SysPrintf("*PCSX2* SDATAOUT\n"); +} + +void cdvdWrite3A(u8 rt) { // DEC-SET +#ifdef CDR_LOG + CDR_LOG("cdvdWrite3A(DecSet) %x\n", rt); +#endif + cdvd.decSet = rt; + SysPrintf("DecSet Write: %02X\n", cdvd.decSet); +} + +static int mg_BIToffset(u8 *buffer){ + int i, ofs = 0x20; for (i=0; i<*(u16*)&buffer[0x1A]; i++)ofs+=0x10; + if (*(u16*)&buffer[0x18] & 1)ofs+=buffer[ofs]; + if ((*(u16*)&buffer[0x18] & 0xF000)==0)ofs+=8; + return ofs + 0x20; +} diff --git a/pcsx2/CDVD.h b/pcsx2/CDVD.h new file mode 100644 index 0000000000..0099c942f8 --- /dev/null +++ b/pcsx2/CDVD.h @@ -0,0 +1,144 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __CDVD_H__ +#define __CDVD_H__ + +#include "PsxCommon.h" + +typedef struct { + u8 status; + u8 second; + u8 minute; + u8 hour; + u8 pad; + u8 day; + u8 month; + u8 year; +} cdvdRTC; + +typedef struct { + u8 nCommand; + u8 Ready; + u8 Error; + u8 PwOff; + u8 Status; + u8 Type; + u8 sCommand; + u8 sDataIn; + u8 sDataOut; + u8 HowTo; + + u8 Param[32]; + u8 Result[32]; + + u8 ParamC; + u8 ParamP; + u8 ResultC; + u8 ResultP; + + u8 CBlockIndex; + u8 COffset; + u8 CReadWrite; + u8 CNumBlocks; + + int RTCcount; + cdvdRTC RTC; + + u32 Sector; + int nSectors; + int Readed; + int Reading; + int ReadMode; + int BlockSize; + int Speed; + int RetryCnt; + int RetryCntP; + int RErr; + int SpindlCtrl; + + u8 Key[16]; + u8 KeyXor; + u8 decSet; + + u8 mg_buffer[65536]; + int mg_size; + int mg_maxsize; + int mg_datatype;//0-data(encrypted); 1-header + u8 mg_kbit[16];//last BIT key 'seen' + u8 mg_kcon[16];//last content key 'seen' +// char Unused[4096]; +} cdvdStruct; + +extern cdvdStruct cdvd; + +void cdvdReset(); +void cdvdReadTimeRcnt(int mode); +void cdvdVsync(); +int cdvdInterrupt(); +int cdvdFreeze(gzFile f, int Mode); +void cdvdReadInterrupt(); +void cdvdNewDiskCB(); +u8 cdvdRead04(void); +u8 cdvdRead05(void); +u8 cdvdRead06(void); +u8 cdvdRead07(void); +u8 cdvdRead08(void); +u8 cdvdRead0A(void); +u8 cdvdRead0B(void); +u8 cdvdRead0C(void); +u8 cdvdRead0D(void); +u8 cdvdRead0E(void); +u8 cdvdRead0F(void); +u8 cdvdRead13(void); +u8 cdvdRead15(void); +u8 cdvdRead16(void); +u8 cdvdRead17(void); +u8 cdvdRead18(void); +u8 cdvdRead20(void); +u8 cdvdRead21(void); +u8 cdvdRead22(void); +u8 cdvdRead23(void); +u8 cdvdRead24(void); +u8 cdvdRead28(void); +u8 cdvdRead29(void); +u8 cdvdRead2A(void); +u8 cdvdRead2B(void); +u8 cdvdRead2C(void); +u8 cdvdRead30(void); +u8 cdvdRead31(void); +u8 cdvdRead32(void); +u8 cdvdRead33(void); +u8 cdvdRead34(void); +u8 cdvdRead38(void); +u8 cdvdRead39(void); +u8 cdvdRead3A(void); +void cdvdWrite04(u8 rt); +void cdvdWrite05(u8 rt); +void cdvdWrite06(u8 rt); +void cdvdWrite07(u8 rt); +void cdvdWrite08(u8 rt); +void cdvdWrite0A(u8 rt); +void cdvdWrite0F(u8 rt); +void cdvdWrite14(u8 rt); +void cdvdWrite16(u8 rt); +void cdvdWrite17(u8 rt); +void cdvdWrite18(u8 rt); +void cdvdWrite3A(u8 rt); + +#endif /* __CDVD_H__ */ diff --git a/pcsx2/CDVDiso.c b/pcsx2/CDVDiso.c new file mode 100644 index 0000000000..68755b6e7f --- /dev/null +++ b/pcsx2/CDVDiso.c @@ -0,0 +1,853 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + * Fixed CdRead by linuzappz + */ + +#include + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +struct dir_toc_data{ + unsigned int start_LBA; + unsigned int num_sectors; + unsigned int num_entries; + unsigned int current_entry; + unsigned int current_sector; + unsigned int current_sector_offset; + unsigned int inc_dirs; + unsigned char extension_list[128+1]; +}; + +//static u8 cdVolDescriptor[2048]; +static struct dir_toc_data getDirTocData; +static struct cdVolDesc CDVolDesc; + +void _splitpath2(const char *constpath, char *dir, char *fname){ + // 255 char max path-length is an ISO9660 restriction + // we must change this for Joliet or relaxed iso restriction support + static char pathcopy[1024+1]; + + char* slash; + + strncpy(pathcopy, constpath, 1024); + + slash = strrchr (pathcopy, '/'); + + // if the path doesn't contain a '/' then look for a '\' + if (!slash) + slash = strrchr (pathcopy, (int)'\\'); + + // if a slash was found + if (slash != NULL) + { + // null terminate the path + slash[0] = 0; + // and copy the path into 'dir' + strncpy(dir, pathcopy, 1024); + dir[255]=0; + + // copy the filename into 'fname' + strncpy(fname, slash+1, 128); + fname[128]=0; + } + else + { + dir[0] = 0; + + strncpy(fname, pathcopy, 128); + fname[128]=0; + } + +} + +// Used in findfile +int tolower(int c); +int strcasecmp(const char *s1, const char *s2){ + while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) + { + s1++; + s2++; + } + + return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); +} + +// Copy a TOC Entry from the CD native format to our tidier format +void TocEntryCopy(struct TocEntry* tocEntry, struct dirTocEntry* internalTocEntry){ + int i; + int filenamelen; + + tocEntry->fileSize = internalTocEntry->fileSize; + tocEntry->fileLBA = internalTocEntry->fileLBA; + tocEntry->fileProperties = internalTocEntry->fileProperties; + memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); + + if (CDVolDesc.filesystemType == 2){ + // This is a Joliet Filesystem, so use Unicode to ISO string copy + + filenamelen = internalTocEntry->filenameLength/2; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + for (i=0; i < filenamelen; i++) + tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; + + tocEntry->filename[filenamelen] = 0; + } + else{ + filenamelen = internalTocEntry->filenameLength; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + // use normal string copy + strncpy(tocEntry->filename,internalTocEntry->filename,128); + tocEntry->filename[filenamelen] = 0; + } +} + +// Check if a TOC Entry matches our extension list +int TocEntryCompare(char* filename, char* extensions){ + static char ext_list[129]; + + char* token; + + char* ext_point; + + strncpy(ext_list,extensions,128); + ext_list[128]=0; + + token = strtok( ext_list, " ," ); + while( token != NULL ) + { + // if 'token' matches extension of 'filename' + // then return a match + ext_point = strrchr(filename,'.'); + + if (strnicmp(ext_point, token, strlen(token)) == 0) + return (TRUE); + + /* Get next token: */ + token = strtok( NULL, " ," ); + } + + // If not match found then return FALSE + return (FALSE); + +} + +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ + +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + int rmode; + + switch (mode->datapattern) { + case CdSecS2048: + rmode = CDVD_MODE_2048; break; + case CdSecS2328: + rmode = CDVD_MODE_2328; break; + case CdSecS2340: + rmode = CDVD_MODE_2340; break; + default: + return 0; + } + + for (i=0; idatapattern){ + case CdSecS2048: + memcpy_fast((void*)((uptr)buf+2048*i), buff, 2048);break;//only data + case CdSecS2328: + memcpy_fast((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub + case CdSecS2340: + memcpy_fast((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync + } + FreezeMMXRegs(0); + } + return 1; +} + +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + + for (i=lsn; i<(lsn+sectors); i++){ + if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) + return 0; + buff = CDVDgetBuffer(); + if (buff==NULL) return 0; + +// switch (mode->datapattern){ +// case CdSecS2064: + ((u32*)buf)[0] = i + 0x30000; + FreezeMMXRegs(1); + memcpy_fast((u8*)buf+12, buff, 2048); + FreezeMMXRegs(0); + buf = (char*)buf + 2064; break; +// default: +// return 0; +// } + } + + return 1; +} + +/************************************************************** +* The functions below are not exported for normal file-system * +* operations, but are used by the file-system operations, and * +* may also be exported for use via RPC * +**************************************************************/ + +int CDVD_GetVolumeDescriptor(void){ + // Read until we find the last valid Volume Descriptor + int volDescSector; + + static struct cdVolDesc localVolDesc; + +#ifdef DEBUG + SysPrintf("CDVD_GetVolumeDescriptor called\n"); +#endif + + for (volDescSector = 16; volDescSector<20; volDescSector++) + { + CdRead(volDescSector,1,&localVolDesc,&cdReadMode); +// CdSync(0x00); + + // If this is still a volume Descriptor + if (strncmp(localVolDesc.volID, "CD001", 5) == 0) + { + if ((localVolDesc.filesystemType == 1) || + (localVolDesc.filesystemType == 2)) + { + FreezeMMXRegs(1); + memcpy_fast(&CDVolDesc, &localVolDesc, sizeof(struct cdVolDesc)); + FreezeMMXRegs(0); + } + } + else + break; + } + +#ifdef DEBUG + if (CDVolDesc.filesystemType == 1) + SysPrintf("CD FileSystem is ISO9660\n"); + else if (CDVolDesc.filesystemType == 2) + SysPrintf("CD FileSystem is Joliet\n"); + else SysPrintf("Could not detect CD FileSystem type\n"); +#endif +// CdStop(); + + return TRUE; +} + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry){ + static char filename[128+1]; + static char pathname[1024+1]; + static char toc[2048]; + char* dirname; + + + static struct TocEntry localTocEntry; // used for internal checking only + + int found_dir; + + int num_dir_sectors; + int current_sector; + + int dir_lba; + + struct dirTocEntry* tocEntryPointer; + +#ifdef DEBUG + SysPrintf("CDVD_findfile called\n"); +#endif + + //make sure we have good cdReadMode + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; + + _splitpath2(fname, pathname, filename); + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + tocEntryPointer = (struct dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + current_sector = tocEntryPointer->fileLBA; + + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + + while( dirname != NULL ) + { + found_dir = FALSE; +/* + while(tocEntryPointer->length > 0) + { + // while there are still more directory entries then search through + // for the one we want + + if (tocEntryPointer->fileProperties & 0x02) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcasecmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } +*/ + while(1) + { + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) + { + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) + { + SysPrintf("Couldn't Read from CD !\n"); + return -1; + } +// CdSync(0x00); + + tocEntryPointer = (struct dirTocEntry*)toc; + } + else + { + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + + if (tocEntryPointer->fileProperties & 0x02) + { + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + { + SysPrintf("CDVD_findfile: could not find dir\n"); + return -1; + } + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) + { + SysPrintf("Couldn't Read from CD !\n"); + return -1; + } +// CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + tocEntryPointer = (struct dirTocEntry*)toc; + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + +#ifdef DEBUG + SysPrintf("CDVD_findfile: found dir, now looking for file\n"); +#endif + + tocEntryPointer = (struct dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + dir_lba = tocEntryPointer->fileLBA; + + tocEntryPointer = (struct dirTocEntry*)toc; + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + while (num_dir_sectors > 0) + { + while(tocEntryPointer->length != 0) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || + ((filename[strlen(filename)-2] == ';') && + (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && + (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) + { + // if the filename matches then copy the toc Entry + tocEntry->fileLBA = localTocEntry.fileLBA; + tocEntry->fileProperties = localTocEntry.fileProperties; + tocEntry->fileSize = localTocEntry.fileSize; + + strcpy(tocEntry->filename, localTocEntry.filename); + memcpy(tocEntry->date, localTocEntry.date, 7); + +#ifdef DEBUG + SysPrintf("CDVD_findfile: found file\n"); +#endif + + return TRUE; + } + + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + dir_lba++; + + if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ + SysPrintf("Couldn't Read from CD !\n"); + return -1; + } +// CdSync(0x00); + + tocEntryPointer = (struct dirTocEntry*)toc; + } + } + +#ifdef DEBUG + SysPrintf("CDVD_findfile: could not find file\n"); +#endif + + return FALSE; +} + +// This is the RPC-ready function which takes the request to start the tocEntry retrieval +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ +// int dir_depth = 1; + static char toc[2048]; + char* dirname; + int found_dir; + int num_dir_sectors; + unsigned int toc_entry_num; + struct dirTocEntry* tocEntryPointer; + static struct TocEntry localTocEntry; + int current_sector; + + // store the extension list statically for the retrieve function + strncpy(getDirTocData.extension_list, extensions, 128); + getDirTocData.extension_list[128]=0; + + getDirTocData.inc_dirs = inc_dirs; + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); +#endif + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + tocEntryPointer = (struct dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; + current_sector = tocEntryPointer->fileLBA; + + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + // use strtok to get the next dir name + + // if there isnt one, then assume we want the LBA + // for the current one, and exit the while loop + + // if there is another dir name then increment dir_depth + // and look through dir table entries until we find the right name + // if we dont find the right name + // before finding an entry at a higher level (lower num), then return nothing + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + while( dirname != NULL ){ + found_dir = FALSE; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + tocEntryPointer = (struct dirTocEntry*)toc; + } + else{ + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + if (tocEntryPointer->fileProperties & 0x02){ + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0){ + // if the name matches then we've found the directory + found_dir = TRUE; +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); + RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); +#endif + break; + } + } + + // point to the next entry + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + return -1; + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + tocEntryPointer = (struct dirTocEntry*)toc; + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // We know how much data we need to read in from the DirTocHeader + // but we need to read in at least 1 sector before we can get this value + + // Now we need to COUNT the number of entries (dont do anything with info at this point) + // so set the tocEntryPointer to point to the first actual file entry + + // This is a bit of a waste of reads since we're not actually copying the data out yet, + // but we dont know how big this TOC might be, so we cant allocate a specific size + + tocEntryPointer = (struct dirTocEntry*)toc; + + // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. + getDirTocData.start_LBA = localTocEntry.fileLBA; + getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; + getDirTocData.num_entries = 0; + getDirTocData.current_entry = 0; + getDirTocData.current_sector = getDirTocData.start_LBA; + getDirTocData.current_sector_offset = 0; + + num_dir_sectors = getDirTocData.num_sectors; + + tocEntryPointer = (struct dirTocEntry*)toc; + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + toc_entry_num=0; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ + // decrease the number of dirs remaining + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + tocEntryPointer = (struct dirTocEntry*)toc; + +// continue; + } + else{ + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + return (toc_entry_num); + } + } + + // We've found a file/dir in this directory + // now check if it matches our extension list (if there is one) + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if (localTocEntry.fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs){ + toc_entry_num++; + } + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + } + else{ + toc_entry_num++; + } + } + + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + + // THIS SHOULD BE UNREACHABLE - + // since we are trying to count ALL matching entries, rather than upto a limit + + + // STORE total number of TOC entries + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + + + // we've reached the toc entry limit, so return how many we've done + return (toc_entry_num); + +} + +// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries +// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries){ + static char toc[2048]; + int toc_entry_num; + + struct dirTocEntry* tocEntryPointer; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + if (getDirTocData.current_entry == 0){ + // if this is the first read then make sure we point to the first real entry + tocEntryPointer = (struct dirTocEntry*)toc; + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (struct dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + + getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; + } + else{ + tocEntryPointer = (struct dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + + if (req_entries > 128) + req_entries = 128; + + for (toc_entry_num=0; toc_entry_num < req_entries;){ + if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ + // decrease the number of dirs remaining + getDirTocData.num_sectors--; + + if (getDirTocData.num_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + getDirTocData.current_sector_offset = 0; + tocEntryPointer = (struct dirTocEntry*)(toc + getDirTocData.current_sector_offset); + +// continue; + } + else{ + return (toc_entry_num); + } + } + + // This must be incremented even if the filename doesnt match extension list + getDirTocData.current_entry++; + + // We've found a file in this directory + // now check if it matches our extension list (if there is one) + + // Copy the entry regardless, as it makes the comparison easier + // if it doesn't match then it will just be overwritten + TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); + + if (tocEntry[toc_entry_num].fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs) { + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (struct dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (struct dirTocEntry*)(toc + getDirTocData.current_sector_offset); + + } + else{ + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (struct dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + } +/* + if (strlen(getDirTocData.extension_list) > 0) + { + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) + { + + // increment this here, rather than in the main for loop + // since this should count the number of matching entries + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else + { + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } +*/ + } + return (toc_entry_num); +} diff --git a/pcsx2/CDVDiso.h b/pcsx2/CDVDiso.h new file mode 100644 index 0000000000..83d43c9288 --- /dev/null +++ b/pcsx2/CDVDiso.h @@ -0,0 +1,149 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISO_H__ +#define __CDVDISO_H__ + +#include "CDVDlib.h" + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries); + +#if defined(_MSC_VER) +#pragma pack(1) +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTableEntry +{ + u8 dirNameLength; + u8 reserved; + u32 dirTOCLBA; + u16 dirDepth; + u8 dirName[32]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTocEntry +{ + short length; + unsigned int fileLBA; + unsigned int fileLBA_bigend; + unsigned int fileSize; + unsigned int fileSize_bigend; + unsigned char dateStamp[6]; + unsigned char reserved1; + unsigned char fileProperties; + unsigned char reserved2[6]; + unsigned char filenameLength; + unsigned char filename[128]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif // This is the internal format on the CD +// TocEntry structure contains only the important stuff needed for export + +#if defined(_MSC_VER) +#pragma pack() +#endif + +#endif//__CDVDISO_H__ diff --git a/pcsx2/CDVDisodrv.c b/pcsx2/CDVDisodrv.c new file mode 100644 index 0000000000..8985d60910 --- /dev/null +++ b/pcsx2/CDVDisodrv.c @@ -0,0 +1,284 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#include + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +CdRMode cdReadMode; + +struct fdtable{ +//int fd; + int fileSize; + int LBA; + int filePos; +}; + +static struct fdtable fd_table[16]; +static int fd_used[16]; +static int files_open=0; +static int inited=FALSE; + +/************************************************************* +* The functions below are the normal file-system operations, * +* used to provide a standard filesystem interface * +*************************************************************/ + +////////////////////////////////////////////////////////////////////// +// CDVDFS_init +// called by 80000592 sceCdInit() +////////////////////////////////////////////////////////////////////// +void CDVDFS_init(){ + + if (inited) return;//might change in the future as a param; forceInit/Reset + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); + RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); + RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); +#endif + + //CdInit(0); already called by plugin loading system ;) + + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; //isofs driver only needs + //2KB sectors + + memset(fd_table, 0, sizeof(fd_table)); + memset(fd_used, 0, 16*sizeof(int)); + + inited = TRUE; + + return; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_open +// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_open(char *name, int mode){ + register int j; + static struct TocEntry tocEntry; + + // check if the file exists + if (CDVD_findfile(name, &tocEntry) != TRUE) + return -1; + + if(mode != 1) return -2; //SCE_RDONLY + + // set up a new file descriptor + for(j=0; j < 16; j++) if(fd_used[j] == 0) break; + if(j >= 16) return -3; + + fd_used[j] = 1; + files_open++; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); +#endif + + fd_table[j].fileSize = tocEntry.fileSize; + fd_table[j].LBA = tocEntry.fileLBA; + fd_table[j].filePos = 0; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); +#endif + + return j; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_lseek +// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_lseek(int fd, int offset, int whence){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + switch(whence){ + case SEEK_SET: + fd_table[fd].filePos = offset; + break; + + case SEEK_CUR: + fd_table[fd].filePos += offset; + break; + + case SEEK_END: + fd_table[fd].filePos = fd_table[fd].fileSize + offset; + break; + + default: + return -1; + } + + if (fd_table[fd].filePos < 0) + fd_table[fd].filePos = 0; + + if (fd_table[fd].filePos > fd_table[fd].fileSize) + fd_table[fd].filePos = fd_table[fd].fileSize; + + return fd_table[fd].filePos; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_read +// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_read( int fd, char *buffer, int size ){ +// int start_sector; + int off_sector; +// int num_sectors; + + //static char local_buffer[2024*2048]; //4MB + static char lb[2048]; //2KB + //Start, Aligned, End + int ssector, asector, esector; + int ssize=0, asize, esize; + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + // A few sanity checks + if (fd_table[fd].filePos > fd_table[fd].fileSize){ + // We cant start reading from past the beginning of the file + return 0; // File exists but we couldnt read anything from it + } + + if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) + size = fd_table[fd].fileSize - fd_table[fd].filePos; + + // Now work out where we want to start reading from + asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + if (off_sector){ + ssize = min(2048 - off_sector, size); + size -= ssize; + asector++; + } + asize = size & 0xFFFFF800; + esize = size & 0x000007FF; + esector=asector + (asize >> 11); + size += ssize; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); +#endif + + if (ssize){ if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + FreezeMMXRegs(1); + memcpy_fast(buffer, lb + off_sector, ssize); + FreezeMMXRegs(0); + } + if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + if (esize){ if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + FreezeMMXRegs(1); + memcpy_fast(buffer+ssize+asize, lb, esize); + FreezeMMXRegs(0); + } +/*********************** + // Now work out where we want to start reading from + start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + num_sectors = ((off_sector + size) >> 11) + 1; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); +#endif + + // Read the data (we only ever get 16KB max request at once) + if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + //CdSync(0); hm, a wait function maybe... + + memcpy_fast(buffer,local_buffer+off_sector,size); +**************************/ + fd_table[fd].filePos += size; + + return (size); +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_write +// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" +// hehe, this ain't a CD writing option :D +////////////////////////////////////////////////////////////////////// +int CDVDFS_write( int fd, char * buffer, int size ){ + if(size == 0) return 0; + else return -1; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_close +// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_close( int fd){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); +#endif + + fd_used[fd] = 0; + files_open--; + + return 0; +} + diff --git a/pcsx2/CDVDisodrv.h b/pcsx2/CDVDisodrv.h new file mode 100644 index 0000000000..9cf3a6319b --- /dev/null +++ b/pcsx2/CDVDisodrv.h @@ -0,0 +1,39 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISODRV_H__ +#define __CDVDISODRV_H__ + +//#include "Common.h" +#include "CDVDlib.h" + +extern CdRMode cdReadMode; + +/* Filing-system exported functions */ +void CDVDFS_init(); +int CDVDFS_open(char *name, int mode); +int CDVDFS_lseek(int fd, int offset, int whence); +int CDVDFS_read( int fd, char * buffer, int size ); +int CDVDFS_write( int fd, char * buffer, int size ); +int CDVDFS_close( int fd); + +#endif//__CDVDISODRV_H__ diff --git a/pcsx2/CDVDlib.h b/pcsx2/CDVDlib.h new file mode 100644 index 0000000000..2a96abeb17 --- /dev/null +++ b/pcsx2/CDVDlib.h @@ -0,0 +1,202 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Linux kernel headers + * Modified by Florin for PCSX2 emu + */ + +#ifndef _CDVDLIB_H +#define _CDVDLIB_H + +#include "Common.h" + +// Macros for READ Data pattan +#define CdSecS2048 0 // sector size 2048 +#define CdSecS2328 1 // sector size 2328 +#define CdSecS2340 2 // sector size 2340 + +//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ +//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ + +/* + * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, + * 2340, or 2352 bytes long. + * Sector types of the standard CD-ROM data formats: + * + * format sector type user data size (bytes) + * ----------------------------------------------------------------------------- + * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) + * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) + * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) + * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) + * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) + * + * + * The layout of the standard CD-ROM data formats: + * ----------------------------------------------------------------------------- + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | + * | 12 - 4 - 8 - 2324 - 4 | + * + */ + +// Macros for Spindle control +#define CdSpinMax 0 +#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. +#define CdSpinStm 0 // Recommended stream rotation speed. + +// Macros for TrayReq +#define CdTrayOpen 0 +#define CdTrayClose 1 +#define CdTrayCheck 2 + +/* + * Macros for sceCdGetDiskType() //comments translated from japanese;) + */ +#define SCECdIllgalMedia 0xff + /* ILIMEDIA (Illegal Media) + A non-PS / non-PS2 Disc. */ +#define SCECdDVDV 0xfe + /* DVDV (DVD Video) + A non-PS / non-PS2 Disc, but a DVD Video Disc */ +#define SCECdCDDA 0xfd + /* CDDA (CD DA) + A non-PS / non-PS2 Disc that include a DA track */ +#define SCECdPS2DVD 0x14 + /* PS2DVD PS2 consumer DVD. */ +#define SCECdPS2CDDA 0x13 + /* PS2CDDA PS2 consumer CD that includes a DA track */ +#define SCECdPS2CD 0x12 + /* PS2CD PS2 consumer CD that does not include a DA track */ +#define SCECdPSCDDA 0x11 + /* PSCDDA PS CD that includes a DA track */ +#define SCECdPSCD 0x10 + /* PSCD PS CD that does not include a DA track */ +#define SCECdDETCT 0x01 + /* DETCT (Detecting) Disc distinction action */ +#define SCECdNODISC 0x00 + /* NODISC (No disc) No disc entered */ + +/* + * Media mode + */ +#define SCECdCD 1 +#define SCECdDVD 2 + +typedef struct { + u8 stat; // 0: normal. Any other: error + u8 second; // second (BCD value) + u8 minute; // minute (BCD value) + u8 hour; // hour (BCD value) + u8 week; // week (BCD value) + u8 day; // day (BCD value) + u8 month; // month (BCD value) + u8 year; // year (BCD value) +} CdCLOCK; + +typedef struct { + u32 lsn; // Logical sector number of file + u32 size; // File size (in bytes) + char name[16]; // Filename + u8 date[8]; // 1th: Seconds + // 2th: Minutes + // 3th: Hours + // 4th: Date + // 5th: Month + // 6th 7th: Year (4 digits) +} CdlFILE; + +typedef struct { + u8 minute; // Minutes + u8 second; // Seconds + u8 sector; // Sector + u8 track; // Track number +} CdlLOCCD; + +typedef struct { + u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) + u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. + // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. + u8 datapattern; // SCECdSecS2048: Data size 2048 bytes + // SCECdSecS2328: 2328 bytes + // SCECdSecS2340: 2340 bytes + u8 pad; // Padding data produced by alignment. +} CdRMode; + +#if defined(_WIN32) +#pragma pack(1) +#endif + +struct TocEntry +{ + u32 fileLBA; + u32 fileSize; + u8 fileProperties; + u8 padding1[3]; + u8 filename[128+1]; + u8 date[7]; +#if defined(_WIN32) +}; +#else +} __attribute__((packed)); +#endif + +#if defined(_WIN32) +#pragma pack() +#endif + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +/* +int CdBreak(void); +int CdCallback( void (*func)() ); +int CdDiskReady(int mode); +int CdGetDiskType(void); +int CdGetError(void); +u32 CdGetReadPos(void); +int CdGetToc(u8 *toc); +int CdInit(int init_mode); +CdlLOCCD *CdIntToPos(int i, CdlLOCCD *p); +int CdPause(void); +int CdPosToInt(CdlLOCCD *p);*/ +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +/*int CdReadClock(CdCLOCK *rtc); +int CdSearchFile (CdlFILE *fp, const char *name); +int CdSeek(u32 lsn); +int CdStandby(void); +int CdStatus(void); +int CdStop(void); +int CdSync(int mode); +int CdTrayReq(int mode, u32 *traycnt); +*/ +#endif // _CDVDLIB_H diff --git a/pcsx2/COP0.c b/pcsx2/COP0.c new file mode 100644 index 0000000000..85e4caebd0 --- /dev/null +++ b/pcsx2/COP0.c @@ -0,0 +1,369 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "Common.h" +#include "R5900.h" +#include "InterTables.h" + +//extern BOOL bExecBIOS; + +void COP0() { + Int_COP0PrintTable[_Rs_](); +} + +void COP0_BC0() { +#ifdef COP0_LOG + COP0_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); +#endif + Int_COP0BC0PrintTable[(cpuRegs.code >> 16) & 0x03](); +} + +void COP0_Func() { +#ifdef COP0_LOG + COP0_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); +#endif + Int_COP0C0PrintTable[_Funct_](); +} + +void COP0_Unknown() { +#ifdef CPU_LOG + CPU_LOG("COP0 Unknown opcode called\n"); +#endif +} + +void UpdateCP0Status() { + u32 value = cpuRegs.CP0.n.Status.val; + + if (value & 0x06 || + (value & 0x18) == 0) { // Kernel Mode (KSU = 0 | EXL = 1 | ERL = 1)*/ + memSetKernelMode(); // Kernel memory always + } else { // User Mode + memSetUserMode(); + } + cpuTestHwInts(); +} + +void WriteCP0Status(u32 value) { + cpuRegs.CP0.n.Status.val = value; + UpdateCP0Status(); +} + +extern u32 s_iLastCOP0Cycle; +extern u32 s_iLastPERFCycle[2]; + +void MFC0() { + if (!_Rt_) return; +#ifdef COP0_LOG + if (_Rd_ != 9) { COP0_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); } +#endif + + //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MFC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); + switch (_Rd_) { + + case 12: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)(cpuRegs.CP0.r[_Rd_] & 0xf0c79c1f); break; + case 25: + switch(_Imm_ & 0x3F){ + case 0: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pccr; break; + case 1: + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + } + + cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr0; + break; + case 3: + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + s_iLastPERFCycle[1] = cpuRegs.cycle; + } + cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr1; + break; + } + /*SysPrintf("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ + break; + case 24: + SysPrintf("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + case 9: + // update + cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; + s_iLastCOP0Cycle = cpuRegs.cycle; + default: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.CP0.r[_Rd_]; + } +} + +void MTC0() { +#ifdef COP0_LOG + COP0_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); +#endif + //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); + switch (_Rd_) { + case 25: + /*if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ + switch(_Imm_ & 0x3F){ + case 0: + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + cpuRegs.PERF.n.pccr = cpuRegs.GPR.r[_Rt_].UL[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + s_iLastPERFCycle[1] = cpuRegs.cycle; + break; + case 1: cpuRegs.PERF.n.pcr0 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[0] = cpuRegs.cycle; break; + case 3: cpuRegs.PERF.n.pcr1 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[1] = cpuRegs.cycle; break; + } + break; + case 24: + SysPrintf("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + case 12: WriteCP0Status(cpuRegs.GPR.r[_Rt_].UL[0]); break; + case 9: s_iLastCOP0Cycle = cpuRegs.cycle; cpuRegs.CP0.r[9] = cpuRegs.GPR.r[_Rt_].UL[0]; break; + default: cpuRegs.CP0.r[_Rd_] = cpuRegs.GPR.r[_Rt_].UL[0]; break; + } +} + +int CPCOND0() { + if(((psHu16(DMAC_STAT) & psHu16(DMAC_PCR)) & 0x3ff) == (psHu16(DMAC_PCR) & 0x3ff)) return 1; + else return 0; +} + +//#define CPCOND0 1 + +#define BC0(cond) \ + if (CPCOND0() cond) { \ + intDoBranch(_BranchTarget_); \ + } + +void BC0F() { + BC0(== 0); +} + +void BC0T() { + BC0(== 1); +} + +#define BC0L(cond) \ + if (CPCOND0() cond) { \ + intDoBranch(_BranchTarget_); \ + } else cpuRegs.pc+= 4; + +void BC0FL() { + BC0L(== 0); +} + +void BC0TL() { + BC0L(== 1); +} + +void TLBR() { +#ifdef CPU_LOG +/* CPU_LOG("COP0_TLBR %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ +#endif + int i = cpuRegs.CP0.n.Index&0x1f; + +// if( !bExecBIOS ) +// __Log("TLBR %d\n", cpuRegs.CP0.n.Index&0x1f); + + SysPrintf("COP0_TLBR\n"); + cpuRegs.CP0.n.PageMask = tlb[i].PageMask; + cpuRegs.CP0.n.EntryHi = tlb[i].EntryHi&~(tlb[i].PageMask|0x1f00); + cpuRegs.CP0.n.EntryLo0 = (tlb[i].EntryLo0&~1)|((tlb[i].EntryHi>>12)&1); + cpuRegs.CP0.n.EntryLo1 =(tlb[i].EntryLo1&~1)|((tlb[i].EntryHi>>12)&1); +} + +void ClearTLB(int i) { + u32 mask, addr; + u32 saddr, eaddr; + + + if (tlb[i].EntryLo0 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = tlb[i].VPN2 >> 12; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memClearPageAddr(addr << 12); + Cpu->Clear(addr << 12, 1); + } + } + } + + if (tlb[i].EntryLo1 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memClearPageAddr(addr << 12); + Cpu->Clear(addr << 12, 1); + } + } + } +} + +void WriteTLB(int i) { + u32 mask, addr; + u32 saddr, eaddr; + + tlb[i].PageMask = cpuRegs.CP0.n.PageMask; + tlb[i].EntryHi = cpuRegs.CP0.n.EntryHi; + tlb[i].EntryLo0 = cpuRegs.CP0.n.EntryLo0; + tlb[i].EntryLo1 = cpuRegs.CP0.n.EntryLo1; + + tlb[i].Mask = (cpuRegs.CP0.n.PageMask >> 13) & 0xfff; + tlb[i].nMask = (~tlb[i].Mask) & 0xfff; + tlb[i].VPN2 = ((cpuRegs.CP0.n.EntryHi >> 13) & (~tlb[i].Mask)) << 13; + tlb[i].ASID = cpuRegs.CP0.n.EntryHi & 0xfff; + tlb[i].G = cpuRegs.CP0.n.EntryLo0 & cpuRegs.CP0.n.EntryLo1 & 0x1; + tlb[i].PFN0 = (((cpuRegs.CP0.n.EntryLo0 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; + tlb[i].PFN0|= (0x80000000); + tlb[i].PFN1 = (((cpuRegs.CP0.n.EntryLo1 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; + tlb[i].PFN1|= (0x80000000); + if (tlb[i].VPN2 == 0x70000000) return; + + if (tlb[i].EntryLo0 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = tlb[i].VPN2 >> 12; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memSetPageAddr(addr << 12, tlb[i].PFN0 + ((addr - saddr) << 12)); + Cpu->Clear(addr << 12, 1); + } + } + } + + if (tlb[i].EntryLo1 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memSetPageAddr(addr << 12, tlb[i].PFN1 + ((addr - saddr) << 12)); + Cpu->Clear(addr << 12, 1); + } + } + } +} + +void TLBWI() { + int j = cpuRegs.CP0.n.Index & 0x3f; + + if (j > 48) return; + +#ifdef CPU_LOG +/* CPU_LOG("COP0_TLBWI %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Index, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ +#endif + +// if( !bExecBIOS ) +// __Log("TLBWI %d\n", j); + + ClearTLB(j); + WriteTLB(j); +} + +void TLBWR() { + int j = cpuRegs.CP0.n.Random & 0x3f; + + if (j > 48) return; + +#ifdef CPU_LOG +/* CPU_LOG("COP0_TLBWR %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ +#endif + +// if( !bExecBIOS ) +// __Log("TLBWR %d\n", j); + + ClearTLB(j); + WriteTLB(j); +} + +void TLBP() { + int i; + + + union { + struct { + u32 VPN2:19; + u32 VPN2X:2; + u32 G:3; + u32 ASID:8; + } s; + u32 u; + } EntryHi32; + +// if( !bExecBIOS ) +// __Log("TLBP %x\n", cpuRegs.CP0.n.EntryHi); + + EntryHi32.u=cpuRegs.CP0.n.EntryHi; + + cpuRegs.CP0.n.Index=0xFFFFFFFF; + for(i=0;i<48;i++){ + if(tlb[i].VPN2==((~tlb[i].Mask)&(EntryHi32.s.VPN2)) + &&((tlb[i].G&1)||((tlb[i].ASID & 0xff) == EntryHi32.s.ASID))) { + cpuRegs.CP0.n.Index=i; + break; + } + } + if(cpuRegs.CP0.n.Index == 0xFFFFFFFF) cpuRegs.CP0.n.Index = 0x80000000; +} + +void ERET() { + if (cpuRegs.CP0.n.Status.b.ERL) { + cpuRegs.pc = cpuRegs.CP0.n.ErrorEPC; + cpuRegs.CP0.n.Status.b.ERL = 0; + } else { + cpuRegs.pc = cpuRegs.CP0.n.EPC; + cpuRegs.CP0.n.Status.b.EXL = 0; + } + UpdateCP0Status(); + intSetBranch(); +} + +void DI() { + if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || + cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { + cpuRegs.CP0.n.Status.b.EIE = 0; + UpdateCP0Status(); + } +} + +void EI() { + if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || + cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { + cpuRegs.CP0.n.Status.b.EIE = 1; + UpdateCP0Status(); + } +} + diff --git a/pcsx2/COP0.h b/pcsx2/COP0.h new file mode 100644 index 0000000000..f1c1cb8e82 --- /dev/null +++ b/pcsx2/COP0.h @@ -0,0 +1,27 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __COP0_H__ +#define __COP0_H__ + +void WriteCP0Status(u32 value); +void UpdateCP0Status(); +void WriteTLB(int i); +void ClearTLB(int i); + +#endif /* __COP0_H__ */ diff --git a/pcsx2/Cache.c b/pcsx2/Cache.c new file mode 100644 index 0000000000..67a759e38b --- /dev/null +++ b/pcsx2/Cache.c @@ -0,0 +1,391 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "Common.h" +#include "Cache.h" + +#ifndef PCSX2_VIRTUAL_MEM +_cacheS pCache[64]; +int getFreeCache(u32 mem, int mode, int * way) { + u8 * out; + u32 paddr; + u32 taddr[2]; + u8 * t; + int number; + int i = (mem >> 6) & 0x3F; + + paddr = memLUTR[mem >> 12]; + taddr[0] = memLUTW[pCache[i].tag[0]>>12]; + taddr[1] = memLUTW[pCache[i].tag[1]>>12]; + + if (taddr[0] == paddr && (pCache[i].tag[0] & 0x20)) + { + *way = 0; + return i; + }else if(taddr[1] == paddr && (pCache[i].tag[1] & 0x20)) + { + *way = 1; + return i; + } + + number = ((pCache[i].tag[0]>>4) & 1) ^ ((pCache[i].tag[1]>>4) & 1); + + if(pCache[i].tag[number] & 0x60) // Valid Dirty + { + t = (char *)(taddr[number]); + out = (u8*)(t + (mem & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[i].data[number][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[i].data[number][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[i].data[number][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[i].data[number][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[i].data[number][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[i].data[number][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[i].data[number][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[i].data[number][3].b8._8)[1]; + } + + + + if(mode == 1) + { + pCache[i].tag[number] |= 0x40; // Set Dirty Bit if mode == write + } + + pCache[i].tag[number] &= ~(0xFFFFF000); + pCache[i].tag[number] |= ((mem>>12) & 0xFFFFF) << 12; + + + t = (u8 *)paddr; + out= (u8*)(t + (mem & 0xFC0)); + ((u64*)pCache[i].data[number][0].b8._8)[0] = ((u64*)out)[0]; + ((u64*)pCache[i].data[number][0].b8._8)[1] = ((u64*)out)[1]; + ((u64*)pCache[i].data[number][1].b8._8)[0] = ((u64*)out)[2]; + ((u64*)pCache[i].data[number][1].b8._8)[1] = ((u64*)out)[3]; + ((u64*)pCache[i].data[number][2].b8._8)[0] = ((u64*)out)[4]; + ((u64*)pCache[i].data[number][2].b8._8)[1] = ((u64*)out)[5]; + ((u64*)pCache[i].data[number][3].b8._8)[0] = ((u64*)out)[6]; + ((u64*)pCache[i].data[number][3].b8._8)[1] = ((u64*)out)[7]; + + if(pCache[i].tag[number] & 0x10) pCache[i].tag[number] &= ~(0x10); + else pCache[i].tag[number] |= 0x10; + + pCache[i].tag[number] |= 0x20; + *way = number; + return i; +} + +void writeCache8(u32 mem, u8 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache8 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + + pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)] = value; +} + +void writeCache16(u32 mem, u16 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache16 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + + *(u16*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache32(u32 mem, u32 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache32 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + *(u32*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache64(u32 mem, u64 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache64 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + *(u64*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache128(u32 mem, u64 *value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache128 %8.8x adding to %d\n", mem, i); + ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[0] = value[0]; + ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[1] = value[1]; +} + +u8 *readCache(u32 mem) { + int i, number; + + i = getFreeCache(mem,0,&number); +// CACHE_LOG("readCache %8.8x from %d, way %d\n", mem, i,number); + + return pCache[i].data[number][(mem>>4) & 0x3].b8._8; +} + +extern int Dcache; +void CACHE() { + u32 addr; + //if(Dcache == 0) return; + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + switch (_Rt_) { + case 0x1a: + { + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTR[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } + +#ifdef CACHE_LOG + CACHE_LOG("CACHE DHIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); +#endif + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + case 0x18: + { + u8 * out; + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTW[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } + +#ifdef CACHE_LOG + CACHE_LOG("CACHE DHWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); +#endif + + if(pCache[index].tag[way] & 0x60) // Valid Dirty + { + char * t = (char *)(taddr);//paddr[way]); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + + break; + } + case 0x1c: + { + u8 * out; + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTW[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } +#ifdef CACHE_LOG + CACHE_LOG("CACHE DHWOIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); +#endif + if(pCache[index].tag[way] & 0x60) // Valid Dirty + { + char * t = (char *)(taddr); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x40); + break; + } + case 0x16: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXIN addr %x, index %d, way %d, flag %x\n",addr,index,way,pCache[index].tag[way] & 0x78); +#endif + pCache[index].tag[way] &= ~(0x6F); + + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + case 0x11: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; + cpuRegs.CP0.r[28] = *(u32 *)(out+(addr&0xf)); +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXLDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); +#endif + break; + } + case 0x10: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + + cpuRegs.CP0.r[28] = 0; + cpuRegs.CP0.r[28] = pCache[index].tag[way]; +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXLTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); +#endif + break; + } + case 0x13: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; + *(u32*)(&pCache[index].data[way][(addr>>4) & 0x3].b8._8[(addr&0xf)]) = cpuRegs.CP0.r[28]; +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXSDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); +#endif + break; + } + case 0x12: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + pCache[index].tag[way] = cpuRegs.CP0.r[28]; +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXSTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28] & 0x6F); +#endif + break; + } + case 0x14: + { + + u8 * out; + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + +#ifdef CACHE_LOG + CACHE_LOG("CACHE DXWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); +#endif + if(pCache[index].tag[way] & 0x60) // Dirty + { + u32 paddr = memLUTW[pCache[index].tag[way] >> 12]; + char * t = (char *)(paddr); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + } +} +#else + +void CACHE() { +} + +#endif \ No newline at end of file diff --git a/pcsx2/Cache.h b/pcsx2/Cache.h new file mode 100644 index 0000000000..903e2c07de --- /dev/null +++ b/pcsx2/Cache.h @@ -0,0 +1,47 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __CACHE_H__ +#define __CACHE_H__ + +#include "Common.h" + +typedef struct __u8bit_128 { + u8 _8[16]; + +}_u8bit_128; + +typedef struct _u128v2 { + _u8bit_128 b8; + +}u128; + +typedef struct { + u32 tag[2]; + u128 data[2][4]; +} _cacheS; + +_cacheS pCache[64]; +void writeCache8(u32 mem, u8 value); +void writeCache16(u32 mem, u16 value); +void writeCache32(u32 mem, u32 value); +void writeCache64(u32 mem, u64 value); +void writeCache128(u32 mem, u64 *value); +u8 *readCache(u32 mem); + +#endif /* __CACHE_H__ */ diff --git a/pcsx2/CdRom.c b/pcsx2/CdRom.c new file mode 100644 index 0000000000..32b50e9e32 --- /dev/null +++ b/pcsx2/CdRom.c @@ -0,0 +1,1092 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +//THIS ALL IS FOR THE CDROM REGISTERS HANDLING +#include "PsxCommon.h" + +#define CdlSync 0 +#define CdlNop 1 +#define CdlSetloc 2 +#define CdlPlay 3 +#define CdlForward 4 +#define CdlBackward 5 +#define CdlReadN 6 +#define CdlStandby 7 +#define CdlStop 8 +#define CdlPause 9 +#define CdlInit 10 +#define CdlMute 11 +#define CdlDemute 12 +#define CdlSetfilter 13 +#define CdlSetmode 14 +#define CdlGetmode 15 +#define CdlGetlocL 16 +#define CdlGetlocP 17 +#define Cdl18 18 +#define CdlGetTN 19 +#define CdlGetTD 20 +#define CdlSeekL 21 +#define CdlSeekP 22 +#define CdlTest 25 +#define CdlID 26 +#define CdlReadS 27 +#define CdlReset 28 +#define CdlReadToc 30 + +#define AUTOPAUSE 249 +#define READ_ACK 250 +#define READ 251 +#define REPPLAY_ACK 252 +#define REPPLAY 253 +#define ASYNC 254 +/* don't set 255, it's reserved */ + +char *CmdName[0x100]= { + "CdlSync", "CdlNop", "CdlSetloc", "CdlPlay", + "CdlForward", "CdlBackward", "CdlReadN", "CdlStandby", + "CdlStop", "CdlPause", "CdlInit", "CdlMute", + "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetmode", + "CdlGetlocL", "CdlGetlocP", "Cdl18", "CdlGetTN", + "CdlGetTD", "CdlSeekL", "CdlSeekP", NULL, + NULL, "CdlTest", "CdlID", "CdlReadS", + "CdlReset", NULL, "CDlReadToc", NULL +}; + +long LoadCdBios; +int cdOpenCase; + +u8 Test04[] = { 0 }; +u8 Test05[] = { 0 }; +u8 Test20[] = { 0x98, 0x06, 0x10, 0xC3 }; +u8 Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F }; +u8 Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; + +// 1x = 75 sectors per second +// PSXCLK = 1 sec in the ps +// so (PSXCLK / 75) / BIAS = cdr read time (linuzappz) +//#define cdReadTime ((PSXCLK / 75) / BIAS) +unsigned long cdReadTime;// = ((PSXCLK / 75) / BIAS); + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +/*static struct CdrStat stat; +static struct SubQ *subq;*/ + +#define CDR_INT(eCycle) PSX_INT(17, eCycle) +#define CDREAD_INT(eCycle) PSX_INT(18, eCycle) + +#define StartReading(type) { \ + cdr.Reading = type; \ + cdr.FirstSector = 1; \ + cdr.Readed = 0xff; \ + AddIrqQueue(READ_ACK, 0x800); \ +} + +#define StopReading() { \ + if (cdr.Reading) { \ + cdr.Reading = 0; \ + psxRegs.interrupt&=~0x40000; \ + } \ +} + +#define StopCdda() { \ + if (cdr.Play) { \ +/* if (!Config.Cdda) CDR_stop();*/ \ + cdr.StatP&=~0x80; \ + cdr.Play = 0; \ + } \ +} + +#define SetResultSize(size) { \ + cdr.ResultP = 0; \ + cdr.ResultC = size; \ + cdr.ResultReady = 1; \ +} + +s32 MSFtoLSN(u8 *Time) { + u32 lsn; + + lsn = Time[2]; + lsn+=(Time[1] - 2) * 75; + lsn+= Time[0] * 75 * 60; + return lsn; +} + +void LSNtoMSF(u8 *Time, s32 lsn) { + lsn += 150; + Time[2] = lsn / 4500; // minuten + lsn = lsn - Time[2] * 4500; // minuten rest + Time[1] = lsn / 75; // sekunden + Time[0] = lsn - Time[1] * 75; // sekunden rest +} + +void ReadTrack() { + cdr.Prev[0] = itob(cdr.SetSector[0]); + cdr.Prev[1] = itob(cdr.SetSector[1]); + cdr.Prev[2] = itob(cdr.SetSector[2]); + +#ifdef CDR_LOG + CDR_LOG("KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]); +#endif + cdr.RErr = CDVDreadTrack(MSFtoLSN(cdr.SetSector), CDVD_MODE_2352); +} + +// cdr.Stat: +#define NoIntr 0 +#define DataReady 1 +#define Complete 2 +#define Acknowledge 3 +#define DataEnd 4 +#define DiskError 5 + +void AddIrqQueue(u8 irq, unsigned long ecycle) { + cdr.Irq = irq; + if (cdr.Stat) { + cdr.eCycle = ecycle; + } else { + CDR_INT(ecycle); + } +} + +void cdrInterrupt() { + cdvdTD trackInfo; + int i; + u8 Irq = cdr.Irq; + + if (cdr.Stat) { + CDR_INT(0x800); + return; + } + + cdr.Irq = 0xff; + cdr.Ctrl&=~0x80; + + switch (Irq) { + case CdlSync: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlNop: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; +/* i = stat.Status; + if (CDR_getStatus(&stat) != -1) { + if (stat.Type == 0xff) cdr.Stat = DiskError; + if (stat.Status & 0x10) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x11; + cdr.Result[0]&=~0x02; + } + else if (i & 0x10) { + cdr.StatP |= 0x2; + cdr.Result[0]|= 0x2; + CheckCdrom(); + } + }*/ + break; + + case CdlSetloc: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlPlay: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + cdr.StatP|= 0x82; +// if ((cdr.Mode & 0x5) == 0x5) AddIrqQueue(REPPLAY, cdReadTime); + break; + + case CdlForward: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlBackward: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlStandby: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlStop: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP&=~0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; +// cdr.Stat = Acknowledge; + break; + + case CdlPause: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlPause + 0x20, 0x800); + break; + + case CdlPause + 0x20: + SetResultSize(1); + cdr.StatP&=~0x20; + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlInit: + SetResultSize(1); + cdr.StatP = 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; +// if (!cdr.Init) { + AddIrqQueue(CdlInit + 0x20, 0x800); +// } + break; + + case CdlInit + 0x20: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + cdr.Init = 1; + break; + + case CdlMute: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlDemute: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlSetfilter: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlSetmode: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlGetmode: + SetResultSize(6); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Result[1] = cdr.Mode; + cdr.Result[2] = cdr.File; + cdr.Result[3] = cdr.Channel; + cdr.Result[4] = 0; + cdr.Result[5] = 0; + cdr.Stat = Acknowledge; + break; + + case CdlGetlocL: + SetResultSize(8); +// for (i=0; i<8; i++) cdr.Result[i] = itob(cdr.Transfer[i]); + for (i=0; i<8; i++) cdr.Result[i] = cdr.Transfer[i]; + cdr.Stat = Acknowledge; + break; + + case CdlGetlocP: + SetResultSize(8); +/* subq = (struct SubQ*) CDR_getBufferSub(); + if (subq != NULL) { + cdr.Result[0] = subq->TrackNumber; + cdr.Result[1] = subq->IndexNumber; + memcpy(cdr.Result+2, subq->TrackRelativeAddress, 3); + memcpy(cdr.Result+5, subq->AbsoluteAddress, 3); + } else { +*/ cdr.Result[0] = 1; + cdr.Result[1] = 1; + cdr.Result[2] = cdr.Prev[0]; + cdr.Result[3] = itob((btoi(cdr.Prev[1])) - 2); + cdr.Result[4] = cdr.Prev[2]; + cdr.Result[5] = cdr.Prev[0]; + cdr.Result[6] = cdr.Prev[1]; + cdr.Result[7] = cdr.Prev[2]; +// } + cdr.Stat = Acknowledge; + break; + + case CdlGetTN: + cdr.CmdProcess = 0; + SetResultSize(3); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + if (CDVDgetTN(&cdr.ResultTN) == -1) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + } else { + cdr.Stat = Acknowledge; + cdr.Result[1] = itob(cdr.ResultTN.strack); + cdr.Result[2] = itob(cdr.ResultTN.etrack); + } + break; + + case CdlGetTD: + cdr.CmdProcess = 0; + cdr.Track = btoi(cdr.Param[0]); + SetResultSize(4); + cdr.StatP|= 0x2; + if (CDVDgetTD(cdr.Track, &trackInfo) == -1) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + } else { + LSNtoMSF(cdr.ResultTD, trackInfo.lsn); + cdr.Stat = Acknowledge; + cdr.Result[0] = cdr.StatP; + cdr.Result[1] = itob(cdr.ResultTD[0]); + cdr.Result[2] = itob(cdr.ResultTD[1]); + cdr.Result[3] = itob(cdr.ResultTD[2]); + } + break; + + case CdlSeekL: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlSeekL + 0x20, 0x800); + break; + + case CdlSeekL + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlSeekP: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlSeekP + 0x20, 0x800); + break; + + case CdlSeekP + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlTest: + cdr.Stat = Acknowledge; + switch (cdr.Param[0]) { + case 0x20: // System Controller ROM Version + SetResultSize(4); + *(int*)cdr.Result = *(int*)Test20; + break; + case 0x22: + SetResultSize(8); + *(int*)cdr.Result = *(int*)Test22; + break; + case 0x23: case 0x24: + SetResultSize(8); + *(int*)cdr.Result = *(int*)Test23; + break; + } + break; + + case CdlID: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlID + 0x20, 0x800); + break; + + case CdlID + 0x20: + SetResultSize(8); +// if (CDR_getStatus(&stat) == -1) { + cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player + cdr.Result[1] = 0x00; // 0x80 leads to the menu in the bios, else loads CD +/* } + else { + if (stat.Type == 2) { + cdr.Result[0] = 0x08; + cdr.Result[1] = 0x10; + } + else { + cdr.Result[0] = 0x00; + cdr.Result[1] = 0x00; + } + }*/ + if (!LoadCdBios) cdr.Result[1] |= 0x80; + + cdr.Result[2] = 0x00; + cdr.Result[3] = 0x00; + strncpy((char *)&cdr.Result[4], "PCSX", 4); + cdr.Stat = Complete; + break; + + case CdlReset: + SetResultSize(1); + cdr.StatP = 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlReadToc: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlReadToc + 0x20, 0x800); + break; + + case CdlReadToc + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case AUTOPAUSE: + cdr.OCUP = 0; +/* SetResultSize(1); + StopCdda(); + StopReading(); + cdr.OCUP = 0; + cdr.StatP&=~0x20; + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = DataEnd; +*/ AddIrqQueue(CdlPause, 0x400); + break; + + case READ_ACK: + if (!cdr.Reading) { + psxRegs.interrupt&= ~(1 << 17); + return; + } + + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + + ReadTrack(); + + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + + break; + + case REPPLAY_ACK: + cdr.Stat = Acknowledge; + cdr.Result[0] = cdr.StatP; + SetResultSize(1); + AddIrqQueue(REPPLAY, cdReadTime); + break; + + case REPPLAY: + if ((cdr.Mode & 5) != 5) break; +/* if (CDR_getStatus(&stat) == -1) { + cdr.Result[0] = 0; + cdr.Result[1] = 0; + cdr.Result[2] = 0; + cdr.Result[3] = 0; + cdr.Result[4] = 0; + cdr.Result[5] = 0; + cdr.Result[6] = 0; + cdr.Result[7] = 0; + } else memcpy(cdr.Result, &stat.Track, 8); + cdr.Stat = 1; + SetResultSize(8); + AddIrqQueue(REPPLAY_ACK, cdReadTime); +*/ break; + + case 0xff: + psxRegs.interrupt&= ~(1 << 17); + return; + + default: + cdr.Stat = Complete; + break; + } + + if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) psxHu32(0x1070)|=0x4; + +#ifdef CDR_LOG + CDR_LOG("Cdr Interrupt %x\n", Irq); +#endif + psxRegs.interrupt&= ~(1 << 17); +} + +void cdrReadInterrupt() { + u8 *buf; + + if (!cdr.Reading) { + psxRegs.interrupt&= ~(1 << 18); + return; + } + + if (cdr.Stat) { + CDREAD_INT(0x800); + return; + } + +#ifdef CDR_LOG + CDR_LOG("KEY END"); +#endif + + cdr.OCUP = 1; + SetResultSize(1); + cdr.StatP|= 0x22; + cdr.Result[0] = cdr.StatP; + + SysMessage("Reading From CDR"); + buf = CDVDgetBuffer(); + if (buf == NULL) cdr.RErr = -1; + + if (cdr.RErr == -1) { +#ifdef CDR_LOG + fprintf(emuLog, " err\n"); +#endif + memset(cdr.Transfer, 0, 2340); + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + return; + } + FreezeMMXRegs(1); + memcpy_fast(cdr.Transfer, buf+12, 2340); + FreezeMMXRegs(0); + cdr.Stat = DataReady; + +#ifdef CDR_LOG + fprintf(emuLog, " %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); +#endif + +/* if ((cdr.Muted == 1) && (cdr.Mode & 0x40) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA + if ((cdr.Transfer[4+2] & 0x4) && + ((cdr.Mode&0x8) ? (cdr.Transfer[4+1] == cdr.Channel) : 1) && + (cdr.Transfer[4+0] == cdr.File)) { + int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector); + + if (!ret) { + SPU_playADPCMchannel(&cdr.Xa); + cdr.FirstSector = 0; + } + else cdr.FirstSector = -1; + } + }*/ + + cdr.SetSector[2]++; + if (cdr.SetSector[2] == 75) { + cdr.SetSector[2] = 0; + cdr.SetSector[1]++; + if (cdr.SetSector[1] == 60) { + cdr.SetSector[1] = 0; + cdr.SetSector[0]++; + } + } + + cdr.Readed = 0; + + if ((cdr.Transfer[4+2] & 0x80) && (cdr.Mode & 0x2)) { // EOF +#ifdef CDR_LOG + CDR_LOG("AutoPausing Read\n"); +#endif +// AddIrqQueue(AUTOPAUSE, 0x800); + AddIrqQueue(CdlPause, 0x800); + } + else { + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + } + + psxHu32(0x1070)|=0x4; + return; +} + +/* +cdrRead0: + bit 0 - 0 REG1 command send / 1 REG1 data read + bit 1 - 0 data transfer finish / 1 data transfer ready/in progress + bit 2 - unknown + bit 3 - unknown + bit 4 - unknown + bit 5 - 1 result ready + bit 6 - 1 dma ready + bit 7 - 1 command being processed +*/ + +u8 cdrRead0(void) { + if (cdr.ResultReady) cdr.Ctrl|= 0x20; + else cdr.Ctrl&=~0x20; + + if (cdr.OCUP) cdr.Ctrl|= 0x40; + else cdr.Ctrl&=~0x40; + + // what means the 0x10 and the 0x08 bits? i only saw it used by the bios + cdr.Ctrl|=0x18; + +#ifdef CDR_LOG + CDR_LOG("CD0 Read: %x\n", cdr.Ctrl); +#endif + return psxHu8(0x1800) = cdr.Ctrl; +} + +/* +cdrWrite0: + 0 - to send a command / 1 - to get the result +*/ + +void cdrWrite0(u8 rt) { +#ifdef CDR_LOG + CDR_LOG("CD0 write: %x\n", rt); +#endif + cdr.Ctrl = rt | (cdr.Ctrl & ~0x3); + + if (rt == 0) { + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 0; + } +} + +u8 cdrRead1(void) { + if (cdr.ResultReady && cdr.Ctrl & 0x1) { + psxHu8(0x1801) = cdr.Result[cdr.ResultP++]; + if (cdr.ResultP == cdr.ResultC) cdr.ResultReady = 0; + } else psxHu8(0x1801) = 0; +#ifdef CDR_LOG + CDR_LOG("CD1 Read: %x\n", psxHu8(0x1801)); +#endif + return psxHu8(0x1801); +} + +void cdrWrite1(u8 rt) { + int i; + +#ifdef CDR_LOG + CDR_LOG("CD1 write: %x (%s)\n", rt, CmdName[rt]); +#endif +// psxHu8(0x1801) = rt; + cdr.Cmd = rt; + cdr.OCUP = 0; + +#ifdef CDRCMD_DEBUG + SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]); + if (cdr.ParamC) { + SysPrintf(" Param[%d] = {", cdr.ParamC); + for (i=0;i cdr.ResultTN[1]) cdr.CurTrack = cdr.ResultTN[1]; + if (CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD) != -1) { + int tmp = cdr.ResultTD[2]; + cdr.ResultTD[2] = cdr.ResultTD[0]; + cdr.ResultTD[0] = tmp; + if (!Config.Cdda) CDR_play(cdr.ResultTD); + } + } + } + else if (!Config.Cdda) CDR_play(cdr.SetSector); +*/ cdr.Play = 1; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlForward: + if (cdr.CurTrack < 0xaa) cdr.CurTrack++; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlBackward: + if (cdr.CurTrack > 1) cdr.CurTrack--; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadN: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(1); + break; + + case CdlStandby: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlStop: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlPause: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x40000); + break; + + case CdlReset: + case CdlInit: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlMute: + cdr.Muted = 0; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlDemute: + cdr.Muted = 1; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetfilter: + cdr.File = cdr.Param[0]; + cdr.Channel = cdr.Param[1]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetmode: +#ifdef CDR_LOG + CDR_LOG("Setmode %x\n", cdr.Param[0]); +#endif + cdr.Mode = cdr.Param[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetmode: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocL: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocP: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTN: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTD: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekL: + ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekP: + ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlTest: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlID: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadS: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(2); + break; + + case CdlReadToc: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + default: +#ifdef CDR_LOG + CDR_LOG("Unknown Cmd: %x\n", cdr.Cmd); +#endif + return; + } + if (cdr.Stat != NoIntr) psxHu32(0x1070)|=0x4; +} + +u8 cdrRead2(void) { + u8 ret; + + if (cdr.Readed == 0) { + ret = 0; + } else { + ret = *cdr.pTransfer++; + } + +#ifdef CDR_LOG + CDR_LOG("CD2 Read: %x\n", ret); +#endif + return ret; +} + +void cdrWrite2(u8 rt) { +#ifdef CDR_LOG + CDR_LOG("CD2 write: %x\n", rt); +#endif + if (cdr.Ctrl & 0x1) { + switch (rt) { + case 0x07: + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 0; + cdr.Ctrl = 0; + break; + + default: + cdr.Reg2 = rt; + break; + } + } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) { + cdr.Param[cdr.ParamP++] = rt; + cdr.ParamC++; + } +} + +u8 cdrRead3(void) { + if (cdr.Stat) { + if (cdr.Ctrl & 0x1) psxHu8(0x1803) = cdr.Stat | 0xE0; + else psxHu8(0x1803) = 0xff; + } else psxHu8(0x1803) = 0; +#ifdef CDR_LOG + CDR_LOG("CD3 Read: %x\n", psxHu8(0x1803)); +#endif + return psxHu8(0x1803); +} + +void cdrWrite3(u8 rt) { +#ifdef CDR_LOG + CDR_LOG("CD3 write: %x\n", rt); +#endif + if (rt == 0x07 && cdr.Ctrl & 0x1) { + cdr.Stat = 0; + + if (cdr.Irq == 0xff) { cdr.Irq = 0; return; } + if (cdr.Irq) { + CDR_INT(cdr.eCycle); + }/* else if (cdr.Reading) { + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + }*/ + return; + } + if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) { + cdr.Readed = 1; + cdr.pTransfer = cdr.Transfer; + + switch (cdr.Mode&0x30) { + case 0x10: + case 0x00: cdr.pTransfer+=12; break; + default: break; + } + } +} + +void psxDma3(u32 madr, u32 bcr, u32 chcr) { + u32 cdsize; + +#ifdef CDR_LOG + CDR_LOG("*** DMA 3 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + switch (chcr) { + case 0x11000000: + case 0x11400100: + if (cdr.Readed == 0) { +#ifdef CDR_LOG + CDR_LOG("*** DMA 3 *** NOT READY\n"); +#endif + return; + } + + cdsize = (bcr & 0xffff) * 4; + FreezeMMXRegs(1); + memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdsize); + FreezeMMXRegs(0); + psxCpu->Clear(madr, cdsize/4); + cdr.pTransfer+=cdsize; + + break; + case 0x41000200: + //SysPrintf("unhandled cdrom dma3: madr: %x, bcr: %x, chcr %x\n", madr, bcr, chcr); + // size = 16 * 32 * 4 (one sector) +/* PSXMu8(madr+0) = 0x10; + PSXMu8(madr+1) = 0x00; + PSXMu8(madr+2) = 0x03; + PSXMu8(madr+3) = 0x00;*/ + return; + + default: +#ifdef CDR_LOG + CDR_LOG("Unknown cddma %lx\n", chcr); +#endif + break; + } + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); +} + +void cdrReset() { + memset(&cdr, 0, sizeof(cdr)); + cdr.CurTrack=1; + cdr.File=1; cdr.Channel=1; + cdReadTime = (PSXCLK / 1757) * BIAS; + //DVD is 4x (PSXCLK / 75) CD is 24x on the PS2, so that would mean CD = (PSXCLK / 450) + // 75/4 = 18.75 x 24 = 450 remember its faster than the PS1 ;) Refraction + + // with the timing set to 60 Gran Turismo works + // anybody knows why it doesn't with 75? + // 75 is the correct cdrom timing +// if (Config.CdTiming) +// cdReadTime = (PSXCLK / 60) / BIAS; + // this seems to be the most compatible + // let's leave like this until we know why + // 75 is buggy with some games +} + +int cdrFreeze(gzFile f, int Mode) { + int tmp; + + gzfreeze(&cdr, sizeof(cdr)); + + if (Mode == 1) tmp = (int)(cdr.pTransfer - cdr.Transfer); + gzfreeze(&tmp, 4); + if (Mode == 0) cdr.pTransfer = cdr.Transfer + tmp; + + return 0; +} + diff --git a/pcsx2/CdRom.h b/pcsx2/CdRom.h new file mode 100644 index 0000000000..fe04f79ddc --- /dev/null +++ b/pcsx2/CdRom.h @@ -0,0 +1,92 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#include "PsxCommon.h" +#include "Decode_XA.h" +#include "PS2Edefs.h" + +typedef struct { + u8 OCUP; + u8 Reg1Mode; + u8 Reg2; + u8 CmdProcess; + u8 Ctrl; + u8 Stat; + + u8 StatP; + + u8 Transfer[2352]; + u8 *pTransfer; + + u8 Prev[4]; + u8 Param[8]; + u8 Result[8]; + + u8 ParamC; + u8 ParamP; + u8 ResultC; + u8 ResultP; + u8 ResultReady; + u8 Cmd; + u8 Readed; + unsigned long Reading; + + cdvdTN ResultTN; + u8 ResultTD[4]; + u8 SetSector[4]; + u8 SetSectorSeek[4]; + u8 Track; + int Play; + int CurTrack; + int Mode, File, Channel, Muted; + int Reset; + int RErr; + int FirstSector; + + xa_decode_t Xa; + + int Init; + + u8 Irq; + unsigned long eCycle; + + char Unused[4087]; +} cdrStruct; + +cdrStruct cdr; + +s32 MSFtoLSN(u8 *Time); +void LSNtoMSF(u8 *Time, s32 lsn); + +void cdrReset(); +void cdrInterrupt(); +void cdrReadInterrupt(); +u8 cdrRead0(void); +u8 cdrRead1(void); +u8 cdrRead2(void); +u8 cdrRead3(void); +void cdrWrite0(u8 rt); +void cdrWrite1(u8 rt); +void cdrWrite2(u8 rt); +void cdrWrite3(u8 rt); +int cdrFreeze(gzFile f, int Mode); + +#endif /* __CDROM_H__ */ diff --git a/pcsx2/Common.h b/pcsx2/Common.h new file mode 100644 index 0000000000..8f9095d3a9 --- /dev/null +++ b/pcsx2/Common.h @@ -0,0 +1,267 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#if defined (__linux__) // some distributions are lower case +#define __LINUX__ +#endif + +#include +#include + +#include "PS2Etypes.h" + +#if defined(__x86_64__) +#define DONT_USE_GETTEXT +#endif + +#if defined(_WIN32) + +#include + +typedef struct { + HWND hWnd; // Main window handle + HINSTANCE hInstance; // Application instance + HMENU hMenu; // Main window menu + HANDLE hConsole; +} AppData; + +extern AppData gApp; +#define pthread_mutex__unlock pthread_mutex_unlock + +#elif defined(__MINGW32__) + +#include +#include +#define BOOL int +#include // posix_memalign() +#undef TRUE +#define TRUE 1 +#undef FALSE +#define FALSE 0 + +//#define max(a,b) (((a) > (b)) ? (a) : (b)) +//#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define __declspec(x) +#define __assume(x) ; +#define strnicmp strncasecmp +#define stricmp strcasecmp +#include +//#pragma intrinsic (InterlockedAnd) +// Definitions added Feb 16, 2006 by efp +//#define __declspec(x) +#include +#define __forceinline inline +#define _aligned_malloc(x,y) __mingw_aligned_malloc(x,y) +#define _aligned_free(x) __mingw_aligned_free(x) +#define pthread_mutex__unlock pthread_mutex_unlock + +#define fpusqrtf sqrtf +#define fpufabsf fabsf +#define fpusinf sinf +#define fpucosf cosf +#define fpuexpf expf +#define fpuatanf atanf +#define fpuatan2f atan2f + +#else + +#include +#include // posix_memalign() + +// Definitions added Feb 16, 2006 by efp +//#ifndef __declspec +//#define __declspec(x) +//#endif + +#endif + +#ifdef ENABLE_NLS + +#ifdef __MSCW32__ +#include "libintlmsc.h" +#else +#include +#include +#endif + +#undef _ +#define _(String) dgettext (PACKAGE, String) +#ifdef gettext_noop +# define N_(String) gettext_noop (String) +#else +# define N_(String) (String) +#endif + +#else + +#define _(msgid) msgid +#define N_(msgid) msgid + +#endif + +typedef struct _TESTRUNARGS +{ + u8 enabled; + u8 jpgcapture; + + int frame; // if < 0, frame is unlimited (run until crash). + int numimages; + int curimage; + u32 autopad; // mask for auto buttons + int efile; + int snapdone; + + char* ptitle; + char* pimagename; + char* plogname; + char* pgsdll, *pcdvddll, *pspudll; + +} TESTRUNARGS; + +extern TESTRUNARGS g_TestRun; + +#define BIAS 2 // Bus is half of the actual ps2 speed +//#define PS2CLK 36864000 /* 294.912 mhz */ +//#define PSXCLK 9216000 /* 36.864 Mhz */ +//#define PSXCLK 186864000 /* 36.864 Mhz */ +#define PS2CLK 294912000 /* 294.912 mhz */ + + +/* Config.PsxType == 1: PAL: + VBlank interlaced 50.00 Hz + VBlank non-interlaced 49.76 Hz + HBlank 15.625 KHz + Config.PsxType == 0: NSTC + VBlank interlaced 59.94 Hz + VBlank non-interlaced 59.82 Hz + HBlank 15.73426573 KHz */ + +//VBlanks per second +#define VBLANK_NTSC ((Config.PsxType & 2) ? 59.94 : 59.82) +#define VBLANK_PAL ((Config.PsxType & 2) ? 50.00 : 49.76) + +//HBlanks per second +#define HBLANK_NTSC (15734.26573) +#define HBLANK_PAL (15625) + +//VBlank timers for EE, bit more accurate. +#define VBLANKCNT(count) ((u32)((Config.PsxType & 1) ? (VBLANKPALSELECT * count) : (VBLANKNTSCSELECT * count))) +#define VBLANKPALSELECT ((Config.PsxType & 2) ? (PS2CLK / 50.00) : (PS2CLK / 49.76)) +#define VBLANKNTSCSELECT ((Config.PsxType & 2) ? (PS2CLK / 59.94) : (PS2CLK / 59.82)) + +//EE VBlank speeds +#define PS2VBLANK_NTSC_INT ((PS2CLK / 59.94)) +#define PS2VBLANK_NTSC ((PS2CLK / 59.82)) +#define PS2VBLANK_PAL_INT ((PS2CLK / 50.00)) +#define PS2VBLANK_PAL ((PS2CLK / 49.76)) + +//HBlank timer for EE, bit more accurate. +#define HBLANKCNT(count) ((u32)(PS2HBLANK * count)) + +//EE HBlank speeds +#define PS2HBLANK_NTSC ((int)(PS2CLK / HBLANK_NTSC)) +#define PS2HBLANK_PAL ((int)(PS2CLK / HBLANK_PAL)) +#define PS2HBLANK ((int)((Config.PsxType & 1) ? PS2HBLANK_PAL : PS2HBLANK_NTSC)) + +//IOP VBlank speeds +#define PSXVBLANK_NTSC ((int)(PSXCLK / VBLANK_NTSC)) +#define PSXVBLANK_PAL ((int)(PSXCLK / VBLANK_PAL)) +#define PSXVBLANK ((int)((Config.PsxType & 1) ? PSXVBLANK_PAL : PSXVBLANK_NTSC)) + +//IOP HBlank speeds +#define PSXHBLANK_NTSC ((int)(PSXCLK / HBLANK_NTSC)) +#define PSXHBLANK_PAL ((int)(PSXCLK / HBLANK_PAL)) +#define PSXHBLANK ((int)((Config.PsxType & 1) ? PSXHBLANK_PAL : PSXHBLANK_NTSC)) + +//Misc Clocks +#define PSXPIXEL ((int)(PSXCLK / 13500000)) +#define PSXSOUNDCLK ((int)(48000)) + +#define COLOR_BLACK "\033[30m" +#define COLOR_RED "\033[31m" +#define COLOR_GREEN "\033[32m" +#define COLOR_YELLOW "\033[33m" +#define COLOR_BLUE "\033[34m" +#define COLOR_MAGENTA "\033[35m" +#define COLOR_CYAN "\033[36m" +#define COLOR_WHITE "\033[37m" +#define COLOR_RESET "\033[0m" + +#include // sync functions + +#include "Plugins.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "System.h" +#include "Memory.h" +#include "Elfheader.h" +#include "Hw.h" +//#include "GS.h" +#include "Vif.h" +#include "SPR.h" +#include "Sif.h" +#include "Plugins.h" +#include "PS2Edefs.h" +#include "Misc.h" +#include "Counters.h" +#include "IPU/IPU.h" +#include "Patch.h" +#include "COP0.h" +#include "VifDma.h" +#if (defined(__i386__) || defined(__x86_64__)) +#include "x86/ix86/ix86.h" +#endif + +int cdCaseopen; + +extern void __Log(char *fmt, ...); +extern u16 logProtocol; +extern u8 logSource; +#define PCSX2_VERSION "0.9.5" + +// C++ code for sqrtf +void InitFPUOps(); +extern float (*fpusqrtf)(float fval); +extern float (*fpufabsf)(float fval); +extern float (*fpusinf)(float fval); +extern float (*fpucosf)(float fval); +extern float (*fpuexpf)(float fval); +extern float (*fpuatanf)(float fval); +extern float (*fpuatan2f)(float fvalx, float fvaly); + +// Added Feb 16, 2006 by efp +#ifdef __LINUX__ +#include // EBUSY +#endif /* __LINUX__ */ + +#define DESTROY_MUTEX(mutex) { \ + int err = pthread_mutex_destroy(&mutex); \ + if( err == EBUSY ) \ + SysPrintf("cannot destroy"#mutex"\n"); \ +} \ + +#define DESTROY_COND(cond) { \ + int err = pthread_cond_destroy(&cond); \ + if( err == EBUSY ) \ + SysPrintf("cannot destroy"#cond"\n"); \ +} \ + +#endif /* __COMMON_H__ */ diff --git a/pcsx2/Counters.c b/pcsx2/Counters.c new file mode 100644 index 0000000000..910922deb0 --- /dev/null +++ b/pcsx2/Counters.c @@ -0,0 +1,815 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include "Common.h" +#include "PsxCommon.h" +#include "GS.h" + +u64 profile_starttick = 0; +u64 profile_totalticks = 0; + +int gates = 0; +extern u8 psxhblankgate; +int hblankend = 0; +Counter counters[6]; +u32 nextCounter, nextsCounter; +static void (*s_prevExecuteVU1Block)() = NULL; +LARGE_INTEGER lfreq; + +// its so it doesnt keep triggering an interrupt once its reached its target +// if it doesnt reset the counter it needs stopping +u32 eecntmask = 0; + +void rcntUpdTarget(int index) { + counters[index].sCycleT = cpuRegs.cycle; +} + +void rcntUpd(int index) { + counters[index].sCycle = cpuRegs.cycle; + rcntUpdTarget(index); +} + +void rcntReset(int index) { + counters[index].count = 0; + //counters[index].mode&= ~0x00400C00; + rcntUpd(index); +} + +void rcntSet() { + u32 c; + int i; + + nextCounter = 0xffffffff; + nextsCounter = cpuRegs.cycle; + + for (i = 0; i < 4; i++) { + if (!(counters[i].mode & 0x80) || (counters[i].mode & 0x3) == 0x3) continue; // Stopped + c = ((0x10000 - counters[i].count) * counters[i].rate) - (cpuRegs.cycle - counters[i].sCycleT); + if (c < nextCounter) { + nextCounter = c; + } + + // the + 10 is just in case of overflow + //if(!(counters[i].mode & 0x100) || counters[i].target > 0xffff) continue; + c = ((counters[i].target - counters[i].count) * counters[i].rate) - (cpuRegs.cycle - counters[i].sCycleT); + if (c < nextCounter) { + nextCounter = c; + } + + } + //Calculate HBlank + c = counters[4].CycleT - (cpuRegs.cycle - counters[4].sCycleT); + if (c < nextCounter) { + nextCounter = c; + } + //if(nextCounter > 0x1000) SysPrintf("Nextcounter %x HBlank %x VBlank %x\n", nextCounter, c, counters[5].CycleT - (cpuRegs.cycle - counters[5].sCycleT)); + //Calculate VBlank + c = counters[5].CycleT - (cpuRegs.cycle - counters[5].sCycleT); + if (c < nextCounter) { + nextCounter = c; + } + +} + +void rcntInit() { + int i; + + memset(counters, 0, sizeof(counters)); + + for (i=0; i<4; i++) { + counters[i].rate = 2; + counters[i].target = 0xffff; + } + counters[0].interrupt = 9; + counters[1].interrupt = 10; + counters[2].interrupt = 11; + counters[3].interrupt = 12; + + counters[4].mode = 0x3c0; // The VSync counter mode + counters[5].mode = 0x3c0; + + + + UpdateVSyncRate(); + /*hblankend = 0; + counters[5].mode &= ~0x10000; + counters[4].sCycleT = cpuRegs.cycle; + counters[4].CycleT = HBLANKCNT(1); + counters[4].count = 1; + counters[5].CycleT = VBLANKCNT(1); + counters[5].count = 1; + counters[5].sCycleT = cpuRegs.cycle;*/ + +#ifdef _WIN32 + QueryPerformanceFrequency(&lfreq); +#endif + + for (i=0; i<4; i++) rcntUpd(i); + rcntSet(); + + assert(Cpu != NULL && Cpu->ExecuteVU1Block != NULL ); + s_prevExecuteVU1Block = Cpu->ExecuteVU1Block; +} + +// debug code, used for stats +int g_nCounters[4]; +extern u32 s_lastvsync[2]; +static int iFrame = 0; + +#ifndef _WIN32 +#include +#endif + +u64 iTicks=0; + +u64 GetTickFrequency() +{ +#ifdef _WIN32 + return lfreq.QuadPart; +#else + return 1000000; +#endif +} + +u64 GetCPUTicks() +{ +#ifdef _WIN32 + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart; +#else + struct timeval t; + gettimeofday(&t, NULL); + return (u64)t.tv_sec*1000000+t.tv_usec; +#endif +} + + +void UpdateVSyncRate() { + if (Config.PsxType & 1) { + SysPrintf("PAL\n"); + counters[4].Cycle = 227000; + /*if(Config.PsxType & 2)counters[5].rate = PS2VBLANK_PAL_INT; + else counters[5].rate = PS2VBLANK_PAL;*/ + + counters[5].Cycle = 720; + } else { + SysPrintf("NTSC\n"); + counters[4].Cycle = 227000; + /*if(Config.PsxType & 2)counters[5].rate = PS2VBLANK_NTSC_INT; + else counters[5].rate = PS2VBLANK_NTSC;*/ + + counters[5].Cycle = 720; + } + + hblankend = 0; + counters[5].mode &= ~0x10000; + counters[4].sCycleT = cpuRegs.cycle; + counters[4].CycleT = HBLANKCNT(1); + counters[4].count = 1; + counters[5].CycleT = VBLANKCNT(1); + counters[5].count = 1; + counters[5].sCycleT = cpuRegs.cycle; + + //rcntUpdTarget(4); + //counters[4].CycleT = counters[4].rate; + ///rcntUpdTarget(5); + /*counters[5].CycleT = counters[5].rate; + counters[5].Cycle = PS2VBLANKEND;*/ + + { + u32 vsyncs = (Config.PsxType&1) ? 50:60; + if(Config.CustomFps>0) vsyncs = Config.CustomFps; + iTicks = GetTickFrequency()/vsyncs; + SysPrintf("Framelimiter rate updated (UpdateVSyncRate): %d fps\n",vsyncs); + } + rcntSet(); +} + +u32 pauses=0; + +void FrameLimiter() +{ + static u64 iStart=0, iEnd=0, iExpectedEnd=0; + + if(iStart==0) iStart = GetCPUTicks(); + + iExpectedEnd = iStart + iTicks; + iEnd = GetCPUTicks(); + + if(iEnd>=iExpectedEnd) + { + u64 diff = iEnd-iExpectedEnd; + if((diff>>3)>iTicks) iExpectedEnd=iEnd; + } + else do { + Sleep(1); + pauses++; + iEnd = GetCPUTicks(); + } while(iEnd 0 ) { + + if( uNumFrames == ARRAYSIZE(uPrevTimes) ) uTotalTime -= uPrevTimes[uNextFrame]; + + uPrevTimes[uNextFrame] = uDeltaTime; + uNextFrame = (uNextFrame + 1) % ARRAYSIZE(uPrevTimes); + uTotalTime += uDeltaTime; + + if( uNumFrames < ARRAYSIZE(uPrevTimes) ) ++uNumFrames; + } + //the +6 accounts for calling FrameLimiter() instead Sleep() + uExpectedTime = (Config.PsxType&1) ? (ARRAYSIZE(uPrevTimes) * 1000 / 50 +6) : (ARRAYSIZE(uPrevTimes) * 1000 / 60 +6); + + if( nNoSkipFrames > 0 ) --nNoSkipFrames; + + // hmm... this might be more complicated than it needs to be... or not? + if( changed != 0 ) { + if( changed > 0 ) { + ++nConsecutiveRender; + --changed; + + if( nConsecutiveRender > 20 && uTotalTime + 1 < uExpectedTime ) nNoSkipFrames = ARRAYSIZE(uPrevTimes); + + } + else { + ++nConsecutiveSkip; + ++changed; + } + } + else { + + if( nNoSkipFrames == 0 && nConsecutiveRender > 1 && nConsecutiveSkip < 1 && + (CHECK_MULTIGS? (uTotalTime >= uExpectedTime + uDeltaTime/4 && (uTotalTime >= uExpectedTime + uDeltaTime*3/4 || nConsecutiveSkip==0)) : + (uTotalTime >= uExpectedTime + (uDeltaTime/4))) ) { + + + if( nConsecutiveSkip == 0 ) { + + //first freeze GS regs THEN send dummy packet + if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 1, 0, 0); + else GSsetFrameSkip(1); + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) { + Cpu->ExecuteVU1Block = DummyExecuteVU1Block; + } + } + + changed = -1; + nConsecutiveSkip++; + } + else { + + if( nConsecutiveSkip > 1) { + //first set VU1 to enabled THEN unfreeze GS regs + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + Cpu->ExecuteVU1Block = s_prevExecuteVU1Block; + if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); + else GSsetFrameSkip(0); + + nConsecutiveRender = 0; + } + + changed = 3; + nConsecutiveRender++; + nConsecutiveSkip = 0; + + if( nConsecutiveRender > 20 && uTotalTime + 1 < uExpectedTime ) { + + nNoSkipFrames = ARRAYSIZE(uPrevTimes); + } + } + } + uLastTime = uCurTime; + //dont get too fast, instead keep at smooth full fps + FrameLimiter(); + break; + } + } + } else { // VSync Start (240 hsyncs) + //UpdateVSyncRateEnd(); +#ifdef EE_PROFILING + if( (iFrame%20) == 0 ) { + SysPrintf("Profiled Cycles at %d frames %d\n", iFrame, profile_totalticks); + CLEAR_EE_PROFILE(); + } +#endif + + + //SysPrintf("c: %x, %x\n", cpuRegs.cycle, *(u32*)&VU1.Micro[16]); + //if( (iFrame%20) == 0 ) SysPrintf("svu time: %d\n", SuperVUGetRecTimes(1) * 100000 / lfreq.QuadPart); +// if( (iFrame%10) == 0 ) { +// SysPrintf("vu0 time: %d\n", vu0time); +// vu0time = 0; +// } + + +#ifdef PCSX2_DEVBUILD + if( g_TestRun.enabled && g_TestRun.frame > 0 ) { + if( iFrame > g_TestRun.frame ) { + // take a snapshot + if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) { + if( g_TestRun.snapdone ) { + g_TestRun.curimage++; + g_TestRun.snapdone = 0; + g_TestRun.frame += 20; + if( g_TestRun.curimage >= g_TestRun.numimages ) { + // exit + SysClose(); + exit(0); + } + } + else { + // query for the image + GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture); + } + } + else { + // exit + SysClose(); + exit(0); + } + } + } + + GSVSYNC(); + + if( g_SaveGSStream == 1 ) { + freezeData fP; + + g_SaveGSStream = 2; + gsFreeze(g_fGSSave, 1); + + if (GSfreeze(FREEZE_SIZE, &fP) == -1) { + gzclose(g_fGSSave); + g_SaveGSStream = 0; + } + else { + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) { + gzclose(g_fGSSave); + g_SaveGSStream = 0; + } + else { + if (GSfreeze(FREEZE_SAVE, &fP) == -1) { + gzclose(g_fGSSave); + g_SaveGSStream = 0; + } + else { + gzwrite(g_fGSSave, &fP.size, sizeof(fP.size)); + if (fP.size) { + gzwrite(g_fGSSave, fP.data, fP.size); + free(fP.data); + } + } + } + } + } + else if( g_SaveGSStream == 2 ) { + + if( --g_nLeftGSFrames <= 0 ) { + gzclose(g_fGSSave); + g_fGSSave = NULL; + g_SaveGSStream = 0; + SysPrintf("Done saving GS stream\n"); + } + } +#endif + + + + + + //counters[5].mode&= ~0x10000; + //UpdateVSyncRate(); + + //SysPrintf("ctrs: %d %d %d %d\n", g_nCounters[0], g_nCounters[1], g_nCounters[2], g_nCounters[3]); + //SysPrintf("vif: %d\n", (((LARGE_INTEGER*)g_nCounters)->QuadPart * 1000000) / lfreq.QuadPart); + //memset(g_nCounters, 0, 16); + counters[5].mode|= 0x10000; + if ((CSRw & 0x8)) + GSCSRr|= 0x8; + + if (!(GSIMR&0x800) ) + gsIrq(); + + hwIntcIrq(2); + psxVSyncStart(); + + if(Config.Patch) applypatch(1); + if(gates)rcntStartGate(0x8); + +// __Log("%u %u 0\n", cpuRegs.cycle-s_lastvsync[1], timeGetTime()-s_lastvsync[0]); +// s_lastvsync[0] = timeGetTime(); +// s_lastvsync[1] = cpuRegs.cycle; + } +} + + +void rcntUpdate() +{ + int i; + u32 change = 0; + for (i=0; i<=3; i++) { + if(gates & (1< 0) SysPrintf("Change saved on %x = %x\n", i, change); + } + + if ((u32)(cpuRegs.cycle - counters[4].sCycleT) >= (u32)counters[4].CycleT && hblankend == 1){ + + + if ((CSRw & 0x4)) + GSCSRr |= 4; // signal + + + if (!(GSIMR&0x400) ) + gsIrq(); + + if(gates)rcntEndGate(0); + if(psxhblankgate)psxCheckEndGate(0); + hblankend = 0; + + counters[4].CycleT = HBLANKCNT(counters[4].count); + } else + if ((u32)(cpuRegs.cycle - counters[4].sCycleT) >= (u32)counters[4].CycleT) { + + if(counters[4].count >= counters[4].Cycle){ + //SysPrintf("%x of %x hblanks reorder in %x cycles cpuRegs.cycle = %x\n", counters[4].count, counters[4].Cycle, cpuRegs.cycle - counters[4].sCycleT, cpuRegs.cycle); + counters[4].sCycleT += HBLANKCNT(counters[4].Cycle); + counters[4].count -= counters[4].Cycle; + + } + //counters[4].sCycleT += HBLANKCNT(1); + counters[4].count++; + + counters[4].CycleT = HBLANKCNT(counters[4].count) - (HBLANKCNT(0.5)); + + rcntStartGate(0); + psxCheckStartGate(0); + hblankend = 1; + //if(cpuRegs.cycle > 0xffff0000 || cpuRegs.cycle < 0x1000 + //SysPrintf("%x hsync done in %x cycles cpuRegs.cycle = %x next will happen on %x\n", counters[4].count, counters[4].CycleT, cpuRegs.cycle, (u32)(counters[4].sCycleT + counters[4].CycleT)); + } + + if((counters[5].mode & 0x10000)){ + if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT){ + //counters[5].sCycleT = cpuRegs.cycle; + counters[5].CycleT = VBLANKCNT(counters[5].count); + VSync(); + } + } else if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT) { + if(counters[5].count >= counters[5].Cycle){ + //SysPrintf("reset %x of %x frames done in %x cycles cpuRegs.cycle = %x\n", counters[5].count, counters[5].Cycle, cpuRegs.cycle - counters[5].sCycleT, cpuRegs.cycle); + counters[5].sCycleT += VBLANKCNT(counters[5].Cycle); + counters[5].count -= counters[5].Cycle; + } + counters[5].count++; + //counters[5].sCycleT += VBLANKCNT(1); + counters[5].CycleT = VBLANKCNT(counters[5].count) - (VBLANKCNT(1)/2); + //SysPrintf("%x frames done in %x cycles cpuRegs.cycle = %x cycletdiff %x\n", counters[5].Cycle, counters[5].sCycleT, cpuRegs.cycle, (counters[5].CycleT - VBLANKCNT(1)) - (cpuRegs.cycle - counters[5].sCycleT)); + VSync(); + } + + for (i=0; i<=3; i++) { + if (!(counters[i].mode & 0x80)) continue; // Stopped + + if ((s64)(counters[i].target - counters[i].count) <= 0 /*&& (counters[i].target & 0xffff) > 0*/) { // Target interrupt + + if((counters[i].target > 0xffff)) { + //SysPrintf("EE Correcting target %x after reset on target\n", i); + counters[i].target &= 0xffff; + } + + if(counters[i].mode & 0x100 ) { +#ifdef EECNT_LOG + EECNT_LOG("EE counter %d target reached mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); +#endif + + counters[i].mode|= 0x0400; // Target flag + hwIntcIrq(counters[i].interrupt); + if (counters[i].mode & 0x40) { //The PS2 only resets if the interrupt is enabled - Tested on PS2 + + counters[i].count -= counters[i].target; // Reset on target + } + else counters[i].target += 0x10000000; + } else counters[i].target += 0x10000000; + + } + if (counters[i].count > 0xffff) { + + + if (counters[i].mode & 0x0200) { // Overflow interrupt +#ifdef EECNT_LOG + EECNT_LOG("EE counter %d overflow mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); +#endif + counters[i].mode|= 0x0800; // Overflow flag + hwIntcIrq(counters[i].interrupt); + //SysPrintf("counter[%d] overflow interrupt (%x)\n", i, cpuRegs.cycle); + } + counters[i].count -= 0x10000; + if(counters[i].target > 0xffff) { + //SysPrintf("EE %x Correcting target on overflow\n", i); + counters[i].target &= 0xffff; + } + } + + } + + + rcntSet(); + +} + + + +void rcntWcount(int index, u32 value) { + u32 change = 0; +#ifdef EECNT_LOG + EECNT_LOG("EE count write %d count %x with %x target %x eecycle %x\n", index, counters[index].count, value, counters[index].target, cpuRegs.eCycle); +#endif + counters[index].count = value & 0xffff; + if(counters[index].target > 0xffff) { + counters[index].target &= 0xffff; + //SysPrintf("EE Counter %x count write, target > 0xffff\n", index); + } + //rcntUpd(index); + if((counters[index].mode & 0x3) != 0x3){ + change = cpuRegs.cycle - counters[index].sCycleT; + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + }/* else { + SysPrintf("EE Counter %x count write %x\n", index, value); + }*/ + rcntSet(); +} + +void rcntWmode(int index, u32 value) +{ + u32 change = 0; + + + if (value & 0xc00) { //Clear status flags, the ps2 only clears what is given in the value + counters[index].mode &= ~(value & 0xc00); + } + + if(counters[index].mode & 0x80){ + if((counters[index].mode & 0x3) != 0x3){ + change = cpuRegs.cycle - counters[index].sCycleT; + counters[index].count += (int)(change / counters[index].rate); + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + } + //if(change != 0) SysPrintf("Weee\n"); + //counters[index].sCycleT = cpuRegs.cycle - ((cpuRegs.cycle - counters[index].sCycleT) % counters[index].rate); + if(!(value & 0x80)) SysPrintf("Stopping\n"); + } + else { + SysPrintf("Counter %d not running c%x s%x c%x\n", index, counters[index].count, counters[index].sCycleT, cpuRegs.cycle); + if(value & 0x80) SysPrintf("Starting %d, v%x\n", index, value); + counters[index].sCycleT = cpuRegs.cycle; + } + //if((value & 0x80) && !(counters[index].mode & 0x80)) rcntUpd(index); //Counter wasnt started, so set the start cycle + + counters[index].mode = (counters[index].mode & 0xc00) | (value & 0x3ff); + +#ifdef EECNT_LOG + EECNT_LOG("EE counter set %d mode %x count %x\n", index, counters[index].mode, rcntCycle(index)); +#endif + /*if((value & 0x3) && (counters[index].mode & 0x3) != 0x3){ + //SysPrintf("Syncing %d with HBLANK clock\n", index); + counters[index].CycleT = counters[4].CycleT; + }*/ + + switch (value & 0x3) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK + case 0: counters[index].rate = 2; break; + case 1: counters[index].rate = 32; break; + case 2: counters[index].rate = 512; break; + case 3: counters[index].rate = PS2HBLANK; break; + } + + if((counters[index].mode & 0xF) == 0x7) { + gates &= ~(1< 0xffff) && (counters[index].target & 0xffff) > rcntCycle(index)) { + //SysPrintf("EE Correcting target %x after mode write\n", index); + counters[index].target &= 0xffff; + }*/ + rcntSet(); + +} + +void rcntStartGate(int mode){ + int i; + + if(mode == 0){ + for(i = 0; i < 4; i++){ //Update counters using the hblank as the clock + if((counters[i].mode & 0x83) == 0x83) counters[i].count++; + } + } + + for(i=0; i <=3; i++){ //Gates for counters + if(!(gates & (1<> 4); + switch((counters[i].mode & 0x30) >> 4){ + case 0x0: //Count When Signal is low (off) + counters[i].count = rcntRcount(i); + rcntUpd(i); + counters[i].mode &= ~0x80; + break; + case 0x1: //Reset and start counting on Vsync start + counters[i].mode |= 0x80; + rcntReset(i); + counters[i].target &= 0xffff; + break; + case 0x2: //Reset and start counting on Vsync end + //Do Nothing + break; + case 0x3: //Reset and start counting on Vsync start and end + counters[i].mode |= 0x80; + rcntReset(i); + counters[i].target &= 0xffff; + break; + default: + SysPrintf("EE Start Counter %x Gate error\n", i); + break; + } + } +} +void rcntEndGate(int mode){ + int i; + + for(i=0; i <=3; i++){ //Gates for counters + if(!(gates & (1<> 4); + switch((counters[i].mode & 0x30) >> 4){ + case 0x0: //Count When Signal is low (off) + rcntUpd(i); + counters[i].mode |= 0x80; + break; + case 0x1: //Reset and start counting on Vsync start + //Do Nothing + break; + case 0x2: //Reset and start counting on Vsync end + counters[i].mode |= 0x80; + rcntReset(i); + counters[i].target &= 0xffff; + break; + case 0x3: //Reset and start counting on Vsync start and end + counters[i].mode |= 0x80; + rcntReset(i); + counters[i].target &= 0xffff; + break; + default: + SysPrintf("EE Start Counter %x Gate error\n", i); + break; + } + } +} +void rcntWtarget(int index, u32 value) { + +#ifdef EECNT_LOG + EECNT_LOG("EE target write %d target %x value %x\n", index, counters[index].target, value); +#endif + counters[index].target = value & 0xffff; + if(counters[index].target <= rcntCycle(index)/* && counters[index].target != 0*/) { + //SysPrintf("EE Saving target %d from early trigger, target = %x, count = %x\n", index, counters[index].target, rcntCycle(index)); + counters[index].target += 0x10000000; + } + rcntSet(); +} + +void rcntWhold(int index, u32 value) { +#ifdef EECNT_LOG + EECNT_LOG("EE hold write %d value %x\n", index, value); +#endif + counters[index].hold = value; +} + +u16 rcntRcount(int index) { + u16 ret; + + if ((counters[index].mode & 0x80)) { + ret = counters[index].count + (int)((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); + }else{ + ret = counters[index].count; + } +#ifdef EECNT_LOG + EECNT_LOG("EE count read %d value %x\n", index, ret); +#endif + return (u16)ret; +} + +u32 rcntCycle(int index) { + + if ((counters[index].mode & 0x80)) { + return (u32)counters[index].count + (int)((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); + }else{ + return (u32)counters[index].count; + } +} + +int rcntFreeze(gzFile f, int Mode) { + gzfreezel(counters); + gzfreeze(&nextCounter, sizeof(nextCounter)); + gzfreeze(&nextsCounter, sizeof(nextsCounter)); + + return 0; +} + diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h new file mode 100644 index 0000000000..2c4049e0d4 --- /dev/null +++ b/pcsx2/Counters.h @@ -0,0 +1,46 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __COUNTERS_H__ +#define __COUNTERS_H__ + +typedef struct { + u32 count, mode, target, hold; + u32 rate, interrupt; + u32 Cycle, sCycle; + u32 CycleT, sCycleT; +} Counter; + +extern Counter counters[6]; +extern u32 nextCounter, nextsCounter; + +void rcntInit(); +void rcntUpdate(); +void rcntStartGate(int mode); +void rcntEndGate(int mode); +void rcntWcount(int index, u32 value); +void rcntWmode(int index, u32 value); +void rcntWtarget(int index, u32 value); +void rcntWhold(int index, u32 value); +u16 rcntRcount(int index); +u32 rcntCycle(int index); +int rcntFreeze(gzFile f, int Mode); + +void UpdateVSyncRate(); + +#endif /* __COUNTERS_H__ */ diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h new file mode 100644 index 0000000000..1b149bcedb --- /dev/null +++ b/pcsx2/DebugTools/Debug.h @@ -0,0 +1,145 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include +#include + +#include "PS2Edefs.h" +#include "Misc.h" + +extern FILE *emuLog; + +char* disR5900F(u32 code, u32 pc); +char* disR5900Fasm(u32 code, u32 pc); +char* disR3000Fasm(u32 code, u32 pc); + +void disR5900AddSym(u32 addr, char *name); +char* disR5900GetSym(u32 addr); +char* disR5900GetUpperSym(u32 addr); +void disR5900FreeSyms(); + +char* disVU0MicroUF(u32 code, u32 pc); +char* disVU0MicroLF(u32 code, u32 pc); +char* disVU1MicroUF(u32 code, u32 pc); +char* disVU1MicroLF(u32 code, u32 pc); + +char* disR3000AF(u32 code, u32 pc); + +extern char *CP2VFnames[]; +extern char *disRNameCP2f[]; +extern char *disRNameCP2i[]; + +//that way is slower but you now not need to compile every time ;P +#ifdef PCSX2_DEVBUILD + +extern int Log; +extern u32 varLog; +extern u16 logProtocol; +extern u8 logSource; + +void __Log(char *fmt, ...); + +//memcars has the same number as PAD_LOG +#define MEMCARDS_LOG if (varLog & 0x02000000) {logProtocol=7; logSource='I';} if (varLog & 0x02000000) __Log + +#define CPU_LOG if (varLog & 0x00000001) {logProtocol=1; logSource='E';} if (varLog & 0x00000001) __Log +#define MEM_LOG if (varLog & 0x00000002) {logProtocol=6; logSource='E';} if (varLog & 0x00000002) __Log("%8.8lx: ", cpuRegs.pc); if (varLog & 0x00000002) __Log +#define HW_LOG if (varLog & 0x00000004) {logProtocol=6; logSource='E';} if (varLog & 0x00000004) __Log("%8.8lx: ", cpuRegs.pc); if (varLog & 0x00000004) __Log +#define DMA_LOG if (varLog & 0x00000008) {logProtocol=5; logSource='E';} if (varLog & 0x00000008) __Log +#define BIOS_LOG if (varLog & 0x00000010) {logProtocol=0; logSource='E';} if (varLog & 0x00000010) __Log("%8.8lx: ", cpuRegs.pc); if (varLog & 0x00000010) __Log +#define ELF_LOG if (varLog & 0x00000020) {logProtocol=7; logSource='E';} if (varLog & 0x00000020) __Log +#define FPU_LOG if (varLog & 0x00000040) {logProtocol=1; logSource='E';} if (varLog & 0x00000040) __Log +#define MMI_LOG if (varLog & 0x00000080) {logProtocol=1; logSource='E';} if (varLog & 0x00000080) __Log +#define VU0_LOG if (varLog & 0x00000100) {logProtocol=2; logSource='E';} if (varLog & 0x00000100) __Log +#define COP0_LOG if (varLog & 0x00000200) {logProtocol=1; logSource='E';} if (varLog & 0x00000200) __Log +#define VIF_LOG if (varLog & 0x00000400) {logProtocol=3; logSource='E';} if (varLog & 0x00000400) __Log +#define SPR_LOG if (varLog & 0x00000800) {logProtocol=7; logSource='E';} if (varLog & 0x00000800) __Log +#define GIF_LOG if (varLog & 0x00001000) {logProtocol=4; logSource='E';} if (varLog & 0x00001000) __Log +#define SIF_LOG if (varLog & 0x00002000) {logProtocol=9; logSource='E';} if (varLog & 0x00002000) __Log +#define IPU_LOG if (varLog & 0x00004000) {logProtocol=8; logSource='E';} if (varLog & 0x00004000) __Log +#define VUM_LOG if (varLog & 0x00008000) {logProtocol=2; logSource='E';} if (varLog & 0x00008000) __Log +#define RPC_LOG if (varLog & 0x00010000) {logProtocol=9; logSource='E';} if (varLog & 0x00010000) __Log + +#define PSXCPU_LOG if (varLog & 0x00100000) {logProtocol=1; logSource='I';} if (varLog & 0x00100000) __Log +#define PSXMEM_LOG if (varLog & 0x00200000) {logProtocol=6; logSource='I';} if (varLog & 0x00200000) __Log("%8.8lx : ", psxRegs.pc); if (varLog & 0x00200000) __Log +#define PSXHW_LOG if (varLog & 0x00400000) {logProtocol=2; logSource='I';} if (varLog & 0x00400000) __Log("%8.8lx : ", psxRegs.pc); if (varLog & 0x00400000) __Log +#define PSXBIOS_LOG if (varLog & 0x00800000) {logProtocol=0; logSource='I';} if (varLog & 0x00800000) __Log("%8.8lx : ", psxRegs.pc); if (varLog & 0x00800000) __Log +#define PSXDMA_LOG if (varLog & 0x01000000) {logProtocol=5; logSource='I';} if (varLog & 0x01000000) __Log + +#define PAD_LOG if (varLog & 0x02000000) {logProtocol=7; logSource='I';} if (varLog & 0x02000000) __Log +#define GTE_LOG if (varLog & 0x04000000) {logProtocol=3; logSource='I';} if (varLog & 0x04000000) __Log +#define CDR_LOG if (varLog & 0x08000000) {logProtocol=8; logSource='I';} if (varLog & 0x08000000) __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); if (varLog & 0x08000000) __Log +#define GPU_LOG if (varLog & 0x10000000) {logProtocol=4; logSource='I';} if (varLog & 0x10000000) __Log +#define PSXCNT_LOG if (varLog & 0x20000000) {logProtocol=0; logSource='I';} if (varLog & 0x20000000) __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); if (varLog & 0x20000000) __Log +#define EECNT_LOG if (varLog & 0x40000000) {logProtocol=0; logSource='I';} if (varLog & 0x40000000) __Log("%8.8lx %8.8lx: ", cpuRegs.pc, cpuRegs.cycle); if (varLog & 0x40000000) __Log + +#if defined (CPU_LOG) || defined(MEM_LOG) || defined(HW_LOG) || defined(DMA_LOG) || \ + defined(BIOS_LOG) || defined(ELF_LOG) || defined(FPU_LOG) || defined(MMI_LOG) || \ + defined(VU0_LOG) || defined(COP0_LOG) || defined(VIF_LOG) || defined(SPR_LOG) || \ + defined(GIF_LOG) || defined(SIF_LOG) || defined(IPU_LOG) || defined(VUM_log) || \ + defined(PSXCPU_LOG) || defined(PSXMEM_LOG)|| defined(IOPBIOS_LOG)|| defined(IOPHW_LOG)|| \ + defined(PAD_LOG) || defined(GTE_LOG) || defined(CDR_LOG) || defined(GPU_LOG) || \ + defined(MEMCARDS_LOG)|| defined(PSXCNT_LOG) || defined(EECNT_LOG) +#define EMU_LOG __Log +#endif + +#else // PCSX2_DEVBUILD + +#define varLog 0 +#define Log 0 + +#define CPU_LOG 0&& +#define MEM_LOG 0&& +#define HW_LOG 0&& +#define DMA_LOG 0&& +#define BIOS_LOG 0&& +#define ELF_LOG 0&& +#define FPU_LOG 0&& +#define MMI_LOG 0&& +#define VU0_LOG 0&& +#define COP0_LOG 0&& +#define VIF_LOG 0&& +#define SPR_LOG 0&& +#define GIF_LOG 0&& +#define SIF_LOG 0&& +#define IPU_LOG 0&& +#define VUM_LOG 0&& +#define RPC_LOG 0&& + +#define PSXCPU_LOG 0&& +#define PSXMEM_LOG 0&& +#define PSXHW_LOG 0&& +#define PSXBIOS_LOG 0&& +#define PSXDMA_LOG 0&& + +#define PAD_LOG 0&& +#define GTE_LOG 0&& +#define CDR_LOG 0&& +#define GPU_LOG 0&& +#define PSXCNT_LOG 0&& +#define EECNT_LOG 0&& + +#define EMU_LOG 0&& + +#endif + +#endif /* __DEBUG_H__ */ diff --git a/pcsx2/DebugTools/DisASM.h b/pcsx2/DebugTools/DisASM.h new file mode 100644 index 0000000000..d7cbcc0536 --- /dev/null +++ b/pcsx2/DebugTools/DisASM.h @@ -0,0 +1,54 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "R5900.h" + +//DECODE PROCUDURES + +//cop0 +#define DECODE_FS (DECODE_RD) +#define DECODE_FT (DECODE_RT) +#define DECODE_FD (DECODE_SA) +///******** + +#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) +#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register +#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) +#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) +#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) +#define DECODE_BREAK (DECODE_SYSCALL) +#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) + +//IOP + +#define DECODE_RD_IOP ((psxRegs.code >> 11) & 0x1F) +#define DECODE_RT_IOP ((psxRegs.code >> 16) & 0x1F) +#define DECODE_RS_IOP ((psxRegs.code >> 21) & 0x1F) +#define DECODE_IMMED_IOP ( psxRegs.code & 0xFFFF) +#define DECODE_SA_IOP ((psxRegs.code >> 6) & 0x1F) +#define DECODE_FS_IOP (DECODE_RD_IOP) + diff --git a/pcsx2/DebugTools/DisR3000A.c b/pcsx2/DebugTools/DisR3000A.c new file mode 100644 index 0000000000..d99829d0ad --- /dev/null +++ b/pcsx2/DebugTools/DisR3000A.c @@ -0,0 +1,318 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Debug.h" + +char ostr[256]; + +// Names of registers +static char *disRNameGPR[] = { + "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra"}; + +static char *disRNameCP0[] = { + "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", + "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , + "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; + + +// Type deffinition of our functions + +typedef char* (*TdisR3000AF)(u32 code, u32 pc); + +// These macros are used to assemble the disassembler functions +#define MakeDisFg(fn, b) char* fn(u32 code, u32 pc) { b; return ostr; } +#define MakeDisF(fn, b) \ + static char* fn(u32 code, u32 pc) { \ + sprintf (ostr, "%8.8lx %8.8lx:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + + +#include "R3000A.h" + +#undef _Funct_ +#undef _Rd_ +#undef _Rt_ +#undef _Rs_ +#undef _Sa_ +#undef _Im_ +#undef _Target_ + +#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register + +#define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) +#define _Branch_ (pc + 4 + ((short)_Im_ * 4)) +#define _OfB_ _Im_, _nRs_ + +#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) +#define dGPR(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i]) +#define dCP0(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i]) +#define dHI() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.hi, "hi") +#define dLO() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.lo, "lo") +#define dImm() sprintf(ostr, "%s %4.4lx (%ld),", ostr, _Im_, _Im_) +#define dTarget() sprintf(ostr, "%s %8.8lx,", ostr, _Target_) +#define dSa() sprintf(ostr, "%s %2.2lx (%ld),", ostr, _Sa_, _Sa_) +#define dOfB() sprintf(ostr, "%s %4.4lx (%8.8lx (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_]) +#define dOffset() sprintf(ostr, "%s %8.8lx,", ostr, _Branch_) +#define dCode() sprintf(ostr, "%s %8.8lx,", ostr, (code >> 6) & 0xffffff) + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +MakeDisF(disADDI, dName("ADDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disADDIU, dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disANDI, dName("ANDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disORI, dName("ORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTI, dName("SLTI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTIU, dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disXORI, dName("XORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +MakeDisF(disADD, dName("ADD"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disADDU, dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disAND, dName("AND"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disNOR, dName("NOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disOR, dName("OR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLT, dName("SLT"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLTU, dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUB, dName("SUB"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUBU, dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disXOR, dName("XOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register arithmetic & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +MakeDisF(disDIV, dName("DIV"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disDIVU, dName("DIVU"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULT, dName("MULT"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULTU, dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +MakeDisF(disBGEZ, dName("BGEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGTZ, dName("BGTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLEZ, dName("BLEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZ, dName("BLTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR(_Rs_); dOffset();) + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +MakeDisF(disSLL, if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); }) +MakeDisF(disSRA, dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();) +MakeDisF(disSRL, dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +MakeDisF(disSLLV, dName("SLLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRAV, dName("SRAV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRLV, dName("SRLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +MakeDisF(disLUI, dName("LUI"); dGPR(_Rt_); dImm();) + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMFHI, dName("MFHI"); dGPR(_Rd_); dHI();) +MakeDisF(disMFLO, dName("MFLO"); dGPR(_Rd_); dLO();) + +/********************************************************* +* Move from GPR to HI/LO * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMTHI, dName("MTHI"); dHI(); dGPR(_Rs_);) +MakeDisF(disMTLO, dName("MTLO"); dLO(); dGPR(_Rs_);) + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +MakeDisF(disBREAK, dName("BREAK")) +MakeDisF(disRFE, dName("RFE")) +MakeDisF(disSYSCALL, dName("SYSCALL")) + + + +MakeDisF(disRTPS, dName("RTPS")) +MakeDisF(disOP , dName("OP")) +MakeDisF(disNCLIP, dName("NCLIP")) +MakeDisF(disDPCS, dName("DPCS")) +MakeDisF(disINTPL, dName("INTPL")) +MakeDisF(disMVMVA, dName("MVMVA")) +MakeDisF(disNCDS , dName("NCDS")) +MakeDisF(disCDP , dName("CDP")) +MakeDisF(disNCDT , dName("NCDT")) +MakeDisF(disNCCS , dName("NCCS")) +MakeDisF(disCC , dName("CC")) +MakeDisF(disNCS , dName("NCS")) +MakeDisF(disNCT , dName("NCT")) +MakeDisF(disSQR , dName("SQR")) +MakeDisF(disDCPL , dName("DCPL")) +MakeDisF(disDPCT , dName("DPCT")) +MakeDisF(disAVSZ3, dName("AVSZ3")) +MakeDisF(disAVSZ4, dName("AVSZ4")) +MakeDisF(disRTPT , dName("RTPT")) +MakeDisF(disGPF , dName("GPF")) +MakeDisF(disGPL , dName("GPL")) +MakeDisF(disNCCT , dName("NCCT")) + +MakeDisF(disMFC2, dName("MFC2"); dGPR(_Rt_);) +MakeDisF(disCFC2, dName("CFC2"); dGPR(_Rt_);) +MakeDisF(disMTC2, dName("MTC2")) +MakeDisF(disCTC2, dName("CTC2")) + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +MakeDisF(disBEQ, dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) +MakeDisF(disBNE, dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +MakeDisF(disJ, dName("J"); dTarget();) +MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR(31);) + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +MakeDisF(disJR, dName("JR"); dGPR(_Rs_);) +MakeDisF(disJALR, dName("JALR"); dGPR(_Rs_); dGPR(_Rd_)) + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +MakeDisF(disLB, dName("LB"); dGPR(_Rt_); dOfB();) +MakeDisF(disLBU, dName("LBU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLH, dName("LH"); dGPR(_Rt_); dOfB();) +MakeDisF(disLHU, dName("LHU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLW, dName("LW"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWL, dName("LWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWR, dName("LWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWC2, dName("LWC2"); dGPR(_Rt_); dOfB();) +MakeDisF(disSB, dName("SB"); dGPR(_Rt_); dOfB();) +MakeDisF(disSH, dName("SH"); dGPR(_Rt_); dOfB();) +MakeDisF(disSW, dName("SW"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWL, dName("SWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWR, dName("SWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWC2, dName("SWC2"); dGPR(_Rt_); dOfB();) + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +MakeDisF(disMFC0, dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disMTC0, dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);) +MakeDisF(disCFC0, dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disCTC0, dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);) + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +MakeDisF(disNULL, dName("*** Bad OP ***");) + + +TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL + disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , + disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , + disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , + disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , + disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , + disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL}; + +MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](code, pc)) + +TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND + disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](code, pc)) + +TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 + disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disCOP0, disR3000A_COP0[_Rs_](code, pc)) + +TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) + disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](code, pc)) + +TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) + disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, + disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, + disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, + disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, + disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, + disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT }; + +MakeDisF(disCOP2, disR3000A_COP2[_Funct_](code, pc)) + +TdisR3000AF disR3000A[] = { + disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , + disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , + disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , + disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , + disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , + disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disSWC2 , disNULL , disNULL, disNULL, disNULL , disNULL }; + +MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) diff --git a/pcsx2/DebugTools/DisR3000asm.c b/pcsx2/DebugTools/DisR3000asm.c new file mode 100644 index 0000000000..4ffd9644a6 --- /dev/null +++ b/pcsx2/DebugTools/DisR3000asm.c @@ -0,0 +1,361 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "Debug.h" +#include "R5900.h" +#include "R3000A.h" +#include "DisASM.h" + +unsigned long IOP_opcode_addr; + +char *GPR_IOP_REG[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; +char *COP0_IOP_REG[32] ={ + "Index","Random","EntryLo0","EntryLo1","Context","PageMask", + "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", + "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", + "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", + "TagHi","ErrorPC","C0r31" +}; +void IOPD_SPECIAL(char *buf); +void IOPD_REGIMM(char *buf); +void IOPD_J(char *buf); +void IOPD_JAL(char *buf); +void IOPD_BEQ(char *buf); +void IOPD_BNE(char *buf); +void IOPD_BLEZ(char *buf); +void IOPD_BGTZ(char *buf); +void IOPD_ADDI(char *buf); +void IOPD_ADDIU(char *buf); +void IOPD_SLTI(char *buf); +void IOPD_SLTIU(char *buf); +void IOPD_ANDI(char *buf); +void IOPD_ORI(char *buf); +void IOPD_XORI(char *buf); +void IOPD_LUI(char *buf); +void IOPD_COP0(char *buf); +void IOPD_COP2(char *buf); +void IOPD_LB(char *buf); +void IOPD_LH(char *buf); +void IOPD_LWL(char *buf); +void IOPD_LW(char *buf); +void IOPD_LBU(char *buf); +void IOPD_LHU(char *buf); +void IOPD_LWR(char *buf); +void IOPD_SB(char *buf); +void IOPD_SH(char *buf); +void IOPD_SWL(char *buf); +void IOPD_SW(char *buf); +void IOPD_SWR(char *buf); +void IOPD_LWC2(char *buf); +void IOPD_SWC2(char *buf); + +void IOPD_SLL(char *buf); +void IOPD_SRL(char *buf); +void IOPD_SRA(char *buf); +void IOPD_SLLV(char *buf); +void IOPD_SRLV(char *buf); +void IOPD_SRAV(char *buf); +void IOPD_JR(char *buf); +void IOPD_JALR(char *buf); +void IOPD_SYSCALL(char *buf); +void IOPD_BREAK(char *buf); +void IOPD_MFHI(char *buf); +void IOPD_MTHI(char *buf); +void IOPD_MFLO(char *buf); +void IOPD_MTLO(char *buf); +void IOPD_MULT(char *buf); +void IOPD_MULTU(char *buf); +void IOPD_DIV(char *buf); +void IOPD_DIVU(char *buf); +void IOPD_ADD(char *buf); +void IOPD_ADDU(char *buf); +void IOPD_SUB(char *buf); +void IOPD_SUBU(char *buf); +void IOPD_AND(char *buf); +void IOPD_OR(char *buf); +void IOPD_XOR(char *buf); +void IOPD_NOR(char *buf); +void IOPD_SLT(char *buf); +void IOPD_SLTU(char *buf); + + +void IOPD_BLTZ(char *buf); +void IOPD_BGEZ(char *buf); +void IOPD_BLTZAL(char *buf); +void IOPD_BGEZAL(char *buf); + + + +void IOPD_MFC0(char *buf); +void IOPD_CFC0(char *buf); +void IOPD_MTC0(char *buf); +void IOPD_CTC0(char *buf); +void IOPD_RFE(char *buf); + + + +void IOPD_BASIC(char *buf); +void IOPD_RTPS(char *buf); +void IOPD_NCLIP(char *buf); +void IOPD_OP(char *buf); +void IOPD_DPCS(char *buf); +void IOPD_INTPL(char *buf); +void IOPD_MVMVA(char *buf); +void IOPD_NCDS(char *buf); +void IOPD_CDP(char *buf); +void IOPD_NCDT(char *buf); +void IOPD_NCCS(char *buf); +void IOPD_CC(char *buf); +void IOPD_NCS(char *buf); +void IOPD_NCT(char *buf); +void IOPD_SQR(char *buf); +void IOPD_DCPL(char *buf); +void IOPD_DPCT(char *buf); +void IOPD_AVSZ3(char *buf); +void IOPD_AVSZ4(char *buf); +void IOPD_RTPT(char *buf); +void IOPD_GPF(char *buf); +void IOPD_GPL(char *buf); +void IOPD_NCCT(char *buf); + + + +void IOPD_MFC2(char *buf); +void IOPD_CFC2(char *buf); +void IOPD_MTC2(char *buf); +void IOPD_CTC2(char *buf); +void IOPD_NULL(char *buf); + + + + void (*IOP_DEBUG_BSC[64])(char *buf) = { + IOPD_SPECIAL, IOPD_REGIMM, IOPD_J , IOPD_JAL , IOPD_BEQ , IOPD_BNE , IOPD_BLEZ, IOPD_BGTZ, + IOPD_ADDI , IOPD_ADDIU , IOPD_SLTI, IOPD_SLTIU, IOPD_ANDI, IOPD_ORI , IOPD_XORI, IOPD_LUI , + IOPD_COP0 , IOPD_NULL , IOPD_COP2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_LB , IOPD_LH , IOPD_LWL , IOPD_LW , IOPD_LBU , IOPD_LHU , IOPD_LWR , IOPD_NULL, + IOPD_SB , IOPD_SH , IOPD_SWL , IOPD_SW , IOPD_NULL, IOPD_NULL, IOPD_SWR , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_LWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_SWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + + +void (*IOP_DEBUG_SPC[64])(char *buf) = { + IOPD_SLL , IOPD_NULL , IOPD_SRL , IOPD_SRA , IOPD_SLLV , IOPD_NULL , IOPD_SRLV, IOPD_SRAV, + IOPD_JR , IOPD_JALR , IOPD_NULL, IOPD_NULL, IOPD_SYSCALL, IOPD_BREAK, IOPD_NULL, IOPD_NULL, + IOPD_MFHI, IOPD_MTHI , IOPD_MFLO, IOPD_MTLO, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_MULT, IOPD_MULTU, IOPD_DIV , IOPD_DIVU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_ADD , IOPD_ADDU , IOPD_SUB , IOPD_SUBU, IOPD_AND , IOPD_OR , IOPD_XOR , IOPD_NOR , + IOPD_NULL, IOPD_NULL , IOPD_SLT , IOPD_SLTU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_REG[32])(char *buf) = { + IOPD_BLTZ , IOPD_BGEZ , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_BLTZAL, IOPD_BGEZAL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_CP0[32])(char *buf) = { + IOPD_MFC0, IOPD_NULL, IOPD_CFC0, IOPD_NULL, IOPD_MTC0, IOPD_NULL, IOPD_CTC0, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_RFE , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_CP2[64])(char *buf) = { + IOPD_BASIC, IOPD_RTPS , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NCLIP, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_OP , IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_DPCS , IOPD_INTPL, IOPD_MVMVA, IOPD_NCDS, IOPD_CDP , IOPD_NULL , IOPD_NCDT , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NCCS, IOPD_CC , IOPD_NULL , IOPD_NCS , IOPD_NULL, + IOPD_NCT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_SQR , IOPD_DCPL , IOPD_DPCT , IOPD_NULL, IOPD_NULL, IOPD_AVSZ3, IOPD_AVSZ4, IOPD_NULL, + IOPD_RTPT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_GPF , IOPD_GPL , IOPD_NCCT +}; + +void (*IOP_DEBUG_CP2BSC[32])(char *buf) = { + IOPD_MFC2, IOPD_NULL, IOPD_CFC2, IOPD_NULL, IOPD_MTC2, IOPD_NULL, IOPD_CTC2, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +static char dbuf2[1024]; +static char obuf2[1024]; + +char *disR3000Fasm(u32 code, u32 pc) { + u32 scode = psxRegs.code; + IOP_opcode_addr = pc; + psxRegs.code = code; + IOP_DEBUG_BSC[(code) >> 26](dbuf2); + + sprintf(obuf2, "%08lX:\t%s", pc, dbuf2); + + psxRegs.code = scode; + return obuf2; +} +char *IOP_jump_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = (IOP_opcode_addr & 0xf0000000)|((psxRegs.code&0x3ffffff)<<2); + sprintf(buf, "0x%08lX", addr); + return buf; +} +char *IOP_offset_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = ((((short)( psxRegs.code & 0xFFFF) * 4) + IOP_opcode_addr + 4)); + sprintf(buf, "0x%08lX", addr); + return buf; +} +//basic table +void IOPD_SPECIAL(char *buf){IOP_DEBUG_SPC[((psxRegs.code) & 0x3F)](buf);} +void IOPD_REGIMM(char *buf){IOP_DEBUG_REG[DECODE_RT_IOP](buf);} +void IOPD_J(char *buf) { sprintf(buf, "j\t%s", IOP_jump_decode());} +void IOPD_JAL(char *buf){sprintf(buf, "jal\t%s", IOP_jump_decode());} +void IOPD_BEQ(char *buf){sprintf(buf, "beq\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } +void IOPD_BNE(char *buf){sprintf(buf, "bne\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } +void IOPD_BLEZ(char *buf){sprintf(buf, "blez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGTZ(char *buf){sprintf(buf, "bgtz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_ADDI(char *buf){sprintf(buf, "addi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ADDIU(char *buf){sprintf(buf, "addiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_SLTI(char *buf){sprintf(buf, "slti\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_SLTIU(char *buf){sprintf(buf, "sltiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ANDI(char *buf){sprintf(buf, "andi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ORI(char *buf){sprintf(buf, "ori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } +void IOPD_XORI(char *buf){sprintf(buf, "xori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } +void IOPD_LUI(char *buf){sprintf(buf, "lui\t%s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP); } +void IOPD_COP0(char *buf){IOP_DEBUG_CP0[DECODE_RS_IOP](buf);} +void IOPD_COP2(char *buf){IOP_DEBUG_CP2[((psxRegs.code) & 0x3F)](buf);} +void IOPD_LB(char *buf){sprintf(buf, "lb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LH(char *buf){sprintf(buf, "lh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LWL(char *buf){sprintf(buf, "lwl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LW(char *buf){sprintf(buf, "lw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LBU(char *buf){sprintf(buf, "lbu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LHU(char *buf){sprintf(buf, "lhu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LWR(char *buf){sprintf(buf, "lwr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SB(char *buf){sprintf(buf, "sb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SH(char *buf){sprintf(buf, "sh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SWL(char *buf){sprintf(buf, "swl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SW(char *buf){sprintf(buf, "sw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SWR(char *buf){sprintf(buf, "swr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_LWC2(char *buf){strcpy(buf, "lwc2");} +void IOPD_SWC2(char *buf){strcpy(buf, "swc2");} +//special table +void IOPD_SLL(char *buf) +{ + if (psxRegs.code == 0x00000000) + strcpy(buf, "nop"); + else + sprintf(buf, "sll\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); +} +void IOPD_SRL(char *buf){sprintf(buf, "srl\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); } +void IOPD_SRA(char *buf){sprintf(buf, "sra\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP);} +void IOPD_SLLV(char *buf){sprintf(buf, "sllv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SRLV(char *buf){sprintf(buf, "srlv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SRAV(char *buf){sprintf(buf, "srav\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_JR(char *buf){sprintf(buf, "jr\t%s", GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_JALR(char *buf) +{ + int rd = DECODE_RD_IOP; + + if (rd == 31) + sprintf(buf, "jalr\t%s", GPR_IOP_REG[DECODE_RS_IOP]); + else + sprintf(buf, "jalr\t%s, %s", GPR_IOP_REG[rd], GPR_IOP_REG[DECODE_RS_IOP]); +} + +void IOPD_SYSCALL(char *buf){strcpy(buf, "syscall");} +void IOPD_BREAK(char *buf){strcpy(buf, "break");} +void IOPD_MFHI(char *buf){sprintf(buf, "mfhi\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } +void IOPD_MTHI(char *buf){sprintf(buf, "mthi\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_MFLO(char *buf){sprintf(buf, "mflo\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } +void IOPD_MTLO(char *buf){sprintf(buf, "mtlo\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_MULT(char *buf){sprintf(buf, "mult\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_MULTU(char *buf){sprintf(buf, "multu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_DIV(char *buf){sprintf(buf, "div\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_DIVU(char *buf){sprintf(buf, "divu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } + +void IOPD_ADD(char *buf) { sprintf(buf, "add\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_ADDU(char *buf) { sprintf(buf, "addu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SUB(char *buf) { sprintf(buf, "sub\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SUBU(char *buf) { sprintf(buf, "subu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_AND(char *buf) { sprintf(buf, "and\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_OR(char *buf) { sprintf(buf, "or\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_XOR(char *buf) { sprintf(buf, "xor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_NOR(char *buf) { sprintf(buf, "nor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SLT(char *buf) { sprintf(buf, "slt\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SLTU(char *buf) { sprintf(buf, "sltu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +//regimm + +void IOPD_BLTZ(char *buf) { sprintf(buf, "bltz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGEZ(char *buf) { sprintf(buf, "bgez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BLTZAL(char *buf) { sprintf(buf, "bltzal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGEZAL(char *buf) { sprintf(buf, "bgezal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } + +//cop0 + +void IOPD_MFC0(char *buf){ sprintf(buf, "mfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_MTC0(char *buf){ sprintf(buf, "mtc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_CFC0(char *buf){ sprintf(buf, "cfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_CTC0(char *buf){ sprintf(buf, "ctc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_RFE(char *buf){strcpy(buf, "rfe");} +//cop2 +void IOPD_BASIC(char *buf){IOP_DEBUG_CP2BSC[DECODE_RS_IOP](buf);} +void IOPD_RTPS(char *buf){strcpy(buf, "rtps");} +void IOPD_NCLIP(char *buf){strcpy(buf, "nclip");} +void IOPD_OP(char *buf){strcpy(buf, "op");} +void IOPD_DPCS(char *buf){strcpy(buf, "dpcs");} +void IOPD_INTPL(char *buf){strcpy(buf, "intpl");} +void IOPD_MVMVA(char *buf){strcpy(buf, "mvmva");} +void IOPD_NCDS(char *buf){strcpy(buf, "ncds");} +void IOPD_CDP(char *buf){strcpy(buf, "cdp");} +void IOPD_NCDT(char *buf){strcpy(buf, "ncdt");} +void IOPD_NCCS(char *buf){strcpy(buf, "nccs");} +void IOPD_CC(char *buf){strcpy(buf, "cc");} +void IOPD_NCS(char *buf){strcpy(buf, "ncs");} +void IOPD_NCT(char *buf){strcpy(buf, "nct");} +void IOPD_SQR(char *buf){strcpy(buf, "sqr");} +void IOPD_DCPL(char *buf){strcpy(buf, "dcpl");} +void IOPD_DPCT(char *buf){strcpy(buf, "dpct");} +void IOPD_AVSZ3(char *buf){strcpy(buf, "avsz3");} +void IOPD_AVSZ4(char *buf){strcpy(buf, "avsz4");} +void IOPD_RTPT(char *buf){strcpy(buf, "rtpt");} +void IOPD_GPF(char *buf){strcpy(buf, "gpf");} +void IOPD_GPL(char *buf){strcpy(buf, "gpl");} +void IOPD_NCCT(char *buf){strcpy(buf, "ncct");} +//cop2 basic +void IOPD_MFC2(char *buf){strcpy(buf, "mfc2");} +void IOPD_CFC2(char *buf){strcpy(buf, "cfc2");} +void IOPD_MTC2(char *buf){strcpy(buf, "mtc2");} +void IOPD_CTC2(char *buf){strcpy(buf, "ctc2");} +//null +void IOPD_NULL(char *buf){strcpy(buf, "????");} diff --git a/pcsx2/DebugTools/DisR5900.c b/pcsx2/DebugTools/DisR5900.c new file mode 100644 index 0000000000..cecc6f8679 --- /dev/null +++ b/pcsx2/DebugTools/DisR5900.c @@ -0,0 +1,994 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "Debug.h" +#include "R5900.h" +#include "VU.h" + +long jumpMode; +char ostr[1024]; + +// Names of registers +char *disRNameGPR[] = { + "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra", "hi", "lo"}; // lo,hi used in rec + +char *disRNameCP0[] = { + "Index" , "Random" , "EntryLo0" , "EntryLo1", "Context" , "PageMask" , "Wired" , "*RES*", + "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID", + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "*RES*" , "*RES*" , "*RES*" , "Debug", + "DEPC" , "PerfCnt" , "ErrCtl" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "DESAVE"}; + +char *disRNameCP1[] = { + "FPR0" , "FPR1" , "FPR2" , "FPR3" , "FPR4" , "FPR5" , "FPR6" , "FPR7", + "FPR8" , "FPR9" , "FPR10", "FPR11", "FPR12", "FPR13", "FPR14", "FPR15", + "FPR16", "FPR17", "FPR18", "FPR19", "FPR20", "FPR21", "FPR22", "FPR23", + "FPR24", "FPR25", "FPR26", "FPR27", "FPR28", "FPR29", "FPR30", "FPR31"}; + +char *disRNameCP1c[] = { + "FRevID", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "FStatus"}; + +char *disRNameCP2f[] = { + "VF00", "VF01", "VF02", "VF03", "VF04", "VF05", "VF06", "VF07", + "VF08", "VF09", "VF10", "VF11", "VF12", "VF13", "VF14", "VF15", + "VF16", "VF17", "VF18", "VF19", "VF20", "VF21", "VF22", "VF23", + "VF24", "VF25", "VF26", "VF27", "VF28", "VF29", "VF30", "VF31"}; + +char *disRNameCP2i[] = { + "VI00", "VI01", "VI02", "VI03", "VI04", "VI05", "VI06", "VI07", + "VI08", "VI09", "VI10", "VI11", "VI12", "VI13", "VI14", "VI15", + "Status", "MAC", "Clip", "*RES*", "R", "I", "Q", "*RES*", + "*RES*", "*RES*", "TPC", "CMSAR0", "FBRST", "VPU-STAT", "*RES*", "CMSAR1"}; + +char *CP2VFnames[] = { "x", "y", "z", "w" }; + +// Type deffinition of our functions +#define DisFInterface (u32 code, u32 pc) +#define DisFInterfaceT (u32, u32) +#define DisFInterfaceN (code, pc) + +typedef char* (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + char* fn DisFInterface { \ + sprintf (ostr, "%8.8x %8.8x:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + +#undef _Target_ +#undef _Branch_ +#undef _Funct_ +#undef _Rd_ +#undef _Rt_ +#undef _Rs_ +#undef _Sa_ +#undef _Im_ + +#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register + + +#define _rRs_ cpuRegs.GPR.r[_Rs_].UL[1], cpuRegs.GPR.r[_Rs_].UL[0] // Rs register +#define _rRt_ cpuRegs.GPR.r[_Rt_].UL[1], cpuRegs.GPR.r[_Rt_].UL[0] // Rt register +#define _rRd_ cpuRegs.GPR.r[_Rd_].UL[1], cpuRegs.GPR.r[_Rd_].UL[0] // Rd register +#define _rSa_ cpuRegs.GPR.r[_Sa_].UL[1], cpuRegs.GPR.r[_Sa_].UL[0] // Sa register + +#define _rFs_ cpuRegs.CP0.r[_Rd_] // Fs register + +#define _rRs32_ cpuRegs.GPR.r[_Rs_].UL[0] // Rs register +#define _rRt32_ cpuRegs.GPR.r[_Rt_].UL[0] // Rt register +#define _rRd32_ cpuRegs.GPR.r[_Rd_].UL[0] // Rd register +#define _rSa32_ cpuRegs.GPR.r[_Sa_].UL[0] // Sa register + + +#define _nRs_ _rRs_, disRNameGPR[_Rs_] +#define _nRt_ _rRt_, disRNameGPR[_Rt_] +#define _nRd_ _rRd_, disRNameGPR[_Rd_] +#define _nSa_ _rSa_, disRNameGPR[_Sa_] +#define _nRd0_ _rFs_, disRNameCP0[_Rd_] + +#define _nRs32_ _rRs32_, disRNameGPR[_Rs_] +#define _nRt32_ _rRt32_, disRNameGPR[_Rt_] +#define _nRd32_ _rRd32_, disRNameGPR[_Rd_] +#define _nSa32_ _rSa32_, disRNameGPR[_Sa_] + +#define _I_ _Im_, _Im_ +#define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) +#define _Branch_ (pc + 4 + ((short)_Im_ * 4)) +#define _OfB_ _Im_, _nRs_ + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + +#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) +#define dGPR128(i) sprintf(ostr, "%s %8.8x_%8.8x_%8.8x_%8.8x (%s),", ostr, cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) +#define dGPR64(i) sprintf(ostr, "%s %8.8x_%8.8x (%s),", ostr, cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) +#define dGPR64U(i) sprintf(ostr, "%s %8.8x_%8.8x (%s),", ostr, cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], disRNameGPR[i]) +#define dGPR32(i) sprintf(ostr, "%s %8.8x (%s),", ostr, cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) + +#define dCP032(i) sprintf(ostr, "%s %8.8x (%s),", ostr, cpuRegs.CP0.r[i], disRNameCP0[i]) + +#define dCP132(i) sprintf(ostr, "%s %f (%s),", ostr, fpuRegs.fpr[i].f, disRNameCP1[i]) +#define dCP1c32(i) sprintf(ostr, "%s %8.8x (%s),", ostr, fpuRegs.fprc[i], disRNameCP1c[i]) +#define dCP1acc() sprintf(ostr, "%s %f (ACC),", ostr, fpuRegs.ACC.f) + +#define dCP2128f(i) sprintf(ostr, "%s w=%f z=%f y=%f x=%f (%s),", ostr, VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232x(i) sprintf(ostr, "%s x=%f (%s),", ostr, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232y(i) sprintf(ostr, "%s y=%f (%s),", ostr, VU0.VF[i].f.y, disRNameCP2f[i]) +#define dCP232z(i) sprintf(ostr, "%s z=%f (%s),", ostr, VU0.VF[i].f.z, disRNameCP2f[i]) +#define dCP232w(i) sprintf(ostr, "%s w=%f (%s),", ostr, VU0.VF[i].f.w, disRNameCP2f[i]) +#define dCP2ACCf() sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) +#define dCP232i(i) sprintf(ostr, "%s %8.8x (%s),", ostr, VU0.VI[i].UL, disRNameCP2i[i]) +#define dCP232iF(i) sprintf(ostr, "%s %f (%s),", ostr, VU0.VI[i].F, disRNameCP2i[i]) +#define dCP232f(i, j) sprintf(ostr, "%s Q %s=%f (%s),", ostr, CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) + +#define dHI64() sprintf(ostr, "%s %8.8x_%8.8x (%s),", ostr, cpuRegs.HI.UL[1], cpuRegs.HI.UL[0], "hi") +#define dLO64() sprintf(ostr, "%s %8.8x_%8.8x (%s),", ostr, cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], "lo") +#define dImm() sprintf(ostr, "%s %4.4x (%d),", ostr, _Im_, _Im_) +#define dTarget() sprintf(ostr, "%s %8.8x,", ostr, _Target_) +#define dSa() sprintf(ostr, "%s %2.2x (%d),", ostr, _Sa_, _Sa_) +#define dSa32() sprintf(ostr, "%s %2.2x (%d),", ostr, _Sa_+32, _Sa_+32) +#define dOfB() sprintf(ostr, "%s %4.4x (%8.8x (%s)),", ostr, _Im_, cpuRegs.GPR.r[_Rs_].UL[0], disRNameGPR[_Rs_]) +#define dOffset() sprintf(ostr, "%s %8.8x,", ostr, _Branch_) +#define dCode() sprintf(ostr, "%s %8.8x,", ostr, (code >> 6) & 0xffffff) +#define dSaR() sprintf(ostr, "%s %8.8x,", ostr, cpuRegs.sa) + +typedef struct { + u32 addr; + char name[32]; +} sSymbol; + +static sSymbol *dSyms = NULL; +static int nSyms = 0; + +void disR5900AddSym(u32 addr, char *name) { + dSyms = (sSymbol*)realloc(dSyms, sizeof(sSymbol) * (nSyms+1)); + if (dSyms == NULL) return; + dSyms[nSyms].addr = addr; + strncpy(dSyms[nSyms].name, name, 32); + nSyms++; +} + +void disR5900FreeSyms() { + if (dSyms != NULL) { free(dSyms); dSyms = NULL; } + nSyms = 0; +} + +char *disR5900GetSym(u32 addr) { + int i; + + if (dSyms == NULL) return NULL; + for (i=0; i laddr) { + laddr = dSyms[i].addr; + j = i; + } + } + if (j == -1) return NULL; + return dSyms[j].name; +} + +#define dFindSym(i) { \ + char *str = disR5900GetSym(i); \ + if (str != NULL) sprintf(ostr, "%s %s", ostr, str); \ +} + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +MakeDisF(disADDI, dName("ADDI"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) +MakeDisF(disADDIU, dName("ADDIU"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) +MakeDisF(disANDI, dName("ANDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disORI, dName("ORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disSLTI, dName("SLTI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disSLTIU, dName("SLTIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disXORI, dName("XORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disDADDI, dName("DADDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disDADDIU, dName("DADDIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +MakeDisF(disADD, dName("ADD"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disADDU, dName("ADDU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDADD, dName("DADD"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disDADDU, dName("DADDU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSUB, dName("SUB"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disSUBU, dName("SUBU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDSUB, dName("DSUB"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disDSUBU, dName("DSDBU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disAND, dName("AND"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disOR, dName("OR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disXOR, dName("XOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disNOR, dName("NOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSLT, dName("SLT"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSLTU, dName("SLTU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +MakeDisF(disJ, dName("J"); dTarget(); dFindSym(_Target_);) +MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR32(31); dFindSym(_Target_);) + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +MakeDisF(disJR, dName("JR"); dGPR32(_Rs_); dFindSym(cpuRegs.GPR.r[_Rs_].UL[0]);) +MakeDisF(disJALR, dName("JALR"); dGPR32(_Rs_); dGPR32(_Rd_); dFindSym(cpuRegs.GPR.r[_Rs_].UL[0]);) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +MakeDisF(disDIV, dName("DIV"); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDIVU, dName("DIVU"); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disMULT, dName("MULT"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) +MakeDisF(disMULTU, dName("MULTU"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +MakeDisF(disLUI, dName("LUI"); dGPR64(_Rt_); dImm();) + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMFHI, dName("MFHI"); dGPR64(_Rd_); dHI64();) +MakeDisF(disMFLO, dName("MFLO"); dGPR64(_Rd_); dLO64();) + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +MakeDisF(disMTHI, dName("MTHI"); dHI64(); dGPR64(_Rs_);) +MakeDisF(disMTLO, dName("MTLO"); dLO64(); dGPR64(_Rs_);) + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +MakeDisF(disSLL, if (code) { dName("SLL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa(); } else { dName("NOP"); }) +MakeDisF(disDSLL, dName("DSLL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSLL32, dName("DSLL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) +MakeDisF(disSRA, dName("SRA"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) +MakeDisF(disDSRA, dName("DSRA"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSRA32, dName("DSRA32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) +MakeDisF(disSRL, dName("SRL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) +MakeDisF(disDSRL, dName("DSRL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSRL32, dName("DSRL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +MakeDisF(disSLLV, dName("SLLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSLLV, dName("DSLLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) +MakeDisF(disSRAV, dName("SRAV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSRAV, dName("DSRAV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) +MakeDisF(disSRLV, dName("SRLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSRLV, dName("DSRLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +MakeDisF(disLB, dName("LB"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLBU, dName("LBU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLH, dName("LH"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLHU, dName("LHU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLW, dName("LW"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWU, dName("LWU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWL, dName("LWL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWR, dName("LWR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLD, dName("LD"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLDL, dName("LDL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLDR, dName("LDR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLQ, dName("LQ"); dGPR128(_Rt_); dOfB();) +MakeDisF(disSB, dName("SB"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSH, dName("SH"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSW, dName("SW"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSWL, dName("SWL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSWR, dName("SWR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSD, dName("SD"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSDL, dName("SDL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSDR, dName("SDR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSQ, dName("SQ"); dGPR128(_Rt_); dOfB();) + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +MakeDisF(disBEQ, dName("BEQ"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBNE, dName("BNE"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, rd * +*********************************************************/ +MakeDisF(disMFC0, dName("MFC0"); dGPR32(_Rt_); dCP032(_Rd_);) +MakeDisF(disMTC0, dName("MTC0"); dCP032(_Rd_); dGPR32(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +MakeDisF(disBGEZ, dName("BGEZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGTZ, dName("BGTZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLEZ, dName("BLEZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZ, dName("BLTZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR64(_Rs_); dOffset();) + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ + + +MakeDisF(disBEQL, dName("BEQL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBNEL, dName("BNEL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBLEZL, dName("BLEZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGTZL, dName("BGTZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZL, dName("BLTZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZL, dName("BGEZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZALL, dName("BLTZALL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZALL, dName("BGEZALL"); dGPR64(_Rs_); dOffset();) + + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +MakeDisF(disBC0F, dName("BC0F"); dOffset();) +MakeDisF(disBC0T, dName("BC0T"); dOffset();) +MakeDisF(disBC0FL, dName("BC0FL"); dOffset();) +MakeDisF(disBC0TL, dName("BC0TL"); dOffset();) + +MakeDisF(disTLBR, dName("TLBR");) +MakeDisF(disTLBWI, dName("TLBWI");) +MakeDisF(disTLBWR, dName("TLBWR");) +MakeDisF(disTLBP, dName("TLBP");) +MakeDisF(disERET, dName("ERET");) +MakeDisF(disEI, dName("EI");) +MakeDisF(disDI, dName("DI");) + +/********************************************************* +* COP1 opcodes * +* * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +MakeDisF(disMFC1, dName("MFC1"); dGPR64(_Rt_); dCP132(_Fs_);) +MakeDisF(disCFC1, dName("CFC1"); dGPR64(_Rt_); dCP1c32(_Fs_);) +MakeDisF(disMTC1, dName("MTC1"); dCP132(_Fs_); dGPR64(_Rt_);) +MakeDisF(disCTC1, dName("CTC1"); dCP1c32(_Fs_); dGPR64(_Rt_);) + +MakeDisF(disBC1F, dName("BC1F");) +MakeDisF(disBC1T, dName("BC1T");) +MakeDisF(disBC1FL, dName("BC1FL");) +MakeDisF(disBC1TL, dName("BC1TL");) + +MakeDisF(disADDs, dName("ADDs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSUBs, dName("SUBs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMULs, dName("MULs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disDIVs, dName("DIVs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSQRTs, dName("SQRTs"); dCP132(_Fd_); dCP132(_Ft_);) +MakeDisF(disABSs, dName("ABSs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disMOVs, dName("MOVs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disNEGs, dName("NEGs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disRSQRTs, dName("RSQRTs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disADDAs, dName("ADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSUBAs, dName("SUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMULAs, dName("MULAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMADDs, dName("MADDs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMSUBs, dName("MSUBs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMADDAs, dName("MADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMSUBAs, dName("MSUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCVTWs, dName("CVTWs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disMAXs, dName("MAXs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMINs, dName("MINs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCFs, dName("CFs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCEQs, dName("CEQs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCLTs, dName("CLTs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCLEs, dName("CLEs"); dCP132(_Fs_); dCP132(_Ft_);) + +MakeDisF(disCVTSw, dName("CVTSw"); dCP132(_Fd_); dCP132(_Fs_);) + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +MakeDisF(disLWC1, dName("LWC1"); dCP132(_Rt_); dOffset();) +MakeDisF(disSWC1, dName("SWC1"); dCP132(_Rt_); dOffset();) + +/********************************************************* +* Conditional Move * +* Format: OP rd, rs, rt * +*********************************************************/ + +MakeDisF(disMOVZ, dName("MOVZ"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disMOVN, dName("MOVN"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) + +/********************************************************* +* MMI opcodes * +* * +*********************************************************/ + +MakeDisF(disMULT1, dName("MULT1");) +MakeDisF(disMULTU1, dName("MULTU1");) + +/********************************************************* +* MMI0 opcodes * +* * +*********************************************************/ + +MakeDisF(disPADDW, dName("PADDW");) +MakeDisF(disPADDH, dName("PADDH");) +MakeDisF(disPADDB, dName("PADDB");) + +MakeDisF(disPADDSW, dName("PADDSW");) +MakeDisF(disPADDSH, dName("PADDSH");) +MakeDisF(disPADDSB, dName("PADDSB");) + +MakeDisF(disPSUBW, dName("PSUBW");) +MakeDisF(disPSUBH, dName("PSUBH");) +MakeDisF(disPSUBB, dName("PSUBB");) + +MakeDisF(disPSUBSW, dName("PSUBSW");) +MakeDisF(disPSUBSH, dName("PSUBSH");) +MakeDisF(disPSUBSB, dName("PSUBSB");) + +MakeDisF(disPCGTW, dName("PCGTW");) +MakeDisF(disPCGTH, dName("PCGTH");) +MakeDisF(disPCGTB, dName("PCGTB");) + +MakeDisF(disPMAXW, dName("PMAXW");) +MakeDisF(disPMAXH, dName("PMAXH");) + +MakeDisF(disPEXTLW, dName("PEXTLW"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disPEXTLH, dName("PEXTLH"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disPEXTLB, dName("PEXTLB");) +MakeDisF(disPEXTS, dName("PEXTS");) + +MakeDisF(disPPACW, dName("PPACW");) +MakeDisF(disPPACH, dName("PPACH");) +MakeDisF(disPPACB, dName("PPACB");) +MakeDisF(disPPACS, dName("PPACS");) + +/********************************************************* +* MMI1 opcodes * +* * +*********************************************************/ + +MakeDisF(disPADSBH, dName("PADSBH");) + +MakeDisF(disPABSW, dName("PABSW");) +MakeDisF(disPABSH, dName("PABSH");) + +MakeDisF(disPCEQW, dName("PCEQW");) +MakeDisF(disPCEQH, dName("PCEQH");) +MakeDisF(disPCEQB, dName("PCEQB");) + +MakeDisF(disPMINW, dName("PMINW");) +MakeDisF(disPMINH, dName("PMINH");) + +MakeDisF(disPADDUW, dName("PADDUW");) +MakeDisF(disPADDUH, dName("PADDUH");) +MakeDisF(disPADDUB, dName("PADDUB");) + +MakeDisF(disPSUBUW, dName("PSUBUW");) +MakeDisF(disPSUBUH, dName("PSUBUH");) +MakeDisF(disPSUBUB, dName("PSUBUB");) + +MakeDisF(disPEXTUW, dName("PEXTUW"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) +MakeDisF(disPEXTUH, dName("PEXTUH"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) +MakeDisF(disPEXTUB, dName("PEXTUB");) + +MakeDisF(disQFSRV, dName("QFSRV");) + +/********************************************************* +* MMI2 opcodes * +* * +*********************************************************/ + +MakeDisF(disPMADDW, dName("PMADDW");) +MakeDisF(disPMADDH, dName("PMADDH");) + +MakeDisF(disPSLLVW, dName("PSLLVW");) +MakeDisF(disPSRLVW, dName("PSRLVW");) + +MakeDisF(disPMFHI, dName("PMFHI");) +MakeDisF(disPMFLO, dName("PMFLO");) + +MakeDisF(disPINTH, dName("PINTH");) + +MakeDisF(disPMULTW, dName("PMULTW");) +MakeDisF(disPMULTH, dName("PMULTH");) + +MakeDisF(disPDIVW, dName("PDIVW");) +MakeDisF(disPDIVH, dName("PDIVH");) + +MakeDisF(disPCPYLD, dName("PCPYLD"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPAND, dName("PAND"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) +MakeDisF(disPXOR, dName("PXOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPMSUBW, dName("PMSUBW");) +MakeDisF(disPMSUBH, dName("PMSUBH");) + +MakeDisF(disPHMADH, dName("PHMADH");) +MakeDisF(disPHMSBH, dName("PHMSBH");) + +MakeDisF(disPEXEW, dName("PEXEW");) +MakeDisF(disPEXEH, dName("PEXEH");) + +MakeDisF(disPREVH, dName("PREVH");) + +MakeDisF(disPDIVBW, dName("PDIVBW");) + +MakeDisF(disPROT3W, dName("PROT3W");) + +/********************************************************* +* MMI3 opcodes * +* * +*********************************************************/ + +MakeDisF(disPMADDUW, dName("PMADDUW");) + +MakeDisF(disPSRAVW, dName("PSRAVW");) + +MakeDisF(disPMTHI, dName("PMTHI");) +MakeDisF(disPMTLO, dName("PMTLO");) + +MakeDisF(disPINTEH, dName("PINTEH");) + +MakeDisF(disPMULTUW, dName("PMULTUW");) +MakeDisF(disPDIVUW, dName("PDIVUW");) + +MakeDisF(disPCPYUD, dName("PCPYUD"); dGPR128(_Rd_); dGPR128(_Rt_); dGPR128(_Rs_);) + +MakeDisF(disPOR, dName("POR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) +MakeDisF(disPNOR, dName("PNOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPEXCH, dName("PEXCH");) +MakeDisF(disPEXCW, dName("PEXCW");) + +MakeDisF(disPCPYH, dName("PCPYH"); dGPR128(_Rd_); dGPR128(_Rt_);) + +/********************************************************* +* COP2 opcodes * +* * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _X code>>24 +#define _Y code>>23 +#define _Z code>>22 +#define _W code>>21 + +MakeDisF(disLQC2, dName("LQC2"); dCP2128f(_Rt_); dOfB();) +MakeDisF(disSQC2, dName("SQC2"); dCP2128f(_Rt_); dOfB();) + +MakeDisF(disQMFC2, dName("QMFC2");) +MakeDisF(disQMTC2, dName("QMTC2");) +MakeDisF(disCFC2, dName("CFC2"); dGPR32(_Rt_); dCP232i(_Fs_);) +MakeDisF(disCTC2, dName("CTC2"); dCP232i(_Fs_); dGPR32(_Rt_);) + +MakeDisF(disBC2F, dName("BC2F");) +MakeDisF(disBC2T, dName("BC2T");) +MakeDisF(disBC2FL, dName("BC2FL");) +MakeDisF(disBC2TL, dName("BC2TL");) + +// SPEC1 +MakeDisF(disVADD, dName("VADD");) +MakeDisF(disVADDx, dName("VADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDy, dName("VADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDz, dName("VADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDw, dName("VADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDq, dName("VADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) +MakeDisF(disVADDi, dName("VADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) +MakeDisF(disVSUB, dName("VSUB");) +MakeDisF(disVSUBx, dName("VSUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBy, dName("VSUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBz, dName("VSUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBw, dName("VSUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBq, dName("VSUBq");) +MakeDisF(disVSUBi, dName("VSUBi");) +MakeDisF(disVMADD, dName("VMADD");) +MakeDisF(disVMADDx, dName("VMADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMADDy, dName("VMADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) +MakeDisF(disVMADDz, dName("VMADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) +MakeDisF(disVMADDw, dName("VMADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) +MakeDisF(disVMADDq, dName("VMADDq");) +MakeDisF(disVMADDi, dName("VMADDi");) +MakeDisF(disVMSUB, dName("VMSUB");) +MakeDisF(disVMSUBx, dName("VMSUBx");) +MakeDisF(disVMSUBy, dName("VMSUBy");) +MakeDisF(disVMSUBz, dName("VMSUBz");) +MakeDisF(disVMSUBw, dName("VMSUBw");) +MakeDisF(disVMSUBq, dName("VMSUBq");) +MakeDisF(disVMSUBi, dName("VMSUBi");) +MakeDisF(disVMAX, dName("VMAX");) +MakeDisF(disVMAXx, dName("VMAXx");) +MakeDisF(disVMAXy, dName("VMAXy");) +MakeDisF(disVMAXz, dName("VMAXz");) +MakeDisF(disVMAXw, dName("VMAXw");) +MakeDisF(disVMAXi, dName("VMAXi");) +MakeDisF(disVMINI, dName("VMINI");) +MakeDisF(disVMINIx, dName("VMINIx");) +MakeDisF(disVMINIy, dName("VMINIy");) +MakeDisF(disVMINIz, dName("VMINIz");) +MakeDisF(disVMINIw, dName("VMINIw");) +MakeDisF(disVMINIi, dName("VMINIi");) +MakeDisF(disVMUL, dName("VMUL");) +MakeDisF(disVMULx, dName("VMULx");) +MakeDisF(disVMULy, dName("VMULy");) +MakeDisF(disVMULz, dName("VMULz");) +MakeDisF(disVMULw, dName("VMULw");) +MakeDisF(disVMULq, dName("VMULq");) +MakeDisF(disVMULi, dName("VMULi");) +MakeDisF(disVIADD, dName("VIADD");) +MakeDisF(disVIADDI, dName("VIADDI");) +MakeDisF(disVISUB, dName("VISUB");) +MakeDisF(disVIAND, dName("VIAND");) +MakeDisF(disVIOR, dName("VIOR");) +MakeDisF(disVOPMSUB, dName("VOPMSUB");) +MakeDisF(disVCALLMS, dName("VCALLMS");) +MakeDisF(disVCALLMSR, dName("VCALLMSR");) + +// SPEC2 +MakeDisF(disVADDA, dName("VADDA");) +MakeDisF(disVADDAx, dName("VADDAx");) +MakeDisF(disVADDAy, dName("VADDAy");) +MakeDisF(disVADDAz, dName("VADDAz");) +MakeDisF(disVADDAw, dName("VADDAw");) +MakeDisF(disVADDAq, dName("VADDAq");) +MakeDisF(disVADDAi, dName("VADDAi");) +MakeDisF(disVMADDA, dName("VMADDA");) +MakeDisF(disVMADDAx, dName("VMADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMADDAy, dName("VMADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) +MakeDisF(disVMADDAz, dName("VMADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) +MakeDisF(disVMADDAw, dName("VMADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) +MakeDisF(disVMADDAq, dName("VMADDAq");) +MakeDisF(disVMADDAi, dName("VMADDAi");) +MakeDisF(disVSUBAx, dName("VSUBAx");) +MakeDisF(disVSUBAy, dName("VSUBAy");) +MakeDisF(disVSUBAz, dName("VSUBAz");) +MakeDisF(disVSUBAw, dName("VSUBAw");) +MakeDisF(disVMSUBAx, dName("VMSUBAx");) +MakeDisF(disVMSUBAy, dName("VMSUBAy");) +MakeDisF(disVMSUBAz, dName("VMSUBAz");) +MakeDisF(disVMSUBAw, dName("VMSUBAw");) +MakeDisF(disVITOF0, dName("VITOF0");) +MakeDisF(disVITOF4, dName("VITOF4");) +MakeDisF(disVITOF12, dName("VITOF12");) +MakeDisF(disVITOF15, dName("VITOF15");) +MakeDisF(disVFTOI0, dName("VFTOI0");) +MakeDisF(disVFTOI4, dName("VFTOI4");) +MakeDisF(disVFTOI12, dName("VFTOI12");) +MakeDisF(disVFTOI15, dName("VFTOI15");) +MakeDisF(disVMULA, dName("VMULA");) +MakeDisF(disVMULAx, dName("VMULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMULAy, dName("VMULAy");) +MakeDisF(disVMULAz, dName("VMULAz");) +MakeDisF(disVMULAw, dName("VMULAw");) +MakeDisF(disVMOVE, dName("VMOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_);) +MakeDisF(disVMR32, dName("VMR32");) +MakeDisF(disVDIV, dName("VDIV");) +MakeDisF(disVSQRT, dName("VSQRT"); dCP232f(_Ft_, _Ftf_);) +MakeDisF(disVRSQRT, dName("VRSQRT");) +MakeDisF(disVRNEXT, dName("VRNEXT");) +MakeDisF(disVRGET, dName("VRGET");) +MakeDisF(disVRINIT, dName("VRINIT");) +MakeDisF(disVRXOR, dName("VRXOR");) +MakeDisF(disVWAITQ, dName("VWAITQ");) + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ + +MakeDisF(disSYNC, dName("SYNC");) +MakeDisF(disBREAK, dName("BREAK");) +MakeDisF(disSYSCALL, dName("SYSCALL"); dCode();) +MakeDisF(disCACHE, sprintf(ostr, "%s %-7s, %x,", ostr, "CACHE", _Rt_); dOfB();) +MakeDisF(disPREF, dName("PREF");) + +MakeDisF(disMFSA, dName("MFSA"); dGPR64(_Rd_); dSaR();) +MakeDisF(disMTSA, dName("MTSA"); dGPR64(_Rs_); dSaR();) + +MakeDisF(disMTSAB, dName("MTSAB");dGPR64(_Rs_); dImm();) +MakeDisF(disMTSAH, dName("MTSAH");dGPR64(_Rs_); dImm();) + +MakeDisF(disTGE, dName("TGE"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTGEU, dName("TGEU"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTLT, dName("TLT"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTLTU, dName("TLTU"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTEQ, dName("TEQ"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTNE, dName("TNE"); dGPR64(_Rs_); dGPR64(_Rt_);) + +MakeDisF(disTGEI, dName("TGEI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTGEIU, dName("TGEIU"); dGPR64(_Rs_); dImm();) +MakeDisF(disTLTI, dName("TLTI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTLTIU, dName("TLTIU"); dGPR64(_Rs_); dImm();) +MakeDisF(disTEQI, dName("TEQI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTNEI, dName("TNEI"); dGPR64(_Rs_); dImm();) + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +MakeDisF(disNULL, dName("*** Bad OP ***");) + +TdisR5900F disR5900_MMI0[] = { // Subset of disMMI0 + disPADDW, disPSUBW, disPCGTW, disPMAXW, + disPADDH, disPSUBH, disPCGTH, disPMAXH, + disPADDB, disPSUBB, disPCGTB, disNULL, + disNULL, disNULL, disNULL, disNULL, + disPADDSW, disPSUBSW, disPEXTLW, disPPACW, + disPADDSH, disPSUBSH, disPEXTLH, disPPACH, + disPADDSB, disPSUBSB, disPEXTLB, disPPACB, + disNULL, disNULL, disPEXTS, disPPACS}; + +MakeDisF(disMMI0, disR5900_MMI0[_Sa_] DisFInterfaceN) + +TdisR5900F disR5900_MMI1[] = { // Subset of disMMI1 + disNULL, disPABSW, disPCEQW, disPMINW, + disPADSBH, disPABSH, disPCEQH, disPMINH, + disNULL, disNULL, disPCEQB, disNULL, + disNULL, disNULL, disNULL, disNULL, + disPADDUW, disPSUBUW, disPEXTUW, disNULL, + disPADDUH, disPSUBUH, disPEXTUH, disNULL, + disPADDUB, disPSUBUB, disPEXTUB, disQFSRV, + disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disMMI1, disR5900_MMI1[_Sa_] DisFInterfaceN) + +TdisR5900F disR5900_MMI2[] = { // Subset of disMMI2 + disPMADDW, disNULL, disPSLLVW, disPSRLVW, + disPMSUBW, disNULL, disNULL, disNULL, + disPMFHI, disPMFLO, disPINTH, disNULL, + disPMULTW, disPDIVW, disPCPYLD, disNULL, + disPMADDH, disPHMADH, disPAND, disPXOR, + disPMSUBH, disPHMSBH, disNULL, disNULL, + disNULL, disNULL, disPEXEH, disPREVH, + disPMULTH, disPDIVBW, disPEXEW, disPROT3W}; + +MakeDisF(disMMI2, disR5900_MMI2[_Sa_] DisFInterfaceN) + +TdisR5900F disR5900_MMI3[] = { // Subset of disMMI3 + disPMADDUW, disNULL, disNULL, disPSRAVW, + disNULL, disNULL, disNULL, disNULL, + disPMTHI, disPMTLO, disPINTEH, disNULL, + disPMULTUW, disPDIVUW, disPCPYUD, disNULL, + disNULL, disNULL, disPOR, disPNOR, + disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disPEXCH, disPCPYH, + disNULL, disNULL, disPEXCW, disNULL}; + +MakeDisF(disMMI3, disR5900_MMI3[_Sa_] DisFInterfaceN) + +TdisR5900F disR5900_MMI[] = { // Subset of disMMI + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMMI0, disMMI2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMULT1, disMULTU1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMMI1, disMMI3, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disMMI, disR5900_MMI[_Funct_] DisFInterfaceN) + + +TdisR5900F disR5900_COP0_BC0[] = { //subset of disCOP0 BC + disBC0F, disBC0T, disBC0FL, disBC0TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP0_BC0, disR5900_COP0_BC0[_Rt_] DisFInterfaceN) + +TdisR5900F disR5900_COP0_Func[] = { //subset of disCOP0 Function + disNULL, disTLBR, disTLBWI, disNULL, disNULL, disNULL, disTLBWR, disNULL, + disTLBP, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disERET, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disEI , disDI , disNULL , disNULL, disNULL, disNULL, disNULL , disNULL +}; +MakeDisF(disCOP0_Func, disR5900_COP0_Func[_Funct_] DisFInterfaceN) + +TdisR5900F disR5900_COP0[] = { // Subset of disCOP0 + disMFC0, disNULL, disNULL, disNULL, disMTC0, disNULL, disNULL, disNULL, + disCOP0_BC0, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP0_Func, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disCOP0, disR5900_COP0[_Rs_] DisFInterfaceN) + +TdisR5900F disR5900_COP1_S[] = { //subset of disCOP1 S + disADDs, disSUBs, disMULs, disDIVs, disSQRTs, disABSs, disMOVs, disNEGs, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disRSQRTs, disNULL, + disADDAs, disSUBAs, disMULAs, disNULL, disMADDs, disMSUBs, disMADDAs, disMSUBAs, + disNULL, disNULL, disNULL, disNULL, disCVTWs, disNULL, disNULL, disNULL, + disMINs, disMAXs, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCFs, disNULL, disCEQs, disNULL, disCLTs, disNULL, disCLEs, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP1_S, disR5900_COP1_S[_Funct_] DisFInterfaceN) + +TdisR5900F disR5900_COP1_W[] = { //subset of disCOP1 W + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCVTSw, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP1_W, disR5900_COP1_W[_Funct_] DisFInterfaceN) + +TdisR5900F disR5900_COP1_BC1[] = { //subset of disCOP1 BC + disBC1F, disBC1T, disBC1FL, disBC1TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP1_BC1, disR5900_COP1_BC1[_Rt_] DisFInterfaceN) + +TdisR5900F disR5900_COP1[] = { // Subset of disCOP1 + disMFC1, disNULL, disCFC1, disNULL, disMTC1, disNULL, disCTC1, disNULL, + disCOP1_BC1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP1_S, disNULL, disNULL, disNULL, disCOP1_W, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disCOP1, disR5900_COP1[_Rs_] DisFInterfaceN) + +TdisR5900F disR5900_COP2_SPEC2[] = { //subset of disCOP2 SPEC2 + disVADDAx, disVADDAy, disVADDAz, disVADDAw, disVSUBAx, disVSUBAy, disVSUBAz, disVSUBAw, + disVMADDAx, disVMADDAy, disVMADDAz, disVMADDAw, disVMSUBAx, disVMSUBAy, disVMSUBAz, disVMSUBAw, + disVITOF0, disVITOF4, disVITOF12, disVITOF15, disVFTOI0, disVFTOI4, disVFTOI12, disVFTOI15, + disVMULAx, disVMULAy, disVMULAz, disVMULAw, disNULL, disNULL, disNULL, disNULL, + disVADDAq, disVMADDAq, disVADDAi, disVMADDAi, disNULL, disNULL, disNULL, disNULL, + disVADDA, disVMADDA, disVMULA, disNULL, disNULL, disNULL, disNULL, disNULL, + disVMOVE, disVMR32, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disVDIV, disVSQRT, disVRSQRT, disVWAITQ, disNULL, disNULL, disNULL, disNULL, + disVRNEXT, disVRGET, disVRINIT, disVRXOR, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP2_SPEC2, disR5900_COP2_SPEC2[(code & 0x3) | ((code >> 4) & 0x7c)] DisFInterfaceN) + +TdisR5900F disR5900_COP2_SPEC1[] = { //subset of disCOP2 SPEC1 + disVADDx, disVADDy, disVADDz, disVADDw, disVSUBx, disVSUBy, disVSUBz, disVSUBw, + disVMADDx, disVMADDy, disVMADDz, disVMADDw, disVMSUBx, disVMSUBy, disVMSUBz, disVMSUBw, + disVMAXx, disVMAXy, disVMAXz, disVMAXw, disVMINIx, disVMINIy, disVMINIz, disVMINIw, + disVMULx, disVMULy, disVMULz, disVMULw, disVMULq, disVMAXi, disVMULi, disVMINIi, + disVADDq, disVMADDq, disVADDi, disVMADDi, disVSUBq, disVMSUBq, disVSUBi, disVMSUBi, + disVADD, disVMADD, disVMUL, disVMAX, disVSUB, disVMSUB, disVOPMSUB, disVMINI, + disVIADD, disVISUB, disVIADDI, disNULL, disVIAND, disVIOR, disNULL, disNULL, + disVCALLMS, disVCALLMSR, disNULL, disNULL, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, +}; + +MakeDisF(disCOP2_SPEC1, disR5900_COP2_SPEC1[_Funct_] DisFInterfaceN) + +TdisR5900F disR5900_COP2_BC2[] = { //subset of disCOP2 BC + disBC2F, disBC2T, disBC2FL, disBC2TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +MakeDisF(disCOP2_BC2, disR5900_COP2_BC2[_Rt_] DisFInterfaceN) + +TdisR5900F disR5900_COP2[] = { // Subset of disCOP2 + disNULL, disQMFC2, disCFC2, disNULL, disNULL, disQMTC2, disCTC2, disNULL, + disCOP2_BC2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, + disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1}; + +MakeDisF(disCOP2, disR5900_COP2[_Rs_] DisFInterfaceN) + +TdisR5900F disR5900_REGIMM[] = { // Subset of disREGIMM + disBLTZ, disBGEZ, disBLTZL, disBGEZL, disNULL, disNULL, disNULL, disNULL, + disTGEI, disTGEIU, disTLTI, disTLTIU, disTEQI, disNULL, disTNEI, disNULL, + disBLTZAL, disBGEZAL, disBLTZALL, disBGEZALL, disNULL, disNULL, disNULL, disNULL, + disMTSAB, disMTSAH , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disREGIMM, disR5900_REGIMM[_Rt_] DisFInterfaceN) + +TdisR5900F disR5900_SPECIAL[] = { + disSLL, disNULL, disSRL, disSRA, disSLLV, disNULL, disSRLV, disSRAV, + disJR, disJALR, disMOVZ, disMOVN, disSYSCALL, disBREAK,disNULL, disSYNC, + disMFHI, disMTHI, disMFLO, disMTLO, disDSLLV, disNULL, disDSRLV, disDSRAV, + disMULT, disMULTU,disDIV, disDIVU, disNULL, disNULL, disNULL, disNULL, + disADD, disADDU, disSUB, disSUBU, disAND, disOR, disXOR, disNOR, + disMFSA , disMTSA, disSLT, disSLTU, disDADD, disDADDU,disDSUB, disDSUBU, + disTGE, disTGEU, disTLT, disTLTU, disTEQ, disNULL, disTNE, disNULL, + disDSLL, disNULL, disDSRL, disDSRA, disDSLL32, disNULL, disDSRL32,disDSRA32 }; + +MakeDisF(disSPECIAL, disR5900_SPECIAL[_Funct_] DisFInterfaceN) + +TdisR5900F disR5900[] = { + disSPECIAL, disREGIMM, disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , + disADDI , disADDIU , disSLTI, disSLTIU, disANDI, disORI , disXORI , disLUI , + disCOP0 , disCOP1 , disCOP2, disNULL , disBEQL, disBNEL, disBLEZL, disBGTZL, + disDADDI , disDADDIU, disLDL , disLDR , disMMI , disNULL, disLQ , disSQ , + disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disLWU , + disSB , disSH , disSWL , disSW , disSDL , disSDR , disSWR , disCACHE, + disNULL , disLWC1 , disNULL, disPREF , disNULL, disNULL, disLQC2 , disLD , + disNULL , disSWC1 , disNULL, disNULL , disNULL, disNULL, disSQC2 , disSD }; + +MakeDisF(disR5900F, disR5900[code >> 26] DisFInterfaceN) + diff --git a/pcsx2/DebugTools/DisR5900asm.c b/pcsx2/DebugTools/DisR5900asm.c new file mode 100644 index 0000000000..7283895bb3 --- /dev/null +++ b/pcsx2/DebugTools/DisR5900asm.c @@ -0,0 +1,1679 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "PS2Etypes.h" +#include "Debug.h" +#include "R5900.h" +#include "DisASM.h" + +unsigned long opcode_addr; + +/* +//DECODE PROCUDURES + +//cop0 +#define DECODE_FS (DECODE_RD) +#define DECODE_FT (DECODE_RT) +#define DECODE_FD (DECODE_SA) +/// ******** + +#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) +#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register +#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) +#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) +#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) +#define DECODE_BREAK (DECODE_SYSCALL) +#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) +*/ +/*************************CPUS REGISTERS**************************/ +char *GPR_REG[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; +char *COP0_REG[32] ={ + "Index","Random","EntryLo0","EntryLo1","Context","PageMask", + "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", + "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", + "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", + "TagHi","ErrorPC","C0r31" +}; +//floating point cop1 Floating point reg +char *COP1_REG_FP[32] ={ + "f00","f01","f02","f03","f04","f05","f06","f07", + "f08","f09","f10","f11","f12","f13","f14","f15", + "f16","f17","f18","f19","f20","f21","f21","f23", + "f24","f25","f26","f27","f28","f29","f30","f31" +}; +//floating point cop1 control registers +char *COP1_REG_FCR[32] ={ + "fcr00","fcr01","fcr02","fcr03","fcr04","fcr05","fcr06","fcr07", + "fcr08","fcr09","fcr10","fcr11","fcr12","fcr13","fcr14","fcr15", + "fcr16","fcr17","fcr18","fcr19","fcr20","fcr21","fcr21","fcr23", + "fcr24","fcr25","fcr26","fcr27","fcr28","fcr29","fcr30","fcr31" +}; + +//floating point cop2 reg +char *COP2_REG_FP[32] ={ + "vf00","vf01","vf02","vf03","vf04","vf05","vf06","vf07", + "vf08","vf09","vf10","vf11","vf12","vf13","vf14","vf15", + "vf16","vf17","vf18","vf19","vf20","vf21","vf21","vf23", + "vf24","vf25","vf26","vf27","vf28","vf29","vf30","vf31" +}; +//cop2 control registers + +char *COP2_REG_CTL[32] ={ + "vi00","vi01","vi02","vi03","vi04","vi05","vi06","vi07", + "vi08","vi09","vi10","vi11","vi12","vi13","vi14","vi15", + "Status","MACflag","ClipFlag","c2c19","R","I","Q","c2c23", + "c2c24","c2c25","TPC","CMSAR0","FBRST","VPU-STAT","c2c30","CMSAR1" +}; + + + + + +//**************************************************************** +void P_SpecialOpcode(char *buf); +void P_REGIMMOpcode(char *buf); +void P_UnknownOpcode(char *buf); +void P_COP0(char *buf); +void P_COP1(char *buf); +void P_COP2(char *buf); +void P_MMI_Unknown(char *buf); +void P_MMI(char *buf); +void P_MMI0(char *buf); +void P_MMI1(char *buf); +void P_MMI2(char *buf); +void P_MMI3(char *buf); +void P_COP0_Unknown(char *buf); +void P_COP0_BC0(char *buf); +void P_COP0_Func(char *buf); +void P_COP1_BC1(char *buf); +void P_COP1_S(char *buf); +void P_COP1_W(char *buf); +void P_COP1_Unknown(char *buf); +void P_COP2_BC2(char *buf); +void P_COP2_SPECIAL(char *buf); +void P_COP2_Unknown(char *buf); +void P_COP2_SPECIAL2(char *buf); + +// **********************Standard Opcodes************************** +void P_J(char *buf); +void P_JAL(char *buf); +void P_BEQ(char *buf); +void P_BNE(char *buf); +void P_BLEZ(char *buf); +void P_BGTZ(char *buf); +void P_ADDI(char *buf); +void P_ADDIU(char *buf); +void P_SLTI(char *buf); +void P_SLTIU(char *buf); +void P_ANDI(char *buf); +void P_ORI(char *buf); +void P_XORI(char *buf); +void P_LUI(char *buf); +void P_BEQL(char *buf); +void P_BNEL(char *buf); +void P_BLEZL(char *buf); +void P_BGTZL(char *buf); +void P_DADDI(char *buf); +void P_DADDIU(char *buf); +void P_LDL(char *buf); +void P_LDR(char *buf); +void P_LB(char *buf); +void P_LH(char *buf); +void P_LWL(char *buf); +void P_LW(char *buf); +void P_LBU(char *buf); +void P_LHU(char *buf); +void P_LWR(char *buf); +void P_LWU(char *buf); +void P_SB(char *buf); +void P_SH(char *buf); +void P_SWL(char *buf); +void P_SW(char *buf); +void P_SDL(char *buf); +void P_SDR(char *buf); +void P_SWR(char *buf); +void P_CACHE(char *buf); +void P_LWC1(char *buf); +void P_PREF(char *buf); +void P_LQC2(char *buf); +void P_LD(char *buf); +void P_SQC2(char *buf); +void P_SD(char *buf); +void P_LQ(char *buf); +void P_SQ(char *buf); +void P_SWC1(char *buf); +//***************end of standard opcodes************************* + + +//***************SPECIAL OPCODES********************************** +void P_SLL(char *buf); +void P_SRL(char *buf); +void P_SRA(char *buf); +void P_SLLV(char *buf); +void P_SRLV(char *buf); +void P_SRAV(char *buf); +void P_JR(char *buf); +void P_JALR(char *buf); +void P_SYSCALL(char *buf); +void P_BREAK(char *buf); +void P_SYNC(char *buf); +void P_MFHI(char *buf); +void P_MTHI(char *buf); +void P_MFLO(char *buf); +void P_MTLO(char *buf); +void P_DSLLV(char *buf); +void P_DSRLV(char *buf); +void P_DSRAV(char *buf); +void P_MULT(char *buf); +void P_MULTU(char *buf); +void P_DIV(char *buf); +void P_DIVU(char *buf); +void P_ADD(char *buf); +void P_ADDU(char *buf); +void P_SUB(char *buf); +void P_SUBU(char *buf); +void P_AND(char *buf); +void P_OR(char *buf); +void P_XOR(char *buf); +void P_NOR(char *buf); +void P_SLT(char *buf); +void P_SLTU(char *buf); +void P_DADD(char *buf); +void P_DADDU(char *buf); +void P_DSUB(char *buf); +void P_DSUBU(char *buf); +void P_TGE(char *buf); +void P_TGEU(char *buf); +void P_TLT(char *buf); +void P_TLTU(char *buf); +void P_TEQ(char *buf); +void P_TNE(char *buf); +void P_DSLL(char *buf); +void P_DSRL(char *buf); +void P_DSRA(char *buf); +void P_DSLL32(char *buf); +void P_DSRL32(char *buf); +void P_DSRA32(char *buf); +void P_MOVZ(char *buf); +void P_MOVN(char *buf); +void P_MFSA(char *buf); +void P_MTSA(char *buf); +//******************END OF SPECIAL OPCODES************************** + +//******************REGIMM OPCODES********************************** +void P_BLTZ(char *buf); +void P_BGEZ(char *buf); +void P_BLTZL(char *buf); +void P_BGEZL(char *buf); +void P_TGEI(char *buf); +void P_TGEIU(char *buf); +void P_TLTI(char *buf); +void P_TLTIU(char *buf); +void P_TEQI(char *buf); +void P_TNEI(char *buf); +void P_BLTZAL(char *buf); +void P_BGEZAL(char *buf); +void P_BLTZALL(char *buf); +void P_BGEZALL(char *buf); +void P_MTSAB(char *buf); +void P_MTSAH(char *buf); +//*****************END OF REGIMM OPCODES***************************** +//*****************MMI OPCODES********************************* +void P_MADD(char *buf); +void P_MADDU(char *buf); +void P_PLZCW(char *buf); +void P_MADD1(char *buf); +void P_MADDU1(char *buf); +void P_MFHI1(char *buf); +void P_MTHI1(char *buf); +void P_MFLO1(char *buf); +void P_MTLO1(char *buf); +void P_MULT1(char *buf); +void P_MULTU1(char *buf); +void P_DIV1(char *buf); +void P_DIVU1(char *buf); +void P_PMFHL(char *buf); +void P_PMTHL(char *buf); +void P_PSLLH(char *buf); +void P_PSRLH(char *buf); +void P_PSRAH(char *buf); +void P_PSLLW(char *buf); +void P_PSRLW(char *buf); +void P_PSRAW(char *buf); +//*****************END OF MMI OPCODES************************** +//*************************MMI0 OPCODES************************ + +void P_PADDW(char *buf); +void P_PSUBW(char *buf); +void P_PCGTW(char *buf); +void P_PMAXW(char *buf); +void P_PADDH(char *buf); +void P_PSUBH(char *buf); +void P_PCGTH(char *buf); +void P_PMAXH(char *buf); +void P_PADDB(char *buf); +void P_PSUBB(char *buf); +void P_PCGTB(char *buf); +void P_PADDSW(char *buf); +void P_PSUBSW(char *buf); +void P_PEXTLW(char *buf); +void P_PPACW(char *buf); +void P_PADDSH(char *buf); +void P_PSUBSH(char *buf); +void P_PEXTLH(char *buf); +void P_PPACH(char *buf); +void P_PADDSB(char *buf); +void P_PSUBSB(char *buf); +void P_PEXTLB(char *buf); +void P_PPACB(char *buf); +void P_PEXT5(char *buf); +void P_PPAC5(char *buf); +//***END OF MMI0 OPCODES****************************************** +//**********MMI1 OPCODES************************************** +void P_PABSW(char *buf); +void P_PCEQW(char *buf); +void P_PMINW(char *buf); +void P_PADSBH(char *buf); +void P_PABSH(char *buf); +void P_PCEQH(char *buf); +void P_PMINH(char *buf); +void P_PCEQB(char *buf); +void P_PADDUW(char *buf); +void P_PSUBUW(char *buf); +void P_PEXTUW(char *buf); +void P_PADDUH(char *buf); +void P_PSUBUH(char *buf); +void P_PEXTUH(char *buf); +void P_PADDUB(char *buf); +void P_PSUBUB(char *buf); +void P_PEXTUB(char *buf); +void P_QFSRV(char *buf); +//********END OF MMI1 OPCODES*********************************** +//*********MMI2 OPCODES*************************************** +void P_PMADDW(char *buf); +void P_PSLLVW(char *buf); +void P_PSRLVW(char *buf); +void P_PMSUBW(char *buf); +void P_PMFHI(char *buf); +void P_PMFLO(char *buf); +void P_PINTH(char *buf); +void P_PMULTW(char *buf); +void P_PDIVW(char *buf); +void P_PCPYLD(char *buf); +void P_PMADDH(char *buf); +void P_PHMADH(char *buf); +void P_PAND(char *buf); +void P_PXOR(char *buf); +void P_PMSUBH(char *buf); +void P_PHMSBH(char *buf); +void P_PEXEH(char *buf); +void P_PREVH(char *buf); +void P_PMULTH(char *buf); +void P_PDIVBW(char *buf); +void P_PEXEW(char *buf); +void P_PROT3W(char *buf); +//*****END OF MMI2 OPCODES*********************************** +//*************************MMI3 OPCODES************************ +void P_PMADDUW(char *buf); +void P_PSRAVW(char *buf); +void P_PMTHI(char *buf); +void P_PMTLO(char *buf); +void P_PINTEH(char *buf); +void P_PMULTUW(char *buf); +void P_PDIVUW(char *buf); +void P_PCPYUD(char *buf); +void P_POR(char *buf); +void P_PNOR(char *buf); +void P_PEXCH(char *buf); +void P_PCPYH(char *buf); +void P_PEXCW(char *buf); +//**********************END OF MMI3 OPCODES******************** +//**************************************************************************** +//** COP0 ** +//**************************************************************************** +void P_MFC0(char *buf); +void P_MTC0(char *buf); +void P_BC0F(char *buf); +void P_BC0T(char *buf); +void P_BC0FL(char *buf); +void P_BC0TL(char *buf); +void P_TLBR(char *buf); +void P_TLBWI(char *buf); +void P_TLBWR(char *buf); +void P_TLBP(char *buf); +void P_ERET(char *buf); +void P_DI(char *buf); +void P_EI(char *buf); +//**************************************************************************** +//** END OF COP0 ** +//**************************************************************************** +//**************************************************************************** +//** COP1 - Floating Point Unit (FPU) ** +//**************************************************************************** +void P_MFC1(char *buf); +void P_CFC1(char *buf); +void P_MTC1(char *buf); +void P_CTC1(char *buf); +void P_BC1F(char *buf); +void P_BC1T(char *buf); +void P_BC1FL(char *buf); +void P_BC1TL(char *buf); +void P_ADD_S(char *buf); +void P_SUB_S(char *buf); +void P_MUL_S(char *buf); +void P_DIV_S(char *buf); +void P_SQRT_S(char *buf); +void P_ABS_S(char *buf); +void P_MOV_S(char *buf); +void P_NEG_S(char *buf); +void P_RSQRT_S(char *buf); +void P_ADDA_S(char *buf); +void P_SUBA_S(char *buf); +void P_MULA_S(char *buf); +void P_MADD_S(char *buf); +void P_MSUB_S(char *buf); +void P_MADDA_S(char *buf); +void P_MSUBA_S(char *buf); +void P_CVT_W(char *buf); +void P_MAX_S(char *buf); +void P_MIN_S(char *buf); +void P_C_F(char *buf); +void P_C_EQ(char *buf); +void P_C_LT(char *buf); +void P_C_LE(char *buf); + void P_CVT_S(char *buf); +//**************************************************************************** +//** END OF COP1 ** +//**************************************************************************** +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void P_QMFC2(char *buf); +void P_CFC2(char *buf); +void P_QMTC2(char *buf); +void P_CTC2(char *buf); +void P_BC2F(char *buf); +void P_BC2T(char *buf); +void P_BC2FL(char *buf); +void P_BC2TL(char *buf); +//*****************SPECIAL 1 VUO TABLE******************************* +void P_VADDx(char *buf); +void P_VADDy(char *buf); +void P_VADDz(char *buf); +void P_VADDw(char *buf); +void P_VSUBx(char *buf); +void P_VSUBy(char *buf); +void P_VSUBz(char *buf); +void P_VSUBw(char *buf); +void P_VMADDx(char *buf); +void P_VMADDy(char *buf); +void P_VMADDz(char *buf); +void P_VMADDw(char *buf); +void P_VMSUBx(char *buf); +void P_VMSUBy(char *buf); +void P_VMSUBz(char *buf); +void P_VMSUBw(char *buf); +void P_VMAXx(char *buf); +void P_VMAXy(char *buf); +void P_VMAXz(char *buf); +void P_VMAXw(char *buf); +void P_VMINIx(char *buf); +void P_VMINIy(char *buf); +void P_VMINIz(char *buf); +void P_VMINIw(char *buf); +void P_VMULx(char *buf); +void P_VMULy(char *buf); +void P_VMULz(char *buf); +void P_VMULw(char *buf); +void P_VMULq(char *buf); +void P_VMAXi(char *buf); +void P_VMULi(char *buf); +void P_VMINIi(char *buf); +void P_VADDq(char *buf); +void P_VMADDq(char *buf); +void P_VADDi(char *buf); +void P_VMADDi(char *buf); +void P_VSUBq(char *buf); +void P_VMSUBq(char *buf); +void P_VSUbi(char *buf); +void P_VMSUBi(char *buf); +void P_VADD(char *buf); +void P_VMADD(char *buf); +void P_VMUL(char *buf); +void P_VMAX(char *buf); +void P_VSUB(char *buf); +void P_VMSUB(char *buf); +void P_VOPMSUB(char *buf); +void P_VMINI(char *buf); +void P_VIADD(char *buf); +void P_VISUB(char *buf); +void P_VIADDI(char *buf); +void P_VIAND(char *buf); +void P_VIOR(char *buf); +void P_VCALLMS(char *buf); +void P_CALLMSR(char *buf); +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void P_VADDAx(char *buf); +void P_VADDAy(char *buf); +void P_VADDAz(char *buf); +void P_VADDAw(char *buf); +void P_VSUBAx(char *buf); +void P_VSUBAy(char *buf); +void P_VSUBAz(char *buf); +void P_VSUBAw(char *buf); +void P_VMADDAx(char *buf); +void P_VMADDAy(char *buf); +void P_VMADDAz(char *buf); +void P_VMADDAw(char *buf); +void P_VMSUBAx(char *buf); +void P_VMSUBAy(char *buf); +void P_VMSUBAz(char *buf); +void P_VMSUBAw(char *buf); +void P_VITOF0(char *buf); +void P_VITOF4(char *buf); +void P_VITOF12(char *buf); +void P_VITOF15(char *buf); +void P_VFTOI0(char *buf); +void P_VFTOI4(char *buf); +void P_VFTOI12(char *buf); +void P_VFTOI15(char *buf); +void P_VMULAx(char *buf); +void P_VMULAy(char *buf); +void P_VMULAz(char *buf); +void P_VMULAw(char *buf); +void P_VMULAq(char *buf); +void P_VABS(char *buf); +void P_VMULAi(char *buf); +void P_VCLIPw(char *buf); +void P_VADDAq(char *buf); +void P_VMADDAq(char *buf); +void P_VADDAi(char *buf); +void P_VMADDAi(char *buf); +void P_VSUBAq(char *buf); +void P_VMSUBAq(char *buf); +void P_VSUBAi(char *buf); +void P_VMSUBAi(char *buf); +void P_VADDA(char *buf); +void P_VMADDA(char *buf); +void P_VMULA(char *buf); +void P_VSUBA(char *buf); +void P_VMSUBA(char *buf); +void P_VOPMULA(char *buf); +void P_VNOP(char *buf); +void P_VMONE(char *buf); +void P_VMR32(char *buf); +void P_VLQI(char *buf); +void P_VSQI(char *buf); +void P_VLQD(char *buf); +void P_VSQD(char *buf); +void P_VDIV(char *buf); +void P_VSQRT(char *buf); +void P_VRSQRT(char *buf); +void P_VWAITQ(char *buf); +void P_VMTIR(char *buf); +void P_VMFIR(char *buf); +void P_VILWR(char *buf); +void P_VISWR(char *buf); +void P_VRNEXT(char *buf); +void P_VRGET(char *buf); +void P_VRINIT(char *buf); +void P_VRXOR(char *buf); +//************************************END OF SPECIAL2 VUO TABLE**************************** + + +/* + CPU: Instructions encoded by opcode field. + 31---------26---------------------------------------------------0 + | opcode | | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | *1 | *2 | J | JAL | BEQ | BNE | BLEZ | BGTZ | +001 | ADDI | ADDIU | SLTI | SLTIU | ANDI | ORI | XORI | LUI | +010 | *3 | *4 | *5 | --- | BEQL | BNEL | BLEZL | BGTZL | +011 | DADDI |DADDIU | LDL | LDR | *6 | --- | LQ | SQ | +100 | LB | LH | LWL | LW | LBU | LHU | LWR | LWU | +101 | SB | SH | SWL | SW | SDL | SDR | SWR | CACHE | +110 | --- | LWC1 | --- | PREF | --- | --- | LQC2 | LD | +111 | --- | SWC1 | --- | --- | --- | --- | SQC2 | SD | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = SPECIAL, see SPECIAL list *2 = REGIMM, see REGIMM list + *3 = COP0 *4 = COP1 + *5 = COP2 *6 = MMI table +*/ +void (*OpcodePrintTable[64])(char *buf) = { + P_SpecialOpcode, P_REGIMMOpcode, P_J, P_JAL, P_BEQ, P_BNE, P_BLEZ, P_BGTZ, + P_ADDI, P_ADDIU, P_SLTI, P_SLTIU, P_ANDI, P_ORI, P_XORI, P_LUI, + P_COP0, P_COP1, P_COP2, P_UnknownOpcode, P_BEQL, P_BNEL, P_BLEZL, P_BGTZL, + P_DADDI, P_DADDIU, P_LDL, P_LDR, P_MMI, P_UnknownOpcode, P_LQ, P_SQ, + P_LB, P_LH, P_LWL, P_LW, P_LBU, P_LHU, P_LWR, P_LWU, + P_SB, P_SH, P_SWL, P_SW, P_SDL, P_SDR, P_SWR, P_CACHE, + P_UnknownOpcode, P_LWC1, P_UnknownOpcode, P_PREF, P_UnknownOpcode,P_UnknownOpcode, P_LQC2, P_LD, + P_UnknownOpcode, P_SWC1, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode,P_UnknownOpcode, P_SQC2, P_SD +}; + + + /* + SPECIAL: Instr. encoded by function field when opcode field = SPECIAL + 31---------26------------------------------------------5--------0 + | = SPECIAL | | function| + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | SLL | --- | SRL | SRA | SLLV | --- | SRLV | SRAV | +001 | JR | JALR | MOVZ | MOVN |SYSCALL| BREAK | --- | SYNC | +010 | MFHI | MTHI | MFLO | MTLO | DSLLV | --- | DSRLV | DSRAV | +011 | MULT | MULTU | DIV | DIVU | ---- | --- | ---- | ----- | +100 | ADD | ADDU | SUB | SUBU | AND | OR | XOR | NOR | +101 | MFSA | MTSA | SLT | SLTU | DADD | DADDU | DSUB | DSUBU | +110 | TGE | TGEU | TLT | TLTU | TEQ | --- | TNE | --- | +111 | DSLL | --- | DSRL | DSRA |DSLL32 | --- |DSRL32 |DSRA32 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ + +void (*SpecialPrintTable[64])(char *buf) = { + P_SLL, P_UnknownOpcode, P_SRL, P_SRA, P_SLLV, P_UnknownOpcode, P_SRLV, P_SRAV, + P_JR, P_JALR, P_MOVZ, P_MOVN, P_SYSCALL, P_BREAK, P_UnknownOpcode, P_SYNC, + P_MFHI, P_MTHI, P_MFLO, P_MTLO, P_DSLLV, P_UnknownOpcode, P_DSRLV, P_DSRAV, + P_MULT, P_MULTU, P_DIV, P_DIVU, P_UnknownOpcode,P_UnknownOpcode,P_UnknownOpcode,P_UnknownOpcode, + P_ADD, P_ADDU, P_SUB, P_SUBU, P_AND, P_OR, P_XOR, P_NOR, + P_MFSA , P_MTSA , P_SLT, P_SLTU, P_DADD, P_DADDU, P_DSUB, P_DSUBU, + P_TGE, P_TGEU, P_TLT, P_TLTU, P_TEQ, P_UnknownOpcode, P_TNE, P_UnknownOpcode, + P_DSLL, P_UnknownOpcode, P_DSRL, P_DSRA, P_DSLL32, P_UnknownOpcode, P_DSRL32, P_DSRA32 +}; + +/* + REGIMM: Instructions encoded by the rt field when opcode field = REGIMM. + 31---------26----------20-------16------------------------------0 + | = REGIMM | | rt | | + ------6---------------------5------------------------------------ + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BLTZ | BGEZ | BLTZL | BGEZL | --- | --- | --- | --- | + 01 | TGEI | TGEIU | TLTI | TLTIU | TEQI | --- | TNEI | --- | + 10 | BLTZAL| BGEZAL|BLTZALL|BGEZALL| --- | --- | --- | --- | + 11 | MTSAB | MTSAH | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*REGIMMPrintTable[32])(char *buf) = { + P_BLTZ, P_BGEZ, P_BLTZL, P_BGEZL, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, + P_TGEI, P_TGEIU, P_TLTI, P_TLTIU, P_TEQI, P_UnknownOpcode, P_TNEI, P_UnknownOpcode, + P_BLTZAL, P_BGEZAL, P_BLTZALL, P_BGEZALL, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, + P_MTSAB, P_MTSAH , P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, +}; +/* + MMI: Instr. encoded by function field when opcode field = MMI + 31---------26------------------------------------------5--------0 + | = MMI | | function| + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | MADD | MADDU | --- | --- | PLZCW | --- | --- | --- | +001 | *1 | *2 | --- | --- | --- | --- | --- | --- | +010 | MFHI1 | MTHI1 | MFLO1 | MTLO1 | --- | --- | --- | --- | +011 | MULT1 | MULTU1| DIV1 | DIVU1 | --- | --- | --- | --- | +100 | MADD1 | MADDU1| --- | --- | --- | --- | --- | --- | +101 | *3 | *4 | --- | --- | --- | --- | --- | --- | +110 | PMFHL | PMTHL | --- | --- | PSLLH | --- | PSRLH | PSRAH | +111 | --- | --- | --- | --- | PSLLW | --- | PSRLW | PSRAW | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + + *1 = see MMI0 table *2 = see MMI2 Table + *3 = see MMI1 table *4 = see MMI3 Table +*/ +void (*MMIPrintTable[64])(char *buf) = { + P_MADD, P_MADDU, P_MMI_Unknown, P_MMI_Unknown, P_PLZCW, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MMI0, P_MMI2, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MFHI1, P_MTHI1, P_MFLO1, P_MTLO1, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MULT1, P_MULTU1, P_DIV1, P_DIVU1, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MADD1, P_MADDU1, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MMI1 , P_MMI3, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_PMFHL, P_PMTHL, P_MMI_Unknown, P_MMI_Unknown, P_PSLLH, P_MMI_Unknown, P_PSRLH, P_PSRAH, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_PSLLW, P_MMI_Unknown, P_PSRLW, P_PSRAW, +}; +/* + MMI0: Instr. encoded by function field when opcode field = MMI & MMI0 + + 31---------26------------------------------10--------6-5--------0 + | | |function | MMI0 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PADDW | PSUBW | PCGTW | PMAXW | +001 |PADDH | PSUBH | PCGTH | PMAXH | +010 |PADDB | PSUBB | PCGTB | --- | +011 | --- | --- | --- | --- | +100 |PADDSW |PSUBSW |PEXTLW | PPACW | +101 |PADDSH |PSUBSH |PEXTLH | PPACH | +110 |PADDSB |PSUBSB |PEXTLB | PPACB | +111 | --- | --- | PEXT5 | PPAC5 | + hi |-------|-------|-------|-------| +*/ +void (*MMI0PrintTable[32])(char *buf) = { + P_PADDW, P_PSUBW, P_PCGTW, P_PMAXW, + P_PADDH, P_PSUBH, P_PCGTH, P_PMAXH, + P_PADDB, P_PSUBB, P_PCGTB, P_MMI_Unknown, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_PADDSW, P_PSUBSW, P_PEXTLW, P_PPACW, + P_PADDSH, P_PSUBSH, P_PEXTLH, P_PPACH, + P_PADDSB, P_PSUBSB, P_PEXTLB, P_PPACB, + P_MMI_Unknown, P_MMI_Unknown, P_PEXT5, P_PPAC5, +}; +/* + MMI1: Instr. encoded by function field when opcode field = MMI & MMI1 + + 31---------26------------------------------------------5--------0 + | | |function | MMI1 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 | --- | PABSW | PCEQW | PMINW | +001 |PADSBH | PABSH | PCEQH | PMINH | +010 | --- | --- | PCEQB | --- | +011 | --- | --- | --- | --- | +100 |PADDUW |PSUBUW |PEXTUW | --- | +101 |PADDUH |PSUBUH |PEXTUH | --- | +110 |PADDUB |PSUBUB |PEXTUB | QFSRV | +111 | --- | --- | --- | --- | + hi |-------|-------|-------|-------| +*/ +void (*MMI1PrintTable[32])(char *buf) = { + P_MMI_Unknown, P_PABSW, P_PCEQW, P_PMINW, + P_PADSBH, P_PABSH, P_PCEQH, P_PMINH, + P_MMI_Unknown, P_MMI_Unknown, P_PCEQB, P_MMI_Unknown, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_PADDUW, P_PSUBUW, P_PEXTUW, P_MMI_Unknown, + P_PADDUH, P_PSUBUH, P_PEXTUH, P_MMI_Unknown, + P_PADDUB, P_PSUBUB, P_PEXTUB, P_QFSRV, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, +}; + +/* + MMI2: Instr. encoded by function field when opcode field = MMI & MMI2 + + 31---------26------------------------------------------5--------0 + | | |function | MMI2 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PMADDW | --- |PSLLVW |PSRLVW | +001 |PMSUBW | --- | --- | --- | +010 |PMFHI |PMFLO |PINTH | --- | +011 |PMULTW |PDIVW |PCPYLD | --- | +100 |PMADDH |PHMADH | PAND | PXOR | +101 |PMSUBH |PHMSBH | --- | --- | +110 | --- | --- | PEXEH | PREVH | +111 |PMULTH |PDIVBW | PEXEW |PROT3W | + hi |-------|-------|-------|-------| +*/ +void (*MMI2PrintTable[32])(char *buf) = { + P_PMADDW, P_MMI_Unknown, P_PSLLVW, P_PSRLVW, + P_PMSUBW, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_PMFHI, P_PMFLO, P_PINTH, P_MMI_Unknown, + P_PMULTW, P_PDIVW, P_PCPYLD, P_MMI_Unknown, + P_PMADDH, P_PHMADH, P_PAND, P_PXOR, + P_PMSUBH, P_PHMSBH, P_MMI_Unknown, P_MMI_Unknown, + P_MMI_Unknown, P_MMI_Unknown, P_PEXEH, P_PREVH, + P_PMULTH, P_PDIVBW, P_PEXEW, P_PROT3W, +}; +/* + MMI3: Instr. encoded by function field when opcode field = MMI & MMI3 + 31---------26------------------------------------------5--------0 + | | |function | MMI3 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PMADDUW| --- | --- |PSRAVW | +001 | --- | --- | --- | --- | +010 |PMTHI | PMTLO |PINTEH | --- | +011 |PMULTUW| PDIVUW|PCPYUD | --- | +100 | --- | --- | POR | PNOR | +101 | --- | --- | --- | --- | +110 | --- | --- | PEXCH | PCPYH | +111 | --- | --- | PEXCW | --- | + hi |-------|-------|-------|-------| + */ +void (*MMI3PrintTable[32])(char *buf) = { + P_PMADDUW, P_MMI_Unknown, P_MMI_Unknown, P_PSRAVW, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_PMTHI, P_PMTLO, P_PINTEH, P_MMI_Unknown, + P_PMULTUW, P_PDIVUW, P_PCPYUD, P_MMI_Unknown, + P_MMI_Unknown, P_MMI_Unknown, P_POR, P_PNOR, + P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, P_MMI_Unknown, + P_MMI_Unknown, P_MMI_Unknown, P_PEXCH, P_PCPYH, + P_MMI_Unknown, P_MMI_Unknown, P_PEXCW, P_MMI_Unknown, +}; +/* + COP0: Instructions encoded by the rs field when opcode = COP0. + 31--------26-25------21 ----------------------------------------0 + | = COP0 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | MFC0 | --- | --- | --- | MTC0 | --- | --- | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1=BC See BC0 list *2 = TLB instr, see TLB list +*/ +void (*COP0PrintTable[32])(char *buf) = { + P_MFC0, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_MTC0, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_BC0, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Func, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, +}; +/* + BC0: Instructions encoded by the rt field when opcode = COP0 & rs field=BC0 + 31--------26-25------21 ----------------------------------------0 + | = COP0 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC0F | BC0T | BC0FL | BC0TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP0BC0PrintTable[32])(char *buf) = { + P_BC0F, P_BC0T, P_BC0FL, P_BC0TL, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, +}; +/* + C0=Instructions encode by function field when Opcode field=COP0 & rs field=C0 + 31---------26------------------------------------------5--------0 + | | | | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | --- | TLBR | TLBWI | --- | --- | --- | TLBWR | --- | +001 | TLBP | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- | --- | --- | +011 | ERET | --- | --- | --- | --- | --- | --- | --- | +100 | --- | --- | --- | --- | --- | --- | --- | --- | +101 | --- | --- | --- | --- | --- | --- | --- | --- | +110 | --- | --- | --- | --- | --- | --- | --- | --- | +111 | EI | DI | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP0C0PrintTable[64])(char *buf) = { + P_COP0_Unknown, P_TLBR, P_TLBWI, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_TLBWR, P_COP0_Unknown, + P_TLBP, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_ERET, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, + P_EI, P_DI, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown +}; +/* + COP1: Instructions encoded by the fmt field when opcode = COP1. + 31--------26-25------21 ----------------------------------------0 + | = COP1 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | MFC1 | --- | CFC1 | --- | MTC1 | --- | CTC1 | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | --- | --- | --- | *3 | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = BC instructions, see BC1 list *2 = S instr, see FPU list + *3 = W instr, see FPU list +*/ +void (*COP1PrintTable[32])(char *buf) = { + P_MFC1, P_COP1_Unknown, P_CFC1, P_COP1_Unknown, P_MTC1, P_COP1_Unknown, P_CTC1, P_COP1_Unknown, + P_COP1_BC1, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, + P_COP1_S, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_W, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, + P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, +}; +/* + BC1: Instructions encoded by the rt field when opcode = COP1 & rs field=BC1 + 31--------26-25------21 ----------------------------------------0 + | = COP1 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC1F | BC1T | BC1FL | BC1TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP1BC1PrintTable[32])(char *buf) = { + P_BC1F, P_BC1T, P_BC1FL, P_BC1TL, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, + P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, + P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, + P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, +}; +/* + FPU: Instructions encoded by the function field when opcode = COP1 + and rs = S + 31--------26-25------21 -------------------------------5--------0 + | = COP1 | = S | | function| + ------6----------5-----------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | ADD.S | SUB.S | MUL.S | DIV.S | SQRT.S| ABS.S | MOV.S | NEG.S | +001 | --- | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- |RSQRT.S| --- | +011 | ADDA.S| SUBA.S| MULA.S| --- | MADD.S| MSUB.S|MADDA.S|MSUBA.S| +100 | --- | --- | --- | --- | CVT.W | --- | --- | --- | +101 | MAX.S | MIN.S | --- | --- | --- | --- | --- | --- | +110 | C.F | --- | C.EQ | --- | C.LT | --- | C.LE | --- | +111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP1SPrintTable[64])(char *buf) = { +P_ADD_S, P_SUB_S, P_MUL_S, P_DIV_S, P_SQRT_S, P_ABS_S, P_MOV_S, P_NEG_S, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_RSQRT_S, P_COP1_Unknown, +P_ADDA_S, P_SUBA_S, P_MULA_S, P_COP1_Unknown,P_MADD_S, P_MSUB_S, P_MADDA_S, P_MSUBA_S, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_CVT_W, P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_MAX_S, P_MIN_S, P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_C_F, P_COP1_Unknown,P_C_EQ, P_COP1_Unknown,P_C_LT, P_COP1_Unknown,P_C_LE, P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +}; +/* + FPU: Instructions encoded by the function field when opcode = COP1 + and rs = W + 31--------26-25------21 -------------------------------5--------0 + | = COP1 | = W | | function| + ------6----------5-----------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | --- | --- | --- | --- | --- | --- | --- | --- | +001 | --- | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- | --- | --- | +011 | --- | --- | --- | --- | --- | --- | --- | --- | +100 | CVT.S | --- | --- | --- | --- | --- | --- | --- | +101 | --- | --- | --- | --- | --- | --- | --- | --- | +110 | --- | --- | --- | --- | --- | --- | --- | --- | +111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP1WPrintTable[64])(char *buf) = { +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_CVT_S, P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown,P_COP1_Unknown, +}; + +//************************************************************* +//COP2 TABLES :) +//************************************************************* +/* + COP2: Instructions encoded by the fmt field when opcode = COP2. + 31--------26-25------21 ----------------------------------------0 + | = COP2 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | --- | QMFC2 | CFC2 | --- | --- | QMTC2 | CTC2 | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | + 11 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = BC instructions, see BC2 list *2 =see special1 table +*/ +void (*COP2PrintTable[32])(char *buf) = { + P_COP2_Unknown, P_QMFC2, P_CFC2, P_COP2_Unknown, P_COP2_Unknown, P_QMTC2, P_CTC2, P_COP2_Unknown, + P_COP2_BC2, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, + P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, + + +}; +/* + BC2: Instructions encoded by the rt field when opcode = COP2 & rs field=BC1 + 31--------26-25------21 ----------------------------------------0 + | = COP2 | rs=BC2| | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC2F | BC2T | BC2FL | BC2TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + */ +void (*COP2BC2PrintTable[32])(char *buf) = { + P_BC2F, P_BC2T, P_BC2FL, P_BC2TL, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, +}; +/* + Special1 table : instructions encode by function field when opcode=COP2 & rs field=Special1 + 31---------26---------------------------------------------------0 + | =COP2 | rs=Special | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 |VADDx |VADDy |VADDz |VADDw |VSUBx |VSUBy |VSUBz |VSUBw | +001 |VMADDx |VMADDy |VMADDz |VMADDw |VMSUBx |VMSUBy |VMSUBz |VMSUBw | +010 |VMAXx |VMAXy |VMAXz |VMAXw |VMINIx |VMINIy |VMINIz |VMINIw | +011 |VMULx |VMULy |VMULz |VMULw |VMULq |VMAXi |VMULi |VMINIi | +100 |VADDq |VMADDq |VADDi |VMADDi |VSUBq |VMSUBq |VSUbi |VMSUBi | +101 |VADD |VMADD |VMUL |VMAX |VSUB |VMSUB |VOPMSUB|VMINI | +110 |VIADD |VISUB |VIADDI | --- |VIAND |VIOR | --- | --- | +111 |VCALLMS|CALLMSR| --- | --- | *1 | *1 | *1 | *1 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1=see special2 table +*/ +void (*COP2SPECIAL1PrintTable[64])(char *buf) = +{ + P_VADDx, P_VADDy, P_VADDz, P_VADDw, P_VSUBx, P_VSUBy, P_VSUBz, P_VSUBw, + P_VMADDx, P_VMADDy, P_VMADDz, P_VMADDw, P_VMSUBx, P_VMSUBy, P_VMSUBz, P_VMSUBw, + P_VMAXx, P_VMAXy, P_VMAXz, P_VMAXw, P_VMINIx, P_VMINIy, P_VMINIz, P_VMINIw, + P_VMULx, P_VMULy, P_VMULz, P_VMULw, P_VMULq, P_VMAXi, P_VMULi, P_VMINIi, + P_VADDq, P_VMADDq, P_VADDi, P_VMADDi, P_VSUBq, P_VMSUBq, P_VSUbi, P_VMSUBi, + P_VADD, P_VMADD, P_VMUL, P_VMAX, P_VSUB, P_VMSUB, P_VOPMSUB, P_VMINI, + P_VIADD, P_VISUB, P_VIADDI, P_COP2_Unknown,P_VIAND, P_VIOR, P_COP2_Unknown, P_COP2_Unknown, + P_VCALLMS, P_CALLMSR, P_COP2_Unknown,P_COP2_Unknown,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2, + +}; +/* + Special2 table : instructions encode by function field when opcode=COp2 & rs field=Special2 + + 31---------26---------------------------------------------------0 + | =COP2 | rs=Special2 | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +0000 |VADDAx |VADDAy |VADDAz |VADDAw |VSUBAx |VSUBAy |VSUBAz |VSUBAw | +0001 |VMADDAx|VMADDAy|VMADDAz|VMADDAw|VMSUBAx|VMSUBAy|VMSUBAz|VMSUBAw| +0010 |VITOF0 |VITOF4 |VITOF12|VITOF15|VFTOI0 |VFTOI4 |VFTOI12|VFTOI15| +0011 |VMULAx |VMULAy |VMULAz |VMULAw |VMULAq |VABS |VMULAi |VCLIPw | +0100 |VADDAq |VMADDAq|VADDAi |VMADDAi|VSUBAq |VMSUBAq|VSUBAi |VMSUBAi| +0101 |VADDA |VMADDA |VMULA | --- |VSUBA |VMSUBA |VOPMULA|VNOP | +0110 |VMONE |VMR32 | --- | --- |VLQI |VSQI |VLQD |VSQD | +0111 |VDIV |VSQRT |VRSQRT |VWAITQ |VMTIR |VMFIR |VILWR |VISWR | +1000 |VRNEXT |VRGET |VRINIT |VRXOR | --- | --- | --- | --- | +1001 | --- | --- | --- | --- | --- | --- | --- | --- | +1010 | --- | --- | --- | --- | --- | --- | --- | --- | +1011 | --- | --- | --- | --- | --- | --- | --- | --- | +1100 | --- | --- | --- | --- | --- | --- | --- | --- | +1101 | --- | --- | --- | --- | --- | --- | --- | --- | +1110 | --- | --- | --- | --- | --- | --- | --- | --- | +1111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP2SPECIAL2PrintTable[128])(char *buf) = +{ + P_VADDAx ,P_VADDAy ,P_VADDAz ,P_VADDAw ,P_VSUBAx ,P_VSUBAy ,P_VSUBAz ,P_VSUBAw, + P_VMADDAx ,P_VMADDAy ,P_VMADDAz ,P_VMADDAw ,P_VMSUBAx ,P_VMSUBAy ,P_VMSUBAz ,P_VMSUBAw, + P_VITOF0 ,P_VITOF4 ,P_VITOF12 ,P_VITOF15 ,P_VFTOI0 ,P_VFTOI4 ,P_VFTOI12 ,P_VFTOI15, + P_VMULAx ,P_VMULAy ,P_VMULAz ,P_VMULAw ,P_VMULAq ,P_VABS ,P_VMULAi ,P_VCLIPw, + P_VADDAq ,P_VMADDAq ,P_VADDAi ,P_VMADDAi ,P_VSUBAq ,P_VMSUBAq ,P_VSUBAi ,P_VMSUBAi, + P_VADDA ,P_VMADDA ,P_VMULA ,P_COP2_Unknown,P_VSUBA ,P_VMSUBA ,P_VOPMULA ,P_VNOP, + P_VMONE ,P_VMR32 ,P_COP2_Unknown,P_COP2_Unknown,P_VLQI ,P_VSQI ,P_VLQD ,P_VSQD, + P_VDIV ,P_VSQRT ,P_VRSQRT ,P_VWAITQ ,P_VMTIR ,P_VMFIR ,P_VILWR ,P_VISWR, + P_VRNEXT ,P_VRGET ,P_VRINIT ,P_VRXOR ,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, +}; + +//**************************TABLES CALLS*********************** + +static char dbuf[1024]; +static char obuf[1024]; + +char *disR5900Fasm(u32 code, u32 pc) { + u32 scode = cpuRegs.code; + opcode_addr = pc; + cpuRegs.code = code; + OpcodePrintTable[(code) >> 26](dbuf); + + sprintf(obuf, "%08X:\t%s", pc, dbuf); + + cpuRegs.code = scode; + return obuf; +} + +void P_SpecialOpcode(char *buf) +{ + SpecialPrintTable[DECODE_FUNCTION](buf); +} +void P_REGIMMOpcode(char *buf) +{ + REGIMMPrintTable[DECODE_RT](buf); +} + +//***********COP0 TABLE CALLS******************************** + +void P_COP0(char *buf) +{ + COP0PrintTable[DECODE_RS](buf); +} +void P_COP0_BC0(char *buf) +{ + + COP0BC0PrintTable[DECODE_C0BC](buf); +} +void P_COP0_Func(char *buf) +{ + + COP0C0PrintTable[DECODE_FUNCTION](buf); +} + +//*****************MMI TABLES CALLS************************** +void P_MMI(char *buf) +{ + + MMIPrintTable[DECODE_FUNCTION](buf); +} +void P_MMI0(char *buf) +{ + MMI0PrintTable[DECODE_SA](buf); +} +void P_MMI1(char *buf) +{ + MMI1PrintTable[DECODE_SA](buf); +} +void P_MMI2(char *buf) +{ + MMI2PrintTable[DECODE_SA](buf); +} +void P_MMI3(char *buf) +{ + MMI3PrintTable[DECODE_SA](buf); +} +//****************END OF MMI TABLES CALLS********************** +//COP1 TABLECALLS******************************************* +void P_COP1(char *buf) +{ + + COP1PrintTable[DECODE_RS](buf); +} +void P_COP1_BC1(char *buf) +{ + COP1BC1PrintTable[DECODE_C1BC](buf); +} +void P_COP1_S(char *buf) +{ + COP1SPrintTable[DECODE_FUNCTION](buf); +} +void P_COP1_W(char *buf) +{ + COP1WPrintTable[DECODE_FUNCTION](buf); +} +//**********************END OF COP1 TABLE CALLS + +//************************************************************* +//************************COP2********************************** +void P_COP2(char *buf) +{ + + COP2PrintTable[DECODE_RS](buf); +} +void P_COP2_BC2(char *buf) +{ + COP2BC2PrintTable[DECODE_C2BC](buf); +} +void P_COP2_SPECIAL(char *buf) +{ + COP2SPECIAL1PrintTable[DECODE_FUNCTION ](buf); + +} +void P_COP2_SPECIAL2(char *buf) +{ + + COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)](buf); + +} + +//**************************UNKNOWN**************************** +void P_UnknownOpcode(char *buf) +{ + strcpy(buf, "?????"); +} +void P_COP0_Unknown(char *buf) +{ + strcpy(buf, "COP0 ??"); +} +void P_COP1_Unknown(char *buf) +{ + strcpy(buf, "COP1 ??"); +} +void P_COP2_Unknown(char *buf) +{ + strcpy(buf,"COP2 ??"); +} + +void P_MMI_Unknown(char *buf) +{ + strcpy(buf,"MMI ??"); +} + + + +//************************************************************* + +//*****************SOME DECODE STUFF*************************** +#define dFindSym(i) { \ + char *str = disR5900GetSym(i); \ + if (str != NULL) sprintf(buf, "%s %s", buf, str); \ +} + +char *jump_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = DECODE_JUMP; + sprintf(buf, "0x%08X", addr); + + dFindSym(addr); + return buf; +} + +char *offset_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = DECODE_OFFSET; + sprintf(buf, "0x%08X", addr); + dFindSym(addr); + return buf; +} + +//*********************END OF DECODE ROUTINES****************** + +//********************* Standard Opcodes*********************** +void P_J(char *buf) { sprintf(buf, "j\t%s", jump_decode());} +void P_JAL(char *buf) { sprintf(buf, "jal\t%s", jump_decode());} +void P_BEQ(char *buf) { sprintf(buf, "beq\t%s, %s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT], offset_decode()); } +void P_BNE(char *buf) { sprintf(buf, "bne\t%s, %s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT], offset_decode()); } +void P_BLEZ(char *buf) { sprintf(buf, "blez\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGTZ(char *buf) { sprintf(buf, "bgtz\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_ADDI(char *buf) { sprintf(buf, "addi\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void P_ADDIU(char *buf) { sprintf(buf, "addiu\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void P_SLTI(char *buf) { sprintf(buf, "slti\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_SLTIU(char *buf) { sprintf(buf, "sltiu\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_ANDI(char *buf) { sprintf(buf, "andi\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void P_ORI(char *buf) { sprintf(buf, "ori\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_XORI(char *buf) { sprintf(buf, "xori\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_LUI(char *buf) { sprintf(buf, "lui\t%s, 0x%04X", GPR_REG[DECODE_RT], DECODE_IMMED); } +void P_BEQL(char *buf) { sprintf(buf, "beql\t%s, %s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT], offset_decode()); } +void P_BNEL(char *buf) { sprintf(buf, "bnel\t%s, %s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT], offset_decode()); } +void P_BLEZL(char *buf) { sprintf(buf, "blezl\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGTZL(char *buf) { sprintf(buf, "bgtzl\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_DADDI(char *buf) { sprintf(buf, "daddi\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_DADDIU(char *buf) { sprintf(buf, "daddiu\t%s, %s, 0x%04X", GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_LDL(char *buf) { sprintf(buf, "ldl\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LDR(char *buf) { sprintf(buf, "ldr\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LB(char *buf) { sprintf(buf, "lb\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LH(char *buf) { sprintf(buf, "lh\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LWL(char *buf) { sprintf(buf, "lwl\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LW(char *buf) { sprintf(buf, "lw\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LBU(char *buf) { sprintf(buf, "lbu\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LHU(char *buf) { sprintf(buf, "lhu\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LWR(char *buf) { sprintf(buf, "lwr\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LWU(char *buf) { sprintf(buf, "lwu\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SB(char *buf) { sprintf(buf, "sb\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SH(char *buf) { sprintf(buf, "sh\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SWL(char *buf) { sprintf(buf, "swl\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SW(char *buf) { sprintf(buf, "sw\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SDL(char *buf) { sprintf(buf, "sdl\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SDR(char *buf) { sprintf(buf, "sdr\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SWR(char *buf) { sprintf(buf, "swr\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LD(char *buf) { sprintf(buf, "ld\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SD(char *buf) { sprintf(buf, "sd\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LQ(char *buf) { sprintf(buf, "lq\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SQ(char *buf) { sprintf(buf, "sq\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SWC1(char *buf) { sprintf(buf, "swc1\t%s, 0x%04X(%s)", COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_SQC2(char *buf) { sprintf(buf, "sqc2\t%s, 0x%04X(%s)", COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_PREF(char *buf) { strcpy(buf, "pref ---");/*sprintf(buf, "PREF\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[RS]); */} +void P_LWC1(char *buf) { sprintf(buf, "lwc1\t%s, 0x%04X(%s)", COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void P_LQC2(char *buf) { sprintf(buf, "lqc2\t%s, 0x%04X(%s)", COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +//********************END OF STANDARD OPCODES************************* + +void P_SLL(char *buf) +{ + if (cpuRegs.code == 0x00000000) + strcpy(buf, "nop"); + else + sprintf(buf, "sll\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); +} + +void P_SRL(char *buf) { sprintf(buf, "srl\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_SRA(char *buf) { sprintf(buf, "sra\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_SLLV(char *buf) { sprintf(buf, "sllv\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_SRLV(char *buf) { sprintf(buf, "srlv\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]);} +void P_SRAV(char *buf) { sprintf(buf, "srav\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_JR(char *buf) { sprintf(buf, "jr\t%s", GPR_REG[DECODE_RS]); } + +void P_JALR(char *buf) +{ + int rd = DECODE_RD; + + if (rd == 31) + sprintf(buf, "jalr\t%s", GPR_REG[DECODE_RS]); + else + sprintf(buf, "jalr\t%s, %s", GPR_REG[rd], GPR_REG[DECODE_RS]); +} + + +void P_SYNC(char *buf) { sprintf(buf, "SYNC");} +void P_MFHI(char *buf) { sprintf(buf, "mfhi\t%s", GPR_REG[DECODE_RD]); } +void P_MTHI(char *buf) { sprintf(buf, "mthi\t%s", GPR_REG[DECODE_RS]); } +void P_MFLO(char *buf) { sprintf(buf, "mflo\t%s", GPR_REG[DECODE_RD]); } +void P_MTLO(char *buf) { sprintf(buf, "mtlo\t%s", GPR_REG[DECODE_RS]); } +void P_DSLLV(char *buf) { sprintf(buf, "dsllv\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_DSRLV(char *buf) { sprintf(buf, "dsrlv\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_DSRAV(char *buf) { sprintf(buf, "dsrav\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_MULT(char *buf) { sprintf(buf, "mult\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void P_MULTU(char *buf) { sprintf(buf, "multu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void P_DIV(char *buf) { sprintf(buf, "div\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DIVU(char *buf) { sprintf(buf, "divu\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_ADD(char *buf) { sprintf(buf, "add\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_ADDU(char *buf) { sprintf(buf, "addu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_SUB(char *buf) { sprintf(buf, "sub\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_SUBU(char *buf) { sprintf(buf, "subu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_AND(char *buf) { sprintf(buf, "and\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_OR(char *buf) { sprintf(buf, "or\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_XOR(char *buf) { sprintf(buf, "xor\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_NOR(char *buf) { sprintf(buf, "nor\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_SLT(char *buf) { sprintf(buf, "slt\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_SLTU(char *buf) { sprintf(buf, "sltu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DADD(char *buf) { sprintf(buf, "dadd\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DADDU(char *buf) { sprintf(buf, "daddu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DSUB(char *buf) { sprintf(buf, "dsub\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DSUBU(char *buf) { sprintf(buf, "dsubu\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TGE(char *buf) { sprintf(buf, "tge\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TGEU(char *buf) { sprintf(buf, "tgeu\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TLT(char *buf) { sprintf(buf, "tlt\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TLTU(char *buf) { sprintf(buf, "tltu\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TEQ(char *buf) { sprintf(buf, "teq\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_TNE(char *buf) { sprintf(buf, "tne\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DSLL(char *buf) { sprintf(buf, "dsll\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_DSRL(char *buf) { sprintf(buf, "dsrl\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_DSRA(char *buf) { sprintf(buf, "dsra\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_DSLL32(char *buf) { sprintf(buf, "dsll32\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_DSRL32(char *buf) { sprintf(buf, "dsrl32\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_DSRA32(char *buf) { sprintf(buf, "dsra32\t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_MOVZ(char *buf) { sprintf(buf, "movz\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MOVN(char *buf) { sprintf(buf, "movn\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MFSA(char *buf) { sprintf(buf, "mfsa\t%s", GPR_REG[DECODE_RD]);} +void P_MTSA(char *buf) { sprintf(buf, "mtsa\t%s", GPR_REG[DECODE_RS]);} +//*** unsupport (yet) cpu opcodes +void P_SYSCALL(char *buf) { strcpy(buf, "syscall ---");/*sprintf(buf, "syscall\t0x%05X", DECODE_SYSCALL);*/} +void P_BREAK(char *buf) { strcpy(buf, "break ---");/*sprintf(buf, "break\t0x%05X", DECODE_BREAK); */} +void P_CACHE(char *buf) { strcpy(buf, "cache ---");/*sprintf(buf, "cache\t%s, 0x%04X(%s)", GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); */} +//************************REGIMM OPCODES*************************** +void P_BLTZ(char *buf) { sprintf(buf, "bltz\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGEZ(char *buf) { sprintf(buf, "bgez\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BLTZL(char *buf) { sprintf(buf, "bltzl\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGEZL(char *buf) { sprintf(buf, "bgezl\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_TGEI(char *buf) { sprintf(buf, "tgei\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_TGEIU(char *buf) { sprintf(buf, "tgeiu\t%s,0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_TLTI(char *buf) { sprintf(buf, "tlti\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_TLTIU(char *buf) { sprintf(buf, "tltiu\t%s,0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_TEQI(char *buf) { sprintf(buf, "teqi\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_TNEI(char *buf) { sprintf(buf, "tnei\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED); } +void P_BLTZAL(char *buf) { sprintf(buf, "bltzal\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGEZAL(char *buf) { sprintf(buf, "bgezal\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BLTZALL(char *buf) { sprintf(buf, "bltzall\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_BGEZALL(char *buf) { sprintf(buf, "bgezall\t%s, %s", GPR_REG[DECODE_RS], offset_decode()); } +void P_MTSAB(char *buf) { sprintf(buf, "mtsab\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED);} +void P_MTSAH(char *buf) { sprintf(buf, "mtsah\t%s, 0x%04X", GPR_REG[DECODE_RS], DECODE_IMMED);} + + +//***************************SPECIAL 2 CPU OPCODES******************* +const char* pmfhl_sub[] = { "lw", "uw", "slw", "lh", "sh" }; + +void P_MADD(char *buf) { sprintf(buf, "madd\t%s, %s %s", GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MADDU(char *buf) { sprintf(buf, "maddu\t%s, %s %s", GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void P_PLZCW(char *buf) { sprintf(buf, "plzcw\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS]); } +void P_MADD1(char *buf) { sprintf(buf, "madd1\t%s, %s %s", GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MADDU1(char *buf) { sprintf(buf, "maddu1\t%s, %s %s", GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MFHI1(char *buf) { sprintf(buf, "mfhi1\t%s", GPR_REG[DECODE_RD]); } +void P_MTHI1(char *buf) { sprintf(buf, "mthi1\t%s", GPR_REG[DECODE_RS]); } +void P_MFLO1(char *buf) { sprintf(buf, "mflo1\t%s", GPR_REG[DECODE_RD]); } +void P_MTLO1(char *buf) { sprintf(buf, "mtlo1\t%s", GPR_REG[DECODE_RS]); } +void P_MULT1(char *buf) { sprintf(buf, "mult1\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_MULTU1(char *buf) { sprintf(buf, "multu1\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void P_DIV1(char *buf) { sprintf(buf, "div1\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_DIVU1(char *buf) { sprintf(buf, "divu1\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +//that have parametres that i haven't figure out how to display... +void P_PMFHL(char *buf) { sprintf(buf, "pmfhl.%s \t%s", pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RD]); } +void P_PMTHL(char *buf) { sprintf(buf, "pmthl.%s \t%s", pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RS]); } +void P_PSLLH(char *buf) { sprintf(buf, "psllh \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void P_PSRLH(char *buf) { sprintf(buf, "psrlh \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void P_PSRAH(char *buf) { sprintf(buf, "psrah \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void P_PSLLW(char *buf) { sprintf(buf, "psllw \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void P_PSRLW(char *buf) { sprintf(buf, "psrlw \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void P_PSRAW(char *buf) { sprintf(buf, "psraw \t%s, %s, 0x%02X", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +//***************************END OF SPECIAL OPCODES****************** +//*************************MMI0 OPCODES************************ + +void P_PADDW(char *buf){ sprintf(buf, "paddw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBW(char *buf){ sprintf(buf, "psubw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCGTW(char *buf){ sprintf(buf, "pcgtw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMAXW(char *buf){ sprintf(buf, "pmaxw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDH(char *buf){ sprintf(buf, "paddh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBH(char *buf){ sprintf(buf, "psubh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCGTH(char *buf){ sprintf(buf, "pcgth\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMAXH(char *buf){ sprintf(buf, "pmaxh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDB(char *buf){ sprintf(buf, "paddb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBB(char *buf){ sprintf(buf, "psubb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCGTB(char *buf){ sprintf(buf, "pcgtb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDSW(char *buf){ sprintf(buf, "paddsw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBSW(char *buf){ sprintf(buf, "psubsw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTLW(char *buf){ sprintf(buf, "pextlw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PPACW(char *buf) { sprintf(buf, "ppacw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDSH(char *buf){ sprintf(buf, "paddsh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBSH(char *buf){ sprintf(buf, "psubsh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTLH(char *buf){ sprintf(buf, "pextlh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PPACH(char *buf) { sprintf(buf, "ppach\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDSB(char *buf){ sprintf(buf, "paddsb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBSB(char *buf){ sprintf(buf, "psubsb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTLB(char *buf){ sprintf(buf, "pextlb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PPACB(char *buf) { sprintf(buf, "ppacb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXT5(char *buf) { sprintf(buf, "pext5\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PPAC5(char *buf) { sprintf(buf, "ppac5\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +//**********END OF MMI0 OPCODES********************************* +//**********MMI1 OPCODES************************************** +void P_PABSW(char *buf){ sprintf(buf, "pabsw%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PCEQW(char *buf){ sprintf(buf, "pceqw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMINW(char *buf){ sprintf(buf, "pminw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADSBH(char *buf){ sprintf(buf, "padsbh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PABSH(char *buf){ sprintf(buf, "pabsh%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PCEQH(char *buf){ sprintf(buf, "pceqh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMINH(char *buf){ sprintf(buf, "pminh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCEQB(char *buf){ sprintf(buf, "pceqb\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDUW(char *buf){ sprintf(buf, "padduw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBUW(char *buf){ sprintf(buf, "psubuw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTUW(char *buf){ sprintf(buf, "pextuw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDUH(char *buf){ sprintf(buf, "padduh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBUH(char *buf){ sprintf(buf, "psubuh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTUH(char *buf){ sprintf(buf, "pextuh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PADDUB(char *buf){ sprintf(buf, "paddub\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSUBUB(char *buf){ sprintf(buf, "psubub\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXTUB(char *buf){ sprintf(buf, "pextub\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_QFSRV(char *buf) { sprintf(buf, "qfsrv\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +//********END OF MMI1 OPCODES*********************************** +//*********MMI2 OPCODES*************************************** +void P_PMADDW(char *buf){ sprintf(buf, "pmaddw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSLLVW(char *buf){ sprintf(buf, "psllvw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PSRLVW(char *buf){ sprintf(buf, "psrlvw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMSUBW(char *buf){ sprintf(buf, "msubw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMFHI(char *buf){ sprintf(buf, "pmfhi\t%s", GPR_REG[DECODE_RD]); } +void P_PMFLO(char *buf){ sprintf(buf, "pmflo\t%s", GPR_REG[DECODE_RD]); } +void P_PINTH(char *buf){ sprintf(buf, "pinth\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMULTW(char *buf){ sprintf(buf, "pmultw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PDIVW(char *buf){ sprintf(buf, "pdivw\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCPYLD(char *buf){ sprintf(buf, "pcpyld\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMADDH(char *buf){ sprintf(buf, "pmaddh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PHMADH(char *buf){ sprintf(buf, "phmadh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PAND(char *buf){ sprintf(buf, "pand\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PXOR(char *buf){ sprintf(buf, "pxor\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMSUBH(char *buf){ sprintf(buf, "pmsubh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PHMSBH(char *buf){ sprintf(buf, "phmsbh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXEH(char *buf){ sprintf(buf, "pexeh\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PREVH(char *buf){ sprintf(buf, "prevh\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PMULTH(char *buf){ sprintf(buf, "pmulth\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PDIVBW(char *buf){ sprintf(buf, "pdivbw\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXEW(char *buf){ sprintf(buf, "pexew\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void P_PROT3W(char *buf){ sprintf(buf, "prot3w\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +//*****END OF MMI2 OPCODES*********************************** +//*************************MMI3 OPCODES************************ +void P_PMADDUW(char *buf){ sprintf(buf, "pmadduw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_PSRAVW(char *buf){ sprintf(buf, "psravw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void P_PMTHI(char *buf){ sprintf(buf, "pmthi\t%s", GPR_REG[DECODE_RS]); } +void P_PMTLO(char *buf){ sprintf(buf, "pmtlo\t%s", GPR_REG[DECODE_RS]); } +void P_PINTEH(char *buf){ sprintf(buf, "pinteh\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PMULTUW(char *buf){ sprintf(buf, "pmultuw\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PDIVUW(char *buf){ sprintf(buf, "pdivuw\t%s, %s", GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PCPYUD(char *buf){ sprintf(buf, "pcpyud\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_POR(char *buf){ sprintf(buf, "por\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PNOR(char *buf){ sprintf(buf, "pnor\t%s, %s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void P_PEXCH(char *buf){ sprintf(buf, "pexch\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +void P_PCPYH(char *buf){ sprintf(buf, "pcpyh\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +void P_PEXCW(char *buf){ sprintf(buf, "pexcw\t%s, %s", GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +//**********************END OF MMI3 OPCODES******************** +//**************************************************************************** +//** COP0 ** +//**************************************************************************** +void P_MFC0(char *buf){ sprintf(buf, "mfc0\t%s, %s", GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } +void P_MTC0(char *buf){ sprintf(buf, "mtc0\t%s, %s", GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } +void P_BC0F(char *buf){ sprintf(buf, "bc0f\t%s", offset_decode()); } +void P_BC0T(char *buf){ sprintf(buf, "bc0t\t%s", offset_decode()); } +void P_BC0FL(char *buf){ sprintf(buf, "bc0fl\t%s", offset_decode()); } +void P_BC0TL(char *buf){ sprintf(buf, "bc0tl\t%s", offset_decode()); } +void P_TLBR(char *buf){ strcpy(buf,"tlbr");} +void P_TLBWI(char *buf){ strcpy(buf,"tlbwi");} +void P_TLBWR(char *buf){ strcpy(buf,"tlbwr");} +void P_TLBP(char *buf){ strcpy(buf,"tlbp");} +void P_ERET(char *buf){ strcpy(buf,"eret");} +void P_DI(char *buf){ strcpy(buf,"di");} +void P_EI(char *buf){ strcpy(buf,"ei");} +//**************************************************************************** +//** END OF COP0 ** +//**************************************************************************** +//**************************************************************************** +//** COP1 - Floating Point Unit (FPU) ** +//**************************************************************************** +void P_MFC1(char *buf){ sprintf(buf, "mfc1\t%s, %s", GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } +void P_CFC1(char *buf){ sprintf(buf, "cfc1\t%s, %s", GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } +void P_MTC1(char *buf){ sprintf(buf, "mtc1\t%s, %s", GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } +void P_CTC1(char *buf){ sprintf(buf, "ctc1\t%s, %s", GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } +void P_BC1F(char *buf){ sprintf(buf, "bc1f\t%s", offset_decode()); } +void P_BC1T(char *buf){ sprintf(buf, "bc1t\t%s", offset_decode()); } +void P_BC1FL(char *buf){ sprintf(buf, "bc1fl\t%s", offset_decode()); } +void P_BC1TL(char *buf){ sprintf(buf, "bc1tl\t%s", offset_decode()); } +void P_ADD_S(char *buf){ sprintf(buf, "add.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_SUB_S(char *buf){ sprintf(buf, "sub.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_MUL_S(char *buf){ sprintf(buf, "mul.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_DIV_S(char *buf){ sprintf(buf, "div.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_SQRT_S(char *buf){ sprintf(buf, "sqrt.s\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FT]); } +void P_ABS_S(char *buf){ sprintf(buf, "abs.s\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void P_MOV_S(char *buf){ sprintf(buf, "mov.s\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void P_NEG_S(char *buf){ sprintf(buf, "neg.s\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]);} +void P_RSQRT_S(char *buf){sprintf(buf, "rsqrt.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_ADDA_S(char *buf){ sprintf(buf, "adda.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_SUBA_S(char *buf){ sprintf(buf, "suba.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_MULA_S(char *buf){ sprintf(buf, "mula.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_MADD_S(char *buf){ sprintf(buf, "madd.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_MSUB_S(char *buf){ sprintf(buf, "msub.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_MADDA_S(char *buf){sprintf(buf, "madda.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_MSUBA_S(char *buf){sprintf(buf, "msuba.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_CVT_W(char *buf){ sprintf(buf, "cvt.w.s\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void P_MAX_S(char *buf){ sprintf(buf, "max.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_MIN_S(char *buf){ sprintf(buf, "min.s\t%s, %s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void P_C_F(char *buf){ sprintf(buf, "c.f.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_C_EQ(char *buf){ sprintf(buf, "c.eq.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_C_LT(char *buf){ sprintf(buf, "c.lt.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_C_LE(char *buf){ sprintf(buf, "c.le.s\t%s, %s", COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void P_CVT_S(char *buf){ sprintf(buf, "cvt.s.w\t%s, %s", COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +//**************************************************************************** +//** END OF COP1 ** +//**************************************************************************** +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void P_QMFC2(char *buf){ sprintf(buf, "qmfc2\t%s, %s", GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } +void P_CFC2(char *buf){ sprintf(buf, "cfc2\t%s, %s", GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } +void P_QMTC2(char *buf){ sprintf(buf, "qmtc2\t%s, %s", GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } +void P_CTC2(char *buf){ sprintf(buf, "ctc2\t%s, %s", GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } +void P_BC2F(char *buf){ sprintf(buf, "bc2f\t%s", offset_decode()); } +void P_BC2T(char *buf){ sprintf(buf, "bc2t\t%s", offset_decode()); } +void P_BC2FL(char *buf){ sprintf(buf, "bc2fl\t%s", offset_decode()); } +void P_BC2TL(char *buf){ sprintf(buf, "bc2tl\t%s", offset_decode()); } +//******************************SPECIAL 1 VUO TABLE**************************************** +#define _X ((cpuRegs.code>>24) & 1) +#define _Y ((cpuRegs.code>>23) & 1) +#define _Z ((cpuRegs.code>>22) & 1) +#define _W ((cpuRegs.code>>21) & 1) + +const char *dest_string(void) +{ + static char str[5]; + int i; + i = 0; + if(_X) str[i++] = 'x'; + if(_Y) str[i++] = 'y'; + if(_Z) str[i++] = 'z'; + if(_W) str[i++] = 'w'; + str[i++] = 0; + return (const char *)str; +} + +char dest_fsf() +{ + const arr[4] = { 'x', 'y', 'z', 'w' }; + return arr[(cpuRegs.code>>21)&3]; +} + +char dest_ftf() +{ + const arr[4] = { 'x', 'y', 'z', 'w' }; + return arr[(cpuRegs.code>>23)&3]; +} + +void P_VADDx(char *buf){sprintf(buf, "vaddx.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDy(char *buf){sprintf(buf, "vaddy.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDz(char *buf){sprintf(buf, "vaddz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDw(char *buf){sprintf(buf, "vaddw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBx(char *buf){sprintf(buf, "vsubx.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBy(char *buf){sprintf(buf, "vsuby.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBz(char *buf){sprintf(buf, "vsubz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBw(char *buf){sprintf(buf, "vsubw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDx(char *buf){sprintf(buf, "vmaddx.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDy(char *buf){sprintf(buf, "vmaddy.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDz(char *buf){sprintf(buf, "vmaddz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDw(char *buf){sprintf(buf, "vmaddw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBx(char *buf){sprintf(buf, "vmsubx.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBy(char *buf){sprintf(buf, "vmsuby.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBz(char *buf){sprintf(buf, "vmsubz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBw(char *buf){sprintf(buf, "vmsubw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXx(char *buf){sprintf(buf, "vmaxx.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXy(char *buf){sprintf(buf, "vmaxy.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXz(char *buf){sprintf(buf, "vmaxz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXw(char *buf){sprintf(buf, "vmaxw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIx(char *buf){sprintf(buf, "vminix.%s %s, %s, %sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIy(char *buf){sprintf(buf, "vminiy.%s %s, %s, %sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); ;} +void P_VMINIz(char *buf){sprintf(buf, "vminiz.%s %s, %s, %sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIw(char *buf){sprintf(buf, "vminiw.%s %s, %s, %sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULx(char *buf){sprintf(buf,"vmulx.%s %s,%s,%sx", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULy(char *buf){sprintf(buf,"vmuly.%s %s,%s,%sy", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULz(char *buf){sprintf(buf,"vmulz.%s %s,%s,%sz", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULw(char *buf){sprintf(buf,"vmulw.%s %s,%s,%sw", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULq(char *buf){sprintf(buf,"vmulq.%s %s,%s,Q",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMAXi(char *buf){sprintf(buf,"vmaxi.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMULi(char *buf){sprintf(buf,"vmuli.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMINIi(char *buf){sprintf(buf,"vminii.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADDq(char *buf){sprintf(buf,"vaddq.%s %s,%s,Q",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMADDq(char *buf){sprintf(buf,"vmaddq.%s %s,%s,Q",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADDi(char *buf){sprintf(buf,"vaddi.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMADDi(char *buf){sprintf(buf,"vmaddi.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VSUBq(char *buf){sprintf(buf,"vsubq.%s %s,%s,Q",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMSUBq(char *buf){sprintf(buf,"vmsubq.%s %s,%s,Q",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VSUbi(char *buf){sprintf(buf,"vsubi.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMSUBi(char *buf){sprintf(buf,"vmsubi.%s %s,%s,I",dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADD(char *buf){sprintf(buf, "vadd.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADD(char *buf){sprintf(buf, "vmadd.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMUL(char *buf){sprintf(buf, "vmul.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAX(char *buf){sprintf(buf, "vmax.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUB(char *buf){sprintf(buf, "vsub.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUB(char *buf){sprintf(buf, "vmsub.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VOPMSUB(char *buf){sprintf(buf, "vopmsub.xyz %s, %s, %s", COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINI(char *buf){sprintf(buf, "vmini.%s %s, %s, %s", dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VIADD(char *buf){sprintf(buf,"viadd %s, %s, %s", COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VISUB(char *buf){sprintf(buf,"visub %s, %s, %s", COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VIADDI(char *buf){sprintf(buf,"viaddi %s, %s, 0x%x", COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], DECODE_SA);} +void P_VIAND(char *buf){sprintf(buf,"viand %s, %s, %s", COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VIOR(char *buf){sprintf(buf,"vior %s, %s, %s", COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VCALLMS(char *buf){strcpy(buf,"vcallms");} +void P_CALLMSR(char *buf){strcpy(buf,"callmsr");} +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void P_VADDAx(char *buf){sprintf(buf,"vaddax.%s ACC,%s,%sx",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAy(char *buf){sprintf(buf,"vadday.%s ACC,%s,%sy",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAz(char *buf){sprintf(buf,"vaddaz.%s ACC,%s,%sz",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAw(char *buf){sprintf(buf,"vaddaw.%s ACC,%s,%sw",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAx(char *buf){sprintf(buf,"vsubax.%s ACC,%s,%sx",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAy(char *buf){sprintf(buf,"vsubay.%s ACC,%s,%sy",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAz(char *buf){sprintf(buf,"vsubaz.%s ACC,%s,%sz",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAw(char *buf){sprintf(buf,"vsubaw.%s ACC,%s,%sw",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAx(char *buf){sprintf(buf,"vmaddax.%s ACC,%s,%sx",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAy(char *buf){sprintf(buf,"vmadday.%s ACC,%s,%sy",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAz(char *buf){sprintf(buf,"vmaddaz.%s ACC,%s,%sz",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAw(char *buf){sprintf(buf,"vmaddaw.%s ACC,%s,%sw",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAx(char *buf){sprintf(buf,"vmsubax.%s ACC,%s,%sx",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAy(char *buf){sprintf(buf,"vmsubay.%s ACC,%s,%sy",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAz(char *buf){sprintf(buf,"vmsubaz.%s ACC,%s,%sz",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAw(char *buf){sprintf(buf,"vmsubaw.%s ACC,%s,%sw",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VITOF0(char *buf){sprintf(buf, "vitof0.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF4(char *buf){sprintf(buf, "vitof4.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF12(char *buf){sprintf(buf, "vitof12.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF15(char *buf){sprintf(buf, "vitof15.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI0(char *buf) {sprintf(buf, "vftoi0.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI4(char *buf) {sprintf(buf, "vftoi4.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI12(char *buf){sprintf(buf, "vftoi12.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI15(char *buf){sprintf(buf, "vftoi15.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VMULAx(char *buf){sprintf(buf,"vmulax.%s ACC,%s,%sx",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAy(char *buf){sprintf(buf,"vmulay.%s ACC,%s,%sy",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAz(char *buf){sprintf(buf,"vmulaz.%s ACC,%s,%sz",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAw(char *buf){sprintf(buf,"vmulaw.%s ACC,%s,%sw",dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAq(char *buf){sprintf(buf,"vmulaq.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VABS(char *buf){sprintf(buf, "vabs.%s %s, %s", dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]);} +void P_VMULAi(char *buf){sprintf(buf,"vmulaq.%s ACC %s, I" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VCLIPw(char *buf){sprintf(buf,"vclip %sxyz, %sw", COP2_REG_FP[DECODE_FS], COP2_REG_FP[DECODE_FT]);} +void P_VADDAq(char *buf){sprintf(buf,"vaddaq.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMADDAq(char *buf){sprintf(buf,"vmaddaq.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VADDAi(char *buf){sprintf(buf,"vaddai.%s ACC %s, I" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMADDAi(char *buf){sprintf(buf,"vmaddai.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VSUBAq(char *buf){sprintf(buf,"vsubaq.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMSUBAq(char *buf){sprintf(buf,"vmsubaq.%s ACC %s, Q" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VSUBAi(char *buf){sprintf(buf,"vsubai.%s ACC %s, I" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMSUBAi(char *buf){sprintf(buf,"vmsubai.%s ACC %s, I" ,dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VADDA(char *buf){sprintf(buf,"vadda.%s ACC %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDA(char *buf){sprintf(buf,"vmadda.%s ACC %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULA(char *buf){sprintf(buf,"vmula.%s ACC %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBA(char *buf){sprintf(buf,"vsuba.%s ACC %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBA(char *buf){sprintf(buf,"vmsuba.%s ACC %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VOPMULA(char *buf){sprintf(buf,"vopmula.xyz %sxyz, %sxyz" ,COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VNOP(char *buf){strcpy(buf,"vnop");} +void P_VMONE(char *buf){sprintf(buf,"vmove.%s, %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } +void P_VMR32(char *buf){sprintf(buf,"vmr32.%s, %s, %s" ,dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } +void P_VLQI(char *buf){sprintf(buf,"vlqi %s%s, (%s++)", COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VSQI(char *buf){sprintf(buf,"vsqi %s%s, (%s++)", COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} +void P_VLQD(char *buf){sprintf(buf,"vlqd %s%s, (--%s)", COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VSQD(char *buf){sprintf(buf,"vsqd %s%s, (--%s)", COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} +void P_VDIV(char *buf){sprintf(buf,"vdiv Q, %s%c, %s%c", COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VSQRT(char *buf){sprintf(buf,"vsqrt Q, %s%c", COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VRSQRT(char *buf){sprintf(buf,"vrsqrt Q, %s%c, %s%c", COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VWAITQ(char *buf){sprintf(buf,"vwaitq");} +void P_VMTIR(char *buf){sprintf(buf,"vmtir %s, %s%c", COP2_REG_CTL[DECODE_FT], COP2_REG_FP[DECODE_FS], dest_fsf());} +void P_VMFIR(char *buf){sprintf(buf,"vmfir %s%c, %s", COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VILWR(char *buf){sprintf(buf,"vilwr %s, (%s)%s", COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VISWR(char *buf){sprintf(buf,"viswr %s, (%s)%s", COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VRNEXT(char *buf){sprintf(buf,"vrnext %s%s, R", COP2_REG_CTL[DECODE_FT], dest_string());} +void P_VRGET(char *buf){sprintf(buf,"vrget %s%s, R", COP2_REG_CTL[DECODE_FT], dest_string());} +void P_VRINIT(char *buf){sprintf(buf,"vrinit R, %s%s", COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VRXOR(char *buf){sprintf(buf,"vrxor R, %s%s", COP2_REG_CTL[DECODE_FS], dest_string());} +//************************************END OF SPECIAL2 VUO TABLE**************************** diff --git a/pcsx2/DebugTools/DisVU0Micro.c b/pcsx2/DebugTools/DisVU0Micro.c new file mode 100644 index 0000000000..4e98833b6a --- /dev/null +++ b/pcsx2/DebugTools/DisVU0Micro.c @@ -0,0 +1,83 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include + +#include "Debug.h" + +char ostr[1024]; + +// Type deffinition of our functions +#define DisFInterface (u32 code, u32 pc) +#define DisFInterfaceT (u32, u32) +#define DisFInterfaceN (code, pc) + +typedef char* (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + char* fn DisFInterface { \ + sprintf (ostr, "%8.8x %8.8x:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + +//Lower/Upper instructions can use that.. +#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register + +#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) +#define dNameU(i) { char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); sprintf(ostr, "%s %-7s,", ostr, op); } + + +#define dCP2128f(i) sprintf(ostr, "%s w=%f z=%f y=%f x=%f (%s),", ostr, VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232x(i) sprintf(ostr, "%s x=%f (%s),", ostr, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232y(i) sprintf(ostr, "%s y=%f (%s),", ostr, VU0.VF[i].f.y, disRNameCP2f[i]) +#define dCP232z(i) sprintf(ostr, "%s z=%f (%s),", ostr, VU0.VF[i].f.z, disRNameCP2f[i]) +#define dCP232w(i) sprintf(ostr, "%s w=%f (%s),", ostr, VU0.VF[i].f.w, disRNameCP2f[i]) +#define dCP2ACCf() sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) +#define dCP232i(i) sprintf(ostr, "%s %8.8x (%s),", ostr, VU0.VI[i].UL, disRNameCP2i[i]) +#define dCP232iF(i) sprintf(ostr, "%s %f (%s),", ostr, VU0.VI[i].F, disRNameCP2i[i]) +#define dCP232f(i, j) sprintf(ostr, "%s Q %s=%f (%s),", ostr, CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) +#define dImm5() sprintf(ostr, "%s %d,", ostr, (code >> 6) & 0x1f) +#define dImm11() sprintf(ostr, "%s %d,", ostr, code & 0x7ff) +#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) + +#define _X ((code>>24) & 0x1) +#define _Y ((code>>23) & 0x1) +#define _Z ((code>>22) & 0x1) +#define _W ((code>>21) & 0x1) + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +extern char* disNULL DisFInterface; + +#include "DisVUmicro.h" +#include "DisVUops.h" +#include "VU.h" + +_disVUOpcodes(VU0); +_disVUTables(VU0); + diff --git a/pcsx2/DebugTools/DisVU1Micro.c b/pcsx2/DebugTools/DisVU1Micro.c new file mode 100644 index 0000000000..03ba8506c0 --- /dev/null +++ b/pcsx2/DebugTools/DisVU1Micro.c @@ -0,0 +1,123 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "Debug.h" +#include "VUmicro.h" + +char ostr[1024]; + +// Type deffinition of our functions +#define DisFInterface (u32 code, u32 pc) +#define DisFInterfaceT (u32, u32) +#define DisFInterfaceN (code, pc) + +typedef char* (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + char* fn DisFInterface { \ + if( !CHECK_VU1REC ) sprintf (ostr, "%8.8x %8.8x:", pc, code); \ + else ostr[0] = 0; \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + +//Lower/Upper instructions can use that.. +#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register + +#define dName(i) sprintf(ostr, "%s %-12s", ostr, i); \ + +#define dNameU(i) { \ + char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); \ + sprintf(ostr, "%s %-12s", ostr, op); \ +} + +#define dCP2128f(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s w=%f (%8.8x) z=%f (%8.8x) y=%f (%8.8xl) x=%f (%8.8x) (%s),", ostr, VU1.VF[i].f.w, VU1.VF[i].UL[3], VU1.VF[i].f.z, VU1.VF[i].UL[2], VU1.VF[i].f.y, VU1.VF[i].UL[1], VU1.VF[i].f.x, VU1.VF[i].UL[0], disRNameCP2f[i]); \ +} \ + +#define dCP232x(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s x=%f (%s),", ostr, VU1.VF[i].f.x, disRNameCP2f[i]); \ +} \ + +#define dCP232y(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s y=%f (%s),", ostr, VU1.VF[i].f.y, disRNameCP2f[i]); \ +} \ + +#define dCP232z(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s z=%f (%s),", ostr, VU1.VF[i].f.z, disRNameCP2f[i]); \ +} + +#define dCP232w(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s w=%f (%s),", ostr, VU1.VF[i].f.w, disRNameCP2f[i]); \ +} + +#define dCP2ACCf() { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s ACC,", ostr); \ + else sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU1.ACC.f.w, VU1.ACC.f.z, VU1.ACC.f.y, VU1.ACC.f.x); \ +} \ + +#define dCP232i(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ + else sprintf(ostr, "%s %8.8x (%s),", ostr, VU1.VI[i].UL, disRNameCP2i[i]); \ +} + +#define dCP232iF(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ + else sprintf(ostr, "%s %f (%s),", ostr, VU1.VI[i].F, disRNameCP2i[i]); \ +} + +#define dCP232f(i, j) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s%s,", ostr, disRNameCP2f[i], CP2VFnames[j]); \ + else sprintf(ostr, "%s %s=%f (%s),", ostr, CP2VFnames[j], VU1.VF[i].F[j], disRNameCP2f[i]); \ +} + +#define dImm5() sprintf(ostr, "%s %d,", ostr, (s16)((code >> 6) & 0x10 ? 0xfff0 | ((code >> 6) & 0xf) : (code >> 6) & 0xf)) +#define dImm11() sprintf(ostr, "%s %d,", ostr, (s16)(code & 0x400 ? 0xfc00 | (code & 0x3ff) : code & 0x3ff)) +#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) + +#define _X ((code>>24) & 0x1) +#define _Y ((code>>23) & 0x1) +#define _Z ((code>>22) & 0x1) +#define _W ((code>>21) & 0x1) + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +extern char* disNULL DisFInterface; + +#include "DisVUmicro.h" +#include "DisVUops.h" + +_disVUOpcodes(VU1); +_disVUTables(VU1); + diff --git a/pcsx2/DebugTools/DisVUmicro.h b/pcsx2/DebugTools/DisVUmicro.h new file mode 100644 index 0000000000..15caffe9ca --- /dev/null +++ b/pcsx2/DebugTools/DisVUmicro.h @@ -0,0 +1,209 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#define _disVUTables(VU) \ + \ +/****************/ \ +/* LOWER TABLES */ \ +/****************/ \ + \ +TdisR5900F dis##VU##LowerOP_T3_00_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_MOVE , dis##VU##MI_LQI , dis##VU##MI_DIV , dis##VU##MI_MTIR, \ + dis##VU##MI_RNEXT , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_MFP , dis##VU##MI_XTOP , dis##VU##MI_XGKICK, \ + dis##VU##MI_ESADD , dis##VU##MI_EATANxy, dis##VU##MI_ESQRT, dis##VU##MI_ESIN, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_01_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_MR32 , dis##VU##MI_SQI , dis##VU##MI_SQRT , dis##VU##MI_MFIR, \ + dis##VU##MI_RGET , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , dis##VU##MI_XITOP, disNULL , \ + dis##VU##MI_ERSADD, dis##VU##MI_EATANxz, dis##VU##MI_ERSQRT, dis##VU##MI_EATAN, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_10_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_LQD , dis##VU##MI_RSQRT, dis##VU##MI_ILWR, \ + dis##VU##MI_RINIT , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_ELENG , dis##VU##MI_ESUM , dis##VU##MI_ERCPR, dis##VU##MI_EEXP, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_11_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_SQD , dis##VU##MI_WAITQ, dis##VU##MI_ISWR, \ + dis##VU##MI_RXOR , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_ERLENG, disNULL , dis##VU##MI_WAITP, disNULL , \ +}; \ + \ +MakeDisF(dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_00_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_01_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_10_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_11, dis##VU##LowerOP_T3_11_OPCODE[_Fd_] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##LowerOP_OPCODE[64] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , /* 0x20 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_IADD , dis##VU##MI_ISUB , dis##VU##MI_IADDI, disNULL , /* 0x30 */ \ + dis##VU##MI_IAND , dis##VU##MI_IOR , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_11, \ +}; \ + \ +MakeDisF(dis##VU##LowerOP, dis##VU##LowerOP_OPCODE[code & 0x3f] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##MicroL[] = { \ + dis##VU##MI_LQ , dis##VU##MI_SQ , disNULL , disNULL, \ + dis##VU##MI_ILW , dis##VU##MI_ISW , disNULL , disNULL, \ + dis##VU##MI_IADDIU, dis##VU##MI_ISUBIU, disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + dis##VU##MI_FCEQ , dis##VU##MI_FCSET , dis##VU##MI_FCAND, dis##VU##MI_FCOR, /* 0x10 */ \ + dis##VU##MI_FSEQ , dis##VU##MI_FSSET , dis##VU##MI_FSAND, dis##VU##MI_FSOR, \ + dis##VU##MI_FMEQ , disNULL , dis##VU##MI_FMAND, dis##VU##MI_FMOR, \ + dis##VU##MI_FCGET , disNULL , disNULL , disNULL, \ + dis##VU##MI_B , dis##VU##MI_BAL , disNULL , disNULL, /* 0x20 */ \ + dis##VU##MI_JR , dis##VU##MI_JALR , disNULL , disNULL, \ + dis##VU##MI_IBEQ , dis##VU##MI_IBNE , disNULL , disNULL, \ + dis##VU##MI_IBLTZ , dis##VU##MI_IBGTZ , dis##VU##MI_IBLEZ, dis##VU##MI_IBGEZ, \ + disNULL , disNULL , disNULL , disNULL, /* 0x30 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + dis##VU##LowerOP , disNULL , disNULL , disNULL, /* 0x40*/ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x50 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x60 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x70 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ +}; \ + \ + \ +MakeDisF(dis##VU##MicroLF, dis##VU##MicroL[code >> 25] DisFInterfaceN) \ + \ + \ +/****************/ \ +/* UPPER TABLES */ \ +/****************/ \ + \ +TdisR5900F dis##VU##_UPPER_FD_00_TABLE[32] = { \ + dis##VU##MI_ADDAx, dis##VU##MI_SUBx , dis##VU##MI_MADDAx, dis##VU##MI_MSUBAx, \ + dis##VU##MI_ITOF0, dis##VU##MI_FTOI0, dis##VU##MI_MULAx , dis##VU##MI_MULAq , \ + dis##VU##MI_ADDAq, dis##VU##MI_SUBAq, dis##VU##MI_ADDA , dis##VU##MI_SUBA , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_01_TABLE[32] = { \ + dis##VU##MI_ADDAy , dis##VU##MI_SUBy , dis##VU##MI_MADDAy, dis##VU##MI_MSUBAy, \ + dis##VU##MI_ITOF4 , dis##VU##MI_FTOI4 , dis##VU##MI_MULAy , dis##VU##MI_ABS , \ + dis##VU##MI_MADDAq, dis##VU##MI_MSUBAq, dis##VU##MI_MADDA , dis##VU##MI_MSUBA , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_10_TABLE[32] = { \ + dis##VU##MI_ADDAz , dis##VU##MI_SUBz , dis##VU##MI_MADDAz, dis##VU##MI_MSUBAz, \ + dis##VU##MI_ITOF12, dis##VU##MI_FTOI12, dis##VU##MI_MULAz , dis##VU##MI_MULAi , \ + dis##VU##MI_ADDAi, dis##VU##MI_SUBAi , dis##VU##MI_MULA , dis##VU##MI_OPMULA, \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_11_TABLE[32] = { \ + dis##VU##MI_ADDAw , dis##VU##MI_SUBw , dis##VU##MI_MADDAw, dis##VU##MI_MSUBAw, \ + dis##VU##MI_ITOF15, dis##VU##MI_FTOI15, dis##VU##MI_MULAw , dis##VU##MI_CLIP , \ + dis##VU##MI_MADDAi, dis##VU##MI_MSUBAi, disNULL , dis##VU##MI_NOP , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +MakeDisF(dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_00_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_01_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_10_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_11, dis##VU##_UPPER_FD_11_TABLE[_Fd_] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##MicroU[] = { \ + dis##VU##MI_ADDx , dis##VU##MI_ADDy , dis##VU##MI_ADDz , dis##VU##MI_ADDw, \ + dis##VU##MI_SUBx , dis##VU##MI_SUBy , dis##VU##MI_SUBz , dis##VU##MI_SUBw, \ + dis##VU##MI_MADDx , dis##VU##MI_MADDy , dis##VU##MI_MADDz , dis##VU##MI_MADDw, \ + dis##VU##MI_MSUBx , dis##VU##MI_MSUBy , dis##VU##MI_MSUBz , dis##VU##MI_MSUBw, \ + dis##VU##MI_MAXx , dis##VU##MI_MAXy , dis##VU##MI_MAXz , dis##VU##MI_MAXw, /* 0x10 */ \ + dis##VU##MI_MINIx , dis##VU##MI_MINIy , dis##VU##MI_MINIz , dis##VU##MI_MINIw, \ + dis##VU##MI_MULx , dis##VU##MI_MULy , dis##VU##MI_MULz , dis##VU##MI_MULw, \ + dis##VU##MI_MULq , dis##VU##MI_MAXi , dis##VU##MI_MULi , dis##VU##MI_MINIi, \ + dis##VU##MI_ADDq , dis##VU##MI_MADDq , dis##VU##MI_ADDi , dis##VU##MI_MADDi, /* 0x20 */ \ + dis##VU##MI_SUBq , dis##VU##MI_MSUBq , dis##VU##MI_SUBi , dis##VU##MI_MSUBi, \ + dis##VU##MI_ADD , dis##VU##MI_MADD , dis##VU##MI_MUL , dis##VU##MI_MAX, \ + dis##VU##MI_SUB , dis##VU##MI_MSUB , dis##VU##MI_OPMSUB, dis##VU##MI_MINI, \ + disNULL , disNULL , disNULL , disNULL , /* 0x30 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_11, \ +}; \ + \ + \ +MakeDisF(dis##VU##MicroUF, dis##VU##MicroU[code & 0x3f] DisFInterfaceN) \ + diff --git a/pcsx2/DebugTools/DisVUops.h b/pcsx2/DebugTools/DisVUops.h new file mode 100644 index 0000000000..fb43a9d69a --- /dev/null +++ b/pcsx2/DebugTools/DisVUops.h @@ -0,0 +1,197 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#define _disVUOpcodes(VU) \ + \ +/*****************/ \ +/* LOWER OPCODES */ \ +/*****************/ \ + \ +MakeDisF(dis##VU##MI_DIV, dName("DIV"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_SQRT, dName("SQRT"); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_RSQRT, dName("RSQRT"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_IADDI, dName("IADDI"); dCP232i(_Ft_); dCP232i(_Fs_); dImm5();) \ +MakeDisF(dis##VU##MI_IADDIU, dName("IADDIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ +MakeDisF(dis##VU##MI_IADD, dName("IADD"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_IAND, dName("IAND"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_IOR, dName("IOR"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ISUB, dName("ISUB"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ISUBIU, dName("ISUBIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ +MakeDisF(dis##VU##MI_MOVE, if (_Fs_ == 0 && _Ft_ == 0) { dNameU("NOP"); } else { dNameU("MOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_); }) \ +MakeDisF(dis##VU##MI_MFIR, dNameU("MFIR"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_MTIR, dNameU("MTIR"); dCP232i(_Ft_); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_MR32, dNameU("MR32"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_LQ, dNameU("LQ"); dCP2128f(_Ft_); dCP232i(_Fs_); dImm11();) \ +MakeDisF(dis##VU##MI_LQD, dNameU("LQD"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_LQI, dNameU("LQI"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_SQ, dNameU("SQ"); dCP2128f(_Fs_); dCP232i(_Ft_); dImm11(); ) \ +MakeDisF(dis##VU##MI_SQD, dNameU("SQD"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_SQI, dNameU("SQI"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ILW, dNameU("ILW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ISW, dNameU("ISW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ILWR, dNameU("ILWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ISWR, dNameU("ISWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_LOI, dName("LOI"); ) \ +MakeDisF(dis##VU##MI_RINIT, dNameU("RINIT"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_RGET, dNameU("RGET"); dCP232i(REG_R); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_RNEXT, dNameU("RNEXT"); dCP232i(REG_R); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_RXOR, dNameU("RXOR"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_WAITQ, dName("WAITQ"); ) \ +MakeDisF(dis##VU##MI_FSAND, dName("FSAND"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff); ) \ +MakeDisF(dis##VU##MI_FSEQ, dName("FSEQ"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ +MakeDisF(dis##VU##MI_FSOR, dName("FSOR"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ +MakeDisF(dis##VU##MI_FSSET, dName("FSSET"); dCP232i(REG_STATUS_FLAG);) \ +MakeDisF(dis##VU##MI_FMAND, dName("FMAND"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FMEQ, dName("FMEQ"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FMOR, dName("FMOR"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FCAND, dName("FCAND"); dCP232i(1); sprintf(ostr, "%s %8.8x,", ostr, code&0xffffff); ) \ +MakeDisF(dis##VU##MI_FCEQ, dName("FCEQ"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_FCOR, dName("FCOR"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_FCSET, dName("FCSET"); dCP232i(REG_CLIP_FLAG); sprintf(ostr, "%s %.6x,", ostr, code&0xffffff); ) \ +MakeDisF(dis##VU##MI_FCGET, dName("FCGET"); dCP232i(_Ft_); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_IBEQ, dName("IBEQ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBGEZ, dName("IBEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBGTZ, dName("IBGTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBLEZ, dName("IBLEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBLTZ, dName("IBLTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBNE, dName("IBNE"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_B, dName("B"); dImm11();) \ +MakeDisF(dis##VU##MI_BAL, dName("BAL"); dImm11(); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_JR, dName("JR"); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_JALR, dName("JALR"); dCP232i(_Ft_); dCP232i(_Fs_); ) \ +MakeDisF(dis##VU##MI_MFP, dNameU("MFP"); dCP2128f(_Ft_); dCP232i(REG_P);) \ +MakeDisF(dis##VU##MI_WAITP, dName("WAITP"); ) \ +MakeDisF(dis##VU##MI_ESADD, dName("ESADD"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ERSADD, dName("ERSADD"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ELENG, dName("ELENG"); dCP2128f(_Fs_); ) \ +MakeDisF(dis##VU##MI_ERLENG, dName("ERLENG"); dCP2128f(_Fs_); ) \ +MakeDisF(dis##VU##MI_EATANxy, dName("EATANxy"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_EATANxz, dName("EATANxz"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ESUM, dName("ESUM"); dCP232i(_Fs_); ) \ +MakeDisF(dis##VU##MI_ERCPR, dName("ERCPR"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ESQRT, dName("ESQRT"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ERSQRT, dName("ERSQRT"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ESIN, dName("ESIN"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_EATAN, dName("EATAN"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_EEXP, dName("EEXP"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_XITOP, dName("XITOP"); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_XGKICK, dName("XGKICK"); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_XTOP, dName("XTOP"); dCP232i(_Ft_);) \ + \ + \ +/*****************/ \ +/* UPPER OPCODES */ \ +/*****************/ \ + \ +MakeDisF(dis##VU##MI_ABS, dNameU("ABS"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ADD, dNameU("ADD"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDi, dNameU("ADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_ADDq, dNameU("ADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_ADDx, dNameU("ADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDy, dNameU("ADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDz, dNameU("ADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDw, dNameU("ADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDA, dNameU("ADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAi, dNameU("ADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_ADDAq, dNameU("ADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_ADDAx, dNameU("ADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAy, dNameU("ADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAz, dNameU("ADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAw, dNameU("ADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_SUB, dNameU("SUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBi, dNameU("SUBi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_SUBq, dNameU("SUBq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_SUBx, dNameU("SUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBy, dNameU("SUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBz, dNameU("SUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBw, dNameU("SUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBA, dNameU("SUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAi, dNameU("SUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_SUBAq, dNameU("SUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_SUBAx, dNameU("SUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAy, dNameU("SUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAz, dNameU("SUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAw, dNameU("SUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MUL, dNameU("MUL"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MULi, dNameU("MULi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MULq, dNameU("MULq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MULx, dNameU("MULx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MULy, dNameU("MULy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MULz, dNameU("MULz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MULw, dNameU("MULw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MULA, dNameU("MULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAi, dNameU("MULAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MULAq, dNameU("MULAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MULAx, dNameU("MULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAy, dNameU("MULAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAz, dNameU("MULAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAw, dNameU("MULAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MADD, dNameU("MADD"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDi, dNameU("MADDi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MADDq, dNameU("MADDq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MADDx, dNameU("MADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDy, dNameU("MADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDz, dNameU("MADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDw, dNameU("MADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDA, dNameU("MADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAi, dNameU("MADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MADDAq, dNameU("MADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MADDAx, dNameU("MADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAy, dNameU("MADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAz, dNameU("MADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAw, dNameU("MADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUB, dNameU("MSUB"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBi, dNameU("MSUBi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MSUBq, dNameU("MSUBq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MSUBx, dNameU("MSUBx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBy, dNameU("MSUBy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBz, dNameU("MSUBz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBw, dNameU("MSUBw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBA, dNameU("MSUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAi, dNameU("MSUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MSUBAq, dNameU("MSUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MSUBAx, dNameU("MSUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAy, dNameU("MSUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAz, dNameU("MSUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAw, dNameU("MSUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MAX, dNameU("MAX"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXi, dNameU("MAXi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MAXx, dNameU("MAXx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXy, dNameU("MAXy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXz, dNameU("MAXz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXw, dNameU("MAXw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MINI, dNameU("MINI"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIi, dNameU("MINIi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MINIx, dNameU("MINIx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIy, dNameU("MINIy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIz, dNameU("MINIz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIw, dNameU("MINIw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_OPMULA, dNameU("OPMULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_OPMSUB, dNameU("OPMSUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_NOP, dName("NOP");) \ +MakeDisF(dis##VU##MI_FTOI0, dNameU("FTOI0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI4, dNameU("FTOI4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI12, dNameU("FTOI12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI15, dNameU("FTOI15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF0, dNameU("ITOF0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF4, dNameU("ITOF4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF12, dNameU("ITOF12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF15, dNameU("ITOF15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_CLIP, dNameU("CLIP"); dCP2128f(_Fs_); dCP232w(_Ft_);) \ + diff --git a/pcsx2/DebugTools/Makefile.am b/pcsx2/DebugTools/Makefile.am new file mode 100644 index 0000000000..8d6763ce0c --- /dev/null +++ b/pcsx2/DebugTools/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I@srcdir@/../ +noinst_LIBRARIES = libDebugTools.a + +libDebugTools_a_SOURCES = \ +cpuopsDebug.c Debug.h.bak DisR3000asm.c DisVU0Micro.c DisVUops.h \ +cpuopsDebug.h DisASM.h DisR5900asm.c DisVU1Micro.c \ +Debug.h DisR3000A.c DisR5900.c DisVUmicro.h diff --git a/pcsx2/DebugTools/cpuopsDebug.c b/pcsx2/DebugTools/cpuopsDebug.c new file mode 100644 index 0000000000..a19058bd15 --- /dev/null +++ b/pcsx2/DebugTools/cpuopsDebug.c @@ -0,0 +1,1063 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "Common.h" +#include "Debug.h" +#include "cpuopsDebug.h" + +void UpdateR5900op() +{ + FILE *fp; + fp=fopen("cpuops.txt", "wt"); + fprintf(fp, "------------\n"); + fprintf(fp, "--R5900ops--\n"); + fprintf(fp, "------------\n"); + if(L_ADD>0) fprintf(fp, "Add %d\n", L_ADD); + if(L_ADDI>0) fprintf(fp, "Addi %d\n", L_ADDI); + if(L_ADDIU>0) fprintf(fp, "Addiu %d\n", L_ADDIU); + if(L_ADDU>0) fprintf(fp, "Addu %d\n", L_ADDU); + if(L_AND>0) fprintf(fp, "And %d\n", L_AND); + if(L_ANDI>0) fprintf(fp, "Andi %d\n", L_ANDI); + if(L_BEQ>0) fprintf(fp, "Beq %d\n", L_BEQ); + if(L_BEQL>0) fprintf(fp, "Beql %d\n", L_BEQL); + if(L_BGEZ>0) fprintf(fp, "Bgez %d\n", L_BGEZ); + if(L_BGEZAL>0) fprintf(fp, "Bgezal %d\n", L_BGEZAL); + if(L_BGEZALL>0) fprintf(fp, "Bgezall %d\n", L_BGEZALL); + if(L_BGEZL>0) fprintf(fp, "Bgezl %d\n", L_BGEZL); + if( L_BGTZ>0) fprintf(fp, "Bgtz %d\n", L_BGTZ); + if( L_BGTZL>0) fprintf(fp, "Bgtzl %d\n", L_BGTZL); + if(L_BLEZ>0) fprintf(fp, "Blez %d\n", L_BLEZ); + if(L_BLEZL>0) fprintf(fp, "blezl %d\n", L_BLEZL); + if(L_BLTZ>0) fprintf(fp, "bltz %d\n", L_BLTZ); + if(L_BLTZAL>0) fprintf(fp, "bltzal %d\n", L_BLTZAL); + if(L_BLTZALL>0) fprintf(fp, "bltzall %d\n", L_BLTZALL); + if(L_BLTZL>0) fprintf(fp, "bltzl %d\n", L_BLTZL); + if(L_BNE>0) fprintf(fp, "bne %d\n", L_BNE); + if(L_BNEL>0) fprintf(fp, "bnel %d\n", L_BNEL); + if(L_BREAK>0) fprintf(fp, "break %d\n", L_BREAK); + if(L_CACHE>0) fprintf(fp, "cache %d\n", L_CACHE); + if(L_DADD>0) fprintf(fp, "dadd %d\n", L_DADD); + if(L_DADDI>0) fprintf(fp, "daddi %d\n", L_DADDI); + if(L_DADDIU>0) fprintf(fp, "daddiu %d\n", L_DADDIU); + if(L_DADDU>0) fprintf(fp, "daddu %d\n", L_DADDU); + if(L_DIV>0) fprintf(fp, "div %d\n", L_DIV); + if(L_DIVU>0) fprintf(fp, "divu %d\n", L_DIVU); + if(L_DSLL>0) fprintf(fp, "dsll %d\n", L_DSLL); + if(L_DSLL32>0) fprintf(fp, "dsll32 %d\n", L_DSLL32); + if(L_DSLLV>0) fprintf(fp, "dsllv %d\n", L_DSLLV); + if(L_DSRA>0) fprintf(fp, "dsra %d\n", L_DSRA); + if(L_DSRA32>0) fprintf(fp, "dsra32 %d\n", L_DSRA32); + if(L_DSRAV>0) fprintf(fp, "dsrav %d\n", L_DSRAV); + if(L_DSRL>0) fprintf(fp, "dsrl %d\n", L_DSRL); + if(L_DSRL32>0) fprintf(fp, "dsr32 %d\n", L_DSRL32); + if(L_DSRLV>0) fprintf(fp, "dsrlv %d\n", L_DSRLV); + if(L_DSUB>0) fprintf(fp, "dsub %d\n", L_DSUB); + if(L_DSUBU>0) fprintf(fp, "dsubu %d\n", L_DSUBU); + if(L_J>0) fprintf(fp, "j %d\n", L_J); + if(L_JAL>0) fprintf(fp, "jal %d\n", L_JAL); + if(L_JALR>0) fprintf(fp, "jalr %d\n", L_JALR); + if(L_JR>0) fprintf(fp, "jr %d\n", L_JR); + if(L_LB>0) fprintf(fp, "lb %d\n", L_LB); + if(L_LBU>0) fprintf(fp, "lbu %d\n", L_LBU); + if(L_LD>0) fprintf(fp, "ld %d\n", L_LD); + if(L_LDL>0) fprintf(fp, "ldl %d\n", L_LDL); + if(L_LDR>0) fprintf(fp, "ldr %d\n", L_LDR); + if(L_LH>0) fprintf(fp, "lh %d\n", L_LH); + if(L_LHU>0) fprintf(fp, "lhu %d\n", L_LHU); + if(L_LQ>0) fprintf(fp, "lq %d\n", L_LQ); + if(L_LUI>0) fprintf(fp, "lui %d\n", L_LUI); + if(L_LW>0) fprintf(fp, "lw %d\n", L_LW); + if(L_LWL>0) fprintf(fp, "lwl %d\n", L_LWL); + if(L_LWR>0) fprintf(fp, "lwr %d\n", L_LWR); + if(L_LWU>0) fprintf(fp, "lwu %d\n", L_LWU); + if(L_MFHI>0) fprintf(fp, "mfhi %d\n", L_MFHI); + if(L_MFLO>0) fprintf(fp, "mflo %d\n", L_MFLO); + if(L_MFSA>0) fprintf(fp, "mfsa %d\n", L_MFSA); + if(L_MOVN>0) fprintf(fp, "movn %d\n", L_MOVN); + if(L_MOVZ>0) fprintf(fp, "movz %d\n", L_MOVZ); + if(L_MTHI>0) fprintf(fp, "mthi %d\n", L_MTHI); + if(L_MTLO>0) fprintf(fp, "mtlo %d\n", L_MTLO); + if(L_MTSA>0) fprintf(fp, "mtsa %d\n", L_MTSA); + if(L_MTSAB>0) fprintf(fp, "mtsab %d\n", L_MTSAB); + if(L_MTSAH>0) fprintf(fp, "mtsah %d\n", L_MTSAH); + if(L_MULT>0) fprintf(fp, "mult %d\n", L_MULT); + if(L_MULTU>0) fprintf(fp, "multu %d\n", L_MULTU); + if(L_NOR>0) fprintf(fp, "nor %d\n", L_NOR); + if(L_OR>0) fprintf(fp, "or %d\n", L_OR); + if(L_ORI>0) fprintf(fp, "ori %d\n", L_ORI); + if(L_PREF>0) fprintf(fp, "pref %d\n", L_PREF); + if(L_SB>0) fprintf(fp, "sb %d\n", L_SB); + if(L_SD>0) fprintf(fp, "sd %d\n", L_SD); + if(L_SDL>0) fprintf(fp, "sdl %d\n", L_SDL); + if(L_SDR>0) fprintf(fp, "sdr %d\n", L_SDR); + if(L_SH>0) fprintf(fp, "sh %d\n", L_SH); + if(L_SLL>0) fprintf(fp, "sll %d\n", L_SLL); + if(L_SLLV>0) fprintf(fp, "sllv %d\n", L_SLLV); + if(L_SLT>0) fprintf(fp, "slt %d\n", L_SLT); + if(L_SLTI>0) fprintf(fp, "slti %d\n", L_SLTI); + if(L_SLTIU>0) fprintf(fp, "sltiu %d\n", L_SLTIU); + if(L_SLTU>0) fprintf(fp, "sltu %d\n", L_SLTU); + if(L_SQ>0) fprintf(fp, "sq %d\n", L_SQ); + if(L_SRA>0) fprintf(fp, "sra %d\n", L_SRA); + if(L_SRAV>0) fprintf(fp, "srav %d\n", L_SRAV); + if(L_SRL>0) fprintf(fp, "srl %d\n", L_SRL); + if(L_SRLV>0) fprintf(fp, "srlv %d\n", L_SRLV); + if(L_SUB>0) fprintf(fp, "sub %d\n", L_SUB); + if(L_SUBU>0) fprintf(fp, "subu %d\n", L_SUBU); + if(L_SW>0) fprintf(fp, "sw %d\n", L_SW); + if(L_SWL>0) fprintf(fp, "swl %d\n", L_SWL); + if(L_SWR>0) fprintf(fp, "swr %d\n", L_SWR); + if(L_SYNC>0) fprintf(fp, "sync %d\n", L_SYNC); + if(L_SYSCALL>0) fprintf(fp, "syscall %d\n", L_SYSCALL); + if(L_TEQ>0) fprintf(fp, "teq %d\n", L_TEQ); + if(L_TEQI>0) fprintf(fp, "teqi %d\n", L_TEQI); + if(L_TGE>0) fprintf(fp, "tge %d\n", L_TGE); + if(L_TGEI>0) fprintf(fp, "tgei %d\n", L_TGEI); + if(L_TGEIU>0) fprintf(fp, "tgeiu %d\n", L_TGEIU); + if(L_TGEU>0) fprintf(fp, "tgeu %d\n", L_TGEU); + if(L_TLT>0) fprintf(fp, "tlt %d\n", L_TLT); + if(L_TLTI>0) fprintf(fp, "tlti %d\n", L_TLTI); + if(L_TLTIU>0) fprintf(fp, "tltiu %d\n", L_TLTIU); + if(L_TLTU>0) fprintf(fp, "tltu %d\n", L_TLTU); + if(L_TNE>0) fprintf(fp, "tne %d\n", L_TNE); + if(L_TNEI>0) fprintf(fp, "tnei %d\n", L_TNEI); + if(L_XOR>0) fprintf(fp, "xor %d\n", L_XOR); + if(L_XORI>0) fprintf(fp, "xori %d\n", L_XORI); + fprintf(fp, "------------\n"); + fprintf(fp, "--MMI ops--\n"); + fprintf(fp, "------------\n"); + if(L_DIV1>0) fprintf(fp, "div1 %d\n", L_DIV1); + if(L_DIVU1>0) fprintf(fp, "divu1 %d\n", L_DIVU1); + if(L_MADD>0) fprintf(fp, "madd %d\n", L_MADD); + if(L_MADD1>0) fprintf(fp, "madd1 %d\n", L_MADD1); + if(L_MADDU>0) fprintf(fp, "maddu %d\n", L_MADDU); + if(L_MADDU1>0) fprintf(fp, "maddu1 %d\n", L_MADDU1); + if(L_MFHI1>0) fprintf(fp, "mfhi1 %d\n", L_MFHI1); + if(L_MFLO1>0) fprintf(fp, "mflo1 %d\n", L_MFLO1); + if(L_MTHI1>0) fprintf(fp, "mthi1 %d\n", L_MTHI1); + if(L_MTLO1>0) fprintf(fp, "mtlo1 %d\n", L_MTLO1); + if(L_MULT1>0) fprintf(fp, "mult1 %d\n", L_MULT1); + if(L_MULTU1>0) fprintf(fp, "multu1 %d\n", L_MULTU1); + if(L_PABSH>0) fprintf(fp, "pabsh %d\n", L_PABSH); + if(L_PABSW>0) fprintf(fp, "pabsw %d\n", L_PABSW); + if(L_PADDB>0) fprintf(fp, "paddb %d\n", L_PADDB); + if(L_PADDH>0) fprintf(fp, "paddh %d\n", L_PADDH); + if(L_PADDSB>0) fprintf(fp, "paddsb %d\n", L_PADDSB); + if(L_PADDSH>0) fprintf(fp, "paddsh %d\n", L_PADDSH); + if(L_PADDSW>0) fprintf(fp, "paddsw %d\n", L_PADDSW); + if(L_PADDUB>0) fprintf(fp, "paddub %d\n", L_PADDUB); + if(L_PADDUH>0) fprintf(fp, "padduh %d\n", L_PADDUH); + if(L_PADDUW>0) fprintf(fp, "padduw %d\n", L_PADDUW); + if(L_PADDW>0) fprintf(fp, "paddw %d\n", L_PADDW); + if(L_PADSBH>0) fprintf(fp, "padsbh %d\n", L_PADSBH); + if(L_PAND>0) fprintf(fp, "pand %d\n", L_PAND); + if(L_PCEQB>0) fprintf(fp, "pceqb %d\n", L_PCEQB); + if(L_PCEQH>0) fprintf(fp, "pceqh %d\n", L_PCEQH); + if(L_PCEQW>0) fprintf(fp, "pceqw %d\n", L_PCEQW); + if(L_PCGTB>0) fprintf(fp, "pcgtb %d\n", L_PCGTB); + if(L_PCGTH>0) fprintf(fp, "pcgth %d\n", L_PCGTH); + if(L_PCGTW>0) fprintf(fp, "pcgtw %d\n", L_PCGTW); + if(L_PCPYH>0) fprintf(fp, "pcpyh %d\n", L_PCPYH); + if(L_PCPYLD>0) fprintf(fp, "pcpyld %d\n", L_PCPYLD); + if(L_PCPYUD>0) fprintf(fp, "pcpyud %d\n", L_PCPYUD); + if(L_PDIVBW>0) fprintf(fp, "pdivbw %d\n", L_PDIVBW); + if(L_PDIVUW>0) fprintf(fp, "pdivuw %d\n", L_PDIVUW); + if(L_PDIVW>0) fprintf(fp, "pdivw %d\n", L_PDIVW); + if(L_PEXCH>0) fprintf(fp, "pexch %d\n", L_PEXCH); + if(L_PEXCW>0) fprintf(fp, "pexcw %d\n", L_PEXCW); + if(L_PEXEH>0) fprintf(fp, "pexeh %d\n", L_PEXEH); + if(L_PEXEW>0) fprintf(fp, "pexew %d\n", L_PEXEW); + if(L_PEXT5>0) fprintf(fp, "pext5 %d\n", L_PEXT5); + if(L_PEXTLB>0) fprintf(fp, "pextlb %d\n", L_PEXTLB); + if(L_PEXTLH>0) fprintf(fp, "pextlh %d\n", L_PEXTLH); + if(L_PEXTLW>0) fprintf(fp, "pextlw %d\n", L_PEXTLW); + if(L_PEXTUB>0) fprintf(fp, "pextub %d\n", L_PEXTUB); + if(L_PEXTUH>0) fprintf(fp, "pextuh %d\n", L_PEXTUH); + if(L_PEXTUW>0) fprintf(fp, "pextuw %d\n", L_PEXTUW); + if(L_PHMADH>0) fprintf(fp, "phmadh %d\n", L_PHMADH); + if(L_PHMSBH>0) fprintf(fp, "phmsbh %d\n", L_PHMSBH); + if(L_PINTEH>0) fprintf(fp, "pinteh %d\n", L_PINTEH); + if(L_PINTH>0) fprintf(fp, "pinth %d\n", L_PINTH); + if(L_PLZCW>0) fprintf(fp, "plzcw %d\n", L_PLZCW); + if(L_PMADDH>0) fprintf(fp, "pmaddh %d\n", L_PMADDH); + if(L_PMADDUW>0) fprintf(fp, "pmadduw %d\n", L_PMADDUW); + if(L_PMADDW>0) fprintf(fp, "pmaddw %d\n", L_PMADDW); + if(L_PMAXH>0) fprintf(fp, "pmaxh %d\n", L_PMAXH); + if(L_PMAXW>0) fprintf(fp, "pmaxw %d\n", L_PMAXW); + if(L_PMFHI>0) fprintf(fp, "pmfhi %d\n", L_PMFHI); + if(L_PMFHL>0) fprintf(fp, "pmfhl %d\n", L_PMFHL); + if(L_PMFLO>0) fprintf(fp, "pmflo %d\n", L_PMFLO); + if(L_PMINH>0) fprintf(fp, "pminh %d\n", L_PMINH); + if(L_PMINW>0) fprintf(fp, "pminw %d\n", L_PMINW); + if(L_PMSUBH>0) fprintf(fp, "pmsubh %d\n", L_PMSUBH); + if(L_PMSUBW>0) fprintf(fp, "pmsubw %d\n", L_PMSUBW); + if(L_PMTHI>0) fprintf(fp, "pmthi %d\n", L_PMTHI); + if(L_PMTHL>0) fprintf(fp, "pmthl %d\n", L_PMTHL); + if(L_PMTLO>0) fprintf(fp, "pmtlo %d\n", L_PMTLO); + if(L_PMULTH>0) fprintf(fp, "pmulth %d\n", L_PMULTH); + if(L_PMULTUW>0) fprintf(fp, "pmultuw %d\n", L_PMULTUW); + if(L_PMULTW>0) fprintf(fp, "pmultw %d\n", L_PMULTW); + if(L_PNOR>0) fprintf(fp, "pnor %d\n", L_PNOR); + if(L_POR>0) fprintf(fp, "por %d\n", L_POR); + if(L_PPAC5>0) fprintf(fp, "ppac5 %d\n", L_PPAC5); + if(L_PPACB>0) fprintf(fp, "ppacb %d\n", L_PPACB); + if(L_PPACH>0) fprintf(fp, "ppach %d\n", L_PPACH); + if(L_PPACW>0) fprintf(fp, "ppacw %d\n", L_PPACW); + if(L_PREVH>0) fprintf(fp, "prevh %d\n", L_PREVH); + if(L_PROT3W>0) fprintf(fp, "prot3w %d\n", L_PROT3W); + if(L_PSLLH>0) fprintf(fp, "psllh %d\n", L_PSLLH); + if(L_PSLLVW>0) fprintf(fp, "psllvw %d\n", L_PSLLVW); + if(L_PSLLW>0) fprintf(fp, "psllw %d\n", L_PSLLW); + if(L_PSRAH>0) fprintf(fp, "psrah %d\n", L_PSRAH); + if(L_PSRAVW>0) fprintf(fp, "psravw %d\n", L_PSRAVW); + if(L_PSRAW>0) fprintf(fp, "psraw %d\n", L_PSRAW); + if(L_PSRLH>0) fprintf(fp, "psrlh %d\n", L_PSRLH); + if(L_PSRLVW>0) fprintf(fp, "psrlvw %d\n", L_PSRLVW); + if(L_PSRLW>0) fprintf(fp, "psrlw %d\n", L_PSRLW); + if(L_PSUBB>0) fprintf(fp, "psubb %d\n", L_PSUBB); + if(L_PSUBH>0) fprintf(fp, "psubh %d\n", L_PSUBH); + if(L_PSUBSB>0) fprintf(fp, "psubsb %d\n", L_PSUBSB); + if(L_PSUBSH>0) fprintf(fp, "psubsh %d\n", L_PSUBSH); + if(L_PSUBSW>0) fprintf(fp, "psubsw %d\n", L_PSUBSW); + if(L_PSUBUB>0) fprintf(fp, "psubub %d\n", L_PSUBUB); + if(L_PSUBUH>0) fprintf(fp, "psubuh %d\n", L_PSUBUH); + if(L_PSUBUW>0) fprintf(fp, "psubuw %d\n", L_PSUBUW); + if(L_PSUBW>0) fprintf(fp, "psubw %d\n", L_PSUBW); + if(L_PXOR>0) fprintf(fp, "pxor %d\n", L_PXOR); + if(L_QFSRV>0) fprintf(fp, "qfsrv %d\n", L_QFSRV); + fprintf(fp, "------------\n"); + fprintf(fp, "--COP0 ops--\n"); + fprintf(fp, "------------\n"); + if(L_BC0F>0) fprintf(fp, "bc0f %d\n", L_BC0F); + if(L_BC0FL>0) fprintf(fp, "bc0fl %d\n", L_BC0FL); + if(L_BC0T>0) fprintf(fp, "bc0t %d\n", L_BC0T); + if(L_BC0TL>0) fprintf(fp, "bc0tl %d\n", L_BC0TL); + if(L_DI>0) fprintf(fp, "di %d\n", L_DI); + if(L_EI>0) fprintf(fp, "ei %d\n", L_EI); + if(L_ERET>0) fprintf(fp, "eret %d\n", L_ERET); + if(L_MTC0>0) fprintf(fp, "mtc0 %d\n", L_MTC0); + if(L_TLBP>0) fprintf(fp, "tlbp %d\n", L_TLBP); + if(L_TLBR>0) fprintf(fp, "tlbr %d\n", L_TLBR); + if(L_TLBWI>0) fprintf(fp, "tlbwi %d\n", L_TLBWI); + if(L_TLBWR>0) fprintf(fp, "tlbwr %d\n", L_TLBWR); + if(L_MFC0>0) fprintf(fp, "mfc0 %d\n", L_MFC0); + fprintf(fp, "------------\n"); + fprintf(fp, "--COP1 ops--\n"); + fprintf(fp, "------------\n"); + if(L_LWC1>0) fprintf(fp, "lwc1 %d\n", L_LWC1); + if(L_SWC1>0) fprintf(fp, "swc1 %d\n", L_SWC1); + if(L_ABS_S>0) fprintf(fp, "abs_s %d\n", L_ABS_S); + if(L_ADD_S>0) fprintf(fp, "add_s %d\n", L_ADD_S); + if(L_ADDA_S>0) fprintf(fp, "adda_s %d\n", L_ADDA_S); + if(L_BC1F>0) fprintf(fp, "bc1f %d\n", L_BC1F); + if(L_BC1FL>0) fprintf(fp, "bc1fl %d\n", L_BC1FL); + if(L_BC1T>0) fprintf(fp, "bc1t %d\n", L_BC1T); + if(L_BC1TL>0) fprintf(fp, "bc1tl %d\n", L_BC1TL); + if(L_C_EQ>0) fprintf(fp, "c_eq %d\n", L_C_EQ); + if(L_C_F>0) fprintf(fp, "c_f %d\n", L_C_F); + if(L_C_LE>0) fprintf(fp, "c_le %d\n", L_C_LE); + if(L_C_LT>0) fprintf(fp, "c_lt %d\n", L_C_LT); + if(L_CFC1>0) fprintf(fp, "cfc1 %d\n", L_CFC1); + if(L_CTC1>0) fprintf(fp, "ctc1 %d\n", L_CTC1); + if(L_CVT_S>0) fprintf(fp, "cvt_s %d\n", L_CVT_S); + if(L_CVT_W>0) fprintf(fp, "cvt_w %d\n", L_CVT_W); + if(L_DIV_S>0) fprintf(fp, "div_s %d\n", L_DIV_S); + if(L_MADD_S>0) fprintf(fp, "madd_s %d\n", L_MADD_S); + if(L_MADDA_S>0) fprintf(fp, "madda_s %d\n", L_MADDA_S); + if(L_MAX_S>0) fprintf(fp, "max_s %d\n", L_MAX_S); + if(L_MFC1>0) fprintf(fp, "mfc1 %d\n", L_MFC1); + if(L_MIN_S>0) fprintf(fp, "min_s %d\n", L_MIN_S); + if(L_MOV_S>0) fprintf(fp, "mov_s %d\n", L_MOV_S); + if(L_MSUB_S>0) fprintf(fp, "msub_s %d\n", L_MSUB_S); + if(L_MSUBA_S>0) fprintf(fp, "msuba_s %d\n", L_MSUBA_S); + if(L_MTC1>0) fprintf(fp, "mtc1 %d\n", L_MTC1); + if(L_MUL_S>0) fprintf(fp, "mul_s %d\n", L_MUL_S); + if(L_MULA_S>0) fprintf(fp, "mula_s %d\n", L_MULA_S); + if(L_NEG_S>0) fprintf(fp, "neg_s %d\n", L_NEG_S); + if(L_RSQRT_S>0) fprintf(fp, "rsqrt_s %d\n", L_RSQRT_S); + if(L_SQRT_S>0) fprintf(fp, "sqrt_s %d\n", L_SQRT_S); + if(L_SUB_S>0) fprintf(fp, "sub_s %d\n", L_SUB_S); + if(L_SUBA_S>0) fprintf(fp, "suba_s %d\n", L_SUBA_S); + fprintf(fp, "------------\n"); + fprintf(fp, "--COP2 ops--\n"); + fprintf(fp, "------------\n"); + if(L_LQC2>0) fprintf(fp, "lqc2 %d\n", L_LQC2); + if(L_SQC2>0) fprintf(fp, "sqc2 %d\n", L_SQC2); + if(L_BC2F>0) fprintf(fp, "bc2f %d\n", L_BC2F); + if(L_BC2FL>0) fprintf(fp, "bc2fl %d\n", L_BC2FL); + if(L_BC2T>0) fprintf(fp, "bc2t %d\n", L_BC2T); + if(L_BC2TL>0) fprintf(fp, "bc2tl %d\n", L_BC2TL); + if(L_CFC2>0) fprintf(fp, "cfc2 %d\n", L_CFC2); + if(L_CTC2>0) fprintf(fp, "ctc2 %d\n", L_CTC2); + if(L_QMFC2>0) fprintf(fp, "qmfc2 %d\n", L_QMFC2); + if(L_QMTC2>0) fprintf(fp, "qmtc2 %d\n", L_QMTC2); + if(L_VABS>0) fprintf(fp, "vabs %d\n", L_VABS); + if(L_VADD>0) fprintf(fp, "vadd %d\n", L_VADD); + if(L_VADDA>0) fprintf(fp, "vadda %d\n", L_VADDA); + if(L_VADDAi>0) fprintf(fp, "vaddai %d\n", L_VADDAi); + if(L_VADDAq>0) fprintf(fp, "vaddaq %d\n", L_VADDAq); + if(L_VADDAw>0) fprintf(fp, "vaddaw %d\n", L_VADDAw); + if(L_VADDAx>0) fprintf(fp, "vaddax %d\n", L_VADDAx); + if(L_VADDAy>0) fprintf(fp, "vadday %d\n", L_VADDAy); + if(L_VADDAz>0) fprintf(fp, "vaddaz %d\n", L_VADDAz); + if(L_VADDi>0) fprintf(fp, "vaddi %d\n", L_VADDi); + if(L_VADDq>0) fprintf(fp, "vaddq %d\n", L_VADDq); + if(L_VADDw>0) fprintf(fp, "vaddw %d\n", L_VADDw); + if(L_VADDx>0) fprintf(fp, "vaddx %d\n", L_VADDx); + if(L_VADDy>0) fprintf(fp, "vaddy %d\n", L_VADDy); + if(L_VADDz>0) fprintf(fp, "vaddz %d\n", L_VADDz); + if(L_VCALLMS>0) fprintf(fp, "vcallms %d\n", L_VCALLMS); + if(L_VCALLMSR>0) fprintf(fp, "vcallmsr %d\n", L_VCALLMSR); + if(L_VCLIPw>0) fprintf(fp, "vclip %d\n", L_VCLIPw); + if(L_VDIV>0) fprintf(fp, "vdiv %d\n", L_VDIV); + if(L_VFTOI0>0) fprintf(fp, "vftoi0 %d\n", L_VFTOI0); + if(L_VFTOI12>0) fprintf(fp, "vftoi12 %d\n", L_VFTOI12); + if(L_VFTOI15>0) fprintf(fp, "vftoi15 %d\n", L_VFTOI15); + if(L_VFTOI4>0) fprintf(fp, "vftoi14 %d\n", L_VFTOI4); + if(L_VIADD>0) fprintf(fp, "viadd %d\n", L_VIADD); + if(L_VIADDI>0) fprintf(fp, "viaddi %d\n", L_VIADDI); + if(L_VIAND>0) fprintf(fp, "viand %d\n", L_VIAND); + if(L_VILWR>0) fprintf(fp, "vilwr %d\n", L_VILWR); + if(L_VIOR>0) fprintf(fp, "vior %d\n", L_VIOR); + if(L_VISUB>0) fprintf(fp, "visub %d\n", L_VISUB); + if(L_VISWR>0) fprintf(fp, "viswr %d\n", L_VISWR); + if(L_VITOF0>0) fprintf(fp, "vitof0 %d\n", L_VITOF0); + if(L_VITOF12>0) fprintf(fp, "vitof12 %d\n", L_VITOF12); + if(L_VITOF15>0) fprintf(fp, "vitof15 %d\n", L_VITOF15); + if(L_VITOF4>0) fprintf(fp, "vitof4 %d\n", L_VITOF4); + if(L_VLQD>0) fprintf(fp, "vlqd %d\n", L_VLQD); + if(L_VLQI>0) fprintf(fp, "vlqi %d\n", L_VLQI); + if(L_VMADD>0) fprintf(fp, "vmadd %d\n", L_VMADD); + if(L_VMADDA>0) fprintf(fp, "vmadda %d\n", L_VMADDA); + if(L_VMADDAi>0) fprintf(fp, "vmaddai %d\n", L_VMADDAi); + if(L_VMADDAq>0) fprintf(fp, "vmaddaq %d\n", L_VMADDAq); + if(L_VMADDAw>0) fprintf(fp, "vmaddaw %d\n", L_VMADDAw); + if(L_VMADDAx>0) fprintf(fp, "vmaddax %d\n", L_VMADDAx); + if(L_VMADDAy>0) fprintf(fp, "vmadday %d\n", L_VMADDAy); + if(L_VMADDAz>0) fprintf(fp, "vmaddaz %d\n", L_VMADDAz); + if(L_VMADDi>0) fprintf(fp, "vmaddi %d\n", L_VMADDi); + if(L_VMADDq>0) fprintf(fp, "vmaddq %d\n", L_VMADDq); + if(L_VMADDw>0) fprintf(fp, "vmaddw %d\n", L_VMADDw); + if(L_VMADDx>0) fprintf(fp, "vmaddx %d\n", L_VMADDx); + if(L_VMADDy>0) fprintf(fp, "vmaddy %d\n", L_VMADDy); + if(L_VMADDz>0) fprintf(fp, "vmaddz %d\n", L_VMADDz); + if(L_VMAX>0) fprintf(fp, "vmax %d\n", L_VMAX); + if(L_VMAXi>0) fprintf(fp, "vmaxi %d\n", L_VMAXi); + if(L_VMAXw>0) fprintf(fp, "vmaxw %d\n", L_VMAXw); + if(L_VMAXx>0) fprintf(fp, "vmaxx %d\n", L_VMAXx); + if(L_VMAXy>0) fprintf(fp, "vmaxy %d\n", L_VMAXy); + if(L_VMAXz>0) fprintf(fp, "vmaxz %d\n", L_VMAXz); + if(L_VMFIR>0) fprintf(fp, "vmfir %d\n", L_VMFIR); + if(L_VMINI>0) fprintf(fp, "vmini %d\n", L_VMINI); + if(L_VMINIi>0) fprintf(fp, "vminii %d\n", L_VMINIi); + if(L_VMINIw>0) fprintf(fp, "vminiw %d\n", L_VMINIw); + if(L_VMINIx>0) fprintf(fp, "vminix %d\n", L_VMINIx); + if(L_VMINIy>0) fprintf(fp, "vminiy %d\n", L_VMINIy); + if(L_VMINIz>0) fprintf(fp, "vminiz %d\n", L_VMINIz); + if(L_VMOVE>0) fprintf(fp, "vmove %d\n", L_VMOVE); + if(L_VMR32>0) fprintf(fp, "vmr32 %d\n", L_VMR32); + if(L_VMSUB>0) fprintf(fp, "vmsub %d\n", L_VMSUB); + if(L_VMSUBA>0) fprintf(fp, "vmsuba %d\n", L_VMSUBA); + if(L_VMSUBAi>0) fprintf(fp, "vmsubai %d\n", L_VMSUBAi); + if(L_VMSUBAq>0) fprintf(fp, "vmsubaq %d\n", L_VMSUBAq); + if(L_VMSUBAw>0) fprintf(fp, "vmsubaw %d\n", L_VMSUBAw); + if(L_VMSUBAx>0) fprintf(fp, "vmsubax %d\n", L_VMSUBAx); + if(L_VMSUBAy>0) fprintf(fp, "vmsubay %d\n", L_VMSUBAy); + if(L_VMSUBAz>0) fprintf(fp, "vmsubaz %d\n", L_VMSUBAz); + if(L_VMSUBi>0) fprintf(fp, "vmsubi %d\n", L_VMSUBi); + if(L_VMSUBq>0) fprintf(fp, "vmsubq %d\n", L_VMSUBq); + if(L_VMSUBw>0) fprintf(fp, "vmsubw %d\n", L_VMSUBw); + if(L_VMSUBx>0) fprintf(fp, "vmsubx %d\n", L_VMSUBx); + if(L_VMSUBy>0) fprintf(fp, "vmsuby %d\n", L_VMSUBy); + if(L_VMSUBz>0) fprintf(fp, "vmsubz %d\n", L_VMSUBz); + if(L_VMTIR>0) fprintf(fp, "vmtir %d\n", L_VMTIR); + if(L_VMUL>0) fprintf(fp, "vmul %d\n", L_VMUL); + if(L_VMULA>0) fprintf(fp, "vmula %d\n", L_VMULA); + if(L_VMULAi>0) fprintf(fp, "vmulai %d\n", L_VMULAi); + if(L_VMULAq>0) fprintf(fp, "vmulaq %d\n", L_VMULAq); + if(L_VMULAw>0) fprintf(fp, "vmulaw %d\n", L_VMULAw); + if(L_VMULAx>0) fprintf(fp, "vmulax %d\n", L_VMULAx); + if(L_VMULAy>0) fprintf(fp, "vmulay %d\n", L_VMULAy); + if(L_VMULAz>0) fprintf(fp, "vmulaz %d\n", L_VMULAz); + if(L_VMULi>0) fprintf(fp, "vmuli %d\n", L_VMULi); + if(L_VMULq>0) fprintf(fp, "vmulq %d\n", L_VMULq); + if(L_VMULw>0) fprintf(fp, "vmulw %d\n", L_VMULw); + if(L_VMULx>0) fprintf(fp, "vmulx %d\n", L_VMULx); + if(L_VMULy>0) fprintf(fp, "vmuly %d\n", L_VMULy); + if(L_VMULz>0) fprintf(fp, "vmulz %d\n", L_VMULz); + if(L_VNOP>0) fprintf(fp, "vnop %d\n", L_VNOP); + if(L_VOPMSUB>0) fprintf(fp, "vopmsub %d\n", L_VOPMSUB); + if(L_VOPMULA>0) fprintf(fp, "vopmula %d\n", L_VOPMULA); + if(L_VRGET>0) fprintf(fp, "vrget %d\n", L_VRGET); + if(L_VRINIT>0) fprintf(fp, "vrinit %d\n", L_VRINIT); + if(L_VRNEXT>0) fprintf(fp, "vrnext %d\n", L_VRNEXT); + if(L_VRSQRT>0) fprintf(fp, "vrsqrt %d\n", L_VRSQRT); + if(L_VRXOR>0) fprintf(fp, "vrxor %d\n", L_VRXOR); + if(L_VSQD>0) fprintf(fp, "vsqd %d\n", L_VSQD); + if(L_VSQI>0) fprintf(fp, "vsqi %d\n", L_VSQI); + if(L_VSQRT>0) fprintf(fp, "vsqrt %d\n", L_VSQRT ); + if(L_VSUB>0) fprintf(fp, "vsub %d\n", L_VSUB); + if(L_VSUBA>0) fprintf(fp, "vsuba %d\n", L_VSUBA); + if(L_VSUBAi>0) fprintf(fp, "vsubai %d\n", L_VSUBAi); + if(L_VSUBAq>0) fprintf(fp, "vsubaq %d\n", L_VSUBAq); + if(L_VSUBAw>0) fprintf(fp, "vsubaw %d\n", L_VSUBAw); + if(L_VSUBAx>0) fprintf(fp, "vsubax %d\n", L_VSUBAx); + if(L_VSUBAy>0) fprintf(fp, "vsubay %d\n", L_VSUBAy); + if(L_VSUBAz>0) fprintf(fp, "vsubaz %d\n", L_VSUBAz); + if(L_VSUBi>0) fprintf(fp, "vsubi %d\n", L_VSUBi); + if(L_VSUBq>0) fprintf(fp, "vsubq %d\n", L_VSUBq); + if(L_VSUBw>0) fprintf(fp, "vsubw %d\n", L_VSUBw); + if(L_VSUBx>0) fprintf(fp, "vsubx %d\n", L_VSUBx); + if(L_VSUBy>0) fprintf(fp, "vsuby %d\n", L_VSUBy); + if(L_VSUBz>0) fprintf(fp, "vsubz %d\n", L_VSUBz); + if(L_VWAITQ>0) fprintf(fp, "vwaitq %d\n", L_VWAITQ); + + fclose(fp); + +} + + + + + + + + + + + +/***************/ +//R5900 +void LT_SPECIAL() {LT_SpecialPrintTable[_Funct_]();} +void LT_REGIMM() {LT_REGIMMPrintTable[_Rt_](); } +void LT_UnknownOpcode() {} +void LT_ADDI() { L_ADDI++;} +void LT_ADDIU() { L_ADDIU++;} +void LT_DADDI() { L_DADDI++;} +void LT_DADDIU(){ L_DADDIU++;} +void LT_ANDI() { L_ANDI++;} +void LT_ORI() { L_ORI++;} +void LT_XORI() {L_XORI++;} +void LT_SLTI() {L_SLTI++;} +void LT_SLTIU() {L_SLTIU++;} +void LT_ADD() { L_ADD++;} +void LT_ADDU() { L_ADDU++;} +void LT_DADD() { L_DADD++;} +void LT_DADDU() { L_DADDU++;} +void LT_SUB() { L_SUB++;} +void LT_SUBU() { L_SUBU++;} +void LT_DSUB() { L_DSUB++;} +void LT_DSUBU() { L_DSUBU++;} +void LT_AND() { L_AND++;} +void LT_OR() { L_OR++;} +void LT_XOR() { L_XOR++;} +void LT_NOR() { L_NOR++;} +void LT_SLT() { L_SLT++;} +void LT_SLTU() { L_SLTU++;} +void LT_J() { L_J++;} +void LT_JAL() { L_JAL++;} +void LT_JR() { L_JR++;} +void LT_JALR() { L_JALR++;} +void LT_DIV() { L_DIV++;} +void LT_DIVU() { L_DIVU++;} +void LT_MULT() { L_MULT++;} +void LT_MULTU() { L_MULTU++;} +void LT_LUI() { L_LUI++;} +void LT_MFHI() { L_MFHI++;} +void LT_MFLO() { L_MFLO++;} +void LT_MTHI() { L_MTHI++;} +void LT_MTLO() { L_MTLO++;} +void LT_SLL() { L_SLL++;} +void LT_DSLL() { L_DSLL++;} +void LT_DSLL32(){ L_DSLL32++;} +void LT_SRA() { L_SRA++;} +void LT_DSRA() { L_DSRA++;} +void LT_DSRA32(){ L_DSRA32++;} +void LT_SRL() { L_SRL++;} +void LT_DSRL() { L_DSRL++;} +void LT_DSRL32(){ L_DSRL32++;} +void LT_SLLV() { L_SLLV++;} +void LT_SRAV() { L_SRAV++;} +void LT_SRLV() { L_SRLV++;} +void LT_DSLLV() { L_DSLLV++;} +void LT_DSRAV() { L_DSRAV++;} +void LT_DSRLV() { L_DSRLV++;} +void LT_BEQ() { L_BEQ++;} +void LT_BNE() { L_BNE++;} +void LT_BGEZ() { L_BGEZ++;} +void LT_BGEZAL(){ L_BGEZAL++;} +void LT_BGTZ() { L_BGTZ++;} +void LT_BLEZ() { L_BLEZ++;} +void LT_BLTZ() { L_BLTZ++;} +void LT_BLTZAL(){ L_BLTZAL++;} +void LT_BEQL() { L_BEQL++;} +void LT_BNEL() { L_BNEL++;} +void LT_BLEZL() { L_BLEZL++;} +void LT_BGTZL() { L_BGTZL++;} +void LT_BLTZL() { L_BLTZL++;} +void LT_BGEZL() { L_BGEZL++;} +void LT_BLTZALL(){ L_BLTZALL++;} +void LT_BGEZALL(){ L_BGEZALL++;} +void LT_LB() {L_LB++;} +void LT_LBU() {L_LBU++;} +void LT_LH() {L_LH++;} +void LT_LHU() {L_LHU++;} +void LT_LW() {L_LW++;} +void LT_LWU() {L_LWU++;} +void LT_LWL() {L_LWL++;} +void LT_LWR() {L_LWR++;} +void LT_LD() {L_LD++;} +void LT_LDL() {L_LDL++;} +void LT_LDR() {L_LDR++;} +void LT_LQ() {L_LQ++;} +void LT_SB() {L_SB++;} +void LT_SH() {L_SH++;} +void LT_SW() {L_SW++;} +void LT_SWL() {L_SWL++;} +void LT_SWR() {L_SWR++;} +void LT_SD() {L_SD++;} +void LT_SDL() {L_SDL++;} +void LT_SDR() {L_SDR++;} +void LT_SQ() {L_SQ++;} +void LT_MOVZ() {L_MOVZ++;} +void LT_MOVN() {L_MOVN++;} +void LT_SYSCALL() {L_SYSCALL++;} +void LT_BREAK() {L_BREAK++;} +void LT_CACHE() {L_CACHE++;} +void LT_MFSA() {L_MFSA++;} +void LT_MTSA() {L_MTSA++;} +void LT_SYNC() {L_SYNC++;} +void LT_PREF() {L_PREF++;} +void LT_TGE() {L_TGE++;} +void LT_TGEU() {L_TGEU++;} +void LT_TLT() {L_TLT++;} +void LT_TLTU() {L_TLTU++;} +void LT_TEQ() {L_TEQ++;} +void LT_TNE() {L_TNE++;} +void LT_TGEI() {L_TGEI++;} +void LT_TGEIU() {L_TGEIU++;} +void LT_TLTI() {L_TLTI++;} +void LT_TLTIU() {L_TLTIU++;} +void LT_TEQI() {L_TEQI++;} +void LT_TNEI() {L_TNEI++;} +void LT_MTSAB() {L_MTSAB++;} +void LT_MTSAH() {L_MTSAH++;} +//cop0 +void LT_COP0(){ LT_COP0PrintTable[_Rs_]();} +void LT_COP0_BC0() {LT_COP0BC0PrintTable[(cpuRegs.code >> 16) & 0x03]();} +void LT_COP0_Func() { LT_COP0C0PrintTable[_Funct_](); } +void LT_COP0_Unknown() { } +void LT_MFC0() {L_MFC0++;} +void LT_MTC0() {L_MTC0++;} +void LT_BC0F() {L_BC0F++;} +void LT_BC0T() {L_BC0T++;} +void LT_BC0FL(){L_BC0FL++;} +void LT_BC0TL(){L_BC0TL++;} +void LT_TLBR() {L_TLBR++;} +void LT_TLBWI(){L_TLBWI++;} +void LT_TLBWR(){L_TLBWR++;} +void LT_TLBP() {L_TLBP++;} +void LT_ERET() {L_ERET++;} +void LT_DI() {L_DI++;} +void LT_EI() {L_EI++;} +//mmi +void LT_MMI() {LT_MMIPrintTable[_Funct_]();} +void LT_MMI0() {LT_MMI0PrintTable[_Sa_]();} +void LT_MMI1() {LT_MMI1PrintTable[_Sa_]();} +void LT_MMI2() {LT_MMI2PrintTable[_Sa_]();} +void LT_MMI3() {LT_MMI3PrintTable[_Sa_]();} +void LT_MMI_Unknown() {} +void LT_MADD() {L_MADD++;} +void LT_MADDU(){L_MADDU++;} +void LT_PLZCW(){L_PLZCW++;} +void LT_MADD1(){L_MADD1++;} +void LT_MADDU1(){L_MADDU1++;} +void LT_MFHI1(){L_MFHI1++;} +void LT_MTHI1(){L_MTHI1++;} +void LT_MFLO1(){L_MFLO1++;} +void LT_MTLO1(){L_MTLO1++;} +void LT_MULT1(){L_MULT1++;} +void LT_MULTU1(){L_MULTU1++;} +void LT_DIV1(){L_DIV1++;} +void LT_DIVU1(){L_DIVU1++;} +void LT_PMFHL(){L_PMFHL++;} +void LT_PMTHL(){L_PMTHL++;} +void LT_PSLLH(){L_PSLLH++;} +void LT_PSRLH(){L_PSRLH++;} +void LT_PSRAH(){L_PSRAH++;} +void LT_PSLLW(){L_PSLLW++;} +void LT_PSRLW(){L_PSRLW++;} +void LT_PSRAW(){L_PSRAW++;} +void LT_PADDW(){L_PADDW++;} +void LT_PSUBW(){L_PSUBW++;} +void LT_PCGTW(){L_PCGTW++;} +void LT_PMAXW(){L_PMAXW++;} +void LT_PADDH(){L_PADDH++;} +void LT_PSUBH(){L_PSUBH++;} +void LT_PCGTH(){L_PCGTH++;} +void LT_PMAXH(){L_PMAXH++;} +void LT_PADDB(){L_PADDB++;} +void LT_PSUBB(){L_PSUBB++;} +void LT_PCGTB(){L_PCGTB++;} +void LT_PADDSW(){L_PADDSW++;} +void LT_PSUBSW(){L_PSUBSW++;} +void LT_PEXTLW(){L_PEXTLW++;} +void LT_PPACW(){L_PPACW++;} +void LT_PADDSH(){L_PADDSH++;} +void LT_PSUBSH(){L_PSUBSH++;} +void LT_PEXTLH(){L_PEXTLH++;} +void LT_PPACH(){L_PPACH++;} +void LT_PADDSB(){L_PADDSB++;} +void LT_PSUBSB(){L_PSUBSB++;} +void LT_PEXTLB(){L_PEXTLB++;} +void LT_PPACB(){L_PPACB++;} +void LT_PEXT5(){L_PEXT5++;} +void LT_PPAC5(){L_PPAC5++;} +void LT_PABSW(){L_PABSW++;} +void LT_PCEQW(){L_PCEQW++;} +void LT_PMINW(){L_PMINW++;} +void LT_PADSBH(){L_PADSBH++;} +void LT_PABSH(){L_PABSH++;} +void LT_PCEQH(){L_PCEQH++;} +void LT_PMINH(){L_PMINH++;} +void LT_PCEQB(){L_PCEQB++;} +void LT_PADDUW(){L_PADDUW++;} +void LT_PSUBUW(){L_PSUBUW++;} +void LT_PEXTUW(){L_PEXTUW++;} +void LT_PADDUH(){L_PADDUH++;} +void LT_PSUBUH(){L_PSUBUH++;} +void LT_PEXTUH(){L_PEXTUH++;} +void LT_PADDUB(){L_PADDUB++;} +void LT_PSUBUB(){L_PSUBUB++;} +void LT_PEXTUB(){L_PEXTUB++;} +void LT_QFSRV(){L_QFSRV++;} +void LT_PMADDW(){L_PMADDW++;} +void LT_PSLLVW(){L_PSLLVW++;} +void LT_PSRLVW(){L_PSRLVW++;} +void LT_PMSUBW(){L_PMSUBW++;} +void LT_PMFHI(){L_PMFHI++;} +void LT_PMFLO(){L_PMFLO++;} +void LT_PINTH(){L_PINTH++;} +void LT_PMULTW(){L_PMULTW++;} +void LT_PDIVW(){L_PDIVW++;} +void LT_PCPYLD(){L_PCPYLD++;} +void LT_PMADDH(){L_PMADDH++;} +void LT_PHMADH(){L_PHMADH++;} +void LT_PAND(){L_PAND++;} +void LT_PXOR(){L_PXOR++;} +void LT_PMSUBH(){L_PMSUBH++;} +void LT_PHMSBH(){L_PHMSBH++;} +void LT_PEXEH(){L_PEXEH++;} +void LT_PREVH(){L_PREVH++;} +void LT_PMULTH(){L_PMULTH++;} +void LT_PDIVBW(){L_PDIVBW++;} +void LT_PEXEW(){L_PEXEW++;} +void LT_PROT3W(){L_PROT3W++;} +void LT_PMADDUW(){L_PMADDUW++;} +void LT_PSRAVW(){L_PSRAVW++;} +void LT_PMTHI(){L_MTHI++;} +void LT_PMTLO(){L_PMTLO++;} +void LT_PINTEH(){L_PINTEH++;} +void LT_PMULTUW(){L_PMULTUW++;} +void LT_PDIVUW(){L_PDIVUW++;} +void LT_PCPYUD(){L_PCPYUD++;} +void LT_POR(){L_POR++;} +void LT_PNOR(){L_PNOR++;} +void LT_PEXCH(){L_PEXCH++;} +void LT_PCPYH(){L_PCPYH++;} +void LT_PEXCW(){L_PEXCW++;} +//COP1 +void LT_COP1() {LT_COP1PrintTable[_Rs_]();} +void LT_LWC1() {L_LWC1++;} +void LT_SWC1() {L_SWC1++;} +void LT_COP1_BC1() {LT_COP1BC1PrintTable[_Rt_]();} +void LT_COP1_S() {LT_COP1SPrintTable[_Funct_]();} +void LT_COP1_W() {LT_COP1WPrintTable[_Funct_]();} +void LT_COP1_Unknown() {} +void LT_MFC1(){L_MFC1++;} +void LT_CFC1(){L_CFC1++;} +void LT_MTC1(){L_MTC1++;} +void LT_CTC1(){L_CTC1++;} +void LT_BC1F(){L_BC1F++;} +void LT_BC1T(){L_BC1T++;} +void LT_BC1FL(){L_BC1FL++;} +void LT_BC1TL(){L_BC1TL++;} +void LT_ADD_S(){L_ADD_S++;} +void LT_SUB_S(){L_SUB_S++;} +void LT_MUL_S(){L_MUL_S++;} +void LT_DIV_S(){L_DIV_S++;} +void LT_SQRT_S(){L_SQRT_S++;} +void LT_ABS_S(){L_ABS_S++;} +void LT_MOV_S(){L_MOV_S++;} +void LT_NEG_S(){L_NEG_S++;} +void LT_RSQRT_S(){L_RSQRT_S++;} +void LT_ADDA_S(){L_ADDA_S++;} +void LT_SUBA_S(){L_SUBA_S++;} +void LT_MULA_S(){L_MULA_S++;} +void LT_MADD_S(){L_MADD_S++;} +void LT_MSUB_S(){L_MSUB_S++;} +void LT_MADDA_S(){L_MADDA_S++;} +void LT_MSUBA_S(){L_MSUBA_S++;} +void LT_CVT_W(){L_CVT_W++;} +void LT_MAX_S(){L_MAX_S++;} +void LT_MIN_S(){L_MIN_S++;} +void LT_C_F(){L_C_F++;} +void LT_C_EQ(){L_C_EQ++;} +void LT_C_LT(){L_C_LT++;} +void LT_C_LE(){L_C_LE++;} +void LT_CVT_S(){L_CVT_S++;} +//cop2 + +void LT_LQC2() {L_LQC2++;} +void LT_SQC2() {L_SQC2++;} +void LT_COP2() {LT_COP2PrintTable[_Rs_]();} +void LT_COP2_BC2() {LT_COP2BC2PrintTable[_Rt_]();} +void LT_COP2_SPECIAL() { LT_COP2SPECIAL1PrintTable[_Funct_]();} +void LT_COP2_SPECIAL2() {LT_COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]();} +void LT_COP2_Unknown(){} +void LT_QMFC2(){L_QMFC2++;} +void LT_CFC2(){L_CFC2++;} +void LT_QMTC2(){L_QMTC2++;} +void LT_CTC2(){L_CTC2++;} +void LT_BC2F(){L_BC2F++;} +void LT_BC2T(){L_BC2T++;} +void LT_BC2FL(){L_BC2FL++;} +void LT_BC2TL(){L_BC2TL++;} +void LT_VADDx(){L_VADDx++;} +void LT_VADDy(){L_VADDy++;} +void LT_VADDz(){L_VADDz++;} +void LT_VADDw(){L_VADDw++;} +void LT_VSUBx(){L_VSUBx++;} +void LT_VSUBy(){L_VSUBy++;} +void LT_VSUBz(){L_VSUBz++;} +void LT_VSUBw(){L_VSUBw++;} +void LT_VMADDx(){L_VMADDx++;} +void LT_VMADDy(){L_VMADDy++;} +void LT_VMADDz(){L_VMADDz++;} +void LT_VMADDw(){L_VMADDw++;} +void LT_VMSUBx(){L_VMSUBx++;} +void LT_VMSUBy(){L_VMSUBy++;} +void LT_VMSUBz(){L_VMSUBz++;} +void LT_VMSUBw(){L_VMSUBw++;} +void LT_VMAXx(){L_VMAXx++;} +void LT_VMAXy(){L_VMAXy++;} +void LT_VMAXz(){L_VMAXz++;} +void LT_VMAXw(){L_VMAXw++;} +void LT_VMINIx(){L_VMINIx++;} +void LT_VMINIy(){L_VMINIy++;} +void LT_VMINIz(){L_VMINIz++;} +void LT_VMINIw(){L_VMINIw++;} +void LT_VMULx(){L_VMULx++;} +void LT_VMULy(){L_VMULy++;} +void LT_VMULz(){L_VMULz++;} +void LT_VMULw(){L_VMULw++;} +void LT_VMULq(){L_VMULq++;} +void LT_VMAXi(){L_VMAXi++;} +void LT_VMULi(){L_VMULi++;} +void LT_VMINIi(){L_VMINIi++;} +void LT_VADDq(){L_VADDq++;} +void LT_VMADDq(){L_VMADDq++;} +void LT_VADDi(){L_VADDi++;} +void LT_VMADDi(){L_VMADDi++;} +void LT_VSUBq(){L_VSUBq++;} +void LT_VMSUBq(){L_VMSUBq++;} +void LT_VSUBi(){L_VSUBi++;} +void LT_VMSUBi(){L_VMSUBi++;} +void LT_VADD(){L_VADD++;} +void LT_VMADD(){L_VMADD++;} +void LT_VMUL(){L_VMUL++;} +void LT_VMAX(){L_VMAX++;} +void LT_VSUB(){L_VSUB++;} +void LT_VMSUB(){L_VMSUB++;} +void LT_VOPMSUB(){L_VOPMSUB++;} +void LT_VMINI(){L_VMINI++;} +void LT_VIADD(){L_VIADD++;} +void LT_VISUB(){L_VISUB++;} +void LT_VIADDI(){L_VIADDI++;} +void LT_VIAND(){L_VIAND++;} +void LT_VIOR(){L_VIOR++;} +void LT_VCALLMS(){L_VCALLMS++;} +void LT_VCALLMSR(){L_VCALLMSR++;} +void LT_VADDAx(){L_VADDAx++;} +void LT_VADDAy(){L_VADDAy++;} +void LT_VADDAz(){L_VADDAz++;} +void LT_VADDAw(){L_VADDAw++;} +void LT_VSUBAx(){L_VSUBAx++;} +void LT_VSUBAy(){L_VSUBAy++;} +void LT_VSUBAz(){L_VSUBAz++;} +void LT_VSUBAw(){L_VSUBAw++;} +void LT_VMADDAx(){L_VMADDAx++;} +void LT_VMADDAy(){L_VMADDAy++;} +void LT_VMADDAz(){L_VMADDAz++;} +void LT_VMADDAw(){L_VMADDAw++;} +void LT_VMSUBAx(){L_VMSUBAx++;} +void LT_VMSUBAy(){L_VMSUBAy++;} +void LT_VMSUBAz(){L_VMSUBAz++;} +void LT_VMSUBAw(){L_VMSUBAw++;} +void LT_VITOF0(){L_VITOF0++;} +void LT_VITOF4(){L_VITOF4++;} +void LT_VITOF12(){L_VITOF12++;} +void LT_VITOF15(){L_VITOF15++;} +void LT_VFTOI0(){L_VFTOI0++;} +void LT_VFTOI4(){L_VFTOI4++;} +void LT_VFTOI12(){L_VFTOI12++;} +void LT_VFTOI15(){L_VFTOI15++;} +void LT_VMULAx(){L_VMULAx++;} +void LT_VMULAy(){L_VMULAy++;} +void LT_VMULAz(){L_VMULAz++;} +void LT_VMULAw(){L_VMULAw++;} +void LT_VMULAq(){L_VMULAq++;} +void LT_VABS(){L_VABS++;} +void LT_VMULAi(){L_VMULAi++;} +void LT_VCLIPw(){L_VCLIPw++;} +void LT_VADDAq(){L_VADDAq++;} +void LT_VMADDAq(){L_VMADDAq++;} +void LT_VADDAi(){L_VADDAi++;} +void LT_VMADDAi(){L_VMADDAi++;} +void LT_VSUBAq(){L_VSUBAq++;} +void LT_VMSUBAq(){L_VMSUBAq++;} +void LT_VSUBAi(){L_VSUBAi++;} +void LT_VMSUBAi(){L_VMSUBAi++;} +void LT_VADDA(){L_VADDA++;} +void LT_VMADDA(){L_VMADDA++;} +void LT_VMULA(){L_VMULA++;} +void LT_VSUBA(){L_VSUBA++;} +void LT_VMSUBA(){L_VMSUBA++;} +void LT_VOPMULA(){L_VOPMULA++;} +void LT_VNOP(){L_VNOP++;} +void LT_VMOVE(){L_VMOVE++;} +void LT_VMR32(){L_VMR32++;} +void LT_VLQI(){L_VLQI++;} +void LT_VSQI(){L_VSQI++;} +void LT_VLQD(){L_VLQD++;} +void LT_VSQD(){L_VSQD++;} +void LT_VDIV(){L_VDIV++;} +void LT_VSQRT(){L_VSQRT++;} +void LT_VRSQRT(){L_VRSQRT++;} +void LT_VWAITQ(){L_VWAITQ++;} +void LT_VMTIR(){L_VMTIR++;} +void LT_VMFIR(){L_VMFIR++;} +void LT_VILWR(){L_VILWR++;} +void LT_VISWR(){L_VISWR++;} +void LT_VRNEXT(){L_VRNEXT++;} +void LT_VRGET(){L_VRGET++;} +void LT_VRINIT(){L_VRINIT++;} +void LT_VRXOR(){L_VRXOR++;} + +void (*LT_OpcodePrintTable[64])() = +{ + LT_SPECIAL, LT_REGIMM, LT_J, LT_JAL, LT_BEQ, LT_BNE, LT_BLEZ, LT_BGTZ, + LT_ADDI, LT_ADDIU, LT_SLTI, LT_SLTIU, LT_ANDI, LT_ORI, LT_XORI, LT_LUI, + LT_COP0, LT_COP1, LT_COP2, LT_UnknownOpcode, LT_BEQL, LT_BNEL, LT_BLEZL, LT_BGTZL, + LT_DADDI, LT_DADDIU, LT_LDL, LT_LDR, LT_MMI, LT_UnknownOpcode, LT_LQ, LT_SQ, + LT_LB, LT_LH, LT_LWL, LT_LW, LT_LBU, LT_LHU, LT_LWR, LT_LWU, + LT_SB, LT_SH, LT_SWL, LT_SW, LT_SDL, LT_SDR, LT_SWR, LT_CACHE, + LT_UnknownOpcode, LT_LWC1, LT_UnknownOpcode, LT_PREF, LT_UnknownOpcode,LT_UnknownOpcode, LT_LQC2, LT_LD, + LT_UnknownOpcode, LT_SWC1, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode,LT_UnknownOpcode, LT_SQC2, LT_SD +}; + + +void (*LT_SpecialPrintTable[64])() = +{ + LT_SLL, LT_UnknownOpcode, LT_SRL, LT_SRA, LT_SLLV, LT_UnknownOpcode, LT_SRLV, LT_SRAV, + LT_JR, LT_JALR, LT_MOVZ, LT_MOVN, LT_SYSCALL, LT_BREAK, LT_UnknownOpcode, LT_SYNC, + LT_MFHI, LT_MTHI, LT_MFLO, LT_MTLO, LT_DSLLV, LT_UnknownOpcode, LT_DSRLV, LT_DSRAV, + LT_MULT, LT_MULTU, LT_DIV, LT_DIVU, LT_UnknownOpcode,LT_UnknownOpcode,LT_UnknownOpcode,LT_UnknownOpcode, + LT_ADD, LT_ADDU, LT_SUB, LT_SUBU, LT_AND, LT_OR, LT_XOR, LT_NOR, + LT_MFSA , LT_MTSA , LT_SLT, LT_SLTU, LT_DADD, LT_DADDU, LT_DSUB, LT_DSUBU, + LT_TGE, LT_TGEU, LT_TLT, LT_TLTU, LT_TEQ, LT_UnknownOpcode, LT_TNE, LT_UnknownOpcode, + LT_DSLL, LT_UnknownOpcode, LT_DSRL, LT_DSRA, LT_DSLL32, LT_UnknownOpcode, LT_DSRL32, LT_DSRA32 +}; + +void (*LT_REGIMMPrintTable[32])() = { + LT_BLTZ, LT_BGEZ, LT_BLTZL, LT_BGEZL, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, + LT_TGEI, LT_TGEIU, LT_TLTI, LT_TLTIU, LT_TEQI, LT_UnknownOpcode, LT_TNEI, LT_UnknownOpcode, + LT_BLTZAL, LT_BGEZAL, LT_BLTZALL, LT_BGEZALL, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, + LT_MTSAB, LT_MTSAH , LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, LT_UnknownOpcode, +}; +void (*LT_MMIPrintTable[64])() = +{ + LT_MADD, LT_MADDU, LT_MMI_Unknown, LT_MMI_Unknown, LT_PLZCW, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MMI0, LT_MMI2, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MFHI1, LT_MTHI1, LT_MFLO1, LT_MTLO1, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MULT1, LT_MULTU1, LT_DIV1, LT_DIVU1, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MADD1, LT_MADDU1, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MMI1 , LT_MMI3, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_PMFHL, LT_PMTHL, LT_MMI_Unknown, LT_MMI_Unknown, LT_PSLLH, LT_MMI_Unknown, LT_PSRLH, LT_PSRAH, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_PSLLW, LT_MMI_Unknown, LT_PSRLW, LT_PSRAW, +}; + +void (*LT_MMI0PrintTable[32])() = +{ + LT_PADDW, LT_PSUBW, LT_PCGTW, LT_PMAXW, + LT_PADDH, LT_PSUBH, LT_PCGTH, LT_PMAXH, + LT_PADDB, LT_PSUBB, LT_PCGTB, LT_MMI_Unknown, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_PADDSW, LT_PSUBSW, LT_PEXTLW, LT_PPACW, + LT_PADDSH, LT_PSUBSH, LT_PEXTLH, LT_PPACH, + LT_PADDSB, LT_PSUBSB, LT_PEXTLB, LT_PPACB, + LT_MMI_Unknown, LT_MMI_Unknown, LT_PEXT5, LT_PPAC5, +}; + +void (*LT_MMI1PrintTable[32])() = +{ + LT_MMI_Unknown, LT_PABSW, LT_PCEQW, LT_PMINW, + LT_PADSBH, LT_PABSH, LT_PCEQH, LT_PMINH, + LT_MMI_Unknown, LT_MMI_Unknown, LT_PCEQB, LT_MMI_Unknown, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_PADDUW, LT_PSUBUW, LT_PEXTUW, LT_MMI_Unknown, + LT_PADDUH, LT_PSUBUH, LT_PEXTUH, LT_MMI_Unknown, + LT_PADDUB, LT_PSUBUB, LT_PEXTUB, LT_QFSRV, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, +}; + + +void (*LT_MMI2PrintTable[32])() = +{ + LT_PMADDW, LT_MMI_Unknown, LT_PSLLVW, LT_PSRLVW, + LT_PMSUBW, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_PMFHI, LT_PMFLO, LT_PINTH, LT_MMI_Unknown, + LT_PMULTW, LT_PDIVW, LT_PCPYLD, LT_MMI_Unknown, + LT_PMADDH, LT_PHMADH, LT_PAND, LT_PXOR, + LT_PMSUBH, LT_PHMSBH, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MMI_Unknown, LT_MMI_Unknown, LT_PEXEH, LT_PREVH, + LT_PMULTH, LT_PDIVBW, LT_PEXEW, LT_PROT3W, +}; + +void (*LT_MMI3PrintTable[32])() = +{ + LT_PMADDUW, LT_MMI_Unknown, LT_MMI_Unknown, LT_PSRAVW, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_PMTHI, LT_PMTLO, LT_PINTEH, LT_MMI_Unknown, + LT_PMULTUW, LT_PDIVUW, LT_PCPYUD, LT_MMI_Unknown, + LT_MMI_Unknown, LT_MMI_Unknown, LT_POR, LT_PNOR, + LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, LT_MMI_Unknown, + LT_MMI_Unknown, LT_MMI_Unknown, LT_PEXCH, LT_PCPYH, + LT_MMI_Unknown, LT_MMI_Unknown, LT_PEXCW, LT_MMI_Unknown, +}; + +void (*LT_COP0PrintTable[32])() = +{ + LT_MFC0, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_MTC0, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_BC0, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Func, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, +}; + +void (*LT_COP0BC0PrintTable[32])() = +{ + LT_BC0F, LT_BC0T, LT_BC0FL, LT_BC0TL, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, +}; + +void (*LT_COP0C0PrintTable[64])() = { + LT_COP0_Unknown, LT_TLBR, LT_TLBWI, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_TLBWR, LT_COP0_Unknown, + LT_TLBP, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_ERET, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, + LT_EI, LT_DI, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown, LT_COP0_Unknown +}; + + +void (*LT_COP1PrintTable[32])() = { + LT_MFC1, LT_COP1_Unknown, LT_CFC1, LT_COP1_Unknown, LT_MTC1, LT_COP1_Unknown, LT_CTC1, LT_COP1_Unknown, + LT_COP1_BC1, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, + LT_COP1_S, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_W, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, + LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, +}; + +void (*LT_COP1BC1PrintTable[32])() = { + LT_BC1F, LT_BC1T, LT_BC1FL, LT_BC1TL, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, + LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, + LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, + LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, LT_COP1_Unknown, +}; + +void (*LT_COP1SPrintTable[64])() = { +LT_ADD_S, LT_SUB_S, LT_MUL_S, LT_DIV_S, LT_SQRT_S, LT_ABS_S, LT_MOV_S, LT_NEG_S, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_RSQRT_S, LT_COP1_Unknown, +LT_ADDA_S, LT_SUBA_S, LT_MULA_S, LT_COP1_Unknown,LT_MADD_S, LT_MSUB_S, LT_MADDA_S, LT_MSUBA_S, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_CVT_W, LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_MAX_S, LT_MIN_S, LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_C_F, LT_COP1_Unknown,LT_C_EQ, LT_COP1_Unknown,LT_C_LT, LT_COP1_Unknown,LT_C_LE, LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +}; + +void (*LT_COP1WPrintTable[64])() = { +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_CVT_S, LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown,LT_COP1_Unknown, +}; + +void (*LT_COP2PrintTable[32])() = { + LT_COP2_Unknown, LT_QMFC2, LT_CFC2, LT_COP2_Unknown, LT_COP2_Unknown, LT_QMTC2, LT_CTC2, LT_COP2_Unknown, + LT_COP2_BC2, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, + LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, + LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, LT_COP2_SPECIAL, +}; + +void (*LT_COP2BC2PrintTable[32])() = { + LT_BC2F, LT_BC2T, LT_BC2FL, LT_BC2TL, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, + LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, + LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, + LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, LT_COP2_Unknown, +}; + +void (*LT_COP2SPECIAL1PrintTable[64])() = +{ + LT_VADDx, LT_VADDy, LT_VADDz, LT_VADDw, LT_VSUBx, LT_VSUBy, LT_VSUBz, LT_VSUBw, + LT_VMADDx, LT_VMADDy, LT_VMADDz, LT_VMADDw, LT_VMSUBx, LT_VMSUBy, LT_VMSUBz, LT_VMSUBw, + LT_VMAXx, LT_VMAXy, LT_VMAXz, LT_VMAXw, LT_VMINIx, LT_VMINIy, LT_VMINIz, LT_VMINIw, + LT_VMULx, LT_VMULy, LT_VMULz, LT_VMULw, LT_VMULq, LT_VMAXi, LT_VMULi, LT_VMINIi, + LT_VADDq, LT_VMADDq, LT_VADDi, LT_VMADDi, LT_VSUBq, LT_VMSUBq, LT_VSUBi, LT_VMSUBi, + LT_VADD, LT_VMADD, LT_VMUL, LT_VMAX, LT_VSUB, LT_VMSUB, LT_VOPMSUB, LT_VMINI, + LT_VIADD, LT_VISUB, LT_VIADDI, LT_COP2_Unknown,LT_VIAND, LT_VIOR, LT_COP2_Unknown, LT_COP2_Unknown, + LT_VCALLMS, LT_VCALLMSR, LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_SPECIAL2,LT_COP2_SPECIAL2,LT_COP2_SPECIAL2,LT_COP2_SPECIAL2, +}; + +void (*LT_COP2SPECIAL2PrintTable[128])() = +{ + LT_VADDAx ,LT_VADDAy ,LT_VADDAz ,LT_VADDAw ,LT_VSUBAx ,LT_VSUBAy ,LT_VSUBAz ,LT_VSUBAw, + LT_VMADDAx ,LT_VMADDAy ,LT_VMADDAz ,LT_VMADDAw ,LT_VMSUBAx ,LT_VMSUBAy ,LT_VMSUBAz ,LT_VMSUBAw, + LT_VITOF0 ,LT_VITOF4 ,LT_VITOF12 ,LT_VITOF15 ,LT_VFTOI0 ,LT_VFTOI4 ,LT_VFTOI12 ,LT_VFTOI15, + LT_VMULAx ,LT_VMULAy ,LT_VMULAz ,LT_VMULAw ,LT_VMULAq ,LT_VABS ,LT_VMULAi ,LT_VCLIPw, + LT_VADDAq ,LT_VMADDAq ,LT_VADDAi ,LT_VMADDAi ,LT_VSUBAq ,LT_VMSUBAq ,LT_VSUBAi ,LT_VMSUBAi, + LT_VADDA ,LT_VMADDA ,LT_VMULA ,LT_COP2_Unknown,LT_VSUBA ,LT_VMSUBA ,LT_VOPMULA ,LT_VNOP, + LT_VMOVE ,LT_VMR32 ,LT_COP2_Unknown,LT_COP2_Unknown,LT_VLQI ,LT_VSQI ,LT_VLQD ,LT_VSQD, + LT_VDIV ,LT_VSQRT ,LT_VRSQRT ,LT_VWAITQ ,LT_VMTIR ,LT_VMFIR ,LT_VILWR ,LT_VISWR, + LT_VRNEXT ,LT_VRGET ,LT_VRINIT ,LT_VRXOR ,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, + LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown,LT_COP2_Unknown, +}; diff --git a/pcsx2/DebugTools/cpuopsDebug.h b/pcsx2/DebugTools/cpuopsDebug.h new file mode 100644 index 0000000000..ff3cdb251c --- /dev/null +++ b/pcsx2/DebugTools/cpuopsDebug.h @@ -0,0 +1,456 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +void UpdateR5900op(); +extern void (*LT_OpcodePrintTable[64])(); +extern void (*LT_SpecialPrintTable[64])(); +extern void (*LT_REGIMMPrintTable[32])(); +extern void (*LT_MMIPrintTable[64])(); +extern void (*LT_MMI0PrintTable[32])(); +extern void (*LT_MMI1PrintTable[32])(); +extern void (*LT_MMI2PrintTable[32])(); +extern void (*LT_MMI3PrintTable[32])(); +extern void (*LT_COP0PrintTable[32])(); +extern void (*LT_COP0BC0PrintTable[32])(); +extern void (*LT_COP0C0PrintTable[64])(); +extern void (*LT_COP1PrintTable[32])(); +extern void (*LT_COP1BC1PrintTable[32])(); +extern void (*LT_COP1SPrintTable[64])(); +extern void (*LT_COP1WPrintTable[64])(); +extern void (*LT_COP2PrintTable[32])(); +extern void (*LT_COP2BC2PrintTable[32])(); +extern void (*LT_COP2SPECIAL1PrintTable[64])(); +extern void (*LT_COP2SPECIAL2PrintTable[128])(); +// **********************Standard Opcodes************************** +int L_ADD=0; +int L_ADDI=0; +int L_ADDIU=0; +int L_ADDU=0; +int L_AND=0; +int L_ANDI=0; +int L_BEQ=0; +int L_BEQL=0; +int L_BGEZ=0; +int L_BGEZAL=0; +int L_BGEZALL=0; +int L_BGEZL=0; +int L_BGTZ=0; +int L_BGTZL=0; +int L_BLEZ=0; +int L_BLEZL=0; +int L_BLTZ=0; +int L_BLTZAL=0; +int L_BLTZALL=0; +int L_BLTZL=0; +int L_BNE=0; +int L_BNEL=0; +int L_BREAK=0; +int L_CACHE=0; +int L_DADD=0; +int L_DADDI=0; +int L_DADDIU=0; +int L_DADDU=0; +int L_DIV=0; +int L_DIVU=0; +int L_DSLL=0; +int L_DSLL32=0; +int L_DSLLV=0; +int L_DSRA=0; +int L_DSRA32=0; +int L_DSRAV=0; +int L_DSRL=0; +int L_DSRL32=0; +int L_DSRLV=0; +int L_DSUB=0; +int L_DSUBU=0; +int L_J=0; +int L_JAL=0; +int L_JALR=0; +int L_JR=0; +int L_LB=0; +int L_LBU=0; +int L_LD=0; +int L_LDL=0; +int L_LDR=0; +int L_LH=0; +int L_LHU=0; +int L_LQ=0; +int L_LQC2=0; +int L_LUI=0; +int L_LW=0; +int L_LWC1=0; +int L_LWL=0; +int L_LWR=0; +int L_LWU=0; +int L_MFHI=0; +int L_MFLO=0; +int L_MFSA=0; +int L_MOVN=0; +int L_MOVZ=0; +int L_MTHI=0; +int L_MTLO=0; +int L_MTSA=0; +int L_MTSAB=0; +int L_MTSAH=0; +int L_MULT=0; +int L_MULTU=0; +int L_NOR=0; +int L_OR=0; +int L_ORI=0; +int L_PREF=0; +int L_SB=0; +int L_SD=0; +int L_SDL=0; +int L_SDR=0; +int L_SH=0; +int L_SLL=0; +int L_SLLV=0; +int L_SLT=0; +int L_SLTI=0; +int L_SLTIU=0; +int L_SLTU=0; +int L_SQ=0; +int L_SQC2=0; +int L_SRA=0; +int L_SRAV=0; +int L_SRL=0; +int L_SRLV=0; +int L_SUB=0; +int L_SUBU=0; +int L_SW=0; +int L_SWC1=0; +int L_SWL=0; +int L_SWR=0; +int L_SYNC=0; +int L_SYSCALL=0; +int L_TEQ=0; +int L_TEQI=0; +int L_TGE=0; +int L_TGEI=0; +int L_TGEIU=0; +int L_TGEU=0; +int L_TLT=0; +int L_TLTI=0; +int L_TLTIU=0; +int L_TLTU=0; +int L_TNE=0; +int L_TNEI=0; +int L_XOR=0; +int L_XORI=0; + + + + +//*****************MMI OPCODES********************************* +int L_MADD=0; +int L_MADDU=0; +int L_PLZCW=0; +int L_MADD1=0; +int L_MADDU1=0; +int L_MFHI1=0; +int L_MTHI1=0; +int L_MFLO1=0; +int L_MTLO1=0; +int L_MULT1=0; +int L_MULTU1=0; +int L_DIV1=0; +int L_DIVU1=0; +int L_PMFHL=0; +int L_PMTHL=0; +int L_PSLLH=0; +int L_PSRLH=0; +int L_PSRAH=0; +int L_PSLLW=0; +int L_PSRLW=0; +int L_PSRAW=0; +//*****************END OF MMI OPCODES************************** +//*************************MMI0 OPCODES************************ + +int L_PADDW=0; +int L_PSUBW=0; +int L_PCGTW=0; +int L_PMAXW=0; +int L_PADDH=0; +int L_PSUBH=0; +int L_PCGTH=0; +int L_PMAXH=0; +int L_PADDB=0; +int L_PSUBB=0; +int L_PCGTB=0; +int L_PADDSW=0; +int L_PSUBSW=0; +int L_PEXTLW=0; +int L_PPACW=0; +int L_PADDSH=0; +int L_PSUBSH=0; +int L_PEXTLH=0; +int L_PPACH=0; +int L_PADDSB=0; +int L_PSUBSB=0; +int L_PEXTLB=0; +int L_PPACB=0; +int L_PEXT5=0; +int L_PPAC5=0; +//***END OF MMI0 OPCODES****************************************** +//**********MMI1 OPCODES************************************** +int L_PABSW=0; +int L_PCEQW=0; +int L_PMINW=0; +int L_PADSBH=0; +int L_PABSH=0; +int L_PCEQH=0; +int L_PMINH=0; +int L_PCEQB=0; +int L_PADDUW=0; +int L_PSUBUW=0; +int L_PEXTUW=0; +int L_PADDUH=0; +int L_PSUBUH=0; +int L_PEXTUH=0; +int L_PADDUB=0; +int L_PSUBUB=0; +int L_PEXTUB=0; +int L_QFSRV=0; +//********END OF MMI1 OPCODES*********************************** +//*********MMI2 OPCODES*************************************** +int L_PMADDW=0; +int L_PSLLVW=0; +int L_PSRLVW=0; +int L_PMSUBW=0; +int L_PMFHI=0; +int L_PMFLO=0; +int L_PINTH=0; +int L_PMULTW=0; +int L_PDIVW=0; +int L_PCPYLD=0; +int L_PMADDH=0; +int L_PHMADH=0; +int L_PAND=0; +int L_PXOR=0; +int L_PMSUBH=0; +int L_PHMSBH=0; +int L_PEXEH=0; +int L_PREVH=0; +int L_PMULTH=0; +int L_PDIVBW=0; +int L_PEXEW=0; +int L_PROT3W=0; +//*****END OF MMI2 OPCODES*********************************** +//*************************MMI3 OPCODES************************ +int L_PMADDUW=0; +int L_PSRAVW=0; +int L_PMTHI=0; +int L_PMTLO=0; +int L_PINTEH=0; +int L_PMULTUW=0; +int L_PDIVUW=0; +int L_PCPYUD=0; +int L_POR=0; +int L_PNOR=0; +int L_PEXCH=0; +int L_PCPYH=0; +int L_PEXCW=0; +//**********************END OF MMI3 OPCODES******************** +//**************************************************************************** +//** COP0 ** +//**************************************************************************** +int L_MFC0=0; +int L_MTC0=0; +int L_BC0F=0; +int L_BC0T=0; +int L_BC0FL=0; +int L_BC0TL=0; +int L_TLBR=0; +int L_TLBWI=0; +int L_TLBWR=0; +int L_TLBP=0; +int L_ERET=0; +int L_DI=0; +int L_EI=0; +//**************************************************************************** +//** END OF COP0 ** +//**************************************************************************** +//**************************************************************************** +//** COP1 - Floating Point Unit (FPU) ** +//**************************************************************************** +int L_MFC1=0; +int L_CFC1=0; +int L_MTC1=0; +int L_CTC1=0; +int L_BC1F=0; +int L_BC1T=0; +int L_BC1FL=0; +int L_BC1TL=0; +int L_ADD_S=0; +int L_SUB_S=0; +int L_MUL_S=0; +int L_DIV_S=0; +int L_SQRT_S=0; +int L_ABS_S=0; +int L_MOV_S=0; +int L_NEG_S=0; +int L_RSQRT_S=0; +int L_ADDA_S=0; +int L_SUBA_S=0; +int L_MULA_S=0; +int L_MADD_S=0; +int L_MSUB_S=0; +int L_MADDA_S=0; +int L_MSUBA_S=0; +int L_CVT_W=0; +int L_MAX_S=0; +int L_MIN_S=0; +int L_C_F=0; +int L_C_EQ=0; +int L_C_LT=0; +int L_C_LE=0; + int L_CVT_S=0; +//**************************************************************************** +//** END OF COP1 ** +//**************************************************************************** +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +int L_QMFC2=0; +int L_CFC2=0; +int L_QMTC2=0; +int L_CTC2=0; +int L_BC2F=0; +int L_BC2T=0; +int L_BC2FL=0; +int L_BC2TL=0; +int L_VADDx=0; +int L_VADDy=0; +int L_VADDz=0; +int L_VADDw=0; +int L_VSUBx=0; +int L_VSUBy=0; +int L_VSUBz=0; +int L_VSUBw=0; +int L_VMADDx=0; +int L_VMADDy=0; +int L_VMADDz=0; +int L_VMADDw=0; +int L_VMSUBx=0; +int L_VMSUBy=0; +int L_VMSUBz=0; +int L_VMSUBw=0; +int L_VMAXx=0; +int L_VMAXy=0; +int L_VMAXz=0; +int L_VMAXw=0; +int L_VMINIx=0; +int L_VMINIy=0; +int L_VMINIz=0; +int L_VMINIw=0; +int L_VMULx=0; +int L_VMULy=0; +int L_VMULz=0; +int L_VMULw=0; +int L_VMULq=0; +int L_VMAXi=0; +int L_VMULi=0; +int L_VMINIi=0; +int L_VADDq=0; +int L_VMADDq=0; +int L_VADDi=0; +int L_VMADDi=0; +int L_VSUBq=0; +int L_VMSUBq=0; +int L_VSUBi=0; +int L_VMSUBi=0; +int L_VADD=0; +int L_VMADD=0; +int L_VMUL=0; +int L_VMAX=0; +int L_VSUB=0; +int L_VMSUB=0; +int L_VOPMSUB=0; +int L_VMINI=0; +int L_VIADD=0; +int L_VISUB=0; +int L_VIADDI=0; +int L_VIAND=0; +int L_VIOR=0; +int L_VCALLMS=0; +int L_VCALLMSR=0; +int L_VADDAx=0; +int L_VADDAy=0; +int L_VADDAz=0; +int L_VADDAw=0; +int L_VSUBAx=0; +int L_VSUBAy=0; +int L_VSUBAz=0; +int L_VSUBAw=0; +int L_VMADDAx=0; +int L_VMADDAy=0; +int L_VMADDAz=0; +int L_VMADDAw=0; +int L_VMSUBAx=0; +int L_VMSUBAy=0; +int L_VMSUBAz=0; +int L_VMSUBAw=0; +int L_VITOF0=0; +int L_VITOF4=0; +int L_VITOF12=0; +int L_VITOF15=0; +int L_VFTOI0=0; +int L_VFTOI4=0; +int L_VFTOI12=0; +int L_VFTOI15=0; +int L_VMULAx=0; +int L_VMULAy=0; +int L_VMULAz=0; +int L_VMULAw=0; +int L_VMULAq=0; +int L_VABS=0; +int L_VMULAi=0; +int L_VCLIPw=0; +int L_VADDAq=0; +int L_VMADDAq=0; +int L_VADDAi=0; +int L_VMADDAi=0; +int L_VSUBAq=0; +int L_VMSUBAq=0; +int L_VSUBAi=0; +int L_VMSUBAi=0; +int L_VADDA=0; +int L_VMADDA=0; +int L_VMULA=0; +int L_VSUBA=0; +int L_VMSUBA=0; +int L_VOPMULA=0; +int L_VNOP=0; +int L_VMOVE=0; +int L_VMR32=0; +int L_VLQI=0; +int L_VSQI=0; +int L_VLQD=0; +int L_VSQD=0; +int L_VDIV=0; +int L_VSQRT=0; +int L_VRSQRT=0; +int L_VWAITQ=0; +int L_VMTIR=0; +int L_VMFIR=0; +int L_VILWR=0; +int L_VISWR=0; +int L_VRNEXT=0; +int L_VRGET=0; +int L_VRINIT=0; +int L_VRXOR=0; diff --git a/pcsx2/Decode_XA.c b/pcsx2/Decode_XA.c new file mode 100644 index 0000000000..f75d5ac4ff --- /dev/null +++ b/pcsx2/Decode_XA.c @@ -0,0 +1,322 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ +//=== Modified by linuzappz +//============================================ + +#include + +#include "Decode_XA.h" + +#ifdef __WIN32__ +#pragma warning(disable:4244) +#endif + +typedef unsigned char U8; +typedef unsigned short U16; +typedef unsigned long U32; + +#define NOT(_X_) (!(_X_)) +#define CLAMP(_X_,_MI_,_MA_) {if(_X_<_MI_)_X_=_MI_;if(_X_>_MA_)_X_=_MA_;} + +//============================================ +//=== ADPCM DECODING ROUTINES +//============================================ + +static double K0[4] = { + 0.0, + 0.9375, + 1.796875, + 1.53125 +}; + +static double K1[4] = { + 0.0, + 0.0, + -0.8125, + -0.859375 +}; + +#define BLKSIZ 28 /* block size (32 - 4 nibbles) */ + +//=========================================== +void ADPCM_InitDecode( ADPCM_Decode_t *decp ) +{ + decp->y0 = 0; + decp->y1 = 0; +} + +//=========================================== +#define SH 4 +#define SHC 10 + +#define IK0(fid) ((int)((-K0[fid]) * (1<> 4) & 0x0f; + range = (filter_range >> 0) & 0x0f; + + fy0 = decp->y0; + fy1 = decp->y1; + + for (i = BLKSIZ/4; i; --i) { + long y; + long x0, x1, x2, x3; + + y = *blockp++; + x3 = (short)( y & 0xf000) >> range; x3 <<= SH; + x2 = (short)((y << 4) & 0xf000) >> range; x2 <<= SH; + x1 = (short)((y << 8) & 0xf000) >> range; x1 <<= SH; + x0 = (short)((y << 12) & 0xf000) >> range; x0 <<= SH; + + x0 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x0; + x1 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x1; + x2 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x2; + x3 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x3; + + CLAMP( x0, -32768<> SH; destp += inc; + CLAMP( x1, -32768<> SH; destp += inc; + CLAMP( x2, -32768<> SH; destp += inc; + CLAMP( x3, -32768<> SH; destp += inc; + } + decp->y0 = fy0; + decp->y1 = fy1; +} + +static int headtable[4] = {0,2,8,10}; + +//=========================================== +static void xa_decode_data( xa_decode_t *xdp, unsigned char *srcp ) { + const U8 *sound_groupsp; + const U8 *sound_datap, *sound_datap2; + int i, j, k, nbits; + U16 data[4096], *datap; + short *destp; + + destp = xdp->pcm; + nbits = xdp->nbits == 4 ? 4 : 2; + + if (xdp->stereo) { // stereo + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | + ((U16)(sound_datap2[ 4] & 0x0f) << 4) | + ((U16)(sound_datap2[ 8] & 0x0f) << 8) | + ((U16)(sound_datap2[12] & 0x0f) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp+0, 2 ); + + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] >> 4) | + ((U16)(sound_datap2[ 4] >> 4) << 4) | + ((U16)(sound_datap2[ 8] >> 4) << 8) | + ((U16)(sound_datap2[12] >> 4) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->right, sound_groupsp[headtable[i]+1], data, + destp+1, 2 ); + + destp += 28*2; + } + } + } + else { // mono + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | + ((U16)(sound_datap2[ 4] & 0x0f) << 4) | + ((U16)(sound_datap2[ 8] & 0x0f) << 8) | + ((U16)(sound_datap2[12] & 0x0f) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp, 1 ); + + destp += 28; + + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] >> 4) | + ((U16)(sound_datap2[ 4] >> 4) << 4) | + ((U16)(sound_datap2[ 8] >> 4) << 8) | + ((U16)(sound_datap2[12] >> 4) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+1], data, + destp, 1 ); + + destp += 28; + } + } + } +} + +//============================================ +//=== XA SPECIFIC ROUTINES +//============================================ +typedef struct { +U8 filenum; +U8 channum; +U8 submode; +U8 coding; + +U8 filenum2; +U8 channum2; +U8 submode2; +U8 coding2; +} xa_subheader_t; + +#define SUB_SUB_EOF (1<<7) // end of file +#define SUB_SUB_RT (1<<6) // real-time sector +#define SUB_SUB_FORM (1<<5) // 0 form1 1 form2 +#define SUB_SUB_TRIGGER (1<<4) // used for interrupt +#define SUB_SUB_DATA (1<<3) // contains data +#define SUB_SUB_AUDIO (1<<2) // contains audio +#define SUB_SUB_VIDEO (1<<1) // contains video +#define SUB_SUB_EOR (1<<0) // end of record + +#define AUDIO_CODING_GET_STEREO(_X_) ( (_X_) & 3) +#define AUDIO_CODING_GET_FREQ(_X_) (((_X_) >> 2) & 3) +#define AUDIO_CODING_GET_BPS(_X_) (((_X_) >> 4) & 3) +#define AUDIO_CODING_GET_EMPHASIS(_X_) (((_X_) >> 6) & 1) + +#define SUB_UNKNOWN 0 +#define SUB_VIDEO 1 +#define SUB_AUDIO 2 + +//============================================ +static int parse_xa_audio_sector( xa_decode_t *xdp, + xa_subheader_t *subheadp, + unsigned char *sectorp, + int is_first_sector ) { + if ( is_first_sector ) { + switch ( AUDIO_CODING_GET_FREQ(subheadp->coding) ) { + case 0: xdp->freq = 37800; break; + case 1: xdp->freq = 18900; break; + default: xdp->freq = 0; break; + } + switch ( AUDIO_CODING_GET_BPS(subheadp->coding) ) { + case 0: xdp->nbits = 4; break; + case 1: xdp->nbits = 8; break; + default: xdp->nbits = 0; break; + } + switch ( AUDIO_CODING_GET_STEREO(subheadp->coding) ) { + case 0: xdp->stereo = 0; break; + case 1: xdp->stereo = 1; break; + default: xdp->stereo = 0; break; + } + + if ( xdp->freq == 0 ) + return -1; + + ADPCM_InitDecode( &xdp->left ); + ADPCM_InitDecode( &xdp->right ); + + xdp->nsamples = 18 * 28 * 8; + if (xdp->stereo == 1) xdp->nsamples /= 2; + } + xa_decode_data( xdp, sectorp ); + + return 0; +} + +//================================================================ +//=== THIS IS WHAT YOU HAVE TO CALL +//=== xdp - structure were all important data are returned +//=== sectorp - data in input +//=== pcmp - data in output +//=== is_first_sector - 1 if it's the 1st sector of the stream +//=== - 0 for any other successive sector +//=== return -1 if error +//================================================================ +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, int is_first_sector ) { + if (parse_xa_audio_sector(xdp, (xa_subheader_t *)sectorp, sectorp + sizeof(xa_subheader_t), is_first_sector)) + return -1; + + return 0; +} + +/* EXAMPLE: +"nsamples" is the number of 16 bit samples +every sample is 2 bytes in mono and 4 bytes in stereo + +xa_decode_t xa; + + sectorp = read_first_sector(); + xa_decode_sector( &xa, sectorp, 1 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + + while ( --n_sectors ) + { + sectorp = read_next_sector(); + xa_decode_sector( &xa, sectorp, 0 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + } +*/ diff --git a/pcsx2/Decode_XA.h b/pcsx2/Decode_XA.h new file mode 100644 index 0000000000..40262f205d --- /dev/null +++ b/pcsx2/Decode_XA.h @@ -0,0 +1,43 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ + +#ifndef DECODEXA_H +#define DECODEXA_H + +typedef struct { + long y0, y1; +} ADPCM_Decode_t; + +typedef struct { + int freq; + int nbits; + int stereo; + int nsamples; + ADPCM_Decode_t left, right; + short pcm[16384]; +} xa_decode_t; + +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, + int is_first_sector ); + +#endif diff --git a/pcsx2/Docs/ChangeLog.txt b/pcsx2/Docs/ChangeLog.txt new file mode 100644 index 0000000000..b8c4bd15e5 --- /dev/null +++ b/pcsx2/Docs/ChangeLog.txt @@ -0,0 +1,2851 @@ +[ Legend: ] +[ + Added feature ] +[ * Improved/changed feature ] +[ - Bug fixed (we hope) ] +[ ! Attention (Notes) ] +[ M Maintenance ] +[ dates are dd/mm/yyyy !!! ] + +ChangeLog: + v0.9.3: + * 26/11/06 [*] Version 0.9.3 started :) + (Refraction) + v0.9.2: + * 30/10/06:[*] Improved the way Unpacks are handled slightly, just so its a little quicker (not much) + [-] MMI bug causing corrupt characters on Max Payne fixed + [-] Performance counters corrected in INT and REC + [-] Branches in a branch delay slot no longer results in a crash + [*] Changed Run CD to Run CD/DVD, ps2 doesnt use CD's much :P + [*] Removed "Advanced" from the menu, not required anymore (at the moment) + [-] Small alteration to IPU transfers, ending the transfer too quickly + [-] Made a seperate branchtest for INT, fixed the VU not running on the bios in INT + (Refraction - Zerofrog) + + * 16/10/06:[-] Counter bugz again, seemed to effect the text in xmen + [-] Fixed an ipu bug which stopped the GTA San Andreas videos working + [-] couple more smaller unpack changes to remove a hack + (Refraction) + + * 15/10/06:[*] Moved some declarations from patch.c to patch.h + [-] Fixed problem with XML patch loading (see above). + [+] Merged my WIP cheat finder dialog (note WIP). + (Gigaherz) + + * 11/10/06:[+] Added XML Patch support + [-] More unpack fixes for GT3/GT4, Xmen, Midnight Club 2, FFX sky, Whiplash and more :) + (Refraction - Gigaherz) + + * 05/10/06:[-] Fixed VIF Unpack skipping write cycle counting (Fixes XMen 2 amongst other SPS) + [-] Small counter change, am i ever going to get peace from these :( + (Refraction) + + * 03/10/06:[-] Fixed MFIFO issue where VIF/GIF might not be ready + [*] Improved Guitar Hero fix, seems MFIFO isnt too keen on sliced transfers (especially on GIF) + [*] Modified VS2005 Project file so it compiles - Thanks to CKemu for doing that :P + (Refraction - CKemu) + + * 02/10/06:[*] Various changes in cdvd.c. Most notable is the implementation of cdvd.PwOff. + It is actualy INTR_STAT and has "completition" bits that are Ack'ed by cdvdman interrupt handler. + ...to be continued. + (Florin) + + * 30/09/06:[*] Corrected performance counter register reads on COP0 (3 regs are accessed by 1) - Lego Racers 2 + [-] Altered the order DIV on IOP rec handles signs - Lego Racers 2 + (Refraction) + + * 29/09/06:[-] Fixed condition where MFIFO could get ahead of itself/not have enough data available + (fixes Guitar Hero) + [-] Fixed up DMA Stalls between VIF/IPU/GIF, games such as Theme Park World should work properly now. + [+] Added cpu detection for Dual core Opterons, Athlon X2's and Intel Core 2 Duo's (no perf effect) + [+] Added saqibs sound changes so ADMA and ADPCM streams work. + [-] Yes, more counter fixes, fed up of these :P + [-] DMA transfers fixed when a QWC is already given, it transfers the QWC then ends (Fixes Ridge Racer 5 a bit) + [-] Small GSCSR changes, not sure what will be fixed. + [-] Event where the DMA could be terminated during a stall on VIF + [-] Various Rec + MTGS + IPU Fixes + (Refraction - Saqib - ZeroFrog) + + * 25/07/06:[-] Changed Vif0 COL/ROW mem write addresses, they were going to the same QW + [*] Made Vif stalls use cycles to delay, due to the spiderman fix we dont want these interrupting instantly! + (fixes Flatout BIFCO) + [-] Call/Ret now update the ASR status in the CHCR register + [-] Couple of small fixes to Tag BUSERR, altho i hope we never need them :P + [+] Added seperate EE counter logging + (Refraction) + +v0.9.1: + * 28/06/06:[+] MAJOR CHANGE: All recompilers and memory code rewritten. + eeRec now does block analysis, constant propagation, liveness + analysis, mmx/xmm reg caching, etc. + vuRec is about 10x faster than older vurec. Both VU0 and + VU1 recs work and share the same code. + iopRec - does same as eeRec, except is simpler + Altogether, 3D scenes are 2-4x faster than 0.9 release. + (zerofrog) + * 09/05/06:[*] Moved repository to SVN. Play nice. Any questions... you know where to find me + [+] new developer blogs from me and auMatt + (Florin-auMatt) + + * 05/05/06:[*] Changed names of the SSBUS registers in PsxHw.c + [!] dev1 is rom bus, dev5 is cdvd bus, dev9 is ata|smap|dvr|uart|flash bus + (Florin) + + * 04/05/06:[+] Added atad and dev9 functions names to psxinterpreter.c + (Florin) + + * 01/05/06:[+] Added *pass-through* MagicGate support. It will work with pre-decrypted files + (Florin) + + * 30/04/06:[-] Fixed (almost:P) the debug bios for remote debugging in WinMain.c + [*] Added PSX detection in Misc.c + [+] Added DevBlog.txt file to Docs. Please read and contribute. + (Florin) + + * 15/04/06:[M] Removed some *shit*; please don't commit *.suo/aps/opt/plg/ncb/exp files + [*] added/fixed some scmd commands in cdvd.c + (Florin) + + * 13/04/06:[*] Implemented CDVD Scmd 0x3E(set OSDVER for PSTwo), Thanks to loser for info. + (auMatt) + + * 12/04/06:[!] Uploaded to CVS the latest version, (fixed vc2005 project, + converted all files to CR/LF ending) + [!] When commiting to CVS, please write same text to comment as in here + [*] Changed the _MSC_VER version displaying; hoping ms will keep it linear :) + [*] Implemented properly CDVD Scmd 0x36 (get OSDVER for PStwo) + (Florin) + + * 10/04/06:[!] Changed to version 0.9.1 + [-] Fixed some Vif FIFO bugs and moved VIF interrupt to check the channel has ended + [-] Fixed some counter bugs (better now i can test on my ps2!) + [!] This code is not perfectly stable and contains debug printouts! It is purely for the other + devs who dont have the latest code ;) + (Refraction) + + v0.9: + * 02/04/06:[+] VU0 Rec added, still buggy + [*] VU1 Speedups and fixes, needs more testing but seems better + [*] CDVD Timing Improved wait times for commands reduced. + [-] Misc eeRec bug fixes made + [*] Vif stalls greatly improved loads more games now work! + [*] Counters modified with gates and improved accuracy + [*] Cycle counting in EE/IOP done on branches to cut download + 2D speed up by over double! + [-] Misc VIF unpack fixes + [-] GIF Stalls should now work correctly + [+] Virtual Memory for Windows XP users, quicker than TLB + [*] Difference CPU options can be mixed and matched by users choice + [-] SIF communication fixed, games can now be booted via the bios (in most cases) + [!] Lots of other fixes have been made by due to lazyness we didnt document! :D + [+] MTGS and Dual Core modes added which are VERY experimental! + [!] This is the FINAL code for 0.9 enjoy! + (Refraction, ZeroFrog, Saqib) + * 15/02/06:[+] Multithreaded GS/Dual Core Support + (zerofrog) + * 17/01/06:[-] Some changes in CDVD tray status + (efp) + + * 16/01/06:[-] Fixed sticky flags. + [*] Implemented/Fixed a lot of vu functions in vurec. VuRec now properly checks for underflow/overflow + (zerofrog) + * 15/01/06:[-] Bug fixes in VU rec/interp (Ebit, xgkick). Added 24bit precision for VUs. + [*] Changed all math functions to use the C++ floating point versions. + (zerofrog) + * 14/01/06:[-] VU Flag fixes + double removal (it needed doing) from zerofrog + [-] Disabled an old PSX Counter hack that i left in some how! + [*] Changed SIF reg code to something simpler and less time consuming + (Refraction) + * 13/01/06:[*] Fixed mac update flags for vu interpreter. + (zerofrog) + + * 12/01/06:[-] Changed IPU.c, thread syncing issue fixed by zerofrog + [*] Altered SBUS so it is triggered on PSX dma + [*] Removed a load of IOP hacks, should improve compatability in some cases + [!] A lot of changes have been made since 05/09/05 but weve lost track, whoops + (Refraction Saqib zerofrog) + + * 05/01/06:[*] Added GSreadFIFO2 for faster reads from GS. + [-] Fixed the multi-threaded IPU and added sync primitives for interrupts and DMA. + The green squares should be gone too. + (zerofrog) + + * 05/09/05:[-] Fixed VU-Rec crash if the pc overflowed the vumem, thanks to fumofumo! + [*] New Icon for 0.9 made by CKemu + [+] Vsync rate now selectable, current Vsync speed is default but less compatable in + some cases, option selects real vsync speed, syncs sound correctly. + (Refraction) + + * 03/09/05:[-] IOP rec & VU0rec fix, x86ptr being set in the wrong place, also a couple of vu-rec op fixes + thanks to fumofumo on irc. + [-] Slowed VSync down to actual speed, so sound isnt half the speed of the graphics, + a few more changes to counters as well, BOR works again, just slower ;p + (Refraction) + + * 30/08/05:[-] Few more changes to the counters, seems much better again, last fix killed stuff + [-] VSync rate now actually changes between PAL and NTSC, before it was stuck in NTSC + [-] Couple of changes in VIF + * 24/08/05:[-] Readded setting of Done on VIF1 TTE, added the same on VIF0 + [-] Applied VIF1 FBRST fix to VIF0 too + [-] Fixed problem causing Beats Of Rage to skip and altered slow sound prob again. + (Refraction) + + * 23/08/05:[-] Did some more timing fixes, they should be a LOT more compatable now + [-] Small change to FBRST, was causing crashes if VIF was finished. + [+] Added counter copy to hold on SBUS interrupt + (Refraction) + + * 21/08/05:[-] Few fixes in the eeRec, shouldnt crash on Kingdom Hearts now, Thanks to fumofumo! + [-] Fixed a bug in FBRST and Vif1, altho theres still an interrupting problem somewhere :/ + [-] Int VU now uses Single Precision (its faster) with no loss of graphics. + [-] Made sure MAC, CLIP and STATUS flags are all located on VU0. + [*] Enabled linuz's SSE unpack code, gives a nice little speed boost, works ok :) + [-] VU execute blocks limited to 128, seems a little faster, no loss of graphics, seems + to fix a few looping infinately issues (VU not breaking) (GiGaHeRz) + [-] Hack removed on TLBP, should hopefully work ok, doesnt seem to break anything (GiGaHeRz) + [+] Added SPU2 hack, should fix some games, not compatable with videos tho. removed fast dvd + [-] More counter stuff, also added gating to IOP counters, not totally sure on it. + [-] Added a couple of checks in VU & eeRec to make sure the constant registers werent overwritten + [-] Temp fix for the dma alignment error on GIF + [-] modified dma timings, qwc / BIAS could mess up if qwc = 1 + [-] Singled out some problematic VU-Rec ops that cause FFX to hang and borkey graphics. + (Refraction) + + * 12/08/05:[*] Few more timing things, music shouldnt be slow anymore on games and cleaned up + counters a bit. + [+] Added SBUS register logging on IOP side + [-] Temp fixed a MAC flag problem in vu-rec till linuz sorts it properly + [*] Committed new logo, nice job CKEmu ;) + [*] Vu-Rec now supports non SSE2 processors thanks to kekko for the changes! + (refraction) + + * 05/08/05:[+] Added faster Cd/DVD reads to the Advanced options (Refraction) + [-] The previous DVD/CD change by ref was just a hack, so i commited the old + version again + [-] I've commented out RECOMPILE_VUMI_LOADSTORE on iVUmicro.h, instead + of commenting it out in iVU1micro.c as ref did on last update, + that way is better until i fix the real problem + [*] Improved vuDIV for .x to .x cases + [+] Added PEXTRW/PINSRW + (linuzappz) + + * 05/08/05:[-] Fixed a couple of VU-Rec ops, swapped some over to the interpreter to fix 2d + (thanks to fumofumo for the tipoff) + [-] Yes more timing stuff :P think its as compatable as its going to get now. + [*] DVD/CD reads now considerably faster, some loading times down by 1600%!!! + Compatability still good :) + [-] Fixed a bug in 128bit hardware reads + [-] Fixed a bug i made in VU which messed graphics up eg Frequency and Sega Tennis + (refraction) + + * 04/08/05:[-] More IOP/EE timing fixes, Thanks for the info linuz + [-] Vsync speeds shouldnt be as insane as they were, the target was set as 1/4 the rate + instead of 1/2! + [!] 32bit timer interrupt checks arent working properly eg. overflow only works + when checking if they are equal, on target only works on overflow :/ but the checking + method which was used in SafeIOP is more accurate. + (refraction) + + * 03/08/05:[-] Fixed FTOX in VUrec + (linuzappz) + + * 31/07/05:[-] Reverted to old Branchtarget's, seems to stop the RecUNKs + [-] Fixed the timing a bit between IOP & EE, shouldn't need SafeIOP anymore :D + [-] Removed Pointless While loops on GIF & SPR, also fixed condition where SPR0 + couldn't use destination chain mode + [!] Gating on the IOP needs checking/completing, i have no docs on it so + i can't check the values for it, they seem different to EE :/ + [-] Removed GS Stall checking on GIF, could have caused it not to send data. + [*] Added code for faster V4-32 unpacks when CL == WL + [*] x86 code kept in int format for rec instead of U8 to INT conversion (GiGaHeRz) + (refraction) + + * 21/07/05:[-] Fixed setting of the Double Buffer + [-] Fixed the Branchtarget's for R3000A and R5900 + [*] Altered some stuff in vuflags, seems to give a speed boost :P + (refraction) + + * 18/07/05:[-] Removed some useless & 0xffff on Hw.c + [-] Reverted Sif changes to the old code, + gotta speak about this with refraction + [+] Added VIF1_STAT at vif1Write32, to handled the FDR bit + [-] VIF1 now clears qwc with "from memory" transfer + (linuzappz) + + * 17/07/05:[-] Fixed a bug in VIF where done could be unset + [-] Fixed a couple of bugs in VU + [*] Rewrote SIF0, seems to be a bit more compatable as well + as more readable + [-] Altered the loops for vu(1/0)exec, seems to fix some graphics + without comprimising compatability + (refraction) + + * 12/07/05:[-] Fixed VIF stop on stall occurance (refraction) + [-] Added two common funcs for source chain dmas + [-] Fixed REFE and END (even once again) in dmas + [-] Fixed interrupt i bit issue in Vif1 (on multiple i bits) + (linuzappz) + + * 08/07/05:[-] MFIFO now wraps around the ring buffer when it's full, + in both GIF/VIF1 + (linuzappz) + + * 06/07/05:[-] Bug in DIRECT/HL caused vif errors + [-] Recomitted old VIF0 IRQ stuff, seemed to cause problems + (Refraction) + + * 05/07/05:[-] Fixed IRQ setting for VIF0 transfers (Refraction) + [*] Removed Call/Ret from SPR1, not used (Refraction) + [+] Added some more comments to DMA stuff (Refraction) + [-] Reimplemented the old vifunpack code, since saqib's one + had problems 'in pieces' transfers + [-] ElfHeader now loads the data though the program headers only + [-] Removed tadr+= 16 on refe/end on dmas + [!] I'll start commenting more the code from now on, so it'll + be easier for us to understand every part of pcsx2, others + pls do the same kthx + (Refraction-linuzappz) + + * 02/07/05:[-] Added saqib vif fixes + [-] Fixed Stall canceling stat bits (VIF_STAT_INT) + [-] Fixed Stall bits clearing + (Refraction-saqib-linuzappz) + + * 29/06/05:[*] iR3000A now has defines same as iR5900.c + [+] Added PSXCNT_LOG + (linuzappz) + + * 28/06/05:[+] Added InterlaceHack (usefull for Dinasty Warriors 3) + [+] Added SafeCnts flag, which makes very accurate iop counters, + but they make pcsx2 slower + [+] Added FastIopClk which sets the PsxClk to 86864000 + [!] There are sorta hacks and will go away in time when i figure + out how to really fix them + (linuzappz) + + * 28/06/05:[+] Added SIO plugin specs. Should be followed by compatible plugins :P + (Florin) + + * 22/06/05:[-] Console supports colors ;) + (linuzappz) + + * 19/06/05:[-] Fixed D/T flags (added interrupts) at VU0/1 + (linuzappz) + + * 18/06/05:[-] Rather small fixes to last update in vif, replaced cyclenum + with _vif->cl, also fixed a timing issue in vif0 + (linuzappz) + + * 14/06/05:[-] Alot of bugs fixed in VIF. Masking was not correct so was + filling write. VIF0 was incorrect. The VIF0 Fifo was always being set to 0. + [-] dmaSPR1 now handles Transfer Tag option. + (saqib and Refraction) + + * 31/05/05:[-] Fixed UNPACK's with masking + (linuzappz) + + * 29/05/05:[-] Fixed a few small timing issues with VIF1 + [-] Refixed end source chain tag to add 16 to tadr + (linuzappz) + + * 28/05/05:[*] Uncommented GS dma irq code + [-] Fixed some switch cases at iVUmicro.c + [-] Tested/Fixed DIS_S/MAX_S/MIN_S at iFPU.c + (linuzappz) + + * 28/05/05:[*] removed CVT_S regcaching from iFPU.c. That doesn't seem to work properly :~ + [*] Added MAX_S , MIN_S to reg caching iFPU.c . Not tested but should work + (shadow) + + * 28/05/05:[+] Added PNOR and impoved a few more MMI opcodes + [+] Few more opcodes to ix86_sse.c as well + (shadow) + + * 26/05/05:[+] added emulated hardware cd/dvd sector decryption routines + (should make the playstation2 logo display correctly now amoung other things) + [-] fixed cdvdReadKey to get correct args sent to it, also behaves a little differently depending on args + (loser) + + * 26/05/05:[*] fixed a silly bug in iMMI.c pmaxh,pminh opcodes + [*] optimized PCEQB,PCEQH,PCEQW,PCGTB,PCGTH,PCGTW + [*] few more addes to ix86_sse.c . Linuz seemed to discovered new opcodes :P + (shadow) + + * 25/05/05:[+] Few opcodes added in ix86_sse.c .Few of them still needs recheck (shadow- Gabest) + [*] Added the following SSE,SSE2 opcodes to iMMI.c . + paddub,padduh,paddh,pcpyld,pmaxh,pminh,paddsb,paddsh,psubsb,psubsw,paddb,paddw,psubsb,psubsh + psubb,psubb,psubh,psubw + [*] More opcodes in SSE2 . PCPYUD,PSRLW,PSRLH,PSRAH,PSRAW,PSLLH ,PSLLW ,PCEQB,PCEQH,PCEQW,PCGTB,PCGTH,PCGTW + (shadow) + + * 24/05/05:[*] PSXCLK now can be changed at the ini, defaults + to the right value (36864000) if it's 0 anyways + [-] Fixed bug at Interpreter.c for sstates + (linuzappz) + + * 23/05/05:[-] fixed a bug in iMMi.c PADDSD,PSUBSD doesn't exist in ix86 (who added them?) + [*] Added a new prefix in ix86_SSE opcodes, it is now more clear to understand what each opcode do + that also helped to find that linuz had added an SSE2 instruction in iFPU.c bad linuz ;P + [-] PSMAXSW,PSMINSW was writing to a XMM register (the SSE version writes to MMX register) fixed.. + [+] a few more SSE2 instructions needed for iMMI.c added in ix86_sse.c . + Linuz code them properly pls ;) + (shadow) + + * 23/05/05:[+] Added Devc++ 4.9.9.2 project files for compiling mingw32 with IDE :) + [-] Added a few missing defines + [!] still my project file can't make as fast exe as linuz's sse build. can't figure why yet + the problem should me around Makefile.win :~ + (shadow) + + * 21/05/05:[-] More PS1 compat fixes + [!] Seems the GPU->GS is done by the PS1DRV, gotta find out more + (linuzappz) + + * 19/05/05:[+] PS1 games kinda boot now as well ;) + (linuzappz) + + * 16/05/05:[-] Misc GUI fixes + (linuzappz) + + * 15/05/05:[-] More FPU regcaching stuff + [!] Finally changed version to 0.9 :D + (linuzappz) + + v0.8: + * 10/05/05:[-] Added some more code for FPU regcaching, still unused + [!] Code is closed today until release, only bugfixes now + (linuzappz) + + * 08/05/05:[-] More fixes/improvemets to VUrec/iFPU + (linuzappz) + + * 07/05/05:[-] COP2 now is recompiled when VUrec is enabled + (linuzappz) + + * 05/05/05:[-] Fixed a rather small bug in VIF1 unpack + [-] VU random functions are more correct now, thx goes to _Riff_ and saqib + [-] Sio arranged better for sstates + [*] Modified "FireWire" syms to "FW" + (linuzappz) + + * 04/05/05:[-] Timings in VIF1 should be more accurate now + [-] Fixed bug in the elf loading filter + (linuzappz) + + * 02/05/05:[*] recommited the old reccop2.c (shadow) + + * 02/05/05:[-] Fixed bug in REF/REFS dma at VIF1/GS MFIFO + (saqib) + + * 02/05/05:[*] Cpudialog will disable the checkboxes if the requested features not found + (shadow) + + * 01/05/05:[*] Created a new <> folder to clean up some stuff in the existing interface + Folders became better now and included project files only for vcnet2003 so far... + [*] Moved all patchbrowser source to patchbrowser.c and added language support for it + [*] CpuDialog is now At CpuDlg.c . Redone the Dialog a lotta better ;) + [*] The remaining console,thread,patches configure are now part of the main menu + [*] Organize cpudetection code a bit better. Cpudetection is now done in winmain.c + (shadow) + * 01/05/05:[*] Even more VUrec stuff + [+] Added some more Stats.c info per frame + [-] Fixed some MFIFO bugs remaining + (linuzappz) + + * 30/04/05:[*] More work on VUrec, flags are somehow implemented, PSHUFD is now + used to unpack XYZW/IQ stuff and bug fixes as well :) + (linuzappz) + + * 29/04/05:[-] Updated VIF0 code as VIF1 + [-] VIF1 doens't clears str on MFIFO (saqib) + [-] Fixed some MFIFO bugs in both GS/VIF1(saqib) + [*] Cleaned up dma## functions + (linuzappz) + + * 28/04/05:[-] end source chain tag seems not to touch tadr + [-] Vif1 dmaIrq seems ok, need to test it more tough + (linuzappz) + + * 26/04/05:[+] Added BC1 ops at rec + [+] Started some optimizations for UNPACK + [-] Skipping vif mode was still a bit buggy, seems ok now + (linuzappz) + + * 25/04/05:[*] VIF1 dma is kinda more asynchonous now + (linuzappz) + + * 22/04/05:[+] Added some cache code, not used by default, + it's just for testing atm + (linuzappz) + + * 21/04/05:[-] Readded SysPrintf for Cd/DvdReads + [-] Fixed NReady busy stuff, thx to loser + (linuzappz) + + * 19/04/05:[-] More VUrec refixing/work + (linuzappz) + + * 18/04/05:[+] added CDVDreadSubQ, CDVDgetTOC, CDVDctrlTrayOpen, CDVDctrlTrayClose + to the cdvd plugin definitions + [*] changed CDVDgetType to CDVDgetDiskType + [-] fixed NVM (eeprom) access from cdvd stuff + [+] added reading of mecha version from an external file + [-] fixed raw dvd sector readng for dvd9 discs (otp and ptp) + [+] added hw-reg read/write for DecSet register 0x1f40203A + [+] made cdSeek change the current cdvd sector + [*] incremented cdvd plugin version and brought cdvd plugins in cvs up to date + (loser) + [-] __WIN32__ should not be used over PS2Etypes.h, + __MSCW32__ or __MINGW32__ must be used there + (linuzappz) + + * 16/04/05:[-] xyzw stalls was kinda wrong ;P seems ok now + [-] Fixed a bit vurecs + (linuzappz) + + * 16/04/05:[+] Added GSsetCSR + (saqib-linuzappz) + + * 14/04/05:[-] Fixed some small bugs over VUops.c for the regsNum stuff, + thx goes to saqib + [-] Really fixed skipping vif this time :P + [-] Fixed DIV/RSQRT exceptions (saqib-linuzappz) + (linuzappz) + + * 13/04/05:[-] Fixed skipping write mode at Vif + [-] Fixed unpack overflowing + (linuzappz) + [-] updated all visual studio project files to have the correct source/lib/includes + also removed unused dirs and files. now even 'debug config' will build ok :) + (loser) + + * 10/04/05:[-] Fixed stalls for VF regs, xyzw must be handled separatedly + (linuzappz) + + * 04/04/05:[-] Kinda reworked VU MAC flags, also fixed RSQRT neg prob, thx to Riff/saqib + [-] Fixes to VifDma cl/wl stuff + (linuzappz) + + * 03/04/05:[*] Modified a bit how branch works on VUs + (linuzappz) + + * 02/04/05:[-] Some fixes to VU flags/pipelines + (linuzappz) + + * 30/03/05:[*] Cleaned up a bit writes to VIFX regs + [-] Fixed a small bug in vif1 stalls + [-] Commented readclock win32 code at CDVD.c + [-] Fixed two small issues with branches in interp + (linuzappz) + + * 29/03/05:[*] Added some fixes from LDChen to hConsole/WM_PAINT stuff + [*] Modified GetToc stuff in cdvd to support dvds + [*] cdvdTD uses lsn now + (linuzappz) + + * 28/03/05:[+] Added placetopatch == 1, which means patches will be applied every vsync ;) + (linuzappz) + + * 27/03/05:[*] Improved cpu detection for Amd's 64 using BrandID. Most of the models should be + detected correct now (at least my cpu does ;P) (shadow) + + * 24/03/05:[-] Fixed ISUBIU :D + [-] Some fixes to flags, status was fecked, now seems better + [-] Commented the GS dma IRQ again, seems to cause more probs, will + fix it later + (linuzappz) + + * 21/03/05:[-] Fixed VIFX_CODE reg + [+] Added previous normal vu fixes to vurec + [*] Added EFU pipeline to VUmicro, kinda untested + [-] Hopefully fixed GS dma IRQ + (linuzappz) + + * 21/03/05:[-] Fixed cdReadKey function to emulate correctly. Now games should boot using + Execute with non Modded Bios. + (auMatt & Loser) + + * 20/03/05:[-] Started reg caching for VUrec ;D + [*] Rearrenged a bit rec32/64, added a common 'x86' dir + (linuzappz) + + * 18/03/05:[-] VU1micro was being executed instead of VU0, bad linuz bad :P + [-] Fixed VU's JR/JALR/BAL :D + (linuzappz) + + * 17/03/05:[-] Cleanup/speedup/fixup from last fixes :P + [-] VIF0 has no from mode ;) + (linuzappz) + + * 16/03/05:[*] Added some more debug info to CDVD + (auMatt) + + * 15/03/05:[*] Added an evil vuDouble function to convert from vu float format + to ieee 754 format ;) + [-] Reworked MAX/MINI + [+] Added experimental work for VU pipelines + (linuzappz) + + * 14/03/05:[-] Added the pipelines VU1 bug to VU0 + (linuzappz) + + * 12/03/05:[-] Fixed some pipelines bug within VU1 + (linuzappz) + + * 10/03/05:[-] Fixed small bug over VIF1 dma FIFO + (linuzappz) + + * 08/03/05:[-] Fixed vu flushing over vuExecMicro + (linuzappz) + + * 06/03/05:[-] Fixed UNPACK V4_5 with mask + (linuzappz) + + * 04/03/05:[-] Small fixes to VUrec + (linuzappz) + + * 01/03/05:[+] Added new VS2005 sln and .vcproj to build the 32bit version of + pcsx2 in VS2005 Beta1 (You have to use different projects to build) + [*] Changed some of the files to make them compile in VS2005. + (GoldFinger) + + * 23/02/05:[-] Commented hack at VSync + [+] Added interleave mode for SPR + (linuzappz) + + * 20/02/05:[*] Changed IRQ defines to functions + [-] VIF irq by vifcode seems ok now + [+] Added offset/difference with mask UNPACK modes in vif + [-] SPR1 was transfer /4 the size it should have :/ + (linuzappz) + + * 16/02/05:[-] Fixed some VPU-STAT related issues + [+] 'sstates' dir is now created at init + (linuzappz) + + * 15/02/05:[+] Another DNAS by nachbrenner + (linuzappz) + + * 14/02/05:[+] Added offset/difference UNPACK modes in vif + (linuzappz) + + * 14/02/05:[*] 64bit rec back to x86-64 better this way + [*] Updated vsnet2005beta1 project files to compile with x86-64 dir + [*] Added a few pragma warnings disable to a few files to correct some silly vsnet2005beta1 + warnings (blah MS deprecated stdio pffff) (shadow) + + * 10/02/05:[-] Fixed bug in CDVD_findfile + (linuzappz) + + * 09/02/05:[*] GSvsync is now called on the vsync start + (linuzappz) + + * 08/02/05:[*] QWC is set to 0 after a normal transfer in GS/SPR1/VIF1 + and MADR is increased qwc*16 as well + (linuzappz) + + * 07/02/05:[*] Changed a bit the CPU dialog. Now it is better i guess :) . Linuz update the pcsx2.po again pls :D + [*] Added a __VCNET2005__ definition cause vcnet2005beta1 doesn't support inline asm.. + That only effects Cpudetection.c and Gte.c (not much since it has c code instead to use). + Cpudetection must be written on ml64 to be useable on vcnet2005. + [*] Added prelimary vcnet2005beta1 project files. gettext disabled cause we still doesn't have a + 64bit version for it + [*] Small fixes around and wholaaa i produced the first buggy pcsx2_64bit.exe :) (shadow) + + + * 07/02/05:[+] Added another DNAS version thx to Nachbrenner + [-] Fixed SPR0 chain mode + [-] Fixed intc/dmac interrupts that gets cleared right away + [-] Cleaned up langs a bit, only spanish works so far now + [+] Added 1f402007 reg, "BREAK", still not really handled ;P, + thx to matt + (linuzappz) + + * 31/01/05:[-] Disabled recompile functions recBGEZ() and recBLEZ() from iR3000.c . That will make + recompiler not to crash after the players selection screen in Virtua Fighter 4. Thanks + to JayteeMaster for bug tracing it ;) (shadow) + + * 30/01/05:[-] Fixed some more bugs in IPU, some streams had a few problems, now they are ok. + Quality of ipu playback also improved(thanks JayteeMaster for pointing it out) + (asadr aka saqib) + + * 26/01/05;[*] Merged a big part of linuz's amd64 rec to the normal rec (shadow) + + * 25/01/05:[-] Finally fixed IPU. Mpegs and IPU streams run + so do PSS files.Some fixes to MMI and Interpreter (asadr) + + * 23/01/05:[-] Fixed vurec crash on pcs that doesn't support SSE2 + [*] General cleanup on ix86-32 rec. Goldrec removed since no progress has been made + lately (shadow) + + * 20/01/05:[+] Added x86-64 rec, still unclean, but i'll leave for holidays this + saturday, so ^^ + (linuzappz) + + * 19/01/05:[-] Fix for end chain mode at vif, still gotta check it + (linuzappz) + + * 16/01/05:[-] Lots of fixes to VUmicro, thx to Refraction for pointig out + some bugs ^^ + [*] Commited ix86 changes for x64 + (linuzappz) + + * 13/01/05:[-] WriteNVM now takes address in param[1], thx to auMatt + (linuzappz) + + * 06/01/05:[-] Fixed long types at VU.h + [-] Removed memLUT decl + [!] Notice long is 8bytes long in amd64, so we should + stick to the u32/s32 types instead of using long pls :) + (linuzappz) + + * 06/01/05:[-] Fixed SBUS IRQ at iop + [-] dmaGetAddr now uses memLUTR + (linuzappz) + + * 05/01/05:[*] Changed some stuff for amd64, still more to come + [+] Added more memRead/Write funcs for speed + [-] Fixed some iVUmicro bugs + [-] Fixed QFSRV/MTSAH/MTSAB + (linuzappz) + + * 03/01/05:[+] Implemented MFLAG for VU0 + [-] Vsync is now genereted on boths cpus at the same time + (linuzappz) + + * 03/01/05:[-] Commented dma irq stuff, fecks some games, gotta recheck that + (linuzappz) + + * 22/12/04:[-] Fixed bug in branch address in vus + (linuzappz) + + v0.7: + * 18/12/04:[*] Added GSread8/16/GSwrite8/16, GSgifTransfer1 now has two args, + added the addr and pMem points to the VU1 mem + (linuzappz) + + * 16/12/04:[*] Pofis improved his Patchbrowser (shadow) + + * 06/12/04:[-] Fixed Langs support for win32 + (linuzappz) + + * 06/12/04:[*] Added support for 1.90 Bios NVM. + (auMatt) + + * 06/12/04:[+] Added Patch Browser for win32 . Made by Pofis (shadow) + + * 05/12/04:[*] NVM always loads rom %Bios%.NVM + [*] Cd/Dvd Reads are now again displayed on console, + that is very helpfull for testing :) + (linuzappz) + + * 28/11/04:[-] BC2T/F/TL/FL also check for VU1 to be stopped + [-] VU1 memory is masked on micro load/store instructions, + dunno yet about VU0, gotta test ;) + (linuzappz) + + * 26/11/04:[-] VU D/T flags are handled now (kindaof :P). + (linuzappz) + + * 20/11/04:[-] RTC timezone fixed (gigaherz) + + * 19/11/04:[-] Fixed vu branch negative overflows + (linuzappz) + + * 17/11/04:[*] Fixed some stuff in logging so now + -Memcards sysprintf messages Are now MEMCARDS_LOG define and enable with PAD_LOG + -Cdreads Dvdreads are now in CDR_LOG + -Vus Overflow enable from CPU_LOG + That means less logs at runtime and no more complains from nasty betatesters :D (shadow) + + + * 17/11/04:[*] fixed linuz bug in naming the memcards different in 2 different places + Memcards now are Mcd001.ps2 and Mcd002.ps2 in emu and McdDialog (shadow) + + * 16/11/04:[-] Fixed NVM File Load and Creation. Defaults to BIOS name als now. + (auMatt) + + * 15/11/04:[+] Added another DNAS at Misc.c. + (nachbrenner) + + * 14/11/04:[-] VU0/1 reset shouldn't reset the micro memory. + [*] Commented the LT_OpcodePrintTable call on Interpreter.c, + for speed :) + (linuzappz) + + * 12/11/04:[-] Second MCD works fine now. + (linuzappz) + + * 11/11/04:[-] Finally fixed SIF1 bug :D:D + (linuzappz) + + * 10/11/04:[+] Added MingW32 support ;). + (linuzappz) + + * 10/11/04:[-] Fixed NVM loading/reading/writing and also fixed v12 NVM issues. + (auMatt) + + * 09/11/04:[+] Added BiosVersion var. + [*] Sif stuff now gets saved over sstates. + (linuzappz) + + * 09/11/04:[-] Fixed bug in ModelID code in CDVD + (florin-auMatt) + + * 07/11/04:[-] Fixed bug that caused to interrupt twice before + handling the first interrupt. + (linuzappz) + + * 05/11/04:[-] Small fix for broken elfs. + (linuzappz) + + * 04/11/04:[-] CDVD was interrupting dma too much :P. + (linuzappz) + + * 03/11/04:[*] Added FREEZE_SIZE. + (gabest-linuzappz) + + * 03/11/04:[+] Added a couple of DNAS at Misc.c. + (nachbrenner) + + * 02/11/04:[+] Added hack for QFC in GS ;). + (linuzappz) + + * 01/11/04:[+] Implemented VU0 Interlocks over CFC2/CTC2/QMFC2/QMTC2. + (linuzappz) + + * 31/10/04:[-] Fixed v12 bios running. + (auMatt) + + * 30/10/04:[-] Fixed v9-v10 bios running. + (auMatt) + + * 28/10/04:[-] Really fixed SIF SMFLAG/MSFLAG :P:D + (linuzappz) + + * 28/10/04:[-] Fixed MCDS :D + (asadr) + + * 26/10/04:[*] Added rom2/erom support + (auMatt/linuzappz) + + * 23/10/04:[*] Added/Fixed Model Number Reading + (auMatt/Florin) + + * 18/10/04:[-] Fixed SIF SMFLAG/MSFLAG, needs testing tho + (linuzappz) + + * 06/10/04:[*] More BIOS detection added.(auMatt) + + * 04/10/04:[-] Fixed EXL bug + [-] Fixed SIF0/1 when fifo got filled up + (linuzappz) + + * 01/10/04:[-] CdReadConfig/CdWriteConfig now uses NVM ^^ + [!] Bios configurations now gets saved/loaded from NVM (nvm.raw) + (linuzappz) + + * 1/10/04:[+] Started coding the memcard manager. Far from finish but will be better soon :D + [*] Change settings . Default memcard is now a ps2 memcard. (shadow) + + * 30/09/04:[-] Newer bios will now work with pcsx2. Pads fixed, more + compatibility. (asadr) + + * 27/09/04:[-] VU0/1 Reset hopefull fixed + (linuzappz) + + * 16/09/04:[*] NVM now is readed/written from nvm.raw. + [-] ReadILink/GetMecaconVersion are really implemented ^^ + (auMatt-linuzappz) + + * 15/09/04:[*] Rewritten LoadConfig-SaveConfig to use ini instead of registry. + [*] Removed DeleteRegistry button. For obvious reasons :D (shadow) + + * 15/09/04:[-] Pads finally fixed - Fixed PADwin Plugin Required! + Updated stuff at PsxSio2.c and Sio.c (Pad Hack still + there but won't be used) asadr + + * 13/09/04:[+] Added an option for setting the main thread priority, usefull at work :P + (linuzappz) + + * 13/09/04:[*] Fixes to SCMD's (auMatt) + * 02/09/04:[*] Finally commited asadr's IPU changes + [-] Fixed small bug in memory dump for win32 + (linuzappz) + + * 30/08/04:[*] Added Deci2 Call back into the Interpreter.c for printf.(auMatt) + + * 18/08/04:[*] fixed finaly the IOP disasm. Should be correct now... + [+] for stuff for amd64 porting.notice that pcsx2_2003_amd64 project just check for 64bit + portability.Can't produce 64bit exe yet.. (shadow) + + * 15/08/04:[-] fixed the IOP-EE disasm problem.(for ppl with vc != 2003 you must include + DisR3000asm.c and DismAsm.h in your project files) + [!] Still have to finish the correct IOP disasm :D + [+] Added small framework for x86-64. Still nothing that useable :D (shadow) + + * 04/08/04:[-] PadHack now works again :) + [-] Sio2 now supports states again + (linuzappz) + + * 02/08/04:[*] F2 will print the selected state on the console + [*] Added overflow messages for ISW/ILW/ILWR/ISWR + [*] FBRST should reset the vus when VU0 Reset/VU1 Reset + bits are set, but i don't really know have much it's + resetted :P + (linuzappz) + + * 30/07/04:[-] Vif1 MPG lacked a flush + (linuzappz) + + * 28/06/04:[+] Added GSprintf, GSgetDriverInfo and PADgsDriverInfo + [+] Deci2Call 0x10 gets printed ;) + [-] Some fixes to CDVD reading + (linuzappz) + + * 24/06/04:[-] Fixed some bugs over interrupts and + exceptions + (linuzappz) + + * 22/06/04:[-] Couple of bugs fixed over IPU1 dma + [-] psHu32(INTC_STAT) changed to INTC_IRQ + (asadr-linuzappz) + + * 16/06/04:[-] Counters regs are returned in 16 bits + [+] Also added them for hwRead16 + [-] Counter only resets when writing to the mode reg + when the value & 0x3ff differs from the actual mode + [-] Fixed BCR interrupting for CDVD ;) + (linuzappz) + + * 14/06/04:[*] Enabled SSE Vif at i386.asm + [*] Added florin's work over mcds, still needs + a cleanup :) + (linuzappz) + + * 10/06/04:[*] CSRr is OR'd with 0x8 always over VSyncEnd + (linuzappz) + + * 08/06/04:[*] VU pointer gets aligned now + (linuzappz) + + * 07/06/04:[*] vuJALR now uses _Fs_*8 + [*] VSync now interrupt for INTC_STAT & 0x1 + [!] Based of debugging Aura for Laura :) + (linuzappz) + + * 07/06/04:[*] Detection for Chinese Bios. + (auMatt) + + * 04/06/04:[-] Cleaned a bit VIF1transfer, and now when + DIRECT/DIRECTHL cmd is misaligned it skips it + [*] Added USBirqHandler, USB specs v2 now + (linuzappz) + + * 04/06/04:[-] VU1 regs now are mapped to VU0 mem + (linuzappz) + + * 02/06/06:[*] finished most of the iops disasm works :P + [*] increase the firewire reg size . seems there are more regs ;p (shadow) + + * 25/05/04:[-] Fixed big stupid bug in counters ;P + Now they're accurate + (linuzappz) + + * 25/05/04:[*] Included new BIOS detection 'P'. For Free and Public BIOS Images. + (auMatt) + + * 20/05/04:[*] BCR now decrements for each cdvdReadSector, thx to Roor + (linuzappz) + + * 18/05/04:[*] Removed PsxBios2.c/h, and cleaned Irx funcs from ElfHeader.c/h + [+] Added cpuTestHwInts/cpuTestINTCInts/cpuTestDMACInts + [+] More work over mcds + [!] Now cpuBranchTest doesn't checks for irqs + (linuzappz) + + * 17/05/04:[-] Fixed bug psx counters, thx gold + (linuzappz) + + * 15/05/04:[+] Added IOP disasm in the debugger... + [!] Not yet finished and i disasm using R5900disasm atm. I will code it correctly soon (shadow) + + * 12/05/04:[*] More optimizations to the FPU rec + [*] BIAS was commented over Counters.c :/ lol + [-] Disabled EMMS_TRACE, it's buggy, dunno why tho + (linuzappz) + + * 11/05/04:[*] Now Saving/Loading FPU CW only for the ops that really need it + [*] Added some optimizations to jumps over rec + [*] Added LQC2/SQC2 + (linuzappz) + + * 08/05/04:[-] Fixed states loading/saving from the menu + (linuzappz) + + * 03/05/04:[*] Uncommented the sio2 1d100 hack + (linuzappz) + + * 3/05/04:[+] started reorganize the src. Lotta unneccesary stuff removed(like HLE) and lotta + organized. still needs a lot of work to clean but it's a start (shadow) + + * 02/05/04:[+] Added D3/D4 defines at Hw.h + (linuzappz) + + * 1/05/04:[+] Added a Delete Registry Button. It deletes pcsx2,gssoft settings + (shadow) + + * 30/04/04:[-] Small bugfix for cpu speed detection, thx to Rainer Aglas + (linuzappz) + + * 27/04/04:[+] Implemented ReadNVM/WriteNVM, untested though + (linuzappz) + + * 15/04/04:[-] SPUdma timings changed to 80, thx _Riff_ + (linuzappz) + + * 13/04/04:[*] Several changes for IPU + [+] IsBIOS now belongs to Misc.c + (asadr-linuzappz) + + [*] Dev9Null/USBLinuz/FireWire Plugins Configure now shows + Message. + [*] Configure Menu Shows USB and FireWire Options. + (auMatt) + + * 12/04/04:[-] Fixed SPU2async cycle, was getting reseted wrongly, + thx _Riff_ + [+] Added SPU2irqCallback + (linuzappz) + + * 08/04/04:[-] Unhacked sio2 for 1d100 recv1 mode + (linuzappz) + + * 07/04/04:[+] FireWire IRQ is implemented ok now + [-] Forgot dev9Interrupt over R3000A.c + (linuzappz) + + * 05/04/04:[+] Added Firewire plugin protocol. (shadow) + + * 02/04/04:[-] VIF-FIFO transfers seems to work better ;) need testing + [+] Added GSreadFIFO + (linuzappz) + + * 30/03/04:[*] sstates now use CRC as well :) + [*] emuLog.txt now goes at 'logs' dir + (linuzappz) + + * 29/03/04:[*] GSdma now waits qwords transferred cycles + before clearing CHCR and triggering, + OPH and APATH are handled as well now. + (linuzappz) + + * 25/03/04:[*] Some rewritte over Sio.c + (linuzappz) + + * 24/03/04:[-] ostr size is now 1024 in Dis*.c + [!] Finally v0.7 :D + (linuzappz) + + v0.6: + * 21/03/04:[-] About dialog was cropping the testers, thx CK :) + (linuzappz) + + * 19/03/04:[+] Added a PadHack option at the cpu dialog + [-] Couple of fixes for release + (linuzappz) + + * 16/03/04:[-] CRC had a bug, now it's ok, sorry :) + [-] Fixed bug in memInit, thx gold :) + [-] LoadState now loads the tlbs + (linuzappz) + + * 16/03/04:[-] Fixed another silly bug in loadElfFile ;) + (linuzappz) + + * 15/03/04:[+] Added texts on the console Title to make patch makers life easier :P (shadow) + + * 15/03/04:[-] Fixed a free in loadElfFile + (linuzappz) + + * 14/03/04:[*] loadElfFile now reads the whole file first + [-] DMA4/7 interrupt timings are more accurate now + (linuzappz) + + * 12/03/04:[+] Added i386.asm, only used on linux so far, + compiles using nasm, it replaces the inline + assembling for Vif + [-] Fixed bug in UNPACK for skipping write + (linuzappz) + + * 11/03/04:[*] Patches names are now using crc, + instead of ie.: + Ridge Racer V PAL was SCES_500.00.pnach, + now it is 5BBC2F40.pnach + this way games with the same code + will not get confused + [-] Fixed bug in disR5900GetUpperSym + (linuzappz) + + * 10/03/04:[+] Added SQ/LQ over iVUmicro + (linuzappz) + + * 09/03/04:[-] sio2Reset was missing from psxHwReset + [-] Fixed sio pad swaps for 0x1100 mode + (linuzappz) + + * 08/03/04:[*] Modified the DEV9irq stuff + (linuzappz) + + * 05/03/04:[-] DEV9irq now issues a SBUS_IRQ + [*] malloc memory is now aligned to 16bytes + (linuzappz) + + * 02/03/04:[-] Added presaving for MMI ops that needed that + [-] vuJR/vuJALR now masks Fs with ~0x7 + (linuzappz) + + * 02/03/04:[+] stats.txt now dumps the Cpu mode + (linuzappz) + + * 01/03/04:[-] dmaGetAddr now uses memLUT + [+] Finally added USB plugins ;) + (linuzappz) + + * 26/02/04:[-] Fixed VUops that didn't have presaving + (linuzappz) + + * 22/02/04:[+] More ops at DisVUops.h + [-] VifDma.c is cleaner now, also fixed some + stuff for savestates + [-] Added some remaining vars at cpuBranchTest + to cpuRegs for savestates + (linuzappz) + + * 21/02/04:[-] Fixed ITOF0 + (linuzappz) + + * 20/02/04:[-] Fixed savestates ;) + (linuzappz) + + * 19/02/04:[*] VUflags now should handle overflow/userflow ok + (linuzappz) + + * 17/02/04:[*] Improved and fixed sio2 stuff + [-] Fixed _vuMFIR + (linuzappz) + + * 16/02/04:[-] DIV could crash when divisor == 0.0, + as well as ERSADD + (linuzappz) + + * 13/02/04:[-] Fixed FCAND over VU1ops.c + [*] Merged VU1ops/VU0ops/Vops to VUops + [*] Cleaned up VUflags.c + [-] hackedRecv now defaults to 0x1100 + (linuzappz) + + * 09/02/04:[-] VifDma.c MPG now clears the VU0/1 Mem though Cpu->ClearVU0/1 + (linuzappz) + + * 09/02/04:[-] More SCMD functions added. Still require working code for them. :) + (auMatt) + + * 06/02/04:[-] More iVUmicro.c opcodes, fixes, and stuff :) + (linuzappz) + + * 06/02/04:[-] Fixed Bios Detection for HK Bios. + (auMatt) + + * 06/02/04:[-] Fixed CdRom/CDVD Interrupt for 0x41000200 chcr, + now it interrupts after the read ends + (linuzappz) + + * 05/02/04:[+] Added FALSE/TRUE in GRecCommon.h + [+] Added more 16bit ops to x86.c/h + [+] Fixed SQD/SQI and implemented IOR/IAND over iVUmicro + [-] BIAS is now 2 again + [+] Now only MARK is writable at Hw.c, for vif0/1Regs + (linuzappz) + + * 03/02/04:[-] Fixed FALSE to GREC_FALSE in GRecMain.c + [-] Added break to F5 ;) + [-] Commented 'ERL Set' SysPrintf + (linuzappz) + + * 02/02/04:[-] Included stdarg.h in GRecCommon.h + [+] Added some scmds to CDVD.c (auMatt) + [+] cdvd.Status now changes to CDVD_STATUS_SEEK_COMPLETE, + after a CdRead CMD + (linuzappz) + + * 16/01/04:[+] Added LQI/LQD/SQI/SQD over Recompiler + [-] Updated EE BIAS to 8, need to test this + [!] SQI/SQD are diabled still, because they are still buggy + and i don't have more time... vacations :D:D + (linuzappz) + + * 15/01/04:[+] Added code for dma interrupts, for IPU FDEC, still commented + (linuzappz) + + * 14/01/04:[+] Temporary fix for PADS. F5 now change the pad mode on the fly. if your game doesn't work + switch it from there. (shadow) + + * 12/01/04:[*] FIFO is now really 128bit as it should be :) + (linuzappz) + + * 09/01/04:[-] Fixed VU->VI[0] != 0 bug in VU1, VU0, Macromode, JALR, BAL, LQI, LQD, SQI, SQD were setting VU->VI[0]. + Address in VCALLMS was incorrect, was causing crash in VF4. + (asadr) + + * 09/01/04:[*] Start to convert VIF stuff to functions instead of macros, right now I just converted + them duplicating the code for VIF0/1 and it is working but it is not the best yet, + commiting just so others can debug VIF while I finish the work, did some minor fixes + on VIF too. + [*] The only major function needed to be reduced to one is VIF0transfer/VIF1transfer, all + others are ok (I think). + (GoldFinger) + + * 09/01/04:[-] Fixed LQC2 for _Fs_ == 0 + [*] Fixed several SIF bugs (NoComp) + (linuzappz) + + * 06/01/04:[-] Fixed UNPACK modes in VIF.c, the Indeterminate fields are now set to 1 by default. (asadr) + + * 04/01/04:[-] Fixed a bug in LQD and LQI when _Ft_ was 0. + (GoldFinger) + + * 04/01/04:[*] Modified the VIFregister structure, both VIFs(0,1) have the exactly same + structure, just VIF0 does not use some of the registers, so I unified the + structures for easy reading and less bugs. + (GoldFinger) + + * 31/12/03:[-] Added USB API at PS2Edefs.h ;) + [+] More ops at DisVUops.h + [*] UNPACK now flushes the VU micro + (linuzappz) + + * 30/12/03:[-] Fixed savestates in Misc.c and added fixed VIFdma.h + (asadr) + + * 29/12/03:[-] Fixed bug for new vu code in savestates + (linuzappz) + + * 27/12/03:[-] Fixed bug in my last update for R5900.c + (linuzappz) + + * 26/12/03:[*] VUflags are now updated when Rd == 0 as well, changed only + at VU1ops.c + [*] VU1Regs/VU0Regs is now VURegs + [!] I think we should merge VU1ops/VU0ops/Vops + (linuzappz) + + * 24/12/03:[-] Fixed DMA8 for PsxDma.c + [*] LUI is now as it was before asadr's update + [*] readded 'if Log' over debugI at Interpreter.c + (linuzappz) + + * 18/12/03:[*] Restructured VU code and VIF. Fixed stuff in Interpreter + and added CTC2 VU1 Microinstruction caller. + (asadr) + + * 18/12/03:[*] Improvements to TLB code. + (linuzappz) + + * 17/12/03:[-] Fixed iCP0.h define to __ICP0__ + [+] Added disR5900GetUpperSym + (linuzappz) + + * 08/12/03:[+] SSE recompile of vus started. Some opcodes works some yet not. + Missing flags that i gonna add soon. Gives some speed boost :) + (shadow) + + * 05/12/03:[-] Fixed bug in GS for CSR stuff + (linuzappz) + + * 03/12/03:[+] Added Interlock for CFC2/CTC2 + [-] Fixed CFC2/CTC2/LQC2/SQC2, they now + check for zero registers + [!] This should fix the 'R0 is not zero' + and the 'VU memory overflow' hopefully ;) + (linuzappz) + + * 03/12/03:[+] You now disable vu0 macromode too when you disable vu recs by the + checkbox iR5900.c + [-] corrected some more bugg0rs of linuzappz sse instructions ix86_sse.c + [!] careful linuzappz's code. Don't ever trust him cause he is a lazy bugg0r + His mind is only for pampita!:) (shadow) + + * 02/12/03:[+] Added UNPCKLPSRtoR and MOVLHPSRtoR, there you go expert :) + (linuzappz) + + * 01/12/03:[-] Fixed savestates + (linuzappz) + + * 30/11/03:[+] a few sse instructions in sse.c + a much cleaner code in reccop2.c (shadow) + + * 28/11/03:[-] Recommited old VUops.h with asadr's EATANxy/EATANxz bugfixes + [!] asadr, the VUops.h you commited was in html format, + and some opcodes you change were only to slow down things, + commit other ones that need fixes. + (linuzappz) + + * 28/11/03:[-] Fixed alot of bugs in VUops.h, hopefully some stuff will now + work as it should (asadr) + + * 27/11/03:[*] fixed some stuff in recCOP2.c (shadow) + + * 25/11/03:[-] Fixed bug in Vif.c, masks hopefully are ok now ;) + (linuzappz) + + * 25/11/03:[-] Fixed Interpreter.c ix86.h include + [-] Added to GRecBasic.h a newline at end of file, linux + complains else ;P + (linuzappz) + + * 24/11/03:[+] Added cpu detection in interpeter.c too so now you can use SSE,MMX code in + interpreter too without the fear that your pc doesn't support it ;P (shadow) + + * 22/11/03:[+] By Nachbrenner request i added a memory patcher in Debugger.Now you can make patches + while pcsx2 is running. It is not yet finished as it can only patch 32bit data but + all the patches so far are 32bit so no problem ;P (shadow) + [!] Update Common.h . We are up to pcsx2 0.6 now! :) + + v0.5: + * 21/11/03:[-] Fixed Vif.c bugs :) + [!] Source code closed for release 0.5, + only bugfixes con be submitted + (linuzappz) + + * 21/11/03:[*] Started optimizing vif.c but I find so many strange stuff (problably bugs), please + linuz, check the comments I added on the vif.c file, and tell me what to do. + (GoldFinger) + + * 20/11/03:[*] Reorganize the cpu dialog a bit and added a new option. Disable vu recompiler + with disable the recompile of vu and will save some games from freeze when + vu memory overflows (quite often) :P . This will be removed when vu problems will + solve :P (shadow) + + * 19/11/03:[-] Fixed bug in savestates + (linuzappz) + + * 18/11/03:[*] Removed the old reg caching code including the sources, so now the only rec + that works is the normal one. + [*] GoldRec is progressing, I did lots of changes to make the progress better, + right now nothing works. + (GoldFinger) + + * 14/11/03:[*] Modified GSfreezeData, now it's plugin dependant + [+] Added SPU2freeze/DEV9freeze + [-] Fixed bug in inifile_read, hi shadow bugg0r :P + [-] Fixed bug in Sio2 + (linuzappz) + + * 14/11/03:[*] change pcsx2 patch system to use *.pnach files.Now you need a patches dir in your + pcsx2. (shadow) + [!] Am i the only one that write a changelog here?? (shadow) + + * 13/11/03:[-] fixed savestate naming in win32 and linux (shadow) + + * 06/11/03:[+] cleaned up a bit rec vu and enabled vu0 micro (shadow) + + * 06/11/03:[-] Workaround in VifDma.h for FiFo transfer ;) + (linuzappz) + + * 04/11/03:[*] Changed the way we handle SPR TTE transfers, also + MFIFO_VIFtransfer transfer always the ptag+2 + [-] Unhacked Sio.c for PADs ;) + [!] Now you gotta use the PADwinKeyb from PADwin at cvs + (linuzappz) + + * 03/11/03:[-] Fixed ba8R16 bug in Memory.c + [*] Enabled VU1 micro recompilation + [*] dmaGetAddr goes though memLUTR now + (linuzappz) + + * 02/11/03:[-] Fixed MSUBA had the same problem as MSUB, iFPU.c + A = A - B * C != A = B * C - A :) + (GoldFinger) + + * 01/11/03:[+] Addded cpu speed detection in cpu detection code + [!] Linuz fix the cpu_detection.c to work with linux pls ;p + [!] Goldfinger was right.Police 24/7 is okay with MSUB now :) (shadow) + + + * 01/11/03:[-] Fixed MSUB (MADD was ok), iFPU.c + Expert, please try in Police 24/7... :) + (GoldFinger) + + * 31/10/03:[-] Fixed PCPYLD, MMI.c + (linuzappz) + + * 30/10/03:[-] disable MADD,MSUB from iFPU. that ops was causing bugs in police 24/7. + Can't figure why, can someone? (shadow) + + * 29/10/03:[-] Commented D/T flags for VUmicro + (linuzappz) + + * 28/10/03:[-] Fixed memory rec issue, blah, shadow was right again :P + (linuzappz) + + * 27/10/03:[-] More fixes to memory stuff, hwregs for 128bit + [-] Fixed vifNum == 0 for UNPACKs + [-] DEV9_R_DEV now goes though DEV9read16 :) + [+] FiFo VIF1 can read data now ;) + [-] Fixed rec mem limit, shadow was right ;P + [!] Try Make Your Dream Home now ;) + (linuzappz) + + * 26/10/03:[-] Fixed Memory stuff, now it works ok :) + (linuzappz) + + * 25/10/03:[*] Some changes to memory cards. It's not what you all expect:P + (Florin) + + * 25/10/03:[*] Improved more the cpudetection routine at the Supporting Instruction sets features + [-] Improved a bit the MMI and fixed some bugs that prevent PII cpus to work (shadow) + + * 23/10/03:[-] Fixed a bug in Memory, untested actually ;), should fix + the loader rec bug + (linuzappz) + + * 24/10/03:[*] Improved the cpudetection routine in goldrec.Now more info appears :) + (shadow) + + * 23/10/03:[*] Improved VIF for transfers in parts + [-] Fixed some bugs in DisVUops.h ;) + [-] Fixed a bug in Memory, VU1.Mem was twice, thx shadow :D + (linuzappz) + + * 21/10/03:[-] Scratchpad memory was set bigger that it really is + [-] Uncommented a few tlb related printfs just in case ;) + (linuzappz) + + * 20/10/03:[*] Rewritten several Memory.c code, it's very untested, so far + i only tested bios, so tell me what's broken now :) + (linuzappz) + + * 18/10/03:[*] Fixed the rec for use with the tlb code, but this is a no go, slow as hell we must + change the whole tlb stuff, please linuz, lets think better before implementing this. + (GoldFinger) + + * 14/10/03:[*] Modified the memRead functions, now they're better for tlbs + misses, but note that they have one more arg, so gold, you'll + have to update the rec + (linuzappz) + + * 12/10/03:[*] Removed the new module in cvs called GoldRec. Now GoldRec is a directory under ix86-32. + (GoldFinger) + + * 10/10/03:[*] Removed the new recompiler from the main project and removed its dependencies, now there + is a new module in cvs called GoldRec, you must check it out. + (GoldFinger) + + * 10/10/03:[*] Improved TLB stuff a lot ;) + (linuzappz) + + * 07/10/03:[-] Fixed bug for recompiler in psx writes from Memory.c + (linuzappz) + + * 06/10/03:[*] VU0/1 now uses the VURegs struct + [+] Added the possibility to load the System.map from ps2linux + [+] Added TLB exceptions + [-] Fixed psxM accesses from Memory.c + (linuzappz) + + * 04/10/03:[*] rewrote the recompiled vu micro startup code and separate it + [-] remove the 3dnow code for reccop2 as it created more problems that it actually solved + [+] qmf2,qmtc2 is now done in SSE too . (shadow) + + * 01/10/03:[+] Handle for the EDI flag at ERET, a guess actually ;) + (linuzappz) + + * 30/09/03:[*] Reg caching works with bios and almost everything as normal rec does, need to + check better what does not work. + [*] Splitted iR5900.c into several .c files for easy navigation and for sanity + purposes as iR5900.c was HUGE. + [-] Fix LOTS of reg caching bugs, the main one was the comparission of 64bits registers. + (GoldFinger) + + * 30/09/03:[*] Added a base interrupt delay for the dma7 (spu2) + [*] More improvements to VifDma.h + (linuzappz) + + * 29/09/03:[-] Reimplemented Interrupt latency over R5900.c + [-] Fixed load/store unsigned addr to signed one over VUops.h + (linuzappz) + + * 28/09/03:[-] Fixed dmaIrq's for Source Chain mode + (linuzappz) + + * 26/09/03:[-] Fix the speed optimization problem that was in softCall function in Bios.c, + added a #pragma to disable optimization just to that function and everything + is working again as it should (linuz, please check if this pragma will interfere + with linux) + [*] The win32 project is back like before, the new Recompiler project was removed and + everything is working. + (GoldFinger) + + * 26/09/03:[+] Added two keys (F11, F12) for Opening/Closing the CDVD tray, + only for linux so far. + (linuzappz) + + * 25/09/03:[*] Sio2 fixes. Now the mcs are 'seen' as PS2 cards but unformated(able:P) + (Florin) + + * 25/09/03:[*] Modified the project structure under win32, I separated the recompiler from + the main project into a static lib, so now I can work with two projects instead + of one and enable optimizations. Now register caching works much better as I + enable speed optimizations in the Recompiler project but had to disable it in + the main project, the real problem is the global optimizations, this way I am + proving that the problem is not on my code... :) + [-] Fix lots of reg caching bugs and commented some of the reg caching instructions + that are buggy. Lots of demos work now, P51, colors, colors15 and maybe some others. + (GoldFinger) + + * 23/09/03:[-] Changed the MessageBox in recFunctions.c to SysMessage + [+] FIFO for VIF0/1 now works :) + (linuzappz) + + * 23/09/03:[*] Splitted the bios files so the code is the .c files and not on the .h files + [-] Fixed several bugs in reg caching and improved the routines + [!] Visual Studio .NET (dont know the others) speed optimizations are + messing with the code so it is recommended to build release mode + without Speed optimizations + (GoldFinger) + + * 23/09/03:[-] Commented the Syms in BiosInit.h, since they are only + for scph10000 + [-] Fixed ret DMA op + [+] Added iVUmicro, for recompiler + (linuzappz) + + * 22/09/03:[*] Added ExecuteVU0/VU1Block in R5900cpu, R5900.c + [+] Destination Chain for SPR0 dma and added Vif masking + [!] Gold, please merge the beta changes i sent you for + the iVUmicro.c/h + (linuzappz) + + * 20/09/03:[*] Now pad2 works in lle mode [tested with bios browser] + [+] New SCMDs and MC commands + [-] Fixes in sio, sio2, cdvd, etc. + [!] Now mcs appear as not inserted, but they are wip:P + SecrCardAuth() works fine;) + (Florin) + + * 19/09/03:[-] Small bugfix in Hw.h, u32 qwc -> u16 qwc; u16 pad; + [+] Small hack in Memory.c for ba000006 + (linuzappz) + + * 17/09/03:[-] Corrected a unpack bug i forgot ;) + [+] Implemented mskpath3 / m3r flags + [-] Fixed rom1.bin lookup for linux + (linuzappz) + + * 16/09/03:[-] Linuz fixed the macro bug hanging Visual Studio + (Gold-linuz) + + * 16/09/03:[-] More bugfixes/additions to Vif/VUs + (linuzappz) + + * 15/09/03:[-] Fixes lots of bugs in Reg Caching, now other demos work. + (GoldFinger) + + * 13/09/03:[-] Some fixes to the subq in cdvd.c (Florin) + + * 13/09/03:[-] Fixed the reg caching bug in tut1. + [*] Changed the DEFINE for reg caching for the config expert put on the CPU + screen, now we have both way to test. Thanks Expert. + (GoldFinger) + + * 13/09/03:[+] Added an option for enable regcaching or not.Now goldfinger should make + support for that!! (shadow) + + * 12/09/03:[-] Fixed the normal rec bug + [+] Added lots of new instructions for reg caching now all tutorials work + (demo 1 is strange), 3stars work also. + (GoldFinger) + + * 12/09/03:[-] Small bugfixes to Vif/VUs + (linuzappz) + + * 10/09/03:[*] More work on ipu (Florin) + + * 10/09/03:[-] New recompiler code wasn't compiling over linux, now it's ok + [-] Fixed VU memory64 writes masks + [+] Added Stats.c/h, it will create a stats.txt with some stats info, + if you define a NOSTATS in Common.h that will not be used + (linuzappz) + + * 09/09/03:[*] Improved the filter of ELF loading in GUI + [*] Register caching started to work, tutorial demo2a is working, others are coming. + [*] Commied ix86.c again with previous fix as linuz removed it. + (GoldFinger) + + * 09/09/03:[-] Fixed __int64 to u64 in Misc.c + [-] Fixed small bug in Vif.h + [-] Fixed bug in GS.c, bios is ok now + [+] Implemented INTC_STAT/MASK and DMAC_STAT for 64bits + [!] I commited the last ix86.c/h, afaik you only + reformatted it gold, please don't reformat my + code + (linuzappz) + + * 09/09/03:[-] Disabled host support for bios as it is buggy. + [*] Added/fixed SCMDs (2,3,1A) in cdvd.c (Florin) + + * 08/09/03:[+] Vif0/1 regs are now mapped to hardware + (linuzappz) + + * 08/09/03:[-] fixed bug in cpu ops debugger. Now all opcodes should appear .(For you goldfinger!) + (shadow) + + * 07/09/03:[+] Completed phase 1/2 of adding host support for bios. (Florin) + + * 06/09/03:[-] Fixed bug in rec when using ezmpeg + * 06/09/03:[*] Re-structuring the whole recompiler to make it easier for + debug and for the sake of understanding + (GoldFinger) + + * 06/09/03:[*] Many things fixed/changed in ipu files (Florin) + + * 05/09/03:[+] Hot keys for savestates in win32 + F1 -> savestate + F2 -> change the slot + F3 -> loadstate + [+] checkbox for enable the patches in cpu dialog + (shadow) + + * 05/09/03:[+] Some more VUmicro debugging + (linuzappz) + + * 05/09/03:[+] Added VDEC & BDEC; now m2v files work but ipu files do not + (Florin) + + * 05/09/03:[-] bug fixed in ifpu.h (shadow) + + * 04/09/03:[+] Added Init of Plugins before Loading of + savestates. + [-] LoadOthers in WinMain.c had a plugin init + missing fixed that. + [!] Fixed GSsoft aswell. And increased vRam size from 4*1024*1024 + to 2*4*1024*1024 as OpenGL doesn't handle wrapping around in + memory. + (asadr) + + * 04/09/03:[+] HSync stuff, and better CSR/IMR handling + [+] Few more FPU insts in ix86.c/h + [!] Please tell me if something is now screwed :) + (linuzappz) + + * 04/09/03:[-] ipu fixes to dmas and vdec (Florin) + + * 02/09/03:[-] fixed the patch system + (goldfinger) + + * 02/09/03:[*] working savestates in win32 :) + (shadow) + + * 01/09/03:[*] Working savestates for linux :) + (linuzappz) + + * 02/09/03:[-] Bug fixes in IPU.c (still hacky when returning BP) + Now ezmpeg gets to VDEC;) (Florin) + + * 01/09/03:[-] Fixed old bug in Sio.c/CdRom.c + (linuzappz) + + * 30/08/03:[+] sceCdReadSubQ <- that is a bad name; it look more like + a gettoc entry (SCMD2) (Florin) + + * 29/08/03:[+] Started the register caching implementation, not ready to test yet + some new x86 opcodes to x86.c and .h iR5900.c is completely changed + a new define for iR5900.c is used to enable reg caching. + (GoldFinger) + + * 29/08/03:[-] Removed 3DNOW code is the FPU since 3DNOW is 64bits, + and FPU is 32bits + [+] Workaround in ElfHeader.c for pukklink, so it will + load ok with Run Cd + [+] Savestates :D + [-] Maybe fixed patches, blah :P + (linuzappz) + + * 27/08/03:[+] CdGetToc + CdReadSubQ + [*] Changed PS2Edefs specs 0.4.3 / CDVD v3 + [*] Changed back the CDVDgetTD function to have a 2nd param: cdvdTD + (Florin) + + * 26/08/03:[-] Fixed patching bug in BiosInit.h that was used only for scph10000 + (Florin) + + * 26/08/03:[*] SPR address in DMAs are now masked with 0x0fffffff + (linuzappz) + + * 25/08/03:[-] Fixed patch stuff + (shadow-linuzappz) + + * 25/08/03:[-] Fixed IDEC bitstream decoding. Now, all *.ipu files + should work fine (Florin) + + * 25/08/03:[-] Fixed VIF Transfers to include MARK reg in VIF0 aswell. + (asadr) + + * 22/08/03:[*] Changed the SSE opcodes to Macro mode (thanks Linuz) and linuz added some more + (GoldFinger) + + * 22/08/03:[-] Changed DEV9 stuff to use DEV9 plugins + (linuzappz) + + * 21/08/03:[+] Added SSE instructions ADDPSRtoR, ADDPSMtoR, SUBPSRtoR, SUBPSMtoR, MULPSRtoR, + MULPSMtoR, MINPSRtoR, MINPSMtoR, MAXPSRtoR, MAXPSMtoR, SQRTPSRtoR, SQRTPSMtoR, + RSQRTPSRtoR, RSQRTPSMtoR, RCPPSRtoR, RCPPSMtoR, CVTPS2PIRtoR, CVTPS2PIMtoR, + CVTPIPS2RtoR, CVTPIPS2MtoR, CMPEQPSRtoR, CMPEQPSMtoR, CMPLTPSRtoR, + CMPLTPSMtoR, CMPLEPSRtoR, CMPLEPSMtoR to ix86.c ( need to compile and check ) :P + (GoldFinger) + + * 21/08/03:[+] Added Patch.c + (shadow-linuzappz) + + * 19/08/03:[+] Fixed bug in PsxHw.h, thanks to psycho_tr + (linuzappz) + + * 15/08/03:[+] More to SMAP + (linuzappz) + + * 14/08/03:[-] Fixed Debugger/RDebugger + [!] There is still one bug left i saw in the RDebugger, + that's the threads are not ended ok, but i'll leave + that to you florin :) + (linuzappz) + + * 12/08/03:[*] Changed the time in CDVD.c and some WIN32 defines to __WIN32__ + (Florin) + + * 08/08/03:[+] Started SMAP/DEV9 stuff + (linuzappz) + + * 06/08/03:[-] Fixed MFIFO for GS dma + (linuzappz) + + v0.41: + * 05/08/03:[-] Uncommented some sif WIP stuff :) + [*] Addeded 0x00100008 PC for cpuExecuteBios as well + [-] Fixed silly bug in CDVD.c for DvdReads + (linuzappz) + + v0.4: + * 29/07/03:[-] Fixed bug in Sif code ;) + (linuzappz) + + * 26/07/03:[-] Fixed the dma memory checking for the scratchpad, + and implemented it over the remaining dmas + (linuzappz) + + * 25/07/03:[-] GSdma now ends when a transfer is outside the memory + [-] Bugfix to Sif1 dma + [-] Some changes in the ICFG write code, and + when D5_CHCR == 0, psxSu32(0x30) = 0x40000; + (linuzappz) + + * 22/07/03:[-] Counters fixes/improvements + [*] Improvements on CdRead/DvdRead + [*] Better Sif1/0 handling + (linuzappz) + + * 22/07/03:[+] New PS2Edefs 0.4.0 :) + (linuzappz) + + * 20/07/03:[-] DvdRead was really 2064 :P + (linuzappz) + + * 19/07/03:[-] Fixed BIG stupid bug in FiFo.c that i left there:P + [!] I'm ashamed:( + [*] Fixed getBits function with back buffer;) + [!] I'm proud of that B-) (Florin) + + * 18/07/03:[-] Fixed includes for Mpeg.c/yuv2rgb.c + [-] Modified DvdRead, uses 2048 blocksize, experimental ;) + [-] CDVDgetTD had to return s32, not u32 + [*] Some reorganization for the rec + (linuzappz) + + * 18/07/03:[-] Fixed some memory allocation bug in IPU.c + [i think there are more, searching...:P] (Florin) + + * 17/07/03:[-] Fixed another Sio bug ;) + [-] Fixed MULT1/MULTU1, s64 was really s32 + [-] Commented out the interrupt delay thingy ;), was causing + troubles with Kengo 2 + [+] Implemented DvdRead + (linuzappz) + + * 17/07/03:[-] Fixed bug in FiFo.c that caused flickering between movies + [*] Fixed color conversion (Florin) + + * 16/07/03:[-] Now we can boot games though bios :) + [-] Fixed 32bits shifts in Interpreter.c + (linuzappz) + + * 16/07/03:[*] Fixed (somehow:P) IDEC so that .ipu files works a bit (Florin) + + * 15/07/03:[*] Changed cdvdLoc stuff to lsn + [-] PsxDma10 now will just return if bcr < 4 + [-] Corrections to IPU1/0 dma transfers, untested but should be fine ;) + [!] Breaks compat with current cdvd plugs + (linuzappz) + + * 15/07/03:[+] CSC + PACK ipu commands Fixes to bitstream decoding (Florin) + + * 14/07/03:[-] Really implemented MFIFO now ;P + [!] mfifo.elf works just fine now, also tekkentag reaches a bit further + (linuzappz) + + * 14/07/03:[+] Some more work on IntraDECoding for IPU (florin) + + * 14/07/03:[-] Some cleaning over Sif.c + [+] MFIFO implemented in both GS/VIF + [-] Fixes to xpadman + (linuzappz) + + * 13/07/03:[*] VUmicro code now can run in "async mode" + [-] Fixed TTE in SPR1 dma + (linuzappz) + + * 10/07/03:[-] Fixed bug in R5900.c when HLE mode was on + [-] fileio ain't crashing anymore when the file is not there + [-] Fixed interrupts on VifDma.h + (linuzappz) + + * 09/07/03:[-] Fixed bug in GS dma transfers when TTE is enabled. + Was passing wrong size of qword now it is GSgifTransfer3(ptag+2, 4) + + * 08/07/03:[*] In Win32 cdvdReadRTC gets correct time. (Florin) + + * 08/07/03:[-] Fixed stupid bug in SPR1 dma, thanks florin :) + (linuzappz) + + * 07/07/03:[-] Fixed bug in Vif UNPACK cmd, tops was *16 ;) + [*] GSgifTransfer/2 => GSgifTransfer1/2/3 (PATH1/2/3) + [*] Updated GS.c with VifDma.h asadr changes, commented the TTE + transfer by now + [*] Updated as well the SPR1 dma + [!] Note that now all vu1 demos work :D + (linuzappz) + + * 06/07/03:[+] Implemented cdvdReadKey + (linuzappz) + + * 05/07/03:[+] VCALLMS/VCALLMSR now are implemented + [*] SPU dma4 now has a delay base of 0x10000 + [-] VifDma.h is now mostly as before asadr rewrote it + last time, since that way had problems with the TTE chcr + flag, now go check the bios Browser ;) + (linuzappz) + + * 04/07/03:[-] IOP won't die now after cpuRegs.cycle overflows :), R5900.c + (linuzappz) + + * 03/07/03:[-] Fixed WriteRTC and bug in Sio.c + (linuzappz) + + * 03/07/03:[+] Some IPU commands (BCLR,FDEC,SETIQ,SETVQ,SETTH) & IPU fifo + (Florin) + + * 02/07/03:[-] Cleaned a bit VifDma.h + [*] Modified the DmaExec macros, now the Dmas take care + to interrupt and to clear the STR bit + (linuzappz) + + * 30/06/03:[*] Usb hack ;), PsxHw.c + (linuzappz) + + * 29/06/03:[*] Modified Iop DMAs for async processing, only for spu/spu2 by now + [-] Vif dma refe/end now sets the tadr to 0, tek4 loops else, but + now is crashing after ;) + [!] sven shows one screen now, and others want to ;) + (linuzappz) + + * 29/06/03:[-] Removed the experimental code i added yesterday from CDVD.c/h + [*] Improved EE/IOP Rcnts + (linuzappz) + + * 28/06/03:[*] More on iop rcnts rewrite + [+] Experimental code in CdRead, now if the lsn sector is + the same than the last one readed it will add nSectors + to it, ie. it readed 2 sectors from 0:2:16; and then + it issues another cdread with the same lsn, it will read + from 0:2:18. + (linuzappz) + + * 27/06/03:[*] Started iop rcnts rewrite, untested and more to come ;) (linuzappz) + + * 27/06/03:[-] Some fixes on iop rcnts + [+] Implemented the SPU2async func + (linuzappz) + + * 26/06/03:[-] Really fixed HLE mode ;). (linuzappz) + + * 26/06/03:[-] Small CDVD.c corrections. (linuzappz) + + * 24/06/03:[*] Fixed elf loader at least not to crash at bad elfs. (Florin) + + * 23/06/03:[*] Added "rom1.bin" as a valid file for rom1 filesystem. (Florin) + + * 23/06/03:[-] Small fix to CDVD.c, maybe fixed a time out problem + with some cdvdman versions. + (linuzappz) + + * 20/06/03:[+] Some mcds work, PsxSio2.c, Sio.c + (linuzappz) + + * 17/06/03:[+] SPU dmas now call the correct funcs, PsxDma.c + (linuzappz) + + * 17/06/03:[-] Fixed Sio2, PADs are working :D, Sio.c, PsxSio2.c + [-] Fixed language in CDVD.c, now's english again :) + (linuzappz) + + * 16/06/03:[-] Better error handling over CDVD.c + [+] ROM1 stuff, Memory.c/h, PsxMem.c, iR3000A.c, iR5900.c + [!] PCSX2 now detects the rom1 in this way: ie. + you use scph10000.bin, then you must have + in the same dir scph10000.bin.rom1 or scph10000.rom1 + (linuzappz) + + * 16/06/03:[-] Rewrote the VIFtransfer and VIFdma again. Better speed and + compatibility this time (asadr). + + * 16/06/03:[*] Reoverwritten CDVD.c/h with my CDVD.c/h, + this is simpler, more direct and faster, + CdRom.c, PsxHw.c, R3000A.c, PsxCounters.c, + Memory.c + [-] Kinda workaround i think in the ICFG reg + (1450), PsxHw.c + [-] Removed VSyncHack at least ;), WinMain.c, + Common.h, ini.c + [!] Games start showing something :D:D + (linuzappz) + + * 15/06/03:[+] More dummy cdvd scmd (Florin) + + * 14/06/03:[-] Fixed SIF0 transfers, PsxDma.c, PsxHw.c/h. + [*] Cleaned up SIF1, R3000A.c, Sif.c + [+] Added a Run CD menuitem, WinMain.c, resource.h + [!] Bios shows something :D:D + (linuzappz) + + * 12/06/03:[-] Fixed bug in release version (unsafe compiler optimizations:P) + (Florin) + + * 11/06/03:[+] More functions on lle cdrom (cdread) (Florin) + + * 10/06/03:[+] Rudely overwritten linuzappz work in CDVD.c/.h + [!] Sorry man, i think i did the best...i created a framework + with names and so on. Also we have to talk about;) (Florin) + + * 10/06/03:[+] Started CDVD.c/h, moved old CDVD.h to CDVDlib.h, + PsxMem.c, PsxCommon.h (linuzappz) + + * 10/06/03:[*] Added new SPU2 dma functions plugin.c + [*] New PS2 plugins specifications 0.3.2 (shadow) + + * 09/06/03:[+] Add SPU2read/SPU2write to PsxMem.c + [-] Few fixes to PsxCounters.c + [+] Added PsxDma7, PsxHw.c, PsxDma.c (linuzappz) + + * 09/06/03:[-] Sif0 chaining fix (Florin) + + * 08/06/03:[+] Started with SIO2... (Florin) + + * 07/06/03:[-] Fixes to SIF0/SIF1 :D + [!] Now OSDSYS loads ok, and so does several modules in iop, + bios now gets stuck in a Deci2Call (reqsend) + (linuzappz) + + * 07/06/03:[-] Fixes0, Fixes1 (Florin;) + + * 06/06/03:[*] Fixed and improved the VIF Dma transfers and rewrote the VIF_Transfer. It's far + more compatible and fast ( all vu1 demos work:D ). (asadr) + + * 06/06/03:[*] Fixed sif1 (...waiting for a better solution;) (Florin) + + * 05/06/03:[-] Sif1 flags fixes (still buggy?) (Florin) + + * 04/06/03:[*] Some adjustments to PsxInterpreter.c (Florin) + + * 03/06/03:[-] Set the PSXCLK to 36.864 Mhz, by now, later PSXCLK should be + a variable, Common.h + [*] Improved iop hw maps, added DMA9/10, PsxDma.c/h, R3000A.c, PsxMem.c + [+] Added RCNT3/4/5 in PsxCounters.c/h, PsxBios.c, PsxHw.c/h + [+] Added a bit more of loggin in PsxInterpreter.c + [-] 0xba000006 now returns 1, for some bioses, Memory.c + [*] Improved dmaSIF1, SIF.c, and cleaned dmaSPR1, SPR.c + [!] Finally my name is on the v0.4 :P + (linuzappz) + + * 03/06/03:[-] Fixed GetPS2ElfName in Misc.c (Florin) + + * 22/05/03:[+] new flags code based in nsx2 flag code. vuflags.c vuflags.h + [*] vuops.h rewrote almost all the vu opcodes with new flags code Upper Instructions + should be okay but might still are some issues with the Lower instructions. + [-] added proper reset in vu1micro.c + [*] added the new vcnet files for compile properly with vuflags + (shadow) + + * 21/05/03:[-] Fully fixed of recSQ in iR5900.c. + [-] Fixed EMMS_TRACING on none 3DNOW machines, EMMS_TRACING now turned on again. + [*] Added CPU autodetection to iR5900.c + [!] #define CPU_3DNOW is not used now. + (Alexey Silinov) + + * 20/05/03:[-] Dummy fix of recSQ in iR5900.c. Recompiler back to work again. + (Alexey Silinov) + + * 10/05/03:[*] Improved fpu.c, just code optimizing in cvt_s, cvt_w, all branches opcodes and + some code organizing. + (GoldFinger) + + * 02/05/03:[+] Added some ioprps to Misc.c (Florin) + + * 02/05/03:[+] Some more work on Padman module 800100Xpadman.c , 800100Xpadman.h (shadow) + + * 30/04/03:[+] Added 2 more syscalls in BiosSysc.h (Florin) + + * 29/04/03:[+] More threads functions. (see threads.txt) + [!] To see threads switching, comment the 3 instructions + at the top of _ThreadHandler function (Bios.c) + (Florin) + + v0.3: + * 01/05/03:[-] Fixed dvd iso issue (roundup of numsectors ...+2047/2048) + in CDVDiso.c (Florin) + + * 30/04/03:[-] Fixed bug in CFC1, Fpu.c + [-] Fixed branches isns on VUops.h, US was instead of SS + [-] Added newline at oef for MMI.c, *mtapman.c + [-] Included in *loadfile.c + [*] Few changes over languages, Misc.c/h, WinMain.c + (linuzappz) + + * 29/04/03:[-] Added a workaround for the interrupt latency in the rec, + R5900.c + (linuzappz) + + * 28/04/03:[-] Fixed a bug in BiosInit.h, instead of 16 dmas there was 15 + [-] Counters 0,1,2 had interruption disabled, Counters.c + (linuzappz) + + * 27/04/03 [-] WinMain.c now only calls GetPS2Elf if on HLE mode + [-] parseCommandLine had a bug when not using HLE, ElfHeader.c + [*] Implemented memRead/Write128, Memory.c/h, iR5900.c + [*] Implemented a better way to count opcodes in iR5900.c + [*] Rewrote AddIntc/DmacHandler, RemoveIntc/DmacHandler, Bios* + (linuzappz) + + * 24/04/03:[*] More threads functions. (see threads.txt) (Florin) + + + * 23/04/03 [-] Undo the "VU0/1 control/integer regs are now the same" update, + VU*, DebugReg.c, (goldfinger-linuzappz) + [+] Implemented latency interrupt thingy ;), R5900.c/h + (linuzappz) + + * 21/04/03 [-] DMAC interrupt wasn't setting the cause in a0, Bios.c + [+] DMACTable is now being used with DefaultDmacHandler, Bios.c/h, + BiosInit.h, HLE.c + [+] Added dummy handles for mtapman901/3, Rpc_services.h, *mtapman* + [*] VIF0 code is now shared with VIF1 code, Vif.c, VifDma.h + (linuzappz) + + * 23/04/03:[*] Fixed RFU061_InitHeap, EndOfHeap, CreateThread, InitThreads + (Florin) + + * 21/04/03:[+] Started threads update (Bios.c/BiosInit.h/BiosSync.h/ + deci2_dbgp.c/ElfHeader.c/.h) (Florin) + [-] Fixed fifos a bit:) (FiFo.c/Hw.h) (Florin) + [*] Fixed VIF1 regs display in Hw.c. I know that those were handeled + but now is more clear (Asad-Florin) + + * 20/04/03:[-] Fixed a bug in WinMain.c. In case of the debuggers with HLE bios, + cpuExecuteBios() was not called, so the tlbs and all stuff + were not inited properly. (Florin) + + * 20/04/03:[-] Fixed a bug in VUmicro.h + [+] VIF1dma now handles 'from Memory' transfers, Vif.c + [-] F11 now un/sets Log, F12 un/sets symbol logging, WinMain.c + (linuzappz) + + * 19/04/03:[-] Fixed a bug in Interpreter.c + [-] VU0/1 control/integer regs are now the same, VU*, DebugReg.c + [*] Cleaned a bit GS.c + (linuzappz) + + * 17/04/03:[-] gsRead32 wasn't calling GSread32, lol :), GS.c + [+] Implemented more syscalls, as dummy for now, Bios.c/h, BiosSysc.h, + HLE.c + [*] Removed the CSR revision/intelace bits over GS.c + [+] Added GSirqCallback to PS2Edefs.h, GS.c, Plugins.c + [+] VIF1 cmd now handles the i bit, still not 100% correct, Vif.c + [-] Fixed several VIF1 bugs, Vif.c + (linuzappz) + + * 16/04/03:[*] biosInit is now called at hle_bootstrap, Bios.c, HLE.c, WinMain.c + [+] Added _TlbInit at biosInit, Bios.c + [*] Deci2Call is now better coded, Bios.c, BiosSysc.h + [-] Fixed some bugs over AddIntcHandler/AddDmacHandler, BiosSysc.h + [+] bios_SetSYSCALL is now implemented, BiosSysc.h + (linuzappz) + + * 17/04/03:[+] Breakpoint support for debugging bios. (Florin) + + * 16/04/03:[-] Readded an update that linuzappz missed in his src, + that was then used by many pcsx2 team members. [it is about my 16/03/2003's] + [+] sceCdReadIOPm in 80000595.c + (Florin) + + * 14/04/03:[*] Memory access bug in deci2 that made pcsx2 to crash. hi linuzappz + [+] MC functions fixes/dummies over 80000400mcserv.c + (Florin) + + * 12/04/03:[*] CP0Count now adds 2 every opcode, instead of 4 + (linuzappz) + + * 12/04/03:[-] Bios VSyncSetFlag is now fixed ok, Bios.c + [*] Started to implement new Bios code, Bios.c/h, BiosInit.h + BiosSysc.h, EEregs.h, HLE.c, R5900.c/h + [!] Please tell me if this update creates some incompatibility, + or something else works now, since the INTC/Exceptions code is + much better now :). + (linuzappz) + + * 08/04/03:[-] DMAC_STAT CIS? bits are now set after a DmaExec, Hw.c + [-] Fixed bug when a plugin returned -1, WinMain.c + [*] Cleaned a bit GSdma, GS.c + [-] Fixed bug in INTC interrupts, Bios.c + (linuzappz) + + * 07/04/03:[+] Added cpu opcodes debugger. Use the CPU ops button in the debugger + and it will create a cpuops.txt with the opcodes that used. + Debugger.c pcsx2.rc, cpuopdebug.c cpuopdebug.h . Now works only in + interpreter. (shadow) + + * 04/04/03:[+] Added LabelGreets/LabelAuthors to Misc.c/h, AboutDlg.c + [*] Languages code over pcsx2 is a bit better, WinMain.c + [+] Added Log to STDOUT over Logging dialog, pcsx2.rc, + Misc.c, resource.h + [+] Now we're emulating the VSync Start and the VSync End, Counters.c + (linuzappz) + + * 26/03/03:[*] Optimized PLZCW in mmi.c (GoldFinger) + [-] fixed MADD1 and MADDU1 in mmi.c (GoldFinger) + [-] PSLLH, PSRLH and PSRAH (sa needed to be the first 4 bits only), + mmi.c (GoldFinger) + [-] PADDSW, the manual seems to be wrong (well it is) so I tryed + to fix it, mmi.c (GoldFinger) + [-] PADDSB, PSUBSB, the comparision was wrong, mmi.c (GoldFinger) + [-] PADDSW, PSUBSW, PADDSH, PSUBSH, PADDSB, PSUBSB, PADDUW, PSUBUW, PADDUH, + PSUBUH, PADDUB, PSUBUB, the sum and sub need a conversion to the higher + value(s16,s32 and s64), mmi.c (GoldFinger) + [-] PMINH, the comparision needs to be signed, mmi.c (GoldFinger) + [-] PHMSBH, was wrong, fixed, mmi.c (GoldFinger) + [-] PEXEH, PREVH, was using _Rs_ when only _Rt_ should be, mmi.c (GoldFinger) + + * 26/03/03:[*] fixed fpu bugs. Hi linuzappz :) . Tmip is correct in interpreter mode finally + fpu.c (shadow) + + * 24/03/03:[+] Fixed Trap instructions, hi shadow :), also cleaned + up a bit the Interpreter.c (linuzappz) + + * 22/03/03:[+] Fixed the 'Load ELF File' issue, added the Memory Dump menu, + WinMain.c (Florin-linuzappz) + [!] I forgot the changelog entry in the last update, + please read it (linuzappz) + [!] I've updated again the pcsx2.po, florin sent one without the + linux port messages since i've never updated u the linux port ;) + + * 20/03/03:[+] Added GSsetWindowInfo, WinMain.c, PS2Edefs.h, Plugins.c + [+] Added MiltuLingual support, using gettext, WinMain.c, Plugins.c, + AboutDlg.c, ConfigDlg.c, pcsx2.rc, Memory.c, iR5900.c, iR3000A.c, + pcsx2.dsp, Sio.c, R5900.c, PsxMem.c, Hw.c, Common.h, ini.c, + resource.h, Win32.h + [-] Fixed IPU.c when IPU_LOG is not defined + [-] Fixed padman/loadfile.c when RPC_LOG is not defined + [*] Removed dummy memory area, Memory.c/h, PsxMem.c/h + (linuzappz) + + * 17/03/03:[*] add some more stuff to DisR5900asm.c . win debugger is better now (shadow) + [-] fix a bug in rec table (visubiu not exist) in macromode .. recCop2.c (shadow) + [!] recheck vu micromode tables. Hmm they seem correct (shadow) + + * 16/03/03:[+] Added "next" (aka "step over") support for deci2 debugging + [+] Added TTYP support (log redirection) (buggy;have to test more) + (Florin) + + * 15/03/03:[*] move loadfile to rpc using florins protocol hi florin;p (shadow) + + * 15/03/03:[*] Fixes to breakpoints in deci2 stuff (Florin) + + * 13/03/03:[+] More deci2 dbgp stuff (BREAK/CONTINUE/RUN) + [!] It is not fully tested. This is EXPERIMENTAL code. + [!] It may contain many bugs and there are also "known issues". + [*] changed names of shadow's padman files and made the according + changes to rpc_services.h & bios.c (Florin) + + * 12/03/03:[*] rewrote padman+xpadman according to florins protocol on RPC folder + [*] removed code from bios.c according to pad handling.. + [+] Add fix that make analog mode to work partially ;) (try turnip) (shadow) + + * 10/03/03:[+] Added more mem mappings to PsxMem.c & Memory.c in order + not to crash the emu when read from a not-covered area (Florin) + + * 10/03/03:[-] fix small bug in winmain that didn't let console to close winmain.c (shadow) + + * 04/03/03:[+] Added remaining UNPAKs and cleaned a bit, Vif.c/h (linuzappz) + + * 03/03/03:[*] replace console writes of IPU with IPU_LOG Ipu.c (Shadow) + + * 01/03/03:[-] Fixed partially FIFO bug; (unlogged change:P) + [!] I haven't fixed it all because is very messed up. + [+] Added a small fix to PsxMem.c in order to allow sifman to stay resident. + (Florin) + + * 28/02/03:[+] Added support for remote debugging with tcp/ip deci2 protocol. + [!] Not finished nor fully tested + [!] There's an issue on Win98 with winsock2 closing [have 2 check that] + [!] New src dir (rdebug\*.*), Win32\RDebugger.c/.h; + [!] also added ws2_32.lib to link libraries + (Florin) + + * 25/02/03:[+] Added 8bit DMAs to Hw.c + [+] More UNPACK cases to Vif.c (linuzappz) + + * 23/02/03:[+] Added BC0s in COP0.c + [!] the BC0s are still fake, but they should be ok ;) (linuzappz) + + * 22/02/03:[*] Now if the Recompiler fails to initialize it'll switch to interpreter (linuzappz) + + v0.2: + * 18/02/03:[-] Small fix in winmain.c in SysInit() causing a crash (shadow) + + * 12/02/03:[+] Added new DMA transfer codes to VIF.c, GS.c + [+] Added the new clipping code to the VU + [*] Fixed most of the VU ops. Better compatibility + [!] The new dma transfer code is 4-5% faster than the last one. :) + + * 12/02/03:[*] Fixed iR5900.c to include iR5900.h, moved some stuff from + ix86.h to iR5900.h + [-] Fixed CPU_LOG flags over iR5900.c/recCOP2.c + [+] Added some SysPrintfs over iR5900.c after x86Init + (linuzappz) + + * 26/01/03:[+] Added some defines in Hw.h (linuzappz) + + * 26/01/03:[-] Fixed include in IPU.c, 'common.h' for 'Common.h', + SJdata.c, 'rpc/...' '...' (linuzappz) + + * 04/02/03:[+] ix86.c: Added CPUID for linux. + SSE is autodetected now (linuzappz) + + * 28/01/03:[+] ix86.c: CPUID added. It will work if u don't change CPU on the FLY. :) + [*] ir5900.c: recompiler changed for CPUID. + [*] recCOP2.c: recompiler changed for CPUID. + (Alexey Silinov) + + * 27/01/03:[+] ir5900.c: recompile of DSRAV,PMINW,PMAXW added. + [!] I'am not sure in this code.Need find demos that use it. + [+] ix86.c: PANDNRtoR,PANDMRtoR added. + (Alexey Silinov) + + * 25/01/03:[-] ir5900.c: Some fpu opcodes for non 3DNOW version fixed with EMMS_TRACE on. + After Linuzappz request:memory opcodes + [-] (LB,LBU,LH,LHU,LW,LWU,.....,SB,SH,SW,...) fixed for version with EMMS_TRACE on. + [-] recCOP2.c: Bugfixed for non 3DNOW version(added another recCOP2SPECIAL1t,recCOP2SPECIAL2t tables). + + [!] Now EMMS_TRACE will work much better. + (Alexey Silinov) + + * 24/01/03:[+] ir5900.c: DSRA,DSRA32 recompilation added. + [*] shifts by _Imm_=0,_Rs_=0 optimized. + [+] PMFHI,PMFLO,PAND,PXOR,PMTHI,PMTLO,POR,PAND now can recompiled to SSE instructions. + [-] JUMPS bugfixed by putting SET_FPUSTATE before it, + because cpuBranchTest use FPU. Pillgen now ok with EMMS_TRACE. + [!] #define CPU_SSE in ix86.h if you have Pentium3/4 or Duron7/AthlonXP. + (Alexey Silinov) + + * 24/01/03: Fixed iR5900.c to compile without 3DNOW (linuzappz) + + * 24/01/03: Moved the emms's in Hw.c, GS.c, Memory.c to iR5900.c (linuzappz) + + * 24/01/03: Rewrote ini.c, same code as Pcsx now :) (linuzappz) + + * 24/01/03: Removed the browse info option over pcsx2.dsp (linuzappz) + + * 24/01/03: Some fixes in Hw.c, missings #ifdef HW_LOG/#endif, + reordered the ipu address and the IPU1 dma was wrong. (linuzappz) + + * 21/01/03: remove the fpu flags reorganize fpu.c a bit. Send code for using it + as reference to all the pcsx2 members. + + * 21/01/03:recCOP2.c + 75% of COP2 ops recompiled used 3DNOW. + only sign MAC flags updated. + Zero,Sticky will be done later. + (Alexey Silinov) + * 19/01/03: + ir5900.c: + Fixed recompiling of RSQRT_S for3DNOW,recPCPYUD(tskin.elf now ok), + recC_LE for x87 FPU(untitled.elf last part now ok). + Optimizing recompile of recADDI,recADDIU,recDADDI,recDADDIU, + recANDI,recORI,recXORI,... (check _Rs_,_Rt_= =0,!=0). + Optimiing recMOVZ,recMOVN only one JMP CC,.. needed. + Added #define EMMS_TRACE to. + Added #define ARITHMETICIMM_RECOMPILE,ARITHMETIC_RECOMPILE,etc. + (Alexey Silinov) + * 18/01/03: ir5900.c:Many recompiler opcodes fixed. + IPU DMA logging update. + (Alexey Silinov) + + * 18/01/03: Fixed fileio_lseek function in 80000001fileio.c. (Florin) + + * 16/01/03: Rewrite fpu and added two version of it. One with flags and + one without. The no flags version is much faster. + fpu.c ,r5900.h,common.h,r5900.c,ini, resources , winmain.c (shadow) + + * 15/01/03: Added memory mapping of IPU_CMD,IPU_CTRL,IPU_TOP,IPU_BP. + Added parsing of IPU commands. + (Alexey Silinov) + * 14/01/03: recMAX_S,recMIN_S,recC_F,recC_EQ,recC_LE,recC_LT-added. + recABS_S,recNEG_S-now don't use FPU. + ix86.c - 3DNOW opcodes added. + #ifdef CPU_3DNOW then FPU recompiled using 3DNOW instruction set. + Now we are ready TODO FPU register cache on CPU_3DNOW. + gs.c add emms before GS read,write. + (Alexey Silinov) + + * 14/01/03: Fixed stupid bug in 80000001fileio.c (Florin) + + * 13/01/03: Fixed some issues in CDVDiso.c & 80000597cdvdfsv.c (Florin) + + * 11/01/03: Fixed fileio [important] functions up to ioprp255 (Florin) + + * 11/01/03 some more MMI opcodes in rec (alexey silinov) + + * 10/01/03 recPADDUB-changed,recPADDUH-added (Alexey Silinov) + + + * 09/01/03 + My copy&paste bugs in recPCPYUD,recPAND,recPXOR fixed. + Now EMMS() instruction writing only before FPU commands if FPU state is MMX.With it size of recompiled code is reduced. + !!Added macros SET_FPUSTATE,SET_MMXSTATE it's must before MMX or FPU instruction. + Fixed many ops.ExtSign32to64() don't used anymore. it's faster and smaller to do CDQ(). + recLUI,recPCPYLD optimized. + Added recompilation of PMAXH,PMINH,PCGTB,PCGTH,PCGTW,PCEQB,PCEQH,PCEQW,PEXTLW,PEXTUW. + ir5900.c,ix86.c, ix86.h + (Alexey Silinov) + + + * 07/01/03: Fixed MADD, MADDA, MSUB, MSUBA opcodes in FPU.c ( asadr ) + + * 07/01/03: added MTSAB,MTSAH in interpreter.c (asadr) + + * 07/01/03: Added Flags in FPU.c, fixed SQRT, DIV, RSQRT opcodes in FPU.c ( asadr ) + + * 07/01/03: add some opcodes in interpreter.c (shadow) + + * 07/01/03: small fix in mult1,multu1 in MMI.c (shadow) + + * 07/01/03: more addes in recompiler iR5900.c (Alexey Silinov) + + * 07/01/03: fixed MULT,MULTU,MULT1,MULTU1 in rec and added DIV1,DIVU1 iR5900.c + (Alexey Silinov) + + * 07/01/03: add several MMI opcodes to recompiler iR5900.c ix86.c ix86.h + (Alexey Silinov) + + * 07/01/03: Fixed libpad version issues; added scePadInit2 support in Bios.c (Florin) + + * 06/01/03: Added sceDvdRead function to 80000595cdvdfsv.c, CDVDiso.h/.c + Moved sifcall_cdvdfsvA from Bios.c to 80000592cdvdfsv.c (Florin) + + * 05/01/03: Fixed libmc version 80000400mcserv.c + Added support for cdrom device in LoadHeap function 80000003sysmem.c (Florin) + + * 05/01/03: Added D and I Flag checking in vuDiv and SQRT opcodes and some more fixes ( asadr ) + + * 05/01/03: Merge all the vu code fixes to the better possible one vuops.h (shadow) + + * 05/01/03: Several vu fixes vuops.h (Alexey Silinov) + + * 04/01/03: Added temporary fix to vuDIV, vuRSQRT, vuERSADD, vuERCPR, ERSQRT ( asadr ) + + * 04/01/03: Added vuERCPRL, vuESUM , vuEATANxz, vuESIN, vuEATAN, vuEEXP, vuRXOR ( asadr ) + + * 04/01/03: Fixed GetPS2ElfName Misc.c + Romanian version pcsx2ro.rc & spell fixes in pcsx2.rc (Florin) + + * 03/01/03: Added callback support in Bios.c + Added function name display support (if you know other places, plz add...) + (Florin) + + * 02/01/03: Fixed sceCdRead (cdvdfsv1.4 and more?) 80000595cdvdfsv.c (Florin) + sceCdSeek, sceCdPause, sceCdStop, sceCdStatus + + * 02/01/03: Added SLTI,SLTIU,SLT,SLTU iR5900.c ( Alexey Silinov) + + * 02/01/03: Added SETS8R ix86.c ix86.h ( Alexey Silinov) + + * 01/01/03: YAH HAPPY NEW YEAR :) + + * 30/12/02: Added Dump memory button in Debug dialog over Debugger.c (Florin) + + * 29/12/02: Start work on Savestates Common.h, Misc.c. Need to include zlib.lib in project (shadow) + + * 29/12/02: Fix small bug In ERET. COP0.c (shadow) + + * 29/12/02: Some more Vu opcodes in the vuops.h (shadow) + + * 29/12/02: Added BC2F,BC2T,BC2TL,BC2FL not sure if i check the right bit althought Vu0.c (shadow) + + * 29/12/02: Added HLE opcode over DisR5900.c (linuzappz) + + * 29/12/02: Fixed some bugs on rec mode, Memory.c, PsxMem.c, + ix86.c/h, iR3000A.c, iR5900.c (linuzappz) + + * 29/12/02: Fixed JALR in Interpreter.c (linuzappz) + + * 28/12/02: Fixed stupid old bug in iR5900.c (linuzappz) + + * 26/12/02: Added compiler detection code (Win32/WinMain.c) (Florin) + + * 20/12/02: Refixed new Threads code, a bit hacky still ;), Bios.c/h, HLE.c (linuzappz) + + * 20/12/02: Refixed Counters.c, GS.c (linuzappz) + + * 20/12/02: Changed some cop0 names over DisR5900.c (linuzappz) + + * 20/12/02: Fixed EXL bit on cpuException, R5900.c (linuzappz) + + * 20/12/02: Fixed ERET, COP0.c, Interpreter.c, R5900.h (linuzappz) + + * 19/12/02: fix bugs in fileio system 80000001fileio.c (florin) + + * 19/12/02: rewrite MMI mmi.c (linuzappz) + + v0.1: + * 17/12/02: Small cleaning for release (linuzappz) + + * 17/12/02: Fixed a comment in CDVD.h (linuzappz) + + v0.046: + * 17/12/02: FIXED THAT BASTARD BUG with interpreter + R5900.c (shadow) + + * 16/12/02: Fixed CDVDFS_read function (CDVDisodrv.c). (Florin) + + * 07/12/02: Added support for SjDATA filesystem (SJdata.c/.h). + Small fixes in 80000003sysmem code. + Moved OpenPlugins call from debugger.c to WinMain.c + Added support for 0B001337cdvd rpc driver. (Florin) + + * 06/12/02: Fixed RPCVER for games that load ioprp.img. + Moved related code Bios.c to Misc.c. (Florin) + + * 05/12/02: Placed a guard in CDVDFS_init/CDVDisodrv.c + Added support for reading from cdvd in Elfheader.c/.h + Implemented RunCD option WinMain.c, GtkGui.c, Misc.c/.h (Florin) + + * 01/12/02: Made fileio_open more compatible with games (up to 2.0F/ioprp255) (Florin) + + * 30/11/02: Add test opcodes TGE,TGEU,TLT,TLTU,TEQ,TNE Intepreter.c (shadow) + + * 30/11/02: Add exceptions defines in R5900.h (shadow) + + * 01/12/02: Removed old VU0 code over VU0.c (linuzappz) + + * 31/11/02: Implemented CheckCdrom/LoadCdrom, still unfinished, Misc.c (linuzappz) + + v0.045: + * 31/11/02: Changed memRead32 for PSMu32 over Interpreter.c (linuzappz) + + * 31/11/02: Fixed CdRead, CDVDiso.c (linuzappz) + +// * 30/11/02: Added irqs for rcnt2/3, started thread HLE code rewrite, +// Bios.c, Counters.c (linuzappz) + + * 28/11/02: Fixed win32 fileio path, and some more small issues (linuzappz) + + * 27/11/02: Added BD0000X0 connection to 1000F0X0 and BC000000 ee memmap, + implemented direct rec clears, and added some more counters stuff, PsxMem.c/h, + Memory.c/h, iR3000A.c, iR5900.c, Counters.c/h, Hw.c, PsxHw.c (linuzappz) + + v0.044: + * 26/11/02: Added RPC handler for 80000595cdvdfsv + Fixes in iso handling system (read function can read more than 16KB) + Fixed issue with deci2call no.3 (junk re-printing) (Florin) + * 20/11/02: Automatic setting of RPCVER + (problems: 1. SDK samples do not load an ioprp; default is "2000";) + 2. starwars game load a ioprp.img; so RPCVER="0000") + Fixed bug in CDVDiso.c/CdRead(); check for null pointer + Fixed issue with the Joliet filesystem (Florin) + * 09/11/02: Added iso parsing & filesystem driver from libcdvd library by Hiryu & Sjeep + Added credits (Hiryu&Sjeep) to Aboutbox & Readme.txt + Changed the order of opening of plugins in Plugins.c/OpenPlugins() + Added (or moved code from bios.c) to handle RPC user & standard code + -works (or should work; needs intensive testing): + 014D704Enaplink, 80000001fileio, + 80000003sysmem, 80000592cdvdfsv, + 80000597cdvdfsv + -dummy (to be implemented; only params display): + 0B0110C5sjpcm, 0badca11amigamod(shadow), + 80000400mcserv,80000596cdvdfsv, + 80000601osdsnd + Added RPC_LOG logging stuff to debug.h, pcsx2.rc & resource.h + Added kputs handling for scePrintf in Deci2Call syscall in bios.c + (Florin) + + v0.043: + * 06/11/02: add some work for amigamod.irx HLE based on Florin + RPC code (shadow) + + * 21/10/02: implement some more opcodes for VU + flags in many opcodes + (shadow) + + * 19/10/02: Added more opcodes to VUops.h (from VU0.c), and started the implementation of flags, + VUflags.h, VU* (shadow-linuzappz) + * 12/10/02: Added fix for several bioses, Hw.c, removed hack for 30002R.bin R5900.c (linuzappz) + + * 06/10/02: Added 0xb2000000 map area as a 0x12000000 mirror, Memory.c (linuzappz) + + * 06/10/02: Added/Fixed some VIF1 unpack cases, Vif.c (linuzappz) + + * 06/10/02: Started Rewrite of SetGsCrt, Bios.c (linuzappz) + + * 05/10/02: Improved gsReads/Writes GS.c (linuzappz) + + * 28/09/02: Added iop HLE code for exceptions in PsxBios.c (linuzappz) + + * 24/09/02: Added ps2 bios check for config dialog in ConfigDlg.c/GtkGui.c (Florin) + + * 23/09/02: Added command line parsing for main's argc, argv in ElfHeader.c (Florin) + + * 14/09/02: Fixed small issue in PsxBios2.c/h, Bios.c (linuzappz) + + * 13/09/02: Fixed bug in Bios.c for sif_call (linuzappz) + + v0.042: + * 25/08/02: Fixed VU SQRT/RSQRT, also added ERSQRT, VUops.h (linuzappz) + + * 24/08/02: Added several stuff for IOP hle (linuzappz) + + * 09/08/02: Added: PADDSW, PSUBSW, PPACW, PADDSH, PSUBSH, PEXTLH, PPACH, PADDSB, PSUBSB, + PPACB, PEXT5, PPAC5, PABSW, PCEQW, PMINW, PADSBH, PABSH, PCEQH, PMINH, + PCEQB, PSUBUW, PADDUH, PSUBUH, PSUBUB, PEXTUB, QFSRV, PSLLVW, PSRLVW, + PINTH, PROT3W, PSRAVW, PEXCW, PEXCH, PINTEH, PMTHI, PMTLO, PEXEW, + PREVH, PEXEH, in MMI.c (GoldFinger) + + * 09/08/02: Changed: PADDUB to conform to defines (GoldFinger) + + v0.041: + * 11/08/02: More to VUops.h (shadow) + + * 10/08/02: Rewrote L/R Stores/Loads (linuzappz) + + * 05/08/02: Add some more opcodes to VUops.h some demos works again(shadow) + + * 04/08/02: Added VUops.h, VU0.c/h, still uncomplete (linuzappz) + + * 04/08/02: Added GSgifTransfer2 for PATH1, VU1micro.c, PS2Edefs.h, Plugins.c (linuzappz) + + * 03/08/02: Added unpack v4-32, Vif.c (linuzappz) + + * 02/08/02: Rewrote partially VUmicrocode, structures and stuff, VU1/0micro.c, VUmicro.h (linuzappz) + + * 02/08/02: Small change on Misc.c (linuzappz) + + * 01/08/02: cpuExecuteBios is now called before the LoadElf, WinMain.c (linuzappz) + + * 01/08/02: Added a couple of HW_LOGS in Hw.c (linuzappz) + + * 01/08/02: Fixed MFC2/CFC2 in DisR3000A.c (linuzappz) + + * 01/08/02: Added small hack on R3000A.c (linuzappz) + + * 01/08/02: Fixed bug in StartThread Bios.c (linuzappz) + + v0.040: + * 31/07/02: Small change in PsxInterpreter.c and PsxHw.c (linuzappz) + + * 31/07/02: Added CDVDgetTN and CDVDgetTD, PS2Edefs.h, Plugins.c, CdRom.c/h (linuzappz) + + * 30/07/02: Fixed Gte.c, now includes PsxCommon.h (linuzappz) + + * 30/07/02: Added GPU_LOG to Debug.h (linuzappz) + + * 30/07/02: IOP now has vsyncs, PsxCounters.c/h (linuzappz) + + * 30/07/02: Added PsxGPU.c/h, moved the GPU_xx stuff from PsxBios.c, PsxDma.c (linuzappz) + + * 24/07/02: Added psxSIF1transfer to R3000A.c,, Sif.c, still not working (linuzappz) + + * 24/07/02: Added a couple of address more to PsxHw.c (linuzappz) + + * 24/07/02: Added zeroEx func to trace writes to stdout, PsxInterpreter.c (linuzappz) + + * 24/07/02: Improved bios_write, PsxBios.c (linuzappz) + + * 24/07/02: PsxMem.c now handles the full 4mb of the bios mem (linuzappz) + + * 24/07/02: Hack for 30002R bios, R5900.c (linuzappz) + + * 24/07/02: Fixed BNEL, BEQL in disR5900.c (linuzappz) + + * 22/07/02: Remove biosCall, now use only biosException, Bios.c/h, Interpreter.c, + R5900.c (linuzappz) + + * 21/07/02: Intialaze of VU1 vu1microc,vumicro.h,R5900.c (shadow) + + * 21/07/02: implement VIF0transfer same way as VIF1transfer vif.c (shadow) + + * 20/07/02: Add debug logs in vu0,vu1 micromode + vu0 execute vu0micro.c, + vu1micro.c,vumicro.h (shadow) + + * 18/07/02: Clean up vu0 macromode vu0.c (shadow) + + * 19/07/02: PsxMem.c now handles 0xbf80xxxx hw addresses (linuzappz) + + * 17/07/02: IOP PRid is 0x1f (not 0x2), R3000A.c (linuzappz) + + * 17/07/02: More to VU1micro.c (shadow) + + * 14/07/02: Added psxMemRLUT/psxMemWLUT instead of only psxMemLUT, PsxMem.c/h (linuzappz) + + * 11/07/02: Added MADD1, MADDU1, PMFHL, PCGTW, PMAXW, PADDH, PSUBH, PCGTH, + PMAXH, PADDB, PCGTB, MMI.c (goldfinger) + + v0.039: + * 08/07/02: Commented the 0xe000 hw dma test, for jasper, Hw.c (linuzappz) + + * 08/07/02: Changed PADreadStatus for PADstartPoll/PADpoll, Plugins.c, PS2Edefs.h, Bios.c, + PsxBios.c, Sio.c (linuzappz) + + * 07/07/02: More to Vif1 dma and added vu1ExecMicro, Vif.c, VU1micro.c/h (linuzappz) + + * 06/07/02: Rewritten/updated iop code, CdRom.c/h, Common.h, Iop*, Psx*, Debug.h, + Decode_XA.c/h, DisR3000A.c, ElfHeader.c, Gte.c/h, Mdec.c/h, R3000A.c, + R5900.c/h, Sio.c/h, iR3000A.c, Bios.c, pcsx2.dsp (linuzappz) + + * 05/07/02: Added CDVDreadTrack/getBuffer and now we're using CDVD plugin, PS2Edefs.h, + Plugins.c, ConfigDlg.c, ini.c pcsx2.rc (linuzappz) + + * 05/07/02: Optimized recANDI and completed the mmi rec tables, iR5900.c,ix86.c/h (linuzappz) + + * 06/07/02: Add VU opcodes tables vu1micro.c,vu0micro.c,vumicro.h (shadow) + + * 03/07/02: Added MADDU, PMTHL, PLZCW, PSLLH, PSRLH, PSRAH, PSLLW, PSRLW, PSRAW in MMI.c(goldfinger) + + * 03/07/02: Small change in MULT1, MULTU1 for speed, MMI.c(goldfinger) + + * 03/07/02: Fixed MADD, PLZCW in MMI.c(goldfinger) + + * 03/07/02: Fixed signed extend in DIVU, SLL, SLLV, Interpreter.c(goldfinger) + + * 03/07/02: Fixed C_F, FPU.c(goldfinger) + + * 04/07/02: Fixed silly bug on Bios.c, also added a workaround on Counters.c (linuzappz) + + * 04/07/02: Refixed CVT_W/S, FPU.c (linuzappz) + + * 03/07/02: Fixed DIV/DIVU and implemented MOVZ/MOVN in iR5900.c (linuzappz) + + v0.038: + * 02/07/02: Small change on CVT_W, FPU.c (linuzappz) + + * 01/07/02: Changed a bit IPU.c/h, added the dmaIPUs on Hw.c and added IPU_LOG, Debug.h, + resource.h, pcsx2.rc, Common.h (linuzappz) + + * 30/06/02: Add the remaining vif regs in the structure vif.h (shadow) + + * 30/06/02: Framework for IPU ipu.c,ipu.h (shadow) + + v0.037: + * 30/06/02: Added a couple of MMI opcodes to iR5900.c, ix86.c/h, also added one more cdvd server, + Bios.c (linuzappz) + + * 29/06/02: Added most of the FPU opcodes on the recompiler, fixed DSRLV/DSLLV, and also added + LQ, SQ, MFHI, MFLO, MTLO, MTHI, iR5900.c, ix86.c/h (linuzappz) + + * 28/06/02: Refixed LDL,LDR,SDL,SDR, Interpreter.c (linuzappz) + + * 27/06/02: Fixed bug in ABS, FPU.c and completed more fpu opcodes on DisR5900.c + fix to vu0 (vu0.c) + (shadow-linuzappz) + + * 27/06/02: Fixed fileio for dummy files, Bios.c (linuzappz) + + * 26/06/02: Changes/(fixes?) to some opcodes in interpreter.c SRA,DSRA,MULT,MULTU + ,SDL,SDR,LDR,LDL.At least cubemastah is correct now!(GoldFinger) + + * 20/06/02: Fixed the new Logging, modified the files on the last entry + WinMain.c (linuzappz) + + * 18/06/02: Realtime Logging Debugger.c,resource.h,pcsx2.rc,ini.c, + Common.h,debug.h (you must enable it!)(need to fixed) (shadow) + + * 18/06/02: Add some work for sjpcm module on Bios.c (shadow) + + v0.36: + * 13/06/02: Fix basic3d on Bios.c (linuzappz) + + * 09/06/02: Fix for call/ret dma in GS.c (shadow) + + * 06/06/02: Started CDVD plugin API on PS2Edefs.h (linuzappz) + + * 06/06/02: Started HLE.c/h, Interpreter.c, Common.h, iR5900.c, InterTables.c/h (linuzappz) + + * 04/06/02: Added some more syscalls on Bios.c (linuzappz) + + * 02/06/02: Fixed some bugs on SPR.c, Sif.c, Vif.c (linuzappz) + + * 02/06/02: More work on DisR5900asm.c (shadow) + + * 02/06/02: More stuff on Vif.c/h and SPR.c (linuzappz) + + * 01/06/02: Started SIFdmas Hw.c, Sif.c/h, Common.h, added SIF_LOG to Debug.h, + also removed the BREAK code since the bios doesn't handles that, Interpreter.c (linuzappz) + + * 01/06/02: Added PLZCW to MMI.c (linuzappz) + + * 01/06/02: RFU060 is now as before, added INTC and DMAC stuff, added INTC regs 0x1000f000 and + 0x1000f010, and DMAC 0x1000e010, Hw.c/h, Bios.c, Counters.c, R5900.c/h (linuzappz) + + * 31/05/02: Thread stuff is better now, added RFU061 and fixed RFU060, Bios.c (linuzappz) + + * 30/05/02: VU0 stuff is almost complete on DisR5900asm.c (shadow) + + * 30/05/02: Set gp on ElfHeader.c (linuzappz) + + * 30/05/02: Renamed _LOG to EMU_LOG, Debug.h, WinMain.c (linuzappz) + + * 28/05/02: Implemented GetCop0/iGetCop0 bios calls, Bios.c (linuzappz) + + * 28/05/02: Added names to GPR/COP0 regs, R5900.h, COP0.c, Bios.c, Interpreter.c, + FPU.c, DisR5900.c, R5900.c, VU0.c, MMI.c, iR5900.c, ElfHeader.c (linuzappz) + + * 28/05/02: Fixed PSUBW, PSUBB, added PADDW, PEXTLB, PEXTUH, MMI.c, PERF + on Interpreter.c, and TLBWR, TLBR to COP0.c (linuzappz) + + * 28/05/02: disasm.c/h is now DisR5900asm.c, Debugger.c, Debug.h, also added symbols + support for it (linuzappz) + + v0.35: + * 27/05/02: INCREASE VERSION ON 0.036! WinMain.c (shadow) + + * 27/05/02: add partialy support for VU0 in Win32 disasm.fix a bug in tables for MMI + disasm.c disasm.h (shadow) + + * 27/05/02: add VU1 register debugger. resource.h, pcsx2.rc,debugger.h, debugreg.c (shadow) + + * 27/05/02: Started real threads stuff on Bios.c (linuzappz) + + * 27/05/02: Rewrote dmaGIF/dmaVIF1, GS.c/h, Vif.c/h, Hw.c/h (linuzappz) + + * 27/05/02: add Macros for VU0Mem + Some new VU0 opcodes VISWR,VILWR, (shadow - [TyRaNiD] ) + + * 27/05/02: add some new Defines (_Id_ _Is_ _It_ _Imm5_) and some new opcodes + VIADD,VISUB,VIOR,VIAND,VIADDDI,VFOI12,VFOI15,VABS (shadow) + + * 26/05/02: Added support for Symbols on DisR5900.c, ElfHeader.c, Debug.h, + also refixed the qwc on SPR.c (linuzappz) + + * 26/05/02: Added some cdvdfsv stuff on Bios.c, also set the gs revision to 3 in + CSR, GS.c (linuzappz) + + * 25/05/02: CTC2/CFC2 to DisR5900.c (linuzappz) + + * 25/05/02: Added BREAK opcode on Interpreter.c (linuzappz) + + * 25/05/02: Now the b0000000 to b2000000 address are handled as a 10000000 mirror, + Hw.c, Memory.c (linuzappz) + + * 25/05/02: Removed some old code on R5900.c, rewrote a bit the ElfHeader.c (linuzappz) + + * 24/05/02: Add gsWrite... on bios_SetGsCrt (tyranid) + + * 24/05/02: MULT1/MULTU1 are now ok MMI.c (linuzappz) + + * 24/05/02: Added 1000f000 addr on hwRead32, Hw.c (linuzappz) + + * 23/05/02: add VU0 opcodes VSUBi,VSUBq,VMULA,VMULAi,VMULAq,VMSUB,VMSUBi, + VMSUBq,VMADDA,VMAX,VMINI,VADDA,VADDAi,VADDAq,VADDAx,VADDAy, + VADDAz,VADDAw,VSUBA,VSUBAi,VSUBAq,VSUBAx,VSUBAy,VSUBAz,VSUBAw, + VMSUBA,VMSUBAx,VMSUBAy,VMSUVAz,VMSUBAw,VMSUBAi,VMSUBAq (shadow) + + * 23/05/02: add VU0-1 status. (vu0.h , vumicro.h) (shadow) + + * 23/05/02: Added VU0/1micro.c/VUmicro.h (shadow) + + * 23/05/02: Fixed bios_isceSifDmaStat (return -1), also started some work on the + zero-exception stuff, Bios.c, IopBios.c, R5900.c (linuzappz) + + * 23/05/02: VRNEXT should be fine now, VU0.c (linuzappz) + + * 23/05/02: Small addition on Bios.c, 0x80000003 cmd on bios_isceSifSetDma (linuzappz) + + * 22/05/02: Added define __VU0_H__ on VU0.h (linuzappz) + + * 22/05/02: Rewritten GSdma/dmaGIF stuff, now only GSgifTransfer exists, added dmaGIF to GS.c, also added + GIF_LOG to Debug.h, Plugins.c/h (linuzappz) + + * 21/05/02: Fixed one bug in WinMain.c, now can rerun a elf ok (linuzappz) + + * 21/05/02: More stuff to Vif.c (linuzappz) + + * 20/05/02: Fixed one bug in biosException (linuzappz) + + * Started SPRdmas, SPR.c/h, Hw.c, Common.h, also added SPR_LOG, Debug.h (linuzappz) + + * 'call' dmaChain mode in dmaVIF1 should be right now (linuzappz) + + * More changes to the GS plugin API, GSdmaGIF/GSdma, PS2Edefs.h, Plugins.c, Hw.c, Vif.c, + also fixed little bug in SPU2init (linuzappz) + + * Small change in GSmakeSnapshot, now pass char *path (linuzappz) + + v0.34: + + * add more opcodes to Disasm DisR5900.c (shadow) + + * correct MTSA in interpreter interpreter.c (_Rs_ and not _Rd_) (shadow) + + * fixed FPU register debugger debugreg.c .Now registers appears float (shadow) + + * Some more stuff on Bios.c/Counters.c, timer1 intc, fixed bug in CreateSema (semaid stuff), + and added iSignalSema (linuzappz) + + * Added some VU0 opcodes to DisR5900.c (linuzappz) + + * Fixed bug in FPU.c, BC1XX branch delay (linuzappz) + + * Started Vif0/1 dmas, Hw.c, Vif.c/h, Common.h, added VIF_LOG to Debug.h (linuzappz) + + * Fixed VSUBx, VMULz, renamed VMONE to VMOVE, VU0.c (linuzappz) + + * Moved COP2 from Interpreter.c to VU0.c, and MMI to MMI.c (linuzappz) + + * fixed VU0 register debugger debugreg.c (Linuzappz-shadow) + + * Added ExecuteBlock and removed ExecuteBios on R5900cpu, R59000.h, Interpreter.c + and iR5900.c, also added psxExecuteBios, R5900.c, WndMain.c (linuzappz) + + * Some fixes to VU0.c, _Rd_ == 0, not _Rd_ != 0 (linuzappz) + + * Added MTHI1/MTLO1, MMI.c (linuzappz) + + * Rewrote Memory.c (linuzappz) + + * Improved iR5900.c branchs, and updated ix86.c/h (linuzappz) + + * Fixed bug in MULTU, (u64) stuff (linuzappz) + + * Interrupt Exception code was wrong, 0 -> 0x400 (linuzappz) + + * Started ChangeLog + diff --git a/pcsx2/Docs/License.txt b/pcsx2/Docs/License.txt new file mode 100644 index 0000000000..7d1f8605f8 --- /dev/null +++ b/pcsx2/Docs/License.txt @@ -0,0 +1,342 @@ + 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/pcsx2/Docs/PCSX2 FAQ 0.9.4.rtf b/pcsx2/Docs/PCSX2 FAQ 0.9.4.rtf new file mode 100644 index 0000000000..50c55e0d7d --- /dev/null +++ b/pcsx2/Docs/PCSX2 FAQ 0.9.4.rtf @@ -0,0 +1,172 @@ +{\rtf1\ansi\ansicpg1253\deff0\deflang1032{\fonttbl{\f0\froman\fprq2\fcharset161{\*\fname Times New Roman;}Times New Roman Greek;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fcharset161{\*\fname Arial;}Arial Greek;}} +{\colortbl ;\red0\green0\blue255;} +{\*\generator Msftedit 5.41.15.1515;}\viewkind4\uc1\pard\b\f0\fs44 PCSX2 0.9.4 FAQ\par +\par +\b0\fs28 In this document we will try to answer the most common questions our end users have. This is mostly a copy/paste from the Emuforums thread created by CKemu with some updates and corrections.\par +\b\fs44\par +\par +\par +Can I 'Play' Games?\b0\par +\fs28 \par +If by 'playing' a game, you mean: at full speed with sound, perfect graphics, etc, then \b NO\b0 . Come back next year.\par + \par +Since this release (PCSX2 0.9.4) compatibility has increased greatly. Many games will now go 'in-game' or at least to some form of menu. Whilst games may get 'in-game', they will not run at 'playable' speeds, due to the complex nature of PS2 emulation, and the lack of modern hardware that is powerful enough to emulate such a console.\par + \par +Speed has recently increased significantly, for near 'fullspeed' games, we recommend you examine the {\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/95668-post-your-pcsx2-0-9-4-screenshots-here.html"}}{\fldrslt{\cf1\ul screenshots thread}}}\cf0\ulnone\f0\fs28 for speeds.\par + \par +\b\fs44 Is game 'X' Working?\b0\fs28\par + \par +Before posting this, check the {\field{\*\fldinst{HYPERLINK "http://www.pcsx2.net/compat.php?p=1&c=$&s1=1&s2=1&s3=1&s4=1&s5=1" }}{\fldrslt{\cf1\ul compatibility list}}}\cf0\ulnone\f0\fs28 you will be able to see how far your game goes, if you can't get it as far as we can, check your configuration against the {\field{\*\fldinst{HYPERLINK "http://www.pcsx2.net/guide.php" }}{\fldrslt{\cf1\ul Configuration Guide}}}\cf0\ulnone\f0\fs28 , if you still have no luck, you may post the question. If your game is not in the compatibility list then I\rquote m afraid you are on your own, we cannot guarantee it working either way so it is impossible to tell if we can help you at all.\par + \par +\b\fs44 Does PCSX2 play PlayStation 1 (PSOne / PSX / PS1) Games?\b0\fs28\par + \par +\b No\b0 , simple as that. PCSX2's primary goal is to emulate the PS2, which would eventually include PlayStation 1 games, however at this time the key focus is to make PlayStation 2 games 'run' with a high degree of compatibility, including support for such features as USB device support (EyeToy, Special Controllers), DEV9 (Network, HDD) etc.\par + \par +If you wish to play PlayStation 1 games, there are extremely compatible, fast and stable emulators already in existance, and I recommend:\par + \par +{\field{\*\fldinst{HYPERLINK "http://psxemulator.gazaxian.com/" }}{\fldrslt{\cf1\ul pSX}}}\cf0\ulnone\f0\fs28 - New emulator, with a growing level of compatibility and is very simple to use.\par +{\field{\*\fldinst{HYPERLINK "http://epsxe.com/" }}{\fldrslt{\cf1\ul ePSXe}}}\cf0\ulnone\f0\fs28 - The famous and widely supported PS1 emulator, use this if you love features, and plugins!\par +{\field{\*\fldinst{HYPERLINK "http://batard.psxfanatics.com/" }}{\fldrslt{\cf1\ul PSXeven}}}\cf0\ulnone\f0\fs28 - Created by Xeven, supports the PSEmu Pro plugin system, and often has increased compatibilty over ePSXe with some specific games.\par + \par +\par +\b\fs44 My game worked in 0.9.2 but not in 0.9.4 why?\b0\fs28\par + \par +Due to changes in the emulator some games may not work as well as they did in the previous release, as you will find with most emulation projects, you fix one game, you break another somewhere. So the best solution to this is, play your game on the version it worked best for you.\par + \par +\b\fs44 PCSX2 doesn't work on my Athlon XP (or other non SSE2 chips)\b0\fs28\par + \par +Due to the nature of the VM (pcsx2.exe), which heavily uses SSE2, this version of the emulator will \b NOT\b0 work for you, however the TLB (pcsx2t.exe) build should work for you. Note when using a \b non\b0 SSE2 cpu to run PCSX2, make sure you select the \b non\b0 SSE2 versions of the plugins.\par + \par +\par +\b\fs44 ZeroGS looks REALLY ugly!! - What gives?\par +\b0\fs28 \par +\par +ZeroGS renders to native PS2 resolution, that\rquote s it's default render target, when you set the window size to say 1024x768, ZeroGS still renders to native PS2 resolution, but stretches that resolution to fit the window size. What you are used to is setting your window size to x*y and the target resolution also changes accordingly.\par + \par +The so called 'AA' ZeroGS uses, isn't actually anti aliasing, it simply ups the render target size, so you end up with a higher resolution image, thus increasing it's quality (albeit blocky).\par + \par +So you're thinking, well what gives? To be honest, you do, the forum user, so many people whine about speed (oh no my aging rig..or general abuse thrown at the mods / developers), it was decided that in order to maintain speed, the render target and window resolution would remain unlinked, despite the obvious fuglyness of it.\par + \par +\b\fs44 Where is the BIOS?\par +\b0\fs28 \par +It is Illegal to ask for a BIOS, as the BIOS is copyright of SONY. If you wish to use a REAL BIOS with PCSX2, you can dump it from your own PS2 (there are guides {\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/83608-rfs-guide-dumping-your-ps2-bios-over-lan.html" }}{\fldrslt{\cf1\ul here}}}\cf0\ulnone\f0\fs28 and {\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/84994-guide-dump-bios-through-usb.html" }}{\fldrslt{\cf1\ul here}}}\cf0\ulnone\f0\fs28 . Or find it by yourself.\par + \par +\b\fs44 No SCPH10,000 Support?!\par +\b0\fs28 \par +The SCPH10,000 BIOS doesn't have all the libraries many games need to load, thus for better results, use a more modern BIOS version.\par + \par +\b\fs44 Do I need ROM1, ROM2, EROM?\par +\b0\fs28 \par +If the console is warning you about not having these files, do not panic, all you need is the main ROM0 (the 4,096kb main BIOS file). You can dump the ROM1, ROM2, EROM from your own PS2 console, again guides and tools are on the internet, use {\field{\*\fldinst{HYPERLINK "http://www.google.com" }}{\fldrslt{\cf1\ul Google}}}\cf0\ulnone\f0\fs28\par +\par +\b\fs44 Is PCSX2 finally using the new .p2b BIOS format?\par +\par +\b0\fs28 Unfortunately, florin the team member responsible for this feature got held back and it did not make it in the release. Nevertheless, you can extract the contents of your .p2b BIOS file using 7zip, so you are still able to use your own complete BIOS files\par +\par + \par +\b\fs44 Where can I get games?\b0\fs28\par + \par +From your local computer game shop, where else?\par + \par +This forum does not support warez or piracy, helping someone get links to such files, asking for such files, or linking to illegal material will be warned then banned if the violation is repeated. There are \b MANY\b0 great games out there, and you owe it to the talented creators to buy their games, and many you can get very cheaply, in platinum editions or second hand.\par + \par +\b\fs44 Can I be a betatester?\b0\fs28\par + \par +Ask this and the answer will always be \b NO\b0 . Keep asking it and you'll find yourself with a big fat ban.\par + \par +\b\fs44 What are the system requirements?\b0\fs28\par + \par +We recommend the following:\par + \par +\b Minimal Specs:\par +\b0 AMD XP/64 or Intel Pentium 4 (VM Built will not work with [B]non[/B] SSE2 CPU's)\par +512MB of RAM\par +Pixel Shader 1.4 supporting card (GSdx Graphics Plugin Only)\par + \par +\b Recommended Specs:\b0 (For reasonable performance in many games, but not all)\par +AMD64 X2 or Intel Conroe E6600+ (Multi Threading is supported in PCSX2)\par +512-1024MB of RAM (more RAM allows for VM mode to be stable)\par +Pixel Shader 2.0 supporting card (recommended GeForce 6600-8800 or equivalent ATi card)\par + \par +\b Possible Ideal Specs:\b0\par +64bit OS such as Vista or winXP64, to allow for future support of 64bit recompilers.\par +Future AMD or Intel Quad Core maybe needed, but currently the support of 4 threads is not handled by PCSX2, and the effect of threading out EE / VU is not yet known.\par +We don't forsee you requiring a GPU more powerful than the current generation of cards, up to and including the nVidia GeForce 8800.\par + \par +A more in-depth guide to system specifications can be found {\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/84457-will-emulator-run-fast-my-computer.html" }}{\fldrslt{\cf1\ul here}}}\cf0\ulnone\f0\fs28 .\par + \par +\b\fs44 How do I compile the SVN source?\par +\b0\fs28 \par +We do not support SVN builds on this forum. Only official builds are permitted to be discussed. This is mainly to stop confusion, people 'handing out' betas, n00b questions when dealing with errors, as it's hard to keep track of multiple 0.x.x versions.\par + \par +Besides, if you need to ask that question, then trust me, you don't want to be bothered. It's very very hard.\par + \par +\b\fs44 What is going on with PCSX2?\par +\b0\fs28\par +\i Why aren't we getting lots of info, or is PCSX2 dead?\i0\par +\pard\fi-360\li720\tx720\lang2057\f1\'b7\tab\lang1032\f0 When something 'special' happens, one of the beta-testers will post shots and information.\par +\pard\lang2057\f1\'b7\tab\lang1032\f0 When something super-dupa mega super hyper turbo mega mega happens, shots will be posted like \i super mega\i0 lightning fast on the main {\field{\*\fldinst{HYPERLINK "http://www.pcsx2.net/"}}{\fldrslt{\cf1\ul news page}}}\cf0\ulnone\f0\fs28 .\par +\lang2057\f1\'b7\tab\lang1032\f0 If no shots are being posted, assume that the progress is slow but steady, and whilst stuff is happening, it doesn't result in anything that you'd be able to see (eg techy nerd stuff).\par +\lang2057\f1\'b7\tab\lang1032\f0 If nothing is being posted whatsoever, assume that \b A:\b0 The developers have lives (yeah I didn't believe that either), \b B:\b0 The developers are taking a rest.\par +\lang2057\f1\'b7\tab\lang1032\f0 What if \b SHOCK HORROR\b0 no news has been posted for ages???!!!!!! Assume any of the above or most of the team was killed.\par +\lang2057\f1\'b7\tab\lang1032\f0 What if I have programming knowledge, and could understand the technical changes being made? Well then go browse to the SVN, and aquire the \b changelog.txt\b0 .\par +\par +\b\fs44 When will the next version be released?\par +\b0\fs28 \par +The authors are writing this in there spare time. If they knew, they would inform you, normally a release is made when significant progress and a big difference in 'output' is shown, eg, when you the end user will be able to see more stuff running.\par + \par +\b\fs44 Why bother making releases when it is not finished?\b0\fs28\par + \par +In a nutshell, it keeps the "Gimme the next release \b NOW!\b0 " crowd from getting too annoying. More importantly it alls folks to see how things are progressing first hand.\par + \par +\b\fs44 How do I make a patch?\par +\b0\fs28 \par +Making a patch will \b not\b0 make a game 'playable' but may allow you further into it. Patches can be used to skip videos that don't play, or other simple bugs, they will not make '3D' perfect or make sound super duppa!\par + \par +{\field{\*\fldinst{HYPERLINK "http://www.pcsx2.net/nachbrenner/" }}{\fldrslt{\cf1\ul Nachbrenner's Site for making Patches}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://www.ngemu.com/forums/showthread.php?t=62837" }}{\fldrslt{\cf1\ul Simple Guide for Video Skip Patches}}}\cf0\ulnone\f0\fs28\par + \par +\b\fs44 My Sprites have black borders!\b0\fs28\par + \par +This happens when you have \b Linear Texture Filtering\b0 (LTF) turned on in GSdx, to solve this, turn off LTF. This is most often the cause of black squares or borders around sprites in 2D and 2.5D fighting games.\par + \par +\b\fs44 Every Game I run crashes the emulator instantly!\par +\b0\fs28 \par +This is often caused by people having the \b NLOOP0\b0 hack enabled in the GS plugin (ZeroGS KOSMOS / GSdx), and using the Run>Execute menu. By using Run>Execute the emulator first boots the BIOS, which will crash when you have NLOOP0 enabled. Simply use File>RunCD menu to avoid crashes, and this is the recommended option for anygame.\par + \par +If you wish to run the BIOS, simply \b DISABLE\b0 NLOOP0 in your GS plugin first!\par + \par +\b\fs44 Useful Links\par +\b0\fs28 \par +BIOS Guides:\par + \par +{\field{\*\fldinst{HYPERLINK "http://www.ngemu.com/forums/showthread.php?t=65015" }}{\fldrslt{\cf1\ul CKemu's guide to using the PS2 BIOS}}}\cf0\ulnone\f0\fs28 \par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/84994-guide-dump-bios-through-usb.html" }}{\fldrslt{\cf1\ul RealOne's Guide to USB BIOS Dumping}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/83608-rfs-guide-dumping-your-ps2-bios-over-lan.html" }}{\fldrslt{\cf1\ul Reichfuher's guide to dumping your Playstation 2 BIOS}}}\cf0\ulnone\f0\fs28\par +\par +Error/Problem Guides:\par + \par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/67512-common-problems-solutions-guide.html" \\\\l "post912874" }}{\fldrslt{\cf1\ul Refraction's guide to common problems and errors.}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/84457-will-emulator-run-fast-my-computer.html" }}{\fldrslt{\cf1\ul Will the emulator run fast on my computer?}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/70174-why-pcsx2-slow.html" }}{\fldrslt{\cf1\ul Why is PCSX2 Slow?}}}\cf0\ulnone\f0\fs28\par +\par +Memory Card Guides:\par + \par +{\field{\*\fldinst{HYPERLINK "http://www.ngemu.com/forums/showthread.php?t=64482" }}{\fldrslt{\cf1\ul Convert GameFAQ saves to PCSX2 memorycard}}}\cf0\ulnone\f0\fs28 {\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/69844-load-us-ntsc-final-fantasy-x-gamesaves-any-ffx-version.html" }}{\fldrslt{\cf1\ul Load US memcard saves on any region version of FFX and FFX-2}}}\cf0\ulnone\f0\fs28\par + \par +Plugins/Patch Guides:\par + \par +{\field{\*\fldinst{HYPERLINK "http://www.ngemu.com/forums/showthread.php?t=62837" }}{\fldrslt{\cf1\ul Guide to making patches for PCSX2}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/1065199-post74.html" }}{\fldrslt{\cf1\ul TwinPad Keyboard Plugin Latest Version}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/ps2-plugin-questions-troubleshooting/87274-lilypad-new-pad-plugin-lame-name.html" }}{\fldrslt{\cf1\ul Lilypad plugin}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/ps2-plugin-questions-troubleshooting/94273-megapad-plugin.html" }}{\fldrslt{\cf1\ul MegaPad plugin}}}\cf0\ulnone\f0\fs28\par + \par +Reviews:\par + \par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/76251-pcsx2-review-cpu-power-does-matter.html" }}{\fldrslt{\cf1\ul PCSX2 Review Part 1: CPU Power Matters}}}\cf0\ulnone\f0\fs28\par +{\field{\*\fldinst{HYPERLINK "http://forums.ngemu.com/pcsx2-official-forum/80417-pcsx2-review-part2-gpu-power-also-matter.html" }}{\fldrslt{\cf1\ul PCSX2 Review Part 2: GPU Power Also Matters}}}\cf0\ulnone\f0\fs28\par +\par +\par +\f2\fs20\par +} + \ No newline at end of file diff --git a/pcsx2/Docs/PS2Edefs.txt b/pcsx2/Docs/PS2Edefs.txt new file mode 100644 index 0000000000..5442da8297 --- /dev/null +++ b/pcsx2/Docs/PS2Edefs.txt @@ -0,0 +1,443 @@ + PS2E Definitions v0.3.0 (beta) + ------------------------------ + + Author: linuzappz@pcsx.net + +Note: Refer to PS2Edefs.h for more info. + +1) API Funcs +2) FAQs +3) Notes + +1) API Funcs: + --------- + + Common stuff: + ------------ + +// u32 CALLBACK PS2EgetLibType(void); + +Gets the plugin type, from the following defines: + +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +Note that the types can be ORed so you can make an +ie. GS/PAD plugin in one dll. + +// u32 CALLBACK PS2EgetLibVersion(void); + +Will get the plugin version: + +const unsigned char version = 1; // GS library v1 +const unsigned char revision = VERSION; +const unsigned char build = BUILD; // increase that with each version + +return version<<16|revision<<8|build; + +'version' is the GS plugin API version, as this is beta, +it should be 1. +'revision' and 'build' are plugin defined values. + +// char* CALLBACK PS2EgetLibName(void); + +Get the LibName, ie. "GSsoftdx Driver"; + + + + GS plugin API: + ------------- + +Basic funcs +----------- + +// s32 CALLBACK GSinit(); + +Inits the plugin, return 0 on success, else -1. + +// s32 CALLBACK GSopen(void *pDsp, char *Title); + +Opens the plugin, return 0 on success, else -1. +The plugin must fill the 'pDsp' arg (32bit) that'll be +passed to other plugins (*1), this is OS dependant (*2). + +On Win32: pass a HWND value, ie: + *(long*)pDsp = (long)GShwnd; +On Linux: pass a Display value, ie: + *(long*)pDsp = (long)display; + +*1 Even if this value is passed to every plugin, this +may not be used by the plugins. + +*2 This could change anyways, ie. maybe you can code a +GS/PAD plugin for a speacial library, so the pDsp +will be a value that you need to communicate between +them (if you need to do this). + +// void CALLBACK GSclose(); + +Close the plugin. + +// void CALLBACK GSshutdown(); + +Shutdown the plugin. + +// void CALLBACK GSvsync(); + +Called on every VSync. + +// void CALLBACK GSgifTransfer(u32 *pMem, u32 size); + +Transfer 'size' qwords (128bit) from 'pMem' to the Gif. + +// void CALLBACK GSgifTransfer2(u32 *pMem); + +Transfer a qwords (128bit) block from 'pMem' to the Gif. + +// void CALLBACK GSwrite32(u32 mem, u32 value); + +Writes to address 'mem' data 'value', 32bit. +Addresses can range from 0x12000000 to 0x14000000. + +// void CALLBACK GSwrite64(u32 mem, u64 value); + +Writes to address 'mem' data 'value', 64bit. +Addresses can range from 0x12000000 to 0x14000000. + +// u32 CALLBACK GSread32(u32 mem); + +Returns 32bit from address 'mem'. +Addresses can range from 0x12000000 to 0x14000000. + +// u64 CALLBACK GSread64(u32 mem); + +Returns 64bit from address 'mem'. +Addresses can range from 0x12000000 to 0x14000000. + +Extended funcs +-------------- + +// void CALLBACK GSkeyEvent(keyEvent *ev); + +Gets called when there is a keyEvent from the PAD plugin + +// void CALLBACK GSmakeSnapshot(char *path); + +Makes an snapshot of the vRam, can be a with the full +vRam or just the view area (as you prefer), to the dir +'path'. + + +// #ifdef __WIN32__ +// s32 CALLBACK GSsetWindowInfo(winInfo *info); +// #endif + +Windows only function, will pass the info struct to the +GS plugin, if the plugin will use this info it should +return 1 (TRUE), else the emu will destroy the window +handle and let the plugin take care of that. +This function must be called before the GSopen. +Note that the emu should hide the hMenu and the hStatusWnd +if it they are set. +The position and size of the window is not specified and +should be reset by the plugin, but the window passed should +be in a normal state, not maximized nor minimized. +After a GSclose the emu must destroy the window and +recreate it. + +// void CALLBACK GSconfigure(); + +Configure the plugin. + +// void CALLBACK GSabout(); + +Shows an About Dialog of the plugin. + +// s32 CALLBACK GStest(); + +Returns 0 if the plugin should work ok, else -1. + + + + PAD plugin API: -=[ OBSOLETE ]=- + -------------- + +Basic funcs +----------- + +// s32 CALLBACK PADinit(u32 flags); + +Inits the plugin, return 0 on success, else -1. + +// s32 CALLBACK PADopen(void *pDsp); + +Opens the plugin, return 0 on success, else -1. +The 'pDsp' is a value from the GS plugin (refer to +GSopen). + +// void CALLBACK PADclose(); + +Close the plugin. + +// void CALLBACK PADshutdown(); + +Shutdown the plugin. + +// keyEvent* CALLBACK PADkeyEvent(); + +Called every vsync, return NULL if no event happened. + +// u8 CALLBACK PADstartPoll(int pad); + +Starts polling data from the PAD, 'pad' can be 1 (pad1) +or 2 (pad2). +Returns first byte from buffer; + +// u8 CALLBACK PADpoll(u8 value); + +Returns next byte from buffer; +Refer to "pad and mem card data.txt" or "padmem.txt", +for info about value/buffer data. + +// u32 CALLBACK PADquery(); + +returns: 1 if supported pad1 + 2 if supported pad2 + 3 if both are supported + +Extended funcs +-------------- + +// void CALLBACK PADconfigure(); + +Configure the plugin. + +// void CALLBACK PADabout(); + +Shows an About Dialog of the plugin. + +// s32 CALLBACK PADtest(); + +Returns 0 if the plugin should work ok, else -1. + + + + SIO plugin API: + -------------- + +Basic funcs +----------- + +// s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); + +Inits the plugin, return 0 on success, else -1. +port/slot combination will be used to load the corresponding + configuration data from ini. It's like an id for the instance. +'f' is a callback function that is used by SIO_TYPE_MTAP capable + plugins to change active slot in emulator (since sio is emu-controled). + +// s32 CALLBACK SIOopen(void *pDsp); + +Opens the plugin, return 0 on success, else -1. +The 'pDsp' is a value from the GS plugin (refer to +GSopen). + +// void CALLBACK SIOclose(); + +Close the plugin. + +// void CALLBACK SIOshutdown(); + +Shutdown the plugin. + +// u8 CALLBACK SIOstartPoll(u8 value); + +Starts polling data from the SIO, 'value' is + 0x01, 0x21, 0x61 and 0x81 corresponding to pad, mtap, rm and mc. +Returns first byte from buffer; + +// u8 CALLBACK SIOpoll(u8 value); + +Returns next byte from buffer; +Refer to "pad and mem card data.txt", "padmem.txt" or + "padspecs.txt" (http://ps2dev.ps2-scene.org/padspecs.txt), +for info about value/buffer data. + +// u32 CALLBACK SIOquery(); + +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +returns: ORed value of SIO_TYPE_xxxx - the capabilities of the plugin +eg. a remote control plugin will return SIO_TYPE_PAD | SIO_TYPE_RM + +Extended funcs +-------------- + +// void CALLBACK SIOconfigure(); + +Configure the plugin. + +// void CALLBACK SIOabout(); + +Shows an About Dialog of the plugin. + +// s32 CALLBACK SIOtest(); + +Returns 0 if the plugin should work ok, else -1. + + + + SPU2 plugin API: + --------------- + +TODO :) + +Basic funcs +----------- + +// s32 CALLBACK SPU2init(); +// s32 CALLBACK SPU2open(void *pDsp); +// void CALLBACK SPU2close(); +// void CALLBACK SPU2shutdown(); +// void CALLBACK SPU2update(); +// void CALLBACK SPU2dma(u32 *dmaAddr, char *pRam); +// void CALLBACK SPU2write(u32 mem, u16 value); +// u16 CALLBACK SPU2read(u32 mem); + +Extended funcs +-------------- + +// void CALLBACK SPU2configure(); +// void CALLBACK SPU2about(); +// s32 CALLBACK SPU2test(); + + + + CDVD plugin API: + --------------- + +Basic funcs +----------- + +// s32 CALLBACK CDVDinit(); + +Inits the plugin, return 0 on success, else -1. + +// s32 CALLBACK CDVDopen(); + +Opens the plugin, return 0 on success, else -1. + +// void CALLBACK CDVDclose(); + +Close the plugin. + +// void CALLBACK CDVDshutdown(); + +Shutdown the plugin. + +// s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +Starts reading from the specified 'lsn' sector location, +return 0 on success, else -1. + +// u8* CALLBACK CDVDgetBuffer(); + +Gets a pointer to the buffer with the sector data +readed by a previously CDVDreadTrack call. +The buffer size depends on the mode used for readTrack. + +note: return can be NULL (for async modes) + +// s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq); + +Read subq data from disc at 'lsn' location (only cds have subq data), +return 0 on success, else -1. + +// s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); + +Get the the cdvdTN data for the currect CdRom, +return 0 on success, else -1. + +// s32 CALLBACK CDVDgetTD(u8 Track, cdvdLoc *Buffer); + +Get the the cdvdTD data for the 'Track' track in the current CdRom, +return 0 on success, else -1. + +// s32 CALLBACK CDVDgetTOC(void* toc); + +Get ps2 style toc from disc, return 0 on success, else -1. +(ps2 toc isnt quite the same as a normal disc toc, +especially for dvds) + +// s32 CALLBACK CDVDgetDiskType(); + +Returns disktype in the format CDVD_TYPE_xxxx + +// s32 CALLBACK CDVDgetTrayStatus(); + +Returns tray status in the format CDVD_TRAY_xxxx + +// s32 CALLBACK CDVDctrlTrayOpen(); + +Opens disc tray, return 0 on success, else -1. + +// s32 CALLBACK CDVDctrlTrayClose(); + +Closes disc tray, return 0 on success, else -1. + + +Extended funcs +-------------- + +// void CALLBACK CDVDconfigure(); + +Configure the plugin. + +// void CALLBACK CDVDabout(); + +Shows an About Dialog of the plugin. + +// s32 CALLBACK CDVDtest(); + +Returns 0 if the plugin should work ok, else -1. + + +2) FAQs + + * What's the right open/close sequence? + 1. CDVD + 2. GS + 3. PAD1/2 + 4. SPU2 + + * Where to start coding a plugin? + Get an open source plugin, mine are all open source, + so you can freely base on them. + + * Why GSgifTransfer2 exists? + GSgifTransfer2 is used by the XGKICK VU1 opcode, and + it doesn't has a size, the GSgifTransfer is used by he GIF + and the VIF dmas, and it has a size, so that's why :). + +3) Notes + + * CDVDgetBuffer should be used after CDVDreadTrack, + like this: + CDVDreadTrack(time); + ptr = CDVDgetBuffer(); + + but not like this; + ptr = CDVDgetBuffer(); + CDVDreadTrack(time); + + * Errors should be checked for both CDVDreadTrack and CDVDgetBuffer, + and not only CDVDreadTrack. + diff --git a/pcsx2/Docs/RemoteDebugging.txt b/pcsx2/Docs/RemoteDebugging.txt new file mode 100644 index 0000000000..339b400b48 --- /dev/null +++ b/pcsx2/Docs/RemoteDebugging.txt @@ -0,0 +1,105 @@ +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» +ºNOTE: 1. this is an internal pcsx2 team document, for developers ONLYº +º 2. lamers/gamers are excluded º +º 3. DECI2 will not run your games:P º +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ + +RemoteDebugging +=============== + +This is a new feature available for debugging applications within pcsx2 emu. + Using a remote debugger is not wellcomed unless it is more featured. + Fortunately, there are such debuggers. Currently added support is for win32 + target only; also, only TCP/IP remote connection and only for Sony's DECI2 + app-level protocol. Future addition could be GNU debugger remote support. + +Anyway, pcsx2 has a new menu item that allows one to start a debugging session + by specifying the listen port [default for DECI2 is 8510]. Pcsx2 will act like + a server for the remote debugger. It is set to accept connections on any IP. + For local debugging sessions, use IP=127.0.0.1 aka IP=localhost. On the + other hand, if a pcsx2 would be listening on an active IP in the Internet, + anyone could connect to it;) Only one connection is supported. After the + connection is closed by the client/remote tool, the only thing to do is to + "admire" the log window and then close it/restart the emu. + +So, to start a debug session: + - first start the emu [quite reasonable; because it will be the server]. There + are some issues if you start the client first or if you didn't close ALL the + client subprograms in the last debugging session. + - choose from the menu, Debug->Remote Debugging. A dialog will pop asking for + the port to use. Also, if you have a non-HLE bios selected in the Config box, + ie. a true bios, there will be also an option weather to debug the bios. You + have 2 choices: + -not checked=Run Bios + before any debug is performed a bios run. ie. the emu + will run the bios up to the shell loading or a bit + further, to the moment when all the iop modules are + loaded. You will have then a full environment loaded. + -checked=Debug Bios + nothing is done further and the PC=0xBFC00000. + - after that a connection log window will be shown and you can follow the + connection data exchange. First, the emu is placed in a wait state. + - this is the moment you have to run the client. It will open the connection. + The emu accepts the connection and the DECI2 protocol is on;) + You'll see how the client queries for registers values & memory areas. + - the situation gets complicated since you can do many things from now on: + +Debug bios: + - start with a bios selected and the check box checked (see above). + - PC=0xBFC00000 and you can trace the bios now. Anyway, there is no breakpoints + support for the bios as the client "thinks" you are debugging the real PS2, + so you cannot write to bios area. BTW: the breakpoints are implemented by + patching the code with a BREAK instruction. Since you cannot write such instr + you cannot put a breakpoint on the bios, cannot run to address and so on... +Run bios: + - start with a bios selected and the check box not checked (see above). + - wait till the emu runs the bios...it will take some time. After THAT the + connection log window will be displayed. + - PC=0x82000 or smth like that...you can check the environment set up while + running the bios. The modules window for instance. And various memory + structures. Also, this is the entrypoint of the shell loading. Try to trace + it;) +Debug an application: + - start with HLEbios selected (see above) + - since the debugger (the client) does debug whatever you want to. You can + load the elf to debug with pcsx2 loader (ie. with File->Load ELF file or + from the CDVD). But you will need to know the entrypoint to force it in + remote debugger (set PC to cursor or to address). This way is not recomended. + I like to use the loader of the debugger since it knows to load the source + also if available and does not cause troubles with setting the PC. Also, if + the ELF has symbols, it can run it to main;) + - now, you're on your own. Use step by step, step over, breakpoints, run to + cursor, run to address etc. HAPPY DEBUGGING! + +KNOWN ISSUES and NOTES +====================== + - use CDVDnull or another plugin as you like to have or not a src for cdvd + loading;) + - pcsx2 does not have support to debug the IOP. You can do this now but it is + a hard job. That is due to the fact that PS2 can run every processor + independently (ie. one can be stopped) and pcsx2 cannot. The emu runs either + all the procs or nothing. So, in the debugger, the debugged processor is on + stop and others are "running". When there will be added support for debugging + the IOP, also only one processor will run. + - do not step through the program very fast. Because of the communication speed + and a reentrancy issue, this will get the debugger in a FALSE run state. That + means that the debugger "thinks" that the PS2 (ie. pcsx2;)) is running, + although it is not. The simple solution to this is to press STOP/BREAK button + in the debugger. Notice also that some run states might be also true! When + you are stepping over a big loop...that might take some time, so if you stop + the emu you will get in the middle of the loop:P + - you can also notice the low speed that can also be met in the pcsx2 debugger. + That's because Cpu->Step() is used. + - also, notice that you cannot debug in recompiler mode! ONLY interpreter mode + works! + - IOP modules loading is not supported and the files loaded from host directory + are also loaded in pcsx2 way, ie. from host\ directory; not through remote + debugger. + - if you try to debug the bios and the code is not displayed...scroll down + in order to have only valid addresses on the screen; ie. the top address + to be 0xBFC00000 and in emu communication log there will be no ADDRESS ERROR. + + +=============================== +Florin (florinsasu@yahoo.com) +2003/04/17 diff --git a/pcsx2/Docs/Translating.txt b/pcsx2/Docs/Translating.txt new file mode 100644 index 0000000000..9fb98e10a2 --- /dev/null +++ b/pcsx2/Docs/Translating.txt @@ -0,0 +1,41 @@ + Translating PCSX2 + ----------------- + +Just some small notes for translators. + +First download the translator package from the download section of http://www.pcsx2.net + +PCSX2 translations are based on the gettext library: +http://www.gnu.org/software/gettext. + +The main file to translate is pcsx2.po which cames in the package you downloaded, +note that you must place the translated +strings over the msgstr and leave untouched the msgid. + +Example: + +msgid "Memory Card 1" +msgstr "Your Translation goes here" + +To test the translation use the msgfmt.exe utility to +convert the translated pcsx2.po file to a pcsx2.mo file +with this command: 'msgfmt pcsx2.po -o pcsx2.mo -v', after translating +the file please send us the .po and .mo file and please ask before +translating it, maybe someone has already started it +for your language. + +Version update for 0.9.2/3: + +I have rewritten the contents of the Translation doc to ease reading +and brung it up to date with the current GUI. Translations will work in 0.9.2 +but some Menu options may still show as their original names (fixed in 0.9.3). + + + +If you have any problems contact us and we'll try to +help you. + +Regards +linuzappz,shadow,refraction + +Contact me at : refraction@gmail.com or visit us on efnet #pcsx2 \ No newline at end of file diff --git a/pcsx2/Docs/devblog.txt b/pcsx2/Docs/devblog.txt new file mode 100644 index 0000000000..130345c7b4 --- /dev/null +++ b/pcsx2/Docs/devblog.txt @@ -0,0 +1,273 @@ +Developers Blog +=============== + +This file is mainly an R&D document containing developers findings. The aim is + to have it as much accurate as possible. Each item has to contain a number(ID), + the name of developer, revisions history and a short description. +Also, this document will serve as a pinboard - will contain coding rules, + explanations on implementation of different parts of the emulator, suggestions, + questions and ideas. + + +============================================================================== +============================================================================== +============================================================================== + +[ ID ] 4 +[name] Florin +[desc] PS2 info dumping project +[hist] 2006-05-08 initial version + +The emulator needs some information from a Playstation2 console. +We used to require the 'bios' software. In order to get better results + more and more information was needed. So here are some guidelines + on what we need and what we don't need from the console. +Also, a new dumper and handling of these infos in the emu are in work. + +a. The so-called 'bios', is actualy rom0 found in consoles, devkits, + test-kits and PSX at address 0xBFC00000 on both EE and IOP. + [!] Note that on 75xxx the EE side bios mismatch zone fields, + so it is recomended to make a IOP side dump. +b. Rom1 and Erom contain DvdPlayer related software and are located + starting with 0xBE000000 on PS2s from 18000 and up. Over various + versions, the size of rom1 and size and position of erom changed. + They used to be dumped separately, the new dumper will simplify this, + there'll only one file containing both rom1 and erom (2M or 4M). + [!] Note that on 70xxx and 75xxx (PStwo's) the dumping of erom from EE + is not possible, the correct dump is done only from IOP! + [!] rom1 and erom are identical for same generation for all zones. + In order to be able to run the dvdplayer code in the emulator, it needs + to be pre-decrypted. EROMDRV and DVDELF will have some 'decrypt' patches. +c. NVM (Non Volatile Memory) is 1K of code and provide valuable info about + console model and region. 10000 and 15000 don't contain the model name. + PStwo's contain the zone codes making possible to have a single version + of the rom for all zones. +d. Rom2 is found only in Chinese PS2s (50009, 70009...) and contains + a font file: GB18030. It is located at 0xBE400000. It was (w/o + justification) assumed that it is as big as rom1. There is no need to + dump it on any other console than chinese. The size is to be calculated + from the filesystem (as rom0 and rom1, it has romfs). +e. BBA (BroadBand Adapter) info is not needed to be dumped. At least not + for the emulator itself, maybe for the DEV9 plugin. Anyway, it's just + a MAC address that can be made up. +f. The current dumper is reading CDVD Mecha version. This will be replaced + by a more complete information file that will contain the following info: + from [EE] + CPU revision - revision code from COP0->PRId register + easier read from (u16)GetCop0(15) + high byte is 0x2E for EE + low byte is: high nibble major, low nibble minor of revision + FPU revision - revision code from COP1->control register 0 + same description as for cpu PRId + VUs revision - hum, i'm not aware of any revision for them :( + VUs memory - local and micro memory sizes are not detected + GS revision - upper halfword in CSR register + high byte is ID = 0x55 + low bytes is major.minor (per nibbles) + GS mem - is 4M + IPU revision - hum, i'm not aware of any revision for IPU :( + Caches - instruction and data cache sizes are read from + COP0->Config register + easier read from GetCop0(16). + MEM - total RAM available + easier read with Syscall +127 - GetMemorySize() + the values are: 32M for console and test-kits, + 128M for devkits and 64M for PSX + the size is not roughly detected. As devkits have multiple + boot modes (128M or 64M). + from [IOP] + CPU revision - revision code from COP0->PRId register + high byte seems to be 0 + low byte is major.minor (per nibbles) + initial japs have major=1, + most of the consoles have major=2, + 75xxx have a new IOP processor with major=3 + Caches - are known to be 4K-I$; 1K-D$ + 0xFFFE0130 is CACHE_CONFIG register... + MEM - total RAM available + easier to read with QueryMemSize() + the values are: 2M for consoles and test-kits, + 8M for devkits and PSX + again, the size is incorrectly read :) + SPU mem - 2M (any method of detection?) + CDVD mecha - version of CDVD controller + Scmd 0x03 with subcode 0x00 (outsize=4) + the first byte is the MG-encryption code + second is major, third is minor, fourth is [2b completed] + meka - i don't know; not supported on early consoles + Scmd 0x03 with subcode 0x90 (outsize=1+1) + DEV9 revision- type of DEV9 device: 0x2x for PCMCIA, 0x3x for EXPBAY + *(vu16*)BF80146E + USB OHCI rev - Hc_revision of the OHCI controller + *(vu32*)0xBF801600 + ILINK rev/id - I'm not sure of this one, on ps2's that don't have + firewire anymore, the value is 0xFF; on 10000 is random + *(vu32*)0xBF808480 and *(vu32*)0xBF808500 (looks like mirror) + +g. The dumper will sign the dumped content, so John Doe cannot play easily + with the bios data ;) The emu works correctly with good data/food. + +h. I'm thinking of a method to check for modified content (dumps made with a + chipped console). Probably, it will be done in the emu and presented as a + warrning. + + +============================================================================== +============================================================================== +============================================================================== + +[ ID ] 3 +[name] auMatt +[desc] PS2 NVM Data not 100% +[hist] 2006-05-07 initial version + + ³v0-v8 ³ v9- ³ Bits ³ Bytes º +ÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍ͹ +ÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍ͹ +PS1 Disc Spd ³ 0x300 ³ 0x2c0 ³ ³ º +PS1 Texture ³ 0x300 ³ 0x2c0 ³ ³ º +Video Output ³ 0x300 ³ 0x2c0 ³ ³ º +SPDIF ³ 0x310 ³ 0x2c0 ³ 0 ³ º +A/R ³ 0x310 ³ 0x2c0 ³ 1 & 2 ³ º +Language ³ 0x311 ³ 0x2c1 ³ All ³ º +TimeZone ³ 0x312 ³ 0x2c2 ³ ³ º +Summer Time ³ 0x312 ³ 0x2c2 ³ 3 ³ º +Time Format ³ 0x312 ³ 0x2c2 ³ 5 ³ º +DateNotation ³ 0x312 ³ 0x2c2 ³ 6 & 7 ³ º +TimeZone ³ 0x313 ³ 0x2c3 ³ All ³ º +TimeZone ³ 0x315 ³ 0x2c5 ³ All ³ º +Model Number ³ 0x1a0 ³ 0x1b0 ³ ³ 16 º +Console ID ³ 0x1c8 ³ 0x1f0 ³ ³ 8 º +ILink ID ³ 0x1c0 ³ 0x1e0 ³ ³ 8 º +Date Stamp ³ 0x180 ³ ³ ³ 16 º +Date Stamp ³ 0x1e0 ³ ³ ³ 16 º +Date Stamp ³ 0x1f0 ³ ³ ³ 16 º +Rem. Control ³ ³ 0x2c4 ³ 5 ³ º +Checksum ³ 0x31f ³ 0x2cf ³ All ³ º + +Checksum is calculated by the previous 15 bytes added together, then ANDed with 0xFF +Serial Number of Console can be obtained from bytes 7,6 & 5 of the Console ID in dec. + + +============================================================================== +============================================================================== +============================================================================== + +[ ID ] 2 +[name] Florin +[desc] PS2 bios versioning +[hist] 2006-04-30 initial version + +MG zone - the MagicGate decryption zone. You can find the code as one of the bits + in the byte at offset +1C in MagicGate encrypted files +PS1 drv - the letter for PS1VERx files in PStwo rom0 +ROMVER - has the following format VVvvZTYYYYMMDD in 14 bytes + VV, vv are the version of the bios in BCD + Z is zone code, see below + T is type of the console: C - consumer console, D - devkit/test console + YYYYMMDD is date of the bios + - BxDATA-SYSTEM, BxEXEC-SYSTEM, BxEXEC-DVDPLAYER uses Z code in place of 'x' + I: default, Japan; A: Usa, Asia; E: Europe, Oceania, Russia; C: China +VERSTR - the code from that file in rom0 +OSDVER - VVvvZlng is the format of the file for scph5xxxx. in PStwo the last 4 letters + are read from NVM, offset +180 7 chars (ROMVER:1|OSDVER:4|VERSTR:1|DVDID:1) +mecha - version read from CDVD SCmd 0x03:0x00 + +The following table is far from complete... + + ³Japan ³ USA ³AusNz ³ UK ³Europe³Korea ³ HK ³Taiwan³Russia³China ³Mexic º +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +MG zone ³ 0/J ³ 1/U ³ 3/O ³ 2/E ³ 2/E ³ 4/A ³ 4/A ³ 4/A ³ 5/R ³ 6/C ³ 7/M º +PS1 drv ³ J ³ A ³ E ³ E ³ E ³ H ³ H ³ H ³ E ³ C ³ A º +ROMVER ³0 J ³1 A ³2 E ³2 E ³2 E ³1 H ³1 H ³1 H ³2 E ³3 C ³1 A º +VERSTR ³ J ³ A ³ E ³ E ³ E ³ J ³ J ³ J ³ E ³ J ³ A º +OSDVER ³0 Jjpn³1 Aeng³2 Eeng³2 Eeng³2 Eeng³5 Kkor³6 Htch³6 Htch³4 Rrus³3 Csch³ Aspa?º +ÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v0 scph³10000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³0.12.0ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³0100JCÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³000117ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + scph³15000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³0.18.0ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³0101JCÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³000217ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + scph³18000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³0.22.0ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³0120JCÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³001027ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v1 scph³30000 ³30001 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v2 ³30000 ³30001 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v3 ³30000 ³30001 ³30002 ³30003 ³30004 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v4 scph³30000 ³30001 ³30002 ³30003 ³30004 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³ ³ ³ ³0120EC³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³ ³ ³ ³000902³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ³35000 ³35001 ³35002 ³35003 ³35004 ³35005 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v5 ³30000 ³30001 ³30002 ³30003 ³30004 ³30005 ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + scph³30000R³30001R³30002R³30003R³30004R³30005R³30006R³30007RÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³0.32.0³ ³ ³2.32.0³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³0160JC³ ³ ³0160EC³0160EC³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³011004³ ³ ³011004³011004³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v6 ³ ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v7 scph³37000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + ³39000 ³39001 ³39002 ³39003 ³39004 ³39005 ³39006 ³39007 ³39008 ÃÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³ ³1.36.0³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄĶ + ver³ ³0160AC³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄĶ + date³ ³020207³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÅÄÄÄÄÄĶ + ÃÄÄÄÄÄÄ´39001NÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´39010Nº +ÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v8 scph³39000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´39006 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ + mecha³0.38.0³ ³ ³ ³ ³ ³ ³ ³ ³ ³ º + ver³0160JC³ ³ ³ ³ ³ ³ ³ ³ ³ ³ º + date³020426³ ³ ³ ³ ³ ³ ³ ³ ³ ³ º +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v9 scph³50000 ³50001 ³50002 ³50003 ³50004 ³50005N³50006 ³50007 ³50008 ³50009 ÃÄÄÄÄÄĶ + ÃÄÄÄÄÄÄ´50001NÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´50010Nº + ³55000 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´55005N³55006 ³55007 ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +ÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄĶ +v10 scph³ ³50001 ³50002 ³50003 ³50004 ³ ³50006 ³50007 ³ ³50009 ³50010 º + mecha³ ³ ³ ³ ³ ³ ³4.54.0³4.??.0³ ³6.??.0³ º + ver³ ³ ³ ³ ³0190EC³ ³0190HC³0190HC³ ³0190CC³ º + date³ ³ ³ ³ ³030623³ ³030623³030623³ ³030623³ º +v11 ³ ³ ³ ³ ³50004 ³ ³ ³ ³ ³ ³ ºMexic USA +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍÎÍÍÍÍÍÍÑÍÍÍÍÍÍ» +v12 scph³70000 ÃÄÄÄÄÄÄ´70002 ³70003 ³70004 ³70005 ³70006 ³70007 ³70008 ³70009 ÃÄÄÄÄÄÄ´70011 ³70012 º + mecha³ ÃÄÄÄÄÄÄ´3.62.0³2.62.0³2.??.0³ ³4.64.0³ ³5.??.0³ ÃÄÄÄÄÄÄ´ ³1.60.0º + ver³0200JCÃÄÄÄÄÄÄ´0200EC³0200EC³0200EC³ ³0200HC³ ³0200EC³ ÃÄÄÄÄÄÄ´ ³0200ACº + date³040614ÃÄÄÄÄÄÄ´040614³040614³040614³ ³040614³ ³040614³ ÃÄÄÄÄÄÄ´ ³040614º +v13 scph³ ³70001 ³70002 ³70003 ³70004 ³ ³ ³ ³ ³ ³ ÌÍÍÍÍÍÍÏÍÍÍÍÍͼ +ÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͹ +v14 scph³75000 ³75001 ³75002 ³75003 ³75004 ³75005 ³75006 ³75007 ³75008 ÃÄÄÄÄÄÄ´75010 º + mecha³ ³1.66.0³3.66.0³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄ´ º + ver³ ³0220AC³0220EC³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄ´ º + date³ ³050620³050620³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄ´ º +ÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄĽ + + +============================================================================== +============================================================================== +============================================================================== + +[ ID ] 1 +[name] Florin +[desc] CVS management rules +[hist] 2006-04-30 initial version + +Please do not commit on CVS temporary files or those made by development tools + (IDEs). Eg: *.suo/aps/opt/plg/ncb/exp +Keep it clean and before commiting a new module see the previous structure and + naming rules. If unsure about how to do any opperation please ASK. please ASK! +There's no rush ;) +Also, I'm considering switching to SVN, as CVS seems to be *abandoned* by + sourceforge.net +Any change to sources has to be commited to the public CVS. The risk of + stealing is faced by any open-source developer - the difference is the + quality! The original will always stand up ;) +Try not to break the source by your patches. Although linux and 64-bit versions + are not maintained atm, your changes should be done with all versions in mind. +Happy coding :) diff --git a/pcsx2/Docs/readme 0.9.4.txt b/pcsx2/Docs/readme 0.9.4.txt new file mode 100644 index 0000000000..2048b28cb2 --- /dev/null +++ b/pcsx2/Docs/readme 0.9.4.txt @@ -0,0 +1,146 @@ +PCSX2 is a PlayStation 2 emulator for Windows and Linux, started by the same team that brought you PCSX (a Sony PlayStation 1 emulator). + +The PCSX2 project attempts to allow PS2 code to be executed on your computer, thus meaning you can put a PS2 DVD or CD into your computers drive, and boot it up! + + +Overview + +The project has been running for more than five years now, and since it's initial release has grown in compatibility. From initially just being able to run a few public domain demos, it's current state enables many games to boot and actually go in game, such as the 'famous' Final Fantasy X or Devil May Cry 3. You can always visit the PCSX2 homepage (http://www.pcsx2.net) to check the latest compatibility status of games with more than 1800 titles tested. + + +Configuration + +A very detailed guide is available on the PCSX2 homepage which is already translated in several languages! +You can consult it here: http://www.pcsx2.net/guide.php + + +Status + +PCSX2 has come a long way since its’ starting point back at 2002.Current features include: + +•Separate recompilers for Emotion Engine (EE) , Vector Unit 0 (VU0) and Vector Unit 1 (VU1). +•Dual core support, with the Graphics Synthesizer (GS) running on a second thread. +•Usage of MMX,SSE1,SSE2 and limited SSE3 extensions +•Proper SPU2 emulation featuring Auto DMA and Time Scaling +•Full gamepad support featuring Dual Shock 2,analog controls and even supporting analog movement over keyboard (using some external plugins) +•Patch system for creating cheats and for workarounds on games + +Sections that still need work: + +•Dev9 functions, such as HDD and Ethernet (partially implemented) support +•Firewire emulation (quite low on the list though) +•USB emulation (very partially implemented) +•Image Processing Unit (IPU) emulation which is responsible for the FMV playback.It has been implemented but it is buggy and slow +•MIPS cache needs to be properly implemented (barely works at this time) + + + + +How can you help + +As most of you are aware, the PCSX2 team is working on this project at the expense of their free time and provide it without charging the program’s use. +If you want to show your appreciation to these people and motivate them, you can donate any amount of money you feel is right to the team’s paypal account found in the official site. +These funds will be used so the team members can get more modern and new hardware in order to test and debug more efficiently and even implement new features (just like dual core support for example). + +If you are a programmer and you are interested in helping the PCSX2 team by making additions or corrections to the code, you are free to browse through the public SVN repository here (http://sourceforge.net/projects/pcsx2) after taking into account PCSX2 is under the GNU General Public Licence (GPL) v2. + + + +The Coding Team + +Below you can see 3 tables, showing the current team members who are actively coding at the present time, the current team members who have been inactive for some time and the older team members who for some reason quit along the way, which include the previous project leader Linuzappz to whom we send our best regards :) + + +Current active team members: + +Nickname Real Name Place Occupation Comments + +florin Florin Sasu Romania co-coder Master of HLE. Master of cd code and bios HLE.. +saqib - Pakistan Main Coder Fixing bugs around (FPU, Interpreter, VUs...) +Nachnbrenner - Germany co-coder patch freak :P +aumatt Australia co-coder a bit of everything mostly handles CDVD cmds +refraction Alex Brown England co-coder General Coding DMA/VIF etc +zerofrog - USA co-coder Recompilers, ZeroGS, x86-64, linux, optimizations, general fixes and new features + +Current inactive team members: + +Nickname Real Name Place Occupation Comments + +Shadow George Moralis Greece co-coder Master of cpu, master of bugs, general coding… +Goldfinger - Brazil co-coder MMI,FPU and general stuff +loser - Australia co-coder obscure cdvd related stuff + +Ex team members: + +Nickname Real Name Place Occupation Comments + +Linuzappz - Argentina Main Coder Master of The GS emulation and so many others.. +basara - - co-coder Recompiler programmer. general coding +[TyRaNiD] - - co-coder GS programmer.General coding +Roor - - co-coder General coding + +Additional coding: +F|RES, Pofis, Gigaherz, Nocomp, _Riff_, fumofumo + +The Beta Tester Team + +Beta testers are people (slaves/mindless grunts :P) who constantly test new PCSX2 beta builds to report any new bugs, regressions or improvements. While this might sound simple to most, what many people do not know is that testers also debug with the coders, maintain the huge game compatibility list, create dumps and logs for the coders and so much more. As above, active, inactive and ex members are listed alphabetically + +Current active members: + +Bositman, CKemu, Crushtest, Falcon4Ever, GeneralPlot, Prafull, RPGWizard, RudyX, Parotaku + + +Current inactive team members: + +Belmont, Knuckles, Raziel + + +Ex team members: +Chaoscode, CpUMasteR, EFX , Elly, JegHegy, Razorblade, Seta San, Snake875 + + +Additional thanks and credits + +Duke of NAPALM: For the 3d stars demo. The first demo that worked in pcsx2 :) +Tony Saveski (dreamtime): For his great ps2tutorials!! +F|res: Author of dolphin, a big thanks from shadow.. +Now3d: The guy that helped shadow at his first steps.. +Keith: Who believed in us.. +Bobbi & Thorgal: For hosting us, for the old page design and so many other things +Sjeep: Help and info +BGnome: Help testing stuff +Dixon: Design of the old pcsx2 page, and the pcsx2.net domain +Bositman: PCSX2 beta tester :) (gia sou bositman pare ta credits sou ) +No-Reccess: Nice guy and great demo coder :) +NSX2 team: For their help with VU ;) +Razorblade: For the old PCSX2 logo & icon. +Snake: He knows what for :P +Ector: Awesome emu :) +Zezu: A good guy. Good luck with your emu :P +Hiryu & Sjeep: For their libcdvd (iso parsing and filesystem driver code) +Sjeep: For the SjDATA filesystem driver +F|res: For the original DECI2 implementation +libmpeg2: For the mpeg2 decoding routines +Aumatt: For applying fixes to pcsx2 +Microsoft: For VC.Net 2003 (and now 2005) (really faster than vc6) :P +NASM team: For nasm +CKemu: Logos/design + +and probably to a few more.. + +Special Shadow's thanks go to... + +My friends: Dimitris, James, Thodoris, Thanasis and probably to a few more..and of course to a lady somewhere out there.... + + +Created for v0.9.4 by bositman. + + + + + + + +The PCSX2 Coding and Beta testing team + diff --git a/pcsx2/Docs/specs.tex b/pcsx2/Docs/specs.tex new file mode 100644 index 0000000000..aca2581945 --- /dev/null +++ b/pcsx2/Docs/specs.tex @@ -0,0 +1,159 @@ +\documentclass[10pt]{article} + +\begin{document} +\section{...stuff...} +-order the plugins are started\\ +-platform dependent stuff, calling convention\\ + +\section{Generic functions} +The following three functions will be present in all the plugin libraries, + in order to be recognized as valid PS2E plugins. They will help + the emulator to find a plugin capabilities. + +\subsection{PS2EgetLibType} +\begin{quote}\texttt{unsigned int} PS2EgetLibType(\texttt{void});\end{quote} + +\begin{description} +\item[PS2EgetLibType] returns the type of the plugin. + In fact it indicates the APIs supported by the dynamic library. + The returned value can be one of: +\begin{itemize} +\item PS2E\_LT\_GS 0x01 +\item PS2E\_LT\_PAD 0x02 +\item PS2E\_LT\_SPU2 0x04 +\item PS2E\_LT\_CDVD 0x08 +\item PS2E\_LT\_DEV9 0x10 +\end{itemize} +Currently, these are the only plugin types supported. Note that the values + can be ORed. +\end{description} + + + +\subsection{PS2EgetLibVersion2} +\begin{quote}\texttt{unsigned int} PS2EgetLibVersion2(\texttt{unsigned int} + type);\end{quote} + +\begin{description} +\item[PS2EgetLibVersion2] returns a combination of version numbers. +Parameter \emph{type} is used to select the functions set for which + the emulator requests version information. See \texttt{PS2EgetLibType} + for the values of this parameter. + +The 5 APIs and their corresponding specs have changed over time. + In order to prevent crashes and incompatibilities, a spec version have + been introduced as the highest 16 bits of the returned value. +\begin{itemize} +\item PS2E\_GS\_VERSION 0x0002 +\item PS2E\_PAD\_VERSION 0x0002 +\item PS2E\_SPU2\_VERSION 0x0002 +\item PS2E\_CDVD\_VERSION 0x0003 +\item PS2E\_DEV9\_VERSION 0x0001 +\end{itemize} +Notice that when the specs do change \texttt{and} the compatibility is broken, + this version number is increased. The emulator loading code will support + only one version for a certain library type at a time. If the internal + version and plugin API version does not match, the plugin + will not be loaded nor used. + +The low half of the returned value reflects the version of the plugin itself. + A major.minor versioning scheme is used on the two bytes like this: +\begin{verbatim} +...//code +return (PS2E_CDVD_VERSION<<16) | (0<<8) | (67); //version 0.67 +\end{verbatim} +\end{description} + + + +\subsection{PS2EgetLibName} +\begin{quote}\texttt{char*} PS2EgetLibName(\texttt{void});\end{quote} + +\begin{description} +\item[PS2EgetLibName] returns a string that contains a short\footnote{ +less then 30 chars in one line} name. The string is stored + in the plugin and will be used to represent the plugin in a config dialog. +\end{description} + + + + + +\section{CDVD functions} +This section describes the functions that corresponds to CDVD\footnote{short for CD/DVD} +API - type PS2E\_LT\_CDVD(0x08). + These specs are for PS2E\_CDVD\_VERSION(0x0003). + +\subsection{CDVDinit} +\begin{quote}\texttt{int} CDVDinit(\texttt{void});\end{quote} + +\begin{description} +\item[CDVDinit] does the initialization of the CDVD interface. + It is the first function called; so, it can be used to do all the + init stuff such as reading saved configuration, one-time hardware init and + preparing the internal structures, tables, etc\ldots + If an error is found the function will return -1, otherwise 0. +\end{description} + + + +\subsection{CDVDshutdown} +\begin{quote}\texttt{void} CDVDshutdown(\texttt{void});\end{quote} + +\begin{description} +\item[CDVDshutdown] is called when the emulator is closed. Do now the freeing + operations. DO NOT FORGET TO FREE the resources used. The OS will probably + free the garbage left, but some pieces of hardware might need a + ``deinitialization'' procedure in order to work next time the emulator + is run. Imagine that the user will choose another plugin to run with + next time instead of yours, do not cause troubles. +\end{description} + + + +\subsection{CDVDopen} +\begin{quote}\texttt{int} CDVDopen(\texttt{void});\end{quote} + +\begin{description} +\item[CDVDopen] is called when the emulation starts. + It is recommended that functions called from now on (until + \texttt{CDVDclose} is met) to spend few processing time. Avoid calling + blocking functions and if you do, the user should be notified visualy. + Report errors by return value and warrings using a log. + If an error is found the function will return -1 and the emulation stops, + otherwise 0. + +Do not report errors using message boxes while the emu runs, the GS plugin + might use a display mode that can cause troubles to windowing system + in showing your message. +\end{description} + + + +\subsection{CDVDclose} +\begin{quote}\texttt{void} CDVDclose(\texttt{void});\end{quote} + +\begin{description} +\item[CDVDclose] is called when the emulation is stopped. Some of the + resources that you aquired with \texttt{CDVDstart} have to be released now + in order that other programs to use them. If you locked the CD/DVD tray, + unlock it so the user can change the disc. +\end{description} + + + +\subsection{CDVDreadTrack} +\begin{quote}\texttt{int} CDVDreadTrack(\texttt{unsigned int} + lsn, \texttt{int} mode);\end{quote} + +\begin{description} +\item[CDVDreadTrack] is the function that performs the read of \texttt{a} + sector from the CD/DVD. Parameter \emph{lsn} specifies the absolute value + of the sector number in linear addressing mode without \emph{lead-in}\footnote{i.e.\ +without leading 150 sectors == 2 seconds}. Usualy, the plugin will read + a full sector of 2352 bytes in its internal buffer. + The second parameter tells what port of ... +\end{description} + +\end{document} + diff --git a/pcsx2/EEregs.h b/pcsx2/EEregs.h new file mode 100644 index 0000000000..2af2517334 --- /dev/null +++ b/pcsx2/EEregs.h @@ -0,0 +1,40 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __EEREGS_H__ +#define __EEREGS_H__ + +#define at cpuRegs.GPR.n.at +#define k0 cpuRegs.GPR.n.k0 +#define k1 cpuRegs.GPR.n.k1 +#define v0 cpuRegs.GPR.n.v0 +#define v1 cpuRegs.GPR.n.v1 +#define a0 cpuRegs.GPR.n.a0 +#define a1 cpuRegs.GPR.n.a1 +#define a2 cpuRegs.GPR.n.a2 +#define a3 cpuRegs.GPR.n.a3 +#define t0 cpuRegs.GPR.n.t0 +#define s0 cpuRegs.GPR.n.s0 +#define gp cpuRegs.GPR.n.gp +#define fp cpuRegs.GPR.n.s8 +#define sp cpuRegs.GPR.n.sp +#define ra cpuRegs.GPR.n.ra + +#define pc0 cpuRegs.pc + +#endif /* __EEREGS_H__ */ diff --git a/pcsx2/Elfheader.c b/pcsx2/Elfheader.c new file mode 100644 index 0000000000..5c08032baf --- /dev/null +++ b/pcsx2/Elfheader.c @@ -0,0 +1,702 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include //2002-09-28 (Florin) +#include + +#include "Common.h" +#include "CDVDisodrv.h" + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +u32 ElfCRC; + +typedef struct { + u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) + u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //Processor: 8=MIPS R3000 + u32 e_version; //Version: 1=current + u32 e_entry; //Entry point address + u32 e_phoff; //Start of program headers (offset from file start) + u32 e_shoff; //Start of section headers (offset from file start) + u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //Program headers entry size + u16 e_phnum; //Number of program headers + u16 e_shentsize; //Section headers entry size + u16 e_shnum; //Number of section headers + u16 e_shstrndx; //Section header stringtable index +} ELF_HEADER; + +typedef struct { + u32 p_type; //see notes1 + u32 p_offset; //Offset from file start to program segment. + u32 p_vaddr; //Virtual address of the segment + u32 p_paddr; //Physical address of the segment + u32 p_filesz; //Number of bytes in the file image of the segment + u32 p_memsz; //Number of bytes in the memory image of the segment + u32 p_flags; //Flags for segment + u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +} ELF_PHR; + +/* +notes1 +------ +0=Inactive +1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +2=Dynamic linking +3=Interpreter. The array element must specify a path name +4=Note. The array element must specify the location and size of aux. info +5=reserved +6=The array element must specify location and size of the program header table. +*/ + +typedef struct { + u32 sh_name; //No. to the index of the Section header stringtable index + u32 sh_type; //See notes2 + u32 sh_flags; //see notes3 + u32 sh_addr; //Section start address + u32 sh_offset; //Offset from start of file to section + u32 sh_size; //Size of section + u32 sh_link; //Section header table index link + u32 sh_info; //Info + u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //Fixed size entries. +} ELF_SHR; +/* +notes 2 +------- +Type: +0=Inactive +1=PROGBITS +2=SYMTAB symbol table +3=STRTAB string table +4=RELA relocation entries +5=HASH hash table +6=DYNAMIC dynamic linking information +7=NOTE +8=NOBITS +9=REL relocation entries +10=SHLIB +0x70000000=LOPROC processor specifc +0x7fffffff=HIPROC +0x80000000=LOUSER lower bound +0xffffffff=HIUSER upper bound + +notes 3 +------- +Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +1=Write section contains data the is be writeable during execution. +2=Alloc section occupies memory during execution +4=Exec section contains executable instructions +0xf0000000=Mask bits processor-specific +*/ + +typedef struct { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +} Elf32_Sym; + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +typedef struct { + u32 r_offset; + u32 r_info; +} Elf32_Rel; + +//unfinished!!!! + +char *sections_names; + +ELF_HEADER *elfHeader; +ELF_PHR *elfProgH; +ELF_SHR *elfSectH; +char *name; +u8 *elfdata; +u32 elfsize; + +struct stat sbuf; +struct TocEntry toc; + +//2002-09-19 (Florin) +char args[256]="ez.m2v"; //to be accessed by other files +unsigned int args_ptr; //a big value; in fact, it is an address + +//in a0 is passed the address of the command line args, +//i.e. a pointer to an area like this: +//+00 unknown/unused +//+04 argc; number of arguments +//+08 argv[0]; address of the first parameter - program name (char*) - +//+08 argv[1]; address of the second parameter (char*) | +//+0C argv[2]; and so on | +//........ | +//+08+4*argc the program name(first param) <-- +//+08+4*argc+strlen(argv[0]+1) the rest of params; i.e. a copy of 'args' +// see above 'char args[256];' +unsigned int parseCommandLine( char *filename ) +{ + if ( ( args_ptr != 0xFFFFFFFF ) && ( args_ptr > 264 ) ) + { // 4 + 4 + 256 + char * p; + int argc, + i; + + args_ptr -= 256; + if ( args_ptr < 0 ) + { + return 0; + } + args[ 255 ] = 0; + memcpy( &PS2MEM_BASE[ args_ptr ], args, 256 ); //params 1, 2, etc copied + memset( &PS2MEM_BASE[ args_ptr + strlen( args ) ], 0, 256 - strlen( args ) ); +#ifdef _WIN32 + p = strrchr( filename, '\\' ); +#else //linux + p = strrchr( filename, '/' ); + if( p == NULL ) + p = strchr(filename, '\\'); +#endif + if ( p ) + { + p++; + } + else + { + p = filename; + } + args_ptr -= strlen( p ) + 1; + if ( args_ptr < 0 ) + { + return 0; + } + strcpy( (char*)&PS2MEM_BASE[ args_ptr ], p ); //fill param 0; i.e. name of the program + + for ( i = strlen( p ) + 1 + 256, argc = 0; i > 0; i-- ) + { + while ( i && ( ( PS2MEM_BASE[ args_ptr + i ] == 0 ) || ( PS2MEM_BASE[ args_ptr + i ] == 32 ) ) ) + { + i--; + } + if ( PS2MEM_BASE[ args_ptr + i + 1 ] == ' ' ) + { + PS2MEM_BASE[ args_ptr + i + 1 ] = 0; + } + while ( i && ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i] != 32 ) ) + { + i--; + } + if ( ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i ] != 32 ) ) + { //i==0 + argc++; + if ( args_ptr - 4 - 4 - argc * 4 < 0 ) + { + return 0; + } + ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i; + } + else + { + if ( ( PS2MEM_BASE[ args_ptr + i + 1 ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i + 1 ] != 32 ) ) + { + argc++; + if ( args_ptr - 4 - 4 - argc * 4 < 0 ) + { + return 0; + } + ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i + 1; + } + } + } + ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 1 ] = argc; //how many args + ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 2 ] = ( argc > 0); //have args? //not used, cannot be filled at all + + return ( args_ptr - argc * 4 - 8 ); + } + + return 0; +} +//--------------- + +int readFile( char *Exepath, char *ptr, u32 offset, int size ) { + FILE *f; + int fi; + + if ((strnicmp( Exepath, "cdrom0:", strlen("cdrom0:")) == 0) || + (strnicmp( Exepath, "cdrom1:", strlen("cdrom0:")) == 0)) { + if ((u32)offset >= toc.fileSize) return -1; + fi = CDVDFS_open(Exepath + strlen("cdromN:"), 1);//RDONLY + if (fi < 0) return -1; + CDVDFS_lseek(fi, offset, SEEK_SET); + size = CDVDFS_read(fi, ptr, size); + CDVDFS_close(fi ); + } else { + f = fopen(Exepath, "rb"); + if (f == NULL) return -1; + if ( offset >= (u64)sbuf.st_size) return -1; + fseek(f, offset, SEEK_SET); + size = fread(ptr, 1, size, f); + fclose(f); + } + + return size; +} + +int loadHeaders( char *Exepath ) { + elfHeader = (ELF_HEADER*)elfdata; + + if ( ( elfHeader->e_shentsize != sizeof(ELF_SHR) ) && ( elfHeader->e_shnum > 0 ) ) { + SysMessage( "size of section header not standard\n" ); + } + + if((elfHeader->e_shnum * elfHeader->e_shentsize) != 0) { + elfSectH = (ELF_SHR *) malloc( elfHeader->e_shnum * elfHeader->e_shentsize ); + } else { + elfSectH = NULL; + } + + if ( ( elfHeader->e_phnum * elfHeader->e_phentsize ) != 0 ) { + elfProgH = (ELF_PHR *) malloc( elfHeader->e_phnum * elfHeader->e_phentsize ); + } else { + elfProgH = NULL; + } + +#ifdef ELF_LOG + ELF_LOG( "type: " ); +#endif + switch( elfHeader->e_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", elfHeader->e_type ); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG( "no file type" ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG( "relocatable" ); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG( "executable" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); +#endif + switch ( elfHeader->e_machine ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown" ); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG( "mips_rs3000" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("version: %d\n",elfHeader->e_version); + ELF_LOG("entry: %08x\n",elfHeader->e_entry); + ELF_LOG("flags: %08x\n",elfHeader->e_flags); + ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); + ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); + ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); + ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); + ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); + ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); + ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); + ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); + + ELF_LOG("\n"); +#endif + + return TRUE; +} + + +BOOL loadProgramHeaders( char *Exepath ) +{ + int i; + + if ( elfHeader->e_phnum == 0 ) + { + return TRUE; + } + + // is this critical, or warning? + if ( elfHeader->e_phentsize != sizeof( ELF_PHR ) ) + { + SysMessage( "size of program header not standard\n" ); + } + + elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; + + for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); +#endif + switch ( elfProgH[ i ].p_type ) { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("load"); +#endif + if (elfProgH[ i ].p_offset < elfsize) { + int size; + + if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { + size = elfsize - elfProgH[ i ].p_offset; + } else { + size = elfProgH[ i ].p_filesz; + } + + if( elfProgH[ i ].p_vaddr != elfProgH[ i ].p_paddr ) + SysPrintf("ElfProgram different load addrs: paddr=0x%8.8x, vaddr=0x%8.8x\n", elfProgH[ i ].p_paddr, elfProgH[ i ].p_vaddr); + // used to be paddr + memcpy(&PS2MEM_BASE[elfProgH[ i ].p_vaddr & 0x1ffffff], + &elfdata[elfProgH[ i ].p_offset], + size); +#ifdef ELF_LOG + ELF_LOG("\t*LOADED*"); +#endif + } + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); + ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); + ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); + ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); + ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); + ELF_LOG("palign: %08x\n",elfProgH[i].p_align); + ELF_LOG("\n"); +#endif + } + + return TRUE; +} + + +BOOL loadSectionHeaders( char * Exepath ) +{ + int i; + int i_st = -1; + int i_dt = -1; + + if (elfHeader->e_shnum == 0 || + elfHeader->e_shoff > elfsize) { + return TRUE; + } + + elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; + + if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { + sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; + } + + for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); +#endif + if ( elfSectH[i].sh_flags & 0x2 ) { + //2002-09-19 (Florin) + args_ptr = min( args_ptr, elfSectH[ i ].sh_addr & 0x1ffffff ); + //--------------- +/* if (elfSectH[i].sh_offset < elfsize) { + int size; + + if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { + size = elfsize - elfSectH[i].sh_offset; + } else { + size = elfSectH[i].sh_size; + } + memcpy(&PS2MEM_BASE[ elfSectH[ i ].sh_addr &0x1ffffff ], + &elfdata[elfSectH[i].sh_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG( "\t*LOADED*" ); +#endif*/ + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("type: "); +#endif + switch ( elfSectH[ i ].sh_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG("unknown %08x",elfSectH[i].sh_type); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG("null"); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("progbits"); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG("symtab"); +#endif + break; + + case 0x3: +#ifdef ELF_LOG + ELF_LOG("strtab"); +#endif + break; + + case 0x4: +#ifdef ELF_LOG + ELF_LOG("rela"); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG("no bits"); +#endif + break; + + case 0x9: +#ifdef ELF_LOG + ELF_LOG("rel"); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); + ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); + ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); + ELF_LOG("size: %08x\n", elfSectH[i].sh_size); + ELF_LOG("link: %08x\n", elfSectH[i].sh_link); + ELF_LOG("info: %08x\n", elfSectH[i].sh_info); + ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); + ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); +#endif + // dump symbol table + + if ( elfSectH[ i ].sh_type == 0x02 ) + { + i_st = i; + i_dt = elfSectH[i].sh_link; + } + } + + if ( ( i_st >= 0 ) && ( i_dt >= 0 ) ) + { + char * SymNames; + Elf32_Sym * eS; + + SymNames = (char*)&elfdata[elfSectH[ i_dt ].sh_offset]; + eS = (Elf32_Sym*)&elfdata[elfSectH[ i_st ].sh_offset]; + SysPrintf("found %d symbols\n", elfSectH[ i_st ].sh_size / sizeof( Elf32_Sym )); + + for ( i = 1; i < (int)( elfSectH[ i_st ].sh_size / sizeof( Elf32_Sym ) ); i++ ) { + if ( ( eS[ i ].st_value != 0 ) && ( ELF32_ST_TYPE( eS[ i ].st_info ) == 2 ) ) { +// SysPrintf("%x:%s\n", eS[i].st_value, &SymNames[eS[i].st_name]); + disR5900AddSym( eS[i].st_value, &SymNames[ eS[ i ].st_name ] ); +/* if (!strcmp(&SymNames[eS[i].st_name], "sceSifCheckStatRpc")) { + psMu32(eS[i].st_value & 0x1ffffff) = (0x3b << 26) | 1; + SysPrintf("found sceSifCheckStatRpc!!\n"); + }*/ + } + } + } + + return TRUE; +} + +extern int LoadPatch(char *patchfile); +extern void LoadGameSpecificSettings(); + +int loadElfFile(char *filename) { + char str[256]; + char str2[256]; + u32 crc; + u32 i; + + SysPrintf("loadElfFile: %s\n", filename); + if (strnicmp( filename, "cdrom0:", strlen( "cdrom0:" ) ) && + strnicmp( filename, "cdrom1:", strlen( "cdrom1:" ) ) ) { + if ( stat( filename, &sbuf ) != 0 ) + return -1; + elfsize = sbuf.st_size; + } else { + CDVDFS_init( ); + if ( CDVD_findfile( filename + strlen( "cdromN:" ), &toc ) == -1 ) + return -1; + elfsize = toc.fileSize; + } + + SysPrintf("loadElfFile: %d\n", elfsize); + elfdata = (u8*)malloc(elfsize); + if (elfdata == NULL) return -1; + readFile(filename, (char*)elfdata, 0, elfsize); + +/* { + FILE *f = fopen("game.elf", "wb"); + fwrite(elfdata, 1, elfsize, f); + fclose(f); + }*/ + + //2002-09-19 (Florin) + args_ptr = 0xFFFFFFFF; //big value, searching for minimum + //------------------- + loadHeaders( filename ); + cpuRegs.pc = elfHeader->e_entry; //set pc to proper place + loadProgramHeaders( filename ); + loadSectionHeaders( filename ); + +#ifdef ELF_LOG + ELF_LOG( "PC set to: %8.8lx\n", cpuRegs.pc ); +#endif + cpuRegs.GPR.n.sp.UL[0] = 0x81f00000; + cpuRegs.GPR.n.gp.UL[0] = 0x81f80000; // might not be 100% ok + + //2002-09-19 (Florin) + cpuRegs.GPR.n.a0.UL[0] = parseCommandLine( filename ); + //--------------- + + for ( i = 0; i < 0x100000; i++ ) { + if ( strcmp( "rom0:OSDSYS", (char*)PSM( i ) ) == 0 ) { + strcpy( (char*)PSM( i ), filename ); + SysPrintf( "addr %x \"%s\" -> \"%s\"\n", i, "rom0:OSDSYS", filename ); + } + } + + //CRC + for (i=0, crc=0; i +#include "Common.h" +#include "R5900.h" +#include "InterTables.h" + +// Helper Macros +//**************************************************************** +#define _Ft_ ( ( cpuRegs.code >> 16 ) & 0x1F ) +#define _Fs_ ( ( cpuRegs.code >> 11 ) & 0x1F ) +#define _Fd_ ( ( cpuRegs.code >> 6 ) & 0x1F ) + +#define _FtValf_ fpuRegs.fpr[ _Ft_ ].f +#define _FsValf_ fpuRegs.fpr[ _Fs_ ].f +#define _FdValf_ fpuRegs.fpr[ _Fd_ ].f +#define _FAValf_ fpuRegs.ACC.f + +#define _ContVal_ fpuRegs.fprc[ 31 ] + +// Testing +#define _FtValUl_ fpuRegs.fpr[ _Ft_ ].UL +#define _FsValUl_ fpuRegs.fpr[ _Fs_ ].UL +#define _FdValUl_ fpuRegs.fpr[ _Fd_ ].UL +#define _FAValUl_ fpuRegs.ACC.UL + +//**************************************************************** + +void COP1() { +#ifdef FPU_LOG + FPU_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); +#endif + Int_COP1PrintTable[_Rs_](); +} + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + + + +void LWC1() { + s32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code);// ((cpuRegs.code & 0x8000 ? 0xFFFF8000 : 0)| (cpuRegs.code & 0x7fff)); + memRead32(addr, &fpuRegs.fpr[_Rt_].UL); +} + +void SWC1() { + s32 addr; + addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code);//((cpuRegs.code & 0x8000 ? 0xFFFF8000 : 0)| (cpuRegs.code & 0x7fff)); + memWrite32(addr, fpuRegs.fpr[_Rt_].UL); +} + +void COP1_BC1() { + Int_COP1BC1PrintTable[_Rt_](); +} + +void COP1_S() { + Int_COP1SPrintTable[_Funct_](); +} + +void COP1_W() { + Int_COP1WPrintTable[_Funct_](); +} + +void COP1_Unknown() { +#ifdef FPU_LOG + FPU_LOG("Unknown FPU opcode called\n"); +#endif +} + + + +void MFC1() { + if ( !_Rt_ ) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (s32)_FsValUl_; +} + +void CFC1() { + if ( !_Rt_ || ( _Fs_ != 0 && _Fs_ != 31 ) ) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (s32)fpuRegs.fprc[_Fs_]; +} + +void MTC1() { + _FsValUl_ = cpuRegs.GPR.r[_Rt_].UL[0]; +} + +void CTC1() { + if(_Fs_!=31) return; + fpuRegs.fprc[_Fs_] = cpuRegs.GPR.r[_Rt_].UL[0]; +} + +#define C_cond_S(cond) \ + _ContVal_ = ( _FsValf_ cond _FtValf_ ) ? \ + ( _ContVal_ | 0x00800000 ) : \ + ( _ContVal_ & ~0x00800000 ); + +void C_F() { _ContVal_ &= ~0x00800000;} //clears C regardless +void C_EQ() { C_cond_S(==); } +void C_LT() { C_cond_S(<); } +void C_LE() { C_cond_S(<=); } + +#define BC1(cond) \ + if ( ( _ContVal_ & 0x00800000 ) cond 0 ) { \ + intDoBranch( _BranchTarget_ ); \ + } +void BC1F() { BC1(==); } +void BC1T() { BC1(!=); } + +#define BC1L(cond) \ + if ( ( _ContVal_ & 0x00800000 ) cond 0 ) { \ + intDoBranch( _BranchTarget_ ); \ + } else cpuRegs.pc += 4; +void BC1FL() { BC1L(==); } // Equal to 0 +void BC1TL() { BC1L(!=); } // different from 0 + + +void ADD_S() { _FdValf_ = _FsValf_ + _FtValf_; } +void SUB_S() { _FdValf_ = _FsValf_ - _FtValf_; } +void MUL_S() { _FdValf_ = _FsValf_ * _FtValf_; } +void MOV_S() { _FdValf_ = _FsValf_; } +void NEG_S() { _FdValf_ = -_FsValf_; } +void ADDA_S() { _FAValf_ = _FsValf_ + _FtValf_; } +void SUBA_S() { _FAValf_ = _FsValf_ - _FtValf_; } +void MULA_S() { _FAValf_ = _FsValf_ * _FtValf_; } +void MADD_S() { _FdValf_ = _FAValf_ + ( _FsValf_ * _FtValf_ ); } +void MSUB_S() { _FdValf_ = _FAValf_ - ( _FsValf_ * _FtValf_ ); } +void MADDA_S() { _FAValf_ += _FsValf_ * _FtValf_; } +void MSUBA_S() { _FAValf_ -= _FsValf_ * _FtValf_; } +void ABS_S() { _FdValf_ = fpufabsf(_FsValf_); } +void MAX_S() { _FdValf_ = max( _FsValf_, _FtValf_ ); } +void MIN_S() { _FdValf_ = min( _FsValf_, _FtValf_ ); } +void DIV_S() { if ( _FtValf_ ) { _FdValf_ = _FsValf_ / _FtValf_; } } +void SQRT_S() { + //if ( _FtValf_ >= 0.0f ) { _FdValf_ = fpusqrtf( _FtValf_ ); } + //else { + _FdValf_ = fpusqrtf(fpufabsf(_FtValf_)); + //} +} +void CVT_S() { _FdValf_ = (float)(s32)_FsValUl_; } +void CVT_W() { + if ( ( _FsValUl_ & 0x7F800000 ) <= 0x4E800000 ) { _FdValUl_ = (s32)(float)_FsValf_; } + else if ( _FsValUl_ & 0x80000000 ) { _FdValUl_ = 0x80000000; } + else { _FdValUl_ = 0x7fffffff; } +} + +void RSQRT_S() { + if ( _FtValf_ >= 0.0f ) { + float tmp = fpusqrtf( _FtValf_ ); + if ( tmp != 0 ) { _FdValf_ = _FsValf_ / tmp; } + } +} + +//3322 2222 2222 1111 1111 1100 0000 0000 +//1098 7654 3210 9876 5432 1098 7654 3210 +//0000 0000 0000 0000 0000 0000 0000 0000 diff --git a/pcsx2/FPU2.cpp b/pcsx2/FPU2.cpp new file mode 100644 index 0000000000..e182329f30 --- /dev/null +++ b/pcsx2/FPU2.cpp @@ -0,0 +1,42 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include + +// sqrtf only defined in C++ +extern "C" { + +float (*fpusqrtf)(float fval) = 0; +float (*fpufabsf)(float fval) = 0; +float (*fpusinf)(float fval) = 0; +float (*fpucosf)(float fval) = 0; +float (*fpuexpf)(float fval) = 0; +float (*fpuatanf)(float fval) = 0; +float (*fpuatan2f)(float fvalx, float fvaly) = 0; + +void InitFPUOps() +{ + fpusqrtf = sqrtf; + fpufabsf = fabsf; + fpusinf = sinf; + fpucosf = cosf; + fpuexpf = expf; + fpuatanf = atanf; + fpuatan2f = atan2f; +} + +} diff --git a/pcsx2/FiFo.c b/pcsx2/FiFo.c new file mode 100644 index 0000000000..87260735fa --- /dev/null +++ b/pcsx2/FiFo.c @@ -0,0 +1,177 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "Common.h" +#include "Hw.h" +#include "GS.h" + +#include + +////////////////////////////////////////////////////////////////////////// +/////////////////////////// Quick & dirty FIFO :D //////////////////////// +////////////////////////////////////////////////////////////////////////// +extern int FIFOto_write(u32* pMem, int size); +extern void FIFOfrom_readsingle(void *value); + +extern int g_nIPU0Data; +extern u8* g_pIPU0Pointer; +extern int FOreadpos; +// NOTE: cannot use XMM/MMX regs +void ReadFIFO(u32 mem, u64 *out) { + if ((mem >= 0x10004000) && (mem < 0x10005000)) { +#ifdef VIF_LOG + VIF_LOG("ReadFIFO VIF0 0x%08X\n", mem); +#endif + out[0] = psHu64(mem ); + out[1] = psHu64(mem+8); + return; + } else + if ((mem >= 0x10005000) && (mem < 0x10006000)) { + +#ifdef PCSX2_DEVBUILD + VIF_LOG("ReadFIFO VIF1 0x%08X\n", mem); + + if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) { + SysPrintf("reading from vif1 fifo when stalled\n"); + } +#endif + + if (vif1Regs->stat & 0x800000) { + if (--psHu32(D1_QWC) == 0) { + vif1Regs->stat&= ~0x1f000000; + } else { + } + } + out[0] = psHu64(mem ); + out[1] = psHu64(mem+8); + return; + } else if( (mem&0xfffff010) == 0x10007000) { + + if( g_nIPU0Data > 0 ) { + out[0] = *(u64*)(g_pIPU0Pointer); + out[1] = *(u64*)(g_pIPU0Pointer+8); + FOreadpos = (FOreadpos + 4) & 31; + g_nIPU0Data--; + g_pIPU0Pointer += 16; + } + return; + }else if ( (mem&0xfffff010) == 0x10007010) { + FIFOfrom_readsingle((void*)out); + return; + } + SysPrintf("ReadFIFO Unknown %x\n", mem); +} + +void ConstReadFIFO(u32 mem) +{ + // not done +} + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +extern HANDLE g_hGsEvent; +#else +extern pthread_cond_t g_condGsEvent; +#endif + +void WriteFIFO(u32 mem, u64 *value) { + int ret; + + if ((mem >= 0x10004000) && (mem < 0x10005000)) { +#ifdef VIF_LOG + VIF_LOG("WriteFIFO VIF0 0x%08X\n", mem); +#endif + psHu64(mem ) = value[0]; + psHu64(mem+8) = value[1]; + vif0ch->qwc += 1; + ret = VIF0transfer((u32*)value, 4, 0); + assert(ret == 0 ); // vif stall code not implemented + } + else if ((mem >= 0x10005000) && (mem < 0x10006000)) { +#ifdef VIF_LOG + VIF_LOG("WriteFIFO VIF1 0x%08X\n", mem); +#endif + psHu64(mem ) = value[0]; + psHu64(mem+8) = value[1]; + +#ifdef PCSX2_DEVBUILD + if(vif1Regs->stat & VIF1_STAT_FDR) + SysPrintf("writing to fifo when fdr is set!\n"); + if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) { + SysPrintf("writing to vif1 fifo when stalled\n"); + } +#endif + vif1ch->qwc += 1; + ret = VIF1transfer((u32*)value, 4, 0); + assert(ret == 0 ); // vif stall code not implemented + } + else if ((mem >= 0x10006000) && (mem < 0x10007000)) { + u64* data; +#ifdef GIF_LOG + GIF_LOG("WriteFIFO GIF 0x%08X\n", mem); +#endif + + psHu64(mem ) = value[0]; + psHu64(mem+8) = value[1]; + + if( CHECK_MULTIGS ) { + data = (u64*)GSRingBufCopy(NULL, 16, GS_RINGTYPE_P3); + + data[0] = value[0]; + data[1] = value[1]; + GSgifTransferDummy(2, (u32*)data, 1); + GSRINGBUF_DONECOPY(data, 16); + + if( !CHECK_DUALCORE ) { +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + SetEvent(g_hGsEvent); +#else + pthread_cond_signal(&g_condGsEvent); +#endif + } + } + else { + FreezeXMMRegs(1); + GSGIFTRANSFER3((u32*)value, 1); + FreezeXMMRegs(0); + } + + } else + if ((mem&0xfffff010) == 0x10007010) { +#ifdef IPU_LOG + IPU_LOG("WriteFIFO IPU_in[%d] <- %8.8X_%8.8X_%8.8X_%8.8X\n", (mem - 0x10007010)/8, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); +#endif + //commiting every 16 bytes + while( FIFOto_write((void*)value, 1) == 0 ) { + SysPrintf("IPU sleeping\n"); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + } else { + SysPrintf("WriteFIFO Unknown %x\n", mem); + } +} + +void ConstWriteFIFO(u32 mem) { +} diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp new file mode 100644 index 0000000000..86f607c0d3 --- /dev/null +++ b/pcsx2/GS.cpp @@ -0,0 +1,1881 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// rewritten by zerofrog to add multithreading/gs caching to GS and VU1 + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#endif + +#include + +#include +#include + +using namespace std; + +extern "C" { + +#define PLUGINtypedefs // for GSgifTransfer1 + +#include "PS2Edefs.h" +#include "zlib.h" +#include "Elfheader.h" +#include "Misc.h" +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" +#include "VifDma.h" +#include "Memory.h" +#include "Hw.h" +#include "DebugTools/Debug.h" + +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "Counters.h" +#include "GS.h" + +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; +extern _GSfreeze GSfreeze; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; + +extern _PADupdate PAD1update, PAD2update; + +extern _GSsetupRecording GSsetupRecording; +extern _SPU2setupRecording SPU2setupRecording; + +// could convert to pthreads only easily, just don't have the time +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +HANDLE g_hGsEvent = NULL, // set when path3 is ready to be processed + g_hVuGSExit = NULL; // set when thread needs to exit +HANDLE g_hGSOpen = NULL, g_hGSDone = NULL; +HANDLE g_hVuGsThread = NULL; + +DWORD WINAPI GSThreadProc(LPVOID lpParam); + +#else +pthread_cond_t g_condGsEvent = PTHREAD_COND_INITIALIZER; +sem_t g_semGsThread; +pthread_mutex_t g_mutexGsThread = PTHREAD_MUTEX_INITIALIZER; +int g_nGsThreadExit = 0; +pthread_t g_VuGsThread; + +void* GSThreadProc(void* idp); + +#endif + +bool gsHasToExit=false; +int g_FFXHack=0; + +#ifdef PCSX2_DEVBUILD + +// GS Playback +int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save +int g_nLeftGSFrames = 0; // when saving, number of frames left +gzFile g_fGSSave; + +// MTGS recording +FILE* g_fMTGSWrite = NULL, *g_fMTGSRead = NULL; +u32 g_MTGSDebug = 0, g_MTGSId = 0; +#endif + +u32 CSRw; +void gsWaitGS(); + +extern long pDsp; +typedef u8* PU8; + +PCSX2_ALIGNED16(u8 g_MTGSMem[0x2000]); // mtgs has to have its own memory + +} // extern "C" + +#ifdef PCSX2_VIRTUAL_MEM +#define gif ((DMACh*)&PS2MEM_HW[0xA000]) +#else +#define gif ((DMACh*)&psH[0xA000]) +#endif + +#ifdef PCSX2_VIRTUAL_MEM +#define PS2GS_BASE(mem) ((PS2MEM_BASE+0x12000000)+(mem&0x13ff)) +#else +u8 g_RealGSMem[0x2000]; +#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) +#endif + +// dummy GS for processing SIGNAL, FINISH, and LABEL commands +typedef struct +{ + u32 nloop : 15; + u32 eop : 1; + u32 dummy0 : 16; + u32 dummy1 : 14; + u32 pre : 1; + u32 prim : 11; + u32 flg : 2; + u32 nreg : 4; + u32 regs[2]; + u32 curreg; +} GIFTAG; + +static GIFTAG g_path[3]; +static PCSX2_ALIGNED16(u8 s_byRegs[3][16]); + +// g_pGSRingPos == g_pGSWritePos => fifo is empty +u8* g_pGSRingPos = NULL, // cur pos ring is at + *g_pGSWritePos = NULL; // cur pos ee thread is at + +extern int g_nCounters[]; + +void gsInit() +{ + if( CHECK_MULTIGS ) { + +#ifdef _WIN32 + g_pGSRingPos = (u8*)VirtualAlloc(GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); +#else + // setup linux vm + g_pGSRingPos = (u8*)SysMmap((uptr)GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE); +#endif + if( g_pGSRingPos != GS_RINGBUFFERBASE ) { + SysMessage("Cannot alloc GS ring buffer\n"); + exit(0); + } + + memcpy(g_MTGSMem, PS2MEM_GS, sizeof(g_MTGSMem)); + InterlockedExchangePointer((volatile PVOID*)&g_pGSWritePos, GS_RINGBUFFERBASE); + + if( GSsetBaseMem != NULL ) + GSsetBaseMem(g_MTGSMem); + +#if defined(_DEBUG) && defined(PCSX2_DEVBUILD) + assert( g_fMTGSWrite == NULL && g_fMTGSRead == NULL ); + g_fMTGSWrite = fopen("mtgswrite.txt", "w"); + g_fMTGSRead = fopen("mtgsread.txt", "w"); +#endif + + gsHasToExit=false; + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + g_hGsEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + g_hVuGSExit = CreateEvent(NULL, FALSE, FALSE, NULL); + g_hGSOpen = CreateEvent(NULL, FALSE, FALSE, NULL); + g_hGSDone = CreateEvent(NULL, FALSE, FALSE, NULL); + + SysPrintf("gsInit\n"); + + g_hVuGsThread = CreateThread(NULL, 0, GSThreadProc, NULL, 0, NULL); +#else + SysPrintf("gsInit\n"); + sem_init(&g_semGsThread, 0, 0); + + pthread_mutex_lock(&g_mutexGsThread); + if( pthread_create(&g_VuGsThread, NULL, GSThreadProc, NULL) != 0 ) { + SysMessage("Failed to create gsthread\n"); + exit(0); + } + + pthread_mutex_lock(&g_mutexGsThread); + pthread_mutex_unlock(&g_mutexGsThread); +#endif + } +} + +void gsWaitGS() +{ + if( CHECK_DUALCORE ) { + while( *(volatile PU8*)&g_pGSRingPos != *(volatile PU8*)&g_pGSWritePos ); + } + else { + while( g_pGSRingPos != g_pGSWritePos ) { +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + } +} + +void gsShutdown() +{ + if( CHECK_MULTIGS ) { + + gsHasToExit=true; + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + SetEvent(g_hVuGSExit); + SysPrintf("Closing gs thread\n"); + WaitForSingleObject(g_hVuGsThread, INFINITE); + CloseHandle(g_hVuGsThread); + CloseHandle(g_hGsEvent); + CloseHandle(g_hVuGSExit); + CloseHandle(g_hGSOpen); + CloseHandle(g_hGSDone); +#else + InterlockedExchange((long*)&g_nGsThreadExit, 1); + sem_post(&g_semGsThread); + pthread_cond_signal(&g_condGsEvent); + SysPrintf("waiting for thread to terminate\n"); + pthread_join(g_VuGsThread, NULL); + + sem_destroy(&g_semGsThread); + + SysPrintf("thread terminated\n"); +#endif + gsHasToExit=false; + +#ifdef _WIN32 + VirtualFree(GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE, MEM_DECOMMIT|MEM_RELEASE); +#else + SysMunmap((uptr)GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE); +#endif + +#if defined(_DEBUG) && defined(PCSX2_DEVBUILD) + if( g_fMTGSWrite != NULL ) { + fclose(g_fMTGSWrite); + g_fMTGSWrite = NULL; + } + if( g_fMTGSRead != NULL ) { + fclose(g_fMTGSRead); + g_fMTGSRead = NULL; + } +#endif + } + else + GSclose(); +} + +u8* GSRingBufCopy(void* mem, u32 size, u32 type) +{ + u8* writepos = g_pGSWritePos; + u8* tempbuf; + assert( size < GS_RINGBUFFERSIZE ); + assert( writepos < GS_RINGBUFFEREND ); + assert( ((uptr)writepos & 15) == 0 ); + assert( (size&15) == 0); + + size += 16; + tempbuf = *(volatile PU8*)&g_pGSRingPos; + if( writepos + size > GS_RINGBUFFEREND ) { + + // skip to beginning + while( writepos < tempbuf || tempbuf == GS_RINGBUFFERBASE ) { + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + tempbuf = *(volatile PU8*)&g_pGSRingPos; + + if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) + break; + } + + // notify GS + if( writepos != GS_RINGBUFFEREND ) { + InterlockedExchangePointer((void**)writepos, GS_RINGTYPE_RESTART); + } + + InterlockedExchangePointer((void**)&g_pGSWritePos, GS_RINGBUFFERBASE); + writepos = GS_RINGBUFFERBASE; + } + else if( writepos + size == GS_RINGBUFFEREND ) { + while(tempbuf == GS_RINGBUFFERBASE && tempbuf != *(volatile PU8*)&g_pGSWritePos) { + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + + tempbuf = *(volatile PU8*)&g_pGSRingPos; + } + } + + while( writepos < tempbuf && (writepos+size >= tempbuf || (writepos+size == GS_RINGBUFFEREND && tempbuf == GS_RINGBUFFERBASE)) ) { + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + tempbuf = *(volatile PU8*)&g_pGSRingPos; + + if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) + break; + } + + // just copy + *(u32*)writepos = type|(((size-16)>>4)<<16); + return writepos+16; +} + +void GSRingBufSimplePacket(int type, int data0, int data1, int data2) +{ + u8* writepos = g_pGSWritePos; + u8* tempbuf; + + assert( writepos + 16 <= GS_RINGBUFFEREND ); + + tempbuf = *(volatile PU8*)&g_pGSRingPos; + if( writepos < tempbuf && writepos+16 >= tempbuf ) { + + do { + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + tempbuf = *(volatile PU8*)&g_pGSRingPos; + + if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) + break; + } while(writepos < tempbuf && writepos+16 >= tempbuf ); + } + + *(u32*)writepos = type; + *(int*)(writepos+4) = data0; + *(int*)(writepos+8) = data1; + *(int*)(writepos+12) = data2; + + writepos += 16; + if( writepos == GS_RINGBUFFEREND ) { + + while(tempbuf == GS_RINGBUFFERBASE && tempbuf != *(volatile PU8*)&g_pGSWritePos) { + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); +#ifdef _WIN32 + Sleep(1); +#else + usleep(500); +#endif + } + + tempbuf = *(volatile PU8*)&g_pGSRingPos; + } + + writepos = GS_RINGBUFFERBASE; + } + InterlockedExchangePointer((void**)&g_pGSWritePos, writepos); + + if( !CHECK_DUALCORE ) { + GS_SETEVENT(); + } +} + +void gsReset() +{ + SysPrintf("GIF reset\n"); + + // GSDX crashes + //if( GSreset ) GSreset(); + + if( CHECK_MULTIGS ) { + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + ResetEvent(g_hGsEvent); + ResetEvent(g_hVuGSExit); +#else + //TODO +#endif + gsHasToExit=false; + g_pGSRingPos = g_pGSWritePos; + } + + memset(g_path, 0, sizeof(g_path)); + memset(s_byRegs, 0, sizeof(s_byRegs)); + +#ifndef PCSX2_VIRTUAL_MEM + memset(g_RealGSMem, 0, 0x2000); +#endif + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now + GSIMR = 0x7f00; + psHu32(GIF_STAT) = 0; + psHu32(GIF_CTRL) = 0; + psHu32(GIF_MODE) = 0; +} + +void gsGIFReset() +{ + memset(g_path, 0, sizeof(g_path)); + +#ifndef PCSX2_VIRTUAL_MEM + memset(g_RealGSMem, 0, 0x2000); +#endif + + if( GSgifSoftReset != NULL ) + GSgifSoftReset(7); + if( CHECK_MULTIGS ) + memset(g_path, 0, sizeof(g_path)); + +// else +// GSreset(); + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now + GSIMR = 0x7f00; + psHu32(GIF_STAT) = 0; + psHu32(GIF_CTRL) = 0; + psHu32(GIF_MODE) = 0; +} + +void CSRwrite(u32 value) +{ + CSRw |= value & ~0x60; + GSwriteCSR(CSRw); + + GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f); + if( value & 0x100 ) { // FLUSH + //SysPrintf("GS_CSR FLUSH GS fifo: %x (CSRr=%x)\n", value, GSCSRr); + } + + if (value & 0x200) { // resetGS + //GSCSRr = 0x400E; // The host FIFO neeeds to be empty too or GSsync will fail (saqib) + //GSIMR = 0xff00; + if( GSgifSoftReset != NULL ) { + GSgifSoftReset(7); + if( CHECK_MULTIGS ) { + memset(g_path, 0, sizeof(g_path)); + memset(s_byRegs, 0, sizeof(s_byRegs)); + } + } + else GSreset(); + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 - GS is always at a finish state as we don't have a FIFO(saqib) + //Since when!! Refraction, since 4/21/06 (zerofrog) ok ill let you off, looks like theyre all set (ref) + GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1 + + // and this too (fixed megaman ac) + //CSRw = (u32)GSCSRr; + GSwriteCSR(CSRw); + } +} + +static void IMRwrite(u32 value) { + GSIMR = (value & 0x1f00)|0x6000; + + // don't update mtgs mem +} + +void gsWrite8(u32 mem, u8 value) { + switch (mem) { + case 0x12001000: // GS_CSR + CSRwrite((CSRw & ~0x000000ff) | value); break; + case 0x12001001: // GS_CSR + CSRwrite((CSRw & ~0x0000ff00) | (value << 8)); break; + case 0x12001002: // GS_CSR + CSRwrite((CSRw & ~0x00ff0000) | (value << 16)); break; + case 0x12001003: // GS_CSR + CSRwrite((CSRw & ~0xff000000) | (value << 24)); break; + default: + *PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE8, mem&0x13ff, value, 0); + } + } + +#ifdef GIF_LOG + GIF_LOG("GS write 8 at %8.8lx with data %8.8lx\n", mem, value); +#endif +} + +extern void UpdateVSyncRate(); + +void gsWrite16(u32 mem, u16 value) { + + switch (mem) { + case 0x12000010: // GS_SMODE1 + if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL + else Config.PsxType &= ~1; // NTSC + *(u16*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); + } + + UpdateVSyncRate(); + break; + + case 0x12000020: // GS_SMODE2 + if(value & 0x1) Config.PsxType |= 2; // Interlaced + else Config.PsxType &= ~2; // Non-Interlaced + *(u16*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); + } + + break; + + case 0x12001000: // GS_CSR + CSRwrite( (CSRw&0xffff0000) | value); + break; + case 0x12001002: // GS_CSR + CSRwrite( (CSRw&0xffff) | ((u32)value<<16)); + break; + case 0x12001010: // GS_IMR + SysPrintf("writing to IMR 16\n"); + IMRwrite(value); + break; + + default: + *(u16*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); + } + } + +#ifdef GIF_LOG + GIF_LOG("GS write 16 at %8.8lx with data %8.8lx\n", mem, value); +#endif +} + +void gsWrite32(u32 mem, u32 value) +{ + assert( !(mem&3)); + switch (mem) { + case 0x12000010: // GS_SMODE1 + if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL + else Config.PsxType &= ~1; // NTSC + *(u32*)PS2GS_BASE(mem) = value; + + UpdateVSyncRate(); + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); + } + + break; + case 0x12000020: // GS_SMODE2 + if(value & 0x1) Config.PsxType |= 2; // Interlaced + else Config.PsxType &= ~2; // Non-Interlaced + *(u32*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); + } + break; + + case 0x12001000: // GS_CSR + CSRwrite(value); + break; + + case 0x12001010: // GS_IMR + IMRwrite(value); + break; + default: + *(u32*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); + } + } + +#ifdef GIF_LOG + GIF_LOG("GS write 32 at %8.8lx with data %8.8lx\n", mem, value); +#endif +} + +void gsWrite64(u32 mem, u64 value) { + + switch (mem) { + case 0x12000010: // GS_SMODE1 + if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL + else Config.PsxType &= ~1; // NTSC + UpdateVSyncRate(); + *(u64*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); + } + + break; + + case 0x12000020: // GS_SMODE2 + if(value & 0x1) Config.PsxType |= 2; // Interlaced + else Config.PsxType &= ~2; // Non-Interlaced + *(u64*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, 0); + } + + break; + case 0x12001000: // GS_CSR + CSRwrite((u32)value); + break; + + case 0x12001010: // GS_IMR + IMRwrite((u32)value); + break; + + default: + *(u64*)PS2GS_BASE(mem) = value; + + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); + } + } + +#ifdef GIF_LOG + GIF_LOG("GS write 64 at %8.8lx with data %8.8lx_%8.8lx\n", mem, ((u32*)&value)[1], (u32)value); +#endif +} + +u8 gsRead8(u32 mem) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 8 %8.8lx, at %8.8lx\n", *(u8*)(PS2MEM_BASE+(mem&~0xc00)), mem); +#endif + + return *(u8*)PS2GS_BASE(mem); +} + +u16 gsRead16(u32 mem) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 16 %8.8lx, at %8.8lx\n", *(u16*)(PS2MEM_BASE+(mem&~0xc00)), mem); +#endif + + return *(u16*)PS2GS_BASE(mem); +} + +u32 gsRead32(u32 mem) { + +#ifdef GIF_LOG + GIF_LOG("GS read 32 %8.8lx, at %8.8lx\n", *(u32*)(PS2MEM_BASE+(mem&~0xc00)), mem); +#endif + return *(u32*)PS2GS_BASE(mem); +} + +u64 gsRead64(u32 mem) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 64 %8.8lx, at %8.8lx\n", *(u32*)PS2GS_BASE(mem), mem); +#endif + return *(u64*)PS2GS_BASE(mem); +} + +void gsIrq() { + hwIntcIrq(0); +} + +static void GSRegHandlerSIGNAL(u32* data) +{ +#ifdef GIF_LOG + GIF_LOG("GS SIGNAL data %x_%x CSRw %x\n",data[0], data[1], CSRw); +#endif + GSSIGLBLID->SIGID = (GSSIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + + if ((CSRw & 0x1)) + GSCSRr |= 1; // signal + + + if (!(GSIMR&0x100) ) + gsIrq(); + + +} + +static void GSRegHandlerFINISH(u32* data) +{ +#ifdef GIF_LOG + GIF_LOG("GS FINISH data %x_%x CSRw %x\n",data[0], data[1], CSRw); +#endif + if ((CSRw & 0x2)) + GSCSRr |= 2; // finish + + if (!(GSIMR&0x200) ) + gsIrq(); + +} + +static void GSRegHandlerLABEL(u32* data) +{ + GSSIGLBLID->LBLID = (GSSIGLBLID->LBLID&~data[1])|(data[0]&data[1]); +} + +typedef void (*GIFRegHandler)(u32* data); +static GIFRegHandler s_GSHandlers[3] = { GSRegHandlerSIGNAL, GSRegHandlerFINISH, GSRegHandlerLABEL }; +extern "C" int Path3transfer; + +// simulates a GIF tag +u32 GSgifTransferDummy(int path, u32 *pMem, u32 size) +{ + int nreg, i, nloop; + u32 curreg; + u32 tempreg; + GIFTAG* ptag = &g_path[path]; + + if( path == 0 ) { + nloop = 0; + } + else { + nloop = ptag->nloop; + curreg = ptag->curreg; + nreg = ptag->nreg == 0 ? 16 : ptag->nreg; + } + + while(size > 0) + { + if(nloop == 0) { + + ptag = (GIFTAG*)pMem; + nreg = ptag->nreg == 0 ? 16 : ptag->nreg; + + pMem+= 4; + size--; + + if( path == 2 && ptag->eop) Path3transfer = 0; //fixes SRS and others + + if( path == 0 ) { + // if too much data for VU1, just ignore + if( ptag->nloop * nreg > size * (ptag->flg==1?2:1) ) { +#ifdef PCSX2_DEVBUILD + //SysPrintf("MTGS: VU1 too much data\n"); +#endif + g_path[path].nloop = 0; + return ++size; // have to increment or else the GS plugin will process this packet + } + } + + if(ptag->nloop == 0 ) { + if( path == 0 ) { + + if( ptag->eop ) + return size; + + // ffx hack + if( g_FFXHack ) + continue; + + return size; + } + + g_path[path].nloop = 0; + + // motogp graphics show + if( !ptag->eop ) + continue; + + return size; + } + + tempreg = ptag->regs[0]; + for(i = 0; i < nreg; ++i, tempreg >>= 4) { + + if( i == 8 ) tempreg = ptag->regs[1]; + s_byRegs[path][i] = tempreg&0xf; + } + + nloop = ptag->nloop; + curreg = 0; + } + + switch(ptag->flg) + { + case 0: // PACKED + { + for(; size > 0; size--, pMem += 4) + { +// if( s_byRegs[path][curreg] == 11 ) { +// // pretty bad, just get out +// SysPrintf("MTGS: bad GS stream\n"); +// g_path[path].nloop = 0; +// return 0; +// } + +// // if VU1, make sure pMem never exceeds VU1 mem +// if( path == 0 && (u8*)pMem >= VU1.Mem + 0x4000 ) { +// SysPrintf("MTGS: memory exceeds bounds\n"); +// g_path[path].nloop = 0; +// return size; +// } + + if( s_byRegs[path][curreg] == 0xe && (pMem[2]&0xff) >= 0x60 ) { + if( (pMem[2]&0xff) < 0x63 ) + s_GSHandlers[pMem[2]&0x3](pMem); + } + + curreg++; + if (nreg == curreg) { + curreg = 0; + if( nloop-- <= 1 ) { + size--; + pMem += 4; + break; + } + } + } + + if( nloop > 0 ) { + assert(size == 0); + // midnight madness cares because the tag is 5 dwords + int* psrc = (int*)ptag; + int* pdst = (int*)&g_path[path]; + pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; + g_path[path].nloop = nloop; + g_path[path].curreg = curreg; + return 0; + } + + break; + } + case 1: // REGLIST + { + size *= 2; + + tempreg = ptag->regs[0]; + for(i = 0; i < nreg; ++i, tempreg >>= 4) { + + if( i == 8 ) tempreg = ptag->regs[1]; + assert( (tempreg&0xf) < 0x64 ); + s_byRegs[path][i] = tempreg&0xf; + } + + for(; size > 0; pMem+= 2, size--) + { + if( s_byRegs[path][curreg] >= 0x60 && s_byRegs[path][curreg] < 0x63 ) + s_GSHandlers[s_byRegs[path][curreg]&3](pMem); + + curreg++; + if (nreg == curreg) { + curreg = 0; + if( nloop-- <= 1 ) { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + + if( nloop > 0 ) { + assert(size == 0); + // midnight madness cares because the tag is 5 dwords + int* psrc = (int*)ptag; + int* pdst = (int*)&g_path[path]; + pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; + g_path[path].nloop = nloop; + g_path[path].curreg = curreg; + return 0; + } + + break; + } + case 2: // GIF_IMAGE (FROM_VFRAM) + case 3: + { + // simulate + if( (int)size < nloop ) { + // midnight madness cares because the tag is 5 dwords + int* psrc = (int*)ptag; + int* pdst = (int*)&g_path[path]; + pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; + g_path[path].nloop = nloop-size; + return 0; + } + else { + pMem += nloop*4; + size -= nloop; + nloop = 0; + } + break; + } + } + + if( path == 0 && ptag->eop ) { + g_path[0].nloop = 0; + return size; + } + } + + g_path[path] = *ptag; + g_path[path].curreg = curreg; + g_path[path].nloop = nloop; + return size; +} +static int gspath3done=0; +int gscycles = 0; + +void gsInterrupt() { +#ifdef GIF_LOG + GIF_LOG("gsInterrupt: %8.8x\n", cpuRegs.cycle); +#endif + + if((gif->chcr & 0x100) == 0){ + //SysPrintf("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x\n", gif->chcr, gif->qwc, done); + cpuRegs.interrupt &= ~(1 << 2); + return; + } + if(gif->qwc > 0 || gspath3done == 0) { + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + SysPrintf("gs dma masked\n"); + return; + } + + GIFdma(); +#ifdef GSPATH3FIX + if ((vif1Regs->mskpath3 && (vif1ch->chcr & 0x100)) || (psHu32(GIF_MODE) & 0x1)) cpuRegs.interrupt &= ~(1 << 2); +#endif + return; + } + + gspath3done = 0; + gscycles = 0; + Path3transfer = 0; + gif->chcr &= ~0x100; + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x4000; //FIFO empty + //psHu32(GIF_MODE)&= ~0x4; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 + hwDmacIrq(DMAC_GIF); + + cpuRegs.interrupt &= ~(1 << 2); +} + +static u64 s_gstag=0; // used for querying the last tag + +#define WRITERING_DMA(pMem, qwc) { \ + psHu32(GIF_STAT) |= 0xE00; \ + Path3transfer = 1; \ + if( CHECK_MULTIGS) { \ + u8* pgsmem = GSRingBufCopy(pMem, (qwc)<<4, GS_RINGTYPE_P3); \ + if( pgsmem != NULL ) { \ + int sizetoread = (qwc)<<4; \ + u32 pendmem = (u32)gif->madr + sizetoread; \ + /* check if page of endmem is valid (dark cloud2) */ \ + if( dmaGetAddr(pendmem-16) == NULL ) { \ + pendmem = ((pendmem-16)&~0xfff)-16; \ + while(dmaGetAddr(pendmem) == NULL) { \ + pendmem = (pendmem&~0xfff)-16; \ + } \ + memcpy_fast(pgsmem, pMem, pendmem-(u32)gif->madr+16); \ + } \ + else memcpy_fast(pgsmem, pMem, sizetoread); \ + \ + GSRINGBUF_DONECOPY(pgsmem, sizetoread); \ + GSgifTransferDummy(2, pMem, qwc); \ + } \ + \ + if( !CHECK_DUALCORE ) GS_SETEVENT(); \ + } \ + else { \ + GSGIFTRANSFER3(pMem, qwc); \ + if( GSgetLastTag != NULL ) { \ + GSgetLastTag(&s_gstag); \ + if( (s_gstag) == 1 ) { \ + Path3transfer = 0; /* fixes SRS and others */ \ + } \ + } \ + } \ +} \ + +int _GIFchain() { +#ifdef GSPATH3FIX + u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; +#else + u32 qwc = gif->qwc; +#endif + u32 *pMem; + + //if (gif->qwc == 0) return 0; + + pMem = (u32*)dmaGetAddr(gif->madr); + if (pMem == NULL) { + // reset path3, fixes dark cloud 2 + if( GSgifSoftReset != NULL ) + GSgifSoftReset(4); + if( CHECK_MULTIGS ) { + memset(&g_path[2], 0, sizeof(g_path[2])); + } + + //must increment madr and clear qwc, else it loops + gif->madr+= gif->qwc*16; + gif->qwc = 0; + SysPrintf("NULL GIFchain\n"); + return -1; + } + WRITERING_DMA(pMem, qwc); + + //if((psHu32(GIF_MODE) & 0x4)) amount -= qwc; + gif->madr+= qwc*16; + gif->qwc -= qwc; + return (qwc)*2; +} + +#define GIFchain() \ + if (gif->qwc) { \ + gscycles+= _GIFchain(); /* guessing */ \ + } + +int gscount = 0; +static int prevcycles = 0; +static u32* prevtag = NULL; + +void GIFdma() { + u32 *ptag; + gscycles= prevcycles ? prevcycles: gscycles; + u32 id; + + + /*if ((psHu32(DMAC_CTRL) & 0xC0)) { + SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); + }*/ + + + if( (psHu32(GIF_CTRL) & 8) ) { + // temporarily stop + SysPrintf("Gif dma temp paused?\n"); + + return; + } + +#ifdef GIF_LOG + GIF_LOG("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + gif->chcr, gif->madr, gif->qwc, + gif->tadr, gif->asr0, gif->asr1); +#endif + + +#ifndef GSPATH3FIX + if (psHu32(GIF_MODE) & 0x4) { + } else + if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { + gif->chcr &= ~0x100; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + hwDmacIrq(2); + return; + } +#endif + + FreezeXMMRegs(1); + FreezeMMXRegs(1); + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && prevcycles != 0) { // STD == GIF + SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); + + if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) ) { + INT(2, gscycles); + gscycles = 0; + FreezeXMMRegs(0); + FreezeMMXRegs(0); + return; + } + prevcycles = 0; + gif->qwc = 0; + } + + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x8000; //FIFO full + //psHu32(GIF_STAT)|= 0xE00; // OPH=1 | APATH=3 + psHu32(GIF_STAT)|= 0x10000000; // FQC=31, hack ;) + +#ifdef GSPATH3FIX + if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1){ + if(gif->qwc == 0){ + if((gif->chcr & 0x10e) == 0x104){ + ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR + + if (ptag == NULL) { //Is ptag empty? + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + FreezeXMMRegs(0); + FreezeMMXRegs(0); + return; + } + gscycles += 2; + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + gif->madr = ptag[1]; //MADR = ADDR field + gspath3done = hwDmacSrcChainWithStack(gif, id); +#ifdef GIF_LOG + GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], gif->qwc, id, gif->madr); +#endif + if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef GIF_LOG + GIF_LOG("PATH3 MSK dmaIrq Set\n"); +#endif + SysPrintf("GIF TIE\n"); + gspath3done |= 1; + } + + } + } + + GIFchain(); + + + if((gspath3done == 1 || (gif->chcr & 0xc) == 0) && gif->qwc == 0){ + if(gif->qwc > 0)SysPrintf("Horray\n"); + gspath3done = 0; + gif->chcr &= ~0x100; + //psHu32(GIF_MODE)&= ~0x4; + GSCSRr &= ~0xC000; + GSCSRr |= 0x4000; + Path3transfer = 0; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 + hwDmacIrq(DMAC_GIF); + } + FreezeXMMRegs(0); + FreezeMMXRegs(0); + //Dont unfreeze xmm regs here, Masked PATH3 can only be called by VIF, which is already handling it. + return; + } +#endif + //gscycles = 0; + // Transfer Dn_QWC from Dn_MADR to GIF + if ((gif->chcr & 0xc) == 0 || gif->qwc > 0) { // Normal Mode + //gscount++; + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && (gif->chcr & 0xc) == 0) { + SysPrintf("DMA Stall Control on GIF normal\n"); + } + GIFchain(); + if(gif->qwc == 0 && (gif->chcr & 0xc) == 0)gspath3done = 1; + } + else { + // Chain Mode +//#ifndef GSPATH3FIX + while (gspath3done == 0 && gif->qwc == 0) { //Loop if the transfers aren't intermittent +//#endif + ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + FreezeXMMRegs(0); + FreezeMMXRegs(0); + return; + } + gscycles+=2; // Add 1 cycles from the QW read for the tag + // Transfer dma tag if tte is set + if (gif->chcr & 0x40) { + //u32 temptag[4] = {0}; +#ifdef PCSX2_DEVBUILD + //SysPrintf("GIF TTE: %x_%x\n", ptag[3], ptag[2]); +#endif + + //temptag[0] = ptag[2]; + //temptag[1] = ptag[3]; + //GSGIFTRANSFER3(ptag, 1); + } + + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + gif->madr = ptag[1]; //MADR = ADDR field + + + + gspath3done = hwDmacSrcChainWithStack(gif, id); +#ifdef GIF_LOG + GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], gif->qwc, id, gif->madr); +#endif + + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80) { // STD == GIF + // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall + if(!gspath3done && gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) && id == 4) { + // stalled + SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); + prevcycles = gscycles; + gif->tadr -= 16; + hwDmacIrq(13); + INT(2, gscycles); + gscycles = 0; + FreezeXMMRegs(0); + FreezeMMXRegs(0); + return; + } + } + + GIFchain(); //Transfers the data set by the switch + + if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef GIF_LOG + GIF_LOG("dmaIrq Set\n"); +#endif + //SysPrintf("GIF TIE\n"); + + // SysPrintf("GSdmaIrq Set\n"); + gspath3done = 1; + //gif->qwc = 0; + //break; + } +//#ifndef GSPATH3FIX + } +//#endif + } + prevtag = NULL; + prevcycles = 0; + if (!(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1))) { + INT(2, gscycles); + gscycles = 0; + } + + FreezeXMMRegs(0); + FreezeMMXRegs(0); + + +} +void dmaGIF() { + /*if(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1)){ + INT(2, 48); //Wait time for the buffer to fill, fixes some timing problems in path 3 masking + } //It takes the time of 24 QW for the BUS to become ready - The Punisher, And1 Streetball + else*/ + gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) + + if(gif->qwc > 0 && (gif->chcr & 0x4) == 0x4) + gspath3done = 1; //Halflife sets a QWC amount in chain mode, no tadr set. + + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC ) { // GIF MFIFO + //SysPrintf("GIF MFIFO\n"); + gifMFIFOInterrupt(); + return; + } + + GIFdma(); +} + + + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) + +static unsigned int mfifocycles; +static unsigned int giftempqwc = 0; +static unsigned int gifqwc = 0; +static unsigned int gifdone = 0; + +int mfifoGIFrbTransfer() { + u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; + int mfifoqwc = min(gifqwc, qwc); + u32 *src; + + + /* Check if the transfer should wrap around the ring buffer */ + if ((gif->madr+mfifoqwc*16) > (psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16)) { + int s1 = ((psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16) - gif->madr) >> 4; + + /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + src = (u32*)PSM(gif->madr); + if (src == NULL) return -1; + WRITERING_DMA(src, s1); + + /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ + src = (u32*)PSM(psHu32(DMAC_RBOR)); + if (src == NULL) return -1; + WRITERING_DMA(src, (mfifoqwc - s1)); + + } else { + /* it doesn't, so just transfer 'qwc*16' words + from 'gif->madr' to GS */ + src = (u32*)PSM(gif->madr); + if (src == NULL) return -1; + + WRITERING_DMA(src, mfifoqwc); + gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR)); + } + + gifqwc -= mfifoqwc; + gif->qwc -= mfifoqwc; + gif->madr+= mfifoqwc*16; + mfifocycles+= (mfifoqwc) * 2; /* guessing */ + + + return 0; +} + + +int mfifoGIFchain() { + /* Is QWC = 0? if so there is nothing to transfer */ + + if (gif->qwc == 0) return 0; + + if (gif->madr >= psHu32(DMAC_RBOR) && + gif->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { + if (mfifoGIFrbTransfer() == -1) return -1; + } else { + int mfifoqwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; + u32 *pMem = (u32*)dmaGetAddr(gif->madr); + if (pMem == NULL) return -1; + + WRITERING_DMA(pMem, mfifoqwc); + gif->madr+= mfifoqwc*16; + gif->qwc -= mfifoqwc; + mfifocycles+= (mfifoqwc) * 2; /* guessing */ + } + + + + + return 0; +} + + + +void mfifoGIFtransfer(int qwc) { + u32 *ptag; + int id; + u32 temp = 0; + mfifocycles = 0; + + if(qwc > 0 ) { + gifqwc += qwc; + if(!(gif->chcr & 0x100))return; + } +#ifdef SPR_LOG + SPR_LOG("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); +#endif + + + + if(gif->qwc == 0){ + if(gif->tadr == spr0->madr) { + #ifdef PCSX2_DEVBUILD + /*if( gifqwc > 1 ) + SysPrintf("gif mfifo tadr==madr but qwc = %d\n", gifqwc);*/ + #endif + //hwDmacIrq(14); + + return; + } + gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR)); + ptag = (u32*)dmaGetAddr(gif->tadr); + + id = (ptag[0] >> 28) & 0x7; + gif->qwc = (ptag[0] & 0xffff); + gif->madr = ptag[1]; + mfifocycles += 2; + + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); + + #ifdef SPR_LOG + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", + ptag[1], ptag[0], gif->qwc, id, gif->madr, gif->tadr, gifqwc, spr0->madr); + #endif + gifqwc--; + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); + gifdone = 2; //End Transfer + break; + + case 1: // CNT - Transfer QWC following the tag. + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag + gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + gifdone = 0; + break; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = gif->madr; //Temporarily Store ADDR + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag + gif->tadr = temp; //Copy temporarily stored ADDR to Tag + gifdone = 0; + break; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag + gifdone = 0; + break; + + case 7: // End - Transfer QWC following the tag + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag + gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + gifdone = 2; //End Transfer + break; + } + if ((gif->chcr & 0x80) && (ptag[0] >> 31)) { +#ifdef SPR_LOG + SPR_LOG("dmaIrq Set\n"); +#endif + gifdone = 2; + } + } + FreezeXMMRegs(1); + FreezeMMXRegs(1); + if (mfifoGIFchain() == -1) { + SysPrintf("GIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", + gif->qwc, gif->madr, gif->tadr); + gifdone = 1; + } + FreezeXMMRegs(0); + FreezeMMXRegs(0); + + + + if(gif->qwc == 0 && gifdone == 2) gifdone = 1; + INT(11,mfifocycles); + +#ifdef SPR_LOG + SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); +#endif + +} + +void gifMFIFOInterrupt() +{ + + + if(!(gif->chcr & 0x100)) { SysPrintf("WTF GIFMFIFO\n");cpuRegs.interrupt &= ~(1 << 11); return ; } + + if(gifdone != 1) { + if(gifqwc <= 0) { + //SysPrintf("Empty\n"); + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + hwDmacIrq(14); + cpuRegs.interrupt &= ~(1 << 11); + return; + } + mfifoGIFtransfer(0); + return; + } + if(gifdone == 0 || gif->qwc > 0) { + SysPrintf("Shouldnt go here\n"); + cpuRegs.interrupt &= ~(1 << 11); + return; + } + //if(gifqwc > 0)SysPrintf("GIF MFIFO ending with stuff in it %x\n", gifqwc); + gifqwc = 0; + gifdone = 0; + gif->chcr &= ~0x100; + hwDmacIrq(DMAC_GIF); + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x4000; //FIFO empty + //psHu32(GIF_MODE)&= ~0x4; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 + cpuRegs.interrupt &= ~(1 << 11); +} + +int HasToExit() +{ + return (gsHasToExit!=0); +} + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +DWORD WINAPI GSThreadProc(LPVOID lpParam) +{ + HANDLE handles[2] = { g_hGsEvent, g_hVuGSExit }; + //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + + { + int ret; + HANDLE openhandles[2] = { g_hGSOpen, g_hVuGSExit }; + if( WaitForMultipleObjects(2, openhandles, FALSE, INFINITE) == WAIT_OBJECT_0+1 ) { + return 0; + } + ret = GSopen((void *)&pDsp, "PCSX2", 1); + GSCSRr = 0x551B400F; // 0x55190000 + SysPrintf("gsOpen done\n"); + if (ret != 0) { SysMessage ("Error Opening GS Plugin"); return (DWORD)-1; } + SetEvent(g_hGSDone); + } +#else +void* GSThreadProc(void* lpParam) +{ + // g_mutexGSThread already locked + SysPrintf("waiting for gsOpen\n"); + pthread_cond_wait(&g_condGsEvent, &g_mutexGsThread); + pthread_mutex_unlock(&g_mutexGsThread); + pthread_testcancel(); + if( g_nGsThreadExit ) + return NULL; + + int ret = GSopen((void *)&pDsp, "PCSX2", 1); + GSCSRr = 0x551B400F; // 0x55190000 + SysPrintf("gsOpen done\n"); + if (ret != 0) { + SysMessage ("Error Opening GS Plugin"); + return NULL; + } + + sem_post(&g_semGsThread); + pthread_mutex_unlock(&g_mutexGsThread); +#endif + + SysPrintf("Starting GS thread\n"); + u8* writepos; + u32 tag; + u32 counter = 0; + + while(!gsHasToExit) { + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + if( !CHECK_DUALCORE ) + { + if( WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0+1 ) + { + break; //exit thread and close gs + } + } +#else + if( !CHECK_DUALCORE ) { + sem_wait(&g_semGsThread); + if( g_nGsThreadExit ) { + GSclose(); + return 0; + } + } + else if( !(counter++ & 0xffff) ) { + if( g_nGsThreadExit ) { + GSclose(); + return 0; + } + } +#endif + + if( g_pGSRingPos != g_pGSWritePos ) { + + do { + writepos = *(volatile PU8*)&g_pGSWritePos; + + while( g_pGSRingPos != writepos ) { + + assert( g_pGSRingPos < GS_RINGBUFFEREND ); + // process until writepos + tag = *(u32*)g_pGSRingPos; + + switch( tag&0xffff ) { + case GS_RINGTYPE_RESTART: + InterlockedExchangePointer((volatile PVOID*)&g_pGSRingPos, GS_RINGBUFFERBASE); + + if( GS_RINGBUFFERBASE == writepos ) + goto ExitGS; + + continue; + + case GS_RINGTYPE_P1: + { + int qsize = (tag>>16); + MTGS_RECREAD(g_pGSRingPos+16, (qsize<<4)); + // make sure that tag>>16 is the MAX size readable + GSgifTransfer1((u32*)(g_pGSRingPos+16) - 0x1000 + 4*qsize, 0x4000-qsize*16); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16 + ((tag>>16)<<4)); + break; + } + case GS_RINGTYPE_P2: + MTGS_RECREAD(g_pGSRingPos+16, ((tag>>16)<<4)); + GSgifTransfer2((u32*)(g_pGSRingPos+16), tag>>16); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16 + ((tag>>16)<<4)); + break; + case GS_RINGTYPE_P3: + MTGS_RECREAD(g_pGSRingPos+16, ((tag>>16)<<4)); + GSgifTransfer3((u32*)(g_pGSRingPos+16), tag>>16); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16 + ((tag>>16)<<4)); + break; + case GS_RINGTYPE_VSYNC: + GSvsync(*(int*)(g_pGSRingPos+4)); + if( PAD1update != NULL ) PAD1update(0); + if( PAD2update != NULL ) PAD2update(1); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + + case GS_RINGTYPE_FRAMESKIP: + GSsetFrameSkip(*(int*)(g_pGSRingPos+4)); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + case GS_RINGTYPE_MEMWRITE8: + g_MTGSMem[*(int*)(g_pGSRingPos+4)] = *(u8*)(g_pGSRingPos+8); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + case GS_RINGTYPE_MEMWRITE16: + *(u16*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u16*)(g_pGSRingPos+8); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + case GS_RINGTYPE_MEMWRITE32: + *(u32*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u32*)(g_pGSRingPos+8); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + case GS_RINGTYPE_MEMWRITE64: + *(u64*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u64*)(g_pGSRingPos+8); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + + case GS_RINGTYPE_VIFFIFO: + { + u64* pMem; + assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); + assert( vif1ch->qwc == (tag>>16) ); + + assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); + pMem = (u64*)dmaGetAddr(vif1ch->madr); + + if (pMem == NULL) { + psHu32(DMAC_STAT)|= 1<<15; + break; + } + + if( GSreadFIFO2 == NULL ) { + int size; + for (size=(tag>>16); size>0; size--) { + GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); + pMem[0] = psHu64(0x5000); + pMem[1] = psHu64(0x5008); pMem+= 2; + } + } + else { + GSreadFIFO2(pMem, tag>>16); + + // set incase read + psHu64(0x5000) = pMem[2*(tag>>16)-2]; + psHu64(0x5008) = pMem[2*(tag>>16)-1]; + } + + assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); + assert( vif1ch->qwc == (tag>>16) ); + +// tag = (tag>>16) + (cpuRegs.cycle- *(u32*)(g_pGSRingPos+8)); +// if( tag & 0x80000000 ) tag = 0; + vif1ch->madr += vif1ch->qwc * 16; + if(vif1Regs->mskpath3 == 0)vif1Regs->stat&= ~0x1f000000; + + INT(1, 0); // since gs thread always lags real thread + vif1ch->qwc = 0; + + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + + case GS_RINGTYPE_SAVE: + { + gzFile f = *(gzFile*)(g_pGSRingPos+4); + freezeData fP; + + if (GSfreeze(FREEZE_SIZE, &fP) == -1) { + gzclose(f); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) { + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + + if (GSfreeze(FREEZE_SAVE, &fP) == -1) { + gzclose(f); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + + gzwrite(f, &fP.size, sizeof(fP.size)); + if (fP.size) { + gzwrite(f, fP.data, fP.size); + free(fP.data); + } + + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + case GS_RINGTYPE_LOAD: + { + gzFile f = *(gzFile*)(g_pGSRingPos+4); + freezeData fP; + + gzread(f, &fP.size, sizeof(fP.size)); + if (fP.size) { + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) { + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + + gzread(f, fP.data, fP.size); + } + if (GSfreeze(FREEZE_LOAD, &fP) == -1) { + // failed + } + if (fP.size) + free(fP.data); + + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + case GS_RINGTYPE_RECORD: + { + int record = *(int*)(g_pGSRingPos+4); + if( GSsetupRecording != NULL ) GSsetupRecording(record, NULL); + if( SPU2setupRecording != NULL ) SPU2setupRecording(record, NULL); + InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); + break; + } + default: + + SysPrintf("GSThreadProc, bad packet writepos: %x g_pGSRingPos: %x, g_pGSWritePos: %x\n", writepos, g_pGSRingPos, g_pGSWritePos); + assert(0); + g_pGSRingPos = g_pGSWritePos; + //flushall(); + } + + assert( g_pGSRingPos <= GS_RINGBUFFEREND ); + if( g_pGSRingPos == GS_RINGBUFFEREND ) + InterlockedExchangePointer((volatile PVOID*)&g_pGSRingPos, GS_RINGBUFFERBASE); + + if( g_pGSRingPos == g_pGSWritePos ) { + break; + } + } +ExitGS: + ; + } while(g_pGSRingPos != *(volatile PU8*)&g_pGSWritePos); + } + + // process vu1 + } + + GSclose(); + return 0; +} + +int gsFreeze(gzFile f, int Mode) { + + gzfreeze(PS2MEM_GS, 0x2000); + gzfreeze(&CSRw, sizeof(CSRw)); + gzfreeze(g_path, sizeof(g_path)); + gzfreeze(s_byRegs, sizeof(s_byRegs)); + + return 0; +} + +#ifdef PCSX2_DEVBUILD + +struct GSStatePacket +{ + u32 type; + vector mem; +}; + +// runs the GS +void RunGSState(gzFile f) +{ + u32 newfield; + list< GSStatePacket > packets; + + while(!gzeof(f)) { + int type, size; + gzread(f, &type, sizeof(type)); + + if( type != GSRUN_VSYNC ) gzread(f, &size, 4); + + packets.push_back(GSStatePacket()); + GSStatePacket& p = packets.back(); + + p.type = type; + + if( type != GSRUN_VSYNC ) { + p.mem.resize(size*16); + gzread(f, &p.mem[0], size*16); + } + } + + list::iterator it = packets.begin(); + g_SaveGSStream = 3; + + int skipfirst = 1; + + // first extract the data + while(1) { + + switch(it->type) { + case GSRUN_TRANS1: + GSgifTransfer1((u32*)&it->mem[0], 0); + break; + case GSRUN_TRANS2: + GSgifTransfer2((u32*)&it->mem[0], it->mem.size()/16); + break; + case GSRUN_TRANS3: + GSgifTransfer3((u32*)&it->mem[0], it->mem.size()/16); + break; + case GSRUN_VSYNC: + // flip + newfield = (*(u32*)(PS2MEM_GS+0x1000)&0x2000) ? 0 : 0x2000; + *(u32*)(PS2MEM_GS+0x1000) = (*(u32*)(PS2MEM_GS+0x1000) & ~(1<<13)) | newfield; + + GSvsync(newfield); + SysUpdate(); + + if( g_SaveGSStream != 3 ) + return; + +// if( skipfirst ) { +// ++it; +// it = packets.erase(packets.begin(), it); +// skipfirst = 0; +// } + + //it = packets.begin(); + //continue; + break; + default: + assert(0); + } + + ++it; + if( it == packets.end() ) + it = packets.begin(); + } +} + +#endif + +#undef GIFchain + diff --git a/pcsx2/GS.h b/pcsx2/GS.h new file mode 100644 index 0000000000..9bdd5d5a61 --- /dev/null +++ b/pcsx2/GS.h @@ -0,0 +1,233 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __GS_H__ +#define __GS_H__ + +typedef struct +{ + u32 SIGID; + u32 LBLID; +} GSRegSIGBLID; + +#define GSPATH3FIX + +#ifdef PCSX2_VIRTUAL_MEM +#define GSCSRr *((u64*)(PS2MEM_GS+0x1000)) +#define GSIMR *((u32*)(PS2MEM_GS+0x1010)) +#define GSSIGLBLID ((GSRegSIGBLID*)(PS2MEM_GS+0x1080)) +#else +extern u8 g_RealGSMem[0x2000]; +#define GSCSRr *((u64*)(g_RealGSMem+0x1000)) +#define GSIMR *((u32*)(g_RealGSMem+0x1010)) +#define GSSIGLBLID ((GSRegSIGBLID*)(g_RealGSMem+0x1080)) +#endif + +#define GS_RINGBUFFERBASE (u8*)(0x10200000) +#define GS_RINGBUFFERSIZE 0x00300000 // 3Mb +#define GS_RINGBUFFEREND (u8*)(GS_RINGBUFFERBASE+GS_RINGBUFFERSIZE) + +#define GS_RINGTYPE_RESTART 0 +#define GS_RINGTYPE_P1 1 +#define GS_RINGTYPE_P2 2 +#define GS_RINGTYPE_P3 3 +#define GS_RINGTYPE_VSYNC 4 +#define GS_RINGTYPE_VIFFIFO 5 // GSreadFIFO2 +#define GS_RINGTYPE_FRAMESKIP 6 +#define GS_RINGTYPE_MEMWRITE8 7 +#define GS_RINGTYPE_MEMWRITE16 8 +#define GS_RINGTYPE_MEMWRITE32 9 +#define GS_RINGTYPE_MEMWRITE64 10 +#define GS_RINGTYPE_SAVE 11 +#define GS_RINGTYPE_LOAD 12 +#define GS_RINGTYPE_RECORD 13 + +// if returns NULL, don't copy (memory is preserved) +u8* GSRingBufCopy(void* mem, u32 size, u32 type); +void GSRingBufSimplePacket(int type, int data0, int data1, int data2); + +extern u8* g_pGSWritePos; +#ifdef PCSX2_DEVBUILD + +// use for debugging MTGS +extern FILE* g_fMTGSWrite, *g_fMTGSRead; +extern u32 g_MTGSDebug, g_MTGSId; + +#define MTGS_RECWRITE(start, size) { \ + if( g_MTGSDebug & 1 ) { \ + u32* pstart = (u32*)(start); \ + u32 cursize = (u32)(size); \ + fprintf(g_fMTGSWrite, "*%x-%x (%d)\n", (u32)(uptr)(start), (u32)(size), ++g_MTGSId); \ + /*while(cursize > 0) { \ + fprintf(g_fMTGSWrite, "%x %x %x %x\n", pstart[0], pstart[1], pstart[2], pstart[3]); \ + pstart += 4; \ + cursize -= 16; \ + }*/ \ + if( g_MTGSDebug & 2 ) fflush(g_fMTGSWrite); \ + } \ +} \ + +#define MTGS_RECREAD(start, size) { \ + if( g_MTGSDebug & 1 ) { \ + u32* pstart = (u32*)(start); \ + u32 cursize = (u32)(size); \ + fprintf(g_fMTGSRead, "*%x-%x (%d)\n", (u32)(uptr)(start), (u32)(size), ++g_MTGSId); \ + /*while(cursize > 0) { \ + fprintf(g_fMTGSRead, "%x %x %x %x\n", pstart[0], pstart[1], pstart[2], pstart[3]); \ + pstart += 4; \ + cursize -= 16; \ + }*/ \ + if( g_MTGSDebug & 4 ) fflush(g_fMTGSRead); \ + } \ +} \ + +#else + +#define MTGS_RECWRITE 0&& +#define MTGS_RECREAD 0&& + +#endif + +// mem and size are the ones from GSRingBufCopy +#define GSRINGBUF_DONECOPY(mem, size) { \ + u8* temp = (u8*)(mem) + (size); \ + assert( temp <= GS_RINGBUFFEREND); \ + MTGS_RECWRITE(mem, size); \ + if( temp == GS_RINGBUFFEREND ) temp = GS_RINGBUFFERBASE; \ + InterlockedExchangePointer((void**)&g_pGSWritePos, temp); \ +} + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +#define GS_SETEVENT() SetEvent(g_hGsEvent) +#else +#include +#include +extern sem_t g_semGsThread; +#define GS_SETEVENT() sem_post(&g_semGsThread) +#endif + +u32 GSgifTransferDummy(int path, u32 *pMem, u32 size); + +void gsInit(); +void gsShutdown(); +void gsReset(); + +// used for resetting GIF fifo +void gsGIFReset(); + +void gsWrite8(u32 mem, u8 value); +void gsConstWrite8(u32 mem, int mmreg); + +void gsWrite16(u32 mem, u16 value); +void gsConstWrite16(u32 mem, int mmreg); + +void gsWrite32(u32 mem, u32 value); +void gsConstWrite32(u32 mem, int mmreg); + +void gsWrite64(u32 mem, u64 value); +void gsConstWrite64(u32 mem, int mmreg); + +void gsConstWrite128(u32 mem, int mmreg); + +u8 gsRead8(u32 mem); +int gsConstRead8(u32 x86reg, u32 mem, u32 sign); + +u16 gsRead16(u32 mem); +int gsConstRead16(u32 x86reg, u32 mem, u32 sign); + +u32 gsRead32(u32 mem); +int gsConstRead32(u32 x86reg, u32 mem); + +u64 gsRead64(u32 mem); +void gsConstRead64(u32 mem, int mmreg); + +void gsConstRead128(u32 mem, int xmmreg); + +void gsIrq(); +void gsInterrupt(); +void dmaGIF(); +void GIFdma(); +void mfifoGIFtransfer(int qwc); +int gsFreeze(gzFile f, int Mode); +int _GIFchain(); +void gifMFIFOInterrupt(); + +// GS Playback +#define GSRUN_TRANS1 1 +#define GSRUN_TRANS2 2 +#define GSRUN_TRANS3 3 +#define GSRUN_VSYNC 4 + +#ifdef PCSX2_DEVBUILD + +extern int g_SaveGSStream; +extern int g_nLeftGSFrames; +extern gzFile g_fGSSave; + +#define GSGIFTRANSFER1(pMem, addr) { \ + if( g_SaveGSStream == 2) { \ + int type = GSRUN_TRANS1; \ + int size = (0x4000-(addr))/16; \ + gzwrite(g_fGSSave, &type, sizeof(type)); \ + gzwrite(g_fGSSave, &size, 4); \ + gzwrite(g_fGSSave, ((u8*)pMem)+(addr), size*16); \ + } \ + GSgifTransfer1(pMem, addr); \ +} + +#define GSGIFTRANSFER2(pMem, size) { \ + if( g_SaveGSStream == 2) { \ + int type = GSRUN_TRANS2; \ + int _size = size; \ + gzwrite(g_fGSSave, &type, sizeof(type)); \ + gzwrite(g_fGSSave, &_size, 4); \ + gzwrite(g_fGSSave, pMem, _size*16); \ + } \ + GSgifTransfer2(pMem, size); \ +} + +#define GSGIFTRANSFER3(pMem, size) { \ + if( g_SaveGSStream == 2 ) { \ + int type = GSRUN_TRANS3; \ + int _size = size; \ + gzwrite(g_fGSSave, &type, sizeof(type)); \ + gzwrite(g_fGSSave, &_size, 4); \ + gzwrite(g_fGSSave, pMem, _size*16); \ + } \ + GSgifTransfer3(pMem, size); \ +} + +#define GSVSYNC() { \ + if( g_SaveGSStream == 2 ) { \ + int type = GSRUN_VSYNC; \ + gzwrite(g_fGSSave, &type, sizeof(type)); \ + } \ +} \ + +#else + +#define GSGIFTRANSFER1(pMem, size) GSgifTransfer1(pMem, size) +#define GSGIFTRANSFER2(pMem, size) GSgifTransfer2(pMem, size) +#define GSGIFTRANSFER3(pMem, size) GSgifTransfer3(pMem, size) +#define GSVSYNC() + +#endif + +void RunGSState(gzFile f); + +#endif diff --git a/pcsx2/Hw.c b/pcsx2/Hw.c new file mode 100644 index 0000000000..2df4c9f117 --- /dev/null +++ b/pcsx2/Hw.c @@ -0,0 +1,1496 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "PsxMem.h" +#include "IPU/IPU.h" +#include "GS.h" + +#include + +#ifndef PCSX2_VIRTUAL_MEM +u8 *psH; // hw mem +u16 *psHW; +u32 *psHL; +u64 *psHD; +#endif + +int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX +int rdram_sdevid = 0; + +int hwInit() { + +#ifndef PCSX2_VIRTUAL_MEM + psH = (u8*)_aligned_malloc(0x00010000, 16); + if (psH == NULL) { + SysMessage(_("Error allocating memory")); return -1; + } +#endif + + gsInit(); + vif0Init(); + vif1Init(); + vifDmaInit(); + sifInit(); + sprInit(); + ipuInit(); + + return 0; +} + +void hwShutdown() { +#ifndef PCSX2_VIRTUAL_MEM + if (psH == NULL) return; + _aligned_free(psH); psH = NULL; +#endif + ipuShutdown(); +} + +void hwReset() +{ + memset(PS2MEM_HW+0x2000, 0, 0x0000e000); + + psHu32(0xf520) = 0x1201; + psHu32(0xf260) = 0x1D000060; + // i guess this is kinda a version, it's used by some bioses + psHu32(0xf590) = 0x1201; + + gsReset(); + ipuReset(); +} + +u8 hwRead8(u32 mem) +{ + u8 ret; + +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10000000 && mem < 0x10008000 ) + SysPrintf("hwRead8 to %x\n", mem); +#endif + +#ifdef SPR_LOG + SPR_LOG("Hardware read 8bit at %lx, ret %lx\n", mem, psHu8(mem)); +#endif + + switch (mem) { + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) ret = 0; + else if(mem == 0x1000F240) { + ret = psHu32(mem); + //psHu32(mem) &= ~0x4000; + } + else ret = psHu32(mem); + return (u8)ret; + } + + if (mem < 0x10010000) + { + ret = psHu8(mem); + } + else ret = 0; +#ifdef HW_LOG + HW_LOG("Unknown Hardware Read 8 at %x\n",mem); +#endif + break; + } + + return ret; +} + +u16 hwRead16(u32 mem) +{ + u16 ret; + +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10002000 && mem < 0x10008000 ) + SysPrintf("hwRead16 to %x\n", mem); +#endif + +#ifdef SPR_LOG + SPR_LOG("Hardware read 16bit at %lx, ret %lx\n", mem, psHu16(mem)); +#endif + switch (mem) { + case 0x10000000: ret = (u16)rcntRcount(0); break; + case 0x10000010: ret = (u16)counters[0].mode; break; + case 0x10000020: ret = (u16)counters[0].target; break; + case 0x10000030: ret = (u16)counters[0].hold; break; + + case 0x10000800: ret = (u16)rcntRcount(1); break; + case 0x10000810: ret = (u16)counters[1].mode; break; + case 0x10000820: ret = (u16)counters[1].target; break; + case 0x10000830: ret = (u16)counters[1].hold; break; + + case 0x10001000: ret = (u16)rcntRcount(2); break; + case 0x10001010: ret = (u16)counters[2].mode; break; + case 0x10001020: ret = (u16)counters[2].target; break; + + case 0x10001800: ret = (u16)rcntRcount(3); break; + case 0x10001810: ret = (u16)counters[3].mode; break; + case 0x10001820: ret = (u16)counters[3].target; break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) ret = 0; + else if(mem == 0x1000F240) { + ret = psHu16(mem) | 0x0102; + psHu32(mem) &= ~0x4000; + } + else ret = psHu32(mem); + return (u16)ret; + } + if (mem < 0x10010000) { + ret = psHu16(mem); + } + else ret = 0; +#ifdef HW_LOG + HW_LOG("Unknown Hardware Read 16 at %x\n",mem); +#endif + break; + } + + return ret; +} + +u32 hwRead32(u32 mem) { + u32 ret; + + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + return ipuRead32(mem); + } + + // gauntlen uses 0x1001xxxx + switch (mem) { + case 0x10000000: return (u16)rcntRcount(0); + case 0x10000010: return (u16)counters[0].mode; + case 0x10000020: return (u16)counters[0].target; + case 0x10000030: return (u16)counters[0].hold; + + case 0x10000800: return (u16)rcntRcount(1); + case 0x10000810: return (u16)counters[1].mode; + case 0x10000820: return (u16)counters[1].target; + case 0x10000830: return (u16)counters[1].hold; + + case 0x10001000: return (u16)rcntRcount(2); + case 0x10001010: return (u16)counters[2].mode; + case 0x10001020: return (u16)counters[2].target; + + case 0x10001800: return (u16)rcntRcount(3); + case 0x10001810: return (u16)counters[3].mode; + case 0x10001820: return (u16)counters[3].target; + +#ifdef PCSX2_DEVBUILD + case 0x1000A000: + ret = psHu32(mem);//dma2 chcr + HW_LOG("Hardware read DMA2_CHCR 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A010: + ret = psHu32(mem);//dma2 madr + HW_LOG("Hardware read DMA2_MADR 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A020: + ret = psHu32(mem);//dma2 qwc + HW_LOG("Hardware readDMA2_QWC 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A030: + ret = psHu32(mem);//dma2 taddr + HW_LOG("Hardware read DMA2_TADDR 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A040: + ret = psHu32(mem);//dma2 asr0 + HW_LOG("Hardware read DMA2_ASR0 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A050: + ret = psHu32(mem);//dma2 asr1 + HW_LOG("Hardware read DMA2_ASR1 32bit at %lx, ret %lx\n", mem, ret); + break; + case 0x1000A080: + ret = psHu32(mem);//dma2 saddr + HW_LOG("Hardware read DMA2_SADDR 32 at %lx, ret %lx\n", mem, ret); + break; + case 0x1000B400: // dma4 chcr + ret = ((DMACh *)&PS2MEM_HW[0xb400])->chcr; + SPR_LOG("Hardware read IPU1_CHCR 32 at %lx, ret %x\n", mem, ret); + break; + + case 0x1000e010: // DMAC_STAT + HW_LOG("DMAC_STAT Read 32bit %x\n", psHu32(0xe010)); + return psHu32(0xe010); + case 0x1000f000: // INTC_STAT +// HW_LOG("INTC_STAT Read 32bit %x\n", psHu32(0xf000)); + return psHu32(0xf000); + case 0x1000f010: // INTC_MASK + HW_LOG("INTC_MASK Read 32bit %x\n", psHu32(0xf010)); + return psHu32(0xf010); +#endif + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430://MCH_RICM + ret = 0; + break; + + case 0x1000f440://MCH_DRD + + if ((psHu32(0xf430) >> 6) & 0xF) + ret = 0; + else + switch ((psHu32(0xf430)>>16) & 0xFFF){//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + case 0x21://INIT + ret = 0x1F * (rdram_sdevid < rdram_devices); + rdram_sdevid += (rdram_sdevid < rdram_devices); + break; + case 0x23://CNFGA + ret = 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 + break; + case 0x24://CNFGB + //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 + ret = 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 + break; + case 0x40://DEVID + ret = psHu32(0xf430) & 0x1F; // =SDEV + break; + default: + ret = 0; + break; + } + break; + + case 0x1000f520: // DMAC_ENABLER +#ifdef HW_LOG + HW_LOG("DMAC_ENABLER Read 32bit %lx\n", psHu32(0xf590)); +#endif + return psHu32(0xf590); + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + // SIF Control Registers + /*1D000020 (word) - EE -> IOP status flag ( set to 0x10000 always ready ) + 1D000030 (word) - IOP -> EE status flag + 1D000040 (word) - See psxMem.c ( Initially set to 0xF00042 and reset to + to this value if 0x20 is written ) + 1D000060 (word) - used to detect whether the SIF interface exists + read must be 0x1D000060, or the top 20 bits must be zero + */ + // note, any changes you make in here, also make on recMemRead32 + if(mem ==0x1000f260) ret = 0; + else if(mem == 0x1000F240) { + ret = psHu32(mem) | 0xF0000102; + //psHu32(mem) &= ~0x4000; + } + else ret = psHu32(mem); +//#ifdef HW_LOG + //__Log("%x: sif %x(%x) Read 32bit %x\n", cpuRegs.pc, mem, 0xbd000000 | (mem & 0xf0),ret); +//#endif } + break; + + } + else if (mem < 0x10010000) { + ret = psHu32(mem); + } + else { + SysPrintf("32bit HW read of address 0x%x\n", mem); + ret = 0; + } +#ifdef HW_LOG + HW_LOG("Unknown Hardware Read 32 at %lx, ret %lx\n", mem, ret); +#endif + break; + } + + return ret; +} + +u64 hwRead64(u32 mem) { + u64 ret; + + if ((mem>=0x10002000) && (mem<0x10003000)) { + return ipuRead64(mem); + } + + switch (mem) { + default: + if (mem < 0x10010000) { + ret = psHu64(mem); + } + else ret = 0; +#ifdef HW_LOG + HW_LOG("Unknown Hardware Read 64 at %x\n",mem); +#endif + break; + } + + return ret; +} + +void hwRead128(u32 mem, u64 *out) { + if (mem >= 0x10004000 && mem < 0x10008000) { + ReadFIFO(mem, out); return; + } + + if (mem < 0x10010000) { + out[0] = psHu64(mem); + out[1] = psHu64(mem+8); + } + +#ifdef HW_LOG + HW_LOG("Unknown Hardware Read 128 at %x\n",mem); +#endif +} + +// dark cloud2 uses it +#define DmaExec8(name, num) { \ + psHu8(mem) = (u8)value; \ + if ((psHu8(mem) & 0x1) && (psHu32(DMAC_CTRL) & 0x1)) { \ + /*SysPrintf("Running DMA 8 %x\n", psHu32(mem & ~0x1));*/ \ + dma##name(); \ + } \ +} + +char sio_buffer[1024]; +int sio_count; + +void hwWrite8(u32 mem, u8 value) { + +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10000000 && mem < 0x10008000 ) + SysPrintf("hwWrite8 to %x\n", mem); +#endif + + switch (mem) { + case 0x10000000: rcntWcount(0, value); break; + case 0x10000010: rcntWmode(0, (counters[0].mode & 0xff00) | value); break; + case 0x10000011: rcntWmode(0, (counters[0].mode & 0xff) | value << 8); break; + case 0x10000020: rcntWtarget(0, value); break; + case 0x10000030: rcntWhold(0, value); break; + + case 0x10000800: rcntWcount(1, value); break; + case 0x10000810: rcntWmode(1, (counters[1].mode & 0xff00) | value); break; + case 0x10000811: rcntWmode(1, (counters[1].mode & 0xff) | value << 8); break; + case 0x10000820: rcntWtarget(1, value); break; + case 0x10000830: rcntWhold(1, value); break; + + case 0x10001000: rcntWcount(2, value); break; + case 0x10001010: rcntWmode(2, (counters[2].mode & 0xff00) | value); break; + case 0x10001011: rcntWmode(2, (counters[2].mode & 0xff) | value << 8); break; + case 0x10001020: rcntWtarget(2, value); break; + + case 0x10001800: rcntWcount(3, value); break; + case 0x10001810: rcntWmode(3, (counters[3].mode & 0xff00) | value); break; + case 0x10001811: rcntWmode(3, (counters[3].mode & 0xff) | value << 8); break; + case 0x10001820: rcntWtarget(3, value); break; + + case 0x1000f180: + if (value == '\n') { + sio_buffer[sio_count] = 0; + SysPrintf(COLOR_GREEN "%s\n" COLOR_RESET, sio_buffer); + sio_count = 0; + } else { + if (sio_count < 1023) { + sio_buffer[sio_count++] = value; + } + } +// SysPrintf("%c", value); + break; + + case 0x10003c02: //Tony Hawks Project 8 uses this + vif1Write32(mem & ~0x2, value << 16); + break; + case 0x10008001: // dma0 - vif0 +#ifdef DMA_LOG + DMA_LOG("VIF0dma %lx\n", value); +#endif + DmaExec8(VIF0, 0); + break; + + case 0x10009001: // dma1 - vif1 +#ifdef DMA_LOG + DMA_LOG("VIF1dma %lx\n", value); +#endif + DmaExec8(VIF1, 1); + break; + + case 0x1000a001: // dma2 - gif +#ifdef DMA_LOG + DMA_LOG("0x%8.8x hwWrite8: GSdma %lx 0x%lx\n", cpuRegs.cycle, value); +#endif + DmaExec8(GIF, 2); + break; + + case 0x1000b001: // dma3 - fromIPU +#ifdef DMA_LOG + DMA_LOG("IPU0dma %lx\n", value); +#endif + DmaExec8(IPU0, 3); + break; + + case 0x1000b401: // dma4 - toIPU +#ifdef DMA_LOG + DMA_LOG("IPU1dma %lx\n", value); +#endif + DmaExec8(IPU1, 4); + break; + + case 0x1000c001: // dma5 - sif0 +#ifdef DMA_LOG + DMA_LOG("SIF0dma %lx\n", value); +#endif +// if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec8(SIF0, 5); + break; + + case 0x1000c401: // dma6 - sif1 +#ifdef DMA_LOG + DMA_LOG("SIF1dma %lx\n", value); +#endif + DmaExec8(SIF1, 6); + break; + + case 0x1000c801: // dma7 - sif2 +#ifdef DMA_LOG + DMA_LOG("SIF2dma %lx\n", value); +#endif + DmaExec8(SIF2, 7); + break; + + case 0x1000d001: // dma8 - fromSPR +#ifdef DMA_LOG + DMA_LOG("fromSPRdma8 %lx\n", value); +#endif + DmaExec8(SPR0, 8); + break; + + case 0x1000d401: // dma9 - toSPR +#ifdef DMA_LOG + DMA_LOG("toSPRdma8 %lx\n", value); +#endif + DmaExec8(SPR1, 9); + break; + + case 0x1000f592: // DMAC_ENABLEW + psHu8(0xf592) = value; + psHu8(0xf522) = value; + break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + psHu8(mem) = value; + break; + case 0x40: + if(!(value & 0x100)) psHu32(mem) &= ~0x100; + break; + } + return; + } + assert( (mem&0xff0f) != 0xf200 ); + + switch(mem&~3) { + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + psHu8(mem) = value; + } +#ifdef HW_LOG + HW_LOG("Unknown Hardware write 8 at %x with value %x\n", mem, value); +#endif + break; + } +} + +#define DmaExec16(name, num) { \ + psHu16(mem) = (u16)value; \ + if ((psHu16(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) { \ + SysPrintf("16bit DMA Start\n"); \ + dma##name(); \ + } \ +} + +void hwWrite16(u32 mem, u16 value) +{ +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10000000 && mem < 0x10008000 ) + SysPrintf("hwWrite16 to %x\n", mem); +#endif + switch(mem) { + case 0x10008000: // dma0 - vif0 +#ifdef DMA_LOG + DMA_LOG("VIF0dma %lx\n", value); +#endif + DmaExec16(VIF0, 0); + break; + +// Latest Fix for Florin by asadr (VIF1) + case 0x10009000: // dma1 - vif1 - chcr +#ifdef DMA_LOG + DMA_LOG("VIF1dma CHCR %lx\n", value); +#endif + DmaExec16(VIF1, 1); + break; + +#ifdef HW_LOG + case 0x10009010: // dma1 - vif1 - madr + HW_LOG("VIF1dma Madr %lx\n", value); + psHu32(mem) = value;//dma1 madr + break; + case 0x10009020: // dma1 - vif1 - qwc + HW_LOG("VIF1dma QWC %lx\n", value); + psHu32(mem) = value;//dma1 qwc + break; + case 0x10009030: // dma1 - vif1 - tadr + HW_LOG("VIF1dma TADR %lx\n", value); + psHu32(mem) = value;//dma1 tadr + break; + case 0x10009040: // dma1 - vif1 - asr0 + HW_LOG("VIF1dma ASR0 %lx\n", value); + psHu32(mem) = value;//dma1 asr0 + break; + case 0x10009050: // dma1 - vif1 - asr1 + HW_LOG("VIF1dma ASR1 %lx\n", value); + psHu32(mem) = value;//dma1 asr1 + break; + case 0x10009080: // dma1 - vif1 - sadr + HW_LOG("VIF1dma SADR %lx\n", value); + psHu32(mem) = value;//dma1 sadr + break; +#endif +// --------------------------------------------------- + + case 0x1000a000: // dma2 - gif +#ifdef DMA_LOG + DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); +#endif + DmaExec16(GIF, 2); + break; +#ifdef HW_LOG + + case 0x1000a010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a020: + psHu32(mem) = value;//dma2 qwc + HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a030: + psHu32(mem) = value;//dma2 taddr + HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a040: + psHu32(mem) = value;//dma2 asr0 + HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a050: + psHu32(mem) = value;//dma2 asr1 + HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + case 0x1000b000: // dma3 - fromIPU +#ifdef DMA_LOG + DMA_LOG("IPU0dma %lx\n", value); +#endif + DmaExec16(IPU0, 3); + break; + +#ifdef HW_LOG + case 0x1000b010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b020: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b030: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + case 0x1000b400: // dma4 - toIPU +#ifdef DMA_LOG + DMA_LOG("IPU1dma %lx\n", value); +#endif + DmaExec16(IPU1, 4); + break; +#ifdef HW_LOG + case 0x1000b410: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b420: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b430: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b480: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + + case 0x1000c000: // dma5 - sif0 +#ifdef DMA_LOG + DMA_LOG("SIF0dma %lx\n", value); +#endif +// if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec16(SIF0, 5); + break; + + case 0x1000c002: + //? + break; + case 0x1000c400: // dma6 - sif1 +#ifdef DMA_LOG + DMA_LOG("SIF1dma %lx\n", value); +#endif + DmaExec16(SIF1, 6); + break; + +#ifdef HW_LOG + case 0x1000c420: // dma6 - sif1 - qwc + HW_LOG("SIF1dma QWC = %lx\n", value); + psHu32(mem) = value; + break; +#endif + +#ifdef HW_LOG + case 0x1000c430: // dma6 - sif1 - tadr + HW_LOG("SIF1dma TADR = %lx\n", value); + psHu32(mem) = value; + break; +#endif + + case 0x1000c800: // dma7 - sif2 +#ifdef DMA_LOG + DMA_LOG("SIF2dma %lx\n", value); +#endif + DmaExec16(SIF2, 7); + break; + case 0x1000c802: + //? + break; + case 0x1000d000: // dma8 - fromSPR +#ifdef DMA_LOG + DMA_LOG("fromSPRdma %lx\n", value); +#endif + DmaExec16(SPR0, 8); + break; + + case 0x1000d400: // dma9 - toSPR +#ifdef DMA_LOG + DMA_LOG("toSPRdma %lx\n", value); +#endif + DmaExec16(SPR1, 9); + break; + case 0x1000f592: // DMAC_ENABLEW + psHu16(0xf592) = value; + psHu16(0xf522) = value; + break; + case 0x1000f130: + case 0x1000f132: + case 0x1000f410: + case 0x1000f412: + case 0x1000f430: + case 0x1000f432: + break; + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + psHu16(mem) = value; + break; + case 0x20: + psHu16(mem) |= value; + break; + case 0x30: + psHu16(mem) &= ~value; + break; + case 0x40: + assert( (mem&2)==0); + if(!(value & 0x100)) psHu16(mem) &= ~0x100; + else psHu16(mem) |= 0x100; + break; + case 0x60: + psHu16(mem) = 0; + break; + } + return; + } + assert( (mem&0xff0f) != 0xf200 ); + +#ifndef PCSX2_VIRTUAL_MEM + if (mem < 0x10010000) +#endif + { + psHu16(mem) = value; + } + } + +#ifdef HW_LOG + HW_LOG("Unknown Hardware write 16 at %x with value %x\n",mem,value); +#endif +} + +#define DmaExec(name, num) { \ + /* Keep the old tag if in chain mode and hw doesnt set it*/ \ + if( (value & 0xc) == 0x4 && (value & 0xffff0000) == 0) \ + psHu32(mem) = (psHu32(mem) & 0xFFFF0000) | (u16)value; \ + else /* Else (including Normal mode etc) write whatever the hardware sends*/ \ + psHu32(mem) = (u32)value; \ + \ + if ((psHu32(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) { \ + dma##name(); \ + } \ +} + +void hwWrite32(u32 mem, u32 value) { + int i; + + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + //psHu32(mem) = value; + ipuWrite32(mem,value); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + vif0Write32(mem, value); return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + vif1Write32(mem, value); return; + } + + switch (mem) { + case 0x10000000: rcntWcount(0, value); break; + case 0x10000010: rcntWmode(0, value); break; + case 0x10000020: rcntWtarget(0, value); break; + case 0x10000030: rcntWhold(0, value); break; + + case 0x10000800: rcntWcount(1, value); break; + case 0x10000810: rcntWmode(1, value); break; + case 0x10000820: rcntWtarget(1, value); break; + case 0x10000830: rcntWhold(1, value); break; + + case 0x10001000: rcntWcount(2, value); break; + case 0x10001010: rcntWmode(2, value); break; + case 0x10001020: rcntWtarget(2, value); break; + + case 0x10001800: rcntWcount(3, value); break; + case 0x10001810: rcntWmode(3, value); break; + case 0x10001820: rcntWtarget(3, value); break; + + case GIF_CTRL: + //SysPrintf("GIF_CTRL write %x\n", value); + psHu32(mem) = value & 0x8; + if(value & 0x1) { + gsGIFReset(); + //gsReset(); + } + else { + if( value & 8 ) psHu32(GIF_STAT) |= 8; + else psHu32(GIF_STAT) &= ~8; + } + return; + + case GIF_MODE: + // need to set GIF_MODE (hamster ball) +#ifdef GSPATH3FIX + //SysPrintf("GIFMODE %x\n", value); +#endif + psHu32(GIF_MODE) = value; + if (value & 0x1) psHu32(GIF_STAT)|= 0x1; + else psHu32(GIF_STAT)&= ~0x1; + if (value & 0x4) psHu32(GIF_STAT)|= 0x4; + else psHu32(GIF_STAT)&= ~0x4; + break; + + case GIF_STAT: // stat is readonly + SysPrintf("Gifstat write value = %x\n", value); + return; + + case 0x10008000: // dma0 - vif0 +#ifdef DMA_LOG + DMA_LOG("VIF0dma %lx\n", value); +#endif + DmaExec(VIF0, 0); + break; + +// Latest Fix for Florin by asadr (VIF1) + case 0x10009000: // dma1 - vif1 - chcr +#ifdef DMA_LOG + DMA_LOG("VIF1dma CHCR %lx\n", value); +#endif + DmaExec(VIF1, 1); + break; +#ifdef HW_LOG + case 0x10009010: // dma1 - vif1 - madr + HW_LOG("VIF1dma Madr %lx\n", value); + psHu32(mem) = value;//dma1 madr + break; + case 0x10009020: // dma1 - vif1 - qwc + HW_LOG("VIF1dma QWC %lx\n", value); + psHu32(mem) = value;//dma1 qwc + break; + case 0x10009030: // dma1 - vif1 - tadr + HW_LOG("VIF1dma TADR %lx\n", value); + psHu32(mem) = value;//dma1 tadr + break; + case 0x10009040: // dma1 - vif1 - asr0 + HW_LOG("VIF1dma ASR0 %lx\n", value); + psHu32(mem) = value;//dma1 asr0 + break; + case 0x10009050: // dma1 - vif1 - asr1 + HW_LOG("VIF1dma ASR1 %lx\n", value); + psHu32(mem) = value;//dma1 asr1 + break; + case 0x10009080: // dma1 - vif1 - sadr + HW_LOG("VIF1dma SADR %lx\n", value); + psHu32(mem) = value;//dma1 sadr + break; +#endif +// --------------------------------------------------- + + case 0x1000a000: // dma2 - gif +#ifdef DMA_LOG + DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); +#endif + DmaExec(GIF, 2); + break; +#ifdef HW_LOG + case 0x1000a010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a020: + psHu32(mem) = value;//dma2 qwc + HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a030: + psHu32(mem) = value;//dma2 taddr + HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a040: + psHu32(mem) = value;//dma2 asr0 + HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a050: + psHu32(mem) = value;//dma2 asr1 + HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + case 0x1000b000: // dma3 - fromIPU +#ifdef DMA_LOG + DMA_LOG("IPU0dma %lx\n", value); +#endif + DmaExec(IPU0, 3); + break; +#ifdef HW_LOG + case 0x1000b010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b020: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b030: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + case 0x1000b400: // dma4 - toIPU +#ifdef DMA_LOG + DMA_LOG("IPU1dma %lx\n", value); +#endif + DmaExec(IPU1, 4); + break; +#ifdef HW_LOG + case 0x1000b410: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b420: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b430: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b480: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + + case 0x1000c000: // dma5 - sif0 +#ifdef DMA_LOG + DMA_LOG("SIF0dma %lx\n", value); +#endif +// if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec(SIF0, 5); + break; + + case 0x1000c400: // dma6 - sif1 +#ifdef DMA_LOG + DMA_LOG("SIF1dma %lx\n", value); +#endif + DmaExec(SIF1, 6); + break; + +#ifdef HW_LOG + case 0x1000c420: // dma6 - sif1 - qwc + HW_LOG("SIF1dma QWC = %lx\n", value); + psHu32(mem) = value; + break; +#endif + +#ifdef HW_LOG + case 0x1000c430: // dma6 - sif1 - tadr + HW_LOG("SIF1dma TADR = %lx\n", value); + psHu32(mem) = value; + break; +#endif + + case 0x1000c800: // dma7 - sif2 +#ifdef DMA_LOG + DMA_LOG("SIF2dma %lx\n", value); +#endif + DmaExec(SIF2, 7); + break; + + case 0x1000d000: // dma8 - fromSPR +#ifdef DMA_LOG + DMA_LOG("fromSPRdma %lx\n", value); +#endif + DmaExec(SPR0, 8); + break; + + case 0x1000d400: // dma9 - toSPR +#ifdef DMA_LOG + DMA_LOG("toSPRdma %lx\n", value); +#endif + DmaExec(SPR1, 9); + break; + +#ifdef HW_LOG + case 0x1000e000: // DMAC_CTRL + HW_LOG("DMAC_CTRL Write 32bit %x\n", value); + psHu32(mem) = value; + break; +#endif + + case 0x1000e010: // DMAC_STAT +#ifdef HW_LOG + HW_LOG("DMAC_STAT Write 32bit %x\n", value); +#endif + psHu16(0xe010)&= ~(value & 0xffff); // clear on 1 + value = value >> 16; + for (i=0; i<16; i++) { // reverse on 1 + if (value & (1<> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 + rdram_sdevid = 0; // if SIO repeater is cleared, reset sdevid + psHu32(mem) = value & ~0x80000000; //kill the busy bit + break; + + case 0x1000f440://MCH_DRD: + psHu32(mem) = value; + break; + + case 0x1000f590: // DMAC_ENABLEW + HW_LOG("DMAC_ENABLEW Write 32bit %lx\n", value); + psHu32(0xf590) = value; + psHu32(0xf520) = value; + return; + + case 0x1000f130: + case 0x1000f410: + +#ifdef PCSX2_DEVBUILD + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status); +#endif + break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + psHu32(mem) = value; + break; + case 0x20: + psHu32(mem) |= value; + break; + case 0x30: + psHu32(mem) &= ~value; + break; + case 0x40: + if(!(value & 0x100)) psHu32(mem) &= ~0x100; + else psHu32(mem) |= 0x100; + break; + case 0x60: + psHu32(mem) = 0; + break; + } +//#ifdef HW_LOG +// SysPrintf("sif %x Write 32bit %x \n", mem, value); +//#endif + // already written in psxMemWrite32 +#ifdef PCSX2_DEVBUILD + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status); +#endif + return; + } + +#ifndef PCSX2_VIRTUAL_MEM + if (mem < 0x10010000) +#endif + { + psHu32(mem) = value; + } +#ifdef PCSX2_DEVBUILD + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status); +#endif + break; + } +} + +void hwWrite64(u32 mem, u64 value) { + u32 val32; + int i; + + if ((mem>=0x10002000) && (mem<=0x10002030)) { + ipuWrite64(mem, value); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + vif0Write32(mem, value); return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + vif1Write32(mem, value); return; + } + + switch (mem) { + case GIF_CTRL: +#ifdef PCSX2_DEVBUILD + SysPrintf("GIF_CTRL write 64\n", value); +#endif + psHu32(mem) = value & 0x8; + if(value & 0x1) { + gsGIFReset(); + //gsReset(); + } + else { + if( value & 8 ) psHu32(GIF_STAT) |= 8; + else psHu32(GIF_STAT) &= ~8; + } + + return; + + case GIF_MODE: +#ifdef GSPATH3FIX + SysPrintf("GIFMODE64 %x\n", value); +#endif + psHu64(GIF_MODE) = value; + if (value & 0x1) psHu32(GIF_STAT)|= 0x1; + else psHu32(GIF_STAT)&= ~0x1; + if (value & 0x4) psHu32(GIF_STAT)|= 0x4; + else psHu32(GIF_STAT)&= ~0x4; + break; + + case GIF_STAT: // stat is readonly + return; + + case 0x1000a000: // dma2 - gif +#ifdef DMA_LOG + DMA_LOG("0x%8.8x hwWrite64: GSdma %lx\n", cpuRegs.cycle, value); +#endif + DmaExec(GIF, 2); + break; + +#ifdef HW_LOG + case 0x1000e000: // DMAC_CTRL + HW_LOG("DMAC_CTRL Write 64bit %x\n", value); + psHu64(mem) = value; + break; +#endif + + case 0x1000e010: // DMAC_STAT +#ifdef HW_LOG + HW_LOG("DMAC_STAT Write 64bit %x\n", value); +#endif + val32 = (u32)value; + psHu16(0xe010)&= ~(val32 & 0xffff); // clear on 1 + val32 = val32 >> 16; + for (i=0; i<16; i++) { // reverse on 1 + if (val32 & (1<= 0x10004000 && mem < 0x10008000) { + WriteFIFO(mem, value); return; + } + + switch (mem) { + case 0x1000f590: // DMAC_ENABLEW + psHu32(0xf590) = *(u32*)value; + psHu32(0xf520) = *(u32*)value; + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + default: + + psHu64(mem ) = value[0]; + psHu64(mem+8) = value[1]; + +#ifdef PCSX2_DEVBUILD + HW_LOG("Unknown Hardware write 128 at %x with value %x_%x (status=%x)\n", mem, value[1], value[0], cpuRegs.CP0.n.Status); +#endif + break; + } +} + +void intcInterrupt() { + cpuRegs.interrupt &= ~(1 << 30); + if ((cpuRegs.CP0.n.Status.val & 0x400) != 0x400) return; + + if ((psHu32(INTC_STAT)) == 0) { + SysPrintf("*PCSX2*: intcInterrupt already cleared\n"); + return; + } + if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0) return; + +#ifdef HW_LOG + HW_LOG("intcInterrupt %x\n", psHu32(INTC_STAT) & psHu32(INTC_MASK)); +#endif + if(psHu32(INTC_STAT) & 0x2){ + counters[0].hold = rcntRcount(0); + counters[1].hold = rcntRcount(1); + } + + cpuException(0x400, cpuRegs.branch); +} + +void dmacTestInterrupt() { + cpuRegs.interrupt &= ~(1 << 31); + if ((cpuRegs.CP0.n.Status.val & 0x800) != 0x800) return; + + if ((psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000) == 0) return; + + if((psHu32(DMAC_CTRL) & 0x1) == 0) return; +} + + + +void dmacInterrupt() +{ + cpuRegs.interrupt &= ~(1 << 31); + if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return; + + if ((psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000) == 0) return; + + if((psHu32(DMAC_CTRL) & 0x1) == 0) return; + +#ifdef HW_LOG + HW_LOG("dmacInterrupt %x\n", (psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000)); +#endif + + cpuException(0x800, cpuRegs.branch); +} + +void hwIntcIrq(int n) { + //if( psHu32(INTC_MASK) & (1<= msize) { + int s1 = msize - addr; + int s2 = size - s1; + + /* it does, so first copy 's1' bytes from 'data' to 'addr' */ + dst = PSM(addr); + if (dst == NULL) return -1; + Cpu->Clear(addr, s1/4); + memcpy_fast(dst, data, s1); + + /* and second copy 's2' bytes from '&data[s1]' to 'maddr' */ + dst = PSM(psHu32(DMAC_RBOR)); + if (dst == NULL) return -1; + Cpu->Clear(psHu32(DMAC_RBOR), s2/4); + memcpy_fast(dst, &data[s1], s2); + } else { + //u32 * tempptr, * tempptr2; + + /* it doesn't, so just copy 'size' bytes from 'data' to 'addr' */ + dst = PSM(addr); + if (dst == NULL) return -1; + Cpu->Clear(addr, size/4); + memcpy_fast(dst, data, size); + } + + + return 0; +} + + +int hwDmacSrcChainWithStack(DMACh *dma, int id) { + u32 temp; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + //dma->tadr += 16; + return 1; //End Transfer + + case 1: // CNT - Transfer QWC following the tag. + dma->madr = dma->tadr + 16; //Set MADR to QW after Tag + dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data + return 0; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = dma->madr; //Temporarily Store ADDR + dma->madr = dma->tadr + 16; //Set MADR to QW following the tag + dma->tadr = temp; //Copy temporarily stored ADDR to Tag + return 0; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + dma->tadr += 16; //Set TADR to next tag + return 0; + + case 5: // Call - Transfer QWC following the tag, save succeeding tag + temp = dma->madr; //Temporarily Store ADDR + + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + + if ((dma->chcr & 0x30) == 0x0) { //Check if ASR0 is empty + dma->asr0 = dma->madr + (dma->qwc << 4); //If yes store Succeeding tag + dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address in call stack + }else if((dma->chcr & 0x30) == 0x10){ + dma->chcr = (dma->chcr & 0xffffffcf) | 0x20; //2 Addresses in call stack + dma->asr1 = dma->madr + (dma->qwc << 4); //If no store Succeeding tag in ASR1 + }else { + SysPrintf("Call Stack Overflow (report if it fixes/breaks anything)\n"); + return 1; //Return done + } + dma->tadr = temp; //Set TADR to temporarily stored ADDR + + return 0; + + case 6: // Ret - Transfer QWC following the tag, load next tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + + if ((dma->chcr & 0x30) == 0x20) { //If ASR1 is NOT equal to 0 (Contains address) + dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address left in call stack + dma->tadr = dma->asr1; //Read ASR1 as next tag + dma->asr1 = 0; //Clear ASR1 + } else { //If ASR1 is empty (No address held) + if((dma->chcr & 0x30) == 0x10) { //Check if ASR0 is NOT equal to 0 (Contains address) + dma->chcr = (dma->chcr & 0xffffffcf); //No addresses left in call stack + dma->tadr = dma->asr0; //Read ASR0 as next tag + dma->asr0 = 0; //Clear ASR0 + } else { //Else if ASR1 and ASR0 are empty + //dma->tadr += 16; //Clear tag address - Kills Klonoa 2 + return 1; //End Transfer + } + } + return 0; + + case 7: // End - Transfer QWC following the tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + //comment out tadr fixes lemans + //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III + return 1; //End Transfer + } + + return -1; +} + +int hwDmacSrcChain(DMACh *dma, int id) { + u32 temp; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + //dma->tadr += 16; + return 1; //End Transfer + + case 1: // CNT - Transfer QWC following the tag. + dma->madr = dma->tadr + 16; //Set MADR to QW after Tag + dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data + return 0; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = dma->madr; //Temporarily Store ADDR + dma->madr = dma->tadr + 16; //Set MADR to QW following the tag + dma->tadr = temp; //Copy temporarily stored ADDR to Tag + return 0; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + dma->tadr += 16; //Set TADR to next tag + return 0; + + case 7: // End - Transfer QWC following the tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III + return 1; //End Transfer + } + + return -1; +} diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h new file mode 100644 index 0000000000..0a83c3d4c2 --- /dev/null +++ b/pcsx2/Hw.h @@ -0,0 +1,419 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __HW_H__ +#define __HW_H__ + +#include "PS2Etypes.h" +#include + +#ifndef PCSX2_VIRTUAL_MEM +extern u8 *psH; // hw mem +extern u16 *psHW; +extern u32 *psHL; +extern u64 *psHD; +#endif + +#define psHs8(mem) (*(s8 *)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs16(mem) (*(s16*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs32(mem) (*(s32*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs64(mem) (*(s64*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu8(mem) (*(u8 *)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu16(mem) (*(u16*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu32(mem) (*(u32*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu64(mem) (*(u64*)&PS2MEM_HW[(mem) & 0xffff]) + +extern u32 g_nextBranchCycle; + +#define INT(n, ecycle) { \ + g_nextBranchCycle = min(g_nextBranchCycle, cpuRegs.cycle+ecycle); \ + cpuRegs.interrupt|= 1 << n; \ + cpuRegs.sCycle[n] = cpuRegs.cycle; \ + cpuRegs.eCycle[n] = ecycle; \ +} + +// VIF0 -- 0x10004000 -- psH[0x4000] +// VIF1 -- 0x10005000 -- psH[0x5000] +// GIF -- 0x10006000 -- psH[0x6000] +// IPUout -- 0x10007000 -- psH[0x7000] +// IPUin -- 0x10007010 -- psH[0x7010] + +void ReadFIFO(u32 mem, u64 *out); +void ConstReadFIFO(u32 mem); + +void WriteFIFO(u32 mem, u64 *value); +void ConstWriteFIFO(u32 mem); + + +// +// --- DMA --- +// + +typedef struct { + u32 chcr; + u32 null0[3]; + u32 madr; + u32 null1[3]; + u16 qwc; u16 pad; + u32 null2[3]; + u32 tadr; + u32 null3[3]; + u32 asr0; + u32 null4[3]; + u32 asr1; + u32 null5[11]; + u32 sadr; +} DMACh; + +// HW defines + +#define RCNT0_COUNT 0x10000000 +#define RCNT0_MODE 0x10000010 +#define RCNT0_TARGET 0x10000020 +#define RCNT0_HOLD 0x10000030 + +#define RCNT1_COUNT 0x10000800 +#define RCNT1_MODE 0x10000810 +#define RCNT1_TARGET 0x10000820 +#define RCNT1_HOLD 0x10000830 + +#define RCNT2_COUNT 0x10001000 +#define RCNT2_MODE 0x10001010 +#define RCNT2_TARGET 0x10001020 + +#define RCNT3_COUNT 0x10001800 +#define RCNT3_MODE 0x10001810 +#define RCNT3_TARGET 0x10001820 + +#define IPU_CMD 0x10002000 +#define IPU_CTRL 0x10002010 +#define IPU_BP 0x10002020 +#define IPU_TOP 0x10002030 + +#define GIF_CTRL 0x10003000 +#define GIF_MODE 0x10003010 +#define GIF_STAT 0x10003020 +#define GIF_TAG0 0x10003040 +#define GIF_TAG1 0x10003050 +#define GIF_TAG2 0x10003060 +#define GIF_TAG3 0x10003070 +#define GIF_CNT 0x10003080 +#define GIF_P3CNT 0x10003090 +#define GIF_P3TAG 0x100030A0 + +#define GIF_FIFO 0x10006000 + +#define IPUout_FIFO 0x10007000 +#define IPUin_FIFO 0x10007010 + +//VIF0 +#define D0_CHCR 0x10008000 +#define D0_MADR 0x10008010 +#define D0_QWC 0x10008020 + +//VIF1 +#define D1_CHCR 0x10009000 +#define D1_MADR 0x10009010 +#define D1_QWC 0x10009020 +#define D1_TADR 0x10009030 + +//GS +#define D2_CHCR 0x1000A000 +#define D2_MADR 0x1000A010 +#define D2_QWC 0x1000A020 +#define D2_TADR 0x1000A030 + +//fromIPU +#define D3_CHCR 0x1000B000 +#define D3_MADR 0x1000B010 +#define D3_QWC 0x1000B020 + +//toIPU +#define D4_CHCR 0x1000B400 +#define D4_MADR 0x1000B410 +#define D4_QWC 0x1000B420 +#define D4_TADR 0x1000B430 + +//SIF0 +#define D5_CHCR 0x1000C000 +#define D5_MADR 0x1000C010 +#define D5_QWC 0x1000C020 + +//SIF1 +#define D6_CHCR 0x1000C400 +#define D6_MADR 0x1000C410 +#define D6_QWC 0x1000C420 + +//SIF2 +#define D7_CHCR 0x1000C800 +#define D7_MADR 0x1000C810 +#define D7_QWC 0x1000C820 + +//fromSPR +#define D8_CHCR 0x1000D000 +#define D8_MADR 0x1000D010 +#define D8_QWC 0x1000D020 +#define D8_SADR 0x1000D080 + + +#define DMAC_CTRL 0x1000E000 +#define DMAC_STAT 0x1000E010 +#define DMAC_PCR 0x1000E020 +#define DMAC_SQWC 0x1000E030 +#define DMAC_RBSR 0x1000E040 +#define DMAC_RBOR 0x1000E050 +#define DMAC_STADR 0x1000E060 + +#define INTC_STAT 0x1000F000 +#define INTC_MASK 0x1000F010 + +#define SBUS_F220 0x1000F220 +#define SBUS_SMFLG 0x1000F230 +#define SBUS_F240 0x1000F240 + +#define DMAC_ENABLER 0x1000F520 +#define DMAC_ENABLEW 0x1000F590 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + +#define GS_PMODE 0x12000000 +#define GS_SMODE1 0x12000010 +#define GS_SMODE2 0x12000020 +#define GS_SRFSH 0x12000030 +#define GS_SYNCH1 0x12000040 +#define GS_SYNCH2 0x12000050 +#define GS_SYNCV 0x12000060 +#define GS_DISPFB1 0x12000070 +#define GS_DISPLAY1 0x12000080 +#define GS_DISPFB2 0x12000090 +#define GS_DISPLAY2 0x120000A0 +#define GS_EXTBUF 0x120000B0 +#define GS_EXTDATA 0x120000C0 +#define GS_EXTWRITE 0x120000D0 +#define GS_BGCOLOR 0x120000E0 +#define GS_CSR 0x12001000 +#define GS_IMR 0x12001010 +#define GS_BUSDIR 0x12001040 +#define GS_SIGLBLID 0x12001080 + +#define INTC_GS 0 +#define INTC_SBUS 1 +#define INTC_VBLANK_S 2 +#define INTC_VBLANK_E 3 +#define INTC_VIF0 4 +#define INTC_VIF1 5 +#define INTC_VU0 6 +#define INTC_VU1 7 +#define INTC_IPU 8 +#define INTC_TIM0 9 +#define INTC_TIM1 10 +#define INTC_TIM2 11 +#define INTC_TIM3 12 + +#define DMAC_STAT_SIS (1<<13) // stall condition +#define DMAC_STAT_MEIS (1<<14) // mfifo empty +#define DMAC_STAT_BEIS (1<<15) // bus error +#define DMAC_STAT_SIM (1<<29) // stall mask +#define DMAC_STAT_MEIM (1<<30) // mfifo mask + +#define DMAC_VIF0 0 +#define DMAC_VIF1 1 +#define DMAC_GIF 2 +#define DMAC_FROM_IPU 3 +#define DMAC_TO_IPU 4 +#define DMAC_SIF0 5 +#define DMAC_SIF1 6 +#define DMAC_SIF2 7 +#define DMAC_FROM_SPR 8 +#define DMAC_TO_SPR 9 +#define DMAC_ERROR 15 + +#define VIF0_STAT_VPS_W (1) +#define VIF0_STAT_VPS_D (2) +#define VIF0_STAT_VPS_T (3) +#define VIF0_STAT_VPS (3) +#define VIF0_STAT_VEW (1<<2) +#define VIF0_STAT_MRK (1<<6) +#define VIF0_STAT_DBF (1<<7) +#define VIF0_STAT_VSS (1<<8) +#define VIF0_STAT_VFS (1<<9) +#define VIF0_STAT_VIS (1<<10) +#define VIF0_STAT_INT (1<<11) +#define VIF0_STAT_ER0 (1<<12) +#define VIF0_STAT_ER1 (1<<13) + +#define VIF1_STAT_VPS_W (1) +#define VIF1_STAT_VPS_D (2) +#define VIF1_STAT_VPS_T (3) +#define VIF1_STAT_VPS (3) +#define VIF1_STAT_VEW (1<<2) +#define VIF1_STAT_VGW (1<<3) +#define VIF1_STAT_MRK (1<<6) +#define VIF1_STAT_DBF (1<<7) +#define VIF1_STAT_VSS (1<<8) +#define VIF1_STAT_VFS (1<<9) +#define VIF1_STAT_VIS (1<<10) +#define VIF1_STAT_INT (1<<11) +#define VIF1_STAT_ER0 (1<<12) +#define VIF1_STAT_ER1 (1<<13) +#define VIF1_STAT_FDR (1<<23) + +//DMA interrupts & masks +#define BEISintr (0x8000) +#define VIF0intr (0x10001) +#define VIF1intr (0x20002) +#define GIFintr (0x40004) +#define IPU0intr (0x80008) +#define IPU1intr (0x100010) +#define SIF0intr (0x200020) +#define SIF1intr (0x400040) +#define SIF2intr (0x800080) +#define SPR0intr (0x1000100) +#define SPR1intr (0x2000200) +#define SISintr (0x20002000) +#define MEISintr (0x40004000) + +#define DMAend(dma, num) { \ + dma->chcr &= ~0x100; \ + psHu32(DMAC_STAT)|= 1<>12 ].aPFNs == NULL ) { + SysPrintf("*PCSX2*: DMA error: %8.8x\n", mem); + return NULL; + } +#endif + pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; + if( pbase != NULL ) + p = pbase + ((u32)p&0xfff); +#endif + + return p; +} + +#else + +extern u8 *psS; //0.015 mb, scratch pad +extern uptr *memLUTR; + +extern __forceinline void *dmaGetAddr(u32 addr) { + u8 *ptr; + +/*#ifdef DMA_LOG + if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x\n", addr); } +#endif*/ + if (addr & 0x80000000) { // teh sux why the f00k 0xE0000000 + return (void*)&psS[addr & 0x3ff0]; + } + + ptr = (u8*)memLUTR[addr >> 12]; + if (ptr == NULL) { + SysPrintf("*PCSX2*: DMA error: %8.8x\n", addr); + return NULL; + } + return (void*)(ptr + (addr & 0xff0)); +} + +#endif + +int hwInit(); +void hwReset(); +void hwShutdown(); + +// hw read functions +u8 hwRead8 (u32 mem); +int hwConstRead8 (u32 x86reg, u32 mem, u32 sign); + +u16 hwRead16(u32 mem); +int hwConstRead16(u32 x86reg, u32 mem, u32 sign); + +u32 hwRead32(u32 mem); +int hwConstRead32(u32 x86reg, u32 mem); + +u64 hwRead64(u32 mem); +void hwConstRead64(u32 mem, int mmreg); + +void hwRead128(u32 mem, u64 *out); +void hwConstRead128(u32 mem, int xmmreg); + +// hw write functions +void hwWrite8 (u32 mem, u8 value); +void hwConstWrite8 (u32 mem, int mmreg); + +void hwWrite16(u32 mem, u16 value); +void hwConstWrite16(u32 mem, int mmreg); + +void hwWrite32(u32 mem, u32 value); +void hwConstWrite32(u32 mem, int mmreg); + +void hwWrite64(u32 mem, u64 value); +void hwConstWrite64(u32 mem, int mmreg); + +void hwWrite128(u32 mem, u64 *value); +void hwConstWrite128(u32 mem, int xmmreg); + +void hwIntcIrq(int n); +void hwDmacIrq(int n); + +int hwMFIFORead(u32 addr, u8 *data, int size); +int hwMFIFOWrite(u32 addr, u8 *data, int size); + +int hwDmacSrcChainWithStack(DMACh *dma, int id); +int hwDmacSrcChain(DMACh *dma, int id); + +void intcInterrupt(); +void dmacInterrupt(); + +#endif /* __HW_H__ */ diff --git a/pcsx2/IPU/IPU.c b/pcsx2/IPU/IPU.c new file mode 100644 index 0000000000..5dc349cb18 --- /dev/null +++ b/pcsx2/IPU/IPU.c @@ -0,0 +1,2040 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "IPU.h" +#include "mpeg2lib/Mpeg.h" +#include "yuv2rgb.h" + +#include +#include + +#include "iR5900.h" +#include "coroutine.h" + +#ifdef _WIN32 +#define FASTCALL __fastcall +#else +#define FASTCALL +#endif + +#ifndef PCSX2_VIRTUAL_MEM +IPUregisters g_ipuRegsReal; +#endif + +#define ipu0dma ((DMACh *)&PS2MEM_HW[0xb000]) +#define ipu1dma ((DMACh *)&PS2MEM_HW[0xb400]) + +#define IPU_DMA_GIFSTALL 1 +#define IPU_DMA_TIE0 2 +#define IPU_DMA_TIE1 4 +#define IPU_DMA_ACTV1 8 +#define IPU_DMA_DOTIE1 16 +#define IPU_DMA_FIREINT0 32 +#define IPU_DMA_FIREINT1 64 +#define IPU_DMA_VIFSTALL 128 + +static int g_nDMATransfer = 0; +int g_nIPU0Data = 0; // data left to transfer +u8* g_pIPU0Pointer = NULL; +int g_nCmdPos[2] = {0}, g_nCmdIndex = 0; +int ipuCurCmd = 0xffffffff; + +// returns number of qw read +int FIFOfrom_write(u32 * value, int size); +void FIFOfrom_read(void *value,int size); +int FIFOto_read(void *value); +int FIFOto_write(u32* pMem, int size); +void FIFOto_clear(); + +int FOreadpos = 0, FOwritepos = 0; +static int FIreadpos = 0, FIwritepos = 0; +PCSX2_ALIGNED16(u32 fifo_input[32]); +PCSX2_ALIGNED16(u32 fifo_output[32]); + +void ReorderBitstream(); +u16 FillInternalBuffer(u32 * pointer, u32 advance, u32 size); + +// the BP doesn't advance and returns -1 if there is no data to be read +tIPU_BP g_BP; +static coroutine_t s_routine; // used for executing BDEC/IDEC +static int s_RoutineDone = 0; +static u32 s_tempstack[0x4000]; // 64k + +void IPUCMD_WRITE(u32 val); +void IPUWorker(); +int IPU0dma(); +int IPU1dma(); + +// Color conversion stuff, the memory layout is a total hack +// convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t) +//char convert_data_buffer[sizeof(convert_rgb_t)]; +#ifdef __x86_64__ +char convert_data_buffer[0x24]; +#else +char convert_data_buffer[0x1C]; +#endif +convert_init_t convert_init={convert_data_buffer, sizeof(convert_data_buffer)}; +convert_t *convert; + +// Quantization matrix +static u8 niq[64], //non-intraquant matrix + iq[64]; //intraquant matrix +u16 vqclut[16]; //clut conversion table +static u8 s_thresh[2]; //thresholds for color conversions +int coded_block_pattern=0; +PCSX2_ALIGNED16(struct macroblock_8 mb8); +PCSX2_ALIGNED16(struct macroblock_16 mb16); +PCSX2_ALIGNED16(struct macroblock_rgb32 rgb32); +PCSX2_ALIGNED16(struct macroblock_rgb16 rgb16); + +u8 indx4[16*16/2]; +u32 mpeg2_inited; //mpeg2_idct_init() must be called only once +u8 PCT[]={'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; +decoder_t g_decoder; //static, only to place it in bss +decoder_t tempdec; + +extern u8 mpeg2_scan_norm[64]; +extern u8 mpeg2_scan_alt[64]; + +PCSX2_ALIGNED16(u8 _readbits[80]); //local buffer (ring buffer) +u8* readbits = _readbits; // always can decrement by one 1qw + +#define SATURATE_4BITS(val) ((val)>15 ? 15 : (val)) + +void IPUProcessInterrupt() +{ + if( ipuRegs->ctrl.BUSY ) { + IPUWorker(); + } +} + +///////////////////////////////////////////////////////// +// Register accesses (run on EE thread) +int ipuInit() +{ + memset(ipuRegs, 0, sizeof(IPUregisters)); + memset(&g_BP, 0, sizeof(g_BP)); + + //other stuff + g_decoder.intra_quantizer_matrix =(u8*)iq; + g_decoder.non_intra_quantizer_matrix =(u8*)niq; + g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P + g_decoder.mb8 =&mb8; + g_decoder.mb16=&mb16; + g_decoder.rgb32=&rgb32; + g_decoder.rgb16=&rgb16; + g_decoder.stride=16; + + return 0; +} + +void ipuReset() +{ + memset(ipuRegs, 0, sizeof(IPUregisters)); + g_nDMATransfer = 0; +} + +void ipuShutdown() +{ +} + +int ipuFreeze(gzFile f, int Mode) { + IPUProcessInterrupt(); + + gzfreeze(ipuRegs, sizeof(IPUregisters)); + gzfreeze(&g_nDMATransfer, sizeof(g_nDMATransfer)); + gzfreeze(&FIreadpos, sizeof(FIreadpos)); + gzfreeze(&FIwritepos, sizeof(FIwritepos)); + gzfreeze(fifo_input, sizeof(fifo_input)); + gzfreeze(&FOreadpos, sizeof(FOreadpos)); + gzfreeze(&FOwritepos, sizeof(FOwritepos)); + gzfreeze(fifo_output, sizeof(fifo_output)); + gzfreeze(&g_BP, sizeof(g_BP)); + gzfreeze(niq, sizeof(niq)); + gzfreeze(iq, sizeof(niq)); + gzfreeze(vqclut, sizeof(vqclut)); + gzfreeze(s_thresh, sizeof(s_thresh)); + gzfreeze(&coded_block_pattern, sizeof(coded_block_pattern)); + gzfreeze(&g_decoder, sizeof(g_decoder)); + gzfreeze(mpeg2_scan_norm, sizeof(mpeg2_scan_norm)); + gzfreeze(mpeg2_scan_alt, sizeof(mpeg2_scan_alt)); + gzfreeze(g_nCmdPos, sizeof(g_nCmdPos)); + gzfreeze(&g_nCmdIndex, sizeof(g_nCmdIndex)); + gzfreeze(&ipuCurCmd, sizeof(ipuCurCmd)); + + gzfreeze(_readbits, sizeof(_readbits)); + + if( Mode == 0 ) { + int temp = readbits-_readbits; + gzfreeze(&temp, sizeof(temp)); + } + else { + int temp; + gzfreeze(&temp, sizeof(temp)); + readbits = _readbits; + } + + //other stuff + g_decoder.intra_quantizer_matrix =(u8*)iq; + g_decoder.non_intra_quantizer_matrix =(u8*)niq; + g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P + g_decoder.mb8 =&mb8; + g_decoder.mb16=&mb16; + g_decoder.rgb32=&rgb32; + g_decoder.rgb16=&rgb16; + g_decoder.stride=16; + + if (!mpeg2_inited){ + mpeg2_idct_init(); + convert=convert_rgb (CONVERT_RGB, 32); + convert(16, 16, 0, NULL, &convert_init); + memset(mb8.Y,0,sizeof(mb8.Y)); + memset(mb8.Cb,0,sizeof(mb8.Cb)); + memset(mb8.Cr,0,sizeof(mb8.Cr)); + memset(mb16.Y,0,sizeof(mb16.Y)); + memset(mb16.Cb,0,sizeof(mb16.Cb)); + memset(mb16.Cr,0,sizeof(mb16.Cr)); + mpeg2_inited=1; + } + + return 0; +} + +BOOL ipuCanFreeze() +{ + return ipuCurCmd == 0xffffffff; +} + +u32 ipuRead32(u32 mem) +{ + IPUProcessInterrupt(); + + switch (mem){ + + case 0x10002010: // IPU_CTRL + ipuRegs->ctrl.IFC = g_BP.IFC; + //ipuRegs->ctrl.OFC = min(g_nIPU0Data, 8); // check if transfering to ipu0 + ipuRegs->ctrl.CBP = coded_block_pattern; + +#ifdef IPU_LOG + if( !ipuRegs->ctrl.BUSY ) { + IPU_LOG("Ipu read32: IPU_CTRL=0x%08X %x\n", ipuRegs->ctrl._u32, cpuRegs.pc); + } +#endif + return ipuRegs->ctrl._u32; + + case 0x10002020: // IPU_BP + + ipuRegs->ipubp = g_BP.BP & 0x7f; + ipuRegs->ipubp |= g_BP.IFC<<8; + ipuRegs->ipubp |= (g_BP.FP+g_BP.bufferhasnew) << 16; + +#ifdef IPU_LOG + IPU_LOG("Ipu read32: IPU_BP=0x%08X\n", *(u32*)&g_BP); +#endif + return ipuRegs->ipubp; + } + + return *(u32*)(((u8*)ipuRegs)+(mem&0xff)); // ipu repeats every 0x100 +} + +u64 ipuRead64(u32 mem) +{ + IPUProcessInterrupt(); + +#ifdef PCSX2_DEVBUILD + if( mem == 0x10002010 ) { + SysPrintf("reading 64bit IPU ctrl\n"); + } + if( mem == 0x10002020 ) { + SysPrintf("reading 64bit IPU top\n"); + } +#endif + + switch (mem){ + case 0x10002000: // IPU_CMD +#ifdef IPU_LOG + //if(!ipuRegs->cmd.BUSY){ + if( ipuRegs->cmd.DATA&0xffffff ) { + IPU_LOG("Ipu read64: IPU_CMD=BUSY=%x, DATA=%08X\n", ipuRegs->cmd.BUSY?1:0,ipuRegs->cmd.DATA); + } +#endif + //return *(u64*)&ipuRegs->cmd; + break; + + case 0x10002030: // IPU_TOP +#ifdef IPU_LOG + IPU_LOG("Ipu read64: IPU_TOP=%x, bp = %d\n",ipuRegs->top,g_BP.BP); +#endif + + //return *(u64*)&ipuRegs->top; + break; + + default: +#ifdef IPU_LOG + IPU_LOG("Ipu read64: Unknown=%x\n", mem); +#endif + break; + + } + return *(u64*)(((u8*)ipuRegs)+(mem&0xff)); +} + +#ifndef PCSX2_NORECBUILD + +#ifndef __x86_64__ + +int ipuConstRead32(u32 x86reg, u32 mem) +{ + int workingreg, tempreg, tempreg2; + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + +// if( !(x86reg&(MEM_XMMTAG|MEM_MMXTAG)) ) { +// if( x86reg == EAX ) { +// tempreg = ECX; +// tempreg2 = EDX; +// } +// else if( x86reg == ECX ) { +// tempreg = EAX; +// tempreg2 = EDX; +// } +// else if( x86reg == EDX ) { +// tempreg = EAX; +// tempreg2 = ECX; +// } +// +// workingreg = x86reg; +// } +// else { + workingreg = EAX; + tempreg = ECX; + tempreg2 = EDX; +// } + + switch (mem){ + + case 0x10002010: // IPU_CTRL + + MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); + AND32ItoR(workingreg, ~0x3f0f); // save OFC + OR8MtoR(workingreg, (u32)&g_BP.IFC); + OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem + +// MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); +// AND32ItoR(workingreg, ~0x3fff); +// MOV32MtoR(tempreg, (u32)&g_nIPU0Data); +// MOV8MtoR(workingreg, (u32)&g_BP.IFC); +// +// CMP32ItoR(tempreg, 8); +// j8Ptr[5] = JLE8(0); +// MOV32ItoR(tempreg, 8); +// x86SetJ8( j8Ptr[5] ); +// SHL32ItoR(tempreg, 4); +// +// OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem +// OR8RtoR(workingreg, tempreg); + +#ifdef _DEBUG + MOV32RtoM((u32)&ipuRegs->ctrl._u32, workingreg); +#endif + // NOTE: not updating ipuRegs->ctrl +// if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); +// else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); + return 1; + + case 0x10002020: // IPU_BP + + assert( (u32)&g_BP.FP + 1 == (u32)&g_BP.bufferhasnew ); + + MOVZX32M8toR(workingreg, (u32)&g_BP.BP); + MOVZX32M8toR(tempreg, (u32)&g_BP.FP); + AND8ItoR(workingreg, 0x7f); + ADD8MtoR(tempreg, (u32)&g_BP.bufferhasnew); + MOV8MtoR(workingreg+4, (u32)&g_BP.IFC); + + SHL32ItoR(tempreg, 16); + OR32RtoR(workingreg, tempreg); + +#ifdef _DEBUG + MOV32RtoM((u32)&ipuRegs->ipubp, workingreg); +#endif + // NOTE: not updating ipuRegs->ipubp +// if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); +// else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); + + return 1; + + default: + // ipu repeats every 0x100 + _eeReadConstMem32(x86reg, (u32)(((u8*)ipuRegs)+(mem&0xff))); + return 0; + } + + return 0; +} + +void ipuConstRead64(u32 mem, int mmreg) +{ + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (u32)(((u8*)ipuRegs)+(mem&0xff))); + else { + MOVQMtoR(mmreg, (u32)(((u8*)ipuRegs)+(mem&0xff))); + SetMMXstate(); + } +} + +#else + +int ipuConstRead32(u32 x86reg, u32 mem) +{ + assert(0); +} + +void ipuConstRead64(u32 mem, int mmreg) +{ + assert(0); +} + +#endif // __x86_64__ + +#endif // !defined(PCSX2_NORECBUILD) + +void ipuSoftReset() +{ + if (!mpeg2_inited){ + mpeg2_idct_init(); + convert=convert_rgb (CONVERT_RGB, 32); + convert(16, 16, 0, NULL, &convert_init); + memset(mb8.Y,0,sizeof(mb8.Y)); + memset(mb8.Cb,0,sizeof(mb8.Cb)); + memset(mb8.Cr,0,sizeof(mb8.Cr)); + memset(mb16.Y,0,sizeof(mb16.Y)); + memset(mb16.Cb,0,sizeof(mb16.Cb)); + memset(mb16.Cr,0,sizeof(mb16.Cr)); + mpeg2_inited=1; + } + + FIFOto_clear(); + memset(fifo_output,0,sizeof(u32)*32); + FOwritepos = 0; + FOreadpos = 0; + coded_block_pattern = 0; + + //g_nDMATransfer = 0; + + ipuRegs->ctrl._u32 = 0; + g_BP.BP = 0; + g_BP.IFC = 0; + g_BP.FP = 0; + g_BP.bufferhasnew = 0; + ipuRegs->top = 0; + g_nCmdIndex = 0; + ipuCurCmd = 0xffffffff; + g_nCmdPos[0] = 0; g_nCmdPos[1] = 0; +} + +void ipuWrite32(u32 mem,u32 value) +{ + IPUProcessInterrupt(); + + switch (mem){ + case 0x10002000: // IPU_CMD +#ifdef IPU_LOG + IPU_LOG("Ipu write32: IPU_CMD=0x%08X\n",value); +#endif + IPUCMD_WRITE(value); + break; + case 0x10002010: // IPU_CTRL + ipuRegs->ctrl._u32 = (value&0x47f30000)|(ipuRegs->ctrl._u32&0x8000ffff); + if( ipuRegs->ctrl.IDP == 3 ) { + SysPrintf("IPU Invaild Intra DC Precision, switching to 9 bits\n"); + ipuRegs->ctrl.IDP = 1; + } + if (ipuRegs->ctrl.RST & 0x1) { // RESET + ipuSoftReset(); + } + +#ifdef IPU_LOG + IPU_LOG("Ipu write32: IPU_CTRL=0x%08X\n",value); +#endif + + break; + default: +#ifdef IPU_LOG + IPU_LOG("Ipu write32: Unknown=%x\n", mem); +#endif + *(u32*)((u8*)ipuRegs + (mem&0xfff)) = value; + break; + } +} + +void ipuWrite64(u32 mem, u64 value) +{ + IPUProcessInterrupt(); + + switch (mem){ + case 0x10002000: +#ifdef IPU_LOG + IPU_LOG("Ipu write64: IPU_CMD=0x%08X\n",value); +#endif + IPUCMD_WRITE((u32)value); + break; + + default: +#ifdef IPU_LOG + IPU_LOG("Ipu write64: Unknown=%x\n", mem); +#endif + *(u64*)((u8*)ipuRegs + (mem&0xfff)) = value; + break; + } +} + +#ifndef PCSX2_NORECBUILD + +#ifndef __x86_64__ + +void ipuConstWrite32(u32 mem, int mmreg) +{ + iFlushCall(0); + if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) PUSH32R(mmreg); + CALLFunc((u32)IPUProcessInterrupt); + + switch (mem){ + case 0x10002000: // IPU_CMD + if( (mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) _recPushReg(mmreg); + CALLFunc((u32)IPUCMD_WRITE); + ADD32ItoR(ESP, 4); + break; + case 0x10002010: // IPU_CTRL + if( mmreg & MEM_EECONSTTAG ) { + u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x47f30000; + + if( c & 0x40000000 ) { + CALLFunc((u32)ipuSoftReset); + } + else { + AND32ItoM((u32)&ipuRegs->ctrl._u32, 0x8000ffff); + OR32ItoM((u32)&ipuRegs->ctrl._u32, c); + } + } + else { + if( mmreg & MEM_XMMTAG ) SSE2_MOVD_XMM_to_R(EAX, mmreg&0xf); + else if( mmreg & MEM_MMXTAG ) MOVD32MMXtoR(EAX, mmreg&0xf); + else POP32R(EAX); + + MOV32MtoR(ECX, (u32)&ipuRegs->ctrl._u32); + AND32ItoR(EAX, 0x47f30000); + AND32ItoR(ECX, 0x8000ffff); + OR32RtoR(EAX, ECX); + MOV32RtoM((u32)&ipuRegs->ctrl._u32, EAX); + + TEST32ItoR(EAX, 0x40000000); + j8Ptr[5] = JZ8(0); + + // reset + CALLFunc((u32)ipuSoftReset); + + x86SetJ8( j8Ptr[5] ); + } + + break; + default: + if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) POP32R(mmreg); + _eeWriteConstMem32((u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); + break; + } +} + +void ipuConstWrite64(u32 mem, int mmreg) +{ + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + + switch (mem){ + case 0x10002000: + _recPushReg(mmreg); + CALLFunc((u32)IPUCMD_WRITE); + ADD32ItoR(ESP, 4); + break; + + default: + _eeWriteConstMem64( (u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); + break; + } +} + +#else + +void ipuConstWrite32(u32 mem, int mmreg) +{ + assert(0); +} + +void ipuConstWrite64(u32 mem, int mmreg) +{ + assert(0); +} + +#endif + +#endif + +/////////////////////////////////////////// +// IPU Commands (exec on worker thread only) + +static void ipuBCLR(u32 val) { + FIFOto_clear(); + g_BP.BP = val & 0x7F; + g_BP.FP = 0; + g_BP.bufferhasnew = 0; + g_BP.IFC = 0; + ipuRegs->ctrl.BUSY = 0; + ipuRegs->cmd.BUSY = 0; + memset(readbits,0,80); +#ifdef IPU_LOG + IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X\n", g_BP.BP); +#endif +} + +static BOOL ipuIDEC(u32 val) +{ + tIPU_CMD_IDEC idec={0, 0, 0, 0, 0, 0, 0, 0, 0}; + + *(u32*)&idec=val; +#ifdef IPU_LOG + IPU_LOG("IPU IDEC command.\n"); + if (idec.FB){ IPU_LOG(" Skip %d bits.",idec.FB);} + IPU_LOG(" Quantizer step code=0x%X.",idec.QSC); + if (idec.DTD==0){ IPU_LOG(" Does not decode DT."); + }else{ IPU_LOG(" Decodes DT.");} + if (idec.SGN==0){ IPU_LOG(" No bias."); + }else{ IPU_LOG(" Bias=128.");} + if (idec.DTE==1){ IPU_LOG(" Dither Enabled.");} + if (idec.OFM==0){ IPU_LOG(" Output format is RGB32."); + }else{ IPU_LOG(" Output format is RGB16.");} + IPU_LOG("\n"); +#endif + g_BP.BP+= idec.FB;//skip FB bits + //from IPU_CTRL + ipuRegs->ctrl.PCT = I_TYPE; //Intra DECoding;) + g_decoder.coding_type =ipuRegs->ctrl.PCT; + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + g_decoder.q_scale_type =ipuRegs->ctrl.QST; + g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; + g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; + g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; + //from IDEC value + g_decoder.quantizer_scale =idec.QSC; + g_decoder.frame_pred_frame_dct=!idec.DTD; + g_decoder.sgn =idec.SGN; + g_decoder.dte =idec.DTE; + g_decoder.ofm =idec.OFM; + //other stuff + g_decoder.dcr =1;//resets DC prediction value + + s_routine = so_create(mpeg2sliceIDEC, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); + assert( s_routine != NULL ); + so_call(s_routine); + if(s_RoutineDone) + s_routine = NULL; + + return s_RoutineDone; +} + +#ifdef _DEBUG +static int s_bdec=0; +#else +#define s_bdec 0 +#endif + +static BOOL ipuBDEC(u32 val) +{ + tIPU_CMD_BDEC bdec={0, 0, 0, 0, 0, 0, 0, 0}; + *(u32*)&bdec=val; + +#ifdef IPU_LOG + IPU_LOG("IPU BDEC(macroblock decode) command %x, num: 0x%x\n",cpuRegs.pc, s_bdec); + if (bdec.FB){ IPU_LOG(" Skip 0x%X bits.", bdec.FB);} + if (bdec.MBI){ IPU_LOG(" Intra MB.");} + else{ IPU_LOG(" Non-intra MB.");} + if (bdec.DCR){ IPU_LOG(" Resets DC prediction value.");} + else{ IPU_LOG(" Doesn't reset DC prediction value.");} + if (bdec.DT){ IPU_LOG(" Use field DCT.");} + else{ IPU_LOG(" Use frame DCT.");} + IPU_LOG(" Quantiser step=0x%X\n",bdec.QSC); +#endif + +#ifdef _DEBUG + s_bdec++; +#endif + + g_BP.BP+= bdec.FB;//skip FB bits + g_decoder.coding_type = I_TYPE; + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + g_decoder.q_scale_type =ipuRegs->ctrl.QST; + g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; + g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; + g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; + //from BDEC value + /* JayteeMaster: the quantizer (linear/non linear) depends on the q_scale_type */ + g_decoder.quantizer_scale =g_decoder.q_scale_type?non_linear_quantizer_scale [bdec.QSC]:bdec.QSC<<1; + g_decoder.macroblock_modes =bdec.DT ? DCT_TYPE_INTERLACED : 0; + g_decoder.dcr =bdec.DCR; + g_decoder.macroblock_modes|=bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN; + + memset(&mb8, 0, sizeof(struct macroblock_8)); + memset(&mb16, 0, sizeof(struct macroblock_16)); + + s_routine = so_create(mpeg2_slice, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); + assert( s_routine != NULL ); + so_call(s_routine); + if(s_RoutineDone) + s_routine = NULL; + return s_RoutineDone; +} + +static BOOL ipuVDEC(u32 val) { + + switch( g_nCmdPos[0] ) { + case 0: + ipuRegs->cmd.DATA = 0; + if( !getBits32((u8*)&g_decoder.bitstream_buf, 0) ) + return FALSE; + + g_decoder.bitstream_bits = -16; + BigEndian(g_decoder.bitstream_buf, g_decoder.bitstream_buf); + + switch((val >> 26) & 3){ + case 0://Macroblock Address Increment + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + ipuRegs->cmd.DATA = get_macroblock_address_increment(&g_decoder); + break; + case 1://Macroblock Type //known issues: no error detected + g_decoder.frame_pred_frame_dct=1;//prevent DCT_TYPE_INTERLACED + g_decoder.coding_type =ipuRegs->ctrl.PCT; + ipuRegs->cmd.DATA=get_macroblock_modes(&g_decoder); + break; + case 2://Motion Code //known issues: no error detected + ipuRegs->cmd.DATA=get_motion_delta(&g_decoder,0); + break; + case 3://DMVector + ipuRegs->cmd.DATA=get_dmv(&g_decoder); + break; + } + + g_BP.BP+=(g_decoder.bitstream_bits+16); + if((int)g_BP.BP < 0) { + g_BP.BP += 128; + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + ipuRegs->cmd.DATA = (ipuRegs->cmd.DATA & 0xFFFF) | ((g_decoder.bitstream_bits+16) << 16); + ipuRegs->ctrl.ECD = (ipuRegs->cmd.DATA==0); + + case 1: + if( !getBits32((u8*)&ipuRegs->top, 0) ) { + g_nCmdPos[0] = 1; + return FALSE; + } + + BigEndian(ipuRegs->top, ipuRegs->top); + +#ifdef IPU_LOG + IPU_LOG("IPU VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d\n", + ipuRegs->cmd.DATA,ipuRegs->cmd.DATA >> 16,val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ? + ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")),ipuRegs->ctrl.PCT); +#endif + + return TRUE; + } + + assert(0); + return FALSE; +} + +static BOOL ipuFDEC(u32 val) +{ + if( !getBits32((u8*)&ipuRegs->cmd.DATA, 0) ) + return FALSE; + + BigEndian(ipuRegs->cmd.DATA, ipuRegs->cmd.DATA); + ipuRegs->top = ipuRegs->cmd.DATA; + +#ifdef IPU_LOG + IPU_LOG("FDEC read: 0x%8.8x\n", ipuRegs->top); +#endif + + return TRUE; +} + +static BOOL ipuSETIQ(u32 val) +{ + int i; + + if ((val >> 27) & 1){ + g_nCmdPos[0] += getBits((u8*)niq + g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); // 8*8*8 + +#ifdef IPU_LOG + IPU_LOG("Read non-intra quantisation matrix from IPU FIFO.\n"); + for (i=0; i<8; i++){ + IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", + niq[i*8+0], niq[i*8+1], niq[i*8+2], niq[i*8+3], + niq[i*8+4], niq[i*8+5], niq[i*8+6], niq[i*8+7]); + } +#endif + }else{ + g_nCmdPos[0] += getBits((u8*)iq+8*g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); +#ifdef IPU_LOG + IPU_LOG("Read intra quantisation matrix from IPU FIFO.\n"); + for (i=0; i<8; i++){ + IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", + iq[i*8+0], iq[i*8+1], iq[i*8+2], iq[i*8+3], + iq[i*8+4], iq[i*8+5], iq[i*8+6], iq[i*8+7]); + } +#endif + } + + return g_nCmdPos[0] == 64; +} + +static BOOL ipuSETVQ(u32 val) +{ + g_nCmdPos[0] += getBits((u8*)vqclut+g_nCmdPos[0], 256-8*g_nCmdPos[0], 1); // 16*2*8 + + if( g_nCmdPos[0] == 32 ) { +#ifdef IPU_LOG + IPU_LOG("IPU SETVQ command.\nRead VQCLUT table from IPU FIFO.\n"); + IPU_LOG( + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n" + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n", + vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F, + vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F, + vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F, + vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F, + vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F, + vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F, + vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F, + vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F, + vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F, + vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F, + vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F, + vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F, + vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F, + vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F, + vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F, + vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F); +#endif + } + + return g_nCmdPos[0] == 32; +} + +// IPU Transfers are split into 8Qwords so we need to send ALL the data +static BOOL ipuCSC(u32 val) +{ + tIPU_CMD_CSC csc ={0, 0, 0, 0, 0}; + *(u32*)&csc=val; + +#ifdef IPU_LOG + IPU_LOG("IPU CSC(Colorspace conversion from YCbCr) command (%d).\n",csc.MBC); + if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} + else{ IPU_LOG("Output format is RGB32. ");} + if (csc.DTE){ IPU_LOG("Dithering enabled."); } +#endif + //SysPrintf("CSC\n"); + for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ + + if( g_nCmdPos[0] < 3072/8 ) { + g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 3072-8*g_nCmdPos[0], 1); + + if( g_nCmdPos[0] < 3072/8 ) + return FALSE; + + ipu_csc(&mb8, &rgb32, 0); + if (csc.OFM){ + ipu_dither2(&rgb32, &rgb16, csc.DTE); + } + } + + if (csc.OFM){ + while(g_nCmdPos[1] < 32) + { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); + + if( g_nCmdPos[1] <= 0 ) + return FALSE; + } + } + else { + while(g_nCmdPos[1] < 64) + { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb32)+4*g_nCmdPos[1], 64-g_nCmdPos[1]); + + if( g_nCmdPos[1] <= 0 ) + return FALSE; + } + } + + g_nCmdPos[0] = 0; + g_nCmdPos[1] = 0; + } + + return TRUE; +} + +// Todo - Need to add the same stop and start code as CSC +static BOOL ipuPACK(u32 val) { + tIPU_CMD_CSC csc ={0, 0, 0, 0, 0}; + + *(u32*)&csc=val; +#ifdef IPU_LOG + IPU_LOG("IPU PACK (Colorspace conversion from RGB32) command.\n"); + if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} + else{ IPU_LOG("Output format is INDX4. ");} + if (csc.DTE){ IPU_LOG("Dithering enabled."); } + IPU_LOG("Number of macroblocks to be converted: %d\n", csc.MBC); +#endif + for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ + + if( g_nCmdPos[0] < 512 ) { + g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); + + if( g_nCmdPos[0] < 64 ) + return FALSE; + + ipu_csc(&mb8, &rgb32, 0); + ipu_dither2(&rgb32, &rgb16, csc.DTE); + if (csc.OFM){ + ipu_vq(&rgb16, indx4); + } + } + + if (csc.OFM) { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); + + if( g_nCmdPos[1] < 32 ) + return FALSE; + } + else { + g_nCmdPos[1] += FIFOfrom_write(((u32*)indx4)+4*g_nCmdPos[1], 8-g_nCmdPos[1]); + + if( g_nCmdPos[1] < 8 ) + return FALSE; + } + + g_nCmdPos[0] = 0; + g_nCmdPos[1] = 0; + } + + return TRUE; +} + +static void ipuSETTH(u32 val) { + s_thresh[0] = (val & 0xff); + s_thresh[1] = ((val>>16) & 0xff); +#ifdef IPU_LOG + IPU_LOG("IPU SETTH (Set threshold value)command %x.\n", val&0xff00ff); +#endif +} + +/////////////////////// +// IPU Worker Thread // +/////////////////////// +#define IPU_INTERRUPT(dma) { \ + hwIntcIrq(INTC_IPU); \ +} + +void IPUCMD_WRITE(u32 val) { + + // don't process anything if currently busy + if( ipuRegs->ctrl.BUSY ) { + // wait for thread + SysPrintf("IPU BUSY!\n"); + } + + ipuRegs->ctrl.ECD = 0; + ipuRegs->ctrl.SCD = 0; //clear ECD/SCD + ipuRegs->cmd.DATA = val; + g_nCmdPos[0] = 0; + + switch (ipuRegs->cmd.CMD) { + case SCE_IPU_BCLR: + ipuBCLR(val); + IPU_INTERRUPT(DMAC_TO_IPU); + return; + + case SCE_IPU_VDEC: + + g_BP.BP+= val & 0x3F; + + // check if enough data in queue + if( ipuVDEC(val) ) { + return; + } + + ipuRegs->cmd.BUSY = 0x80000000; + ipuRegs->topbusy = 0x80000000; + + break; + + case SCE_IPU_FDEC: + +#ifdef IPU_LOG + IPU_LOG("IPU FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, FP %d, CHCR 0x%x, %x\n", + val & 0x3f,g_BP.IFC,(int)g_BP.BP,g_BP.FP,((DMACh*)&PS2MEM_HW[0xb400])->chcr,cpuRegs.pc); +#endif + + g_BP.BP+= val & 0x3F; + + if( ipuFDEC(val) ) { + return; + } + + ipuRegs->cmd.BUSY = 0x80000000; + ipuRegs->topbusy = 0x80000000; + + break; + + case SCE_IPU_SETTH: + ipuSETTH(val); + hwIntcIrq(INTC_IPU); + return; + + case SCE_IPU_SETIQ: +#ifdef IPU_LOG + IPU_LOG("IPU SETIQ command.\n"); +#endif +#ifdef IPU_LOG + if (val & 0x3f){ + IPU_LOG("Skip %d bits.\n", val & 0x3f); + } +#endif + g_BP.BP+= val & 0x3F; + + if( ipuSETIQ(ipuRegs->cmd.DATA) ) { + return; + } + + break; + case SCE_IPU_SETVQ: + if( ipuSETVQ(ipuRegs->cmd.DATA) ) { + return; + } + + break; + case SCE_IPU_CSC: + g_nCmdPos[1] = 0; + g_nCmdIndex = 0; + + if( ipuCSC(ipuRegs->cmd.DATA) ) { + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + return; + } + + break; + case SCE_IPU_PACK: + + g_nCmdPos[1] = 0; + g_nCmdIndex = 0; + + if( ipuPACK(ipuRegs->cmd.DATA) ) { + return; + } + + break; + + case SCE_IPU_IDEC: + if( ipuIDEC(val) ) { + // idec done, ipu0 done too + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + return; + } + + ipuRegs->topbusy = 0x80000000; + // have to resort to the thread + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + + return; + + case SCE_IPU_BDEC: + if( ipuBDEC(val)) { + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) + hwIntcIrq(INTC_IPU); + + return; + } + + ipuRegs->topbusy = 0x80000000; + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + + return; + } + + // have to resort to the thread + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + hwIntcIrq(INTC_IPU); +} + +void IPUWorker() +{ + assert( ipuRegs->ctrl.BUSY ); + + switch (ipuCurCmd) { + case SCE_IPU_VDEC: + if( !ipuVDEC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->cmd.BUSY = 0; + ipuRegs->topbusy = 0; + + break; + + case SCE_IPU_FDEC: + if( !ipuFDEC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->cmd.BUSY = 0; + ipuRegs->topbusy = 0; + + break; + + case SCE_IPU_SETIQ: + if( !ipuSETIQ(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + case SCE_IPU_SETVQ: + if( !ipuSETVQ(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + case SCE_IPU_CSC: + if( !ipuCSC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + break; + case SCE_IPU_PACK: + if( !ipuPACK(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + + case SCE_IPU_IDEC: + so_call(s_routine); + if( !s_RoutineDone ) { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->ctrl.OFC = 0; + ipuRegs->ctrl.BUSY = 0; + ipuRegs->topbusy = 0; + ipuRegs->cmd.BUSY = 0; + ipuCurCmd = 0xffffffff; + // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + INT(DMAC_FROM_IPU,0); + + s_routine = NULL; + break; + case SCE_IPU_BDEC: + so_call(s_routine); + if(!s_RoutineDone) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->ctrl.BUSY = 0; + ipuRegs->topbusy = 0; + ipuRegs->cmd.BUSY = 0; + ipuCurCmd = 0xffffffff; + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + s_routine = NULL; + if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) + hwIntcIrq(INTC_IPU); + return; + + default: + SysPrintf("Unknown IPU command: %x\n", ipuRegs->cmd.CMD); + break; + } + + // success + ipuRegs->ctrl.BUSY = 0; + ipuCurCmd = 0xffffffff; +} + +///////////////// +// Buffer reader + +// move the readbits queue +__forceinline void inc_readbits() +{ + readbits += 16; + if( readbits >= _readbits+64 ) { + + // move back + *(u64*)(_readbits) = *(u64*)(_readbits+64); + *(u64*)(_readbits+8) = *(u64*)(_readbits+72); + readbits = _readbits; + } +} + +// returns the pointer of readbits moved by 1 qword +__forceinline u8* next_readbits() +{ + return readbits + 16; +} + +// returns the pointer of readbits moved by 1 qword +u8* prev_readbits() +{ + if( readbits < _readbits+16 ) { + return _readbits+48-(readbits-_readbits); + } + + return readbits-16; +} + +void ReorderBitstream() +{ + readbits = prev_readbits(); + g_BP.FP = 2; +} + + +// IPU has a 2qword internal buffer whose status is pointed by FP. +// If FP is 1, there's 1 qword in buffer. Second qword is only loaded +// incase there are less than 32bits available in the first qword. +// \return Number of bits available (clamps at 16 bits) +u16 FillInternalBuffer(u32 * pointer, u32 advance, u32 size) +{ + if(g_BP.FP == 0) + { + if( FIFOto_read(next_readbits()) == 0 ) + return 0; + + inc_readbits(); + g_BP.FP = 1; + } + else if(g_BP.FP < 2 && (*(int*)pointer+size) >= 128) + { + if( FIFOto_read(next_readbits()) ) + { + g_BP.FP += 1; + } + } + + if(*(int*)pointer >= 128) + { + assert( g_BP.FP >= 1); + + if(g_BP.FP > 1) + { + inc_readbits(); + } + + if(advance) + { + g_BP.FP--; + *pointer &= 127; + } + } + + return g_BP.FP >= 1 ? g_BP.FP*128-(*(int*)pointer) : 0; +} + +// whenever reading fractions of bytes. The low bits always come from the next byte +// while the high bits come from the current byte +u8 getBits32(u8 *address, u32 advance) +{ + register u32 mask, shift=0; + u8* readpos; + + // Check if the current BP has exceeded or reached the limit of 128 + if( FillInternalBuffer(&g_BP.BP,1,32) < 32 ) + return 0; + + readpos = readbits+(int)g_BP.BP/8; + + if (g_BP.BP & 7) { + + shift = g_BP.BP&7; + mask = (0xff>>shift); + mask = mask|(mask<<8)|(mask<<16)|(mask<<24); + + *(u32*)address = ((~mask&*(u32*)(readpos+1))>>(8-shift)) | (((mask)&*(u32*)readpos)<>shift); + mask = mask|(mask<<8); + + *(u16*)address = ((~mask&*(u16*)(readpos+1))>>(8-shift)) | (((mask)&*(u16*)readpos)<>shift); + + *(u8*)address = (((~mask)&readpos[1])>>(8-shift)) | (((mask)&*readpos)<> (pointer&7)) << + (8-howmuch-(pointer&7))) & 0xFF; + mask &= readbits[((pointer)>>3)]; + mask >>= 8-howmuch-(pointer&7); + pointer += howmuch; + size -= howmuch; + shift -= howmuch; + *address |= mask << shift; + } + + ++address; + } + else + { + u8* readmem; + while (size) + { + if( FillInternalBuffer(&pointer,advance,8) < 8 ) + { + if(advance) + { + g_BP.BP = pointer; + } + return address-oldaddr; + } + + howmuch = min(128-pointer, size); + size -= howmuch; + + readmem = readbits + (pointer>>3); + pointer += howmuch; + howmuch >>= 3; + + while(howmuch >= 4) { + *(u32*)address = *(u32*)readmem; + howmuch -= 4; + address += 4; + readmem += 4; + } + + switch(howmuch) { + case 3: address[2] = readmem[2]; + case 2: address[1] = readmem[1]; + case 1: address[0] = readmem[0]; + case 0: + break; +#ifdef _MSC_VER + default: __assume(0); +#endif + } + + address += howmuch; + } + } + + // If not advance then reset the Reading buffer value + if(advance) + { + g_BP.BP = pointer; + + } + else readbits = oldbits; // restore the last pointer + + return address-oldaddr; +} + +///////////////////// CORE FUNCTIONS ///////////////// +void Skl_YUV_To_RGB32_MMX(u8 *RGB, const int Dst_BpS, const u8 *Y, const u8 *U, const u8 *V, + const int Src_BpS, const int Width, const int Height); + +void ipu_csc(struct macroblock_8 *mb8, struct macroblock_rgb32 *rgb32, int sgn){ + int i; + u8* p = (u8*)rgb32; + + convert_init.start(convert_init.id, (u8*)rgb32, CONVERT_FRAME); + convert_init.copy(convert_init.id, (u8*)mb8->Y, (u8*)mb8->Cr, (u8*)mb8->Cb, 0); + + // do alpha processing +// if( cpucaps.hasStreamingSIMD2Extensions ) { +// int i; +// u8* p = (u8*)rgb32; +// +// __asm { +// movaps xmm6, s_thresh +// pshufd xmm7, xmm6, 0xee +// pshufd xmm6, xmm6, 0x44 +// pxor xmm5, xmm5 +// } +// +// for(i = 0; i < 64; i += 4, p += 64) { +// // process 2 qws at a time +// __asm { +// // extract 8 dwords +// mov edi, p +// movaps xmm0, qword ptr [edi] +// movaps xmm1, qword ptr [edi+16] +// movaps xmm2, qword ptr [edi+32] +// movaps xmm3, qword ptr [edi+48] +// +// +// } + // fixes suikoden5 + if( s_thresh[0] > 0 ) { + for(i = 0; i < 64*4; i++, p += 4) { + if( p[0] < s_thresh[0] && p[1] < s_thresh[0] && p[2] < s_thresh[0] ) + *(u32*)p = 0; + else + p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; + } + } + else if( s_thresh[1] > 0 ) { + for(i = 0; i < 64*4; i++, p += 4) { + p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; + } + } + else { + for(i = 0; i < 64; i++, p += 16) { + p[3] = p[7] = p[11] = p[15] = 0x80; + } + } +} + +void ipu_dither2(struct macroblock_rgb32* rgb32, struct macroblock_rgb16 *rgb16, int dte) +{ + int i, j; + for(i = 0; i < 16; ++i) { + for(j = 0; j < 16; ++j) { + rgb16->c[i][j].r = rgb32->c[i][j].r>>3; + rgb16->c[i][j].g = rgb32->c[i][j].g>>3; + rgb16->c[i][j].b = rgb32->c[i][j].b>>3; + rgb16->c[i][j].a = rgb32->c[i][j].a==0x40; + } + } +} + +void ipu_dither(struct macroblock_8 *mb8, struct macroblock_rgb16 *rgb16, int dte) +{ + //SysPrintf("IPU: Dither not implemented"); +} + +void ipu_vq(struct macroblock_rgb16 *rgb16, u8* indx4){ + SysPrintf("IPU: VQ not implemented"); +} + +void ipu_copy(struct macroblock_8 *mb8, struct macroblock_16 *mb16){ + unsigned char *s=(unsigned char*)mb8; + signed short *d=(signed short*)mb16; + int i; + for (i=0; i< 256; i++) *d++ = *s++; //Y bias - 16 + for (i=0; i< 64; i++) *d++ = *s++; //Cr bias - 128 + for (i=0; i< 64; i++) *d++ = *s++; //Cb bias - 128 + /*for(i = 0; i < 384/(16*6); ++i, s += 16*4, d += 16*4) { + __m128i r0, r1, r2, r3, r4, r5, r6, r7; + + r0 = _mm_load_si128((__m128i*)s); + r2 = _mm_load_si128((__m128i*)s+1); + r4 = _mm_load_si128((__m128i*)s+2); + r6 = _mm_load_si128((__m128i*)s+3); + + // signed shift + r1 = _mm_srai_epi16(_mm_unpackhi_epi8(r0, r0), 8); + r0 = _mm_srai_epi16(_mm_unpacklo_epi8(r0, r0), 8); + r3 = _mm_srai_epi16(_mm_unpackhi_epi8(r2, r2), 8); + r2 = _mm_srai_epi16(_mm_unpacklo_epi8(r2, r2), 8); + r5 = _mm_srai_epi16(_mm_unpackhi_epi8(r4, r4), 8); + r4 = _mm_srai_epi16(_mm_unpacklo_epi8(r4, r4), 8); + r7 = _mm_srai_epi16(_mm_unpackhi_epi8(r6, r6), 8); + r6 = _mm_srai_epi16(_mm_unpacklo_epi8(r6, r6), 8); + + _mm_store_si128((__m128i*)d, r0); + _mm_store_si128((__m128i*)d+1, r1); + _mm_store_si128((__m128i*)d+2, r2); + _mm_store_si128((__m128i*)d+3, r3); + _mm_store_si128((__m128i*)d+4, r4); + _mm_store_si128((__m128i*)d+5, r5); + _mm_store_si128((__m128i*)d+6, r6); + _mm_store_si128((__m128i*)d+7, r7); + }*/ +} + +///////////////////// IPU DMA //////////////////////// +void FIFOto_clear() +{ + //assert( g_BP.IFC == 0 ); + memset(fifo_input,0,sizeof(fifo_input)); + g_BP.IFC = 0; + ipuRegs->ctrl.IFC = 0; + FIreadpos = 0; + FIwritepos = 0; +} + +int FIFOto_read(void *value) +{ + // wait until enough data + if( g_BP.IFC == 0 ) { + if( IPU1dma() == 0 ) + return 0; + + assert( g_BP.IFC > 0 ); + } + + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_input[FIreadpos]; fifo_input[FIreadpos] = 0; + ((u32*)value)[1] = fifo_input[FIreadpos+1]; fifo_input[FIreadpos+1] = 0; + ((u32*)value)[2] = fifo_input[FIreadpos+2]; fifo_input[FIreadpos+2] = 0; + ((u32*)value)[3] = fifo_input[FIreadpos+3]; fifo_input[FIreadpos+3] = 0; + FIreadpos = (FIreadpos + 4) & 31; + g_BP.IFC--; + return 1; +} + +int FIFOto_write(u32* pMem, int size) +{ + int transsize; + int firsttrans = min(size, 8-(int)g_BP.IFC); + + g_BP.IFC+=firsttrans; + transsize = firsttrans; + + while(transsize-- > 0) { + fifo_input[FIwritepos] = pMem[0]; + fifo_input[FIwritepos+1] = pMem[1]; + fifo_input[FIwritepos+2] = pMem[2]; + fifo_input[FIwritepos+3] = pMem[3]; + FIwritepos = (FIwritepos+4)&31; + pMem +=4; + } + + return firsttrans; +} + +#define IPU1chain() { \ + if(ipu1dma->qwc > 0) \ + { \ + int qwc = ipu1dma->qwc; \ + pMem = (u32*)dmaGetAddr(ipu1dma->madr); \ + if (pMem == NULL) { SysPrintf("ipu1dma NULL!\n"); return totalqwc; } \ + qwc = FIFOto_write(pMem, qwc); \ + ipu1dma->madr += qwc<< 4; \ + ipu1dma->qwc -= qwc; \ + totalqwc += qwc; \ + if( ipu1dma->qwc > 0 ) { \ + g_nDMATransfer |= IPU_DMA_ACTV1; \ + return totalqwc; \ + } \ + } \ +} + +int IPU1dma() +{ + u32 *ptag, *pMem; + int done=0; + int ipu1cycles = 0; + int totalqwc = 0; + + assert( !(ipu1dma->chcr&0x40) ); + + if( !(ipu1dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc > 0 ) { + IPU1chain(); + + if ((ipu1dma->chcr & 0x80) && (g_nDMATransfer&IPU_DMA_DOTIE1)) { //Check TIE bit of CHCR and IRQ bit of tag + SysPrintf("IPU1 TIE\n"); + + INT(DMAC_TO_IPU, totalqwc*BIAS); + g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + + g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + + if( (ipu1dma->chcr&0xc) == 0 ) { + INT(DMAC_TO_IPU, totalqwc*BIAS); + return totalqwc; + } + else { + u32 tag = ipu1dma->chcr; // upper bits describe current tag + + if ((ipu1dma->chcr & 0x80) && (tag&0x80000000)) { + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); + + switch(tag&0x70000000) { + case 0x00000000: ipu1dma->tadr += 16; break; + case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; + } + + ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); +#ifdef IPU_LOG + IPU_LOG("dmaIrq Set\n"); +#endif + INT(DMAC_TO_IPU, totalqwc*BIAS); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + + switch( tag&0x70000000 ) + { + case 0x00000000: + ipu1dma->tadr += 16; + INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); + return totalqwc; + + case 0x70000000: + ipu1dma->tadr = ipu1dma->madr; + INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); + return totalqwc; + } + } + } + + if ((ipu1dma->chcr & 0xc) == 0 && ipu1dma->qwc == 0) { // Normal Mode + //SysPrintf("ipu1 normal empty qwc?\n"); + return totalqwc; + } + + // Transfer Dn_QWC from Dn_MADR to GIF + + if ((ipu1dma->chcr & 0xc) == 0 || ipu1dma->qwc > 0) { // Normal Mode +#ifdef IPU_LOG + IPU_LOG("dmaIPU1 Normal size=%d, addr=%lx, fifosize=%x\n", + ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); +#endif + IPU1chain(); + INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + return totalqwc; + } + else + { + // Chain Mode + //while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + SysPrintf("IPU1 BUSERR\n"); + ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return totalqwc; + } + ipu1cycles+=1; // Add 1 cycles from the QW read for the tag + + ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + ipu1dma->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + //ipu1dma->madr = ptag[1]; //MADR = ADDR field + + //done = hwDmacSrcChainWithStack(ipu1dma, id); + switch(ptag[0] & 0x70000000) { + case 0x00000000: // refe + // do not change tadr + ipu1dma->madr = ptag[1]; + done = 1; + break; + + case 0x10000000: // cnt + ipu1dma->madr = ipu1dma->tadr + 16; + // Set the taddr to the next tag + ipu1dma->tadr += 16 + (ipu1dma->qwc << 4); + break; + + case 0x20000000: // next + ipu1dma->madr = ipu1dma->tadr + 16; + ipu1dma->tadr = ptag[1]; + break; + + case 0x30000000: // ref + ipu1dma->madr = ptag[1]; + ipu1dma->tadr += 16; + break; + + case 0x70000000: // end + // do not change tadr + ipu1dma->madr = ipu1dma->tadr + 16; + done = 1; + break; + + default: + #ifdef IPU_LOG + IPU_LOG("ERROR: different transfer mode!, Please report to PCSX2 Team\n"); + #endif + break; + } + +#ifdef IPU_LOG + IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x\n", + ptag[1], ptag[0], ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); +#endif + + if( (ipu1dma->chcr & 0x80) && ptag[0] & 0x80000000 ) + g_nDMATransfer |= IPU_DMA_DOTIE1; + else + g_nDMATransfer &= ~IPU_DMA_DOTIE1; + + //Britney Dance beat does a blank NEXT tag, for some odd reason the fix doesnt work if after IPU1Chain O_o + if(ipu1dma->qwc == 0 && done == 0 && !(g_nDMATransfer & IPU_DMA_DOTIE1)) IPU1dma(); + + IPU1chain(); + + if ((ipu1dma->chcr & 0x80) && (ptag[0]&0x80000000) && ipu1dma->qwc == 0) { //Check TIE bit of CHCR and IRQ bit of tag + SysPrintf("IPU1 TIE\n"); + + if( done ) { + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); + + switch(ptag[0]&0x70000000) { + case 0x00000000: ipu1dma->tadr += 16; break; + case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; + } + + ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); + } + + INT(DMAC_TO_IPU, ipu1cycles+totalqwc*BIAS); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + //} + + if(ipu1dma->qwc == 0){ + switch( ptag[0]&0x70000000 ) + { + case 0x00000000: + ipu1dma->tadr += 16; + INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + return totalqwc; + + case 0x70000000: + ipu1dma->tadr = ipu1dma->madr; + INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + return totalqwc; + } + } + } + + INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + return totalqwc; +} + + + + +int FIFOfrom_write(u32 *value,int size) +{ + int transsize; + int firsttrans; + + if((int)ipuRegs->ctrl.OFC >= 8) + { + if(IPU0dma() == 0) + { +// ipuRegs->ctrl.OFC = 0; + } + } + + transsize = min(size,8-(int)ipuRegs->ctrl.OFC); + firsttrans = transsize; + + while(transsize-- > 0) { + fifo_output[FOwritepos] = ((u32*)value)[0]; + fifo_output[FOwritepos+1] = ((u32*)value)[1]; + fifo_output[FOwritepos+2] = ((u32*)value)[2]; + fifo_output[FOwritepos+3] = ((u32*)value)[3]; + FOwritepos = (FOwritepos+4)&31; + value += 4; + } + + ipuRegs->ctrl.OFC+=firsttrans; + IPU0dma(); + //SysPrintf("Written %d qwords, %d\n",firsttrans,ipuRegs->ctrl.OFC); + + return firsttrans; +} + +void FIFOfrom_read(void *value,int size) +{ + ipuRegs->ctrl.OFC -= size; + while(size > 0) + { + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; + ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; + ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; + ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; + value = (u32*)value + 4; + FOreadpos = (FOreadpos + 4) & 31; + size--; + } +} + + +void FIFOfrom_readsingle(void *value) +{ + if(ipuRegs->ctrl.OFC > 0) + { + ipuRegs->ctrl.OFC --; + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; + ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; + ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; + ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; + FOreadpos = (FOreadpos + 4) & 31; + } +} + +int IPU0dma() +{ + int readsize; + void* pMem; + + int qwc = ipu0dma->qwc; + u32 chcr = ipu0dma->chcr; + + if( !(ipu0dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc == 0) + return 0; + + assert( !(ipu0dma->chcr&0x40) ); + +#ifdef IPU_LOG + IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc = %lx\n", + ipu0dma->chcr, ipu0dma->madr, ipu0dma->qwc); +#endif + + assert((ipu0dma->chcr & 0xC) == 0 ); + pMem = (u32*)dmaGetAddr(ipu0dma->madr); + readsize = min(ipu0dma->qwc, (int)ipuRegs->ctrl.OFC); + FIFOfrom_read(pMem,readsize); + ipu0dma->madr += readsize<< 4; + ipu0dma->qwc -= readsize; // note: qwc is u16 + if(ipu0dma->qwc == 0) { + if ((psHu32(DMAC_CTRL) & 0x30) == 0x30) { // STS == fromIPU + psHu32(DMAC_STADR) = ipu0dma->madr; + switch (psHu32(DMAC_CTRL) & 0xC0) { + case 0x80: // GIF + g_nDMATransfer |= IPU_DMA_GIFSTALL; + break; + case 0x40: // VIF + g_nDMATransfer |= IPU_DMA_VIFSTALL; + break; + } + } + INT(DMAC_FROM_IPU,readsize*BIAS); + + } + + return readsize; +} + +void dmaIPU0() // fromIPU +{ + if( ipuRegs->ctrl.BUSY ) + IPUWorker(); +} + +void dmaIPU1() // toIPU +{ + //g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + IPU1dma(); + if( ipuRegs->ctrl.BUSY ) + IPUWorker(); +} + +extern void GIFdma(); + +void ipu0Interrupt() { +#ifdef IPU_LOG + IPU_LOG("ipu0Interrupt: %x\n", cpuRegs.cycle); +#endif + + if( g_nDMATransfer & IPU_DMA_FIREINT0 ) { + hwIntcIrq(INTC_IPU); + g_nDMATransfer &= ~IPU_DMA_FIREINT0; + } + + if( g_nDMATransfer & IPU_DMA_GIFSTALL ) { + // gif + g_nDMATransfer &= ~IPU_DMA_GIFSTALL; + if(((DMACh*)&PS2MEM_HW[0xA000])->chcr & 0x100) GIFdma(); + } + + if( g_nDMATransfer & IPU_DMA_VIFSTALL ) { + // vif + g_nDMATransfer &= ~IPU_DMA_VIFSTALL; + if(((DMACh*)&PS2MEM_HW[0x9000])->chcr & 0x100)dmaVIF1(); + } + + if( g_nDMATransfer & IPU_DMA_TIE0 ) { + g_nDMATransfer &= ~IPU_DMA_TIE0; + } + + ipu0dma->chcr &= ~0x100; + + hwDmacIrq(DMAC_FROM_IPU); + + cpuRegs.interrupt &= ~(1 << 3); +} + +void ipu1Interrupt() { +#ifdef IPU_LOG + IPU_LOG("ipu1Interrupt %x:\n", cpuRegs.cycle); +#endif + + if( g_nDMATransfer & IPU_DMA_FIREINT1 ) { + hwIntcIrq(INTC_IPU); + g_nDMATransfer &= ~IPU_DMA_FIREINT1; + } + + if( g_nDMATransfer & IPU_DMA_TIE1 ) { + g_nDMATransfer &= ~IPU_DMA_TIE1; + }else + ipu1dma->chcr &= ~0x100; + + hwDmacIrq(DMAC_TO_IPU); + + cpuRegs.interrupt &= ~(1 << 4); +} diff --git a/pcsx2/IPU/IPU.h b/pcsx2/IPU/IPU.h new file mode 100644 index 0000000000..aff55a5e8f --- /dev/null +++ b/pcsx2/IPU/IPU.h @@ -0,0 +1,203 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IPU_H__ +#define __IPU_H__ + +#include "Common.h" +#ifdef _MSC_VER +#pragma pack(1) +#endif + +// +// Bitfield Structure +// +typedef union { + struct { + u32 OPTION : 28; // VDEC decoded value + u32 CMD : 4; // last command + u32 _BUSY; + }; + struct { + u32 DATA; + u32 BUSY; + }; +} tIPU_CMD; + +#define IPU_CTRL_IFC_M (0x0f<< 0) +#define IPU_CTRL_OFC_M (0x0f<< 4) +#define IPU_CTRL_CBP_M (0x3f<< 8) +#define IPU_CTRL_ECD_M (0x01<<14) +#define IPU_CTRL_SCD_M (0x01<<15) +#define IPU_CTRL_IDP_M (0x03<<16) +#define IPU_CTRL_AS_M (0x01<<20) +#define IPU_CTRL_IVF_M (0x01<<21) +#define IPU_CTRL_QST_M (0x01<<22) +#define IPU_CTRL_MP1_M (0x01<<23) +#define IPU_CTRL_PCT_M (0x07<<24) +#define IPU_CTRL_RST_M (0x01<<30) +#define IPU_CTRL_BUSY_M (0x01<<31) + +#define IPU_CTRL_IFC_O ( 0) +#define IPU_CTRL_OFC_O ( 4) +#define IPU_CTRL_CBP_O ( 8) +#define IPU_CTRL_ECD_O (14) +#define IPU_CTRL_SCD_O (15) +#define IPU_CTRL_IDP_O (16) +#define IPU_CTRL_AS_O (20) +#define IPU_CTRL_IVF_O (21) +#define IPU_CTRL_QST_O (22) +#define IPU_CTRL_MP1_O (23) +#define IPU_CTRL_PCT_O (24) +#define IPU_CTRL_RST_O (30) +#define IPU_CTRL_BUSY_O (31) + + +// +// Bitfield Structure +// +typedef union { + struct { + u32 IFC : 4; // Input FIFO counter + u32 OFC : 4; // Output FIFO counter + u32 CBP : 6; // Coded block pattern + u32 ECD : 1; // Error code pattern + u32 SCD : 1; // Start code detected + u32 IDP : 2; // Intra DC precision + u32 resv0 : 2; + u32 AS : 1; // Alternate scan + u32 IVF : 1; // Intra VLC format + u32 QST : 1; // Q scale step + u32 MP1 : 1; // MPEG1 bit strea + u32 PCT : 3; // Picture Type + u32 resv1 : 3; + u32 RST : 1; // Reset + u32 BUSY : 1; // Busy + }; + u32 _u32; +} tIPU_CTRL; + +#define IPU_BP_BP_M (0x7f<< 0) +#define IPU_BP_IFC_M (0x0f<< 8) +#define IPU_BP_FP_M (0x03<<16) + +#define IPU_BP_BP_O ( 0) +#define IPU_BP_IFC_O ( 8) +#define IPU_BP_FP_O (16) + + +// +// Bitfield Structure +// +typedef struct { + u32 BP; // Bit stream point + u16 IFC; // Input FIFO counter + u8 FP; // FIFO point + u8 bufferhasnew; +} tIPU_BP; + +#ifdef _WIN32 +#pragma pack() +#endif + +typedef struct { + u32 FB : 6; + u32 UN2 :10; + u32 QSC : 5; + u32 UN1 : 3; + u32 DTD : 1; + u32 SGN : 1; + u32 DTE : 1; + u32 OFM : 1; + u32 cmd : 4; +} tIPU_CMD_IDEC; + +typedef struct { + u32 FB : 6; + u32 UN2 :10; + u32 QSC : 5; + u32 UN1 : 4; + u32 DT : 1; + u32 DCR : 1; + u32 MBI : 1; + u32 cmd : 4; +} tIPU_CMD_BDEC; + +typedef struct { + u32 MBC :11; + u32 UN2 :15; + u32 DTE : 1; + u32 OFM : 1; + u32 cmd : 4; +} tIPU_CMD_CSC; + +#define SCE_IPU_BCLR 0x0 +#define SCE_IPU_IDEC 0x1 +#define SCE_IPU_BDEC 0x2 +#define SCE_IPU_VDEC 0x3 +#define SCE_IPU_FDEC 0x4 +#define SCE_IPU_SETIQ 0x5 +#define SCE_IPU_SETVQ 0x6 +#define SCE_IPU_CSC 0x7 +#define SCE_IPU_PACK 0x8 +#define SCE_IPU_SETTH 0x9 + +typedef struct { + tIPU_CMD cmd; + u32 dummy0[2]; + tIPU_CTRL ctrl; + u32 dummy1[3]; + u32 ipubp; + u32 dummy2[3]; + u32 top; + u32 topbusy; + u32 dummy3[2]; +} IPUregisters, *PIPUregisters; + +#define ipuRegs ((IPUregisters*)(PS2MEM_HW+0x2000)) + +void dmaIPU0(); +void dmaIPU1(); + +int ipuInit(); +void ipuReset(); +void ipuShutdown(); +int ipuFreeze(gzFile f, int Mode); +BOOL ipuCanFreeze(); + +u32 ipuRead32(u32 mem); +int ipuConstRead32(u32 x86reg, u32 mem); + +u64 ipuRead64(u32 mem); +void ipuConstRead64(u32 mem, int mmreg); + +void ipuWrite32(u32 mem,u32 value); +void ipuConstWrite32(u32 mem, int mmreg); + +void ipuWrite64(u32 mem,u64 value); +void ipuConstWrite64(u32 mem, int mmreg); + +void ipu0Interrupt(); +void ipu1Interrupt(); + +u8 getBits32(u8 *address, u32 advance); +u8 getBits16(u8 *address, u32 advance); +u8 getBits8(u8 *address, u32 advance); +int getBits(u8 *address, u32 size, u32 advance); + +#endif diff --git a/pcsx2/IPU/Makefile.am b/pcsx2/IPU/Makefile.am new file mode 100644 index 0000000000..e76e41620e --- /dev/null +++ b/pcsx2/IPU/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I@srcdir@/../ -I@srcdir@/../x86 +noinst_LIBRARIES = libIPU.a + +libIPU_a_SOURCES = IPU.c yuv2rgb.c coroutine.c acoroutine.S + +SUBDIRS = mpeg2lib + +#libIPU_a_LIBADD = mpeg2lib/libmpeg2IPU.a \ No newline at end of file diff --git a/pcsx2/IPU/acoroutine.S b/pcsx2/IPU/acoroutine.S new file mode 100644 index 0000000000..d81b0e02dc --- /dev/null +++ b/pcsx2/IPU/acoroutine.S @@ -0,0 +1,181 @@ +.intel_syntax + +.extern g_pCurrentRoutine + +#ifdef __x86_64__ + +#define FUNC_OFFSET 0 +#define STACK_OFFSET 8 +#define RBX_OFFSET 16 +#define RBP_OFFSET 24 +#define R12_OFFSET 32 +#define R13_OFFSET 40 +#define R14_OFFSET 48 +#define R15_OFFSET 56 +#define DATA_OFFSET 64 +#define RESTORE_OFFSET 72 + +.globl so_call +so_call: + test dword ptr [%rdi+RESTORE_OFFSET], 1 + jnz so_call_RestoreRegs + mov [%rdi+RBP_OFFSET], %rbp + mov [%rdi+RBX_OFFSET], %rbx + mov [%rdi+R12_OFFSET], %r12 + mov [%rdi+R13_OFFSET], %r13 + mov [%rdi+R14_OFFSET], %r14 + mov [%rdi+R15_OFFSET], %r15 + mov dword ptr [%rdi+RESTORE_OFFSET], 1 + jmp so_call_CallFn +so_call_RestoreRegs: + // have to load and save at the same time + mov %rax, [%rdi+RBP_OFFSET] + mov %rcx, [%rdi+RBX_OFFSET] + mov %rdx, [%rdi+R12_OFFSET] + mov [%rdi+RBP_OFFSET], %rbp + mov [%rdi+RBX_OFFSET], %rbx + mov [%rdi+R12_OFFSET], %r12 + mov %rbp, %rax + mov %rbx, %rcx + mov %r12, %rdx + mov %rax, [%rdi+R13_OFFSET] + mov %rcx, [%rdi+R14_OFFSET] + mov %rdx, [%rdi+R15_OFFSET] + mov [%rdi+R13_OFFSET], %r13 + mov [%rdi+R14_OFFSET], %r14 + mov [%rdi+R15_OFFSET], %r15 + mov %r13, %rax + mov %r14, %rcx + mov %r15, %rdx + +so_call_CallFn: + mov [g_pCurrentRoutine], %rdi + + // swap the stack + mov %rax, [%rdi+STACK_OFFSET] + mov [%rdi+STACK_OFFSET], %rsp + mov %rsp, %rax + mov %rax, [%rdi+FUNC_OFFSET] + mov %rdi, [%rdi+DATA_OFFSET] + + jmp %rax + +.globl so_resume +so_resume: + mov %rdi, [g_pCurrentRoutine] + mov %rax, [%rdi+RBP_OFFSET] + mov %rcx, [%rdi+RBX_OFFSET] + mov %rdx, [%rdi+R12_OFFSET] + mov [%rdi+RBP_OFFSET], %rbp + mov [%rdi+RBX_OFFSET], %rbx + mov [%rdi+R12_OFFSET], %r12 + mov %rbp, %rax + mov %rbx, %rcx + mov %r12, %rdx + mov %rax, [%rdi+R13_OFFSET] + mov %rcx, [%rdi+R14_OFFSET] + mov %rdx, [%rdi+R15_OFFSET] + mov [%rdi+R13_OFFSET], %r13 + mov [%rdi+R14_OFFSET], %r14 + mov [%rdi+R15_OFFSET], %r15 + mov %r13, %rax + mov %r14, %rcx + mov %r15, %rdx + + // put the return address in pcalladdr + mov %rsi, [%rsp] + mov [%rdi], %rsi + add %rsp, 8 // remove the return address + + // swap stack pointers + mov %rax, [%rdi+STACK_OFFSET] + mov [%rdi+STACK_OFFSET], %rsp + mov %rsp, %rax + + ret + +.globl so_exit +so_exit: + mov %rdi, [g_pCurrentRoutine] + mov %rsp, [%rdi+STACK_OFFSET] + mov %rbp, [%rdi+RBP_OFFSET] + mov %rbx, [%rdi+RBX_OFFSET] + mov %r12, [%rdi+R12_OFFSET] + mov %r13, [%rdi+R13_OFFSET] + mov %r14, [%rdi+R14_OFFSET] + mov %r15, [%rdi+R15_OFFSET] + ret +#else + +.globl so_call +so_call: + mov %eax, dword ptr [%esp+4] + test dword ptr [%eax+24], 1 + jnz RestoreRegs + mov [%eax+8], %ebx + mov [%eax+12], %esi + mov [%eax+16], %edi + mov [%eax+20], %ebp + mov dword ptr [%eax+24], 1 + jmp CallFn +RestoreRegs: + // have to load and save at the same time + mov %ecx, [%eax+8] + mov %edx, [%eax+12] + mov [%eax+8], %ebx + mov [%eax+12], %esi + mov %ebx, %ecx + mov %esi, %edx + mov %ecx, [%eax+16] + mov %edx, [%eax+20] + mov [%eax+16], %edi + mov [%eax+20], %ebp + mov %edi, %ecx + mov %ebp, %edx + +CallFn: + mov [g_pCurrentRoutine], %eax + mov %ecx, %esp + mov %esp, [%eax+4] + mov [%eax+4], %ecx + + jmp dword ptr [%eax] + +.globl so_resume +so_resume: + mov %eax, [g_pCurrentRoutine] + mov %ecx, [%eax+8] + mov %edx, [%eax+12] + mov [%eax+8], %ebx + mov [%eax+12], %esi + mov %ebx, %ecx + mov %esi, %edx + mov %ecx, [%eax+16] + mov %edx, [%eax+20] + mov [%eax+16], %edi + mov [%eax+20], %ebp + mov %edi, %ecx + mov %ebp, %edx + + // put the return address in pcalladdr + mov %ecx, [%esp] + mov [%eax], %ecx + add %esp, 4 // remove the return address + + // swap stack pointers + mov %ecx, [%eax+4] + mov [%eax+4], %esp + mov %esp, %ecx + ret + +.globl so_exit +so_exit: + mov %eax, [g_pCurrentRoutine] + mov %esp, [%eax+4] + mov %ebx, [%eax+8] + mov %esi, [%eax+12] + mov %edi, [%eax+16] + mov %ebp, [%eax+20] + ret + +#endif diff --git a/pcsx2/IPU/acoroutine.asm b/pcsx2/IPU/acoroutine.asm new file mode 100644 index 0000000000..d81a5f12d2 --- /dev/null +++ b/pcsx2/IPU/acoroutine.asm @@ -0,0 +1,140 @@ +; Pcsx2 - Pc Ps2 Emulator +; Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +;; x86-64 coroutine fucntions +extern g_pCurrentRoutine:ptr + +.code + +so_call proc public + test dword ptr [rcx+88], 1 + jnz so_call_RestoreRegs + mov [rcx+24], rbp + mov [rcx+16], rbx + mov [rcx+32], r12 + mov [rcx+40], r13 + mov [rcx+48], r14 + mov [rcx+56], r15 + mov [rcx+64], rsi + mov [rcx+72], rdi + mov dword ptr [rcx+88], 1 + jmp so_call_CallFn +so_call_RestoreRegs: + ;; have to load and save at the same time + ;; rbp, rbx, r12 + mov rax, [rcx+24] + mov r8, [rcx+16] + mov rdx, [rcx+32] + mov [rcx+24], rbp + mov [rcx+16], rbx + mov [rcx+32], r12 + mov rbp, rax + mov rbx, r8 + mov r12, rdx + ;; r13, r14, r15 + mov rax, [rcx+40] + mov r8, [rcx+48] + mov rdx, [rcx+56] + mov [rcx+40], r13 + mov [rcx+48], r14 + mov [rcx+56], r15 + mov r13, rax + mov r14, r8 + mov r15, rdx + + ;; rsi, rdi + mov rax, [rcx+64] + mov rdx, [rcx+72] + mov [rcx+64], rsi + mov [rcx+72], rdi + mov rsi, rax + mov rdi, rdx + +so_call_CallFn: + mov [g_pCurrentRoutine], rcx + + ;; swap the stack + mov rax, [rcx+8] + mov [rcx+8], rsp + mov rsp, rax + mov rax, [rcx+0] + mov rcx, [rcx+80] + + jmp rax + +so_call endp + +; so_resume +so_resume proc public + ;; rbp, rbx, r12 + mov rcx, [g_pCurrentRoutine] + mov rax, [rcx+24] + mov r8, [rcx+16] + mov rdx, [rcx+32] + mov [rcx+24], rbp + mov [rcx+16], rbx + mov [rcx+32], r12 + mov rbp, rax + mov rbx, r8 + mov r12, rdx + ;; r13, r14, r15 + mov rax, [rcx+40] + mov r8, [rcx+48] + mov rdx, [rcx+56] + mov [rcx+40], r13 + mov [rcx+48], r14 + mov [rcx+56], r15 + mov r13, rax + mov r14, r8 + mov r15, rdx + ;; rsi, rdi + mov rax, [rcx+64] + mov rdx, [rcx+72] + mov [rcx+64], rsi + mov [rcx+72], rdi + mov rsi, rax + mov rdi, rdx + + ;; put the return address in pcalladdr + mov rax, [rsp] + mov [rcx], rax + add rsp, 8 ;; remove the return address + + ;; swap stack pointers + mov rax, [rcx+8] + mov [rcx+8], rsp + mov rsp, rax + + ret + +so_resume endp + +so_exit proc public + mov rcx, [g_pCurrentRoutine] + mov rsp, [rcx+8] + mov rbp, [rcx+24] + mov rbx, [rcx+16] + mov r12, [rcx+32] + mov r13, [rcx+40] + mov r14, [rcx+48] + mov r15, [rcx+56] + mov rsi, [rcx+64] + mov rdi, [rcx+72] + ret +so_exit endp + +end \ No newline at end of file diff --git a/pcsx2/IPU/coroutine.c b/pcsx2/IPU/coroutine.c new file mode 100644 index 0000000000..3bdf105fe8 --- /dev/null +++ b/pcsx2/IPU/coroutine.c @@ -0,0 +1,172 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "PS2Etypes.h" +#include "coroutine.h" + +typedef struct s_coroutine { + void* pcalladdr; + void *pcurstack; +#ifdef __x86_64__ + uptr storerbx, storerbp, r12, r13, r14, r15; +#ifdef _MSC_VER + // msft also has rsi and rdi as non-volatile + uptr storersi, storerdi; +#endif + + void* data; +#else + uptr storeebx, storeesi, storeedi, storeebp; +#endif + int restore; // if nonzero, restore the registers + int alloc; + //struct s_coroutine *caller; + //struct s_coroutine *restarget; + +} coroutine; + +#define CO_STK_ALIGN 256 +#define CO_STK_COROSIZE ((sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1)) +#define CO_MIN_SIZE (4 * 1024) + +coroutine* g_pCurrentRoutine; + +coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size) +{ + void* endstack; + int alloc = 0, r = CO_STK_COROSIZE; + coroutine *co; + + if ((size &= ~(sizeof(long) - 1)) < CO_MIN_SIZE) + return NULL; + if (!stack) { + size = (size + sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1); + stack = malloc(size); + if (!stack) + return NULL; + alloc = size; + } + endstack = (char*)stack + size - 64; + co = stack; + stack = (char *) stack + CO_STK_COROSIZE; + *(void**)endstack = NULL; + *(void**)((char*)endstack+sizeof(void*)) = data; +#ifdef __x86_64__ + co->data = data; +#endif + co->alloc = alloc; + co->pcalladdr = (void*)func; + co->pcurstack = endstack; + return co; +} + +void so_delete(coroutine_t coro) +{ + coroutine *co = (coroutine *) coro; + assert( co != NULL ); + if (co->alloc) + free(co); +} + +// see acoroutines.S and acoroutines.asm for other asm implementations +#if defined(_MSC_VER) && !defined(__x86_64__) + +__declspec(naked) void so_call(coroutine_t coro) +{ + __asm { + mov eax, dword ptr [esp+4] + test dword ptr [eax+24], 1 + jnz RestoreRegs + mov [eax+8], ebx + mov [eax+12], esi + mov [eax+16], edi + mov [eax+20], ebp + mov dword ptr [eax+24], 1 + jmp CallFn +RestoreRegs: + // have to load and save at the same time + mov ecx, [eax+8] + mov edx, [eax+12] + mov [eax+8], ebx + mov [eax+12], esi + mov ebx, ecx + mov esi, edx + mov ecx, [eax+16] + mov edx, [eax+20] + mov [eax+16], edi + mov [eax+20], ebp + mov edi, ecx + mov ebp, edx + +CallFn: + mov [g_pCurrentRoutine], eax + mov ecx, esp + mov esp, [eax+4] + mov [eax+4], ecx + + jmp dword ptr [eax] + } +} + +__declspec(naked) void so_resume(void) +{ + __asm { + mov eax, [g_pCurrentRoutine] + mov ecx, [eax+8] + mov edx, [eax+12] + mov [eax+8], ebx + mov [eax+12], esi + mov ebx, ecx + mov esi, edx + mov ecx, [eax+16] + mov edx, [eax+20] + mov [eax+16], edi + mov [eax+20], ebp + mov edi, ecx + mov ebp, edx + + // put the return address in pcalladdr + mov ecx, [esp] + mov [eax], ecx + add esp, 4 // remove the return address + + // swap stack pointers + mov ecx, [eax+4] + mov [eax+4], esp + mov esp, ecx + ret + } +} + +__declspec(naked) void so_exit(void) +{ + __asm { + mov eax, [g_pCurrentRoutine] + mov esp, [eax+4] + mov ebx, [eax+8] + mov esi, [eax+12] + mov edi, [eax+16] + mov ebp, [eax+20] + ret + } +} +#endif diff --git a/pcsx2/IPU/coroutine.h b/pcsx2/IPU/coroutine.h new file mode 100644 index 0000000000..4d0f3e1e9f --- /dev/null +++ b/pcsx2/IPU/coroutine.h @@ -0,0 +1,39 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCSX2_COROUTINE_LIB +#define PCSX2_COROUTINE_LIB + +#ifdef __cplusplus +extern "C" { +#endif + +// low level coroutine library +typedef void *coroutine_t; + +coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size); +void so_delete(coroutine_t coro); +void so_call(coroutine_t coro); +void so_resume(void); +void so_exit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pcsx2/IPU/idct_mmx.obj b/pcsx2/IPU/idct_mmx.obj new file mode 100644 index 0000000000000000000000000000000000000000..9f7d3136085bf4a54addc94ef8f77313e62d4963 GIT binary patch literal 11510 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 HNu%)(hlkEg literal 0 HcmV?d00001 diff --git a/pcsx2/IPU/mpeg2lib/Idct.c b/pcsx2/IPU/mpeg2lib/Idct.c new file mode 100644 index 0000000000..b8d9fff454 --- /dev/null +++ b/pcsx2/IPU/mpeg2lib/Idct.c @@ -0,0 +1,301 @@ +/* + * idct.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that 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 + */ + +//#include +#include "Common.h" + +#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */ +#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */ +#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */ +#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */ +#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */ +#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */ +#define clp(val,res) res = (val < 0) ? 0 : ((val > 255) ? 255 : val); +#define clp2(val,res) res = (val < -255) ? -255 : ((val > 255) ? 255 : val); +/* idct main entry point */ +void (* mpeg2_idct_copy) (s16 * block, u8 * dest, int stride); +/* JayteeMaster: changed dest to 16 bit signed */ +void (* mpeg2_idct_add) (int last, s16 * block, + /*u8*/s16 * dest, int stride); + +/* + * In legal streams, the IDCT output should be between -384 and +384. + * In corrupted streams, it is possible to force the IDCT output to go + * to +-3826 - this is the worst case for a column IDCT where the + * column inputs are 16-bit values. + */ +static u8 clip_lut[1024]; +#define CLIP(i) ((clip_lut+384)[(i)]) + +#if 0 +#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ +do { \ + t0 = W0*d0 + W1*d1; \ + t1 = W0*d1 - W1*d0; \ +} while (0) +#else +#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ +do { \ + int tmp = W0 * (d0 + d1); \ + t0 = tmp + (W1 - W0) * d1; \ + t1 = tmp - (W1 + W0) * d0; \ +} while (0) +#endif + +static void idct_row (s16 * const block) +{ + int d0, d1, d2, d3; + int a0, a1, a2, a3, b0, b1, b2, b3; + int t0, t1, t2, t3; + + /* shortcut */ + if (!(block[1] | ((s32 *)block)[1] | ((s32 *)block)[2] | + ((s32 *)block)[3])) { + u32 tmp = (u16) (block[0] << 3); + tmp |= tmp << 16; + ((s32 *)block)[0] = tmp; + ((s32 *)block)[1] = tmp; + ((s32 *)block)[2] = tmp; + ((s32 *)block)[3] = tmp; + return; + } + + d0 = (block[0] << 11) + 128; + d1 = block[1]; + d2 = block[2] << 11; + d3 = block[3]; + t0 = d0 + d2; + t1 = d0 - d2; + BUTTERFLY (t2, t3, W6, W2, d3, d1); + a0 = t0 + t2; + a1 = t1 + t3; + a2 = t1 - t3; + a3 = t0 - t2; + + d0 = block[4]; + d1 = block[5]; + d2 = block[6]; + d3 = block[7]; + BUTTERFLY (t0, t1, W7, W1, d3, d0); + BUTTERFLY (t2, t3, W3, W5, d1, d2); + b0 = t0 + t2; + b3 = t1 + t3; + t0 -= t2; + t1 -= t3; + b1 = ((t0 + t1) * 181) >> 8; + b2 = ((t0 - t1) * 181) >> 8; + + block[0] = (a0 + b0) >> 8; + block[1] = (a1 + b1) >> 8; + block[2] = (a2 + b2) >> 8; + block[3] = (a3 + b3) >> 8; + block[4] = (a3 - b3) >> 8; + block[5] = (a2 - b2) >> 8; + block[6] = (a1 - b1) >> 8; + block[7] = (a0 - b0) >> 8; +} + +static void idct_col (s16 * const block) +{ + int d0, d1, d2, d3; + int a0, a1, a2, a3, b0, b1, b2, b3; + int t0, t1, t2, t3; + + d0 = (block[8*0] << 11) + 65536; + d1 = block[8*1]; + d2 = block[8*2] << 11; + d3 = block[8*3]; + t0 = d0 + d2; + t1 = d0 - d2; + BUTTERFLY (t2, t3, W6, W2, d3, d1); + a0 = t0 + t2; + a1 = t1 + t3; + a2 = t1 - t3; + a3 = t0 - t2; + + d0 = block[8*4]; + d1 = block[8*5]; + d2 = block[8*6]; + d3 = block[8*7]; + BUTTERFLY (t0, t1, W7, W1, d3, d0); + BUTTERFLY (t2, t3, W3, W5, d1, d2); + b0 = t0 + t2; + b3 = t1 + t3; + t0 = (t0 - t2) >> 8; + t1 = (t1 - t3) >> 8; + b1 = (t0 + t1) * 181; + b2 = (t0 - t1) * 181; + + block[8*0] = (a0 + b0) >> 17; + block[8*1] = (a1 + b1) >> 17; + block[8*2] = (a2 + b2) >> 17; + block[8*3] = (a3 + b3) >> 17; + block[8*4] = (a3 - b3) >> 17; + block[8*5] = (a2 - b2) >> 17; + block[8*6] = (a1 - b1) >> 17; + block[8*7] = (a0 - b0) >> 17; +} + +static void mpeg2_idct_copy_c (s16 * block, u8 * dest, + const int stride) +{ + int i; + + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + for (i = 0; i < 8; i++) + idct_col (block + i); + do { + dest[0] = CLIP (block[0]); + dest[1] = CLIP (block[1]); + dest[2] = CLIP (block[2]); + dest[3] = CLIP (block[3]); + dest[4] = CLIP (block[4]); + dest[5] = CLIP (block[5]); + dest[6] = CLIP (block[6]); + dest[7] = CLIP (block[7]); + + block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; + block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; + + dest += stride; + block += 8; + } while (--i); +} + +/* JayteeMaster: changed dest to 16 bit signed */ +static void mpeg2_idct_add_c (const int last, s16 * block, + /*u8*/s16 * dest, const int stride) +{ + int i; + + if (last != 129 || (block[0] & 7) == 4) { + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + for (i = 0; i < 8; i++) + idct_col (block + i); + do { + dest[0] = block[0]; + dest[1] = block[1]; + dest[2] = block[2]; + dest[3] = block[3]; + dest[4] = block[4]; + dest[5] = block[5]; + dest[6] = block[6]; + dest[7] = block[7]; + + block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; + block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; + + dest += stride; + block += 8; + } while (--i); + } else { + int DC; + + DC = (block[0] + 4) >> 3; + block[0] = block[63] = 0; + i = 8; + do { + dest[0] = DC; + dest[1] = DC; + dest[2] = DC; + dest[3] = DC; + dest[4] = DC; + dest[5] = DC; + dest[6] = DC; + dest[7] = DC; + dest += stride; + } while (--i); + } +} + +u8 mpeg2_scan_norm[64] = { + /* Zig-Zag scan pattern */ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +u8 mpeg2_scan_alt[64] = { + /* Alternate scan pattern */ + 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, + 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, + 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45, + 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 +}; + +/* idct_mmx.c */ +void mpeg2_idct_copy_mmxext (s16 * block, u8 * dest, int stride); +void mpeg2_idct_add_mmxext (int last, s16 * block, + s16 * dest, int stride); +void mpeg2_idct_copy_mmx (s16 * block, u8 * dest, int stride); +void mpeg2_idct_add_mmx (int last, s16 * block, + s16 * dest, int stride); +void mpeg2_idct_mmx_init (void); + +void mpeg2_idct_init() +{ +#if !defined(_MSC_VER) || _MSC_VER < 1400 // ignore vc2005 and beyond + int i, j; + +/* if(hasMultimediaExtensions == 1) + { + mpeg2_idct_copy = mpeg2_idct_copy_mmx; + mpeg2_idct_add = mpeg2_idct_add_mmx; + mpeg2_idct_mmx_init (); + }else if(hasMultimediaExtensionsExt == 1) + { + mpeg2_idct_copy = mpeg2_idct_copy_mmxext; + mpeg2_idct_add = mpeg2_idct_add_mmxext; + mpeg2_idct_mmx_init (); + }else*/ + { + mpeg2_idct_copy = mpeg2_idct_copy_c; + mpeg2_idct_add = mpeg2_idct_add_c; + for (i = -384; i < 640; i++) + clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); + for (i = 0; i < 64; i++) { + j = mpeg2_scan_norm[i]; + mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + j = mpeg2_scan_alt[i]; + mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + } + } + +#else //blah vcnet2005 idiocity :D + int i,j; + mpeg2_idct_copy = mpeg2_idct_copy_c; + mpeg2_idct_add = mpeg2_idct_add_c; + for (i = -384; i < 640; i++) + clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); + for (i = 0; i < 64; i++) { + j = mpeg2_scan_norm[i]; + mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + j = mpeg2_scan_alt[i]; + mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + } +#endif +} diff --git a/pcsx2/IPU/mpeg2lib/Makefile.am b/pcsx2/IPU/mpeg2lib/Makefile.am new file mode 100644 index 0000000000..93e7a871d8 --- /dev/null +++ b/pcsx2/IPU/mpeg2lib/Makefile.am @@ -0,0 +1,4 @@ +INCLUDES = -I@srcdir@/../ -I@srcdir@/../../ +noinst_LIBRARIES = libmpeg2IPU.a + +libmpeg2IPU_a_SOURCES = Idct.c Mpeg.c Mpeg.h Vlc.h \ No newline at end of file diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.c b/pcsx2/IPU/mpeg2lib/Mpeg.c new file mode 100644 index 0000000000..64a485f28a --- /dev/null +++ b/pcsx2/IPU/mpeg2lib/Mpeg.c @@ -0,0 +1,1378 @@ +/* + * Mpeg.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that 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 + */ + +#include "Mpeg.h" +#include "Vlc.h" +#include "coroutine.h" + +extern void (* mpeg2_idct_copy) (s16 * block, u8* dest, int stride); +/* JayteeMaster: changed dest to 16 bit signed */ +extern void (* mpeg2_idct_add) (int last, s16 * block, + /*u8*/s16* dest, int stride); + +extern int FIFOfrom_write(u32* value, int size); + +/* JayteeMaster: remove static attribute */ +/*static */int non_linear_quantizer_scale [] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 14, 16, 18, 20, 22, + 24, 28, 32, 36, 40, 44, 48, 52, + 56, 64, 72, 80, 88, 96, 104, 112 +}; + +extern tIPU_BP g_BP; + +/* Bitstream and buffer needs to be realocated inorder for sucessful + reading of the old data. Here the old data stored in the 2nd slot + of the internal buffer is copied to 1st slot, and the new data read + into 1st slot is copied to the 2nd slot. Which will later be copied + back to the 1st slot when 128bits have been read. +*/ +extern void ReorderBitstream(); + +int get_macroblock_modes (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + int macroblock_modes; + const MBtab * tab; + + switch (decoder->coding_type) { + case I_TYPE: + + macroblock_modes = UBITS (bit_buf, 2); + + if( macroblock_modes == 0 ) + return 0; // error + + tab = MB_I + (macroblock_modes>>1); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if ((! (decoder->frame_pred_frame_dct)) && + (decoder->picture_structure == FRAME_PICTURE)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + + return macroblock_modes; + + case P_TYPE: + + macroblock_modes = UBITS (bit_buf, 6); + + if( macroblock_modes == 0 ) + return 0; // error + + tab = MB_P + (macroblock_modes>>1); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (decoder->picture_structure != FRAME_PICTURE) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (decoder->frame_pred_frame_dct) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case B_TYPE: + + macroblock_modes = UBITS (bit_buf, 6); + + if( macroblock_modes == 0 ) + return 0; // error + tab = MB_B + macroblock_modes; + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (decoder->picture_structure != FRAME_PICTURE) { + if (! (macroblock_modes & MACROBLOCK_INTRA)) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (decoder->frame_pred_frame_dct) { + /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */ + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_INTRA) + goto intra; + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + intra: + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case D_TYPE: + + macroblock_modes = UBITS (bit_buf, 1); + if( macroblock_modes == 0 ) + return 0; // error + DUMPBITS (bit_buf, bits, 1); + return MACROBLOCK_INTRA; + + default: + return 0; + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static int get_quantizer_scale (decoder_t * const decoder) +{ + int quantizer_scale_code; + + quantizer_scale_code = UBITS (decoder->bitstream_buf, 5); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 5); + + if (decoder->q_scale_type) return non_linear_quantizer_scale [quantizer_scale_code]; + else return quantizer_scale_code << 1; +} + +static int get_coded_block_pattern (decoder_t * const decoder) +{ + const CBPtab * tab; + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + if (decoder->bitstream_buf >= 0x20000000) { + tab = CBP_7 + (UBITS (decoder->bitstream_buf, 7) - 16); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); + return tab->cbp; + } + + tab = CBP_9 + UBITS (decoder->bitstream_buf, 9); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); + return tab->cbp; +} + +static int get_luma_dc_dct_diff (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_lum_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + DUMPBITS (bit_buf, bits, tab->len); + bits += size; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 3); + return 0; + } + } + + tab = DC_long + (UBITS (bit_buf, 9) - 0x1e0);//0x1e0); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static int get_chroma_dc_dct_diff (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_chrom_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + DUMPBITS (bit_buf, bits, tab->len); + bits += size; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 2); + return 0; + } + } + + tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len + 1); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +#define SATURATE(val) \ +do { \ + if (((u32)(val + 2048) > 4095)) \ + val = SBITS (val, 1) ^ 2047; \ +} while (0) + +static void get_intra_block_B14 (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + u32 bit_buf; + u8 * bit_ptr; + int bits; + s16 * dest; + + dest = decoder->DCTblock; + i = 0; + mismatch = ~dest[0]; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + i += tab->run; + if (i >= 64) break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static void get_intra_block_B15 (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + u32 bit_buf; + u8 * bit_ptr; + int bits; + s16 * dest; + + dest = decoder->DCTblock; + i = 0; + mismatch = ~dest[0]; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x04000000) { + + tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) { + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else { + /* end of block. I commented out this code because if we */ + /* dont exit here we will still exit at the later test :) */ + //if (i >= 128) break; /* end of block */ + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) break; /* illegal, check against buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + } + } else if (bit_buf >= 0x02000000) { + tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>28) != 0x6 ) + ipuRegs->ctrl.ECD = 1; + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static int get_non_intra_block (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + s16 * dest; + + i = -1; + mismatch = -1; + dest = decoder->DCTblock; + + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) / 32; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; + return i; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static void get_mpeg1_intra_block (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + const DCTtab * tab; + u32 bit_buf; + int bits; + u8 * bit_ptr; + s16 * dest; + + i = 0; + dest = decoder->DCTblock; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) >> 4; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static int get_mpeg1_non_intra_block (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + const DCTtab * tab; + u32 bit_buf; + int bits; + u8 * bit_ptr; + s16 * dest; + + i = -1; + dest = decoder->DCTblock; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + val = 2 * (val + SBITS (val, 1)) + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) / 32; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; + return i; +} + +static void slice_intra_DCT (decoder_t * const decoder, const int cc, + u8 * const dest, const int stride) +{ + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + /* Get the intra DC coefficient and inverse quantize it */ + if (cc == 0) decoder->dc_dct_pred[0] += get_luma_dc_dct_diff (decoder); + else decoder->dc_dct_pred[cc] += get_chroma_dc_dct_diff (decoder); + + decoder->DCTblock[0] = decoder->dc_dct_pred[cc] << (3 - decoder->intra_dc_precision); + + if (decoder->mpeg1) get_mpeg1_intra_block (decoder); + else if (decoder->intra_vlc_format){ + get_intra_block_B15 (decoder); + }else{ + get_intra_block_B14 (decoder); + } + + mpeg2_idct_copy (decoder->DCTblock, dest, stride); +} + +/* JayteeMaster: changed dest to 16 bit signed */ +static void slice_non_intra_DCT (decoder_t * const decoder, + /*u8*/s16 * const dest, const int stride){ + int last; + memset(decoder->DCTblock,0,sizeof(decoder->DCTblock)); + if (decoder->mpeg1) last = get_mpeg1_non_intra_block (decoder); + else last = get_non_intra_block (decoder); + + mpeg2_idct_add (last, decoder->DCTblock, dest, stride); +} + +extern int coded_block_pattern; +extern u16 FillInternalBuffer(u32 * pointer, u32 advance, u32 size); +extern decoder_t g_decoder; +extern int g_nIPU0Data; // or 0x80000000 whenever transferring +extern u8* g_pIPU0Pointer; + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +typedef struct _TGA_HEADER +{ + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header + +#if defined(_MSC_VER) +} TGA_HEADER; +#pragma pack(pop) +#else +} TGA_HEADER __attribute__((packed)); +#endif + +void SaveTGA(const char* filename, int width, int height, void* pdata) +{ + TGA_HEADER hdr; + FILE* f = fopen(filename, "wb"); + if( f == NULL ) + return; + + assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); + + memset(&hdr, 0, sizeof(hdr)); + hdr.imagetype = 2; + hdr.bits = 32; + hdr.width = width; + hdr.height = height; + hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical + + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(pdata, width*height*4, 1, f); + fclose(f); +} +static int s_index = 0, s_frame = 0; + +void SaveRGB32(u8* ptr) +{ + char filename[255]; + sprintf(filename, "frames/frame%.4d.tga", s_index++); + SaveTGA(filename, 16, 16, ptr); +} + +void waitForSCD() +{ + u8 bit8 = 1; + + while(!getBits8((u8*)&bit8, 0)) + so_resume(); + + if (bit8==0) + { + if (g_BP.BP & 7) + g_BP.BP += 8 - (g_BP.BP&7); + + ipuRegs->ctrl.SCD = 1; + } + + while(!getBits32((u8*)&ipuRegs->top, 0)) + { + so_resume(); + } + + BigEndian(ipuRegs->top, ipuRegs->top); + + /*if(ipuRegs->ctrl.SCD) + { + switch(ipuRegs->top & 0xFFFFFFF0) + { + case 0x100: + case 0x1A0: + break; + case 0x1B0: + ipuRegs->ctrl.SCD = 0; + if(ipuRegs->top == 0x1b4) ipuRegs->ctrl.ECD = 1; + //else + //{ + // do + // { + // while(!getBits32((u8*)&ipuRegs->top, 1)) + // { + // so_resume(); + // } + + // BigEndian(ipuRegs->top, ipuRegs->top); + // } + // while((ipuRegs->top & 0xfffffff0) != 0x100); + //} + break; + default: + ipuRegs->ctrl.SCD = 0; + break; + } + }*/ +} + +void mpeg2sliceIDEC(void* pdone) +{ + u32 read; + + decoder_t * decoder = &g_decoder; + + *(int*)pdone = 0; + bitstream_init(decoder); + + decoder->dc_dct_pred[0] = + decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + + decoder->mbc=0; + ipuRegs->ctrl.ECD = 0; + + if (UBITS (decoder->bitstream_buf, 2) == 0) + { + ipuRegs->ctrl.SCD = 0; + }else{ + while (1) { + int DCT_offset, DCT_stride; + int mba_inc; + const MBAtab * mba; + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + decoder->macroblock_modes = get_macroblock_modes (decoder); + + /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */ + if (decoder->macroblock_modes & MACROBLOCK_QUANT)//only IDEC + decoder->quantizer_scale = get_quantizer_scale (decoder); + + if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = decoder->stride; + DCT_stride = decoder->stride * 2; + } else { + DCT_offset = decoder->stride * 8; + DCT_stride = decoder->stride; + } + + if (decoder->macroblock_modes & MACROBLOCK_INTRA) { + decoder->coded_block_pattern = 0x3F;//all 6 blocks + //ipuRegs->ctrl.CBP = 0x3f; + + memset(decoder->mb8,0,sizeof(struct macroblock_8)); + memset(decoder->rgb32,0,sizeof(struct rgb32)); + + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); + slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); + slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); + + // Send The MacroBlock via DmaIpuFrom + if (decoder->ofm==0){ + ipu_csc(decoder->mb8, decoder->rgb32, decoder->sgn); + + g_nIPU0Data = 64; + g_pIPU0Pointer = (u8*)decoder->rgb32; + //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); + while(g_nIPU0Data > 0) { + read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( read == 0 ) + { + so_resume(); + } + else { + g_pIPU0Pointer += read*16; + g_nIPU0Data -= read; + } + } + } + else{ + //ipu_dither(decoder->mb8, decoder->rgb16, decoder->dte); + ipu_csc(decoder->mb8, decoder->rgb32, decoder->dte); + ipu_dither2(decoder->rgb32, decoder->rgb16, decoder->dte); + + g_nIPU0Data = 32; + g_pIPU0Pointer = (u8*)decoder->rgb16; + //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); + while(g_nIPU0Data > 0) { + read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( read == 0 ){ + so_resume(); + } + else { + g_pIPU0Pointer += read*16; + g_nIPU0Data -= read; + } + } + } + decoder->mbc++; + } + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + mba_inc = 0; + while (1) { + if (decoder->bitstream_buf >= 0x10000000) { + mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); + break; + } else if (decoder->bitstream_buf >= 0x03000000) { + mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); + break; + } else switch (UBITS (decoder->bitstream_buf, 11)) { + case 8: /* macroblock_escape */ + mba_inc += 33; + /* pass through */ + case 15: /* macroblock_stuffing (MPEG1 only) */ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + continue; + default: /* end of slice/frame, or error? */ + { + ipuRegs->ctrl.SCD = 0; + coded_block_pattern=decoder->coded_block_pattern; + + g_BP.BP+=decoder->bitstream_bits-16; + + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + waitForSCD(); + + *(int*)pdone = 1; + so_exit(); + } + } + } + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); + mba_inc += mba->mba; + + if (mba_inc) { + decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + do { + decoder->mbc++; + } while (--mba_inc); + } + } + } + + ipuRegs->ctrl.SCD = 0; + + coded_block_pattern=decoder->coded_block_pattern; + + g_BP.BP+=decoder->bitstream_bits-16; + + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + waitForSCD(); + + *(int*)pdone = 1; + so_exit(); +} + +void mpeg2_slice(void* pdone) +{ + int DCT_offset, DCT_stride; + u8 bit8=0; + u32 fp = g_BP.FP; + u32 bp; + decoder_t * decoder = &g_decoder; + u32 size = 0; + + *(int*)pdone = 0; + ipuRegs->ctrl.ECD = 0; + + memset(decoder->mb8,0,sizeof(struct macroblock_8)); + memset(decoder->mb16,0,sizeof(struct macroblock_16)); + + bitstream_init (decoder); + + if (decoder->dcr) + decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + + if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = decoder->stride; + DCT_stride = decoder->stride * 2; + } else { + DCT_offset = decoder->stride * 8; + DCT_stride = decoder->stride; + } + if (decoder->macroblock_modes & MACROBLOCK_INTRA) { + decoder->coded_block_pattern = 0x3F;//all 6 blocks + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); + slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); + slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); + ipu_copy(decoder->mb8,decoder->mb16); + } else { + if (decoder->macroblock_modes & MACROBLOCK_PATTERN) { + decoder->coded_block_pattern = get_coded_block_pattern (decoder); + /* JayteeMaster: changed from mb8 to mb16 and from u8 to s16 */ + if (decoder->coded_block_pattern & 0x20) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y, DCT_stride); + if (decoder->coded_block_pattern & 0x10) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + 8, DCT_stride); + if (decoder->coded_block_pattern & 0x08) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset, DCT_stride); + if (decoder->coded_block_pattern & 0x04) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset + 8, DCT_stride); + if (decoder->coded_block_pattern & 0x2) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cb, decoder->stride>>1); + if (decoder->coded_block_pattern & 0x1) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cr, decoder->stride>>1); + + } + } + + //Send The MacroBlock via DmaIpuFrom + size = 0; // Reset + + ipuRegs->ctrl.SCD=0; + coded_block_pattern=decoder->coded_block_pattern; + + bp = g_BP.BP; + g_BP.BP+=((int)decoder->bitstream_bits-16); + // BP goes from 0 to 128, so negative values mean to read old buffer + // so we minus from 128 to get the correct BP + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + decoder->mbc = 1; + g_nIPU0Data = 48; + g_pIPU0Pointer = (u8*)decoder->mb16; + while(g_nIPU0Data > 0) { + size = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( size == 0 ) + so_resume(); + else { + g_pIPU0Pointer += size*16; + g_nIPU0Data -= size; + } + } + + waitForSCD(); + + decoder->bitstream_bits = 0; + *(int*)pdone = 1; + so_exit(); +} + +int get_motion_delta (decoder_t * const decoder, + const int f_code) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + int delta; + int sign; + const MVtab * tab; + + if ( (bit_buf & 0x80000000) ) { + DUMPBITS (bit_buf, bits, 1); + return 0x00010000; + } else if ( (bit_buf & 0xf0000000) || ((bit_buf & 0xfc000000)==0x0c000000) ) { + + tab = MV_4 + UBITS (bit_buf, 4); + delta = (tab->delta << f_code) + 1; + bits += tab->len + f_code + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) + delta += UBITS (bit_buf, f_code); + bit_buf <<= f_code; + + return (delta ^ sign) - sign; + + } else { + + tab = MV_10 + UBITS (bit_buf, 10); + delta = (tab->delta << f_code) + 1; + bits += tab->len + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) { + NEEDBITS (bit_buf, bits, bit_ptr); + delta += UBITS (bit_buf, f_code); + DUMPBITS (bit_buf, bits, f_code); + } + + return (delta ^ sign) - sign; + + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +int get_dmv (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DMVtab * tab; + + tab = DMV_2 + UBITS (bit_buf, 2); + DUMPBITS (bit_buf, bits, tab->len); + return tab->dmv; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +int get_macroblock_address_increment(decoder_t * const decoder){ + const MBAtab *mba; + + if (decoder->bitstream_buf >= 0x10000000) + mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); + else if (decoder->bitstream_buf >= 0x03000000) + mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); + else switch (UBITS (decoder->bitstream_buf, 11)) { + case 8: /* macroblock_escape */ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + return 0x23; + case 15: /* macroblock_stuffing (MPEG1 only) */ + if (decoder->mpeg1){ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + return 0x22; + } + default: + return 0;//error + } + + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); + return mba->mba + 1; +} diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.h b/pcsx2/IPU/mpeg2lib/Mpeg.h new file mode 100644 index 0000000000..5c570fe1de --- /dev/null +++ b/pcsx2/IPU/mpeg2lib/Mpeg.h @@ -0,0 +1,200 @@ +/* + * Mpeg.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __MPEG_H__ +#define __MPEG_H__ + +#include "Common.h" + +/* macroblock modes */ +#define MACROBLOCK_INTRA 1 +#define MACROBLOCK_PATTERN 2 +#define MACROBLOCK_MOTION_BACKWARD 4 +#define MACROBLOCK_MOTION_FORWARD 8 +#define MACROBLOCK_QUANT 16 +#define DCT_TYPE_INTERLACED 32 +/* motion_type */ +#define MOTION_TYPE_SHIFT 6 +#define MOTION_TYPE_MASK (3*64) +#define MOTION_TYPE_BASE 64 +#define MC_FIELD (1*64) +#define MC_FRAME (2*64) +#define MC_16X8 (2*64) +#define MC_DMV (3*64) + +/* picture structure */ +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_PICTURE 3 + +/* picture coding type */ +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +struct macroblock_8{ + unsigned char Y[16][16]; //0 + unsigned char Cb[8][8]; //1 + unsigned char Cr[8][8]; //2 +}; + +struct macroblock_16{ + short Y[16][16]; //0 + short Cb[8][8]; //1 + short Cr[8][8]; //2 +}; + +struct rgb32{ + unsigned char r, g, b, a; +}; + +struct macroblock_rgb32{ + struct rgb32 c[16][16]; +}; + +struct rgb16{ + unsigned short r:5, g:5, b:5, a:1; +}; + +struct macroblock_rgb16{ + struct rgb16 c[16][16]; +}; + +struct decoder_s { + /* first, state that carries information from one macroblock to the */ + /* next inside a slice, and is never used outside of mpeg2_slice() */ + + /* DCT coefficients - should be kept aligned ! */ + s16 DCTblock[64]; + + /* bit parsing stuff */ + u32 bitstream_buf; /* current 32 bit working set */ + int bitstream_bits; /* used bits in working set */ + u8 * bitstream_ptr; /* buffer with stream data; 128 bits buffer */ + + struct macroblock_8 *mb8; + struct macroblock_16 *mb16; + struct macroblock_rgb32 *rgb32; + struct macroblock_rgb16 *rgb16; + + int stride; + + /* predictor for DC coefficients in intra blocks */ + s16 dc_dct_pred[3]; + + int quantizer_scale; /* remove */ + int dmv_offset; /* remove */ + + /* now non-slice-specific information */ + + /* sequence header stuff */ + u8 *intra_quantizer_matrix; + u8 *non_intra_quantizer_matrix; + + /* picture header stuff */ + + /* what type of picture this is (I, P, B, D) */ + int coding_type; + + /* picture coding extension stuff */ + + /* quantization factor for intra dc coefficients */ + int intra_dc_precision; + /* top/bottom/both fields */ + int picture_structure; + /* bool to indicate all predictions are frame based */ + int frame_pred_frame_dct; + /* bool to indicate whether intra blocks have motion vectors */ + /* (for concealment) */ + int concealment_motion_vectors; + /* bit to indicate which quantization table to use */ + int q_scale_type; + /* bool to use different vlc tables */ + int intra_vlc_format; + /* used for DMV MC */ + int top_field_first; + // Pseudo Sign Offset + int sgn; + // Dither Enable + int dte; + // Output Format + int ofm; + // Macroblock count + int mbc; + // Macroblock type + int macroblock_modes; + // DC Reset + int dcr; + // Coded block pattern + int coded_block_pattern; + + /* stuff derived from bitstream */ + + /* pointer to the zigzag scan we're supposed to be using */ + const u8 * scan; + + int second_field; + + int mpeg1; +}; + +typedef struct decoder_s decoder_t; + +#define IDEC 0 +#define BDEC 1 +void mpeg2sliceIDEC(void* pdone); +void mpeg2_slice(void* pdone); +int get_macroblock_address_increment(decoder_t * const decoder); +int get_macroblock_modes (decoder_t * const decoder); +int get_motion_delta (decoder_t * const decoder, + const int f_code); +int get_dmv (decoder_t * const decoder); +extern int non_linear_quantizer_scale[]; // JayteeMaster: it is needed in Ipu.c + +void ipu_csc(struct macroblock_8 *mb8, struct macroblock_rgb32 *rgb32, int sgn); +void ipu_dither(struct macroblock_8 *mb8, struct macroblock_rgb16 *rgb16, int dte); +void ipu_dither2(struct macroblock_rgb32* rgb32, struct macroblock_rgb16 *rgb16, int dte); +void ipu_vq(struct macroblock_rgb16 *rgb16, u8* indx4); +void ipu_copy(struct macroblock_8 *mb8, struct macroblock_16 *mb16); + +int slice (decoder_t * const decoder, u8 * buffer); +/* idct.c */ +void mpeg2_idct_init (); + +#ifdef _MSC_VER +#define BigEndian(out, in) out = _byteswap_ulong(in) +#else +//#define BigEndian(out, in) \ +// __asm__(".intel_syntax\n" \ +// "bswap %0\n" \ +// ".att_syntax\n" : "=r"(out) : "0"(in) ) + +#define BigEndian(out, in) \ + out = (((((in) >> 24) & 0xFF) << 0) + ((((in) >> 16) & 0xFF) << 8) + \ + ((((in) >> 8) & 0xFF) << 16) + ((((in) >> 0) & 0xFF) << 24)); + +#endif + +#endif//__MPEG_H__ diff --git a/pcsx2/IPU/mpeg2lib/Vlc.h b/pcsx2/IPU/mpeg2lib/Vlc.h new file mode 100644 index 0000000000..503267b1dc --- /dev/null +++ b/pcsx2/IPU/mpeg2lib/Vlc.h @@ -0,0 +1,446 @@ +/* + * vlc.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VLC_H__ +#define __VLC_H__ + +#include "IPU.h" +#include "coroutine.h" + +static u8 data[2]; +static u8 dword[4]; +extern tIPU_BP g_BP; +extern decoder_t g_decoder; +extern void ReorderBitstream(); +static void GETWORD(u32 * bit_buf,int bits) +{ + while(!getBits16(data,1)) + { + so_resume(); + } + *bit_buf |= ((data[0] << 8) | data[1]) << (bits); +} + +static void bitstream_init (decoder_t * decoder){ + decoder->bitstream_bits = -16; + + while( !getBits32(dword, 1) ) + so_resume(); + + decoder->bitstream_buf = (dword[0] << 24) | (dword[1] << 16) | + (dword[2] << 8) |dword[3]; +} + +/* make sure that there are at least 16 valid bits in bit_buf */ +#define NEEDBITS(bit_buf,bits,bit_ptr) \ +do { \ + if (bits > 0) { \ + GETWORD(&bit_buf,bits); \ + bits -= 16; \ + } \ +} while (0) + +/* remove num valid bits from bit_buf */ +#define DUMPBITS(bit_buf,bits,num) \ +do { \ + /*IPU_LOG("DUMPBITS %d\n",num);*/ \ + bit_buf <<= (num); \ + bits += (num); \ +} while (0) + +/* take num bits from the high part of bit_buf and zero extend them */ +#define UBITS(bit_buf,num) (((u32)(bit_buf)) >> (32 - (num))) + +/* take num bits from the high part of bit_buf and sign extend them */ +#define SBITS(bit_buf,num) (((s32)(bit_buf)) >> (32 - (num))) + +typedef struct { + u8 modes; + u8 len; +} MBtab; + +typedef struct { + u8 delta; + u8 len; +} MVtab; + +typedef struct { + s8 dmv; + u8 len; +} DMVtab; + +typedef struct { + u8 cbp; + u8 len; +} CBPtab; + +typedef struct { + u8 size; + u8 len; +} DCtab; + +typedef struct { + u8 run; + u8 level; + u8 len; +} DCTtab; + +typedef struct { + u8 mba; + u8 len; +} MBAtab; + + +#define INTRA MACROBLOCK_INTRA +#define QUANT MACROBLOCK_QUANT + +static const MBtab MB_I [] = { + {INTRA|QUANT, 2}, {INTRA, 1} +}; + +#define MC MACROBLOCK_MOTION_FORWARD +#define CODED MACROBLOCK_PATTERN + +static const MBtab MB_P [] = { + {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, + {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} +}; + +#define FWD MACROBLOCK_MOTION_FORWARD +#define BWD MACROBLOCK_MOTION_BACKWARD +#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD + +static const MBtab MB_B [] = { + {0, 0}, {INTRA|QUANT, 6}, + {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, + {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, + {INTRA, 5}, {INTRA, 5}, + {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, + {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} +}; + +#undef INTRA +#undef QUANT +#undef MC +#undef CODED +#undef FWD +#undef BWD +#undef INTER + + +static const MVtab MV_4 [] = { + { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} +}; + +static const MVtab MV_10 [] = { + { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, + { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, + {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, + { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, + { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, + { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} +}; + + +static const DMVtab DMV_2 [] = { + { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} +}; + + +static const CBPtab CBP_7 [] = { + {0x22, 7}, {0x12, 7}, {0x0a, 7}, {0x06, 7}, + {0x21, 7}, {0x11, 7}, {0x09, 7}, {0x05, 7}, + {0x3f, 6}, {0x3f, 6}, {0x03, 6}, {0x03, 6}, + {0x24, 6}, {0x24, 6}, {0x18, 6}, {0x18, 6}, + {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, + {0x02, 5}, {0x02, 5}, {0x02, 5}, {0x02, 5}, + {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, + {0x01, 5}, {0x01, 5}, {0x01, 5}, {0x01, 5}, + {0x38, 5}, {0x38, 5}, {0x38, 5}, {0x38, 5}, + {0x34, 5}, {0x34, 5}, {0x34, 5}, {0x34, 5}, + {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, + {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, + {0x28, 5}, {0x28, 5}, {0x28, 5}, {0x28, 5}, + {0x14, 5}, {0x14, 5}, {0x14, 5}, {0x14, 5}, + {0x30, 5}, {0x30, 5}, {0x30, 5}, {0x30, 5}, + {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3} +}; + +static const CBPtab CBP_9 [] = { + {0, 0}, {0x00, 9}, {0x27, 9}, {0x1b, 9}, + {0x3b, 9}, {0x37, 9}, {0x2f, 9}, {0x1f, 9}, + {0x3a, 8}, {0x3a, 8}, {0x36, 8}, {0x36, 8}, + {0x2e, 8}, {0x2e, 8}, {0x1e, 8}, {0x1e, 8}, + {0x39, 8}, {0x39, 8}, {0x35, 8}, {0x35, 8}, + {0x2d, 8}, {0x2d, 8}, {0x1d, 8}, {0x1d, 8}, + {0x26, 8}, {0x26, 8}, {0x1a, 8}, {0x1a, 8}, + {0x25, 8}, {0x25, 8}, {0x19, 8}, {0x19, 8}, + {0x2b, 8}, {0x2b, 8}, {0x17, 8}, {0x17, 8}, + {0x33, 8}, {0x33, 8}, {0x0f, 8}, {0x0f, 8}, + {0x2a, 8}, {0x2a, 8}, {0x16, 8}, {0x16, 8}, + {0x32, 8}, {0x32, 8}, {0x0e, 8}, {0x0e, 8}, + {0x29, 8}, {0x29, 8}, {0x15, 8}, {0x15, 8}, + {0x31, 8}, {0x31, 8}, {0x0d, 8}, {0x0d, 8}, + {0x23, 8}, {0x23, 8}, {0x13, 8}, {0x13, 8}, + {0x0b, 8}, {0x0b, 8}, {0x07, 8}, {0x07, 8} +}; + +static const DCtab DC_lum_5 [] = { + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} +}; + +static const DCtab DC_chrom_5 [] = { + {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} +}; + +static const DCtab DC_long [] = { + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + + +static const DCTtab DCT_16 [] = { + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + { 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0}, + { 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0}, + { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0}, + { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0} +}; + +static const DCTtab DCT_15 [] = { + { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, + { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, + { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, + { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, + { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, + { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, + { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, + { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, + { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, + { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, + { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, + { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} +}; + +static const DCTtab DCT_13 [] = { + { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, + { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, + { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, + { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, + { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, + { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, + { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, + { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, + { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, + { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, + { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, + { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} +}; + +static const DCTtab DCT_B14_10 [] = { + { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, + { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} +}; + +static const DCTtab DCT_B14_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, + { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, + { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, + { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, + { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} +}; + +static const DCTtab DCT_B14AC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} +}; + +static const DCTtab DCT_B14DC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} +}; + +static const DCTtab DCT_B15_10 [] = { + { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, + { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} +}; + +static const DCTtab DCT_B15_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, + { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, + { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, + { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, + { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, + { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, + { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, + { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} +}; + + +static const MBAtab MBA_5 [] = { + {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} +}; + +static const MBAtab MBA_11 [] = { + {32, 11}, {31, 11}, {30, 11}, {29, 11}, + {28, 11}, {27, 11}, {26, 11}, {25, 11}, + {24, 11}, {23, 11}, {22, 11}, {21, 11}, + {20, 10}, {20, 10}, {19, 10}, {19, 10}, + {18, 10}, {18, 10}, {17, 10}, {17, 10}, + {16, 10}, {16, 10}, {15, 10}, {15, 10}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 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}, { 7, 7}, { 7, 7}, { 7, 7} +}; +#endif//__VLC_H__ diff --git a/pcsx2/IPU/yuv2rgb.asm b/pcsx2/IPU/yuv2rgb.asm new file mode 100644 index 0000000000..c5714205ea --- /dev/null +++ b/pcsx2/IPU/yuv2rgb.asm @@ -0,0 +1,242 @@ +;/******************************************************** +; * Some code. Copyright (C) 2003 by Pascal Massimino. * +; * All Rights Reserved. (http://skal.planet-d.net) * +; * For Educational/Academic use ONLY. See 'LICENSE.TXT'.* +; ********************************************************/ +;////////////////////////////////////////////////////////// +;// NASM macros +;////////////////////////////////////////////////////////// + +%ifdef LINUX + +;////////////////////////////////////////////////////////// +; LINUX / egcs / macros +;////////////////////////////////////////////////////////// + +%macro extrn 1 + extern %1 + %define %1 %1 +%endmacro +%macro globl 1 + global %1 + %define %1 %1 +%endmacro + +%macro DATA 0 +[section data align=16 write alloc USE32] +%endmacro +%macro TEXT 0 +[section text align=16 nowrite alloc exec USE32] +%endmacro + +%endif ; LINUX + +;////////////////////////////////////////////////////////// + +%ifdef WIN32 + +%macro extrn 1 + extern _%1 + %define %1 _%1 +%endmacro + +%macro globl 1 + global _%1 + %define %1 _%1 +%endmacro + +%macro DATA 0 +[section .data align=16 write alloc USE32] +%endmacro +%macro TEXT 0 +[section .text align=16 nowrite alloc exec USE32] +%endmacro + +%endif ; WIN32 + +;////////////////////////////////////////////////////////// +; +; MACRO for timing. NASM. +; Total additional code size is 0xb0. +; this keep code alignment right. + +extrn Skl_Cur_Count_ +extrn Skl_Print_Tics + +%macro SKL_USE_RDSTC 0 +extrn SKL_RDTSC_0_ASM +extrn SKL_RDTSC_1_ASM +extrn SKL_RDTSC_2_ASM +%endmacro +%define SKL_RDTSC_OFFSET 15 ; check value with skl_rdtsc.h... + +%macro SKL_RDTSC_IN 0 + SKL_USE_RDSTC + call SKL_RDTSC_0_ASM +.Skl_RDTSC_Loop_: + call SKL_RDTSC_1_ASM +%endmacro + +%macro SKL_RDTSC_OUT 0 + call SKL_RDTSC_2_ASM + dec dword [Skl_Cur_Count_] + jge near .Skl_RDTSC_Loop_ + push dword 53 + call Skl_Print_Tics +%endmacro + +;////////////////////////////////////////////////////////// + +globl Skl_YUV_To_RGB32_MMX + +;////////////////////////////////////////////////////////////////////// + + ; eax: *U + ; ebx: *V + ; esi: *Y + ; edx: Src_BpS + ; edi: *Dst + ; ebx: Dst_BpS + ; ecx: Counter + +%define RGBp esp+20 +%define Yp esp+16 +%define Up esp+12 +%define Vp esp+8 +%define xCnt esp+4 +%define yCnt esp+0 + +Skl_YUV_To_RGB32_MMX: + + push ebx + push esi + push edi + push ebp + + mov edi, [esp+4 +16] ; RGB + mov ebp, [esp+12 +16] ; Y + mov eax, [esp+16 +16] ; U + mov ebx, [esp+20 +16] ; V + mov edx, [esp+24 +16] ; Src_BpS + mov ecx, [esp+28 +16] ; Width + + lea edi, [edi+4*ecx] ; RGB += Width*sizeof(32b) + lea ebp, [ebp+ecx] ; ebp: Y1 = Y + Width + add edx, ebp ; edx: Y2 = Y1+ BpS + push edi ; [RGBp] + push ebp ; [Yp] + shr ecx, 1 ; Width/=2 + lea eax, [eax+ecx] ; U += W/2 + lea ebx, [ebx+ecx] ; V += W/2 + push eax ; [Up] + push ebx ; [Vp] + + neg ecx ; ecx = -Width/2 + push ecx ; save [xCnt] + push eax ; fake ([yCnt]) + + mov ecx, [esp+32 +40] ; Height + shr ecx, 1 ; /2 + + mov esi, [Up] + mov edi, [Vp] + + jmp .Go + +align 16 +.Loop_y + dec ecx + jg .Add + + add esp, 24 ; rid of all tmp + pop ebp + pop edi + pop esi + pop ebx + + ret + +align 16 +.Add + mov edi, [esp+8 +40] ; Dst_BpS + mov esi, [esp+24 +40] ; Src_BpS + mov edx, [RGBp] + mov ebp, [Yp] + lea edx, [edx+2*edi] ; RGB += 2*Dst_BpS + lea ebp, [ebp+2*esi] ; Y += 2*Src_BpS + mov [RGBp], edx + mov edi, [Vp] + mov [Yp], ebp ; Y1 + lea edx, [ebp+esi] ; Y2 + + lea edi, [edi+esi] ; V += Src_BpS + add esi, [Up] ; U += Src_BpS + mov [Vp], edi + mov [Up], esi + +.Go + mov [yCnt], ecx + mov ecx, [xCnt] + + ; 5210c@640x480 + +.Loop_x ; edi,esi: U,V; ebp,edx: Y1, Y2; ecx: xCnt + + ; R = Y + a.U + ; G = Y + c.V + b.U + ; B = Y + d.V + + movzx eax, byte [edi+ecx+0] + movzx ebx, byte [esi+ecx+0] + movq mm0, [Skl_YUV_Tab32_MMX+0*2048 + eax*8] + movzx eax, byte [edi+ecx+1] + paddw mm0, [Skl_YUV_Tab32_MMX+1*2048 + ebx*8] + movzx ebx, byte [esi+ecx+1] + movq mm4, [Skl_YUV_Tab32_MMX+0*2048 + eax*8] + movzx eax, byte [ebp + 2*ecx+0] + paddw mm4, [Skl_YUV_Tab32_MMX+1*2048 + ebx*8] + movzx ebx, byte [ebp + 2*ecx+1] + + movq mm1, mm0 + movq mm2, mm0 + movq mm3, mm0 + movq mm5, mm4 + movq mm6, mm4 + movq mm7, mm4 + + paddw mm0, [Skl_YUV_Tab32_MMX+2*2048 + eax*8] + movzx eax, byte [ebp + 2*ecx+2] + paddw mm1, [Skl_YUV_Tab32_MMX+2*2048 + ebx*8] + movzx ebx, byte [ebp + 2*ecx+3] + packuswb mm0, mm1 + paddw mm4, [Skl_YUV_Tab32_MMX+2*2048 + eax*8] + movzx eax, byte [edx + 2*ecx+0] + paddw mm5, [Skl_YUV_Tab32_MMX+2*2048 + ebx*8] + + packuswb mm4, mm5 + mov esi, [RGBp] + movzx ebx, byte [edx + 2*ecx+1] + movq [esi+8*ecx+0], mm0 ; 2x32b + movq [esi+8*ecx+8], mm4 ; 2x32b + + paddw mm2, [Skl_YUV_Tab32_MMX+2*2048 + eax*8] + movzx eax, byte [edx + 2*ecx+2] + paddw mm3, [Skl_YUV_Tab32_MMX+2*2048 + ebx*8] + movzx ebx, byte [edx + 2*ecx+3] + packuswb mm2, mm3 + paddw mm6, [Skl_YUV_Tab32_MMX+2*2048 + eax*8] + add esi, [esp+8 +40] + paddw mm7, [Skl_YUV_Tab32_MMX+2*2048 + ebx*8] + + mov edi, [Vp] + packuswb mm6, mm7 + movq [esi+8*ecx+0], mm2 ; 2x32b + movq [esi+8*ecx+8], mm6 ; 2x32b + + add ecx, 2 + mov esi, [Up] + + jl near .Loop_x + + mov ecx, [yCnt] + jmp .Loop_y diff --git a/pcsx2/IPU/yuv2rgb.c b/pcsx2/IPU/yuv2rgb.c new file mode 100644 index 0000000000..c7df6a906d --- /dev/null +++ b/pcsx2/IPU/yuv2rgb.c @@ -0,0 +1,510 @@ +/* + * yuv2rgb.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that 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 + */ + +#include +#include + +#include "mpeg2lib/Mpeg.h" +#include "yuv2rgb.h" + +//#include "convert_internal.h" //START +typedef struct { + u8 * rgb_ptr; + int width; + int uv_stride, uv_stride_frame; + int rgb_stride, rgb_stride_frame; + void (* yuv2rgb) (u8 *, u8 *, u8 *, u8 *, + void *, void *, int); +} convert_rgb_t; + +typedef void yuv2rgb_copy (void * id, u8 * const * src, + unsigned int v_offset); + +yuv2rgb_copy * yuv2rgb_init_mmxext (int bpp, int mode); +yuv2rgb_copy * yuv2rgb_init_mmx (int bpp, int mode); +yuv2rgb_copy * yuv2rgb_init_mlib (int bpp, int mode); +//#include "convert_internal.h" //END + +static u32 matrix_coefficients = 6; + +const s32 Inverse_Table_6_9[8][4] = { + {117504, 138453, 13954, 34903}, /*0 no sequence_display_extension */ + {117504, 138453, 13954, 34903}, /*1 ITU-R Rec. 709 (1990) */ + {104597, 132201, 25675, 53279}, /*2 unspecified */ + {104597, 132201, 25675, 53279}, /*3 reserved */ + {104448, 132798, 24759, 53109}, /*4 FCC */ + {104597, 132201, 25675, 53279}, /*5 ITU-R Rec. 624-4 System B, G */ + {104597, 132201, 25675, 53279}, /*6 SMPTE 170M */ + {117579, 136230, 16907, 35559} /*7 SMPTE 240M (1987) */ +}; + +typedef void yuv2rgb_c_internal (u8 *, u8 *, u8 *, u8 *, + void *, void *, int); + +void * table_rV[256]; +void * table_gU[256]; +int table_gV[256]; +void * table_bU[256]; + +#define _RGB(type,i) \ + U = pu[i]; \ + V = pv[i]; \ + r = (type *) table_rV[V]; \ + g = (type *) (((u8 *)table_gU[U]) + table_gV[V]); \ + b = (type *) table_bU[U]; + +#define DST(py,dst,i) \ + Y = py[2*i]; \ + dst[2*i] = r[Y] + g[Y] + b[Y]; \ + Y = py[2*i+1]; \ + dst[2*i+1] = r[Y] + g[Y] + b[Y]; + +#define DSTRGB(py,dst,i) \ + Y = py[2*i]; \ + dst[6*i] = r[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = b[Y]; \ + Y = py[2*i+1]; \ + dst[6*i+3] = r[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = b[Y]; + +#define DSTBGR(py,dst,i) \ + Y = py[2*i]; \ + dst[6*i] = b[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = r[Y]; \ + Y = py[2*i+1]; \ + dst[6*i+3] = b[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = r[Y]; + +static void yuv2rgb_c_32 (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u32 * r, * g, * b; + u32 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u32 *) _dst_1; + dst_2 = (u32 *) _dst_2; + + do { + _RGB (u32, 0); + DST (py_1, dst_1, 0); + DST (py_2, dst_2, 0); + + _RGB (u32, 1); + DST (py_2, dst_2, 1); + DST (py_1, dst_1, 1); + + _RGB (u32, 2); + DST (py_1, dst_1, 2); + DST (py_2, dst_2, 2); + + _RGB (u32, 3); + DST (py_2, dst_2, 3); + DST (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); +} + +/* This is very near from the yuv2rgb_c_32 code */ +static void yuv2rgb_c_24_rgb (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u8 * r, * g, * b; + u8 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u8 *) _dst_1; + dst_2 = (u8 *) _dst_2; + + do { + _RGB (u8, 0); + DSTRGB (py_1, dst_1, 0); + DSTRGB (py_2, dst_2, 0); + + _RGB (u8, 1); + DSTRGB (py_2, dst_2, 1); + DSTRGB (py_1, dst_1, 1); + + _RGB (u8, 2); + DSTRGB (py_1, dst_1, 2); + DSTRGB (py_2, dst_2, 2); + + _RGB (u8, 3); + DSTRGB (py_2, dst_2, 3); + DSTRGB (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); +} + +/* only trivial mods from yuv2rgb_c_24_rgb */ +static void yuv2rgb_c_24_bgr (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u8 * r, * g, * b; + u8 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u8 *) _dst_1; + dst_2 = (u8 *) _dst_2; + + do { + _RGB (u8, 0); + DSTBGR (py_1, dst_1, 0); + DSTBGR (py_2, dst_2, 0); + + _RGB (u8, 1); + DSTBGR (py_2, dst_2, 1); + DSTBGR (py_1, dst_1, 1); + + _RGB (u8, 2); + DSTBGR (py_1, dst_1, 2); + DSTBGR (py_2, dst_2, 2); + + _RGB (u8, 3); + DSTBGR (py_2, dst_2, 3); + DSTBGR (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); +} + +/* This is exactly the same code as yuv2rgb_c_32 except for the types of */ +/* r, g, b, dst_1, dst_2 */ +static void yuv2rgb_c_16 (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u16 * r, * g, * b; + u16 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u16 *) _dst_1; + dst_2 = (u16 *) _dst_2; + + do { + _RGB (u16, 0); + DST (py_1, dst_1, 0); + DST (py_2, dst_2, 0); + + _RGB (u16, 1); + DST (py_2, dst_2, 1); + DST (py_1, dst_1, 1); + + _RGB (u16, 2); + DST (py_1, dst_1, 2); + DST (py_2, dst_2, 2); + + _RGB (u16, 3); + DST (py_2, dst_2, 3); + DST (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); +} + +static int div_round (int dividend, int divisor) +{ + if (dividend > 0) + return (dividend + (divisor>>1)) / divisor; + else + return -((-dividend + (divisor>>1)) / divisor); +} + +static yuv2rgb_c_internal * yuv2rgb_c_init (int order, int bpp) +{ + int i; + u8 table_Y[1024]; + u32 * table_32 = 0; + u16 * table_16 = 0; + u8 * table_8 = 0; + int entry_size = 0; + void * table_r = 0; + void * table_g = 0; + void * table_b = 0; + yuv2rgb_c_internal * yuv2rgb; + + int crv = Inverse_Table_6_9[matrix_coefficients][0]; + int cbu = Inverse_Table_6_9[matrix_coefficients][1]; + int cgu = -Inverse_Table_6_9[matrix_coefficients][2]; + int cgv = -Inverse_Table_6_9[matrix_coefficients][3]; + + for (i = 0; i < 1024; i++) { + int j; + + j = (76309 * (i - 384 - 16) + 32768) >> 16; + j = (j < 0) ? 0 : ((j > 255) ? 255 : j); + table_Y[i] = j; + } + + switch (bpp) { + case 32: + yuv2rgb = yuv2rgb_c_32; + + table_32 = (u32 *) malloc ((197 + 2*682 + 256 + 132) * + sizeof (u32)); + + entry_size = sizeof (u32); + table_r = table_32 + 197; + table_b = table_32 + 197 + 685; + table_g = table_32 + 197 + 2*682; + + for (i = -197; i < 256+197; i++) + ((u32 *) table_r)[i] = + table_Y[i+384] << ((order == CONVERT_RGB) ? 16 : 0); + for (i = -132; i < 256+132; i++) + ((u32 *) table_g)[i] = table_Y[i+384] << 8; + for (i = -232; i < 256+232; i++) + ((u32 *) table_b)[i] = + table_Y[i+384] << ((order == CONVERT_RGB) ? 0 : 16); + break; + + case 24: + yuv2rgb = (order == CONVERT_RGB) ? yuv2rgb_c_24_rgb : yuv2rgb_c_24_bgr; + + table_8 = (u8 *) malloc ((256 + 2*232) * sizeof (u8)); + + entry_size = sizeof (u8); + table_r = table_g = table_b = table_8 + 232; + + for (i = -232; i < 256+232; i++) + ((u8 * )table_b)[i] = table_Y[i+384]; + break; + + case 15: + case 16: + yuv2rgb = yuv2rgb_c_16; + + table_16 = (u16 *) malloc ((197 + 2*682 + 256 + 132) * + sizeof (u16)); + + entry_size = sizeof (u16); + table_r = table_16 + 197; + table_b = table_16 + 197 + 685; + table_g = table_16 + 197 + 2*682; + + for (i = -197; i < 256+197; i++) { + int j = table_Y[i+384] >> 3; + + if (order == CONVERT_RGB) + j <<= ((bpp==16) ? 11 : 10); + + ((u16 *)table_r)[i] = j; + } + for (i = -132; i < 256+132; i++) { + int j = table_Y[i+384] >> ((bpp==16) ? 2 : 3); + + ((u16 *)table_g)[i] = j << 5; + } + for (i = -232; i < 256+232; i++) { + int j = table_Y[i+384] >> 3; + + if (order == CONVERT_RGB) + j <<= ((bpp==16) ? 11 : 10); + + ((u16 *)table_b)[i] = j; + } + break; + + default: + fprintf (stderr, "%ibpp not supported by yuv2rgb\n", bpp); + exit (1); + } + + for (i = 0; i < 256; i++) { + table_rV[i] = (((u8 *)table_r) + + entry_size * div_round (crv * (i-128), 76309)); + table_gU[i] = (((u8 *)table_g) + + entry_size * div_round (cgu * (i-128), 76309)); + table_gV[i] = entry_size * div_round (cgv * (i-128), 76309); + table_bU[i] = (((u8 *)table_b) + + entry_size * div_round (cbu * (i-128), 76309)); + } + + return yuv2rgb; +} + +static void convert_yuv2rgb_c (void * _id, u8 * Y, u8 * Cr, u8 * Cb, + unsigned int v_offset) +{ + convert_rgb_t * id = (convert_rgb_t *) _id; + u8 * dst; + u8 * py; + u8 * pu; + u8 * pv; + int loop; + + dst = id->rgb_ptr + id->rgb_stride * v_offset; + py = Y; pu = Cr; pv = Cb; + + loop = 8; + do { + id->yuv2rgb (py, py + (id->uv_stride << 1), pu, pv, + dst, dst + id->rgb_stride, id->width); + py += id->uv_stride << 2; + pu += id->uv_stride; + pv += id->uv_stride; + dst += 2 * id->rgb_stride; + } while (--loop); +} + +static void convert_start (void * _id, u8 * dest, int flags) +{ + convert_rgb_t * id = (convert_rgb_t *) _id; + id->rgb_ptr = dest; + switch (flags) { + case CONVERT_BOTTOM_FIELD: + id->rgb_ptr += id->rgb_stride_frame; + /* break thru */ + case CONVERT_TOP_FIELD: + id->uv_stride = id->uv_stride_frame << 1; + id->rgb_stride = id->rgb_stride_frame << 1; + break; + default: + id->uv_stride = id->uv_stride_frame; + id->rgb_stride = id->rgb_stride_frame; + } +} + +static void convert_internal (int order, int bpp, int width, int height, + u32 accel, void * arg, + convert_init_t * result) +{ + convert_rgb_t * id = (convert_rgb_t *) result->id; + + if (!id) { + result->id_size = sizeof (convert_rgb_t); + } else { + id->width = width; + id->uv_stride_frame = width >> 1; + id->rgb_stride_frame = ((bpp + 7) >> 3) * width; + + result->buf_size[0] = id->rgb_stride_frame * height; + result->buf_size[1] = result->buf_size[2] = 0; + result->start = convert_start; + + result->copy = NULL; +#ifdef ARCH_X86 + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMXEXT)) { + result->copy = yuv2rgb_init_mmxext (order, bpp); + } + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMX)) { + result->copy = yuv2rgb_init_mmx (order, bpp); + } +#endif +#ifdef LIBVO_MLIB + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_MLIB)) { + result->copy = yuv2rgb_init_mlib (order, bpp); + } +#endif + if (result->copy == NULL) { + result->copy = convert_yuv2rgb_c; + id->yuv2rgb = yuv2rgb_c_init (order, bpp); + } + } +} + +void convert_rgb32 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 32, width, height, accel, arg, result); +} + +void convert_rgb24 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 24, width, height, accel, arg, result); +} + +void convert_rgb16 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 16, width, height, accel, arg, result); +} + +void convert_rgb15 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 15, width, height, accel, arg, result); +} + +void convert_bgr32 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 32, width, height, accel, arg, result); +} + +void convert_bgr24 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 24, width, height, accel, arg, result); +} + +void convert_bgr16 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 16, width, height, accel, arg, result); +} + +void convert_bgr15 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 15, width, height, accel, arg, result); +} + +convert_t* convert_rgb (int order, int bpp) +{ + if (order == CONVERT_RGB || order == CONVERT_BGR) + switch (bpp) { + case 32: return (order == CONVERT_RGB) ? convert_rgb32 : convert_bgr32; + case 24: return (order == CONVERT_RGB) ? convert_rgb24 : convert_bgr24; + case 16: return (order == CONVERT_RGB) ? convert_rgb16 : convert_bgr16; + case 15: return (order == CONVERT_RGB) ? convert_rgb15 : convert_bgr15; + } + return NULL; +} diff --git a/pcsx2/IPU/yuv2rgb.h b/pcsx2/IPU/yuv2rgb.h new file mode 100644 index 0000000000..d53c32f0d0 --- /dev/null +++ b/pcsx2/IPU/yuv2rgb.h @@ -0,0 +1,57 @@ +/* + * yuv2rgb.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef YUV2RGB_H +#define YUV2RGB_H + +#define CONVERT_FRAME 0 +#define CONVERT_TOP_FIELD 1 +#define CONVERT_BOTTOM_FIELD 2 +#define CONVERT_BOTH_FIELDS 3 + +typedef struct convert_init_s { + void * id; + int id_size; + int buf_size[3]; + void (* start) (void * id, u8 * dest, int flags); + void (* copy) (void * id, u8 * Y, u8 * Cr, u8 * Cb, unsigned int v_offset); +} convert_init_t; + +typedef void convert_t (int width, int height, u32 accel, void * arg, + convert_init_t * result); + +convert_t convert_rgb32; +convert_t convert_rgb24; +convert_t convert_rgb16; +convert_t convert_rgb15; +convert_t convert_bgr32; +convert_t convert_bgr24; +convert_t convert_bgr16; +convert_t convert_bgr15; + +#define CONVERT_RGB 0 +#define CONVERT_BGR 1 +convert_t * convert_rgb (int order, int bpp); + +#endif /* YUV2RGB_H */ diff --git a/pcsx2/InterTables.c b/pcsx2/InterTables.c new file mode 100644 index 0000000000..9c5ad0d8d6 --- /dev/null +++ b/pcsx2/InterTables.c @@ -0,0 +1,224 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +//all tables for R5900 are define here.. + +#include "InterTables.h" + +void (*Int_OpcodePrintTable[64])() = +{ + SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, + ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, + COP0, COP1, COP2, UnknownOpcode, BEQL, BNEL, BLEZL, BGTZL, + DADDI, DADDIU, LDL, LDR, MMI, UnknownOpcode, LQ, SQ, + LB, LH, LWL, LW, LBU, LHU, LWR, LWU, + SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, + UnknownOpcode, LWC1, UnknownOpcode, PREF, UnknownOpcode,UnknownOpcode, LQC2, LD, + UnknownOpcode, SWC1, UnknownOpcode, UnknownOpcode, UnknownOpcode,UnknownOpcode, SQC2, SD +}; + + +void (*Int_SpecialPrintTable[64])() = +{ + SLL, UnknownOpcode, SRL, SRA, SLLV, UnknownOpcode, SRLV, SRAV, + JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, UnknownOpcode, SYNC, + MFHI, MTHI, MFLO, MTLO, DSLLV, UnknownOpcode, DSRLV, DSRAV, + MULT, MULTU, DIV, DIVU, UnknownOpcode,UnknownOpcode,UnknownOpcode,UnknownOpcode, + ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, + MFSA , MTSA , SLT, SLTU, DADD, DADDU, DSUB, DSUBU, + TGE, TGEU, TLT, TLTU, TEQ, UnknownOpcode, TNE, UnknownOpcode, + DSLL, UnknownOpcode, DSRL, DSRA, DSLL32, UnknownOpcode, DSRL32, DSRA32 +}; + +void (*Int_REGIMMPrintTable[32])() = { + BLTZ, BGEZ, BLTZL, BGEZL, UnknownOpcode, UnknownOpcode, UnknownOpcode, UnknownOpcode, + TGEI, TGEIU, TLTI, TLTIU, TEQI, UnknownOpcode, TNEI, UnknownOpcode, + BLTZAL, BGEZAL, BLTZALL, BGEZALL, UnknownOpcode, UnknownOpcode, UnknownOpcode, UnknownOpcode, + MTSAB, MTSAH , UnknownOpcode, UnknownOpcode, UnknownOpcode, UnknownOpcode, UnknownOpcode, UnknownOpcode, +}; + +void (*Int_MMIPrintTable[64])() = +{ + MADD, MADDU, MMI_Unknown, MMI_Unknown, PLZCW, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI0, MMI2, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MFHI1, MTHI1, MFLO1, MTLO1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MULT1, MULTU1, DIV1, DIVU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MADD1, MADDU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI1 , MMI3, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMFHL, PMTHL, MMI_Unknown, MMI_Unknown, PSLLH, MMI_Unknown, PSRLH, PSRAH, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, PSLLW, MMI_Unknown, PSRLW, PSRAW, +}; + +void (*Int_MMI0PrintTable[32])() = +{ + PADDW, PSUBW, PCGTW, PMAXW, + PADDH, PSUBH, PCGTH, PMAXH, + PADDB, PSUBB, PCGTB, MMI_Unknown, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PADDSW, PSUBSW, PEXTLW, PPACW, + PADDSH, PSUBSH, PEXTLH, PPACH, + PADDSB, PSUBSB, PEXTLB, PPACB, + MMI_Unknown, MMI_Unknown, PEXT5, PPAC5, +}; + +void (*Int_MMI1PrintTable[32])() = +{ + MMI_Unknown, PABSW, PCEQW, PMINW, + PADSBH, PABSH, PCEQH, PMINH, + MMI_Unknown, MMI_Unknown, PCEQB, MMI_Unknown, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PADDUW, PSUBUW, PEXTUW, MMI_Unknown, + PADDUH, PSUBUH, PEXTUH, MMI_Unknown, + PADDUB, PSUBUB, PEXTUB, QFSRV, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, +}; + + +void (*Int_MMI2PrintTable[32])() = +{ + PMADDW, MMI_Unknown, PSLLVW, PSRLVW, + PMSUBW, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMFHI, PMFLO, PINTH, MMI_Unknown, + PMULTW, PDIVW, PCPYLD, MMI_Unknown, + PMADDH, PHMADH, PAND, PXOR, + PMSUBH, PHMSBH, MMI_Unknown, MMI_Unknown, + MMI_Unknown, MMI_Unknown, PEXEH, PREVH, + PMULTH, PDIVBW, PEXEW, PROT3W, +}; + +void (*Int_MMI3PrintTable[32])() = +{ + PMADDUW, MMI_Unknown, MMI_Unknown, PSRAVW, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMTHI, PMTLO, PINTEH, MMI_Unknown, + PMULTUW, PDIVUW, PCPYUD, MMI_Unknown, + MMI_Unknown, MMI_Unknown, POR, PNOR, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI_Unknown, MMI_Unknown, PEXCH, PCPYH, + MMI_Unknown, MMI_Unknown, PEXCW, MMI_Unknown, +}; + +void (*Int_COP0PrintTable[32])() = +{ + MFC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, MTC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_BC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Func, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, +}; + +void (*Int_COP0BC0PrintTable[32])() = +{ + BC0F, BC0T, BC0FL, BC0TL, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, +}; + +void (*Int_COP0C0PrintTable[64])() = { + COP0_Unknown, TLBR, TLBWI, COP0_Unknown, COP0_Unknown, COP0_Unknown, TLBWR, COP0_Unknown, + TLBP, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + ERET, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + EI, DI, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown +}; + +void (*Int_COP1PrintTable[32])() = { + MFC1, COP1_Unknown, CFC1, COP1_Unknown, MTC1, COP1_Unknown, CTC1, COP1_Unknown, + COP1_BC1, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_S, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_W, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, +}; + +void (*Int_COP1BC1PrintTable[32])() = { + BC1F, BC1T, BC1FL, BC1TL, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, +}; + +void (*Int_COP1SPrintTable[64])() = { +ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,RSQRT_S, COP1_Unknown, +ADDA_S, SUBA_S, MULA_S, COP1_Unknown,MADD_S, MSUB_S, MADDA_S, MSUBA_S, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,CVT_W, COP1_Unknown,COP1_Unknown,COP1_Unknown, +MAX_S, MIN_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +C_F, COP1_Unknown,C_EQ, COP1_Unknown,C_LT, COP1_Unknown,C_LE, COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +}; + +void (*Int_COP1WPrintTable[64])() = { +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +CVT_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, +}; + + +void (*Int_COP2PrintTable[32])() = { + COP2_Unknown, QMFC2, CFC2, COP2_Unknown, COP2_Unknown, QMTC2, CTC2, COP2_Unknown, + COP2_BC2, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, + COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, +}; + +void (*Int_COP2BC2PrintTable[32])() = { + BC2F, BC2T, BC2FL, BC2TL, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, +}; + +void (*Int_COP2SPECIAL1PrintTable[64])() = +{ + VADDx, VADDy, VADDz, VADDw, VSUBx, VSUBy, VSUBz, VSUBw, + VMADDx, VMADDy, VMADDz, VMADDw, VMSUBx, VMSUBy, VMSUBz, VMSUBw, + VMAXx, VMAXy, VMAXz, VMAXw, VMINIx, VMINIy, VMINIz, VMINIw, + VMULx, VMULy, VMULz, VMULw, VMULq, VMAXi, VMULi, VMINIi, + VADDq, VMADDq, VADDi, VMADDi, VSUBq, VMSUBq, VSUBi, VMSUBi, + VADD, VMADD, VMUL, VMAX, VSUB, VMSUB, VOPMSUB, VMINI, + VIADD, VISUB, VIADDI, COP2_Unknown,VIAND, VIOR, COP2_Unknown, COP2_Unknown, + VCALLMS, VCALLMSR, COP2_Unknown,COP2_Unknown,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2, +}; + +void (*Int_COP2SPECIAL2PrintTable[128])() = +{ + VADDAx ,VADDAy ,VADDAz ,VADDAw ,VSUBAx ,VSUBAy ,VSUBAz ,VSUBAw, + VMADDAx ,VMADDAy ,VMADDAz ,VMADDAw ,VMSUBAx ,VMSUBAy ,VMSUBAz ,VMSUBAw, + VITOF0 ,VITOF4 ,VITOF12 ,VITOF15 ,VFTOI0 ,VFTOI4 ,VFTOI12 ,VFTOI15, + VMULAx ,VMULAy ,VMULAz ,VMULAw ,VMULAq ,VABS ,VMULAi ,VCLIPw, + VADDAq ,VMADDAq ,VADDAi ,VMADDAi ,VSUBAq ,VMSUBAq ,VSUBAi ,VMSUBAi, + VADDA ,VMADDA ,VMULA ,COP2_Unknown,VSUBA ,VMSUBA ,VOPMULA ,VNOP, + VMOVE ,VMR32 ,COP2_Unknown,COP2_Unknown,VLQI ,VSQI ,VLQD ,VSQD, + VDIV ,VSQRT ,VRSQRT ,VWAITQ ,VMTIR ,VMFIR ,VILWR ,VISWR, + VRNEXT ,VRGET ,VRINIT ,VRXOR ,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, +}; diff --git a/pcsx2/InterTables.h b/pcsx2/InterTables.h new file mode 100644 index 0000000000..e6f0ce6060 --- /dev/null +++ b/pcsx2/InterTables.h @@ -0,0 +1,491 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef INTERTABLES_H +#define INTERTABLES_H + +extern void (*Int_OpcodePrintTable[64])(); +extern void (*Int_SpecialPrintTable[64])(); +extern void (*Int_REGIMMPrintTable[32])(); +extern void (*Int_MMIPrintTable[64])(); +extern void (*Int_MMI0PrintTable[32])(); +extern void (*Int_MMI1PrintTable[32])(); +extern void (*Int_MMI2PrintTable[32])(); +extern void (*Int_MMI3PrintTable[32])(); +extern void (*Int_COP0PrintTable[32])(); +extern void (*Int_COP0BC0PrintTable[32])(); +extern void (*Int_COP0C0PrintTable[64])(); +extern void (*Int_COP1PrintTable[32])(); +extern void (*Int_COP1BC1PrintTable[32])(); +extern void (*Int_COP1SPrintTable[64])(); +extern void (*Int_COP1WPrintTable[64])(); +extern void (*Int_COP2PrintTable[32])(); +extern void (*Int_COP2BC2PrintTable[32])(); +extern void (*Int_COP2SPECIAL1PrintTable[64])(); +extern void (*Int_COP2SPECIAL2PrintTable[128])(); + +void SPECIAL(); +void REGIMM(); +void UnknownOpcode(); +void COP0(); +void COP1(); +void COP2(); +void MMI_Unknown(); +void MMI(); +void MMI0(); +void MMI1(); +void MMI2(); +void MMI3(); +void COP0_Unknown(); +void COP0_BC0(); +void COP0_Func(); +void COP1_BC1(); +void COP1_S(); +void COP1_W(); +void COP1_Unknown(); +void COP2_BC2(); +void COP2_SPECIAL(); +void COP2_Unknown(); +void COP2_SPECIAL2(); + +// **********************Standard Opcodes************************** +void J(); +void JAL(); +void BEQ(); +void BNE(); +void BLEZ(); +void BGTZ(); +void ADDI(); +void ADDIU(); +void SLTI(); +void SLTIU(); +void ANDI(); +void ORI(); +void XORI(); +void LUI(); +void BEQL(); +void BNEL(); +void BLEZL(); +void BGTZL(); +void DADDI(); +void DADDIU(); +void LDL(); +void LDR(); +void LB(); +void LH(); +void LWL(); +void LW(); +void LBU(); +void LHU(); +void LWR(); +void LWU(); +void SB(); +void SH(); +void SWL(); +void SW(); +void SDL(); +void SDR(); +void SWR(); +void CACHE(); +void LWC1(); +void PREF(); +void LQC2(); +void LD(); +void SQC2(); +void SD(); +void LQ(); +void SQ(); +void SWC1(); +//***************end of standard opcodes************************* + + +//***************SPECIAL OPCODES********************************** +void SLL(); +void SRL(); +void SRA(); +void SLLV(); +void SRLV(); +void SRAV(); +void JR(); +void JALR(); +void SYSCALL(); +void BREAK(); +void SYNC(); +void MFHI(); +void MTHI(); +void MFLO(); +void MTLO(); +void DSLLV(); +void DSRLV(); +void DSRAV(); +void MULT(); +void MULTU(); +void DIV(); +void DIVU(); +void ADD(); +void ADDU(); +void SUB(); +void SUBU(); +void AND(); +void OR(); +void XOR(); +void NOR(); +void SLT(); +void SLTU(); +void DADD(); +void DADDU(); +void DSUB(); +void DSUBU(); +void TGE(); +void TGEU(); +void TLT(); +void TLTU(); +void TEQ(); +void TNE(); +void DSLL(); +void DSRL(); +void DSRA(); +void DSLL32(); +void DSRL32(); +void DSRA32(); +void MOVZ(); +void MOVN(); +void MFSA(); +void MTSA(); +//******************END OF SPECIAL OPCODES************************** + +//******************REGIMM OPCODES********************************** +void BLTZ(); +void BGEZ(); +void BLTZL(); +void BGEZL(); +void TGEI(); +void TGEIU(); +void TLTI(); +void TLTIU(); +void TEQI(); +void TNEI(); +void BLTZAL(); +void BGEZAL(); +void BLTZALL(); +void BGEZALL(); +void MTSAB(); +void MTSAH(); +//*****************END OF REGIMM OPCODES***************************** +//*****************MMI OPCODES********************************* +void MADD(); +void MADDU(); +void PLZCW(); +void MADD1(); +void MADDU1(); +void MFHI1(); +void MTHI1(); +void MFLO1(); +void MTLO1(); +void MULT1(); +void MULTU1(); +void DIV1(); +void DIVU1(); +void PMFHL(); +void PMTHL(); +void PSLLH(); +void PSRLH(); +void PSRAH(); +void PSLLW(); +void PSRLW(); +void PSRAW(); +//*****************END OF MMI OPCODES************************** +//*************************MMI0 OPCODES************************ + +void PADDW(); +void PSUBW(); +void PCGTW(); +void PMAXW(); +void PADDH(); +void PSUBH(); +void PCGTH(); +void PMAXH(); +void PADDB(); +void PSUBB(); +void PCGTB(); +void PADDSW(); +void PSUBSW(); +void PEXTLW(); +void PPACW(); +void PADDSH(); +void PSUBSH(); +void PEXTLH(); +void PPACH(); +void PADDSB(); +void PSUBSB(); +void PEXTLB(); +void PPACB(); +void PEXT5(); +void PPAC5(); +//***END OF MMI0 OPCODES****************************************** +//**********MMI1 OPCODES************************************** +void PABSW(); +void PCEQW(); +void PMINW(); +void PADSBH(); +void PABSH(); +void PCEQH(); +void PMINH(); +void PCEQB(); +void PADDUW(); +void PSUBUW(); +void PEXTUW(); +void PADDUH(); +void PSUBUH(); +void PEXTUH(); +void PADDUB(); +void PSUBUB(); +void PEXTUB(); +void QFSRV(); +//********END OF MMI1 OPCODES*********************************** +//*********MMI2 OPCODES*************************************** +void PMADDW(); +void PSLLVW(); +void PSRLVW(); +void PMSUBW(); +void PMFHI(); +void PMFLO(); +void PINTH(); +void PMULTW(); +void PDIVW(); +void PCPYLD(); +void PMADDH(); +void PHMADH(); +void PAND(); +void PXOR(); +void PMSUBH(); +void PHMSBH(); +void PEXEH(); +void PREVH(); +void PMULTH(); +void PDIVBW(); +void PEXEW(); +void PROT3W(); +//*****END OF MMI2 OPCODES*********************************** +//*************************MMI3 OPCODES************************ +void PMADDUW(); +void PSRAVW(); +void PMTHI(); +void PMTLO(); +void PINTEH(); +void PMULTUW(); +void PDIVUW(); +void PCPYUD(); +void POR(); +void PNOR(); +void PEXCH(); +void PCPYH(); +void PEXCW(); +//**********************END OF MMI3 OPCODES******************** +//**************************************************************************** +//** COP0 ** +//**************************************************************************** +void MFC0(); +void MTC0(); +void BC0F(); +void BC0T(); +void BC0FL(); +void BC0TL(); +void TLBR(); +void TLBWI(); +void TLBWR(); +void TLBP(); +void ERET(); +void DI(); +void EI(); +//**************************************************************************** +//** END OF COP0 ** +//**************************************************************************** +//**************************************************************************** +//** COP1 - Floating Point Unit (FPU) ** +//**************************************************************************** +void MFC1(); +void CFC1(); +void MTC1(); +void CTC1(); +void BC1F(); +void BC1T(); +void BC1FL(); +void BC1TL(); +void ADD_S(); +void SUB_S(); +void MUL_S(); +void DIV_S(); +void SQRT_S(); +void ABS_S(); +void MOV_S(); +void NEG_S(); +void RSQRT_S(); +void ADDA_S(); +void SUBA_S(); +void MULA_S(); +void MADD_S(); +void MSUB_S(); +void MADDA_S(); +void MSUBA_S(); +void CVT_W(); +void MAX_S(); +void MIN_S(); +void C_F(); +void C_EQ(); +void C_LT(); +void C_LE(); + void CVT_S(); +//**************************************************************************** +//** END OF COP1 ** +//**************************************************************************** +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void QMFC2(); +void CFC2(); +void QMTC2(); +void CTC2(); +void BC2F(); +void BC2T(); +void BC2FL(); +void BC2TL(); +//*****************SPECIAL 1 VUO TABLE******************************* +void VADDx(); +void VADDy(); +void VADDz(); +void VADDw(); +void VSUBx(); +void VSUBy(); +void VSUBz(); +void VSUBw(); +void VMADDx(); +void VMADDy(); +void VMADDz(); +void VMADDw(); +void VMSUBx(); +void VMSUBy(); +void VMSUBz(); +void VMSUBw(); +void VMAXx(); +void VMAXy(); +void VMAXz(); +void VMAXw(); +void VMINIx(); +void VMINIy(); +void VMINIz(); +void VMINIw(); +void VMULx(); +void VMULy(); +void VMULz(); +void VMULw(); +void VMULq(); +void VMAXi(); +void VMULi(); +void VMINIi(); +void VADDq(); +void VMADDq(); +void VADDi(); +void VMADDi(); +void VSUBq(); +void VMSUBq(); +void VSUBi(); +void VMSUBi(); +void VADD(); +void VMADD(); +void VMUL(); +void VMAX(); +void VSUB(); +void VMSUB(); +void VOPMSUB(); +void VMINI(); +void VIADD(); +void VISUB(); +void VIADDI(); +void VIAND(); +void VIOR(); +void VCALLMS(); +void VCALLMSR(); +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void VADDAx(); +void VADDAy(); +void VADDAz(); +void VADDAw(); +void VSUBAx(); +void VSUBAy(); +void VSUBAz(); +void VSUBAw(); +void VMADDAx(); +void VMADDAy(); +void VMADDAz(); +void VMADDAw(); +void VMSUBAx(); +void VMSUBAy(); +void VMSUBAz(); +void VMSUBAw(); +void VITOF0(); +void VITOF4(); +void VITOF12(); +void VITOF15(); +void VFTOI0(); +void VFTOI4(); +void VFTOI12(); +void VFTOI15(); +void VMULAx(); +void VMULAy(); +void VMULAz(); +void VMULAw(); +void VMULAq(); +void VABS(); +void VMULAi(); +void VCLIPw(); +void VADDAq(); +void VMADDAq(); +void VADDAi(); +void VMADDAi(); +void VSUBAq(); +void VMSUBAq(); +void VSUBAi(); +void VMSUBAi(); +void VADDA(); +void VMADDA(); +void VMULA(); +void VSUBA(); +void VMSUBA(); +void VOPMULA(); +void VNOP(); +void VMOVE(); +void VMR32(); +void VLQI(); +void VSQI(); +void VLQD(); +void VSQD(); +void VDIV(); +void VSQRT(); +void VRSQRT(); +void VWAITQ(); +void VMTIR(); +void VMFIR(); +void VILWR(); +void VISWR(); +void VRNEXT(); +void VRGET(); +void VRINIT(); +void VRXOR(); +//************************************END OF SPECIAL2 ************ +#endif diff --git a/pcsx2/Interpreter.c b/pcsx2/Interpreter.c new file mode 100644 index 0000000000..d9c7405fb0 --- /dev/null +++ b/pcsx2/Interpreter.c @@ -0,0 +1,1061 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "Common.h" +#include "R5900.h" +#include "InterTables.h" +#include "VUmicro.h" +#include "ix86/ix86.h" + +#include + +extern u32 maxrecmem; + +char *bios[256]={ +//0x00 + "RFU000_FullReset", "ResetEE", "SetGsCrt", "RFU003", + "Exit", "RFU005", "LoadExecPS2", "ExecPS2", + "RFU008", "RFU009", "AddSbusIntcHandler", "RemoveSbusIntcHandler", + "Interrupt2Iop", "SetVTLBRefillHandler", "SetVCommonHandler", "SetVInterruptHandler", +//0x10 + "AddIntcHandler", "RemoveIntcHandler", "AddDmacHandler", "RemoveDmacHandler", + "_EnableIntc", "_DisableIntc", "_EnableDmac", "_DisableDmac", + "_SetAlarm", "_ReleaseAlarm", "_iEnableIntc", "_iDisableIntc", + "_iEnableDmac", "_iDisableDmac", "_iSetAlarm", "_iReleaseAlarm", +//0x20 + "CreateThread", "DeleteThread", "StartThread", "ExitThread", + "ExitDeleteThread", "TerminateThread", "iTerminateThread", "DisableDispatchThread", + "EnableDispatchThread", "ChangeThreadPriority", "iChangeThreadPriority", "RotateThreadReadyQueue", + "iRotateThreadReadyQueue", "ReleaseWaitThread", "iReleaseWaitThread", "GetThreadId", +//0x30 + "ReferThreadStatus","iReferThreadStatus", "SleepThread", "WakeupThread", + "_iWakeupThread", "CancelWakeupThread", "iCancelWakeupThread", "SuspendThread", + "iSuspendThread", "ResumeThread", "iResumeThread", "JoinThread", + "RFU060", "RFU061", "EndOfHeap", "RFU063", +//0x40 + "CreateSema", "DeleteSema", "SignalSema", "iSignalSema", + "WaitSema", "PollSema", "iPollSema", "ReferSemaStatus", + "iReferSemaStatus", "RFU073", "SetOsdConfigParam", "GetOsdConfigParam", + "GetGsHParam", "GetGsVParam", "SetGsHParam", "SetGsVParam", +//0x50 + "RFU080_CreateEventFlag", "RFU081_DeleteEventFlag", + "RFU082_SetEventFlag", "RFU083_iSetEventFlag", + "RFU084_ClearEventFlag", "RFU085_iClearEventFlag", + "RFU086_WaitEventFlag", "RFU087_PollEventFlag", + "RFU088_iPollEventFlag", "RFU089_ReferEventFlagStatus", + "RFU090_iReferEventFlagStatus", "RFU091_GetEntryAddress", + "EnableIntcHandler_iEnableIntcHandler", + "DisableIntcHandler_iDisableIntcHandler", + "EnableDmacHandler_iEnableDmacHandler", + "DisableDmacHandler_iDisableDmacHandler", +//0x60 + "KSeg0", "EnableCache", "DisableCache", "GetCop0", + "FlushCache", "RFU101", "CpuConfig", "iGetCop0", + "iFlushCache", "RFU105", "iCpuConfig", "sceSifStopDma", + "SetCPUTimerHandler", "SetCPUTimer", "SetOsdConfigParam2", "SetOsdConfigParam2", +//0x70 + "GsGetIMR_iGsGetIMR", "GsGetIMR_iGsPutIMR", "SetPgifHandler", "SetVSyncFlag", + "RFU116", "print", "sceSifDmaStat_isceSifDmaStat", "sceSifSetDma_isceSifSetDma", + "sceSifSetDChain_isceSifSetDChain", "sceSifSetReg", "sceSifGetReg", "ExecOSD", + "Deci2Call", "PSMode", "MachineType", "GetMemorySize", +}; + +extern void (*LT_OpcodePrintTable[64])(); +int branch2 = 0; +static u32 branchPC; + +// These macros are used to assemble the repassembler functions + +#ifdef CPU_LOG +#define debugI() \ + if (Log) { CPU_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); } \ + if (cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1]) SysPrintf("R0 is not zero!!!!\n"); +#else +#define debugI() +#endif + +void execI() { + + cpuRegs.cycle++; + //cpuRegs.CP0.n.Count++; /*count every cycles.*/ + +#ifdef _DEBUG + if (memRead32(cpuRegs.pc, &cpuRegs.code) == -1) return; + debugI(); +#else + cpuRegs.code = *(u32 *)PSM(cpuRegs.pc); +#endif + + + cpuRegs.pc+= 4; +// if((cpuRegs.PERF.n.pccr & 0x80000020) == 0x80000020) cpuRegs.PERF.n.pcr0++; +// if((cpuRegs.PERF.n.pccr & 0x80008000) == 0x80008000) cpuRegs.PERF.n.pcr1++; + + Int_OpcodePrintTable[cpuRegs.code >> 26](); +} + +__inline void doBranch(u32 tar) { + branch2 = cpuRegs.branch = 1; + branchPC = tar; + execI(); + cpuRegs.branch = 0; + cpuRegs.pc = branchPC; + + IntcpuBranchTest(); +} + +void intDoBranch(u32 target) { + doBranch(target); +} + +void intSetBranch() { + branch2 = 1; +} + +void SPECIAL() {Int_SpecialPrintTable[_Funct_]();} +void REGIMM() {Int_REGIMMPrintTable[_Rt_](); } + + +void UnknownOpcode() { +#ifdef CPU_LOG + CPU_LOG("%8.8lx: Unknown opcode called\n", cpuRegs.pc); +#endif +} + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void ADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed!!!! +void ADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed !!! +void DADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im +void DADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im +void ANDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & (s64)_ImmU_; } // Rt = Rs And Im +void ORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | (s64)_ImmU_; } // Rt = Rs Or Im +void XORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ (s64)_ImmU_; } // Rt = Rs Xor Im +void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_); } // Rt = Rs < Im (signed) +void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_); } // Rt = Rs < Im (unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void ADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt (Exception on Integer Overflow) +void ADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt +void DADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } +void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } +void SUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs - Rt (Exception on Integer Overflow) +void SUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0]; } // Rd = Rs - Rt +void DSUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0];} +void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; } +void AND() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs And Rt +void OR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Or Rt +void XOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Xor Rt +void NOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] =~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); }// Rd = Rs Nor Rt +void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]; } // Rd = Rs < Rt (signed) +void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs < Rt (unsigned) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ + +void J() { +#ifdef _DEBUG + u32 temp = _JumpTarget_; + u32 pc = cpuRegs.pc; +#endif + doBranch(_JumpTarget_); +#ifdef _DEBUG + JumpCheckSym(temp, pc); +#endif +} + +void JAL() { +#ifdef _DEBUG + u32 temp = _JumpTarget_; + u32 pc = cpuRegs.pc; +#endif + _SetLink(31); doBranch(_JumpTarget_); +#ifdef _DEBUG + JumpCheckSym(temp, pc); +#endif +} + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void JR() { +#ifdef _DEBUG + u32 temp = cpuRegs.GPR.r[_Rs_].UL[0]; + u32 pc = cpuRegs.pc; + int rs = _Rs_; +#endif + doBranch(cpuRegs.GPR.r[_Rs_].UL[0]); +#ifdef _DEBUG + JumpCheckSym(temp, pc); + if (rs == 31) JumpCheckSymRet(pc); +#endif +} + +void JALR() { + u32 temp = cpuRegs.GPR.r[_Rs_].UL[0]; +#ifdef _DEBUG + u32 pc = cpuRegs.pc; +#endif + + if (_Rd_) { _SetLink(_Rd_); } + doBranch(temp); +#ifdef _DEBUG + JumpCheckSym(temp, pc); +#endif +} + + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void DIV() { + if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { + cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; + cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; + } +} + +void DIVU() { + if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { + cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; + cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; + } +} + +void MULT() { //different in ps2... + s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; + + cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); + cpuRegs.HI.UD[0] = (s32)(res >> 32); + + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference +} + +void MULTU() { //different in ps2.. + u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; + + cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); + cpuRegs.HI.UD[0] = (s32)(res >> 32); + + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference +} + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void LUI() { + if (!_Rt_) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); +} + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void MFHI() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; } // Rd = Hi +void MFLO() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void MTHI() { cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Hi = Rs +void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs + + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa +void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); } +void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));} +void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic) +void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_); } +void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32));} +void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical) +void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_); } +void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32));} + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void SLLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt << rs +void SRAV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (arithmetic) +void SRLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (logical) +void DSLLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} +void DSRAV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} +void DSRLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) \ + if (cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) doBranch(_BranchTarget_); \ + else IntcpuBranchTest(); + + +void BEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void BNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else IntcpuBranchTest(); + +#define RepZBranchLinki32(op) \ + _SetLink(31); \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else IntcpuBranchTest(); + +void BGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void BGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void BGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void BLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void BLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void BLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32Likely(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; IntcpuBranchTest(); } + +#define RepZBranchLinki32Likely(op) \ + _SetLink(31); \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; IntcpuBranchTest(); } + +#define RepBranchi32Likely(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; IntcpuBranchTest(); } + + +void BEQL() { RepBranchi32Likely(==) } // Branch if Rs == Rt +void BNEL() { RepBranchi32Likely(!=) } // Branch if Rs != Rt +void BLEZL() { RepZBranchi32Likely(<=) } // Branch if Rs <= 0 +void BGTZL() { RepZBranchi32Likely(>) } // Branch if Rs > 0 +void BLTZL() { RepZBranchi32Likely(<) } // Branch if Rs < 0 +void BGEZL() { RepZBranchi32Likely(>=) } // Branch if Rs >= 0 +void BLTZALL() { RepZBranchLinki32Likely(<) } // Branch if Rs < 0 and link +void BGEZALL() { RepZBranchLinki32Likely(>=) } // Branch if Rs >= 0 and link + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +void LB() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead8RS(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead8RS(addr, &dummy); + } +} + +void LBU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead8RU(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead8RU(addr, &dummy); + } +} + +void LH() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead16RS(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead16RS(addr, &dummy); + } +} + +void LHU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead16RU(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead16RU(addr, &dummy); + } +} + +void LW() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead32RS(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead32RS(addr, &dummy); + } +} + +void LWU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead32RU(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead32RU(addr, &dummy); + } +} + +u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; +u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void LWL() { + s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (!_Rt_) return; + if (memRead32(addr & ~3, &mem) == -1) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWL_MASK[shift]) | + (mem << LWL_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + */ +} + +u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; +u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void LWR() { + s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (!_Rt_) return; + if (memRead32(addr & ~3, &mem) == -1) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | + (mem >> LWR_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + */ +} + +void LD() { + s32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead64(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead64(addr, &dummy); + } +} + +u64 LDL_MASK[8] = { 0x00ffffffffffffffLL, 0x0000ffffffffffffLL, 0x000000ffffffffffLL, 0x00000000ffffffffLL, + 0x0000000000ffffffLL, 0x000000000000ffffLL, 0x00000000000000ffLL, 0x0000000000000000LL }; +u32 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; + +void LDL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (!_Rt_) return; + if (memRead64(addr & ~7, &mem) == -1) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) | + (mem << LDL_SHIFT[shift]); +} + +u64 LDR_MASK[8] = { 0x0000000000000000LL, 0xff00000000000000LL, 0xffff000000000000LL, 0xffffff0000000000LL, + 0xffffffff00000000LL, 0xffffffffff000000LL, 0xffffffffffff0000LL, 0xffffffffffffff00LL }; +u32 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; + +void LDR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (!_Rt_) return; + if (memRead64(addr & ~7, &mem) == -1) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) | + (mem >> LDR_SHIFT[shift]); +} + +void LQ() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + addr&=~0xf; + + if (_Rt_) { + memRead128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 val[2]; + memRead128(addr, val); + } +} + +void SB() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]); +} + +void SH() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]); +} + +void SW(){ + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]); +} + +u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0x00000000 }; +u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void SWL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (memRead32(addr & ~3, &mem) == -1) return; + + memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) | + ( mem & SWL_MASK[shift]) ); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + */ +} + +u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; +u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void SWR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (memRead32(addr & ~3, &mem) == -1) return; + + memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) | + ( mem & SWR_MASK[shift]) ); + + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + */ +} + +void SD() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite64(addr,cpuRegs.GPR.r[_Rt_].UD[0]); +} + +u64 SDL_MASK[8] = { 0xffffffffffffff00LL, 0xffffffffffff0000LL, 0xffffffffff000000LL, 0xffffffff00000000LL, + 0xffffff0000000000LL, 0xffff000000000000LL, 0xff00000000000000LL, 0x0000000000000000LL }; +u32 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; + +void SDL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (memRead64(addr & ~7, &mem) == -1) return; + + memWrite64(addr & ~7, (cpuRegs.GPR.r[_Rt_].UD[0] >> SDL_SHIFT[shift]) | + ( mem & SDL_MASK[shift]) ); +} + +u64 SDR_MASK[8] = { 0x0000000000000000LL, 0x00000000000000ffLL, 0x000000000000ffffLL, 0x0000000000ffffffLL, + 0x00000000ffffffffLL, 0x000000ffffffffffLL, 0x0000ffffffffffffLL, 0x00ffffffffffffffLL }; +u32 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; + +void SDR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (memRead64(addr & ~7, &mem) == -1) return; + + memWrite64(addr & ~7, (cpuRegs.GPR.r[_Rt_].UD[0] << SDR_SHIFT[shift]) | + ( mem & SDR_MASK[shift]) ); +} + +void SQ() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + addr&=~0xf; + memWrite128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); +} + +/********************************************************* +* Conditional Move * +* Format: OP rd, rs, rt * +*********************************************************/ + +void MOVZ() { + if (!_Rd_) return; + if (cpuRegs.GPR.r[_Rt_].UD[0] == 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + } +} +void MOVN() { + if (!_Rd_) return; + if (cpuRegs.GPR.r[_Rt_].UD[0] != 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + } +} + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ + +#include "Sifcmd.h" +/* +int __Deci2Call(int call, u32 *addr); +*/ +u32 *deci2addr = NULL; +u32 deci2handler; +char deci2buffer[256]; + +/* + * int Deci2Call(int, u_int *); + */ + +int __Deci2Call(int call, u32 *addr) { + if (call > 0x10) { + return -1; + } + + switch (call) { + case 1: // open + + deci2addr = (u32*)PSM(addr[1]); +#ifdef BIOS_LOG + BIOS_LOG("deci2open: %x,%x,%x,%x\n", + addr[3], addr[2], addr[1], addr[0]); +#endif + deci2handler = addr[2]; + + return 1; + + case 2: // close + return 1; + + case 3: // reqsend + +#ifdef BIOS_LOG + BIOS_LOG("deci2reqsend: %x,%x,%x,%x: deci2addr: %x,%x,%x,buf=%x %x,%x,len=%x,%x\n", + addr[3], addr[2], addr[1], addr[0], + deci2addr[7], deci2addr[6], deci2addr[5], deci2addr[4], + deci2addr[3], deci2addr[2], deci2addr[1], deci2addr[0]); +#endif +// cpuRegs.pc = deci2handler; +// SysPrintf("deci2msg: %s", (char*)PSM(deci2addr[4]+0xc)); + if (deci2addr == NULL) return 1; + if (deci2addr[1]>0xc){ + u8* pdeciaddr = (u8*)dmaGetAddr(deci2addr[4]+0xc); + if( pdeciaddr == NULL ) pdeciaddr = (u8*)PSM(deci2addr[4]+0xc); + else pdeciaddr += (deci2addr[4]+0xc)%16; + memcpy(deci2buffer, pdeciaddr, deci2addr[1]-0xc); + deci2buffer[deci2addr[1]-0xc>=255?255:deci2addr[1]-0xc]='\0'; + SysPrintf(deci2buffer); + } + deci2addr[3] = 0; + return 1; + + case 4: // poll +#ifdef BIOS_LOG + BIOS_LOG("deci2poll: %x,%x,%x,%x\n", + addr[3], addr[2], addr[1], addr[0]); +#endif + return 1; + + case 5: // exrecv + return 1; + + case 6: // exsend + return 1; + + case 0x10://kputs + SysPrintf("%s", PSM(*addr)); + return 1; + } + + return 0; +} + + +void SYSCALL() { +#ifdef BIOS_LOG + u8 call; + + if (cpuRegs.GPR.n.v1.SL[0] < 0) + call = (u8)(-cpuRegs.GPR.n.v1.SL[0]); + else call = cpuRegs.GPR.n.v1.UC[0]; + BIOS_LOG("Bios call: %s (%x)\n", bios[call], call); + if (call == 0x7c && cpuRegs.GPR.n.a0.UL[0] == 0x10) { + SysPrintf("%s", PSM(PSMu32(cpuRegs.GPR.n.a1.UL[0]))); + } else + //if (call == 0x7c) SysPrintf("Deci2Call: %x\n", cpuRegs.GPR.n.a0.UL[0]); + if (call == 0x7c) __Deci2Call(cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0])); + if (call == 0x77) { + struct t_sif_dma_transfer *dmat; +// struct t_sif_cmd_header *hdr; +// struct t_sif_rpc_bind *bind; +// struct t_rpc_server_data *server; + int n_transfer; + u32 addr; +// int sid; + + n_transfer = cpuRegs.GPR.n.a1.UL[0] - 1; + if (n_transfer >= 0) { + addr = cpuRegs.GPR.n.a0.UL[0] + n_transfer * sizeof(struct t_sif_dma_transfer); + dmat = (struct t_sif_dma_transfer*)PSM(addr); + +#ifdef BIOS_LOG + BIOS_LOG("bios_%s: n_transfer=%d, size=%x, attr=%x, dest=%x, src=%x\n", + bios[cpuRegs.GPR.n.v1.UC[0]], n_transfer, + dmat->size, dmat->attr, + dmat->dest, dmat->src); +#endif + } +//Log=1; + } +#endif +// if (cpuRegs.GPR.n.v1.UD[0] == 0x77) Log=1; + cpuRegs.pc -= 4; + cpuException(0x20, cpuRegs.branch); +} + +void BREAK(void) { + cpuRegs.pc -= 4; + cpuException(0x24, cpuRegs.branch); +} + +void MFSA( void ) { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].SD[0] = (s64)cpuRegs.sa; +} + +void MTSA( void ) { + cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0]; +} + +void SYNC( void ) +{ +} + +void PREF( void ) +{ +} + + + +/********************************************************* +* Register trap * +* Format: OP rs, rt * +*********************************************************/ + +void TGE() { + if (cpuRegs.GPR.r[_Rs_].SD[0]>= cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TGEU() { + if (cpuRegs.GPR.r[_Rs_].UD[0]>= cpuRegs.GPR.r[_Rt_].UD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TLT() { + if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TLTU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TEQ() { + if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TNE() { + if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +/********************************************************* +* Trap with immediate operand * +* Format: OP rs, rt * +*********************************************************/ + +void TGEI() { + + if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TGEIU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] >= _ImmU_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TLTI() { + if(cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TLTIU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] < _ImmU_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TEQI() { + if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +void TNEI() { + if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } +} + +/********************************************************* +* Sa intructions * +* Format: OP rs, rt * +*********************************************************/ + +void MTSAB() { + cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3; +} + +void MTSAH() { + cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4; +} + + + +/////////////////////////////////////////// + +int intInit() { + //detect cpu for use the optimaze asm code + return 0; +} + +void intReset() { + cpuRegs.branch = 0; + branch2 = 0; +} + +void intExecute() { + for (;;) execI(); +} + +static void intExecuteBlock() { + branch2 = 0; + while (!branch2) execI(); +} + + +extern void iDumpVU0Registers(); +extern void iDumpVU1Registers(); +extern u32 vudump; +extern int vu0branch, vu1branch; + +void intExecuteVU0Block() { +int i; + +#ifdef _DEBUG + int prevbranch; +#endif + + for (i = 128; i--;) { + + if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) + break; + +#ifdef _DEBUG + prevbranch = vu0branch; +#endif + vu0Exec(&VU0); +#ifdef _DEBUG + if( (vudump&0x80) && prevbranch == 1 ) { + __Log("tVU: %x\n", VU0.VI[ REG_TPC ].UL); + iDumpVU0Registers(); + } +#endif + } + + if( i < 0 && (VU0.branch || VU0.ebit) ) { + // execute one more + vu0Exec(&VU0); + } +} + +void intExecuteVU1Block() { + + int i; +#ifdef _DEBUG + int prevbranch; +#endif + + for (i = 128; i--;) { + if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) + break; + +#ifdef _DEBUG + prevbranch = vu1branch; +#endif + vu1Exec(&VU1); +#ifdef _DEBUG + if( (vudump&8) && prevbranch == 1 ) { + __Log("tVU: %x\n", VU1.VI[ REG_TPC ].UL); + iDumpVU1Registers(); + } +#endif + } + + if( i < 0 && (VU1.branch || VU1.ebit) ) { + // execute one more + vu1Exec(&VU1); + } +} + + +void intEnableVU0micro(int enable) { +} + +void intEnableVU1micro(int enable) { +} + +void intStep() { + execI(); +} + +void intClear(u32 Addr, u32 Size) { +} + +void intVU0Clear(u32 Addr, u32 Size) { +} + +void intVU1Clear(u32 Addr, u32 Size) { +} + +void intShutdown() { +} + +R5900cpu intCpu = { + intInit, + intReset, + intStep, + intExecute, + intExecuteBlock, + intExecuteVU0Block, + intExecuteVU1Block, + intEnableVU0micro, + intEnableVU1micro, + intClear, + intVU0Clear, + intVU1Clear, + intShutdown +}; + diff --git a/pcsx2/Linux/.pixmaps/pcsxAbout.xpm b/pcsx2/Linux/.pixmaps/pcsxAbout.xpm new file mode 100644 index 0000000000..2ebc445d15 --- /dev/null +++ b/pcsx2/Linux/.pixmaps/pcsxAbout.xpm @@ -0,0 +1,334 @@ +/* XPM */ +static char *pcsxAbout[] = { +/* columns rows colors chars-per-pixel */ +"314 176 152 2", +" c #252d42", +". c #282e45", +"X c #282f48", +"o c #273046", +"O c #283046", +"+ c #2a334b", +"@ c #2d3650", +"# c #2e3853", +"$ c #303651", +"% c #303955", +"& c #333d5b", +"* c #383f57", +"= c #383e5d", +"- c #35405e", +"; c #39415d", +": c #364161", +"> c #384465", +", c #3a4668", +"< c #3e4866", +"1 c #3c496c", +"2 c #3e4b70", +"3 c #40475b", +"4 c #41485d", +"5 c #404767", +"6 c #424a63", +"7 c #434c6c", +"8 c #484f61", +"9 c #464e70", +"0 c #44506f", +"q c #4c5263", +"w c #465071", +"e c #495273", +"r c #4d5679", +"t c #4e5974", +"y c #4e587b", +"u c #515665", +"i c #535866", +"p c #545968", +"a c #595d69", +"s c #50577b", +"d c #505a75", +"f c #51597d", +"g c #5c606a", +"h c #55617f", +"j c #5a637b", +"k c #64666d", +"l c #65686e", +"z c #666870", +"x c #6b6d71", +"c c #6e7073", +"v c #767676", +"b c #545d81", +"n c #566085", +"m c #586185", +"M c #5b648a", +"N c #5e6883", +"B c #5e688d", +"V c #666d84", +"C c #606a8b", +"Z c #686f86", +"A c #626b93", +"S c #656f98", +"D c #687085", +"F c #6a738c", +"G c #667097", +"H c #667098", +"J c #6d7691", +"K c #6b749d", +"L c #6e7893", +"P c #72788c", +"I c #757d93", +"U c #6d76a0", +"Y c #6e78a1", +"T c #717ba4", +"R c #747ea8", +"E c #7c8397", +"W c #79829a", +"Q c #7680ab", +"! c #7a84ae", +"~ c #7c85b1", +"^ c #7e88b3", +"/ c #808080", +"( c #80838f", +") c #888888", +"_ c #808799", +"` c #82899d", +"' c gray57", +"] c gray60", +"[ c #858da3", +"{ c #858eba", +"} c #8d93a5", +"| c #8f95a8", +" . c #8690bc", +".. c #8891bd", +"X. c #9096a9", +"o. c #999ead", +"O. c #9aa0af", +"+. c #9ca2b4", +"@. c #a2a2a2", +"#. c #aaaaaa", +"$. c #a5a9b6", +"%. c #a7acba", +"&. c #a8adbc", +"*. c #aab0bf", +"=. c #bababa", +"-. c #8e96c3", +";. c #8e98c4", +":. c #9099c6", +">. c #959dca", +",. c #96a0cc", +"<. c #98a0cd", +"1. c #9ca5d1", +"2. c #a4add9", +"3. c #aab0c0", +"4. c #b3b6c2", +"5. c #b4b8c4", +"6. c #b6bbc8", +"7. c #adb5e1", +"8. c #b0b7e3", +"9. c #b0b8e3", +"0. c #bec2cb", +"q. c #bfc7ef", +"w. c #bfc7f0", +"e. c #c2c2c2", +"r. c #c0c3cd", +"t. c gray80", +"y. c #c2c6d1", +"u. c #ccced6", +"i. c #cdd0d7", +"p. c #ced1d9", +"a. c #d0d2d7", +"s. c #d4d5d9", +"d. c #dddddd", +"f. c #c0c7f0", +"g. c #c3cbf2", +"h. c #c8cef4", +"j. c #cad0f5", +"k. c #d9dbe1", +"l. c #d2d8f6", +"z. c #dbdff8", +"x. c #dce0f8", +"c. c gray90", +"v. c #e5e7eb", +"b. c #e6e8ec", +"n. c #eeeeee", +"m. c #e1e5f9", +"M. c #ebeefb", +"N. c #eff1fc", +"B. c #f2f3f5", +"V. c #f0f1fc", +"C. c #f7f8fd", +"Z. c #fefefe", +/* pixels */ +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 1 1 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 2 , , , 1 , 1 , 1 1 , , , , 1 , , , , 1 , , , , , , > , > > , > , , : , , : , : , : , : > > > > : > > , : : : : > : : > : : : : : : : - : : - : - - : - - - - - - & - - & - - & & & & & & : & & & & & & & & & & & & & # # # # # & & # & # & # # & # # # # # # & # # & # # # # # # # # # # # @ # @ @ # @ @ @ @ @ @ @ @ @ X @ @ + @ @ + @ + @ + @ + + @ + + @ + + @ + + + + + + + + + + + + + + o + + o + + + o + X o X X + o o O O O O O X X O . . . . . . . . . o o . . . . o . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 2 1 1 2 2 1 2 1 2 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 , 1 , , , , 2 1 , 1 , , , , , 1 , , , , , , , , , , , , > , , , > , > : , , : : , , : , : , : > > , : : > > : : : , : : : : > : : : : : : : : : - : - - - : - - - - - - & - - & - - & : & : & : & & & & & & & & & # & & # & & & & & : & # # & # & # & & # # & & # & # # # # # # # # # # # # # # @ # @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ + @ + @ @ + + @ + + + + + + + + + + + + + + + o X + + o o + o + o + X X + + + o X o X X O O O O o o O X O . . . o o . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 2 2 1 2 1 1 1 1 1 2 1 1 1 1 1 1 1 , 2 , 1 1 1 , 1 1 1 1 , , 1 , 1 1 , 1 1 , 1 , 1 , , , , , , , , , , , > , , > , , > , , , : , : : , : , > : , > > : : > > : > : : > : : : : : > - : : - : - - : : : - : - - - - - & - & & - & - & & & & & & & & & & & & & & & & & # & # : # # # & & & & & # & # # & & # & # # # # # # # # & # # % # @ # # @ # # @ % @ @ @ @ @ @ @ @ @ @ @ @ X @ @ + @ @ @ + @ + @ + + + + + + + + + + + + + + + + o + + + + X + o + + o + o o @ + X + X o o o X + X O O O O X X . . . o o . . o . . . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 1 2 1 2 1 1 2 1 1 1 1 1 1 2 , 2 2 1 1 1 1 , , 1 1 1 , 1 , , 1 , , , , , , , , , , , , , , > , , > , > , > , > : , , > , , , : , : > > : > > > : > : > : : > : : : : : : : : - : : - : : - - - - - - - - - - - - - - - - & : & & : & & & & & & & & & # & & & & & & & # & : # & # # & # # & # # & # # # & & & # # & # # # # # # # # # # @ # @ @ # @ % @ @ @ @ @ @ @ @ @ @ @ + @ + + @ + + @ + + @ + + @ + + + @ + + + + + + + X + + + + + X + o + + o + o o X X X o o + o X O O O O X O O O O . . . o . o . . o . . . . ", +"2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 1 2 1 1 1 2 1 2 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 2 , 1 , 1 1 , 1 1 , , , , , , , , , , , , , , , , , , , > , , > , : , : : : , : , > : , , : , : > > , : > : : , : , : : : : > : : : : : : : : - - - - - - - - - : & & - - - & & & : & & & & & & & & & & & & & & & & : # # & & # # & # & # & # & & # # & # # # # & # # & # # # # @ # % % # # # # @ # @ @ @ @ @ @ X @ @ @ @ @ @ @ + @ @ @ + @ @ + @ + + @ + + @ + + + + + + + + + + + + + + + + + + o o @ X o + o + o + o + + X X O O + O O O . . O . . . o o o o o . o o . . . . ", +"9 2 2 2 w 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 1 2 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 , 1 , 1 , 1 , , , 1 1 1 , 1 , , , , , , , , , , , , > , > > , , , > , , , : , : , , : : , : > > : : : , : : : : : : > : : : : : : - : : : - : : - - - - - - - & - : - & - & - & & & & & & & & & & & & & & & # & : # # # : # & & # & # & # & # # & # & # & # & # # # # # # # # % # @ # # # @ # # @ # @ @ @ @ @ # @ @ @ @ X @ @ @ + + @ @ @ + + + + + @ + @ + + + @ + + + + + + + X + X + o + o X + + o o + o o o + o o o o o o O O O O O O O . . O . o . o . . o . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 2 2 2 1 1 2 1 2 1 1 2 1 1 1 1 1 1 1 , 1 1 , 1 1 1 , , 1 1 , 1 , 1 , 1 , , 1 , , , , , , , , , : , > , , , , > , > > , , , : , , : , : : > , : , : > > : , : : : > : : : : : : : : : : : : - : - : : : - - : - - - : & & - & - - - & : & & : & & & & & & & & & & & # & : & & : # : & & # & # & # & # & # # # # # # # # # # # # # # # # # # # @ @ # @ @ # @ # @ @ @ # @ @ @ @ @ X @ @ @ + + + @ + @ @ + @ + + + + + + @ + + + + + + + + + o + o + X + o + + + X o + + o o + o o + o O O O O O O . . O . o . . o . . . o . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 1 1 1 , 1 , 1 , 1 , 1 , , , 1 , , , , , , , , , , , > , > , > , , > : , , > > , , : , > > > : > : > : : > : > : : > : : : : : : : : - : : - : - - - - - - - - - & : - - & - & & & : & & & & & : & & & & & & & & & & # # & # # & # & & # & # # & & # & # & # & # # & & # # # # & # # # # # # # # @ # @ # @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ @ + + @ + @ + + + @ + @ + + + + + + + + + + + + + + X + X + o + o @ + o o + o o + o X + O O O O O O O O o o . . o o . . . o . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 1 2 2 1 2 1 2 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 2 , , , , , 1 , , 1 , , , , , , , , , , , , , , > , , > , , , , , , : , , : , , : > > , > > > > , : : , : : , : > : : : : : : > : : : - : - - : - - - - - - - - - : & & & & : & & : & & & & & & & & & & & & & # & # & # & # & & & # & # & # & # & # # & & # % # # & # # % @ & & @ & @ @ @ # @ @ # # @ @ @ @ @ @ @ @ # @ @ @ @ @ + @ + + @ @ + @ + @ @ + + @ + @ + + + + + + + + + + + o + + o + o + + + O + + O + + + X X o o o O O O O O X X O O O O O O . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , , , 2 2 , 2 , , , , , , 1 , , , , , , , , , , , , , , , > , : , : , : , : , , : , > > : > : : > : : , : , : : : : > : : : : : : : : : : - : - : - - : - - - - - : & & : : & & : & & : & & & & & & & & & & & & & & & & & & & & # & # # & # & # & # & # # # % % # # # # # % @ @ @ @ @ % @ # # @ # @ # @ # # @ # @ X @ # X X # @ @ @ @ @ @ @ + + + @ + + + + + + + + + + + + + + + o + + + + o + + X + O O + + o O o X X X + o O X X X O O O O X . o O O O X o O . . o o o o o ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 1 2 1 2 1 1 2 1 2 2 2 1 1 2 2 1 2 1 1 1 1 , 1 1 1 1 , 1 1 1 , , 2 , 2 , 1 1 1 , 2 , , 1 , , , , , , , , , , , , , > , : : , , , : , , : : , > > : , : : : , , : : : , : > : , : , : : : : : - : : - : - : - - - - - - - & & : & : & & & & & & & : & & & & & & & & & & & & # & # & & & # & & # # & # # & & # # & # & # & # # # & & @ @ @ % @ @ % # @ @ @ # @ # @ @ @ # @ # X # # @ @ X @ @ @ @ @ + @ + @ + + @ + @ + + + + + + + + + + + + + + + X + X + + + o + o X o + X X X + o + + o O + O O O O O O X o o O O o . . . . o . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 2 , 1 , , , , , , , , , , , 1 , , , , , , , , , > , , > , , , , : , , , : , , > , : , : , , : : : : , : : : : : : : : : : : : : : - : : - : - : - - - - - - : : : & & : & : & : & & & & & & # & & & & & & & & & & & & # & & # & & & # & & # # & & # # # # # & # # # @ @ & @ @ % # @ # # # @ @ # @ @ @ @ @ @ # # # @ @ @ @ @ + @ + + @ + + @ + @ + @ + + + @ + + + @ + + + + + + + + + + + + O + + + O + + X + o X X O O o o O O O O O O X X O X O O O o . . o . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 1 2 1 2 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , , 1 , , 1 , 2 1 , , , , , 1 , , , , , > , , , , , , > , : , , , , : , , : : , > > , : , : : > , : , : : : : : : : , : : : : : : : : : : : : - - - - - - - - & : & : & - & & & : & : & & & & & & & & & & & & & & & & # # & # & # & # & & & & # # # & # % & # & # # # # & # # & & @ % @ @ % @ @ @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ + @ @ + @ @ + + @ + + + + + + + + + + + X + + + o + + X + + O + X + X + + O + O O O O O O O O O O O O . X O O o . o O . . o . o o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 1 2 2 1 2 1 1 1 2 1 1 2 1 1 1 2 1 1 1 1 1 1 1 , 1 1 1 1 2 1 , 1 , 1 1 , , , 1 1 , , , , , , , , , , , , , > , , , , , : , : , : , , , : > > : , : , > > : > > : , : , : : : : : : : : : : : : : : : - : : - : - - - - - & : & & & : : & & & & & & & & : & & & & & & # & # & & & & & # & & & & # # # # & & # & # # # # # # # # # # # @ @ % @ @ @ @ @ & @ @ # # @ @ @ @ @ @ @ @ @ X @ X @ @ + + @ @ + @ @ + + @ + + + + + + + + + + + + + + + + + + + + + O + + o X + + o O O O O O + O O O O O O O o O . O O . . O . . . . o . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 1 2 2 2 1 2 2 2 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 , , , , , , , , , , , , , , , : , : , , : , , : , , : , , > > , : > , : : : > > : , : , : : : : : : : : : : : : : : : - - : : - - - - - - : : & : : : & & : & & & : & & & # & & & & & & # & & & & & # & # & # # & & # & # & # # & # & # # & # # # # # # & @ @ @ % # # # # # @ @ @ @ @ @ @ @ @ @ @ X @ @ @ @ @ @ + + @ + + @ + + @ @ + + + + + + + + + + + o + + + o + + o o + + o O + + O + X O + O O O O O O O O O X O o O O O X o . . . . . o . . . o ", +"e 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 1 1 2 1 1 1 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 1 , 1 1 , , , , 1 , , 1 , , , , , , , , > , , , , , , , : , , , : , : , > > : > , : : , , : > > : : : : : , > : : : : : : : : : : : : : - - - - - - - - : & & - & & : & & & : & & & & & & & & & & & & & & & & # & & & & & # & & # & # & # & # # # & % & # # & # # # # # @ & % @ # @ @ # # @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ @ + + @ + + + @ + + @ + + + + + + + + + + o + + X + + + + X X + X X + O O O + + O O O O O O O . X O . . . . . o . . o . . . . . . ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 1 2 1 1 2 2 1 2 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 , , , , , , , , , , , , , , , , : : , , : > > > > > , > > > : : , : > : : > : > : > : : : : : : : - : - - - - - - - - - & - - : & & & & : - & & : & & & & : & & & & & & # & & & # & & & # & # & # & # & # & & # # # & # % % % % % % % % @ # # # # # @ @ @ # # @ @ # @ @ @ @ @ @ @ @ @ @ X @ @ @ @ @ @ @ X X @ + + @ + + @ + + + + + + + + + + + O + + + o + o + + O + O O O + O + X O O + O + X O X o O . . . . o o . . . . o . O O O O ", +"2 2 2 2 2 2 2 e 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 1 1 1 1 2 1 1 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 , 1 1 , 1 1 , 1 1 1 1 1 , , 1 1 , , 1 , , , , , , , , , : , , , , : , , : , , , , : , > > > > : : > : , : > : : : , : : > : : : : : : : : - : : : - : : : - : - - - - - - & : : : & & - - & & : & & & & & & & & & & & & & & & & # & & & # % & # & # & # # # & # & # # % % % @ % @ % % @ % @ # # @ % # @ @ # @ @ @ @ @ @ @ X @ @ @ @ @ @ @ X @ X @ X @ @ + @ + + + + + + + + + + + + + + + + + O X + + o + X o O O O + O O O O O O X X O O O O O O . . . o . . . . o o . o . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 1 2 1 1 2 1 2 2 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , , , , , 1 , , , 1 , , , , , , , , , , : , : : , : , : , , : , : > > > > > > > > > > : > : : : : : : : : : > : : : : : : - : : - - - : - - - - - & : & & & : : & & - - & & & & - & & # : & & & & & & & & & # # & & & & # & # & # # & & # % # # # @ % % % @ % % @ % # # # @ % # # @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ X @ @ @ @ @ @ @ + @ @ + @ + + + + + + + + + + + + O + + + + O + O O + + O + o + O + O + O o O + O O O O O O O X . . . o . . O O . o O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 1 , , 2 , , 1 , , 1 , 1 , , > 1 , , , , , , , , , , , , , , , , , , > , : , , , : > > > > > > > : : : , : > , : > > : > : : : : : : : : : : : - : : - - - - : - - - - : & : & & & - & & & & & & & & & & & # : # & # & & & & & & # # & % & & # # & % # & # # & % & % % % @ % % % # # # # # @ # @ # # @ @ # @ # @ @ @ @ @ @ @ @ X @ @ @ X @ @ @ X @ + @ + + + + + @ @ + + + X + + + + + + + O + + + + + o + + o + X + O O O O O X O O O O O X X . . . . o . X O o . . o O . O O O ", +"2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 1 2 2 1 1 2 2 2 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 , , 2 , 1 , 1 , , 1 , 1 , 1 , , , , , , , , , > , , , : , : , , : , > , : , > , , , > > > > > > > > : > > : : > : > : > : : : : : : > - : > - : : - - : - - - - - - - & - & & & : & & & & - & & & & & & & & & # & & & & & # & & & # # & & & & # # # % % & % # % # # % # @ % % # # % % @ % @ # # # $ # @ # @ @ @ @ @ @ @ @ @ @ # @ @ + @ @ @ X @ X @ @ + @ @ + + + + + + + + + + + + + + X + + + O O + O O + O O + o O + O + O O O O + X O O O O O . o . . . . o . O O . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 2 1 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 , 1 1 1 , , , , , , 1 , , , , , , , , , , , , , , > , , , , > , > > > , : > > > > : > > > > > : > > : : : : > : > : : > : - - : - : - - : : - - - - - - - - - - : : & & : & - - & - & - & & & & & & : & & & # & & # & & & & # # # # & & & & % % % % % % # % % @ % % # % @ # # @ % # # @ # @ # @ @ # @ @ @ @ @ @ @ @ X @ @ @ @ + @ @ @ @ @ + + + + @ @ + + + + + + + + + + + + + + + + + + + + + + O + o + + O O O O + O O O O X O o O O . o O . o . . o O O O O O . O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 2 1 1 1 2 1 2 2 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , 1 1 1 , 1 , 1 1 , 1 , , , , , , , , , , , , , , , , , , : , , , , : , > > > > > > > > > > : > > > > : > : , : : : : > : : : : - > > - - - : - - : : - - - - - & : & : : & & : : & & & & & & & & & & & # & & # & & & & & & # & & & & # & # & # % % % % # # % & # % % % # # # # @ % # # # # # @ @ # # @ # @ @ @ @ @ # X @ @ @ @ @ @ @ X + @ X @ + @ @ + + + + + + + + + + + + + o + O + + O + O O + O O + + o o O + O O O + + O O O O O O X O . o . o o . . . . O O O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 1 1 2 2 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 , , , , , , , , , , , , , : , , , : , : , : , , > > > > > > > > > > : : > > > : > : : > : : : : > : : > - - - - : - : : - - : - - - - : & : & & & : & & & - & & & : & & & & & & & & & & # & & # & # & & # & # & & # & % % % % & # % # % # % % % % # # % @ % @ $ # # @ # @ @ # @ @ @ @ @ @ @ @ @ @ X @ @ X @ + @ @ X @ + @ + + @ + @ + + + @ + + + + + + + + + + O + + + O + O + o X + O X + O O O O O O O O O O O . O o o . o o . . O O O . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 2 1 1 1 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 , , 1 1 , 1 1 1 , , 1 1 , 1 > 1 1 > 1 , , , , > , , , , , : , , : , , , , , > , > > > : , > > > > > > > > : > : , : , > : : : > : : : - : : : - : - : - : : - - - - - & : & : & & : & & & & & & : & & & & & : & & & : & & : & & & & # # & & # & # & # # & % % % % % % % # # # % % # # # % # @ % @ @ % @ # @ # @ # @ # @ @ @ @ # @ @ @ @ @ @ + + @ + + + @ + + + + + + @ + + @ + + + + X + + X + + O + + X X X + O + O O + + o o O O O O O O O O O X . . . o . . o . o . . . o o O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 1 2 1 1 2 1 2 1 2 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 , , , , , , , , , , , , , , > : , > > > > > , : , > : : > : > : > : : : : : > : : : : : : > : : : : : : - : - : - - - - - : & : & & : & & & : : & & & & & & & & # & & & & # & # # # & # & & # # & # & # & & % % % % % # % % % % # # # % # # @ @ % # # # # @ @ @ @ @ @ @ @ @ @ @ @ X @ @ @ @ + + @ @ + + @ @ + @ + + @ @ + + + + + + + + + + + + + X + + + + + + + X + O X O X X + O O O + O X O O O O O O . . o . o . O o O . o O O ", +"y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 2 2 2 1 2 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 , , , , , > , , , , , , > , : , > , > , > , , : , : > > : > > : > : , : , : : : > : : : : : : - : : : - - - - - - - - - - - : : & : : & : & & & & - & : & & & & & & & & : # & & & & # & & & & & & & & # & # # % % % % % % % # # # % % # # # # % @ # @ # # @ # # # @ @ # @ @ @ @ @ @ # # @ @ @ @ @ + + @ @ X + @ + + @ X + + + + + + + + + + + + + O + + + X X + X X O + O + O O X X O O O O X O O O O X o O . . o . . o . . o O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 1 1 1 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 , 1 , , , 1 , 1 1 , 1 1 > 1 , , , , , , , , : , , , : , : , , , > > > > > > > > > > > > > > > > : , : : : : , : : : > : : : : : : : - : : : : - - : - - - - & & : & & & : & : & & & & & & & & & & : # # # # & & # & & & # & # & # # # & # & # & % % % % % % % % # % % % % # # # % # # # @ # @ # @ @ @ @ @ @ @ # X @ # X @ @ X + @ @ @ + @ @ @ + @ + + + @ + + + + + + + + + + + + + + + X + O O + + O X X + + O + X O O + O X + O O O O o O . O . . . . o . o . . . . O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 1 1 1 2 1 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 > , , , , , , > , , , , , , , , , , , > : > > > > : , > , : : > , : > > : : : , : : : : : : : : : : : : : - - : - : - - - - - - - : : & : : & - & & & - & : & & & & & & & & & & & & : & & & & # & & # & & & # % % % % % % % % % % % % % % # # # % % # % # % # # # # # @ # @ @ @ @ @ @ @ @ @ @ X # @ @ @ + @ + @ + + + @ + + + + @ + + + + + + + + + + O + + + O + + + + O + O + O O O O O + O + X O X O O O O O O O o o o o o . . . . . . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 2 1 2 2 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 , 1 , 1 1 1 1 , 1 , , , , , , , , , 1 , , , , , , , , , , , : , : : , , , , , > , > > , > : : , , : : , : > : : , : : : : , : : : : : : : : : : : - - - : - - - - - - & & : & & - : & : & & & & & & & & & & & & # & & & # # # & # & & % % & # % & % % % & % % % % % % # % # # # # # # # # # @ @ @ % @ # @ @ @ @ # @ @ @ @ @ X @ @ @ @ @ @ @ @ + @ @ X + @ + @ @ + + + + + + + + + + + + + + + O O + + + O O + O + O + + + O X O O O X O O O O O O O . O o o o . . . o . . . o o o o O ", +"2 2 2 2 2 2 2 y 2 2 2 2 2 2 2 2 2 1 2 1 1 2 1 1 2 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 1 , , , , , , 1 , 1 , , , , , , , , , , , , , , , > , , , > , : , , , > > , > : , , > > > , : : : > > : : : : : : : : : : : : : : : : - : : : - - - - - - - - : & : & : & & & & & & & & & & & & & & & & & & & & # & & & & # & % & % & % & % & % % % % % % % % % # % # # % # # % @ # # @ # @ @ @ # # # @ @ @ @ @ @ @ @ @ @ @ # + + @ + @ @ + @ @ @ + + + @ + + + + + + + + + + + + + + + + + O + O + O O X + O O O O + O O O O O O O O O O O o O . . . o . . o o o . o o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 2 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 , , , , , , , , , > , , > , , , > : , , > > , > > > > : > > > : > : , > : , : , : , : : : : : : , : : : - : - - : : - - : - - - - & : & : & - & : : & & : & & & & & & & & & & & & : # & & # : # # & % & # & # % % % & % % % % % % % # # % # # # # $ # # # @ % % # @ @ @ @ @ @ @ @ @ @ @ @ X # @ X @ @ @ + @ + @ + + + @ + + + + @ + @ + + + + + + + + O O + + + O + + O + + + O O + O + O O + O O O O O O O O O O . . O . . . o . . . . o o O ", +"2 0 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 1 2 1 2 2 1 1 2 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 , 1 , 1 1 , 1 , 1 , 1 , 1 , 1 , 1 , , , , , , , , , , > , , , > > > > > , > , > > , : , : , : > : : > > > > > : : > : : > : : : : : : : : : : : : : & : & & : - - : - & : & : # : : : # : : & & & : & @ - - - # - - - @ - - @ # - # # - - # # - # # # # % % - # # % % # # # # # # # # # # % # # @ % # # @ @ @ @ @ @ @ @ @ @ + @ @ @ + @ + @ + + @ + + + + @ + @ + + + + + + + + + + + + + X X + + + + X + o + O + O O O + X O X o O + O O O O O O . . . . . o . . . . o o . o . O O ", +"2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 1 1 2 2 1 2 1 2 2 1 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 > > , > > , , : , > > : , , : : > : > : > : > > : : : : : : : : & : : : : : : : : : : - : & : : & : & : : : # # : : # # : : # - - # - @ - @ - - @ @ - - # - # # % # - # # % - - % % % # % # % % # & # # # # # # # # # # # @ @ # # @ # @ @ @ @ @ @ @ @ @ @ + @ @ # + @ @ + @ # @ @ + @ + + @ + @ + + + + + + + + + + + + X + + + o X + + O O + O O o o + o o o O O O O + O X X . . . o . . o . o . o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 1 2 2 2 2 2 1 1 2 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 , 1 , 1 , , , , , , , , , , , , , , , > , , , 1 > > 1 > > > > , : : , > > , : , : , , > > > > > : : : : > > : > : : : : : : - & : : : : : - & : & : & : & & : : # : : : # : : & : & & # - - - - - # - - - - - # - - # # - - # # - # - # % % % % % % % & # # # % # & # % @ % % # # # # @ # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ + + @ @ + @ + + + + + + + @ + + + + + + + + + + + o + + + + o X + o + O + X o + o + + + O O O O O O O X o X O . o o . O X O . . . . o O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 1 2 1 1 1 1 1 2 2 1 1 1 1 1 1 1 , 1 , 1 1 1 1 , 1 1 , 1 , 1 , 1 1 , , 1 1 , , 1 , , , , , , , , , > > > > > > > , > , , , : > , : > : , : : : > > > : > > : : : : : : : > : : : : : : : : : : & : : & : & : : & : & : : # & : : & & # : # & - - # # - # - # @ # - @ # - # - - # - # # - # % # % % % % % % % # # # & # # # # @ % @ % # @ @ # # @ @ @ # @ @ @ @ @ @ @ @ + @ + + # @ @ + @ + @ + @ + @ + @ + + + + + + + + + + + + + + o + + X + + X + + X + + O + o o O O + O O O O O X o O . . o . X . X . o o . o O O O O ", +"2 2 2 2 2 2 0 2 2 2 2 2 1 2 2 1 2 1 2 2 2 1 2 1 1 2 1 1 1 2 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 > > > > , , > , : > > , , : , > , : > , > > > : : > : > : : > : : : : : : : : : : & : & : : : & & : - - & : & & : & : & & : : # : # : # @ - - - - # - - - @ - # - # - # # % # - # # # % & % % % % % % % # % # # # % # % % # # # # # # @ # @ # @ # @ @ @ @ @ @ @ @ @ @ @ # + # + + @ + + # @ + + + + + + + + + + + + + + + + + + + + + o + X + + + o o X O O O X O O O O O + X O O . X X . . O o . . . . . . o O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , , 1 , 1 1 , , 1 , 1 , , , , , , , , , > , , , , , , , > , 1 : > > > , > , : : , : , > > : : > : : > > : > : : > : : : : : : : : : = : : : : & : & : : : & : : & : & & : & & : : # : & : : : - - @ - - - # @ - - # - - # # # - % - # # - - % % % % % % % % % % % % # # # % # # # # # @ # # @ @ @ # @ @ @ @ @ @ @ @ @ @ @ + @ + # # + @ + @ + + + + @ + # @ + + + + + + + + + o + + o X + + + + X X + o + + X + + O + O O O O O O O X . O o O O . o o . O . o o . o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 1 2 1 1 1 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 1 1 1 1 , 1 1 1 , , , 1 , , 1 , , , , , , , , > > , > > > 1 > , , : , , , > > , : : , : > , > > > > : : > : > : : > : > : : : : : : : : : : & & : : : - & - : & : & : : : & : # : & & & & # : - - @ - # - - - # - # @ # - # - # - # # # # - % % % % % % % % % # # # % % # # # # @ % @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ @ @ @ + @ + @ + + @ + + + + + + + + + + + + + + + + + X + + + + + X X X X + o X + O + + O + O O O O O O O O . O O o o . O . X o o . . o . . O O O O ", +"2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 1 2 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , , , , 1 , , 1 , 1 , , , , , , , , , , , > , , , , , 1 > > > , : , > > : , > , : > > > > : : : : > > > : > : > > : : : : : : : : : : : : : : : : : & : & : & : & & : & & & & # : : # : & & & # - - - - # # - - # - - - # - # - # # - - # # # % & % % % % # % % % % % % # # # # # @ % # # % @ # @ # @ @ @ @ + @ @ @ @ @ @ + @ + @ @ @ @ + @ # + + + # + @ + @ + + + + + + + + + + + + + X o + + + X + X + + o + X O O O O + O O O O O O O O O . . . . O O . . . . . O O ", +"2 2 2 2 2 2 r 2 2 2 2 2 2 2 2 2 2 1 1 2 1 2 1 1 1 1 2 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 , 1 1 , , 1 1 , , , 1 1 , , , 1 , , , , , , > , > , , > > , , , : , : , : : , : , : > : > , > > > : > : : : : : : : : : : : : : : - : - : - : - - - - - & : : & : & : : : : : : & : # & # : # - - - # - - # - - # - - # - # # & & # # & # & % % & # # & # # # # # - # # % # + - - + - + + - # @ @ @ # @ # @ @ + # # @ + @ + @ + + @ @ + @ + + + # + @ + + + + + + + + + + + o + + o + o + + + O O + O + O X X O X O O O + X O O O O O O X . . . . . o . . . o . o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 1 2 2 1 1 2 1 2 1 1 1 2 1 2 1 1 1 2 1 1 1 , 2 1 1 1 1 1 1 1 1 1 , , 1 , , , , , 1 , , , , , , , , , , , , , > > 1 > : , , , , , , , : , , , > , > : > : : > > : > : : > : > : > : : : : : - - : - : - : - : - - : : & : & & & : # # : # : # : : : # - - # - - # - # @ # - # # - # # & # & & & # & # % & # & # % # % # # # # # # # # @ + + - O - + $ # # @ # @ @ @ @ # + @ + @ # @ @ + + # + @ + @ @ @ + + + @ + + + @ + + + + + + + + + + + + + + o + + + O + O + + + O + O X O X X O + O O O X O O . . . o o o . . . . . . . . O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 1 2 1 1 2 1 2 1 2 2 1 1 1 1 1 1 1 2 , 1 1 1 , , 1 1 1 1 , , 1 , 1 , , , 1 , , , , , , , , , , , > , , , > , > > , , : : , , : , : , : : > , : > : > : > > > : > > > : : > : : : : : : : : : : : - : - - : - & : & : & & : : # : : : : & : & : & & # - - # # # - - - # # - - # # - & # & # # & # & & & # # # & % % # # + - # # # # - + + + - O o + @ @ @ @ @ @ @ @ # # @ @ @ @ + @ # + @ @ @ + @ + + + @ + + @ + @ + + + + + + + + + + + + + + + o X + + X O + O O X + O + o o X X O O O O O X O O . . . o . . . . . . . o o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 2 1 2 2 2 2 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 , , , , , , , > , > , , , , > , , > , , : , , , : , , : , : , : > > : : : > : : > : : : : > : - : : : - : - : - : - - - - & : & : : & : : : # # : & & # : # : - - # - - - - # - - - - # - - # # & & # & # & # # % & # # % % # - # # # # # % # - @ - @ O - - + # @ # @ @ @ @ @ + @ @ # + # # @ + @ @ + + @ + @ # + + @ + + + + @ + + + + + + + + + o + + o + + + O X + O O + + O O O O X + X X O O O O + X O X O O o . . . o o o . o . o . o ", +"2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 1 1 1 1 1 1 1 , 2 1 1 1 1 1 , 1 1 , 1 1 , , , 1 1 1 , 1 , , 1 1 , 1 , , , , , , , , , , > , > , , , > > > , : > , : , , : : , : , : : > : : , , : > > : : : : > : : : : : : : : : : - : - - - : - - - - - : & : & # : : : : # & : : : & # - # - - - @ @ - @ + - - # - # - & & & # # & # & # & # # % % % & - + # # - @ + - + - + @ + + - - # # # @ @ # @ @ # @ + + + @ @ @ @ @ + o @ @ @ @ + # + + + + + @ + + + + + + + + + + + + + + + o + + X O + O + O O O O O + + O + + + + O O + O O O O X X . . O . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 1 2 1 1 2 2 1 1 1 2 2 1 2 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 , 1 1 1 , , 1 , 1 1 , , 1 , , , 1 1 , , , , , , , , , , , , > , , , , , , , : , : , : , : : , : , > : : > > : : > > : : : : : : : : : : = : : - : : - - - - - - & & : : & : : # : : : & : & & : : - # - # - - - - - - - @ - # - # & # # & & # & # # # & & % # # # # + - + + + - @ @ @ + - - + + + @ # + # @ @ @ @ # + # @ # # + + + + # @ @ o + o + @ + + @ + + + + + + + + + + + + + o + o + + + O + X + O O O O + O + + + + + + + $ $ $ + $ + + + O O O O . . . . . . . o ", +"2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 1 2 2 1 2 2 2 1 2 1 1 2 1 1 1 1 1 2 1 1 1 1 , 1 1 1 1 , 1 1 1 1 , 1 1 , , 1 , 1 , , 1 , , , , , , , , , , , > , > , , > , > , , : : , , : , : , : , , : > : > : : : : > > : : : : : : : : : - : : : : : : - - : - - - - - - : & & : # : : # & # : # & & & & - - # - # - - # @ - - @ # - # - # & & # # & % & & # % % & % # % + - - + @ # + @ + - @ @ - + + - # @ # @ # @ @ @ + # + # @ + + @ @ + @ @ + @ @ + + + + + + + + + + @ + + + + + + + + o + + + o o + O O + O + O O + O + + @ + % % $ * # * * @ $ + + + O O O O o o o o . . o . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 1 2 2 1 2 2 1 1 2 1 1 1 1 1 1 1 1 1 2 1 , 1 1 1 1 1 , 1 , 1 , 1 1 , 1 , 1 , , , , , , , , , > , , , , , , > , > > , : , , , > > , : , : , : : , : , : , , : : : : : : : > : : : : : : : : - : - : - - : : - - - : & & : : & : & : : : : # : & : # & # - - - @ - - # - - @ - - # - - & # & & & # & # # & % # # # # & - @ + - + - - O - @ + - + - + + @ # # # + @ @ @ @ @ # # + # # @ + # @ @ + + @ @ @ + @ @ + + @ + + + + + + + + + + + + + + + + + O + + O + O + + + + + + % # * ; ; > : ; ; = * $ $ + + + O . . . . . o . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 1 1 2 1 1 2 2 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 1 , , , , 1 1 , 1 , , 1 1 , , , , , , , , , > , , , > , : , , , : , , : : , : , : , > : > : : , : > > : : : : : > : : : : : : : - : - : - - - - - - & - & : & : & & & : # : & & # : : & & & & & # & & & - 8 4 4 4 8 < 4 , , , < 4 4 4 8 4 4 4 4 4 4 4 4 4 4 4 4 8 4 4 - $ @ $ - + + - o # @ @ @ @ @ + @ + # @ + @ + # + @ @ + @ @ + @ + + + @ + + + @ + @ + + + + + + + + + + O + + + O + + X + + o + + + + + # = ; 5 7 2 e e e 1 7 < = # @ + + + O X . . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 , 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 , , , , , , , , , , , , , , , , , , , > , > > , , : : , , : , , : , : , : > , : , > : : > : > : : : : : : : : : : - : : : : - : - - : - - : - : & : & & : & & & : & : & & & & & & & & & & & & 4 v v v v v v v v c v v v v v v v v v v v v v v v v v v v v v v k ; - + + - - $ # # @ # # @ # # @ @ @ @ @ @ + @ + @ @ + + @ @ + @ + @ + + @ + + + + + + O + + + + + + + O O + + O + X + o + O + + @ * * > 7 e s n M M m n f e 7 > * # + + O . . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 2 1 2 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 > 1 , 1 1 , , , , , , , , , , , , , , , , , , , > , , , > , , , , , , : : , , : > , : > , : : , : > , : > : , : : : : : : : - : : : : : - : - : - - : - : & : : & : : & : & & & & : : & & & & & & & & & & # 4 v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v k $ @ O - $ @ # @ @ @ @ @ @ @ # @ # @ # # @ + @ @ + @ + @ + @ + + + + + + + + + + + + + + + + + + + + + O + + X + o + o + + $ # * > w f M S U T R T K S m f 9 : * % + + O X . . . X . . X . X ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 , 2 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 1 1 1 , 1 , 1 , 1 1 , 1 , , 1 , , , , , , > > , , , : , , , : : , , , , : > > , : , : : , > : > : : : : : : : , : : : : : > - : - - - : - : - : - - : & : & & : & & & : & : & & & & & & & & & & & & & & & 8 v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v x ; - + O # @ @ # @ @ @ # @ + @ + + + # + @ + @ @ + @ + @ + + @ + + @ + + + + + + + + O + + X + O + + + + + + + X + + + @ $ ; > 0 f C K ! ..;.;.;. .~ Y B f 7 : * $ + O . . . . . X X X X X X X X X . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 2 1 2 2 1 1 2 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 , , , , , , , , , , , , , > > , , , : , , , : , > , > : , > > : > : : > : : > > : : : : , : : : - - : : : - : - - : - : & : & - : & : & & & : & & & & : & & & : & & & & & & # & < v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v l - # @ @ @ @ @ # @ @ @ @ @ + @ # + @ + @ @ + @ + @ + @ @ + + + + @ + @ + + + + + + + + + + O + + + O O X + + o X + + $ # ; 7 y A R { <.2.7.9.7.2.>.{ R A r 7 = $ $ + X O . O X + X X $ + + + X X X X ", +"2 2 2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 2 1 2 2 1 1 1 1 1 1 , 1 1 1 1 1 1 , 1 1 1 1 > 1 1 , , , , 1 , 1 > , , , , , , , > > , , : , , , > : , : , : , , > , : , , : > : > : > , : : > : : : > : > : : : : > : : : - : - > - - : - : & : - : : & & : & : & & : : # & : # & & & & & & & & & < v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v k # $ # @ # @ @ @ @ @ @ @ @ @ @ @ @ # + @ @ + @ + @ + @ + @ + + + + @ + + + @ + + + + + + + + O + + + O + + O + + + % = , e M K ..1.9.w.j.j.j.w.7.1.{ Y M w 5 * $ + + O O . + + + $ $ $ $ $ * $ $ $ + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 1 2 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 1 , 1 1 , 1 , 1 1 1 , 1 > 1 1 , , 1 , , , 1 , , 1 , , , , , , , , , , > , , , , > : , , , , : > : > > : , , : : , , , : : , : : > , : : : : : : : - : : - : : : - : : - - : - - - & : & : : - & & & & & : : & & & # & & & & & & # 8 v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 8 $ # @ @ @ # # # @ @ @ @ @ @ + @ + + # @ @ + @ @ + + + + + @ + @ + + + + + + + + + + + + + + + O + + + O + + + + # ; 7 f S ~ <.9.g.l.x.x.x.l.h.9.>.! G r 6 & $ + + O O + + + % * * = = 3 * * = $ $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 2 1 2 1 2 2 1 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 > , , , , , , , , , , , , > > > , , , : , > > , , > > > : : , : > : : : , : : > : > : : : > : : : : : : : : : - - - - : - & : : & : & : & & & : & & : & & : # : # : & & & & & & & 0 v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v c # # @ # # @ + @ @ @ @ @ @ @ @ @ @ @ @ + + @ + + @ + @ @ + + + + + + @ + + + + + + + + O + O + + O + o + o + + @ % : 7 n U ..2.w.l.m.M.N.M.m.l.w.2.{ Y b 9 = $ + + + + + $ % = > 6 7 9 9 9 7 5 5 = ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 2 1 2 1 1 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , , 1 , 1 , , 1 , , 1 , , , , , 1 , , , , , > , > > , , , , , > , > , : , , : , : , : , : : > > : , : : > : : : : : : : : : : : - : - - - : : : & : & & & & : & & : - & : & # : : # : & : & & & & & & & & , D c v c v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 8 # @ @ # # @ # @ @ @ @ + @ @ @ + @ + @ @ + @ @ + @ + @ + @ + + + + + + + + + + + + + + + + + + + + O + + + + + * > e m T :.8.h.z.M.C.C.C.M.z.j.7.;.T M w ; $ $ X + $ $ * ; 7 w r b m M m b s 9 5 = % $ X $ . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 1 2 1 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 , , , , , , , , , , , , , , , > > > , , > > > , : : , : , : , : : , : > , : : : : > : > : > : : : : : - : - : > - & & : : : : : : & : & : : # - & & - & & : : # : & & & & & & & # : h l l l l l l l l l l l l l l l l l l l l l l v v v v v v v v v v v v v v v c @ # @ @ @ @ # + @ @ @ @ @ @ @ @ @ @ @ + @ + + @ + @ + + + + @ + + + + + + # + @ @ + $ + + + + O + X + X + + $ & ; e C R :.9.h.m.V.Z.Z.Z.V.x.j.7.:.T M e 5 $ $ + + $ * : 7 r b S K T T T K A m s 7 3 * $ . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 1 2 1 2 1 2 1 2 2 2 2 1 1 1 1 2 1 1 1 1 1 1 1 1 , , 1 , 1 , , , , 1 , , , , 1 , 1 , , , , 1 , , , , , , , > , > > , > , , > , , > , > , , : , : , : > , : > : : > : > : > : > : : : : > : : > - : - > - : : & : & : : & : & : & - - : & : & & & & # & : & & & & & & & & & & - & & # & # - # - - # & - % # - # # # & % % # g v v v v v v v v v v v v v v - - # @ @ @ @ @ @ @ @ @ @ @ + @ @ + + @ + @ + + @ X + @ + + + + @ + + + @ % # # # @ % $ % + + + + X + X + + + & > e M R ;.7.h.m.M.C.C.C.M.x.h.7.;.T M w ; * $ + $ * ; 7 s A T R ..-.-.-.{ ! K B s 7 3 $ + . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 2 1 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 , , , , , , , , , , , , , , > > , > , > , > > , > > , > , : > , : , : , > : , : > : > > : : : : : : : : : : : - - : - : - - & : : : & : : & & - - - - & & - & & & : : : # # & & & & & # & & & & & & & & # & # - # # - # # # # # # & % % # # # @ g v v v v v v v v v v v v v i o @ @ # @ # @ @ + @ @ @ @ + @ + @ @ + @ + @ + @ @ + @ + @ + @ + @ @ # % # % % = # * * * @ # % $ + + + + + @ * ; w b K { 2.q.l.m.M.V.M.m.l.w.2.{ K b 7 ; $ $ $ $ = 6 r C R { >.2.2.8.7.2.>.{ Y C s 4 * * + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 2 2 1 1 1 2 1 1 2 1 2 1 1 2 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 1 1 , 1 , , , 1 , , , , , , , , , , , , , , , , , > , , > , , , : , : > , : : , : : > : : , : : > : : : > > : : > : : : : : - : : : > - - > : : & : : : & : : - : & : # - & & : # : & : : & & & & & & & & & # & # & & # & # - # # - # # % % & # # # & # & # # # - v v v v v v v v v v v v v c @ @ @ + # # @ # + + # @ @ @ @ @ + @ @ @ + @ + + X @ + + @ X + + @ $ % & = = : < < > : ; = # @ $ + + + + + $ # = 7 b S ~ <.9.h.l.z.x.x.l.h.9.>.~ G s 7 * % $ $ % 3 e m K { 1.8.f.h.j.h.f.8.1.{ U b r ; * . . . ", +"2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 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 , , , , , , , , , , , > , , , : , , > : > , > , > , > , : , > > > , : : , > > > > : : : > : : > : : : : : - : - - - - - : & : & : : & : & & : : : & & & & : & # & : # & & & & & & # & & & & & & & & # # - - # # - # - & % & % & # % # # # # p v v v v v v v v v v v v v - @ @ @ # + # + # # # @ + @ + @ + + @ @ @ + + + @ + @ + + @ @ @ # * = : 5 7 e e e e e 7 5 > = $ $ $ + + + + $ & , e b Y { 1.9.w.g.j.j.w.9.1.{ K M e : % % $ % = 7 s G R <.8.h.l.z.m.z.l.h.8.>.R A s 5 * + . . ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 1 2 1 1 2 1 2 2 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 , , , , , , , > , , > , > > , > , , , , > > > > > , , > , > : > > > : : > > : : : > : : : > : : : : : - > - > - - : - : - & : : & & : & : & # : : : & : & : # : & & & & & & & & & # & & & & & & & # - # # # # - % # & # % # # & % - # # ; v v v v v v v v v v v v v < @ @ @ @ @ # # # # + + @ @ + @ @ + @ + @ + @ + + + @ + @ + $ % % : 5 7 r b b M M M m f r 7 < = # $ + + + + $ % = 7 y A T { >.2.7.7.7.2.>.{ T A r 7 = * + % % = 7 b K .2.f.l.m.M.M.M.m.l.g.2...K b 7 . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 1 2 1 2 2 1 2 2 2 1 2 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 1 1 , 1 1 , 1 , 1 , 1 , , , , , , , , , , , , , , , , , , , , > , > , > > , > > : : , : > , : , : , : : > > : : > : > : : : : : : : : - - - : - - & : : : : & : : & : # - : - & & & # : : & # : & & & & & & & & & & & # # & # & - # # - - # # # % # & # # % # # # # # # l v v v v v v v v v v v v q - @ @ @ @ @ @ @ + @ # @ @ @ + @ @ @ + + @ + @ @ + + @ + $ % & : 5 w f M K K R Q R K S M b 9 5 = & $ + + + $ $ = > 7 b A Y ~ -.;.:.-.-.~ Y C f 9 > * $ + $ % : w b Y ;.8.h.z.M.C.C.C.M.z.j.2.-.T b 9 ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 2 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 , 1 , 2 , 2 , , 1 , 1 , , , 1 , 1 , , , , , , , , , , , , , , > > > , , > > > > > > : , > : , : > > > > : > > : > > : : : > > : : : : : : : : : : : & : : & : : - & - - & & & : & E u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.v.u.} 6 % & & # & & # # # & % % % % % # # % # % # * i v v v v v v v v v v v v a - o - O + + + - + + + + + @ @ + @ @ + @ # + + + @ + $ @ @ # = < e f G Y ^ ..:.>.;...^ K S b 9 < = @ + + + + $ % = : 9 s M S K T R T K A m s 7 : * $ $ + $ $ ; e C T :.8.h.m.N.C.Z.C.N.x.h.8.:.T N w ; $ + O . . ", +"2 2 2 2 2 y 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 1 1 2 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 , , , , , > , > , > , > , > > , > , > , > , : > : : , , : > : > : > : : : : : : : : : : : : : : : : & : : : : & : : & : & = - - : & & : o.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.E % & & # # & & & # & % % % % % % % % # # # q v v v v v v v v v v v v k o - @ @ - + + O - + - O - + @ + @ + + + + + @ + + @ @ @ $ ; ; 0 f A R .<.2.7.9.7.2.<...R C f 7 : # $ $ + + + $ % * 3 7 e s m M M m m f w 7 > * % $ + + + * ; w b T ;.8.g.z.M.C.Z.C.M.z.h.7...T b 9 * $ + O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 2 2 1 2 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 2 1 1 , 1 , 1 , 1 , 1 , , , , , , , , , , , , , > , > , > , > > > > > > > > : > : > , : : , > > > > > > : > : : : > : : : : : : : : : - & : & : & : : & : : : & : & : & & +.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.E # & # & & # & # % % % % % % % % % % $ # 3 v v v v v v v v v v v v k - o O @ + O - - O @ + + + + + # @ @ # + # @ + + + @ + # % ; < r M Y .1.9.w.j.j.j.q.9.1...K M e 7 = $ + + + + + $ % = : < 5 w w e w 7 5 5 ; * % + + + + + $ ; 7 b K { 2.f.l.m.M.N.N.m.l.f.2.{ K b 9 * $ + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 1 1 1 2 1 1 2 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , , , 1 , 1 1 , , , , , 1 , , , , , , , , , > , , , , , , > > 1 > > > , > , , > , > : : , : : > : : : : > : : > : : : : : : : : : : : : : - : : : & & : : & & : & : & : & o.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.m & & & # & # & & % % % % % % % % # # # 4 v v v v v v v v v v v v k o - - @ @ - O + + @ - o - + + # + + + @ + + @ # + + @ @ ; ; 0 f S ^ <.9.j.l.x.x.x.l.j.9.<.^ S s 7 = $ $ + + + + + $ @ # = = ; > ; ; ; = * % + + + + O + + $ * 7 r A { >.8.g.l.z.x.z.l.g.8.>.R S s 6 * $ O . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 2 1 2 1 2 , 2 2 2 1 1 2 1 1 1 1 1 1 1 1 1 , 1 , , 1 , 1 1 1 , , , 1 , 1 1 , , 1 , , , , , , , , > , , , , > , > 1 > , > > > > > , : , : , , : , > : > > > : > : > : : > : : : : : : : : : : - : : : & : : & & : : & : & : & & o.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.k.# & & % % % # % % % % % % % % % # # # 4 v v v v v v v v v v v v k + O $ - + + + + # + + - + + @ @ + + + + + + + @ + + @ # ; ; w n Y ..2.g.l.m.M.N.M.m.l.f.2. .K m w ; * + + + + O + + O $ $ % % $ * % * $ $ $ + + O O O O + $ % 5 r b K { 1.8.f.g.h.h.f.8.1.{ Y b w : $ $ X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 1 1 2 1 1 2 2 2 , 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 , 1 , 1 1 1 1 1 , , 1 , , , , , , , , , , , , , > , , , > > , > , > > > , , > > > : , : , : : , : > > : > : > : > > : > : : : : : : : - : - : : - : & : : & : : & & : & : & = : o.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.L & # & % & & % % % % % % % % % % # % 4 v v v v v v v v v v v v k - O - + - + + - + # + + @ + + @ @ @ @ @ @ @ # + @ @ # # - > e M Q :.7.j.x.N.C.Z.C.M.x.h.8.:.Y B e > * % + + + X + + + + + + $ $ + $ + + + + + O X O O + + % = 5 s C U { >.2.8.8.8.2.>.{ T C s 5 * $ + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 2 2 2 1 2 2 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , , 1 , 1 , , 1 , , , , , , , , , , , , , , , > , , > > > > , > > > > > > , : , : , : : , > : > > : > : : : : : : : : : : : : : : : : : & : : : & : : : : & : & : : & & t D V V V N D V N V V V x V V V o.Z.Z.Z.Z.Z.Z.Z.Z.Z.0.# & & % % % % % % % % % % & % # % # 4 v v v v v v v v v v v v k - - o + + + @ @ + # # + + # + @ @ @ @ + @ + + @ + + # # - < r B Q :.9.j.x.N.C.Z.Z.B.m.j.9.>.Q B e > # @ + + X O + X X + + + + + + + O + O O O X X X O X O + $ % ; 7 f C K ! { ;.:.-.{ R Y C s 7 = $ + + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 1 1 2 1 , 2 1 1 1 1 1 1 1 2 , 1 1 1 1 1 , 1 1 1 1 1 , 1 , 1 , , 1 , , , 1 1 , , , , , , > , , > , , , , , > , , > > , , > , > : , : , : , : : > > : : > : > : : > > : > : : : : : : : - : : : & : : : : & & : : & : & & : & & & - & & & - - - & & - & & & % # } Z.Z.Z.Z.Z.Z.Z.Z.Z.< # % & % & % % % % % % % # % % % % 8 v v v v v v v v v v v v k o O + - - o @ @ @ # + o - + @ @ + + + @ + @ + + @ @ # # - < e M Q ;.7.h.x.N.C.C.C.N.x.h.9.:.R M e > * + + + + O O O O X O + O O + O O O X O X O O O O O O + $ % 5 7 f b S K T T Y K S b s 7 > = $ + X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 1 2 , 2 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 , 1 1 , 1 , 1 , 1 , 1 , 1 , 1 , , , 1 , , , , , , , , > , , > , > , , > > , > > > > > > , , > > > > > > > > : > : > : > > - > : : : : : - : : : - - - : : - - - : & : : & : & : & : & : & - & & & & & & & & & # & & & & = v.Z.Z.Z.Z.Z.Z.Z.Z.P # % % & # # # # # & # # # # % # # i v v v v v v v v v v v v k @ @ - + @ @ @ @ @ @ + @ @ + @ @ + @ @ + @ + + + + $ + % = < w n Y ..2.f.l.m.N.B.N.x.l.f.2...U b 9 : # @ + + O O O O O O O O O O O O O O o . O O X O O O O O X + $ * ; 6 e r b m M b b r e 7 3 * $ + + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 2 1 , , 1 2 2 2 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 1 , 1 , , , 1 , , , , , , , , , , , , > , > , > , > , > , > , : : > : > , : : : > > > : > : : > : : > : : : : : : : > - > : & - : - : & & & & : : & & & & & & - & - & & & & & & & & & & & & # } Z.Z.Z.Z.Z.Z.Z.Z.o.& & # & # & & & # # & & # % # # # l v v v v v v v v v v v v u # @ + o - @ @ @ @ @ @ @ o - + @ @ + @ + + + @ @ + @ + % % ; 9 b H ^ <.9.h.l.x.x.x.l.g.8.<.! S b 7 = % @ + X O + + O + O O O + O O O X X o o O O X O O X + + $ * ; : 6 9 w e e 7 6 : * $ $ + X . ", +"2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 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 , , , , , , , , > , , > , , , , > > > > , > > > > , > > > , : : > > > > > > : > : > : > : : : : : : : : - : - - - : : - : : : : : & & & : & : & : - & & - - & & - & & & & & & & % & j Z.Z.Z.Z.Z.Z.Z.Z.u.% & % % & # # & # # # # # % % # - v v v v v v v v v v v v v q - o + @ @ @ @ @ @ @ @ + + @ + @ @ + + @ + @ + @ + + % # % ; 1 r M Y .1.9.f.j.j.j.q.9.2...K M r < = # @ + + O O O O O X + O O O O O O O X X O O o O . . X X + $ $ $ ; ; ; = = * * * $ + + X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 L J J L J W W W W W W B Q L L L C 7 2 1 1 1 1 1 1 , 1 1 1 1 1 1 , , , C J F J J F F L F F J J F J , , , , , > , , , > 9 F F F F F F F F F C F F F 2 , : > > > : : F D F D D D F 7 : : : - - : : : Z F Z Z Z Z Z - & : & & : : : & : & - & & & - & & - & & & & & & & & & & # & Z.Z.Z.Z.Z.Z.Z.Z.u.# # & % # # & # & # & # & % # % u v v v v v v v v v v v v v ; @ @ o - @ @ @ @ @ + @ @ @ @ @ @ + @ @ + @ + + + + + + $ % = > 1 b A R ..<.2.9.9.9.2.<. .R A f 1 ; * % + O + + O + O O + O O O O O O O X o o O O O O X . . X . X + + + + $ $ $ $ * $ $ + + + X . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 Z.Z.Z.Z.Z.Z.Z.Z.Z.m.C.C.Z.Z.Z.Z.Z.b.J 1 1 1 1 1 1 1 1 , , 1 , 1 1 I b.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.> , , , , > , > w &.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.F : , : > : > > 6.Z.Z.Z.Z.Z.Z.` : : : > : : : I Z.Z.Z.Z.Z.Z.u.& : & & : : & : & & & & & - & & & & & & & & & & & & & & % & & B.Z.Z.Z.Z.Z.Z.Z.B.# & & # % & # & # # % % # # # - c v v v v v v v v v v v v v + + - # @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ + @ + @ + + @ + @ % # ; < w b A K ^ ..;.>.;...^ Y A f e < = @ + + + + O + O + O O O O O + O O O . O O O . o . . . . . . + + + + + + $ + + + O . . + . . O . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.Z.Z.Z.N.V.Z.Z.Z.Z.Z.Z.Z.Z.I 1 1 1 1 1 1 1 1 1 1 1 , [ Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , , > , , , , k.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.F > : > > > : > D Z.Z.Z.Z.Z.Z.r.: > : : : : > 6.Z.Z.Z.Z.Z.Z.I : : - : : & - & : & : & : & - - & & & - & & & & & & & & & % & u.Z.Z.Z.Z.Z.Z.Z.Z.& % % # & # & # % & % # # # @ a v v v v v v v v v v v v v k - - O @ @ - o @ @ @ @ + @ @ + + @ @ + + @ + @ + @ + + @ + @ % # ; 5 w b B S Y Y Q R Y S M s w < * % @ @ O O O + O O O + X + O O O O O O O o . O X O O o o . o . . . . . . O O O . + O O O O + + + + + + + + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.e 1 1 1 1 , 1 , 1 1 1 H Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , , , , , , &.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.Z.F > , : > : : > > v.Z.Z.Z.Z.Z.Z.7 : : : : : 7 Z.Z.Z.Z.Z.Z.v.: : & & : & : - - & & : - & & & & & - & & & & & & & & & & & & & B.Z.Z.Z.Z.Z.Z.Z.B.# & % & # # # % # # # # # % i v v v v v v v v v v v v v v 4 - O + @ @ @ @ @ @ @ @ @ @ @ + + @ + @ @ + @ + @ + @ + + @ + # % = - > 7 r f m B B M n b e 7 > = % @ + + + O O O + O O O X O O O O O O O O O o . o o . . . . X . . . . . . X . . X . O + O X $ $ $ $ $ $ + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.3.1 1 1 1 1 1 1 1 , , p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , , , , > y Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.C.F > : , : , : > : | Z.Z.Z.Z.Z.Z.` : : : : : ` Z.Z.Z.Z.Z.Z.o.: & : : & : : & - & : & : & - & - - & & & & & & & & # & & & # & Z.Z.Z.Z.Z.Z.Z.Z.s.i i i p p p i p i p p a k v v v v v v v v v v v v v v v c $ + + - # @ @ + @ @ @ @ + @ @ @ @ @ @ @ + @ + @ + @ + + @ + @ + % # = = > < 7 e e e e e 7 , > ; # $ @ + + O + + O X X + O + O O O O O O O O O O o X O . . O . . . o X . . O + + $ $ % * * 3 * 3 * * $ $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 Z.Z.Z.Z.Z.Z.k.L L L L L L +.Z.Z.Z.Z.Z.Z.B.1 1 1 1 , 2 , 1 1 C Z.Z.Z.Z.Z.Z.Z.+.J J J J P F F J J F , , , > , , &.Z.Z.Z.Z.Z.Z.k.W F F F F F F F F F 2 > > > : > : : : 0 B.Z.Z.Z.Z.Z.r.: : : : : k.Z.Z.Z.Z.Z.Z.7 : - : - - - : & : & - - - & - - - & = & & : & & & & # - # - & V Z.Z.Z.Z.Z.Z.Z.Z.d.v v v v v v v v v v v v v v v v v v v v v v v v v v v v a - + @ @ - @ @ @ + @ @ o + # # @ @ @ @ + @ + @ + + @ + + @ + + @ $ $ % & = * : : < < > : ; * # % $ $ + + + O O O + X X O O X O X O + X O O X O O O O O . . o . X O o X X X X X $ % & 3 5 9 9 9 e 7 5 ; = % $ X X ", +"2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 2 1 1 Z.Z.Z.Z.Z.Z.p.2 1 1 1 1 1 2 +.Z.Z.Z.Z.Z.Z.W 1 1 1 1 1 1 1 1 &.Z.Z.Z.Z.Z.Z.+., , , , , , 1 , , , , , , , , , , b.Z.Z.Z.Z.Z.B.9 > > , > > > > > > > > > > : > > > > : > 5.Z.Z.Z.Z.Z.Z.7 : : : d Z.Z.Z.Z.Z.Z.4.- : - - - - - & : & : & - & & & & & & & & & & - & & & & & - # 8 0.Z.Z.Z.Z.Z.Z.Z.Z.e.v v v v v v v v v v v v v v v v v v v v v v v v v v v v ; $ + O - O @ @ @ + - + - # + + @ @ + + + @ + @ @ + @ @ + @ @ @ + $ $ $ % % % = & & * * * # % % $ + + + O + O + X O + + O O + X X O O X X O X O O O O . O . o o O o X + + $ * = 5 9 s b b b b b s 9 7 = * $ O X X ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 Z.Z.Z.Z.Z.Z.p.2 2 1 2 1 1 2 e Z.Z.Z.Z.Z.Z.+.1 1 1 , 1 1 1 , p.Z.Z.Z.Z.Z.Z.w , 1 , , 1 , , , , , , , , , , , d Z.Z.Z.Z.Z.Z.&.> > > , > > > > > > > > > > > > : > > > : N Z.Z.Z.Z.Z.Z.` > - : %.Z.Z.Z.Z.Z.Z.C = - - - - - - & : & : - & - - & & : & : & & & & & & = & - & q / B.Z.Z.Z.Z.Z.Z.Z.Z.#.v v v v v v v v v v v v v v v v v v v v v v v v v v v u # - - O + - + @ @ @ + @ @ @ @ + # @ @ @ @ @ + o + @ + @ $ @ # # % # # $ # % # # * $ % # % $ $ $ + + + + X + X + O O O O O + X X + O O O O O O X O o X X o . . X X o O X O + $ * = 7 r b C S T T T K A b s 7 : * + X X ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 Z.Z.Z.Z.Z.Z.p.1 1 1 1 1 2 1 2 0.Z.Z.Z.Z.Z.p., 1 1 1 1 , , 1 Z.Z.Z.Z.Z.Z.0., 1 1 , , , , 1 , , , , , > , , , F Z.Z.Z.Z.Z.Z.F , > > > > , > > > > > > > : > > > - > > : : k.Z.Z.Z.Z.Z.u.- - - v.Z.Z.Z.Z.Z.k.- - - : - - - - : & : & - & & & & - & & & & & & & & & % & # 8 v t.Z.Z.Z.Z.Z.Z.Z.Z.Z.) v v v v v v v v v v v v v v v v v v v v v v v v v v l * @ + + - O + O - @ @ @ @ @ + # # + @ o @ @ + @ + @ @ + $ # # % = = = ; * = & & & # $ @ + $ + + + + X + O + + O O O + O + O o X o o O O O O X X O O O O . o . . O O X X + + * = 7 s C Y { { -.-.-.{ ! K C s 7 * % $ O ", +"2 2 2 2 9 2 2 2 2 2 2 1 2 2 1 2 2 2 2 Z.Z.Z.Z.Z.Z.p.1 2 2 1 1 2 1 2 +.Z.Z.Z.Z.Z.b.1 1 1 1 1 1 1 1 Z.Z.Z.Z.Z.Z.+.1 , , 1 1 , , , , , , , , , , > , +.Z.Z.Z.Z.Z.Z.9 , > , > > , > > > > : > > > > > : > : - > > W Z.Z.Z.Z.Z.Z.t > I Z.Z.Z.Z.Z.Z._ - : - - - - - - & : & : & & - - - 5 V V V V V V V V V V V V =.d.Z.Z.Z.Z.Z.Z.Z.Z.Z.d.v v v v v v v v v v v v v v v v v v v v v v v v v v c ; # # + - - @ + + - + + + + + + + + + # + # + @ + @ @ @ # # # ; - > , < , 5 > : = = # % $ @ + + + + O O + X O O + + + + O O O O o O o O O O X O O X O O O O X o o . O . o O O + $ * 7 s C T { >.2.2.8.8.2.>.{ Y M s 7 * $ + ", +"2 2 2 2 2 2 2 2 2 2 9 2 2 1 2 2 2 1 1 Z.Z.Z.Z.Z.Z.p.2 7 1 2 1 1 1 1 L Z.Z.Z.Z.Z.Z.1 , 1 1 1 1 , 1 Z.Z.Z.Z.Z.Z.+., 1 , , , , , , 1 , , , > , , , , +.Z.Z.Z.Z.Z.Z., > > , > > > > > > > > > > : > > > > : > > > : B.Z.Z.Z.Z.Z.} - 6.Z.Z.Z.Z.Z.B.7 - - : - - - - - : & : & & : - e 4.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.#.v v v v v v v v v v v v v v v v v v v v v v v v v v ; $ # % + + O O - O - + - + - o + - + + + @ + + + @ # @ $ # = = > 7 1 9 e e e w 7 < : = # % @ + + + + O + + + + O O O O O + O + + O O O O O + X O o X X . X o o o . . O o o o O O O $ * : e m K { 1.8.f.h.j.h.f.8.1.{ K m 9 ; $ + ", +"2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.1 2 1 1 1 2 1 1 L Z.Z.Z.Z.Z.Z.1 1 1 1 1 , 1 1 Z.Z.Z.Z.Z.Z.+., 1 1 , 1 , , 1 , , , , , , , , , +.Z.Z.Z.Z.Z.Z., , > > , , > > > > > > > > > > > : - > > - - > %.Z.Z.Z.Z.Z.k.1 Z.Z.Z.Z.Z.Z.5.- : - - - - - - - & : & : : - j B.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.c.v v v v v v v v v v v v v v v v v v v v v v v v v k * % % $ # - + + - O - O + # @ - + - o - + @ @ + # # + + - # = : , 7 t b n M A M M b r 7 5 = % $ @ + + + + X + O O + O + O O + O O O O O O O O O O o O O O . o . . . . o . . X X X + $ * 5 r C ! >.8.h.l.z.z.z.l.g.9.>.~ C r 5 * + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 Z.Z.Z.Z.Z.Z.p.2 1 2 2 1 1 1 1 L Z.Z.Z.Z.Z.Z.1 1 1 1 , 1 1 , Z.Z.Z.Z.Z.Z.+., , , , , , , , , , , , , , , , , +.Z.Z.Z.Z.Z.Z.F > > , > > > > > > > > > > > > > > > > > > > : t Z.Z.Z.Z.Z.Z.+.Z.Z.Z.Z.Z.Z.r : - : - - - - - - : & - & & e B.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.' v v v v v v v v v v v v v v v v v v v v v v v k 8 $ % $ $ @ + @ @ + - + + + - @ + o o - + + + # + # + + + @ @ & ; 7 e b M H Y R R R K S M b w , = * $ + + + O + X O + + O O + O O + O O + O O O O O O . o o O o o . o o . o . . o O + + = 7 f K .2.f.l.m.M.V.M.m.l.q.2.{ K f 7 = $ ", +"2 e 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 1 Z.Z.Z.Z.Z.Z.p.2 1 2 1 2 1 1 1 W Z.Z.Z.Z.Z.Z.1 1 1 , 1 1 1 1 Z.Z.Z.Z.Z.Z.+., , , , 1 , , , , 1 , , , , , , , I Z.Z.Z.Z.Z.Z.%., > , > > > > > > > : > : > > > : > : : > > > : u.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.u.- : - - : - - - - - - = - - = u.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.#.v v c a p p q t p i p p u i i i u u u p u 6 4 & # # # # # # # # @ O @ @ - + + + - - O + + + + + + # + + @ @ @ - ; < 0 n A Y ^ -.:.>.:...^ T C f e < = @ + + + + + O + X + O + O O + + X O O O O O O O O O O O O . . o . . . o o . . . . . O + $ ; 9 m T ;.7.h.z.N.C.Z.C.M.z.h.7...T m 9 = $ ", +"2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 Z.Z.Z.Z.Z.Z.p.1 2 1 1 1 1 1 1 +.Z.Z.Z.Z.Z.b.1 1 1 1 1 , 1 1 Z.Z.Z.Z.Z.Z.+.1 1 1 , , , , , , , , , , , , , , N Z.Z.Z.Z.Z.Z.B.w > , , , > > > > , : > > > > > > : , > : - > > I Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z._ : - - & - - - - - - - - & - V Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.n.' v v c - & % & # & % # % % # % % # % % # # $ % @ % # # # # # @ # @ @ - - @ + O - O o + + @ + - - + # + # @ $ # # ; ; 0 f A Q ..<.2.7.9.9.2.<. .Q A f 1 : * % @ + + X + X + O + O O O O O X O O O + O O O O O O o . o . . o . . . . . o . O O % ; e m T -.8.h.z.N.Z.Z.C.N.x.h.8.:.T m 9 ; $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.1 1 1 2 2 1 1 1 p.Z.Z.Z.Z.Z.p.1 1 , 1 1 1 , 1 Z.Z.Z.Z.Z.Z.+., , 1 , 1 , , 1 , 1 , , , > , , > , B.Z.Z.Z.Z.Z.Z.k.I F D F F F F N > : > : > : > : , : : > > : : : v.Z.Z.Z.Z.Z.Z.Z.Z.Z.v.: - : : : : : : - - - - & - - 0.Z.Z.Z.Z.Z.Z.Z.Z.Z.v.u.u.u.u.s.d.d.d.d.d.d.t.=.O.v v v v ; % # % # % % % % % & % % % % # & # # % @ % % # # # # @ # @ # @ @ O @ + - O - + @ - + + + + @ @ @ + @ $ # - ; 1 t B Y .1.9.w.j.j.j.f.9.1. .T M r < = % + + + + O + O + O O + + O + X + X X X O O O O O O O X . . . . . o . . . X o . . . O $ $ = 9 m T ;.7.h.l.M.C.C.C.M.x.h.7.;.K m 7 = $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 Z.Z.Z.Z.Z.Z.p.2 1 1 1 1 2 1 n Z.Z.Z.Z.Z.Z.&.1 1 1 1 1 1 , , Z.Z.Z.Z.Z.Z.+.1 , , , , , , , , , , , , , , , , , 6.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.Z.v.W > > > > : , : : > : : > > : O.Z.Z.Z.Z.Z.Z.Z.Z.Z.O.- : - : & : & - - - - - - - 5 Z.Z.Z.Z.Z.Z.Z.Z.Z.4.= & & & ; c v v v v v v v v v v v v k - & & # & % & % % % % % % # % # # & % % % % @ # # # # @ # # @ - O - @ + - + + @ @ @ + + - + + + @ @ @ @ # - ; 1 n H ^ 1.9.j.l.x.x.x.l.j.9.,.^ S b 7 ; % $ + + O + + O O + + O O + X O o X X + O O O O O O X X . . . . . . o . O O O + $ = 7 b K .2.f.l.m.M.N.M.m.l.f.2. .K h 7 = $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.2 1 1 2 2 2 1 0.Z.Z.Z.Z.Z.Z.W 1 1 1 , 1 1 1 1 Z.Z.Z.Z.Z.Z.+., , 1 1 1 , , 1 , , , , , , , , , > d Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.! ; > > : : : > , : : : : : d Z.Z.Z.Z.Z.Z.Z.Z.Z.d : - : : & : : & : : : - - - I Z.Z.Z.Z.Z.Z.Z.Z.B.< & & & & - v v v v v v v v v v v v v q % % % % & % % % % & % % % % # & # # # # # # # # # # # # @ # # + + - O @ @ - + @ @ @ + - O + + @ @ @ @ @ # - ; e m Y -.2.q.l.x.M.N.M.m.l.q.2...Y m w : % % + O + + X + O O + + O O O O O + o o X X O O O O . O . . o o . . o o . . o . . O + $ * 6 s S R >.8.h.l.z.x.z.l.g.8.>.! S r 5 * $ . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.[ +.+.+.+.+.p.Z.Z.Z.Z.Z.Z.B.1 1 1 1 1 1 , 1 , Z.Z.Z.Z.Z.Z.+., 1 1 , , , , , , , , , , , , , , > , 6.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.t > > , > , : : > : , > : : 6.Z.Z.Z.Z.Z.Z.Z.6.: - : - : : : & : : & & - & & o.Z.Z.Z.Z.Z.Z.Z.Z.4.& & & & & 4 v v v v v v v v v v v v v ; % % & % & % % & % # % % % % % # # # # # & # # # # # # # # @ @ @ @ @ @ - @ + O @ @ @ @ @ + - + @ + + @ # # - < e B Q ;.7.h.x.N.C.Z.C.M.x.j.7.;.R M e < ; # + + + X + O + X O O + + O + O X O O + O O o O O . O . . o o . . . . . . . . . O X $ * ; e b Y { <.8.f.g.j.h.f.7.<.{ Y b w ; $ + . ", +"2 2 2 r 2 2 2 2 2 2 2 2 2 1 1 2 2 2 1 Z.Z.Z.Z.Z.Z.p.p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.+., 1 1 1 1 1 1 1 1 Z.Z.Z.Z.Z.Z.+., 1 , , , , , , 1 , , , , , , , , , , 0 k.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.0.> > , : : : : > : : : , : 4.Z.Z.Z.Z.Z.Z.Z.4.: - - : & - : : & - & : - - & 0.Z.Z.Z.Z.Z.Z.Z.Z.E & & & & & q v v v v v v v v v v v v v - # & % % % % % % % % % & % % % # & & # # # # # # # # # # @ # @ - @ @ @ O O @ - + + @ @ + + + + @ + @ @ # @ ; < r B Q >.9.j.x.N.C.Z.Z.N.x.j.9.>.Q B e < = + @ + O + O + O + O + O O O O O O O + O O O O O O . . o . . o . . . . O . . O X + $ = 7 s C U .>.2.7.9.7.2.>.{ Y M r 5 * $ O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 7 2 2 1 2 2 1 Z.Z.Z.Z.Z.Z.p.p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.e 1 1 1 1 1 , 1 , 1 Z.Z.Z.Z.Z.Z.+.1 , 1 1 , 1 , , , , , , , , , > , , , , w 6.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.B.> - : : , : , : > : : : 7 B.Z.Z.Z.Z.Z.Z.Z.B.7 : : - : : & & : : : & & : & p.Z.Z.Z.Z.Z.Z.Z.Z.D - & & & * i v v v v v v v v v v v v z # & % % % & % % % % % % # # % % # # # # # # # # # # # # # # # @ + @ - O + - @ @ - + + # - + - o + @ @ @ $ - ; ; t B R ;.9.h.x.N.C.Z.C.N.x.j.7.:.Y M e < * # # + + + O X + O + O O + O + O O O O O O O o O O . . . . . o . . . . o . o X X X $ % = 7 f C K ! .;.:.;.{ ! K C s 7 ; % + O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 Z.Z.Z.Z.Z.Z.p.p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.V 1 1 1 1 1 , 1 1 1 1 Z.Z.Z.Z.Z.Z.+., 1 , , , , , 1 , , , , , > , , , > , > , , 0 F F F F F F W 5.Z.Z.Z.Z.Z.Z.Z.I : > > : > > : > > : > | Z.Z.Z.Z.Z.Z.Z.Z.Z.} : : = : : - - : : & : : & : u.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & # a v v v v v v v v v v v v z - # & # & # - # # # & # % % % % # % # # % % # # # # # # # # # # @ # # @ @ @ @ @ @ @ @ @ + @ @ + @ @ @ + @ * & < 9 M U -.2.w.l.m.M.N.N.x.l.g.2...K M w : = $ + + + + + O O + O O + O X O O X X X O O O O X O o o o o o . o . . . . . o o . O + $ * 3 7 r b S K T R K K A b r 7 * ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.p.Z.Z.Z.Z.Z.Z.Z.Z.B.6.n 1 1 1 1 1 1 1 1 1 , 1 Z.Z.Z.Z.Z.Z.+.1 , , 1 1 , , , , , , , , , , , , , , , ; , , , > > > > > > , I Z.Z.Z.Z.Z.Z.+.> : > : > : > : : : : v.Z.Z.Z.Z.Z.Z.Z.Z.Z.v.: : : : & - - : & : & : - & u.Z.Z.Z.Z.Z.Z.Z.Z.V & - & - & p v v v v v v v v v v v v z # # # & # & # # & # & # % % % % # % % % # # # # # @ # # @ % # # # @ @ @ @ @ @ @ + @ @ @ @ @ @ @ + + @ @ @ # # > 2 b H ^ 1.9.j.l.x.x.x.l.h.9.,.^ S f 7 ; = + + + O O O + + X + X + O + O O + o + O O O O X O X X o o X o . . . o o o . . . X O + + $ % = 5 w r b m M m f r e 6 ; * ", +"2 2 2 2 r 2 2 2 2 2 2 2 2 2 2 2 2 1 1 Z.Z.Z.Z.Z.Z.p.2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , Z.Z.Z.Z.Z.Z.+., 1 , 1 1 , , , , , , , , , , > , , > > ; , , , , > > , > > > > b.Z.Z.Z.Z.Z.0.> : > > : > : : > > I Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.I : : : & : - & : : & & = : u.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & & g v v v v v v v v v v v v g # - # & & # - - # # # & % % % % % % % # % # % # # % # # # % @ # @ @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ # * ; 1 r B T ..1.9.q.h.j.j.q.9.1. .Y M r < = $ + + + O + + O O + O + O + O O O O X o O O O O O O O O O . o o . . . X . X . O O O X $ % * ; 7 7 7 9 9 8 5 ; * + + ", +"2 2 r 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 Z.Z.Z.Z.Z.Z.+., , , , , , , 1 , , , 1 , , , , , > , , , > , > > , > , > > , > 5.Z.Z.Z.Z.Z.p.> > > : > : > > : : p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.u.- - : : = : : : & : - - & p.Z.Z.Z.Z.Z.Z.Z.Z.V & - & & - p v v v v v v v v v v v v p - # - # # & # # & & # # % % % % % # # % % % # # # # # $ # @ @ $ @ # # @ @ # @ @ @ @ @ + @ @ @ @ # + @ + @ % # = , w f A Q ..1.2.7.9.9.2.<. .Q A b 7 ; = # + + + + O + + + O + O O O O + + O O O O X O O X O O X X O . O . . . o . . . . . O O X $ + % % % = ; ; * * * $ % ", +"2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.2 1 2 1 1 2 2 1 1 1 1 1 1 1 1 , 1 1 1 1 1 1 , Z.Z.Z.Z.Z.Z.+.1 , , , , 1 1 , 1 , , , , , , , , > , > , , > , > , , > , : > > +.Z.Z.Z.Z.Z.u.: > > > > : > : : d Z.Z.Z.Z.Z.Z.u.Z.Z.Z.Z.Z.Z.t - : : & : : & : & & - & u.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & & p v v v v v v v v v v v v p - # - - & # - # # & & # & % % % % % % # # # # % % @ # @ % @ % @ # @ @ # @ # @ @ @ @ @ @ @ @ @ + + + @ + + # % # - < w n A R ^ ..>.>.>...^ Y A f 9 < = # % + + + O + O + O + + O + + O O O + X o X O O O O O O X . . o o . . . . O . . . + + $ $ $ $ $ $ $ $ $ + . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.2 7 1 1 1 2 2 1 1 2 1 1 1 1 1 1 1 1 , 1 , 1 1 Z.Z.Z.Z.Z.Z.+., 1 1 , , , , , , , , , , , , , , , , , , > , > > > > > > , > > +.Z.Z.Z.Z.Z.p.> > : : > > : > , %.Z.Z.Z.Z.Z.Z.j v.Z.Z.Z.Z.Z.4.- : & : : - - : - - - - u.Z.Z.Z.Z.Z.Z.Z.Z.Z & & - & & p v v v v v v v v v v v v p # # # # # & # % & # # # % % % % # # # % # % # % # # # % @ # @ # @ # # @ # @ @ @ @ @ @ @ @ + @ + @ @ + # @ # # % = - 1 e f B H Y Y Q Y Y S M y e 5 ; # % + + + O O + + O O X O O O O O + O O o + X X O O O O O X O O o . . o . o . o o X o X . . . O X X O + + + + O X X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 Z.Z.Z.Z.Z.Z.p.1 1 2 1 2 1 1 1 1 1 2 1 1 1 1 1 1 , , 1 1 1 , Z.Z.Z.Z.Z.Z.+.1 , , , , , 1 , , , , , , , , , , , , , , > , > , , > > > , : , +.Z.Z.Z.Z.Z.u.: > > : > > > : 1 B.Z.Z.Z.Z.Z.b.: %.Z.Z.Z.Z.Z.B.7 : : : & - - - - : & : p.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & & p v v v v v v v v v v v v p # - & % - # % % # # & & % % % % % % % # # # # # # # @ % % @ @ $ @ @ @ @ @ @ @ @ @ # @ @ @ @ + @ # + # + @ + @ % # = ; < 0 t f m B B B m f r w < = % % % + + + + + O + + + + O X O O + O + O o o O + O O O O O O X o o . . o . . . o X X . . X X . . X . O . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Z.Z.Z.Z.Z.Z.&., 1 , 1 1 , , , , 1 , , , , , , , , > , , , > , > > , , > > , , u.Z.Z.Z.Z.Z.%.> : > > : : : : ` Z.Z.Z.Z.Z.Z.| : d Z.Z.Z.Z.Z.Z.} : & & : - - : & - - & u.Z.Z.Z.Z.Z.Z.Z.Z.F & & & & & p v v v v v v v v v v v v p # - # # - # & % # & # # % % % % % # # # % # % # $ # % @ @ % @ % @ @ + - @ @ @ @ @ @ @ + @ @ @ # + # + @ + @ + + # % & ; > 7 0 w e r e e 1 < - ; * % + + + + O + + + O + + O + + O + O O O O O O O O O O O X X O X o . . o . X O . . . O O . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 b.Z.Z.Z.Z.Z.k., 1 1 , , , , , , , , , , , > , , , , , : , , : , > , > > > > 0 Z.Z.Z.Z.Z.Z.| , > : : > : > : v.Z.Z.Z.Z.Z.Z.t : : k.Z.Z.Z.Z.Z.v.: : & : : & : : - : & p.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & & p v v v v v v v v v v v v i = % % & # % & # - - @ - + - + - % % % % # % # # % # # # # # # % @ @ # @ # @ @ @ @ @ @ + @ @ @ + # + @ @ + + @ @ @ # # # - - ; > , > < > - ; % # # @ + + + + + + + + + + $ + + X + O + O O X O O X O O O O O O O . X O O X X X X X O + + X X X X X . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 Z.Z.Z.Z.Z.Z.f.1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.Z.Z.Z.Z.Z.Z.J , , , , 1 , , 1 , , , , , , , , , , , , , , , > , > , > > , X.Z.Z.Z.Z.Z.Z.h > > > > > > , D Z.Z.Z.Z.Z.Z.k.: : : } Z.Z.Z.Z.Z.Z.I : : & & : & & - & - u.Z.Z.Z.Z.Z.Z.Z.Z.V & & & & & p v v v v v v v v v v v v p % # & # # & # & + + - + - + - + % # % # # % # # # # # # # @ + # - # @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ + # @ + + @ @ @ # # # # # - ; & ; % * # $ @ $ + + $ + + + $ + $ % $ + @ $ + @ + + O X + O + X + O O O X X . O O O X X O X O + + + $ + + + O O O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 Z.Z.Z.Z.Z.Z.p.1 2 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 [ Z.Z.Z.Z.Z.Z.k.e , 1 1 , , , , , , , , , , , , , , , , , , , , > , > > > m B.Z.Z.Z.Z.Z.v.> > > > > : : > r.Z.Z.Z.Z.Z.Z.X.: : : d Z.Z.Z.Z.Z.Z.u.& : : : : & : & - & p.Z.Z.Z.Z.Z.Z.Z.Z.k.u.u.u.u.u.s.d.d.d.d.d.d.d.d.d.d.d.d.s.u.$.% & & # & # - + + - + - + - % # # # % % # # # # # # # # % # + @ @ @ @ @ @ @ # @ @ @ + # + # # + @ + @ @ @ + + + + # # @ @ # # # @ $ # $ @ @ + + + + + # @ $ * # * = & * * @ @ + + + + O O O O O O O O O O O . . O O O O + + $ $ $ * $ * $ $ $ + + . X . X ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.2 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 , 1 1 1 1 , 1 e B.Z.Z.Z.Z.Z.Z.B.p.p.p.p.p.p.i.i.i.i., , , , , : N i.i.i.i.i.u.p.u.p.p.p.Z.Z.Z.Z.Z.Z.Z.O.: > > : : > > t Z.Z.Z.Z.Z.Z.Z.7 : : : - k.Z.Z.Z.Z.Z.Z.e : & : & : : - : & u.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.u.& % # & # & + - - + - @ - + % % # % # # % # % # # # # @ @ @ @ @ @ @ # @ # @ @ @ + @ # + # + + # + @ + + + @ @ @ + @ @ @ @ @ @ @ @ + @ + + + + + + @ @ @ * = ; > : 5 : ; = & # # % + + + O O O O O O X O O o . O O O + + $ % * * * ; = = = * * $ $ + O X . ", +"2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 1 Z.Z.Z.Z.Z.Z.p.1 2 1 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 , 2 1 1 +.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , , , , , F Z.C.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.M.1 : > > > > : > %.Z.Z.Z.Z.Z.Z.r.: : : : : ` Z.Z.Z.Z.Z.Z.4.- - : : & & - : & p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.u.% % - - - - - @ - + O $ - - % % # # & % # # # # # # @ # @ # @ @ - # @ @ @ @ @ @ @ @ @ @ + @ + @ + + @ + @ + + + @ + + @ @ + $ + + $ + + + + + + + # * ; > 5 7 e w e e 9 7 5 : * * + + + + X O O O O O O O O O O + + $ $ % = : 5 9 9 e 9 9 5 ; * * @ X X X ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 1 2 Z.Z.Z.Z.Z.Z.p.1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , , 1 e k.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , , , > , F Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.W : : > > : > > 7 B.Z.Z.Z.Z.Z.Z.` : : : : : 7 Z.Z.Z.Z.Z.Z.B.7 - & : & : - & & u.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.t.% % + $ + O @ - + - - + - + # # # # # # # # # # # % # # # @ @ @ + @ @ @ @ @ @ + @ @ + @ @ @ @ @ @ @ + @ + @ @ + + + + + + + + + + + + + + + @ # $ % = > 0 e f m M M C b f e 9 : & $ $ + + X O O O O O X X O O O + + $ = = 6 e r b b C b b f e 6 ; & $ $ X ", +"2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 Z.Z.Z.Z.Z.Z.p.1 2 1 1 1 1 1 1 2 1 1 1 , 1 , 2 1 1 1 , 1 1 1 , , C k.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z., , > , , , F Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.W : , : , : > : > ` Z.Z.Z.Z.Z.Z.B.7 : : : : : : r.Z.Z.Z.Z.Z.Z.} - & : : & - & - p.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.t.- ; - - ; - - - - @ ; - - $ % # # # # # # # % % # # @ # # # - + @ @ # # @ @ @ @ @ + @ @ @ @ @ @ @ + + @ @ @ + @ + + @ + @ + + + + + + + + + @ $ * = < e s B G U R R T K G M s 9 5 = $ $ + O X X O X O O O X O + + $ * > 9 s m S K T T T K G m r 7 ; * $ X X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 p.p.p.p.p.p.3.1 2 2 1 2 1 1 1 1 1 1 1 2 2 1 , 1 1 1 1 1 1 1 , 1 1 , [ 0.p.p.p.p.p.p.p.p.p.p.p.p.p., , , , , > N p.p.p.u.u.u.p.u.p.u.p.p.p.p.&.d , , : , : > > > : %.u.p.u.p.u.p.+.: : : : : : - I u.u.u.p.u.u.4.- : : & : - - & I B.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.t.; 4 3 ; 3 3 ; 4 8 ; 4 4 ; 4 , > 4 4 4 4 4 < 3 3 3 3 3 3 3 3 - + @ @ @ @ @ @ @ @ @ @ @ @ @ + + @ @ + @ @ + + + # + # + + + + $ + + + + + + + @ # ; > 0 f A K ! { ;.>.:...! Y A f w : * $ + + + O O O O O O O O + $ * : 7 s M Y ! .;.:.-.{ R Y C s 7 = % $ X . ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 1 1 1 1 2 1 2 1 1 2 2 1 1 1 1 1 1 1 2 1 , 2 , 1 1 1 , 1 1 1 , 1 , 1 , 1 , , , 1 , , > , , , , , , , , , , , , > , > , > > > > > , > : , , : , > , : : > > : : : , : : : > : : : : : : : : : : : - : : - : : & : & : - - - - - & V D V V V V V V V N V V E ] ] ] ] ] ] ] ] ] ] ] ] ] ] ' v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v ; O - o O - O O + $ O + - + - O @ @ + @ + @ + @ + + + @ + + @ + + @ + + + + + % + = : 7 f S T ..<.2.8.9.7.2.<.{ R B y 7 : * + + O O O O O X O + + + # : 7 s A Y { >.2.8.8.8.2.>.{ T A s 5 = $ + + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 2 1 2 2 2 2 1 2 1 1 2 1 1 1 1 1 2 1 1 , 1 2 , , 1 1 , 2 , 1 , 1 , , , , 1 , 1 , , 1 , , , , , , , , , > , , > , , , > > , > , > > > > , : : > , : : , : > > : : > : : > : : : > : : : : : : : - - - : : & & : & : : & - - & - & - & - - & & - & - - & & & i v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v ; - o - - + + - O - - $ O + - + + @ @ + @ + + @ @ + @ + + + + + + + + + + + + + * = 5 e M K .1.9.g.h.h.j.q.9.1.{ Y M e > & @ + + O O O O O O O + @ * : e b U { <.7.f.h.h.h.f.8.1.{ K b e ; % X X . . ", +"r 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 2 1 1 2 1 1 2 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 , 1 , 1 , 1 1 1 1 1 , , , , , , , , , , , , , , , , , , > , > > , > , > , > > > > > , , , : : > > : > : > : > : : , : > : : : : : : > : : : : - : - : : : : : & : : - - - - - - - & - & & - - & & & & & i v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 3 $ - o - O O - + + - + + @ O + + @ + @ @ + @ + + @ + + @ + + + + + + + + + + % # : 7 b S ! <.9.h.l.x.m.x.l.g.9.>.~ A b 7 = % + + X O O O O O O + % = 5 s S ! >.8.h.l.z.m.z.l.h.8.>.R S s 5 * $ + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 2 2 1 2 1 1 1 1 1 1 2 2 1 1 1 , 1 1 1 1 1 1 1 1 , 1 1 , , 1 , 1 , 1 1 1 , , , 1 , , , , , , > , , , , , , , > > , : , > , > > : , : : , : : , > > > : : > : : : : > : : : > : : : : : : : - : : & : & : & : & & - & - - & & & & & & - & & & & & ; i v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 3 O o - O - + O - o o + @ @ @ + @ @ + + + @ + @ + + @ + + + # + + + + + + + + # * > e m Y ..2.g.l.m.M.V.M.m.l.w.2.-.U b 7 ; % $ + O O O O O O + $ $ : 7 b U { 2.f.l.m.M.N.M.m.l.f.2.{ K b 7 * $ + . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 2 1 2 1 2 1 2 1 2 2 1 2 1 1 1 1 1 1 1 1 , , 1 , 1 1 , 1 1 1 , 1 , , 1 , , , , , , , , , , , , , > , > , , > , , > > > > > , > , > , > : , , : > : > > > : > > : > : : : > > : : : : - : : : : & : : & : : & : : : - - - & - & - - : & & & - & & & & & p v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 3 $ O - o - O - @ @ @ @ @ - O + + @ @ @ @ + @ + # + + @ + + + + + @ + + + + # $ & 5 e M T :.8.h.x.M.C.C.C.N.x.h.8.:.T m w : * $ + + O O O O X + + $ : w b R -.8.h.z.N.C.Z.C.M.z.h.7...T b e ; * + . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 2 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 , , , , , , , , , , , , > , > , , , , , , > > > > : , , > : , : , > > : > : : > : > : : : : : : : : : : : : - : : : : : & - : & & - - - - & - - & & - & - & & & & & & i v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v ; - - O + o O - @ @ @ @ @ + @ @ @ + + @ + @ @ + @ + + # + + @ + + + + + + + @ % & > r M R >.9.h.x.V.C.Z.C.N.m.h.9.:.R M e > $ + + O O O O X O + + * 3 w M R ;.9.h.m.B.C.Z.C.N.z.j.8.:.R b e ; % + . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 2 1 1 1 1 2 1 1 2 , 1 1 1 , 1 1 , 1 1 1 1 1 1 , 1 , 1 , 1 , , , , 1 , , , , , , , , , > > , , , , > > , > > , > > > , : : , : , : : : > : > > : : : : : : : : : : : : : - : : : : - : & : : : : : & & - - - - & & - & & & - & & & & - & u v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 3 o - - - - O O + - @ @ O - + @ @ @ @ + + @ + @ + + + + + + + + + @ + + + $ + @ = 5 e M R :.8.h.x.N.C.Z.C.M.x.j.7.;.T C e > * + + O O O O O O + + % ; w b R -.8.h.z.M.C.C.C.M.x.h.7.-.T b e = $ + . . ", +"2 2 r 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 1 1 2 2 1 2 1 1 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 , , 1 , 1 , 1 , 1 , , 1 , , , , , , , , , , , , , , , , > > , , > > , > > > , : , , : , : , : > : : , : : : , > > : > : : : : : : : : : - : - : & : & : & : & - - - & - - & & - - - & - & - & % - ; v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v 3 - o O O + + - + O @ @ + + @ @ + + @ @ @ + @ + + @ @ + @ + @ + + + + + + + + @ * : e b K ..2.w.l.m.M.V.N.m.l.q.2. .K m 9 : # $ O O O X O O X O $ $ ; 7 b Y { 2.f.l.m.M.B.M.m.l.f.2.{ K f 9 * $ + . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 1 1 1 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 , , 1 , 1 1 , , 1 , , , , , , , 1 , > , , , , > , , , , > , > > , > > > > : , , > : > > : > > > : > > > : : > > : : : : : : : : : - : : & : : - : - : : & : - & : & : - & : & - & & & & - & & & & - u p g z l l l l l l l l g l l k g l k k k k k k k k k k l l k l k k k k k k k k k k k k ; @ # @ # @ @ @ - + + - O O + @ @ @ + + @ + + @ @ + + + + + + + + + + + + + + % % : 7 f S ~ <.9.h.l.z.m.z.l.g.8.>.! G f 7 = $ + O O O O X O X + + $ * 7 s S ! >.8.h.l.z.z.z.l.h.8.>.! A s 5 % $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 , 1 1 1 1 , 1 , 1 , 1 , 1 1 , 1 , , , , , , , , , , , , > , > > > , > > > , > > , > : : , , : > > : > > : : : > : : : > : : > : : : : : : : : : : & - : : & : : & - - & : & & : & - & & - & - & & & & & & & & & & & - & & & % % & - # - - - - @ - - @ - @ - @ - # @ - + - # - @ + + - + - # + # @ @ # @ @ @ @ @ @ + + + O + - - + @ + @ @ + @ + @ + @ + @ @ @ + + + + + + + + + @ $ = 5 r M T ..1.9.q.h.h.h.f.9.1. .T m e 5 * @ + + O O O O X + O + $ & : e M Y { 1.8.f.h.h.h.f.8.1.{ U b 9 5 * $ ", +"r 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 2 1 1 1 1 2 2 1 1 2 2 1 1 1 1 1 , 1 1 1 1 , , 1 1 1 , 1 , , 1 , , 1 , , , , , , , , , , , , , , , > , > > , , , > , , > > > > > , > , : : , , : > : > > > > > > : : : : : : : : : : : : & : : : : : & : : & : : : & : - : & & & - & & & & - & & & - & & & & - # % & % % & & & # - @ - @ + + - @ @ - + - + - - @ - + - # + - - + - + + + - - + + - O @ # # @ @ @ - - o - @ @ O + @ @ + @ @ @ + + + @ + + + + + @ + + + @ + + + # $ * : 9 f A T ..<.2.8.8.8.2.>.{ T A s 7 = * $ + O O O O O O O O + $ $ = 7 r A Y { >.2.8.8.7.2.>.{ T C s 5 = $ + ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 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 , , , , , , , , , , , , , > > , > > , , > > , : , : , > > : > > > > : : : : : > > : : : : : > : : : - : : : : & : : & : - & & & : & & & & : & & - - & & & & & - # & - # & - # & & & & & # & & # - @ - - - + - - + - @ - + # + + - + # - @ + - @ + - - + + + - $ @ @ # @ @ @ @ + + + @ @ + @ @ + @ @ + @ + + @ + + @ + + @ + + @ + + + + + + + $ % = 5 e f A K ! ..;.>.;.{ { Y A f 9 5 = # + O O O O X O O X O O X $ & ; 7 s C U ! { ;.:.;. .! U C s 7 ; % $ X ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 1 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 , , , , , , , , , , , , , > > , > , , > > > > > , : : , : , > > > : > > : : : : : : : : : > : : : : : : : & : : : : : & : & & : - - - : - & & - - & & - - & & & & - - & & & & - & # % & # & # & - @ - @ - @ - # @ - + - @ # # - # - + - + @ + - - + + @ - + + + @ # @ # @ @ @ @ @ @ @ + + @ @ @ @ + @ @ + @ + @ + @ + + @ + + + + + + + + + + + @ $ # = 5 9 s M S K T R T U S M f w 5 * @ + + + O O O X O O o O O + + % * : 7 s m A K T T T K A m s 7 ; $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 1 2 1 2 2 1 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 , , , , , , , , , , > > , , , > , , > > > > , > > : , , : > : : , > > : > > > > : : : : : : : : : - : : : : : : & : & : : : : : : - & - & & : - & & - & & & & & & - # - # # & & # & & & & & & & # @ - @ - @ - @ @ - + @ @ - # - + # # # # @ - # + @ + - + + + - - @ $ - @ @ @ @ @ @ @ @ @ @ @ @ + @ @ @ + @ + @ + @ + + @ + + + @ + @ + + + + + + + $ % % = 5 9 e b m M C C b f e 7 : = $ @ + O O O O O + O X O X X + + $ = ; 7 e s b b m m b r e 6 = * $ ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 1 1 2 2 1 2 1 1 1 1 2 1 1 1 1 1 1 1 , 1 1 , 1 1 1 1 1 1 1 , 1 , , , , , 1 , , , , , , , , , , , > , , , , > > > > , , > > > , , , : > , , : : > > : > : : > > > : > > : > : : : : : : : : & : : & : - : & : & - & & - - & & - & - & - - & & & & & - & & & & & & & # & & # & % - @ - @ - + @ - # @ - @ - @ - # # # + # - # - + + - - @ - + + + - @ + + @ @ @ @ @ - @ @ + O @ + @ + @ + @ + + @ @ + @ + + @ + + + @ + + + + + + + + @ $ % = : 5 7 e e e e w 7 5 ; * # % + + + O O O O O O O O X X O O + $ $ * = 5 6 9 e w w 9 6 3 * * $ . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 1 2 2 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 , , 1 1 , , , 1 , , 1 , , , , 1 , , , , , , , , , > , > , , > > , > > , > > > , : : , : : , : : > : > > : : > : > : : : : : : : : : : : : : : : : : & & : & : & : - - & - - & - & & & & & & - & & - # & & & & # & & & & & % & @ - @ - # - - @ - - + - # # @ @ - # - # + # # # - + + + - + - + + # @ # # @ @ @ + O @ @ @ - + @ @ + @ @ + @ + @ + @ + + + + @ + + + + + + + + + + + + @ @ % * & : 3 : > : : * = & $ $ + + O + O O O X O O O O O . X O O X + + % & * = = = ; = = * $ . $ . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 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 , , , , , , , , , , , , , , , , , , > , : > > > > , , : : , : , : > > , : : > : > : : : : : : : : : : : : : : : : - : : - & : - : : & : & & : & & & : & - & & & - & - & & & & & & & & & & # & & & & # & # & # & & & # & # # & & @ # & @ # @ & @ @ & @ & @ @ @ @ @ @ @ & @ @ @ @ @ # @ @ @ @ @ @ @ X @ @ + @ @ @ + @ + + @ + @ + + + + @ + + + + + + + + + + @ + @ @ # % % & % & & # @ @ @ + + + X X + O O O O X O O O O O O O O + + $ $ $ * $ * $ + $ + O O O . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 2 1 1 2 2 2 1 1 2 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 , 1 , 1 , , , , , , , , , , , , , : , , , : , , : > > , : , > : , > , , : : : : : > > > > > > : > > : : > : : > : - : : - - : - & : : & & - - : & : : & & : & & - & & & & & & & & & & & & & & # & & & & # & & & & # # & # # # & # & # # # # & @ & # % # # % & @ # # @ & # @ # # @ @ @ @ @ # @ @ @ @ # X @ @ @ @ @ + @ + @ + + @ @ + + + @ + + + + + + + + + + + + + + + o @ @ @ @ # # # @ @ + @ + + + X o o o o O O O O O O X X O O X X O O + + + + + + + + + + O O . . ", +"2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 1 , , 1 1 , , 1 , , , , 1 , , , , , , , , , , , , , : , > , , , > > , : : , : , , : , : , , > > : : > : > : : : : : : : : : : : : : : : - : : : - : : & - & : & : : & : : & - & - & & & & & & & & & & & & # & & & & & & # & # & & & & & # # # & & # @ & @ & @ @ # @ % # @ @ @ @ # # # @ @ @ & # @ # @ @ @ # @ @ @ @ @ @ @ @ @ @ + + + @ + + + @ @ + @ + @ + + + + + + + + + o + + X + + + @ + + + @ + + + + + + X o O O o X X O O O O O O O O O O . X O O . O O + + . O + . O o . ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 1 2 2 1 1 2 1 2 1 2 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 , 1 , 1 1 , 1 , , 1 1 , 1 , , 1 , , , , , , , , , , , , : , , , > , , , > , , , , : , : : : , , : : > : > > : > : > : > : > : : : : : : : : : - : - - : : - : : : : & : & & : & : & & & - & & - & - & & & & & & & & # & # & # & # & & & # # & # & # & # & # & @ & # # & # & # # # # & # # @ & @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ X @ + @ @ @ @ @ + @ + + @ + + + + + + @ + + + + + + + @ o @ + + X o o + + o + + X + X X + o + O + X X + X O O O O X O O X X O . o O O . . . . o o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 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 , , , , , , , , , , , , , , , , , , > , > , : : , , , : , , , : : , , : : > > : : > > > : > > : : : : : : : : : : : : : - : : - - - - & : & & & : & & & & : & & - & & & & & & & & & & & & & & & & & & & & # # # & & & # & # # # & # # & & @ & # # # % # # % @ # # # # @ @ & @ @ @ @ @ @ @ @ @ @ X @ @ # @ @ @ @ + @ @ + @ + @ + + @ + + + + + + + + + + + + + + + o + o + o + + o + X + + o O O O O O o o o O O O O O O O o o O O X O X o . . . . . . O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 1 2 1 2 1 2 2 1 1 1 2 2 2 2 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 , , 1 1 , 1 , 1 , , 1 1 , 1 , , , , , , , : , , : , , > , , > , , , : , , , : : , , : , : , , : , , : : : > : : > > : : : : : - : - : : : - - - : - : : : : & : : & : : & : & : & - & & - & & & & & & & & & & & & # & & # & & & & & # # & # & # & # & & @ # @ @ @ & % # % # # & # # # # @ @ # @ @ @ @ @ @ @ @ @ # # @ @ X # X @ + @ + + @ + @ @ + @ + + + @ + + @ + + + + o + X @ + + + + + + + o + + + o o X + + O + o + O X O X O O O O O X o o X O O O . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 2 2 1 1 1 1 1 2 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 , , , , , , , , , , , , , , > , : , , : , : , : : > , : : , : : : , : : > : > : : > : : > : : : : : : : : - : : - - - - : & : & : & : & : & & & - & & : & - & & & & & & & & & & & # & # # & # & & # & # & # & # & # % # @ # # & % # % @ # % # # # # # # @ # # @ @ & @ @ @ # @ @ @ @ # @ # X @ @ + @ + @ @ + @ + + @ + + @ @ + + + + + + + + + + + o o @ + + + X + + o o X o + + O O O O o + + o O O O O O O O X O O O O o X o . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 1 2 2 1 1 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , , 1 1 1 1 , 1 , 1 , 1 1 , , , 1 , , , , , , , , , , , , , , : , > , , > , , , , : > , > , , , : , : , , : : > > : > : > : : : > : : : : : : : - - : - - : - : - & : & : & : & : & & : & & - & & & & - & & & & & & & & # & & & & & & & # & # & & # & # # # & & # & @ & # % % % % # # # % @ # # # # # @ # @ @ @ @ @ @ @ @ @ @ # X # & X @ @ @ @ + @ @ + @ @ + @ + + + + + + @ + + + + + + + X @ o + X + X + o + + + X o + O + + O O X o o O O O O X O X o o O X . . . . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 1 2 2 1 2 1 1 2 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 , , , , , , , , , , , , , , , : , : , > > > > > > > > > , : , : : > : : > : > : : : > : : : : : : : - : - : : : : & : & : & : & : & - - & - & - & - - & & & & & & & & & & & & & # & & & # & & # & & # # # & # & @ & # # @ & # # % # @ # # # # # @ # # # @ @ # # # @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ @ @ + + + + + + + + + + + X + + + + + X + + X + + + + + X + O O O O O + + X X O O O O O O X O . o . . X O O O O . . o . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 2 1 1 2 1 2 2 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 , 1 , 1 , 1 , 1 1 , 1 , , , 1 , , 1 1 , , , , , , , , , , , , : , , : , , , , , , , , , : > > > > : > : , : > > > > > > : : > : : : : : : : : : : : - : - & - - : & : : & & : : & & & - & - & & & & & & & & & & & # & & # & # & & & # & & & # # & & & & # & # & @ & & # # % % & # & # # % @ % # # @ @ # @ @ @ @ @ @ @ @ @ @ @ @ # X # # X + @ + + + @ + @ + + + + + @ + @ + + + + + + + + + + + + + + X + + X o O O + X o + O O O O O + o O O O O O O X X . o o . o . o . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 2 1 1 2 1 2 1 2 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 , 1 , , , , 1 , , , , , , , , , , , > , , , , , > > : > > : , > > > > : , : : > > : : > : : : : : : > : : : : : : : - - : - : : : : & : : & : & : & : & : & : & & - & & & & & & & & & & & & & % & & & & & # & # & & # # # # & # # # & @ & & @ & # @ # # # % % @ & & X @ @ @ @ @ @ @ # @ # @ @ @ @ @ X @ @ @ @ + @ @ @ @ @ + + + @ + @ @ + + + @ + + + + + + + o + X + X + o + o X + + + O + o O O + + o + o O O O X + X O O o O O o o . . . O O . . o o O . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 2 2 1 2 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 , 1 1 , , 1 , 1 , 1 , 1 , 1 , , , , , 1 , , 1 , , , , , , : , , , : , : , , : , > , > , > > > > : : , : > : > > > : > > > : : : : : : : : - : : : : - : & : : : : & : & : & : & & : & & : - & & - & - & & & & & & & & & & & # & # & # & & & # & & & & # # & & @ & @ @ & # @ & # # % @ @ @ @ @ & & @ @ @ # # @ # @ @ @ @ @ @ @ @ X @ @ @ @ @ + + @ + + @ @ + + @ + + + @ + + + + + + + + + + + + + + + + + + o + o + + + O + O O X O X O O O X O X X O O . O . o o . . . O . . o o ", +"2 2 y 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 2 1 2 2 1 1 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 , 1 1 1 , 1 1 1 1 1 1 1 , 1 , , 1 , , , 1 , 1 , , , , , , , , , , , , , : , > , > > , : , , > > > > > > > > > > : : > > > : : > : : : : : : : : : : : - : : - : & : & - - : & & : : & : & & & & & & & : & & & & & & & & & & & & & & # & & & # & & # & & # & & # # & # & @ # # # # # # # # # # @ & & @ @ @ @ & @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + + @ + + + + @ + + @ + + + + + + + + + + + + + + o + + o + + o O O + O X O O O O + O O O O O O O O O O O O O X X . . O o . o . o . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 1 1 2 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 , , 1 , 1 , 1 , 1 , , 1 , , , , , , , , , , , , , > > , , > , > , > , , , : , : > > > > : > > : > > > : : : : > : : > : > : : : : : : : : - - : : & : : - - - - : & & : & : : & : & & & & & & - & & & & & & # & & & & & & # # & # & & # # & # # & # & # @ & & @ @ & & # & # % # @ @ @ @ @ @ @ @ # @ # # @ @ @ @ X @ @ @ @ @ @ @ + @ + @ @ + @ @ + @ @ + + + + + + + @ + + + + + + + + + + + + + O + + O + O + X + + O O o O O + O O O O O O O O O O O O O X o O o . . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 1 1 2 1 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , , 1 1 , 1 1 1 , 1 , 1 , , 1 , 1 , , , , , , , , , : , , , , , , > , > , > : , : , > > > > > > > > > > > > > : > > : > : : > : : : : : : : - : - : - - : - - - - & - & : & & & : & & & : & - & - & & & & & & & & & # # & # & & # & & # & # & & # & # # & # & # @ & # # # # # @ # % # @ @ @ @ & @ & @ @ @ # @ @ @ @ @ # @ @ @ @ @ X @ @ + @ + @ + @ + @ + + + @ + + + @ + + + + + + + + + o + + o + o + + O + O + O + O O O + O O O O O O O O O O O X o O O . O . X O o o o o . ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 2 1 2 2 1 2 2 1 2 1 2 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , , 1 , 1 1 , 1 , , , , , , , , , , , , , , , > , , > , , > , > , > , , , : > > > > > > > > : : : > > : > : : : > : : : : : : : : : - : - : : - - : - - : - : & : & : & & : & & & & & & & & & & & & & & & & & & & & & & & # & # & & # & # & # # & # & # @ # & @ & @ # # # # & @ & @ @ @ @ @ # @ # @ # @ @ @ @ @ @ # X @ @ @ @ @ + @ + @ + @ + + + @ + @ + + + + + + + + + + + + + + X + + + O O + O + O + O O + O + O + O O O O O X O X O O O . . O o O o . . . . . ", +"2 2 2 2 2 2 2 2 y 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 , 2 1 1 , , 1 , 1 , 1 1 , 1 1 , 1 , , , , , , , , , , , , , , : , , : , , : , , : , , , > , > > > : , : > > > : > : > : : > : : : > : : : : : > : : : : : - - - : : - - : - - - & : & & & : : - & - - & - & & & & & & & & & # & & & & # & # & # & & # & # & # & # # & # & # & & & # # & # # # # # # # # # # @ # # @ @ @ @ @ # @ @ @ @ X @ @ @ @ @ @ @ @ X @ X @ + @ + @ + + @ + + + @ + + + + + + O + + + + + + + + X O + O O O + O + O O o X O O O O O O O o o o X X o O X . O O O O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 2 1 1 1 1 2 1 2 1 1 1 1 1 1 1 2 , 1 , 2 1 1 1 , 1 , 1 1 , , 1 , 1 , 1 1 , , 1 , , , , , , , , , , , , , , , , , > , : , : > , : , > , > > > > > > : > > : > : > : : > : : : : : : : : : : - - - - - - & : : & : & : : & & & & & & & - & & & & & & & & & & & & & # & & & & & & # & & # & # & # & # & # # # @ # # # # # # & # # # # # # # # @ @ @ # # @ @ @ @ @ @ @ @ @ @ @ @ @ X @ @ X @ @ X @ + @ + + + @ + + @ + + + X + + + + + + + + + X o + O + + O + + O + O O O X + O o O O O O O O o O O O O o O O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 1 2 1 2 1 2 1 1 2 1 2 1 1 1 1 1 1 1 , 2 1 1 1 , , 1 1 1 1 , 1 , , 1 , 1 , , 1 , 1 , , , , , , , , : , , , , , : > , : , , : , : : , > > > : > > > : > : > : > : : > : > > : : : : : : : - - : : : - - : & : - - & : - & : & : & - & & & & & & & & & & & & & & & & & # # & & # & & # # & # & # & & # # & & # # & # # # # # # # # # # # @ @ # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ X @ X @ @ @ + + + + + + + + + + + + + + + + + + + O o + + + + O + O O O O o O O O + + O O O O O O O O X O O X O o o O . O O O O O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 2 2 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 , 1 , 1 1 1 , 1 , , 1 , 1 , , , , 1 , , , , , , , , , , , , , , , , : , , , , , , : , > , , : , : > > > : : > > > : > : > : : : : : : : : : : : : : : : - - - - : - - - - : & : & & : & & & - - & & - & & & & & & & & & # & & & & & # & & & # & # & # & # # # & @ # & # # & # # # & # # # # # # # # # # # # @ # @ @ @ @ @ @ @ @ @ @ @ X @ @ @ @ @ @ @ @ X @ + @ @ + @ + @ + + + + + + + + O + + + O + + X + o + + o + + + O + O O o O + O O X O O O O O X O O X O O O O O O . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 1 2 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , 1 , 1 , 1 , 1 , , , , , , , , , , , , , > , , , > , , > , , > : , : , > : , , : , : > > > : : > : > > : : > : : : : : : : - : : : - : - : - : - - - - - & : & & - & : : & - & & & & & & & & & & # & & & & & & & # # & & & # & & # & # & & # # & # # # # # & # # # & # # # # # & # # @ @ @ @ # @ # @ @ # @ @ @ X @ @ @ @ @ @ @ @ @ @ @ @ + @ + + @ + + @ @ + + + + + + + + + + + + X + + O + O + o + + X + O O O O O O O O + X O O O O O O O . . o . O O O O o O O o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 1 1 2 2 1 2 2 1 2 1 2 2 1 2 1 1 1 1 1 1 , 1 1 1 1 1 , 1 1 , 1 1 , 1 , 1 , 1 , 1 1 , 1 , , , , , , , , , , , > , , > , , : , > , , , : , : , : > > > > > > > > > > : > : > : : : : : : : : : : - : : - - - : - - - - - - : & & : & : & & - & & & - & - & & & & & & & & & & & # & & & & # # & # & & # & # & # & # # & # # # # # # # # # # # # # # # # # # # @ # @ @ @ @ @ @ @ @ @ @ @ X @ @ @ X + X @ @ X @ + + + + + + + + + + + + + + + + + + + + o + o + X + O + o O + X X + + O O O O O O X X O O O . X O . o . o o O O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 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 , , , , , , , , , , , , , > , > > > , , : , : , , : > , > > > > > > : > > : : > : > : : : > : > : : : : : : - : : - - : - - - - - - : & : & & & : & & & & & - & & - & & & & & & & & & & & # & & # & # & & # & # # & & & # # # # # & # % & # # # # # # # # # # @ # # @ # # @ @ @ @ @ @ @ @ X @ @ @ @ @ X + @ X @ @ X @ + + @ + @ + + + + + + + + X + + + + O + + + + + + O + + O + X O O O O O + + O O O O O O O O . . o . o o . O o O o O O o ", +"2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 2 2 2 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , 1 1 , 1 , 1 1 , , , , , , , , , , , , , , > > , , , > , : , , , : , : , , : > > > > > : > > : > > : : : : > : > : : : : : : : : - : : - : - - : - - - - & : & : : & & & : - & - & & & & & & & & & & # & & # & & # & # & & & # & # & & # # # # & & # & # % % # # # # # # # # # # # # @ @ # # @ @ # @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + + + + + @ + + + + + + + + + + + + + X + o + X + O o O + o + O + O O O O O O O O O O O . . O X . . . . o o o O O o O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 1 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 1 , 1 , 1 , 1 1 , 1 1 , , , , , , , , , , , , , : , , , , > , , > , , , : > , : : , : > > , > > : > > > > : : > : > : > : : : : : : : : : : : - : : : & : : & : : & : & : & : : & & & & - & - & & & & & & & & & & & & & & # & & & # & & # & & @ & # & # # # # & # & % # # % # # # & # # # # # # # @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ X @ @ @ @ + @ + @ X + @ + + + @ + + @ + + + + + + O @ O + O + + + O + + X + O O + O O O O O X + X O O O O O X X o O O . . o . . . O o . . o . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 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 , , , , , , , > , , > , > , > : , , , , , , : , > > > > > > > : : > > > > : : : : > : : : > : : : : : : : - : : : & : : : & : & : & : & & : & : & & & & & & & & & & & & & & # # & & & & # & & # & & # # & # & & # & & & & # # & # % # # # # @ # # # # @ # @ # # @ # @ @ @ @ @ @ @ @ @ @ @ @ @ @ X X @ @ @ @ + @ + @ + + + + + + + + @ + + + + + + + + O + o + + + O + X + O O O + O X + X O X O O O O O O O o . . . o . . . . o o o . . O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 2 2 1 1 2 1 2 2 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 , 1 1 1 1 1 , 1 , , 1 , , , 1 , 1 , , , , , , , , , , , > , , , , > : , : , > : , , > > , : > > > > > : > : > : : > > : : > : : : : : : - : - - : - : : : & : & & : : & : : & : & & - & - & & & & & & & & & & # & & & # & & & & # & & # & # & # & # # # # # # # # # # % # # # % # # # # # # # @ # @ # @ @ @ # @ @ @ # # @ @ @ @ @ @ @ @ @ @ @ + + @ + @ + + + @ + + + + + + + + + X + + + + + O + + O + O O + X O + + O + X o + + o O O O X O X X o . O o . o o o o . O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 1 1 1 1 2 2 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 1 1 , 1 , 1 1 , 1 , 1 , 1 , , , , , , , , , , , , , , , , : , , > , , , , > , > > , : : > > > > > > > > : > : > > : > : : > : : : : - : : : : - - : & & - : : - : & : & & & & & : & & - & & : & & & & & & & & & & & & & # & # & & & # & & # & # & & # & # # & & # # # # & & # # # # # # # # # # @ @ @ # @ @ @ @ @ @ X @ @ @ @ X @ @ X @ @ @ X @ + @ + + @ + + @ + + + + + + + + + + + O + + + + O O + + X + O + O O O + X O O O O O O O X O O X o o . . . . o . o . o . o . O O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 1 1 2 1 1 1 2 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 , 1 , 1 1 1 1 , 1 , 1 , , , 1 , , , , 1 , , , , , , , , , , , , , : , , : : , > , > , : , : > : > > : : > > > : > : : > : : : : : : : : : - : : : : : : : : : & : & : : & : : & : & & & & & & - & & & & & & & & & & & & & & # # & & # & & # & # & # & & # & & # # # # # # % # % # # # # # # @ # # # # @ @ @ # @ @ # @ @ @ @ @ X X @ + @ + @ @ + + @ + + + + + @ + + + + + + + + + + + X + + + + + X + + X O O + O O O O O O O + o O O O + O O . . O . o o . . . . . . . o O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 1 2 2 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 , , , , , , , , , , , , , , , , , : , , : , : > : , : , > > > : > > : : > : > : : : > : : : : : : : : : : : - : : & : & : & & : & & : & : & & & & - : & & & & & & & & & & & # & & & # # & & & # & # # & & & # & # # # # # # # & # # # # # # # # # # # # # # # # @ # @ # # @ @ @ @ @ @ @ @ # @ @ + @ @ @ + @ @ + + @ @ + + + @ + + + + + + + + + + + + O + X + + + X O + + O + X + + O + O O + X O O O O O . O . O . . o o . . . o o . . . O O ", +"2 2 2 2 2 2 2 2 1 2 2 2 2 , 2 2 1 2 2 1 1 2 2 1 1 1 2 1 1 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 , 1 , 1 , , 1 1 , , , , , , 1 , , , , , , , : , : , : , , , : , > > > : > , : > > > > > > > : : : > : > : : > : : : : : : : : & : : & : & : - : & : & & : : & : & : & - & & - - & & & & & & & & & & & & # & & & & & # & & & & # & & # & # & # & # # & & # % # # # % % # # # # # @ @ @ # # @ @ @ @ @ @ @ X # @ @ @ X @ @ @ @ + @ + @ @ @ @ + + + + @ + @ + + + + + + + + + + + + O + + O + + O O + + O O O + O O O o O O O O O O O . . o o . . . . . o o o . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 2 2 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 , , , , , , , , , , : , , , , , , > > , , > , , > , , : , > > > : > : > > > > : : > : > : : > : : : : : : : : : : : : - - : & : - : & & : & : & & - & & & - & & & & & & & # & & & & & & & # # & & # & # # & # # # & # & # # # & # # # # % % % % @ # # # # # # # # @ # @ # @ @ @ @ @ @ @ # @ @ # @ @ + + @ + @ + + + + @ + @ + + + + + + + + + + + + + + X + + O + + + O + + O O + O + O O O O O o O O O O O O . o . O . O o . . . o . o o O O ", +"2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 1 2 2 2 1 1 2 1 2 1 1 1 2 1 2 , 1 1 1 1 1 , 2 2 , 1 1 1 , 1 1 , , 1 1 , , 1 1 , , , , , 1 , , , , , , , , > , , > , > , > , : > , : , > : : , : > > > > > > : > > : : > : : : > : : : > : : : : : : - : - : - : & & : - & : : : & : & & : : & & & & & & : & & & & & & & & # & & & # & # & & & & # & # & # # & # # # & # & # # & # # # # # # # # # # # # @ @ - @ @ @ @ o - + o - @ @ @ @ @ @ @ + @ + + @ @ + @ + @ + @ + @ + + + + + + + + + + + + + + + + o + + X X + O + + X + + O O o O O O O O X X O X O X O o o O o O X X O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 2 1 1 2 2 1 2 1 1 2 1 2 1 1 2 , , 1 1 1 , 1 1 1 1 , 1 , , 1 , 1 1 , , 1 , 1 , , 1 , , , , , , , , , , > , > , , , , , , : , , , > , > , : , > : > > : > > : > : : > : > : : : : : : : : : - : - - : : : : - : : & & & : : : & & : & : & & & & & & & & & & & & & & & & & & & & # # & & # & # & # # & & # # # & # # # # # & # # # # # # # # @ @ # + # @ o @ - o @ @ + @ @ @ + @ + @ @ + @ @ + @ @ + + @ + + + + + + + + + + + + + + + + X + + + o + o + + O + O O X X O O O + O O O O O + O O o X O O O O X O O X O o o O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 1 1 1 2 , 2 1 2 1 1 1 2 , 1 , , 1 1 1 1 1 , 1 , 1 1 , 1 , 1 , , , , , , , , 1 , , , , > , , , > , > > , : , : : , , : > : , : : > > > > : > : > > : : : > : : : : : : : : : : : - : - : - : : & & : & & : & : & & & & & & : & & & & & & & & & & & & & & & # & & # # & & & # & # & # & & & # & & # # # # & # & # # # & # # # # # # # # + @ @ - @ - o @ @ @ @ @ @ @ + @ + @ @ + @ @ + + @ + @ + + + + + @ + + + + + + + + X X + + + + + + o o + O O O o + o X O O O + O O O O O O O X X o o O X o O X o o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 2 1 1 1 2 1 1 1 1 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 , , , , , , , , , , , > , , , > , , , > , , > > , > > : , > > > > > > : > : : > > : : > : : > : : : : : - : : - : : : & : : - : & : & : & : & : : & & & & & & & & & & & & & & # & # & & & # & & & # & # & & # & # # # # # # # & # # # # # # # # # # # # # # # # @ + - @ @ @ o - + @ @ @ @ @ + o - + @ + @ @ + @ + + @ + + + @ @ + + + + + + + + + + + + + X + o + o + + O + + O + X + + o O O O O O O O O O O X X . . . . o O o O X . O O ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 1 1 2 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 1 1 , 1 , 1 , 1 , , , , , , , , , , , , , > , , , , , > > , , : , , , : > > , > , : > > : > > : > > : > > : > : : : : : : > : : - : : : - : & : : & : & : & : & : & & : & & & & & & : & & & & & & & & & # & & & & & & # # & & & # & # & # & # & # # # # # & & # # # & # # # # # # # # # # @ + + - o + + @ o + @ @ + @ @ + + @ @ + @ @ + + @ @ @ + + + @ + + + + + + + + + + + X + + + + + X + X + O + O o O X + O O O O O O O O O O X O o . o O . . o o o . o . X O O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 2 2 1 2 2 2 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 , , , , , , , , , , : , , , > , , : , > , > , : : , : > > : > > > > : > > : : > : > > > : : : & : : : - : - - : - & : - - - : : & & : : & : & & : & & & & & & & & & # & & & & & & # & & & & & & # & & & # & # # # & & # & # # # # # # # # # # # # # # # # @ # - + o - - @ @ - - o @ @ @ + @ @ @ + + @ @ + @ + + + + @ + + + + + + + + + + + + + + + + X + X + X + O + O + + o O O + + + O + O O O O O o X O . X o o O o O X O o . . O . O ", +"y 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 2 1 1 1 1 1 2 1 2 , 1 1 1 2 2 1 1 1 1 1 1 1 1 1 , 1 1 1 1 , , 1 1 , 1 , , , , , , , , , , , , , , , : , > , , > > > > , > , > : , : : , : , , : : > > : : : : > : > : : : : : : : : : : : - : : - : : & : & : & & & : & & : & & : & & : & : & & & & & & & & & & # & # & # & # # # # & # # & & & & # # # & # & # & # & # # # # # # # # # # @ # # @ + @ @ @ @ @ @ o - @ @ @ @ + @ + @ @ + @ + @ + @ + @ + + @ + + + @ + + + + + + + X + + + + + X + O + O + o + + + X O O O + O O O O O O X O X . . . . o X O X . o . . O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 1 1 2 2 1 2 1 2 1 2 1 1 1 1 1 2 , 1 1 1 1 1 1 1 1 1 , 1 , , 1 , 1 1 , , 1 , , , 1 , , , , , , > , , , , > , , , , , , , , , : , : > , > , , : , > : > > > : > > > > : : : : : : : > : : : : : : : : - : : - : - : - - & : : & & & : & : & & & & & & & & & & & & & & & & & & & & & & & & & # & & # # # # & & # # & # # # # # # # # # & # # # # # # @ # @ - @ @ @ @ @ @ @ @ + @ @ @ @ @ # + @ @ @ + + @ + @ + + + + @ + + + + + + + + + + + + + o + + + X + O + O + o X O O + O O O O O O O O O O O O o . o . O o X . . . . O O . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 1 2 2 1 2 1 1 1 1 2 1 2 , 1 2 1 2 , 1 1 2 , 1 1 1 1 1 , 1 1 1 , 1 , 1 1 , 1 1 , , , , , , , , , , > , > , , , > > > , : , , , > , > : , , : > : , > > : > : > > > : : : : > > : : : : : : : : & : & : : & : - - - - & : & : & : - & & & : & & & & & & & & & & & # & & # & & & # & # # & & # # & # & & # # & # # # # # # # # # # # # # # # # # # # # - o # @ @ @ @ @ + @ @ @ @ + @ + + @ @ @ + + + + @ + + + + + @ + + @ + + + + + + + + o + o + + + O + X + O O + + O + O + O + O O O O O O O O O O X . . . . o o . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 2 1 1 1 1 1 2 1 1 1 1 , 2 , 1 , , 1 1 , 1 1 , 1 , , 1 , , , , , , , 1 , 1 , , , , , , , , , > , , , > , , , : > , : > , : : , > > : > > : > : : : : > > > : : : : : : : : : : : : : : : : - : - - - - - & : & & & - - : & & & & & & & & & & & & & & & & & & # & & & & & # & & & # & # & # & # # & & # & # & # # # # # # # # # # @ # # - @ # @ @ @ @ @ @ @ @ @ @ @ @ + @ @ + @ @ @ @ @ @ + + @ + @ + + + + + + + + + + + + + + + + + o + X + + + + O O + O O O O O O O O O O X O O O X O X . . . . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 1 2 1 1 1 2 1 1 1 1 2 2 , 1 1 1 1 2 1 1 1 1 1 1 , 1 1 1 , , 1 1 , 1 , , 1 1 , 1 , , , , , , , , > , , , > > > > > : , : , > , , > , > > : : , > > > > : > > > : : : : > : : : : : : : : : : : & : : & - : & : - - - : : & - & & - & & & & - & & - & & & & & # & & & & & & # & # & & # & # # & # & # & # # & # # # # # & # & # # # # # # # # @ # @ o @ @ # # @ @ @ @ @ @ @ @ + @ @ + @ @ + @ + + + + + + + + + + + + + + + + + + o + + + o o + o + + O + O + O O O X + X + + O O + O O X O O O X O O X o o o o . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 1 1 2 2 1 1 2 1 2 1 2 1 2 1 1 1 1 2 , 1 , 1 1 1 1 , 1 1 , 1 , 1 , , 1 , , , , , , , , , , , , , , , > , , , > , , : , , > , : : , : , : , > : , : > : > : > : : > : > : > : : : : : : : : : : : : : : : & : : & - : & & : & : & - & : & : & & & & & & & & & & & & # & & # & & & & & & & # & # # & & # # & # # & # & # # # # # # # # # # # # @ # @ @ @ # @ @ @ @ @ @ @ @ @ @ @ @ + @ + + @ @ @ + @ @ + @ @ @ + @ + + + + + + + + + + + + + + + + + X + O + O + + + O O O O O O O X O O O O O O O X X O . . . . . o . o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , , 1 , 1 , 1 , , 1 , 1 , 1 , , , , 1 , , , , , , , , > , > > > , , , : , , : , > : , > , : > > > : > : > > : > : : > : > : : > : : : : : : : & : & & : : & : & & - & : & : - & - & - & - & & - & & & & & & & & # & & & & # & & # & # & & # & # & # # & & # # # # & # # & # # # & # # # # # # # # # # @ # @ # @ @ @ @ @ @ + @ @ @ @ @ # @ + + + @ + + + + + + + + @ + @ @ + + + + + + + + o + + + X + + O + + O + O + O + O O X O X O O O X o o O O o O O X o . o . o . . . . ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 1 1 1 1 1 1 1 2 1 1 1 1 1 2 1 1 , 1 , 1 , 1 1 1 1 1 1 , , 1 1 , 1 , , 1 1 , , 1 , , , , , , , , , , , , , > , > , , : , , , > , : , : , > > : , > : : > : : > > : : : : : : : : : : : : : : : : : : : : - : : : : & : & - & & - & - & & & & & & & & & & & & & & & & & & & # & # & # # & # & # & & & # # & # # # # & # # & # # # # # # # # # @ @ @ # @ @ @ @ @ @ @ + @ @ @ @ + + @ + @ @ + @ + @ @ @ @ + + @ + + + + + + + + + + + o + + + o + + X O + O O + O O O O O O O + O O O O O O O o O O O o o o . o . . . . . ", +"2 2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 2 1 2 1 1 1 2 1 2 2 2 1 1 1 2 , 2 1 1 1 1 1 1 2 , 1 1 , 1 1 1 1 1 1 , 1 1 , , , , , 1 , , , , , , , , , , , , , , , , > , , : , > , : : , , : , : : , , : : > > > > : > : : > : > > : : : : : : : : : & & : : & & : - - & : & & & - - & - & - & & & - & & & & & & & & & & # & & # & & & # # & & # & # & # # # & # # # & # # # # # # # # # # # # # # # # # # @ # @ @ @ @ @ @ @ + @ @ @ @ @ @ @ + @ @ + @ + + + @ + @ + + + + + + + + + + + + + + + + + + + X + + + X O O + + O X O O O + X O X O O O O O O O O O O . . o o . . o o ", +"2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 1 2 1 1 1 2 1 2 1 1 1 1 1 1 1 2 , 2 1 1 1 1 , 1 , , , 1 , , , 1 , 1 , , , , , , , , , , > , , > , > > , , > , , > , > > , , : , : > > : , : > > : : > > : > : : : : : : : : : : : - : : : : & : : : & : - - : : & : & - - - & & - - & & & & & & & & & & & & & & & & & # & # & # & & # & # & # # & # # # & # # # & # # # # # # # # # # # # # # @ @ # @ @ @ @ @ @ @ @ @ + @ + @ + @ + @ @ + @ @ + + @ + + + + + + + + + + + + + + o + + o + o + + X X + O + O + O + O + O X O O O O O O O O O O O . o . . . . . o o " +}; diff --git a/pcsx2/Linux/Config.c b/pcsx2/Linux/Config.c new file mode 100644 index 0000000000..05a5214f17 --- /dev/null +++ b/pcsx2/Linux/Config.c @@ -0,0 +1,151 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include "Linux.h" + +#define GetValue(name, var) \ + tmp = strstr(data, name); \ + if (tmp != NULL) { \ + tmp+=strlen(name); \ + while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ + if (*tmp != '\n') sscanf(tmp, "%s", var); \ + } + +#define GetValuel(name, var) \ + tmp = strstr(data, name); \ + if (tmp != NULL) { \ + tmp+=strlen(name); \ + while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ + if (*tmp != '\n') sscanf(tmp, "%x", &var); \ + } + +#define SetValue(name, var) \ + fprintf (f,"%s = %s\n", name, var); + +#define SetValuel(name, var) \ + fprintf (f,"%s = %x\n", name, var); + +int LoadConfig() { + struct stat buf; + FILE *f; + int size; + char *data,*tmp; + char strtemp[255]; + + if (stat(cfgfile, &buf) == -1) return -1; + size = buf.st_size; + + f = fopen(cfgfile,"r"); + if (f == NULL) return -1; + + data = (char*)malloc(size); + if (data == NULL) return -1; + + fread(data, 1, size, f); + fclose(f); + + GetValue("Bios", Config.Bios); + Config.Lang[0] = 0; + GetValue("Lang", Config.Lang); + GetValuel("Ps2Out", Config.PsxOut); + GetValuel("ThPriority", Config.ThPriority); + GetValue("PluginsDir", Config.PluginsDir); + GetValue("BiosDir", Config.BiosDir); + GetValue("Mcd1", Config.Mcd1); + GetValue("Mcd2", Config.Mcd2); + + // plugins + GetValue("GS", Config.GS); + GetValue("SPU2", Config.SPU2); + GetValue("CDVD", Config.CDVD); + GetValue("PAD1", Config.PAD1); + GetValue("PAD2", Config.PAD2); + GetValue("DEV9", Config.DEV9); + GetValue("USB", Config.USB); + GetValue("FW", Config.FW); + + + // cpu + GetValuel("Options", Config.Options); + + GetValuel("Patch", Config.Patch); + +#ifdef PCSX2_DEVBUILD + GetValuel("varLog", varLog); +#endif + + free(data); + +#ifdef ENABLE_NLS + if (Config.Lang[0]) { + extern int _nl_msg_cat_cntr; + + setenv("LANGUAGE", Config.Lang, 1); + ++_nl_msg_cat_cntr; + } +#endif + + return 0; +} + +///////////////////////////////////////////////////////// + +void SaveConfig() { + FILE *f; + + f = fopen(cfgfile,"w"); + if (f == NULL) return; + + // interface + SetValue("Bios", Config.Bios); + SetValue("Lang", Config.Lang); + SetValue("PluginsDir", Config.PluginsDir); + SetValue("BiosDir", Config.BiosDir); + SetValuel("Ps2Out", Config.PsxOut); + SetValuel("ThPriority", Config.ThPriority); + SetValue("Mcd1", Config.Mcd1); + SetValue("Mcd2", Config.Mcd2); + // plugins + SetValue("GS", Config.GS); + SetValue("SPU2", Config.SPU2); + SetValue("CDVD", Config.CDVD); + SetValue("PAD1", Config.PAD1); + SetValue("PAD2", Config.PAD2); + SetValue("DEV9", Config.DEV9); + SetValue("USB", Config.USB); + SetValue("FW", Config.FW); + //cpu + SetValuel("Options", Config.Options); + // misc + SetValuel("Patch", Config.Patch); + +#ifdef PCSX2_DEVBUILD + SetValuel("varLog", varLog); +#endif + + + fclose(f); + + return; +} diff --git a/pcsx2/Linux/GtkGui.c b/pcsx2/Linux/GtkGui.c new file mode 100644 index 0000000000..3253c73217 --- /dev/null +++ b/pcsx2/Linux/GtkGui.c @@ -0,0 +1,1651 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include "support.h" +#include "callbacks.h" +#include "interface.h" +#include "Linux.h" + +#include "Paths.h" + + +static int needReset = 1; +int confret; +int confplug=0; +extern int RunExe; + +_PS2EgetLibType PS2EgetLibType = NULL; +_PS2EgetLibVersion2 PS2EgetLibVersion2 = NULL; +_PS2EgetLibName PS2EgetLibName = NULL; + +// Helper Functions +void FindPlugins(); + +// Functions Callbacks +void OnFile_LoadElf(GtkMenuItem *menuitem, gpointer user_data); +void OnFile_Exit(GtkMenuItem *menuitem, gpointer user_data); +void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data); +void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data); +void OnEmu_Arguments(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Cpu(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data); +void OnLanguage(GtkMenuItem *menuitem, gpointer user_data); +void OnHelp_Help(); +void OnHelp_About(GtkMenuItem *menuitem, gpointer user_data); + +GtkWidget *Window; +GtkWidget* pStatusBar = NULL; +GtkWidget *CmdLine; //2002-09-28 (Florin) +GtkWidget *ConfDlg; +GtkWidget *AboutDlg; +GtkWidget *DebugWnd; +GtkWidget *LogDlg; +GtkWidget *FileSel; + +GtkAccelGroup *AccelGroup; + +typedef struct { + GtkWidget *Combo; + GList *glist; + char plist[255][255]; + int plugins; +} PluginConf; + +PluginConf GSConfS; +PluginConf PAD1ConfS; +PluginConf PAD2ConfS; +PluginConf SPU2ConfS; +PluginConf CDVDConfS; +PluginConf DEV9ConfS; +PluginConf USBConfS; +PluginConf FWConfS; +PluginConf BiosConfS; + +void StartGui() { + GtkWidget *Menu; + GtkWidget *Item; + GtkWidget* vbox; + int i; + + add_pixmap_directory(".pixmaps"); + + Window = create_MainWindow(); + +#ifdef PCSX2_VIRTUAL_MEM + gtk_window_set_title(GTK_WINDOW(Window), "PCSX2 "PCSX2_VERSION" Watermoose VM"); +#else + gtk_window_set_title(GTK_WINDOW(Window), "PCSX2 "PCSX2_VERSION" Watermoose"); +#endif + + // status bar + pStatusBar = gtk_statusbar_new (); + gtk_box_pack_start (GTK_BOX(lookup_widget(Window, "status_box")), pStatusBar, TRUE, TRUE, 0); + gtk_widget_show (pStatusBar); + + gtk_statusbar_push(GTK_STATUSBAR(pStatusBar),0, + "F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot"); + + // add all the languages + Item = lookup_widget(Window, "GtkMenuItem_Language"); + Menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(Item), Menu); + + for (i=0; iExecute(); +} + +void OnFile_RunCD(GtkMenuItem *menuitem, gpointer user_data) { + needReset = 1; + efile = 0; + RunExecute(1); +} + +void OnRunElf_Ok(GtkButton* button, gpointer user_data) { + gchar *File; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(elfname, File); + gtk_widget_destroy(FileSel); + needReset = 1; + efile = 1; + RunExecute(1); +} + +void OnRunElf_Cancel(GtkButton* button, gpointer user_data) { + gtk_widget_destroy(FileSel); +} + +void OnFile_LoadElf(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new("Select Psx Elf File"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnFile_Exit(GtkMenuItem *menuitem, gpointer user_data) { + DIR *dir; + struct dirent *ent; + void *Handle; + char plugin[256]; + + // with this the problem with plugins that are linked with the pthread + // library is solved + + dir = opendir(Config.PluginsDir); + if (dir != NULL) { + while ((ent = readdir(dir)) != NULL) { + sprintf (plugin, "%s%s", Config.PluginsDir, ent->d_name); + + if (strstr(plugin, ".so") == NULL) continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) continue; + } + } + + printf(_("PCSX2 Quitting\n")); + if (UseGui) gtk_main_quit(); + SysClose(); + if (UseGui) gtk_exit(0); + else exit(0); +} + +void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data) +{ + if(needReset == 1) + RunExe = 1; + efile = 0; + RunExecute(1); +} + +void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data) +{ + ResetPlugins(); + needReset = 1; + efile = 0; +} + +int Slots[5] = { -1, -1, -1, -1, -1 }; + +void ResetMenuSlots(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *Item; + char str[256]; + int i; + + for (i=0; i<5; i++) { + sprintf(str, "GtkMenuItem_LoadSlot%d", i+1); + Item = lookup_widget(Window, str); + if (Slots[i] == -1) + gtk_widget_set_sensitive(Item, FALSE); + else + gtk_widget_set_sensitive(Item, TRUE); + } +} + +void UpdateMenuSlots(GtkMenuItem *menuitem, gpointer user_data) { + char str[256]; + int i; + + for (i=0; i<5; i++) { + sprintf(str, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, i); + Slots[i] = CheckState(str); + } +} + +void States_Load(int num) { + char Text[256]; + int ret; + + efile = 2; + RunExecute(0); + + sprintf (Text, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, num); + ret = LoadState(Text); +/* if (ret == 0) + sprintf (Text, _("*PCSX2*: Loaded State %d"), num+1); + else sprintf (Text, _("*PCSX2*: Error Loading State %d"), num+1); + GPU_displayText(Text);*/ + + Cpu->Execute(); +} + +void States_Save(int num) { + char Text[256]; + int ret; + + sprintf (Text, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, num); + ret = SaveState(Text); + if (ret == 0) + sprintf(Text, _("*PCSX2*: Saving State %d"), num+1); + else sprintf(Text, _("*PCSX2*: Error Saving State %d"), num+1); + //StatusSet(Text); + + RunExecute(1); +} + +void OnStates_Load1(GtkMenuItem *menuitem, gpointer user_data) { States_Load(0); } +void OnStates_Load2(GtkMenuItem *menuitem, gpointer user_data) { States_Load(1); } +void OnStates_Load3(GtkMenuItem *menuitem, gpointer user_data) { States_Load(2); } +void OnStates_Load4(GtkMenuItem *menuitem, gpointer user_data) { States_Load(3); } +void OnStates_Load5(GtkMenuItem *menuitem, gpointer user_data) { States_Load(4); } + +void OnLoadOther_Ok(GtkButton* button, gpointer user_data) { + gchar *File; + char str[256]; + char Text[256]; + int ret; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(str, File); + gtk_widget_destroy(FileSel); + + efile = 2; + RunExecute(0); + + ret = LoadState(str); +/* if (ret == 0) + sprintf (Text, _("*PCSX*: Loaded State %s"), str); + else sprintf (Text, _("*PCSX*: Error Loading State %s"), str); + GPU_displayText(Text);*/ + + Cpu->Execute(); +} + +void OnLoadOther_Cancel(GtkButton* button, gpointer user_data) { + gtk_widget_destroy(FileSel); +} + +void OnStates_LoadOther(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new(_("Select State File")); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), SSTATES_DIR "/"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnLoadOther_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnLoadOther_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnStates_Save1(GtkMenuItem *menuitem, gpointer user_data) { States_Save(0); } +void OnStates_Save2(GtkMenuItem *menuitem, gpointer user_data) { States_Save(1); } +void OnStates_Save3(GtkMenuItem *menuitem, gpointer user_data) { States_Save(2); } +void OnStates_Save4(GtkMenuItem *menuitem, gpointer user_data) { States_Save(3); } +void OnStates_Save5(GtkMenuItem *menuitem, gpointer user_data) { States_Save(4); } + +void OnSaveOther_Ok(GtkButton* button, gpointer user_data) { + gchar *File; + char str[256]; + char Text[256]; + int ret; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(str, File); + gtk_widget_destroy(FileSel); + RunExecute(0); + + ret = SaveState(str); +/* if (ret == 0) + sprintf (Text, _("*PCSX*: Saved State %s"), str); + else sprintf (Text, _("*PCSX*: Error Saving State %s"), str); + GPU_displayText(Text);*/ + + Cpu->Execute(); +} + +void OnSaveOther_Cancel(GtkButton* button, gpointer user_data) { + gtk_widget_destroy(FileSel); +} + +void OnStates_SaveOther(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new(_("Select State File")); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), SSTATES_DIR "/"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnSaveOther_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnSaveOther_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +//2002-09-28 (Florin) +void OnArguments_Ok(GtkButton *button, gpointer user_data) { + GtkWidget *widgetCmdLine; + char *str; + + widgetCmdLine = lookup_widget(CmdLine, "GtkEntry_dCMDLINE"); + str = (char*)gtk_entry_get_text(GTK_ENTRY(widgetCmdLine)); + memcpy(args, str, 256); + + gtk_widget_destroy(CmdLine); + gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); +} + +void OnArguments_Cancel(GtkButton* button, gpointer user_data) { + gtk_widget_destroy(CmdLine); + gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); +} + +void OnEmu_Arguments(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *widgetCmdLine; + + CmdLine = create_CmdLine(); + gtk_window_set_title(GTK_WINDOW(CmdLine), _("Program arguments")); + + widgetCmdLine = lookup_widget(CmdLine, "GtkEntry_dCMDLINE"); + gtk_entry_set_text(GTK_ENTRY(widgetCmdLine), args); + //args exported by ElfHeader.h + gtk_widget_show_all(CmdLine); + gtk_widget_set_sensitive(Window, FALSE); + gtk_main(); +} +//------------------- + +void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + GSconfigure(); + chdir(file); + gtk_widget_set_sensitive(Window, TRUE); +} + +void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + PAD1configure(); + if (strcmp(Config.PAD1, Config.PAD2)) PAD2configure(); + chdir(file); + gtk_widget_set_sensitive(Window, TRUE); +} + +void OnConf_Spu2(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + SPU2configure(); + gtk_widget_set_sensitive(Window, TRUE); + chdir(file); +} + +void OnConf_Cdvd(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + CDVDconfigure(); + gtk_widget_set_sensitive(Window, TRUE); + chdir(file); +} + +void OnConf_Dev9(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + DEV9configure(); + gtk_widget_set_sensitive(Window, TRUE); + chdir(file); +} + +void OnConf_Usb(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + USBconfigure(); + gtk_widget_set_sensitive(Window, TRUE); + chdir(file); +} + +void OnConf_Fw(GtkMenuItem *menuitem, gpointer user_data) { + char file[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(Window, FALSE); + FWconfigure(); + gtk_widget_set_sensitive(Window, TRUE); + chdir(file); +} + +GtkWidget *CpuDlg; + +void OnCpu_Ok(GtkButton *button, gpointer user_data) { + GtkWidget *Btn; + long t; + u32 newopts = 0; + + Cpu->Shutdown(); + vu0Shutdown(); + vu1Shutdown(); + + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_EERec"))) ) { + newopts |= PCSX2_EEREC; + } + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_VU0rec"))) ) + newopts |= PCSX2_VU0REC; + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_VU1rec"))) ) + newopts |= PCSX2_VU1REC; + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_MTGS"))) ) + newopts |= PCSX2_GSMULTITHREAD; + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_CpuDC"))) ) + newopts |= PCSX2_DUALCORE; + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitNormal"))) ) + newopts |= PCSX2_FRAMELIMIT_NORMAL; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitLimit"))) ) + newopts |= PCSX2_FRAMELIMIT_LIMIT; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitFS"))) ) + newopts |= PCSX2_FRAMELIMIT_SKIP; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_VUSkip"))) ) + newopts |= PCSX2_FRAMELIMIT_VUSKIP; + + if( (Config.Options&PCSX2_GSMULTITHREAD) ^ (newopts&PCSX2_GSMULTITHREAD) ) { + Config.Options = newopts; + SaveConfig(); + SysMessage("Restart Pcsx2"); + exit(0); + } + + if( newopts & PCSX2_EEREC ) newopts |= PCSX2_COP2REC; + + Config.Options = newopts; + + UpdateVSyncRate(); + SaveConfig(); + + cpuRestartCPU(); + + gtk_widget_destroy(CpuDlg); + + if (Window) gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); +} + +void OnCpu_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(CpuDlg); + if (Window) gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); +} + + +void OnConf_Cpu(GtkMenuItem *menuitem, gpointer user_data) +{ + GtkWidget *Btn; + char str[512]; + + CpuDlg = create_CpuDlg(); + gtk_window_set_title(GTK_WINDOW(CpuDlg), _("Configuration")); + + if(!cpucaps.hasStreamingSIMDExtensions) { + Config.Options &= (PCSX2_VU0REC|PCSX2_VU1REC);//disable the config just in case + } + if(!cpucaps.hasMultimediaExtensions) { + Config.Options &= ~(PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_COP2REC);//return to interpreter mode + } + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_EERec")), !!CHECK_EEREC); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_VU0rec")), !!CHECK_VU0REC); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_VU1rec")), !!CHECK_VU1REC); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_MTGS")), !!CHECK_MULTIGS); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkCheckButton_CpuDC")), !!CHECK_DUALCORE); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitNormal")), CHECK_FRAMELIMIT==PCSX2_FRAMELIMIT_NORMAL); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitLimit")), CHECK_FRAMELIMIT==PCSX2_FRAMELIMIT_LIMIT); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitFS")), CHECK_FRAMELIMIT==PCSX2_FRAMELIMIT_SKIP); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_VUSkip")), CHECK_FRAMELIMIT==PCSX2_FRAMELIMIT_VUSKIP); + + sprintf(str, "Cpu Vendor: %s", cpuinfo.x86ID); + gtk_label_set_text(GTK_LABEL(lookup_widget(CpuDlg, "GtkLabel_CpuVendor")), str); + sprintf(str, "Familly: %s", cpuinfo.x86Fam); + gtk_label_set_text(GTK_LABEL(lookup_widget(CpuDlg, "GtkLabel_Family")), str); + sprintf(str, "Cpu Speed: %d MHZ", cpuinfo.cpuspeed); + gtk_label_set_text(GTK_LABEL(lookup_widget(CpuDlg, "GtkLabel_CpuSpeed")), str); + + strcpy(str,"Features: "); + if(cpucaps.hasMultimediaExtensions) strcat(str,"MMX"); + if(cpucaps.hasStreamingSIMDExtensions) strcat(str,",SSE"); + if(cpucaps.hasStreamingSIMD2Extensions) strcat(str,",SSE2"); + if(cpucaps.hasStreamingSIMD3Extensions) strcat(str,",SSE3"); + if(cpucaps.hasAMD64BitArchitecture) strcat(str,",x86-64"); + gtk_label_set_text(GTK_LABEL(lookup_widget(CpuDlg, "GtkLabel_Features")), str); + + //GtkLabel_CpuVendor + //GtkLabel_Family + //GtkLabel_CpuSpeed + //GtkLabel_Features + gtk_widget_show_all(CpuDlg); + if (Window) gtk_widget_set_sensitive(Window, FALSE); + gtk_main(); +} + +#define FindComboText(combo,list,conf) \ + if (strlen(conf) > 0) { \ + int i; \ + for (i=2;i<255;i+=2) { \ + if (!strcmp(conf, list[i-2])) { \ + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), list[i-1]); \ + break; \ + } \ + } \ + } + +#define GetComboText(combo,list,conf) \ + { \ + int i; \ + char *tmp = (char*)gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)); \ + for (i=2;i<255;i+=2) { \ + if (!strcmp(tmp, list[i-1])) { \ + strcpy(conf, list[i-2]); \ + break; \ + } \ + } \ + } + +void OnConfConf_Ok(GtkButton *button, gpointer user_data) { + GetComboText(GSConfS.Combo, GSConfS.plist, Config.GS) + GetComboText(PAD1ConfS.Combo, PAD1ConfS.plist, Config.PAD1); + GetComboText(PAD2ConfS.Combo, PAD2ConfS.plist, Config.PAD2); + GetComboText(SPU2ConfS.Combo, SPU2ConfS.plist, Config.SPU2); + GetComboText(CDVDConfS.Combo, CDVDConfS.plist, Config.CDVD); + GetComboText(DEV9ConfS.Combo, DEV9ConfS.plist, Config.DEV9); + GetComboText(USBConfS.Combo, USBConfS.plist, Config.USB); + GetComboText(FWConfS.Combo, FWConfS.plist, Config.FW); + GetComboText(BiosConfS.Combo, BiosConfS.plist, Config.Bios); + + SaveConfig(); + + if (confplug == 0) { + ReleasePlugins(); + LoadPlugins(); + } + + needReset = 1; + gtk_widget_destroy(ConfDlg); + if (Window) gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); + confret = 1; +} + +void OnConfConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(ConfDlg); + if (Window) gtk_widget_set_sensitive(Window, TRUE); + gtk_main_quit(); + confret = 0; +} + +#define ConfPlugin(src, confs, plugin, name) \ + void *drv; \ + src conf; \ + char file[256]; \ + GetComboText(confs.Combo, confs.plist, plugin); \ + strcpy(file, Config.PluginsDir); \ + strcat(file, plugin); \ + drv = SysLoadLibrary(file); \ + getcwd(file, ARRAYSIZE(file)); /* store current dir */ \ + chdir(Config.PluginsDir); /* change dirs so that plugins can find their config file*/ \ + if (drv == NULL) return; \ + conf = (src) SysLoadSym(drv, name); \ + if (SysLibError() == NULL) conf(); \ + chdir(file); /* change back*/ \ + SysCloseLibrary(drv); + +#define TestPlugin(src, confs, plugin, name) \ + void *drv; \ + src conf; \ + int ret = 0; \ + char file[256]; \ + GetComboText(confs.Combo, confs.plist, plugin); \ + strcpy(file, Config.PluginsDir); \ + strcat(file, plugin); \ + drv = SysLoadLibrary(file); \ + if (drv == NULL) return; \ + conf = (src) SysLoadSym(drv, name); \ + if (SysLibError() == NULL) { \ + ret = conf(); \ + if (ret == 0) \ + SysMessage(_("This plugin reports that should work correctly")); \ + else SysMessage(_("This plugin reports that should not work correctly")); \ + } \ + SysCloseLibrary(drv); + +void OnConfConf_GsConf(GtkButton *button, gpointer user_data) { + ConfPlugin(_GSconfigure, GSConfS, Config.GS, "GSconfigure"); +} + +void OnConfConf_GsTest(GtkButton *button, gpointer user_data) { + TestPlugin(_GStest, GSConfS, Config.GS, "GStest"); +} + +void OnConfConf_GsAbout(GtkButton *button, gpointer user_data) { + ConfPlugin(_GSabout, GSConfS, Config.GS, "GSabout"); +} + +void OnConfConf_Pad1Conf(GtkButton *button, gpointer user_data) { + ConfPlugin(_PADconfigure, PAD1ConfS, Config.PAD1, "PADconfigure"); +} + +void OnConfConf_Pad1Test(GtkButton *button, gpointer user_data) { + TestPlugin(_PADtest, PAD1ConfS, Config.PAD1, "PADtest"); +} + +void OnConfConf_Pad1About(GtkButton *button, gpointer user_data) { + ConfPlugin(_PADabout, PAD1ConfS, Config.PAD1, "PADabout"); +} + +void OnConfConf_Pad2Conf(GtkButton *button, gpointer user_data) { + ConfPlugin(_PADconfigure, PAD2ConfS, Config.PAD2, "PADconfigure"); +} + +void OnConfConf_Pad2Test(GtkButton *button, gpointer user_data) { + TestPlugin(_PADtest, PAD2ConfS, Config.PAD2, "PADtest"); +} + +void OnConfConf_Pad2About(GtkButton *button, gpointer user_data) { + ConfPlugin(_PADabout, PAD2ConfS, Config.PAD2, "PADabout"); +} + +void OnConfConf_Spu2Conf(GtkButton *button, gpointer user_data) { + ConfPlugin(_SPU2configure, SPU2ConfS, Config.SPU2, "SPU2configure"); +} + +void OnConfConf_Spu2Test(GtkButton *button, gpointer user_data) { + TestPlugin(_SPU2test, SPU2ConfS, Config.SPU2, "SPU2test"); +} + +void OnConfConf_Spu2About(GtkButton *button, gpointer user_data) { + ConfPlugin(_SPU2about, SPU2ConfS, Config.SPU2, "SPU2about"); +} + +void OnConfConf_CdvdConf(GtkButton *button, gpointer user_data) { + ConfPlugin(_CDVDconfigure, CDVDConfS, Config.CDVD, "CDVDconfigure"); +} + +void OnConfConf_CdvdTest(GtkButton *button, gpointer user_data) { + TestPlugin(_CDVDtest, CDVDConfS, Config.CDVD, "CDVDtest"); +} + +void OnConfConf_CdvdAbout(GtkButton *button, gpointer user_data) { + ConfPlugin(_CDVDabout, CDVDConfS, Config.CDVD, "CDVDabout"); +} + +void OnConfConf_Dev9Conf(GtkButton *button, gpointer user_data) { + ConfPlugin(_DEV9configure, DEV9ConfS, Config.DEV9, "DEV9configure"); +} + +void OnConfConf_Dev9Test(GtkButton *button, gpointer user_data) { + TestPlugin(_DEV9test, DEV9ConfS, Config.DEV9, "DEV9test"); +} + +void OnConfConf_Dev9About(GtkButton *button, gpointer user_data) { + ConfPlugin(_DEV9about, DEV9ConfS, Config.DEV9, "DEV9about"); +} + +void OnConfConf_UsbConf(GtkButton *button, gpointer user_data) { + ConfPlugin(_USBconfigure, USBConfS, Config.USB, "USBconfigure"); +} + +void OnConfConf_UsbTest(GtkButton *button, gpointer user_data) { + TestPlugin(_USBtest, USBConfS, Config.USB, "USBtest"); +} + +void OnConfConf_UsbAbout(GtkButton *button, gpointer user_data) { + ConfPlugin(_USBabout, USBConfS, Config.USB, "USBabout"); +} + +void OnConfConf_FWConf(GtkButton *button, gpointer user_data) { + ConfPlugin(_FWconfigure, FWConfS, Config.FW, "FWconfigure"); +} + +void OnConfConf_FWTest(GtkButton *button, gpointer user_data) { + TestPlugin(_FWtest, FWConfS, Config.FW, "FWtest"); +} + +void OnConfConf_FWAbout(GtkButton *button, gpointer user_data) { + ConfPlugin(_FWabout, FWConfS, Config.FW, "FWabout"); +} + +#define ConfCreatePConf(name, type) \ + type##ConfS.Combo = lookup_widget(ConfDlg, "GtkCombo_" name); \ + gtk_combo_set_popdown_strings(GTK_COMBO(type##ConfS.Combo), type##ConfS.glist); \ + FindComboText(type##ConfS.Combo, type##ConfS.plist, Config.type); \ + +void UpdateConfDlg() { + FindPlugins(); + + ConfCreatePConf("Gs", GS); + ConfCreatePConf("Pad1", PAD1); + ConfCreatePConf("Pad2", PAD2); + ConfCreatePConf("Spu2", SPU2); + ConfCreatePConf("Cdvd", CDVD); + ConfCreatePConf("Dev9", DEV9); + ConfCreatePConf("Usb", USB); + ConfCreatePConf("FW", FW); + ConfCreatePConf("Bios", Bios); +} + +void OnPluginsPath_Ok() { + gchar *File; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(Config.PluginsDir, File); + if (Config.PluginsDir[strlen(Config.PluginsDir)-1] != '/') + strcat(Config.PluginsDir, "/"); + + UpdateConfDlg(); + + gtk_widget_destroy(FileSel); +} + +void OnPluginsPath_Cancel() { + gtk_widget_destroy(FileSel); +} + +void OnConfConf_PluginsPath(GtkButton *button, gpointer user_data) { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new(_("Select Plugins Directory")); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnPluginsPath_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnPluginsPath_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnBiosPath_Ok() { + gchar *File; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(Config.BiosDir, File); + if (Config.BiosDir[strlen(Config.BiosDir)-1] != '/') + strcat(Config.BiosDir, "/"); + + UpdateConfDlg(); + + gtk_widget_destroy(FileSel); +} + +void OnBiosPath_Cancel() { + gtk_widget_destroy(FileSel); +} + +void OnConfConf_BiosPath(GtkButton *button, gpointer user_data) { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new(_("Select Bios Directory")); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnBiosPath_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnBiosPath_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data) { + FindPlugins(); + + ConfDlg = create_ConfDlg(); + gtk_window_set_title(GTK_WINDOW(ConfDlg), _("Configuration")); + + UpdateConfDlg(); + + gtk_widget_show_all(ConfDlg); + if (Window) gtk_widget_set_sensitive(Window, FALSE); + gtk_main(); +} + +GtkWidget *CmdLine; +GtkWidget *ListDV; +GtkListStore *ListDVModel; +GtkWidget *SetPCDlg, *SetPCEntry; +GtkWidget *SetBPADlg, *SetBPAEntry; +GtkWidget *SetBPCDlg, *SetBPCEntry; +GtkWidget *DumpCDlg, *DumpCTEntry, *DumpCFEntry; +GtkWidget *DumpRDlg, *DumpRTEntry, *DumpRFEntry; +GtkWidget *MemWriteDlg, *MemEntry, *DataEntry; +GtkAdjustment *DebugAdj; +static u32 dPC; +static u32 dBPA = -1; +static u32 dBPC = -1; +static char nullAddr[256]; +int DebugMode; // 0 - EE | 1 - IOP + +#include "R3000A.h" +#include "PsxMem.h" + +void UpdateDebugger() { + + char *str; + int i; + DebugAdj->value = (gfloat)dPC/4; + gtk_list_store_clear(ListDVModel); + + for (i=0; i<23; i++) { + GtkTreeIter iter; + u32 *mem; + u32 pc = dPC + i*4; + if (DebugMode) { + mem = (u32*)PSXM(pc); + } else + mem = PSM(pc); + if (mem == NULL) { sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", pc); str = nullAddr; } + else str = disR5900Fasm(*mem, pc); + gtk_list_store_append(ListDVModel, &iter); + gtk_list_store_set(ListDVModel, &iter, 0, str, -1); + + } +} + +void OnDebug_Close(GtkButton *button, gpointer user_data) { + ClosePlugins(); + gtk_widget_destroy(DebugWnd); + gtk_main_quit(); + gtk_widget_set_sensitive(Window, TRUE); +} + +void OnDebug_ScrollChange(GtkAdjustment *adj) { + dPC = (u32)adj->value*4; + dPC&= ~0x3; + + UpdateDebugger(); +} + +void OnSetPC_Ok(GtkButton *button, gpointer user_data) { + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetPCEntry)); + + sscanf(str, "%lx", &dPC); + dPC&= ~0x3; + + gtk_widget_destroy(SetPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetPC_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(SetPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetPC(GtkButton *button, gpointer user_data) { + SetPCDlg = create_SetPCDlg(); + + SetPCEntry = lookup_widget(SetPCDlg, "GtkEntry_dPC"); + + gtk_widget_show_all(SetPCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnSetBPA_Ok(GtkButton *button, gpointer user_data) { + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPAEntry)); + + sscanf(str, "%lx", &dBPA); + dBPA&= ~0x3; + + gtk_widget_destroy(SetBPADlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetBPA_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(SetBPADlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetBPA(GtkButton *button, gpointer user_data) { + SetBPADlg = create_SetBPADlg(); + + SetBPAEntry = lookup_widget(SetBPADlg, "GtkEntry_BPA"); + + gtk_widget_show_all(SetBPADlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnSetBPC_Ok(GtkButton *button, gpointer user_data) { + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPCEntry)); + + sscanf(str, "%lx", &dBPC); + + gtk_widget_destroy(SetBPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetBPC_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(SetBPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetBPC(GtkButton *button, gpointer user_data) { + SetBPCDlg = create_SetBPCDlg(); + + SetBPCEntry = lookup_widget(SetBPCDlg, "GtkEntry_BPC"); + + gtk_widget_show_all(SetBPCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDebug_ClearBPs(GtkButton *button, gpointer user_data) { + dBPA = -1; + dBPC = -1; +} + +void OnDumpC_Ok(GtkButton *button, gpointer user_data) { + FILE *f; + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCFEntry)); + u32 addrf, addrt; + + sscanf(str, "%lx", &addrf); addrf&=~0x3; + str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCTEntry)); + sscanf(str, "%lx", &addrt); addrt&=~0x3; + + f = fopen("dump.txt", "w"); + if (f == NULL) return; + + while (addrf != addrt) { + u32 *mem; + + if (DebugMode) { + mem = PSXM(addrf); + } else { + mem = PSM(addrf); + } + if (mem == NULL) { sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", addrf); str = nullAddr; } + else str = disR5900Fasm(*mem, addrf); + + fprintf(f, "%s\n", str); + addrf+= 4; + } + + fclose(f); + + gtk_widget_destroy(DumpCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDumpC_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(DumpCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_DumpCode(GtkButton *button, gpointer user_data) { + DumpCDlg = create_DumpCDlg(); + + DumpCFEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCF"); + DumpCTEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCT"); + + gtk_widget_show_all(DumpCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDumpR_Ok(GtkButton *button, gpointer user_data) { + FILE *f; + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRFEntry)); + u32 addrf, addrt; + + sscanf(str, "%lx", &addrf); addrf&=~0x3; + str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRTEntry)); + sscanf(str, "%lx", &addrt); addrt&=~0x3; + + f = fopen("dump.txt", "w"); + if (f == NULL) return; + + while (addrf != addrt) { + u32 *mem; + u32 out; + + if (DebugMode) { + mem = PSXM(addrf); + } else { + mem = PSM(addrf); + } + if (mem == NULL) out = 0; + else out = *mem; + + fwrite(&out, 4, 1, f); + addrf+= 4; + } + + fclose(f); + + gtk_widget_destroy(DumpRDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDumpR_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(DumpRDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_RawDump(GtkButton *button, gpointer user_data) { + DumpRDlg = create_DumpRDlg(); + + DumpRFEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRF"); + DumpRTEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRT"); + + gtk_widget_show_all(DumpRDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDebug_Step(GtkButton *button, gpointer user_data) { + Cpu->Step(); + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_Skip(GtkButton *button, gpointer user_data) { + cpuRegs.pc+= 4; + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +int HasBreakPoint(u32 pc) { + if (pc == dBPA) return 1; + if (DebugMode == 0) { + if ((cpuRegs.cycle - 10) <= dBPC && + (cpuRegs.cycle + 10) >= dBPC) return 1; + } else { + if ((psxRegs.cycle - 100) <= dBPC && + (psxRegs.cycle + 100) >= dBPC) return 1; + } + return 0; +} + +void OnDebug_Go(GtkButton *button, gpointer user_data) { + for (;;) { + if (HasBreakPoint(cpuRegs.pc)) break; + Cpu->Step(); + } + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_Log(GtkButton *button, gpointer user_data) { +#ifdef PCSX2_DEVBUILD + Log = 1 - Log; +#endif +} + +void OnDebug_EEMode(GtkToggleButton *togglebutton, gpointer user_data) { + DebugMode = 0; + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_IOPMode(GtkToggleButton *togglebutton, gpointer user_data) { + DebugMode = 1; + dPC = psxRegs.pc; + UpdateDebugger(); +} + +void OnMemWrite32_Ok(GtkButton *button, gpointer user_data) { + char *mem = (char*)gtk_entry_get_text(GTK_ENTRY(MemEntry)); + char *data = (char*)gtk_entry_get_text(GTK_ENTRY(DataEntry)); + + printf("memWrite32: %s, %s\n", mem, data); + memWrite32(strtol(mem, (char**)NULL, 0), strtol(data, (char**)NULL, 0)); + + gtk_widget_destroy(MemWriteDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnMemWrite32_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(MemWriteDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_memWrite32(GtkButton *button, gpointer user_data) { + MemWriteDlg = create_MemWrite32(); + + MemEntry = lookup_widget(MemWriteDlg, "GtkEntry_Mem"); + DataEntry = lookup_widget(MemWriteDlg, "GtkEntry_Data"); + + gtk_widget_show_all(MemWriteDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); + + UpdateDebugger(); +} + +void OnDebug_Debugger(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *scroll; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + if (OpenPlugins(NULL) == -1) return; + if (needReset) { SysReset(); needReset = 0; } + + if (!efile) + efile=GetPS2ElfName(elfname); + if (efile) + loadElfFile(elfname); + efile=0; + + dPC = cpuRegs.pc; + + DebugWnd = create_DebugWnd(); + + ListDVModel = gtk_list_store_new (1, G_TYPE_STRING); + ListDV = lookup_widget(DebugWnd, "GtkList_DisView"); + gtk_tree_view_set_model(GTK_TREE_VIEW(ListDV), GTK_TREE_MODEL(ListDVModel)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("heading", renderer, + "text", 0, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (ListDV), column); + + scroll = lookup_widget(DebugWnd, "GtkVScrollbar_VList"); + + DebugAdj = GTK_RANGE(scroll)->adjustment; + DebugAdj->lower = (gfloat)0x00000000/4; + DebugAdj->upper = (gfloat)0xffffffff/4; + DebugAdj->step_increment = (gfloat)1; + DebugAdj->page_increment = (gfloat)20; + DebugAdj->page_size = (gfloat)23; + + gtk_signal_connect(GTK_OBJECT(DebugAdj), + "value_changed", GTK_SIGNAL_FUNC(OnDebug_ScrollChange), + NULL); + + UpdateDebugger(); + + gtk_widget_show_all(DebugWnd); + gtk_widget_set_sensitive(Window, FALSE); + gtk_main(); +} + +void OnLogging_Ok(GtkButton *button, gpointer user_data) { + GtkWidget *Btn; + char str[32]; + int i, ret; + +#ifdef PCSX2_DEVBUILD + for (i=0; i<17; i++) { + sprintf(str, "Log%d", i); + Btn = lookup_widget(LogDlg, str); + ret = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + if (ret) varLog|= 1<>8)&0xff ,version&0xff, (version>>24)&0xff); \ + type##ConfS.plugins+=2; \ + strcpy(type##ConfS.plist[type##ConfS.plugins-1], name); \ + strcpy(type##ConfS.plist[type##ConfS.plugins-2], ent->d_name); \ + type##ConfS.glist = g_list_append(type##ConfS.glist, type##ConfS.plist[type##ConfS.plugins-1]); \ +} + +void FindPlugins() { + DIR *dir; + struct dirent *ent; + void *Handle; + char plugin[256],name[256]; + + GSConfS.plugins = 0; CDVDConfS.plugins = 0; DEV9ConfS.plugins = 0; + PAD1ConfS.plugins = 0; PAD2ConfS.plugins = 0; SPU2ConfS.plugins = 0; + USBConfS.plugins = 0; FWConfS.plugins = 0; BiosConfS.plugins = 0; + GSConfS.glist = NULL; CDVDConfS.glist = NULL; DEV9ConfS.glist = NULL; + PAD1ConfS.glist = NULL; PAD2ConfS.glist = NULL; SPU2ConfS.glist = NULL; + USBConfS.glist = NULL; FWConfS.glist = NULL; BiosConfS.glist = NULL; + + dir = opendir(Config.PluginsDir); + if (dir == NULL) { + SysMessage(_("Could not open '%s' directory"), Config.PluginsDir); + return; + } + while ((ent = readdir(dir)) != NULL) { + u32 version; + u32 type; + + sprintf (plugin, "%s%s", Config.PluginsDir, ent->d_name); + + if (strstr(plugin, ".so") == NULL) continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) { + printf("%s\n", dlerror()); continue; + } + + PS2EgetLibType = (_PS2EgetLibType) dlsym(Handle, "PS2EgetLibType"); + PS2EgetLibName = (_PS2EgetLibName) dlsym(Handle, "PS2EgetLibName"); + PS2EgetLibVersion2 = (_PS2EgetLibVersion2) dlsym(Handle, "PS2EgetLibVersion2"); + if (PS2EgetLibType == NULL || PS2EgetLibName == NULL || PS2EgetLibVersion2 == NULL) + continue; + type = PS2EgetLibType(); + + if (type & PS2E_LT_GS) { + version = PS2EgetLibVersion2(PS2E_LT_GS); + if (((version >> 16)&0xff) == PS2E_GS_VERSION) { + ComboAddPlugin(GS); + } + else + SysPrintf("Plugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_GS_VERSION); + } + if (type & PS2E_LT_PAD) { + _PADquery query; + + query = (_PADquery)dlsym(Handle, "PADquery"); + version = PS2EgetLibVersion2(PS2E_LT_PAD); + if (((version >> 16)&0xff) == PS2E_PAD_VERSION && query) { + if (query() & 0x1) + ComboAddPlugin(PAD1); + if (query() & 0x2) + ComboAddPlugin(PAD2); + } else SysPrintf("Plugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_PAD_VERSION); + } + if (type & PS2E_LT_SPU2) { + version = PS2EgetLibVersion2(PS2E_LT_SPU2); + if (((version >> 16)&0xff) == PS2E_SPU2_VERSION) { + ComboAddPlugin(SPU2); + } else SysPrintf("Plugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_SPU2_VERSION); + } + if (type & PS2E_LT_CDVD) { + version = PS2EgetLibVersion2(PS2E_LT_CDVD); + if (((version >> 16)&0xff) == PS2E_CDVD_VERSION) { + ComboAddPlugin(CDVD); + } else SysPrintf("Plugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_CDVD_VERSION); + } + if (type & PS2E_LT_DEV9) { + version = PS2EgetLibVersion2(PS2E_LT_DEV9); + if (((version >> 16)&0xff) == PS2E_DEV9_VERSION) { + ComboAddPlugin(DEV9); + } else SysPrintf("DEV9Plugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_DEV9_VERSION); + } + if (type & PS2E_LT_USB) { + version = PS2EgetLibVersion2(PS2E_LT_USB); + if (((version >> 16)&0xff) == PS2E_USB_VERSION) { + ComboAddPlugin(USB); + } else SysPrintf("USBPlugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_USB_VERSION); + } + if (type & PS2E_LT_FW) { + version = PS2EgetLibVersion2(PS2E_LT_FW); + if (((version >> 16)&0xff) == PS2E_FW_VERSION) { + ComboAddPlugin(FW); + } else SysPrintf("FWPlugin %s: Version %x != %x\n", plugin, (version >> 16)&0xff, PS2E_FW_VERSION); + } + } + closedir(dir); + + dir = opendir(Config.BiosDir); + if (dir == NULL) { + SysMessage(_("Could not open '%s' directory"), Config.BiosDir); + return; + } + + while ((ent = readdir(dir)) != NULL) { + struct stat buf; + char description[50]; //2002-09-28 (Florin) + + sprintf (plugin, "%s%s", Config.BiosDir, ent->d_name); + if (stat(plugin, &buf) == -1) continue; +// if (buf.st_size < (1024*512)) continue; + if (buf.st_size > (1024*4096)) continue; //2002-09-28 (Florin) + if (!IsBIOS(ent->d_name, description)) continue;//2002-09-28 (Florin) + + BiosConfS.plugins+=2; + snprintf(BiosConfS.plist[BiosConfS.plugins-1], sizeof(BiosConfS.plist[0]), "%s (", description); + strncat(BiosConfS.plist[BiosConfS.plugins-1], ent->d_name, min(sizeof(BiosConfS.plist[0]-2), strlen(ent->d_name))); + strcat(BiosConfS.plist[BiosConfS.plugins-1], ")"); + strcpy(BiosConfS.plist[BiosConfS.plugins-2], ent->d_name); + BiosConfS.glist = g_list_append(BiosConfS.glist, BiosConfS.plist[BiosConfS.plugins-1]); + } + closedir(dir); +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + if (!UseGui) { printf("%s\n",msg); return; } + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), _("PCSX2 Msg")); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label(_("Ok")); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + gtk_widget_grab_focus(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void +on_patch_browser1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ +} + +void +on_patch_finder2_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ +} + +void +on_enable_console1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + Config.PsxOut=(int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); + SaveConfig(); +} + +void +on_enable_patches1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + Config.Patch=(int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); + SaveConfig(); +} diff --git a/pcsx2/Linux/Linux.h b/pcsx2/Linux/Linux.h new file mode 100644 index 0000000000..816476c0c2 --- /dev/null +++ b/pcsx2/Linux/Linux.h @@ -0,0 +1,47 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ + +#include "Common.h" + +typedef struct { + char lang[256]; +} _langs; + +_langs *langs; +unsigned int langsMax; + +extern int UseGui; +char cfgfile[256]; + +int LoadConfig(); +void SaveConfig(); + +void StartGui(); +void RunGui(); + +int Pcsx2Configure(); + +void InitLanguages(); +char *GetLanguageNext(); +void CloseLanguages(); +void ChangeLanguage(char *lang); + +#endif /* __LINUX_H__ */ diff --git a/pcsx2/Linux/LnxMain.c b/pcsx2/Linux/LnxMain.c new file mode 100644 index 0000000000..e32a92a95b --- /dev/null +++ b/pcsx2/Linux/LnxMain.c @@ -0,0 +1,621 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "Common.h" +#include "PsxCommon.h" +#include "Linux.h" + +#include "../Paths.h" + +int UseGui = 1; +int needReset = 1; +int RunExe = 0; +extern int g_SaveGSStream; +extern int g_ZeroGSOptions; + +#ifdef PCSX2_DEVBUILD + +TESTRUNARGS g_TestRun; +char* g_pRunGSState = NULL; + +#endif + +int main(int argc, char *argv[]) { + char *file = NULL; + char elfname[256]; + char *lang; + int runcd=0; + int efile = 0; + char* g_pRunGSState = NULL; + int i; + struct stat buf; + +#ifdef PCSX2_VIRTUAL_MEM + void* pmem = mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + + if( pmem != PS2MEM_BASE ) { + SysMessage("Failed to allocate virtual memory %x-%x. Use TLB build", + PS2MEM_BASE, PS2MEM_BASE+0x40000000); + return -1; + } +#endif + + +#ifdef ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, "Langs"); + textdomain(PACKAGE); +#endif + + printf("\n"); + mkdir(CONFIG_DIR, 0755); + + strcpy(cfgfile, CONFIG_DIR "/pcsx2.cfg"); + +#ifdef PCSX2_DEVBUILD + memset(&g_TestRun, 0, sizeof(g_TestRun)); +#endif + + i = 1; + while(i < argc) { + char* token = argv[i++]; + + if( stricmp(token, "-help") == 0 || stricmp(token, "--help") == 0 || stricmp(token, "-h") == 0 ) { + char* phelpmsg = + "\tpcsx2 [options] [file]\n\n" + "-cfg [file] {configuration file}\n" + "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" + "-help {display this help file}\n" + "-nogui {Don't use gui when launching}\n" + "-loadgs [file} {Loads a gsstate}\n" + "\n" +#ifdef PCSX2_DEVBUILD + "Testing Options: \n" + "\t-frame [frame] {game will run up to this frame before exiting}\n" + "\t-image [name] {path and base name of image (do not include the .ext)}\n" + "\t-jpg {save images to jpg format}\n" + "\t-log [name] {log path to save log file in}\n" + "\t-logopt [hex] {log options in hex (see debug.h) }\n" + "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" + "\t-test {Triggers testing mode (only for dev builds)}\n" + "\n" +#endif + + "Load Plugins:\n" + "\t-cdvd [dllpath] {specify the dll load path of the CDVD plugin}\n" + "\t-gs [dllpath] {specify the dll load path of the GS plugin}\n" + "-pad [tsxcal] {specify to hold down on the triangle, square, circle, x, start, select buttons}\n" + "\t-spu [dllpath] {specify the dll load path of the SPU2 plugin}\n" + "\n"; + + //SysMessage(phelpmsg); + return 0; + } + else if( stricmp(token, "-efile") == 0 ) { + token = argv[i++]; + if( token != NULL ) { + efile = atoi(token); + } + } + else if( stricmp(token, "-nogui") == 0 ) { + UseGui = 0; + } + else if( stricmp(token, "-loadgs") == 0 ) { + g_pRunGSState = argv[i++]; + } +#ifdef PCSX2_DEVBUILD + else if( stricmp(token, "-image") == 0 ) { + g_TestRun.pimagename = argv[i++]; + } + else if( stricmp(token, "-log") == 0 ) { + g_TestRun.plogname = argv[i++]; + } + else if( stricmp(token, "-logopt") == 0 ) { + token = argv[i++]; + if( token != NULL ) { + if( token[0] == '0' && token[1] == 'x' ) token += 2; + sscanf(token, "%x", &varLog); + } + } + else if( stricmp(token, "-frame") == 0 ) { + token = argv[i++]; + if( token != NULL ) { + g_TestRun.frame = atoi(token); + } + } + else if( stricmp(token, "-numimages") == 0 ) { + token = argv[i++]; + if( token != NULL ) { + g_TestRun.numimages = atoi(token); + } + } + else if( stricmp(token, "-jpg") == 0 ) { + g_TestRun.jpgcapture = 1; + } + else if( stricmp(token, "-gs") == 0 ) { + token = argv[i++]; + g_TestRun.pgsdll = token; + } + else if( stricmp(token, "-cdvd") == 0 ) { + token = argv[i++]; + g_TestRun.pcdvddll = token; + } + else if( stricmp(token, "-spu") == 0 ) { + token = argv[i++]; + g_TestRun.pspudll = token; + } + else if( stricmp(token, "-test") == 0 ) { + g_TestRun.enabled = 1; + } +#endif + else if( stricmp(token, "-pad") == 0 ) { + token = argv[i++]; + printf("-pad ignored\n"); + } + else if( stricmp(token, "-loadgs") == 0 ) { + token = argv[i++]; + g_pRunGSState = token; + } + else { + file = token; + printf("opening file %s\n", file); + } + } + +#ifdef PCSX2_DEVBUILD + g_TestRun.efile = efile; + g_TestRun.ptitle = file; +#endif + + if (LoadConfig() == -1) { + + if (UseGui) gtk_init(NULL, NULL); + + memset(&Config, 0, sizeof(Config)); + strcpy(Config.BiosDir, DEFAULT_BIOS_DIR "/"); + strcpy(Config.PluginsDir, DEFAULT_PLUGINS_DIR "/"); + Config.Patch = 1; + Config.Options = PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_COP2REC; + + SysMessage(_("Pcsx2 needs to be configured")); + Pcsx2Configure(); + + return 0; + } + + // make gtk thread safe if using MTGS + if( CHECK_MULTIGS ) { + g_thread_init(NULL); + gdk_threads_init(); + } + + if (UseGui) gtk_init(NULL, NULL); + + if (Config.Lang[0] == 0) { + strcpy(Config.Lang, "en"); + } + + langs = (_langs*)malloc(sizeof(_langs)); + strcpy(langs[0].lang, "en"); + InitLanguages(); i=1; + while ((lang = GetLanguageNext()) != NULL) { + langs = (_langs*)realloc(langs, sizeof(_langs)*(i+1)); + strcpy(langs[i].lang, lang); + i++; + } + CloseLanguages(); + langsMax = i; + + if( Config.PsxOut ) { + // output the help commands + SysPrintf("\tF1 - save state\n"); + SysPrintf("\t(Shift +) F2 - cycle states\n"); + SysPrintf("\tF3 - load state\n"); + +#ifdef PCSX2_DEVBUILD + SysPrintf("\tF10 - dump performance counters\n"); + SysPrintf("\tF11 - save GS state\n"); + SysPrintf("\tF12 - dump hardware registers\n"); +#endif + } + + if (SysInit() == -1) return 1; + +#ifdef PCSX2_DEVBUILD + if( g_pRunGSState ) { + LoadGSState(g_pRunGSState); + SysClose(); + return 0; + } +#endif + + if (UseGui&&file==NULL) { + StartGui(); + return 0; + } + + if (OpenPlugins(file) == -1) { + return -1; + } + SysReset(); + + cpuExecuteBios(); + if (file) + strcpy(elfname, file); + if (!efile) + efile=GetPS2ElfName(elfname); + loadElfFile(elfname); + + if( GSsetGameCRC != NULL ) + GSsetGameCRC(ElfCRC, g_ZeroGSOptions); + + Cpu->Execute(); + + return 0; +} + +DIR *dir; + +void InitLanguages() { + dir = opendir(LANGS_DIR); +} + +char *GetLanguageNext() { + struct dirent *ent; + + if (dir == NULL) return NULL; + for (;;) { + ent = readdir(dir); + if (ent == NULL) return NULL; + + if (!strcmp(ent->d_name, ".")) continue; + if (!strcmp(ent->d_name, "..")) continue; + break; + } + + return ent->d_name; +} + +void CloseLanguages() { + if (dir) closedir(dir); +} + +void ChangeLanguage(char *lang) { + strcpy(Config.Lang, lang); + SaveConfig(); + LoadConfig(); +} + +void KeyEvent(keyEvent* ev) { + char Text[256]; + int ret; + static int shift = 0; + + if (ev == NULL) + return; + + if( GSkeyEvent != NULL ) + GSkeyEvent(ev); + + if( ev->event == KEYPRESS ) { + if( ev->key == XK_Shift_L || ev->key == XK_Shift_R ) + shift = 1; + } + else { + if (ev->event == KEYRELEASE) { + if( ev->key == XK_Shift_L || ev->key == XK_Shift_R ) + shift = 0; + } + + return; + } + + switch (ev->key) { + case XK_F1: ProcessFKeys(1, shift); break; + case XK_F2: ProcessFKeys(2, shift); break; + case XK_F3: ProcessFKeys(3, shift); break; + case XK_F4: ProcessFKeys(4, shift); break; + case XK_F5: ProcessFKeys(5, shift); break; + case XK_F6: ProcessFKeys(6, shift); break; + case XK_F7: ProcessFKeys(7, shift); break; + case XK_F8: ProcessFKeys(8, shift); break; + case XK_F9: ProcessFKeys(9, shift); break; + case XK_F10: ProcessFKeys(10, shift); break; + case XK_F11: ProcessFKeys(11, shift); break; + case XK_F12: ProcessFKeys(12, shift); break; + + case XK_Escape: + signal(SIGINT, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + +#ifdef PCSX2_DEVBUILD + if( g_SaveGSStream >= 3 ) { + // gs state + g_SaveGSStream = 4; + break; + } +#endif + + ClosePlugins(); + if (!UseGui) + exit(0); + RunGui(); + break; + default: + GSkeyEvent(ev); + break; + } +} + +int SysInit() { + mkdir(SSTATES_DIR, 0755); + mkdir(MEMCARDS_DIR, 0755); + +#ifdef EMU_LOG + mkdir(LOGS_DIR, 0755); + +#ifdef PCSX2_DEVBUILD + if( g_TestRun.plogname != NULL ) + emuLog = fopen(g_TestRun.plogname, "w"); + if( emuLog == NULL ) + emuLog = fopen(LOGS_DIR "/emuLog.txt","wb"); +#endif + + if( emuLog != NULL ) + setvbuf(emuLog, NULL, _IONBF, 0); +#endif + + if(cpuInit() == -1 ) + return -1; + + while (LoadPlugins() == -1) { + if (Pcsx2Configure() == 0) + exit(1); + } + + return 0; +} + +void SysReset() { + cpuReset(); +} + +void SysClose() { + cpuShutdown(); + ReleasePlugins(); + + if (emuLog != NULL) { + fclose(emuLog); + emuLog = NULL; + } +} + +void SysPrintf(char *fmt, ...) { + va_list list; + char msg[512]; + char* ptr, *src; + int len, i, j, s; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (Config.PsxOut == 0) { +#ifdef EMU_LOG +#ifndef LOG_STDOUT + if (emuLog != NULL && !(varLog & 0x80000000)) { + fprintf(emuLog, "%s", msg); + } +#endif +#endif + return; + } + + // due to various linux ways of writing lines, convert all \r\n to \n +// src = msg; +// while( (ptr = strstr(src, "\r\n")) != NULL ) { +// ptr[0] = 0; +// printf("%s\n", src); +// src = ptr+2; +// } +// +// if( src[0] != 0 ) +// printf("%s", src); + printf("%s", msg); + +#ifdef EMU_LOG +#ifndef LOG_STDOUT + if (emuLog != NULL && !(varLog & 0x80000000)) { + ptr = msg; len = strlen(msg); + for (i=0, j=0; ipname = (char*)malloc(20); + sprintf(pblock->pname, "/pcsx2_shm%d", s_nShmCounter++); + shm_unlink(pblock->pname); // unlink to make sure one can be created + pblock->fd = shm_open(pblock->pname, O_RDWR|O_CREAT, 0); + + if( pblock->fd < 0 ) { + perror("shm_open failed"); + SysMessage("Failed to create shared memory object %s\n", pblock->pname); + return -1; + } + + if( ftruncate(fd, size) < 0 ) { + perror("ftruncate failed"); + SysMessage("Failed to allocate 0x%x bytes to shm\n", size); + } + + pblock->size = size; + + return 0; +} + +void SysPhysicalFree(PSMEMORYBLOCK* pblock) +{ + assert( pblock != NULL ); + if( pblock->fd ) + close(pblock->fd); + if( pblock->pname ) { + shm_unlink(pblock->pname); + free(pblock->pname); + } + memset(pblock, 0, sizeof(PSMEMORYBLOCK)); +} + +int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock) +{ + void* pmem; + assert(pblock != NULL && pblock->fd >= 0 && pblock->size >= size ); + pmem = mmap(base, size, PROT_READ|PROT_WRITE, MAP_SHARED, pblock->fd, 0); + + if( pmem != base ) { + + if( pmem == (void*)-1 ) { + munmap(base, size); + } + + SysPrintf("Failed to map memory at 0x%x of size 0x%x with shm %s\n", (uptr)base, (uptr)size, pblock->pname); + return -1; + } + + return 0; +} + +void SysVirtualFree(void* lpMemReserved, u32 size) +{ + if( munmap(lpMemReserved, size) < 0 ) + SysPrintf("Failed to unmap %x\n", lpMemReserved); +} + + +int SysMapUserPhysicalPages(void* Addr, uptr NumPages, PSMEMORYBLOCK* pblock, int pageoffset) +{ + void* pmem; + if( pblock == NULL ) { + // unmap + if( munmap(base, size) < 0 ) { + SysPrintf("SysMapUserPhysicalPages: Failed to unmap %x\n", Addr); + return 0; + } + } + else { + // map + pmem = mmap(Addr, NumPages*s_nPageSize, PROT_READ|PROT_WRITE, MAP_SHARED, pblock->fd, pageoffset*s_nPageSize); + if( pmem != base ) { + SysPrintf("SysMapUserPhysicalPages: Failed to map 0x%x, size=0x%x, offset=0x%x\n", + Addr, NumPages*s_nPageSize, pageoffset*s_nPageSize); + return 0; + } + } + + return 1; +} + +#endif diff --git a/pcsx2/Linux/Makefile.am b/pcsx2/Linux/Makefile.am new file mode 100644 index 0000000000..84abfcfda0 --- /dev/null +++ b/pcsx2/Linux/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I@srcdir@/../ + +bin_PROGRAMS = pcsx2 + +# the application source, library search path, and link libraries +pcsx2_SOURCES = Config.c interface.c GtkGui.c LnxMain.c support.c + +pcsx2_LDFLAGS = + +pcsx2_DEPENDENCIES = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a + +pcsx2_LDADD = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a + + +if RECBUILD +pcsx2_LDADD += ../x86/libx86recomp.a ../x86/ix86/libix86.a +pcsx2_DEPENDENCIES += ../x86/libx86recomp.a ../x86/ix86/libix86.a +endif + +pcsx2_DEPENDENCIES += ../DebugTools/libDebugTools.a +pcsx2_LDADD += ../DebugTools/libDebugTools.a \ No newline at end of file diff --git a/pcsx2/Linux/buildgui.sh b/pcsx2/Linux/buildgui.sh new file mode 100644 index 0000000000..ef9beeb9f4 --- /dev/null +++ b/pcsx2/Linux/buildgui.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Pcsx2 - Pc Ps2 Emulator +# Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# +# builds the GUI C classes +mkdir temp +cp pcsx2.glade temp/ +cd temp +glade-2 --write-source pcsx2.glade +rm src/main.c +cp src/*.h src/*.c ../ +cd .. +/bin/rm -rf temp diff --git a/pcsx2/Linux/callbacks.h b/pcsx2/Linux/callbacks.h new file mode 100644 index 0000000000..83aabc0166 --- /dev/null +++ b/pcsx2/Linux/callbacks.h @@ -0,0 +1,403 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include + + +void +OnDestroy (GtkObject *object, + gpointer user_data); + +void +OnFile_RunCD (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnFile_LoadElf (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Load1 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Load2 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Load3 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Load4 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Load5 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_LoadOther (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Save1 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Save2 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Save3 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Save4 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_Save5 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnStates_SaveOther (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnFile_Exit (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnEmu_Run (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnEmu_Reset (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnEmu_Arguments (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Conf (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Gs (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Pads (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Spu2 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Cdvd (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Dev9 (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Usb (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Fw (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnConf_Cpu (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_patch_browser1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_patch_finder2_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_enable_console1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_enable_patches1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnDebug_Debugger (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnDebug_Logging (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnHelp_About (GtkMenuItem *menuitem, + gpointer user_data); + +void +OnHelpAbout_Ok (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad2Conf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad2Test (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad2About (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad1Conf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad1Test (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Pad1About (GtkButton *button, + gpointer user_data); + +void +OnConfConf_GsConf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_GsTest (GtkButton *button, + gpointer user_data); + +void +OnConfConf_GsAbout (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Spu2Conf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Spu2Test (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Spu2About (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Dev9Conf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Dev9Test (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Dev9About (GtkButton *button, + gpointer user_data); + +void +OnConfConf_CdvdConf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_CdvdTest (GtkButton *button, + gpointer user_data); + +void +OnConfConf_CdvdAbout (GtkButton *button, + gpointer user_data); + +void +OnConfConf_UsbConf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_UsbTest (GtkButton *button, + gpointer user_data); + +void +OnConfConf_UsbAbout (GtkButton *button, + gpointer user_data); + +void +OnConfConf_FWConf (GtkButton *button, + gpointer user_data); + +void +OnConfConf_FWTest (GtkButton *button, + gpointer user_data); + +void +OnConfConf_FWAbout (GtkButton *button, + gpointer user_data); + +void +OnConfConf_PluginsPath (GtkButton *button, + gpointer user_data); + +void +OnConfConf_BiosPath (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConfConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnCpu_Ok (GtkButton *button, + gpointer user_data); + +void +OnCpu_Cancel (GtkButton *button, + gpointer user_data); + +void +OnDebug_EEMode (GtkToggleButton *togglebutton, + gpointer user_data); + +void +OnDebug_IOPMode (GtkToggleButton *togglebutton, + gpointer user_data); + +void +OnDebug_Step (GtkButton *button, + gpointer user_data); + +void +OnDebug_Skip (GtkButton *button, + gpointer user_data); + +void +OnDebug_Go (GtkButton *button, + gpointer user_data); + +void +OnDebug_Log (GtkButton *button, + gpointer user_data); + +void +OnDebug_SetPC (GtkButton *button, + gpointer user_data); + +void +OnDebug_SetBPA (GtkButton *button, + gpointer user_data); + +void +OnDebug_SetBPC (GtkButton *button, + gpointer user_data); + +void +OnDebug_ClearBPs (GtkButton *button, + gpointer user_data); + +void +OnDebug_DumpCode (GtkButton *button, + gpointer user_data); + +void +OnDebug_RawDump (GtkButton *button, + gpointer user_data); + +void +OnDebug_Close (GtkButton *button, + gpointer user_data); + +void +OnDebug_memWrite32 (GtkButton *button, + gpointer user_data); + +void +OnSetPC_Ok (GtkButton *button, + gpointer user_data); + +void +OnSetPC_Cancel (GtkButton *button, + gpointer user_data); + +void +OnSetBPA_Ok (GtkButton *button, + gpointer user_data); + +void +OnSetBPA_Cancel (GtkButton *button, + gpointer user_data); + +void +OnSetBPC_Ok (GtkButton *button, + gpointer user_data); + +void +OnSetBPC_Cancel (GtkButton *button, + gpointer user_data); + +void +OnDumpC_Ok (GtkButton *button, + gpointer user_data); + +void +OnDumpC_Cancel (GtkButton *button, + gpointer user_data); + +void +OnDumpR_Ok (GtkButton *button, + gpointer user_data); + +void +OnDumpR_Cancel (GtkButton *button, + gpointer user_data); + +void +OnLogging_Ok (GtkButton *button, + gpointer user_data); + +void +OnLogging_Cancel (GtkButton *button, + gpointer user_data); + +void +OnArguments_Ok (GtkButton *button, + gpointer user_data); + +void +OnArguments_Cancel (GtkButton *button, + gpointer user_data); + +void +OnMemWrite32_Ok (GtkButton *button, + gpointer user_data); + +void +OnMemWrite32_Cancel (GtkButton *button, + gpointer user_data); diff --git a/pcsx2/Linux/interface.c b/pcsx2/Linux/interface.c new file mode 100644 index 0000000000..84e1f6706a --- /dev/null +++ b/pcsx2/Linux/interface.c @@ -0,0 +1,2759 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_MainWindow (void) +{ + GtkWidget *MainWindow; + GtkWidget *vbox1; + GtkWidget *GtkMenuBar_Menu; + GtkWidget *GtkMenuItem_File; + GtkWidget *GtkMenuItem_File_menu; + GtkWidget *run_cd1; + GtkWidget *GtkMenuItem_LoadElf; + GtkWidget *separator2; + GtkWidget *states1; + GtkWidget *states1_menu; + GtkWidget *load1; + GtkWidget *load1_menu; + GtkWidget *slot_1; + GtkWidget *slot_3; + GtkWidget *slot_4; + GtkWidget *slot_5; + GtkWidget *slot_2; + GtkWidget *other1; + GtkWidget *save1; + GtkWidget *save1_menu; + GtkWidget *slot_6; + GtkWidget *slot_7; + GtkWidget *slot_8; + GtkWidget *slot_9; + GtkWidget *slot_10; + GtkWidget *other2; + GtkWidget *GtkMenuItem_Exit; + GtkWidget *GtkMenuItem_Emulator; + GtkWidget *GtkMenuItem_Emulator_menu; + GtkWidget *GtkMenuItem_Run; + GtkWidget *GtkMenuItem_Reset; + GtkWidget *GtkMenuItem_Arguments; + GtkWidget *GtkMenuItem_Configuration; + GtkWidget *GtkMenuItem_Configuration_menu; + GtkWidget *GtkMenuItem_PluginsBios; + GtkWidget *separator3; + GtkWidget *GtkMenuItem_Graphics; + GtkWidget *GtkMenuItem_Controllers; + GtkWidget *GtkMenuItem_Sound; + GtkWidget *GtkMenuItem_Cdvdrom; + GtkWidget *GtkMenuItem_Dev9; + GtkWidget *GtkMenuItem_USB; + GtkWidget *GtkMenuItem_FW; + GtkWidget *separator4; + GtkWidget *GtkMenuItem_Cpu; + GtkWidget *GtkMenuItem_Language; + GtkWidget *misc1; + GtkWidget *misc1_menu; + GtkWidget *patch_browser1; + GtkWidget *patch_finder2; + GtkWidget *separator7; + GtkWidget *enable_console1; + GtkWidget *enable_patches1; + GtkWidget *GtkMenuItem_Debug; + GtkWidget *GtkMenuItem_Debug_menu; + GtkWidget *GtkMenuItem_EnterDebugger; + GtkWidget *GtkMenuItem_Logging; + GtkWidget *GtkMenuItem_Help; + GtkWidget *GtkMenuItem_Help_menu; + GtkWidget *GtkMenuItem_About; + GtkWidget *image1; + GtkWidget *status_box; + + MainWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (MainWindow), _("PCSX")); + gtk_window_set_position (GTK_WINDOW (MainWindow), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (MainWindow), vbox1); + + GtkMenuBar_Menu = gtk_menu_bar_new (); + gtk_widget_show (GtkMenuBar_Menu); + gtk_box_pack_start (GTK_BOX (vbox1), GtkMenuBar_Menu, FALSE, FALSE, 0); + + GtkMenuItem_File = gtk_menu_item_new_with_mnemonic (_("_File")); + gtk_widget_show (GtkMenuItem_File); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_File); + + GtkMenuItem_File_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (GtkMenuItem_File), GtkMenuItem_File_menu); + + run_cd1 = gtk_menu_item_new_with_mnemonic (_("_Run CD")); + gtk_widget_show (run_cd1); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_File_menu), run_cd1); + + GtkMenuItem_LoadElf = gtk_menu_item_new_with_mnemonic (_("_Load Elf")); + gtk_widget_show (GtkMenuItem_LoadElf); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_File_menu), GtkMenuItem_LoadElf); + + separator2 = gtk_separator_menu_item_new (); + gtk_widget_show (separator2); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_File_menu), separator2); + gtk_widget_set_sensitive (separator2, FALSE); + + states1 = gtk_menu_item_new_with_mnemonic (_("States")); + gtk_widget_show (states1); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_File_menu), states1); + + states1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (states1), states1_menu); + + load1 = gtk_menu_item_new_with_mnemonic (_("Load")); + gtk_widget_show (load1); + gtk_container_add (GTK_CONTAINER (states1_menu), load1); + + load1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (load1), load1_menu); + + slot_1 = gtk_menu_item_new_with_mnemonic (_("Slot 1")); + gtk_widget_show (slot_1); + gtk_container_add (GTK_CONTAINER (load1_menu), slot_1); + + slot_3 = gtk_menu_item_new_with_mnemonic (_("Slot 2")); + gtk_widget_show (slot_3); + gtk_container_add (GTK_CONTAINER (load1_menu), slot_3); + + slot_4 = gtk_menu_item_new_with_mnemonic (_("Slot 3")); + gtk_widget_show (slot_4); + gtk_container_add (GTK_CONTAINER (load1_menu), slot_4); + + slot_5 = gtk_menu_item_new_with_mnemonic (_("Slot 4")); + gtk_widget_show (slot_5); + gtk_container_add (GTK_CONTAINER (load1_menu), slot_5); + + slot_2 = gtk_menu_item_new_with_mnemonic (_("Slot 5")); + gtk_widget_show (slot_2); + gtk_container_add (GTK_CONTAINER (load1_menu), slot_2); + + other1 = gtk_menu_item_new_with_mnemonic (_("Other...")); + gtk_widget_show (other1); + gtk_container_add (GTK_CONTAINER (load1_menu), other1); + + save1 = gtk_menu_item_new_with_mnemonic (_("Save")); + gtk_widget_show (save1); + gtk_container_add (GTK_CONTAINER (states1_menu), save1); + + save1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (save1), save1_menu); + + slot_6 = gtk_menu_item_new_with_mnemonic (_("Slot 1")); + gtk_widget_show (slot_6); + gtk_container_add (GTK_CONTAINER (save1_menu), slot_6); + + slot_7 = gtk_menu_item_new_with_mnemonic (_("Slot 2")); + gtk_widget_show (slot_7); + gtk_container_add (GTK_CONTAINER (save1_menu), slot_7); + + slot_8 = gtk_menu_item_new_with_mnemonic (_("Slot 3")); + gtk_widget_show (slot_8); + gtk_container_add (GTK_CONTAINER (save1_menu), slot_8); + + slot_9 = gtk_menu_item_new_with_mnemonic (_("Slot 4")); + gtk_widget_show (slot_9); + gtk_container_add (GTK_CONTAINER (save1_menu), slot_9); + + slot_10 = gtk_menu_item_new_with_mnemonic (_("Slot 5")); + gtk_widget_show (slot_10); + gtk_container_add (GTK_CONTAINER (save1_menu), slot_10); + + other2 = gtk_menu_item_new_with_mnemonic (_("Other...")); + gtk_widget_show (other2); + gtk_container_add (GTK_CONTAINER (save1_menu), other2); + + GtkMenuItem_Exit = gtk_menu_item_new_with_mnemonic (_("E_xit")); + gtk_widget_show (GtkMenuItem_Exit); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_File_menu), GtkMenuItem_Exit); + + GtkMenuItem_Emulator = gtk_menu_item_new_with_mnemonic (_("_Run")); + gtk_widget_show (GtkMenuItem_Emulator); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_Emulator); + + GtkMenuItem_Emulator_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (GtkMenuItem_Emulator), GtkMenuItem_Emulator_menu); + + GtkMenuItem_Run = gtk_menu_item_new_with_mnemonic (_("E_xecute")); + gtk_widget_show (GtkMenuItem_Run); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Emulator_menu), GtkMenuItem_Run); + + GtkMenuItem_Reset = gtk_menu_item_new_with_mnemonic (_("Re_set")); + gtk_widget_show (GtkMenuItem_Reset); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Emulator_menu), GtkMenuItem_Reset); + + GtkMenuItem_Arguments = gtk_menu_item_new_with_mnemonic (_("_Arguments")); + gtk_widget_show (GtkMenuItem_Arguments); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Emulator_menu), GtkMenuItem_Arguments); + + GtkMenuItem_Configuration = gtk_menu_item_new_with_mnemonic (_("_Config")); + gtk_widget_show (GtkMenuItem_Configuration); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_Configuration); + + GtkMenuItem_Configuration_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (GtkMenuItem_Configuration), GtkMenuItem_Configuration_menu); + + GtkMenuItem_PluginsBios = gtk_menu_item_new_with_mnemonic (_("_Configure")); + gtk_widget_show (GtkMenuItem_PluginsBios); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_PluginsBios); + + separator3 = gtk_separator_menu_item_new (); + gtk_widget_show (separator3); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), separator3); + gtk_widget_set_sensitive (separator3, FALSE); + + GtkMenuItem_Graphics = gtk_menu_item_new_with_mnemonic (_("_Graphics")); + gtk_widget_show (GtkMenuItem_Graphics); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Graphics); + + GtkMenuItem_Controllers = gtk_menu_item_new_with_mnemonic (_("C_ontrollers")); + gtk_widget_show (GtkMenuItem_Controllers); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Controllers); + + GtkMenuItem_Sound = gtk_menu_item_new_with_mnemonic (_("_Sound")); + gtk_widget_show (GtkMenuItem_Sound); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Sound); + + GtkMenuItem_Cdvdrom = gtk_menu_item_new_with_mnemonic (_("_Cdvdrom")); + gtk_widget_show (GtkMenuItem_Cdvdrom); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Cdvdrom); + + GtkMenuItem_Dev9 = gtk_menu_item_new_with_mnemonic (_("D_ev9")); + gtk_widget_show (GtkMenuItem_Dev9); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Dev9); + + GtkMenuItem_USB = gtk_menu_item_new_with_mnemonic (_("U_SB")); + gtk_widget_show (GtkMenuItem_USB); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_USB); + + GtkMenuItem_FW = gtk_menu_item_new_with_mnemonic (_("Fire_Wire")); + gtk_widget_show (GtkMenuItem_FW); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_FW); + + separator4 = gtk_separator_menu_item_new (); + gtk_widget_show (separator4); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), separator4); + gtk_widget_set_sensitive (separator4, FALSE); + + GtkMenuItem_Cpu = gtk_menu_item_new_with_mnemonic (_("C_pu")); + gtk_widget_show (GtkMenuItem_Cpu); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Configuration_menu), GtkMenuItem_Cpu); + + GtkMenuItem_Language = gtk_menu_item_new_with_mnemonic (_("_Language")); + gtk_widget_show (GtkMenuItem_Language); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_Language); + + misc1 = gtk_menu_item_new_with_mnemonic (_("_Misc")); + gtk_widget_show (misc1); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), misc1); + + misc1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (misc1), misc1_menu); + + patch_browser1 = gtk_menu_item_new_with_mnemonic (_("Patch _Browser")); + gtk_widget_show (patch_browser1); + gtk_container_add (GTK_CONTAINER (misc1_menu), patch_browser1); + + patch_finder2 = gtk_menu_item_new_with_mnemonic (_("Patch _Finder")); + gtk_widget_show (patch_finder2); + gtk_container_add (GTK_CONTAINER (misc1_menu), patch_finder2); + + separator7 = gtk_separator_menu_item_new (); + gtk_widget_show (separator7); + gtk_container_add (GTK_CONTAINER (misc1_menu), separator7); + gtk_widget_set_sensitive (separator7, FALSE); + + enable_console1 = gtk_check_menu_item_new_with_mnemonic (_("Enable _Console")); + gtk_widget_show (enable_console1); + gtk_container_add (GTK_CONTAINER (misc1_menu), enable_console1); + + enable_patches1 = gtk_check_menu_item_new_with_mnemonic (_("Enable _Patches")); + gtk_widget_show (enable_patches1); + gtk_container_add (GTK_CONTAINER (misc1_menu), enable_patches1); + + GtkMenuItem_Debug = gtk_menu_item_new_with_mnemonic (_("_Debug")); + gtk_widget_show (GtkMenuItem_Debug); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_Debug); + + GtkMenuItem_Debug_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (GtkMenuItem_Debug), GtkMenuItem_Debug_menu); + + GtkMenuItem_EnterDebugger = gtk_menu_item_new_with_mnemonic (_("Enter Debugger ...")); + gtk_widget_show (GtkMenuItem_EnterDebugger); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Debug_menu), GtkMenuItem_EnterDebugger); + + GtkMenuItem_Logging = gtk_menu_item_new_with_mnemonic (_("Logging")); + gtk_widget_show (GtkMenuItem_Logging); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Debug_menu), GtkMenuItem_Logging); + + GtkMenuItem_Help = gtk_menu_item_new_with_mnemonic (_("_Help")); + gtk_widget_show (GtkMenuItem_Help); + gtk_container_add (GTK_CONTAINER (GtkMenuBar_Menu), GtkMenuItem_Help); + + GtkMenuItem_Help_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (GtkMenuItem_Help), GtkMenuItem_Help_menu); + + GtkMenuItem_About = gtk_menu_item_new_with_mnemonic (_("&About...")); + gtk_widget_show (GtkMenuItem_About); + gtk_container_add (GTK_CONTAINER (GtkMenuItem_Help_menu), GtkMenuItem_About); + + image1 = create_pixmap (MainWindow, "pcsxAbout.bmp"); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (vbox1), image1, TRUE, TRUE, 1); + + status_box = gtk_vbox_new (FALSE, 0); + gtk_widget_show (status_box); + gtk_box_pack_start (GTK_BOX (vbox1), status_box, TRUE, TRUE, 0); + + g_signal_connect ((gpointer) MainWindow, "destroy", + G_CALLBACK (OnDestroy), + NULL); + g_signal_connect ((gpointer) run_cd1, "activate", + G_CALLBACK (OnFile_RunCD), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_LoadElf, "activate", + G_CALLBACK (OnFile_LoadElf), + NULL); + g_signal_connect ((gpointer) slot_1, "activate", + G_CALLBACK (OnStates_Load1), + NULL); + g_signal_connect ((gpointer) slot_3, "activate", + G_CALLBACK (OnStates_Load2), + NULL); + g_signal_connect ((gpointer) slot_4, "activate", + G_CALLBACK (OnStates_Load3), + NULL); + g_signal_connect ((gpointer) slot_5, "activate", + G_CALLBACK (OnStates_Load4), + NULL); + g_signal_connect ((gpointer) slot_2, "activate", + G_CALLBACK (OnStates_Load5), + NULL); + g_signal_connect ((gpointer) other1, "activate", + G_CALLBACK (OnStates_LoadOther), + NULL); + g_signal_connect ((gpointer) slot_6, "activate", + G_CALLBACK (OnStates_Save1), + NULL); + g_signal_connect ((gpointer) slot_7, "activate", + G_CALLBACK (OnStates_Save2), + NULL); + g_signal_connect ((gpointer) slot_8, "activate", + G_CALLBACK (OnStates_Save3), + NULL); + g_signal_connect ((gpointer) slot_9, "activate", + G_CALLBACK (OnStates_Save4), + NULL); + g_signal_connect ((gpointer) slot_10, "activate", + G_CALLBACK (OnStates_Save5), + NULL); + g_signal_connect ((gpointer) other2, "activate", + G_CALLBACK (OnStates_SaveOther), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Exit, "activate", + G_CALLBACK (OnFile_Exit), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Run, "activate", + G_CALLBACK (OnEmu_Run), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Reset, "activate", + G_CALLBACK (OnEmu_Reset), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Arguments, "activate", + G_CALLBACK (OnEmu_Arguments), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_PluginsBios, "activate", + G_CALLBACK (OnConf_Conf), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Graphics, "activate", + G_CALLBACK (OnConf_Gs), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Controllers, "activate", + G_CALLBACK (OnConf_Pads), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Sound, "activate", + G_CALLBACK (OnConf_Spu2), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Cdvdrom, "activate", + G_CALLBACK (OnConf_Cdvd), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Dev9, "activate", + G_CALLBACK (OnConf_Dev9), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_USB, "activate", + G_CALLBACK (OnConf_Usb), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_FW, "activate", + G_CALLBACK (OnConf_Fw), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Cpu, "activate", + G_CALLBACK (OnConf_Cpu), + NULL); + g_signal_connect ((gpointer) patch_browser1, "activate", + G_CALLBACK (on_patch_browser1_activate), + NULL); + g_signal_connect ((gpointer) patch_finder2, "activate", + G_CALLBACK (on_patch_finder2_activate), + NULL); + g_signal_connect ((gpointer) enable_console1, "activate", + G_CALLBACK (on_enable_console1_activate), + NULL); + g_signal_connect ((gpointer) enable_patches1, "activate", + G_CALLBACK (on_enable_patches1_activate), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_EnterDebugger, "activate", + G_CALLBACK (OnDebug_Debugger), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_Logging, "activate", + G_CALLBACK (OnDebug_Logging), + NULL); + g_signal_connect ((gpointer) GtkMenuItem_About, "activate", + G_CALLBACK (OnHelp_About), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (MainWindow, MainWindow, "MainWindow"); + GLADE_HOOKUP_OBJECT (MainWindow, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuBar_Menu, "GtkMenuBar_Menu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_File, "GtkMenuItem_File"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_File_menu, "GtkMenuItem_File_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, run_cd1, "run_cd1"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_LoadElf, "GtkMenuItem_LoadElf"); + GLADE_HOOKUP_OBJECT (MainWindow, separator2, "separator2"); + GLADE_HOOKUP_OBJECT (MainWindow, states1, "states1"); + GLADE_HOOKUP_OBJECT (MainWindow, states1_menu, "states1_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, load1, "load1"); + GLADE_HOOKUP_OBJECT (MainWindow, load1_menu, "load1_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_1, "slot_1"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_3, "slot_3"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_4, "slot_4"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_5, "slot_5"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_2, "slot_2"); + GLADE_HOOKUP_OBJECT (MainWindow, other1, "other1"); + GLADE_HOOKUP_OBJECT (MainWindow, save1, "save1"); + GLADE_HOOKUP_OBJECT (MainWindow, save1_menu, "save1_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_6, "slot_6"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_7, "slot_7"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_8, "slot_8"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_9, "slot_9"); + GLADE_HOOKUP_OBJECT (MainWindow, slot_10, "slot_10"); + GLADE_HOOKUP_OBJECT (MainWindow, other2, "other2"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Exit, "GtkMenuItem_Exit"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Emulator, "GtkMenuItem_Emulator"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Emulator_menu, "GtkMenuItem_Emulator_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Run, "GtkMenuItem_Run"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Reset, "GtkMenuItem_Reset"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Arguments, "GtkMenuItem_Arguments"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Configuration, "GtkMenuItem_Configuration"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Configuration_menu, "GtkMenuItem_Configuration_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_PluginsBios, "GtkMenuItem_PluginsBios"); + GLADE_HOOKUP_OBJECT (MainWindow, separator3, "separator3"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Graphics, "GtkMenuItem_Graphics"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Controllers, "GtkMenuItem_Controllers"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Sound, "GtkMenuItem_Sound"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Cdvdrom, "GtkMenuItem_Cdvdrom"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Dev9, "GtkMenuItem_Dev9"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_USB, "GtkMenuItem_USB"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_FW, "GtkMenuItem_FW"); + GLADE_HOOKUP_OBJECT (MainWindow, separator4, "separator4"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Cpu, "GtkMenuItem_Cpu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Language, "GtkMenuItem_Language"); + GLADE_HOOKUP_OBJECT (MainWindow, misc1, "misc1"); + GLADE_HOOKUP_OBJECT (MainWindow, misc1_menu, "misc1_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, patch_browser1, "patch_browser1"); + GLADE_HOOKUP_OBJECT (MainWindow, patch_finder2, "patch_finder2"); + GLADE_HOOKUP_OBJECT (MainWindow, separator7, "separator7"); + GLADE_HOOKUP_OBJECT (MainWindow, enable_console1, "enable_console1"); + GLADE_HOOKUP_OBJECT (MainWindow, enable_patches1, "enable_patches1"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Debug, "GtkMenuItem_Debug"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Debug_menu, "GtkMenuItem_Debug_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_EnterDebugger, "GtkMenuItem_EnterDebugger"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Logging, "GtkMenuItem_Logging"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Help, "GtkMenuItem_Help"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_Help_menu, "GtkMenuItem_Help_menu"); + GLADE_HOOKUP_OBJECT (MainWindow, GtkMenuItem_About, "GtkMenuItem_About"); + GLADE_HOOKUP_OBJECT (MainWindow, image1, "image1"); + GLADE_HOOKUP_OBJECT (MainWindow, status_box, "status_box"); + + return MainWindow; +} + +GtkWidget* +create_AboutDlg (void) +{ + GtkWidget *AboutDlg; + GtkWidget *vbox2; + GtkWidget *hbox1; + GtkWidget *vbox4; + GtkWidget *GtkAbout_LabelVersion; + GtkWidget *frame1; + GtkWidget *vbox6; + GtkWidget *GtkAbout_LabelAuthors; + GtkWidget *pixmap1; + GtkWidget *frame2; + GtkWidget *vbox5; + GtkWidget *GtkAbout_LabelGreets; + GtkWidget *hbuttonbox1; + GtkWidget *GtkButton_Ok; + + AboutDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (AboutDlg), 10); + gtk_window_set_title (GTK_WINDOW (AboutDlg), _("Pcsx About")); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (AboutDlg), vbox2); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox2), hbox1, TRUE, TRUE, 0); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_box_pack_start (GTK_BOX (hbox1), vbox4, TRUE, TRUE, 0); + + GtkAbout_LabelVersion = gtk_label_new (_("PCSX2\n\nVersion x.x")); + gtk_widget_show (GtkAbout_LabelVersion); + gtk_box_pack_start (GTK_BOX (vbox4), GtkAbout_LabelVersion, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GtkAbout_LabelVersion), GTK_JUSTIFY_CENTER); + + frame1 = gtk_frame_new (NULL); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox4), frame1, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame1), 5); + + vbox6 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox6); + gtk_container_add (GTK_CONTAINER (frame1), vbox6); + gtk_container_set_border_width (GTK_CONTAINER (vbox6), 5); + + GtkAbout_LabelAuthors = gtk_label_new (_("written by...")); + gtk_widget_show (GtkAbout_LabelAuthors); + gtk_box_pack_start (GTK_BOX (vbox6), GtkAbout_LabelAuthors, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GtkAbout_LabelAuthors), GTK_JUSTIFY_CENTER); + + pixmap1 = create_pixmap (AboutDlg, "pcsxAbout.xpm"); + gtk_widget_show (pixmap1); + gtk_box_pack_start (GTK_BOX (hbox1), pixmap1, TRUE, TRUE, 0); + + frame2 = gtk_frame_new (NULL); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox2), frame2, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame2), 5); + + vbox5 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox5); + gtk_container_add (GTK_CONTAINER (frame2), vbox5); + gtk_container_set_border_width (GTK_CONTAINER (vbox5), 5); + + GtkAbout_LabelGreets = gtk_label_new (_("greets to...")); + gtk_widget_show (GtkAbout_LabelGreets); + gtk_box_pack_start (GTK_BOX (vbox5), GtkAbout_LabelGreets, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GtkAbout_LabelGreets), GTK_JUSTIFY_CENTER); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox1, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 30); + + GtkButton_Ok = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (GtkButton_Ok); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), GtkButton_Ok); + GTK_WIDGET_SET_FLAGS (GtkButton_Ok, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) GtkButton_Ok, "clicked", + G_CALLBACK (OnHelpAbout_Ok), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (AboutDlg, AboutDlg, "AboutDlg"); + GLADE_HOOKUP_OBJECT (AboutDlg, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (AboutDlg, hbox1, "hbox1"); + GLADE_HOOKUP_OBJECT (AboutDlg, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (AboutDlg, GtkAbout_LabelVersion, "GtkAbout_LabelVersion"); + GLADE_HOOKUP_OBJECT (AboutDlg, frame1, "frame1"); + GLADE_HOOKUP_OBJECT (AboutDlg, vbox6, "vbox6"); + GLADE_HOOKUP_OBJECT (AboutDlg, GtkAbout_LabelAuthors, "GtkAbout_LabelAuthors"); + GLADE_HOOKUP_OBJECT (AboutDlg, pixmap1, "pixmap1"); + GLADE_HOOKUP_OBJECT (AboutDlg, frame2, "frame2"); + GLADE_HOOKUP_OBJECT (AboutDlg, vbox5, "vbox5"); + GLADE_HOOKUP_OBJECT (AboutDlg, GtkAbout_LabelGreets, "GtkAbout_LabelGreets"); + GLADE_HOOKUP_OBJECT (AboutDlg, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (AboutDlg, GtkButton_Ok, "GtkButton_Ok"); + + return AboutDlg; +} + +GtkWidget* +create_ConfDlg (void) +{ + GtkWidget *ConfDlg; + GtkWidget *vbox12; + GtkWidget *table2; + GtkWidget *GtkCombo_Pad1; + GList *GtkCombo_Pad1_items = NULL; + GtkWidget *combo_entry4; + GtkWidget *GtkCombo_Pad2; + GList *GtkCombo_Pad2_items = NULL; + GtkWidget *combo_entry5; + GtkWidget *hbuttonbox6; + GtkWidget *GtkButton_PAD2configure; + GtkWidget *GtkButton_PAD2test; + GtkWidget *GtkButton_PAD2about; + GtkWidget *hbuttonbox7; + GtkWidget *GtkButton_PAD1configure; + GtkWidget *GtkButton_PAD1test; + GtkWidget *GtkButton_PAD1about; + GtkWidget *hbuttonbox8; + GtkWidget *GtkButton_GSconfigure; + GtkWidget *GtkButton_GStest; + GtkWidget *GtkButton_GSabout; + GtkWidget *GtkLabel_Graphics; + GtkWidget *GtkLabel_FirstController; + GtkWidget *GtkLabel_SecondController; + GtkWidget *GtkCombo_Gs; + GList *GtkCombo_Gs_items = NULL; + GtkWidget *combo_entry2; + GtkWidget *GtkLabel_Sound; + GtkWidget *GtkCombo_Spu2; + GList *GtkCombo_Spu2_items = NULL; + GtkWidget *entry1; + GtkWidget *hbuttonbox12; + GtkWidget *GtkButton_SPU2configure; + GtkWidget *GtkButton_SPU2test; + GtkWidget *GtkButton_SPU2about; + GtkWidget *GtkCombo_Dev9; + GList *GtkCombo_Dev9_items = NULL; + GtkWidget *entry3; + GtkWidget *hbuttonbox21; + GtkWidget *GtkButton_DEV9configure; + GtkWidget *GtkButton_DEV9test; + GtkWidget *GtkButton_DEV9about; + GtkWidget *label23; + GtkWidget *GtkLabel_Cdvdrom; + GtkWidget *GtkCombo_Cdvd; + GList *GtkCombo_Cdvd_items = NULL; + GtkWidget *entry2; + GtkWidget *hbuttonbox13; + GtkWidget *GtkButton_CDVDconfigure; + GtkWidget *GtkButton_CDVDtest; + GtkWidget *GtkButton_CDVDabout; + GtkWidget *label29; + GtkWidget *GtkCombo_Usb; + GList *GtkCombo_Usb_items = NULL; + GtkWidget *entry4; + GtkWidget *hbuttonbox23; + GtkWidget *GtkButton_USBconfigure; + GtkWidget *GtkButton_USBtest; + GtkWidget *GtkButton_USBabout; + GtkWidget *GtkCombo_Bios; + GList *GtkCombo_Bios_items = NULL; + GtkWidget *combo_entry7; + GtkWidget *GtkCombo_FW; + GList *GtkCombo_FW_items = NULL; + GtkWidget *entry5; + GtkWidget *hbuttonbox24; + GtkWidget *GtkButton_FWconfigure; + GtkWidget *GtkButton_FWtest; + GtkWidget *GtkButton_FireWireabout; + GtkWidget *label30; + GtkWidget *GtkLabel_Bios; + GtkWidget *hbox5; + GtkWidget *hbuttonbox11; + GtkWidget *GtkButton_SelectPluginsDir; + GtkWidget *GtkButton_SelectBiosDir; + GtkWidget *hbuttonbox10; + GtkWidget *GtkButton_Ok; + GtkWidget *GtkButton_Cancel; + + ConfDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (ConfDlg), 10); + gtk_window_set_title (GTK_WINDOW (ConfDlg), _("Conf")); + + vbox12 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox12); + gtk_container_add (GTK_CONTAINER (ConfDlg), vbox12); + + table2 = gtk_table_new (14, 2, FALSE); + gtk_widget_show (table2); + gtk_box_pack_start (GTK_BOX (vbox12), table2, TRUE, TRUE, 0); + gtk_table_set_col_spacings (GTK_TABLE (table2), 15); + + GtkCombo_Pad1 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Pad1)->popwin), + "GladeParentKey", GtkCombo_Pad1); + gtk_widget_show (GtkCombo_Pad1); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Pad1, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Pad1_items = g_list_append (GtkCombo_Pad1_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Pad1), GtkCombo_Pad1_items); + g_list_free (GtkCombo_Pad1_items); + + combo_entry4 = GTK_COMBO (GtkCombo_Pad1)->entry; + gtk_widget_show (combo_entry4); + gtk_entry_set_invisible_char (GTK_ENTRY (combo_entry4), 8226); + + GtkCombo_Pad2 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Pad2)->popwin), + "GladeParentKey", GtkCombo_Pad2); + gtk_widget_show (GtkCombo_Pad2); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Pad2, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Pad2_items = g_list_append (GtkCombo_Pad2_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Pad2), GtkCombo_Pad2_items); + g_list_free (GtkCombo_Pad2_items); + + combo_entry5 = GTK_COMBO (GtkCombo_Pad2)->entry; + gtk_widget_show (combo_entry5); + gtk_entry_set_invisible_char (GTK_ENTRY (combo_entry5), 8226); + + hbuttonbox6 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox6); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox6, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + GtkButton_PAD2configure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_PAD2configure); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), GtkButton_PAD2configure); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD2configure, GTK_CAN_DEFAULT); + + GtkButton_PAD2test = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_PAD2test); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), GtkButton_PAD2test); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD2test, GTK_CAN_DEFAULT); + + GtkButton_PAD2about = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_PAD2about); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), GtkButton_PAD2about); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD2about, GTK_CAN_DEFAULT); + + hbuttonbox7 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox7); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox7, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + GtkButton_PAD1configure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_PAD1configure); + gtk_container_add (GTK_CONTAINER (hbuttonbox7), GtkButton_PAD1configure); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD1configure, GTK_CAN_DEFAULT); + + GtkButton_PAD1test = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_PAD1test); + gtk_container_add (GTK_CONTAINER (hbuttonbox7), GtkButton_PAD1test); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD1test, GTK_CAN_DEFAULT); + + GtkButton_PAD1about = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_PAD1about); + gtk_container_add (GTK_CONTAINER (hbuttonbox7), GtkButton_PAD1about); + GTK_WIDGET_SET_FLAGS (GtkButton_PAD1about, GTK_CAN_DEFAULT); + + hbuttonbox8 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox8); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox8, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + GtkButton_GSconfigure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_GSconfigure); + gtk_container_add (GTK_CONTAINER (hbuttonbox8), GtkButton_GSconfigure); + GTK_WIDGET_SET_FLAGS (GtkButton_GSconfigure, GTK_CAN_DEFAULT); + + GtkButton_GStest = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_GStest); + gtk_container_add (GTK_CONTAINER (hbuttonbox8), GtkButton_GStest); + GTK_WIDGET_SET_FLAGS (GtkButton_GStest, GTK_CAN_DEFAULT); + + GtkButton_GSabout = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_GSabout); + gtk_container_add (GTK_CONTAINER (hbuttonbox8), GtkButton_GSabout); + GTK_WIDGET_SET_FLAGS (GtkButton_GSabout, GTK_CAN_DEFAULT); + + GtkLabel_Graphics = gtk_label_new (_("Graphics")); + gtk_widget_show (GtkLabel_Graphics); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_Graphics, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Graphics), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_Graphics), 0, 0.5); + + GtkLabel_FirstController = gtk_label_new (_("First Controller")); + gtk_widget_show (GtkLabel_FirstController); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_FirstController, 0, 1, 3, 4, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_FirstController), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_FirstController), 0, 0.5); + + GtkLabel_SecondController = gtk_label_new (_("Second Controller")); + gtk_widget_show (GtkLabel_SecondController); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_SecondController, 1, 2, 3, 4, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_SecondController), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_SecondController), 0, 0.5); + + GtkCombo_Gs = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Gs)->popwin), + "GladeParentKey", GtkCombo_Gs); + gtk_widget_show (GtkCombo_Gs); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Gs, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Gs_items = g_list_append (GtkCombo_Gs_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Gs), GtkCombo_Gs_items); + g_list_free (GtkCombo_Gs_items); + + combo_entry2 = GTK_COMBO (GtkCombo_Gs)->entry; + gtk_widget_show (combo_entry2); + gtk_entry_set_invisible_char (GTK_ENTRY (combo_entry2), 8226); + + GtkLabel_Sound = gtk_label_new (_("Sound")); + gtk_widget_show (GtkLabel_Sound); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_Sound, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Sound), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_Sound), 0, 0.5); + + GtkCombo_Spu2 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Spu2)->popwin), + "GladeParentKey", GtkCombo_Spu2); + gtk_widget_show (GtkCombo_Spu2); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Spu2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Spu2_items = g_list_append (GtkCombo_Spu2_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Spu2), GtkCombo_Spu2_items); + g_list_free (GtkCombo_Spu2_items); + + entry1 = GTK_COMBO (GtkCombo_Spu2)->entry; + gtk_widget_show (entry1); + gtk_entry_set_invisible_char (GTK_ENTRY (entry1), 8226); + + hbuttonbox12 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox12); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox12, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + GtkButton_SPU2configure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_SPU2configure); + gtk_container_add (GTK_CONTAINER (hbuttonbox12), GtkButton_SPU2configure); + GTK_WIDGET_SET_FLAGS (GtkButton_SPU2configure, GTK_CAN_DEFAULT); + + GtkButton_SPU2test = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_SPU2test); + gtk_container_add (GTK_CONTAINER (hbuttonbox12), GtkButton_SPU2test); + GTK_WIDGET_SET_FLAGS (GtkButton_SPU2test, GTK_CAN_DEFAULT); + + GtkButton_SPU2about = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_SPU2about); + gtk_container_add (GTK_CONTAINER (hbuttonbox12), GtkButton_SPU2about); + GTK_WIDGET_SET_FLAGS (GtkButton_SPU2about, GTK_CAN_DEFAULT); + + GtkCombo_Dev9 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Dev9)->popwin), + "GladeParentKey", GtkCombo_Dev9); + gtk_widget_show (GtkCombo_Dev9); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Dev9, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Dev9_items = g_list_append (GtkCombo_Dev9_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Dev9), GtkCombo_Dev9_items); + g_list_free (GtkCombo_Dev9_items); + + entry3 = GTK_COMBO (GtkCombo_Dev9)->entry; + gtk_widget_show (entry3); + gtk_entry_set_invisible_char (GTK_ENTRY (entry3), 8226); + + hbuttonbox21 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox21); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox21, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + GtkButton_DEV9configure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_DEV9configure); + gtk_container_add (GTK_CONTAINER (hbuttonbox21), GtkButton_DEV9configure); + GTK_WIDGET_SET_FLAGS (GtkButton_DEV9configure, GTK_CAN_DEFAULT); + + GtkButton_DEV9test = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_DEV9test); + gtk_container_add (GTK_CONTAINER (hbuttonbox21), GtkButton_DEV9test); + GTK_WIDGET_SET_FLAGS (GtkButton_DEV9test, GTK_CAN_DEFAULT); + + GtkButton_DEV9about = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_DEV9about); + gtk_container_add (GTK_CONTAINER (hbuttonbox21), GtkButton_DEV9about); + GTK_WIDGET_SET_FLAGS (GtkButton_DEV9about, GTK_CAN_DEFAULT); + + label23 = gtk_label_new (_("Dev9")); + gtk_widget_show (label23); + gtk_table_attach (GTK_TABLE (table2), label23, 0, 1, 6, 7, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label23), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label23), 0, 0.5); + + GtkLabel_Cdvdrom = gtk_label_new (_("Cdvdrom")); + gtk_widget_show (GtkLabel_Cdvdrom); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_Cdvdrom, 1, 2, 6, 7, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Cdvdrom), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_Cdvdrom), 0, 0.5); + + GtkCombo_Cdvd = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Cdvd)->popwin), + "GladeParentKey", GtkCombo_Cdvd); + gtk_widget_show (GtkCombo_Cdvd); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Cdvd, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Cdvd_items = g_list_append (GtkCombo_Cdvd_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Cdvd), GtkCombo_Cdvd_items); + g_list_free (GtkCombo_Cdvd_items); + + entry2 = GTK_COMBO (GtkCombo_Cdvd)->entry; + gtk_widget_show (entry2); + gtk_entry_set_invisible_char (GTK_ENTRY (entry2), 8226); + + hbuttonbox13 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox13); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox13, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + GtkButton_CDVDconfigure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_CDVDconfigure); + gtk_container_add (GTK_CONTAINER (hbuttonbox13), GtkButton_CDVDconfigure); + GTK_WIDGET_SET_FLAGS (GtkButton_CDVDconfigure, GTK_CAN_DEFAULT); + + GtkButton_CDVDtest = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_CDVDtest); + gtk_container_add (GTK_CONTAINER (hbuttonbox13), GtkButton_CDVDtest); + GTK_WIDGET_SET_FLAGS (GtkButton_CDVDtest, GTK_CAN_DEFAULT); + + GtkButton_CDVDabout = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_CDVDabout); + gtk_container_add (GTK_CONTAINER (hbuttonbox13), GtkButton_CDVDabout); + GTK_WIDGET_SET_FLAGS (GtkButton_CDVDabout, GTK_CAN_DEFAULT); + + label29 = gtk_label_new (_("Usb")); + gtk_widget_show (label29); + gtk_table_attach (GTK_TABLE (table2), label29, 0, 1, 9, 10, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label29), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label29), 0, 0.5); + + GtkCombo_Usb = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Usb)->popwin), + "GladeParentKey", GtkCombo_Usb); + gtk_widget_show (GtkCombo_Usb); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Usb, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Usb_items = g_list_append (GtkCombo_Usb_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Usb), GtkCombo_Usb_items); + g_list_free (GtkCombo_Usb_items); + + entry4 = GTK_COMBO (GtkCombo_Usb)->entry; + gtk_widget_show (entry4); + gtk_entry_set_invisible_char (GTK_ENTRY (entry4), 8226); + + hbuttonbox23 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox23); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox23, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + GtkButton_USBconfigure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_USBconfigure); + gtk_container_add (GTK_CONTAINER (hbuttonbox23), GtkButton_USBconfigure); + GTK_WIDGET_SET_FLAGS (GtkButton_USBconfigure, GTK_CAN_DEFAULT); + + GtkButton_USBtest = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_USBtest); + gtk_container_add (GTK_CONTAINER (hbuttonbox23), GtkButton_USBtest); + GTK_WIDGET_SET_FLAGS (GtkButton_USBtest, GTK_CAN_DEFAULT); + + GtkButton_USBabout = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_USBabout); + gtk_container_add (GTK_CONTAINER (hbuttonbox23), GtkButton_USBabout); + GTK_WIDGET_SET_FLAGS (GtkButton_USBabout, GTK_CAN_DEFAULT); + + GtkCombo_Bios = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Bios)->popwin), + "GladeParentKey", GtkCombo_Bios); + gtk_widget_show (GtkCombo_Bios); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_Bios, 1, 2, 13, 14, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_Bios_items = g_list_append (GtkCombo_Bios_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Bios), GtkCombo_Bios_items); + g_list_free (GtkCombo_Bios_items); + + combo_entry7 = GTK_COMBO (GtkCombo_Bios)->entry; + gtk_widget_show (combo_entry7); + gtk_entry_set_invisible_char (GTK_ENTRY (combo_entry7), 8226); + + GtkCombo_FW = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_FW)->popwin), + "GladeParentKey", GtkCombo_FW); + gtk_widget_show (GtkCombo_FW); + gtk_table_attach (GTK_TABLE (table2), GtkCombo_FW, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + GtkCombo_FW_items = g_list_append (GtkCombo_FW_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_FW), GtkCombo_FW_items); + g_list_free (GtkCombo_FW_items); + + entry5 = GTK_COMBO (GtkCombo_FW)->entry; + gtk_widget_show (entry5); + gtk_entry_set_invisible_char (GTK_ENTRY (entry5), 8226); + + hbuttonbox24 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox24); + gtk_table_attach (GTK_TABLE (table2), hbuttonbox24, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + GtkButton_FWconfigure = gtk_button_new_with_mnemonic (_("Configure")); + gtk_widget_show (GtkButton_FWconfigure); + gtk_container_add (GTK_CONTAINER (hbuttonbox24), GtkButton_FWconfigure); + GTK_WIDGET_SET_FLAGS (GtkButton_FWconfigure, GTK_CAN_DEFAULT); + + GtkButton_FWtest = gtk_button_new_with_mnemonic (_("Test")); + gtk_widget_show (GtkButton_FWtest); + gtk_container_add (GTK_CONTAINER (hbuttonbox24), GtkButton_FWtest); + GTK_WIDGET_SET_FLAGS (GtkButton_FWtest, GTK_CAN_DEFAULT); + + GtkButton_FireWireabout = gtk_button_new_with_mnemonic (_("About")); + gtk_widget_show (GtkButton_FireWireabout); + gtk_container_add (GTK_CONTAINER (hbuttonbox24), GtkButton_FireWireabout); + GTK_WIDGET_SET_FLAGS (GtkButton_FireWireabout, GTK_CAN_DEFAULT); + + label30 = gtk_label_new (_("FireWire")); + gtk_widget_show (label30); + gtk_table_attach (GTK_TABLE (table2), label30, 1, 2, 9, 10, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label30), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label30), 0, 0.5); + + GtkLabel_Bios = gtk_label_new (_("Bios")); + gtk_widget_show (GtkLabel_Bios); + gtk_table_attach (GTK_TABLE (table2), GtkLabel_Bios, 1, 2, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Bios), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_Bios), 0, 0.5); + + hbox5 = gtk_hbox_new (FALSE, 14); + gtk_widget_show (hbox5); + gtk_box_pack_start (GTK_BOX (vbox12), hbox5, TRUE, TRUE, 0); + + hbuttonbox11 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox11); + gtk_box_pack_start (GTK_BOX (hbox5), hbuttonbox11, FALSE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox11), GTK_BUTTONBOX_START); + + GtkButton_SelectPluginsDir = gtk_button_new_with_mnemonic (_("Select Plugins Dir")); + gtk_widget_show (GtkButton_SelectPluginsDir); + gtk_container_add (GTK_CONTAINER (hbuttonbox11), GtkButton_SelectPluginsDir); + GTK_WIDGET_SET_FLAGS (GtkButton_SelectPluginsDir, GTK_CAN_DEFAULT); + + GtkButton_SelectBiosDir = gtk_button_new_with_mnemonic (_("Select Bios Dir")); + gtk_widget_show (GtkButton_SelectBiosDir); + gtk_container_add (GTK_CONTAINER (hbuttonbox11), GtkButton_SelectBiosDir); + GTK_WIDGET_SET_FLAGS (GtkButton_SelectBiosDir, GTK_CAN_DEFAULT); + + hbuttonbox10 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox10); + gtk_box_pack_start (GTK_BOX (hbox5), hbuttonbox10, TRUE, TRUE, 0); + + GtkButton_Ok = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (GtkButton_Ok); + gtk_container_add (GTK_CONTAINER (hbuttonbox10), GtkButton_Ok); + GTK_WIDGET_SET_FLAGS (GtkButton_Ok, GTK_CAN_DEFAULT); + + GtkButton_Cancel = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (GtkButton_Cancel); + gtk_container_add (GTK_CONTAINER (hbuttonbox10), GtkButton_Cancel); + GTK_WIDGET_SET_FLAGS (GtkButton_Cancel, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) GtkButton_PAD2configure, "clicked", + G_CALLBACK (OnConfConf_Pad2Conf), + NULL); + g_signal_connect ((gpointer) GtkButton_PAD2test, "clicked", + G_CALLBACK (OnConfConf_Pad2Test), + NULL); + g_signal_connect ((gpointer) GtkButton_PAD2about, "clicked", + G_CALLBACK (OnConfConf_Pad2About), + NULL); + g_signal_connect ((gpointer) GtkButton_PAD1configure, "clicked", + G_CALLBACK (OnConfConf_Pad1Conf), + NULL); + g_signal_connect ((gpointer) GtkButton_PAD1test, "clicked", + G_CALLBACK (OnConfConf_Pad1Test), + NULL); + g_signal_connect ((gpointer) GtkButton_PAD1about, "clicked", + G_CALLBACK (OnConfConf_Pad1About), + NULL); + g_signal_connect ((gpointer) GtkButton_GSconfigure, "clicked", + G_CALLBACK (OnConfConf_GsConf), + NULL); + g_signal_connect ((gpointer) GtkButton_GStest, "clicked", + G_CALLBACK (OnConfConf_GsTest), + NULL); + g_signal_connect ((gpointer) GtkButton_GSabout, "clicked", + G_CALLBACK (OnConfConf_GsAbout), + NULL); + g_signal_connect ((gpointer) GtkButton_SPU2configure, "clicked", + G_CALLBACK (OnConfConf_Spu2Conf), + NULL); + g_signal_connect ((gpointer) GtkButton_SPU2test, "clicked", + G_CALLBACK (OnConfConf_Spu2Test), + NULL); + g_signal_connect ((gpointer) GtkButton_SPU2about, "clicked", + G_CALLBACK (OnConfConf_Spu2About), + NULL); + g_signal_connect ((gpointer) GtkButton_DEV9configure, "clicked", + G_CALLBACK (OnConfConf_Dev9Conf), + NULL); + g_signal_connect ((gpointer) GtkButton_DEV9test, "clicked", + G_CALLBACK (OnConfConf_Dev9Test), + NULL); + g_signal_connect ((gpointer) GtkButton_DEV9about, "clicked", + G_CALLBACK (OnConfConf_Dev9About), + NULL); + g_signal_connect ((gpointer) GtkButton_CDVDconfigure, "clicked", + G_CALLBACK (OnConfConf_CdvdConf), + NULL); + g_signal_connect ((gpointer) GtkButton_CDVDtest, "clicked", + G_CALLBACK (OnConfConf_CdvdTest), + NULL); + g_signal_connect ((gpointer) GtkButton_CDVDabout, "clicked", + G_CALLBACK (OnConfConf_CdvdAbout), + NULL); + g_signal_connect ((gpointer) GtkButton_USBconfigure, "clicked", + G_CALLBACK (OnConfConf_UsbConf), + NULL); + g_signal_connect ((gpointer) GtkButton_USBtest, "clicked", + G_CALLBACK (OnConfConf_UsbTest), + NULL); + g_signal_connect ((gpointer) GtkButton_USBabout, "clicked", + G_CALLBACK (OnConfConf_UsbAbout), + NULL); + g_signal_connect ((gpointer) GtkButton_FWconfigure, "clicked", + G_CALLBACK (OnConfConf_FWConf), + NULL); + g_signal_connect ((gpointer) GtkButton_FWtest, "clicked", + G_CALLBACK (OnConfConf_FWTest), + NULL); + g_signal_connect ((gpointer) GtkButton_FireWireabout, "clicked", + G_CALLBACK (OnConfConf_FWAbout), + NULL); + g_signal_connect ((gpointer) GtkButton_SelectPluginsDir, "clicked", + G_CALLBACK (OnConfConf_PluginsPath), + NULL); + g_signal_connect ((gpointer) GtkButton_SelectBiosDir, "clicked", + G_CALLBACK (OnConfConf_BiosPath), + NULL); + g_signal_connect ((gpointer) GtkButton_Ok, "clicked", + G_CALLBACK (OnConfConf_Ok), + NULL); + g_signal_connect ((gpointer) GtkButton_Cancel, "clicked", + G_CALLBACK (OnConfConf_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (ConfDlg, ConfDlg, "ConfDlg"); + GLADE_HOOKUP_OBJECT (ConfDlg, vbox12, "vbox12"); + GLADE_HOOKUP_OBJECT (ConfDlg, table2, "table2"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Pad1, "GtkCombo_Pad1"); + GLADE_HOOKUP_OBJECT (ConfDlg, combo_entry4, "combo_entry4"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Pad2, "GtkCombo_Pad2"); + GLADE_HOOKUP_OBJECT (ConfDlg, combo_entry5, "combo_entry5"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox6, "hbuttonbox6"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD2configure, "GtkButton_PAD2configure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD2test, "GtkButton_PAD2test"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD2about, "GtkButton_PAD2about"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox7, "hbuttonbox7"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD1configure, "GtkButton_PAD1configure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD1test, "GtkButton_PAD1test"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_PAD1about, "GtkButton_PAD1about"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox8, "hbuttonbox8"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_GSconfigure, "GtkButton_GSconfigure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_GStest, "GtkButton_GStest"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_GSabout, "GtkButton_GSabout"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_Graphics, "GtkLabel_Graphics"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_FirstController, "GtkLabel_FirstController"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_SecondController, "GtkLabel_SecondController"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Gs, "GtkCombo_Gs"); + GLADE_HOOKUP_OBJECT (ConfDlg, combo_entry2, "combo_entry2"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_Sound, "GtkLabel_Sound"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Spu2, "GtkCombo_Spu2"); + GLADE_HOOKUP_OBJECT (ConfDlg, entry1, "entry1"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox12, "hbuttonbox12"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_SPU2configure, "GtkButton_SPU2configure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_SPU2test, "GtkButton_SPU2test"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_SPU2about, "GtkButton_SPU2about"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Dev9, "GtkCombo_Dev9"); + GLADE_HOOKUP_OBJECT (ConfDlg, entry3, "entry3"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox21, "hbuttonbox21"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_DEV9configure, "GtkButton_DEV9configure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_DEV9test, "GtkButton_DEV9test"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_DEV9about, "GtkButton_DEV9about"); + GLADE_HOOKUP_OBJECT (ConfDlg, label23, "label23"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_Cdvdrom, "GtkLabel_Cdvdrom"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Cdvd, "GtkCombo_Cdvd"); + GLADE_HOOKUP_OBJECT (ConfDlg, entry2, "entry2"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox13, "hbuttonbox13"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_CDVDconfigure, "GtkButton_CDVDconfigure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_CDVDtest, "GtkButton_CDVDtest"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_CDVDabout, "GtkButton_CDVDabout"); + GLADE_HOOKUP_OBJECT (ConfDlg, label29, "label29"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Usb, "GtkCombo_Usb"); + GLADE_HOOKUP_OBJECT (ConfDlg, entry4, "entry4"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox23, "hbuttonbox23"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_USBconfigure, "GtkButton_USBconfigure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_USBtest, "GtkButton_USBtest"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_USBabout, "GtkButton_USBabout"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_Bios, "GtkCombo_Bios"); + GLADE_HOOKUP_OBJECT (ConfDlg, combo_entry7, "combo_entry7"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkCombo_FW, "GtkCombo_FW"); + GLADE_HOOKUP_OBJECT (ConfDlg, entry5, "entry5"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox24, "hbuttonbox24"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_FWconfigure, "GtkButton_FWconfigure"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_FWtest, "GtkButton_FWtest"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_FireWireabout, "GtkButton_FireWireabout"); + GLADE_HOOKUP_OBJECT (ConfDlg, label30, "label30"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkLabel_Bios, "GtkLabel_Bios"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbox5, "hbox5"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox11, "hbuttonbox11"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_SelectPluginsDir, "GtkButton_SelectPluginsDir"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_SelectBiosDir, "GtkButton_SelectBiosDir"); + GLADE_HOOKUP_OBJECT (ConfDlg, hbuttonbox10, "hbuttonbox10"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_Ok, "GtkButton_Ok"); + GLADE_HOOKUP_OBJECT (ConfDlg, GtkButton_Cancel, "GtkButton_Cancel"); + + return ConfDlg; +} + +GtkWidget* +create_CpuDlg (void) +{ + GtkWidget *CpuDlg; + GtkWidget *vbox8; + GtkWidget *hbox20; + GtkWidget *alignment1; + GtkWidget *vbox27; + GtkWidget *alignment3; + GtkWidget *frame8; + GtkWidget *alignment2; + GtkWidget *vbox28; + GtkWidget *GtkLabel_CpuVendor; + GtkWidget *GtkLabel_Family; + GtkWidget *GtkLabel_CpuSpeed; + GtkWidget *GtkLabel_Features; + GtkWidget *label35; + GtkWidget *GtkCheckButton_EERec; + GtkWidget *frame6; + GtkWidget *vbox26; + GtkWidget *GtkCheckButton_VU0rec; + GtkWidget *GtkCheckButton_VU1rec; + GtkWidget *label32; + GtkWidget *GtkCheckButton_MTGS; + GtkWidget *GtkCheckButton_CpuDC; + GtkWidget *frame9; + GtkWidget *alignment4; + GtkWidget *vbox29; + GtkWidget *GtkRadioButton_LimitNormal; + GSList *GtkRadioButton_LimitNormal_group = NULL; + GtkWidget *GtkRadioButton_LimitLimit; + GtkWidget *GtkRadioButton_LimitFS; + GtkWidget *GtkRadioButton_VUSkip; + GtkWidget *label41; + GtkWidget *hbuttonbox3; + GtkWidget *GtkButton_Ok; + GtkWidget *GtkButton_Cancel; + + CpuDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (CpuDlg), 5); + gtk_window_set_title (GTK_WINDOW (CpuDlg), _("Cpu")); + + vbox8 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox8); + gtk_container_add (GTK_CONTAINER (CpuDlg), vbox8); + + hbox20 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox20); + gtk_box_pack_start (GTK_BOX (vbox8), hbox20, TRUE, TRUE, 0); + + alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment1); + gtk_box_pack_start (GTK_BOX (hbox20), alignment1, TRUE, TRUE, 0); + + vbox27 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox27); + gtk_container_add (GTK_CONTAINER (alignment1), vbox27); + + alignment3 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment3); + gtk_box_pack_start (GTK_BOX (vbox27), alignment3, TRUE, TRUE, 0); + + frame8 = gtk_frame_new (NULL); + gtk_widget_show (frame8); + gtk_container_add (GTK_CONTAINER (alignment3), frame8); + + alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (frame8), alignment2); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment2), 0, 0, 12, 0); + + vbox28 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox28); + gtk_container_add (GTK_CONTAINER (alignment2), vbox28); + + GtkLabel_CpuVendor = gtk_label_new (_("CPU vendor")); + gtk_widget_show (GtkLabel_CpuVendor); + gtk_box_pack_start (GTK_BOX (vbox28), GtkLabel_CpuVendor, FALSE, FALSE, 0); + + GtkLabel_Family = gtk_label_new (_("Family")); + gtk_widget_show (GtkLabel_Family); + gtk_box_pack_start (GTK_BOX (vbox28), GtkLabel_Family, FALSE, FALSE, 0); + + GtkLabel_CpuSpeed = gtk_label_new (_("Cpu Speed")); + gtk_widget_show (GtkLabel_CpuSpeed); + gtk_box_pack_start (GTK_BOX (vbox28), GtkLabel_CpuSpeed, FALSE, FALSE, 0); + + GtkLabel_Features = gtk_label_new (_("Features")); + gtk_widget_show (GtkLabel_Features); + gtk_box_pack_start (GTK_BOX (vbox28), GtkLabel_Features, FALSE, FALSE, 0); + + label35 = gtk_label_new (""); + gtk_widget_show (label35); + gtk_frame_set_label_widget (GTK_FRAME (frame8), label35); + gtk_label_set_use_markup (GTK_LABEL (label35), TRUE); + + GtkCheckButton_EERec = gtk_check_button_new_with_mnemonic (_("EERec - EE/IOP recompiler")); + gtk_widget_show (GtkCheckButton_EERec); + gtk_box_pack_start (GTK_BOX (vbox8), GtkCheckButton_EERec, FALSE, FALSE, 0); + + frame6 = gtk_frame_new (NULL); + gtk_widget_show (frame6); + gtk_box_pack_start (GTK_BOX (vbox8), frame6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame6), 5); + + vbox26 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox26); + gtk_container_add (GTK_CONTAINER (frame6), vbox26); + gtk_container_set_border_width (GTK_CONTAINER (vbox26), 5); + + GtkCheckButton_VU0rec = gtk_check_button_new_with_mnemonic (_("VU0rec - enable recompiler for VU0 unit")); + gtk_widget_show (GtkCheckButton_VU0rec); + gtk_box_pack_start (GTK_BOX (vbox26), GtkCheckButton_VU0rec, FALSE, FALSE, 0); + + GtkCheckButton_VU1rec = gtk_check_button_new_with_mnemonic (_("VU1rec - enable recompiler for VU1 unit")); + gtk_widget_show (GtkCheckButton_VU1rec); + gtk_box_pack_start (GTK_BOX (vbox26), GtkCheckButton_VU1rec, FALSE, FALSE, 0); + + label32 = gtk_label_new (_("VU Recompilers - All options are set by default")); + gtk_widget_show (label32); + gtk_frame_set_label_widget (GTK_FRAME (frame6), label32); + + GtkCheckButton_MTGS = gtk_check_button_new_with_mnemonic (_("Multi threaded GS mode (MTGS)\n (faster on dual core/HT CPUs, requires pcsx2 restart)")); + gtk_widget_show (GtkCheckButton_MTGS); + gtk_box_pack_start (GTK_BOX (vbox8), GtkCheckButton_MTGS, FALSE, FALSE, 0); + + GtkCheckButton_CpuDC = gtk_check_button_new_with_mnemonic (_("Dual Core Mode (DC) - Much faster, but only valid with MTGS")); + gtk_widget_show (GtkCheckButton_CpuDC); + gtk_box_pack_start (GTK_BOX (vbox8), GtkCheckButton_CpuDC, FALSE, FALSE, 0); + + frame9 = gtk_frame_new (NULL); + gtk_widget_show (frame9); + gtk_box_pack_start (GTK_BOX (vbox8), frame9, TRUE, TRUE, 0); + + alignment4 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment4); + gtk_container_add (GTK_CONTAINER (frame9), alignment4); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment4), 0, 0, 12, 0); + + vbox29 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox29); + gtk_container_add (GTK_CONTAINER (alignment4), vbox29); + + GtkRadioButton_LimitNormal = gtk_radio_button_new_with_mnemonic (NULL, _("Normal - All frames are rendered as fast as possible")); + gtk_widget_show (GtkRadioButton_LimitNormal); + gtk_box_pack_start (GTK_BOX (vbox29), GtkRadioButton_LimitNormal, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitNormal), GtkRadioButton_LimitNormal_group); + GtkRadioButton_LimitNormal_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitNormal)); + + GtkRadioButton_LimitLimit = gtk_radio_button_new_with_mnemonic (NULL, _("Limit - Force frames to normal speeds if too fast")); + gtk_widget_show (GtkRadioButton_LimitLimit); + gtk_box_pack_start (GTK_BOX (vbox29), GtkRadioButton_LimitLimit, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitLimit), GtkRadioButton_LimitNormal_group); + GtkRadioButton_LimitNormal_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitLimit)); + + GtkRadioButton_LimitFS = gtk_radio_button_new_with_mnemonic (NULL, _("Frame Skip - In order to achieve normal speeds, \n some frames are skipped (faster).\n Fps displayed counts skipped frames too")); + gtk_widget_show (GtkRadioButton_LimitFS); + gtk_box_pack_start (GTK_BOX (vbox29), GtkRadioButton_LimitFS, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitFS), GtkRadioButton_LimitNormal_group); + GtkRadioButton_LimitNormal_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_LimitFS)); + + GtkRadioButton_VUSkip = gtk_radio_button_new_with_mnemonic (NULL, _("VU Skip - Same as Frame Skip, but tried to skip more. \n Artifacts might be present, but will be faster")); + gtk_widget_show (GtkRadioButton_VUSkip); + gtk_box_pack_start (GTK_BOX (vbox29), GtkRadioButton_VUSkip, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_VUSkip), GtkRadioButton_LimitNormal_group); + GtkRadioButton_LimitNormal_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_VUSkip)); + + label41 = gtk_label_new (_("Frame Limiting")); + gtk_widget_show (label41); + gtk_frame_set_label_widget (GTK_FRAME (frame9), label41); + gtk_label_set_use_markup (GTK_LABEL (label41), TRUE); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox8), hbuttonbox3, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox3), 30); + + GtkButton_Ok = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (GtkButton_Ok); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_Ok); + GTK_WIDGET_SET_FLAGS (GtkButton_Ok, GTK_CAN_DEFAULT); + + GtkButton_Cancel = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (GtkButton_Cancel); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_Cancel); + GTK_WIDGET_SET_FLAGS (GtkButton_Cancel, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) GtkButton_Ok, "clicked", + G_CALLBACK (OnCpu_Ok), + NULL); + g_signal_connect ((gpointer) GtkButton_Cancel, "clicked", + G_CALLBACK (OnCpu_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (CpuDlg, CpuDlg, "CpuDlg"); + GLADE_HOOKUP_OBJECT (CpuDlg, vbox8, "vbox8"); + GLADE_HOOKUP_OBJECT (CpuDlg, hbox20, "hbox20"); + GLADE_HOOKUP_OBJECT (CpuDlg, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (CpuDlg, vbox27, "vbox27"); + GLADE_HOOKUP_OBJECT (CpuDlg, alignment3, "alignment3"); + GLADE_HOOKUP_OBJECT (CpuDlg, frame8, "frame8"); + GLADE_HOOKUP_OBJECT (CpuDlg, alignment2, "alignment2"); + GLADE_HOOKUP_OBJECT (CpuDlg, vbox28, "vbox28"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkLabel_CpuVendor, "GtkLabel_CpuVendor"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkLabel_Family, "GtkLabel_Family"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkLabel_CpuSpeed, "GtkLabel_CpuSpeed"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkLabel_Features, "GtkLabel_Features"); + GLADE_HOOKUP_OBJECT (CpuDlg, label35, "label35"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkCheckButton_EERec, "GtkCheckButton_EERec"); + GLADE_HOOKUP_OBJECT (CpuDlg, frame6, "frame6"); + GLADE_HOOKUP_OBJECT (CpuDlg, vbox26, "vbox26"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkCheckButton_VU0rec, "GtkCheckButton_VU0rec"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkCheckButton_VU1rec, "GtkCheckButton_VU1rec"); + GLADE_HOOKUP_OBJECT (CpuDlg, label32, "label32"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkCheckButton_MTGS, "GtkCheckButton_MTGS"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkCheckButton_CpuDC, "GtkCheckButton_CpuDC"); + GLADE_HOOKUP_OBJECT (CpuDlg, frame9, "frame9"); + GLADE_HOOKUP_OBJECT (CpuDlg, alignment4, "alignment4"); + GLADE_HOOKUP_OBJECT (CpuDlg, vbox29, "vbox29"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkRadioButton_LimitNormal, "GtkRadioButton_LimitNormal"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkRadioButton_LimitLimit, "GtkRadioButton_LimitLimit"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkRadioButton_LimitFS, "GtkRadioButton_LimitFS"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkRadioButton_VUSkip, "GtkRadioButton_VUSkip"); + GLADE_HOOKUP_OBJECT (CpuDlg, label41, "label41"); + GLADE_HOOKUP_OBJECT (CpuDlg, hbuttonbox3, "hbuttonbox3"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkButton_Ok, "GtkButton_Ok"); + GLADE_HOOKUP_OBJECT (CpuDlg, GtkButton_Cancel, "GtkButton_Cancel"); + + return CpuDlg; +} + +GtkWidget* +create_DebugWnd (void) +{ + GtkWidget *DebugWnd; + GtkWidget *vbox16; + GtkWidget *hbox16; + GtkWidget *GtkRadioButton_EE; + GSList *GtkRadioButton_EE_group = NULL; + GtkWidget *GtkRadioButton_IOP; + GtkWidget *hbox6; + GtkWidget *hbox7; + GtkWidget *scrolledwindow1; + GtkWidget *viewport1; + GtkWidget *GtkList_DisView; + GtkWidget *GtkVScrollbar_VList; + GtkWidget *vbox22; + GtkWidget *vbuttonbox2; + GtkWidget *button52; + GtkWidget *button53; + GtkWidget *button65; + GtkWidget *button64; + GtkWidget *vbuttonbox3; + GtkWidget *button58; + GtkWidget *button59; + GtkWidget *button60; + GtkWidget *button61; + GtkWidget *vbuttonbox1; + GtkWidget *button39; + GtkWidget *button40; + GtkWidget *button41; + GtkWidget *vbuttonbox4; + GtkWidget *button68; + GtkWidget *button69; + GtkWidget *button70; + + DebugWnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (DebugWnd), 5); + gtk_window_set_title (GTK_WINDOW (DebugWnd), _("PCSX2 Debugger")); + + vbox16 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox16); + gtk_container_add (GTK_CONTAINER (DebugWnd), vbox16); + gtk_container_set_border_width (GTK_CONTAINER (vbox16), 5); + + hbox16 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox16); + gtk_box_pack_start (GTK_BOX (vbox16), hbox16, TRUE, TRUE, 0); + + GtkRadioButton_EE = gtk_radio_button_new_with_mnemonic (NULL, _("EE Debug Mode")); + gtk_widget_show (GtkRadioButton_EE); + gtk_box_pack_start (GTK_BOX (hbox16), GtkRadioButton_EE, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_EE), GtkRadioButton_EE_group); + GtkRadioButton_EE_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_EE)); + + GtkRadioButton_IOP = gtk_radio_button_new_with_mnemonic (NULL, _("IOP Debug Mode")); + gtk_widget_show (GtkRadioButton_IOP); + gtk_box_pack_start (GTK_BOX (hbox16), GtkRadioButton_IOP, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GtkRadioButton_IOP), GtkRadioButton_EE_group); + GtkRadioButton_EE_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (GtkRadioButton_IOP)); + + hbox6 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox6); + gtk_box_pack_start (GTK_BOX (vbox16), hbox6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox6), 5); + + hbox7 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox7); + gtk_box_pack_start (GTK_BOX (hbox6), hbox7, TRUE, TRUE, 0); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (hbox7), scrolledwindow1, TRUE, TRUE, 0); + GTK_WIDGET_UNSET_FLAGS (scrolledwindow1, GTK_CAN_FOCUS); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER); + + viewport1 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); + + GtkList_DisView = gtk_tree_view_new (); + gtk_widget_show (GtkList_DisView); + gtk_container_add (GTK_CONTAINER (viewport1), GtkList_DisView); + GTK_WIDGET_UNSET_FLAGS (GtkList_DisView, GTK_CAN_FOCUS); + + GtkVScrollbar_VList = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 412, 1, 20, 2))); + gtk_widget_show (GtkVScrollbar_VList); + gtk_box_pack_start (GTK_BOX (hbox7), GtkVScrollbar_VList, TRUE, TRUE, 0); + + vbox22 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox22); + gtk_box_pack_start (GTK_BOX (hbox6), vbox22, TRUE, TRUE, 0); + + vbuttonbox2 = gtk_vbutton_box_new (); + gtk_widget_show (vbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox22), vbuttonbox2, TRUE, TRUE, 0); + + button52 = gtk_button_new_with_mnemonic (_("Step")); + gtk_widget_show (button52); + gtk_container_add (GTK_CONTAINER (vbuttonbox2), button52); + GTK_WIDGET_SET_FLAGS (button52, GTK_CAN_DEFAULT); + + button53 = gtk_button_new_with_mnemonic (_("Skip")); + gtk_widget_show (button53); + gtk_container_add (GTK_CONTAINER (vbuttonbox2), button53); + GTK_WIDGET_SET_FLAGS (button53, GTK_CAN_DEFAULT); + + button65 = gtk_button_new_with_mnemonic (_("Go")); + gtk_widget_show (button65); + gtk_container_add (GTK_CONTAINER (vbuttonbox2), button65); + GTK_WIDGET_SET_FLAGS (button65, GTK_CAN_DEFAULT); + + button64 = gtk_button_new_with_mnemonic (_("Log On/Off")); + gtk_widget_show (button64); + gtk_container_add (GTK_CONTAINER (vbuttonbox2), button64); + GTK_WIDGET_SET_FLAGS (button64, GTK_CAN_DEFAULT); + + vbuttonbox3 = gtk_vbutton_box_new (); + gtk_widget_show (vbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox22), vbuttonbox3, TRUE, TRUE, 0); + + button58 = gtk_button_new_with_mnemonic (_("Set PC")); + gtk_widget_show (button58); + gtk_container_add (GTK_CONTAINER (vbuttonbox3), button58); + GTK_WIDGET_SET_FLAGS (button58, GTK_CAN_DEFAULT); + + button59 = gtk_button_new_with_mnemonic (_("Set BP Addr")); + gtk_widget_show (button59); + gtk_container_add (GTK_CONTAINER (vbuttonbox3), button59); + GTK_WIDGET_SET_FLAGS (button59, GTK_CAN_DEFAULT); + + button60 = gtk_button_new_with_mnemonic (_("Set BP Count")); + gtk_widget_show (button60); + gtk_container_add (GTK_CONTAINER (vbuttonbox3), button60); + GTK_WIDGET_SET_FLAGS (button60, GTK_CAN_DEFAULT); + + button61 = gtk_button_new_with_mnemonic (_("Clear BPs")); + gtk_widget_show (button61); + gtk_container_add (GTK_CONTAINER (vbuttonbox3), button61); + GTK_WIDGET_SET_FLAGS (button61, GTK_CAN_DEFAULT); + + vbuttonbox1 = gtk_vbutton_box_new (); + gtk_widget_show (vbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox22), vbuttonbox1, TRUE, TRUE, 0); + + button39 = gtk_button_new_with_mnemonic (_("Dump code")); + gtk_widget_show (button39); + gtk_container_add (GTK_CONTAINER (vbuttonbox1), button39); + GTK_WIDGET_SET_FLAGS (button39, GTK_CAN_DEFAULT); + + button40 = gtk_button_new_with_mnemonic (_("Raw Dump")); + gtk_widget_show (button40); + gtk_container_add (GTK_CONTAINER (vbuttonbox1), button40); + GTK_WIDGET_SET_FLAGS (button40, GTK_CAN_DEFAULT); + + button41 = gtk_button_new_with_mnemonic (_("Close")); + gtk_widget_show (button41); + gtk_container_add (GTK_CONTAINER (vbuttonbox1), button41); + GTK_WIDGET_SET_FLAGS (button41, GTK_CAN_DEFAULT); + + vbuttonbox4 = gtk_vbutton_box_new (); + gtk_widget_show (vbuttonbox4); + gtk_box_pack_start (GTK_BOX (hbox6), vbuttonbox4, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (vbuttonbox4), 10); + + button68 = gtk_button_new_with_mnemonic (_("memWrite32")); + gtk_widget_show (button68); + gtk_container_add (GTK_CONTAINER (vbuttonbox4), button68); + GTK_WIDGET_SET_FLAGS (button68, GTK_CAN_DEFAULT); + + button69 = gtk_button_new_with_mnemonic (_("button69")); + gtk_widget_show (button69); + gtk_container_add (GTK_CONTAINER (vbuttonbox4), button69); + GTK_WIDGET_SET_FLAGS (button69, GTK_CAN_DEFAULT); + + button70 = gtk_button_new_with_mnemonic (_("button70")); + gtk_widget_show (button70); + gtk_container_add (GTK_CONTAINER (vbuttonbox4), button70); + GTK_WIDGET_SET_FLAGS (button70, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) GtkRadioButton_EE, "toggled", + G_CALLBACK (OnDebug_EEMode), + NULL); + g_signal_connect ((gpointer) GtkRadioButton_IOP, "toggled", + G_CALLBACK (OnDebug_IOPMode), + NULL); + g_signal_connect ((gpointer) button52, "clicked", + G_CALLBACK (OnDebug_Step), + NULL); + g_signal_connect ((gpointer) button53, "clicked", + G_CALLBACK (OnDebug_Skip), + NULL); + g_signal_connect ((gpointer) button65, "clicked", + G_CALLBACK (OnDebug_Go), + NULL); + g_signal_connect ((gpointer) button64, "clicked", + G_CALLBACK (OnDebug_Log), + NULL); + g_signal_connect ((gpointer) button58, "clicked", + G_CALLBACK (OnDebug_SetPC), + NULL); + g_signal_connect ((gpointer) button59, "clicked", + G_CALLBACK (OnDebug_SetBPA), + NULL); + g_signal_connect ((gpointer) button60, "clicked", + G_CALLBACK (OnDebug_SetBPC), + NULL); + g_signal_connect ((gpointer) button61, "clicked", + G_CALLBACK (OnDebug_ClearBPs), + NULL); + g_signal_connect ((gpointer) button39, "clicked", + G_CALLBACK (OnDebug_DumpCode), + NULL); + g_signal_connect ((gpointer) button40, "clicked", + G_CALLBACK (OnDebug_RawDump), + NULL); + g_signal_connect ((gpointer) button41, "clicked", + G_CALLBACK (OnDebug_Close), + NULL); + g_signal_connect ((gpointer) button68, "clicked", + G_CALLBACK (OnDebug_memWrite32), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (DebugWnd, DebugWnd, "DebugWnd"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbox16, "vbox16"); + GLADE_HOOKUP_OBJECT (DebugWnd, hbox16, "hbox16"); + GLADE_HOOKUP_OBJECT (DebugWnd, GtkRadioButton_EE, "GtkRadioButton_EE"); + GLADE_HOOKUP_OBJECT (DebugWnd, GtkRadioButton_IOP, "GtkRadioButton_IOP"); + GLADE_HOOKUP_OBJECT (DebugWnd, hbox6, "hbox6"); + GLADE_HOOKUP_OBJECT (DebugWnd, hbox7, "hbox7"); + GLADE_HOOKUP_OBJECT (DebugWnd, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (DebugWnd, viewport1, "viewport1"); + GLADE_HOOKUP_OBJECT (DebugWnd, GtkList_DisView, "GtkList_DisView"); + GLADE_HOOKUP_OBJECT (DebugWnd, GtkVScrollbar_VList, "GtkVScrollbar_VList"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbox22, "vbox22"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbuttonbox2, "vbuttonbox2"); + GLADE_HOOKUP_OBJECT (DebugWnd, button52, "button52"); + GLADE_HOOKUP_OBJECT (DebugWnd, button53, "button53"); + GLADE_HOOKUP_OBJECT (DebugWnd, button65, "button65"); + GLADE_HOOKUP_OBJECT (DebugWnd, button64, "button64"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbuttonbox3, "vbuttonbox3"); + GLADE_HOOKUP_OBJECT (DebugWnd, button58, "button58"); + GLADE_HOOKUP_OBJECT (DebugWnd, button59, "button59"); + GLADE_HOOKUP_OBJECT (DebugWnd, button60, "button60"); + GLADE_HOOKUP_OBJECT (DebugWnd, button61, "button61"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbuttonbox1, "vbuttonbox1"); + GLADE_HOOKUP_OBJECT (DebugWnd, button39, "button39"); + GLADE_HOOKUP_OBJECT (DebugWnd, button40, "button40"); + GLADE_HOOKUP_OBJECT (DebugWnd, button41, "button41"); + GLADE_HOOKUP_OBJECT (DebugWnd, vbuttonbox4, "vbuttonbox4"); + GLADE_HOOKUP_OBJECT (DebugWnd, button68, "button68"); + GLADE_HOOKUP_OBJECT (DebugWnd, button69, "button69"); + GLADE_HOOKUP_OBJECT (DebugWnd, button70, "button70"); + + return DebugWnd; +} + +GtkWidget* +create_SetPCDlg (void) +{ + GtkWidget *SetPCDlg; + GtkWidget *vbox17; + GtkWidget *label9; + GtkWidget *hbox8; + GtkWidget *label10; + GtkWidget *GtkEntry_dPC; + GtkWidget *hbuttonbox14; + GtkWidget *button42; + GtkWidget *button43; + + SetPCDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SetPCDlg), 5); + gtk_window_set_title (GTK_WINDOW (SetPCDlg), _("SetPCDlg")); + + vbox17 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox17); + gtk_container_add (GTK_CONTAINER (SetPCDlg), vbox17); + gtk_container_set_border_width (GTK_CONTAINER (vbox17), 5); + + label9 = gtk_label_new (_("Set New PC Address (in Hex):")); + gtk_widget_show (label9); + gtk_box_pack_start (GTK_BOX (vbox17), label9, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label9), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label9), 0.1, 0.5); + + hbox8 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox8); + gtk_box_pack_start (GTK_BOX (vbox17), hbox8, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox8), 5); + + label10 = gtk_label_new (_("0x")); + gtk_widget_show (label10); + gtk_box_pack_start (GTK_BOX (hbox8), label10, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label10), GTK_JUSTIFY_CENTER); + + GtkEntry_dPC = gtk_entry_new (); + gtk_widget_show (GtkEntry_dPC); + gtk_box_pack_start (GTK_BOX (hbox8), GtkEntry_dPC, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_dPC), 8226); + + hbuttonbox14 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox14); + gtk_box_pack_start (GTK_BOX (vbox17), hbuttonbox14, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox14), 30); + + button42 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button42); + gtk_container_add (GTK_CONTAINER (hbuttonbox14), button42); + GTK_WIDGET_SET_FLAGS (button42, GTK_CAN_DEFAULT); + + button43 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button43); + gtk_container_add (GTK_CONTAINER (hbuttonbox14), button43); + GTK_WIDGET_SET_FLAGS (button43, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button42, "clicked", + G_CALLBACK (OnSetPC_Ok), + NULL); + g_signal_connect ((gpointer) button43, "clicked", + G_CALLBACK (OnSetPC_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (SetPCDlg, SetPCDlg, "SetPCDlg"); + GLADE_HOOKUP_OBJECT (SetPCDlg, vbox17, "vbox17"); + GLADE_HOOKUP_OBJECT (SetPCDlg, label9, "label9"); + GLADE_HOOKUP_OBJECT (SetPCDlg, hbox8, "hbox8"); + GLADE_HOOKUP_OBJECT (SetPCDlg, label10, "label10"); + GLADE_HOOKUP_OBJECT (SetPCDlg, GtkEntry_dPC, "GtkEntry_dPC"); + GLADE_HOOKUP_OBJECT (SetPCDlg, hbuttonbox14, "hbuttonbox14"); + GLADE_HOOKUP_OBJECT (SetPCDlg, button42, "button42"); + GLADE_HOOKUP_OBJECT (SetPCDlg, button43, "button43"); + + return SetPCDlg; +} + +GtkWidget* +create_SetBPADlg (void) +{ + GtkWidget *SetBPADlg; + GtkWidget *vbox18; + GtkWidget *label11; + GtkWidget *hbox9; + GtkWidget *label12; + GtkWidget *GtkEntry_BPA; + GtkWidget *hbuttonbox15; + GtkWidget *button44; + GtkWidget *button45; + + SetBPADlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SetBPADlg), 5); + gtk_window_set_title (GTK_WINDOW (SetBPADlg), _("SetBreakPoint Addr")); + + vbox18 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox18); + gtk_container_add (GTK_CONTAINER (SetBPADlg), vbox18); + gtk_container_set_border_width (GTK_CONTAINER (vbox18), 5); + + label11 = gtk_label_new (_("Set New BP Address (in Hex):")); + gtk_widget_show (label11); + gtk_box_pack_start (GTK_BOX (vbox18), label11, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label11), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label11), 0.1, 0.5); + + hbox9 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox9); + gtk_box_pack_start (GTK_BOX (vbox18), hbox9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox9), 5); + + label12 = gtk_label_new (_("0x")); + gtk_widget_show (label12); + gtk_box_pack_start (GTK_BOX (hbox9), label12, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label12), GTK_JUSTIFY_CENTER); + + GtkEntry_BPA = gtk_entry_new (); + gtk_widget_show (GtkEntry_BPA); + gtk_box_pack_start (GTK_BOX (hbox9), GtkEntry_BPA, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_BPA), 8226); + + hbuttonbox15 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox15); + gtk_box_pack_start (GTK_BOX (vbox18), hbuttonbox15, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox15), 30); + + button44 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button44); + gtk_container_add (GTK_CONTAINER (hbuttonbox15), button44); + GTK_WIDGET_SET_FLAGS (button44, GTK_CAN_DEFAULT); + + button45 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button45); + gtk_container_add (GTK_CONTAINER (hbuttonbox15), button45); + GTK_WIDGET_SET_FLAGS (button45, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button44, "clicked", + G_CALLBACK (OnSetBPA_Ok), + NULL); + g_signal_connect ((gpointer) button45, "clicked", + G_CALLBACK (OnSetBPA_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (SetBPADlg, SetBPADlg, "SetBPADlg"); + GLADE_HOOKUP_OBJECT (SetBPADlg, vbox18, "vbox18"); + GLADE_HOOKUP_OBJECT (SetBPADlg, label11, "label11"); + GLADE_HOOKUP_OBJECT (SetBPADlg, hbox9, "hbox9"); + GLADE_HOOKUP_OBJECT (SetBPADlg, label12, "label12"); + GLADE_HOOKUP_OBJECT (SetBPADlg, GtkEntry_BPA, "GtkEntry_BPA"); + GLADE_HOOKUP_OBJECT (SetBPADlg, hbuttonbox15, "hbuttonbox15"); + GLADE_HOOKUP_OBJECT (SetBPADlg, button44, "button44"); + GLADE_HOOKUP_OBJECT (SetBPADlg, button45, "button45"); + + return SetBPADlg; +} + +GtkWidget* +create_SetBPCDlg (void) +{ + GtkWidget *SetBPCDlg; + GtkWidget *vbox19; + GtkWidget *label13; + GtkWidget *hbox10; + GtkWidget *label14; + GtkWidget *GtkEntry_BPC; + GtkWidget *hbuttonbox16; + GtkWidget *button46; + GtkWidget *button47; + + SetBPCDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SetBPCDlg), 5); + gtk_window_set_title (GTK_WINDOW (SetBPCDlg), _("SetBreakPoint Addr")); + + vbox19 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox19); + gtk_container_add (GTK_CONTAINER (SetBPCDlg), vbox19); + gtk_container_set_border_width (GTK_CONTAINER (vbox19), 5); + + label13 = gtk_label_new (_("Set New BP Count (in Hex):")); + gtk_widget_show (label13); + gtk_box_pack_start (GTK_BOX (vbox19), label13, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label13), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label13), 0.1, 0.5); + + hbox10 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox10); + gtk_box_pack_start (GTK_BOX (vbox19), hbox10, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox10), 5); + + label14 = gtk_label_new (_("0x")); + gtk_widget_show (label14); + gtk_box_pack_start (GTK_BOX (hbox10), label14, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label14), GTK_JUSTIFY_CENTER); + + GtkEntry_BPC = gtk_entry_new (); + gtk_widget_show (GtkEntry_BPC); + gtk_box_pack_start (GTK_BOX (hbox10), GtkEntry_BPC, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_BPC), 8226); + + hbuttonbox16 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox16); + gtk_box_pack_start (GTK_BOX (vbox19), hbuttonbox16, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox16), 30); + + button46 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button46); + gtk_container_add (GTK_CONTAINER (hbuttonbox16), button46); + GTK_WIDGET_SET_FLAGS (button46, GTK_CAN_DEFAULT); + + button47 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button47); + gtk_container_add (GTK_CONTAINER (hbuttonbox16), button47); + GTK_WIDGET_SET_FLAGS (button47, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button46, "clicked", + G_CALLBACK (OnSetBPC_Ok), + NULL); + g_signal_connect ((gpointer) button47, "clicked", + G_CALLBACK (OnSetBPC_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (SetBPCDlg, SetBPCDlg, "SetBPCDlg"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, vbox19, "vbox19"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, label13, "label13"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, hbox10, "hbox10"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, label14, "label14"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, GtkEntry_BPC, "GtkEntry_BPC"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, hbuttonbox16, "hbuttonbox16"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, button46, "button46"); + GLADE_HOOKUP_OBJECT (SetBPCDlg, button47, "button47"); + + return SetBPCDlg; +} + +GtkWidget* +create_DumpCDlg (void) +{ + GtkWidget *DumpCDlg; + GtkWidget *vbox20; + GtkWidget *label15; + GtkWidget *hbox11; + GtkWidget *label16; + GtkWidget *GtkEntry_DumpCF; + GtkWidget *hbox12; + GtkWidget *label17; + GtkWidget *GtkEntry_DumpCT; + GtkWidget *label21; + GtkWidget *hbuttonbox17; + GtkWidget *button48; + GtkWidget *button49; + + DumpCDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (DumpCDlg), 5); + gtk_window_set_title (GTK_WINDOW (DumpCDlg), _("Dump code")); + + vbox20 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox20); + gtk_container_add (GTK_CONTAINER (DumpCDlg), vbox20); + gtk_container_set_border_width (GTK_CONTAINER (vbox20), 5); + + label15 = gtk_label_new (_("Set Dump Addr (in Hex):")); + gtk_widget_show (label15); + gtk_box_pack_start (GTK_BOX (vbox20), label15, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label15), 0.1, 0.5); + + hbox11 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox11); + gtk_box_pack_start (GTK_BOX (vbox20), hbox11, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox11), 5); + + label16 = gtk_label_new (_("From 0x")); + gtk_widget_show (label16); + gtk_box_pack_start (GTK_BOX (hbox11), label16, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label16), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label16), TRUE); + + GtkEntry_DumpCF = gtk_entry_new (); + gtk_widget_show (GtkEntry_DumpCF); + gtk_box_pack_start (GTK_BOX (hbox11), GtkEntry_DumpCF, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_DumpCF), 8226); + + hbox12 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox12); + gtk_box_pack_start (GTK_BOX (vbox20), hbox12, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox12), 5); + + label17 = gtk_label_new (_("To 0x")); + gtk_widget_show (label17); + gtk_box_pack_start (GTK_BOX (hbox12), label17, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label17), GTK_JUSTIFY_CENTER); + + GtkEntry_DumpCT = gtk_entry_new (); + gtk_widget_show (GtkEntry_DumpCT); + gtk_box_pack_start (GTK_BOX (hbox12), GtkEntry_DumpCT, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_DumpCT), 8226); + + label21 = gtk_label_new (_("Dump File = \"dump.txt\"")); + gtk_widget_show (label21); + gtk_box_pack_start (GTK_BOX (vbox20), label21, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label21), 0.1, 0.5); + + hbuttonbox17 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox17); + gtk_box_pack_start (GTK_BOX (vbox20), hbuttonbox17, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox17), 30); + + button48 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button48); + gtk_container_add (GTK_CONTAINER (hbuttonbox17), button48); + GTK_WIDGET_SET_FLAGS (button48, GTK_CAN_DEFAULT); + + button49 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button49); + gtk_container_add (GTK_CONTAINER (hbuttonbox17), button49); + GTK_WIDGET_SET_FLAGS (button49, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button48, "clicked", + G_CALLBACK (OnDumpC_Ok), + NULL); + g_signal_connect ((gpointer) button49, "clicked", + G_CALLBACK (OnDumpC_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (DumpCDlg, DumpCDlg, "DumpCDlg"); + GLADE_HOOKUP_OBJECT (DumpCDlg, vbox20, "vbox20"); + GLADE_HOOKUP_OBJECT (DumpCDlg, label15, "label15"); + GLADE_HOOKUP_OBJECT (DumpCDlg, hbox11, "hbox11"); + GLADE_HOOKUP_OBJECT (DumpCDlg, label16, "label16"); + GLADE_HOOKUP_OBJECT (DumpCDlg, GtkEntry_DumpCF, "GtkEntry_DumpCF"); + GLADE_HOOKUP_OBJECT (DumpCDlg, hbox12, "hbox12"); + GLADE_HOOKUP_OBJECT (DumpCDlg, label17, "label17"); + GLADE_HOOKUP_OBJECT (DumpCDlg, GtkEntry_DumpCT, "GtkEntry_DumpCT"); + GLADE_HOOKUP_OBJECT (DumpCDlg, label21, "label21"); + GLADE_HOOKUP_OBJECT (DumpCDlg, hbuttonbox17, "hbuttonbox17"); + GLADE_HOOKUP_OBJECT (DumpCDlg, button48, "button48"); + GLADE_HOOKUP_OBJECT (DumpCDlg, button49, "button49"); + + return DumpCDlg; +} + +GtkWidget* +create_DumpRDlg (void) +{ + GtkWidget *DumpRDlg; + GtkWidget *vbox21; + GtkWidget *label18; + GtkWidget *hbox13; + GtkWidget *label19; + GtkWidget *GtkEntry_DumpRF; + GtkWidget *hbox14; + GtkWidget *label20; + GtkWidget *GtkEntry_DumpRT; + GtkWidget *label22; + GtkWidget *hbuttonbox18; + GtkWidget *button50; + GtkWidget *button51; + + DumpRDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (DumpRDlg), 5); + gtk_window_set_title (GTK_WINDOW (DumpRDlg), _("Raw Dump")); + + vbox21 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox21); + gtk_container_add (GTK_CONTAINER (DumpRDlg), vbox21); + gtk_container_set_border_width (GTK_CONTAINER (vbox21), 5); + + label18 = gtk_label_new (_("Set Dump Addr (in Hex):")); + gtk_widget_show (label18); + gtk_box_pack_start (GTK_BOX (vbox21), label18, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label18), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label18), 0.1, 0.5); + + hbox13 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox13); + gtk_box_pack_start (GTK_BOX (vbox21), hbox13, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox13), 5); + + label19 = gtk_label_new (_("From 0x")); + gtk_widget_show (label19); + gtk_box_pack_start (GTK_BOX (hbox13), label19, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label19), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label19), TRUE); + + GtkEntry_DumpRF = gtk_entry_new (); + gtk_widget_show (GtkEntry_DumpRF); + gtk_box_pack_start (GTK_BOX (hbox13), GtkEntry_DumpRF, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_DumpRF), 8226); + + hbox14 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox14); + gtk_box_pack_start (GTK_BOX (vbox21), hbox14, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox14), 5); + + label20 = gtk_label_new (_("To 0x")); + gtk_widget_show (label20); + gtk_box_pack_start (GTK_BOX (hbox14), label20, FALSE, FALSE, 0); + + GtkEntry_DumpRT = gtk_entry_new (); + gtk_widget_show (GtkEntry_DumpRT); + gtk_box_pack_start (GTK_BOX (hbox14), GtkEntry_DumpRT, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_DumpRT), 8226); + + label22 = gtk_label_new (_("Dump File = \"dump.txt\"")); + gtk_widget_show (label22); + gtk_box_pack_start (GTK_BOX (vbox21), label22, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label22), 0.1, 0.5); + + hbuttonbox18 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox18); + gtk_box_pack_start (GTK_BOX (vbox21), hbuttonbox18, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox18), 30); + + button50 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button50); + gtk_container_add (GTK_CONTAINER (hbuttonbox18), button50); + GTK_WIDGET_SET_FLAGS (button50, GTK_CAN_DEFAULT); + + button51 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button51); + gtk_container_add (GTK_CONTAINER (hbuttonbox18), button51); + GTK_WIDGET_SET_FLAGS (button51, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button50, "clicked", + G_CALLBACK (OnDumpR_Ok), + NULL); + g_signal_connect ((gpointer) button51, "clicked", + G_CALLBACK (OnDumpR_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (DumpRDlg, DumpRDlg, "DumpRDlg"); + GLADE_HOOKUP_OBJECT (DumpRDlg, vbox21, "vbox21"); + GLADE_HOOKUP_OBJECT (DumpRDlg, label18, "label18"); + GLADE_HOOKUP_OBJECT (DumpRDlg, hbox13, "hbox13"); + GLADE_HOOKUP_OBJECT (DumpRDlg, label19, "label19"); + GLADE_HOOKUP_OBJECT (DumpRDlg, GtkEntry_DumpRF, "GtkEntry_DumpRF"); + GLADE_HOOKUP_OBJECT (DumpRDlg, hbox14, "hbox14"); + GLADE_HOOKUP_OBJECT (DumpRDlg, label20, "label20"); + GLADE_HOOKUP_OBJECT (DumpRDlg, GtkEntry_DumpRT, "GtkEntry_DumpRT"); + GLADE_HOOKUP_OBJECT (DumpRDlg, label22, "label22"); + GLADE_HOOKUP_OBJECT (DumpRDlg, hbuttonbox18, "hbuttonbox18"); + GLADE_HOOKUP_OBJECT (DumpRDlg, button50, "button50"); + GLADE_HOOKUP_OBJECT (DumpRDlg, button51, "button51"); + + return DumpRDlg; +} + +GtkWidget* +create_Logging (void) +{ + GtkWidget *Logging; + GtkWidget *vbox23; + GtkWidget *hbox15; + GtkWidget *frame4; + GtkWidget *table3; + GtkWidget *Log0; + GtkWidget *Log1; + GtkWidget *Log2; + GtkWidget *Log3; + GtkWidget *Log4; + GtkWidget *Log5; + GtkWidget *Log6; + GtkWidget *Log7; + GtkWidget *Log8; + GtkWidget *Log9; + GtkWidget *Log10; + GtkWidget *Log11; + GtkWidget *Log12; + GtkWidget *Log13; + GtkWidget *Log15; + GtkWidget *Log14; + GtkWidget *Log16; + GtkWidget *Log31; + GtkWidget *Log; + GtkWidget *Log30; + GtkWidget *label33; + GtkWidget *frame5; + GtkWidget *table4; + GtkWidget *Log27; + GtkWidget *Log26; + GtkWidget *Log25; + GtkWidget *Log24; + GtkWidget *Log23; + GtkWidget *Log22; + GtkWidget *Log21; + GtkWidget *Log20; + GtkWidget *Log28; + GtkWidget *label34; + GtkWidget *hbuttonbox19; + GtkWidget *button66; + GtkWidget *button67; + + Logging = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (Logging), 5); + gtk_window_set_title (GTK_WINDOW (Logging), _("Logging")); + + vbox23 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox23); + gtk_container_add (GTK_CONTAINER (Logging), vbox23); + gtk_container_set_border_width (GTK_CONTAINER (vbox23), 5); + + hbox15 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox15); + gtk_box_pack_start (GTK_BOX (vbox23), hbox15, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox15), 5); + + frame4 = gtk_frame_new (NULL); + gtk_widget_show (frame4); + gtk_box_pack_start (GTK_BOX (hbox15), frame4, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame4), 5); + + table3 = gtk_table_new (8, 3, FALSE); + gtk_widget_show (table3); + gtk_container_add (GTK_CONTAINER (frame4), table3); + gtk_container_set_border_width (GTK_CONTAINER (table3), 5); + gtk_table_set_row_spacings (GTK_TABLE (table3), 5); + gtk_table_set_col_spacings (GTK_TABLE (table3), 5); + + Log0 = gtk_check_button_new_with_mnemonic (_("Cpu Log")); + gtk_widget_show (Log0); + gtk_table_attach (GTK_TABLE (table3), Log0, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log1 = gtk_check_button_new_with_mnemonic (_("Mem Log")); + gtk_widget_show (Log1); + gtk_table_attach (GTK_TABLE (table3), Log1, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log2 = gtk_check_button_new_with_mnemonic (_("Hw Log")); + gtk_widget_show (Log2); + gtk_table_attach (GTK_TABLE (table3), Log2, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log3 = gtk_check_button_new_with_mnemonic (_("Dma Log")); + gtk_widget_show (Log3); + gtk_table_attach (GTK_TABLE (table3), Log3, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log4 = gtk_check_button_new_with_mnemonic (_("Bios Log")); + gtk_widget_show (Log4); + gtk_table_attach (GTK_TABLE (table3), Log4, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log5 = gtk_check_button_new_with_mnemonic (_("Elf Log")); + gtk_widget_show (Log5); + gtk_table_attach (GTK_TABLE (table3), Log5, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log6 = gtk_check_button_new_with_mnemonic (_("Fpu Log")); + gtk_widget_show (Log6); + gtk_table_attach (GTK_TABLE (table3), Log6, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log7 = gtk_check_button_new_with_mnemonic (_("MMI Log")); + gtk_widget_show (Log7); + gtk_table_attach (GTK_TABLE (table3), Log7, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log8 = gtk_check_button_new_with_mnemonic (_("VU0 Log")); + gtk_widget_show (Log8); + gtk_table_attach (GTK_TABLE (table3), Log8, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log9 = gtk_check_button_new_with_mnemonic (_("Cop0 Log")); + gtk_widget_show (Log9); + gtk_table_attach (GTK_TABLE (table3), Log9, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log10 = gtk_check_button_new_with_mnemonic (_("Vif Log")); + gtk_widget_show (Log10); + gtk_table_attach (GTK_TABLE (table3), Log10, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log11 = gtk_check_button_new_with_mnemonic (_("SPR Log")); + gtk_widget_show (Log11); + gtk_table_attach (GTK_TABLE (table3), Log11, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log12 = gtk_check_button_new_with_mnemonic (_("GIF Log")); + gtk_widget_show (Log12); + gtk_table_attach (GTK_TABLE (table3), Log12, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log13 = gtk_check_button_new_with_mnemonic (_("Sif Log")); + gtk_widget_show (Log13); + gtk_table_attach (GTK_TABLE (table3), Log13, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log15 = gtk_check_button_new_with_mnemonic (_("VU Micro Log")); + gtk_widget_show (Log15); + gtk_table_attach (GTK_TABLE (table3), Log15, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log14 = gtk_check_button_new_with_mnemonic (_("IPU Log")); + gtk_widget_show (Log14); + gtk_table_attach (GTK_TABLE (table3), Log14, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log16 = gtk_check_button_new_with_mnemonic (_("RPC Log")); + gtk_widget_show (Log16); + gtk_table_attach (GTK_TABLE (table3), Log16, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log31 = gtk_check_button_new_with_mnemonic (_("Log to STDOUT")); + gtk_widget_show (Log31); + gtk_table_attach (GTK_TABLE (table3), Log31, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log = gtk_check_button_new_with_mnemonic (_("Log")); + gtk_widget_show (Log); + gtk_table_attach (GTK_TABLE (table3), Log, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log30 = gtk_check_button_new_with_mnemonic (_("SYMs Log")); + gtk_widget_show (Log30); + gtk_table_attach (GTK_TABLE (table3), Log30, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label33 = gtk_label_new (_("EE Logs")); + gtk_widget_show (label33); + gtk_frame_set_label_widget (GTK_FRAME (frame4), label33); + + frame5 = gtk_frame_new (NULL); + gtk_widget_show (frame5); + gtk_box_pack_start (GTK_BOX (hbox15), frame5, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame5), 5); + + table4 = gtk_table_new (8, 2, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (frame5), table4); + gtk_container_set_border_width (GTK_CONTAINER (table4), 5); + gtk_table_set_row_spacings (GTK_TABLE (table4), 5); + gtk_table_set_col_spacings (GTK_TABLE (table4), 5); + + Log27 = gtk_check_button_new_with_mnemonic (_("Cdr Log")); + gtk_widget_show (Log27); + gtk_table_attach (GTK_TABLE (table4), Log27, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log26 = gtk_check_button_new_with_mnemonic (_("Gte Log")); + gtk_widget_show (Log26); + gtk_table_attach (GTK_TABLE (table4), Log26, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log25 = gtk_check_button_new_with_mnemonic (_("Pad Log")); + gtk_widget_show (Log25); + gtk_table_attach (GTK_TABLE (table4), Log25, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log24 = gtk_check_button_new_with_mnemonic (_("Dma Log")); + gtk_widget_show (Log24); + gtk_table_attach (GTK_TABLE (table4), Log24, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log23 = gtk_check_button_new_with_mnemonic (_("Bios Log")); + gtk_widget_show (Log23); + gtk_table_attach (GTK_TABLE (table4), Log23, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log22 = gtk_check_button_new_with_mnemonic (_("Hw Log")); + gtk_widget_show (Log22); + gtk_table_attach (GTK_TABLE (table4), Log22, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log21 = gtk_check_button_new_with_mnemonic (_("Mem Log")); + gtk_widget_show (Log21); + gtk_table_attach (GTK_TABLE (table4), Log21, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log20 = gtk_check_button_new_with_mnemonic (_("IOP Log")); + gtk_widget_show (Log20); + gtk_table_attach (GTK_TABLE (table4), Log20, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + Log28 = gtk_check_button_new_with_mnemonic (_("GPU Log")); + gtk_widget_show (Log28); + gtk_table_attach (GTK_TABLE (table4), Log28, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label34 = gtk_label_new (_("IOP Logs")); + gtk_widget_show (label34); + gtk_frame_set_label_widget (GTK_FRAME (frame5), label34); + + hbuttonbox19 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox19); + gtk_box_pack_start (GTK_BOX (vbox23), hbuttonbox19, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox19), 30); + + button66 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button66); + gtk_container_add (GTK_CONTAINER (hbuttonbox19), button66); + GTK_WIDGET_SET_FLAGS (button66, GTK_CAN_DEFAULT); + + button67 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button67); + gtk_container_add (GTK_CONTAINER (hbuttonbox19), button67); + GTK_WIDGET_SET_FLAGS (button67, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button66, "clicked", + G_CALLBACK (OnLogging_Ok), + NULL); + g_signal_connect ((gpointer) button67, "clicked", + G_CALLBACK (OnLogging_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Logging, Logging, "Logging"); + GLADE_HOOKUP_OBJECT (Logging, vbox23, "vbox23"); + GLADE_HOOKUP_OBJECT (Logging, hbox15, "hbox15"); + GLADE_HOOKUP_OBJECT (Logging, frame4, "frame4"); + GLADE_HOOKUP_OBJECT (Logging, table3, "table3"); + GLADE_HOOKUP_OBJECT (Logging, Log0, "Log0"); + GLADE_HOOKUP_OBJECT (Logging, Log1, "Log1"); + GLADE_HOOKUP_OBJECT (Logging, Log2, "Log2"); + GLADE_HOOKUP_OBJECT (Logging, Log3, "Log3"); + GLADE_HOOKUP_OBJECT (Logging, Log4, "Log4"); + GLADE_HOOKUP_OBJECT (Logging, Log5, "Log5"); + GLADE_HOOKUP_OBJECT (Logging, Log6, "Log6"); + GLADE_HOOKUP_OBJECT (Logging, Log7, "Log7"); + GLADE_HOOKUP_OBJECT (Logging, Log8, "Log8"); + GLADE_HOOKUP_OBJECT (Logging, Log9, "Log9"); + GLADE_HOOKUP_OBJECT (Logging, Log10, "Log10"); + GLADE_HOOKUP_OBJECT (Logging, Log11, "Log11"); + GLADE_HOOKUP_OBJECT (Logging, Log12, "Log12"); + GLADE_HOOKUP_OBJECT (Logging, Log13, "Log13"); + GLADE_HOOKUP_OBJECT (Logging, Log15, "Log15"); + GLADE_HOOKUP_OBJECT (Logging, Log14, "Log14"); + GLADE_HOOKUP_OBJECT (Logging, Log16, "Log16"); + GLADE_HOOKUP_OBJECT (Logging, Log31, "Log31"); + GLADE_HOOKUP_OBJECT (Logging, Log, "Log"); + GLADE_HOOKUP_OBJECT (Logging, Log30, "Log30"); + GLADE_HOOKUP_OBJECT (Logging, label33, "label33"); + GLADE_HOOKUP_OBJECT (Logging, frame5, "frame5"); + GLADE_HOOKUP_OBJECT (Logging, table4, "table4"); + GLADE_HOOKUP_OBJECT (Logging, Log27, "Log27"); + GLADE_HOOKUP_OBJECT (Logging, Log26, "Log26"); + GLADE_HOOKUP_OBJECT (Logging, Log25, "Log25"); + GLADE_HOOKUP_OBJECT (Logging, Log24, "Log24"); + GLADE_HOOKUP_OBJECT (Logging, Log23, "Log23"); + GLADE_HOOKUP_OBJECT (Logging, Log22, "Log22"); + GLADE_HOOKUP_OBJECT (Logging, Log21, "Log21"); + GLADE_HOOKUP_OBJECT (Logging, Log20, "Log20"); + GLADE_HOOKUP_OBJECT (Logging, Log28, "Log28"); + GLADE_HOOKUP_OBJECT (Logging, label34, "label34"); + GLADE_HOOKUP_OBJECT (Logging, hbuttonbox19, "hbuttonbox19"); + GLADE_HOOKUP_OBJECT (Logging, button66, "button66"); + GLADE_HOOKUP_OBJECT (Logging, button67, "button67"); + + return Logging; +} + +GtkWidget* +create_CmdLine (void) +{ + GtkWidget *CmdLine; + GtkWidget *vbox24; + GtkWidget *GtkLabel_Text; + GtkWidget *hbox17; + GtkWidget *GtkEntry_dCMDLINE; + GtkWidget *GtkLabel_Note; + GtkWidget *hbuttonbox20; + GtkWidget *GtkButton_Ok; + GtkWidget *GtkButton_Cancel; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + CmdLine = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (CmdLine), 5); + gtk_window_set_title (GTK_WINDOW (CmdLine), _("Program arguments")); + gtk_window_set_modal (GTK_WINDOW (CmdLine), TRUE); + + vbox24 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox24); + gtk_container_add (GTK_CONTAINER (CmdLine), vbox24); + gtk_container_set_border_width (GTK_CONTAINER (vbox24), 5); + + GtkLabel_Text = gtk_label_new (_("Fill in the command line arguments for opened program:")); + gtk_widget_show (GtkLabel_Text); + gtk_box_pack_start (GTK_BOX (vbox24), GtkLabel_Text, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Text), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (GtkLabel_Text), 0.1, 0.5); + + hbox17 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox17); + gtk_box_pack_start (GTK_BOX (vbox24), hbox17, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox17), 5); + + GtkEntry_dCMDLINE = gtk_entry_new (); + gtk_widget_show (GtkEntry_dCMDLINE); + gtk_box_pack_start (GTK_BOX (hbox17), GtkEntry_dCMDLINE, TRUE, TRUE, 0); + gtk_tooltips_set_tip (tooltips, GtkEntry_dCMDLINE, _("If you don't know what to write leave it blank"), NULL); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_dCMDLINE), 8226); + + GtkLabel_Note = gtk_label_new (_("Note: this is intented for developers only.")); + gtk_widget_show (GtkLabel_Note); + gtk_box_pack_start (GTK_BOX (vbox24), GtkLabel_Note, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GtkLabel_Note), GTK_JUSTIFY_CENTER); + + hbuttonbox20 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox20); + gtk_box_pack_start (GTK_BOX (vbox24), hbuttonbox20, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox20), 30); + + GtkButton_Ok = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (GtkButton_Ok); + gtk_container_add (GTK_CONTAINER (hbuttonbox20), GtkButton_Ok); + GTK_WIDGET_SET_FLAGS (GtkButton_Ok, GTK_CAN_DEFAULT); + + GtkButton_Cancel = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (GtkButton_Cancel); + gtk_container_add (GTK_CONTAINER (hbuttonbox20), GtkButton_Cancel); + GTK_WIDGET_SET_FLAGS (GtkButton_Cancel, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) GtkButton_Ok, "clicked", + G_CALLBACK (OnArguments_Ok), + NULL); + g_signal_connect ((gpointer) GtkButton_Cancel, "clicked", + G_CALLBACK (OnArguments_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (CmdLine, CmdLine, "CmdLine"); + GLADE_HOOKUP_OBJECT (CmdLine, vbox24, "vbox24"); + GLADE_HOOKUP_OBJECT (CmdLine, GtkLabel_Text, "GtkLabel_Text"); + GLADE_HOOKUP_OBJECT (CmdLine, hbox17, "hbox17"); + GLADE_HOOKUP_OBJECT (CmdLine, GtkEntry_dCMDLINE, "GtkEntry_dCMDLINE"); + GLADE_HOOKUP_OBJECT (CmdLine, GtkLabel_Note, "GtkLabel_Note"); + GLADE_HOOKUP_OBJECT (CmdLine, hbuttonbox20, "hbuttonbox20"); + GLADE_HOOKUP_OBJECT (CmdLine, GtkButton_Ok, "GtkButton_Ok"); + GLADE_HOOKUP_OBJECT (CmdLine, GtkButton_Cancel, "GtkButton_Cancel"); + GLADE_HOOKUP_OBJECT_NO_REF (CmdLine, tooltips, "tooltips"); + + return CmdLine; +} + +GtkWidget* +create_MemWrite32 (void) +{ + GtkWidget *MemWrite32; + GtkWidget *vbox25; + GtkWidget *hbox18; + GtkWidget *label27; + GtkWidget *label25; + GtkWidget *GtkEntry_Mem; + GtkWidget *hbox19; + GtkWidget *label28; + GtkWidget *label26; + GtkWidget *GtkEntry_Data; + GtkWidget *hbuttonbox22; + GtkWidget *button71; + GtkWidget *button72; + + MemWrite32 = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (MemWrite32), 5); + gtk_window_set_title (GTK_WINDOW (MemWrite32), _("memWrite32")); + + vbox25 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox25); + gtk_container_add (GTK_CONTAINER (MemWrite32), vbox25); + gtk_container_set_border_width (GTK_CONTAINER (vbox25), 5); + + hbox18 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox18); + gtk_box_pack_start (GTK_BOX (vbox25), hbox18, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox18), 5); + + label27 = gtk_label_new (_("Address ")); + gtk_widget_show (label27); + gtk_box_pack_start (GTK_BOX (hbox18), label27, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label27), GTK_JUSTIFY_CENTER); + + label25 = gtk_label_new (_("0x")); + gtk_widget_show (label25); + gtk_box_pack_start (GTK_BOX (hbox18), label25, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label25), GTK_JUSTIFY_CENTER); + + GtkEntry_Mem = gtk_entry_new (); + gtk_widget_show (GtkEntry_Mem); + gtk_box_pack_start (GTK_BOX (hbox18), GtkEntry_Mem, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_Mem), 8226); + + hbox19 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox19); + gtk_box_pack_start (GTK_BOX (vbox25), hbox19, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox19), 5); + + label28 = gtk_label_new (_("Data ")); + gtk_widget_show (label28); + gtk_box_pack_start (GTK_BOX (hbox19), label28, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label28), GTK_JUSTIFY_CENTER); + + label26 = gtk_label_new (_("0x")); + gtk_widget_show (label26); + gtk_box_pack_start (GTK_BOX (hbox19), label26, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label26), GTK_JUSTIFY_CENTER); + + GtkEntry_Data = gtk_entry_new (); + gtk_widget_show (GtkEntry_Data); + gtk_box_pack_start (GTK_BOX (hbox19), GtkEntry_Data, TRUE, TRUE, 0); + gtk_entry_set_invisible_char (GTK_ENTRY (GtkEntry_Data), 8226); + + hbuttonbox22 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox22); + gtk_box_pack_start (GTK_BOX (vbox25), hbuttonbox22, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox22), 30); + + button71 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button71); + gtk_container_add (GTK_CONTAINER (hbuttonbox22), button71); + GTK_WIDGET_SET_FLAGS (button71, GTK_CAN_DEFAULT); + + button72 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button72); + gtk_container_add (GTK_CONTAINER (hbuttonbox22), button72); + GTK_WIDGET_SET_FLAGS (button72, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button71, "clicked", + G_CALLBACK (OnMemWrite32_Ok), + NULL); + g_signal_connect ((gpointer) button72, "clicked", + G_CALLBACK (OnMemWrite32_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (MemWrite32, MemWrite32, "MemWrite32"); + GLADE_HOOKUP_OBJECT (MemWrite32, vbox25, "vbox25"); + GLADE_HOOKUP_OBJECT (MemWrite32, hbox18, "hbox18"); + GLADE_HOOKUP_OBJECT (MemWrite32, label27, "label27"); + GLADE_HOOKUP_OBJECT (MemWrite32, label25, "label25"); + GLADE_HOOKUP_OBJECT (MemWrite32, GtkEntry_Mem, "GtkEntry_Mem"); + GLADE_HOOKUP_OBJECT (MemWrite32, hbox19, "hbox19"); + GLADE_HOOKUP_OBJECT (MemWrite32, label28, "label28"); + GLADE_HOOKUP_OBJECT (MemWrite32, label26, "label26"); + GLADE_HOOKUP_OBJECT (MemWrite32, GtkEntry_Data, "GtkEntry_Data"); + GLADE_HOOKUP_OBJECT (MemWrite32, hbuttonbox22, "hbuttonbox22"); + GLADE_HOOKUP_OBJECT (MemWrite32, button71, "button71"); + GLADE_HOOKUP_OBJECT (MemWrite32, button72, "button72"); + + return MemWrite32; +} + diff --git a/pcsx2/Linux/interface.h b/pcsx2/Linux/interface.h new file mode 100644 index 0000000000..fad1ec703e --- /dev/null +++ b/pcsx2/Linux/interface.h @@ -0,0 +1,34 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_MainWindow (void); +GtkWidget* create_AboutDlg (void); +GtkWidget* create_ConfDlg (void); +GtkWidget* create_CpuDlg (void); +GtkWidget* create_DebugWnd (void); +GtkWidget* create_SetPCDlg (void); +GtkWidget* create_SetBPADlg (void); +GtkWidget* create_SetBPCDlg (void); +GtkWidget* create_DumpCDlg (void); +GtkWidget* create_DumpRDlg (void); +GtkWidget* create_Logging (void); +GtkWidget* create_CmdLine (void); +GtkWidget* create_MemWrite32 (void); diff --git a/pcsx2/Linux/pcsx2.glade b/pcsx2/Linux/pcsx2.glade new file mode 100644 index 0000000000..7786648bd8 --- /dev/null +++ b/pcsx2/Linux/pcsx2.glade @@ -0,0 +1,5235 @@ + + + + + + + True + PCSX + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + _Run CD + True + + + + + + + True + _Load Elf + True + + + + + + + True + + + + + + True + States + True + + + + + + + True + Load + True + + + + + + + True + Slot 1 + True + + + + + + + True + Slot 2 + True + + + + + + + True + Slot 3 + True + + + + + + + True + Slot 4 + True + + + + + + + True + Slot 5 + True + + + + + + + True + Other... + True + + + + + + + + + + + True + Save + True + + + + + + + True + Slot 1 + True + + + + + + + True + Slot 2 + True + + + + + + + True + Slot 3 + True + + + + + + + True + Slot 4 + True + + + + + + + True + Slot 5 + True + + + + + + + True + Other... + True + + + + + + + + + + + + + + + True + E_xit + True + + + + + + + + + + + True + _Run + True + + + + + + + True + E_xecute + True + + + + + + + True + Re_set + True + + + + + + + True + _Arguments + True + + + + + + + + + + + True + _Config + True + + + + + + + True + _Configure + True + + + + + + + True + + + + + + True + _Graphics + True + + + + + + + True + C_ontrollers + True + + + + + + + True + _Sound + True + + + + + + + True + _Cdvdrom + True + + + + + + + True + D_ev9 + True + + + + + + + True + U_SB + True + + + + + + + True + Fire_Wire + True + + + + + + + True + + + + + + True + C_pu + True + + + + + + + + + + + True + _Language + True + + + + + + True + _Misc + True + + + + + + + True + Patch _Browser + True + + + + + + + True + Patch _Finder + True + + + + + + + True + + + + + + True + Enable _Console + True + False + + + + + + + True + Enable _Patches + True + False + + + + + + + + + + + True + _Debug + True + + + + + + + True + Enter Debugger ... + True + + + + + + + True + Logging + True + + + + + + + + + + + True + _Help + True + + + + + + + True + &About... + True + + + + + + + + + + 0 + False + False + + + + + + True + pcsxAbout.bmp + 0.5 + 0.5 + 0 + 0 + + + 1 + True + True + + + + + + True + False + 0 + + + + + + + 0 + True + True + + + + + + + + 10 + True + Pcsx About + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + False + 0 + + + + True + False + 0 + + + + True + PCSX2 + +Version x.x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + False + 0 + + + + True + written by... + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + pcsxAbout.xpm + 0.5 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + 0 + True + True + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + False + 0 + + + + True + greets to... + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 10 + True + Conf + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + 14 + 2 + False + 0 + 15 + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 0 + 1 + 4 + 5 + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 4 + 5 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 1 + 2 + 5 + 6 + fill + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + 1 + 5 + 6 + fill + fill + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + 1 + 2 + 3 + fill + + + + + + True + Graphics + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + + + + + + + + True + First Controller + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + + + + + + + + True + Second Controller + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 3 + 4 + + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 0 + 1 + 1 + 2 + + + + + + + True + Sound + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 0 + 1 + + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 1 + 2 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 1 + 2 + 2 + 3 + fill + fill + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 0 + 1 + 7 + 8 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + 1 + 8 + 9 + fill + + + + + + True + Dev9 + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 6 + 7 + + + + + + + + True + Cdvdrom + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 6 + 7 + + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 7 + 8 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 1 + 2 + 8 + 9 + fill + fill + + + + + + True + Usb + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 9 + 10 + + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 0 + 1 + 10 + 11 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + 1 + 11 + 12 + fill + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 13 + 14 + + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + • + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 10 + 11 + + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Configure + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Test + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + About + True + GTK_RELIEF_NORMAL + True + + + + + + 1 + 2 + 11 + 12 + fill + fill + + + + + + True + FireWire + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 9 + 10 + + + + + + + + True + Bios + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 12 + 13 + + + + + + + 0 + True + True + + + + + + True + False + 14 + + + + True + GTK_BUTTONBOX_START + 0 + + + + True + True + True + Select Plugins Dir + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Select Bios Dir + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + 5 + True + Cpu + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + False + 0 + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + False + 0 + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + CPU vendor + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Family + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Cpu Speed + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Features + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + True + + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + + + 0 + True + True + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + True + EERec - EE/IOP recompiler + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + False + 0 + + + + True + True + VU0rec - enable recompiler for VU0 unit + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + VU1rec - enable recompiler for VU1 unit + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + + + True + VU Recompilers - All options are set by default + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + True + Multi threaded GS mode (MTGS) + (faster on dual core/HT CPUs, requires pcsx2 restart) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Dual Core Mode (DC) - Much faster, but only valid with MTGS + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + True + Normal - All frames are rendered as fast as possible + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Limit - Force frames to normal speeds if too fast + True + GTK_RELIEF_NORMAL + True + False + False + True + GtkRadioButton_LimitNormal + + + 0 + False + False + + + + + + True + True + Frame Skip - In order to achieve normal speeds, + some frames are skipped (faster). + Fps displayed counts skipped frames too + True + GTK_RELIEF_NORMAL + True + False + False + True + GtkRadioButton_LimitNormal + + + 0 + False + False + + + + + + True + True + VU Skip - Same as Frame Skip, but tried to skip more. + Artifacts might be present, but will be faster + True + GTK_RELIEF_NORMAL + True + False + False + True + GtkRadioButton_LimitNormal + + + 0 + False + False + + + + + + + + + + True + Frame Limiting + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + PCSX2 Debugger + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 0 + + + + True + False + 5 + + + + True + True + EE Debug Mode + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + + True + True + IOP Debug Mode + True + GTK_RELIEF_NORMAL + True + False + False + True + GtkRadioButton_EE + + + + 0 + False + False + + + + + 0 + False + True + + + + + + 5 + True + False + 0 + + + + True + False + 0 + + + + True + GTK_POLICY_ALWAYS + GTK_POLICY_NEVER + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + False + False + False + True + False + False + False + + + + + + + 0 + True + True + + + + + + True + GTK_UPDATE_CONTINUOUS + False + 0 0 412 1 20 2 + + + 0 + False + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Step + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Skip + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Go + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Log On/Off + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Set PC + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Set BP Addr + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Set BP Count + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Clear BPs + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Dump code + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Raw Dump + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Close + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + 0 + False + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 10 + + + + True + True + True + memWrite32 + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + button69 + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + button70 + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + 0 + True + True + + + + + + + + 5 + True + SetPCDlg + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Set New PC Address (in Hex): + False + False + GTK_JUSTIFY_CENTER + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + SetBreakPoint Addr + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Set New BP Address (in Hex): + False + False + GTK_JUSTIFY_CENTER + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + SetBreakPoint Addr + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Set New BP Count (in Hex): + False + False + GTK_JUSTIFY_CENTER + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + Dump code + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Set Dump Addr (in Hex): + False + False + GTK_JUSTIFY_LEFT + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + From 0x + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + To 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + Dump File = "dump.txt" + False + False + GTK_JUSTIFY_LEFT + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + Raw Dump + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Set Dump Addr (in Hex): + False + False + GTK_JUSTIFY_CENTER + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + From 0x + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + To 0x + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + Dump File = "dump.txt" + False + False + GTK_JUSTIFY_LEFT + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + Logging + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + 5 + True + False + 5 + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + 8 + 3 + False + 5 + 5 + + + + True + True + Cpu Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + Mem Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + Hw Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + Dma Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + True + Bios Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + True + Elf Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 5 + 6 + fill + + + + + + + True + True + Fpu Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 6 + 7 + fill + + + + + + + True + True + MMI Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + True + VU0 Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + True + Cop0 Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + True + Vif Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + True + SPR Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 3 + 4 + fill + + + + + + + True + True + GIF Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 4 + 5 + fill + + + + + + + True + True + Sif Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 5 + 6 + fill + + + + + + + True + True + VU Micro Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 7 + 8 + fill + + + + + + + True + True + IPU Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 6 + 7 + fill + + + + + + + True + True + RPC Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + True + Log to STDOUT + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 2 + 3 + 5 + 6 + fill + + + + + + + True + True + Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 2 + 3 + 7 + 8 + fill + + + + + + + True + True + SYMs Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 2 + 3 + 6 + 7 + fill + + + + + + + + + True + EE Logs + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + 8 + 2 + False + 5 + 5 + + + + True + True + Cdr Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + True + Gte Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 6 + 7 + fill + + + + + + + True + True + Pad Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 5 + 6 + fill + + + + + + + True + True + Dma Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + True + Bios Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + True + Hw Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + Mem Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + IOP Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + GPU Log + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + + + True + IOP Logs + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + Program arguments + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + True + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + Fill in the command line arguments for opened program: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.10000000149 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + If you don't know what to write leave it blank + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + Note: this is intented for developers only. + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + memWrite32 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + 5 + True + False + 2 + + + + True + Address + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + 5 + True + False + 2 + + + + True + Data + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0x + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + • + False + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + diff --git a/pcsx2/Linux/support.c b/pcsx2/Linux/support.c new file mode 100644 index 0000000000..a3c79b3e1b --- /dev/null +++ b/pcsx2/Linux/support.c @@ -0,0 +1,161 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/pcsx2/Linux/support.h b/pcsx2/Linux/support.h new file mode 100644 index 0000000000..9168053de0 --- /dev/null +++ b/pcsx2/Linux/support.h @@ -0,0 +1,86 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/pcsx2/MMI.c b/pcsx2/MMI.c new file mode 100644 index 0000000000..16fcdbe6d2 --- /dev/null +++ b/pcsx2/MMI.c @@ -0,0 +1,1477 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "InterTables.h" + + +void MMI() { +#ifdef MMI_LOG + MMI_LOG("%s\n", disR5900F(cpuRegs.code, cpuRegs.pc)); +#endif + Int_MMIPrintTable[_Funct_](); +} + +void MMI0() { + Int_MMI0PrintTable[_Sa_](); +} + +void MMI1() { + Int_MMI1PrintTable[_Sa_](); +} + +void MMI2() { + Int_MMI2PrintTable[_Sa_](); +} + +void MMI3() { + Int_MMI3PrintTable[_Sa_](); +} + +void MMI_Unknown() { + SysPrintf ("Unknown MMI opcode called\n"); +} + +//*****************MMI OPCODES********************************* + +void MADD() { + s64 temp = (s64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + + ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); + + cpuRegs.LO.SD[0] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[0] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; +} + +void MADDU() { + u64 tempu = (u64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + + ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); + + cpuRegs.LO.SD[0] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.SD[0] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; +} + +#define _PLZCW(n) { \ + sign = cpuRegs.GPR.r[_Rs_].UL[n] >> 31; \ + for (i=30; i>=0; i--) { \ + if (((cpuRegs.GPR.r[_Rs_].UL[n] >> i) & 0x1) != sign) { \ + break; \ + } \ + } \ + cpuRegs.GPR.r[_Rd_].UL[n] = 30 - i; \ +} + +void PLZCW() { + int i; + u32 sign; + + if (!_Rd_) return; + + _PLZCW (0); + _PLZCW (1); +} + +void MADD1() { + s64 temp = (s64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + + ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); + + cpuRegs.LO.SD[1] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[1] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; +} + +void MADDU1() { + u64 tempu = (u64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + + ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); + + cpuRegs.LO.SD[1] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.SD[1] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; +} + +void MFHI1() { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[1]; +} + +void MFLO1() { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; +} + +void MTHI1() { + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; +} + +void MTLO1() { + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; +} + +void MULT1() { + s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; + + cpuRegs.LO.UD[1] = (s64)(s32)(temp & 0xffffffff); + cpuRegs.HI.UD[1] = (s64)(s32)(temp >> 32); + + /* Modified a bit . asadr */ + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; +} + +void MULTU1() { + u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; + + cpuRegs.LO.UD[1] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.UD[1] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; +} + +void DIV1() { + if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { + cpuRegs.LO.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; + cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; + } +} + +void DIVU1() { + if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; + } +} + +#define PMFHL_CLAMP(dst, src) \ + if ((int)src > (int)0x00007fff) dst = 0x7fff; \ + else \ + if ((int)src < (int)0xffff8000) dst = 0x8000; \ + else dst = (u16)src; + +void PMFHL() { + if (!_Rd_) return; + + switch (_Sa_) { + case 0x00: // LW + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + break; + + case 0x01: // UW + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[3]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[3]; + break; + + case 0x02: // SLW + { + u64 TempU64 = ((u64)cpuRegs.HI.UL[0] << 32) | (u64)cpuRegs.LO.UL[0]; + if (TempU64 >= 0x000000007fffffffLL) { + cpuRegs.GPR.r[_Rd_].UD[0] = 0x000000007fffffffLL; + } else if (TempU64 <= 0xffffffff80000000LL) { + cpuRegs.GPR.r[_Rd_].UD[0] = 0xffffffff80000000LL; + } else { + cpuRegs.GPR.r[_Rd_].UD[0] = (s64)cpuRegs.LO.SL[0]; + } + + TempU64 = ((u64)cpuRegs.HI.UL[2] << 32) | (u64)cpuRegs.LO.UL[2]; + if (TempU64 >= 0x000000007fffffffLL) { + cpuRegs.GPR.r[_Rd_].UD[1] = 0x000000007fffffffLL; + } else if (TempU64 <= 0xffffffff80000000LL) { + cpuRegs.GPR.r[_Rd_].UD[1] = 0xffffffff80000000LL; + } else { + cpuRegs.GPR.r[_Rd_].UD[1] = (s64)cpuRegs.LO.SL[2]; + } + } + break; + + case 0x03: // LH + cpuRegs.GPR.r[_Rd_].US[0] = cpuRegs.LO.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = cpuRegs.LO.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = cpuRegs.HI.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = cpuRegs.HI.US[2]; + cpuRegs.GPR.r[_Rd_].US[4] = cpuRegs.LO.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = cpuRegs.LO.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = cpuRegs.HI.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = cpuRegs.HI.US[6]; + break; + + case 0x04: // SH + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[0], cpuRegs.LO.UL[0]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[1], cpuRegs.LO.UL[1]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[2], cpuRegs.HI.UL[0]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[3], cpuRegs.HI.UL[1]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[4], cpuRegs.LO.UL[2]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[5], cpuRegs.LO.UL[3]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[6], cpuRegs.HI.UL[2]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[7], cpuRegs.HI.UL[3]); + break; + } +} + +void PMTHL() { + if (_Sa_ != 0) return; + + cpuRegs.LO.UL[0] = cpuRegs.GPR.r[_Rs_].UL[0]; + cpuRegs.HI.UL[0] = cpuRegs.GPR.r[_Rs_].UL[1]; + cpuRegs.LO.UL[2] = cpuRegs.GPR.r[_Rs_].UL[2]; + cpuRegs.HI.UL[2] = cpuRegs.GPR.r[_Rs_].UL[3]; +} + +#define _PSLLH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] << ( _Sa_ & 0xf ); + +void PSLLH() { + if (!_Rd_) return; + + _PSLLH(0); _PSLLH(1); _PSLLH(2); _PSLLH(3); + _PSLLH(4); _PSLLH(5); _PSLLH(6); _PSLLH(7); +} + +#define _PSRLH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] >> ( _Sa_ & 0xf ); + +void PSRLH () { + if (!_Rd_) return; + + _PSRLH(0); _PSRLH(1); _PSRLH(2); _PSRLH(3); + _PSRLH(4); _PSRLH(5); _PSRLH(6); _PSRLH(7); +} + +#define _PSRAH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].SS[n] >> ( _Sa_ & 0xf ); + +void PSRAH() { + if (!_Rd_) return; + + _PSRAH(0); _PSRAH(1); _PSRAH(2); _PSRAH(3); + _PSRAH(4); _PSRAH(5); _PSRAH(6); _PSRAH(7); +} + +#define _PSLLW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] << _Sa_; + +void PSLLW() { + if (!_Rd_) return; + + _PSLLW(0); _PSLLW(1); _PSLLW(2); _PSLLW(3); +} + +#define _PSRLW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] >> _Sa_; + +void PSRLW() { + if (!_Rd_) return; + + _PSRLW(0); _PSRLW(1); _PSRLW(2); _PSRLW(3); +} + +#define _PSRAW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].SL[n] >> _Sa_; + +void PSRAW() { + if (!_Rd_) return; + + _PSRAW(0); _PSRAW(1); _PSRAW(2); _PSRAW(3); +} + +//*****************END OF MMI OPCODES************************** +//*************************MMI0 OPCODES************************ + +#define _PADDW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] + cpuRegs.GPR.r[_Rt_].UL[n]; + +void PADDW() { + if (!_Rd_) return; + + _PADDW(0); _PADDW(1); _PADDW(2); _PADDW(3); +} + +#define _PSUBW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] - cpuRegs.GPR.r[_Rt_].UL[n]; + +void PSUBW() { + if (!_Rd_) return; + + _PSUBW(0); _PSUBW(1); _PSUBW(2); _PSUBW(3); +} + +#define _PCGTW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) ? \ + 0xFFFFFFFF : 0x00000000; + +void PCGTW() { + if (!_Rd_) return; + + _PCGTW(0); _PCGTW(1); _PCGTW(2); _PCGTW(3); +} + +#define _PMAXW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) ? \ + cpuRegs.GPR.r[_Rs_].UL[n] : cpuRegs.GPR.r[_Rt_].UL[n]; + +void PMAXW() { + if (!_Rd_) return; + + _PMAXW(0); _PMAXW(1); _PMAXW(2); _PMAXW(3); +} + +#define _PADDH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] + cpuRegs.GPR.r[_Rt_].US[n]; + +void PADDH() { + if (!_Rd_) return; + + _PADDH(0); _PADDH(1); _PADDH(2); _PADDH(3); + _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); +} + +#define _PSUBH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] - cpuRegs.GPR.r[_Rt_].US[n]; + +void PSUBH() { + if (!_Rd_) return; + + _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); + _PSUBH(4); _PSUBH(5); _PSUBH(6); _PSUBH(7); +} + +#define _PCGTH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = \ + (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) ? \ + 0xFFFF : 0x0000; + +void PCGTH() { + if (!_Rd_) return; + + _PCGTH(0); _PCGTH(1); _PCGTH(2); _PCGTH(3); + _PCGTH(4); _PCGTH(5); _PCGTH(6); _PCGTH(7); +} + +#define _PMAXH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = \ + (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) ? \ + cpuRegs.GPR.r[_Rs_].US[n] : cpuRegs.GPR.r[_Rt_].US[n]; + +void PMAXH() { + if (!_Rd_) return; + + _PMAXH(0); _PMAXH(1); _PMAXH(2); _PMAXH(3); + _PMAXH(4); _PMAXH(5); _PMAXH(6); _PMAXH(7); +} + +#define _PADDB(n) \ + cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] + cpuRegs.GPR.r[_Rt_].SC[n]; + +void PADDB() { + if (!_Rd_) return; + + _PADDB(0); _PADDB(1); _PADDB(2); _PADDB(3); + _PADDB(4); _PADDB(5); _PADDB(6); _PADDB(7); + _PADDB(8); _PADDB(9); _PADDB(10); _PADDB(11); + _PADDB(12); _PADDB(13); _PADDB(14); _PADDB(15); +} + +#define _PSUBB(n) \ + cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] - cpuRegs.GPR.r[_Rt_].SC[n]; + +void PSUBB() { + if (!_Rd_) return; + + _PSUBB(0); _PSUBB(1); _PSUBB(2); _PSUBB(3); + _PSUBB(4); _PSUBB(5); _PSUBB(6); _PSUBB(7); + _PSUBB(8); _PSUBB(9); _PSUBB(10); _PSUBB(11); + _PSUBB(12); _PSUBB(13); _PSUBB(14); _PSUBB(15); +} + +#define _PCGTB(n) \ + cpuRegs.GPR.r[_Rd_].UC[n] = (cpuRegs.GPR.r[_Rs_].SC[n] > cpuRegs.GPR.r[_Rt_].SC[n]) ? \ + 0xFF : 0x00; + +void PCGTB() { + if (!_Rd_) return; + + _PCGTB(0); _PCGTB(1); _PCGTB(2); _PCGTB(3); + _PCGTB(4); _PCGTB(5); _PCGTB(6); _PCGTB(7); + _PCGTB(8); _PCGTB(9); _PCGTB(10); _PCGTB(11); + _PCGTB(12); _PCGTB(13); _PCGTB(14); _PCGTB(15); +} + +#define _PADDSW(n) \ + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] + (s64)cpuRegs.GPR.r[_Rt_].SL[n]; \ + if (sTemp64 > 0x7FFFFFFF) { \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; \ + } else \ + if ((sTemp64 < (s32)0x80000000) ) { \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000LL; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; \ + } + +void PADDSW() { + s64 sTemp64; + + if (!_Rd_) return; + + _PADDSW(0); _PADDSW(1); _PADDSW(2); _PADDSW(3); +} + +#define _PSUBSW(n) \ + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] - (s64)cpuRegs.GPR.r[_Rt_].SL[n]; \ + if (sTemp64 >= 0x7FFFFFFF) { \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; \ + } else \ + if ((sTemp64 < (s32)0x80000000) ) { \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; \ + } + +void PSUBSW() { + s64 sTemp64; + + if (!_Rd_) return; + + _PSUBSW(0); + _PSUBSW(1); + _PSUBSW(2); + _PSUBSW(3); +} + +void PEXTLW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[1]; +} + +void PPACW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rs.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[2]; +} + +#define _PADDSH(n) \ + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] + (s32)cpuRegs.GPR.r[_Rt_].SS[n]; \ + if (sTemp32 > 0x7FFF) { \ + cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; \ + } else \ + if ((sTemp32 < (s32)0xffff8000) ) { \ + cpuRegs.GPR.r[_Rd_ ].US[n] = 0x8000; \ + } else { \ + cpuRegs.GPR.r[_Rd_ ].US[n] = (s16)sTemp32; \ + } + +void PADDSH() { + s32 sTemp32; + + if (!_Rd_) return; + + _PADDSH(0); _PADDSH(1); _PADDSH(2); _PADDSH(3); + _PADDSH(4); _PADDSH(5); _PADDSH(6); _PADDSH(7); +} + +#define _PSUBSH(n) \ + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] - (s32)cpuRegs.GPR.r[_Rt_].SS[n]; \ + if (sTemp32 >= 0x7FFF) { \ + cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; \ + } else \ + if ((sTemp32 < (s32)0xffff8000) ) { \ + cpuRegs.GPR.r[_Rd_].US[n] = 0x8000; \ + } else { \ + cpuRegs.GPR.r[_Rd_].US[n] = (s16)sTemp32; \ + } + +void PSUBSH() { + s32 sTemp32; + + if (!_Rd_) return; + + _PSUBSH(0); _PSUBSH(1); _PSUBSH(2); _PSUBSH(3); + _PSUBSH(4); _PSUBSH(5); _PSUBSH(6); _PSUBSH(7); +} + +void PEXTLH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[1]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[3]; +} + +void PPACH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[4] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[6] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; +} + +#define _PADDSB(n) \ + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] + (s16)cpuRegs.GPR.r[_Rt_].SC[n]; \ + if (sTemp16 > 0x7F) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; \ + } else \ + if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; \ + } + +void PADDSB() { + s16 sTemp16; + + if (!_Rd_) return; + + _PADDSB(0); _PADDSB(1); _PADDSB(2); _PADDSB(3); + _PADDSB(4); _PADDSB(5); _PADDSB(6); _PADDSB(7); + _PADDSB(8); _PADDSB(9); _PADDSB(10); _PADDSB(11); + _PADDSB(12); _PADDSB(13); _PADDSB(14); _PADDSB(15); +} + +#define _PSUBSB(n) \ + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] - (s16)cpuRegs.GPR.r[_Rt_].SC[n]; \ + if (sTemp16 >= 0x7F) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; \ + } else \ + if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; \ + } + +void PSUBSB() { + s16 sTemp16; + + if (!_Rd_) return; + + _PSUBSB(0); _PSUBSB(1); _PSUBSB(2); _PSUBSB(3); + _PSUBSB(4); _PSUBSB(5); _PSUBSB(6); _PSUBSB(7); + _PSUBSB(8); _PSUBSB(9); _PSUBSB(10); _PSUBSB(11); + _PSUBSB(12); _PSUBSB(13); _PSUBSB(14); _PSUBSB(15); +} + +void PEXTLB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[1]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[1]; + + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[3]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[3]; + + cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[5]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[5]; + + cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[6]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[6]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[7]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[7]; +} + +void PPACB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rt.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rt.UC[6]; + + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rt.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rt.UC[14]; + + cpuRegs.GPR.r[_Rd_].UC[8] = Rs.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rs.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[6]; + + cpuRegs.GPR.r[_Rd_].UC[12] = Rs.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rs.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[14]; +} + +#define _PEXT5(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x0000001F) << 3) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x000003E0) << 6) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00007C00) << 9) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00008000) << 16); + +void PEXT5() { + if (!_Rd_) return; + + _PEXT5(0); _PEXT5(1); _PEXT5(2); _PEXT5(3); +} + +#define _PPAC5(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 3) & 0x0000001F) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 6) & 0x000003E0) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 9) & 0x00007C00) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 16) & 0x00008000); + +void PPAC5() { + if (!_Rd_) return; + + _PPAC5(0); _PPAC5(1); _PPAC5(2); _PPAC5(3); +} + +//***END OF MMI0 OPCODES****************************************** +//**********MMI1 OPCODES************************************** + +#define _PABSW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = abs(cpuRegs.GPR.r[_Rt_].SL[n]); + +void PABSW() { + if (!_Rd_) return; + + _PABSW(0); _PABSW(1); _PABSW(2); _PABSW(3); +} + +#define _PCEQW(n) \ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + (cpuRegs.GPR.r[_Rs_].UL[n] == cpuRegs.GPR.r[_Rt_].UL[n]) ? \ + 0xFFFFFFFF : 0x00000000; + +void PCEQW() { + if (!_Rd_) return; + + _PCEQW(0); _PCEQW(1); _PCEQW(2); _PCEQW(3); +} + +#define _PMINW(n) \ + cpuRegs.GPR.r[_Rd_].SL[n] = \ + (cpuRegs.GPR.r[_Rs_].SL[n] < cpuRegs.GPR.r[_Rt_].SL[n]) ? \ + cpuRegs.GPR.r[_Rs_].SL[n] : cpuRegs.GPR.r[_Rt_].SL[n]; + +void PMINW() { + if (!_Rd_) return; + + _PMINW(0); _PMINW(1); _PMINW(2); _PMINW(3); +} + +void PADSBH() { + if (!_Rd_) return; + + _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); + _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); +} + +#define _PABSH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = abs(cpuRegs.GPR.r[_Rt_].SS[n]); + +void PABSH() { + if (!_Rd_) return; + + _PABSH(0); _PABSH(1); _PABSH(2); _PABSH(3); + _PABSH(4); _PABSH(5); _PABSH(6); _PABSH(7); +} + +#define _PCEQH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = \ + (cpuRegs.GPR.r[_Rs_].US[n] == cpuRegs.GPR.r[_Rt_].US[n]) ? 0xFFFF : 0x0000; + +void PCEQH() { + if (!_Rd_) return; + + _PCEQH(0); _PCEQH(1); _PCEQH(2); _PCEQH(3); + _PCEQH(4); _PCEQH(5); _PCEQH(6); _PCEQH(7); +} + +#define _PMINH(n) \ + cpuRegs.GPR.r[_Rd_].US[n] = \ + (cpuRegs.GPR.r[_Rs_].SS[n] < cpuRegs.GPR.r[_Rt_].SS[n]) ? \ + cpuRegs.GPR.r[_Rs_].US[n] : cpuRegs.GPR.r[_Rt_].US[n]; + +void PMINH() { + if (!_Rd_) return; + + _PMINH(0); _PMINH(1); _PMINH(2); _PMINH(3); + _PMINH(4); _PMINH(5); _PMINH(6); _PMINH(7); +} + +#define _PCEQB(n) \ + cpuRegs.GPR.r[_Rd_].UC[n] = (cpuRegs.GPR.r[_Rs_].UC[n] == \ + cpuRegs.GPR.r[_Rt_].UC[n]) ? 0xFF : 0x00; + +void PCEQB() { + if (!_Rd_) return; + + _PCEQB(0); _PCEQB(1); _PCEQB(2); _PCEQB(3); + _PCEQB(4); _PCEQB(5); _PCEQB(6); _PCEQB(7); + _PCEQB(8); _PCEQB(9); _PCEQB(10); _PCEQB(11); + _PCEQB(12); _PCEQB(13); _PCEQB(14); _PCEQB(15); +} + +#define _PADDUW(n) \ + tmp = (s64)cpuRegs.GPR.r[_Rs_].UL[n] + (s64)cpuRegs.GPR.r[_Rt_].UL[n]; \ + if (tmp > 0xffffffff) \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0xffffffff; \ + else cpuRegs.GPR.r[_Rd_].UL[n] = (u32)tmp; + +void PADDUW () { + s64 tmp; + + if (!_Rd_) return; + + _PADDUW(0); _PADDUW(1); _PADDUW(2); _PADDUW(3); +} + +#define _PSUBUW(n) \ + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].UL[n] - (s64)cpuRegs.GPR.r[_Rt_].UL[n]; \ + if (sTemp64 <= 0x0) { \ + cpuRegs.GPR.r[_Rd_].UL[n] = 0x0; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UL[n] = (u32)sTemp64; \ + } + +void PSUBUW() { + s64 sTemp64; + + if (!_Rd_) return; + + _PSUBUW(0); _PSUBUW(1); _PSUBUW(2); _PSUBUW(3); +} + +void PEXTUW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[3]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[3]; +} + +#define _PADDUH(n) \ + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] + (s32)cpuRegs.GPR.r[_Rt_].US[n]; \ + if (sTemp32 > 0xFFFF) { \ + cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; \ + } else { \ + cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; \ + } + +void PADDUH() { + s32 sTemp32; + + if (!_Rd_) return; + + _PADDUH(0); _PADDUH(1); _PADDUH(2); _PADDUH(3); + _PADDUH(4); _PADDUH(5); _PADDUH(6); _PADDUH(7); +} + +#define _PSUBUH(n) \ + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] - (s32)cpuRegs.GPR.r[_Rt_].US[n]; \ + if (sTemp32 <= 0x0) { \ + cpuRegs.GPR.r[_Rd_].US[n] = 0x0; \ + } else { \ + cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; \ + } + +void PSUBUH() { + s32 sTemp32; + + if (!_Rd_) return; + + _PSUBUH(0); _PSUBUH(1); _PSUBUH(2); _PSUBUH(3); + _PSUBUH(4); _PSUBUH(5); _PSUBUH(6); _PSUBUH(7); +} + +void PEXTUH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; + + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[7]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; +} + +#define _PADDUB(n) \ + Temp16 = (u16)cpuRegs.GPR.r[_Rs_].UC[n] + (u16)cpuRegs.GPR.r[_Rt_].UC[n]; \ + if (Temp16 > 0xFF) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UC[n] = (u8)Temp16; \ + } + +void PADDUB() { + u16 Temp16; + + if (!_Rd_) return; + + _PADDUB(0); _PADDUB(1); _PADDUB(2); _PADDUB(3); + _PADDUB(4); _PADDUB(5); _PADDUB(6); _PADDUB(7); + _PADDUB(8); _PADDUB(9); _PADDUB(10); _PADDUB(11); + _PADDUB(12); _PADDUB(13); _PADDUB(14); _PADDUB(15); +} + +#define _PSUBUB(n) \ + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].UC[n] - (s16)cpuRegs.GPR.r[_Rt_].UC[n]; \ + if (sTemp16 <= 0x0) { \ + cpuRegs.GPR.r[_Rd_].UC[n] = 0x0; \ + } else { \ + cpuRegs.GPR.r[_Rd_].UC[n] = (u8)sTemp16; \ + } + +void PSUBUB() { + s16 sTemp16; + + if (!_Rd_) return; + + _PSUBUB(0); _PSUBUB(1); _PSUBUB(2); _PSUBUB(3); + _PSUBUB(4); _PSUBUB(5); _PSUBUB(6); _PSUBUB(7); + _PSUBUB(8); _PSUBUB(9); _PSUBUB(10); _PSUBUB(11); + _PSUBUB(12); _PSUBUB(13); _PSUBUB(14); _PSUBUB(15); +} + +void PEXTUB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[9]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[9]; + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[11]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[11]; + cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[13]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[13]; + cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[14]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[14]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[15]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[15]; +} + +void QFSRV() { // JayteeMaster: changed a bit to avoid screw up + GPR_reg Rd; + if (!_Rd_) return; + + if (cpuRegs.sa == 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; + } else { + if (cpuRegs.sa < 64) { + /* + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; + cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); + */ + Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; + Rd.UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; + Rd.UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); + Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_] = Rd; + } else { + /* + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); + cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); + */ + Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); + Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); + Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); + Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_] = Rd; + } + } +} + +//********END OF MMI1 OPCODES*********************************** + +//*********MMI2 OPCODES*************************************** + +#define _PMADDW(dd, ss) { \ + s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) + \ + ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); \ + \ + cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); \ + cpuRegs.HI.SD[dd] = (s32)(temp >> 32); \ + \ + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; \ +} + +void PMADDW() { + _PMADDW(0, 0); + _PMADDW(1, 2); +} + +void PSLLVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (s32)(cpuRegs.GPR.r[_Rt_].UL[2] << + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +void PSRLVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] >> + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].UL[2] >> + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +#define _PMSUBW(dd, ss) { \ + s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) - \ + ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); \ + \ + cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); \ + cpuRegs.HI.SD[dd] = (s32)(temp >> 32); \ + \ + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; \ +} + +void PMSUBW() { + _PMSUBW(0, 0); + _PMSUBW(1, 2); +} + +void PMFHI() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.HI.UD[1]; +} + +void PMFLO() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.LO.UD[1]; +} + +void PINTH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; +} + +#define _PMULTW(dd, ss) { \ + s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]; \ + \ + cpuRegs.LO.UD[dd] = (s32)(temp & 0xffffffff); \ + cpuRegs.HI.UD[dd] = (s32)(temp >> 32); \ + \ + if (_Rd_) { \ + cpuRegs.GPR.r[_Rd_].SD[dd] = temp; \ + } \ +} + +void PMULTW() { + _PMULTW(0, 0); + _PMULTW(1, 2); +} + +#define _PDIVW(dd, ss) \ + if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) { \ + cpuRegs.LO.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] / cpuRegs.GPR.r[_Rt_].SL[ss]; \ + cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] % cpuRegs.GPR.r[_Rt_].SL[ss]; \ + } + +void PDIVW() { + _PDIVW(0, 0); + _PDIVW(1, 2); +} + +void PCPYLD() { + if (!_Rd_) return; + + // note: first _Rs_, since the other way when _Rd_ equals + // _Rs_ or _Rt_ this would screw up + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; +} + +void PMADDH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = cpuRegs.LO.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp; */ + + temp = cpuRegs.LO.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = cpuRegs.HI.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp; */ + + temp = cpuRegs.HI.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = cpuRegs.LO.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp; */ + + temp = cpuRegs.LO.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = cpuRegs.HI.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp; */ + + temp = cpuRegs.HI.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } + +} + +// JayteeMaster: changed a bit to avoid screw up +#define _PHMADH(hlr, dd, n) { \ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; \ + \ + cpuRegs.hlr.UL[dd] = temp; \ + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[n] = temp; */\ +} + +void PHMADH() { // JayteeMaster: changed a bit to avoid screw up. Also used 0,2,4,6 instead of 0,1,2,3 + _PHMADH(LO, 0, 0); + _PHMADH(HI, 0, 2); + _PHMADH(LO, 2, 4); + _PHMADH(HI, 2, 6); + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +void PAND() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] & cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PXOR() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] ^ cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PMSUBH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = cpuRegs.LO.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ + + temp = cpuRegs.LO.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = cpuRegs.HI.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ + + temp = cpuRegs.HI.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = cpuRegs.LO.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ + + temp = cpuRegs.LO.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = cpuRegs.HI.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ + + temp = cpuRegs.HI.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +// JayteeMaster: changed a bit to avoid screw up +#define _PHMSBH(hlr, dd, n, rdd) { \ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; \ + \ + cpuRegs.hlr.UL[dd] = temp; \ + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[rdd] = temp;*/ \ +} + +void PHMSBH() { // JayteeMaster: changed a bit to avoid screw up + _PHMSBH(LO, 0, 0, 0); + _PHMSBH(HI, 0, 2, 1); + _PHMSBH(LO, 2, 4, 2); + _PHMSBH(HI, 2, 6, 3); + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +void PEXEH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; +} + +void PREVH () { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[7]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; +} + +void PMULTH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +#define _PDIVBW(n) \ + cpuRegs.LO.UL[n] = (s32)(cpuRegs.GPR.r[_Rs_].SL[n] / cpuRegs.GPR.r[_Rt_].SS[0]); \ + cpuRegs.HI.UL[n] = (s16)(cpuRegs.GPR.r[_Rs_].SL[n] % cpuRegs.GPR.r[_Rt_].SS[0]); \ + +void PDIVBW() { + if (cpuRegs.GPR.r[_Rt_].US[0] == 0) return; + + _PDIVBW(0); _PDIVBW(1); _PDIVBW(2); _PDIVBW(3); +} + +void PEXEW() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +void PROT3W() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +//*****END OF MMI2 OPCODES*********************************** + +//*************************MMI3 OPCODES************************ + +#define _PMADDUW(dd, ss) { \ + u64 tempu = (u64)((u64)cpuRegs.LO.UL[ss] | ((u64)cpuRegs.HI.UL[ss] << 32)) + \ + ((u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]); \ + \ + cpuRegs.LO.SD[dd] = (s32)(tempu & 0xffffffff); \ + cpuRegs.HI.SD[dd] = (s32)(tempu >> 32); \ + \ + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; \ +} + +void PMADDUW() { + _PMADDUW(0, 0); + _PMADDUW(1, 2); +} + +void PSRAVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] >> + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].SL[2] >> + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +void PMTHI() { + cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; +} + +void PMTLO() { + cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; +} + +void PINTEH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; +} + +#define _PMULTUW(dd, ss) { \ + u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; \ + \ + cpuRegs.LO.UD[dd] = (s32)(tempu & 0xffffffff); \ + cpuRegs.HI.UD[dd] = (s32)(tempu >> 32); \ + \ + if (_Rd_) { \ + cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; \ + } \ +} + +void PMULTUW() { + _PMULTUW(0, 0); + _PMULTUW(1, 2); +} + +#define _PDIVUW(dd, ss) \ + if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) { \ + cpuRegs.LO.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] / (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; \ + cpuRegs.HI.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] % (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; \ + } + +void PDIVUW() { + _PDIVUW(0, 0); + _PDIVUW(1, 2); +} + +void PCPYUD() { + if (!_Rd_) return; + + // note: first _Rs_, since the other way when _Rd_ equals + // _Rs_ or _Rt_ this would screw up + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[1]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void POR() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PNOR () { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = ~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); + cpuRegs.GPR.r[_Rd_].UD[1] = ~(cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]); +} + +void PEXCH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; +} + +void PCPYH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; +} + +void PEXCW() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +//**********************END OF MMI3 OPCODES******************** + +// obs: +// QFSRV not verified + diff --git a/pcsx2/Makefile.am b/pcsx2/Makefile.am new file mode 100644 index 0000000000..24cd733dcc --- /dev/null +++ b/pcsx2/Makefile.am @@ -0,0 +1,29 @@ +AUTOMAKE_OPTIONS = foreign +INCLUDES = -I@srcdir@/x86/ +noinst_LIBRARIES = libpcsx2.a + +libpcsx2_a_SOURCES = \ +CdRom.c Decode_XA.h Mdec.h PsxBios.h R3000A.c Vif.h \ +CdRom.h EEregs.h PsxCommon.h R3000A.h VU0.c \ +CDVD.c Elfheader.c Memory.c PsxCounters.c R5900.c VU0.h \ +CDVD.h Elfheader.h Memory.h PsxCounters.h R5900.h VU0micro.c \ +CDVDiso.c FiFo.c Misc.c PsxDma.c Sif.c VU1micro.c \ +CDVDisodrv.c FPU2.cpp PsxDma.h Sifcmd.h VUflags.c \ +CDVDisodrv.h FPU.c MMI.c Sif.h VUflags.h \ +CDVDiso.h GS.cpp Patch.c Sio.c VU.h \ +CDVDlib.h GS.h Patch.h PsxHw.c Sio.h VUmicro.h \ +Common.h Hw.c Plugins.c PsxHw.h SPR.c VUops.c \ +COP0.c Hw.h Plugins.h PsxInterpreter.c SPR.h VUops.h \ +COP0.h Interpreter.c PS2Edefs.h PsxMem.c System.h \ +Counters.c InterTables.c PS2Etypes.h PsxMem.h Vif.c \ +Counters.h InterTables.h PsxBios2.h PsxSio2.c VifDma.c \ +Decode_XA.c Mdec.c PsxBios.c PsxSio2.h VifDma.h Cache.c \ +xmlpatchloader.cpp + +if RECBUILD +recdir = x86 +else +recdir= +endif + +SUBDIRS = $(recdir) . DebugTools IPU RDebug tinyxml Linux \ No newline at end of file diff --git a/pcsx2/Mdec.c b/pcsx2/Mdec.c new file mode 100644 index 0000000000..85f133b30e --- /dev/null +++ b/pcsx2/Mdec.c @@ -0,0 +1,521 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* This code was based on the FPSE v0.08 Mdec decoder*/ + +#include +#include + +#include "PsxCommon.h" +#include "Mdec.h" + +#define FIXED + +#define CONST_BITS 8 +#define PASS1_BITS 2 + +#define FIX_1_082392200 (277) +#define FIX_1_414213562 (362) +#define FIX_1_847759065 (473) +#define FIX_2_613125930 (669) + +#define MULTIPLY(var,const) (DESCALE((var) * (const), CONST_BITS)) + +#define DEQUANTIZE(coef,quantval) (coef) + +#define DESCALE(x,n) ((x)>>(n)) +#define RANGE(n) (n) + +#define DCTSIZE 8 +#define DCTSIZE2 64 + +static void idct1(int *block) +{ + int val = RANGE(DESCALE(block[0], PASS1_BITS+3)); + int i; + for(i=0;i>16)*(bcr&0xffff); + + if (cmd==0x60000000) { + } else + if (cmd==0x40000001) { + u8 *p = (u8*)PSXM(adr); + iqtab_init(iq_y,p); + iqtab_init(iq_uv,p+64); + } else + if ((cmd&0xf5ff0000)==0x30000000) { + mdec.rl = (u16*)PSXM(adr); + } + else { + } + + HW_DMA0_CHCR &= ~0x01000000; + psxDmaInterrupt(0); +} + +void psxDma1(u32 adr, u32 bcr, u32 chcr) { + int blk[DCTSIZE2*6]; + unsigned short *image; + int size; + +#ifdef CDR_LOG + CDR_LOG("DMA1 %lx %lx %lx (cmd = %lx)\n", adr, bcr, chcr, mdec.command); +#endif + + if (chcr!=0x01000200) return; + + size = (bcr>>16)*(bcr&0xffff); + image = (u16*)PSXM(adr); + if (mdec.command&0x08000000) { + for (;size>0;size-=(16*16)/2,image+=(16*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb15(blk,image); + } + } else { + for (;size>0;size-=(24*16)/2,image+=(24*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb24(blk,(u8 *)image); + } + } + + HW_DMA1_CHCR &= ~0x01000000; + psxDmaInterrupt(1); +} + + +#define RUNOF(a) ((a)>>10) +#define VALOF(a) (((int)(a)<<(32-10))>>(32-10)) + +static int zscan[DCTSIZE2] = { + 0 ,1 ,8 ,16,9 ,2 ,3 ,10, + 17,24,32,25,18,11,4 ,5 , + 12,19,26,33,40,48,41,34, + 27,20,13,6 ,7 ,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63 +}; + +static int aanscales[DCTSIZE2] = { + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +void iqtab_init(int *iqtab,unsigned char *iq_y) +{ +#define CONST_BITS14 14 +#define IFAST_SCALE_BITS 2 + int i; + + for(i=0;i>(CONST_BITS14-IFAST_SCALE_BITS); + } +} + +#define NOP 0xfe00 +unsigned short* rl2blk(int *blk,unsigned short *mdec_rl) { + int i,k,q_scale,rl; + int *iqtab; + + memset (blk, 0, 6*DCTSIZE2*4); + iqtab = iq_uv; + for(i=0;i<6;i++) { // decode blocks (Cr,Cb,Y1,Y2,Y3,Y4) + if (i>1) iqtab = iq_y; + + // zigzag transformation + rl = *mdec_rl++; + q_scale = RUNOF(rl); + blk[0] = iqtab[0]*VALOF(rl); + for(k = 0;;) { + rl = *mdec_rl++; + if (rl==NOP) break; + k += RUNOF(rl)+1; // skip level zero-coefficients + if (k > 63) break; + blk[zscan[k]] = (VALOF(rl) * iqtab[k] * q_scale) / 8; // / 16; + } +// blk[0] = (blk[0] * iq_t[0] * 8) / 16; +// for(int j=1;j<64;j++) +// blk[j] = blk[j] * iq_t[j] * q_scale; + + // idct + idct(blk,k+1); + + blk+=DCTSIZE2; + } + return mdec_rl; +} + +#ifdef FIXED +#define MULR(a) ((((int)0x0000059B) * (a)) >> 10) +#define MULG(a) ((((int)0xFFFFFEA1) * (a)) >> 10) +#define MULG2(a) ((((int)0xFFFFFD25) * (a)) >> 10) +#define MULB(a) ((((int)0x00000716) * (a)) >> 10) +#else +#define MULR(a) ((int)((float)1.40200 * (a))) +#define MULG(a) ((int)((float)-0.3437 * (a))) +#define MULG2(a) ((int)((float)-0.7143 * (a))) +#define MULB(a) ((int)((float)1.77200 * (a))) +#endif + +#define MAKERGB15(r,g,b) ( (((r)>>3)<<10)|(((g)>>3)<<5)|((b)>>3) ) +#define ROUND(c) roundtbl[((c)+128+256)]//&0x3ff] +/*#define ROUND(c) round(c+128) +int round(int r) { + if (r<0) return 0; + if (r>255) return 255; + return r; +}*/ + +#define RGB15(n, Y) \ + image[n] = MAKERGB15(ROUND(Y + R),ROUND(Y + G),ROUND(Y + B)); + +#define RGB15BW(n, Y) \ + image[n] = MAKERGB15(ROUND(Y),ROUND(Y),ROUND(Y)); + +#define RGB24(n, Y) \ + image[n+2] = ROUND(Y + R); \ + image[n+1] = ROUND(Y + G); \ + image[n+0] = ROUND(Y + B); + +#define RGB24BW(n, Y) \ + image[n+2] = ROUND(Y); \ + image[n+1] = ROUND(Y); \ + image[n+0] = ROUND(Y); + +unsigned char roundtbl[256*3]; + +void round_init(void) { + int i; + for(i=0;i<256;i++) { + roundtbl[i]=0; + roundtbl[i+256]=i; + roundtbl[i+512]=255; + } +} + +void yuv2rgb15(int *blk,unsigned short *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int Cb,Cr,R,G,B; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!(Config.Mdec&0x1)) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Crblk++,Cbblk++,Yblk+=2) { + Cr = *Crblk; + Cb = *Cbblk; + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB15(0, Yblk[0]); + RGB15(1, Yblk[1]); + RGB15(16, Yblk[8]); + RGB15(17, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB15(8, Yblk[DCTSIZE2+0]); + RGB15(9, Yblk[DCTSIZE2+1]); + RGB15(24, Yblk[DCTSIZE2+8]); + RGB15(25, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Yblk+=2) { + RGB15BW(0, Yblk[0]); + RGB15BW(1, Yblk[1]); + RGB15BW(16, Yblk[8]); + RGB15BW(17, Yblk[9]); + + RGB15BW(8, Yblk[DCTSIZE2+0]); + RGB15BW(9, Yblk[DCTSIZE2+1]); + RGB15BW(24, Yblk[DCTSIZE2+8]); + RGB15BW(25, Yblk[DCTSIZE2+9]); + } + } +} + +void yuv2rgb24(int *blk,unsigned char *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int Cb,Cr,R,G,B; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!(Config.Mdec&0x1)) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Crblk++,Cbblk++,Yblk+=2) { + Cr = *Crblk; + Cb = *Cbblk; + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB24(0, Yblk[0]); + RGB24(1*3, Yblk[1]); + RGB24(16*3, Yblk[8]); + RGB24(17*3, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB24(8*3, Yblk[DCTSIZE2+0]); + RGB24(9*3, Yblk[DCTSIZE2+1]); + RGB24(24*3, Yblk[DCTSIZE2+8]); + RGB24(25*3, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Yblk+=2) { + RGB24BW(0, Yblk[0]); + RGB24BW(1*3, Yblk[1]); + RGB24BW(16*3, Yblk[8]); + RGB24BW(17*3, Yblk[9]); + + RGB24BW(8*3, Yblk[DCTSIZE2+0]); + RGB24BW(9*3, Yblk[DCTSIZE2+1]); + RGB24BW(24*3, Yblk[DCTSIZE2+8]); + RGB24BW(25*3, Yblk[DCTSIZE2+9]); + } + } +} + +int mdecFreeze(gzFile f, int Mode) { + + gzfreeze(&mdec, sizeof(mdec)); + + gzfreezel(iq_y); + + gzfreezel(iq_uv); + + + + return 0; + +} + + + + diff --git a/pcsx2/Mdec.h b/pcsx2/Mdec.h new file mode 100644 index 0000000000..bc01be8378 --- /dev/null +++ b/pcsx2/Mdec.h @@ -0,0 +1,31 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __MDEC_H__ +#define __MDEC_H__ + +void mdecInit(); +void mdecWrite0(u32 data); +void mdecWrite1(u32 data); +u32 mdecRead0(); +u32 mdecRead1(); +void psxDma0(u32 madr, u32 bcr, u32 chcr); +void psxDma1(u32 madr, u32 bcr, u32 chcr); +int mdecFreeze(gzFile f, int Mode); + +#endif /* __MDEC_H__ */ diff --git a/pcsx2/Memory.c b/pcsx2/Memory.c new file mode 100644 index 0000000000..0166ac3c05 --- /dev/null +++ b/pcsx2/Memory.c @@ -0,0 +1,3168 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + +RAM +--- +0x00100000-0x01ffffff this is the physical address for the ram.its cached there +0x20100000-0x21ffffff uncached +0x30100000-0x31ffffff uncached & acceleretade +0xa0000000-0xa1ffffff MIRROR might...??? +0x80000000-0x81ffffff MIRROR might... ???? + +scratch pad +---------- +0x70000000-0x70003fff scratch pad + +BIOS +---- +0x1FC00000 - 0x1FFFFFFF un-cached +0x9FC00000 - 0x9FFFFFFF cached +0xBFC00000 - 0xBFFFFFFF un-cached +*/ + +////////// +// Rewritten by zerofrog(@gmail.com) to add os virtual memory +////////// + + +#if _WIN32_WINNT < 0x0500 +#define _WIN32_WINNT 0x0500 +#endif + +#pragma warning(disable:4799) // No EMMS at end of function + +#include +#include +#include +#include + +#include "Common.h" + +#ifdef PCSX2_NORECBUILD +#define REC_CLEARM(mem) +#else +#include "iR5900.h" +#endif + +#include "PsxMem.h" +#include "R3000A.h" +#include "PsxHw.h" +#include "VUmicro.h" +#include "GS.h" + +#ifdef ENABLECACHE +#include "Cache.h" +#endif + +#include + +extern u32 maxrecmem; +extern int rdram_devices, rdram_sdevid; + +#ifndef __x86_64__ +extern void * memcpy_fast(void *dest, const void *src, size_t n); +#endif + +//#define FULLTLB +int MemMode = 0; // 0 is Kernel Mode, 1 is Supervisor Mode, 2 is User Mode + +u16 ba0R16(u32 mem) { +#ifdef MEM_LOG + //MEM_LOG("ba00000 Memory read16 address %x\n", mem); +#endif + +#ifdef PCSX2_VIRTUAL_MEM + if (mem == 0x1a000006) { +#else + if (mem == 0xba000006) { +#endif + static int ba6; + ba6++; + if (ba6 == 3) ba6 = 0; + return ba6; + } + return 0; +} + +///////////////////////////// +// VIRTUAL MEM START +///////////////////////////// +#ifdef PCSX2_VIRTUAL_MEM + +PSMEMORYBLOCK s_psM = {0}, s_psHw = {0}, s_psS = {0}, s_psxM = {0}, s_psVuMem = {0}; + +#define PHYSICAL_ALLOC(ptr, size, block) { \ + if(SysPhysicalAlloc(size, &block) == -1 ) \ + goto eCleanupAndExit; \ + if(SysVirtualPhyAlloc((void*)ptr, size, &block) == -1) \ + goto eCleanupAndExit; \ +} \ + +#define PHYSICAL_FREE(ptr, size, block) { \ + SysVirtualFree(ptr, size); \ + SysPhysicalFree(&block); \ +} \ + +#ifdef _WIN32 // windows implementation of vm + +PSMEMORYMAP initMemoryMap(ULONG_PTR* aPFNs, ULONG_PTR* aVFNs) +{ + PSMEMORYMAP m; + m.aPFNs = aPFNs; + m.aVFNs = aVFNs; + return m; +} + +// only do vm hack for release +#ifndef PCSX2_DEVBUILD +#define VM_HACK +#endif + +// virtual memory blocks +PSMEMORYMAP *memLUT = NULL; + +#define VIRTUAL_ALLOC(base, size, Protection) { \ + LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE|MEM_COMMIT, Protection ); \ + if( lpMemReserved == NULL || base != lpMemReserved ) \ + { \ + SysPrintf("Cannot reserve memory at 0x%8.8x(%x), error: %d.\n", base, lpMemReserved, GetLastError()); \ + goto eCleanupAndExit; \ + } \ +} \ + +#define VIRTUAL_FREE(ptr, size) { \ + VirtualFree(ptr, size, MEM_DECOMMIT); \ + VirtualFree(ptr, 0, MEM_RELEASE); \ +} \ + +int memInit() { + + int i; + LPVOID pExtraMem = NULL; + + // release the previous reserved mem + VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE); + + // allocate all virtual memory + PHYSICAL_ALLOC(PS2MEM_BASE, 0x02000000, s_psM); + VIRTUAL_ALLOC(PS2MEM_ROM, 0x00400000, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_ROM1, 0x00040000, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_ROM2, 0x00080000, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_EROM, 0x001C0000, PAGE_READONLY); + PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_ALLOC(PS2MEM_HW, 0x00010000, s_psHw); + PHYSICAL_ALLOC(PS2MEM_PSX, 0x00200000, s_psxM); + PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_ALLOC(PS2MEM_PSXHW, 0x00010000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PAGE_NOACCESS); + + VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PAGE_READWRITE); + + // reserve the left over 224Mb, don't map + pExtraMem = VirtualAlloc(PS2MEM_BASE+0x02000000, 0x0e000000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + if( pExtraMem != PS2MEM_BASE+0x02000000 ) + goto eCleanupAndExit; + + // reserve left over psx mem + pExtraMem = VirtualAlloc(PS2MEM_PSX+0x00200000, 0x00600000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + if( pExtraMem != PS2MEM_PSX+0x00200000 ) + goto eCleanupAndExit; + + // reserve gs mem + pExtraMem = VirtualAlloc(PS2MEM_BASE+0x20000000, 0x10000000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + if( pExtraMem != PS2MEM_BASE+0x20000000 ) + goto eCleanupAndExit; + + // special addrs mmap + VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PAGE_READWRITE); + + // alloc virtual mappings + memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16); + memset(memLUT, 0, sizeof(PSMEMORYMAP)*0x100000); + for (i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]); + for (i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]); + for (i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]); + for (i=0; i<0x00004; i++) memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]); + for (i=0; i<0x00004; i++) memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]); + for (i=0; i<0x00004; i++) memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]); + for (i=0; i<0x00004; i++) memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]); + + for (i=0; i<0x00004; i++) memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]); + + // map to other modes + memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); + memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); + + if (psxInit() == -1) + goto eCleanupAndExit; + + return 0; + +eCleanupAndExit: + if( pExtraMem != NULL ) + VirtualFree(pExtraMem, 0x0e000000, MEM_RELEASE); + memShutdown(); + return -1; +} + +void memShutdown() +{ + VirtualFree(PS2MEM_BASE+0x02000000, 0, MEM_RELEASE); + VirtualFree(PS2MEM_PSX+0x00200000, 0, MEM_RELEASE); + VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE); + + PHYSICAL_FREE(PS2MEM_BASE, 0x02000000, s_psM); + VIRTUAL_FREE(PS2MEM_ROM, 0x00400000); + VIRTUAL_FREE(PS2MEM_ROM1, 0x00080000); + VIRTUAL_FREE(PS2MEM_ROM2, 0x00080000); + VIRTUAL_FREE(PS2MEM_EROM, 0x001C0000); + PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_FREE(PS2MEM_HW, 0x00010000, s_psHw); + PHYSICAL_FREE(PS2MEM_PSX, 0x00800000, s_psxM); + PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs + + VIRTUAL_FREE(PS2MEM_PSXHW, 0x00010000); + VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000); + VIRTUAL_FREE(PS2MEM_GS, 0x00010000); + VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2_, 0x00010000); + + VIRTUAL_FREE(PS2MEM_B80, 0x00010000); + VIRTUAL_FREE(PS2MEM_BA0, 0x00010000); + + VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); + + _aligned_free(memLUT); memLUT = NULL; + + // reserve mem + VirtualAlloc(PS2MEM_BASE, 0x40000000, MEM_RESERVE, PAGE_NOACCESS); +} + +//NOTE: A lot of the code reading depends on the registers being less than 8 +// MOV8 88/8A +// MOV16 6689 +// MOV32 89/8B +// SSEMtoR64 120f +// SSERtoM64 130f +// SSEMtoR128 280f +// SSERtoM128 290f + +#define SKIP_WRITE() { \ + switch(code&0xff) { \ + case 0x88: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + break; \ + case 0x66: \ + assert( code&0x800000 ); \ + assert( (code&0xffff) == 0x8966 ); \ + ContextRecord->Eip += 7; \ + break; \ + case 0x89: \ + assert( code&0x8000 ); \ + ContextRecord->Eip += 6; \ + break; \ + case 0x0f: /* 130f, 230f*/ \ + assert( (code&0xffff) == 0x290f || (code&0xffff) == 0x130f ); \ + assert( code&0x800000 ); \ + ContextRecord->Eip += 7; \ + break; \ + default: \ + goto DefaultHandler; \ + } \ +} \ + +#define SKIP_READ() { \ + switch(code&0xff) { \ + case 0x8A: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + rd = (code>>(8+3))&7; \ + break; \ + case 0x66: \ + if( (code&0x07000000) == 0x05000000 ) ContextRecord->Eip += 8; /* 8 for mem reads*/ \ + else ContextRecord->Eip += 4 + ((code&0x1f000000) == 0x0c000000) + !!(code&0x40000000); \ + rd = (code>>(24+3))&7; \ + break; \ + case 0x8B: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + rd = (code>>(8+3))&7; \ + break; \ + case 0x0f: { \ + assert( (code&0xffff)==0x120f || (code&0xffff)==0x280f || (code&0xffff) == 0xb60f || (code&0xffff) == 0xb70f ); \ + if( !(code&0x800000) ) goto DefaultHandler; \ + ContextRecord->Eip += 7; \ + rd = (code>>(16+3))&7; \ + break; } \ + default: \ + goto DefaultHandler; \ + } \ +} \ + +int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps) +{ + struct _EXCEPTION_RECORD* ExceptionRecord = eps->ExceptionRecord; + struct _CONTEXT* ContextRecord = eps->ContextRecord; + + u32 addr; + + C_ASSERT(sizeof(ContextRecord->Eax) == 4); + + // If the exception is not a page fault, exit. + if (ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // get bad virtual address + addr = (u32)ExceptionRecord->ExceptionInformation[1]; + + if( addr >= (u32)PS2MEM_BASE && addr < (u32)PS2MEM_BASE+0x60000000) { + PSMEMORYMAP* pmap; + + pmap = &memLUT[(addr-(u32)PS2MEM_BASE)>>12]; + + if( pmap->aPFNs == NULL ) { + // NOTE: this is a hack because the address is truncated and there's no way + // to tell what it's upper bits are (due to OS limitations). + pmap += 0x80000; + if( pmap->aPFNs == NULL ) { + pmap += 0x20000; + } + //else addr += 0x20000000; + } + + if( pmap->aPFNs != NULL ) { + LPVOID pnewaddr; + DWORD oldaddr = pmap->aVFNs[0]; + + if( pmap->aVFNs[0] != 0 ) { + // delete the current mapping + SysMapUserPhysicalPages((void*)pmap->aVFNs[0], 1, NULL, 0); + } + + assert( pmap->aPFNs[0] != 0 ); + + pmap->aVFNs[0] = addr&~0xfff; + if( SysMapUserPhysicalPages((void*)(addr&~0xfff), 1, pmap->aPFNs, 0) ) + return EXCEPTION_CONTINUE_EXECUTION; + + // try allocing the virtual mem + pnewaddr = VirtualAlloc((void*)(addr&~0xffff), 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + + if( SysMapUserPhysicalPages((void*)(addr&~0xfff), 1, pmap->aPFNs, 0) ) + return EXCEPTION_CONTINUE_EXECUTION; + + SysPrintf("Fatal error, virtual page 0x%x cannot be found %d (p:%x,v:%x)\n", + addr-(u32)PS2MEM_BASE, GetLastError(), pmap->aPFNs[0], pmap->aVFNs[0]); + } + } + else { + // check if vumem + + if( (addr&0xffff4000) == 0x11000000 ) { + // vu0mem + SysMapUserPhysicalPages((void*)s_psVuMem.aVFNs[1], 1, NULL, 0); + + s_psVuMem.aVFNs[1] = addr&~0xfff; + SysMapUserPhysicalPages((void*)addr, 1, s_psVuMem.aPFNs, 1); + + return EXCEPTION_CONTINUE_EXECUTION; + } + } + +#ifdef VM_HACK + { + u32 code = *(u32*)ExceptionRecord->ExceptionAddress; + u32 rd = 0; + + if( ExceptionRecord->ExceptionInformation[0] ) { + //SKIP_WRITE(); + // shouldn't be writing + } + else { + SysPrintf("vmhack "); + SKIP_READ(); + //((u32*)&ContextRecord->Eax)[rd] = 0; + return EXCEPTION_CONTINUE_EXECUTION; // TODO: verify this!!! + } + } +DefaultHandler: +#endif + + return EXCEPTION_CONTINUE_SEARCH; +} + +#else // linux implementation + +#define VIRTUAL_ALLOC(base, size, Protection) { \ + void* lpMemReserved = mmap( base, size, Protection, MAP_PRIVATE|MAP_ANONYMOUS ); \ + if( lpMemReserved == NULL || base != lpMemReserved ) \ + { \ + SysPrintf("Cannot reserve memory at 0x%8.8x(%x).\n", base, lpMemReserved); \ + perror("err"); \ + goto eCleanupAndExit; \ + } \ +} \ + +#define VIRTUAL_FREE(ptr, size) munmap(ptr, size) + +uptr *memLUT = NULL; + +int memInit() +{ +int i; + LPVOID pExtraMem = NULL; + + // release the previous reserved mem + munmap(PS2MEM_BASE, 0x40000000); + + // allocate all virtual memory + PHYSICAL_ALLOC(PS2MEM_BASE, 0x02000000, s_psM); + VIRTUAL_ALLOC(PS2MEM_ROM, 0x00400000, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_ROM1, 0x00040000, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_ROM2, 0x00080000, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_EROM, 0x001C0000, PROT_READ); + PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_ALLOC(PS2MEM_HW, 0x00010000, s_psHw); + PHYSICAL_ALLOC(PS2MEM_PSX, 0x00200000, s_psxM); + PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_ALLOC(PS2MEM_PSXHW, 0x00010000, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PROT_NONE); + + VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PROT_READ|PROT_WRITE); + + // special addrs mmap + VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PROT_READ|PROT_WRITE); + + // alloc virtual mappings + memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(uptr), 16); + memset(memLUT, 0, sizeof(uptr)*0x100000); + for (i=0; i<0x02000; i++) memLUT[i + 0x00000] = PS2MEM_BASE+(i<<12); + for (i=2; i<0x00010; i++) memLUT[i + 0x10000] = PS2MEM_BASE+0x10000000+(i<<12); + for (i=0; i<0x00800; i++) memLUT[i + 0x1c000] = PS2MEM_BASE+0x1c000000+(i<<12); + for (i=0; i<0x00004; i++) memLUT[i + 0x11000] = PS2MEM_VU0MICRO; + for (i=0; i<0x00004; i++) memLUT[i + 0x11004] = PS2MEM_VU0MEM; + for (i=0; i<0x00004; i++) memLUT[i + 0x11008] = PS2MEM_VU1MICRO+(i<<12); + for (i=0; i<0x00004; i++) memLUT[i + 0x1100c] = PS2MEM_VU1MEM+(i<<12); + + for (i=0; i<0x00004; i++) memLUT[i + 0x50000] = PS2MEM_SCRATCH+(i<<12); + + // map to other modes + memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(uptr)); + memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(uptr)); + + if (psxInit() == -1) + goto eCleanupAndExit; + +eCleanupAndExit: + memShutdown(); + return -1; +} + +void memShutdown() +{ + VIRTUAL_FREE(PS2MEM_BASE, 0x40000000); + VIRTUAL_FREE(PS2MEM_PSX, 0x00800000); + + PHYSICAL_FREE(PS2MEM_BASE, 0x02000000, s_psM); + VIRTUAL_FREE(PS2MEM_ROM, 0x00400000); + VIRTUAL_FREE(PS2MEM_ROM1, 0x00080000); + VIRTUAL_FREE(PS2MEM_ROM2, 0x00080000); + VIRTUAL_FREE(PS2MEM_EROM, 0x001C0000); + PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_FREE(PS2MEM_HW, 0x00010000, s_psHw); + PHYSICAL_FREE(PS2MEM_PSX, 0x00800000, s_psxM); + PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs + + VIRTUAL_FREE(PS2MEM_PSXHW, 0x00010000); + VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000); + VIRTUAL_FREE(PS2MEM_GS, 0x00010000); + VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2_, 0x00010000); + + VIRTUAL_FREE(PS2MEM_B80, 0x00010000); + VIRTUAL_FREE(PS2MEM_BA0, 0x00010000); + + VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); + + _aligned_free(memLUT); memLUT = NULL; + + // reserve mem + if( mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) != PS2MEM_BASE ) { + SysPrintf("failed to reserve mem\n"); + } +} + +#endif // _WIN32 + +// Some games read/write between different addrs but same physical memory +// this causes major slowdowns because it goes into the exception handler, so use this (zerofrog) +u32 VM_RETRANSLATE(u32 mem) +{ + u8* p, *pbase; + if( (mem&0xffff0000) == 0x50000000 ) // reserved scratch pad mem + return PS2MEM_BASE_+mem; + + p = (u8*)dmaGetAddrBase(mem); + +#ifdef _WIN32 + // do manual LUT since IPU/SPR seems to use addrs 0x3000xxxx quite often + if( memLUT[ (p-PS2MEM_BASE)>>12 ].aPFNs == NULL ) { + return PS2MEM_BASE_+mem; + } + + pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; + if( pbase != NULL ) + p = pbase + ((u32)p&0xfff); +#endif + + return (u32)p; +} + +void memSetPageAddr(u32 vaddr, u32 paddr) { + + PSMEMORYMAP* pmap; + + if( vaddr == paddr ) + return; + + if( (vaddr>>28) != 1 && (vaddr>>28) != 9 && (vaddr>>28) != 11 ) { +#ifdef _WIN32 + pmap = &memLUT[vaddr >> 12]; + + if( pmap->aPFNs != NULL && (pmap->aPFNs != memLUT[paddr>>12].aPFNs || + pmap->aVFNs[0] != TRANSFORM_ADDR(vaddr)+(u32)PS2MEM_BASE) ) { + + SysMapUserPhysicalPages((void*)pmap->aVFNs[0], 1, NULL, 0); + pmap->aVFNs[0] = 0; + } + + *pmap = memLUT[paddr >> 12]; +#else + memLUT[vaddr>>12] = memLUT[paddr>>12]; +#endif + } +} + +void memClearPageAddr(u32 vaddr) { +// SysPrintf("memClearPageAddr: %8.8x\n", vaddr); + + if ((vaddr & 0xffffc000) == 0x70000000) return; + +#ifdef _WIN32 +// if( vaddr >= 0x20000000 && vaddr < 0x80000000 ) { +// Cpu->Clear(vaddr&~0xfff, 0x1000/4); +// if( memLUT[vaddr>>12].aVFNs != NULL ) { +// SysMapUserPhysicalPages((void*)memLUT[vaddr>>12].aVFNs[0], 1, NULL, 0 ); +// memLUT[vaddr>>12].aVFNs = NULL; +// memLUT[vaddr>>12].aPFNs = NULL; +// } +// } +#else + if( memLUT[vaddr>>12] != NULL ) { + SysVirtualFree(memLUT[vaddr>>12], 0x1000); + memLUT[vaddr>>12] = 0; + } +#endif +} + +u8 recMemRead8() +{ + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&~0xffff) ) { + case 0x1f400000: return psxHw4Read8(mem); + case 0x10000000: return hwRead8(mem); + case 0x1f800000: return psxHwRead8(mem); + case 0x12000000: return *(PS2MEM_BASE+(mem&~0xc00)); + case 0x14000000: + { + u32 ret = DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); + return ret; + } + + default: + return *(u8*)(PS2MEM_BASE+mem); + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return 0; +} + +void _eeReadConstMem8(int mmreg, u32 mem, int sign) +{ + assert( !IS_XMMREG(mmreg)); + + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem-3); + assert(0); + } + else { + if( sign ) MOVSX32M8toR(mmreg, mem); + else MOVZX32M8toR(mmreg, mem); + } +} + +void _eeReadConstMem16(int mmreg, u32 mem, int sign) +{ + assert( !IS_XMMREG(mmreg)); + + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem-2); + assert(0); + } + else { + if( sign ) MOVSX32M16toR(mmreg, mem); + else MOVZX32M16toR(mmreg, mem); + } +} + +void _eeReadConstMem32(int mmreg, u32 mem) +{ + if( IS_XMMREG(mmreg) ) SSEX_MOVD_M32_to_XMM(mmreg&0xf, mem); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem); + } + else MOV32MtoR(mmreg, mem); +} + +void _eeReadConstMem128(int mmreg, u32 mem) +{ + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQMtoR((mmreg>>4)&0xf, mem+8); + MOVQMtoR(mmreg&0xf, mem); + } + else SSEX_MOVDQA_M128_to_XMM( mmreg&0xf, mem); +} + +void _eeWriteConstMem8(u32 mem, int mmreg) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + if( IS_EECONSTREG(mmreg) ) MOV8ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV8ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV8RtoM(mem, mmreg); +} + +void _eeWriteConstMem16(u32 mem, int mmreg) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + if( IS_EECONSTREG(mmreg) ) MOV16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV16RtoM(mem, mmreg); +} + +void _eeWriteConstMem16OP(u32 mem, int mmreg, int op) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + switch(op) { + case 0: // and + if( IS_EECONSTREG(mmreg) ) AND16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) AND16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else AND16RtoM(mem, mmreg); + break; + case 1: // and + if( IS_EECONSTREG(mmreg) ) OR16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) OR16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else OR16RtoM(mem, mmreg); + break; + default: assert(0); + } +} + +void _eeWriteConstMem32(u32 mem, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV32RtoM(mem, mmreg); +} + +void _eeWriteConstMem32OP(u32 mem, int mmreg, int op) +{ + switch(op) { + case 0: // and + if( IS_XMMREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SSE2_PAND_M128_to_XMM(mmreg&0xf, mem); + SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SetMMXstate(); + PANDMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + AND32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + AND32RtoM(mem, mmreg&0xf); + } + break; + + case 1: // or + if( IS_XMMREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SSE2_POR_M128_to_XMM(mmreg&0xf, mem); + SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SetMMXstate(); + PORMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + OR32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + OR32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + OR32RtoM(mem, mmreg&0xf); + } + break; + + case 2: // not and + if( mmreg & MEM_XMMTAG ) { + _deleteEEreg(mmreg>>16, 1); + SSEX_PANDN_M128_to_XMM(mmreg&0xf, mem); + SSEX_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( mmreg & MEM_MMXTAG ) { + _deleteEEreg(mmreg>>16, 1); + PANDNMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + AND32ItoM(mem, ~g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM(mem, ~g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + NOT32R(mmreg&0xf); + AND32RtoM(mem, mmreg&0xf); + } + break; + + default: assert(0); + } +} + +void _eeWriteConstMem64(u32 mem, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_XMM_to_M64(mem, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQRtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); + } + else assert(0); +} + +void _eeWriteConstMem128(u32 mem, int mmreg) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQRtoM(mem, mmreg&0xf); + MOVQRtoM(mem+8, (mmreg>>4)&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + SetMMXstate(); + MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); + MOVQRtoM(mem+8, mmreg&0xf); + } + else SSEX_MOVDQA_XMM_to_M128(mem, mmreg&0xf); +} + +void _eeMoveMMREGtoR(x86IntRegType to, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_R(to, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVD32MMXtoR(to, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) MOV32ItoR(to, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoR(to, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else if( mmreg != to ) MOV32RtoR(to, mmreg); +} + +int recMemConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { + case 0x1f40: return psxHw4ConstRead8(x86reg, mem, sign); + case 0x1000: return hwConstRead8(x86reg, mem, sign); + case 0x1f80: return psxHwConstRead8(x86reg, mem, sign); + case 0x1200: return gsConstRead8(x86reg, mem, sign); + case 0x1400: + { + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read8); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + return 1; + } + + default: + _eeReadConstMem8(x86reg, VM_RETRANSLATE(mem), sign); + return 0; + } +} + +u16 recMemRead16() { + + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( mem>>16 ) { + case 0x1000: return hwRead16(mem); + case 0x1f80: return psxHwRead16(mem); + case 0x1200: return *(u16*)(PS2MEM_BASE+(mem&~0xc00)); + case 0x1800: return 0; + case 0x1a00: return ba0R16(mem); + case 0x1f90: + case 0x1f00: + return SPU2read(mem); + case 0x1400: + { + u32 ret = DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); + return ret; + } + + default: + return *(u16*)(PS2MEM_BASE+mem); + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return 0; +} + +int recMemConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { + case 0x1000: return hwConstRead16(x86reg, mem, sign); + case 0x1f80: return psxHwConstRead16(x86reg, mem, sign); + case 0x1200: return gsConstRead16(x86reg, mem, sign); + case 0x1800: + if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else XOR32RtoR(x86reg, x86reg); + return 0; + case 0x1a00: + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)ba0R16); + ADD32ItoR(ESP, 4); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + + case 0x1f90: + case 0x1f00: + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2read); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + + case 0x1400: + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read16); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + + default: + _eeReadConstMem16(x86reg, VM_RETRANSLATE(mem), sign); + return 0; + } +} + +__declspec(naked) +u32 recMemRead32() { + // ecx is address - already anded with ~0xa0000000 + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwread + cmp dx, 0x1f80 + je psxhwread + cmp dx, 0x1200 + je gsread + cmp dx, 0x1400 + je devread + + // default read + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + } + +hwread: + { + __asm { + cmp ecx, 0x10002000 + jb counterread + + cmp ecx, 0x1000f260 + je hwsifpresetread + cmp ecx, 0x1000f240 + je hwsifsyncread + cmp ecx, 0x1000f440 + je hwmch_drd + cmp ecx, 0x1000f430 + je hwmch_ricm + + cmp ecx, 0x10003000 + jb hwdefread2 + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + + // ipu +hwdefread2: + push ecx + call ipuRead32 + add esp, 4 + ret + + // sif +hwsifpresetread: + xor eax, eax + ret +hwsifsyncread: + mov eax, 0x1000F240 + mov eax, dword ptr [eax+PS2MEM_BASE_] + or eax, 0xF0000102 + ret + } + +counterread: + { + static u32 mem, index; + + // counters + __asm mov mem, ecx + index = (mem>>11)&3; + + if( (mem&0x7ff) == 0 ) { + __asm { + push index + call rcntRcount + add esp, 4 + and eax, 0xffff + ret + } + } + + index = (u32)&counters[index] + ((mem>>2)&0xc); + + __asm { + mov eax, index + mov eax, dword ptr [eax] + movzx eax, ax + ret + } + } + +hwmch_drd: // MCH_DRD + __asm { + mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] + shr eax, 6 + test eax, 0xf + jz mch_drd_2 +hwmch_ricm: + xor eax, eax + ret + +mch_drd_2: + shr eax, 10 + and eax, 0xfff + cmp eax, 0x21 // INIT + je mch_drd_init + cmp eax, 0x23 // CNFGA + je mch_drd_cnfga + cmp eax, 0x24 // CNFGB + je mch_drd_cnfgb + cmp eax, 0x40 // DEVID + je mch_drd_devid + xor eax, eax + ret + +mch_drd_init: + mov edx, rdram_devices + xor eax, eax + cmp edx, rdram_sdevid + setg al + add rdram_sdevid, eax + imul eax, 0x1f + ret + +mch_drd_cnfga: + mov eax, 0x0D0D + ret + +mch_drd_cnfgb: + mov eax, 0x0090 + ret + +mch_drd_devid: + mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] + and eax, 0x1f + ret + } + } + +psxhwread: + __asm { + push ecx + call psxHwRead32 + add esp, 4 + ret + } + +gsread: + __asm { + and ecx, 0xfffff3ff + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + } + +devread: + __asm { + and ecx, 0xfbffffff + push ecx + call DEV9read32 + add esp, 4 + ret + } +} + +int recMemConstRead32(u32 x86reg, u32 mem) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&~0xffff) ) { + case 0x10000000: return hwConstRead32(x86reg, mem); + case 0x1f800000: return psxHwConstRead32(x86reg, mem); + case 0x12000000: return gsConstRead32(x86reg, mem); + case 0x14000000: + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read32); + return 1; + + default: + _eeReadConstMem32(x86reg, VM_RETRANSLATE(mem)); + return 0; + } +} + +void recMemRead64(u64 *out) +{ + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&0xffff0000) ) { + case 0x10000000: *out = hwRead64(mem); return; + case 0x11000000: *out = *(u64*)(PS2MEM_BASE+mem); return; + case 0x12000000: *out = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); return; + + default: + //assert(0); + *out = *(u64*)(PS2MEM_BASE+mem); + return; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); +} + +void recMemConstRead64(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { + case 0x10000000: hwConstRead64(mem, mmreg); return; + case 0x12000000: gsConstRead64(mem, mmreg); return; + default: + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, VM_RETRANSLATE(mem)); + else { + MOVQMtoR(mmreg, VM_RETRANSLATE(mem)); + SetMMXstate(); + } + return; + } +} + +void recMemRead128(u64 *out) { + + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&0xffff0000) ) { + case 0x10000000: + hwRead128(mem, out); + return; + case 0x12000000: + out[0] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); + out[1] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)+8); + return; + case 0x11000000: + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return; + default: + //assert(0); + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); +} + +void recMemConstRead128(u32 mem, int xmmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { + case 0x10000000: hwConstRead128(mem, xmmreg); return; + case 0x12000000: gsConstRead128(mem, xmmreg); return; + default: + _eeReadConstMem128(xmmreg, VM_RETRANSLATE(mem)); + return; + } +} + +void errwrite() +{ + int i, bit, tempeax; + __asm mov i, ecx + __asm mov tempeax, eax + __asm mov bit, edx + SysPrintf("Error write%d at %x\n", bit, i); + assert(0); + __asm mov eax, tempeax + __asm mov ecx, i +} + +void recMemWrite8() +{ + register u32 mem; + register u8 value; + __asm mov mem, ecx // already anded with ~0xa0000000 + __asm mov value, al + + switch( mem>>16 ) { + case 0x1f40: psxHw4Write8(mem, value); return; + case 0x1000: hwWrite8(mem, value); return; + case 0x1f80: psxHwWrite8(mem, value); return; + case 0x1200: gsWrite8(mem, value); return; + case 0x1400: + DEV9write8(mem & ~0x04000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); + return; + +#ifdef _DEBUG + case 0x1100: assert(0); +#endif + default: + // vus, bad addrs, etc + *(u8*)(PS2MEM_BASE+mem) = value; + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +int recMemConstWrite8(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { + case 0x1f40: psxHw4ConstWrite8(mem, mmreg); return 0; + case 0x1000: hwConstWrite8(mem, mmreg); return 0; + case 0x1f80: psxHwConstWrite8(mem, mmreg); return 0; + case 0x1200: gsConstWrite8(mem, mmreg); return 0; + case 0x1400: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write8); + return 0; + + case 0x1100: + _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU0); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU1); + ADD32ItoR(ESP, 8); + } + return 0; + + default: + _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +void recMemWrite16() { + + register u32 mem; + register u16 value; + __asm mov mem, ecx // already anded with ~0xa0000000 + __asm mov value, ax + + switch( mem>>16 ) { + case 0x1000: hwWrite16(mem, value); return; + case 0x1600: + //HACK: DEV9 VM crash fix + return; + case 0x1f80: psxHwWrite16(mem, value); return; + case 0x1200: gsWrite16(mem, value); return; + case 0x1f90: + case 0x1f00: SPU2write(mem, value); return; + case 0x1400: + DEV9write16(mem & ~0x04000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); + return; + +#ifdef _DEBUG + case 0x1100: assert(0); +#endif + default: + // vus, bad addrs, etc + *(u16*)(PS2MEM_BASE+mem) = value; + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +int recMemConstWrite16(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { + case 0x1000: hwConstWrite16(mem, mmreg); return 0; + case 0x1600: + //HACK: DEV9 VM crash fix + return 0; + case 0x1f80: psxHwConstWrite16(mem, mmreg); return 0; + case 0x1200: gsConstWrite16(mem, mmreg); return 0; + case 0x1f90: + case 0x1f00: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2write); + return 0; + case 0x1400: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write16); + return 0; + + case 0x1100: + _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU0); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU1); + ADD32ItoR(ESP, 8); + } + return 0; + + default: + _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +C_ASSERT( sizeof(BASEBLOCK) == 8 ); + +__declspec(naked) +void recMemWrite32() +{ + // ecx is address - already anded with ~0xa0000000 + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1f80 + je psxwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1400 + je devwrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + // default write + mov dword ptr [ecx+PS2MEM_BASE_], eax + ret + +hwwrite: + push eax + push ecx + call hwWrite32 + add esp, 8 + ret +psxwrite: + push eax + push ecx + call psxHwWrite32 + add esp, 8 + ret +gswrite: + push eax + push ecx + call gsWrite32 + add esp, 8 + ret +devwrite: + and ecx, 0xfbffffff + push eax + push ecx + call DEV9write32 + add esp, 8 + ret +vuwrite: + // default write + mov dword ptr [ecx+PS2MEM_BASE_], eax + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, Cpu + push 1 + push ecx + call [eax]Cpu.ClearVU0 + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, Cpu + push 1 + push ecx + call [eax]Cpu.ClearVU1 + add esp, 8 +vuend: + ret + } +} + +int recMemConstWrite32(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem&0xffff0000 ) { + case 0x10000000: hwConstWrite32(mem, mmreg); return 0; + case 0x1f800000: psxHwConstWrite32(mem, mmreg); return 0; + case 0x12000000: gsConstWrite32(mem, mmreg); return 0; + case 0x1f900000: + case 0x1f000000: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2write); + return 0; + case 0x14000000: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write32); + return 0; + + case 0x11000000: + _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU0); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU1); + ADD32ItoR(ESP, 8); + } + return 0; + + default: + _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +__declspec(naked) void recMemWrite64() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + // default write + mov edx, 64 + call errwrite + +hwwrite: + push dword ptr [eax+4] + push dword ptr [eax] + push ecx + call hwWrite64 + add esp, 12 + ret + +gswrite: + push dword ptr [eax+4] + push dword ptr [eax] + push ecx + call gsWrite64 + add esp, 12 + ret + +vuwrite: + mov ebx, dword ptr [eax] + mov edx, dword ptr [eax+4] + mov dword ptr [ecx+PS2MEM_BASE_], ebx + mov dword ptr [ecx+PS2MEM_BASE_+4], edx + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, Cpu + push 2 + push ecx + call [eax]Cpu.ClearVU0 + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, Cpu + push 2 + push ecx + call [eax]Cpu.ClearVU1 + add esp, 8 +vuend: + ret + } +} + +int recMemConstWrite64(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem>>16) ) { + case 0x1000: hwConstWrite64(mem, mmreg); return 0; + case 0x1200: gsConstWrite64(mem, mmreg); return 0; + + case 0x1100: + _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(2); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU0); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(2); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU1); + ADD32ItoR(ESP, 8); + } + return 0; + + default: + _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +__declspec(naked) +void recMemWrite128() +{ + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + mov edx, 128 + call errwrite + +hwwrite: + + push eax + push ecx + call hwWrite128 + add esp, 8 + ret + +vuwrite: + mov ebx, dword ptr [eax] + mov edx, dword ptr [eax+4] + mov edi, dword ptr [eax+8] + mov eax, dword ptr [eax+12] + mov dword ptr [ecx+PS2MEM_BASE_], ebx + mov dword ptr [ecx+PS2MEM_BASE_+4], edx + mov dword ptr [ecx+PS2MEM_BASE_+8], edi + mov dword ptr [ecx+PS2MEM_BASE_+12], eax + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, Cpu + push 4 + push ecx + call [eax]Cpu.ClearVU0 + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, Cpu + push 4 + push ecx + call [eax]Cpu.ClearVU1 + add esp, 8 +vuend: + + // default write + //movaps xmm7, qword ptr [eax] + + // removes possible exceptions and saves on remapping memory + // *might* be faster for certain games, no way to tell +// cmp ecx, 0x20000000 +// jb Write128 +// +// // look for better mapping +// mov edx, ecx +// shr edx, 12 +// shl edx, 3 +// add edx, memLUT +// mov edx, dword ptr [edx + 4] +// cmp edx, 0 +// je Write128 +// mov edx, dword ptr [edx] +// cmp edx, 0 +// je Write128 +// and ecx, 0xfff +// movaps qword ptr [ecx+edx], xmm7 +// jmp CheckOverwrite +//Write128: + //movaps qword ptr [ecx+PS2MEM_BASE_], xmm7 + ret + +gswrite: + sub esp, 8 + movlps xmm7, qword ptr [eax] + movlps qword ptr [esp], xmm7 + push ecx + call gsWrite64 + + // call again for upper 8 bytes + movlps xmm7, qword ptr [eax+8] + movlps qword ptr [esp+4], xmm7 + add [esp], 8 + call gsWrite64 + add esp, 12 + ret + } +} + +int recMemConstWrite128(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { + case 0x10000000: hwConstWrite128(mem, mmreg); return 0; + case 0x12000000: gsConstWrite128(mem, mmreg); return 0; + + case 0x11000000: + _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(4); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU0); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(4); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)Cpu->ClearVU1); + ADD32ItoR(ESP, 8); + } + return 0; + + default: + _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +int memRead8 (u32 mem, u8 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: *out = psxHw4Read8(mem); return 0; + case 0x10000000: *out = hwRead8(mem); return 0; + case 0x1f800000: *out = psxHwRead8(mem); return 0; + case 0x12000000: *out = gsRead8(mem); return 0; + case 0x14000000: + *out = DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u8*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead8RS (u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: *out = (s8)psxHw4Read8(mem); return 0; + case 0x10000000: *out = (s8)hwRead8(mem); return 0; + case 0x1f800000: *out = (s8)psxHwRead8(mem); return 0; + case 0x12000000: *out = (s8)gsRead8(mem); return 0; + case 0x14000000: + *out = (s8)DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(s8*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead8RU (u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: *out = (u8)psxHw4Read8(mem); return 0; + case 0x10000000: *out = (u8)hwRead8(mem); return 0; + case 0x1f800000: *out = (u8)psxHwRead8(mem); return 0; + case 0x12000000: *out = (u8)gsRead8(mem); return 0; + case 0x14000000: + *out = (u8)DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u8*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16(u32 mem, u16 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead16(mem); return 0; + case 0x1f800000: *out = psxHwRead16(mem); return 0; + case 0x12000000: *out = gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = SPU2read(mem); return 0; + break; + case 0x14000000: + *out = DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u16*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16RS(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (s16)hwRead16(mem); return 0; + case 0x1f800000: *out = (s16)psxHwRead16(mem); return 0; + case 0x12000000: *out = (s16)gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = (s16)ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = (s16)SPU2read(mem); return 0; + break; + case 0x14000000: + *out = (s16)DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(s16*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16RU(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (u16)hwRead16(mem ); return 0; + case 0x1f800000: *out = (u16)psxHwRead16(mem ); return 0; + case 0x12000000: *out = (u16)gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = (u16)ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = (u16)SPU2read(mem ); return 0; + break; + case 0x14000000: + *out = (u16)DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u16*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32(u32 mem, u32 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead32(mem); return 0; + case 0x1f800000: *out = psxHwRead32(mem); return 0; + case 0x12000000: *out = gsRead32(mem); return 0; + case 0x14000000: + *out = (u32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u32*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32RS(u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (s32)hwRead32(mem); return 0; + case 0x1f800000: *out = (s32)psxHwRead32(mem); return 0; + case 0x12000000: *out = (s32)gsRead32(mem); return 0; + case 0x14000000: + *out = (s32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(s32*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32RU(u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (u32)hwRead32(mem); return 0; + case 0x1f800000: *out = (u32)psxHwRead32(mem); return 0; + case 0x12000000: *out = (u32)gsRead32(mem); return 0; + case 0x14000000: + *out = (u32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u32*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead64(u32 mem, u64 *out) { + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead64(mem); return 0; + case 0x12000000: *out = gsRead64(mem); return 0; + + default: + *out = *(u64*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead128(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: + hwRead128(mem, out); + return 0; + case 0x12000000: + out[0] = gsRead64(mem); + out[1] = gsRead64(mem + 8); + return 0; + + default: + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +void memWrite8 (u32 mem, u8 value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: psxHw4Write8(mem, value); return; + case 0x10000000: hwWrite8(mem, value); return; + case 0x1f800000: psxHwWrite8(mem, value); return; + case 0x12000000: gsWrite8(mem, value); return; + case 0x14000000: + DEV9write8(mem & ~0x04000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); + return; + + default: + *(u8*)(PS2MEM_BASE+mem) = value; + + if (CHECK_EEREC) { + REC_CLEARM(mem&~3); + } + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite16(u32 mem, u16 value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite16(mem, value); return; + case 0x1f800000: psxHwWrite16(mem, value); return; + case 0x12000000: gsWrite16(mem, value); return; + case 0x1f900000: + case 0x1f000000: SPU2write(mem, value); return; + case 0x14000000: + DEV9write16(mem & ~0x04000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); + return; + + default: + *(u16*)(PS2MEM_BASE+mem) = value; + if (CHECK_EEREC) { + REC_CLEARM(mem&~3); + } + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite32(u32 mem, u32 value) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite32(mem, value); return; + case 0x1f800000: psxHwWrite32(mem, value); return; + case 0x12000000: gsWrite32(mem, value); return; + case 0x1f900000: + case 0x1f000000: SPU2write(mem, value); return; + case 0x14000000: + DEV9write32(mem & ~0x4000000, value); + SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0x4000000, value); + return; + + default: + *(u32*)(PS2MEM_BASE+mem) = value; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + } + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite64(u32 mem, u64 value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite64(mem, value); return; + case 0x12000000: gsWrite64(mem, value); return; + + default: + *(u64*)(PS2MEM_BASE+mem) = value; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + REC_CLEARM(mem+4); + } + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)(value>>32), (u32)value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite128(u32 mem, u64 *value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite128(mem, value); return; + case 0x12000000: + gsWrite64(mem, value[0]); + gsWrite64(mem + 8, value[1]); + return; + + default: + *(u64*)(PS2MEM_BASE+mem) = value[0]; + *(u64*)(PS2MEM_BASE+mem+8) = value[1]; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + REC_CLEARM(mem+4); + REC_CLEARM(mem+8); + REC_CLEARM(mem+12); + } + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +#else + +u8 *psM; //32mb Main Ram +u8 *psR; //4mb rom area +u8 *psR1; //256kb rom1 area (actually 196kb, but can't mask this) +u8 *psR2; // 0x00080000 +u8 *psER; // 0x001C0000 +u8 *psS; //0.015 mb, scratch pad + +uptr *memLUTR; +uptr *memLUTW; +uptr *memLUTRK; +uptr *memLUTWK; +uptr *memLUTRU; +uptr *memLUTWU; + +#define CHECK_MEM(mem) //MyMemCheck(mem) + +void MyMemCheck(u32 mem) +{ + if( mem == 0x1c02f2a0 ) + SysPrintf("yo\n"); +} + +///////////////////////////// +// REGULAR MEM START +///////////////////////////// + +void memMapMem(u32 base) { + int i; + + for (i=0; i<0x02000; i++) memLUTRK[i + 0x00000 + base] = (uptr)&psM[i << 12]; + for (i=0; i<0x00400; i++) memLUTRK[i + 0x1fc00 + base] = (uptr)&psR[i << 12]; + for (i=0; i<0x00040; i++) memLUTRK[i + 0x1e000 + base] = (uptr)&psR1[i << 12]; + for (i=0; i<0x00080; i++) memLUTRK[i + 0x1e400 + base] = (uptr)&psR2[i << 12]; + for (i=0; i<0x001C0; i++) memLUTRK[i + 0x1e040 + base] = (uptr)&psER[i << 12]; + for (i=0; i<0x00800; i++) memLUTRK[i + 0x1c000 + base] = (uptr)&psxM[(i & 0x1ff) << 12]; + for (i=0; i<0x00004; i++) memLUTRK[i + 0x11000 + base] = (uptr)VU0.Micro; + for (i=0; i<0x00004; i++) memLUTRK[i + 0x11004 + base] = (uptr)VU0.Mem; + for (i=0; i<0x00004; i++) memLUTRK[i + 0x11008 + base] = (uptr)&VU1.Micro[i << 12]; + for (i=0; i<0x00004; i++) memLUTRK[i + 0x1100c + base] = (uptr)&VU1.Mem[i << 12]; + + for (i=0; i<0x02000; i++) memLUTWK[i + 0x00000 + base] = (uptr)&psM[i << 12]; + for (i=0; i<0x00400; i++) memLUTWK[i + 0x1fc00 + base] = (uptr)&psR[i << 12]; + for (i=0; i<0x00040; i++) memLUTWK[i + 0x1e000 + base] = (uptr)&psR1[i << 12]; + for (i=0; i<0x00080; i++) memLUTWK[i + 0x1e400 + base] = (uptr)&psR2[i << 12]; + for (i=0; i<0x001C0; i++) memLUTWK[i + 0x1e040 + base] = (uptr)&psER[i << 12]; + for (i=0; i<0x00800; i++) memLUTWK[i + 0x1c000 + base] = (uptr)&psxM[(i & 0x1ff) << 12]; + for (i=0; i<0x00004; i++) memLUTWK[i + 0x11000 + base] = (uptr)VU0.Micro; + for (i=0; i<0x00004; i++) memLUTWK[i + 0x11004 + base] = (uptr)VU0.Mem; + for (i=0; i<0x00004; i++) memLUTWK[i + 0x11008 + base] = (uptr)&VU1.Micro[i << 12]; + for (i=0; i<0x00004; i++) memLUTWK[i + 0x1100c + base] = (uptr)&VU1.Mem[i << 12]; + + assert( ((uptr)VU0.Mem&15)==0 && ((uptr)VU0.Micro&15)==0); + for (i=0; i<0x00010; i++) memLUTRK[i + 0x10000 + base] = 1; // hwm + for (i=0; i<0x00010; i++) memLUTRK[i + 0x1f800 + base] = 2; // psh + for (i=0; i<0x00010; i++) memLUTRK[i + 0x1f400 + base] = 3; // psh4 + for (i=0; i<0x00010; i++) memLUTRK[i + 0x18000 + base] = 4; // b80 + for (i=0; i<0x00010; i++) memLUTRK[i + 0x1a000 + base] = 5; // ba0 + for (i=0; i<0x00010; i++) memLUTRK[i + 0x12000 + base] = 6; // gsm + for (i=0; i<0x00010; i++) memLUTRK[i + 0x14000 + base] = 7; // dev9 + for (i=0; i<0x00010; i++) memLUTRK[i + 0x1f900 + base] = 8; // spu2 + for (i=0; i<0x00010; i++) memLUTRK[i + 0x1f000 + base] = 8; // spu2 (not sure) + + for (i=0; i<0x00010; i++) memLUTWK[i + 0x10000 + base] = 1; // hwm + for (i=0; i<0x00010; i++) memLUTWK[i + 0x1f800 + base] = 2; // psh + for (i=0; i<0x00010; i++) memLUTWK[i + 0x1f400 + base] = 3; // psh4 + for (i=0; i<0x00010; i++) memLUTWK[i + 0x1a000 + base] = 5; // ba0 + for (i=0; i<0x00010; i++) memLUTWK[i + 0x12000 + base] = 6; // gsm + for (i=0; i<0x00010; i++) memLUTWK[i + 0x14000 + base] = 7; // dev9 + for (i=0; i<0x00010; i++) memLUTWK[i + 0x1f900 + base] = 8; // spu2 + for (i=0; i<0x00010; i++) memLUTWK[i + 0x1f000 + base] = 8; // spu2 (not sure) +} + +void memMapKernelMem() { + memMapMem(0xa0000); + memMapMem(0x80000); + memMapMem(0x00000); +} + +void memMapSupervisorMem() { +} + +void memMapUserMem() { +} + +int memInit() { + int i; + + psR = (u8*)_aligned_malloc(0x00400010, 16); + psR1 = (u8*)_aligned_malloc(0x00080010, 16); + psR2 = (u8*)_aligned_malloc(0x00080010, 16); + + if (psxInit() == -1) + return -1; + + memLUTRK = (uptr*)_aligned_malloc(0x100000 * sizeof(uptr), 16); + memLUTWK = (uptr*)_aligned_malloc(0x100000 * sizeof(uptr), 16); + memLUTRU = (uptr*)_aligned_malloc(0x100000 * sizeof(uptr), 16); + memLUTWU = (uptr*)_aligned_malloc(0x100000 * sizeof(uptr), 16); + + psM = (u8*)_aligned_malloc(0x02000010, 16); + psER = (u8*)_aligned_malloc(0x001C0010, 16); + psS = (u8*)_aligned_malloc(0x00004010, 16); + if (memLUTRK == NULL || memLUTWK == NULL || + memLUTRU == NULL || memLUTWU == NULL || + psM == NULL || psR == NULL || psR1 == NULL || + psR2 == NULL || psER == NULL || psS == NULL) { + SysMessage(_("Error allocating memory")); return -1; + } + + memset(memLUTRK, 0, 0x100000 * 4); + memset(memLUTWK, 0, 0x100000 * 4); + memset(memLUTRU, 0, 0x100000 * 4); + memset(memLUTWU, 0, 0x100000 * 4); + + memset(psM, 0, 0x02000010); + memset(psR, 0, 0x00400010); + memset(psR1, 0, 0x00080010); + memset(psR2, 0, 0x00080010); + memset(psER, 0, 0x001C0010); + memset(psS, 0, 0x00004010); + + for (i=0x00000; i<0x00004; i++) memLUTRK[i + 0x70000] = (uptr)&psS[i << 12]; + for (i=0x00000; i<0x00004; i++) memLUTWK[i + 0x70000] = (uptr)&psS[i << 12]; + + for (i=0x00000; i<0x00004; i++) memLUTRU[i + 0x70000] = (uptr)&psS[i << 12]; + for (i=0x00000; i<0x00004; i++) memLUTWU[i + 0x70000] = (uptr)&psS[i << 12]; + + + memMapKernelMem(); + memMapSupervisorMem(); + memMapUserMem(); + + memSetKernelMode(); + +#ifdef ENABLECACHE + memset(pCache,0,sizeof(_cacheS)*64); +#endif + + return 0; +} + +void memShutdown() { + FREE(psM); + FREE(psR); + FREE(psR1); + FREE(psR2); + FREE(psER); + FREE(psS); + FREE(memLUTRK); + FREE(memLUTWK); + FREE(memLUTRU); + FREE(memLUTWU); +} + +void memSetPageAddr(u32 vaddr, u32 paddr) { +// SysPrintf("memSetPageAddr: %8.8x -> %8.8x\n", vaddr, paddr); + + memLUTRU[vaddr >> 12] = memLUTRK[paddr >> 12]; + memLUTWU[vaddr >> 12] = memLUTWK[paddr >> 12]; + + memLUTRK[vaddr >> 12] = memLUTRK[paddr >> 12]; + memLUTWK[vaddr >> 12] = memLUTWK[paddr >> 12]; +} + +void memClearPageAddr(u32 vaddr) { +// SysPrintf("memClearPageAddr: %8.8x\n", vaddr); + + if ((vaddr & 0xffffc000) == 0x70000000) return; + memLUTRU[vaddr >> 12] = 0; + memLUTWU[vaddr >> 12] = 0; + +#ifdef FULLTLB + memLUTRK[vaddr >> 12] = 0; + memLUTWK[vaddr >> 12] = 0; +#endif +} + +int memRead8 (u32 mem, u8 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + u8 *tmp = readCache(mem); + *out = *(u8 *)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u8 *)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = hwRead8(mem & ~0xa0000000); return 0; + case 2: // psh + *out = psxHwRead8(mem & ~0xa0000000); return 0; + case 3: // psh4 + *out = psxHw4Read8(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = gsRead8(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = DEV9read8(mem & ~0xa4000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead8RS (u32 mem, u64 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(s8 *)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(s8 *)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (s8)hwRead8(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (s8)psxHwRead8(mem & ~0xa0000000); return 0; + case 3: // psh4 + *out = (s8)psxHw4Read8(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = (s8)gsRead8(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (s8)DEV9read8(mem & ~0xa4000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead8RU (u32 mem, u64 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(u8 *)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u8 *)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (u8)hwRead8(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (u8)psxHwRead8(mem & ~0xa0000000); return 0; + case 3: // psh4 + *out = (u8)psxHw4Read8(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = (u8)gsRead8(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (u8)DEV9read8(mem & ~0xa4000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16(u32 mem, u16 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + u8 *tmp = readCache(mem); + *out = *(u16 *)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u16*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = hwRead16(mem & ~0xa0000000); return 0; + case 2: // psh + *out = psxHwRead16(mem & ~0xa0000000); return 0; + case 4: // b80 +#ifdef MEM_LOG + MEM_LOG("b800000 Memory read16 address %x\n", mem); +#endif + *out = 0; return 0; + case 5: // ba0 + *out = ba0R16(mem); return 0; + case 6: // gsm + *out = gsRead16(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = DEV9read16(mem & ~0xa4000000); + SysPrintf("DEV9 read16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, *out); + return 0; + case 8: // spu2 + *out = SPU2read(mem & ~0xa0000000); return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16RS(u32 mem, u64 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(s16*)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(s16*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (s16)hwRead16(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (s16)psxHwRead16(mem & ~0xa0000000); return 0; + case 4: // b80 +#ifdef MEM_LOG + MEM_LOG("b800000 Memory read16 address %x\n", mem); +#endif + *out = 0; return 0; + case 5: // ba0 + *out = (s16)ba0R16(mem); return 0; + case 6: // gsm + *out = (s16)gsRead16(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (s16)DEV9read16(mem & ~0xa4000000); + SysPrintf("DEV9 read16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, *out); + return 0; + case 8: // spu2 + *out = (s16)SPU2read(mem & ~0xa0000000); return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead16RU(u32 mem, u64 *out) { + char *p; + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(u16*)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u16*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (u16)hwRead16(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (u16)psxHwRead16(mem & ~0xa0000000); return 0; + case 4: // b80 +#ifdef MEM_LOG + MEM_LOG("b800000 Memory read16 address %x\n", mem); +#endif + *out = 0; return 0; + case 5: // ba0 + *out = (u16)ba0R16(mem); return 0; + case 6: // gsm + *out = (u16)gsRead16(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (u16)DEV9read16(mem & ~0xa4000000); + SysPrintf("DEV9 read16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, *out); + return 0; + case 8: // spu2 + *out = (u16)SPU2read(mem & ~0xa0000000); return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32(u32 mem, u32 *out) { + char *p; + + CHECK_MEM(mem); + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + u8 *tmp = readCache(mem); + *out = *(u32 *)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u32*)(p + (mem & 0xfff)); + return 0; + } + assert( (int)(uptr)p < 8 ); + + switch ((int)(uptr)p) { + case 1: // hwm + *out = hwRead32(mem & ~0xa0000000); return 0; + case 2: // psh + *out = psxHwRead32(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = gsRead32(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = DEV9read32(mem & ~0xa4000000); + SysPrintf("DEV9 read32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32RS(u32 mem, u64 *out) { + char *p; + + CHECK_MEM(mem); + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(s32*)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(s32*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (s32)hwRead32(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (s32)psxHwRead32(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = (s32)gsRead32(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (s32)DEV9read32(mem & ~0xa4000000); + SysPrintf("DEV9 read32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead32RU(u32 mem, u64 *out) { + char *p; + + CHECK_MEM(mem); + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + char *tmp = (char*)readCache(mem); + *out = *(u32*)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u32*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = (u32)hwRead32(mem & ~0xa0000000); return 0; + case 2: // psh + *out = (u32)psxHwRead32(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = (u32)gsRead32(mem & ~0xa0000000); return 0; + case 7: // dev9 + *out = (u32)DEV9read32(mem & ~0xa4000000); + SysPrintf("DEV9 read32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, *out); + return 0; + } + +#ifdef PCSX2_DEVBUILD + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead64(u32 mem, u64 *out) { + char *p; + + CHECK_MEM(mem); + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + u8 *tmp = readCache(mem); + *out = *(u64*)(tmp+(mem&0xf)); + return 0; + } +#endif + *out = *(u64*)(p + (mem & 0xfff)); + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + *out = hwRead64(mem & ~0xa0000000); return 0; + case 6: // gsm + *out = gsRead64(mem & ~0xa0000000); return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read64 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int memRead128(u32 mem, u64 *out) { + char *p; + + CHECK_MEM(mem); + + p = (char *)(memLUTR[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && + (cpuRegs.CP0.r[16] & 0x10000) && !(cpuRegs.CP0.n.Status.val & 0x4)) { + u64 *tmp = (u64*)readCache(mem); + out[0] = tmp[0]; + out[1] = tmp[1]; + return 0; + } +#endif + p+= mem & 0xfff; + out[0] = ((u64*)p)[0]; + out[1] = ((u64*)p)[1]; + return 0; + } + + switch ((int)(uptr)p) { + case 1: // hwm + hwRead128(mem & ~0xa0000000, out); return 0; + case 6: // gsm + out[0] = gsRead64((mem ) & ~0xa0000000); + out[1] = gsRead64((mem+8) & ~0xa0000000); return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read128 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +#define CHECK_VUMEM(size) { \ + if( mem >= 0x11000000 && mem < 0x11004000 ) \ + Cpu->ClearVU0(mem&0x3ff8, size); \ + else if( mem >= 0x11008000 && mem < 0x1100c000 ) \ + Cpu->ClearVU1(mem&0x3ff8, size); \ +} + +void memWrite8 (u32 mem, u8 value) { + char *p; + + p = (char *)(memLUTW[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && (cpuRegs.CP0.r[16] & 0x10000)) { + writeCache8(mem, value); + return; + } +#endif + + *(u8 *)(p + (mem & 0xfff)) = value; + if (CHECK_EEREC) { + CHECK_VUMEM(1); + REC_CLEARM(mem&(~3)); +// PSXREC_CLEARM(mem & 0x1ffffc); + } + return; + } + + switch ((int)(uptr)p) { + case 1: // hwm + hwWrite8(mem & ~0xa0000000, value); + return; + case 2: // psh + psxHwWrite8(mem & ~0xa0000000, value); return; + case 3: // psh4 + psxHw4Write8(mem & ~0xa0000000, value); return; + case 6: // gsm + gsWrite8(mem & ~0xa0000000, value); return; + case 7: // dev9 + DEV9write8(mem & ~0xa4000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, value); + return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite16(u32 mem, u16 value) { + char *p; + + p = (char *)(memLUTW[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && (cpuRegs.CP0.r[16] & 0x10000)) { + writeCache16(mem, value); + return; + } +#endif + *(u16*)(p + (mem & 0xfff)) = value; + if (CHECK_EEREC) { + CHECK_VUMEM(1); + REC_CLEARM(mem&~1); + //PSXREC_CLEARM(mem & 0x1ffffe); + } + return; + } + + switch ((int)(uptr)p) { + case 1: // hwm + hwWrite16(mem & ~0xa0000000, value); + return; + case 2: // psh + psxHwWrite16(mem & ~0xa0000000, value); return; + case 5: // ba0 +#ifdef MEM_LOG + MEM_LOG("ba00000 Memory write16 to address %x with data %x\n", mem, value); +#endif + return; + case 6: // gsm + gsWrite16(mem & ~0xa0000000, value); return; + case 7: // dev9 + DEV9write16(mem & ~0xa4000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, value); + return; + case 8: // spu2 + SPU2write(mem & ~0xa0000000, value); return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite32(u32 mem, u32 value) +{ + char *p; + p = (char *)(memLUTW[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && (cpuRegs.CP0.r[16] & 0x10000)) + { + writeCache32(mem, value); + return; + } +#endif + *(u32*)(p + (mem & 0xfff)) = value; + if (CHECK_EEREC) { + CHECK_VUMEM(1); + REC_CLEARM(mem); +// PSXREC_CLEARM(mem & 0x1fffff); + } + return; + } + + switch ((int)(uptr)p) { + case 1: // hwm + hwWrite32(mem & ~0xa0000000, value); + return; + case 2: // psh + psxHwWrite32(mem & ~0xa0000000, value); return; + case 6: // gsm + gsWrite32(mem & ~0xa0000000, value); return; + case 7: // dev9 + DEV9write32(mem & ~0xa4000000, value); + SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, value); + return; + } +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite64(u32 mem, u64 value) { + char *p; + + p = (char *)(memLUTW[mem >> 12]); + if ((uptr)p > 0x10) { + #ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && (cpuRegs.CP0.r[16] & 0x10000)) { + writeCache64(mem, value); + return; + } + #endif + /* __asm __volatile ( + "movq %1, %%mm0\n" + "movq %%mm0, %0\n" + "emms\n" + : "=m"(*(u64*)(p + (mem & 0xfff))) : "m"(value) + );*/ + *(u64*)(p + (mem & 0xfff)) = value; + if (CHECK_EEREC) { + CHECK_VUMEM(2); + REC_CLEARM(mem); + REC_CLEARM(mem+4); + } + return; + } + + + switch ((int)(uptr)p) { + case 1: // hwm + hwWrite64(mem & ~0xa0000000, value); + return; + case 6: // gsm + gsWrite64(mem & ~0xa0000000, value); return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)(value>>32), (u32)value); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + +void memWrite128(u32 mem, u64 *value) { + char *p; + + p = (char *)(memLUTW[mem >> 12]); + if ((uptr)p > 0x10) { +#ifdef ENABLECACHE + if ((mem & 0x20000000) == 0 && (cpuRegs.CP0.r[16] & 0x10000)) { + writeCache128(mem, value); + return; + } +#endif + p+= mem & 0xfff; + ((u64*)p)[0] = value[0]; + ((u64*)p)[1] = value[1]; + if (CHECK_EEREC) { + CHECK_VUMEM(4); + REC_CLEARM(mem); + REC_CLEARM(mem+4); + REC_CLEARM(mem+8); + REC_CLEARM(mem+12); + +/* PSXREC_CLEARM((mem) & 0x1fffff); + PSXREC_CLEARM((mem+4) & 0x1fffff); + PSXREC_CLEARM((mem+8) & 0x1fffff); + PSXREC_CLEARM((mem+12) & 0x1fffff);*/ + } + return; + } + + switch ((int)(uptr)p) { + case 1: // hwm + hwWrite128(mem & ~0xa0000000, value); + return; + case 6: // gsm + mem &= ~0xa0000000; + gsWrite64(mem, value[0]); + gsWrite64(mem+8, value[1]); return; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); +#endif + cpuTlbMissW(mem, cpuRegs.branch); +} + + +#endif // PCSX2_VIRTUAL_MEM + +void loadBiosRom(char *ext, u8 *dest) { + struct stat buf; + char Bios1[256]; + char Bios[256]; + FILE *fp; + char *ptr; + int i; + + strcpy(Bios, Config.BiosDir); + strcat(Bios, Config.Bios); + + sprintf(Bios1, "%s.%s", Bios, ext); + if (stat(Bios1, &buf) != -1) { + fp = fopen(Bios1, "rb"); + fread(dest, 1, buf.st_size, fp); + fclose(fp); + return; + } + + sprintf(Bios1, "%s", Bios); + ptr = Bios1; i = strlen(Bios1); + while (i > 0) { if (ptr[i] == '.') break; i--; } + ptr[i+1] = 0; + strcat(Bios1, ext); + if (stat(Bios1, &buf) != -1) { + fp = fopen(Bios1, "rb"); + fread(dest, 1, buf.st_size, fp); + fclose(fp); + return; + } + + sprintf(Bios1, "%s%s.bin", Config.BiosDir, ext); + if (stat(Bios1, &buf) != -1) { + fp = fopen(Bios1, "rb"); + fread(dest, 1, buf.st_size, fp); + fclose(fp); + return; + } + SysPrintf("\n\n\n"); + SysPrintf("**************\n"); + SysPrintf("%s NOT FOUND\n", ext); + SysPrintf("**************\n\n\n"); +} + +void memReset() { + struct stat buf; + char Bios[256]; + FILE *fp; + +#ifdef PCSX2_VIRTUAL_MEM + DWORD OldProtect; + memset(PS2MEM_BASE, 0, 0x02000000); + memset(PS2MEM_SCRATCH, 0, 0x00004000); +#else + memset(psM, 0, 0x02000000); + memset(psS, 0, 0x00004000); +#endif + + strcpy(Bios, Config.BiosDir); + strcat(Bios, Config.Bios); + + if (stat(Bios, &buf) == -1) { + SysMessage(_("Unable to load bios: '%s', PCSX2 can't run without that"), Bios); + return; + } + +#ifdef PCSX2_VIRTUAL_MEM + +#ifdef _WIN32 + // make sure can write + VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READWRITE, &OldProtect); +#else + mprotect(PS2EMEM_ROM, 0x00400000, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_ROM1, 0x00400000, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_ROM2, 0x00800000, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_EROM, 0x001C0000, PROT_READ|PROT_WRITE); +#endif + +#endif + + fp = fopen(Bios, "rb"); + fread(PS2MEM_ROM, 1, buf.st_size, fp); + fclose(fp); + + BiosVersion = GetBiosVersion(); + SysPrintf("Bios Version %d.%d\n", BiosVersion >> 8, BiosVersion & 0xff); + + //injectIRX("host.irx"); //not fully tested; still buggy + + // reset memLUT + + loadBiosRom("rom1", PS2MEM_ROM1); + loadBiosRom("rom2", PS2MEM_ROM2); + loadBiosRom("erom", PS2MEM_EROM); + +#ifdef PCSX2_VIRTUAL_MEM + +#ifdef _WIN32 + VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READONLY, &OldProtect); +#else + mprotect(PS2EMEM_ROM, 0x00400000, PROT_READ); + mprotect(PS2EMEM_ROM1, 0x00400000, PROT_READ); + mprotect(PS2EMEM_ROM2, 0x00800000, PROT_READ); + mprotect(PS2EMEM_EROM, 0x001C0000, PROT_READ); +#endif + +#endif +} + +void memSetKernelMode() { +#ifndef PCSX2_VIRTUAL_MEM + memLUTR = memLUTRK; + memLUTW = memLUTWK; +#endif + MemMode = 0; +} + +void memSetSupervisorMode() { +} + +void memSetUserMode() { +#ifdef FULLTLB +#ifndef PCSX2_VIRTUAL_MEM + memLUTR = memLUTRU; + memLUTW = memLUTWU; +#endif + MemMode = 2; +#endif +} + + diff --git a/pcsx2/Memory.h b/pcsx2/Memory.h new file mode 100644 index 0000000000..684d86db74 --- /dev/null +++ b/pcsx2/Memory.h @@ -0,0 +1,267 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +////////// +// Rewritten by zerofrog to add os virtual memory +////////// + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +//#define ENABLECACHE + +#define PS2MEM_BASE_ 0x15000000 +#define PS2MEM_PSX_ (PS2MEM_BASE_+0x1c000000) + +#ifdef PCSX2_VIRTUAL_MEM + +#ifdef _WIN32 +typedef struct _PSMEMORYMAP +{ + uptr* aPFNs, *aVFNs; +} PSMEMORYMAP; +#endif + +#define TRANSFORM_ADDR(memaddr) ( ((u32)(memaddr)>=0x40000000) ? ((memaddr)&~0xa0000000) : (memaddr) ) + +//new memory model +#define PS2MEM_BASE ((u8*)PS2MEM_BASE_) +#define PS2MEM_HW ((u8*)((u32)PS2MEM_BASE+0x10000000)) +#define PS2MEM_ROM ((u8*)((u32)PS2MEM_BASE+0x1fc00000)) +#define PS2MEM_ROM1 ((u8*)((u32)PS2MEM_BASE+0x1e000000)) +#define PS2MEM_ROM2 ((u8*)((u32)PS2MEM_BASE+0x1e400000)) +#define PS2MEM_EROM ((u8*)((u32)PS2MEM_BASE+0x1e040000)) +#define PS2MEM_PSX ((u8*)PS2MEM_PSX_) +#define PS2MEM_SCRATCH ((u8*)((u32)PS2MEM_BASE+0x50000000)) +#define PS2MEM_VU0MICRO ((u8*)((u32)PS2MEM_BASE+0x11000000)) +#define PS2MEM_VU0MEM ((u8*)((u32)PS2MEM_BASE+0x11004000)) +#define PS2MEM_VU1MICRO ((u8*)((u32)PS2MEM_BASE+0x11008000)) +#define PS2MEM_VU1MEM ((u8*)((u32)PS2MEM_BASE+0x1100c000)) + +// function for mapping memory +#define PS2MEM_PSXHW ((u8*)((u32)PS2MEM_BASE+0x1f800000)) +#define PS2MEM_PSXHW4 ((u8*)((u32)PS2MEM_BASE+0x1f400000)) +#define PS2MEM_GS ((u8*)((u32)PS2MEM_BASE+0x12000000)) +#define PS2MEM_DEV9 ((u8*)((u32)PS2MEM_BASE+0x14000000)) +#define PS2MEM_SPU2 ((u8*)((u32)PS2MEM_BASE+0x1f900000)) +#define PS2MEM_SPU2_ ((u8*)((u32)PS2MEM_BASE+0x1f000000)) // ? +#define PS2MEM_B80 ((u8*)((u32)PS2MEM_BASE+0x18000000)) +#define PS2MEM_BA0 ((u8*)((u32)PS2MEM_BASE+0x1a000000)) + +#define PSM(mem) (PS2MEM_BASE + TRANSFORM_ADDR(mem)) + +#else + +extern u8 *psM; //32mb Main Ram +extern u8 *psR; //4mb rom area +extern u8 *psR1; //256kb rom1 area (actually 196kb, but can't mask this) +extern u8 *psR2; // 0x00080000 +extern u8 *psER; // 0x001C0000 +extern u8 *psS; //0.015 mb, scratch pad + +#define PS2MEM_BASE psM +#define PS2MEM_HW psH +#define PS2MEM_ROM psR +#define PS2MEM_ROM1 psR1 +#define PS2MEM_ROM2 psR2 +#define PS2MEM_EROM psER +#define PS2MEM_SCRATCH psS + +extern u8 g_RealGSMem[0x2000]; +#define PS2MEM_GS g_RealGSMem + +//#define _PSM(mem) (memLUTR[(mem) >> 12] == 0 ? NULL : (void*)(memLUTR[(mem) >> 12] + ((mem) & 0xfff))) +#define PSM(mem) ((void*)(memLUTR[(mem) >> 12] + ((mem) & 0xfff))) +#define FREE(ptr) _aligned_free(ptr) + +extern uptr *memLUTR; +extern uptr *memLUTW; +extern uptr *memLUTRK; +extern uptr *memLUTWK; +extern uptr *memLUTRU; +extern uptr *memLUTWU; + +#endif + +#define psMs8(mem) (*(s8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs16(mem) (*(s16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs32(mem) (*(s32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs64(mem) (*(s64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu8(mem) (*(u8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu16(mem) (*(u16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu32(mem) (*(u32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu64(mem) (*(u64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) + +#define psRs8(mem) (*(s8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs16(mem) (*(s16*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs32(mem) (*(s32*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs64(mem) (*(s64*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu8(mem) (*(u8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu16(mem) (*(u16*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu32(mem) (*(u32*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu64(mem) (*(u64*)&PS2MEM_ROM[(mem) & 0x3fffff]) + +#define psR1s8(mem) (*(s8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s16(mem) (*(s16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s32(mem) (*(s32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s64(mem) (*(s64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u8(mem) (*(u8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u16(mem) (*(u16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u32(mem) (*(u32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u64(mem) (*(u64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) + +#define psR2s8(mem) (*(s8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s16(mem) (*(s16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s32(mem) (*(s32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s64(mem) (*(s64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u8(mem) (*(u8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u16(mem) (*(u16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u32(mem) (*(u32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u64(mem) (*(u64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) + +#define psERs8(mem) (*(s8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs16(mem) (*(s16*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs32(mem) (*(s32*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs64(mem) (*(s64*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu8(mem) (*(u8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu16(mem) (*(u16*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu32(mem) (*(u32*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu64(mem) (*(u64*)&PS2MEM_EROM[(mem) & 0x3ffff]) + +#define psSs8(mem) (*(s8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs16(mem) (*(s16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs32(mem) (*(s32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs64(mem) (*(s64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu8(mem) (*(u8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu16(mem) (*(u16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu32(mem) (*(u32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu64(mem) (*(u64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) + +#define PSMs8(mem) (*(s8 *)PSM(mem)) +#define PSMs16(mem) (*(s16*)PSM(mem)) +#define PSMs32(mem) (*(s32*)PSM(mem)) +#define PSMs64(mem) (*(s64*)PSM(mem)) +#define PSMu8(mem) (*(u8 *)PSM(mem)) +#define PSMu16(mem) (*(u16*)PSM(mem)) +#define PSMu32(mem) (*(u32*)PSM(mem)) +#define PSMu64(mem) (*(u64*)PSM(mem)) + +int memInit(); +void memReset(); +void memSetKernelMode(); +void memSetSupervisorMode(); +void memSetUserMode(); +void memSetPageAddr(u32 vaddr, u32 paddr); +void memClearPageAddr(u32 vaddr); +void memShutdown(); + +int memRead8(u32 mem, u8 *out); +int memRead8RS(u32 mem, u64 *out); +int memRead8RU(u32 mem, u64 *out); +int memRead16(u32 mem, u16 *out); +int memRead16RS(u32 mem, u64 *out); +int memRead16RU(u32 mem, u64 *out); +int memRead32(u32 mem, u32 *out); +int memRead32RS(u32 mem, u64 *out); +int memRead32RU(u32 mem, u64 *out); +int memRead64(u32 mem, u64 *out); +int memRead128(u32 mem, u64 *out); +void memWrite8 (u32 mem, u8 value); +void memWrite16(u32 mem, u16 value); +void memWrite32(u32 mem, u32 value); +void memWrite64(u32 mem, u64 value); +void memWrite128(u32 mem, u64 *value); + +// recMemConstRead8, recMemConstRead16, recMemConstRead32 return 1 if a call was made, 0 otherwise +u8 recMemRead8(); +u16 recMemRead16(); +u32 recMemRead32(); +void recMemRead64(u64 *out); +void recMemRead128(u64 *out); + +// returns 1 if mem should be cleared +void recMemWrite8(); +void recMemWrite16(); +void recMemWrite32(); +void recMemWrite64(); +void recMemWrite128(); + +// VM only functions +#ifdef PCSX2_VIRTUAL_MEM + +void _eeReadConstMem8(int mmreg, u32 mem, int sign); +void _eeReadConstMem16(int mmreg, u32 mem, int sign); +void _eeReadConstMem32(int mmreg, u32 mem); +void _eeReadConstMem128(int mmreg, u32 mem); +void _eeWriteConstMem8(u32 mem, int mmreg); +void _eeWriteConstMem16(u32 mem, int mmreg); +void _eeWriteConstMem32(u32 mem, int mmreg); +void _eeWriteConstMem64(u32 mem, int mmreg); +void _eeWriteConstMem128(u32 mem, int mmreg); +void _eeMoveMMREGtoR(int to, int mmreg); + +// extra ops +void _eeWriteConstMem16OP(u32 mem, int mmreg, int op); +void _eeWriteConstMem32OP(u32 mem, int mmreg, int op); + +int recMemConstRead8(u32 x86reg, u32 mem, u32 sign); +int recMemConstRead16(u32 x86reg, u32 mem, u32 sign); +int recMemConstRead32(u32 x86reg, u32 mem); +void recMemConstRead64(u32 mem, int mmreg); +void recMemConstRead128(u32 mem, int xmmreg); + +int recMemConstWrite8(u32 mem, int mmreg); +int recMemConstWrite16(u32 mem, int mmreg); +int recMemConstWrite32(u32 mem, int mmreg); +int recMemConstWrite64(u32 mem, int mmreg); +int recMemConstWrite128(u32 mem, int xmmreg); + +extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); + +#else + +#define _eeReadConstMem8 0&& +#define _eeReadConstMem16 0&& +#define _eeReadConstMem32 0&& +#define _eeReadConstMem128 0&& +#define _eeWriteConstMem8 0&& +#define _eeWriteConstMem16 0&& +#define _eeWriteConstMem32 0&& +#define _eeWriteConstMem64 0&& +#define _eeWriteConstMem128 0&& +#define _eeMoveMMREGtoR 0&& + +// extra ops +#define _eeWriteConstMem16OP 0&& +#define _eeWriteConstMem32OP 0&& + +#define recMemConstRead8 0&& +#define recMemConstRead16 0&& +#define recMemConstRead32 0&& +#define recMemConstRead64 0&& +#define recMemConstRead128 0&& + +#define recMemConstWrite8 0&& +#define recMemConstWrite16 0&& +#define recMemConstWrite32 0&& +#define recMemConstWrite64 0&& +#define recMemConstWrite128 0&& + +#endif + +#endif diff --git a/pcsx2/Misc.c b/pcsx2/Misc.c new file mode 100644 index 0000000000..d0949ccbfa --- /dev/null +++ b/pcsx2/Misc.c @@ -0,0 +1,1153 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "Plugins.h" +#include "Common.h" +#include "PsxCommon.h" +#include "CDVDisodrv.h" +#include "VUmicro.h" +#ifdef _WIN32 +#include "RDebug/deci2.h" +#endif + +#include "VU.h" +#include "iCore.h" +#include "iVUzerorec.h" + +#include "GS.h" + +#include "Cache.h" + +#include "Paths.h" + +u32 dwSaveVersion = 0x7a300010; +u32 dwCurSaveStateVer = 0; +extern u32 s_iLastCOP0Cycle; +extern u32 s_iLastPERFCycle[2]; +extern int g_psxWriteOk; + +PcsxConfig Config; +u32 BiosVersion; +char CdromId[12]; +static int g_Pcsx2Recording = 0; // true 1 if recording video and sound + +char *LabelAuthors = { N_( + "PCSX2 a PS2 emulator\n\n" + "written by:\n" + "saqib, refraction, zerofrog,\n" + "shadow, linuzappz, florin,\n" + "nachbrenner, auMatt, loser, \n" + "alexey silinov, goldfinger,\n" + "\n" + "Webmasters: CKemu, Falcon4ever") +}; + +char *LabelGreets = { N_( + "Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785, Raziel\n" + "Special thanks to: Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" + "Seta-San, Skarmeth, blackd_wd, _Demo_\n" + "\n" + "Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n" + "\n" + "Some betatester/support dudes: Belmont, bositman, ChaosCode, CKemu, crushtest," + "falcon4ever, GeneralPlot, jegHegy, parotaku, Prafull, Razorblade, Rudy_X, Seta-san") +}; + +static struct { + char *name; + u32 size; +} ioprps[]={ + {"IOPRP14", 43845}, + {"IOPRP142", 48109}, + {"IOPRP143", 58317}, + {"IOPRP144", 58525}, + {"IOPRP15", 82741}, + {"IOPRP151", 82917}, + {"IOPRP153", 82949}, + {"IOPRP16", 91909}, + {"IOPRP165", 98901}, + {"IOPRP20", 109809}, + {"IOPRP202", 110993}, + {"IOPRP205", 119797}, + {"IOPRP21", 126857}, + {"IOPRP211", 129577}, + {"IOPRP213", 129577}, + {"IOPRP214", 140945}, + {"IOPRP22", 199257}, + {"IOPRP221", 196937}, + {"IOPRP222", 198233}, + {"IOPRP224", 201065}, + {"IOPRP23", 230329}, + {"IOPRP234", 247641}, + {"IOPRP24", 251065}, + {"IOPRP241", 251049}, + {"IOPRP242", 252409}, + {"IOPRP243", 253201}, + {"IOPRP250", 264897}, + {"IOPRP252", 265233}, + {"IOPRP253", 267217}, + {"IOPRP254", 264449}, + {"IOPRP255", 264449}, + {"IOPRP260", 248945}, + {"IOPRP270", 249121}, + {"IOPRP271", 266817}, + {"IOPRP280", 269889}, + {"IOPRP300", 275345}, + {"DNAS280", 272753}, + {"DNAS270", 251729}, + {"DNAS271", 268977}, + {"DNAS300", 278641}, + {"DNAS280", 272705}, + {"DNAS255", 264945}, + {NULL, 0} +}; + +void GetRPCVersion(char *ioprp, char *rpcver){ + char *p=ioprp; int i; + struct TocEntry te; + + if (p && (CDVD_findfile(p+strlen("cdromN:"), &te) != -1)){ + for (i=0; ioprps[i].size>0; i++) + if (te.fileSize==ioprps[i].size) + break; + if (ioprps[i].size>0) + p=ioprps[i].name; + } + if (p && (p=strstr(p, "IOPRP")+strlen("IOPRP"))){ + for (i=0;(i<4) && p && (*p>='0') && (*p<='9');i++, p++) rpcver[i]=*p; + for ( ; i<4 ;i++ ) rpcver[i]='0'; + } +} + +u32 GetBiosVersion() { + unsigned int fileOffset=0; + char *ROMVER; + char vermaj[8]; + char vermin[8]; + struct romdir *rd; + u32 version; + int i; + + for (i=0; i<512*1024; i++) { + rd = (struct romdir*)&psRu8(i); + if (strncmp(rd->fileName, "RESET", 5) == 0) + break; /* found romdir */ + } + if (i == 512*1024) return -1; + + while(strlen(rd->fileName) > 0){ + if (strcmp(rd->fileName, "ROMVER") == 0){ // found romver + ROMVER = &psRs8(fileOffset); + + strncpy(vermaj, ROMVER+ 0, 2); vermaj[2] = 0; + strncpy(vermin, ROMVER+ 2, 2); vermin[2] = 0; + version = strtol(vermaj, (char**)NULL, 0) << 8; + version|= strtol(vermin, (char**)NULL, 0); + + return version; + } + + if ((rd->fileSize % 0x10)==0) + fileOffset += rd->fileSize; + else + fileOffset += (rd->fileSize + 0x10) & 0xfffffff0; + + rd++; + } + + return -1; +} + +//2002-09-22 (Florin) +int IsBIOS(char *filename, char *description){ + struct stat buf; + char Bios[260], ROMVER[14+1], zone[12+1]; + FILE *fp; + unsigned int fileOffset=0, found=FALSE; + struct romdir rd; + + strcpy(Bios, Config.BiosDir); + strcat(Bios, filename); + + if (stat(Bios, &buf) == -1) return FALSE; + + fp = fopen(Bios, "rb"); + if (fp == NULL) return FALSE; + + while ((ftell(fp)<512*1024) && (fread(&rd, DIRENTRY_SIZE, 1, fp)==1)) + if (strcmp(rd.fileName, "RESET") == 0) + break; /* found romdir */ + + if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) { + fclose(fp); + return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img + } + + while(strlen(rd.fileName) > 0){ + if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver + unsigned int filepos=ftell(fp); + fseek(fp, fileOffset, SEEK_SET); + if (fread(&ROMVER, 14, 1, fp) == 0) break; + fseek(fp, filepos, SEEK_SET);//go back + + switch(ROMVER[4]){ + case 'T':sprintf(zone, "T10K "); break; + case 'X':sprintf(zone, "Test ");break; + case 'J':sprintf(zone, "Japan "); break; + case 'A':sprintf(zone, "USA "); break; + case 'E':sprintf(zone, "Europe"); break; + case 'H':sprintf(zone, "HK "); break; + case 'P':sprintf(zone, "Free "); break; + case 'C':sprintf(zone, "China "); break; + default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show + } + sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone, + ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":""); + strncpy(description+ 8, ROMVER+ 0, 2);//ver major + strncpy(description+11, ROMVER+ 2, 2);//ver minor + strncpy(description+14, ROMVER+12, 2);//day + strncpy(description+17, ROMVER+10, 2);//month + strncpy(description+20, ROMVER+ 6, 4);//year + found = TRUE; + } + + if ((rd.fileSize % 0x10)==0) + fileOffset += rd.fileSize; + else + fileOffset += (rd.fileSize + 0x10) & 0xfffffff0; + + if (fread(&rd, DIRENTRY_SIZE, 1, fp)==0) break; + } + fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; + + fclose(fp); + + if (found) { + char percent[6]; + + if (buf.st_size<(int)fileOffset){ + sprintf(percent, " %d%%", buf.st_size*100/(int)fileOffset); + strcat(description, percent);//we force users to have correct bioses, + //not that lame scph10000 of 513KB ;-) + } + return TRUE; + } + + return FALSE; //fail quietly +} + +// LOAD STUFF + +#define ISODCL(from, to) (to - from + 1) + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + char name [1]; +}; + +#define READTRACK(lsn) \ + if (CDVDreadTrack(lsn, CDVD_MODE_2352) == -1) return -1; \ + buf = CDVDgetBuffer(); if (buf == NULL) return -1; + +int LoadCdrom() { + return 0; +} + +int CheckCdrom() { + u8 *buf; + + READTRACK(16); + strncpy(CdromId, (char*)buf+52, 10); + + return 0; +} + +int GetPS2ElfName(char *name){ + FILE *fp; + int f; + char buffer[256];//if a file is longer...it should be shorter :D + char *pos; + static struct TocEntry tocEntry; + int i; + + CDVDFS_init(); + + // check if the file exists + if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ + SysPrintf("SYSTEM.CNF not found\n"); + return 0;//could not find; not a PS/PS2 cdvd + } + + f=CDVDFS_open("SYSTEM.CNF;1", 1); + CDVDFS_read(f, buffer, 256); + CDVDFS_close(f); + + buffer[tocEntry.fileSize]='\0'; + +// SysPrintf( +// "---------------------SYSTEM.CNF---------------------\n" +// "%s" +// "----------------------------------------------------\n", buffer); + pos=strstr(buffer, "BOOT2"); + if (pos==NULL){ + pos=strstr(buffer, "BOOT"); + if (pos==NULL) { + SysPrintf("This is not a PS2 game!\n"); + return 0; + } + return 1; + } + pos+=strlen("BOOT2"); + while (pos && *pos && pos<=&buffer[255] + && (*pos<'A' || (*pos>'Z' && *pos<'a') || *pos>'z')) + pos++; + if (!pos || *pos==0) + return 0; + + sscanf(pos, "%s", name); + //SysPrintf("ELF name: '%s'\n", name); + + if (strncmp("cdrom0:\\", name, 8) == 0) { + strncpy(CdromId, name+8, 11); CdromId[11] = 0; + } + +// inifile_read(CdromId); + + fp = fopen("System.map", "r"); + if (fp) { + u32 addr; + + SysPrintf("Loading System.map\n", fp); + while (!feof(fp)) { + fseek(fp, 8, SEEK_CUR); + buffer[0] = '0'; buffer[1] = 'x'; + for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0; + addr = strtoul(buffer, (char**)NULL, 0); + fseek(fp, 3, SEEK_CUR); + for (i=0; i<256; i++) { + buffer[i] = fgetc(fp); + if (buffer[i] == '\n' || buffer[i] == 0) break; + } + if (buffer[i] == 0) break; + buffer[i] = 0; + + disR5900AddSym(addr, buffer); + } + fclose(fp); + } + + return 2; +} + +/*#define PSX_EXE 1 +#define CPE_EXE 2 +#define COFF_EXE 3 +#define INVALID_EXE 4 + +static int PSXGetFileType(FILE *f) { + unsigned long current; + unsigned long mybuf[2048]; + EXE_HEADER *exe_hdr; + FILHDR *coff_hdr; + + current = ftell(f); + fseek(f,0L,SEEK_SET); + fread(mybuf,2048,1,f); + fseek(f,current,SEEK_SET); + + exe_hdr = (EXE_HEADER *)mybuf; + if (memcmp(exe_hdr->id,"PS-X EXE",8)==0) + return PSX_EXE; + + if (mybuf[0]=='C' && mybuf[1]=='P' && mybuf[2]=='E') + return CPE_EXE; + + coff_hdr = (FILHDR *)mybuf; + if (coff_hdr->f_magic == 0x0162) + return COFF_EXE; + + return INVALID_EXE; +} + +int Load(char *ExePath) { + FILE *tmpFile; + EXE_HEADER tmpHead; + int type; + + strcpy(CdromId, "SLUS_999.99"); + + tmpFile = fopen(ExePath,"rb"); + if (tmpFile == NULL) { SysMessage("Error opening file: %s", ExePath); return 0; } + + type = PSXGetFileType(tmpFile); + switch (type) { + case PSX_EXE: + fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile); + fseek(tmpFile, 0x800, SEEK_SET); + fread((void *)PSXM(tmpHead.t_addr), tmpHead.t_size,1,tmpFile); + fclose(tmpFile); + psxRegs.pc = tmpHead.pc0; + psxRegs.GPR.n.gp = tmpHead.gp0; + psxRegs.GPR.n.sp = tmpHead.s_addr; + if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00; + break; + case CPE_EXE: + SysMessage("Pcsx found that you wanna use a CPE file. CPE files not support yet"); + break; + case COFF_EXE: + SysMessage("Pcsx found that you wanna use a COFF file.COFF files not support yet"); + break; + case INVALID_EXE: + SysMessage("This file is not a psx file"); + break; + } + return 1; +} +*/ + +FILE *emuLog; + +#ifdef PCSX2_DEVBUILD +int Log; +u32 varLog; +#endif + +u16 logProtocol; +u8 logSource; +int connected=0; + +#define SYNC_LOGGING + +void __Log(char *fmt, ...) { +#ifdef EMU_LOG + va_list list; + static char tmp[2024]; //hm, should be enough + + va_start(list, fmt); +#ifdef _WIN32 + if (connected && logProtocol>=0 && logProtocol<0x10){ + vsprintf(tmp, fmt, list); + sendTTYP(logProtocol, logSource, tmp); + }//else //!!!!! is disabled, so the text goes to ttyp AND log +#endif + { +#ifndef LOG_STDOUT + if (varLog & 0x80000000) { + vsprintf(tmp, fmt, list); + SysPrintf(tmp); + } else if( emuLog != NULL ) { + vfprintf(emuLog, fmt, list); + } +#else //i assume that this will not be used (Florin) + vsprintf(tmp, fmt, list); + SysPrintf(tmp); +#endif + } + va_end(list); +#endif +} + +// STATES + +#define STATE_VERSION "STv6" +const char Pcsx2Header[32] = STATE_VERSION " PCSX2 v" PCSX2_VERSION; + +#define _PS2Esave(type) \ + if (type##freeze(FREEZE_SIZE, &fP) == -1) { \ + gzclose(f); \ + return -1; \ + } \ + fP.data = (s8*)malloc(fP.size); \ + if (fP.data == NULL) return -1; \ + \ + if (type##freeze(FREEZE_SAVE, &fP) == -1) { \ + gzclose(f); \ + return -1; \ + } \ + \ + gzwrite(f, &fP.size, sizeof(fP.size)); \ + if (fP.size) { \ + gzwrite(f, fP.data, fP.size); \ + free(fP.data); \ + } + +#define _PS2Eload(type) \ + gzread(f, &fP.size, sizeof(fP.size)); \ + if (fP.size) { \ + fP.data = (s8*)malloc(fP.size); \ + if (fP.data == NULL) return -1; \ + gzread(f, fP.data, fP.size); \ + } \ + if (type##freeze(FREEZE_LOAD, &fP) == -1) { \ + /* skip */ \ + /*if (fP.size) free(fP.data); \ + gzclose(f); \ + return -1;*/ \ + } \ + if (fP.size) free(fP.data); + + +extern void gsWaitGS(); + +int SaveState(char *file) { + + gzFile f; + freezeData fP; + + gsWaitGS(); + + SysPrintf("SaveState: %s\n", file); + f = gzopen(file, "wb"); + if (f == NULL) return -1; + + gzwrite(f, &dwSaveVersion, 4); + + gzwrite(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory + gzwrite(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory + gzwrite(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory + gzwrite(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad + + gzwrite(f, PS2MEM_HW, 0x00010000); // hardware memory + + gzwrite(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0 + gzwrite(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs] + gzwrite(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs + gzwrite(f, (void*)&tlb, sizeof(tlb)); // tlbs + gzwrite(f, &EEsCycle, sizeof(EEsCycle)); + gzwrite(f, &EEoCycle, sizeof(EEoCycle)); + gzwrite(f, &IOPoCycle, sizeof(IOPoCycle)); + gzwrite(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle)); + gzwrite(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle)); + gzwrite(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle)); + gzwrite(f, s_iLastPERFCycle, sizeof(u32)*2); + gzwrite(f, &g_psxWriteOk, sizeof(g_psxWriteOk)); + + //gzwrite(f, (void*)&ipuRegs, sizeof(IPUregisters)); // ipu regs + //hope didn't forgot any cpu.... + + rcntFreeze(f, 1); + gsFreeze(f, 1); + vu0Freeze(f, 1); + vu1Freeze(f, 1); + vif0Freeze(f, 1); + vif1Freeze(f, 1); + sifFreeze(f, 1); + ipuFreeze(f, 1); + + // iop now + gzwrite(f, psxM, 0x00200000); // 2 MB main memory + //gzwrite(f, psxP, 0x00010000); // pralell memory + gzwrite(f, psxH, 0x00010000); // hardware memory + //gzwrite(f, psxS, 0x00010000); // sif memory + + sioFreeze(f, 1); + cdrFreeze(f, 1); + cdvdFreeze(f, 1); + psxRcntFreeze(f, 1); + //mdecFreeze(f, 1); + sio2Freeze(f, 1); + + SysPrintf("Saving GS\n"); + if( CHECK_MULTIGS ) { + // have to call in thread, otherwise weird stuff will start happening + uptr uf = (uptr)f; + GSRingBufSimplePacket(GS_RINGTYPE_SAVE, (int)(uf&0xffffffff), (int)(uf>>32), 0); + gsWaitGS(); + } + else { + _PS2Esave(GS); + } + SysPrintf("Saving SPU2\n"); + _PS2Esave(SPU2); + SysPrintf("Saving DEV9\n"); + _PS2Esave(DEV9); + SysPrintf("Saving USB\n"); + _PS2Esave(USB); + SysPrintf("Saving ok\n"); + + gzclose(f); + + return 0; +} + +extern u32 dumplog; +u32 s_vucount=0; + +int LoadState(char *file) { + + gzFile f; + freezeData fP; + int i; +#ifdef PCSX2_VIRTUAL_MEM + u32 OldProtect; +#endif + +#ifdef _DEBUG + s_vucount = 0; + //dumplog |= 2; +#endif + + SysPrintf("LoadState: %s\n", file); + f = gzopen(file, "rb"); + if (f == NULL) return -1; + + gzread(f, &dwCurSaveStateVer, 4); + + if( dwCurSaveStateVer != dwSaveVersion ) { + + // pcsx2 supports opening these formats + if( dwCurSaveStateVer != 0x7a30000d && dwCurSaveStateVer != 0x7a30000e && dwCurSaveStateVer != 0x7a30000f) { + gzclose(f); + SysPrintf("State to load is a different version from current.\n"); + return 0; + } + } + + // stop and reset the system first + gsWaitGS(); + + for (i=0; i<48; i++) ClearTLB(i); + + Cpu->Reset(); +#ifndef PCSX2_NORECBUILD + recResetVU0(); + recResetVU1(); +#endif + psxCpu->Reset(); + + SysPrintf("Loading memory\n"); + +#ifdef PCSX2_VIRTUAL_MEM + // make sure can write + VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READWRITE, &OldProtect); +#endif + + gzread(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory + gzread(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory + gzread(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory + gzread(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad + +#ifdef PCSX2_VIRTUAL_MEM + VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READONLY, &OldProtect); +#endif + + gzread(f, PS2MEM_HW, 0x00010000); // hardware memory + + SysPrintf("Loading structs\n"); + gzread(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0 + gzread(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs + gzread(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs + gzread(f, (void*)&tlb, sizeof(tlb)); // tlbs + gzread(f, &EEsCycle, sizeof(EEsCycle)); + gzread(f, &EEoCycle, sizeof(EEoCycle)); + gzread(f, &IOPoCycle, sizeof(IOPoCycle)); + gzread(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle)); + gzread(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle)); + gzread(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle)); + if( dwCurSaveStateVer >= 0x7a30000e ) { + gzread(f, s_iLastPERFCycle, sizeof(u32)*2); + } + gzread(f, &g_psxWriteOk, sizeof(g_psxWriteOk)); + + rcntFreeze(f, 0); + gsFreeze(f, 0); + vu0Freeze(f, 0); + vu1Freeze(f, 0); + vif0Freeze(f, 0); + vif1Freeze(f, 0); + sifFreeze(f, 0); + ipuFreeze(f, 0); + + // iop now + SysPrintf("Loading iop mem\n"); + gzread(f, psxM, 0x00200000); // 2 MB main memory + //gzread(f, psxP, 0x00010000); // pralell memory + gzread(f, psxH, 0x00010000); // hardware memory + //gzread(f, psxS, 0x00010000); // sif memory + + SysPrintf("Loading iop stuff\n"); + sioFreeze(f, 0); + cdrFreeze(f, 0); + cdvdFreeze(f, 0); + psxRcntFreeze(f, 0); + //mdecFreeze(f, 0); + sio2Freeze(f, 0); + + SysPrintf("Loading GS\n"); + if( CHECK_MULTIGS ) { + // have to call in thread, otherwise weird stuff will start happening + uptr uf = (uptr)f; + GSRingBufSimplePacket(GS_RINGTYPE_LOAD, (int)(uf&0xffffffff), (int)(uf>>32), 0); + gsWaitGS(); + } + else { + _PS2Eload(GS); + } + SysPrintf("Loading SPU2\n"); + _PS2Eload(SPU2); + SysPrintf("Loading DEV9\n"); + _PS2Eload(DEV9); + SysPrintf("Loading USB\n"); + _PS2Eload(USB); + + SysPrintf("Loading ok\n"); + + gzclose(f); + memset(pCache,0,sizeof(_cacheS)*64); + + //dumplog |= 4; + WriteCP0Status(cpuRegs.CP0.n.Status.val); + for (i=0; i<48; i++) WriteTLB(i); + + return 0; +} + +#ifdef PCSX2_DEVBUILD + +int SaveGSState(char *file) +{ + if( g_SaveGSStream ) return -1; + + SysPrintf("SaveGSState: %s\n", file); + g_fGSSave = gzopen(file, "wb"); + if (g_fGSSave == NULL) return -1; + + g_SaveGSStream = 1; + g_nLeftGSFrames = 2; + + gzwrite(g_fGSSave, &g_nLeftGSFrames, sizeof(g_nLeftGSFrames)); + + return 0; +} + +extern long pDsp; +int LoadGSState(char *file) +{ + int ret; + char strfile[255]; + gzFile f; + freezeData fP; + + f = gzopen(file, "rb"); + if (f == NULL) { + + sprintf(strfile, SSTATES_DIR "/%s", file); + // try prefixing with sstates + f = gzopen(strfile, "rb"); + if( f == NULL ) { + SysPrintf("Failed to find gs state\n"); + return -1; + } + + file = strfile; + } + + SysPrintf("LoadGSState: %s\n", file); + + GSirqCallback(gsIrq); + ret = GSopen(&pDsp, "PCSX2", 0); + if (ret != 0) { + SysMessage (_("Error Opening GS Plugin")); + return -1; + } + + ret = PAD1open((void *)&pDsp); + + gzread(f, &g_nLeftGSFrames, sizeof(g_nLeftGSFrames)); + + gsFreeze(f, 0); + _PS2Eload(GS); + + RunGSState(f); + gzclose(f); + + GSclose(); + PAD1close(); + + return 0; +} + +#endif + +int CheckState(char *file) { + gzFile f; + char header[32]; + + f = gzopen(file, "rb"); + if (f == NULL) return -1; + + gzread(f, header, 32); + + gzclose(f); + + if (strncmp(STATE_VERSION " PCSX2", header, 10)) return -1; + + return 0; +} + + +typedef struct { + char id[8]; + char name[64]; +} LangDef; + +LangDef sLangs[] = { + { "ar_AR", N_("Arabic") }, + { "bg_BG", N_("Bulgarian") }, + { "ca_CA", N_("Catalan") }, + { "cz_CZ", N_("Czech") }, + { "du_DU", N_("Dutch") }, + { "de_DE", N_("German") }, + { "el_EL", N_("Greek") }, + { "en_US", N_("English") }, + { "fr_FR", N_("French") }, + { "hb_HB" , N_("Hebrew") }, + { "hu_HU", N_("Hungarian") }, + { "it_IT", N_("Italian") }, + { "ja_JA", N_("Japanese") }, + { "pe_PE", N_("Persian") }, + { "po_PO", N_("Portuguese") }, + { "po_BR", N_("Portuguese BR") }, + { "pl_PL" , N_("Polish") }, + { "ro_RO", N_("Romanian") }, + { "ru_RU", N_("Russian") }, + { "es_ES", N_("Spanish") }, + { "sh_SH" , N_("S-Chinese") }, + { "sw_SW", N_("Swedish") }, + { "tc_TC", N_("T-Chinese") }, + { "tr_TR", N_("Turkish") }, + { "", "" }, +}; + + +char *ParseLang(char *id) { + int i=0; + + while (sLangs[i].id[0] != 0) { + if (!strcmp(id, sLangs[i].id)) + return _(sLangs[i].name); + i++; + } + + return id; +} + +#define NUM_STATES 10 +int StatesC = 0; +extern void iDumpRegisters(u32 startpc, u32 temp); +extern void recExecuteVU0Block(void); +extern void recExecuteVU1Block(void); +extern void DummyExecuteVU1Block(void); +extern int LoadConfig(); +extern void SaveConfig(); +extern char strgametitle[256]; + +char* mystrlwr( char* string ) +{ + assert( string != NULL ); + while ( 0 != ( *string++ = (char)tolower( *string ) ) ); + return string; +} + +void ProcessFKeys(int fkey, int shift) +{ + char Text[256]; + int ret; + + assert(fkey >= 1 && fkey <= 12 ); + switch(fkey) { + case 1: + sprintf(Text, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, StatesC); + ret = SaveState(Text); + break; + case 2: + if( shift ) + StatesC = (StatesC+NUM_STATES-1)%NUM_STATES; + else + StatesC = (StatesC+1)%NUM_STATES; + SysPrintf("*PCSX2*: Selected State %ld\n", StatesC); + if( GSchangeSaveState != NULL ) { + sprintf(Text, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, StatesC); + GSchangeSaveState(StatesC, Text); + } + break; + case 3: + sprintf (Text, SSTATES_DIR "/%8.8X.%3.3d", ElfCRC, StatesC); + ret = LoadState(Text); + break; + + case 4: + +#ifdef PCSX2_NORECBUILD + SysPrintf("frame skipping only valid for recompiler build\n"); +#else + // cycle + if( shift ) { + // previous + Config.Options = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_VUSKIP)&PCSX2_FRAMELIMIT_MASK); + } + else { + // next + Config.Options = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_LIMIT)&PCSX2_FRAMELIMIT_MASK); + } + + switch(CHECK_FRAMELIMIT) { + case PCSX2_FRAMELIMIT_NORMAL: + if( GSsetFrameSkip != NULL ) GSsetFrameSkip(0); + Cpu->ExecuteVU1Block = recExecuteVU1Block; + SysPrintf("Normal - Frame Limit Mode Changed\n"); + break; + case PCSX2_FRAMELIMIT_LIMIT: + if( GSsetFrameSkip != NULL ) GSsetFrameSkip(0); + Cpu->ExecuteVU1Block = recExecuteVU1Block; + SysPrintf("Limit - Frame Limit Mode Changed\n"); + break; + case PCSX2_FRAMELIMIT_SKIP: + Cpu->ExecuteVU1Block = recExecuteVU1Block; + SysPrintf("Frame Skip - Frame Limit Mode Changed\n"); + break; + case PCSX2_FRAMELIMIT_VUSKIP: + SysPrintf("VU Skip - Frame Limit Mode Changed\n"); + break; + } + SaveConfig(); +#endif + break; + // note: VK_F5-VK_F7 are reserved for GS + case 8: + GSmakeSnapshot("snap/"); + break; + +#ifdef PCSX2_DEVBUILD + case 10: + { +#ifdef PCSX2_NORECBUILD + SysPrintf("Block performances times only valid for recompiler builds\n"); +#else + int num; + FILE* f; + BASEBLOCKEX** ppblocks = GetAllBaseBlocks(&num, 0); + + f = fopen("perflog.txt", "w"); + while(num-- > 0 ) { + if( ppblocks[0]->visited > 0 ) { + fprintf(f, "%u %u %u %u\n", ppblocks[0]->startpc, (u32)(ppblocks[0]->ltime.QuadPart / ppblocks[0]->visited), ppblocks[0]->visited, ppblocks[0]->size); + } + ppblocks[0]->visited = 0; + ppblocks[0]->ltime.QuadPart = 0; + ppblocks++; + } + fclose(f); + SysPrintf("perflog.txt written\n"); +#endif + break; + } + + case 11: + if( CHECK_MULTIGS ) { + SysPrintf("Cannot make gsstates in MTGS mode\n"); + } + else { + if( strgametitle[0] != 0 ) { + // only take the first two words + char name[255], temptitle[255], *tok; + sprintf(temptitle, "%s", strgametitle); + tok = strtok(strgametitle, " "); + sprintf(name, "%s_", mystrlwr(tok)); + tok = strtok(NULL, " "); + if( tok != NULL ) strcat(name, tok); + + sprintf(Text, SSTATES_DIR "/%s.%d.gs", name, StatesC); + } + else + sprintf(Text, SSTATES_DIR "/%8.8X.%d.gs", ElfCRC, StatesC); + + SaveGSState(Text); + } + break; +#endif + + case 12: + if( shift ) { +#ifdef PCSX2_DEVBUILD +#ifndef PCSX2_NORECBUILD + iDumpRegisters(cpuRegs.pc, 0); + SysPrintf("hardware registers dumped EE:%x, IOP:%x\n", cpuRegs.pc, psxRegs.pc); +#endif +#endif + } + else { + g_Pcsx2Recording ^= 1; + if( CHECK_MULTIGS ) { + GSRingBufSimplePacket(GS_RINGTYPE_RECORD, g_Pcsx2Recording, 0, 0); + } + else { + if( GSsetupRecording != NULL ) GSsetupRecording(g_Pcsx2Recording, NULL); + if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL); + } + } + break; + } +} + +void injectIRX(char *filename){ + struct stat buf; + char path[260], name[260], *p, *q; + struct romdir *rd; + int iROMDIR=-1, iIOPBTCONF=-1, iBLANK=-1, i, filesize; + FILE *fp; + + strcpy(name, filename); + for (i=0; name[i] && name[i]!='.' && i<10; i++) name[i]=toupper(name[i]);name[i]=0; + + //phase 1: find ROMDIR in bios + for (p=(char*)PS2MEM_ROM; p<(char*)PS2MEM_ROM+0x80000; p++) + if (strncmp(p, "RESET", 5)==0) + break; + rd=(struct romdir*)p; + + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, name, strlen(name))==0)break; + if (rd[i].fileName[0])return;//already in;) + + //phase 2: make room in IOPBTCONF & ROMDIR + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "ROMDIR", 6)==0)iROMDIR=i; + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "IOPBTCONF", 9)==0)iIOPBTCONF=i; + + for (i=0; rd[i].fileName[0]; i++)if (rd[i].fileName[0]=='-')break; iBLANK=i; + rd[iBLANK].fileSize-=DIRENTRY_SIZE+DIRENTRY_SIZE; + p=(char*)PS2MEM_ROM;for (i=0; iq){*((u64*)p)=*((u64*)p-4);*((u64*)p+1)=*((u64*)p-3);p-=DIRENTRY_SIZE;} + *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iIOPBTCONF].fileSize+=DIRENTRY_SIZE; + + q=(char*)PS2MEM_ROM;for (i=0; i<=iROMDIR; i++) q+=(rd[i].fileSize+0xF)&(~0xF); + while (p >q){*((u64*)p)=*((u64*)p-2);*((u64*)p+1)=*((u64*)p-1);p-=DIRENTRY_SIZE;} + *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iROMDIR].fileSize+=DIRENTRY_SIZE; + + //phase 3: add the name to the end of IOPBTCONF + p=(char*)PS2MEM_ROM;for (i=0; i +#include +#include + +// compile-time assert +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#ifdef __x86_64__ +#define X86_32CODE(x) +#else +#define X86_32CODE(x) x +#endif + +#define PCSX2_GSMULTITHREAD 1 // uses multithreaded gs +#define PCSX2_DUALCORE 2 // speed up for dual cores +#define PCSX2_FRAMELIMIT 4 // limits frames to normal speeds +#define PCSX2_EEREC 0x10 +#define PCSX2_VU0REC 0x20 +#define PCSX2_VU1REC 0x40 +#define PCSX2_COP2REC 0x80 +#define PCSX2_FORCEABS 0x100 +#define PCSX2_FRAMELIMIT_MASK 0xc00 +#define PCSX2_FRAMELIMIT_NORMAL 0x000 +#define PCSX2_FRAMELIMIT_LIMIT 0x400 +#define PCSX2_FRAMELIMIT_SKIP 0x800 +#define PCSX2_FRAMELIMIT_VUSKIP 0xc00 + +#define CHECK_MULTIGS (Config.Options&PCSX2_GSMULTITHREAD) +#define CHECK_DUALCORE (Config.Options&PCSX2_DUALCORE) +#define CHECK_EEREC (Config.Options&PCSX2_EEREC) +#define CHECK_COP2REC (Config.Options&PCSX2_COP2REC) // goes with ee option +#define CHECK_FORCEABS (~(Config.Hacks >> 1) & 1) // always on, (Config.Options&PCSX2_FORCEABS) + +#define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK) + +//#ifdef PCSX2_DEVBUILD +#define CHECK_VU0REC (Config.Options&PCSX2_VU0REC) +#define CHECK_VU1REC (Config.Options&PCSX2_VU1REC) +//#else +//// force to VU recs all the time +//#define CHECK_VU0REC 1 +//#define CHECK_VU1REC 1 +// +//#endif + +typedef struct { + char Bios[256]; + char GS[256]; + char PAD1[256]; + char PAD2[256]; + char SPU2[256]; + char CDVD[256]; + char DEV9[256]; + char USB[256]; + char FW[256]; + char Mcd1[256]; + char Mcd2[256]; + char PluginsDir[256]; + char BiosDir[256]; + char Lang[256]; + u32 Options; // PCSX2_X options + int PsxOut; + int PsxType; + int Cdda; + int Mdec; + int Patch; + int ThPriority; + int CustomFps; + int Hacks; +} PcsxConfig; + +extern PcsxConfig Config; +extern u32 BiosVersion; +extern char CdromId[12]; + +#define gzfreeze(ptr, size) \ + if (Mode == 1) gzwrite(f, ptr, size); \ + else if (Mode == 0) gzread(f, ptr, size); + +#define gzfreezel(ptr) gzfreeze(ptr, sizeof(ptr)) + +int LoadCdrom(); +int CheckCdrom(); +int GetPS2ElfName(char*); + +extern char *LabelAuthors; +extern char *LabelGreets; +int SaveState(char *file); +int LoadState(char *file); +int CheckState(char *file); + +int SaveGSState(char *file); +int LoadGSState(char *file); + +char *ParseLang(char *id); +void ProcessFKeys(int fkey, int shift); // processes fkey related commands value 1-12 + +#ifdef _WIN32 + +void ListPatches (HWND hW); +int ReadPatch (HWND hW, char fileName[1024]); +char * lTrim (char *s); +BOOL Save_Patch_Proc( char * filename ); + +#else + +// functions that linux lacks +#define Sleep(seconds) usleep(1000*(seconds)) + +#include + +extern __forceinline u32 timeGetTime() +{ + struct timeb t; + ftime(&t); + return (u32)(t.time*1000+t.millitm); +} + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define BOOL int + +#undef TRUE +#define TRUE 1 +#undef FALSE +#define FALSE 0 + +#ifndef strnicmp +#define strnicmp strncasecmp +#endif + +#ifndef stricmp +#define stricmp strcasecmp +#endif + +#endif + +#define DIRENTRY_SIZE 16 + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + +struct romdir{ + char fileName[10]; + u16 extInfoSize; + u32 fileSize; +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +u32 GetBiosVersion(); +int IsBIOS(char *filename, char *description); + +// check to see if needs freezing +#ifdef PCSX2_NORECBUILD +#define FreezeMMXRegs(save) +#define FreezeXMMRegs(save) +#else +void FreezeXMMRegs_(int save); +extern u32 g_EEFreezeRegs; +#define FreezeXMMRegs(save) if( g_EEFreezeRegs ) { FreezeXMMRegs_(save); } + +#ifndef __x86_64__ +void FreezeMMXRegs_(int save); +#define FreezeMMXRegs(save) if( g_EEFreezeRegs ) { FreezeMMXRegs_(save); } +#else +#define FreezeMMXRegs(save) +#endif + +#endif + +// define a PCS2 specific memcpy and make sure it is used all in real-time code +#if _MSC_VER >= 1400 // vs2005+ uses xmm/mmx in memcpy +__forceinline void memcpy_pcsx2(void* dest, const void* src, size_t n) +{ + //FreezeMMXRegs(1); // mmx not used + FreezeXMMRegs(1); + memcpy(dest, src, n); + // have to be unfrozen by parent call! +} +#else +#define memcpy_pcsx2 memcpy +#endif + +#ifdef PCSX2_NORECBUILD +#define memcpy_fast memcpy +#else + +#if defined(_WIN32) && !defined(__x86_64__) +// faster memcpy +void * memcpy_amd_(void *dest, const void *src, size_t n); +#define memcpy_fast memcpy_amd_ +//#define memcpy_fast memcpy //Dont use normal memcpy, it has sse in 2k5! +#else +// for now disable linux fast memcpy +#define memcpy_fast memcpy_pcsx2 +#endif + +#endif + +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize); +void memxor_mmx(void* dst, const void* src1, int cmpsize); + +#ifdef _MSC_VER +#pragma pack() +#endif + +void __Log(char *fmt, ...); +void injectIRX(char *filename); + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +// declare linux equivalents +extern __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +extern __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free + +#endif + +// cross-platform atomic operations +#if defined (_WIN32) +/* +#ifndef __x86_64__ // for some reason x64 doesn't like this + +LONG __cdecl _InterlockedIncrement(LONG volatile *Addend); +LONG __cdecl _InterlockedDecrement(LONG volatile *Addend); +LONG __cdecl _InterlockedCompareExchange(LPLONG volatile Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LPLONG volatile Target, LONG Value); +PVOID __cdecl _InterlockedExchangePointer(PVOID volatile* Target, PVOID Value); + +LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); +LONG __cdecl _InterlockedAnd(LPLONG volatile Addend, LONG Value); +#endif + +#pragma intrinsic (_InterlockedExchange) +#define InterlockedExchange _InterlockedExchange + +#pragma intrinsic (_InterlockedExchangeAdd) +#define InterlockedExchangeAdd _InterlockedExchangeAdd +*/ +#else + +typedef void* PVOID; + +/*inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) { + # if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) + return test_and_set(__p, __q); + # else + return __test_and_set(__p, (unsigned long)__q); + # endif + }*/ + +extern __forceinline void InterlockedExchangePointer(PVOID volatile* Target, void* Value) +{ +#ifdef __x86_64__ + __asm__ __volatile__(".intel_syntax\n" + "lock xchg [%0], %%rax\n" + ".att_syntax\n" : : "r"(Target), "a"(Value) : "memory" ); +#else + __asm__ __volatile__(".intel_syntax\n" + "lock xchg [%0], %%eax\n" + ".att_syntax\n" : : "r"(Target), "a"(Value) : "memory" ); +#endif +} + +extern __forceinline long InterlockedExchange(long volatile* Target, long Value) +{ + __asm__ __volatile__(".intel_syntax\n" + "lock xchg [%0], %%eax\n" + ".att_syntax\n" : : "r"(Target), "a"(Value) : "memory" ); +} + +extern __forceinline long InterlockedExchangeAdd(long volatile* Addend, long Value) +{ + __asm__ __volatile__(".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory" ); +} + +#endif + +//#pragma intrinsic (_InterlockedExchange64) +//#define InterlockedExchange64 _InterlockedExchange64 +// +//#pragma intrinsic (_InterlockedExchangeAdd64) +//#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 + +//#ifdef __x86_64__ +//#define InterlockedExchangePointerAdd InterlockedExchangeAdd64 +//#else +//#define InterlockedExchangePointerAdd InterlockedExchangeAdd +//#endif + +#endif /* __MISC_H__ */ + diff --git a/pcsx2/PS2Edefs.h b/pcsx2/PS2Edefs.h new file mode 100644 index 0000000000..bea99e39e0 --- /dev/null +++ b/pcsx2/PS2Edefs.h @@ -0,0 +1,880 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2setClockPtr SPU2setClockPtr; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBasync USBasync; + +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/pcsx2/PS2Etypes.h b/pcsx2/PS2Etypes.h new file mode 100644 index 0000000000..797d0f8dd7 --- /dev/null +++ b/pcsx2/PS2Etypes.h @@ -0,0 +1,105 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifdef _WIN32 +#include +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#define PCSX2_ALIGNED16_DECL(x) x + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/pcsx2/Patch.c b/pcsx2/Patch.c new file mode 100644 index 0000000000..9e7ef23921 --- /dev/null +++ b/pcsx2/Patch.c @@ -0,0 +1,638 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// +// Includes +// +#include +#include + +#include "PsxCommon.h" + +#include "Paths.h" + +#ifdef _WIN32 +#include "windows/cheats/cheats.h" +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +#include "Patch.h" + +int g_ZeroGSOptions=0; + +// +// Variables +// +PatchTextTable commands[] = +{ + { "comment", 1, patchFunc_comment }, + { "gametitle", 2, patchFunc_gametitle }, + { "patch", 3, patchFunc_patch }, + { "fastmemory", 4, patchFunc_fastmemory }, // enable for faster but bugger mem (mvc2 is faster) + { "roundmode", 5, patchFunc_roundmode }, // changes rounding mode for floating point + // syntax: roundmode=X,Y + // possible values for X,Y: NEAR, DOWN, UP, CHOP + // X - EE rounding mode (default is NEAR) + // Y - VU rounding mode (default is CHOP) + { "zerogs", 6, patchFunc_zerogs }, // zerogs=hex + { "path3hack", 7, patchFunc_path3hack }, + { "vunanmode",8, patchFunc_vunanmode }, + { "", 0, NULL } +}; + +PatchTextTable dataType[] = +{ + { "byte", 1, NULL }, + { "short", 2, NULL }, + { "word", 3, NULL }, + { "double", 4, NULL }, + { "extended", 5, NULL }, + { "", 0, NULL } +}; + +PatchTextTable cpuCore[] = +{ + { "EE", 1, NULL }, + { "IOP", 2, NULL }, + { "", 0, NULL } +}; + +IniPatch patch[ MAX_PATCH ]; +int patchnumber; + + +// +// Function Implementations +// + +int PatchTableExecute( char * text1, char * text2, PatchTextTable * Table ) +{ + int i = 0; + + while ( Table[ i ].text[ 0 ] ) + { + if ( !strcmp( Table[ i ].text, text1 ) ) + { + if ( Table[ i ].func ) + { + Table[ i ].func( text1, text2 ); + } + break; + } + i++; + } + + return Table[ i ].code; +} +u32 SkipCount=0; +u32 IterationCount=0; +u32 IterationIncrement=0; +u32 ValueIncrement=0; +u32 PrevCheatType=0; +u32 PrevCheataddr = 0; +u32 LastType = 0; + + + +void _applypatch(int place, IniPatch *p) { + u32 Cheataddr = 0; + u8 u8Val=0; + u16 u16Val=0; + u32 u32Val=0; + u32 i; + + if (p->placetopatch != place) return; + + if (p->enabled == 0) return; + + if (p->cpu == 1) { //EE + if (p->type == 1) { //byte + memWrite8(p->addr, (u8)p->data); + } else + if (p->type == 2) { //short + memWrite16(p->addr, (u16)p->data); + } else + if (p->type == 3) { //word + memWrite32(p->addr, (u32)p->data); + } else + if (p->type == 4) { //double + memWrite64(p->addr, p->data); + } + if (p->type == 5) { //extended + + if (SkipCount > 0){ + SkipCount--; + }else if (PrevCheatType == 0x3040) { // vvvvvvvv 00000000 Inc + memRead32(PrevCheataddr,&u32Val); + memWrite32(PrevCheataddr, u32Val+(p->addr)); + PrevCheatType = 0; + }else if (PrevCheatType == 0x3050){ // vvvvvvvv 00000000 Dec + memRead32(PrevCheataddr,&u32Val); + memWrite32(PrevCheataddr, u32Val-(p->addr)); + PrevCheatType = 0; + }else if (PrevCheatType == 0x4000){ // vvvvvvvv iiiiiiii + for(i=0;iaddr+((u32)p->data*i))); + PrevCheatType = 0; + }else if (PrevCheatType == 0x5000){ // dddddddd iiiiiiii + for(i=0;idata)+i,u8Val); + } + PrevCheatType = 0; + }else if (PrevCheatType == 0x6000){ // 000Xnnnn iiiiiiii + // Get Number of pointers + if (IterationCount == 0) + IterationCount = (u32)p->addr&0x0000FFFF; + + // Read first pointer + LastType = ((u32)p->addr&0x000F0000)/0x10000; + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr =u32Val+(u32)p->data; + IterationCount--; + + // Check if needed to read another pointer + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType=0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType=0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType=0x2) + memWrite32(PrevCheataddr,IterationIncrement); + }else{ + PrevCheatType = 0x6001; + } + + }else if (PrevCheatType == 0x6001){ // 000Xnnnn iiiiiiii + + // Read first pointer + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr =u32Val+(u32)p->addr; + IterationCount--; + + // Check if needed to read another pointer + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType=0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType=0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType=0x2) + memWrite32(PrevCheataddr,IterationIncrement); + }else{ + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr =u32Val+(u32)p->data; + IterationCount--; + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType=0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType=0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType=0x2) + memWrite32(PrevCheataddr,IterationIncrement); + } + } + + }else if ((p->addr&0xF0000000) == 0x00000000){ // 0aaaaaaa 0000000vv + memWrite8(p->addr&0x0FFFFFFF, (u8)p->data&0x000000FF); + PrevCheatType = 0; + }else if ((p->addr&0xF0000000) == 0x10000000){ // 0aaaaaaa 0000vvvv + memWrite16(p->addr&0x0FFFFFFF, (u16)p->data&0x0000FFFF); + PrevCheatType = 0; + }else if ((p->addr&0xF0000000) == 0x20000000){ // 0aaaaaaa vvvvvvvv + memWrite32(p->addr&0x0FFFFFFF, (u32)p->data); + PrevCheatType = 0; + }else if ((p->addr&0xFFFF0000) == 0x30000000){ // 300000vv 0aaaaaaa Inc + memRead8((u32)p->data,&u8Val); + memWrite8((u32)p->data, u8Val+(p->addr&0x000000FF)); + PrevCheatType = 0; + }else if ((p->addr&0xFFFF0000) == 0x30100000){ // 301000vv 0aaaaaaa Dec + memRead8((u32)p->data,&u8Val); + memWrite8((u32)p->data, u8Val-(p->addr&0x000000FF)); + PrevCheatType = 0; + }else if ((p->addr&0xFFFF0000) == 0x30200000){ // 3020vvvv 0aaaaaaa Inc + memRead16((u32)p->data,&u16Val); + memWrite16((u32)p->data, u16Val+(p->addr&0x0000FFFF)); + PrevCheatType = 0; + }else if ((p->addr&0xFFFF0000) == 0x30300000){ // 3030vvvv 0aaaaaaa Dec + memRead16((u32)p->data,&u16Val); + memWrite16((u32)p->data, u16Val-(p->addr&0x0000FFFF)); + PrevCheatType = 0; + }else if ((p->addr&0xFFFF0000) == 0x30400000){ // 30400000 0aaaaaaa Inc + Another line + PrevCheatType= 0x3040; + PrevCheataddr= (u32)p->data; + }else if ((p->addr&0xFFFF0000) == 0x30500000){ // 30500000 0aaaaaaa Inc + Another line + PrevCheatType= 0x3050; + PrevCheataddr= (u32)p->data; + }else if ((p->addr&0xF0000000) == 0x40000000){ // 4aaaaaaa nnnnssss + Another line + IterationCount=((u32)p->data&0xFFFF0000)/0x10000; + IterationIncrement=((u32)p->data&0x0000FFFF)*4; + PrevCheataddr=(u32)p->addr&0x0FFFFFFF; + PrevCheatType= 0x4000; + }else if ((p->addr&0xF0000000) == 0x50000000){ // 5sssssss nnnnnnnn + Another line + PrevCheataddr = (u32)p->addr&0x0FFFFFFF; + IterationCount=((u32)p->data); + PrevCheatType= 0x5000; + }else if ((p->addr&0xF0000000) == 0x60000000){ // 6aaaaaaa 000000vv + Another line/s + PrevCheataddr = (u32)p->addr&0x0FFFFFFF; + IterationIncrement=((u32)p->data); + IterationCount=0; + PrevCheatType= 0x6000; + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00000000)){ // 7aaaaaaa 000000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val|(p->data&0x000000FF))); + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00100000)){ // 7aaaaaaa 0010vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val|(p->data&0x0000FFFF))); + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00200000)){ // 7aaaaaaa 002000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val&(p->data&0x000000FF))); + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00300000)){ // 7aaaaaaa 0030vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val&(p->data&0x0000FFFF))); + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00400000)){ // 7aaaaaaa 004000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val^(p->data&0x000000FF))); + }else if (((p->addr&0xF0000000) == 0x70000000)&&((p->data&0x00F00000) == 0x00500000)){ // 7aaaaaaa 0050vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val^(p->data&0x0000FFFF))); + }else if ((p->addr < 0xE0000000)&&(((u32)p->data&0xFFFF0000)==0x00000000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val != (0x0000FFFF&(u32)p->data)) + SkipCount = 1; + PrevCheatType= 0; + }else if ((p->addr < 0xE0000000)&&(((u32)p->data&0xFFFF0000)==0x00100000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val == (0x0000FFFF&(u32)p->data)) + SkipCount = 1; + PrevCheatType= 0; + }else if ((p->addr < 0xE0000000)&&(((u32)p->data&0xFFFF0000)==0x00200000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val <= (0x0000FFFF&(u32)p->data)) + SkipCount = 1; + PrevCheatType= 0; + }else if ((p->addr < 0xE0000000)&&(((u32)p->data&0xFFFF0000)==0x00300000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val >= (0x0000FFFF&(u32)p->data)) + SkipCount = 1; + PrevCheatType= 0; + }else if ((p->addr < 0xF0000000)&&(((u32)p->data&0xF0000000)==0x00000000)){ + memRead16((u32)p->data&0x0FFFFFFF,&u16Val); + if (u16Val != (0x0000FFFF&(u32)p->addr)) + SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; + PrevCheatType= 0; + }else if ((p->addr < 0xF0000000)&&(((u32)p->data&0xF0000000)==0x10000000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val == (0x0000FFFF&(u32)p->data)) + SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; + PrevCheatType= 0; + }else if ((p->addr < 0xF0000000)&&(((u32)p->data&0xF0000000)==0x20000000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val <= (0x0000FFFF&(u32)p->data)) + SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; + PrevCheatType= 0; + }else if ((p->addr < 0xF0000000)&&(((u32)p->data&0xF0000000)==0x30000000)){ + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val >= (0x0000FFFF&(u32)p->data)) + SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; + PrevCheatType= 0; + } + } + } else + if (p->cpu == 2) { //IOP + if (p->type == 1) { //byte + psxMemWrite8(p->addr, (u8)p->data); + } else + if (p->type == 2) { //short + psxMemWrite16(p->addr, (u16)p->data); + } else + if (p->type == 3) { //word + psxMemWrite32(p->addr, (u32)p->data); + } + } +} + + +//this is for apply patches directly to memory +void applypatch(int place) { + int i; + + if (place == 0) { + SysPrintf(" patchnumber: %d\n", patchnumber); + } + + for ( i = 0; i < patchnumber; i++ ) { + _applypatch(place, &patch[i]); + } +} + +void patchFunc_comment( char * text1, char * text2 ) +{ + SysPrintf( "comment: %s \n", text2 ); +} + +char strgametitle[256] = {0}; + +void patchFunc_gametitle( char * text1, char * text2 ) +{ + SysPrintf( "gametitle: %s \n", text2 ); +#ifdef _WIN32 + sprintf(strgametitle,"%s",text2); + if (gApp.hConsole) SetConsoleTitle(strgametitle); +#endif +} + +extern int RunExe; + +void patchFunc_patch( char * cmd, char * param ) +{ + //patch=placetopatch,cpucore,address,type,data + char * pText; + + if ( patchnumber >= MAX_PATCH ) + { + SysPrintf( "Patch ERROR: Maximum number of patches reached: %s=%s\n", cmd, param ); + return; + } + + pText = strtok( param, "," ); + pText = param; +// inifile_trim( pText ); + + if(RunExe == 1) patch[ patchnumber ].placetopatch = 1; + else patch[ patchnumber ].placetopatch = strtol( pText, (char **)NULL, 0 ); + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + patch[ patchnumber ].cpu = PatchTableExecute( pText, NULL, cpuCore ); + if ( patch[ patchnumber ].cpu == 0 ) + { + SysPrintf( "Unrecognized patch '%s'\n", pText ); + return; + } + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + sscanf( pText, "%X", &patch[ patchnumber ].addr ); + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + patch[ patchnumber ].type = PatchTableExecute( pText, NULL, dataType ); + if ( patch[ patchnumber ].type == 0 ) + { + SysPrintf( "Unrecognized patch '%s'\n", pText ); + return; + } + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + sscanf( pText, "%I64X", &patch[ patchnumber ].data ); + + patch[ patchnumber ].enabled = 1; + + patchnumber++; +} + +//this routine is for execute the commands of the ini file +void inifile_command( char * cmd ) +{ + int code; + char command[ 256 ]; + char parameter[ 256 ]; + + // extract param part (after '=') + char * pEqual = strchr( cmd, '=' ); + + if ( ! pEqual ) + { + // fastmemory doesn't have = + pEqual = cmd+strlen(cmd); +// SysPrintf( "Ini file ERROR: unknow line: %s \n", cmd ); +// return; + } + + memset( command, 0, sizeof( command ) ); + memset( parameter, 0, sizeof( parameter ) ); + + strncpy( command, cmd, pEqual - cmd ); + strncpy( parameter, pEqual + 1, sizeof( parameter ) ); + + inifile_trim( command ); + inifile_trim( parameter ); + + code = PatchTableExecute( command, parameter, commands ); +} + +void inifile_trim( char * buffer ) +{ + char * pInit = buffer; + char * pEnd = NULL; + + while ( ( *pInit == ' ' ) || ( *pInit == '\t' ) ) //skip space + { + pInit++; + } + if ( ( pInit[ 0 ] == '/' ) && ( pInit[ 1 ] == '/' ) ) //remove comment + { + buffer[ 0 ] = '\0'; + return; + } + pEnd = pInit + strlen( pInit ) - 1; + if ( pEnd <= pInit ) + { + buffer[ 0 ] = '\0'; + return; + } + while ( ( *pEnd == '\r' ) || ( *pEnd == '\n' ) || + ( *pEnd == ' ' ) || ( *pEnd == '\t' ) ) + { + pEnd--; + } + if ( pEnd <= pInit ) + { + buffer[ 0 ] = '\0'; + return; + } + memmove( buffer, pInit, pEnd - pInit + 1 ); + buffer[ pEnd - pInit + 1 ] = '\0'; +} + +void inisection_process( FILE * f1 ) +{ + char buffer[ 1024 ]; + while( fgets( buffer, sizeof( buffer ), f1 ) ) + { + inifile_trim( buffer ); + if ( buffer[ 0 ] ) + { + inifile_command( buffer ); + } + } +} + +//this routine is for reading the ini file + +void inifile_read( char * name ) +{ + FILE * f1; + char buffer[ 1024 ]; + + patchnumber = 0; +#ifdef _WIN32 + sprintf( buffer, PATCHES_DIR "\\%s.pnach", name ); +#else + sprintf( buffer, PATCHES_DIR "/%s.pnach", name ); +#endif + + f1 = fopen( buffer, "rt" ); + +#ifndef _WIN32 + if( !f1 ) { + // try all upper case because linux is case sensitive + char* pstart = buffer+8; + char* pend = buffer+strlen(buffer); + while(pstart != pend ) { + // stop at the first . since we only want to update the hex + if( *pstart == '.' ) + break; + *pstart++ = toupper(*pstart); + } + + f1 = fopen(buffer, "rt"); + } +#endif + + if( !f1 ) + { + SysPrintf( _( "No patch found.Resuming execution without a patch (this is NOT an error).\n" )); + return; + } + + inisection_process( f1 ); + + fclose( f1 ); +} + +void resetpatch( void ) +{ + patchnumber = 0; +} + +int AddPatch(int Mode, int Place, int Address, int Size, u64 data) +{ + + if ( patchnumber >= MAX_PATCH ) + { + SysPrintf( "Patch ERROR: Maximum number of patches reached.\n"); + return -1; + } + + if(RunExe == 1) patch[patchnumber].placetopatch = 1; + else patch[patchnumber].placetopatch = Mode; + patch[patchnumber].cpu = Place; + patch[patchnumber].addr=Address; + patch[patchnumber].type=Size; + patch[patchnumber].data = data; + return patchnumber++; +} + +void patchFunc_fastmemory( char * cmd, char * param ) +{ +#ifndef PCSX2_NORECBUILD + // only valid for recompilers + SetFastMemory(1); +#endif +} + +extern void SetVUNanMode(int mode); + +void patchFunc_vunanmode( char * cmd, char * param ) +{ +#ifndef PCSX2_NORECBUILD + // only valid for recompilers + SetVUNanMode(param != NULL ? atoi(param) : 1); +#endif +} + +extern int path3hack; +void patchFunc_path3hack( char * cmd, char * param ) +{ + path3hack = 1; +} + +void patchFunc_roundmode( char * cmd, char * param ) +{ + //roundmode = X,Y + int index; + char * pText; + + u32 eetype=0x0000; + u32 vutype=0x6000; + + index = 0; + pText = strtok( param, ", " ); + while(pText != NULL) { + u32 type = 0xffff; + if( stricmp(pText, "near") == 0 ) { + type = 0x0000; + } + else if( stricmp(pText, "down") == 0 ) { + type = 0x2000; + } + else if( stricmp(pText, "up") == 0 ) { + type = 0x4000; + } + else if( stricmp(pText, "chop") == 0 ) { + type = 0x6000; + } + + if( type == 0xffff ) { + printf("bad argument (%s) to round mode! skipping...\n", pText); + break; + } + + if( index == 0 ) eetype=type; + else vutype=type; + + if( index == 1 ) + break; + + index++; + pText = strtok(NULL, ", "); + } + + SetRoundMode(eetype,vutype); +} + +void patchFunc_zerogs(char* cmd, char* param) +{ + sscanf(param, "%x", &g_ZeroGSOptions); +} + +void SetRoundMode(u32 ee, u32 vu) +{ + // don't set a state for interpreter only +#ifndef PCSX2_NORECBUILD + SetCPUState(0x9f80|ee, 0x9f80|vu); +#endif +} diff --git a/pcsx2/Patch.h b/pcsx2/Patch.h new file mode 100644 index 0000000000..fe724ab98c --- /dev/null +++ b/pcsx2/Patch.h @@ -0,0 +1,98 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PATCH_H__ +#define __PATCH_H__ + +// +// Defines +// +#define MAX_PATCH 1024 + +#define IFIS(x,str) if(!strnicmp(x,str,sizeof(str)-1)) + +#define GETNEXT_PARAM() \ + while ( *param && ( *param != ',' ) ) param++; \ + if ( *param ) param++; \ + while ( *param && ( *param == ' ' ) ) param++; \ + if ( *param == 0 ) { SysPrintf( _( "Not enough params for inicommand\n" ) ); return; } + +// +// Typedefs +// +typedef void (*PATCHTABLEFUNC)( char * text1, char * text2 ); + +typedef struct +{ + char * text; + int code; + PATCHTABLEFUNC func; +} PatchTextTable; + +typedef struct +{ + int enabled; + int group; + int type; + int cpu; + int placetopatch; + u32 addr; + u64 data; +} IniPatch; + +// +// Function prototypes +// +void patchFunc_comment( char * text1, char * text2 ); +void patchFunc_gametitle( char * text1, char * text2 ); +void patchFunc_patch( char * text1, char * text2 ); +void patchFunc_fastmemory( char * text1, char * text2 ); +void patchFunc_path3hack( char * text1, char * text2 ); +void patchFunc_roundmode( char * text1, char * text2 ); +void patchFunc_zerogs( char * text1, char * text2 ); +void patchFunc_vunanmode( char * text1, char * text2 ); + +void inifile_trim( char * buffer ); + +// +// Variables +// +extern PatchTextTable commands[]; + +extern PatchTextTable dataType[]; + +extern PatchTextTable cpuCore[]; + +extern IniPatch patch[ MAX_PATCH ]; +extern int patchnumber; + + +void applypatch( int place ); +void inifile_read( char * name ); +void inifile_command( char * cmd ); +void resetpatch( void ); + +int AddPatch(int Mode, int Place, int Address, int Size, u64 data); + +void SetFastMemory(int); // iR5900LoadStore.c +void SetVUNanMemory(int); // iVUmicro.c +void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR); + +void SetRoundMode(u32 ee, u32 vu); + +#endif /* __PATCH_H__ */ + diff --git a/pcsx2/Paths.h b/pcsx2/Paths.h new file mode 100644 index 0000000000..5fe7fe1d4f --- /dev/null +++ b/pcsx2/Paths.h @@ -0,0 +1,18 @@ +#ifndef PATCHES_H_INCLUDED +#define PATCHES_H_INCLUDED + +#define CONFIG_DIR "inis" + +#define DEFAULT_BIOS_DIR "bios" +#define DEFAULT_PLUGINS_DIR "plugins" + +#define MEMCARDS_DIR "memcards" +#define PATCHES_DIR "patches" + +#define SSTATES_DIR "sstates" + +#define LANGS_DIR "Langs" + +#define LOGS_DIR "logs" + +#endif//PATCHES_H_INCLUDED \ No newline at end of file diff --git a/pcsx2/Plugins.c b/pcsx2/Plugins.c new file mode 100644 index 0000000000..7836ac77b3 --- /dev/null +++ b/pcsx2/Plugins.c @@ -0,0 +1,667 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "GS.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#endif + +#define CheckErr(func) \ + err = SysLibError(); \ + if (err != NULL) { SysMessage (_("%s: Error loading %s: %s"), filename, func, err); return -1; } + +#define LoadSym(dest, src, name, checkerr) \ + dest = (src) SysLoadSym(drv, name); if (checkerr == 1) CheckErr(name); \ + if (checkerr == 2) { err = SysLibError(); if (err != NULL) errval = 1; } + +#define TestPS2Esyms(type) { \ + _PS2EgetLibVersion2 PS2EgetLibVersion2; \ + SysLoadSym(drv, "PS2EgetLibType"); CheckErr("PS2EgetLibType"); \ + PS2EgetLibVersion2 = (_PS2EgetLibVersion2) SysLoadSym(drv, "PS2EgetLibVersion2"); CheckErr("PS2EgetLibVersion2"); \ + SysLoadSym(drv, "PS2EgetLibName"); CheckErr("PS2EgetLibName"); \ + if( ((PS2EgetLibVersion2(PS2E_LT_##type) >> 16)&0xff) != PS2E_##type##_VERSION) { \ + SysMessage (_("Can't load '%s', wrong PS2E version (%x != %x)"), filename, (PS2EgetLibVersion2(PS2E_LT_##type) >> 16)&0xff, PS2E_##type##_VERSION); return -1; \ + } \ +} + +static char *err; +static int errval; + +void *GSplugin; + +void CALLBACK GS_printf(int timeout, char *fmt, ...) { + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + SysPrintf(msg); +} + +s32 CALLBACK GS_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK GS_keyEvent(keyEvent *ev) {} +void CALLBACK GS_makeSnapshot(char *path) {} +void CALLBACK GS_irqCallback(void (*callback)()) {} +void CALLBACK GS_configure() {} +void CALLBACK GS_about() {} +long CALLBACK GS_test() { return 0; } + +#define LoadGSsym1(dest, name) \ + LoadSym(GS##dest, _GS##dest, name, 1); + +#define LoadGSsym0(dest, name) \ + LoadSym(GS##dest, _GS##dest, name, 0); \ + if (GS##dest == NULL) GS##dest = (_GS##dest) GS_##dest; + +#define LoadGSsymN(dest, name) \ + LoadSym(GS##dest, _GS##dest, name, 0); + +int LoadGSplugin(char *filename) { + void *drv; + + GSplugin = SysLoadLibrary(filename); + if (GSplugin == NULL) { SysMessage (_("Could Not Load GS Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = GSplugin; + TestPS2Esyms(GS); + LoadGSsym1(init, "GSinit"); + LoadGSsym1(shutdown, "GSshutdown"); + LoadGSsym1(open, "GSopen"); + LoadGSsym1(close, "GSclose"); + LoadGSsym1(gifTransfer1, "GSgifTransfer1"); + LoadGSsym1(gifTransfer2, "GSgifTransfer2"); + LoadGSsym1(gifTransfer3, "GSgifTransfer3"); + LoadGSsym1(readFIFO, "GSreadFIFO"); + LoadGSsymN(getLastTag, "GSgetLastTag"); + LoadGSsymN(readFIFO2, "GSreadFIFO2"); // optional + LoadGSsym1(vsync, "GSvsync"); + + LoadGSsym0(keyEvent, "GSkeyEvent"); + LoadGSsymN(changeSaveState, "GSchangeSaveState"); + LoadGSsymN(gifSoftReset, "GSgifSoftReset"); + LoadGSsym0(makeSnapshot, "GSmakeSnapshot"); + LoadGSsym0(irqCallback, "GSirqCallback"); + LoadGSsym0(printf, "GSprintf"); + LoadGSsym1(setBaseMem, "GSsetBaseMem"); + LoadGSsymN(setGameCRC, "GSsetGameCRC"); + LoadGSsym1(reset, "GSreset"); + LoadGSsym1(writeCSR, "GSwriteCSR"); + LoadGSsymN(makeSnapshot2,"GSmakeSnapshot2"); + LoadGSsymN(getDriverInfo,"GSgetDriverInfo"); + + LoadGSsymN(setFrameSkip, "GSsetFrameSkip"); + LoadGSsymN(setupRecording, "GSsetupRecording"); + +#ifdef _WIN32 + LoadGSsymN(setWindowInfo,"GSsetWindowInfo"); +#endif + LoadGSsym0(freeze, "GSfreeze"); + LoadGSsym0(configure, "GSconfigure"); + LoadGSsym0(about, "GSabout"); + LoadGSsym0(test, "GStest"); + + return 0; +} + +void *PAD1plugin; + +void CALLBACK PAD1_configure() {} +void CALLBACK PAD1_about() {} +long CALLBACK PAD1_test() { return 0; } + +#define LoadPAD1sym1(dest, name) \ + LoadSym(PAD1##dest, _PAD##dest, name, 1); + +#define LoadPAD1sym0(dest, name) \ + LoadSym(PAD1##dest, _PAD##dest, name, 0); \ + if (PAD1##dest == NULL) PAD1##dest = (_PAD##dest) PAD1_##dest; + +#define LoadPAD1symN(dest, name) \ + LoadSym(PAD1##dest, _PAD##dest, name, 0); + +int LoadPAD1plugin(char *filename) { + void *drv; + + PAD1plugin = SysLoadLibrary(filename); + if (PAD1plugin == NULL) { SysMessage (_("Could Not Load PAD1 Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = PAD1plugin; + TestPS2Esyms(PAD); + LoadPAD1sym1(init, "PADinit"); + LoadPAD1sym1(shutdown, "PADshutdown"); + LoadPAD1sym1(open, "PADopen"); + LoadPAD1sym1(close, "PADclose"); + LoadPAD1sym1(keyEvent, "PADkeyEvent"); + LoadPAD1sym1(startPoll, "PADstartPoll"); + LoadPAD1sym1(poll, "PADpoll"); + LoadPAD1sym1(query, "PADquery"); + LoadPAD1symN(update, "PADupdate"); + + LoadPAD1symN(gsDriverInfo, "PADgsDriverInfo"); + LoadPAD1sym0(configure, "PADconfigure"); + LoadPAD1sym0(about, "PADabout"); + LoadPAD1sym0(test, "PADtest"); + + return 0; +} + +void *PAD2plugin; + +void CALLBACK PAD2_configure() {} +void CALLBACK PAD2_about() {} +long CALLBACK PAD2_test() { return 0; } + +#define LoadPAD2sym1(dest, name) \ + LoadSym(PAD2##dest, _PAD##dest, name, 1); + +#define LoadPAD2sym0(dest, name) \ + LoadSym(PAD2##dest, _PAD##dest, name, 0); \ + if (PAD2##dest == NULL) PAD2##dest = (_PAD##dest) PAD2_##dest; + +#define LoadPAD2symN(dest, name) \ + LoadSym(PAD2##dest, _PAD##dest, name, 0); + +int LoadPAD2plugin(char *filename) { + void *drv; + + PAD2plugin = SysLoadLibrary(filename); + if (PAD2plugin == NULL) { SysMessage (_("Could Not Load PAD2 Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = PAD2plugin; + TestPS2Esyms(PAD); + LoadPAD2sym1(init, "PADinit"); + LoadPAD2sym1(shutdown, "PADshutdown"); + LoadPAD2sym1(open, "PADopen"); + LoadPAD2sym1(close, "PADclose"); + LoadPAD2sym1(keyEvent, "PADkeyEvent"); + LoadPAD2sym1(startPoll, "PADstartPoll"); + LoadPAD2sym1(poll, "PADpoll"); + LoadPAD2sym1(query, "PADquery"); + LoadPAD2symN(update, "PADupdate"); + + LoadPAD2symN(gsDriverInfo, "PADgsDriverInfo"); + LoadPAD2sym0(configure, "PADconfigure"); + LoadPAD2sym0(about, "PADabout"); + LoadPAD2sym0(test, "PADtest"); + + return 0; +} + +void *SPU2plugin; + +s32 CALLBACK SPU2_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK SPU2_configure() {} +void CALLBACK SPU2_about() {} +s32 CALLBACK SPU2_test() { return 0; } + +#define LoadSPU2sym1(dest, name) \ + LoadSym(SPU2##dest, _SPU2##dest, name, 1); + +#define LoadSPU2sym0(dest, name) \ + LoadSym(SPU2##dest, _SPU2##dest, name, 0); \ + if (SPU2##dest == NULL) SPU2##dest = (_SPU2##dest) SPU2_##dest; + +#define LoadSPU2symN(dest, name) \ + LoadSym(SPU2##dest, _SPU2##dest, name, 0); + +int LoadSPU2plugin(char *filename) { + void *drv; + + SPU2plugin = SysLoadLibrary(filename); + if (SPU2plugin == NULL) { SysMessage (_("Could Not Load SPU2 Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = SPU2plugin; + TestPS2Esyms(SPU2); + LoadSPU2sym1(init, "SPU2init"); + LoadSPU2sym1(shutdown, "SPU2shutdown"); + LoadSPU2sym1(open, "SPU2open"); + LoadSPU2sym1(close, "SPU2close"); + LoadSPU2sym1(write, "SPU2write"); + LoadSPU2sym1(read, "SPU2read"); + LoadSPU2sym1(readDMA4Mem, "SPU2readDMA4Mem"); + LoadSPU2sym1(writeDMA4Mem, "SPU2writeDMA4Mem"); + LoadSPU2sym1(interruptDMA4,"SPU2interruptDMA4"); + LoadSPU2sym1(readDMA7Mem, "SPU2readDMA7Mem"); + LoadSPU2sym1(writeDMA7Mem, "SPU2writeDMA7Mem"); + LoadSPU2sym1(interruptDMA7,"SPU2interruptDMA7"); + LoadSPU2symN(setDMABaseAddr, "SPU2setDMABaseAddr"); + LoadSPU2sym1(ReadMemAddr, "SPU2ReadMemAddr"); + LoadSPU2sym1(WriteMemAddr, "SPU2WriteMemAddr"); + LoadSPU2sym1(irqCallback, "SPU2irqCallback"); + + LoadSPU2symN(setClockPtr, "SPU2setClockPtr"); + + LoadSPU2symN(setupRecording, "SPU2setupRecording"); + + LoadSPU2sym0(freeze, "SPU2freeze"); + LoadSPU2sym0(configure, "SPU2configure"); + LoadSPU2sym0(about, "SPU2about"); + LoadSPU2sym0(test, "SPU2test"); + LoadSPU2symN(async, "SPU2async"); + + return 0; +} + +void *CDVDplugin; + +void CALLBACK CDVD_configure() {} +void CALLBACK CDVD_about() {} +long CALLBACK CDVD_test() { return 0; } + +#define LoadCDVDsym1(dest, name) \ + LoadSym(CDVD##dest, _CDVD##dest, name, 1); + +#define LoadCDVDsym0(dest, name) \ + LoadSym(CDVD##dest, _CDVD##dest, name, 0); \ + if (CDVD##dest == NULL) CDVD##dest = (_CDVD##dest) CDVD_##dest; + +#define LoadCDVDsymN(dest, name) \ + LoadSym(CDVD##dest, _CDVD##dest, name, 0); \ + +int LoadCDVDplugin(char *filename) { + void *drv; + + CDVDplugin = SysLoadLibrary(filename); + if (CDVDplugin == NULL) { SysMessage (_("Could Not Load CDVD Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = CDVDplugin; + TestPS2Esyms(CDVD); + LoadCDVDsym1(init, "CDVDinit"); + LoadCDVDsym1(shutdown, "CDVDshutdown"); + LoadCDVDsym1(open, "CDVDopen"); + LoadCDVDsym1(close, "CDVDclose"); + LoadCDVDsym1(readTrack, "CDVDreadTrack"); + LoadCDVDsym1(getBuffer, "CDVDgetBuffer"); + LoadCDVDsym1(readSubQ, "CDVDreadSubQ"); + LoadCDVDsym1(getTN, "CDVDgetTN"); + LoadCDVDsym1(getTD, "CDVDgetTD"); + LoadCDVDsym1(getTOC, "CDVDgetTOC"); + LoadCDVDsym1(getDiskType, "CDVDgetDiskType"); + LoadCDVDsym1(getTrayStatus, "CDVDgetTrayStatus"); + LoadCDVDsym1(ctrlTrayOpen, "CDVDctrlTrayOpen"); + LoadCDVDsym1(ctrlTrayClose, "CDVDctrlTrayClose"); + + LoadCDVDsym0(configure, "CDVDconfigure"); + LoadCDVDsym0(about, "CDVDabout"); + LoadCDVDsym0(test, "CDVDtest"); + LoadCDVDsymN(newDiskCB, "CDVDnewDiskCB"); + + return 0; +} + +void *DEV9plugin; + +s32 CALLBACK DEV9_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK DEV9_configure() {} +void CALLBACK DEV9_about() {} +long CALLBACK DEV9_test() { return 0; } + +#define LoadDEV9sym1(dest, name) \ + LoadSym(DEV9##dest, _DEV9##dest, name, 1); + +#define LoadDEV9sym0(dest, name) \ + LoadSym(DEV9##dest, _DEV9##dest, name, 0); \ + if (DEV9##dest == NULL) DEV9##dest = (_DEV9##dest) DEV9_##dest; + +int LoadDEV9plugin(char *filename) { + void *drv; + + DEV9plugin = SysLoadLibrary(filename); + if (DEV9plugin == NULL) { SysMessage (_("Could Not Load DEV9 Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = DEV9plugin; + TestPS2Esyms(DEV9); + LoadDEV9sym1(init, "DEV9init"); + LoadDEV9sym1(shutdown, "DEV9shutdown"); + LoadDEV9sym1(open, "DEV9open"); + LoadDEV9sym1(close, "DEV9close"); + LoadDEV9sym1(read8, "DEV9read8"); + LoadDEV9sym1(read16, "DEV9read16"); + LoadDEV9sym1(read32, "DEV9read32"); + LoadDEV9sym1(write8, "DEV9write8"); + LoadDEV9sym1(write16, "DEV9write16"); + LoadDEV9sym1(write32, "DEV9write32"); + LoadDEV9sym1(readDMA8Mem, "DEV9readDMA8Mem"); + LoadDEV9sym1(writeDMA8Mem, "DEV9writeDMA8Mem"); + LoadDEV9sym1(irqCallback, "DEV9irqCallback"); + LoadDEV9sym1(irqHandler, "DEV9irqHandler"); + + LoadDEV9sym0(freeze, "DEV9freeze"); + LoadDEV9sym0(configure, "DEV9configure"); + LoadDEV9sym0(about, "DEV9about"); + LoadDEV9sym0(test, "DEV9test"); + + return 0; +} + +void *USBplugin; + +s32 CALLBACK USB_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK USB_configure() {} +void CALLBACK USB_about() {} +long CALLBACK USB_test() { return 0; } + +#define LoadUSBsym1(dest, name) \ + LoadSym(USB##dest, _USB##dest, name, 1); + +#define LoadUSBsym0(dest, name) \ + LoadSym(USB##dest, _USB##dest, name, 0); \ + if (USB##dest == NULL) USB##dest = (_USB##dest) USB_##dest; + +#define LoadUSBsymX(dest, name) \ + LoadSym(USB##dest, _USB##dest, name, 0); \ + +int LoadUSBplugin(char *filename) { + void *drv; + + USBplugin = SysLoadLibrary(filename); + if (USBplugin == NULL) { SysMessage (_("Could Not Load USB Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = USBplugin; + TestPS2Esyms(USB); + LoadUSBsym1(init, "USBinit"); + LoadUSBsym1(shutdown, "USBshutdown"); + LoadUSBsym1(open, "USBopen"); + LoadUSBsym1(close, "USBclose"); + LoadUSBsym1(read8, "USBread8"); + LoadUSBsym1(read16, "USBread16"); + LoadUSBsym1(read32, "USBread32"); + LoadUSBsym1(write8, "USBwrite8"); + LoadUSBsym1(write16, "USBwrite16"); + LoadUSBsym1(write32, "USBwrite32"); + LoadUSBsym1(irqCallback, "USBirqCallback"); + LoadUSBsym1(irqHandler, "USBirqHandler"); + LoadUSBsym1(setRAM, "USBsetRAM"); + + LoadUSBsymX(async, "USBasync"); + + LoadUSBsym0(freeze, "USBfreeze"); + LoadUSBsym0(configure, "USBconfigure"); + LoadUSBsym0(about, "USBabout"); + LoadUSBsym0(test, "USBtest"); + + return 0; +} +void *FWplugin; + +s32 CALLBACK FW_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK FW_configure() {} +void CALLBACK FW_about() {} +long CALLBACK FW_test() { return 0; } + +#define LoadFWsym1(dest, name) \ + LoadSym(FW##dest, _FW##dest, name, 1); + +#define LoadFWsym0(dest, name) \ + LoadSym(FW##dest, _FW##dest, name, 0); \ + if (FW##dest == NULL) FW##dest = (_FW##dest) FW_##dest; + +int LoadFWplugin(char *filename) { + void *drv; + + FWplugin = SysLoadLibrary(filename); + if (FWplugin == NULL) { SysMessage (_("Could Not Load FW Plugin '%s': %s"), filename, SysLibError()); return -1; } + drv = FWplugin; + TestPS2Esyms(FW); + LoadFWsym1(init, "FWinit"); + LoadFWsym1(shutdown, "FWshutdown"); + LoadFWsym1(open, "FWopen"); + LoadFWsym1(close, "FWclose"); + LoadFWsym1(read32, "FWread32"); + LoadFWsym1(write32, "FWwrite32"); + LoadFWsym1(irqCallback, "FWirqCallback"); + + LoadFWsym0(freeze, "FWfreeze"); + LoadFWsym0(configure, "FWconfigure"); + LoadFWsym0(about, "FWabout"); + LoadFWsym0(test, "FWtest"); + + return 0; +} +static int loadp=0; + +int InitPlugins() { + int ret; + + if( GSsetBaseMem ) { + + if( CHECK_MULTIGS ) { + extern u8 g_MTGSMem[]; + GSsetBaseMem(g_MTGSMem); + } + else { + GSsetBaseMem(PS2MEM_GS); + } + } + + ret = GSinit(); + if (ret != 0) { SysMessage (_("GSinit error: %d"), ret); return -1; } + ret = PAD1init(1); + if (ret != 0) { SysMessage (_("PAD1init error: %d"), ret); return -1; } + ret = PAD2init(2); + if (ret != 0) { SysMessage (_("PAD2init error: %d"), ret); return -1; } + ret = SPU2init(); + if (ret != 0) { SysMessage (_("SPU2init error: %d"), ret); return -1; } + ret = CDVDinit(); + if (ret != 0) { SysMessage (_("CDVDinit error: %d"), ret); return -1; } + ret = DEV9init(); + if (ret != 0) { SysMessage (_("DEV9init error: %d"), ret); return -1; } + ret = USBinit(); + if (ret != 0) { SysMessage (_("USBinit error: %d"), ret); return -1; } + ret = FWinit(); + if (ret != 0) { SysMessage (_("FWinit error: %d"), ret); return -1; } + return 0; +} + +void ShutdownPlugins() { + GSshutdown(); + PAD1shutdown(); + PAD2shutdown(); + SPU2shutdown(); + CDVDshutdown(); + DEV9shutdown(); + USBshutdown(); + FWshutdown(); +} + +int LoadPlugins() { + char Plugin[256]; + + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.GS); + if (LoadGSplugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.PAD1); + if (LoadPAD1plugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.PAD2); + if (LoadPAD2plugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.SPU2); + if (LoadSPU2plugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.CDVD); + if (LoadCDVDplugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.DEV9); + if (LoadDEV9plugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.USB); + if (LoadUSBplugin(Plugin) == -1) return -1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.FW); + if (LoadFWplugin(Plugin) == -1) return -1; + if (InitPlugins() == -1) return -1; + + loadp=1; + + return 0; +} + +uptr pDsp; +static pluginsopened = 0; +extern void spu2DMA4Irq(); +extern void spu2DMA7Irq(); +extern void spu2Irq(); + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +extern HANDLE g_hGSOpen, g_hGSDone; +#else +extern pthread_mutex_t g_mutexGsThread; +extern pthread_cond_t g_condGsEvent; +extern sem_t g_semGsThread; +#endif + +int OpenPlugins(const char* pTitleFilename) { + GSdriverInfo info; + int ret; + + if (loadp == 0) return -1; + +#ifndef _WIN32 + // change dir so that CDVD can find its config file + char file[255], pNewTitle[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + + if( pTitleFilename != NULL && pTitleFilename[0] != '/' ) { + // because we are changing the dir, we have to set a new title if it is a relative dir + sprintf(pNewTitle, "%s/%s", file, pTitleFilename); + pTitleFilename = pNewTitle; + } +#endif + + //first we need the data + if (CDVDnewDiskCB) CDVDnewDiskCB(cdvdNewDiskCB); + + ret = CDVDopen(pTitleFilename); + + if (ret != 0) { SysMessage (_("Error Opening CDVD Plugin")); goto OpenError; } + cdvdNewDiskCB(); + + //video + GSirqCallback(gsIrq); + + // make sure only call open once per instance + if( !pluginsopened ) { + if( CHECK_MULTIGS ) { +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + SetEvent(g_hGSOpen); + WaitForSingleObject(g_hGSDone, INFINITE); +#else + pthread_cond_signal(&g_condGsEvent); + sem_wait(&g_semGsThread); + pthread_mutex_lock(&g_mutexGsThread); + pthread_mutex_unlock(&g_mutexGsThread); SysPrintf("MTGS thread unlocked\n"); +#endif + } + else { + ret = GSopen((void *)&pDsp, "PCSX2", 0); + if (ret != 0) { SysMessage (_("Error Opening GS Plugin")); goto OpenError; } + } + } + + //then the user input + if (GSgetDriverInfo) { + GSgetDriverInfo(&info); + if (PAD1gsDriverInfo) PAD1gsDriverInfo(&info); + if (PAD2gsDriverInfo) PAD2gsDriverInfo(&info); + } + ret = PAD1open((void *)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening PAD1 Plugin")); goto OpenError; } + ret = PAD2open((void *)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening PAD2 Plugin")); goto OpenError; } + + //the sound + + SPU2irqCallback(spu2Irq,spu2DMA4Irq,spu2DMA7Irq); + if( SPU2setDMABaseAddr != NULL ) + SPU2setDMABaseAddr((uptr)PSXM(0)); + + if(SPU2setClockPtr != NULL) + SPU2setClockPtr(&psxRegs.cycle); + + ret = SPU2open((void*)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening SPU2 Plugin")); goto OpenError; } + + //and last the dev9 + DEV9irqCallback(dev9Irq); + dev9Handler = DEV9irqHandler(); + ret = DEV9open(&(psxRegs.pc)); //((void *)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening DEV9 Plugin")); goto OpenError; } + + USBirqCallback(usbIrq); + usbHandler = USBirqHandler(); + USBsetRAM(psxM); + ret = USBopen((void *)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening USB Plugin")); goto OpenError; } + + FWirqCallback(fwIrq); + ret = FWopen((void *)&pDsp); + if (ret != 0) { SysMessage (_("Error Opening FW Plugin")); goto OpenError; } + + pluginsopened = 1; +#ifdef __LINUX__ + chdir(file); +#endif + return 0; + +OpenError: +#ifdef __LINUX__ + chdir(file); +#endif + + return -1; +} + +extern void gsWaitGS(); + +void ClosePlugins() +{ + gsWaitGS(); + + CDVDclose(); + DEV9close(); + USBclose(); + FWclose(); + SPU2close(); + PAD1close(); + PAD2close(); +} + +void ResetPlugins() { + gsWaitGS(); + + ShutdownPlugins(); + InitPlugins(); +} + +void ReleasePlugins() { + if (loadp == 0) return; + + if (GSplugin == NULL || PAD1plugin == NULL || PAD2plugin == NULL || + SPU2plugin == NULL || CDVDplugin == NULL || DEV9plugin == NULL || + USBplugin == NULL || FWplugin == NULL) return; + + ShutdownPlugins(); + + SysCloseLibrary(GSplugin); GSplugin = NULL; + SysCloseLibrary(PAD1plugin); PAD1plugin = NULL; + SysCloseLibrary(PAD2plugin); PAD2plugin = NULL; + SysCloseLibrary(SPU2plugin); SPU2plugin = NULL; + SysCloseLibrary(CDVDplugin); CDVDplugin = NULL; + SysCloseLibrary(DEV9plugin); DEV9plugin = NULL; + SysCloseLibrary(USBplugin); USBplugin = NULL; + SysCloseLibrary(FWplugin); FWplugin = NULL; + loadp=0; +} diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h new file mode 100644 index 0000000000..cb62404680 --- /dev/null +++ b/pcsx2/Plugins.h @@ -0,0 +1,32 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PLUGINS_H__ +#define __PLUGINS_H__ + +#define PLUGINtypedefs +#define PLUGINfuncs +#include "PS2Edefs.h" + +int LoadPlugins(); +void ReleasePlugins(); +int OpenPlugins(const char* pTitleFilename); +void ClosePlugins(); +void ResetPlugins(); + +#endif /* __PLUGINS_H__ */ diff --git a/pcsx2/PsxBios.c b/pcsx2/PsxBios.c new file mode 100644 index 0000000000..24fecad1d3 --- /dev/null +++ b/pcsx2/PsxBios.c @@ -0,0 +1,300 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include "PsxCommon.h" + +char *biosA0n[256] = { +// 0x00 + "open", "lseek", "read", "write", + "close", "ioctl", "exit", "sys_a0_07", + "getc", "putc", "todigit", "atof", + "strtoul", "strtol", "abs", "labs", +// 0x10 + "atoi", "atol", "atob", "setjmp", + "longjmp", "strcat", "strncat", "strcmp", + "strncmp", "strcpy", "strncpy", "strlen", + "index", "rindex", "strchr", "strrchr", +// 0x20 + "strpbrk", "strspn", "strcspn", "strtok", + "strstr", "toupper", "tolower", "bcopy", + "bzero", "bcmp", "memcpy", "memset", + "memmove", "memcmp", "memchr", "rand", +// 0x30 + "srand", "qsort", "strtod", "malloc", + "free", "lsearch", "bsearch", "calloc", + "realloc", "InitHeap", "_exit", "getchar", + "putchar", "gets", "puts", "printf", +// 0x40 + "sys_a0_40", "LoadTest", "Load", "Exec", + "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram", + "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets", + "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f", +// 0x50 + "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53", + "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57", + "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init", + "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open", +// 0x60 + "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile", + "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write", + "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", + "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", +// 0x70 + "_bu_init", "_96_init", "_96_remove", "sys_a0_73", + "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", + "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", + "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", +// 0x80 + "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83", + "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87", + "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b", + "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", +// 0x90 + "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", + "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", + "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", + "SetConf", "GetConf", "sys_a0_9e", "SetMem", +// 0xa0 + "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr", + "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0", + "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info", + "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af", +// 0xb0 + "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3", + "?? sub_function", +}; + +char *biosB0n[256] = { +// 0x00 + "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", + "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", + "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", + "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", +// 0x10 + "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", + "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", + "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", + "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", +// 0x20 + "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23", + "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27", + "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b", + "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f", +// 0x30 + "sys_b0_30", "sys_b0_31", "open", "lseek", + "read", "write", "close", "ioctl", + "exit", "sys_b0_39", "getc", "putc", + "getchar", "putchar", "gets", "puts", +// 0x40 + "cd", "format", "firstfile", "nextfile", + "rename", "delete", "undelete", "AddDevice", + "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD", + "StopCARD", "sys_b0_4d", "_card_write", "_card_read", +// 0x50 + "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53", + "_get_errno", "_get_error", "GetC0Table", "GetB0Table", + "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD", + "_card_status", "_card_wait", +}; + +char *biosC0n[256] = { +// 0x00 + "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP", + "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler", + "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError", + "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f", +// 0x10 + "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut", + "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc", + "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect", + "PatchAOTable", +}; + +//#define r0 (psxRegs.GPR.n.r0) +#define at (psxRegs.GPR.n.at) +#define v0 (psxRegs.GPR.n.v0) +#define v1 (psxRegs.GPR.n.v1) +#define a0 (psxRegs.GPR.n.a0) +#define a1 (psxRegs.GPR.n.a1) +#define a2 (psxRegs.GPR.n.a2) +#define a3 (psxRegs.GPR.n.a3) +#define t0 (psxRegs.GPR.n.t0) +#define t1 (psxRegs.GPR.n.t1) +#define t2 (psxRegs.GPR.n.t2) +#define t3 (psxRegs.GPR.n.t3) +#define t4 (psxRegs.GPR.n.t4) +#define t5 (psxRegs.GPR.n.t5) +#define t6 (psxRegs.GPR.n.t6) +#define t7 (psxRegs.GPR.n.t7) +#define s0 (psxRegs.GPR.n.s0) +#define s1 (psxRegs.GPR.n.s1) +#define s2 (psxRegs.GPR.n.s2) +#define s3 (psxRegs.GPR.n.s3) +#define s4 (psxRegs.GPR.n.s4) +#define s5 (psxRegs.GPR.n.s5) +#define s6 (psxRegs.GPR.n.s6) +#define s7 (psxRegs.GPR.n.s7) +#define t8 (psxRegs.GPR.n.t6) +#define t9 (psxRegs.GPR.n.t7) +#define k0 (psxRegs.GPR.n.k0) +#define k1 (psxRegs.GPR.n.k1) +#define gp (psxRegs.GPR.n.gp) +#define sp (psxRegs.GPR.n.sp) +#define fp (psxRegs.GPR.n.s8) +#define ra (psxRegs.GPR.n.ra) +#define pc0 (psxRegs.pc) + +#define Ra0 ((char*)PSXM(a0)) +#define Ra1 ((char*)PSXM(a1)) +#define Ra2 ((char*)PSXM(a2)) +#define Ra3 ((char*)PSXM(a3)) +#define Rv0 ((char*)PSXM(v0)) +#define Rsp ((char*)PSXM(sp)) + +void bios_write() { // 0x35/0x03 + + + if (a0 == 1) { // stdout + char *ptr = Ra1; + + while (a2 > 0) { + SysPrintf(COLOR_RED "%c" COLOR_RESET, *ptr++); a2--; + } + pc0 = ra; return; + } +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("bios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2); +#endif + + v0 = -1; + + pc0 = ra; +} + +void bios_printf() { // 3f + char tmp[1024]; + char tmp2[1024]; + unsigned long save[4]; + char *ptmp = tmp; + int n=1, i=0, j; + + memcpy(save, (char*)PSXM(sp), 4*4); + psxMu32(sp) = a0; + psxMu32(sp + 4) = a1; + psxMu32(sp + 8) = a2; + psxMu32(sp + 12) = a3; + + while (Ra0[i]) { + switch (Ra0[i]) { + case '%': + j = 0; + tmp2[j++] = '%'; +_start: + switch (Ra0[++i]) { + case '.': + case 'l': + tmp2[j++] = Ra0[i]; goto _start; + default: + if (Ra0[i] >= '0' && Ra0[i] <= '9') { + tmp2[j++] = Ra0[i]; + goto _start; + } + break; + } + tmp2[j++] = Ra0[i]; + tmp2[j] = 0; + + switch (Ra0[i]) { + case 'f': case 'F': + ptmp+= sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break; + case 'a': case 'A': + case 'e': case 'E': + case 'g': case 'G': + ptmp+= sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break; + case 'p': + case 'i': + case 'd': case 'D': + case 'o': case 'O': + case 'x': case 'X': + ptmp+= sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break; + case 'c': + ptmp+= sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break; + case 's': + ptmp+= sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break; + case '%': + *ptmp++ = Ra0[i]; break; + } + i++; + break; + default: + *ptmp++ = Ra0[i++]; + } + } + *ptmp = 0; + + memcpy((char*)PSXM(sp), save, 4*4); + + SysPrintf(COLOR_RED "%s" COLOR_RESET, tmp); + + pc0 = ra; +} + +void bios_putchar () { // 3d + char tmp[12]; + + sprintf (tmp,"%c",(char)a0); + SysPrintf(tmp); + + pc0 = ra; +} + +void bios_puts () { // 3e/3f + SysPrintf(Ra0); + + pc0 = ra; +} + +void (*biosA0[256])(); +void (*biosB0[256])(); +void (*biosC0[256])(); + +void psxBiosInit() { + int i; + + for(i = 0; i < 256; i++) { + biosA0[i] = NULL; + biosB0[i] = NULL; + biosC0[i] = NULL; + } + biosA0[0x3e] = bios_puts; + biosA0[0x3f] = bios_printf; + + biosB0[0x3d] = bios_putchar; + biosB0[0x3f] = bios_puts; + +} + +void psxBiosShutdown() { +} + diff --git a/pcsx2/PsxBios.h b/pcsx2/PsxBios.h new file mode 100644 index 0000000000..43f533c60c --- /dev/null +++ b/pcsx2/PsxBios.h @@ -0,0 +1,35 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXBIOS_H__ +#define __PSXBIOS_H__ + +extern char *biosA0n[256]; +extern char *biosB0n[256]; +extern char *biosC0n[256]; + +void psxBiosInit(); +void psxBiosShutdown(); +void psxBiosException(); +void psxBiosFreeze(int Mode); + +extern void (*biosA0[256])(); +extern void (*biosB0[256])(); +extern void (*biosC0[256])(); + +#endif /* __PSXBIOS_H__ */ diff --git a/pcsx2/PsxBios2.h b/pcsx2/PsxBios2.h new file mode 100644 index 0000000000..52e995b94a --- /dev/null +++ b/pcsx2/PsxBios2.h @@ -0,0 +1,94 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/***** sysmem imageInfo +00000800: 00 16 00 00 70 14 00 00 ¦ 01 01 00 00 01 00 00 00 +0000 next: .word ? //00001600 +0004 name: .word ? //00001470 +0008 version: .half ? //0101 +000A flags: .half ? //---- +000C index: .half ? //0001 +000E field_E: .half ? //---- +00000810: 90 08 00 00 A0 94 00 00 ¦ 30 08 00 00 40 0C 00 00 +0010 entry: .word ? //00000890 +0014 gp_value: .word ? //000094A0 +0018 p1_vaddr: .word ? //00000830 +001C text_size: .word ? //00000C40 +00000820: 40 00 00 00 10 00 00 00 ¦ 00 00 00 00 00 00 00 00 +0020 data_size: .word ? //00000040 +0024 bss_size: .word ? //00000010 +0028 field_28: .word ? //-------- +002C field_2C: .word ? //-------- +*****/ + +#ifndef __PSX_BIOS_H__ +#define __PSX_BIOS_H__ + +typedef struct { + u32 next, //+00 + name; //+04 + u16 version, //+08 + flags, //+0A + index, //+0C + _unkE; //+0E + u32 entry, //+10 + _gp, //+14 + vaddr, //+18 + text_size, //+1C + data_size, //+20 + bss_size, //+24 + _pad28, //+28 + _pad2C; //+2C +} irxImageInfo; //=30 + +typedef struct { + int active; + u32 server; + u32 fhandler; +} _sifServer; + +#define SIF_SERVERS 32 + +_sifServer sifServer[SIF_SERVERS]; + +// max modules/funcs + +#define IRX_MODULES 64 +#define IRX_FUNCS 256 + +typedef struct { + u32 num; + u32 entry; +} irxFunc; + +typedef struct { + int active; + u32 name[2]; + irxFunc funcs[IRX_FUNCS]; +} irxModule; + +irxModule irxMod[IRX_MODULES]; + + +void iopModulesInit(); +int iopSetImportFunc(u32 *ptr); +int iopSetExportFunc(u32 *ptr); +void sifServerCall(u32 server, u32 num, char *bin, int insize, char *bout, int outsize); +void sifAddServer(u32 server, u32 fhandler); + +#endif diff --git a/pcsx2/PsxCommon.h b/pcsx2/PsxCommon.h new file mode 100644 index 0000000000..315332717b --- /dev/null +++ b/pcsx2/PsxCommon.h @@ -0,0 +1,53 @@ +/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXCOMMON_H__ +#define __PSXCOMMON_H__ + +#include "PS2Etypes.h" + +#ifdef _WIN32 +#include +#endif + +#include + +#include "System.h" +#include + +extern long LoadCdBios; +extern int cdOpenCase; + +#define PSXCLK 36864000 /* 36.864 Mhz */ + +#include "Plugins.h" +#include "R3000A.h" +#include "PsxMem.h" +#include "PsxHw.h" +#include "PsxBios.h" +#include "PsxDma.h" +#include "PsxCounters.h" +#include "CdRom.h" +#include "Sio.h" +#include "DebugTools/Debug.h" +#include "PsxSio2.h" +#include "CDVD.h" +#include "Memory.h" +#include "Hw.h" +#include "Sif.h" + +#endif /* __PSXCOMMON_H__ */ diff --git a/pcsx2/PsxCounters.c b/pcsx2/PsxCounters.c new file mode 100644 index 0000000000..2f62f9d01f --- /dev/null +++ b/pcsx2/PsxCounters.c @@ -0,0 +1,801 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "PsxCommon.h" + +psxCounter psxCounters[8]; +u32 psxNextCounter, psxNextsCounter; +static int cnts = 6; +u8 psxhblankgate = 0; +u8 psxvblankgate = 0; +u8 psxcntmask = 0; + +static void psxRcntUpd16(u32 index) { + psxCounters[index].sCycleT = psxRegs.cycle; +} + +static void psxRcntUpd32(u32 index) { + psxCounters[index].sCycleT = psxRegs.cycle; +} + +static void psxRcntReset16(u32 index) { + psxCounters[index].count = 0; + + psxCounters[index].mode&= ~0x18301C00; + psxRcntUpd16(index); +} + +static void psxRcntReset32(u32 index) { + psxCounters[index].count = 0; + + psxCounters[index].mode&= ~0x18301C00; + psxRcntUpd32(index); +} + +static void psxRcntSet() { + u64 c; + int i; + + psxNextCounter = 0xffffffff; + psxNextsCounter = psxRegs.cycle; + + for (i=0; i<3; i++) { + if(psxCounters[i].rate == PSXHBLANK) continue; + c = (u64)((0x10000 - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + //if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; + c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + + } + for (i=3; i<6; i++) { + if(psxCounters[i].rate == PSXHBLANK) continue; + c = (u64)((0x100000000 - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + + //if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffffffff) continue; + c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + + } + + if(SPU2async) + { + c = (u32)(psxCounters[6].CycleT - (psxRegs.cycle - psxCounters[6].sCycleT)) ; + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + } + if(USBasync) + { + c = (u32)(psxCounters[7].CycleT - (psxRegs.cycle - psxCounters[7].sCycleT)) ; + if (c < psxNextCounter) { + psxNextCounter = (u32)c; + } + } +} + + +void psxRcntInit() { + int i; + + memset(psxCounters, 0, sizeof(psxCounters)); + + for (i=0; i<3; i++) { + psxCounters[i].rate = 1; + psxCounters[i].mode|= 0x0400; + psxCounters[i].target = 0x0; + } + for (i=3; i<6; i++) { + psxCounters[i].rate = 1; + psxCounters[i].mode|= 0x0400; + psxCounters[i].target = 0x0; + } + + psxCounters[0].interrupt = 0x10; + psxCounters[1].interrupt = 0x20; + psxCounters[2].interrupt = 0x40; + + psxCounters[3].interrupt = 0x04000; + psxCounters[4].interrupt = 0x08000; + psxCounters[5].interrupt = 0x10000; + + if (SPU2async != NULL) { + + + psxCounters[6].rate = 1; + psxCounters[6].CycleT = ((Config.Hacks & 0x4) ? 768 : 9216); + psxCounters[6].mode = 0x8; + } + + if (USBasync != NULL) { + psxCounters[7].rate = 1; + psxCounters[7].CycleT = PSXCLK/1000; + psxCounters[7].mode = 0x8; + } + + for (i=0; i<3; i++) + psxCounters[i].sCycleT = psxRegs.cycle; + for (i=3; i<6; i++) + psxCounters[i].sCycleT = psxRegs.cycle; + for (i=6; i<8; i++) + psxCounters[i].sCycleT = psxRegs.cycle; + + psxRcntSet(); +} + +void psxVSyncStart() { + cdvdVsync(); + psxHu32(0x1070)|= 1; + if(psxvblankgate & 1) psxCheckStartGate(1); + if(psxvblankgate & (1 << 3)) psxCheckStartGate(3); +} + +void psxVSyncEnd() { + psxHu32(0x1070)|= 0x800; + if(psxvblankgate & 1) psxCheckEndGate(1); + if(psxvblankgate & (1 << 3)) psxCheckEndGate(3); +} +void psxCheckEndGate(int counter) { //Check Gate events when Vsync Ends + int i = counter; + //SysPrintf("End Gate %x\n", counter); + if(counter < 3){ //Gates for 16bit counters + if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate + + switch((psxCounters[i].mode & 0x6) >> 1) { + case 0x0: //GATE_ON_count + psxCounters[i].count += (u16)psxRcntRcount16(i); //Only counts when signal is on + break; + case 0x1: //GATE_ON_ClearStart + if(psxCounters[i].mode & 0x10000000)psxRcntUpd16(i); + psxCounters[i].mode &= ~0x10000000; + break; + case 0x2: //GATE_ON_Clear_OFF_Start + psxCounters[i].mode &= ~0x10000000; + psxRcntUpd16(i); + break; + case 0x3: //GATE_ON_Start + break; + default: + SysPrintf("PCSX2 Warning: 16bit IOP Counter Gate Not Set!\n"); + break; + } + } + + if(counter >= 3){ //Gates for 32bit counters + if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate + + switch((psxCounters[i].mode & 0x6) >> 1) { + case 0x0: //GATE_ON_count + psxCounters[i].count += (u32)psxRcntRcount32(i); //Only counts when signal is on + break; + case 0x1: //GATE_ON_ClearStart + if(psxCounters[i].mode & 0x10000000)psxRcntUpd32(i); + psxCounters[i].mode &= ~0x10000000; + break; + case 0x2: //GATE_ON_Clear_OFF_Start + psxCounters[i].mode &= ~0x10000000; + psxRcntUpd32(i); + break; + case 0x3: //GATE_ON_Start + break; + default: + SysPrintf("PCSX2 Warning: 32bit IOP Counter Gate Not Set!\n"); + break; + } + } +} +void psxCheckStartGate(int counter) { //Check Gate events when Vsync Starts + int i = counter; + + if(counter == 0){ + if((psxCounters[1].mode & 0x101) == 0x100 || (psxCounters[1].mode & 0x10000101) == 0x101)psxCounters[1].count++; + if((psxCounters[3].mode & 0x101) == 0x100 || (psxCounters[3].mode & 0x10000101) == 0x101)psxCounters[3].count++; + /*if(SPU2async) + { + SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + //SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + psxCounters[6].sCycleT = psxRegs.cycle; + }*/ + } + + if(counter < 3){ //Gates for 16bit counters + if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate + //SysPrintf("PSX Gate %x\n", i); + switch((psxCounters[i].mode & 0x6) >> 1) { + case 0x0: //GATE_ON_count + psxRcntUpd32(i); + psxCounters[i].mode |= 0x10000000; + break; + case 0x1: //GATE_ON_ClearStart + if(psxCounters[i].mode & 0x10000000)psxRcntUpd16(i); + psxCounters[i].mode &= ~0x10000000; + break; + case 0x2: //GATE_ON_Clear_OFF_Start + psxRcntReset32(i); + psxCounters[i].mode |= 0x10000000; + break; + case 0x3: //GATE_ON_Start + psxCounters[i].mode &= ~0x10000000; + break; + default: + SysPrintf("PCSX2 Warning: 16bit IOP Counter Gate Not Set!\n"); + break; + } + } + + if(counter >= 3){ //Gates for 32bit counters + if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate + //SysPrintf("PSX Gate %x\n", i); + switch((psxCounters[i].mode & 0x6) >> 1) { + case 0x0: //GATE_ON_count + psxRcntUpd32(i); + psxCounters[i].mode &= ~0x10000000; + break; + case 0x1: //GATE_ON_ClearStart + if(psxCounters[i].mode & 0x10000000)psxRcntUpd32(i); + psxCounters[i].mode &= ~0x10000000; + break; + case 0x2: //GATE_ON_Clear_OFF_Start + psxRcntReset32(i); + psxCounters[i].mode |= 0x10000000; + break; + case 0x3: //GATE_ON_Start + psxCounters[i].mode &= ~0x10000000; + break; + default: + SysPrintf("PCSX2 Warning: 32bit IOP Counter Gate Not Set!\n"); + break; + } + } +} + +void _testRcnt16target(int i) { + +#ifdef PSXCNT_LOG + PSXCNT_LOG("[%d] target %x >= %x (CycleT); count=%I64x, target=%I64x, mode=%I64x\n", i, (psxRegs.cycle - psxCounters[i].sCycleT), psxCounters[i].CycleT, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); +#endif + + if(psxCounters[i].target > 0xffff) { + psxCounters[i].target &= 0xffff; + //SysPrintf("IOP 16 Correcting target target %x\n", psxCounters[i].target); + } + + if (psxCounters[i].mode & 0x10){ + if(psxCounters[i].mode & 0x80)psxCounters[i].mode&= ~0x0400; // Interrupt flag + psxCounters[i].mode|= 0x0800; // Target flag + } + + + + if (psxCounters[i].mode & 0x10) { // Target interrupt + psxHu32(0x1070)|= psxCounters[i].interrupt; + } + + if (psxCounters[i].mode & 0x08) { // Reset on target + psxCounters[i].count -= psxCounters[i].target; + if((psxCounters[i].mode & 0x40) == 0){ + SysPrintf("Counter %x repeat intr not set on zero ret, ignoring target\n", i); + psxCounters[i].target += 0x1000000000; + } + + } else psxCounters[i].target += 0x1000000000; + +} + +void _testRcnt16overflow(int i) { + +#ifdef PSXCNT_LOG + PSXCNT_LOG("[%d] overflow 0x%x >= 0x%x (Cycle); Rcount=0x%x, count=0x%x\n", i, (psxRegs.cycle - psxCounters[i].sCycle) / psxCounters[i].rate, psxCounters[i].Cycle, psxRcntRcount16(i), psxCounters[i].count); +#endif + + + if (psxCounters[i].mode & 0x0020) { // Overflow interrupt + psxHu32(0x1070)|= psxCounters[i].interrupt; + psxCounters[i].mode|= 0x1000; // Overflow flag + if(psxCounters[i].mode & 0x80){ + + psxCounters[i].mode&= ~0x0400; // Interrupt flag + } + //SysPrintf("Overflow 16\n"); + } + psxCounters[i].count -= 0x10000; + psxRcntUpd16(i); + if(psxCounters[i].target > 0xffff) { + if((psxCounters[i].mode & 0x50) <= 0x40 && (psxCounters[i].mode & 0x50) != 0) SysPrintf("Counter %x overflowing, no repeat interrupt mode = %x\n", i, psxCounters[i].mode); + psxCounters[i].target &= 0xffff; + //SysPrintf("IOP 16 Correcting target ovf %x\n", psxCounters[i].target); + } +} + +void _testRcnt32target(int i) { + +#ifdef PSXCNT_LOG + PSXCNT_LOG("[%d] target %x >= %x (CycleT); count=%I64x, target=%I64x, mode=%I64x\n", i, (psxRegs.cycle - psxCounters[i].sCycleT), psxCounters[i].CycleT, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); +#endif + if(psxCounters[i].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target on target reset\n"); + psxCounters[i].target &= 0xffffffff; + } + + +// newtarget[i] = 0; + + + if (psxCounters[i].mode & 0x10){ + if(psxCounters[i].mode & 0x80)psxCounters[i].mode&= ~0x0400; // Interrupt flag + psxCounters[i].mode|= 0x0800; // Target flag + } + + + if (psxCounters[i].mode & 0x10) { // Target interrupt + psxHu32(0x1070)|= psxCounters[i].interrupt; + + } + + if (psxCounters[i].mode & 0x08) { // Reset on target + psxCounters[i].count -= psxCounters[i].target; + if((psxCounters[i].mode & 0x40) == 0){ + SysPrintf("Counter %x repeat intr not set on zero ret, ignoring target\n", i); + psxCounters[i].target += 0x1000000000; + } + + } else psxCounters[i].target += 0x1000000000; + +} + +void _testRcnt32overflow(int i) { + +#ifdef PSXCNT_LOG + PSXCNT_LOG("[%d] overflow 0x%x >= 0x%x (Cycle); Rcount=0x%x, count=0x%x\n", i, (psxRegs.cycle - psxCounters[i].sCycle), psxCounters[i].Cycle, psxRcntRcount32(i), psxCounters[i].count); +#endif + //SysPrintf("Overflow 32\n"); + if (psxCounters[i].mode & 0x0020) { // Overflow interrupt + psxHu32(0x1070)|= psxCounters[i].interrupt; + psxCounters[i].mode|= 0x1000; // Overflow flag + if(psxCounters[i].mode & 0x80){ + + psxCounters[i].mode&= ~0x0400; // Interrupt flag + } + } + psxCounters[i].count -= 0x100000000; + if(psxCounters[i].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target on overflow\n"); + if((psxCounters[i].mode & 0x50) <= 0x40 && (psxCounters[i].mode & 0x50) != 0) SysPrintf("Counter %x overflowing, no repeat interrupt mode = %x\n", i, psxCounters[i].mode); + psxCounters[i].target &= 0xffffffff; + } +} + + +void _testRcnt16(int i) { + + if (/*psxCounters[i].target > 0 &&*/ (s64)(psxCounters[i].target - psxCounters[i].count) <= 0){ + _testRcnt16target(i); + } + if (psxCounters[i].count > 0xffff) + _testRcnt16overflow(i); +} + +void _testRcnt32(int i) { + + if (/*psxCounters[i].target > 0 && */(s64)(psxCounters[i].target - psxCounters[i].count) <= 0){ + _testRcnt32target(i); + } + if (psxCounters[i].count > 0xffffffff) + _testRcnt32overflow(i); + + +} +extern int spu2interrupts[2]; +void psxRcntUpdate() { + int i; + u32 change = 0; + + for (i=0; i<=5; i++) { + if((psxCounters[i].mode & 0x1) != 0 || psxCounters[i].rate == PSXHBLANK){ + //SysPrintf("Stopped accidental update of psx counter %x when using a gate\hblank source\n", i); + continue; + } + + change = psxRegs.cycle - psxCounters[i].sCycleT; + psxCounters[i].count += change / psxCounters[i].rate; + if(psxCounters[i].rate != 1){ + change -= (change / psxCounters[i].rate) * psxCounters[i].rate; + psxCounters[i].sCycleT = psxRegs.cycle - change; + //if(change > 0) SysPrintf("PSX Change saved on %x = %x\n", i, change); + } else psxCounters[i].sCycleT = psxRegs.cycle; + } + + _testRcnt16(0); + _testRcnt16(1); + _testRcnt16(2); + _testRcnt32(3); + _testRcnt32(4); + _testRcnt32(5); + + + if(SPU2async) + { + if((psxRegs.cycle - psxCounters[6].sCycleT) >= psxCounters[6].CycleT){ + SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + //SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = ((Config.Hacks & 0x4) ? 768 : 9216); + } + } + + if(USBasync) + { + if ((psxRegs.cycle - psxCounters[7].sCycleT) >= psxCounters[7].CycleT) { + USBasync(psxRegs.cycle - psxCounters[7].sCycleT); + psxCounters[7].sCycleT = psxRegs.cycle; + } + } + + psxRcntSet(); +} + +void psxRcntWcount16(int index, u32 value) { + u32 change = 0; +#ifdef PSXCNT_LOG + PSXCNT_LOG("writeCcount[%d] = %x\n", index, value); +#endif + + change = psxRegs.cycle - psxCounters[index].sCycleT; + //psxCounters[i].count += change / psxCounters[i].rate; + if(psxCounters[index].rate != 1){ + change -= (change / psxCounters[index].rate) * psxCounters[index].rate; + psxCounters[index].sCycleT = psxRegs.cycle - change; + if(change > 0) SysPrintf("PSX Change count write 16 %x = %x\n", index, change); + } + psxCounters[index].count = value & 0xffff; + if(psxCounters[index].target > 0xffff) { + //SysPrintf("IOP 16 Correcting target on count write\n"); + psxCounters[index].target &= 0xffff; + } + if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 16 IOP\n"); + psxRcntUpd16(index); + psxRcntSet(); +} + +void psxRcntWcount32(int index, u32 value) { + u32 change = 0; +#ifdef PSXCNT_LOG + PSXCNT_LOG("writeCcount[%d] = %x\n", index, value); +#endif + + change = psxRegs.cycle - psxCounters[index].sCycleT; + //psxCounters[i].count += change / psxCounters[i].rate; + if(psxCounters[index].rate != 1){ + change -= (change / psxCounters[index].rate) * psxCounters[index].rate; + psxCounters[index].sCycleT = psxRegs.cycle - change; + if(change > 0) SysPrintf("PSX Change count write 32 %x = %x\n", index, change); + } + psxCounters[index].count = value; + if(psxCounters[index].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target\n"); + psxCounters[index].target &= 0xffffffff; + } + if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 32 IOP\n"); + //psxRcntUpd32(index); + psxRcntSet(); +} + +void psxRcnt0Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[0] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 0 Value write %x\n", value & 0x1c00); + } + + psxCounters[0].mode = value; + psxCounters[0].mode|= 0x0400; + psxCounters[0].rate = 1; + + if(value & 0x100) { + //SysPrintf("Timer 0 Set to Pixel clock %x\n", value); + psxCounters[0].rate = PSXPIXEL; + }// else SysPrintf("Timer 0 Set to 1 %x\n", value); + + if(psxCounters[0].mode & 0x1){ + SysPrintf("Gate Check set on Counter 0 %x\n", value); + psxCounters[0].mode|= 0x1000000; + psxhblankgate |= 1; + }else + psxhblankgate &= ~1; + + psxCounters[0].count = 0; + psxRcntUpd16(0); + if(psxCounters[0].target > 0xffff) { + //SysPrintf("IOP 16 Correcting target 0 after mode write\n"); + psxCounters[0].target &= 0xffff; + } + psxRcntSet(); + //} +} + +void psxRcnt1Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[1] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 1 Value write %x\n", value & 0x1c00); + } + + psxCounters[1].mode = value; + psxCounters[1].mode|= 0x0400; + psxCounters[1].rate = 1; + + if(value & 0x100){ + //SysPrintf("Timer 1 Set to HBlank clock %x\n", value); + psxCounters[1].rate = PSXHBLANK; + }// else SysPrintf("Timer 1 Set to 1 clock %x\n", value); + + if(psxCounters[1].mode & 0x1){ + SysPrintf("Gate Check set on Counter 1 %x\n", value); + psxCounters[1].mode|= 0x1000000; + psxvblankgate |= 1<<1; + }else + psxvblankgate &= ~(1<<1); + + psxCounters[1].count = 0; + psxRcntUpd16(1); + if(psxCounters[1].target > 0xffff) { + //SysPrintf("IOP 16 Correcting target 1 after mode write\n"); + psxCounters[1].target &= 0xffff; + } + psxRcntSet(); + //} +} + +void psxRcnt2Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[2] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 2 Value write %x\n", value & 0x1c00); + } + + psxCounters[2].mode = value; + psxCounters[2].mode|= 0x0400; + + switch(value & 0x200){ + case 0x200: + //SysPrintf("Timer 2 Set to 8 %x\n", value); + psxCounters[2].rate = 8; + break; + case 0x000: + //SysPrintf("Timer 2 Set to 1 %x\n", value); + psxCounters[2].rate = 1; + break; + } + + if((psxCounters[2].mode & 0x7) == 0x7 || (psxCounters[2].mode & 0x7) == 0x1){ + //SysPrintf("Gate set on IOP C2, disabling\n"); + psxCounters[2].mode|= 0x1000000; + } + // Need to set a rate and target + psxCounters[2].count = 0; + psxRcntUpd16(2); + if(psxCounters[2].target > 0xffff) { + //SysPrintf("IOP 16 Correcting target 2 after mode write\n"); + psxCounters[2].target &= 0xffff; + } + psxRcntSet(); +} + +void psxRcnt3Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[3] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 3 Value write %x\n", value & 0x1c00); + } + + psxCounters[3].mode = value; + psxCounters[3].rate = 1; + psxCounters[3].mode|= 0x0400; + + if(value & 0x100){ + //SysPrintf("Timer 3 Set to HBLANK clock %x\n", value); + psxCounters[3].rate = PSXHBLANK; + }//else SysPrintf("Timer 3 Set to 1 %x\n", value); + + if(psxCounters[3].mode & 0x1){ + SysPrintf("Gate Check set on Counter 3\n"); + psxCounters[3].mode|= 0x1000000; + psxvblankgate |= 1<<3; + }else + psxvblankgate &= ~(1<<3); + + psxCounters[3].count = 0; + psxRcntUpd32(3); + if(psxCounters[3].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target 3 after mode write\n"); + psxCounters[3].target &= 0xffffffff; + } + psxRcntSet(); + //} +} + +void psxRcnt4Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[4] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 4 Value write %x\n", value & 0x1c00); + } + + psxCounters[4].mode = value; + psxCounters[4].mode|= 0x0400; + + switch(value & 0x6000){ + case 0x0000: + //SysPrintf("Timer 4 Set to 1 %x\n", value); + psxCounters[4].rate = 1; + break; + case 0x2000: + SysPrintf("Timer 4 Set to 8 %x\n", value); + psxCounters[4].rate = 8; + break; + case 0x4000: + SysPrintf("Timer 4 Set to 16 %x\n", value); + psxCounters[4].rate = 16; + break; + case 0x6000: + SysPrintf("Timer 4 Set to 256 %x\n", value); + psxCounters[4].rate = 256; + break; + } + // Need to set a rate and target + if((psxCounters[4].mode & 0x7) == 0x7 || (psxCounters[4].mode & 0x7) == 0x1){ + SysPrintf("Gate set on IOP C4, disabling\n"); + psxCounters[4].mode|= 0x1000000; + } + psxCounters[4].count = 0; + psxRcntUpd32(4); + if(psxCounters[4].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target 4 after mode write\n"); + psxCounters[4].target &= 0xffffffff; + } + psxRcntSet(); +} + +void psxRcnt5Wmode(u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("IOP writeCmode[5] = %lx\n", value); +#endif + + if (value & 0x1c00) { + SysPrintf("Counter 5 Value write %x\n", value & 0x1c00); + } + + psxCounters[5].mode = value; + psxCounters[5].mode|= 0x0400; + + switch(value & 0x6000){ + case 0x0000: + //SysPrintf("Timer 5 Set to 1 %x\n", value); + psxCounters[5].rate = 1; + break; + case 0x2000: + SysPrintf("Timer 5 Set to 8 %x\n", value); + psxCounters[5].rate = 8; + break; + case 0x4000: + SysPrintf("Timer 5 Set to 16 %x\n", value); + psxCounters[5].rate = 16; + break; + case 0x6000: + SysPrintf("Timer 5 Set to 256 %x\n", value); + psxCounters[5].rate = 256; + break; + } + // Need to set a rate and target + if((psxCounters[5].mode & 0x7) == 0x7 || (psxCounters[5].mode & 0x7) == 0x1){ + SysPrintf("Gate set on IOP C5, disabling\n"); + psxCounters[5].mode|= 0x1000000; + } + psxCounters[5].count = 0; + psxRcntUpd32(5); + if(psxCounters[5].target > 0xffffffff) { + //SysPrintf("IOP 32 Correcting target 5 after mode write\n"); + psxCounters[5].target &= 0xffffffff; + } + psxRcntSet(); +} + +void psxRcntWtarget16(int index, u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("writeCtarget16[%ld] = %lx\n", index, value); +#endif + psxCounters[index].target = value & 0xffff; + if(psxCounters[index].target <= psxRcntCycles(index)/* && psxCounters[index].target != 0*/) { + //SysPrintf("IOP 16 Saving %x target from early trigger target = %x, count = %I64x\n", index, psxCounters[index].target, psxRcntCycles(index)); + psxCounters[index].target += 0x1000000000; + } + + psxRcntSet(); +} + +void psxRcntWtarget32(int index, u32 value) { +#ifdef PSXCNT_LOG + PSXCNT_LOG("writeCtarget32[%ld] = %lx (count=%lx) ; sCycleT: %x CycleT: %x psxRegscycle %x\n", + index, value, psxCounters[index].count, psxCounters[index].sCycleT, psxCounters[index].CycleT, psxRegs.cycle); +#endif + + psxCounters[index].target = value; + if(psxCounters[index].target <= psxRcntCycles(index)/* && psxCounters[index].target != 0*/) { + //SysPrintf("IOP 32 Saving %x target from early trigger target = %x, count = %I64x\n", index, psxCounters[index].target, psxRcntCycles(index)); + psxCounters[index].target += 0x1000000000; + } + + psxRcntSet(); +} + +u16 psxRcntRcount16(int index) { + if(psxCounters[index].mode & 0x1000000) return (u16)psxCounters[index].count; + return (u16)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); +} + +u32 psxRcntRcount32(int index) { + if(psxCounters[index].mode & 0x1000000) return (u32)psxCounters[index].count; + return (u32)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); +} + +u64 psxRcntCycles(int index) { + if(psxCounters[index].mode & 0x1000000) return psxCounters[index].count; + return (u64)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); +} + +extern u32 dwCurSaveStateVer; +int psxRcntFreeze(gzFile f, int Mode) +{ + if( Mode == 0 && (dwCurSaveStateVer < 0x7a300010) ) { // reading + // struct used to be 32bit count and target + int i; + u32 val; + for(i = 0; i < ARRAYSIZE(psxCounters); ++i) { + gzfreeze(&val,4); psxCounters[i].count = val; + gzfreeze(&val,4); psxCounters[i].mode = val; + gzfreeze(&val,4); psxCounters[i].target = val; + gzfreeze((u8*)&psxCounters[i].rate, sizeof(psxCounters[i])-20); + } + } + else + gzfreezel(psxCounters); + + + return 0; +} diff --git a/pcsx2/PsxCounters.h b/pcsx2/PsxCounters.h new file mode 100644 index 0000000000..c0a1e2fea8 --- /dev/null +++ b/pcsx2/PsxCounters.h @@ -0,0 +1,56 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXCOUNTERS_H__ +#define __PSXCOUNTERS_H__ + +typedef struct { + u64 count, target; + u32 mode; + u32 rate, interrupt, otarget; + u32 sCycle, Cycle; + u32 sCycleT, CycleT; +} psxCounter; + +extern psxCounter psxCounters[8]; +extern u32 psxNextCounter, psxNextsCounter; + +void psxRcntInit(); +void psxRcntUpdate(); +void cntspu2async(); +void psxRcntWcount16(int index, u32 value); +void psxRcntWcount32(int index, u32 value); +void psxRcnt0Wmode(u32 value); +void psxRcnt1Wmode(u32 value); +void psxRcnt2Wmode(u32 value); +void psxRcnt3Wmode(u32 value); +void psxRcnt4Wmode(u32 value); +void psxRcnt5Wmode(u32 value); +void psxRcntWtarget16(int index, u32 value); +void psxRcntWtarget32(int index, u32 value); +u16 psxRcntRcount16(int index); +u32 psxRcntRcount32(int index); +u64 psxRcntCycles(int index); +int psxRcntFreeze(gzFile f, int Mode); + +void psxVSyncStart(); +void psxVSyncEnd(); +void psxCheckStartGate(int counter); +void psxCheckEndGate(int counter); + +#endif /* __PSXCOUNTERS_H__ */ diff --git a/pcsx2/PsxDma.c b/pcsx2/PsxDma.c new file mode 100644 index 0000000000..5b0d696963 --- /dev/null +++ b/pcsx2/PsxDma.c @@ -0,0 +1,289 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "PsxCommon.h" + +// Dma0/1 in Mdec.c +// Dma3 in CdRom.c +// Dma8 in PsxSpd.c +// Dma11/12 in PsxSio2.c +//static int spudmaenable[2]; +int spu2interrupts[2]; +int iopsifbusy[2] = { 0, 0 }; +void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU + int size; + + /*if(chcr & 0x400) SysPrintf("SPU 2 DMA 4 linked list chain mode! chcr = %x madr = %x bcr = %x\n", chcr, madr, bcr); + if(chcr & 0x40000000) SysPrintf("SPU 2 DMA 4 Unusual bit set on 'to' direction chcr = %x madr = %x bcr = %x\n", chcr, madr, bcr); + if((chcr & 0x1) == 0) SysPrintf("SPU 2 DMA 4 loading from spu2 memory chcr = %x madr = %x bcr = %x\n", chcr, madr, bcr); +*/ + + if(SPU2async) + { + //if((psxRegs.cycle - psxCounters[6].sCycleT) >= psxCounters[6].CycleT){ + SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + //SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = ((bcr >> 16) * (bcr & 0xFFFF)) * 3; + //} + psxNextCounter -= (psxRegs.cycle-psxNextsCounter); + psxNextsCounter = psxRegs.cycle; + if(psxCounters[6].CycleT < psxNextCounter) psxNextCounter = psxCounters[6].CycleT; + + } + + switch (chcr) { + case 0x01000201: //cpu to spu transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 4 - SPU mem2spu *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + //SysPrintf("DMA4 write blocks %x, size per block %x\n", (bcr >> 16), (bcr & 0xFFFF)); + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + SPU2writeDMA4Mem((u16 *)PSXM(madr), size*2); + break; + case 0x01000200: //spu to cpu transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 4 - SPU spu2mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + //SysPrintf("DMA4 read blocks %x, size per block %x\n", (bcr >> 16), (bcr & 0xFFFF)); + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + SPU2readDMA4Mem((u16 *)PSXM(madr), size*2); + psxCpu->Clear(HW_DMA4_MADR, size); + break; + + default: + SysPrintf("*** DMA 4 - SPU unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + break; + } + + //spudmaenable[0] = size; +} + +int psxDma4Interrupt() { + HW_DMA4_CHCR &= ~0x01000000; + psxDmaInterrupt(4); + psxHu32(0x1070)|= 1<<9; + return 1; +} + +void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU + HW_DMA2_CHCR &= ~0x01000000; + psxDmaInterrupt(2); +} + +void psxDma6(u32 madr, u32 bcr, u32 chcr) { + u32 *mem = (u32 *)PSXM(madr); + +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 6 - OT *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + if (chcr == 0x11000002) { + while (bcr--) { + *mem-- = (madr - 4) & 0xffffff; + madr -= 4; + } + mem++; *mem = 0xffffff; + } else { + // Unknown option +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 6 - OT unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + } + HW_DMA6_CHCR &= ~0x01000000; + psxDmaInterrupt(6); +} + +void psxDma7(u32 madr, u32 bcr, u32 chcr) { + int size; + + if(SPU2async) + { + //if((psxRegs.cycle - psxCounters[6].sCycleT) >= psxCounters[6].CycleT){ + SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + //SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = ((bcr >> 16) * (bcr & 0xFFFF)) * 3; + //} + psxNextCounter -= (psxRegs.cycle-psxNextsCounter); + psxNextsCounter = psxRegs.cycle; + if(psxCounters[6].CycleT < psxNextCounter) psxNextCounter = psxCounters[6].CycleT; + + } + + + switch (chcr) { + case 0x01000201: //cpu to spu2 transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 7 - SPU2 mem2spu *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + //SysPrintf("DMA7 write blocks %x, size per block %x\n", (bcr >> 16), (bcr & 0xFFFF)); + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + + SPU2writeDMA7Mem((u16 *)PSXM(madr), size*2); + break; + case 0x01000200: //spu2 to cpu transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 7 - SPU2 spu2mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + //SysPrintf("DMA4 read blocks %x, size per block %x\n", (bcr >> 16), (bcr & 0xFFFF)); + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + + SPU2readDMA7Mem((u16 *)PSXM(madr), size*2); + psxCpu->Clear(HW_DMA7_MADR, size); + break; + default: + SysPrintf("*** DMA 7 - SPU unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + break; + } + +} + +int psxDma7Interrupt() { + + HW_DMA7_CHCR &= ~0x01000000; + psxDmaInterrupt2(0); + return 1; + +} +extern int eesifbusy[2]; +void psxDma9(u32 madr, u32 bcr, u32 chcr) { + + DMACh *dma = (DMACh*)&PS2MEM_HW[0xc000]; + +#ifdef SIF_LOG + SIF_LOG("IOP: dmaSIF0 chcr = %lx, madr = %lx, bcr = %lx, tadr = %lx\n", chcr, madr, bcr, HW_DMA9_TADR); +#endif + + iopsifbusy[0] = 1; + psHu32(0x1000F240) |= 0x2000; + if (eesifbusy[0] == 1 && iopsifbusy[0] == 1) { + SIF0Dma(); + psHu32(0x1000F240) &= ~0x20; + psHu32(0x1000F240) &= ~0x2000; + } +} + +void psxDma10(u32 madr, u32 bcr, u32 chcr) { + DMACh *dma = (DMACh*)&PS2MEM_HW[0xc400]; + +#ifdef SIF_LOG + SIF_LOG("IOP: dmaSIF1 chcr = %lx, madr = %lx, bcr = %lx\n", chcr, madr, bcr); +#endif + + iopsifbusy[1] = 1; + psHu32(0x1000F240) |= 0x4000; + if (eesifbusy[1] == 1 && iopsifbusy[1] == 1) { + SIF1Dma(); + psHu32(0x1000F240) &= ~0x40; + psHu32(0x1000F240) &= ~0x100; + psHu32(0x1000F240) &= ~0x4000; + } +} + +void psxDma8(u32 madr, u32 bcr, u32 chcr) { + int size; + + switch (chcr & 0x01000201) { + case 0x01000201: //cpu to dev9 transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 8 - DEV9 mem2dev9 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + + DEV9writeDMA8Mem((u32*)PSXM(madr), size*8); + break; + case 0x01000200: //dev9 to cpu transfer +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 8 - DEV9 dev9mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + size = (bcr >> 16) * (bcr & 0xFFFF); // Number of blocks to transfer + + DEV9readDMA8Mem((u32*)PSXM(madr), size*8); + break; +#ifdef PSXDMA_LOG + default: + PSXDMA_LOG("*** DMA 8 - DEV9 unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + break; +#endif + } + HW_DMA8_CHCR &= ~0x01000000; + psxDmaInterrupt2(1); +} + +void dev9Interrupt() { + if (dev9Handler == NULL) goto irq; + if (dev9Handler() != 1) { + psxRegs.interrupt&= ~(1 << 20); + return; + } +irq: + psxHu32(0x1070)|= 1<<13; + //SBUS + hwIntcIrq(INTC_SBUS); + psxRegs.interrupt&= ~(1 << 20); +} + +void dev9Irq(int cycles) { + PSX_INT(20, cycles); +} + +void usbInterrupt() { + if (usbHandler == NULL) goto irq; + if (usbHandler() != 1) { + psxRegs.interrupt&= ~(1 << 21); + return; + } +irq: + psxHu32(0x1070)|= 1<<22; + //SBUS + hwIntcIrq(INTC_SBUS); + psxRegs.interrupt&= ~(1 << 21); +} + +void usbIrq(int cycles) { + PSX_INT(21, cycles); +} + +void fwIrq() { + psxHu32(0x1070)|= 1<<24; + //SBUS + hwIntcIrq(INTC_SBUS); +} + +void spu2DMA4Irq() { + SPU2interruptDMA4(); + //HW_DMA4_BCR = 0; + HW_DMA4_CHCR &= ~0x01000000; + psxDmaInterrupt(4); +} + +void spu2DMA7Irq() { + SPU2interruptDMA7(); + //HW_DMA7_BCR = 0; + HW_DMA7_CHCR &= ~0x01000000; + psxDmaInterrupt2(0); +} + +void spu2Irq() { + psxHu32(0x1070)|= 1<<9; + //SBUS + hwIntcIrq(INTC_SBUS); +} diff --git a/pcsx2/PsxDma.h b/pcsx2/PsxDma.h new file mode 100644 index 0000000000..702519f760 --- /dev/null +++ b/pcsx2/PsxDma.h @@ -0,0 +1,42 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXDMA_H__ +#define __PSXDMA_H__ + +void psxDma2(u32 madr, u32 bcr, u32 chcr); +void psxDma3(u32 madr, u32 bcr, u32 chcr); +void psxDma4(u32 madr, u32 bcr, u32 chcr); +void psxDma6(u32 madr, u32 bcr, u32 chcr); +void psxDma7(u32 madr, u32 bcr, u32 chcr); +void psxDma8(u32 madr, u32 bcr, u32 chcr); +void psxDma9(u32 madr, u32 bcr, u32 chcr); +void psxDma10(u32 madr, u32 bcr, u32 chcr); + +int psxDma4Interrupt(); +int psxDma7Interrupt(); +void dev9Interrupt(); +DEV9handler dev9Handler; +void dev9Irq(int cycles); +void usbInterrupt(); +USBhandler usbHandler; +void usbIrq(int cycles); +void fwIrq(); +void spu2Irq(); + +#endif /* __PSXDMA_H__ */ diff --git a/pcsx2/PsxHw.c b/pcsx2/PsxHw.c new file mode 100644 index 0000000000..d1c91660f4 --- /dev/null +++ b/pcsx2/PsxHw.c @@ -0,0 +1,1825 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "PsxCommon.h" +#include "Misc.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#endif + +// NOTE: Any modifications to read/write fns should also go into their const counterparts + +void psxHwReset() { +/* if (Config.Sio) psxHu32(0x1070) |= 0x80; + if (Config.SpuIrq) psxHu32(0x1070) |= 0x200;*/ + + memset(psxH, 0, 0x10000); + +// mdecInit(); //intialize mdec decoder + cdrReset(); + cdvdReset(); + psxRcntInit(); + sioInit(); +// sio2Reset(); +} + +u8 psxHwRead8(u32 add) { + u8 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread8(add); + } + + switch (add) { + case 0x1f801040: hard = sioRead8();break; + // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now + + case 0x1f80146e: // DEV9_R_REV + return DEV9read8(add); + +#ifdef PCSX2_DEVBUILD + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter read %x\n", add); + hard = psxHu8(add); + return hard; +#endif + + case 0x1f801800: hard = cdrRead0(); break; + case 0x1f801801: hard = cdrRead1(); break; + case 0x1f801802: hard = cdrRead2(); break; + case 0x1f801803: hard = cdrRead3(); break; + + case 0x1f803100: // PS/EE/IOP conf related + hard = 0x10; // Dram 2M + break; + + case 0x1F808264: + hard = sio2_fifoOut();//sio2 serial data feed/fifo_out +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read8 DATAOUT %08X\n", hard); +#endif + return hard; + + default: + hard = psxHu8(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 8bit read at address %lx\n", add); +#endif + return hard; + } + +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); +#endif + return hard; +} + +u16 psxHwRead16(u32 add) { + u16 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread16(add); + } + + switch (add) { +#ifdef PSXHW_LOG + case 0x1f801070: PSXHW_LOG("IREG 16bit read %x\n", psxHu16(0x1070)); + return psxHu16(0x1070); +#endif +#ifdef PSXHW_LOG + case 0x1f801074: PSXHW_LOG("IMASK 16bit read %x\n", psxHu16(0x1074)); + return psxHu16(0x1074); +#endif + + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f801044: + hard = sio.StatReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f801048: + hard = sio.ModeReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f80104a: + hard = sio.CtrlReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f80104e: + hard = sio.BaudReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + + //Serial port stuff not support now ;P + // case 0x1f801050: hard = serial_read16(); break; + // case 0x1f801054: hard = serial_status_read(); break; + // case 0x1f80105a: hard = serial_control_read(); break; + // case 0x1f80105e: hard = serial_baud_read(); break; + + case 0x1f801100: + hard = (u16)psxRcntRcount16(0); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; + psxCounters[0].mode &= ~0x1800; + psxCounters[0].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801108: + hard = psxCounters[0].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 target read16: %x\n", hard); +#endif + return hard; + case 0x1f801110: + hard = (u16)psxRcntRcount16(1); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; + psxCounters[1].mode &= ~0x1800; + psxCounters[1].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801118: + hard = psxCounters[1].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 target read16: %x\n", hard); +#endif + return hard; + case 0x1f801120: + hard = (u16)psxRcntRcount16(2); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; + psxCounters[2].mode &= ~0x1800; + psxCounters[2].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801128: + hard = psxCounters[2].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 target read16: %x\n", hard); +#endif + return hard; + + case 0x1f80146e: // DEV9_R_REV + return DEV9read16(add); + + case 0x1f801480: + hard = (u16)psxRcntRcount32(3); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 count read16: %lx\n", hard); +#endif + return hard; + case 0x1f801484: + hard = psxCounters[3].mode; + psxCounters[3].mode &= ~0x1800; + psxCounters[3].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 mode read16: %lx\n", hard); +#endif + return hard; + case 0x1f801488: + hard = psxCounters[3].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 target read16: %lx\n", hard); +#endif + return hard; + case 0x1f801490: + hard = (u16)psxRcntRcount32(4); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 count read16: %lx\n", hard); +#endif + return hard; + case 0x1f801494: + hard = psxCounters[4].mode; + psxCounters[4].mode &= ~0x1800; + psxCounters[4].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 mode read16: %lx\n", hard); +#endif + return hard; + case 0x1f801498: + hard = psxCounters[4].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 target read16: %lx\n", hard); +#endif + return hard; + case 0x1f8014a0: + hard = (u16)psxRcntRcount32(5); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 count read16: %lx\n", hard); +#endif + return hard; + case 0x1f8014a4: + hard = psxCounters[5].mode; + psxCounters[5].mode &= ~0x1800; + psxCounters[5].mode |= 0x400; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 mode read16: %lx\n", hard); +#endif + return hard; + case 0x1f8014a8: + hard = psxCounters[5].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 target read16: %lx\n", hard); +#endif + return hard; + + case 0x1f801504: + hard = psxHu16(0x1504); +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 BCR_size 16bit read %lx\n", hard); +#endif + return hard; + case 0x1f801506: + hard = psxHu16(0x1506); +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 BCR_count 16bit read %lx\n", hard); +#endif + return hard; + //case 0x1f802030: hard = //int_2000???? + //case 0x1f802040: hard =//dip switches...?? + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + hard = SPU2read(add); + } else { + hard = psxHu16(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 16bit read at address %lx\n", add); +#endif + } + return hard; + } + +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 16bit read at address %lx value %x\n", add, hard); +#endif + return hard; +} + +u32 psxHwRead32(u32 add) { + u32 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread32(add); + } + if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. + return FWread32(add); + } + + switch (add) { + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; + hard|= sioRead8() << 16; + hard|= sioRead8() << 24; +#ifdef PAD_LOG + PAD_LOG("sio read32 ;ret = %lx\n", hard); +#endif + return hard; + + // case 0x1f801050: hard = serial_read32(); break;//serial port +#ifdef PSXHW_LOG + case 0x1f801060: + PSXHW_LOG("RAM size read %lx\n", psxHu32(0x1060)); + return psxHu32(0x1060); +#endif +#ifdef PSXHW_LOG + case 0x1f801070: PSXHW_LOG("IREG 32bit read %x\n", psxHu32(0x1070)); + return psxHu32(0x1070); +#endif +#ifdef PSXHW_LOG + case 0x1f801074: PSXHW_LOG("IMASK 32bit read %x\n", psxHu32(0x1074)); + return psxHu32(0x1074); +#endif + case 0x1f801078: +#ifdef PSXHW_LOG + PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); +#endif + hard = psxHu32(0x1078); + psxHu32(0x1078) = 0; + return hard; + +/* case 0x1f801810: +// hard = GPU_readData(); +#ifdef PSXHW_LOG + PSXHW_LOG("GPU DATA 32bit read %lx\n", hard); +#endif + return hard;*/ +/* case 0x1f801814: + hard = GPU_readStatus(); +#ifdef PSXHW_LOG + PSXHW_LOG("GPU STATUS 32bit read %lx\n", hard); +#endif + return hard; +*/ +/* case 0x1f801820: hard = mdecRead0(); break; + case 0x1f801824: hard = mdecRead1(); break; +*/ +#ifdef PSXHW_LOG + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit read %lx\n", psxHu32(0x10a0)); + return HW_DMA2_MADR; + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit read %lx\n", psxHu32(0x10a4)); + return HW_DMA2_BCR; + case 0x1f8010a8: + PSXHW_LOG("DMA2 CHCR 32bit read %lx\n", psxHu32(0x10a8)); + return HW_DMA2_CHCR; +#endif + +#ifdef PSXHW_LOG + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit read %lx\n", psxHu32(0x10b0)); + return HW_DMA3_MADR; + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit read %lx\n", psxHu32(0x10b4)); + return HW_DMA3_BCR; + case 0x1f8010b8: + PSXHW_LOG("DMA3 CHCR 32bit read %lx\n", psxHu32(0x10b8)); + return HW_DMA3_CHCR; +#endif + +#ifdef PSXHW_LOG + case 0x1f801520: + PSXHW_LOG("DMA9 MADR 32bit read %lx\n", HW_DMA9_MADR); + return HW_DMA9_MADR; + case 0x1f801524: + PSXHW_LOG("DMA9 BCR 32bit read %lx\n", HW_DMA9_BCR); + return HW_DMA9_BCR; + case 0x1f801528: + PSXHW_LOG("DMA9 CHCR 32bit read %lx\n", HW_DMA9_CHCR); + return HW_DMA9_CHCR; + case 0x1f80152C: + PSXHW_LOG("DMA9 TADR 32bit read %lx\n", HW_DMA9_TADR); + return HW_DMA9_TADR; +#endif + +#ifdef PSXHW_LOG + case 0x1f801530: + PSXHW_LOG("DMA10 MADR 32bit read %lx\n", HW_DMA10_MADR); + return HW_DMA10_MADR; + case 0x1f801534: + PSXHW_LOG("DMA10 BCR 32bit read %lx\n", HW_DMA10_BCR); + return HW_DMA10_BCR; + case 0x1f801538: + PSXHW_LOG("DMA10 CHCR 32bit read %lx\n", HW_DMA10_CHCR); + return HW_DMA10_CHCR; +#endif + +// case 0x1f8010f0: PSXHW_LOG("DMA PCR 32bit read " << psxHu32(0x10f0)); +// return HW_DMA_PCR; // dma rest channel +#ifdef PSXHW_LOG + case 0x1f8010f4: + PSXHW_LOG("DMA ICR 32bit read %lx\n", HW_DMA_ICR); + return HW_DMA_ICR; +#endif +//SSBus registers + case 0x1f801000: + hard = psxHu32(0x1000); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801004: + hard = psxHu32(0x1004); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801008: + hard = psxHu32(0x1008); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f80100C: + hard = psxHu32(0x100C); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev1_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801010: + hard = psxHu32(0x1010); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS rom_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801014: + hard = psxHu32(0x1014); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801018: + hard = psxHu32(0x1018); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev5_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f80101C: + hard = psxHu32(0x101C); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801020: + hard = psxHu32(0x1020); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS com_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801400: + hard = psxHu32(0x1400); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev1_addr 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801404: + hard = psxHu32(0x1404); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu_addr 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801408: + hard = psxHu32(0x1408); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev5_addr 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f80140C: + hard = psxHu32(0x140C); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu1_addr 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801410: + hard = psxHu32(0x1410); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801414: + hard = psxHu32(0x1414); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu1_delay 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801418: + hard = psxHu32(0x1418); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f80141C: + hard = psxHu32(0x141C); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801420: + hard = psxHu32(0x1420); +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); +#endif + return hard; + + case 0x1f8010f0: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA PCR 32bit read %lx\n", HW_DMA_PCR); +#endif + return HW_DMA_PCR; + + case 0x1f8010c8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA4 CHCR 32bit read %lx\n", HW_DMA4_CHCR); +#endif + return HW_DMA4_CHCR; // DMA4 chcr (SPU DMA) + + // time for rootcounters :) + case 0x1f801100: + hard = (u16)psxRcntRcount16(0); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801104: + hard = (u16)psxCounters[0].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801108: + hard = psxCounters[0].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T0 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f801110: + hard = (u16)psxRcntRcount16(1); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801114: + hard = (u16)psxCounters[1].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801118: + hard = psxCounters[1].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T1 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f801120: + hard = (u16)psxRcntRcount16(2); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801124: + hard = (u16)psxCounters[2].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801128: + hard = psxCounters[2].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T2 target read32: %lx\n", hard); +#endif + return hard; + + case 0x1f801480: + hard = (u32)psxRcntRcount32(3); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801484: + hard = (u16)psxCounters[3].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801488: + hard = psxCounters[3].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T3 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f801490: + hard = (u32)psxRcntRcount32(4); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801494: + hard = (u16)psxCounters[4].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801498: + hard = psxCounters[4].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T4 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f8014a0: + hard = (u32)psxRcntRcount32(5); +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f8014a4: + hard = (u16)psxCounters[5].mode; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f8014a8: + hard = psxCounters[5].target; +#ifdef PSXCNT_LOG + PSXCNT_LOG("T5 target read32: %lx\n", hard); +#endif + return hard; + + case 0x1f801450: + hard = psxHu32(add); +#ifdef PSXHW_LOG + PSXHW_LOG("%08X ICFG 32bit read %x\n", psxRegs.pc, hard); +#endif + return hard; + + + case 0x1F8010C0: + HW_DMA4_MADR = SPU2ReadMemAddr(0); + return HW_DMA4_MADR; + + case 0x1f801500: + HW_DMA7_MADR = SPU2ReadMemAddr(1); +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 MADR 32bit read %lx\n", HW_DMA7_MADR); +#endif + return HW_DMA7_MADR; // DMA7 madr + case 0x1f801504: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 BCR 32bit read %lx\n", HW_DMA7_BCR); +#endif + return HW_DMA7_BCR; // DMA7 bcr + + case 0x1f801508: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 CHCR 32bit read %lx\n", HW_DMA7_CHCR); +#endif + return HW_DMA7_CHCR; // DMA7 chcr (SPU2) + + case 0x1f801570: + hard = psxHu32(0x1570); +#ifdef PSXHW_LOG + PSXHW_LOG("DMA PCR2 32bit read %lx\n", hard); +#endif + return hard; +#ifdef PSXHW_LOG + case 0x1f801574: + PSXHW_LOG("DMA ICR2 32bit read %lx\n", HW_DMA_ICR2); + return HW_DMA_ICR2; +#endif + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + hard=sio2_getSend3((add-0x1F808200)/4); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read param[%d] (%lx)\n", (add-0x1F808200)/4, hard); +#endif + return hard; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F80825C: + hard=sio2_getSend1((add-0x1F808240)/8); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read send1[%d] (%lx)\n", (add-0x1F808240)/8, hard); +#endif + return hard; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F808258: + hard=sio2_getSend2((add-0x1F808244)/8); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read send2[%d] (%lx)\n", (add-0x1F808244)/8, hard); +#endif + return hard; + + case 0x1F808268: + hard=sio2_getCtrl(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read CTRL (%lx)\n", hard); +#endif + return hard; + + case 0x1F80826C: + hard=sio2_getRecv1(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read Recv1 (%lx)\n", hard); +#endif + return hard; + + case 0x1F808270: + hard=sio2_getRecv2(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read Recv2 (%lx)\n", hard); +#endif + return hard; + + case 0x1F808274: + hard=sio2_getRecv3(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read Recv3 (%lx)\n", hard); +#endif + return hard; + + case 0x1F808278: + hard=sio2_get8278(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read [8278] (%lx)\n", hard); +#endif + return hard; + + case 0x1F80827C: + hard=sio2_get827C(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read [827C] (%lx)\n", hard); +#endif + return hard; + + case 0x1F808280: + hard=sio2_getIntr(); +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 read INTR (%lx)\n", hard); +#endif + return hard; + + default: + hard = psxHu32(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 32bit read at address %lx: %lx\n", add, hard); +#endif + return hard; + } +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 32bit read at address %lx: %lx\n", add, hard); +#endif + return hard; +} + +int g_pbufi; +s8 g_pbuf[1024]; + +#define DmaExec(n) { \ + if (HW_DMA##n##_CHCR & 0x01000000 && \ + HW_DMA_PCR & (8 << (n * 4))) { \ + psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ + } \ +} + +void psxHwWrite8(u32 add, u8 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite8(add, value); return; + } +#ifdef PCSX2_DEVBUILD + if((add & 0xf) == 0xa) SysPrintf("8bit write (possible chcr set) %x value %x\n", add, value); +#endif + switch (add) { + case 0x1f801040: + sioWrite8(value); + break; + // case 0x1f801050: serial_write8(value); break;//serial port + + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter write %x\n", add); + psxHu8(add) = value; + return; + case 0x1f801450: +#ifdef PSXHW_LOG + if (value) { PSXHW_LOG("%08X ICFG 8bit write %lx\n", psxRegs.pc, value); } +#endif + psxHu8(0x1450) = value; + return; + + case 0x1f801800: cdrWrite0(value); break; + case 0x1f801801: cdrWrite1(value); break; + case 0x1f801802: cdrWrite2(value); break; + case 0x1f801803: cdrWrite3(value); break; + + case 0x1f80380c: + if (value == '\r') break; + if (value == '\n' || g_pbufi >= 1023) { + g_pbuf[g_pbufi++] = 0; g_pbufi = 0; + SysPrintf("%s\n", g_pbuf); + } + else g_pbuf[g_pbufi++] = value; + psxHu8(add) = value; + return; + + case 0x1F808260: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write8 DATAIN <- %08X\n", value); +#endif + sio2_serialIn(value);return;//serial data feed/fifo + + default: + psxHu8(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); +#endif + return; + } + psxHu8(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); +#endif +} + +void psxHwWrite16(u32 add, u16 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite16(add, value); return; + } +#ifdef PCSX2_DEVBUILD + if((add & 0xf) == 0x9) SysPrintf("16bit write (possible chcr set) %x value %x\n", add, value); +#endif + switch (add) { + case 0x1f801040: + sioWrite8((u8)value); + sioWrite8((u8)(value>>8)); +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f801044: +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f801048: + sio.ModeReg = value; +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f80104a: // control register + sioWriteCtrl16(value); +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f80104e: // baudrate register + sio.BaudReg = value; +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + + //serial port ;P + // case 0x1f801050: serial_write16(value); break; + // case 0x1f80105a: serial_control_write(value);break; + // case 0x1f80105e: serial_baud_write(value); break; + // case 0x1f801054: serial_status_write(value); break; + + case 0x1f801070: +#ifdef PSXHW_LOG + PSXHW_LOG("IREG 16bit write %x\n", value); +#endif +// if (Config.Sio) psxHu16(0x1070) |= 0x80; +// if (Config.SpuIrq) psxHu16(0x1070) |= 0x200; + psxHu16(0x1070) &= value; + return; +#ifdef PSXHW_LOG + case 0x1f801074: PSXHW_LOG("IMASK 16bit write %x\n", value); + psxHu16(0x1074) = value; + return; +#endif + + case 0x1f8010c4: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA4 BCR_size 16bit write %lx\n", value); +#endif + psxHu16(0x10c4) = value; return; // DMA4 bcr_size + + case 0x1f8010c6: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA4 BCR_count 16bit write %lx\n", value); +#endif + psxHu16(0x10c6) = value; return; // DMA4 bcr_count + + case 0x1f801100: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount16(0, value); return; + case 0x1f801104: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 MODE 16bit write %x\n", value); +#endif + psxRcnt0Wmode(value); return; + case 0x1f801108: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget16(0, value); return; + + case 0x1f801110: +#ifdef PSXHW_LOG + PSXCNT_LOG("COUNTER 1 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount16(1, value); return; + case 0x1f801114: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 1 MODE 16bit write %x\n", value); +#endif + psxRcnt1Wmode(value); return; + case 0x1f801118: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 1 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget16(1, value); return; + + case 0x1f801120: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount16(2, value); return; + case 0x1f801124: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 MODE 16bit write %x\n", value); +#endif + psxRcnt2Wmode(value); return; + case 0x1f801128: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget16(2, value); return; + + case 0x1f801450: +#ifdef PSXHW_LOG + if (value) { PSXHW_LOG("%08X ICFG 16bit write %lx\n", psxRegs.pc, value); } +#endif + psxHu16(0x1450) = value/* & (~0x8)*/; + return; + + case 0x1f801480: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 COUNT 16bit write %lx\n", value); +#endif + psxRcntWcount32(3, value); return; + case 0x1f801484: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 MODE 16bit write %lx\n", value); +#endif + psxRcnt3Wmode(value); return; + case 0x1f801488: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 TARGET 16bit write %lx\n", value); +#endif + psxRcntWtarget32(3, value); return; + + case 0x1f801490: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 COUNT 16bit write %lx\n", value); +#endif + psxRcntWcount32(4, value); return; + case 0x1f801494: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 MODE 16bit write %lx\n", value); +#endif + psxRcnt4Wmode(value); return; + case 0x1f801498: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 TARGET 16bit write %lx\n", value); +#endif + psxRcntWtarget32(4, value); return; + + case 0x1f8014a0: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 COUNT 16bit write %lx\n", value); +#endif + psxRcntWcount32(5, value); return; + case 0x1f8014a4: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 MODE 16bit write %lx\n", value); +#endif + psxRcnt5Wmode(value); return; + case 0x1f8014a8: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 TARGET 16bit write %lx\n", value); +#endif + psxRcntWtarget32(5, value); return; + + case 0x1f801504: + psxHu16(0x1504) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 BCR_size 16bit write %lx\n", value); +#endif + return; + case 0x1f801506: + psxHu16(0x1506) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 BCR_count 16bit write %lx\n", value); +#endif + return; + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + SPU2write(add, value); + return; + } + + psxHu16(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 16bit write at address %lx value %x\n", add, value); +#endif + return; + } + psxHu16(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 16bit write at address %lx value %x\n", add, value); +#endif +} + +#define DmaExec2(n) { \ + if (HW_DMA##n##_CHCR & 0x01000000 && \ + HW_DMA_PCR2 & (8 << ((n-7) * 4))) { \ + psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ + } \ +} + +void psxHwWrite32(u32 add, u32 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite32(add, value); return; + } + if (add >= 0x1f808400 && add <= 0x1f808550) { + FWwrite32(add, value); return; + } + switch (add) { + case 0x1f801040: + sioWrite8((u8)value); + sioWrite8((u8)((value&0xff) >> 8)); + sioWrite8((u8)((value&0xff) >> 16)); + sioWrite8((u8)((value&0xff) >> 24)); +#ifdef PAD_LOG + PAD_LOG("sio write32 %lx\n", value); +#endif + return; + // case 0x1f801050: serial_write32(value); break;//serial port +#ifdef PSXHW_LOG + case 0x1f801060: + PSXHW_LOG("RAM size write %lx\n", value); + psxHu32(add) = value; + return; // Ram size +#endif + + case 0x1f801070: +#ifdef PSXHW_LOG + PSXHW_LOG("IREG 32bit write %lx\n", value); +#endif +// if (Config.Sio) psxHu32(0x1070) |= 0x80; +// if (Config.SpuIrq) psxHu32(0x1070) |= 0x200; + psxHu32(0x1070) &= value; + return; +#ifdef PSXHW_LOG + case 0x1f801074: + PSXHW_LOG("IMASK 32bit write %lx\n", value); + psxHu32(0x1074) = value; + return; + + case 0x1f801078: + PSXHW_LOG("ICTRL 32bit write %lx\n", value); +// SysPrintf("ICTRL 32bit write %lx\n", value); + psxHu32(0x1078) = value; + return; +#endif + + //SSBus registers + case 0x1f801000: + psxHu32(0x1000) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f801004: + psxHu32(0x1004) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f801008: + psxHu32(0x1008) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f80100C: + psxHu32(0x100C) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev1_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f801010: + psxHu32(0x1010) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS rom_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f801014: + psxHu32(0x1014) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f801018: + psxHu32(0x1018) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev5_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f80101C: + psxHu32(0x101C) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f801020: + psxHu32(0x1020) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS com_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f801400: + psxHu32(0x1400) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev1_addr 32bit write %lx\n", value); +#endif + return; + case 0x1f801404: + psxHu32(0x1404) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu_addr 32bit write %lx\n", value); +#endif + return; + case 0x1f801408: + psxHu32(0x1408) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS dev5_addr 32bit write %lx\n", value); +#endif + return; + case 0x1f80140C: + psxHu32(0x140C) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu1_addr 32bit write %lx\n", value); +#endif + return; + case 0x1f801410: + psxHu32(0x1410) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f801414: + psxHu32(0x1414) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS spu1_delay 32bit write %lx\n", value); +#endif + return; + case 0x1f801418: + psxHu32(0x1418) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f80141C: + psxHu32(0x141C) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; + case 0x1f801420: + psxHu32(0x1420) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("SSBUS 32bit write %lx\n", value); +#endif + return; +#ifdef PSXHW_LOG + case 0x1f801080: + PSXHW_LOG("DMA0 MADR 32bit write %lx\n", value); + HW_DMA0_MADR = value; return; // DMA0 madr + case 0x1f801084: + PSXHW_LOG("DMA0 BCR 32bit write %lx\n", value); + HW_DMA0_BCR = value; return; // DMA0 bcr +#endif + case 0x1f801088: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA0 CHCR 32bit write %lx\n", value); +#endif + HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) +// DmaExec(0); + return; + +#ifdef PSXHW_LOG + case 0x1f801090: + PSXHW_LOG("DMA1 MADR 32bit write %lx\n", value); + HW_DMA1_MADR = value; return; // DMA1 madr + case 0x1f801094: + PSXHW_LOG("DMA1 BCR 32bit write %lx\n", value); + HW_DMA1_BCR = value; return; // DMA1 bcr +#endif + case 0x1f801098: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA1 CHCR 32bit write %lx\n", value); +#endif + HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) +// DmaExec(1); + return; + +#ifdef PSXHW_LOG + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit write %lx\n", value); + HW_DMA2_MADR = value; return; // DMA2 madr + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit write %lx\n", value); + HW_DMA2_BCR = value; return; // DMA2 bcr +#endif + case 0x1f8010a8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA2 CHCR 32bit write %lx\n", value); +#endif + HW_DMA2_CHCR = value; // DMA2 chcr (GPU DMA) + DmaExec(2); + return; + +#ifdef PSXHW_LOG + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit write %lx\n", value); + HW_DMA3_MADR = value; return; // DMA3 madr + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit write %lx\n", value); + HW_DMA3_BCR = value; return; // DMA3 bcr +#endif + case 0x1f8010b8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA3 CHCR 32bit write %lx\n", value); +#endif + HW_DMA3_CHCR = value; // DMA3 chcr (CDROM DMA) + DmaExec(3); + + return; + + case 0x1f8010c0: + PSXHW_LOG("DMA4 MADR 32bit write %lx\n", value); + SPU2WriteMemAddr(0,value); + HW_DMA4_MADR = value; return; // DMA4 madr + case 0x1f8010c4: + PSXHW_LOG("DMA4 BCR 32bit write %lx\n", value); + HW_DMA4_BCR = value; return; // DMA4 bcr + case 0x1f8010c8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA4 CHCR 32bit write %lx\n", value); +#endif + HW_DMA4_CHCR = value; // DMA4 chcr (SPU DMA) + DmaExec(4); + return; + +#if 0 + case 0x1f8010d0: break; //DMA5write_madr(); + case 0x1f8010d4: break; //DMA5write_bcr(); + case 0x1f8010d8: break; //DMA5write_chcr(); // Not yet needed?? +#endif + +#ifdef PSXHW_LOG + case 0x1f8010e0: + PSXHW_LOG("DMA6 MADR 32bit write %lx\n", value); + HW_DMA6_MADR = value; return; // DMA6 madr + case 0x1f8010e4: + PSXHW_LOG("DMA6 BCR 32bit write %lx\n", value); + HW_DMA6_BCR = value; return; // DMA6 bcr +#endif + case 0x1f8010e8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA6 CHCR 32bit write %lx\n", value); +#endif + HW_DMA6_CHCR = value; // DMA6 chcr (OT clear) + DmaExec(6); + return; + + case 0x1f801500: + PSXHW_LOG("DMA7 MADR 32bit write %lx\n", value); + SPU2WriteMemAddr(1,value); + HW_DMA7_MADR = value; return; // DMA7 madr + case 0x1f801504: + PSXHW_LOG("DMA7 BCR 32bit write %lx\n", value); + HW_DMA7_BCR = value; return; // DMA7 bcr + case 0x1f801508: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA7 CHCR 32bit write %lx\n", value); +#endif + HW_DMA7_CHCR = value; // DMA7 chcr (SPU2) + DmaExec2(7); + return; + +#ifdef PSXHW_LOG + case 0x1f801510: + PSXHW_LOG("DMA8 MADR 32bit write %lx\n", value); + HW_DMA8_MADR = value; return; // DMA8 madr + case 0x1f801514: + PSXHW_LOG("DMA8 BCR 32bit write %lx\n", value); + HW_DMA8_BCR = value; return; // DMA8 bcr +#endif + case 0x1f801518: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA8 CHCR 32bit write %lx\n", value); +#endif + HW_DMA8_CHCR = value; // DMA8 chcr (DEV9) + DmaExec2(8); + return; + +#ifdef PSXHW_LOG + case 0x1f801520: + PSXHW_LOG("DMA9 MADR 32bit write %lx\n", value); + HW_DMA9_MADR = value; return; // DMA9 madr + case 0x1f801524: + PSXHW_LOG("DMA9 BCR 32bit write %lx\n", value); + HW_DMA9_BCR = value; return; // DMA9 bcr +#endif + case 0x1f801528: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA9 CHCR 32bit write %lx\n", value); +#endif + HW_DMA9_CHCR = value; // DMA9 chcr (SIF0) + DmaExec2(9); + return; +#ifdef PSXHW_LOG + case 0x1f80152c: + PSXHW_LOG("DMA9 TADR 32bit write %lx\n", value); + HW_DMA9_TADR = value; return; // DMA9 tadr +#endif + +#ifdef PSXHW_LOG + case 0x1f801530: + PSXHW_LOG("DMA10 MADR 32bit write %lx\n", value); + HW_DMA10_MADR = value; return; // DMA10 madr + case 0x1f801534: + PSXHW_LOG("DMA10 BCR 32bit write %lx\n", value); + HW_DMA10_BCR = value; return; // DMA10 bcr +#endif + case 0x1f801538: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA10 CHCR 32bit write %lx\n", value); +#endif + HW_DMA10_CHCR = value; // DMA10 chcr (SIF1) + DmaExec2(10); + return; + +#ifdef PSXHW_LOG + case 0x1f801540: + PSXHW_LOG("DMA11 SIO2in MADR 32bit write %lx\n", value); + HW_DMA11_MADR = value; return; + + case 0x1f801544: + PSXHW_LOG("DMA11 SIO2in BCR 32bit write %lx\n", value); + HW_DMA11_BCR = value; return; +#endif + case 0x1f801548: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA11 SIO2in CHCR 32bit write %lx\n", value); +#endif + HW_DMA11_CHCR = value; // DMA11 chcr (SIO2 in) + DmaExec2(11); + return; + +#ifdef PSXHW_LOG + case 0x1f801550: + PSXHW_LOG("DMA12 SIO2out MADR 32bit write %lx\n", value); + HW_DMA12_MADR = value; return; + + case 0x1f801554: + PSXHW_LOG("DMA12 SIO2out BCR 32bit write %lx\n", value); + HW_DMA12_BCR = value; return; +#endif + case 0x1f801558: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA12 SIO2out CHCR 32bit write %lx\n", value); +#endif + HW_DMA12_CHCR = value; // DMA12 chcr (SIO2 out) + DmaExec2(12); + return; + + case 0x1f801570: + psxHu32(0x1570) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("DMA PCR2 32bit write %lx\n", value); +#endif + return; +#ifdef PSXHW_LOG + case 0x1f8010f0: + PSXHW_LOG("DMA PCR 32bit write %lx\n", value); + HW_DMA_PCR = value; + return; +#endif + + case 0x1f8010f4: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA ICR 32bit write %lx\n", value); +#endif + { + u32 tmp = (~value) & HW_DMA_ICR; + HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; + return; + } + + case 0x1f801574: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA ICR2 32bit write %lx\n", value); +#endif + { + u32 tmp = (~value) & HW_DMA_ICR2; + HW_DMA_ICR2 = ((tmp ^ value) & 0xffffff) ^ tmp; + return; + } + +/* case 0x1f801810: +#ifdef PSXHW_LOG + PSXHW_LOG("GPU DATA 32bit write %lx\n", value); +#endif + GPU_writeData(value); return; + case 0x1f801814: +#ifdef PSXHW_LOG + PSXHW_LOG("GPU STATUS 32bit write %lx\n", value); +#endif + GPU_writeStatus(value); return; +*/ +/* case 0x1f801820: + mdecWrite0(value); break; + case 0x1f801824: + mdecWrite1(value); break; +*/ + case 0x1f801100: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount16(0, value ); return; + case 0x1f801104: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 MODE 32bit write %lx\n", value); +#endif + psxRcnt0Wmode(value); return; + case 0x1f801108: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 0 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget16(0, value ); return; + + case 0x1f801110: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 1 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount16(1, value ); return; + case 0x1f801114: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 1 MODE 32bit write %lx\n", value); +#endif + psxRcnt1Wmode(value); return; + case 0x1f801118: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 1 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget16(1, value ); return; + + case 0x1f801120: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount16(2, value ); return; + case 0x1f801124: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 MODE 32bit write %lx\n", value); +#endif + psxRcnt2Wmode(value); return; + case 0x1f801128: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 2 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget16(2, value); return; + + case 0x1f801480: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount32(3, value); return; + case 0x1f801484: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 MODE 32bit write %lx\n", value); +#endif + psxRcnt3Wmode(value); return; + case 0x1f801488: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 3 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget32(3, value); return; + + case 0x1f801490: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount32(4, value); return; + case 0x1f801494: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 MODE 32bit write %lx\n", value); +#endif + psxRcnt4Wmode(value); return; + case 0x1f801498: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 4 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget32(4, value); return; + + case 0x1f8014a0: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount32(5, value); return; + case 0x1f8014a4: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 MODE 32bit write %lx\n", value); +#endif + psxRcnt5Wmode(value); return; + case 0x1f8014a8: +#ifdef PSXCNT_LOG + PSXCNT_LOG("COUNTER 5 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget32(5, value); return; + + case 0x1f8014c0: +#ifdef PSXHW_LOG + PSXHW_LOG("RTC_HOLDMODE 32bit write %lx\n", value); +#endif + SysPrintf("RTC_HOLDMODE 32bit write %lx\n", value); + break; + + case 0x1f801450: +#ifdef PSXHW_LOG + if (value) { PSXHW_LOG("%08X ICFG 32bit write %lx\n", psxRegs.pc, value); } +#endif +/* if (value && + psxSu32(0x20) == 0x20000 && + (psxSu32(0x30) == 0x20000 || + psxSu32(0x30) == 0x40000)) { // don't ask me why :P + psxSu32(0x20) = 0x10000; + psxSu32(0x30) = 0x10000; + }*/ + psxHu32(0x1450) = /*(*/value/* & (~0x8)) | (psxHu32(0x1450) & 0x8)*/; + return; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write param[%d] <- %lx\n", (add-0x1F808200)/4, value); +#endif + sio2_setSend3((add-0x1F808200)/4, value); return; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F808258: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write send1[%d] <- %lx\n", (add-0x1F808240)/8, value); +#endif + sio2_setSend1((add-0x1F808240)/8, value); return; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F80825C: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write send2[%d] <- %lx\n", (add-0x1F808244)/8, value); +#endif + sio2_setSend2((add-0x1F808244)/8, value); return; + + case 0x1F808268: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write CTRL <- %lx\n", value); +#endif + sio2_setCtrl(value); return; + + case 0x1F808278: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write [8278] <- %lx\n", value); +#endif + sio2_set8278(value); return; + + case 0x1F80827C: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write [827C] <- %lx\n", value); +#endif + sio2_set827C(value); return; + + case 0x1F808280: +#ifdef PSXHW_LOG + PSXHW_LOG("SIO2 write INTR <- %lx\n", value); +#endif + sio2_setIntr(value); return; + + default: + psxHu32(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 32bit write at address %lx value %lx\n", add, value); +#endif + return; + } + psxHu32(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 32bit write at address %lx value %lx\n", add, value); +#endif +} + +u8 psxHw4Read8(u32 add) { + u8 hard; + + switch (add) { + case 0x1f402004: return cdvdRead04(); + case 0x1f402005: return cdvdRead05(); + case 0x1f402006: return cdvdRead06(); + case 0x1f402007: return cdvdRead07(); + case 0x1f402008: return cdvdRead08(); + case 0x1f40200A: return cdvdRead0A(); + case 0x1f40200B: return cdvdRead0B(); + case 0x1f40200C: return cdvdRead0C(); + case 0x1f40200D: return cdvdRead0D(); + case 0x1f40200E: return cdvdRead0E(); + case 0x1f40200F: return cdvdRead0F(); + case 0x1f402013: return cdvdRead13(); + case 0x1f402015: return cdvdRead15(); + case 0x1f402016: return cdvdRead16(); + case 0x1f402017: return cdvdRead17(); + case 0x1f402018: return cdvdRead18(); + case 0x1f402020: return cdvdRead20(); + case 0x1f402021: return cdvdRead21(); + case 0x1f402022: return cdvdRead22(); + case 0x1f402023: return cdvdRead23(); + case 0x1f402024: return cdvdRead24(); + case 0x1f402028: return cdvdRead28(); + case 0x1f402029: return cdvdRead29(); + case 0x1f40202A: return cdvdRead2A(); + case 0x1f40202B: return cdvdRead2B(); + case 0x1f40202C: return cdvdRead2C(); + case 0x1f402030: return cdvdRead30(); + case 0x1f402031: return cdvdRead31(); + case 0x1f402032: return cdvdRead32(); + case 0x1f402033: return cdvdRead33(); + case 0x1f402034: return cdvdRead34(); + case 0x1f402038: return cdvdRead38(); + case 0x1f402039: return cdvdRead39(); + case 0x1f40203A: return cdvdRead3A(); + default: +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 8bit read at address %lx\n", add); +#endif + SysPrintf("*Unkwnown 8bit read at address %lx\n", add); + return 0; + } + +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); +#endif + + return hard; +} + +void psxHw4Write8(u32 add, u8 value) { + switch (add) { + case 0x1f402004: cdvdWrite04(value); return; + case 0x1f402005: cdvdWrite05(value); return; + case 0x1f402006: cdvdWrite06(value); return; + case 0x1f402007: cdvdWrite07(value); return; + case 0x1f402008: cdvdWrite08(value); return; + case 0x1f40200A: cdvdWrite0A(value); return; + case 0x1f40200F: cdvdWrite0F(value); return; + case 0x1f402014: cdvdWrite14(value); return; + case 0x1f402016: + cdvdWrite16(value); + FreezeMMXRegs(0); + FreezeXMMRegs(0) + return; + case 0x1f402017: cdvdWrite17(value); return; + case 0x1f402018: cdvdWrite18(value); return; + case 0x1f40203A: cdvdWrite3A(value); return; + default: +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); +#endif + SysPrintf("*Unknown 8bit write at address %lx value %x\n", add, value); + return; + } +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); +#endif +} + +void psxDmaInterrupt(int n) { + if (HW_DMA_ICR & (1 << (16 + n))) { + HW_DMA_ICR|= (1 << (24 + n)); + psxRegs.CP0.n.Cause |= 1 << (9 + n); + psxHu32(0x1070) |= 8; + + } +} + +void psxDmaInterrupt2(int n) { + if (HW_DMA_ICR2 & (1 << (16 + n))) { +/* if (HW_DMA_ICR2 & (1 << (24 + n))) { + SysPrintf("*PCSX2*: HW_DMA_ICR2 n=%d already set\n", n); + } + if (psxHu32(0x1070) & 8) { + SysPrintf("*PCSX2*: psxHu32(0x1070) 8 already set (n=%d)\n", n); + }*/ + HW_DMA_ICR2|= (1 << (24 + n)); + psxRegs.CP0.n.Cause |= 1 << (16 + n); + psxHu32(0x1070) |= 8; + } +} diff --git a/pcsx2/PsxHw.h b/pcsx2/PsxHw.h new file mode 100644 index 0000000000..cb689ed2e5 --- /dev/null +++ b/pcsx2/PsxHw.h @@ -0,0 +1,117 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXHW_H__ +#define __PSXHW_H__ + +#define HW_DMA0_MADR (psxHu32(0x1080)) // MDEC in DMA +#define HW_DMA0_BCR (psxHu32(0x1084)) +#define HW_DMA0_CHCR (psxHu32(0x1088)) + +#define HW_DMA1_MADR (psxHu32(0x1090)) // MDEC out DMA +#define HW_DMA1_BCR (psxHu32(0x1094)) +#define HW_DMA1_CHCR (psxHu32(0x1098)) + +#define HW_DMA2_MADR (psxHu32(0x10a0)) // GPU DMA +#define HW_DMA2_BCR (psxHu32(0x10a4)) +#define HW_DMA2_CHCR (psxHu32(0x10a8)) +#define HW_DMA2_TADR (psxHu32(0x10ac)) + +#define HW_DMA3_MADR (psxHu32(0x10b0)) // CDROM DMA +#define HW_DMA3_BCR (psxHu32(0x10b4)) +#define HW_DMA3_BCR_L16 (psxHu16(0x10b4)) +#define HW_DMA3_BCR_H16 (psxHu16(0x10b6)) +#define HW_DMA3_CHCR (psxHu32(0x10b8)) + +#define HW_DMA4_MADR (psxHu32(0x10c0)) // SPU DMA +#define HW_DMA4_BCR (psxHu32(0x10c4)) +#define HW_DMA4_CHCR (psxHu32(0x10c8)) +#define HW_DMA4_TADR (psxHu32(0x10cc)) + +#define HW_DMA6_MADR (psxHu32(0x10e0)) // GPU DMA (OT) +#define HW_DMA6_BCR (psxHu32(0x10e4)) +#define HW_DMA6_CHCR (psxHu32(0x10e8)) + +#define HW_DMA7_MADR (psxHu32(0x1500)) // SPU2 DMA +#define HW_DMA7_BCR (psxHu32(0x1504)) +#define HW_DMA7_CHCR (psxHu32(0x1508)) + +#define HW_DMA8_MADR (psxHu32(0x1510)) // DEV9 DMA +#define HW_DMA8_BCR (psxHu32(0x1514)) +#define HW_DMA8_CHCR (psxHu32(0x1518)) + +#define HW_DMA9_MADR (psxHu32(0x1520)) // SIF0 DMA +#define HW_DMA9_BCR (psxHu32(0x1524)) +#define HW_DMA9_CHCR (psxHu32(0x1528)) +#define HW_DMA9_TADR (psxHu32(0x152c)) + +#define HW_DMA10_MADR (psxHu32(0x1530)) // SIF1 DMA +#define HW_DMA10_BCR (psxHu32(0x1534)) +#define HW_DMA10_CHCR (psxHu32(0x1538)) + +#define HW_DMA11_MADR (psxHu32(0x1540)) // SIO2 in +#define HW_DMA11_BCR (psxHu32(0x1544)) +#define HW_DMA11_CHCR (psxHu32(0x1548)) + +#define HW_DMA12_MADR (psxHu32(0x1550)) // SIO2 out +#define HW_DMA12_BCR (psxHu32(0x1554)) +#define HW_DMA12_CHCR (psxHu32(0x1558)) + +#define HW_DMA_PCR (psxHu32(0x10f0)) +#define HW_DMA_ICR (psxHu32(0x10f4)) + +#define HW_DMA_PCR2 (psxHu32(0x1570)) +#define HW_DMA_ICR2 (psxHu32(0x1574)) + +#define PSX_INT(n, ecycle) \ + psxRegs.interrupt|= 1 << n; \ + g_psxNextBranchCycle = min(g_psxNextBranchCycle, psxRegs.cycle+ecycle); \ + psxRegs.sCycle[n] = psxRegs.cycle; \ + psxRegs.eCycle[n] = ecycle; + + +void psxHwReset(); +u8 psxHwRead8 (u32 add); +int psxHwConstRead8(u32 x86reg, u32 add, u32 sign); + +u16 psxHwRead16(u32 add); +int psxHwConstRead16(u32 x86reg, u32 add, u32 sign); + +u32 psxHwRead32(u32 add); +int psxHwConstRead32(u32 x86reg, u32 add); + +void psxHwWrite8 (u32 add, u8 value); +void psxHwConstWrite8(u32 add, int mmreg); + +void psxHwWrite16(u32 add, u16 value); +void psxHwConstWrite16(u32 add, int mmreg); + +void psxHwWrite32(u32 add, u32 value); +void psxHwConstWrite32(u32 add, int mmreg); + +u8 psxHw4Read8 (u32 add); +int psxHw4ConstRead8 (u32 x86reg, u32 add, u32 sign); + +void psxHw4Write8(u32 add, u8 value); +void psxHw4ConstWrite8(u32 add, int mmreg); + +int psxHwFreeze(gzFile f, int Mode); +void psxDmaInterrupt(int n); +void psxDmaInterrupt2(int n); + +#endif /* __PSXHW_H__ */ diff --git a/pcsx2/PsxInterpreter.c b/pcsx2/PsxInterpreter.c new file mode 100644 index 0000000000..f44200d2ec --- /dev/null +++ b/pcsx2/PsxInterpreter.c @@ -0,0 +1,804 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include + +#include "PsxCommon.h" +#include "Common.h" + +static int branch = 0; +static int branch2 = 0; +static u32 branchPC; + +// These macros are used to assemble the repassembler functions + +#ifdef _DEBUG +#define execI() { \ + psxRegs.code = PSXMu32(psxRegs.pc); \ + \ + if (Log) { \ + PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); \ + } \ + psxRegs.pc+= 4; \ + psxRegs.cycle++; \ + \ + psxBSC[psxRegs.code >> 26](); \ +} +#else +#define execI() { \ + psxRegs.code = PSXMu32(psxRegs.pc); \ + \ + psxRegs.pc+= 4; \ + psxRegs.cycle++; \ + \ + psxBSC[psxRegs.code >> 26](); \ +} +#endif + + +#define doBranch(tar) { \ + branch2 = branch = 1; \ + branchPC = tar; \ + execI(); \ + branch = 0; \ + psxRegs.pc = branchPC; \ + \ + psxBranchTest(); \ +} + +// Subsets +void (*psxBSC[64])(); +void (*psxSPC[64])(); +void (*psxREG[32])(); +void (*psxCP0[32])(); +void (*psxCP2[64])(); +void (*psxCP2BSC[32])(); + +extern void bios_write(); +extern void bios_printf(); + +typedef struct { + char name[8]; + char names[64][32]; + int maxn; +} irxlib; + +#define IRXLIBS 14 +irxlib irxlibs[32] = { +/*00*/ { { "sysmem" } , + { "start", "init_memory", "retonly", "return_addr_of_memsize", + "AllocSysMemory", "FreeSysMemory", "QueryMemSize", "QueryMaxFreeMemSize", + "QueryTotalFreeMemSize", "QueryBlockTopAddress", "QueryBlockSize", "retonly", + "retonly", "retonly", "Kprintf", "set_Kprintf" } , + 16 }, +/*01*/ { { "loadcore" } , + { "start", "retonly", "retonly_", "return_LibraryEntryTable", + "FlushIcache", "FlushDcache", "RegisterLibraryEntries", "ReleaseLibraryEntries", + "findFixImports", "restoreImports", "RegisterNonAutoLinkEntries", "QueryLibraryEntryTable", + "QueryBootMode", "RegisterBootMode", "setFlag", "resetFlag", + "linkModule", "unlinkModule", "retonly_", "retonly_", + "registerFunc", "jumpA0001B34", "read_header", "load_module", + "findImageInfo" }, + 25 }, +/*02*/ { { "excepman" } , + { "start", "reinit", "deinit", "getcommon", + "RegisterExceptionHandler", "RegisterPriorityExceptionHandler", + "RegisterDefaultExceptionHandler", "ReleaseExceptionHandler", + "ReleaseDefaultExceptionHandler" } , + 9 }, +/*03_4*/{ { "intrman" } , + { "start", "return_0", "deinit", "call3", + "RegisterIntrHandler", "ReleaseIntrHandler", "EnableIntr", "DisableIntr", + "CpuDisableIntr", "CpuEnableIntr", "syscall04", "syscall08", + "resetICTRL", "setICTRL", "syscall0C", "call15", + "call16", "CpuSuspendIntr", "CpuResumeIntr", "CpuSuspendIntr", + "CpuResumeIntr", "syscall10", "syscall14", "QueryIntrContext", + "QueryIntrStack", "iCatchMultiIntr", "retonly", "call27", + "set_h1", "reset_h1", "set_h2", "reset_h2" } , + 0x20 }, +/*05*/ { { "ssbusc" } , + { "start", "retonly", "return_0", "retonly", + "setTable1", "getTable1", "setTable2", "getTable2", + "setCOM_DELAY_1st", "getCOM_DELAY_1st", "setCOM_DELAY_2nd", "getCOM_DELAY_2nd", + "setCOM_DELAY_3rd", "getCOM_DELAY_3rd", "setCOM_DELAY_4th", "getCOM_DELAY_4th", + "setCOM_DELAY", "getCOM_DELAY" } , + 18 }, +/*06*/ { { "dmacman" } , + { "start", "retonly", "deinit", "retonly", + "SetD_MADR", "GetD_MADR", "SetD_BCR", "GetD_BCR", + "SetD_CHCR", "GetD_CHCR", "SetD_TADR", "GetD_TADR", + "Set_4_9_A", "Get_4_9_A", "SetDPCR", "GetDPCR", + "SetDPCR2", "GetDPCR2", "SetDPCR3", "GetDPCR3", + "SetDICR", "GetDICR", "SetDICR2", "GetDICR2", + "SetBF80157C", "GetBF80157C", "SetBF801578", "GetBF801578", + "SetDMA", "SetDMA_chainedSPU_SIF0", "SetDMA_SIF0", "SetDMA_SIF1", + "StartTransfer", "SetVal", "EnableDMAch", "DisableDMAch" } , + 36 }, +/*07_8*/{ { "timrman" } , + { "start", "retonly", "retonly", "call3", + "AllocHardTimer", "ReferHardTimer", "FreeHardTimer", "SetTimerMode", + "GetTimerStatus", "SetTimerCounter", "GetTimerCounter", "SetTimerCompare", + "GetTimerCompare", "SetHoldMode", "GetHoldMode", "GetHoldReg", + "GetHardTimerIntrCode" } , + 17 }, +/*09*/ { { "sysclib" } , + { "start", "reinit", "retonly", "retonly", + "setjmp", "longjmp", "toupper", "tolower", + "look_ctype_table", "get_ctype_table", "memchr", "memcmp", + "memcpy", "memmove", "memset", "bcmp", + "bcopy", "bzero", "prnt", "sprintf", + "strcat", "strchr", "strcmp", "strcpy", + "strcspn", "index", "rindex", "strlen", + "strncat", "strncmp", "strncpy", "strpbrk", + "strrchr", "strspn", "strstr", "strtok", + "strtol", "atob", "strtoul", "wmemcopy", + "wmemset", "vsprintf" } , + 0x2b }, +/*0A*/ { { "heaplib" } , + { "start", "retonly", "retonly", "retonly", + "CreateHeap", "DestroyHeap", "HeapMalloc", "HeapFree", + "HeapSize", "retonly", "retonly", "call11", + "call12", "call13", "call14", "call15", + "retonly", "retonly" } , + 18 }, +/*13*/ { { "stdio" } , + { "start", "unknown", "unknown", "unknown", + "printf" } , + 5 }, +/*14*/ { { "sifman" } , + { "start", "retonly", "deinit", "retonly", + "sceSif2Init", "sceSifInit", "sceSifSetDChain", "sceSifSetDma", + "sceSifDmaStat", "sceSifSend", "sceSifSendSync", "sceSifIsSending", + "sceSifSetSIF0DMA", "sceSifSendSync0", "sceSifIsSending0", "sceSifSetSIF1DMA", + "sceSifSendSync1", "sceSifIsSending1", "sceSifSetSIF2DMA", "sceSifSendSync2", + "sceSifIsSending2", "getEEIOPflags", "setEEIOPflags", "getIOPEEflags", + "setIOPEEflags", "getEErcvaddr", "getIOPrcvaddr", "setIOPrcvaddr", + "call28", "sceSifCheckInit", "setSif0CB", "resetSif0CB", + "retonly", "retonly", "retonly", "retonly" } , + 36 }, +/*16*/ { { "sifcmd" } , + { "start", "retonly", "deinit", "retonly", + "sceSifInitCmd", "sceSifExitCmd", "sceSifGetSreg", "sceSifSetSreg", + "sceSifSetCmdBuffer", "sceSifSetSysCmdBuffer", + "sceSifAddCmdHandler", "sceSifRemoveCmdHandler", + "sceSifSendCmd", "isceSifSendCmd", "sceSifInitRpc", "sceSifBindRpc", + "sceSifCallRpc", "sceSifRegisterRpc", + "sceSifCheckStatRpc", "sceSifSetRpcQueue", + "sceSifGetNextRequest", "sceSifExecRequest", + "sceSifRpcLoop", "sceSifGetOtherData", + "sceSifRemoveRpc", "sceSifRemoveRpcQueue", + "setSif1CB", "resetSif1CB", + "retonly", "retonly", "retonly", "retonly" } , + 32 }, +/*19*/ { { "cdvdman" } , + { "start", "retonly", "retonly", "retonly", + "sceCdInit", "sceCdStandby", "sceCdRead", "sceCdSeek", + "sceCdGetError", "sceCdGetToc", "sceCdSearchFile", "sceCdSync", + "sceCdGetDiskType", "sceCdDiskReady", "sceCdTrayReq", "sceCdStop", + "sceCdPosToInt", "sceCdIntToPos", "retonly", "call19", + "sceDvdRead", "sceCdCheckCmd", "_sceCdRI", "sceCdWriteILinkID", + "sceCdReadClock", "sceCdWriteRTC", "sceCdReadNVM", "sceCdWriteNVM", + "sceCdStatus", "sceCdApplySCmd", "setHDmode", "sceCdOpenConfig", + "sceCdCloseConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdReadKey", + "sceCdDecSet", "sceCdCallback", "sceCdPause", "sceCdBreak", + "call40", "sceCdReadConsoleID", "sceCdWriteConsoleID", "sceCdGetMecaconVersion", + "sceCdGetReadPos", "AudioDigitalOut", "sceCdNop", "_sceGetFsvRbuf", + "_sceCdstm0Cb", "_sceCdstm1Cb", "_sceCdSC", "_sceCdRC", + "sceCdForbidDVDP", "sceCdReadSubQ", "sceCdApplyNCmd", "AutoAdjustCtrl", + "sceCdStInit", "sceCdStRead", "sceCdStSeek", "sceCdStStart", + "sceCdStStat", "sceCdStStop" } , + 62 }, +/*??*/ { { "sio2man" } , + { "start", "retonly", "deinit", "retonly", + "set8268_ctrl", "get8268_ctrl", "get826C_recv1", "call7_send1", + "call8_send1", "call9_send2", "call10_send2", "get8270_recv2", + "call12_set_params", "call13_get_params", "get8274_recv3", "set8278", + "get8278", "set827C", "get827C", "set8260_datain", + "get8264_dataout", "set8280_intr", "get8280_intr", "signalExchange1", + "signalExchange2", "packetExchange" } , + 26 } +}; + +#define Ra0 ((char*)PSXM(psxRegs.GPR.n.a0)) +#define Ra1 ((char*)PSXM(psxRegs.GPR.n.a1)) +#define Ra2 ((char*)PSXM(psxRegs.GPR.n.a2)) +#define Ra3 ((char*)PSXM(psxRegs.GPR.n.a3)) + +char* intrname[]={ +"INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 +"INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 +"INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 +"INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C +"INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 +"INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 +"INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 +"INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C +"INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 +"INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 +"INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 +"INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C +"INT_30", "INT_31", "INT_32", "INT_33", //30 +"INT_34", "INT_35", "INT_36", "INT_37", //34 +"INT_38", "INT_39", "INT_3A", "INT_3B", //38 +"INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C +"INT_MAX" //40 +}; + +void zeroEx() { + u32 pc; + u32 code; + char *lib; + char *fname = NULL; + int i; + + if (!Config.PsxOut) return; + + pc = psxRegs.pc; + while (PSXMu32(pc) != 0x41e00000) pc-=4; + + lib = (char*)PSXM(pc+12); + code = PSXMu32(psxRegs.pc - 4) & 0xffff; + + for (i=0; i= (u32)irxlibs[i].maxn) break; + + fname = irxlibs[i].names[code]; + //if( strcmp(fname, "setIOPrcvaddr") == 0 ) { +// SysPrintf("yo\n"); +// varLog |= 0x100000; +// Log = 1; +// } + break; + } + } + +#ifdef PSXBIOS_LOG + {char libz[9]; memcpy(libz, lib, 8); libz[8]=0; + PSXBIOS_LOG("%s: %s (%x)" + " (%x, %x, %x, %x)" //comment this line to disable param showing + , libz, fname == NULL ? "unknown" : fname, code, + psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + } +#endif + +// Log=0; +// if (!strcmp(lib, "intrman") && code == 0x11) Log=1; +// if (!strcmp(lib, "sifman") && code == 0x5) Log=1; +// if (!strcmp(lib, "sifcmd") && code == 0x4) Log=1; +// if (!strcmp(lib, "thbase") && code == 0x6) Log=1; +/* + if (!strcmp(lib, "sifcmd") && code == 0xe) { + branchPC = psxRegs.GPR.n.ra; + psxRegs.GPR.n.v0 = 0; + return; + } +*/ + if (!strncmp(lib, "ioman", 5) && code == 7) { + if (psxRegs.GPR.n.a0 == 1) { + pc = psxRegs.pc; + bios_write(); + psxRegs.pc = pc; + } + } + + if (!strncmp(lib, "sysmem", 6) && code == 0xe) { + bios_printf(); + psxRegs.pc = psxRegs.GPR.n.ra; + } + + if (!strncmp(lib, "loadcore", 8) && code == 6) { + SysPrintf("loadcore RegisterLibraryEntries (%x): %8.8s\n", psxRegs.pc, PSXM(psxRegs.GPR.n.a0+12)); + } + + if (!strncmp(lib, "intrman", 7) && code == 4) { + SysPrintf("intrman RegisterIntrHandler (%x): intr %s, handler %x\n", psxRegs.pc, intrname[psxRegs.GPR.n.a0], psxRegs.GPR.n.a2); + } + + if (!strncmp(lib, "sifcmd", 6) && code == 17) { + SysPrintf("sifcmd sceSifRegisterRpc (%x): rpc_id %x\n", psxRegs.pc, psxRegs.GPR.n.a1); + } + +#ifdef PSXBIOS_LOG + if (!strncmp(lib, "sysclib", 8)) { + switch (code) { + case 0x16: // strcmp + if (varLog & 0x00800000) EMU_LOG(" \"%s\": \"%s\"", Ra0, Ra1); + break; + + case 0x1e: // strncpy + if (varLog & 0x00800000) EMU_LOG(" \"%s\"", Ra1); + break; + } + } +#endif + +#ifdef PSXBIOS_LOG + if (varLog & 0x00800000) EMU_LOG("\n"); +#endif + +/* psxRegs.pc = branchPC; + pc = psxRegs.GPR.n.ra; + while (psxRegs.pc != pc) psxCpu->ExecuteBlock(); + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("%s: %s (%x) END\n", lib, fname == NULL ? "unknown" : fname, code); +#endif*/ +} +/*/==========================================CALL LOG +char* getName(char *file, u32 addr){ + FILE *f; u32 a; + static char name[100]; + + f=fopen(file, "r"); + if (!f) + name[0]=0; + else{ + while (!feof(f)){ + fscanf(f, "%08X %s\r\n", &a, name); + if (a==addr)break; + } + fclose(f); + } + return name; +} + +void spyFunctions(){ + register irxImageInfo *iii; + if (psxRegs.pc >= 0x200000) return; + for (iii=(irxImageInfo*)PSXM(0x800); iii && iii->text_size; + iii=iii->next ? (irxImageInfo*)PSXM(iii->next) : NULL) + if (iii->vaddr<=psxRegs.pc && psxRegs.pcvaddr+iii->text_size+iii->data_size+iii->bss_size){ + if (strcmp("secrman_for_cex", PSXM(iii->name))==0){ + char *name=getName("secrman.fun", psxRegs.pc-iii->vaddr); + if (strncmp("__push_params", name, 13)==0){ + PAD_LOG(PSXM(psxRegs.GPR.n.a0), psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + }else{ + PAD_LOG("secrman: %s (ra=%06X cycle=%d)\n", name, psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}}else + if (strcmp("mcman", PSXM(iii->name))==0){ + PAD_LOG("mcman: %s (ra=%06X cycle=%d)\n", getName("mcman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else + if (strcmp("padman", PSXM(iii->name))==0){ + PAD_LOG("padman: %s (ra=%06X cycle=%d)\n", getName("padman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else + if (strcmp("sio2man", PSXM(iii->name))==0){ + PAD_LOG("sio2man: %s (ra=%06X cycle=%d)\n", getName("sio2man.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);} + break; + } +} +*/ +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) +void psxADDIU() { if (!_Rt_) { zeroEx(); return; } _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im +void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im +void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im +void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im +void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) +void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < _ImmU_; } // Rt = Rs < Im (Unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) +void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt +void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) +void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt +void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt +void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt +void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt +void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt +void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) +void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void psxDIV() { + if (_rRt_ != 0) { + _rLo_ = _i32(_rRs_) / _i32(_rRt_); + _rHi_ = _i32(_rRs_) % _i32(_rRt_); + } +} + +void psxDIVU() { + if (_rRt_ != 0) { + _rLo_ = _rRs_ / _rRt_; + _rHi_ = _rRs_ % _rRt_; + } +} + +void psxMULT() { + u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +void psxMULTU() { + u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); +#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } + +void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void psxSLL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa +void psxSRA() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) +void psxSRL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void psxSLLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs +void psxSRAV() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) +void psxSRLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void psxLUI() { if (!_Rt_) return; _rRt_ = psxRegs.code << 16; } // Upper halfword of Rt = Im + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi +void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs +void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +void psxBREAK() { + // Break exception - psx rom doens't handles this + psxRegs.pc -= 4; + psxException(0x24, branch); +} + +void psxSYSCALL() { + psxRegs.pc -= 4; + psxException(0x20, branch); + +} + +void psxRFE() { +// SysPrintf("RFE\n"); + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +// Log=0; +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); + +void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +void psxJ() { doBranch(_JumpTarget_); } +void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); /*spyFunctions();*/ } + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void psxJR() { doBranch(_u32(_rRs_)); } +void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); } + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _oB_ (_u32(_rRs_) + _Imm_) + +void psxLB() { + if (_Rt_) { + _rRt_ = (s8 )psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLBU() { + if (_Rt_) { + _rRt_ = psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLH() { + if (_Rt_) { + _rRt_ = (s16)psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLHU() { + if (_Rt_) { + _rRt_ = psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLW() { + if (_Rt_) { + _rRt_ = psxMemRead32(_oB_); + } else { + psxMemRead32(_oB_); + } +} + +void psxLWL() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & (0x00ffffff >> shift) ) | + ( mem << (24 - shift) ); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + + */ +} + +void psxLWR() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & (0xffffff00 << (24 - shift)) ) | + ( mem >> shift ); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + + */ +} + +void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } +void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } +void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } + +void psxSWL() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) >> (24 - shift) ) ) | + ( mem & (0xffffff00 << shift) )); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + + */ +} + +void psxSWR() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) << shift ) | + (mem & (0x00ffffff >> (24 - shift)) ) ) ); + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + + */ +} + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +void psxMFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } +void psxCFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } + +void psxMTC0() { _rFs_ = _u32(_rRt_); } +void psxCTC0() { _rFs_ = _u32(_rRt_); } + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +void psxNULL() { +SysPrintf("psx: Unimplemented op %x\n", psxRegs.code); +} + +void psxSPECIAL() { + psxSPC[_Funct_](); +} + +void psxREGIMM() { + psxREG[_Rt_](); +} + +void psxCOP0() { + psxCP0[_Rs_](); +} + +void psxCOP2() { + psxCP2[_Funct_](); +} + +void psxBASIC() { + psxCP2BSC[_Rs_](); +} + + +void (*psxBSC[64])() = { + psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, + psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , + psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, + psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL +}; + + +void (*psxSPC[64])() = { + psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, + psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, + psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, + psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, + psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , + psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL +}; + +void (*psxREG[32])() = { + psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP0[32])() = { + psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP2[64])() = { + psxBASIC, psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL, psxNULL, // 00 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 08 + psxNULL , psxNULL, psxNULL, psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 10 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 18 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, // 28 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL // 38 +}; + +void (*psxCP2BSC[32])() = { + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + + +/////////////////////////////////////////// + +static int intInit() { + return 0; +} + +static void intReset() { +} + +static void intExecute() { + for (;;) execI(); +} + +#ifdef _DEBUG +extern u32 psxdump; +extern void iDumpPsxRegisters(u32,u32); +#endif + +static void intExecuteBlock() { + while (EEsCycle > 0){ + branch2 = 0; + while (!branch2) { + execI(); + +#ifdef _DEBUG + if( psxdump & 16 ) { + iDumpPsxRegisters(psxRegs.pc,1); + } +#endif + } + } +} + +static void intClear(u32 Addr, u32 Size) { +} + +static void intShutdown() { +} + +R3000Acpu psxInt = { + intInit, + intReset, + intExecute, + intExecuteBlock, + intClear, + intShutdown +}; diff --git a/pcsx2/PsxMem.c b/pcsx2/PsxMem.c new file mode 100644 index 0000000000..62b151ccab --- /dev/null +++ b/pcsx2/PsxMem.c @@ -0,0 +1,794 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "PsxCommon.h" +#include "VU.h" +#include "iCore.h" +#include "Hw.h" +#include "iR3000A.h" + +extern u32 g_psxMaxRecMem; +int g_psxWriteOk=1; +static u32 writectrl; + +#ifdef PCSX2_VIRTUAL_MEM + +int psxMemInit() +{ + // all mem taken care by memInit + return 0; +} + +void psxMemReset() +{ + memset(psxM, 0, 0x00200000); +} + +void psxMemShutdown() +{ +} + +u8 psxMemRead8(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + break; + +#ifdef _DEBUG + case 0x1d00: assert(0); +#endif + + case 0x1f40: + mem &= 0x1fffffff; + return psxHw4Read8(mem); + + case 0x1000: return DEV9read8(mem & 0x1FFFFFFF); + + default: + assert( g_psxWriteOk ); + return *(u8*)PSXM(mem); + } +} + +u16 psxMemRead16(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu16(mem); + else + return psxHwRead16(mem); + break; + + case 0x1d00: +#ifdef SIF_LOG + SIF_LOG("Sif reg read %x value %x\n", mem, psxHu16(mem)); +#endif + switch(mem & 0xF0) + { + case 0x40: return psHu16(0x1000F240) | 0x0002; + case 0x60: return 0; + default: return *(u16*)(PS2MEM_HW+0xf200+(mem&0xf0)); + } + break; + + case 0x1f90: + return SPU2read(mem & 0x1FFFFFFF); + case 0x1000: + return DEV9read16(mem & 0x1FFFFFFF); + + default: + assert( g_psxWriteOk ); + return *(u16*)PSXM(mem); + } +} + +u32 psxMemRead32(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu32(mem); + else + return psxHwRead32(mem); + break; + + case 0x1d00: +#ifdef SIF_LOG + SIF_LOG("Sif reg read %x value %x\n", mem, psxHu32(mem)); +#endif + switch(mem & 0xF0) + { + case 0x40: return psHu32(0x1000F240) | 0xF0000002; + case 0x60: return 0; + default: return *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)); + } + break; + + case 0x1fff: return g_psxWriteOk; + case 0x1000: + return DEV9read32(mem & 0x1FFFFFFF); + + default: + //assert(g_psxWriteOk); + if( mem == 0xfffe0130 ) + return writectrl; + else if( mem == 0xffffffff ) + return writectrl; + else if( g_psxWriteOk ) + return *(u32*)PSXM(mem); + else return 0; + } +} + +void psxMemWrite8(u32 mem, u8 value) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + break; + + case 0x1f40: + mem&= 0x1fffffff; + psxHw4Write8(mem, value); + break; + + case 0x1d00: + SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); + *(u8*)(PS2MEM_HW+0xf200+(mem&0xff)) = value; + break; + + case 0x1000: + DEV9write8(mem & 0x1fffffff, value); + return; + + default: + assert(g_psxWriteOk); + *(u8 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + break; + } +} + +void psxMemWrite16(u32 mem, u16 value) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1600: + //HACK: DEV9 VM crash fix + break; + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu16(mem) = value; + else + psxHwWrite16(mem, value); + break; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu16(0x1000F210) = value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu16(0x1000F240) &= ~0xF000; + psHu16(0x1000F240) |= 0x2000; + } + + if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + else psHu16(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + default: + assert(0); + } + return; + + case 0x1f90: + SPU2write(mem & 0x1FFFFFFF, value); return; + + case 0x1000: + DEV9write16(mem & 0x1fffffff, value); return; + default: + assert( g_psxWriteOk ); + *(u16 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + break; + } +} + +void psxMemWrite32(u32 mem, u32 value) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu32(mem) = value; + else + psxHwWrite32(mem, value); + break; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu32(0x1000F210) = value; + return; + case 0x20: + // write to ps2 mem + psHu32(0x1000F220) &= ~value; + return; + case 0x30: + // write to ps2 mem + psHu32(0x1000F230) |= value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu32(0x1000F240) &= ~0xF000; + psHu32(0x1000F240) |= 0x2000; + } + + + if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; + else psHu32(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + default: + *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; + } + + return; + + case 0x1000: + DEV9write32(mem & 0x1fffffff, value); + return; + + case 0x1ffe: + if( mem == 0xfffe0130 ) { + writectrl = value; + switch (value) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + g_psxWriteOk = 0; +#ifdef PSXMEM_LOG +// PSXMEM_LOG("writectrl: writenot ok\n"); +#endif + break; + case 0x1e988: + case 0x1edd8: + g_psxWriteOk = 1; +#ifdef PSXMEM_LOG +// PSXMEM_LOG("writectrl: write ok\n"); +#endif + break; + default: +#ifdef PSXMEM_LOG + PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); +#endif + break; + } + } + break; + + default: + + if( g_psxWriteOk ) { + *(u32 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + } + + break; + } +} + +#else + +// TLB functions + +#ifdef TLB_DEBUG_MEM +void* PSXM(u32 mem) +{ + return (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); +} + +void* _PSXM(u32 mem) +{ + return ((void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); +} +#endif + +s8 *psxM; +s8 *psxP; +s8 *psxH; +s8 *psxS; +uptr *psxMemWLUT; +uptr *psxMemRLUT; + +int psxMemInit() +{ + int i; + + psxMemRLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); + psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); + memset(psxMemRLUT, 0, 0x10000 * sizeof(uptr)); + memset(psxMemWLUT, 0, 0x10000 * sizeof(uptr)); + + psxM = (char*)SysMmap(PS2MEM_PSX_, 0x00200000); + psxP = (char*)SysMmap(PS2MEM_BASE_+0x1f000000, 0x00010000); + psxH = (char*)SysMmap(PS2MEM_BASE_+0x1f800000, 0x00010000); + psxS = (char*)SysMmap(PS2MEM_BASE_+0x1d000000, 0x00010000); + + assert( (uptr)psxM <= 0xffffffff && (uptr)psxP <= 0xffffffff && (uptr)psxH <= 0xffffffff && (uptr)psxS <= 0xffffffff); + + if (psxMemRLUT == NULL || psxMemWLUT == NULL || + psxM == NULL || psxP == NULL || psxH == NULL) { + SysMessage(_("Error allocating memory")); return -1; + } + + memset(psxM, 0, 0x00200000); + memset(psxP, 0, 0x00010000); + memset(psxH, 0, 0x00010000); + memset(psxS, 0, 0x00010000); + + +// MemR + for (i=0; i<0x0080; i++) psxMemRLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemRLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemRLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; + + for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1f00] = (uptr)&psxP[i << 16]; + + for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1f80] = (uptr)&psxH[i << 16]; + for (i=0; i<0x0001; i++) psxMemRLUT[i + 0xbf80] = (uptr)&psxH[i << 16]; + + for (i=0; i<0x0040; i++) psxMemRLUT[i + 0x1fc0] = (uptr)&PS2MEM_ROM[i << 16]; + for (i=0; i<0x0040; i++) psxMemRLUT[i + 0x9fc0] = (uptr)&PS2MEM_ROM[i << 16]; + for (i=0; i<0x0040; i++) psxMemRLUT[i + 0xbfc0] = (uptr)&PS2MEM_ROM[i << 16]; + + for (i=0; i<0x0004; i++) psxMemRLUT[i + 0x1e00] = (uptr)&PS2MEM_ROM1[i << 16]; + for (i=0; i<0x0004; i++) psxMemRLUT[i + 0x9e00] = (uptr)&PS2MEM_ROM1[i << 16]; + for (i=0; i<0x0004; i++) psxMemRLUT[i + 0xbe00] = (uptr)&PS2MEM_ROM1[i << 16]; + + for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1d00] = (uptr)&psxS[i << 16]; + for (i=0; i<0x0001; i++) psxMemRLUT[i + 0xbd00] = (uptr)&psxS[i << 16]; + +// MemW + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; + + for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1f00] = (uptr)&psxP[i << 16]; + + for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1f80] = (uptr)&psxH[i << 16]; + for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbf80] = (uptr)&psxH[i << 16]; + +// for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; + +// for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1d00] = (uptr)&psxS[i << 16]; +// for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbd00] = (uptr)&psxS[i << 16]; + + return 0; +} + +void psxMemReset() { + memset(psxM, 0, 0x00200000); + memset(psxP, 0, 0x00010000); + //memset(psxS, 0, 0x00010000); +} + +void psxMemShutdown() +{ + SysMunmap((uptr)psxM, 0x00200000); psxM = NULL; + SysMunmap((uptr)psxP, 0x00010000); psxP = NULL; + SysMunmap((uptr)psxH, 0x00010000); psxH = NULL; + SysMunmap((uptr)psxS, 0x00010000); psxS = NULL; + _aligned_free(psxMemRLUT); + _aligned_free(psxMemWLUT); +} + +u8 psxMemRead8(u32 mem) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + } else + if (t == 0x1f40) { + mem&= 0x1fffffff; + return psxHw4Read8(mem); + } else { + p = (char *)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + return *(u8 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF); +#ifdef PSXMEM_LOG + PSXMEM_LOG("err lb %8.8lx\n", mem); +#endif + return 0; + } + } +} + +u16 psxMemRead16(u32 mem) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu16(mem); + else + return psxHwRead16(mem); + } else { + p = (char *)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + if (t == 0x1d00) { + u16 ret; + switch(mem & 0xF0) + { + case 0x00: + ret= psHu16(0x1000F200); + break; + case 0x10: + ret= psHu16(0x1000F210); + break; + case 0x40: + ret= psHu16(0x1000F240) | 0x0002; + break; + case 0x60: + ret = 0; + break; + default: + ret = psxHu16(mem); + break; + } +#ifdef SIF_LOG + SIF_LOG("Sif reg read %x value %x\n", mem, ret); +#endif + return ret; + } + return *(u16 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1F90) + return SPU2read(mem & 0x1FFFFFFF); + if (t == 0x1000) return DEV9read16(mem & 0x1FFFFFFF); +#ifdef PSXMEM_LOG + PSXMEM_LOG("err lh %8.8lx\n", mem); +#endif + return 0; + } + } +} + +u32 psxMemRead32(u32 mem) { + char *p; + u32 t; + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu32(mem); + else + return psxHwRead32(mem); + } else { + //see also Hw.c + p = (char *)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + if (t == 0x1d00) { + u32 ret; + switch(mem & 0xF0) + { + case 0x00: + ret= psHu32(0x1000F200); + break; + case 0x10: + ret= psHu32(0x1000F210); + break; + case 0x20: + ret= psHu32(0x1000F220); + break; + case 0x30: // EE Side + ret= psHu32(0x1000F230); + break; + case 0x40: + ret= psHu32(0x1000F240) | 0xF0000002; + break; + case 0x60: + ret = 0; + break; + default: + ret = psxHu32(mem); + break; + } +#ifdef SIF_LOG + SIF_LOG("Sif reg read %x value %x\n", mem, ret); +#endif + return ret; + } + return *(u32 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF); + + if (mem != 0xfffe0130) { +#ifdef PSXMEM_LOG + if (g_psxWriteOk) PSXMEM_LOG("err lw %8.8lx\n", mem); +#endif + } else { + return writectrl; + } + return 0; + } + } +} + +void psxMemWrite8(u32 mem, u8 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + } else + if (t == 0x1f40) { + mem&= 0x1fffffff; + psxHw4Write8(mem, value); + } else { + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + *(u8 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if ((t & 0x1FFF)==0x1D00) SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); + if (t == 0x1d00) { + psxSu8(mem) = value; return; + } + if (t == 0x1000) { + DEV9write8(mem & 0x1fffffff, value); return; + } +#ifdef PSXMEM_LOG + PSXMEM_LOG("err sb %8.8lx = %x\n", mem, value); +#endif + } + } +} + +void psxMemWrite16(u32 mem, u16 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu16(mem) = value; + else + psxHwWrite16(mem, value); + } else { + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + if ((t & 0x1FFF)==0x1D00) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value); + *(u16 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if (t == 0x1d00) { + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu16(0x1000F210) = value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu16(0x1000F240) &= ~0xF000; + psHu16(0x1000F240) |= 0x2000; + } + + + if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + else psHu16(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + } + psxSu16(mem) = value; return; + } + if (t == 0x1F90) { + SPU2write(mem & 0x1FFFFFFF, value); return; + } + if (t == 0x1000) { + DEV9write16(mem & 0x1fffffff, value); return; + } +#ifdef PSXMEM_LOG + PSXMEM_LOG("err sh %8.8lx = %x\n", mem, value); +#endif + } + } +} + +void psxMemWrite32(u32 mem, u32 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu32(mem) = value; + else + psxHwWrite32(mem, value); + } else { + //see also Hw.c + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + *(u32 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if (mem != 0xfffe0130) { + if (t == 0x1d00) { +#ifdef MEM_LOG + MEM_LOG("iop Sif reg write %x value %x\n", mem, value); +#endif + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu32(0x1000F210) = value; + return; + case 0x20: + // write to ps2 mem + psHu32(0x1000F220) &= ~value; + return; + case 0x30: + // write to ps2 mem + psHu32(0x1000F230) |= value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu32(0x1000F240) &= ~0xF000; + psHu32(0x1000F240) |= 0x2000; + } + + + if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; + else psHu32(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + } + psxSu32(mem) = value; + + // write to ps2 mem + if( (mem & 0xf0) != 0x60 ) + *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; + return; + } + if (t == 0x1000) { + DEV9write32(mem & 0x1fffffff, value); return; + } + + //if (!g_psxWriteOk) psxCpu->Clear(mem&~3, 1); +#ifdef PSXMEM_LOG + if (g_psxWriteOk) { PSXMEM_LOG("err sw %8.8lx = %x\n", mem, value); } +#endif + } else { + int i; + + writectrl = value; + switch (value) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + if (g_psxWriteOk == 0) break; + g_psxWriteOk = 0; + memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(uptr)); + memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(uptr)); + memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(uptr)); +#ifdef PSXMEM_LOG +// PSXMEM_LOG("writectrl: writenot ok\n"); +#endif + break; + case 0x1e988: + case 0x1edd8: + if (g_psxWriteOk == 1) break; + g_psxWriteOk = 1; + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; + for (i=0; i<0x0080; i++) psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; +#ifdef PSXMEM_LOG +// PSXMEM_LOG("writectrl: write ok\n"); +#endif + break; + default: +#ifdef PSXMEM_LOG + PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); +#endif + break; + } + } + } + } +} + +#endif diff --git a/pcsx2/PsxMem.h b/pcsx2/PsxMem.h new file mode 100644 index 0000000000..762f4b3921 --- /dev/null +++ b/pcsx2/PsxMem.h @@ -0,0 +1,119 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXMEMORY_H__ +#define __PSXMEMORY_H__ + +#ifdef PCSX2_VIRTUAL_MEM + +// VM +#define psxM PS2MEM_PSX +#define psxH PS2MEM_PSXHW + +#define PSXM(mem) ((mem&0x10000000)?PSM(mem):(PS2MEM_PSX+(mem&0x1fffff))) +#define _PSXM(mem) PSXM(mem) + +#else + +// TLB +extern s8 *psxM; +extern s8 *psxP; +extern s8 *psxH; +extern s8 *psxS; +extern uptr *psxMemWLUT; +extern uptr *psxMemRLUT; + +//#define TLB_DEBUG_MEM +#ifdef TLB_DEBUG_MEM +void* PSXM(u32 mem); +void* _PSXM(u32 mem); +#else +#define PSXM(mem) (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#define _PSXM(mem) ((void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#endif + +#define psxSs8(mem) psxS[(mem) & 0xffff] +#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0xffff]) +#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0xffff]) +#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0xffff]) +#define psxSu16(mem) (*(u16*)&psxS[(mem) & 0xffff]) +#define psxSu32(mem) (*(u32*)&psxS[(mem) & 0xffff]) + +#endif + +#define psxMs8(mem) psxM[(mem) & 0x1fffff] +#define psxMs16(mem) (*(s16*)&psxM[(mem) & 0x1fffff]) +#define psxMs32(mem) (*(s32*)&psxM[(mem) & 0x1fffff]) +#define psxMu8(mem) (*(u8*) &psxM[(mem) & 0x1fffff]) +#define psxMu16(mem) (*(u16*)&psxM[(mem) & 0x1fffff]) +#define psxMu32(mem) (*(u32*)&psxM[(mem) & 0x1fffff]) +#define psxMu64(mem) (*(u64*)&psxM[(mem) & 0x1fffff]) + +#define psxPs8(mem) psxP[(mem) & 0xffff] +#define psxPs16(mem) (*(s16*)&psxP[(mem) & 0xffff]) +#define psxPs32(mem) (*(s32*)&psxP[(mem) & 0xffff]) +#define psxPu8(mem) (*(u8*) &psxP[(mem) & 0xffff]) +#define psxPu16(mem) (*(u16*)&psxP[(mem) & 0xffff]) +#define psxPu32(mem) (*(u32*)&psxP[(mem) & 0xffff]) + +#define psxHs8(mem) psxH[(mem) & 0xffff] +#define psxHs16(mem) (*(s16*)&psxH[(mem) & 0xffff]) +#define psxHs32(mem) (*(s32*)&psxH[(mem) & 0xffff]) +#define psxHu8(mem) (*(u8*) &psxH[(mem) & 0xffff]) +#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff]) +#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff]) + +#define PSXMs8(mem) (*(s8 *)_PSXM(mem)) +#define PSXMs16(mem) (*(s16*)_PSXM(mem)) +#define PSXMs32(mem) (*(s32*)_PSXM(mem)) +#define PSXMu8(mem) (*(u8 *)_PSXM(mem)) +#define PSXMu16(mem) (*(u16*)_PSXM(mem)) +#define PSXMu32(mem) (*(u32*)_PSXM(mem)) + +int psxMemInit(); +void psxMemReset(); +void psxMemShutdown(); + +u8 psxMemRead8 (u32 mem); +u16 psxMemRead16(u32 mem); +u32 psxMemRead32(u32 mem); +void psxMemWrite8 (u32 mem, u8 value); +void psxMemWrite16(u32 mem, u16 value); +void psxMemWrite32(u32 mem, u32 value); + +// x86reg and mmreg are always x86 regs +void psxRecMemRead8(); +int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign); + +void psxRecMemRead16(); +int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign); + +void psxRecMemRead32(); +int psxRecMemConstRead32(u32 x86reg, u32 mem); + +void psxRecMemWrite8(); +int psxRecMemConstWrite8(u32 mem, int mmreg); + +void psxRecMemWrite16(); +int psxRecMemConstWrite16(u32 mem, int mmreg); + +void psxRecMemWrite32(); +int psxRecMemConstWrite32(u32 mem, int mmreg); + + +#endif /* __PSXMEMORY_H__ */ diff --git a/pcsx2/PsxSio2.c b/pcsx2/PsxSio2.c new file mode 100644 index 0000000000..72a013d780 --- /dev/null +++ b/pcsx2/PsxSio2.c @@ -0,0 +1,284 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "PsxCommon.h" + +/* +w [8268]=0x3bc sio2_start/sio2man +r [8270] padman_start/padman + padman->7480[00]=bit4; + padman->7480[13]=bit5; + packetExchange(&703F8); +w [8268]|=0x0C; +........ +w [8268]|=0x01; + +only recv2 & dataout influences padman +*/ + +// 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, +// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, packet->sendArray3 +// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, call12/13_s/getparams +// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, + +// 0xBF808240,0xBF808248,0xBF808250,0xBF808258, packet->sendArray1/call_7/8 +// 0xBF808244,0xBF80824C,0xBF808254,0xBF80825C, packet->sendArray2/call_9/10 + +// 0xBF808260, serial data/fifo in/out s/get8260_datain/out packet->sendbuf(nomem!) +// 0xBF808268, ctrl s/get8268_ctrl + +// 0xBF80826C, packet->recv1/2/3 get826C_recv1, get8270_recv2, get8274_recv3 +// 0xBF808270,0xBF808274, + +// 0xBF808278,0xBF80827C, s/get8278, s/get827C +// 0xBF808280 interrupt related s/get8280_intr + + +void sio2Reset() { + SysPrintf("Sio2 init\n"); + memset(&sio2, 0, sizeof(sio2)); + sio2.packet.recvVal1 = 0x1D100; // Nothing is connected at start +} + +u32 sio2_getRecv1() { +#ifdef PAD_LOG + PAD_LOG("Reading Recv1 = %x\n",sio2.packet.recvVal1); +#endif + return sio2.packet.recvVal1; +} + +u32 sio2_getRecv2() { +#ifdef PAD_LOG + PAD_LOG("Reading Recv2 = %x\n",0xF); +#endif + return 0xf; +}//0, 0x10, 0x20, 0x10 | 0x20; bits 4 & 5 + +u32 sio2_getRecv3() { + if(sio2.packet.recvVal3 == 0x8C || sio2.packet.recvVal3 == 0x8b || + sio2.packet.recvVal3 == 0x83) + { +#ifdef PAD_LOG + PAD_LOG("Reading Recv3 = %x\n",sio2.packet.recvVal3); +#endif + sio.packetsize = sio2.packet.recvVal3; + sio2.packet.recvVal3 = 0; // Reset + return sio.packetsize; + }else{ +#ifdef PAD_LOG + PAD_LOG("Reading Recv3 = %x\n",sio.packetsize << 16); +#endif + return sio.packetsize << 16; + } +} + +void sio2_setSend1(u32 index, u32 value){sio2.packet.sendArray1[index]=value;} //0->3 +u32 sio2_getSend1(u32 index){return sio2.packet.sendArray1[index];} //0->3 +void sio2_setSend2(u32 index, u32 value){sio2.packet.sendArray2[index]=value;} //0->3 +u32 sio2_getSend2(u32 index){return sio2.packet.sendArray2[index];} //0->3 + +void sio2_setSend3(u32 index, u32 value) +{ +// int i; + sio2.packet.sendArray3[index]=value; +#ifdef PAD_LOG +// if (index==15){ +// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray1[i]);}PAD_LOG("\n"); +// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray2[i]);}PAD_LOG("\n"); +// for (i=0; i<8; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); +// for ( ; i<16; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); + PAD_LOG("[%d] : 0x%08X ", index,sio2.packet.sendArray3[index]); + PAD_LOG("\n"); +// } +#endif +} //0->15 + +u32 sio2_getSend3(u32 index) {return sio2.packet.sendArray3[index];} //0->15 + +void sio2_setCtrl(u32 value){ + sio2.ctrl=value; + if (sio2.ctrl & 1){ //recv packet + //handle data that had been sent + + //trigger interupt for SIO2 + psxHu32(0x1070)|=0x20000; + //SBUS + sio2.recvIndex=0; + sio2.ctrl &= ~1; + } else { // send packet + //clean up + sio2.packet.sendSize=0; //reset size + sio2.cmdport=0; + sio2.cmdlength=0; + sioWriteCtrl16(SIO_RESET); + } +} +u32 sio2_getCtrl(){return sio2.ctrl;} + +void sio2_setIntr(u32 value){sio2.intr=value;} +u32 sio2_getIntr(){ + return sio2.intr; +} + +void sio2_set8278(u32 value){sio2._8278=value;} +u32 sio2_get8278(){return sio2._8278;} +void sio2_set827C(u32 value){sio2._827C=value;} +u32 sio2_get827C(){return sio2._827C;} + +void sio2_serialIn(u8 value){ + u16 ctrl=0x0002; + if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) + { + + sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; + ctrl &= ~0x2000; + ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; + //sioWriteCtrl16(SIO_RESET); + sioWriteCtrl16(ctrl); +#ifdef PSXDMA_LOG + PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); +#endif + sio2.cmdport++; + } + + if (sio2.cmdlength) sio2.cmdlength--; + sioWrite8(value); + + if (sio2.packet.sendSize > BUFSIZE) {//asadr + SysPrintf("*PCSX2*: sendSize >= %d\n", BUFSIZE); + } else { + sio2.buf[sio2.packet.sendSize] = sioRead8(); + sio2.packet.sendSize++; + } +} +extern void SIODMAWrite(u8 value); + +void sio2_fifoIn(u8 value){ + u16 ctrl=0x0002; + if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) + { + + sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; + ctrl &= ~0x2000; + ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; + //sioWriteCtrl16(SIO_RESET); + sioWriteCtrl16(ctrl); +#ifdef PSXDMA_LOG + PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); +#endif + sio2.cmdport++; + } + + if (sio2.cmdlength) sio2.cmdlength--; + SIODMAWrite(value); + + if (sio2.packet.sendSize > BUFSIZE) {//asadr + SysPrintf("*PCSX2*: sendSize >= %d\n", BUFSIZE); + } else { + sio2.buf[sio2.packet.sendSize] = sioRead8(); + sio2.packet.sendSize++; + } +} + +u8 sio2_fifoOut(){ + if (sio2.recvIndex <= sio2.packet.sendSize){ + //PAD_LOG("READING %x\n",sio2.buf[sio2.recvIndex]); + return sio2.buf[sio2.recvIndex++]; + } else { + SysPrintf("*PCSX2*: buffer overrun\n"); + } + return 0; // No Data +} + +///////////////////////////////////////////////// +//////////////////////////////////////////// DMA +///////////////////////////////////////////////// + +void psxDma11(u32 madr, u32 bcr, u32 chcr) { + unsigned int i, j; + int size = (bcr >> 16) * (bcr & 0xffff); +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 11 - SIO2 in *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + if (chcr != 0x01000201) return; + + for(i = 0; i < (bcr >> 16); i++) + { + sio.count = 1; + for(j = 0; j < ((bcr & 0xFFFF) * 4); j++) + { + sio2_fifoIn(PSXMu8(madr)); + madr++; + if(sio2.packet.sendSize == BUFSIZE) { + HW_DMA11_MADR = madr; + PSX_INT(11,(size>>2)); // Interrupts should always occur at the end + return; + } + } + + } + + HW_DMA11_MADR = madr; + PSX_INT(11,(size>>2)); // Interrupts should always occur at the end +} + +void psxDMA11Interrupt() +{ + HW_DMA11_CHCR &= ~0x01000000; + psxDmaInterrupt2(4); + psxRegs.interrupt&= ~(1 << 11); +} + +void psxDma12(u32 madr, u32 bcr, u32 chcr) { + int size = bcr; +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 12 - SIO2 out *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + if (chcr != 0x41000200) return; + + sio2.recvIndex = 0; // Set To start; saqib + + bcr = ((bcr >> 16) * (bcr & 0xFFFF)) * 4; // 8 bits + + while (bcr > 0) { + PSXMu8(madr) = sio2_fifoOut(); + bcr--; madr++; + if(sio2.recvIndex == sio2.packet.sendSize) break; + } + HW_DMA12_MADR = madr; + PSX_INT(12,(size>>2)); // Interrupts should always occur at the end +} + +void psxDMA12Interrupt() +{ + HW_DMA12_CHCR &= ~0x01000000; + psxDmaInterrupt2(5); + psxRegs.interrupt&= ~(1 << 12); +} + +int sio2Freeze(gzFile f, int Mode) { + gzfreeze(&sio2, sizeof(sio2)); + + return 0; +} + diff --git a/pcsx2/PsxSio2.h b/pcsx2/PsxSio2.h new file mode 100644 index 0000000000..6e64de113c --- /dev/null +++ b/pcsx2/PsxSio2.h @@ -0,0 +1,100 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __PSXSIO2_H__ +#define __PSXSIO2_H__ + + +#define BUFSIZE 8448 + +//from sio2man.c + +struct SIO2_packet { + unsigned int recvVal1; // 0x00 + unsigned int sendArray1[4]; // 0x04-0x10 + unsigned int sendArray2[4]; // 0x14-0x20 + + unsigned int recvVal2; // 0x24 + + unsigned int sendArray3[16]; // 0x28-0x64 + + unsigned int recvVal3; // 0x68 + + int sendSize; // 0x6C + int recvSize; // 0x70 + + unsigned char *sendBuf; // 0x74 + unsigned char *recvBuf; // 0x78 + + unsigned int dmacAddress1; + unsigned int dmacSize1; + unsigned int dmacCount1; + unsigned int dmacAddress2; + unsigned int dmacSize2; + unsigned int dmacCount2; +}; + +typedef struct { + struct SIO2_packet packet; + u32 ctrl; + u32 intr; + u32 _8278, _827C; + int recvIndex; + u32 hackedRecv; + int cmdport; + int cmdlength; //length of a command sent to a port + //is less_equal than the dma send size + u8 buf[BUFSIZE]; +} sio2Struct; + +sio2Struct sio2; + +void sio2Reset(); + +u32 sio2_getRecv1(); +u32 sio2_getRecv2(); +u32 sio2_getRecv3(); +void sio2_setSend1(u32 index, u32 value); //0->3 +u32 sio2_getSend1(u32 index); //0->3 +void sio2_setSend2(u32 index, u32 value); //0->3 +u32 sio2_getSend2(u32 index); //0->3 +void sio2_setSend3(u32 index, u32 value); //0->15 +u32 sio2_getSend3(u32 index); //0->15 + +void sio2_setCtrl(u32 value); +u32 sio2_getCtrl(); +void sio2_setIntr(u32 value); +u32 sio2_getIntr(); +void sio2_set8278(u32 value); +u32 sio2_get8278(); +void sio2_set827C(u32 value); +u32 sio2_get827C(); + +void sio2_serialIn(u8 value); +void sio2_fifoIn(u8 value); +u8 sio2_fifoOut(); + +void psxDma11(u32 madr, u32 bcr, u32 chcr); +void psxDma12(u32 madr, u32 bcr, u32 chcr); + +void psxDMA11Interrupt(); +void psxDMA12Interrupt(); +int sio2Freeze(gzFile f, int Mode); + +#endif /* __PSXSIO2_H__ */ + diff --git a/pcsx2/R3000A.c b/pcsx2/R3000A.c new file mode 100644 index 0000000000..4614f53bbf --- /dev/null +++ b/pcsx2/R3000A.c @@ -0,0 +1,218 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "PsxCommon.h" +#include "Misc.h" + +// used for constant propagation +R3000Acpu *psxCpu; +u32 g_psxConstRegs[32]; +u32 g_psxHasConstReg, g_psxFlushedConstReg; +u32 g_psxNextBranchCycle = 0; + +PCSX2_ALIGNED16(psxRegisters psxRegs); + +int psxInit() +{ + psxCpu = CHECK_EEREC ? &psxRec : &psxInt; + +#ifdef PCSX2_DEVBUILD + Log=0; +#endif + + if (psxMemInit() == -1) return -1; + + return psxCpu->Init(); +} + +void psxReset() { + + psxCpu->Reset(); + + psxMemReset(); + + memset(&psxRegs, 0, sizeof(psxRegs)); + + psxRegs.pc = 0xbfc00000; // Start in bootstrap + + psxRegs.CP0.n.Status = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 + psxRegs.CP0.n.PRid = 0x0000001f; // PRevID = Revision ID, same as the IOP R3000A + + psxHwReset(); + psxBiosInit(); + psxExecuteBios(); +} + +void psxShutdown() { + psxMemShutdown(); + psxBiosShutdown(); + psxSIOShutdown(); + psxCpu->Shutdown(); +} + +void psxException(u32 code, u32 bd) { +// PSXCPU_LOG("psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); +// SysPrintf("psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); + // Set the Cause + psxRegs.CP0.n.Cause &= ~0x7f; + psxRegs.CP0.n.Cause |= code; + +#ifdef PSXCPU_LOG + if (bd) { PSXCPU_LOG("bd set\n"); } +#endif + // Set the EPC & PC + if (bd) { + psxRegs.CP0.n.Cause|= 0x80000000; + psxRegs.CP0.n.EPC = (psxRegs.pc - 4); + } else + psxRegs.CP0.n.EPC = (psxRegs.pc); + + if (psxRegs.CP0.n.Status & 0x400000) + psxRegs.pc = 0xbfc00180; + else + psxRegs.pc = 0x80000080; + + // Set the Status + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) | + ((psxRegs.CP0.n.Status & 0xf) << 2); + + /*if ((((PSXMu32(psxRegs.CP0.n.EPC) >> 24) & 0xfe) == 0x4a)) { + // "hokuto no ken" / "Crash Bandicot 2" ... fix + PSXMu32(psxRegs.CP0.n.EPC)&= ~0x02000000; + }*/ + + if (Config.PsxOut && !CHECK_EEREC) { + u32 call = psxRegs.GPR.n.t1 & 0xff; + switch (psxRegs.pc & 0x1fffff) { + case 0xa0: +#ifdef PSXBIOS_LOG + if (call != 0x28 && call != 0xe) { + PSXBIOS_LOG("Bios call a0: %s (%x) %x,%x,%x,%x\n", biosA0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); } +#endif + if (biosA0[call]) + biosA0[call](); + break; + case 0xb0: +#ifdef PSXBIOS_LOG + if (call != 0x17 && call != 0xb) { + PSXBIOS_LOG("Bios call b0: %s (%x) %x,%x,%x,%x\n", biosB0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); } +#endif + if (biosB0[call]) + biosB0[call](); + break; + case 0xc0: +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("Bios call c0: %s (%x) %x,%x,%x,%x\n", biosC0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); +#endif + if (biosC0[call]) + biosC0[call](); + break; + } + } + + /*if (psxRegs.CP0.n.Cause == 0x400 && (!(psxHu32(0x1450) & 0x8))) { + hwIntcIrq(1); + }*/ +} + +#define PSX_TESTINT(n, callback) \ + if (psxRegs.interrupt & (1 << n)) { \ + if ((int)(psxRegs.cycle - psxRegs.sCycle[n]) >= psxRegs.eCycle[n]) { \ + callback(); \ + } \ + else if( (int)(g_psxNextBranchCycle - psxRegs.sCycle[n]) > psxRegs.eCycle[n] ) \ + g_psxNextBranchCycle = psxRegs.sCycle[n] + psxRegs.eCycle[n]; \ + } + +static void _psxTestInterrupts() { + // uncommenting until refraction can give a good reason as to why it shouldn't be here + // Good reason given, why have something in there we dont use anymore? + /*PSX_TESTINT(4, psxDma4Interrupt); + PSX_TESTINT(7, psxDma7Interrupt);*/ + + PSX_TESTINT(9, sif0Interrupt); // SIF0 + PSX_TESTINT(10, sif1Interrupt); // SIF1 + PSX_TESTINT(11, psxDMA11Interrupt); // SIO2 + PSX_TESTINT(12, psxDMA12Interrupt); // SIO2 + PSX_TESTINT(16, sioInterrupt); + PSX_TESTINT(17, cdrInterrupt); + PSX_TESTINT(18, cdrReadInterrupt); + PSX_TESTINT(19, cdvdReadInterrupt); + PSX_TESTINT(20, dev9Interrupt); + PSX_TESTINT(21, usbInterrupt); +} + +#define IOP_WAIT_CYCLE 64 + +void psxBranchTest() +{ + EEsCycle -= (psxRegs.cycle - IOPoCycle) << 3; + IOPoCycle = psxRegs.cycle; + if( EEsCycle > 0 ) + g_psxNextBranchCycle = psxRegs.cycle + min(IOP_WAIT_CYCLE, (EEsCycle>>3)); + else + g_psxNextBranchCycle = psxRegs.cycle; + + if ((int)(psxRegs.cycle - psxNextsCounter) >= psxNextCounter) + psxRcntUpdate(); + + if (psxRegs.interrupt) { + _psxTestInterrupts(); + } + +// if( (int)psxRegs.cycle-(int)g_psxNextBranchCycle > 0 ) +// g_psxNextBranchCycle = psxRegs.cycle+1; +// else + if( (int)(g_psxNextBranchCycle-psxNextsCounter) >= (u32)psxNextCounter ) + g_psxNextBranchCycle = (u32)psxNextsCounter+(u32)psxNextCounter; + + if (psxHu32(0x1078)) { + if(psxHu32(0x1070) & psxHu32(0x1074)){ + if ((psxRegs.CP0.n.Status & 0xFE01) >= 0x401) { +//#ifdef PSXCPU_LOG +// PSXCPU_LOG("Interrupt: %x %x\n", HWMu32(0x1070), HWMu32(0x1074)); +//#endif + psxException(0, 0); + } + } + } +} + +void psxExecuteBios() { +/* while (psxRegs.pc != 0x80030000) + psxCpu->ExecuteBlock(); +#ifdef PSX_LOG + PSX_LOG("*BIOS END*\n"); +#endif*/ +} + +void psxRestartCPU() +{ + psxCpu->Shutdown(); + psxCpu = CHECK_EEREC ? &psxRec : &psxInt; + + if (psxCpu->Init() == -1) { + SysClose(); + exit(1); + } + psxCpu->Reset(); +} diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h new file mode 100644 index 0000000000..cc56d3b7c0 --- /dev/null +++ b/pcsx2/R3000A.h @@ -0,0 +1,213 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __R3000A_H__ +#define __R3000A_H__ + +#include + +extern u32 g_psxNextBranchCycle; + +typedef struct { + int (*Init)(); + void (*Reset)(); + void (*Execute)(); /* executes up to a break */ + void (*ExecuteBlock)(); /* executes up to a jump */ + void (*Clear)(u32 Addr, u32 Size); + void (*Shutdown)(); +} R3000Acpu; + +extern R3000Acpu *psxCpu; +extern R3000Acpu psxInt; +extern R3000Acpu psxRec; + +typedef union { + struct { + u32 r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra, hi, lo; // hi needs to be at index 32! don't change + } n; + u32 r[34]; /* Lo, Hi in r[33] and r[32] */ +} GPRRegs; + +typedef union { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare, + Status, Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Reserved3, + Reserved4, Reserved5, ECC, CacheErr, + TagLo, TagHi, ErrorEPC, Reserved6; + } n; + u32 r[32]; +} CP0Regs; + +typedef struct { + short x, y; +} SVector2D; + +typedef struct { + short z, pad; +} SVector2Dz; + +typedef struct { + short x, y, z, pad; +} SVector3D; + +typedef struct { + short x, y, z, pad; +} LVector3D; + +typedef struct { + unsigned char r, g, b, c; +} CBGR; + +typedef struct { + short m11, m12, m13, m21, m22, m23, m31, m32, m33, pad; +} SMatrix3D; + +typedef union { + struct { + SVector3D v0, v1, v2; + CBGR rgb; + s32 otz; + s32 ir0, ir1, ir2, ir3; + SVector2D sxy0, sxy1, sxy2, sxyp; + SVector2Dz sz0, sz1, sz2, sz3; + CBGR rgb0, rgb1, rgb2; + s32 reserved; + s32 mac0, mac1, mac2, mac3; + u32 irgb, orgb; + s32 lzcs, lzcr; + } n; + u32 r[32]; +} CP2Data; + +typedef union { + struct { + SMatrix3D rMatrix; + s32 trX, trY, trZ; + SMatrix3D lMatrix; + s32 rbk, gbk, bbk; + SMatrix3D cMatrix; + s32 rfc, gfc, bfc; + s32 ofx, ofy; + s32 h; + s32 dqa, dqb; + s32 zsf3, zsf4; + s32 flag; + } n; + u32 r[32]; +} CP2Ctrl; + +typedef struct psxRegisters_t { + GPRRegs GPR; /* General Purpose Registers */ + CP0Regs CP0; /* Coprocessor0 Registers */ + CP2Data CP2D; /* Cop2 data registers */ + CP2Ctrl CP2C; /* Cop2 control registers */ + u32 pc; /* Program counter */ + u32 code; /* The instruction */ + u32 cycle; + u32 interrupt; + u32 sCycle[64]; + u32 eCycle[64]; + u32 _msflag[32]; + u32 _smflag[32]; +} psxRegisters; + +extern PCSX2_ALIGNED16_DECL(psxRegisters psxRegs); + +#define PSX_IS_CONST1(reg) ((reg)<32 && (g_psxHasConstReg&(1<<(reg)))) +#define PSX_IS_CONST2(reg1, reg2) ((g_psxHasConstReg&(1<<(reg1)))&&(g_psxHasConstReg&(1<<(reg2)))) +#define PSX_SET_CONST(reg) { \ + if( (reg) < 32 ) { \ + g_psxHasConstReg |= (1<<(reg)); \ + g_psxFlushedConstReg &= ~(1<<(reg)); \ + } \ +} + +#define PSX_DEL_CONST(reg) { \ + if( (reg) < 32 ) g_psxHasConstReg &= ~(1<<(reg)); \ +} + +extern u32 g_psxConstRegs[32]; +extern u32 g_psxHasConstReg, g_psxFlushedConstReg; + +#ifndef _PC_ + +#define _i32(x) (s32)x +#define _u32(x) x + +#define _i16(x) (short)x +#define _u16(x) (unsigned short)x + +#define _i8(x) (char)x +#define _u8(x) (unsigned char)x + +/**** R3000A Instruction Macros ****/ +#define _PC_ psxRegs.pc // The next PC to be executed + +#define _Funct_ ((psxRegs.code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((psxRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((psxRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((psxRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((psxRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ((unsigned short)psxRegs.code) // The immediate part of the instruction register +#define _Target_ (psxRegs.code & 0x03ffffff) // The target part of the instruction register + +#define _Imm_ ((short)psxRegs.code) // sign-extended immediate +#define _ImmU_ (psxRegs.code&0xffff) // zero-extended immediate + +#define _rRs_ psxRegs.GPR.r[_Rs_] // Rs register +#define _rRt_ psxRegs.GPR.r[_Rt_] // Rt register +#define _rRd_ psxRegs.GPR.r[_Rd_] // Rd register +#define _rSa_ psxRegs.GPR.r[_Sa_] // Sa register +#define _rFs_ psxRegs.CP0.r[_Rd_] // Fs register + +#define _c2dRs_ psxRegs.CP2D.r[_Rs_] // Rs cop2 data register +#define _c2dRt_ psxRegs.CP2D.r[_Rt_] // Rt cop2 data register +#define _c2dRd_ psxRegs.CP2D.r[_Rd_] // Rd cop2 data register +#define _c2dSa_ psxRegs.CP2D.r[_Sa_] // Sa cop2 data register + +#define _rHi_ psxRegs.GPR.n.hi // The HI register +#define _rLo_ psxRegs.GPR.n.lo // The LO register + +#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ (((s32)(s16)_Imm_ * 4) + _PC_) // Calculates the target during a branch instruction +//#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +//#define _BranchTarget_ ((short)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register + +extern int EEsCycle; +extern u32 EEoCycle, IOPoCycle; + +#endif + +int psxInit(); +void psxReset(); +void psxShutdown(); +void psxException(u32 code, u32 step); +void psxBranchTest(); +void psxExecuteBios(); +void psxRestartCPU(); + +#endif /* __R3000A_H__ */ diff --git a/pcsx2/R5900.c b/pcsx2/R5900.c new file mode 100644 index 0000000000..a96c02a8cd --- /dev/null +++ b/pcsx2/R5900.c @@ -0,0 +1,633 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "Common.h" +#include "Memory.h" +#include "Hw.h" +#include "DebugTools/Debug.h" +#include "R3000A.h" +#include "VUmicro.h" +#include "GS.h" + +#include "Paths.h" + +static int inter; + +PCSX2_ALIGNED16(cpuRegisters cpuRegs); +PCSX2_ALIGNED16(fpuRegisters fpuRegs); +PCSX2_ALIGNED16(tlbs tlb[48]); +PCSX2_ALIGNED16(GPR_reg64 g_cpuConstRegs[32]) = {0}; + +u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; +R5900cpu *Cpu; + +int EEsCycle; +u32 EEoCycle, IOPoCycle; +u32 bExecBIOS = 0; // set if the BIOS has already been executed + +extern u32 dwSaveVersion; + +int cpuInit() +{ + int ret; + + SysPrintf("PCSX2 v" PCSX2_VERSION " save ver: %x\n", dwSaveVersion); + /*SysPrintf("Color Legend: White - PCSX2 message\n"); + SysPrintf(COLOR_GREEN " Green - EE sio2 printf\n" COLOR_RESET); + SysPrintf(COLOR_RED " Red - IOP printf\n" COLOR_RESET);*/ + SysPrintf("EE pc offset: 0x%x, PSX pc offset: 0x%x\n", (u32)&cpuRegs.pc - (u32)&cpuRegs, (u32)&psxRegs.pc - (u32)&psxRegs); + + InitFPUOps(); + + cpuRegs.constzero = 0; +#ifdef PCSX2_NORECBUILD + Cpu = &intCpu; +#else + cpudetectInit(); + Cpu = CHECK_EEREC ? &recCpu : &intCpu; +#endif + + ret = Cpu->Init(); + if (ret == -1 && CHECK_EEREC) { + SysMessage(_("Error initializing Recompiler, switching to Interpreter")); + Config.Options &= ~(PCSX2_EEREC|PCSX2_VU1REC|PCSX2_VU0REC); + Cpu = &intCpu; + ret = Cpu->Init(); + } + +#ifdef PCSX2_VIRTUAL_MEM + if (memInit() == -1) { + PROCESS_INFORMATION pi; + STARTUPINFO si; + char strdir[255], strexe[255]; + if( MessageBox(NULL, "Failed to allocate enough physical memory to run pcsx2. Try closing\n" + "down background programs, restarting windows, or buying more memory.\n\n" + "Launch TLB version of pcsx2 (pcsx2t.exe)?", "Memory Allocation Error", MB_YESNO) == IDYES ) { + + GetCurrentDirectory(ARRAYSIZE(strdir), strdir); + _snprintf(strexe, ARRAYSIZE(strexe), "%s\\pcsx2t.exe", strdir); + + memset(&si, 0, sizeof(si)); + + if( !CreateProcess(strexe, "", NULL, NULL, FALSE, DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, NULL, strdir, &si, &pi)) { + _snprintf(strdir, ARRAYSIZE(strexe), "Failed to launch %s\n", strexe); + MessageBox(NULL, strdir, "Failure", MB_OK); + } + else { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } + + return -1; + } +#endif + if (hwInit() == -1) return -1; + if (vu0Init() == -1) return -1; + if (vu1Init() == -1) return -1; +#ifndef PCSX2_VIRTUAL_MEM + if (memInit() == -1) return -1; +#endif + +#ifdef PCSX2_DEVBUILD + Log = 0; +#endif + + return ret; +} + +void cpuReset() +{ + Cpu->Reset(); + + memReset(); + + memset(&cpuRegs, 0, sizeof(cpuRegs)); + memset(&fpuRegs, 0, sizeof(fpuRegs)); + memset(&tlb, 0, sizeof(tlb)); + + cpuRegs.pc = 0xbfc00000; ///set pc reg to stack + cpuRegs.CP0.n.Config = 0x440; + cpuRegs.CP0.n.Status.val = 0x70400004; //0x10900000 <-- wrong; // COP0 enabled | BEV = 1 | TS = 1 + cpuRegs.CP0.n.PRid = 0x00002e20; // PRevID = Revision ID, same as R5900 + fpuRegs.fprc[0] = 0x00002e00; // fpu Revision.. + fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control + + vu0Reset(); + vu1Reset(); + hwReset(); + vif0Reset(); + vif1Reset(); + rcntInit(); + psxReset(); +} + +void cpuShutdown() +{ + hwShutdown(); +// biosShutdown(); + psxShutdown(); + vu0Shutdown(); + vu1Shutdown(); + memShutdown(); + gsShutdown(); + disR5900FreeSyms(); + + Cpu->Shutdown(); +} + +void cpuException(u32 code, u32 bd) { + u32 offset; + cpuRegs.CP0.n.Cause = code & 0xffff; + + if(cpuRegs.CP0.n.Status.b.ERL == 0){ //Error Level 0-1 + if(((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC)) offset = 0x0; //TLB Refill + else if ((code & 0x7C) == 0x0) offset = 0x200; //Interrupt + else offset = 0x180; // Everything else + + + if (cpuRegs.CP0.n.Status.b.EXL == 0) { + cpuRegs.CP0.n.Status.b.EXL = 1; + if (bd) { + SysPrintf("branch delay!!\n"); + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + cpuRegs.CP0.n.Cause |= 0x80000000; + } else { + cpuRegs.CP0.n.EPC = cpuRegs.pc; + cpuRegs.CP0.n.Cause &= ~0x80000000; + } + } else { + offset = 0x180; //Overrride the cause + SysPrintf("cpuException: Status.EXL = 1 cause %x\n", code); + } + if (cpuRegs.CP0.n.Status.b.BEV == 0) { + cpuRegs.pc = 0x80000000 + offset; + } else { + cpuRegs.pc = 0xBFC00200 + offset; + } + } else { //Error Level 2 + SysPrintf("FIX ME: Level 2 cpuException\n"); + if((code & 0x38000) <= 0x8000 ) { //Reset / NMI + cpuRegs.pc = 0xBFC00000; + SysPrintf("Reset request\n"); + UpdateCP0Status(); + return; + } else if((code & 0x38000) == 0x10000) offset = 0x80; //Performance Counter + else if((code & 0x38000) == 0x18000) offset = 0x100; //Debug + else SysPrintf("Unknown Level 2 Exception!! Cause %x\n", code); + + if (cpuRegs.CP0.n.Status.b.EXL == 0) { + cpuRegs.CP0.n.Status.b.EXL = 1; + if (bd) { + SysPrintf("branch delay!!\n"); + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + cpuRegs.CP0.n.Cause |= 0x80000000; + } else { + cpuRegs.CP0.n.EPC = cpuRegs.pc; + cpuRegs.CP0.n.Cause &= ~0x80000000; + } + } else { + offset = 0x180; //Overrride the cause + SysPrintf("cpuException: Status.EXL = 1 cause %x\n", code); + } + if (cpuRegs.CP0.n.Status.b.DEV == 0) { + cpuRegs.pc = 0x80000000 + offset; + } else { + cpuRegs.pc = 0xBFC00200 + offset; + } + } + UpdateCP0Status(); +} + +void cpuTlbMiss(u32 addr, u32 bd, u32 excode) { + SysPrintf("cpuTlbMiss %x, %x, addr: %x, status=%x, code=%x\n", cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode); + if (bd) { + SysPrintf("branch delay!!\n"); + } + + assert(0); // temporary + + cpuRegs.CP0.n.BadVAddr = addr; + cpuRegs.CP0.n.Context &= 0xFF80000F; + cpuRegs.CP0.n.Context |= (addr >> 9) & 0x007FFFF0; + cpuRegs.CP0.n.EntryHi = (addr & 0xFFFFE000) | (cpuRegs.CP0.n.EntryHi & 0x1FFF); + + cpuRegs.CP0.n.Cause = excode; + if (!(cpuRegs.CP0.n.Status.val & 0x2)) { // EXL bit + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + } + + if ((cpuRegs.CP0.n.Status.val & 0x1) == 0) { + cpuRegs.pc = 0x80000000; + } else { + cpuRegs.pc = 0x80000180; + } + + cpuRegs.CP0.n.Status.b.EXL = 1; + UpdateCP0Status(); +// Log=1; varLog|= 0x40000000; +} + +void cpuTlbMissR(u32 addr, u32 bd) { + cpuTlbMiss(addr, bd, EXC_CODE_TLBL); +} + +void cpuTlbMissW(u32 addr, u32 bd) { + cpuTlbMiss(addr, bd, EXC_CODE_TLBS); +} + +void JumpCheckSym(u32 addr, u32 pc) { +#if 0 +// if (addr == 0x80051770) { SysPrintf("Log!: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); Log=1; varLog|= 0x40000000; } + if (addr == 0x8002f150) { SysPrintf("printk: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); } + if (addr == 0x8002aba0) return; + if (addr == 0x8002f450) return; + if (addr == 0x800dd520) return; +// if (addr == 0x80049300) SysPrintf("register_blkdev: %x\n", cpuRegs.GPR.n.a0.UL[0]); + if (addr == 0x8013cb70) { SysPrintf("change_root: %x\n", cpuRegs.GPR.n.a0.UL[0]); } +// if (addr == 0x8013d1e8) { SysPrintf("Log!\n"); Log++; if (Log==2) exit(0); varLog|= 0x40000000; } +// if (addr == 0x00234e88) { SysPrintf("StoreImage\n"); Log=1; /*psMu32(0x234e88) = 0x03e00008; psMu32(0x234e8c) = 0;*/ } +#endif +/* if ((pc >= 0x00131D50 && + pc < 0x00132454) || + (pc >= 0x00786a90 && + pc < 0x00786ac8))*/ + /*if (varLog & 0x40000000) { + char *str; + char *strf; + + str = disR5900GetSym(addr); + if (str != NULL) { + strf = disR5900GetUpperSym(pc); + if (strf) { + SysPrintf("Func %8.8x: %s (called by %8.8x: %s)\n", addr, str, pc, strf); + } else { + SysPrintf("Func %8.8x: %s (called by %x)\n", addr, str, pc); + } + if (!strcmp(str, "printf")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } + if (!strcmp(str, "printk")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } + } + }*/ +} + +void JumpCheckSymRet(u32 addr) { + /*if (varLog & 0x40000000) { + char *str; + str = disR5900GetUpperSym(addr); + if (str != NULL) { + SysPrintf("Return : %s, v0=%8.8x\n", str, cpuRegs.GPR.n.v0.UL[0]); + } + }*/ +} + +__inline void _cpuTestMissingINTC() { + if (cpuRegs.CP0.n.Status.val & 0x400 && + psHu32(INTC_STAT) & psHu32(INTC_MASK)) { + if ((cpuRegs.interrupt & (1 << 30)) == 0) { + SysPrintf("*PCSX2*: Error, missing INTC Interrupt\n"); + } + } +} + +__inline void _cpuTestMissingDMAC() { + if (cpuRegs.CP0.n.Status.val & 0x800 && + (psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000)) { + if ((cpuRegs.interrupt & (1 << 31)) == 0) { + SysPrintf("*PCSX2*: Error, missing DMAC Interrupt\n"); + } + } +} + +void cpuTestMissingHwInts() { + if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { + _cpuTestMissingINTC(); + _cpuTestMissingDMAC(); +// _cpuTestTIMR(); + } +} + +#define TESTINT(n, callback) { \ + if ( (cpuRegs.interrupt & (1 << n)) ) { \ + if( ((int)(cpuRegs.cycle - cpuRegs.sCycle[n]) >= cpuRegs.eCycle[n]) ) { \ + callback(); \ + } \ + else if( (int)(g_nextBranchCycle - cpuRegs.sCycle[n]) > cpuRegs.eCycle[n] ) { \ + g_nextBranchCycle = cpuRegs.sCycle[n] + cpuRegs.eCycle[n]; \ + } \ + } \ +} \ + +void _cpuTestInterrupts() { + + inter = cpuRegs.interrupt; + /* These are 'pcsx2 interrupts', they handle asynchronous stuff + that depends on the cycle timings */ + + TESTINT(0, vif0Interrupt); + TESTINT(10, vifMFIFOInterrupt); + TESTINT(1, vif1Interrupt); + TESTINT(11, gifMFIFOInterrupt); + TESTINT(2, gsInterrupt); + TESTINT(3, ipu0Interrupt); + TESTINT(4, ipu1Interrupt); + TESTINT(5, EEsif0Interrupt); + TESTINT(6, EEsif1Interrupt); + TESTINT(8, SPRFROMinterrupt); + TESTINT(9, SPRTOinterrupt); + + if ((cpuRegs.CP0.n.Status.val & 0x10007) != 0x10001) return; + TESTINT(30, intcInterrupt); + TESTINT(31, dmacInterrupt); +} + +u32 s_iLastCOP0Cycle = 0; +u32 s_iLastPERFCycle[2] = {0,0}; + +static void _cpuTestTIMR() { + cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; + s_iLastCOP0Cycle = cpuRegs.cycle; + + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + } + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + s_iLastPERFCycle[1] = cpuRegs.cycle; + } + + if ( (cpuRegs.CP0.n.Status.val & 0x8000) && + cpuRegs.CP0.n.Count >= cpuRegs.CP0.n.Compare && cpuRegs.CP0.n.Count < cpuRegs.CP0.n.Compare+1000 ) { + SysPrintf("timr intr: %x, %x\n", cpuRegs.CP0.n.Count, cpuRegs.CP0.n.Compare); + cpuException(0x808000, cpuRegs.branch); + } +} + +#define EE_WAIT_CYCLE 512 + +// if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates +u32 g_nextBranchCycle = 0; +u32 s_lastvsync[2]; +extern u8 g_globalXMMSaved; +X86_32CODE(extern u8 g_globalMMXSaved;) + +u32 loaded = 0; +u32 g_MTGSVifStart = 0, g_MTGSVifCount=0; +extern void gsWaitGS(); + +void cpuBranchTest() +{ +#ifndef PCSX2_NORECBUILD + // dont' remove this check unless doing an official release + if( g_globalXMMSaved X86_32CODE(|| g_globalMMXSaved) ) + SysPrintf("frozen regs have not been restored!!!\n"); + assert( !g_globalXMMSaved X86_32CODE(&& !g_globalMMXSaved) ); + g_EEFreezeRegs = 0; +#endif + +// if( !loaded && cpuRegs.cycle > 0x20000000 ) { +// char strstate[255]; +// sprintf(strstate, SSTATES_DIR "/%8.8X.000", ElfCRC); +// LoadState(strstate); +// loaded = 1; +// } + + g_nextBranchCycle = cpuRegs.cycle + EE_WAIT_CYCLE; + + if ((int)(cpuRegs.cycle - nextsCounter) >= nextCounter) + rcntUpdate(); + + // stall mtgs if it is taking too long + if( g_MTGSVifCount > 0 ) { + if( cpuRegs.cycle-g_MTGSVifStart > g_MTGSVifCount ) { + gsWaitGS(); + g_MTGSVifCount = 0; + } + } + + if (cpuRegs.interrupt) + _cpuTestInterrupts(); + + if( (int)(g_nextBranchCycle-nextsCounter) >= nextCounter ) + g_nextBranchCycle = nextsCounter+nextCounter; + +//#ifdef CPU_LOG +// cpuTestMissingHwInts(); +//#endif + _cpuTestTIMR(); + + EEsCycle += cpuRegs.cycle - EEoCycle; + EEoCycle = cpuRegs.cycle; + + psxCpu->ExecuteBlock(); + + if (VU0.VI[REG_VPU_STAT].UL & 0x1) { + FreezeXMMRegs(1); + Cpu->ExecuteVU0Block(); + FreezeXMMRegs(0); + } + + if( (int)cpuRegs.cycle-(int)g_nextBranchCycle > 0 ) + g_nextBranchCycle = cpuRegs.cycle+1; + +#ifndef PCSX2_NORECBUILD + assert( !g_globalXMMSaved X86_32CODE(&& !g_globalMMXSaved) ); + g_EEFreezeRegs = 1; +#endif +} + +static void _cpuTestINTC() { + if ((cpuRegs.CP0.n.Status.val & 0x10407) == 0x10401){ + if (psHu32(INTC_STAT) & psHu32(INTC_MASK)) { + if ((cpuRegs.interrupt & (1 << 30)) == 0) { + INT(30,4); + } + } + } +} + +static void _cpuTestDMAC() { + if ((cpuRegs.CP0.n.Status.val & 0x10807) == 0x10801){ + if (psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000) { + if ( (cpuRegs.interrupt & (1 << 31)) == 0) { + INT(31, 4); + } + } + } +} + +void cpuTestHwInts() { + //if ((cpuRegs.CP0.n.Status.val & 0x10007) != 0x10001) return; + _cpuTestINTC(); + _cpuTestDMAC(); + _cpuTestTIMR(); +} + +void cpuTestINTCInts() { + //if ((cpuRegs.CP0.n.Status.val & 0x10407) == 0x10401) { + _cpuTestINTC(); + //} +} + +void cpuTestDMACInts() { + //if ((cpuRegs.CP0.n.Status.val & 0x10807) == 0x10801) { + _cpuTestDMAC(); + //} +} + +void cpuTestTIMRInts() { + if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { + _cpuTestTIMR(); + } +} + +void cpuExecuteBios() +{ + // filter CPU options + if( CHECK_EEREC ) Config.Options |= PCSX2_COP2REC; + else Config.Options &= ~PCSX2_COP2REC; + +#ifndef PCSX2_NORECBUILD + if( !cpucaps.hasStreamingSIMDExtensions ) { + Config.Options &= ~(PCSX2_VU1REC|PCSX2_VU0REC); + } +#endif + + // remove frame skipping if GS doesn't support it + switch(CHECK_FRAMELIMIT) { + case PCSX2_FRAMELIMIT_SKIP: + case PCSX2_FRAMELIMIT_VUSKIP: + if( GSsetFrameSkip == NULL ) + Config.Options &= ~PCSX2_FRAMELIMIT_MASK; + break; + } + + SysPrintf("Using Frame Skipping: "); + switch(CHECK_FRAMELIMIT) { + case PCSX2_FRAMELIMIT_NORMAL: SysPrintf("Normal\n"); break; + case PCSX2_FRAMELIMIT_LIMIT: SysPrintf("Limit\n"); break; + case PCSX2_FRAMELIMIT_SKIP: SysPrintf("Skip\n"); break; + case PCSX2_FRAMELIMIT_VUSKIP: SysPrintf("VU Skip\n"); break; + } + + //? if(CHECK_FRAMELIMIT==PCSX2_FRAMELIMIT_LIMIT) + { + extern u64 GetTickFrequency(); + extern u64 iTicks; + u32 vsyncs = (Config.PsxType&1) ? 50:60; + if(Config.CustomFps>0) vsyncs = Config.CustomFps; + iTicks = GetTickFrequency()/vsyncs; + SysPrintf("Framelimiter rate updated (cpuExecuteBios): %d fps\n",vsyncs); + } + + SysPrintf("* PCSX2 *: ExecuteBios\n"); + + bExecBIOS = TRUE; + while (cpuRegs.pc != 0x00200008 && + cpuRegs.pc != 0x00100008) { + Cpu->ExecuteBlock(); + } + + bExecBIOS = FALSE; +// { +// FILE* f = fopen("eebios.bin", "wb"); +// fwrite(PSM(0x80000000), 0x100000, 1, f); +// fclose(f); +// exit(0); + +// f = fopen("iopbios.bin", "wb"); +// fwrite(PS2MEM_PSX, 0x80000, 1, f); +// fclose(f); +// } + +// REC_CLEARM(0x00200008); +// REC_CLEARM(0x00100008); +// REC_CLEARM(cpuRegs.pc); + if( CHECK_EEREC ) Cpu->Reset(); + + SysPrintf("* PCSX2 *: ExecuteBios Complete\n"); + GSprintf(5, "PCSX2 v" PCSX2_VERSION "\nExecuteBios Complete\n"); +} + +void cpuRestartCPU() +{ +#ifdef PCSX2_NORECBUILD + Cpu = &intCpu; +#else + Cpu = CHECK_EEREC ? &recCpu : &intCpu; +#endif + + // restart vus + if (Cpu->Init() == -1) { + SysClose(); + exit(1); + } + + vu0Init(); + vu1Init(); + Cpu->Reset(); + psxRestartCPU(); +} + +// for interpreter only +void IntcpuBranchTest() +{ +#ifndef PCSX2_NORECBUILD + g_EEFreezeRegs = 0; +#endif + + g_nextBranchCycle = cpuRegs.cycle + EE_WAIT_CYCLE; + + if ((int)(cpuRegs.cycle - nextsCounter) >= nextCounter) + rcntUpdate(); + + if (cpuRegs.interrupt) + _cpuTestInterrupts(); + + if( (int)(g_nextBranchCycle-nextsCounter) >= nextCounter ) + g_nextBranchCycle = nextsCounter+nextCounter; + +//#ifdef CPU_LOG +// cpuTestMissingHwInts(); +//#endif + _cpuTestTIMR(); + + EEsCycle += cpuRegs.cycle - EEoCycle; + EEoCycle = cpuRegs.cycle; + + psxCpu->ExecuteBlock(); + + if (VU0.VI[REG_VPU_STAT].UL & 0x1) { + Cpu->ExecuteVU0Block(); + } + if (VU0.VI[REG_VPU_STAT].UL & 0x100) { + Cpu->ExecuteVU1Block(); + } + + if( (int)cpuRegs.cycle-(int)g_nextBranchCycle > 0 ) + g_nextBranchCycle = cpuRegs.cycle+1; + +#ifndef PCSX2_NORECBUILD + g_EEFreezeRegs = 1; +#endif +} diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h new file mode 100644 index 0000000000..db6efcc2d8 --- /dev/null +++ b/pcsx2/R5900.h @@ -0,0 +1,304 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __R5900_H__ +#define __R5900_H__ + +#include + +typedef struct { + int (*Init)(); + void (*Reset)(); + void (*Step)(); + void (*Execute)(); /* executes up to a break */ + void (*ExecuteBlock)(); /* executes up to a jump */ + void (*ExecuteVU0Block)(); /* executes up to a jump */ + void (*ExecuteVU1Block)(); /* executes up to a jump */ + void (*EnableVU0micro)(int enable); + void (*EnableVU1micro)(int enable); + void (*Clear)(u32 Addr, u32 Size); + void (*ClearVU0)(u32 Addr, u32 Size); + void (*ClearVU1)(u32 Addr, u32 Size); + void (*Shutdown)(); +} R5900cpu; + +extern R5900cpu *Cpu; +extern R5900cpu intCpu; +extern R5900cpu recCpu; +extern u32 bExecBIOS; + +typedef union { // Declare union type GPR register + u64 UD[2]; //128 bits + s64 SD[2]; + u32 UL[4]; + s32 SL[4]; + u16 US[8]; + s16 SS[8]; + u8 UC[16]; + s8 SC[16]; +} GPR_reg; + +typedef union { + struct { + GPR_reg r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra; + } n; + GPR_reg r[32]; +} GPRregs; + +typedef union { + struct { + u32 pccr, pcr0, pcr1, pad; + } n; + u32 r[4]; +} PERFregs; + +typedef union { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare; + union { + struct { + int IE:1; + int EXL:1; + int ERL:1; + int KSU:2; + int unused0:3; + int IM:8; + int EIE:1; + int _EDI:1; + int CH:1; + int unused1:3; + int BEV:1; + int DEV:1; + int unused2:2; + int FR:1; + int unused3:1; + int CU:4; + } b; + u32 val; + } Status; + u32 Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Debug, + DEPC, PerfCnt, ErrCtl, CacheErr, + TagLo, TagHi, ErrorEPC, DESAVE; + } n; + u32 r[32]; +} CP0regs; + +typedef struct { + GPRregs GPR; // GPR regs + // NOTE: don't change order since recompiler uses it + GPR_reg HI; + GPR_reg LO; // hi & log 128bit wide + CP0regs CP0; // is COP0 32bit? + u32 sa; // shift amount (32bit), needs to be 16 byte aligned + u32 constzero; // always 0, for MFSA + u32 pc; // Program counter, when changing offset in struct, check iR5900-X.S to make sure offset is correct + u32 code; // The instruction + PERFregs PERF; + u32 eCycle[32]; + u32 sCycle[32]; // for internal counters + u32 cycle; // calculate cpucycles.. + u32 interrupt; + int branch; + int opmode; // operating mode + u32 tempcycles; +} cpuRegisters; + +extern int EEsCycle; +extern u32 EEoCycle, IOPoCycle; +extern PCSX2_ALIGNED16_DECL(cpuRegisters cpuRegs); + +// used for optimization +typedef union { + u64 UD[1]; //64 bits + s64 SD[1]; + u32 UL[2]; + s32 SL[3]; + u16 US[4]; + s16 SS[4]; + u8 UC[8]; + s8 SC[8]; +} GPR_reg64; + +#define GPR_IS_CONST1(reg) ((reg)<32 && (g_cpuHasConstReg&(1<<(reg)))) +#define GPR_IS_CONST2(reg1, reg2) ((g_cpuHasConstReg&(1<<(reg1)))&&(g_cpuHasConstReg&(1<<(reg2)))) +#define GPR_SET_CONST(reg) { \ + if( (reg) < 32 ) { \ + g_cpuHasConstReg |= (1<<(reg)); \ + g_cpuFlushedConstReg &= ~(1<<(reg)); \ + } \ +} + +#define GPR_DEL_CONST(reg) { \ + if( (reg) < 32 ) g_cpuHasConstReg &= ~(1<<(reg)); \ +} + +extern PCSX2_ALIGNED16_DECL(GPR_reg64 g_cpuConstRegs[32]); +extern u32 g_cpuHasConstReg, g_cpuFlushedConstReg; + +typedef union { + float f; + u32 UL; +} FPRreg; + +typedef struct { + FPRreg fpr[32]; // 32bit floating point registers + u32 fprc[32]; // 32bit floating point control registers + FPRreg ACC; // 32 bit accumulator +} fpuRegisters; + +extern PCSX2_ALIGNED16_DECL(fpuRegisters fpuRegs); + + +typedef struct { + u32 PageMask,EntryHi; + u32 EntryLo0,EntryLo1; + u32 Mask, nMask; + u32 G; + u32 ASID; + u32 VPN2; + u32 PFN0; + u32 PFN1; +} tlbs; + +extern PCSX2_ALIGNED16_DECL(tlbs tlb[48]); + +#ifndef _PC_ + +#define _i64(x) (s64)x +#define _u64(x) (u64)x + +#define _i32(x) (s32)x +#define _u32(x) (u32)x + +#define _i16(x) (s16)x +#define _u16(x) (u16)x + +#define _i8(x) (s8)x +#define _u8(x) (u8)x + +/**** R3000A Instruction Macros ****/ +#define _PC_ cpuRegs.pc // The next PC to be executed + +#define _Funct_ ((cpuRegs.code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ((u16)cpuRegs.code) // The immediate part of the instruction register +#define _Target_ (cpuRegs.code & 0x03ffffff) // The target part of the instruction register + +#define _Imm_ ((s16)cpuRegs.code) // sign-extended immediate +#define _ImmU_ (cpuRegs.code&0xffff) // zero-extended immediate + + +//#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +//#define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction + +#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) cpuRegs.GPR.r[x].UD[0] = _PC_ + 4; // Sets the return address in the link register + +#endif + +int cpuInit(); +void cpuReset(); +void cpuShutdown(); +void cpuException(u32 code, u32 bd); +void cpuTlbMissR(u32 addr, u32 bd); +void cpuTlbMissW(u32 addr, u32 bd); +void IntcpuBranchTest(); +void cpuBranchTest(); +void cpuTestHwInts(); +void cpuTestINTCInts(); +void cpuTestDMACInts(); +void cpuTestTIMRInts(); +void _cpuTestInterrupts(); +void cpuExecuteBios(); +void cpuRestartCPU(); + +u32 VirtualToPhysicalR(u32 addr); +u32 VirtualToPhysicalW(u32 addr); + +void intDoBranch(u32 target); +void intSetBranch(); +void intExecuteVU0Block(); +void intExecuteVU1Block(); + +void JumpCheckSym(u32 addr, u32 pc); +void JumpCheckSymRet(u32 addr); + +extern u32 g_EEFreezeRegs; + +//exception code +#define EXC_CODE(x) ((x)<<2) + +#define EXC_CODE_Int EXC_CODE(0) +#define EXC_CODE_Mod EXC_CODE(1) /* TLB Modification exception */ +#define EXC_CODE_TLBL EXC_CODE(2) /* TLB Miss exception (load or instruction fetch) */ +#define EXC_CODE_TLBS EXC_CODE(3) /* TLB Miss exception (store) */ +#define EXC_CODE_AdEL EXC_CODE(4) +#define EXC_CODE_AdES EXC_CODE(5) +#define EXC_CODE_IBE EXC_CODE(6) +#define EXC_CODE_DBE EXC_CODE(7) +#define EXC_CODE_Sys EXC_CODE(8) +#define EXC_CODE_Bp EXC_CODE(9) +#define EXC_CODE_Ri EXC_CODE(10) +#define EXC_CODE_CpU EXC_CODE(11) +#define EXC_CODE_Ov EXC_CODE(12) +#define EXC_CODE_Tr EXC_CODE(13) +#define EXC_CODE_FPE EXC_CODE(15) +#define EXC_CODE_WATCH EXC_CODE(23) +#define EXC_CODE__MASK 0x0000007c +#define EXC_CODE__SHIFT 2 + +#define EXC_TLB_STORE 1 +#define EXC_TLB_LOAD 0 + +//#define EE_PROFILING //EE Profiling enable + +#ifdef EE_PROFILING //EE Profiling code + +extern u64 profile_starttick; +extern u64 profile_totalticks; + +#define START_EE_PROFILE() \ + profile_starttick = GetCPUTick(); + +#define END_EE_PROFILE() \ + profile_totalticks += GetCPUTick()-profile_starttick; + +#define CLEAR_EE_PROFILE() \ + profile_totalticks = 0; + +#else +#define START_EE_PROFILE() + +#define END_EE_PROFILE() + +#define CLEAR_EE_PROFILE() +#endif + +#endif /* __R5900_H__ */ diff --git a/pcsx2/RDebug/Makefile.am b/pcsx2/RDebug/Makefile.am new file mode 100644 index 0000000000..80aa6b0f2e --- /dev/null +++ b/pcsx2/RDebug/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I@srcdir@/../ +noinst_LIBRARIES = libRDebug.a + +libRDebug_a_SOURCES = \ +deci2.c deci2_dcmp.c deci2_drfp.h deci2_iloadp.h deci2_ttyp.c \ +deci2_dbgp.c deci2_dcmp.h deci2.h deci2_netmp.c deci2_ttyp.h \ +deci2_dbgp.h deci2_iloadp.c deci2_netmp.h \ No newline at end of file diff --git a/pcsx2/RDebug/deci2.c b/pcsx2/RDebug/deci2.c new file mode 100644 index 0000000000..2f6c88cfee --- /dev/null +++ b/pcsx2/RDebug/deci2.c @@ -0,0 +1,26 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "deci2.h" + +void exchangeSD(DECI2_HEADER *h){ + u8 tmp =h->source; + h->source =h->destination; + h->destination =tmp; +} diff --git a/pcsx2/RDebug/deci2.h b/pcsx2/RDebug/deci2.h new file mode 100644 index 0000000000..d2033b660f --- /dev/null +++ b/pcsx2/RDebug/deci2.h @@ -0,0 +1,70 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2_H__ +#define __DECI2_H__ + +#include "Common.h" +#include "deci2_dcmp.h" +#include "deci2_iloadp.h" +#include "deci2_dbgp.h" +#include "deci2_netmp.h" +#include "deci2_ttyp.h" + +#define PROTO_DCMP 0x0001 +#define PROTO_ITTYP 0x0110 +#define PROTO_IDBGP 0x0130 +#define PROTO_ILOADP 0x0150 +#define PROTO_ETTYP 0x0220 +#define PROTO_EDBGP 0x0230 +#define PROTO_NETMP 0x0400 + + +#pragma pack(1) +typedef struct tag_DECI2_HEADER{ + u16 length, //+00 + _pad, //+02 + protocol; //+04 + char source, //+06 + destination;//+07 +} DECI2_HEADER; //=08 + +typedef struct tag_DECI2_DBGP_BRK{ + u32 address, //+00 + count; //+04 +} DECI2_DBGP_BRK; //=08 +#pragma pack() + +#define STOP 0 +#define RUN 1 + +extern DECI2_DBGP_BRK ebrk[32], ibrk[32]; +extern int ebrk_count, ibrk_count; +extern int runStatus, runCode, runCount; + +#ifdef _WIN32 +extern HANDLE runEvent; //i don't like this; +#endif + +extern int connected; + //when add linux code this might change + +int writeData(char *result); +void exchangeSD(DECI2_HEADER *h); + +#endif//__DECI2_H__ diff --git a/pcsx2/RDebug/deci2.txt b/pcsx2/RDebug/deci2.txt new file mode 100644 index 0000000000..8cf7221c99 --- /dev/null +++ b/pcsx2/RDebug/deci2.txt @@ -0,0 +1,27 @@ +pcsx2 log->debugger tty mapping +ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÑÍÍÍÄÄÄÂÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +Bios ³EE³ 0 ³IOP³ Bios ³ +CPU & MMI & COP0 & FPU ³EE³ 1 ³IOP³ IOP cpu ³ +VU0 & VUMicro ³EE³ 2 ³IOP³ HW ³ +VIF ³EE³ 3 ³IOP³ GTE ³ +GIF ³EE³ 4 ³IOP³ GPU ³ +DMA ³EE³ 5 ³IOP³ DMA ³ +HW & Unknown Memory ³EE³ 6 ³IOP³ Unknown Memory ³ +ELF & Scratch pad ³EE³ 7 ³IOP³ PAD ³ +IPU ³EE³ 8 ³IOP³ CDR ³ +SIF & RPC services ³EE³ 9 ³IOP³ ³ + ³ ³ ³ ³ ³ +SysMessage ³EE³Kernel³IOP³ SysMessage ³ +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÁÄÄÄÄÄÄÁÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +PRODG: 230,130, 120,121,122,110-119,11F,210-219,21F,410 +CW: 230,130,150,120,121, 210-219,21F,110-119,11F + +0400 PROTO_NETMP +0001 PROTO_DCMP + PROTO_MTWKS +012? PROTO_DRFP (%s) +0230 PROTO_ESDBG +0130 PROTO_ISDBG +011? PROTO_I%dTTY +021? PROTO_E%dTTY + diff --git a/pcsx2/RDebug/deci2_dbgp.c b/pcsx2/RDebug/deci2_dbgp.c new file mode 100644 index 0000000000..597d526672 --- /dev/null +++ b/pcsx2/RDebug/deci2_dbgp.c @@ -0,0 +1,414 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "PsxCommon.h" +#include "VUmicro.h" +#include "deci2.h" + +typedef struct tag_DECI2_DBGP_HEADER{ + DECI2_HEADER h; //+00 + u16 id; //+08 + u8 type, //+0A + code, //+0B + result, //+0C + count; //+0D + u16 _pad; //+0E +} DECI2_DBGP_HEADER; //=10 + +typedef struct tag_DECI2_DBGP_CONF{ + u32 major_ver, //+00 + minor_ver, //+04 + target_id, //+08 + _pad, //+0C + mem_align, //+10 + _pad2, //+14 + reg_size, //+18 + nreg, //+1C + nbrkpt, //+20 + ncont, //+24 + nstep, //+28 + nnext, //+2C + mem_limit_align, //+30 + mem_limit_size, //+34 + run_stop_state, //+38 + hdbg_area_addr, //+3C + hdbg_area_size; //+40 +} DECI2_DBGP_CONF; //=44 + +DECI2_DBGP_CONF +cpu={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +vu0={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +vu1={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 32, 1, 0x00, 0x00, 0x07, 0x200, 1, 0x0001E670, 0x100}; +//iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 0, 1, 0x00, 0x00, 0x07, 0x200, 0, 0x00006940, 0x100}; + +#pragma pack(2) +typedef struct tag_DECI2_DBGP_EREG{ + u8 kind, //+00 + number; //+01 + u16 _pad; //+02 + u64 value[2]; //+04 +} DECI2_DBGP_EREG; //=14 + +typedef struct tag_DECI2_DBGP_IREG{ + u8 kind, //+00 + number; //+01 + u16 _pad; //+02 + u32 value; //+04 +} DECI2_DBGP_IREG; //=08 + +typedef struct tag_DECI2_DBGP_MEM{ + u8 space, //+00 + align; //+01 + u16 _pad; //+02 + u32 address; //+04 + u32 length; //+08 +} DECI2_DBGP_MEM; //=0C + +typedef struct tag_DECI2_DBGP_RUN{ + u32 entry, //+00 + gp, //+04 + _pad, //+08 + _pad1, //+0C + argc; //+10 + u32 argv[0]; //+14 +} DECI2_DBGP_RUN; //=14 +#pragma pack() + +void D2_DBGP(char *inbuffer, char *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy){ + DECI2_DBGP_HEADER *in=(DECI2_DBGP_HEADER*)inbuffer, + *out=(DECI2_DBGP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_DBGP_HEADER); + DECI2_DBGP_EREG *eregs=(DECI2_DBGP_EREG*)((u8*)out+sizeof(DECI2_DBGP_HEADER)); + DECI2_DBGP_IREG *iregs=(DECI2_DBGP_IREG*)((u8*)out+sizeof(DECI2_DBGP_HEADER)); + DECI2_DBGP_MEM *mem =(DECI2_DBGP_MEM*) ((u8*)out+sizeof(DECI2_DBGP_HEADER)); + DECI2_DBGP_RUN *run =(DECI2_DBGP_RUN*) ((u8*)in+sizeof(DECI2_DBGP_HEADER)); + static char line[1024]; + int i, s; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + //out->h.length=sizeof(DECI2_DBGP_HEADER); + out->type++; + out->result=0; //ok + exchangeSD((DECI2_HEADER*)out); + switch(in->type){ + case 0x00://ok + sprintf(line, "%s/GETCONF", in->id==0?"CPU":in->id==1?"VU0":"VU1"); + data=(u8*)out+sizeof(DECI2_DBGP_HEADER); + if (in->h.destination=='I'){ + memcpy(data, &iop, sizeof(DECI2_DBGP_CONF)); + }else + switch(in->id){ + case 0:memcpy(data, &cpu, sizeof(DECI2_DBGP_CONF));break; + case 1:memcpy(data, &vu0, sizeof(DECI2_DBGP_CONF));break; + case 2:memcpy(data, &vu1, sizeof(DECI2_DBGP_CONF));break; + } + break; + case 0x02://ok + sprintf(line, "%s/2", in->id==0?"CPU":in->id==1?"VU0":"VU1"); + break; + case 0x04://ok + sprintf(line, "%s/GETREG count=%d kind[0]=%d number[0]=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number); + if (in->h.destination=='I'){ + for (i=0; icount; i++) + switch (iregs[i].kind){ + case 1:switch (iregs[i].number){ + case 0:iregs[i].value=psxRegs.GPR.n.lo;break; + case 1:iregs[i].value=psxRegs.GPR.n.hi;break; + } + break; + case 2:iregs[i].value=psxRegs.GPR.r[iregs[i].number]; break; + case 3: + if (iregs[i].number==14) psxRegs.CP0.n.EPC=psxRegs.pc; + iregs[i].value=psxRegs.CP0.r[iregs[i].number]; + break; + case 6:iregs[i].value=psxRegs.CP2D.r[iregs[i].number]; break; + case 7:iregs[i].value=psxRegs.CP2C.r[iregs[i].number]; break; + default: + iregs[0].value++;//dummy; might be assert(0) + } + }else + for (i=0; icount; i++) + switch (eregs[i].kind){ + case 0:memcpy(eregs[i].value, &cpuRegs.GPR.r[eregs[i].number], 16);break; + case 1: + switch(eregs[i].number){ + case 0:memcpy(eregs[i].value, &cpuRegs.HI.UD[0], 8);break; + case 1:memcpy(eregs[i].value, &cpuRegs.LO.UD[0], 8);break; + case 2:memcpy(eregs[i].value, &cpuRegs.HI.UD[1], 8);break; + case 3:memcpy(eregs[i].value, &cpuRegs.LO.UD[1], 8);break; + case 4:memcpy(eregs[i].value, &cpuRegs.sa, 4); break; + } + case 2: + if (eregs[i].number==14) cpuRegs.CP0.n.EPC=cpuRegs.pc; + memcpy(eregs[i].value, &cpuRegs.CP0.r[eregs[i].number], 4); + break; + case 3:break;//performance counter 32x3 + case 4:break;//hw debug reg 32x8 + case 5:memcpy(eregs[i].value, &fpuRegs.fpr[eregs[i].number], 4);break; + case 6:memcpy(eregs[i].value, &fpuRegs.fprc[eregs[i].number], 4);break; + case 7:memcpy(eregs[i].value, &VU0.VF[eregs[i].number], 16);break; + case 8:memcpy(eregs[i].value, &VU0.VI[eregs[i].number], 4);break; + case 9:memcpy(eregs[i].value, &VU1.VF[eregs[i].number], 16);break; + case 10:memcpy(eregs[i].value, &VU1.VI[eregs[i].number], 4);break; + default: + eregs[0].value[0]++;//dummy; might be assert(0) + } + break; + case 0x06://ok + sprintf(line, "%s/PUTREG count=%d kind[0]=%d number[0]=%d value=%016I64X_%016I64X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number, eregs[0].value[1], eregs[0].value[0]); + if (in->h.destination=='I'){ + for (i=0; icount; i++) + switch (iregs[i].kind){ + case 1:switch (iregs[i].number){ + case 0:psxRegs.GPR.n.lo=iregs[i].value;break; + case 1:psxRegs.GPR.n.hi=iregs[i].value;break; + } + break; + case 2:psxRegs.GPR.r[iregs[i].number]=iregs[i].value; break; + case 3: + psxRegs.CP0.r[iregs[i].number]=iregs[i].value; + if (iregs[i].number==14) psxRegs.pc=psxRegs.CP0.n.EPC; + break; + case 6:psxRegs.CP2D.r[iregs[i].number]=iregs[i].value; break; + case 7:psxRegs.CP2C.r[iregs[i].number]=iregs[i].value; break; + default: + ;//dummy; might be assert(0) + } + }else + for (i=0; icount; i++) + switch (eregs[i].kind){ + case 0:memcpy(&cpuRegs.GPR.r[eregs[i].number], eregs[i].value, 16);break; + case 1: + switch(eregs[i].number){ + case 0:memcpy(&cpuRegs.HI.UD[0], eregs[i].value, 8);break; + case 1:memcpy(&cpuRegs.LO.UD[0], eregs[i].value, 8);break; + case 2:memcpy(&cpuRegs.HI.UD[1], eregs[i].value, 8);break; + case 3:memcpy(&cpuRegs.LO.UD[1], eregs[i].value, 8);break; + case 4:memcpy(&cpuRegs.sa, eregs[i].value, 4); break; + } + break; + case 2: + memcpy(&cpuRegs.CP0.r[eregs[i].number], eregs[i].value, 4); + if (eregs[i].number==14) cpuRegs.pc=cpuRegs.CP0.n.EPC; + break; + case 3:break;//performance counter 32x3 + case 4:break;//hw debug reg 32x8 + case 5:memcpy(&fpuRegs.fpr[eregs[i].number], eregs[i].value, 4);break; + case 6:memcpy(&fpuRegs.fprc[eregs[i].number], eregs[i].value, 4);break; + case 7:memcpy(&VU0.VF[eregs[i].number], eregs[i].value, 16);break; + case 8:memcpy(&VU0.VI[eregs[i].number], eregs[i].value, 4);break; + case 9:memcpy(&VU1.VF[eregs[i].number], eregs[i].value, 16);break; + case 10:memcpy(&VU1.VI[eregs[i].number], eregs[i].value, 4);break; + default: + ;//dummy; might be assert(0) + } + break; + case 0x08://ok + sprintf(line, "%s/RDMEM %08X/%X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); + data=(u8*)out+ //kids: don't try this at home! :D + ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); + if ((mem->address & ((1 << mem->align)-1)) || + (mem->length & ((1 << mem->align)-1))){ + out->result=1; + strcat(line, " ALIGN ERROR"); + break; + } + if (in->h.destination=='I') + if (PSXM(mem->address & 0x1FFFFFFF)) + memcpy(data, PSXM(mem->address & 0x1FFFFFFF), mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + break; + } + else + switch(mem->space){ + case 0: + if ((mem->address & 0xF0000000) == 0x70000000) + memcpy(data, PSM(mem->address), mem->length); + else + if ((((mem->address & 0x1FFFFFFF)>128*1024*1024) || ((mem->address & 0x1FFFFFFF)<32*1024*1024)) && PSM(mem->address & 0x1FFFFFFF)) + memcpy(data, PSM(mem->address & 0x1FFFFFFF), mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + } + break; + case 1: + if (in->id==1) + memcpy(data, &VU0.Mem[mem->address & 0xFFF], mem->length); + else + memcpy(data, &VU1.Mem[mem->address & 0x3FFF], mem->length); + break; + case 2: + if (in->id==1) + memcpy(data, &VU0.Micro[mem->address & 0xFFF], mem->length); + else + memcpy(data, &VU1.Micro[mem->address & 0x3FFF], mem->length); + break; + } + out->h.length=mem->length+data-(u8*)out; + break; + case 0x0a://ok + sprintf(line, "%s/WRMEM %08X/%X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); + data=(u8*)in+ //kids: don't try this at home! :D + ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); + if (mem->length==4 && *(int*)data==0x0000000D) + strcat(line, " BREAKPOINT"); + if ((mem->address & ((1 << mem->align)-1)) || + (mem->length & ((1 << mem->align)-1))){ + out->result=1; + strcat(line, " ALIGN ERROR"); + break; + } + if (in->h.destination=='I') + if (PSXM(mem->address & 0x1FFFFFFF)) + memcpy(PSXM(mem->address & 0x1FFFFFFF), data, mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + break; + } + else + switch(mem->space){ + case 0: + if ((mem->address & 0xF0000000) == 0x70000000) + memcpy(PSM(mem->address), data, mem->length); + else + if (PSM(mem->address & 0x1FFFFFFF)) + memcpy(PSM(mem->address & 0x1FFFFFFF), data, mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + } + break; + case 1: + if (in->id==1) + memcpy(&VU0.Mem[mem->address & 0xFFF], data, mem->length); + else + memcpy(&VU1.Mem[mem->address & 0x3FFF], data, mem->length); + break; + case 2: + if (in->id==1) + memcpy(&VU0.Micro[mem->address & 0xFFF], data, mem->length); + else + memcpy(&VU1.Micro[mem->address & 0x3FFF], data, mem->length); + break; + } + out->h.length=sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM); + break; + case 0x10://ok + sprintf(line, "%s/GETBRKPT count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + data=(u8*)out+sizeof(DECI2_DBGP_HEADER); + if (in->h.destination=='I') memcpy(data, ibrk, out->count=ibrk_count); + else memcpy(data, ebrk, out->count=ebrk_count); + out->h.length=sizeof(DECI2_DBGP_HEADER)+out->count*sizeof(DECI2_DBGP_BRK); + break; + case 0x12://ok [does not break on iop brkpts] + sprintf(line, "%s/PUTBRKPT count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + out->h.length=sizeof(DECI2_DBGP_HEADER); + if (in->count>32){ + out->result=1; + strcat(line, "TOO MANY"); + break; + } + if (in->h.destination=='I') memcpy(ibrk, data, ibrk_count=in->count); + else memcpy(ebrk, data, ebrk_count=in->count); + out->count=0; + break; + case 0x14://ok, [w/o iop] + sprintf(line, "%s/BREAK count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + if (in->h.destination=='I') + ; + else{ + out->result = ( InterlockedExchange(&runStatus, STOP)==STOP ? + 0x20 : 0x21 ); + out->code=0xFF; + Sleep(50); + } + break; + case 0x16://ok, [w/o iop] + sprintf(line, "%s/CONTINUE code=%s count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", + in->code==0?"CONT":in->code==1?"STEP":"NEXT", in->count); + if (in->h.destination=='I') + ; + else{ + InterlockedExchange(&runStatus, STOP); + Sleep(100);//first get the run thread to Wait state + runCount=in->count; + runCode=in->code; +#ifdef _WIN32 + SetEvent(runEvent);//kick it +#endif + } + break; + case 0x18://ok [without argc/argv stuff] + sprintf(line, "%s/RUN code=%d count=%d entry=0x%08X gp=0x%08X argc=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->code, in->count, + run->entry, run->gp, run->argc); + cpuRegs.CP0.n.EPC=cpuRegs.pc=run->entry; + cpuRegs.GPR.n.gp.UL[0]=run->gp; +// threads_array[0].argc = run->argc; + for (i=0, s=0; i<(int)run->argc; i++) s+=run->argv[i]; + memcpy(PSM(0), &run->argv[run->argc], s); +// threads_array[0].argstring = 0; + InterlockedExchange(&runStatus, STOP); + Sleep(1000);//first get the run thread to Wait state + runCount=0; + runCode=0xFF; +#ifdef _WIN32 + SetEvent(runEvent);//awake it +#endif + out->h.length=sizeof(DECI2_DBGP_HEADER); + break; + default: + sprintf(line, "type=0x%02X code=%d count=%d [unknown]", in->type, in->code, in->count); + } + sprintf(message, "[DBGP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); + sprintf(eepc, "%08X", cpuRegs.pc); + sprintf(ioppc, "%08X", psxRegs.pc); + sprintf(eecy, "%d", cpuRegs.cycle); + sprintf(iopcy, "%d", psxRegs.cycle); + writeData(outbuffer); +} + +void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count){ + static DECI2_DBGP_HEADER tmp; + tmp.h.length =sizeof(DECI2_DBGP_HEADER); + tmp.h._pad =0; + tmp.h.protocol =( source=='E' ? PROTO_EDBGP : PROTO_IDBGP ); + tmp.h.source =source; + tmp.h.destination='H'; + tmp.id =id; + tmp.type =0x15; + tmp.code =code; + tmp.result =result; + tmp.count =count; + tmp._pad =0; + writeData((char*)&tmp); +} diff --git a/pcsx2/RDebug/deci2_dbgp.h b/pcsx2/RDebug/deci2_dbgp.h new file mode 100644 index 0000000000..7d5db0b755 --- /dev/null +++ b/pcsx2/RDebug/deci2_dbgp.h @@ -0,0 +1,28 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2DBGP_H__ +#define __DECI2DBGP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_DBGP(char *inbuffer, char *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy); +void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count); + +#endif//__DECI2DBGP_H__ diff --git a/pcsx2/RDebug/deci2_dcmp.c b/pcsx2/RDebug/deci2_dcmp.c new file mode 100644 index 0000000000..b623b1a63e --- /dev/null +++ b/pcsx2/RDebug/deci2_dcmp.c @@ -0,0 +1,83 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "deci2.h" + +typedef struct tag_DECI2_DCMP_HEADER{ + DECI2_HEADER h; //+00 + u8 type, //+08 + code; //+09 + u16 _pad; //+0A +} DECI2_DCMP_HEADER; //=0C + +typedef struct tag_DECI2_DCMP_CONNECT{ + u8 result, //+00 + _pad[3];//+01 + u64 EEboot, //+04 + IOPboot;//+0C +} DECI2_DCMP_CONNECT; //=14 + +typedef struct tag_DECI2_DCMP_ECHO{ + u16 identifier, //+00 + sequence; //+02 + u8 data[32]; //+04 +} DECI2_DCMP_ECHO; //=24 + +void D2_DCMP(char *inbuffer, char *outbuffer, char *message){ + DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, + *out=(DECI2_DCMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); + + DECI2_DCMP_CONNECT *connect=(DECI2_DCMP_CONNECT*)data; + DECI2_DCMP_ECHO *echo =(DECI2_DCMP_ECHO*)data; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_DCMP_HEADER); + switch(in->type){ +/* case 0: + sprintf(message, " [DCMP] type=CONNECT code=%s EEboot=0x%I64X IOP=0x%I64X", + in->code==0?"CONNECT":"DISCONNECT", connect->EEboot, connect->IOPboot); + data=(u8*)out+sizeof(DECI2_DCMP_HEADER); + connect=(DECI2_DCMP_CONNECT*)data; + connect->result=0; + break; + case 1: + sprintf(message, " [DCMP] type=ECHO id=%X seq=%X", echo->identifier, echo->sequence); + exchangeSD(&out->h); + break; +// not implemented, not needed? + default: + sprintf(message, " [DCMP] type=%d[unknown]", in->type); +*/ } + out->code++; +} + +void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size){ + static char tmp[100]; + ((DECI2_DCMP_HEADER*)tmp)->h.length =sizeof(DECI2_DCMP_HEADER)+size; + ((DECI2_DCMP_HEADER*)tmp)->h._pad =0; + ((DECI2_DCMP_HEADER*)tmp)->h.protocol =protocol; + ((DECI2_DCMP_HEADER*)tmp)->h.source =source; + ((DECI2_DCMP_HEADER*)tmp)->h.destination=destination; + ((DECI2_DCMP_HEADER*)tmp)->type =type; + ((DECI2_DCMP_HEADER*)tmp)->code =code; + ((DECI2_DCMP_HEADER*)tmp)->_pad =0; + memcpy(&tmp[sizeof(DECI2_DCMP_HEADER)], data, size); + writeData(tmp); +} \ No newline at end of file diff --git a/pcsx2/RDebug/deci2_dcmp.h b/pcsx2/RDebug/deci2_dcmp.h new file mode 100644 index 0000000000..aed478b333 --- /dev/null +++ b/pcsx2/RDebug/deci2_dcmp.h @@ -0,0 +1,28 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2DCMP_H__ +#define __DECI2DCMP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_DCMP(char *inbuffer, char *outbuffer, char *message); +void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size); + +#endif//__DECI2DCMP_H__ diff --git a/pcsx2/RDebug/deci2_drfp.c b/pcsx2/RDebug/deci2_drfp.c new file mode 100644 index 0000000000..7a6e0c3a56 --- /dev/null +++ b/pcsx2/RDebug/deci2_drfp.c @@ -0,0 +1,48 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "deci2.h" + +typedef struct tag_DECI2_DCMP_HEADER{ + DECI2_HEADER h; //+00 + u8 type, //+08 + code; //+09 + u16 _pad; //+0A +} DECI2_DCMP_HEADER; //=0C + +extern char d2_message[100]; + +void D2_DCMP(char *inbuffer, char *outbuffer, char *message){ + DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, + *out=(DECI2_DCMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_DCMP_HEADER); + switch(in->type){ + case 4://[OK] + sprintf(message, " [DCMP] code=MESSAGE %s", data);//null terminated by the memset with 0 call + strcpy(d2_message, data); + break; + default: + sprintf(message, " [DCMP] code=%d[unknown] result=%d", netmp->code, netmp->result); + } + result->code++; + result->result=0; //ok +} diff --git a/pcsx2/RDebug/deci2_drfp.h b/pcsx2/RDebug/deci2_drfp.h new file mode 100644 index 0000000000..78c78eb254 --- /dev/null +++ b/pcsx2/RDebug/deci2_drfp.h @@ -0,0 +1,27 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2DRFP_H__ +#define __DECI2DRFP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_(char *inbuffer, char *outbuffer, char *message); + +#endif//__DECI2DRFP_H__ \ No newline at end of file diff --git a/pcsx2/RDebug/deci2_iloadp.c b/pcsx2/RDebug/deci2_iloadp.c new file mode 100644 index 0000000000..708d6b9285 --- /dev/null +++ b/pcsx2/RDebug/deci2_iloadp.c @@ -0,0 +1,106 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "PsxCommon.h" +#include "PsxBios2.h" +#include "deci2.h" + +typedef struct tag_DECI2_ILOADP_HEADER{ + DECI2_HEADER h; //+00 + u8 code, //+08 cmd + action, //+09 + result, //+0A + stamp; //+0B + u32 moduleId; //+0C +} DECI2_ILOADP_HEADER; //=10 + +typedef struct tag_DECI2_ILOADP_INFO{ + u16 version, //+00 + flags; //+02 + u32 module_address, //+04 + text_size, //+08 + data_size, //+0C + bss_size, //+10 + _pad[3]; //+14 +} DECI2_ILOADP_INFO; + +void writeInfo(DECI2_ILOADP_INFO *info, + u16 version, u16 flags, u32 module_address, + u32 text_size, u32 data_size, u32 bss_size){ + info->version =version; + info->flags =flags; + info->module_address=module_address; + info->text_size =text_size; + info->data_size =data_size; + info->bss_size =bss_size; + info->_pad[0]=info->_pad[1]=info->_pad[2]=0; +} + +void D2_ILOADP(char *inbuffer, char *outbuffer, char *message){ + DECI2_ILOADP_HEADER *in=(DECI2_ILOADP_HEADER*)inbuffer, + *out=(DECI2_ILOADP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_ILOADP_HEADER); + irxImageInfo *iii; + static char line[1024]; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_ILOADP_HEADER); + out->code++; + out->result=0; //ok + exchangeSD((DECI2_HEADER*)out); + switch(in->code){ + case 0: + sprintf(line, "code=START action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + case 2: + sprintf(line, "code=REMOVE action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + case 4: + sprintf(line, "code=LIST action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); + for (iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0, data+=4) + *(u32*)data=iii->index; + + out->h.length=data-(u8*)out; + break; + case 6: + sprintf(line, "code=INFO action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); + for(iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0) + if (iii->index==in->moduleId){ + writeInfo((DECI2_ILOADP_INFO*)data, + iii->version, iii->flags, iii->vaddr, iii->text_size, iii->data_size, iii->bss_size); + data+=sizeof(DECI2_ILOADP_INFO); + strcpy(data, PSXM(iii->name)); + data+=strlen(PSXM(iii->name))+4; + data=(char*)((int)data & 0xFFFFFFFC); + break; + + } + out->h.length=data-(u8*)out; + break; + case 8: + sprintf(line, "code=WATCH action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + default: + sprintf(line, "code=%d[unknown]", in->code); + } + sprintf(message, "[ILOADP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); + writeData(outbuffer); +} diff --git a/pcsx2/RDebug/deci2_iloadp.h b/pcsx2/RDebug/deci2_iloadp.h new file mode 100644 index 0000000000..4c16f42648 --- /dev/null +++ b/pcsx2/RDebug/deci2_iloadp.h @@ -0,0 +1,27 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2ILOADP_H__ +#define __DECI2ILOADP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_ILOADP(char *inbuffer, char *outbuffer, char *message); + +#endif//__DECI2ILOADP_H__ diff --git a/pcsx2/RDebug/deci2_netmp.c b/pcsx2/RDebug/deci2_netmp.c new file mode 100644 index 0000000000..ce540fa9be --- /dev/null +++ b/pcsx2/RDebug/deci2_netmp.c @@ -0,0 +1,134 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "deci2.h" + +typedef struct tag_DECI2_NETMP_HEADER{ + DECI2_HEADER h; //+00 + u8 code, //+08 + result; //+09 +} DECI2_NETMP_HEADER; //=0A + +typedef struct tag_DECI2_NETMP_CONNECT{ + u8 priority, //+00 + _pad; //+01 + u16 protocol; //+02 +} DECI2_NETMP_CONNECT; //=04 + +char d2_message[100]; +int d2_count=1; +DECI2_NETMP_CONNECT d2_connect[50]={0xFF, 0, 0x400}; + +void D2_NETMP(char *inbuffer, char *outbuffer, char *message){ + DECI2_NETMP_HEADER *in=(DECI2_NETMP_HEADER*)inbuffer, + *out=(DECI2_NETMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_NETMP_HEADER); + DECI2_NETMP_CONNECT *connect=(DECI2_NETMP_CONNECT*)data; //connect + int i, n; + static char p[100], line[1024]; + u64 EEboot, IOPboot; //reset + u16 node; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_NETMP_HEADER); + out->code++; + out->result=0; //ok + switch(in->code){ + case 0: + n=(in->h.length-sizeof(DECI2_NETMP_HEADER)) / sizeof(DECI2_NETMP_CONNECT); + sprintf(line, "code=CONNECT"); + for (i=0; ih.length=data-(u8*)out; + writeData(outbuffer); + + node=(u16)'I'; + sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); + + node=(u16)'E'; + sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); + + node=PROTO_ILOADP; + sendDCMP(PROTO_DCMP, 'I', 'H', 2, 1, (char*)&node, sizeof(node)); + + for (i=0; i<10; i++){ + node=PROTO_ETTYP+i; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + + node=PROTO_ITTYP+i; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + } + node=PROTO_ETTYP+0xF; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + + node=PROTO_ITTYP+0xF; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + break; + case 4://[OK] + sprintf(line, "code=MESSAGE %s", data);//null terminated by the memset with 0 call + strcpy(d2_message, data); + writeData(outbuffer); + break; + case 6://[ok] + sprintf(line, "code=STATUS"); + data=(u8*)out+sizeof(DECI2_NETMP_HEADER)+2; + /* + memcpy(data, d2_connect, 1*sizeof(DECI2_NETMP_CONNECT)); + data+=1*sizeof(DECI2_NETMP_CONNECT); + *(u32*)data=1;//quite fast;) + data+=4; + memcpy(data, d2_message, strlen(d2_message)); + data+=strlen(d2_message); + *(u32*)data=0;//null end the string on a word boundary + data+=3;data=(u8*)((int)data & 0xFFFFFFFC);*/ + + out->h.length=data-(u8*)out; + writeData(outbuffer); + break; + case 8: + sprintf(line, "code=KILL protocol=0x%04X", *(u16*)data); + writeData(outbuffer); + break; + case 10: + sprintf(line, "code=VERSION %s", data); + data=(u8*)out+sizeof(DECI2_NETMP_HEADER); + strcpy(data, "0.2.0");data+=strlen("0.2.0");//emu version;) + out->h.length=data-(u8*)out; + writeData(outbuffer); + break; + default: + sprintf(line, "code=%d[unknown] result=%d", in->code, in->result); + writeData(outbuffer); + } + sprintf(message, "[NETMP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); +} diff --git a/pcsx2/RDebug/deci2_netmp.h b/pcsx2/RDebug/deci2_netmp.h new file mode 100644 index 0000000000..31fec77d1f --- /dev/null +++ b/pcsx2/RDebug/deci2_netmp.h @@ -0,0 +1,27 @@ + /* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2NETMP_H__ +#define __DECI2NETMP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_NETMP(char *inbuffer, char *outbuffer, char *message); + +#endif//__DECI2NETMP_H__ diff --git a/pcsx2/RDebug/deci2_ttyp.c b/pcsx2/RDebug/deci2_ttyp.c new file mode 100644 index 0000000000..94be7a5dfe --- /dev/null +++ b/pcsx2/RDebug/deci2_ttyp.c @@ -0,0 +1,41 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "Common.h" +#include "deci2.h" + +typedef struct tag_DECI2_TTYP_HEADER{ + DECI2_HEADER h; //+00 + u32 flushreq; //+08 + u8 data[0]; //+0C +} DECI2_TTYP_HEADER; //=0C + +void sendTTYP(u16 protocol, u8 source, char *data){ + static char tmp[2048]; + ((DECI2_TTYP_HEADER*)tmp)->h.length =sizeof(DECI2_TTYP_HEADER)+strlen(data); + ((DECI2_TTYP_HEADER*)tmp)->h._pad =0; + ((DECI2_TTYP_HEADER*)tmp)->h.protocol =protocol +(source=='E' ? PROTO_ETTYP : PROTO_ITTYP); + ((DECI2_TTYP_HEADER*)tmp)->h.source =source; + ((DECI2_TTYP_HEADER*)tmp)->h.destination='H'; + ((DECI2_TTYP_HEADER*)tmp)->flushreq =0; + if (((DECI2_TTYP_HEADER*)tmp)->h.length>2048) + SysMessage("TTYP: Buffer overflow"); + else + memcpy(&tmp[sizeof(DECI2_TTYP_HEADER)], data, strlen(data)); + //writeData(tmp); +} \ No newline at end of file diff --git a/pcsx2/RDebug/deci2_ttyp.h b/pcsx2/RDebug/deci2_ttyp.h new file mode 100644 index 0000000000..4edf5739b2 --- /dev/null +++ b/pcsx2/RDebug/deci2_ttyp.h @@ -0,0 +1,28 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DECI2TTYP_H__ +#define __DECI2TTYP_H__ + +#include "Common.h" +#include "deci2.h" + +//void D2_(char *inbuffer, char *outbuffer, char *message); +void sendTTYP(u16 protocol, u8 source, char *data); + +#endif//__DECI2TTYP_H__ diff --git a/pcsx2/RDebug/iloadp.txt b/pcsx2/RDebug/iloadp.txt new file mode 100644 index 0000000000..c8b6c68834 --- /dev/null +++ b/pcsx2/RDebug/iloadp.txt @@ -0,0 +1,32 @@ +ILOADP_MODULE_INFO{ + u16 flags ÄÄÄÄ¿ <ÄÄÄ¿ + u16 version <ÄÄÄÙ ÄÄÄÄÙ + u32 addr + u32 sz_text + u32 sz_data + u32 sz_bss + u32 reserved1 + u32 reserved2 + u32 reserved3 + u8* name +}; + +ILOADP_HDR{ + u8 cmd + u8 action + u8 result + u8 stamp + u32 module_id +}; + +ILOADP_START(cmd==00) +------------------------------------------ +ILOADP_HDR_START{ + ILOADP_HDR hdr //+00 + u8* modulename //+10 //asciiz +}; //=10+strlen(modulename)+1 +action 0D(IOP_LOAD_IRX) +modulename host:E:\TEMP2\GCC\share\SIO2D.IRX + +action 02(IOP_RUN) +modulename E:\TEMP2\GCC\share\SIO2D.IRX param diff --git a/pcsx2/SPR.c b/pcsx2/SPR.c new file mode 100644 index 0000000000..4f7d27132d --- /dev/null +++ b/pcsx2/SPR.c @@ -0,0 +1,416 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "Common.h" +#include "SPR.h" +#include "iR5900.h" + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) +#define spr1 ((DMACh*)&PS2MEM_HW[0xD400]) + +void sprInit() { +} + +//__inline static void SPR0transfer(u32 *data, int size) { +///* while (size > 0) { +//#ifdef SPR_LOG +// SPR_LOG("SPR1transfer: %x\n", *data); +//#endif +// data++; size--; +// }*/ +// size <<= 2; +// if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO +// (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO +// hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); +// } else { +// u32 * p = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; +// //WriteCodeSSE2(p,data,size >> 4); +// memcpy_fast((u8*)data, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); +// } +// spr0->sadr+= size; +//} + +static void TestClearVUs(u32 madr, u32 size) +{ + if( madr >= 0x11000000 ) { + if( madr < 0x11004000 ) { +#ifdef _DEBUG + SysPrintf("scratch pad clearing vu0\n"); +#endif + Cpu->ClearVU0(madr&0xfff, size); + } + else if( madr >= 0x11008000 && madr < 0x1100c000 ) { +#ifdef _DEBUG + SysPrintf("scratch pad clearing vu1\n"); +#endif + Cpu->ClearVU1(madr&0x3fff, size); + } + } +} + +int _SPR0chain() { + u32 *pMem; + + if (spr0->qwc == 0) return 0; + pMem = (u32*)dmaGetAddr(spr0->madr); + if (pMem == NULL) return -1; + + //SPR0transfer(pMem, qwc << 2); + + if ((psHu32(DMAC_CTRL) & 0xC) >= 0x8) { // 0x8 VIF1 MFIFO, 0xC GIF MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("SPR MFIFO Write outside MFIFO area\n"); + hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); + spr0->madr += spr0->qwc << 4; + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + } else { + memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); + Cpu->Clear(spr0->madr, spr0->qwc<<2); + // clear VU mem also! + TestClearVUs(spr0->madr, spr0->qwc << 2); + + spr0->madr += spr0->qwc << 4; + } + spr0->sadr += spr0->qwc << 4; + + + return (spr0->qwc) * BIAS; // bus is 1/2 the ee speed +} + +#define SPR0chain() \ + cycles += _SPR0chain(); \ + spr0->qwc = 0; + + +void _SPR0interleave() { + int qwc = spr0->qwc; + int sqwc = psHu32(DMAC_SQWC) & 0xff; + int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; + int cycles = 0; + u32 *pMem; + if(tqwc == 0) tqwc = qwc; + //SysPrintf("dmaSPR0 interleave\n"); +#ifdef SPR_LOG + SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", + spr0->qwc, tqwc, sqwc, spr0->madr, spr0->sadr); +#endif + while (qwc > 0) { + spr0->qwc = min(tqwc, qwc); qwc-= spr0->qwc; + pMem = (u32*)dmaGetAddr(spr0->madr); + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO + (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO + hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); + } else { + Cpu->Clear(spr0->madr, spr0->qwc<<2); + // clear VU mem also! + TestClearVUs(spr0->madr, spr0->qwc<<2); + memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); + } + cycles += tqwc * BIAS; + spr0->sadr+= spr0->qwc * 16; + spr0->madr+= (sqwc+spr0->qwc)*16; //qwc-= sqwc; + } + + spr0->qwc = 0; + INT(8, cycles); +} + +void _dmaSPR0() { + + + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR + SysPrintf("SPR0 stall %d\n", (psHu32(DMAC_CTRL)>>6)&3); + } + + + + // Transfer Dn_QWC from SPR to Dn_MADR + + + + if ((spr0->chcr & 0xc) == 0x0) { // Normal Mode + int cycles = 0; + SPR0chain(); + INT(8, cycles); + + return; + } else if ((spr0->chcr & 0xc) == 0x4) { + int cycles = 0; + u32 *ptag; + int id; + int done = 0; + + if(spr0->qwc > 0){ + SPR0chain(); + INT(8, cycles); + + return; + } + // Destination Chain Mode + + while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; + spr0->sadr+= 16; + + // Transfer dma tag if tte is set +// if (spr0->chcr & 0x40) SPR0transfer(ptag, 4); + + spr0->chcr = ( spr0->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + spr0->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + spr0->madr = ptag[1]; //MADR = ADDR field + +#ifdef SPR_LOG + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], spr0->qwc, id, spr0->madr); +#endif + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR + SysPrintf("SPR stall control\n"); + } + + switch (id) { + case 0: // CNTS - Transfer QWC following the tag (Stall Control) + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20 ) psHu32(DMAC_STADR) = spr0->madr + (spr0->qwc * 16); //Copy MADR to DMAC_STADR stall addr register + break; + + case 1: // CNT - Transfer QWC following the tag. + break; + + case 7: // End - Transfer QWC following the tag + done = 1; //End Transfer + break; + } + SPR0chain(); + if (spr0->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag + //SysPrintf("SPR0 TIE\n"); + done = 1; + spr0->qwc = 0; + break; + } + + +/* if (spr0->chcr & 0x80 && ptag[0] >> 31) { +#ifdef SPR_LOG + SPR_LOG("dmaIrq Set\n"); +#endif + spr0->chcr&= ~0x100; + hwDmacIrq(8); + return; + }*/ + } + INT(8, cycles); + } else { // Interleave Mode + _SPR0interleave(); + } + + + +} + +void SPRFROMinterrupt() +{ + spr0->chcr&= ~0x100; + hwDmacIrq(8); + cpuRegs.interrupt &= ~(1 << 8); +} + +extern void mfifoGIFtransfer(int); +#define gif ((DMACh*)&PS2MEM_HW[0xA000]) +void dmaSPR0() { // fromSPR + int qwc = spr0->qwc; + FreezeMMXRegs(1); +#ifdef SPR_LOG + SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx\n", + spr0->chcr, spr0->madr, spr0->qwc, spr0->sadr); +#endif + + _dmaSPR0(); + FreezeMMXRegs(0); + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC) { // GIF MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("GIF MFIFO Write outside MFIFO area\n"); + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + //SysPrintf("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); + mfifoGIFtransfer(qwc); + } else + if ((psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("VIF MFIFO Write outside MFIFO area\n"); + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + //SysPrintf("mfifoVIF1transfer %x madr %x, tadr %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr); + //vifqwc+= qwc; + mfifoVIF1transfer(qwc); + } + +} + +__inline static void SPR1transfer(u32 *data, int size) { +/* { + int i; + for (i=0; isadr+i*4) & 0x3fff, data[i] ); +#endif + } + }*/ + //Cpu->Clear(spr1->sadr, size); // why? + memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)data, size << 2); + + spr1->sadr+= size << 2; +} + +int _SPR1chain() { + u32 *pMem; + + if (spr1->qwc == 0) return 0; + + pMem = (u32*)dmaGetAddr(spr1->madr); + if (pMem == NULL) return -1; + + SPR1transfer(pMem, spr1->qwc << 2); + spr1->madr+= spr1->qwc << 4; + + return (spr1->qwc) * BIAS; +} + +#define SPR1chain() \ + cycles += _SPR1chain(); \ + spr1->qwc = 0; + + +void _SPR1interleave() { + int qwc = spr1->qwc; + int sqwc = psHu32(DMAC_SQWC) & 0xff; + int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; + int cycles = 0; + u32 *pMem; + if(tqwc == 0) tqwc = qwc; + +#ifdef SPR_LOG + SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", + spr1->qwc, tqwc, sqwc, spr1->madr, spr1->sadr); +#endif + while (qwc > 0) { + spr1->qwc = min(tqwc, qwc); qwc-= spr1->qwc; + pMem = (u32*)dmaGetAddr(spr1->madr); + memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)pMem, spr1->qwc <<4); + spr1->sadr += spr1->qwc * 16; + cycles += spr1->qwc * BIAS; + spr1->madr+= (sqwc + spr1->qwc) * 16; //qwc-= sqwc; + } + + spr1->qwc = 0; + INT(9, cycles); + +} + +void dmaSPR1() { // toSPR + + + FreezeMMXRegs(1); +#ifdef SPR_LOG + SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n" + " tadr = 0x%x, sadr = 0x%x\n", + spr1->chcr, spr1->madr, spr1->qwc, + spr1->tadr, spr1->sadr); +#endif + + + + + if ((spr1->chcr & 0xc) == 0) { // Normal Mode + int cycles = 0; + //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; + // Transfer Dn_QWC from Dn_MADR to SPR1 + SPR1chain(); + INT(9, cycles); + FreezeMMXRegs(0); + return; + } else if ((spr1->chcr & 0xc) == 0x4){ + int cycles = 0; + u32 *ptag; + int id, done=0; + + + if(spr1->qwc > 0){ + //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; + // Transfer Dn_QWC from Dn_MADR to SPR1 + SPR1chain(); + INT(9, cycles); + FreezeMMXRegs(0); + return; + } + // Chain Mode + + while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)dmaGetAddr(spr1->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + SysPrintf("SPR1 Tag BUSERR\n"); + spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + done = 1; + break; + } + spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + spr1->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + spr1->madr = ptag[1]; //MADR = ADDR field + + // Transfer dma tag if tte is set + if (spr1->chcr & 0x40) { +#ifdef SPR_LOG + SPR_LOG("SPR TTE: %x_%x\n", ptag[3], ptag[2]); +#endif + SPR1transfer(ptag, 4); //Transfer Tag + + } + + + +#ifdef SPR_LOG + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], spr1->qwc, id, spr1->madr); +#endif + + done = hwDmacSrcChain(spr1, id); + SPR1chain(); //Transfers the data set by the switch + + if (spr1->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef SPR_LOG + SPR_LOG("dmaIrq Set\n"); +#endif + //SysPrintf("SPR1 TIE\n"); + spr1->qwc = 0; + break; + } + } + INT(9, cycles); + } else { // Interleave Mode + _SPR1interleave(); + } + FreezeMMXRegs(0); + +} + +void SPRTOinterrupt() +{ + spr1->chcr &= ~0x100; + hwDmacIrq(9); + cpuRegs.interrupt &= ~(1 << 9); +} + diff --git a/pcsx2/SPR.h b/pcsx2/SPR.h new file mode 100644 index 0000000000..e263231fb4 --- /dev/null +++ b/pcsx2/SPR.h @@ -0,0 +1,29 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SPR_H__ +#define __SPR_H__ + +#include "Common.h" + +void sprInit(); +void dmaSPR0(); +void dmaSPR1(); +void SPRFROMinterrupt(); +void SPRTOinterrupt(); +#endif /* __SPR_H__ */ diff --git a/pcsx2/Sif.c b/pcsx2/Sif.c new file mode 100644 index 0000000000..6aa7b6554d --- /dev/null +++ b/pcsx2/Sif.c @@ -0,0 +1,683 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "Common.h" +#include "PsxCommon.h" +#include "Sif.h" +#include "Sifcmd.h" + +#define sif0dma ((DMACh*)&PS2MEM_HW[0xc000]) +#define sif1dma ((DMACh*)&PS2MEM_HW[0xc400]) +#define sif2dma ((DMACh*)&PS2MEM_HW[0xc800]) + +#define FIFO_SIF0_W 128 +#define FIFO_SIF1_W 128 + +int eesifbusy[2] = { 0, 0 }; +extern int iopsifbusy[2]; +typedef struct { + u32 fifoData[FIFO_SIF0_W]; + int fifoReadPos; + int fifoWritePos; + int fifoSize; + int chain; + int end; + int tagMode; + int counter; + struct sifData sifData; +} _sif0; + +typedef struct { + u32 fifoData[FIFO_SIF1_W]; + int fifoReadPos; + int fifoWritePos; + int fifoSize; + int chain; + int end; + int tagMode; + int counter; +} _sif1; + +_sif0 sif0; +_sif1 sif1; + +int sifInit() { + memset(&sif0, 0, sizeof(sif0)); + memset(&sif1, 0, sizeof(sif1)); + + return 0; +} +int wP0; +int wP1; +void SIF0write(u32 *from, int words) +{ + /*if(FIFO_SIF0_W < (words+sif0.fifoWritePos)) {*/ + wP0 = min((FIFO_SIF0_W-sif0.fifoWritePos),words); + wP1 = words - wP0; + + memcpy(&sif0.fifoData[sif0.fifoWritePos], from, wP0 << 2); + memcpy(&sif0.fifoData[0], &from[wP0], wP1 << 2); + + sif0.fifoWritePos = (sif0.fifoWritePos + words) & (FIFO_SIF0_W-1); + /*} + else + { + memcpy_fast(&sif0.fifoData[sif0.fifoWritePos], from, words << 2); + sif0.fifoWritePos += words; + }*/ + + sif0.fifoSize += words; +#ifdef SIF_LOG + SIF_LOG(" SIF0 + %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoWritePos); +// { +// int i; +// for(i = 0; i < words; i += 4) { +// SIF_LOG(" EE SIF write data: %x %x %x %x\n", from[i], from[i+1], from[i+2], from[i+3]); +// } +// } +#endif + +/* if (sif0.fifoSize == FIFO_SIF0_W) { + Cpu->ExecuteBlock(); + }*/ +} + +void SIF0read(u32 *to, int words) +{ + /*if(FIFO_SIF0_W < (words+sif0.fifoReadPos)) + {*/ + wP0 = min((FIFO_SIF0_W-sif0.fifoReadPos),words); + wP1 = words - wP0; + + memcpy(to, &sif0.fifoData[sif0.fifoReadPos], wP0 << 2); + memcpy(&to[wP0], &sif0.fifoData[0], wP1 << 2); + + sif0.fifoReadPos = (sif0.fifoReadPos + words) & (FIFO_SIF0_W-1); + /*} + else + { + memcpy_fast(to, &sif0.fifoData[sif0.fifoReadPos], words << 2); + sif0.fifoReadPos += words; + }*/ + + sif0.fifoSize -= words; +#ifdef SIF_LOG + SIF_LOG(" SIF0 - %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoReadPos); +#endif +} + +void SIF1write(u32 *from, int words) +{ + /*if(FIFO_SIF1_W < (words+sif1.fifoWritePos)) + {*/ + wP0 = min((FIFO_SIF1_W-sif1.fifoWritePos),words); + wP1 = words - wP0; + + memcpy(&sif1.fifoData[sif1.fifoWritePos], from, wP0 << 2); + memcpy(&sif1.fifoData[0], &from[wP0], wP1 << 2); + + sif1.fifoWritePos = (sif1.fifoWritePos + words) & (FIFO_SIF1_W-1); + /*} + else + { + memcpy_fast(&sif1.fifoData[sif1.fifoWritePos], from, words << 2); + sif1.fifoWritePos += words; + }*/ + + sif1.fifoSize += words; +#ifdef SIF_LOG + SIF_LOG(" SIF1 + %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoWritePos); +#endif + +/* if (sif1.fifoSize == FIFO_SIF1_W) { + psxCpu->ExecuteBlock(); + }*/ +} + +void SIF1read(u32 *to, int words) +{ + /*if(FIFO_SIF1_W < (words+sif1.fifoReadPos)) + {*/ + wP0 = min((FIFO_SIF1_W-sif1.fifoReadPos),words); + wP1 = words - wP0; + + memcpy(to, &sif1.fifoData[sif1.fifoReadPos], wP0 << 2); + memcpy(&to[wP0], &sif1.fifoData[0], wP1 << 2); + + sif1.fifoReadPos = (sif1.fifoReadPos + words) & (FIFO_SIF1_W-1); + /*} + else + { + memcpy_fast(to, &sif1.fifoData[sif1.fifoReadPos], words << 2); + sif1.fifoReadPos += words; + }*/ + + sif1.fifoSize -= words; +#ifdef SIF_LOG + SIF_LOG(" SIF1 - %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoReadPos); +#endif +} + +void SIF0Dma() +{ + u32 *ptag; + int notDone; + int cycles = 0, psxCycles = 0; + +#ifdef SIF_LOG + SIF_LOG("SIF0 DMA start...\n"); +#endif +notDone = 1; + do + { + + /*if ((psHu32(DMAC_CTRL) & 0xC0)) { + SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); + }*/ + if(iopsifbusy[0] == 1) // If EE SIF0 is enabled + { + //int size = sif0.counter; //HW_DMA9_BCR >> 16; + + if(sif0.counter == 0) // If there's no more to transfer + { + // Note.. add normal mode here + if (sif0.sifData.data & 0xC0000000) // If NORMAL mode or end of CHAIN, or interrupt then stop DMA + { +#ifdef SIF_LOG + SIF_LOG(" IOP SIF Stopped\n"); +#endif + + // Stop & signal interrupts on IOP + //HW_DMA9_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(2); + iopsifbusy[0] = 0; + PSX_INT(9, psxCycles); + //hwIntcIrq(INTC_SBUS); + sif0.sifData.data = 0; + notDone = 0; + } + else // Chain mode + { + // Process DMA tag at HW_DMA9_TADR + sif0.sifData = *(struct sifData *)PSXM(HW_DMA9_TADR); + + sif0.sifData.words = (sif0.sifData.words + 3) & 0xfffffffc; // Round up to nearest 4. + + SIF0write((u32*)PSXM(HW_DMA9_TADR+8), 4); + + //psxCycles += 2; + + HW_DMA9_MADR = sif0.sifData.data & 0xFFFFFF; + HW_DMA9_TADR += 16; ///HW_DMA9_MADR + 16 + sif0.sifData.words << 2; + //HW_DMA9_BCR = (sif0.sifData.words << 16) | 1; + sif0.counter = sif0.sifData.words & 0xFFFFFF; + notDone = 1; + +#ifdef SIF_LOG + SIF_LOG(" SIF0 Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)\n", HW_DMA9_MADR, HW_DMA9_TADR, sif0.counter, sif0.sifData.words, sif0.sifData.data); +#endif + if(sif0.sifData.data & 0x40000000) + { +#ifdef SIF_LOG + SIF_LOG(" END\n"); +#endif + } + else + { +#ifdef SIF_LOG + SIF_LOG(" CNT %08X, %08X\n", sif0.sifData.data, sif0.sifData.words); +#endif + } + } + } + else // There's some data ready to transfer into the fifo.. + { + int wTransfer = min(sif0.counter, FIFO_SIF0_W-sif0.fifoSize); // HW_DMA9_BCR >> 16; + + +#ifdef SIF_LOG + SIF_LOG("+++++++++++ %lX of %lX\n", wTransfer, sif0.counter /*(HW_DMA9_BCR >> 16)*/ ); +#endif + + SIF0write((u32*)PSXM(HW_DMA9_MADR), wTransfer); + HW_DMA9_MADR += wTransfer << 2; + //HW_DMA9_BCR = (HW_DMA9_BCR & 0xFFFF) | (((HW_DMA9_BCR >> 16) - wTransfer)<<16); + psxCycles += (wTransfer / 4) * BIAS; + sif0.counter -= wTransfer; + + //notDone = 1; + } + } + + if(eesifbusy[0] == 1) // If EE SIF enabled and there's something to transfer + { + int size = sif0dma->qwc; + if ((psHu32(DMAC_CTRL) & 0x30) == 0x10) { // STS == fromSIF0 + SysPrintf("SIF0 stall control\n"); + } + if(size > 0) // If we're reading something continue to do so + { + /*if(sif0.fifoSize > 0) + {*/ + int readSize = min(size, (sif0.fifoSize>>2)); + + //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X\n", readSize, sif0dma->madr); +#ifdef SIF_LOG + SIF_LOG("----------- %lX of %lX\n", readSize << 2, size << 2 ); +#endif + + _dmaGetAddr(sif0dma, ptag, sif0dma->madr, 5); + + SIF0read((u32*)ptag, readSize<<2); +// { +// int i; +// for(i = 0; i < readSize; ++i) { +// SIF_LOG("EE SIF0 read madr: %x %x %x %x\n", ((u32*)ptag)[4*i+0], ((u32*)ptag)[4*i+1], ((u32*)ptag)[4*i+2], ((u32*)ptag)[4*i+3]); +// } +// } + + Cpu->Clear(sif0dma->madr, readSize*4); + + cycles += readSize * BIAS; + sif0dma->qwc -= readSize; + sif0dma->madr += readSize << 4; + + //notDone = 1; + //} + } + + if(sif0dma->qwc == 0) + { + if((sif0dma->chcr & 0x80000080) == 0x80000080) // Stop on tag IRQ + { + // Tag interrupt +#ifdef SIF_LOG + SIF_LOG(" EE SIF interrupt\n"); +#endif + //sif0dma->chcr &= ~0x100; + eesifbusy[0] = 0; + INT(5, cycles*BIAS); + //hwDmacIrq(5); + notDone = 0; + } + else if(sif0.end) // Stop on tag END + { + // End tag. +#ifdef SIF_LOG + SIF_LOG(" EE SIF end\n"); +#endif + //sif0dma->chcr &= ~0x100; + //hwDmacIrq(5); + eesifbusy[0] = 0; + INT(5, cycles*BIAS); + notDone = 0; + } + else if(sif0.fifoSize >= 4) // Read a tag + { + static PCSX2_ALIGNED16(u32 tag[4]); + SIF0read((u32*)&tag[0], 4); // Tag + SIF_LOG(" EE SIF read tag: %x %x %x %x\n", tag[0], tag[1], tag[2], tag[3]); + + sif0dma->qwc = (u16)tag[0]; + sif0dma->madr = tag[1]; + sif0dma->chcr = (sif0dma->chcr & 0xffff) | (tag[0] & 0xffff0000); + + /*if ((sif0dma->chcr & 0x80) && (tag[0] >> 31)) { + SysPrintf("SIF0 TIE\n"); + }*/ +#ifdef SIF_LOG + SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)\n", sif0dma->madr, sif0dma->qwc, (tag[0]>>28)&3, (tag[0]>>31)&1, tag[1], tag[0]); +#endif + if ((psHu32(DMAC_CTRL) & 0x30) != 0 && ((tag[0]>>28)&3) == 0) + psHu32(DMAC_STADR) = sif0dma->madr + (sif0dma->qwc * 16); + notDone = 1; + sif0.chain = 1; + if(tag[0] & 0x40000000) + sif0.end = 1; + + } + } + } + }while(notDone); +} + +void SIF1Dma() +{ + int id; + u32 *ptag; + int notDone; + int cycles = 0, psxCycles = 0; + notDone = 1; + do + { + + + if(eesifbusy[1] == 1) // If EE SIF1 is enabled + { + if ((psHu32(DMAC_CTRL) & 0xC0) == 0xC0) { // STS == fromSIF1 + SysPrintf("SIF1 stall control\n"); + } + + if(sif1dma->qwc == 0) // If there's no more to transfer + { + if ((sif1dma->chcr & 0xc) == 0 || sif1.end) // If NORMAL mode or end of CHAIN then stop DMA + { + // Stop & signal interrupts on EE + //sif1dma->chcr &= ~0x100; + //hwDmacIrq(6); +#ifdef SIF_LOG + SIF_LOG("EE SIF1 End %x\n", sif1.end); +#endif + eesifbusy[1] = 0; + notDone = 0; + INT(6, cycles*BIAS); + sif1.chain = 0; + sif1.end = 0; + } + else // Chain mode + { + // Process DMA tag at sif1dma->tadr + notDone = 1; + _dmaGetAddr(sif1dma, ptag, sif1dma->tadr, 6); + sif1dma->chcr = ( sif1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); // Copy the tag + sif1dma->qwc = (u16)ptag[0]; + + if (sif1dma->chcr & 0x40) { + SysPrintf("SIF1 TTE\n"); + SIF1write(ptag+2, 2); + } + + sif1.chain = 1; + id = (ptag[0] >> 28) & 0x7; + + switch(id) + { + case 0: // refe +#ifdef SIF_LOG + SIF_LOG(" REFE %08X\n", ptag[1]); +#endif + sif1.end = 1; + sif1dma->madr = ptag[1]; + sif1dma->tadr += 16; + break; + + case 1: // cnt +#ifdef SIF_LOG + SIF_LOG(" CNT\n"); +#endif + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + case 2: // next +#ifdef SIF_LOG + SIF_LOG(" NEXT %08X\n", ptag[1]); +#endif + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = ptag[1]; + break; + + case 3: // ref + case 4: // refs +#ifdef SIF_LOG + SIF_LOG(" REF %08X\n", ptag[1]); +#endif + sif1dma->madr = ptag[1]; + sif1dma->tadr += 16; + break; + + case 7: // end +#ifdef SIF_LOG + SIF_LOG(" END\n"); +#endif + sif1.end = 1; + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + default: + SysPrintf("Bad addr1 source chain\n"); + } + if ((sif1dma->chcr & 0x80) && (ptag[0] >> 31)) { + SysPrintf("SIF1 TIE\n"); + sif1.end = 1; + } + } + } + else // There's some data ready to transfer into the fifo.. + { + int qwTransfer = sif1dma->qwc; + u32 *data; + + //notDone = 1; + + _dmaGetAddr(sif1dma, data, sif1dma->madr, 6); + + if(qwTransfer > (FIFO_SIF1_W-sif1.fifoSize)/4) // Copy part of sif1dma into FIFO + qwTransfer = (FIFO_SIF1_W-sif1.fifoSize)/4; + + SIF1write(data, qwTransfer << 2); + + sif1dma->madr += qwTransfer << 4; + cycles += qwTransfer * BIAS; + sif1dma->qwc -= qwTransfer; + } + } + + if(iopsifbusy[1] == 1) // If IOP SIF enabled and there's something to transfer + { + int size = sif1.counter; + + if(size > 0) // If we're reading something continue to do so + { + /*if(sif1.fifoSize > 0) + {*/ + int readSize = size; + + if(readSize > sif1.fifoSize) + readSize = sif1.fifoSize; + +#ifdef SIF_LOG + SIF_LOG(" IOP SIF doing transfer %04X to %08X\n", readSize, HW_DMA10_MADR); +#endif + + SIF1read((u32*)PSXM(HW_DMA10_MADR), readSize); + psxCpu->Clear(HW_DMA10_MADR, readSize); + psxCycles += readSize / 4; + sif1.counter = size-readSize; + HW_DMA10_MADR += readSize << 2; + //notDone = 1; + //} + } + + if(sif1.counter <= 0) + { + if(sif1.tagMode & 0x80) // Stop on tag IRQ + { + // Tag interrupt +#ifdef SIF_LOG + SIF_LOG(" IOP SIF interrupt\n"); +#endif + //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(3); + iopsifbusy[1] = 0; + PSX_INT(10, psxCycles); + //hwIntcIrq(INTC_SBUS); + sif1.tagMode = 0; + notDone = 0; + } + else if(sif1.tagMode & 0x40) // Stop on tag END + { + // End tag. +#ifdef SIF_LOG + SIF_LOG(" IOP SIF end\n"); +#endif + //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(3); + iopsifbusy[1] = 0; + PSX_INT(10, psxCycles); + //hwIntcIrq(INTC_SBUS); + sif1.tagMode = 0; + notDone = 0; + } + else if(sif1.fifoSize >= 4) // Read a tag + { + struct sifData d; + + SIF1read((u32*)&d, 4); + +#ifdef SIF_LOG + SIF_LOG(" IOP SIF dest chain tag madr:%08X wc:%04X id:%X irq:%d\n", d.data & 0xffffff, d.words, (d.data>>28)&7, (d.data>>31)&1); +#endif + HW_DMA10_MADR = d.data & 0xffffff; + sif1.counter = d.words; + sif1.tagMode = (d.data >> 24) & 0xFF; + notDone = 1; + } + } + } + }while(notDone); + +} + +void sif0Interrupt() { + /*if (psxHu32(0x1070) & 8) { + PSX_INT(9, 0x800); + return 0; + }*/ + + HW_DMA9_CHCR &= ~0x01000000; + psxDmaInterrupt2(2); + //hwIntcIrq(INTC_SBUS); + psxRegs.interrupt&= ~(1 << 9); + //return 1; +} + +void sif1Interrupt() { + /*if (psxHu32(0x1070) & 8) { + PSX_INT(10, 0x800); + return 0; + }*/ + + HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + psxDmaInterrupt2(3); + //hwIntcIrq(INTC_SBUS); + psxRegs.interrupt&= ~(1 << 10); + //return 1; +} + +void EEsif0Interrupt() { + /*if (psHu32(DMAC_STAT) & (1<<5)) { + INT(5, 0x800); + return 0; + }*/ + sif0dma->chcr &= ~0x100; + hwDmacIrq(5); + cpuRegs.interrupt &= ~(1 << 5); + + //return 1; +} + +void EEsif1Interrupt() { + /*if (psHu32(DMAC_STAT) & (1<<6)) { + INT(6, 0x800); + return 0; + }*/ + hwDmacIrq(6); + sif1dma->chcr &= ~0x100; + cpuRegs.interrupt &= ~(1 << 6); + +// return 1; +} + +void dmaSIF0() { + +#ifdef SIF_LOG + SIF_LOG("EE: dmaSIF0 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", + sif0dma->chcr, sif0dma->madr, sif0dma->qwc, sif0dma->tadr); +#endif + + if (sif0.fifoReadPos != sif0.fifoWritePos) { + SysPrintf("warning, sif0.fifoReadPos != sif0.fifoWritePos\n"); + } +// if(sif0dma->qwc > 0 & (sif0dma->chcr & 0x4) == 0x4) { +// sif0dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. +// SysPrintf("yo\n"); +// } + + psHu32(0x1000F240) |= 0x2000; + eesifbusy[0] = 1; + if(eesifbusy[0] == 1 && iopsifbusy[0] == 1) { + FreezeXMMRegs(1); + hwIntcIrq(INTC_SBUS); + SIF0Dma(); + psHu32(0x1000F240) &= ~0x20; + psHu32(0x1000F240) &= ~0x2000; + FreezeXMMRegs(0); + } +} + +void dmaSIF1() { + +#ifdef SIF_LOG + SIF_LOG("EE: dmaSIF1 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", + sif1dma->chcr, sif1dma->madr, sif1dma->qwc, sif1dma->tadr); +#endif + + if (sif1.fifoReadPos != sif1.fifoWritePos) { + SysPrintf("warning, sif1.fifoReadPos != sif1.fifoWritePos\n"); + } + +// if(sif1dma->qwc > 0 & (sif1dma->chcr & 0x4) == 0x4) { +// sif1dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. +// SysPrintf("yo2\n"); +// } + + psHu32(0x1000F240) |= 0x4000; + eesifbusy[1] = 1; + if(eesifbusy[1] == 1 && iopsifbusy[1] == 1) { + FreezeXMMRegs(1); + SIF1Dma(); + psHu32(0x1000F240) &= ~0x40; + psHu32(0x1000F240) &= ~0x100; + psHu32(0x1000F240) &= ~0x4000; + FreezeXMMRegs(0); + } + +} + +void dmaSIF2() { + +#ifdef SIF_LOG + SIF_LOG("dmaSIF2 chcr = %lx, madr = %lx, qwc = %lx\n", + sif2dma->chcr, sif2dma->madr, sif2dma->qwc); +#endif + + sif2dma->chcr&= ~0x100; + hwDmacIrq(7); + SysPrintf("*PCSX2*: dmaSIF2\n"); +} + + +int sifFreeze(gzFile f, int Mode) { + gzfreeze(&sif0, sizeof(sif0)); + gzfreeze(&sif1, sizeof(sif1)); + return 0; +} diff --git a/pcsx2/Sif.h b/pcsx2/Sif.h new file mode 100644 index 0000000000..782a7869fe --- /dev/null +++ b/pcsx2/Sif.h @@ -0,0 +1,51 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SIF_H__ +#define __SIF_H__ + +#include "Common.h" + +struct sifData{ + int data, + words, + count, + addr; +}; + +int eeSifTransfer; + +DMACh *sif0ch; +DMACh *sif1ch; +DMACh *sif2ch; + +int sifInit(); +void SIF0Dma(); +void SIF1Dma(); +void dmaSIF0(); +void dmaSIF1(); +void dmaSIF2(); +void sif1Interrupt(); +void sif0Interrupt(); +void EEsif1Interrupt(); +void EEsif0Interrupt(); +int EEsif2Interrupt(); +int sifFreeze(gzFile f, int Mode); + + +#endif /* __SIF_H__ */ diff --git a/pcsx2/Sifcmd.h b/pcsx2/Sifcmd.h new file mode 100644 index 0000000000..8734ab2ac7 --- /dev/null +++ b/pcsx2/Sifcmd.h @@ -0,0 +1,193 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SIFCMD_H__ +#define __SIFCMD_H__ + +/* from sifcmd.h */ + +#define SYSTEM_CMD 0x80000000 + +struct t_sif_cmd_header +{ + u32 size; + void *dest; + int command; + u32 unknown; +}; + +struct t_sif_dma_transfer +{ + void *src, + *dest; + int size; + int attr; +}; + +struct t_sif_handler +{ + void (*handler) ( void *a, void *b); + void *buff; +}; + +#define SYSTEM_CMD_CHANGE_SADDR 0x80000000 +#define SYSTEM_CMD_INIT_CMD 0x80000002 +struct t_sif_saddr{ + struct t_sif_cmd_header hdr; //+00 + void *newaddr; //+10 +}; //=14 + +#define SYSTEM_CMD_SET_SREG 0x80000001 +struct t_sif_sreg{ + struct t_sif_cmd_header hdr; //+00 + int index; //+10 + unsigned int value; //+14 +}; //=18 + +#define SYSTEM_CMD_RESET 0x80000003 +struct t_sif_reset{ + struct t_sif_cmd_header hdr; //+00 + int size, //+10 + flag; //+14 + char data[80]; //+18 +}; //=68 + +/* end of sifcmd.h */ + +/* from sifsrpc.h */ + +struct t_sif_rpc_rend +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + + struct t_rpc_client_data *client; /* 7 */ + u32 command; /* 8 */ + struct t_rpc_server_data *server; /* 9 */ + void *buff, /* 10 */ + *buff2; /* 11 */ +}; + +struct t_sif_rpc_other_data +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + + struct t_rpc_receive_data *receive; /* 07 */ + void *src; /* 08 */ + void *dest; /* 09 */ + int size; /* 10 */ +}; + +struct t_sif_rpc_bind +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + struct t_rpc_client_data *client; /* 07 */ + int rpc_number; /* 08 */ +}; + +struct t_sif_rpc_call +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + struct t_rpc_client_data *client; /* 07 */ + int rpc_number; /* 08 */ + int send_size; /* 09 */ + void *receive; /* 10 */ + int rec_size; /* 11 */ + int has_async_ef; /* 12 */ + struct t_rpc_server_data *server; /* 13 */ +}; + +struct t_rpc_server_data +{ + int command; /* 04 00 */ + + void * (*func)(u32, void *, int); /* 05 01 */ + void *buff; /* 06 02 */ + int size; /* 07 03 */ + + void * (*func2)(u32, void *, int); /* 08 04 */ + void *buff2; /* 09 05 */ + int size2; /* 10 06 */ + + struct t_rpc_client_data *client; /* 11 07 */ + void *pkt_addr; /* 12 08 */ + int rpc_number; /* 13 09 */ + + void *receive; /* 14 10 */ + int rec_size; /* 15 11 */ + int has_async_ef; /* 16 12 */ + int rec_id; /* 17 13 */ + + struct t_rpc_server_data *link; /* 18 14 */ + struct r_rpc_server_data *next; /* 19 15 */ + struct t_rpc_data_queue *queued_object; /* 20 16 */ +}; + + +struct t_rpc_header +{ + void *pkt_addr; /* 04 00 */ + u32 rpc_id; /* 05 01 */ + int sema_id; /* 06 02 */ + u32 mode; /* 07 03 */ +}; + + +struct t_rpc_client_data +{ + struct t_rpc_header hdr; + u32 command; /* 04 08 */ + void *buff, /* 05 09 */ + *buff2; /* 06 10 */ + void (*end_function) ( void *); /* 07 11 */ + void *end_param; /* 08 12*/ + struct t_rpc_server_data *server; /* 09 13 */ +}; + +struct t_rpc_receive_data +{ + struct t_rpc_header hdr; + void *src, /* 04 */ + *dest; /* 05 */ + int size; /* 06 */ +}; + +struct t_rpc_data_queue +{ + int thread_id, /* 00 */ + active; /* 01 */ + struct t_rpc_server_data *svdata_ref, /* 02 */ + *start, /* 03 */ + *end; /* 04 */ + struct t_rpc_data_queue *next; /* 05 */ +}; + +/* end of sifrpc.h */ + +#endif//__SIFCMD_H__ diff --git a/pcsx2/Sio.c b/pcsx2/Sio.c new file mode 100644 index 0000000000..110339e4ed --- /dev/null +++ b/pcsx2/Sio.c @@ -0,0 +1,672 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "PsxCommon.h" + +#include "Paths.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#endif + +FILE * MemoryCard1, * MemoryCard2; + +const unsigned char cardh[4] = { 0xFF, 0xFF, 0x5a, 0x5d }; +// Memory Card Specs : Sector size etc. +struct mc_command_0x26_tag mc_command_0x26= {'+', 512, 16, 0x4000, 0x52, 0x5A}; +#define SIO_INT() PSX_INT(16, PSXCLK/250000); /*270;*/ + +void _ReadMcd(char *data, u32 adr, int size) { + ReadMcd(sio.CtrlReg&0x2000?2:1, data, adr, size); +} + +void _SaveMcd(char *data, u32 adr, int size) { + SaveMcd(sio.CtrlReg&0x2000?2:1, data, adr, size); +} + +void _EraseMCDBlock(u32 adr) { + EraseMcd(sio.CtrlReg&0x2000?2:1, adr); +} + +unsigned char xor(unsigned char *buf, unsigned int length){ + register unsigned char i, x; + + for (x=0, i=0; i>13)+1, value); +#endif + break; + case 0x81: // COMMIT + sio.bufcount = 8; + memset(sio.buf, 0xFF, 256); + sio.mcdst = 99; + sio.buf[3] = sio.terminator; + sio.buf[2] = '+'; + sio2.packet.recvVal3 = 0x8c; + if(value == 0x81) { + if(sio.mc_command==0x42) + sio2.packet.recvVal1 = 0x1600; // Writing + else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading + } +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0x21: + case 0x22: + case 0x23: // SECTOR SET + sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0; + memset(sio.buf, 0xFF, 256); + sio2.packet.recvVal3 = 0x8c; + sio.buf[8]=sio.terminator; + sio.buf[7]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + + break; + case 0x24: break; + case 0x25: break; + case 0x26: + sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83; + memset(sio.buf, 0xFF, 256); + memcpy(&sio.buf[2], &mc_command_0x26, sizeof(mc_command_0x26)); + sio.buf[12]=sio.terminator; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0x27: + case 0x28: + case 0xBF: + sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b; + memset(sio.buf, 0xFF, 256); + sio.buf[4]=sio.terminator; + sio.buf[3]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0x42: // WRITE + case 0x43: // READ + case 0x82: + if(value==0x82 && sio.lastsector==sio.sector) sio.mode = 2; + if(value==0x42) sio.mode = 0; + if(value==0x43) sio.lastsector = sio.sector; // Reading + + sio.bufcount =133; sio.mcdst = 99; + memset(sio.buf, 0xFF, 256); + sio.buf[133]=sio.terminator; + sio.buf[132]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0xf0: + case 0xf1: + case 0xf2: + sio.mcdst = 99; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0xf3: + case 0xf7: + sio.bufcount = 4; sio.mcdst = 99; + memset(sio.buf, 0xFF, 256); + sio.buf[4]=sio.terminator; + sio.buf[3]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0x52: + sio.rdwr = 1; memset(sio.buf, 0xFF, 256); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + case 0x57: + sio.rdwr = 2; memset(sio.buf, 0xFF, 256); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + break; + default: + sio.mcdst = 0; + memset(sio.buf, 0xFF, 256); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("Unknown MC(%d) command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + } + sio.mc_command=value; + return; + // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS + case 99: + sio.packetsize++; + sio.parp++; + switch(sio.mc_command) + { + // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here + case 0x21: + // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here + case 0x22: + // SET_READ_PAGE; the next read commands will return data starting with the page set here + case 0x23: + if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0; + if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8; + if (sio.parp==4)sio.sector|=(value & 0xFF)<<16; + if (sio.parp==5)sio.sector|=(value & 0xFF)<<24; + if (sio.parp==6) + { +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) SET PAGE sio.sector 0x%04X\n", + ((sio.CtrlReg&0x2000)>>13)+1, sio.sector); +#endif + } + break; + + // SET_TERMINATOR; reads the new terminator code + case 0x27: + if(sio.parp==2) { + sio.terminator = value; + sio.buf[4] = value; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) SET TERMINATOR command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + + } + break; + + // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one + // depending on the param + case 0x28: + if(sio.parp == 2) { + sio.buf[2] = '+'; + sio.buf[3] = sio.terminator; + + if(value == 0) sio.buf[4] = 0xFF; + else sio.buf[4] = 0x55; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) GET TERMINATOR command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + } + break; + // WRITE DATA + case 0x42: + if (sio.parp==2) { + sio.bufcount=5+value; + memset(sio.buf, 0xFF, 256); + sio.buf[sio.bufcount-1]='+'; + sio.buf[sio.bufcount]=sio.terminator; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) WRITE command 0x%02X\n\n\n\n\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + } else + if ((sio.parp>2) && (sio.parp>13)+1, value); +#endif + } else + if (sio.parp==sio.bufcount-2) { + if (xor(&sio.buf[3], sio.bufcount-5)==value) { + _SaveMcd(&sio.buf[3], (512+16)*sio.sector+sio.k, sio.bufcount-5); + sio.buf[sio.bufcount-1]=value; + sio.k+=sio.bufcount-5; + }else { +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) write XOR value error 0x%02X != ^0x%02X\n", + ((sio.CtrlReg&0x2000)>>13)+1, value, xor(&sio.buf[3], sio.bufcount-5)); +#endif + } + } + break; + // READ DATA + case 0x43: + if (sio.parp==2){ + //int i; + sio.bufcount=value+5; + sio.buf[3]='+'; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) READ command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + _ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value); + if(sio.mode==2) + { + int j; + for(j=0; j < value; j++) + sio.buf[4+j] = ~sio.buf[4+j]; + } + + sio.k+=value; + sio.buf[sio.bufcount-1]=xor(&sio.buf[4], value); + sio.buf[sio.bufcount]=sio.terminator; + } + break; + // INTERNAL ERASE + case 0x82: + if(sio.parp==2) { + sio.buf[2]='+'; + sio.buf[3]=sio.terminator; + /* memset(sio.buf, -1, 256); + _SaveMcd(sio.buf, (512+16)*sio.sector, 256); + _SaveMcd(sio.buf, (512+16)*sio.sector+256, 256); + _SaveMcd(sio.buf, (512+16)*sio.sector+512, 16); + sio.buf[2]='+'; + */ sio.buf[3]=sio.terminator; + //sio.buf[sio.bufcount] = sio.terminator; +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) INTERNAL ERASE command 0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + } + break; + // CARD AUTHENTICATION CHECKS + case 0xF0: + if (sio.parp==2) + { +#ifdef MEMCARDS_LOG + MEMCARDS_LOG("MC(%d) CARD AUTH :0x%02X\n", ((sio.CtrlReg&0x2000)>>13)+1, value); +#endif + switch(value){ + case 1: + case 2: + case 4: + case 15: + case 17: + case 19: + sio.bufcount=13; + memset(sio.buf, 0xFF, 256); + sio.buf[12] = 0; // Xor value of data from index 4 to 11 + sio.buf[3]='+'; + sio.buf[13] = sio.terminator; + break; + case 6: + case 7: + case 11: + sio.bufcount=13; + memset(sio.buf, 0xFF, 256); + sio.buf[12]='+'; + sio.buf[13] = sio.terminator; + break; + default: + sio.bufcount=4; + memset(sio.buf, 0xFF, 256); + sio.buf[3]='+'; + sio.buf[4] = sio.terminator; + } + } + break; + } + if (sio.bufcount<=sio.parp) sio.mcdst = 0; + return; + } + + switch (sio.mtapst) + { + case 0x1: + sio.packetsize++; + sio.parp = 1; + SIO_INT(); + switch(value) { + case 0x12: sio.mtapst = 2; sio.bufcount = 5; break; + case 0x13: sio.mtapst = 2; sio.bufcount = 5; break; + case 0x21: sio.mtapst = 2; sio.bufcount = 6; break; + } + sio.buf[sio.bufcount]='Z'; + sio.buf[sio.bufcount-1]='+'; + return; + case 0x2: + sio.packetsize++; + sio.parp++; + if (sio.bufcount<=sio.parp) sio.mcdst = 0; + SIO_INT(); + return; + } + + + if(sio.count == 1 || way == 0) InitializeSIO(value); +} + +void InitializeSIO(u8 value) +{ + switch (value) { + case 0x01: // start pad + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + + switch (sio.CtrlReg&0x2002) { + case 0x0002: sio.buf[0] = PAD1startPoll(1); break; + case 0x2002: sio.buf[0] = PAD2startPoll(2); break; + } + + sio.bufcount = 2; + sio.parp = 0; + sio.padst = 1; + sio.packetsize = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1100; // Pad is present + SIO_INT(); + return; + + case 0x21: // start mtap + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + sio.parp = 0; + sio.packetsize = 1; + sio.mtapst = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :) + SIO_INT(); + return; + + case 0x61: // start remote control sensor + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + sio.parp = 0; + sio.packetsize = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1100; // Pad is present + SIO_INT(); + return; + + case 0x81: // start memcard + sio.StatReg &= ~TX_EMPTY; + sio.StatReg |= RX_RDY; + memcpy(sio.buf, cardh, 4); + sio.parp = 0; + sio.bufcount = 8; + sio.mcdst = 1; + sio.packetsize = 1; + sio.rdwr = 0; + sio2.packet.recvVal1 = 0x1100; // Memcards are present + sio.count = 0; + SIO_INT(); + PAD_LOG("START MEMORY CARD\n"); + return; + } +} + +void sioWrite8(unsigned char value) +{ + SIO_CommandWrite(value,0); +} + +void SIODMAWrite(u8 value) +{ + SIO_CommandWrite(value,1); +} + +void sioWriteCtrl16(unsigned short value) { + sio.CtrlReg = value & ~RESET_ERR; + if (value & RESET_ERR) sio.StatReg &= ~IRQ; + if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg)) { + sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0; + sio.StatReg = TX_RDY | TX_EMPTY; + psxRegs.interrupt&= ~(1<<16); + } +} + +void sioInterrupt() { +#ifdef PAD_LOG + PAD_LOG("Sio Interrupt\n"); +#endif + sio.StatReg|= IRQ; + psxHu32(0x1070)|=0x80; + psxRegs.interrupt&= ~(1 << 16); +} + +extern u32 dwCurSaveStateVer; +int sioFreeze(gzFile f, int Mode) { + + int savesize = sizeof(sio); + if( Mode == 0 && dwCurSaveStateVer == 0x7a30000e ) + savesize -= 4; + sio.count = 0; + gzfreeze(&sio, savesize); + + return 0; +} + + +/******************************************************************* + ******************************************************************* + *************** MEMORY CARD SPECIFIC FUNTIONS ****************** + ******************************************************************* + *******************************************************************/ +FILE *LoadMcd(int mcd) { + char str[256]; + FILE *f; + + if (mcd == 1) { + strcpy(str, Config.Mcd1); + } else { + strcpy(str, Config.Mcd2); + } + if (*str == 0) sprintf(str, MEMCARDS_DIR "/Mcd00%d.ps2", mcd); + f = fopen(str, "r+b"); + if (f == NULL) { + CreateMcd(str); + f = fopen(str, "r+b"); + } + if (f == NULL) { + SysMessage (_("Failed loading MemCard %s"), str); return NULL; + } + + return f; +} + +void SeekMcd(FILE *f, u32 adr) { + u32 size; + + fseek(f, 0, SEEK_END); size = ftell(f); + if (size == MCD_SIZE + 64) + fseek(f, adr + 64, SEEK_SET); + else if (size == MCD_SIZE + 3904) + fseek(f, adr + 3904, SEEK_SET); + else + fseek(f, adr, SEEK_SET); +} + +void ReadMcd(int mcd, char *data, u32 adr, int size) { + if(mcd == 1) + { + if (MemoryCard1 == NULL) { + memset(data, 0, size); + return; + } + SeekMcd(MemoryCard1, adr); + fread(data, 1, size, MemoryCard1); + } + else + { + if (MemoryCard2 == NULL) { + memset(data, 0, size); + return; + } + SeekMcd(MemoryCard2, adr); + fread(data, 1, size, MemoryCard2); + } +} + +void SaveMcd(int mcd, char *data, u32 adr, int size) { + if(mcd == 1) + { + SeekMcd(MemoryCard1, adr); + fwrite(data, 1, size, MemoryCard1); + } + else + { + SeekMcd(MemoryCard2, adr); + fwrite(data, 1, size, MemoryCard2); + } +} + + +void EraseMcd(int mcd, u32 adr) { + u8 data[528*16]; + memset(data,-1,528*16); + if(mcd == 1) + { + SeekMcd(MemoryCard1, adr); + fwrite(data, 1, 528*16, MemoryCard1); + } + else + { + SeekMcd(MemoryCard2, adr); + fwrite(data, 1, 528*16, MemoryCard2); + } +} + + +void CreateMcd(char *mcd) { + FILE *fp; + int i=0, j=0; + int enc[16] = {0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0,0,0,0}; + + fp = fopen(mcd, "wb"); + if (fp == NULL) return; + for(i=0; i < 16384; i++) + { + for(j=0; j < 512; j++) fputc(0xFF,fp); + for(j=0; j < 16; j++) fputc(enc[j],fp); + } + fclose(fp); +} + + + diff --git a/pcsx2/Sio.h b/pcsx2/Sio.h new file mode 100644 index 0000000000..ad2ee1fb6e --- /dev/null +++ b/pcsx2/Sio.h @@ -0,0 +1,118 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifndef _SIO_H_ +#define _SIO_H_ + +typedef struct { + u16 StatReg; + u16 ModeReg; + u16 CtrlReg; + u16 BaudReg; + + u8 buf[256]; + u32 bufcount; + u32 parp; + u32 mcdst,rdwr; + u8 adrH,adrL; + u32 padst; + u32 mtapst; + u32 packetsize; + + u8 terminator; + u8 mode; + u8 mc_command; + u32 lastsector; + u32 sector; + u32 k; + u32 count; +} _sio; +_sio sio; + +#define MCD_SIZE (1024 * 8 * 16) +#define MC2_SIZE (1024 * 528 * 16) + +// Status Flags +#define TX_RDY 0x0001 +#define RX_RDY 0x0002 +#define TX_EMPTY 0x0004 +#define PARITY_ERR 0x0008 +#define RX_OVERRUN 0x0010 +#define FRAMING_ERR 0x0020 +#define SYNC_DETECT 0x0040 +#define DSR 0x0080 +#define CTS 0x0100 +#define IRQ 0x0200 + +// Control Flags +#define TX_PERM 0x0001 +#define DTR 0x0002 +#define RX_PERM 0x0004 +#define BREAK 0x0008 +#define RESET_ERR 0x0010 +#define RTS 0x0020 +#define SIO_RESET 0x0040 + +int Mcd1Size, Mcd2Size; + +int sioInit(); +void sioShutdown(); +void psxSIOShutdown(); +unsigned char sioRead8(); +void sioWrite8(unsigned char value); +void sioWriteCtrl16(unsigned short value); +void sioInterrupt(); +int sioFreeze(gzFile f, int Mode); +void InitializeSIO(u8 value); + +FILE *LoadMcd(int mcd); +void ReadMcd(int mcd, char *data, u32 adr, int size); +void SaveMcd(int mcd, char *data, u32 adr, int size); +void EraseMcd(int mcd, u32 adr); +void CreateMcd(char *mcd); + +typedef struct { + char Title[48]; + char ID[14]; + char Name[16]; + int IconCount; + short Icon[16*16*3]; + unsigned char Flags; +} McdBlock; + +#ifdef _MSC_VER +#pragma pack(1) +#endif +struct mc_command_0x26_tag{ + u8 field_151; //+02 flags + u16 sectorSize; //+03 divide to it + u16 field_2C; //+05 divide to it + u32 mc_size; //+07 + u8 xor; //+0b don't forget to recalculate it!!! + u8 Z; //+0c +#ifdef _MSC_VER +}; +#pragma pack() +#else +} __attribute__((packed)); +#endif + +void GetMcdBlockInfo(int mcd, int block, McdBlock *info); + +#endif diff --git a/pcsx2/Stats.c b/pcsx2/Stats.c new file mode 100644 index 0000000000..c418bcc422 --- /dev/null +++ b/pcsx2/Stats.c @@ -0,0 +1,73 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "Stats.h" + +#include "Paths.h" + +void statsOpen() { + stats.vsyncCount = 0; + stats.vsyncTime = time(NULL); + stats.eeCycles = 0; + stats.eeSCycle = 0; + stats.iopCycles = 0; + stats.iopSCycle = 0; +} + +void statsClose() { + time_t t; + FILE *f; + + t = time(NULL) - stats.vsyncTime; +#ifdef _WIN32 + f = fopen(LOGS_DIR "\\stats.txt", "w"); +#else + f = fopen(LOGS_DIR "/stats.txt", "w"); +#endif + if (!f) { SysPrintf("Can't open stats.txt\n"); return; } + fprintf(f, "-- PCSX2 v%s statics--\n\n", PCSX2_VERSION); + fprintf(f, "Ran for %d seconds\n", t); + fprintf(f, "Total VSyncs: %d (%s)\n", stats.vsyncCount, Config.PsxType ? "PAL" : "NTSC"); +#ifndef __x86_64__ + fprintf(f, "VSyncs per Seconds: %g\n", (double)stats.vsyncCount / t); +#endif + fprintf(f, "Total EE Instructions Executed: %lld\n", stats.eeCycles); + fprintf(f, "Total IOP Instructions Executed: %lld\n", stats.iopCycles); + if (!CHECK_EEREC) fprintf(f, "Interpreter Mode\n"); + else fprintf(f, "Recompiler Mode: VUrec1 %s, VUrec0 %s\n", + CHECK_VU1REC ? "Enabled" : "Disabled", CHECK_VU0REC ? "Enabled" : "Disabled"); + fclose(f); +} + +void statsVSync() { + static u64 accum = 0, accumvu1 = 0; + static u32 frame = 0; + + stats.eeCycles+= cpuRegs.cycle - stats.eeSCycle; + stats.eeSCycle = cpuRegs.cycle; + stats.iopCycles+= psxRegs.cycle - stats.iopSCycle; + stats.iopSCycle = psxRegs.cycle; + stats.vsyncCount++; + stats.vif1count = 0; + stats.vu1count = 0; +} diff --git a/pcsx2/Stats.h b/pcsx2/Stats.h new file mode 100644 index 0000000000..428859b79a --- /dev/null +++ b/pcsx2/Stats.h @@ -0,0 +1,43 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __STATS_H__ +#define __STATS_H__ + +#include + +typedef struct { + time_t vsyncTime; + u32 vsyncCount; + u32 eeCycles; + u32 eeSCycle; + u32 iopCycles; + u32 iopSCycle; + + u32 ticko; + u32 framecount; + u32 vu1count; + u32 vif1count; +} Stats; +Stats stats; + +void statsOpen(); +void statsClose(); +void statsVSync(); + +#endif /* __STATS_H__ */ diff --git a/pcsx2/System.h b/pcsx2/System.h new file mode 100644 index 0000000000..42a5018489 --- /dev/null +++ b/pcsx2/System.h @@ -0,0 +1,64 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +int SysInit(); // Init mem and plugins +void SysReset(); // Resets mem +void SysPrintf(char *fmt, ...); // Printf used by bios syscalls +void SysMessage(char *fmt, ...); // Message used to print msg to users +void SysUpdate(); // Called on VBlank (to update i.e. pads) +void SysRunGui(); // Returns to the Gui +void SysClose(); // Close mem and plugins +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void *SysMmap(uptr base, u32 size); +void SysMunmap(uptr base, u32 size); + +#ifdef PCSX2_VIRTUAL_MEM + +typedef struct _PSMEMORYBLOCK +{ +#ifdef _WIN32 + int NumberPages; + uptr* aPFNs; + uptr* aVFNs; // virtual pages that own the physical pages +#else + int fd; // file descriptor + char* pname; // given name + int size; // size of allocated region +#endif +} PSMEMORYBLOCK; + +int SysPhysicalAlloc(u32 size, PSMEMORYBLOCK* pblock); +void SysPhysicalFree(PSMEMORYBLOCK* pblock); +int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock); +void SysVirtualFree(void* lpMemReserved, u32 size); + +// returns 1 if successful, 0 otherwise +int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pblock, int pageoffset); + +// call to enable physical page allocation +//BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable); + +#endif + +#endif /* __SYSTEM_H__ */ diff --git a/pcsx2/VU.h b/pcsx2/VU.h new file mode 100644 index 0000000000..5629963e41 --- /dev/null +++ b/pcsx2/VU.h @@ -0,0 +1,183 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VU_H__ +#define __VU_H__ + +#include "Vif.h" + +#define REG_STATUS_FLAG 16 +#define REG_MAC_FLAG 17 +#define REG_CLIP_FLAG 18 +#define REG_ACC_FLAG 19 // dummy flag that indicates that VFACC is written/read (nothing to do with VI[19]) +#define REG_R 20 +#define REG_I 21 +#define REG_Q 22 +#define REG_P 23 //only exists in micromode +#define REG_VF0_FLAG 24 // dummy flag that indicates VF0 is read (nothing to do with VI[24]) +#define REG_TPC 26 +#define REG_CMSAR0 27 +#define REG_FBRST 28 +#define REG_VPU_STAT 29 +#define REG_CMSAR1 31 + +enum VUStatus { + VU_Ready = 0, + VU_Run = 1, + VU_Stop = 2, +}; + +typedef union { + struct { + float x,y,z,w; + } f; + struct { + u32 x,y,z,w; + } i; + + float F[4]; + + u64 UD[2]; //128 bits + s64 SD[2]; + u32 UL[4]; + s32 SL[4]; + u16 US[8]; + s16 SS[8]; + u8 UC[16]; + s8 SC[16]; +} VECTOR; + +typedef union { + float F; + s32 SL; + u32 UL; + s16 SS[2]; + u16 US[2]; + s8 SC[4]; + u8 UC[4]; +} REG_VI; + +#define VUFLAG_BREAKONMFLAG 0x00000001 +#define VUFLAG_MFLAGSET 0x00000002 + +typedef struct { + int enable; + REG_VI reg; + u32 sCycle; + u32 Cycle; + u32 statusflag; +} fdivPipe; + +typedef struct { + int enable; + REG_VI reg; + u32 sCycle; + u32 Cycle; +} efuPipe; + +typedef struct { + int enable; + int reg; + int xyzw; + u32 sCycle; + u32 Cycle; + u32 macflag; + u32 statusflag; + u32 clipflag; +} fmacPipe; + +typedef struct _VURegs { + VECTOR VF[32]; + REG_VI VI[32]; + VECTOR ACC; + REG_VI q; + REG_VI p; + + u32 macflag; + u32 statusflag; + u32 clipflag; + + u32 cycle; + u32 flags; + + void (*vuExec)(struct _VURegs*); + VIFregisters *vifRegs; + + u8 *Mem; + u8 *Micro; + + u32 code; + u32 maxmem; + u32 maxmicro; + + u16 branch; + u16 ebit; + u32 branchpc; + + fmacPipe fmac[8]; + fdivPipe fdiv; + efuPipe efu; + +} VURegs; + +#define VUPIPE_NONE 0 +#define VUPIPE_FMAC 1 +#define VUPIPE_FDIV 2 +#define VUPIPE_EFU 3 +#define VUPIPE_IALU 4 +#define VUPIPE_BRANCH 5 +#define VUPIPE_XGKICK 6 + +#define VUREG_READ 0x1 +#define VUREG_WRITE 0x2 + +typedef struct { + u8 pipe; // if 0xff, COP2 + u8 VFwrite; + u8 VFwxyzw; + u8 VFr0xyzw; + u8 VFr1xyzw; + u8 VFread0; + u8 VFread1; + u32 VIwrite; + u32 VIread; + int cycles; +} _VURegsNum; + +extern VURegs* g_pVU1; +extern PCSX2_ALIGNED16_DECL(VURegs VU0); + +#define VU1 (*g_pVU1) + +extern __forceinline u32* GET_VU_MEM(VURegs* VU, u32 addr) +{ + if( VU == g_pVU1 ) return (u32*)(VU1.Mem+(addr&0x3fff)); + + if( addr >= 0x4200 ) return &VU1.VI[(addr>>2)&0x1f].UL; + + return (u32*)(VU0.Mem+(addr&0x0fff)); +} + + +// various fixes to enable per game (all are off by default) +#define VUFIX_SIGNEDZERO 1 +#define VUFIX_EXTRAFLAGS 2 +#define VUFIX_XGKICKDELAY2 4 +extern int g_VUGameFixes; + +#endif /* __VU_H__ */ diff --git a/pcsx2/VU0.c b/pcsx2/VU0.c new file mode 100644 index 0000000000..75ef0a693c --- /dev/null +++ b/pcsx2/VU0.c @@ -0,0 +1,403 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* TODO + -Fix the flags Proper as they aren't handle now.. + -Add BC Table opcodes + -Add Interlock in QMFC2,QMTC2,CFC2,CTC2 + -Finish instruction set + -Bug Fixes!!! +*/ + +#include +#include +#include +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "InterTables.h" +#include "VUops.h" +#include "VUmicro.h" + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _X (cpuRegs.code>>24) & 0x1 +#define _Y (cpuRegs.code>>23) & 0x1 +#define _Z (cpuRegs.code>>22) & 0x1 +#define _W (cpuRegs.code>>21) & 0x1 + +#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) +#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) + +#include "VUflags.h" + +PCSX2_ALIGNED16(VURegs VU0); + +void COP2() { +#ifdef VU0_LOG + VU0_LOG("%s\n", disR5900Fasm(cpuRegs.code, cpuRegs.pc)); +#endif + Int_COP2PrintTable[_Rs_](); +} + +void COP2_BC2() { Int_COP2BC2PrintTable[_Rt_]();} +void COP2_SPECIAL() { Int_COP2SPECIAL1PrintTable[_Funct_]();} + +void COP2_SPECIAL2() { + Int_COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)](); +} + +void COP2_Unknown() +{ +#ifdef CPU_LOG + CPU_LOG("Unknown COP2 opcode called\n"); +#endif +} + +void LQC2() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)cpuRegs.code; + if (_Ft_) { + memRead128(addr, &VU0.VF[_Ft_].UD[0]); + } else { + u64 val[2]; + memRead128(addr, val); + } +} + +// Asadr.Changed +void SQC2() { + u32 addr = _Imm_ + cpuRegs.GPR.r[_Rs_].UL[0]; + memWrite64(addr, VU0.VF[_Ft_].UD[0]); + memWrite64(addr+8,VU0.VF[_Ft_].UD[1]); +} + + +//**************************************************************************** +void _vu0WaitMicro() { + int startcycle; + + if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) { + return; + } + FreezeXMMRegs(1); + startcycle = VU0.cycle; + + VU0.flags|= VUFLAG_BREAKONMFLAG; + VU0.flags&= ~VUFLAG_MFLAGSET; + + do { + Cpu->ExecuteVU0Block(); + // knockout kings 2002 loops here + if( VU0.cycle-startcycle > 0x1000 ) { + SysPrintf("VU0 wait stall (email zero if gfx are bad)\n"); + break; + } + } while ((VU0.VI[REG_VPU_STAT].UL & 0x1) && (VU0.flags & VUFLAG_MFLAGSET) == 0); + + FreezeXMMRegs(0); + //NEW + cpuRegs.cycle += (VU0.cycle-startcycle)*2; + VU0.flags&= ~VUFLAG_BREAKONMFLAG; +} + + +void QMFC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Rt_ == 0) return; + cpuRegs.GPR.r[_Rt_].UD[0] = VU0.VF[_Fs_].UD[0]; + cpuRegs.GPR.r[_Rt_].UD[1] = VU0.VF[_Fs_].UD[1]; +} + +void QMTC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Fs_ == 0) return; + VU0.VF[_Fs_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; + VU0.VF[_Fs_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void CFC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Rt_ == 0) return; + cpuRegs.GPR.r[_Rt_].UL[0] = VU0.VI[_Fs_].UL; + if(VU0.VI[_Fs_].UL & 0x80000000) + cpuRegs.GPR.r[_Rt_].UL[1] = 0xffffffff; + else + cpuRegs.GPR.r[_Rt_].UL[1] = 0; +} + +void CTC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Fs_ == 0) return; + + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + VU0.VI[REG_FBRST].UL = cpuRegs.GPR.r[_Rt_].UL[0] & 0x0C0C; + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x1) { // VU0 Force Break + SysPrintf("fixme: VU0 Force Break\n"); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x2) { // VU0 Reset + //SysPrintf("fixme: VU0 Reset\n"); + vu0ResetRegs(); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x100) { // VU1 Force Break + SysPrintf("fixme: VU1 Force Break\n"); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x200) { // VU1 Reset +// SysPrintf("fixme: VU1 Reset\n"); + vu1ResetRegs(); + } + break; + case REG_CMSAR1: // REG_CMSAR1 + if (!(VU0.VI[REG_VPU_STAT].UL & 0x100) ) { + VU1.VI[REG_TPC].UL = cpuRegs.GPR.r[_Rt_].US[0]; + //FreezeXMMRegs(1); + vu1ExecMicro(VU1.VI[REG_TPC].UL); // Execute VU1 Micro SubRoutine + //FreezeXMMRegs(0); + } + break; + default: + VU0.VI[_Fs_].UL = cpuRegs.GPR.r[_Rt_].UL[0]; + break; + } +} + +//--------------------------------------------------------------------------------------- + + +#define SYNCMSFLAGS() VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; VU0.VI[REG_MAC_FLAG].UL = VU0.macflag; +#define SYNCFDIV() VU0.VI[REG_Q].UL = VU0.q.UL; VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; + +void VABS() { VU0.code = cpuRegs.code; _vuABS(&VU0); } +void VADD() { VU0.code = cpuRegs.code; _vuADD(&VU0); SYNCMSFLAGS(); } +void VADDi() { VU0.code = cpuRegs.code; _vuADDi(&VU0); SYNCMSFLAGS(); } +void VADDq() { VU0.code = cpuRegs.code; _vuADDq(&VU0); SYNCMSFLAGS(); } +void VADDx() { VU0.code = cpuRegs.code; _vuADDx(&VU0); SYNCMSFLAGS(); } +void VADDy() { VU0.code = cpuRegs.code; _vuADDy(&VU0); SYNCMSFLAGS(); } +void VADDz() { VU0.code = cpuRegs.code; _vuADDz(&VU0); SYNCMSFLAGS(); } +void VADDw() { VU0.code = cpuRegs.code; _vuADDw(&VU0); SYNCMSFLAGS(); } +void VADDA() { VU0.code = cpuRegs.code; _vuADDA(&VU0); SYNCMSFLAGS(); } +void VADDAi() { VU0.code = cpuRegs.code; _vuADDAi(&VU0); SYNCMSFLAGS(); } +void VADDAq() { VU0.code = cpuRegs.code; _vuADDAq(&VU0); SYNCMSFLAGS(); } +void VADDAx() { VU0.code = cpuRegs.code; _vuADDAx(&VU0); SYNCMSFLAGS(); } +void VADDAy() { VU0.code = cpuRegs.code; _vuADDAy(&VU0); SYNCMSFLAGS(); } +void VADDAz() { VU0.code = cpuRegs.code; _vuADDAz(&VU0); SYNCMSFLAGS(); } +void VADDAw() { VU0.code = cpuRegs.code; _vuADDAw(&VU0); SYNCMSFLAGS(); } +void VSUB() { VU0.code = cpuRegs.code; _vuSUB(&VU0); SYNCMSFLAGS(); } +void VSUBi() { VU0.code = cpuRegs.code; _vuSUBi(&VU0); SYNCMSFLAGS(); } +void VSUBq() { VU0.code = cpuRegs.code; _vuSUBq(&VU0); SYNCMSFLAGS(); } +void VSUBx() { VU0.code = cpuRegs.code; _vuSUBx(&VU0); SYNCMSFLAGS(); } +void VSUBy() { VU0.code = cpuRegs.code; _vuSUBy(&VU0); SYNCMSFLAGS(); } +void VSUBz() { VU0.code = cpuRegs.code; _vuSUBz(&VU0); SYNCMSFLAGS(); } +void VSUBw() { VU0.code = cpuRegs.code; _vuSUBw(&VU0); SYNCMSFLAGS(); } +void VSUBA() { VU0.code = cpuRegs.code; _vuSUBA(&VU0); SYNCMSFLAGS(); } +void VSUBAi() { VU0.code = cpuRegs.code; _vuSUBAi(&VU0); SYNCMSFLAGS(); } +void VSUBAq() { VU0.code = cpuRegs.code; _vuSUBAq(&VU0); SYNCMSFLAGS(); } +void VSUBAx() { VU0.code = cpuRegs.code; _vuSUBAx(&VU0); SYNCMSFLAGS(); } +void VSUBAy() { VU0.code = cpuRegs.code; _vuSUBAy(&VU0); SYNCMSFLAGS(); } +void VSUBAz() { VU0.code = cpuRegs.code; _vuSUBAz(&VU0); SYNCMSFLAGS(); } +void VSUBAw() { VU0.code = cpuRegs.code; _vuSUBAw(&VU0); SYNCMSFLAGS(); } +void VMUL() { VU0.code = cpuRegs.code; _vuMUL(&VU0); SYNCMSFLAGS(); } +void VMULi() { VU0.code = cpuRegs.code; _vuMULi(&VU0); SYNCMSFLAGS(); } +void VMULq() { VU0.code = cpuRegs.code; _vuMULq(&VU0); SYNCMSFLAGS(); } +void VMULx() { VU0.code = cpuRegs.code; _vuMULx(&VU0); SYNCMSFLAGS(); } +void VMULy() { VU0.code = cpuRegs.code; _vuMULy(&VU0); SYNCMSFLAGS(); } +void VMULz() { VU0.code = cpuRegs.code; _vuMULz(&VU0); SYNCMSFLAGS(); } +void VMULw() { VU0.code = cpuRegs.code; _vuMULw(&VU0); SYNCMSFLAGS(); } +void VMULA() { VU0.code = cpuRegs.code; _vuMULA(&VU0); SYNCMSFLAGS(); } +void VMULAi() { VU0.code = cpuRegs.code; _vuMULAi(&VU0); SYNCMSFLAGS(); } +void VMULAq() { VU0.code = cpuRegs.code; _vuMULAq(&VU0); SYNCMSFLAGS(); } +void VMULAx() { VU0.code = cpuRegs.code; _vuMULAx(&VU0); SYNCMSFLAGS(); } +void VMULAy() { VU0.code = cpuRegs.code; _vuMULAy(&VU0); SYNCMSFLAGS(); } +void VMULAz() { VU0.code = cpuRegs.code; _vuMULAz(&VU0); SYNCMSFLAGS(); } +void VMULAw() { VU0.code = cpuRegs.code; _vuMULAw(&VU0); SYNCMSFLAGS(); } +void VMADD() { VU0.code = cpuRegs.code; _vuMADD(&VU0); SYNCMSFLAGS(); } +void VMADDi() { VU0.code = cpuRegs.code; _vuMADDi(&VU0); SYNCMSFLAGS(); } +void VMADDq() { VU0.code = cpuRegs.code; _vuMADDq(&VU0); SYNCMSFLAGS(); } +void VMADDx() { VU0.code = cpuRegs.code; _vuMADDx(&VU0); SYNCMSFLAGS(); } +void VMADDy() { VU0.code = cpuRegs.code; _vuMADDy(&VU0); SYNCMSFLAGS(); } +void VMADDz() { VU0.code = cpuRegs.code; _vuMADDz(&VU0); SYNCMSFLAGS(); } +void VMADDw() { VU0.code = cpuRegs.code; _vuMADDw(&VU0); SYNCMSFLAGS(); } +void VMADDA() { VU0.code = cpuRegs.code; _vuMADDA(&VU0); SYNCMSFLAGS(); } +void VMADDAi() { VU0.code = cpuRegs.code; _vuMADDAi(&VU0); SYNCMSFLAGS(); } +void VMADDAq() { VU0.code = cpuRegs.code; _vuMADDAq(&VU0); SYNCMSFLAGS(); } +void VMADDAx() { VU0.code = cpuRegs.code; _vuMADDAx(&VU0); SYNCMSFLAGS(); } +void VMADDAy() { VU0.code = cpuRegs.code; _vuMADDAy(&VU0); SYNCMSFLAGS(); } +void VMADDAz() { VU0.code = cpuRegs.code; _vuMADDAz(&VU0); SYNCMSFLAGS(); } +void VMADDAw() { VU0.code = cpuRegs.code; _vuMADDAw(&VU0); SYNCMSFLAGS(); } +void VMSUB() { VU0.code = cpuRegs.code; _vuMSUB(&VU0); SYNCMSFLAGS(); } +void VMSUBi() { VU0.code = cpuRegs.code; _vuMSUBi(&VU0); SYNCMSFLAGS(); } +void VMSUBq() { VU0.code = cpuRegs.code; _vuMSUBq(&VU0); SYNCMSFLAGS(); } +void VMSUBx() { VU0.code = cpuRegs.code; _vuMSUBx(&VU0); SYNCMSFLAGS(); } +void VMSUBy() { VU0.code = cpuRegs.code; _vuMSUBy(&VU0); SYNCMSFLAGS(); } +void VMSUBz() { VU0.code = cpuRegs.code; _vuMSUBz(&VU0); SYNCMSFLAGS(); } +void VMSUBw() { VU0.code = cpuRegs.code; _vuMSUBw(&VU0); SYNCMSFLAGS(); } +void VMSUBA() { VU0.code = cpuRegs.code; _vuMSUBA(&VU0); SYNCMSFLAGS(); } +void VMSUBAi() { VU0.code = cpuRegs.code; _vuMSUBAi(&VU0); SYNCMSFLAGS(); } +void VMSUBAq() { VU0.code = cpuRegs.code; _vuMSUBAq(&VU0); SYNCMSFLAGS(); } +void VMSUBAx() { VU0.code = cpuRegs.code; _vuMSUBAx(&VU0); SYNCMSFLAGS(); } +void VMSUBAy() { VU0.code = cpuRegs.code; _vuMSUBAy(&VU0); SYNCMSFLAGS(); } +void VMSUBAz() { VU0.code = cpuRegs.code; _vuMSUBAz(&VU0); SYNCMSFLAGS(); } +void VMSUBAw() { VU0.code = cpuRegs.code; _vuMSUBAw(&VU0); SYNCMSFLAGS(); } +void VMAX() { VU0.code = cpuRegs.code; _vuMAX(&VU0); } +void VMAXi() { VU0.code = cpuRegs.code; _vuMAXi(&VU0); } +void VMAXx() { VU0.code = cpuRegs.code; _vuMAXx(&VU0); } +void VMAXy() { VU0.code = cpuRegs.code; _vuMAXy(&VU0); } +void VMAXz() { VU0.code = cpuRegs.code; _vuMAXz(&VU0); } +void VMAXw() { VU0.code = cpuRegs.code; _vuMAXw(&VU0); } +void VMINI() { VU0.code = cpuRegs.code; _vuMINI(&VU0); } +void VMINIi() { VU0.code = cpuRegs.code; _vuMINIi(&VU0); } +void VMINIx() { VU0.code = cpuRegs.code; _vuMINIx(&VU0); } +void VMINIy() { VU0.code = cpuRegs.code; _vuMINIy(&VU0); } +void VMINIz() { VU0.code = cpuRegs.code; _vuMINIz(&VU0); } +void VMINIw() { VU0.code = cpuRegs.code; _vuMINIw(&VU0); } +void VOPMULA() { VU0.code = cpuRegs.code; _vuOPMULA(&VU0); SYNCMSFLAGS(); } +void VOPMSUB() { VU0.code = cpuRegs.code; _vuOPMSUB(&VU0); SYNCMSFLAGS(); } +void VNOP() { VU0.code = cpuRegs.code; _vuNOP(&VU0); } +void VFTOI0() { VU0.code = cpuRegs.code; _vuFTOI0(&VU0); } +void VFTOI4() { VU0.code = cpuRegs.code; _vuFTOI4(&VU0); } +void VFTOI12() { VU0.code = cpuRegs.code; _vuFTOI12(&VU0); } +void VFTOI15() { VU0.code = cpuRegs.code; _vuFTOI15(&VU0); } +void VITOF0() { VU0.code = cpuRegs.code; _vuITOF0(&VU0); } +void VITOF4() { VU0.code = cpuRegs.code; _vuITOF4(&VU0); } +void VITOF12() { VU0.code = cpuRegs.code; _vuITOF12(&VU0); } +void VITOF15() { VU0.code = cpuRegs.code; _vuITOF15(&VU0); } +void VCLIPw() { VU0.code = cpuRegs.code; _vuCLIP(&VU0); VU0.VI[REG_CLIP_FLAG].UL = VU0.clipflag; } + +void VDIV() { VU0.code = cpuRegs.code; _vuDIV(&VU0); SYNCFDIV(); } +void VSQRT() { VU0.code = cpuRegs.code; _vuSQRT(&VU0); SYNCFDIV(); } +void VRSQRT() { VU0.code = cpuRegs.code; _vuRSQRT(&VU0); SYNCFDIV(); } +void VIADD() { VU0.code = cpuRegs.code; _vuIADD(&VU0); } +void VIADDI() { VU0.code = cpuRegs.code; _vuIADDI(&VU0); } +void VIADDIU() { VU0.code = cpuRegs.code; _vuIADDIU(&VU0); } +void VIAND() { VU0.code = cpuRegs.code; _vuIAND(&VU0); } +void VIOR() { VU0.code = cpuRegs.code; _vuIOR(&VU0); } +void VISUB() { VU0.code = cpuRegs.code; _vuISUB(&VU0); } +void VISUBIU() { VU0.code = cpuRegs.code; _vuISUBIU(&VU0); } +void VMOVE() { VU0.code = cpuRegs.code; _vuMOVE(&VU0); } +void VMFIR() { VU0.code = cpuRegs.code; _vuMFIR(&VU0); } +void VMTIR() { VU0.code = cpuRegs.code; _vuMTIR(&VU0); } +void VMR32() { VU0.code = cpuRegs.code; _vuMR32(&VU0); } +void VLQ() { VU0.code = cpuRegs.code; _vuLQ(&VU0); } +void VLQD() { VU0.code = cpuRegs.code; _vuLQD(&VU0); } +void VLQI() { VU0.code = cpuRegs.code; _vuLQI(&VU0); } +void VSQ() { VU0.code = cpuRegs.code; _vuSQ(&VU0); } +void VSQD() { VU0.code = cpuRegs.code; _vuSQD(&VU0); } +void VSQI() { VU0.code = cpuRegs.code; _vuSQI(&VU0); } +void VILW() { VU0.code = cpuRegs.code; _vuILW(&VU0); } +void VISW() { VU0.code = cpuRegs.code; _vuISW(&VU0); } +void VILWR() { VU0.code = cpuRegs.code; _vuILWR(&VU0); } +void VISWR() { VU0.code = cpuRegs.code; _vuISWR(&VU0); } +void VRINIT() { VU0.code = cpuRegs.code; _vuRINIT(&VU0); } +void VRGET() { VU0.code = cpuRegs.code; _vuRGET(&VU0); } +void VRNEXT() { VU0.code = cpuRegs.code; _vuRNEXT(&VU0); } +void VRXOR() { VU0.code = cpuRegs.code; _vuRXOR(&VU0); } +void VWAITQ() { VU0.code = cpuRegs.code; _vuWAITQ(&VU0); } +void VFSAND() { VU0.code = cpuRegs.code; _vuFSAND(&VU0); } +void VFSEQ() { VU0.code = cpuRegs.code; _vuFSEQ(&VU0); } +void VFSOR() { VU0.code = cpuRegs.code; _vuFSOR(&VU0); } +void VFSSET() { VU0.code = cpuRegs.code; _vuFSSET(&VU0); } +void VFMAND() { VU0.code = cpuRegs.code; _vuFMAND(&VU0); } +void VFMEQ() { VU0.code = cpuRegs.code; _vuFMEQ(&VU0); } +void VFMOR() { VU0.code = cpuRegs.code; _vuFMOR(&VU0); } +void VFCAND() { VU0.code = cpuRegs.code; _vuFCAND(&VU0); } +void VFCEQ() { VU0.code = cpuRegs.code; _vuFCEQ(&VU0); } +void VFCOR() { VU0.code = cpuRegs.code; _vuFCOR(&VU0); } +void VFCSET() { VU0.code = cpuRegs.code; _vuFCSET(&VU0); } +void VFCGET() { VU0.code = cpuRegs.code; _vuFCGET(&VU0); } +void VXITOP() { VU0.code = cpuRegs.code; _vuXITOP(&VU0); } + +#define CP2COND (/*(VU0.VI[REG_VPU_STAT].US[0] & 1) | */((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1)) + +#define BC2(cond) \ + if (CP2COND cond) { \ + intDoBranch(_BranchTarget_); \ + } + +void BC2F() { BC2(== 0);} +void BC2T() { BC2(== 1);} + +#define BC2L(cond) \ + if (CP2COND cond) { \ + intDoBranch(_BranchTarget_); \ + } else cpuRegs.pc+= 4; + +void BC2FL() { BC2L(== 0);} +void BC2TL() { BC2L(== 1);} + +void vu0Finish() +{ + if( (VU0.VI[REG_VPU_STAT].UL & 0x1) ) { + int i = 0; + + FreezeXMMRegs(1); + while(i++ < 32) { + Cpu->ExecuteVU0Block(); + if(!(VU0.VI[REG_VPU_STAT].UL & 0x1)) + break; + } + FreezeXMMRegs(0); + if(VU0.VI[REG_VPU_STAT].UL & 0x1) { + VU0.VI[REG_VPU_STAT].UL &= ~1; +#ifdef PCSX2_DEVBUILD + SysPrintf("VU0 stall\n"); +#endif + } + } +} + +void VCALLMS() { + //FreezeXMMRegs(1); + + vu0Finish(); + vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF) * 8); + //FreezeXMMRegs(0); +} + +void VCALLMSR() { + //FreezeXMMRegs(1); + vu0Finish(); + vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0] * 8); + //FreezeXMMRegs(0); +} + +#ifndef _MSC_VER + +u32* GET_VU_MEM(VURegs* VU, u32 addr) +{ + if( VU == g_pVU1 ) return (u32*)(VU1.Mem+(addr&0x3fff)); + + if( addr >= 0x4200 ) return &VU1.VI[(addr>>2)&0x1f].UL; + + return (u32*)(VU0.Mem+(addr&0x0fff)); +} + +#endif diff --git a/pcsx2/VU0.h b/pcsx2/VU0.h new file mode 100644 index 0000000000..b9e3115776 --- /dev/null +++ b/pcsx2/VU0.h @@ -0,0 +1,47 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VU0_H__ +#define __VU0_H__ + +#include "VU.h" +#define Lcode cpuRegs.code + +int vu0Init(); +void vu0Reset(); +void vu0ResetRegs(); +void vu0Freeze(gzFile f, int Mode); +void vu0Shutdown(); + +void recResetVU0( void ); + +void vu0Finish(); + +extern char *recMemVU0; /* VU0 blocks */ +extern char *recVU0; /* VU1 mem */ +extern char *recVU0mac; +extern char *recVU0status; +extern char *recVU0clip; +extern char *recVU0Q; +extern char *recVU0cycles; +extern char* recVU0XMMRegs; +extern char *recPtrVU0; + +extern u32 vu0recpcold; + +#endif /* __VU0_H__ */ diff --git a/pcsx2/VU0micro.c b/pcsx2/VU0micro.c new file mode 100644 index 0000000000..8f65ebaba2 --- /dev/null +++ b/pcsx2/VU0micro.c @@ -0,0 +1,744 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "VUops.h" + +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4113) +#endif + +#ifdef PCSX2_VIRTUAL_MEM +extern PSMEMORYBLOCK s_psVuMem; +extern PSMEMORYMAP *memLUT; +#endif + +#define VF_VAL(x) ((x==0x80000000)?0:(x)) + +void iDumpVU0Registers() +{ + int i; + + for(i = 1; i < 32; ++i) { + __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU0.VF[i].UL[3]), VF_VAL(VU0.VF[i].UL[2]), + VF_VAL(VU0.VF[i].UL[1]), VF_VAL(VU0.VF[i].UL[0])); + if( i == REG_Q || i == REG_P ) __Log("%f\n", VU0.VI[i].F); + else if( i == REG_MAC_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0xff); + else if( i == REG_STATUS_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0x03); + else if( i == REG_CLIP_FLAG ) __Log("0\n"); + else __Log("%x\n", VU0.VI[i].UL); + } + __Log("vfACC: %f %f %f %f\n", VU0.ACC.F[3], VU0.ACC.F[2], VU0.ACC.F[1], VU0.ACC.F[0]); +} + +int vu0Init() +{ +#ifdef PCSX2_VIRTUAL_MEM + // unmap all vu0 pages + SysMapUserPhysicalPages(PS2MEM_VU0MICRO, 16, NULL, 0); + + // mirror 4 times + VU0.Micro = PS2MEM_VU0MICRO; + memLUT[0x11000].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11000].aVFNs = &s_psVuMem.aVFNs[0]; + memLUT[0x11001].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11001].aVFNs = &s_psVuMem.aVFNs[0]; + memLUT[0x11002].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11002].aVFNs = &s_psVuMem.aVFNs[0]; + memLUT[0x11003].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11003].aVFNs = &s_psVuMem.aVFNs[0]; + + // since vuregisters are mapped in vumem0, go to diff addr, but mapping to same physical addr + VirtualFree((void*)0x11000000, 0x10000, MEM_RELEASE); // free just in case + VU0.Mem = VirtualAlloc((void*)0x11000000, 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + + if( VU0.Mem != (void*)0x11000000 ) { + SysPrintf("Failed to alloc vu0mem 0x11000000 %d\n", GetLastError()); + return -1; + } + + memLUT[0x11004].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11004].aVFNs = &s_psVuMem.aVFNs[1]; + memLUT[0x11005].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11005].aVFNs = &s_psVuMem.aVFNs[1]; + memLUT[0x11006].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11006].aVFNs = &s_psVuMem.aVFNs[1]; + memLUT[0x11007].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11007].aVFNs = &s_psVuMem.aVFNs[1]; + + // map only registers + SysMapUserPhysicalPages(VU0.Mem+0x4000, 1, s_psVuMem.aPFNs, 2); +#else + VU0.Mem = (u8*)_aligned_malloc(0x4000+sizeof(VURegs), 16); // for VU1 + VU0.Micro = (u8*)_aligned_malloc(4*1024, 16); + memset(VU0.Mem, 0, 0x4000+sizeof(VURegs)); + memset(VU0.Micro, 0, 4*1024); +#endif + + +// VU0.VF = (VECTOR*)_aligned_malloc(32*sizeof(VECTOR), 16); +// VU0.VI = (REG_VI*)_aligned_malloc(32*sizeof(REG_VI), 16); +// if (VU0.VF == NULL || VU0.VI == NULL) { +// SysMessage(_("Error allocating memory")); return -1; +// } + + /* this is kinda tricky, maxmem is set to 0x4400 here, + tho it's not 100% accurate, since the mem goes from + 0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs), + i guess it shouldn't be a problem, + at least hope so :) (linuz) + */ + VU0.maxmem = 0x4400-4; + VU0.maxmicro = 4*1024-4; + VU0.vuExec = vu0Exec; + VU0.vifRegs = vif0Regs; + +#ifndef PCSX2_NORECBUILD + if( CHECK_VU0REC ) { + SuperVUInit(0); + } +#endif + + vu0Reset(); + + return 0; +} + +void vu0Shutdown() +{ +#ifndef PCSX2_NORECBUILD + if( CHECK_VU0REC ) { + SuperVUDestroy(0); + } +#endif + +#ifdef PCSX2_VIRTUAL_MEM + if( !SysMapUserPhysicalPages(VU0.Mem, 16, NULL, 0) ) + SysPrintf("err releasing vu0 mem %d\n", GetLastError()); + if( VirtualFree(VU0.Mem, 0, MEM_RELEASE) == 0 ) + SysPrintf("err freeing vu0 %d\n", GetLastError()); +#else + _aligned_free(VU0.Mem); + _aligned_free(VU0.Micro); +#endif + + VU0.Mem = NULL; + VU0.Micro = NULL; +// _aligned_free(VU0.VF); VU0.VF = NULL; +// _aligned_free(VU0.VI); VU0.VI = NULL; +} + +void vu0ResetRegs() +{ + VU0.VI[REG_VPU_STAT].UL &= ~0xff; // stop vu0 + VU0.VI[REG_FBRST].UL &= ~0xff; // stop vu0 + vif0Regs->stat &= ~4; +} + +void vu0Reset() +{ + memset(&VU0.ACC, 0, sizeof(VECTOR)); + memset(VU0.VF, 0, sizeof(VECTOR)*32); + memset(VU0.VI, 0, sizeof(REG_VI)*32); + VU0.VF[0].f.x = 0.0f; + VU0.VF[0].f.y = 0.0f; + VU0.VF[0].f.z = 0.0f; + VU0.VF[0].f.w = 1.0f; + VU0.VI[0].UL = 0; + memset(VU0.Mem, 0, 4*1024); + memset(VU0.Micro, 0, 4*1024); + + recResetVU0(); +} + +void recResetVU0( void ) +{ +#ifndef PCSX2_NORECBUILD + if( CHECK_VU0REC ) { + SuperVUReset(0); + } +#endif +} + +void vu0Freeze(gzFile f, int Mode) { + gzfreeze(&VU0.ACC, sizeof(VECTOR)); + gzfreeze(&VU0.code, sizeof(u32)); + gzfreeze(VU0.Mem, 4*1024); + gzfreeze(VU0.Micro, 4*1024); + gzfreeze(VU0.VF, 32*sizeof(VECTOR)); + gzfreeze(VU0.VI, 32*sizeof(REG_VI)); +} + + +void VU0MI_XGKICK() { +} + +void VU0MI_XTOP() { +} + +void vu0ExecMicro(u32 addr) { +#ifdef VUM_LOG + VUM_LOG("vu0ExecMicro %x\n", addr); +#endif + if(VU0.VI[REG_VPU_STAT].UL & 0x1) { + SysPrintf("Previous Microprogram still running on VU0\n"); + vu0Finish(); + } + VU0.VI[REG_VPU_STAT].UL|= 0x1; + VU0.VI[REG_VPU_STAT].UL&= ~0xAE; + if (addr != -1) VU0.VI[REG_TPC].UL = addr; + _vuExecMicroDebug(VU0); + FreezeXMMRegs(1); + Cpu->ExecuteVU0Block(); + FreezeXMMRegs(0); +} + +void _vu0ExecUpper(VURegs* VU, u32 *ptr) { + VU->code = ptr[1]; + IdebugUPPER(VU0); + VU0_UPPER_OPCODE[VU->code & 0x3f](); +} + +void _vu0ExecLower(VURegs* VU, u32 *ptr) { + VU->code = ptr[0]; + IdebugLOWER(VU0); + VU0_LOWER_OPCODE[VU->code >> 25](); +} + +extern void _vuFlushAll(VURegs* VU); +int vu0branch = 0; +void _vu0Exec(VURegs* VU) { + _VURegsNum lregs; + _VURegsNum uregs; + VECTOR _VF; + VECTOR _VFc; + REG_VI _VI; + REG_VI _VIc; + u32 *ptr; + int vfreg; + int vireg; + int discard=0; + + if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){ + #ifdef CPU_LOG + SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x1; + VU->cycle++; + return; + } + + ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; + VU->VI[REG_TPC].UL+=8; + + if (ptr[1] & 0x40000000) { + VU->ebit = 2; + } + if (ptr[1] & 0x20000000) { /* M flag */ + VU->flags|= VUFLAG_MFLAGSET; +// SysPrintf("fixme: M flag set\n"); + } + if (ptr[1] & 0x10000000) { /* D flag */ + if (VU0.VI[REG_FBRST].UL & 0x4) { + VU0.VI[REG_VPU_STAT].UL|= 0x2; + hwIntcIrq(INTC_VU0); + } + } + if (ptr[1] & 0x08000000) { /* T flag */ + if (VU0.VI[REG_FBRST].UL & 0x8) { + VU0.VI[REG_VPU_STAT].UL|= 0x4; + hwIntcIrq(INTC_VU0); + } + } + + VU->code = ptr[1]; + VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); + _vuTestUpperStalls(VU, &uregs); + + /* check upper flags */ + if (ptr[1] & 0x80000000) { /* I flag */ + _vu0ExecUpper(VU, ptr); + + VU->VI[REG_I].UL = ptr[0]; + memset(&lregs, 0, sizeof(lregs)); + } else { + VU->code = ptr[0]; + VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs); + _vuTestLowerStalls(VU, &lregs); + + vu0branch = lregs.pipe == VUPIPE_BRANCH; + + vfreg = 0; vireg = 0; + if (uregs.VFwrite) { + if (lregs.VFwrite == uregs.VFwrite) { +// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VFread0 == uregs.VFwrite || + lregs.VFread1 == uregs.VFwrite) { +// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); + _VF = VU->VF[uregs.VFwrite]; + vfreg = uregs.VFwrite; + } + } + if (uregs.VIread & (1 << REG_CLIP_FLAG)) { + if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { + SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VIread & (1 << REG_CLIP_FLAG)) { + _VI = VU0.VI[REG_CLIP_FLAG]; + vireg = REG_CLIP_FLAG; + } + } + + _vu0ExecUpper(VU, ptr); + + if (discard == 0) { + if (vfreg) { + _VFc = VU->VF[vfreg]; + VU->VF[vfreg] = _VF; + } + if (vireg) { + _VIc = VU->VI[vireg]; + VU->VI[vireg] = _VI; + } + + _vu0ExecLower(VU, ptr); + + if (vfreg) { + VU->VF[vfreg] = _VFc; + } + if (vireg) { + VU->VI[vireg] = _VIc; + } + } + } + _vuAddUpperStalls(VU, &uregs); + + if (!(ptr[1] & 0x80000000)) + _vuAddLowerStalls(VU, &lregs); + + _vuTestPipes(VU); + + if (VU->branch > 0) { + VU->branch--; + if (VU->branch == 0) { + VU->VI[REG_TPC].UL = VU->branchpc; + } + } + + if( VU->ebit > 0 ) { + if( VU->ebit-- == 1 ) { + _vuFlushAll(VU); + VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */ + vif0Regs->stat&= ~0x4; + } + } +} + +void vu0Exec(VURegs* VU) { +// u32 *ptr; + + if (VU->VI[REG_TPC].UL >= VU->maxmicro) { +#ifdef CPU_LOG + SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x1; + } else { + _vu0Exec(VU); + } + VU->cycle++; +#ifdef CPU_LOG + if (VU->VI[0].UL != 0) SysPrintf("VI[0] != 0!!!!\n"); + if (VU->VF[0].f.x != 0.0f) SysPrintf("VF[0].x != 0.0!!!!\n"); + if (VU->VF[0].f.y != 0.0f) SysPrintf("VF[0].y != 0.0!!!!\n"); + if (VU->VF[0].f.z != 0.0f) SysPrintf("VF[0].z != 0.0!!!!\n"); + if (VU->VF[0].f.w != 1.0f) SysPrintf("VF[0].w != 1.0!!!!\n"); +#endif +} + +_vuTables(VU0, VU0); +_vuRegsTables(VU0, VU0regs); + +void VU0unknown() { + assert(0); +#ifdef CPU_LOG + CPU_LOG("Unknown VU micromode opcode called\n"); +#endif +} + +void VU0regsunknown(_VURegsNum *VUregsn) { + assert(0); +#ifdef CPU_LOG + CPU_LOG("Unknown VU micromode opcode called\n"); +#endif +} + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU0MI_ABS() { _vuABS(&VU0); } +void VU0MI_ADD() { _vuADD(&VU0); } +void VU0MI_ADDi() { _vuADDi(&VU0); } +void VU0MI_ADDq() { _vuADDq(&VU0); } +void VU0MI_ADDx() { _vuADDx(&VU0); } +void VU0MI_ADDy() { _vuADDy(&VU0); } +void VU0MI_ADDz() { _vuADDz(&VU0); } +void VU0MI_ADDw() { _vuADDw(&VU0); } +void VU0MI_ADDA() { _vuADDA(&VU0); } +void VU0MI_ADDAi() { _vuADDAi(&VU0); } +void VU0MI_ADDAq() { _vuADDAq(&VU0); } +void VU0MI_ADDAx() { _vuADDAx(&VU0); } +void VU0MI_ADDAy() { _vuADDAy(&VU0); } +void VU0MI_ADDAz() { _vuADDAz(&VU0); } +void VU0MI_ADDAw() { _vuADDAw(&VU0); } +void VU0MI_SUB() { _vuSUB(&VU0); } +void VU0MI_SUBi() { _vuSUBi(&VU0); } +void VU0MI_SUBq() { _vuSUBq(&VU0); } +void VU0MI_SUBx() { _vuSUBx(&VU0); } +void VU0MI_SUBy() { _vuSUBy(&VU0); } +void VU0MI_SUBz() { _vuSUBz(&VU0); } +void VU0MI_SUBw() { _vuSUBw(&VU0); } +void VU0MI_SUBA() { _vuSUBA(&VU0); } +void VU0MI_SUBAi() { _vuSUBAi(&VU0); } +void VU0MI_SUBAq() { _vuSUBAq(&VU0); } +void VU0MI_SUBAx() { _vuSUBAx(&VU0); } +void VU0MI_SUBAy() { _vuSUBAy(&VU0); } +void VU0MI_SUBAz() { _vuSUBAz(&VU0); } +void VU0MI_SUBAw() { _vuSUBAw(&VU0); } +void VU0MI_MUL() { _vuMUL(&VU0); } +void VU0MI_MULi() { _vuMULi(&VU0); } +void VU0MI_MULq() { _vuMULq(&VU0); } +void VU0MI_MULx() { _vuMULx(&VU0); } +void VU0MI_MULy() { _vuMULy(&VU0); } +void VU0MI_MULz() { _vuMULz(&VU0); } +void VU0MI_MULw() { _vuMULw(&VU0); } +void VU0MI_MULA() { _vuMULA(&VU0); } +void VU0MI_MULAi() { _vuMULAi(&VU0); } +void VU0MI_MULAq() { _vuMULAq(&VU0); } +void VU0MI_MULAx() { _vuMULAx(&VU0); } +void VU0MI_MULAy() { _vuMULAy(&VU0); } +void VU0MI_MULAz() { _vuMULAz(&VU0); } +void VU0MI_MULAw() { _vuMULAw(&VU0); } +void VU0MI_MADD() { _vuMADD(&VU0); } +void VU0MI_MADDi() { _vuMADDi(&VU0); } +void VU0MI_MADDq() { _vuMADDq(&VU0); } +void VU0MI_MADDx() { _vuMADDx(&VU0); } +void VU0MI_MADDy() { _vuMADDy(&VU0); } +void VU0MI_MADDz() { _vuMADDz(&VU0); } +void VU0MI_MADDw() { _vuMADDw(&VU0); } +void VU0MI_MADDA() { _vuMADDA(&VU0); } +void VU0MI_MADDAi() { _vuMADDAi(&VU0); } +void VU0MI_MADDAq() { _vuMADDAq(&VU0); } +void VU0MI_MADDAx() { _vuMADDAx(&VU0); } +void VU0MI_MADDAy() { _vuMADDAy(&VU0); } +void VU0MI_MADDAz() { _vuMADDAz(&VU0); } +void VU0MI_MADDAw() { _vuMADDAw(&VU0); } +void VU0MI_MSUB() { _vuMSUB(&VU0); } +void VU0MI_MSUBi() { _vuMSUBi(&VU0); } +void VU0MI_MSUBq() { _vuMSUBq(&VU0); } +void VU0MI_MSUBx() { _vuMSUBx(&VU0); } +void VU0MI_MSUBy() { _vuMSUBy(&VU0); } +void VU0MI_MSUBz() { _vuMSUBz(&VU0); } +void VU0MI_MSUBw() { _vuMSUBw(&VU0); } +void VU0MI_MSUBA() { _vuMSUBA(&VU0); } +void VU0MI_MSUBAi() { _vuMSUBAi(&VU0); } +void VU0MI_MSUBAq() { _vuMSUBAq(&VU0); } +void VU0MI_MSUBAx() { _vuMSUBAx(&VU0); } +void VU0MI_MSUBAy() { _vuMSUBAy(&VU0); } +void VU0MI_MSUBAz() { _vuMSUBAz(&VU0); } +void VU0MI_MSUBAw() { _vuMSUBAw(&VU0); } +void VU0MI_MAX() { _vuMAX(&VU0); } +void VU0MI_MAXi() { _vuMAXi(&VU0); } +void VU0MI_MAXx() { _vuMAXx(&VU0); } +void VU0MI_MAXy() { _vuMAXy(&VU0); } +void VU0MI_MAXz() { _vuMAXz(&VU0); } +void VU0MI_MAXw() { _vuMAXw(&VU0); } +void VU0MI_MINI() { _vuMINI(&VU0); } +void VU0MI_MINIi() { _vuMINIi(&VU0); } +void VU0MI_MINIx() { _vuMINIx(&VU0); } +void VU0MI_MINIy() { _vuMINIy(&VU0); } +void VU0MI_MINIz() { _vuMINIz(&VU0); } +void VU0MI_MINIw() { _vuMINIw(&VU0); } +void VU0MI_OPMULA() { _vuOPMULA(&VU0); } +void VU0MI_OPMSUB() { _vuOPMSUB(&VU0); } +void VU0MI_NOP() { _vuNOP(&VU0); } +void VU0MI_FTOI0() { _vuFTOI0(&VU0); } +void VU0MI_FTOI4() { _vuFTOI4(&VU0); } +void VU0MI_FTOI12() { _vuFTOI12(&VU0); } +void VU0MI_FTOI15() { _vuFTOI15(&VU0); } +void VU0MI_ITOF0() { _vuITOF0(&VU0); } +void VU0MI_ITOF4() { _vuITOF4(&VU0); } +void VU0MI_ITOF12() { _vuITOF12(&VU0); } +void VU0MI_ITOF15() { _vuITOF15(&VU0); } +void VU0MI_CLIP() { _vuCLIP(&VU0); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU0MI_DIV() { _vuDIV(&VU0); } +void VU0MI_SQRT() { _vuSQRT(&VU0); } +void VU0MI_RSQRT() { _vuRSQRT(&VU0); } +void VU0MI_IADD() { _vuIADD(&VU0); } +void VU0MI_IADDI() { _vuIADDI(&VU0); } +void VU0MI_IADDIU() { _vuIADDIU(&VU0); } +void VU0MI_IAND() { _vuIAND(&VU0); } +void VU0MI_IOR() { _vuIOR(&VU0); } +void VU0MI_ISUB() { _vuISUB(&VU0); } +void VU0MI_ISUBIU() { _vuISUBIU(&VU0); } +void VU0MI_MOVE() { _vuMOVE(&VU0); } +void VU0MI_MFIR() { _vuMFIR(&VU0); } +void VU0MI_MTIR() { _vuMTIR(&VU0); } +void VU0MI_MR32() { _vuMR32(&VU0); } +void VU0MI_LQ() { _vuLQ(&VU0); } +void VU0MI_LQD() { _vuLQD(&VU0); } +void VU0MI_LQI() { _vuLQI(&VU0); } +void VU0MI_SQ() { _vuSQ(&VU0); } +void VU0MI_SQD() { _vuSQD(&VU0); } +void VU0MI_SQI() { _vuSQI(&VU0); } +void VU0MI_ILW() { _vuILW(&VU0); } +void VU0MI_ISW() { _vuISW(&VU0); } +void VU0MI_ILWR() { _vuILWR(&VU0); } +void VU0MI_ISWR() { _vuISWR(&VU0); } +void VU0MI_RINIT() { _vuRINIT(&VU0); } +void VU0MI_RGET() { _vuRGET(&VU0); } +void VU0MI_RNEXT() { _vuRNEXT(&VU0); } +void VU0MI_RXOR() { _vuRXOR(&VU0); } +void VU0MI_WAITQ() { _vuWAITQ(&VU0); } +void VU0MI_FSAND() { _vuFSAND(&VU0); } +void VU0MI_FSEQ() { _vuFSEQ(&VU0); } +void VU0MI_FSOR() { _vuFSOR(&VU0); } +void VU0MI_FSSET() { _vuFSSET(&VU0); } +void VU0MI_FMAND() { _vuFMAND(&VU0); } +void VU0MI_FMEQ() { _vuFMEQ(&VU0); } +void VU0MI_FMOR() { _vuFMOR(&VU0); } +void VU0MI_FCAND() { _vuFCAND(&VU0); } +void VU0MI_FCEQ() { _vuFCEQ(&VU0); } +void VU0MI_FCOR() { _vuFCOR(&VU0); } +void VU0MI_FCSET() { _vuFCSET(&VU0); } +void VU0MI_FCGET() { _vuFCGET(&VU0); } +void VU0MI_IBEQ() { _vuIBEQ(&VU0); } +void VU0MI_IBGEZ() { _vuIBGEZ(&VU0); } +void VU0MI_IBGTZ() { _vuIBGTZ(&VU0); } +void VU0MI_IBLTZ() { _vuIBLTZ(&VU0); } +void VU0MI_IBLEZ() { _vuIBLEZ(&VU0); } +void VU0MI_IBNE() { _vuIBNE(&VU0); } +void VU0MI_B() { _vuB(&VU0); } +void VU0MI_BAL() { _vuBAL(&VU0); } +void VU0MI_JR() { _vuJR(&VU0); } +void VU0MI_JALR() { _vuJALR(&VU0); } +void VU0MI_MFP() { _vuMFP(&VU0); } +void VU0MI_WAITP() { _vuWAITP(&VU0); } +void VU0MI_ESADD() { _vuESADD(&VU0); } +void VU0MI_ERSADD() { _vuERSADD(&VU0); } +void VU0MI_ELENG() { _vuELENG(&VU0); } +void VU0MI_ERLENG() { _vuERLENG(&VU0); } +void VU0MI_EATANxy() { _vuEATANxy(&VU0); } +void VU0MI_EATANxz() { _vuEATANxz(&VU0); } +void VU0MI_ESUM() { _vuESUM(&VU0); } +void VU0MI_ERCPR() { _vuERCPR(&VU0); } +void VU0MI_ESQRT() { _vuESQRT(&VU0); } +void VU0MI_ERSQRT() { _vuERSQRT(&VU0); } +void VU0MI_ESIN() { _vuESIN(&VU0); } +void VU0MI_EATAN() { _vuEATAN(&VU0); } +void VU0MI_EEXP() { _vuEEXP(&VU0); } +void VU0MI_XITOP() { _vuXITOP(&VU0); } + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU0regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU0, VUregsn); } +void VU0regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU0, VUregsn); } +void VU0regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU0, VUregsn); } +void VU0regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU0, VUregsn); } +void VU0regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU0, VUregsn); } +void VU0regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU0, VUregsn); } +void VU0regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU0, VUregsn); } +void VU0regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU0, VUregsn); } +void VU0regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU0, VUregsn); } +void VU0regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU0, VUregsn); } +void VU0regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU0, VUregsn); } +void VU0regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU0, VUregsn); } +void VU0regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU0, VUregsn); } +void VU0regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU0, VUregsn); } +void VU0regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU0, VUregsn); } +void VU0regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU0, VUregsn); } +void VU0regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU0, VUregsn); } +void VU0regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU0, VUregsn); } +void VU0regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU0, VUregsn); } +void VU0regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU0, VUregsn); } +void VU0regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU0, VUregsn); } +void VU0regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU0, VUregsn); } +void VU0regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU0, VUregsn); } +void VU0regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU0, VUregsn); } +void VU0regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU0, VUregsn); } +void VU0regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU0, VUregsn); } +void VU0regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU0, VUregsn); } +void VU0regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU0, VUregsn); } +void VU0regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU0, VUregsn); } +void VU0regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU0, VUregsn); } +void VU0regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU0, VUregsn); } +void VU0regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU0, VUregsn); } +void VU0regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU0, VUregsn); } +void VU0regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU0, VUregsn); } +void VU0regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU0, VUregsn); } +void VU0regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU0, VUregsn); } +void VU0regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU0, VUregsn); } +void VU0regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU0, VUregsn); } +void VU0regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU0, VUregsn); } +void VU0regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU0, VUregsn); } +void VU0regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU0, VUregsn); } +void VU0regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU0, VUregsn); } +void VU0regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU0, VUregsn); } +void VU0regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU0, VUregsn); } +void VU0regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU0, VUregsn); } +void VU0regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU0, VUregsn); } +void VU0regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU0, VUregsn); } +void VU0regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU0, VUregsn); } +void VU0regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU0, VUregsn); } +void VU0regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU0, VUregsn); } +void VU0regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU0, VUregsn); } +void VU0regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU0, VUregsn); } +void VU0regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU0, VUregsn); } +void VU0regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU0, VUregsn); } +void VU0regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU0, VUregsn); } +void VU0regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU0, VUregsn); } +void VU0regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU0, VUregsn); } +void VU0regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU0, VUregsn); } +void VU0regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU0, VUregsn); } +void VU0regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU0, VUregsn); } +void VU0regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU0, VUregsn); } +void VU0regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU0, VUregsn); } +void VU0regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU0, VUregsn); } +void VU0regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU0, VUregsn); } +void VU0regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU0, VUregsn); } +void VU0regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU0, VUregsn); } +void VU0regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU0, VUregsn); } +void VU0regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU0, VUregsn); } +void VU0regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU0, VUregsn); } +void VU0regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU0, VUregsn); } +void VU0regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU0, VUregsn); } +void VU0regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU0, VUregsn); } +void VU0regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU0, VUregsn); } +void VU0regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU0, VUregsn); } +void VU0regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU0, VUregsn); } +void VU0regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU0, VUregsn); } +void VU0regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU0, VUregsn); } +void VU0regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU0, VUregsn); } +void VU0regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU0, VUregsn); } +void VU0regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU0, VUregsn); } +void VU0regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU0, VUregsn); } +void VU0regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU0, VUregsn); } +void VU0regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU0, VUregsn); } +void VU0regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU0, VUregsn); } +void VU0regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU0, VUregsn); } +void VU0regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU0, VUregsn); } +void VU0regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU0, VUregsn); } +void VU0regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU0, VUregsn); } +void VU0regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU0, VUregsn); } +void VU0regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU0, VUregsn); } +void VU0regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU0, VUregsn); } +void VU0regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU0, VUregsn); } +void VU0regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU0, VUregsn); } +void VU0regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU0, VUregsn); } +void VU0regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU0, VUregsn); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU0regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU0, VUregsn); } +void VU0regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU0, VUregsn); } +void VU0regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU0, VUregsn); } +void VU0regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU0, VUregsn); } +void VU0regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU0, VUregsn); } +void VU0regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU0, VUregsn); } +void VU0regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU0, VUregsn); } +void VU0regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU0, VUregsn); } +void VU0regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU0, VUregsn); } +void VU0regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU0, VUregsn); } +void VU0regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU0, VUregsn); } +void VU0regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU0, VUregsn); } +void VU0regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU0, VUregsn); } +void VU0regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU0, VUregsn); } +void VU0regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU0, VUregsn); } +void VU0regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU0, VUregsn); } +void VU0regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU0, VUregsn); } +void VU0regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU0, VUregsn); } +void VU0regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU0, VUregsn); } +void VU0regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU0, VUregsn); } +void VU0regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU0, VUregsn); } +void VU0regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU0, VUregsn); } +void VU0regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU0, VUregsn); } +void VU0regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU0, VUregsn); } +void VU0regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU0, VUregsn); } +void VU0regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU0, VUregsn); } +void VU0regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU0, VUregsn); } +void VU0regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU0, VUregsn); } +void VU0regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU0, VUregsn); } +void VU0regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU0, VUregsn); } +void VU0regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU0, VUregsn); } +void VU0regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU0, VUregsn); } +void VU0regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU0, VUregsn); } +void VU0regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU0, VUregsn); } +void VU0regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU0, VUregsn); } +void VU0regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU0, VUregsn); } +void VU0regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU0, VUregsn); } +void VU0regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU0, VUregsn); } +void VU0regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU0, VUregsn); } +void VU0regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU0, VUregsn); } +void VU0regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU0, VUregsn); } +void VU0regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU0, VUregsn); } +void VU0regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU0, VUregsn); } +void VU0regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU0, VUregsn); } +void VU0regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU0, VUregsn); } +void VU0regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU0, VUregsn); } +void VU0regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU0, VUregsn); } +void VU0regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU0, VUregsn); } +void VU0regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU0, VUregsn); } +void VU0regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU0, VUregsn); } +void VU0regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU0, VUregsn); } +void VU0regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU0, VUregsn); } +void VU0regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU0, VUregsn); } +void VU0regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU0, VUregsn); } +void VU0regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU0, VUregsn); } +void VU0regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU0, VUregsn); } +void VU0regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU0, VUregsn); } +void VU0regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU0, VUregsn); } +void VU0regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU0, VUregsn); } +void VU0regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU0, VUregsn); } +void VU0regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU0, VUregsn); } +void VU0regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU0, VUregsn); } +void VU0regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU0, VUregsn); } +void VU0regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU0, VUregsn); } +void VU0regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU0, VUregsn); } +void VU0regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU0, VUregsn); } +void VU0regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU0, VUregsn); } +void VU0regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU0, VUregsn); } +void VU0regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU0, VUregsn); } diff --git a/pcsx2/VU1micro.c b/pcsx2/VU1micro.c new file mode 100644 index 0000000000..d522a877cb --- /dev/null +++ b/pcsx2/VU1micro.c @@ -0,0 +1,704 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include "Common.h" +#include "VU.h" +#include "VUops.h" +#include "VUmicro.h" +#include "iVU1micro.h" +#include "iVUzerorec.h" + +VURegs* g_pVU1; + +#ifdef PCSX2_VIRTUAL_MEM +extern PSMEMORYBLOCK s_psVuMem; +#endif + +#ifdef _WIN32 +#pragma warning(disable:4113) +#endif + +#ifdef _DEBUG +u32 vudump = 0; +#endif + +#define VF_VAL(x) ((x==0x80000000)?0:(x)) + +void iDumpVU1Registers() +{ + int i; +// static int icount = 0; +// __Log("%x\n", icount); + for(i = 1; i < 32; ++i) { +// __Log("v%d: w%f(%x) z%f(%x) y%f(%x) x%f(%x), vi: ", i, VU1.VF[i].F[3], VU1.VF[i].UL[3], VU1.VF[i].F[2], VU1.VF[i].UL[2], +// VU1.VF[i].F[1], VU1.VF[i].UL[1], VU1.VF[i].F[0], VU1.VF[i].UL[0]); + //__Log("v%d: %f %f %f %f, vi: ", i, VU1.VF[i].F[3], VU1.VF[i].F[2], VU1.VF[i].F[1], VU1.VF[i].F[0]); + __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU1.VF[i].UL[3]), VF_VAL(VU1.VF[i].UL[2]), VF_VAL(VU1.VF[i].UL[1]), VF_VAL(VU1.VF[i].UL[0])); + if( i == REG_Q || i == REG_P ) __Log("%f\n", VU1.VI[i].F); + //else __Log("%x\n", VU1.VI[i].UL); + else __Log("%x\n", (i==REG_STATUS_FLAG||i==REG_MAC_FLAG||i==REG_CLIP_FLAG)?0:VU1.VI[i].UL); + } + __Log("vfACC: %f %f %f %f\n", VU1.ACC.F[3], VU1.ACC.F[2], VU1.ACC.F[1], VU1.ACC.F[0]); +} + +int vu1Init() +{ + assert( VU0.Mem != NULL ); + g_pVU1 = (VURegs*)(VU0.Mem + 0x4000); + +#ifdef PCSX2_VIRTUAL_MEM + VU1.Mem = PS2MEM_VU1MEM; + VU1.Micro = PS2MEM_VU1MICRO; +#else + VU1.Mem = (u8*)_aligned_malloc(16*1024, 16); + VU1.Micro = (u8*)_aligned_malloc(16*1024, 16); + if (VU1.Mem == NULL || VU1.Micro == NULL) { + SysMessage(_("Error allocating memory")); return -1; + } + memset(VU1.Mem, 0,16*1024); + memset(VU1.Micro, 0,16*1024); +#endif + + VU1.maxmem = -1;//16*1024-4; + VU1.maxmicro = 16*1024-4; +// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000); +// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200); + VU1.vuExec = vu1Exec; + VU1.vifRegs = vif1Regs; + +#ifndef PCSX2_NORECBUILD + if( CHECK_VU1REC ) { + recVU1Init(); + } +#endif + + vu1Reset(); + + return 0; +} + +void vu1Shutdown() { +#ifndef PCSX2_NORECBUILD + if( CHECK_VU1REC ) { + recVU1Shutdown(); + } +#endif +} + +void vu1ResetRegs() +{ + VU0.VI[REG_VPU_STAT].UL &= ~0xff00; // stop vu1 + VU0.VI[REG_FBRST].UL &= ~0xff00; // stop vu1 + vif1Regs->stat &= ~4; +} + +void vu1Reset() { + memset(&VU1.ACC, 0, sizeof(VECTOR)); + memset(VU1.VF, 0, sizeof(VECTOR)*32); + memset(VU1.VI, 0, sizeof(REG_VI)*32); + VU1.VF[0].f.x = 0.0f; + VU1.VF[0].f.y = 0.0f; + VU1.VF[0].f.z = 0.0f; + VU1.VF[0].f.w = 1.0f; + VU1.VI[0].UL = 0; + memset(VU1.Mem, 0, 16*1024); + memset(VU1.Micro, 0, 16*1024); + +#ifndef PCSX2_NORECBUILD + recResetVU1(); +#endif +} + +void vu1Freeze(gzFile f, int Mode) { + gzfreeze(&VU1.ACC, sizeof(VECTOR)); + gzfreeze(&VU1.code, sizeof(u32)); + gzfreeze(VU1.Mem, 16*1024); + gzfreeze(VU1.Micro, 16*1024); + gzfreeze(VU1.VF, 32*sizeof(VECTOR)); + gzfreeze(VU1.VI, 32*sizeof(REG_VI)); +} + +static int count; + +void vu1ExecMicro(u32 addr) +{ + if(VU0.VI[REG_VPU_STAT].UL & 0x100) { + SysPrintf("Previous Microprogram still running on VU1\n"); + + if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { + do { + Cpu->ExecuteVU1Block(); + } while(VU0.VI[REG_VPU_STAT].UL & 0x100); + } + } +#ifdef VUM_LOG + VUM_LOG("vu1ExecMicro %x\n", addr); + VUM_LOG("vu1ExecMicro %x (count=%d)\n", addr, count++); +#endif + VU0.VI[REG_VPU_STAT].UL|= 0x100; + VU0.VI[REG_VPU_STAT].UL&= ~0x7E000; + vif1Regs->stat|= 0x4; + if (addr != -1) VU1.VI[REG_TPC].UL = addr; + _vuExecMicroDebug(VU1); + + + //do { + FreezeXMMRegs(1); + Cpu->ExecuteVU1Block(); + FreezeXMMRegs(0); + //} while(VU0.VI[REG_VPU_STAT].UL & 0x100); + // rec can call vu1ExecMicro + +} + +void _vu1ExecUpper(VURegs* VU, u32 *ptr) { + VU->code = ptr[1]; + IdebugUPPER(VU1); + VU1_UPPER_OPCODE[VU->code & 0x3f](); +} + +void _vu1ExecLower(VURegs* VU, u32 *ptr) { + VU->code = ptr[0]; + IdebugLOWER(VU1); + VU1_LOWER_OPCODE[VU->code >> 25](); +} + +extern void _vuFlushAll(VURegs* VU); + +int vu1branch = 0; + +void _vu1Exec(VURegs* VU) { + _VURegsNum lregs; + _VURegsNum uregs; + VECTOR _VF; + VECTOR _VFc; + REG_VI _VI; + REG_VI _VIc; + u32 *ptr; + int vfreg; + int vireg; + int discard=0; + + if(VU1.VI[REG_TPC].UL >= VU1.maxmicro){ +#ifdef CPU_LOG + SysPrintf("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x100; + VU->cycle++; + return; + } + ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; + VU->VI[REG_TPC].UL+=8; + + if (ptr[1] & 0x40000000) { /* E flag */ + VU->ebit = 2; + } + if (ptr[1] & 0x10000000) { /* D flag */ + if (VU0.VI[REG_FBRST].UL & 0x400) { + VU0.VI[REG_VPU_STAT].UL|= 0x200; + hwIntcIrq(INTC_VU1); + } + } + if (ptr[1] & 0x08000000) { /* T flag */ + if (VU0.VI[REG_FBRST].UL & 0x800) { + VU0.VI[REG_VPU_STAT].UL|= 0x400; + hwIntcIrq(INTC_VU1); + } + } + +#ifdef VUM_LOG + if (Log) { + VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)\n", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F); + } +#endif + + VU->code = ptr[1]; + VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); + _vuTestUpperStalls(VU, &uregs); + + /* check upper flags */ + if (ptr[1] & 0x80000000) { /* I flag */ + _vu1ExecUpper(VU, ptr); + + VU->VI[REG_I].UL = ptr[0]; + } else { + VU->code = ptr[0]; + VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs); + _vuTestLowerStalls(VU, &lregs); + + vu1branch = lregs.pipe == VUPIPE_BRANCH; + + vfreg = 0; vireg = 0; + if (uregs.VFwrite) { + if (lregs.VFwrite == uregs.VFwrite) { +// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VFread0 == uregs.VFwrite || + lregs.VFread1 == uregs.VFwrite) { +// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); + _VF = VU->VF[uregs.VFwrite]; + vfreg = uregs.VFwrite; + } + } + if (uregs.VIread & (1 << REG_CLIP_FLAG)) { + if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { + SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VIread & (1 << REG_CLIP_FLAG)) { + _VI = VU->VI[REG_CLIP_FLAG]; + vireg = REG_CLIP_FLAG; + } + } + + _vu1ExecUpper(VU, ptr); + + if (discard == 0) { + if (vfreg) { + _VFc = VU->VF[vfreg]; + VU->VF[vfreg] = _VF; + } + if (vireg) { + _VIc = VU->VI[vireg]; + VU->VI[vireg] = _VI; + } + + _vu1ExecLower(VU, ptr); + + if (vfreg) { + VU->VF[vfreg] = _VFc; + } + if (vireg) { + VU->VI[vireg] = _VIc; + } + } + } + _vuAddUpperStalls(VU, &uregs); + _vuAddLowerStalls(VU, &lregs); + + _vuTestPipes(VU); + + if (VU->branch > 0) { + if (VU->branch-- == 1) { + VU->VI[REG_TPC].UL = VU->branchpc; + } + } + + if( VU->ebit > 0 ) { + if( VU->ebit-- == 1 ) { + _vuFlushAll(VU); + VU0.VI[REG_VPU_STAT].UL&= ~0x100; + vif1Regs->stat&= ~0x4; + } + } +} + +void vu1Exec(VURegs* VU) { + if (VU->VI[REG_TPC].UL >= VU->maxmicro) { +#ifdef CPU_LOG + SysPrintf("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x100; + } else { + _vu1Exec(VU); + } + VU->cycle++; +#ifdef CPU_LOG + if (VU->VI[0].UL != 0) SysPrintf("VI[0] != 0!!!!\n"); + if (VU->VF[0].f.x != 0.0f) SysPrintf("VF[0].x != 0.0!!!!\n"); + if (VU->VF[0].f.y != 0.0f) SysPrintf("VF[0].y != 0.0!!!!\n"); + if (VU->VF[0].f.z != 0.0f) SysPrintf("VF[0].z != 0.0!!!!\n"); + if (VU->VF[0].f.w != 1.0f) SysPrintf("VF[0].w != 1.0!!!!\n"); +#endif +} + +_vuTables(VU1, VU1); +_vuRegsTables(VU1, VU1regs); + +void VU1unknown(_VURegsNum *VUregsn) { + //assert(0); +#ifdef CPU_LOG + CPU_LOG("Unknown VU micromode opcode called\n"); +#endif +} + +void VU1regsunknown(_VURegsNum *VUregsn) { + //assert(0); +#ifdef CPU_LOG + CPU_LOG("Unknown VU micromode opcode called\n"); +#endif +} + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU1MI_ABS() { _vuABS(&VU1); } +void VU1MI_ADD() { _vuADD(&VU1); } +void VU1MI_ADDi() { _vuADDi(&VU1); } +void VU1MI_ADDq() { _vuADDq(&VU1); } +void VU1MI_ADDx() { _vuADDx(&VU1); } +void VU1MI_ADDy() { _vuADDy(&VU1); } +void VU1MI_ADDz() { _vuADDz(&VU1); } +void VU1MI_ADDw() { _vuADDw(&VU1); } +void VU1MI_ADDA() { _vuADDA(&VU1); } +void VU1MI_ADDAi() { _vuADDAi(&VU1); } +void VU1MI_ADDAq() { _vuADDAq(&VU1); } +void VU1MI_ADDAx() { _vuADDAx(&VU1); } +void VU1MI_ADDAy() { _vuADDAy(&VU1); } +void VU1MI_ADDAz() { _vuADDAz(&VU1); } +void VU1MI_ADDAw() { _vuADDAw(&VU1); } +void VU1MI_SUB() { _vuSUB(&VU1); } +void VU1MI_SUBi() { _vuSUBi(&VU1); } +void VU1MI_SUBq() { _vuSUBq(&VU1); } +void VU1MI_SUBx() { _vuSUBx(&VU1); } +void VU1MI_SUBy() { _vuSUBy(&VU1); } +void VU1MI_SUBz() { _vuSUBz(&VU1); } +void VU1MI_SUBw() { _vuSUBw(&VU1); } +void VU1MI_SUBA() { _vuSUBA(&VU1); } +void VU1MI_SUBAi() { _vuSUBAi(&VU1); } +void VU1MI_SUBAq() { _vuSUBAq(&VU1); } +void VU1MI_SUBAx() { _vuSUBAx(&VU1); } +void VU1MI_SUBAy() { _vuSUBAy(&VU1); } +void VU1MI_SUBAz() { _vuSUBAz(&VU1); } +void VU1MI_SUBAw() { _vuSUBAw(&VU1); } +void VU1MI_MUL() { _vuMUL(&VU1); } +void VU1MI_MULi() { _vuMULi(&VU1); } +void VU1MI_MULq() { _vuMULq(&VU1); } +void VU1MI_MULx() { _vuMULx(&VU1); } +void VU1MI_MULy() { _vuMULy(&VU1); } +void VU1MI_MULz() { _vuMULz(&VU1); } +void VU1MI_MULw() { _vuMULw(&VU1); } +void VU1MI_MULA() { _vuMULA(&VU1); } +void VU1MI_MULAi() { _vuMULAi(&VU1); } +void VU1MI_MULAq() { _vuMULAq(&VU1); } +void VU1MI_MULAx() { _vuMULAx(&VU1); } +void VU1MI_MULAy() { _vuMULAy(&VU1); } +void VU1MI_MULAz() { _vuMULAz(&VU1); } +void VU1MI_MULAw() { _vuMULAw(&VU1); } +void VU1MI_MADD() { _vuMADD(&VU1); } +void VU1MI_MADDi() { _vuMADDi(&VU1); } +void VU1MI_MADDq() { _vuMADDq(&VU1); } +void VU1MI_MADDx() { _vuMADDx(&VU1); } +void VU1MI_MADDy() { _vuMADDy(&VU1); } +void VU1MI_MADDz() { _vuMADDz(&VU1); } +void VU1MI_MADDw() { _vuMADDw(&VU1); } +void VU1MI_MADDA() { _vuMADDA(&VU1); } +void VU1MI_MADDAi() { _vuMADDAi(&VU1); } +void VU1MI_MADDAq() { _vuMADDAq(&VU1); } +void VU1MI_MADDAx() { _vuMADDAx(&VU1); } +void VU1MI_MADDAy() { _vuMADDAy(&VU1); } +void VU1MI_MADDAz() { _vuMADDAz(&VU1); } +void VU1MI_MADDAw() { _vuMADDAw(&VU1); } +void VU1MI_MSUB() { _vuMSUB(&VU1); } +void VU1MI_MSUBi() { _vuMSUBi(&VU1); } +void VU1MI_MSUBq() { _vuMSUBq(&VU1); } +void VU1MI_MSUBx() { _vuMSUBx(&VU1); } +void VU1MI_MSUBy() { _vuMSUBy(&VU1); } +void VU1MI_MSUBz() { _vuMSUBz(&VU1); } +void VU1MI_MSUBw() { _vuMSUBw(&VU1); } +void VU1MI_MSUBA() { _vuMSUBA(&VU1); } +void VU1MI_MSUBAi() { _vuMSUBAi(&VU1); } +void VU1MI_MSUBAq() { _vuMSUBAq(&VU1); } +void VU1MI_MSUBAx() { _vuMSUBAx(&VU1); } +void VU1MI_MSUBAy() { _vuMSUBAy(&VU1); } +void VU1MI_MSUBAz() { _vuMSUBAz(&VU1); } +void VU1MI_MSUBAw() { _vuMSUBAw(&VU1); } +void VU1MI_MAX() { _vuMAX(&VU1); } +void VU1MI_MAXi() { _vuMAXi(&VU1); } +void VU1MI_MAXx() { _vuMAXx(&VU1); } +void VU1MI_MAXy() { _vuMAXy(&VU1); } +void VU1MI_MAXz() { _vuMAXz(&VU1); } +void VU1MI_MAXw() { _vuMAXw(&VU1); } +void VU1MI_MINI() { _vuMINI(&VU1); } +void VU1MI_MINIi() { _vuMINIi(&VU1); } +void VU1MI_MINIx() { _vuMINIx(&VU1); } +void VU1MI_MINIy() { _vuMINIy(&VU1); } +void VU1MI_MINIz() { _vuMINIz(&VU1); } +void VU1MI_MINIw() { _vuMINIw(&VU1); } +void VU1MI_OPMULA() { _vuOPMULA(&VU1); } +void VU1MI_OPMSUB() { _vuOPMSUB(&VU1); } +void VU1MI_NOP() { _vuNOP(&VU1); } +void VU1MI_FTOI0() { _vuFTOI0(&VU1); } +void VU1MI_FTOI4() { _vuFTOI4(&VU1); } +void VU1MI_FTOI12() { _vuFTOI12(&VU1); } +void VU1MI_FTOI15() { _vuFTOI15(&VU1); } +void VU1MI_ITOF0() { _vuITOF0(&VU1); } +void VU1MI_ITOF4() { _vuITOF4(&VU1); } +void VU1MI_ITOF12() { _vuITOF12(&VU1); } +void VU1MI_ITOF15() { _vuITOF15(&VU1); } +void VU1MI_CLIP() { _vuCLIP(&VU1); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU1MI_DIV() { _vuDIV(&VU1); } +void VU1MI_SQRT() { _vuSQRT(&VU1); } +void VU1MI_RSQRT() { _vuRSQRT(&VU1); } +void VU1MI_IADD() { _vuIADD(&VU1); } +void VU1MI_IADDI() { _vuIADDI(&VU1); } +void VU1MI_IADDIU() { _vuIADDIU(&VU1); } +void VU1MI_IAND() { _vuIAND(&VU1); } +void VU1MI_IOR() { _vuIOR(&VU1); } +void VU1MI_ISUB() { _vuISUB(&VU1); } +void VU1MI_ISUBIU() { _vuISUBIU(&VU1); } +void VU1MI_MOVE() { _vuMOVE(&VU1); } +void VU1MI_MFIR() { _vuMFIR(&VU1); } +void VU1MI_MTIR() { _vuMTIR(&VU1); } +void VU1MI_MR32() { _vuMR32(&VU1); } +void VU1MI_LQ() { _vuLQ(&VU1); } +void VU1MI_LQD() { _vuLQD(&VU1); } +void VU1MI_LQI() { _vuLQI(&VU1); } +void VU1MI_SQ() { _vuSQ(&VU1); } +void VU1MI_SQD() { _vuSQD(&VU1); } +void VU1MI_SQI() { _vuSQI(&VU1); } +void VU1MI_ILW() { _vuILW(&VU1); } +void VU1MI_ISW() { _vuISW(&VU1); } +void VU1MI_ILWR() { _vuILWR(&VU1); } +void VU1MI_ISWR() { _vuISWR(&VU1); } +void VU1MI_RINIT() { _vuRINIT(&VU1); } +void VU1MI_RGET() { _vuRGET(&VU1); } +void VU1MI_RNEXT() { _vuRNEXT(&VU1); } +void VU1MI_RXOR() { _vuRXOR(&VU1); } +void VU1MI_WAITQ() { _vuWAITQ(&VU1); } +void VU1MI_FSAND() { _vuFSAND(&VU1); } +void VU1MI_FSEQ() { _vuFSEQ(&VU1); } +void VU1MI_FSOR() { _vuFSOR(&VU1); } +void VU1MI_FSSET() { _vuFSSET(&VU1); } +void VU1MI_FMAND() { _vuFMAND(&VU1); } +void VU1MI_FMEQ() { _vuFMEQ(&VU1); } +void VU1MI_FMOR() { _vuFMOR(&VU1); } +void VU1MI_FCAND() { _vuFCAND(&VU1); } +void VU1MI_FCEQ() { _vuFCEQ(&VU1); } +void VU1MI_FCOR() { _vuFCOR(&VU1); } +void VU1MI_FCSET() { _vuFCSET(&VU1); } +void VU1MI_FCGET() { _vuFCGET(&VU1); } +void VU1MI_IBEQ() { _vuIBEQ(&VU1); } +void VU1MI_IBGEZ() { _vuIBGEZ(&VU1); } +void VU1MI_IBGTZ() { _vuIBGTZ(&VU1); } +void VU1MI_IBLTZ() { _vuIBLTZ(&VU1); } +void VU1MI_IBLEZ() { _vuIBLEZ(&VU1); } +void VU1MI_IBNE() { _vuIBNE(&VU1); } +void VU1MI_B() { _vuB(&VU1); } +void VU1MI_BAL() { _vuBAL(&VU1); } +void VU1MI_JR() { _vuJR(&VU1); } +void VU1MI_JALR() { _vuJALR(&VU1); } +void VU1MI_MFP() { _vuMFP(&VU1); } +void VU1MI_WAITP() { _vuWAITP(&VU1); } +void VU1MI_ESADD() { _vuESADD(&VU1); } +void VU1MI_ERSADD() { _vuERSADD(&VU1); } +void VU1MI_ELENG() { _vuELENG(&VU1); } +void VU1MI_ERLENG() { _vuERLENG(&VU1); } +void VU1MI_EATANxy() { _vuEATANxy(&VU1); } +void VU1MI_EATANxz() { _vuEATANxz(&VU1); } +void VU1MI_ESUM() { _vuESUM(&VU1); } +void VU1MI_ERCPR() { _vuERCPR(&VU1); } +void VU1MI_ESQRT() { _vuESQRT(&VU1); } +void VU1MI_ERSQRT() { _vuERSQRT(&VU1); } +void VU1MI_ESIN() { _vuESIN(&VU1); } +void VU1MI_EATAN() { _vuEATAN(&VU1); } +void VU1MI_EEXP() { _vuEEXP(&VU1); } +void VU1MI_XITOP() { _vuXITOP(&VU1); } +void VU1MI_XGKICK() { _vuXGKICK(&VU1); } +void VU1MI_XTOP() { _vuXTOP(&VU1); } + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU1regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU1, VUregsn); } +void VU1regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU1, VUregsn); } +void VU1regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU1, VUregsn); } +void VU1regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU1, VUregsn); } +void VU1regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU1, VUregsn); } +void VU1regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU1, VUregsn); } +void VU1regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU1, VUregsn); } +void VU1regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU1, VUregsn); } +void VU1regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU1, VUregsn); } +void VU1regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU1, VUregsn); } +void VU1regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU1, VUregsn); } +void VU1regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU1, VUregsn); } +void VU1regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU1, VUregsn); } +void VU1regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU1, VUregsn); } +void VU1regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU1, VUregsn); } +void VU1regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU1, VUregsn); } +void VU1regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU1, VUregsn); } +void VU1regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU1, VUregsn); } +void VU1regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU1, VUregsn); } +void VU1regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU1, VUregsn); } +void VU1regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU1, VUregsn); } +void VU1regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU1, VUregsn); } +void VU1regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU1, VUregsn); } +void VU1regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU1, VUregsn); } +void VU1regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU1, VUregsn); } +void VU1regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU1, VUregsn); } +void VU1regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU1, VUregsn); } +void VU1regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU1, VUregsn); } +void VU1regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU1, VUregsn); } +void VU1regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU1, VUregsn); } +void VU1regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU1, VUregsn); } +void VU1regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU1, VUregsn); } +void VU1regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU1, VUregsn); } +void VU1regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU1, VUregsn); } +void VU1regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU1, VUregsn); } +void VU1regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU1, VUregsn); } +void VU1regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU1, VUregsn); } +void VU1regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU1, VUregsn); } +void VU1regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU1, VUregsn); } +void VU1regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU1, VUregsn); } +void VU1regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU1, VUregsn); } +void VU1regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU1, VUregsn); } +void VU1regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU1, VUregsn); } +void VU1regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU1, VUregsn); } +void VU1regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU1, VUregsn); } +void VU1regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU1, VUregsn); } +void VU1regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU1, VUregsn); } +void VU1regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU1, VUregsn); } +void VU1regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU1, VUregsn); } +void VU1regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU1, VUregsn); } +void VU1regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU1, VUregsn); } +void VU1regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU1, VUregsn); } +void VU1regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU1, VUregsn); } +void VU1regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU1, VUregsn); } +void VU1regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU1, VUregsn); } +void VU1regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU1, VUregsn); } +void VU1regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU1, VUregsn); } +void VU1regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU1, VUregsn); } +void VU1regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU1, VUregsn); } +void VU1regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU1, VUregsn); } +void VU1regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU1, VUregsn); } +void VU1regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU1, VUregsn); } +void VU1regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU1, VUregsn); } +void VU1regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU1, VUregsn); } +void VU1regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU1, VUregsn); } +void VU1regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU1, VUregsn); } +void VU1regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU1, VUregsn); } +void VU1regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU1, VUregsn); } +void VU1regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU1, VUregsn); } +void VU1regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU1, VUregsn); } +void VU1regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU1, VUregsn); } +void VU1regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU1, VUregsn); } +void VU1regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU1, VUregsn); } +void VU1regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU1, VUregsn); } +void VU1regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU1, VUregsn); } +void VU1regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU1, VUregsn); } +void VU1regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU1, VUregsn); } +void VU1regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU1, VUregsn); } +void VU1regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU1, VUregsn); } +void VU1regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU1, VUregsn); } +void VU1regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU1, VUregsn); } +void VU1regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU1, VUregsn); } +void VU1regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU1, VUregsn); } +void VU1regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU1, VUregsn); } +void VU1regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU1, VUregsn); } +void VU1regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU1, VUregsn); } +void VU1regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU1, VUregsn); } +void VU1regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU1, VUregsn); } +void VU1regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU1, VUregsn); } +void VU1regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU1, VUregsn); } +void VU1regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU1, VUregsn); } +void VU1regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU1, VUregsn); } +void VU1regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU1, VUregsn); } +void VU1regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU1, VUregsn); } +void VU1regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU1, VUregsn); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU1regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU1, VUregsn); } +void VU1regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU1, VUregsn); } +void VU1regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU1, VUregsn); } +void VU1regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU1, VUregsn); } +void VU1regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU1, VUregsn); } +void VU1regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU1, VUregsn); } +void VU1regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU1, VUregsn); } +void VU1regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU1, VUregsn); } +void VU1regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU1, VUregsn); } +void VU1regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU1, VUregsn); } +void VU1regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU1, VUregsn); } +void VU1regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU1, VUregsn); } +void VU1regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU1, VUregsn); } +void VU1regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU1, VUregsn); } +void VU1regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU1, VUregsn); } +void VU1regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU1, VUregsn); } +void VU1regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU1, VUregsn); } +void VU1regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU1, VUregsn); } +void VU1regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU1, VUregsn); } +void VU1regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU1, VUregsn); } +void VU1regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU1, VUregsn); } +void VU1regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU1, VUregsn); } +void VU1regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU1, VUregsn); } +void VU1regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU1, VUregsn); } +void VU1regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU1, VUregsn); } +void VU1regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU1, VUregsn); } +void VU1regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU1, VUregsn); } +void VU1regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU1, VUregsn); } +void VU1regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU1, VUregsn); } +void VU1regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU1, VUregsn); } +void VU1regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU1, VUregsn); } +void VU1regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU1, VUregsn); } +void VU1regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU1, VUregsn); } +void VU1regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU1, VUregsn); } +void VU1regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU1, VUregsn); } +void VU1regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU1, VUregsn); } +void VU1regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU1, VUregsn); } +void VU1regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU1, VUregsn); } +void VU1regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU1, VUregsn); } +void VU1regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU1, VUregsn); } +void VU1regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU1, VUregsn); } +void VU1regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU1, VUregsn); } +void VU1regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU1, VUregsn); } +void VU1regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU1, VUregsn); } +void VU1regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU1, VUregsn); } +void VU1regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU1, VUregsn); } +void VU1regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU1, VUregsn); } +void VU1regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU1, VUregsn); } +void VU1regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU1, VUregsn); } +void VU1regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU1, VUregsn); } +void VU1regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU1, VUregsn); } +void VU1regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU1, VUregsn); } +void VU1regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU1, VUregsn); } +void VU1regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU1, VUregsn); } +void VU1regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU1, VUregsn); } +void VU1regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU1, VUregsn); } +void VU1regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU1, VUregsn); } +void VU1regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU1, VUregsn); } +void VU1regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU1, VUregsn); } +void VU1regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU1, VUregsn); } +void VU1regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU1, VUregsn); } +void VU1regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU1, VUregsn); } +void VU1regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU1, VUregsn); } +void VU1regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU1, VUregsn); } +void VU1regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU1, VUregsn); } +void VU1regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU1, VUregsn); } +void VU1regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU1, VUregsn); } +void VU1regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU1, VUregsn); } +void VU1regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU1, VUregsn); } diff --git a/pcsx2/VUflags.c b/pcsx2/VUflags.c new file mode 100644 index 0000000000..8cd51f8e96 --- /dev/null +++ b/pcsx2/VUflags.c @@ -0,0 +1,95 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "Common.h" +#include "VUmicro.h" +/*****************************************/ +/* NEW FLAGS */ //By asadr. Thnkx F|RES :p +/*****************************************/ + + +__inline void vuUpdateDI(VURegs * VU) { +// u32 Flag_S = 0; +// u32 Flag_I = 0; +// u32 Flag_D = 0; +// +// /* +// FLAG D - I +// */ +// Flag_I = (VU->statusflag >> 4) & 0x1; +// Flag_D = (VU->statusflag >> 5) & 0x1; +// +// VU->statusflag|= (Flag_I | (VU0.VI[REG_STATUS_FLAG].US[0] >> 4)) << 10; +// VU->statusflag|= (Flag_D | (VU0.VI[REG_STATUS_FLAG].US[0] >> 5)) << 11; +} + +#define VU_MAC_UPDATE(name, shift) \ +u32 name(VURegs * VU, float f) { \ + u32 v = *(u32*)&f; \ + int exp = (v >> 23) & 0xff; \ + u32 s = v & 0x80000000; \ + \ + if (s) VU->macflag |= 0x0010<macflag &= ~(0x0010<macflag = (VU->macflag & ~(0x1100<macflag = (VU->macflag&~(0x1000<macflag = (VU->macflag&~(0x0100<macflag = (VU->macflag & ~(0x1101<macflag&= ~(0x1111<macflag & 0x000F) newflag = 0x1; + if (VU->macflag & 0x00F0) newflag |= 0x2; + if (VU->macflag & 0x0F00) newflag |= 0x4; + if (VU->macflag & 0xF000) newflag |= 0x8; + VU->statusflag = (VU->statusflag&0xc30)|newflag|((VU->statusflag&0xf)<<6); +} diff --git a/pcsx2/VUflags.h b/pcsx2/VUflags.h new file mode 100644 index 0000000000..2b4ff3d951 --- /dev/null +++ b/pcsx2/VUflags.h @@ -0,0 +1,38 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VUFLAGS_H__ +#define __VUFLAGS_H__ + +#include "VU.h" + +void vuUpdateDI(VURegs * VU); +u32 VU_MACx_UPDATE(VURegs * VU, float x); +u32 VU_MACy_UPDATE(VURegs * VU, float y); +u32 VU_MACz_UPDATE(VURegs * VU, float z); +u32 VU_MACw_UPDATE(VURegs * VU, float w); +void VU_MACx_CLEAR(VURegs * VU); +void VU_MACy_CLEAR(VURegs * VU); +void VU_MACz_CLEAR(VURegs * VU); +void VU_MACw_CLEAR(VURegs * VU); +void VU_STAT_UPDATE(VURegs * VU); + + +#endif + + diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h new file mode 100644 index 0000000000..0920a61e86 --- /dev/null +++ b/pcsx2/VUmicro.h @@ -0,0 +1,1266 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VUMICRO_H__ +#define __VUMICRO_H__ + +#include "VU.h" + +void iDumpVU0Registers(); +void iDumpVU1Registers(); + +//both for VU0 VU1 micromode + +extern void (*VU0_LOWER_OPCODE[128])(); +extern void (*VU0_UPPER_OPCODE[64])(); + +extern void (*VU0_UPPER_FD_00_TABLE[32])(); +extern void (*VU0_UPPER_FD_01_TABLE[32])(); +extern void (*VU0_UPPER_FD_10_TABLE[32])(); +extern void (*VU0_UPPER_FD_11_TABLE[32])(); + +extern void (*VU0regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); + +extern void (*VU0regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); + +extern void (*VU1_LOWER_OPCODE[128])(); +extern void (*VU1_UPPER_OPCODE[64])(); + +extern void (*VU1_UPPER_FD_00_TABLE[32])(); +extern void (*VU1_UPPER_FD_01_TABLE[32])(); +extern void (*VU1_UPPER_FD_10_TABLE[32])(); +extern void (*VU1_UPPER_FD_11_TABLE[32])(); + +extern void (*VU1regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); + +extern void (*VU1regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); + +// VU0 +int vu0Init(); +void vu0Reset(); +void vu0ResetRegs(); +void vu0Freeze(gzFile f, int Mode); +void vu0Shutdown(); +void vu0ExecMicro(u32 addr); +void vu0Exec(VURegs* VU); +void vu0Finish(); +void recResetVU0( void ); + +// VU1 +int vu1Init(); +void vu1Reset(); +void vu1ResetRegs(); +void recResetVU1( void ); +void vu1Freeze(gzFile f, int Mode); +void vu1Shutdown(); +void vu1ExecMicro(u32 addr); +void vu1Exec(VURegs* VU); + +void VU0_UPPER_FD_00(); +void VU0_UPPER_FD_01(); +void VU0_UPPER_FD_10(); +void VU0_UPPER_FD_11(); + +void VU0LowerOP(); +void VU0LowerOP_T3_00(); +void VU0LowerOP_T3_01(); +void VU0LowerOP_T3_10(); +void VU0LowerOP_T3_11(); + +void VU0unknown(); + +void VU1_UPPER_FD_00(); +void VU1_UPPER_FD_01(); +void VU1_UPPER_FD_10(); +void VU1_UPPER_FD_11(); + +void VU1LowerOP(); +void VU1LowerOP_T3_00(); +void VU1LowerOP_T3_01(); +void VU1LowerOP_T3_10(); +void VU1LowerOP_T3_11(); + +void VU1unknown(); + +void VU0regs_UPPER_FD_00(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_01(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_10(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_11(_VURegsNum *VUregsn); + +void VU0regsLowerOP(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_00(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_01(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_10(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_11(_VURegsNum *VUregsn); + +void VU0regsunknown(_VURegsNum *VUregsn); + +void VU1regs_UPPER_FD_00(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_01(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_10(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_11(_VURegsNum *VUregsn); + +void VU1regsLowerOP(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_00(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_01(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_10(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_11(_VURegsNum *VUregsn); + +void VU1regsunknown(_VURegsNum *VUregsn); + +/***************************************** + VU0 Micromode Upper instructions +*****************************************/ + +void VU0MI_ABS(); +void VU0MI_ADD(); +void VU0MI_ADDi(); +void VU0MI_ADDq(); +void VU0MI_ADDx(); +void VU0MI_ADDy(); +void VU0MI_ADDz(); +void VU0MI_ADDw(); +void VU0MI_ADDA(); +void VU0MI_ADDAi(); +void VU0MI_ADDAq(); +void VU0MI_ADDAx(); +void VU0MI_ADDAy(); +void VU0MI_ADDAz(); +void VU0MI_ADDAw(); +void VU0MI_SUB(); +void VU0MI_SUBi(); +void VU0MI_SUBq(); +void VU0MI_SUBx(); +void VU0MI_SUBy(); +void VU0MI_SUBz(); +void VU0MI_SUBw(); +void VU0MI_SUBA(); +void VU0MI_SUBAi(); +void VU0MI_SUBAq(); +void VU0MI_SUBAx(); +void VU0MI_SUBAy(); +void VU0MI_SUBAz(); +void VU0MI_SUBAw(); +void VU0MI_MUL(); +void VU0MI_MULi(); +void VU0MI_MULq(); +void VU0MI_MULx(); +void VU0MI_MULy(); +void VU0MI_MULz(); +void VU0MI_MULw(); +void VU0MI_MULA(); +void VU0MI_MULAi(); +void VU0MI_MULAq(); +void VU0MI_MULAx(); +void VU0MI_MULAy(); +void VU0MI_MULAz(); +void VU0MI_MULAw(); +void VU0MI_MADD(); +void VU0MI_MADDi(); +void VU0MI_MADDq(); +void VU0MI_MADDx(); +void VU0MI_MADDy(); +void VU0MI_MADDz(); +void VU0MI_MADDw(); +void VU0MI_MADDA(); +void VU0MI_MADDAi(); +void VU0MI_MADDAq(); +void VU0MI_MADDAx(); +void VU0MI_MADDAy(); +void VU0MI_MADDAz(); +void VU0MI_MADDAw(); +void VU0MI_MSUB(); +void VU0MI_MSUBi(); +void VU0MI_MSUBq(); +void VU0MI_MSUBx(); +void VU0MI_MSUBy(); +void VU0MI_MSUBz(); +void VU0MI_MSUBw(); +void VU0MI_MSUBA(); +void VU0MI_MSUBAi(); +void VU0MI_MSUBAq(); +void VU0MI_MSUBAx(); +void VU0MI_MSUBAy(); +void VU0MI_MSUBAz(); +void VU0MI_MSUBAw(); +void VU0MI_MAX(); +void VU0MI_MAXi(); +void VU0MI_MAXx(); +void VU0MI_MAXy(); +void VU0MI_MAXz(); +void VU0MI_MAXw(); +void VU0MI_MINI(); +void VU0MI_MINIi(); +void VU0MI_MINIx(); +void VU0MI_MINIy(); +void VU0MI_MINIz(); +void VU0MI_MINIw(); +void VU0MI_OPMULA(); +void VU0MI_OPMSUB(); +void VU0MI_NOP(); +void VU0MI_FTOI0(); +void VU0MI_FTOI4(); +void VU0MI_FTOI12(); +void VU0MI_FTOI15(); +void VU0MI_ITOF0(); +void VU0MI_ITOF4(); +void VU0MI_ITOF12(); +void VU0MI_ITOF15(); +void VU0MI_CLIP(); + +/***************************************** + VU0 Micromode Lower instructions +*****************************************/ + +void VU0MI_DIV(); +void VU0MI_SQRT(); +void VU0MI_RSQRT(); +void VU0MI_IADD(); +void VU0MI_IADDI(); +void VU0MI_IADDIU(); +void VU0MI_IAND(); +void VU0MI_IOR(); +void VU0MI_ISUB(); +void VU0MI_ISUBIU(); +void VU0MI_MOVE(); +void VU0MI_MFIR(); +void VU0MI_MTIR(); +void VU0MI_MR32(); +void VU0MI_LQ(); +void VU0MI_LQD(); +void VU0MI_LQI(); +void VU0MI_SQ(); +void VU0MI_SQD(); +void VU0MI_SQI(); +void VU0MI_ILW(); +void VU0MI_ISW(); +void VU0MI_ILWR(); +void VU0MI_ISWR(); +void VU0MI_LOI(); +void VU0MI_RINIT(); +void VU0MI_RGET(); +void VU0MI_RNEXT(); +void VU0MI_RXOR(); +void VU0MI_WAITQ(); +void VU0MI_FSAND(); +void VU0MI_FSEQ(); +void VU0MI_FSOR(); +void VU0MI_FSSET(); +void VU0MI_FMAND(); +void VU0MI_FMEQ(); +void VU0MI_FMOR(); +void VU0MI_FCAND(); +void VU0MI_FCEQ(); +void VU0MI_FCOR(); +void VU0MI_FCSET(); +void VU0MI_FCGET(); +void VU0MI_IBEQ(); +void VU0MI_IBGEZ(); +void VU0MI_IBGTZ(); +void VU0MI_IBLEZ(); +void VU0MI_IBLTZ(); +void VU0MI_IBNE(); +void VU0MI_B(); +void VU0MI_BAL(); +void VU0MI_JR(); +void VU0MI_JALR(); +void VU0MI_MFP(); +void VU0MI_WAITP(); +void VU0MI_ESADD(); +void VU0MI_ERSADD(); +void VU0MI_ELENG(); +void VU0MI_ERLENG(); +void VU0MI_EATANxy(); +void VU0MI_EATANxz(); +void VU0MI_ESUM(); +void VU0MI_ERCPR(); +void VU0MI_ESQRT(); +void VU0MI_ERSQRT(); +void VU0MI_ESIN(); +void VU0MI_EATAN(); +void VU0MI_EEXP(); +void VU0MI_XGKICK(); +void VU0MI_XTOP(); +void VU0MI_XITOP(); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU0regsMI_ABS(_VURegsNum *VUregsn); +void VU0regsMI_ADD(_VURegsNum *VUregsn); +void VU0regsMI_ADDi(_VURegsNum *VUregsn); +void VU0regsMI_ADDq(_VURegsNum *VUregsn); +void VU0regsMI_ADDx(_VURegsNum *VUregsn); +void VU0regsMI_ADDy(_VURegsNum *VUregsn); +void VU0regsMI_ADDz(_VURegsNum *VUregsn); +void VU0regsMI_ADDw(_VURegsNum *VUregsn); +void VU0regsMI_ADDA(_VURegsNum *VUregsn); +void VU0regsMI_ADDAi(_VURegsNum *VUregsn); +void VU0regsMI_ADDAq(_VURegsNum *VUregsn); +void VU0regsMI_ADDAx(_VURegsNum *VUregsn); +void VU0regsMI_ADDAy(_VURegsNum *VUregsn); +void VU0regsMI_ADDAz(_VURegsNum *VUregsn); +void VU0regsMI_ADDAw(_VURegsNum *VUregsn); +void VU0regsMI_SUB(_VURegsNum *VUregsn); +void VU0regsMI_SUBi(_VURegsNum *VUregsn); +void VU0regsMI_SUBq(_VURegsNum *VUregsn); +void VU0regsMI_SUBx(_VURegsNum *VUregsn); +void VU0regsMI_SUBy(_VURegsNum *VUregsn); +void VU0regsMI_SUBz(_VURegsNum *VUregsn); +void VU0regsMI_SUBw(_VURegsNum *VUregsn); +void VU0regsMI_SUBA(_VURegsNum *VUregsn); +void VU0regsMI_SUBAi(_VURegsNum *VUregsn); +void VU0regsMI_SUBAq(_VURegsNum *VUregsn); +void VU0regsMI_SUBAx(_VURegsNum *VUregsn); +void VU0regsMI_SUBAy(_VURegsNum *VUregsn); +void VU0regsMI_SUBAz(_VURegsNum *VUregsn); +void VU0regsMI_SUBAw(_VURegsNum *VUregsn); +void VU0regsMI_MUL(_VURegsNum *VUregsn); +void VU0regsMI_MULi(_VURegsNum *VUregsn); +void VU0regsMI_MULq(_VURegsNum *VUregsn); +void VU0regsMI_MULx(_VURegsNum *VUregsn); +void VU0regsMI_MULy(_VURegsNum *VUregsn); +void VU0regsMI_MULz(_VURegsNum *VUregsn); +void VU0regsMI_MULw(_VURegsNum *VUregsn); +void VU0regsMI_MULA(_VURegsNum *VUregsn); +void VU0regsMI_MULAi(_VURegsNum *VUregsn); +void VU0regsMI_MULAq(_VURegsNum *VUregsn); +void VU0regsMI_MULAx(_VURegsNum *VUregsn); +void VU0regsMI_MULAy(_VURegsNum *VUregsn); +void VU0regsMI_MULAz(_VURegsNum *VUregsn); +void VU0regsMI_MULAw(_VURegsNum *VUregsn); +void VU0regsMI_MADD(_VURegsNum *VUregsn); +void VU0regsMI_MADDi(_VURegsNum *VUregsn); +void VU0regsMI_MADDq(_VURegsNum *VUregsn); +void VU0regsMI_MADDx(_VURegsNum *VUregsn); +void VU0regsMI_MADDy(_VURegsNum *VUregsn); +void VU0regsMI_MADDz(_VURegsNum *VUregsn); +void VU0regsMI_MADDw(_VURegsNum *VUregsn); +void VU0regsMI_MADDA(_VURegsNum *VUregsn); +void VU0regsMI_MADDAi(_VURegsNum *VUregsn); +void VU0regsMI_MADDAq(_VURegsNum *VUregsn); +void VU0regsMI_MADDAx(_VURegsNum *VUregsn); +void VU0regsMI_MADDAy(_VURegsNum *VUregsn); +void VU0regsMI_MADDAz(_VURegsNum *VUregsn); +void VU0regsMI_MADDAw(_VURegsNum *VUregsn); +void VU0regsMI_MSUB(_VURegsNum *VUregsn); +void VU0regsMI_MSUBi(_VURegsNum *VUregsn); +void VU0regsMI_MSUBq(_VURegsNum *VUregsn); +void VU0regsMI_MSUBx(_VURegsNum *VUregsn); +void VU0regsMI_MSUBy(_VURegsNum *VUregsn); +void VU0regsMI_MSUBz(_VURegsNum *VUregsn); +void VU0regsMI_MSUBw(_VURegsNum *VUregsn); +void VU0regsMI_MSUBA(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAi(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAq(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAx(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAy(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAz(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAw(_VURegsNum *VUregsn); +void VU0regsMI_MAX(_VURegsNum *VUregsn); +void VU0regsMI_MAXi(_VURegsNum *VUregsn); +void VU0regsMI_MAXx(_VURegsNum *VUregsn); +void VU0regsMI_MAXy(_VURegsNum *VUregsn); +void VU0regsMI_MAXz(_VURegsNum *VUregsn); +void VU0regsMI_MAXw(_VURegsNum *VUregsn); +void VU0regsMI_MINI(_VURegsNum *VUregsn); +void VU0regsMI_MINIi(_VURegsNum *VUregsn); +void VU0regsMI_MINIx(_VURegsNum *VUregsn); +void VU0regsMI_MINIy(_VURegsNum *VUregsn); +void VU0regsMI_MINIz(_VURegsNum *VUregsn); +void VU0regsMI_MINIw(_VURegsNum *VUregsn); +void VU0regsMI_OPMULA(_VURegsNum *VUregsn); +void VU0regsMI_OPMSUB(_VURegsNum *VUregsn); +void VU0regsMI_NOP(_VURegsNum *VUregsn); +void VU0regsMI_FTOI0(_VURegsNum *VUregsn); +void VU0regsMI_FTOI4(_VURegsNum *VUregsn); +void VU0regsMI_FTOI12(_VURegsNum *VUregsn); +void VU0regsMI_FTOI15(_VURegsNum *VUregsn); +void VU0regsMI_ITOF0(_VURegsNum *VUregsn); +void VU0regsMI_ITOF4(_VURegsNum *VUregsn); +void VU0regsMI_ITOF12(_VURegsNum *VUregsn); +void VU0regsMI_ITOF15(_VURegsNum *VUregsn); +void VU0regsMI_CLIP(_VURegsNum *VUregsn); + +/***************************************** + VU0 Micromode Lower instructions +*****************************************/ + +void VU0regsMI_DIV(_VURegsNum *VUregsn); +void VU0regsMI_SQRT(_VURegsNum *VUregsn); +void VU0regsMI_RSQRT(_VURegsNum *VUregsn); +void VU0regsMI_IADD(_VURegsNum *VUregsn); +void VU0regsMI_IADDI(_VURegsNum *VUregsn); +void VU0regsMI_IADDIU(_VURegsNum *VUregsn); +void VU0regsMI_IAND(_VURegsNum *VUregsn); +void VU0regsMI_IOR(_VURegsNum *VUregsn); +void VU0regsMI_ISUB(_VURegsNum *VUregsn); +void VU0regsMI_ISUBIU(_VURegsNum *VUregsn); +void VU0regsMI_MOVE(_VURegsNum *VUregsn); +void VU0regsMI_MFIR(_VURegsNum *VUregsn); +void VU0regsMI_MTIR(_VURegsNum *VUregsn); +void VU0regsMI_MR32(_VURegsNum *VUregsn); +void VU0regsMI_LQ(_VURegsNum *VUregsn); +void VU0regsMI_LQD(_VURegsNum *VUregsn); +void VU0regsMI_LQI(_VURegsNum *VUregsn); +void VU0regsMI_SQ(_VURegsNum *VUregsn); +void VU0regsMI_SQD(_VURegsNum *VUregsn); +void VU0regsMI_SQI(_VURegsNum *VUregsn); +void VU0regsMI_ILW(_VURegsNum *VUregsn); +void VU0regsMI_ISW(_VURegsNum *VUregsn); +void VU0regsMI_ILWR(_VURegsNum *VUregsn); +void VU0regsMI_ISWR(_VURegsNum *VUregsn); +void VU0regsMI_LOI(_VURegsNum *VUregsn); +void VU0regsMI_RINIT(_VURegsNum *VUregsn); +void VU0regsMI_RGET(_VURegsNum *VUregsn); +void VU0regsMI_RNEXT(_VURegsNum *VUregsn); +void VU0regsMI_RXOR(_VURegsNum *VUregsn); +void VU0regsMI_WAITQ(_VURegsNum *VUregsn); +void VU0regsMI_FSAND(_VURegsNum *VUregsn); +void VU0regsMI_FSEQ(_VURegsNum *VUregsn); +void VU0regsMI_FSOR(_VURegsNum *VUregsn); +void VU0regsMI_FSSET(_VURegsNum *VUregsn); +void VU0regsMI_FMAND(_VURegsNum *VUregsn); +void VU0regsMI_FMEQ(_VURegsNum *VUregsn); +void VU0regsMI_FMOR(_VURegsNum *VUregsn); +void VU0regsMI_FCAND(_VURegsNum *VUregsn); +void VU0regsMI_FCEQ(_VURegsNum *VUregsn); +void VU0regsMI_FCOR(_VURegsNum *VUregsn); +void VU0regsMI_FCSET(_VURegsNum *VUregsn); +void VU0regsMI_FCGET(_VURegsNum *VUregsn); +void VU0regsMI_IBEQ(_VURegsNum *VUregsn); +void VU0regsMI_IBGEZ(_VURegsNum *VUregsn); +void VU0regsMI_IBGTZ(_VURegsNum *VUregsn); +void VU0regsMI_IBLTZ(_VURegsNum *VUregsn); +void VU0regsMI_IBLEZ(_VURegsNum *VUregsn); +void VU0regsMI_IBNE(_VURegsNum *VUregsn); +void VU0regsMI_B(_VURegsNum *VUregsn); +void VU0regsMI_BAL(_VURegsNum *VUregsn); +void VU0regsMI_JR(_VURegsNum *VUregsn); +void VU0regsMI_JALR(_VURegsNum *VUregsn); +void VU0regsMI_MFP(_VURegsNum *VUregsn); +void VU0regsMI_WAITP(_VURegsNum *VUregsn); +void VU0regsMI_ESADD(_VURegsNum *VUregsn); +void VU0regsMI_ERSADD(_VURegsNum *VUregsn); +void VU0regsMI_ELENG(_VURegsNum *VUregsn); +void VU0regsMI_ERLENG(_VURegsNum *VUregsn); +void VU0regsMI_EATANxy(_VURegsNum *VUregsn); +void VU0regsMI_EATANxz(_VURegsNum *VUregsn); +void VU0regsMI_ESUM(_VURegsNum *VUregsn); +void VU0regsMI_ERCPR(_VURegsNum *VUregsn); +void VU0regsMI_ESQRT(_VURegsNum *VUregsn); +void VU0regsMI_ERSQRT(_VURegsNum *VUregsn); +void VU0regsMI_ESIN(_VURegsNum *VUregsn); +void VU0regsMI_EATAN(_VURegsNum *VUregsn); +void VU0regsMI_EEXP(_VURegsNum *VUregsn); +void VU0regsMI_XGKICK(_VURegsNum *VUregsn); +void VU0regsMI_XTOP(_VURegsNum *VUregsn); +void VU0regsMI_XITOP(_VURegsNum *VUregsn); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU1MI_ABS(); +void VU1MI_ADD(); +void VU1MI_ADDi(); +void VU1MI_ADDq(); +void VU1MI_ADDx(); +void VU1MI_ADDy(); +void VU1MI_ADDz(); +void VU1MI_ADDw(); +void VU1MI_ADDA(); +void VU1MI_ADDAi(); +void VU1MI_ADDAq(); +void VU1MI_ADDAx(); +void VU1MI_ADDAy(); +void VU1MI_ADDAz(); +void VU1MI_ADDAw(); +void VU1MI_SUB(); +void VU1MI_SUBi(); +void VU1MI_SUBq(); +void VU1MI_SUBx(); +void VU1MI_SUBy(); +void VU1MI_SUBz(); +void VU1MI_SUBw(); +void VU1MI_SUBA(); +void VU1MI_SUBAi(); +void VU1MI_SUBAq(); +void VU1MI_SUBAx(); +void VU1MI_SUBAy(); +void VU1MI_SUBAz(); +void VU1MI_SUBAw(); +void VU1MI_MUL(); +void VU1MI_MULi(); +void VU1MI_MULq(); +void VU1MI_MULx(); +void VU1MI_MULy(); +void VU1MI_MULz(); +void VU1MI_MULw(); +void VU1MI_MULA(); +void VU1MI_MULAi(); +void VU1MI_MULAq(); +void VU1MI_MULAx(); +void VU1MI_MULAy(); +void VU1MI_MULAz(); +void VU1MI_MULAw(); +void VU1MI_MADD(); +void VU1MI_MADDi(); +void VU1MI_MADDq(); +void VU1MI_MADDx(); +void VU1MI_MADDy(); +void VU1MI_MADDz(); +void VU1MI_MADDw(); +void VU1MI_MADDA(); +void VU1MI_MADDAi(); +void VU1MI_MADDAq(); +void VU1MI_MADDAx(); +void VU1MI_MADDAy(); +void VU1MI_MADDAz(); +void VU1MI_MADDAw(); +void VU1MI_MSUB(); +void VU1MI_MSUBi(); +void VU1MI_MSUBq(); +void VU1MI_MSUBx(); +void VU1MI_MSUBy(); +void VU1MI_MSUBz(); +void VU1MI_MSUBw(); +void VU1MI_MSUBA(); +void VU1MI_MSUBAi(); +void VU1MI_MSUBAq(); +void VU1MI_MSUBAx(); +void VU1MI_MSUBAy(); +void VU1MI_MSUBAz(); +void VU1MI_MSUBAw(); +void VU1MI_MAX(); +void VU1MI_MAXi(); +void VU1MI_MAXx(); +void VU1MI_MAXy(); +void VU1MI_MAXz(); +void VU1MI_MAXw(); +void VU1MI_MINI(); +void VU1MI_MINIi(); +void VU1MI_MINIx(); +void VU1MI_MINIy(); +void VU1MI_MINIz(); +void VU1MI_MINIw(); +void VU1MI_OPMULA(); +void VU1MI_OPMSUB(); +void VU1MI_NOP(); +void VU1MI_FTOI0(); +void VU1MI_FTOI4(); +void VU1MI_FTOI12(); +void VU1MI_FTOI15(); +void VU1MI_ITOF0(); +void VU1MI_ITOF4(); +void VU1MI_ITOF12(); +void VU1MI_ITOF15(); +void VU1MI_CLIP(); + +/***************************************** + VU1 Micromode Lower instructions +*****************************************/ + +void VU1MI_DIV(); +void VU1MI_SQRT(); +void VU1MI_RSQRT(); +void VU1MI_IADD(); +void VU1MI_IADDI(); +void VU1MI_IADDIU(); +void VU1MI_IAND(); +void VU1MI_IOR(); +void VU1MI_ISUB(); +void VU1MI_ISUBIU(); +void VU1MI_MOVE(); +void VU1MI_MFIR(); +void VU1MI_MTIR(); +void VU1MI_MR32(); +void VU1MI_LQ(); +void VU1MI_LQD(); +void VU1MI_LQI(); +void VU1MI_SQ(); +void VU1MI_SQD(); +void VU1MI_SQI(); +void VU1MI_ILW(); +void VU1MI_ISW(); +void VU1MI_ILWR(); +void VU1MI_ISWR(); +void VU1MI_LOI(); +void VU1MI_RINIT(); +void VU1MI_RGET(); +void VU1MI_RNEXT(); +void VU1MI_RXOR(); +void VU1MI_WAITQ(); +void VU1MI_FSAND(); +void VU1MI_FSEQ(); +void VU1MI_FSOR(); +void VU1MI_FSSET(); +void VU1MI_FMAND(); +void VU1MI_FMEQ(); +void VU1MI_FMOR(); +void VU1MI_FCAND(); +void VU1MI_FCEQ(); +void VU1MI_FCOR(); +void VU1MI_FCSET(); +void VU1MI_FCGET(); +void VU1MI_IBEQ(); +void VU1MI_IBGEZ(); +void VU1MI_IBGTZ(); +void VU1MI_IBLTZ(); +void VU1MI_IBLEZ(); +void VU1MI_IBNE(); +void VU1MI_B(); +void VU1MI_BAL(); +void VU1MI_JR(); +void VU1MI_JALR(); +void VU1MI_MFP(); +void VU1MI_WAITP(); +void VU1MI_ESADD(); +void VU1MI_ERSADD(); +void VU1MI_ELENG(); +void VU1MI_ERLENG(); +void VU1MI_EATANxy(); +void VU1MI_EATANxz(); +void VU1MI_ESUM(); +void VU1MI_ERCPR(); +void VU1MI_ESQRT(); +void VU1MI_ERSQRT(); +void VU1MI_ESIN(); +void VU1MI_EATAN(); +void VU1MI_EEXP(); +void VU1MI_XGKICK(); +void VU1MI_XTOP(); +void VU1MI_XITOP(); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU1regsMI_ABS(_VURegsNum *VUregsn); +void VU1regsMI_ADD(_VURegsNum *VUregsn); +void VU1regsMI_ADDi(_VURegsNum *VUregsn); +void VU1regsMI_ADDq(_VURegsNum *VUregsn); +void VU1regsMI_ADDx(_VURegsNum *VUregsn); +void VU1regsMI_ADDy(_VURegsNum *VUregsn); +void VU1regsMI_ADDz(_VURegsNum *VUregsn); +void VU1regsMI_ADDw(_VURegsNum *VUregsn); +void VU1regsMI_ADDA(_VURegsNum *VUregsn); +void VU1regsMI_ADDAi(_VURegsNum *VUregsn); +void VU1regsMI_ADDAq(_VURegsNum *VUregsn); +void VU1regsMI_ADDAx(_VURegsNum *VUregsn); +void VU1regsMI_ADDAy(_VURegsNum *VUregsn); +void VU1regsMI_ADDAz(_VURegsNum *VUregsn); +void VU1regsMI_ADDAw(_VURegsNum *VUregsn); +void VU1regsMI_SUB(_VURegsNum *VUregsn); +void VU1regsMI_SUBi(_VURegsNum *VUregsn); +void VU1regsMI_SUBq(_VURegsNum *VUregsn); +void VU1regsMI_SUBx(_VURegsNum *VUregsn); +void VU1regsMI_SUBy(_VURegsNum *VUregsn); +void VU1regsMI_SUBz(_VURegsNum *VUregsn); +void VU1regsMI_SUBw(_VURegsNum *VUregsn); +void VU1regsMI_SUBA(_VURegsNum *VUregsn); +void VU1regsMI_SUBAi(_VURegsNum *VUregsn); +void VU1regsMI_SUBAq(_VURegsNum *VUregsn); +void VU1regsMI_SUBAx(_VURegsNum *VUregsn); +void VU1regsMI_SUBAy(_VURegsNum *VUregsn); +void VU1regsMI_SUBAz(_VURegsNum *VUregsn); +void VU1regsMI_SUBAw(_VURegsNum *VUregsn); +void VU1regsMI_MUL(_VURegsNum *VUregsn); +void VU1regsMI_MULi(_VURegsNum *VUregsn); +void VU1regsMI_MULq(_VURegsNum *VUregsn); +void VU1regsMI_MULx(_VURegsNum *VUregsn); +void VU1regsMI_MULy(_VURegsNum *VUregsn); +void VU1regsMI_MULz(_VURegsNum *VUregsn); +void VU1regsMI_MULw(_VURegsNum *VUregsn); +void VU1regsMI_MULA(_VURegsNum *VUregsn); +void VU1regsMI_MULAi(_VURegsNum *VUregsn); +void VU1regsMI_MULAq(_VURegsNum *VUregsn); +void VU1regsMI_MULAx(_VURegsNum *VUregsn); +void VU1regsMI_MULAy(_VURegsNum *VUregsn); +void VU1regsMI_MULAz(_VURegsNum *VUregsn); +void VU1regsMI_MULAw(_VURegsNum *VUregsn); +void VU1regsMI_MADD(_VURegsNum *VUregsn); +void VU1regsMI_MADDi(_VURegsNum *VUregsn); +void VU1regsMI_MADDq(_VURegsNum *VUregsn); +void VU1regsMI_MADDx(_VURegsNum *VUregsn); +void VU1regsMI_MADDy(_VURegsNum *VUregsn); +void VU1regsMI_MADDz(_VURegsNum *VUregsn); +void VU1regsMI_MADDw(_VURegsNum *VUregsn); +void VU1regsMI_MADDA(_VURegsNum *VUregsn); +void VU1regsMI_MADDAi(_VURegsNum *VUregsn); +void VU1regsMI_MADDAq(_VURegsNum *VUregsn); +void VU1regsMI_MADDAx(_VURegsNum *VUregsn); +void VU1regsMI_MADDAy(_VURegsNum *VUregsn); +void VU1regsMI_MADDAz(_VURegsNum *VUregsn); +void VU1regsMI_MADDAw(_VURegsNum *VUregsn); +void VU1regsMI_MSUB(_VURegsNum *VUregsn); +void VU1regsMI_MSUBi(_VURegsNum *VUregsn); +void VU1regsMI_MSUBq(_VURegsNum *VUregsn); +void VU1regsMI_MSUBx(_VURegsNum *VUregsn); +void VU1regsMI_MSUBy(_VURegsNum *VUregsn); +void VU1regsMI_MSUBz(_VURegsNum *VUregsn); +void VU1regsMI_MSUBw(_VURegsNum *VUregsn); +void VU1regsMI_MSUBA(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAi(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAq(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAx(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAy(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAz(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAw(_VURegsNum *VUregsn); +void VU1regsMI_MAX(_VURegsNum *VUregsn); +void VU1regsMI_MAXi(_VURegsNum *VUregsn); +void VU1regsMI_MAXx(_VURegsNum *VUregsn); +void VU1regsMI_MAXy(_VURegsNum *VUregsn); +void VU1regsMI_MAXz(_VURegsNum *VUregsn); +void VU1regsMI_MAXw(_VURegsNum *VUregsn); +void VU1regsMI_MINI(_VURegsNum *VUregsn); +void VU1regsMI_MINIi(_VURegsNum *VUregsn); +void VU1regsMI_MINIx(_VURegsNum *VUregsn); +void VU1regsMI_MINIy(_VURegsNum *VUregsn); +void VU1regsMI_MINIz(_VURegsNum *VUregsn); +void VU1regsMI_MINIw(_VURegsNum *VUregsn); +void VU1regsMI_OPMULA(_VURegsNum *VUregsn); +void VU1regsMI_OPMSUB(_VURegsNum *VUregsn); +void VU1regsMI_NOP(_VURegsNum *VUregsn); +void VU1regsMI_FTOI0(_VURegsNum *VUregsn); +void VU1regsMI_FTOI4(_VURegsNum *VUregsn); +void VU1regsMI_FTOI12(_VURegsNum *VUregsn); +void VU1regsMI_FTOI15(_VURegsNum *VUregsn); +void VU1regsMI_ITOF0(_VURegsNum *VUregsn); +void VU1regsMI_ITOF4(_VURegsNum *VUregsn); +void VU1regsMI_ITOF12(_VURegsNum *VUregsn); +void VU1regsMI_ITOF15(_VURegsNum *VUregsn); +void VU1regsMI_CLIP(_VURegsNum *VUregsn); + +/***************************************** + VU1 Micromode Lower instructions +*****************************************/ + +void VU1regsMI_DIV(_VURegsNum *VUregsn); +void VU1regsMI_SQRT(_VURegsNum *VUregsn); +void VU1regsMI_RSQRT(_VURegsNum *VUregsn); +void VU1regsMI_IADD(_VURegsNum *VUregsn); +void VU1regsMI_IADDI(_VURegsNum *VUregsn); +void VU1regsMI_IADDIU(_VURegsNum *VUregsn); +void VU1regsMI_IAND(_VURegsNum *VUregsn); +void VU1regsMI_IOR(_VURegsNum *VUregsn); +void VU1regsMI_ISUB(_VURegsNum *VUregsn); +void VU1regsMI_ISUBIU(_VURegsNum *VUregsn); +void VU1regsMI_MOVE(_VURegsNum *VUregsn); +void VU1regsMI_MFIR(_VURegsNum *VUregsn); +void VU1regsMI_MTIR(_VURegsNum *VUregsn); +void VU1regsMI_MR32(_VURegsNum *VUregsn); +void VU1regsMI_LQ(_VURegsNum *VUregsn); +void VU1regsMI_LQD(_VURegsNum *VUregsn); +void VU1regsMI_LQI(_VURegsNum *VUregsn); +void VU1regsMI_SQ(_VURegsNum *VUregsn); +void VU1regsMI_SQD(_VURegsNum *VUregsn); +void VU1regsMI_SQI(_VURegsNum *VUregsn); +void VU1regsMI_ILW(_VURegsNum *VUregsn); +void VU1regsMI_ISW(_VURegsNum *VUregsn); +void VU1regsMI_ILWR(_VURegsNum *VUregsn); +void VU1regsMI_ISWR(_VURegsNum *VUregsn); +void VU1regsMI_LOI(_VURegsNum *VUregsn); +void VU1regsMI_RINIT(_VURegsNum *VUregsn); +void VU1regsMI_RGET(_VURegsNum *VUregsn); +void VU1regsMI_RNEXT(_VURegsNum *VUregsn); +void VU1regsMI_RXOR(_VURegsNum *VUregsn); +void VU1regsMI_WAITQ(_VURegsNum *VUregsn); +void VU1regsMI_FSAND(_VURegsNum *VUregsn); +void VU1regsMI_FSEQ(_VURegsNum *VUregsn); +void VU1regsMI_FSOR(_VURegsNum *VUregsn); +void VU1regsMI_FSSET(_VURegsNum *VUregsn); +void VU1regsMI_FMAND(_VURegsNum *VUregsn); +void VU1regsMI_FMEQ(_VURegsNum *VUregsn); +void VU1regsMI_FMOR(_VURegsNum *VUregsn); +void VU1regsMI_FCAND(_VURegsNum *VUregsn); +void VU1regsMI_FCEQ(_VURegsNum *VUregsn); +void VU1regsMI_FCOR(_VURegsNum *VUregsn); +void VU1regsMI_FCSET(_VURegsNum *VUregsn); +void VU1regsMI_FCGET(_VURegsNum *VUregsn); +void VU1regsMI_IBEQ(_VURegsNum *VUregsn); +void VU1regsMI_IBGEZ(_VURegsNum *VUregsn); +void VU1regsMI_IBGTZ(_VURegsNum *VUregsn); +void VU1regsMI_IBLTZ(_VURegsNum *VUregsn); +void VU1regsMI_IBLEZ(_VURegsNum *VUregsn); +void VU1regsMI_IBNE(_VURegsNum *VUregsn); +void VU1regsMI_B(_VURegsNum *VUregsn); +void VU1regsMI_BAL(_VURegsNum *VUregsn); +void VU1regsMI_JR(_VURegsNum *VUregsn); +void VU1regsMI_JALR(_VURegsNum *VUregsn); +void VU1regsMI_MFP(_VURegsNum *VUregsn); +void VU1regsMI_WAITP(_VURegsNum *VUregsn); +void VU1regsMI_ESADD(_VURegsNum *VUregsn); +void VU1regsMI_ERSADD(_VURegsNum *VUregsn); +void VU1regsMI_ELENG(_VURegsNum *VUregsn); +void VU1regsMI_ERLENG(_VURegsNum *VUregsn); +void VU1regsMI_EATANxy(_VURegsNum *VUregsn); +void VU1regsMI_EATANxz(_VURegsNum *VUregsn); +void VU1regsMI_ESUM(_VURegsNum *VUregsn); +void VU1regsMI_ERCPR(_VURegsNum *VUregsn); +void VU1regsMI_ESQRT(_VURegsNum *VUregsn); +void VU1regsMI_ERSQRT(_VURegsNum *VUregsn); +void VU1regsMI_ESIN(_VURegsNum *VUregsn); +void VU1regsMI_EATAN(_VURegsNum *VUregsn); +void VU1regsMI_EEXP(_VURegsNum *VUregsn); +void VU1regsMI_XGKICK(_VURegsNum *VUregsn); +void VU1regsMI_XTOP(_VURegsNum *VUregsn); +void VU1regsMI_XITOP(_VURegsNum *VUregsn); + +/***************************************** + VU Micromode Tables/Opcodes defs macros +*****************************************/ + + +#define _vuTables(VU, PREFIX) \ + \ +void (*PREFIX##_LOWER_OPCODE[128])() = { \ + PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ + PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ + PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ + PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_00_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ + PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ + PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_01_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ + PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ + PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_10_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ + PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_11_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ + PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_OPCODE[64])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ + PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ +}; \ + \ + void (*PREFIX##_UPPER_OPCODE[64])() = { \ + PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ + PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ + PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ + PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ + PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ + PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ + PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ + PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ + PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ + PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ + PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ + PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ +}; \ + \ + void (*PREFIX##_UPPER_FD_00_TABLE[32])() = { \ + PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ + PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ + PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_01_TABLE[32])() = { \ + PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ + PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ + PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_10_TABLE[32])() = { \ + PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ + PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ + PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_11_TABLE[32])() = { \ + PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ + PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ + PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + \ + \ + void PREFIX##_UPPER_FD_00() { \ + PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](); \ +} \ + \ + void PREFIX##_UPPER_FD_01() { \ + PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##_UPPER_FD_10() { \ + PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##_UPPER_FD_11() { \ + PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP() { \ + PREFIX##LowerOP_OPCODE[VU.code & 0x3f](); \ +} \ + \ + void PREFIX##LowerOP_T3_00() { \ + PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_01() { \ + PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_10() { \ + PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_11() { \ + PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](); \ +} + +#define _vuRegsTables(VU, PREFIX) \ + \ +void (*PREFIX##_LOWER_OPCODE[128])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ + PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ + PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ + PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_00_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ + PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ + PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_01_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ + PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ + PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_10_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ + PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_11_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ + PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_OPCODE[64])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ + PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ +}; \ + \ + void (*PREFIX##_UPPER_OPCODE[64])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ + PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ + PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ + PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ + PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ + PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ + PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ + PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ + PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ + PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ + PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ + PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ +}; \ + \ + void (*PREFIX##_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ + PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ + PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ + PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ + PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ + PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ + PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ + PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ + PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + \ + \ + void PREFIX##_UPPER_FD_00(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_01(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_10(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_11(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_OPCODE[VU.code & 0x3f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_00(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_01(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_10(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_11(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} + + +#ifdef VUM_LOG + +#define IdebugUPPER(VU) \ + if (Log) { VUM_LOG("%s\n", dis##VU##MicroUF(VU.code, VU.VI[REG_TPC].UL)); } +#define IdebugLOWER(VU) \ + if (Log) { VUM_LOG("%s\n", dis##VU##MicroLF(VU.code, VU.VI[REG_TPC].UL)); } + +#else + +#define IdebugUPPER(VU) +#define IdebugLOWER(VU) + +#endif + +#ifdef VUM_LOG +#define _vuExecMicroDebug(VU) \ + VUM_LOG("_vuExecMicro: %8.8x\n", VU.VI[REG_TPC].UL); +#else +#define _vuExecMicroDebug(VU) +#endif + +#include "VUops.h" + +#endif + diff --git a/pcsx2/VUops.c b/pcsx2/VUops.c new file mode 100644 index 0000000000..dfd126e280 --- /dev/null +++ b/pcsx2/VUops.c @@ -0,0 +1,2957 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define PLUGINtypedefs // for GSgifTransfer1 + +#include +#include +#include "Common.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "VUops.h" +#include "GS.h" + +extern _GSgifTransfer1 GSgifTransfer1; + +//Lower/Upper instructions can use that.. +#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X ((VU->code>>24) & 0x1) +#define _Y ((VU->code>>23) & 0x1) +#define _Z ((VU->code>>22) & 0x1) +#define _W ((VU->code>>21) & 0x1) + +#define _XYZW ((VU->code>>21) & 0xF) + +#define _Fsf_ ((VU->code >> 21) & 0x03) +#define _Ftf_ ((VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + + +VECTOR RDzero; + +void _vuFMACflush(VURegs * VU) { + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { +#ifdef VUM_LOG + if (Log) { VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); } +#endif + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; + } + } +} + +void _vuFDIVflush(VURegs * VU) { + if (VU->fdiv.enable == 0) return; + + if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { +#ifdef VUM_LOG + if (Log) { VUM_LOG("flushing FDIV pipe\n"); } +#endif + VU->fdiv.enable = 0; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; + } +} + +void _vuEFUflush(VURegs * VU) { + if (VU->efu.enable == 0) return; + + if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { +#ifdef VUM_LOG +// if (Log) { VUM_LOG("flushing EFU pipe\n"); } +#endif + VU->efu.enable = 0; + VU->VI[REG_P].UL = VU->efu.reg.UL; + } +} + +// called at end of program +void _vuFlushAll(VURegs* VU) +{ + int nRepeat = 1, i; + + do { + nRepeat = 0; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + nRepeat = 1; + + if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { +#ifdef VUM_LOG + if (Log) { VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); } +#endif + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; + } + } + + if (VU->fdiv.enable ) { + + nRepeat = 1; + + if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { + #ifdef VUM_LOG + if (Log) { VUM_LOG("flushing FDIV pipe\n"); } + #endif + nRepeat = 1; + VU->fdiv.enable = 0; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; + } + } + + if (VU->efu.enable) { + + nRepeat = 1; + + if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { + #ifdef VUM_LOG + // if (Log) { VUM_LOG("flushing EFU pipe\n"); } + #endif + nRepeat = 1; + VU->efu.enable = 0; + VU->VI[REG_P].UL = VU->efu.reg.UL; + } + } + + VU->cycle++; + + } while(nRepeat); +} + +void _vuTestPipes(VURegs * VU) { + _vuFMACflush(VU); + _vuFDIVflush(VU); + _vuEFUflush(VU); +} + +void _vuFMACTestStall(VURegs * VU, int reg, int xyzw) { + int cycle; + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + if (VU->fmac[i].reg == reg && + VU->fmac[i].xyzw & xyzw) break; + } + + if (i == 8) return; + + cycle = VU->fmac[i].Cycle - (VU->cycle - VU->fmac[i].sCycle) + 1; // add 1 delay! (fixes segaclassics bad geom) + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; +#ifdef VUM_LOG + if (Log) { VUM_LOG("FMAC[%d] stall %d\n", i, cycle); } +#endif + VU->cycle+= cycle; + _vuTestPipes(VU); +} + +void _vuFMACAdd(VURegs * VU, int reg, int xyzw) { + int i; + + /* find a free fmac pipe */ + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 1) continue; + break; + } + if (i==8) { +// SysPrintf("*PCSX2*: error , out of fmacs %d\n", VU->cycle); + } + +#ifdef VUM_LOG + if (Log) { VUM_LOG("adding FMAC pipe[%d]; xyzw=%x\n", i, xyzw); } +#endif + VU->fmac[i].enable = 1; + VU->fmac[i].sCycle = VU->cycle; + VU->fmac[i].Cycle = 3; + VU->fmac[i].reg = reg; + VU->fmac[i].xyzw = xyzw; + VU->fmac[i].macflag = VU->macflag; + VU->fmac[i].statusflag = VU->statusflag; + VU->fmac[i].clipflag = VU->clipflag; +} + +void _vuFDIVAdd(VURegs * VU, int cycles) { +#ifdef VUM_LOG + if (Log) { VUM_LOG("adding FDIV pipe\n"); } +#endif + VU->fdiv.enable = 1; + VU->fdiv.sCycle = VU->cycle; + VU->fdiv.Cycle = cycles; + VU->fdiv.reg.F = VU->q.F; + VU->fdiv.statusflag = VU->statusflag; +} + +void _vuEFUAdd(VURegs * VU, int cycles) { +#ifdef VUM_LOG +// if (Log) { VUM_LOG("adding EFU pipe\n"); } +#endif + VU->efu.enable = 1; + VU->efu.sCycle = VU->cycle; + VU->efu.Cycle = cycles; + VU->efu.reg.F = VU->p.F; +} + +void _vuFlushFDIV(VURegs * VU) { + int cycle; + + if (VU->fdiv.enable == 0) return; + + cycle = VU->fdiv.Cycle - (VU->cycle - VU->fdiv.sCycle); +#ifdef VUM_LOG + if (Log) { VUM_LOG("waiting FDIV pipe %d\n", cycle); } +#endif + VU->fdiv.enable = 0; + VU->cycle+= cycle; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; +} + +void _vuFlushEFU(VURegs * VU) { + int cycle; + + if (VU->efu.enable == 0) return; + + cycle = VU->efu.Cycle - (VU->cycle - VU->efu.sCycle); +#ifdef VUM_LOG +// if (Log) { VUM_LOG("waiting EFU pipe %d\n", cycle); } +#endif + VU->efu.enable = 0; + VU->cycle+= cycle; + VU->VI[REG_P].UL = VU->efu.reg.UL; +} + +void _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VFread0) { + _vuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); + } + if (VUregsn->VFread1) { + _vuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); + } +} + +void _vuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VFwrite) { + _vuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); + } else + if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) { + _vuFMACAdd(VU, -REG_CLIP_FLAG, 0); + } else { + _vuFMACAdd(VU, 0, 0); + } +} + +void _vuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _vuFlushFDIV(VU); +} + +void _vuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VIwrite & (1 << REG_Q)) { + _vuFDIVAdd(VU, VUregsn->cycles); + } +} + + +void _vuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _vuFlushEFU(VU); +} + +void _vuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VIwrite & (1 << REG_P)) { + _vuEFUAdd(VU, VUregsn->cycles); + } +} + +void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; + } +} + +void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _vuTestFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _vuTestEFUStalls(VU, VUregsn); break; + } +} + +void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; + } +} + +void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _vuAddFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _vuAddEFUStalls(VU, VUregsn); break; + } +} + + +/******************************/ +/* VU Upper instructions */ +/******************************/ +static u32 d; + +float vuDouble(u32 f) +{ + switch(f & 0x7f800000){ + case 0x0: + f &= 0x80000000; + return *(float*)&f; + break; + case 0x7f800000: + d = (f & 0x80000000)|0x7f7fffff; + return *(float*)&d; + break; + default: + return *(float*)&f; + break; + } +} + +void _vuABS(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X){ VU->VF[_Ft_].f.x = fpufabsf(vuDouble(VU->VF[_Fs_].i.x)); } + if (_Y){ VU->VF[_Ft_].f.y = fpufabsf(vuDouble(VU->VF[_Fs_].i.y)); } + if (_Z){ VU->VF[_Ft_].f.z = fpufabsf(vuDouble(VU->VF[_Fs_].i.z)); } + if (_W){ VU->VF[_Ft_].f.w = fpufabsf(vuDouble(VU->VF[_Fs_].i.w)); } +}/*Reworked from define to function. asadr*/ + + +void _vuADD(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuADDi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_I].UL));} else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_I].UL));} else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_I].UL));} else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_I].UL));} else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuADDx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + fty);} else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + fty);} else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + fty);} else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + fty);} else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ti); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ti); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ti); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ti); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAq(VURegs * VU) { + float tf = vuDouble(VU->VI[REG_Q].UL); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tf); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tf); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tf); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tf); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tx); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tx); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tx); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ty); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ty); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ty); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tz); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tz); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tz); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tw); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tw); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tw); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuSUB(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - fty); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - fty); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - fty); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - fty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + + +void _vuSUBA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAi(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAq(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tx); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tx); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tx); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ty); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ty); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ty); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tz); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tz); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tz); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tw); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tw); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tw); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuMUL(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave I reg in ti. asadr */ +void _vuMULi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + + +void _vuMULy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * fty); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * fty); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * fty); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * fty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + + +void _vuMULA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave I reg in ti. asadr */ +void _vuMULAi(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave Q reg in ti. asadr */ +void _vuMULAq(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave X reg in ti. asadr */ +void _vuMULAx(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAy(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAz(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAw(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMADD(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + + +void _vuMADDi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +/* No need to presave . asadr */ +void _vuMADDq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftx)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftx)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftx)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftx)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * fty)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * fty)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * fty)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * fty)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftz)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftz)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftz)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftz)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftw)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftw)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftw)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftw)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDA(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 10/05/03 shadow*/ + +void _vuMADDAi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * ti)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * ti)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * ti)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * ti)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 10/05/03 shadow*/ + +void _vuMADDAq(VURegs * VU) { + float tq = vuDouble(VU->VI[REG_Q].UL); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * tq)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * tq)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * tq)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * tq)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 10/05/03 shadow*/ + +void _vuMADDAx(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAy(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAz(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAw(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMSUB(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ti ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ti ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ti ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ti ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBq(VURegs * VU) { + float tq = vuDouble(VU->VI[REG_Q].UL); + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tq ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tq ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tq ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tq ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftx ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftx ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftx ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftx ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * fty ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * fty ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * fty ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * fty ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftz ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftz ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftz ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftz ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftw ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftw ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftw ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftw ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBA(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAi(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAq(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tx)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tx)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tx)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tx)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ty)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ty)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ty)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ty)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tz)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tz)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tz)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tz)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tw)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tw)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tw)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tw)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +u32 _MAX(u32 a, u32 b) { + if (a & 0x80000000) { // -a + if (b & 0x80000000) { // -b + return (a & 0x7fffffff) > (b & 0x7fffffff) ? b : a; + } else { // +b + return b; + } + } else { // +a + if (b & 0x80000000) { // -b + return a; + } else { // +b + return (a & 0x7fffffff) > (b & 0x7fffffff) ? a : b; + } + } + + return 0; +} + +void _vuMAX(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); +}//checked 13/05/03 shadow + +void _vuMAXi(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); +}//checked 13/05/03 shadow + +void _vuMAXx(VURegs * VU) { + s32 ftx; + if (_Fd_ == 0) return; + + ftx=(s32)VU->VF[_Ft_].i.x; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftx); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftx); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftx); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftx); +} +//checked 13/05/03 shadow + +void _vuMAXy(VURegs * VU) { + s32 fty; + if (_Fd_ == 0) return; + + fty=(s32)VU->VF[_Ft_].i.y; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, fty); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, fty); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, fty); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, fty); +}//checked 13/05/03 shadow + +void _vuMAXz(VURegs * VU) { + s32 ftz; + if (_Fd_ == 0) return; + + ftz=(s32)VU->VF[_Ft_].i.z; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftz); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftz); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftz); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftz); +} + +void _vuMAXw(VURegs * VU) { + s32 ftw; + if (_Fd_ == 0) return; + + ftw=(s32)VU->VF[_Ft_].i.w; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftw); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftw); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftw); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftw); +} + +u32 _MINI(u32 a, u32 b) { + if (a & 0x80000000) { // -a + if (b & 0x80000000) { // -b + return (a & 0x7fffffff) < (b & 0x7fffffff) ? b : a; + } else { // +b + return a; + } + } else { // +a + if (b & 0x80000000) { // -b + return b; + } else { // +b + return (a & 0x7fffffff) < (b & 0x7fffffff) ? a : b; + } + } + + return 0; +} + +void _vuMINI(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); +}//checked 13/05/03 shadow + +void _vuMINIi(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); +}//checked 13/05/03 shadow + +void _vuMINIx(VURegs * VU) { + s32 ftx; + if (_Fd_ == 0) return; + + ftx=(s32)VU->VF[_Ft_].i.x; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftx); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftx); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftx); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftx); +} +//checked 13/05/03 shadow + +void _vuMINIy(VURegs * VU) { + s32 fty; + if (_Fd_ == 0) return; + + fty=(s32)VU->VF[_Ft_].i.y; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, fty); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, fty); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, fty); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, fty); +}//checked 13/05/03 shadow + +void _vuMINIz(VURegs * VU) { + s32 ftz; + if (_Fd_ == 0) return; + + ftz=(s32)VU->VF[_Ft_].i.z; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftz); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftz); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftz); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftz); +} + +void _vuMINIw(VURegs * VU) { + s32 ftw; + if (_Fd_ == 0) return; + + ftw=(s32)VU->VF[_Ft_].i.w; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftw); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftw); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftw); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftw); +} + +void _vuOPMULA(VURegs * VU) { + VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); + VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); + VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); + VU_STAT_UPDATE(VU); +}/*last updated 8/05/03 shadow*/ + +void _vuOPMSUB(VURegs * VU) { + VECTOR * dst; + float ftx, fty, ftz; + float fsx, fsy, fsz; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx = vuDouble(VU->VF[_Ft_].i.x); fty = vuDouble(VU->VF[_Ft_].i.y); ftz = vuDouble(VU->VF[_Ft_].i.z); + fsx = vuDouble(VU->VF[_Fs_].i.x); fsy = vuDouble(VU->VF[_Fs_].i.y); fsz = vuDouble(VU->VF[_Fs_].i.z); + dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - fsy * ftz); + dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - fsz * ftx); + dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - fsx * fty); + VU_STAT_UPDATE(VU); +}/*last updated 8/05/03 shadow*/ + +void _vuNOP(VURegs * VU) { +} + +void _vuFTOI0(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = (s32)vuDouble(VU->VF[_Fs_].i.x); + if (_Y) VU->VF[_Ft_].SL[1] = (s32)vuDouble(VU->VF[_Fs_].i.y); + if (_Z) VU->VF[_Ft_].SL[2] = (s32)vuDouble(VU->VF[_Fs_].i.z); + if (_W) VU->VF[_Ft_].SL[3] = (s32)vuDouble(VU->VF[_Fs_].i.w); +} + +void _vuFTOI4(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int4(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int4(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int4(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int4(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuFTOI12(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int12(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int12(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int12(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int12(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuFTOI15(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int15(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int15(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int15(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int15(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuITOF0(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = (float)VU->VF[_Fs_].SL[0]; + if (_Y) VU->VF[_Ft_].f.y = (float)VU->VF[_Fs_].SL[1]; + if (_Z) VU->VF[_Ft_].f.z = (float)VU->VF[_Fs_].SL[2]; + if (_W) VU->VF[_Ft_].f.w = (float)VU->VF[_Fs_].SL[3]; +} + +void _vuITOF4(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int4_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int4_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int4_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int4_to_float(VU->VF[_Fs_].SL[3]); +} + +void _vuITOF12(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int12_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int12_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int12_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int12_to_float(VU->VF[_Fs_].SL[3]); +} + +void _vuITOF15(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int15_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int15_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int15_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int15_to_float(VU->VF[_Fs_].SL[3]); +} + +/* Different type of clipping by presaving w. asadr */ +void _vuCLIP(VURegs * VU) { + float value = fpufabsf(vuDouble(VU->VF[_Ft_].i.w)); + + VU->clipflag <<= 6; + if ( vuDouble(VU->VF[_Fs_].i.x) > +value ) VU->clipflag|= 0x01; + if ( vuDouble(VU->VF[_Fs_].i.x) < -value ) VU->clipflag|= 0x02; + if ( vuDouble(VU->VF[_Fs_].i.y) > +value ) VU->clipflag|= 0x04; + if ( vuDouble(VU->VF[_Fs_].i.y) < -value ) VU->clipflag|= 0x08; + if ( vuDouble(VU->VF[_Fs_].i.z) > +value ) VU->clipflag|= 0x10; + if ( vuDouble(VU->VF[_Fs_].i.z) < -value ) VU->clipflag|= 0x20; + VU->clipflag = VU->clipflag & 0xFFFFFF; + VU->VI[REG_CLIP_FLAG].UL = VU->clipflag; + + +}/*last update 16/07/05 refraction - Needs checking */ + + +/******************************/ +/* VU Lower instructions */ +/******************************/ + +void _vuDIV(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + +// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if (ft == 0.0) { + if (fs == 0.0) { + VU->statusflag |= 0x10; + } else { + VU->statusflag |= 0x20; + } + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0xFF7FFFFF; + } else { + VU->q.UL = 0x7F7FFFFF; + } + } else { + VU->q.F = fs / ft; + VU->q.F = vuDouble(VU->q.UL); + } +} //last update 15/01/06 zerofrog + +void _vuSQRT(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + +// _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if (ft < 0.0 ) + VU->statusflag |= 0x10; + VU->q.F = fpusqrtf(fpufabsf(ft)); + VU->q.F = vuDouble(VU->q.UL); +} //last update 15/01/06 zerofrog + + +/* Eminent Bug - Dvisior == 0 Check Missing ( D Flag Not Set ) */ +/* REFIXED....ASADR; rerefixed....zerofrog */ +void _vuRSQRT(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + float temp; + +// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if ( ft == 0.0 ) { + VU->statusflag |= 0x20; + + if( fs != 0 ) { + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0xFF7FFFFF; + } else { + VU->q.UL = 0x7F7FFFFF; + } + } + else { + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0x80000000; + } else { + VU->q.UL = 0; + } + + VU->statusflag |= 0x10; + } + + } else { + if (ft < 0.0) { + VU->statusflag |= 0x10; + } + + temp = fpusqrtf(fpufabsf(ft)); + VU->q.F = fs / temp; + VU->q.F = vuDouble(VU->q.UL); + } +} //last update 15/01/06 zerofrog + + +void _vuIADDI(VURegs * VU) { + s16 imm = ((VU->code >> 6) & 0x1f); + imm = ((imm & 0x10 ? 0xfff0 : 0) | (imm & 0xf)); + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + imm; +}//last checked 17/05/03 shadow NOTE: not quite sure about that + +void _vuIADDIU(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); +}//last checked 17/05/03 shadow + +void _vuIADD(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] + VU->VI[_Ft_].SS[0]; +}//last checked 17/05/03 shadow + +void _vuIAND(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] & VU->VI[_Ft_].US[0]; +}//last checked 17/05/03 shadow + +void _vuIOR(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] | VU->VI[_Ft_].US[0]; +} + +void _vuISUB(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] - VU->VI[_Ft_].SS[0]; +} + +void _vuISUBIU(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] - (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); +} + +void _vuMOVE(VURegs * VU) { + if(_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].UL[0] = VU->VF[_Fs_].UL[0]; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VF[_Fs_].UL[1]; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VF[_Fs_].UL[2]; + if (_W) VU->VF[_Ft_].UL[3] = VU->VF[_Fs_].UL[3]; +}//last checked 17/05/03 shadow + +void _vuMFIR(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = (s32)VU->VI[_Fs_].SS[0]; + if (_Y) VU->VF[_Ft_].SL[1] = (s32)VU->VI[_Fs_].SS[0]; + if (_Z) VU->VF[_Ft_].SL[2] = (s32)VU->VI[_Fs_].SS[0]; + if (_W) VU->VF[_Ft_].SL[3] = (s32)VU->VI[_Fs_].SS[0]; +} + +// Big bug!!! mov from fs to ft not ft to fs. asadr +void _vuMTIR(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = *(u16*)&VU->VF[_Fs_].F[_Fsf_]; +} + +void _vuMR32(VURegs * VU) { + u32 tx; + if (_Ft_ == 0) return; + + tx = VU->VF[_Fs_].i.x; + if (_X) VU->VF[_Ft_].i.x = VU->VF[_Fs_].i.y; + if (_Y) VU->VF[_Ft_].i.y = VU->VF[_Fs_].i.z; + if (_Z) VU->VF[_Ft_].i.z = VU->VF[_Fs_].i.w; + if (_W) VU->VF[_Ft_].i.w = tx; +}//last updated 23/10/03 linuzappz + +void _vuLQ(VURegs * VU) { + s16 imm; + u16 addr; + u32 *ptr; + + if (_Ft_ == 0) return; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; +} + +void _vuLQD( VURegs * VU ) { + u32 addr; + u32 *ptr; + + if (_Fs_ != 0) VU->VI[_Fs_].US[0]--; + if (_Ft_ == 0) return; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; +} + +void _vuLQI(VURegs * VU) { + if (_Ft_) { + u32 addr; + u32 *ptr; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; + } + if (_Fs_ != 0) VU->VI[_Fs_].US[0]++; +} + +/* addr is now signed. Asadr */ +void _vuSQ(VURegs * VU) { + s16 imm; + u16 addr; + u32 *ptr; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Ft_].SS[0]) * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; +} + +void _vuSQD(VURegs * VU) { + u32 addr; + u32 *ptr; + + if(_Ft_ != 0) VU->VI[_Ft_].US[0]--; + addr = VU->VI[_Ft_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; +} + +void _vuSQI(VURegs * VU) { + u32 addr; + u32 *ptr; + + addr = VU->VI[_Ft_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; + if(_Ft_ != 0) VU->VI[_Ft_].US[0]++; +} + +/* addr now signed. asadr */ +void _vuILW(VURegs * VU) { + s16 imm; + u16 addr; + u16 *ptr; + if (_Ft_ == 0) return; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) VU->VI[_Ft_].US[0] = ptr[0]; + if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; + if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; + if (_W) VU->VI[_Ft_].US[0] = ptr[6]; +} + +void _vuISW(VURegs * VU) { + s16 imm; + u16 addr; + u16 *ptr; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } + if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } + if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } + if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } +} + +void _vuILWR(VURegs * VU) { + u32 addr; + u16 *ptr; + if (_Ft_ == 0) return; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) VU->VI[_Ft_].US[0] = ptr[0]; + if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; + if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; + if (_W) VU->VI[_Ft_].US[0] = ptr[6]; +} + +void _vuISWR(VURegs * VU) { + u32 addr; + u16 *ptr; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } + if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } + if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } + if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } +} + +/* code contributed by _Riff_ + +The following code implements a Galois form M-series LFSR that can be configured to have a width from 0 to 32. +A Galois field can be represented as G(X) = g_m * X^m + g_(m-1) * X^(m-1) + ... + g_1 * X^1 + g0. +A Galois form M-Series LFSR represents a Galois field where g0 = g_m = 1 and the generated set contains 2^M - 1 values. +In modulo-2 arithmetic, addition is replaced by XOR and multiplication is replaced by AND. +The code is written in such a way that the polynomial lsb (g0) should be set to 0 and g_m is not represented. +As an example for setting the polynomial variable correctly, the 23-bit M-series generating polynomial X^23+X^14 + would be specified as (1 << 14). +*/ + + +//The two-tap 23 stage M-series polynomials are x23+x18 and x23+x14 ((1 << 18) and (1 << 14), respectively). +//The reverse sequences can be generated by x23+x(23-18) and x23+x(23-14) ((1 << 9) and (1 << 5), respectively) +u32 poly = 1 << 5; + +void SetPoly(u32 newPoly) { + poly = poly & ~1; +} + +void AdvanceLFSR(VURegs * VU) { + // code from www.project-fao.org + int x = (VU->VI[REG_R].UL >> 4) & 1; + int y = (VU->VI[REG_R].UL >> 22) & 1; + VU->VI[REG_R].UL <<= 1; + VU->VI[REG_R].UL ^= x ^ y; + VU->VI[REG_R].UL = (VU->VI[REG_R].UL&0x7fffff)|0x3f800000; +} +// old +// u32 lfsr = VU->VI[REG_R].UL & 0x007FFFFF; +// u32 oldlfsr = lfsr; +// lfsr <<= 1; +// if (oldlfsr & 0x00400000) { +// lfsr ^= poly; +// lfsr |= 1; +// } +// +// VU->VI[REG_R].UL = 0x3F800000 | (lfsr & 0x007FFFFF); + +void _vuRINIT(VURegs * VU) { + VU->VI[REG_R].UL = 0x3F800000 | (VU->VF[_Fs_].UL[_Fsf_] & 0x007FFFFF); +} + +void _vuRGET(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; + if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; +} + +void _vuRNEXT(VURegs * VU) { + if (_Ft_ == 0) return; + AdvanceLFSR(VU); + if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; + if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; +} + +void _vuRXOR(VURegs * VU) { + VU->VI[REG_R].UL = 0x3F800000 | ((VU->VI[REG_R].UL ^ VU->VF[_Fs_].UL[_Fsf_]) & 0x007FFFFF); +} + +void _vuWAITQ(VURegs * VU) { +} + +void _vuFSAND(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) & imm; +} + +void _vuFSEQ(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + if((VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) == imm) VU->VI[_Ft_].US[0] = 1; + else VU->VI[_Ft_].US[0] = 0; +} + +void _vuFSOR(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) | imm; +} + +void _vuFSSET(VURegs * VU) { + u16 imm = 0; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); + VU->statusflag = (imm & 0xFC0) | (VU->VI[REG_STATUS_FLAG].US[0] & 0x3F); +} + +void _vuFMAND(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->VI[_Fs_].US[0] & (VU->VI[REG_MAC_FLAG].UL & 0xFFFF); +} + +void _vuFMEQ(VURegs * VU) { + if(_Ft_ == 0) return; + if((VU->VI[REG_MAC_FLAG].UL & 0xFFFF) == VU->VI[_Fs_].US[0]){ + VU->VI[_Ft_].US[0] =1;} else { VU->VI[_Ft_].US[0] =0; } +} + +void _vuFMOR(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_MAC_FLAG].UL & 0xFFFF) | VU->VI[_Fs_].US[0]; +} + +void _vuFCAND(VURegs * VU) { + if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) & (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCEQ(VURegs * VU) { + if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) == (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCOR(VURegs * VU) { + u32 hold = (VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) | ( VU->code & 0xFFFFFF); + if(hold == 0xFFFFFF) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCSET(VURegs * VU) { + VU->clipflag = (u32) (VU->code & 0xFFFFFF); + VU->VI[REG_CLIP_FLAG].UL = (u32) (VU->code & 0xFFFFFF); +} + +void _vuFCGET(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->VI[REG_CLIP_FLAG].UL & 0x0FFF; +} + +s32 _branchAddr(VURegs * VU) { + s32 bpc = VU->VI[REG_TPC].SL + _Imm11_ * 8; + if (bpc < 0) { + bpc = VU->VI[REG_TPC].SL + _UImm11_ * 8; + } + if (VU == &VU1) { + bpc&= 0x3fff; + } else { + bpc&= 0x0fff; + } + + return bpc; +} + +void _setBranch(VURegs * VU, u32 bpc) { + VU->branch = 2; + VU->branchpc = bpc; +// VU->vuExec(VU); +// VU->VI[REG_TPC].UL = bpc; +} + +void _vuIBEQ(VURegs * VU) { + if (VU->VI[_Ft_].US[0] == VU->VI[_Fs_].US[0]) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBGEZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] >= 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBGTZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] > 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBLEZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] <= 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBLTZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] < 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBNE(VURegs * VU) { + if (VU->VI[_Ft_].US[0] != VU->VI[_Fs_].US[0]) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuB(VURegs * VU) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); +} + +void _vuBAL(VURegs * VU) { + s32 bpc = _branchAddr(VU); + + if (_Ft_) { + VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; + } + + _setBranch(VU, bpc); +} + +void _vuJR(VURegs * VU) { + u32 bpc = VU->VI[_Fs_].US[0] * 8; + _setBranch(VU, bpc); +} + +void _vuJALR(VURegs * VU) { + u32 bpc = VU->VI[_Fs_].US[0] * 8; + if (_Ft_) { + VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; + } + + _setBranch(VU, bpc); +} + +void _vuMFP(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].i.x = VU->VI[REG_P].UL; + if (_Y) VU->VF[_Ft_].i.y = VU->VI[REG_P].UL; + if (_Z) VU->VF[_Ft_].i.z = VU->VI[REG_P].UL; + if (_W) VU->VF[_Ft_].i.w = VU->VI[REG_P].UL; +} + +void _vuWAITP(VURegs * VU) { +} + +void _vuESADD(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + VU->p.F = p; +} + +void _vuERSADD(VURegs * VU) { + float p = (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x)) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y)) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z)); + if (p != 0.0) + p = 1.0f / p; + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to value being -ve for sqrt *asadr */ +void _vuELENG(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + if(p >= 0){ + p = fpusqrtf(p); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERLENG(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + if (p >= 0) { + p = fpusqrtf(p); + if (p != 0) { + p = 1.0f / p; + } + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuEATANxy(VURegs * VU) { + float p = 0; + if(vuDouble(VU->VF[_Fs_].i.x) != 0) { + p = fpuatan2f(vuDouble(VU->VF[_Fs_].i.y), vuDouble(VU->VF[_Fs_].i.x)); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuEATANxz(VURegs * VU) { + float p = 0; + if(vuDouble(VU->VF[_Fs_].i.x) != 0) { + p = fpuatan2f(vuDouble(VU->VF[_Fs_].i.z), vuDouble(VU->VF[_Fs_].i.x)); + } + VU->p.F = p; +} + +void _vuESUM(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Fs_].i.w); + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERCPR(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p != 0){ + p = 1.0 / p; + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to Value being -ve for sqrt *asadr */ +void _vuESQRT(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p >= 0){ + p = fpusqrtf(p); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERSQRT(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p >= 0) { + p = fpusqrtf(p); + if (p) { + p = 1.0f / p; + } + } + VU->p.F = p; +} + +void _vuESIN(VURegs * VU) { + float p = fpusinf(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); + VU->p.F = p; +} + +void _vuEATAN(VURegs * VU) { + float p = fpuatanf(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); + VU->p.F = p; +} + +void _vuEEXP(VURegs * VU) { + float p = fpuexpf(-(vuDouble(VU->VF[_Fs_].UL[_Fsf_]))); + VU->p.F = p; +} + +void _vuXITOP(VURegs * VU) { + if (_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->vifRegs->itop; +} + +//extern u32 vudump; +//static void countfn() +//{ +// static int scount = 0; +// scount++; +// +// if( scount > 56 ) { +// __Log("xgkick %d\n", scount); +// vudump |= 8; +// } +//} + +void _vuXGKICK(VURegs * VU) +{ + // flush all pipelines first (in the right order) + _vuFlushAll(VU); + //countfn(); + GSGIFTRANSFER1((u32*)VU->Mem, (VU->VI[_Fs_].US[0]*16) & 0x3fff); +} + +void _vuXTOP(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (u16)VU->vifRegs->top; +} + +#define GET_VF0_FLAG(reg) (((reg)==0)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1 << REG_I)|(ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1 << REG_Q)|(ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= _XYZW; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = (1<VIread = (1 << REG_I)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = (1<VIread = (1 << REG_Q)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= _XYZW; \ + VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Ft_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VFr1xyzw = 0xff; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (_Ft_ ? GET_VF0_FLAG(_Fs_) : 0); \ +} + +#define VUREGS_IDISIT(OP) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_IALU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << _Fd_; \ + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); \ +} + +#define VUREGS_ITIS(OP) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_IALU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << _Ft_; \ + VUregsn->VIread = 1 << _Fs_; \ +} + +#define VUREGS_PFS(OP, _cycles) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_EFU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << REG_P; \ + VUregsn->VIread = GET_VF0_FLAG(_Fs_); \ + VUregsn->cycles = _cycles; \ +} + + + +VUREGS_FTFS(ABS); + +VUREGS_FDFSFT(ADD, 0); +VUREGS_FDFSI(ADDi, 0); +VUREGS_FDFSQ(ADDq, 0); +VUREGS_FDFSFTx(ADDx, 0); +VUREGS_FDFSFTy(ADDy, 0); +VUREGS_FDFSFTz(ADDz, 0); +VUREGS_FDFSFTw(ADDw, 0); + +VUREGS_ACCFSFT(ADDA, 0); +VUREGS_ACCFSI(ADDAi, 0); +VUREGS_ACCFSQ(ADDAq, 0); +VUREGS_ACCFSFTx(ADDAx, 0); +VUREGS_ACCFSFTy(ADDAy, 0); +VUREGS_ACCFSFTz(ADDAz, 0); +VUREGS_ACCFSFTw(ADDAw, 0); + +VUREGS_FDFSFT(SUB, 0); +VUREGS_FDFSI(SUBi, 0); +VUREGS_FDFSQ(SUBq, 0); +VUREGS_FDFSFTx(SUBx, 0); +VUREGS_FDFSFTy(SUBy, 0); +VUREGS_FDFSFTz(SUBz, 0); +VUREGS_FDFSFTw(SUBw, 0); + +VUREGS_ACCFSFT(SUBA, 0); +VUREGS_ACCFSI(SUBAi, 0); +VUREGS_ACCFSQ(SUBAq, 0); +VUREGS_ACCFSFTx(SUBAx, 0); +VUREGS_ACCFSFTy(SUBAy, 0); +VUREGS_ACCFSFTz(SUBAz, 0); +VUREGS_ACCFSFTw(SUBAw, 0); + +#define VUREGS_FDFSFTxyzw_MUL(OP, ACC, xyzw) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + if( _Ft_ == 0 && xyzw > 1 && _XYZW == 0xf ) { /* resetting to 0 */ \ + VUregsn->pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = ACC?0:_Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (ACC?(1<VIread = (ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = ACC?0:_Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (ACC?(1<VIread = GET_VF0_FLAG(_Fs_)|((ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Fd_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFwxyzw= 0xE; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0xE; + VUregsn->VIwrite = 1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Fd_; + VUregsn->VFwxyzw= 0xE; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0xE; + VUregsn->VIwrite = 0; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_NONE; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +VUREGS_FTFS(FTOI0); +VUREGS_FTFS(FTOI4); +VUREGS_FTFS(FTOI12); +VUREGS_FTFS(FTOI15); +VUREGS_FTFS(ITOF0); +VUREGS_FTFS(ITOF4); +VUREGS_FTFS(ITOF12); +VUREGS_FTFS(ITOF15); + +void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0x1; + VUregsn->VIwrite = 1 << REG_CLIP_FLAG; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1 << REG_CLIP_FLAG); +} + +/******************************/ +/* VU Lower instructions */ +/******************************/ + +void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 6; +} + +void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFr0xyzw = 0; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw = 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 6; +} + +void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 12; +} + +VUREGS_ITIS(IADDI); +VUREGS_ITIS(IADDIU); +VUREGS_IDISIT(IADD); +VUREGS_IDISIT(IAND); +VUREGS_IDISIT(IOR); +VUREGS_IDISIT(ISUB); +VUREGS_ITIS(ISUBIU); + +VUREGS_FTFS(MOVE); + +void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = GET_VF0_FLAG(_Fs_); +} + +VUREGS_FTFS(MR32); + +void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Fs_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Fs_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = (1 << _Ft_); + VUregsn->VIread = (1 << _Fs_); +} + +void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = GET_VF0_FLAG(_Fs_); +} + +void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << REG_R; +} + +void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = 1 << REG_R; +} + +void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = (1 << REG_R)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_STATUS_FLAG; + VUregsn->VIread = 0;//1 << REG_STATUS_FLAG; this kills speed +} + +void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_CLIP_FLAG; + VUregsn->VIread = 0; +} + +void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} + +void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << REG_P; +} + +void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_EFU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +VUREGS_PFS(ESADD, 10); +VUREGS_PFS(ERSADD, 17); +VUREGS_PFS(ELENG, 17); +VUREGS_PFS(ERLENG, 23); +VUREGS_PFS(EATANxy, 53); +VUREGS_PFS(EATANxz, 53); +VUREGS_PFS(ESUM, 11); +VUREGS_PFS(ERCPR, 11); +VUREGS_PFS(ESQRT, 11); +VUREGS_PFS(ERSQRT, 17); +VUREGS_PFS(ESIN, 28); +VUREGS_PFS(EATAN, 53); +VUREGS_PFS(EEXP, 43); + +void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} + +void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_XGKICK; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} diff --git a/pcsx2/VUops.h b/pcsx2/VUops.h new file mode 100644 index 0000000000..e8650a1771 --- /dev/null +++ b/pcsx2/VUops.h @@ -0,0 +1,393 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VU1OPS_H__ +#define __VU1OPS_H__ + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +#include "VU.h" + +#define float_to_int4(x) (s32)((float)x * (1.0f / 0.0625f)) +#define float_to_int12(x) (s32)((float)x * (1.0f / 0.000244140625f)) +#define float_to_int15(x) (s32)((float)x * (1.0f / 0.000030517578125)) + +#define int4_to_float(x) (float)((float)x * 0.0625f) +#define int12_to_float(x) (float)((float)x * 0.000244140625f) +#define int15_to_float(x) (float)((float)x * 0.000030517578125) + +#define MAC_Reset( VU ) VU->VI[REG_MAC_FLAG].UL = VU->VI[REG_MAC_FLAG].UL & (~0xFFFF) + +void _vuSetCycleFlags(VURegs * VU); +void _vuFlushFDIV(VURegs * VU); +void _vuFlushEFU(VURegs * VU); +void _vuTestPipes(VURegs * VU); +void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); + +/******************************/ +/* VU Upper instructions */ +/******************************/ + +void _vuABS(VURegs * VU); +void _vuADD(VURegs * VU); +void _vuADDi(VURegs * VU); +void _vuADDq(VURegs * VU); +void _vuADDx(VURegs * VU); +void _vuADDy(VURegs * VU); +void _vuADDz(VURegs * VU); +void _vuADDw(VURegs * VU); +void _vuADDA(VURegs * VU); +void _vuADDAi(VURegs * VU); +void _vuADDAq(VURegs * VU); +void _vuADDAx(VURegs * VU); +void _vuADDAy(VURegs * VU); +void _vuADDAz(VURegs * VU); +void _vuADDAw(VURegs * VU); +void _vuSUB(VURegs * VU); +void _vuSUBi(VURegs * VU); +void _vuSUBq(VURegs * VU); +void _vuSUBx(VURegs * VU); +void _vuSUBy(VURegs * VU); +void _vuSUBz(VURegs * VU); +void _vuSUBw(VURegs * VU); +void _vuSUBA(VURegs * VU); +void _vuSUBAi(VURegs * VU); +void _vuSUBAq(VURegs * VU); +void _vuSUBAx(VURegs * VU); +void _vuSUBAy(VURegs * VU); +void _vuSUBAz(VURegs * VU); +void _vuSUBAw(VURegs * VU); +void _vuMUL(VURegs * VU); +void _vuMULi(VURegs * VU); +void _vuMULq(VURegs * VU); +void _vuMULx(VURegs * VU); +void _vuMULy(VURegs * VU); +void _vuMULz(VURegs * VU); +void _vuMULw(VURegs * VU); +void _vuMULA(VURegs * VU); +void _vuMULAi(VURegs * VU); +void _vuMULAq(VURegs * VU); +void _vuMULAx(VURegs * VU); +void _vuMULAy(VURegs * VU); +void _vuMULAz(VURegs * VU); +void _vuMULAw(VURegs * VU); +void _vuMADD(VURegs * VU) ; +void _vuMADDi(VURegs * VU); +void _vuMADDq(VURegs * VU); +void _vuMADDx(VURegs * VU); +void _vuMADDy(VURegs * VU); +void _vuMADDz(VURegs * VU); +void _vuMADDw(VURegs * VU); +void _vuMADDA(VURegs * VU); +void _vuMADDAi(VURegs * VU); +void _vuMADDAq(VURegs * VU); +void _vuMADDAx(VURegs * VU); +void _vuMADDAy(VURegs * VU); +void _vuMADDAz(VURegs * VU); +void _vuMADDAw(VURegs * VU); +void _vuMSUB(VURegs * VU); +void _vuMSUBi(VURegs * VU); +void _vuMSUBq(VURegs * VU); +void _vuMSUBx(VURegs * VU); +void _vuMSUBy(VURegs * VU); +void _vuMSUBz(VURegs * VU) ; +void _vuMSUBw(VURegs * VU) ; +void _vuMSUBA(VURegs * VU); +void _vuMSUBAi(VURegs * VU); +void _vuMSUBAq(VURegs * VU); +void _vuMSUBAx(VURegs * VU); +void _vuMSUBAy(VURegs * VU); +void _vuMSUBAz(VURegs * VU); +void _vuMSUBAw(VURegs * VU); +void _vuMAX(VURegs * VU); +void _vuMAXi(VURegs * VU); +void _vuMAXx(VURegs * VU); +void _vuMAXy(VURegs * VU); +void _vuMAXz(VURegs * VU); +void _vuMAXw(VURegs * VU); +void _vuMINI(VURegs * VU); +void _vuMINIi(VURegs * VU); +void _vuMINIx(VURegs * VU); +void _vuMINIy(VURegs * VU); +void _vuMINIz(VURegs * VU); +void _vuMINIw(VURegs * VU); +void _vuOPMULA(VURegs * VU); +void _vuOPMSUB(VURegs * VU); +void _vuNOP(VURegs * VU); +void _vuFTOI0(VURegs * VU); +void _vuFTOI4(VURegs * VU); +void _vuFTOI12(VURegs * VU); +void _vuFTOI15(VURegs * VU); +void _vuITOF0(VURegs * VU) ; +void _vuITOF4(VURegs * VU) ; +void _vuITOF12(VURegs * VU); +void _vuITOF15(VURegs * VU); +void _vuCLIP(VURegs * VU); +/******************************/ +/* VU Lower instructions */ +/******************************/ +void _vuDIV(VURegs * VU); +void _vuSQRT(VURegs * VU); +void _vuRSQRT(VURegs * VU); +void _vuIADDI(VURegs * VU); +void _vuIADDIU(VURegs * VU); +void _vuIADD(VURegs * VU); +void _vuIAND(VURegs * VU); +void _vuIOR(VURegs * VU); +void _vuISUB(VURegs * VU); +void _vuISUBIU(VURegs * VU); +void _vuMOVE(VURegs * VU); +void _vuMFIR(VURegs * VU); +void _vuMTIR(VURegs * VU); +void _vuMR32(VURegs * VU); +void _vuLQ(VURegs * VU) ; +void _vuLQD(VURegs * VU); +void _vuLQI(VURegs * VU); +void _vuSQ(VURegs * VU); +void _vuSQD(VURegs * VU); +void _vuSQI(VURegs * VU); +void _vuILW(VURegs * VU); +void _vuISW(VURegs * VU); +void _vuILWR(VURegs * VU); +void _vuISWR(VURegs * VU); +void _vuLOI(VURegs * VU); +void _vuRINIT(VURegs * VU); +void _vuRGET(VURegs * VU); +void _vuRNEXT(VURegs * VU); +void _vuRXOR(VURegs * VU); +void _vuWAITQ(VURegs * VU); +void _vuFSAND(VURegs * VU); +void _vuFSEQ(VURegs * VU); +void _vuFSOR(VURegs * VU); +void _vuFSSET(VURegs * VU); +void _vuFMAND(VURegs * VU); +void _vuFMEQ(VURegs * VU); +void _vuFMOR(VURegs * VU); +void _vuFCAND(VURegs * VU); +void _vuFCEQ(VURegs * VU); +void _vuFCOR(VURegs * VU); +void _vuFCSET(VURegs * VU); +void _vuFCGET(VURegs * VU); +void _vuIBEQ(VURegs * VU); +void _vuIBGEZ(VURegs * VU); +void _vuIBGTZ(VURegs * VU); +void _vuIBLEZ(VURegs * VU); +void _vuIBLTZ(VURegs * VU); +void _vuIBNE(VURegs * VU); +void _vuB(VURegs * VU); +void _vuBAL(VURegs * VU); +void _vuJR(VURegs * VU); +void _vuJALR(VURegs * VU); +void _vuMFP(VURegs * VU); +void _vuWAITP(VURegs * VU); +void _vuESADD(VURegs * VU); +void _vuERSADD(VURegs * VU); +void _vuELENG(VURegs * VU); +void _vuERLENG(VURegs * VU); +void _vuEATANxy(VURegs * VU); +void _vuEATANxz(VURegs * VU); +void _vuESUM(VURegs * VU); +void _vuERCPR(VURegs * VU); +void _vuESQRT(VURegs * VU); +void _vuERSQRT(VURegs * VU); +void _vuESIN(VURegs * VU); +void _vuEATAN(VURegs * VU); +void _vuEEXP(VURegs * VU); +void _vuXITOP(VURegs * VU); +void _vuXGKICK(VURegs * VU); +void _vuXTOP(VURegs * VU); + +/******************************/ +/* VU Upper instructions */ +/******************************/ + +void _vuRegsABS(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMUL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAX(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsOPMULA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsOPMSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsNOP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI0(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI4(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI12(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI15(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF0(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF4(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF12(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF15(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn); +/******************************/ +/* VU Lower instructions */ +/******************************/ +void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADDI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADDIU(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISUBIU(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMOVE(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMR32(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLOI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERSADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsELENG(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERLENG(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATANxy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATANxz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESUM(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERCPR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESIN(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATAN(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEEXP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn); + +#endif diff --git a/pcsx2/Vif.c b/pcsx2/Vif.c new file mode 100644 index 0000000000..2a4acbe45e --- /dev/null +++ b/pcsx2/Vif.c @@ -0,0 +1,647 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "Common.h" +#include "ix86/ix86.h" +#include "Vif.h" +#include "VUmicro.h" + +#include + +VIFregisters *_vifRegs; +u32* _vifMaskRegs = NULL; +PCSX2_ALIGNED16(u32 g_vifRow0[4]); +PCSX2_ALIGNED16(u32 g_vifCol0[4]); +PCSX2_ALIGNED16(u32 g_vifRow1[4]); +PCSX2_ALIGNED16(u32 g_vifCol1[4]); +u32* _vifRow = NULL, *_vifCol = NULL; + +vifStruct *_vif; + +static int n; +static int i; + +__inline static int _limit( int a, int max ) +{ + return ( a > max ? max : a ); +} + +#define _UNPACKpart( offnum, func ) \ + if ( ( size > 0 ) && ( _vifRegs->offset == offnum ) ) { \ + func; \ + size--; \ + _vifRegs->offset++; \ + } + +#define _UNPACKpart_nosize( offnum, func ) \ + if ( ( _vifRegs->offset == offnum ) ) { \ + func; \ + _vifRegs->offset++; \ + } + +static void writeX( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask) & 0x3; break; + case 1: n = (_vifRegs->mask >> 8) & 0x3; break; + case 2: n = (_vifRegs->mask >> 16) & 0x3; break; + default: n = (_vifRegs->mask >> 24) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r0; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r0 = data + _vifRegs->r0; + *dest = _vifRegs->r0; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r0; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +/*#ifdef VIF_LOG + VIF_LOG("writeX %8.8x : Mode %d, r0 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r0,data); +#endif*/ +} + +static void writeY( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 2) & 0x3; break; + case 1: n = (_vifRegs->mask >> 10) & 0x3; break; + case 2: n = (_vifRegs->mask >> 18) & 0x3; break; + default: n = (_vifRegs->mask >> 26) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r1; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r1 = data + _vifRegs->r1; + *dest = _vifRegs->r1; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r1; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +/*#ifdef VIF_LOG + VIF_LOG("writeY %8.8x : Mode %d, r1 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r1,data); +#endif*/ +} + +static void writeZ( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 4) & 0x3; break; + case 1: n = (_vifRegs->mask >> 12) & 0x3; break; + case 2: n = (_vifRegs->mask >> 20) & 0x3; break; + default: n = (_vifRegs->mask >> 28) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r2; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r2 = data + _vifRegs->r2; + *dest = _vifRegs->r2; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r2; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +/*#ifdef VIF_LOG + VIF_LOG("writeZ %8.8x : Mode %d, r2 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r2,data); +#endif*/ +} + +static void writeW( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 6) & 0x3; break; + case 1: n = (_vifRegs->mask >> 14) & 0x3; break; + case 2: n = (_vifRegs->mask >> 22) & 0x3; break; + default: n = (_vifRegs->mask >> 30) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r3; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r3 = data + _vifRegs->r3; + *dest = _vifRegs->r3; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r3; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +/*#ifdef VIF_LOG + VIF_LOG("writeW %8.8x : Mode %d, r3 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r3,data); +#endif*/ +} + +void UNPACK_S_32(u32 *dest, u32 *data, int size) { + _UNPACKpart(0, writeX(dest++, *data) ); + _UNPACKpart(1, writeY(dest++, *data) ); + _UNPACKpart(2, writeZ(dest++, *data) ); + _UNPACKpart(3, writeW(dest , *data) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_16s( u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata) ); + _UNPACKpart(1, writeY(dest++, *sdata) ); + _UNPACKpart(2, writeZ(dest++, *sdata) ); + _UNPACKpart(3, writeW(dest , *sdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_16u( u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata) ); + _UNPACKpart(1, writeY(dest++, *sdata) ); + _UNPACKpart(2, writeZ(dest++, *sdata) ); + _UNPACKpart(3, writeW(dest , *sdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata) ); + _UNPACKpart(1, writeY(dest++, *cdata) ); + _UNPACKpart(2, writeZ(dest++, *cdata) ); + _UNPACKpart(3, writeW(dest , *cdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata) ); + _UNPACKpart(1, writeY(dest++, *cdata) ); + _UNPACKpart(2, writeZ(dest++, *cdata) ); + _UNPACKpart(3, writeW(dest , *cdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_32( u32 *dest, u32 *data, int size ) { + _UNPACKpart(0, writeX(dest++, *data++)); + _UNPACKpart(1, writeY(dest++, *data--)); + _UNPACKpart_nosize(2, writeZ(dest++, *data)); + _UNPACKpart_nosize(3, writeW(dest , 0)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; + +} + +void UNPACK_V2_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest , *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest , *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest , *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest , *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_32(u32 *dest, u32 *data, int size) { + _UNPACKpart(0, writeX(dest++, *data++); ); + _UNPACKpart(1, writeY(dest++, *data++); ); + _UNPACKpart(2, writeZ(dest++, *data++); ); + _UNPACKpart_nosize(3, writeW(dest, *data); ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata++)); + _UNPACKpart(2, writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest, *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata++)); + _UNPACKpart(2, writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest, *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata++)); + _UNPACKpart(2, writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest, *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata++)); + _UNPACKpart(2, writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest, *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_32( u32 *dest, u32 *data , int size) { + _UNPACKpart(0, writeX(dest++, *data++) ); + _UNPACKpart(1, writeY(dest++, *data++) ); + _UNPACKpart(2, writeZ(dest++, *data++) ); + _UNPACKpart(3, writeW(dest , *data ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++) ); + _UNPACKpart(1, writeY(dest++, *sdata++) ); + _UNPACKpart(2, writeZ(dest++, *sdata++) ); + _UNPACKpart(3, writeW(dest , *sdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++) ); + _UNPACKpart(1, writeY(dest++, *sdata++) ); + _UNPACKpart(2, writeZ(dest++, *sdata++) ); + _UNPACKpart(3, writeW(dest , *sdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++) ); + _UNPACKpart(1, writeY(dest++, *cdata++) ); + _UNPACKpart(2, writeZ(dest++, *cdata++) ); + _UNPACKpart(3, writeW(dest , *cdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++) ); + _UNPACKpart(1, writeY(dest++, *cdata++) ); + _UNPACKpart(2, writeZ(dest++, *cdata++) ); + _UNPACKpart(3, writeW(dest , *cdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_5(u32 *dest, u32 *data, int size) { + + _UNPACKpart(0, writeX(dest++, (*data & 0x001f) << 3); ); + _UNPACKpart(1, writeY(dest++, (*data & 0x03e0) >> 2); ); + _UNPACKpart(2, writeZ(dest++, (*data & 0x7c00) >> 7); ); + _UNPACKpart(3, writeW(dest , (*data & 0x8000) >> 8); ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +static int cycles; +extern int g_vifCycles; +int vifqwc = 0; +__inline int mfifoVIF1rbTransfer() { + u32 maddr = psHu32(DMAC_RBOR); + int msize = psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR) + 16, ret; + int mfifoqwc = min(vif1ch->qwc, vifqwc); + u32 *src; + + /* Check if the transfer should wrap around the ring buffer */ + if ((vif1ch->madr+(mfifoqwc << 4)) > (msize)) { + int s1 = ((msize) - vif1ch->madr) >> 2; + +#ifdef SPR_LOG + SPR_LOG("Split MFIFO\n"); +#endif + /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return -1; + if(vif1.vifstalled == 1){ + ret = VIF1transfer(src+vif1.irqoffset, s1-vif1.irqoffset, 0); + }else + ret = VIF1transfer(src, s1, 0); + if(ret == -2) return ret; + + /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ + vif1ch->madr = maddr; + + src = (u32*)PSM(maddr); + if (src == NULL) return -1; + ret = VIF1transfer(src, ((mfifoqwc << 2) - s1), 0); + } else { +#ifdef SPR_LOG + SPR_LOG("Direct MFIFO\n"); +#endif + /* it doesn't, so just transfer 'qwc*4' words */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return -1; + if(vif1.vifstalled == 1) + ret = VIF1transfer(src+vif1.irqoffset, mfifoqwc*4-vif1.irqoffset, 0); + else + ret = VIF1transfer(src, mfifoqwc << 2, 0); + if(ret == -2) return ret; + } + + + return ret; +} + +__inline int mfifoVIF1chain() { + int ret; + + /* Is QWC = 0? if so there is nothing to transfer */ + if (vif1ch->qwc == 0 && vif1.vifstalled == 0) return 0; + + + if (vif1ch->madr >= psHu32(DMAC_RBOR) && + vif1ch->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { + u16 startqwc = vif1ch->qwc; + ret = mfifoVIF1rbTransfer(); + vifqwc -= startqwc - vif1ch->qwc; + } else { + u32 *pMem = (u32*)dmaGetAddr(vif1ch->madr); +#ifdef SPR_LOG + SPR_LOG("Non-MFIFO Location\n"); +#endif + if (pMem == NULL) return -1; + if(vif1.vifstalled == 1){ + ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); + }else + ret = VIF1transfer(pMem, vif1ch->qwc << 2, 0); + } + + return ret; +} + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) +static int tempqwc = 0; + +void mfifoVIF1transfer(int qwc) { + u32 *ptag; + int id; + int ret, temp; + + g_vifCycles = 0; + + if(qwc > 0){ + vifqwc += qwc; +#ifdef SPR_LOG + SPR_LOG("Added %x qw to mfifo, total now %x\n", qwc, vifqwc); +#endif + if((vif1ch->chcr & 0x100) == 0 || vif1.vifstalled == 1) return; + } + + if(vif1ch->qwc == 0){ + /*if(vif1ch->tadr == spr0->madr) { + + #ifdef PCSX2_DEVBUILD + SysPrintf("vif mfifo tadr==madr but qwc = %d\n", vifqwc); + #endif + FreezeMMXRegs(0); + FreezeXMMRegs(0); + //hwDmacIrq(14); + return; + }*/ + + ptag = (u32*)dmaGetAddr(vif1ch->tadr); + + if (vif1ch->chcr & 0x40) { + if( vif1.stallontag == 1) ret = VIF1transfer(ptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on Stall + else ret = VIF1transfer(ptag+2, 2, 1); //Transfer Tag + if (ret == -2) { +#ifdef SPR_LOG + VIF_LOG("MFIFO Stallon tag\n"); +#endif + vif1.stallontag = 1; + INT(10,cycles+g_vifCycles); + return; //IRQ set by VIFTransfer + } + } + + id = (ptag[0] >> 28) & 0x7; + vif1ch->qwc = (ptag[0] & 0xffff); + vif1ch->madr = ptag[1]; + cycles += 2; + + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); + +#ifdef SPR_LOG + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", + ptag[1], ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr, vifqwc, spr0->madr); +#endif + vifqwc--; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); + vif1.done = 2; //End Transfer + break; + + case 1: // CNT - Transfer QWC following the tag. + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + vif1.done = 0; + break; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = vif1ch->madr; //Temporarily Store ADDR + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag + vif1ch->tadr = temp; //Copy temporarily stored ADDR to Tag + if((temp & psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("Next tag = %x outside ring %x size %x\n", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); + vif1.done = 0; + break; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag + vif1.done = 0; + break; + + case 7: // End - Transfer QWC following the tag + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + vif1.done = 2; //End Transfer + break; + } + + if ((vif1ch->chcr & 0x80) && (ptag[0] >> 31)) { +#ifdef SPR_LOG + VIF_LOG("dmaIrq Set\n"); +#endif + vif1.done = 2; + } + } + ret = mfifoVIF1chain(); + if (ret == -1) { + SysPrintf("VIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); + vif1.done = 1; + INT(10,g_vifCycles); + } + if(ret == -2){ + +#ifdef VIF_LOG + VIF_LOG("MFIFO Stall\n"); +#endif + INT(10,g_vifCycles); + return; + } + + if(vif1.done == 2 && vif1ch->qwc == 0) vif1.done = 1; + + INT(10,g_vifCycles); + +#ifdef SPR_LOG + SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr, vifqwc); +#endif +} + +void vifMFIFOInterrupt() +{ + + if(vif1.irq && vif1.tag.size == 0) { + vif1Regs->stat|= VIF1_STAT_INT; + hwIntcIrq(5); + --vif1.irq; + if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) + { + vif1Regs->stat&= ~0x1F000000; // FQC=0 + vif1ch->chcr &= ~0x100; + cpuRegs.interrupt &= ~(1 << 10); + return; + } + } + + if(vif1.done != 1) { + if(vifqwc <= 0){ + //SysPrintf("Empty\n"); + hwDmacIrq(14); + cpuRegs.interrupt &= ~(1 << 10); + return; + } + mfifoVIF1transfer(0); + return; + } + + //if(vifqwc > 0)SysPrintf("VIF MFIFO ending with stuff in it %x\n", vifqwc); + vifqwc = 0; + vif1.done = 0; + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); +#ifdef VIF_LOG + VIF_LOG("vif mfifo dma end\n"); +#endif + vif1Regs->stat&= ~0x1F000000; // FQC=0 +// } + cpuRegs.interrupt &= ~(1 << 10); +} diff --git a/pcsx2/Vif.h b/pcsx2/Vif.h new file mode 100644 index 0000000000..8dedc0cadb --- /dev/null +++ b/pcsx2/Vif.h @@ -0,0 +1,108 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __VIF_H__ +#define __VIF_H__ + +typedef struct { + u8 cl, wl; + u8 pad[2]; +} vifCycle; + +typedef struct { + u32 stat; + u32 pad0[3]; + u32 fbrst; + u32 pad1[3]; + u32 err; + u32 pad2[3]; + u32 mark; + u32 pad3[3]; + vifCycle cycle; //data write cycle + u32 pad4[3]; + u32 mode; + u32 pad5[3]; + u32 num; + u32 pad6[3]; + u32 mask; + u32 pad7[3]; + u32 code; + u32 pad8[3]; + u32 itops; + u32 pad9[3]; + u32 base; // Not used in VIF0 + u32 pad10[3]; + u32 ofst; // Not used in VIF0 + u32 pad11[3]; + u32 tops; // Not used in VIF0 + u32 pad12[3]; + u32 itop; + u32 pad13[3]; + u32 top; // Not used in VIF0 + u32 pad14[3]; + u32 mskpath3; + u32 pad15[3]; + u32 r0; // row0 register + u32 pad16[3]; + u32 r1; // row1 register + u32 pad17[3]; + u32 r2; // row2 register + u32 pad18[3]; + u32 r3; // row3 register + u32 pad19[3]; + u32 c0; // col0 register + u32 pad20[3]; + u32 c1; // col1 register + u32 pad21[3]; + u32 c2; // col2 register + u32 pad22[3]; + u32 c3; // col3 register + u32 pad23[3]; + u32 offset; // internal UNPACK offset + u32 addr; +} VIFregisters; + +#define vif0Regs ((VIFregisters*)&PS2MEM_HW[0x3800]) +#define vif1Regs ((VIFregisters*)&PS2MEM_HW[0x3c00]) + +void dmaVIF0(); +void dmaVIF1(); +void mfifoVIF1transfer(int qwc); +int VIF0transfer(u32 *data, int size, int istag); +int VIF1transfer(u32 *data, int size, int istag); +void vifMFIFOInterrupt(); + +#ifndef PCSX2_NORECBUILD +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask); +#else +#define SetNewMask 0&& +#endif + +#define XMM_R0 xmm0 +#define XMM_R1 xmm1 +#define XMM_R2 xmm2 +#define XMM_WRITEMASK xmm3 +#define XMM_ROWMASK xmm4 +#define XMM_ROWCOLMASK xmm5 +#define XMM_ROW xmm6 +#define XMM_COL xmm7 + +#define XMM_R3 XMM_COL + + +#endif /* __VIF_H__ */ diff --git a/pcsx2/VifDma.c b/pcsx2/VifDma.c new file mode 100644 index 0000000000..1642ab2a57 --- /dev/null +++ b/pcsx2/VifDma.c @@ -0,0 +1,2594 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "Common.h" +#include "Vif.h" +#include "VUmicro.h" +#include "GS.h" + +#include "VifDma.h" + +#include + +#define gif ((DMACh*)&PS2MEM_HW[0xA000]) + +// Extern variables +extern VIFregisters *_vifRegs; +extern vifStruct *_vif; +extern u32* _vifMaskRegs; +extern PCSX2_ALIGNED16_DECL(u32 g_vifRow0[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifCol0[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifRow1[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifCol1[4]); +extern u32* _vifRow, *_vifCol; + +vifStruct vif0, vif1; + +PCSX2_ALIGNED16(u32 g_vif1Masks[64]); +PCSX2_ALIGNED16(u32 g_vif0Masks[64]); +u32 g_vif1HasMask3[4] = {0}, g_vif0HasMask3[4] = {0}; + +// Generic constants +static const unsigned int VIF0intc = 4; +static const unsigned int VIF1intc = 5; +static const unsigned int VIF0dmanum = 0; +static const unsigned int VIF1dmanum = 1; + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +extern HANDLE g_hGsEvent; +#else +extern pthread_cond_t g_condGsEvent; +#endif + +int g_vifCycles = 0; +int path3hack = 0; + +#ifndef __x86_64__ +extern void * memcpy_fast(void *dest, const void *src, size_t n); +#endif + +typedef void (*UNPACKFUNCTYPE)( u32 *dest, u32 *data, int size ); +typedef int (*UNPACKPARTFUNCTYPESSE)( u32 *dest, u32 *data, int size ); +void (*Vif1CMDTLB[82])(); +void (*Vif0CMDTLB[75])(); +int (*Vif1TransTLB[128])(u32 *data); +int (*Vif0TransTLB[128])(u32 *data); + +typedef struct { + UNPACKFUNCTYPE funcU; + UNPACKFUNCTYPE funcS; + + int bsize; // currently unused + int dsize; // byte size of one channel + int gsize; // size of data in bytes used for each write cycle + int qsize; // used for unpack parts, num of vectors that + // will be decompressed from data for 1 cycle +} VIFUnpackFuncTable; + +/* block size; data size; group size; qword size; */ +#define _UNPACK_TABLE32(name, bsize, dsize, gsize, qsize) \ + { UNPACK_##name, UNPACK_##name, \ + bsize, dsize, gsize, qsize }, + +#define _UNPACK_TABLE(name, bsize, dsize, gsize, qsize) \ + { UNPACK_##name##u, UNPACK_##name##s, \ + bsize, dsize, gsize, qsize }, + +// Main table for function unpacking +static const VIFUnpackFuncTable VIFfuncTable[16] = { + _UNPACK_TABLE32(S_32, 1, 4, 4, 4) // 0x0 - S-32 + _UNPACK_TABLE(S_16, 2, 2, 2, 4) // 0x1 - S-16 + _UNPACK_TABLE(S_8, 4, 1, 1, 4) // 0x2 - S-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0x3 + + _UNPACK_TABLE32(V2_32, 24, 4, 8, 2) // 0x4 - V2-32 + _UNPACK_TABLE(V2_16, 12, 2, 4, 2) // 0x5 - V2-16 + _UNPACK_TABLE(V2_8, 6, 1, 2, 2) // 0x6 - V2-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0x7 + + _UNPACK_TABLE32(V3_32, 36, 4, 12, 3) // 0x8 - V3-32 + _UNPACK_TABLE(V3_16, 18, 2, 6, 3) // 0x9 - V3-16 + _UNPACK_TABLE(V3_8, 9, 1, 3, 3) // 0xA - V3-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0xB + + _UNPACK_TABLE32(V4_32, 48, 4, 16, 4) // 0xC - V4-32 + _UNPACK_TABLE(V4_16, 24, 2, 8, 4) // 0xD - V4-16 + _UNPACK_TABLE(V4_8, 12, 1, 4, 4) // 0xE - V4-8 + _UNPACK_TABLE32(V4_5, 6, 2, 2, 4) // 0xF - V4-5 +}; + + +#if !defined(PCSX2_NORECBUILD) + +typedef struct { + // regular 0, 1, 2; mask 0, 1, 2 + UNPACKPARTFUNCTYPESSE funcU[9], funcS[9]; +} VIFSSEUnpackTable; + +#define DECL_UNPACK_TABLE_SSE(name, sign) \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_0(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_1(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_2(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_0(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_1(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_2(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1(u32* dest, u32* data, int dmasize); \ +extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2(u32* dest, u32* data, int dmasize); \ + +#define _UNPACK_TABLE_SSE(name, sign) \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_0, \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_1, \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_2, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_0, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_1, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_2, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2 \ + +#define _UNPACK_TABLE_SSE_NULL \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + +// Main table for function unpacking +DECL_UNPACK_TABLE_SSE(S_32, u); +DECL_UNPACK_TABLE_SSE(S_16, u); +DECL_UNPACK_TABLE_SSE(S_8, u); +DECL_UNPACK_TABLE_SSE(S_16, s); +DECL_UNPACK_TABLE_SSE(S_8, s); + +DECL_UNPACK_TABLE_SSE(V2_32, u); +DECL_UNPACK_TABLE_SSE(V2_16, u); +DECL_UNPACK_TABLE_SSE(V2_8, u); +DECL_UNPACK_TABLE_SSE(V2_16, s); +DECL_UNPACK_TABLE_SSE(V2_8, s); + +DECL_UNPACK_TABLE_SSE(V3_32, u); +DECL_UNPACK_TABLE_SSE(V3_16, u); +DECL_UNPACK_TABLE_SSE(V3_8, u); +DECL_UNPACK_TABLE_SSE(V3_16, s); +DECL_UNPACK_TABLE_SSE(V3_8, s); + +DECL_UNPACK_TABLE_SSE(V4_32, u); +DECL_UNPACK_TABLE_SSE(V4_16, u); +DECL_UNPACK_TABLE_SSE(V4_8, u); +DECL_UNPACK_TABLE_SSE(V4_16, s); +DECL_UNPACK_TABLE_SSE(V4_8, s); +DECL_UNPACK_TABLE_SSE(V4_5, u); + +static const VIFSSEUnpackTable VIFfuncTableSSE[16] = { + { _UNPACK_TABLE_SSE(S_32, u), _UNPACK_TABLE_SSE(S_32, u) }, + { _UNPACK_TABLE_SSE(S_16, u), _UNPACK_TABLE_SSE(S_16, s) }, + { _UNPACK_TABLE_SSE(S_8, u), _UNPACK_TABLE_SSE(S_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V2_32, u), _UNPACK_TABLE_SSE(V2_32, u) }, + { _UNPACK_TABLE_SSE(V2_16, u), _UNPACK_TABLE_SSE(V2_16, s) }, + { _UNPACK_TABLE_SSE(V2_8, u), _UNPACK_TABLE_SSE(V2_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V3_32, u), _UNPACK_TABLE_SSE(V3_32, u) }, + { _UNPACK_TABLE_SSE(V3_16, u), _UNPACK_TABLE_SSE(V3_16, s) }, + { _UNPACK_TABLE_SSE(V3_8, u), _UNPACK_TABLE_SSE(V3_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V4_32, u), _UNPACK_TABLE_SSE(V4_32, u) }, + { _UNPACK_TABLE_SSE(V4_16, u), _UNPACK_TABLE_SSE(V4_16, s) }, + { _UNPACK_TABLE_SSE(V4_8, u), _UNPACK_TABLE_SSE(V4_8, s) }, + { _UNPACK_TABLE_SSE(V4_5, u), _UNPACK_TABLE_SSE(V4_5, u) }, +}; + +#endif + + +__forceinline void vif0FLUSH() { + int _cycles; + _cycles = VU0.cycle; + + //FreezeXMMRegs(1); + vu0Finish(); + //FreezeXMMRegs(0); + g_vifCycles+= (VU0.cycle - _cycles)*BIAS; +} + +__forceinline void vif1FLUSH() { + int _cycles; + _cycles = VU1.cycle; + + if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { + //FreezeXMMRegs(1); + do { + Cpu->ExecuteVU1Block(); + } while(VU0.VI[REG_VPU_STAT].UL & 0x100); + +// FreezeXMMRegs(0); +// FreezeMMXRegs(0); + //FreezeXMMRegs(0); + g_vifCycles+= (VU1.cycle - _cycles)*BIAS; + } +} + +void vifDmaInit() { +} + +__inline static int _limit( int a, int max ) { + return ( a > max ? max : a ); +} + +void DummyExecuteVU1Block(void) +{ + VU0.VI[ REG_VPU_STAT ].UL &= ~0x100; + VU1.vifRegs->stat &= ~4; // also reset the bit (grandia 3 works) +} + +//#define VIFUNPACKDEBUG //enable unpack debugging output + +static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int VIFdmanum){ + const VIFUnpackFuncTable *unpack; + vifStruct *vif; + VIFregisters *vifRegs; + unpack = &VIFfuncTable[ unpackType ]; +// varLog |= 0x00000400; + + if (VIFdmanum == 0) + { + vif = &vif0; + vifRegs = vif0Regs; + } + else + { + vif = &vif1; + vifRegs = vif1Regs; + } + + switch(unpackType){ + case 0x0: + vif->tag.addr += size*4; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing S-32 skip, size = %d\n", size); +#endif + break; + case 0x1: + vif->tag.addr += size*8; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing S-16 skip, size = %d\n", size); +#endif + break; + case 0x2: + vif->tag.addr += size*16; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing S-8 skip, size = %d\n", size); +#endif + break; + case 0x4: + vif->tag.addr += size + ((size / unpack->gsize) * 8); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V2-32 skip, size = %d\n", size); +#endif + break; + case 0x5: + vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 8); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V2-16 skip, size = %d\n", size); +#endif + break; + case 0x6: + vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 8); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V2-8 skip, size = %d\n", size); +#endif + break; + case 0x8: + vif->tag.addr += size + ((size / unpack->gsize) * 4); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V3-32 skip, size = %d\n", size); +#endif + break; + case 0x9: + vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 4); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V3-16 skip, size = %d\n", size); +#endif + break; + case 0xA: + vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 4); +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V3-8 skip, size = %d\n", size); +#endif + break; + case 0xC: + vif->tag.addr += size; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V4-32 skip, size = %d, CL = %d, WL = %d\n", size, vif1Regs->cycle.cl, vif1Regs->cycle.wl); +#endif + break; + case 0xD: + vif->tag.addr += size * 2; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V4-16 skip, size = %d\n", size); +#endif + break; + case 0xE: + vif->tag.addr += size * 4; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V4-8 skip, size = %d\n", size); +#endif + break; + case 0xF: + vif->tag.addr += size * 8; +#ifdef VIFUNPACKDEBUG + SysPrintf("Processing V4-5 skip, size = %d\n", size); +#endif + break; + default: + SysPrintf("Invalid unpack type %x\n", unpackType); + break; + } + //if(vifRegs->offset == 0) { + //vif->tag.addr += (size / unpack->gsize) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + //if(vifRegs->cycle.cl != vifRegs->cycle.wl)SysPrintf("Adjusting\n"); + //} + if((vif->tag.addr & 0xf) == unpack->gsize) { + //SysPrintf("Making up for lost bit Addr %x Gsize %x new addr %x\n", vif->tag.addr, unpack->gsize, vif->tag.addr + (16 - unpack->gsize)); + vif->tag.addr += 16 - unpack->gsize; + } +} + +#ifdef _MSC_VER +//#define __MMX__ +//#define __SSE__ +#include +#include +#endif + +//u32 unpacktotal = 0; + +static void VIFunpack(u32 *data, vifCode *v, int size, const unsigned int VIFdmanum) { + u32 *dest; + unsigned int unpackType; + UNPACKFUNCTYPE func; + const VIFUnpackFuncTable *ft; + vifStruct *vif; + VIFregisters *vifRegs; + VURegs * VU; + u8 *cdata = (u8*)data; + //u64 basetick = GetCPUTick(); +#ifdef _DEBUG + int memsize; +#endif + +#ifdef _MSC_VER + _mm_prefetch((char*)data, _MM_HINT_NTA); +#endif + + if (VIFdmanum == 0) { + VU = &VU0; + vif = &vif0; + vifRegs = vif0Regs; +#ifdef _DEBUG + memsize = 0x1000; +#endif + assert( v->addr < 0x1000 ); + //v->addr &= 0xfff; + } else { + + VU = &VU1; + vif = &vif1; + vifRegs = vif1Regs; +#ifdef _DEBUG + memsize = 0x4000; +#endif + assert( v->addr < 0x4000 ); + //v->addr &= 0x3fff; + + if( Cpu->ExecuteVU1Block == DummyExecuteVU1Block ) { + // don't process since the frame is dummy + vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + // unpacktotal += GetCPUTick()-basetick; + return; + } + } + + dest = (u32*)(VU->Mem + v->addr); + +#ifdef VIF_LOG + VIF_LOG("VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", + VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); +#endif + +/* if (vifRegs->cycle.cl > vifRegs->cycle.wl) { + SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", + VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); + }*/ +#ifdef _DEBUG + if (v->size != size) { +#ifdef VIF_LOG + VIF_LOG("*PCSX2*: warning v->size != size\n"); +#endif + } + if ((v->addr+size*4) > memsize) { + SysPrintf("*PCSX2*: fixme unpack overflow\n"); + SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", + VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); + } +#endif + // The unpack type + unpackType = v->cmd & 0xf; + /*if (v->size != size) { + SysPrintf("*PCSX2*: v->size = %d, size = %d mode = %x\n", v->size, size, unpackType); + }*/ +#ifdef VIFUNPACKDEBUG + if (size == 0) { + SysPrintf("*PCSX2*: Unpack %x with size 0!! v->size = %d cl = %d, wl = %d, mode %d mask %x\n", v->cmd, v->size, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mode, vifRegs->mask); + //return; + } +#endif + + + +#ifdef _MSC_VER + _mm_prefetch((char*)data+128, _MM_HINT_NTA); +#endif + _vifRegs = (VIFregisters*)vifRegs; + _vifMaskRegs = VIFdmanum ? g_vif1Masks : g_vif0Masks; + _vif = vif; + _vifRow = VIFdmanum ? g_vifRow1 : g_vifRow0; + ft = &VIFfuncTable[ unpackType ]; + func = _vif->usn ? ft->funcU : ft->funcS; + // Unpacking + //vif->wl = 0; vif->cl = 0; + + size<<= 2; +#ifdef _DEBUG + memsize = size; +#endif + if( _vifRegs->offset > 0) { + int destinc, unpacksize; +#ifdef VIFUNPACKDEBUG + SysPrintf("aligning packet size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); +#endif + // SSE doesn't handle such small data + if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); + + if(vifRegs->offset < (u32)ft->qsize){ + if((size/ft->dsize) < (ft->qsize - vifRegs->offset)){ + SysPrintf("wasnt enough left size/dsize = %x left to write %x\n", (size/ft->dsize), (ft->qsize - vifRegs->offset)); + } + unpacksize = min((size/ft->dsize), (ft->qsize - vifRegs->offset)); + } else { + unpacksize = 0; + SysPrintf("Unpack align offset = 0\n"); + } + destinc = (4 - ft->qsize) + unpacksize; + + func(dest, (u32*)cdata, unpacksize); + size -= unpacksize*ft->dsize; + cdata += unpacksize*ft->dsize; + + vifRegs->num--; + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + if(vifRegs->cycle.cl != vifRegs->cycle.wl){ + dest += ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + destinc; + //vif->tag.addr += (destinc<<2) + ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + } else { + dest += destinc; + //vif->tag.addr += destinc << 2; + } + vif->cl = 0; + } + else { + dest += destinc; + //vif->tag.addr += destinc << 2; + } +#ifdef VIFUNPACKDEBUG + SysPrintf("aligning packet done size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); +#endif + //} + //skipmeminc += (((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2)*4) * skipped; + } else if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); + + if (vifRegs->cycle.cl >= vifRegs->cycle.wl) { // skipping write + +#ifdef _DEBUG + static s_count=0; +#endif + //u32* olddest = dest; + + int incdest; + //ft = &VIFfuncTable[ unpackType ]; + if( vif->cl != 0 ) { + // continuation from last stream + + // func = vif->usn ? ft->funcU : ft->funcS; + incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; + while (size >= ft->gsize && vifRegs->num > 0) { + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + + vifRegs->num--; + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + dest += incdest; + vif->cl = 0; + break; + } + + dest += 4; + } + + // have to update + _vifRow[0] = _vifRegs->r0; + _vifRow[1] = _vifRegs->r1; + _vifRow[2] = _vifRegs->r2; + _vifRow[3] = _vifRegs->r3; + + } + +#if !defined(PCSX2_NORECBUILD) + + if( size >= ft->gsize && !(v->addr&0xf) && cpucaps.hasStreamingSIMD2Extensions) { + const UNPACKPARTFUNCTYPESSE* pfn; + int writemask; + //static LARGE_INTEGER lbase, lfinal; + //QueryPerformanceCounter(&lbase); + u32 oldcycle = -1; + //FreezeXMMRegs(1); + +// u16 tempdata[4] = { 0x8000, 0x7fff, 0x1010, 0xd0d0 }; +// vifRegs->cycle.cl = 4; +// vifRegs->cycle.wl = 1; +// SetNewMask(g_vif1Masks, g_vif1HasMask3, 0x3f, ~0x3f); +// memset(dest, 0xcd, 64*4); +// VIFfuncTableSSE[1].funcS[6](dest, (u32*)tempdata, 8); + +#ifdef _MSC_VER + +#ifdef __x86_64__ + _vifCol = VIFdmanum ? g_vifCol1 : g_vifCol0; +#else + if( VIFdmanum ) { + __asm movaps XMM_ROW, qword ptr [g_vifRow1] + __asm movaps XMM_COL, qword ptr [g_vifCol1] + } + else { + __asm movaps XMM_ROW, qword ptr [g_vifRow0] + __asm movaps XMM_COL, qword ptr [g_vifCol0] + } +#endif + +#else + if( VIFdmanum ) { + __asm__(".intel_syntax\n" + "movaps %%xmm6, qword ptr [%0]\n" + "movaps %%xmm7, qword ptr [%1]\n" + ".att_syntax\n" : :"r"(g_vifRow1), "r"(g_vifCol1) ); + } + else { + __asm__(".intel_syntax\n" + "movaps %%xmm6, qword ptr [%0]\n" + "movaps %%xmm7, qword ptr [%1]\n" + ".att_syntax\n" : : "r"(g_vifRow0), "r"(g_vifCol0) ); + } +#endif + + if( vifRegs->cycle.cl == 0 || vifRegs->cycle.wl == 0 || (vifRegs->cycle.cl == vifRegs->cycle.wl && !(vifRegs->code&0x10000000)) ) { + oldcycle = *(u32*)&vifRegs->cycle; + vifRegs->cycle.cl = vifRegs->cycle.wl = 1; + } + size = min(size, (int)vifRegs->num*ft->gsize); //size will always be the same or smaller + + pfn = vif->usn ? VIFfuncTableSSE[unpackType].funcU: VIFfuncTableSSE[unpackType].funcS; + writemask = VIFdmanum ? g_vif1HasMask3[min(vifRegs->cycle.wl,3)] : g_vif0HasMask3[min(vifRegs->cycle.wl,3)]; + writemask = pfn[(((vifRegs->code & 0x10000000)>>28)<mode](dest, (u32*)cdata, size); + + if( oldcycle != -1 ) *(u32*)&vifRegs->cycle = oldcycle; + + // if size is left over, update the src,dst pointers + if( writemask > 0 ) { + int left = (size-writemask)/ft->gsize; + cdata += left * ft->gsize; + dest = (u32*)((u8*)dest + ((left/vifRegs->cycle.wl)*vifRegs->cycle.cl + left%vifRegs->cycle.wl)*16); + vifRegs->num -= left; + // Add split transfer skipping + //vif->tag.addr += (size / (ft->gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + // check for left over write cycles (so can spill to next transfer) + _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; + } + else { + vifRegs->num -= size/ft->gsize; + if(vifRegs->num > 0) _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; + } + + size = writemask; + + _vifRegs->r0 = _vifRow[0]; + _vifRegs->r1 = _vifRow[1]; + _vifRegs->r2 = _vifRow[2]; + _vifRegs->r3 = _vifRow[3]; + //QueryPerformanceCounter(&lfinal); + //((LARGE_INTEGER*)g_nCounters)->QuadPart += lfinal.QuadPart - lbase.QuadPart; + } + else +#endif // !PCSX2_NORECBUILD + { + + if(unpackType == 0xC && vifRegs->cycle.cl == vifRegs->cycle.wl) { //No use when SSE is available + // v4-32 + if(vifRegs->mode == 0 && !(vifRegs->code & 0x10000000) && vif->usn == 0){ + vifRegs->num -= size>>4; + FreezeMMXRegs(1); + memcpy_fast((u8*)dest, cdata, size); + FreezeMMXRegs(0); + size = 0; + //unpacktotal += GetCPUTick()-basetick; + return; + } + } + // Assigning the normal upack function, the part type is assigned later + //func = vif->usn ? ft->funcU : ft->funcS; + + incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; + + //SysPrintf("slow vif\n"); + //if(skipped > 0) skipped = 0; + // Add split transfer skipping + //vif->tag.addr += (size / (ft->gsize*vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + + while (size >= ft->gsize && vifRegs->num > 0) { + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + + vifRegs->num--; + //SysPrintf("%d transferred, remaining %d, vifnum %d\n", ft->gsize, size, vifRegs->num); + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + dest += incdest; + vif->cl = 0; + } + else + { + dest += 4; + } + } + + // have to update + _vifRow[0] = _vifRegs->r0; + _vifRow[1] = _vifRegs->r1; + _vifRow[2] = _vifRegs->r2; + _vifRow[3] = _vifRegs->r3; + } + + // used for debugging vif +// { +// int i, j, k; +// u32* curdest = olddest; +// FILE* ftemp = fopen("temp.txt", s_count?"a+":"w"); +// fprintf(ftemp, "%x %x %x\n", s_count, size, vif->tag.addr); +// fprintf(ftemp, "%x %x %x\n", vifRegs->code>>24, vifRegs->mode, *(u32*)&vifRegs->cycle); +// fprintf(ftemp, "row: %x %x %x %x\n", _vifRow[0], _vifRow[1], _vifRow[2], _vifRow[3]); +// //fprintf(ftemp, "row2: %x %x %x %x\n", _vifRegs->r0, _vifRegs->r1, _vifRegs->r2, _vifRegs->r3); +// +// for(i = 0; i < memsize; ) { +// for(k = 0; k < vifRegs->cycle.wl; ++k) { +// for(j = 0; j <= ((vifRegs->code>>26)&3); ++j) { +// fprintf(ftemp, "%x ", curdest[4*k+j]); +// } +// } +// +// fprintf(ftemp, "\n"); +// curdest += 4*vifRegs->cycle.cl; +// i += (((vifRegs->code>>26)&3)+1)*ft->dsize*vifRegs->cycle.wl; +// } +// fclose(ftemp); +// } +// s_count++; + + if( size >= ft->dsize && vifRegs->num > 0) { + #ifdef VIF_LOG + VIF_LOG("warning, end with size = %d\n", size); + #endif + // SSE doesn't handle such small data + //ft = &VIFfuncTable[ unpackType ]; + //func = vif->usn ? ft->funcU : ft->funcS; + #ifdef VIFUNPACKDEBUG + SysPrintf("end with size %x dsize = %x unpacktype %x\n", size, ft->dsize, unpackType); + #endif + //while (size >= ft->dsize) { + /* unpack one qword */ + func(dest, (u32*)cdata, size / ft->dsize); + //cdata += ft->dsize; + //dest += 1; + size = 0; + //} + #ifdef VIFUNPACKDEBUG + SysPrintf("leftover done, size %d, vifnum %d, addr %x\n", size, vifRegs->num, vif->tag.addr); + #endif + } + + } + else { /* filling write */ +#ifdef VIF_LOG + VIF_LOG("*PCSX2*: filling write\n"); +#endif + //ft = &VIFfuncTable[ unpackType ]; + //func = vif->usn ? ft->funcU : ft->funcS; +#ifdef VIFUNPACKDEBUG + SysPrintf("filling write %d cl %d, wl %d mask %x mode %x unpacktype %x\n", vifRegs->num, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mask, vifRegs->mode, unpackType); +#endif + while (size >= ft->gsize || vifRegs->num > 0) { + if (vif->cl == vifRegs->cycle.wl) { + vif->cl = 0; + } + // + if (vif->cl < vifRegs->cycle.cl) { /* unpack one qword */ + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + vif->cl++; + vifRegs->num--; + if (vif->cl == vifRegs->cycle.wl) { + vif->cl = 0; + } + } + else + { + func( dest, (u32*)cdata, ft->qsize); + //cdata += ft->gsize; + //size -= ft->gsize; + vif->tag.addr += 16; + vifRegs->num--; + ++vif->cl; + + } + dest += 4; + //++vif->wl; + if(vifRegs->num == 0) break; + } + } + //unpacktotal += GetCPUTick()-basetick; + //if(vifRegs->num == 0 && size > 3) SysPrintf("Size = %x, Vifnum = 0!\n", size); +} + +static void vuExecMicro( u32 addr, const u32 VIFdmanum ) +{ + int _cycles; + VURegs * VU; + //void (*_vuExecMicro)(); + +// MessageBox(NULL, "3d doesn't work\n", "Query", MB_OK); +// return; + + if (VIFdmanum == 0) { + //_vuExecMicro = Cpu->ExecuteVU0Block; + VU = &VU0; + vif0FLUSH(); + } else { + //_vuExecMicro = Cpu->ExecuteVU1Block; + VU = &VU1; + vif1FLUSH(); + } + if(VU->vifRegs->itops > (VIFdmanum ? 0x3ffu : 0xffu)) + SysPrintf("VIF%d ITOP overrun! %x\n", VIFdmanum, VU->vifRegs->itops); + + VU->vifRegs->itop = VU->vifRegs->itops; + + if (VIFdmanum == 1) { + /* in case we're handling a VIF1 execMicro + set the top with the tops value */ + VU->vifRegs->top = VU->vifRegs->tops & 0x3ff; + + /* is DBF flag set in VIF_STAT? */ + if (VU->vifRegs->stat & 0x80) { + /* it is, so set tops with base + ofst + and clear stat DBF flag */ + VU->vifRegs->tops = VU->vifRegs->base; + VU->vifRegs->stat &= ~0x80; + } else { + /* it is not, so set tops with base + and set the stat DBF flag */ + VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; + VU->vifRegs->stat |= 0x80; + } + } + //FreezeXMMRegs(1); + if (VIFdmanum == 0) { + _cycles = VU0.cycle; + vu0ExecMicro(addr); + // too much delay + //g_vifCycles+= (VU0.cycle - _cycles)*BIAS; + } else { + _cycles = VU1.cycle; + vu1ExecMicro(addr); + // too much delay + //g_vifCycles+= (VU1.cycle - _cycles)*BIAS; + } + //FreezeXMMRegs(0); +} + +u8 s_maskwrite[256]; +void vif0Init() +{ + + u32 i; + + for(i = 0; i < 256; ++i ) { + s_maskwrite[i] = ((i&3)==3)||((i&0xc)==0xc)||((i&0x30)==0x30)||((i&0xc0)==0xc0); + } + + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); +} + +__inline void vif0UNPACK(u32 *data) { + int vifNum; + int vl, vn; + int len; + + if(vif0Regs->cycle.wl == 0 && vif0Regs->cycle.wl < vif0Regs->cycle.cl){ + SysPrintf("Vif0 CL %d, WL %d\n", vif0Regs->cycle.cl, vif0Regs->cycle.wl); + vif0.cmd &= ~0x7f; + return; + } + + vif0FLUSH(); + + vl = (vif0.cmd ) & 0x3; + vn = (vif0.cmd >> 2) & 0x3; + vif0.tag.addr = (vif0Regs->code & 0x3ff) << 4; + vif0.usn = (vif0Regs->code >> 14) & 0x1; + vifNum = (vif0Regs->code >> 16) & 0xff; + if ( vifNum == 0 ) vifNum = 256; + vif0Regs->num = vifNum; + + if ( vif0Regs->cycle.wl <= vif0Regs->cycle.cl ) { + len = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; + } else { + int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + + _limit( vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl ); + + len = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; + } + //if((vif0.tag.addr + (vifNum * 16)) > 0x1000) SysPrintf("VIF0 Oops, Addr %x, NUM %x overlaps to %x\n", vif0.tag.addr, vifNum, (vif0.tag.addr + (vifNum * 16))); + vif0.wl = 0; vif0.cl = 0; + vif0.tag.cmd = vif0.cmd; + vif0.tag.addr &= 0xfff; + vif0.tag.size = len; + vif0Regs->offset = 0; +} + +__inline void _vif0mpgTransfer(u32 addr, u32 *data, int size) { +/* SysPrintf("_vif0mpgTransfer addr=%x; size=%x\n", addr, size); + { + FILE *f = fopen("vu1.raw", "wb"); + fwrite(data, 1, size*4, f); + fclose(f); + }*/ + if (memcmp(VU0.Micro + addr, data, size << 2)) { + FreezeMMXRegs(1); + memcpy_fast(VU0.Micro + addr, data, size << 2); + FreezeMMXRegs(0); + Cpu->ClearVU0(addr, size); + } +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 Data Transfer Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int Vif0TransNull(u32 *data){ // Shouldnt go here + SysPrintf("VIF0 Shouldnt go here CMD = %x\n", vif0Regs->code); + vif0.cmd = 0; + return 0; +} +static int Vif0TransSTMask(u32 *data){ // STMASK + SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); + vif0Regs->mask = data[0]; +#ifdef VIF_LOG + VIF_LOG("STMASK == %x\n", vif0Regs->mask); +#endif + vif0.tag.size = 0; + vif0.cmd = 0; + return 1; +} + +static int Vif0TransSTRow(u32 *data){ // STROW + int ret; + + u32* pmem = &vif0Regs->r0+(vif0.tag.addr<<2); + u32* pmem2 = g_vifRow0+vif0.tag.addr; + assert( vif0.tag.addr < 4 ); + ret = min(4-vif0.tag.addr, vif0.vifpacketsize); + assert( ret > 0 ); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; +#ifdef _MSC_VER + default: __assume(0); +#endif + } + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if(vif0.tag.size == 0) vif0.cmd = 0; + + return ret; +} + +static int Vif0TransSTCol(u32 *data){ // STCOL + int ret; + + u32* pmem = &vif0Regs->c0+(vif0.tag.addr<<2); + u32* pmem2 = g_vifCol0+vif0.tag.addr; + ret = min(4-vif0.tag.addr, vif0.vifpacketsize); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; +#ifdef _MSC_VER + default: __assume(0); +#endif + } + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if(vif0.tag.size == 0) vif0.cmd = 0; + return ret; +} + +static int Vif0TransMPG(u32 *data){ // MPG + if (vif0.vifpacketsize < vif0.tag.size) { + _vif0mpgTransfer(vif0.tag.addr, data, vif0.vifpacketsize); + vif0.tag.addr += vif0.vifpacketsize << 2; + vif0.tag.size -= vif0.vifpacketsize; + return vif0.vifpacketsize; + } else { + int ret; + _vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); + ret = vif0.tag.size; + vif0.tag.size = 0; + vif0.cmd = 0; + return ret; + } +} + +static int Vif0TransUnpack(u32 *data){ // UNPACK + FreezeXMMRegs(1); + if (vif0.vifpacketsize < vif0.tag.size) { + /* size is less that the total size, transfer is + 'in pieces' */ + VIFunpack(data, &vif0.tag, vif0.vifpacketsize, VIF0dmanum); + // g_vifCycles+= size >> 1; + //vif0.tag.addr += size << 2; + vif0.tag.size -= vif0.vifpacketsize; + FreezeXMMRegs(0); + return vif0.vifpacketsize; + } else { + int ret; + /* we got all the data, transfer it fully */ + VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); + //g_vifCycles+= vif0.tag.size >> 1; + ret = vif0.tag.size; + vif0.tag.size = 0; + vif0.cmd = 0; + FreezeXMMRegs(0); + return ret; + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif0 CMD Base Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void Vif0CMDNop(){ // NOP + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTCycl(){ // STCYCL + vif0Regs->cycle.cl = (u8)vif0Regs->code; + vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDITop(){ // ITOP + vif0Regs->itops = vif0Regs->code & 0x3ff; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMod(){ // STMOD + vif0Regs->mode = vif0Regs->code & 0x3; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMark(){ // MARK + vif0Regs->mark = (u16)vif0Regs->code; + vif0Regs->stat |= VIF0_STAT_MRK; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDFlushE(){ // FLUSHE + vif0FLUSH(); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCALF(){ //MSCAL/F + vuExecMicro( (u16)(vif0Regs->code) << 3, VIF0dmanum ); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCNT(){ // MSCNT + vuExecMicro( -1, VIF0dmanum ); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMask(){ // STMASK + vif0.tag.size = 1; +} + +static void Vif0CMDSTRowCol(){// STROW / STCOL + vif0.tag.addr = 0; + vif0.tag.size = 4; +} + +static void Vif0CMDMPGTransfer(){ // MPG + int vifNum; + vif0FLUSH(); + vifNum = (u8)(vif0Regs->code >> 16); + if (vifNum == 0) vifNum = 256; + vif0.tag.addr = (u16)(vif0Regs->code) << 3; + vif0.tag.size = vifNum * 2; +} + +static void Vif0CMDNull(){ // invalid opcode + // if ME1, then force the vif to interrupt + if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); + vif0Regs->stat |= 1 << 13; + vif0.irq++; + } + vif0.cmd &= ~0x7f; +} + +int VIF0transfer(u32 *data, int size, int istag) { + int ret; + int transferred=vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + //vif0.irqoffset = 0; +#ifdef VIF_LOG + VIF_LOG( "VIF0transfer: size %x (vif0.cmd %x)\n", size, vif0.cmd ); +#endif + + vif0.stallontag = 0; + vif0.vifstalled = 0; + vif0.vifpacketsize = size; + + + while (vif0.vifpacketsize > 0) { + + if (vif0.cmd) { + //vif0Regs->stat |= VIF0_STAT_VPS_T; + ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data); + data+= ret; vif0.vifpacketsize-= ret; + //vif0Regs->stat &= ~VIF0_STAT_VPS_T; + continue; + } + + vif0Regs->stat &= ~VIF0_STAT_VPS_W; + + if(vif0.tag.size != 0) SysPrintf("no vif0 cmd but tag size is left last cmd read %x\n", vif0Regs->code); + // if interrupt and new cmd is NOT MARK + if(vif0.irq) { + break; + } + + vif0.cmd = (data[0] >> 24); + vif0Regs->code = data[0]; + + + //vif0Regs->stat |= VIF0_STAT_VPS_D; + if ((vif0.cmd & 0x60) == 0x60) { + vif0UNPACK(data); + } else { +#ifdef VIF_LOG + VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size ); +#endif + if((vif0.cmd & 0x7f) > 0x4A){ + if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); + vif0Regs->stat |= 1 << 13; + vif0.irq++; + } + vif0.cmd = 0; + } else Vif0CMDTLB[(vif0.cmd & 0x7f)](); + } + //vif0Regs->stat &= ~VIF0_STAT_VPS_D; + if(vif0.tag.size > 0) vif0Regs->stat |= VIF0_STAT_VPS_W; + ++data; + --vif0.vifpacketsize; + + if ((vif0.cmd & 0x80)) { //i bit on vifcode and not masked by VIF0_ERR + if(!(vif0Regs->err & 0x1)){ +#ifdef VIF_LOG + VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif0.cmd, psHu32(INTC_MASK) ); +#endif + + ++vif0.irq; + if(istag && vif0.tag.size <= vif0.vifpacketsize) vif0.stallontag = 1; + } + vif0.cmd &= 0x7f; + } + } + transferred += size - vif0.vifpacketsize; + g_vifCycles+= (transferred >> 2)*BIAS; /* guessing */ + // use tag.size because some game doesn't like .cmd + //if( !vif0.cmd ) + if( !vif0.tag.size ) + vif0Regs->stat &= ~VIF0_STAT_VPS_W; + + if (vif0.irq && vif0.tag.size == 0) { + vif0.vifstalled = 1; + + if(((vif0Regs->code >> 24) & 0x7f) != 0x7)vif0Regs->stat|= VIF0_STAT_VIS; + //else SysPrintf("VIF0 IRQ on MARK\n"); + // spiderman doesn't break on qw boundaries + vif0.irqoffset = transferred%4; // cannot lose the offset + + if( istag ) { + return -2; + } + + transferred = transferred >> 2; + vif0ch->madr+= (transferred << 4); + vif0ch->qwc-= transferred; + //SysPrintf("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return -2; + } + + if( !istag ) { + transferred = transferred >> 2; + vif0ch->madr+= (transferred << 4); + vif0ch->qwc-= transferred; + } + + return 0; +} + +int _VIF0chain() { + u32 *pMem; + u32 qwc = vif0ch->qwc; + u32 ret; + + if (vif0ch->qwc == 0 && vif0.vifstalled == 0) return 0; + + pMem = (u32*)dmaGetAddr(vif0ch->madr); + if (pMem == NULL) + return -1; + + if( vif0.vifstalled ) { + ret = VIF0transfer(pMem+vif0.irqoffset, vif0ch->qwc*4-vif0.irqoffset, 0); + } + else { + ret = VIF0transfer(pMem, vif0ch->qwc*4, 0); + } + /*vif0ch->madr+= (vif0ch->qwc << 4); + vif0ch->qwc-= qwc;*/ + + return ret; +} + + +int _chainVIF0() { + int id; + u32 *ptag; + //int done=0; + int ret; + + ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + SysPrintf("Vif0 Tag BUSERR\n"); + vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return -1; //Return -1 as an error has occurred + } + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + vif0ch->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + vif0ch->madr = ptag[1]; //MADR = ADDR field + g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag +#ifdef VIF_LOG + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + ptag[1], ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); +#endif + + vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + // Transfer dma tag if tte is set + + if (vif0ch->chcr & 0x40) { + if(vif0.vifstalled == 1) ret = VIF0transfer(ptag+(2+vif0.irqoffset), 2-vif0.irqoffset, 1); //Transfer Tag on stall + else ret = VIF0transfer(ptag+2, 2, 1); //Transfer Tag + if (ret == -1) return -1; //There has been an error + if (ret == -2) { + //SysPrintf("VIF0 Stall on tag %x\n", vif0.irqoffset); + //vif0.vifstalled = 1; + return vif0.done; //IRQ set by VIFTransfer + } + } + + vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); + +#ifdef VIF_LOG + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + ptag[1], ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); +#endif + + //done |= hwDmacSrcChainWithStack(vif0ch, id); + ret = _VIF0chain(); //Transfers the data set by the switch + if (ret == -1) { return -1; } //There's been an error + if (ret == -2) { //IRQ has been set by VifTransfer + //vif0.vifstalled = 1; + return vif0.done; + } + + //if(id == 7)vif0ch->tadr = vif0ch->madr; + + vif0.vifstalled = 0; + + if ((vif0ch->chcr & 0x80) && (ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef VIF_LOG + VIF_LOG( "dmaIrq Set\n" ); +#endif + //SysPrintf("VIF0 TIE\n"); + //SysPrintf( "VIF0dmaIrq Set\n" ); + //vif0ch->qwc = 0; + //vif0Regs->stat|= VIF0_STAT_VIS; //Set the Tag Interrupt flag of VIF0_STAT + vif0.done = 1; + return vif0.done; //End Transfer + } + return vif0.done; //Return Done +} + +void vif0Interrupt() { + int ret; + g_vifCycles = 0; //Reset the cycle count, Wouldnt reset on stall if put lower down. +#ifdef VIF_LOG + VIF_LOG("vif0Interrupt: %8.8x\n", cpuRegs.cycle); +#endif + + //if(vif0.vifstalled == 1) { + if(vif0.irq && vif0.tag.size == 0) { + vif0Regs->stat|= VIF0_STAT_INT; + hwIntcIrq(VIF0intc); + --vif0.irq; + + if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) + { + vif0Regs->stat&= ~0xF000000; // FQC=0 + vif0ch->chcr &= ~0x100; + cpuRegs.interrupt &= ~1; + return; + } + if(vif0ch->qwc > 0 || vif0.irqoffset > 0){ + if(vif0.stallontag == 1) { + _chainVIF0(); + } + else _VIF0chain(); + INT(0, g_vifCycles); + return; + } + } + + //} + if((vif0ch->chcr & 0x100) == 0) { + SysPrintf("Vif0 running when CHCR = %x\n", vif0ch->chcr); + /*prevviftag = NULL; + prevvifcycles = 0; + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); + hwIntcIrq(VIF1intc); + vif1Regs->stat&= ~0x1F000000; // FQC=0 + return 1;*/ + } + if (vif0ch->chcr & 0x4 && vif0.done == 0 && vif0.vifstalled == 0) { + + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + SysPrintf("vif0 dma masked\n"); + return; + } + + if(vif0ch->qwc > 0) _VIF0chain(); + ret = _chainVIF0(); + INT(0, g_vifCycles); + return; + //if(ret!=2) + /*else*/ //return 1; + } + + + if(vif0ch->qwc > 0) SysPrintf("VIF0 Ending with QWC left\n"); + if(vif0.cmd != 0) SysPrintf("vif0.cmd still set %x\n", vif0.cmd); + vif0ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF0); + vif0Regs->stat&= ~0xF000000; // FQC=0 + + cpuRegs.interrupt &= ~1; +} + +// Vif1 Data Transfer Table +int (*Vif0TransTLB[128])(u32 *data) = +{ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ + Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ + Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ + Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ +}; + +// Vif1 CMD Table +void (*Vif0CMDTLB[75])() = +{ + Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ + Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ + Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ + Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer +}; + +void dmaVIF0() { + +#ifdef VIF_LOG + VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + vif0ch->chcr, vif0ch->madr, vif0ch->qwc, + vif0ch->tadr, vif0ch->asr0, vif0ch->asr1 ); +#endif + + /* Check if there is a pending irq */ + /*if (vif0.irq > 0) { + vif0.irq--; + hwIntcIrq(VIF0intc); + return; + }*/ +// if(vif0ch->qwc > 0) { +// _VIF0chain(); +// INT(0, g_vifCycles); +// } + g_vifCycles = 0; + + + vif0Regs->stat|= 0x8000000; // FQC=8 + + if (!(vif0ch->chcr & 0x4) || vif0ch->qwc > 0) { // Normal Mode + if(_VIF0chain() == -2) { + SysPrintf("Stall on normal %x\n", vif0Regs->stat); + //vif0.vifstalled = 1; + return; + } + vif0.done = 1; + INT(0, g_vifCycles); + return; + } + +/* if (_VIF0chain() != 0) { + INT(0, g_vifCycles); + return; + }*/ + // Chain Mode + vif0.done = 0; + INT(0, g_vifCycles); +} + + +void vif0Write32(u32 mem, u32 value) { + if (mem == 0x10003830) { // MARK +#ifdef VIF_LOG + VIF_LOG("VIF0_MARK write32 0x%8.8x\n", value); +#endif + /* Clear mark flag in VIF0_STAT and set mark with 'value' */ + vif0Regs->stat&= ~VIF0_STAT_MRK; + vif0Regs->mark = value; + } else + if (mem == 0x10003810) { // FBRST +#ifdef VIF_LOG + VIF_LOG("VIF0_FBRST write32 0x%8.8x\n", value); +#endif + if (value & 0x1) { + /* Reset VIF */ + //SysPrintf("Vif0 Reset %x\n", vif0Regs->stat); + memset(&vif0, 0, sizeof(vif0)); + vif0ch->qwc = 0; //? + psHu64(0x10004000) = 0; + psHu64(0x10004008) = 0; + vif0.done = 1; + vif0Regs->err = 0; + vif0Regs->stat&= ~(0xF000000|VIF0_STAT_INT|VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS); // FQC=0 + } + if (value & 0x2) { + /* Force Break the VIF */ + /* I guess we should stop the VIF dma here + but not 100% sure (linuz) */ + vif0Regs->stat |= VIF0_STAT_VFS; + SysPrintf("vif0 force break\n"); + } + if (value & 0x4) { + /* Stop VIF */ + /* Not completly sure about this, can't remember what game + used this, but 'draining' the VIF helped it, instead of + just stoppin the VIF (linuz) */ + vif0Regs->stat |= VIF0_STAT_VSS; + //SysPrintf("Vif0 Stop\n"); + //dmaVIF0(); // Drain the VIF --- VIF Stops as not to outstrip dma source (refraction) + //FreezeXMMRegs(0); + } + if (value & 0x8) { + int cancel = 0; + + /* Cancel stall, first check if there is a stall to cancel, + and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) { + cancel = 1; + } + + vif0Regs->stat &= ~(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | + VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); + if (cancel) { + //SysPrintf("VIF0 Stall Resume\n"); + if( vif0.vifstalled ) { + // loop necessary for spiderman + if(vif0.stallontag == 1){ + //SysPrintf("Sorting VIF0 Stall on tag\n"); + _chainVIF0(); + } else _VIF0chain(); + + vif0ch->chcr |= 0x100; + INT(0, g_vifCycles); // Gets the timing right - Flatout + } + } + } + } else + if (mem == 0x10003820) { // ERR +#ifdef VIF_LOG + VIF_LOG("VIF0_ERR write32 0x%8.8x\n", value); +#endif + /* Set VIF0_ERR with 'value' */ + vif0Regs->err = value; + } else{ + SysPrintf("Unknown Vif0 write to %x\n", mem); + if( mem >= 0x10003900 && mem < 0x10003980 ) { + + assert( (mem&0xf) == 0 ); + if( mem < 0x10003940 ) g_vifRow0[(mem>>4)&3] = value; + else g_vifCol0[(mem>>4)&3] = value; + } else psHu32(mem) = value; + } + + /* Other registers are read-only so do nothing for them */ +} + +void vif0Reset() { + /* Reset the whole VIF, meaning the internal pcsx2 vars + and all the registers */ + memset(&vif0, 0, sizeof(vif0)); + memset(vif0Regs, 0, sizeof(vif0Regs)); + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); + psHu64(0x10004000) = 0; + psHu64(0x10004008) = 0; + vif0.done = 1; + vif0Regs->stat&= ~0xF000000; // FQC=0 + //FreezeXMMRegs(0); + //FreezeMMXRegs(0); +} + +int vif0Freeze(gzFile f, int Mode) { + gzfreeze(&vif0, sizeof(vif0)); + if (Mode == 0) + SetNewMask(g_vif0Masks, g_vif0HasMask3, vif0Regs->mask, ~vif0Regs->mask); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +void vif1Init() { + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); +} + +__inline void vif1UNPACK(u32 *data) { + int vifNum; + int vl, vn; + //int len; + if(vif1Regs->cycle.wl == 0){ + if(vif1Regs->cycle.wl < vif1Regs->cycle.cl){ + SysPrintf("Vif1 CL %d, WL %d\n", vif1Regs->cycle.cl, vif1Regs->cycle.wl); + vif1.cmd &= ~0x7f; + return; +} + } + vif1FLUSH(); + + vl = (vif1.cmd ) & 0x3; + vn = (vif1.cmd >> 2) & 0x3; + + vif1.usn = (vif1Regs->code >> 14) & 0x1; + vifNum = (vif1Regs->code >> 16) & 0xff; + if ( vifNum == 0 ) vifNum = 256; + vif1Regs->num = vifNum; + + if ( vif1Regs->cycle.wl <= vif1Regs->cycle.cl ) { + vif1.tag.size = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; + } else { + int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + + _limit( vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl ); + vif1.tag.size = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; + } + if ( ( vif1Regs->code >> 15) & 0x1 ) { + vif1.tag.addr = (vif1Regs->code + vif1Regs->tops) & 0x3ff; + } else vif1.tag.addr = vif1Regs->code & 0x3ff; + + //vif1.wl = 0; + vif1.cl = 0; + vif1.tag.addr <<= 4; + //if((vif1.tag.addr + (vifNum * 16)) > 0x4000) SysPrintf("Oops, Addr %x, NUM %x overlaps to %x\n", vif1.tag.addr, vifNum, (vif1.tag.addr + (vifNum * 16))); + + vif1.tag.cmd = vif1.cmd; + // vif1Regs->offset = 0; +} + +__inline void _vif1mpgTransfer(u32 addr, u32 *data, int size) { +/* SysPrintf("_vif1mpgTransfer addr=%x; size=%x\n", addr, size); + { + FILE *f = fopen("vu1.raw", "wb"); + fwrite(data, 1, size*4, f); + fclose(f); + }*/ + assert( VU1.Micro > 0 ); + if (memcmp(VU1.Micro + addr, data, size << 2)) { + FreezeMMXRegs(1); + memcpy_fast(VU1.Micro + addr, data, size << 2); + FreezeMMXRegs(0); + Cpu->ClearVU1(addr, size); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 Data Transfer Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int Vif1TransNull(u32 *data){ // Shouldnt go here + SysPrintf("Shouldnt go here CMD = %x\n", vif1Regs->code); + vif1.cmd = 0; + return 0; +} +static int Vif1TransSTMask(u32 *data){ // STMASK + SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); + vif1Regs->mask = data[0]; +#ifdef VIF_LOG + VIF_LOG("STMASK == %x\n", vif1Regs->mask); +#endif + vif1.tag.size = 0; + vif1.cmd = 0; + return 1; +} + +static int Vif1TransSTRow(u32 *data){ + int ret; + + u32* pmem = &vif1Regs->r0+(vif1.tag.addr<<2); + u32* pmem2 = g_vifRow1+vif1.tag.addr; + assert( vif1.tag.addr < 4 ); + ret = min(4-vif1.tag.addr, vif1.vifpacketsize); + assert( ret > 0 ); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; +#ifdef _MSC_VER + default: __assume(0); +#endif + } + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if(vif1.tag.size == 0) vif1.cmd = 0; + + return ret; +} + +static int Vif1TransSTCol(u32 *data){ + int ret; + + u32* pmem = &vif1Regs->c0+(vif1.tag.addr<<2); + u32* pmem2 = g_vifCol1+vif1.tag.addr; + ret = min(4-vif1.tag.addr, vif1.vifpacketsize); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; +#ifdef _MSC_VER + default: __assume(0); +#endif + } + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if(vif1.tag.size == 0) vif1.cmd = 0; + return ret; +} + +static int Vif1TransMPG(u32 *data){ + if (vif1.vifpacketsize < vif1.tag.size) { + _vif1mpgTransfer(vif1.tag.addr, data, vif1.vifpacketsize); + vif1.tag.addr += vif1.vifpacketsize << 2; + vif1.tag.size -= vif1.vifpacketsize; + return vif1.vifpacketsize; + } else { + int ret; + _vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + return ret; + } +} +u32 splittransfer[4]; +u32 splitptr = 0; + +static int Vif1TransDirectHL(u32 *data){ + int ret = 0; + + + if(splitptr > 0){ //Leftover data from the last packet, filling the rest and sending to the GS + if(splitptr < 4 && vif1.vifpacketsize >= (4-splitptr)){ + + while(splitptr < 4){ + splittransfer[splitptr++] = (u32)data++; + ret++; + vif1.tag.size--; + } + } + //if(splitptr < 4) SysPrintf("Whoopsie\n"); + if( CHECK_MULTIGS ) { + u8* gsmem = GSRingBufCopy((u32*)splittransfer[0], 16, GS_RINGTYPE_P2); + if( gsmem != NULL ) { + FreezeMMXRegs(1); + memcpy_fast(gsmem, (u32*)splittransfer[0], 16); + GSRINGBUF_DONECOPY(gsmem, 16); + GSgifTransferDummy(1, (u32*)splittransfer[0], 1); + } + FreezeMMXRegs(0); + if( !CHECK_DUALCORE ) GS_SETEVENT(); + } + else { + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GSGIFTRANSFER2((u32*)splittransfer[0], 1); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } + + if(vif1.tag.size == 0) vif1.cmd = 0; + splitptr = 0; + return ret; + } + if (vif1.vifpacketsize < vif1.tag.size) { + if(vif1.vifpacketsize < 4 && splitptr != 4) { //Not a full QW left in the buffer, saving left over data + ret = vif1.vifpacketsize; + while(ret > 0){ + splittransfer[splitptr++] = (u32)data++; + vif1.tag.size--; + ret--; + } + //if(vif1.tag.size < 0) SysPrintf("Help\n"); + return vif1.vifpacketsize; + } //else if(vif1.vifpacketsize%4 != 0) SysPrintf("Size left = %x, non-qw aligned amount == %x\n", vif1.vifpacketsize, vif1.vifpacketsize%4); + + vif1.tag.size-= vif1.vifpacketsize; + ret = vif1.vifpacketsize; + } else { + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + } + + + + if( CHECK_MULTIGS ) { + u8* gsmem = GSRingBufCopy(data, ret<<2, GS_RINGTYPE_P2); + + if( gsmem != NULL ) { + FreezeMMXRegs(1); + memcpy_fast(gsmem, data, ret<<2); + FreezeMMXRegs(0); + GSRINGBUF_DONECOPY(gsmem, ret<<2); + GSgifTransferDummy(1, data, ret>>2); + } + + if( !CHECK_DUALCORE ) GS_SETEVENT(); + } + else { + + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GSGIFTRANSFER2(data, (ret >> 2)); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } + + + return ret; +} + + +static int Vif1TransUnpack(u32 *data){ + + FreezeXMMRegs(1); + + if (vif1.vifpacketsize < vif1.tag.size) { + /* size is less that the total size, transfer is + 'in pieces' */ + VIFunpack(data, &vif1.tag, vif1.vifpacketsize, VIF1dmanum); + // g_vifCycles+= size >> 1; + //vif1.tag.addr += size << 2; + vif1.tag.size -= vif1.vifpacketsize; + FreezeXMMRegs(0); + return vif1.vifpacketsize; + } else { + int ret; + /* we got all the data, transfer it fully */ + VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); + //g_vifCycles+= vif1.tag.size >> 1; + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + FreezeXMMRegs(0); + return ret; + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 CMD Base Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int transferred = 0; +int Path3transfer=0; +static void Vif1CMDNop(){ // NOP + vif1.cmd &= ~0x7f; +} +static void Vif1CMDSTCycl(){ // STCYCL + vif1Regs->cycle.cl = (u8)vif1Regs->code; + vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDOffset(){ // OFFSET + vif1Regs->ofst = vif1Regs->code & 0x3ff; + vif1Regs->stat &= ~0x80; + vif1Regs->tops = vif1Regs->base; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDBase(){ // BASE + vif1Regs->base = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDITop(){ // ITOP + vif1Regs->itops = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDSTMod(){ // STMOD + vif1Regs->mode = vif1Regs->code & 0x3; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMskPath3(){ // MSKPATH3 + + vif1Regs->mskpath3 = (vif1Regs->code >> 15) & 0x1; + //SysPrintf("VIF MSKPATH3 %x\n", vif1Regs->mskpath3); +#ifdef GSPATH3FIX + + if ( (vif1Regs->code >> 15) & 0x1 ) { + while((gif->chcr & 0x100)){ //Can be done 2 different ways, depends on the game/company + if(path3hack == 0)if(Path3transfer == 0 && gif->qwc == 0) break; + + gsInterrupt(); + + if(path3hack == 1)if(gif->qwc == 0) break; //add games not working with it to elfheader.c to enable this instead + } + //while(gif->chcr & 0x100) gsInterrupt(); // Finish the transfer first + psHu32(GIF_STAT) |= 0x2; + } else { + if(gif->chcr & 0x100) INT(2, (transferred>>2) * BIAS); // Restart Path3 on its own, time it right! + psHu32(GIF_STAT) &= ~0x2; + } +#else + if ( vif1Regs->mskpath3 ) { + if(gif->qwc) _GIFchain(); // Finish the transfer first + psHu32(GIF_STAT) |= 0x2; + } else { + psHu32(GIF_STAT) &= ~0x2; + if(gif->qwc) _GIFchain(); // Finish the transfer first + } +#endif + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMark(){ // MARK + vif1Regs->mark = (u16)vif1Regs->code; + vif1Regs->stat |= VIF1_STAT_MRK; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDFlush(){ // FLUSH/E/A + + vif1FLUSH(); + + if((vif1.cmd & 0x7f) == 0x13) { + //SysPrintf("FlushA\n"); + while((gif->chcr & 0x100)){ + if(Path3transfer == 0 && gif->qwc == 0) break; + gsInterrupt(); + } + } + + vif1.cmd &= ~0x7f; +} +static void Vif1CMDMSCALF(){ //MSCAL/F + vuExecMicro( (u16)(vif1Regs->code) << 3, VIF1dmanum ); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDMSCNT(){ // MSCNT + vuExecMicro( -1, VIF1dmanum ); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDSTMask(){ // STMASK + vif1.tag.size = 1; +} +static void Vif1CMDSTRowCol(){// STROW / STCOL + vif1.tag.addr = 0; + vif1.tag.size = 4; +} + +static void Vif1CMDMPGTransfer(){ // MPG + int vifNum; + vif1FLUSH(); + vifNum = (u8)(vif1Regs->code >> 16); + if (vifNum == 0) vifNum = 256; + vif1.tag.addr = (u16)(vif1Regs->code) << 3; + vif1.tag.size = vifNum * 2; +} +static void Vif1CMDDirectHL(){ // DIRECT/HL + int vifImm; + vifImm = (u16)vif1Regs->code; + if (vifImm == 0) { + vif1.tag.size = 65536 << 2; + } else { + vif1.tag.size = vifImm << 2; + } + while((gif->chcr & 0x100) && (vif1.cmd & 0x7f) == 0x51){ + gsInterrupt(); //DirectHL flushes the lot + //if((psHu32(GIF_STAT) & 0xE00) == 0) break; + } +} +static void Vif1CMDNull(){ // invalid opcode + // if ME1, then force the vif to interrupt + + if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); + vif1Regs->stat |= 1 << 13; + vif1.irq++; + } + vif1.cmd = 0; +} + +// Vif1 Data Transfer Table + +int (*Vif1TransTLB[128])(u32 *data) = +{ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ + Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ + Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ + Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ + Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 CMD Table +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void (*Vif1CMDTLB[82])() = +{ + Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ + Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ + Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ + Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ + Vif1CMDDirectHL, Vif1CMDDirectHL +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int VIF1transfer(u32 *data, int size, int istag) { + int ret; + transferred=vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + +#ifdef VIF_LOG + VIF_LOG( "VIF1transfer: size %x (vif1.cmd %x)\n", size, vif1.cmd ); +#endif + + + vif1.irqoffset = 0; + vif1.vifstalled = 0; + vif1.stallontag = 0; + vif1.vifpacketsize = size; + + //vif1.irq = 0; + while (vif1.vifpacketsize > 0) { + + if (vif1.cmd) { + //vif1Regs->stat |= VIF1_STAT_VPS_T; + ret = Vif1TransTLB[vif1.cmd](data); + data+= ret; vif1.vifpacketsize-= ret; + //vif1Regs->stat &= ~VIF1_STAT_VPS_T; + continue; + } + + if(vif1.tag.size != 0) SysPrintf("no vif1 cmd but tag size is left last cmd read %x\n", vif1Regs->code); + //vif1Regs->stat &= ~VIF1_STAT_VPS_W; + + //if(vif1.tag.size > 0) SysPrintf("VIF1 Tag size %x when cmd == 0!\n", vif1.tag.size); + + + if(vif1.irq) break; + + vif1.cmd = (data[0] >> 24); + vif1Regs->code = data[0]; + + + //vif1Regs->stat |= VIF1_STAT_VPS_D; + if ((vif1.cmd & 0x60) == 0x60) { + vif1UNPACK(data); + } else { +#ifdef VIF_LOG + VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, vif1.vifpacketsize ); +#endif + //vif1CMD(data, size); + /*if((vif1.cmd & 0x7f) > 0x51){ + if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); + vif1Regs->stat |= 1 << 13; + vif1.irq++; + } + vif1.cmd = 0; + } else*/ Vif1CMDTLB[(vif1.cmd & 0x7f)](); + } + //vif1Regs->stat &= ~VIF1_STAT_VPS_D; + //if(vif1.tag.size > 0) vif1Regs->stat |= VIF1_STAT_VPS_W; + ++data; + --vif1.vifpacketsize; + + if ((vif1.cmd & 0x80)) { //i bit on vifcode and not masked by VIF1_ERR +#ifdef VIF_LOG + VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif1.cmd, psHu32(INTC_MASK) ); +#endif + /*if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ + SysPrintf("VIF1 Stall on MFIFO, not implemented!\n"); + }*/ + + if(!(vif1Regs->err & 0x1)){ + ++vif1.irq; + if(istag && vif1.tag.size <= vif1.vifpacketsize) vif1.stallontag = 1; + } + vif1.cmd &= 0x7f; + } + } + //if(vif1.cmd != 0 && vif1.tag.size == 0) SysPrintf("cmd but no tag size is left %x\n", vif1.cmd); + //if(vif1.cmd == 0 && vif1.tag.size != 0) SysPrintf("no cmd but tag size is left last cmd read %x\n", vif1Regs->code); + transferred += size - vif1.vifpacketsize; + g_vifCycles+= (transferred>>2)*BIAS; /* guessing */ + // use tag.size because some game doesn't like .cmd + //if( !vif1.cmd ) + //if( !vif1.tag.size ) + // vif1Regs->stat &= ~VIF1_STAT_VPS_W; + + if (vif1.irq && vif1.tag.size == 0) { + vif1.vifstalled = 1; + if(((vif1Regs->code >> 24) & 0x7f) != 0x7)vif1Regs->stat|= VIF1_STAT_VIS; + //else SysPrintf("Stall on Vif1 MARK\n"); + // spiderman doesn't break on qw boundaries + vif1.irqoffset = transferred%4; // cannot lose the offset + + if( istag ) { + return -2; + } + + transferred = transferred >> 2; + vif1ch->madr+= (transferred << 4); + vif1ch->qwc-= transferred; + //SysPrintf("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return -2; + } + + + if( !istag ) { + /*if(transferred & 0x3) vif1.irqoffset = transferred%4; + else vif1.irqoffset = 0;*/ + + transferred = transferred >> 2; + vif1ch->madr+= (transferred << 4); + vif1ch->qwc-= transferred; + + //if(vif1ch->qwc > 0 && size != 0) vif1.vifstalled = 1; + + } + + + return 0; +} + +int _VIF1chain() { + u32 *pMem; + u32 qwc = vif1ch->qwc; + u32 ret; + + + if (vif1ch->qwc == 0 && vif1.vifstalled == 0) return 0; + + pMem = (u32*)dmaGetAddr(vif1ch->madr); + if (pMem == NULL) + return -1; + +#ifdef VIF_LOG + VIF_LOG("dmaChain size=%d, madr=%lx, tadr=%lx\n", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); +#endif + if( vif1.vifstalled ) { + ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); + } + else { + ret = VIF1transfer(pMem, vif1ch->qwc*4, 0); + } + /*vif1ch->madr+= (vif1ch->qwc << 4); + vif1ch->qwc-= qwc;*/ + + return ret; +} + +static int prevvifcycles = 0; +static u32* prevviftag = NULL; +u32 *vifptag; +int _chainVIF1() { + int id; + //int done=0; + int ret; + //g_vifCycles = prevvifcycles; + + vifptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR + if (vifptag == NULL) { //Is ptag empty? + SysPrintf("Vif1 Tag BUSERR\n"); + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vifptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return -1; //Return -1 as an error has occurred + } + + id = (vifptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + vif1ch->qwc = (u16)vifptag[0]; //QWC set to lower 16bits of the tag + vif1ch->madr = vifptag[1]; //MADR = ADDR field + g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag + + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vifptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + // Transfer dma tag if tte is set + + + + + +#ifdef VIF_LOG + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + vifptag[1], vifptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); +#endif + + + //} else + + + if (!vif1.done && (psHu32(DMAC_CTRL) & 0xC0) == 0x40 && id == 4) { // STD == VIF1 + //vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); + // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall + if( (vif1ch->madr + vif1ch->qwc * 16) >= psHu32(DMAC_STADR) ) { + // stalled + + //SysPrintf("Vif1 Stalling %x, %x, DMA_CTRL = %x\n",vif1ch->madr, psHu32(DMAC_STADR), psHu32(DMAC_CTRL)); + /*prevvifcycles = g_vifCycles; + prevviftag = vifptag;*/ + hwDmacIrq(13); + //vif1ch->tadr -= 16; + return 0; + } + } + //prevvifcycles = 0; + + if (vif1ch->chcr & 0x40) { + if(vif1.vifstalled == 1) ret = VIF1transfer(vifptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on stall + else ret = VIF1transfer(vifptag+2, 2, 1); //Transfer Tag + if (ret == -1) return -1; //There has been an error + if (ret == -2) { + //if(vif1.tag.size > 0)SysPrintf("VIF1 Stall on tag %x code %x\n", vif1.irqoffset, vif1Regs->code); + return 0; //IRQ set by VIFTransfer + } + } + //if((psHu32(DMAC_CTRL) & 0xC0) != 0x40 || id != 4) + vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); + +#ifdef VIF_LOG + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + vifptag[1], vifptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); +#endif + + //done |= hwDmacSrcChainWithStack(vif1ch, id); + ret = _VIF1chain(); //Transfers the data set by the switch + //if (ret == -1) { return -1; } //There's been an error + //if (ret == -2) { //IRQ has been set by VifTransfer + // return 0; + //} + + + if ((vif1ch->chcr & 0x80) && (vifptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef VIF_LOG + VIF_LOG( "dmaIrq Set\n" ); +#endif + //SysPrintf("VIF1 TIE\n"); + //SysPrintf( "VIF1dmaIrq Set\n" ); + //vif1ch->qwc = 0; + //vif1Regs->stat|= VIF1_STAT_VIS; //Set the Tag Interrupt flag of VIF1_STAT + vif1.done = 1; + return 0; //End Transfer + } + return vif1.done; //Return Done +} + +void vif1Interrupt() { + +#ifdef VIF_LOG + VIF_LOG("vif1Interrupt: %8.8x\n", cpuRegs.cycle); +#endif + + g_vifCycles = 0; + + //if(vif1.vifstalled == 1) { + if(vif1.irq && vif1.tag.size == 0) { + vif1Regs->stat|= VIF1_STAT_INT; + hwIntcIrq(VIF1intc); + --vif1.irq; + if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) + { + vif1Regs->stat&= ~0x1F000000; // FQC=0 + // One game doesnt like vif stalling at end, cant remember what. Spiderman isnt keen on it tho + vif1ch->chcr &= ~0x100; + cpuRegs.interrupt &= ~(1 << 1); + return; + } + //return 0; + if(vif1ch->qwc > 0 || vif1.irqoffset > 0){ + if(vif1.stallontag == 1) { + _chainVIF1(); + } + else _VIF1chain(); + INT(1, g_vifCycles); + return; + } + } + + + //} + if((vif1ch->chcr & 0x100) == 0) { + SysPrintf("Vif1 running when CHCR == %x\n", vif1ch->chcr); + /*prevviftag = NULL; + prevvifcycles = 0; + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); + hwIntcIrq(VIF1intc); + vif1Regs->stat&= ~0x1F000000; // FQC=0 + return 1;*/ + } + /*if(vif1ch->qwc > 0){ + _VIF1chain(); + INT(1, g_vifCycles); + return 0; + }*/ + if ((vif1ch->chcr & 0x104) == 0x104 && vif1.done == 0) { + + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + SysPrintf("vif1 dma masked\n"); + return; + } + + _chainVIF1(); + INT(1, g_vifCycles); + + return; + } + if(vif1ch->qwc > 0) SysPrintf("VIF1 Ending with QWC left\n"); + if(vif1.cmd != 0) SysPrintf("vif1.cmd still set %x\n", vif1.cmd); + //SysPrintf("VIF Interrupt\n"); + //if((gif->chcr & 0x100) && vif1Regs->mskpath3) gsInterrupt(); + prevviftag = NULL; + prevvifcycles = 0; + + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); + if(vif1Regs->mskpath3 == 0 || (vif1ch->chcr & 0x1) == 0x1)vif1Regs->stat&= ~0x1F000000; // FQC=0 + + cpuRegs.interrupt &= ~(1 << 1); +} + +extern void gsWaitGS(); +extern u32 g_MTGSVifStart, g_MTGSVifCount; +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) +void dmaVIF1() +{ + +#ifdef VIF_LOG + VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + vif1ch->chcr, vif1ch->madr, vif1ch->qwc, + vif1ch->tadr, vif1ch->asr0, vif1ch->asr1 ); +#endif + + /*if ((psHu32(DMAC_CTRL) & 0xC0)) { + SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); + }*/ + /* Check if there is a pending irq */ + /*if (vif1.irq > 0) { + vif1.irq--; + hwIntcIrq(VIF1intc); + return; + }*/ +// if(vif1ch->qwc > 0) { +// _VIF1chain(); +// INT(1, g_vifCycles); +// } + vif1.done = 0; + g_vifCycles = 0; + + /*if( prevvifcycles != 0 ) { + int stallret = 0; + assert( prevviftag != NULL ); + + vifptag = prevviftag; + // transfer interrupted, so continue + //_VIF1chain(); + _chainVIF1(); + + if (vif1ch->chcr & 0x80 && vifptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag +#ifdef VIF_LOG + VIF_LOG("dmaIrq Set\n"); +#endif + vif1.done = 1; + INT(1, g_vifCycles); + return; + } + //vif1.done = 1; + INT(1, g_vifCycles); + return; + }*/ + + if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) { // VIF MFIFO + //SysPrintf("VIFMFIFO\n"); + if(!(vif1ch->chcr & 0x4)) SysPrintf("MFIFO mode != Chain! %x\n", vif1ch->chcr); + if(vif1ch->madr != spr0->madr)vifMFIFOInterrupt(); + return; + } + +#ifdef PCSX2_DEVBUILD + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { // STD == VIF1 + //SysPrintf("VIF Stall Control Source = %x, Drain = %x\n", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); + //return; + } +#endif + + + vif1Regs->stat|= 0x10000000; // FQC=16 + + if (!(vif1ch->chcr & 0x4) || vif1ch->qwc > 0) { // Normal Mode + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { + SysPrintf("DMA Stall Control on VIF1 normal\n"); + } + if ((vif1ch->chcr & 0x1)) { // to Memory + if(_VIF1chain() == -2) { + SysPrintf("Stall on normal\n"); + vif1.vifstalled = 1; + return; + } + INT(1, g_vifCycles); + } else { // from Memory + + + + if( CHECK_MULTIGS ) { + u8* pTempMem, *pEndMem; + + u8* pMem = GSRingBufCopy(NULL, 0, GS_RINGTYPE_VIFFIFO); + *(u32*)(pMem-16) = GS_RINGTYPE_VIFFIFO|(vif1ch->qwc<<16); // hack + *(u32*)(pMem-12) = vif1ch->madr; + *(u32*)(pMem-8) = cpuRegs.cycle; + + // touch all the pages to make sure they are in memory + pTempMem = dmaGetAddr(vif1ch->madr); + pEndMem = (u8*)((uptr)(pTempMem + vif1ch->qwc*16 + 0xfff)&~0xfff); + pTempMem = (u8*)((uptr)pTempMem&~0xfff); + while(pTempMem < pEndMem ) { + pTempMem[0]++; + pTempMem[0]--; + pTempMem += 0x1000; + } + + GSRINGBUF_DONECOPY(pMem, 0); + + if( !CHECK_DUALCORE ) + GS_SETEVENT(); + + g_MTGSVifStart = cpuRegs.cycle; + g_MTGSVifCount = 4000000; // a little less than 1/60th of a second + + // wait is, the safest option + //gsWaitGS(); + //SysPrintf("waiting for gs\n"); + } + else { + + int size; + u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); + if (pMem == NULL) { //Is ptag empty? + SysPrintf("Vif1 Tag BUSERR\n"); + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + vif1.done = 1; + vif1Regs->stat&= ~0x1f000000; + vif1ch->qwc = 0; + INT(1, g_vifCycles); + + return; //Return -1 as an error has occurred + } + FreezeXMMRegs(1); + if( GSreadFIFO2 == NULL ) { + for (size=vif1ch->qwc; size>0; --size) { + if (size > 1) GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); + pMem[0] = psHu64(0x5000); + pMem[1] = psHu64(0x5008); pMem+= 2; + } + } + else { + GSreadFIFO2(pMem, vif1ch->qwc); + + // set incase read + psHu64(0x5000) = pMem[2*vif1ch->qwc-2]; + psHu64(0x5008) = pMem[2*vif1ch->qwc-1]; + } + FreezeXMMRegs(0); + + + if(vif1Regs->mskpath3 == 0)vif1Regs->stat&= ~0x1f000000; + g_vifCycles += vif1ch->qwc * 2; + vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes + vif1ch->qwc = 0; + INT(1, g_vifCycles); + } + + } + + vif1.done = 1; + return; + } + +/* if (_VIF1chain() != 0) { + INT(1, g_vifCycles); + return; + }*/ + + // Chain Mode + vif1.done = 0; + INT(1, g_vifCycles); +} + + +void vif1Write32(u32 mem, u32 value) { + if (mem == 0x10003c30) { // MARK +#ifdef VIF_LOG + VIF_LOG("VIF1_MARK write32 0x%8.8x\n", value); +#endif + /* Clear mark flag in VIF1_STAT and set mark with 'value' */ + vif1Regs->stat&= ~VIF1_STAT_MRK; + vif1Regs->mark = value; + } else + if (mem == 0x10003c10) { // FBRST +#ifdef VIF_LOG + VIF_LOG("VIF1_FBRST write32 0x%8.8x\n", value); +#endif + if (value & 0x1) { + /* Reset VIF */ + //SysPrintf("Vif1 Reset %x\n", vif1Regs->stat); + memset(&vif1, 0, sizeof(vif1)); + vif1ch->qwc = 0; //? + psHu64(0x10005000) = 0; + psHu64(0x10005008) = 0; + vif1.done = 1; + vif1Regs->err = 0; + vif1Regs->stat&= ~(0x1F800000|VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS); // FQC=0 + } + if (value & 0x2) { + /* Force Break the VIF */ + /* I guess we should stop the VIF dma here + but not 100% sure (linuz) */ + vif1Regs->stat |= VIF1_STAT_VFS; + cpuRegs.interrupt &= ~0x402; + vif1.vifstalled = 1; + SysPrintf("vif1 force break\n"); + } + if (value & 0x4) { + /* Stop VIF */ + /* Not completly sure about this, can't remember what game + used this, but 'draining' the VIF helped it, instead of + just stoppin the VIF (linuz) */ + vif1Regs->stat |= VIF1_STAT_VSS; + vif1.vifstalled = 1; + //SysPrintf("Vif1 Stop\n"); + //dmaVIF1(); // Drain the VIF --- VIF Stops as not to outstrip dma source (refraction) + //FreezeXMMRegs(0); + } + if (value & 0x8) { + int cancel = 0; + + /* Cancel stall, first check if there is a stall to cancel, + and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { + cancel = 1; + } + + vif1Regs->stat &= ~(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | + VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); + if (cancel) { + //SysPrintf("VIF1 Stall Resume\n"); + if( vif1.vifstalled ) { + // loop necessary for spiderman + if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ + //vif1.vifstalled = 0; + //SysPrintf("MFIFO Stall\n"); + INT(10, 0); + }else { + if(vif1.stallontag == 1){ + //SysPrintf("Sorting VIF Stall on tag\n"); + _chainVIF1(); + } else _VIF1chain(); + //vif1.vifstalled = 0' + INT(1, g_vifCycles); // Gets the timing right - Flatout + } + vif1ch->chcr |= 0x100; + } + } + } + } else + if (mem == 0x10003c20) { // ERR +#ifdef VIF_LOG + VIF_LOG("VIF1_ERR write32 0x%8.8x\n", value); +#endif + /* Set VIF1_ERR with 'value' */ + vif1Regs->err = value; + } else + if (mem == 0x10003c00) { // STAT +#ifdef VIF_LOG + VIF_LOG("VIF1_STAT write32 0x%8.8x\n", value); +#endif + +#ifdef PCSX2_DEVBUILD + /* Only FDR bit is writable, so mask the rest */ + if( (vif1Regs->stat & VIF1_STAT_FDR) ^ (value & VIF1_STAT_FDR) ) { + // different so can't be stalled + if (vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { + SysPrintf("changing dir when vif1 fifo stalled\n"); + } + } +#endif + + vif1Regs->stat = (vif1Regs->stat & ~VIF1_STAT_FDR) | (value & VIF1_STAT_FDR); + if (vif1Regs->stat & VIF1_STAT_FDR) { + vif1Regs->stat|= 0x01000000; + } else { + vif1ch->qwc = 0; + vif1.vifstalled = 0; + vif1.done = 1; + vif1Regs->stat&= ~0x1F000000; // FQC=0 + } + } + else + if (mem == 0x10003c50) { // MODE + vif1Regs->mode = value; + } + else { + SysPrintf("Unknown Vif1 write to %x\n", mem); + if( mem >= 0x10003d00 && mem < 0x10003d80 ) { + assert( (mem&0xf) == 0 ); + if( mem < 0x10003d40) g_vifRow1[(mem>>4)&3] = value; + else g_vifCol1[(mem>>4)&3] = value; + } else psHu32(mem) = value; + } + + /* Other registers are read-only so do nothing for them */ +} + +void vif1Reset() { + /* Reset the whole VIF, meaning the internal pcsx2 vars + and all the registers */ + memset(&vif1, 0, sizeof(vif1)); + memset(vif1Regs, 0, sizeof(vif1Regs)); + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); + psHu64(0x10005000) = 0; + psHu64(0x10005008) = 0; + vif1.done = 1; + vif1Regs->stat&= ~0x1F000000; // FQC=0 + /*FreezeXMMRegs(0); + FreezeMMXRegs(0);*/ +} + +int vif1Freeze(gzFile f, int Mode) { + gzfreeze(&vif1, sizeof(vif1)); + if (Mode == 0) + SetNewMask(g_vif1Masks, g_vif1HasMask3, vif1Regs->mask, ~vif1Regs->mask); + + return 0; +} diff --git a/pcsx2/VifDma.h b/pcsx2/VifDma.h new file mode 100644 index 0000000000..a9f19362c7 --- /dev/null +++ b/pcsx2/VifDma.h @@ -0,0 +1,98 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __VIFDMA_H__ +#define __VIFDMA_H__ + +typedef struct { + u32 addr; + u32 size; + u32 cmd; + u16 wl; + u16 cl; +} vifCode; + +// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito +typedef struct { + vifCode tag; + int cmd; + int irq; + int cl; + int wl; + u8 usn; + u8 done; + u8 vifstalled; + u8 stallontag; + u8 irqoffset; // 32bit offset where next vif code is + u32 savedtag; // need this for backwards compat with save states + u32 vifpacketsize; +} vifStruct; + +extern vifStruct vif0, vif1; + +#define vif0ch ((DMACh*)&PS2MEM_HW[0x8000]) +#define vif1ch ((DMACh*)&PS2MEM_HW[0x9000]) + +void UNPACK_S_32( u32 *dest, u32 *data, int size ); + +void UNPACK_S_16u( u32 *dest, u32 *data, int size ); +void UNPACK_S_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_S_8u( u32 *dest, u32 *data, int size ); +void UNPACK_S_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V2_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V2_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V3_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V3_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V4_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V4_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_5( u32 *dest, u32 *data, int size ); + +void vifDmaInit(); +void vif0Init(); +void vif1Init(); +void vif0Interrupt(); +void vif1Interrupt(); + +void vif0Write32(u32 mem, u32 value); +void vif1Write32(u32 mem, u32 value); + +void vif0Reset(); +void vif1Reset(); +int vif0Freeze(gzFile f, int Mode); +int vif1Freeze(gzFile f, int Mode); + +#endif diff --git a/pcsx2/build.sh b/pcsx2/build.sh new file mode 100644 index 0000000000..ff9a9cfd5d --- /dev/null +++ b/pcsx2/build.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# Pcsx2 - Pc Ps2 Emulator +# Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# + +echo --------------- +echo Building Pcsx2 +echo --------------- + +if [ $# -gt 0 ] && [ $1 = "all" ] +then + +aclocal +automake +autoconf +chmod +x configure +./configure ${PCSX2OPTIONS} +make clean +make install + +else + +make $@ + +#if [ $? -ne 0 ] +#then +#exit 1 +#fi + +#if [ $# -eq 0 ] || [ $1 != "clean" ] +#then +#make install +#fi + +fi + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/pcsx2/cheatscpp.h b/pcsx2/cheatscpp.h new file mode 100644 index 0000000000..3a8ac28b98 --- /dev/null +++ b/pcsx2/cheatscpp.h @@ -0,0 +1,48 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef CHEATSCPP_H_INCLUDED +#define CHEATSCPP_H_INCLUDED + +class Group +{ +public: + string title; + bool enabled; + int parentIndex; + + Group(int nParent,bool nEnabled, string &nTitle); + +}; + +class Patch +{ +public: + string title; + int group; + bool enabled; + int patchIndex; + + Patch(int patch, int grp, bool en, string &ttl); + + Patch operator =(const Patch&p); +}; + +extern vector groups; +extern vector patches; + +#endif//CHEATSCPP_H_INCLUDED diff --git a/pcsx2/configure.ac b/pcsx2/configure.ac new file mode 100644 index 0000000000..e80ac00e12 --- /dev/null +++ b/pcsx2/configure.ac @@ -0,0 +1,145 @@ +AC_INIT(pcsx2,0.9.4,zerofrog@gmail.com) + +AM_INIT_AUTOMAKE(pcsx2,0.9.4) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) + +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +CFLAGS= +CPPFLAGS= +CXXFLAGS= +CCASFLAGS= + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), + debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+=" -g " + CPPFLAGS+=" -g " + CXXFLAGS+=" -g " + CCASFLAGS+=" -D_DEBUG -g " + MYOBJDIR="Debug" +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+=" -O3 -fomit-frame-pointer " + CPPFLAGS+=" -O3 -fomit-frame-pointer " + CXXFLAGS+=" -O3 -fomit-frame-pointer " + MYOBJDIR="Release" +fi +AC_MSG_RESULT($debug) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl Check for dev build +AC_MSG_CHECKING(for development build) +AC_ARG_ENABLE(devbuild, AC_HELP_STRING([--enable-devbuild], [Special Build for developers that simplifies testing and adds extra checks]), + devbuild=$enableval,devbuild=no) +if test "x$devbuild" == xyes +then + AC_DEFINE(PCSX2_DEVBUILD,1,[PCSX2_DEVBUILD]) + MYOBJDIR=$MYOBJDIR"Dev" +fi +AC_MSG_RESULT($devbuild) + +AC_MSG_CHECKING(force sse3 instructions) +AC_ARG_ENABLE(sse3, AC_HELP_STRING([--enable-sse3], [Forces sse3 detection on CPUs]), + sse3=$enableval,sse3=no) +if test "x$sse3" == xyes +then + AC_DEFINE(PCSX2_FORCESSE3,1,[PCSX2_DEVBUILD]) +fi +AC_MSG_RESULT(sse3) + +dnl Check for virtual memory build +AC_MSG_CHECKING(for virtual memory build) +AC_ARG_ENABLE(vmbuild, AC_HELP_STRING([--enable-vmbuild], [Adds low level virtual memory support to run pcsx2 faster]), + vmbuild=$enableval,vmbuild=no) +if test "x$vmbuild" == xyes +then + AC_DEFINE(PCSX2_VIRTUAL_MEM,1,[PCSX2_VIRTUAL_MEM]) + MYOBJDIR=$MYOBJDIR"VM" +fi +AC_MSG_RESULT($vmbuild) + +dnl Check for recompilation +AC_MSG_CHECKING(for using platform dependent recompilers) +AC_ARG_ENABLE(recbuild, AC_HELP_STRING([--disable-recbuild], [Disable all architecture dependent recompilers]), + recbuild=$enableval,recbuild=yes) +if test "x$recbuild" == xno +then + AC_DEFINE(PCSX2_NORECBUILD,1,[PCSX2_NORECBUILD]) +fi +AC_MSG_RESULT($recbuild) +AM_CONDITIONAL(RECBUILD, test x$recbuild = xyes) + +dnl Check for 64bit CPU +AC_MSG_CHECKING(for a x86-64 CPU) +dnl if test "$build_os" == "target_os" +dnl then +AC_TRY_RUN([ +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} +],cpu64=yes,cpu64=no,) +dnl else +dnl cpu64=no +dnl fi +if test "x$cpu64" == xyes +then +AC_DEFINE(__x86_64__,1,[__x86_64__]) +CCASFLAGS="$CCASFLAGS -D__x86_64__" +fi +AC_MSG_RESULT($cpu64) +AM_CONDITIONAL(X86_64, test x$cpu64 = xyes) + +dnl gtk +AC_MSG_CHECKING(gtk+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0 gthread-2.0) + +dnl AC_CHECK_LIB(pthread,main,[LIBS="$LIBS -lpthread"]) +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) +AC_CHECK_LIB(z,main,[LIBS="$LIBS -lz"]) + +AC_CHECK_HEADER([libintl.h], [AC_DEFINE(ENABLE_NLS,1,[__x86_64__])]) + +AC_OUTPUT([ + Makefile + DebugTools/Makefile + Linux/Makefile + IPU/Makefile + IPU/mpeg2lib/Makefile + RDebug/Makefile + tinyxml/Makefile + x86/Makefile + x86/ix86/Makefile + zlib/Makefile + ]) + +dnl bindir = pcsx2exe + +echo "Configuration:" +echo " Target system type: $target" +echo " x86-64 build? $cpu64" +echo " Debug build? $debug" +echo " Dev build? $devbuild" +echo " Force sse3? $sse3" +echo " Recompilers enabled? $recbuild" +echo " Virtual memory build? $vmbuild" diff --git a/pcsx2/depcomp b/pcsx2/depcomp new file mode 100644 index 0000000000..88b3a13969 --- /dev/null +++ b/pcsx2/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/pcsx2/install-sh b/pcsx2/install-sh new file mode 100644 index 0000000000..4d4a9519ea --- /dev/null +++ b/pcsx2/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/pcsx2/missing b/pcsx2/missing new file mode 100644 index 0000000000..894e786e16 --- /dev/null +++ b/pcsx2/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, 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. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/pcsx2/mkinstalldirs b/pcsx2/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/pcsx2/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec 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. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/pcsx2/pcsxAbout.bmp b/pcsx2/pcsxAbout.bmp new file mode 100644 index 0000000000000000000000000000000000000000..da33bb08f4a3c365d835b0972a7dfbc43f8b01a2 GIT binary patch literal 251192 zcmce<2bf*QaVDz$-m@%<0U(ic1_Ff6XIuWB6)Z}& zf+bNDGjg68OaulwgF(#506~HPk<-lFI5~$q=lxaHU8l}DcZQI@eT%Qztgim6y1M$D z|Mm&@&Tst3M?U)BK1Kf?!hg5ozwiIMPkrhP{{QbjH6FG6yXE>%eTx3`|AKWROd08A z5t2=4R0%`htP$C0LKtHr06U^LbO3QEL&OZNRSd>m- zsEI1Axi@j)#kzcNm@cak&syt1;>03FwgAY|yrpT~%xvlS^zs|i%Wq1ryd||_bZRA+ zH50Sdvvcd`<<`y3uA7rvHz!*?D_b)Qb$!k4SJ&NDxBi~G+I#Ca+*iNh{)SBtG;De> zwdLW|)<;s?9!+igTzdOs=^anxcRkj!`;q3|kF@N0q<72Apynoj2-%P{FpbIziWHcF zp_ei;2p3nuzAL_(YA!>>YW0~E#8B|+T$E_C5H6y^L{OMVYUE^Sd)2cDf>(eDv8Eyg zEKOjf*xs0|-c(QzRwK%!H?N^td)duJ%&j-kFf7ax05MxN^j+n@7LNRR|GqpN>~34m&k6j}6Yizb)8l22!rd^)q}*V2nW zlUi~;mm5+`Zb&V?DZS#B^vY40wG*=yQ*sqkvK5oF<&$#d6Vv5W>MG~fRozOZdVc-7 z+w0fe(NKF=YQx7ep6LB+3Afgo}v%c3k=TN5!%){0RN&N&YkkCa zEy(Ad1}2}>=KE7y9!PC{D6{RM<{kI7>_oZ0W!D3(yB;XijC99RI2TTuhAM*eCgtR0 z)iBnjwlP;$uU%rBY+A4`qJnL&mE%b^6I2+SB>g0Z5R9w+!8wer`d2}NA**7MC{hF& z3o^hukSL|8vKm^AmC1=5b^dUT_3DVC7reUFUeS}QXwqEME6Issyr5QAP|sGGl;KT= zR<}hkoYJIzD2)znCuQZBp$ovTh4iWtLRf4b7%woGs1SE9CbBvvdqbJfSOzwfTODO6 zfaDXsRX4QN-rBI}vki-{XWC&30{^VIIlXeUl+=n*nbl*mYbWt8XmX}}>eY(5L_SsX zJ^$QUzwXZZ+PlC%e)ID{ddq{@{N%SkM9f3v^I*&FhugQ`=?@`ucoYp%r&+XjsQl=} zMNlVUGn&9*{Ah}tZS(*TrI<^EL&a&4F`2>};y6)nF+k|SA3354@&53T_|Y47nX%mL z%qloP35||eRB+)LE14AZI=iHy^cL4kkY;u|ktCip*SRAq6f_v^5)GQ7;o7-18tT;| zo^8{*6)V*USWQH4F(Ru*1w}$rR4J<|y#g?>a0;qaL4#3^2)3yj6~szyB|NRIttzbm zfMWb{=vFP-CCc*ueQ?M8;Pls9w?5dg__Gae=W}Cf*~s*&(P0rHT0J&XHZfa1xuIg_ zm5O=bpQ}~#uU6kyS93=l?|;d8lR2qurZl_%jY+ z7YoV8?_`~k;H9ax?+w?&CPZWfC%YsJs|VQoj6`UicmNHmdI;BrpTC;+5MxHEx^579 z7xQO=s_Uqzi4zQ-G|_<~8jDmv)rGhn7yecgWvNT1oT`_!7m{+=Nh!ZjNvP+0G z1cs7c z>c=TfsM-ZXCv&eL#k2Z!qiD=F0HcH-F$|q}WNZla93p)fsv%c!u5(mZtVeIfuMe&t z6MX!)!TEopLKO5cZa&jJXHPy+VQgyUnAGaAb!9WIfPY+}3$d%!^XqC*ZmnN8zoGVa zDjV)dZN8_jdR~6ZovnKwMgjS>?YbYAdv1;rn*=E_Q>Z2zwo7F6T0vzoq^1;gqQ`~` z>Ot0Bnr2)$k)o;7I8{#rsUIGTFeu)SG!-BAUKdnYS~mwblHbt&BQUrcg# z>2;0EuWMcX+5SzFgX$ZYrFj$`P93TSo=MhX@UF`TCbkg|HUlPjac(mSSq(+6O(z(D z?ILhAQQGTrq5=EVg#d30jeZEwq6>T#QcfVNlr~oigu}g6)eokMFCI_ zgDKjje!S3KdR=ZA$mhDuQYsL%pqW~NrvTTrzwsM=?|r#|j|TA>^K6e6D-R!@41b2!8aF0f=xR@WN}f~-xEwaK2Vr72x@EY_n}01gH~ z5^1fH0Pjabbv{{7NB zE(k_;Fzdv~8lH>LbcvJD96qlb#8%{k{~lcaPH^FyRL*^)jx^>r^}B{lat_-;SfF>90|o>Y$IUt<8u{; z?G4?OZ31N!H58=Q-0Q4FDM;2!CM5vW0+Xg&Q+1oLa+x%G>p@&;{L&>#l@&v-xLA$C z#0hoz+)5Xj$RQWii<4L#GY@_Gg;1X&C|&{!v*AOv9#keP?=UG88N!3rP^{c=x?Vg} zb*Nx<=&XhqJ?v$NWG;D2j?PB~F21(UA@aHW&%vc{2baE8IQ`A0xBn^k<~Kk=skL)c z*aCU}iLlV>ao8aBT-p}rnjzW^yZ^j#%N?z+K8`I=VcpGvQ)?BAA4izSX^BGN%BE=64;j>2?FGoDEUSm!gGPrl`^^GgQGs-+pfW{P}CR~W+ zOULF{-k4u;eQxEAjjL|#F1vxwSqes1HX4a`X^ct1_27jNE4#LAy#P?B3yOVesZ zhCYdmfq|5wVD+P2qESN!@KeSGsRg*EDm6tiDQTi+L53hXhUaG33tKVtf{Q`&U~EGZ zKZIt0CMZq>?`5awrn-$FHF7l+=e8E-2>>}{r3;K*iIRrUL0OOHZ+$EK>euR4jBQwcGt^^CJJ{Dc1mDEfEhlRls%N*p{$$6ld;QXwNDxnK;u@jLlF5}KNr*ae6PFBg zejHek9;_ZBc;6cv8ek~`4sBI0&Sg-UNYqu$4TF`}x2?H8yX<-*pJmr4i||ioDFM=4 z14I0?>Lw|mpn(cAFA7FRi5?_jsG3rSQP@5ziy@`&a#OQYFwX68&YKRQ!6b)3mlofv znUoQoH*q2uHi2FM8e!;4eO{wr++M2_V^ZTsQDGP-am@7rG;yVONPf&fNw;ysA;58% zxaFafK1HJ@B52d$V*@3c5qzvyW>-{cCSLVfy7PSQ>p|VW23MX6u09o9eya2Ew{vfO zEBE$y(p!JGZpjUGOGh-|Ml_L+D|874dHGFk2fiC;nW5Xg%@?m!-rMrp<2~Ev^5(~c z5$5NU0tPZN>!MCn32)cnaLCbrDO(*hA=KQ^L))I~(?gSwr6VPu%<>!ZD;@cOf^w^F zYAw0RoXd%UiXS#Z!LC97OQhO*8zyhj75OFni_aTr`ZcI;m@YBU&ir5f?WK{|Xa3~v&8v;Mst3yH$xF4Qr@aDqMt0feL5 zG>Q|CR9k=v?|WU-!h9D@)Uy-3f9p+Pm7f`W{gEK`!=Uba!PV~tb>AI4|J~+y|2hBm zx4}ORmG=<;EE|zpF*37iRC>*LDIg-DqrS|+q4}mrPs84?HEzGRuxXEt zVzwz2fKLU%%*1083~h}E=b5cEfN(f=s2Bx^E7T#5~Y6w9JWhqt|@01F&O2PXsJA_!tC~^$wKq`oyqLQ50Y_L+hk|tI&j5%Q9L@;V4 zf-0Q{jl|4Ikuh-66#!CVUD~w0;>~IR6Q$s-tQxCK%E&o6!JDArpRrnC3XTb3 z)35uqXN#m!>LXR@Rm=eHAx0t-3KyoMQ@T2XrLN!!olFG^FI3cxsf4UaBqszViq(p!ht6=W@f(OP}RgijtqxEHk)S)G{Dcab;k z64`f!IaSQ{Y&G%A7o$q+xnGb>z3aF{z=p3=a%eheDf5Ag!IZ0Ex-6nrkO%8Nbmd< zy3zwJX9rr(7Fy5sUVWweOhwPxDwK{xKWKg9uiD=Ho3=N<*1YYvnra^$TsO*{ICg?D z+0IU>;vbShM4pbcnO!A2pPPw)sNB+2a&w`YN0fMMt%;I^XctB34?HV~UTZa1jey0Q z_NsG%iQe`qfRz5!wn}m9%zbR32cxk_!4FkCu3+1UXI@8L$|66qB*PiQqL|QwMS3~e z3ymnXONH1JRIh>sKxy^bbV~n2Ns19co9Zg5(JlzFUNoJ?`xme%EqE9Wx?)Ia;^OPo z`-A+?g3OPD%)e1d{iy5s4{+s`-}j@`rY~djQ@3JN1Ag;o^{DKc(b?4~qZ|vZ8rit% z@usc6nO}c@|B7+CIppLpVU~lA`8YMlNgJP^{V0e5!m*$thotSOqu1(HbgSaJP=e?7Fux= z=taoK^9+$sM9BcsEWZhR9xBW~jcaZJ1+|ym9A+{(3k}Q$98;nh(IgMEs76l7h>1V- zFpAY%*#;1i`Iq885h(x%lXy^T(Ev15#b_6VD1N;*)k-ljE3bzMSxK)73RVpZ&cE2I z3A$p%cZGQ4&Gm0o^* zW(D8GK#lWj<%rD6k-mmt$_nbrt{hRQj>W@K+2E0xFjppK${3nH_%MN9Zxj!57z&~vmR#A00TP(^g z0AdvtI4#j$Jvar)b?DH#ipj|)PaF?2+|bfAt0QjJxe9`}hR~o1fSQO*wefEarOVGG=ANKv&I; zbmuw!L)!o3e#+%1eP@2$wEstq2Y#G=^{?w!jt2Rl&a4@eA@Ug$Dc~R4?c5x#iE!vK znPVOiT%BGqvc1g2oQxA1DK^xivf9Rat+|x}vnH{1q~2&sEm&+tQ&hkH=7H*wEhQs} zc|fyLh>E?eN*0KDh*GrN)WA)n1Q9XqSQyK>)x&7+rR zSHZbOdcEgR!#PJ2T~tSxAf`dD(-^SDSaTXn92&O@P@(pg0A>BneN`jd%5KiBLiR>9 ztr=NR3c@#i6dV&=7n%EFWmQ7BB^bs}XwD|rj)dFLR%FyN7B@e^m71$yV^(?iUWH+G zj2xdboLsXXhh%)jC;P{W*NzFUe3SU6@fo6^re_B0pKd+$&I_7|%q2FXSkoloTC;6Ec==jw{czWW_s%g9rX9?vw-O6M+iWBm zg@lzO>Ha(@sMb3turJ=wXG1XR**9Y_=K(%-Xdp#S*wQhnUD_)Fum=D_|2(2Jos!Mn zfgST>nhI7y=IEL{ZrH`6xTwUxk4K{=uolH=Fzhhmfqkk~IIbYM*Ui*~jYkZx+!HiC zO9l6TnyB=hd%F4HPnr%rlYQmSg?t)TkIR&dbL3M>LYC_c--srLAr^8(gr*i{C((d> zaN$s>kpOru5+`a6*a;G_&wv9+)31AoLI}x@hSdY z&Uq9z?5?1XS{&*_6uIhjy*MdCo&oa^7qN!*=+Z)a9uLMlpD5BL0&7NscJifTa2E*o zq8ry>BOw#l>C23CE(ezg;nK^sn!9B( zU7<#k?*kAk>z3t#np^Oph6jSY1o(+yWSd!t`3GqP1@%|^>FdzqM{Cj7j^aa6z>u-4 z^m9~0nxijj9)nqM1mhh#B@ZWHHBo#_&>^fKvcw75cBw(Kb)9&+>EKTr4?UCG@WuL-qv}_U zORpJ6gi|`6Sg3ToE7%M1<1ni6s0$P%EToUd94YaWGLRA;)~_1Xj@uLxznf`nIsCF} zZ#Y?#Tgd}34(6?jf(fH(=j4dFfYpOdi}f#~*jl`87&W-=7VPuom^b7jcf;fqu;e2g z;%G#91_D#c%?->jB&*=4Ny!JcTo^!qf@Bpviv*?16R`sLr}(5;uago%kgAj{xoq&F z$dn~5qF0PI9mX$&=*4pp*(YDSTntgY^C<_0?~3`PB^Xs$H>$hx7Hs@*rx9Pu(TuO8R1WJ^x+to0=a4+v_JW_hqgayw|bh?3jT;^9fhDS)j2A%@u7@4NeRdS{d z$pC9&WxGbCx8771!S_0I-=uLF5I2vmsaS=!vE|Svx#}n%1>!{>sNl_5P8a=^I%XSP z6t_TlU7z;eH}_SmlTpEj(S`&P`k{Jl4uQEAm^HZ;S$ta0R!(~OWqXIm!#@Dmf=Naq znxt(~10*iK-uqI}zA$KcA!vDCO8B#e$J%3WaYE1p=@u?CfAMg)Rke9I+ z;s;@L3mR<059Q@_z)c|{q6jq+hBrT$nptR#KN+6YsH}n-Ub~>SDyVHt6Kg8W3!u=p zwfy?GeA?2t;rL^h?{OKKu0wIy3u*8ui{ClqQfj;}+P)RMX#tLha~?c0rtZS_=}W z76I3){Wa0^i=3Mwr0F!K%f+Bb?h;tsM2~Ov z8356vmf|#ibn5kPWeC9!1rz7$N?>9lN-H}jk_SH`jpFkl;Ps<|i~mUc)B0l23JQ85 zXnvvlW*(|GvV)cVK3KiK@FODE>=rv|x@fWLNu8kb|tKg2dF5D|q>=Y@_OLE$o? zWVGA-$mlj68!+`shE3|iTyZZjS|l@}2cK0L#lj*v^d4g7Y9-;h-q2@X&1k&xC+~sN zTL*k#b8TgRz^`&N;y$D48bP=PtP(Pe^a|S;<^dpt5oYBmvBD2g;+rqN&>Io;E5@8z zI0~`3V_Rm8;Hmg^m$`%qk;4OZI6IFQKmHh2L+4F=+FD%s(FLz7LMhcQKd9uH9QrO7 zGXpe8tBkIQBt&YkkPs1*k}wjMKyC=IK+8n;C&5M7gm+ij6M+Muc%qSP7?aR=BtCwz1p*xF&Da}53a>C0HdfTasC zac(`Vzj<))UBo$UF9&Te1+6ayZ7&9y7ut?Ji_K5|-KQGLX4K=mr6rzl90g4x^1()^ z1lM2mPz;14wa}5@6gd{+UVc))dQ5wTUyImGHL6&U3WH#~2=A9bCn!#&8Ic8PYVoGd z1+4z1H}uczFTn3H! zEV}6GS>p8TYYp8%isYySz@zZ50gp~$|3h1#NMSA_ji(@9FMo3qy`Z3;>e0bQGgF$v zFiqPfvc=0Bq4(1XJ$nr~R}&SAx=JcVV{7%Gg6$nf7QD5JX>6DJNh+T}wi)d@>5% zh<1V+wfCuj}Fj2}x@ebQaKvQd6N_Mx$;chmZ_s&12rQ z%j#9>2O{UAv9)L_#fPkXjMDK;kM`)0W{p3#rHLaPq=B!iM2c*9gj=HLO9)%x&LgHB zq97t7vA%v;RLC&776I#G=x z)vdaU2>_^u!Qt{*J!EOBLo19X&cTnspy1+*Yx;3u(s(Z7O%ZRxg@~|ebVP&&$_fR^ z#1TLkgONqKajeU#3eL*w(TsJ4`Lr>!XCM`<0(tPMu#prQDCW?_UQnc3zqk}C|>3bF(i-PtA%s(&VDOmTZ=bH{chl{U=T1>*-{sOfbeTjUwNvJ>+XeN4Ak_zWWe4O<0?$~LVW3m#p` zRES%#O7R2R0x7qm@#GKpc&DM#5iD z0|2!M2JAEn5SRdPe$jAl+X?2Ua&^Vn(+i1zn%DZYxFq=FoMz!CXlEVEs%<(Ca`3RN zII(^NZ#6^7*0ah29?AszHu9Kh@8BOXKWm+$D>RxW$-%admpjXkvhWlVSV z*kDsEd$9@n-q=hvdzvLmjt3_*6T^!)GVxZb5nJi9&ef+NwHXt%SM_oXaBS(-_`^^5 zBT%3nsfB;6jBhNC!Pj+L-u&a>(dT-P{{v4WNLXou1kIFG`@vAo_5Crz&;n3Xw5N{9@EE-n#UnTT|$ zIXf8+7PWFnQJT8Ao}Fu)MKBD&b@YXQ2)dTi&1a$@s{1d$)O_UmreiOscl=&GZGNWU zPrBzSre;yVLKP%a6ZfB^{F8~j7sO3NN8{QnHEf+b1PK*gB4|^=(q;8trg=g3%}}0}RgJ4`{UVF4K886hA3*d>PHrsE&!V%ov^BK#vJ zp&_ZmJ7hQtk5!k|>(=Rq1d7<&}&r>z`)|XCdD4VMMldGIY1^k2kk35Ah#VbJLQSd}w zYI-!!yyTh3y{4Ee9apI3ImY6&^VKdlYs7DIC`gz8#ME4J44yO!^K*CRoF6xe_U#W*1o zF4C(Q6>P8g7gq$J(Jw3+UAF>1f5&Wt+7_fy^eb=4R^HZmdPQ$`SAY9E{T=TObiOyx zwZFehxaja;;Y8h=UqAHB=!?rI4AhRNP&c6-?*q2MvrGUf2BU$gIRu@!IJ7=pHsFWH zqS~iOU=ed3PD~K)3A10YVEXa1=CLDbdZn8bn!(m0!_@&i$GMf z;NJ^k3Q{^Ef+`u`QRUOCVbcU-{|rL{y7I+t~c z;pGUSuG0%gpII~-_ukWM=r3UMUxN~XR)qgb6#g>!%}sm$u;as}_`%C`aAcZEPeFwbK{P@FzLdwiT&$2Hi~eFB0<_(0;Zaa7+Qdnhj3`|)|KdE zy{Z(S+Dr%k-s8wl^pC}i#3f=kzg&*+GqA^TCV?aTgSP1y85ZB1$ zm~_d+wu9gA{AgLnhl@HsSk!rPc~9NOf%bO`y|@HBGC1&I+vSR*FHAb}!bI@T;pZoP zym(?;E#(EKEM6VOa@B zG|4(NWKt4pvbJ;^-`&p_@{ybQ%0Cn&Zs~Vb^U1C!OC&APeCkYHeqyPxU|AQRMw|Ac za_Cuoimgwwvnr|_3L~!6B;lC`op5H+7~J*3vp{l2L%Mf^QZ!OlYm3uh!BN?eN?e5}@aIy#H|z_~;;CGY&rpz%)XCgwgQ{ z9rod$Wn?~aO=cuUII%=6K5DkoQTeuT2T>`nB9H=do6HR?I^ z{J1XTS-}Jl=bBGVj!y*v6h`3Q^%HQ1oX&lJ`tv!? zbi{06n}Av7p+lYcC&@?x<1XJTNCOsIrXajbSi-mKrN(W1VIdLZ@gfJ4FB^w|X$m+s z++_98^_nmb<`jSl>HXY83~Qt*04q!Wp$WUhiTDxOr&KU9kT}udoWOY3#nD1mBnb-e zvS=g>apGVT!8vCZ6Z5#Tn3`8t(o*uej7hJZ-hT9%&XX&NcDQtad`_)m&8n`COPk;Q z*2zW0Hb>n4XYyfOh4C&3T-2}z*_#;2vkSxLS@TZ<0xqf_R_W%h%XDqvPaa6J_bWsd zn}sy3(#p|jbuPujV?(@9apXS*-7A@Vmb$uqNza)D&F?R0JoK~Fy1TLYNmtIw*UUx{ z{vn}iCcppV-U5mf5s?zeXL2T_pvn32NrjDx<%_S>(9?;{;uB^UO+{!swEry=2RBV@ ztD1ll-xs(20O9a0bb7i+G8Mw$sAl#U&lH581#l#Tzrbkq+7yAnQGnC1k`2i}Jx1hO z-)$h?*{VpDReY|AK(U-tH zlfgp5KSDtVpPO`P<)ko-nw1a?tQS;-5~C&r+)K3Q*IM_77ifKE62ji@$Ct zpWaY0D^tzn1KJ@LnuD4y!Q|y1dJB|Nj>W)qf6jT3J3ta%dwwQ3Zm8WpsQgoKHOiEK3yTb>bm72xrncECLGa()@IJ+}3|f9g72 zCc7P_9WYPl$0g9WAAk8u>HJG8r(9Y!6%@qeLo9^5&{TLA1PZ#iVp89RNx@c5kqbkD zk)(N9x{?5^hb*bEN;+b_UUTLA_|z#r%p{L14xKU@i6|{VW$hA;))101LL#Nqc2K`A zHfDH^IoBqHjpGL2_#AOgCvHA#y>#H};+EqJaPud#?aK`nGtyNcoH_Y*RB|XR;}$es ze@T&-5-ky}#Y@rjrnD6P%EsivMjx$ADjA#8Cz4zoFXx3xkxWe|XsvWC#i+1l5^sCl zn*(&W+`Y&|PwV7lhte~^1n>iXeuS9^e`%To;tgdR;uBV~U}eFmMw_Hz59t!QSI@65 za2Wa~l^-3;-!(mrJJd4|+ z;BaW~N=?Lb7>u7aY5W22&4qT(EFLcfO$eg=c;V=aYv$sa7pTVVc1T!*YpzZ%U1zJB z-unB?E5=`1HSO~1X+lA`3r+k(mtao7?dSu~PCB)CQg1C&5Dh(Qd#@jd{OVQc6>8oe8WkGF4a7`W# zcb?DuP0+o{Z+@7C+Lv~pT?q1NJoJ;)x;s;qvoqCmbL-~j*K9a_S)p&bH>nsf zp|xt_KuF^}aavH6=&ao;Yi2|+Fqed4`tTfaDRO6x^J$XooT!HV6D+E6vBeH}ZVEUu zqD&+jm>XJ@0?@g5x0@#s)hro*W(hdQ6_&@L{&?Xn4cmUN>-1XYAEKSE(G8f{^5e=50+$K|FedQnW?I|*&5=Uu&kR$H-CtBVkO)TIY#2$QKo!KzG7+t7kWBz zj2??H){KR%&0%0kpUx_pB2{jkjBC%18hSQ|w*rcA4j$MsCr}q-gk(S(DmZQdu`vHg zGX$^_KUbo96|53Jro>c(;Z$%e1ii$72ph{M_TV#DQxOv=Geh^rz;R^EFxK=7r%v1| z0H!BkZ1kuHyJ}XBJLG|i0u(u{pv)tJ)E_SzbMmE;rxuNG+V?MAXUgSLi}pN3K5IKq zuZ0qupZ4P~)s@b;x@z3jRTHnQo^p}-2NZN_$rPp_<)6t1pLY~=?4?O<)&5A{I)#=- zY6;S6AloiQs$P4oAhOly^r2LJayScv!;J9T0F;mz^7LBck z>Q%i=N?k#3HAP)nfcmjW$mGWdrh@1#GT9Z=NYg6SJf@5_bu8$wekbU{#TWR83xxJ% zJ!co;;wyjP`>C4SK|a~_^YgX75CzT8RpaI}y?mI(`-i^p?I0qhBp2l?rxiA1%5v`b zrIDzTvFR*gf+AJ0fTBtZP?-;vuJx0dVd(WFQ|N^O-wXvy9YQ{-l1Y|EL{?Uz<{BcI zu&e>qO!BtWD?at%pdZu)gGYx>Q#!G!0(Uz(bvgw*S(Q}~m^4wx1+xkksm>v&D|LhGXCV^$sa8kceebI%)3u@H@s5lIy=~N zsnB_*FZ~7)4()k}cBq`K;!>U8^f;bo)~%UH6hvjxmDO|!b_w@_R!@^%(81?D3(-Xx zZG>!|5H6H%P&F`|5OnRaRK>25DJpL5Y?HAX&vjQ`H9<@?Yu%-((Ftm1RFFK_<`h0VtVvRam6lkqZ3;#;F%xY< z5RApgdewO#fCsdv8DcDAyw`Dmg0Jjkcec^YM) z^K7B(LSObhA{_9~*{bfd)l{Fa?fBrOO!;(hK7L!TZp|b|L2E!klj&YGm(xq99(#H6 z!52U~#5`OJ1x*GEU0O9|kXDLALM?)vm_x}$do5T1v09uV<(>YyDzxPd3{ZVS|Zb#dzl3!9F;nA!4ps%Bnh{cZUT zw-fVFO$8TU^yIx7uOrgy&`d;BdoJSZGPgS-M#@)BFKp(y$c!{XX-Z(KjKwLTYOe}O zSW+Wk)LOPq#p#TbJuRHW?!m~%u1MmQ%{GmS72IXaqzZ^j8V2{Hs=!=o6M zr3uf>Jop(md~WJ1Qtrpxh>KX+T0MDSlb&B*uoBz1GPrsiAbK`7lD#iGtM| zG@`V1($H$eMDU`wa#EA*-8!{y>+d$d|MTA5+l4MBoQ{))j#C3vKt5**UFQm2=L_AJ z`kRh+UD!aIpK~=R-4`}BzxJnTe7~4Jl~9C&z(QQsOcDOUP3dzhroF#lif0}nA|jsy z&rROg_PgbXFs9wQn;`mPY8t}HkTQ$sPgBZi)3#8^Du zj~ZIM_z~yOOF@$`zNvT>)JkBHrne<0Q-Ymy@h6po&K0=e@)uvrgSKV# zufH87x8aWbMkdhB*Y zgQmz_r>NH$`d-o#U^4heMyH2^ZbarEmK`aTP0m+L?%oicCQXMmnk6R)O!FXu&zns` z#6uL|vdy+}|9*|2cOEnhY@3Y}n^ zlLPH12HHP@Q0VxWcRptdo#zIqU^{eiu;*%j%ZctwTe{9xWAlSLx8XtD;m5jb!FpZA zMrh4sx)4(eT0QOj%4zSvJmmnkKrcjy2%3G*O+L9~O7BLdpfEyN6q&D)ivoT%<<=qG z4yBKe;?K|!?=>+b03jwZ=rCOoKhx>4#s1$S^1-$T{G=7)(^yOM%TMD>w*`Gh2T zaXRNKrr^+u@l3Ji6wrld65EDE#s6K%z$XK@CHpG#sCcmQK-RkU; z0z9j-_$bqRuD*iHD@Q)!9~Pp9D+;^xr^wO36< zgW7fZ;bK8bFYf7G_=NnIFa$@9=`WCH+c8=gA1#=k3WNNbF@@X zrO$405{|+Fgd=)@8_P7E3FGaekZlx(rc=h2Okh4pXT|2?TOf!JaGF{}g)a27A+m&P%-wZ#KR1hjj7fX$Om?vZo+o zA)%m)d@tx6c0miK9(W!bp()r1dHw+rP1*O{l%p?CX|0(S?3iH=WCi4zj#Hu{jmNlNpK!H;V7sK5tOcW1+oyMLn3k`ciem{cATjeW3(+P-H1xKl zkPk4-9*$(_`?f?xj*Col3gob9Wdc)ihHMTQo@o>e%0*?0N220a$LSMOr)dS5j%bSO z&7va%f-f$BcJQj+SW4y_Uk=XUhrZ7Q{BN*3mtA)kEI4nRA@W(q{6n{Z2J=hWPvFVd;_Tl43jWD%x+lN+Ztzdz z77{=~^5##jhTei^3KAl6HMT>tBa%%~rfOElhM6u}nV=*D@kC;?@!LuH={Q@4xw%OG z1;FW5y&tHsbvizP@N86Ztf}+1v0|U-kg@Kf3c7@K;{g`3&}eeCh`KF9n0=gWy~c zTtwaV@y|1rv+)jm8ozVJB~v~P0%|@&rq-1*1+7613YvCt^>nb%`IXa;EttBWcR{ij zBAK{|c0s7|Os&Yu+Uf6@8K79rwaCAM$+fsmVu}t_RGG9DO&pAb%nllU6tu4hT9*c` zOQ_~uQ2&)heDU=RU3_i0E5G?(Fi+za)KrLnKs!|Cc|lodZnl~)$9PA?EHnpSkS}ce zWfB{Y(;r$x%}e!SXv}*yPH(KD!zRlI51&)hRAxPWw4vYtW8MJm#0BM()LJ1W!k7Y5 za(eZ^%tL-qWE6Y?a^Yr$tN9yq6dqoS>fWd))QoF74$U;(L2IWU>&1;++};80y!yG| z_%{aAuLc9{N;om0(Akiyy+4h==0;zrA#!fU6~s0~6l&B zB8w`e*LU?0`Mlkiez!0EUSH!;TznO}FVJO|-}wyoT@DK8g2A&vfW04TP|$@SxDo^n zeW~^Nt&gWl#_=v_Y8rZwFQFMzM6 z4<$ zzy8$}e%l0h3N+q4q%U94*D*W`$zI6qh(J3iAR_!gM`4=`jd~W18^&pxqL+zSS->%k&PBaJ zkg}7;>e)1-v1+;;D#ARWEX*SmR6$3S@P=m(<`Cv0`Hg+(xyx~jgE^|Kc`*|0g0IZ95X)(nUtHQ@o*J9vwDVzBGhVBa4N zUR_`4Nfm+s1+)_@Nk#h`4{K}9NiT!4H-SOJ9*BHW?-Kc>_xEKE_G1gweL5(Ba6Srx zlT1FKAY5~Sc`gLOC1xIMen39;*a8JXV^FxKsYF#f2QuoE(q6R&rdzIj2C^EMy`U)LYoj&qcatyV63djSeG@_ zE)k?l3{|#WNjc^LO>3Bx6%ccUvvqp#%H2Wkxu9if(6X4zlAr~DZFwnQd@X1?^3%+g zM>Cu5%Y$>a-QTqB0Tc*$@{oQef66SonHM)eji zQ&UZ>>7DGHHMpG~wBfAB5#l(9cmPcy1QEEGKgEboq?CCw@f#u0r`FP8Mg=58UDQO) zL_|u`L~VIEdiT-~DlEirgVT3XXms!o;zYCo6Q*BBo=D^r(N>x!Y42AvRdZAH-rWRj+fuj*Upfw-{<+%wa_er-R!qTM znro(0z(r1ZKYG|J(OPg!qfKDExlAE!N|yzwM$BWi^)n0P)0f`Yhn-K;p+fhOVBq~A z_%H}g1i>l4?E(3Kd1TuI=Be|{1M*38X$*pV_l4Ej+I!RZ^%YQ%99LdQH%qFbxI5yU$JiXvwthO}zB9`doI-CIK}SReHhY z+%$oqB6zkfg7H3+U7`^W+NmppqgOwbM(Ikt;>UEPd+3p37VJi z#n+SGIOl<;?GL)L?fzWtZ8`c17}dl=Bs)67MkvcyWK=~uu6*Dr#Gh8nAOSxoRZd}Z_CW4ni+EXI})HXUDzgGd*+#*DyQODMFePwVW5;E zwBs@8VnBqB*boOKaSM}-)YOzBUr6C#TGq`#sC>Nflrf#yj5HOPoysbZ(jQtR;M0U3 zqeK7JZx>EIJ)8 zxA_)>ZwP@5_Y}GRa=@O&^n{gf9`@zC(pA}qw%JC1F zry0ycL^POL)OG?tHUCm}_wV4!E58-Y^N=e$9>OCq<{x|oL%s+`HSdLlg8X)fFUr6| zotx)!V9`i)IvSOREs={}YsJUrD`3|<8;{uVqBRZ-)Q)_-AkB<#;yhx`p(7_*QsqWZ ztU`s9j;4gHw4TA-MF1HZqf-F%-8cCv90emX0Qu?}UHIS&C&DXIbk=ruB>Nm zZd#uXP}H-}o_Y=qXEW^__T+#r|=mO-^ zQ;>^%j?1S@nl!D_%Wle=f7Zh)mTiKm2?UkJ&|3i}hH9eYVe5wrnhyUkyY12J)(0E6Kis_I;U-_`$yY6Z^NaRB z{6#PpWK+aDB3y#a&#t=_1-}tgz;6n<#A;L`m|%(k)JkD0z+8Ks&;G5mu&YE%JN9&L z>lbhm5!K*4DxdD;^6B~QUv5A4%s>lnk0k!}wdFQ_E?o{h<(4E1oDb>(|Z@7GesTd8uS3c0nI4n{n_ZrXZpn5`=$H?|Xha zy6|i2bV$%q!I6iDho1=PwM%5iI}>9|dGKH{i8Q^fQ*u+CNDjl%y(_1YB~uUFYi&gi z&4IKg-W!G{%&g4j2Qvr$ruWKEXy?Uin3H8*&Z=t@ z{Q!tzfSI0lAYex%O{!DaDtp>-%;TF(HNr?Ug_lz0DnzV&FDbOx(&VEsoo$!0rN<0DM)rc zJ*{WjK3bC7@qZvibV~=H;5c{6aeIfJ?But8vHjT7{kbE_w}31SweJ5WuFLq0o7ugI z&lid|8eY6<7BrlZwesfF3z?fC()SMORsk}Qcu?i+;H@Wvd>P;B0jZ*#@o)IxRKZOMXvHX((d%l9rPkzTE%{w1$a^;c6&G+zEQ0e<$U?Iq$AYmc;E_{TDa9uXPumcG+lcmv% zg+0s^Y!}T!66@R!Y@dV60i6Dh0qDdJ3-f^Mf*yY}h)VfP;SHjW3X(t!?3ZvMnZmn3>t@hh3tdXPtU5te#$c3$#4$kN=&?~8#tD?6 zCvM5mpDB34vgh{T%s&T%xb2J$k6d%nRU!USITByE}eC$WY)!!S)ibUFU{Eh;tbjXy$H^kA%!$A&e-?D z3}EOhFhW6Y3Y-?qSBqvz0bw>IhcfqQO;*vO4$0h)62qV=FcGv)>YW|9nAB&rd?E; zcR$v+?LoTu0`o{M-$i8>5-y^;*0E4_{cRnaZ}n%K4=)yvHf_LGb^w1w$?TxS8tt4* z+n#D#cbxkfW*!xoj%Fzr0VDK6ltMJ(Y6v15^6|YwRvui`O8hhP2>&=1LNF8wGhxg6 z+5Ox75+ib&f;pUIMz+?R2$<#}!CmEnlRximI@2={bO!;*M+(SCh)9?Rbx&8i z<3erIn}3<9y*E`hk*^f!sSRYjPncPMZ}Xdf(Q{>I(1-Kum-si>*OJ}*czyLsY?yZI&$ZuQ8{2jqhb zE@2+I)RNr}(gMQ4K1T|!xumE@g#N*vi>>>=o~HLVrhH$Rzs z_d*-*AYhlqmcH-dQclVBc= z!A-U@L-r{hxM0RB#Z28@o0e=7}t5WIEAfOcn@F2k@oo8NnOBG4SEP;W=`5XIoc) z(9H!D)H4|JkL-VX`dT~cUu)j~t?Y&ez%#@=^rU76uC^d&YUa1R`4`<6Y71RB?|#L9 znZpat?)cktd%tz=m8Uv)e<8r@E5(n-=%UN97cRG*yU11}wpMTDsOM`LUD6H;!q4kn zS-`iNaaS4FT(a$v`#jk8$eu@-2ZYnb1xybCwFshAIzr;xx=t@eZn2+a{-NW|AAYm( zXR2^j1^&6ZcGl%G+5(|`ykgdog){dN?GWeq!tzTq-+N)^N6TjQZe{jZ+=N(A_5)JF6b^#K6FKf zT~N06j*hMK!|7mj7hbVBx?W9%#LSbDE;kDaeqQ$$ywEs1O<%E}?bq5ZdbY}Fz&u1g z;2bItv}n@_3{#}VtE>VJFpQ#HCtq`;CV$^e;(^?{VUD9;1Rq}onW>vjw3n~5cFqW1 ze|+G`*LyE*>~6l?)!mEI-Q7cVZ=t)7Sg5Dq_@}$j+mSoceB?*j&5zNeVK5Iqk+I*y z?H!_>+Ztc_gU(aS@nYexNIJ%>z5d|YU4MUm?>8>K{@vUw|5vcbPb4-+ny;CiGzAku znj<+}=%}qbHtf0J2h}baOU|#zDBf!KtpN%i_~Jg&`+pg9f51B&?0G;w$~>~GQQFZx zrek;BW(pAr7lDOf0(?(jdUp=L&WF7vKJV}Y=|n*|4snPQ1%Z5|fPyZS&ISdYSvC9U zqFJDz{h%OI4!krA&3!M<`f%y2_D%DGJsLj*TuS(w=IdqAtA=JOR*Vnz#zd6lL6qJV zX=IdWm%_wEo5_&WbLdJPa$wHG+{}i1K3MzkiE>vyguM3QQ5G*XMIP9?$K3 zJiqIS<~=B%r?U6+joTjr|KR=)@eh6f)Ugo06pt%1x+vp9@&@{KvI1VarBwL5NoFKM z(aS`Vp$bN8@qp%@TL*T`!+9->OSR`8CL;Q}E1&+f^eFf{K|&giIx0yMSAvv0%=U`X z)r^6h#vdL6^Dxi2I@*+R8`sV0q0cYBh<1WjDHD`b;M~F6_@JFv?l0{Blit(Iy0Ra3 zw&gn8o4QasnrZXX+0oVA-Q7Dt#@b3%wJKZunofoY#mvDCe7zmLb11nM* zfMA?0A3s)>L&#Z~^Gh%e>3xQV>_=>o=k3#ix4#@@Hu%dcz1osJk6zS*c5p2lD={t- z3IYrD721zCzwyWEim7S5{^7}o)`gEl+67UWeYtG5P|(@cvyUwT+fX_1GSLpmhYHD{ zrdc4U){R0zk}jVpmtjttlQo}7VHlWC`;bn&EiySgMpGR@Cak1)&#i+yZ#`G_;E9Sy zPgXqoQN<%DXR5(GPo%beKD+Y?&`xgW6S-YaH0~zaY2N!JmEDiKuU&wDq!0_~b_f(C zEQIaQUHF-x&TY55<4Pls#KwtAY7`t1+(c;Gvu;kNn)t_ktqg=iYyhR>9HO9V$1}^<>JSN%I3jTbtb>pGjScD2-XwWc~-Go5Yuu8tOPPj~Mi_CFoD zk6TZy$nX7Xy5=^b8rtn(Yll}QCxLu&Tb^h;@}oXH%qrky`Jex<^5w7n$(L^YA738v z#?K}Pdt=kFA9m4+$JaVxC@d7NI{=@Ei4GC59jc4 zjtfJK1(=k`Ks>H^*fXzf>zyacK|7D0tOWl&dZy;F)V3!wJ3gP@{zP`?=V|}5>+|{D zpq(!?zw!l;Ps=M`Xxi~eGYN6w8I8d9%pcr!Yum=Tw3?CP$S35VYW}#Xnj;({WWw?s5Qr0qRpv0UP#sbb z%S1I&JYK*&E{5Z;)A}#f5(RlKLRWL`+`jG1JdS*ZSWrv~0D49<69+@#t*`VR|9;oS zEgk9iJ91|_a;H1Y`)UfQs32PgLYaEd>fCb2K#UyP{wq5GeIq^u+Anc<+M6F%tR%AEaOB`P^H z&XvqL1`2Y!AmN|c2NujZuz=+KFV8->U=IG`3?+(E?N4o)7tPdaG*MnD2`MsnpH=D7 znsRHLNYjpDhjTHoiL+93FA&Ddp>XTf+6O+WeC(sj&z(f6dhEi6$5Y!spWg9gX6KXn z-CxMO2I!NnPJkXycDA#*#d$2u?p>d z***CkU!sR%pdc>zd%-9;sOl@{U<*XMpz=B3AFvR1LC2QN+5eI!A8dYze_YxB@*I?l zWkNx>xzox`K{BICo|+^9fXI{usdzO}7z9ZRJJDrw-qcY2FkVJc3|Sc`q3lUqszR%<~(~uYR%RwJ$Z%#n%HU z^et4SAdnAlhy3LjuEnU}+ZlyjIzbz`#LOBwc9)xFn_QopaG;ZS?(2yKBfCpz+H zJDVJ>9s%Rhgo=z^S}0AA>F$Bi)|Zc zyDcssRD53e47jEAO#(;~M8i#F#;!QYrf65FS111X(L=?7#kn}~a@geuMI^LRTtwh? z3EuyQpcAhKUE@En5VlD|LAYweg&4L#xC8_L;BGcSwP~m&E-P@RXFhNbeOx8^qXBofI`pSL%@BBg6@u%C*u4}vW zO53H^+Ah7?e);wGD{r)8|3egXpgnaAoP%9Z>zUf7ec#S)|Mz%!hkH9IkPo);cyqga za=K=I(`$d!d1}Q#+qr8zRsLte3f^t%IXTL#*eweNWd_u|ZbWoKLsl-uzOK*?Vp2l8Z8-AY6rk zf^Y{3TOeG5VgCdE!8=7w!Qj=755A8_^C{esuBM|@N~U@q4mt48)$%!4%87r3f{rbj z>nO<4&fJ3w=Yf9?E+k?9f_W!b&g-4I z6SFlaN%U>p_1&}2d^7*-H}e5Lr?=0)vKQb}faI?z2)dR?3cCxVp2BD~@}-FXkn@En z4;g~Q3IYUCING*_iY5p61Bt_xbB!CWpa&P}mM8EL?f4eNUj|15F(G_~tf^Vq(FpKOk(nsNBtqXZW&%ZCWP~;qMaC2v$(*_wdHcSTo@fq2&{SRS zCLEW1kLWYM`<8D)W=|_n2oNN(XyA`Afq*}Fz6eh?QtG+#vA<|03?crHhOLEvsg!qZ zyNMu(tf22-gBA3}_b+~W)6owIZOG=4oQRtazJD|DM?ughV^YOqohmZ~3j}0NG6T;p zqG58fr%qMT+D5zt6BQ|Eg+hyDPM$B2D?Bz`I_cbw`R8^lIKOk@xg877?pS!ec(K1? ziLYWwz*QKmDh#>`LsbMjoR&pB%kc0a;m`gV3_%1$#uidoBq&7qGbL3zQQeYu-|TKk zCrv4e>{8dbfwHmT-8W-_$jsm*bWV;-tYbI-E752}m%tE8OfX-`C9x z@y;x@B^@xi>JJs6d;Mj4aWNc87!eT&IKVI%KUBM{xApPl@wZ~p5Ga}uq$?9 zPyFJ(*rgKSPvUA-;(A@8qb_!_D028UfB8BuqRKeKg0%zuL3jtJTHF33P`ohS{^~%m z{oCKn%DylD1y_Kb{$P9h!dJ1wuST1n!Sm7)&z+&lb%EWJ0z1Ye@K`&IR}x087f}{h za(jslErb!E8IxVD=W{ekn{QWF3VHGkZ3`2Pe~6NUFtp+D&86zXUj0w!z!oRc{v9S! ztRQ${5{S;n9~`dHM}!8WRblt7r=*`Hn@jAc02@urr)lGn)E1!S=(q}iF z{D{zoU`HX(&5S=_-rV;7m;>+LeDuRHiGAZ7w>=Ou1e<9FYmZa}MBdOMX>y~@RFopQ z9I>vcGMW-4&|NeWm~(FD!t=Wp0)j5?S=?1x0PyiwE)BYuh1^S#!qv;7HOpc(%VV|6 z;eUm2^0j{^r4m5UjG)*;2nWF;0`f?LN5&sT9ICv9*V^u?-C;8j(_u|iA!I!+xess6 z(*g+y;AU4zFo9pF2S?UUpu^<&ha$;vgvjCJvU~f@C^Ev#;a$P{<+Xi{e)I~zB(#g~ zJ*M&BM*$|rqC1bX2^c(p9nbvUrh5|Yuf$G$5;^@v^vstrq_bZmk`p5c+8w*NFMhc^ ze$@p!eDIZ^YqM|n6!x(GgJI`;6yEvje*t!4tuOZ7@cegQk@yaG&9{mS^$bMMrY~;8 z34XNs*+~5(;p#iWu3N(ut3#C528w3j$@W3Kd65}AXnR>@T7+Zszom+3$Pvh4+Nx~j zpiM=?m%8Rs6WC+YRS+hr&P&la;sb&_vz;rSa5(x~r;Fm%VgeZ#OhQ0n|KK@uyz7CN z&Tb6%9*iA)j3RhAMxo8D61E~i5TVdb*S@?75QI3-sZYiLb6VeH{e|+@ z_r@Ig5Fee;L!ja7aT&slR7&Y`6fu!RE-7Dw2pGO0GJKvi@H3pe{!p!PgOw95?V5jX z=c4nwBrU#DwAfdusmM?f z1C$UMCM%&v@xhRtoD1N{_d_`6E{%y5jivi8tLI|yj2U*%>}$Luap)J(WA8*yejGXZ zG4klCzei7h8ao3N`U?0Hhw*c%ICgd$J}DWjzSp;R7RQs>+M(e2|BvL~J0sfoc+ZtR z!+rmz!z^`o4fPI0P9vI)PjkS@BG~cVg_kSCm1`Jz)`Tn9g(}x0g-hnrlU?SPSF@45 zy}>leY}YJ8ue&fsNk$d#UUMm`vZ{}=)lC&!E$FISxIg&M$h0a2laqZ(0^B;;u{Sx# zo^eumP5xW{Y!gUAKn8#CatDkb;14uhrmvh0pG=+ktq(sUj0eefjG?G%h-dQu5O>vQ$CeP#C^8MF5}A0_0Y^D zFHic@| zgkb+vFAsZGL~B;W>Q=^TSHc9sYo}!YhzX<(A%-Aj2(cAJ;DfJ254k4Lno5W5zDa*< zj+rhZZb_Gn!}o%)BK{o$K^lm5YGMb#fdmkMB>>S7WMD)QTq*)0laZ97JOQk}zzd-q zK@cV8(537Uyv5(MAIM`S8MhDog|Wl#seN_pldVrj+y4+g`flXd`;p`C
#6CXrR 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%0A&bFGJ^?ZxKwaSay%~z|BlTbA{G+_QCqA8wMysG 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 yT^R{P!VvN=U0F-&j(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, '\0' }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/pcsx2/tinyxml/tinystr.h b/pcsx2/tinyxml/tinystr.h new file mode 100644 index 0000000000..3c2aa9d54d --- /dev/null +++ b/pcsx2/tinyxml/tinystr.h @@ -0,0 +1,319 @@ +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. + * + * - completely rewritten. compact, clean, and fast implementation. + * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) + * - fixed reserve() to work as per specification. + * - fixed buggy compares operator==(), operator<(), and operator>() + * - fixed operator+=() to take a const ref argument, following spec. + * - added "copy" constructor with length, and most compare operators. + * - added swap(), clear(), size(), capacity(), operator+(). + */ + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + // = operator + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + // = operator + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/pcsx2/tinyxml/tinyxml.cpp b/pcsx2/tinyxml/tinyxml.cpp new file mode 100644 index 0000000000..1bd61cd6c9 --- /dev/null +++ b/pcsx2/tinyxml/tinyxml.cpp @@ -0,0 +1,1866 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include + +#ifdef TIXML_USE_STL +#include +#include +#endif + +#include "tinyxml.h" + + +bool TiXmlBase::condenseWhiteSpace = true; + +void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::DOCUMENT ) + { + delete node; + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( replaceThis->parent != this ) + return 0; + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +void TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return &node->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const char* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s ); + } + else { + *i = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const std::string* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s->c_str() ); + } + else { + *i = 0; + } + } + return s; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const char* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s ); + } + else { + *d = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const std::string* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s->c_str() ); + } + else { + *d = 0; + } + } + return s; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + char buf[64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); + #else + sprintf( buf, "%d", val ); + #endif + SetAttribute( name, buf ); +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + std::ostringstream oss; + oss << val; + SetAttribute( name, oss.str() ); +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + char buf[256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); + #else + sprintf( buf, "%f", val ); + #endif + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING _name( cname ); + TIXML_STRING _value( cvalue ); + #else + const char* _name = cname; + const char* _value = cvalue; + #endif + + TiXmlAttribute* node = attributeSet.Find( _name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + // See STL_STRING_BUG below. + //StringToBuffer buf( value ); + + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + // See STL_STRING_BUG below. +// StringToBuffer buf( value ); +// +// if ( buf.buffer && SaveFile( buf.buffer ) ) +// return true; +// +// return false; + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + // There was a really terrifying little bug here. The code: + // value = filename + // in the STL case, cause the assignment method of the std::string to + // be called. What is strange, is that the std::string had the same + // address as it's c_str() method, and so bad things happen. Looks + // like a bug in the Microsoft STL implementation. + // Add an extra string to avoid the crash. + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = fopen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length == 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // If we have a file, assume it is all one big XML file, and read it in. + // The document parser may decide the document ends sooner than the entire file, however. + TIXML_STRING data; + data.reserve( length ); + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // + // + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + const char* lastPos = buf; + const char* p = buf; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + if ( *p == 0xa ) { + // Newline character. No special rules for this. Append all the characters + // since the last string, and include the newline. + data.append( lastPos, (p-lastPos+1) ); // append, include the newline + ++p; // move past the newline + lastPos = p; // and point to the new buffer (may be 0) + assert( p <= (buf+length) ); + } + else if ( *p == 0xd ) { + // Carriage return. Append what we have so far, then + // handle moving forward in the buffer. + if ( (p-lastPos) > 0 ) { + data.append( lastPos, p-lastPos ); // do not add the CR + } + data += (char)0xa; // a proper newline + + if ( *(p+1) == 0xa ) { + // Carriage return - new line sequence + p += 2; + lastPos = p; + assert( p <= (buf+length) ); + } + else { + // it was followed by something else...that is presumably characters again. + ++p; + lastPos = p; + assert( p <= (buf+length) ); + } + } + else { + ++p; + } + } + // Handle any left over characters. + if ( p-lastPos ) { + data.append( lastPos, p-lastPos ); + } + delete [] buf; + buf = 0; + + Parse( data.c_str(), 0, encoding ); + + if ( Error() ) + return false; + else + return true; +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = fopen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorDesc = errorDesc.c_str (); + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + PutString( name, &n ); + PutString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( sscanf( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + #else + sprintf (buf, "%lf", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + PutString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} +*/ +#endif + + +const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} +*/ + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += ""; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += ""; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + buffer += text.Value(); + } + else + { + DoIndent(); + buffer += text.Value(); + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += ""; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/pcsx2/tinyxml/tinyxml.h b/pcsx2/tinyxml/tinyxml.h new file mode 100644 index 0000000000..5391236e68 --- /dev/null +++ b/pcsx2/tinyxml/tinyxml.h @@ -0,0 +1,1776 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include + #include + #include + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SNSCANF _snscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SNSCANF _snscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SNSCANF snscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 5; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simple called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& doc ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& doc ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& element ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& declaration ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& text ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& comment ) { return true; } + /// Visit an unknow node + virtual bool Visit( const TiXmlUnknown& unknown ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_OUT_OF_MEMORY, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Puts a string to a stream, expanding entities as it goes. + // Note this should not contian the '<', '>', etc, or they will be transformed into entities! + static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + DOCUMENT, + ELEMENT, + COMMENT, + UNKNOWN, + TEXT, + DECLARATION, + TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: DOCUMENT, ELEMENT, COMMENT, + UNKNOWN, TEXT, and DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + const TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* Find( const char* _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + #ifdef TIXML_USE_STL + const TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* Find( const std::string& _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + + #endif + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + void operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + #ifdef TIXML_USE_STL + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + void operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } + void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + void operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } + void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + void operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && LoadFile( f.buffer, encoding )); + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && SaveFile( f.buffer )); + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i +#include + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p ) + p += strlen( endTag ); + return p; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + TiXmlDocument* doc = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + p = ReadText( p, &value, false, endTag, false, encoding ); + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + +// int tabsize = 4; +// if ( document ) +// tabsize = document->TabSize(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = ""; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i +#include + +#include "resource.h" +#include "AboutDlg.h" +#include "Common.h" + +#define IDC_STATIC (-1) + +HWND hW; +HBITMAP hBMP, hSilverBMP; + +LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + hBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); + hSilverBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PS2SILVER)); + + hW = CreateWindow("STATIC", "", WS_VISIBLE | WS_CHILD | SS_BITMAP, + 230, 10, 211, 110, hDlg, (HMENU)IDC_STATIC, GetModuleHandle(NULL), NULL); + SendMessage(hW, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBMP); + + SetWindowText(hDlg, _("About")); + + Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); + Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_TEXT), _("PCSX2 EMU\n")); + Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_AUTHORS), _(LabelAuthors)); + Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_GREETS), _(LabelGreets)); + return TRUE; + + case WM_COMMAND: + switch(wParam) { + case IDOK: + EndDialog(hDlg, TRUE ); + return TRUE; + } + break; + } + return FALSE; +} diff --git a/pcsx2/windows/AboutDlg.h b/pcsx2/windows/AboutDlg.h new file mode 100644 index 0000000000..5807d5bcc1 --- /dev/null +++ b/pcsx2/windows/AboutDlg.h @@ -0,0 +1,24 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _PCSX2_ABOUTDLG_H_ +#define _PCSX2_ABOUTDLG_H_ + +LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif diff --git a/pcsx2/windows/Cdrom02.ico b/pcsx2/windows/Cdrom02.ico new file mode 100644 index 0000000000000000000000000000000000000000..07588baeaa79ee6acf726e73fb70937a1dadb53e GIT binary patch literal 12862 zcmeHO>(f_d75()kE6fWRf~lFNF^(DOq=`*Kw`shE;~15usFWItiKUlh5G4rAsI13nq&$ zn@r|UCX+?@0X6v}e#pl+Z_Z@GpZM&fNB+m_Vf!fR*u$m*15oqCk91@z8&FR0H|bl| zGOhS`>uYo?WsSjTl)mm*9sL9ASabl@Ael04Q_M%>@V@}*mLN@zp2+#=?`^t{4Us7; z+lSgi@Y9E4*rBgaD%@O2+>rI_S{1<>I|3{31P^gM5+kw5H4z{*$^&HymP&VnVe$ol z30pEQDCf#hy~}MlD35M&SjK$rK~MXj%>+0i0MD9f$Tc=2!L$a93If+qDY1H*pfTXMX2}`~d1=YTogYDW=>WM?bI)WwDBp?>0|YOe@Y9e)8c1*41j8dBA2? zlS#m>^PSAMASpxd>+3_{_A318nYIGy<5#?OMh;4qFY*-^d~mS7AHiYsj!<={!JNuMNXg%|ax_u3h-1fyX5lJ`S$}?Am^yg?B52ct&9imH+&&l&{ zJM-1295POulfRL(t)eH+B$fbsmdxeHpX{wCBrC5305)S z58P=7Rd?6{uY>4d?qHRz<1ylUj4B=@MMx&R(+=Ej`%x zJQ09k;p5yXS;#Ya9Bn;{CnDAzM z`)2kmjY$&xjG9qCrt;SjAR}c|fVXa9z3n{##%X3Se|@f#Jj_+{04l9g0MM+OlSWye zzj>p*xy;_Wkwpx!tN@K;XdfV@hdT!9(~WHw zAd63!)6=WdD?ln8C|D7@ZR)k!dyTz*jqSbG0En;UNJgWtG!EuZB^>gQCT^Hpt=J`V zL8p&bq}Q#&$d))t!L$YW+D}-odl#PW+79NQ{WfiDka+gn=@^6hSAT4%SG>RaBSRG| z9!#tT^MBGLUsnbMi);XeMDicl9@Gz6uS8FP6|oCG>8OMLy=(~MNfb%_uirP;Qq~?- zjP(lJQ9fkY6A2NoLugvWxJQy?yKx2^d)5kiIIh^YRM?^{dG^GkV>dj>MwrBUcAzFU&%gujq(e0k&x4) zmL6$e__nE@50K2q%Qv>oh}Q?d7p`DDWy^#KxVqeSUC#deWvmW6zsnhQZ41U$VqD1q zW8yF*6MQ~|Cu$Qu?GA(axm5M^fs z^J&AfT|5|{k#xd%`IbnJ{oFV0xl6qgXso+d=qjv2yfXkyc21v&$*bzHJgO@<8T z7pv!#;n_=U$0hdcH@pJuzzD2SpfBUetOY?pKkQuOF(hJi%6Ok?pEB{OKOPv&pKix9-@eFD+q|}aJwPzx(V-dT+oniE!4&(Mi|m;TjlC{0 z6~FDGQR0_WcpdT7ducDUr!TOlzZP9U3~;|j`30H`z0q?%b-q3IRo0W|v&tw?b*x7D zn5V9Y%FNDh{fa$_I?uMAR{$^=junG(lrOW@d4S6ZaIS4RxAZON*jAOubGYKx!6^9| zDFS3pG7;>FvyJuTD2->^7BJ$0eHgf$7clr(6>YoME7Jv4Z8fUgXNRkIl2XHqEn5bIAZ?7vL(y1Lml1ldWZ%SEk1~wr-9e;ubjidgn0`fb;@R zzKFGQ4PTcGUFWWEPh=Q^V&05$2*WN|-YVD}Tl)ppI&@(OG&&Em9*Oe=pxMTXo?3aA zzYa^!=lm_k%aaIGzpIcXVJP*)+Rs~4k4`ZVh|E=j!P{nA-vT#VITRAvre3elbDJiQ ze$G&9y$cUADOh_F^{fC~1)jdm!*X?^hf+3p*pL|ibP@{znoj<+Wh)Iv$;ybUis7$N n`PAcpb11c{#lWfW9typ-^%X;YTBH31;@<&$`v3pWzreo$+!n*^ literal 0 HcmV?d00001 diff --git a/pcsx2/windows/ConfigDlg.c b/pcsx2/windows/ConfigDlg.c new file mode 100644 index 0000000000..8ea3fae3c0 --- /dev/null +++ b/pcsx2/windows/ConfigDlg.c @@ -0,0 +1,502 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include //2002-09-22 (Florin) +#include "common.h" +#include "plugins.h" +#include "resource.h" +#include "Win32.h" + +#define ComboAddPlugin(hw, str) { \ + sprintf(tmpStr, "%s %d.%d.%d", PS2E_GetLibName(), (version>>8)&0xff, version&0xff, (version>>24)&0xff); \ + lp = (char *)malloc(strlen(FindData.cFileName)+8); \ + sprintf(lp, "%s", FindData.cFileName); \ + i = ComboBox_AddString(hw, tmpStr); \ + ComboBox_SetItemData(hw, i, lp); \ + if (_stricmp(str, lp)==0) \ + ComboBox_SetCurSel(hw, i); \ +} + +BOOL OnConfigureDialog(HWND hW) { + WIN32_FIND_DATA FindData; + HANDLE Find; + HANDLE Lib; + _PS2EgetLibType PS2E_GetLibType; + _PS2EgetLibName PS2E_GetLibName; + _PS2EgetLibVersion2 PS2E_GetLibVersion2; + HWND hWC_GS=GetDlgItem(hW,IDC_LISTGS); + HWND hWC_PAD1=GetDlgItem(hW,IDC_LISTPAD1); + HWND hWC_PAD2=GetDlgItem(hW,IDC_LISTPAD2); + HWND hWC_SPU2=GetDlgItem(hW,IDC_LISTSPU2); + HWND hWC_CDVD=GetDlgItem(hW,IDC_LISTCDVD); + HWND hWC_DEV9=GetDlgItem(hW,IDC_LISTDEV9); + HWND hWC_USB=GetDlgItem(hW,IDC_LISTUSB); + HWND hWC_FW=GetDlgItem(hW,IDC_LISTFW); + HWND hWC_BIOS=GetDlgItem(hW,IDC_LISTBIOS); + char tmpStr[256]; + char *lp; + int i; + + strcpy(tmpStr, Config.PluginsDir); + strcat(tmpStr, "*.dll"); + Find = FindFirstFile(tmpStr, &FindData); + + do { + if (Find==INVALID_HANDLE_VALUE) break; + sprintf(tmpStr,"%s%s", Config.PluginsDir, FindData.cFileName); + Lib = LoadLibrary(tmpStr); + if (Lib == NULL) { SysPrintf("%s: %d\n", tmpStr, GetLastError()); continue; } + + PS2E_GetLibType = (_PS2EgetLibType) GetProcAddress((HMODULE)Lib,"PS2EgetLibType"); + PS2E_GetLibName = (_PS2EgetLibName) GetProcAddress((HMODULE)Lib,"PS2EgetLibName"); + PS2E_GetLibVersion2 = (_PS2EgetLibVersion2) GetProcAddress((HMODULE)Lib,"PS2EgetLibVersion2"); + + if (PS2E_GetLibType != NULL && PS2E_GetLibName != NULL && PS2E_GetLibVersion2 != NULL) { + u32 version; + long type; + + type = PS2E_GetLibType(); + if (type & PS2E_LT_GS) { + version = PS2E_GetLibVersion2(PS2E_LT_GS); + if ( ((version >> 16)&0xff) == PS2E_GS_VERSION) { + ComboAddPlugin(hWC_GS, Config.GS); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, 0xff&(version >> 16), PS2E_GS_VERSION); + } + if (type & PS2E_LT_PAD) { + _PADquery query; + + query = (_PADquery)GetProcAddress((HMODULE)Lib, "PADquery"); + version = PS2E_GetLibVersion2(PS2E_LT_PAD); + if (((version >> 16)&0xff) == PS2E_PAD_VERSION && query) { + if (query() & 0x1) + ComboAddPlugin(hWC_PAD1, Config.PAD1); + if (query() & 0x2) + ComboAddPlugin(hWC_PAD2, Config.PAD2); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_PAD_VERSION); + } + if (type & PS2E_LT_SPU2) { + version = PS2E_GetLibVersion2(PS2E_LT_SPU2); + if ( ((version >> 16)&0xff) == PS2E_SPU2_VERSION) { + ComboAddPlugin(hWC_SPU2, Config.SPU2); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_SPU2_VERSION); + } + if (type & PS2E_LT_CDVD) { + version = PS2E_GetLibVersion2(PS2E_LT_CDVD); + if (((version >> 16)&0xff) == PS2E_CDVD_VERSION) { + ComboAddPlugin(hWC_CDVD, Config.CDVD); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_CDVD_VERSION); + } + if (type & PS2E_LT_DEV9) { + version = PS2E_GetLibVersion2(PS2E_LT_DEV9); + if (((version >> 16)&0xff) == PS2E_DEV9_VERSION) { + ComboAddPlugin(hWC_DEV9, Config.DEV9); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_DEV9_VERSION); + } + if (type & PS2E_LT_USB) { + version = PS2E_GetLibVersion2(PS2E_LT_USB); + if (((version >> 16)&0xff) == PS2E_USB_VERSION) { + ComboAddPlugin(hWC_USB, Config.USB); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_USB_VERSION); + } + if (type & PS2E_LT_FW) { + version = PS2E_GetLibVersion2(PS2E_LT_FW); + if (((version >> 16)&0xff) == PS2E_FW_VERSION) { + ComboAddPlugin(hWC_FW, Config.FW); + } else SysPrintf("Plugin %s: Version %x != %x\n", FindData.cFileName, (version >> 16)&0xff, PS2E_FW_VERSION); + } + } + } while (FindNextFile(Find,&FindData)); + + if (Find!=INVALID_HANDLE_VALUE) FindClose(Find); + +// BIOS + + /*lp=(char *)malloc(strlen("HLE") + 1); + sprintf(lp, "HLE"); + i=ComboBox_AddString(hWC_BIOS, _("Internal HLE Bios")); + ComboBox_SetItemData(hWC_BIOS, i, lp); + if (_stricmp(Config.Bios, lp)==0) + ComboBox_SetCurSel(hWC_BIOS, i);*/ + + strcpy(tmpStr, Config.BiosDir); + strcat(tmpStr, "*"); + Find=FindFirstFile(tmpStr, &FindData); + + do { + char description[50]; //2002-09-22 (Florin) + if (Find==INVALID_HANDLE_VALUE) break; + if (!strcmp(FindData.cFileName, ".")) continue; + if (!strcmp(FindData.cFileName, "..")) continue; +// if (FindData.nFileSizeLow < 1024 * 512) continue; + if (FindData.nFileSizeLow > 1024 * 4096) continue; //2002-09-22 (Florin) + if (!IsBIOS(FindData.cFileName, description)) continue;//2002-09-22 (Florin) + lp = (char *)malloc(strlen(FindData.cFileName)+8); + sprintf(lp, "%s", (char *)FindData.cFileName); + i = ComboBox_AddString(hWC_BIOS, description); //2002-09-22 (Florin) modified + ComboBox_SetItemData(hWC_BIOS, i, lp); + if (_stricmp(Config.Bios, FindData.cFileName)==0) + ComboBox_SetCurSel(hWC_BIOS, i); + } while (FindNextFile(Find,&FindData)); + + if (Find!=INVALID_HANDLE_VALUE) FindClose(Find); + + if (ComboBox_GetCurSel(hWC_GS) == -1) + ComboBox_SetCurSel(hWC_GS, 0); + if (ComboBox_GetCurSel(hWC_PAD1) == -1) + ComboBox_SetCurSel(hWC_PAD1, 0); + if (ComboBox_GetCurSel(hWC_PAD2) == -1) + ComboBox_SetCurSel(hWC_PAD2, 0); + if (ComboBox_GetCurSel(hWC_SPU2) == -1) + ComboBox_SetCurSel(hWC_SPU2, 0); + if (ComboBox_GetCurSel(hWC_CDVD) == -1) + ComboBox_SetCurSel(hWC_CDVD, 0); + if (ComboBox_GetCurSel(hWC_DEV9) == -1) + ComboBox_SetCurSel(hWC_DEV9, 0); + if (ComboBox_GetCurSel(hWC_USB) == -1) + ComboBox_SetCurSel(hWC_USB, 0); + if (ComboBox_GetCurSel(hWC_FW) == -1) + ComboBox_SetCurSel(hWC_FW, 0); + if (ComboBox_GetCurSel(hWC_BIOS) == -1) + ComboBox_SetCurSel(hWC_BIOS, 0); + + return TRUE; +} + +#define CleanCombo(item) \ + hWC = GetDlgItem(hW, item); \ + iCnt = ComboBox_GetCount(hWC); \ + for (i=0; i +#include +#include +#include + +#include "Common.h" +#include "VUmicro.h" +#include "PsxCommon.h" +#include "plugins.h" +#include "resource.h" +#include "Win32.h" + +#include "ix86/ix86.h" + +BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char cpuspeedc[20]; + char features[256]; + char cfps[20]; + u32 newopts; + + switch(uMsg) { + case WM_INITDIALOG: + SetWindowText(hW, _("Cpu Config")); + SetDlgItemText(hW, IDC_VENDORINPUT,cpuinfo.x86ID ); + SetDlgItemText(hW, IDC_FAMILYINPUT, cpuinfo.x86Fam); + sprintf(cpuspeedc,"%d MHZ",cpuinfo.cpuspeed); + SetDlgItemText(hW, IDC_CPUSPEEDINPUT, cpuspeedc); + Static_SetText(GetDlgItem(hW, IDC_VENDORNAME), _("CPU Vendor")); + Static_SetText(GetDlgItem(hW, IDC_FAMILYNAME), _("Family")); + Static_SetText(GetDlgItem(hW, IDC_CPUSPEEDNAME), _("CPU Speed")); + Static_SetText(GetDlgItem(hW, IDC_FEATURESNAME), _("Features")); + Static_SetText(GetDlgItem(hW, IDC_CPU_EEREC), _("EERec - EE/IOP recompiler (need MMX/SSE)")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VUGROUP), _("VU Recompilers - All options are set by default")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VU0REC), _("VU0rec - enable recompiler for VU0 unit")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VU1REC), _("VU1rec - enable recompiler for VU1 unit")); + Static_SetText(GetDlgItem(hW, IDC_CPU_GSMULTI), _("Multi threaded GS mode (MTGS)\n(faster on dual core/HT procs, requires pcsx2 restart)")); + Static_SetText(GetDlgItem(hW, IDC_CPU_MULTI), _("Dual Core Mode (DC) - Much faster but only valid with MTGS")); + Static_SetText(GetDlgItem(hW, IDC_FRAMELIMIT), _("Frame Limiting")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_NORMAL), _("Normal - All frames are rendered as fast as possible.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_LIMIT), _("Limit - Force frames to normal speeds if too fast.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_SKIP), _("Frame Skip - In order to achieve normal speeds,\nsome frames are skipped (fast).\nFps displayed counts skipped frames too.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_SKIPVU), _("VU Skip - Same as 'Frame Skip', but tries to skip more.\nArtifacts might be present, but will be faster.")); + Static_SetText(GetDlgItem(hW, IDC_CUSTOM_FPS), _("Custom FPS (0=auto)")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + + //features[0]=':'; + //strcat(features,""); + strcpy(features,""); + if(cpucaps.hasMultimediaExtensions) strcat(features,"MMX"); + if(cpucaps.hasStreamingSIMDExtensions) strcat(features,",SSE"); + if(cpucaps.hasStreamingSIMD2Extensions) strcat(features,",SSE2"); + if(cpucaps.hasStreamingSIMD3Extensions) strcat(features,",SSE3"); + if(cpucaps.hasStreamingSIMD4Extensions) strcat(features,",SSE4.1"); +// if(cpucaps.has3DNOWInstructionExtensions) strcat(features,",3DNOW"); +// if(cpucaps.has3DNOWInstructionExtensionsExt)strcat(features,",3DNOW+"); + if(cpucaps.hasAMD64BitArchitecture) strcat(features,",x86-64"); + SetDlgItemText(hW, IDC_FEATURESINPUT, features); + if(!cpucaps.hasStreamingSIMDExtensions) + { + EnableWindow(GetDlgItem(hW,IDC_RADIORECOMPILERVU),FALSE);//disable checkbox if no SSE2 found + Config.Options &= (PCSX2_VU0REC|PCSX2_VU1REC);//disable the config just in case + } + if(!cpucaps.hasMultimediaExtensions) + { + EnableWindow(GetDlgItem(hW,IDC_RADIORECOMPILER),FALSE); + Config.Options &= ~(PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_COP2REC);//return to interpreter mode + + } + SetDlgItemText(hW, IDC_FEATURESINPUT, features); + + CheckDlgButton(hW, IDC_CPU_EEREC, !!CHECK_EEREC); + +//#ifdef PCSX2_DEVBUILD + CheckDlgButton(hW, IDC_CPU_VU0REC, !!CHECK_VU0REC); + CheckDlgButton(hW, IDC_CPU_VU1REC, !!CHECK_VU1REC); +//#else +// // don't show +// ShowWindow(GetDlgItem(hW, IDC_CPU_VUGROUP), SW_HIDE); +// ShowWindow(GetDlgItem(hW, IDC_CPU_VU0REC), SW_HIDE); +// ShowWindow(GetDlgItem(hW, IDC_CPU_VU1REC), SW_HIDE); +//#endif + + CheckDlgButton(hW, IDC_CPU_GSMULTI, !!CHECK_MULTIGS); + CheckDlgButton(hW, IDC_CPU_MULTI, !!CHECK_DUALCORE); + + CheckRadioButton(hW,IDC_CPU_FL_NORMAL, IDC_CPU_FL_NORMAL+3, IDC_CPU_FL_NORMAL+(CHECK_FRAMELIMIT>>10)); + + sprintf(cfps,"%d",Config.CustomFps); + SetDlgItemText(hW, IDC_CUSTOMFPS, cfps); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + + case IDOK: + Cpu->Shutdown(); + vu0Shutdown(); + vu1Shutdown(); + + newopts = 0; + + if( SendDlgItemMessage(hW,IDC_CPU_EEREC,BM_GETCHECK,0,0) ) newopts |= PCSX2_EEREC; + +//#ifdef PCSX2_DEVBUILD + if( SendDlgItemMessage(hW,IDC_CPU_VU0REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU0REC; + if( SendDlgItemMessage(hW,IDC_CPU_VU1REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU1REC; +//#else //Why oh why were we forcing this in release to public builds? +// newopts |= PCSX2_VU0REC|PCSX2_VU1REC; +//#endif + + if( SendDlgItemMessage(hW,IDC_CPU_GSMULTI,BM_GETCHECK,0,0) ) newopts |= PCSX2_GSMULTITHREAD; + if( SendDlgItemMessage(hW,IDC_CPU_MULTI,BM_GETCHECK,0,0) ) newopts |= PCSX2_DUALCORE; + if( SendDlgItemMessage(hW,IDC_CPU_FRAMELIMIT,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT; + + if( SendDlgItemMessage(hW,IDC_CPU_FL_NORMAL,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_NORMAL; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_LIMIT,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_LIMIT; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIP,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_SKIP; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIPVU,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_VUSKIP; + + if( (Config.Options&PCSX2_GSMULTITHREAD) ^ (newopts&PCSX2_GSMULTITHREAD) ) { + Config.Options = newopts; + SaveConfig(); + MessageBox(NULL, "Restart Pcsx2", "Query", MB_OK); + exit(0); + } + + if( newopts & PCSX2_EEREC ) newopts |= PCSX2_COP2REC; + + Config.Options = newopts; + + GetDlgItemText(hW, IDC_CUSTOMFPS, cfps, 20); + Config.CustomFps = atoi(cfps); + + UpdateVSyncRate(); + SaveConfig(); + + cpuRestartCPU(); + EndDialog(hW, TRUE); + return TRUE; + } + } + return FALSE; +} diff --git a/pcsx2/windows/DebugMemory.c b/pcsx2/windows/DebugMemory.c new file mode 100644 index 0000000000..a8c89758bb --- /dev/null +++ b/pcsx2/windows/DebugMemory.c @@ -0,0 +1,239 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include "Common.h" +#include "resource.h" + + +unsigned long memory_addr; +BOOL mem_inupdate = FALSE; +HWND memoryhWnd,hWnd_memscroll,hWnd_memorydump; +unsigned long memory_patch; +unsigned long data_patch; + +///MEMORY DUMP +unsigned char Debug_Read8(unsigned long addr)//just for anycase.. +{ +#ifdef _WIN32 + __try + { +#endif + u8 val8; + memRead8(addr, &val8); + return val8; +#ifdef _WIN32 + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return 0; + } +#endif +} + + +void RefreshMemory(void) +{ + int x, y; + unsigned long addr; + unsigned char b; + + char buf[128], text[32], temp[8]; + + + + addr = memory_addr; + + if (!mem_inupdate) + { + sprintf(buf, "%08X", addr); + SetDlgItemText(memoryhWnd, IDC_MEMORY_ADDR, buf); + } + + SendMessage(hWnd_memorydump, LB_RESETCONTENT, 0, 0); + + for (y = 0; y < 21; y++) + { + memset(text, 0, 32); + sprintf(buf, "%08X: ", addr); + + for (x = 0; x < 16; x++) + { + b = Debug_Read8(addr++); + + sprintf(temp, "%02X ", b); + strcat(buf, temp); + + if (b < 32 || b > 127) b = 32; + sprintf(temp, "%c", b); + strcat(text, temp); + + + if (x == 7) strcat(buf, " "); + } + + strcat(buf, " "); + strcat(buf, text); + + SendMessage(hWnd_memorydump, LB_ADDSTRING, 0, (LPARAM)buf); + } +} + + +BOOL APIENTRY DumpMemProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char start[16], end[16], fname[128], buf[128]; + u32 start_pc, end_pc, addr; + u8 data; + + FILE *fp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_DUMPMEM_START, buf); + SetDlgItemText(hDlg, IDC_DUMPMEM_END, buf); + SetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, "dump.raw"); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_DUMPMEM_START, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMPMEM_END, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, fname, 128); + fp = fopen(fname, "wb"); + if (fp == NULL) + { + SysMessage("Can't open file '%s' for writing!\n", fname); + } + else + { + for (addr = start_pc; addr < end_pc; addr ++) { + memRead8( addr, &data ); + fwrite(&data, 1, 1, fp); + } + + fclose(fp); + } + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + + + +BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + + char buf[16]; + switch (message) + { + case WM_INITDIALOG: + memory_addr = cpuRegs.pc; + sprintf(buf, "%08X", memory_addr); + SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); + memory_patch= 0; + sprintf(buf, "%08X", memory_patch); + SetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf); + data_patch=0; + sprintf(buf, "%08X", data_patch); + SetDlgItemText(hDlg, IDC_DATA_PATCH, buf); + hWnd_memorydump = GetDlgItem(hDlg, IDC_MEMORY_DUMP); + hWnd_memscroll = GetDlgItem(hDlg, IDC_MEM_SCROLL); + + + + SendMessage(hWnd_memorydump, LB_INITSTORAGE, 11, 1280); + SendMessage(hWnd_memscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_memscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + + RefreshMemory(); + return TRUE; + case WM_VSCROLL: + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: memory_addr += 0x00000010; RefreshMemory(); break; + case SB_LINEUP: memory_addr -= 0x00000010; RefreshMemory(); break; + case SB_PAGEDOWN: memory_addr += 0x00000150; RefreshMemory(); break; + case SB_PAGEUP: memory_addr -= 0x00000150; RefreshMemory(); break; + } + + return TRUE; + + case WM_CLOSE: + EndDialog(hDlg, TRUE ); + return TRUE; + + + case WM_COMMAND: + if (HIWORD(wParam) == EN_UPDATE) + { + mem_inupdate = TRUE; + GetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf, 9); + buf[8] = 0; + + sscanf(buf, "%x", &memory_addr); + RefreshMemory(); + mem_inupdate = FALSE; + return TRUE; + } + + switch (LOWORD(wParam)) { + case IDC_PATCH: + GetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf, 9);//32bit address + buf[8] = 0; + sscanf(buf, "%x", &memory_patch); + GetDlgItemText(hDlg, IDC_DATA_PATCH, buf, 9);//32 bit data only for far + buf[8] = 0; + sscanf(buf, "%x", &data_patch); + memWrite32( memory_patch, data_patch ); + sprintf(buf, "%08X", memory_patch); + SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); + RefreshMemory(); + return TRUE; + + case IDC_DUMPRAW: + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMPMEM), hDlg, (DLGPROC)DumpMemProc); + + return TRUE; + + case IDC_MEMORY_CLOSE: + EndDialog(hDlg, TRUE ); + return TRUE; + } + break; + } + + return FALSE; +} diff --git a/pcsx2/windows/Debugger.c b/pcsx2/windows/Debugger.c new file mode 100644 index 0000000000..ec141478c2 --- /dev/null +++ b/pcsx2/windows/Debugger.c @@ -0,0 +1,677 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include "resource.h" +#include "Debugger.h" +#include "Common.h" +#include "win32.h" +#include "PsxMem.h" +#include "R3000A.h" + +extern void (*IOP_DEBUG_BSC[64])(char *buf); +extern void UpdateR5900op(); +void RefreshIOPDebugger(void); +extern int ISR3000A;//for disasm +HWND hWnd_debugdisasm, hWnd_debugscroll,hWnd_IOP_debugdisasm, hWnd_IOP_debugscroll; +unsigned long DebuggerPC = 0; +HWND hRegDlg;//for debug registers.. +HWND debughWnd; +unsigned long DebuggerIOPPC=0; +HWND hIOPDlg;//IOP debugger + + +void RefreshDebugAll()//refresh disasm and register window +{ + RefreshDebugger(); + RefreshIOPDebugger(); + UpdateRegs(); +} + +void MakeDebugOpcode(void) +{ + memRead32( opcode_addr, &cpuRegs.code ); +} + +void MakeIOPDebugOpcode(void) +{ + psxRegs.code = PSXMu32( opcode_addr); +} + +BOOL HasBreakpoint() +{ + int t; + + for (t = 0; t < NUM_BREAKPOINTS; t++) + { + switch (bkpt_regv[t].type) { + case 1: // exec + if (cpuRegs.pc == bkpt_regv[t].value) return TRUE; + break; + + case 2: // count + if ((cpuRegs.cycle - 10) <= bkpt_regv[t].value && + (cpuRegs.cycle + 10) >= bkpt_regv[t].value) return TRUE; + break; + } + } + return FALSE; + +} +BOOL APIENTRY JumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + unsigned long temp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_JUMP_PC, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_JUMP_PC, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &temp); + + temp &= 0xFFFFFFFC; + DebuggerPC = temp - 0x00000038; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +extern void EEDumpRegs(FILE * fp); +extern void IOPDumpRegs(FILE * fp); +BOOL APIENTRY DumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char start[16], end[16], fname[128], tmp[128], buf[128]; + unsigned long start_pc, end_pc, temp; + + FILE *fp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_DUMP_START, buf); + SetDlgItemText(hDlg, IDC_DUMP_END, buf); + SetDlgItemText(hDlg, IDC_DUMP_FNAME, "EEdisasm.txt"); + + sprintf(buf, "%08X", psxRegs.pc); + SetDlgItemText(hDlg, IDC_DUMP_STARTIOP, buf); + SetDlgItemText(hDlg, IDC_DUMP_ENDIOP, buf); + SetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, "IOPdisasm.txt"); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_DUMP_START, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_END, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_FNAME, fname, 128); + fp = fopen(fname, "wt"); + if (fp == NULL) + { + //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); + } + else + { + fprintf(fp,"----------------------------------\n"); + fprintf(fp,"EE DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + for (temp = start_pc; temp <= end_pc; temp += 4) + { + + + opcode_addr=temp; + MakeDebugOpcode(); + OpcodePrintTable[(cpuRegs.code) >> 26](tmp); + if (HasBreakpoint(temp)) + { + sprintf(buf, "*%08X %08X: %s", temp, cpuRegs.code, tmp); + } + else + { + sprintf(buf, "%08X %08X: %s", temp, cpuRegs.code, tmp); + } + + fprintf(fp, "%s\n", buf); + } + + + fprintf(fp,"\n\n\n----------------------------------\n"); + fprintf(fp,"EE REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + EEDumpRegs(fp); + fclose(fp); + } + + + + GetDlgItemText(hDlg, IDC_DUMP_STARTIOP, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_ENDIOP, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, fname, 128); + fp = fopen(fname, "wt"); + if (fp == NULL) + { + //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); + } + else + { + fprintf(fp,"----------------------------------\n"); + fprintf(fp,"IOP DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + for (temp = start_pc; temp <= end_pc; temp += 4) + { + opcode_addr=temp; + MakeIOPDebugOpcode(); + IOP_DEBUG_BSC[(psxRegs.code) >> 26](tmp); + sprintf(buf, "%08X %08X: %s", temp, psxRegs.code, tmp); + fprintf(fp, "%s\n", buf); + } + + fprintf(fp,"\n\n\n----------------------------------\n"); + fprintf(fp,"IOP REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + IOPDumpRegs(fp); + fclose(fp); + } + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +BOOL APIENTRY BpexecProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", bkpt_regv[0].value); + SetDlgItemText(hDlg, IDC_EXECBP, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_EXECBP, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &bkpt_regv[0].value); + bkpt_regv[0].type = 1; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +BOOL APIENTRY BpcntProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", bkpt_regv[1].value); + SetDlgItemText(hDlg, IDC_CNTBP, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_CNTBP, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &bkpt_regv[1].value); + bkpt_regv[1].type = 2; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} +HINSTANCE m2_hInst; +HWND m2_hWnd; +HWND hIopDlg; + +LRESULT CALLBACK IOP_DISASM(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + hWnd_IOP_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM_IOP); + hWnd_IOP_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL_IOP); + + SendMessage(hWnd_IOP_debugdisasm, LB_INITSTORAGE, 29, 1131); + SendMessage(hWnd_IOP_debugscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_IOP_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + RefreshIOPDebugger(); + return (TRUE); + case WM_VSCROLL: + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: DebuggerIOPPC += 0x00000004; RefreshIOPDebugger(); break; + case SB_LINEUP: DebuggerIOPPC -= 0x00000004; RefreshIOPDebugger(); break; + case SB_PAGEDOWN: DebuggerIOPPC += 0x00000029; RefreshIOPDebugger(); break; + case SB_PAGEUP: DebuggerIOPPC -= 0x00000029; RefreshIOPDebugger(); break; + } + return TRUE; + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + } + break; + } + + return(FALSE); +} +int CreatePropertySheet2(HWND hwndOwner) +{ + PROPSHEETPAGE psp[1]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USETITLE; + psp[0].hInstance = m2_hInst; + psp[0].pszTemplate = MAKEINTRESOURCE( IDD_IOP_DEBUG); + psp[0].pszIcon = NULL; + psp[0].pfnDlgProc =(DLGPROC)IOP_DISASM; + psp[0].pszTitle = "Iop Disasm"; + psp[0].lParam = 0; + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; + psh.hwndParent =hwndOwner; + psh.hInstance = m2_hInst; + psh.pszIcon = NULL; + psh.pszCaption = (LPSTR) "IOP Debugger"; + psh.nStartPage = 0; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + + return (PropertySheet(&psh)); +} + +/** non-zero if the dialog is currently executing instructions. */ +static int isRunning = 0; + +/** non-zero if the user has requested a break in the execution of instructions. */ +static int breakRequested = 0; + +static +void EnterRunningState(HWND hDlg) +{ + isRunning = 1; + breakRequested = 0; + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), FALSE); +} + +static +void EnterHaltedState(HWND hDlg) +{ + isRunning = 0; + breakRequested = 0; + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), TRUE); +} + +BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + FARPROC jmpproc, dumpproc; + FARPROC bpexecproc, bpcntproc; + u32 oldpc = 0; + + switch (message) + { + case WM_INITDIALOG: + ShowCursor(TRUE); + isRunning = 0; + breakRequested = 0; + + SetWindowText(hDlg, "R5900 Debugger"); + debughWnd=hDlg; + DebuggerPC = 0; + // Clear all breakpoints. + memset(bkpt_regv, 0, sizeof(bkpt_regv)); + + hWnd_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM); + hWnd_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL); + + SendMessage(hWnd_debugdisasm, LB_INITSTORAGE, 29, 1131); + SendMessage(hWnd_debugscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + + hRegDlg = (HWND)CreatePropertySheet(hDlg); + hIopDlg = (HWND)CreatePropertySheet2(hDlg); + UpdateRegs(); + SetWindowPos(hRegDlg, NULL, 525, 0, 600, 515,0 ); + SetWindowPos(hIopDlg, NULL, 0 ,515,600,230,0); + RefreshDebugger(); + RefreshIOPDebugger(); + return TRUE; + + case WM_VSCROLL: + + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: DebuggerPC += 0x00000004; RefreshDebugAll(); break; + case SB_LINEUP: DebuggerPC -= 0x00000004; RefreshDebugAll(); break; + case SB_PAGEDOWN: DebuggerPC += 0x00000074; RefreshDebugAll(); break; + case SB_PAGEUP: DebuggerPC -= 0x00000074; RefreshDebugAll(); break; + } + return TRUE; + + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_DEBUG_STEP: + oldpc = psxRegs.pc; + EnterRunningState(hDlg); + Cpu->Step(); + while(oldpc == psxRegs.pc) Cpu->Step(); + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_STEP_EE: + EnterRunningState(hDlg); + Cpu->Step(); + EnterHaltedState(hDlg); + DebuggerPC = 0; + DebuggerIOPPC=0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_STEP_OVER: + /* Step over a subroutine call. */ + /* Note that this may take some time to execute and + * because Cpu->Step() pumps the message loop, we need + * to guard against re-entry. We do that by disabling the step buttons. + */ + EnterRunningState(hDlg); + + if (memRead32(cpuRegs.pc, &cpuRegs.code) != -1){ + u32 target_pc = 0; + if (3 == (cpuRegs.code >> 26)){ + /* it's a JAL instruction. */ + target_pc = cpuRegs.pc + 8; + } else if (0x0c == (cpuRegs.code & 0xFF)){ + /* it's a syscall. */ + target_pc = cpuRegs.pc + 4; + } + if (0 != target_pc){ + while(target_pc != cpuRegs.pc && !breakRequested) { + Cpu->Step(); + } + } else { + Cpu->Step(); + } + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + + return TRUE; + + case IDC_DEBUG_SKIP: + cpuRegs.pc+= 4; + DebuggerPC = 0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_BREAK: + breakRequested = 1; + return TRUE; + + case IDC_DEBUG_GO: + EnterRunningState(hDlg); + for (;;) { + if (breakRequested || HasBreakpoint()) { + Cpu->Step(); + break; + } + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_RUN_TO_CURSOR: + { + /* Run to the cursor without checking for breakpoints. */ + int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); + if (sel != LB_ERR){ + const u32 target_pc = DebuggerPC + sel*4; + EnterRunningState(hDlg); + while(target_pc != cpuRegs.pc && !breakRequested) { + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + } + return TRUE; + } + + case IDC_DEBUG_STEP_TO_CURSOR: + { + int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); + if (sel != LB_ERR){ + const u32 target_pc = DebuggerPC + sel*4; + EnterRunningState(hDlg); + while(target_pc != cpuRegs.pc && !breakRequested) { + if (HasBreakpoint()) { + Cpu->Step(); + break; + } + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + } + return TRUE; + } + + case IDC_DEBUG_LOG: +#ifdef PCSX2_DEVBUILD + Log = 1 - Log; +#endif + return TRUE; + + case IDC_DEBUG_RESETTOPC: + DebuggerPC = 0; + DebuggerIOPPC=0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_JUMP: + jmpproc = MakeProcInstance((FARPROC)JumpProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_JUMP), debughWnd, (DLGPROC)jmpproc); + FreeProcInstance(jmpproc); + + RefreshDebugAll(); + return TRUE; + + case IDC_CPUOP: + UpdateR5900op(); + return TRUE; + + case IDC_DEBUG_BP_EXEC: + bpexecproc = MakeProcInstance((FARPROC)BpexecProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPEXEC), debughWnd, (DLGPROC)bpexecproc); + FreeProcInstance(bpexecproc); + return TRUE; + + case IDC_DEBUG_BP_COUNT: + bpcntproc = MakeProcInstance((FARPROC)BpcntProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPCNT), debughWnd, (DLGPROC)bpcntproc); + FreeProcInstance(bpcntproc); + return TRUE; + + case IDC_DEBUG_BP_CLEAR: + memset(bkpt_regv, 0, sizeof(bkpt_regv)); + return TRUE; + + case IDC_DEBUG_DUMP: + dumpproc = MakeProcInstance((FARPROC)DumpProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMP), debughWnd, (DLGPROC)dumpproc); + FreeProcInstance(dumpproc); + return TRUE; + + case IDC_DEBUG_MEMORY: + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_MEMORY), debughWnd, (DLGPROC)MemoryProc); + return TRUE; + + case IDC_DEBUG_CLOSE: + + EndDialog(hRegDlg ,TRUE); + EndDialog(hDlg,TRUE); + EndDialog(hIopDlg,TRUE); + + ClosePlugins(); + isRunning = 0; + return TRUE; + + } + break; + } + + return FALSE; +} + +/* this lives in interpreter.c */ +extern char* bios[]; + +void RefreshDebugger(void) +{ + unsigned long t; + int cnt; + + if (DebuggerPC == 0) + DebuggerPC = cpuRegs.pc; //- 0x00000038; + + SendMessage(hWnd_debugdisasm, LB_RESETCONTENT, 0, 0); + + for (t = DebuggerPC, cnt = 0; t < (DebuggerPC + 0x00000074); t += 0x00000004, cnt++) + { + char syscall_str[128]; + // Make the opcode. + u32 *mem = (u32*)PSM(t); + char *str; + if (mem == NULL) { + char nullAddr[256]; + sprintf(nullAddr, "%8.8lx 00000000: NULL MEMORY", t); str = nullAddr; + } else { + /* special procesing for syscall. This should probably be moved into the disR5900Fasm() call in the future. */ + if (0x0c == *mem && 0x24030000 == (*(mem-1) & 0xFFFFFF00)){ + /* it's a syscall preceeded by a li v1,$data instruction. */ + u8 bios_call = *(mem-1) & 0xFF; + sprintf(syscall_str, "%08X:\tsyscall\t%s", t, bios[bios_call]); + str = syscall_str; + } else { + str = disR5900Fasm(*mem, t); + } + } + SendMessage(hWnd_debugdisasm, LB_ADDSTRING, 0, (LPARAM)str); + } +} + +void RefreshIOPDebugger(void) +{ + unsigned long t; + int cnt; + + if (DebuggerIOPPC == 0){ + DebuggerIOPPC = psxRegs.pc; //- 0x00000038; + } + SendMessage(hWnd_IOP_debugdisasm, LB_RESETCONTENT, 0, 0); + + for (t = DebuggerIOPPC, cnt = 0; t < (DebuggerIOPPC + 0x00000029); t += 0x00000004, cnt++) + { + // Make the opcode. + u32 mem = PSXMu32(t); + char *str = disR3000Fasm(mem, t); + SendMessage(hWnd_IOP_debugdisasm, LB_ADDSTRING, 0, (LPARAM)str); + } + +} diff --git a/pcsx2/windows/Debugger.h b/pcsx2/windows/Debugger.h new file mode 100644 index 0000000000..babd8a2a65 --- /dev/null +++ b/pcsx2/windows/Debugger.h @@ -0,0 +1,54 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#define NUM_BREAKPOINTS 8 + +extern void (*OpcodePrintTable[64])(char *buf); + +extern BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + + +extern BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +extern void RefreshDebugger(void); + +unsigned long opcode_addr; + +typedef struct +{ + int type; + unsigned long value; +} breakpoints; + +breakpoints bkpt_regv[NUM_BREAKPOINTS]; + + + +LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +void UpdateRegs(void); +int CreatePropertySheet(HWND hwndOwner); diff --git a/pcsx2/windows/Debugreg.c b/pcsx2/windows/Debugreg.c new file mode 100644 index 0000000000..f73700c898 --- /dev/null +++ b/pcsx2/windows/Debugreg.c @@ -0,0 +1,1483 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINVER 0x0500 +#include +#include + +#include "resource.h" +#include "Debugger.h" +#include "Debug.h" +#include "R5900.h" +#include "R3000a.h" +#include "VUmicro.h" + +HINSTANCE m_hInst; +HWND m_hWnd; +char text1[256]; + + +/*R3000a registers handle */ +static HWND IOPGPR0Handle=NULL; +static HWND IOPGPR1Handle=NULL; +static HWND IOPGPR2Handle=NULL; +static HWND IOPGPR3Handle=NULL; +static HWND IOPGPR4Handle=NULL; +static HWND IOPGPR5Handle=NULL; +static HWND IOPGPR6Handle=NULL; +static HWND IOPGPR7Handle=NULL; +static HWND IOPGPR8Handle=NULL; +static HWND IOPGPR9Handle=NULL; +static HWND IOPGPR10Handle=NULL; +static HWND IOPGPR11Handle=NULL; +static HWND IOPGPR12Handle=NULL; +static HWND IOPGPR13Handle=NULL; +static HWND IOPGPR14Handle=NULL; +static HWND IOPGPR15Handle=NULL; +static HWND IOPGPR16Handle=NULL; +static HWND IOPGPR17Handle=NULL; +static HWND IOPGPR18Handle=NULL; +static HWND IOPGPR19Handle=NULL; +static HWND IOPGPR20Handle=NULL; +static HWND IOPGPR21Handle=NULL; +static HWND IOPGPR22Handle=NULL; +static HWND IOPGPR23Handle=NULL; +static HWND IOPGPR24Handle=NULL; +static HWND IOPGPR25Handle=NULL; +static HWND IOPGPR26Handle=NULL; +static HWND IOPGPR27Handle=NULL; +static HWND IOPGPR28Handle=NULL; +static HWND IOPGPR29Handle=NULL; +static HWND IOPGPR30Handle=NULL; +static HWND IOPGPR31Handle=NULL; +static HWND IOPGPRPCHandle=NULL; +static HWND IOPGPRHIHandle=NULL; +static HWND IOPGPRLOHandle=NULL; + +/*R5900 registers handle */ +static HWND GPR0Handle=NULL; +static HWND GPR1Handle=NULL; +static HWND GPR2Handle=NULL; +static HWND GPR3Handle=NULL; +static HWND GPR4Handle=NULL; +static HWND GPR5Handle=NULL; +static HWND GPR6Handle=NULL; +static HWND GPR7Handle=NULL; +static HWND GPR8Handle=NULL; +static HWND GPR9Handle=NULL; +static HWND GPR10Handle=NULL; +static HWND GPR11Handle=NULL; +static HWND GPR12Handle=NULL; +static HWND GPR13Handle=NULL; +static HWND GPR14Handle=NULL; +static HWND GPR15Handle=NULL; +static HWND GPR16Handle=NULL; +static HWND GPR17Handle=NULL; +static HWND GPR18Handle=NULL; +static HWND GPR19Handle=NULL; +static HWND GPR20Handle=NULL; +static HWND GPR21Handle=NULL; +static HWND GPR22Handle=NULL; +static HWND GPR23Handle=NULL; +static HWND GPR24Handle=NULL; +static HWND GPR25Handle=NULL; +static HWND GPR26Handle=NULL; +static HWND GPR27Handle=NULL; +static HWND GPR28Handle=NULL; +static HWND GPR29Handle=NULL; +static HWND GPR30Handle=NULL; +static HWND GPR31Handle=NULL; +static HWND GPRPCHandle=NULL; +static HWND GPRHIHandle=NULL; +static HWND GPRLOHandle=NULL; +/*end of r3000a registers handle */ +/*cop0 registers here */ +static HWND COP00Handle=NULL; +static HWND COP01Handle=NULL; +static HWND COP02Handle=NULL; +static HWND COP03Handle=NULL; +static HWND COP04Handle=NULL; +static HWND COP05Handle=NULL; +static HWND COP06Handle=NULL; +static HWND COP07Handle=NULL; +static HWND COP08Handle=NULL; +static HWND COP09Handle=NULL; +static HWND COP010Handle=NULL; +static HWND COP011Handle=NULL; +static HWND COP012Handle=NULL; +static HWND COP013Handle=NULL; +static HWND COP014Handle=NULL; +static HWND COP015Handle=NULL; +static HWND COP016Handle=NULL; +static HWND COP017Handle=NULL; +static HWND COP018Handle=NULL; +static HWND COP019Handle=NULL; +static HWND COP020Handle=NULL; +static HWND COP021Handle=NULL; +static HWND COP022Handle=NULL; +static HWND COP023Handle=NULL; +static HWND COP024Handle=NULL; +static HWND COP025Handle=NULL; +static HWND COP026Handle=NULL; +static HWND COP027Handle=NULL; +static HWND COP028Handle=NULL; +static HWND COP029Handle=NULL; +static HWND COP030Handle=NULL; +static HWND COP031Handle=NULL; +static HWND COP0PCHandle=NULL; +static HWND COP0HIHandle=NULL; +static HWND COP0LOHandle=NULL; +/*end of cop0 registers */ +/*cop1 registers here */ +static HWND COP10Handle=NULL; +static HWND COP11Handle=NULL; +static HWND COP12Handle=NULL; +static HWND COP13Handle=NULL; +static HWND COP14Handle=NULL; +static HWND COP15Handle=NULL; +static HWND COP16Handle=NULL; +static HWND COP17Handle=NULL; +static HWND COP18Handle=NULL; +static HWND COP19Handle=NULL; +static HWND COP110Handle=NULL; +static HWND COP111Handle=NULL; +static HWND COP112Handle=NULL; +static HWND COP113Handle=NULL; +static HWND COP114Handle=NULL; +static HWND COP115Handle=NULL; +static HWND COP116Handle=NULL; +static HWND COP117Handle=NULL; +static HWND COP118Handle=NULL; +static HWND COP119Handle=NULL; +static HWND COP120Handle=NULL; +static HWND COP121Handle=NULL; +static HWND COP122Handle=NULL; +static HWND COP123Handle=NULL; +static HWND COP124Handle=NULL; +static HWND COP125Handle=NULL; +static HWND COP126Handle=NULL; +static HWND COP127Handle=NULL; +static HWND COP128Handle=NULL; +static HWND COP129Handle=NULL; +static HWND COP130Handle=NULL; +static HWND COP131Handle=NULL; +static HWND COP1C0Handle=NULL; +static HWND COP1C1Handle=NULL; +static HWND COP1ACCHandle=NULL; +/*end of cop1 registers */ +/*cop2 floating registers*/ +static HWND VU0F00Handle=NULL; +static HWND VU0F01Handle=NULL; +static HWND VU0F02Handle=NULL; +static HWND VU0F03Handle=NULL; +static HWND VU0F04Handle=NULL; +static HWND VU0F05Handle=NULL; +static HWND VU0F06Handle=NULL; +static HWND VU0F07Handle=NULL; +static HWND VU0F08Handle=NULL; +static HWND VU0F09Handle=NULL; +static HWND VU0F10Handle=NULL; +static HWND VU0F11Handle=NULL; +static HWND VU0F12Handle=NULL; +static HWND VU0F13Handle=NULL; +static HWND VU0F14Handle=NULL; +static HWND VU0F15Handle=NULL; +static HWND VU0F16Handle=NULL; +static HWND VU0F17Handle=NULL; +static HWND VU0F18Handle=NULL; +static HWND VU0F19Handle=NULL; +static HWND VU0F20Handle=NULL; +static HWND VU0F21Handle=NULL; +static HWND VU0F22Handle=NULL; +static HWND VU0F23Handle=NULL; +static HWND VU0F24Handle=NULL; +static HWND VU0F25Handle=NULL; +static HWND VU0F26Handle=NULL; +static HWND VU0F27Handle=NULL; +static HWND VU0F28Handle=NULL; +static HWND VU0F29Handle=NULL; +static HWND VU0F30Handle=NULL; +static HWND VU0F31Handle=NULL; +/*end of cop2 floating registers*/ +/*cop2 control registers */ +static HWND VU0C00Handle=NULL; +static HWND VU0C01Handle=NULL; +static HWND VU0C02Handle=NULL; +static HWND VU0C03Handle=NULL; +static HWND VU0C04Handle=NULL; +static HWND VU0C05Handle=NULL; +static HWND VU0C06Handle=NULL; +static HWND VU0C07Handle=NULL; +static HWND VU0C08Handle=NULL; +static HWND VU0C09Handle=NULL; +static HWND VU0C10Handle=NULL; +static HWND VU0C11Handle=NULL; +static HWND VU0C12Handle=NULL; +static HWND VU0C13Handle=NULL; +static HWND VU0C14Handle=NULL; +static HWND VU0C15Handle=NULL; +static HWND VU0C16Handle=NULL; +static HWND VU0C17Handle=NULL; +static HWND VU0C18Handle=NULL; +static HWND VU0C19Handle=NULL; +static HWND VU0C20Handle=NULL; +static HWND VU0C21Handle=NULL; +static HWND VU0C22Handle=NULL; +static HWND VU0C23Handle=NULL; +static HWND VU0C24Handle=NULL; +static HWND VU0C25Handle=NULL; +static HWND VU0C26Handle=NULL; +static HWND VU0C27Handle=NULL; +static HWND VU0C28Handle=NULL; +static HWND VU0C29Handle=NULL; +static HWND VU0C30Handle=NULL; +static HWND VU0C31Handle=NULL; +static HWND VU0ACCHandle=NULL; +/*end of cop2 control registers */ +/*vu1 floating registers*/ +static HWND VU1F00Handle=NULL; +static HWND VU1F01Handle=NULL; +static HWND VU1F02Handle=NULL; +static HWND VU1F03Handle=NULL; +static HWND VU1F04Handle=NULL; +static HWND VU1F05Handle=NULL; +static HWND VU1F06Handle=NULL; +static HWND VU1F07Handle=NULL; +static HWND VU1F08Handle=NULL; +static HWND VU1F09Handle=NULL; +static HWND VU1F10Handle=NULL; +static HWND VU1F11Handle=NULL; +static HWND VU1F12Handle=NULL; +static HWND VU1F13Handle=NULL; +static HWND VU1F14Handle=NULL; +static HWND VU1F15Handle=NULL; +static HWND VU1F16Handle=NULL; +static HWND VU1F17Handle=NULL; +static HWND VU1F18Handle=NULL; +static HWND VU1F19Handle=NULL; +static HWND VU1F20Handle=NULL; +static HWND VU1F21Handle=NULL; +static HWND VU1F22Handle=NULL; +static HWND VU1F23Handle=NULL; +static HWND VU1F24Handle=NULL; +static HWND VU1F25Handle=NULL; +static HWND VU1F26Handle=NULL; +static HWND VU1F27Handle=NULL; +static HWND VU1F28Handle=NULL; +static HWND VU1F29Handle=NULL; +static HWND VU1F30Handle=NULL; +static HWND VU1F31Handle=NULL; +/*end of vu1 floating registers*/ +/*vu1 control registers */ +static HWND VU1C00Handle=NULL; +static HWND VU1C01Handle=NULL; +static HWND VU1C02Handle=NULL; +static HWND VU1C03Handle=NULL; +static HWND VU1C04Handle=NULL; +static HWND VU1C05Handle=NULL; +static HWND VU1C06Handle=NULL; +static HWND VU1C07Handle=NULL; +static HWND VU1C08Handle=NULL; +static HWND VU1C09Handle=NULL; +static HWND VU1C10Handle=NULL; +static HWND VU1C11Handle=NULL; +static HWND VU1C12Handle=NULL; +static HWND VU1C13Handle=NULL; +static HWND VU1C14Handle=NULL; +static HWND VU1C15Handle=NULL; +static HWND VU1C16Handle=NULL; +static HWND VU1C17Handle=NULL; +static HWND VU1C18Handle=NULL; +static HWND VU1C19Handle=NULL; +static HWND VU1C20Handle=NULL; +static HWND VU1C21Handle=NULL; +static HWND VU1C22Handle=NULL; +static HWND VU1C23Handle=NULL; +static HWND VU1C24Handle=NULL; +static HWND VU1C25Handle=NULL; +static HWND VU1C26Handle=NULL; +static HWND VU1C27Handle=NULL; +static HWND VU1C28Handle=NULL; +static HWND VU1C29Handle=NULL; +static HWND VU1C30Handle=NULL; +static HWND VU1C31Handle=NULL; +static HWND VU1ACCHandle=NULL; +/*end of vu1 control registers */ + +LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +//comctl32 lib must add to project.. +int CreatePropertySheet(HWND hwndOwner) +{ + + PROPSHEETPAGE psp[7]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USETITLE; + psp[0].hInstance = m_hInst; + psp[0].pszTemplate = MAKEINTRESOURCE( IDD_GPREGS); + psp[0].pszIcon = NULL; + psp[0].pfnDlgProc =(DLGPROC)R5900reg; + psp[0].pszTitle = "R5900"; + psp[0].lParam = 0; + + psp[1].dwSize = sizeof(PROPSHEETPAGE); + psp[1].dwFlags = PSP_USETITLE; + psp[1].hInstance = m_hInst; + psp[1].pszTemplate = MAKEINTRESOURCE( IDD_CP0REGS ); + psp[1].pszIcon = NULL; + psp[1].pfnDlgProc =(DLGPROC)COP0reg; + psp[1].pszTitle = "COP0"; + psp[1].lParam = 0; + + psp[2].dwSize = sizeof(PROPSHEETPAGE); + psp[2].dwFlags = PSP_USETITLE; + psp[2].hInstance = m_hInst; + psp[2].pszTemplate = MAKEINTRESOURCE( IDD_CP1REGS ); + psp[2].pszIcon = NULL; + psp[2].pfnDlgProc =(DLGPROC)COP1reg; + psp[2].pszTitle = "COP1"; + psp[2].lParam = 0; + + psp[3].dwSize = sizeof(PROPSHEETPAGE); + psp[3].dwFlags = PSP_USETITLE; + psp[3].hInstance = m_hInst; + psp[3].pszTemplate = MAKEINTRESOURCE( IDD_VU0REGS ); + psp[3].pszIcon = NULL; + psp[3].pfnDlgProc =(DLGPROC)COP2Freg; + psp[3].pszTitle = "COP2F"; + psp[3].lParam = 0; + + psp[4].dwSize = sizeof(PROPSHEETPAGE); + psp[4].dwFlags = PSP_USETITLE; + psp[4].hInstance = m_hInst; + psp[4].pszTemplate = MAKEINTRESOURCE( IDD_VU0INTEGER ); + psp[4].pszIcon = NULL; + psp[4].pfnDlgProc =(DLGPROC)COP2Creg; + psp[4].pszTitle = "COP2C"; + psp[4].lParam = 0; + + psp[5].dwSize = sizeof(PROPSHEETPAGE); + psp[5].dwFlags = PSP_USETITLE; + psp[5].hInstance = m_hInst; + psp[5].pszTemplate = MAKEINTRESOURCE( IDD_VU1REGS ); + psp[5].pszIcon = NULL; + psp[5].pfnDlgProc =(DLGPROC)VU1Freg; + psp[5].pszTitle = "VU1F"; + psp[5].lParam = 0; + + psp[6].dwSize = sizeof(PROPSHEETPAGE); + psp[6].dwFlags = PSP_USETITLE; + psp[6].hInstance = m_hInst; + psp[6].pszTemplate = MAKEINTRESOURCE( IDD_VU1INTEGER ); + psp[6].pszIcon = NULL; + psp[6].pfnDlgProc =(DLGPROC)VU1Creg; + psp[6].pszTitle = "VU1C"; + psp[6].lParam = 0; + + psp[6].dwSize = sizeof(PROPSHEETPAGE); + psp[6].dwFlags = PSP_USETITLE; + psp[6].hInstance = m_hInst; + psp[6].pszTemplate = MAKEINTRESOURCE( IDD_IOPREGS ); + psp[6].pszIcon = NULL; + psp[6].pfnDlgProc =(DLGPROC)R3000reg; + psp[6].pszTitle = "R3000"; + psp[6].lParam = 0; + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; + psh.hwndParent =hwndOwner; + psh.hInstance = m_hInst; + psh.pszIcon = NULL; + psh.pszCaption = (LPSTR) "Debugger"; + psh.nStartPage = 0; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + + return (PropertySheet(&psh)); + +} +LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + IOPGPR0Handle=GetDlgItem(hDlg,IDC_IOPGPR0); + IOPGPR1Handle=GetDlgItem(hDlg,IDC_IOPGPR1); + IOPGPR2Handle=GetDlgItem(hDlg,IDC_IOPGPR2); + IOPGPR3Handle=GetDlgItem(hDlg,IDC_IOPGPR3); + IOPGPR4Handle=GetDlgItem(hDlg,IDC_IOPGPR4); + IOPGPR5Handle=GetDlgItem(hDlg,IDC_IOPGPR5); + IOPGPR6Handle=GetDlgItem(hDlg,IDC_IOPGPR6); + IOPGPR7Handle=GetDlgItem(hDlg,IDC_IOPGPR7); + IOPGPR8Handle=GetDlgItem(hDlg,IDC_IOPGPR8); + IOPGPR9Handle=GetDlgItem(hDlg,IDC_IOPGPR9); + IOPGPR10Handle=GetDlgItem(hDlg,IDC_IOPGPR10); + IOPGPR11Handle=GetDlgItem(hDlg,IDC_IOPGPR11); + IOPGPR12Handle=GetDlgItem(hDlg,IDC_IOPGPR12); + IOPGPR13Handle=GetDlgItem(hDlg,IDC_IOPGPR13); + IOPGPR14Handle=GetDlgItem(hDlg,IDC_IOPGPR14); + IOPGPR15Handle=GetDlgItem(hDlg,IDC_IOPGPR15); + IOPGPR16Handle=GetDlgItem(hDlg,IDC_IOPGPR16); + IOPGPR17Handle=GetDlgItem(hDlg,IDC_IOPGPR17); + IOPGPR18Handle=GetDlgItem(hDlg,IDC_IOPGPR18); + IOPGPR19Handle=GetDlgItem(hDlg,IDC_IOPGPR19); + IOPGPR20Handle=GetDlgItem(hDlg,IDC_IOPGPR20); + IOPGPR21Handle=GetDlgItem(hDlg,IDC_IOPGPR21); + IOPGPR22Handle=GetDlgItem(hDlg,IDC_IOPGPR22); + IOPGPR23Handle=GetDlgItem(hDlg,IDC_IOPGPR23); + IOPGPR24Handle=GetDlgItem(hDlg,IDC_IOPGPR24); + IOPGPR25Handle=GetDlgItem(hDlg,IDC_IOPGPR25); + IOPGPR26Handle=GetDlgItem(hDlg,IDC_IOPGPR26); + IOPGPR27Handle=GetDlgItem(hDlg,IDC_IOPGPR27); + IOPGPR28Handle=GetDlgItem(hDlg,IDC_IOPGPR28); + IOPGPR29Handle=GetDlgItem(hDlg,IDC_IOPGPR29); + IOPGPR30Handle=GetDlgItem(hDlg,IDC_IOPGPR30); + IOPGPR31Handle=GetDlgItem(hDlg,IDC_IOPGPR31); + IOPGPRPCHandle=GetDlgItem(hDlg,IDC_IOPGPR_PC); + IOPGPRHIHandle=GetDlgItem(hDlg,IDC_IOPGPR_HI); + IOPGPRLOHandle=GetDlgItem(hDlg,IDC_IOPGPR_LO); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + GPR0Handle=GetDlgItem(hDlg,IDC_GPR0); + GPR1Handle=GetDlgItem(hDlg,IDC_GPR1); + GPR2Handle=GetDlgItem(hDlg,IDC_GPR2); + GPR3Handle=GetDlgItem(hDlg,IDC_GPR3); + GPR4Handle=GetDlgItem(hDlg,IDC_GPR4); + GPR5Handle=GetDlgItem(hDlg,IDC_GPR5); + GPR6Handle=GetDlgItem(hDlg,IDC_GPR6); + GPR7Handle=GetDlgItem(hDlg,IDC_GPR7); + GPR8Handle=GetDlgItem(hDlg,IDC_GPR8); + GPR9Handle=GetDlgItem(hDlg,IDC_GPR9); + GPR10Handle=GetDlgItem(hDlg,IDC_GPR10); + GPR11Handle=GetDlgItem(hDlg,IDC_GPR11); + GPR12Handle=GetDlgItem(hDlg,IDC_GPR12); + GPR13Handle=GetDlgItem(hDlg,IDC_GPR13); + GPR14Handle=GetDlgItem(hDlg,IDC_GPR14); + GPR15Handle=GetDlgItem(hDlg,IDC_GPR15); + GPR16Handle=GetDlgItem(hDlg,IDC_GPR16); + GPR17Handle=GetDlgItem(hDlg,IDC_GPR17); + GPR18Handle=GetDlgItem(hDlg,IDC_GPR18); + GPR19Handle=GetDlgItem(hDlg,IDC_GPR19); + GPR20Handle=GetDlgItem(hDlg,IDC_GPR20); + GPR21Handle=GetDlgItem(hDlg,IDC_GPR21); + GPR22Handle=GetDlgItem(hDlg,IDC_GPR22); + GPR23Handle=GetDlgItem(hDlg,IDC_GPR23); + GPR24Handle=GetDlgItem(hDlg,IDC_GPR24); + GPR25Handle=GetDlgItem(hDlg,IDC_GPR25); + GPR26Handle=GetDlgItem(hDlg,IDC_GPR26); + GPR27Handle=GetDlgItem(hDlg,IDC_GPR27); + GPR28Handle=GetDlgItem(hDlg,IDC_GPR28); + GPR29Handle=GetDlgItem(hDlg,IDC_GPR29); + GPR30Handle=GetDlgItem(hDlg,IDC_GPR30); + GPR31Handle=GetDlgItem(hDlg,IDC_GPR31); + GPRPCHandle=GetDlgItem(hDlg,IDC_GPR_PC); + GPRHIHandle=GetDlgItem(hDlg,IDC_GPR_HI); + GPRLOHandle=GetDlgItem(hDlg,IDC_GPR_LO); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + COP00Handle=GetDlgItem(hDlg,IDC_CP00); + COP01Handle=GetDlgItem(hDlg,IDC_CP01); + COP02Handle=GetDlgItem(hDlg,IDC_CP02); + COP03Handle=GetDlgItem(hDlg,IDC_CP03); + COP04Handle=GetDlgItem(hDlg,IDC_CP04); + COP05Handle=GetDlgItem(hDlg,IDC_CP05); + COP06Handle=GetDlgItem(hDlg,IDC_CP06); + COP07Handle=GetDlgItem(hDlg,IDC_CP07); + COP08Handle=GetDlgItem(hDlg,IDC_CP08); + COP09Handle=GetDlgItem(hDlg,IDC_CP09); + COP010Handle=GetDlgItem(hDlg,IDC_CP010); + COP011Handle=GetDlgItem(hDlg,IDC_CP011); + COP012Handle=GetDlgItem(hDlg,IDC_CP012); + COP013Handle=GetDlgItem(hDlg,IDC_CP013); + COP014Handle=GetDlgItem(hDlg,IDC_CP014); + COP015Handle=GetDlgItem(hDlg,IDC_CP015); + COP016Handle=GetDlgItem(hDlg,IDC_CP016); + COP017Handle=GetDlgItem(hDlg,IDC_CP017); + COP018Handle=GetDlgItem(hDlg,IDC_CP018); + COP019Handle=GetDlgItem(hDlg,IDC_CP019); + COP020Handle=GetDlgItem(hDlg,IDC_CP020); + COP021Handle=GetDlgItem(hDlg,IDC_CP021); + COP022Handle=GetDlgItem(hDlg,IDC_CP022); + COP023Handle=GetDlgItem(hDlg,IDC_CP023); + COP024Handle=GetDlgItem(hDlg,IDC_CP024); + COP025Handle=GetDlgItem(hDlg,IDC_CP025); + COP026Handle=GetDlgItem(hDlg,IDC_CP026); + COP027Handle=GetDlgItem(hDlg,IDC_CP027); + COP028Handle=GetDlgItem(hDlg,IDC_CP028); + COP029Handle=GetDlgItem(hDlg,IDC_CP029); + COP030Handle=GetDlgItem(hDlg,IDC_CP030); + COP031Handle=GetDlgItem(hDlg,IDC_CP031); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + COP10Handle=GetDlgItem(hDlg,IDC_FP0); + COP11Handle=GetDlgItem(hDlg,IDC_FP1); + COP12Handle=GetDlgItem(hDlg,IDC_FP2); + COP13Handle=GetDlgItem(hDlg,IDC_FP3); + COP14Handle=GetDlgItem(hDlg,IDC_FP4); + COP15Handle=GetDlgItem(hDlg,IDC_FP5); + COP16Handle=GetDlgItem(hDlg,IDC_FP6); + COP17Handle=GetDlgItem(hDlg,IDC_FP7); + COP18Handle=GetDlgItem(hDlg,IDC_FP8); + COP19Handle=GetDlgItem(hDlg,IDC_FP9); + COP110Handle=GetDlgItem(hDlg,IDC_FP10); + COP111Handle=GetDlgItem(hDlg,IDC_FP11); + COP112Handle=GetDlgItem(hDlg,IDC_FP12); + COP113Handle=GetDlgItem(hDlg,IDC_FP13); + COP114Handle=GetDlgItem(hDlg,IDC_FP14); + COP115Handle=GetDlgItem(hDlg,IDC_FP15); + COP116Handle=GetDlgItem(hDlg,IDC_FP16); + COP117Handle=GetDlgItem(hDlg,IDC_FP17); + COP118Handle=GetDlgItem(hDlg,IDC_FP18); + COP119Handle=GetDlgItem(hDlg,IDC_FP19); + COP120Handle=GetDlgItem(hDlg,IDC_FP20); + COP121Handle=GetDlgItem(hDlg,IDC_FP21); + COP122Handle=GetDlgItem(hDlg,IDC_FP22); + COP123Handle=GetDlgItem(hDlg,IDC_FP23); + COP124Handle=GetDlgItem(hDlg,IDC_FP24); + COP125Handle=GetDlgItem(hDlg,IDC_FP25); + COP126Handle=GetDlgItem(hDlg,IDC_FP26); + COP127Handle=GetDlgItem(hDlg,IDC_FP27); + COP128Handle=GetDlgItem(hDlg,IDC_FP28); + COP129Handle=GetDlgItem(hDlg,IDC_FP29); + COP130Handle=GetDlgItem(hDlg,IDC_FP30); + COP131Handle=GetDlgItem(hDlg,IDC_FP31); + COP1C0Handle=GetDlgItem(hDlg,IDC_FCR0); + COP1C1Handle=GetDlgItem(hDlg,IDC_FCR31); + COP1ACCHandle=GetDlgItem(hDlg,IDC_FPU_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + +LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU0F00Handle=GetDlgItem(hDlg,IDC_VU0_VF00); + VU0F01Handle=GetDlgItem(hDlg,IDC_VU0_VF01); + VU0F02Handle=GetDlgItem(hDlg,IDC_VU0_VF02); + VU0F03Handle=GetDlgItem(hDlg,IDC_VU0_VF03); + VU0F04Handle=GetDlgItem(hDlg,IDC_VU0_VF04); + VU0F05Handle=GetDlgItem(hDlg,IDC_VU0_VF05); + VU0F06Handle=GetDlgItem(hDlg,IDC_VU0_VF06); + VU0F07Handle=GetDlgItem(hDlg,IDC_VU0_VF07); + VU0F08Handle=GetDlgItem(hDlg,IDC_VU0_VF08); + VU0F09Handle=GetDlgItem(hDlg,IDC_VU0_VF09); + VU0F10Handle=GetDlgItem(hDlg,IDC_VU0_VF10); + VU0F11Handle=GetDlgItem(hDlg,IDC_VU0_VF11); + VU0F12Handle=GetDlgItem(hDlg,IDC_VU0_VF12); + VU0F13Handle=GetDlgItem(hDlg,IDC_VU0_VF13); + VU0F14Handle=GetDlgItem(hDlg,IDC_VU0_VF14); + VU0F15Handle=GetDlgItem(hDlg,IDC_VU0_VF15); + VU0F16Handle=GetDlgItem(hDlg,IDC_VU0_VF16); + VU0F17Handle=GetDlgItem(hDlg,IDC_VU0_VF17); + VU0F18Handle=GetDlgItem(hDlg,IDC_VU0_VF18); + VU0F19Handle=GetDlgItem(hDlg,IDC_VU0_VF19); + VU0F20Handle=GetDlgItem(hDlg,IDC_VU0_VF20); + VU0F21Handle=GetDlgItem(hDlg,IDC_VU0_VF21); + VU0F22Handle=GetDlgItem(hDlg,IDC_VU0_VF22); + VU0F23Handle=GetDlgItem(hDlg,IDC_VU0_VF23); + VU0F24Handle=GetDlgItem(hDlg,IDC_VU0_VF24); + VU0F25Handle=GetDlgItem(hDlg,IDC_VU0_VF25); + VU0F26Handle=GetDlgItem(hDlg,IDC_VU0_VF26); + VU0F27Handle=GetDlgItem(hDlg,IDC_VU0_VF27); + VU0F28Handle=GetDlgItem(hDlg,IDC_VU0_VF28); + VU0F29Handle=GetDlgItem(hDlg,IDC_VU0_VF29); + VU0F30Handle=GetDlgItem(hDlg,IDC_VU0_VF30); + VU0F31Handle=GetDlgItem(hDlg,IDC_VU0_VF31); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU0C00Handle=GetDlgItem(hDlg,IDC_VU0_VI00); + VU0C01Handle=GetDlgItem(hDlg,IDC_VU0_VI01); + VU0C02Handle=GetDlgItem(hDlg,IDC_VU0_VI02); + VU0C03Handle=GetDlgItem(hDlg,IDC_VU0_VI03); + VU0C04Handle=GetDlgItem(hDlg,IDC_VU0_VI04); + VU0C05Handle=GetDlgItem(hDlg,IDC_VU0_VI05); + VU0C06Handle=GetDlgItem(hDlg,IDC_VU0_VI06); + VU0C07Handle=GetDlgItem(hDlg,IDC_VU0_VI07); + VU0C08Handle=GetDlgItem(hDlg,IDC_VU0_VI08); + VU0C09Handle=GetDlgItem(hDlg,IDC_VU0_VI09); + VU0C10Handle=GetDlgItem(hDlg,IDC_VU0_VI10); + VU0C11Handle=GetDlgItem(hDlg,IDC_VU0_VI11); + VU0C12Handle=GetDlgItem(hDlg,IDC_VU0_VI12); + VU0C13Handle=GetDlgItem(hDlg,IDC_VU0_VI13); + VU0C14Handle=GetDlgItem(hDlg,IDC_VU0_VI14); + VU0C15Handle=GetDlgItem(hDlg,IDC_VU0_VI15); + VU0C16Handle=GetDlgItem(hDlg,IDC_VU0_VI16); + VU0C17Handle=GetDlgItem(hDlg,IDC_VU0_VI17); + VU0C18Handle=GetDlgItem(hDlg,IDC_VU0_VI18); + VU0C19Handle=GetDlgItem(hDlg,IDC_VU0_VI19); + VU0C20Handle=GetDlgItem(hDlg,IDC_VU0_VI20); + VU0C21Handle=GetDlgItem(hDlg,IDC_VU0_VI21); + VU0C22Handle=GetDlgItem(hDlg,IDC_VU0_VI22); + VU0C23Handle=GetDlgItem(hDlg,IDC_VU0_VI23); + VU0C24Handle=GetDlgItem(hDlg,IDC_VU0_VI24); + VU0C25Handle=GetDlgItem(hDlg,IDC_VU0_VI25); + VU0C26Handle=GetDlgItem(hDlg,IDC_VU0_VI26); + VU0C27Handle=GetDlgItem(hDlg,IDC_VU0_VI27); + VU0C28Handle=GetDlgItem(hDlg,IDC_VU0_VI28); + VU0C29Handle=GetDlgItem(hDlg,IDC_VU0_VI29); + VU0C30Handle=GetDlgItem(hDlg,IDC_VU0_VI30); + VU0C31Handle=GetDlgItem(hDlg,IDC_VU0_VI31); + VU0ACCHandle=GetDlgItem(hDlg,IDC_VU0_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + + +LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU1F00Handle=GetDlgItem(hDlg,IDC_VU1_VF00); + VU1F01Handle=GetDlgItem(hDlg,IDC_VU1_VF01); + VU1F02Handle=GetDlgItem(hDlg,IDC_VU1_VF02); + VU1F03Handle=GetDlgItem(hDlg,IDC_VU1_VF03); + VU1F04Handle=GetDlgItem(hDlg,IDC_VU1_VF04); + VU1F05Handle=GetDlgItem(hDlg,IDC_VU1_VF05); + VU1F06Handle=GetDlgItem(hDlg,IDC_VU1_VF06); + VU1F07Handle=GetDlgItem(hDlg,IDC_VU1_VF07); + VU1F08Handle=GetDlgItem(hDlg,IDC_VU1_VF08); + VU1F09Handle=GetDlgItem(hDlg,IDC_VU1_VF09); + VU1F10Handle=GetDlgItem(hDlg,IDC_VU1_VF10); + VU1F11Handle=GetDlgItem(hDlg,IDC_VU1_VF11); + VU1F12Handle=GetDlgItem(hDlg,IDC_VU1_VF12); + VU1F13Handle=GetDlgItem(hDlg,IDC_VU1_VF13); + VU1F14Handle=GetDlgItem(hDlg,IDC_VU1_VF14); + VU1F15Handle=GetDlgItem(hDlg,IDC_VU1_VF15); + VU1F16Handle=GetDlgItem(hDlg,IDC_VU1_VF16); + VU1F17Handle=GetDlgItem(hDlg,IDC_VU1_VF17); + VU1F18Handle=GetDlgItem(hDlg,IDC_VU1_VF18); + VU1F19Handle=GetDlgItem(hDlg,IDC_VU1_VF19); + VU1F20Handle=GetDlgItem(hDlg,IDC_VU1_VF20); + VU1F21Handle=GetDlgItem(hDlg,IDC_VU1_VF21); + VU1F22Handle=GetDlgItem(hDlg,IDC_VU1_VF22); + VU1F23Handle=GetDlgItem(hDlg,IDC_VU1_VF23); + VU1F24Handle=GetDlgItem(hDlg,IDC_VU1_VF24); + VU1F25Handle=GetDlgItem(hDlg,IDC_VU1_VF25); + VU1F26Handle=GetDlgItem(hDlg,IDC_VU1_VF26); + VU1F27Handle=GetDlgItem(hDlg,IDC_VU1_VF27); + VU1F28Handle=GetDlgItem(hDlg,IDC_VU1_VF28); + VU1F29Handle=GetDlgItem(hDlg,IDC_VU1_VF29); + VU1F30Handle=GetDlgItem(hDlg,IDC_VU1_VF30); + VU1F31Handle=GetDlgItem(hDlg,IDC_VU1_VF31); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU1C00Handle=GetDlgItem(hDlg,IDC_VU1_VI00); + VU1C01Handle=GetDlgItem(hDlg,IDC_VU1_VI01); + VU1C02Handle=GetDlgItem(hDlg,IDC_VU1_VI02); + VU1C03Handle=GetDlgItem(hDlg,IDC_VU1_VI03); + VU1C04Handle=GetDlgItem(hDlg,IDC_VU1_VI04); + VU1C05Handle=GetDlgItem(hDlg,IDC_VU1_VI05); + VU1C06Handle=GetDlgItem(hDlg,IDC_VU1_VI06); + VU1C07Handle=GetDlgItem(hDlg,IDC_VU1_VI07); + VU1C08Handle=GetDlgItem(hDlg,IDC_VU1_VI08); + VU1C09Handle=GetDlgItem(hDlg,IDC_VU1_VI09); + VU1C10Handle=GetDlgItem(hDlg,IDC_VU1_VI10); + VU1C11Handle=GetDlgItem(hDlg,IDC_VU1_VI11); + VU1C12Handle=GetDlgItem(hDlg,IDC_VU1_VI12); + VU1C13Handle=GetDlgItem(hDlg,IDC_VU1_VI13); + VU1C14Handle=GetDlgItem(hDlg,IDC_VU1_VI14); + VU1C15Handle=GetDlgItem(hDlg,IDC_VU1_VI15); + VU1C16Handle=GetDlgItem(hDlg,IDC_VU1_VI16); + VU1C17Handle=GetDlgItem(hDlg,IDC_VU1_VI17); + VU1C18Handle=GetDlgItem(hDlg,IDC_VU1_VI18); + VU1C19Handle=GetDlgItem(hDlg,IDC_VU1_VI19); + VU1C20Handle=GetDlgItem(hDlg,IDC_VU1_VI20); + VU1C21Handle=GetDlgItem(hDlg,IDC_VU1_VI21); + VU1C22Handle=GetDlgItem(hDlg,IDC_VU1_VI22); + VU1C23Handle=GetDlgItem(hDlg,IDC_VU1_VI23); + VU1C24Handle=GetDlgItem(hDlg,IDC_VU1_VI24); + VU1C25Handle=GetDlgItem(hDlg,IDC_VU1_VI25); + VU1C26Handle=GetDlgItem(hDlg,IDC_VU1_VI26); + VU1C27Handle=GetDlgItem(hDlg,IDC_VU1_VI27); + VU1C28Handle=GetDlgItem(hDlg,IDC_VU1_VI28); + VU1C29Handle=GetDlgItem(hDlg,IDC_VU1_VI29); + VU1C30Handle=GetDlgItem(hDlg,IDC_VU1_VI30); + VU1C31Handle=GetDlgItem(hDlg,IDC_VU1_VI31); + VU1ACCHandle=GetDlgItem(hDlg,IDC_VU1_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + +void UpdateRegs(void) +{ + + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[0]); + SendMessage(IOPGPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[1]); + SendMessage(IOPGPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[2]); + SendMessage(IOPGPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[3]); + SendMessage(IOPGPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[4]); + SendMessage(IOPGPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[5]); + SendMessage(IOPGPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[6]); + SendMessage(IOPGPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[7]); + SendMessage(IOPGPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[8]); + SendMessage(IOPGPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[9]); + SendMessage(IOPGPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[10]); + SendMessage(IOPGPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[11]); + SendMessage(IOPGPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[12]); + SendMessage(IOPGPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[13]); + SendMessage(IOPGPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[14]); + SendMessage(IOPGPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[15]); + SendMessage(IOPGPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[16]); + SendMessage(IOPGPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[17]); + SendMessage(IOPGPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[18]); + SendMessage(IOPGPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[19]); + SendMessage(IOPGPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[20]); + SendMessage(IOPGPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[21]); + SendMessage(IOPGPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[22]); + SendMessage(IOPGPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[23]); + SendMessage(IOPGPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[24]); + SendMessage(IOPGPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[25]); + SendMessage(IOPGPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[26]); + SendMessage(IOPGPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[27]); + SendMessage(IOPGPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[28]); + SendMessage(IOPGPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[29]); + SendMessage(IOPGPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[30]); + SendMessage(IOPGPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[31]); + SendMessage(IOPGPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",psxRegs.pc ); + SendMessage(IOPGPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[32]); + SendMessage(IOPGPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[33]); + SendMessage(IOPGPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[0].UL[3],cpuRegs.GPR.r[0].UL[2],cpuRegs.GPR.r[0].UL[1],cpuRegs.GPR.r[0].UL[0] ); + SendMessage(GPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[1].UL[3], cpuRegs.GPR.r[1].UL[2],cpuRegs.GPR.r[1].UL[1],cpuRegs.GPR.r[1].UL[0] ); + SendMessage(GPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[2].UL[3],cpuRegs.GPR.r[2].UL[2], cpuRegs.GPR.r[2].UL[1],cpuRegs.GPR.r[2].UL[0]); + SendMessage(GPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[3].UL[3],cpuRegs.GPR.r[3].UL[2], cpuRegs.GPR.r[3].UL[1],cpuRegs.GPR.r[3].UL[0] ); + SendMessage(GPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[4].UL[3],cpuRegs.GPR.r[4].UL[2], cpuRegs.GPR.r[4].UL[1],cpuRegs.GPR.r[4].UL[0] ); + SendMessage(GPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[5].UL[3],cpuRegs.GPR.r[5].UL[2],cpuRegs.GPR.r[5].UL[1], cpuRegs.GPR.r[5].UL[0] ); + SendMessage(GPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[6].UL[3],cpuRegs.GPR.r[6].UL[2], cpuRegs.GPR.r[6].UL[1], cpuRegs.GPR.r[6].UL[0]); + SendMessage(GPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[7].UL[3], cpuRegs.GPR.r[7].UL[2],cpuRegs.GPR.r[7].UL[1],cpuRegs.GPR.r[7].UL[0] ); + SendMessage(GPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[8].UL[3],cpuRegs.GPR.r[8].UL[2],cpuRegs.GPR.r[8].UL[1],cpuRegs.GPR.r[8].UL[0] ); + SendMessage(GPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[9].UL[3],cpuRegs.GPR.r[9].UL[2],cpuRegs.GPR.r[9].UL[1], cpuRegs.GPR.r[9].UL[0] ); + SendMessage(GPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[10].UL[3],cpuRegs.GPR.r[10].UL[2],cpuRegs.GPR.r[10].UL[1],cpuRegs.GPR.r[10].UL[0] ); + SendMessage(GPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[11].UL[3],cpuRegs.GPR.r[11].UL[2],cpuRegs.GPR.r[11].UL[1],cpuRegs.GPR.r[11].UL[0] ); + SendMessage(GPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[12].UL[3],cpuRegs.GPR.r[12].UL[2],cpuRegs.GPR.r[12].UL[1],cpuRegs.GPR.r[12].UL[0] ); + SendMessage(GPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[13].UL[3],cpuRegs.GPR.r[13].UL[2],cpuRegs.GPR.r[13].UL[1],cpuRegs.GPR.r[13].UL[0] ); + SendMessage(GPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[14].UL[3],cpuRegs.GPR.r[14].UL[2],cpuRegs.GPR.r[14].UL[1],cpuRegs.GPR.r[14].UL[0] ); + SendMessage(GPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[15].UL[3],cpuRegs.GPR.r[15].UL[2],cpuRegs.GPR.r[15].UL[1],cpuRegs.GPR.r[15].UL[0] ); + SendMessage(GPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[16].UL[3],cpuRegs.GPR.r[16].UL[2],cpuRegs.GPR.r[16].UL[1],cpuRegs.GPR.r[16].UL[0] ); + SendMessage(GPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[17].UL[3],cpuRegs.GPR.r[17].UL[2],cpuRegs.GPR.r[17].UL[1],cpuRegs.GPR.r[17].UL[0] ); + SendMessage(GPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[18].UL[3],cpuRegs.GPR.r[18].UL[2],cpuRegs.GPR.r[18].UL[1],cpuRegs.GPR.r[18].UL[0] ); + SendMessage(GPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[19].UL[3],cpuRegs.GPR.r[19].UL[2],cpuRegs.GPR.r[19].UL[1],cpuRegs.GPR.r[19].UL[0] ); + SendMessage(GPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[20].UL[3],cpuRegs.GPR.r[20].UL[2],cpuRegs.GPR.r[20].UL[1],cpuRegs.GPR.r[20].UL[0] ); + SendMessage(GPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[21].UL[3],cpuRegs.GPR.r[21].UL[2],cpuRegs.GPR.r[21].UL[1],cpuRegs.GPR.r[21].UL[0] ); + SendMessage(GPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[22].UL[3],cpuRegs.GPR.r[22].UL[2],cpuRegs.GPR.r[22].UL[1],cpuRegs.GPR.r[22].UL[0] ); + SendMessage(GPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[23].UL[3],cpuRegs.GPR.r[23].UL[2],cpuRegs.GPR.r[23].UL[1],cpuRegs.GPR.r[23].UL[0] ); + SendMessage(GPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[24].UL[3],cpuRegs.GPR.r[24].UL[2],cpuRegs.GPR.r[24].UL[1],cpuRegs.GPR.r[24].UL[0] ); + SendMessage(GPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[25].UL[3],cpuRegs.GPR.r[25].UL[2],cpuRegs.GPR.r[25].UL[1],cpuRegs.GPR.r[25].UL[0] ); + SendMessage(GPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[26].UL[3],cpuRegs.GPR.r[26].UL[2],cpuRegs.GPR.r[26].UL[1],cpuRegs.GPR.r[26].UL[0] ); + SendMessage(GPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[27].UL[3],cpuRegs.GPR.r[27].UL[2],cpuRegs.GPR.r[27].UL[1],cpuRegs.GPR.r[27].UL[0] ); + SendMessage(GPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[28].UL[3],cpuRegs.GPR.r[28].UL[2],cpuRegs.GPR.r[28].UL[1],cpuRegs.GPR.r[28].UL[0] ); + SendMessage(GPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[29].UL[3],cpuRegs.GPR.r[29].UL[2],cpuRegs.GPR.r[29].UL[1],cpuRegs.GPR.r[29].UL[0] ); + SendMessage(GPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[30].UL[3],cpuRegs.GPR.r[30].UL[2],cpuRegs.GPR.r[30].UL[1],cpuRegs.GPR.r[30].UL[0] ); + SendMessage(GPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[31].UL[3],cpuRegs.GPR.r[31].UL[2],cpuRegs.GPR.r[31].UL[1],cpuRegs.GPR.r[31].UL[0] ); + SendMessage(GPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.pc ); + SendMessage(GPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2] ,cpuRegs.HI.UL[1] ,cpuRegs.HI.UL[0] ); + SendMessage(GPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0\0",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0] ); + SendMessage(GPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[0] ); + SendMessage(COP00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[1]); + SendMessage(COP01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[2]); + SendMessage(COP02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[3]); + SendMessage(COP03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[4]); + SendMessage(COP04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[5]); + SendMessage(COP05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[6]); + SendMessage(COP06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[7]); + SendMessage(COP07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[8]); + SendMessage(COP08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[9]); + SendMessage(COP09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[10]); + SendMessage(COP010Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[11]); + SendMessage(COP011Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[12]); + SendMessage(COP012Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[13]); + SendMessage(COP013Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[14]); + SendMessage(COP014Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[15]); + SendMessage(COP015Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[16]); + SendMessage(COP016Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[17]); + SendMessage(COP017Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[18]); + SendMessage(COP018Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[19]); + SendMessage(COP019Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[20]); + SendMessage(COP020Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[21]); + SendMessage(COP021Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[22]); + SendMessage(COP022Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[23]); + SendMessage(COP023Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[24]); + SendMessage(COP024Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[25]); + SendMessage(COP025Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[26]); + SendMessage(COP026Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[27]); + SendMessage(COP027Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[28]); + SendMessage(COP028Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[29]); + SendMessage(COP029Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[30]); + SendMessage(COP030Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[31]); + SendMessage(COP031Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f",fpuRegs.fpr[0].f ); + SendMessage(COP10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[1].f); + SendMessage(COP11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[2].f); + SendMessage(COP12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[3].f); + SendMessage(COP13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[4].f); + SendMessage(COP14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[5].f); + SendMessage(COP15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[6].f); + SendMessage(COP16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[7].f); + SendMessage(COP17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[8].f); + SendMessage(COP18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[9].f); + SendMessage(COP19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[10].f); + SendMessage(COP110Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[11].f); + SendMessage(COP111Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[12].f); + SendMessage(COP112Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[13].f); + SendMessage(COP113Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[14].f); + SendMessage(COP114Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[15].f); + SendMessage(COP115Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[16].f); + SendMessage(COP116Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[17].f); + SendMessage(COP117Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[18].f); + SendMessage(COP118Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[19].f); + SendMessage(COP119Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[20].f); + SendMessage(COP120Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[21].f); + SendMessage(COP121Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[22].f); + SendMessage(COP122Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[23].f); + SendMessage(COP123Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[24].f); + SendMessage(COP124Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[25].f); + SendMessage(COP125Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[26].f); + SendMessage(COP126Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[27].f); + SendMessage(COP127Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[28].f); + SendMessage(COP128Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[29].f); + SendMessage(COP129Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[30].f); + SendMessage(COP130Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[31].f); + SendMessage(COP131Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",fpuRegs.fprc[0]); + SendMessage(COP1C0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",fpuRegs.fprc[31]); + SendMessage(COP1C1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.ACC.f); + SendMessage(COP1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[0].f.w,VU0.VF[0].f.z,VU0.VF[0].f.y,VU0.VF[0].f.x ); + SendMessage(VU0F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[1].f.w,VU0.VF[1].f.z,VU0.VF[1].f.y,VU0.VF[1].f.x ); + SendMessage(VU0F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[2].f.w,VU0.VF[2].f.z,VU0.VF[2].f.y,VU0.VF[2].f.x ); + SendMessage(VU0F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[3].f.w,VU0.VF[3].f.z,VU0.VF[3].f.y,VU0.VF[3].f.x ); + SendMessage(VU0F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[4].f.w,VU0.VF[4].f.z,VU0.VF[4].f.y,VU0.VF[4].f.x ); + SendMessage(VU0F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[5].f.w,VU0.VF[5].f.z,VU0.VF[5].f.y,VU0.VF[5].f.x); + SendMessage(VU0F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[6].f.w,VU0.VF[6].f.z,VU0.VF[6].f.y,VU0.VF[6].f.x ); + SendMessage(VU0F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[7].f.w,VU0.VF[7].f.z,VU0.VF[7].f.y,VU0.VF[7].f.x ); + SendMessage(VU0F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[8].f.w,VU0.VF[8].f.z,VU0.VF[8].f.y,VU0.VF[8].f.x ); + SendMessage(VU0F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[9].f.w,VU0.VF[9].f.z,VU0.VF[9].f.y,VU0.VF[9].f.x ); + SendMessage(VU0F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[10].f.w,VU0.VF[10].f.z,VU0.VF[10].f.y,VU0.VF[10].f.x ); + SendMessage(VU0F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[11].f.w,VU0.VF[11].f.z,VU0.VF[11].f.y,VU0.VF[11].f.x ); + SendMessage(VU0F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[12].f.w,VU0.VF[12].f.z,VU0.VF[12].f.y,VU0.VF[12].f.x ); + SendMessage(VU0F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[13].f.w,VU0.VF[13].f.z,VU0.VF[13].f.y,VU0.VF[13].f.x ); + SendMessage(VU0F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[14].f.w,VU0.VF[14].f.z,VU0.VF[14].f.y,VU0.VF[14].f.x ); + SendMessage(VU0F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[15].f.w,VU0.VF[15].f.z,VU0.VF[15].f.y,VU0.VF[15].f.x ); + SendMessage(VU0F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[16].f.w,VU0.VF[16].f.z,VU0.VF[16].f.y,VU0.VF[16].f.x ); + SendMessage(VU0F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[17].f.w,VU0.VF[17].f.z,VU0.VF[17].f.y,VU0.VF[17].f.x ); + SendMessage(VU0F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[18].f.w,VU0.VF[18].f.z,VU0.VF[18].f.y,VU0.VF[18].f.x ); + SendMessage(VU0F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[19].f.w,VU0.VF[19].f.z,VU0.VF[19].f.y,VU0.VF[19].f.x ); + SendMessage(VU0F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[20].f.w,VU0.VF[20].f.z,VU0.VF[20].f.y,VU0.VF[20].f.x ); + SendMessage(VU0F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[21].f.w,VU0.VF[21].f.z,VU0.VF[21].f.y,VU0.VF[21].f.x ); + SendMessage(VU0F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[22].f.w,VU0.VF[22].f.z,VU0.VF[22].f.y,VU0.VF[22].f.x ); + SendMessage(VU0F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[23].f.w,VU0.VF[23].f.z,VU0.VF[23].f.y,VU0.VF[23].f.x ); + SendMessage(VU0F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[24].f.w,VU0.VF[24].f.z,VU0.VF[24].f.y,VU0.VF[24].f.x ); + SendMessage(VU0F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[25].f.w,VU0.VF[25].f.z,VU0.VF[25].f.y,VU0.VF[25].f.x ); + SendMessage(VU0F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[26].f.w,VU0.VF[26].f.z,VU0.VF[26].f.y,VU0.VF[26].f.x ); + SendMessage(VU0F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[27].f.w,VU0.VF[27].f.z,VU0.VF[27].f.y,VU0.VF[27].f.x ); + SendMessage(VU0F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[28].f.w,VU0.VF[28].f.z,VU0.VF[28].f.y,VU0.VF[28].f.x ); + SendMessage(VU0F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[29].f.w,VU0.VF[29].f.z,VU0.VF[29].f.y,VU0.VF[29].f.x ); + SendMessage(VU0F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[30].f.w,VU0.VF[30].f.z,VU0.VF[30].f.y,VU0.VF[30].f.x ); + SendMessage(VU0F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[31].f.w,VU0.VF[31].f.z,VU0.VF[31].f.y,VU0.VF[31].f.x ); + SendMessage(VU0F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + wsprintf(text1,"%x",VU0.VI[0] ); + SendMessage(VU0C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[1]); + SendMessage(VU0C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[2]); + SendMessage(VU0C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[3]); + SendMessage(VU0C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[4]); + SendMessage(VU0C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[5]); + SendMessage(VU0C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[6]); + SendMessage(VU0C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[7]); + SendMessage(VU0C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[8]); + SendMessage(VU0C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[9]); + SendMessage(VU0C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[10]); + SendMessage(VU0C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[11]); + SendMessage(VU0C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[12]); + SendMessage(VU0C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[13]); + SendMessage(VU0C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[14]); + SendMessage(VU0C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[15]); + SendMessage(VU0C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[16]); + SendMessage(VU0C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[17]); + SendMessage(VU0C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[18]); + SendMessage(VU0C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[19]); + SendMessage(VU0C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[20]); + SendMessage(VU0C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[21]); + SendMessage(VU0C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[22]); + SendMessage(VU0C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[23]); + SendMessage(VU0C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[24]); + SendMessage(VU0C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[25]); + SendMessage(VU0C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[26]); + SendMessage(VU0C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[27]); + SendMessage(VU0C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[28]); + SendMessage(VU0C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[29]); + SendMessage(VU0C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[30]); + SendMessage(VU0C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[31]); + SendMessage(VU0C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f_%f_%f_%f\0",VU0.ACC.f.w,VU0.ACC.f.z,VU0.ACC.f.y,VU0.ACC.f.x ); + SendMessage(VU0ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[0].f.w,VU1.VF[0].f.z,VU1.VF[0].f.y,VU1.VF[0].f.x ); + SendMessage(VU1F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[1].f.w,VU1.VF[1].f.z,VU1.VF[1].f.y,VU1.VF[1].f.x ); + SendMessage(VU1F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[2].f.w,VU1.VF[2].f.z,VU1.VF[2].f.y,VU1.VF[2].f.x ); + SendMessage(VU1F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[3].f.w,VU1.VF[3].f.z,VU1.VF[3].f.y,VU1.VF[3].f.x ); + SendMessage(VU1F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[4].f.w,VU1.VF[4].f.z,VU1.VF[4].f.y,VU1.VF[4].f.x ); + SendMessage(VU1F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[5].f.w,VU1.VF[5].f.z,VU1.VF[5].f.y,VU1.VF[5].f.x); + SendMessage(VU1F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[6].f.w,VU1.VF[6].f.z,VU1.VF[6].f.y,VU1.VF[6].f.x ); + SendMessage(VU1F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[7].f.w,VU1.VF[7].f.z,VU1.VF[7].f.y,VU1.VF[7].f.x ); + SendMessage(VU1F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[8].f.w,VU1.VF[8].f.z,VU1.VF[8].f.y,VU1.VF[8].f.x ); + SendMessage(VU1F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[9].f.w,VU1.VF[9].f.z,VU1.VF[9].f.y,VU1.VF[9].f.x ); + SendMessage(VU1F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[10].f.w,VU1.VF[10].f.z,VU1.VF[10].f.y,VU1.VF[10].f.x ); + SendMessage(VU1F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[11].f.w,VU1.VF[11].f.z,VU1.VF[11].f.y,VU1.VF[11].f.x ); + SendMessage(VU1F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[12].f.w,VU1.VF[12].f.z,VU1.VF[12].f.y,VU1.VF[12].f.x ); + SendMessage(VU1F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[13].f.w,VU1.VF[13].f.z,VU1.VF[13].f.y,VU1.VF[13].f.x ); + SendMessage(VU1F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[14].f.w,VU1.VF[14].f.z,VU1.VF[14].f.y,VU1.VF[14].f.x ); + SendMessage(VU1F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[15].f.w,VU1.VF[15].f.z,VU1.VF[15].f.y,VU1.VF[15].f.x ); + SendMessage(VU1F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[16].f.w,VU1.VF[16].f.z,VU1.VF[16].f.y,VU1.VF[16].f.x ); + SendMessage(VU1F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[17].f.w,VU1.VF[17].f.z,VU1.VF[17].f.y,VU1.VF[17].f.x ); + SendMessage(VU1F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[18].f.w,VU1.VF[18].f.z,VU1.VF[18].f.y,VU1.VF[18].f.x ); + SendMessage(VU1F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[19].f.w,VU1.VF[19].f.z,VU1.VF[19].f.y,VU1.VF[19].f.x ); + SendMessage(VU1F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[20].f.w,VU1.VF[20].f.z,VU1.VF[20].f.y,VU1.VF[20].f.x ); + SendMessage(VU1F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[21].f.w,VU1.VF[21].f.z,VU1.VF[21].f.y,VU1.VF[21].f.x ); + SendMessage(VU1F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[22].f.w,VU1.VF[22].f.z,VU1.VF[22].f.y,VU1.VF[22].f.x ); + SendMessage(VU1F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[23].f.w,VU1.VF[23].f.z,VU1.VF[23].f.y,VU1.VF[23].f.x ); + SendMessage(VU1F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[24].f.w,VU1.VF[24].f.z,VU1.VF[24].f.y,VU1.VF[24].f.x ); + SendMessage(VU1F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[25].f.w,VU1.VF[25].f.z,VU1.VF[25].f.y,VU1.VF[25].f.x ); + SendMessage(VU1F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[26].f.w,VU1.VF[26].f.z,VU1.VF[26].f.y,VU1.VF[26].f.x ); + SendMessage(VU1F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[27].f.w,VU1.VF[27].f.z,VU1.VF[27].f.y,VU1.VF[27].f.x ); + SendMessage(VU1F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[28].f.w,VU1.VF[28].f.z,VU1.VF[28].f.y,VU1.VF[28].f.x ); + SendMessage(VU1F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[29].f.w,VU1.VF[29].f.z,VU1.VF[29].f.y,VU1.VF[29].f.x ); + SendMessage(VU1F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[30].f.w,VU1.VF[30].f.z,VU1.VF[30].f.y,VU1.VF[30].f.x ); + SendMessage(VU1F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[31].f.w,VU1.VF[31].f.z,VU1.VF[31].f.y,VU1.VF[31].f.x ); + SendMessage(VU1F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + wsprintf(text1,"%x",VU1.VI[0] ); + SendMessage(VU1C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[1]); + SendMessage(VU1C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[2]); + SendMessage(VU1C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[3]); + SendMessage(VU1C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[4]); + SendMessage(VU1C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[5]); + SendMessage(VU1C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[6]); + SendMessage(VU1C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[7]); + SendMessage(VU1C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[8]); + SendMessage(VU1C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[9]); + SendMessage(VU1C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[10]); + SendMessage(VU1C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[11]); + SendMessage(VU1C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[12]); + SendMessage(VU1C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[13]); + SendMessage(VU1C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[14]); + SendMessage(VU1C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[15]); + SendMessage(VU1C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[16]); + SendMessage(VU1C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[17]); + SendMessage(VU1C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[18]); + SendMessage(VU1C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[19]); + SendMessage(VU1C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[20]); + SendMessage(VU1C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[21]); + SendMessage(VU1C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[22]); + SendMessage(VU1C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[23]); + SendMessage(VU1C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[24]); + SendMessage(VU1C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[25]); + SendMessage(VU1C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[26]); + SendMessage(VU1C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[27]); + SendMessage(VU1C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[28]); + SendMessage(VU1C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[29]); + SendMessage(VU1C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[30]); + SendMessage(VU1C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[31]); + SendMessage(VU1C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f_%f_%f_%f\0",VU1.ACC.f.w,VU1.ACC.f.z,VU1.ACC.f.y,VU1.ACC.f.x ); + SendMessage(VU1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + +} + + +void EEDumpRegs(FILE * fp) +{ + char text2[256]; + int i; + for(i = 0; i < 32; i++) + { + sprintf(text1,"%x_%x_%x_%x",cpuRegs.GPR.r[i].UL[3],cpuRegs.GPR.r[i].UL[2],cpuRegs.GPR.r[i].UL[1],cpuRegs.GPR.r[i].UL[0]); + sprintf(text2,"GPR Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } + sprintf(text1,"0x%x",cpuRegs.pc); + fprintf(fp,"PC Register : "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x_%x_%x_%x",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2],cpuRegs.HI.UL[1],cpuRegs.HI.UL[0]); + fprintf(fp,"GPR Register HI: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x_%x_%x_%x",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0]); + fprintf(fp,"GPR Register LO: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + + + for(i = 0; i < 32; i++) + { + sprintf(text1,"0x%x",cpuRegs.CP0.r[i]); + sprintf(text2,"COP0 Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } +} + +void IOPDumpRegs(FILE * fp) +{ + char text2[256]; + int i; + for(i = 0; i < 32; i++) + { + sprintf(text1,"%x",psxRegs.GPR.r[i]); + sprintf(text2,"GPR Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } + sprintf(text1,"0x%x",psxRegs.pc); + fprintf(fp,"PC Register : "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x",psxRegs.GPR.r[32]); + fprintf(fp,"GPR Register HI: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x",psxRegs.GPR.r[33]); + fprintf(fp,"GPR Register LO: "); + fprintf(fp,text1); + fprintf(fp,"\n"); +} diff --git a/pcsx2/windows/McdsDlg.c b/pcsx2/windows/McdsDlg.c new file mode 100644 index 0000000000..434c63711e --- /dev/null +++ b/pcsx2/windows/McdsDlg.c @@ -0,0 +1,126 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "plugins.h" +#include "resource.h" +#include "Win32.h" + +#include "Paths.h" + + +HWND mcdDlg; + + +void Open_Mcd_Proc(HWND hW, int mcd) { + OPENFILENAME ofn; + char szFileName[256]; + char szFileTitle[256]; + char szFilter[1024]; + char *str; + + memset(szFileName, 0, sizeof(szFileName)); + memset(szFileTitle, 0, sizeof(szFileTitle)); + memset(szFilter, 0, sizeof(szFilter)); + + + strcpy(szFilter, _("Ps2 Memory Card (*.ps2)")); + str = szFilter + strlen(szFilter) + 1; + strcpy(str, "*.ps2"); + + str+= strlen(str) + 1; + strcpy(str, _("All Files")); + str+= strlen(str) + 1; + strcpy(str, "*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hW; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = MEMCARDS_DIR; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "MC2"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { + Edit_SetText(GetDlgItem(hW,mcd == 1 ? IDC_MCD1 : IDC_MCD2), szFileName); + } +} + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + mcdDlg = hW; + + SetWindowText(hW, _("Memcard Manager")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); + + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); + + if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, "memcards\\Mcd001.ps2"); + if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, "memcards\\Mcd002.ps2"); + Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); + Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_MCDSEL1: + Open_Mcd_Proc(hW, 1); + return TRUE; + case IDC_MCDSEL2: + Open_Mcd_Proc(hW, 2); + return TRUE; + case IDCANCEL: + EndDialog(hW,FALSE); + + return TRUE; + case IDOK: + Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); + Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); + + SaveConfig(); + + EndDialog(hW,TRUE); + + return TRUE; + } + case WM_DESTROY: + return TRUE; + } + return FALSE; +} + diff --git a/pcsx2/windows/McdsDlg.cpp b/pcsx2/windows/McdsDlg.cpp new file mode 100644 index 0000000000..d91dff86e3 --- /dev/null +++ b/pcsx2/windows/McdsDlg.cpp @@ -0,0 +1,1750 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include "libintlmsc.h" +#define _(String) dgettext (PACKAGE, String) + +extern "C"{ +#include "PS2Edefs.h" +#include "resource.h" +#include "Misc.h" +#include "System.h" +#include "McdsDlg.h" +} + +#include +using namespace std; + + + + +u16 SJISTable[0xFFFF]; + + +void IniSJISTable() +{ + memset(SJISTable, 0, 0xFFFF); + //Blow me sony for using this retarded sjis to store the savegame name + SJISTable[0x20] = 0x0020; + SJISTable[0x21] = 0x0021; + SJISTable[0x22] = 0x0022; + SJISTable[0x23] = 0x0023; + SJISTable[0x24] = 0x0024; + SJISTable[0x25] = 0x0025; + SJISTable[0x26] = 0x0026; + SJISTable[0x27] = 0x0027; + SJISTable[0x28] = 0x0028; + SJISTable[0x29] = 0x0029; + SJISTable[0x2A] = 0x002A; + SJISTable[0x2B] = 0x002B; + SJISTable[0x2C] = 0x002C; + SJISTable[0x2D] = 0x002D; + SJISTable[0x2E] = 0x002E; + SJISTable[0x2F] = 0x002F; + SJISTable[0x30] = 0x0030; + SJISTable[0x31] = 0x0031; + SJISTable[0x32] = 0x0032; + SJISTable[0x33] = 0x0033; + SJISTable[0x34] = 0x0034; + SJISTable[0x35] = 0x0035; + SJISTable[0x36] = 0x0036; + SJISTable[0x37] = 0x0037; + SJISTable[0x38] = 0x0038; + SJISTable[0x39] = 0x0039; + SJISTable[0x3A] = 0x003A; + SJISTable[0x3B] = 0x003B; + SJISTable[0x3C] = 0x003C; + SJISTable[0x3D] = 0x003D; + SJISTable[0x3E] = 0x003E; + SJISTable[0x3F] = 0x003F; + SJISTable[0x40] = 0x0040; + SJISTable[0x41] = 0x0041; + SJISTable[0x42] = 0x0042; + SJISTable[0x43] = 0x0043; + SJISTable[0x44] = 0x0044; + SJISTable[0x45] = 0x0045; + SJISTable[0x46] = 0x0046; + SJISTable[0x47] = 0x0047; + SJISTable[0x48] = 0x0048; + SJISTable[0x49] = 0x0049; + SJISTable[0x4A] = 0x004A; + SJISTable[0x4B] = 0x004B; + SJISTable[0x4C] = 0x004C; + SJISTable[0x4D] = 0x004D; + SJISTable[0x4E] = 0x004E; + SJISTable[0x4F] = 0x004F; + SJISTable[0x50] = 0x0050; + SJISTable[0x51] = 0x0051; + SJISTable[0x52] = 0x0052; + SJISTable[0x53] = 0x0053; + SJISTable[0x54] = 0x0054; + SJISTable[0x55] = 0x0055; + SJISTable[0x56] = 0x0056; + SJISTable[0x57] = 0x0057; + SJISTable[0x58] = 0x0058; + SJISTable[0x59] = 0x0059; + SJISTable[0x5A] = 0x005A; + SJISTable[0x5B] = 0x005B; + SJISTable[0x5C] = 0x00A5; + SJISTable[0x5D] = 0x005D; + SJISTable[0x5E] = 0x005E; + SJISTable[0x5F] = 0x005F; + SJISTable[0x60] = 0x0060; + SJISTable[0x61] = 0x0061; + SJISTable[0x62] = 0x0062; + SJISTable[0x63] = 0x0063; + SJISTable[0x64] = 0x0064; + SJISTable[0x65] = 0x0065; + SJISTable[0x66] = 0x0066; + SJISTable[0x67] = 0x0067; + SJISTable[0x68] = 0x0068; + SJISTable[0x69] = 0x0069; + SJISTable[0x6A] = 0x006A; + SJISTable[0x6B] = 0x006B; + SJISTable[0x6C] = 0x006C; + SJISTable[0x6D] = 0x006D; + SJISTable[0x6E] = 0x006E; + SJISTable[0x6F] = 0x006F; + SJISTable[0x70] = 0x0070; + SJISTable[0x71] = 0x0071; + SJISTable[0x72] = 0x0072; + SJISTable[0x73] = 0x0073; + SJISTable[0x74] = 0x0074; + SJISTable[0x75] = 0x0075; + SJISTable[0x76] = 0x0076; + SJISTable[0x77] = 0x0077; + SJISTable[0x78] = 0x0078; + SJISTable[0x79] = 0x0079; + SJISTable[0x7A] = 0x007A; + SJISTable[0x7B] = 0x007B; + SJISTable[0x7C] = 0x007C; + SJISTable[0x7D] = 0x007D; + SJISTable[0x7E] = 0x007E; + + SJISTable[0x8140] = 0x0020; + SJISTable[0x8149] = 0x0021; + SJISTable[0x22] = 0x0022; + SJISTable[0x8194] = 0x0023; + SJISTable[0x8190] = 0x0024; + SJISTable[0x8193] = 0x0025; + SJISTable[0x8195] = 0x0026; + SJISTable[0x27] = 0x0027; + SJISTable[0x8169] = 0x0028; + SJISTable[0x816A] = 0x0029; + SJISTable[0x8196] = 0x002A; + SJISTable[0x817B] = 0x002B; + SJISTable[0x8143] = 0x002C; + SJISTable[0x815D] = 0x002D; + SJISTable[0x8144] = 0x002E; + SJISTable[0x815E] = 0x002F; + SJISTable[0x824F] = 0x0030; + SJISTable[0x8250] = 0x0031; + SJISTable[0x8251] = 0x0032; + SJISTable[0x8252] = 0x0033; + SJISTable[0x8253] = 0x0034; + SJISTable[0x8254] = 0x0035; + SJISTable[0x8255] = 0x0036; + SJISTable[0x8256] = 0x0037; + SJISTable[0x8257] = 0x0038; + SJISTable[0x8258] = 0x0039; + SJISTable[0x8146] = 0x003A; + SJISTable[0x8147] = 0x003B; + SJISTable[0x8183] = 0x003C; + SJISTable[0x8181] = 0x003D; + SJISTable[0x8184] = 0x003E; + SJISTable[0x8148] = 0x003F; + SJISTable[0x8197] = 0x0040; + SJISTable[0x8260] = 0x0041; + SJISTable[0x8261] = 0x0042; + SJISTable[0x8262] = 0x0043; + SJISTable[0x8263] = 0x0044; + SJISTable[0x8264] = 0x0045; + SJISTable[0x8265] = 0x0046; + SJISTable[0x8266] = 0x0047; + SJISTable[0x8267] = 0x0048; + SJISTable[0x8268] = 0x0049; + SJISTable[0x8269] = 0x004A; + SJISTable[0x826A] = 0x004B; + SJISTable[0x826B] = 0x004C; + SJISTable[0x826C] = 0x004D; + SJISTable[0x826D] = 0x004E; + SJISTable[0x826E] = 0x004F; + SJISTable[0x826F] = 0x0050; + SJISTable[0x8270] = 0x0051; + SJISTable[0x8271] = 0x0052; + SJISTable[0x8272] = 0x0053; + SJISTable[0x8273] = 0x0054; + SJISTable[0x8274] = 0x0055; + SJISTable[0x8275] = 0x0056; + SJISTable[0x8276] = 0x0057; + SJISTable[0x8277] = 0x0058; + SJISTable[0x8278] = 0x0059; + SJISTable[0x8279] = 0x005A; + SJISTable[0x816D] = 0x005B; + SJISTable[0x818F] = 0x00A5; + SJISTable[0x816E] = 0x005D; + SJISTable[0x814F] = 0x005E; + SJISTable[0x8151] = 0x005F; + SJISTable[0x814D] = 0x0060; + SJISTable[0x8281] = 0x0061; + SJISTable[0x8282] = 0x0062; + SJISTable[0x8283] = 0x0063; + SJISTable[0x8284] = 0x0064; + SJISTable[0x8285] = 0x0065; + SJISTable[0x8286] = 0x0066; + SJISTable[0x8287] = 0x0067; + SJISTable[0x8288] = 0x0068; + SJISTable[0x8289] = 0x0069; + SJISTable[0x828A] = 0x006A; + SJISTable[0x828B] = 0x006B; + SJISTable[0x828C] = 0x006C; + SJISTable[0x828D] = 0x006D; + SJISTable[0x828E] = 0x006E; + SJISTable[0x828F] = 0x006F; + SJISTable[0x8290] = 0x0070; + SJISTable[0x8291] = 0x0071; + SJISTable[0x8292] = 0x0072; + SJISTable[0x8293] = 0x0073; + SJISTable[0x8294] = 0x0074; + SJISTable[0x8295] = 0x0075; + SJISTable[0x8296] = 0x0076; + SJISTable[0x8297] = 0x0077; + SJISTable[0x8298] = 0x0078; + SJISTable[0x8299] = 0x0079; + SJISTable[0x829A] = 0x007A; + SJISTable[0x816F] = 0x007B; + SJISTable[0x8162] = 0x007C; + SJISTable[0x8170] = 0x007D; + SJISTable[0x7E] = 0x007E; +} + + +HWND mcdDlg; +HTREEITEM root; +HWND treewindow; + +HTREEITEM AddTreeItem(HWND treeview, HTREEITEM parent, const char *name, LPARAM lp) +{ + TVINSERTSTRUCT node={ + parent, + 0, + { + TVIF_TEXT, + NULL, + TVIS_EXPANDED, + TVIS_EXPANDED, + (LPSTR)name, + 0, + 0, + 0, + 0, + lp, + 1 + } + }; + return TreeView_InsertItem(treeview,&node); +} + +void ReadDir(int cluster, int rec, HTREEITEM tree); + + +class Time +{ + public: + u8 sec; + u8 min; + u8 hour; + u8 day; + u8 month; + u16 year; +}; + + +class Dir +{ + protected: + + + public: + static const u16 DF_READ = 0x0001; + static const u16 DF_WRITE = 0x0002; + static const u16 DF_EXECUTE = 0x0004; + static const u16 DF_PROTECTED = 0x0008; + static const u16 DF_FILE = 0x0010; + static const u16 DF_DIRECTORY = 0x0020; + static const u16 DF_HIDDEN = 0x2000; + static const u16 DF_EXISTS = 0x8000; + + // Directory Attributes + u16 Mode; + s32 Lenght; + Time Created; + s32 Cluster; + u32 DirEntry; + Time Modified; + u32 Attribute; + s8 Name[256]; // just in case some names are longer + + // Parent dir and contents of dir + Dir *Parent; + vector

Sons; + + // Used to store the contents of a file + u8 *File; + + Dir() + { + File = 0; + } + + bool IsHidden() + { + return (Mode & DF_HIDDEN) ? 1 : 0; + } + + bool IsFile() + { + return (Mode & DF_FILE) ? 1 : 0; + } + + bool IsDirectory() + { + return (Mode & DF_DIRECTORY) ? 1 : 0; + } + + bool Exists() + { + return (Mode & DF_EXISTS) ? 1 : 0; + } + + void Load(s8 *d) + { + File = 0; + // For the moment we dont need to load more data + Mode = *(u16 *)d; + Lenght = *(u32 *)(d + 0x04); + Cluster = *(u32 *)(d + 0x10); + strncpy(Name, d + 0x40, 255); + } + + Dir* AddSon(Dir &d) + { + d.Parent = this; + vector::iterator i = Sons.insert(Sons.end(), d); + return &i[0]; + } + + void Release() + { + for(int i=0;iFile + 12); + u32 NumVertex = *(u32 *)(File + 16); + + // Check if it's an ico file + if(FileID != 0x00010000) + { + MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); + return 0; + } + + // Is texture compressed? + if(TextureType != 0x07) + { + //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); + //return; + } + + // Calculate the offset to the animation segment + u32 VertexSize = (AnimationShapes * 8) + 8 + 8; + u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; + + // Check if we really are at the animation header + u32 AnimationID = *(u32 *)(File + AnimationSegmentOffset); + if(AnimationID != 0x00000001) + { + MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); + return 0; + } + + // Get the size of all the animation segment + u32 FrameLenght = *(u32 *)(File + AnimationSegmentOffset + 4); + u32 NumberOfFrames = *(u32 *)(File + AnimationSegmentOffset + 16); + + u32 Offset = AnimationSegmentOffset + 20; + for(int i=0;i 0x07) + { + u32 CompressedDataSize = *(u32 *)(File + Offset); + //RLE compression + + Offset += 4; + u32 OffsetEnd = Offset + CompressedDataSize; + u32 WriteCount = 0; + + while(WriteCount < 0x8000 && Offset < OffsetEnd) + { + + u16 Data = *(u16 *)(File + Offset); + + if(Data < 0xFF00) //Replication + { + Offset += 2; + u16 Rep = *(u16 *)(File + Offset); + + for(int i=0;iLenght-0x8000*/Offset], 0x8000); + } + + // Convert from TIM to rgb + for(z=0;z<0x4000;z++) + { + dest[y] = 8 * (ico[z] & 0x1F); + dest[y+1] = 8 * ((ico[z] >>5) & 0x1F); + dest[y+2] = 8 * (ico[z] >>10); + y += 3; + } + + return 1; + } + +}; + + +class SaveGame +{ + public: + + Dir *D; + char Name1[256]; + char Name2[256]; + + u8 Icon[128*128*3]; + + + SaveGame(Dir *_Dir) + { + char IconName[256]; + + D = _Dir; + + // Find icon.sys + for(int i=0;iSons.size();i++) + { + if(!strcmp("icon.sys", D->Sons[i].Name)) + { + char temp[256]; + + // Get Name in SJIS format + u16 *p = (u16 *)(D->Sons[i].File + 192); + + while(*p != 0x0000) + { + // Switch bytes + u8 *pp = (u8 *)p; + u8 tb = *pp; + *pp = pp[1]; + pp[1] = tb; + + // Translate char + *p = SJISTable[*p]; + + p++; + } + + // Convert unicode string + wcstombs(temp, (wchar_t *)(D->Sons[i].File + 192), 255); + + // Get the second line separator + u16 SecondLine = *(u16 *)(D->Sons[i].File + 6); + SecondLine /= 2; + + // Copy the 2 parts of the string to different strings + strncpy(Name1, temp, SecondLine); + Name1[SecondLine] = 0; + + strcpy(Name2, &temp[SecondLine]); + if(strlen(Name2) + SecondLine > 68) + Name2[0] = 0; + + // Get the icon file name + strcpy(IconName, (char *)D->Sons[i].File + 260); + + } + } + + // Find the icon now + for(int i=0;iSons.size();i++) + { + if(!strcmp(IconName, D->Sons[i].Name)) + { + D->Sons[i].BuildICO((char*)Icon); + } + + } + } + + void AddIcoToImageList(HIMAGELIST il) + { + + HDC hDC = GetDC(NULL); + HDC memDC = CreateCompatibleDC (hDC); + HBITMAP memBM = CreateCompatibleBitmap ( hDC, 128, 128 ); + SelectObject ( memDC, memBM ); + + int px, py, pc=0; + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + } + } + + HDC memDC2 = CreateCompatibleDC (hDC); + HBITMAP memBM2 = CreateCompatibleBitmap ( hDC, 64, 64 ); + SelectObject ( memDC2, memBM2 ); + SetStretchBltMode(memDC2, HALFTONE); + StretchBlt(memDC2, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); + + DeleteDC(memDC2); + DeleteDC(memDC); + ImageList_Add(il, memBM2, NULL); + DeleteObject(memBM); + DeleteObject(memBM2); + ReleaseDC(NULL, hDC); + + + } + + void DrawICO(HWND hWnd) + { + // int px, py, pc=0; + HDC dc = GetDC(hWnd); + /* + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(dc, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + + } + } +*/ + /* + HDC hDC = GetDC(NULL); + HDC memDC = CreateCompatibleDC ( hDC ); + HBITMAP memBM = CreateCompatibleBitmap ( hDC, 256, 128 ); + SelectObject ( memDC, memBM ); + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + + } + } + RECT rect; + rect.left=132; + rect.right=255; + rect.top=4; + rect.bottom=255; + DrawText(memDC, Name1, strlen(Name1), &rect, 0); + rect.top=20; + DrawText(memDC, Name2, strlen(Name2), &rect, 0); + + + SetStretchBltMode(dc, HALFTONE); + StretchBlt(dc, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); + //BitBlt(dc, 0, 0, 256, 128, memDC, 0, 0, SRCCOPY); + */ + } + +}; + + +class MemoryCard +{ + public: + FILE *fp; + int FAT[256*256]; + int indirect_table[256]; + char FileName[1024]; + Dir Root; + vector SaveGameList; + HIMAGELIST ImageList; + + MemoryCard() + { + fp = 0; + ImageList = 0; + } + + int BuildFAT() + { + int IFC; + // indirect table containing the clusters with FAT data + int i, o; + + // First read IFC from the superblock (8MB cards only have 1) + fseek(fp, 0x50, SEEK_SET); + fread(&IFC, 4, 1, fp); + + if(IFC != 8) + { + MessageBox(mcdDlg, "IFC is not 8. Memory Card is probably corrupt.", "Error", 0); + return 0; + } + + #ifdef _DEBUG + SysPrintf("IFC: %d\n\n", IFC); + #endif + + // Read the cluster with the indirect data to the FAT. + fseek(fp, 0x420 * IFC, SEEK_SET); + fread(indirect_table, 4, 128, fp); + fseek(fp, (0x420 * IFC) + 0x210, SEEK_SET); + fread(&indirect_table[128], 4, 128, fp); + + // Build the FAT table from the indirect_table + o = 0; + i = 0; + + while(indirect_table[i] != 0xFFFFFFFF) + { + + fseek(fp, 0x420 * indirect_table[i], SEEK_SET); + fread(&FAT[o], 4, 128, fp); + o+=128; + + fseek(fp, (0x420 * indirect_table[i]) + 0x210, SEEK_SET); + fread(&FAT[o], 4, 128, fp); + o+=128; + + i++; + } + return 1; + } + + void ReadFile(Dir *d) + { + + int cluster = d->Cluster; + int size = d->Lenght; + int numclusters = (int)ceil((double)size / 1024); + int numpages = (int)ceil((double)size / 512); + int i=0, j=0, c=0, read=0; + d->File = (u8 *) malloc(size); + + + for(i=0;i 512) + read = 512; + + fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); + fread(&d->File[c], 1, read, fp); + c+=read; + j++; + if(j == numpages) + break; + + read = size - c; + if(read > 512) + read = 512; + + fseek(fp, 0xA920 + (((cluster) * 0x420)+528), SEEK_SET); + fread(&d->File[c], 1, read, fp); + c+=read; + j++; + if(j == numpages) + break; + + cluster = FAT[cluster]; + cluster = cluster ^ 0x80000000; + if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) + break; + } + + } + + void Read(u32 cluster, Dir *d) + { + int i; + s8 file1[512], file2[512]; + Dir D1, D2; + + for(i = 0; i < 0xffff; i++) + { + + // Read first page containing the first dir + fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); + fread(file1, 1, 512, fp); + // Initialize the temporal dir + D1.Load(file1); + if(D1.Exists() && D1.Lenght >= 0 && D1.Cluster >= 0) + { + // If it exists add the dir to current dir + Dir *td = d->AddSon(D1); + + // If it's a directory and not . or .. recursive call + if(D1.IsDirectory() && D1.Name[0]!= '.' ) + { + Read(td->Cluster, td); + } + + // If it's a file load the file + if(D1.IsFile()) + { + ReadFile(td); + } + } + + + // Read second page with second dir or empty + fseek(fp, 0xA920 + (((cluster) * 0x420) + 528), SEEK_SET); + fread(file2, 1, 512, fp); + // Initialize the temporal dir and add it to current dir + D2.Load(file2); + if(D2.Exists() && D2.Lenght >= 0 && D2.Cluster >= 0) + { + Dir *td = d->AddSon(D2); + + if(D2.IsDirectory() && D2.Name[0]!= '.') + { + Read(td->Cluster, td); + } + + // If it's a file load the file + if(D2.IsFile() && D2.Name[0]!= '.') + { + ReadFile(td); + } + } + + // Get next cluster from the FAT table + cluster = FAT[cluster]; + cluster = cluster ^ 0x80000000; + if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) + break; + } + + } + + void Load(char *filename) + { + strcpy(FileName, filename); + + // Clear previous data + if(fp != 0) + { + fclose(fp); + } + memset(FAT, 0, 256*256*4); + Root.Release(); + + SaveGameList.clear(); + ImageList_Destroy(ImageList); + + // Open memory card file + fp = fopen(FileName, "rb"); + + // Check if we opened the file + if(fp == NULL) + { + MessageBox(mcdDlg, "Unable to open memory card file.", "Error", 0); + return; + } + + // Build the FAT table for the card + if(BuildFAT() == 1) + { + // Read the root dir + Read(0, &Root); + } + + fclose(fp); + + ReadSaveGames(); + } + + void AddDirToTreeView(HWND hWnd, HTREEITEM tree, Dir *d) + { + for(int i=0;iSons.size();i++) + { + HTREEITEM temptree = AddTreeItem(hWnd, tree, d->Sons[i].Name, 0); + if(d->Sons[i].IsDirectory()) + { + TreeView_SetItemState(hWnd, temptree, TVIS_EXPANDED|TVIS_BOLD, 0x00F0); + AddDirToTreeView(hWnd, temptree, &d->Sons[i]); + } + } + } + + void AddToListView(HWND hWnd) + { + ListView_SetIconSpacing(hWnd, 128, 128); + ListView_DeleteAllItems(hWnd); + ListView_SetImageList(hWnd, ImageList, LVSIL_NORMAL); + + LVITEM item; + char temp[2560]; + item.mask = LVIF_IMAGE | LVIF_TEXT; + item.iItem = 0; + item.iSubItem = 0; + item.state = 0; + item.stateMask = 0; + item.pszText = temp; + item.cchTextMax = 255; + item.iImage = 1; + item.iIndent = 0; + item.lParam = 0; + + for(int i=0;iSons.size();i++) + { + if(!strcmp(file, d->Sons[i].Name)) + break; + } + + if(i == d->Sons.size()) + { + MessageBox(mcdDlg, "Unable to find the file.", "Error", 0); + return NULL; + } + + return &d->Sons[i]; + } + + void PaintICOFile(HWND hWnd, char *dir, char *name) + { + // First find the file + Dir *d = FindFile(dir, name); + if(d == NULL) + return; + + + + u32 FileID = *(u32 *)d->File; + u32 AnimationShapes = *(u32 *)(d->File + 4); + u32 TextureType = *(u32 *)(d->File + 8); + //u32 ConstantCheck = *(u32 *)(d->File + 12); + u32 NumVertex = *(u32 *)(d->File + 16); + + // Check if it's an ico file + if(FileID != 0x00010000) + { + MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); + return; + } + + // Is texture compressed? + if(TextureType != 0x07) + { + //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); + //return; + } + + // Calculate the offset to the animation segment + u32 VertexSize = (AnimationShapes * 8) + 8 + 8; + u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; + + // Check if we really are at the animation header + u32 AnimationID = *(u32 *)(d->File + AnimationSegmentOffset); + if(AnimationID != 0x00000001) + { + MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); + return; + } + + // Get the size of all the animation segment + u32 FrameLenght = *(u32 *)(d->File + AnimationSegmentOffset + 4); + u32 NumberOfFrames = *(u32 *)(d->File + AnimationSegmentOffset + 16); + + u32 Offset = AnimationSegmentOffset + 20; + for(int i=0;iFile + Offset + 4); + Offset += 16 + (KeyNum * 8) - 8; // The -8 is there because the doc with the ico format spec is either wrong or I'm stupid + } + + int z, y=0; + u16 ico[0x4000]; + u8 cico[128*128*3]; + + if(TextureType > 0x07) + { + u32 CompressedDataSize = *(u32 *)(d->File + Offset); + //RLE compression + + Offset += 4; + u32 OffsetEnd = Offset + CompressedDataSize; + u32 WriteCount = 0; + + while(WriteCount < 0x8000 && Offset < OffsetEnd) + { + + u16 Data = *(u16 *)(d->File + Offset); + + if(Data < 0xFF00) //Replication + { + Offset += 2; + u16 Rep = *(u16 *)(d->File + Offset); + + for(int i=0;iFile + Offset); + WriteCount++; + Offset += 2; + } + } + + } + + } + else + { + // Get the texture from the file + memcpy(ico, &d->File[/*d->Lenght-0x8000*/Offset], 0x8000); + } + + // Convert from TIM to rgb + for(z=0;z<0x4000;z++) + { + cico[y] = 8 * (ico[z] & 0x1F); + cico[y+1] = 8 * ((ico[z] >>5) & 0x1F); + cico[y+2] = 8 * (ico[z] >>10); + y += 3; + } + + // Draw + int px, py, pc=0; + HDC dc = GetDC(hWnd); + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(dc, py, px, RGB(cico[pc], cico[pc+1], cico[pc+2])); + pc+=3; + + } + } + } + + + void ReadSaveGames() + { + // Initialize the conversion table for SJIS strings + IniSJISTable(); + + // Create the image list + ImageList = ImageList_Create(64, 64, ILC_COLOR32, 10, 256); + + for(int i=0;iSons.size(); // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = dircluster; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], Di->Name); // DIRECTORY NAME + + + if(Lenght % 2) + { + // Find empty cluster... + int c = FindEmptyCluster(); + + // THIS MAY BE WRONG...TEST + FAT[oldcluster] = c; + FAT[c] = 0xFFFFFFFF; + + // Add dir to first page of new cluster + fseek(fp, 0xA920 + (((c) * 0x420) + 0), SEEK_SET); + fwrite(dir, 512, 1, fp); + } + else + { + // Add dir to second page of cluster + fseek(fp, 0xA920 + (((oldcluster) * 0x420) + 528), SEEK_SET); + fwrite(dir, 512, 1, fp); + } + + // CALCULATE CRCS OF CLUSTER + + + // INCREASE ROOT DIR SIZE BY 1 + fseek(fp, 0xA920 + (((0) * 0x420) + 4), SEEK_SET); + int nl = Lenght + 1; + fwrite(&nl, 4, 1, fp); + + + int numfiles = 5; + + // ADD FILE ENTRIES TO DIR ., .. + memset(dir, 0, 512); + *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag + *(u32 *)&dir[4] = numfiles; // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = 0; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], "."); // DIRECTORY NAME + fseek(fp, 0xA920 + (((dircluster) * 0x420) + 0), SEEK_SET); + fwrite(dir, 512, 1, fp); + + memset(dir, 0, 512); + *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag + *(u32 *)&dir[4] = 2; // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = 0; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], ".."); // DIRECTORY NAME + fseek(fp, 0xA920 + (((dircluster) * 0x420) + 528), SEEK_SET); + fwrite(dir, 512, 1, fp); + + FAT[dircluster] = 0xFFFFFFFF; + + + // ADD REST OF FILES + + for(int i=2;iFile, d->Lenght, 1, fp); + fclose(fp); + } + } +} + + + +FILE *fp; + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + mcdDlg = hW; + + SetWindowText(hW, _("Memcard Manager")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); + + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); + + if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, "memcards\\Mcd001.ps2"); + if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, "memcards\\Mcd002.ps2"); + Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); + Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); + + //MC1.Load(Config.Mcd1); + //MC2.Load(Config.Mcd2); + + //MC1.AddCardToTreeView(GetDlgItem(hW, IDC_TREE1)); + //MC2.AddCardToTreeView(GetDlgItem(hW, IDC_TREE2)); + + //MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + //MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDC_MCDSEL1: + Open_Mcd_Proc(hW, 1); + return TRUE; + + case IDC_MCDSEL2: + Open_Mcd_Proc(hW, 2); + return TRUE; + + case IDCANCEL: + { + EndDialog(hW,FALSE); + return TRUE; + } + + case IDOK: + Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); + Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); +// SaveConfig(); + + EndDialog(hW,TRUE); + return TRUE; + + case IDC_RELOAD1: + { + char cardname[1024]; + Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); + MC1.Load(cardname); + MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + //MC1.AddCardToTreeView(GetDlgItem(hW,IDC_TREE1)); + break; + } + + case IDC_RELOAD2: + { + char cardname[1024]; + Edit_GetText(GetDlgItem(hW, IDC_MCD2), cardname, 1024); + MC2.Load(cardname); + MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); + //MC2.AddCardToTreeView(GetDlgItem(hW,IDC_TREE2)); + break; + } + + case IDC_LOADICO1: + { + char cardname[1024]; + MC1.SaveRootDir("test"); + Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); + MC1.Load(cardname); + MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) + MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON1), dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_LOADICO2: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) + MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON2), dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_SAVE1: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) + SaveFileDialog(mcdDlg, 1, dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_SAVE2: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) + SaveFileDialog(mcdDlg, 2, dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + } + case WM_DESTROY: + return TRUE; + } + return FALSE; +} + + + + diff --git a/pcsx2/windows/McdsDlg.h b/pcsx2/windows/McdsDlg.h new file mode 100644 index 0000000000..756100a311 --- /dev/null +++ b/pcsx2/windows/McdsDlg.h @@ -0,0 +1,24 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __MCDSDLG_H__ +#define __MCDSDLG_H__ + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __MCDSDLG_H__ */ diff --git a/pcsx2/windows/PatchBrowser.c b/pcsx2/windows/PatchBrowser.c new file mode 100644 index 0000000000..e2c9fd7f88 --- /dev/null +++ b/pcsx2/windows/PatchBrowser.c @@ -0,0 +1,353 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +/************************** +* +* patchbrowser.c contains all the src of patchbrowser window +* no interaction with emulation code +***************************/ + +#include +#include +#include "Common.h" +#include "win32.h" +#include "resource.h" + +/* + * TODO: + * - not topmost + * - resize stuff + * - ask to save in exit (check if changed) + */ +BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + int tmpi,i; + char fileName[MAX_PATH], *tmpStr; + FILE *fp; + + switch(uMsg) { + + case WM_INITDIALOG: + SetWindowText(hW, _("Patches Browser")); + Button_SetText(GetDlgItem(hW,IDC_REFRESHPATCHLIST), _("Refresh List")); + Button_SetText(GetDlgItem(hW,IDC_NEWPATCH), _("New Patch")); + Button_SetText(GetDlgItem(hW,IDC_SAVEPATCH), _("Save Patch")); + Button_SetText(GetDlgItem(hW,IDC_EXITPB), _("Exit")); + Static_SetText(GetDlgItem(hW,IDC_GAMENAMESEARCH), _("Search game name patch:")); + //List Patches + ListPatches ((HWND) hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + + case IDC_NEWPATCH: + + i = Save_Patch_Proc(fileName); + if ( i == FALSE || (fp = fopen(fileName,"a")) == NULL ) { + MessageBox(hW,(LPCTSTR)"Couldn't create the file.",NULL,(UINT)MB_ICONERROR); + return FALSE; + } + + fclose(fp); + i = MessageBox(hW,(LPCTSTR)"File created sucessfully.\nClear textbox?",NULL,(UINT)(MB_YESNO|MB_ICONQUESTION)); + if (i==IDYES) SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)""); + + return TRUE; + + case IDC_SAVEPATCH: + + i = Save_Patch_Proc(fileName); + if ( i == FALSE || (fp = fopen(fileName,"w")) == NULL ) { + MessageBox(hW,(LPCTSTR)"Couldn't save the file.",NULL,(UINT)MB_ICONERROR); + return FALSE; + } + + tmpi = SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL); + i=0; + for (;tmpi>=0;tmpi--) + i += SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_LINELENGTH, (WPARAM)tmpi, (LPARAM)NULL); + + tmpStr = (char *) malloc(i); + sprintf(tmpStr,""); + SendDlgItemMessage(hW, IDC_PATCHTEXT, WM_GETTEXT, (WPARAM)i, (LPARAM)tmpStr); + + //remove \r + for (i=0,tmpi=0; tmpStr[i]!='\0'; i++) + if (tmpStr[i] != '\r') + tmpStr[tmpi++] = tmpStr[i]; + tmpStr[tmpi] = '\0'; + + fputs(tmpStr,fp); + + fclose(fp); + free(tmpStr); + + MessageBox(hW,(LPCTSTR)"File saved sucessfully.",NULL,(UINT)MB_ICONINFORMATION); + + return TRUE; + + case IDC_REFRESHPATCHLIST: + + //List Patches + ListPatches ((HWND) hW); + + return TRUE; + + case IDC_EXITPB: + + //Close Dialog + EndDialog(hW, FALSE); + + return TRUE; + + case IDC_PATCHCRCLIST: + + //Get selected item + tmpi = SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETCURSEL, 0, 0); + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); + + return ReadPatch ((HWND) hW, fileName); + + case IDC_PATCHNAMELIST: + + //Get selected item + tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETCURSEL, 0, 0); + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); + + //another small hack :p + //eg. SOCOM Demo PAL (7dd01dd9.pnach) + for (i=0;i<(int)strlen(fileName);i++) + if (fileName[i] == '(') tmpi = i; + + sprintf(fileName,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + fileName[tmpi+1],fileName[tmpi+2],fileName[tmpi+3], + fileName[tmpi+4],fileName[tmpi+5],fileName[tmpi+6], + fileName[tmpi+7],fileName[tmpi+8],fileName[tmpi+9], + fileName[tmpi+10],fileName[tmpi+11],fileName[tmpi+12], + fileName[tmpi+13],fileName[tmpi+14]); + + //sanity check + if (fileName[tmpi+15] != ')') return FALSE; + + return ReadPatch ((HWND) hW, fileName); + + case IDC_SEARCHPATCHTEXT: + + //get text + SendDlgItemMessage(hW, IDC_SEARCHPATCHTEXT, EM_GETLINE, 0, (LPARAM)fileName); + //search + tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)fileName); + //select match item + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_SETCURSEL, (WPARAM)tmpi, (LPARAM)NULL); + + return TRUE; + } + return TRUE; + + case WM_CLOSE: + EndDialog(hW, FALSE); + break; + + } + return FALSE; +} +void ListPatches (HWND hW) { + + int i, tmpi, filesize, totalPatch=0, totalSize=0; + char tmpStr[MAX_PATH], *fileData; + WIN32_FIND_DATA FindData; + HANDLE Find; + FILE *fp; + + //clear listbox's + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); + + //sprintf(tmpStr,"%s*.pnach", Config.PatchDir) + sprintf(tmpStr, "patches\\*.pnach"); + + Find = FindFirstFile(tmpStr, &FindData); + + do { + if (Find==INVALID_HANDLE_VALUE) break; + + sprintf(tmpStr,"%s", FindData.cFileName); + + //add file name to crc list + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT) LB_ADDSTRING, (WPARAM)NULL, (LPARAM)tmpStr); + + //sprintf(tmpStr,"%s%s", Config.PatchDir, FindData.cFileName) + sprintf(tmpStr,"patches\\%s", FindData.cFileName); + + fp = fopen(tmpStr, "r"); + if (fp == NULL) break; + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + totalSize += filesize; + fseek(fp, 0, SEEK_SET); + + fileData = (char *) malloc(filesize+1024); + sprintf(fileData,""); + + //read file + while((tmpi=fgetc(fp)) != EOF) + sprintf(fileData,"%s%c",fileData,tmpi); + + //small hack :p + for(i=0;ii;tmpi--) + fileData[tmpi] = fileData[tmpi-1]; + fileData[i] = '\r'; + fileData[i+1] = '\n'; + i++; + } + } + + SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)fileData); + + sprintf(fileData,""); + fclose(fp); + + return TRUE; +} + + +//Left Trim (remove the spaces at the left of a string) +char * lTrim (char *s) { + int count=0,i,tmpi; + + for (i=0;i<(int)strlen(s); i++) { + if (s[i] == ' ') count++; + else { + for (tmpi=0;tmpi<(int)strlen(s);tmpi++) + s[tmpi] = s[tmpi+count]; + break; + } + } + return s; +} + + +BOOL Save_Patch_Proc( char * filename ) { + + OPENFILENAME ofn; + char szFileName[ 256 ]; + char szFileTitle[ 256 ]; + char * filter = "Patch Files (*.pnach)\0*.pnach\0ALL Files (*.*)\0*.*"; + + memset( &szFileName, 0, sizeof( szFileName ) ); + memset( &szFileTitle, 0, sizeof( szFileTitle ) ); + + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = filter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "TXT"; + ofn.Flags = OFN_EXPLORER | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + + if ( GetSaveFileName( &ofn ) ) { + + strcpy( filename, szFileName ); + + return TRUE; + } + else { + return FALSE; + } +} diff --git a/pcsx2/windows/RDebugger.c b/pcsx2/windows/RDebugger.c new file mode 100644 index 0000000000..2e091a071f --- /dev/null +++ b/pcsx2/windows/RDebugger.c @@ -0,0 +1,376 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include +#include +#include +#include "resource.h" +#include "Debugger.h" +#include "RDebugger.h" +#include "Common.h" +#include "PsxCommon.h" +#include "win32.h" +#include "../rdebug/deci2.h" + +u32 port=8510; +SOCKET serversocket, remote; +char message[1024]; //message to add to listbox + +int runStatus=STOP, runCode=0, runCount=1; +HANDLE runEvent=NULL; + +DECI2_DBGP_BRK ebrk[32], + ibrk[32]; +int ebrk_count=0, + ibrk_count=0; + +int debuggedCpu=0; //default is to debug EE cpu; IOP=1 +u32 breakAddress=0; //disabled; ie. you cannot use address 0 for a breakpoint +u32 breakCycle=0; //disabled; ie. you cannot stop after 0 cycles + +int CreateSocket(HWND hDlg, int port){ + WSADATA wsadata; + SOCKADDR_IN saServer; + + if (WSAStartup( MAKEWORD(1, 1), &wsadata) || + ((serversocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)){ + MessageBox(hDlg, "Could not create socket\n[Is TCP/IP installed? WinSock 1.1 or above?]", 0, MB_OK); + return FALSE; + } + sprintf(message, "[PCSX2] %s status=%s", wsadata.szDescription, wsadata.szSystemStatus); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + saServer.sin_family = AF_INET; + saServer.sin_addr.S_un.S_addr = INADDR_ANY; // accept any address + saServer.sin_port = htons(port); // port to listen to + + if (bind(serversocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr))==SOCKET_ERROR){ + sprintf(message, "Could not bind to port %d\n" + "[Is there another server running on that port?]", port); + MessageBox(hDlg, message, 0, MB_OK); + closesocket(serversocket); + return FALSE; + } + sprintf(message, "[PCSX2] Port %d is opened", port); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + // SOMAXCONN connections in queque? maybe 1 is enough... + if (listen(serversocket, SOMAXCONN) == SOCKET_ERROR){ + sprintf(message, "Listening for a connection failed\n" + "[dunno?]"); + MessageBox(hDlg, message, 0, MB_OK); + closesocket(serversocket); + return FALSE; + } + sprintf(message, "[PCSX2] Listening for a connection to establish..."); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + cpuRegs.CP0.n.EPC=cpuRegs.pc; + psxRegs.CP0.n.EPC=psxRegs.pc; + sprintf(message, "%08X", cpuRegs.pc); + Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), message); + sprintf(message, "%08X", psxRegs.pc); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), message); + sprintf(message, "%d", cpuRegs.cycle); + Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), message); + sprintf(message, "%d", psxRegs.cycle); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), message); + Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGEE), (debuggedCpu==0)); + Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGIOP), (debuggedCpu==1)); + Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAT), 8); //8 hex digits + Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAFTER), 10);//10 decimal digits + sprintf(message, "%08X", breakAddress); + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAT), message); + sprintf(message, "%d", breakCycle); + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), message); + + Button_Enable(GetDlgItem(hDlg, IDC_DEBUGIOP), FALSE);//////////////////////// + + return TRUE; +} + +int readData(char *buffer){ + int r, count=0; + u8 *p=buffer; + + memset(buffer, 0, BUFFERSIZE); + while (((count+= r = recv(remote, p, BUFFERSIZE, 0))!=INVALID_SOCKET) && + (count<*(u16*)buffer)) + p+=r; + + if (r==INVALID_SOCKET) + return 0; + + return count; +} + +int writeData(char *result){ + int r;/*, i; + static char l[300], p[10]; + DECI2_HEADER *header=(DECI2_HEADER*)result; +*/ + r = send(remote, result, *(u16*)result, 0); + if (r==SOCKET_ERROR) + return 0; +/* + sprintf(l, "size=%d, src=%c dst=%c proto=0x%04X ", + header->length-8, header->source, header->destination, header->protocol); + for (i=8; i<*(u16*)result; i++){ + sprintf(p, "%02X ", result[i]); + strcat(l, p); + } + SysMessage(l); +*/ + return r; +} + +DWORD WINAPI ServingFunction(LPVOID lpParam){ + static u8 buffer[BUFFERSIZE], //a big buffer + result[BUFFERSIZE], //a big buffer + eepc[9], ioppc[9], eecy[15], iopcy[15]; + SOCKADDR_IN saClient; + HWND hDlg=(HWND)lpParam; + DWORD size=sizeof(struct sockaddr); + int exit=FALSE; + + if ((remote = accept(serversocket, (struct sockaddr*)&saClient, &size))==INVALID_SOCKET){ + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Commmunication lost. THE END"); + return FALSE; + } + sprintf(message, "[PCSX2] Connected to %d.%d.%d.%d on remote port %d", + saClient.sin_addr.S_un.S_un_b.s_b1, + saClient.sin_addr.S_un.S_un_b.s_b2, + saClient.sin_addr.S_un.S_un_b.s_b3, + saClient.sin_addr.S_un.S_un_b.s_b4, + saClient.sin_port); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Start serving..."); + connected=1;//from this point on, all log stuff goes to ttyp + + //sendBREAK('E', 0, 0xff, 0x21, 1); //do not enable this unless you know what you are doing! + while (!exit && readData(buffer)){ + DECI2_HEADER *header=(DECI2_HEADER*)buffer; + + switch(header->protocol){ + case 0x0000:exit=TRUE; break; + case PROTO_DCMP:D2_DCMP(buffer, result, message); break; +// case 0x0120:D2_DRFP_EE(buffer, result, message); break; +// case 0x0121:D2_DRFP_IOP(buffer, result, message); break; +// case 0x0122:break; + case PROTO_IDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy); break; +// case 0x0140:break; + case PROTO_ILOADP:D2_ILOADP(buffer, result, message); break; + case PROTO_EDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy);break; +// case 0x0240:break; + case PROTO_NETMP:D2_NETMP(buffer, result, message); break; + default: + sprintf(message, "[DECI2 %c->%c/%04X] Protocol=0x%04X", + header->source, header->destination, + header->length, header->protocol); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + continue; + } + if (exit==FALSE){ + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), eepc); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), ioppc); + Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), eecy); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), iopcy); + } + } + connected=0; + + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Connection closed. THE END"); + return TRUE; +} + +DWORD WINAPI Run2(LPVOID lpParam){ + HWND hDlg=(HWND)lpParam; + static char pc[9]; + int i; + + while (1){ + if (runStatus==RUN){ + if (PSMu32(cpuRegs.pc)==0x0000000D){ + sendBREAK('E', 0, runCode, 0x22, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((runCode==2) && (//next + ((PSMu32(cpuRegs.pc) & 0xFC000000)==0x0C000000) ||//JAL + ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x00000009) ||//JALR + ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C) //SYSCALL + )){u32 tmppc=cpuRegs.pc, skip=(PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C ? 4 : 8; + while (cpuRegs.pc!=tmppc+skip) + Cpu->Step(); + }else + Cpu->Step(); //use this with breakpoints & step-by-step +// Cpu->ExecuteBlock(); //use this to run faster, but not for stepping +// sprintf(pc, "%08X", cpuRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), pc); +// sprintf(pc, "%08X", psxRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), pc); +// sprintf(pc, "%d", cpuRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), pc); +// sprintf(pc, "%d", psxRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), pc); + if (runCount!=0 && --runCount==0){ + sendBREAK('E', 0, runCode, 0x23, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((breakAddress) && (breakAddress==cpuRegs.pc)){ + sendBREAK('E', 0, runCode, 0x21, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((breakCycle) && (breakCycle==cpuRegs.cycle)){ + sendBREAK('E', 0, runCode, 0x21, runCount); + InterlockedExchange(&runStatus, STOP); + breakCycle=0; + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), "0"); + continue; + } + for (i=0; i +#include +#include + +#define BUFFERSIZE (128*1024) + +extern LRESULT WINAPI RemoteDebuggerParamsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +extern LRESULT WINAPI RemoteDebuggerProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/pcsx2/windows/VCprojects/pcsx2_2003.sln b/pcsx2/windows/VCprojects/pcsx2_2003.sln new file mode 100644 index 0000000000..ca8f36c98b --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2003.sln @@ -0,0 +1,100 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2_2003.vcproj", "{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroSPU2", "..\..\..\plugins\spu2\zerospu2\ZeroSPU2.vcproj", "{4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroPAD", "..\..\..\plugins\pad\zeropad\Windows\ZeroPAD.vcproj", "{4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGS", "..\..\..\plugins\gs\zerogs\dx\Win32\zerogs.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGSShaders", "..\..\..\plugins\gs\zerogs\dx\ZeroGSShaders\ZeroGSShaders.vcproj", "{811D47CC-E5F0-456A-918E-5908005E8FC0}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGSogl", "..\..\..\plugins\gs\zerogs\opengl\Win32\zerogsogl.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Debug TLB = Debug TLB + Release = Release + Release (to Public) = Release (to Public) + Release TLB = Release TLB + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug.ActiveCfg = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug.Build.0 = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB.ActiveCfg = Debut TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB.Build.0 = Debut TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release.ActiveCfg = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release.Build.0 = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public).ActiveCfg = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public).Build.0 = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB.ActiveCfg = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB.Build.0 = Release TLB|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug.ActiveCfg = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug.Build.0 = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug TLB.ActiveCfg = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug TLB.Build.0 = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release.ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release.Build.0 = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release (to Public).ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release (to Public).Build.0 = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release TLB.ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release TLB.Build.0 = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug.ActiveCfg = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug.Build.0 = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug TLB.ActiveCfg = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Debug TLB.Build.0 = Debug|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release.ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release.Build.0 = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release (to Public).ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release (to Public).Build.0 = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release TLB.ActiveCfg = Release|Win32 + {4DA8FB7A-A7C5-4FF9-82FA-BA385F3B3D00}.Release TLB.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).Build.0 = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB.ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB.Build.0 = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug.ActiveCfg = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug.Build.0 = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug TLB.ActiveCfg = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug TLB.Build.0 = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release.ActiveCfg = Release|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release.Build.0 = Release|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public).ActiveCfg = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public).Build.0 = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release TLB.ActiveCfg = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release TLB.Build.0 = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).Build.0 = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB.ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB.Build.0 = Release (to Public)|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/pcsx2/windows/VCprojects/pcsx2_2003.vcproj b/pcsx2/windows/VCprojects/pcsx2_2003.vcproj new file mode 100644 index 0000000000..5b0bdcd306 --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2003.vcproj @@ -0,0 +1,1316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/windows/VCprojects/pcsx2_2005.sln b/pcsx2/windows/VCprojects/pcsx2_2005.sln new file mode 100644 index 0000000000..f5abca846c --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2005.sln @@ -0,0 +1,100 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2_2005.vcproj", "{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "..\..\..\plugins\spu2\PeopsSPU2\spu2PeopsSound_2005.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroSPU2", "..\..\..\plugins\spu2\zerospu2\ZeroSPU2_2005.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroPAD", "..\..\..\plugins\pad\zeropad\Windows\ZeroPAD_2005.vcproj", "{CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2null", "..\..\..\plugins\spu2\SPU2null\Src\SPU2null_2005.vcproj", "{D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zerogs", "..\..\..\plugins\gs\zerogs\dx\Win32\zerogs_2005.vcproj", "{5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "..\..\..\plugins\cdvd\CDVDiso\src\Win32\CDVDiso_2005.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug TLB|Win32 = Debug TLB|Win32 + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release TLB|Win32 = Release TLB|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.ActiveCfg = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.Build.0 = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.Build.0 = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.ActiveCfg = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.Build.0 = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.ActiveCfg = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug TLB|Win32.Build.0 = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.Build.0 = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release (to Public)|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release TLB|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release TLB|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug TLB|Win32.Build.0 = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug|Win32.Build.0 = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release (to Public)|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release TLB|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release TLB|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release|Win32.Build.0 = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug TLB|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release TLB|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release TLB|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.ActiveCfg = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|Win32.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pcsx2/windows/VCprojects/pcsx2_2005.vcproj b/pcsx2/windows/VCprojects/pcsx2_2005.vcproj new file mode 100644 index 0000000000..8459d73cad --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2005.vcproj @@ -0,0 +1,1433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/windows/VCprojects/pcsx2_2005_x64.sln b/pcsx2/windows/VCprojects/pcsx2_2005_x64.sln new file mode 100644 index 0000000000..5a73cb9c54 --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2005_x64.sln @@ -0,0 +1,214 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2_2005_x64.vcproj", "{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "..\..\..\plugins\cdvd\CDVDiso\src\Win32\CDVDiso 2005 x64.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2null", "..\..\..\plugins\spu2\SPU2null\Src\SPU2null_2005_x64.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "..\..\..\plugins\spu2\PeopsSPU2\spu2PeopsSound_2005_x64.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PadSSSPSX", "..\..\..\plugins\pad\SSSPSXPAD\PadSSSPSX_2005_x64.vcproj", "{79D9E8A9-C764-4082-826C-B715341FB1E9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroSPU2", "..\..\..\plugins\spu2\zerospu2\ZeroSPU2_2005_x64.vcproj", "{BE29A954-73FD-41A3-B8BE-63F7126E47AE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBNull", "..\..\..\plugins\usb\USBnull\Win32\USBnull_2005_x64.vcproj", "{84EB6606-9C0A-47D4-A3FE-3CD724BC567A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FireWireNull", "..\..\..\plugins\fw\FWnull\Win32\FireWireNull_2005_x64.vcproj", "{EC0CBDD2-8265-4E85-9E88-E2EFF294F031}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dev9Null", "..\..\..\plugins\dev9\dev9null\src\Dev9null_2005_x64.vcproj", "{283CD11D-BCA5-4194-851D-B0878CA5CFC0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGS", "..\..\..\plugins\gs\zerogs\dx\Win32\zerogs_2005_x64.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug TLB|Win32 = Debug TLB|Win32 + Debug TLB|x64 = Debug TLB|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release (to Public)|x64 = Release (to Public)|x64 + Release TLB|Win32 = Release TLB|Win32 + Release TLB|x64 = Release TLB|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.ActiveCfg = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.Build.0 = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|x64.ActiveCfg = Debug TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|x64.Build.0 = Debug TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.Build.0 = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|x64.ActiveCfg = Debug|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|x64.Build.0 = Debug|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|Win32.ActiveCfg = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|x64.ActiveCfg = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|x64.Build.0 = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.ActiveCfg = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.Build.0 = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|x64.ActiveCfg = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|x64.Build.0 = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.ActiveCfg = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.Build.0 = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.ActiveCfg = Release TLB|x64 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.Build.0 = Release TLB|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|Win32.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|x64.Build.0 = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|x64.Build.0 = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|x64.Build.0 = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|Win32.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|x64.Build.0 = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|x64.Build.0 = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|x64.ActiveCfg = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|x64.Build.0 = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|x64.ActiveCfg = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|x64.Build.0 = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|x64.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|x64.Build.0 = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|Win32.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|x64.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|x64.Build.0 = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|x64.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|x64.Build.0 = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|x64.ActiveCfg = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|x64.Build.0 = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|x64.ActiveCfg = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|x64.Build.0 = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|x64.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|x64.Build.0 = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|Win32.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|x64.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|x64.Build.0 = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|x64.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|x64.Build.0 = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug TLB|x64.ActiveCfg = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug TLB|x64.Build.0 = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|Win32.ActiveCfg = Debug|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|Win32.Build.0 = Debug|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|x64.ActiveCfg = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|x64.Build.0 = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release (to Public)|x64.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release (to Public)|x64.Build.0 = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release TLB|Win32.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release TLB|x64.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release TLB|x64.Build.0 = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.ActiveCfg = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.Build.0 = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|x64.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|x64.Build.0 = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug TLB|x64.ActiveCfg = Debug|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug TLB|x64.Build.0 = Debug|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug|Win32.Build.0 = Debug|Win32 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug|x64.ActiveCfg = Debug|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Debug|x64.Build.0 = Debug|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release (to Public)|x64.ActiveCfg = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release (to Public)|x64.Build.0 = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release TLB|Win32.ActiveCfg = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release TLB|x64.ActiveCfg = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release TLB|x64.Build.0 = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release|Win32.ActiveCfg = Release|Win32 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release|Win32.Build.0 = Release|Win32 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release|x64.ActiveCfg = Release|x64 + {BE29A954-73FD-41A3-B8BE-63F7126E47AE}.Release|x64.Build.0 = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug TLB|x64.ActiveCfg = Debug|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug TLB|x64.Build.0 = Debug|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug|Win32.ActiveCfg = Debug|Win32 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug|Win32.Build.0 = Debug|Win32 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug|x64.ActiveCfg = Debug|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Debug|x64.Build.0 = Debug|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release (to Public)|x64.ActiveCfg = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release (to Public)|x64.Build.0 = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release TLB|Win32.ActiveCfg = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release TLB|x64.ActiveCfg = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release TLB|x64.Build.0 = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release|Win32.ActiveCfg = Release|Win32 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release|Win32.Build.0 = Release|Win32 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release|x64.ActiveCfg = Release|x64 + {84EB6606-9C0A-47D4-A3FE-3CD724BC567A}.Release|x64.Build.0 = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug TLB|x64.ActiveCfg = Debug|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug TLB|x64.Build.0 = Debug|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug|Win32.Build.0 = Debug|Win32 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug|x64.ActiveCfg = Debug|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Debug|x64.Build.0 = Debug|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release (to Public)|x64.ActiveCfg = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release (to Public)|x64.Build.0 = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release TLB|Win32.ActiveCfg = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release TLB|x64.ActiveCfg = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release TLB|x64.Build.0 = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release|Win32.ActiveCfg = Release|Win32 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release|Win32.Build.0 = Release|Win32 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release|x64.ActiveCfg = Release|x64 + {EC0CBDD2-8265-4E85-9E88-E2EFF294F031}.Release|x64.Build.0 = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug TLB|x64.ActiveCfg = Debug|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug TLB|x64.Build.0 = Debug|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug|Win32.ActiveCfg = Debug|Win32 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug|Win32.Build.0 = Debug|Win32 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug|x64.ActiveCfg = Debug|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Debug|x64.Build.0 = Debug|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release (to Public)|Win32.ActiveCfg = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release (to Public)|x64.ActiveCfg = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release (to Public)|x64.Build.0 = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release TLB|Win32.ActiveCfg = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release TLB|x64.ActiveCfg = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release TLB|x64.Build.0 = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release|Win32.ActiveCfg = Release|Win32 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release|Win32.Build.0 = Release|Win32 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release|x64.ActiveCfg = Release|x64 + {283CD11D-BCA5-4194-851D-B0878CA5CFC0}.Release|x64.Build.0 = Release|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB|Win32.ActiveCfg = Debug|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB|x64.ActiveCfg = Debug|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug TLB|x64.Build.0 = Debug|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|Win32.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|x64.ActiveCfg = Debug|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|x64.Build.0 = Debug|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|x64.ActiveCfg = Release (to Public)|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|x64.Build.0 = Release (to Public)|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB|Win32.ActiveCfg = Release (to Public)|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB|x64.ActiveCfg = Release (to Public)|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release TLB|x64.Build.0 = Release (to Public)|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|Win32.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|Win32.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|x64.ActiveCfg = Release|x64 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pcsx2/windows/VCprojects/pcsx2_2005_x64.vcproj b/pcsx2/windows/VCprojects/pcsx2_2005_x64.vcproj new file mode 100644 index 0000000000..dbfa1e4a17 --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2005_x64.vcproj @@ -0,0 +1,2244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.sln b/pcsx2/windows/VCprojects/pcsx2_2008.sln new file mode 100644 index 0000000000..df1eed2083 --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2008.sln @@ -0,0 +1,100 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2_2008.vcproj", "{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "..\..\..\plugins\spu2\PeopsSPU2\spu2PeopsSound_2008.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroSPU2", "..\..\..\plugins\spu2\zerospu2\ZeroSPU2_2008.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroPAD", "..\..\..\plugins\pad\zeropad\Windows\ZeroPAD_2008.vcproj", "{CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2null", "..\..\..\plugins\spu2\SPU2null\Src\SPU2null_2008.vcproj", "{D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zerogs", "..\..\..\plugins\gs\zerogs\dx\Win32\zerogs_2008.vcproj", "{5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "..\..\..\plugins\cdvd\CDVDiso\src\Win32\CDVDiso_2008.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug TLB|Win32 = Debug TLB|Win32 + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release TLB|Win32 = Release TLB|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.ActiveCfg = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug TLB|Win32.Build.0 = Debug TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.Build.0 = Debug|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.ActiveCfg = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release TLB|Win32.Build.0 = Release TLB|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.ActiveCfg = Release|Win32 + {1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug TLB|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release (to Public)|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release TLB|Win32.Build.0 = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug TLB|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release (to Public)|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release TLB|Win32.Build.0 = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug TLB|Win32.Build.0 = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.Build.0 = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release (to Public)|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release TLB|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release TLB|Win32.Build.0 = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug TLB|Win32.Build.0 = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Debug|Win32.Build.0 = Debug|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release (to Public)|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release TLB|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release TLB|Win32.Build.0 = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release|Win32.ActiveCfg = Release|Win32 + {D87F63EC-5CD8-4A41-B416-16C7ABD4E5CB}.Release|Win32.Build.0 = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug TLB|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release TLB|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release TLB|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.ActiveCfg = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|Win32.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug TLB|Win32.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release (to Public)|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release TLB|Win32.Build.0 = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj new file mode 100644 index 0000000000..d5ecea841a --- /dev/null +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -0,0 +1,1415 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/windows/VCprojects/vsprops/common.vsprops b/pcsx2/windows/VCprojects/vsprops/common.vsprops new file mode 100644 index 0000000000..cc09cbe92e --- /dev/null +++ b/pcsx2/windows/VCprojects/vsprops/common.vsprops @@ -0,0 +1,28 @@ + + + + + diff --git a/pcsx2/windows/VCprojects/vsprops/debug.vsprops b/pcsx2/windows/VCprojects/vsprops/debug.vsprops new file mode 100644 index 0000000000..af6f81ca44 --- /dev/null +++ b/pcsx2/windows/VCprojects/vsprops/debug.vsprops @@ -0,0 +1,18 @@ + + + + + diff --git a/pcsx2/windows/VCprojects/vsprops/devbuild.vsprops b/pcsx2/windows/VCprojects/vsprops/devbuild.vsprops new file mode 100644 index 0000000000..5713920648 --- /dev/null +++ b/pcsx2/windows/VCprojects/vsprops/devbuild.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/pcsx2/windows/VCprojects/vsprops/release.vsprops b/pcsx2/windows/VCprojects/vsprops/release.vsprops new file mode 100644 index 0000000000..bfc1fe43b7 --- /dev/null +++ b/pcsx2/windows/VCprojects/vsprops/release.vsprops @@ -0,0 +1,27 @@ + + + + + + diff --git a/pcsx2/windows/VCprojects/vsprops/virtualmem.vsprops b/pcsx2/windows/VCprojects/vsprops/virtualmem.vsprops new file mode 100644 index 0000000000..76d0783d46 --- /dev/null +++ b/pcsx2/windows/VCprojects/vsprops/virtualmem.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/pcsx2/windows/Win32.h b/pcsx2/windows/Win32.h new file mode 100644 index 0000000000..1a1a58e346 --- /dev/null +++ b/pcsx2/windows/Win32.h @@ -0,0 +1,49 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WIN32_H__ +#define __WIN32_H__ + +extern int needReset; + +AppData gApp; +HWND hStatusWnd; + +LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM); +void CreateMainWindow(int nCmdShow); +void RunGui(); +int LoadConfig(); +void SaveConfig(); + +BOOL Open_File_Proc(char *filename); +BOOL Pcsx2Configure(HWND hWnd); +void RunExecute(int run); +void InitLanguages(); +char *GetLanguageNext(); +void CloseLanguages(); +void ChangeLanguage(char *lang); +void OpenConsole(); +void CloseConsole(); +#define StatusSet(text) SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text); + +//patch browser window +BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +//cpu dialog window +BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +#endif + diff --git a/pcsx2/windows/WinMain.c b/pcsx2/windows/WinMain.c new file mode 100644 index 0000000000..5b3a195568 --- /dev/null +++ b/pcsx2/windows/WinMain.c @@ -0,0 +1,1970 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINVER 0x0500 + +#if _WIN32_WINNT < 0x0501 +#define _WIN32_WINNT 0x0501 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "win32.h" +#include "resource.h" +#include "debugger.h" +#include "rdebugger.h" +#include "AboutDlg.h" +#include "McdsDlg.h" + +#include "VU.h" +#include "iCore.h" +#include "iVUzerorec.h" + +#include "cheats/cheats.h" + +#include "../Paths.h" + +#define COMPILEDATE __DATE__ + +static int efile; +char filename[256]; +extern int g_SaveGSStream; + +static int AccBreak = 0; +int needReset = 1; +unsigned int langsMax; +typedef struct { + char lang[256]; +} _langs; +_langs *langs = NULL; + +int UseGui = 1; +int nDisableSC = 0; // screensaver +int firstRun=1; +int RunExe = 0; +void OpenConsole() { + COORD csize; + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + SMALL_RECT srect; + + if (gApp.hConsole) return; + AllocConsole(); + SetConsoleTitle(_("Ps2 Output")); + csize.X = 100; + csize.Y = 1024; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), csize); + + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbiInfo); + srect = csbiInfo.srWindow; + srect.Right = srect.Left + 99; + srect.Bottom = srect.Top + 64; + SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &srect); + gApp.hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +} + +void CloseConsole() { + if (gApp.hConsole == NULL) return; + FreeConsole(); gApp.hConsole = NULL; +} +void strcatz(char *dst, char *src) { + int len = strlen(dst) + 1; + strcpy(dst + len, src); +} + +//2002-09-20 (Florin) +BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);//forward def +//------------------- + +extern int g_ZeroGSOptions; +void RunExecute(int run) { + SetThreadPriority(GetCurrentThread(), Config.ThPriority); + SetPriorityClass(GetCurrentProcess(), Config.ThPriority == THREAD_PRIORITY_HIGHEST ? ABOVE_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS); + nDisableSC = 1; + + if (needReset == 1) { + SysReset(); + } + + if( UseGui ) + AccBreak = 1; + + DestroyWindow(gApp.hWnd); + gApp.hWnd = NULL; + + if (OpenPlugins(g_TestRun.ptitle) == -1) { + CreateMainWindow(SW_SHOWNORMAL); + return; + } + + if (needReset == 1) { + if(RunExe == 0)cpuExecuteBios(); + //if (efile == 2) + if(!efile)efile=GetPS2ElfName(filename); + //if (efile) + loadElfFile(filename); + + RunExe = 0; + efile=0; + needReset = 0; + } + + // this needs to be called for every new game! (note: sometimes launching games through bios will give a crc of 0) + if( GSsetGameCRC != NULL ) + GSsetGameCRC(ElfCRC, g_ZeroGSOptions); + + if (run) Cpu->Execute(); +} + +int Slots[5] = { -1, -1, -1, -1, -1 }; + +void ResetMenuSlots() { + int i; + + for (i=0; i<5; i++) { + if (Slots[i] == -1) + EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_GRAYED); + else + EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_ENABLED); + } +} + +void UpdateMenuSlots() { + char str[256]; + int i; + + for (i=0; i<5; i++) { + sprintf (str, "sstates\\%8.8X.%3.3d", ElfCRC, i); + Slots[i] = CheckState(str); + } +} + +void States_Load(int num) { + char Text[256]; + int ret; + + efile = 0; + RunExecute(0); + + sprintf (Text, "sstates\\%8.8X.%3.3d", ElfCRC, num); + ret = LoadState(Text); + if (ret == 0) + sprintf (Text, _("*PCSX2*: Loaded State %d"), num+1); + else sprintf (Text, _("*PCSX2*: Error Loading State %d"), num+1); + StatusSet(Text); + + Cpu->Execute(); +} + +void States_Save(int num) { + char Text[256]; + int ret; + + + sprintf (Text, "sstates\\%8.8X.%3.3d", ElfCRC, num); + ret = SaveState(Text); + if (ret == 0) + sprintf(Text, _("*PCSX2*: Saving State %d"), num+1); + else sprintf(Text, _("*PCSX2*: Error Saving State %d"), num+1); + StatusSet(Text); + + RunExecute(1); +} + +void OnStates_LoadOther() { + OPENFILENAME ofn; + char szFileName[256]; + char szFileTitle[256]; + char szFilter[256]; + + memset(&szFileName, 0, sizeof(szFileName)); + memset(&szFileTitle, 0, sizeof(szFileTitle)); + + strcpy(szFilter, _("PCSX2 State Format")); + strcatz(szFilter, "*.*;*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "EXE"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { + char Text[256]; + int ret; + + efile = 2; + RunExecute(0); + + ret = LoadState(szFileName); + + if (ret == 0) + sprintf(Text, _("*PCSX2*: Saving State %s"), szFileName); + else sprintf(Text, _("*PCSX2*: Error Saving State %s"), szFileName); + StatusSet(Text); + + Cpu->Execute(); + } +} + +void OnStates_Save1() { States_Save(0); } +void OnStates_Save2() { States_Save(1); } +void OnStates_Save3() { States_Save(2); } +void OnStates_Save4() { States_Save(3); } +void OnStates_Save5() { States_Save(4); } + +char* g_pRunGSState = NULL; + +void OnStates_SaveOther() { + OPENFILENAME ofn; + char szFileName[256]; + char szFileTitle[256]; + char szFilter[256]; + + memset(&szFileName, 0, sizeof(szFileName)); + memset(&szFileTitle, 0, sizeof(szFileTitle)); + + strcpy(szFilter, _("PCSX2 State Format")); + strcatz(szFilter, "*.*;*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "EXE"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { + char Text[256]; + int ret; + + ret = SaveState(szFileName); + if (ret == 0) + sprintf(Text, _("*PCSX2*: Loaded State %s"), szFileName); + else sprintf(Text, _("*PCSX2*: Error Loading State %s"), szFileName); + StatusSet(Text); + + RunExecute(1); + } +} + +TESTRUNARGS g_TestRun; + +static int ParseCommandLine(char* pcmd) +{ + const char* pdelim = " \t\r\n"; + char* token = strtok(pcmd, pdelim); + + g_TestRun.efile = 0; + + while(token != NULL) { + + if( _stricmp(token, "-help") == 0) { + const char* phelpmsg = + "pcsx2 [options] [file]\n\n" + "-cfg [file] {configuration file}\n" + "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" + "-help {display this help file}\n" + "-nogui {Don't use gui when launching}\n" + "-loadgs [file} {Loads a gsstate}\n" + "\n" +#ifdef PCSX2_DEVBUILD + "Testing Options: \n" + "\t-frame [frame] {game will run up to this frame before exiting}\n" + "\t-image [name] {path and base name of image (do not include the .ext)}\n" + "\t-jpg {save images to jpg format}\n" + "\t-log [name] {log path to save log file in}\n" + "\t-logopt [hex] {log options in hex (see debug.h) }\n" + "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" + "\t-test {Triggers testing mode (only for dev builds)}\n" + "\n" +#endif + + "Load Plugins:\n" + "\t-cdvd [dllpath] {specify the dll load path of the CDVD plugin}\n" + "\t-gs [dllpath] {specify the dll load path of the GS plugin}\n" + "-pad [tsxcal] {specify to hold down on the triangle, square, circle, x, start, select buttons}\n" + "\t-spu [dllpath] {specify the dll load path of the SPU2 plugin}\n" + "\n"; + + printf("%s", phelpmsg); + MessageBox(NULL,phelpmsg,"Help", MB_OK); + return -1; + } + else if( _stricmp(token, "-nogui") == 0 ) { + UseGui = 0; + } +#ifdef PCSX2_DEVBUILD + else if( _stricmp(token, "-image") == 0 ) { + token = strtok(NULL, pdelim); + g_TestRun.pimagename = token; + } + else if( _stricmp(token, "-log") == 0 ) { + token = strtok(NULL, pdelim); + g_TestRun.plogname = token; + } + else if( _stricmp(token, "-logopt") == 0 ) { + token = strtok(NULL, pdelim); + if( token != NULL ) { + if( token[0] == '0' && token[1] == 'x' ) token += 2; + sscanf(token, "%x", &varLog); + } + } + else if( _stricmp(token, "-frame") == 0 ) { + token = strtok(NULL, pdelim); + if( token != NULL ) { + g_TestRun.frame = atoi(token); + } + } + else if( _stricmp(token, "-numimages") == 0 ) { + token = strtok(NULL, pdelim); + if( token != NULL ) { + g_TestRun.numimages = atoi(token); + } + } + else if( _stricmp(token, "-jpg") == 0 ) { + g_TestRun.jpgcapture = 1; + } +#endif + else if( _stricmp(token, "-pad") == 0 ) { + token = strtok(NULL, pdelim); + printf("-pad ignored\n"); + } + else if( _stricmp(token, "-efile") == 0 ) { + token = strtok(NULL, pdelim); + if( token != NULL ) { + g_TestRun.efile = atoi(token); + } + } + else if( _stricmp(token, "-gs") == 0 ) { + token = strtok(NULL, pdelim); + g_TestRun.pgsdll = token; + } + else if( _stricmp(token, "-cdvd") == 0 ) { + token = strtok(NULL, pdelim); + g_TestRun.pcdvddll = token; + } + else if( _stricmp(token, "-spu") == 0 ) { + token = strtok(NULL, pdelim); + g_TestRun.pspudll = token; + } + else if( _stricmp(token, "-loadgs") == 0 ) { + token = strtok(NULL, pdelim); + g_pRunGSState = token; + } + else { + g_TestRun.ptitle = token; + printf("opening file %s\n", token); + } + + if( token == NULL ) { + printf("invalid args\n"); + return -1; + } + + token = strtok(NULL, pdelim); + } + + return 0; +} + +extern void LoadPatch(char *crc); + +BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable); + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + char *lang; + int i; + +#ifdef PCSX2_VIRTUAL_MEM + LPVOID lpMemReserved; +#endif + + InitCommonControls(); + pInstance=hInstance; + FirstShow=true; + +#ifdef PCSX2_VIRTUAL_MEM + + if( !SysLoggedSetLockPagesPrivilege( GetCurrentProcess(), TRUE ) ) + return -1; + + lpMemReserved = VirtualAlloc(PS2MEM_BASE, 0x40000000, MEM_RESERVE, PAGE_NOACCESS); + + if( lpMemReserved == NULL || lpMemReserved!= PS2MEM_BASE ) { + char str[255]; + sprintf(str, "Cannot allocate mem addresses %x-%x, err: %d", PS2MEM_BASE, PS2MEM_BASE+0x40000000, GetLastError()); + MessageBox(NULL, str, "SysError", MB_OK); + return -1; + } + + __try + { + +#endif + + gApp.hInstance = hInstance; + gApp.hMenu = NULL; + gApp.hWnd = NULL; + gApp.hConsole = NULL; + +#ifdef ENABLE_NLS + bindtextdomain(PACKAGE, "Langs\\"); + textdomain(PACKAGE); +#endif + + if (LoadConfig() == -1) { + memset(&Config, 0, sizeof(Config)); + //strcpy(Config.Bios, "HLE"); + strcpy(Config.BiosDir, "Bios\\"); + strcpy(Config.PluginsDir, "Plugins\\"); + Config.Patch = 1; + Config.Options = PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_COP2REC; + + SysMessage(_("Pcsx2 needs to be configured")); + Pcsx2Configure(NULL); + + return 0; + } + if (Config.Lang[0] == 0) { + strcpy(Config.Lang, "en_US"); + } + + langs = (_langs*)malloc(sizeof(_langs)); + strcpy(langs[0].lang, "en_US"); + InitLanguages(); i=1; + while ((lang = GetLanguageNext()) != NULL) { + langs = (_langs*)realloc(langs, sizeof(_langs)*(i+1)); + strcpy(langs[i].lang, lang); + i++; + } + CloseLanguages(); + langsMax = i; + + if (Config.PsxOut) OpenConsole(); + + memset(&g_TestRun, 0, sizeof(g_TestRun)); + + if( lpCmdLine == NULL || *lpCmdLine == 0 ) + SysPrintf("-help to see arguments\n"); + else if( ParseCommandLine(lpCmdLine) == -1 ) { + return 2; + } + + if( g_TestRun.pgsdll ) + _snprintf(Config.GS, sizeof(Config.GS), "%s", g_TestRun.pgsdll); + if( g_TestRun.pcdvddll ) + _snprintf(Config.CDVD, sizeof(Config.CDVD), "%s", g_TestRun.pcdvddll); + if( g_TestRun.pspudll ) + _snprintf(Config.SPU2, sizeof(Config.SPU2), "%s", g_TestRun.pspudll); + + if (SysInit() == -1) return 1; + +#ifdef PCSX2_DEVBUILD + if( g_TestRun.enabled || g_TestRun.ptitle != NULL ) { + // run without ui + UseGui = 0; + _snprintf(filename, sizeof(filename), "%s", g_TestRun.ptitle); + needReset = 1; + efile = g_TestRun.efile; + RunExecute(1); + SysClose(); + return 0; // success! + } +#endif + +#ifdef PCSX2_DEVBUILD + if( g_pRunGSState ) { + LoadGSState(g_pRunGSState); + SysClose(); + return 0; + } +#endif + + CreateMainWindow(nCmdShow); + + if( Config.PsxOut ) { + // output the help commands + SysPrintf("\tF1 - save state\n"); + SysPrintf("\t(Shift +) F2 - cycle states\n"); + SysPrintf("\tF3 - load state\n"); + +#ifdef PCSX2_DEVBUILD + SysPrintf("\tF10 - dump performance counters\n"); + SysPrintf("\tF11 - save GS state\n"); + SysPrintf("\tF12 - dump hardware registers\n"); +#endif + } + + LoadPatch("default"); + +// needReset = 1; +// efile = 0; +// RunExecute(1); + + RunGui(); + +#ifdef PCSX2_VIRTUAL_MEM + + } + __except(SysPageFaultExceptionFilter(GetExceptionInformation())) + { + } + + VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE); +#endif + + return 0; +} + +void RunGui() { + MSG msg; + + for (;;) { + if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + Sleep(10); + } +} + +static int shiftkey = 0; +void CALLBACK KeyEvent(keyEvent* ev) +{ + + if (ev == NULL) return; + if (ev->event == KEYRELEASE) { + switch (ev->key) { + case VK_SHIFT: shiftkey = 0; break; + } + GSkeyEvent(ev); return; + } + if (ev->event != KEYPRESS) + return; + + //some pad plugins don't give a key released event for shift, so this is needed + //shiftkey = GetKeyState(VK_SHIFT)&0x8000; + //Well SSXPad breaks with your code, thats why my code worked and your makes reg dumping impossible + //So i suggest you fix the plugins that dont. + + switch (ev->key) { + case VK_SHIFT: shiftkey = 1; break; + case VK_F1: ProcessFKeys(1, shiftkey); break; + case VK_F2: ProcessFKeys(2, shiftkey); break; + case VK_F3: ProcessFKeys(3, shiftkey); break; + case VK_F4: ProcessFKeys(4, shiftkey); break; + case VK_F5: ProcessFKeys(5, shiftkey); break; + case VK_F6: ProcessFKeys(6, shiftkey); break; + case VK_F7: ProcessFKeys(7, shiftkey); break; + case VK_F8: ProcessFKeys(8, shiftkey); break; + case VK_F9: ProcessFKeys(9, shiftkey); break; + case VK_F10: ProcessFKeys(10, shiftkey); break; + case VK_F11: ProcessFKeys(11, shiftkey); break; + case VK_F12: ProcessFKeys(12, shiftkey); break; + + case VK_ESCAPE: +#ifdef PCSX2_DEVBUILD + if( g_SaveGSStream >= 3 ) { + // gs state + g_SaveGSStream = 4; + break; + } +#endif + + ClosePlugins(); + + if( !UseGui ) { + // not using GUI and user just quit, so exit + exit(0); + } + + CreateMainWindow(SW_SHOWNORMAL); + RunGui(); + nDisableSC = 0; + break; + default: + GSkeyEvent(ev); + break; + } +} + +#ifdef PCSX2_DEVBUILD + +BOOL APIENTRY LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + int i; + switch (message) { + case WM_INITDIALOG: + for (i=0; i<32; i++) + if (varLog & (1<= ID_LANGS && LOWORD(wParam) <= (ID_LANGS + langsMax)) { + AccBreak = 1; + DestroyWindow(gApp.hWnd); + ChangeLanguage(langs[LOWORD(wParam) - ID_LANGS].lang); + CreateMainWindow(SW_NORMAL); + return TRUE; + } + } + break; + case WM_DESTROY: + if (!AccBreak) { + SysClose(); + DeleteObject(hbitmap_background); + PostQuitMessage(0); + exit(0); + } else AccBreak = 0; + return TRUE; + + case WM_SYSCOMMAND: + if( nDisableSC && (wParam== SC_SCREENSAVE || wParam == SC_MONITORPOWER) ) { + return FALSE; + } + else + return DefWindowProc(hWnd, msg, wParam, lParam); + break; + + case WM_QUIT: + if (Config.PsxOut) CloseConsole(); + exit(0); + break; + + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + return FALSE; +} + +#define _ADDSUBMENU(menu, menun, string) \ + submenu[menun] = CreatePopupMenu(); \ + AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)submenu[menun], string); + +#define ADDSUBMENU(menun, string) \ + _ADDSUBMENU(gApp.hMenu, menun, string); + +#define ADDSUBMENUS(submn, menun, string) \ + submenu[menun] = CreatePopupMenu(); \ + InsertMenu(submenu[submn], 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT)submenu[menun], string); + +#define ADDMENUITEM(menun, string, id) \ + item.fType = MFT_STRING; \ + item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ + item.fState = MFS_ENABLED; \ + item.wID = id; \ + sprintf(buf, string); \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +#define ADDMENUITEMC(menun, string, id) \ + item.fType = MFT_STRING; \ + item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ + item.fState = MFS_ENABLED | MFS_CHECKED; \ + item.wID = id; \ + sprintf(buf, string); \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +#define ADDSEPARATOR(menun) \ + item.fMask = MIIM_TYPE; \ + item.fType = MFT_SEPARATOR; \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +void CreateMainMenu() { + MENUITEMINFO item; + HMENU submenu[5]; + char buf[256]; + int i; + + item.cbSize = sizeof(MENUITEMINFO); + item.dwTypeData = buf; + item.cch = 256; + + gApp.hMenu = CreateMenu(); + + //submenu = CreatePopupMenu(); + //AppendMenu(gApp.hMenu, MF_STRING | MF_POPUP, (UINT)submenu, _("&File")); + ADDSUBMENU(0, _("&File")); + ADDMENUITEM(0, _("E&xit"), ID_FILE_EXIT); + ADDSEPARATOR(0); + ADDSUBMENUS(0, 1, _("&States")); + ADDSEPARATOR(0); + ADDMENUITEM(0, _("&Open ELF File"), ID_FILEOPEN); + ADDMENUITEM(0, _("&Run CD/DVD"), ID_FILE_RUNCD); + ADDSUBMENUS(1, 3, _("&Save")); + ADDSUBMENUS(1, 2, _("&Load")); + ADDMENUITEM(2, _("&Other..."), ID_FILE_STATES_LOAD_OTHER); + ADDMENUITEM(2, _("Slot &5"), ID_FILE_STATES_LOAD_SLOT5); + ADDMENUITEM(2, _("Slot &4"), ID_FILE_STATES_LOAD_SLOT4); + ADDMENUITEM(2, _("Slot &3"), ID_FILE_STATES_LOAD_SLOT3); + ADDMENUITEM(2, _("Slot &2"), ID_FILE_STATES_LOAD_SLOT2); + ADDMENUITEM(2, _("Slot &1"), ID_FILE_STATES_LOAD_SLOT1); + ADDMENUITEM(3, _("&Other..."), ID_FILE_STATES_SAVE_OTHER); + ADDMENUITEM(3, _("Slot &5"), ID_FILE_STATES_SAVE_SLOT5); + ADDMENUITEM(3, _("Slot &4"), ID_FILE_STATES_SAVE_SLOT4); + ADDMENUITEM(3, _("Slot &3"), ID_FILE_STATES_SAVE_SLOT3); + ADDMENUITEM(3, _("Slot &2"), ID_FILE_STATES_SAVE_SLOT2); + ADDMENUITEM(3, _("Slot &1"), ID_FILE_STATES_SAVE_SLOT1); + + ADDSUBMENU(0, _("&Run")); + + ADDSUBMENUS(0, 1, _("&Process Priority")); + ADDMENUITEM(1, _("&Low"), ID_PROCESSLOW ); + ADDMENUITEM(1, _("High"), ID_PROCESSHIGH); + ADDMENUITEM(1, _("Normal"), ID_PROCESSNORMAL); + ADDMENUITEM(0,_("&Arguments"), ID_RUN_CMDLINE); + ADDMENUITEM(0,_("Re&set"), ID_RUN_RESET); + ADDMENUITEM(0,_("E&xecute"), ID_RUN_EXECUTE); + + ADDSUBMENU(0,_("&Config")); +#ifdef PCSX2_DEVBUILD +// ADDMENUITEM(0,_("&Advanced"), ID_CONFIG_ADVANCED); +#endif + ADDMENUITEM(0,_("Speed &Hacks"), ID_HACKS); + ADDMENUITEM(0,_("&Patches"), ID_PATCHBROWSER); + ADDMENUITEM(0,_("C&pu"), ID_CONFIG_CPU); + ADDMENUITEM(0,_("&Memcards"), ID_CONFIG_MEMCARDS); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("Fire&Wire"), ID_CONFIG_FW); + ADDMENUITEM(0,_("U&SB"), ID_CONFIG_USB); + ADDMENUITEM(0,_("D&ev9"), ID_CONFIG_DEV9); + ADDMENUITEM(0,_("C&dvdrom"), ID_CONFIG_CDVDROM); + ADDMENUITEM(0,_("&Sound"), ID_CONFIG_SOUND); + ADDMENUITEM(0,_("C&ontrollers"), ID_CONFIG_CONTROLLERS); + ADDMENUITEM(0,_("&Graphics"), ID_CONFIG_GRAPHICS); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("&Configure"), ID_CONFIG_CONFIGURE); + + ADDSUBMENU(0,_("&Language")); + + for (i=langsMax-1; i>=0; i--) { + if (!strcmp(Config.Lang, langs[i].lang)) { + ADDMENUITEMC(0,ParseLang(langs[i].lang), ID_LANGS + i); + } else { + ADDMENUITEM(0,ParseLang(langs[i].lang), ID_LANGS + i); + } + } + +#ifdef PCSX2_DEVBUILD + ADDSUBMENU(0, _("&Debug")); + ADDMENUITEM(0,_("&Logging"), ID_DEBUG_LOGGING); + ADDMENUITEM(0,_("Memory Dump"), ID_DEBUG_MEMORY_DUMP); + ADDMENUITEM(0,_("&Remote Debugging"), ID_DEBUG_REMOTEDEBUGGING); + ADDMENUITEM(0,_("Enter &Debugger..."), ID_DEBUG_ENTERDEBUGGER); +#endif + + ADDSUBMENU(0, _("&Misc")); + ADDMENUITEM(0,_("Enable &Patches"), ID_PATCHES); + ADDMENUITEM(0,_("Enable &Console"), ID_CONSOLE); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("Patch &Finder..."), ID_CHEAT_FINDER_SHOW); + ADDMENUITEM(0,_("Patch &Browser..."), ID_CHEAT_BROWSER_SHOW); + + + ADDSUBMENU(0, _("&Help")); + ADDMENUITEM(0,_("&Compatibility List..."), ID_HELP_HELP); + ADDMENUITEM(0,_("&About..."), ID_HELP_ABOUT); + +#ifndef PCSX2_DEVBUILD + EnableMenuItem(GetSubMenu(gApp.hMenu, 4), ID_DEBUG_LOGGING, MF_GRAYED); +#endif +} + +void CreateMainWindow(int nCmdShow) { + WNDCLASS wc; + HWND hWnd; + char buf[256]; + char COMPILER[20]=""; + BITMAP bm; + RECT rect; + int w, h; + +#ifdef _MSC_VER + sprintf(COMPILER, "(VC%d)", (_MSC_VER+100)/200);//hacky:) works for VC6 & VC.NET +#elif __BORLANDC__ + sprintf(COMPILER, "(BC)"); +#endif + /* Load Background Bitmap from the ressource */ + hbitmap_background = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); + + wc.lpszClassName = "PCSX2 Main"; + wc.lpfnWndProc = MainWndProc; + wc.style = 0; + wc.hInstance = gApp.hInstance; + wc.hIcon = LoadIcon(gApp.hInstance, MAKEINTRESOURCE(IDI_ICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_MENUTEXT); + wc.lpszMenuName = 0; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + RegisterClass(&wc); + GetObject(hbitmap_background, sizeof(bm), &bm); + + { +#ifdef PCSX2_VIRTUAL_MEM + const char* pvm = "VM"; +#else + const char* pvm = "non VM"; +#endif + +#ifdef PCSX2_DEVBUILD + sprintf(buf, _("PCSX2 %s Watermoose - %s Compile Date - %s %s"), PCSX2_VERSION, pvm, COMPILEDATE, COMPILER); +#else + sprintf(buf, _("PCSX2 %s Watermoose - %s"), PCSX2_VERSION, pvm); +#endif + } + + hWnd = CreateWindow("PCSX2 Main", + buf, WS_OVERLAPPED | WS_SYSMENU, + 20, 20, 320, 240, NULL, NULL, + gApp.hInstance, NULL); + + gApp.hWnd = hWnd; + ResetMenuSlots(); + CreateMainMenu(); + + SetMenu(gApp.hWnd, gApp.hMenu); + if(Config.ThPriority==THREAD_PRIORITY_NORMAL) CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_CHECKED); + if(Config.ThPriority==THREAD_PRIORITY_HIGHEST) CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_CHECKED); + if(Config.ThPriority==THREAD_PRIORITY_LOWEST) CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_CHECKED); + if(Config.PsxOut) CheckMenuItem(gApp.hMenu,ID_CONSOLE,MF_CHECKED); + if(Config.Patch) CheckMenuItem(gApp.hMenu,ID_PATCHES,MF_CHECKED); + hStatusWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, 100); + sprintf(buf, "PCSX2 %s", PCSX2_VERSION); + StatusSet(buf); + + w = bm.bmWidth; h = bm.bmHeight; + GetWindowRect(hStatusWnd, &rect); + h+= rect.bottom - rect.top; + GetMenuItemRect(hWnd, gApp.hMenu, 0, &rect); + h+= rect.bottom - rect.top; + MoveWindow(hWnd, 20, 20, w, h, TRUE); + + DestroyWindow(hStatusWnd); + hStatusWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, 100); + sprintf(buf, "F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot", PCSX2_VERSION); + StatusSet(buf); + ShowWindow(hWnd, nCmdShow); + SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); +} + +BOOL Open_File_Proc(char * filename) { + OPENFILENAME ofn; + char szFileName[ 256 ]; + char szFileTitle[ 256 ]; + char * filter = "ELF Files (*.ELF)\0*.ELF\0ALL Files (*.*)\0*.*\0"; + + memset( &szFileName, 0, sizeof( szFileName ) ); + memset( &szFileTitle, 0, sizeof( szFileTitle ) ); + + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = filter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "ELF"; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName(&ofn)) { + struct stat buf; + + if (stat(szFileName, &buf) != 0) { + return FALSE; + } + + strcpy(filename, szFileName); + return TRUE; + } + + return FALSE; +} + +//2002-09-20 (Florin) +BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + SetWindowText(hDlg, _("Program arguments")); + + Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); + Button_SetText(GetDlgItem(hDlg, IDCANCEL), _("Cancel")); + Static_SetText(GetDlgItem(hDlg, IDC_TEXT), _("Fill in the command line arguments for opened program:")); + Static_SetText(GetDlgItem(hDlg, IDC_TIP), _("Tip: If you don't know what to write\nleave it blank")); + + SetDlgItemText(hDlg, IDC_CMDLINE, args); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + char tmp[256]; + + GetDlgItemText(hDlg, IDC_CMDLINE, tmp, 256); + + ZeroMemory(args, 256); + strcpy(args, tmp); + args[255]=0; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +WIN32_FIND_DATA lFindData; +HANDLE lFind; +int lFirst; + +void InitLanguages() { + lFind = FindFirstFile("Langs\\*", &lFindData); + lFirst = 1; +} + +char *GetLanguageNext() { + for (;;) { + if (!strcmp(lFindData.cFileName, ".")) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + continue; + } + if (!strcmp(lFindData.cFileName, "..")) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + continue; + } + break; + } + if (lFirst == 0) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + } else lFirst = 0; + if (lFind==INVALID_HANDLE_VALUE) return NULL; + + return lFindData.cFileName; +} + +void CloseLanguages() { + if (lFind!=INVALID_HANDLE_VALUE) FindClose(lFind); +} + +void ChangeLanguage(char *lang) { + strcpy(Config.Lang, lang); + SaveConfig(); + LoadConfig(); +} + +//------------------- + +static int sinit=0; + +int SysInit() { + CreateDirectory(MEMCARDS_DIR, NULL); + CreateDirectory(SSTATES_DIR, NULL); +#ifdef EMU_LOG + CreateDirectory(LOGS_DIR, NULL); + +#ifdef PCSX2_DEVBUILD + if( g_TestRun.plogname != NULL ) + emuLog = fopen(g_TestRun.plogname, "w"); + if( emuLog == NULL ) + emuLog = fopen(LOGS_DIR "\\emuLog.txt","w"); +#endif + + if( emuLog != NULL ) + setvbuf(emuLog, NULL, _IONBF, 0); + +#endif + if (cpuInit() == -1) return -1; + + while (LoadPlugins() == -1) { + if (Pcsx2Configure(NULL) == FALSE) { + exit(1); + } + } + + sinit=1; + + return 0; +} + +void SysReset() { + if (sinit == 0) return; + StatusSet(_("Resetting...")); + cpuReset(); + StatusSet(_("Ready")); +} + + +void SysClose() { + if (sinit == 0) return; + cpuShutdown(); + ReleasePlugins(); + sinit=0; +} + +int concolors[] = { + 0, + FOREGROUND_RED, + FOREGROUND_GREEN, + FOREGROUND_GREEN | FOREGROUND_RED, + FOREGROUND_BLUE, + FOREGROUND_RED | FOREGROUND_BLUE, + FOREGROUND_RED | FOREGROUND_GREEN, + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE +}; + +void SysPrintf(char *fmt, ...) { + va_list list; + char msg[512]; + char *ptr; + DWORD tmp; + int len, s; + int i, j; + + va_start(list,fmt); + _vsnprintf(msg,511,fmt,list); + msg[511] = '\0'; + va_end(list); + + if (Config.PsxOut == 0) { +#ifdef EMU_LOG +#ifndef LOG_STDOUT + if (emuLog != NULL && !(varLog & 0x80000000)) { + fprintf(emuLog, "%s", msg); + } +#endif +#endif + return; + } + + ptr = msg; len = strlen(msg); + for (i=0, j=0; i 0x7ffe) // String is too large + return FALSE; + } + + // Store the string. + pLsaString->Buffer = (WCHAR *)pwszString; + pLsaString->Length = (USHORT)dwLen * sizeof(WCHAR); + pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR); + + return TRUE; +} + +PLSA_TRANSLATED_SID2 GetSIDInformation (LPWSTR AccountName,LSA_HANDLE PolicyHandle) +{ + LSA_UNICODE_STRING lucName; + PLSA_TRANSLATED_SID2 ltsTranslatedSID; + PLSA_REFERENCED_DOMAIN_LIST lrdlDomainList; + //LSA_TRUST_INFORMATION myDomain; + NTSTATUS ntsResult; + PWCHAR DomainString = NULL; + + // Initialize an LSA_UNICODE_STRING with the name. + if (!InitLsaString(&lucName, AccountName)) + { + wprintf(L"Failed InitLsaString\n"); + return NULL; + } + + ntsResult = LsaLookupNames2( + PolicyHandle, // handle to a Policy object + 0, + 1, // number of names to look up + &lucName, // pointer to an array of names + &lrdlDomainList, // receives domain information + <sTranslatedSID // receives relative SIDs + ); + if (0 != ntsResult) + { + wprintf(L"Failed LsaLookupNames - %lu \n", + LsaNtStatusToWinError(ntsResult)); + return NULL; + } + + // Get the domain the account resides in. +// myDomain = lrdlDomainList->Domains[ltsTranslatedSID->DomainIndex]; +// DomainString = (PWCHAR) LocalAlloc(LPTR, myDomain.Name.Length + 1); +// wcsncpy(DomainString, myDomain.Name.Buffer, myDomain.Name.Length); + + // Display the relative Id. +// wprintf(L"Relative Id is %lu in domain %ws.\n", +// ltsTranslatedSID->RelativeId, +// DomainString); + + LsaFreeMemory(lrdlDomainList); + + return ltsTranslatedSID; +} + +BOOL AddPrivileges(PSID AccountSID, LSA_HANDLE PolicyHandle, BOOL bAdd) +{ + LSA_UNICODE_STRING lucPrivilege; + NTSTATUS ntsResult; + + // Create an LSA_UNICODE_STRING for the privilege name(s). + if (!InitLsaString(&lucPrivilege, L"SeLockMemoryPrivilege")) + { + wprintf(L"Failed InitLsaString\n"); + return FALSE; + } + + if( bAdd ) { + ntsResult = LsaAddAccountRights( + PolicyHandle, // An open policy handle. + AccountSID, // The target SID. + &lucPrivilege, // The privilege(s). + 1 // Number of privileges. + ); + } + else { + ntsResult = LsaRemoveAccountRights( + PolicyHandle, // An open policy handle. + AccountSID, // The target SID + FALSE, + &lucPrivilege, // The privilege(s). + 1 // Number of privileges. + ); + } + + if (ntsResult == 0) + { + wprintf(L"Privilege added.\n"); + } + else + { + int err = LsaNtStatusToWinError(ntsResult); + char str[255]; + _snprintf(str, 255, "Privilege was not added - %lu \n", LsaNtStatusToWinError(ntsResult)); + MessageBox(NULL, str, "Privilege error", MB_OK); + return FALSE; + } + + return TRUE; +} + +#define TARGET_SYSTEM_NAME L"mysystem" +LSA_HANDLE GetPolicyHandle() +{ + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + WCHAR SystemName[] = TARGET_SYSTEM_NAME; + USHORT SystemNameLength; + LSA_UNICODE_STRING lusSystemName; + NTSTATUS ntsResult; + LSA_HANDLE lsahPolicyHandle; + + // Object attributes are reserved, so initialize to zeroes. + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + + //Initialize an LSA_UNICODE_STRING to the server name. + SystemNameLength = wcslen(SystemName); + lusSystemName.Buffer = SystemName; + lusSystemName.Length = SystemNameLength * sizeof(WCHAR); + lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR); + + // Get a handle to the Policy object. + ntsResult = LsaOpenPolicy( + NULL, //Name of the target system. + &ObjectAttributes, //Object attributes. + POLICY_ALL_ACCESS, //Desired access permissions. + &lsahPolicyHandle //Receives the policy handle. + ); + + if (ntsResult != 0) + { + // An error occurred. Display it as a win32 error code. + wprintf(L"OpenPolicy returned %lu\n", + LsaNtStatusToWinError(ntsResult)); + return NULL; + } + return lsahPolicyHandle; +} + + +/***************************************************************** + LoggedSetLockPagesPrivilege: a function to obtain, if possible, or + release the privilege of locking physical pages. + + Inputs: + + HANDLE hProcess: Handle for the process for which the + privilege is needed + + BOOL bEnable: Enable (TRUE) or disable? + + Return value: TRUE indicates success, FALSE failure. + +*****************************************************************/ +BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable) +{ + struct { + u32 Count; + LUID_AND_ATTRIBUTES Privilege [1]; + } Info; + + HANDLE Token; + BOOL Result; + + // Open the token. + + Result = OpenProcessToken ( hProcess, + TOKEN_ADJUST_PRIVILEGES, + & Token); + + if( Result != TRUE ) { + SysPrintf( "Cannot open process token.\n" ); + return FALSE; + } + + // Enable or disable? + + Info.Count = 1; + if( bEnable ) + { + Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + } + else + { + Info.Privilege[0].Attributes = SE_PRIVILEGE_REMOVED; + } + + // Get the LUID. + Result = LookupPrivilegeValue ( NULL, + SE_LOCK_MEMORY_NAME, + &(Info.Privilege[0].Luid)); + + if( Result != TRUE ) + { + SysPrintf( "Cannot get privilege value for %s.\n", SE_LOCK_MEMORY_NAME ); + return FALSE; + } + + // Adjust the privilege. + + Result = AdjustTokenPrivileges ( Token, FALSE, + (PTOKEN_PRIVILEGES) &Info, + 0, NULL, NULL); + + // Check the result. + if( Result != TRUE ) + { + SysPrintf ("Cannot adjust token privileges, error %u.\n", GetLastError() ); + return FALSE; + } + else + { + if( GetLastError() != ERROR_SUCCESS ) + { + + BOOL bSuc = FALSE; + LSA_HANDLE policy; + PLSA_TRANSLATED_SID2 ltsTranslatedSID; + +// if( !DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_USERNAME), gApp.hWnd, (DLGPROC)UserNameProc) ) +// return FALSE; + DWORD len = sizeof(s_szUserName); + GetUserNameW(s_szUserName, &len); + + policy = GetPolicyHandle(); + + if( policy != NULL ) { + + ltsTranslatedSID = GetSIDInformation(s_szUserName, policy); + + if( ltsTranslatedSID != NULL ) { + bSuc = AddPrivileges(ltsTranslatedSID->Sid, policy, bEnable); + LsaFreeMemory(ltsTranslatedSID); + } + + LsaClose(policy); + } + + if( bSuc ) { + // Get the LUID. + LookupPrivilegeValue ( NULL, SE_LOCK_MEMORY_NAME, &(Info.Privilege[0].Luid)); + + bSuc = AdjustTokenPrivileges ( Token, FALSE, (PTOKEN_PRIVILEGES) &Info, 0, NULL, NULL); + } + + if( bSuc ) { + if( MessageBox(NULL, "PCSX2 just changed your SE_LOCK_MEMORY privilege in order to gain access to physical memory.\n" + "Log off/on and run pcsx2 again. Do you want to log off?\n", + "Privilege changed query", MB_YESNO) == IDYES ) { + ExitWindows(EWX_LOGOFF, 0); + } + } + else { + MessageBox(NULL, "Failed adding SE_LOCK_MEMORY privilege, please check the local policy.\n" + "Go to security settings->Local Policies->User Rights. There should be a \"Lock pages in memory\".\n" + "Add your user to that and log off/on. This enables pcsx2 to run at real-time by allocating physical memory.\n" + "Also can try Control Panel->Local Security Policy->... (this does not work on Windows XP Home)\n" + "(zerofrog)\n", "Virtual Memory Access Denied", MB_OK); + return FALSE; + } + } + } + + CloseHandle( Token ); + + return TRUE; +} + +static u32 s_dwPageSize = 0; +int SysPhysicalAlloc(u32 size, PSMEMORYBLOCK* pblock) +{ +//#ifdef WIN32_FILE_MAPPING +// assert(0); +//#endif + ULONG_PTR NumberOfPagesInitial; // initial number of pages requested + int PFNArraySize; // memory to request for PFN array + BOOL bResult; + + assert( pblock != NULL ); + memset(pblock, 0, sizeof(PSMEMORYBLOCK)); + + if( s_dwPageSize == 0 ) { + SYSTEM_INFO sSysInfo; // useful system information + GetSystemInfo(&sSysInfo); // fill the system information structure + s_dwPageSize = sSysInfo.dwPageSize; + + if( s_dwPageSize != 0x1000 ) { + SysMessage("Error! OS page size must be 4Kb!\n" + "If for some reason the OS cannot have 4Kb pages, then run the TLB build."); + return -1; + } + } + + // Calculate the number of pages of memory to request. + pblock->NumberPages = (size+s_dwPageSize-1)/s_dwPageSize; + PFNArraySize = pblock->NumberPages * sizeof (ULONG_PTR); + + pblock->aPFNs = (ULONG_PTR *) HeapAlloc (GetProcessHeap (), 0, PFNArraySize); + + if (pblock->aPFNs == NULL) { + SysPrintf("Failed to allocate on heap.\n"); + goto eCleanupAndExit; + } + + // Allocate the physical memory. + NumberOfPagesInitial = pblock->NumberPages; + bResult = AllocateUserPhysicalPages( GetCurrentProcess(), &pblock->NumberPages, pblock->aPFNs ); + + if( bResult != TRUE ) + { + SysPrintf("Cannot allocate physical pages, error %u.\n", GetLastError() ); + goto eCleanupAndExit; + } + + if( NumberOfPagesInitial != pblock->NumberPages ) + { + SysPrintf("Allocated only %p of %p pages.\n", pblock->NumberPages, NumberOfPagesInitial ); + goto eCleanupAndExit; + } + + pblock->aVFNs = (ULONG_PTR*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize); + + return 0; + +eCleanupAndExit: + SysPhysicalFree(pblock); + return -1; +} + +void SysPhysicalFree(PSMEMORYBLOCK* pblock) +{ + assert( pblock != NULL ); + + // Free the physical pages. + FreeUserPhysicalPages( GetCurrentProcess(), &pblock->NumberPages, pblock->aPFNs ); + + if( pblock->aPFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aPFNs); + if( pblock->aVFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aVFNs); + memset(pblock, 0, sizeof(PSMEMORYBLOCK)); +} + +int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock) +{ + BOOL bResult; + int i; + + LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE ); + if( lpMemReserved == NULL || base != lpMemReserved ) + { + SysPrintf("Cannot reserve memory at 0x%8.8x(%x), error: %d.\n", base, lpMemReserved, GetLastError()); + goto eCleanupAndExit; + } + + // Map the physical memory into the window. + bResult = MapUserPhysicalPages( base, pblock->NumberPages, pblock->aPFNs ); + + for(i = 0; i < pblock->NumberPages; ++i) + pblock->aVFNs[i] = (ULONG_PTR)base + 0x1000*i; + + if( bResult != TRUE ) + { + SysPrintf("MapUserPhysicalPages failed to map, error %u.\n", GetLastError() ); + goto eCleanupAndExit; + } + + return 0; + +eCleanupAndExit: + SysVirtualFree(base, size); + return -1; +} + +void SysVirtualFree(void* lpMemReserved, u32 size) +{ + // unmap + if( MapUserPhysicalPages( lpMemReserved, (size+s_dwPageSize-1)/s_dwPageSize, NULL ) != TRUE ) + { + SysPrintf("MapUserPhysicalPages failed to unmap, error %u.\n", GetLastError() ); + return; + } + + // Free virtual memory. + VirtualFree( lpMemReserved, 0, MEM_RELEASE ); +} + +int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pfn, int pageoffset) +{ + BOOL bResult = MapUserPhysicalPages(Addr, NumPages, pfn+pageoffset); + +#ifdef _DEBUG + //if( !bResult ) + //__Log("Failed to map user pages: 0x%x:0x%x, error = %d\n", Addr, NumPages, GetLastError()); +#endif + + return bResult; +} + +#else + +#endif diff --git a/pcsx2/windows/afxresmw.h b/pcsx2/windows/afxresmw.h new file mode 100644 index 0000000000..147f64b376 --- /dev/null +++ b/pcsx2/windows/afxresmw.h @@ -0,0 +1,23 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/pcsx2/windows/cheats/browser.cpp b/pcsx2/windows/cheats/browser.cpp new file mode 100644 index 0000000000..ae49bf85f7 --- /dev/null +++ b/pcsx2/windows/cheats/browser.cpp @@ -0,0 +1,1136 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include +#include + +#include +#include + +using namespace std; + +#include "../cheatscpp.h" + +#include "PS2Etypes.h" + + +extern "C" { +#include "windows/resource.h" +#include "PS2Edefs.h" +#include "Memory.h" +#include "Elfheader.h" +#include "cheats.h" +#include "../../patch.h" +} + +HWND hWndBrowser; + + +/// ADDED CODE /// +void CreateListBox(HWND hWnd) +{ + // Setting the ListView style + LRESULT lStyle = SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); + + // Adding colummns to the ListView + LVCOLUMN cols[7]={ + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Address",0,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,35,"CPU",1,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Data",2,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Enabled",3,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,45,"Group",4,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,80,"PlaceToPatch",5,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Type",6,0,0} + }; + + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),0,&cols[0]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),1,&cols[1]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),2,&cols[2]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),3,&cols[3]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),4,&cols[4]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),5,&cols[5]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),6,&cols[6]); +} + +void RefreshListBox(HWND hWnd) +{ + // First delete all items + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_PATCHES)); + + char Address[100], CPU[100], Data[100], Enabled[100], Group[100], PlaceToPatch[100], Type[100]; + + LVITEM item[7]={ + {LVIF_TEXT|LVIF_STATE,0,0,0,0,Address,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,1,0,0,CPU,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,2,0,0,Data,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,3,0,0,Enabled,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,4,0,0,Group,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,5,0,0,PlaceToPatch,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,6,0,0,Type,0,0,0,0} + }; + + char datatype[4][10]={"byte", "short", "word", "double"}; + char cpucore[2][10]={"EE", "IOP"}; + + // Adding items + for (int i = patchnumber-1; i >= 0; i--) + { + sprintf(Address, "0x%.8x", patch[i].addr); + sprintf(CPU, "%s", cpucore[patch[i].cpu-1]); + sprintf(Data, "0x%.8x", patch[i].data); + sprintf(Enabled, "%s", patch[i].enabled?"Yes":"No"); + sprintf(Group, "%d", patch[i].group); + sprintf(PlaceToPatch, "%d", patch[i].placetopatch); + sprintf(Type, "%s", datatype[patch[i].type-1]); + + ListView_InsertItem(GetDlgItem(hWnd,IDC_PATCHES),&item[0]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[1]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[2]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[3]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[4]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[5]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[6]); + } +} + + +// Decryption code for GS2v3-4/GS5 from maxconvert 0.71 +unsigned char gsv3_bseeds1[256] = { +0x6E, 0x3C, 0x01, 0x30, 0x45, 0xDA, 0xA1, 0x77, 0x6A, 0x41, 0xFC, 0xC6, 0x00, 0xEA, 0x2F, 0x23, +0xD9, 0x6F, 0x79, 0x39, 0x7E, 0xCC, 0x9A, 0x4E, 0x1E, 0xF4, 0xA7, 0x3D, 0x05, 0x75, 0xD0, 0x36, +0x9E, 0x8D, 0xF8, 0x8B, 0x96, 0x7A, 0xBF, 0x49, 0x62, 0x4F, 0x2A, 0xB8, 0xAF, 0x60, 0x80, 0x0D, +0x99, 0x89, 0xA9, 0xED, 0xB6, 0xD5, 0x7B, 0x54, 0x56, 0x65, 0x5C, 0xB3, 0xD3, 0x11, 0xDF, 0x27, +0x10, 0x71, 0x91, 0x3E, 0x25, 0x52, 0x46, 0x15, 0x3A, 0x31, 0x51, 0x81, 0xC5, 0xB1, 0xBE, 0x43, +0x95, 0x7C, 0x83, 0x53, 0x38, 0x88, 0x21, 0x4C, 0x9B, 0x7F, 0x90, 0xB9, 0xDB, 0x55, 0x33, 0xB7, +0xAD, 0x61, 0xD8, 0xE1, 0xE4, 0x20, 0xDC, 0x5F, 0xA4, 0x67, 0x26, 0x97, 0x2E, 0xAC, 0x7D, 0x24, +0xBD, 0x22, 0x04, 0x6C, 0xC0, 0x73, 0xE0, 0x32, 0x0C, 0xA3, 0xEE, 0x2B, 0xA0, 0x8A, 0x5B, 0xF3, +0xA6, 0xD1, 0x68, 0x8E, 0xAE, 0xC7, 0x9C, 0x82, 0xB4, 0xF9, 0xF6, 0xC4, 0x1B, 0xAB, 0x57, 0xCE, +0xEF, 0x69, 0xF7, 0x74, 0xFF, 0xA2, 0x6D, 0xF5, 0xB2, 0x0A, 0x37, 0x1F, 0xEC, 0x06, 0x5D, 0x0F, +0xB0, 0x08, 0xD7, 0xE3, 0x85, 0x58, 0x1A, 0x9F, 0x1D, 0x84, 0xE9, 0xEB, 0x0E, 0x66, 0x64, 0x40, +0x4A, 0x44, 0x35, 0x92, 0x3B, 0x86, 0xF0, 0xF2, 0xAA, 0x47, 0xCB, 0x02, 0xB5, 0xDD, 0xD2, 0x13, +0x16, 0x07, 0xC2, 0xE5, 0x17, 0xA5, 0x5E, 0xCA, 0xD6, 0xC9, 0x87, 0x2D, 0xC1, 0xCD, 0x76, 0x50, +0x1C, 0xE2, 0x8F, 0x29, 0xD4, 0xDE, 0xA8, 0xE7, 0x14, 0xFB, 0xC3, 0xE6, 0xFD, 0x5A, 0x48, 0xCF, +0x98, 0x42, 0x63, 0x4D, 0xBB, 0xE8, 0x70, 0xF1, 0x12, 0x78, 0x0B, 0xFA, 0xBA, 0x18, 0x93, 0x9D, +0x6B, 0x28, 0x2C, 0x09, 0x59, 0xFE, 0xC8, 0x34, 0x03, 0x94, 0x72, 0x8C, 0x3F, 0x4B, 0x19, 0xBC +}; + +unsigned char gsv3_bseeds2[25] = { 0x12, 0x18, 0x07, 0x0A, 0x17, 0x16, 0x10, 0x00, +0x05, 0x0D, 0x04, 0x02, 0x09, 0x08, 0x0E, 0x0F, 0x13, 0x11, 0x01, 0x15, +0x03, 0x06, 0x0C, 0x0B, 0x14 +}; + +unsigned char gsv3_bseeds3[64] = {0x1D, 0x01, 0x33, 0x0B, 0x23, 0x22, 0x2C, 0x24, +0x0E, 0x2A, 0x2D, 0x0F, 0x2B, 0x20, 0x08, 0x34, 0x17, 0x1B, 0x36, 0x0C, +0x12, 0x1F, 0x35, 0x27, 0x0A, 0x31, 0x11, 0x05, 0x1E, 0x32, 0x14, 0x02, +0x21, 0x03, 0x04, 0x0D, 0x09, 0x16, 0x2E, 0x1A, 0x26, 0x25, 0x2F, 0x07, +0x1C, 0x29, 0x18, 0x30, 0x10, 0x15, 0x13, 0x19, 0x06, 0x38, 0x28, 0x00, +0x37, 0x48, 0x48, 0x7F, 0x45, 0x45, 0x45, 0x7F +}; + +unsigned char gsv3_bseeds4[64] = { 0x10, 0x01, 0x18, 0x3C, 0x33, 0x29, 0x00, 0x06, +0x07, 0x02, 0x04, 0x13, 0x0B, 0x28, 0x15, 0x08, 0x1F, 0x3E, 0x0C, 0x05, +0x11, 0x1D, 0x1E, 0x27, 0x1A, 0x17, 0x38, 0x23, 0x2D, 0x37, 0x03, 0x2C, +0x2A, 0x1B, 0x22, 0x39, 0x25, 0x14, 0x24, 0x34, 0x20, 0x2F, 0x36, 0x3F, +0x3A, 0x0E, 0x0F, 0x2B, 0x32, 0x31, 0x21, 0x12, 0x26, 0x35, 0x30, 0x3B, +0x09, 0x19, 0x16, 0x0D, 0x0A, 0x2E, 0x3D, 0x1C +}; + +unsigned short gsv3_hseeds[4] = { 0x6C27, 0x1D38, 0x7FE1, 0x0000}; + +unsigned char gsv3_bseeds101[256] = { +0x0C, 0x02, 0xBB, 0xF8, 0x72, 0x1C, 0x9D, 0xC1, 0xA1, 0xF3, 0x99, 0xEA, 0x78, 0x2F, 0xAC, 0x9F, +0x40, 0x3D, 0xE8, 0xBF, 0xD8, 0x47, 0xC0, 0xC4, 0xED, 0xFE, 0xA6, 0x8C, 0xD0, 0xA8, 0x18, 0x9B, +0x65, 0x56, 0x71, 0x0F, 0x6F, 0x44, 0x6A, 0x3F, 0xF1, 0xD3, 0x2A, 0x7B, 0xF2, 0xCB, 0x6C, 0x0E, +0x03, 0x49, 0x77, 0x5E, 0xF7, 0xB2, 0x1F, 0x9A, 0x54, 0x13, 0x48, 0xB4, 0x01, 0x1B, 0x43, 0xFC, +0xAF, 0x09, 0xE1, 0x4F, 0xB1, 0x04, 0x46, 0xB9, 0xDE, 0x27, 0xB0, 0xFD, 0x57, 0xE3, 0x17, 0x29, +0xCF, 0x4A, 0x45, 0x53, 0x37, 0x5D, 0x38, 0x8E, 0xA5, 0xF4, 0xDD, 0x7E, 0x3A, 0x9E, 0xC6, 0x67, +0x2D, 0x61, 0x28, 0xE2, 0xAE, 0x39, 0xAD, 0x69, 0x82, 0x91, 0x08, 0xF0, 0x73, 0x96, 0x00, 0x11, +0xE6, 0x41, 0xFA, 0x75, 0x93, 0x1D, 0xCE, 0x07, 0xE9, 0x12, 0x25, 0x36, 0x51, 0x6E, 0x14, 0x59, +0x2E, 0x4B, 0x87, 0x52, 0xA9, 0xA4, 0xB5, 0xCA, 0x55, 0x31, 0x7D, 0x23, 0xFB, 0x21, 0x83, 0xD2, +0x5A, 0x42, 0xB3, 0xEE, 0xF9, 0x50, 0x24, 0x6B, 0xE0, 0x30, 0x16, 0x58, 0x86, 0xEF, 0x20, 0xA7, +0x7C, 0x06, 0x95, 0x79, 0x68, 0xC5, 0x80, 0x1A, 0xD6, 0x32, 0xB8, 0x8D, 0x6D, 0x60, 0x84, 0x2C, +0xA0, 0x4D, 0x98, 0x3B, 0x88, 0xBC, 0x34, 0x5F, 0x2B, 0x5B, 0xEC, 0xE4, 0xFF, 0x70, 0x4E, 0x26, +0x74, 0xCC, 0xC2, 0xDA, 0x8B, 0x4C, 0x0B, 0x85, 0xF6, 0xC9, 0xC7, 0xBA, 0x15, 0xCD, 0x8F, 0xDF, +0x1E, 0x81, 0xBE, 0x3C, 0xD4, 0x35, 0xC8, 0xA2, 0x62, 0x10, 0x05, 0x5C, 0x66, 0xBD, 0xD5, 0x3E, +0x76, 0x63, 0xD1, 0xA3, 0x64, 0xC3, 0xDB, 0xD7, 0xE5, 0xAA, 0x0D, 0xAB, 0x9C, 0x33, 0x7A, 0x90, +0xB6, 0xE7, 0xB7, 0x7F, 0x19, 0x97, 0x8A, 0x92, 0x22, 0x89, 0xEB, 0xD9, 0x0A, 0xDC, 0xF5, 0x94 +}; + + +u8 DecryptGS2v3(u32* address, u32* value, u8 ctrl) +{ + u32 command = *address & 0xFE000000; + u32 tmp = 0, tmp2 = 0, mask = 0, i = 0; + u8 bmask[4], flag; + u8 encFlag = (*address >> 25) & 0x7; + + if(ctrl > 0) + { + switch(ctrl) + { + case 2: + { + *address ^= (gsv3_hseeds[1] << 2); + *value ^= (gsv3_hseeds[1] << 13); + for(i = 0; i < 0x40; i++) + { + if(i < 32) + { + flag = (*value >> i) & 1; + } + else + { + flag = (*address >> (i - 32)) & 1; + } + + if(flag > 0) + { + if(gsv3_bseeds4[i] < 32) + { + tmp2 |= (1 << gsv3_bseeds4[i]); + } + else + { + tmp |= (1 << (gsv3_bseeds4[i] - 32)); + } + } + } + + *address = tmp ^ (gsv3_hseeds[2] << 3); + *value = tmp2 ^ gsv3_hseeds[2]; + break; + } + + case 4: + { + tmp = *address ^ (gsv3_hseeds[1] << 3); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *address = tmp ^ (gsv3_hseeds[2] << 16); + + tmp = *value ^ (gsv3_hseeds[1] << 9); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *value = tmp ^ (gsv3_hseeds[2] << 5); + break; + } + } + return 0; + } + + if(command >= 0x30000000 && command <= 0x6FFFFFFF) + { + if(encFlag == 1 || encFlag == 2) + { + ctrl = 2; + } + else if (encFlag == 3 || encFlag == 4) + { + ctrl = 4; + } + } + + switch(encFlag) + { + case 0: + { + break; + } + + case 1: + { + tmp = *address & 0x01FFFFFF; + tmp = tmp ^ (gsv3_hseeds[1] << 8); + mask = 0; + for(i = 0; i < 25; i++) + { + mask |= ((tmp & (1 << i)) >> i) << gsv3_bseeds2[i]; + } + tmp = mask ^ gsv3_hseeds[2]; + tmp |= command; + *address = tmp & 0xF1FFFFFF; + break; + } + + case 2: + { + if(encFlag == 2) + { + tmp = *address & 0x01FFFFFF; + *address = tmp ^ (gsv3_hseeds[1] << 1); + *value ^= (gsv3_hseeds[1] << 16); + tmp = 0; + tmp2 = 0; + for(i = 0; i < 0x39; i++) + { + if(i < 32) + { + flag = (*value >> i) & 1; + } + else + { + flag = (*address >> (i - 32)) & 1; + } + + if(flag > 0) + { + if(gsv3_bseeds3[i] < 32) + { + tmp2 |= (1 << gsv3_bseeds3[i]); + } + else + { + tmp |= (1 << (gsv3_bseeds3[i] - 32)); + } + } + } + *address = ((tmp ^ (gsv3_hseeds[2] << 8)) | command) & 0xF1FFFFFF; + *value = tmp2 ^ gsv3_hseeds[2]; + } + break; + } + + case 3: + { + tmp = *address ^ (gsv3_hseeds[1] << 8); + bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; + tmp = (tmp & 0xFFFF0000) ; + tmp |= (bmask[0] ^ (bmask[1] << 8)) ; + tmp ^= (gsv3_hseeds[2] << 4); + *address = tmp & 0xF1FFFFFF; + break; + } + + case 4: + { + tmp = *address ^ (gsv3_hseeds[1] << 8); + bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; + tmp = (tmp & 0xFFFF0000) ; + tmp |= (bmask[1] | (bmask[0] << 8)) ; + tmp ^= (gsv3_hseeds[2] << 4); + tmp2 = *address ^ (gsv3_hseeds[1] << 3); + *address = tmp & 0xF1FFFFFF; + tmp = *value ^ (gsv3_hseeds[1] << 9); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *value = tmp ^ (gsv3_hseeds[2] << 5); + break; + } + + case 5: + case 6: + case 7: + default: + break; + } + + return ctrl; + +} + +typedef struct +{ + unsigned int address, value; +}Cheat; + +int ParseCheats(char *cur, std::vector &Cheats, HWND hWnd) +{ + // Parse the text and put the cheats to the vector + while(*cur!=NULL){ + Cheat C; + + // if there is endline advance 2 chars + if(*cur==0x0d && *(cur+1)==0x0a) + cur+=2; + // check if new start is null + if(*cur==NULL) + break; + + // get address and value and insert in the vector + int ret = sscanf(cur, "%X %X", &C.address, &C.value); + if(ret != 2) + { + MessageBox(hWnd,"Code conversion is probably wrong.","Error",0); + return 0; + } + Cheats.insert(Cheats.end(), C); + cur+=17; + } + return 1; +} + + +// Callback for the GameShark2 v3-4 cheat dialog +BOOL CALLBACK AddGS(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + static HWND hParent; + + switch(uMsg) + { + + case WM_PAINT: + return FALSE; + case WM_INITDIALOG: + hParent=(HWND)lParam; + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDC_CONVERT: // Convert the code + { + std::vector Cheats; + char chepa[256]; + + // Set ready text to false + SetWindowText(GetDlgItem(hWnd,IDC_READY), "0"); + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); + + // Parsing the cheats + ParseCheats(chepa, Cheats, hWnd); + + int control = 0; + *chepa=0; + // Decrypt multiline code + for(unsigned int i=0;i Cheats; + char ready[2], chepa[256]; + + // Check if we are ready to add first + GetWindowText(GetDlgItem(hWnd,IDC_READY),ready,2); + if(ready[0] == '0') + { + MessageBox(hWnd, "First convert the code.", "Error", 0); + break; + } + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_CONVERTEDCODE),chepa,256); + + // Parsing the cheats + int ret = ParseCheats(chepa, Cheats, hWnd); + + if(ret == 1) + { + // Adding cheats + for(unsigned int i=0;i Cheats; + char chepa[256]; + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); + + if(strlen(chepa) == 0) + { + MessageBox(hWnd, "Add some cheats.", "Error", 0); + break; + } + + // Parsing the cheats + int ret = ParseCheats(chepa, Cheats, hWnd); + + if(ret == 1) + { + // Adding cheats + for(unsigned int i=0;i +#include +#include +#include + +#include + +#include "PS2Etypes.h" + +extern "C" { +#include "windows/resource.h" +#include "PS2Edefs.h" +#include "Memory.h" + +#include "cheats.h" +#include "../../patch.h" +} + +class result +{ +public: + u32 address; + result(u32 addr): + address(addr) + { + } +}; + +char *sizenames[4]={"char","short","word","double"}; + +char mtext[100]; + +HINSTANCE pInstance; + +int TSelect; + +bool Unsigned; +int Source; +int Compare; +int Size; +int CompareTo; + +u64 CompareValue; + +std::vector results; + +//int mresults; + +bool FirstSearch; + +bool FirstShow; + +char olds[0x02000000]; + +char tn[100]; +char to[100]; +char tv[100]; + +#ifdef PCSX2_VIRTUAL_MEM +u8 *mptr[2]={PS2MEM_BASE,PS2MEM_PSX}; +#else +char *mptr[2]; +extern "C" extern s8 *psxM; +#endif + +int msize[2]={0x02000000,0x00200000}; + +int lticks; + +HWND hWndFinder; + +LVCOLUMN cols[3]={ + {LVCF_TEXT|LVCF_WIDTH,0,60,"Address",0,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"Old V",1,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"New V",2,0,0} +}; + +LVITEM item[3]={ + {LVIF_TEXT|LVIF_STATE,0,0,0,0,tn,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,1,0,0,to,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,2,0,0,tv,0,0,0,0} +}; + +void DoEvents() +{ + MSG msg; + while(PeekMessage(&msg,0,0,0,PM_REMOVE)!=0) + DispatchMessage(&msg); +} + +void UpdateStatus() +{ + int nticks=GetTickCount(); + if((nticks-lticks)>250) + { + int nshown=ListView_GetItemCount(GetDlgItem(hWndFinder,IDC_RESULTS)); + sprintf(mtext,"%d matches found (%d shown).",results.size(),nshown); + SetWindowText(GetDlgItem(hWndFinder,IDC_MATCHES),mtext); + lticks=nticks; + DoEvents(); + } +} + +void SearchReset() +{ + memcpy(olds,mptr[Source],msize[Source]); + FirstSearch=true; + + results.clear(); + +} + +int AddResult(u32 addr) +{ + result nr=result(addr); + results.push_back(nr); + return 1; +} + +bool CompareAny(u64 val,u64 cto) +{ + + if(Unsigned) + { + switch(Size) + { + case 0: + val=(u8)val; + cto=(u8)cto; + break; + case 1: + val=(u16)val; + cto=(u16)cto; + break; + case 2: + val=(u32)val; + cto=(u32)cto; + break; + case 3: + break; + default:return false; + } + switch(Compare) + { + case 0: /* EQ */ + return val==cto; + case 1: /* GT */ + return val> cto; + case 2: /* LT */ + return val< cto; + case 3: /* GE */ + return val>=cto; + case 4: /* LE */ + return val<=cto; + default:/* NE */ + return val!=cto; + } + } + else + { + switch(Size) + { + case 0: + val=(s8)val; + cto=(s8)cto; + break; + case 1: + val=(s16)val; + cto=(s16)cto; + break; + case 2: + val=(s32)val; + cto=(s32)cto; + break; + case 3: + break; + default:return false; + } + switch(Compare) + { + case 0: /* EQ */ + return (s64)val==(s64)cto; + case 1: /* GT */ + return (s64)val> (s64)cto; + case 2: /* LT */ + return (s64)val< (s64)cto; + case 3: /* GE */ + return (s64)val>=(s64)cto; + case 4: /* LE */ + return (s64)val<=(s64)cto; + default:/* NE */ + return (s64)val!=(s64)cto; + } + } +} + +void SearchFirst() +{ + int MSize=1< oldr=std::vector(results); + + results.clear(); + + for(i=0;i", + Source?"IOP":"EE", + tn, + sizenames[Size]); + + SetWindowText(GetDlgItem(hWnd,IDC_ADDR),tn); + SetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv); + SetWindowText(GetDlgItem(hWnd,IDC_NAME),to); + + break; + } + } + + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDOK: + GetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv,100); + value=_atoi64(tv); + AddPatch(1,Source+1,results[Selected].address,Size+1,value); + + EndDialog(hWnd,1); + break; + + + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void AddCheat(HINSTANCE hInstance, HWND hParent) +{ + INT_PTR retret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_ADD),hParent,(DLGPROC)AddCheatProc,(LPARAM)hParent); +} + +void AddResults(HWND hWnd) +{ + int i,mresults; + u64 sizemask=(1<<(1<32768) { + mresults=32768; + } + + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); + + for(i=0;i32768) { + sprintf(mtext,"%d matches found (32768 shown).",results.size()); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); + } + else { + sprintf(mtext,"%d matches found.",results.size()); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); + } + +} + +BOOL CALLBACK FinderProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + LRESULT lStyle; + + switch(uMsg) + { + + case WM_PAINT: + INIT_CHECK(IDC_UNSIGNED,Unsigned); + return FALSE; + case WM_INITDIALOG: + +#ifndef PCSX2_VIRTUAL_MEM + mptr[0]=(char*)psM; + mptr[1]=psxM; +#endif + + + hWndFinder=hWnd; + + ENABLE_CONTROL(IDC_VALUE,false); + + GROUP_INIT(IDC_EE,Source); + GROUP_SELECT(IDC_EE); + GROUP_SELECT(IDC_IOP); + + GROUP_INIT(IDC_OLD,CompareTo); + GROUP_SELECT(IDC_OLD); + GROUP_SELECT(IDC_SET); + ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); + + GROUP_INIT(IDC_EQ,Compare); + GROUP_SELECT(IDC_EQ); + GROUP_SELECT(IDC_GT); + GROUP_SELECT(IDC_LT); + GROUP_SELECT(IDC_GE); + GROUP_SELECT(IDC_LE); + GROUP_SELECT(IDC_NE); + + GROUP_INIT(IDC_8B,Size); + GROUP_SELECT(IDC_8B); + GROUP_SELECT(IDC_16B); + GROUP_SELECT(IDC_32B); + GROUP_SELECT(IDC_64B); + + INIT_CHECK(IDC_UNSIGNED,Unsigned); + + //Listview Init + lStyle = SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); + + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),0,&cols[0]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),1,&cols[1]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),2,&cols[2]); + + if(FirstShow) + { + SearchReset(); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); + FirstShow=false; + } + else { + AddResults(hWnd); + } + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDC_ADD: + AddCheat(pInstance,hWnd); + break; + + case IDC_RESET: + ENABLE_CONTROL(IDC_EE, true); + ENABLE_CONTROL(IDC_IOP, true); + ENABLE_CONTROL(IDC_LRESULTS,true); + ENABLE_CONTROL(IDC_STATUS, true); + ENABLE_CONTROL(IDC_UNSIGNED,true); + ENABLE_CONTROL(IDC_8B, true); + ENABLE_CONTROL(IDC_16B, true); + ENABLE_CONTROL(IDC_32B, true); + ENABLE_CONTROL(IDC_64B, true); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); + SearchReset(); + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); + break; + + case IDC_SEARCH: + GetWindowText(GetDlgItem(hWnd,IDC_VALUE),mtext,100); + CompareValue=atoi(mtext); + ENABLE_CONTROL(IDC_SEARCH, false); + ENABLE_CONTROL(IDC_RESET, false); + ENABLE_CONTROL(IDC_ADD, false); + ENABLE_CONTROL(IDCANCEL, false); + if(FirstSearch) { + ENABLE_CONTROL(IDC_EE, false); + ENABLE_CONTROL(IDC_IOP, false); + ENABLE_CONTROL(IDC_LRESULTS,false); + ENABLE_CONTROL(IDC_STATUS, false); + ENABLE_CONTROL(IDC_UNSIGNED,false); + ENABLE_CONTROL(IDC_8B, false); + ENABLE_CONTROL(IDC_16B, false); + ENABLE_CONTROL(IDC_32B, false); + ENABLE_CONTROL(IDC_64B, false); + SearchFirst(); + } + else SearchMore(); + + AddResults(hWnd); + + memcpy(olds,mptr[Source],msize[Source]); + + ENABLE_CONTROL(IDC_SEARCH, true); + ENABLE_CONTROL(IDC_RESET, true); + ENABLE_CONTROL(IDC_ADD, true); + ENABLE_CONTROL(IDCANCEL, true); + + break; + + HANDLE_CHECK(IDC_UNSIGNED,Unsigned); + + HANDLE_GROUP_ITEM(IDC_EE); + HANDLE_GROUP_ITEM(IDC_IOP); + BEGIN_GROUP_HANDLER(IDC_EE,Source); + GROUP_SELECT(IDC_EE); + GROUP_SELECT(IDC_IOP); + break; + + HANDLE_GROUP_ITEM(IDC_OLD); + HANDLE_GROUP_ITEM(IDC_SET); + BEGIN_GROUP_HANDLER(IDC_OLD,CompareTo); + GROUP_SELECT(IDC_OLD); + GROUP_SELECT(IDC_SET); + ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); + break; + + HANDLE_GROUP_ITEM(IDC_EQ); + HANDLE_GROUP_ITEM(IDC_GT); + HANDLE_GROUP_ITEM(IDC_LT); + HANDLE_GROUP_ITEM(IDC_GE); + HANDLE_GROUP_ITEM(IDC_LE); + HANDLE_GROUP_ITEM(IDC_NE); + BEGIN_GROUP_HANDLER(IDC_EQ,Compare); + GROUP_SELECT(IDC_EQ); + GROUP_SELECT(IDC_GT); + GROUP_SELECT(IDC_LT); + GROUP_SELECT(IDC_GE); + GROUP_SELECT(IDC_LE); + GROUP_SELECT(IDC_NE); + break; + + HANDLE_GROUP_ITEM(IDC_8B); + HANDLE_GROUP_ITEM(IDC_16B); + HANDLE_GROUP_ITEM(IDC_32B); + HANDLE_GROUP_ITEM(IDC_64B); + BEGIN_GROUP_HANDLER(IDC_8B,Size); + GROUP_SELECT(IDC_8B); + GROUP_SELECT(IDC_16B); + GROUP_SELECT(IDC_32B); + GROUP_SELECT(IDC_64B); + break; + + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void ShowFinder(HINSTANCE hInstance, HWND hParent) +{ + INT_PTR ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_FINDER),hParent,(DLGPROC)FinderProc,1); +} diff --git a/pcsx2/windows/cheats/cheats.h b/pcsx2/windows/cheats/cheats.h new file mode 100644 index 0000000000..80040f8002 --- /dev/null +++ b/pcsx2/windows/cheats/cheats.h @@ -0,0 +1,36 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef CHEATS_H_INCLUDED +#define CHEATS_H_INCLUDED + +#ifndef __cplusplus +typedef enum ebool +{ + false, + true +} bool; +#endif + +extern HINSTANCE pInstance; +extern bool FirstShow; + +void AddCheat(HINSTANCE hInstance, HWND hParent); +void ShowFinder(HINSTANCE hInstance, HWND hParent); +void ShowCheats(HINSTANCE hInstance, HWND hParent); + +#endif//CHEATS_H_INCLUDED diff --git a/pcsx2/windows/ini.c b/pcsx2/windows/ini.c new file mode 100644 index 0000000000..9b588218d2 --- /dev/null +++ b/pcsx2/windows/ini.c @@ -0,0 +1,179 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* +15-09-2004 : file rewriten for work with inis (shadow) +*/ + +#include +#include +#include +#include "Common.h" +#include "win32.h" +#include + +#include "Paths.h" + +int LoadConfig() { + FILE *fp; + +#ifdef ENABLE_NLS + char text[256]; + extern int _nl_msg_cat_cntr; +#endif + PcsxConfig *Conf = &Config; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)gApp.hInstance), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return -1; + strcpy(szTemp, "\\" CONFIG_DIR "\\pcsx2.ini"); + fp=fopen(CONFIG_DIR "\\pcsx2.ini","rt");//check if pcsx2.ini really exists + if (!fp) + { + CreateDirectory(CONFIG_DIR,NULL); + return -1; + } + fclose(fp); + //interface + GetPrivateProfileString("Interface", "Bios", NULL, szValue, 256, szIniFile); + strcpy(Conf->Bios, szValue); + GetPrivateProfileString("Interface", "Lang", NULL, szValue, 256, szIniFile); + strcpy(Conf->Lang, szValue); + GetPrivateProfileString("Interface", "Ps2Out", NULL, szValue, 20, szIniFile); + Conf->PsxOut = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Interface", "ThPriority", NULL, szValue, 20, szIniFile); + Conf->ThPriority = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Interface", "PluginsDir", NULL, szValue, 256, szIniFile); + strcpy(Conf->PluginsDir, szValue); + GetPrivateProfileString("Interface", "BiosDir", NULL, szValue, 256, szIniFile); + strcpy(Conf->BiosDir, szValue); + GetPrivateProfileString("Interface", "Mcd1", NULL, szValue, 256, szIniFile); + strcpy(Conf->Mcd1, szValue); + GetPrivateProfileString("Interface", "Mcd2", NULL, szValue, 256, szIniFile); + strcpy(Conf->Mcd2, szValue); + Config.CustomFps=GetPrivateProfileInt("Interface", "CustomFps", 0, szIniFile); + //plugins + GetPrivateProfileString("Plugins", "GS", NULL, szValue, 256, szIniFile); + strcpy(Conf->GS, szValue); + GetPrivateProfileString("Plugins", "SPU2", NULL, szValue, 256, szIniFile); + strcpy(Conf->SPU2, szValue); + GetPrivateProfileString("Plugins", "CDVD", NULL, szValue, 256, szIniFile); + strcpy(Conf->CDVD, szValue); + GetPrivateProfileString("Plugins", "PAD1", NULL, szValue, 256, szIniFile); + strcpy(Conf->PAD1, szValue); + GetPrivateProfileString("Plugins", "PAD2", NULL, szValue, 256, szIniFile); + strcpy(Conf->PAD2, szValue); + GetPrivateProfileString("Plugins", "DEV9", NULL, szValue, 256, szIniFile); + strcpy(Conf->DEV9, szValue); + GetPrivateProfileString("Plugins", "USB", NULL, szValue, 256, szIniFile); + strcpy(Conf->USB, szValue); + GetPrivateProfileString("Plugins", "FW", NULL, szValue, 256, szIniFile); + strcpy(Conf->FW, szValue); + //cpu + GetPrivateProfileString("Cpu Options", "Options", NULL, szValue, 20, szIniFile); + Conf->Options= (u32)strtoul(szValue, NULL, 10); + + //Misc + GetPrivateProfileString("Misc", "Patch", NULL, szValue, 20, szIniFile); + Conf->Patch = strtoul(szValue, NULL, 10); + +#ifdef PCSX2_DEVBUILD + GetPrivateProfileString("Misc", "varLog", NULL, szValue, 20, szIniFile); + varLog = strtoul(szValue, NULL, 16); +#endif + GetPrivateProfileString("Misc", "Hacks", NULL, szValue, 20, szIniFile); + Conf->Hacks = strtoul(szValue, NULL, 16); + +#ifdef ENABLE_NLS + sprintf(text, "LANGUAGE=%s", Conf->Lang); +#ifdef _WIN32 + gettext_putenv(text); +#else + putenv(text); +#endif +#endif + + return 0; +} + +///////////////////////////////////////////////////////// + +void SaveConfig() { + + PcsxConfig *Conf = &Config; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)gApp.hInstance), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\" CONFIG_DIR "\\pcsx2.ini"); + //interface + sprintf(szValue,"%s",Conf->Bios); + WritePrivateProfileString("Interface","Bios",szValue,szIniFile); + sprintf(szValue,"%s",Conf->Lang); + WritePrivateProfileString("Interface","Lang",szValue,szIniFile); + sprintf(szValue,"%s",Conf->PluginsDir); + WritePrivateProfileString("Interface","PluginsDir",szValue,szIniFile); + sprintf(szValue,"%s",Conf->BiosDir); + WritePrivateProfileString("Interface","BiosDir",szValue,szIniFile); + sprintf(szValue,"%u",Conf->PsxOut); + WritePrivateProfileString("Interface","Ps2Out",szValue,szIniFile); + sprintf(szValue,"%u",Conf->ThPriority); + WritePrivateProfileString("Interface","ThPriority",szValue,szIniFile); + sprintf(szValue,"%s",Conf->Mcd1); + WritePrivateProfileString("Interface","Mcd1",szValue,szIniFile); + sprintf(szValue,"%s",Conf->Mcd2); + WritePrivateProfileString("Interface","Mcd2",szValue,szIniFile); + sprintf(szValue,"%d",Conf->CustomFps); + WritePrivateProfileString("Interface", "CustomFps", szValue, szIniFile); + //plugins + sprintf(szValue,"%s",Conf->GS); + WritePrivateProfileString("Plugins","GS",szValue,szIniFile); + sprintf(szValue,"%s",Conf->SPU2); + WritePrivateProfileString("Plugins","SPU2",szValue,szIniFile); + sprintf(szValue,"%s",Conf->CDVD); + WritePrivateProfileString("Plugins","CDVD",szValue,szIniFile); + sprintf(szValue,"%s",Conf->PAD1); + WritePrivateProfileString("Plugins","PAD1",szValue,szIniFile); + sprintf(szValue,"%s",Conf->PAD2); + WritePrivateProfileString("Plugins","PAD2",szValue,szIniFile); + sprintf(szValue,"%s",Conf->DEV9); + WritePrivateProfileString("Plugins","DEV9",szValue,szIniFile); + sprintf(szValue,"%s",Conf->USB); + WritePrivateProfileString("Plugins","USB",szValue,szIniFile); + sprintf(szValue,"%s",Conf->FW); + WritePrivateProfileString("Plugins","FW",szValue,szIniFile); + //cpu + sprintf(szValue,"%u", Conf->Options); + WritePrivateProfileString("Cpu Options","Options",szValue,szIniFile); + //Misc + sprintf(szValue,"%u",Conf->Patch); + WritePrivateProfileString("Misc","Patch",szValue,szIniFile); + sprintf(szValue,"%x",varLog); + WritePrivateProfileString("Misc","varLog",szValue,szIniFile); + sprintf(szValue,"%u",Conf->Hacks); + WritePrivateProfileString("Misc","Hacks",szValue,szIniFile); + + +} + diff --git a/pcsx2/windows/libs/gnu_gettext.lib b/pcsx2/windows/libs/gnu_gettext.lib new file mode 100644 index 0000000000000000000000000000000000000000..8b3885a56b2f9d31a261c89fbd0e31d15fc51c14 GIT binary patch literal 2916 zcmcIm%}*0S6#s1t6sieCjfr2dB!s{PNNJ%MHH)HwP(D)1#miW_1)4xhuow>{UOD)e zcr=_1C;tEshIsPefwS?z4d2_H*-nSjr35CKop~QSZ{GX8H#7au^1Fr27x7WMzD=dm zQxlV^#6&&Y9+UL=cv8;Z#Q}5!(LtcY0b=_==ds_rW&y7s(nvktEBgVB+)ud+F}JY1 zl+B5m*DJ5GbIZA9XHiX1+<#N( zZ&?ITv(`hx2nds~MvAP4(uZe8SYaqbL%!h8^YZlDhcqK+!%qAzB>!0 z!fxe#WxZ+-Wryv|+~T|^H9xnB!GH1!J}xmY;O!pIFa@Vj+1{Z|pY*li>`d8IX!0&2 zP`*2Wx9?5G@w{YPQN>BJ4lxkuq-q@I5Aa7eULANYDIOwtOW!M3^tDz-B9#j6jf@rX zD&w2CN8Tx{Mw#P!qS{BxoN>kF%=w}SIdbOQTt-|5<0rI}3vaKuku{;GN+La}#m+xf zevt(q@y4y7bc;@VHvo2F&Uu}vjpXl;Ja zaLr~cKDBMK#D|gjZZNQeL5E_QR8SiB9+54Mr>I?I#?olnw`A~$tM~08+2M0W1UIE= z%Amu&QpIg}^?J3lK4TO7^Zk!*F$rj%vLVHS>w*CX+ CYG_^n literal 0 HcmV?d00001 diff --git a/pcsx2/windows/libs/libintlmsc.h b/pcsx2/windows/libs/libintlmsc.h new file mode 100644 index 0000000000..25a96a998d --- /dev/null +++ b/pcsx2/windows/libs/libintlmsc.h @@ -0,0 +1,116 @@ +/* This file is part of a Windows32 DLL Interface to: + GNU gettext - internationalization aids + Copyright (C) 1996, 1998 Free Software Foundation, Inc. + + This file was written by Franco Bez + +This program 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, 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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. */ + +/* REPLACEMENT FOR ORIGINAL LIBINTL.H for use with Windows32 */ + +#if !defined(__LIBINTL_H_INCLUDED) +#define __LIBINTL_H_INCLUDED + +#if defined(__cplusplus) +extern "C" { +#endif + +/* See if we allready know what we want static or dll linkage or none at all*/ +#if defined DONT_USE_GETTEXT || ( defined USE_SAFE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) || ( defined USE_GETTEXT_DLL && defined USE_SAFE_GETTEXT_DLL ) || ( defined USE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) +/* TWO IS HARDLY POSSIBLE */ +#undef USE_GETTEXT_DLL +#undef USE_GETTEXT_STATIC +#undef USE_SAFE_GETTEXT_DLL +#endif /* MORE THAN ONE - OR NONE AT ALL */ + +#if !defined USE_GETTEXT_DLL && !defined USE_SAFE_GETTEXT_DLL && !defined USE_GETTEXT_STATIC && !defined DONT_USE_GETTEXT +/* not explicitly defined so try to guess it - + if GNUC is used - we use static linkage by default + because at the moment this is the only plattform + for which a static lib is available + else we use the DLL built with GNUC */ +# if defined __GNUC__ +# define USE_GETTEXT_STATIC +# else +# define USE_GETTEXT_DLL +# endif /* __GNUC__ */ +#endif /* NONE */ + +/* NOW ONLY ONE OF + DONT_USE_GETTEXT , USE_GETTEXT_DLL , USE_SAFE_GETTEXT_DLL , USE_GETTEXT_STATIC + IS DEFINED */ + +#if defined USE_GETTEXT_DLL +/* exported functions in DLL gnu_gettext.dll + you should link with import library + -lgnu_gettext (for mingw32) OR gnu_gettext.lib (MSVC) */ +__declspec(dllimport) char *gettext(const char *__msgid); +__declspec(dllimport) char *dgettext(const char *__domainname,const char *__msgid); +__declspec(dllimport) char *dcgettext(const char *__domainname,const char *__msgid, int __category); +__declspec(dllimport) char *textdomain(const char *__domainname); +__declspec(dllimport) char *bindtextdomain(const char *__domainname,const char *__dirname); +/* calling _putenv from within the DLL */ +__declspec(dllexport) int gettext_putenv(const char *envstring); +#endif /* DLL */ + +#if defined USE_SAFE_GETTEXT_DLL +/* Uses DLL gnu_gettext.dll ONLY if present, otherwise NO translation will take place + you should link with "safe_gettext_dll.o -lstdc++" see README for safe_gettext_dll for Details */ +/* The safe gettext functions */ +extern char *gettext(const char *szMsgId); +extern char *dgettext(const char *szDomain,const char *szMsgId); +extern char *dcgettext(const char *szDomain,const char *szMsgId,int iCategory); +extern char *textdomain(const char *szDomain); +extern char *bindtextdomain(const char *szDomain,const char *szDirectory); +/* calling _putenv from within the DLL */ +extern int gettext_putenv(const char *envstring); +#endif /* SAFE DLL */ + +#if defined USE_GETTEXT_STATIC +/* exported functions in static library libintl.a + and supporting macros + you should link with -lintl (mingw32) */ +extern char *gettext__(const char *__msgid); +extern char *dgettext__(const char *__domainname,const char *__msgid); +extern char *dcgettext__(const char *__domainname,const char *__msgid, int __category); +extern char *textdomain__(const char *__domainname); +extern char *bindtextdomain__(const char *__domainname,const char *__dirname); +#define gettext(szMsgId) gettext__(szMsgId) +#define dgettext(szDomain,szMsgId) dgettext__(szDomain,szMsgId) +#define dcgettext(szDomain,szMsgId,iCategory) dcgettext__(szDomain,szMsgId,iCategory) +#define textdomain(szDomain) textdomain__(szDomain) +#define bindtextdomain(szDomain,szDirectory) bindtextdomain__(szDomain,szDirectory) +// dummy - for static linkage - calling _putenv from within the DLL +#define gettext_putenv(a) _putenv(a) +#endif /* STATIC */ + +#if defined DONT_USE_GETTEXT +/* DON'T USE GETTEXT AT ALL + MAKROS TO MAKE CODE COMPILE WELL, BUT GETTEXT WILL NOT BE USESD +*/ +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) ((char *) Domainname) +# define bindtextdomain(Domainname, Dirname) ((char *) Dirname) +// dummy - for static linkage - calling _putenv from within the DLL +# define gettext_putenv(a) _putenv(a) +#endif /* DON'T USE AT ALL */ + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /*!defined(__LIBINTL_H_INCLUDED)*/ diff --git a/pcsx2/windows/libs/pthread.h b/pcsx2/windows/libs/pthread.h new file mode 100644 index 0000000000..e206de0a8c --- /dev/null +++ b/pcsx2/windows/libs/pthread.h @@ -0,0 +1,1368 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,7,0,0 +#define PTW32_VERSION_STRING "2, 7, 0, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#ifndef RC_INVOKED + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifndef NEED_FTIME +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include +#endif /* HAVE_SIGNAL_H */ + +#include +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#ifndef ENOSYS +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#ifndef EDEADLK +# ifdef EDEADLOCK +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200112L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200112L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200112L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200112L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/pcsx2/windows/libs/pthreadVC2.lib b/pcsx2/windows/libs/pthreadVC2.lib new file mode 100644 index 0000000000000000000000000000000000000000..b447a8b71ec31903598669991dac05f24ace9f25 GIT binary patch literal 29280 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 literal 0 HcmV?d00001 diff --git a/pcsx2/windows/libs/sched.h b/pcsx2/windows/libs/sched.h new file mode 100644 index 0000000000..a72c6a8f62 --- /dev/null +++ b/pcsx2/windows/libs/sched.h @@ -0,0 +1,178 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/pcsx2/windows/libs/semaphore.h b/pcsx2/windows/libs/semaphore.h new file mode 100644 index 0000000000..20e822c3d5 --- /dev/null +++ b/pcsx2/windows/libs/semaphore.h @@ -0,0 +1,166 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/pcsx2/windows/mingw/Makefile.win b/pcsx2/windows/mingw/Makefile.win new file mode 100644 index 0000000000..7449952180 --- /dev/null +++ b/pcsx2/windows/mingw/Makefile.win @@ -0,0 +1,348 @@ +# Project: pcsx2 +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//pcsx2_private.res +OBJ = Obj//AboutDlg.o Obj//ConfigDlg.o Obj//CpuDlg.o Obj//Debugger.o Obj//DebugMemory.o Obj//Debugreg.o Obj//ini.o Obj//McdsDlg.o Obj//PatchBrowser.o Obj//RDebugger.o Obj//WinMain.o Obj//Idct.o Obj//IPU.o Obj//Mpeg.o Obj//yuv2rgb.o Obj//cpuopsDebug.o Obj//DisR3000A.o Obj//DisR3000asm.o Obj//DisR5900.o Obj//DisR5900asm.o Obj//DisVU0Micro.o Obj//DisVU1Micro.o Obj//adler32.o Obj//compress.o Obj//crc32.o Obj//deflate.o Obj//gzio.o Obj//infback.o Obj//inffast.o Obj//inflate.o Obj//inftrees.o Obj//trees.o Obj//uncompr.o Obj//zutil.o Obj//iR5900Arit.o Obj//iR5900AritImm.o Obj//iR5900Branch.o Obj//iR5900Jump.o Obj//iR5900LoadStore.o Obj//iR5900Move.o Obj//iR5900MultDiv.o Obj//iR5900Shift.o Obj//iCP0.o Obj//iFPU.o Obj//iMMI.o Obj//iR3000A.o Obj//iR5900.o Obj//iVU0micro.o Obj//iVU1micro.o Obj//iVUmicro.o Obj//recCOP2.o Obj//ix86.o Obj//ix86_3dnow.o Obj//ix86_cpudetect.o Obj//ix86_fpu.o Obj//ix86_mmx.o Obj//ix86_sse.o Obj//CDVD.o Obj//CDVDiso.o Obj//CDVDisodrv.o Obj//COP0.o Obj//Counters.o Obj//Decode_XA.o Obj//Elfheader.o Obj//FiFo.o Obj//FPU.o Obj//GS.o Obj//Gte.o Obj//Hw.o Obj//Interpreter.o Obj//InterTables.o Obj//Mdec.o Obj//Memory.o Obj//Misc.o Obj//MMI.o Obj//Patch.o Obj//Plugins.o Obj//PsxBios.o Obj//PsxCounters.o Obj//PsxDma.o Obj//PsxGPU.o Obj//PsxHw.o Obj//PsxInterpreter.o Obj//PsxMem.o Obj//PsxSio2.o Obj//R3000A.o Obj//R5900.o Obj//Sif.o Obj//Sio.o Obj//SPR.o Obj//Stats.o Obj//Vif.o Obj//VifDma.o Obj//VU0.o Obj//VU0micro.o Obj//VU1micro.o Obj//VUflags.o Obj//VUops.o Obj//Cache.o Obj//CdRom.o Obj//deci2.o Obj//deci2_dbgp.o Obj//deci2_dcmp.o Obj//deci2_iloadp.o Obj//deci2_netmp.o Obj//deci2_ttyp.o $(RES) +LINKOBJ = Obj//AboutDlg.o Obj//ConfigDlg.o Obj//CpuDlg.o Obj//Debugger.o Obj//DebugMemory.o Obj//Debugreg.o Obj//ini.o Obj//McdsDlg.o Obj//PatchBrowser.o Obj//RDebugger.o Obj//WinMain.o Obj//Idct.o Obj//IPU.o Obj//Mpeg.o Obj//yuv2rgb.o Obj//cpuopsDebug.o Obj//DisR3000A.o Obj//DisR3000asm.o Obj//DisR5900.o Obj//DisR5900asm.o Obj//DisVU0Micro.o Obj//DisVU1Micro.o Obj//adler32.o Obj//compress.o Obj//crc32.o Obj//deflate.o Obj//gzio.o Obj//infback.o Obj//inffast.o Obj//inflate.o Obj//inftrees.o Obj//trees.o Obj//uncompr.o Obj//zutil.o Obj//iR5900Arit.o Obj//iR5900AritImm.o Obj//iR5900Branch.o Obj//iR5900Jump.o Obj//iR5900LoadStore.o Obj//iR5900Move.o Obj//iR5900MultDiv.o Obj//iR5900Shift.o Obj//iCP0.o Obj//iFPU.o Obj//iMMI.o Obj//iR3000A.o Obj//iR5900.o Obj//iVU0micro.o Obj//iVU1micro.o Obj//iVUmicro.o Obj//recCOP2.o Obj//ix86.o Obj//ix86_3dnow.o Obj//ix86_cpudetect.o Obj//ix86_fpu.o Obj//ix86_mmx.o Obj//ix86_sse.o Obj//CDVD.o Obj//CDVDiso.o Obj//CDVDisodrv.o Obj//COP0.o Obj//Counters.o Obj//Decode_XA.o Obj//Elfheader.o Obj//FiFo.o Obj//FPU.o Obj//GS.o Obj//Gte.o Obj//Hw.o Obj//Interpreter.o Obj//InterTables.o Obj//Mdec.o Obj//Memory.o Obj//Misc.o Obj//MMI.o Obj//Patch.o Obj//Plugins.o Obj//PsxBios.o Obj//PsxCounters.o Obj//PsxDma.o Obj//PsxGPU.o Obj//PsxHw.o Obj//PsxInterpreter.o Obj//PsxMem.o Obj//PsxSio2.o Obj//R3000A.o Obj//R5900.o Obj//Sif.o Obj//Sio.o Obj//SPR.o Obj//Stats.o Obj//Vif.o Obj//VifDma.o Obj//VU0.o Obj//VU0micro.o Obj//VU1micro.o Obj//VUflags.o Obj//VUops.o Obj//Cache.o Obj//CdRom.o Obj//deci2.o Obj//deci2_dbgp.o Obj//deci2_dcmp.o Obj//deci2_iloadp.o Obj//deci2_netmp.o Obj//deci2_ttyp.o $(RES) +LIBS = -mwindows -Wall -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -s +INCS = -I"../../" -I"C:/Documents and Settings/shadow/Desktop/Npcsx2" -I"../../" -I"../../zlib" -I"../../DebugTools" -I"../../IPU" -I"../../x86" -I"../../ix86-32" -I"../" +CXXINCS = -I"../../" -I"../../zlib" -I"../../DebugTools" -I"../../IPU" -I"../../x86" -I"../../ix86-32" -I"../" +BIN = pcsx2.exe +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -D__WIN32__ -D__MINGW32__ -O3 -fomit-frame-pointer -finline-functions -fno-exceptions -ffast-math -fno-strict-aliasing -m128bit-long-double -mfpmath=sse -march=athlon64 +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before pcsx2.exe all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +$(BIN): $(OBJ) + $(CC) $(LINKOBJ) -o "pcsx2.exe" $(LIBS) + +Obj//AboutDlg.o: ../AboutDlg.c + $(CC) -c ../AboutDlg.c -o Obj//AboutDlg.o $(CFLAGS) + +Obj//ConfigDlg.o: ../ConfigDlg.c + $(CC) -c ../ConfigDlg.c -o Obj//ConfigDlg.o $(CFLAGS) + +Obj//CpuDlg.o: ../CpuDlg.c + $(CC) -c ../CpuDlg.c -o Obj//CpuDlg.o $(CFLAGS) + +Obj//Debugger.o: ../Debugger.c + $(CC) -c ../Debugger.c -o Obj//Debugger.o $(CFLAGS) + +Obj//DebugMemory.o: ../DebugMemory.c + $(CC) -c ../DebugMemory.c -o Obj//DebugMemory.o $(CFLAGS) + +Obj//Debugreg.o: ../Debugreg.c + $(CC) -c ../Debugreg.c -o Obj//Debugreg.o $(CFLAGS) + +Obj//ini.o: ../ini.c + $(CC) -c ../ini.c -o Obj//ini.o $(CFLAGS) + +Obj//McdsDlg.o: ../McdsDlg.c + $(CC) -c ../McdsDlg.c -o Obj//McdsDlg.o $(CFLAGS) + +Obj//PatchBrowser.o: ../PatchBrowser.c + $(CC) -c ../PatchBrowser.c -o Obj//PatchBrowser.o $(CFLAGS) + +Obj//RDebugger.o: ../RDebugger.c + $(CC) -c ../RDebugger.c -o Obj//RDebugger.o $(CFLAGS) + +Obj//WinMain.o: ../WinMain.c + $(CC) -c ../WinMain.c -o Obj//WinMain.o $(CFLAGS) + +Obj//Idct.o: ../../IPU/Idct.c + $(CC) -c ../../IPU/Idct.c -o Obj//Idct.o $(CFLAGS) + +Obj//IPU.o: ../../IPU/IPU.c + $(CC) -c ../../IPU/IPU.c -o Obj//IPU.o $(CFLAGS) + +Obj//Mpeg.o: ../../IPU/Mpeg.c + $(CC) -c ../../IPU/Mpeg.c -o Obj//Mpeg.o $(CFLAGS) + +Obj//yuv2rgb.o: ../../IPU/yuv2rgb.c + $(CC) -c ../../IPU/yuv2rgb.c -o Obj//yuv2rgb.o $(CFLAGS) + +Obj//cpuopsDebug.o: ../../DebugTools/cpuopsDebug.c + $(CC) -c ../../DebugTools/cpuopsDebug.c -o Obj//cpuopsDebug.o $(CFLAGS) + +Obj//DisR3000A.o: ../../DebugTools/DisR3000A.c + $(CC) -c ../../DebugTools/DisR3000A.c -o Obj//DisR3000A.o $(CFLAGS) + +Obj//DisR3000asm.o: ../../DebugTools/DisR3000asm.c + $(CC) -c ../../DebugTools/DisR3000asm.c -o Obj//DisR3000asm.o $(CFLAGS) + +Obj//DisR5900.o: ../../DebugTools/DisR5900.c + $(CC) -c ../../DebugTools/DisR5900.c -o Obj//DisR5900.o $(CFLAGS) + +Obj//DisR5900asm.o: ../../DebugTools/DisR5900asm.c + $(CC) -c ../../DebugTools/DisR5900asm.c -o Obj//DisR5900asm.o $(CFLAGS) + +Obj//DisVU0Micro.o: ../../DebugTools/DisVU0Micro.c + $(CC) -c ../../DebugTools/DisVU0Micro.c -o Obj//DisVU0Micro.o $(CFLAGS) + +Obj//DisVU1Micro.o: ../../DebugTools/DisVU1Micro.c + $(CC) -c ../../DebugTools/DisVU1Micro.c -o Obj//DisVU1Micro.o $(CFLAGS) + +Obj//adler32.o: ../../zlib/adler32.c + $(CC) -c ../../zlib/adler32.c -o Obj//adler32.o $(CFLAGS) + +Obj//compress.o: ../../zlib/compress.c + $(CC) -c ../../zlib/compress.c -o Obj//compress.o $(CFLAGS) + +Obj//crc32.o: ../../zlib/crc32.c + $(CC) -c ../../zlib/crc32.c -o Obj//crc32.o $(CFLAGS) + +Obj//deflate.o: ../../zlib/deflate.c + $(CC) -c ../../zlib/deflate.c -o Obj//deflate.o $(CFLAGS) + +Obj//gzio.o: ../../zlib/gzio.c + $(CC) -c ../../zlib/gzio.c -o Obj//gzio.o $(CFLAGS) + +Obj//infback.o: ../../zlib/infback.c + $(CC) -c ../../zlib/infback.c -o Obj//infback.o $(CFLAGS) + +Obj//inffast.o: ../../zlib/inffast.c + $(CC) -c ../../zlib/inffast.c -o Obj//inffast.o $(CFLAGS) + +Obj//inflate.o: ../../zlib/inflate.c + $(CC) -c ../../zlib/inflate.c -o Obj//inflate.o $(CFLAGS) + +Obj//inftrees.o: ../../zlib/inftrees.c + $(CC) -c ../../zlib/inftrees.c -o Obj//inftrees.o $(CFLAGS) + +Obj//trees.o: ../../zlib/trees.c + $(CC) -c ../../zlib/trees.c -o Obj//trees.o $(CFLAGS) + +Obj//uncompr.o: ../../zlib/uncompr.c + $(CC) -c ../../zlib/uncompr.c -o Obj//uncompr.o $(CFLAGS) + +Obj//zutil.o: ../../zlib/zutil.c + $(CC) -c ../../zlib/zutil.c -o Obj//zutil.o $(CFLAGS) + +Obj//iR5900Arit.o: ../../ix86-32/iR5900Arit.c + $(CC) -c ../../ix86-32/iR5900Arit.c -o Obj//iR5900Arit.o $(CFLAGS) + +Obj//iR5900AritImm.o: ../../ix86-32/iR5900AritImm.c + $(CC) -c ../../ix86-32/iR5900AritImm.c -o Obj//iR5900AritImm.o $(CFLAGS) + +Obj//iR5900Branch.o: ../../ix86-32/iR5900Branch.c + $(CC) -c ../../ix86-32/iR5900Branch.c -o Obj//iR5900Branch.o $(CFLAGS) + +Obj//iR5900Jump.o: ../../ix86-32/iR5900Jump.c + $(CC) -c ../../ix86-32/iR5900Jump.c -o Obj//iR5900Jump.o $(CFLAGS) + +Obj//iR5900LoadStore.o: ../../ix86-32/iR5900LoadStore.c + $(CC) -c ../../ix86-32/iR5900LoadStore.c -o Obj//iR5900LoadStore.o $(CFLAGS) + +Obj//iR5900Move.o: ../../ix86-32/iR5900Move.c + $(CC) -c ../../ix86-32/iR5900Move.c -o Obj//iR5900Move.o $(CFLAGS) + +Obj//iR5900MultDiv.o: ../../ix86-32/iR5900MultDiv.c + $(CC) -c ../../ix86-32/iR5900MultDiv.c -o Obj//iR5900MultDiv.o $(CFLAGS) + +Obj//iR5900Shift.o: ../../ix86-32/iR5900Shift.c + $(CC) -c ../../ix86-32/iR5900Shift.c -o Obj//iR5900Shift.o $(CFLAGS) + +Obj//iCP0.o: ../../x86/iCP0.c + $(CC) -c ../../x86/iCP0.c -o Obj//iCP0.o $(CFLAGS) + +Obj//iFPU.o: ../../x86/iFPU.c + $(CC) -c ../../x86/iFPU.c -o Obj//iFPU.o $(CFLAGS) + +Obj//iMMI.o: ../../x86/iMMI.c + $(CC) -c ../../x86/iMMI.c -o Obj//iMMI.o $(CFLAGS) + +Obj//iR3000A.o: ../../x86/iR3000A.c + $(CC) -c ../../x86/iR3000A.c -o Obj//iR3000A.o $(CFLAGS) + +Obj//iR5900.o: ../../x86/iR5900.c + $(CC) -c ../../x86/iR5900.c -o Obj//iR5900.o $(CFLAGS) + +Obj//iVU0micro.o: ../../x86/iVU0micro.c + $(CC) -c ../../x86/iVU0micro.c -o Obj//iVU0micro.o $(CFLAGS) + +Obj//iVU1micro.o: ../../x86/iVU1micro.c + $(CC) -c ../../x86/iVU1micro.c -o Obj//iVU1micro.o $(CFLAGS) + +Obj//iVUmicro.o: ../../x86/iVUmicro.c + $(CC) -c ../../x86/iVUmicro.c -o Obj//iVUmicro.o $(CFLAGS) + +Obj//recCOP2.o: ../../x86/recCOP2.c + $(CC) -c ../../x86/recCOP2.c -o Obj//recCOP2.o $(CFLAGS) + +Obj//ix86.o: ../../x86/ix86/ix86.c + $(CC) -c ../../x86/ix86/ix86.c -o Obj//ix86.o $(CFLAGS) + +Obj//ix86_3dnow.o: ../../x86/ix86/ix86_3dnow.c + $(CC) -c ../../x86/ix86/ix86_3dnow.c -o Obj//ix86_3dnow.o $(CFLAGS) + +Obj//ix86_cpudetect.o: ../../x86/ix86/ix86_cpudetect.c + $(CC) -c ../../x86/ix86/ix86_cpudetect.c -o Obj//ix86_cpudetect.o $(CFLAGS) + +Obj//ix86_fpu.o: ../../x86/ix86/ix86_fpu.c + $(CC) -c ../../x86/ix86/ix86_fpu.c -o Obj//ix86_fpu.o $(CFLAGS) + +Obj//ix86_mmx.o: ../../x86/ix86/ix86_mmx.c + $(CC) -c ../../x86/ix86/ix86_mmx.c -o Obj//ix86_mmx.o $(CFLAGS) + +Obj//ix86_sse.o: ../../x86/ix86/ix86_sse.c + $(CC) -c ../../x86/ix86/ix86_sse.c -o Obj//ix86_sse.o $(CFLAGS) + +Obj//CDVD.o: ../../CDVD.c + $(CC) -c ../../CDVD.c -o Obj//CDVD.o $(CFLAGS) + +Obj//CDVDiso.o: ../../CDVDiso.c + $(CC) -c ../../CDVDiso.c -o Obj//CDVDiso.o $(CFLAGS) + +Obj//CDVDisodrv.o: ../../CDVDisodrv.c + $(CC) -c ../../CDVDisodrv.c -o Obj//CDVDisodrv.o $(CFLAGS) + +Obj//COP0.o: ../../COP0.c + $(CC) -c ../../COP0.c -o Obj//COP0.o $(CFLAGS) + +Obj//Counters.o: ../../Counters.c + $(CC) -c ../../Counters.c -o Obj//Counters.o $(CFLAGS) + +Obj//Decode_XA.o: ../../Decode_XA.c + $(CC) -c ../../Decode_XA.c -o Obj//Decode_XA.o $(CFLAGS) + +Obj//Elfheader.o: ../../Elfheader.c + $(CC) -c ../../Elfheader.c -o Obj//Elfheader.o $(CFLAGS) + +Obj//FiFo.o: ../../FiFo.c + $(CC) -c ../../FiFo.c -o Obj//FiFo.o $(CFLAGS) + +Obj//FPU.o: ../../FPU.c + $(CC) -c ../../FPU.c -o Obj//FPU.o $(CFLAGS) + +Obj//GS.o: ../../GS.c + $(CC) -c ../../GS.c -o Obj//GS.o $(CFLAGS) + +Obj//Gte.o: ../../Gte.c + $(CC) -c ../../Gte.c -o Obj//Gte.o $(CFLAGS) + +Obj//Hw.o: ../../Hw.c + $(CC) -c ../../Hw.c -o Obj//Hw.o $(CFLAGS) + +Obj//Interpreter.o: ../../Interpreter.c + $(CC) -c ../../Interpreter.c -o Obj//Interpreter.o $(CFLAGS) + +Obj//InterTables.o: ../../InterTables.c + $(CC) -c ../../InterTables.c -o Obj//InterTables.o $(CFLAGS) + +Obj//Mdec.o: ../../Mdec.c + $(CC) -c ../../Mdec.c -o Obj//Mdec.o $(CFLAGS) + +Obj//Memory.o: ../../Memory.c + $(CC) -c ../../Memory.c -o Obj//Memory.o $(CFLAGS) + +Obj//Misc.o: ../../Misc.c + $(CC) -c ../../Misc.c -o Obj//Misc.o $(CFLAGS) + +Obj//MMI.o: ../../MMI.c + $(CC) -c ../../MMI.c -o Obj//MMI.o $(CFLAGS) + +Obj//Patch.o: ../../Patch.c + $(CC) -c ../../Patch.c -o Obj//Patch.o $(CFLAGS) + +Obj//Plugins.o: ../../Plugins.c + $(CC) -c ../../Plugins.c -o Obj//Plugins.o $(CFLAGS) + +Obj//PsxBios.o: ../../PsxBios.c + $(CC) -c ../../PsxBios.c -o Obj//PsxBios.o $(CFLAGS) + +Obj//PsxCounters.o: ../../PsxCounters.c + $(CC) -c ../../PsxCounters.c -o Obj//PsxCounters.o $(CFLAGS) + +Obj//PsxDma.o: ../../PsxDma.c + $(CC) -c ../../PsxDma.c -o Obj//PsxDma.o $(CFLAGS) + +Obj//PsxGPU.o: ../../PsxGPU.c + $(CC) -c ../../PsxGPU.c -o Obj//PsxGPU.o $(CFLAGS) + +Obj//PsxHw.o: ../../PsxHw.c + $(CC) -c ../../PsxHw.c -o Obj//PsxHw.o $(CFLAGS) + +Obj//PsxInterpreter.o: ../../PsxInterpreter.c + $(CC) -c ../../PsxInterpreter.c -o Obj//PsxInterpreter.o $(CFLAGS) + +Obj//PsxMem.o: ../../PsxMem.c + $(CC) -c ../../PsxMem.c -o Obj//PsxMem.o $(CFLAGS) + +Obj//PsxSio2.o: ../../PsxSio2.c + $(CC) -c ../../PsxSio2.c -o Obj//PsxSio2.o $(CFLAGS) + +Obj//R3000A.o: ../../R3000A.c + $(CC) -c ../../R3000A.c -o Obj//R3000A.o $(CFLAGS) + +Obj//R5900.o: ../../R5900.c + $(CC) -c ../../R5900.c -o Obj//R5900.o $(CFLAGS) + +Obj//Sif.o: ../../Sif.c + $(CC) -c ../../Sif.c -o Obj//Sif.o $(CFLAGS) + +Obj//Sio.o: ../../Sio.c + $(CC) -c ../../Sio.c -o Obj//Sio.o $(CFLAGS) + +Obj//SPR.o: ../../SPR.c + $(CC) -c ../../SPR.c -o Obj//SPR.o $(CFLAGS) + +Obj//Stats.o: ../../Stats.c + $(CC) -c ../../Stats.c -o Obj//Stats.o $(CFLAGS) + +Obj//Vif.o: ../../Vif.c + $(CC) -c ../../Vif.c -o Obj//Vif.o $(CFLAGS) + +Obj//VifDma.o: ../../VifDma.c + $(CC) -c ../../VifDma.c -o Obj//VifDma.o $(CFLAGS) + +Obj//VU0.o: ../../VU0.c + $(CC) -c ../../VU0.c -o Obj//VU0.o $(CFLAGS) + +Obj//VU0micro.o: ../../VU0micro.c + $(CC) -c ../../VU0micro.c -o Obj//VU0micro.o $(CFLAGS) + +Obj//VU1micro.o: ../../VU1micro.c + $(CC) -c ../../VU1micro.c -o Obj//VU1micro.o $(CFLAGS) + +Obj//VUflags.o: ../../VUflags.c + $(CC) -c ../../VUflags.c -o Obj//VUflags.o $(CFLAGS) + +Obj//VUops.o: ../../VUops.c + $(CC) -c ../../VUops.c -o Obj//VUops.o $(CFLAGS) + +Obj//Cache.o: ../../Cache.c + $(CC) -c ../../Cache.c -o Obj//Cache.o $(CFLAGS) + +Obj//CdRom.o: ../../CdRom.c + $(CC) -c ../../CdRom.c -o Obj//CdRom.o $(CFLAGS) + +Obj//deci2.o: ../../RDebug/deci2.c + $(CC) -c ../../RDebug/deci2.c -o Obj//deci2.o $(CFLAGS) + +Obj//deci2_dbgp.o: ../../RDebug/deci2_dbgp.c + $(CC) -c ../../RDebug/deci2_dbgp.c -o Obj//deci2_dbgp.o $(CFLAGS) + +Obj//deci2_dcmp.o: ../../RDebug/deci2_dcmp.c + $(CC) -c ../../RDebug/deci2_dcmp.c -o Obj//deci2_dcmp.o $(CFLAGS) + +Obj//deci2_iloadp.o: ../../RDebug/deci2_iloadp.c + $(CC) -c ../../RDebug/deci2_iloadp.c -o Obj//deci2_iloadp.o $(CFLAGS) + +Obj//deci2_netmp.o: ../../RDebug/deci2_netmp.c + $(CC) -c ../../RDebug/deci2_netmp.c -o Obj//deci2_netmp.o $(CFLAGS) + +Obj//deci2_ttyp.o: ../../RDebug/deci2_ttyp.c + $(CC) -c ../../RDebug/deci2_ttyp.c -o Obj//deci2_ttyp.o $(CFLAGS) + +Obj//pcsx2_private.res: pcsx2_private.rc ../pcsx2.rc + $(WINDRES) -i pcsx2_private.rc --input-format=rc -o Obj//pcsx2_private.res -O coff --include-dir ../../ --include-dir ../ --include-dir ../mingw diff --git a/pcsx2/windows/mingw/afxres.h b/pcsx2/windows/mingw/afxres.h new file mode 100644 index 0000000000..147f64b376 --- /dev/null +++ b/pcsx2/windows/mingw/afxres.h @@ -0,0 +1,23 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/pcsx2/windows/mingw/pcsx2.dev b/pcsx2/windows/mingw/pcsx2.dev new file mode 100644 index 0000000000..db8fafbceb --- /dev/null +++ b/pcsx2/windows/mingw/pcsx2.dev @@ -0,0 +1,2116 @@ +[Project] +FileName=pcsx2.dev +Name=pcsx2 +UnitCount=205 +Type=0 +Ver=1 +ObjFiles= +Includes=../..;../../zlib;../../DebugTools;../../IPU;../../x86;../../ix86-32;..;../RDebug +Libs= +PrivateResource=pcsx2_private.rc +ResourceIncludes=../../;../;..\mingw +MakeIncludes= +Compiler=-v_@@_-D__WIN32___@@_-D__MINGW32__ _@@_-Wall _@@_-O3 ${-fomit-frame-pointer -finline-functions -fno-exceptions -ffast-math -fno-strict-aliasing} -mfpmath=sse -march=athlon64_@@_ _@@_ +CppCompiler= +Linker=-lcomctl32 _@@_-lwsock32 _@@_-lwinmm _@@_-lgdi32 _@@_-lcomdlg32 _@@__@@_-m128bit-long-double_@@_ +IsCpp=0 +Icon= +ExeOutput=../ +ObjectOutput=Obj/ +OverrideOutput=0 +OverrideOutputName=pcsx2.exe +HostApplication= +Folders=cpu,DebugTools,DECI2,GUI,Hardware,IOP_CPU,IPU,ix86,ix86/x86,ix86-32,misc,plugins,Sif,zlib +CommandLine= +UseCustomMakefile=0 +CustomMakefile=..\Makefile +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\AboutDlg.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\AboutDlg.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\ConfigDlg.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\CpuDlg.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\Debugger.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\Debugger.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\DebugMemory.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\Debugreg.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\ini.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\McdsDlg.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\McdsDlg.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\PatchBrowser.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\pcsx2.rc +Folder=GUI +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\RDebugger.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\RDebugger.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\resource.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\Win32.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\WinMain.c +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=afxres.h +CompileCpp=0 +Folder=GUI +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\IPU\Idct.c +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\IPU\IPU.c +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\IPU\IPU.h +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\IPU\Mpeg.c +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\IPU\Mpeg.h +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\IPU\Vlc.h +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\IPU\yuv2rgb.c +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\IPU\yuv2rgb.h +CompileCpp=0 +Folder=IPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\DebugTools\cpuopsDebug.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\DebugTools\cpuopsDebug.h +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\DebugTools\Debug.h +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\DebugTools\DisASM.h +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\DebugTools\DisR3000A.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\DebugTools\DisR3000asm.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\..\DebugTools\DisR5900.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\DebugTools\DisR5900asm.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\DebugTools\DisVU0Micro.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\..\DebugTools\DisVU1Micro.c +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\..\DebugTools\DisVUmicro.h +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\..\DebugTools\DisVUops.h +CompileCpp=0 +Folder=DebugTools +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\..\zlib\adler32.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=..\..\zlib\compress.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=..\..\zlib\crc32.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit43] +FileName=..\..\zlib\crc32.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit44] +FileName=..\..\zlib\deflate.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit45] +FileName=..\..\zlib\deflate.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit46] +FileName=..\..\zlib\gzio.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit47] +FileName=..\..\zlib\infback.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit48] +FileName=..\..\zlib\inffast.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit49] +FileName=..\..\zlib\inffast.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit50] +FileName=..\..\zlib\inffixed.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit51] +FileName=..\..\zlib\inflate.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit52] +FileName=..\..\zlib\inflate.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit53] +FileName=..\..\zlib\inftrees.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit54] +FileName=..\..\zlib\inftrees.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit55] +FileName=..\..\zlib\trees.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit56] +FileName=..\..\zlib\trees.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit57] +FileName=..\..\zlib\uncompr.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit58] +FileName=..\..\zlib\zconf.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit59] +FileName=..\..\zlib\zlib.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit60] +FileName=..\..\zlib\zutil.c +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit61] +FileName=..\..\zlib\zutil.h +CompileCpp=0 +Folder=zlib +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit62] +FileName=..\..\ix86-32\iR5900Arit.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit63] +FileName=..\..\ix86-32\iR5900Arit.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit64] +FileName=..\..\ix86-32\iR5900AritImm.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit65] +FileName=..\..\ix86-32\iR5900AritImm.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit66] +FileName=..\..\ix86-32\iR5900Branch.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit67] +FileName=..\..\ix86-32\iR5900Branch.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit68] +FileName=..\..\ix86-32\iR5900Jump.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit69] +FileName=..\..\ix86-32\iR5900Jump.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit70] +FileName=..\..\ix86-32\iR5900LoadStore.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit71] +FileName=..\..\ix86-32\iR5900LoadStore.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit72] +FileName=..\..\ix86-32\iR5900Move.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit73] +FileName=..\..\ix86-32\iR5900Move.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit74] +FileName=..\..\ix86-32\iR5900MultDiv.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit75] +FileName=..\..\ix86-32\iR5900MultDiv.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit76] +FileName=..\..\ix86-32\iR5900Shift.c +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit77] +FileName=..\..\ix86-32\iR5900Shift.h +CompileCpp=0 +Folder=ix86-32 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit78] +FileName=..\..\x86\iCP0.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit79] +FileName=..\..\x86\iCP0.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit80] +FileName=..\..\x86\iFPU.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit81] +FileName=..\..\x86\iFPU.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit82] +FileName=..\..\x86\iMMI.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit83] +FileName=..\..\x86\iMMI.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit84] +FileName=..\..\x86\iR3000A.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit85] +FileName=..\..\x86\iR5900.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit86] +FileName=..\..\x86\iR5900.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit87] +FileName=..\..\x86\iVU0micro.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit88] +FileName=..\..\x86\iVU0micro.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit89] +FileName=..\..\x86\iVU1micro.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit90] +FileName=..\..\x86\iVU1micro.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit91] +FileName=..\..\x86\iVUmicro.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit92] +FileName=..\..\x86\iVUmicro.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit93] +FileName=..\..\x86\iVUops.h +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit94] +FileName=..\..\x86\recCOP2.c +CompileCpp=0 +Folder=ix86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit95] +FileName=..\..\x86\ix86\ix86.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit96] +FileName=..\..\x86\ix86\ix86.h +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit97] +FileName=..\..\x86\ix86\ix86_3dnow.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit98] +FileName=..\..\x86\ix86\ix86_cpudetect.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit99] +FileName=..\..\x86\ix86\ix86_fpu.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit100] +FileName=..\..\x86\ix86\ix86_mmx.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit101] +FileName=..\..\x86\ix86\ix86_sse.c +CompileCpp=0 +Folder=ix86/x86 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit102] +FileName=..\..\CDVD.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit103] +FileName=..\..\CDVD.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit104] +FileName=..\..\CDVDiso.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit105] +FileName=..\..\CDVDiso.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit106] +FileName=..\..\CDVDisodrv.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit107] +FileName=..\..\CDVDisodrv.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit108] +FileName=..\..\CDVDlib.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit109] +FileName=..\..\Common.h +CompileCpp=0 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit110] +FileName=..\..\COP0.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit111] +FileName=..\..\COP0.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit112] +FileName=..\..\Counters.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit113] +FileName=..\..\Counters.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit114] +FileName=..\..\Decode_XA.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit115] +FileName=..\..\Decode_XA.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit116] +FileName=..\..\EEregs.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit117] +FileName=..\..\Elfheader.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit118] +FileName=..\..\Elfheader.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit119] +FileName=..\..\FiFo.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit120] +FileName=..\..\FPU.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit121] +FileName=..\..\GS.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit122] +FileName=..\..\GS.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit123] +FileName=..\..\Gte.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit124] +FileName=..\..\Gte.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit125] +FileName=..\..\Hw.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit126] +FileName=..\..\Hw.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit127] +FileName=..\..\Interpreter.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit128] +FileName=..\..\InterTables.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit129] +FileName=..\..\InterTables.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit130] +FileName=..\..\Mdec.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit131] +FileName=..\..\Mdec.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit132] +FileName=..\..\Memory.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit133] +FileName=..\..\Memory.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit134] +FileName=..\..\Misc.c +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit135] +FileName=..\..\Misc.h +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit136] +FileName=..\..\MMI.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit137] +FileName=..\..\Patch.c +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit138] +FileName=..\..\Patch.h +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit139] +FileName=..\..\Plugins.c +CompileCpp=0 +Folder=plugins +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit140] +FileName=..\..\Plugins.h +CompileCpp=0 +Folder=plugins +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit141] +FileName=..\..\PS2Edefs.h +CompileCpp=0 +Folder=plugins +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit142] +FileName=..\..\PS2Etypes.h +CompileCpp=0 +Folder=plugins +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit143] +FileName=..\..\PsxBios2.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit144] +FileName=..\..\PsxBios.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit145] +FileName=..\..\PsxBios.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit146] +FileName=..\..\PsxCommon.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit147] +FileName=..\..\PsxCounters.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit148] +FileName=..\..\PsxCounters.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit149] +FileName=..\..\PsxDma.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit150] +FileName=..\..\PsxDma.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit151] +FileName=..\..\PsxGPU.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit152] +FileName=..\..\PsxGPU.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit153] +FileName=..\..\PsxHw.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit154] +FileName=..\..\PsxHw.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit155] +FileName=..\..\PsxInterpreter.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit156] +FileName=..\..\PsxMem.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit157] +FileName=..\..\PsxMem.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit158] +FileName=..\..\PsxSio2.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit159] +FileName=..\..\PsxSio2.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit160] +FileName=..\..\R3000A.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit161] +FileName=..\..\R3000A.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit162] +FileName=..\..\R5900.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit163] +FileName=..\..\R5900.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit164] +FileName=..\..\Sif.c +CompileCpp=0 +Folder=Sif +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit165] +FileName=..\..\Sif.h +CompileCpp=0 +Folder=Sif +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit166] +FileName=..\..\Sifcmd.h +CompileCpp=0 +Folder=Sif +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit167] +FileName=..\..\Sio.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit168] +FileName=..\..\Sio.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit169] +FileName=..\..\SPR.c +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit170] +FileName=..\..\SPR.h +CompileCpp=0 +Folder=Hardware +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit171] +FileName=..\..\Stats.c +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit172] +FileName=..\..\Stats.h +CompileCpp=0 +Folder=misc +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit173] +FileName=..\..\System.h +CompileCpp=0 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit174] +FileName=..\..\Vif.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit175] +FileName=..\..\Vif.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit176] +FileName=..\..\VifDma.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit177] +FileName=..\..\VifDma.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit178] +FileName=..\..\VU0.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit179] +FileName=..\..\VU0.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit180] +FileName=..\..\VU0micro.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit181] +FileName=..\..\VU1micro.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit182] +FileName=..\..\VU.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit183] +FileName=..\..\VUflags.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit184] +FileName=..\..\VUflags.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit185] +FileName=..\..\VUmicro.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit186] +FileName=..\..\VUops.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit187] +FileName=..\..\VUops.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit188] +FileName=..\..\Cache.c +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit189] +FileName=..\..\Cache.h +CompileCpp=0 +Folder=cpu +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit190] +FileName=..\..\CdRom.c +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit191] +FileName=..\..\CdRom.h +CompileCpp=0 +Folder=IOP_CPU +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit192] +FileName=..\Cdrom02.ico +Folder=GUI +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit193] +FileName=..\..\pcsxAbout.bmp +Folder=GUI +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit194] +FileName=..\..\RDebug\deci2.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit195] +FileName=..\..\RDebug\deci2.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit196] +FileName=..\..\RDebug\deci2_dbgp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit197] +FileName=..\..\RDebug\deci2_dbgp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit198] +FileName=..\..\RDebug\deci2_dcmp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit199] +FileName=..\..\RDebug\deci2_dcmp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit202] +FileName=..\..\RDebug\deci2_netmp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit203] +FileName=..\..\RDebug\deci2_netmp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit204] +FileName=..\..\RDebug\deci2_ttyp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit205] +FileName=..\..\RDebug\deci2_ttyp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit206] +FileName=..\..\RDebug\deci2_ttyp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit207] +FileName=..\..\RDebug\deci2_ttyp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit200] +FileName=..\..\RDebug\deci2_iloadp.c +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit201] +FileName=..\..\RDebug\deci2_iloadp.h +CompileCpp=0 +Folder=DECI2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/pcsx2/windows/mingw/pcsx2.layout b/pcsx2/windows/mingw/pcsx2.layout new file mode 100644 index 0000000000..eb0d940638 --- /dev/null +++ b/pcsx2/windows/mingw/pcsx2.layout @@ -0,0 +1,1424 @@ +[Editor_0] +CursorCol=1 +CursorRow=24 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_1] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_4] +CursorCol=1 +CursorRow=95 +TopLine=54 +LeftChar=1 +Open=1 +Top=1 +[Editor_3] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_5] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_6] +CursorCol=2 +CursorRow=239 +TopLine=193 +LeftChar=1 +Open=0 +Top=0 +[Editor_8] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_9] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_7] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_10] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_11] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_12] +CursorCol=1 +CursorRow=19 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_13] +CursorCol=20 +CursorRow=172 +TopLine=132 +LeftChar=1 +Open=0 +Top=0 +[Editor_14] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_15] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_16] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_17] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_2] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_19] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_20] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_22] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_23] +CursorCol=1 +CursorRow=175 +TopLine=146 +LeftChar=1 +Open=0 +Top=0 +[Editor_24] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_25] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_26] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_21] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_27] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_28] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_29] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_31] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_30] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_32] +CursorCol=48 +CursorRow=360 +TopLine=315 +LeftChar=1 +Open=0 +Top=0 +[Editor_33] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_34] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_35] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_36] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_37] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_38] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_39] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_40] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_41] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_42] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_43] +CursorCol=8 +CursorRow=841 +TopLine=812 +LeftChar=1 +Open=0 +Top=0 +[Editor_44] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_45] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_46] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_47] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_48] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_49] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_50] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_51] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_52] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_53] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_54] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_55] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_56] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_57] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_58] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_59] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_60] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_61] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_62] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_63] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_64] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_65] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_66] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_67] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_68] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_69] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_70] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_71] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_72] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_73] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_74] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_75] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_76] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_77] +CursorCol=18 +CursorRow=24 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_78] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_79] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_80] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_81] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_82] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_83] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_84] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_85] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_86] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_87] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_88] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_89] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_90] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_91] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_92] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_93] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_113] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_114] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_189] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_190] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_187] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_188] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_135] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_143] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_126] +CursorCol=1 +CursorRow=515 +TopLine=496 +LeftChar=1 +Open=0 +Top=0 +[Editor_127] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_128] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_133] +CursorCol=1 +CursorRow=684 +TopLine=643 +LeftChar=1 +Open=0 +Top=0 +[Editor_134] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_136] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_137] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_138] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_139] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_140] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_141] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_145] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_144] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_142] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_146] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_147] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_150] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_152] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_154] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_132] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_148] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_149] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_151] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_153] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_155] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_156] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_157] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_158] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_159] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_160] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_161] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_162] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_173] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_174] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_175] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_176] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_181] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_177] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_178] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_179] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_180] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_182] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_183] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_184] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_185] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_186] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_119] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_131] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_124] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_125] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_122] +CursorCol=17 +CursorRow=207 +TopLine=197 +LeftChar=1 +Open=0 +Top=0 +[Editor_123] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_129] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_130] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_163] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_164] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_166] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_167] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_109] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_110] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_192] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_170] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_168] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_169] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_165] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_111] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_112] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_101] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_102] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_103] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_104] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_105] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_106] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_107] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_115] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_116] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_117] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_118] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_120] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_121] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_171] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editors] +Focused=-1 +Order=-1 +[Editor_18] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_94] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_95] +Open=0 +Top=0 +[Editor_96] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_97] +Open=1 +Top=0 +CursorCol=28 +CursorRow=477 +TopLine=439 +LeftChar=1 +[Editor_98] +Open=0 +Top=0 +[Editor_99] +Open=0 +Top=0 +CursorCol=1 +CursorRow=337 +TopLine=296 +LeftChar=1 +[Editor_100] +Open=0 +Top=0 +[Editor_108] +Open=0 +Top=0 +CursorCol=3 +CursorRow=3 +TopLine=1 +LeftChar=1 +[Editor_172] +Open=0 +Top=0 +[Editor_191] +Open=0 +Top=0 +[Editor_193] +Open=0 +Top=0 +CursorCol=20 +CursorRow=23 +TopLine=1 +LeftChar=1 +[Editor_194] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_195] +Open=0 +Top=0 +CursorCol=1 +CursorRow=349 +TopLine=1 +LeftChar=1 +[Editor_196] +Open=0 +Top=0 +[Editor_197] +Open=0 +Top=0 +CursorCol=6 +CursorRow=42 +TopLine=37 +LeftChar=1 +[Editor_198] +Open=0 +Top=0 +CursorCol=6 +CursorRow=25 +TopLine=1 +LeftChar=1 +[Editor_199] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_200] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_201] +Open=0 +Top=0 +CursorCol=21 +CursorRow=133 +TopLine=89 +LeftChar=1 +[Editor_202] +Open=0 +Top=0 +CursorCol=9 +CursorRow=27 +TopLine=1 +LeftChar=1 +[Editor_203] +Open=0 +Top=0 +CursorCol=21 +CursorRow=40 +TopLine=1 +LeftChar=1 +[Editor_204] +Open=0 +Top=0 +CursorCol=9 +CursorRow=27 +TopLine=1 +LeftChar=1 +[Editor_205] +Open=1 +Top=0 +CursorCol=21 +CursorRow=40 +TopLine=1 +LeftChar=1 +[Editor_206] +Open=0 +Top=0 diff --git a/pcsx2/windows/mingw/pcsx2_private.h b/pcsx2/windows/mingw/pcsx2_private.h new file mode 100644 index 0000000000..2e8cf9ddcb --- /dev/null +++ b/pcsx2/windows/mingw/pcsx2_private.h @@ -0,0 +1,40 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ +/* DO NOT EDIT ! */ + +#ifndef PCSX2_PRIVATE_H +#define PCSX2_PRIVATE_H + +/* VERSION DEFINITIONS */ +#define VER_STRING "0.1.1.1" +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_RELEASE 1 +#define VER_BUILD 1 +#define COMPANY_NAME "" +#define FILE_VERSION "" +#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" +#define INTERNAL_NAME "" +#define LEGAL_COPYRIGHT "" +#define LEGAL_TRADEMARKS "" +#define ORIGINAL_FILENAME "" +#define PRODUCT_NAME "" +#define PRODUCT_VERSION "" + +#endif /*PCSX2_PRIVATE_H*/ diff --git a/pcsx2/windows/mingw/pcsx2_private.rc b/pcsx2/windows/mingw/pcsx2_private.rc new file mode 100644 index 0000000000..aea0afea38 --- /dev/null +++ b/pcsx2/windows/mingw/pcsx2_private.rc @@ -0,0 +1,5 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ +/* DO NOT EDIT! */ + +#include "../pcsx2.rc" + diff --git a/pcsx2/windows/pcsx2.rc b/pcsx2/windows/pcsx2.rc new file mode 100644 index 0000000000..23232aad99 --- /dev/null +++ b/pcsx2/windows/pcsx2.rc @@ -0,0 +1,1589 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Romanian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ROM) +#ifdef _WIN32 +LANGUAGE LANG_ROMANIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CMDLINE DIALOG 0, 0, 186, 82 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Program arguments" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,36,37,50,14 + PUSHBUTTON "Cancel",IDCANCEL,99,37,50,14 + CTEXT "Tip: If you don't know what to write\nleave it blank",IDC_TIP,7,56,172,19,WS_BORDER + EDITTEXT IDC_CMDLINE,7,17,172,14,ES_AUTOHSCROLL + LTEXT "Fill in the command line arguments for opened program:",IDC_TEXT,7,7,174,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CMDLINE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 75 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Romanian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CP0REGS DIALOG 0, 0, 267, 237 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "COP0 " +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_CP00,48,7,51,12,ES_READONLY + LTEXT "Index",-1,7,9,18,8 + EDITTEXT IDC_CP01,48,21,51,12,ES_READONLY + LTEXT "Random",-1,7,23,28,8 + EDITTEXT IDC_CP02,48,35,51,12,ES_READONLY + LTEXT "EntryLo0",-1,7,37,29,8 + EDITTEXT IDC_CP03,48,49,51,12,ES_READONLY + LTEXT "EntryLo1",-1,7,51,29,8 + EDITTEXT IDC_CP04,48,63,51,12,ES_READONLY + LTEXT "Context",-1,7,65,25,8 + EDITTEXT IDC_CP05,48,77,51,12,ES_READONLY + LTEXT "PageMask",-1,7,79,35,8 + EDITTEXT IDC_CP06,48,91,51,12,ES_READONLY + LTEXT "Wired",-1,7,93,20,8 + EDITTEXT IDC_CP07,48,105,51,12,ES_READONLY + EDITTEXT IDC_CP08,48,119,51,12,ES_READONLY + LTEXT "BadVAddr",-1,7,121,33,8 + EDITTEXT IDC_CP09,48,133,52,12,ES_READONLY + LTEXT "Count",-1,7,135,20,8 + EDITTEXT IDC_CP010,48,147,51,12,ES_READONLY + LTEXT "EntryHi",-1,7,149,24,8 + EDITTEXT IDC_CP011,48,161,52,12,ES_READONLY + LTEXT "Compare",-1,7,163,29,8 + EDITTEXT IDC_CP012,48,175,51,12,ES_READONLY + LTEXT "Status",-1,7,177,21,8 + EDITTEXT IDC_CP013,48,189,51,12,ES_READONLY + LTEXT "Cause",-1,7,191,21,8 + EDITTEXT IDC_CP014,48,203,51,12,ES_READONLY + LTEXT "EPC",-1,7,205,15,8 + EDITTEXT IDC_CP015,48,218,51,12,ES_READONLY + LTEXT "PRId",-1,7,219,17,8 + EDITTEXT IDC_CP016,191,7,51,12,ES_READONLY + LTEXT "Config",-1,145,9,21,8 + EDITTEXT IDC_CP017,191,21,51,12,ES_READONLY + EDITTEXT IDC_CP018,191,35,51,12,ES_READONLY + EDITTEXT IDC_CP019,191,49,51,12,ES_READONLY + EDITTEXT IDC_CP020,191,63,51,12,ES_READONLY + EDITTEXT IDC_CP021,191,77,51,12,ES_READONLY + EDITTEXT IDC_CP022,191,91,51,12,ES_READONLY + EDITTEXT IDC_CP023,191,105,51,12,ES_READONLY + EDITTEXT IDC_CP024,191,119,51,12,ES_READONLY + EDITTEXT IDC_CP025,191,133,51,12,ES_READONLY + EDITTEXT IDC_CP026,191,147,51,12,ES_READONLY + LTEXT "Debug",-1,147,122,22,8 + EDITTEXT IDC_CP027,191,161,51,12,ES_READONLY + LTEXT "Perf",-1,149,136,14,8 + EDITTEXT IDC_CP028,191,175,51,12,ES_READONLY + LTEXT "TagLo",-1,145,177,22,8 + EDITTEXT IDC_CP029,191,189,51,12,ES_READONLY + LTEXT "TagHi",-1,145,191,20,8 + EDITTEXT IDC_CP030,191,203,51,12,ES_READONLY + LTEXT "ErrorEPC",-1,145,205,30,8 + EDITTEXT IDC_CP031,191,218,51,12,ES_READONLY +END + +IDD_DEBUG DIALOGEX 0, 0, 341, 270 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Debugger" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LISTBOX IDC_DEBUG_DISASM,7,6,198,257,LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_TABSTOP,WS_EX_TRANSPARENT + SCROLLBAR IDC_DEBUG_SCROLL,205,6,11,257,SBS_VERT + PUSHBUTTON "Go",IDC_DEBUG_GO,224,6,50,14 + PUSHBUTTON "S&tep (IOP)",IDC_DEBUG_STEP,224,183,50,14 + GROUPBOX "R5900",IDC_STATIC,221,39,114,63 + PUSHBUTTON "&Step Into",IDC_DEBUG_STEP_EE,224,50,50,14 + PUSHBUTTON "S&kip",IDC_DEBUG_SKIP,224,67,50,14 + PUSHBUTTON "Step to Cursor",IDC_DEBUG_STEP_TO_CURSOR,224,84,51,14 + PUSHBUTTON "Run &Over",IDC_DEBUG_STEP_OVER,277,50,52,14 + PUSHBUTTON "&Run to Cursor",IDC_DEBUG_RUN_TO_CURSOR,278,67,51,14 + PUSHBUTTON "Break",IDC_DEBUG_BREAK,278,84,51,14 + PUSHBUTTON "Bkpt on Exec",IDC_DEBUG_BP_EXEC,224,125,50,14 + PUSHBUTTON "Bkpt on Count",IDC_DEBUG_BP_COUNT,224,141,50,14 + PUSHBUTTON "Clear Bkpts",IDC_DEBUG_BP_CLEAR,224,158,50,14 + PUSHBUTTON "Un/Set Log",IDC_DEBUG_LOG,279,124,50,14 + PUSHBUTTON "Reset to PC",IDC_DEBUG_RESETTOPC,279,142,50,14 + PUSHBUTTON "Jump to ADDR",IDC_DEBUG_JUMP,279,158,50,14 + PUSHBUTTON "Dump code",IDC_DEBUG_DUMP,223,211,50,14 + PUSHBUTTON "Dump memory",IDC_DEBUG_MEMORY,223,228,50,14 + PUSHBUTTON "Cpu ops",IDC_CPUOP,223,244,50,14 + PUSHBUTTON "Close",IDC_DEBUG_CLOSE,280,244,50,14 +END + +IDD_DUMP DIALOGEX 0, 0, 386, 96 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Dump code" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + EDITTEXT IDC_DUMP_START,73,14,82,13 + EDITTEXT IDC_DUMP_END,73,29,82,13 + EDITTEXT IDC_DUMP_FNAME,73,50,82,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,87,74,50,14 + PUSHBUTTON "Cancel",IDCANCEL,227,73,50,14 + LTEXT "Start PC Address:",IDC_STATIC,19,17,52,8 + LTEXT "End PC Address:",IDC_STATIC,19,32,50,8 + LTEXT "Filename:",IDC_STATIC,19,53,31,8 + GROUPBOX "EE",IDC_STATIC,14,6,167,64 + EDITTEXT IDC_DUMP_STARTIOP,255,15,82,13 + EDITTEXT IDC_DUMP_ENDIOP,255,30,82,13 + EDITTEXT IDC_DUMP_FNAMEIOP,255,50,82,13,ES_AUTOHSCROLL + LTEXT "Start PC Address:",IDC_STATIC,201,18,52,8 + LTEXT "End PC Address:",IDC_STATIC,201,33,50,8 + LTEXT "Filename:",IDC_STATIC,201,54,31,8 + GROUPBOX "IOP",IDC_STATIC,195,7,167,63 +END + +IDD_GPREGS DIALOG 0, 0, 391, 279 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "R5900 Main registers" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_GPR0,22,7,166,12,ES_READONLY + LTEXT "R0",-1,7,9,10,8 + EDITTEXT IDC_GPR1,22,21,166,12,ES_READONLY + LTEXT "AT",-1,7,23,10,8 + EDITTEXT IDC_GPR2,22,35,166,12,ES_READONLY + LTEXT "V0",-1,7,37,10,8 + EDITTEXT IDC_GPR3,22,49,166,12,ES_READONLY + LTEXT "V1",-1,7,51,10,8 + EDITTEXT IDC_GPR4,22,63,166,12,ES_READONLY + LTEXT "A0",-1,7,65,10,8 + EDITTEXT IDC_GPR5,22,77,166,12,ES_READONLY + LTEXT "A1",-1,7,79,10,8 + EDITTEXT IDC_GPR6,22,91,166,12,ES_READONLY + LTEXT "A2",-1,7,93,10,8 + EDITTEXT IDC_GPR7,22,105,166,12,ES_READONLY + LTEXT "A3",-1,7,107,10,8 + EDITTEXT IDC_GPR8,22,119,166,12,ES_READONLY + LTEXT "T0",-1,7,121,10,8 + EDITTEXT IDC_GPR9,22,133,166,12,ES_READONLY + LTEXT "T1",-1,7,135,10,8 + EDITTEXT IDC_GPR10,22,147,166,12,ES_READONLY + LTEXT "T2",-1,7,149,10,8 + EDITTEXT IDC_GPR11,22,161,166,12,ES_READONLY + LTEXT "T3",-1,7,163,10,8 + EDITTEXT IDC_GPR12,22,175,166,12,ES_READONLY + LTEXT "T4",-1,7,177,10,8 + EDITTEXT IDC_GPR13,22,189,166,12,ES_READONLY + LTEXT "T5",-1,7,191,10,8 + EDITTEXT IDC_GPR14,22,203,166,12,ES_READONLY + LTEXT "T6",-1,7,205,10,8 + EDITTEXT IDC_GPR15,22,218,166,12,ES_READONLY + LTEXT "T7",-1,7,219,10,8 + EDITTEXT IDC_GPR16,214,7,165,12,ES_READONLY + LTEXT "S0",-1,196,10,10,8 + EDITTEXT IDC_GPR17,214,20,166,12,ES_READONLY + LTEXT "S1",-1,196,22,10,8 + EDITTEXT IDC_GPR18,214,35,166,12,ES_READONLY + LTEXT "S2",-1,196,36,10,8 + EDITTEXT IDC_GPR19,214,49,165,12,ES_READONLY + LTEXT "S3",-1,196,52,10,8 + EDITTEXT IDC_GPR20,214,63,165,12,ES_READONLY + LTEXT "S4",-1,196,66,10,8 + EDITTEXT IDC_GPR21,214,76,165,12,ES_READONLY + LTEXT "S5",-1,196,80,10,8 + EDITTEXT IDC_GPR22,214,91,165,12,ES_READONLY + LTEXT "S6",-1,196,94,10,8 + EDITTEXT IDC_GPR23,214,105,165,12,ES_READONLY + LTEXT "S7",-1,196,108,10,8 + EDITTEXT IDC_GPR24,214,119,165,12,ES_READONLY + LTEXT "T8",-1,196,121,10,8 + EDITTEXT IDC_GPR25,214,132,165,12,ES_READONLY + LTEXT "T9",-1,196,135,10,8 + EDITTEXT IDC_GPR26,214,147,165,12,ES_READONLY + LTEXT "K0",-1,196,149,10,8 + EDITTEXT IDC_GPR27,214,161,165,12,ES_READONLY + LTEXT "K1",-1,196,163,10,8 + EDITTEXT IDC_GPR28,214,175,165,12,ES_READONLY + LTEXT "GP",-1,196,178,11,8 + EDITTEXT IDC_GPR29,214,188,165,12,ES_READONLY + LTEXT "SP",-1,196,190,10,8 + EDITTEXT IDC_GPR30,214,203,165,12,ES_READONLY + LTEXT "S8",-1,196,205,10,8 + EDITTEXT IDC_GPR31,214,217,165,12,ES_READONLY + LTEXT "RA",-1,196,220,11,8 + EDITTEXT IDC_GPR_PC,20,260,57,12,ES_READONLY + LTEXT "PC",-1,7,263,10,8 + EDITTEXT IDC_GPR_HI,21,238,167,12,ES_READONLY + LTEXT "HI",-1,7,241,8,8 + LTEXT "LO",-1,196,241,10,8 + EDITTEXT IDC_GPR_LO,214,238,165,12,ES_READONLY +END + +IDD_JUMP DIALOG 0, 0, 175, 64 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Jump to specific address" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_JUMP_PC,73,14,82,13 + DEFPUSHBUTTON "OK",IDOK,25,43,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,42,50,14 + LTEXT "Enter new PC Address:",IDC_STATIC,3,18,70,8 +END + +IDD_MEMORY DIALOG 0, 0, 317, 270 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Memory" +FONT 8, "Courier" +BEGIN + EDITTEXT IDC_MEMORY_ADDR,54,7,97,12 + PUSHBUTTON "Close",IDC_MEMORY_CLOSE,266,7,42,14 + LTEXT "Address:",IDC_STATIC,14,8,34,8 + LISTBOX IDC_MEMORY_DUMP,3,29,300,169,LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_TABSTOP + SCROLLBAR IDC_MEM_SCROLL,303,29,9,172,SBS_VERT + GROUPBOX "Memory Patch",IDC_STATIC,3,204,307,57 + EDITTEXT IDC_ADDRESS_PATCH,124,220,97,12 + EDITTEXT IDC_DATA_PATCH,124,242,97,12 + LTEXT "Address",IDC_STATIC,84,222,40,8 + LTEXT "Data",IDC_STATIC,85,244,39,8 + PUSHBUTTON "Patch It",IDC_PATCH,238,230,64,16 + PUSHBUTTON "Raw dump",IDC_DUMPRAW,204,7,50,14 +END + +IDD_VU1INTEGER DIALOG 0, 0, 357, 263 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "VU1 Integer & Control Registers" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_VU1_VI00,29,7,89,12,WS_DISABLED + LTEXT "VI00",IDC_STATIC,7,9,16,8 + EDITTEXT IDC_VU1_VI01,29,21,89,12,WS_DISABLED + LTEXT "VI01",IDC_STATIC,7,23,16,8 + EDITTEXT IDC_VU1_VI02,29,35,89,12,WS_DISABLED + LTEXT "VI02",IDC_STATIC,7,37,16,8 + EDITTEXT IDC_VU1_VI03,29,49,89,12,WS_DISABLED + LTEXT "VI03",IDC_STATIC,7,51,16,8 + EDITTEXT IDC_VU1_VI04,29,63,89,12,WS_DISABLED + LTEXT "VI04",IDC_STATIC,7,65,16,8 + EDITTEXT IDC_VU1_VI05,29,77,89,12,WS_DISABLED + LTEXT "VI05",IDC_STATIC,7,79,16,8 + EDITTEXT IDC_VU1_VI06,29,91,89,12,WS_DISABLED + LTEXT "VI06",IDC_STATIC,7,93,16,8 + EDITTEXT IDC_VU1_VI07,29,105,89,12,WS_DISABLED + LTEXT "VI07",IDC_STATIC,7,107,16,8 + EDITTEXT IDC_VU1_VI08,29,119,89,12,WS_DISABLED + LTEXT "VI08",IDC_STATIC,7,121,16,8 + EDITTEXT IDC_VU1_VI09,29,133,89,12,WS_DISABLED + LTEXT "VI09",IDC_STATIC,7,135,16,8 + EDITTEXT IDC_VU1_VI10,29,147,89,12,WS_DISABLED + LTEXT "VI10",IDC_STATIC,7,149,16,8 + EDITTEXT IDC_VU1_VI11,29,161,89,12,WS_DISABLED + LTEXT "VI11",IDC_STATIC,7,163,16,8 + EDITTEXT IDC_VU1_VI12,29,175,89,12,WS_DISABLED + LTEXT "VI12",IDC_STATIC,7,177,16,8 + EDITTEXT IDC_VU1_VI13,29,189,89,12,WS_DISABLED + LTEXT "VI13",IDC_STATIC,7,191,16,8 + EDITTEXT IDC_VU1_VI14,29,203,89,12,WS_DISABLED + LTEXT "VI14",IDC_STATIC,7,205,16,8 + EDITTEXT IDC_VU1_VI15,29,218,89,12,WS_DISABLED + LTEXT "VI15",IDC_STATIC,7,219,16,8 + EDITTEXT IDC_VU1_VI16,172,7,89,12,WS_DISABLED + LTEXT "Status Flag",IDC_STATIC,123,9,36,8 + EDITTEXT IDC_VU1_VI17,172,21,89,12,WS_DISABLED + LTEXT "MAC Flag",IDC_STATIC,123,23,32,8 + EDITTEXT IDC_VU1_VI18,172,35,89,12,WS_DISABLED + LTEXT "Clipping Flag",IDC_STATIC,123,37,41,8 + EDITTEXT IDC_VU1_VI19,172,49,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,51,8,8 + EDITTEXT IDC_VU1_VI20,172,63,89,12,WS_DISABLED + LTEXT "R register",IDC_STATIC,123,65,31,8 + EDITTEXT IDC_VU1_VI21,172,77,89,12,WS_DISABLED + LTEXT "I register",IDC_STATIC,123,79,28,8 + EDITTEXT IDC_VU1_VI22,172,91,89,12,WS_DISABLED + LTEXT "Q register",IDC_STATIC,123,93,31,8 + EDITTEXT IDC_VU1_VI23,172,105,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,107,8,8 + EDITTEXT IDC_VU1_VI24,172,119,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,121,8,8 + EDITTEXT IDC_VU1_VI25,172,133,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,135,8,8 + EDITTEXT IDC_VU1_VI26,172,147,89,12,WS_DISABLED + LTEXT "TPC register",IDC_STATIC,123,149,40,8 + EDITTEXT IDC_VU1_VI27,172,161,89,12,WS_DISABLED + LTEXT "P register",IDC_STATIC,124,108,30,8 + EDITTEXT IDC_VU1_VI28,172,175,89,12,WS_DISABLED + EDITTEXT IDC_VU1_VI29,172,189,89,12,WS_DISABLED + EDITTEXT IDC_VU1_VI30,172,203,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,205,8,8 + EDITTEXT IDC_VU1_VI31,172,218,89,12,WS_DISABLED + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDVERT | SS_SUNKEN,273,7,1,222 + LTEXT "Accumulator",IDC_STATIC,27,238,43,14 + EDITTEXT IDC_VU1_ACC,78,239,166,12,ES_READONLY +END + +IDD_VU0REGS DIALOG 0, 0, 391, 279 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "VUO Floating Point Registers" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_VU0_VF00,28,7,166,12,ES_READONLY + LTEXT "VF00",-1,7,9,18,8 + EDITTEXT IDC_VU0_VF01,28,21,166,12,ES_READONLY + LTEXT "VF01",-1,7,23,18,8 + EDITTEXT IDC_VU0_VF02,28,35,166,12,ES_READONLY + LTEXT "VF02",-1,7,37,18,8 + EDITTEXT IDC_VU0_VF03,28,49,166,12,ES_READONLY + LTEXT "VF03",-1,7,51,18,8 + EDITTEXT IDC_VU0_VF04,28,63,166,12,ES_READONLY + LTEXT "VF04",-1,7,65,18,8 + EDITTEXT IDC_VU0_VF05,28,77,166,12,ES_READONLY + LTEXT "VF05",-1,7,79,18,8 + EDITTEXT IDC_VU0_VF06,28,91,166,12,ES_READONLY + LTEXT "VF06",-1,7,93,18,8 + EDITTEXT IDC_VU0_VF07,28,105,166,12,ES_READONLY + LTEXT "VF07",-1,7,107,18,8 + EDITTEXT IDC_VU0_VF08,28,119,166,12,ES_READONLY + LTEXT "VF08",-1,7,121,18,8 + EDITTEXT IDC_VU0_VF09,28,133,166,12,ES_READONLY + LTEXT "VF09",-1,7,135,18,8 + EDITTEXT IDC_VU0_VF10,28,147,166,12,ES_READONLY + LTEXT "VF10",-1,7,149,18,8 + EDITTEXT IDC_VU0_VF11,28,161,166,12,ES_READONLY + LTEXT "VF11",-1,7,163,18,8 + EDITTEXT IDC_VU0_VF12,28,175,166,12,ES_READONLY + LTEXT "VF12",-1,7,177,18,8 + EDITTEXT IDC_VU0_VF13,28,189,166,12,ES_READONLY + LTEXT "VF13",-1,7,191,18,8 + EDITTEXT IDC_VU0_VF14,28,203,166,12,ES_READONLY + LTEXT "VF14",-1,7,205,18,8 + EDITTEXT IDC_VU0_VF15,28,218,166,12,ES_READONLY + LTEXT "VF15",-1,7,219,18,8 + EDITTEXT IDC_VU0_VF16,214,7,165,12,ES_READONLY + LTEXT "VF16",-1,196,10,18,8 + EDITTEXT IDC_VU0_VF17,214,20,166,12,ES_READONLY + LTEXT "VF17",-1,196,22,18,8 + EDITTEXT IDC_VU0_VF18,214,35,166,12,ES_READONLY + LTEXT "VF18",-1,196,36,18,8 + EDITTEXT IDC_VU0_VF19,214,49,165,12,ES_READONLY + LTEXT "VF19",-1,196,52,18,8 + EDITTEXT IDC_VU0_VF20,214,63,165,12,ES_READONLY + LTEXT "VF20",-1,196,66,18,8 + EDITTEXT IDC_VU0_VF21,214,76,165,12,ES_READONLY + LTEXT "VF21",-1,196,80,18,8 + EDITTEXT IDC_VU0_VF22,214,91,165,12,ES_READONLY + LTEXT "VF22",-1,196,94,18,8 + EDITTEXT IDC_VU0_VF23,214,105,165,12,ES_READONLY + LTEXT "VF23",-1,196,108,18,8 + EDITTEXT IDC_VU0_VF24,214,119,165,12,ES_READONLY + LTEXT "VF24",-1,196,121,18,8 + EDITTEXT IDC_VU0_VF25,214,132,165,12,ES_READONLY + LTEXT "VF25",-1,196,135,18,8 + EDITTEXT IDC_VU0_VF26,214,147,165,12,ES_READONLY + LTEXT "VF26",-1,196,149,18,8 + EDITTEXT IDC_VU0_VF27,214,161,165,12,ES_READONLY + LTEXT "VF27",-1,196,163,18,8 + EDITTEXT IDC_VU0_VF28,214,175,165,12,ES_READONLY + LTEXT "VF28",-1,196,178,18,8 + EDITTEXT IDC_VU0_VF29,214,188,165,12,ES_READONLY + LTEXT "VF29",-1,196,190,18,8 + EDITTEXT IDC_VU0_VF30,214,203,165,12,ES_READONLY + LTEXT "VF30",-1,196,205,18,8 + EDITTEXT IDC_VU0_VF31,214,217,165,12,ES_READONLY + LTEXT "VF31",-1,196,220,18,8 +END + +IDD_CP1REGS DIALOG 0, 0, 357, 237 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "COP1 Registers " +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_FP0,29,7,89,12,WS_DISABLED + LTEXT "FP0",IDC_STATIC,7,9,14,8 + EDITTEXT IDC_FP1,29,21,89,12,WS_DISABLED + LTEXT "FP1",IDC_STATIC,7,23,14,8 + EDITTEXT IDC_FP2,29,35,89,12,WS_DISABLED + LTEXT "FP2",IDC_STATIC,7,37,14,8 + EDITTEXT IDC_FP3,29,49,89,12,WS_DISABLED + LTEXT "FP3",IDC_STATIC,7,51,14,8 + EDITTEXT IDC_FP4,29,63,89,12,WS_DISABLED + LTEXT "FP4",IDC_STATIC,7,65,14,8 + EDITTEXT IDC_FP5,29,77,89,12,WS_DISABLED + LTEXT "FP5",IDC_STATIC,7,79,14,8 + EDITTEXT IDC_FP6,29,91,89,12,WS_DISABLED + LTEXT "FP6",IDC_STATIC,7,93,14,8 + EDITTEXT IDC_FP7,29,105,89,12,WS_DISABLED + LTEXT "FP7",IDC_STATIC,7,107,14,8 + EDITTEXT IDC_FP8,29,119,89,12,WS_DISABLED + LTEXT "FP8",IDC_STATIC,7,121,14,8 + EDITTEXT IDC_FP9,29,133,89,12,WS_DISABLED + LTEXT "FP9",IDC_STATIC,7,135,14,8 + EDITTEXT IDC_FP10,29,147,89,12,WS_DISABLED + LTEXT "FP10",IDC_STATIC,7,149,18,8 + EDITTEXT IDC_FP11,29,161,89,12,WS_DISABLED + LTEXT "FP11",IDC_STATIC,7,163,18,8 + EDITTEXT IDC_FP12,29,175,89,12,WS_DISABLED + LTEXT "FP12",IDC_STATIC,7,177,18,8 + EDITTEXT IDC_FP13,29,189,89,12,WS_DISABLED + LTEXT "FP13",IDC_STATIC,7,191,18,8 + EDITTEXT IDC_FP14,29,203,89,12,WS_DISABLED + LTEXT "FP14",IDC_STATIC,7,205,18,8 + EDITTEXT IDC_FP15,29,218,89,12,WS_DISABLED + LTEXT "FP15",IDC_STATIC,7,219,18,8 + EDITTEXT IDC_FP16,145,7,89,12,WS_DISABLED + LTEXT "FP16",IDC_STATIC,123,9,18,8 + EDITTEXT IDC_FP17,145,21,89,12,WS_DISABLED + LTEXT "FP17",IDC_STATIC,123,23,18,8 + EDITTEXT IDC_FP18,145,35,89,12,WS_DISABLED + LTEXT "FP18",IDC_STATIC,123,37,18,8 + EDITTEXT IDC_FP19,145,49,89,12,WS_DISABLED + LTEXT "FP19",IDC_STATIC,123,51,18,8 + EDITTEXT IDC_FP20,145,63,89,12,WS_DISABLED + LTEXT "FP20",IDC_STATIC,123,65,18,8 + EDITTEXT IDC_FP21,145,77,89,12,WS_DISABLED + LTEXT "FP21",IDC_STATIC,123,79,18,8 + EDITTEXT IDC_FP22,145,91,89,12,WS_DISABLED + LTEXT "FP22",IDC_STATIC,123,93,18,8 + EDITTEXT IDC_FP23,145,105,89,12,WS_DISABLED + LTEXT "FP23",IDC_STATIC,123,107,18,8 + EDITTEXT IDC_FP24,145,119,89,12,WS_DISABLED + LTEXT "FP24",IDC_STATIC,123,121,18,8 + EDITTEXT IDC_FP25,145,133,89,12,WS_DISABLED + LTEXT "FP25",IDC_STATIC,123,135,18,8 + EDITTEXT IDC_FP26,145,147,89,12,WS_DISABLED + LTEXT "FP26",IDC_STATIC,123,149,18,8 + EDITTEXT IDC_FP27,145,161,89,12,WS_DISABLED + LTEXT "FP27",IDC_STATIC,123,163,18,8 + EDITTEXT IDC_FP28,145,175,89,12,WS_DISABLED + LTEXT "FP28",IDC_STATIC,123,177,18,8 + EDITTEXT IDC_FP29,145,189,89,12,WS_DISABLED + LTEXT "FP29",IDC_STATIC,123,191,18,8 + EDITTEXT IDC_FP30,145,203,89,12,WS_DISABLED + LTEXT "FP30",IDC_STATIC,123,205,18,8 + EDITTEXT IDC_FP31,145,218,89,12,WS_DISABLED + LTEXT "FP31",IDC_STATIC,123,219,18,8 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDVERT | SS_SUNKEN,244,8,1,223 + LTEXT "Implementation/Revision Reg",IDC_STATIC,253,9,94,8 + EDITTEXT IDC_FCR0,298,21,50,12,WS_DISABLED + LTEXT "FCR0",IDC_STATIC,253,23,19,8 + LTEXT "Control/Status Register",IDC_STATIC,253,37,74,8 + EDITTEXT IDC_FCR31,298,49,50,12,WS_DISABLED + LTEXT "FCR31",IDC_STATIC,253,51,23,8 + LTEXT "Accumulator",IDC_STATIC,256,68,43,14 + EDITTEXT IDC_FPU_ACC,299,68,49,12,ES_AUTOHSCROLL | WS_DISABLED +END + +IDD_VU0INTEGER DIALOG 0, 0, 357, 263 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "VUO Integer & Control Registers" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_VU0_VI00,29,7,89,12,WS_DISABLED + LTEXT "VI00",IDC_STATIC,7,9,16,8 + EDITTEXT IDC_VU0_VI01,29,21,89,12,WS_DISABLED + LTEXT "VI01",IDC_STATIC,7,23,16,8 + EDITTEXT IDC_VU0_VI02,29,35,89,12,WS_DISABLED + LTEXT "VI02",IDC_STATIC,7,37,16,8 + EDITTEXT IDC_VU0_VI03,29,49,89,12,WS_DISABLED + LTEXT "VI03",IDC_STATIC,7,51,16,8 + EDITTEXT IDC_VU0_VI04,29,63,89,12,WS_DISABLED + LTEXT "VI04",IDC_STATIC,7,65,16,8 + EDITTEXT IDC_VU0_VI05,29,77,89,12,WS_DISABLED + LTEXT "VI05",IDC_STATIC,7,79,16,8 + EDITTEXT IDC_VU0_VI06,29,91,89,12,WS_DISABLED + LTEXT "VI06",IDC_STATIC,7,93,16,8 + EDITTEXT IDC_VU0_VI07,29,105,89,12,WS_DISABLED + LTEXT "VI07",IDC_STATIC,7,107,16,8 + EDITTEXT IDC_VU0_VI08,29,119,89,12,WS_DISABLED + LTEXT "VI08",IDC_STATIC,7,121,16,8 + EDITTEXT IDC_VU0_VI09,29,133,89,12,WS_DISABLED + LTEXT "VI09",IDC_STATIC,7,135,16,8 + EDITTEXT IDC_VU0_VI10,29,147,89,12,WS_DISABLED + LTEXT "VI10",IDC_STATIC,7,149,16,8 + EDITTEXT IDC_VU0_VI11,29,161,89,12,WS_DISABLED + LTEXT "VI11",IDC_STATIC,7,163,16,8 + EDITTEXT IDC_VU0_VI12,29,175,89,12,WS_DISABLED + LTEXT "VI12",IDC_STATIC,7,177,16,8 + EDITTEXT IDC_VU0_VI13,29,189,89,12,WS_DISABLED + LTEXT "VI13",IDC_STATIC,7,191,16,8 + EDITTEXT IDC_VU0_VI14,29,203,89,12,WS_DISABLED + LTEXT "VI14",IDC_STATIC,7,205,16,8 + EDITTEXT IDC_VU0_VI15,29,218,89,12,WS_DISABLED + LTEXT "VI15",IDC_STATIC,7,219,16,8 + EDITTEXT IDC_VU0_VI16,172,7,89,12,WS_DISABLED + LTEXT "Status Flag",IDC_STATIC,123,9,36,8 + EDITTEXT IDC_VU0_VI17,172,21,89,12,WS_DISABLED + LTEXT "MAC Flag",IDC_STATIC,123,23,32,8 + EDITTEXT IDC_VU0_VI18,172,35,89,12,WS_DISABLED + LTEXT "Clipping Flag",IDC_STATIC,123,37,41,8 + EDITTEXT IDC_VU0_VI19,172,49,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,51,8,8 + EDITTEXT IDC_VU0_VI20,172,63,89,12,WS_DISABLED + LTEXT "R register",IDC_STATIC,123,65,31,8 + EDITTEXT IDC_VU0_VI21,172,77,89,12,WS_DISABLED + LTEXT "I register",IDC_STATIC,123,79,28,8 + EDITTEXT IDC_VU0_VI22,172,91,89,12,WS_DISABLED + LTEXT "Q register",IDC_STATIC,123,93,31,8 + EDITTEXT IDC_VU0_VI23,172,105,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,107,8,8 + EDITTEXT IDC_VU0_VI24,172,119,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,121,8,8 + EDITTEXT IDC_VU0_VI25,172,133,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,135,8,8 + EDITTEXT IDC_VU0_VI26,172,147,89,12,WS_DISABLED + LTEXT "TPC register",IDC_STATIC,123,149,40,8 + EDITTEXT IDC_VU0_VI27,172,161,89,12,WS_DISABLED + LTEXT "CMSAR0 reg",IDC_STATIC,123,163,42,8 + EDITTEXT IDC_VU0_VI28,172,175,89,12,WS_DISABLED + LTEXT "FBRST register",IDC_STATIC,123,177,49,8 + EDITTEXT IDC_VU0_VI29,172,189,89,12,WS_DISABLED + LTEXT "VPU-STAT reg",IDC_STATIC,123,191,48,8 + EDITTEXT IDC_VU0_VI30,172,203,89,12,WS_DISABLED + LTEXT "",IDC_STATIC,123,205,8,8 + EDITTEXT IDC_VU0_VI31,172,218,89,12,WS_DISABLED + LTEXT "CMSAR1 reg",IDC_STATIC,123,219,42,8 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDVERT | SS_SUNKEN,273,7,1,222 + LTEXT "Accumulator",IDC_STATIC,27,238,43,14 + EDITTEXT IDC_VU0_ACC,78,239,166,12,ES_READONLY + LTEXT "P register",IDC_STATIC,124,108,30,8 +END + +IDD_VU1REGS DIALOG 0, 0, 391, 279 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "VU1Floating Point Registers" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_VU1_VF00,28,7,166,12,ES_READONLY + LTEXT "VF00",-1,7,9,18,8 + EDITTEXT IDC_VU1_VF01,28,21,166,12,ES_READONLY + LTEXT "VF01",-1,7,23,18,8 + EDITTEXT IDC_VU1_VF02,28,35,166,12,ES_READONLY + LTEXT "VF02",-1,7,37,18,8 + EDITTEXT IDC_VU1_VF03,28,49,166,12,ES_READONLY + LTEXT "VF03",-1,7,51,18,8 + EDITTEXT IDC_VU1_VF04,28,63,166,12,ES_READONLY + LTEXT "VF04",-1,7,65,18,8 + EDITTEXT IDC_VU1_VF05,28,77,166,12,ES_READONLY + LTEXT "VF05",-1,7,79,18,8 + EDITTEXT IDC_VU1_VF06,28,91,166,12,ES_READONLY + LTEXT "VF06",-1,7,93,18,8 + EDITTEXT IDC_VU1_VF07,28,105,166,12,ES_READONLY + LTEXT "VF07",-1,7,107,18,8 + EDITTEXT IDC_VU1_VF08,28,119,166,12,ES_READONLY + LTEXT "VF08",-1,7,121,18,8 + EDITTEXT IDC_VU1_VF09,28,133,166,12,ES_READONLY + LTEXT "VF09",-1,7,135,18,8 + EDITTEXT IDC_VU1_VF10,28,147,166,12,ES_READONLY + LTEXT "VF10",-1,7,149,18,8 + EDITTEXT IDC_VU1_VF11,28,161,166,12,ES_READONLY + LTEXT "VF11",-1,7,163,18,8 + EDITTEXT IDC_VU1_VF12,28,175,166,12,ES_READONLY + LTEXT "VF12",-1,7,177,18,8 + EDITTEXT IDC_VU1_VF13,28,189,166,12,ES_READONLY + LTEXT "VF13",-1,7,191,18,8 + EDITTEXT IDC_VU1_VF14,28,203,166,12,ES_READONLY + LTEXT "VF14",-1,7,205,18,8 + EDITTEXT IDC_VU1_VF15,28,218,166,12,ES_READONLY + LTEXT "VF15",-1,7,219,18,8 + EDITTEXT IDC_VU1_VF16,214,7,165,12,ES_READONLY + LTEXT "VF16",-1,196,10,18,8 + EDITTEXT IDC_VU1_VF17,214,20,166,12,ES_READONLY + LTEXT "VF17",-1,196,22,18,8 + EDITTEXT IDC_VU1_VF18,214,35,166,12,ES_READONLY + LTEXT "VF18",-1,196,36,18,8 + EDITTEXT IDC_VU1_VF19,214,49,165,12,ES_READONLY + LTEXT "VF19",-1,196,52,18,8 + EDITTEXT IDC_VU1_VF20,214,63,165,12,ES_READONLY + LTEXT "VF20",-1,196,66,18,8 + EDITTEXT IDC_VU1_VF21,214,76,165,12,ES_READONLY + LTEXT "VF21",-1,196,80,18,8 + EDITTEXT IDC_VU1_VF22,214,91,165,12,ES_READONLY + LTEXT "VF22",-1,196,94,18,8 + EDITTEXT IDC_VU1_VF23,214,105,165,12,ES_READONLY + LTEXT "VF23",-1,196,108,18,8 + EDITTEXT IDC_VU1_VF24,214,119,165,12,ES_READONLY + LTEXT "VF24",-1,196,121,18,8 + EDITTEXT IDC_VU1_VF25,214,132,165,12,ES_READONLY + LTEXT "VF25",-1,196,135,18,8 + EDITTEXT IDC_VU1_VF26,214,147,165,12,ES_READONLY + LTEXT "VF26",-1,196,149,18,8 + EDITTEXT IDC_VU1_VF27,214,161,165,12,ES_READONLY + LTEXT "VF27",-1,196,163,18,8 + EDITTEXT IDC_VU1_VF28,214,175,165,12,ES_READONLY + LTEXT "VF28",-1,196,178,18,8 + EDITTEXT IDC_VU1_VF29,214,188,165,12,ES_READONLY + LTEXT "VF29",-1,196,190,18,8 + EDITTEXT IDC_VU1_VF30,214,203,165,12,ES_READONLY + LTEXT "VF30",-1,196,205,18,8 + EDITTEXT IDC_VU1_VF31,214,217,165,12,ES_READONLY + LTEXT "VF31",-1,196,220,18,8 +END + +IDD_RDEBUGPARAMS DIALOGEX 0, 0, 174, 58 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Remote Debugging" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,7,37,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,37,50,14 + EDITTEXT IDC_PORT,127,7,40,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Accept connections on TCP/IP port:",IDC_STATIC,7,7,120,10 + CONTROL "Debug Bios",IDC_DEBUGBIOS,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,22,50,10 +END + +IDD_RDEBUG DIALOGEX 0, 0, 254, 271 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Remote Debugging" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "E&xit",IDOK,199,251,48,14 + LISTBOX IDC_COMMUNICATION,7,7,240,211,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + PUSHBUTTON "&Clear",IDC_CLEAR,199,229,48,14 + EDITTEXT IDC_EEPC,74,229,52,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_IOPPC,132,229,52,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "EE pc address:\t IOP pc address:",IDC_STATIC,77,219,113,9 + CONTROL "Debug EE",IDC_DEBUGEE,"Button",BS_AUTORADIOBUTTON,77,255,48,10 + CONTROL "Debug IOP",IDC_DEBUGIOP,"Button",BS_AUTORADIOBUTTON | BS_LEFTTEXT,132,254,50,11 + EDITTEXT IDC_STOPAT,7,229,56,13,ES_AUTOHSCROLL + EDITTEXT IDC_STOPAFTER,7,252,56,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Break at (hex addr):",IDC_STATIC,7,219,67,8 + LTEXT "Break after (cycles):",IDC_STATIC,7,243,66,8 + EDITTEXT IDC_EECYCLE,74,241,52,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_IOPCYCLE,132,241,52,12,ES_AUTOHSCROLL | ES_READONLY +END + +IDD_MCDCONF DIALOGEX 0, 0, 466, 261 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Memcard Manager" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,147,236,50,14 + PUSHBUTTON "Cancel",IDCANCEL,209,236,50,14 + EDITTEXT IDC_MCD1,10,208,160,14,ES_MULTILINE | ES_AUTOHSCROLL + EDITTEXT IDC_MCD2,259,208,160,14,ES_AUTOHSCROLL + PUSHBUTTON "Select Mcd",IDC_MCDSEL1,10,171,50,14 + PUSHBUTTON "Select Mcd",IDC_MCDSEL2,261,171,50,14 + GROUPBOX "Memory Card 2",IDC_FRAMEMCD2,258,5,194,157 + PUSHBUTTON "Format Mcd",IDC_FORMAT1,65,171,50,14 + GROUPBOX "Memory Card 1",IDC_FRAMEMCD1,5,5,195,156 + PUSHBUTTON "Format Mcd",IDC_FORMAT2,316,171,50,14 + PUSHBUTTON "Reload Mcd",IDC_RELOAD1,120,171,50,14 + PUSHBUTTON "Reload Mcd",IDC_RELOAD2,371,171,50,14 + PUSHBUTTON "-> Copy ->",IDC_COPYTO2,206,30,45,14 + PUSHBUTTON "<- Copy <-",IDC_COPYTO1,206,50,45,14 + PUSHBUTTON "Paste",IDC_PASTE,206,70,45,14 + PUSHBUTTON "<- Un/Delete",IDC_DELETE1,206,90,45,14 + PUSHBUTTON "Un/Delete ->",IDC_DELETE2,206,110,45,14 + CONTROL "",IDC_TREE1,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,10,14,160,112 + CONTROL "",IDC_TREE2,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,262,15,160,112 + CONTROL "",IDC_ICON1,"Static",SS_BLACKFRAME | SS_REALSIZEIMAGE | NOT WS_VISIBLE | WS_BORDER,165,141,88,82 + PUSHBUTTON "Load Icon",IDC_LOADICO1,10,190,50,14 + PUSHBUTTON "Save File",IDC_SAVE1,65,190,50,14 + PUSHBUTTON "Load Icon",IDC_LOADICO2,261,189,50,14 + PUSHBUTTON "Save File",IDC_SAVE2,317,189,50,14 + CONTROL "",IDC_ICON2,"Static",SS_BLACKFRAME | SS_REALSIZEIMAGE | NOT WS_VISIBLE | WS_BORDER,168,146,88,82 + CONTROL "",IDC_LIST1,"SysListView32",LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,10,14,185,143 + CONTROL "",IDC_LIST2,"SysListView32",LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,262,15,185,143 +END + +IDD_DUMPMEM DIALOG 0, 0, 175, 95 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Dump memory" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_DUMPMEM_START,73,14,82,13 + EDITTEXT IDC_DUMPMEM_END,73,29,82,13 + EDITTEXT IDC_DUMPMEM_FNAME,73,50,82,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,25,74,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,74,50,14 + LTEXT "Start Address:",IDC_STATIC,19,17,52,8 + LTEXT "End Address:",IDC_STATIC,19,32,50,8 + LTEXT "Filename:",IDC_STATIC,19,53,31,8 +END + +IDD_DIALOGBAR DIALOGEX 0, 0, 330, 16 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "TODO: layout dialog bar",IDC_STATIC,126,4,77,8 +END + +IDD_IOPREGS DIALOGEX 0, 0, 417, 295 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "IOP Main Registers" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_IOPGPR0,22,20,166,12,ES_READONLY + LTEXT "R0",-1,7,23,10,8 + EDITTEXT IDC_IOPGPR1,22,34,166,12,ES_READONLY + LTEXT "AT",-1,7,36,10,8 + EDITTEXT IDC_IOPGPR2,22,49,166,12,ES_READONLY + LTEXT "V0",-1,7,50,10,8 + EDITTEXT IDC_IOPGPR3,22,63,166,12,ES_READONLY + LTEXT "V1",-1,7,65,10,8 + EDITTEXT IDC_IOPGPR4,22,76,166,12,ES_READONLY + LTEXT "A0",-1,7,79,10,8 + EDITTEXT IDC_IOPGPR5,22,90,166,12,ES_READONLY + LTEXT "A1",-1,7,92,10,8 + EDITTEXT IDC_IOPGPR6,22,105,166,12,ES_READONLY + LTEXT "A2",-1,7,106,10,8 + EDITTEXT IDC_IOPGPR7,22,119,166,12,ES_READONLY + LTEXT "A3",-1,7,121,10,8 + EDITTEXT IDC_IOPGPR8,22,132,166,12,ES_READONLY + LTEXT "T0",-1,7,135,10,8 + EDITTEXT IDC_IOPGPR9,22,146,166,12,ES_READONLY + LTEXT "T1",-1,7,148,10,8 + EDITTEXT IDC_IOPGPR10,22,161,166,12,ES_READONLY + LTEXT "T2",-1,7,162,10,8 + EDITTEXT IDC_IOPGPR11,22,175,166,12,ES_READONLY + LTEXT "T3",-1,7,177,10,8 + EDITTEXT IDC_IOPGPR12,22,188,166,12,ES_READONLY + LTEXT "T4",-1,7,191,10,8 + EDITTEXT IDC_IOPGPR13,22,202,166,12,ES_READONLY + LTEXT "T5",-1,7,204,10,8 + EDITTEXT IDC_IOPGPR14,22,217,166,12,ES_READONLY + LTEXT "T6",-1,7,218,10,8 + EDITTEXT IDC_IOPGPR15,22,231,166,12,ES_READONLY + LTEXT "T7",-1,7,233,10,8 + EDITTEXT IDC_IOPGPR16,214,20,165,12,ES_READONLY + LTEXT "S0",-1,196,23,10,8 + EDITTEXT IDC_IOPGPR17,214,34,166,12,ES_READONLY + LTEXT "S1",-1,196,36,10,8 + EDITTEXT IDC_IOPGPR18,214,49,166,12,ES_READONLY + LTEXT "S2",-1,196,50,10,8 + EDITTEXT IDC_IOPGPR19,214,63,165,12,ES_READONLY + LTEXT "S3",-1,196,66,10,8 + EDITTEXT IDC_IOPGPR20,214,76,165,12,ES_READONLY + LTEXT "S4",-1,196,79,10,8 + EDITTEXT IDC_IOPGPR21,214,90,165,12,ES_READONLY + LTEXT "S5",-1,196,94,10,8 + EDITTEXT IDC_IOPGPR22,214,105,165,12,ES_READONLY + LTEXT "S6",-1,196,108,10,8 + EDITTEXT IDC_IOPGPR23,214,119,165,12,ES_READONLY + LTEXT "S7",-1,196,122,10,8 + EDITTEXT IDC_IOPGPR24,214,132,165,12,ES_READONLY + LTEXT "T8",-1,196,135,10,8 + EDITTEXT IDC_IOPGPR25,214,146,165,12,ES_READONLY + LTEXT "T9",-1,196,148,10,8 + EDITTEXT IDC_IOPGPR26,214,161,165,12,ES_READONLY + LTEXT "K0",-1,196,162,10,8 + EDITTEXT IDC_IOPGPR27,214,175,165,12,ES_READONLY + LTEXT "K1",-1,196,177,10,8 + EDITTEXT IDC_IOPGPR28,214,188,165,12,ES_READONLY + LTEXT "GP",-1,196,191,11,8 + EDITTEXT IDC_IOPGPR29,214,202,165,12,ES_READONLY + LTEXT "SP",-1,196,204,10,8 + EDITTEXT IDC_IOPGPR30,214,217,165,12,ES_READONLY + LTEXT "S8",-1,196,218,10,8 + EDITTEXT IDC_IOPGPR31,214,231,165,12,ES_READONLY + LTEXT "RA",-1,196,234,11,8 + EDITTEXT IDC_IOPGPR_PC,20,272,57,12,ES_READONLY + LTEXT "PC",-1,7,276,10,8 + EDITTEXT IDC_IOPGPR_HI,21,252,167,12,ES_READONLY + LTEXT "HI",-1,7,255,8,8 + LTEXT "LO",-1,196,255,10,8 + EDITTEXT IDC_IOPGPR_LO,214,252,165,12,ES_READONLY +END + +IDD_USERNAME DIALOGEX 0, 0, 186, 79 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter User Name" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,7,58,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,58,50,14 + LTEXT "Pcsx2 needs to allocate physical memory in order to execute faster. Enter the windows username you wish this privilege to be enabled for.",IDC_STATIC,7,7,172,25 + EDITTEXT IDC_USER_NAME,73,37,106,13,ES_AUTOHSCROLL + LTEXT "User Name:",IDC_STATIC,7,41,38,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_RDEBUGPARAMS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 167 + TOPMARGIN, 7 + BOTTOMMARGIN, 51 + END + + IDD_RDEBUG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 247 + TOPMARGIN, 7 + BOTTOMMARGIN, 265 + END + + IDD_MCDCONF, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 299 + TOPMARGIN, 7 + BOTTOMMARGIN, 178 + END + + IDD_DIALOGBAR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 323 + TOPMARGIN, 7 + BOTTOMMARGIN, 9 + END + + IDD_IOPREGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 410 + TOPMARGIN, 7 + BOTTOMMARGIN, 284 + END + + IDD_USERNAME, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 72 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_PS2SILVER BITMAP "ps2_silver.bmp" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +ABOUT_DIALOG DIALOGEX 0, 0, 431, 270 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_ACCEPTFILES +CAPTION "About" +FONT 8, "Microsoft Sans Serif", 400, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,205,250,50,14 + CTEXT "PCSX2 \nVersion x.x",IDC_PCSX_ABOUT_TEXT,55,10,45,15,0,WS_EX_TRANSPARENT + CTEXT "PCSX2 a PS2 Emulator...",IDC_PCSX_ABOUT_AUTHORS,9,36,135,92,0,WS_EX_TRANSPARENT + CTEXT "Greets to...",IDC_PCSX_ABOUT_GREETS,88,158,311,77 + GROUPBOX "",IDC_STATIC,5,29,145,113 + GROUPBOX "",IDC_STATIC,77,148,333,91 + CONTROL 132,IDC_PS2SILVER_RECT,"Static",SS_BITMAP,0,167,70,74 +END + +IDD_HACKS DIALOGEX 0, 0, 186, 103 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "PCSX2 Speed Hacks" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,41,82,50,14 + PUSHBUTTON "Cancel",IDCANCEL,96,82,50,14 + CONTROL "EE/IOP Sync Hack - General Speedup",IDC_SYNCHACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,172,10 + CONTROL "Disable Forced ABS - Speeds up intense 3D",IDC_ABSHACK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,34,160,10 + CTEXT "These hacks will effect the speed of PCSX2 but possibly comprimise on compatability",IDC_HACKDESC,7,7,172,17 + CONTROL "Tighter SPU2 Sync ( FFXII vids) - slower",IDC_SOUNDHACK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,59,154,9 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + ABOUT_DIALOG, DIALOG + BEGIN + RIGHTMARGIN, 429 + BOTTOMMARGIN, 264 + END + + IDD_HACKS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 96 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +SPLASH_LOGO BITMAP "..\\pcsxAbout.bmp" +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Spanish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_FINDER DIALOGEX 3, 1, 262, 212 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Cheat Finder" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Results",IDC_RESULTS,"SysListView32",LVS_REPORT | WS_TABSTOP,96,15,161,153,WS_EX_CLIENTEDGE + GROUPBOX "Values of size",IDC_STATIC,5,44,86,45 + CHECKBOX "Unsigned",IDC_UNSIGNED,11,74,70,10,NOT WS_TABSTOP + CONTROL "64bits",IDC_64B,"Button",BS_AUTORADIOBUTTON | WS_GROUP,48,64,33,10 + CONTROL "32bits",IDC_32B,"Button",BS_AUTORADIOBUTTON | WS_GROUP,48,54,33,10 + CONTROL "16bits",IDC_16B,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,64,33,10 + CONTROL "8bits",IDC_8B,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,54,33,10 + PUSHBUTTON "Close",IDCANCEL,208,192,49,15,NOT WS_TABSTOP + PUSHBUTTON "Search",IDC_SEARCH,96,192,49,15,NOT WS_TABSTOP + GROUPBOX "Comapred to",IDC_STATIC,5,162,86,45 + EDITTEXT IDC_VALUE,21,192,65,12,ES_AUTOHSCROLL | NOT WS_TABSTOP + CONTROL "Specific Value",IDC_SET,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,182,75,10 + CONTROL "Old Value",IDC_OLD,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,172,75,10 + GROUPBOX "Search in",IDC_STATIC,5,5,86,35 + CONTROL "Smaller or equal",IDC_LE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,139,75,10 + CONTROL "Greater or equal",IDC_GE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,129,75,10 + CONTROL "Smaller",IDC_LT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,120,75,10 + CONTROL "Greater",IDC_GT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,110,75,10 + CONTROL "Equal",IDC_EQ,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,101,75,10 + PUSHBUTTON "Reset",IDC_RESET,96,172,49,15,NOT WS_TABSTOP + PUSHBUTTON "Add",IDC_ADD,208,172,49,15,NOT WS_TABSTOP + RTEXT "1 match found.",IDC_MATCHES,125,5,132,10,NOT WS_GROUP + LTEXT "Results:",IDC_STATIC,96,5,29,10,NOT WS_GROUP + CONTROL "EE RAM",IDC_EE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,15,43,10 + CONTROL "IOP RAM",IDC_IOP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,25,43,10 + CONTROL "Not equal",IDC_NE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,148,75,10 + GROUPBOX "being",IDC_STATIC,5,92,86,67 +END + +IDD_ADD DIALOGEX 3, 1, 145, 74 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Add Cheat" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "OK",IDOK,37,54,49,15,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,91,54,49,15,NOT WS_TABSTOP + LTEXT "Cheat Name",IDC_STATIC,5,30,75,10,NOT WS_GROUP + LTEXT "New Value",IDC_STATIC,69,5,70,10,NOT WS_GROUP + LTEXT "Address",IDC_STATIC,5,5,59,10,NOT WS_GROUP + EDITTEXT IDC_NAME,5,39,134,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_VALUE,69,15,70,12,ES_AUTOHSCROLL | NOT WS_TABSTOP + EDITTEXT IDC_ADDR,5,15,59,12,ES_AUTOHSCROLL | NOT WS_TABSTOP +END + +IDD_CHEATS DIALOGEX 0, 0, 345, 198 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Patch List" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Exit",IDCANCEL,288,175,50,14 + CONTROL "",IDC_GROUPS,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_EDITLABELS | TVS_CHECKBOXES | NOT WS_VISIBLE | WS_TABSTOP,7,7,230,126,WS_EX_CLIENTEDGE + CONTROL "",IDC_PATCHES,"SysListView32",LVS_REPORT | WS_TABSTOP,7,7,270,183,WS_EX_CLIENTEDGE + PUSHBUTTON "Enable/Disable",IDC_ENABLEBUTTON,287,7,51,14 + PUSHBUTTON "Add GS2v3-4",IDC_ADDGS,287,62,51,14 + PUSHBUTTON "Edit Patch",IDC_EDITPATCH,287,43,51,14 + PUSHBUTTON "Add Patch",IDC_ADDPATCH,287,25,51,14 + PUSHBUTTON "Add RAW",IDC_ADDRAW,287,81,51,14 + DEFPUSHBUTTON "OK",IDOK,288,155,50,14,NOT WS_VISIBLE + PUSHBUTTON "pnach Writer",IDC_PNACHWRITER,287,100,51,14 + PUSHBUTTON "Skip MPEG",IDC_SKIPMPEG,287,119,51,14 +END + +IDD_ADDGS DIALOGEX 3, 1, 145, 117 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Add Cheat" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "Add",IDOK,91,98,49,15,NOT WS_TABSTOP + PUSHBUTTON "Convert",IDC_CONVERT,38,98,49,15,NOT WS_TABSTOP + EDITTEXT IDC_CONVERTEDCODE,5,58,134,33,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP + LTEXT "Converted code:",-1,5,46,75,10,NOT WS_GROUP + LTEXT "GS2v3-4(GSv5 remove first line):",-1,5,5,123,10,NOT WS_GROUP + LTEXT "Static",IDC_ADDRESS,1,101,8,7,NOT WS_VISIBLE + LTEXT "Static",IDC_VALUE,126,47,8,7,NOT WS_VISIBLE + LTEXT "0",IDC_READY,17,104,9,6,NOT WS_VISIBLE + EDITTEXT IDC_ADDR,5,15,132,28,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | NOT WS_TABSTOP +END + +IDD_EDITPATCH DIALOGEX 3, 1, 145, 154 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Edit Patch" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,91,135,49,15,NOT WS_TABSTOP + PUSHBUTTON "Save",IDC_SAVE,38,135,49,15,NOT WS_TABSTOP + LTEXT "Address:",IDC_STATIC,5,4,50,10 + EDITTEXT IDC_ADDRESS,58,3,69,12,ES_AUTOHSCROLL + LTEXT "Data:",IDC_STATIC,5,22,50,10 + EDITTEXT IDC_DATA,58,21,69,12,ES_AUTOHSCROLL + LTEXT "Group:",IDC_STATIC,5,39,50,10 + EDITTEXT IDC_GROUP,58,38,69,12,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS,132,36,11,20 + LTEXT "CPU:",IDC_STATIC,5,58,50,10 + LTEXT "Enabled:",IDC_STATIC,5,76,50,10 + LTEXT "PlaceToPatch:",IDC_STATIC,5,94,50,10 + LTEXT "Type:",IDC_STATIC,5,111,50,10 + COMBOBOX IDC_CPU,57,56,70,37,CBS_DROPDOWNLIST | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_ENABLED,57,74,70,38,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_PLACETOPATCH,57,92,70,35,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_TYPE,57,109,70,54,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_ADDRAW DIALOGEX 3, 1, 145, 71 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Add Cheat" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "Add",IDOK,91,51,49,15,NOT WS_TABSTOP + LTEXT "Enter RAW codes:",-1,5,5,123,10,NOT WS_GROUP + EDITTEXT IDC_ADDR,5,15,132,28,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,38,51,49,15,NOT WS_TABSTOP +END + +IDD_PNACHWRITER DIALOGEX 3, 1, 146, 161 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "pnach Writer" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,91,141,49,15,NOT WS_TABSTOP + PUSHBUTTON "Save",IDC_SAVE,38,141,49,15,NOT WS_TABSTOP + LTEXT "CRC:",IDC_STATIC,5,5,50,10 + EDITTEXT IDC_CRC,58,4,69,12,ES_AUTOHSCROLL + LTEXT "Comment:",IDC_STATIC,5,22,50,10 + EDITTEXT IDC_COMMENT,58,21,69,12,ES_AUTOHSCROLL + LTEXT "Gametitle:",IDC_STATIC,5,39,50,10 + EDITTEXT IDC_GAMETITLE,58,38,69,12,ES_AUTOHSCROLL + LTEXT "Round Mode:",IDC_STATIC,5,123,50,10 + LTEXT "Fastmemory:",IDC_STATIC,5,76,50,10 + COMBOBOX IDC_ROUND2,102,122,39,63,CBS_DROPDOWNLIST | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_ROUND1,57,122,41,79,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Check1",IDC_FASTMEMORY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,58,76,9,8 + LTEXT "Zerogs:",IDC_STATIC,5,54,50,10 + EDITTEXT IDC_ZEROGS,57,54,69,12,ES_AUTOHSCROLL + LTEXT "Path3 Hack:",IDC_STATIC,6,91,50,10 + CONTROL "Check1",IDC_PATH3HACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,58,91,9,8 + LTEXT "vunanmode:",IDC_STATIC,5,107,50,10 + CONTROL "Check1",IDC_VUNANMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,58,107,9,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CHEATS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 338 + TOPMARGIN, 7 + BOTTOMMARGIN, 191 + END + + IDD_ADDGS, DIALOG + BEGIN + BOTTOMMARGIN, 74 + END + + IDD_EDITPATCH, DIALOG + BEGIN + VERTGUIDE, 58 + VERTGUIDE, 127 + BOTTOMMARGIN, 150 + HORZGUIDE, 19 + HORZGUIDE, 36 + HORZGUIDE, 54 + HORZGUIDE, 72 + HORZGUIDE, 90 + HORZGUIDE, 108 + HORZGUIDE, 124 + HORZGUIDE, 126 + END + + IDD_ADDRAW, DIALOG + BEGIN + BOTTOMMARGIN, 66 + END + + IDD_PNACHWRITER, DIALOG + BEGIN + RIGHTMARGIN, 145 + VERTGUIDE, 58 + VERTGUIDE, 127 + BOTTOMMARGIN, 157 + HORZGUIDE, 19 + HORZGUIDE, 36 + HORZGUIDE, 54 + HORZGUIDE, 72 + HORZGUIDE, 90 + HORZGUIDE, 108 + HORZGUIDE, 124 + HORZGUIDE, 126 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Spanish resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 317, 244 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_LISTGS,10,15,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGGS,10,35,45,12 + PUSHBUTTON "Test...",IDC_TESTGS,60,35,45,12 + PUSHBUTTON "About...",IDC_ABOUTGS,110,35,45,12 + COMBOBOX IDC_LISTSPU2,166,15,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGSPU2,165,35,45,12 + PUSHBUTTON "Test...",IDC_TESTSPU2,215,35,45,12 + PUSHBUTTON "About...",IDC_ABOUTSPU2,265,35,43,12 + COMBOBOX IDC_LISTCDVD,10,105,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGCDVD,10,125,43,12 + PUSHBUTTON "Test...",IDC_TESTCDVD,60,125,45,12 + PUSHBUTTON "About...",IDC_ABOUTCDVD,110,125,45,12 + COMBOBOX IDC_LISTBIOS,165,196,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,207,223,50,14 + PUSHBUTTON "Cancel",IDCANCEL,260,223,50,14 + CTEXT "Graphics",IDC_GRAPHICS,50,5,62,10,SS_CENTERIMAGE + CTEXT "Sound",IDC_SOUND,200,5,71,10,SS_CENTERIMAGE + CTEXT "Cdvdrom",IDC_CDVDROM,55,95,56,10,SS_CENTERIMAGE + CTEXT "Bios",IDC_BIOS,208,185,61,10,SS_CENTERIMAGE + COMBOBOX IDC_LISTPAD1,10,60,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGPAD1,10,80,45,12 + PUSHBUTTON "Test...",IDC_TESTPAD1,60,80,45,12 + PUSHBUTTON "About...",IDC_ABOUTPAD1,110,80,45,12 + CTEXT "Second Controller",IDC_SECONDCONTROLLER,191,50,90,10,SS_CENTERIMAGE + COMBOBOX IDC_LISTPAD2,166,60,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGPAD2,165,80,45,12 + PUSHBUTTON "Test...",IDC_TESTPAD2,215,80,45,12 + PUSHBUTTON "About...",IDC_ABOUTPAD2,265,80,45,12 + CTEXT "First Controller",IDC_FIRSTCONTROLLER,41,50,82,10,SS_CENTERIMAGE + PUSHBUTTON "Set Bios Directory",IDC_BIOSDIR,14,223,134,14 + PUSHBUTTON "Set Plugins Directory",IDC_PLUGINSDIR,14,204,134,14 + COMBOBOX IDC_LISTDEV9,165,105,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGDEV9,165,125,43,12 + PUSHBUTTON "Test...",IDC_TESTDEV9,215,125,45,12 + PUSHBUTTON "About...",IDC_ABOUTDEV9,265,125,45,12 + CTEXT "Dev9",IDC_DEV9,221,95,30,10,SS_CENTERIMAGE + COMBOBOX IDC_LISTUSB,10,151,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGUSB,10,170,43,12 + PUSHBUTTON "Test...",IDC_TESTUSB,60,170,45,12 + PUSHBUTTON "About...",IDC_ABOUTUSB,110,170,45,12 + CTEXT "Usb",IDC_USB,59,140,47,10,SS_CENTERIMAGE + COMBOBOX IDC_LISTFW,165,151,145,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_CONFIGFW,165,169,43,12 + PUSHBUTTON "Test...",IDC_TESTFW,214,169,45,12 + PUSHBUTTON "About...",IDC_ABOUTFW,265,169,45,12 + CTEXT "FireWire",IDC_FW,206,141,60,8 +END + +IDD_BPEXEC DIALOG 0, 0, 182, 61 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "BreakPoint on Exec" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_EXECBP,92,10,82,13 + DEFPUSHBUTTON "OK",IDOK,30,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,100,40,50,14 + LTEXT "Enter BreakPoint Address:",IDC_STATIC,5,13,84,8 +END + +IDD_BPCNT DIALOG 0, 0, 182, 61 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "BreakPoint on Count" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_CNTBP,92,10,82,13 + DEFPUSHBUTTON "OK",IDOK,30,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,100,40,50,14 + LTEXT "Enter BreakPoint Count:",IDC_STATIC,5,13,77,8 +END + +IDD_ADVANCED DIALOGEX 0, 0, 177, 69 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Advanced" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,47,50,14 + PUSHBUTTON "Cancel",IDCANCEL,121,47,50,14 + CONTROL "Enable Reg Caching",IDC_REGCACHING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,15,81,10 + GROUPBOX "",IDC_STATIC,2,7,168,38 + PUSHBUTTON "Reset",IDC_ADVRESET,5,47,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + TOPMARGIN, 7 + BOTTOMMARGIN, 237 + HORZGUIDE, 169 + END + + IDD_BPEXEC, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 6 + BOTTOMMARGIN, 54 + END + + IDD_BPCNT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 54 + END + + IDD_ADVANCED, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON ICON "Cdrom02.ico" +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Greek resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ELL) +#ifdef _WIN32 +LANGUAGE LANG_GREEK, SUBLANG_DEFAULT +#pragma code_page(1253) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PATCHBROWSER DIALOGEX 0, 0, 487, 282 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Patches Browser" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "New Patch",IDC_NEWPATCH,112,257,60,14 + EDITTEXT IDC_PATCHTEXT,113,95,354,153,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL + PUSHBUTTON "Save Patch",IDC_SAVEPATCH,186,257,60,14,WS_DISABLED + PUSHBUTTON "Refresh List",IDC_REFRESHPATCHLIST,21,257,60,14 + LISTBOX IDC_PATCHCRCLIST,19,95,69,153,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_PATCHNAMELIST,17,34,452,50,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Search game name patch:",IDC_GAMENAMESEARCH,17,16,101,9 + EDITTEXT IDC_SEARCHPATCHTEXT,109,14,295,12,ES_AUTOHSCROLL + PUSHBUTTON "Exit",IDC_EXITPB,411,257,59,14 +END + +IDD_LOGGING DIALOGEX 0, 0, 263, 177 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Logging" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,206,156,50,14 + CONTROL "Cpu log",IDC_CPULOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,5,53,10 + CONTROL "COP0 log",IDC_COP0LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,20,59,10 + CONTROL "FPU log",IDC_FPULOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,35,55,10 + CONTROL "MMI log",IDC_MMILOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,50,55,10 + CONTROL "VUO log",IDC_VU0LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,65,56,10 + CONTROL "Bios log",IDC_BIOSLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,80,54,10 + CONTROL "DMA log",IDC_DMALOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,95,57,10 + CONTROL "HW log",IDC_HWLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,110,53,10 + CONTROL "Unknown Memory log",IDC_MEMLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,5,84,10 + CONTROL "Elf log",IDC_ELFLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,20,35,10 + CONTROL "VIF log",IDC_VIFLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,35,38,10 + CONTROL "Scratch pad log",IDC_SPRLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,50,66,10 + CONTROL "Gif log",IDC_GIFLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,65,49,10 + CONTROL "SIF log",IDC_SIFLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,80,51,10 + GROUPBOX "IOP",IDC_STATIC,161,7,95,127 + CONTROL "IOP cpu log",IDC_IOPLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,15,67,10 + CONTROL "HW log",IDC_IOPHWLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,30,53,10 + CONTROL "Bios log",IDC_IOPBIOSLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,45,41,10 + CONTROL "Unknown Memory log",IDC_IOPMEMLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,60,85,10 + CONTROL "IPU log",IDC_IPULOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,95,39,10 + CONTROL "DMA log",IDC_IOPDMALOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,75,67,10 + CONTROL "PAD log",IDC_IOPPADLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,90,53,10 + CONTROL "CDR log",IDC_IOPCDRLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,104,43,10 + CONTROL "VUMicro log",IDC_VUMICROLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,110,55,10 + CONTROL "RPC services log",IDC_RPCSERVICES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,125,67,10 + CONTROL "Log to STDOUT",IDC_STDOUTPUTLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,125,68,10 + CONTROL "Log",IDC_LOGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,140,28,10 + CONTROL "Symbols log",IDC_SYMLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,140,53,10 + CONTROL "Counters log",IDC_IOPCNTLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,118,55,10 + CONTROL "EE Counters log",IDC_EECNTLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,165,139,73,11 +END + +IDD_IOP_DEBUG DIALOGEX 0, 0, 358, 107 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Debug" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LISTBOX IDC_DEBUG_DISASM_IOP,7,7,330,92,LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_TABSTOP,WS_EX_TRANSPARENT + SCROLLBAR IDC_DEBUG_SCROLL_IOP,340,7,11,93,SBS_VERT +END + +IDD_CPUDLG DIALOGEX 0, 0, 250, 377 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "EERec - EE/IOP recompiler (need MMX/SSE)",IDC_CPU_EEREC, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,103,236,18 + CONTROL "VU0rec - enable recompiler for VU0 unit",IDC_CPU_VU0REC, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,127,219,18 + CONTROL "VU1rec - enable recompiler for VU1 unit",IDC_CPU_VU1REC, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,144,228,18 + CONTROL "Multi threaded GS mode (MTGS)\n (faster on dual core/HT procs, requires pcsx2 restart)",IDC_CPU_GSMULTI, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,166,236,30 + CONTROL "Dual Core Mode (DC) - Much faster but only valid with MTGS",IDC_CPU_MULTI, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,199,236,26 + CONTROL "Normal - All frames are rendered as fast as possible.",IDC_CPU_FL_NORMAL, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP,14,236,221,17 + CONTROL "Limit - Force frames to normal speeds if too fast.",IDC_CPU_FL_LIMIT, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,14,254,222,15 + CONTROL "Frame Skip - In order to achieve normal speeds,\n some frames are skipped (fast).\n Fps displayed counts skipped frames too.",IDC_CPU_FL_SKIP, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,15,277,221,35 + CONTROL "VU Skip - Same as 'Frame Skip', but tries to skip more.\n Artifacts might be present, but will be faster.",IDC_CPU_FL_SKIPVU, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,15,314,220,31 + DEFPUSHBUTTON "OK",IDOK,59,356,61,14 + PUSHBUTTON "Cancel",IDCANCEL,131,356,61,14,NOT WS_TABSTOP + LTEXT "CPU Vendor",IDC_VENDORNAME,12,23,88,8 + LTEXT "Family",IDC_FAMILYNAME,12,41,88,8 + LTEXT "Cpu Speed",IDC_CPUSPEEDNAME,12,60,88,8 + LTEXT "",IDC_VENDORINPUT,112,24,124,8 + LTEXT "",IDC_FAMILYINPUT,112,41,124,8 + LTEXT "",IDC_FEATURESINPUT,111,79,124,8 + LTEXT "",IDC_CPUSPEEDINPUT,111,61,124,8 + GROUPBOX "VU Recompilers - All options are set by default",IDC_CPU_VUGROUP,7,119,236,46 + GROUPBOX "Frame Limiting",IDC_FRAMELIMIT,7,225,236,127 + LTEXT "Features",IDC_FEATURESNAME,12,78,88,8 + GROUPBOX "",IDC_STATIC,7,7,236,90 + LTEXT "Custom FPS (0=auto):",IDC_CUSTOM_FPS,32,270,73,8 + EDITTEXT IDC_CUSTOMFPS,115,268,53,13,ES_AUTOHSCROLL | ES_NUMBER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 256 + TOPMARGIN, 7 + BOTTOMMARGIN, 170 + END + + IDD_IOP_DEBUG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 351 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + END + + IDD_CPUDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 370 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Greek resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/pcsx2/windows/ps2_silver.bmp b/pcsx2/windows/ps2_silver.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cb58820cdf1d734c0f8889bde4b6023e9feb4e12 GIT binary patch literal 37974 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 0) { +Execute_CheckCycles: + cmp dword ptr [EEsCycle], 0 + jle Execute_Exit + + // calc PSX_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [psxRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + mov %r8d, [REG_BLOCK+4] + mov %r9d, REG_PC + and %r8d, 0x5fffffff + and %r9d, 0x5fffffff + cmp %r8d, %r9d + jne Execute_Recompile + mov %edx, [REG_BLOCK] + and %rdx, 0xfffffff // pFnptr + jnz Execute_Function + +Execute_Recompile: + call psxRecRecompile + mov %edx, [REG_BLOCK] + and %rdx, 0xfffffff // pFnptr + +Execute_Function: + call %rdx + + jmp Execute_CheckCycles + +Execute_Exit: + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + ret + + +// jumped to when invalid psxpc address +.globl psxDispatcher +psxDispatcher: + // EDX contains the current psxpc to jump to, stack contains the jump addr to modify + push %rdx + + // calc PSX_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [psxRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov %eax, REG_PC + mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] + and %eax, PSX_MEMMASK // remove higher bits + and %edx, PSX_MEMMASK + cmp %eax, %edx + je psxDispatcher_CheckPtr + + // recompile + call psxRecRecompile +psxDispatcher_CheckPtr: + mov REG_BLOCKd, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test REG_BLOCKd, REG_BLOCKd + jnz psxDispatcher_CallFn + // throw an exception + int 10 + +psxDispatcher_CallFn: +#endif + + and REG_BLOCK, 0x0fffffff + mov %rdx, REG_BLOCK + pop %rcx // x86Ptr to mod + sub %rdx, %rcx + sub %rdx, 4 + mov [%rcx], %edx + + jmp REG_BLOCK + +.globl psxDispatcherClear +psxDispatcherClear: + // %EDX contains the current psxpc + mov dword ptr [psxRegs + PCOFFSET], %edx + mov %eax, %edx + + // calc PSX_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov REG_BLOCKd, %edx + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov REG_PC, %edx + mov %eax, REG_PC + mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] + and %eax, PSX_MEMMASK // remove higher bits + and %edx, PSX_MEMMASK + cmp %eax, %edx + jne psxDispatcherClear_Recompile + + mov %eax, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test %eax, %eax + jnz psxDispatcherClear_CallFn + // throw an exception + int 10 + +psxDispatcherClear_CallFn: +#endif + + and %rax, 0x0fffffff + jmp %rax + +psxDispatcherClear_Recompile: + call psxRecRecompile + mov %eax, dword ptr [REG_BLOCK] + + // r15 holds the prev x86 pointer + and %rax, 0x0fffffff + mov byte ptr [%r15], 0xe9 // jmp32 + mov %rdx, %rax + sub %rdx, %r15 + sub %rdx, 5 + mov [%r15+1], %edx + + jmp %rax + +// called when jumping to variable psxpc address +.globl psxDispatcherReg +psxDispatcherReg: + + //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + mov %eax, dword ptr [psxRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // check if startpc == psxRegs.pc + cmp REG_PC, dword ptr [REG_BLOCK+BLOCKTYPE_STARTPC] + jne psxDispatcherReg_recomp + + mov REG_BLOCKd, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test %eax, %eax + jnz psxDispatcherReg_CallFn2 + // throw an exception + int 10 +psxDispatcherReg_CallFn2: +#endif + and REG_BLOCK, 0x0fffffff + jmp REG_BLOCK // fnptr + +psxDispatcherReg_recomp: + call psxRecRecompile + + mov %eax, dword ptr [REG_BLOCK] + and %rax, 0x0fffffff + jmp %rax // fnprt + +#else // not x86-64 + +#define REG_PC %ecx +#define REG_BLOCK %esi + +// jumped to when invalid psxpc address +.globl psxDispatcher +psxDispatcher: + // EDX contains the current psxpc to jump to, stack contains the jump addr to modify + push %edx + + // calc PSX_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [psxRegs + PCOFFSET] + mov REG_BLOCK, %eax + mov REG_PC, %eax + shr %eax, 16 + and REG_BLOCK, 0xffff + shl %eax, 2 + add %eax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, dword ptr [%eax] + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov %eax, REG_PC + mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] + and %eax, PSX_MEMMASK // remove higher bits + and %edx, PSX_MEMMASK + cmp %eax, %edx + je psxDispatcher_CheckPtr + + // recompile + push REG_BLOCK + push REG_PC // psxpc + call psxRecRecompile + add %esp, 4 // pop old param + pop REG_BLOCK +psxDispatcher_CheckPtr: + mov REG_BLOCK, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test REG_BLOCK, REG_BLOCK + jnz psxDispatcher_CallFn + // throw an exception + int 10 + +psxDispatcher_CallFn: +#endif + + and REG_BLOCK, 0x0fffffff + mov %edx, REG_BLOCK + pop %ecx // x86Ptr to mod + sub %edx, %ecx + sub %edx, 4 + mov dword ptr [%ecx], %edx + + jmp REG_BLOCK + +.globl psxDispatcherClear +psxDispatcherClear: + // %EDX contains the current psxpc + mov dword ptr [psxRegs + PCOFFSET], %edx + + // calc PSX_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, %edx + mov REG_BLOCK, %edx + shr %eax, 16 + and REG_BLOCK, 0xffff + shl %eax, 2 + add %eax, [psxRecLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, dword ptr [%eax]; + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov %eax, %edx + mov REG_PC, %edx + mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] + and %eax, PSX_MEMMASK // remove higher bits + and %edx, PSX_MEMMASK + cmp %eax, %edx + jne psxDispatcherClear_Recompile + + add %esp, 4 // ignore stack + mov %eax, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test %eax, %eax + jnz psxDispatcherClear_CallFn + // throw an exception + int 10 + +psxDispatcherClear_CallFn: +#endif + + and %eax, 0x0fffffff + jmp %eax + +psxDispatcherClear_Recompile: + push REG_BLOCK + push REG_PC + call psxRecRecompile + add %esp, 4 // pop old param + pop REG_BLOCK + mov %eax, dword ptr [REG_BLOCK] + + pop %ecx // old fnptr + + and %eax, 0x0fffffff + mov byte ptr [%ecx], 0xe9 // jmp32 + mov %edx, %eax + sub %edx, %ecx + sub %edx, 5 + mov dword ptr [%ecx+1], %edx + + jmp %eax + +// called when jumping to variable psxpc address +.globl psxDispatcherReg +psxDispatcherReg: + + //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + mov %edx, dword ptr [psxRegs+PCOFFSET] + mov %ecx, %edx + + shr %edx, 14 + and %edx, 0xfffffffc + add %edx, [psxRecLUT] + mov %edx, dword ptr [%edx] + + mov %eax, %ecx + and %eax, 0xfffc + // %edx += 2*%eax + shl %eax, 1 + add %edx, %eax + + // check if startpc == psxRegs.pc + mov %eax, %ecx + //and %eax, 0x5fffffff // remove higher bits + cmp %eax, dword ptr [%edx+BLOCKTYPE_STARTPC] + jne psxDispatcherReg_recomp + + mov %eax, dword ptr [%edx] + +#ifdef _DEBUG + test %eax, %eax + jnz psxDispatcherReg_CallFn2 + // throw an exception + int 10 +psxDispatcherReg_CallFn2: +#endif + and %eax, 0x0fffffff + jmp %eax // fnptr + +psxDispatcherReg_recomp: + sub %esp, 8 + mov dword ptr [%esp+4], %edx + mov dword ptr [%esp], %ecx + call psxRecRecompile + mov %edx, dword ptr [%esp+4] + add %esp, 8 + + mov %eax, dword ptr [%edx] + and %eax, 0x0fffffff + jmp %eax // fnptr + +#endif diff --git a/pcsx2/x86/aVUzerorec.S b/pcsx2/x86/aVUzerorec.S new file mode 100644 index 0000000000..e4601275cc --- /dev/null +++ b/pcsx2/x86/aVUzerorec.S @@ -0,0 +1,155 @@ +// iR3000A.c assembly routines +// zerofrog(@gmail.com) +.intel_syntax + +.extern svudispfntemp +.extern s_TotalVUCycles +.extern s_callstack +.extern s_vu1esp +.extern s_writeQ +.extern s_writeP +.extern g_curdebugvu +.extern SuperVUGetProgram +.extern SuperVUCleanupProgram +.extern g_sseVUMXCSR +.extern g_sseMXCSR + +// SuperVUExecuteProgram(u32 startpc, int vuindex) +.globl SuperVUExecuteProgram +SuperVUExecuteProgram: +#ifdef __x86_64__ + mov %rax, [%rsp] + mov dword ptr [s_TotalVUCycles], 0 + add %rsp, 8 + mov [s_callstack], %rax + call SuperVUGetProgram + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + // function arguments + push %rdi + push %rsi + +#ifdef _DEBUG + mov s_vu1esp, %rsp +#endif + + ldmxcsr g_sseVUMXCSR + mov dword ptr [s_writeQ], 0xffffffff + mov dword ptr [s_writeP], 0xffffffff + jmp %rax +#else + mov %eax, [%esp] + mov dword ptr s_TotalVUCycles, 0 + add %esp, 4 + mov dword ptr [s_callstack], %eax + call SuperVUGetProgram + mov s_vu1ebp, %ebp + mov s_vu1esi, %esi + mov s_vuedi, %edi + mov s_vuebx, %ebx +#ifdef _DEBUG + mov s_vu1esp, %esp +#endif + + ldmxcsr g_sseVUMXCSR + mov dword ptr s_writeQ, 0xffffffff + mov dword ptr s_writeP, 0xffffffff + jmp %eax +#endif // __x86_64__ + + +.globl SuperVUEndProgram +SuperVUEndProgram: + // restore cpu state + ldmxcsr g_sseMXCSR + +#ifdef __x86_64__ +#ifdef _DEBUG + sub s_vu1esp, %rsp +#endif + + // function arguments for SuperVUCleanupProgram + pop %rsi + pop %rdi + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbx + pop %rbp +#else + mov %ebp, s_vu1ebp + mov %esi, s_vu1esi + mov %edi, s_vuedi + mov %ebx, s_vuebx + +#ifdef _DEBUG + sub s_vu1esp, %esp +#endif +#endif + + call SuperVUCleanupProgram + jmp [s_callstack] // so returns correctly + + +.globl svudispfn +svudispfn: +#ifdef __x86_64__ + mov [g_curdebugvu], %rax + push %rax + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %rbx + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + call svudispfntemp + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rbx + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rax +#else + mov [g_curdebugvu], %eax + mov s_saveecx, %ecx + mov s_saveedx, %edx + mov s_saveebx, %ebx + mov s_saveesi, %esi + mov s_saveedi, %edi + mov s_saveebp, %ebp + + call svudispfntemp + + mov %ecx, s_saveecx + mov %edx, s_saveedx + mov %ebx, s_saveebx + mov %esi, s_saveesi + mov %edi, s_saveedi + mov %ebp, s_saveebp +#endif + ret \ No newline at end of file diff --git a/pcsx2/x86/aVif.S b/pcsx2/x86/aVif.S new file mode 100644 index 0000000000..a929a148a8 --- /dev/null +++ b/pcsx2/x86/aVif.S @@ -0,0 +1,1632 @@ +/*Pcsx2 - Pc Ps2 Emulator + Copyright (C) 2002-2007 Pcsx2 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 + +*/ +.intel_syntax + +.extern _vifRegs +.extern _vifMaskRegs +.extern _vifRow + +#ifdef __x86_64__ +#define VIF_ESP %rsp +#define VIF_SRC %rsi +#define VIF_INC %rcx +#define VIF_DST %rdi +#define VIF_SIZE %edx +#define VIF_TMPADDR %rax +#define VIF_SAVEEBX %r8 +#define VIF_SAVEEBXd %r8d +#else +#define VIF_ESP %esp +#define VIF_SRC %esi +#define VIF_INC %ecx +#define VIF_DST %edi +#define VIF_SIZE %edx +#define VIF_TMPADDR %eax +#define VIF_SAVEEBX %ebx +#define VIF_SAVEEBXd %ebx +#endif + +#define XMM_R0 %xmm0 +#define XMM_R1 %xmm1 +#define XMM_R2 %xmm2 +#define XMM_WRITEMASK %xmm3 +#define XMM_ROWMASK %xmm4 +#define XMM_ROWCOLMASK %xmm5 +#define XMM_ROW %xmm6 +#define XMM_COL %xmm7 + +#define XMM_R3 XMM_COL + +// writing masks +#define UNPACK_Write0_Regular(r0, CL, DEST_OFFSET, MOVDQA) \ + MOVDQA xmmword ptr [VIF_DST+DEST_OFFSET], r0; + +#define UNPACK_Write1_Regular(r0, CL, DEST_OFFSET, MOVDQA) \ + MOVDQA xmmword ptr [VIF_DST], r0; \ + add VIF_DST, VIF_INC; \ + +#define UNPACK_Write0_Mask UNPACK_Write0_Regular +#define UNPACK_Write1_Mask UNPACK_Write1_Regular + +// masked write (dest needs to be in edi) +#define UNPACK_Write0_WriteMask(r0, CL, DEST_OFFSET, MOVDQA) \ + movdqa XMM_WRITEMASK, xmmword ptr [VIF_TMPADDR + 64*(CL) + 48]; \ + pand r0, XMM_WRITEMASK; \ + pandn XMM_WRITEMASK, xmmword ptr [VIF_DST]; \ + por r0, XMM_WRITEMASK; \ + MOVDQA xmmword ptr [VIF_DST], r0; \ + add VIF_DST, 16; \ + +// masked write (dest needs to be in edi) +#define UNPACK_Write1_WriteMask(r0, CL, DEST_OFFSET, MOVDQA) \ + movdqa XMM_WRITEMASK, xmmword ptr [VIF_TMPADDR + 64*(0) + 48]; \ + pand r0, XMM_WRITEMASK; \ + pandn XMM_WRITEMASK, xmmword ptr [VIF_DST]; \ + por r0, XMM_WRITEMASK; \ + MOVDQA xmmword ptr [VIF_DST], r0; \ + add VIF_DST, VIF_INC; \ + +#define UNPACK_Mask_SSE_0(r0) \ + pand r0, XMM_WRITEMASK; \ + por r0, XMM_ROWCOLMASK; \ + +// once a xmmword is uncomprssed, applies masks and saves +// note: modifying XMM_WRITEMASK +// dest = row + write (only when mask=0), otherwise write +#define UNPACK_Mask_SSE_1(r0) \ + pand r0, XMM_WRITEMASK; \ + por r0, XMM_ROWCOLMASK; \ + pand XMM_WRITEMASK, XMM_ROW; \ + paddd r0, XMM_WRITEMASK; \ + +// dest = row + write (only when mask=0), otherwise write +// row = row + write (only when mask = 0), otherwise row +#define UNPACK_Mask_SSE_2(r0) \ + pand r0, XMM_WRITEMASK; \ + pand XMM_WRITEMASK, XMM_ROW; \ + paddd XMM_ROW, r0; \ + por r0, XMM_ROWCOLMASK; \ + paddd r0, XMM_WRITEMASK; \ + +#define UNPACK_WriteMask_SSE_0 UNPACK_Mask_SSE_0 +#define UNPACK_WriteMask_SSE_1 UNPACK_Mask_SSE_1 +#define UNPACK_WriteMask_SSE_2 UNPACK_Mask_SSE_2 + +#define UNPACK_Regular_SSE_0(r0) + +#define UNPACK_Regular_SSE_1(r0) \ + paddd r0, XMM_ROW; \ + +#define UNPACK_Regular_SSE_2(r0) \ + paddd r0, XMM_ROW; \ + movdqa XMM_ROW, r0; \ + +// setting up masks +#define UNPACK_Setup_Mask_SSE(CL) \ + mov VIF_TMPADDR, _vifMaskRegs; \ + movdqa XMM_ROWMASK, xmmword ptr [VIF_TMPADDR + 64*(CL) + 16]; \ + movdqa XMM_ROWCOLMASK, xmmword ptr [VIF_TMPADDR + 64*(CL) + 32]; \ + movdqa XMM_WRITEMASK, xmmword ptr [VIF_TMPADDR + 64*(CL)]; \ + pand XMM_ROWMASK, XMM_ROW; \ + pand XMM_ROWCOLMASK, XMM_COL; \ + por XMM_ROWCOLMASK, XMM_ROWMASK; \ + +#define UNPACK_Start_Setup_Mask_SSE_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Start_Setup_Mask_SSE_1(CL) \ + mov VIF_TMPADDR, _vifMaskRegs; \ + movdqa XMM_ROWMASK, xmmword ptr [VIF_TMPADDR + 64*(CL) + 16]; \ + movdqa XMM_ROWCOLMASK, xmmword ptr [VIF_TMPADDR + 64*(CL) + 32]; \ + pand XMM_ROWMASK, XMM_ROW; \ + pand XMM_ROWCOLMASK, XMM_COL; \ + por XMM_ROWCOLMASK, XMM_ROWMASK; \ + +#define UNPACK_Start_Setup_Mask_SSE_2(CL) + +#define UNPACK_Setup_Mask_SSE_0_1(CL) +#define UNPACK_Setup_Mask_SSE_1_1(CL) \ + mov VIF_TMPADDR, _vifMaskRegs; \ + movdqa XMM_WRITEMASK, xmmword ptr [VIF_TMPADDR + 64*(0)]; \ + +// ignore CL, since vif.cycle.wl == 1 +#define UNPACK_Setup_Mask_SSE_2_1(CL) \ + mov VIF_TMPADDR, _vifMaskRegs; \ + movdqa XMM_ROWMASK, xmmword ptr [VIF_TMPADDR + 64*(0) + 16]; \ + movdqa XMM_ROWCOLMASK, xmmword ptr [VIF_TMPADDR + 64*(0) + 32]; \ + movdqa XMM_WRITEMASK, xmmword ptr [VIF_TMPADDR + 64*(0)]; \ + pand XMM_ROWMASK, XMM_ROW; \ + pand XMM_ROWCOLMASK, XMM_COL; \ + por XMM_ROWCOLMASK, XMM_ROWMASK; \ + +#define UNPACK_Setup_Mask_SSE_0_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Setup_Mask_SSE_1_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Setup_Mask_SSE_2_0(CL) UNPACK_Setup_Mask_SSE(CL) + +// write mask always destroys XMM_WRITEMASK, so 0_0 = 1_0 +#define UNPACK_Setup_WriteMask_SSE_0_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Setup_WriteMask_SSE_1_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Setup_WriteMask_SSE_2_0(CL) UNPACK_Setup_Mask_SSE(CL) +#define UNPACK_Setup_WriteMask_SSE_0_1(CL) UNPACK_Setup_Mask_SSE_1_1(CL) +#define UNPACK_Setup_WriteMask_SSE_1_1(CL) UNPACK_Setup_Mask_SSE_1_1(CL) +#define UNPACK_Setup_WriteMask_SSE_2_1(CL) UNPACK_Setup_Mask_SSE_2_1(CL) + +#define UNPACK_Start_Setup_WriteMask_SSE_0(CL) UNPACK_Start_Setup_Mask_SSE_1(CL) +#define UNPACK_Start_Setup_WriteMask_SSE_1(CL) UNPACK_Start_Setup_Mask_SSE_1(CL) +#define UNPACK_Start_Setup_WriteMask_SSE_2(CL) UNPACK_Start_Setup_Mask_SSE_2(CL) + +#define UNPACK_Start_Setup_Regular_SSE_0(CL) +#define UNPACK_Start_Setup_Regular_SSE_1(CL) +#define UNPACK_Start_Setup_Regular_SSE_2(CL) +#define UNPACK_Setup_Regular_SSE_0_0(CL) +#define UNPACK_Setup_Regular_SSE_1_0(CL) +#define UNPACK_Setup_Regular_SSE_2_0(CL) +#define UNPACK_Setup_Regular_SSE_0_1(CL) +#define UNPACK_Setup_Regular_SSE_1_1(CL) +#define UNPACK_Setup_Regular_SSE_2_1(CL) + +#define UNPACK_INC_DST_0_Regular(qw) add VIF_DST, (16*qw) +#define UNPACK_INC_DST_1_Regular(qw) +#define UNPACK_INC_DST_0_Mask(qw) add VIF_DST, (16*qw) +#define UNPACK_INC_DST_1_Mask(qw) +#define UNPACK_INC_DST_0_WriteMask(qw) +#define UNPACK_INC_DST_1_WriteMask(qw) + +// unpacks for 1,2,3,4 elements (V3 uses this directly) +#define UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType) \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+0); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+1); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R1); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R1, CL+1, 16, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+2); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R2); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R2, CL+2, 32, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+3); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R3); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R3, CL+3, 48, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(4) + +// V3 uses this directly +#define UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType) \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+1); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R1); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R1, CL+1, 16, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+2); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R2); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R2, CL+2, 32, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(3); \ + +#define UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType) \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+1); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R1); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R1, CL+1, 16, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(2); \ + +#define UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType) \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(1); \ + +// S-32 +// only when cl==1 +#define UNPACK_S_32SSE_4x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R3, xmmword ptr [VIF_SRC]; \ + \ + pshufd XMM_R0, XMM_R3, 0; \ + pshufd XMM_R1, XMM_R3, 0x55; \ + pshufd XMM_R2, XMM_R3, 0xaa; \ + pshufd XMM_R3, XMM_R3, 0xff; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_S_32SSE_4A(CL, TOTALCL, MaskType, ModeType) UNPACK_S_32SSE_4x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_S_32SSE_4(CL, TOTALCL, MaskType, ModeType) UNPACK_S_32SSE_4x(CL, TOTALCL, MaskType, ModeType, movdqu) + +#define UNPACK_S_32SSE_3x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R2, xmmword ptr [VIF_SRC]; \ + \ + pshufd XMM_R0, XMM_R2, 0; \ + pshufd XMM_R1, XMM_R2, 0x55; \ + pshufd XMM_R2, XMM_R2, 0xaa; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_S_32SSE_3A(CL, TOTALCL, MaskType, ModeType) UNPACK_S_32SSE_3x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_S_32SSE_3(CL, TOTALCL, MaskType, ModeType) UNPACK_S_32SSE_3x(CL, TOTALCL, MaskType, ModeType, movdqu) + +#define UNPACK_S_32SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R1, qword ptr [VIF_SRC]; \ + \ + pshufd XMM_R0, XMM_R1, 0; \ + pshufd XMM_R1, XMM_R1, 0x55; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_S_32SSE_2A UNPACK_S_32SSE_2 + +#define UNPACK_S_32SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + pshufd XMM_R0, XMM_R0, 0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_S_32SSE_1A UNPACK_S_32SSE_1 + +// S-16 +#define UNPACK_S_16SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R3, qword ptr [VIF_SRC]; \ + punpcklwd XMM_R3, XMM_R3; \ + UNPACK_RIGHTSHIFT XMM_R3, 16; \ + \ + pshufd XMM_R0, XMM_R3, 0; \ + pshufd XMM_R1, XMM_R3, 0x55; \ + pshufd XMM_R2, XMM_R3, 0xaa; \ + pshufd XMM_R3, XMM_R3, 0xff; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_S_16SSE_4A UNPACK_S_16SSE_4 + +#define UNPACK_S_16SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R2, qword ptr [VIF_SRC]; \ + punpcklwd XMM_R2, XMM_R2; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + pshufd XMM_R0, XMM_R2, 0; \ + pshufd XMM_R1, XMM_R2, 0x55; \ + pshufd XMM_R2, XMM_R2, 0xaa; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + add VIF_SRC, 6; \ + +#define UNPACK_S_16SSE_3A UNPACK_S_16SSE_3 + +#define UNPACK_S_16SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R1, dword ptr [VIF_SRC]; \ + punpcklwd XMM_R1, XMM_R1; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + \ + pshufd XMM_R0, XMM_R1, 0; \ + pshufd XMM_R1, XMM_R1, 0x55; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_S_16SSE_2A UNPACK_S_16SSE_2 + +#define UNPACK_S_16SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + pshufd XMM_R0, XMM_R0, 0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 2; \ + +#define UNPACK_S_16SSE_1A UNPACK_S_16SSE_1 + +// S-8 +#define UNPACK_S_8SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R3, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R3, XMM_R3; \ + punpcklwd XMM_R3, XMM_R3; \ + UNPACK_RIGHTSHIFT XMM_R3, 24; \ + \ + pshufd XMM_R0, XMM_R3, 0; \ + pshufd XMM_R1, XMM_R3, 0x55; \ + pshufd XMM_R2, XMM_R3, 0xaa; \ + pshufd XMM_R3, XMM_R3, 0xff; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_S_8SSE_4A UNPACK_S_8SSE_4 + +#define UNPACK_S_8SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R2, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R2, XMM_R2; \ + punpcklwd XMM_R2, XMM_R2; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + pshufd XMM_R0, XMM_R2, 0; \ + pshufd XMM_R1, XMM_R2, 0x55; \ + pshufd XMM_R2, XMM_R2, 0xaa; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 3; \ + +#define UNPACK_S_8SSE_3A UNPACK_S_8SSE_3 + +#define UNPACK_S_8SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R1, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R1, XMM_R1; \ + punpcklwd XMM_R1, XMM_R1; \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + \ + pshufd XMM_R0, XMM_R1, 0; \ + pshufd XMM_R1, XMM_R1, 0x55; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 2; \ + +#define UNPACK_S_8SSE_2A UNPACK_S_8SSE_2 + +#define UNPACK_S_8SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + pshufd XMM_R0, XMM_R0, 0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + inc VIF_SRC; \ + +#define UNPACK_S_8SSE_1A UNPACK_S_8SSE_1 + +// V2-32 +#define UNPACK_V2_32SSE_4A(CL, TOTALCL, MaskType, ModeType) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + MOVDQA XMM_R2, xmmword ptr [VIF_SRC+16]; \ + \ + pshufd XMM_R1, XMM_R0, 0xee; \ + pshufd XMM_R3, XMM_R2, 0xee; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V2_32SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+8]; \ + movq XMM_R2, qword ptr [VIF_SRC+16]; \ + movq XMM_R3, qword ptr [VIF_SRC+24]; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V2_32SSE_3A(CL, TOTALCL, MaskType, ModeType) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + movq XMM_R2, qword ptr [VIF_SRC+16]; \ + pshufd XMM_R1, XMM_R0, 0xee; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V2_32SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+8]; \ + movq XMM_R2, qword ptr [VIF_SRC+16]; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V2_32SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+8]; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V2_32SSE_2A UNPACK_V2_32SSE_2 + +#define UNPACK_V2_32SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V2_32SSE_1A UNPACK_V2_32SSE_1 + +// V2-16 +// due to lemmings, have to copy lower xmmword to the upper xmmword of every reg +#define UNPACK_V2_16SSE_4A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhwd XMM_R2, xmmword ptr [VIF_SRC]; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + punpckhqdq XMM_R3, XMM_R2; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + punpckhqdq XMM_R3, XMM_R3; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + add VIF_SRC, 16; \ + +#define UNPACK_V2_16SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + punpckhwd XMM_R2, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + punpckhqdq XMM_R3, XMM_R2; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + punpckhqdq XMM_R3, XMM_R3; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V2_16SSE_3A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhwd XMM_R2, xmmword ptr [VIF_SRC]; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V2_16SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + punpckhwd XMM_R2, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V2_16SSE_2A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V2_16SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V2_16SSE_1A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + punpcklqdq XMM_R0, XMM_R0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_V2_16SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + punpcklqdq XMM_R0, XMM_R0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +// V2-8 +// and1 streetball needs to copy lower xmmword to the upper xmmword of every reg +#define UNPACK_V2_8SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + punpckhwd XMM_R2, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + punpckhqdq XMM_R3, XMM_R2; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + punpckhqdq XMM_R3, XMM_R3; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V2_8SSE_4A UNPACK_V2_8SSE_4 + +#define UNPACK_V2_8SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + punpckhwd XMM_R2, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpcklqdq XMM_R2, XMM_R2; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 6; \ + +#define UNPACK_V2_8SSE_3A UNPACK_V2_8SSE_3 + +#define UNPACK_V2_8SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + punpckhqdq XMM_R1, XMM_R0; \ + \ + punpcklqdq XMM_R0, XMM_R0; \ + punpckhqdq XMM_R1, XMM_R1; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_V2_8SSE_2A UNPACK_V2_8SSE_2 + +#define UNPACK_V2_8SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + punpcklqdq XMM_R0, XMM_R0; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 2; \ + +#define UNPACK_V2_8SSE_1A UNPACK_V2_8SSE_1 + +// V3-32 +// midnight club 2 crashes because reading a qw at +36 is out of bounds +#define UNPACK_V3_32SSE_4x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+12]; \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+0); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+1); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R1); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R1, CL+1, 16, movdqa); \ + \ + MOVDQA XMM_R3, xmmword ptr [VIF_SRC+32]; \ + movdqu XMM_R2, xmmword ptr [VIF_SRC+24]; \ + psrldq XMM_R3, 4; \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+2); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R2); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R2, CL+2, 32, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+3); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R3); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R3, CL+3, 48, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(4); \ + \ + add VIF_SRC, 48; \ + +#define UNPACK_V3_32SSE_4A(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_4x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_V3_32SSE_4(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_4x(CL, TOTALCL, MaskType, ModeType, movdqu) + +#define UNPACK_V3_32SSE_3x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+12]; \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R0); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R0, CL, 0, movdqa); \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+1); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R1); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R1, CL+1, 16, movdqa); \ + \ + movdqu XMM_R2, xmmword ptr [VIF_SRC+24]; \ + \ + UNPACK_Setup_##MaskType##_SSE_##ModeType##_##TOTALCL##(CL+2); \ + UNPACK_##MaskType##_SSE_##ModeType##(XMM_R2); \ + UNPACK_Write##TOTALCL##_##MaskType##(XMM_R2, CL+2, 32, movdqa); \ + \ + UNPACK_INC_DST_##TOTALCL##_##MaskType##(3); \ + \ + add VIF_SRC, 36; \ + +#define UNPACK_V3_32SSE_3A(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_3x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_V3_32SSE_3(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_3x(CL, TOTALCL, MaskType, ModeType, movdqu) + +#define UNPACK_V3_32SSE_2x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+12]; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V3_32SSE_2A(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_2x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_V3_32SSE_2(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_2x(CL, TOTALCL, MaskType, ModeType, movdqu) + +#define UNPACK_V3_32SSE_1x(CL, TOTALCL, MaskType, ModeType, MOVDQA) \ + MOVDQA XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V3_32SSE_1A(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_1x(CL, TOTALCL, MaskType, ModeType, movdqa) +#define UNPACK_V3_32SSE_1(CL, TOTALCL, MaskType, ModeType) UNPACK_V3_32SSE_1x(CL, TOTALCL, MaskType, ModeType, movdqu) + +// V3-16 +#define UNPACK_V3_16SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+6]; \ + \ + punpcklwd XMM_R0, XMM_R0; \ + movq XMM_R2, qword ptr [VIF_SRC+12]; \ + punpcklwd XMM_R1, XMM_R1; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + movq XMM_R3, qword ptr [VIF_SRC+18]; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + punpcklwd XMM_R2, XMM_R2; \ + punpcklwd XMM_R3, XMM_R3; \ + \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + UNPACK_RIGHTSHIFT XMM_R3, 16; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V3_16SSE_4A UNPACK_V3_16SSE_4 + +#define UNPACK_V3_16SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+6]; \ + \ + punpcklwd XMM_R0, XMM_R0; \ + movq XMM_R2, qword ptr [VIF_SRC+12]; \ + punpcklwd XMM_R1, XMM_R1; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 18; \ + +#define UNPACK_V3_16SSE_3A UNPACK_V3_16SSE_3 + +#define UNPACK_V3_16SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+6]; \ + \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R1, XMM_R1; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V3_16SSE_2A UNPACK_V3_16SSE_2 + +#define UNPACK_V3_16SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 6; \ + +#define UNPACK_V3_16SSE_1A UNPACK_V3_16SSE_1 + +// V3-8 +#define UNPACK_V3_8SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R1, qword ptr [VIF_SRC]; \ + movq XMM_R3, qword ptr [VIF_SRC+6]; \ + \ + punpcklbw XMM_R1, XMM_R1; \ + punpcklbw XMM_R3, XMM_R3; \ + punpcklwd XMM_R0, XMM_R1; \ + psrldq XMM_R1, 6; \ + punpcklwd XMM_R2, XMM_R3; \ + psrldq XMM_R3, 6; \ + punpcklwd XMM_R1, XMM_R1; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + punpcklwd XMM_R3, XMM_R3; \ + \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R3, 24; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V3_8SSE_4A UNPACK_V3_8SSE_4 + +#define UNPACK_V3_8SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + movd XMM_R1, dword ptr [VIF_SRC+3]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + movd XMM_R2, dword ptr [VIF_SRC+6]; \ + punpcklbw XMM_R1, XMM_R1; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklbw XMM_R2, XMM_R2; \ + \ + punpcklwd XMM_R1, XMM_R1; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 9 \ + +#define UNPACK_V3_8SSE_3A UNPACK_V3_8SSE_3 + +#define UNPACK_V3_8SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + movd XMM_R1, dword ptr [VIF_SRC+3]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklbw XMM_R1, XMM_R1; \ + \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R1, XMM_R1; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 6; \ + +#define UNPACK_V3_8SSE_2A UNPACK_V3_8SSE_2 + +#define UNPACK_V3_8SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 3; \ + +#define UNPACK_V3_8SSE_1A UNPACK_V3_8SSE_1 + +// V4-32 +#define UNPACK_V4_32SSE_4A(CL, TOTALCL, MaskType, ModeType) \ + movdqa XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqa XMM_R1, xmmword ptr [VIF_SRC+16]; \ + movdqa XMM_R2, xmmword ptr [VIF_SRC+32]; \ + movdqa XMM_R3, xmmword ptr [VIF_SRC+48]; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 64; \ + +#define UNPACK_V4_32SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+16]; \ + movdqu XMM_R2, xmmword ptr [VIF_SRC+32]; \ + movdqu XMM_R3, xmmword ptr [VIF_SRC+48]; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 64; \ + +#define UNPACK_V4_32SSE_3A(CL, TOTALCL, MaskType, ModeType) \ + movdqa XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqa XMM_R1, xmmword ptr [VIF_SRC+16]; \ + movdqa XMM_R2, xmmword ptr [VIF_SRC+32]; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 48; \ + +#define UNPACK_V4_32SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+16]; \ + movdqu XMM_R2, xmmword ptr [VIF_SRC+32]; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 48; \ + +#define UNPACK_V4_32SSE_2A(CL, TOTALCL, MaskType, ModeType) \ + movdqa XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqa XMM_R1, xmmword ptr [VIF_SRC+16]; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V4_32SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R1, xmmword ptr [VIF_SRC+16]; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V4_32SSE_1A(CL, TOTALCL, MaskType, ModeType) \ + movdqa XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V4_32SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +// V4-16 +#define UNPACK_V4_16SSE_4A(CL, TOTALCL, MaskType, ModeType) \ + \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhwd XMM_R1, xmmword ptr [VIF_SRC]; \ + punpcklwd XMM_R2, xmmword ptr [VIF_SRC+16]; \ + punpckhwd XMM_R3, xmmword ptr [VIF_SRC+16]; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + UNPACK_RIGHTSHIFT XMM_R3, 16; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V4_16SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + movdqu XMM_R2, xmmword ptr [VIF_SRC+16]; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpckhwd XMM_R3, XMM_R2; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + UNPACK_RIGHTSHIFT XMM_R3, 16; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 32; \ + +#define UNPACK_V4_16SSE_3A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhwd XMM_R1, xmmword ptr [VIF_SRC]; \ + punpcklwd XMM_R2, xmmword ptr [VIF_SRC+16]; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V4_16SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + movq XMM_R2, qword ptr [VIF_SRC+16]; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + UNPACK_RIGHTSHIFT XMM_R2, 16; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 24; \ + +#define UNPACK_V4_16SSE_2A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhwd XMM_R1, xmmword ptr [VIF_SRC]; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V4_16SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movq XMM_R1, qword ptr [VIF_SRC+8]; \ + \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R1, XMM_R1; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + UNPACK_RIGHTSHIFT XMM_R1, 16; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V4_16SSE_1A(CL, TOTALCL, MaskType, ModeType) \ + punpcklwd XMM_R0, xmmword ptr [VIF_SRC]; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V4_16SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 16; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +// V4-8 +#define UNPACK_V4_8SSE_4A(CL, TOTALCL, MaskType, ModeType) \ + punpcklbw XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhbw XMM_R2, xmmword ptr [VIF_SRC]; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpckhwd XMM_R3, XMM_R2; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R3, 24; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V4_8SSE_4(CL, TOTALCL, MaskType, ModeType) \ + movdqu XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + punpckhbw XMM_R2, XMM_R0; \ + punpcklbw XMM_R0, XMM_R0; \ + \ + punpckhwd XMM_R3, XMM_R2; \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R3, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 16; \ + +#define UNPACK_V4_8SSE_3A(CL, TOTALCL, MaskType, ModeType) \ + punpcklbw XMM_R0, xmmword ptr [VIF_SRC]; \ + punpckhbw XMM_R2, xmmword ptr [VIF_SRC]; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V4_8SSE_3(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + movd XMM_R2, dword ptr [VIF_SRC+8]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklbw XMM_R2, XMM_R2; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + UNPACK_RIGHTSHIFT XMM_R2, 24; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 12; \ + +#define UNPACK_V4_8SSE_2A(CL, TOTALCL, MaskType, ModeType) \ + punpcklbw XMM_R0, xmmword ptr [VIF_SRC]; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V4_8SSE_2(CL, TOTALCL, MaskType, ModeType) \ + movq XMM_R0, qword ptr [VIF_SRC]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + UNPACK_RIGHTSHIFT XMM_R1, 24; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V4_8SSE_1A(CL, TOTALCL, MaskType, ModeType) \ + punpcklbw XMM_R0, xmmword ptr [VIF_SRC]; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_V4_8SSE_1(CL, TOTALCL, MaskType, ModeType) \ + movd XMM_R0, dword ptr [VIF_SRC]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + UNPACK_RIGHTSHIFT XMM_R0, 24; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +// V4-5 +.extern s_TempDecompress + +#define DECOMPRESS_RGBA(OFFSET) \ + mov %bl, %al; \ + shl %bl, 3; \ + mov byte ptr [s_TempDecompress+OFFSET], %bl; \ + \ + mov %bx, %ax; \ + shr %bx, 2; \ + and %bx, 0xf8; \ + mov byte ptr [s_TempDecompress+OFFSET+1], %bl; \ + \ + mov %bx, %ax; \ + shr %bx, 7; \ + and %bx, 0xf8; \ + mov byte ptr [s_TempDecompress+OFFSET+2], %bl; \ + mov %bx, %ax; \ + shr %bx, 8; \ + and %bx, 0x80; \ + mov byte ptr [s_TempDecompress+OFFSET+3], %bl; \ + +#define UNPACK_V4_5SSE_4(CL, TOTALCL, MaskType, ModeType) \ + mov %eax, dword ptr [VIF_SRC]; \ + DECOMPRESS_RGBA(0); \ + \ + shr %eax, 16; \ + DECOMPRESS_RGBA(4); \ + \ + mov %eax, dword ptr [VIF_SRC+4]; \ + DECOMPRESS_RGBA(8); \ + \ + shr %eax, 16; \ + DECOMPRESS_RGBA(12); \ + \ + movdqa XMM_R0, xmmword ptr [s_TempDecompress]; \ + \ + punpckhbw XMM_R2, XMM_R0; \ + punpcklbw XMM_R0, XMM_R0; \ + \ + punpckhwd XMM_R3, XMM_R2; \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + psrld XMM_R0, 24; \ + psrld XMM_R1, 24; \ + psrld XMM_R2, 24; \ + psrld XMM_R3, 24; \ + \ + UNPACK4_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 8; \ + +#define UNPACK_V4_5SSE_4A UNPACK_V4_5SSE_4 + +#define UNPACK_V4_5SSE_3(CL, TOTALCL, MaskType, ModeType) \ + mov %eax, dword ptr [VIF_SRC]; \ + DECOMPRESS_RGBA(0); \ + \ + shr %eax, 16; \ + DECOMPRESS_RGBA(4); \ + \ + mov %eax, dword ptr [VIF_SRC]; \ + DECOMPRESS_RGBA(8); \ + \ + movdqa XMM_R0, xmmword ptr [s_TempDecompress]; \ + \ + punpckhbw XMM_R2, XMM_R0; \ + punpcklbw XMM_R0, XMM_R0; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + punpcklwd XMM_R2, XMM_R2; \ + \ + psrld XMM_R0, 24; \ + psrld XMM_R1, 24; \ + psrld XMM_R2, 24; \ + \ + UNPACK3_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 6; \ + +#define UNPACK_V4_5SSE_3A UNPACK_V4_5SSE_3 + +#define UNPACK_V4_5SSE_2(CL, TOTALCL, MaskType, ModeType) \ + mov %eax, dword ptr [VIF_SRC]; \ + DECOMPRESS_RGBA(0); \ + \ + shr %eax, 16; \ + DECOMPRESS_RGBA(4); \ + \ + movq XMM_R0, qword ptr [s_TempDecompress]; \ + \ + punpcklbw XMM_R0, XMM_R0; \ + \ + punpckhwd XMM_R1, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + psrld XMM_R0, 24; \ + psrld XMM_R1, 24; \ + \ + UNPACK2_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 4; \ + +#define UNPACK_V4_5SSE_2A UNPACK_V4_5SSE_2 + +#define UNPACK_V4_5SSE_1(CL, TOTALCL, MaskType, ModeType) \ + mov %ax, word ptr [VIF_SRC]; \ + DECOMPRESS_RGBA(0) \ + \ + movd XMM_R0, dword ptr [s_TempDecompress]; \ + punpcklbw XMM_R0, XMM_R0; \ + punpcklwd XMM_R0, XMM_R0; \ + \ + psrld XMM_R0, 24; \ + \ + UNPACK1_SSE(CL, TOTALCL, MaskType, ModeType); \ + \ + add VIF_SRC, 2; \ + +#define UNPACK_V4_5SSE_1A UNPACK_V4_5SSE_1 + +#pragma warning(disable:4731) + +#define SAVE_ROW_REG_BASE \ + mov VIF_TMPADDR, _vifRow; \ + movdqa xmmword ptr [VIF_TMPADDR], XMM_ROW; \ + mov VIF_TMPADDR, _vifRegs; \ + movss dword ptr [VIF_TMPADDR+0x100], XMM_ROW; \ + psrldq XMM_ROW, 4; \ + movss dword ptr [VIF_TMPADDR+0x110], XMM_ROW; \ + psrldq XMM_ROW, 4; \ + movss dword ptr [VIF_TMPADDR+0x120], XMM_ROW; \ + psrldq XMM_ROW, 4; \ + movss dword ptr [VIF_TMPADDR+0x130], XMM_ROW; \ + +#define SAVE_NO_REG + +#ifdef __x86_64__ +#define INIT_ARGS() + +#define POP_REGS() + +#define INC_STACK(reg) add %rsp, 8; + +#else + +// 32 bit versions have the args on the stack +#define INIT_ARGS() \ + push %edi; \ + push %esi; \ + push %ebx; \ + mov VIF_DST, dword ptr [%esp+4+12]; \ + mov VIF_SRC, dword ptr [%esp+8+12]; \ + mov VIF_SIZE, dword ptr [%esp+12+12]; \ + + +#define POP_REGS() \ + pop %ebx; \ + pop %esi; \ + pop %edi; \ + +#define INC_STACK(reg) add %esp, 4; + +#endif + +// qsize - bytes of compressed size of 1 decompressed xmmword +// int UNPACK_SkippingWrite_##name##_##sign##_##MaskType##_##ModeType(u32* dest, u32* data, int dmasize) + +#define defUNPACK_SkippingWrite(name, MaskType, ModeType, qsize, sign, SAVE_ROW_REG) \ +.globl UNPACK_SkippingWrite_##name##_##sign##_##MaskType##_##ModeType; \ +UNPACK_SkippingWrite_##name##_##sign##_##MaskType##_##ModeType: \ + INIT_ARGS(); \ + mov VIF_TMPADDR, _vifRegs; \ + movzx VIF_INC, byte ptr [VIF_TMPADDR + 0x40]; \ + movzx VIF_SAVEEBX, byte ptr [VIF_TMPADDR + 0x41]; \ + sub VIF_INC, VIF_SAVEEBX; \ + shl VIF_INC, 4; \ + \ + cmp VIF_SAVEEBXd, 1; \ + je name##_##sign##_##MaskType##_##ModeType##_WL1; \ + cmp VIF_SAVEEBXd, 2; \ + je name##_##sign##_##MaskType##_##ModeType##_WL2; \ + cmp VIF_SAVEEBXd, 3; \ + je name##_##sign##_##MaskType##_##ModeType##_WL3; \ + jmp name##_##sign##_##MaskType##_##ModeType##_WL4; \ + \ +name##_##sign##_##MaskType##_##ModeType##_WL1: \ + UNPACK_Start_Setup_##MaskType##_SSE_##ModeType##(0); \ + \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Done3; \ + \ + add VIF_INC, 16; \ + \ + /* first align VIF_SRC to 16 bytes */ \ +name##_##sign##_##MaskType##_##ModeType##_C1_Align16: \ + \ + test VIF_SRC, 15; \ + jz name##_##sign##_##MaskType##_##ModeType##_C1_UnpackAligned; \ + \ + UNPACK_##name##SSE_1(0, 1, MaskType, ModeType); \ + \ + cmp VIF_SIZE, (2*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_DoneWithDec; \ + sub VIF_SIZE, qsize; \ + jmp name##_##sign##_##MaskType##_##ModeType##_C1_Align16; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_UnpackAligned: \ + \ + cmp VIF_SIZE, (2*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Unpack1; \ + cmp VIF_SIZE, (3*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Unpack2; \ + cmp VIF_SIZE, (4*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Unpack3; \ + prefetchnta [VIF_SRC + 64]; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_Unpack4: \ + UNPACK_##name##SSE_4A(0, 1, MaskType, ModeType); \ + \ + cmp VIF_SIZE, (8*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_DoneUnpack4; \ + sub VIF_SIZE, (4*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C1_Unpack4; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_DoneUnpack4: \ + \ + sub VIF_SIZE, (4*qsize); \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Done3; \ + cmp VIF_SIZE, (2*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Unpack1; \ + cmp VIF_SIZE, (3*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C1_Unpack2; \ + /* fall through */ \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_Unpack3: \ + UNPACK_##name##SSE_3A(0, 1, MaskType, ModeType); \ + \ + sub VIF_SIZE, (3*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C1_Done3; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_Unpack2: \ + UNPACK_##name##SSE_2A(0, 1, MaskType, ModeType); \ + \ + sub VIF_SIZE, (2*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C1_Done3; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C1_Unpack1: \ + UNPACK_##name##SSE_1A(0, 1, MaskType, ModeType); \ +name##_##sign##_##MaskType##_##ModeType##_C1_DoneWithDec: \ + sub VIF_SIZE, qsize; \ +name##_##sign##_##MaskType##_##ModeType##_C1_Done3: \ + SAVE_ROW_REG; \ + mov %eax, VIF_SIZE; \ + POP_REGS(); \ + ret; \ + \ +name##_##sign##_##MaskType##_##ModeType##_WL2: \ + cmp VIF_SIZE, (2*qsize); \ + \ + jl name##_##sign##_##MaskType##_##ModeType##_C2_Done3; \ +name##_##sign##_##MaskType##_##ModeType##_C2_Unpack: \ + UNPACK_##name##SSE_2(0, 0, MaskType, ModeType); \ + \ + add VIF_DST, VIF_INC; /* take into account wl */ \ + cmp VIF_SIZE, (4*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C2_Done2; \ + sub VIF_SIZE, (2*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C2_Unpack; /* unpack next */ \ + \ +name##_##sign##_##MaskType##_##ModeType##_C2_Done2: \ + sub VIF_SIZE, (2*qsize); \ +name##_##sign##_##MaskType##_##ModeType##_C2_Done3: \ + cmp VIF_SIZE, qsize; \ + /* execute left over qw */ \ + jl name##_##sign##_##MaskType##_##ModeType##_C2_Done4; \ + UNPACK_##name##SSE_1(0, 0, MaskType, ModeType); \ + \ + sub VIF_SIZE, qsize; \ +name##_##sign##_##MaskType##_##ModeType##_C2_Done4: \ + \ + SAVE_ROW_REG; \ + mov %eax, VIF_SIZE; \ + POP_REGS(); \ + ret; \ + \ +name##_##sign##_##MaskType##_##ModeType##_WL3: \ + cmp VIF_SIZE, (3*qsize); \ + \ + jl name##_##sign##_##MaskType##_##ModeType##_C3_Done5; \ +name##_##sign##_##MaskType##_##ModeType##_C3_Unpack: \ + UNPACK_##name##SSE_3(0, 0, MaskType, ModeType); \ + \ + add VIF_DST, VIF_INC; /* take into account wl */ \ + cmp VIF_SIZE, (6*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C3_Done2; \ + sub VIF_SIZE, (3*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C3_Unpack; /* unpack next */ \ +name##_##sign##_##MaskType##_##ModeType##_C3_Done2: \ + sub VIF_SIZE, (3*qsize); \ +name##_##sign##_##MaskType##_##ModeType##_C3_Done5: \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C3_Done4; \ + \ + /* execute left over qw */ \ + cmp VIF_SIZE, (2*qsize); \ + jl name##_##sign##_##MaskType##_##ModeType##_C3_Done3; \ + \ + /* process 2 qws */ \ + UNPACK_##name##SSE_2(0, 0, MaskType, ModeType); \ + \ + sub VIF_SIZE, (2*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C3_Done4; \ +name##_##sign##_##MaskType##_##ModeType##_C3_Done3: \ + /* process 1 qw */ \ + sub VIF_SIZE, qsize; \ + UNPACK_##name##SSE_1(0, 0, MaskType, ModeType); \ +name##_##sign##_##MaskType##_##ModeType##_C3_Done4: \ + SAVE_ROW_REG; \ + mov %eax, VIF_SIZE; \ + POP_REGS(); \ + ret; \ + \ +name##_##sign##_##MaskType##_##ModeType##_WL4: /* >= 4 */ \ + sub VIF_SAVEEBX, 3; \ + push VIF_INC; \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C4_Done; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C4_Unpack: \ + cmp VIF_SIZE, (3*qsize); \ + jge name##_##sign##_##MaskType##_##ModeType##_C4_Unpack3; \ + cmp VIF_SIZE, (2*qsize); \ + jge name##_##sign##_##MaskType##_##ModeType##_C4_Unpack2; \ + \ + UNPACK_##name##SSE_1(0, 0, MaskType, ModeType) \ + \ + /* not enough data left */ \ + sub VIF_SIZE, qsize; \ + jmp name##_##sign##_##MaskType##_##ModeType##_C4_Done; \ +name##_##sign##_##MaskType##_##ModeType##_C4_Unpack2: \ + UNPACK_##name##SSE_2(0, 0, MaskType, ModeType); \ + \ + /* not enough data left */ \ + sub VIF_SIZE, (2*qsize); \ + jmp name##_##sign##_##MaskType##_##ModeType##_C4_Done; \ +name##_##sign##_##MaskType##_##ModeType##_C4_Unpack3: \ + UNPACK_##name##SSE_3(0, 0, MaskType, ModeType); \ + \ + sub VIF_SIZE, (3*qsize); \ + /* more data left, process 1qw at a time */ \ + mov VIF_INC, VIF_SAVEEBX; \ + \ +name##_##sign##_##MaskType##_##ModeType##_C4_UnpackX: \ + /* check if any data left */ \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C4_Done; \ + \ + UNPACK_##name##SSE_1(3, 0, MaskType, ModeType); \ + \ + sub VIF_SIZE, qsize; \ + cmp VIF_INC, 1; \ + je name##_##sign##_##MaskType##_##ModeType##_C4_DoneLoop; \ + sub VIF_INC, 1; \ + jmp name##_##sign##_##MaskType##_##ModeType##_C4_UnpackX; \ +name##_##sign##_##MaskType##_##ModeType##_C4_DoneLoop: \ + add VIF_DST, [VIF_ESP]; /* take into account wl */ \ + cmp VIF_SIZE, qsize; \ + jl name##_##sign##_##MaskType##_##ModeType##_C4_Done; \ + jmp name##_##sign##_##MaskType##_##ModeType##_C4_Unpack; /* unpack next */ \ +name##_##sign##_##MaskType##_##ModeType##_C4_Done: \ + \ + SAVE_ROW_REG; \ + INC_STACK(); \ + mov %eax, VIF_SIZE; \ + POP_REGS(); \ + ret; \ + +#define UNPACK_RIGHTSHIFT psrld +#define defUNPACK_SkippingWrite2(name, qsize) \ + defUNPACK_SkippingWrite(name, Regular, 0, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Regular, 1, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Regular, 2, qsize, u, SAVE_ROW_REG_BASE) \ + defUNPACK_SkippingWrite(name, Mask, 0, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Mask, 1, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Mask, 2, qsize, u, SAVE_ROW_REG_BASE) \ + defUNPACK_SkippingWrite(name, WriteMask, 0, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, WriteMask, 1, qsize, u, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, WriteMask, 2, qsize, u, SAVE_ROW_REG_BASE) \ + +defUNPACK_SkippingWrite2(S_32, 4) +defUNPACK_SkippingWrite2(S_16, 2) +defUNPACK_SkippingWrite2(S_8, 1) +defUNPACK_SkippingWrite2(V2_32, 8) +defUNPACK_SkippingWrite2(V2_16, 4) +defUNPACK_SkippingWrite2(V2_8, 2) +defUNPACK_SkippingWrite2(V3_32, 12) +defUNPACK_SkippingWrite2(V3_16, 6) +defUNPACK_SkippingWrite2(V3_8, 3) +defUNPACK_SkippingWrite2(V4_32, 16) +defUNPACK_SkippingWrite2(V4_16, 8) +defUNPACK_SkippingWrite2(V4_8, 4) +defUNPACK_SkippingWrite2(V4_5, 2) + +#undef UNPACK_RIGHTSHIFT +#undef defUNPACK_SkippingWrite2 + +#define UNPACK_RIGHTSHIFT psrad +#define defUNPACK_SkippingWrite2(name, qsize) \ + defUNPACK_SkippingWrite(name, Mask, 0, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Regular, 0, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Regular, 1, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Regular, 2, qsize, s, SAVE_ROW_REG_BASE) \ + defUNPACK_SkippingWrite(name, Mask, 1, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, Mask, 2, qsize, s, SAVE_ROW_REG_BASE) \ + defUNPACK_SkippingWrite(name, WriteMask, 0, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, WriteMask, 1, qsize, s, SAVE_NO_REG) \ + defUNPACK_SkippingWrite(name, WriteMask, 2, qsize, s, SAVE_ROW_REG_BASE) \ + +defUNPACK_SkippingWrite2(S_16, 2) +defUNPACK_SkippingWrite2(S_8, 1) +defUNPACK_SkippingWrite2(V2_16, 4) +defUNPACK_SkippingWrite2(V2_8, 2) +defUNPACK_SkippingWrite2(V3_16, 6) +defUNPACK_SkippingWrite2(V3_8, 3) +defUNPACK_SkippingWrite2(V4_16, 8) +defUNPACK_SkippingWrite2(V4_8, 4) + +#undef UNPACK_RIGHTSHIFT +#undef defUNPACK_SkippingWrite2 diff --git a/pcsx2/x86/aVif.asm b/pcsx2/x86/aVif.asm new file mode 100644 index 0000000000..d23423de40 --- /dev/null +++ b/pcsx2/x86/aVif.asm @@ -0,0 +1,1941 @@ +; Pcsx2 - Pc Ps2 Emulator +; Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +;; Fast VIF assembly routines for UNPACK zerofrog(@gmail.com) +;; NOTE: This file is used to build aVif_proc-[32/64].asm because ml has a very +;; weak preprocessor. To generate the files, install nasm and run the following command: +;; aVif_proc-32.asm: nasmw -e aVif.asm > aVif_proc-32.asm +;; aVif_proc-64.asm: nasmw -e -D__x86_64__ aVif.asm > aVif_proc-64.asm +;; once the files are built, remove all lines starting with %line +;; and remove the brackets from the exports + +%ifndef __x86_64__ +.686 +.model flat, c +.mmx +.xmm +%endif + +extern _vifRegs:abs +extern _vifMaskRegs:abs +extern _vifRow:abs +extern _vifCol:abs +extern s_TempDecompress:abs + + +.code + + +%ifdef __x86_64__ +%define VIF_ESP rsp +%define VIF_SRC rdx +%define VIF_INC rdi +%define VIF_DST rcx +%define VIF_SIZE r8d +%define VIF_TMPADDR rax +%define VIF_SAVEEBX r9 +%define VIF_SAVEEBXd r9d +%else +%define VIF_ESP esp +%define VIF_SRC esi +%define VIF_INC ecx +%define VIF_DST edi +%define VIF_SIZE edx +%define VIF_TMPADDR eax +%define VIF_SAVEEBX ebx +%define VIF_SAVEEBXd ebx +%endif + +%define XMM_R0 xmm0 +%define XMM_R1 xmm1 +%define XMM_R2 xmm2 +%define XMM_WRITEMASK xmm3 +%define XMM_ROWMASK xmm4 +%define XMM_ROWCOLMASK xmm5 +%define XMM_ROW xmm6 +%define XMM_COL xmm7 +%define XMM_R3 XMM_COL + +;; writing masks +UNPACK_Write0_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [VIF_DST+DEST_OFFSET], r0 + endm + +UNPACK_Write1_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [VIF_DST], r0 + add VIF_DST, VIF_INC + endm + +UNPACK_Write0_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write0_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + +UNPACK_Write1_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write1_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + +;; masked write (dest needs to be in edi) +UNPACK_Write0_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + ;; masked write (dest needs to be in edi) + movdqa XMM_WRITEMASK, [VIF_TMPADDR + 64*(CL) + 48] + pand r0, XMM_WRITEMASK + pandn XMM_WRITEMASK, [VIF_DST] + por r0, XMM_WRITEMASK + MOVDQA [VIF_DST], r0 + add VIF_DST, 16 + endm + +;; masked write (dest needs to be in edi) +UNPACK_Write1_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + ;; masked write (dest needs to be in edi) + movdqa XMM_WRITEMASK, [VIF_TMPADDR + 64*(0) + 48] + pand r0, XMM_WRITEMASK + pandn XMM_WRITEMASK, [VIF_DST] + por r0, XMM_WRITEMASK + MOVDQA [VIF_DST], r0 + add VIF_DST, VIF_INC + endm + +UNPACK_Mask_SSE_0 macro r0 + pand r0, XMM_WRITEMASK + por r0, XMM_ROWCOLMASK + endm + +;; once a qword is uncomprssed, applies masks and saves +;; note: modifying XMM_WRITEMASK +;; dest = row + write (only when mask=0), otherwise write +UNPACK_Mask_SSE_1 macro r0 + ;; dest = row + write (only when mask=0), otherwise write + pand r0, XMM_WRITEMASK + por r0, XMM_ROWCOLMASK + pand XMM_WRITEMASK, XMM_ROW + paddd r0, XMM_WRITEMASK + endm + +;; dest = row + write (only when mask=0), otherwise write +;; row = row + write (only when mask = 0), otherwise row +UNPACK_Mask_SSE_2 macro r0 + ;; dest = row + write (only when mask=0), otherwise write + ;; row = row + write (only when mask = 0), otherwise row + pand r0, XMM_WRITEMASK + pand XMM_WRITEMASK, XMM_ROW + paddd XMM_ROW, r0 + por r0, XMM_ROWCOLMASK + paddd r0, XMM_WRITEMASK + endm + +UNPACK_WriteMask_SSE_0 macro r0 + UNPACK_Mask_SSE_0 r0 + endm +UNPACK_WriteMask_SSE_1 macro r0 + UNPACK_Mask_SSE_1 r0 + endm +UNPACK_WriteMask_SSE_2 macro r0 + UNPACK_Mask_SSE_2 r0 + endm + +UNPACK_Regular_SSE_0 macro r0 + endm + +UNPACK_Regular_SSE_1 macro r0 + paddd r0, XMM_ROW + endm + +UNPACK_Regular_SSE_2 macro r0 + paddd r0, XMM_ROW + movdqa XMM_ROW, r0 + endm + +;; setting up masks +UNPACK_Setup_Mask_SSE macro CL + mov VIF_TMPADDR, [_vifMaskRegs] + movdqa XMM_ROWMASK, [VIF_TMPADDR + 64*(CL) + 16] + movdqa XMM_ROWCOLMASK, [VIF_TMPADDR + 64*(CL) + 32] + movdqa XMM_WRITEMASK, [VIF_TMPADDR + 64*(CL)] + pand XMM_ROWMASK, XMM_ROW + pand XMM_ROWCOLMASK, XMM_COL + por XMM_ROWCOLMASK, XMM_ROWMASK + endm + +UNPACK_Start_Setup_Mask_SSE_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + +UNPACK_Start_Setup_Mask_SSE_1 macro CL + mov VIF_TMPADDR, [_vifMaskRegs] + movdqa XMM_ROWMASK, [VIF_TMPADDR + 64*(CL) + 16] + movdqa XMM_ROWCOLMASK, [VIF_TMPADDR + 64*(CL) + 32] + pand XMM_ROWMASK, XMM_ROW + pand XMM_ROWCOLMASK, XMM_COL + por XMM_ROWCOLMASK, XMM_ROWMASK + endm + +UNPACK_Start_Setup_Mask_SSE_2 macro CL + endm + +UNPACK_Setup_Mask_SSE_0_1 macro CL + endm +UNPACK_Setup_Mask_SSE_1_1 macro CL + mov VIF_TMPADDR, [_vifMaskRegs] + movdqa XMM_WRITEMASK, [VIF_TMPADDR + 64*(0)] + endm + +;; ignore CL, since vif.cycle.wl == 1 +UNPACK_Setup_Mask_SSE_2_1 macro CL + ;; ignore CL, since vif.cycle.wl == 1 + mov VIF_TMPADDR, [_vifMaskRegs] + movdqa XMM_ROWMASK, [VIF_TMPADDR + 64*(0) + 16] + movdqa XMM_ROWCOLMASK, [VIF_TMPADDR + 64*(0) + 32] + movdqa XMM_WRITEMASK, [VIF_TMPADDR + 64*(0)] + pand XMM_ROWMASK, XMM_ROW + pand XMM_ROWCOLMASK, XMM_COL + por XMM_ROWCOLMASK, XMM_ROWMASK + endm + +UNPACK_Setup_Mask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + +;; write mask always destroys XMM_WRITEMASK, so 0_0 = 1_0 +UNPACK_Setup_WriteMask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_0_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_1_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_2_1 macro CL + UNPACK_Setup_Mask_SSE_2_1 CL + endm + +UNPACK_Start_Setup_WriteMask_SSE_0 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_1 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_2 macro CL + UNPACK_Start_Setup_Mask_SSE_2 CL + endm + +UNPACK_Start_Setup_Regular_SSE_0 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_1 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_2 macro CL + endm +UNPACK_Setup_Regular_SSE_0_0 macro CL + endm +UNPACK_Setup_Regular_SSE_1_0 macro CL + endm +UNPACK_Setup_Regular_SSE_2_0 macro CL + endm +UNPACK_Setup_Regular_SSE_0_1 macro CL + endm +UNPACK_Setup_Regular_SSE_1_1 macro CL + endm +UNPACK_Setup_Regular_SSE_2_1 macro CL + endm + +UNPACK_INC_DST_0_Regular macro qw + add VIF_DST, (16*qw) + endm +UNPACK_INC_DST_1_Regular macro qw + endm +UNPACK_INC_DST_0_Mask macro qw + add VIF_DST, (16*qw) + endm +UNPACK_INC_DST_1_Mask macro qw + endm +UNPACK_INC_DST_0_WriteMask macro qw + endm +UNPACK_INC_DST_1_WriteMask macro qw + endm + +;; unpacks for 1,2,3,4 elements (V3 uses this directly) +UNPACK4_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R3 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R3, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + endm + +;; V3 uses this directly +UNPACK3_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + endm + +UNPACK2_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R1, CL+1, 16, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 2 + endm + +UNPACK1_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 1 + endm + +;; S-32 +;; only when cl==1 +UNPACK_S_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R3, [VIF_SRC] + + pshufd XMM_R0, XMM_R3, 0 + pshufd XMM_R1, XMM_R3, 055h + pshufd XMM_R2, XMM_R3, 0aah + pshufd XMM_R3, XMM_R3, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_S_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R2, [VIF_SRC] + + pshufd XMM_R0, XMM_R2, 0 + pshufd XMM_R1, XMM_R2, 055h + pshufd XMM_R2, XMM_R2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_S_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R1, QWORD PTR [VIF_SRC] + + pshufd XMM_R0, XMM_R1, 0 + pshufd XMM_R1, XMM_R1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_S_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + pshufd XMM_R0, XMM_R0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_S_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; S-16 +UNPACK_S_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R3, QWORD PTR [VIF_SRC] + punpcklwd XMM_R3, XMM_R3 + UNPACK_RIGHTSHIFT XMM_R3, 16 + + pshufd XMM_R0, XMM_R3, 0 + pshufd XMM_R1, XMM_R3, 055h + pshufd XMM_R2, XMM_R3, 0aah + pshufd XMM_R3, XMM_R3, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_S_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R2, QWORD PTR [VIF_SRC] + punpcklwd XMM_R2, XMM_R2 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + pshufd XMM_R0, XMM_R2, 0 + pshufd XMM_R1, XMM_R2, 055h + pshufd XMM_R2, XMM_R2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + add VIF_SRC, 6 + endm + +UNPACK_S_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R1, dword ptr [VIF_SRC] + punpcklwd XMM_R1, XMM_R1 + UNPACK_RIGHTSHIFT XMM_R1, 16 + + pshufd XMM_R0, XMM_R1, 0 + pshufd XMM_R1, XMM_R1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_S_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 16 + pshufd XMM_R0, XMM_R0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 2 + endm + +UNPACK_S_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; S-8 +UNPACK_S_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R3, dword ptr [VIF_SRC] + punpcklbw XMM_R3, XMM_R3 + punpcklwd XMM_R3, XMM_R3 + UNPACK_RIGHTSHIFT XMM_R3, 24 + + pshufd XMM_R0, XMM_R3, 0 + pshufd XMM_R1, XMM_R3, 055h + pshufd XMM_R2, XMM_R3, 0aah + pshufd XMM_R3, XMM_R3, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_S_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R2, dword ptr [VIF_SRC] + punpcklbw XMM_R2, XMM_R2 + punpcklwd XMM_R2, XMM_R2 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + pshufd XMM_R0, XMM_R2, 0 + pshufd XMM_R1, XMM_R2, 055h + pshufd XMM_R2, XMM_R2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 3 + endm + +UNPACK_S_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R1, dword ptr [VIF_SRC] + punpcklbw XMM_R1, XMM_R1 + punpcklwd XMM_R1, XMM_R1 + UNPACK_RIGHTSHIFT XMM_R1, 24 + + pshufd XMM_R0, XMM_R1, 0 + pshufd XMM_R1, XMM_R1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 2 + endm + +UNPACK_S_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + pshufd XMM_R0, XMM_R0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + inc VIF_SRC + endm + +UNPACK_S_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; V2-32 +UNPACK_V2_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + MOVDQA XMM_R0, [VIF_SRC] + MOVDQA XMM_R2, [VIF_SRC+16] + + pshufd XMM_R1, XMM_R0, 0eeh + pshufd XMM_R3, XMM_R2, 0eeh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V2_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+8] + movq XMM_R2, QWORD PTR [VIF_SRC+16] + movq XMM_R3, QWORD PTR [VIF_SRC+24] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V2_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + MOVDQA XMM_R0, [VIF_SRC] + movq XMM_R2, QWORD PTR [VIF_SRC+16] + pshufd XMM_R1, XMM_R0, 0eeh + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V2_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+8] + movq XMM_R2, QWORD PTR [VIF_SRC+16] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V2_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+8] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V2_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V2_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; V2-16 +;; due to lemmings, have to copy lower qword to the upper qword of every reg +UNPACK_V2_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + punpckhwd XMM_R2, [VIF_SRC] + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + punpckhqdq XMM_R3, XMM_R2 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + punpckhqdq XMM_R3, XMM_R3 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + add VIF_SRC, 16 + endm + +UNPACK_V2_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + + punpckhwd XMM_R2, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + punpckhqdq XMM_R3, XMM_R2 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + punpckhqdq XMM_R3, XMM_R3 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V2_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + punpckhwd XMM_R2, [VIF_SRC] + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V2_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + + punpckhwd XMM_R2, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V2_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + UNPACK_RIGHTSHIFT XMM_R0, 16 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V2_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 16 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V2_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + UNPACK_RIGHTSHIFT XMM_R0, 16 + punpcklqdq XMM_R0, XMM_R0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_V2_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 16 + punpcklqdq XMM_R0, XMM_R0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +;; V2-8 +;; and1 streetball needs to copy lower qword to the upper qword of every reg +UNPACK_V2_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + + punpcklbw XMM_R0, XMM_R0 + punpckhwd XMM_R2, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + punpckhqdq XMM_R3, XMM_R2 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + punpckhqdq XMM_R3, XMM_R3 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V2_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + + punpcklbw XMM_R0, XMM_R0 + punpckhwd XMM_R2, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpcklqdq XMM_R2, XMM_R2 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 6 + endm + +UNPACK_V2_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + ;; move the lower 64 bits down + punpckhqdq XMM_R1, XMM_R0 + + punpcklqdq XMM_R0, XMM_R0 + punpckhqdq XMM_R1, XMM_R1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_V2_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + punpcklqdq XMM_R0, XMM_R0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 2 + endm + +UNPACK_V2_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; V3-32 +UNPACK_V3_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R1, CL+1, 16, movdqa + + ;; midnight club 2 crashes because reading a qw at +36 is out of bounds + MOVDQA XMM_R3, [VIF_SRC+32] + movdqu XMM_R2, [VIF_SRC+24] + psrldq XMM_R3, 4 + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R3 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R3, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + + add VIF_SRC, 48 + endm + +UNPACK_V3_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R1, CL+1, 16, movdqa + + movdqu XMM_R2, [VIF_SRC+24] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) XMM_R2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) XMM_R2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + + add VIF_SRC, 36 + endm + +UNPACK_V3_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_2x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+12] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V3_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_1x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA XMM_R0, [VIF_SRC] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V3_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +;; V3-16 +UNPACK_V3_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+6] + + punpcklwd XMM_R0, XMM_R0 + movq XMM_R2, QWORD PTR [VIF_SRC+12] + punpcklwd XMM_R1, XMM_R1 + UNPACK_RIGHTSHIFT XMM_R0, 16 + movq XMM_R3, QWORD PTR [VIF_SRC+18] + UNPACK_RIGHTSHIFT XMM_R1, 16 + punpcklwd XMM_R2, XMM_R2 + punpcklwd XMM_R3, XMM_R3 + + UNPACK_RIGHTSHIFT XMM_R2, 16 + UNPACK_RIGHTSHIFT XMM_R3, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V3_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+6] + + punpcklwd XMM_R0, XMM_R0 + movq XMM_R2, QWORD PTR [VIF_SRC+12] + punpcklwd XMM_R1, XMM_R1 + UNPACK_RIGHTSHIFT XMM_R0, 16 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R1, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 18 + endm + +UNPACK_V3_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+6] + + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R1, XMM_R1 + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V3_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 6 + endm + +UNPACK_V3_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; V3-8 +UNPACK_V3_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R1, QWORD PTR [VIF_SRC] + movq XMM_R3, QWORD PTR [VIF_SRC+6] + + punpcklbw XMM_R1, XMM_R1 + punpcklbw XMM_R3, XMM_R3 + punpcklwd XMM_R0, XMM_R1 + psrldq XMM_R1, 6 + punpcklwd XMM_R2, XMM_R3 + psrldq XMM_R3, 6 + punpcklwd XMM_R1, XMM_R1 + UNPACK_RIGHTSHIFT XMM_R0, 24 + punpcklwd XMM_R3, XMM_R3 + + UNPACK_RIGHTSHIFT XMM_R2, 24 + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R3, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V3_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + movd XMM_R1, dword ptr [VIF_SRC+3] + + punpcklbw XMM_R0, XMM_R0 + movd XMM_R2, dword ptr [VIF_SRC+6] + punpcklbw XMM_R1, XMM_R1 + punpcklwd XMM_R0, XMM_R0 + punpcklbw XMM_R2, XMM_R2 + + punpcklwd XMM_R1, XMM_R1 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 9 + endm + +UNPACK_V3_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + movd XMM_R1, dword ptr [VIF_SRC+3] + + punpcklbw XMM_R0, XMM_R0 + punpcklbw XMM_R1, XMM_R1 + + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R1, XMM_R1 + + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 6 + endm + +UNPACK_V3_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 3 + endm + +UNPACK_V3_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; V4-32 +UNPACK_V4_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + movdqa XMM_R0, [VIF_SRC] + movdqa XMM_R1, [VIF_SRC+16] + movdqa XMM_R2, [VIF_SRC+32] + movdqa XMM_R3, [VIF_SRC+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 64 + endm + +UNPACK_V4_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+16] + movdqu XMM_R2, [VIF_SRC+32] + movdqu XMM_R3, [VIF_SRC+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 64 + endm + +UNPACK_V4_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + movdqa XMM_R0, [VIF_SRC] + movdqa XMM_R1, [VIF_SRC+16] + movdqa XMM_R2, [VIF_SRC+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 48 + endm + +UNPACK_V4_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+16] + movdqu XMM_R2, [VIF_SRC+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 48 + endm + +UNPACK_V4_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + movdqa XMM_R0, [VIF_SRC] + movdqa XMM_R1, [VIF_SRC+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V4_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + movdqu XMM_R1, [VIF_SRC+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V4_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + movdqa XMM_R0, [VIF_SRC] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V4_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +;; V4-16 +UNPACK_V4_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + + punpcklwd XMM_R0, [VIF_SRC] + punpckhwd XMM_R1, [VIF_SRC] + punpcklwd XMM_R2, [VIF_SRC+16] + punpckhwd XMM_R3, [VIF_SRC+16] + + UNPACK_RIGHTSHIFT XMM_R1, 16 + UNPACK_RIGHTSHIFT XMM_R3, 16 + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V4_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + movdqu XMM_R2, [VIF_SRC+16] + + punpckhwd XMM_R1, XMM_R0 + punpckhwd XMM_R3, XMM_R2 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R1, 16 + UNPACK_RIGHTSHIFT XMM_R3, 16 + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 32 + endm + +UNPACK_V4_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + punpckhwd XMM_R1, [VIF_SRC] + punpcklwd XMM_R2, [VIF_SRC+16] + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R1, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V4_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + movq XMM_R2, QWORD PTR [VIF_SRC+16] + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R1, 16 + UNPACK_RIGHTSHIFT XMM_R2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 24 + endm + +UNPACK_V4_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + punpckhwd XMM_R1, [VIF_SRC] + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V4_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movq XMM_R1, QWORD PTR [VIF_SRC+8] + + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R1, XMM_R1 + + UNPACK_RIGHTSHIFT XMM_R0, 16 + UNPACK_RIGHTSHIFT XMM_R1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V4_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd XMM_R0, [VIF_SRC] + UNPACK_RIGHTSHIFT XMM_R0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V4_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +;; V4-8 +UNPACK_V4_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklbw XMM_R0, [VIF_SRC] + punpckhbw XMM_R2, [VIF_SRC] + + punpckhwd XMM_R1, XMM_R0 + punpckhwd XMM_R3, XMM_R2 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R3, 24 + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V4_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu XMM_R0, [VIF_SRC] + + punpckhbw XMM_R2, XMM_R0 + punpcklbw XMM_R0, XMM_R0 + + punpckhwd XMM_R3, XMM_R2 + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R3, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R1, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 16 + endm + +UNPACK_V4_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklbw XMM_R0, [VIF_SRC] + punpckhbw XMM_R2, [VIF_SRC] + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V4_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + movd XMM_R2, dword ptr [VIF_SRC+8] + + punpcklbw XMM_R0, XMM_R0 + punpcklbw XMM_R2, XMM_R2 + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R0, 24 + UNPACK_RIGHTSHIFT XMM_R2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 12 + endm + +UNPACK_V4_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklbw XMM_R0, [VIF_SRC] + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V4_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq XMM_R0, QWORD PTR [VIF_SRC] + + punpcklbw XMM_R0, XMM_R0 + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + UNPACK_RIGHTSHIFT XMM_R1, 24 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V4_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklbw XMM_R0, [VIF_SRC] + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_V4_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd XMM_R0, dword ptr [VIF_SRC] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + UNPACK_RIGHTSHIFT XMM_R0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +;; V4-5 +DECOMPRESS_RGBA macro OFFSET + mov bl, al + shl bl, 3 + mov byte ptr [s_TempDecompress+OFFSET], bl + + mov bx, ax + shr bx, 2 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+1], bl + + mov bx, ax + shr bx, 7 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+2], bl + mov bx, ax + shr bx, 8 + and bx, 080h + mov byte ptr [s_TempDecompress+OFFSET+3], bl + endm + +UNPACK_V4_5SSE_4 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [VIF_SRC] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [VIF_SRC+4] + DECOMPRESS_RGBA 8 + + shr eax, 16 + DECOMPRESS_RGBA 12 + + ;; have to use movaps instead of movdqa +%ifdef __x86_64__ + movdqa XMM_R0, XMMWORD PTR [s_TempDecompress] +%else + movaps XMM_R0, [s_TempDecompress] +%endif + + punpckhbw XMM_R2, XMM_R0 + punpcklbw XMM_R0, XMM_R0 + + punpckhwd XMM_R3, XMM_R2 + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + psrld XMM_R0, 24 + psrld XMM_R1, 24 + psrld XMM_R2, 24 + psrld XMM_R3, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 8 + endm + +UNPACK_V4_5SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_3 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [VIF_SRC] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [VIF_SRC] + DECOMPRESS_RGBA 8 + + ;; have to use movaps instead of movdqa +%ifdef __x86_64__ + movdqa XMM_R0, XMMWORD PTR [s_TempDecompress] +%else + movaps XMM_R0, [s_TempDecompress] +%endif + + punpckhbw XMM_R2, XMM_R0 + punpcklbw XMM_R0, XMM_R0 + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + punpcklwd XMM_R2, XMM_R2 + + psrld XMM_R0, 24 + psrld XMM_R1, 24 + psrld XMM_R2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 6 + endm + +UNPACK_V4_5SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_2 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [VIF_SRC] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + movq XMM_R0, QWORD PTR [s_TempDecompress] + + punpcklbw XMM_R0, XMM_R0 + + punpckhwd XMM_R1, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + psrld XMM_R0, 24 + psrld XMM_R1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 4 + endm + +UNPACK_V4_5SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_1 macro CL, TOTALCL, MaskType, ModeType + mov ax, word ptr [VIF_SRC] + DECOMPRESS_RGBA 0 + + movd XMM_R0, DWORD PTR [s_TempDecompress] + punpcklbw XMM_R0, XMM_R0 + punpcklwd XMM_R0, XMM_R0 + + psrld XMM_R0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add VIF_SRC, 2 + endm + +UNPACK_V4_5SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_1 CL, TOTALCL, MaskType, ModeType + endm + +;; save the row reg +SAVE_ROW_REG_BASE macro + mov VIF_TMPADDR, [_vifRow] + movdqa [VIF_TMPADDR], XMM_ROW + mov VIF_TMPADDR, [_vifRegs] + movss dword ptr [VIF_TMPADDR+0100h], XMM_ROW + psrldq XMM_ROW, 4 + movss dword ptr [VIF_TMPADDR+0110h], XMM_ROW + psrldq XMM_ROW, 4 + movss dword ptr [VIF_TMPADDR+0120h], XMM_ROW + psrldq XMM_ROW, 4 + movss dword ptr [VIF_TMPADDR+0130h], XMM_ROW + endm + +SAVE_NO_REG macro + endm + +%ifdef __x86_64__ + +INIT_ARGS macro + mov rax, qword ptr [_vifRow] + mov r9, qword ptr [_vifCol] + movaps xmm6, XMMWORD PTR [rax] + movaps xmm7, XMMWORD PTR [r9] + endm + +INC_STACK macro reg + add rsp, 8 + endm + +%else + +%define STACKOFFSET 12 + +;; 32 bit versions have the args on the stack +INIT_ARGS macro + mov VIF_DST, dword ptr [esp+4+STACKOFFSET] + mov VIF_SRC, dword ptr [esp+8+STACKOFFSET] + mov VIF_SIZE, dword ptr [esp+12+STACKOFFSET] + endm + +INC_STACK macro reg + add esp, 4 + endm + +%endif + +;; qsize - bytes of compressed size of 1 decompressed qword +;; int UNPACK_SkippingWrite_##name##_##sign##_##MaskType##_##ModeType(u32* dest, u32* data, int dmasize) +defUNPACK_SkippingWrite macro name, MaskType, ModeType, qsize, sign, SAVE_ROW_REG +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType) proc public +%ifdef __x86_64__ + push rdi +%else + push edi + push esi + push ebx +%endif + INIT_ARGS + mov VIF_TMPADDR, [_vifRegs] + movzx VIF_INC, byte ptr [VIF_TMPADDR + 040h] + movzx VIF_SAVEEBX, byte ptr [VIF_TMPADDR + 041h] + sub VIF_INC, VIF_SAVEEBX + shl VIF_INC, 4 + + cmp VIF_SAVEEBXd, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1) + cmp VIF_SAVEEBXd, 2 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2) + cmp VIF_SAVEEBXd, 3 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1): + @CatStr(UNPACK_Start_Setup_, MaskType, _SSE_, ModeType) 0 + + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + + add VIF_INC, 16 + + ;; first align VIF_SRC to 16 bytes +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16): + + test VIF_SRC, 15 + jz @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned) + + @CatStr(UNPACK_, name, SSE_1) 0, 1, MaskType, ModeType + + cmp VIF_SIZE, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec) + sub VIF_SIZE, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned): + + cmp VIF_SIZE, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp VIF_SIZE, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + cmp VIF_SIZE, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3) + prefetchnta [VIF_SRC + 64] + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4): + @CatStr(UNPACK_, name, SSE_4A) 0, 1, MaskType, ModeType + + cmp VIF_SIZE, (8*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4) + sub VIF_SIZE, (4*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4): + + sub VIF_SIZE, (4*qsize) + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + cmp VIF_SIZE, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp VIF_SIZE, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + ;; fall through + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3): + @CatStr(UNPACK_, name, SSE_3A) 0, 1, MaskType, ModeType + + sub VIF_SIZE, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2): + @CatStr(UNPACK_, name, SSE_2A) 0, 1, MaskType, ModeType + + sub VIF_SIZE, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1): + @CatStr(UNPACK_, name, SSE_1A) 0, 1, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec): + sub VIF_SIZE, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3): + SAVE_ROW_REG + mov eax, VIF_SIZE +%ifdef __x86_64__ + pop rdi +%else + pop ebx + pop esi + pop edi +%endif + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2): + cmp VIF_SIZE, (2*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + ;; take into account wl + add VIF_DST, VIF_INC + cmp VIF_SIZE, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2) + sub VIF_SIZE, (2*qsize) + ;; unpack next + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2): + sub VIF_SIZE, (2*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3): + cmp VIF_SIZE, qsize + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4) + + ;; execute left over qw + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + sub VIF_SIZE, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4): + + SAVE_ROW_REG + mov eax, VIF_SIZE +%ifdef __x86_64__ + pop rdi +%else + pop ebx + pop esi + pop edi +%endif + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3): + cmp VIF_SIZE, (3*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + add VIF_DST, VIF_INC + cmp VIF_SIZE, (6*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2) + sub VIF_SIZE, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2): + sub VIF_SIZE, (3*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5): + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) + + cmp VIF_SIZE, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3) + + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + sub VIF_SIZE, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3): + sub VIF_SIZE, qsize + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4): + SAVE_ROW_REG + mov eax, VIF_SIZE +%ifdef __x86_64__ + pop rdi +%else + pop ebx + pop esi + pop edi +%endif + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4): + sub VIF_SAVEEBX, 3 + push VIF_INC + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack): + cmp VIF_SIZE, (3*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3) + cmp VIF_SIZE, (2*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2) + + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + ;; not enough data left + sub VIF_SIZE, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + ;; not enough data left + sub VIF_SIZE, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + ;; more data left, process 1qw at a time + sub VIF_SIZE, (3*qsize) + mov VIF_INC, VIF_SAVEEBX + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX): + + ;; check if any data left + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + + @CatStr(UNPACK_, name, SSE_1) 3, 0, MaskType, ModeType + + sub VIF_SIZE, qsize + cmp VIF_INC, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop) + sub VIF_INC, 1 + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop): + add VIF_DST, [VIF_ESP] + cmp VIF_SIZE, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done): + + SAVE_ROW_REG + INC_STACK() + mov eax, VIF_SIZE + +%ifdef __x86_64__ + pop rdi +%else + pop ebx + pop esi + pop edi +%endif + ret +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType endp) +endm + +UNPACK_RIGHTSHIFT macro reg, shift + psrld reg, shift + endm + +defUNPACK_SkippingWrite2 macro name, qsize + defUNPACK_SkippingWrite name, Regular, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, u, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2 S_32, 4 +defUNPACK_SkippingWrite2 S_16, 2 +defUNPACK_SkippingWrite2 S_8, 1 +defUNPACK_SkippingWrite2 V2_32, 8 +defUNPACK_SkippingWrite2 V2_16, 4 +defUNPACK_SkippingWrite2 V2_8, 2 +defUNPACK_SkippingWrite2 V3_32, 12 +defUNPACK_SkippingWrite2 V3_16, 6 +defUNPACK_SkippingWrite2 V3_8, 3 +defUNPACK_SkippingWrite2 V4_32, 16 +defUNPACK_SkippingWrite2 V4_16, 8 +defUNPACK_SkippingWrite2 V4_8, 4 +defUNPACK_SkippingWrite2 V4_5, 2 + +UNPACK_RIGHTSHIFT macro reg, shift + psrad reg, shift + endm + + +defUNPACK_SkippingWrite2a macro name, qsize + defUNPACK_SkippingWrite name, Mask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, s, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2a S_16, 2 +defUNPACK_SkippingWrite2a S_8, 1 +defUNPACK_SkippingWrite2a V2_16, 4 +defUNPACK_SkippingWrite2a V2_8, 2 +defUNPACK_SkippingWrite2a V3_16, 6 +defUNPACK_SkippingWrite2a V3_8, 3 +defUNPACK_SkippingWrite2a V4_16, 8 +defUNPACK_SkippingWrite2a V4_8, 4 + +end diff --git a/pcsx2/x86/fast_routines.S b/pcsx2/x86/fast_routines.S new file mode 100644 index 0000000000..ff08b861c5 --- /dev/null +++ b/pcsx2/x86/fast_routines.S @@ -0,0 +1,349 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2005 Pcsx2 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 + */ + +// Fast assembly routines for x86-64 +// zerofrog(@gmail.com) +.intel_syntax +.extern g_EEFreezeRegs +.extern FreezeMMXRegs_ + +// mmx memcmp implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +// u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +#ifdef __x86_64__ +#define MEMCMP_SRC1 %rdi +#define MEMCMP_SRC2 %rsi +#define MEMCMP_SIZE %edx +#else +#define MEMCMP_SRC1 %edx +#define MEMCMP_SRC2 %esi +#define MEMCMP_SIZE %ecx +#endif + +.globl memcmp_mmx +memcmp_mmx: +#ifndef __x86_64__ + // make sure mmx regs are stored + // FreezeMMXRegs(1); + cmp dword ptr [g_EEFreezeRegs], 0 + je memcmp_mmx_begin + push 1 + call FreezeMMXRegs_ + add %esp, 4 + +memcmp_mmx_begin: + push %esi + mov MEMCMP_SRC1, dword ptr [%esp+8] + mov MEMCMP_SRC2, dword ptr [%esp+12] + mov MEMCMP_SIZE, dword ptr [%esp+16] +#endif + + cmp MEMCMP_SIZE, 32 + jl memcmp_Done4 + + // custom test first 8 to make sure things are ok + movq %mm0, [MEMCMP_SRC2] + movq %mm1, [MEMCMP_SRC2+8] + pcmpeqd %mm0, [MEMCMP_SRC1] + pcmpeqd %mm1, [MEMCMP_SRC1+8] + pand %mm0, %mm1 + movq %mm2, [MEMCMP_SRC2+16] + pmovmskb %eax, %mm0 + movq %mm3, [MEMCMP_SRC2+24] + + // check if eq + cmp %eax, 0xff + je memcmp_NextComp + mov %eax, 1 + jmp memcmp_End + +memcmp_NextComp: + pcmpeqd %mm2, [MEMCMP_SRC1+16] + pcmpeqd %mm3, [MEMCMP_SRC1+24] + pand %mm2, %mm3 + pmovmskb %eax, %mm2 + + sub MEMCMP_SIZE, 32 + add MEMCMP_SRC2, 32 + add MEMCMP_SRC1, 32 + + // check if eq + cmp %eax, 0xff + je memcmp_ContinueTest + mov %eax, 1 + jmp memcmp_End + + cmp MEMCMP_SIZE, 64 + jl memcmp_Done8 + +memcmp_Cmp8: + movq %mm0, [MEMCMP_SRC2] + movq %mm1, [MEMCMP_SRC2+8] + movq %mm2, [MEMCMP_SRC2+16] + movq %mm3, [MEMCMP_SRC2+24] + movq %mm4, [MEMCMP_SRC2+32] + movq %mm5, [MEMCMP_SRC2+40] + movq %mm6, [MEMCMP_SRC2+48] + movq %mm7, [MEMCMP_SRC2+56] + pcmpeqd %mm0, [MEMCMP_SRC1] + pcmpeqd %mm1, [MEMCMP_SRC1+8] + pcmpeqd %mm2, [MEMCMP_SRC1+16] + pcmpeqd %mm3, [MEMCMP_SRC1+24] + pand %mm0, %mm1 + pcmpeqd %mm4, [MEMCMP_SRC1+32] + pand %mm0, %mm2 + pcmpeqd %mm5, [MEMCMP_SRC1+40] + pand %mm0, %mm3 + pcmpeqd %mm6, [MEMCMP_SRC1+48] + pand %mm0, %mm4 + pcmpeqd %mm7, [MEMCMP_SRC1+56] + pand %mm0, %mm5 + pand %mm0, %mm6 + pand %mm0, %mm7 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je memcmp_Continue + mov %eax, 1 + jmp memcmp_End + +memcmp_Continue: + sub MEMCMP_SIZE, 64 + add MEMCMP_SRC2, 64 + add MEMCMP_SRC1, 64 +memcmp_ContinueTest: + cmp MEMCMP_SIZE, 64 + jge memcmp_Cmp8 + +memcmp_Done8: + test MEMCMP_SIZE, 0x20 + jz memcmp_Done4 + movq %mm0, [MEMCMP_SRC2] + movq %mm1, [MEMCMP_SRC2+8] + movq %mm2, [MEMCMP_SRC2+16] + movq %mm3, [MEMCMP_SRC2+24] + pcmpeqd %mm0, [MEMCMP_SRC1] + pcmpeqd %mm1, [MEMCMP_SRC1+8] + pcmpeqd %mm2, [MEMCMP_SRC1+16] + pcmpeqd %mm3, [MEMCMP_SRC1+24] + pand %mm0, %mm1 + pand %mm0, %mm2 + pand %mm0, %mm3 + pmovmskb %eax, %mm0 + sub MEMCMP_SIZE, 32 + add MEMCMP_SRC2, 32 + add MEMCMP_SRC1, 32 + + // check if eq + cmp %eax, 0xff + je memcmp_Done4 + mov %eax, 1 + jmp memcmp_End + +memcmp_Done4: + cmp MEMCMP_SIZE, 24 + jne memcmp_Done2 + movq %mm0, [MEMCMP_SRC2] + movq %mm1, [MEMCMP_SRC2+8] + movq %mm2, [MEMCMP_SRC2+16] + pcmpeqd %mm0, [MEMCMP_SRC1] + pcmpeqd %mm1, [MEMCMP_SRC1+8] + pcmpeqd %mm2, [MEMCMP_SRC1+16] + pand %mm0, %mm1 + pand %mm0, %mm2 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je memcmp_Done + mov %eax, 1 + jmp memcmp_End + +memcmp_Done2: + cmp MEMCMP_SIZE, 16 + jne memcmp_Done1 + + movq %mm0, [MEMCMP_SRC2] + movq %mm1, [MEMCMP_SRC2+8] + pcmpeqd %mm0, [MEMCMP_SRC1] + pcmpeqd %mm1, [MEMCMP_SRC1+8] + pand %mm0, %mm1 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je memcmp_Done + mov %eax, 1 + jmp memcmp_End + +memcmp_Done1: + cmp MEMCMP_SIZE, 8 + jne memcmp_Done + + mov %eax, [MEMCMP_SRC2] + mov MEMCMP_SRC2, [MEMCMP_SRC2+4] + cmp %eax, [MEMCMP_SRC1] + je memcmp_Next + mov %eax, 1 + jmp memcmp_End + +memcmp_Next: + cmp MEMCMP_SRC2, [MEMCMP_SRC1+4] + je memcmp_Done + mov %eax, 1 + jmp memcmp_End + +memcmp_Done: + xor %eax, %eax + +memcmp_End: + emms +#ifndef __x86_64__ + pop %esi +#endif + ret + +// memxor_mmx +#ifdef __x86_64__ +#define MEMXOR_SRC1 %rdi +#define MEMXOR_SRC2 %rsi +#define MEMXOR_SIZE %edx +#else +#define MEMXOR_SRC1 %edx +#define MEMXOR_SRC2 %esi +#define MEMXOR_SIZE %ecx +#endif + +.globl memxor_mmx +memxor_mmx: +#ifndef __x86_64__ + // make sure mmx regs are stored + // FreezeMMXRegs(1); + cmp dword ptr [g_EEFreezeRegs], 0 + je memxor_mmx_begin + push 1 + call FreezeMMXRegs_ + add %esp, 4 + +memxor_mmx_begin: + push %esi + mov MEMXOR_SRC1, dword ptr [%esp+8] + mov MEMXOR_SRC2, dword ptr [%esp+12] + mov MEMXOR_SIZE, dword ptr [%esp+16] +#endif + cmp MEMXOR_SIZE, 64 + jl memxor_Setup4 + + movq %mm0, [MEMXOR_SRC2] + movq %mm1, [MEMXOR_SRC2+8] + movq %mm2, [MEMXOR_SRC2+16] + movq %mm3, [MEMXOR_SRC2+24] + movq %mm4, [MEMXOR_SRC2+32] + movq %mm5, [MEMXOR_SRC2+40] + movq %mm6, [MEMXOR_SRC2+48] + movq %mm7, [MEMXOR_SRC2+56] + sub MEMXOR_SIZE, 64 + add MEMXOR_SRC2, 64 + cmp MEMXOR_SIZE, 64 + jl memxor_End8 + +memxor_Cmp8: + pxor %mm0, [MEMXOR_SRC2] + pxor %mm1, [MEMXOR_SRC2+8] + pxor %mm2, [MEMXOR_SRC2+16] + pxor %mm3, [MEMXOR_SRC2+24] + pxor %mm4, [MEMXOR_SRC2+32] + pxor %mm5, [MEMXOR_SRC2+40] + pxor %mm6, [MEMXOR_SRC2+48] + pxor %mm7, [MEMXOR_SRC2+56] + + sub MEMXOR_SIZE, 64 + add MEMXOR_SRC2, 64 + cmp MEMXOR_SIZE, 64 + jge memxor_Cmp8 + +memxor_End8: + pxor %mm0, %mm4 + pxor %mm1, %mm5 + pxor %mm2, %mm6 + pxor %mm3, %mm7 + + cmp MEMXOR_SIZE, 32 + jl memxor_End4 + pxor %mm0, [MEMXOR_SRC2] + pxor %mm1, [MEMXOR_SRC2+8] + pxor %mm2, [MEMXOR_SRC2+16] + pxor %mm3, [MEMXOR_SRC2+24] + sub MEMXOR_SIZE, 32 + add MEMXOR_SRC2, 32 + jmp memxor_End4 + +memxor_Setup4: + cmp MEMXOR_SIZE, 32 + jl memxor_Setup2 + + movq %mm0, [MEMXOR_SRC2] + movq %mm1, [MEMXOR_SRC2+8] + movq %mm2, [MEMXOR_SRC2+16] + movq %mm3, [MEMXOR_SRC2+24] + sub MEMXOR_SIZE, 32 + add MEMXOR_SRC2, 32 + +memxor_End4: + pxor %mm0, %mm2 + pxor %mm1, %mm3 + + cmp MEMXOR_SIZE, 16 + jl memxor_End2 + pxor %mm0, [MEMXOR_SRC2] + pxor %mm1, [MEMXOR_SRC2+8] + sub MEMXOR_SIZE, 16 + add MEMXOR_SRC2, 16 + jmp memxor_End2 + +memxor_Setup2: + cmp MEMXOR_SIZE, 16 + jl memxor_Setup1 + + movq %mm0, [MEMXOR_SRC2] + movq %mm1, [MEMXOR_SRC2+8] + sub MEMXOR_SIZE, 16 + add MEMXOR_SRC2, 16 + +memxor_End2: + pxor %mm0, %mm1 + + cmp MEMXOR_SIZE, 8 + jl memxor_End1 + pxor %mm0, [MEMXOR_SRC2] +memxor_End1: + movq [MEMXOR_SRC1], %mm0 + jmp memxor_End + +memxor_Setup1: + movq %mm0, [MEMXOR_SRC2] + movq [MEMXOR_SRC1], %mm0 +memxor_End: + emms +#ifndef __x86_64__ + pop %esi +#endif + ret diff --git a/pcsx2/x86/fast_routines.cpp b/pcsx2/x86/fast_routines.cpp new file mode 100644 index 0000000000..0e59069f22 --- /dev/null +++ b/pcsx2/x86/fast_routines.cpp @@ -0,0 +1,596 @@ +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +extern "C" { + +#include "PS2Etypes.h" + +#ifdef _WIN32 +#include +#endif + +#include "Misc.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +#ifdef _DEBUG +extern char g_globalMMXLocked, g_globalMMXSaved; + +void checkregs() +{ + assert( !g_globalMMXLocked || g_globalMMXSaved ); +} +#endif + +void * memcpy_amd_(void *dest, const void *src, size_t n) +{ + + +#ifdef _DEBUG + __asm call checkregs +#endif + + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { + push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + + +// returns the xor of all elements, cmpsize has to be mult of 8 +void memxor_mmx(void* dst, const void* src1, int cmpsize) +{ + FreezeMMXRegs(1); + assert( (cmpsize&7) == 0 ); + + __asm { + mov ecx, cmpsize + mov eax, src1 + mov edx, dst + + cmp ecx, 64 + jl Setup4 + + movq mm0, [eax] + movq mm1, [eax+8] + movq mm2, [eax+16] + movq mm3, [eax+24] + movq mm4, [eax+32] + movq mm5, [eax+40] + movq mm6, [eax+48] + movq mm7, [eax+56] + sub ecx, 64 + add eax, 64 + cmp ecx, 64 + jl End8 + +Cmp8: + pxor mm0, [eax] + pxor mm1, [eax+8] + pxor mm2, [eax+16] + pxor mm3, [eax+24] + pxor mm4, [eax+32] + pxor mm5, [eax+40] + pxor mm6, [eax+48] + pxor mm7, [eax+56] + + sub ecx, 64 + add eax, 64 + cmp ecx, 64 + jge Cmp8 + +End8: + pxor mm0, mm4 + pxor mm1, mm5 + pxor mm2, mm6 + pxor mm3, mm7 + + cmp ecx, 32 + jl End4 + pxor mm0, [eax] + pxor mm1, [eax+8] + pxor mm2, [eax+16] + pxor mm3, [eax+24] + sub ecx, 32 + add eax, 32 + jmp End4 + +Setup4: + cmp ecx, 32 + jl Setup2 + + movq mm0, [eax] + movq mm1, [eax+8] + movq mm2, [eax+16] + movq mm3, [eax+24] + sub ecx, 32 + add eax, 32 + +End4: + pxor mm0, mm2 + pxor mm1, mm3 + + cmp ecx, 16 + jl End2 + pxor mm0, [eax] + pxor mm1, [eax+8] + sub ecx, 16 + add eax, 16 + jmp End2 + +Setup2: + cmp ecx, 16 + jl Setup1 + + movq mm0, [eax] + movq mm1, [eax+8] + sub ecx, 16 + add eax, 16 + +End2: + pxor mm0, mm1 + + cmp ecx, 8 + jl End1 + pxor mm0, [eax] +End1: + movq [edx], mm0 + jmp End + +Setup1: + movq mm0, [eax] + movq [edx], mm0 +End: + emms + } + FreezeMMXRegs(0); +} + +#endif + +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iCOP2.c b/pcsx2/x86/iCOP2.c new file mode 100644 index 0000000000..0ec5a9a831 --- /dev/null +++ b/pcsx2/x86/iCOP2.c @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#include +#include +#include +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "InterTables.h" +#include "VUmicro.h" +#include "iVU0micro.h" +#include "iVUmicro.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +// cycle cycles statusflag macflag clipflag +_vuopinfo g_cop2info = {0, 0, 1, 1, 1, 0, 0}; + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) +#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) +#define _Cc_ (cpuRegs.code & 0x03) + +#define REC_COP2_FUNC(f, delreg) \ + void f(); \ + void rec##f() { \ + SysPrintf("cop2 "#f" called\n"); \ + X86_32CODE(SetFPUstate()); \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_NOCONST); \ + CALLFunc((uptr)f); \ + _freeX86regs(); \ + branch = 2; \ +} + +#define INTERPRETATE_COP2_FUNC(f) \ +void recV##f() { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)V##f); \ + _freeX86regs(); \ +} + +#define REC_COP2_VU0(f) \ +void recV##f() { \ + recVU0MI_##f(); \ + _freeX86regs(); \ +} + +extern u32 dumplog; +#define REC_COP2_VU0_Q(f) \ +void recV##f() { \ + recVU0MI_##f(); \ + _freeX86regs(); \ +} + +void rec_C2UNK() +{ + SysPrintf("Cop2 bad opcode:%x\n",cpuRegs.code); +} + +void _vuRegs_C2UNK(VURegs * VU, _VURegsNum *VUregsn) +{ + SysPrintf("Cop2 bad _vuRegs code:%x\n",cpuRegs.code); +} + +void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn); + +void (*recCOP2t[32])(); +void (*recCOP2_BC2t[32])(); +void (*recCOP2SPECIAL1t[64])(); +void (*recCOP2SPECIAL2t[128])(); + +void recCOP2(); +void recCOP2_SPECIAL(); +void recCOP2_BC2(); +void recCOP2_SPECIAL2(); + +extern void _vu0WaitMicro(); + +static void recCFC2() +{ + int mmreg, creg; + + if (cpuRegs.code & 1) { + iFlushCall(IS_X8664?(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86):FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Rt_) return; + + _deleteGPRtoXMMreg(_Rt_, 2); + +#ifdef __x86_64__ + mmreg = _allocX86reg(-1, X86TYPE_GPR, _Rt_, MODE_WRITE); + + if( (creg = _checkX86reg(X86TYPE_VI, _Fs_, MODE_READ)) >= 0 ) { + if(EEINST_ISLIVE1(_Rt_)) { + if( _Fs_ < 16 ) { + // zero extending + MOVZX64R16toR(mmreg, creg); + } + else { + // sign extend, use full 32 bits + MOV32RtoR(mmreg, creg); + SHL64ItoR(mmreg, 32); + SAR64ItoR(mmreg, 32); + } + } + else { + // just move + MOV32RtoR(mmreg, creg); + EEINST_RESETHASLIVE1(_Rt_); + } + } + else { + if(EEINST_ISLIVE1(_Rt_)) { + if( _Fs_ < 16 ) { + // zero extending + MOVZX64M16toR(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + } + else { + // sign extend, use full 32 bits + MOV32MtoR(RAX, (uptr)&VU0.VI[ _Fs_ ].UL); + CDQE(); + MOV64RtoR(mmreg, RAX); + } + } + else { + // just move + MOV32MtoR(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + EEINST_RESETHASLIVE1(_Rt_); + } + } +#else + if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE)) >= 0 ) { + + if( _Fs_ >= 16 ) { + MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + + if( EEINST_ISLIVE1(_Rt_) ) { + _signExtendGPRtoMMX(mmreg, _Rt_, 0); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + } + } + else { + MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + } + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (uptr)&VU0.VI[ _Fs_ ].UL); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) { + if( _Fs_ < 16 ) { + // no sign extending + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1],0); + } + else { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + } + else { + EEINST_RESETHASLIVE1(_Rt_); + } + } +#endif + + _eeOnWriteReg(_Rt_, 1); +} + +static void recCTC2() +{ + int mmreg; + + if (cpuRegs.code & 1) { + iFlushCall(IS_X8664?(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86):FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Fs_) return; + + if( GPR_IS_CONST1(_Rt_) ) { + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + + if( g_cpuConstRegs[_Rt_].UL[0] & 0x202 ) + iFlushCall(FLUSH_FREE_TEMPX86); + _deleteX86reg(X86TYPE_VI, REG_FBRST, 2); + + if( g_cpuConstRegs[_Rt_].UL[0] & 2 ) { + CALLFunc((uptr)vu0ResetRegs); + } + + if( g_cpuConstRegs[_Rt_].UL[0] & 0x200 ) { + CALLFunc((uptr)vu1ResetRegs); + } + + MOV16ItoM((uptr)&VU0.VI[REG_FBRST].UL,g_cpuConstRegs[_Rt_].UL[0]&0x0c0c); + break; + + case REG_CMSAR1: // REG_CMSAR1 + + iFlushCall(IS_X8664?FLUSH_FREE_TEMPX86:FLUSH_NOCONST); // since CALLFunc + assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 && + _checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 ); + + // ignore if VU1 is operating + /*TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 0x100); + j8Ptr[0] = JNZ8(0); + + MOV32ItoM((uptr)&VU1.VI[REG_TPC].UL, g_cpuConstRegs[_Rt_].UL[0]&0xffff);*/ + // Execute VU1 Micro SubRoutine +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 1); +#else + /*PUSH32I(1); + CALLFunc((uptr)FreezeXMMRegs_);*/ +#endif + _callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff); +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 0); +#else + /*PUSH32I(0); + CALLFunc((uptr)FreezeXMMRegs_);*/ + //ADD32ItoR(ESP, 4); +#endif + //x86SetJ8( j8Ptr[0] ); + break; + default: + if( _Fs_ < 16 ) + assert( (g_cpuConstRegs[_Rt_].UL[0]&0xffff0000)==0); + +#ifdef __x86_64__ + if( (mmreg = _checkX86reg(X86TYPE_VI, _Fs_, MODE_WRITE)) >= 0 ) + MOV32ItoR(mmreg, g_cpuConstRegs[_Rt_].UL[0]); + else +#else + MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]); +#endif + + // a lot of games have vu0 spinning on some integer + // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) + iFlushCall(IS_X8664?(FLUSH_FREE_TEMPX86|FLUSH_FREE_VU0):FLUSH_NOCONST); + /* TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 1); + j8Ptr[0] = JZ8(0);*/ + +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 1); +#else + /*PUSH32I(1); + CALLFunc((uptr)FreezeXMMRegs_);*/ +#endif + + CALLFunc((uptr)Cpu->ExecuteVU0Block); + +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 0); +#else + /*PUSH32I(0); + CALLFunc((uptr)FreezeXMMRegs_);*/ + //ADD32ItoR(ESP, 4); +#endif + //x86SetJ8(j8Ptr[0]); + break; + } + } + else { + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + iFlushCall(FLUSH_FREE_TEMPX86); + assert( _checkX86reg(X86TYPE_VI, REG_FBRST, 0) < 0 ); + + _eeMoveGPRtoR(EAX, _Rt_); + + TEST32ItoR(EAX,0x2); + j8Ptr[0] = JZ8(0); + CALLFunc((uptr)vu0ResetRegs); + _eeMoveGPRtoR(EAX, _Rt_); + x86SetJ8(j8Ptr[0]); + + TEST32ItoR(EAX,0x200); + j8Ptr[0] = JZ8(0); + CALLFunc((uptr)vu1ResetRegs); + _eeMoveGPRtoR(EAX, _Rt_); + x86SetJ8(j8Ptr[0]); + + AND32ItoR(EAX,0x0C0C); + MOV16RtoM((uptr)&VU0.VI[REG_FBRST].UL,EAX); + break; + case REG_CMSAR1: // REG_CMSAR1 + + iFlushCall(IS_X8664?FLUSH_FREE_TEMPX86:FLUSH_NOCONST); // since CALLFunc + + // ignore if VU1 is operating + /*TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 0x100); + j8Ptr[0] = JNZ8(0);*/ + + _eeMoveGPRtoR(EAX, _Rt_); + //MOV16RtoM((uptr)&VU1.VI[REG_TPC].UL,EAX); + /*FreezeXMMRegs(1);*/ + _callFunctionArg1((uptr)vu1ExecMicro, MEM_X86TAG|EAX, 0); // Execute VU1 Micro SubRoutine + /*FreezeXMMRegs(0);*/ + //x86SetJ8( j8Ptr[0] ); + break; + default: +#ifdef __x86_64__ + if( (mmreg = _checkX86reg(X86TYPE_VI, _Fs_, MODE_WRITE)) >= 0 ) + _eeMoveGPRtoR(mmreg, _Rt_); + else +#else + _eeMoveGPRtoM((uptr)&VU0.VI[_Fs_].UL,_Rt_); +#endif + + // a lot of games have vu0 spinning on some integer + // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) + iFlushCall(IS_X8664?(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86):FLUSH_NOCONST); + /*TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 1); + j8Ptr[0] = JZ8(0);*/ +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 1); +#else + /*PUSH32I(1); + CALLFunc((uptr)FreezeXMMRegs_);*/ +#endif + // CALLFunc((uptr)Cpu->ExecuteVU0Block); +#ifdef __x86_64__ + _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 0); +#else + /*PUSH32I(0); + CALLFunc((uptr)FreezeXMMRegs_);*/ + //ADD32ItoR(ESP, 4); +#endif + // x86SetJ8(j8Ptr[0]); + break; + } + } +} + +static void recQMFC2(void) +{ + int t0reg, fsreg; + _xmmregs temp; + + if (cpuRegs.code & 1) { + iFlushCall(IS_X8664?(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86):FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Rt_) return; + +#ifndef __x86_64__ + _deleteMMXreg(MMX_GPR+_Rt_, 2); +#endif + + _deleteX86reg(X86TYPE_GPR, _Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + + // could 'borrow' the reg + fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_READ); + + if( fsreg >= 0 ) { + if( xmmregs[fsreg].mode & MODE_WRITE ) { + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + SSEX_MOVDQA_XMM_to_XMM(t0reg, fsreg); + + // change regs + temp = xmmregs[t0reg]; + xmmregs[t0reg] = xmmregs[fsreg]; + xmmregs[fsreg] = temp; + } + else { + // swap regs + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + + xmmregs[fsreg] = xmmregs[t0reg]; + xmmregs[t0reg].inuse = 0; + } + } + else { + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + if( t0reg >= 0 ) { + SSE_MOVAPS_M128_to_XMM( t0reg, (uptr)&VU0.VF[_Fs_].UD[0]); + } + else { + _recMove128MtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], (uptr)&VU0.VF[_Fs_].UL[0]); + } + } + + _clearNeededXMMregs(); +} + +static void recQMTC2() +{ + int mmreg, fsreg; + + if (cpuRegs.code & 1) { + iFlushCall(IS_X8664?(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86):FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Fs_) return; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0) { + fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_WRITE); + + if( fsreg >= 0 ) { + + if( (xmmregs[mmreg].mode&MODE_WRITE) && (g_pCurInstInfo->regs[_Rt_]&(EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) { + SSE_MOVAPS_XMM_to_XMM(fsreg, mmreg); + } + else { + // swap regs + if( (xmmregs[mmreg].mode&MODE_WRITE) && (g_pCurInstInfo->regs[_Rt_]&(EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) + SSE_MOVAPS_XMM_to_M128((uptr)&cpuRegs.GPR.r[_Rt_], mmreg); + + xmmregs[mmreg] = xmmregs[fsreg]; + xmmregs[mmreg].mode = MODE_WRITE; + xmmregs[fsreg].inuse = 0; + g_xmmtypes[mmreg] = XMMT_FPS; + } + } + else { + + if( (xmmregs[mmreg].mode&MODE_WRITE) && (g_pCurInstInfo->regs[_Rt_]&(EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) + SSE_MOVAPS_XMM_to_M128((uptr)&cpuRegs.GPR.r[_Rt_], mmreg); + + // swap regs + xmmregs[mmreg].type = XMMTYPE_VFREG; + xmmregs[mmreg].VU = 0; + xmmregs[mmreg].reg = _Fs_; + xmmregs[mmreg].mode = MODE_WRITE; + g_xmmtypes[mmreg] = XMMT_FPS; + } + } + else { + fsreg = _allocVFtoXMMreg(&VU0, -1, _Fs_, MODE_WRITE); + + if( fsreg >= 0 ) { +#ifdef __x86_64__ + if( (mmreg = _checkX86reg(X86TYPE_GPR, _Rt_, MODE_READ)) >= 0) { + SSE2_MOVQ_R_to_XMM(fsreg, mmreg); + SSE_MOVHPS_M64_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + } +#else + if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0) { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(fsreg, mmreg); + SSE_MOVHPS_M64_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + } +#endif + else { + if( GPR_IS_CONST1( _Rt_ ) ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ) == -1 ); + _flushConstReg(_Rt_); + } + + SSE_MOVAPS_M128_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + } + } + else { + _deleteEEreg(_Rt_, 0); + _recMove128MtoM((uptr)&VU0.VF[_Fs_].UL[0], (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + } + + _clearNeededXMMregs(); +} + +void _cop2AnalyzeOp(EEINST* pinst, int dostalls) +{ + _vuRegsCOP22(&VU0, &pinst->vuregs); + if( !dostalls ) return; + + _recvuTestLowerStalls(&VU0, &pinst->vuregs); + + switch(VU0.code & 0x3f) { + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1d: case 0x1f: + case 0x2b: case 0x2f: + break; + + case 0x3c: + switch ((VU0.code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + pinst->vuregs.VIwrite |= (1<> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: + break; + default: + pinst->vuregs.VIwrite |= (1<> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + pinst->vuregs.VIwrite |= (1<> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: case 0xb: + break; + default: + pinst->vuregs.VIwrite |= (1<vuregs.VIwrite |= (1<vuregs.VIwrite & (1 << REG_CLIP_FLAG)) { + _recAddWriteBack(vucycle+4, 1<vuregs.VIwrite & (1 << REG_Q)) { + _recAddWriteBack(vucycle+pinst->vuregs.cycles, 1<cycle = vucycle; + _recvuAddLowerStalls(&VU0, &pinst->vuregs); + _recvuTestPipes(&VU0); + + vucycle++; +} + +////////////////////////////////////////////////////////////////////////// +// BC2: Instructions +////////////////////////////////////////////////////////////////////////// +REC_COP2_FUNC(BC2F, 0); +REC_COP2_FUNC(BC2T, 0); +REC_COP2_FUNC(BC2FL, 0); +REC_COP2_FUNC(BC2TL, 0); + +////////////////////////////////////////////////////////////////////////// +// Special1 instructions +////////////////////////////////////////////////////////////////////////// +//TODO: redirect all the opcodes to the ivu0micro same functions +REC_COP2_VU0(IADD); +REC_COP2_VU0(IADDI); +REC_COP2_VU0(ISUB); +REC_COP2_VU0(IOR); +REC_COP2_VU0(IAND); +REC_COP2_VU0(OPMSUB); +REC_COP2_VU0(MADDq); +REC_COP2_VU0(MADDi); +REC_COP2_VU0(MSUBq); +REC_COP2_VU0(MSUBi); +REC_COP2_VU0(SUBi); +REC_COP2_VU0(SUBq); +REC_COP2_VU0(MULi); +REC_COP2_VU0(MULq); +REC_COP2_VU0(MAXi); +REC_COP2_VU0(MINIi); +REC_COP2_VU0(MUL); +REC_COP2_VU0(MAX); +REC_COP2_VU0(MADD); +REC_COP2_VU0(MSUB); + +REC_COP2_VU0(MINIx); +REC_COP2_VU0(MINIy); +REC_COP2_VU0(MINIz); +REC_COP2_VU0(MINIw); + +REC_COP2_VU0(MAXx); +REC_COP2_VU0(MAXy); +REC_COP2_VU0(MAXz); +REC_COP2_VU0(MAXw); + +REC_COP2_VU0(MULx); +REC_COP2_VU0(MULy); +REC_COP2_VU0(MULz); +REC_COP2_VU0(MULw); + +REC_COP2_VU0(ADD); +REC_COP2_VU0(ADDi); +REC_COP2_VU0(ADDq); +REC_COP2_VU0(ADDx); +REC_COP2_VU0(ADDy); +REC_COP2_VU0(ADDz); +REC_COP2_VU0(ADDw); + +REC_COP2_VU0(SUBx); +REC_COP2_VU0(SUBy); +REC_COP2_VU0(SUBz); +REC_COP2_VU0(SUBw); + +REC_COP2_VU0(MADDx); +REC_COP2_VU0(MADDy); +REC_COP2_VU0(MADDz); +REC_COP2_VU0(MADDw); + +REC_COP2_VU0(MSUBx); +REC_COP2_VU0(MSUBy); +REC_COP2_VU0(MSUBz); +REC_COP2_VU0(MSUBw); + +REC_COP2_VU0(SUB); +REC_COP2_VU0(MINI); + +////////////////////////////////////////////////////////////////////////// +// Special2 instructions +////////////////////////////////////////////////////////////////////////// + +REC_COP2_VU0(CLIP); +REC_COP2_VU0(LQI); +REC_COP2_VU0(SQI); +REC_COP2_VU0(LQD); +REC_COP2_VU0(SQD); +REC_COP2_VU0(MTIR); +REC_COP2_VU0(MFIR); +REC_COP2_VU0(ILWR); +REC_COP2_VU0(ISWR); +REC_COP2_VU0(RINIT); +REC_COP2_VU0(RXOR); +REC_COP2_VU0(RNEXT); +REC_COP2_VU0(RGET); + +REC_COP2_VU0(ITOF0); +REC_COP2_VU0(ITOF4); +REC_COP2_VU0(ITOF12); +REC_COP2_VU0(ITOF15); +REC_COP2_VU0(FTOI0); +REC_COP2_VU0(FTOI4); +REC_COP2_VU0(FTOI12); +REC_COP2_VU0(FTOI15); +REC_COP2_VU0(MADDA); +REC_COP2_VU0(MSUBA); +REC_COP2_VU0(MADDAi); +REC_COP2_VU0(MADDAq); +REC_COP2_VU0(MADDAx); +REC_COP2_VU0(MADDAy); +REC_COP2_VU0(MADDAz); +REC_COP2_VU0(MADDAw); +REC_COP2_VU0(MSUBAi); +REC_COP2_VU0(MSUBAq); +REC_COP2_VU0(MSUBAx); +REC_COP2_VU0(MSUBAy); +REC_COP2_VU0(MSUBAz); +REC_COP2_VU0(MSUBAw); +REC_COP2_VU0(ADDAi); +REC_COP2_VU0(ADDA); +REC_COP2_VU0(SUBA); +REC_COP2_VU0(MULA); +REC_COP2_VU0(ADDAq); +REC_COP2_VU0(ADDAx); +REC_COP2_VU0(ADDAy); +REC_COP2_VU0(ADDAz); +REC_COP2_VU0(ADDAw); +REC_COP2_VU0(SUBAi); +REC_COP2_VU0(SUBAq); +REC_COP2_VU0(SUBAx); +REC_COP2_VU0(SUBAy); +REC_COP2_VU0(SUBAz); +REC_COP2_VU0(SUBAw); +REC_COP2_VU0(MULAi); +REC_COP2_VU0(MULAq); +REC_COP2_VU0(MULAx); +REC_COP2_VU0(MULAy); +REC_COP2_VU0(MULAz); +REC_COP2_VU0(MULAw); +REC_COP2_VU0(OPMULA); +REC_COP2_VU0(MOVE); +REC_COP2_VU0_Q(DIV); +REC_COP2_VU0_Q(SQRT); +REC_COP2_VU0_Q(RSQRT); +REC_COP2_VU0(MR32); +REC_COP2_VU0(ABS); + +void recVNOP(){} +void recVWAITQ(){} +INTERPRETATE_COP2_FUNC(CALLMS); +INTERPRETATE_COP2_FUNC(CALLMSR); + +void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn); + +// information +void _vuRegsQMFC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xf; +} + +void _vuRegsCFC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VIread = 1<<_Fs_; +} + +void _vuRegsQMTC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VFwrite = _Fs_; + VUregsn->VFwxyzw= 0xf; +} + +void _vuRegsCTC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VIwrite = 1<<_Fs_; +} + +void (*_vuRegsCOP2t[32])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegs_C2UNK, _vuRegsQMFC2, _vuRegsCFC2, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsQMTC2, _vuRegsCTC2, _vuRegs_C2UNK, + _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, + _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, + _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, +}; + +void (*_vuRegsCOP2SPECIAL1t[64])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegsADDx, _vuRegsADDy, _vuRegsADDz, _vuRegsADDw, _vuRegsSUBx, _vuRegsSUBy, _vuRegsSUBz, _vuRegsSUBw, + _vuRegsMADDx, _vuRegsMADDy, _vuRegsMADDz, _vuRegsMADDw, _vuRegsMSUBx, _vuRegsMSUBy, _vuRegsMSUBz, _vuRegsMSUBw, + _vuRegsMAXx, _vuRegsMAXy, _vuRegsMAXz, _vuRegsMAXw, _vuRegsMINIx, _vuRegsMINIy, _vuRegsMINIz, _vuRegsMINIw, + _vuRegsMULx, _vuRegsMULy, _vuRegsMULz, _vuRegsMULw, _vuRegsMULq, _vuRegsMAXi, _vuRegsMULi, _vuRegsMINIi, + _vuRegsADDq, _vuRegsMADDq, _vuRegsADDi, _vuRegsMADDi, _vuRegsSUBq, _vuRegsMSUBq, _vuRegsSUBi, _vuRegsMSUBi, + _vuRegsADD, _vuRegsMADD, _vuRegsMUL, _vuRegsMAX, _vuRegsSUB, _vuRegsMSUB, _vuRegsOPMSUB, _vuRegsMINI, + _vuRegsIADD, _vuRegsISUB, _vuRegsIADDI, _vuRegs_C2UNK, _vuRegsIAND, _vuRegsIOR, _vuRegs_C2UNK, _vuRegs_C2UNK, + _vuRegsNOP, _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2, +}; + +void (*_vuRegsCOP2SPECIAL2t[128])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegsADDAx ,_vuRegsADDAy ,_vuRegsADDAz ,_vuRegsADDAw ,_vuRegsSUBAx ,_vuRegsSUBAy ,_vuRegsSUBAz ,_vuRegsSUBAw, + _vuRegsMADDAx ,_vuRegsMADDAy ,_vuRegsMADDAz ,_vuRegsMADDAw ,_vuRegsMSUBAx ,_vuRegsMSUBAy ,_vuRegsMSUBAz ,_vuRegsMSUBAw, + _vuRegsITOF0 ,_vuRegsITOF4 ,_vuRegsITOF12 ,_vuRegsITOF15 ,_vuRegsFTOI0 ,_vuRegsFTOI4 ,_vuRegsFTOI12 ,_vuRegsFTOI15, + _vuRegsMULAx ,_vuRegsMULAy ,_vuRegsMULAz ,_vuRegsMULAw ,_vuRegsMULAq ,_vuRegsABS ,_vuRegsMULAi ,_vuRegsCLIP, + _vuRegsADDAq ,_vuRegsMADDAq ,_vuRegsADDAi ,_vuRegsMADDAi ,_vuRegsSUBAq ,_vuRegsMSUBAq ,_vuRegsSUBAi ,_vuRegsMSUBAi, + _vuRegsADDA ,_vuRegsMADDA ,_vuRegsMULA ,_vuRegs_C2UNK ,_vuRegsSUBA ,_vuRegsMSUBA ,_vuRegsOPMULA ,_vuRegsNOP, + _vuRegsMOVE ,_vuRegsMR32 ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegsLQI ,_vuRegsSQI ,_vuRegsLQD ,_vuRegsSQD, + _vuRegsDIV ,_vuRegsSQRT ,_vuRegsRSQRT ,_vuRegsWAITQ ,_vuRegsMTIR ,_vuRegsMFIR ,_vuRegsILWR ,_vuRegsISWR, + _vuRegsRNEXT ,_vuRegsRGET ,_vuRegsRINIT ,_vuRegsRXOR ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, +}; + +void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn) +{ + _vuRegsCOP2t[_Rs_](VU, VUregsn); +} + +void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn) +{ + _vuRegsCOP2SPECIAL1t[_Funct_](VU, VUregsn); +} + +void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn) +{ + int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); + _vuRegsCOP2SPECIAL2t[opc](VU, VUregsn); +} + +// recompilation +void (*recCOP2t[32])() = { + rec_C2UNK, recQMFC2, recCFC2, rec_C2UNK, rec_C2UNK, recQMTC2, recCTC2, rec_C2UNK, + recCOP2_BC2, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, + recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, +}; + +void (*recCOP2_BC2t[32])() = { + recBC2F, recBC2T, recBC2FL, recBC2TL, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, +}; + +void (*recCOP2SPECIAL1t[64])() = { + recVADDx, recVADDy, recVADDz, recVADDw, recVSUBx, recVSUBy, recVSUBz, recVSUBw, + recVMADDx, recVMADDy, recVMADDz, recVMADDw, recVMSUBx, recVMSUBy, recVMSUBz, recVMSUBw, + recVMAXx, recVMAXy, recVMAXz, recVMAXw, recVMINIx, recVMINIy, recVMINIz, recVMINIw, + recVMULx, recVMULy, recVMULz, recVMULw, recVMULq, recVMAXi, recVMULi, recVMINIi, + recVADDq, recVMADDq, recVADDi, recVMADDi, recVSUBq, recVMSUBq, recVSUBi, recVMSUBi, + recVADD, recVMADD, recVMUL, recVMAX, recVSUB, recVMSUB, recVOPMSUB, recVMINI, + recVIADD, recVISUB, recVIADDI, rec_C2UNK, recVIAND, recVIOR, rec_C2UNK, rec_C2UNK, + recVCALLMS, recVCALLMSR, rec_C2UNK, rec_C2UNK, recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2, +}; + +void (*recCOP2SPECIAL2t[128])() = { + recVADDAx ,recVADDAy ,recVADDAz ,recVADDAw ,recVSUBAx ,recVSUBAy ,recVSUBAz ,recVSUBAw, + recVMADDAx ,recVMADDAy ,recVMADDAz ,recVMADDAw ,recVMSUBAx ,recVMSUBAy ,recVMSUBAz ,recVMSUBAw, + recVITOF0 ,recVITOF4 ,recVITOF12 ,recVITOF15 ,recVFTOI0 ,recVFTOI4 ,recVFTOI12 ,recVFTOI15, + recVMULAx ,recVMULAy ,recVMULAz ,recVMULAw ,recVMULAq ,recVABS ,recVMULAi ,recVCLIP, + recVADDAq ,recVMADDAq ,recVADDAi ,recVMADDAi ,recVSUBAq ,recVMSUBAq ,recVSUBAi ,recVMSUBAi, + recVADDA ,recVMADDA ,recVMULA ,rec_C2UNK ,recVSUBA ,recVMSUBA ,recVOPMULA ,recVNOP, + recVMOVE ,recVMR32 ,rec_C2UNK ,rec_C2UNK ,recVLQI ,recVSQI ,recVLQD ,recVSQD, + recVDIV ,recVSQRT ,recVRSQRT ,recVWAITQ ,recVMTIR ,recVMFIR ,recVILWR ,recVISWR, + recVRNEXT ,recVRGET ,recVRINIT ,recVRXOR ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, +}; + +void recCOP22() +{ + cinfo = &g_cop2info; + g_VUregs = &g_pCurInstInfo->vuregs; + VU0.code = cpuRegs.code; + g_pCurInstInfo->vuregs.pipe = 0xff; // to notify eeVURecompileCode that COP2 + recCOP2t[_Rs_](); +#ifndef __x86_64__ + _freeX86regs(); +#endif +} + +void recCOP2_SPECIAL() +{ + recCOP2SPECIAL1t[_Funct_](); +} + +void recCOP2_BC2() +{ + recCOP2_BC2t[_Rt_](); +} + +void recCOP2_SPECIAL2() +{ + int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); + recCOP2SPECIAL2t[opc](); +} + +#endif diff --git a/pcsx2/x86/iCP0.c b/pcsx2/x86/iCP0.c new file mode 100644 index 0000000000..c97a0a1c98 --- /dev/null +++ b/pcsx2/x86/iCP0.c @@ -0,0 +1,365 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iCP0.h" + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +#ifndef CP0_RECOMPILE + +REC_SYS(MFC0); +REC_SYS(MTC0); +REC_SYS(BC0F); +REC_SYS(BC0T); +REC_SYS(BC0FL); +REC_SYS(BC0TL); +REC_SYS(TLBR); +REC_SYS(TLBWI); +REC_SYS(TLBWR); +REC_SYS(TLBP); +REC_SYS(ERET); +REC_SYS(DI); +REC_SYS(EI); + +#else + +//////////////////////////////////////////////////// +//REC_SYS(MTC0); +//////////////////////////////////////////////////// +REC_SYS(BC0F); +//////////////////////////////////////////////////// +REC_SYS(BC0T); +//////////////////////////////////////////////////// +REC_SYS(BC0FL); +//////////////////////////////////////////////////// +REC_SYS(BC0TL); +//////////////////////////////////////////////////// +REC_SYS(TLBR); +//////////////////////////////////////////////////// +REC_SYS(TLBWI); +//////////////////////////////////////////////////// +REC_SYS(TLBWR); +//////////////////////////////////////////////////// +REC_SYS(TLBP); +//////////////////////////////////////////////////// +REC_SYS(ERET); +//////////////////////////////////////////////////// +REC_SYS(DI); +//////////////////////////////////////////////////// +REC_SYS(EI); + +//////////////////////////////////////////////////// +extern u32 s_iLastCOP0Cycle; +extern u32 s_iLastPERFCycle[2]; + +void recMFC0( void ) +{ + int mmreg; + + if ( ! _Rt_ ) return; + + if( _Rd_ == 9 ) { + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + MOV32RtoR(EAX,ECX); + SUB32MtoR(EAX, (uptr)&s_iLastCOP0Cycle); + ADD32RtoM((uptr)&cpuRegs.CP0.n.Count, EAX); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + MOV32MtoR( EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ] ); + + _deleteEEreg(_Rt_, 0); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else EEINST_RESETHASLIVE1(_Rt_); + return; + } + if( _Rd_ == 25 ) { + + _deleteEEreg(_Rt_, 0); + switch(_Imm_ & 0x3F){ + case 0: + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); + + break; + case 1: + // check if needs to be incremented + MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr0); + AND32ItoR(ECX, 0x800003E0); + + CMP32ItoR(ECX, 0x80000020); + j8Ptr[0] = JNE8(0); + + MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); + SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); + ADD32RtoR(EAX, EDX); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], EDX); + MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); + + x86SetJ8(j8Ptr[0]); + break; + case 3: + // check if needs to be incremented + MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr1); + AND32ItoR(ECX, 0x800F8000); + + CMP32ItoR(ECX, 0x80008000); + j8Ptr[0] = JNE8(0); + + MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); + SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); + ADD32RtoR(EAX, EDX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], EDX); + MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); + + x86SetJ8(j8Ptr[0]); + + break; + } + + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else EEINST_RESETHASLIVE1(_Rt_); + +#ifdef PCSX2_DEVBUILD + SysPrintf("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); +#endif + return; + } + else if( _Rd_ == 24){ + SysPrintf("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + return; + } + _eeOnWriteReg(_Rt_, 1); + + if( EEINST_ISLIVE1(_Rt_) ) { + _deleteEEreg(_Rt_, 0); + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], EAX); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + +#ifndef __x86_64__ + if( (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { + MOVDMtoMMX(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + SetMMXstate(); + } + else +#endif + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0) { + + if( EEINST_ISLIVE2(_Rt_) ) { + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); + } + xmmregs[mmreg].inuse = 0; + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + } + else { + SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + } + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + if(_Rd_ == 12) AND32ItoR(EAX, 0xf0c79c1f); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + } + } + } +} + +void updatePCCR() +{ + // read the old pccr and update pcr0/1 + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32RtoR(EDX, EAX); + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + + AND32ItoR(EAX, 0x800003E0); + CMP32ItoR(EAX, 0x80000020); + j8Ptr[0] = JNE8(0); + MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); + ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr0, ECX); + SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); + x86SetJ8(j8Ptr[0]); + + AND32ItoR(EDX, 0x800F8000); + CMP32ItoR(EDX, 0x80008000); + j8Ptr[0] = JNE8(0); + MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); + ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr1, ECX); + SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); + x86SetJ8(j8Ptr[0]); +} + +void recMTC0() +{ + if( GPR_IS_CONST1(_Rt_) ) { + switch (_Rd_) { + case 12: + iFlushCall(FLUSH_NODESTROY); + //_flushCachedRegs(); //NOTE: necessary? + _callFunctionArg1((uptr)WriteCP0Status, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]); + break; + case 9: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + MOV32ItoM((uptr)&cpuRegs.CP0.r[9], g_cpuConstRegs[_Rt_].UL[0]); + break; + case 25: + SysPrintf("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); + switch(_Imm_ & 0x3F){ + case 0: + + updatePCCR(); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pccr, g_cpuConstRegs[_Rt_].UL[0]); + + // update the cycles + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + case 1: + MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr0, g_cpuConstRegs[_Rt_].UL[0]); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], EAX); + break; + case 3: + MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr1, g_cpuConstRegs[_Rt_].UL[0]); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], EAX); + break; + } + break; + case 24: + SysPrintf("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + default: + MOV32ItoM((uptr)&cpuRegs.CP0.r[_Rd_], g_cpuConstRegs[_Rt_].UL[0]); + break; + } + } + else { + switch (_Rd_) { + case 12: + iFlushCall(FLUSH_NODESTROY); + //_flushCachedRegs(); //NOTE: necessary? + _callFunctionArg1((uptr)WriteCP0Status, MEM_GPRTAG|_Rt_, 0); + break; + case 9: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[9], _Rt_); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + break; + case 25: + SysPrintf("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); + switch(_Imm_ & 0x3F){ + case 0: + updatePCCR(); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_); + + // update the cycles + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + case 1: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr0, _Rt_); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + break; + case 3: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr1, _Rt_); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + } + break; + case 24: + SysPrintf("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + default: + _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[_Rd_], _Rt_); + break; + } + } +} + +/*void rec(COP0) { +} + +void rec(BC0F) { +} + +void rec(BC0T) { +} + +void rec(BC0FL) { +} + +void rec(BC0TL) { +} + +void rec(TLBR) { +} + +void rec(TLBWI) { +} + +void rec(TLBWR) { +} + +void rec(TLBP) { +} + +void rec(ERET) { +} +*/ + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iCP0.h b/pcsx2/x86/iCP0.h new file mode 100644 index 0000000000..b1b6a21b27 --- /dev/null +++ b/pcsx2/x86/iCP0.h @@ -0,0 +1,41 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __ICP0_H__ +#define __ICP0_H__ + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +void recMFC0( void ); +void recMTC0( void ); +void recBC0F( void ); +void recBC0T( void ); +void recBC0FL( void ); +void recBC0TL( void ); +void recTLBR( void ); +void recTLBWI( void ); +void recTLBWR( void ); +void recTLBP( void ); +void recERET( void ); +void recDI( void ); +void recEI( void ); + +#endif diff --git a/pcsx2/x86/iCore.cpp b/pcsx2/x86/iCore.cpp new file mode 100644 index 0000000000..2cf58436bf --- /dev/null +++ b/pcsx2/x86/iCore.cpp @@ -0,0 +1,1480 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#endif + +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "iCore.h" +#include "R3000A.h" + +u16 g_x86AllocCounter = 0; +u16 g_xmmAllocCounter = 0; + +EEINST* g_pCurInstInfo = NULL; + +u32 g_cpuRegHasLive1 = 0, g_cpuPrevRegHasLive1 = 0; // set if upper 32 bits are live +u32 g_cpuRegHasSignExt = 0, g_cpuPrevRegHasSignExt = 0; // set if upper 32 bits are the sign extension of the lower integer + +// used to make sure regs don't get changed while in recompiler +// use FreezeMMXRegs, FreezeXMMRegs +u8 g_globalXMMSaved = 0; +u32 g_recWriteback = 0; + +#ifdef _DEBUG +char g_globalXMMLocked = 0; +#endif + +_xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; +PCSX2_ALIGNED16(u64 g_globalXMMData[2*XMMREGS];) + +// X86 caching +_x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; + +} // end extern "C" + +#include +using namespace std; + +//void _eeSetLoadStoreReg(int gprreg, u32 offset, int x86reg) +//{ +// int regs[2] = {ESI, EDI}; +// +// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_WRITE); +// if( i < 0 ) { +// for(i = 0; i < 2; ++i) { +// if( !x86regs[regs[i]].inuse ) break; +// } +// +// assert( i < 2 ); +// i = regs[i]; +// } +// +// if( i != x86reg ) MOV32RtoR(x86reg, i); +// x86regs[i].extra = offset; +//} + +//int _eeGeLoadStoreReg(int gprreg, int* poffset) +//{ +// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_READ); +// if( i >= 0 ) return -1; +// +// if( poffset ) *poffset = x86regs[i].extra; +// return i; +//} + +// XMM Caching +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] + +static int s_xmmchecknext = 0; + +void _initXMMregs() { + memset(xmmregs, 0, sizeof(xmmregs)); + g_xmmAllocCounter = 0; + s_xmmchecknext = 0; +} + +__forceinline void* _XMMGetAddr(int type, int reg, VURegs *VU) +{ + if (type == XMMTYPE_VFREG ) return (void*)VU_VFx_ADDR(reg); + else if (type == XMMTYPE_ACC ) return (void*)VU_ACCx_ADDR; + else if (type == XMMTYPE_GPRREG) { + if( reg < 32 ) + assert( !(g_cpuHasConstReg & (1<regs[xmmregs[i].reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) { + _freeXMMreg(i); + return i; + } + } + } + + // check for future xmm usage + for (i=0; iregs[xmmregs[i].reg] & EEINST_XMM) ) { + _freeXMMreg(i); + return i; + } + } + } + + tempi = -1; + bestcount = 0xffff; + for (i=0; i= 0 ) { + // requested specific reg, so return that instead + if( i != xmmreg ) { + if( xmmregs[i].mode & MODE_READ ) readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= xmmregs[i].mode&MODE_WRITE; + xmmregs[i].inuse = 0; + break; + } + } + + xmmregs[i].needed = 1; + + if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ) ) { + SSE_MOVAPS_M128_to_XMM(i, VU_VFx_ADDR(vfreg)); + xmmregs[i].mode |= MODE_READ; + } + + g_xmmtypes[i] = XMMT_FPS; + xmmregs[i].counter = g_xmmAllocCounter++; // update counter + xmmregs[i].mode|= mode; + return i; + } + + if (xmmreg == -1) { + xmmreg = _getFreeXMMreg(); + } + else { + _freeXMMreg(xmmreg); + } + + g_xmmtypes[xmmreg] = XMMT_FPS; + xmmregs[xmmreg].inuse = 1; + xmmregs[xmmreg].type = XMMTYPE_VFREG; + xmmregs[xmmreg].reg = vfreg; + xmmregs[xmmreg].mode = mode; + xmmregs[xmmreg].needed = 1; + xmmregs[xmmreg].VU = XMM_CONV_VU(VU); + xmmregs[xmmreg].counter = g_xmmAllocCounter++; + if (mode & MODE_READ) { + if( readfromreg >= 0 ) SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); + else SSE_MOVAPS_M128_to_XMM(xmmreg, VU_VFx_ADDR(xmmregs[xmmreg].reg)); + } + + return xmmreg; +} + +int _checkXMMreg(int type, int reg, int mode) +{ + int i; + + for (i=0; i= 0 ) { + // requested specific reg, so return that instead + if( i != xmmreg ) { + if( xmmregs[i].mode & MODE_READ ) readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= xmmregs[i].mode&MODE_WRITE; + xmmregs[i].inuse = 0; + break; + } + } + + if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ)) { + SSE_MOVAPS_M128_to_XMM(i, VU_ACCx_ADDR); + xmmregs[i].mode |= MODE_READ; + } + + g_xmmtypes[i] = XMMT_FPS; + xmmregs[i].counter = g_xmmAllocCounter++; // update counter + xmmregs[i].needed = 1; + xmmregs[i].mode|= mode; + return i; + } + + if (xmmreg == -1) { + xmmreg = _getFreeXMMreg(); + } + else { + _freeXMMreg(xmmreg); + } + + g_xmmtypes[xmmreg] = XMMT_FPS; + xmmregs[xmmreg].inuse = 1; + xmmregs[xmmreg].type = XMMTYPE_ACC; + xmmregs[xmmreg].mode = mode; + xmmregs[xmmreg].needed = 1; + xmmregs[xmmreg].VU = XMM_CONV_VU(VU); + xmmregs[xmmreg].counter = g_xmmAllocCounter++; + xmmregs[xmmreg].reg = 0; + + if (mode & MODE_READ) { + if( readfromreg >= 0 ) SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); + else SSE_MOVAPS_M128_to_XMM(xmmreg, VU_ACCx_ADDR); + } + + return xmmreg; +} + +int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode) { + int i; + + for (i=0; i= 0 ) { + // transfer + if (cpucaps.hasStreamingSIMD2Extensions ) { + + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(xmmreg, mmxreg); + SSE2_PUNPCKLQDQ_XMM_to_XMM(xmmreg, xmmreg); + SSE2_PUNPCKHQDQ_M128_to_XMM(xmmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); + + if( mmxregs[mmxreg].mode & MODE_WRITE ) { + + // instead of setting to write, just flush to mem + if( !(mode & MODE_WRITE) ) { + SetMMXstate(); + MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], mmxreg); + } + //xmmregs[xmmreg].mode |= MODE_WRITE; + } + + // don't flush + mmxregs[mmxreg].inuse = 0; + } + else { + _freeMMXreg(mmxreg); + SSEX_MOVDQA_M128_to_XMM(xmmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); + } + } +#else + if( (mmxreg = _checkX86reg(X86TYPE_GPR, gprreg, 0)) >= 0 ) { + SSE2_MOVQ_R_to_XMM(xmmreg, mmxreg); + SSE_MOVHPS_M64_to_XMM(xmmreg, (uptr)&cpuRegs.GPR.r[gprreg].UL[0]); + + // read only, instead of setting to write, just flush to mem + if( !(mode&MODE_WRITE) && (x86regs[mmxreg].mode & MODE_WRITE) ) { + MOV64RtoM((uptr)&cpuRegs.GPR.r[gprreg].UL[0], mmxreg); + } + + x86regs[mmxreg].inuse = 0; + } +#endif + else + { + SSEX_MOVDQA_M128_to_XMM(xmmreg, (uptr)&cpuRegs.GPR.r[gprreg].UL[0]); + } + } + } + else { +#ifndef __x86_64__ + _deleteMMXreg(MMX_GPR+gprreg, 0); +#else + _deleteX86reg(X86TYPE_GPR, gprreg, 0); +#endif + } + + return xmmreg; +} + +int _allocFPACCtoXMMreg(int xmmreg, int mode) +{ + int i; + if( !cpucaps.hasStreamingSIMDExtensions ) return -1; + + for (i=0; iregs[xmmregs[i].reg]&EEINST_USED) ) { + return 1; + } + } + } + return 0; +} + +void _moveXMMreg(int xmmreg) +{ + int i; + if( !xmmregs[xmmreg].inuse ) return; + + for (i=0; iregs[gprreg] & EEINST_XMM ) return _allocGPRtoXMMreg(-1, gprreg, mode); + + return _checkXMMreg(XMMTYPE_GPRREG, gprreg, mode); +} + +int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode) +{ + if( pinst->fpuregs[fpureg] & EEINST_XMM ) return _allocFPtoXMMreg(-1, fpureg, mode); + + return _checkXMMreg(XMMTYPE_FPREG, fpureg, mode); +} + +int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode) +{ + if( pinst->regs[gprreg] & EEINST_USED ) + return _allocX86reg(-1, X86TYPE_GPR, gprreg, mode); + + return _checkX86reg(X86TYPE_GPR, gprreg, mode); +} + +void _recClearInst(EEINST* pinst) +{ + memset(&pinst->regs[0], EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2, sizeof(pinst->regs)); + memset(&pinst->fpuregs[0], EEINST_LIVE0, sizeof(pinst->fpuregs)); + memset(&pinst->info, 0, sizeof(EEINST)-sizeof(pinst->regs)-sizeof(pinst->fpuregs)); +} + +// returns nonzero value if reg has been written between [startpc, endpc-4] +int _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg) +{ + int i, inst = 1; + while(size-- > 0) { + for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { + if( pinst->writeType[i] == xmmtype && pinst->writeReg[i] == reg ) + return inst; + } + ++inst; + pinst++; + } + + return 0; +} + +int _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg) +{ + int i, inst = 1; + while(size-- > 0) { + for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { + if( pinst->writeType[i] == xmmtype && pinst->writeReg[i] == reg ) + return inst; + } + for(i = 0; i < ARRAYSIZE(pinst->readType); ++i) { + if( pinst->readType[i] == xmmtype && pinst->readReg[i] == reg ) + return inst; + } + ++inst; + pinst++; + } + + return 0; +} + +void _recFillRegister(EEINST* pinst, int type, int reg, int write) +{ + int i = 0; + if( write ) { + for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { + if( pinst->writeType[i] == XMMTYPE_TEMP ) { + pinst->writeType[i] = type; + pinst->writeReg[i] = reg; + return; + } + } + assert(0); + } + else { + for(i = 0; i < ARRAYSIZE(pinst->readType); ++i) { + if( pinst->readType[i] == XMMTYPE_TEMP ) { + pinst->readType[i] = type; + pinst->readReg[i] = reg; + return; + } + } + assert(0); + } +} + +void SetMMXstate() { +#ifdef __x86_64__ + assert(0); +#else + x86FpuState = MMX_STATE; +#endif +} + +// Writebacks // +void _recClearWritebacks() +{ +} + +void _recAddWriteBack(int cycle, u32 viwrite, EEINST* parent) +{ +} + +EEINSTWRITEBACK* _recCheckWriteBack(int cycle) +{ + return NULL; +} + +extern "C" void cpudetectSSE3(void* pfnCallSSE3) +{ + cpucaps.hasStreamingSIMD3Extensions = 1; + +#ifdef _MSC_VER + __try { + ((void (*)())pfnCallSSE3)(); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + cpucaps.hasStreamingSIMD3Extensions = 0; + } +#else // linux + +#ifdef PCSX2_FORCESSE3 + cpucaps.hasStreamingSIMD3Extensions = 1; +#else + // exception handling doesn't work, so disable for x86 builds of linux + cpucaps.hasStreamingSIMD3Extensions = 0; +#endif +// try { +// __asm__("call *%0" : : "m"(pfnCallSSE3) ); +// } +// catch(...) { +// SysPrintf("no SSE3 found\n"); +// cpucaps.hasStreamingSIMD3Extensions = 0; +// } +#endif +} + +extern "C" void cpudetectSSE4(void* pfnCallSSE4) +{ +return; + cpucaps.hasStreamingSIMD4Extensions = 1; + +#ifdef _MSC_VER + __try { + ((void (*)())pfnCallSSE4)(); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + cpucaps.hasStreamingSIMD4Extensions = 0; + } +#else // linux + +#ifdef PCSX2_FORCESSE4 + cpucaps.hasStreamingSIMD4Extensions = 1; +#else + // exception handling doesn't work, so disable for x86 builds of linux + cpucaps.hasStreamingSIMD4Extensions = 0; +#endif +// try { +// __asm__("call *%0" : : "m"(pfnCallSSE4) ); +// } +// catch(...) { +// SysPrintf("no SSE4.1 found\n"); +// cpucaps.hasStreamingSIMD4Extensions = 0; +// } +#endif +} + +struct BASEBLOCKS +{ + // 0 - ee, 1 - iop + inline void Add(BASEBLOCKEX*); + inline void Remove(BASEBLOCKEX*); + inline int Get(u32 startpc); + inline void Reset(); + + inline BASEBLOCKEX** GetAll(int* pnum); + + vector blocks; +}; + +void BASEBLOCKS::Add(BASEBLOCKEX* pex) +{ + assert( pex != NULL ); + + switch(blocks.size()) { + case 0: + blocks.push_back(pex); + return; + case 1: + assert( blocks.front()->startpc != pex->startpc ); + + if( blocks.front()->startpc < pex->startpc ) { + blocks.push_back(pex); + } + else blocks.insert(blocks.begin(), pex); + + return; + + default: + { + int imin = 0, imax = blocks.size(), imid; + + while(imin < imax) { + imid = (imin+imax)>>1; + + if( blocks[imid]->startpc > pex->startpc ) imax = imid; + else imin = imid+1; + } + + assert( imin == blocks.size() || blocks[imin]->startpc > pex->startpc ); + if( imin > 0 ) assert( blocks[imin-1]->startpc < pex->startpc ); + blocks.insert(blocks.begin()+imin, pex); + + return; + } + } +} + +int BASEBLOCKS::Get(u32 startpc) +{ + switch(blocks.size()) { + case 1: + return 0; + case 2: + return blocks.front()->startpc < startpc; + + default: + { + int imin = 0, imax = blocks.size()-1, imid; + + while(imin < imax) { + imid = (imin+imax)>>1; + + if( blocks[imid]->startpc > startpc ) imax = imid; + else if( blocks[imid]->startpc == startpc ) return imid; + else imin = imid+1; + } + + assert( blocks[imin]->startpc == startpc ); + return imin; + } + } +} + +void BASEBLOCKS::Remove(BASEBLOCKEX* pex) +{ + assert( pex != NULL ); + int i = Get(pex->startpc); + assert( blocks[i] == pex ); + blocks.erase(blocks.begin()+i); +} + +void BASEBLOCKS::Reset() +{ + blocks.resize(0); + blocks.reserve(512); +} + +BASEBLOCKEX** BASEBLOCKS::GetAll(int* pnum) +{ + assert( pnum != NULL ); + *pnum = blocks.size(); + return &blocks[0]; +} + +static BASEBLOCKS s_vecBaseBlocksEx[2]; + +void AddBaseBlockEx(BASEBLOCKEX* pex, int cpu) +{ + s_vecBaseBlocksEx[cpu].Add(pex); +} + +BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu) +{ + return s_vecBaseBlocksEx[cpu].blocks[s_vecBaseBlocksEx[cpu].Get(startpc)]; +} + +void RemoveBaseBlockEx(BASEBLOCKEX* pex, int cpu) +{ + s_vecBaseBlocksEx[cpu].Remove(pex); +} + +void ResetBaseBlockEx(int cpu) +{ + s_vecBaseBlocksEx[cpu].Reset(); +} + +BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu) +{ + return s_vecBaseBlocksEx[cpu].GetAll(pnum); +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iCore.h b/pcsx2/x86/iCore.h new file mode 100644 index 0000000000..0c0f194dc4 --- /dev/null +++ b/pcsx2/x86/iCore.h @@ -0,0 +1,490 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// NOTE: x86-64 recompiler doesn't support mmx +#ifndef _PCSX2_CORE_RECOMPILER_ +#define _PCSX2_CORE_RECOMPILER_ + +#include "ix86/ix86.h" +#include "iVUmicro.h" + +#if defined(__x86_64__) && defined(_MSC_VER) +// xp64 has stack shadow memory +#define REC_INC_STACK 48 +#else +#define REC_INC_STACK 0 +#endif + +// used to keep block information +#define BLOCKTYPE_STARTPC 4 // startpc offset +#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot + +typedef struct _BASEBLOCK +{ + u32 pFnptr : 28; + u32 uType : 4; + u32 startpc; +} BASEBLOCK; + +C_ASSERT( sizeof(BASEBLOCK) == 8 ); + +// extra block info (only valid for start of fn) +typedef struct _BASEBLOCKEX +{ + u16 size; // size in dwords + u16 dummy; + u32 startpc; // for debugging? + +#ifdef PCSX2_DEVBUILD + u32 visited; // number of times called + LARGE_INTEGER ltime; // regs it assumes to have set already +#endif + +} BASEBLOCKEX; + +#define GET_BLOCKTYPE(b) ((b)->Type) +#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + +#define X86TYPE_TEMP 0 +#define X86TYPE_GPR 1 +#define X86TYPE_VI 2 +#define X86TYPE_MEMOFFSET 3 +#define X86TYPE_VIMEMOFFSET 4 +#define X86TYPE_VUQREAD 5 +#define X86TYPE_VUPREAD 6 +#define X86TYPE_VUQWRITE 7 +#define X86TYPE_VUPWRITE 8 +#define X86TYPE_PSX 9 +#define X86TYPE_PCWRITEBACK 10 +#define X86TYPE_VUJUMP 12 // jump from random mem (g_recWriteback) +#define X86TYPE_VITEMP 13 +#define X86TYPE_FNARG 14 // function parameter, max is 4 + +#define X86TYPE_VU1 0x80 + +#define X86_ISVI(type) ((type&~X86TYPE_VU1) == X86TYPE_VI) + +typedef struct { + u8 inuse; + u8 reg; // value of 0 - not used + u8 mode; + u8 needed; + u8 type; // X86TYPE_ + u16 counter; + u32 extra; // extra info assoc with the reg +} _x86regs; + +extern _x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; + +uptr _x86GetAddr(int type, int reg); +void _initX86regs(); +int _getFreeX86reg(int mode); +int _allocX86reg(int x86reg, int type, int reg, int mode); +void _deleteX86reg(int type, int reg, int flush); +int _checkX86reg(int type, int reg, int mode); +void _addNeededX86reg(int type, int reg); +void _clearNeededX86regs(); +void _freeX86reg(int x86reg); +void _flushX86regs(); +void _freeX86regs(); +void _freeX86tempregs(); +u8 _hasFreeX86reg(); + +// see MEM_X defines for argX format +void _callPushArg(u32 arg, uptr argmem, x86IntRegType X86ARG); /// X86ARG is ignored for 32bit recs +void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem); +void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem); +void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem); + +// when using mmx/xmm regs, use; 0 is load +// freezes no matter the state +void FreezeXMMRegs_(int save); + +void _flushCachedRegs(); +void _flushConstRegs(); +void _flushConstReg(int reg); + +// return type: 0 - const, 1 - mmx, 2 - xmm +#define PROCESS_EE_MMX 0x01 +#define PROCESS_EE_XMM 0x02 + +// currently only used in FPU +#define PROCESS_EE_S 0x04 // S is valid, otherwise take from mem +#define PROCESS_EE_T 0x08 // T is valid, otherwise take from mem + +// not used in VU recs +#define PROCESS_EE_MODEWRITES 0x10 // if s is a reg, set if not in cpuRegs +#define PROCESS_EE_MODEWRITET 0x20 // if t is a reg, set if not in cpuRegs +#define PROCESS_EE_LO 0x40 // lo reg is valid +#define PROCESS_EE_HI 0x80 // hi reg is valid +#define PROCESS_EE_ACC 0x40 // acc reg is valid + +// used in VU recs +#define PROCESS_VU_UPDATEFLAGS 0x10 +#define PROCESS_VU_SUPER 0x40 // set if using supervu recompilation +#define PROCESS_VU_COP2 0x80 // simple cop2 + +#define EEREC_S (((info)>>8)&0xf) +#define EEREC_T (((info)>>12)&0xf) +#define EEREC_D (((info)>>16)&0xf) +#define EEREC_LO (((info)>>20)&0xf) +#define EEREC_HI (((info)>>24)&0xf) +#define EEREC_ACC (((info)>>20)&0xf) +#define EEREC_TEMP (((info)>>24)&0xf) +#define VUREC_FMAC ((info)&0x80000000) + +#define PROCESS_EE_SET_S(reg) ((reg)<<8) +#define PROCESS_EE_SET_T(reg) ((reg)<<12) +#define PROCESS_EE_SET_D(reg) ((reg)<<16) +#define PROCESS_EE_SET_LO(reg) ((reg)<<20) +#define PROCESS_EE_SET_HI(reg) ((reg)<<24) +#define PROCESS_EE_SET_ACC(reg) ((reg)<<20) + +#define PROCESS_VU_SET_ACC(reg) PROCESS_EE_SET_ACC(reg) +#define PROCESS_VU_SET_TEMP(reg) ((reg)<<24) + +#define PROCESS_VU_SET_FMAC() 0x80000000 + +// special info not related to above flags +#define PROCESS_CONSTS 1 +#define PROCESS_CONSTT 2 + +#define XMM_CONV_VU(VU) (VU==&VU1) + +#define XMMTYPE_TEMP 0 // has to be 0 +#define XMMTYPE_VFREG 1 +#define XMMTYPE_ACC 2 +#define XMMTYPE_FPREG 3 +#define XMMTYPE_FPACC 4 +#define XMMTYPE_GPRREG 5 + +// lo and hi regs +#define XMMGPR_LO 33 +#define XMMGPR_HI 32 +#define XMMFPU_ACC 32 + +typedef struct { + u8 inuse; + u8 reg; + u8 type; + u8 mode; + u8 needed; + u8 VU; // 0 = VU0, 1 = VU1 + u16 counter; +} _xmmregs; + +void _initXMMregs(); +int _getFreeXMMreg(); +int _allocTempXMMreg(XMMSSEType type, int xmmreg); +int _allocVFtoXMMreg(VURegs *VU, int xmmreg, int vfreg, int mode); +int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode); +int _allocGPRtoXMMreg(int xmmreg, int gprreg, int mode); +int _allocACCtoXMMreg(VURegs *VU, int xmmreg, int mode); +int _allocFPACCtoXMMreg(int xmmreg, int mode); +int _checkXMMreg(int type, int reg, int mode); +void _addNeededVFtoXMMreg(int vfreg); +void _addNeededACCtoXMMreg(); +void _addNeededFPtoXMMreg(int fpreg); +void _addNeededFPACCtoXMMreg(); +void _addNeededGPRtoXMMreg(int gprreg); +void _clearNeededXMMregs(); +void _deleteVFtoXMMreg(int reg, int vu, int flush); +void _deleteACCtoXMMreg(int vu, int flush); +void _deleteGPRtoXMMreg(int reg, int flush); +void _deleteFPtoXMMreg(int reg, int flush); +void _freeXMMreg(int xmmreg); +void _moveXMMreg(int xmmreg); // instead of freeing, moves it to a diff location +void _flushXMMregs(); +u8 _hasFreeXMMreg(); +void _freeXMMregs(); +int _getNumXMMwrite(); + +// Constants used for controlling iFlushCall, _psxFlushCall +#define FLUSH_CACHED_REGS 1 +#define FLUSH_FLUSH_XMM 2 +#define FLUSH_FREE_XMM 4 // both flushes and frees +#define FLUSH_FLUSH_MMX 8 +#define FLUSH_FREE_MMX 16 // both flushes and frees +#define FLUSH_FLUSH_ALLX86 32 // flush x86 +#define FLUSH_FREE_TEMPX86 64 // flush and free temporary x86 regs +#define FLUSH_FREE_ALLX86 128 // free all x86 regs +#define FLUSH_FREE_VU0 0x100 // free all vu0 related regs + +#define FLUSH_EVERYTHING 0xfff +// no freeing, used when callee won't destroy mmx/xmm regs +#define FLUSH_NODESTROY (FLUSH_CACHED_REGS|FLUSH_FLUSH_XMM|FLUSH_FLUSH_MMX|FLUSH_FLUSH_ALLX86) +// used when regs aren't going to be changed be callee +#define FLUSH_NOCONST (FLUSH_FREE_XMM|FLUSH_FREE_MMX|FLUSH_FREE_TEMPX86) + +#ifdef __x86_64__ +#define IS_X8664 1 +#else +#define IS_X8664 0 +#endif + +// Note: All functions with _ee prefix are for EE only + +// finds where the GPR is stored and moves lower 32 bits to EAX +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr); +void _eeMoveGPRtoM(u32 to, int fromgpr); +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr); + +void _psxMoveGPRtoR(x86IntRegType to, int fromgpr); +void _psxMoveGPRtoM(u32 to, int fromgpr); +void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr); + +// uses MEM_MMXTAG/MEM_XMMTAG to differentiate between the regs +void _recPushReg(int mmreg); + +void _signExtendSFtoM(u32 mem); + +// returns new index of reg, lower 32 bits already in mmx +// shift is used when the data is in the top bits of the mmx reg to begin with +// a negative shift is for sign extension +int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy); // returns true if reg destroyed + +// Defines for passing register info + +// only valid during writes. If write128, then upper 64bits are in an mmxreg +// (mmreg&0xf). Constant is used from gprreg ((mmreg>>16)&0x1f) +#define MEM_EECONSTTAG 0x0100 // argument is a GPR and comes from g_cpuConstRegs +#define MEM_PSXCONSTTAG 0x0200 +#define MEM_MEMORYTAG 0x0400 +// mmreg is mmxreg +#define MEM_MMXTAG 0x0800 +// mmreg is xmmreg +#define MEM_XMMTAG 0x8000 +#define MEM_X86TAG 0x4000 // ignored most of the time +#define MEM_GPRTAG 0x2000 // argument is a GPR reg +#define MEM_CONSTTAG 0x1000 // argument is a const + +#define IS_EECONSTREG(reg) (reg>=0&&((reg)&MEM_EECONSTTAG)) +#define IS_PSXCONSTREG(reg) (reg>=0&&((reg)&MEM_PSXCONSTTAG)) +#define IS_MMXREG(reg) (reg>=0&&((reg)&MEM_MMXTAG)) +#define IS_XMMREG(reg) (reg>=0&&((reg)&MEM_XMMTAG)) +#define IS_X86REG(reg) (reg>=0&&((reg)&MEM_X86TAG)) +#define IS_GPRREG(reg) (reg>=0&&((reg)&MEM_GPRTAG)) +#define IS_CONSTREG(reg) (reg>=0&&((reg)&MEM_CONSTTAG)) +#define IS_MEMORYREG(reg) (reg>=0&&((reg)&MEM_MEMORYTAG)) + +////////////////////// +// Instruction Info // +////////////////////// +#define EEINST_LIVE0 1 // if var is ever used (read or write) +#define EEINST_LIVE1 2 // if cur var's next 32 bits are needed +#define EEINST_LIVE2 4 // if cur var's next 64 bits are needed +#define EEINST_LASTUSE 8 // if var isn't written/read anymore +#define EEINST_MMX 0x10 // var will be used in mmx ops +#define EEINST_XMM 0x20 // var will be used in xmm ops (takes precedence +#define EEINST_USED 0x40 + +#define EEINSTINFO_COP1 1 +#define EEINSTINFO_COP2 2 +#define EEINSTINFO_NOREC 4 // if set, inst is recompiled alone +#define EEINSTINFO_COREC 8 // if set, inst is recompiled with another similar inst +#define EEINSTINFO_MMX EEINST_MMX +#define EEINSTINFO_XMM EEINST_XMM + +typedef struct _EEINST +{ + u8 regs[34]; // includes HI/LO (HI=32, LO=33) + u8 fpuregs[33]; // ACC=32 + u8 info; // extra info, if 1 inst is COP1, 2 inst is COP2. Also uses EEINST_MMX|EEINST_XMM + + // uses XMMTYPE_ flags; if type == XMMTYPE_TEMP, not used + u8 writeType[3], writeReg[3]; // reg written in this inst, 0 if no reg + u8 readType[4], readReg[4]; + + // valid if info & EEINSTINFO_COP2 + int cycle; // cycle of inst (at offset from block) + _VURegsNum vuregs; + + u8 numpeeps; // number of peephole optimizations +} EEINST; + +extern EEINST* g_pCurInstInfo; // info for the cur instruction +void _recClearInst(EEINST* pinst); + +// returns the number of insts + 1 until written (0 if not written) +int _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg); +// returns the number of insts + 1 until used (0 if not used) +int _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg); +void _recFillRegister(EEINST* pinst, int type, int reg, int write); + +#define EEINST_ISLIVE64(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1)) +#define EEINST_ISLIVEXMM(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) +#define EEINST_ISLIVE1(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE1) +#define EEINST_ISLIVE2(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE2) + +#define FPUINST_ISLIVE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LIVE0) +#define FPUINST_LASTUSE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LASTUSE) + +// if set, then the variable at this inst really has its upper 32 bits valid +// The difference between EEINST_LIVE1 is that the latter is used in back propagation +// The former is set at recompile time. +#define EEINST_RESETHASLIVE1(reg) { if( (reg) < 32 ) g_cpuRegHasLive1 &= ~(1<<(reg)); } +#define EEINST_HASLIVE1(reg) (g_cpuPrevRegHasLive1&(1<<(reg))) + +#define EEINST_SETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt |= (1<<(reg)); } +#define EEINST_RESETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt &= ~(1<<(reg)); } +#define EEINST_ISSIGNEXT(reg) (g_cpuPrevRegHasSignExt&(1<<(reg))) + +// writeback inst (used for cop2) +typedef struct _EEINSTWRITEBACK +{ + int cycle; + u32 viwrite; // mask of written viregs (REG_STATUS_FLAG and REG_MAC_FLAG are treated the same) + EEINST* parent; +} EEINSTWRITEBACK; + +void _recClearWritebacks(); +void _recAddWriteBack(int cycle, u32 viwrite, EEINST* parent); + +// if cycle == -1, returns the next writeback (used for flushing) +EEINSTWRITEBACK* _recCheckWriteBack(int cycle); + +extern u32 g_recWriteback; // used for jumps +extern u32 g_cpuRegHasLive1, g_cpuPrevRegHasLive1; +extern u32 g_cpuRegHasSignExt, g_cpuPrevRegHasSignExt; + +extern u8 g_globalXMMSaved; +extern _xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; + +#ifdef _DEBUG +extern char g_globalXMMLocked; +#endif + +// allocates only if later insts use XMM, otherwise checks +int _allocCheckGPRtoXMM(EEINST* pinst, int gprreg, int mode); +int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode); + +// allocates only if later insts use this register +int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode); + +// 0 - ee, 1 - iop +void AddBaseBlockEx(BASEBLOCKEX*, int cpu); +void RemoveBaseBlockEx(BASEBLOCKEX*, int cpu); +BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu); +void ResetBaseBlockEx(int cpu); + +BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu); + +#define MODE_READ 1 +#define MODE_WRITE 2 +#define MODE_READHALF 4 // read only low 64 bits +#define MODE_VUXY 0x8 // vector only has xy valid (real zw are in mem), not the same as MODE_READHALF +#define MODE_VUZ 0x10 // z only doesn't work for now +#define MODE_VUXYZ (MODE_VUZ|MODE_VUXY) // vector only has xyz valid (real w is in memory) +#define MODE_NOFLUSH 0x20 // can't flush reg to mem +#define MODE_NOFRAME 0x40 // when allocating x86regs, don't use ebp reg +#define MODE_8BITREG 0x80 // when allocating x86regs, use only eax, ecx, edx, and ebx + +void SetMMXstate(); +void cpudetectSSE3(void* pfnCallSSE3); +void cpudetectSSE4(void* pfnCallSSE4); + +void _recMove128MtoM(u32 to, u32 from); + +#ifndef __x86_64__ +///////////////////// +// MMX x86-32 only // +///////////////////// + +#define FPU_STATE 0 +#define MMX_STATE 1 + +void FreezeMMXRegs_(int save); +void SetFPUstate(); + +// max is 0x7f, when 0x80 is set, need to flush reg +#define MMX_GET_CACHE(ptr, index) ((u8*)ptr)[index] +#define MMX_SET_CACHE(ptr, ind3, ind2, ind1, ind0) ((u32*)ptr)[0] = (ind3<<24)|(ind2<<16)|(ind1<<8)|ind0; +#define MMX_GPR 0 +#define MMX_HI XMMGPR_HI +#define MMX_LO XMMGPR_LO +#define MMX_FPUACC 34 +#define MMX_FPU 64 +#define MMX_COP0 96 +#define MMX_TEMP 0x7f + +#define MMX_IS32BITS(x) (((x)>=MMX_FPU&&(x)= MMX_GPR && (x) < MMX_GPR+34) + +typedef struct { + u8 inuse; + u8 reg; // value of 0 - not used + u8 mode; + u8 needed; + u16 counter; +} _mmxregs; + +void _initMMXregs(); +int _getFreeMMXreg(); +int _allocMMXreg(int MMXreg, int reg, int mode); +void _addNeededMMXreg(int reg); +int _checkMMXreg(int reg, int mode); +void _clearNeededMMXregs(); +void _deleteMMXreg(int reg, int flush); +void _freeMMXreg(int mmxreg); +void _moveMMXreg(int mmxreg); // instead of freeing, moves it to a diff location +void _flushMMXregs(); +u8 _hasFreeMMXreg(); +void _freeMMXregs(); +int _getNumMMXwrite(); + +int _signExtendMtoMMX(x86MMXRegType to, u32 mem); +int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg); +int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode); + +void _recMove128RmOffsettoM(u32 to, u32 offset); +void _recMove128MtoRmOffset(u32 offset, u32 from); + +// op = 0, and +// op = 1, or +// op = 2, xor +// op = 3, nor (the 32bit versoins only do OR) +void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); +void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); + +// returns new index of reg, lower 32 bits already in mmx +// shift is used when the data is in the top bits of the mmx reg to begin with +// a negative shift is for sign extension +int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift); + +extern u8 g_globalMMXSaved; +extern _mmxregs mmxregs[MMXREGS], s_saveMMXregs[MMXREGS]; +extern u16 x86FpuState, iCWstate; + +#ifdef _DEBUG +extern char g_globalMMXLocked; +#endif + +#else + +void LogicalOp64RtoR(x86IntRegType to, x86IntRegType from, int op); +void LogicalOp64RtoM(uptr to, x86IntRegType from, int op); +void LogicalOp64MtoR(x86IntRegType to, uptr from, int op); + +#endif // __x86_64__ + +void LogicalOp32RtoM(uptr to, x86IntRegType from, int op); +void LogicalOp32MtoR(x86IntRegType to, uptr from, int op); +void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); +void LogicalOp32ItoM(uptr to, u32 from, int op); + +#endif diff --git a/pcsx2/x86/iFPU.c b/pcsx2/x86/iFPU.c new file mode 100644 index 0000000000..25f8d228e9 --- /dev/null +++ b/pcsx2/x86/iFPU.c @@ -0,0 +1,1511 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iFPU.h" + +#define REC_FPUBRANCH(f) \ + void f(); \ + void rec##f() { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)f); \ + branch = 2; \ +} + +#define REC_FPUFUNC(f) \ + void f(); \ + void rec##f() { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)f); \ +} + +/********************************************************* +* COP1 opcodes * +* * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +extern PCSX2_ALIGNED16_DECL(u32 g_minvals[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_maxvals[4]); + +//////////////////////////////////////////////////// +void recMFC1(void) { + int regt, regs; + if ( ! _Rt_ ) return; + + _eeOnWriteReg(_Rt_, 1); + + regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + if( regs >= 0 ) { + _deleteGPRtoXMMreg(_Rt_, 2); + +#ifdef __x86_64__ + regt = _allocCheckGPRtoX86(g_pCurInstInfo, _Rt_, MODE_WRITE); + + if( regt >= 0 ) { + + if(EEINST_ISLIVE1(_Rt_)) { + SSE2_MOVD_XMM_to_R(RAX, regs); + // sign extend + CDQE(); + MOV64RtoR(regt, RAX); + } + else { + SSE2_MOVD_XMM_to_R(regt, regs); + EEINST_RESETHASLIVE1(_Rt_); + } + } +#else + regt = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + + if( regt >= 0 ) { + SSE2_MOVDQ2Q_XMM_to_MM(regt, regs); + + if(EEINST_ISLIVE1(_Rt_)) _signExtendGPRtoMMX(regt, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } +#endif + else { + if(EEINST_ISLIVE1(_Rt_)) { + _signExtendXMMtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs, 0); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs); + } + } + } +#ifndef __x86_64__ + else if( (regs = _checkMMXreg(MMX_FPU+_Fs_, MODE_READ)) >= 0 ) { + // convert to mmx reg + mmxregs[regs].reg = MMX_GPR+_Rt_; + mmxregs[regs].mode |= MODE_READ|MODE_WRITE; + _signExtendGPRtoMMX(regs, _Rt_, 0); + } +#endif + else { + regt = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + + if( regt >= 0 ) { + if( xmmregs[regt].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], regt); + } + xmmregs[regt].inuse = 0; + } +#ifdef __x86_64__ + else if( (regt = _allocCheckGPRtoX86(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { + + if(EEINST_ISLIVE1(_Rt_)) { + MOV32MtoR( RAX, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + CDQE(); + MOV64RtoR(regt, RAX); + } + else { + MOV32MtoR( regt, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + EEINST_RESETHASLIVE1(_Rt_); + } + } + else +#endif + { + + _deleteEEreg(_Rt_, 0); + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + + if(EEINST_ISLIVE1(_Rt_)) { +#ifdef __x86_64__ + CDQE(); + MOV64RtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX); +#else + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); +#endif + } + else { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + } + } +} + +//////////////////////////////////////////////////// +void recCFC1(void) +{ + if ( ! _Rt_ ) return; + + _eeOnWriteReg(_Rt_, 1); + + MOV32MtoR( EAX, (uptr)&fpuRegs.fprc[ _Fs_ ] ); + _deleteEEreg(_Rt_, 0); + + if(EEINST_ISLIVE1(_Rt_)) { +#ifdef __x86_64__ + CDQE(); + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX ); +#else + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); +#endif + } + else { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } +} + +//////////////////////////////////////////////////// +void recMTC1(void) +{ + if( GPR_IS_CONST1(_Rt_) ) { + _deleteFPtoXMMreg(_Fs_, 0); + MOV32ItoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, g_cpuConstRegs[_Rt_].UL[0]); + } + else { + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) { + if( g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE ) { + // transfer the reg directly + _deleteGPRtoXMMreg(_Rt_, 2); + _deleteFPtoXMMreg(_Fs_, 2); + _allocFPtoXMMreg(mmreg, _Fs_, MODE_WRITE); + } + else { + int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); + if( mmreg2 >= 0 ) SSE_MOVSS_XMM_to_XMM(mmreg2, mmreg); + else SSE_MOVSS_XMM_to_M32((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); + } + } +#ifndef __x86_64__ + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + + if( cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); + if( mmreg2 >= 0 ) { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(mmreg2, mmreg); + } + else { + SetMMXstate(); + MOVDMMXtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); + } + } + else { + _deleteFPtoXMMreg(_Fs_, 0); + SetMMXstate(); + MOVDMMXtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); + } + } +#endif + else { + int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); + + if( mmreg2 >= 0 ) SSE_MOVSS_M32_to_XMM(mmreg2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + MOV32RtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, EAX); + } + } + } +} + +//////////////////////////////////////////////////// +void recCTC1( void ) +{ + if( GPR_IS_CONST1(_Rt_)) { + MOV32ItoM((uptr)&fpuRegs.fprc[ _Fs_ ], g_cpuConstRegs[_Rt_].UL[0]); + } + else { + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) { + SSEX_MOVD_XMM_to_M32((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); + } +#ifdef __x86_64__ + else if( (mmreg = _checkX86reg(X86TYPE_GPR, _Rt_, MODE_READ)) >= 0 ) { + MOV32RtoM((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); + } +#else + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + MOVDMMXtoM((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); + SetMMXstate(); + } +#endif + else { + _deleteGPRtoXMMreg(_Rt_, 1); + +#ifdef __x86_64__ + _deleteX86reg(X86TYPE_GPR, _Rt_, 1); +#else + _deleteMMXreg(MMX_GPR+_Rt_, 1); +#endif + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32RtoM( (uptr)&fpuRegs.fprc[ _Fs_ ], EAX ); + } + } +} + +//////////////////////////////////////////////////// +void recCOP1_BC1() +{ + recCP1BC1[_Rt_](); +} + +static u32 _mxcsr = 0x7F80; +static u32 _mxcsrs; +static u32 fpucw = 0x007f; +static u32 fpucws = 0; + +//////////////////////////////////////////////////// +void SaveCW(int type) { + if (iCWstate & type) return; + + if (type == 2) { +// SSE_STMXCSR((uptr)&_mxcsrs); +// SSE_LDMXCSR((uptr)&_mxcsr); + } else { + FNSTCW( (uptr)&fpucws ); + FLDCW( (uptr)&fpucw ); + } + iCWstate|= type; +} + +//////////////////////////////////////////////////// +void LoadCW( void ) { + if (iCWstate == 0) return; + + if (iCWstate & 2) { + //SSE_LDMXCSR((uptr)&_mxcsrs); + } + if (iCWstate & 1) { + FLDCW( (uptr)&fpucws ); + } + iCWstate = 0; +} + +//////////////////////////////////////////////////// +void recCOP1_S( void ) +{ +#ifndef __x86_64__ + if( !EE_FPU_REGCACHING || !cpucaps.hasStreamingSIMD2Extensions) { + _freeMMXreg(6); + _freeMMXreg(7); + } +#endif + recCP1S[ _Funct_ ]( ); +} + +//////////////////////////////////////////////////// +void recCOP1_W( void ) +{ +#ifndef __x86_64__ + if( !EE_FPU_REGCACHING ) { + _freeMMXreg(6); + _freeMMXreg(7); + } +#endif + recCP1W[ _Funct_ ]( ); +} + +#ifndef FPU_RECOMPILE + + +REC_FPUFUNC(ADD_S); +REC_FPUFUNC(SUB_S); +REC_FPUFUNC(MUL_S); +REC_FPUFUNC(DIV_S); +REC_FPUFUNC(SQRT_S); +REC_FPUFUNC(RSQRT_S); +REC_FPUFUNC(ABS_S); +REC_FPUFUNC(MOV_S); +REC_FPUFUNC(NEG_S); +REC_FPUFUNC(ADDA_S); +REC_FPUFUNC(SUBA_S); +REC_FPUFUNC(MULA_S); +REC_FPUFUNC(MADD_S); +REC_FPUFUNC(MSUB_S); +REC_FPUFUNC(MADDA_S); +REC_FPUFUNC(MSUBA_S); +REC_FPUFUNC(CVT_S); +REC_FPUFUNC(CVT_W); +REC_FPUFUNC(MIN_S); +REC_FPUFUNC(MAX_S); +REC_FPUBRANCH(BC1F); +REC_FPUBRANCH(BC1T); +REC_FPUBRANCH(BC1FL); +REC_FPUBRANCH(BC1TL); +REC_FPUFUNC(C_F); +REC_FPUFUNC(C_EQ); +REC_FPUFUNC(C_LE); +REC_FPUFUNC(C_LT); + +#else + +// define the FPU ops using the x86 FPU. x86-64 doesn't use FPU +#ifndef __x86_64__ + +void SetQFromStack(u32 mem) +{ + write16(0xe5d9); + FNSTSWtoAX(); + write8(0x9e); + j8Ptr[0] = JAE8(0); // jnc + + // sign bit is in bit 9 of EAX + FSTP(0); // pop + AND32ItoR(EAX, 0x200); + SHL32ItoR(EAX, 22); + OR32MtoR(EAX, (uptr)&g_maxvals[0]); + MOV32RtoM(mem, EAX); + j8Ptr[1] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + // just pop + FSTP32(mem); + x86SetJ8(j8Ptr[1]); +} + +void recC_EQ_(int info) +{ + SetFPUstate(); + + FLD32( (uptr)&fpuRegs.fpr[_Fs_].f); + FCOMP32( (uptr)&fpuRegs.fpr[_Ft_].f); + FNSTSWtoAX( ); + TEST32ItoR( EAX, 0x00004000 ); + j8Ptr[ 0 ] = JE8( 0 ); + OR32ItoM( (uptr)&fpuRegs.fprc[ 31 ], 0x00800000 ); + j8Ptr[ 1 ] = JMP8( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + AND32ItoM( (uptr)&fpuRegs.fprc[ 31 ], ~0x00800000 ); + + x86SetJ8( j8Ptr[ 1 ] ); +} + +void recC_LT_(int info) +{ + SetFPUstate(); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FCOMP32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FNSTSWtoAX( ); + TEST32ItoR( EAX, 0x00000100 ); + j8Ptr[ 0 ] = JE8( 0 ); + OR32ItoM( (uptr)&fpuRegs.fprc[ 31 ], 0x00800000 ); + j8Ptr[ 1 ] = JMP8( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + AND32ItoM( (uptr)&fpuRegs.fprc[ 31 ], ~0x00800000 ); + + x86SetJ8( j8Ptr[1] ); +} + +void recC_LE_(int info) +{ + SetFPUstate(); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FCOMP32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FNSTSWtoAX( ); + TEST32ItoR( EAX, 0x00004100 ); + j8Ptr[ 0 ] = JE8( 0 ); + OR32ItoM( (uptr)&fpuRegs.fprc[ 31 ], 0x00800000 ); + j8Ptr[ 1 ] = JMP8( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + AND32ItoM( (uptr)&fpuRegs.fprc[ 31 ], ~0x00800000 ); + + x86SetJ8( j8Ptr[ 1 ] ); +} + +void recADD_S_(int info) { + SetFPUstate(); + + SaveCW(1); + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FADD32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recSUB_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FSUB32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recMUL_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recDIV_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FDIV32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + SetQFromStack( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recSQRT_S_(int info) +{ + static u32 tmp; + + SysPrintf("SQRT\n"); + SetFPUstate(); + SaveCW(1); + + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + AND32ItoR( EAX, 0x7fffffff); + MOV32RtoM((uptr)&tmp, EAX); + FLD32( (uptr)&tmp ); + FSQRT( ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recABS_S_(int info) +{ + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + AND32ItoR( EAX, 0x7fffffff ); + MOV32RtoM( (uptr)&fpuRegs.fpr[ _Fd_ ].f, EAX ); +} + +void recMOV_S_(int info) +{ + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + MOV32RtoM( (uptr)&fpuRegs.fpr[ _Fd_ ].UL, EAX ); +} + +void recNEG_S_(int info) +{ + MOV32MtoR( EAX,(uptr)&fpuRegs.fpr[ _Fs_ ].f ); + XOR32ItoR( EAX, 0x80000000 ); + MOV32RtoM( (uptr)&fpuRegs.fpr[ _Fd_ ].f, EAX ); +} + +void recRSQRT_S_(int info) +{ + static u32 tmp; + + SysPrintf("RSQRT\n"); + SetFPUstate(); + SaveCW(1); + + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + AND32ItoR( EAX, 0x7fffffff); + MOV32RtoM((uptr)&tmp, EAX); + FLD32( (uptr)&tmp ); + FSQRT( ); + FSTP32( (uptr)&tmp ); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FDIV32( (uptr)&tmp ); + SetQFromStack( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); + +// FLD32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); +// FSQRT( ); +// FSTP32( (uptr)&tmp ); +// +// MOV32MtoR( EAX, (uptr)&tmp ); +// OR32RtoR( EAX, EAX ); +// j8Ptr[ 0 ] = JE8( 0 ); +// FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); +// FDIV32( (uptr)&tmp ); +// FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +// x86SetJ8( j8Ptr[ 0 ] ); +} + +void recADDA_S_(int info) { + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FADD32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.ACC.f ); +} + +void recSUBA_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FSUB32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.ACC.f ); +} + +void recMULA_S_(int info) { + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSTP32( (uptr)&fpuRegs.ACC.f ); +} + +void recMADD_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FADD32( (uptr)&fpuRegs.ACC.f ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recMADDA_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FADD32( (uptr)&fpuRegs.ACC.f ); + FSTP32( (uptr)&fpuRegs.ACC.f ); +} + +void recMSUB_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.ACC.f ); + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSUBP( ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recMSUBA_S_(int info) +{ + SetFPUstate(); + SaveCW(1); + + FLD32( (uptr)&fpuRegs.ACC.f ); + FLD32( (uptr)&fpuRegs.fpr[ _Fs_ ].f ); + FMUL32( (uptr)&fpuRegs.fpr[ _Ft_ ].f ); + FSUBP( ); + FSTP32( (uptr)&fpuRegs.ACC.f ); +} + +void recCVT_S_(int info) +{ + SetFPUstate(); + FILD32( (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + FSTP32( (uptr)&fpuRegs.fpr[ _Fd_ ].f ); +} + +void recMAX_S_(int info) +{ + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_NODESTROY); + CALLFunc( (u32)MAX_S ); +} + +void recMIN_S_(int info) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_NODESTROY); + CALLFunc( (u32)MIN_S ); +} + +#endif + +//////////////////////////////////////////////////// +void recC_EQ_xmm(int info) +{ + // assumes that inputs are valid + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); break; + case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); break; + default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break; + } + + //write8(0x9f); // lahf + //TEST16ItoR(EAX, 0x4400); + j8Ptr[0] = JZ8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], 0x00800000); + x86SetJ8(j8Ptr[1]); +} + +FPURECOMPILE_CONSTCODE(C_EQ, XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recC_F() +{ + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); +} + +//////////////////////////////////////////////////// +void recC_LT_xmm(int info) +{ + // assumes that inputs are valid + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); break; + case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); break; + default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break; + } + + //write8(0x9f); // lahf + //TEST16ItoR(EAX, 0x4400); + if( info & PROCESS_EE_S ) { + j8Ptr[0] = JB8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], 0x00800000); + x86SetJ8(j8Ptr[1]); + } + else { + j8Ptr[0] = JBE8(0); + OR32ItoM((uptr)&fpuRegs.fprc[31], 0x00800000); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); + x86SetJ8(j8Ptr[1]); + } +} + +FPURECOMPILE_CONSTCODE(C_LT, XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recC_LE_xmm(int info ) +{ + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); break; + case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); break; + default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break; + } + + //write8(0x9f); // lahf + //TEST16ItoR(EAX, 0x4400); + if( info & PROCESS_EE_S ) { + j8Ptr[0] = JBE8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], 0x00800000); + x86SetJ8(j8Ptr[1]); + } + else { + j8Ptr[0] = JB8(0); + OR32ItoM((uptr)&fpuRegs.fprc[31], 0x00800000); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~0x00800000 ); + x86SetJ8(j8Ptr[1]); + } +} + +FPURECOMPILE_CONSTCODE(C_LE, XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// + + + // Doesnt seem to like negatives - Ruins katamari graphics + // I REPEAT THE SIGN BIT (THATS 0x80000000) MUST *NOT* BE SET, jeez. +static PCSX2_ALIGNED16(u32 s_overflowmask[]) = {0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff}; +static u32 s_signbit = 0x80000000; +extern int g_VuNanHandling; + +void ClampValues(regd){ + int t5reg = _allocTempXMMreg(XMMT_FPS, -1); + + SSE_XORPS_XMM_to_XMM(t5reg, t5reg); + SSE_CMPORDSS_XMM_to_XMM(t5reg, regd); + + if( g_VuNanHandling ) + SSE_ORPS_M128_to_XMM(t5reg, (uptr)s_overflowmask); + + SSE_ANDPS_XMM_to_XMM(regd, t5reg); + SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + _freeXMMreg(t5reg); +} + +void ClampValues2(regd){ + int t5reg = _allocTempXMMreg(XMMT_FPS, -1); + + SSE_XORPS_XMM_to_XMM(t5reg, t5reg); + SSE_CMPORDSS_XMM_to_XMM(t5reg, regd); + + SSE_ORPS_M128_to_XMM(t5reg, (uptr)s_overflowmask); // fixes katamari falling off podium + + SSE_ANDPS_XMM_to_XMM(regd, t5reg); + + // not necessary since above ORPS handles that (i think) Lets enable it for now ;) + SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + + _freeXMMreg(t5reg); +} + +static void (*recComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = { + SSE_ADDSS_XMM_to_XMM, SSE_MULSS_XMM_to_XMM, SSE_MAXSS_XMM_to_XMM, SSE_MINSS_XMM_to_XMM }; + +static void (*recComOpM32_to_XMM[] )(x86SSERegType, uptr) = { + SSE_ADDSS_M32_to_XMM, SSE_MULSS_M32_to_XMM, SSE_MAXSS_M32_to_XMM, SSE_MINSS_M32_to_XMM }; + +int recCommutativeOp(int info, int regd, int op) { + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if (regd == EEREC_S) recComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Ft_]); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Ft_]); + } + break; + case PROCESS_EE_T: + if (regd == EEREC_T) recComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Fs_]); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_T); + recComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Fs_]); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + // SysPrintf("Hello2 :)\n"); + if (regd == EEREC_S) recComOpXMM_to_XMM[op](regd, EEREC_T); + else if (regd == EEREC_T) recComOpXMM_to_XMM[op](regd, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recComOpXMM_to_XMM[op](regd, EEREC_T); + } + break; + default: + SysPrintf("But we dont have regs2 :(\n"); + /*if (regd == EEREC_S) { + recComOpXMM_to_XMM[op](regd, EEREC_T); + } + else if (regd == EEREC_T) { + recComOpXMM_to_XMM[op](regd, EEREC_S); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recComOpXMM_to_XMM[op](regd, EEREC_T); + }*/ + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Ft_]); + break; + } + return regd; +} + +static void (*recNonComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = { + SSE_SUBSS_XMM_to_XMM, SSE_DIVSS_XMM_to_XMM }; + +static void (*recNonComOpM32_to_XMM[] )(x86SSERegType, uptr) = { + SSE_SUBSS_M32_to_XMM, SSE_DIVSS_M32_to_XMM }; + +int recNonCommutativeOp(int info, int regd, int op) +{ + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if (regd != EEREC_S) SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recNonComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Ft_]); + break; + case PROCESS_EE_T: + if (regd == EEREC_T) { + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + recNonComOpXMM_to_XMM[op](t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recNonComOpXMM_to_XMM[op](regd, EEREC_T); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + //SysPrintf("Hello1 :)\n"); + if (regd == EEREC_T) { + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + recNonComOpXMM_to_XMM[op](t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + else if (regd == EEREC_S) { + recNonComOpXMM_to_XMM[op](regd, EEREC_T); + } + else + { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recNonComOpXMM_to_XMM[op](regd, EEREC_T); + } + break; + default: + SysPrintf("But we dont have regs1 :(\n"); + /*if (regd == EEREC_S) { + recNonComOpXMM_to_XMM[op](regd, EEREC_T); + } else + if (regd == EEREC_T) { + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + recNonComOpXMM_to_XMM[op](t0reg, regd); + + // swap regs + xmmregs[t0reg] = xmmregs[regd]; + xmmregs[regd].inuse = 0; + return t0reg; + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recNonComOpXMM_to_XMM[op](regd, EEREC_T); + }*/ + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recNonComOpM32_to_XMM[op](regd, (uptr)&fpuRegs.fpr[_Ft_]); + break; + } + + return regd; +} + +void recADD_S_xmm(int info) +{ + ClampValues(recCommutativeOp(info, EEREC_D, 0)); +} + +FPURECOMPILE_CONSTCODE(ADD_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recSUB_S_xmm(int info) +{ + ClampValues(recNonCommutativeOp(info, EEREC_D, 0)); +} + +FPURECOMPILE_CONSTCODE(SUB_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recMUL_S_xmm(int info) +{ + ClampValues(recCommutativeOp(info, EEREC_D, 1)); +} + +FPURECOMPILE_CONSTCODE(MUL_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recDIV_S_xmm(int info) +{ + ClampValues2(recNonCommutativeOp(info, EEREC_D, 1)); +} + +FPURECOMPILE_CONSTCODE(DIV_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +static u32 PCSX2_ALIGNED16(s_neg[4]) = { 0x80000000, 0, 0, 0 }; +static u32 PCSX2_ALIGNED16(s_pos[4]) = { 0x7fffffff, 0, 0, 0 }; + +void recSQRT_S_xmm(int info) +{ + if( info & PROCESS_EE_T ) { + //if( CHECK_FORCEABS ) { + if( EEREC_D == EEREC_T ) SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_T); + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + + } + + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); + //} + /*else { + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_T); + }*/ + } + else { + //if( CHECK_FORCEABS ) { + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); + /*} + else { + SSE_SQRTSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Ft_]); + }*/ + } + ClampValues(EEREC_D); +} + +FPURECOMPILE_CONSTCODE(SQRT_S, XMMINFO_WRITED|XMMINFO_READT); + +void recABS_S_xmm(int info) +{ + + if( info & PROCESS_EE_S ) { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + //xmmregs[EEREC_D].mode &= ~MODE_WRITE; + } + ClampValues(EEREC_D); +} + +FPURECOMPILE_CONSTCODE(ABS_S, XMMINFO_WRITED|XMMINFO_READS); + +void recMOV_S_xmm(int info) +{ + if( info & PROCESS_EE_S ) { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + } +} + +FPURECOMPILE_CONSTCODE(MOV_S, XMMINFO_WRITED|XMMINFO_READS); + +void recNEG_S_xmm(int info) { + if( info & PROCESS_EE_S ) { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + } + + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&s_neg[0]); + ClampValues(EEREC_D); +} + +FPURECOMPILE_CONSTCODE(NEG_S, XMMINFO_WRITED|XMMINFO_READS); + +void recRSQRT_S_xmm(int info) +{ + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if( EEREC_D == EEREC_S ) { + SSE_SQRTSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } + else { + SSE_SQRTSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } + + break; + case PROCESS_EE_T: + SSE_SQRTSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + break; + default: + if( (info & PROCESS_EE_T) && (info & PROCESS_EE_S) ) { + if( EEREC_D == EEREC_T ){ + SSE_SQRTSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } + else if( EEREC_D == EEREC_S ){ + SSE_SQRTSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } else { + SSE_SQRTSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } + }else{ + SSE_SQRTSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_DIVSS_XMM_to_XMM(EEREC_D, t0reg); + } + + break; + } + _freeXMMreg(t0reg); + ClampValues(EEREC_D); +} + +FPURECOMPILE_CONSTCODE(RSQRT_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +void recADDA_S_xmm(int info) +{ + ClampValues(recCommutativeOp(info, EEREC_ACC, 0)); +} + +FPURECOMPILE_CONSTCODE(ADDA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); + +void recSUBA_S_xmm(int info) { + ClampValues(recNonCommutativeOp(info, EEREC_ACC, 0)); +} + +FPURECOMPILE_CONSTCODE(SUBA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); + +void recMULA_S_xmm(int info) { + ClampValues(recCommutativeOp(info, EEREC_ACC, 1)); +} + +FPURECOMPILE_CONSTCODE(MULA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); + +void recMADDtemp(int info, int regd) +{ + int vreg; + u32 mreg; + int t0reg; + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if(regd == EEREC_S) { + SSE_MULSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } + break; + case PROCESS_EE_T: + if(regd == EEREC_T) { + SSE_MULSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_ADDSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } + break; + default: + if((info & PROCESS_EE_S) && (info & PROCESS_EE_T)){ + if(regd == EEREC_S) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } else + if(regd == EEREC_T) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_ADDSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } + break; + } else { + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_ADDSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + else + { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + if((info&PROCESS_EE_ACC))SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + } + } + break; + } + + + ClampValues(regd); +} + +void recMADD_S_xmm(int info) +{ + recMADDtemp(info, EEREC_D); +} + +FPURECOMPILE_CONSTCODE(MADD_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recMADDA_S_xmm(int info) +{ + recMADDtemp(info, EEREC_ACC); +} + +FPURECOMPILE_CONSTCODE(MADDA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recMSUBtemp(int info, int regd) +{ + int vreg; + u32 mreg; + int t0reg; + + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if(regd == EEREC_S) { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + break; + case PROCESS_EE_T: + if(regd == EEREC_T) { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + break; + default: + if((info & PROCESS_EE_S) && (info & PROCESS_EE_T)){ + if(regd == EEREC_S) { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else + if(regd == EEREC_T) { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } else { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + break; + } else { + if(regd == EEREC_ACC){ + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + else + { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if((info&PROCESS_EE_ACC))SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + else SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.ACC); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MULSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_SUBSS_XMM_to_XMM(regd, t0reg); + _freeXMMreg(t0reg); + } + } + break; + } + +} + +void recMSUB_S_xmm(int info) +{ + recMSUBtemp(info, EEREC_D); +} + +FPURECOMPILE_CONSTCODE(MSUB_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recMSUBA_S_xmm(int info) +{ + recMSUBtemp(info, EEREC_ACC); +} + +FPURECOMPILE_CONSTCODE(MSUBA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recCVT_S_xmm(int info) +{ + if( !(info&PROCESS_EE_S) || (EEREC_D != EEREC_S && !(info&PROCESS_EE_MODEWRITES)) ) { + SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + } + else { + if( cpucaps.hasStreamingSIMD2Extensions ) { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( info&PROCESS_EE_MODEWRITES ) { + if( xmmregs[EEREC_S].reg == _Fs_ ) + _deleteFPtoXMMreg(_Fs_, 1); + else { + // force sync + SSE_MOVSS_XMM_to_M32((uptr)&fpuRegs.fpr[_Fs_], EEREC_S); + } + } + SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + xmmregs[EEREC_D].mode |= MODE_WRITE; // in the case that _Fs_ == _Fd_ + } + } +} + +FPURECOMPILE_CONSTCODE(CVT_S, XMMINFO_WRITED|XMMINFO_READS); + +//////////////////////////////////////////////////// +void recCVT_W() +{ + if( cpucaps.hasStreamingSIMDExtensions ) { + int t0reg; + int regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + + if( regs >= 0 ) { + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + _freeXMMreg(t0reg); + SSE_MOVSS_M32_to_XMM(t0reg, (u32)&s_signbit); + SSE_CVTTSS2SI_XMM_to_R32(EAX, regs); + SSE_MOVSS_XMM_to_M32((uptr)&fpuRegs.fpr[ _Fs_ ], regs); + } + else SSE_CVTTSS2SI_M32_to_R32(EAX, (uptr)&fpuRegs.fpr[ _Fs_ ]); + _deleteFPtoXMMreg(_Fd_, 2); + + MOV32MtoR(ECX, (uptr)&fpuRegs.fpr[ _Fs_ ]); + AND32ItoR(ECX, 0x7f800000); + CMP32ItoR(ECX, 0x4E800000); + j8Ptr[0] = JLE8(0); + + // need to detect if reg is positive + /*if( regs >= 0 ) { + SSE_UCOMISS_XMM_to_XMM(regs, t0reg); + j8Ptr[2] = JB8(0); + } + else {*/ + TEST32ItoM((uptr)&fpuRegs.fpr[ _Fs_ ], 0x80000000); + j8Ptr[2] = JNZ8(0); + //} + + MOV32ItoM((uptr)&fpuRegs.fpr[_Fd_], 0x7fffffff); + j8Ptr[1] = JMP8(0); + + x86SetJ8( j8Ptr[2] ); + MOV32ItoM((uptr)&fpuRegs.fpr[_Fd_], 0x80000000); + j8Ptr[1] = JMP8(0); + + x86SetJ8( j8Ptr[0] ); + + MOV32RtoM((uptr)&fpuRegs.fpr[_Fd_], EAX); + + x86SetJ8( j8Ptr[1] ); + } +#ifndef __x86_64__ + else { + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); + iFlushCall(FLUSH_EVERYTHING); + _flushConstRegs(); + CALLFunc((uptr)CVT_W); + } +#endif +} + +void recMAX_S_xmm(int info) +{ + recCommutativeOp(info, EEREC_D, 2); +} + +FPURECOMPILE_CONSTCODE(MAX_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +void recMIN_S_xmm(int info) +{ + recCommutativeOp(info, EEREC_D, 3); +} + +FPURECOMPILE_CONSTCODE(MIN_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//////////////////////////////////////////////////// +void recBC1F( void ) { + u32 branchTo = (s32)_Imm_ * 4 + pc; + + _eeFlushAllUnused(); + MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); + TEST32ItoR(EAX, 0x00800000); + j32Ptr[0] = JNZ32(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32(j32Ptr[0]); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +void recBC1T( void ) { + u32 branchTo = (s32)_Imm_ * 4 + pc; + + _eeFlushAllUnused(); + MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); + TEST32ItoR(EAX, 0x00800000); + j32Ptr[0] = JZ32(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + //j32Ptr[1] = JMP32(0); + + x86SetJ32(j32Ptr[0]); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + //x86SetJ32(j32Ptr[1]); +} + +//////////////////////////////////////////////////// +void recBC1FL( void ) { + u32 branchTo = _Imm_ * 4 + pc; + + _eeFlushAllUnused(); + MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); + TEST32ItoR(EAX, 0x00800000); + j32Ptr[0] = JNZ32(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32(j32Ptr[0]); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBC1TL( void ) { + u32 branchTo = _Imm_ * 4 + pc; + + _eeFlushAllUnused(); + MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); + TEST32ItoR(EAX, 0x00800000); + j32Ptr[0] = JZ32(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + x86SetJ32(j32Ptr[0]); + + LoadBranchState(); + SetBranchImm(pc); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iFPU.h b/pcsx2/x86/iFPU.h new file mode 100644 index 0000000000..d9c85aa7f0 --- /dev/null +++ b/pcsx2/x86/iFPU.h @@ -0,0 +1,60 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IFPU_H__ +#define __IFPU_H__ + +void recMFC1( void ); +void recCFC1( void ); +void recMTC1( void ); +void recCTC1( void ); +void recCOP1_BC1( void ); +void recCOP1_S( void ); +void recCOP1_W( void ); +void recC_EQ( void ); +void recC_F( void ); +void recC_LT( void ); +void recC_LE( void ); +void recADD_S( void ); +void recSUB_S( void ); +void recMUL_S( void ); +void recDIV_S( void ); +void recSQRT_S( void ); +void recABS_S( void ); +void recMOV_S( void ); +void recNEG_S( void ); +void recRSQRT_S( void ); +void recADDA_S( void ); +void recSUBA_S( void ); +void recMULA_S( void ); +void recMADD_S( void ); +void recMSUB_S( void ); +void recMADDA_S( void ); +void recMSUBA_S( void ); +void recCVT_S( void ); +void recCVT_W( void ); +void recMAX_S( void ); +void recMIN_S( void ); +void recBC1F( void ); +void recBC1T( void ); +void recBC1FL( void ); +void recBC1TL( void ); + +#endif + + diff --git a/pcsx2/x86/iGS.cpp b/pcsx2/x86/iGS.cpp new file mode 100644 index 0000000000..b67f6c5340 --- /dev/null +++ b/pcsx2/x86/iGS.cpp @@ -0,0 +1,516 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#endif + +#include + +#include +#include + +using namespace std; + +extern "C" { +#include "zlib.h" +#include "Elfheader.h" +#include "Misc.h" +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" +#include "VifDma.h" +#include "Memory.h" +#include "Hw.h" + +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "Counters.h" +#include "GS.h" + +extern u32 CSRw; + +} + +void CSRwrite(u32 value); + +#ifdef PCSX2_VIRTUAL_MEM +#define PS2GS_BASE(mem) ((PS2MEM_BASE+0x12000000)+(mem&0x13ff)) +#else +extern u8 g_RealGSMem[0x2000]; +#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) +#endif + +void gsConstWrite8(u32 mem, int mmreg) +{ + switch (mem&~3) { + case 0x12001000: // GS_CSR + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + MOV32MtoR(ECX, (uptr)&CSRw); + AND32ItoR(EAX, 0xff<<(mem&3)*8); + AND32ItoR(ECX, ~(0xff<<(mem&3)*8)); + OR32ItoR(EAX, ECX); + _callFunctionArg1((uptr)CSRwrite, EAX|MEM_X86TAG, 0); + break; + default: + _eeWriteConstMem8( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callFunctionArg3((uptr)GSRingBufSimplePacket, MEM_CONSTTAG, MEM_CONSTTAG, mmreg, + GS_RINGTYPE_MEMWRITE8, mem&0x13ff, 0); + } + break; + } +} + +void recSetSMODE1() +{ + iFlushCall(0); + AND32ItoR(EAX, 0x6000); + CMP32ItoR(EAX, 0x6000); + j8Ptr[5] = JNE8(0); + + // PAL + OR32ItoM( (uptr)&Config.PsxType, 1); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + + // NTSC + AND32ItoM( (uptr)&Config.PsxType, ~1 ); + + x86SetJ8( j8Ptr[6] ); + CALLFunc((uptr)UpdateVSyncRate); +} + +void recSetSMODE2() +{ + TEST32ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + + // Interlaced + OR32ItoM( (uptr)&Config.PsxType, 2); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + + // Non-Interlaced + AND32ItoM( (uptr)&Config.PsxType, ~2 ); + + x86SetJ8( j8Ptr[6] ); +} + +void gsConstWrite16(u32 mem, int mmreg) +{ + switch (mem&~3) { + case 0x12000010: // GS_SMODE1 + assert( !(mem&3)); + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE1(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE16, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + + } + + break; + + case 0x12000020: // GS_SMODE2 + assert( !(mem&3)); + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE2(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE16, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12001000: // GS_CSR + + assert( !(mem&2) ); + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + + MOV32MtoR(ECX, (uptr)&CSRw); + AND32ItoR(EAX, 0xffff<<(mem&2)*8); + AND32ItoR(ECX, ~(0xffff<<(mem&2)*8)); + OR32ItoR(EAX, ECX); + _callFunctionArg1((uptr)CSRwrite, EAX|MEM_X86TAG, 0); + break; + + default: + _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + _callFunctionArg3((uptr)GSRingBufSimplePacket, MEM_CONSTTAG, MEM_CONSTTAG, mmreg, + GS_RINGTYPE_MEMWRITE16, mem&0x13ff, 0); + } + + break; + } +} + +// (value&0x1f00)|0x6000 +void gsConstWriteIMR(int mmreg) +{ + const u32 mem = 0x12001010; + if( mmreg & MEM_XMMTAG ) { + SSE2_MOVD_XMM_to_M32((uptr)PS2GS_BASE(mem), mmreg&0xf); + AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); + OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); + } +#ifndef __x86_64__ + else if( mmreg & MEM_MMXTAG ) { + SetMMXstate(); + MOVDMMXtoM((uptr)PS2GS_BASE(mem), mmreg&0xf); + AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); + OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); + } +#endif + else if( mmreg & MEM_EECONSTTAG ) { + MOV32ItoM( (uptr)PS2GS_BASE(mem), (g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x1f00)|0x6000); + } + else { + AND32ItoR(mmreg, 0x1f00); + OR32ItoR(mmreg, 0x6000); + MOV32RtoM( (uptr)PS2GS_BASE(mem), mmreg ); + } + + // IMR doesn't need to be updated in MTGS mode +} + +void gsConstWrite32(u32 mem, int mmreg) { + + switch (mem) { + + case 0x12000010: // GS_SMODE1 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE1(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12000020: // GS_SMODE2 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE2(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)CSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + gsConstWriteIMR(mmreg); + break; + default: + _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callFunctionArg3((uptr)GSRingBufSimplePacket, MEM_CONSTTAG, MEM_CONSTTAG, mmreg, + GS_RINGTYPE_MEMWRITE32, mem&0x13ff, 0); + } + + break; + } +} + +void gsConstWrite64(u32 mem, int mmreg) +{ + switch (mem) { + case 0x12000010: // GS_SMODE1 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE1(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12000020: // GS_SMODE2 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE2(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)CSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + gsConstWriteIMR(mmreg); + break; + + default: + _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem)+4, X86ARG4); + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem), X86ARG3); + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE64, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 16); +#endif + } + + break; + } +} + +void gsConstWrite128(u32 mem, int mmreg) +{ + switch (mem) { + case 0x12000010: // GS_SMODE1 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE1(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12000020: // GS_SMODE2 + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) + _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); + + recSetSMODE2(); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 12); +#endif + } + + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)CSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + // (value&0x1f00)|0x6000 + gsConstWriteIMR(mmreg); + break; + + default: + _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); + + if( CHECK_MULTIGS ) { + iFlushCall(0); + + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem)+4, X86ARG4); + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem), X86ARG3); + _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE64, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 16); +#endif + + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem)+12, X86ARG4); + _callPushArg(MEM_MEMORYTAG, (uptr)PS2GS_BASE(mem)+8, X86ARG3); + _callPushArg(MEM_CONSTTAG, (mem&0x13ff)+8, X86ARG2); + _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE64, X86ARG1); + CALLFunc((uptr)GSRingBufSimplePacket); +#ifndef __x86_64__ + ADD32ItoR(ESP, 16); +#endif + } + + break; + } +} + +int gsConstRead8(u32 x86reg, u32 mem, u32 sign) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 8 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); +#endif + _eeReadConstMem8(x86reg, (uptr)PS2GS_BASE(mem), sign); + return 0; +} + +int gsConstRead16(u32 x86reg, u32 mem, u32 sign) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 16 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); +#endif + _eeReadConstMem16(x86reg, (uptr)PS2GS_BASE(mem), sign); + return 0; +} + +int gsConstRead32(u32 x86reg, u32 mem) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 32 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); +#endif + _eeReadConstMem32(x86reg, (uptr)PS2GS_BASE(mem)); + return 0; +} + +void gsConstRead64(u32 mem, int mmreg) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); +#endif + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PS2GS_BASE(mem)); + else { +#ifndef __x86_64__ + MOVQMtoR(mmreg, (uptr)PS2GS_BASE(mem)); + SetMMXstate(); +#else + assert(0); +#endif + } +} + +void gsConstRead128(u32 mem, int xmmreg) +{ +#ifdef GIF_LOG + GIF_LOG("GS read 128 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); +#endif + _eeReadConstMem128( xmmreg, (uptr)PS2GS_BASE(mem)); +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iHw.c b/pcsx2/x86/iHw.c new file mode 100644 index 0000000000..498ad1e810 --- /dev/null +++ b/pcsx2/x86/iHw.c @@ -0,0 +1,1297 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "PsxMem.h" +#include "IPU/IPU.h" +#include "GS.h" + +#ifndef PCSX2_VIRTUAL_MEM +extern u8 *psH; // hw mem +extern u16 *psHW; +extern u32 *psHL; +extern u64 *psHD; +#endif + +extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX +extern int rdram_sdevid; +extern char sio_buffer[1024]; +extern int sio_count; + +int hwConstRead8(u32 x86reg, u32 mem, u32 sign) +{ +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10000000 && mem < 0x10008000 ) + SysPrintf("hwRead8 to %x\n", mem); +#endif + + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else) + XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + //psHu32(mem) &= ~0x4000; + return 0; + } + } + + if (mem < 0x10010000) + { + _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + } + else { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + } + + return 0; +} + +#define CONSTREAD16_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R16toR(EAX, EAX); \ + else MOVZX32R16toR(EAX, EAX); \ +} \ + +static u32 s_regreads[3] = {0x010200000, 0xbfff0000, 0xF0000102}; +int hwConstRead16(u32 x86reg, u32 mem, u32 sign) +{ +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10002000 && mem < 0x10008000 ) + SysPrintf("hwRead16 to %x\n", mem); +#endif +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10000000 && mem < 0x10002000 ){ +#ifdef EECNT_LOG + EECNT_LOG("cnt read to %x\n", mem); +#endif + } +#endif + + switch (mem) { + case 0x10000000: + PUSH32I(0); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + case 0x10000010: + _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); + return 0; + case 0x10000020: + _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); + return 0; + case 0x10000030: + _eeReadConstMem16(x86reg, (uptr)&counters[0].hold, sign); + return 0; + + case 0x10000800: + PUSH32I(1); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10000810: + _eeReadConstMem16(x86reg, (uptr)&counters[1].mode, sign); + return 0; + + case 0x10000820: + _eeReadConstMem16(x86reg, (uptr)&counters[1].target, sign); + return 0; + + case 0x10000830: + _eeReadConstMem16(x86reg, (uptr)&counters[1].hold, sign); + return 0; + + case 0x10001000: + PUSH32I(2); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10001010: + _eeReadConstMem16(x86reg, (uptr)&counters[2].mode, sign); + return 0; + + case 0x10001020: + _eeReadConstMem16(x86reg, (uptr)&counters[2].target, sign); + return 0; + + case 0x10001800: + PUSH32I(3); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10001810: + _eeReadConstMem16(x86reg, (uptr)&counters[3].mode, sign); + return 0; + + case 0x10001820: + _eeReadConstMem16(x86reg, (uptr)&counters[3].target, sign); + return 0; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + MMXONLY(if( IS_MMXREG(x86reg) ) { + MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff] - 2); + PORMtoR(x86reg&0xf, (uptr)&s_regreads[0]); + PANDMtoR(x86reg&0xf, (uptr)&s_regreads[1]); + } + else ) + { + if( sign ) MOVSX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + else MOVZX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + + OR32ItoR(x86reg, 0x0102); + AND32ItoR(x86reg, ~0x4000); + } + return 0; + } + } + if (mem < 0x10010000) { + _eeReadConstMem16(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + } + else { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + } + + return 0; + } +} + +#ifdef PCSX2_VIRTUAL_MEM +// +//#if defined(_MSC_VER) && !defined(__x86_64__) +//__declspec(naked) void recCheckF440() +//{ +// __asm { +// add b440, 1 +// mov eax, b440 +// sub eax, 3 +// mov edx, 31 +// +// cmp eax, 27 +// ja WriteVal +// shl eax, 2 +// mov edx, dword ptr [eax+b440table] +// +//WriteVal: +// mov eax, PS2MEM_BASE_+0x1000f440 +// mov dword ptr [eax], edx +// ret +// } +//} +//#else +//void recCheckF440(); +//#endif + +void iMemRead32Check() +{ + // test if 0xf440 +// if( bExecBIOS ) { +// u8* ptempptr[2]; +// CMP32ItoR(ECX, 0x1000f440); +// ptempptr[0] = JNE8(0); +// +//// // increment and test +//// INC32M((uptr)&b440); +//// MOV32MtoR(EAX, (uptr)&b440); +//// SUB32ItoR(EAX, 3); +//// MOV32ItoR(EDX, 31); +//// +//// CMP32ItoR(EAX, 27); +//// +//// // look up table +//// ptempptr[1] = JA8(0); +//// SHL32ItoR(EAX, 2); +//// ADD32ItoR(EAX, (int)b440table); +//// MOV32RmtoR(EDX, EAX); +//// +//// x86SetJ8( ptempptr[1] ); +//// +//// MOV32RtoM( (int)PS2MEM_HW+0xf440, EDX); +// CALLFunc((uptr)recCheckF440); +// +// x86SetJ8( ptempptr[0] ); +// } +} + +#endif + +int hwContRead32_f440() +{ + if ((psHu32(0xf430) >> 6) & 0xF) + return 0; + else + switch ((psHu32(0xf430)>>16) & 0xFFF){//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + case 0x21://INIT + { + int ret = 0x1F * (rdram_sdevid < rdram_devices); + rdram_sdevid += (rdram_sdevid < rdram_devices); + return ret; + } + case 0x23://CNFGA + return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 + case 0x24://CNFGB + //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 + return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 + case 0x40://DEVID + return psHu32(0xf430) & 0x1F; // =SDEV + } + + return 0; +} + +int hwConstRead32(u32 x86reg, u32 mem) +{ + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + return ipuConstRead32(x86reg, mem); + } + + switch (mem) { + case 0x10000000: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)rcntRcount); +#ifdef EECNT_LOG + EECNT_LOG("Counter 0 count read = %x\n", rcntRcount(0)); +#endif + ADD32ItoR(ESP, 4); + return 1; + case 0x10000010: + _eeReadConstMem32(x86reg, (uptr)&counters[0].mode); +#ifdef EECNT_LOG + EECNT_LOG("Counter 0 mode read = %x\n", counters[0].mode); +#endif + return 0; + case 0x10000020: + _eeReadConstMem32(x86reg, (uptr)&counters[0].target); +#ifdef EECNT_LOG + EECNT_LOG("Counter 0 target read = %x\n", counters[0].target); +#endif + return 0; + case 0x10000030: + _eeReadConstMem32(x86reg, (uptr)&counters[0].hold); + return 0; + + case 0x10000800: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)rcntRcount); +#ifdef EECNT_LOG + EECNT_LOG("Counter 1 count read = %x\n", rcntRcount(1)); +#endif + ADD32ItoR(ESP, 4); + return 1; + case 0x10000810: + _eeReadConstMem32(x86reg, (uptr)&counters[1].mode); +#ifdef EECNT_LOG + EECNT_LOG("Counter 1 mode read = %x\n", counters[1].mode); +#endif + return 0; + case 0x10000820: + _eeReadConstMem32(x86reg, (uptr)&counters[1].target); +#ifdef EECNT_LOG + EECNT_LOG("Counter 1 target read = %x\n", counters[1].target); +#endif + return 0; + case 0x10000830: + _eeReadConstMem32(x86reg, (uptr)&counters[1].hold); + return 0; + + case 0x10001000: + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)rcntRcount); +#ifdef EECNT_LOG + EECNT_LOG("Counter 2 count read = %x\n", rcntRcount(2)); +#endif + ADD32ItoR(ESP, 4); + return 1; + case 0x10001010: + _eeReadConstMem32(x86reg, (uptr)&counters[2].mode); +#ifdef EECNT_LOG + EECNT_LOG("Counter 2 mode read = %x\n", counters[2].mode); +#endif + return 0; + case 0x10001020: + _eeReadConstMem32(x86reg, (uptr)&counters[2].target); +#ifdef EECNT_LOG + EECNT_LOG("Counter 2 target read = %x\n", counters[2].target); +#endif + return 0; + case 0x10001030: + _eeReadConstMem32(x86reg, (uptr)&counters[2].hold); + return 0; + + case 0x10001800: + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)rcntRcount); +#ifdef EECNT_LOG + EECNT_LOG("Counter 3 count read = %x\n", rcntRcount(3)); +#endif + ADD32ItoR(ESP, 4); + return 1; + case 0x10001810: + _eeReadConstMem32(x86reg, (uptr)&counters[3].mode); +#ifdef EECNT_LOG + EECNT_LOG("Counter 3 mode read = %x\n", counters[3].mode); +#endif + return 0; + case 0x10001820: + _eeReadConstMem32(x86reg, (uptr)&counters[3].target); +#ifdef EECNT_LOG + EECNT_LOG("Counter 3 target read = %x\n", counters[3].target); +#endif + return 0; + case 0x10001830: + _eeReadConstMem32(x86reg, (uptr)&counters[3].hold); + return 0; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + return 0; + + case 0x1000f440: + iFlushCall(0); + CALLFunc((uptr)hwContRead32_f440); + return 1; + + case 0x1000f520: // DMAC_ENABLER + _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[0xf590]); + return 0; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + if( IS_XMMREG(x86reg) ) { + SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + SSEX_POR_M128_to_XMM(x86reg&0xf, (uptr)&s_regreads[2]); + } + MMXONLY(else if( IS_MMXREG(x86reg) ) { + MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + PORMtoR(x86reg&0xf, (uptr)&s_regreads[2]); + }) + else { + MOV32MtoR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + OR32ItoR(x86reg, 0xF0000102); + } + return 0; + } + } + + if (mem < 0x10010000) { + _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + } + else { + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + } + + return 0; + } +} + +void hwConstRead64(u32 mem, int mmreg) { + if ((mem>=0x10002000) && (mem<0x10003000)) { + ipuConstRead64(mem, mmreg); + return; + } + + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PSM(mem)); + else { + X86_64ASSERT(); + MMXONLY(MOVQMtoR(mmreg, (uptr)PSM(mem)); + SetMMXstate();) + } +} + +PCSX2_ALIGNED16(u32 s_TempFIFO[4]); +void hwConstRead128(u32 mem, int xmmreg) { + if (mem >= 0x10004000 && mem < 0x10008000) { + iFlushCall(0); + PUSH32I((uptr)&s_TempFIFO[0]); + PUSH32I(mem); + CALLFunc((uptr)ReadFIFO); + ADD32ItoR(ESP, 8); + _eeReadConstMem128( xmmreg, (uptr)&s_TempFIFO[0]); + return; + } + + _eeReadConstMem128( xmmreg, (uptr)PSM(mem)); +} + +// when writing imm +#define recDmaExecI8(name, num) { \ + MOV8ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); \ + if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 1 ) { \ + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + CALLFunc((uptr)dma##name); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +#define recDmaExec8(name, num) { \ + iFlushCall(0); \ + if( IS_EECONSTREG(mmreg) ) { \ + recDmaExecI8(name, num); \ + } \ + else { \ + _eeMoveMMREGtoR(EAX, mmreg); \ + _eeWriteConstMem8((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); \ + \ + TEST8ItoR(EAX, 1); \ + j8Ptr[5] = JZ8(0); \ + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + \ + CALLFunc((uptr)dma##name); \ + \ + x86SetJ8( j8Ptr[5] ); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +static void PrintDebug(u8 value) +{ + if (value == '\n') { + sio_buffer[sio_count] = 0; + SysPrintf(COLOR_GREEN "%s\n" COLOR_RESET, sio_buffer); + sio_count = 0; + } else { + if (sio_count < 1023) { + sio_buffer[sio_count++] = value; + } + } +} + +#define CONSTWRITE_CALLTIMER(name, index, bit) { \ + if( !IS_EECONSTREG(mmreg) ) { \ + if( bit == 8 ) MOVZX32R8toR(mmreg&0xf, mmreg&0xf); \ + else if( bit == 16 ) MOVZX32R16toR(mmreg&0xf, mmreg&0xf); \ + } \ + _recPushReg(mmreg); \ + iFlushCall(0); \ + PUSH32I(index); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 8); \ +} \ + +#define CONSTWRITE_TIMERS(bit) \ + case 0x10000000: CONSTWRITE_CALLTIMER(rcntWcount, 0, bit); break; \ + case 0x10000010: CONSTWRITE_CALLTIMER(rcntWmode, 0, bit); break; \ + case 0x10000020: CONSTWRITE_CALLTIMER(rcntWtarget, 0, bit); break; \ + case 0x10000030: CONSTWRITE_CALLTIMER(rcntWhold, 0, bit); break; \ + \ + case 0x10000800: CONSTWRITE_CALLTIMER(rcntWcount, 1, bit); break; \ + case 0x10000810: CONSTWRITE_CALLTIMER(rcntWmode, 1, bit); break; \ + case 0x10000820: CONSTWRITE_CALLTIMER(rcntWtarget, 1, bit); break; \ + case 0x10000830: CONSTWRITE_CALLTIMER(rcntWhold, 1, bit); break; \ + \ + case 0x10001000: CONSTWRITE_CALLTIMER(rcntWcount, 2, bit); break; \ + case 0x10001010: CONSTWRITE_CALLTIMER(rcntWmode, 2, bit); break; \ + case 0x10001020: CONSTWRITE_CALLTIMER(rcntWtarget, 2, bit); break; \ + \ + case 0x10001800: CONSTWRITE_CALLTIMER(rcntWcount, 3, bit); break; \ + case 0x10001810: CONSTWRITE_CALLTIMER(rcntWmode, 3, bit); break; \ + case 0x10001820: CONSTWRITE_CALLTIMER(rcntWtarget, 3, bit); break; \ + +void hwConstWrite8(u32 mem, int mmreg) +{ + switch (mem) { + CONSTWRITE_TIMERS(8) + + case 0x1000f180: + _recPushReg(mmreg); \ + iFlushCall(0); + CALLFunc((uptr)PrintDebug); + ADD32ItoR(ESP, 4); + break; + + case 0x10008001: // dma0 - vif0 + recDmaExec8(VIF0, 0); + break; + + case 0x10009001: // dma1 - vif1 + recDmaExec8(VIF1, 1); + break; + + case 0x1000a001: // dma2 - gif + recDmaExec8(GIF, 2); + break; + + case 0x1000b001: // dma3 - fromIPU + recDmaExec8(IPU0, 3); + break; + + case 0x1000b401: // dma4 - toIPU + recDmaExec8(IPU1, 4); + break; + + case 0x1000c001: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec8(SIF0, 5); + break; + + case 0x1000c401: // dma6 - sif1 + recDmaExec8(SIF1, 6); + break; + + case 0x1000c801: // dma7 - sif2 + recDmaExec8(SIF2, 7); + break; + + case 0x1000d001: // dma8 - fromSPR + recDmaExec8(SPR0, 8); + break; + + case 0x1000d401: // dma9 - toSPR + recDmaExec8(SPR1, 9); + break; + + case 0x1000f592: // DMAC_ENABLEW + _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf522], mmreg ); + _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf592], mmreg ); + break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem8( (uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JNZ8(0); + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + x86SetJ8(j8Ptr[5]); + } + break; + } + return; + } + assert( (mem&0xff0f) != 0xf200 ); + + switch(mem&~3) { + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: +#ifdef PCSX2_VIRTUAL_MEM + //NOTE: this might cause crashes, but is more correct + _eeWriteConstMem8((u32)PS2MEM_BASE + mem, mmreg); +#else + if (mem < 0x10010000) + { + _eeWriteConstMem8((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + } +#endif + } + + break; + } +} + +#define recDmaExecI16(name, num) { \ + MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); \ + if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100 ) { \ + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + CALLFunc((uptr)dma##name); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +#define recDmaExec16(name, num) { \ + iFlushCall(0); \ + if( IS_EECONSTREG(mmreg) ) { \ + recDmaExecI16(name, num); \ + } \ + else { \ + _eeMoveMMREGtoR(EAX, mmreg); \ + _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); \ + \ + TEST16ItoR(EAX, 0x100); \ + j8Ptr[5] = JZ8(0); \ + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + \ + CALLFunc((uptr)dma##name); \ + \ + x86SetJ8( j8Ptr[5] ); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +void hwConstWrite16(u32 mem, int mmreg) +{ + switch(mem) { + CONSTWRITE_TIMERS(16) + case 0x10008000: // dma0 - vif0 + recDmaExec16(VIF0, 0); + break; + + case 0x10009000: // dma1 - vif1 - chcr + recDmaExec16(VIF1, 1); + break; + + case 0x1000a000: // dma2 - gif + recDmaExec16(GIF, 2); + break; + case 0x1000b000: // dma3 - fromIPU + recDmaExec16(IPU0, 3); + break; + case 0x1000b400: // dma4 - toIPU + recDmaExec16(IPU1, 4); + break; + case 0x1000c000: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec16(SIF0, 5); + break; + case 0x1000c002: + //? + break; + case 0x1000c400: // dma6 - sif1 + recDmaExec16(SIF1, 6); + break; + case 0x1000c800: // dma7 - sif2 + recDmaExec16(SIF2, 7); + break; + case 0x1000c802: + //? + break; + case 0x1000d000: // dma8 - fromSPR + recDmaExec16(SPR0, 8); + break; + case 0x1000d400: // dma9 - toSPR + recDmaExec16(SPR1, 9); + break; + case 0x1000f592: // DMAC_ENABLEW + _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf522], mmreg); + _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf592], mmreg); + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x20: + _eeWriteConstMem16OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); + break; + case 0x30: + if( IS_EECONSTREG(mmreg) ) { + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + } + else { + NOT32R(mmreg&0xf); + AND16RtoM((uptr)&PS2MEM_HW[mem&0xffff], mmreg&0xf); + } + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + } + else { + OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + + x86SetJ8( j8Ptr[6] ); + } + + break; + case 0x60: + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], 0); + break; + } + return; + } + +#ifdef PCSX2_VIRTUAL_MEM + //NOTE: this might cause crashes, but is more correct + _eeWriteConstMem16((u32)PS2MEM_BASE + mem, mmreg); +#else + if (mem < 0x10010000) + { + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + } +#endif + } +} + +// when writing an Imm +#define recDmaExecI(name, num) { \ + u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]; \ + /* Keep the old tag if in chain mode and hw doesnt set it*/ \ + if( (c & 0xc) == 0x4 && (c&0xffff0000) == 0 ) { \ + MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); \ + } \ + else MOV32ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); \ + if( c & 0x100 ) { \ + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + CALLFunc((uptr)dma##name); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +#define recDmaExec(name, num) { \ + iFlushCall(0); \ + if( IS_EECONSTREG(mmreg) ) { \ + recDmaExecI(name, num); \ + } \ + else { \ + _eeMoveMMREGtoR(EAX, mmreg); \ + TEST32ItoR(EAX, 0xffff0000); \ + j8Ptr[6] = JNZ8(0); \ + MOV32RtoR(ECX, EAX); \ + AND32ItoR(ECX, 0xc); \ + CMP32ItoR(ECX, 4); \ + j8Ptr[7] = JNE8(0); \ + if( IS_XMMREG(mmreg) || IS_MMXREG(mmreg) ) { \ + MOV16RtoM((uptr)&PS2MEM_HW[(mem) & 0xffff], EAX); \ + } \ + else { \ + _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); \ + } \ + j8Ptr[8] = JMP8(0); \ + x86SetJ8(j8Ptr[6]); \ + x86SetJ8(j8Ptr[7]); \ + _eeWriteConstMem32((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); \ + x86SetJ8(j8Ptr[8]); \ + \ + TEST16ItoR(EAX, 0x100); \ + j8Ptr[5] = JZ8(0); \ + TEST32ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); \ + j8Ptr[6] = JZ8(0); \ + \ + CALLFunc((uptr)dma##name); \ + \ + x86SetJ8( j8Ptr[5] ); \ + x86SetJ8( j8Ptr[6] ); \ + } \ +} \ + +#define CONSTWRITE_CALLTIMER32(name, index, bit) { \ + _recPushReg(mmreg); \ + iFlushCall(0); \ + PUSH32I(index); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 8); \ +} \ + +void hwConstWrite32(u32 mem, int mmreg) +{ + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + //psHu32(mem) = value; + ipuConstWrite32(mem, mmreg); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif0Write32); + ADD32ItoR(ESP, 8); + return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif1Write32); + ADD32ItoR(ESP, 8); + return; + } + + switch (mem) { + case 0x10000000: CONSTWRITE_CALLTIMER32(rcntWcount, 0, bit); break; + case 0x10000010: CONSTWRITE_CALLTIMER32(rcntWmode, 0, bit); break; + case 0x10000020: CONSTWRITE_CALLTIMER32(rcntWtarget, 0, bit); break; + case 0x10000030: CONSTWRITE_CALLTIMER32(rcntWhold, 0, bit); break; + + case 0x10000800: CONSTWRITE_CALLTIMER32(rcntWcount, 1, bit); break; + case 0x10000810: CONSTWRITE_CALLTIMER32(rcntWmode, 1, bit); break; + case 0x10000820: CONSTWRITE_CALLTIMER32(rcntWtarget, 1, bit); break; + case 0x10000830: CONSTWRITE_CALLTIMER32(rcntWhold, 1, bit); break; + + case 0x10001000: CONSTWRITE_CALLTIMER32(rcntWcount, 2, bit); break; + case 0x10001010: CONSTWRITE_CALLTIMER32(rcntWmode, 2, bit); break; + case 0x10001020: CONSTWRITE_CALLTIMER32(rcntWtarget, 2, bit); break; + + case 0x10001800: CONSTWRITE_CALLTIMER32(rcntWcount, 3, bit); break; + case 0x10001810: CONSTWRITE_CALLTIMER32(rcntWmode, 3, bit); break; + case 0x10001820: CONSTWRITE_CALLTIMER32(rcntWtarget, 3, bit); break; + + case GIF_CTRL: + + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + TEST8ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + + // reset GS + CALLFunc((uptr)gsGIFReset); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32I8toR(EAX, 8); + MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); + + TEST16ItoR(EAX, 8); + j8Ptr[5] = JZ8(0); + OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); + j8Ptr[7] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + return; + + case GIF_MODE: + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); + AND8ItoR(EAX, 5); + OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); + return; + + case GIF_STAT: // stat is readonly + return; + + case 0x10008000: // dma0 - vif0 + recDmaExec(VIF0, 0); + break; + + case 0x10009000: // dma1 - vif1 - chcr + recDmaExec(VIF1, 1); + break; + + case 0x1000a000: // dma2 - gif + recDmaExec(GIF, 2); + break; + + case 0x1000b000: // dma3 - fromIPU + recDmaExec(IPU0, 3); + break; + case 0x1000b400: // dma4 - toIPU + recDmaExec(IPU1, 4); + break; + case 0x1000c000: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec(SIF0, 5); + break; + + case 0x1000c400: // dma6 - sif1 + recDmaExec(SIF1, 6); + break; + + case 0x1000c800: // dma7 - sif2 + recDmaExec(SIF2, 7); + break; + + case 0x1000d000: // dma8 - fromSPR + recDmaExec(SPR0, 8); + break; + + case 0x1000d400: // dma9 - toSPR + recDmaExec(SPR1, 9); + break; + + case 0x1000e010: // DMAC_STAT + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + MOV32RtoR(ECX, EAX); + NOT32R(ECX); + AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); + + SHR32ItoR(EAX, 16); + XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10807); + CMP32ItoR(EAX, 0x10801); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestDMACInts); + + x86SetJ8( j8Ptr[5] ); + break; + + case 0x1000f000: // INTC_STAT + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[0xf000], mmreg, 2); + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10407); + CMP32ItoR(EAX, 0x10401); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestINTCInts); + + x86SetJ8( j8Ptr[5] ); + break; + + case 0x1000f010: // INTC_MASK + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10407); + CMP32ItoR(EAX, 0x10401); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestINTCInts); + + x86SetJ8( j8Ptr[5] ); + break; + + case 0x1000f130: + case 0x1000f410: + break; + + case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + + //if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 + // rdram_sdevid = 0 + _eeMoveMMREGtoR(EAX, mmreg); + MOV32RtoR(EDX, EAX); + MOV32RtoR(ECX, EAX); + SHR32ItoR(EAX, 6); + SHR32ItoR(EDX, 16); + AND32ItoR(EAX, 0xf); + AND32ItoR(EDX, 0xfff); + CMP32ItoR(EAX, 1); + j8Ptr[5] = JNE8(0); + CMP32ItoR(EDX, 0x21); + j8Ptr[6] = JNE8(0); + + TEST32ItoM((uptr)&psHu32(0xf440), 0x80); + j8Ptr[7] = JNZ8(0); + + // if SIO repeater is cleared, reset sdevid + MOV32ItoM((uptr)&rdram_sdevid, 0); + + //kill the busy bit + x86SetJ8(j8Ptr[5]); + x86SetJ8(j8Ptr[6]); + x86SetJ8(j8Ptr[7]); + AND32ItoR(ECX, ~0x80000000); + MOV32RtoM((uptr)&psHu32(0xf430), ECX); + break; + + case 0x1000f440://MCH_DRD: + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf440], mmreg); + break; + + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + return; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x20: + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); + break; + case 0x30: + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + } + else { + OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST32ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + + x86SetJ8( j8Ptr[6] ); + } + + break; + case 0x60: + MOV32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0); + break; + } + return; + } + +#ifdef PCSX2_VIRTUAL_MEM + //NOTE: this might cause crashes, but is more correct + _eeWriteConstMem32((u32)PS2MEM_BASE + mem, mmreg); +#else + if (mem < 0x10010000) + { + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + } +#endif + break; + } +} + +void hwConstWrite64(u32 mem, int mmreg) +{ + if ((mem>=0x10002000) && (mem<=0x10002030)) { + ipuConstWrite64(mem, mmreg); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif0Write32); + ADD32ItoR(ESP, 8); + return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif1Write32); + ADD32ItoR(ESP, 8); + return; + } + + switch (mem) { + case GIF_CTRL: + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + TEST8ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + + // reset GS + CALLFunc((uptr)gsGIFReset); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32I8toR(EAX, 8); + MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); + + TEST16ItoR(EAX, 8); + j8Ptr[5] = JZ8(0); + OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); + j8Ptr[7] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + return; + + case GIF_MODE: + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); + AND8ItoR(EAX, 5); + OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); + break; + + case GIF_STAT: // stat is readonly + return; + + case 0x1000a000: // dma2 - gif + recDmaExec(GIF, 2); + break; + + case 0x1000e010: // DMAC_STAT + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + MOV32RtoR(ECX, EAX); + NOT32R(ECX); + AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); + + SHR32ItoR(EAX, 16); + XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10807); + CMP32ItoR(EAX, 0x10801); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestDMACInts); + + x86SetJ8( j8Ptr[5] ); + break; + + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + break; + + case 0x1000f000: // INTC_STAT + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10407); + CMP32ItoR(EAX, 0x10401); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestINTCInts); + + x86SetJ8( j8Ptr[5] ); + break; + + case 0x1000f010: // INTC_MASK + + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.n.Status.val); + AND32ItoR(EAX, 0x10407); + CMP32ItoR(EAX, 0x10401); + j8Ptr[5] = JNE8(0); + CALLFunc((uptr)cpuTestINTCInts); + + x86SetJ8( j8Ptr[5] ); + + break; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + + _eeWriteConstMem64((uptr)PSM(mem), mmreg); + break; + } +} + +void hwConstWrite128(u32 mem, int mmreg) +{ + if (mem >= 0x10004000 && mem < 0x10008000) { + _eeWriteConstMem128((uptr)&s_TempFIFO[0], mmreg); + iFlushCall(0); + PUSH32I((uptr)&s_TempFIFO[0]); + PUSH32I(mem); + CALLFunc((uptr)WriteFIFO); + ADD32ItoR(ESP, 8); + return; + } + + switch (mem) { + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + default: + +#ifdef PCSX2_VIRTUAL_MEM + _eeWriteConstMem128( PS2MEM_BASE_+mem, mmreg); +#else + if (mem < 0x10010000) + _eeWriteConstMem128((uptr)&PS2MEM_HW[mem&0xffff], mmreg); +#endif + break; + } +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iMMI.c b/pcsx2/x86/iMMI.c new file mode 100644 index 0000000000..037ac28bf6 --- /dev/null +++ b/pcsx2/x86/iMMI.c @@ -0,0 +1,3376 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/********************************************************* +* cached MMI opcodes * +* * +*********************************************************/ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" + +#ifndef MMI_RECOMPILE + +REC_FUNC( PLZCW, _Rd_ ); + +#ifndef MMI0_RECOMPILE + +REC_FUNC( MMI0, _Rd_ ); + +#endif + +#ifndef MMI1_RECOMPILE + +REC_FUNC( MMI1, _Rd_ ); + +#endif + +#ifndef MMI2_RECOMPILE + +REC_FUNC( MMI2, _Rd_ ); + +#endif + +#ifndef MMI3_RECOMPILE + +REC_FUNC( MMI3, _Rd_ ); + +#endif + +REC_FUNC( PMFHL, _Rd_ ); +REC_FUNC( PMTHL, _Rd_ ); + +REC_FUNC( PSRLW, _Rd_ ); +REC_FUNC( PSRLH, _Rd_ ); + +REC_FUNC( PSRAH, _Rd_ ); +REC_FUNC( PSRAW, _Rd_ ); + +REC_FUNC( PSLLH, _Rd_ ); +REC_FUNC( PSLLW, _Rd_ ); + +#else + +void recPLZCW() +{ + int regd = -1; + int regs = 0; + + if ( ! _Rd_ ) return; + + if( GPR_IS_CONST1(_Rs_) ) { + _eeOnWriteReg(_Rd_, 0); + _deleteEEreg(_Rd_, 0); + GPR_SET_CONST(_Rd_); + + for(regs = 0; regs < 2; ++regs) { + u32 val = g_cpuConstRegs[_Rs_].UL[regs]; + + if( val != 0 ) { + u32 setbit = val&0x80000000; + g_cpuConstRegs[_Rd_].UL[regs] = 0; + val <<= 1; + + while((val & 0x80000000) == setbit) { + g_cpuConstRegs[_Rd_].UL[regs]++; + val <<= 1; + } + } + else { + g_cpuConstRegs[_Rd_].UL[regs] = 31; + } + } + return; + } + + _eeOnWriteReg(_Rd_, 0); + + if( (regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { + SSE2_MOVD_XMM_to_R(EAX, regs); + regs |= MEM_XMMTAG; + } +#ifndef __x86_64__ + else if( (regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { + MOVD32MMXtoR(EAX, regs); + SetMMXstate(); + regs |= MEM_MMXTAG; + } +#endif + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + regs = 0; + } + + if( EEINST_ISLIVE1(_Rd_) ) + _deleteEEreg(_Rd_, 0); +#ifndef __x86_64__ + else { + if( (regd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) < 0 ) { + _deleteEEreg(_Rd_, 0); + } + } +#endif + + // first word + TEST32RtoR(EAX, EAX); + j8Ptr[0] = JNZ8(0); + + // zero, so put 31 + if( EEINST_ISLIVE1(_Rd_) || regd < 0 ) { + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 31); + } +#ifndef __x86_64__ + else { + SetMMXstate(); + PCMPEQDRtoR(regd, regd); + PSRLQItoR(regd, 59); + } +#endif + + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + TEST32ItoR(EAX, 0x80000000); + j8Ptr[0] = JZ8(0); + NOT32R(EAX); + x86SetJ8(j8Ptr[0]); + + // not zero + x86SetJ8(j8Ptr[0]); + BSRRtoR(EAX, EAX); + MOV32ItoR(ECX, 30); + SUB32RtoR(ECX, EAX); + if( EEINST_ISLIVE1(_Rd_) || regd < 0 ) { + MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + } +#ifndef __x86_64__ + else { + SetMMXstate(); + MOVD32RtoMMX(regd, ECX); + } +#endif + + x86SetJ8(j8Ptr[1]); + + // second word + if( EEINST_ISLIVE1(_Rd_) ) { + if( regs >= 0 && (regs & MEM_XMMTAG) ) { + SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); + SSE2_MOVD_XMM_to_R(EAX, regs&0xf); + SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); + } +#ifndef __x86_64__ + else if( regs >= 0 && (regs & MEM_MMXTAG) ) { + PSHUFWRtoR(regs, regs, 0x4e); + MOVD32MMXtoR(EAX, regs&0xf); + PSHUFWRtoR(regs&0xf, regs&0xf, 0x4e); + SetMMXstate(); + } +#endif + else MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + + TEST32RtoR(EAX, EAX); + j8Ptr[0] = JNZ8(0); + + // zero, so put 31 + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 31); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + TEST32ItoR(EAX, 0x80000000); + j8Ptr[0] = JZ8(0); + NOT32R(EAX); + x86SetJ8(j8Ptr[0]); + + // not zero + x86SetJ8(j8Ptr[0]); + BSRRtoR(EAX, EAX); + MOV32ItoR(ECX, 30); + SUB32RtoR(ECX, EAX); + MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX); + x86SetJ8(j8Ptr[1]); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + + GPR_DEL_CONST(_Rd_); +} + +static u32 PCSX2_ALIGNED16(s_CmpMasks[]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + +void recPMFHL() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO|XMMINFO_READHI) + + int t0reg; + + switch (_Sa_) { + case 0x00: // LW + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + + _freeXMMreg(t0reg); + break; + + case 0x01: // UW + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0xdd); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0xdd); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + break; + + case 0x02: // SLW + // fall to interp + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + iFlushCall(FLUSH_CACHED_REGS); // since calling CALLFunc + CALLFunc( (u32)PMFHL ); + break; + + case 0x03: // LH + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + break; + + case 0x04: // SH + if( EEREC_D == EEREC_HI ) { + SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_LO); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x72); + } + else { + if( EEREC_D != EEREC_LO ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_HI); + + // shuffle so a1a0b1b0->a1b1a0b0 + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); + } + break; + default: + SysPrintf("PMFHL??\n"); + assert(0); + } + +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMFHL, _Rd_ ); +} + +void recPMTHL() +{ + REC_FUNC_INLINE( PMTHL, 0 ); +} + +#ifndef MMI0_RECOMPILE + +REC_FUNC( MMI0, _Rd_ ); + +#endif + +#ifndef MMI1_RECOMPILE + +REC_FUNC( MMI1, _Rd_ ); + +#endif + +#ifndef MMI2_RECOMPILE + +REC_FUNC( MMI2, _Rd_ ); + +#endif + +#ifndef MMI3_RECOMPILE + +REC_FUNC( MMI3, _Rd_ ); + +#endif + +#ifdef __x86_64__ + +#define MMX_ALLOC_TEMP1(code) +#define MMX_ALLOC_TEMP2(code) +#define MMX_ALLOC_TEMP3(code) +#define MMX_ALLOC_TEMP4(code) + +#else + +// MMX helper routines +#define MMX_ALLOC_TEMP1(code) { \ + int t0reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ +} \ + +#define MMX_ALLOC_TEMP2(code) { \ + int t0reg, t1reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ +} \ + +#define MMX_ALLOC_TEMP3(code) { \ + int t0reg, t1reg, t2reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ + _freeMMXreg(t2reg); \ +} \ + +#define MMX_ALLOC_TEMP4(code) { \ + int t0reg, t1reg, t2reg, t3reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t3reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ + _freeMMXreg(t2reg); \ + _freeMMXreg(t3reg); \ +} \ + +#endif // __x86_64__ + +//////////////////////////////////////////////////// +void recPSRLH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRLWItoR( t0reg, _Sa_&0xf ); + PSRLWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRLW( void ) +{ + if( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRLDItoR( t0reg, _Sa_ ); + PSRLDItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRAH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRAWItoR( t0reg, _Sa_&0xf ); + PSRAWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRAW( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRADItoR( t0reg, _Sa_ ); + PSRADItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSLLH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSLLWItoR( t0reg, _Sa_&0xf ); + PSLLWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSLLW( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSLLDItoR( t0reg, _Sa_ ); + PSLLDItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +/* +void recMADD( void ) +{ +} + +void recMADDU( void ) +{ +} + +void recPLZCW( void ) +{ +} +*/ + +#ifdef MMI0_RECOMPILE + +void recMMI0( void ) +{ + recMMI0t[ _Sa_ ]( ); +} + +#endif + +#ifdef MMI1_RECOMPILE + +void recMMI1( void ) +{ + recMMI1t[ _Sa_ ]( ); +} + +#endif + +#ifdef MMI2_RECOMPILE + +void recMMI2( void ) +{ + recMMI2t[ _Sa_ ]( ); +} + +#endif + +#ifdef MMI3_RECOMPILE + +void recMMI3( void ) +{ + recMMI3t[ _Sa_ ]( ); +} + +#endif + +#endif + +/********************************************************* +* MMI0 opcodes * +* * +*********************************************************/ +#ifndef MMI0_RECOMPILE + +REC_FUNC( PADDB, _Rd_); +REC_FUNC( PADDH, _Rd_); +REC_FUNC( PADDW, _Rd_); +REC_FUNC( PADDSB, _Rd_); +REC_FUNC( PADDSH, _Rd_); +REC_FUNC( PADDSW, _Rd_); +REC_FUNC( PSUBB, _Rd_); +REC_FUNC( PSUBH, _Rd_); +REC_FUNC( PSUBW, _Rd_); +REC_FUNC( PSUBSB, _Rd_); +REC_FUNC( PSUBSH, _Rd_); +REC_FUNC( PSUBSW, _Rd_); + +REC_FUNC( PMAXW, _Rd_); +REC_FUNC( PMAXH, _Rd_); + +REC_FUNC( PCGTW, _Rd_); +REC_FUNC( PCGTH, _Rd_); +REC_FUNC( PCGTB, _Rd_); + +REC_FUNC( PEXTLW, _Rd_); + +REC_FUNC( PPACW, _Rd_); +REC_FUNC( PEXTLH, _Rd_); +REC_FUNC( PPACH, _Rd_); +REC_FUNC( PEXTLB, _Rd_); +REC_FUNC( PPACB, _Rd_); +REC_FUNC( PEXT5, _Rd_); +REC_FUNC( PPAC5, _Rd_); + +#else + +//////////////////////////////////////////////////// +void recPMAXW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_T); + + if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); + _freeXMMreg(t1reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + + SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMAXW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPPACW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(((_Rs_!=0||!cpucaps.hasStreamingSIMD2Extensions)?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( cpucaps.hasStreamingSIMD2Extensions ) { + if( _Rs_ == 0 ) { + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + if( EEREC_D == EEREC_T ) { + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_S, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + + // swap mmx regs.. don't ask + xmmregs[t0reg] = xmmregs[EEREC_D]; + xmmregs[EEREC_D].inuse = 0; + } + } + } + else { + if( EEREC_D != EEREC_S ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_S, 0x88 ); + } + else { + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_T, 0x88 ); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); //Copy this one cos it could get overwritten + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], ECX); //This is where we bring it back + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); +} + +void recPPACH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_S, 0x88); + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + + if( cpucaps.hasStreamingSIMD2Extensions ) { + SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + } + else { + SSE_SHUFPS_XMM_to_XMM(EEREC_D, t0reg, 0x88); + } + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[6]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[4]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); +} + +//////////////////////////////////////////////////// +void recPPACB() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _hasFreeXMMreg() ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, EEREC_D); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(t0reg, 8); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSE2_PSRLW_I8_to_XMM(t0reg, 8); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PPACB, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXT5() +{ + REC_FUNC_INLINE( PEXT5, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPPAC5() +{ + REC_FUNC_INLINE( PPAC5, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMAXH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + if( cpucaps.hasStreamingSIMDExtensions ) { + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + SSE_PMAXSW_MM_to_MM( t0reg, t1reg ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + SSE_PMAXSW_MM_to_MM( t2reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) + } + else { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PMAXH ); + } +} + +//////////////////////////////////////////////////// +void recPCGTB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PCMPGTBRtoR( t0reg, t1reg ); + + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPGTBRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCGTH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + PCMPGTWRtoR( t0reg, t1reg ); + PCMPGTWRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCGTW( void ) +{ + //TODO:optimize RS | RT== 0 + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + PCMPGTDRtoR( t0reg, t1reg ); + PCMPGTDRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDSB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDSBRtoR( t0reg, t2reg); + PADDSBRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDSH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDSWRtoR( t0reg, t2reg); + PADDSWRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +//NOTE: check kh2 movies if changing this +void recPADDSW( void ) +{ + if ( ! _Rd_ ) return; + +//CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) +//CPU_SSE_XMMCACHE_END + + if( _Rd_ ) _deleteEEreg(_Rd_, 0); + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PADDSW ); +} + +//////////////////////////////////////////////////// +void recPSUBSB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBSBRtoR( t0reg, t2reg); + PSUBSBRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBSH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBSWRtoR( t0reg, t2reg); + PSUBSWRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +//NOTE: check kh2 movies if changing this +void recPSUBSW( void ) +{ + if ( ! _Rd_ ) return; + +//CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) +//CPU_SSE_XMMCACHE_END + + if( _Rd_ ) _deleteEEreg(_Rd_, 0); + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PSUBSW ); +} + +//////////////////////////////////////////////////// +void recPADDB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDBRtoR( t0reg, t2reg ); + PADDBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + else if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDWRtoR( t0reg, t2reg ); + PADDWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + else if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDDRtoR( t0reg, t2reg ); + PADDDRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBBRtoR( t0reg, t2reg ); + PSUBBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBWRtoR( t0reg, t2reg ); + PSUBWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBDRtoR( t0reg, t2reg); + PSUBDRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPEXTLW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); +} + +void recPEXTLB( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + //SysPrintf("PEXTLB\n"); + //Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[7]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[7]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[6]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[6]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[5]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[5]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[4]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[4]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[3]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[3]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[2]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[2]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[1]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[1]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[0]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[0]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); +} + +void recPEXTLH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[3]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[1]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); +} + +#endif + +/********************************************************* +* MMI1 opcodes * +* * +*********************************************************/ +#ifndef MMI1_RECOMPILE + +REC_FUNC( PABSW, _Rd_); +REC_FUNC( PABSH, _Rd_); + +REC_FUNC( PMINW, _Rd_); +REC_FUNC( PADSBH, _Rd_); +REC_FUNC( PMINH, _Rd_); +REC_FUNC( PCEQB, _Rd_); +REC_FUNC( PCEQH, _Rd_); +REC_FUNC( PCEQW, _Rd_); + +REC_FUNC( PADDUB, _Rd_); +REC_FUNC( PADDUH, _Rd_); +REC_FUNC( PADDUW, _Rd_); + +REC_FUNC( PSUBUB, _Rd_); +REC_FUNC( PSUBUH, _Rd_); +REC_FUNC( PSUBUW, _Rd_); + +REC_FUNC( PEXTUW, _Rd_); +REC_FUNC( PEXTUH, _Rd_); +REC_FUNC( PEXTUB, _Rd_); +REC_FUNC( QFSRV, _Rd_); + +#else + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(int s_MaskHighBitD[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; +PCSX2_ALIGNED16(int s_MaskHighBitW[4]) = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 }; + +void recPABSW() +{ + if( !_Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _deleteEEreg(_Rt_, 1); + _deleteEEreg(_Rd_, 0); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PABSW ); +} + +//////////////////////////////////////////////////// +void recPABSH() +{ +if( !_Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAW_I8_to_XMM(t0reg, 15); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _deleteEEreg(_Rt_, 1); + _deleteEEreg(_Rd_, 0); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PABSW ); +} + +//////////////////////////////////////////////////// +void recPMINW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_S); + + if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); + _freeXMMreg(t1reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + + SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMINW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPADSBH() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_D); + // reset lower bits to 0s + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 8); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + + if( EEREC_D == EEREC_S ) { + SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); + } + + // t0reg - adds, EEREC_D - subs + SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); + SSE_MOVLHPS_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE(PADSBH, _Rd_); +} + +//////////////////////////////////////////////////// +void recPADDUW() +{ +CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rt_ == 0 ) { + if( _Rs_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( _Rs_ == 0 ) { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + int t2reg = _allocTempXMMreg(XMMT_INT, -1); + + if( _hasFreeXMMreg() ) { + int t3reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(t3reg, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t0reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(t3reg, t0reg); + SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); + SSE2_PADDQ_XMM_to_XMM(t2reg, t3reg); + _freeXMMreg(t3reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + + SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); + SSE2_PSRLDQ_I8_to_XMM(t2reg, 8); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xE8); + SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); + SSE2_PADDQ_XMM_to_XMM(t2reg, t0reg); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + } + + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t1reg); + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, t2reg); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t2reg); + SSE2_PCMPGTD_XMM_to_XMM(t1reg, t0reg); + SSEX_POR_XMM_to_XMM(EEREC_D, t1reg); + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + _freeXMMreg(t2reg); + } + +CPU_SSE_XMMCACHE_END + REC_FUNC_INLINE( PADDUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUB() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PSUBUB, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PSUBUH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUW() +{ + REC_FUNC_INLINE( PSUBUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXTUH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PEXTUH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recQFSRV() +{ + //u8* pshift1, *pshift2, *poldptr, *pnewptr; + + if ( ! _Rd_ ) return; +/* +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + + if( _Rs_ == 0 ) { + MOV32MtoR(EAX, (uptr)&cpuRegs.sa); + SHR32ItoR(EAX, 3); + + poldptr = x86Ptr; + x86Ptr += 6; + + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 0); + pshift1 = x86Ptr-1; + + pnewptr = x86Ptr; + x86Ptr = poldptr; + + MOV8RtoM((uptr)pshift1, EAX); + x86Ptr = pnewptr; + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + MOV32MtoR(EAX, (uptr)&cpuRegs.sa); + SHR32ItoR(EAX, 3); + MOV32ItoR(ECX, 16); + SUB32RtoR(ECX, EAX); + + poldptr = x86Ptr; + x86Ptr += 12; + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PSRLDQ_I8_to_XMM(t0reg, 0); + pshift1 = x86Ptr-1; + + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 0); + pshift2 = x86Ptr-1; + + pnewptr = x86Ptr; + x86Ptr = poldptr; + + MOV8RtoM((uptr)pshift1, EAX); + MOV8RtoM((uptr)pshift2, ECX); + + x86Ptr = pnewptr; + + SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); + + _freeXMMreg(t0reg); + } + +CPU_SSE_XMMCACHE_END*/ + + REC_FUNC_INLINE( QFSRV, _Rd_ ); +} + + +void recPEXTUB( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but faster than int + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[8]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[8]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[9]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[9]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[10]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[10]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[11]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[11]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[12]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[12]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[13]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[13]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[14]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[14]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[15]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[15]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); +} + +//////////////////////////////////////////////////// +void recPEXTUW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 2 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 2 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 3 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 3 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); +} + +//////////////////////////////////////////////////// +void recPMINH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + if( cpucaps.hasStreamingSIMDExtensions ) { + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + SSE_PMINSW_MM_to_MM( t0reg, t2reg ); + SSE_PMINSW_MM_to_MM( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) + } + else { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (u32)PMINH ); + } +} + +//////////////////////////////////////////////////// +void recPCEQB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQBRtoR( t0reg, t2reg ); + PCMPEQBRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCEQH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQWRtoR( t0reg, t2reg ); + PCMPEQWRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCEQW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQDRtoR( t0reg, t2reg ); + PCMPEQDRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDUB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rt_ ) { + if( EEREC_D == EEREC_S ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + if( EEREC_D != EEREC_S ) SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDUSBRtoR( t0reg, t2reg ); + PADDUSBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDUH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDUSWRtoR( t0reg, t2reg ); + PADDUSWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +#endif +/********************************************************* +* MMI2 opcodes * +* * +*********************************************************/ +#ifndef MMI2_RECOMPILE + +REC_FUNC( PMFHI, _Rd_); +REC_FUNC( PMFLO, _Rd_); +REC_FUNC( PCPYLD, _Rd_); +REC_FUNC( PAND, _Rd_); +REC_FUNC( PXOR, _Rd_); + +REC_FUNC( PMADDW, _Rd_); +REC_FUNC( PSLLVW, _Rd_); +REC_FUNC( PSRLVW, _Rd_); +REC_FUNC( PMSUBW, _Rd_); +REC_FUNC( PINTH, _Rd_); +REC_FUNC( PMULTW, _Rd_); +REC_FUNC( PDIVW, _Rd_); +REC_FUNC( PMADDH, _Rd_); +REC_FUNC( PHMADH, _Rd_); +REC_FUNC( PMSUBH, _Rd_); +REC_FUNC( PHMSBH, _Rd_); +REC_FUNC( PEXEH, _Rd_); +REC_FUNC( PREVH, _Rd_); +REC_FUNC( PMULTH, _Rd_); +REC_FUNC( PDIVBW, _Rd_); +REC_FUNC( PEXEW, _Rd_); +REC_FUNC( PROT3W, _Rd_ ); + +#else + +//////////////////////////////////////////////////// +void recPMADDW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + REC_FUNC_INLINE( PMADDW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSLLVW() +{ + REC_FUNC_INLINE( PSLLVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSRLVW() +{ + REC_FUNC_INLINE( PSRLVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMSUBW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); +//CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) +// int t0reg = _allocTempXMMreg(XMMT_INT, -1); +// +// if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); +// else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); +// else { +// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); +// SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); +// } +// +// // add from LO/HI +// SSE_SHUFPS_XMM_to_XMM(EEREC_LO, EEREC_HI, 0x88); +// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); +// SSE2_PSUBQ_XMM_to_XMM(EEREC_LO, EEREC_D); +// +// // get the signs +// SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); +// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); +// SSE2_PSRAD_I8_to_XMM(t0reg, 31); +// +// // interleave +// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); +// SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); +// SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); +// +// SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); +// SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); +// +// _freeXMMreg(t0reg); +//CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMSUBW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMULTW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + REC_FUNC_INLINE( PMULTW, _Rd_ ); +} +//////////////////////////////////////////////////// +void recPDIVW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + REC_FUNC_INLINE( PDIVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPDIVBW() +{ + REC_FUNC_INLINE( PDIVBW, _Rd_ ); //-- +} + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(int s_mask[4]) = {~0, 0, ~0, 0}; + +void recPHMADH() +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _Rd_ ? EEREC_D : _allocTempXMMreg(XMMT_INT, -1); + + if( t0reg == EEREC_S ) { + + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + + if( t0reg == EEREC_T ) { + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + } + else { + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + } + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + } + else { + if( t0reg != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_T); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + } + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_HI); + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + + SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); + + if( _Rd_ ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + } + + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); + + SSE2_PAND_M128_to_XMM(EEREC_LO, (u32)s_mask); + SSE2_PAND_M128_to_XMM(EEREC_HI, (u32)s_mask); + + if( !_Rd_ ) _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PHMADH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMSUBH() +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); + + SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PSUBD_XMM_to_XMM(EEREC_HI, t1reg); + + if( _Rd_ ) { + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + } + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMSUBH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPHMSBH() +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, EEREC_HI); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + + SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); + + if( _Rd_ ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + } + + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); + + _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PHMSBH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXEH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xc6); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PEXEH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPREVH( void ) +{ + if (!_Rd_) return; + + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x1B); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x1B); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PREVH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPINTH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE_MOVHLPS_XMM_to_XMM(t0reg, EEREC_S); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE_MOVLHPS_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction + MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); + MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); + MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[2], EBX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[4], ECX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[0], EDX); + + MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[5]); + MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); + MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rs_].US[7]); + MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); + + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[5], EBX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[7], ECX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[6], EDX); +} + +void recPEXEW( void ) +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); + + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); +} + +void recPROT3W( void ) +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc9); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); + MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); + + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); +} + +void recPMULTH( void ) +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_HI, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_LO, EEREC_HI); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, EEREC_HI); + + if( _Rd_ ) { + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, t0reg, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_HI); + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_LO, t0reg); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if(!_Rt_ || !_Rs_) { + MOV32ItoM( (uptr)&cpuRegs.LO.UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[3], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[3], 0); + + if( _Rd_ ) { + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], 0); + } + return; + } + + //Done - Refraction + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); + + if (_Rd_) { + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + } +} + +void recPMFHI( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READHI) + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_HI); +CPU_SSE_XMMCACHE_END + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.HI.UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.HI.UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMFLO( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO) + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.LO.UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.LO.UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPAND( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) + if( EEREC_D == EEREC_T ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PANDMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PANDMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPXOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) + if( EEREC_D == EEREC_T ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( EEREC_D == EEREC_S ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PXORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PXORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYLD( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|((cpucaps.hasStreamingSIMD2Extensions&&_Rs_==0)?0:XMMINFO_READS)|XMMINFO_READT) + if( cpucaps.hasStreamingSIMD2Extensions ) { + if( _Rs_ == 0 ) { + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_S == EEREC_T ) SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x44); + else if( EEREC_D == EEREC_S ) { + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + else { + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } + else { + if( EEREC_D == EEREC_T ) SSE_MOVLHPS_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_T, 0x44); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_S, 0x44); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t1reg ); + SetMMXstate(); + ) +} + + +void recPMADDH( void ) +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); + + SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PADDD_XMM_to_XMM(EEREC_HI, t1reg); + + if( _Rd_ ) { + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_HI, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + } + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if(_Rt_ && _Rs_){ + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); + + } + + if (_Rd_) { + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + } +} + +#endif +/********************************************************* +* MMI3 opcodes * +* * +*********************************************************/ +#ifndef MMI3_RECOMPILE + +REC_FUNC( PMADDUW, _Rd_); +REC_FUNC( PSRAVW, _Rd_); +REC_FUNC( PMTHI, _Rd_); +REC_FUNC( PMTLO, _Rd_); +REC_FUNC( PINTEH, _Rd_); +REC_FUNC( PMULTUW, _Rd_); +REC_FUNC( PDIVUW, _Rd_); +REC_FUNC( PCPYUD, _Rd_); +REC_FUNC( POR, _Rd_); +REC_FUNC( PNOR, _Rd_); +REC_FUNC( PCPYH, _Rd_); +REC_FUNC( PEXCW, _Rd_); +REC_FUNC( PEXCH, _Rd_); + +#else + +//////////////////////////////////////////////////// +REC_FUNC( PSRAVW, _Rd_ ); + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(u32 s_tempPINTEH[4]) = {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + +void recPINTEH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + + int t0reg = -1; + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else { + if( EEREC_D != EEREC_T ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PAND_M128_to_XMM(EEREC_D, (u32)s_tempPINTEH); + } + } + else if( _Rt_ == 0 ) { + if( EEREC_D != EEREC_S ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_S == EEREC_T ) { + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_S, 0xa0); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xa0); + } + else if( EEREC_D == EEREC_T ) { + assert( EEREC_D != EEREC_S ); + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + SSE2_PSLLD_I8_to_XMM(t0reg, 16); + SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + if( EEREC_D != EEREC_S) SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PSLLD_I8_to_XMM(t0reg, 16); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + SSE2_PSRLD_I8_to_XMM(t0reg, 16); + SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); + } + } + + if( t0reg >= 0 ) _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PINTEH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMULTUW() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + + if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + + // get the signs + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + + // interleave + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + REC_FUNC_INLINE( PMULTUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMADDUW() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + + // add from LO/HI + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + SSE2_PADDQ_XMM_to_XMM(EEREC_D, EEREC_LO); + + // get the signs + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + + // interleave + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PMADDUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +//do EEINST_SETSIGNEXT +REC_FUNC( PDIVUW, _Rd_ ); + +//////////////////////////////////////////////////// +void recPEXCW() +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PEXCW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXCH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); +CPU_SSE_XMMCACHE_END + + REC_FUNC_INLINE( PEXCH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPNOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + } + else { + if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + if( _Rt_ != 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } + else if( _Rt_ == 0 ) { + if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + if( EEREC_D == EEREC_S ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + if( EEREC_S != EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + } + + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg ); + SSEX_PXOR_XMM_to_XMM( EEREC_D, t0reg ); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP3( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQDRtoR( t2reg, t2reg ); + PXORRtoR( t0reg, t2reg ); + PXORRtoR( t1reg, t2reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMTHI( void ) +{ +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITEHI) + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(XMMGPR_HI, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMTLO( void ) +{ +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITELO) + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(XMMGPR_LO, 0); + _deleteGPRtoXMMreg(_Rs_, 1); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYUD( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READS|((cpucaps.hasStreamingSIMD2Extensions&&_Rs_==0)?0:XMMINFO_READT)|XMMINFO_WRITED) + + if( cpucaps.hasStreamingSIMD2Extensions ) { + if( _Rt_ == 0 ) { + if( EEREC_D == EEREC_S ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); + } + } + else { + if( EEREC_D == EEREC_S ) SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + //TODO + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + else { + if( EEREC_S == EEREC_T ) { + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0xee); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } + } + else { + if( EEREC_D == EEREC_S ) { + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_T, 0xee); + } + else if( EEREC_D == EEREC_T ) { + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( _Rs_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + else if( _Rt_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + if( EEREC_S != EEREC_T ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + if ( _Rt_ != 0 ) + { + PORMtoR ( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PORMtoR ( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + } + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //PUSH32R( EBX ); + MOVZX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOV32RtoR( ECX, EAX ); + SHL32ItoR( ECX, 16 ); + OR32RtoR( EAX, ECX ); + MOVZX32M16toR( EDX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOV32RtoR( ECX, EDX ); + SHL32ItoR( ECX, 16 ); + OR32RtoR( EDX, ECX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], EDX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EDX ); + //POP32R( EBX ); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iMMI.h b/pcsx2/x86/iMMI.h new file mode 100644 index 0000000000..dc8e7b3a06 --- /dev/null +++ b/pcsx2/x86/iMMI.h @@ -0,0 +1,133 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/********************************************************* +* MMI opcodes * +* * +*********************************************************/ +#ifndef __IMMI_H__ +#define __IMMI_H__ + +void recMADD(); +void recMADDU(); +void recPLZCW(); +void recMMI0(); +void recMMI1(); +void recMMI2(); +void recMMI3(); +void recMADD1(); +void recMADDU1(); +void recPMFHL(); +void recPMTHL(); +void recPMAXW(); +void recPMINW(); +void recPPACW(); +void recPEXTLH(); +void recPPACH(); +void recPEXTLB(); +void recPPACB(); +void recPEXT5(); +void recPPAC5(); +void recPABSW(); +void recPADSBH(); +void recPABSH(); +void recPADDUW(); +void recPSUBUW(); +void recPSUBUH(); +void recPEXTUH(); +void recPSUBUB(); +void recPEXTUB(); +void recQFSRV(); +void recPMADDW(); +void recPSLLVW(); +void recPSRLVW(); +void recPMSUBW(); +void recPINTH(); +void recPMULTW(); +void recPDIVW(); +void recPMADDH(); +void recPHMADH(); +void recPMSUBH(); +void recPHMSBH(); +void recPEXEH(); +void recPREVH(); +void recPMULTH(); +void recPDIVBW(); +void recPEXEW(); +void recPROT3W(); +void recPMADDUW(); +void recPSRAVW(); +void recPINTEH(); +void recPMULTUW(); +void recPDIVUW(); +void recPEXCH(); +void recPEXCW(); + +void recPSRLH(); +void recPSRLW(); +void recPSRAH(); +void recPSRAW(); +void recPSLLH(); +void recPSLLW(); +void recMTHI1(); +void recMTLO1(); +void recMFHI1(); +void recMFLO1(); +void recMULT1(); +void recMULTU1(); +void recDIV1(); +void recDIVU1(); +void recPMAXH(); +void recPCGTB(); +void recPCGTH(); +void recPCGTW(); +void recPADDSB(); +void recPADDSH(); +void recPADDSW(); +void recPSUBSB(); +void recPSUBSH(); +void recPSUBSW(); +void recPADDB(); +void recPADDH(); +void recPADDW(); +void recPSUBB(); +void recPSUBH(); +void recPSUBW(); +void recPEXTLW(); +void recPEXTUW(); +void recPMINH(); +void recPCEQB(); +void recPCEQH(); +void recPCEQW(); +void recPADDUB(); +void recPADDUH(); +void recPMFHI(); +void recPMFLO(); +void recPAND(); +void recPXOR(); +void recPCPYLD(); +void recPNOR(); +void recPMTHI(); +void recPMTLO(); +void recPCPYUD(); +void recPOR(); +void recPCPYH(); + +#endif + + diff --git a/pcsx2/x86/iPsxHw.c b/pcsx2/x86/iPsxHw.c new file mode 100644 index 0000000000..eaa1344994 --- /dev/null +++ b/pcsx2/x86/iPsxHw.c @@ -0,0 +1,1164 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include + +#include "PsxCommon.h" +#include "iR5900.h" + +extern int g_pbufi; +extern s8 g_pbuf[1024]; + +#define CONSTREAD8_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R8toR(EAX, EAX); \ + else MOVZX32R8toR(EAX, EAX); \ +} \ + +static u32 s_16 = 0x10; + +int psxHwConstRead8(u32 x86reg, u32 add, u32 sign) { + + if (add >= 0x1f801600 && add < 0x1f801700) { + PUSH32I(add); + CONSTREAD8_CALL(USBread8); + // since calling from different dll, esp already changed + return 1; + } + + switch (add) { + case 0x1f801040: + CONSTREAD8_CALL(sioRead8); + return 1; + // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now + +#ifdef PCSX2_DEVBUILD + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter read %x\n", add); + _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; +#endif + + case 0x1f80146e: // DEV9_R_REV + PUSH32I(add); + CONSTREAD8_CALL(DEV9read8); + return 1; + + case 0x1f801800: CONSTREAD8_CALL(cdrRead0); return 1; + case 0x1f801801: CONSTREAD8_CALL(cdrRead1); return 1; + case 0x1f801802: CONSTREAD8_CALL(cdrRead2); return 1; + case 0x1f801803: CONSTREAD8_CALL(cdrRead3); return 1; + + case 0x1f803100: // PS/EE/IOP conf related + if( IS_XMMREG(x86reg) ) SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&s_16); + MMXONLY(else if( IS_MMXREG(x86reg) ) MOVDMtoMMX(x86reg&0xf, (uptr)&s_16);) + else MOV32ItoR(x86reg, 0x10); + return 0; + + case 0x1F808264: //sio2 serial data feed/fifo_out + CONSTREAD8_CALL(sio2_fifoOut); + return 1; + + default: + _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; + } +} + +#define CONSTREAD16_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R16toR(EAX, EAX); \ + else MOVZX32R16toR(EAX, EAX); \ +} \ + +void psxConstReadCounterMode16(int x86reg, int index, int sign) +{ + if( IS_MMXREG(x86reg) ) { + X86_64ASSERT(); + MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); + MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode - 2);) + } + else { + if( sign ) MOVSX32M16toR(ECX, (uptr)&psxCounters[index].mode); + else MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); + + MOV32RtoR(x86reg, ECX); + } + + AND16ItoR(ECX, ~0x1800); + OR16ItoR(ECX, 0x400); + MOV16RtoM((uptr)&psxCounters[index].mode, ECX); +} + +int psxHwConstRead16(u32 x86reg, u32 add, u32 sign) { + if (add >= 0x1f801600 && add < 0x1f801700) { + PUSH32I(add); + CONSTREAD16_CALL(USBread16); + return 1; + } + + switch (add) { + + case 0x1f801040: + iFlushCall(0); + CALLFunc((uptr)sioRead8); + PUSHR(EAX); + CALLFunc((uptr)sioRead8); + POPR(ECX); + AND32ItoR(ECX, 0xff); + SHL32ItoR(EAX, 8); + OR32RtoR(EAX, ECX); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + + case 0x1f801044: + _eeReadConstMem16(x86reg, (uptr)&sio.StatReg, sign); + return 0; + + case 0x1f801048: + _eeReadConstMem16(x86reg, (uptr)&sio.ModeReg, sign); + return 0; + + case 0x1f80104a: + _eeReadConstMem16(x86reg, (uptr)&sio.CtrlReg, sign); + return 0; + + case 0x1f80104e: + _eeReadConstMem16(x86reg, (uptr)&sio.BaudReg, sign); + return 0; + + // counters[0] + case 0x1f801100: + PUSH32I(0); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801104: + psxConstReadCounterMode16(x86reg, 0, sign); + return 0; + + case 0x1f801108: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[0].target, sign); + return 0; + + // counters[1] + case 0x1f801110: + PUSH32I(1); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801114: + psxConstReadCounterMode16(x86reg, 1, sign); + return 0; + + case 0x1f801118: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[1].target, sign); + return 0; + + // counters[2] + case 0x1f801120: + PUSH32I(2); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801124: + psxConstReadCounterMode16(x86reg, 2, sign); + return 0; + + case 0x1f801128: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[2].target, sign); + return 0; + + case 0x1f80146e: // DEV9_R_REV + PUSH32I(add); + CONSTREAD16_CALL(DEV9read16); + return 1; + + // counters[3] + case 0x1f801480: + PUSH32I(3); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801484: + psxConstReadCounterMode16(x86reg, 3, sign); + return 0; + + case 0x1f801488: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[3].target, sign); + return 0; + + // counters[4] + case 0x1f801490: + PUSH32I(4); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801494: + psxConstReadCounterMode16(x86reg, 4, sign); + return 0; + + case 0x1f801498: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[4].target, sign); + return 0; + + // counters[5] + case 0x1f8014a0: + PUSH32I(5); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f8014a4: + psxConstReadCounterMode16(x86reg, 5, sign); + return 0; + + case 0x1f8014a8: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[5].target, sign); + return 0; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + + PUSH32I(add); + CONSTREAD16_CALL(SPU2read); + return 1; + } else { + _eeReadConstMem16(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; + } + } +} + +void psxConstReadCounterMode32(int x86reg, int index) +{ + if( IS_MMXREG(x86reg) ) { + X86_64ASSERT(); + MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); + MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode);) + } + else { + MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); + MOV32RtoR(x86reg, ECX); + } + + //AND16ItoR(ECX, ~0x1800); + //OR16ItoR(ECX, 0x400); + //MOV16RtoM((uptr)&psxCounters[index].mode, ECX); +} + +static u32 s_tempsio; +int psxHwConstRead32(u32 x86reg, u32 add) { + if (add >= 0x1f801600 && add < 0x1f801700) { + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBread32); + return 1; + } + if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)FWread32); + return 1; + } + + switch (add) { + case 0x1f801040: + iFlushCall(0); + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + MOV32RtoM((uptr)&s_tempsio, EAX); + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + SHL32ItoR(EAX, 8); + OR32RtoM((uptr)&s_tempsio, EAX); + + // 3rd + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + SHL32ItoR(EAX, 16); + OR32RtoM((uptr)&s_tempsio, EAX); + + // 4th + CALLFunc((uptr)sioRead8); + SHL32ItoR(EAX, 24); + OR32MtoR(EAX, (uptr)&s_tempsio); + return 1; + + //case 0x1f801050: hard = serial_read32(); break;//serial port + case 0x1f801078: +#ifdef PSXHW_LOG + PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); +#endif + _eeReadConstMem32(x86reg, (uptr)&psxH[add&0xffff]); + MOV32ItoM((uptr)&psxH[add&0xffff], 0); + return 0; + + // counters[0] + case 0x1f801100: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801104: + psxConstReadCounterMode32(x86reg, 0); + return 0; + + case 0x1f801108: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[0].target); + return 0; + + // counters[1] + case 0x1f801110: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801114: + psxConstReadCounterMode32(x86reg, 1); + return 0; + + case 0x1f801118: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[1].target); + return 0; + + // counters[2] + case 0x1f801120: + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801124: + psxConstReadCounterMode32(x86reg, 2); + return 0; + + case 0x1f801128: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[2].target); + return 0; + + // counters[3] + case 0x1f801480: + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801484: + psxConstReadCounterMode32(x86reg, 3); + return 0; + + case 0x1f801488: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[3].target); + return 0; + + // counters[4] + case 0x1f801490: + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801494: + psxConstReadCounterMode32(x86reg, 4); + return 0; + + case 0x1f801498: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[4].target); + return 0; + + // counters[5] + case 0x1f8014a0: + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f8014a4: + psxConstReadCounterMode32(x86reg, 5); + return 0; + + case 0x1f8014a8: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[5].target); + return 0; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + iFlushCall(0); + PUSH32I((add-0x1F808200)/4); + CALLFunc((uptr)sio2_getSend3); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F80825C: + iFlushCall(0); + PUSH32I((add-0x1F808240)/8); + CALLFunc((uptr)sio2_getSend1); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F808258: + iFlushCall(0); + PUSH32I((add-0x1F808244)/8); + CALLFunc((uptr)sio2_getSend2); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808268: + iFlushCall(0); + CALLFunc((uptr)sio2_getCtrl); + return 1; + + case 0x1F80826C: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv1); + return 1; + + case 0x1F808270: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv2); + return 1; + + case 0x1F808274: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv3); + return 1; + + case 0x1F808278: + iFlushCall(0); + CALLFunc((uptr)sio2_get8278); + return 1; + + case 0x1F80827C: + iFlushCall(0); + CALLFunc((uptr)sio2_get827C); + return 1; + + case 0x1F808280: + iFlushCall(0); + CALLFunc((uptr)sio2_getIntr); + return 1; + + case 0x1F801C00: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)SPU2ReadMemAddr); + return 1; + + case 0x1F801500: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)SPU2ReadMemAddr); + return 1; + + default: + _eeReadConstMem32(x86reg, (uptr)&psxH[(add) & 0xffff]); + return 0; + } +} + +#define CONSTWRITE_CALL(name) { \ + _recPushReg(mmreg); \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 4); \ +} \ + +void Write8PrintBuffer(u8 value) +{ + if (value == '\r') return; + if (value == '\n' || g_pbufi >= 1023) { + g_pbuf[g_pbufi++] = 0; g_pbufi = 0; + SysPrintf("%s\n", g_pbuf); return; + } + g_pbuf[g_pbufi++] = value; +} + +void psxHwConstWrite8(u32 add, int mmreg) +{ + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite8); + return; + } + + switch (add) { + case 0x1f801040: + CONSTWRITE_CALL(sioWrite8); break; + //case 0x1f801050: serial_write8(value); break;//serial port + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter write %x\n", add); + _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); + return; + case 0x1f801800: CONSTWRITE_CALL(cdrWrite0); break; + case 0x1f801801: CONSTWRITE_CALL(cdrWrite1); break; + case 0x1f801802: CONSTWRITE_CALL(cdrWrite2); break; + case 0x1f801803: CONSTWRITE_CALL(cdrWrite3); break; + case 0x1f80380c: CONSTWRITE_CALL(Write8PrintBuffer); break; + case 0x1F808260: CONSTWRITE_CALL(sio2_serialIn); break; + + default: + _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +void psxHwConstWrite16(u32 add, int mmreg) { + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite16); + return; + } + + switch (add) { + case 0x1f801040: + _recPushReg(mmreg); + iFlushCall(0); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 3); + return; + case 0x1f801044: + return; + case 0x1f801048: + _eeWriteConstMem16((uptr)&sio.ModeReg, mmreg); + return; + case 0x1f80104a: // control register + CONSTWRITE_CALL(sioWriteCtrl16); + return; + case 0x1f80104e: // baudrate register + _eeWriteConstMem16((uptr)&sio.BaudReg, mmreg); + return; + + case 0x1f801070: + _eeWriteConstMem16OP((uptr)&psxH[(add) & 0xffff], mmreg, 0); + return; + + // counters[0] + case 0x1f801100: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + case 0x1f801104: + CONSTWRITE_CALL(psxRcnt0Wmode); + return; + case 0x1f801108: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[1] + case 0x1f801110: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801114: + CONSTWRITE_CALL(psxRcnt1Wmode); + return; + + case 0x1f801118: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[2] + case 0x1f801120: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801124: + CONSTWRITE_CALL(psxRcnt2Wmode); + return; + + case 0x1f801128: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[3] + case 0x1f801480: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801484: + CONSTWRITE_CALL(psxRcnt3Wmode); + return; + + case 0x1f801488: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[4] + case 0x1f801490: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801494: + CONSTWRITE_CALL(psxRcnt4Wmode); + return; + + case 0x1f801498: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[5] + case 0x1f8014a0: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014a4: + CONSTWRITE_CALL(psxRcnt5Wmode); + return; + + case 0x1f8014a8: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)SPU2write); + // leave esp alone + return; + } + + _eeWriteConstMem16((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +#define recDmaExec(n) { \ + iFlushCall(0); \ + if( n > 6 ) TEST32ItoM((uptr)&HW_DMA_PCR2, 8 << (((n<<2)-28)&0x1f)); \ + else TEST32ItoM((uptr)&HW_DMA_PCR, 8 << (((n<<2))&0x1f)); \ + j8Ptr[5] = JZ8(0); \ + MOV32MtoR(EAX, (uptr)&HW_DMA##n##_CHCR); \ + TEST32ItoR(EAX, 0x01000000); \ + j8Ptr[6] = JZ8(0); \ + \ + _callFunctionArg3((uptr)psxDma##n, MEM_MEMORYTAG, MEM_MEMORYTAG, MEM_X86TAG, (uptr)&HW_DMA##n##_MADR, (uptr)&HW_DMA##n##_BCR, EAX); \ + \ + x86SetJ8( j8Ptr[5] ); \ + x86SetJ8( j8Ptr[6] ); \ +} \ + +#define CONSTWRITE_CALL32(name) { \ + iFlushCall(0); \ + _recPushReg(mmreg); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 4); \ +} \ + +void psxHwConstWrite32(u32 add, int mmreg) +{ + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite32); + return; + } + if (add >= 0x1f808400 && add <= 0x1f808550) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)FWwrite32); + return; + } + + switch (add) { + case 0x1f801040: + _recPushReg(mmreg); + iFlushCall(0); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + return; + + case 0x1f801070: + _eeWriteConstMem32OP((uptr)&psxH[(add) & 0xffff], mmreg, 0); // and + return; + +// case 0x1f801088: +// HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) +//// DmaExec(0); +// return; + +// case 0x1f801098: +// HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) +//// DmaExec(1); +// return; + + case 0x1f8010a8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(2); + return; + + case 0x1f8010b8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(3); + return; + + case 0x1f8010c8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(4); + return; + + case 0x1f8010e8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(6); + return; + + case 0x1f801508: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(7); + return; + + case 0x1f801518: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(8); + return; + + case 0x1f801528: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(9); + return; + + case 0x1f801538: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(10); + return; + + case 0x1f801548: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(11); + return; + + case 0x1f801558: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(12); + return; + + case 0x1f8010f4: + case 0x1f801574: + { + // u32 tmp = (~value) & HW_DMA_ICR; + _eeMoveMMREGtoR(EAX, mmreg); + MOV32RtoR(ECX, EAX); + NOT32R(ECX); + AND32MtoR(ECX, (uptr)&psxH[(add) & 0xffff]); + + // HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; + XOR32RtoR(EAX, ECX); + AND32ItoR(EAX, 0xffffff); + XOR32RtoR(EAX, ECX); + MOV32RtoM((uptr)&psxH[(add) & 0xffff], EAX); + return; + } + + // counters[0] + case 0x1f801100: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + case 0x1f801104: + CONSTWRITE_CALL32(psxRcnt0Wmode); + return; + case 0x1f801108: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[1] + case 0x1f801110: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801114: + CONSTWRITE_CALL32(psxRcnt1Wmode); + return; + + case 0x1f801118: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[2] + case 0x1f801120: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801124: + CONSTWRITE_CALL32(psxRcnt2Wmode); + return; + + case 0x1f801128: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[3] + case 0x1f801480: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801484: + CONSTWRITE_CALL32(psxRcnt3Wmode); + return; + + case 0x1f801488: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[4] + case 0x1f801490: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801494: + CONSTWRITE_CALL32(psxRcnt4Wmode); + return; + + case 0x1f801498: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[5] + case 0x1f8014a0: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014a4: + CONSTWRITE_CALL32(psxRcnt5Wmode); + return; + + case 0x1f8014a8: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014c0: + SysPrintf("RTC_HOLDMODE 32bit write\n"); + break; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808200)/4); + CALLFunc((uptr)sio2_setSend3); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F808258: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808240)/8); + CALLFunc((uptr)sio2_setSend1); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F80825C: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808244)/8); + CALLFunc((uptr)sio2_setSend2); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808268: CONSTWRITE_CALL32(sio2_setCtrl); return; + case 0x1F808278: CONSTWRITE_CALL32(sio2_set8278); return; + case 0x1F80827C: CONSTWRITE_CALL32(sio2_set827C); return; + case 0x1F808280: CONSTWRITE_CALL32(sio2_setIntr); return; + + case 0x1F8010C0: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)SPU2WriteMemAddr); + return; + + case 0x1F801500: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)SPU2WriteMemAddr); + return; + default: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +int psxHw4ConstRead8(u32 x86reg, u32 add, u32 sign) { + switch (add) { + case 0x1f402004: CONSTREAD8_CALL((u32)cdvdRead04); return 1; + case 0x1f402005: CONSTREAD8_CALL((u32)cdvdRead05); return 1; + case 0x1f402006: CONSTREAD8_CALL((u32)cdvdRead06); return 1; + case 0x1f402007: CONSTREAD8_CALL((u32)cdvdRead07); return 1; + case 0x1f402008: CONSTREAD8_CALL((u32)cdvdRead08); return 1; + case 0x1f40200A: CONSTREAD8_CALL((u32)cdvdRead0A); return 1; + case 0x1f40200B: CONSTREAD8_CALL((u32)cdvdRead0B); return 1; + case 0x1f40200C: CONSTREAD8_CALL((u32)cdvdRead0C); return 1; + case 0x1f40200D: CONSTREAD8_CALL((u32)cdvdRead0D); return 1; + case 0x1f40200E: CONSTREAD8_CALL((u32)cdvdRead0E); return 1; + case 0x1f40200F: CONSTREAD8_CALL((u32)cdvdRead0F); return 1; + case 0x1f402013: CONSTREAD8_CALL((u32)cdvdRead13); return 1; + case 0x1f402015: CONSTREAD8_CALL((u32)cdvdRead15); return 1; + case 0x1f402016: CONSTREAD8_CALL((u32)cdvdRead16); return 1; + case 0x1f402017: CONSTREAD8_CALL((u32)cdvdRead17); return 1; + case 0x1f402018: CONSTREAD8_CALL((u32)cdvdRead18); return 1; + case 0x1f402020: CONSTREAD8_CALL((u32)cdvdRead20); return 1; + case 0x1f402021: CONSTREAD8_CALL((u32)cdvdRead21); return 1; + case 0x1f402022: CONSTREAD8_CALL((u32)cdvdRead22); return 1; + case 0x1f402023: CONSTREAD8_CALL((u32)cdvdRead23); return 1; + case 0x1f402024: CONSTREAD8_CALL((u32)cdvdRead24); return 1; + case 0x1f402028: CONSTREAD8_CALL((u32)cdvdRead28); return 1; + case 0x1f402029: CONSTREAD8_CALL((u32)cdvdRead29); return 1; + case 0x1f40202A: CONSTREAD8_CALL((u32)cdvdRead2A); return 1; + case 0x1f40202B: CONSTREAD8_CALL((u32)cdvdRead2B); return 1; + case 0x1f40202C: CONSTREAD8_CALL((u32)cdvdRead2C); return 1; + case 0x1f402030: CONSTREAD8_CALL((u32)cdvdRead30); return 1; + case 0x1f402031: CONSTREAD8_CALL((u32)cdvdRead31); return 1; + case 0x1f402032: CONSTREAD8_CALL((u32)cdvdRead32); return 1; + case 0x1f402033: CONSTREAD8_CALL((u32)cdvdRead33); return 1; + case 0x1f402034: CONSTREAD8_CALL((u32)cdvdRead34); return 1; + case 0x1f402038: CONSTREAD8_CALL((u32)cdvdRead38); return 1; + case 0x1f402039: CONSTREAD8_CALL((u32)cdvdRead39); return 1; + case 0x1f40203A: CONSTREAD8_CALL((u32)cdvdRead3A); return 1; + default: + SysPrintf("*Unkwnown 8bit read at address %lx\n", add); + XOR32RtoR(x86reg, x86reg); + return 0; + } +} + +void psxHw4ConstWrite8(u32 add, int mmreg) { + switch (add) { + case 0x1f402004: CONSTWRITE_CALL(cdvdWrite04); return; + case 0x1f402005: CONSTWRITE_CALL(cdvdWrite05); return; + case 0x1f402006: CONSTWRITE_CALL(cdvdWrite06); return; + case 0x1f402007: CONSTWRITE_CALL(cdvdWrite07); return; + case 0x1f402008: CONSTWRITE_CALL(cdvdWrite08); return; + case 0x1f40200A: CONSTWRITE_CALL(cdvdWrite0A); return; + case 0x1f40200F: CONSTWRITE_CALL(cdvdWrite0F); return; + case 0x1f402014: CONSTWRITE_CALL(cdvdWrite14); return; + case 0x1f402016: + MMXONLY(_freeMMXregs();) + CONSTWRITE_CALL(cdvdWrite16); + return; + case 0x1f402017: CONSTWRITE_CALL(cdvdWrite17); return; + case 0x1f402018: CONSTWRITE_CALL(cdvdWrite18); return; + case 0x1f40203A: CONSTWRITE_CALL(cdvdWrite3A); return; + default: + SysPrintf("*Unknown 8bit write at address %lx\n", add); + return; + } +} + +#endif // PCSX2_NORECBUILD + diff --git a/pcsx2/x86/iPsxMem.c b/pcsx2/x86/iPsxMem.c new file mode 100644 index 0000000000..c4f4a450a9 --- /dev/null +++ b/pcsx2/x86/iPsxMem.c @@ -0,0 +1,878 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "PsxCommon.h" +#include "VU.h" +#include "iCore.h" +#include "iR3000A.h" + +extern u32 g_psxMaxRecMem; +extern int g_psxWriteOk; +static u32 writectrl; + +#ifdef PCSX2_VIRTUAL_MEM + +#ifdef _DEBUG + +#define ASSERT_WRITEOK \ +{ \ + __asm cmp g_psxWriteOk, 1 \ + __asm je WriteOk \ + __asm int 10 \ +} \ +WriteOk: \ + +#else +#define ASSERT_WRITEOK +#endif + +__declspec(naked) void psxRecMemRead8() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1f40 + je hw4read + cmp dx, 0x1000 + je devread + cmp dx, 0x1f00 + je spuread + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead8 + add esp, 4 + ret + +hw4read: + push ecx + call psxHw4Read8 + add esp, 4 + ret + +devread: + push ecx + call DEV9read8 + // stack already incremented + ret + +spuread: + push ecx + call SPU2read + // stack already incremented + ret + } +} + +int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + return psxHwConstRead8(x86reg, mem&0x1fffffff, sign); + +#ifdef _DEBUG + case 0x1d00: assert(0); +#endif + + case 0x1f40: + return psxHw4ConstRead8(x86reg, mem&0x1fffffff, sign); + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read8); + if( sign ) MOVSX32R8toR(x86reg, EAX); + else MOVZX32R8toR(x86reg, EAX); + return 0; + + default: + _eeReadConstMem8(x86reg, (u32)PSXM(mem), sign); + return 0; + } +} + +__declspec(naked) void psxRecMemRead16() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1f90 + je spuread + cmp dx, 0x1d00 + je sifread + cmp dx, 0x1000 + je devread + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead16 + add esp, 4 + ret + +sifread: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + + + mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] + + cmp dl, 0x40 + jne End + + // 0x40 + or eax, 2 + jmp End +Sif60: + xor eax, eax + jmp End + +spuread: + push ecx + call SPU2read + // stack already incremented + +End: + ret + +devread: + push ecx + call DEV9read16 + // stack already incremented + ret + } +} + +int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: return psxHwConstRead16(x86reg, mem&0x1fffffff, sign); + + case 0x1d00: + + switch(mem & 0xF0) + { + case 0x40: + _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xF240, sign); + OR32ItoR(x86reg, 0x0002); + break; + case 0x60: + XOR32RtoR(x86reg, x86reg); + break; + default: + _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0), sign); + break; + } + return 0; + + case 0x1f90: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)SPU2read); + if( sign ) MOVSX32R16toR(x86reg, EAX); + else MOVZX32R16toR(x86reg, EAX); + return 0; + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read16); + if( sign ) MOVSX32R16toR(x86reg, EAX); + else MOVZX32R16toR(x86reg, EAX); + return 0; + + default: + assert( g_psxWriteOk ); + _eeReadConstMem16(x86reg, (u32)PSXM(mem), sign); + return 0; + } + + return 0; +} + +__declspec(naked) void psxRecMemRead32() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1d00 + je sifread + cmp dx, 0x1000 + je devread + cmp ecx, 0x1ffe0130 + je WriteCtrlRead + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead32 + add esp, 4 + ret + +sifread: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + + // do the read from ps2 mem + mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] + + cmp dl, 0x40 + jne End + + // 0x40 + or eax, 0xf0000002 + jmp End +Sif60: + xor eax, eax +End: + ret + +devread: + push ecx + call DEV9read32 + // stack already incremented + ret + +WriteCtrlRead: + mov eax, writectrl + ret + } +} + +int psxRecMemConstRead32(u32 x86reg, u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: return psxHwConstRead32(x86reg, mem&0x1fffffff); + + case 0x1d00: + switch(mem & 0xF0) + { + case 0x40: + _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xF240); + OR32ItoR(x86reg, 0xf0000002); + break; + case 0x60: + XOR32RtoR(x86reg, x86reg); + break; + default: + _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0)); + break; + } + return 0; + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read32); + return 1; + + default: + if( mem == 0xfffe0130 ) + MOV32MtoR(x86reg, (uptr)&writectrl); + else { + XOR32RtoR(x86reg, x86reg); + CMP32ItoM((uptr)&g_psxWriteOk, 0); + CMOVNE32MtoR(x86reg, (u32)PSXM(mem)); + } + + return 0; + } +} + +__declspec(naked) void psxRecMemWrite8() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1f40 + je hw4write + cmp dx, 0x1000 + je devwrite + } + + ASSERT_WRITEOK + + __asm { +memwrite: + // rom writes, has to be PS2MEM_BASE_ + mov byte ptr [ecx+PS2MEM_BASE_], al + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite8 + add esp, 8 + ret + +hw4write: + push eax + push ecx + call psxHw4Write8 + add esp, 8 + ret + +devwrite: + push eax + push ecx + call DEV9write8 + // stack alwritey incremented + ret + } +} + +int psxRecMemConstWrite8(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + psxHwConstWrite8(mem&0x1fffffff, mmreg); + return 0; + case 0x1f40: + psxHw4ConstWrite8(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + assert(0); + _eeWriteConstMem8((u32)(PS2MEM_HW+0xf200+(mem&0xff)), mmreg); + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write8); + return 0; + + default: + _eeWriteConstMem8((u32)PSXM(mem), mmreg); + return 1; + } +} + +__declspec(naked) void psxRecMemWrite16() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1f90 + je spuwrite + cmp dx, 0x1d00 + je sifwrite + cmp dx, 0x1000 + je devwrite + cmp dx, 0x1600 + je ignorewrite + } + + ASSERT_WRITEOK + + __asm { +memwrite: + // rom writes, has to be PS2MEM_BASE_ + mov word ptr [ecx+PS2MEM_BASE_], ax + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite16 + add esp, 8 + ret + +sifwrite: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + cmp dl, 0x40 + je Sif40 + + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], ax + ret + +Sif40: + mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] + test ax, 0xa0 + jz Sif40_2 + // psHu16(0x1000F240) &= ~0xF000; + // psHu16(0x1000F240) |= 0x2000; + and bx, 0x0fff + or bx, 0x2000 + +Sif40_2: + // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + // else psHu16(0x1000F240) |= temp; + and ax, 0xf0 + test bx, ax + jz Sif40_3 + + not ax + and bx, ax + jmp Sif40_4 +Sif40_3: + or bx, ax +Sif40_4: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx + ret + +Sif60: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], 0 + ret + +spuwrite: + push eax + push ecx + call SPU2write + // stack alwritey incremented + ret + +devwrite: + push eax + push ecx + call DEV9write16 + // stack alwritey incremented + ret + +ignorewrite: + ret + } +} + +int psxRecMemConstWrite16(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1600: + //HACK: DEV9 VM crash fix + return 0; + case 0x1f80: + psxHwConstWrite16(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + _eeWriteConstMem16((u32)(PS2MEM_HW+0xf210), mmreg); + return 0; + case 0x40: + { + // delete x86reg + _eeMoveMMREGtoR(EAX, mmreg); + + assert( mmreg != EBX ); + MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); + TEST16ItoR(EAX, 0xa0); + j8Ptr[0] = JZ8(0); + + AND16ItoR(EBX, 0x0fff); + OR16ItoR(EBX, 0x2000); + + x86SetJ8(j8Ptr[0]); + + AND16ItoR(EAX, 0xf0); + TEST16RtoR(EAX, 0xf0); + j8Ptr[0] = JZ8(0); + + NOT32R(EAX); + AND16RtoR(EBX, EAX); + j8Ptr[1] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + OR16RtoR(EBX, EAX); + + x86SetJ8(j8Ptr[1]); + + MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); + + return 0; + } + case 0x60: + MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); + return 0; + default: + assert(0); + } + return 0; + + case 0x1f90: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)SPU2write); + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write16); + return 0; + + default: + _eeWriteConstMem16((u32)PSXM(mem), mmreg); + return 1; + } +} + +__declspec(naked) void psxRecMemWrite32() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1d00 + je sifwrite + cmp dx, 0x1000 + je devwrite + cmp dx, 0x1ffe + je WriteCtrl + } + + __asm { + // rom writes, has to be PS2MEM_BASE_ + test g_psxWriteOk, 1 + jz endwrite + +memwrite: + mov dword ptr [ecx+PS2MEM_BASE_], eax +endwrite: + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite32 + add esp, 8 + ret + +sifwrite: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + cmp dl, 0x40 + je Sif40 + cmp dl, 0x30 + je Sif30 + cmp dl, 0x20 + je Sif20 + + mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret + +Sif40: + mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] + test ax, 0xa0 + jz Sif40_2 + // psHu16(0x1000F240) &= ~0xF000; + // psHu16(0x1000F240) |= 0x2000; + and bx, 0x0fff + or bx, 0x2000 + +Sif40_2: + // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + // else psHu16(0x1000F240) |= temp; + and ax, 0xf0 + test bx, ax + jz Sif40_3 + + not ax + and bx, ax + jmp Sif40_4 +Sif40_3: + or bx, ax +Sif40_4: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx + ret + +Sif30: + or dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret +Sif20: + not eax + and dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret +Sif60: + mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], 0 + ret + +devwrite: + push eax + push ecx + call DEV9write32 + // stack alwritey incremented + ret + +WriteCtrl: + cmp ecx, 0x1ffe0130 + jne End + + mov writectrl, eax + + cmp eax, 0x800 + je SetWriteNotOk + cmp eax, 0x804 + je SetWriteNotOk + cmp eax, 0xc00 + je SetWriteNotOk + cmp eax, 0xc04 + je SetWriteNotOk + cmp eax, 0xcc0 + je SetWriteNotOk + cmp eax, 0xcc4 + je SetWriteNotOk + cmp eax, 0x0c4 + je SetWriteNotOk + + // test ok + cmp eax, 0x1e988 + je SetWriteOk + cmp eax, 0x1edd8 + je SetWriteOk + +End: + ret + +SetWriteNotOk: + mov g_psxWriteOk, 0 + ret +SetWriteOk: + mov g_psxWriteOk, 1 + ret + } +} + +int psxRecMemConstWrite32(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1f80: + psxHwConstWrite32(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + _eeWriteConstMem32((u32)PS2MEM_HW+0xf210, mmreg); + return 0; + case 0x20: + // write to ps2 mem + // delete x86reg + if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM((u32)PS2MEM_HW+0xf220, ~g_psxConstRegs[(mmreg>>16)&0x1f]); + } + else { + NOT32R(mmreg); + AND32RtoM((u32)PS2MEM_HW+0xf220, mmreg); + } + return 0; + case 0x30: + // write to ps2 mem + _eeWriteConstMem32OP((u32)PS2MEM_HW+0xf230, mmreg, 1); + return 0; + case 0x40: + { + // delete x86reg + assert( mmreg != EBX ); + + _eeMoveMMREGtoR(EAX, mmreg); + + MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); + TEST16ItoR(EAX, 0xa0); + j8Ptr[0] = JZ8(0); + + AND16ItoR(EBX, 0x0fff); + OR16ItoR(EBX, 0x2000); + + x86SetJ8(j8Ptr[0]); + + AND16ItoR(EAX, 0xf0); + TEST16RtoR(EAX, 0xf0); + j8Ptr[0] = JZ8(0); + + NOT32R(EAX); + AND16RtoR(EBX, EAX); + j8Ptr[1] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + OR16RtoR(EBX, EAX); + + x86SetJ8(j8Ptr[1]); + + MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); + + return 0; + } + case 0x60: + MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); + return 0; + default: + assert(0); + } + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write32); + return 0; + + case 0x1ffe: + if( mem == 0xfffe0130 ) { + u8* ptrs[9]; + + _eeWriteConstMem32((uptr)&writectrl, mmreg); + + if( IS_PSXCONSTREG(mmreg) ) { + switch (g_psxConstRegs[(mmreg>>16)&0x1f]) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + MOV32ItoM((uptr)&g_psxWriteOk, 0); + break; + case 0x1e988: + case 0x1edd8: + MOV32ItoM((uptr)&g_psxWriteOk, 1); + break; + default: + assert(0); + } + } + else { + // not ok + CMP32ItoR(mmreg, 0x800); + ptrs[0] = JE8(0); + CMP32ItoR(mmreg, 0x804); + ptrs[1] = JE8(0); + CMP32ItoR(mmreg, 0xc00); + ptrs[2] = JE8(0); + CMP32ItoR(mmreg, 0xc04); + ptrs[3] = JE8(0); + CMP32ItoR(mmreg, 0xcc0); + ptrs[4] = JE8(0); + CMP32ItoR(mmreg, 0xcc4); + ptrs[5] = JE8(0); + CMP32ItoR(mmreg, 0x0c4); + ptrs[6] = JE8(0); + + // ok + CMP32ItoR(mmreg, 0x1e988); + ptrs[7] = JE8(0); + CMP32ItoR(mmreg, 0x1edd8); + ptrs[8] = JE8(0); + + x86SetJ8(ptrs[0]); + x86SetJ8(ptrs[1]); + x86SetJ8(ptrs[2]); + x86SetJ8(ptrs[3]); + x86SetJ8(ptrs[4]); + x86SetJ8(ptrs[5]); + x86SetJ8(ptrs[6]); + MOV32ItoM((uptr)&g_psxWriteOk, 0); + ptrs[0] = JMP8(0); + + x86SetJ8(ptrs[7]); + x86SetJ8(ptrs[8]); + MOV32ItoM((uptr)&g_psxWriteOk, 1); + + x86SetJ8(ptrs[0]); + } + } + return 0; + + default: + TEST8ItoM((uptr)&g_psxWriteOk, 1); + j8Ptr[0] = JZ8(0); + _eeWriteConstMem32((u32)PSXM(mem), mmreg); + x86SetJ8(j8Ptr[0]); + return 1; + } +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp new file mode 100644 index 0000000000..0ba776fb01 --- /dev/null +++ b/pcsx2/x86/iR3000A.cpp @@ -0,0 +1,1530 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// recompiler reworked to add dynamic linking Jan06 +// and added reg caching, const propagation, block analysis Jun06 +// zerofrog(@gmail.com) +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +extern "C" { +#include +#include +#include +#include +#include + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#else +#include +#include +#endif + +#include "System.h" +#include "zlib.h" +#include "Memory.h" +#include "Misc.h" +#include "Vif.h" +#include "VU.h" + +#include "R3000A.h" +#include "PsxMem.h" + +#include "ix86/ix86.h" + +#include "iCore.h" +#include "iR3000A.h" +#include "PsxCounters.h" + +extern u32 psxNextCounter, psxNextsCounter; +u32 g_psxMaxRecMem = 0; +extern char *disRNameGPR[]; +extern char* disR3000Fasm(u32 code, u32 pc); + +void psxRecRecompile(u32 startpc); + +uptr *psxRecLUT; +} + + +#define PSX_NUMBLOCKS (1<<12) +#define MAPBASE 0x48000000 +#define RECMEM_SIZE (8*1024*1024) + +#define PSX_MEMMASK 0x5fffffff // mask when comparing two pcs + +// R3000A statics +int psxreclog = 0; + +static u32 s_BranchCount = 0; +static char *recMem; // the recompiled blocks will be here +static BASEBLOCK *recRAM; // and the ptr to the blocks here +static BASEBLOCK *recROM; // and here +static BASEBLOCK *recROM1; // also here +static BASEBLOCKEX *recBlocks = NULL; +static char *recPtr; +u32 psxpc; // recompiler psxpc +int psxbranch; // set for branch +static EEINST* s_pInstCache = NULL; +static u32 s_nInstCacheSize = 0; + +static BASEBLOCK* s_pCurBlock = NULL; +static BASEBLOCKEX* s_pCurBlockEx = NULL; +static BASEBLOCK* s_pDispatchBlock = NULL; +static u32 s_nEndBlock = 0; // what psxpc the current block ends + +static u32 s_nNextBlock = 0; // next free block in recBlocks + +static u32 s_ConstGPRreg; +static u32 s_saveConstGPRreg = 0, s_saveHasConstReg = 0, s_saveFlushedConstReg = 0; +static EEINST* s_psaveInstInfo = NULL; + +u32 s_psxBlockCycles = 0; // cycles of current block recompiling +static u32 s_savenBlockCycles = 0; + +static void iPsxBranchTest(u32 newpc, u32 cpuBranch); +void psxRecompileNextInstruction(int delayslot); + +extern void (*rpsxBSC[64])(); +extern void (*rpsxBSC_co[64])(); +void rpsxpropBSC(EEINST* prev, EEINST* pinst); + +#ifdef _DEBUG +extern "C" { +u32 psxdump = 0; +} +#else +#define psxdump 0 +#endif + +#define PSX_GETBLOCK(x) PC_GETBLOCK_(x, psxRecLUT) + +#define PSXREC_CLEARM(mem) { \ + if ((mem) < g_psxMaxRecMem && psxRecLUT[(mem) >> 16]) { \ + BASEBLOCK* p = PSX_GETBLOCK(mem); \ + if( *(u32*)p ) psxRecClearMem(p); \ + } \ +} \ + +BASEBLOCKEX* PSX_GETBLOCKEX(BASEBLOCK* p) +{ +// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); +// if( pex >= recBlocks && pex < recBlocks+PSX_NUMBLOCKS ) +// return pex; + + // otherwise, use the sorted list + return GetBaseBlockEx(p->startpc, 1); +} + +//////////////////////////////////////////////////// +static void iDumpBlock( int startpc, char * ptr ) +{ + FILE *f; + char filename[ 256 ]; +#ifdef __LINUX__ + char command[256]; +#endif + u32 i, j; + EEINST* pcur; + u8 used[34]; + int numused, count; + + SysPrintf( "dump1 %x:%x, %x\n", startpc, psxpc, psxRegs.cycle ); +#ifdef _WIN32 + CreateDirectory("dumps", NULL); +sprintf( filename, "dumps\\psxdump%.8X.txt", startpc); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/psxdump%.8X.txt", startpc); +#endif + + fflush( stdout ); + + f = fopen( filename, "w" ); + assert( f != NULL ); + for ( i = startpc; i < s_nEndBlock; i += 4 ) { + fprintf( f, "%s\n", disR3000Fasm( *(u32*)PSXM( i ), i ) ); + } + + // write the instruction info + fprintf(f, "\n\nlive0 - %x, lastuse - %x used - %x\n", EEINST_LIVE0, EEINST_LASTUSE, EEINST_USED); + + memset(used, 0, sizeof(used)); + numused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( s_pInstCache->regs[i] & EEINST_USED ) { + used[i] = 1; + numused++; + } + } + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%2d ", i); + } + fprintf(f, "\n"); + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); + } + fprintf(f, "\n"); + + pcur = s_pInstCache+1; + for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { + fprintf(f, "%2d: %2.2x ", i+1, pcur->info); + + count = 1; + for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { + if( used[j] ) { + fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&count tempdump", filename ); +#else + sprintf( command, "objdump -D --target=binary --architecture=i386 -M intel mydump1 | cat %s - > tempdump", filename ); +#endif + system( command ); + sprintf(command, "mv tempdump %s", filename); + system(command); + f = fopen( filename, "a+" ); +#endif +} + +u8 _psxLoadWritesRs(u32 tempcode) +{ + switch(tempcode>>26) { + case 32: case 33: case 34: case 35: case 36: case 37: case 38: + return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt + } + return 0; +} + +u8 _psxIsLoadStore(u32 tempcode) +{ + switch(tempcode>>26) { + case 32: case 33: case 34: case 35: case 36: case 37: case 38: + // 4 byte stores + case 40: case 41: case 42: case 43: case 46: + return 1; + } + return 0; +} + +void _psxFlushAllUnused() +{ + int i; + for(i = 0; i < 34; ++i) { + if( psxpc < s_nEndBlock ) { + if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) + continue; + } + else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) + continue; + + if( i < 32 && PSX_IS_CONST1(i) ) _psxFlushConstReg(i); + else { + _deleteX86reg(X86TYPE_PSX, i, 1); + } + } +} + +int _psxFlushUnusedConstReg() +{ + int i; + for(i = 1; i < 32; ++i) { + if( (g_psxHasConstReg & (1< 0 ); + + // make sure right GPR was saved + assert( g_psxHasConstReg == s_saveHasConstReg || (g_psxHasConstReg ^ s_saveHasConstReg) == (1<>26) == 9 ) { + //ADDIU, call bios + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); + _psxFlushCall(FLUSH_NODESTROY); + CALLFunc((uptr)zeroEx); + } +#endif + return; + } + + // for now, don't support xmm + PSX_CHECK_SAVE_REG(_Rt_); + + _deleteX86reg(X86TYPE_PSX, _Rs_, 1); + _deleteX86reg(X86TYPE_PSX, _Rt_, 0); + + if( PSX_IS_CONST1(_Rs_) ) { + PSX_SET_CONST(_Rt_); + constcode(); + return; + } + + noconstcode(0); + PSX_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + PSX_CHECK_SAVE_REG(_Rd_); + + _deleteX86reg(X86TYPE_PSX, _Rt_, 1); + _deleteX86reg(X86TYPE_PSX, _Rd_, 0); + + if( PSX_IS_CONST1(_Rt_) ) { + PSX_SET_CONST(_Rd_); + constcode(); + return; + } + + noconstcode(0); + PSX_DEL_CONST(_Rd_); +} + +// rd = rt MULT rs (SPECIAL) +void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI) +{ + _deleteX86reg(X86TYPE_PSX, _Rs_, 1); + _deleteX86reg(X86TYPE_PSX, _Rt_, 1); + + if( LOHI ) { + _deleteX86reg(X86TYPE_PSX, PSX_HI, 1); + _deleteX86reg(X86TYPE_PSX, PSX_LO, 1); + } + + if( PSX_IS_CONST2(_Rs_, _Rt_) ) { + constcode(); + return; + } + + if( PSX_IS_CONST1(_Rs_) ) { + constscode(0); + return; + } + + if( PSX_IS_CONST1(_Rt_) ) { + consttcode(0); + return; + } + + noconstcode(0); +} + +static int recInit() { + int i; + uptr startaddr; + + // can't have upper 4 bits nonzero! + startaddr = 0x0f000000; + while(!(startaddr & 0xf0000000)) { + recMem = (char*)SysMmap(startaddr, RECMEM_SIZE); + if( (uptr)recMem & 0xf0000000 ) { + SysMunmap((uptr)recMem, RECMEM_SIZE); recMem = NULL; + startaddr += 0x00100000; + continue; + } + else break; + } + + if( recMem == NULL ) { + SysPrintf("R3000A bad rec memory allocation\n"); + return 1; + } + + psxRecLUT = (uptr*) malloc(0x010000 * sizeof(uptr)); + memset(psxRecLUT, 0, 0x010000 * sizeof(uptr)); + + recRAM = (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x200000, 16); + recROM = (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x400000, 16); + recROM1= (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x040000, 16); + recBlocks = (BASEBLOCKEX*) _aligned_malloc( sizeof(BASEBLOCKEX)*PSX_NUMBLOCKS, 16); + if (recRAM == NULL || recROM == NULL || recROM1 == NULL || + recMem == NULL || psxRecLUT == NULL) { + SysMessage("Error allocating memory"); return -1; + } + + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + + for (i=0; i<0x80; i++) psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14]; + for (i=0; i<0x80; i++) psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14]; + for (i=0; i<0x80; i++) psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14]; + + for (i=0; i<0x40; i++) psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14]; + for (i=0; i<0x40; i++) psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14]; + for (i=0; i<0x40; i++) psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14]; + + for (i=0; i<0x40; i++) psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14]; + for (i=0; i<0x40; i++) psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14]; + for (i=0; i<0x40; i++) psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14]; + + memset(recMem, 0xcd, RECMEM_SIZE); + + return 0; +} + +static void recReset() { + memset(recRAM, 0, sizeof(BASEBLOCK)/4*0x200000); + memset(recROM, 0, sizeof(BASEBLOCK)/4*0x400000); + memset(recROM1,0, sizeof(BASEBLOCK)/4*0x040000); + + memset( recBlocks, 0, sizeof(BASEBLOCKEX)*PSX_NUMBLOCKS ); + if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + ResetBaseBlockEx(1); + g_psxMaxRecMem = 0; + + recPtr = recMem; + psxbranch = 0; +} + +static void recShutdown() { + if (recMem == NULL) return; + free(psxRecLUT); + SysMunmap((uptr)recMem, RECMEM_SIZE); + _aligned_free(recRAM); + _aligned_free(recROM); + _aligned_free(recROM1); + _aligned_free( recBlocks ); recBlocks = NULL; + free( s_pInstCache ); s_pInstCache = NULL; s_nInstCacheSize = 0; + + x86Shutdown(); +} + +#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code + +#if !defined(__x86_64__) +static u32 s_uSaveESP = 0; + +static void R3000AExecute() +{ +#ifdef _DEBUG + u8* fnptr; + u32 oldesi; +/*#else + R3000AFNPTR pfn;*/ +#endif + + BASEBLOCK* pblock; + + while (EEsCycle > 0) { + pblock = PSX_GETBLOCK(psxRegs.pc); + + if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { + psxRecRecompile(psxRegs.pc); + } + + assert( pblock->pFnptr != 0 ); + +#ifdef _DEBUG + + fnptr = (u8*)pblock->pFnptr; + +#ifdef _MSC_VER + + __asm { + // save data + mov oldesi, esi; + mov s_uSaveESP, esp; + sub s_uSaveESP, 8; + push ebp; + + call fnptr; // jump into function + // restore data + pop ebp; + mov esi, oldesi; + } + +#else // linux + + __asm__("movl %%esi, %0\n" + "movl %%esp, %1\n" + "sub $8, %%esp\n" + "push %%ebp\n" + "call *%2\n" + "pop %%ebp\n" + "movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) : ); +#endif // _MSC_VER + +#else + ((R3000AFNPTR)pblock->pFnptr)(); +#endif + } +} + +#else +extern "C" void R3000AExecute(); +#endif + +extern u32 g_psxNextBranchCycle; +u32 g_psxlastpc = 0; + +#if defined(_MSC_VER) && !defined(__x86_64__) + +static u32 g_temp; + +// jumped to when invalid psxpc address +__declspec(naked,noreturn) void psxDispatcher() +{ + // EDX contains the current psxpc to jump to, stack contains the jump addr to modify + __asm push edx + + // calc PSX_GETBLOCK + s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + + __asm { + mov eax, s_pDispatchBlock + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov ecx, psxRegs.pc + mov edx, [eax+BLOCKTYPE_STARTPC]; + and ecx, PSX_MEMMASK // remove higher bits + and edx, PSX_MEMMASK + cmp ecx, edx + je CheckPtr + + // recompile + push psxRegs.pc // psxpc + call psxRecRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock +CheckPtr: + mov eax, dword ptr [eax] + } + +#ifdef _DEBUG + __asm mov g_temp, eax + assert( g_temp ); +#endif + +// __asm { +// test eax, 0x40000000 // BLOCKTYPE_NEEDCLEAR +// jz Done +// // move new psxpc +// and eax, 0x0fffffff +// mov ecx, psxRegs.pc +// mov dword ptr [eax+1], ecx +// } + __asm { + and eax, 0x0fffffff + mov edx, eax + pop ecx // x86Ptr to mod + sub edx, ecx + sub edx, 4 + mov dword ptr [ecx], edx + + jmp eax + } +} + +__declspec(naked,noreturn) void psxDispatcherClear() +{ + // EDX contains the current psxpc + __asm mov psxRegs.pc, edx + __asm push edx + + // calc PSX_GETBLOCK + s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + + if( (s_pDispatchBlock->startpc&PSX_MEMMASK) == (psxRegs.pc&PSX_MEMMASK) ) { + assert( s_pDispatchBlock->pFnptr != 0 ); + + // already modded the code, jump to the new place + __asm { + pop edx + add esp, 4 // ignore stack + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + and eax, 0x0fffffff + jmp eax + } + } + + __asm { + call psxRecRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + + pop ecx // old fnptr + + and eax, 0x0fffffff + mov byte ptr [ecx], 0xe9 // jmp32 + mov edx, eax + sub edx, ecx + sub edx, 5 + mov dword ptr [ecx+1], edx + + jmp eax + } +} + +// called when jumping to variable psxpc address +__declspec(naked,noreturn) void psxDispatcherReg() +{ + __asm { + //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + mov edx, psxRegs.pc + mov ecx, edx + } + + __asm { + shr edx, 14 + and edx, 0xfffffffc + add edx, psxRecLUT + mov edx, dword ptr [edx] + + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // check if startpc == psxRegs.pc + mov eax, ecx + //and eax, 0x5fffffff // remove higher bits + cmp eax, dword ptr [edx+BLOCKTYPE_STARTPC] + jne recomp + + mov eax, dword ptr [edx] + } + +#ifdef _DEBUG + __asm mov g_temp, eax + assert( g_temp ); +#endif + + __asm { + and eax, 0x0fffffff + jmp eax // fnptr + +recomp: + sub esp, 8 + mov dword ptr [esp+4], edx + mov dword ptr [esp], ecx + call psxRecRecompile + mov edx, dword ptr [esp+4] + add esp, 8 + + mov eax, dword ptr [edx] + and eax, 0x0fffffff + jmp eax // fnptr + } +} + +#else // _MSC_VER + +#ifdef __cplusplus +extern "C" { +#endif + +void psxDispatcher(); +void psxDispatcherClear(); +void psxDispatcherReg(); + +#ifdef __cplusplus +} +#endif + +#endif // _MSC_VER + +static void recClear(u32 Addr, u32 Size) +{ + u32 i; + for(i = 0; i < Size; ++i, Addr+=4) { + PSXREC_CLEARM(Addr); + } +} + +#ifdef __x86_64__ +#define EE_MIN_BLOCK_BYTES 16 +#else +#define EE_MIN_BLOCK_BYTES 15 +#endif + +void rpsxMemConstClear(u32 mem) +{ + // NOTE! This assumes recLUT never changes its mapping + if( !psxRecLUT[mem>>16] ) + return; + + CMP32ItoM((uptr)PSX_GETBLOCK(mem), 0); + j8Ptr[6] = JE8(0); + + _callFunctionArg1((uptr)psxRecClearMem, MEM_CONSTTAG, (uptr)PSX_GETBLOCK(mem)); + x86SetJ8(j8Ptr[6]); +} + +void psxRecClearMem(BASEBLOCK* p) +{ + BASEBLOCKEX* pexblock; + BASEBLOCK* pstart; + int lastdelay; + + assert( p != NULL ); + + if( p->uType & BLOCKTYPE_DELAYSLOT ) { + psxRecClearMem(p-1); + if( p->pFnptr == 0 ) + return; + } + + assert( p->pFnptr != 0 ); + assert( p->startpc ); + + x86Ptr = (s8*)p->pFnptr; + + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, p->startpc); + assert( (uptr)x86Ptr <= 0xffffffff ); +#ifdef __x86_64__ + MOV32ItoR(R15, (uptr)x86Ptr); // will be replaced by JMP32 +#else + PUSH32I((uptr)x86Ptr); +#endif + JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr + 5 )); + assert( x86Ptr == (s8*)p->pFnptr + EE_MIN_BLOCK_BYTES ); + + pstart = PSX_GETBLOCK(p->startpc); + pexblock = PSX_GETBLOCKEX(pstart); + assert( pexblock->startpc == pstart->startpc ); + +// if( pexblock->pOldFnptr ) { +// // have to mod oldfnptr too +// x86Ptr = pexblock->pOldFnptr; +// +// MOV32ItoR(EDX, p->startpc); +// JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr + 5 )); +// } +// else +// pexblock->pOldFnptr = (u8*)p->pFnptr; + + // don't delete if last is delay + lastdelay = pexblock->size; + if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { + assert( pstart[pexblock->size-1].pFnptr != pstart->pFnptr ); + if( pstart[pexblock->size-1].pFnptr != 0 ) { + pstart[pexblock->size-1].uType = 0; + --lastdelay; + } + } + + memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + + RemoveBaseBlockEx(pexblock, 1); + pexblock->size = 0; + pexblock->startpc = 0; +} + +void psxSetBranchReg(u32 reg) +{ + psxbranch = 1; + + if( reg != 0xffffffff ) { + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _psxMoveGPRtoR(ESI, reg); + + psxRecompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((uptr)&psxRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (uptr)&g_recWriteback); + MOV32RtoM((uptr)&psxRegs.pc, EAX); + } + } + + _psxFlushCall(FLUSH_EVERYTHING); + iPsxBranchTest(0xffffffff, 1); + + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); +} + +void psxSetBranchImm( u32 imm ) +{ + u32* ptr; + psxbranch = 1; + assert( imm ); + + // end the current block + MOV32ItoM( (uptr)&psxRegs.pc, imm ); + _psxFlushCall(FLUSH_EVERYTHING); + iPsxBranchTest(imm, imm <= psxpc); + + MOV32ItoR(EDX, 0); + ptr = (u32*)(x86Ptr-4); + *ptr = (uptr)JMP32((uptr)psxDispatcher - ( (uptr)x86Ptr + 5 )); +} + +#define USE_FAST_BRANCHES (Config.Hacks & 1) +#define PSXCYCLE_MULT ((Config.Hacks & 1) ? 2.125 : (17/16)) + +static void iPsxBranchTest(u32 newpc, u32 cpuBranch) +{ + if( !USE_FAST_BRANCHES || cpuBranch ) { + MOV32MtoR(ECX, (uptr)&psxRegs.cycle); + ADD32ItoR(ECX, s_psxBlockCycles*PSXCYCLE_MULT); // greater mult factor causes nfsmw to crash + MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles + } + else { + ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles*PSXCYCLE_MULT); + return; + } + + SUB32MtoR(ECX, (uptr)&g_psxNextBranchCycle); + + // check if should branch + j8Ptr[0] = JS8( 0 ); + + CALLFunc((uptr)psxBranchTest); + + CMP32ItoM((uptr)&EEsCycle, 0); + j8Ptr[2] = JG8(0); + if( REC_INC_STACK ) + ADD64ItoR(ESP, REC_INC_STACK); + RET2(); + x86SetJ8( j8Ptr[2] ); + + if( newpc != 0xffffffff ) { + CMP32ItoM((uptr)&psxRegs.pc, newpc); + JNE32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 6 )); + } + + x86SetJ8( j8Ptr[0] ); +} + +static int *s_pCode; + +#if !defined(_MSC_VER) || !defined(__x86_64__) +static void checkcodefn() +{ + int pctemp; + +#ifdef _MSC_VER + __asm mov pctemp, eax; +#else + __asm__("movl %%eax, %0" : : "m"(pctemp) ); +#endif + SysPrintf("iop code changed! %x\n", pctemp); +} +#endif + +void rpsxSYSCALL() +{ + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); + _psxFlushCall(FLUSH_NODESTROY); + + _callFunctionArg2((uptr)psxException, MEM_CONSTTAG, MEM_CONSTTAG, 0x20, psxbranch==1); + + CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles); + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + + //if (!psxbranch) psxbranch = 2; +} + +extern "C" void psxBREAK(); +void rpsxBREAK() +{ + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); + _psxFlushCall(FLUSH_NODESTROY); + + _callFunctionArg2((uptr)psxBREAK, MEM_CONSTTAG, MEM_CONSTTAG, 0x24, psxbranch==1); + + CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles); + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + + //if (!psxbranch) psxbranch = 2; +} + +u32 psxRecompileCodeSafe(u32 temppc) +{ + BASEBLOCK* pblock = PSX_GETBLOCK(temppc); + + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( psxpc == pblock->startpc ) + return 0; + } + + return 1; +} + +void psxRecompileNextInstruction(int delayslot) +{ + static u8 s_bFlushReg = 1; + + BASEBLOCK* pblock = PSX_GETBLOCK(psxpc); + + // need *ppblock != s_pCurBlock because of branches + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( !delayslot && psxpc == pblock->startpc ) { + // code already in place, so jump to it and exit recomp + assert( PSX_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + + _psxFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&psxRegs.pc, psxpc); + +// if( pexblock->pOldFnptr ) { +// // code already in place, so jump to it and exit recomp +// JMP32((uptr)pexblock->pOldFnptr - ((uptr)x86Ptr + 5)); +// branch = 3; +// return; +// } + + JMP32((uptr)pblock->pFnptr - ((uptr)x86Ptr + 5)); + psxbranch = 3; + return; + } + else { + + if( !(delayslot && pblock->startpc == psxpc) ) { + s8* oldX86 = x86Ptr; + //__Log("clear block %x\n", pblock->startpc); + psxRecClearMem(pblock); + x86Ptr = oldX86; + if( delayslot ) + SysPrintf("delay slot %x\n", psxpc); + } + } + } + + if( delayslot ) + pblock->uType = BLOCKTYPE_DELAYSLOT; + +#ifdef _DEBUG + MOV32ItoR(EAX, psxpc); +#endif + + s_pCode = (int *)PSXM( psxpc ); + assert(s_pCode); + + psxRegs.code = *(int *)s_pCode; + s_psxBlockCycles++; + psxpc += 4; + +//#ifdef _DEBUG +// CMP32ItoM((uptr)s_pCode, psxRegs.code); +// j8Ptr[0] = JE8(0); +// MOV32ItoR(EAX, psxpc); +// CALLFunc((uptr)checkcodefn); +// x86SetJ8( j8Ptr[ 0 ] ); +//#endif + + + g_pCurInstInfo++; + + // peephole optimizations + if( g_pCurInstInfo->info & EEINSTINFO_COREC ) { + assert(0); +// recBSC_co[cpuRegs.code>>26](); +// psxpc += 4; +// s_psxBlockCycles++; +// g_pCurInstInfo++; + } + else { + assert( !(g_pCurInstInfo->info & EEINSTINFO_NOREC) ); + rpsxBSC[ psxRegs.code >> 26 ](); + } + + if( !delayslot ) { + if( s_bFlushReg ) { + //_psxFlushUnusedConstReg(); + } + else s_bFlushReg = 1; + } + else s_bFlushReg = 1; + + _clearNeededX86regs(); +} + +static void recExecute() { + for (;;) R3000AExecute(); +} + +static void recExecuteBlock() { + R3000AExecute(); +} + +#include "PsxHw.h" + +extern "C" +void iDumpPsxRegisters(u32 startpc, u32 temp) +{ + int i; + const char* pstr = temp ? "t" : ""; + + __Log("%spsxreg: %x %x ra:%x k0: %x %x\n", pstr, startpc, psxRegs.cycle, psxRegs.GPR.n.ra, psxRegs.GPR.n.k0, *(int*)PSXM(0x13c128)); + for(i = 0; i < 34; i+=2) __Log("%spsx%s: %x %x\n", pstr, disRNameGPR[i], psxRegs.GPR.r[i], psxRegs.GPR.r[i+1]); + __Log("%scycle: %x %x %x %x; counters %x %x\n", pstr, psxRegs.cycle, g_psxNextBranchCycle, EEsCycle, IOPoCycle, + (uptr)psxNextsCounter, (uptr)psxNextCounter); + + __Log("psxdma%d c%x b%x m%x t%x\n", 2, HW_DMA2_CHCR, HW_DMA2_BCR, HW_DMA2_MADR, HW_DMA2_TADR); + __Log("psxdma%d c%x b%x m%x\n", 3, HW_DMA3_CHCR, HW_DMA3_BCR, HW_DMA3_MADR); + __Log("psxdma%d c%x b%x m%x t%x\n", 4, HW_DMA4_CHCR, HW_DMA4_BCR, HW_DMA4_MADR, HW_DMA4_TADR); + __Log("psxdma%d c%x b%x m%x\n", 6, HW_DMA6_CHCR, HW_DMA6_BCR, HW_DMA6_MADR); + __Log("psxdma%d c%x b%x m%x\n", 7, HW_DMA7_CHCR, HW_DMA7_BCR, HW_DMA7_MADR); + __Log("psxdma%d c%x b%x m%x\n", 8, HW_DMA8_CHCR, HW_DMA8_BCR, HW_DMA8_MADR); + __Log("psxdma%d c%x b%x m%x t%x\n", 9, HW_DMA9_CHCR, HW_DMA9_BCR, HW_DMA9_MADR, HW_DMA9_TADR); + __Log("psxdma%d c%x b%x m%x\n", 10, HW_DMA10_CHCR, HW_DMA10_BCR, HW_DMA10_MADR); + __Log("psxdma%d c%x b%x m%x\n", 11, HW_DMA11_CHCR, HW_DMA11_BCR, HW_DMA11_MADR); + __Log("psxdma%d c%x b%x m%x\n", 12, HW_DMA12_CHCR, HW_DMA12_BCR, HW_DMA12_MADR); + for(i = 0; i < 7; ++i) __Log("%scounter%d: mode %x count %I64x rate %x scycle %x target %I64x\n", pstr, i, psxCounters[i].mode, psxCounters[i].count, psxCounters[i].rate, psxCounters[i].sCycleT, psxCounters[i].target); +// for(i = 0; i < 32; ++i) { +// __Log("int%d: %x %x\n", i, psxRegs.sCycle[i], psxRegs.eCycle[i]); +// } +} + +void iDumpPsxRegisters(u32 startpc); + +static void printfn() +{ + static int lastrec = 0; + static int curcount = 0; + const int skip = 0; + + //*(int*)PSXM(0x27990) = 1; // enables cdvd bios output for scph10000 + + if( psxRegs.cycle == 0x113a1be5 ) { +// FILE* tempf = fopen("tempdmciop.txt", "wb"); +// fwrite(PSXM(0), 0x200000, 1, tempf); +// fclose(tempf); + //psxdump |= 2; + } + +// if( psxRegs.cycle == 0x114152d8 ) { +// psxRegs.GPR.n.s0 = 0x55000; +// } + + if( (psxdump&2) && lastrec != g_psxlastpc ) { + curcount++; + + if( curcount > skip ) { + iDumpPsxRegisters(g_psxlastpc, 1); + curcount = 0; + } + + lastrec = g_psxlastpc; + } +} + +u32 s_psxrecblocks[] = {0}; + +void psxRecRecompile(u32 startpc) +{ + u32 i; + u32 branchTo; + u32 willbranch3 = 0; + u32* ptr; + +#ifdef _DEBUG + //psxdump |= 4; + if( psxdump & 4 ) + iDumpPsxRegisters(startpc, 0); +#endif + + assert( startpc ); + + // if recPtr reached the mem limit reset whole mem + if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) + recReset(); + + s_pCurBlock = PSX_GETBLOCK(startpc); + + if( s_pCurBlock->pFnptr ) { + // clear if already taken + assert( s_pCurBlock->startpc < startpc ); + psxRecClearMem(s_pCurBlock); + } + + if( s_pCurBlock->startpc == startpc ) { + s_pCurBlockEx = PSX_GETBLOCKEX(s_pCurBlock); + assert( s_pCurBlockEx->startpc == startpc ); + } + else { + s_pCurBlockEx = NULL; + for(i = 0; i < PSX_NUMBLOCKS; ++i) { + if( recBlocks[(i+s_nNextBlock)%PSX_NUMBLOCKS].size == 0 ) { + s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%PSX_NUMBLOCKS; + s_nNextBlock = (i+s_nNextBlock+1)%PSX_NUMBLOCKS; + break; + } + } + + if( s_pCurBlockEx == NULL ) { + //SysPrintf("ee reset (blocks)\n"); + recReset(); + s_nNextBlock = 0; + s_pCurBlockEx = recBlocks; + } + + s_pCurBlockEx->startpc = startpc; + } + + x86SetPtr( recPtr ); + x86Align(16); + recPtr = x86Ptr; + + psxbranch = 0; + + s_pCurBlock->startpc = startpc; + s_pCurBlock->pFnptr = (u32)(uptr)x86Ptr; + s_psxBlockCycles = 0; + + // reset recomp state variables + psxpc = startpc; + s_saveConstGPRreg = 0; + g_psxHasConstReg = g_psxFlushedConstReg = 1; + + _initX86regs(); + +#ifdef _DEBUG + // for debugging purposes + MOV32ItoM((uptr)&g_psxlastpc, psxpc); + CALLFunc((uptr)printfn); +#endif + + // go until the next branch + i = startpc; + s_nEndBlock = 0xffffffff; + + while(1) { + BASEBLOCK* pblock = PSX_GETBLOCK(i); + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( i == pblock->startpc ) { + // branch = 3 + willbranch3 = 1; + s_nEndBlock = i; + break; + } + } + + psxRegs.code = *(int *)PSXM(i); + + switch(psxRegs.code >> 26) { + case 0: // special + + if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR + s_nEndBlock = i + 8; + goto StartRecomp; + } + + break; + case 1: // regimm + + if( _Rt_ == 0 || _Rt_ == 1 || _Rt_ == 16 || _Rt_ == 17 ) { + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + break; + + case 2: // J + case 3: // JAL + s_nEndBlock = i + 8; + goto StartRecomp; + + // branches + case 4: case 5: case 6: case 7: + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + i += 4; + } + +StartRecomp: + + // rec info // + { + EEINST* pcur; + + if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { + free(s_pInstCache); + s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; + s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); + assert( s_pInstCache != NULL ); + } + + pcur = s_pInstCache + (s_nEndBlock-startpc)/4; + _recClearInst(pcur); + pcur->info = 0; + + for(i = s_nEndBlock; i > startpc; i -= 4 ) { + psxRegs.code = *(int *)PSXM(i-4); + pcur[-1] = pcur[0]; + rpsxpropBSC(pcur-1, pcur); + pcur--; + } + } + + // peephole optimizations // +// { +// g_pCurInstInfo = s_pInstCache; +// +// for(i = startpc; i < s_nEndBlock-4; i += 4) { +// g_pCurInstInfo++; +// if( psxRecompileCodeSafe(i) ) { +// u32 curcode = *(u32*)PSXM(i); +// u32 nextcode = *(u32*)PSXM(i+4); +// if( _psxIsLoadStore(curcode) && _psxIsLoadStore(nextcode) && (curcode>>26) == (nextcode>>26) && rpsxBSC_co[curcode>>26] != NULL ) { +// +// // rs has to be the same, and cannot be just written +// if( ((curcode >> 21) & 0x1F) == ((nextcode >> 21) & 0x1F) && !_psxLoadWritesRs(curcode) ) { +// +// // good enough +// g_pCurInstInfo[0].info |= EEINSTINFO_COREC; +// g_pCurInstInfo[0].numpeeps = 1; +// g_pCurInstInfo[1].info |= EEINSTINFO_NOREC; +// g_pCurInstInfo++; +// i += 4; +// continue; +// } +// } +// } +// } +// } + +#ifdef _DEBUG + // dump code + for(i = 0; i < ARRAYSIZE(s_psxrecblocks); ++i) { + if( startpc == s_psxrecblocks[i] ) { + iDumpBlock(startpc, recPtr); + } + } + + if( (psxdump & 1) ) + iDumpBlock(startpc, recPtr); +#endif + + g_pCurInstInfo = s_pInstCache; + while (!psxbranch && psxpc < s_nEndBlock) { + psxRecompileNextInstruction(0); + } + +#ifdef _DEBUG + if( (psxdump & 1) ) + iDumpBlock(startpc, recPtr); +#endif + + assert( (psxpc-startpc)>>2 <= 0xffff ); + s_pCurBlockEx->size = (psxpc-startpc)>>2; + + for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // don't overwrite if delay slot + if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // set the block ptr + AddBaseBlockEx(s_pCurBlockEx, 1); + + if( !(psxpc&0x10000000) ) + g_psxMaxRecMem = max( (psxpc&~0xa0000000), g_psxMaxRecMem ); + + if( psxbranch == 2 ) { + _psxFlushCall(FLUSH_EVERYTHING); + + iPsxBranchTest(0xffffffff, 1); + + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + } + else { + assert( psxbranch != 3 ); + if( psxbranch ) assert( !willbranch3 ); + else ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles*PSXCYCLE_MULT); + + if( willbranch3 ) { + BASEBLOCK* pblock = PSX_GETBLOCK(s_nEndBlock); + assert( psxpc == s_nEndBlock ); + _psxFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&psxRegs.pc, psxpc); + JMP32((uptr)pblock->pFnptr - ((uptr)x86Ptr + 5)); + psxbranch = 3; + } + else if( !psxbranch ) { + // didn't branch, but had to stop + MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); + + _psxFlushCall(FLUSH_EVERYTHING); + + ptr = JMP32(0); + //JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + } + } + + assert( x86Ptr >= (s8*)s_pCurBlock->pFnptr + EE_MIN_BLOCK_BYTES ); + assert( x86Ptr < recMem+RECMEM_SIZE ); + + recPtr = x86Ptr; + + assert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); + + if( !psxbranch ) { + BASEBLOCK* pcurblock = s_pCurBlock; + u32 nEndBlock = s_nEndBlock; + s_pCurBlock = PSX_GETBLOCK(psxpc); + assert( ptr != NULL ); + + if( s_pCurBlock->startpc != psxpc ) + psxRecRecompile(psxpc); + + // could have reset + if( pcurblock->startpc == startpc ) { + assert( pcurblock->pFnptr ); + assert( s_pCurBlock->startpc == nEndBlock ); + *ptr = (u32)((uptr)s_pCurBlock->pFnptr - ( (uptr)ptr + 4 )); + } + else { + psxRecRecompile(startpc); + assert( pcurblock->pFnptr != 0 ); + } + } + else + assert( s_pCurBlock->pFnptr != 0 ); +} + +R3000Acpu psxRec = { + recInit, + recReset, + recExecute, + recExecuteBlock, + recClear, + recShutdown +}; + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iR3000A.h b/pcsx2/x86/iR3000A.h new file mode 100644 index 0000000000..9cb8ef1a40 --- /dev/null +++ b/pcsx2/x86/iR3000A.h @@ -0,0 +1,99 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _R3000A_SUPERREC_ +#define _R3000A_SUPERREC_ + +extern void __Log(char *fmt, ...); + +// to be consistent with EE +#define PSX_HI XMMGPR_HI +#define PSX_LO XMMGPR_LO + +extern uptr *psxRecLUT; + +u8 _psxLoadWritesRs(u32 tempcode); +u8 _psxIsLoadStore(u32 tempcode); + +void _psxFlushAllUnused(); +int _psxFlushUnusedConstReg(); +void _psxFlushCachedRegs(); +void _psxFlushConstReg(int reg); +void _psxFlushConstRegs(); + +void _psxDeleteReg(int reg, int flush); +void _psxFlushCall(int flushtype); + +void _psxOnWriteReg(int reg); +void PSX_CHECK_SAVE_REG(int reg); + +extern u32 psxpc; // recompiler pc +extern int psxbranch; // set for branch + +void psxSaveBranchState(); +void psxLoadBranchState(); + +void psxSetBranchReg(u32 reg); +void psxSetBranchImm( u32 imm ); +void psxRecompileNextInstruction(int delayslot); + +typedef void (*R3000AFNPTR)(); +typedef void (*R3000AFNPTR_INFO)(int info); + +void psxRecClearMem(BASEBLOCK* p); + +// +// non mmx/xmm version, slower +// +// rd = rs op rt +#define PSXRECOMPILE_CONSTCODE0(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst0(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_); \ +} \ + +// rt = rs op imm16 +#define PSXRECOMPILE_CONSTCODE1(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst1(rpsx##fn##_const, rpsx##fn##_); \ +} \ + +// rd = rt op sa +#define PSXRECOMPILE_CONSTCODE2(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst2(rpsx##fn##_const, rpsx##fn##_); \ +} \ + +// [lo,hi] = rt op rs +#define PSXRECOMPILE_CONSTCODE3(fn, LOHI) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst3(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_, LOHI); \ +} \ + +// rd = rs op rt +void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode); +// rt = rs op imm16 +void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); +// rd = rt op sa +void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); +// [lo,hi] = rt op rs +void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI); + +#endif diff --git a/pcsx2/x86/iR3000Atables.cpp b/pcsx2/x86/iR3000Atables.cpp new file mode 100644 index 0000000000..7bea96d1c3 --- /dev/null +++ b/pcsx2/x86/iR3000Atables.cpp @@ -0,0 +1,2053 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +extern "C" { +#include +#include +#include +#include +#include + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#endif + +#include "System.h" +#include "Memory.h" +#include "Misc.h" +#include "Vif.h" +#include "VU.h" + +#include "R3000A.h" +#include "PsxMem.h" + +#include "ix86/ix86.h" + +#include "iCore.h" +#include "iR3000A.h" + +extern void psxLWL(); +extern void psxLWR(); +extern void psxSWL(); +extern void psxSWR(); + +extern int g_psxWriteOk; +extern u32 g_psxMaxRecMem; +} + +// R3000A instruction implementation +#define REC_FUNC(f) \ +void psx##f(); \ +static void rpsx##f() { \ + MOV32ItoM((uptr)&psxRegs.code, (u32)psxRegs.code); \ + _psxFlushCall(FLUSH_EVERYTHING); \ + /*MOV32ItoM((u32)&psxRegs.pc, (u32)pc);*/ \ + CALLFunc((uptr)psx##f); \ + PSX_DEL_CONST(_Rt_); \ +/* branch = 2; */\ +} + +//// +void rpsxADDIU_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] + _Imm_; +} + +// adds a constant to sreg and puts into dreg +void rpsxADDconst(int dreg, int sreg, u32 off, int info) +{ + if (sreg) { + if (sreg == dreg) { + ADD32ItoM((uptr)&psxRegs.GPR.r[dreg], off); + } else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + if (off) ADD32ItoR(EAX, off); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], off); + } +} + +void rpsxADDIU_(int info) +{ + // Rt = Rs + Im + if (!_Rt_) return; + rpsxADDconst(_Rt_, _Rs_, _Imm_, info); +} + +PSXRECOMPILE_CONSTCODE1(ADDIU); + +void rpsxADDI() { rpsxADDIU(); } + +//// SLTI +void rpsxSLTI_const() +{ + g_psxConstRegs[_Rt_] = *(int*)&g_psxConstRegs[_Rs_] < _Imm_; +} + +void rpsxSLTconst(int info, int dreg, int sreg, int imm) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); + SETL8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); +} + +void rpsxSLTI_(int info) { rpsxSLTconst(info, _Rt_, _Rs_, _Imm_); } + +PSXRECOMPILE_CONSTCODE1(SLTI); + +//// SLTIU +void rpsxSLTIU_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] < _ImmU_; +} + +void rpsxSLTUconst(int info, int dreg, int sreg, int imm) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); + SETB8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); +} + +void rpsxSLTIU_(int info) { rpsxSLTUconst(info, _Rt_, _Rs_, (s32)_Imm_); } + +PSXRECOMPILE_CONSTCODE1(SLTIU); + +//// ANDI +void rpsxANDI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] & _ImmU_; +} + +void rpsxANDconst(int info, int dreg, int sreg, u32 imm) +{ + if (imm) { + if (sreg == dreg) { + AND32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + AND32ItoR(EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } else { + MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], 0); + } +} + +void rpsxANDI_(int info) { rpsxANDconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(ANDI); + +//// ORI +void rpsxORI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] | _ImmU_; +} + +void rpsxORconst(int info, int dreg, int sreg, u32 imm) +{ + if (imm) { + if (sreg == dreg) { + OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + OR32ItoR (EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + if( dreg != sreg ) { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxORI_(int info) { rpsxORconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(ORI); + +void rpsxXORI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] ^ _ImmU_; +} + +void rpsxXORconst(int info, int dreg, int sreg, u32 imm) +{ + if( imm == 0xffffffff ) { + if( dreg == sreg ) { + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } + else if (imm) { + + if (sreg == dreg) { + XOR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + XOR32ItoR(EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + if( dreg != sreg ) { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxXORI_(int info) { rpsxXORconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(XORI); + +void rpsxLUI() +{ + if(!_Rt_) return; + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + PSX_SET_CONST(_Rt_); + g_psxConstRegs[_Rt_] = psxRegs.code << 16; +} + +void rpsxADDU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] + g_psxConstRegs[_Rt_]; +} + +void rpsxADDU_consts(int info) { rpsxADDconst(_Rd_, _Rt_, g_psxConstRegs[_Rs_], info); } +void rpsxADDU_constt(int info) +{ + info |= PROCESS_EE_SET_S(EEREC_T); + rpsxADDconst(_Rd_, _Rs_, g_psxConstRegs[_Rt_], info); +} + +void rpsxADDU_(int info) +{ + if (_Rs_ && _Rt_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + ADD32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + } else if (_Rs_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + } else if (_Rt_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + } else { + XOR32RtoR(EAX, EAX); + } + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(ADDU); + +void rpsxADD() { rpsxADDU(); } + + +void rpsxSUBU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] - g_psxConstRegs[_Rt_]; +} + +void rpsxSUBU_consts(int info) +{ + MOV32ItoR(EAX, g_psxConstRegs[_Rs_]); + SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSUBU_constt(int info) { rpsxADDconst(_Rd_, _Rs_, -(int)g_psxConstRegs[_Rt_], info); } + +void rpsxSUBU_(int info) +{ + // Rd = Rs - Rt + if (!_Rd_) return; + + if( _Rd_ == _Rs_ ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SUB32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); + } +} + +PSXRECOMPILE_CONSTCODE0(SUBU); + +void rpsxSUB() { rpsxSUBU(); } + +void rpsxLogicalOp(int info, int op) +{ + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[vreg]); + LogicalOp32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX, op); + if( op == 3 ) + NOT32M((uptr)&psxRegs.GPR.r[_Rd_]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + LogicalOp32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_], op); + if( op == 3 ) + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX); + } +} + +void rpsxAND_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] & g_psxConstRegs[_Rt_]; +} + +void rpsxAND_consts(int info) { rpsxANDconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxAND_constt(int info) { rpsxANDconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxAND_(int info) { rpsxLogicalOp(info, 0); } + +PSXRECOMPILE_CONSTCODE0(AND); + +void rpsxOR_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]; +} + +void rpsxOR_consts(int info) { rpsxORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxOR_constt(int info) { rpsxORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxOR_(int info) { rpsxLogicalOp(info, 1); } + +PSXRECOMPILE_CONSTCODE0(OR); + +//// XOR +void rpsxXOR_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] ^ g_psxConstRegs[_Rt_]; +} + +void rpsxXOR_consts(int info) { rpsxXORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxXOR_constt(int info) { rpsxXORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxXOR_(int info) { rpsxLogicalOp(info, 2); } + +PSXRECOMPILE_CONSTCODE0(XOR); + +//// NOR +void rpsxNOR_const() +{ + g_psxConstRegs[_Rd_] = ~(g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]); +} + +void rpsxNORconst(int info, int dreg, int sreg, u32 imm) +{ + if( imm ) { + if( dreg == sreg ) { + OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + OR32ItoR(ECX, imm); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } + else { + if( dreg == sreg ) { + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxNOR_consts(int info) { rpsxNORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxNOR_constt(int info) { rpsxNORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxNOR_(int info) { rpsxLogicalOp(info, 3); } + +PSXRECOMPILE_CONSTCODE0(NOR); + +//// SLT +void rpsxSLT_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rs_] < *(int*)&g_psxConstRegs[_Rt_]; +} + +void rpsxSLT_consts(int info) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); + SETG8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLT_constt(int info) { rpsxSLTconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxSLT_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SETL8R (EAX); + AND32ItoR(EAX, 0xff); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLT); + +//// SLTU +void rpsxSLTU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] < g_psxConstRegs[_Rt_]; +} + +void rpsxSLTU_consts(int info) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); + SETA8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLTU_constt(int info) { rpsxSLTUconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxSLTU_(int info) +{ + // Rd = Rs < Rt (unsigned) + if (!_Rd_) return; + + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SBB32RtoR(EAX, EAX); + NEG32R (EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLTU); + +//// MULT +void rpsxMULT_const() +{ + u64 res = (s64)((s64)*(int*)&g_psxConstRegs[_Rs_] * (s64)*(int*)&g_psxConstRegs[_Rt_]); + + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); +} + +void rpsxMULTsuperconst(int info, int sreg, int imm, int sign) +{ + // Lo/Hi = Rs * Rt (signed) + MOV32ItoR(EAX, imm); + if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[sreg]); + else MUL32M ((uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); +} + +void rpsxMULTsuper(int info, int sign) +{ + // Lo/Hi = Rs * Rt (signed) + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); + else MUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); +} + +void rpsxMULT_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 1); } +void rpsxMULT_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 1); } +void rpsxMULT_(int info) { rpsxMULTsuper(info, 1); } + +PSXRECOMPILE_CONSTCODE3(MULT, 1); + +//// MULTU +void rpsxMULTU_const() +{ + u64 res = (u64)((u64)g_psxConstRegs[_Rs_] * (u64)g_psxConstRegs[_Rt_]); + + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); +} + +void rpsxMULTU_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 0); } +void rpsxMULTU_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 0); } +void rpsxMULTU_(int info) { rpsxMULTsuper(info, 0); } + +PSXRECOMPILE_CONSTCODE3(MULTU, 1); + +//// DIV +void rpsxDIV_const() +{ + u32 lo, hi; + + if (g_psxConstRegs[_Rt_] != 0) { + lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_]; + hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_]; + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); + } +} + +void rpsxDIVsuperconsts(int info, int sign) +{ + u32 imm = g_psxConstRegs[_Rs_]; + + if( imm ) { + // Lo/Hi = Rs / Rt (signed) + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); + CMP32ItoR(ECX, 0); + j8Ptr[0] = JE8(0); + MOV32ItoR(EAX, imm); + + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + x86SetJ8(j8Ptr[0]); + } + else { + XOR32RtoR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + } +} + +void rpsxDIVsuperconstt(int info, int sign) +{ + u32 imm = g_psxConstRegs[_Rt_]; + + if( imm ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32ItoR(ECX, imm); + //CDQ(); + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + } +} + +void rpsxDIVsuper(int info, int sign) +{ + // Lo/Hi = Rs / Rt (signed) + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); + CMP32ItoR(ECX, 0); + j8Ptr[0] = JE8(0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + x86SetJ8(j8Ptr[0]); +} + +void rpsxDIV_consts(int info) { rpsxDIVsuperconsts(info, 1); } +void rpsxDIV_constt(int info) { rpsxDIVsuperconstt(info, 1); } +void rpsxDIV_(int info) { rpsxDIVsuper(info, 1); } + +PSXRECOMPILE_CONSTCODE3(DIV, 1); + +//// DIVU +void rpsxDIVU_const() +{ + u32 lo, hi; + + if (g_psxConstRegs[_Rt_] != 0) { + lo = g_psxConstRegs[_Rs_] / g_psxConstRegs[_Rt_]; + hi = g_psxConstRegs[_Rs_] % g_psxConstRegs[_Rt_]; + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); + } +} + +void rpsxDIVU_consts(int info) { rpsxDIVsuperconsts(info, 0); } +void rpsxDIVU_constt(int info) { rpsxDIVsuperconstt(info, 0); } +void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); } + +PSXRECOMPILE_CONSTCODE3(DIVU, 1); + +//// LoadStores +#ifdef PCSX2_VIRTUAL_MEM + +// VM load store functions (fastest) + +//#define REC_SLOWREAD +//#define REC_SLOWWRITE + +int _psxPrepareReg(int gprreg) +{ + return 0; +} + +static u32 s_nAddMemOffset = 0; + +#define SET_HWLOC() { \ + x86SetJ8(j8Ptr[0]); \ + SHR32ItoR(ECX, 3); \ + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); \ +} \ + +int rpsxSetMemLocation(int regs, int mmreg) +{ + s_nAddMemOffset = 0; + MOV32MtoR( ECX, (int)&psxRegs.GPR.r[ regs ] ); + + if ( _Imm_ != 0 ) ADD32ItoR( ECX, _Imm_ ); + + SHL32ItoR(ECX, 3); + j8Ptr[0] = JS8(0); + SHR32ItoR(ECX, 3); + AND32ItoR(ECX, 0x1fffff); // 2Mb + return 1; +} + +void recLoad32(u32 bit, u32 sign) +{ + int mmreg = -1; + +#ifdef REC_SLOWREAD + _psxFlushConstReg(_Rs_); +#else + if( PSX_IS_CONST1( _Rs_ ) ) { + // do const processing + int ineax = 0; + + _psxOnWriteReg(_Rt_); + mmreg = EAX; + + switch(bit) { + case 8: ineax = psxRecMemConstRead8(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); break; + case 16: + assert( (g_psxConstRegs[_Rs_]+_Imm_) % 2 == 0 ); + ineax = psxRecMemConstRead16(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); + break; + case 32: + assert( (g_psxConstRegs[_Rs_]+_Imm_) % 4 == 0 ); + ineax = psxRecMemConstRead32(mmreg, g_psxConstRegs[_Rs_]+_Imm_); + break; + } + + if( _Rt_ ) MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); + } + else +#endif + { + int dohw; + int mmregs = _psxPrepareReg(_Rs_); + + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + dohw = rpsxSetMemLocation(_Rs_, mmregs); + + switch(bit) { + case 8: + if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + case 16: + if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + case 32: + MOV32RmtoROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC(); + + switch(bit) { + case 8: + CALLFunc( (int)psxRecMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + break; + case 16: + CALLFunc( (int)psxRecMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + break; + case 32: + CALLFunc( (int)psxRecMemRead32 ); + break; + } + + x86SetJ8(j8Ptr[1]); + } + + if( _Rt_ ) + MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); + } +} + +void rpsxLB() { recLoad32(8, 1); } +void rpsxLBU() { recLoad32(8, 0); } +void rpsxLH() { recLoad32(16, 1); } +void rpsxLHU() { recLoad32(16, 0); } +void rpsxLW() { recLoad32(32, 0); } + +extern void rpsxMemConstClear(u32 mem); + +// check if mem is executable, and clear it +__declspec(naked) void rpsxWriteMemClear() +{ + _asm { + mov edx, ecx + shr edx, 14 + and dl, 0xfc + add edx, psxRecLUT + test dword ptr [edx], 0xffffffff + jnz Clear32 + ret +Clear32: + // recLUT[mem>>16] + (mem&0xfffc) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + cmp dword ptr [edx], 0 + je ClearRet + sub esp, 4 + mov dword ptr [esp], edx + call psxRecClearMem + add esp, 4 +ClearRet: + ret + } +} + +extern u32 s_psxBlockCycles; +void recStore(int bit) +{ +#ifdef REC_SLOWWRITE + _psxFlushConstReg(_Rs_); +#else + if( PSX_IS_CONST1( _Rs_ ) ) { + u8* pjmpok; + u32 addr = g_psxConstRegs[_Rs_]+_Imm_; + int doclear = 0; + + if( !(addr & 0x10000000) ) { + // check g_psxWriteOk + CMP32ItoM((uptr)&g_psxWriteOk, 0); + pjmpok = JE8(0); + } + + switch(bit) { + case 8: + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite8(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite8(addr, EAX); + } + + break; + + case 16: + assert( (addr)%2 == 0 ); + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite16(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite16(addr, EAX); + } + + break; + + case 32: + assert( (addr)%4 == 0 ); + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite32(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite32(addr, EAX); + } + + break; + } + + if( !(addr & 0x10000000) ) { + if( doclear ) rpsxMemConstClear((addr)&~3); + x86SetJ8(pjmpok); + } + } + else +#endif + { + int dohw; + int mmregs = _psxPrepareReg(_Rs_); + dohw = rpsxSetMemLocation(_Rs_, mmregs); + + CMP32ItoM((uptr)&g_psxWriteOk, 0); + u8* pjmpok = JE8(0); + + if( PSX_IS_CONST1( _Rt_ ) ) { + switch(bit) { + case 8: MOV8ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + case 16: MOV16ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + case 32: MOV32ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + } + } + else { + switch(bit) { + case 8: + MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV8RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + + case 16: + MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV16RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + + case 32: + MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + } + } + + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (uptr)&g_psxMaxRecMem); + + j8Ptr[1] = JAE8(0); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + CALLFunc((u32)rpsxWriteMemClear); + + if( dohw ) { + j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + if( PSX_IS_CONST1(_Rt_) ) { + switch(bit) { + case 8: MOV8ItoR(EAX, g_psxConstRegs[_Rt_]); break; + case 16: MOV16ItoR(EAX, g_psxConstRegs[_Rt_]); break; + case 32: MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); break; + } + } + else { + switch(bit) { + case 8: MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + case 16: MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + case 32: MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + } + } + + if( s_nAddMemOffset != 0 ) ADD32ItoR(ECX, s_nAddMemOffset); + + // some type of hardware write + switch(bit) { + case 8: CALLFunc( (int)psxRecMemWrite8 ); break; + case 16: CALLFunc( (int)psxRecMemWrite16 ); break; + case 32: CALLFunc( (int)psxRecMemWrite32 ); break; + } + + x86SetJ8(j8Ptr[2]); + } + + x86SetJ8(j8Ptr[1]); + x86SetJ8(pjmpok); + } +} + +void rpsxSB() { recStore(8); } +void rpsxSH() { recStore(16); } +void rpsxSW() { recStore(32); } + +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); + +#else + +// TLB loadstore functions (slower +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); + +static void rpsxLB() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVSX32R8toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLBU() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVZX32R8toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLH() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVSX32R16toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLHU() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVZX32R16toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLW() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + _psxFlushCall(FLUSH_EVERYTHING); + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + +#ifndef TLB_DEBUG_MEM + TEST32ItoR(X86ARG1, 0x10000000); + j8Ptr[0] = JZ8(0); +#endif + + _callFunctionArg1((uptr)psxMemRead32, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } +#ifndef TLB_DEBUG_MEM + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + // read from psM directly + AND32ItoR(X86ARG1, 0x1fffff); + ADD32ItoR(X86ARG1, (uptr)psxM); + + MOV32RmtoR( X86ARG1, X86ARG1 ); + MOV32RtoM( (uptr)&psxRegs.GPR.r[_Rt_], X86ARG1); + + x86SetJ8(j8Ptr[1]); +#endif + PSX_DEL_CONST(_Rt_); +} + +static void rpsxSB() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite8, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +static void rpsxSH() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite16, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +static void rpsxSW() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite32, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +#endif // end load store + +//// SLL +void rpsxSLL_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << _Sa_; +} + +// shifttype: 0 - sll, 1 - srl, 2 - sra +void rpsxShiftConst(int info, int rdreg, int rtreg, int imm, int shifttype) +{ + imm &= 0x1f; + if (imm) { + if( rdreg == rtreg ) { + switch(shifttype) { + case 0: SHL32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + case 1: SHR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + case 2: SAR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + } + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); + switch(shifttype) { + case 0: SHL32ItoR(EAX, imm); break; + case 1: SHR32ItoR(EAX, imm); break; + case 2: SAR32ItoR(EAX, imm); break; + } + MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); + } + } + else { + if( rdreg != rtreg ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); + } + } +} + +void rpsxSLL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 0); } +PSXRECOMPILE_CONSTCODE2(SLL); + +//// SRL +void rpsxSRL_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> _Sa_; +} + +void rpsxSRL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 1); } +PSXRECOMPILE_CONSTCODE2(SRL); + +//// SRA +void rpsxSRA_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> _Sa_; +} + +void rpsxSRA_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 2); } +PSXRECOMPILE_CONSTCODE2(SRA); + +//// SLLV +void rpsxSLLV_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxShiftVconsts(int info, int shifttype) +{ + rpsxShiftConst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_], shifttype); +} + +void rpsxShiftVconstt(int info, int shifttype) +{ + MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + switch(shifttype) { + case 0: SHL32CLtoR(EAX); break; + case 1: SHR32CLtoR(EAX); break; + case 2: SAR32CLtoR(EAX); break; + } + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLLV_consts(int info) { rpsxShiftVconsts(info, 0); } +void rpsxSLLV_constt(int info) { rpsxShiftVconstt(info, 0); } +void rpsxSLLV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SHL32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLLV); + +//// SRLV +void rpsxSRLV_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxSRLV_consts(int info) { rpsxShiftVconsts(info, 1); } +void rpsxSRLV_constt(int info) { rpsxShiftVconstt(info, 1); } +void rpsxSRLV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SHR32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SRLV); + +//// SRAV +void rpsxSRAV_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxSRAV_consts(int info) { rpsxShiftVconsts(info, 2); } +void rpsxSRAV_constt(int info) { rpsxShiftVconstt(info, 2); } +void rpsxSRAV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SAR32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SRAV); + +extern void rpsxSYSCALL(); +extern void rpsxBREAK(); + +void rpsxMFHI() +{ + if (!_Rd_) return; + + _psxOnWriteReg(_Rd_); + _psxDeleteReg(_Rd_, 0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.hi); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxMTHI() +{ + if( PSX_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); + } + else { + _psxDeleteReg(_Rs_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); + } +} + +void rpsxMFLO() +{ + if (!_Rd_) return; + + _psxOnWriteReg(_Rd_); + _psxDeleteReg(_Rd_, 0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.lo); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxMTLO() +{ + if( PSX_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); + } + else { + _psxDeleteReg(_Rs_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + } +} + +void rpsxJ() +{ + // j target + u32 newpc = _Target_ * 4 + (psxpc & 0xf0000000); + psxRecompileNextInstruction(1); + psxSetBranchImm(newpc); +} + +void rpsxJAL() +{ + u32 newpc = (_Target_ << 2) + ( psxpc & 0xf0000000 ); + _psxDeleteReg(31, 0); + PSX_SET_CONST(31); + g_psxConstRegs[31] = psxpc + 4; + + psxRecompileNextInstruction(1); + psxSetBranchImm(newpc); +} + +void rpsxJR() +{ + psxSetBranchReg(_Rs_); +} + +void rpsxJALR() +{ + // jalr Rs + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _psxMoveGPRtoR(ESI, _Rs_); + + if ( _Rd_ ) + { + _psxDeleteReg(_Rd_, 0); + PSX_SET_CONST(_Rd_); + g_psxConstRegs[_Rd_] = psxpc + 4; + } + + psxRecompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((uptr)&psxRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (uptr)&g_recWriteback); + MOV32RtoM((uptr)&psxRegs.pc, EAX); + } + + psxSetBranchReg(0xffffffff); +} + +//// BEQ +static void* s_pbranchjmp; +static u32 s_do32 = 0; + +#define JUMPVALID(pjmp) (( x86Ptr - (s8*)pjmp ) <= 0x80) + +void rpsxSetBranchEQ(int info, int process) +{ + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rt_ ], g_psxConstRegs[_Rs_] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rs_ ], g_psxConstRegs[_Rt_] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } + else { + MOV32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rs_ ] ); + CMP32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rt_ ] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } +} + +void rpsxBEQ_const() +{ + u32 branchTo; + + if( g_psxConstRegs[_Rs_] == g_psxConstRegs[_Rt_] ) + branchTo = ((s32)_Imm_ * 4) + psxpc; + else + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); +} + +void rpsxBEQ_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + if ( _Rs_ == _Rt_ ) + { + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + } + else + { + _psxFlushAllUnused(); + s8* prevx86 = x86Ptr; + s_do32 = 0; + psxSaveBranchState(); + + rpsxSetBranchEQ(info, process); + + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); + + if( JUMPVALID(s_pbranchjmp) ) { + x86SetJ8A( (u8*)s_pbranchjmp ); + } + else { + x86Ptr = prevx86; + s_do32 = 1; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + rpsxSetBranchEQ(info, process); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); + x86SetJ32A( (u32*)s_pbranchjmp ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + } +} + +void rpsxBEQ_(int info) { rpsxBEQ_process(info, 0); } +void rpsxBEQ_consts(int info) { rpsxBEQ_process(info, PROCESS_CONSTS); } +void rpsxBEQ_constt(int info) { rpsxBEQ_process(info, PROCESS_CONSTT); } +PSXRECOMPILE_CONSTCODE3(BEQ, 0); + +//// BNE +void rpsxBNE_const() +{ + u32 branchTo; + + if( g_psxConstRegs[_Rs_] != g_psxConstRegs[_Rt_] ) + branchTo = ((s32)_Imm_ * 4) + psxpc; + else + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); +} + +void rpsxBNE_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + if ( _Rs_ == _Rt_ ) + { + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + return; + } + + _psxFlushAllUnused(); + s8* prevx86 = x86Ptr; + s_do32 = 0; + rpsxSetBranchEQ(info, process); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(s_pbranchjmp) ) { + x86SetJ8A( (u8*)s_pbranchjmp ); + } + else { + x86Ptr = prevx86; + s_do32 = 1; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + rpsxSetBranchEQ(info, process); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( (u32*)s_pbranchjmp ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +void rpsxBNE_(int info) { rpsxBNE_process(info, 0); } +void rpsxBNE_consts(int info) { rpsxBNE_process(info, PROCESS_CONSTS); } +void rpsxBNE_constt(int info) { rpsxBNE_process(info, PROCESS_CONSTT); } +PSXRECOMPILE_CONSTCODE3(BNE, 0); + +//// BLTZ +void rpsxBLTZ() +{ + // Branch if Rs < 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] >= 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JL8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JL32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BGEZ +void rpsxBGEZ() +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( g_psxConstRegs[_Rs_] < 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JGE8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JGE32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BLTZAL +void rpsxBLTZAL() +{ + // Branch if Rs < 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushConstReg(31); + _psxDeleteReg(31, 0); + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] >= 0 ) + branchTo = psxpc+4; + else { + PSX_SET_CONST(_Rt_); + g_psxConstRegs[31] = psxpc+4; + } + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JL8(0); + + psxSaveBranchState(); + + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JL32(0); + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BGEZAL +void rpsxBGEZAL() +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + _psxFlushConstReg(31); + _psxDeleteReg(31, 0); + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( g_psxConstRegs[_Rs_] < 0 ) + branchTo = psxpc+4; + else MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JGE8(0); + + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JGE32(0); + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BLEZ +void rpsxBLEZ() +{ + // Branch if Rs <= 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] > 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + _psxDeleteReg(_Rs_, 1); + _clearNeededX86regs(); + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JLE8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JLE32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); +} + +//// BGTZ +void rpsxBGTZ() +{ + // Branch if Rs > 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] <= 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + _psxDeleteReg(_Rs_, 1); + _clearNeededX86regs(); + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + s8* prevx86 = x86Ptr; + u8* pjmp = JG8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JG32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); +} + +void rpsxMFC0() +{ + // Rt = Cop0->Rd + if (!_Rt_) return; + + _psxOnWriteReg(_Rt_); + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); +} + +void rpsxCFC0() +{ + // Rt = Cop0->Rd + if (!_Rt_) return; + + _psxOnWriteReg(_Rt_); + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); +} + +void rpsxMTC0() +{ + // Cop0->Rd = Rt + if( PSX_IS_CONST1(_Rt_) ) { + MOV32ItoM((uptr)&psxRegs.CP0.r[_Rd_], g_psxConstRegs[_Rt_]); + } + else { + _psxDeleteReg(_Rt_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.CP0.r[_Rd_], EAX); + } +} + +void rpsxCTC0() +{ + // Cop0->Rd = Rt + rpsxMTC0(); +} + +void rpsxRFE() +{ + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.n.Status); + MOV32RtoR(ECX, EAX); + AND32ItoR(EAX, 0xfffffff0); + AND32ItoR(ECX, 0x3c); + SHR32ItoR(ECX, 2); + OR32RtoR (EAX, ECX); + MOV32RtoM((uptr)&psxRegs.CP0.n.Status, EAX); +} + +// R3000A tables +extern void (*rpsxBSC[64])(); +extern void (*rpsxSPC[64])(); +extern void (*rpsxREG[32])(); +extern void (*rpsxCP0[32])(); +extern void (*rpsxCP2[64])(); +extern void (*rpsxCP2BSC[32])(); + +static void rpsxSPECIAL() { rpsxSPC[_Funct_](); } +static void rpsxREGIMM() { rpsxREG[_Rt_](); } +static void rpsxCOP0() { rpsxCP0[_Rs_](); } +//static void rpsxBASIC() { rpsxCP2BSC[_Rs_](); } + +static void rpsxNULL() { + SysPrintf("psxUNK: %8.8x\n", psxRegs.code); +} + +void (*rpsxBSC[64])() = { + rpsxSPECIAL, rpsxREGIMM, rpsxJ , rpsxJAL , rpsxBEQ , rpsxBNE , rpsxBLEZ, rpsxBGTZ, + rpsxADDI , rpsxADDIU , rpsxSLTI, rpsxSLTIU, rpsxANDI, rpsxORI , rpsxXORI, rpsxLUI , + rpsxCOP0 , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxLB , rpsxLH , rpsxLWL , rpsxLW , rpsxLBU , rpsxLHU , rpsxLWR , rpsxNULL, + rpsxSB , rpsxSH , rpsxSWL , rpsxSW , rpsxNULL, rpsxNULL, rpsxSWR , rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +void (*rpsxSPC[64])() = { + rpsxSLL , rpsxNULL, rpsxSRL , rpsxSRA , rpsxSLLV , rpsxNULL , rpsxSRLV, rpsxSRAV, + rpsxJR , rpsxJALR, rpsxNULL, rpsxNULL, rpsxSYSCALL, rpsxBREAK, rpsxNULL, rpsxNULL, + rpsxMFHI, rpsxMTHI, rpsxMFLO, rpsxMTLO, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxMULT, rpsxMULTU, rpsxDIV, rpsxDIVU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxADD , rpsxADDU, rpsxSUB , rpsxSUBU, rpsxAND , rpsxOR , rpsxXOR , rpsxNOR , + rpsxNULL, rpsxNULL, rpsxSLT , rpsxSLTU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL +}; + +void (*rpsxREG[32])() = { + rpsxBLTZ , rpsxBGEZ , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxBLTZAL, rpsxBGEZAL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +void (*rpsxCP0[32])() = { + rpsxMFC0, rpsxNULL, rpsxCFC0, rpsxNULL, rpsxMTC0, rpsxNULL, rpsxCTC0, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxRFE , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +// coissued insts +void (*rpsxBSC_co[64] )() = { + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, +}; + +//////////////////////////////////////////////// +// Back-Prob Function Tables - Gathering Info // +//////////////////////////////////////////////// +#define rpsxpropSetRead(reg) { \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + prev->regs[reg] |= EEINST_LIVE0|EEINST_USED; \ + pinst->regs[reg] |= EEINST_USED; \ + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 0); \ +} \ + +#define rpsxpropSetWrite(reg) { \ + prev->regs[reg] &= ~EEINST_LIVE0; \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + pinst->regs[reg] |= EEINST_USED; \ + prev->regs[reg] |= EEINST_USED; \ + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 1); \ +} + +void rpsxpropBSC(EEINST* prev, EEINST* pinst); +void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst); +void rpsxpropREGIMM(EEINST* prev, EEINST* pinst); +void rpsxpropCP0(EEINST* prev, EEINST* pinst); +void rpsxpropCP2(EEINST* prev, EEINST* pinst); + +//SPECIAL, REGIMM, J , JAL , BEQ , BNE , BLEZ, BGTZ, +//ADDI , ADDIU , SLTI, SLTIU, ANDI, ORI , XORI, LUI , +//COP0 , NULL , COP2, NULL , NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, +//LB , LH , LWL , LW , LBU , LHU , LWR , NULL, +//SB , SH , SWL , SW , NULL, NULL, SWR , NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL +void rpsxpropBSC(EEINST* prev, EEINST* pinst) +{ + switch(psxRegs.code >> 26) { + case 0: rpsxpropSPECIAL(prev, pinst); break; + case 1: rpsxpropREGIMM(prev, pinst); break; + case 2: // j + break; + case 3: // jal + rpsxpropSetWrite(31); + break; + case 4: // beq + case 5: // bne + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + + case 6: // blez + case 7: // bgtz + rpsxpropSetRead(_Rs_); + break; + + case 15: // lui + rpsxpropSetWrite(_Rt_); + break; + + case 16: rpsxpropCP0(prev, pinst); break; + case 18: assert(0); break; + + // stores + case 40: case 41: case 42: case 43: case 46: + rpsxpropSetRead(_Rt_); + rpsxpropSetRead(_Rs_); + break; + + default: + rpsxpropSetWrite(_Rt_); + rpsxpropSetRead(_Rs_); + break; + } +} + +//SLL , NULL, SRL , SRA , SLLV , NULL , SRLV, SRAV, +//JR , JALR, NULL, NULL, SYSCALL, BREAK, NULL, NULL, +//MFHI, MTHI, MFLO, MTLO, NULL , NULL , NULL, NULL, +//MULT, MULTU, DIV, DIVU, NULL , NULL , NULL, NULL, +//ADD , ADDU, SUB , SUBU, AND , OR , XOR , NOR , +//NULL, NULL, SLT , SLTU, NULL , NULL , NULL, NULL, +//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL, +//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL +void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst) +{ + switch(_Funct_) { + case 0: // SLL + case 2: // SRL + case 3: // SRA + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rt_); + break; + + case 8: // JR + rpsxpropSetRead(_Rs_); + break; + case 9: // JALR + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rs_); + break; + + case 12: // syscall + case 13: // break + _recClearInst(prev); + prev->info = 0; + break; + case 15: // sync + break; + + case 16: // mfhi + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(PSX_HI); + break; + case 17: // mthi + rpsxpropSetWrite(PSX_HI); + rpsxpropSetRead(_Rs_); + break; + case 18: // mflo + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(PSX_LO); + break; + case 19: // mtlo + rpsxpropSetWrite(PSX_LO); + rpsxpropSetRead(_Rs_); + break; + + case 24: // mult + case 25: // multu + case 26: // div + case 27: // divu + rpsxpropSetWrite(PSX_LO); + rpsxpropSetWrite(PSX_HI); + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + + case 32: // add + case 33: // addu + case 34: // sub + case 35: // subu + rpsxpropSetWrite(_Rd_); + if( _Rs_ ) rpsxpropSetRead(_Rs_); + if( _Rt_ ) rpsxpropSetRead(_Rt_); + break; + + default: + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + } +} + +//BLTZ , BGEZ , NULL, NULL, NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL, +//BLTZAL, BGEZAL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL +void rpsxpropREGIMM(EEINST* prev, EEINST* pinst) +{ + switch(_Rt_) { + case 0: // bltz + case 1: // bgez + rpsxpropSetRead(_Rs_); + break; + + case 16: // bltzal + case 17: // bgezal + // do not write 31 + rpsxpropSetRead(_Rs_); + break; + + default: + assert(0); + break; + } +} + +//MFC0, NULL, CFC0, NULL, MTC0, NULL, CTC0, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//RFE , NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +void rpsxpropCP0(EEINST* prev, EEINST* pinst) +{ + switch(_Rs_) { + case 0: // mfc0 + case 2: // cfc0 + rpsxpropSetWrite(_Rt_); + break; + + case 4: // mtc0 + case 6: // ctc0 + rpsxpropSetRead(_Rt_); + break; + case 16: // rfe + break; + default: + assert(0); + } +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iR5900.h b/pcsx2/x86/iR5900.h new file mode 100644 index 0000000000..8e67d0da14 --- /dev/null +++ b/pcsx2/x86/iR5900.h @@ -0,0 +1,254 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900_H__ +#define __IR5900_H__ + +#include "VU.h" +#include "iCore.h" + +// these might not work anymore +#define ARITHMETICIMM_RECOMPILE +#define ARITHMETIC_RECOMPILE +#define MULTDIV_RECOMPILE +#define SHIFT_RECOMPILE +#define BRANCH_RECOMPILE +#define JUMP_RECOMPILE +#define LOADSTORE_RECOMPILE +#define MOVE_RECOMPILE +#define MMI_RECOMPILE +#define MMI0_RECOMPILE +#define MMI1_RECOMPILE +#define MMI2_RECOMPILE +#define MMI3_RECOMPILE +#define FPU_RECOMPILE +#define CP0_RECOMPILE +#define CP2_RECOMPILE + +#define EE_CONST_PROP // rec2 - enables constant propagation (faster) +#define EE_FPU_REGCACHING 1 + +#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) + +void recClearMem(BASEBLOCK* p); +#define REC_CLEARM(mem) { \ + if ((mem) < maxrecmem && recLUT[(mem) >> 16]) { \ + BASEBLOCK* p = PC_GETBLOCK(mem); \ + if( *(u32*)p ) recClearMem(p); \ + } \ +} \ + +extern u32 pc; +extern int branch; +extern uptr* recLUT; + +extern u32 pc; // recompiler pc +extern int branch; // set for branch +extern u32 target; // branch target +extern u16 x86FpuState; +extern u16 iCWstate; +extern u32 s_nBlockCycles; // cycles of current block recompiling + +#define REC_FUNC_INLINE( f, delreg ) \ + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); \ + MOV32ItoM( (u32)&cpuRegs.pc, pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + if( (delreg) > 0 ) _deleteEEreg(delreg, 0); \ + CALLFunc( (u32)f ); + +#define REC_FUNC( f, delreg ) \ + void f( void ); \ + void rec##f( void ) \ + { \ + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); \ + MOV32ItoM( (u32)&cpuRegs.pc, pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + if( (delreg) > 0 ) _deleteEEreg(delreg, 0); \ + CALLFunc( (u32)f ); \ + } + +#define REC_SYS( f ) \ + void f( void ); \ + void rec##f( void ) \ + { \ + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); \ + MOV32ItoM( (u32)&cpuRegs.pc, pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc( (u32)f ); \ + branch = 2; \ + } + +// used when processing branches +void SaveBranchState(); +void LoadBranchState(); + +void recompileNextInstruction(int delayslot); +void SetBranchReg( u32 reg ); +void SetBranchImm( u32 imm ); + +void iFlushCall(int flushtype); +void SaveCW(); +void LoadCW(); + +extern void (*recBSC[64])(); +extern void (*recSPC[64])(); +extern void (*recREG[32])(); +extern void (*recCP0[32])(); +extern void (*recCP0BC0[32])(); +extern void (*recCP0C0[64])(); +extern void (*recCP1[32])(); +extern void (*recCP1BC1[32])(); +extern void (*recCP1S[64])(); +extern void (*recCP1W[64])(); +extern void (*recMMIt[64])(); +extern void (*recMMI0t[32])(); +extern void (*recMMI1t[32])(); +extern void (*recMMI2t[32])(); +extern void (*recMMI3t[32])(); + +u32* _eeGetConstReg(int reg); // gets a memory pointer to the constant reg + +void _eeFlushAllUnused(); +void _eeOnWriteReg(int reg, int signext); + +// totally deletes from const, xmm, and mmx entries +// if flush is 1, also flushes to memory +// if 0, only flushes if not an xmm reg (used when overwriting lower 64bits of reg) +void _deleteEEreg(int reg, int flush); + +// allocates memory on the instruction size and returns the pointer +void* recAllocStackMem(int size, int align); + +////////////////////////////////////// +// Templates for code recompilation // +////////////////////////////////////// +typedef void (*R5900FNPTR)(); +typedef void (*R5900FNPTR_INFO)(int info); + +#define EERECOMPILE_CODE0(fn, xmminfo) \ +void rec##fn(void) \ +{ \ + eeRecompileCode0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_, xmminfo); \ +} \ + +#define EERECOMPILE_CODEX(codename, fn) \ +void rec##fn(void) \ +{ \ + codename(rec##fn##_const, rec##fn##_); \ +} \ + +// +// MMX/XMM caching helpers +// + +// rd = rs op rt +void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo); +// rt = rs op imm16 +void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt op sa +void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rt op rs (SPECIAL) +void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode); + +// +// non mmx/xmm version, slower +// +// rd = rs op rt +#define EERECOMPILE_CONSTCODE0(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_); \ +} \ + +// rt = rs op imm16 +#define EERECOMPILE_CONSTCODE1(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst1(rec##fn##_const, rec##fn##_); \ +} \ + +// rd = rt op sa +#define EERECOMPILE_CONSTCODE2(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst2(rec##fn##_const, rec##fn##_); \ +} \ + +// rd = rt op rs +#define EERECOMPILE_CONSTCODESPECIAL(fn, mult) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConstSPECIAL(rec##fn##_const, rec##fn##_, mult); \ +} \ + +// rd = rs op rt +void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode); +// rt = rs op imm16 +void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt op sa +void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt MULT rs (SPECIAL) +void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT); + +// XMM caching helpers +#define XMMINFO_READLO 0x01 +#define XMMINFO_READHI 0x02 +#define XMMINFO_WRITELO 0x04 +#define XMMINFO_WRITEHI 0x08 +#define XMMINFO_WRITED 0x10 +#define XMMINFO_READD 0x20 +#define XMMINFO_READS 0x40 +#define XMMINFO_READT 0x80 +#define XMMINFO_READD_LO 0x100 // if set and XMMINFO_READD is set, reads only low 64 bits of D +#define XMMINFO_READACC 0x200 +#define XMMINFO_WRITEACC 0x400 + +#define CPU_SSE_XMMCACHE_START(xmminfo) \ + if (cpucaps.hasStreamingSIMDExtensions) \ + { \ + int info = eeRecompileCodeXMM(xmminfo); \ + +#define CPU_SSE2_XMMCACHE_START(xmminfo) \ + if (cpucaps.hasStreamingSIMD2Extensions) \ + { \ + int info = eeRecompileCodeXMM(xmminfo); \ + +#define CPU_SSE_XMMCACHE_END \ + _clearNeededXMMregs(); \ + return; \ + } \ + +#ifdef __x86_64__ +#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \ +void rec##fn(void) \ +{ \ + eeFPURecompileCode(rec##fn##_xmm, NULL, xmminfo); \ +} +#else +#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \ +void rec##fn(void) \ +{ \ + eeFPURecompileCode(rec##fn##_xmm, rec##fn##_, xmminfo); \ +} +#endif + +// rd = rs op rt (all regs need to be in xmm) +int eeRecompileCodeXMM(int xmminfo); +void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR_INFO fpucode, int xmminfo); + +#endif // __IR5900_H__ diff --git a/pcsx2/x86/iR5900Arit.h b/pcsx2/x86/iR5900Arit.h new file mode 100644 index 0000000000..e94b6595f2 --- /dev/null +++ b/pcsx2/x86/iR5900Arit.h @@ -0,0 +1,45 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900ARIT_H__ +#define __IR5900ARIT_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +void recADD( void ); +void recADDU( void ); +void recDADD( void ); +void recDADDU( void ); +void recSUB( void ); +void recSUBU( void ); +void recDSUB( void ); +void recDSUBU( void ); +void recAND( void ); +void recOR( void ); +void recXOR( void ); +void recNOR( void ); +void recSLT( void ); +void recSLTU( void ); + +#endif diff --git a/pcsx2/x86/iR5900AritImm.h b/pcsx2/x86/iR5900AritImm.h new file mode 100644 index 0000000000..b30fd0c4bb --- /dev/null +++ b/pcsx2/x86/iR5900AritImm.h @@ -0,0 +1,41 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900ARITIMM_H__ +#define __IR5900ARITIMM_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ + +void recADDI( void ); +void recADDIU( void ); +void recDADDI( void ); +void recDADDIU( void ); +void recANDI( void ); +void recORI( void ); +void recXORI( void ); + +void recSLTI( void ); +void recSLTIU( void ); + +#endif diff --git a/pcsx2/x86/iR5900Branch.h b/pcsx2/x86/iR5900Branch.h new file mode 100644 index 0000000000..5e77840040 --- /dev/null +++ b/pcsx2/x86/iR5900Branch.h @@ -0,0 +1,47 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900BRANCH_H__ +#define __IR5900BRANCH_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ + +void recBEQ( void ); +void recBEQL( void ); +void recBNE( void ); +void recBNEL( void ); +void recBLTZ( void ); +void recBLTZL( void ); +void recBLTZAL( void ); +void recBLTZALL( void ); +void recBGTZ( void ); +void recBGTZL( void ); +void recBLEZ( void ); +void recBLEZL( void ); +void recBGEZ( void ); +void recBGEZL( void ); +void recBGEZAL( void ); +void recBGEZALL( void ); + +#endif diff --git a/pcsx2/x86/iR5900Jump.h b/pcsx2/x86/iR5900Jump.h new file mode 100644 index 0000000000..b613bee67e --- /dev/null +++ b/pcsx2/x86/iR5900Jump.h @@ -0,0 +1,35 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900JUMP_H__ +#define __IR5900JUMP_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ + +void recJ( void ); +void recJAL( void ); +void recJR( void ); +void recJALR( void ); + +#endif diff --git a/pcsx2/x86/iR5900LoadStore.h b/pcsx2/x86/iR5900LoadStore.h new file mode 100644 index 0000000000..8dabe5d1fc --- /dev/null +++ b/pcsx2/x86/iR5900LoadStore.h @@ -0,0 +1,90 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900LOADSTORE_H__ +#define __IR5900LOADSTORE_H__ +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +void recLB( void ); +void recLBU( void ); +void recLH( void ); +void recLHU( void ); +void recLW( void ); +void recLWU( void ); +void recLWL( void ); +void recLWR( void ); +void recLD( void ); +void recLDR( void ); +void recLDL( void ); +void recLQ( void ); +void recSB( void ); +void recSH( void ); +void recSW( void ); +void recSWL( void ); +void recSWR( void ); +void recSD( void ); +void recSDL( void ); +void recSDR( void ); +void recSQ( void ); +void recLWC1( void ); +void recSWC1( void ); +void recLQC2( void ); +void recSQC2( void ); + +// coissues +#ifdef PCSX2_VIRTUAL_MEM +void recLB_co( void ); +void recLBU_co( void ); +void recLH_co( void ); +void recLHU_co( void ); +void recLW_co( void ); +void recLWU_co( void ); +void recLWL_co( void ); +void recLWR_co( void ); +void recLD_co( void ); +void recLDR_co( void ); +void recLDL_co( void ); +void recLQ_co( void ); +void recSB_co( void ); +void recSH_co( void ); +void recSW_co( void ); +void recSWL_co( void ); +void recSWR_co( void ); +void recSD_co( void ); +void recSDL_co( void ); +void recSDR_co( void ); +void recSQ_co( void ); +void recLWC1_co( void ); +void recSWC1_co( void ); +void recLQC2_co( void ); +void recSQC2_co( void ); + +// coissue-X +void recLD_coX(int num); +void recLQ_coX(int num); +void recLWC1_coX(int num); +void recSD_coX(int num); +void recSQ_coX(int num); +void recSWC1_coX(int num); + +#endif + +#endif diff --git a/pcsx2/x86/iR5900Move.h b/pcsx2/x86/iR5900Move.h new file mode 100644 index 0000000000..0dc37285a4 --- /dev/null +++ b/pcsx2/x86/iR5900Move.h @@ -0,0 +1,33 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900MOVE_H__ +#define __IR5900MOVE_H__ + +#include "Common.h" +#include "InterTables.h" + +void recLUI( void ); +void recMFLO( void ); +void recMFHI( void ); +void recMTLO( void ); +void recMTHI( void ); +void recMOVN( void ); +void recMOVZ( void ); + +#endif diff --git a/pcsx2/x86/iR5900MultDiv.h b/pcsx2/x86/iR5900MultDiv.h new file mode 100644 index 0000000000..35b0df5ba9 --- /dev/null +++ b/pcsx2/x86/iR5900MultDiv.h @@ -0,0 +1,35 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900MULTDIV_H__ +#define __IR5900MULTDIV_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ + +void recMULT( void ); +void recMULTU( void ); +void recDIV( void ); +void recDIVU( void ); + +#endif diff --git a/pcsx2/x86/iR5900Shift.h b/pcsx2/x86/iR5900Shift.h new file mode 100644 index 0000000000..44b4eee846 --- /dev/null +++ b/pcsx2/x86/iR5900Shift.h @@ -0,0 +1,47 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR5900SHIFT_H__ +#define __IR5900SHIFT_H__ + +#include "Common.h" +#include "InterTables.h" + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ + +void recSLL( void ); +void recSRL( void ); +void recSRA( void ); +void recDSLL( void ); +void recDSRL( void ); +void recDSRA( void ); +void recDSLL32( void ); +void recDSRL32( void ); +void recDSRA32( void ); + +void recSLLV( void ); +void recSRLV( void ); +void recSRAV( void ); +void recDSLLV( void ); +void recDSRLV( void ); +void recDSRAV( void ); + +#endif diff --git a/pcsx2/x86/iVU0micro.c b/pcsx2/x86/iVU0micro.c new file mode 100644 index 0000000000..df94e5d4f9 --- /dev/null +++ b/pcsx2/x86/iVU0micro.c @@ -0,0 +1,782 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" +#include "VUmicro.h" +#include "iVUmicro.h" +#include "iVU0micro.h" +#include "iVUops.h" +#include "VUops.h" + +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +static VURegs * const VU = (VURegs*)&VU0; + +//u32 vu0time = 0; +//static LARGE_INTEGER vu0base, vu0final; + +#ifdef _DEBUG +extern u32 vudump; +#endif + +static u32 vuprogcount = 0; + +void recExecuteVU0Block( void ) +{ + //SysPrintf("executeVU0 %x\n", VU0.VI[ REG_TPC ].UL); + //QueryPerformanceCounter(&vu0base); + +// assert( VU0.VI[REG_VPU_STAT].UL & 1 ); + if((VU0.VI[REG_VPU_STAT].UL & 1) == 0){ + //SysPrintf("Execute block VU0, VU0 not busy\n"); + return; + } +#ifdef _DEBUG + vuprogcount++; + +// __Log("VU: %x %x\n", VU0.VI[ REG_TPC ].UL, vuprogcount); +// iDumpVU0Registers(); + + //vudump |= 0x10; + //vudump |= 0x80; + + if( (vudump&0x80) && !CHECK_VU0REC ) { + __Log("tVU: %x\n", VU0.VI[ REG_TPC ].UL); + iDumpVU0Registers(); + } +#endif + + //while( (VU0.VI[ REG_VPU_STAT ].UL&1) ) { + if( CHECK_VU0REC) { + FreezeXMMRegs(1); + SuperVUExecuteProgram(VU0.VI[ REG_TPC ].UL&0xfff, 0); + FreezeXMMRegs(0); + } + else { + intExecuteVU0Block(); + } + //} + +// __Log("eVU: %x %x\n", VU0.VI[ REG_TPC ].UL, vuprogcount); +// iDumpVU0Registers(); +// QueryPerformanceCounter(&vu0final); +// vu0time += (u32)(vu0final.QuadPart-vu0final.QuadPart); +} + +void recClearVU0( u32 Addr, u32 Size ) +{ + if( CHECK_VU0REC ) { + SuperVUClear(Addr, Size*4, 0); + } +} + +void (*recVU0_LOWER_OPCODE[128])() = { + recVU0MI_LQ , recVU0MI_SQ , recVU0unknown , recVU0unknown, + recVU0MI_ILW , recVU0MI_ISW , recVU0unknown , recVU0unknown, + recVU0MI_IADDIU, recVU0MI_ISUBIU, recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_FCEQ , recVU0MI_FCSET , recVU0MI_FCAND, recVU0MI_FCOR, /* 0x10 */ + recVU0MI_FSEQ , recVU0MI_FSSET , recVU0MI_FSAND, recVU0MI_FSOR, + recVU0MI_FMEQ , recVU0unknown , recVU0MI_FMAND, recVU0MI_FMOR, + recVU0MI_FCGET , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_B , recVU0MI_BAL , recVU0unknown , recVU0unknown, /* 0x20 */ + recVU0MI_JR , recVU0MI_JALR , recVU0unknown , recVU0unknown, + recVU0MI_IBEQ , recVU0MI_IBNE , recVU0unknown , recVU0unknown, + recVU0MI_IBLTZ , recVU0MI_IBGTZ , recVU0MI_IBLEZ, recVU0MI_IBGEZ, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x30 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0LowerOP , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x40*/ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x50 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x60 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x70 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, +}; + +void (*recVU0LowerOP_T3_00_OPCODE[32])() = { + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_MOVE , recVU0MI_LQI , recVU0MI_DIV , recVU0MI_MTIR, + recVU0MI_RNEXT , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x10 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0MI_MFP , recVU0unknown , recVU0unknown, + recVU0MI_ESADD , recVU0MI_EATANxy, recVU0MI_ESQRT, recVU0MI_ESIN, +}; + +void (*recVU0LowerOP_T3_01_OPCODE[32])() = { + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_MR32 , recVU0MI_SQI , recVU0MI_SQRT , recVU0MI_MFIR, + recVU0MI_RGET , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x10 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0MI_XITOP, recVU0unknown, + recVU0MI_ERSADD, recVU0MI_EATANxz, recVU0MI_ERSQRT, recVU0MI_EATAN, +}; + +void (*recVU0LowerOP_T3_10_OPCODE[32])() = { + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0MI_LQD , recVU0MI_RSQRT, recVU0MI_ILWR, + recVU0MI_RINIT , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x10 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_ELENG , recVU0MI_ESUM , recVU0MI_ERCPR, recVU0MI_EEXP, +}; + +void (*recVU0LowerOP_T3_11_OPCODE[32])() = { + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0MI_SQD , recVU0MI_WAITQ, recVU0MI_ISWR, + recVU0MI_RXOR , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x10 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_ERLENG, recVU0unknown , recVU0MI_WAITP, recVU0unknown, +}; + +void (*recVU0LowerOP_OPCODE[64])() = { + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x10 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x20 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0MI_IADD , recVU0MI_ISUB , recVU0MI_IADDI, recVU0unknown, /* 0x30 */ + recVU0MI_IAND , recVU0MI_IOR , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0LowerOP_T3_00, recVU0LowerOP_T3_01, recVU0LowerOP_T3_10, recVU0LowerOP_T3_11, +}; + +void (*recVU0_UPPER_OPCODE[64])() = { + recVU0MI_ADDx , recVU0MI_ADDy , recVU0MI_ADDz , recVU0MI_ADDw, + recVU0MI_SUBx , recVU0MI_SUBy , recVU0MI_SUBz , recVU0MI_SUBw, + recVU0MI_MADDx , recVU0MI_MADDy , recVU0MI_MADDz , recVU0MI_MADDw, + recVU0MI_MSUBx , recVU0MI_MSUBy , recVU0MI_MSUBz , recVU0MI_MSUBw, + recVU0MI_MAXx , recVU0MI_MAXy , recVU0MI_MAXz , recVU0MI_MAXw, /* 0x10 */ + recVU0MI_MINIx , recVU0MI_MINIy , recVU0MI_MINIz , recVU0MI_MINIw, + recVU0MI_MULx , recVU0MI_MULy , recVU0MI_MULz , recVU0MI_MULw, + recVU0MI_MULq , recVU0MI_MAXi , recVU0MI_MULi , recVU0MI_MINIi, + recVU0MI_ADDq , recVU0MI_MADDq , recVU0MI_ADDi , recVU0MI_MADDi, /* 0x20 */ + recVU0MI_SUBq , recVU0MI_MSUBq , recVU0MI_SUBi , recVU0MI_MSUBi, + recVU0MI_ADD , recVU0MI_MADD , recVU0MI_MUL , recVU0MI_MAX, + recVU0MI_SUB , recVU0MI_MSUB , recVU0MI_OPMSUB, recVU0MI_MINI, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, /* 0x30 */ + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown, + recVU0_UPPER_FD_00, recVU0_UPPER_FD_01, recVU0_UPPER_FD_10, recVU0_UPPER_FD_11, +}; + +void (*recVU0_UPPER_FD_00_TABLE[32])() = { + recVU0MI_ADDAx, recVU0MI_SUBAx , recVU0MI_MADDAx, recVU0MI_MSUBAx, + recVU0MI_ITOF0, recVU0MI_FTOI0, recVU0MI_MULAx , recVU0MI_MULAq , + recVU0MI_ADDAq, recVU0MI_SUBAq, recVU0MI_ADDA , recVU0MI_SUBA , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , +}; + +void (*recVU0_UPPER_FD_01_TABLE[32])() = { + recVU0MI_ADDAy , recVU0MI_SUBAy , recVU0MI_MADDAy, recVU0MI_MSUBAy, + recVU0MI_ITOF4 , recVU0MI_FTOI4 , recVU0MI_MULAy , recVU0MI_ABS , + recVU0MI_MADDAq, recVU0MI_MSUBAq, recVU0MI_MADDA , recVU0MI_MSUBA , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , +}; + +void (*recVU0_UPPER_FD_10_TABLE[32])() = { + recVU0MI_ADDAz , recVU0MI_SUBAz , recVU0MI_MADDAz, recVU0MI_MSUBAz, + recVU0MI_ITOF12, recVU0MI_FTOI12, recVU0MI_MULAz , recVU0MI_MULAi , + recVU0MI_ADDAi, recVU0MI_SUBAi , recVU0MI_MULA , recVU0MI_OPMULA, + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , +}; + +void (*recVU0_UPPER_FD_11_TABLE[32])() = { + recVU0MI_ADDAw , recVU0MI_SUBAw , recVU0MI_MADDAw, recVU0MI_MSUBAw, + recVU0MI_ITOF15, recVU0MI_FTOI15, recVU0MI_MULAw , recVU0MI_CLIP , + recVU0MI_MADDAi, recVU0MI_MSUBAi, recVU0unknown , recVU0MI_NOP , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , + recVU0unknown , recVU0unknown , recVU0unknown , recVU0unknown , +}; + +void recVU0_UPPER_FD_00( void ) +{ + recVU0_UPPER_FD_00_TABLE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0_UPPER_FD_01( void ) +{ + recVU0_UPPER_FD_01_TABLE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0_UPPER_FD_10( void ) +{ + recVU0_UPPER_FD_10_TABLE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0_UPPER_FD_11( void ) +{ + recVU0_UPPER_FD_11_TABLE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0LowerOP( void ) +{ + recVU0LowerOP_OPCODE[ VU0.code & 0x3f ]( ); +} + +void recVU0LowerOP_T3_00( void ) +{ + recVU0LowerOP_T3_00_OPCODE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0LowerOP_T3_01( void ) +{ + recVU0LowerOP_T3_01_OPCODE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0LowerOP_T3_10( void ) +{ + recVU0LowerOP_T3_10_OPCODE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + +void recVU0LowerOP_T3_11( void ) +{ + recVU0LowerOP_T3_11_OPCODE[ ( VU0.code >> 6 ) & 0x1f ]( ); +} + + +void recVU0unknown( void ) +{ +#ifdef CPU_LOG + CPU_LOG("Unknown VU0 micromode opcode calledn"); +#endif +} + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +#ifdef RECOMPILE_VUMI_ABS +void recVU0MI_ABS() { recVUMI_ABS(VU, VUREC_INFO); } +#else +void recVU0MI_ABS() { REC_VUOP(VU0, ABS); } +#endif + +#ifdef RECOMPILE_VUMI_ADD +void recVU0MI_ADD() { recVUMI_ADD(VU, VUREC_INFO); } +void recVU0MI_ADDi() { recVUMI_ADDi(VU, VUREC_INFO); } +void recVU0MI_ADDq() { recVUMI_ADDq(VU, VUREC_INFO); } +void recVU0MI_ADDx() { recVUMI_ADDx(VU, VUREC_INFO); } +void recVU0MI_ADDy() { recVUMI_ADDy(VU, VUREC_INFO); } +void recVU0MI_ADDz() { recVUMI_ADDz(VU, VUREC_INFO); } +void recVU0MI_ADDw() { recVUMI_ADDw(VU, VUREC_INFO); } +#else +void recVU0MI_ADD() { REC_VUOP(VU0, ADD); } +void recVU0MI_ADDi() { REC_VUOP(VU0, ADDi); } +void recVU0MI_ADDq() { REC_VUOP(VU0, ADDq); } +void recVU0MI_ADDx() { REC_VUOP(VU0, ADDx); } +void recVU0MI_ADDy() { REC_VUOP(VU0, ADDy); } +void recVU0MI_ADDz() { REC_VUOP(VU0, ADDz); } +void recVU0MI_ADDw() { REC_VUOP(VU0, ADDw); } +#endif + +#ifdef RECOMPILE_VUMI_ADDA +void recVU0MI_ADDA() { recVUMI_ADDA(VU, VUREC_INFO); } +void recVU0MI_ADDAi() { recVUMI_ADDAi(VU, VUREC_INFO); } +void recVU0MI_ADDAq() { recVUMI_ADDAq(VU, VUREC_INFO); } +void recVU0MI_ADDAx() { recVUMI_ADDAx(VU, VUREC_INFO); } +void recVU0MI_ADDAy() { recVUMI_ADDAy(VU, VUREC_INFO); } +void recVU0MI_ADDAz() { recVUMI_ADDAz(VU, VUREC_INFO); } +void recVU0MI_ADDAw() { recVUMI_ADDAw(VU, VUREC_INFO); } +#else +void recVU0MI_ADDA() { REC_VUOP(VU0, ADDA); } +void recVU0MI_ADDAi() { REC_VUOP(VU0, ADDAi); } +void recVU0MI_ADDAq() { REC_VUOP(VU0, ADDAq); } +void recVU0MI_ADDAx() { REC_VUOP(VU0, ADDAx); } +void recVU0MI_ADDAy() { REC_VUOP(VU0, ADDAy); } +void recVU0MI_ADDAz() { REC_VUOP(VU0, ADDAz); } +void recVU0MI_ADDAw() { REC_VUOP(VU0, ADDAw); } +#endif + +#ifdef RECOMPILE_VUMI_SUB +void recVU0MI_SUB() { recVUMI_SUB(VU, VUREC_INFO); } +void recVU0MI_SUBi() { recVUMI_SUBi(VU, VUREC_INFO); } +void recVU0MI_SUBq() { recVUMI_SUBq(VU, VUREC_INFO); } +void recVU0MI_SUBx() { recVUMI_SUBx(VU, VUREC_INFO); } +void recVU0MI_SUBy() { recVUMI_SUBy(VU, VUREC_INFO); } +void recVU0MI_SUBz() { recVUMI_SUBz(VU, VUREC_INFO); } +void recVU0MI_SUBw() { recVUMI_SUBw(VU, VUREC_INFO); } +#else +void recVU0MI_SUB() { REC_VUOP(VU0, SUB); } +void recVU0MI_SUBi() { REC_VUOP(VU0, SUBi); } +void recVU0MI_SUBq() { REC_VUOP(VU0, SUBq); } +void recVU0MI_SUBx() { REC_VUOP(VU0, SUBx); } +void recVU0MI_SUBy() { REC_VUOP(VU0, SUBy); } +void recVU0MI_SUBz() { REC_VUOP(VU0, SUBz); } +void recVU0MI_SUBw() { REC_VUOP(VU0, SUBw); } +#endif + +#ifdef RECOMPILE_VUMI_SUBA +void recVU0MI_SUBA() { recVUMI_SUBA(VU, VUREC_INFO); } +void recVU0MI_SUBAi() { recVUMI_SUBAi(VU, VUREC_INFO); } +void recVU0MI_SUBAq() { recVUMI_SUBAq(VU, VUREC_INFO); } +void recVU0MI_SUBAx() { recVUMI_SUBAx(VU, VUREC_INFO); } +void recVU0MI_SUBAy() { recVUMI_SUBAy(VU, VUREC_INFO); } +void recVU0MI_SUBAz() { recVUMI_SUBAz(VU, VUREC_INFO); } +void recVU0MI_SUBAw() { recVUMI_SUBAw(VU, VUREC_INFO); } +#else +void recVU0MI_SUBA() { REC_VUOP(VU0, SUBA); } +void recVU0MI_SUBAi() { REC_VUOP(VU0, SUBAi); } +void recVU0MI_SUBAq() { REC_VUOP(VU0, SUBAq); } +void recVU0MI_SUBAx() { REC_VUOP(VU0, SUBAx); } +void recVU0MI_SUBAy() { REC_VUOP(VU0, SUBAy); } +void recVU0MI_SUBAz() { REC_VUOP(VU0, SUBAz); } +void recVU0MI_SUBAw() { REC_VUOP(VU0, SUBAw); } +#endif + +#ifdef RECOMPILE_VUMI_MUL +void recVU0MI_MUL() { recVUMI_MUL(VU, VUREC_INFO); } +void recVU0MI_MULi() { recVUMI_MULi(VU, VUREC_INFO); } +void recVU0MI_MULq() { recVUMI_MULq(VU, VUREC_INFO); } +void recVU0MI_MULx() { recVUMI_MULx(VU, VUREC_INFO); } +void recVU0MI_MULy() { recVUMI_MULy(VU, VUREC_INFO); } +void recVU0MI_MULz() { recVUMI_MULz(VU, VUREC_INFO); } +void recVU0MI_MULw() { recVUMI_MULw(VU, VUREC_INFO); } +#else +void recVU0MI_MUL() { REC_VUOP(VU0, MUL); } +void recVU0MI_MULi() { REC_VUOP(VU0, MULi); } +void recVU0MI_MULq() { REC_VUOP(VU0, MULq); } +void recVU0MI_MULx() { REC_VUOP(VU0, MULx); } +void recVU0MI_MULy() { REC_VUOP(VU0, MULy); } +void recVU0MI_MULz() { REC_VUOP(VU0, MULz); } +void recVU0MI_MULw() { REC_VUOP(VU0, MULw); } +#endif + +#ifdef RECOMPILE_VUMI_MULA +void recVU0MI_MULA() { recVUMI_MULA(VU, VUREC_INFO); } +void recVU0MI_MULAi() { recVUMI_MULAi(VU, VUREC_INFO); } +void recVU0MI_MULAq() { recVUMI_MULAq(VU, VUREC_INFO); } +void recVU0MI_MULAx() { recVUMI_MULAx(VU, VUREC_INFO); } +void recVU0MI_MULAy() { recVUMI_MULAy(VU, VUREC_INFO); } +void recVU0MI_MULAz() { recVUMI_MULAz(VU, VUREC_INFO); } +void recVU0MI_MULAw() { recVUMI_MULAw(VU, VUREC_INFO); } +#else +void recVU0MI_MULA() { REC_VUOP(VU0, MULA); } +void recVU0MI_MULAi() { REC_VUOP(VU0, MULAi); } +void recVU0MI_MULAq() { REC_VUOP(VU0, MULAq); } +void recVU0MI_MULAx() { REC_VUOP(VU0, MULAx); } +void recVU0MI_MULAy() { REC_VUOP(VU0, MULAy); } +void recVU0MI_MULAz() { REC_VUOP(VU0, MULAz); } +void recVU0MI_MULAw() { REC_VUOP(VU0, MULAw); } +#endif + +#ifdef RECOMPILE_VUMI_MADD +void recVU0MI_MADD() { recVUMI_MADD(VU, VUREC_INFO); } +void recVU0MI_MADDi() { recVUMI_MADDi(VU, VUREC_INFO); } +void recVU0MI_MADDq() { recVUMI_MADDq(VU, VUREC_INFO); } +void recVU0MI_MADDx() { recVUMI_MADDx(VU, VUREC_INFO); } +void recVU0MI_MADDy() { recVUMI_MADDy(VU, VUREC_INFO); } +void recVU0MI_MADDz() { recVUMI_MADDz(VU, VUREC_INFO); } +void recVU0MI_MADDw() { recVUMI_MADDw(VU, VUREC_INFO); } +#else +void recVU0MI_MADD() { REC_VUOP(VU0, MADD); } +void recVU0MI_MADDi() { REC_VUOP(VU0, MADDi); } +void recVU0MI_MADDq() { REC_VUOP(VU0, MADDq); } +void recVU0MI_MADDx() { REC_VUOP(VU0, MADDx); } +void recVU0MI_MADDy() { REC_VUOP(VU0, MADDy); } +void recVU0MI_MADDz() { REC_VUOP(VU0, MADDz); } +void recVU0MI_MADDw() { REC_VUOP(VU0, MADDw); } +#endif + +#ifdef RECOMPILE_VUMI_MADDA +void recVU0MI_MADDA() { recVUMI_MADDA(VU, VUREC_INFO); } +void recVU0MI_MADDAi() { recVUMI_MADDAi(VU, VUREC_INFO); } +void recVU0MI_MADDAq() { recVUMI_MADDAq(VU, VUREC_INFO); } +void recVU0MI_MADDAx() { recVUMI_MADDAx(VU, VUREC_INFO); } +void recVU0MI_MADDAy() { recVUMI_MADDAy(VU, VUREC_INFO); } +void recVU0MI_MADDAz() { recVUMI_MADDAz(VU, VUREC_INFO); } +void recVU0MI_MADDAw() { recVUMI_MADDAw(VU, VUREC_INFO); } +#else +void recVU0MI_MADDA() { REC_VUOP(VU0, MADDA); } +void recVU0MI_MADDAi() { REC_VUOP(VU0, MADDAi); } +void recVU0MI_MADDAq() { REC_VUOP(VU0, MADDAq); } +void recVU0MI_MADDAx() { REC_VUOP(VU0, MADDAx); } +void recVU0MI_MADDAy() { REC_VUOP(VU0, MADDAy); } +void recVU0MI_MADDAz() { REC_VUOP(VU0, MADDAz); } +void recVU0MI_MADDAw() { REC_VUOP(VU0, MADDAw); } +#endif + +#ifdef RECOMPILE_VUMI_MSUB +void recVU0MI_MSUB() { recVUMI_MSUB(VU, VUREC_INFO); } +void recVU0MI_MSUBi() { recVUMI_MSUBi(VU, VUREC_INFO); } +void recVU0MI_MSUBq() { recVUMI_MSUBq(VU, VUREC_INFO); } +void recVU0MI_MSUBx() { recVUMI_MSUBx(VU, VUREC_INFO); } +void recVU0MI_MSUBy() { recVUMI_MSUBy(VU, VUREC_INFO); } +void recVU0MI_MSUBz() { recVUMI_MSUBz(VU, VUREC_INFO); } +void recVU0MI_MSUBw() { recVUMI_MSUBw(VU, VUREC_INFO); } +#else +void recVU0MI_MSUB() { REC_VUOP(VU0, MSUB); } +void recVU0MI_MSUBi() { REC_VUOP(VU0, MSUBi); } +void recVU0MI_MSUBq() { REC_VUOP(VU0, MSUBq); } +void recVU0MI_MSUBx() { REC_VUOP(VU0, MSUBx); } +void recVU0MI_MSUBy() { REC_VUOP(VU0, MSUBy); } +void recVU0MI_MSUBz() { REC_VUOP(VU0, MSUBz); } +void recVU0MI_MSUBw() { REC_VUOP(VU0, MSUBw); } +#endif + +#ifdef RECOMPILE_VUMI_MSUBA +void recVU0MI_MSUBA() { recVUMI_MSUBA(VU, VUREC_INFO); } +void recVU0MI_MSUBAi() { recVUMI_MSUBAi(VU, VUREC_INFO); } +void recVU0MI_MSUBAq() { recVUMI_MSUBAq(VU, VUREC_INFO); } +void recVU0MI_MSUBAx() { recVUMI_MSUBAx(VU, VUREC_INFO); } +void recVU0MI_MSUBAy() { recVUMI_MSUBAy(VU, VUREC_INFO); } +void recVU0MI_MSUBAz() { recVUMI_MSUBAz(VU, VUREC_INFO); } +void recVU0MI_MSUBAw() { recVUMI_MSUBAw(VU, VUREC_INFO); } +#else +void recVU0MI_MSUBA() { REC_VUOP(VU0, MSUBA); } +void recVU0MI_MSUBAi() { REC_VUOP(VU0, MSUBAi); } +void recVU0MI_MSUBAq() { REC_VUOP(VU0, MSUBAq); } +void recVU0MI_MSUBAx() { REC_VUOP(VU0, MSUBAx); } +void recVU0MI_MSUBAy() { REC_VUOP(VU0, MSUBAy); } +void recVU0MI_MSUBAz() { REC_VUOP(VU0, MSUBAz); } +void recVU0MI_MSUBAw() { REC_VUOP(VU0, MSUBAw); } +#endif + +#ifdef RECOMPILE_VUMI_MAX +void recVU0MI_MAX() { recVUMI_MAX(VU, VUREC_INFO); } +void recVU0MI_MAXi() { recVUMI_MAXi(VU, VUREC_INFO); } +void recVU0MI_MAXx() { recVUMI_MAXx(VU, VUREC_INFO); } +void recVU0MI_MAXy() { recVUMI_MAXy(VU, VUREC_INFO); } +void recVU0MI_MAXz() { recVUMI_MAXz(VU, VUREC_INFO); } +void recVU0MI_MAXw() { recVUMI_MAXw(VU, VUREC_INFO); } +#else +void recVU0MI_MAX() { REC_VUOP(VU0, MAX); } +void recVU0MI_MAXi() { REC_VUOP(VU0, MAXi); } +void recVU0MI_MAXx() { REC_VUOP(VU0, MAXx); } +void recVU0MI_MAXy() { REC_VUOP(VU0, MAXy); } +void recVU0MI_MAXz() { REC_VUOP(VU0, MAXz); } +void recVU0MI_MAXw() { REC_VUOP(VU0, MAXw); } +#endif + +#ifdef RECOMPILE_VUMI_MINI +void recVU0MI_MINI() { recVUMI_MINI(VU, VUREC_INFO); } +void recVU0MI_MINIi() { recVUMI_MINIi(VU, VUREC_INFO); } +void recVU0MI_MINIx() { recVUMI_MINIx(VU, VUREC_INFO); } +void recVU0MI_MINIy() { recVUMI_MINIy(VU, VUREC_INFO); } +void recVU0MI_MINIz() { recVUMI_MINIz(VU, VUREC_INFO); } +void recVU0MI_MINIw() { recVUMI_MINIw(VU, VUREC_INFO); } +#else +void recVU0MI_MINI() { REC_VUOP(VU0, MINI); } +void recVU0MI_MINIi() { REC_VUOP(VU0, MINIi); } +void recVU0MI_MINIx() { REC_VUOP(VU0, MINIx); } +void recVU0MI_MINIy() { REC_VUOP(VU0, MINIy); } +void recVU0MI_MINIz() { REC_VUOP(VU0, MINIz); } +void recVU0MI_MINIw() { REC_VUOP(VU0, MINIw); } +#endif + +#ifdef RECOMPILE_VUMI_FTOI +void recVU0MI_FTOI0() { recVUMI_FTOI0(VU, VUREC_INFO); } +void recVU0MI_FTOI4() { recVUMI_FTOI4(VU, VUREC_INFO); } +void recVU0MI_FTOI12() { recVUMI_FTOI12(VU, VUREC_INFO); } +void recVU0MI_FTOI15() { recVUMI_FTOI15(VU, VUREC_INFO); } +void recVU0MI_ITOF0() { recVUMI_ITOF0(VU, VUREC_INFO); } +void recVU0MI_ITOF4() { recVUMI_ITOF4(VU, VUREC_INFO); } +void recVU0MI_ITOF12() { recVUMI_ITOF12(VU, VUREC_INFO); } +void recVU0MI_ITOF15() { recVUMI_ITOF15(VU, VUREC_INFO); } +#else +void recVU0MI_FTOI0() { REC_VUOP(VU0, FTOI0); } +void recVU0MI_FTOI4() { REC_VUOP(VU0, FTOI4); } +void recVU0MI_FTOI12() { REC_VUOP(VU0, FTOI12); } +void recVU0MI_FTOI15() { REC_VUOP(VU0, FTOI15); } +void recVU0MI_ITOF0() { REC_VUOP(VU0, ITOF0); } +void recVU0MI_ITOF4() { REC_VUOP(VU0, ITOF4); } +void recVU0MI_ITOF12() { REC_VUOP(VU0, ITOF12); } +void recVU0MI_ITOF15() { REC_VUOP(VU0, ITOF15); } +#endif + +void recVU0MI_OPMULA() { recVUMI_OPMULA(VU, VUREC_INFO); } +void recVU0MI_OPMSUB() { recVUMI_OPMSUB(VU, VUREC_INFO); } +void recVU0MI_NOP() { } +void recVU0MI_CLIP() { recVUMI_CLIP(VU, VUREC_INFO); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +#ifdef RECOMPILE_VUMI_MISC + +void recVU0MI_MTIR() { recVUMI_MTIR(VU, VUREC_INFO); } +void recVU0MI_MR32() { recVUMI_MR32(VU, VUREC_INFO); } +void recVU0MI_MFIR() { recVUMI_MFIR(VU, VUREC_INFO); } +void recVU0MI_MOVE() { recVUMI_MOVE(VU, VUREC_INFO); } +void recVU0MI_WAITQ() { recVUMI_WAITQ(VU, VUREC_INFO); } +void recVU0MI_MFP() { recVUMI_MFP(VU, VUREC_INFO); } +void recVU0MI_WAITP() { SysPrintf("vu0 wait p?\n"); } + +#else + +void recVU0MI_MOVE() { REC_VUOP(VU0, MOVE); } +void recVU0MI_MFIR() { REC_VUOP(VU0, MFIR); } +void recVU0MI_MTIR() { REC_VUOP(VU0, MTIR); } +void recVU0MI_MR32() { REC_VUOP(VU0, MR32); } +void recVU0MI_WAITQ() { } +void recVU0MI_MFP() { REC_VUOP(VU0, MFP); } +void recVU0MI_WAITP() { REC_VUOP(VU0, WAITP); } + +#endif + +#ifdef RECOMPILE_VUMI_MATH + +void recVU0MI_SQRT() { recVUMI_SQRT(VU, VUREC_INFO); } +void recVU0MI_RSQRT() { recVUMI_RSQRT(VU, VUREC_INFO); } +void recVU0MI_DIV() { recVUMI_DIV(VU, VUREC_INFO); } + +#else + +void recVU0MI_DIV() { REC_VUOP(VU0, DIV);} +void recVU0MI_SQRT() { REC_VUOP(VU0, SQRT); } +void recVU0MI_RSQRT() { REC_VUOP(VU0, RSQRT); } + +#endif + +#ifdef RECOMPILE_VUMI_E + +void recVU0MI_ESADD() { REC_VUOP(VU0, ESADD); } +void recVU0MI_ERSADD() { REC_VUOP(VU0, ERSADD); } +void recVU0MI_ELENG() { recVUMI_ELENG(VU, VUREC_INFO); } +void recVU0MI_ERLENG() { REC_VUOP(VU0, ERLENG); } +void recVU0MI_EATANxy() { REC_VUOP(VU0, EATANxy); } +void recVU0MI_EATANxz() { REC_VUOP(VU0, EATANxz); } +void recVU0MI_ESUM() { REC_VUOP(VU0, ESUM); } +void recVU0MI_ERCPR() { REC_VUOP(VU0, ERCPR); } +void recVU0MI_ESQRT() { REC_VUOP(VU0, ESQRT); } +void recVU0MI_ERSQRT() { REC_VUOP(VU0, ERSQRT); } +void recVU0MI_ESIN() { REC_VUOP(VU0, ESIN); } +void recVU0MI_EATAN() { REC_VUOP(VU0, EATAN); } +void recVU0MI_EEXP() { REC_VUOP(VU0, EEXP); } + +#else + +void recVU0MI_ESADD() { REC_VUOP(VU0, ESADD); } +void recVU0MI_ERSADD() { REC_VUOP(VU0, ERSADD); } +void recVU0MI_ELENG() { REC_VUOP(VU0, ELENG); } +void recVU0MI_ERLENG() { REC_VUOP(VU0, ERLENG); } +void recVU0MI_EATANxy() { REC_VUOP(VU0, EATANxy); } +void recVU0MI_EATANxz() { REC_VUOP(VU0, EATANxz); } +void recVU0MI_ESUM() { REC_VUOP(VU0, ESUM); } +void recVU0MI_ERCPR() { REC_VUOP(VU0, ERCPR); } +void recVU0MI_ESQRT() { REC_VUOP(VU0, ESQRT); } +void recVU0MI_ERSQRT() { REC_VUOP(VU0, ERSQRT); } +void recVU0MI_ESIN() { REC_VUOP(VU0, ESIN); } +void recVU0MI_EATAN() { REC_VUOP(VU0, EATAN); } +void recVU0MI_EEXP() { REC_VUOP(VU0, EEXP); } + +#endif + +#ifdef RECOMPILE_VUMI_X + +void recVU0MI_XITOP() { recVUMI_XITOP(VU, VUREC_INFO); } +void recVU0MI_XGKICK() { recVUMI_XGKICK(VU, VUREC_INFO); } +void recVU0MI_XTOP() { recVUMI_XTOP(VU, VUREC_INFO); } + +#else + +void recVU0MI_XITOP() { REC_VUOP(VU0, XITOP); } +void recVU0MI_XGKICK() { REC_VUOP(VU0, XGKICK);} +void recVU0MI_XTOP() { REC_VUOP(VU0, XTOP);} + +#endif + +#ifdef RECOMPILE_VUMI_RANDOM + +void recVU0MI_RINIT() { recVUMI_RINIT(VU, VUREC_INFO); } +void recVU0MI_RGET() { recVUMI_RGET(VU, VUREC_INFO); } +void recVU0MI_RNEXT() { recVUMI_RNEXT(VU, VUREC_INFO); } +void recVU0MI_RXOR() { recVUMI_RXOR(VU, VUREC_INFO); } + +#else + +void recVU0MI_RINIT() { REC_VUOP(VU0, RINIT); } +void recVU0MI_RGET() { REC_VUOP(VU0, RGET); } +void recVU0MI_RNEXT() { REC_VUOP(VU0, RNEXT); } +void recVU0MI_RXOR() { REC_VUOP(VU0, RXOR); } + +#endif + +#ifdef RECOMPILE_VUMI_FLAG + +void recVU0MI_FSAND() { recVUMI_FSAND(VU, VUREC_INFO); } +void recVU0MI_FSEQ() { recVUMI_FSEQ(VU, VUREC_INFO); } +void recVU0MI_FSOR() { recVUMI_FSOR(VU, VUREC_INFO); } +void recVU0MI_FSSET() { recVUMI_FSSET(VU, VUREC_INFO); } +void recVU0MI_FMEQ() { recVUMI_FMEQ(VU, VUREC_INFO); } +void recVU0MI_FMOR() { recVUMI_FMOR(VU, VUREC_INFO); } +void recVU0MI_FCEQ() { recVUMI_FCEQ(VU, VUREC_INFO); } +void recVU0MI_FCOR() { recVUMI_FCOR(VU, VUREC_INFO); } +void recVU0MI_FCSET() { recVUMI_FCSET(VU, VUREC_INFO); } +void recVU0MI_FCGET() { recVUMI_FCGET(VU, VUREC_INFO); } +void recVU0MI_FCAND() { recVUMI_FCAND(VU, VUREC_INFO); } +void recVU0MI_FMAND() { recVUMI_FMAND(VU, VUREC_INFO); } + +#else + +void recVU0MI_FSAND() { REC_VUOP(VU0, FSAND); } +void recVU0MI_FSEQ() { REC_VUOP(VU0, FSEQ); } +void recVU0MI_FSOR() { REC_VUOP(VU0, FSOR); } +void recVU0MI_FSSET() { REC_VUOP(VU0, FSSET); } +void recVU0MI_FMAND() { REC_VUOP(VU0, FMAND); } +void recVU0MI_FMEQ() { REC_VUOP(VU0, FMEQ); } +void recVU0MI_FMOR() { REC_VUOP(VU0, FMOR); } +void recVU0MI_FCAND() { REC_VUOP(VU0, FCAND); } +void recVU0MI_FCEQ() { REC_VUOP(VU0, FCEQ); } +void recVU0MI_FCOR() { REC_VUOP(VU0, FCOR); } +void recVU0MI_FCSET() { REC_VUOP(VU0, FCSET); } +void recVU0MI_FCGET() { REC_VUOP(VU0, FCGET); } + +#endif + +#ifdef RECOMPILE_VUMI_LOADSTORE + +void recVU0MI_LQ() { recVUMI_LQ(VU, VUREC_INFO); } +void recVU0MI_LQD() { recVUMI_LQD(VU, VUREC_INFO); } +void recVU0MI_LQI() { recVUMI_LQI(VU, VUREC_INFO); } +void recVU0MI_SQ() { recVUMI_SQ(VU, VUREC_INFO); } +void recVU0MI_SQD() { recVUMI_SQD(VU, VUREC_INFO); } +void recVU0MI_SQI() { recVUMI_SQI(VU, VUREC_INFO); } +void recVU0MI_ILW() { recVUMI_ILW(VU, VUREC_INFO); } +void recVU0MI_ISW() { recVUMI_ISW(VU, VUREC_INFO); } +void recVU0MI_ILWR() { recVUMI_ILWR(VU, VUREC_INFO); } +void recVU0MI_ISWR() { recVUMI_ISWR(VU, VUREC_INFO); } + +#else + +void recVU0MI_LQ() { REC_VUOP(VU0, LQ); } +void recVU0MI_LQD() { REC_VUOP(VU0, LQD); } +void recVU0MI_LQI() { REC_VUOP(VU0, LQI); } +void recVU0MI_SQ() { REC_VUOP(VU0, SQ); } +void recVU0MI_SQD() { REC_VUOP(VU0, SQD); } +void recVU0MI_SQI() { REC_VUOP(VU0, SQI); } +void recVU0MI_ILW() { REC_VUOP(VU0, ILW); } +void recVU0MI_ISW() { REC_VUOP(VU0, ISW); } +void recVU0MI_ILWR() { REC_VUOP(VU0, ILWR); } +void recVU0MI_ISWR() { REC_VUOP(VU0, ISWR); } + +#endif + +#ifdef RECOMPILE_VUMI_ARITHMETIC + +void recVU0MI_IADD() { recVUMI_IADD(VU, VUREC_INFO); } +void recVU0MI_IADDI() { recVUMI_IADDI(VU, VUREC_INFO); } +void recVU0MI_IADDIU() { recVUMI_IADDIU(VU, VUREC_INFO); } +void recVU0MI_IOR() { recVUMI_IOR(VU, VUREC_INFO); } +void recVU0MI_ISUB() { recVUMI_ISUB(VU, VUREC_INFO); } +void recVU0MI_IAND() { recVUMI_IAND(VU, VUREC_INFO); } +void recVU0MI_ISUBIU() { recVUMI_ISUBIU(VU, VUREC_INFO); } + +#else + +void recVU0MI_IADD() { REC_VUOP(VU0, IADD); } +void recVU0MI_IADDI() { REC_VUOP(VU0, IADDI); } +void recVU0MI_IADDIU() { REC_VUOP(VU0, IADDIU); } +void recVU0MI_IOR() { REC_VUOP(VU0, IOR); } +void recVU0MI_ISUB() { REC_VUOP(VU0, ISUB); } +void recVU0MI_IAND() { REC_VUOP(VU0, IAND); } +void recVU0MI_ISUBIU() { REC_VUOP(VU0, ISUBIU); } + +#endif + +#ifdef RECOMPILE_VUMI_BRANCH + +void recVU0MI_IBEQ() { recVUMI_IBEQ(VU, VUREC_INFO); } +void recVU0MI_IBGEZ() { recVUMI_IBGEZ(VU, VUREC_INFO); } +void recVU0MI_IBLTZ() { recVUMI_IBLTZ(VU, VUREC_INFO); } +void recVU0MI_IBLEZ() { recVUMI_IBLEZ(VU, VUREC_INFO); } +void recVU0MI_IBGTZ() { recVUMI_IBGTZ(VU, VUREC_INFO); } +void recVU0MI_IBNE() { recVUMI_IBNE(VU, VUREC_INFO); } +void recVU0MI_B() { recVUMI_B(VU, VUREC_INFO); } +void recVU0MI_BAL() { recVUMI_BAL(VU, VUREC_INFO); } +void recVU0MI_JR() { recVUMI_JR(VU, VUREC_INFO); } +void recVU0MI_JALR() { recVUMI_JALR(VU, VUREC_INFO); } + +#else + +void recVU0MI_IBEQ() { REC_VUOP(VU0, IBEQ); } +void recVU0MI_IBGEZ() { REC_VUOP(VU0, IBGEZ); } +void recVU0MI_IBGTZ() { REC_VUOP(VU0, IBGTZ); } +void recVU0MI_IBLTZ() { REC_VUOP(VU0, IBLTZ); } +void recVU0MI_IBLEZ() { REC_VUOP(VU0, IBLEZ); } +void recVU0MI_IBNE() { REC_VUOP(VU0, IBNE); } +void recVU0MI_B() { REC_VUOP(VU0, B); } +void recVU0MI_BAL() { REC_VUOP(VU0, BAL); } +void recVU0MI_JR() { REC_VUOP(VU0, JR); } +void recVU0MI_JALR() { REC_VUOP(VU0, JALR); } + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iVU0micro.h b/pcsx2/x86/iVU0micro.h new file mode 100644 index 0000000000..ef7faa4d49 --- /dev/null +++ b/pcsx2/x86/iVU0micro.h @@ -0,0 +1,229 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IVU0MICRO_H__ +#define __IVU0MICRO_H__ + +void recResetVU0(); +void recExecuteVU0Block( void ); +void recClearVU0( u32 Addr, u32 Size ); + +extern void (*recVU0_LOWER_OPCODE[128])(); +extern void (*recVU0_UPPER_OPCODE[64])(); + +extern void (*recVU0_UPPER_FD_00_TABLE[32])(); +extern void (*recVU0_UPPER_FD_01_TABLE[32])(); +extern void (*recVU0_UPPER_FD_10_TABLE[32])(); +extern void (*recVU0_UPPER_FD_11_TABLE[32])(); + +extern void (*recVU1_LOWER_OPCODE[128])(); +extern void (*recVU1_UPPER_OPCODE[64])(); + +extern void (*recVU1_UPPER_FD_00_TABLE[32])(); +extern void (*recVU1_UPPER_FD_01_TABLE[32])(); +extern void (*recVU1_UPPER_FD_10_TABLE[32])(); +extern void (*recVU1_UPPER_FD_11_TABLE[32])(); + +void recVU0_UPPER_FD_00(); +void recVU0_UPPER_FD_01(); +void recVU0_UPPER_FD_10(); +void recVU0_UPPER_FD_11(); + +void recVU0LowerOP(); +void recVU0LowerOP_T3_00(); +void recVU0LowerOP_T3_01(); +void recVU0LowerOP_T3_10(); +void recVU0LowerOP_T3_11(); + +void recVU0unknown(); + + + +/***************************************** + VU0 Micromode Upper instructions +*****************************************/ + +void recVU0MI_ABS(); +void recVU0MI_ADD(); +void recVU0MI_ADDi(); +void recVU0MI_ADDq(); +void recVU0MI_ADDx(); +void recVU0MI_ADDy(); +void recVU0MI_ADDz(); +void recVU0MI_ADDw(); +void recVU0MI_ADDA(); +void recVU0MI_ADDAi(); +void recVU0MI_ADDAq(); +void recVU0MI_ADDAx(); +void recVU0MI_ADDAy(); +void recVU0MI_ADDAz(); +void recVU0MI_ADDAw(); +void recVU0MI_SUB(); +void recVU0MI_SUBi(); +void recVU0MI_SUBq(); +void recVU0MI_SUBx(); +void recVU0MI_SUBy(); +void recVU0MI_SUBz(); +void recVU0MI_SUBw(); +void recVU0MI_SUBA(); +void recVU0MI_SUBAi(); +void recVU0MI_SUBAq(); +void recVU0MI_SUBAx(); +void recVU0MI_SUBAy(); +void recVU0MI_SUBAz(); +void recVU0MI_SUBAw(); +void recVU0MI_MUL(); +void recVU0MI_MULi(); +void recVU0MI_MULq(); +void recVU0MI_MULx(); +void recVU0MI_MULy(); +void recVU0MI_MULz(); +void recVU0MI_MULw(); +void recVU0MI_MULA(); +void recVU0MI_MULAi(); +void recVU0MI_MULAq(); +void recVU0MI_MULAx(); +void recVU0MI_MULAy(); +void recVU0MI_MULAz(); +void recVU0MI_MULAw(); +void recVU0MI_MADD(); +void recVU0MI_MADDi(); +void recVU0MI_MADDq(); +void recVU0MI_MADDx(); +void recVU0MI_MADDy(); +void recVU0MI_MADDz(); +void recVU0MI_MADDw(); +void recVU0MI_MADDA(); +void recVU0MI_MADDAi(); +void recVU0MI_MADDAq(); +void recVU0MI_MADDAx(); +void recVU0MI_MADDAy(); +void recVU0MI_MADDAz(); +void recVU0MI_MADDAw(); +void recVU0MI_MSUB(); +void recVU0MI_MSUBi(); +void recVU0MI_MSUBq(); +void recVU0MI_MSUBx(); +void recVU0MI_MSUBy(); +void recVU0MI_MSUBz(); +void recVU0MI_MSUBw(); +void recVU0MI_MSUBA(); +void recVU0MI_MSUBAi(); +void recVU0MI_MSUBAq(); +void recVU0MI_MSUBAx(); +void recVU0MI_MSUBAy(); +void recVU0MI_MSUBAz(); +void recVU0MI_MSUBAw(); +void recVU0MI_MAX(); +void recVU0MI_MAXi(); +void recVU0MI_MAXx(); +void recVU0MI_MAXy(); +void recVU0MI_MAXz(); +void recVU0MI_MAXw(); +void recVU0MI_MINI(); +void recVU0MI_MINIi(); +void recVU0MI_MINIx(); +void recVU0MI_MINIy(); +void recVU0MI_MINIz(); +void recVU0MI_MINIw(); +void recVU0MI_OPMULA(); +void recVU0MI_OPMSUB(); +void recVU0MI_NOP(); +void recVU0MI_FTOI0(); +void recVU0MI_FTOI4(); +void recVU0MI_FTOI12(); +void recVU0MI_FTOI15(); +void recVU0MI_ITOF0(); +void recVU0MI_ITOF4(); +void recVU0MI_ITOF12(); +void recVU0MI_ITOF15(); +void recVU0MI_CLIP(); + +/***************************************** + VU0 Micromode Lower instructions +*****************************************/ + +void recVU0MI_DIV(); +void recVU0MI_SQRT(); +void recVU0MI_RSQRT(); +void recVU0MI_IADD(); +void recVU0MI_IADDI(); +void recVU0MI_IADDIU(); +void recVU0MI_IAND(); +void recVU0MI_IOR(); +void recVU0MI_ISUB(); +void recVU0MI_ISUBIU(); +void recVU0MI_MOVE(); +void recVU0MI_MFIR(); +void recVU0MI_MTIR(); +void recVU0MI_MR32(); +void recVU0MI_LQ(); +void recVU0MI_LQD(); +void recVU0MI_LQI(); +void recVU0MI_SQ(); +void recVU0MI_SQD(); +void recVU0MI_SQI(); +void recVU0MI_ILW(); +void recVU0MI_ISW(); +void recVU0MI_ILWR(); +void recVU0MI_ISWR(); +void recVU0MI_RINIT(); +void recVU0MI_RGET(); +void recVU0MI_RNEXT(); +void recVU0MI_RXOR(); +void recVU0MI_WAITQ(); +void recVU0MI_FSAND(); +void recVU0MI_FSEQ(); +void recVU0MI_FSOR(); +void recVU0MI_FSSET(); +void recVU0MI_FMAND(); +void recVU0MI_FMEQ(); +void recVU0MI_FMOR(); +void recVU0MI_FCAND(); +void recVU0MI_FCEQ(); +void recVU0MI_FCOR(); +void recVU0MI_FCSET(); +void recVU0MI_FCGET(); +void recVU0MI_IBEQ(); +void recVU0MI_IBGEZ(); +void recVU0MI_IBGTZ(); +void recVU0MI_IBLEZ(); +void recVU0MI_IBLTZ(); +void recVU0MI_IBNE(); +void recVU0MI_B(); +void recVU0MI_BAL(); +void recVU0MI_JR(); +void recVU0MI_JALR(); +void recVU0MI_MFP(); +void recVU0MI_WAITP(); +void recVU0MI_ESADD(); +void recVU0MI_ERSADD(); +void recVU0MI_ELENG(); +void recVU0MI_ERLENG(); +void recVU0MI_EATANxy(); +void recVU0MI_EATANxz(); +void recVU0MI_ESUM(); +void recVU0MI_ERCPR(); +void recVU0MI_ESQRT(); +void recVU0MI_ERSQRT(); +void recVU0MI_ESIN(); +void recVU0MI_EATAN(); +void recVU0MI_EEXP(); +void recVU0MI_XITOP(); + +#endif /* __IVU0MICRO_H__ */ diff --git a/pcsx2/x86/iVU1micro.c b/pcsx2/x86/iVU1micro.c new file mode 100644 index 0000000000..1561032e2d --- /dev/null +++ b/pcsx2/x86/iVU1micro.c @@ -0,0 +1,218 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" +#include "VU.h" +#include "VUmicro.h" +#include "iVUmicro.h" +#include "iVU1micro.h" +#include "iVUops.h" +#include "VUops.h" + +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +#define VU ((VURegs*)&VU1) + +u32 vu1recpcold = -1; +u32 vu1reccountold = -1; + +static _vuopinfo _opinfo[256]; + +//Lower/Upper instructions can use that.. +#define _Ft_ ((VU1.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((VU1.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((VU1.code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X ((VU1.code>>24) & 0x1) +#define _Y ((VU1.code>>23) & 0x1) +#define _Z ((VU1.code>>22) & 0x1) +#define _W ((VU1.code>>21) & 0x1) + +#define _Fsf_ ((VU1.code >> 21) & 0x03) +#define _Ftf_ ((VU1.code >> 23) & 0x03) + + +#define VU1_VFx_ADDR(x) (uptr)&VU1.VF[x].UL[0] +#define VU1_VFy_ADDR(x) (uptr)&VU1.VF[x].UL[1] +#define VU1_VFz_ADDR(x) (uptr)&VU1.VF[x].UL[2] +#define VU1_VFw_ADDR(x) (uptr)&VU1.VF[x].UL[3] + +#define VU1_REGR_ADDR (uptr)&VU1.VI[REG_R] +#define VU1_REGI_ADDR (uptr)&VU1.VI[REG_I] +#define VU1_REGQ_ADDR (uptr)&VU1.VI[REG_Q] +#define VU1_REGMAC_ADDR (uptr)&VU1.VI[REG_MAC_FLAG] + +#define VU1_VI_ADDR(x) (uptr)&VU1.VI[x].UL + +#define VU1_ACCx_ADDR (uptr)&VU1.ACC.UL[0] +#define VU1_ACCy_ADDR (uptr)&VU1.ACC.UL[1] +#define VU1_ACCz_ADDR (uptr)&VU1.ACC.UL[2] +#define VU1_ACCw_ADDR (uptr)&VU1.ACC.UL[3] + +static void VU1RecompileBlock(void); + +void recVU1Init() +{ + SuperVUInit(1); +} + +void recVU1Shutdown() +{ + SuperVUDestroy(1); +} + +void recResetVU1( void ) { + + if( CHECK_VU1REC ) { + SuperVUReset(1); + } + + vu1recpcold = 0; +#ifndef __x86_64__ + x86FpuState = FPU_STATE; +#endif + iCWstate = 0; + + branch = 0; +} + +static void iDumpBlock() +{ + FILE *f; + char filename[ 256 ]; + u32 *mem; + u32 i; + +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf( filename, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); +#endif + SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename ); + + f = fopen( filename, "wb" ); + for ( i = VU1.VI[REG_TPC].UL; i < pc; i += 8 ) { + char* pstr; + mem = (u32*)&VU1.Micro[i]; + + pstr = disVU1MicroUF( mem[1], i+4 ); + fprintf(f, "%x: %-40s ", i, pstr); + + pstr = disVU1MicroLF( mem[0], i ); + fprintf(f, "%s\n", pstr); + } + fclose( f ); +} + +u32 g_VUProgramId = 0; + +#ifdef _DEBUG +static u32 vuprogcount = 0; +extern u32 vudump; +#endif + +void recExecuteVU1Block(void) +{ +#ifdef _DEBUG + vuprogcount++; + + if( vudump & 8 ) { + __Log("start vu1: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount); + } +#endif + + if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){ + //SysPrintf("Execute block VU1, VU1 not busy\n"); + return; + } + + if (CHECK_VU1REC) + { + if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) { +#ifdef CPU_LOG + SysPrintf("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x100; + VU->cycle++; + return; + } + + assert( (VU1.VI[ REG_TPC ].UL&7) == 0 ); + + //__Log("prog: %x %x %x\n", vuprogcount, *(int*)0x1883a740, *(int*)0x18fe5fe0); + //for(i = 1; i < 32; ++i) __Log("vf%d: %x %x %x %x, vi: %x\n", i, VU0.VF[i].UL[3], VU0.VF[i].UL[2], VU0.VF[i].UL[1], VU0.VF[i].UL[0], VU0.VI[i].UL); + + //if( VU1.VI[ REG_TPC ].UL == 0x670 ) { +// __Log("VU: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount); +// iDumpVU1Registers(); +// vudump |= 8; + + FreezeXMMRegs(1); + // while loop needed since not always will return finished + do { + SuperVUExecuteProgram(VU1.VI[ REG_TPC ].UL, 1); + } + while( VU0.VI[ REG_VPU_STAT ].UL&0x100 ); + FreezeXMMRegs(0); + +// __Log("eVU: %x\n", VU1.VI[ REG_TPC ].UL); +// iDumpVU1Registers(); + } + else { +#ifdef _DEBUG + if( (vudump&8) ) { + __Log("tVU: %x\n", VU1.VI[ REG_TPC ].UL); + iDumpVU1Registers(); + } +#endif + + while(VU0.VI[ REG_VPU_STAT ].UL&0x100) + intExecuteVU1Block(); + } +} + +void recClearVU1( u32 Addr, u32 Size ) { + assert( (Addr&7) == 0 ); + + if( CHECK_VU1REC ) { + SuperVUClear(Addr, Size*4, 1); + } +} + +#endif diff --git a/pcsx2/x86/iVU1micro.h b/pcsx2/x86/iVU1micro.h new file mode 100644 index 0000000000..9db687a9d8 --- /dev/null +++ b/pcsx2/x86/iVU1micro.h @@ -0,0 +1,31 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IVU1MICRO_H__ +#define __IVU1MICRO_H__ + +void recVU1Init(); +void recVU1Shutdown(); +void recResetVU1(); +void recExecuteVU1Block( void ); +void recClearVU1( u32 Addr, u32 Size ); + +extern u32 vudump; +void iDumpVU1Registers(); + +#endif /* __IVU1MICRO_H__ */ diff --git a/pcsx2/x86/iVUmicro.c b/pcsx2/x86/iVUmicro.c new file mode 100644 index 0000000000..9eeccc16fb --- /dev/null +++ b/pcsx2/x86/iVUmicro.c @@ -0,0 +1,5346 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#define PLUGINtypedefs // for GSgifTransfer1 + +#include "Common.h" +#include "GS.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "iVUmicro.h" +#include "iVU0micro.h" +#include "iVU1micro.h" +#include "iVUops.h" +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +extern _GSgifTransfer1 GSgifTransfer1; + +int g_VuNanHandling = 0; // for now enable all the time + +int vucycle; +int vucycleold; +_vuopinfo *cinfo = NULL; + +//Lower/Upper instructions can use that.. +#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X (( VU->code>>24) & 0x1) +#define _Y (( VU->code>>23) & 0x1) +#define _Z (( VU->code>>22) & 0x1) +#define _W (( VU->code>>21) & 0x1) + +#define _XYZW_SS (_X+_Y+_Z+_W==1) + +#define _Fsf_ (( VU->code >> 21) & 0x03) +#define _Ftf_ (( VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] +#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] +#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] + +#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] +#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] +#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] + +#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) + +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] +#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] +#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] +#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] + +#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) + +PCSX2_ALIGNED16(float recMult_float_to_int4[4]) = { 16.0, 16.0, 16.0, 16.0 }; +PCSX2_ALIGNED16(float recMult_float_to_int12[4]) = { 4096.0, 4096.0, 4096.0, 4096.0 }; +PCSX2_ALIGNED16(float recMult_float_to_int15[4]) = { 32768.0, 32768.0, 32768.0, 32768.0 }; + +PCSX2_ALIGNED16(float recMult_int_to_float4[4]) = { 0.0625f, 0.0625f, 0.0625f, 0.0625f }; +PCSX2_ALIGNED16(float recMult_int_to_float12[4]) = { 0.000244140625, 0.000244140625, 0.000244140625, 0.000244140625 }; +PCSX2_ALIGNED16(float recMult_int_to_float15[4]) = { 0.000030517578125, 0.000030517578125, 0.000030517578125, 0.000030517578125 }; +static s32 bpc; +_VURegsNum* g_VUregs = NULL; +u8 g_MACFlagTransform[256] = {0}; // used to flip xyzw bits + +static int SSEmovMask[ 16 ][ 4 ] = +{ +{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +{ 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF }, +{ 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 }, +{ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, +{ 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 }, +{ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, +{ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, +{ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, +{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 }, +{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF }, +{ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 }, +{ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, +{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 }, +{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, +{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, +{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } +}; + +#define VU_SWAPSRC 0xf090 // don't touch + +#define _vuIsRegSwappedWithTemp() (VU_SWAPSRC & (1<<_X_Y_Z_W)) + +// use for allocating vi regs +#define ALLOCTEMPX86(mode) _allocX86reg(-1, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) +#define ALLOCVI(vi, mode) _allocX86reg(-1, X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), vi, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) +#define ADD_VI_NEEDED(vi) _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), vi); + +// 1 - src, 0 - dest wzyx +void VU_MERGE0(int dest, int src) { // 0000 +} +void VU_MERGE1(int dest, int src) { // 1000 + SSE_MOVHLPS_XMM_to_XMM(src, dest); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc4); +} +void VU_MERGE2(int dest, int src) { // 0100 + SSE_MOVHLPS_XMM_to_XMM(src, dest); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x64); +} +void VU_MERGE3(int dest, int src) { // 1100 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); +} +void VU_MERGE4(int dest, int src) { // 0010s + SSE_MOVSS_XMM_to_XMM(src, dest); + SSE_SHUFPS_XMM_to_XMM(src, dest, 0xe4); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE5(int dest, int src) { // 1010 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xd8); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd8); +} +void VU_MERGE6(int dest, int src) { // 0110 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x9c); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x78); +} +void VU_MERGE7(int dest, int src) { // 1110s + SSE_MOVSS_XMM_to_XMM(src, dest); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE8(int dest, int src) { // 0001 + SSE_MOVSS_XMM_to_XMM(dest, src); +} +void VU_MERGE9(int dest, int src) { // 1001 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc9); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd2); +} +void VU_MERGE10(int dest, int src) { // 0101 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x8d); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x72); +} +void VU_MERGE11(int dest, int src) { // 1101 + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); +} +void VU_MERGE12(int dest, int src) { // 0011s + SSE_SHUFPS_XMM_to_XMM(src, dest, 0xe4); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE13(int dest, int src) { // 1011s + SSE_MOVHLPS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, dest, 0x64); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE14(int dest, int src) { // 0111s + SSE_MOVHLPS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, dest, 0xc4); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE15(int dest, int src) { // 1111s + SSE_MOVAPS_XMM_to_XMM(dest, src); +} + +typedef void (*VUMERGEFN)(int dest, int src); +static VUMERGEFN s_VuMerge[16] = { + VU_MERGE0, VU_MERGE1, VU_MERGE2, VU_MERGE3, + VU_MERGE4, VU_MERGE5, VU_MERGE6, VU_MERGE7, + VU_MERGE8, VU_MERGE9, VU_MERGE10, VU_MERGE11, + VU_MERGE12, VU_MERGE13, VU_MERGE14, VU_MERGE15 }; +/* +#define VU_MERGE_REGS(dest, src) { \ + if( dest != src ) s_VuMerge[_X_Y_Z_W](dest, src); \ +} \ + +#define VU_MERGE_REGS_CUSTOM(dest, src, xyzw) { \ + if( dest != src ) s_VuMerge[xyzw](dest, src); \ +} \ +*/ +void VU_MERGE_REGS_CUSTOM(int dest, int src, int xyzw) +{ + xyzw &= 0xf; + + if(dest != src && xyzw != 0) + { + if(cpucaps.hasStreamingSIMD4Extensions) + { + xyzw = ((xyzw & 1) << 3) | ((xyzw & 2) << 1) | ((xyzw & 4) >> 1) | ((xyzw & 8) >> 3); + + SSE4_BLENDPS_XMM_to_XMM(dest, src, xyzw); + } + else + { + s_VuMerge[xyzw](dest, src); + } + } +} + +#define VU_MERGE_REGS(dest, src) { \ + VU_MERGE_REGS_CUSTOM(dest, src, _X_Y_Z_W); \ +} \ + +void _unpackVF_xyzw(int dstreg, int srcreg, int xyzw) +{ + // don't use pshufd + if( dstreg == srcreg || !cpucaps.hasStreamingSIMD3Extensions) { + if( dstreg != srcreg ) SSE_MOVAPS_XMM_to_XMM(dstreg, srcreg); + switch (xyzw) { + case 0: SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0x00); break; + case 1: SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0x55); break; + case 2: SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0xaa); break; + case 3: SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0xff); break; + } + } + else { +/* + switch (xyzw) { + case 0: + SSE3_MOVSLDUP_XMM_to_XMM(dstreg, srcreg); + SSE_MOVLHPS_XMM_to_XMM(dstreg, dstreg); + break; + case 1: + SSE3_MOVSHDUP_XMM_to_XMM(dstreg, srcreg); + SSE_MOVLHPS_XMM_to_XMM(dstreg, dstreg); + break; + case 2: + SSE3_MOVSLDUP_XMM_to_XMM(dstreg, srcreg); + SSE_MOVHLPS_XMM_to_XMM(dstreg, dstreg); + break; + case 3: + SSE3_MOVSHDUP_XMM_to_XMM(dstreg, srcreg); + SSE_MOVHLPS_XMM_to_XMM(dstreg, dstreg); + break; + } +*/ + switch (xyzw) { + case 0: + SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x00); + break; + case 1: + SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x55); + break; + case 2: + SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xaa); + break; + case 3: + SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xff); + break; + } + } +} + +void _unpackVFSS_xyzw(int dstreg, int srcreg, int xyzw) +{ + if( cpucaps.hasStreamingSIMD4Extensions ) { + switch (xyzw) { + case 0: SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(0, 0, 0)); break; + case 1: SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(1, 0, 0)); break; + case 2: SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(2, 0, 0)); break; + case 3: SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(3, 0, 0)); break; + } + } + else { + switch (xyzw) { + case 0: + if( dstreg != srcreg ) SSE_MOVAPS_XMM_to_XMM(dstreg, srcreg); + break; + case 1: + if( cpucaps.hasStreamingSIMD3Extensions ) SSE3_MOVSHDUP_XMM_to_XMM(dstreg, srcreg); + else { + if( dstreg != srcreg ) SSE_MOVAPS_XMM_to_XMM(dstreg, srcreg); + SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0x55); + } + break; + case 2: + SSE_MOVHLPS_XMM_to_XMM(dstreg, srcreg); + break; + case 3: + if( cpucaps.hasStreamingSIMD3Extensions && dstreg != srcreg ) { + SSE3_MOVSHDUP_XMM_to_XMM(dstreg, srcreg); + SSE_MOVHLPS_XMM_to_XMM(dstreg, dstreg); + } + else { + if( dstreg != srcreg ) SSE_MOVAPS_XMM_to_XMM(dstreg, srcreg); + SSE_SHUFPS_XMM_to_XMM(dstreg, dstreg, 0xff); + } + break; + } + } +} + +void _vuFlipRegSS(VURegs * VU, int reg) +{ + assert( _XYZW_SS ); + if( _Y ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xe1); + else if( _Z ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xc6); + else if( _W ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x27); +} + +void _vuMoveSS(VURegs * VU, int dstreg, int srcreg) +{ + assert( _XYZW_SS ); + if( _Y ) _unpackVFSS_xyzw(dstreg, srcreg, 1); + else if( _Z ) _unpackVFSS_xyzw(dstreg, srcreg, 2); + else if( _W ) _unpackVFSS_xyzw(dstreg, srcreg, 3); + else _unpackVFSS_xyzw(dstreg, srcreg, 0); +} + +void _recvuFMACflush(VURegs * VU) { + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + if ((vucycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { +#ifdef VUM_LOG +// if (Log) { VUM_LOG("flushing FMAC pipe[%d]\n", i); } +#endif + VU->fmac[i].enable = 0; + } + } +} + +void _recvuFDIVflush(VURegs * VU) { + if (VU->fdiv.enable == 0) return; + + if ((vucycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { +// SysPrintf("flushing FDIV pipe\n"); + VU->fdiv.enable = 0; + } +} + +void _recvuEFUflush(VURegs * VU) { + if (VU->efu.enable == 0) return; + + if ((vucycle - VU->efu.sCycle) >= VU->efu.Cycle) { +// SysPrintf("flushing FDIV pipe\n"); + VU->efu.enable = 0; + } +} + +void _recvuTestPipes(VURegs * VU) { + _recvuFMACflush(VU); + _recvuFDIVflush(VU); + _recvuEFUflush(VU); +} + +void _recvuFMACTestStall(VURegs * VU, int reg, int xyzw) { + int cycle; + int i; + u32 mask = 0; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + if (VU->fmac[i].reg == reg && + (VU->fmac[i].xyzw & xyzw)) break; + } + + if (i == 8) return; + + // do a perchannel delay + // old code +// cycle = VU->fmac[i].Cycle - (vucycle - VU->fmac[i].sCycle); + + // new code + mask = 4; // w +// if( VU->fmac[i].xyzw & 1 ) mask = 4; // w +// else if( VU->fmac[i].xyzw & 2 ) mask = 3; // z +// else if( VU->fmac[i].xyzw & 4 ) mask = 2; // y +// else { +// assert(VU->fmac[i].xyzw & 8 ); +// mask = 1; // x +// } + +// mask = 0; +// if( VU->fmac[i].xyzw & 1 ) mask++; // w +// else if( VU->fmac[i].xyzw & 2 ) mask++; // z +// else if( VU->fmac[i].xyzw & 4 ) mask++; // y +// else if( VU->fmac[i].xyzw & 8 ) mask++; // x + + assert( (int)VU->fmac[i].sCycle < (int)vucycle ); + cycle = 0; + if( vucycle - VU->fmac[i].sCycle < mask ) + cycle = mask - (vucycle - VU->fmac[i].sCycle); + + VU->fmac[i].enable = 0; + vucycle+= cycle; + _recvuTestPipes(VU); +} + +void _recvuFMACAdd(VURegs * VU, int reg, int xyzw) { + int i; + + /* find a free fmac pipe */ + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 1) continue; + break; + } + if (i==8) { + SysPrintf("*PCSX2*: error , out of fmacs\n"); + } + +#ifdef VUM_LOG +// if (Log) { VUM_LOG("adding FMAC pipe[%d]; reg %d\n", i, reg); } +#endif + VU->fmac[i].enable = 1; + VU->fmac[i].sCycle = vucycle; + VU->fmac[i].Cycle = 3; + VU->fmac[i].xyzw = xyzw; + VU->fmac[i].reg = reg; +} + +void _recvuFDIVAdd(VURegs * VU, int cycles) { +// SysPrintf("adding FDIV pipe\n"); + VU->fdiv.enable = 1; + VU->fdiv.sCycle = vucycle; + VU->fdiv.Cycle = cycles; +} + +void _recvuEFUAdd(VURegs * VU, int cycles) { +// SysPrintf("adding EFU pipe\n"); + VU->efu.enable = 1; + VU->efu.sCycle = vucycle; + VU->efu.Cycle = cycles; +} + +void _recvuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + + if( VUregsn->VFread0 && (VUregsn->VFread0 == VUregsn->VFread1) ) { + _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw|VUregsn->VFr1xyzw); + } + else { + if (VUregsn->VFread0) { + _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); + } + if (VUregsn->VFread1) { + _recvuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); + } + } +} + +void _recvuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VFwrite) { + _recvuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); + } else + if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) { +// SysPrintf("REG_CLIP_FLAG pipe\n"); + _recvuFMACAdd(VU, -REG_CLIP_FLAG, 0); + } else { + _recvuFMACAdd(VU, 0, 0); + } +} + +void _recvuFlushFDIV(VURegs * VU) { + int cycle; + + if (VU->fdiv.enable == 0) return; + + cycle = VU->fdiv.Cycle - (vucycle - VU->fdiv.sCycle); +// SysPrintf("waiting FDIV pipe %d\n", cycle); + VU->fdiv.enable = 0; + vucycle+= cycle; +} + +void _recvuFlushEFU(VURegs * VU) { + int cycle; + + if (VU->efu.enable == 0) return; + + cycle = VU->efu.Cycle - (vucycle - VU->efu.sCycle); +// SysPrintf("waiting FDIV pipe %d\n", cycle); + VU->efu.enable = 0; + vucycle+= cycle; +} + +void _recvuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _recvuFlushFDIV(VU); +} + +void _recvuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _recvuFlushEFU(VU); +} + +void _recvuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + if (VUregsn->VIwrite & (1 << REG_Q)) { + _recvuFDIVAdd(VU, VUregsn->cycles); + } +} + +void _recvuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + if (VUregsn->VIwrite & (1 << REG_P)) { + _recvuEFUAdd(VU, VUregsn->cycles); + } +} + +void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; + } +} + +void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _recvuTestFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _recvuTestEFUStalls(VU, VUregsn); break; + } +} + +void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; + } +} + +void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _recvuAddFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _recvuAddEFUStalls(VU, VUregsn); break; + } +} + + +void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs) +{ + _VURegsNum* lregs; + _VURegsNum* uregs; + int *ptr; + + lregs = pCodeRegs; + uregs = pCodeRegs+1; + + ptr = (int*)&VU->Micro[pc]; + pc += 8; + + if (ptr[1] & 0x40000000) { // EOP + branch |= 8; + } + + VU->code = ptr[1]; + if (VU == &VU1) { + VU1regs_UPPER_OPCODE[VU->code & 0x3f](uregs); + } else { + VU0regs_UPPER_OPCODE[VU->code & 0x3f](uregs); + } + + _recvuTestUpperStalls(VU, uregs); + switch(VU->code & 0x3f) { + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1d: case 0x1f: + case 0x2b: case 0x2f: + break; + + case 0x3c: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3d: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3e: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3f: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: case 0xb: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + + if (uregs->VIread & (1 << REG_Q)) { + info->q |= 2; + } + + if (uregs->VIread & (1 << REG_P)) { + assert( VU == &VU1 ); + info->p |= 2; + } + + // check upper flags + if (ptr[1] & 0x80000000) { // I flag + info->cycle = vucycle; + memset(lregs, 0, sizeof(lregs)); + } else { + + VU->code = ptr[0]; + if (VU == &VU1) { + VU1regs_LOWER_OPCODE[VU->code >> 25](lregs); + } else { + VU0regs_LOWER_OPCODE[VU->code >> 25](lregs); + } + + _recvuTestLowerStalls(VU, lregs); + info->cycle = vucycle; + + if (lregs->pipe == VUPIPE_BRANCH) { + branch |= 1; + } + + if (lregs->VIwrite & (1 << REG_Q)) { + info->q |= 4; + info->cycles = lregs->cycles; + info->pqinst = (VU->code&2)>>1; // rsqrt is 2 + } + else if (lregs->pipe == VUPIPE_FDIV) { + info->q |= 8|1; + info->pqinst = 0; + } + + if (lregs->VIwrite & (1 << REG_P)) { + assert( VU == &VU1 ); + info->p |= 4; + info->cycles = lregs->cycles; + + switch( VU->code & 0xff ) { + case 0xfd: info->pqinst = 0; break; //eatan + case 0x7c: info->pqinst = 0; break; //eatanxy + case 0x7d: info->pqinst = 0; break; //eatanzy + case 0xfe: info->pqinst = 1; break; //eexp + case 0xfc: info->pqinst = 2; break; //esin + case 0x3f: info->pqinst = 3; break; //erleng + case 0x3e: info->pqinst = 4; break; //eleng + case 0x3d: info->pqinst = 4; break; //ersadd + case 0xbd: info->pqinst = 4; break; //ersqrt + case 0xbe: info->pqinst = 5; break; //ercpr + case 0xbc: info->pqinst = 5; break; //esqrt + case 0x7e: info->pqinst = 5; break; //esum + case 0x3c: info->pqinst = 6; break; //esadd + default: assert(0); + } + } + else if (lregs->pipe == VUPIPE_EFU) { + info->p |= 8|1; + } + + if (lregs->VIread & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_READ; + if (lregs->VIread & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_READ; + + if (lregs->VIwrite & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_WRITE; + if (lregs->VIwrite & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_WRITE; + + if (lregs->VIread & (1 << REG_Q)) { + info->q |= 2; + } + + if (lregs->VIread & (1 << REG_P)) { + assert( VU == &VU1 ); + info->p |= 2; + } + + _recvuAddLowerStalls(VU, lregs); + } + _recvuAddUpperStalls(VU, uregs); + + _recvuTestPipes(VU); + + vucycle++; +} + +// Analyze an op - first pass +void _vurecAnalyzeOp(VURegs *VU, _vuopinfo *info) { + _VURegsNum lregs; + _VURegsNum uregs; + int *ptr; + +// SysPrintf("_vurecAnalyzeOp %x; %p\n", pc, info); + ptr = (int*)&VU->Micro[pc]; + pc += 8; + +/* SysPrintf("_vurecAnalyzeOp Upper: %s\n", disVU1MicroUF( ptr[1], pc ) ); + if ((ptr[1] & 0x80000000) == 0) { + SysPrintf("_vurecAnalyzeOp Lower: %s\n", disVU1MicroLF( ptr[0], pc ) ); + }*/ + if (ptr[1] & 0x40000000) { + branch |= 8; + } + + VU->code = ptr[1]; + if (VU == &VU1) { + VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); + } else { + VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); + } + + _recvuTestUpperStalls(VU, &uregs); + switch(VU->code & 0x3f) { + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1d: case 0x1f: + case 0x2b: case 0x2f: + break; + + case 0x3c: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag|= VUOP_WRITE; + info->macflag|= VUOP_WRITE; + break; + } + break; + case 0x3d: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: + break; + default: + info->statusflag|= VUOP_WRITE; + info->macflag|= VUOP_WRITE; + break; + } + break; + case 0x3e: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag|= VUOP_WRITE; + info->macflag|= VUOP_WRITE; + break; + } + break; + case 0x3f: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: case 0xb: + break; + default: + info->statusflag|= VUOP_WRITE; + info->macflag|= VUOP_WRITE; + break; + } + break; + + default: + info->statusflag|= VUOP_WRITE; + info->macflag|= VUOP_WRITE; + break; + } + + if (uregs.VIwrite & (1 << REG_CLIP_FLAG)) { + info->clipflag |= VUOP_WRITE; + } + + if (uregs.VIread & (1 << REG_Q)) { + info->q |= VUOP_READ; + } + + if (uregs.VIread & (1 << REG_P)) { + assert( VU == &VU1 ); + info->p |= VUOP_READ; + } + + /* check upper flags */ + if (ptr[1] & 0x80000000) { /* I flag */ + info->cycle = vucycle; + + } else { + + VU->code = ptr[0]; + if (VU == &VU1) { + VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs); + } else { + VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs); + } + + _recvuTestLowerStalls(VU, &lregs); + info->cycle = vucycle; + + if (lregs.pipe == VUPIPE_BRANCH) { + branch |= 1; + } + + if (lregs.VIwrite & (1 << REG_Q)) { +// SysPrintf("write to Q\n"); + info->q |= VUOP_WRITE; + info->cycles = lregs.cycles; + } + else if (lregs.pipe == VUPIPE_FDIV) { + info->q |= 8|1; + } + + if (lregs.VIwrite & (1 << REG_P)) { +// SysPrintf("write to P\n"); + info->p |= VUOP_WRITE; + info->cycles = lregs.cycles; + } + else if (lregs.pipe == VUPIPE_EFU) { + assert( VU == &VU1 ); + info->p |= 8|1; + } + + if (lregs.VIread & (1 << REG_CLIP_FLAG)) { + info->clipflag|= VUOP_READ; + } + + if (lregs.VIread & (1 << REG_STATUS_FLAG)) { + info->statusflag|= VUOP_READ; + } + + if (lregs.VIread & (1 << REG_MAC_FLAG)) { + info->macflag|= VUOP_READ; + } + + _recvuAddLowerStalls(VU, &lregs); + } + _recvuAddUpperStalls(VU, &uregs); + + _recvuTestPipes(VU); + + vucycle++; +} + +int eeVURecompileCode(VURegs *VU, _VURegsNum* regs) +{ + int info = 0; + int vfread0=-1, vfread1 = -1, vfwrite = -1, vfacc = -1, vftemp=-1; + + assert( regs != NULL ); + + if( regs->VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); + if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); + if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); + if( regs->VIread & (1<VIread & (1<VFread0 ) vfread0 = _allocVFtoXMMreg(VU, -1, regs->VFread0, MODE_READ); + else if( regs->VIread & (1<VFread1 ) vfread1 = _allocVFtoXMMreg(VU, -1, regs->VFread1, MODE_READ); + else if( (regs->VIread & (1<VFr1xyzw != 0xff) vfread1 = _allocVFtoXMMreg(VU, -1, 0, MODE_READ); + + if( regs->VIread & (1<VIwrite&(1<VIwrite & (1<VFwxyzw != 0xf?MODE_READ:0)); + } + + if( regs->VFwrite ) { + assert( !(regs->VIwrite&(1<VFwrite, MODE_WRITE|(regs->VFwxyzw != 0xf?MODE_READ:0)); + } + + if( vfacc>= 0 ) info |= PROCESS_EE_SET_ACC(vfacc); + if( vfwrite >= 0 ) { + if( regs->VFwrite == _Ft_ && vfread1 < 0 ) { + info |= PROCESS_EE_SET_T(vfwrite); + } + else { + assert( regs->VFwrite == _Fd_ ); + info |= PROCESS_EE_SET_D(vfwrite); + } + } + + if( vfread0 >= 0 ) info |= PROCESS_EE_SET_S(vfread0); + if( vfread1 >= 0 ) info |= PROCESS_EE_SET_T(vfread1); + + vftemp = _allocTempXMMreg(XMMT_FPS, -1); + info |= PROCESS_VU_SET_TEMP(vftemp); + + if( regs->VIwrite & (1 << REG_CLIP_FLAG) ) { + // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC + int t1reg = _allocTempXMMreg(XMMT_FPS, -1); + int t2reg = _allocTempXMMreg(XMMT_FPS, -1); + + info |= PROCESS_EE_SET_D(t1reg); + info |= PROCESS_EE_SET_ACC(t2reg); + + _freeXMMreg(t1reg); // don't need + _freeXMMreg(t2reg); // don't need + } + else if( regs->VIwrite & (1<statusflag & 1 ) info |= PROCESS_VU_UPDATEFLAGS; + if( cinfo->macflag & 1) info |= PROCESS_VU_UPDATEFLAGS; + + if( regs->pipe == 0xff ) info |= PROCESS_VU_COP2; + + return info; +} + +// returns the correct VI addr +u32 GetVIAddr(VURegs * VU, int reg, int read, int info) +{ + if( info & PROCESS_VU_SUPER ) return SuperVUGetVIAddr(reg, read); + if( info & PROCESS_VU_COP2 ) return (uptr)&VU->VI[reg].UL; + + if( read != 1 ) { + if( reg == REG_MAC_FLAG ) return (uptr)&VU->macflag; + if( reg == REG_CLIP_FLAG ) return (uptr)&VU->clipflag; + if( reg == REG_STATUS_FLAG ) return (uptr)&VU->statusflag; + if( reg == REG_Q ) return (uptr)&VU->q; + if( reg == REG_P ) return (uptr)&VU->p; + } + + return (uptr)&VU->VI[reg].UL; +} + +// gets a temp reg that is not EEREC_TEMP +int _vuGetTempXMMreg(int info) +{ + int t1reg = -1; + + if( _hasFreeXMMreg() ) { + t1reg = _allocTempXMMreg(XMMT_FPS, -1); + /* + if( t1reg == EEREC_TEMP && _hasFreeXMMreg() ) { + int t = _allocTempXMMreg(XMMT_FPS, -1); + _freeXMMreg(t1reg); + t1reg = t; + _freeXMMreg(t1reg); + } + else { + _freeXMMreg(t1reg); + t1reg = -1; + } + */ + if( t1reg == EEREC_TEMP ) { + if( _hasFreeXMMreg() ) { + int t = _allocTempXMMreg(XMMT_FPS, -1); + _freeXMMreg(t1reg); + t1reg = t; + } + else { + _freeXMMreg(t1reg); + t1reg = -1; + } + } + } + + return t1reg; +} + +PCSX2_ALIGNED16(u32 g_minvals[4]) = {0xff7fffff, 0xff7fffff, 0xff7fffff, 0xff7fffff}; +PCSX2_ALIGNED16(u32 g_maxvals[4]) = {0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff}; + +static PCSX2_ALIGNED16(int const_clip[]) = { + 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, + 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + +static PCSX2_ALIGNED16(u32 s_FloatMinMax[]) = { + 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, + 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, + 0, 0, 0, 0 }; + +static PCSX2_ALIGNED16(float s_fones[]) = { 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f }; +static PCSX2_ALIGNED16(u32 s_mask[]) = {0x7fffff, 0x7fffff, 0x7fffff, 0x7fffff }; +static PCSX2_ALIGNED16(u32 s_expmask[]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; + +static PCSX2_ALIGNED16(u32 s_overflowmask[]) = {0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000}; + +void SetVUNanMode(int mode) +{ + g_VuNanHandling = mode; + if( mode ) + SysPrintf("enabling vunan mode"); +} + +void CheckForOverflowSS_(int fdreg, int t0reg) +{ + assert( t0reg != fdreg ); + SSE_XORPS_XMM_to_XMM(t0reg, t0reg); + SSE_CMPORDSS_XMM_to_XMM(t0reg, fdreg); + if( g_VuNanHandling ) + SSE_ORPS_M128_to_XMM(t0reg, (uptr)s_overflowmask); + SSE_ANDPS_XMM_to_XMM(fdreg, t0reg); + +// SSE_MOVSS_M32_to_XMM(t0reg, (u32)s_expmask); +// SSE_ANDPS_XMM_to_XMM(t0reg, fdreg); +// SSE_CMPNESS_M32_to_XMM(t0reg, (u32)s_expmask); +// SSE_ANDPS_XMM_to_XMM(fdreg, t0reg); +} + + + +void CheckForOverflow_(int fdreg, int t0reg, int keepxyzw) +{ +// SSE_MAXPS_M128_to_XMM(fdreg, (u32)g_minvals); +// SSE_MINPS_M128_to_XMM(fdreg, (u32)g_maxvals); + + SSE_XORPS_XMM_to_XMM(t0reg, t0reg); + SSE_CMPORDPS_XMM_to_XMM(t0reg, fdreg); + + /*if( g_VuNanHandling ) + SSE_ORPS_M128_to_XMM(t0reg, (uptr)s_overflowmask);*/ + + // for partial masks, sometimes regs can be integers + if( keepxyzw != 15 ) + SSE_ORPS_M128_to_XMM(t0reg, (uptr)&SSEmovMask[15-keepxyzw][0]); + SSE_ANDPS_XMM_to_XMM(fdreg, t0reg); + +// SSE_MOVAPS_M128_to_XMM(t0reg, (u32)s_expmask); +// SSE_ANDPS_XMM_to_XMM(t0reg, fdreg); +// SSE_CMPNEPS_M128_to_XMM(t0reg, (u32)s_expmask); +// //SSE_ORPS_M128_to_XMM(t0reg, (u32)g_minvals); +// SSE_ANDPS_XMM_to_XMM(fdreg, t0reg); +} + +void CheckForOverflow(VURegs *VU, int info, int regd) +{ + if( CHECK_FORCEABS && EEREC_TEMP != regd) { + // changing the order produces different results (tektag) + CheckForOverflow_(regd, EEREC_TEMP, _X_Y_Z_W); + } +} + +// if unordered replaces with 0x7f7fffff +void ClampUnordered(int regd, int t0reg, int dosign) +{ + SSE_XORPS_XMM_to_XMM(t0reg, t0reg); + SSE_CMPORDPS_XMM_to_XMM(t0reg, regd); + SSE_ORPS_M128_to_XMM(t0reg, (uptr)&const_clip[4]); + SSE_ANDPS_XMM_to_XMM(regd, t0reg); + SSE_ANDNPS_M128_to_XMM(t0reg, (uptr)g_maxvals); + SSE_ORPS_XMM_to_XMM(regd, t0reg); +} + +//__declspec(naked) void temp() +//{ +// __asm ret +//} + +// VU Flags +// NOTE: flags don't compute under/over flows since it is highly unlikely +// that games used them. Including them will lower performance. +void recUpdateFlags(VURegs * VU, int reg, int info) +{ + u32 flagmask; + u8* pjmp; + u32 macaddr, stataddr, prevstataddr; + int x86macflag, x86newflag, x86oldflag; + const static u8 macarr[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; + if( !(info & PROCESS_VU_UPDATEFLAGS) ) + return; + + flagmask = macarr[_X_Y_Z_W]; + macaddr = VU_VI_ADDR(REG_MAC_FLAG, 0); + stataddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); + prevstataddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); + + if( stataddr == 0 ) { + stataddr = prevstataddr; + } + //assert( stataddr != 0); + + + // 20 insts + x86newflag = ALLOCTEMPX86(MODE_8BITREG); + x86macflag = ALLOCTEMPX86(0); + x86oldflag = ALLOCTEMPX86(0); + + // can do with 8 bits since only computing zero/sign flags + if( EEREC_TEMP != reg ) { + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); //Clear EEREC_TEMP + SSE_CMPEQPS_XMM_to_XMM(EEREC_TEMP, reg); // set all F's if each vector is zero + + MOV32MtoR(x86oldflag, prevstataddr); // load the previous status in to x86oldflag + + SSE_MOVMSKPS_XMM_to_R32(x86newflag, EEREC_TEMP); // move the sign bits of the previous calculation (is reg vec zero) in to x86newflag + + XOR32RtoR(EAX, EAX); //Clear EAX + + //if( !(g_VUGameFixes&VUFIX_SIGNEDZERO) ) { + SSE_ANDNPS_XMM_to_XMM(EEREC_TEMP, reg); // necessary! //EEREC_TEMP = !EEREC_TEMP & reg, + // so if the result was zero before, EEREC_TEMP will now be blank. + //} + + AND32ItoR(x86newflag, 0x0f&flagmask); //Grab "Is zero" bits from the first calculation + pjmp = JZ8(0); //Skip if none are + OR32ItoR(EAX, 1); // Set if they are + x86SetJ8(pjmp); + + /*if( !(g_VUGameFixes&VUFIX_SIGNEDZERO) )*/ SSE_MOVMSKPS_XMM_to_R32(x86macflag, EEREC_TEMP); // Grab sign bits from before, remember if "reg" + //Was zero, so will the sign bits + //else SSE_MOVMSKPS_XMM_to_R32(x86macflag, reg); // unless we are using the signed zero fix, in which case, we keep it either way ;) + + + AND32ItoR(x86macflag, 0x0f&flagmask); // Seperate the vectors we are using + pjmp = JZ8(0); + OR32ItoR(EAX, 2); // Set the "Signed" flag if it is signed + x86SetJ8(pjmp); + SHL32ItoR(x86newflag, 4); // Shift the zero flags left 4 + OR32RtoR(x86macflag, x86newflag); + } + else { + SSE_MOVMSKPS_XMM_to_R32(x86macflag, EEREC_TEMP); // mask is < 0 (including 80000000) Get sign bits of all 4 vectors + // put results in lower 4 bits of x86macflag + + MOV32MtoR(x86oldflag, prevstataddr); //move current (previous) status register to x86oldflag + XOR32RtoR(EAX, EAX); //Clear EAX for our new flag + + SSE_CMPEQPS_M128_to_XMM(EEREC_TEMP, (uptr)&s_FloatMinMax[8]); //if the result zero? + //set to all F's (true) or All 0's on each vector (depending on result) + + SSE_MOVMSKPS_XMM_to_R32(x86newflag, EEREC_TEMP); // put the sign bit results from the previous calculation in x86newflag + // so x86newflag == 0xf if EEREC_TEMP is zero and == 0x0 if it is all a value. + + //if( !(g_VUGameFixes&VUFIX_SIGNEDZERO) ) { + NOT32R(x86newflag); //flip all bits from previous calculation, so now if the result was zero, the result here is 0's + AND32RtoR(x86macflag, x86newflag); //check non-zero macs against signs of initial register values + // so if the result was zero, regardless of if its signed or not, it wont set the signed flags + //} + + AND32ItoR(x86macflag, 0xf&flagmask); //seperate out the flags we are actually using? + pjmp = JZ8(0); //if none are the flags are set to 1 (aka the result is non-zero & positive, or they were zero) dont set the "signed" flag + OR32ItoR(EAX, 2); //else we are signed + x86SetJ8(pjmp); + + //if( !(g_VUGameFixes&VUFIX_SIGNEDZERO) ) { //Flip the bits back again so we have our "its zero" values + NOT32R(x86newflag); //flip! + //} + + AND32ItoR(x86newflag, 0xf&flagmask); //mask out the vectors we didnt use + pjmp = JZ8(0); //If none were zero skip + OR32ItoR(EAX, 1); //We had a zero, so set el status flag with "zero":p + x86SetJ8(pjmp); + + SHL32ItoR(x86newflag, 4); //Move our zero flags left 4 + OR32RtoR(x86macflag, x86newflag); //then stick our signed flags intront of it + } + + // x86macflag - new untransformed mac flag, EAX - new status bits, x86oldflag - old status flag + // x86macflag = zero_wzyx | sign_wzyx + MOV8RmtoROffset(x86newflag, x86macflag, (u32)g_MACFlagTransform); // transform + //MOV32RtoR(x86macflag, x86newflag ); + //MOV32RtoR(x86macflag, x86oldflag); + //SHL32ItoR(x86macflag, 6); + //OR32RtoR(x86oldflag, x86macflag); + + if( macaddr != 0 ) { + + // has to write full 32 bits! + MOV8RtoM(macaddr, x86newflag); + + // vampire night breaks with (g_VUGameFixes&VUFIX_EXTRAFLAGS), crazi taxi needs it + /* if( (g_VUGameFixes&VUFIX_EXTRAFLAGS) && flagmask != 0xf ) { + MOV8MtoR(x86newflag, VU_VI_ADDR(REG_MAC_FLAG, 2)); // get previous written + AND8ItoR(x86newflag, ~g_MACFlagTransform[(flagmask|(flagmask<<4))]); + OR8RtoM(macaddr, x86newflag); + } */ + } + + //AND32ItoR(x86oldflag, 0x0c0); + SHR32ItoR(x86oldflag, 6); + OR32RtoR(x86oldflag, EAX); + SHL32ItoR(x86oldflag, 6); + OR32RtoR(x86oldflag, EAX); + //SHL32ItoR(EAX,6); + //OR32RtoR(x86oldflag, EAX); + MOV32RtoM(stataddr, x86oldflag); + + _freeX86reg(x86macflag); + _freeX86reg(x86newflag); + _freeX86reg(x86oldflag); +} + +/******************************/ +/* VU Upper instructions */ +/******************************/ + +static PCSX2_ALIGNED16(int const_abs_table[16][4]) = +{ + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, + { 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, + { 0xffffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, + { 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, + { 0xffffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, + { 0xffffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, + { 0xffffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, + { 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff }, + { 0x7fffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, + { 0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, + { 0x7fffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, + { 0x7fffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, + { 0x7fffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, +}; + +void recVUMI_ABS(VURegs *VU, int info) +{ + if ( _Ft_ == 0 ) return; + + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } else { + if( EEREC_T != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_ANDPS_M128_to_XMM(EEREC_T, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); + } +} + +PCSX2_ALIGNED16(float s_two[4]) = {0,0,0,2}; + +void recVUMI_ADD(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( _Fs_ == 0 && _Ft_ == 0 ) { + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (u32)s_two); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVAPS_M128_to_XMM(EEREC_D, (u32)s_two); + } + } + else { + if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } + +// if( _Fd_ == 0 && (_Fs_ == 0 || _Ft_ == 0) ) +// info |= PROCESS_VU_UPDATEFLAGS; + + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_ADD_iq(VURegs *VU, uptr addr, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_ADDSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_M32_to_XMM(EEREC_D, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || EEREC_D == EEREC_S || EEREC_D == EEREC_TEMP) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } else { + if( EEREC_D == EEREC_TEMP ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } + + recUpdateFlags(VU, EEREC_D, info); + + if( addr == VU_REGQ_ADDR ) CheckForOverflow(VU, info, EEREC_D); +} + +void recVUMI_ADD_xyzw(VURegs *VU, int xyzw, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( _Ft_ == 0 && xyzw < 3 ) { + // just move + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + else if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP) ) { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_T ) { + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if( _Fs_ == 0 && !_W ) { + // just move + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + +// SSE_MOVAPS_XMM_to_M128((u32)s_tempmem, EEREC_TEMP); +// SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); +// SSE_CMPNLTPS_M128_to_XMM(EEREC_TEMP, (u32)s_FloatMinMax); +// SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)s_tempmem); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( _X_Y_Z_W != 0xf || EEREC_D == EEREC_S || EEREC_D == EEREC_TEMP) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } else { + if( EEREC_D == EEREC_TEMP ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + else { + _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } + + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_ADDi(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_ADDq(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_ADDx(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 0, info); } +void recVUMI_ADDy(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 1, info); } +void recVUMI_ADDz(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 2, info); } +void recVUMI_ADDw(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 3, info); } + +void recVUMI_ADDA(VURegs *VU, int info) +{ + if( _X_Y_Z_W == 8 ) { + if (EEREC_ACC == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if (EEREC_ACC == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if( EEREC_ACC == EEREC_T ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDA_iq(VURegs *VU, int addr, int info) +{ + if( _XYZW_SS ) { + assert( EEREC_ACC != EEREC_TEMP ); + if( EEREC_ACC == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_ACC); + SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); + _vuFlipRegSS(VU, EEREC_ACC); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(EEREC_ACC, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + } + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDA_xyzw(VURegs *VU, int xyzw, int info) +{ + if( _X_Y_Z_W == 8 ) { + if( xyzw == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + if( _Fs_ == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + else { + _unpackVF_xyzw(EEREC_ACC, EEREC_T, xyzw); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + } + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDAi(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_ADDAq(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_ADDAx(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 0, info); } +void recVUMI_ADDAy(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 1, info); } +void recVUMI_ADDAz(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 2, info); } +void recVUMI_ADDAw(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 3, info); } + +void recVUMI_SUB(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( EEREC_S == EEREC_T ) { + if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); + else SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + } + else if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( _Ft_ > 0 || _W ) SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } + + recUpdateFlags(VU, EEREC_D, info); + // neopets works better with this? + //CheckForOverflow(info, EEREC_D); +} + +void recVUMI_SUB_iq(VURegs *VU, int addr, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_D, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + else { + if( EEREC_D == EEREC_TEMP ) { + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if (EEREC_D != EEREC_S) SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } + + recUpdateFlags(VU, EEREC_D, info); + + if( addr == VU_REGQ_ADDR ) CheckForOverflow(VU, info, EEREC_D); +} + +static PCSX2_ALIGNED16(s_unaryminus[4]) = {0x80000000, 0, 0, 0}; + +void recVUMI_SUB_xyzw(VURegs *VU, int xyzw, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + if( _X_Y_Z_W == 8 ) { + if( EEREC_D == EEREC_TEMP ) { + + switch (xyzw) { + case 0: + if( EEREC_TEMP != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + break; + case 1: + if( cpucaps.hasStreamingSIMD3Extensions ) SSE3_MOVSLDUP_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else { + if( EEREC_TEMP != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + break; + case 2: + SSE_MOVLHPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + break; + case 3: + if( cpucaps.hasStreamingSIMD3Extensions && EEREC_TEMP != EEREC_S ) { + SSE3_MOVSLDUP_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MOVLHPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + } + else { + if( EEREC_TEMP != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + } + break; + } + + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) { + if( xyzw == 1 ) SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0xe1); // y + else if( xyzw == 2 ) SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0xc6); // z + else if( xyzw == 3 ) SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x27); // w + //} + } + else { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_T ) { + if( _Fs_ > 0 ) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_XORPS_M128_to_XMM(EEREC_D, (u32)s_unaryminus); + } + else { + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } +// else if( _XYZW_SS && xyzw == 0 ) { +// if( EEREC_D == EEREC_S ) { +// if( EEREC_D == EEREC_T ) { +// SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); +// _vuFlipRegSS(VU, EEREC_D); +// SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); +// _vuFlipRegSS(VU, EEREC_D); +// } +// else { +// _vuFlipRegSS(VU, EEREC_D); +// SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); +// _vuFlipRegSS(VU, EEREC_D); +// } +// } +// else if( EEREC_D == EEREC_T ) { +// _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Y?1:(_Z?2:3)); +// SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); +// _vuFlipRegSS(VU, EEREC_D); +// SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); +// _vuFlipRegSS(VU, EEREC_D); +// } +// else { +// _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Y?1:(_Z?2:3)); +// _vuFlipRegSS(VU, EEREC_D); +// SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); +// SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); +// _vuFlipRegSS(VU, EEREC_D); +// } +// } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_D, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + else { + if( EEREC_D == EEREC_TEMP ) { + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } + + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_SUBi(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_SUBq(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_SUBx(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 0, info); } +void recVUMI_SUBy(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 1, info); } +void recVUMI_SUBz(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 2, info); } +void recVUMI_SUBw(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 3, info); } + +void recVUMI_SUBA(VURegs *VU, int info) +{ + if( EEREC_S == EEREC_T ) { + if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_ACC, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); + else SSE_XORPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC); + } + else if( _X_Y_Z_W == 8 ) { + if (EEREC_ACC == EEREC_S) SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if (EEREC_ACC == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if( EEREC_ACC == EEREC_T ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBA_iq(VURegs *VU, int addr, int info) +{ + if( _XYZW_SS ) { + if( EEREC_ACC == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_ACC); + SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); + _vuFlipRegSS(VU, EEREC_ACC); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_ACC); + SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_ACC); + } + } + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_ACC, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + else { + if( EEREC_ACC != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBA_xyzw(VURegs *VU, int xyzw, int info) +{ + if( _X_Y_Z_W == 8 ) { + if( xyzw == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_ACC, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + else { + if( EEREC_ACC != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBAi(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_SUBAq(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_SUBAx(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 0, info); } +void recVUMI_SUBAy(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 1, info); } +void recVUMI_SUBAz(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 2, info); } +void recVUMI_SUBAw(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 3, info); } + +void recVUMI_MUL_toD(VURegs *VU, int regd, int info) +{ + if (_X_Y_Z_W == 1 && (_Ft_ == 0 || _Fs_==0) ) { // W + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, _Ft_ ? EEREC_T : EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else if( _Fd_ == _Fs_ && _Fs_ == _Ft_ && _XYZW_SS ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MULSS_XMM_to_XMM(EEREC_D, EEREC_D); + _vuFlipRegSS(VU, EEREC_D); + } + else if( _X_Y_Z_W == 8 ) { + if (regd == EEREC_S) SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + else if (regd == EEREC_T) SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + else if (regd == EEREC_T) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + } + } +} + +void recVUMI_MUL_iq_toD(VURegs *VU, int addr, int regd, int info) +{ + if( _XYZW_SS ) { + if( regd == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + _vuFlipRegSS(VU, EEREC_S); + } + else if( regd == EEREC_S ) { + _vuFlipRegSS(VU, regd); + SSE_MULSS_M32_to_XMM(regd, addr); + _vuFlipRegSS(VU, regd); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + } + } + } +} + +void recVUMI_MUL_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) +{ + if( _Ft_ == 0 ) { + if( xyzw < 3 ) { + if (_X_Y_Z_W != 0xf) { + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + SSE_XORPS_XMM_to_XMM(regd, regd); + } + } + else { + assert(xyzw==3); + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else if( regd != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + } + } + else if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_TEMP ) { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + } + else { + if( xyzw == 0 ) { + if( regd == EEREC_T ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + else { + _unpackVF_xyzw(regd, EEREC_T, xyzw); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + } + } + } +} + +void recVUMI_MUL(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MUL_iq(VURegs *VU, int addr, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_iq_toD(VU, addr, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); + // spacefisherman needs overflow checking on MULi.z + if( addr == VU_REGQ_ADDR || _Z ) + CheckForOverflow(VU, info, EEREC_D); +} + +void recVUMI_MUL_xyzw(VURegs *VU, int xyzw, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MULi(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MULq(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MULx(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 0, info); } +void recVUMI_MULy(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 1, info); } +void recVUMI_MULz(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 2, info); } +void recVUMI_MULw(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 3, info); } + +void recVUMI_MULA( VURegs *VU, int info ) +{ + recVUMI_MUL_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULA_iq(VURegs *VU, int addr, int info) +{ + recVUMI_MUL_iq_toD(VU, addr, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULA_xyzw(VURegs *VU, int xyzw, int info) +{ + recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULAi(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MULAq(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MULAx(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 0, info); } +void recVUMI_MULAy(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 1, info); } +void recVUMI_MULAz(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 2, info); } +void recVUMI_MULAw(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 3, info); } + +void recVUMI_MADD_toD(VURegs *VU, int regd, int info) +{ + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_ACC ) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if (regd == EEREC_T) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else if (regd == EEREC_S) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if (regd == EEREC_T) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if (regd == EEREC_S) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } +} + +void recVUMI_MADD_iq_toD(VURegs *VU, int addr, int regd, int info) +{ + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_ACC ) { + if( _Fs_ == 0 ) { + // add addr to w + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ADDSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } + else { + assert( EEREC_TEMP < XMMREGS ); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + else if( regd == EEREC_S ) { + SSE_MULSS_M32_to_XMM(regd, addr); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + } + else { + if( _Fs_ == 0 ) { + // add addr to w + if( _W ) { + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ADDSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } + + return; + } + + if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } + } +} + +void recVUMI_MADD_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) +{ + if( _Ft_ == 0 ) { + + if( xyzw == 3 ) { + // just add + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_S ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else { + if( regd != EEREC_ACC ) SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_S); + } + } + else { + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_S ) SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + else { + if( regd != EEREC_ACC ) SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_S); + } + } + } + } + else { + // just move acc to regd + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd != EEREC_ACC ) SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + } + } + + return; + } + + if( _X_Y_Z_W == 8 ) { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if( regd == EEREC_ACC ) { + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + _unpackVF_xyzw(regd, EEREC_T, xyzw); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } + } +} + +void recVUMI_MADD(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MADD_iq(VURegs *VU, int addr, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_iq_toD(VU, addr, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); + + if( addr == VU_REGQ_ADDR ) CheckForOverflow(VU, info, EEREC_D); +} + +void recVUMI_MADD_xyzw(VURegs *VU, int xyzw, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_xyzw_toD(VU, xyzw, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); + + // super bust-a-move arrows + CheckForOverflow(VU, info, EEREC_D); +} + +void recVUMI_MADDi(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MADDq(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MADDx(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 0, info); } +void recVUMI_MADDy(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 1, info); } +void recVUMI_MADDz(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 2, info); } +void recVUMI_MADDw(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 3, info); } + +void recVUMI_MADDA( VURegs *VU, int info ) +{ + recVUMI_MADD_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAi( VURegs *VU , int info) +{ + recVUMI_MADD_iq_toD( VU, VU_VI_ADDR(REG_I, 1), EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAq( VURegs *VU , int info) +{ + recVUMI_MADD_iq_toD( VU, VU_REGQ_ADDR, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAx( VURegs *VU , int info) +{ + recVUMI_MADD_xyzw_toD(VU, 0, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAy( VURegs *VU , int info) +{ + recVUMI_MADD_xyzw_toD(VU, 1, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAz( VURegs *VU , int info) +{ + recVUMI_MADD_xyzw_toD(VU, 2, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAw( VURegs *VU , int info) +{ + recVUMI_MADD_xyzw_toD(VU, 3, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUB_toD(VURegs *VU, int regd, int info) +{ + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(regd, t1reg); + _freeXMMreg(t1reg); + } + else { + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + else { + if( regd == EEREC_S ) { + assert( regd != EEREC_ACC ); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_T ) { + assert( regd != EEREC_ACC ); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_TEMP ) { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( regd != EEREC_ACC ) SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + } +} + +void recVUMI_MSUB_temp_toD(VURegs *VU, int regd, int info) +{ + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + if( regd != EEREC_TEMP ) { + VU_MERGE_REGS(regd, t1reg); + } + else + SSE_MOVAPS_XMM_to_XMM(regd, t1reg); + + _freeXMMreg(t1reg); + } + else { + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else { + if( regd != EEREC_ACC ) SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + } +} + +void recVUMI_MSUB_iq_toD(VURegs *VU, int regd, int addr, int info) +{ + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + recVUMI_MSUB_temp_toD(VU, regd, info); +} + +void recVUMI_MSUB_xyzw_toD(VURegs *VU, int regd, int xyzw, int info) +{ + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + recVUMI_MSUB_temp_toD(VU, regd, info); +} + +void recVUMI_MSUB(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUB_iq(VURegs *VU, int addr, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_iq_toD(VU, EEREC_D, addr, info); + recUpdateFlags(VU, EEREC_D, info); + + if( addr == VU_REGQ_ADDR ) CheckForOverflow(VU, info, EEREC_D); +} + +void recVUMI_MSUBi(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MSUBq(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MSUBx(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 0, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBy(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 1, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBz(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 2, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBw(VURegs *VU, int info) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 3, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBA( VURegs *VU, int info ) +{ + recVUMI_MSUB_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAi( VURegs *VU, int info ) +{ + recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_VI_ADDR(REG_I, 1), info ); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAq( VURegs *VU, int info ) +{ + recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_REGQ_ADDR, info ); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAx( VURegs *VU, int info ) +{ + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 0, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAy( VURegs *VU, int info ) +{ + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 1, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAz( VURegs *VU, int info ) +{ + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 2, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAw( VURegs *VU, int info ) +{ + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 3, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MAX(VURegs *VU, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D == EEREC_S ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +} + +void recVUMI_MAX_iq(VURegs *VU, int addr, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_MAXSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if(EEREC_D == EEREC_S) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +} + +void recVUMI_MAX_xyzw(VURegs *VU, int xyzw, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { + if( _Fs_ == 0 && _Ft_ == 0 ) { + if( xyzw < 3 ) { + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (u32)s_fones); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_S ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } + else if (_X_Y_Z_W != 0xf) { + if( _Fs_ == 0 && _Ft_ == 0 ) { + if( xyzw < 3 ) { + if( _X_Y_Z_W & 1 ) { + // w included, so insert the whole reg + SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[0]); + } + else { + // w not included, can zero out + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + } + } + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (u32)s_fones); + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + } + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( _Fs_ == 0 && _Ft_ == 0 ) { + if( xyzw < 3 ) SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + else SSE_MOVAPS_M128_to_XMM(EEREC_D, (u32)s_fones); + } + else { + if (EEREC_D == EEREC_S) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +} + +void recVUMI_MAXi(VURegs *VU, int info) { recVUMI_MAX_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MAXx(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 0, info); } +void recVUMI_MAXy(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 1, info); } +void recVUMI_MAXz(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 2, info); } +void recVUMI_MAXw(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 3, info); } + +void recVUMI_MINI(VURegs *VU, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D == EEREC_S ) { + // need for GT4 vu0rec + ClampUnordered(EEREC_T, EEREC_TEMP, 0); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + // need for GT4 vu0rec + ClampUnordered(EEREC_S, EEREC_TEMP, 0); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +} + +void recVUMI_MINI_iq(VURegs *VU, int addr, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_MINSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if(EEREC_D == EEREC_S) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +} + +void recVUMI_MINI_xyzw(VURegs *VU, int xyzw, int info) +{ + if ( _Fd_ == 0 ) return; + + if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_S ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if (_X_Y_Z_W != 0xf) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +} + +void recVUMI_MINIi(VURegs *VU, int info) { recVUMI_MINI_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MINIx(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 0, info); } +void recVUMI_MINIy(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 1, info); } +void recVUMI_MINIz(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 2, info); } +void recVUMI_MINIw(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 3, info); } + +void recVUMI_OPMULA( VURegs *VU, int info ) +{ + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xD2); // EEREC_T = WYXZ + SSE_SHUFPS_XMM_to_XMM( EEREC_TEMP, EEREC_TEMP, 0xC9 ); // EEREC_TEMP = WXZY + SSE_MULPS_XMM_to_XMM( EEREC_TEMP, EEREC_T ); + + VU_MERGE_REGS_CUSTOM(EEREC_ACC, EEREC_TEMP, 14); + + // revert EEREC_T + if( EEREC_T != EEREC_ACC ) + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); + + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_OPMSUB( VURegs *VU, int info ) +{ + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM( EEREC_T, EEREC_T, 0xD2 ); // EEREC_T = WYXZ + SSE_SHUFPS_XMM_to_XMM( EEREC_TEMP, EEREC_TEMP, 0xC9 ); // EEREC_TEMP = WXZY + SSE_MULPS_XMM_to_XMM( EEREC_TEMP, EEREC_T); + + // negate and add + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS_CUSTOM(EEREC_D, EEREC_TEMP, 14); + + // revert EEREC_T + if( EEREC_T != EEREC_D ) + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); + + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_NOP( VURegs *VU, int info ) +{ +} + +void recVUMI_FTOI0(VURegs *VU, int info) +{ + if ( _Ft_ == 0 ) return; + + if (_X_Y_Z_W != 0xf) { + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else SSE2EMU_CVTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_S); + else SSE2EMU_CVTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_S); + } +} + +void recVUMI_FTOIX(VURegs *VU, int addr, int info) +{ + if ( _Ft_ == 0 ) return; + + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + else SSE2EMU_CVTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if (EEREC_T != EEREC_S) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_T, addr); + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); + else SSE2EMU_CVTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); + } +} + +void recVUMI_FTOI4( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int4[0], info); } +void recVUMI_FTOI12( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int12[0], info); } +void recVUMI_FTOI15( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int15[0], info); } + +void recVUMI_ITOF0( VURegs *VU, int info ) +{ + if ( _Ft_ == 0 ) return; + + if (_X_Y_Z_W != 0xf) { + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else { + _deleteVFtoXMMreg(_Fs_, VU==&VU1, 1); + SSE2EMU_CVTDQ2PS_M128_to_XMM(EEREC_TEMP, VU_VFx_ADDR( _Fs_ )); + } + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } + else { + if( cpucaps.hasStreamingSIMD2Extensions ) SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); + else { + _deleteVFtoXMMreg(_Fs_, VU==&VU1, 1); + SSE2EMU_CVTDQ2PS_M128_to_XMM(EEREC_T, VU_VFx_ADDR( _Fs_ )); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } + } +} + +void recVUMI_ITOFX(VURegs *VU, int addr, int info) +{ + if ( _Ft_ == 0 ) return; + + if (_X_Y_Z_W != 0xf) { + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else { + _deleteVFtoXMMreg(_Fs_, VU==&VU1, 1); + SSE2EMU_CVTDQ2PS_M128_to_XMM(EEREC_TEMP, VU_VFx_ADDR( _Fs_ )); + } + + SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } else { + if(cpucaps.hasStreamingSIMD2Extensions) SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); + else { + _deleteVFtoXMMreg(_Fs_, VU==&VU1, 1); + SSE2EMU_CVTDQ2PS_M128_to_XMM(EEREC_T, VU_VFx_ADDR( _Fs_ )); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } + + SSE_MULPS_M128_to_XMM(EEREC_T, addr); + } +} + +void recVUMI_ITOF4( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float4[0], info); } +void recVUMI_ITOF12( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float12[0], info); } +void recVUMI_ITOF15( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float15[0], info); } + +void recVUMI_CLIP(VURegs *VU, int info) +{ + int t1reg = EEREC_D; + int t2reg = EEREC_ACC; + int x86temp0, x86temp1; + + u32 clipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 0); + u32 prevclipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 2); + + if( clipaddr == 0 ) { + // battle star has a clip right before fcset + SysPrintf("skipping vu clip\n"); + return; + } + assert( clipaddr != 0 ); + assert( t1reg != t2reg && t1reg != EEREC_TEMP && t2reg != EEREC_TEMP ); + + x86temp1 = ALLOCTEMPX86(MODE_8BITREG); + x86temp0 = ALLOCTEMPX86(0); + + if( _Ft_ == 0 ) { + // all 1s + SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&s_fones[0]); + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)&s_fones[4]); + + MOV32MtoR(EAX, prevclipaddr); + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, 3); + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (int)const_clip); + + MOV32MtoR(EAX, prevclipaddr); + + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_TEMP); + SSE_ORPS_M128_to_XMM(t1reg, (uptr)&const_clip[4]); + } + + SSE_CMPNLEPS_XMM_to_XMM(t1reg, EEREC_S); //-w, -z, -y, -x + SSE_CMPLTPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); //+w, +z, +y, +x + + SHL32ItoR(EAX, 6); + + SSE_MOVAPS_XMM_to_XMM(t2reg, EEREC_TEMP); //t2 = +w, +z, +y, +x + SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, t1reg); //EEREC_TEMP = -y,+y,-x,+x + SSE_UNPCKHPS_XMM_to_XMM(t2reg, t1reg); //t2reg = -w,+w,-z,+z + SSE_MOVMSKPS_XMM_to_R32(x86temp0, EEREC_TEMP); // -y,+y,-x,+x + SSE_MOVMSKPS_XMM_to_R32(x86temp1, t2reg); // -w,+w,-z,+z + + AND32ItoR(EAX, 0xffffff); + + AND8ItoR(x86temp1, 0x3); + SHL32ItoR(x86temp1, 4); + OR32RtoR(EAX, x86temp0); + OR32RtoR(EAX, x86temp1); + + MOV32RtoM(clipaddr, EAX); + /*if( !(info&(PROCESS_VU_SUPER|PROCESS_VU_COP2)) )*/ MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); + + _freeXMMreg(t1reg); + _freeXMMreg(t2reg); + + _freeX86reg(x86temp0); + _freeX86reg(x86temp1); +} + +/******************************/ +/* VU Lower instructions */ +/******************************/ + +void recVUMI_DIV(VURegs *VU, int info) +{ + int t1reg; + + if( _Fs_ == 0 ) { + + if( _Ft_ == 0 ) { + if( _Fsf_ < 3 ) { // 0/ft + if( _Ftf_ < 3 ) { // 0/0 + //SysPrintf("DIV 0/0\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag (only when 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); + } else { // 0/1 + //SysPrintf("DIV 0/1\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); + } + }else if( _Ftf_ < 3 ) { // 1/0 + //SysPrintf("DIV 1/0\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); + } else { // 1/1 + //SysPrintf("DIV 1/1\n"); + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x3f800000); + } + return; + } + + if( _Fsf_ == 3 ) { // = 1 + // don't use RCPSS (very bad precision) + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + + if( _Ftf_ != 0 || (xmmregs[EEREC_T].mode & MODE_WRITE) ) + { + if( _Ftf_ ) + { + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) + { + _unpackVFSS_xyzw(t1reg, EEREC_T, _Ftf_); + + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, t1reg); + + _freeXMMreg(t1reg); + } + else + { + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, (0xe4e4>>(2*_Ftf_))&0xff); + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, (0xe4e4>>(8-2*_Ftf_))&0xff); // revert + } + } + else + { + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + } + } + else { + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Ft_].UL[_Ftf_]); + } + } + else { // = 0 So result is -MAX/+MAX + //SysPrintf("FS = 0, FT != 0\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag (only when 0/0) + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (u32)&g_maxvals); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + //MOV32ItoR(VU_VI_ADDR(REG_Q, 0), 0); + return; + } + } + else { + if( _Ft_ == 0 ) { + if( _Ftf_ < 3 ) { + //SysPrintf("FS != 0, FT == 0\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); + + } else { + //SysPrintf("FS != 0, FT == 1\n"); + if( _Fsf_ == 0 ) SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + } + + return; + } + + if( _Fsf_ == 0 ) SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + else _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + if( _Ftf_ ) + { + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) + { + _unpackVFSS_xyzw(t1reg, EEREC_T, _Ftf_); + + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, t1reg); + + _freeXMMreg(t1reg); + } + else + { + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, (0xe4e4>>(2*_Ftf_))&0xff); + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, (0xe4e4>>(8-2*_Ftf_))&0xff); // revert + } + } + else + { + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + } + } + + //if( !CHECK_FORCEABS ) { + SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + //} + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); +} + +void recVUMI_SQRT( VURegs *VU, int info ) +{ + int vftemp = ALLOCTEMPX86(MODE_8BITREG); + u8* pjmp; + + AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFDF); //Divide flag cleared regardless of result + + if( _Ftf_ ) { + if( xmmregs[EEREC_T].mode & MODE_WRITE ) { + //SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + _unpackVF_xyzw(EEREC_TEMP, EEREC_TEMP, _Ftf_); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Ft_].UL[_Ftf_]); + //SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); + } + } + else { + //SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (u32)const_clip); + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + } + /* Check for negative divide */ + XOR32RtoR(vftemp, vftemp); + SSE_MOVMSKPS_XMM_to_R32(vftemp, EEREC_TEMP); + AND32ItoR(vftemp, 1); //Check sign + pjmp = JZ8(0); //Skip if none are + //SysPrintf("Invalid SQRT\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag - Negative number sqrt + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); //So we do a cardinal sqrt + x86SetJ8(pjmp); + + //SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); + + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + _freeX86reg(vftemp); + +} + +void recVUMI_RSQRT(VURegs *VU, int info) +{ + int vftemp = ALLOCTEMPX86(MODE_8BITREG); + u8* njmp; + + if( _Ftf_ ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + _unpackVF_xyzw(EEREC_TEMP, EEREC_TEMP, _Ftf_); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + } + /* Check for negative divide */ + XOR32RtoR(vftemp, vftemp); + SSE_MOVMSKPS_XMM_to_R32(vftemp, EEREC_TEMP); + AND32ItoR(vftemp, 1); //Check sign + njmp = JZ8(0); //Skip if none are + //SysPrintf("Invalid RSQRT\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag - Negative number sqrt + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); //So we do a cardinal sqrt + x86SetJ8(njmp); + + //SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)const_clip); + + if( _Fs_ == 0 ) { + if( _Fsf_ == 3 ) { + if(_Ft_ != 0 ||_Ftf_ == 3 ) + { + //SysPrintf("_Fs_ = 0.3 _Ft_ != 0 || _Ft_ = 0.3 \n"); + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); //Dont use RSQRT, terrible accuracy + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + //SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_Q, 0)); + + + } + else + { + //SysPrintf("FS0.3 / 0!\n"); + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); + _freeX86reg(vftemp); + return; + } + }else { + if(_Ft_ != 0 || _Ftf_ == 3) { + //SysPrintf("FS = 0 FT != 0\n"); + //SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0x7f7fffff); // +MAX, no negative in here :p + _freeX86reg(vftemp); + return; + } + else + { + //SysPrintf("FS = 0 FT = 0!\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag (only when 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0); + _freeX86reg(vftemp); + return; + } + } + } + else { + int t1reg; + if( _Ft_ == 0 ) { + if( _Ftf_ < 3 ) { + //SysPrintf("FS != 0 FT = 0!\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); //Invalid Flag (only when 0/0) + SSE_MOVMSKPS_XMM_to_R32(vftemp, EEREC_S); + SHL32ItoR(vftemp, 31); //Check sign + OR32ItoR(vftemp, 0x7f7fffff); + MOV32RtoM(VU_VI_ADDR(REG_Q, 0), vftemp); + _freeX86reg(vftemp); + return; + }else { + //SysPrintf("FS != 0 FT = 1!\n"); + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); //Zero divide (only when not 0/0) + MOV32ItoM(VU_VI_ADDR(REG_Q, 0), 0xff7fffff); + _freeX86reg(vftemp); + return; + } + + } + //SysPrintf("Normal RSQRT\n"); + + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) + { + _unpackVFSS_xyzw(t1reg, EEREC_S, _Fsf_); + SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, t1reg); + _freeXMMreg(t1reg); + } + else + { + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_Q, 0)); + } + } + + //if( !CHECK_FORCEABS ) { + SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + //} + + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + _freeX86reg(vftemp); +} + +void _addISIMMtoIT(VURegs *VU, s16 imm, int info) +{ + int fsreg = -1, ftreg; + if (_Ft_ == 0) return; + + if( _Fs_ == 0 ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV32ItoR(ftreg, imm&0xffff); + return; + } + + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if (ftreg == fsreg) { + if (imm != 0 ) { + ADD16ItoR(ftreg, imm); + } + } else { + if( imm ) { + LEA32RtoR(ftreg, fsreg, imm); + MOVZX32R16toR(ftreg, ftreg); + } + else MOV32RtoR(ftreg, fsreg); + } +} + +void recVUMI_IADDI(VURegs *VU, int info) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + + imm = ( VU->code >> 6 ) & 0x1f; + imm = ( imm & 0x10 ? 0xfff0 : 0) | ( imm & 0xf ); + _addISIMMtoIT(VU, imm, info); +} + +void recVUMI_IADDIU(VURegs *VU, int info) +{ + int imm; + + if ( _Ft_ == 0 ) return; + + imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); + _addISIMMtoIT(VU, imm, info); +} + +void recVUMI_IADD( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + } + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + } + else { + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) ADD32RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) ADD32RtoR(fdreg, fsreg); + else LEA16RRtoR(fdreg, fsreg, ftreg); + MOVZX32R16toR(fdreg, fdreg); // neeed since don't know if fdreg's upper bits are 0 + } +} + +void recVUMI_IAND( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + + if ( ( _Fs_ == 0 ) || ( _Ft_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) AND16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) AND16RtoR(fdreg, fsreg); + else { + MOV32RtoR(fdreg, ftreg); + AND32RtoR(fdreg, fsreg); + } +} + +void recVUMI_IOR( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + } + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + } + else + { + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) OR16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) OR16RtoR(fdreg, fsreg); + else { + MOV32RtoR(fdreg, fsreg); + OR32RtoR(fdreg, ftreg); + } + } +} + +void recVUMI_ISUB( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + } + NEG16R(fdreg); + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else { + MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + } + else + { + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) SUB16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) { + SUB16RtoR(fdreg, fsreg); + NEG16R(fdreg); + } + else { + MOV32RtoR(fdreg, fsreg); + SUB16RtoR(fdreg, ftreg); + } + } +} + +void recVUMI_ISUBIU( VURegs *VU, int info ) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + + imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); + imm = -imm; + _addISIMMtoIT(VU, (u32)imm & 0xffff, info); +} + +void recVUMI_MOVE( VURegs *VU, int info ) +{ + if (_Ft_ == 0) return; + + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if( EEREC_T != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + } +} + +void recVUMI_MFIR( VURegs *VU, int info ) +{ + static u32 s_temp; + if ( _Ft_ == 0 ) return; + + _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, 1); + + if( cpucaps.hasStreamingSIMD2Extensions ) { + if( _XYZW_SS ) { + SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); + _vuFlipRegSS(VU, EEREC_T); + SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_T); + } + else if (_X_Y_Z_W != 0xf) { + SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); + SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } else { + SSE2_MOVD_M32_to_XMM(EEREC_T, VU_VI_ADDR(_Fs_, 1)-2); + SSE2_PSRAD_I8_to_XMM(EEREC_T, 16); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } + } + else { + MOVSX32M16toR(EAX, VU_VI_ADDR(_Fs_, 1)); + MOV32RtoM((uptr)&s_temp, EAX); + + if( _X_Y_Z_W != 0xf ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&s_temp); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_T, (uptr)&s_temp); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } + } +} + +void recVUMI_MTIR( VURegs *VU, int info ) +{ + if ( _Ft_ == 0 ) return; + + _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, 2); + + if( _Fsf_ == 0 ) { + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_S); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_TEMP); + } + + AND32ItoM(VU_VI_ADDR(_Ft_, 0), 0xffff); +} + +void recVUMI_MR32( VURegs *VU, int info ) +{ + if (_Ft_ == 0) return; + + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x39); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if( EEREC_T != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x39); + } +} + +// if x86reg < 0, reads directly from offset +void _loadEAX(VURegs *VU, int x86reg, uptr offset, int info) +{ + assert( offset < 0x80000000 ); + + if( x86reg >= 0 ) { + switch(_X_Y_Z_W) { + case 3: // ZW + SSE_MOVHPS_RmOffset_to_XMM(EEREC_T, x86reg, offset+8); + break; + case 6: // YZ + SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0x9c); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); + break; + + case 8: // X + SSE_MOVSS_RmOffset_to_XMM(EEREC_TEMP, x86reg, offset); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + break; + case 9: // XW + SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0xc9); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); + break; + case 12: // XY + SSE_MOVLPS_RmOffset_to_XMM(EEREC_T, x86reg, offset); + break; + case 15: + if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_T, x86reg, offset); + else SSE_MOVUPSRmtoROffset(EEREC_T, x86reg, offset); + break; + default: + if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else SSE_MOVUPSRmtoROffset(EEREC_TEMP, x86reg, offset); + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + break; + } + } + else { + switch(_X_Y_Z_W) { + case 3: // ZW + SSE_MOVHPS_M64_to_XMM(EEREC_T, offset+8); + break; + case 6: // YZ + SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0x9c); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); + break; + case 8: // X + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, offset); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + break; + case 9: // XW + SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0xc9); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); + break; + case 12: // XY + SSE_MOVLPS_M64_to_XMM(EEREC_T, offset); + break; + case 15: + if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_T, offset); + else SSE_MOVUPS_M128_to_XMM(EEREC_T, offset); + break; + default: + if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + else SSE_MOVUPS_M128_to_XMM(EEREC_TEMP, offset); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + break; + } + } +} + +int recVUTransformAddr(int x86reg, VURegs* VU, int vireg, int imm) +{ + u8* pjmp[2]; + if( x86reg == EAX ) { + if (imm) ADD32ItoR(x86reg, imm); + } + else { + if( imm ) LEA32RtoR(EAX, x86reg, imm); + else MOV32RtoR(EAX, x86reg); + } + + if( VU == &VU1 ) { + SHL32ItoR(EAX, 4); + AND32ItoR(EAX, 0x3fff); + } + else { + // if addr >= 4200, reads integers + CMP32ItoR(EAX, 0x420); + pjmp[0] = JL8(0); + AND32ItoR(EAX, 0x1f); + SHL32ItoR(EAX, 2); + OR32ItoR(EAX, 0x4200); + + pjmp[1] = JMP8(0); + x86SetJ8(pjmp[0]); + SHL32ItoR(EAX, 4); + AND32ItoR(EAX, 0xfff); // can be removed + + x86SetJ8(pjmp[1]); + } + + return EAX; +} + +void recVUMI_LQ(VURegs *VU, int info) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + if (_Fs_ == 0) { + _loadEAX(VU, -1, (uptr)GET_VU_MEM(VU, (u32)imm*16), info); + } else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem, info); + } +} + +void recVUMI_LQD( VURegs *VU, int info ) +{ + int fsreg; + + if ( _Fs_ != 0 ) { + fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); + SUB16ItoR( fsreg, 1 ); + } + + if ( _Ft_ == 0 ) return; + + if ( _Fs_ == 0 ) { + _loadEAX(VU, -1, (uptr)VU->Mem, info); + } else { + _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); + } +} + +void recVUMI_LQI(VURegs *VU, int info) +{ + int fsreg; + + if ( _Ft_ == 0 ) { + if( _Fs_ != 0 ) { + if( (fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_WRITE|MODE_READ)) >= 0 ) { + ADD16ItoR(fsreg, 1); + } + else { + ADD16ItoM( VU_VI_ADDR( _Fs_, 0 ), 1 ); + } + } + return; + } + + if (_Fs_ == 0) { + _loadEAX(VU, -1, (uptr)VU->Mem, info); + } else { + fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); + _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); + ADD16ItoR( fsreg, 1 ); + } +} + +void _saveEAX(VURegs *VU, int x86reg, uptr offset, int info) +{ + int t1reg; + assert( offset < 0x80000000 ); + + if( _Fs_ == 0 ) { + if( _XYZW_SS ) { + u32 c = _W ? 0x3f800000 : 0; + if( x86reg >= 0 ) MOV32ItoRmOffset(x86reg, c, offset+(_W?12:(_Z?8:(_Y?4:0)))); + else MOV32ItoM(offset+(_W?12:(_Z?8:(_Y?4:0))), c); + } + else { + int zeroreg = (x86reg == EAX) ? ALLOCTEMPX86(0) : EAX; + + XOR32RtoR(zeroreg, zeroreg); + if( x86reg >= 0 ) { + if( _X ) MOV32RtoRmOffset(x86reg, zeroreg, offset); + if( _Y ) MOV32RtoRmOffset(x86reg, zeroreg, offset+4); + if( _Z ) MOV32RtoRmOffset(x86reg, zeroreg, offset+8); + if( _W ) MOV32ItoRmOffset(x86reg, 0x3f800000, offset+12); + } + else { + if( _X ) MOV32RtoM(offset, zeroreg); + if( _Y ) MOV32RtoM(offset+4, zeroreg); + if( _Z ) MOV32RtoM(offset+8, zeroreg); + if( _W ) MOV32ItoM(offset+12, 0x3f800000); + } + + if( zeroreg != EAX ) _freeX86reg(zeroreg); + } + return; + } + + switch(_X_Y_Z_W) { + case 1: // W + //SysPrintf("SAVE EAX W\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset+12); + else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); + break; + case 2: // Z + //SysPrintf("SAVE EAX Z\n"); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); + else SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); + break; + case 3: // ZW + //SysPrintf("SAVE EAX ZW\n"); + if( x86reg >= 0 ) SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+8); + else SSE_MOVHPS_XMM_to_M64(offset+8, EEREC_S); + break; + case 5: // YW + //SysPrintf("SAVE EAX YW\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) { + SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVLPS_XMM_to_M64(offset+4, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + } + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); + break; + case 4: // Y + //SysPrintf("SAVE EAX Y\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xe1); + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); + else SSE_MOVSS_XMM_to_M32(offset+4, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xe1); + break; + case 6: // YZ + //SysPrintf("SAVE EAX YZ\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xc9); + if( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); + else SSE_MOVLPS_XMM_to_M64(offset+4, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xd2); + break; + case 7: // YZW + //SysPrintf("SAVE EAX YZW\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x39); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) { + SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVLPS_XMM_to_M64(offset+4, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + } + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x93); + break; + case 8: // X + //SysPrintf("SAVE EAX X\n"); + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + break; + case 9: // XW + //SysPrintf("SAVE EAX XW\n"); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + + if( cpucaps.hasStreamingSIMD3Extensions ) SSE3_MOVSLDUP_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + else SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x55); + + if( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + + break; + case 12: // XY + //SysPrintf("SAVE EAX XY\n"); + if( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); + else SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); + break; + + case 13: // XYW + //SysPrintf("SAVE EAX XYW\n"); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB4); //ZWYX + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) { + SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + + } + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB4); + break; + case 14: // XYZ + //SysPrintf("SAVE EAX XYZ\n"); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( x86reg >= 0 ) { + SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); + } + else { + SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); + } + break; + case 15: // XYZW + //SysPrintf("SAVE EAX XYZW\n"); + if( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRtoRmOffset(x86reg, EEREC_S, offset+0); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRtoRmOffset(x86reg, EEREC_S, offset+0); + else { + if( offset & 15 ) SSE_MOVUPS_XMM_to_M128(offset, EEREC_S); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); + } + } + break; + default: + //SysPrintf("SAVEEAX Default %d\n", _X_Y_Z_W); + // EEREC_D is a temp reg + // find the first nonwrite reg + t1reg = _vuGetTempXMMreg(info); + + if( t1reg < 0 ) { + for(t1reg = 0; t1reg < XMMREGS; ++t1reg) { + if( xmmregs[t1reg].inuse && !(xmmregs[t1reg].mode&MODE_WRITE) ) break; + } + + if( t1reg == XMMREGS ) t1reg = -1; + else { + if( t1reg != EEREC_S ) _allocTempXMMreg(XMMT_FPS, t1reg); + } + } + + if( t1reg >= 0 ) { + // found a temp reg + if( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else { + if( offset & 15 ) SSE_MOVUPS_M128_to_XMM(EEREC_TEMP, offset); + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + } + } + + if( t1reg != EEREC_S ) SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + + VU_MERGE_REGS(EEREC_TEMP, t1reg); + + if( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRtoRmOffset(x86reg, EEREC_TEMP, offset); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_TEMP); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRtoRmOffset(x86reg, EEREC_TEMP, offset); + else SSE_MOVUPS_XMM_to_M128(offset, EEREC_TEMP); + } + + if( t1reg != EEREC_S ) _freeXMMreg(t1reg); + else { + // read back the data + SSE_MOVAPS_M128_to_XMM(EEREC_S, (uptr)&VU->VF[_Fs_]); + } + } + else { + // do it with one reg + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + + if( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else { + if( offset & 15 ) SSE_MOVUPS_M128_to_XMM(EEREC_TEMP, offset); + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + } + } + + VU_MERGE_REGS(EEREC_TEMP, EEREC_S); + + if( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRtoRmOffset(x86reg, EEREC_TEMP, offset); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_TEMP); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRtoRmOffset(x86reg, EEREC_TEMP, offset); + else { + if( offset & 15 ) SSE_MOVUPS_XMM_to_M128(offset, EEREC_TEMP); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_TEMP); + } + } + + // read back the data + SSE_MOVAPS_M128_to_XMM(EEREC_S, (uptr)&VU->VF[_Fs_]); + } + + break; + } +} + +void recVUMI_SQ(VURegs *VU, int info) +{ + s16 imm; + + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + if ( _Ft_ == 0 ) { + _saveEAX(VU, -1, (uptr)GET_VU_MEM(VU, (int)imm * 16), info); + } + else { + int ftreg = ALLOCVI(_Ft_, MODE_READ); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, imm), (uptr)VU->Mem, info); + } +} + +void recVUMI_SQD(VURegs *VU, int info) +{ + if (_Ft_ == 0) { + _saveEAX(VU, -1, (uptr)VU->Mem, info); + } else { + int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); + SUB16ItoR( ftreg, 1 ); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); + } +} + +void recVUMI_SQI(VURegs *VU, int info) +{ + if (_Ft_ == 0) { + _saveEAX(VU, -1, (uptr)VU->Mem, info); + } else { + int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); + + ADD16ItoR( ftreg, 1 ); + } +} + +void recVUMI_ILW(VURegs *VU, int info) +{ + int ftreg; + s16 imm, off; + + if ( _Ft_ == 0 ) return; + + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + if (_X) off = 0; + else if (_Y) off = 4; + else if (_Z) off = 8; + else if (_W) off = 12; + + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if ( _Fs_ == 0 ) { + MOVZX32M16toR( ftreg, (uptr)GET_VU_MEM(VU, (int)imm * 16 + off) ); + } + else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + MOV32RmtoROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem + off); + } +} + +void recVUMI_ISW( VURegs *VU, int info ) +{ + s16 imm; + + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + + if (_Fs_ == 0) { + uptr off = (uptr)GET_VU_MEM(VU, (int)imm * 16); + int ftreg = ALLOCVI(_Ft_, MODE_READ); + + if (_X) MOV32RtoM(off, ftreg); + if (_Y) MOV32RtoM(off+4, ftreg); + if (_Z) MOV32RtoM(off+8, ftreg); + if (_W) MOV32RtoM(off+12, ftreg); + } + else { + int x86reg, fsreg, ftreg; + + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + x86reg = recVUTransformAddr(fsreg, VU, _Fs_, imm); + + if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); + if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); + if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); + if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); + } +} + +void recVUMI_ILWR( VURegs *VU, int info ) +{ + int off, ftreg; + + if ( _Ft_ == 0 ) return; + + if (_X) off = 0; + else if (_Y) off = 4; + else if (_Z) off = 8; + else if (_W) off = 12; + + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if ( _Fs_ == 0 ) { + MOVZX32M16toR( ftreg, (uptr)VU->Mem + off ); + } + else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + MOVZX32Rm16toROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem + off); + } +} + +void recVUMI_ISWR( VURegs *VU, int info ) +{ + int ftreg; + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if (_Fs_ == 0) { + if (_X) MOV32RtoM((uptr)VU->Mem, ftreg); + if (_Y) MOV32RtoM((uptr)VU->Mem+4, ftreg); + if (_Z) MOV32RtoM((uptr)VU->Mem+8, ftreg); + if (_W) MOV32RtoM((uptr)VU->Mem+12, ftreg); + } + else { + int x86reg; + int fsreg = ALLOCVI(_Fs_, MODE_READ); + x86reg = recVUTransformAddr(fsreg, VU, _Fs_, 0); + + if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); + if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); + if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); + if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); + } +} + +void recVUMI_RINIT(VURegs *VU, int info) +{ + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 2); + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)s_mask); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)s_fones); + SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); + } + else { + int rreg = ALLOCVI(REG_R, MODE_WRITE); + + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + MOV32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); + + AND32ItoR( rreg, 0x7fffff ); + OR32ItoR( rreg, 0x7f << 23 ); + } +} + +void recVUMI_RGET(VURegs *VU, int info) +{ + if ( _Ft_ == 0 ) return; + + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + + if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_REGR_ADDR); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_T, VU_REGR_ADDR); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } +} + +void recVUMI_RNEXT( VURegs *VU, int info ) +{ + int rreg, x86temp0, x86temp1; + if ( _Ft_ == 0) return; + + rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); + + x86temp0 = ALLOCTEMPX86(0); + x86temp1 = ALLOCTEMPX86(0); + + // code from www.project-fao.org + MOV32MtoR(rreg, VU_REGR_ADDR); + MOV32RtoR(x86temp0, rreg); + SHR32ItoR(x86temp0, 4); + AND32ItoR(x86temp0, 1); + + MOV32RtoR(x86temp1, rreg); + SHR32ItoR(x86temp1, 22); + AND32ItoR(x86temp1, 1); + + SHL32ItoR(rreg, 1); + XOR32RtoR(x86temp0, x86temp1); + XOR32RtoR(rreg, x86temp0); + AND32ItoR(rreg, 0x7fffff); + OR32ItoR(rreg, 0x3f800000); + + _freeX86reg(x86temp0); + _freeX86reg(x86temp1); + + recVUMI_RGET(VU, info); +} + +void recVUMI_RXOR( VURegs *VU, int info ) +{ + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode & MODE_NOFLUSH) ) { + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + SSE_XORPS_M128_to_XMM(EEREC_TEMP, VU_REGR_ADDR); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (u32)s_mask); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (u32)s_fones); + SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); + } + else { + int rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); + + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + XOR32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); + AND32ItoR( rreg, 0x7fffff ); + OR32ItoR ( rreg, 0x3f800000 ); + } +} + +void recVUMI_WAITQ( VURegs *VU, int info ) +{ +// if( info & PROCESS_VU_SUPER ) { +// //CALLFunc(waitqfn); +// SuperVUFlush(0, 1); +// } +} + +void recVUMI_FSAND( VURegs *VU, int info ) +{ + int ftreg; + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV32MtoR(ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1)); + AND32ItoR( ftreg, 0xFF&imm ); // yes 0xff not 0xfff since only first 8 bits are valid! +} + +void recVUMI_FSEQ( VURegs *VU, int info ) +{ + int ftreg; + u32 imm; + if ( _Ft_ == 0 ) return; + + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M8toR( EAX, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); + XOR32RtoR(ftreg, ftreg); + + CMP16ItoR(EAX, imm); + SETE8R(ftreg); +} + +void recVUMI_FSOR( VURegs *VU, int info ) +{ + int ftreg; + u32 imm; + if(_Ft_ == 0) return; + + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M8toR( ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); + OR32ItoR( ftreg, imm ); +} + +void recVUMI_FSSET(VURegs *VU, int info) +{ + u32 writeaddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); + u32 prevaddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); + + u16 imm = 0; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); + + // keep the low 6 bits ONLY if the upper instruction is an fmac instruction (otherwise rewrite) - metal gear solid 3 +// if( (info & PROCESS_VU_SUPER) && VUREC_FMAC ) { +// MOV32MtoR(EAX, prevaddr); +// AND32ItoR(EAX, 0x3f); +// if ((imm&0xfc0) != 0) OR32ItoR(EAX, imm & 0xFC0); +// MOV32RtoM(writeaddr ? writeaddr : prevaddr, EAX); +// } +// else { + MOV32ItoM(writeaddr ? writeaddr : prevaddr, imm&0xfc0); +// } +} + +void recVUMI_FMAND( VURegs *VU, int info ) +{ + int fsreg, ftreg; + if ( _Ft_ == 0 ) return; + + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_8BITREG); + + if( fsreg >= 0 ) { + if( ftreg != fsreg ) MOV32RtoR(ftreg, fsreg); + } + else MOV8MtoR(ftreg, VU_VI_ADDR(_Fs_, 1)); + + //AND16MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + AND8MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + MOVZX32R8toR(ftreg, ftreg); +} + +void recVUMI_FMEQ( VURegs *VU, int info ) +{ + int ftreg, fsreg; + if ( _Ft_ == 0 ) return; + + if( _Ft_ == _Fs_ ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_READ|MODE_8BITREG); + // really 8 since not doing under/over flows + CMP8MtoR(ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + SETE8R(EAX); + MOVZX32R8toR(ftreg, EAX); + } + else { + ADD_VI_NEEDED(_Fs_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_8BITREG); + + XOR32RtoR(ftreg, ftreg); + + CMP8MtoR(fsreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + SETE8R(ftreg); + } +} + +void recVUMI_FMOR( VURegs *VU, int info ) +{ + int fsreg, ftreg; + if ( _Ft_ == 0 ) return; + + if( _Fs_ == 0 ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_8BITREG); + MOVZX32M8toR(ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + } + if( _Ft_ == _Fs_ ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_READ|MODE_8BITREG); + OR8MtoR(ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + } + else { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M8toR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + + if( fsreg >= 0 ) { + OR16RtoR( ftreg, fsreg); + } + else { + OR16MtoR( ftreg, VU_VI_ADDR(_Fs_, 1)); + } + } +} + +void recVUMI_FCAND( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1)); + XOR32RtoR(ftreg, ftreg); + AND32ItoR( EAX, VU->code & 0xFFFFFF ); + SETNZ8R(ftreg); +} + +void recVUMI_FCEQ( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1)); + //AND32ItoR( EAX, 0xffffff); + XOR32RtoR(ftreg, ftreg); + CMP32ItoR( EAX, VU->code&0xffffff ); + SETE8R(ftreg); +} + +void recVUMI_FCOR( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1)); + //AND32ItoR( EAX, 0xffffff); + XOR32RtoR(ftreg, ftreg); + OR32ItoR( EAX, VU->code | 0xff000000 ); + ADD32ItoR(EAX, 1); + + // set to 1 if EAX is 0 + SETZ8R(ftreg); +} + +void recVUMI_FCSET( VURegs *VU, int info ) +{ + u32 addr = VU_VI_ADDR(REG_CLIP_FLAG, 0); + + MOV32ItoM(addr ? addr : VU_VI_ADDR(REG_CLIP_FLAG, 2), VU->code&0xffffff ); + + if( !(info & (PROCESS_VU_SUPER|PROCESS_VU_COP2)) ) + MOV32ItoM( VU_VI_ADDR(REG_CLIP_FLAG, 1), VU->code&0xffffff ); +} + +void recVUMI_FCGET( VURegs *VU, int info ) +{ + int ftreg; + if(_Ft_ == 0) return; + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOV32MtoR(ftreg, VU_VI_ADDR(REG_CLIP_FLAG, 1)); + AND32ItoR(ftreg, 0x0fff); +} + +// SuperVU branch fns are in ivuzerorec.cpp +static s32 _recbranchAddr(VURegs * VU) +{ + bpc = pc + (_Imm11_ << 3); + if (bpc < 0) { + bpc = pc + (_UImm11_ << 3); + } + if (VU == &VU1) { + bpc&= 0x3fff; + } else { + bpc&= 0x0fff; + } + + return bpc; +} + +void recVUMI_IBEQ(VURegs *VU, int info) +{ + int fsreg, ftreg; + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + bpc = _recbranchAddr(VU); + + CMP16RtoR( fsreg, ftreg ); + j8Ptr[ 0 ] = JNE8( 0 ); + + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_IBGEZ( VURegs *VU, int info ) +{ + int fsreg = ALLOCVI(_Fs_, MODE_READ); + + bpc = _recbranchAddr(VU); + + MOV16ItoM( VU_VI_ADDR(REG_TPC, 0), (int)pc ); + CMP16ItoR( fsreg, 0x0 ); + j8Ptr[ 0 ] = JL8( 0 ); + + // supervu will take care of the rest + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_IBGTZ( VURegs *VU, int info ) +{ + int fsreg = ALLOCVI(_Fs_, MODE_READ); + bpc = _recbranchAddr(VU); + + MOV16ItoM( VU_VI_ADDR(REG_TPC, 0), (int)pc ); + CMP16ItoR( fsreg, 0x0 ); + j8Ptr[ 0 ] = JLE8( 0 ); + + // supervu will take care of the rest + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_IBLEZ( VURegs *VU, int info ) +{ + int fsreg = ALLOCVI(_Fs_, MODE_READ); + + bpc = _recbranchAddr(VU); + + MOV16ItoM( VU_VI_ADDR(REG_TPC, 0), (int)pc ); + CMP16ItoR( fsreg, 0x0 ); + j8Ptr[ 0 ] = JG8( 0 ); + + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_IBLTZ( VURegs *VU, int info ) +{ + int fsreg = ALLOCVI(_Fs_, MODE_READ); + + bpc = _recbranchAddr(VU); + + MOV16ItoM( VU_VI_ADDR(REG_TPC, 0), (int)pc ); + CMP16ItoR( fsreg, 0x0 ); + j8Ptr[ 0 ] = JGE8( 0 ); + + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_IBNE( VURegs *VU, int info ) +{ + int fsreg, ftreg; + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + bpc = _recbranchAddr(VU); + + MOV16ItoM( VU_VI_ADDR(REG_TPC, 0), (int)pc ); + CMP16RtoR( fsreg, ftreg ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV16ItoM((uptr)&VU->branch, 2); + MOV32ItoM((uptr)&VU->branchpc, bpc); + + // only jump when not E bit + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +void recVUMI_B(VURegs *VU, int info) +{ + // supervu will take care of the rest + bpc = _recbranchAddr(VU); + + MOV32ItoM(VU_VI_ADDR(REG_TPC, 0), bpc); + + branch |= 3; +} + +void recVUMI_BAL( VURegs *VU, int info ) +{ + bpc = _recbranchAddr(VU); + + MOV32ItoM(VU_VI_ADDR(REG_TPC, 0), bpc); + + if ( _Ft_ ) { + int ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV16ItoR( ftreg, (pc+8)>>3 ); + } + + branch |= 3; +} + +void recVUMI_JR(VURegs *VU, int info) +{ + // fsreg cannot be ESP + int fsreg = ALLOCVI(_Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + MOV32RtoM(VU_VI_ADDR(REG_TPC, 0), EAX); + + branch |= 3; +} + +void recVUMI_JALR(VURegs *VU, int info) +{ + // fsreg cannot be ESP + int fsreg = ALLOCVI(_Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + MOV32RtoM(VU_VI_ADDR(REG_TPC, 0), EAX); + + if ( _Ft_ ) { + int ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV16ItoR( ftreg, (pc+8)>>3 ); + } + + branch |= 3; +} + +void recVUMI_MFP(VURegs *VU, int info) +{ + if (_Ft_ == 0) return; + + if( _XYZW_SS ) { + _vuFlipRegSS(VU, EEREC_T); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_T); + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_T, VU_VI_ADDR(REG_P, 1)); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } +} + +static PCSX2_ALIGNED16(float s_tempmem[4]); + +void recVUMI_WAITP(VURegs *VU, int info) +{ +// if( info & PROCESS_VU_SUPER ) +// SuperVUFlush(1, 1); +} + +// in all EFU insts, EEREC_D is a temp reg +void vuSqSumXYZ(int regd, int regs, int regtemp) +{ + if( cpucaps.hasStreamingSIMD4Extensions ) + { + SSE_MOVAPS_XMM_to_XMM(regd, regs); + SSE4_DPPS_XMM_to_XMM(regd, regd, 0x71); + } + else + { + SSE_MOVAPS_XMM_to_XMM(regtemp, regs); + SSE_MULPS_XMM_to_XMM(regtemp, regtemp); + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE3_HADDPS_XMM_to_XMM(regd, regtemp); + SSE_ADDPS_XMM_to_XMM(regd, regtemp); // regd.z = x+y+z + SSE_MOVHLPS_XMM_to_XMM(regd, regd); // move to x + } + else { + SSE_MOVSS_XMM_to_XMM(regd, regtemp); + SSE_SHUFPS_XMM_to_XMM(regtemp, regtemp, 0xE1); + SSE_ADDSS_XMM_to_XMM(regd, regtemp); + SSE_SHUFPS_XMM_to_XMM(regtemp, regtemp, 0xD2); + SSE_ADDSS_XMM_to_XMM(regd, regtemp); + //SSE_SHUFPS_XMM_to_XMM(regtemp, regtemp, 0xC6); + } + } + + //SysPrintf("SUMXYZ\n"); +} + +void recVUMI_ESADD( VURegs *VU, int info) +{ + assert( VU == &VU1 ); + //SysPrintf("ESADD\n"); + if( cpucaps.hasStreamingSIMD4Extensions ) + { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE4_DPPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x71); + } + else + { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE3_HADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); // EEREC_D.z = x+y+z + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_D); // move to x + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x55); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + + CheckForOverflowSS_(EEREC_TEMP, EEREC_D); + //SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + //SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_ERSADD( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + // almost same as vuSqSumXYZ + + if( cpucaps.hasStreamingSIMD4Extensions ) + { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE4_DPPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x71); + } + else + { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE3_HADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); // EEREC_D.z = x+y+z + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_D); // move to x + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x55); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + + // don't use RCPSS (very bad precision) + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + CheckForOverflowSS_(EEREC_TEMP, EEREC_D); + //SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + //SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_ELENG( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_ERLENG( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); //Dont want to use EEREC_D incase it overwrites something + //SysPrintf("ERLENG\n"); + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 0)); + //SSE_RSQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + //CheckForOverflowSS_(EEREC_TEMP, EEREC_D); + //SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + //SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_EATANxy( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + SSE_MOVLPS_XMM_to_M64((u32)s_tempmem, EEREC_S); + FLD32((uptr)&s_tempmem[0]); + FLD32((uptr)&s_tempmem[1]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[0]); + FLD32((uptr)&VU->VF[_Fs_].UL[1]); + } + + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} + +void recVUMI_EATANxz( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + SSE_MOVLPS_XMM_to_M64((u32)s_tempmem, EEREC_S); + FLD32((uptr)&s_tempmem[0]); + FLD32((uptr)&s_tempmem[2]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[0]); + FLD32((uptr)&VU->VF[_Fs_].UL[2]); + } + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} + +void recVUMI_ESUM( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // y+w, x+z + SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // y+w, y+w, x+z, x+z + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SSE_ADDSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + } + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_ERCPR( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + + // don't use RCPSS (very bad precision) + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + if( _Fsf_ ) SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, (0xe4e4>>(2*_Fsf_))&0xff); + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + + // revert + if( _Fsf_ ) SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, (0xe4e4>>(8-2*_Fsf_))&0xff); + } + else { + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + CheckForOverflowSS_(EEREC_TEMP, EEREC_D); + //SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); + //SSE_MAXSS_M32_to_XMM(EEREC_TEMP, (uptr)&g_minvals[0]); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +void recVUMI_ESQRT( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( _Fsf_ ) { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + } + else { + SSE_SQRTSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + } + else SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} + +#if defined(_MSC_VER) && !defined(__x86_64__) + +static u32 s_saveecx, s_saveedx, s_saveebx, s_saveesi, s_saveedi, s_saveebp; +float tempsqrt = 0; +extern float vuDouble(u32 f); +__declspec(naked) void tempERSQRT() +{ + __asm { + mov s_saveecx, ecx + mov s_saveedx, edx + mov s_saveebx, ebx + mov s_saveesi, esi + mov s_saveedi, edi + mov s_saveebp, ebp + } + + if (tempsqrt >= 0) { + tempsqrt = fpusqrtf(tempsqrt); + if (tempsqrt) { + tempsqrt = 1.0f / tempsqrt; + } + tempsqrt = vuDouble(*(u32*)&tempsqrt); + } + + __asm { + mov ecx, s_saveecx + mov edx, s_saveedx + mov ebx, s_saveebx + mov esi, s_saveesi + mov edi, s_saveedi + mov ebp, s_saveebp + ret + } +} +#endif + +void recVUMI_ERSQRT( VURegs *VU, int info ) +{ + int t1reg; + + assert( VU == &VU1 ); + +// if( _Fsf_ ) { +// if( xmmregs[EEREC_S].mode & MODE_WRITE ) { +// _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); +// SSE_MOVSS_XMM_to_M32((uptr)&tempsqrt, EEREC_TEMP); +// } +// else { +// MOV32MtoR(EAX, (uptr)&VU->VF[_Fs_].UL[_Fsf_]); +// MOV32RtoM((uptr)&tempsqrt, EAX); +// } +// } +// else { +// SSE_MOVSS_XMM_to_M32((uptr)&tempsqrt, EEREC_S); +// } +// +// +// CALLFunc((uptr)tempERSQRT); +// MOV32MtoR(EAX, (uptr)&tempsqrt); +// MOV32RtoM(VU_VI_ADDR(REG_P, 0), EAX); +/* + // need to explicitly check for 0 (naruto ultimate ninja) + if( _Fsf_ ) { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + //int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + //SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + //SSE_CMPNESS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + SysPrintf("ERSQRT\n"); + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 0)); + //SSE_ANDPS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + } + else { + //SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + //CMP32ItoM((uptr)&VU->VF[_Fs_].UL[_Fsf_], 0); + //j8Ptr[0] = JE8(0); + SysPrintf("ERSQRT2\n"); + SSE_RSQRTSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Fs_].UL[_Fsf_]); + //x86SetJ8(j8Ptr[0]); + } + } + else { + SysPrintf("ERSQRT3\n"); + SSE_RSQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + //SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + //SSE_CMPNESS_XMM_to_XMM(EEREC_D, EEREC_S); + //SSE_ANDPS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + } + +*/ + //SysPrintf("ERSQRT\n"); + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + if( _Fsf_ ) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + } + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) + { + SSE_MOVSS_M32_to_XMM(t1reg, (uptr)&VU->VF[0].UL[3]); + SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), t1reg); + + _freeXMMreg(t1reg); + } + else + { + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[3]); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 0)); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + } +} + +void recVUMI_ESIN( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((u32)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((u32)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FLD32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + FSIN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} + +void recVUMI_EATAN( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((u32)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((u32)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FLD32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + } + + FLD1(); + FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} + +void recVUMI_EEXP( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + FLDL2E(); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((u32)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((u32)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FMUL32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FMUL32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + // basically do 2^(log_2(e) * val) + FLD(0); + FRNDINT(); + FXCH(1); + FSUB32Rto0(1); + F2XM1(); + FLD1(); + FADD320toR(1); + FSCALE(); + FSTP(1); + + FSTP32(VU_VI_ADDR(REG_P, 0)); +} + +void recVUMI_XITOP( VURegs *VU, int info ) +{ + int ftreg; + if (_Ft_ == 0) return; + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->itop ); +} + +void recVUMI_XTOP( VURegs *VU, int info ) +{ + int ftreg; + if ( _Ft_ == 0 ) return; + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->top ); +} + +#if defined(_WIN32) && !defined(WIN32_PTHREADS) +extern HANDLE g_hGsEvent; +#else +extern pthread_cond_t g_condGsEvent; +#endif + +void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) +{ + u32 size; + u8* pmem; + u32* data = (u32*)((u8*)pMem + (addr&0x3fff)); + + static int scount = 0; + ++scount; + + size = GSgifTransferDummy(0, data, (0x4000-(addr&0x3fff))>>4); + + size = 0x4000-(size<<4)-(addr&0x3fff); + assert( size >= 0 ); + + // can't exceed 0x4000 +// left = addr+size-0x4000; +// if( left > 0 ) size -= left; + if( size > 0 ) { + + pmem = GSRingBufCopy(NULL, size, GS_RINGTYPE_P1); + assert( pmem != NULL ); + FreezeMMXRegs(1); + memcpy_fast(pmem, (u8*)pMem+addr, size); + FreezeMMXRegs(0); + // if( left > 0 ) { + // memcpy_fast(pmem+size-left, (u8*)pMem, left); + // } + GSRINGBUF_DONECOPY(pmem, size); + + if( !CHECK_DUALCORE ) { +#if defined(_WIN32) && !defined(WIN32_PTHREADS) + SetEvent(g_hGsEvent); +#else + pthread_cond_signal(&g_condGsEvent); +#endif + } + } +} + +void recVUMI_XGKICK( VURegs *VU, int info ) +{ + int fsreg = ALLOCVI(_Fs_, MODE_READ); + _freeX86reg(fsreg); + SHL32ItoR(fsreg, 4); + AND32ItoR(fsreg, 0x3fff); + + iFlushCall(FLUSH_NOCONST); + + _callPushArg(MEM_X86TAG, fsreg, X86ARG2); + _callPushArg(MEM_CONSTTAG, (uptr)VU->Mem, X86ARG1); + + if( CHECK_MULTIGS ) { + CALLFunc((uptr)VU1XGKICK_MTGSTransfer); +#ifndef __x86_64__ + ADD32ItoR(ESP, 8); +#endif + } + else { + FreezeMMXRegs(1); + //FreezeXMMRegs(1); + CALLFunc((uptr)GSgifTransfer1); + FreezeMMXRegs(0); + //FreezeXMMRegs(0); + } +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/iVUmicro.h b/pcsx2/x86/iVUmicro.h new file mode 100644 index 0000000000..526cc28464 --- /dev/null +++ b/pcsx2/x86/iVUmicro.h @@ -0,0 +1,274 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IVUMICRO_H__ +#define __IVUMICRO_H__ + +#define VU0_MEMSIZE 0x1000 +#define VU1_MEMSIZE 0x4000 + +#define RECOMPILE_VUMI_ABS +#define RECOMPILE_VUMI_SUB +#define RECOMPILE_VUMI_SUBA +#define RECOMPILE_VUMI_MADD +#define RECOMPILE_VUMI_MADDA +#define RECOMPILE_VUMI_MSUB +#define RECOMPILE_VUMI_MSUBA + +#define RECOMPILE_VUMI_ADD +#define RECOMPILE_VUMI_ADDA +#define RECOMPILE_VUMI_MUL +#define RECOMPILE_VUMI_MULA +#define RECOMPILE_VUMI_MAX +#define RECOMPILE_VUMI_MINI +#define RECOMPILE_VUMI_FTOI + +#define RECOMPILE_VUMI_MATH +#define RECOMPILE_VUMI_MISC +#define RECOMPILE_VUMI_E +#define RECOMPILE_VUMI_X +#define RECOMPILE_VUMI_RANDOM +#define RECOMPILE_VUMI_FLAG +#define RECOMPILE_VUMI_BRANCH +#define RECOMPILE_VUMI_ARITHMETIC +#define RECOMPILE_VUMI_LOADSTORE + +#ifdef __x86_64__ +#undef RECOMPILE_VUMI_X +#endif + +u32 GetVIAddr(VURegs * VU, int reg, int read, int info); // returns the correct VI addr +void recUpdateFlags(VURegs * VU, int reg, int info); + +void _recvuTestPipes(VURegs * VU); +void _recvuFlushFDIV(VURegs * VU); +void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); + +#define VUOP_READ 2 +#define VUOP_WRITE 4 + +// save on mem +typedef struct { + int cycle; + int cycles; + u8 statusflag; + u8 macflag; + u8 clipflag; + u8 dummy; + u8 q; + u8 p; + u16 pqinst; // bit of instruction specifying index (srec only) +} _vuopinfo; +extern _vuopinfo *cinfo; + +void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs); + +// allocates all the necessary regs and returns the indices +int eeVURecompileCode(VURegs *VU, _VURegsNum* regs); + +void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr); // used for MTGS in XGKICK + +extern _VURegsNum* g_VUregs; + +#define SWAP(x, y) *(u32*)&y ^= *(u32*)&x ^= *(u32*)&y ^= *(u32*)&x; +#define VUREC_INFO eeVURecompileCode(VU, g_VUregs) + +extern int vucycle; +extern int vucycleold; + + +/***************************************** + VU Micromode Upper instructions +*****************************************/ + +void recVUMI_ABS(VURegs *vuRegs, int info); +void recVUMI_ADD(VURegs *vuRegs, int info); +void recVUMI_ADDi(VURegs *vuRegs, int info); +void recVUMI_ADDq(VURegs *vuRegs, int info); +void recVUMI_ADDx(VURegs *vuRegs, int info); +void recVUMI_ADDy(VURegs *vuRegs, int info); +void recVUMI_ADDz(VURegs *vuRegs, int info); +void recVUMI_ADDw(VURegs *vuRegs, int info); +void recVUMI_ADDA(VURegs *vuRegs, int info); +void recVUMI_ADDAi(VURegs *vuRegs, int info); +void recVUMI_ADDAq(VURegs *vuRegs, int info); +void recVUMI_ADDAx(VURegs *vuRegs, int info); +void recVUMI_ADDAy(VURegs *vuRegs, int info); +void recVUMI_ADDAz(VURegs *vuRegs, int info); +void recVUMI_ADDAw(VURegs *vuRegs, int info); +void recVUMI_SUB(VURegs *vuRegs, int info); +void recVUMI_SUBi(VURegs *vuRegs, int info); +void recVUMI_SUBq(VURegs *vuRegs, int info); +void recVUMI_SUBx(VURegs *vuRegs, int info); +void recVUMI_SUBy(VURegs *vuRegs, int info); +void recVUMI_SUBz(VURegs *vuRegs, int info); +void recVUMI_SUBw(VURegs *vuRegs, int info); +void recVUMI_SUBA(VURegs *vuRegs, int info); +void recVUMI_SUBAi(VURegs *vuRegs, int info); +void recVUMI_SUBAq(VURegs *vuRegs, int info); +void recVUMI_SUBAx(VURegs *vuRegs, int info); +void recVUMI_SUBAy(VURegs *vuRegs, int info); +void recVUMI_SUBAz(VURegs *vuRegs, int info); +void recVUMI_SUBAw(VURegs *vuRegs, int info); +void recVUMI_MUL(VURegs *vuRegs, int info); +void recVUMI_MULi(VURegs *vuRegs, int info); +void recVUMI_MULq(VURegs *vuRegs, int info); +void recVUMI_MULx(VURegs *vuRegs, int info); +void recVUMI_MULy(VURegs *vuRegs, int info); +void recVUMI_MULz(VURegs *vuRegs, int info); +void recVUMI_MULw(VURegs *vuRegs, int info); +void recVUMI_MULA(VURegs *vuRegs, int info); +void recVUMI_MULAi(VURegs *vuRegs, int info); +void recVUMI_MULAq(VURegs *vuRegs, int info); +void recVUMI_MULAx(VURegs *vuRegs, int info); +void recVUMI_MULAy(VURegs *vuRegs, int info); +void recVUMI_MULAz(VURegs *vuRegs, int info); +void recVUMI_MULAw(VURegs *vuRegs, int info); +void recVUMI_MADD(VURegs *vuRegs, int info); +void recVUMI_MADDi(VURegs *vuRegs, int info); +void recVUMI_MADDq(VURegs *vuRegs, int info); +void recVUMI_MADDx(VURegs *vuRegs, int info); +void recVUMI_MADDy(VURegs *vuRegs, int info); +void recVUMI_MADDz(VURegs *vuRegs, int info); +void recVUMI_MADDw(VURegs *vuRegs, int info); +void recVUMI_MADDA(VURegs *vuRegs, int info); +void recVUMI_MADDAi(VURegs *vuRegs, int info); +void recVUMI_MADDAq(VURegs *vuRegs, int info); +void recVUMI_MADDAx(VURegs *vuRegs, int info); +void recVUMI_MADDAy(VURegs *vuRegs, int info); +void recVUMI_MADDAz(VURegs *vuRegs, int info); +void recVUMI_MADDAw(VURegs *vuRegs, int info); +void recVUMI_MSUB(VURegs *vuRegs, int info); +void recVUMI_MSUBi(VURegs *vuRegs, int info); +void recVUMI_MSUBq(VURegs *vuRegs, int info); +void recVUMI_MSUBx(VURegs *vuRegs, int info); +void recVUMI_MSUBy(VURegs *vuRegs, int info); +void recVUMI_MSUBz(VURegs *vuRegs, int info); +void recVUMI_MSUBw(VURegs *vuRegs, int info); +void recVUMI_MSUBA(VURegs *vuRegs, int info); +void recVUMI_MSUBAi(VURegs *vuRegs, int info); +void recVUMI_MSUBAq(VURegs *vuRegs, int info); +void recVUMI_MSUBAx(VURegs *vuRegs, int info); +void recVUMI_MSUBAy(VURegs *vuRegs, int info); +void recVUMI_MSUBAz(VURegs *vuRegs, int info); +void recVUMI_MSUBAw(VURegs *vuRegs, int info); +void recVUMI_MAX(VURegs *vuRegs, int info); +void recVUMI_MAXi(VURegs *vuRegs, int info); +void recVUMI_MAXx(VURegs *vuRegs, int info); +void recVUMI_MAXy(VURegs *vuRegs, int info); +void recVUMI_MAXz(VURegs *vuRegs, int info); +void recVUMI_MAXw(VURegs *vuRegs, int info); +void recVUMI_MINI(VURegs *vuRegs, int info); +void recVUMI_MINIi(VURegs *vuRegs, int info); +void recVUMI_MINIx(VURegs *vuRegs, int info); +void recVUMI_MINIy(VURegs *vuRegs, int info); +void recVUMI_MINIz(VURegs *vuRegs, int info); +void recVUMI_MINIw(VURegs *vuRegs, int info); +void recVUMI_OPMULA(VURegs *vuRegs, int info); +void recVUMI_OPMSUB(VURegs *vuRegs, int info); +void recVUMI_NOP(VURegs *vuRegs, int info); +void recVUMI_FTOI0(VURegs *vuRegs, int info); +void recVUMI_FTOI4(VURegs *vuRegs, int info); +void recVUMI_FTOI12(VURegs *vuRegs, int info); +void recVUMI_FTOI15(VURegs *vuRegs, int info); +void recVUMI_ITOF0(VURegs *vuRegs, int info); +void recVUMI_ITOF4(VURegs *vuRegs, int info); +void recVUMI_ITOF12(VURegs *vuRegs, int info); +void recVUMI_ITOF15(VURegs *vuRegs, int info); +void recVUMI_CLIP(VURegs *vuRegs, int info); + +/***************************************** + VU Micromode Lower instructions +*****************************************/ + +void recVUMI_DIV(VURegs *vuRegs, int info); +void recVUMI_SQRT(VURegs *vuRegs, int info); +void recVUMI_RSQRT(VURegs *vuRegs, int info); +void recVUMI_IADD(VURegs *vuRegs, int info); +void recVUMI_IADDI(VURegs *vuRegs, int info); +void recVUMI_IADDIU(VURegs *vuRegs, int info); +void recVUMI_IAND(VURegs *vuRegs, int info); +void recVUMI_IOR(VURegs *vuRegs, int info); +void recVUMI_ISUB(VURegs *vuRegs, int info); +void recVUMI_ISUBIU(VURegs *vuRegs, int info); +void recVUMI_MOVE(VURegs *vuRegs, int info); +void recVUMI_MFIR(VURegs *vuRegs, int info); +void recVUMI_MTIR(VURegs *vuRegs, int info); +void recVUMI_MR32(VURegs *vuRegs, int info); +void recVUMI_LQ(VURegs *vuRegs, int info); +void recVUMI_LQD(VURegs *vuRegs, int info); +void recVUMI_LQI(VURegs *vuRegs, int info); +void recVUMI_SQ(VURegs *vuRegs, int info); +void recVUMI_SQD(VURegs *vuRegs, int info); +void recVUMI_SQI(VURegs *vuRegs, int info); +void recVUMI_ILW(VURegs *vuRegs, int info); +void recVUMI_ISW(VURegs *vuRegs, int info); +void recVUMI_ILWR(VURegs *vuRegs, int info); +void recVUMI_ISWR(VURegs *vuRegs, int info); +void recVUMI_LOI(VURegs *vuRegs, int info); +void recVUMI_RINIT(VURegs *vuRegs, int info); +void recVUMI_RGET(VURegs *vuRegs, int info); +void recVUMI_RNEXT(VURegs *vuRegs, int info); +void recVUMI_RXOR(VURegs *vuRegs, int info); +void recVUMI_WAITQ(VURegs *vuRegs, int info); +void recVUMI_FSAND(VURegs *vuRegs, int info); +void recVUMI_FSEQ(VURegs *vuRegs, int info); +void recVUMI_FSOR(VURegs *vuRegs, int info); +void recVUMI_FSSET(VURegs *vuRegs, int info); +void recVUMI_FMAND(VURegs *vuRegs, int info); +void recVUMI_FMEQ(VURegs *vuRegs, int info); +void recVUMI_FMOR(VURegs *vuRegs, int info); +void recVUMI_FCAND(VURegs *vuRegs, int info); +void recVUMI_FCEQ(VURegs *vuRegs, int info); +void recVUMI_FCOR(VURegs *vuRegs, int info); +void recVUMI_FCSET(VURegs *vuRegs, int info); +void recVUMI_FCGET(VURegs *vuRegs, int info); +void recVUMI_IBEQ(VURegs *vuRegs, int info); +void recVUMI_IBGEZ(VURegs *vuRegs, int info); +void recVUMI_IBGTZ(VURegs *vuRegs, int info); +void recVUMI_IBLTZ(VURegs *vuRegs, int info); +void recVUMI_IBLEZ(VURegs *vuRegs, int info); +void recVUMI_IBNE(VURegs *vuRegs, int info); +void recVUMI_B(VURegs *vuRegs, int info); +void recVUMI_BAL(VURegs *vuRegs, int info); +void recVUMI_JR(VURegs *vuRegs, int info); +void recVUMI_JALR(VURegs *vuRegs, int info); +void recVUMI_MFP(VURegs *vuRegs, int info); +void recVUMI_WAITP(VURegs *vuRegs, int info); +void recVUMI_ESADD(VURegs *vuRegs, int info); +void recVUMI_ERSADD(VURegs *vuRegs, int info); +void recVUMI_ELENG(VURegs *vuRegs, int info); +void recVUMI_ERLENG(VURegs *vuRegs, int info); +void recVUMI_EATANxy(VURegs *vuRegs, int info); +void recVUMI_EATANxz(VURegs *vuRegs, int info); +void recVUMI_ESUM(VURegs *vuRegs, int info); +void recVUMI_ERCPR(VURegs *vuRegs, int info); +void recVUMI_ESQRT(VURegs *vuRegs, int info); +void recVUMI_ERSQRT(VURegs *vuRegs, int info); +void recVUMI_ESIN(VURegs *vuRegs, int info); +void recVUMI_EATAN(VURegs *vuRegs, int info); +void recVUMI_EEXP(VURegs *vuRegs, int info); +void recVUMI_XGKICK(VURegs *vuRegs, int info); +void recVUMI_XTOP(VURegs *vuRegs, int info); +void recVUMI_XITOP(VURegs *vuRegs, int info); +void recVUMI_XTOP( VURegs *VU , int info); + +#endif /* __IVUMICRO_H__ */ diff --git a/pcsx2/x86/iVUops.h b/pcsx2/x86/iVUops.h new file mode 100644 index 0000000000..2b4cc89ab2 --- /dev/null +++ b/pcsx2/x86/iVUops.h @@ -0,0 +1,44 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef _WIN32 +#pragma warning(disable:4244) +#endif + +#define REC_VUOP(VU, f) { \ + _freeXMMregs(&VU); \ + X86_32CODE(_freeMMXregs(); SetFPUstate();) \ + MOV32ItoM((u32)&VU.code, (u32)VU.code); \ + CALLFunc((u32)VU##MI_##f); \ +} + +#define REC_VUOPFLAGS(VU, f) { \ + _freeXMMregs(&VU); \ + X86_32CODE(_freeMMXregs(); SetFPUstate();) \ + MOV32ItoM((u32)&VU.code, (u32)VU.code); \ + CALLFunc((u32)VU##MI_##f); \ +} + +#define REC_VUBRANCH(VU, f) { \ + _freeXMMregs(&VU); \ + X86_32CODE(_freeMMXregs(); SetFPUstate();) \ + MOV32ItoM((u32)&VU.code, (u32)VU.code); \ + MOV32ItoM((u32)&VU.VI[REG_TPC].UL, (u32)pc); \ + CALLFunc((u32)VU##MI_##f); \ + branch = 1; \ +} diff --git a/pcsx2/x86/iVUzerorec.cpp b/pcsx2/x86/iVUzerorec.cpp new file mode 100644 index 0000000000..e051e7d2be --- /dev/null +++ b/pcsx2/x86/iVUzerorec.cpp @@ -0,0 +1,4578 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// Super VU recompiler - author: zerofrog(@gmail.com) + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include +#include + +#include "PS2Etypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PLUGINtypedefs // for GSgifTransfer1 + +#if defined(_WIN32) +#include +#else +#include +#include +#endif + +#include "PS2Edefs.h" +#include "zlib.h" +#include "Misc.h" +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" + +#include "Memory.h" +#include "Hw.h" +#include "GS.h" + +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "iVUzerorec.h" + +// temporary externs +extern u32 vudump; +extern void iDumpVU0Registers(); +extern void iDumpVU1Registers(); + +extern char* disVU1MicroUF(u32 code, u32 pc); +extern char* disVU1MicroLF(u32 code, u32 pc); + +extern _GSgifTransfer1 GSgifTransfer1; + +#ifdef __cplusplus +} +#endif + +#include +#include +#include +#include +using namespace std; + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +// SuperVURec optimization options, uncomment only for debugging purposes +#define SUPERVU_CACHING // vu programs are saved and queried via CRC (might query the wrong program) + // disable when in doubt +#define SUPERVU_WRITEBACKS // don't flush the writebacks after every block +#define SUPERVU_X86CACHING // use x86reg caching (faster) +#define SUPERVU_VIBRANCHDELAY // when integers are modified right before a branch that uses the integer, + // the old integer value is used in the branch + // fixes kh2 +#define SUPERVU_PROPAGATEFLAGS // the correct behavior of VUs, for some reason superman breaks gfx with it on... + +#ifndef _DEBUG +#define SUPERVU_INTERCACHING // registers won't be flushed at block boundaries (faster) +#endif + +#define SUPERVU_CHECKCONDITION 0 // has to be 0!! + +#define VU_EXESIZE 0x00800000 + +#define _Imm11_ ((s32)(vucode & 0x400 ? 0xfffffc00 | (vucode & 0x3ff) : vucode & 0x3ff)&0x3fff) +#define _UImm11_ ((s32)(vucode & 0x7ff)&0x3fff) + +#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register + +static const u32 QWaitTimes[] = { 6, 12 }; +static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 }; + +static u32 s_vuInfo; // info passed into rec insts + +static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; +static char* s_recVUMem = NULL, *s_recVUPtr = NULL; + +// tables +extern void (*recSVU_UPPER_OPCODE[64])(); +extern void (*recSVU_LOWER_OPCODE[128])(); + +#define INST_Q_READ 0x0001 // flush Q +#define INST_P_READ 0x0002 // flush P +#define INST_BRANCH_DELAY 0x0004 +#define INST_CLIP_WRITE 0x0040 // inst writes CLIP in the future +#define INST_STATUS_WRITE 0x0080 +#define INST_MAC_WRITE 0x0100 +#define INST_Q_WRITE 0x0200 +#define INST_CACHE_VI 0x0400 // write old vi value to s_VIBranchDelay +#define INST_DUMMY_ 0x8000 +#define INST_DUMMY 0x83c0 + +#define VFFREE_INVALID0 0x80000000 // (vffree[i]&0xf) is invalid + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +union VURecRegs +{ + struct { + u16 reg; + u16 type; + }; + u32 id; +}; + +#define SUPERVU_XGKICKDELAY 1 // yes this is needed as default (wipeout) + +class VuBaseBlock; + +struct VuFunctionHeader +{ + struct RANGE + { + RANGE() : pmem(NULL) {} + + u16 start, size; + void* pmem; // all the mem + }; + + VuFunctionHeader() : pprogfunc(NULL), startpc(0xffffffff) {} + ~VuFunctionHeader() { + for(vector::iterator it = ranges.begin(); it != ranges.end(); ++it) { + free(it->pmem); + } + } + + // returns true if the checksum for the current mem is the same as this fn + bool IsSame(void* pmem); + + u32 startpc; + void* pprogfunc; + + vector ranges; +}; + +struct VuBlockHeader +{ + VuBaseBlock* pblock; + u32 delay; +}; + +// one vu inst (lower and upper) +class VuInstruction +{ +public: + VuInstruction() { memset(this, 0, sizeof(VuInstruction)); nParentPc = -1; vicached = -1; } + + int nParentPc; // used for syncing with flag writes, -1 for no parent + + _vuopinfo info; + + _VURegsNum regs[2]; // [0] - lower, [1] - upper + u32 livevars[2]; // live variables right before this inst, [0] - inst, [1] - float + u32 addvars[2]; // live variables to add + u32 usedvars[2]; // set if var is used in the future including vars used in this inst + u32 keepvars[2]; + u16 pqcycles; // the number of cycles to stall if function writes to the regs + u16 type; // INST_ + + u32 pClipWrite, pMACWrite, pStatusWrite; // addrs to write the flags + u32 vffree[2]; + s8 vfwrite[2], vfread0[2], vfread1[2], vfacc[2]; + s8 vfflush[2]; // extra flush regs + s8 vicached; // if >= 0, then use the cached integer s_VIBranchDelay + + int SetCachedRegs(int upper, u32 vuxyz); + void Recompile(list::iterator& itinst, u32 vuxyz); +}; + +#define BLOCKTYPE_EOP 0x01 // at least one of the children of the block contains eop (or the block itself) +#define BLOCKTYPE_FUNCTION 0x02 +#define BLOCKTYPE_HASEOP 0x04 // last inst of block is an eop +#define BLOCKTYPE_MACFLAGS 0x08 +#define BLOCKTYPE_ANALYZED 0x40 +#define BLOCKTYPE_IGNORE 0x80 // special for recursive fns +#define BLOCKTYPE_ANALYZEDPARENT 0x100 + +// base block used when recompiling +class VuBaseBlock +{ +public: + typedef list LISTBLOCKS; + + VuBaseBlock(); + + // returns true if the leads to a EOP (ALL VU blocks must ret true) + void AssignVFRegs(); + void AssignVIRegs(int parent); + + // returns true if only xyz of the reg has been used so far + u32 GetModeXYZW(u32 curpc, int vfreg); + + list::iterator GetInstIterAtPc(int instpc); + void GetInstsAtPc(int instpc, list& listinsts); + + void Recompile(); + + u16 type; // BLOCKTYPE_ + u16 id; + u16 startpc; + u16 endpc; // first inst not in block + void* pcode; // x86 code pointer + void* pendcode; // end of the x86 code pointer + int cycles; + list insts; + list parents; + LISTBLOCKS blocks; // blocks branches to + u32* pChildJumps[4]; // addrs that need to be filled with the children's start addrs + // if highest bit is set, addr needs to be relational + u32 vuxyz; // corresponding bit is set if reg's xyz channels are used only + u32 vuxy; // corresponding bit is set if reg's xyz channels are used only + + _xmmregs startregs[XMMREGS], endregs[XMMREGS]; + int nStartx86, nEndx86; // indices into s_vecRegArray + + int allocX86Regs; + int prevFlagsOutOfBlock; +}; + +struct WRITEBACK +{ + WRITEBACK() : nParentPc(0), cycle(0) //, pStatusWrite(NULL), pMACWrite(NULL) + { + viwrite[0] = viwrite[1] = 0; + viread[0] = viread[1] = 0; + } + + void InitInst(VuInstruction* pinst, int cycle) const + { + u32 write = viwrite[0]|viwrite[1]; + pinst->type = ((write&(1<nParentPc = nParentPc; + pinst->info.cycle = cycle; + for(int i = 0; i < 2; ++i) { + pinst->regs[i].VIwrite = viwrite[i]; + pinst->regs[i].VIread = viread[i]; + } + } + + static int SortWritebacks(const WRITEBACK& w1, const WRITEBACK& w2) { + return w1.cycle < w2.cycle; + } + + int nParentPc; + int cycle; + u32 viwrite[2]; + u32 viread[2]; +}; + +struct VUPIPELINES +{ + fmacPipe fmac[8]; + fdivPipe fdiv; + efuPipe efu; + list< WRITEBACK > listWritebacks; +}; + +VuBaseBlock::VuBaseBlock() +{ + type = 0; endpc = 0; cycles = 0; pcode = NULL; id = 0; + memset(pChildJumps, 0, sizeof(pChildJumps)); + memset(startregs, 0, sizeof(startregs)); + memset(endregs, 0, sizeof(endregs)); + allocX86Regs = nStartx86 = nEndx86 = -1; + prevFlagsOutOfBlock = 0; +} + +#define SUPERVU_STACKSIZE 0x1000 + +static list s_listVUHeaders[2]; +static list* s_plistCachedHeaders[2]; +static VuFunctionHeader** recVUHeaders[2] = {NULL}; +static VuBlockHeader* recVUBlocks[2] = {NULL}; +static u8* recVUStack = NULL, *recVUStackPtr = NULL; +static vector<_x86regs> s_vecRegArray(128); + +static VURegs* VU = NULL; +static list s_listBlocks; +static u32 s_vu = 0; +static u32 s_UnconditionalDelay = 0; // 1 if there are two sequential branches and the last is unconditional +static u32 g_nLastBlockExecuted = 0; + +// Global functions +extern "C" void* SuperVUGetProgram(u32 startpc, int vuindex); +extern "C" void SuperVUCleanupProgram(u32 startpc, int vuindex); +static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex); +static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes); +static void SuperVUInitLiveness(VuBaseBlock* pblock); +static void SuperVULivenessAnalysis(); +static void SuperVUEliminateDeadCode(); +static void SuperVUAssignRegs(); + +//void SuperVUFreeXMMreg(int xmmreg, int xmmtype, int reg); +#define SuperVUFreeXMMreg 0&& +void SuperVUFreeXMMregs(u32* livevars); + +static u32* SuperVUStaticAlloc(u32 size); +static void SuperVURecompile(); +extern "C" void SuperVUEndProgram(); + +// allocate VU resources +void SuperVUInit(int vuindex) +{ + if( vuindex < 0 ) { + // upper 4 bits cannot be nonzero! + s_recVUMem = (char*)SysMmap(0x0c000000, VU_EXESIZE); + if( (uptr)s_recVUMem > 0x80000000 ) + SysPrintf("bad SuperVU alloc %x\n", s_recVUMem); + memset(s_recVUMem, 0xcd, VU_EXESIZE); + s_recVUPtr = s_recVUMem; + recVUStack = new u8[SUPERVU_STACKSIZE * 4]; + } + else { + recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex]/8]; + recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex]/8]; + s_plistCachedHeaders[vuindex] = new list[s_MemSize[vuindex]/8]; + } +} + +// destroy VU resources +void SuperVUDestroy(int vuindex) +{ + list::iterator it; + + if( vuindex < 0 ) { + SuperVUDestroy(0); + SuperVUDestroy(1); + SysMunmap((uptr)s_recVUMem, VU_EXESIZE); + s_recVUPtr = NULL; + delete[] recVUStack; recVUStack = NULL; + } + else { + delete[] recVUHeaders[vuindex]; recVUHeaders[vuindex] = NULL; + delete[] recVUBlocks[vuindex]; recVUBlocks[vuindex] = NULL; + + if( s_plistCachedHeaders[vuindex] != NULL ) { + for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { + FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; + s_plistCachedHeaders[vuindex][j].clear(); + } + delete[] s_plistCachedHeaders[vuindex]; s_plistCachedHeaders[vuindex] = NULL; + } + + FORIT(it, s_listVUHeaders[vuindex]) delete *it; + s_listVUHeaders[vuindex].clear(); + } +} + +// reset VU +void SuperVUReset(int vuindex) +{ + list::iterator it; + + if( vuindex < 0 ) { + SuperVUReset(0); + SuperVUReset(1); + + //memset(s_recVUMem, 0xcd, VU_EXESIZE); + s_recVUPtr = s_recVUMem; + + memset(recVUStack, 0, SUPERVU_STACKSIZE); + } + else { + if( recVUHeaders[vuindex] ) memset( recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex]/8) ); + if( recVUBlocks[vuindex] ) memset( recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex]/8) ); + + if( s_plistCachedHeaders[vuindex] != NULL ) { + for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { + FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; + s_plistCachedHeaders[vuindex][j].clear(); + } + } + + FORIT(it, s_listVUHeaders[vuindex]) delete *it; + s_listVUHeaders[vuindex].clear(); + } +} + +// clear the block and any joining blocks +void SuperVUClear(u32 startpc, u32 size, int vuindex) +{ + vector::iterator itrange; + list::iterator it = s_listVUHeaders[vuindex].begin(); + u32 endpc = startpc+size; + while( it != s_listVUHeaders[vuindex].end() ) { + + // for every fn, check if it has code in the range + FORIT(itrange, (*it)->ranges) { + if( startpc < (u32)itrange->start+itrange->size && itrange->start < endpc ) + break; + } + + if( itrange != (*it)->ranges.end() ) { + recVUHeaders[vuindex][(*it)->startpc/8] = NULL; +#ifdef SUPERVU_CACHING + list* plist = &s_plistCachedHeaders[vuindex][(*it)->startpc/8]; + plist->push_back(*it); + if( plist->size() > 10 ) { + // list is too big, delete + delete plist->front(); + plist->pop_front(); + } + it = s_listVUHeaders[vuindex].erase(it); +#else + delete *it; + it = s_listVUHeaders[vuindex].erase(it); +#endif + } + else ++it; + } +} + +static VuFunctionHeader* s_pFnHeader = NULL; +static VuBaseBlock* s_pCurBlock = NULL; +static VuInstruction* s_pCurInst = NULL; +static u32 s_StatusRead = 0, s_MACRead = 0, s_ClipRead = 0; // read addrs +static u32 s_PrevStatusWrite = 0, s_PrevMACWrite = 0, s_PrevClipWrite = 0, s_PrevIWrite = 0; +static u32 s_WriteToReadQ = 0; +static u32 s_VIBranchDelay = 0; // value of register to use in a vi branch delayed situation + +extern "C" { +u32 s_TotalVUCycles; // total cycles since start of program execution +} + +int SuperVUGetLiveness(int vfreg) +{ + assert( s_pCurInst != NULL ); + if( vfreg == 32 ) return ((s_pCurInst->livevars[0]&(1<usedvars[0]&(1<livevars[0]&(1<usedvars[0]&(1<livevars[1]&(1<usedvars[1]&(1<pStatusWrite); + assert(!read || addr != 0); + return addr; + } + case REG_MAC_FLAG: + { + return (read==2) ? s_PrevMACWrite : (read ? s_MACRead : s_pCurInst->pMACWrite); + } + case REG_CLIP_FLAG: + { + u32 addr = (read==2) ? s_PrevClipWrite : (read ? s_ClipRead : s_pCurInst->pClipWrite); + assert( !read || addr != 0 ); + return addr; + } + case REG_Q: return (read || s_WriteToReadQ) ? (uptr)&VU->VI[REG_Q] : (uptr)&VU->q; + case REG_P: return read ? (uptr)&VU->VI[REG_P] : (uptr)&VU->p; + case REG_I: return s_PrevIWrite; + } + +#ifdef SUPERVU_VIBRANCHDELAY + if( read != 0 && (s_pCurInst->regs[0].pipe == VUPIPE_BRANCH) && s_pCurInst->vicached >= 0 && s_pCurInst->vicached == reg ) { + // test for branch delays + return (uptr)&s_VIBranchDelay; + } +#endif + + return (uptr)&VU->VI[reg]; +} + +void SuperVUDumpBlock(list& blocks, int vuindex) +{ + FILE *f; + char filename[ 256 ], str[256]; + u32 *mem; + u32 i; + static int gid = 0; + +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf( filename, "dumps\\svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); +#endif + //SysPrintf( "dump1 %x => %s\n", s_pFnHeader->startpc, filename ); + + f = fopen( filename, "w" ); + + fprintf(f, "Format: upper_inst lower_inst\ntype f:vf_live_vars vf_used_vars i:vi_live_vars vi_used_vars inst_cycle pq_inst\n"); + fprintf(f, "Type: %.2x - qread, %.2x - pread, %.2x - clip_write, %.2x - status_write\n" + "%.2x - mac_write, %.2x -qflush\n", + INST_Q_READ, INST_P_READ, INST_CLIP_WRITE, INST_STATUS_WRITE, INST_MAC_WRITE, INST_Q_WRITE); + fprintf(f, "XMM: Upper: read0 read1 write acc temp; Lower: read0 read1 write acc temp\n\n"); + + list::iterator itblock; + list::iterator itinst; + VuBaseBlock::LISTBLOCKS::iterator itchild; + + FORIT(itblock, blocks) { + fprintf(f, "block:%c %x-%x; children: ", ((*itblock)->type&BLOCKTYPE_HASEOP)?'*':' ', + (*itblock)->startpc, (*itblock)->endpc-8); + FORIT(itchild, (*itblock)->blocks) { + fprintf(f, "%x ", (*itchild)->startpc); + } + fprintf(f, "; vuxyz = %x, vuxy = %x\n", (*itblock)->vuxyz&(*itblock)->insts.front().usedvars[1], + (*itblock)->vuxy&(*itblock)->insts.front().usedvars[1]); + + itinst = (*itblock)->insts.begin(); + i = (*itblock)->startpc; + while(itinst != (*itblock)->insts.end() ) { + assert( i <= (*itblock)->endpc ); + if( itinst->type & INST_DUMMY ) { + if( itinst->nParentPc >= 0 && !(itinst->type&INST_DUMMY_)) { + // search for the parent + fprintf(f, "writeback 0x%x (%x)\n", itinst->type, itinst->nParentPc); + } + } + else { + mem = (u32*)&VU->Micro[i]; + char* pstr = disVU1MicroUF( mem[1], i+4 ); + fprintf(f, "%.4x: %-40s", i, pstr); + if( mem[1] & 0x80000000 ) fprintf(f, " I=%f(%.8x)\n", *(float*)mem, mem[0]); + else fprintf(f, "%s\n", disVU1MicroLF( mem[0], i )); + i += 8; + } + + ++itinst; + } + + fprintf(f, "\n"); + + _x86regs* pregs; + if( (*itblock)->nStartx86 >= 0 || (*itblock)->nEndx86 >= 0 ) { + fprintf(f, "X86: AX CX DX BX SP BP SI DI\n"); + } + + if( (*itblock)->nStartx86 >= 0 ) { + pregs = &s_vecRegArray[(*itblock)->nStartx86]; + fprintf(f, "STR: "); + for(i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); + else fprintf(f, "-1 "); + } + fprintf(f, "\n"); + } + + if( (*itblock)->nEndx86 >= 0 ) { + fprintf(f, "END: "); + pregs = &s_vecRegArray[(*itblock)->nEndx86]; + for(i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); + else fprintf(f, "-1 "); + } + fprintf(f, "\n"); + } + + itinst = (*itblock)->insts.begin(); + for ( i = (*itblock)->startpc; i < (*itblock)->endpc; ++itinst ) { + + if( itinst->type & INST_DUMMY ) { + } + else { + sprintf(str, "%.4x:%x f:%.8x_%.8x", i, itinst->type, itinst->livevars[1], itinst->usedvars[1]); + fprintf(f, "%-46s i:%.8x_%.8x c:%d pq:%d\n", str, + itinst->livevars[0], itinst->usedvars[0], (int)itinst->info.cycle, (int)itinst->pqcycles ); + + sprintf(str, "XMM r0:%d r1:%d w:%d a:%d t:%x;", + itinst->vfread0[1], itinst->vfread1[1], itinst->vfwrite[1], itinst->vfacc[1], itinst->vffree[1]); + fprintf(f, "%-46s r0:%d r1:%d w:%d a:%d t:%x\n", str, + itinst->vfread0[0], itinst->vfread1[0], itinst->vfwrite[0], itinst->vfacc[0], itinst->vffree[0]); + i += 8; + } + } + +#ifdef __LINUX__ + // dump the asm + if( (*itblock)->pcode != NULL ) { + char command[255]; + FILE* fasm = fopen( "mydump1", "wb" ); + //SysPrintf("writing: %x, %x\n", (*itblock)->startpc, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode); + fwrite( (*itblock)->pcode, 1, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode, fasm ); + fclose( fasm ); +#ifdef __x86_64__ + sprintf( command, "objdump -D --target=binary --architecture=i386:x86-64 -M intel mydump1 > tempdump"); +#else + sprintf( command, "objdump -D --target=binary --architecture=i386 -M intel mydump1 > tempdump"); +#endif + system( command ); + fasm = fopen("tempdump", "r"); + // read all of it and write it to f + fseek(fasm, 0, SEEK_END); + vector vbuffer(ftell(fasm)); + fseek(fasm, 0, SEEK_SET); + fread(&vbuffer[0], vbuffer.size(), 1, fasm); + + fprintf(f, "\n\n"); + fwrite(&vbuffer[0], vbuffer.size(), 1, f); + fclose(fasm); + } +#endif + + fprintf(f, "\n---------------\n"); + } + + fclose( f ); +} + +extern "C" { +LARGE_INTEGER svubase, svufinal; +static u64 svutime; +} + +// uncomment to count svu exec time +//#define SUPERVU_COUNT +u64 SuperVUGetRecTimes(int clear) +{ + u64 temp = svutime; + if( clear ) svutime = 0; + return temp; +} + +// Private methods +void* SuperVUGetProgram(u32 startpc, int vuindex) +{ + assert( startpc < s_MemSize[vuindex] ); + assert( (startpc%8) == 0 ); + assert( recVUHeaders[vuindex] != NULL ); + VuFunctionHeader** pheader = &recVUHeaders[vuindex][startpc/8]; + + if( *pheader == NULL ) { +#ifdef _DEBUG +// if( vuindex ) VU1.VI[REG_TPC].UL = startpc; +// else VU0.VI[REG_TPC].UL = startpc; +// __Log("VU: %x\n", startpc); +// iDumpVU1Registers(); +// vudump |= 2; +#endif + + // measure run time + //QueryPerformanceCounter(&svubase); + +#ifdef SUPERVU_CACHING + void* pmem = (vuindex&1) ? VU1.Micro : VU0.Micro; + // check if program exists in cache + list::iterator it; + FORIT(it, s_plistCachedHeaders[vuindex][startpc/8]) { + if( (*it)->IsSame(pmem) ) { + // found, transfer to regular lists + void* pfn = (*it)->pprogfunc; + recVUHeaders[vuindex][startpc/8] = *it; + s_listVUHeaders[vuindex].push_back(*it); + s_plistCachedHeaders[vuindex][startpc/8].erase(it); + return pfn; + } + } +#endif + + *pheader = SuperVURecompileProgram(startpc, vuindex); + + if( *pheader == NULL ) { + assert( s_TotalVUCycles > 0 ); + if( vuindex ) VU1.VI[REG_TPC].UL = startpc; + else VU0.VI[REG_TPC].UL = startpc; + return (void*)SuperVUEndProgram; + } + + //QueryPerformanceCounter(&svufinal); + //svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); + + assert( (*pheader)->pprogfunc != NULL ); + } + //else assert( (*pheader)->IsSame((vuindex&1) ? VU1.Micro : VU0.Micro) ); + + assert( (*pheader)->startpc == startpc ); + + return (*pheader)->pprogfunc; +} + +bool VuFunctionHeader::IsSame(void* pmem) +{ +#ifdef SUPERVU_CACHING + //u32 checksum[2]; + vector::iterator it; + FORIT(it, ranges) { + //memxor_mmx(checksum, (u8*)pmem+it->start, it->size); + //if( checksum[0] != it->checksum[0] || checksum[1] != it->checksum[1] ) + // return false; + // memcmp_mmx doesn't work on x86-64 machines +#ifdef __x86_64__ + if( memcmp((u8*)pmem+it->start, it->pmem, it->size) ) +#else + if( memcmp_mmx((u8*)pmem+it->start, it->pmem, it->size) ) +#endif + return false; + } +#endif + return true; +} + +list::iterator VuBaseBlock::GetInstIterAtPc(int instpc) +{ + assert( instpc >= 0 ); + + u32 curpc = startpc; + list::iterator it; + for(it = insts.begin(); it != insts.end(); ++it) { + if( it->type & INST_DUMMY ) + continue; + + if( curpc == instpc ) + break; + curpc += 8; + } + + if( it != insts.end() ) + return it; + + assert( 0 ); + return insts.begin(); +} + +void VuBaseBlock::GetInstsAtPc(int instpc, list& listinsts) +{ + assert( instpc >= 0 ); + + listinsts.clear(); + + u32 curpc = startpc; + list::iterator it; + for(it = insts.begin(); it != insts.end(); ++it) { + if( it->type & INST_DUMMY ) + continue; + + if( curpc == instpc ) + break; + curpc += 8; + } + + if( it != insts.end() ) { + listinsts.push_back(&(*it)); + return; + } + + // look for the pc in other blocks + for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { + if( *itblock == this ) + continue; + + if( instpc >= (*itblock)->startpc && instpc < (*itblock)->endpc ) { + listinsts.push_back(&(*(*itblock)->GetInstIterAtPc(instpc))); + } + } + + assert(listinsts.size()>0); +} + +static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) +{ + assert( vuindex < 2 ); + assert( s_recVUPtr != NULL ); + //SysPrintf("svu%c rec: %x\n", '0'+vuindex, startpc); + + // if recPtr reached the mem limit reset whole mem + if ( ( (uptr)s_recVUPtr - (uptr)s_recVUMem ) >= VU_EXESIZE-0x40000 ) { + //SysPrintf("SuperVU reset mem\n"); + SuperVUReset(-1); + if( s_TotalVUCycles > 0 ) { + // already executing, so return NULL + return NULL; + } + } + + list::iterator itblock; + + s_vu = vuindex; + VU = s_vu ? &VU1 : &VU0; + s_pFnHeader = new VuFunctionHeader(); + s_listVUHeaders[vuindex].push_back(s_pFnHeader); + s_pFnHeader->startpc = startpc; + + memset( recVUBlocks[s_vu], 0, sizeof(VuBlockHeader) * (s_MemSize[s_vu]/8) ); + + // analyze the global graph + s_listBlocks.clear(); + VUPIPELINES pipes; + memset(pipes.fmac, 0, sizeof(pipes.fmac)); + memset(&pipes.fdiv, 0, sizeof(pipes.fdiv)); + memset(&pipes.efu, 0, sizeof(pipes.efu)); + SuperVUBuildBlocks(NULL, startpc, pipes); + + // fill parents + VuBaseBlock::LISTBLOCKS::iterator itchild; + FORIT(itblock, s_listBlocks) { + FORIT(itchild, (*itblock)->blocks) + (*itchild)->parents.push_back(*itblock); + + //(*itblock)->type &= ~(BLOCKTYPE_IGNORE|BLOCKTYPE_ANALYZED); + } + + assert( s_listBlocks.front()->startpc == startpc ); + s_listBlocks.front()->type |= BLOCKTYPE_FUNCTION; + + FORIT(itblock, s_listBlocks) { + SuperVUInitLiveness(*itblock); + } + + SuperVULivenessAnalysis(); + SuperVUEliminateDeadCode(); + SuperVUAssignRegs(); + +#ifdef _DEBUG + if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) + SuperVUDumpBlock(s_listBlocks, s_vu); +#endif + + // code generation + x86SetPtr(s_recVUPtr); + _initXMMregs(); + branch = 0; + + SuperVURecompile(); + + s_recVUPtr = x86Ptr; + + // set the function's range + VuFunctionHeader::RANGE r; + s_pFnHeader->ranges.reserve(s_listBlocks.size()); + + FORIT(itblock, s_listBlocks) { + r.start = (*itblock)->startpc; + r.size = (*itblock)->endpc-(*itblock)->startpc; +#ifdef SUPERVU_CACHING + //memxor_mmx(r.checksum, &VU->Micro[r.start], r.size); + r.pmem = malloc(r.size); + FreezeMMXRegs(1); + memcpy_fast(r.pmem, &VU->Micro[r.start], r.size); + FreezeMMXRegs(0); +#endif + s_pFnHeader->ranges.push_back(r); + } + +#if defined(_DEBUG) && defined(__LINUX__) + // dump at the end to capture the actual code + if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) + SuperVUDumpBlock(s_listBlocks, s_vu); +#endif + + // destroy + for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { + delete *itblock; + } + s_listBlocks.clear(); + + assert( s_recVUPtr < s_recVUMem+VU_EXESIZE ); + + return s_pFnHeader; +} + +static int _recbranchAddr(u32 vucode) { + u32 bpc = pc + (_Imm11_ << 3); + if (bpc < 0) { + bpc = pc + (_UImm11_ << 3); + } + bpc &= (s_MemSize[s_vu]-1); + + return bpc; +} + +// return inst that flushes everything +static VuInstruction SuperVUFlushInst() +{ + VuInstruction inst; + // don't need to raed q/p + inst.type = INST_DUMMY_;//|INST_Q_READ|INST_P_READ; + return inst; +} + +void SuperVUAddWritebacks(VuBaseBlock* pblock, const list& listWritebacks) +{ +#ifdef SUPERVU_WRITEBACKS + // regardless of repetition, add the pipes (for selfloops) + list::const_iterator itwriteback = listWritebacks.begin(); + list::iterator itinst = pblock->insts.begin(), itinst2; + + while(itwriteback != listWritebacks.end()) { + if( itinst != pblock->insts.end() && (itinst->info.cycle < itwriteback->cycle || (itinst->type&INST_DUMMY) ) ) { + ++itinst; + continue; + } + + itinst2 = pblock->insts.insert(itinst, VuInstruction()); + itwriteback->InitInst(&(*itinst2), vucycle); + ++itwriteback; + } +#endif +} + +static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes) +{ + // check if block already exists + //SysPrintf("startpc %x\n", startpc); + startpc &= (s_vu ? 0x3fff : 0xfff); + VuBlockHeader* pbh = &recVUBlocks[s_vu][startpc/8]; + + if ( pbh->pblock != NULL ) { + + VuBaseBlock* pblock = pbh->pblock; + list::iterator itinst; + + if( pblock->startpc == startpc ) { + SuperVUAddWritebacks(pblock, pipes.listWritebacks); + return pblock; + } + + // have to divide the blocks, pnewblock is first block + assert( startpc > pblock->startpc ); + assert( startpc < pblock->endpc ); + + u32 dummyinst = (startpc-pblock->startpc)>>3; + + // count inst non-dummy insts + itinst = pblock->insts.begin(); + u32 inst = 0; + int cycleoff = 0; + + while(dummyinst > 0) { + if( itinst->type & INST_DUMMY ) + ++itinst; + else { + cycleoff = itinst->info.cycle; + ++itinst; + --dummyinst; + } + } + + // NOTE: still leaves insts with their writebacks in different blocks + while( itinst->type & INST_DUMMY ) + ++itinst; + + // the difference in cycles between dummy insts (naruto utlimate ninja) + int cyclediff = 0; + if( parent == pblock ) + cyclediff = itinst->info.cycle-cycleoff; + cycleoff = itinst->info.cycle; + + // new block + VuBaseBlock* pnewblock = new VuBaseBlock(); + s_listBlocks.push_back(pnewblock); + + pnewblock->startpc = startpc; + pnewblock->endpc = pblock->endpc; + pnewblock->cycles = pblock->cycles-cycleoff+cyclediff; + + pnewblock->blocks.splice(pnewblock->blocks.end(), pblock->blocks); + pnewblock->insts.splice(pnewblock->insts.end(), pblock->insts, itinst, pblock->insts.end()); + pnewblock->type = pblock->type; + + // any writebacks in the next 3 cycles also belong to original block +// for(itinst = pnewblock->insts.begin(); itinst != pnewblock->insts.end(); ) { +// if( (itinst->type & INST_DUMMY) && itinst->nParentPc >= 0 && itinst->nParentPc < (int)startpc ) { +// +// if( !(itinst->type & INST_Q_WRITE) ) +// pblock->insts.push_back(*itinst); +// itinst = pnewblock->insts.erase(itinst); +// continue; +// } +// +// ++itinst; +// } + + pbh = &recVUBlocks[s_vu][startpc/8]; + for(u32 inst = startpc; inst < pblock->endpc; inst += 8) { + if( pbh->pblock == pblock ) + pbh->pblock = pnewblock; + ++pbh; + } + + FORIT(itinst, pnewblock->insts) + itinst->info.cycle -= cycleoff; + + SuperVUAddWritebacks(pnewblock, pipes.listWritebacks); + + // old block + pblock->blocks.push_back(pnewblock); + pblock->endpc = startpc; + pblock->cycles = cycleoff; + pblock->type &= BLOCKTYPE_MACFLAGS; + //pblock->insts.push_back(SuperVUFlushInst()); //don't need + + return pnewblock; + } + + VuBaseBlock* pblock = new VuBaseBlock(); + s_listBlocks.push_back(pblock); + + int i = 0; + branch = 0; + pc = startpc; + pblock->startpc = startpc; + + // clear stalls (might be a prob) + memcpy(VU->fmac, pipes.fmac, sizeof(pipes.fmac)); + memcpy(&VU->fdiv, &pipes.fdiv, sizeof(pipes.fdiv)); + memcpy(&VU->efu, &pipes.efu, sizeof(pipes.efu)); +// memset(VU->fmac, 0, sizeof(VU->fmac)); +// memset(&VU->fdiv, 0, sizeof(VU->fdiv)); +// memset(&VU->efu, 0, sizeof(VU->efu)); + + vucycle = 0; + + u8 macflags = 0; + + list< WRITEBACK > listWritebacks; + list< WRITEBACK >::iterator itwriteback; + list::iterator itinst; + u32 hasSecondBranch = 0; + u32 needFullStatusFlag = 0; + +#ifdef SUPERVU_WRITEBACKS + listWritebacks = pipes.listWritebacks; +#endif + + // first analysis pass for status flags + while(1) { + u32* ptr = (u32*)&VU->Micro[pc]; + pc += 8; + int prevbranch = branch; + + if( ptr[1] & 0x40000000 ) + branch = 1; + + if( !(ptr[1] & 0x80000000) ) { // not I + switch( ptr[0]>>25 ) { + case 0x24: // jr + case 0x25: // jalr + case 0x20: // B + case 0x21: // BAL + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + branch = 1; + break; + + case 0x14: // fseq + case 0x17: // fsor + //needFullStatusFlag = 2; + break; + + case 0x16: // fsand + if( (ptr[0]&0xc0) ) { + // sometimes full sticky bits are needed (simple series 2000 - oane chapara) + //SysPrintf("needSticky: %x-%x\n", s_pFnHeader->startpc, startpc); + needFullStatusFlag = 2; + } + break; + } + } + + if( prevbranch ) + break; + + if( pc >= s_MemSize[s_vu] ) { + SysPrintf("inf vu0 prog %x\n", startpc); + break; + } + } + + // second full pass + pc = startpc; + branch = 0; + VuInstruction* pprevinst=NULL, *ppprevinst=NULL, *pinst = NULL; + + while(1) { + + if( pc == s_MemSize[s_vu] ) { + branch |= 8; + break; + } + + if( !branch && pbh->pblock != NULL ) { + pblock->blocks.push_back(pbh->pblock); + break; + } + + int prevbranch = branch; + + if( !prevbranch ) { + pbh->pblock = pblock; + } + else assert( prevbranch || pbh->pblock == NULL); + + pblock->insts.push_back(VuInstruction()); + + ppprevinst = pprevinst; + pprevinst = pinst; + pinst = &pblock->insts.back(); + SuperVUAnalyzeOp(VU, &pinst->info, pinst->regs); + +#ifdef SUPERVU_VIBRANCHDELAY + if( pinst->regs[0].pipe == VUPIPE_BRANCH && pblock->insts.size() > 1 ) { + + if( pprevinst != NULL && pprevinst->info.cycle+1==pinst->info.cycle && + (pprevinst->regs[0].pipe == VUPIPE_IALU||pprevinst->regs[0].pipe == VUPIPE_FMAC) && ((pprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) + && !(pprevinst->regs[0].VIread&((1<Micro[pc-16]; + + // check for the previous instruction. If that has the same register used, then have a 2 cycle delay! + // (monsterhouse has sqi vi05, sqi vi05, ibeq vi05, vi03). The ibeq should read the vi05 before the first sqi + if( ppprevinst != NULL && ppprevinst->info.cycle+2==pinst->info.cycle && (ppprevinst->regs[0].pipe == VUPIPE_FMAC||ppprevinst->regs[0].pipe == VUPIPE_IALU) && + ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) && + ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) == ((ppprevinst->regs[0].VIwrite & pprevinst->regs[0].VIread) & 0xffff) && + !(ppprevinst->regs[0].VIread&((1<startpc); + + // ignore if prev instruction is ILW or ILWR (xenosaga 2) + lowercode = *(int*)&VU->Micro[pc-24]; + pdelayinst = ppprevinst; + } + + //SysPrintf("vurec: %x\n", pc); + // ignore if prev instruction is ILW or ILWR (xenosaga 2) + if( (lowercode>>25) != 4 // ILW + && !((lowercode>>25) == 0x40 && (lowercode&0x3ff)==0x3fe) ) { // ILWR + + //SysPrintf("branchdelay: %x: %x\n", s_pFnHeader->startpc, pc-8); + + // share the same register + pdelayinst->type |= INST_CACHE_VI; + + // find the correct register + u32 mask = pdelayinst->regs[0].VIwrite & pinst->regs[0].VIread; + for(int i = 0; i < 16; ++i) { + if( mask & (1<vicached = i; + break; + } + } + + pinst->vicached = pdelayinst->vicached; + } + } + } +#endif + + if( prevbranch ) { + if( pinst->regs[0].pipe == VUPIPE_BRANCH ) + hasSecondBranch = 1; + pinst->type |= INST_BRANCH_DELAY; + } + + // check write back + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ) { + if( pinst->info.cycle >= itwriteback->cycle ) { + itinst = pblock->insts.insert(--pblock->insts.end(), VuInstruction()); + itwriteback->InitInst(&(*itinst), pinst->info.cycle); + itwriteback = listWritebacks.erase(itwriteback); + } + else ++itwriteback; + } + + // add new writebacks + WRITEBACK w; + const u32 allflags = (1<regs[j].VIwrite & allflags; + + if( pinst->info.macflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.statusflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.macflag|pinst->info.statusflag) & VUOP_READ ) + macflags = 1; + if( pinst->regs[0].VIread & ((1<regs[1].pipe == VUPIPE_FMAC && (pinst->regs[1].VFwrite==0&&!(pinst->regs[1].VIwrite&(1<regs[0].VIread |= (1<VIwrite |= lregs->VIwrite & (1<info.statusflag&VUOP_WRITE)&&!(pinst->regs[0].VIwrite&(1<regs[j].VIread & allflags; + + if( (pinst->regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIwrite &= ~allflags; + } + + if( pinst->info.macflag & VUOP_READ) w.viread[1] |= 1<info.statusflag & VUOP_READ) w.viread[1] |= 1<info.cycle+4; + listWritebacks.push_back(w); + } + + if( pinst->info.q&VUOP_READ ) pinst->type |= INST_Q_READ; + if( pinst->info.p&VUOP_READ ) pinst->type |= INST_P_READ; + + if( pinst->info.q&VUOP_WRITE ) { + pinst->pqcycles = QWaitTimes[pinst->info.pqinst]+1; + + memset(&w, 0, sizeof(w)); + w.nParentPc = pc-8; + w.cycle = pinst->info.cycle+pinst->pqcycles; + w.viwrite[0] = 1<info.p&VUOP_WRITE ) + pinst->pqcycles = PWaitTimes[pinst->info.pqinst]+1; + + if( prevbranch ) { + break; + } + + // make sure there is always a branch + // sensible soccer overflows on vu0, so increase the limit... + if( (s_vu==1 && i >= 0x799) || (s_vu==0 && i >= 0x201) ) { + SysPrintf("VuRec base block doesn't terminate!\n"); + assert(0); + break; + } + + i++; + pbh++; + } + + if( macflags ) + pblock->type |= BLOCKTYPE_MACFLAGS; + + pblock->endpc = pc; + u32 lastpc = pc; + + pblock->cycles = vucycle; + +#ifdef SUPERVU_WRITEBACKS + if( !branch || (branch&8) ) +#endif + { + // flush writebacks + if( listWritebacks.size() > 0 ) { + listWritebacks.sort(WRITEBACK::SortWritebacks); + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { + if( itwriteback->viwrite[0] & (1<insts.push_back(VuInstruction()); + itwriteback->InitInst(&pblock->insts.back(), vucycle); + } + + listWritebacks.clear(); + } + } + + if( !branch ) + return pblock; + + if( branch & 8 ) { + // what if also a jump? + pblock->type |= BLOCKTYPE_EOP|BLOCKTYPE_HASEOP; + + // add an instruction to flush p and q (if written) + pblock->insts.push_back(SuperVUFlushInst()); + return pblock; + } + + // it is a (cond) branch or a jump + u32 vucode = *(u32*)(VU->Micro+lastpc-16); + int bpc = _recbranchAddr(vucode)-8; + + VUPIPELINES newpipes; + memcpy(newpipes.fmac, VU->fmac, sizeof(newpipes.fmac)); + memcpy(&newpipes.fdiv, &VU->fdiv, sizeof(newpipes.fdiv)); + memcpy(&newpipes.efu, &VU->efu, sizeof(newpipes.efu)); + + for(i = 0; i < 8; ++i) newpipes.fmac[i].sCycle -= vucycle; + newpipes.fdiv.sCycle -= vucycle; + newpipes.efu.sCycle -= vucycle; + + if( listWritebacks.size() > 0 ) { + // flush all when jumping, send down the pipe when in branching + bool bFlushWritebacks = (vucode>>25)==0x24||(vucode>>25)==0x25;//||(vucode>>25)==0x20||(vucode>>25)==0x21; + + listWritebacks.sort(WRITEBACK::SortWritebacks); + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { + if( itwriteback->viwrite[0] & (1<cycle < vucycle || bFlushWritebacks ) { + pblock->insts.push_back(VuInstruction()); + itwriteback->InitInst(&pblock->insts.back(), vucycle); + } + else { + newpipes.listWritebacks.push_back(*itwriteback); + newpipes.listWritebacks.back().cycle -= vucycle; + } + } + } + + if( newpipes.listWritebacks.size() > 0 ) // other blocks might read the mac flags + pblock->type |= BLOCKTYPE_MACFLAGS; + + u32 firstbranch = vucode>>25; + switch(firstbranch) { + case 0x24: // jr + pblock->type |= BLOCKTYPE_EOP; // jump out of procedure, since not returning, set EOP + pblock->insts.push_back(SuperVUFlushInst()); + break; + + case 0x25: // jalr + { + // linking, so will return to procedure + pblock->insts.push_back(SuperVUFlushInst()); + + VuBaseBlock* pjumpblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + + pblock->blocks.push_back(pjumpblock); + break; + } + case 0x20: // B + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x21: // BAL + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + pblock->blocks.push_back(pbranchblock); + + // if has a second branch that is B or BAL, skip this + u32 secondbranch = (*(u32*)(VU->Micro+lastpc-8))>>25; + if( !hasSecondBranch || (secondbranch != 0x21 && secondbranch != 0x20) ) { + pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + } + + break; + } + default: + assert(pblock->blocks.size() == 1); + break; + } + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + + if( hasSecondBranch ) { + u32 vucode = *(u32*)(VU->Micro+lastpc-8); + pc = lastpc; + int bpc = _recbranchAddr(vucode); + + switch(vucode>>25) { + case 0x24: // jr + SysPrintf("svurec bad jr jump!\n"); + assert(0); + break; + + case 0x25: // jalr + { + SysPrintf("svurec bad jalr jump!\n"); + assert(0); + break; + } + case 0x20: // B + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x21: // BAL + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // replace instead of pushing a new block + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + + // only add the block if the previous branch doesn't include the next instruction (ie, if a direct jump) + if( firstbranch == 0x24 || firstbranch == 0x25 || firstbranch == 0x20 || firstbranch == 0x21 ) { + pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + } + + break; + } + default: + assert(0); + } + } + + return recVUBlocks[s_vu][startpc/8].pblock; +} + +static void SuperVUInitLiveness(VuBaseBlock* pblock) +{ + list::iterator itinst, itnext; + + assert( pblock->insts.size() > 0 ); + + for(itinst = pblock->insts.begin(); itinst != pblock->insts.end(); ++itinst) { + + if( itinst->type & INST_DUMMY_ ) { + itinst->addvars[0] = itinst->addvars[1] = 0xffffffff; + itinst->livevars[0] = itinst->livevars[1] = 0xffffffff; + itinst->keepvars[0] = itinst->keepvars[1] = 0xffffffff; + itinst->usedvars[0] = itinst->usedvars[1] = 0; + } + else { + itinst->addvars[0] = itinst->regs[0].VIread | itinst->regs[1].VIread; + itinst->addvars[1] = (itinst->regs[0].VFread0 ? (1 << itinst->regs[0].VFread0) : 0) | + (itinst->regs[0].VFread1 ? (1 << itinst->regs[0].VFread1) : 0) | + (itinst->regs[1].VFread0 ? (1 << itinst->regs[1].VFread0) : 0) | + (itinst->regs[1].VFread1 ? (1 << itinst->regs[1].VFread1) : 0); + + // vf0 is not handled by VFread + if( !itinst->regs[0].VFread0 && (itinst->regs[0].VIread & (1<addvars[1] |= 1; + if( !itinst->regs[1].VFread0 && (itinst->regs[1].VIread & (1<addvars[1] |= 1; + if( !itinst->regs[0].VFread1 && (itinst->regs[0].VIread & (1<regs[0].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; + if( !itinst->regs[1].VFread1 && (itinst->regs[1].VIread & (1<regs[1].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; + + + u32 vfwrite = 0; + if( itinst->regs[0].VFwrite != 0 ) { + if( itinst->regs[0].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[0].VFwrite; + else vfwrite |= 1<regs[0].VFwrite; + } + if( itinst->regs[1].VFwrite != 0 ) { + if( itinst->regs[1].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[1].VFwrite; + else vfwrite |= 1<regs[1].VFwrite; + } + if( (itinst->regs[1].VIwrite & (1<regs[1].VFwxyzw != 0xf ) + itinst->addvars[1] |= 1<regs[0].VIwrite|itinst->regs[1].VIwrite); + + itinst->usedvars[0] = itinst->addvars[0]|viwrite; + itinst->usedvars[1] = itinst->addvars[1]|vfwrite; + +// itinst->addvars[0] &= ~viwrite; +// itinst->addvars[1] &= ~vfwrite; + itinst->keepvars[0] = ~viwrite; + itinst->keepvars[1] = ~vfwrite; + } + } + + itinst = --pblock->insts.end(); + while( itinst != pblock->insts.begin() ) { + itnext = itinst; --itnext; + + itnext->usedvars[0] |= itinst->usedvars[0]; + itnext->usedvars[1] |= itinst->usedvars[1]; + + itinst = itnext; + } +} + +u32 COMPUTE_LIVE(u32 R, u32 K, u32 L) +{ + u32 live = R | ((L)&(K)); + // special process mac and status flags + // only propagate liveness if doesn't write to the flag + if( !(L&(1<::reverse_iterator itblock; + list::iterator itinst, itnext; + VuBaseBlock::LISTBLOCKS::iterator itchild; + + u32 livevars[2]; + + do { + changed = FALSE; + for(itblock = s_listBlocks.rbegin(); itblock != s_listBlocks.rend(); ++itblock) { + + u32 newlive; + VuBaseBlock* pb = *itblock; + + // the last inst relies on the neighbor's insts + itinst = --pb->insts.end(); + + if( pb->blocks.size() > 0 ) { + livevars[0] = 0; livevars[1] = 0; + for( itchild = pb->blocks.begin(); itchild != pb->blocks.end(); ++itchild) { + VuInstruction& front = (*itchild)->insts.front(); + livevars[0] |= front.livevars[0]; + livevars[1] |= front.livevars[1]; + } + + newlive = COMPUTE_LIVE(itinst->addvars[0], itinst->keepvars[0], livevars[0]); + + // should propagate status flags whose parent insts are not in this block +// if( itinst->nParentPc >= 0 && (itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) +// newlive |= livevars[0]&((1<livevars[0] != newlive ) { + changed = TRUE; + itinst->livevars[0] = newlive; + } + + newlive = COMPUTE_LIVE(itinst->addvars[1], itinst->keepvars[1], livevars[1]); + if( itinst->livevars[1] != newlive ) { + changed = TRUE; + itinst->livevars[1] = newlive; + } + } + + while( itinst != pb->insts.begin() ) { + + itnext = itinst; --itnext; + + newlive = COMPUTE_LIVE(itnext->addvars[0], itnext->keepvars[0], itinst->livevars[0]); + + // should propagate status flags whose parent insts are not in this block +// if( itnext->nParentPc >= 0 && (itnext->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) && !(itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) +// newlive |= itinst->livevars[0]&((1<livevars[0] != newlive ) { + changed = TRUE; + itnext->livevars[0] = newlive; + itnext->livevars[1] = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); + } + else { + newlive = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); + if( itnext->livevars[1] != newlive ) { + changed = TRUE; + itnext->livevars[1] = newlive; + } + } + + itinst = itnext; + } + +// if( (livevars[0] | itinst->livevars[0]) != itinst->livevars[0] ) { +// changed = TRUE; +// itinst->livevars[0] |= livevars[0]; +// } +// if( (livevars[1] | itinst->livevars[1]) != itinst->livevars[1] ) { +// changed = TRUE; +// itinst->livevars[1] |= livevars[1]; +// } +// +// while( itinst != pb->insts.begin() ) { +// +// itnext = itinst; --itnext; +// if( (itnext->livevars[0] | (itinst->livevars[0] & itnext->keepvars[0])) != itnext->livevars[0] ) { +// changed = TRUE; +// itnext->livevars[0] |= itinst->livevars[0] & itnext->keepvars[0]; +// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; +// } +// else if( (itnext->livevars[1] | (itinst->livevars[1] & itnext->keepvars[1])) != itnext->livevars[1] ) { +// changed = TRUE; +// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; +// } +// +// itinst = itnext; +// } + } + + } while(changed); +} + +static void SuperVUEliminateDeadCode() +{ + list::iterator itblock; + VuBaseBlock::LISTBLOCKS::iterator itchild; + list::iterator itinst, itnext; + list listParents; + list::iterator itparent; + + FORIT(itblock, s_listBlocks) { + +#ifdef _DEBUG + u32 startpc = (*itblock)->startpc; + u32 curpc = startpc; +#endif + + itnext = (*itblock)->insts.begin(); + itinst = itnext++; + while(itnext != (*itblock)->insts.end() ) { + if( itinst->type & (INST_CLIP_WRITE|INST_MAC_WRITE|INST_STATUS_WRITE) ) { + u32 live0 = itnext->livevars[0]; + if( itinst->nParentPc >= 0 && itnext->nParentPc >= 0 && itinst->nParentPc != itnext->nParentPc ) { // superman returns + // take the live vars from the next next inst + list::iterator itnextnext = itnext; ++itnextnext; + if( itnextnext != (*itblock)->insts.end() ) { + live0 = itnextnext->livevars[0]; + } + } + + itinst->regs[0].VIwrite &= live0; + itinst->regs[1].VIwrite &= live0; + + u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; + + (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); + int removetype = 0; + + FORIT(itparent, listParents) { + VuInstruction* parent = *itparent; + + if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { + if( !(viwrite&(1<info.macflag = 0; + // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { + if( !(viwrite&(1<info.statusflag = 0; + // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; + if( itinst->type == 0 ) { + itnext = (*itblock)->insts.erase(itinst); + itinst = itnext++; + continue; + } + } +#ifdef _DEBUG + else curpc += 8; +#endif + itinst = itnext; + ++itnext; + } + + if( itinst->type & INST_DUMMY ) { + // last inst with the children + u32 mask = 0; + for(itchild = (*itblock)->blocks.begin(); itchild != (*itblock)->blocks.end(); ++itchild) { + mask |= (*itchild)->insts.front().livevars[0]; + } + itinst->regs[0].VIwrite &= mask; + itinst->regs[1].VIwrite &= mask; + u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; + + if( itinst->nParentPc >= 0 ) { + + (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); + int removetype = 0; + + FORIT(itparent, listParents) { + VuInstruction* parent = *itparent; + + if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { + if( !(viwrite&(1<info.macflag = 0; +#ifndef SUPERVU_WRITEBACKS + assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { + if( !(viwrite&(1<info.statusflag = 0; +#ifndef SUPERVU_WRITEBACKS + assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; + if( itinst->type == 0 ) { + (*itblock)->insts.erase(itinst); + } + } + } + } +} + +// assigns xmm/x86 regs to all instructions, ignore mode field +// returns true if changed +bool AlignStartRegsToEndRegs(_xmmregs* startregs, const list& parents) +{ + list::const_iterator itblock, itblock2; + int bestscore; + _xmmregs bestregs; + bool bchanged = false; + + // find the best merge of regs that minimizes writes/reads + for(int i = 0; i < XMMREGS; ++i) { + + bestscore = 1000; + memset(&bestregs, 0, sizeof(bestregs)); + + FORIT(itblock, parents) { + int curscore = 0; + if( ((*itblock)->type & BLOCKTYPE_ANALYZED) && (*itblock)->endregs[i].inuse ) { + int type = (*itblock)->endregs[i].type; + int reg = (*itblock)->endregs[i].reg; + + FORIT(itblock2, parents) { + if( (*itblock2)->type & BLOCKTYPE_ANALYZED ) { + if( (*itblock2)->endregs[i].inuse ) { + if( (*itblock2)->endregs[i].type != type || (*itblock2)->endregs[i].reg != reg ) { + curscore += 1; + } + } + else curscore++; + } + } + } + + if( curscore < 1 && curscore < bestscore ) { + memcpy(&bestregs, &(*itblock)->endregs[i], sizeof(bestregs)); + bestscore = curscore; + } + } + + if( bestscore < 1 ) { + if( startregs[i].inuse == bestregs.inuse ) { + if( bestregs.inuse && (startregs[i].type != bestregs.type || startregs[i].reg != bestregs.reg) ) + bchanged = true; + } + else bchanged = true; + + memcpy(&startregs[i], &bestregs, sizeof(bestregs)); + FORIT(itblock, parents) memcpy(&(*itblock)->endregs[i], &bestregs, sizeof(bestregs)); + } + else { + if( startregs[i].inuse ) bchanged = true; + startregs[i].inuse = 0; + FORIT(itblock, parents) (*itblock)->endregs[i].inuse = 0; + } + } + + return bchanged; +} + +void VuBaseBlock::AssignVFRegs() +{ + int i; + VuBaseBlock::LISTBLOCKS::iterator itchild; + list::iterator itblock; + list::iterator itinst, itnext, itinst2; + + // init the start regs + if( type & BLOCKTYPE_ANALYZED ) return; // nothing changed + memcpy(xmmregs, startregs, sizeof(xmmregs)); + + if( type & BLOCKTYPE_ANALYZED ) { + // check if changed + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse != startregs[i].inuse ) + break; + if( xmmregs[i].inuse && (xmmregs[i].reg != startregs[i].reg || xmmregs[i].type != startregs[i].type) ) + break; + } + + if( i == XMMREGS ) return; // nothing changed + } + + s8* oldX86 = x86Ptr; + + FORIT(itinst, insts) { + + if( itinst->type & INST_DUMMY ) + continue; + + // reserve, go from upper to lower + int lastwrite = -1; + + for(i = 1; i >= 0; --i) { + _VURegsNum* regs = itinst->regs+i; + + // redo the counters so that the proper regs are released + for(int j = 0; j < XMMREGS; ++j) { + if( xmmregs[j].inuse ) { + if( xmmregs[j].type == XMMTYPE_VFREG ) { + int count = 0; + itinst2 = itinst; + + if( i ) { + if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg ) { + itinst2 = insts.end(); + break; + } + else { + ++count; + ++itinst2; + } + } + + while(itinst2 != insts.end() ) { + if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg || + itinst2->regs[1].VFread0 == xmmregs[j].reg || itinst2->regs[1].VFread1 == xmmregs[j].reg || itinst2->regs[1].VFwrite == xmmregs[j].reg) + break; + + ++count; + ++itinst2; + } + xmmregs[j].counter = 1000-count; + } + else { + assert( xmmregs[j].type == XMMTYPE_ACC ); + + int count = 0; + itinst2 = itinst; + + if( i ) ++itinst2; // acc isn't used in lower insts + + while(itinst2 != insts.end() ) { + assert( !((itinst2->regs[0].VIread|itinst2->regs[0].VIwrite) & (1<regs[1].VIread|itinst2->regs[1].VIwrite) & (1<VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); + if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); + if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); + if( regs->VIread & (1<VIread & (1<vfread0[i] = itinst->vfread1[i] = itinst->vfwrite[i] = itinst->vfacc[i] = -1; + itinst->vfflush[i] = -1; + + if( regs->VFread0 ) itinst->vfread0[i] = _allocVFtoXMMreg(VU, -1, regs->VFread0, 0); + else if( regs->VIread & (1<vfread0[i] = _allocVFtoXMMreg(VU, -1, 0, 0); + if( regs->VFread1 ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, regs->VFread1, 0); + else if( (regs->VIread & (1<VFr1xyzw != 0xff ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, 0, 0); + if( regs->VIread & (1<vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + + int reusereg = -1; // 0 - VFwrite, 1 - VFAcc + + if( regs->VFwrite ) { + assert( !(regs->VIwrite&(1<VFwxyzw == 0xf ) { + itinst->vfwrite[i] = _checkXMMreg(XMMTYPE_VFREG, regs->VFwrite, 0); + if( itinst->vfwrite[i] < 0 ) reusereg = 0; + } + else { + itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); + } + } + else if( regs->VIwrite & (1<VFwxyzw == 0xf ) { + itinst->vfacc[i] = _checkXMMreg(XMMTYPE_ACC, 0, 0); + if( itinst->vfacc[i] < 0 ) reusereg = 1; + } + else { + itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + } + } + + if( reusereg >= 0 ) { + // reuse + itnext = itinst; itnext++; + + u8 type = reusereg ? XMMTYPE_ACC : XMMTYPE_VFREG; + u8 reg = reusereg ? 0 : regs->VFwrite; + + if( itinst->vfacc[i] >= 0 && lastwrite != itinst->vfacc[i] && + (itnext == insts.end() || ((regs->VIread&(1<usedvars[0]&(1<livevars[0]&(1<livevars[0]&(1<vfacc[i]); + xmmregs[itinst->vfacc[i]].inuse = 1; + xmmregs[itinst->vfacc[i]].reg = reg; + xmmregs[itinst->vfacc[i]].type = type; + xmmregs[itinst->vfacc[i]].mode = 0; + itinst->vfwrite[i] = itinst->vfacc[i]; + } + else if( itinst->vfread0[i] >= 0 && lastwrite != itinst->vfread0[i] && + (itnext == insts.end() || (regs->VFread0 > 0 && (!(itnext->usedvars[1]&(1<VFread0)) || !(itnext->livevars[1]&(1<VFread0))))) ) { + + if(itnext == insts.end() || (itnext->livevars[1]®s->VFread0)) _freeXMMreg(itinst->vfread0[i]); + xmmregs[itinst->vfread0[i]].inuse = 1; + xmmregs[itinst->vfread0[i]].reg = reg; + xmmregs[itinst->vfread0[i]].type = type; + xmmregs[itinst->vfread0[i]].mode = 0; + if( reusereg ) itinst->vfacc[i] = itinst->vfread0[i]; + else itinst->vfwrite[i] = itinst->vfread0[i]; + } + else if( itinst->vfread1[i] >= 0 && lastwrite != itinst->vfread1[i] && + (itnext == insts.end() || (regs->VFread1 > 0 && (!(itnext->usedvars[1]&(1<VFread1)) || !(itnext->livevars[1]&(1<VFread1))))) ) { + + if(itnext == insts.end() || (itnext->livevars[1]®s->VFread1)) _freeXMMreg(itinst->vfread1[i]); + xmmregs[itinst->vfread1[i]].inuse = 1; + xmmregs[itinst->vfread1[i]].reg = reg; + xmmregs[itinst->vfread1[i]].type = type; + xmmregs[itinst->vfread1[i]].mode = 0; + if( reusereg ) itinst->vfacc[i] = itinst->vfread1[i]; + else itinst->vfwrite[i] = itinst->vfread1[i]; + } + else { + if( reusereg ) itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + else itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); + } + } + + if( itinst->vfwrite[i] >= 0 ) lastwrite = itinst->vfwrite[i]; + else if( itinst->vfacc[i] >= 0 ) lastwrite = itinst->vfacc[i]; + + // always alloc at least 1 temp reg + int free0 = (i||regs->VFwrite||regs->VFread0||regs->VFread1||(regs->VIwrite&(1<vfwrite[1] >= 0 && (itinst->vfread0[0]==itinst->vfwrite[1]||itinst->vfread1[0]==itinst->vfwrite[1]) ) { + itinst->vfflush[i] = _allocTempXMMreg(XMMT_FPS, -1); + } + + if( i == 1 && (regs->VIwrite & (1<VIwrite & (1<vfflush[i] >= 0 ) _freeXMMreg(itinst->vfflush[i]); + if( free0 >= 0 ) _freeXMMreg(free0); + + itinst->vffree[i] = (free0&0xf)|(free1<<8)|(free2<<16); + if( free0 == -1 ) itinst->vffree[i] |= VFFREE_INVALID0; + + _clearNeededXMMregs(); + } + } + + assert( x86Ptr == oldX86 ); + u32 analyzechildren = !(type&BLOCKTYPE_ANALYZED); + type |= BLOCKTYPE_ANALYZED; + + //memset(endregs, 0, sizeof(endregs)); + + if( analyzechildren ) { + FORIT(itchild, blocks) (*itchild)->AssignVFRegs(); + } +} + +struct MARKOVBLANKET +{ + list parents; + list children; +}; + +static MARKOVBLANKET s_markov; + +void VuBaseBlock::AssignVIRegs(int parent) +{ + const int maxregs = 6; + + if( parent ) { + if( (type&BLOCKTYPE_ANALYZEDPARENT) ) + return; + + type |= BLOCKTYPE_ANALYZEDPARENT; + s_markov.parents.push_back(this); + for(LISTBLOCKS::iterator it = blocks.begin(); it != blocks.end(); ++it) { + (*it)->AssignVIRegs(0); + } + return; + } + + if( (type&BLOCKTYPE_ANALYZED) ) + return; + + // child + assert( allocX86Regs == -1 ); + allocX86Regs = s_vecRegArray.size(); + s_vecRegArray.resize(allocX86Regs+X86REGS); + + _x86regs* pregs = &s_vecRegArray[allocX86Regs]; + memset(pregs, 0, sizeof(_x86regs)*X86REGS); + + assert( parents.size() > 0 ); + + list::iterator itparent; + u32 usedvars = insts.front().usedvars[0]; + u32 livevars = insts.front().livevars[0]; + + if( parents.size() > 0 ) { + u32 usedvars2 = 0xffffffff; + FORIT(itparent, parents) usedvars2 &= (*itparent)->insts.front().usedvars[0]; + usedvars |= usedvars2; + } + + usedvars &= livevars; + + // currently order doesn't matter + int num = 0; + + if( usedvars ) { + for(int i = 1; i < 16; ++i) { + if( usedvars & (1<= maxregs ) break; + } + } + } + + if( num < maxregs) { + livevars &= ~usedvars; + livevars &= insts.back().usedvars[0]; + + if( livevars ) { + for(int i = 1; i < 16; ++i) { + if( livevars & (1<= maxregs) break; + } + } + } + } + + s_markov.children.push_back(this); + type |= BLOCKTYPE_ANALYZED; + FORIT(itparent, parents) { + (*itparent)->AssignVIRegs(1); + } +} + +u32 VuBaseBlock::GetModeXYZW(u32 curpc, int vfreg) +{ + if( vfreg <= 0 ) return false; + + list::iterator itinst = insts.begin(); + advance(itinst, (curpc-startpc)/8); + + u8 mxy = 1; + u8 mxyz = 1; + + while(itinst != insts.end()) { + for(int i = 0; i < 2; ++i ) { + if( itinst->regs[i].VFwrite == vfreg ) { + if( itinst->regs[i].VFwxyzw != 0xe ) mxyz = 0; + if( itinst->regs[i].VFwxyzw != 0xc ) mxy = 0; + } + if( itinst->regs[i].VFread0 == vfreg ) { + if( itinst->regs[i].VFr0xyzw != 0xe ) mxyz = 0; + if( itinst->regs[i].VFr0xyzw != 0xc ) mxy = 0; + } + if( itinst->regs[i].VFread1 == vfreg ) { + if( itinst->regs[i].VFr1xyzw != 0xe ) mxyz = 0; + if( itinst->regs[i].VFr1xyzw != 0xc ) mxy = 0; + } + + if( !mxy && !mxyz ) return 0; + } + ++itinst; + } + + return (mxy?MODE_VUXY:0)|(mxyz?MODE_VUXYZ:0); +} + +static void SuperVUAssignRegs() +{ + list::iterator itblock, itblock2; + + // assign xyz regs +// FORIT(itblock, s_listBlocks) { +// (*itblock)->vuxyz = 0; +// (*itblock)->vuxy = 0; +// +// for(int i = 0; i < 32; ++i) { +// u32 mode = (*itblock)->GetModeXYZW((*itblock)->startpc, i); +// if( mode & MODE_VUXYZ ) { +// if( mode & MODE_VUZ ) (*itblock)->vuxyz |= 1<vuxy |= 1<type &= ~BLOCKTYPE_ANALYZED; + s_listBlocks.front()->AssignVFRegs(); + + // VI assignments, find markov blanket for each node in the graph + // then allocate regs based on the commonly used ones +#ifdef SUPERVU_X86CACHING + FORIT(itblock, s_listBlocks) (*itblock)->type &= ~(BLOCKTYPE_ANALYZED|BLOCKTYPE_ANALYZEDPARENT); + s_vecRegArray.resize(0); + u8 usedregs[16]; + + // note: first block always has to start with no alloc regs + bool bfirst = true; + + FORIT(itblock, s_listBlocks) { + + if( !((*itblock)->type & BLOCKTYPE_ANALYZED) ) { + + if( (*itblock)->parents.size() == 0 ) { + (*itblock)->type |= BLOCKTYPE_ANALYZED; + bfirst = false; + continue; + } + + s_markov.children.clear(); + s_markov.parents.clear(); + (*itblock)->AssignVIRegs(0); + + // assign the regs + int regid = s_vecRegArray.size(); + s_vecRegArray.resize(regid+X86REGS); + + _x86regs* mergedx86 = &s_vecRegArray[regid]; + memset(mergedx86, 0, sizeof(_x86regs)*X86REGS); + + if( !bfirst ) { + *(u32*)usedregs = *((u32*)usedregs+1) = *((u32*)usedregs+2) = *((u32*)usedregs+3) = 0; + + FORIT(itblock2, s_markov.children) { + assert( (*itblock2)->allocX86Regs >= 0 ); + _x86regs* pregs = &s_vecRegArray[(*itblock2)->allocX86Regs]; + for(int i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse && pregs[i].reg < 16) { + //assert( pregs[i].reg < 16); + usedregs[pregs[i].reg]++; + } + } + } + + int num = 1; + for(int i = 0; i < 16; ++i) { + if( usedregs[i] == s_markov.children.size() ) { + // use + mergedx86[num].inuse = 1; + mergedx86[num].reg = i; + mergedx86[num].type = (s_vu?X86TYPE_VU1:0)|X86TYPE_VI; + mergedx86[num].mode = MODE_READ; + if( ++num >= X86REGS ) + break; + if( num == ESP ) + ++num; + } + } + + FORIT(itblock2, s_markov.children) { + assert( (*itblock2)->nStartx86 == -1 ); + (*itblock2)->nStartx86 = regid; + } + + FORIT(itblock2, s_markov.parents) { + assert( (*itblock2)->nEndx86 == -1 ); + (*itblock2)->nEndx86 = regid; + } + } + + bfirst = false; + } + } +#endif +} + +////////////////// +// Recompilation +////////////////// + +extern "C" { +// cycles in which the last Q,P regs were finished (written to VU->VI[]) +// the write occurs before the instruction is executed at that cycle +// compare with s_TotalVUCycles +// if less than 0, already flushed +int s_writeQ, s_writeP; + +// declare the saved registers +uptr s_vu1esp, s_callstack;//, s_vu1esp +#ifndef __x86_64__ +uptr s_vu1ebp, s_vuebx, s_vuedi, s_vu1esi; +#endif + +} + +static int s_recWriteQ, s_recWriteP; // wait times during recompilation +static int s_needFlush; // first bit - Q, second bit - P, third bit - Q has been written, fourth bit - P has been written + +static u32 s_ssecsr; +static int s_JumpX86; +static int s_ScheduleXGKICK = 0, s_XGKICKReg = -1; + +extern "C" u32 g_sseVUMXCSR, g_sseMXCSR; + +void recSVUMI_XGKICK_( VURegs *VU ); + +void SuperVUCleanupProgram(u32 startpc, int vuindex) +{ +#ifdef SUPERVU_COUNT + QueryPerformanceCounter(&svufinal); + svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); +#endif + +#ifdef _DEBUG + assert( s_vu1esp == 0 ); +#endif + + VU = vuindex ? &VU1 : &VU0; + VU->cycle += s_TotalVUCycles; + if( (int)s_writeQ > 0 ) VU->VI[REG_Q] = VU->q; + if( (int)s_writeP > 0 ) { + assert(VU == &VU1); + VU1.VI[REG_P] = VU1.p; // only VU1 + } + + //memset(recVUStack, 0, SUPERVU_STACKSIZE * 4); +} + +#if defined(_MSC_VER) && !defined(__x86_64__) + +// entry point of all vu programs from emulator calls +__declspec(naked) void SuperVUExecuteProgram(u32 startpc, int vuindex) +{ +#ifdef SUPERVU_COUNT + QueryPerformanceCounter(&svubase); +#endif + __asm { + mov eax, dword ptr [esp] + mov s_TotalVUCycles, 0 // necessary to be here! + add esp, 4 + mov s_callstack, eax + call SuperVUGetProgram + + // save cpu state + mov s_vu1ebp, ebp + mov s_vu1esi, esi // have to save even in Release + mov s_vuedi, edi // have to save even in Release + mov s_vuebx, ebx + } +#ifdef _DEBUG + __asm { + mov s_vu1esp, esp + } +#endif + + __asm { + //stmxcsr s_ssecsr + ldmxcsr g_sseVUMXCSR + + // init vars + mov s_writeQ, 0xffffffff + mov s_writeP, 0xffffffff + + jmp eax + } +} + +// exit point of all vu programs +__declspec(naked) static void SuperVUEndProgram() +{ + __asm { + // restore cpu state + ldmxcsr g_sseMXCSR + + mov ebp, s_vu1ebp + mov esi, s_vu1esi + mov edi, s_vuedi + mov ebx, s_vuebx + } + +#ifdef _DEBUG + __asm { + sub s_vu1esp, esp + } +#endif + + __asm { + call SuperVUCleanupProgram + jmp s_callstack // so returns correctly + } +} + +#endif + +// Flushes P/Q regs +void SuperVUFlush(int p, int wait) +{ + u8* pjmp[3]; + if( !(s_needFlush&(1<info.cycle < recwait ) return; + + if( recwait == 0 ) { + // write didn't happen this block + MOV32MtoR(EAX, p ? (uptr)&s_writeP : (uptr)&s_writeQ); + OR32RtoR(EAX, EAX); + pjmp[0] = JS8(0); + + if( s_pCurInst->info.cycle ) SUB32ItoR(EAX, s_pCurInst->info.cycle); + + // if writeQ <= total+offset + if( !wait ) { // only write back if time is up + CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); + pjmp[1] = JG8(0); + } + else { + // add (writeQ-total-offset) to s_TotalVUCycles + // necessary? + CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); + pjmp[2] = JLE8(0); + MOV32RtoM((uptr)&s_TotalVUCycles, EAX); + x86SetJ8(pjmp[2]); + } + } + else if( wait && s_pCurInst->info.cycle < recwait ) { + ADD32ItoM((uptr)&s_TotalVUCycles, recwait); + } + + MOV32MtoR(EAX, SuperVUGetVIAddr(p?REG_P:REG_Q, 0)); + MOV32ItoM(p ? (uptr)&s_writeP : (uptr)&s_writeQ, 0x80000000); + MOV32RtoM(SuperVUGetVIAddr(p?REG_P:REG_Q, 1), EAX); + + if( recwait == 0 ) { + if( !wait ) x86SetJ8(pjmp[1]); + x86SetJ8(pjmp[0]); + } + + if( wait || (!p && recwait == 0 && s_pCurInst->info.cycle >= 12) || (!p && recwait > 0 && s_pCurInst->info.cycle >= recwait ) ) + s_needFlush &= ~(1<::iterator itblock; + + FORIT(itblock, s_listBlocks) (*itblock)->type &= ~BLOCKTYPE_ANALYZED; + s_listBlocks.front()->Recompile(); + // make sure everything compiled + FORIT(itblock, s_listBlocks) assert( ((*itblock)->type & BLOCKTYPE_ANALYZED) && (*itblock)->pcode != NULL ); + + // link all blocks + FORIT(itblock, s_listBlocks) { + VuBaseBlock::LISTBLOCKS::iterator itchild; + + assert( (*itblock)->blocks.size() <= ARRAYSIZE((*itblock)->pChildJumps) ); + + int i = 0; + FORIT(itchild, (*itblock)->blocks) { + + if( (u32)(uptr)(*itblock)->pChildJumps[i] == 0xffffffff ) + continue; + + if( (*itblock)->pChildJumps[i] == NULL ) { + VuBaseBlock* pchild = *itchild; + + if( pchild->type & BLOCKTYPE_HASEOP) { + assert( pchild->blocks.size() == 0); + + AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag + AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); + + MOV32ItoM((uptr)&VU->VI[REG_TPC], pchild->endpc); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + } + // only other case is when there are two branches + else assert( (*itblock)->insts.back().regs[0].pipe == VUPIPE_BRANCH ); + + continue; + } + + if( (u32)(uptr)(*itblock)->pChildJumps[i] & 0x80000000 ) { + // relative + assert( (uptr)(*itblock)->pChildJumps[i] <= 0xffffffff); + (*itblock)->pChildJumps[i] = (u32*)((uptr)(*itblock)->pChildJumps[i] & 0x7fffffff); + *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode - ((uptr)(*itblock)->pChildJumps[i] + 4); + } + else *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode; + + ++i; + } + } + + s_pFnHeader->pprogfunc = s_listBlocks.front()->pcode; +} + +// debug +static u32 s_svulast = 0, s_vufnheader; +extern "C" u32 s_vucount; +u32 g_vu1lastrec = 0, skipparent = -1; +static u32 badaddrs[][2] = {0,0xffff}; +extern "C" { + +#ifndef __x86_64__ +u32 s_saveecx, s_saveedx, s_saveebx, s_saveesi, s_saveedi, s_saveebp; +#endif + +u32 g_curdebugvu; +} + +//extern "C" float vuDouble(u32 f); + +#if defined(_MSC_VER) && !defined(__x86_64__) +__declspec(naked) static void svudispfn() +{ + static u32 i; + + __asm { + mov g_curdebugvu, eax + mov s_saveecx, ecx + mov s_saveedx, edx + mov s_saveebx, ebx + mov s_saveesi, esi + mov s_saveedi, edi + mov s_saveebp, ebp + } +#else + +extern "C" void svudispfn(); + +extern "C" void svudispfntemp() +{ + static u32 i; +#endif + +// VU1.VF[7].F[0] = vuDouble(VU1.VF[7].UL[0]); +// VU1.VF[7].F[1] = vuDouble(VU1.VF[7].UL[1]); +// VU1.VF[7].F[2] = vuDouble(VU1.VF[7].UL[2]); +// VU1.VF[7].F[3] = vuDouble(VU1.VF[7].UL[3]); + +#ifdef _DEBUG + if( ((vudump&8) && g_curdebugvu) || ((vudump&0x80) && !g_curdebugvu) ) { //&& g_vu1lastrec != g_vu1last ) { + + if( skipparent != g_vu1lastrec ) { + for(i = 0; i < ARRAYSIZE(badaddrs); ++i) { + if( s_svulast == badaddrs[i][1] && g_vu1lastrec == badaddrs[i][0] ) + break; + } + + if( i == ARRAYSIZE(badaddrs) ) + { + //static int curesp; + //__asm mov curesp, esp + __Log("tVU: %x %x %x\n", s_svulast, s_vucount, s_vufnheader); + if( g_curdebugvu ) iDumpVU1Registers(); + else iDumpVU0Registers(); + s_vucount++; + } + } + + g_vu1lastrec = s_svulast; + } +#endif + +#if defined(_MSC_VER) && !defined(__x86_64__) + __asm { + mov ecx, s_saveecx + mov edx, s_saveedx + mov ebx, s_saveebx + mov esi, s_saveesi + mov edi, s_saveedi + mov ebp, s_saveebp + ret + } +#endif +} + +// frees an xmmreg depending on the liveness info of hte current inst +//void SuperVUFreeXMMreg(int xmmreg, int xmmtype, int reg) +//{ +// if( !xmmregs[xmmreg].inuse ) return; +// if( xmmregs[xmmreg].type == xmmtype && xmmregs[xmmreg].reg == reg ) return; +// +// if( s_pNextInst == NULL ) { +// // last inst, free +// _freeXMMreg(xmmreg); +// return; +// } +// +// if( xmmregs[xmmreg].type == XMMTYPE_VFREG ) { +// if( (s_pCurInst->livevars[1]|s_pNextInst->livevars[1]) & (1<livevars[0]|s_pNextInst->livevars[0]) & (1<VF[xmmregs[i].reg] : (uptr)&VU->ACC; + + if( xmmregs[i].mode & MODE_VUZ ) { + SSE_MOVHPS_XMM_to_M64(addr, (x86SSERegType)i); + SSE_SHUFPS_M128_to_XMM((x86SSERegType)i, addr, 0xc4); + } + else SSE_MOVHPS_M64_to_XMM((x86SSERegType)i, addr+8); + + xmmregs[i].mode &= ~MODE_VUXYZ; + } + + _freeXMMreg(i); + } + } + } + + //_freeXMMregs(); +} + +//void timeout() { SysPrintf("VU0 timeout\n"); } +void SuperVUTestVU0Condition(u32 incstack) +{ + if( s_vu && !SUPERVU_CHECKCONDITION ) return; // vu0 only + + CMP32ItoM((uptr)&s_TotalVUCycles, 512); // sometimes games spin on vu0, so be careful with this value + // woody hangs if too high + +#ifndef __x86_64__ + // x86-64 doesn't use a stack + if( incstack ) { + u8* ptr = JB8(0); + + if( incstack ) ADD32ItoR(ESP, incstack); + //CALLFunc((u32)timeout); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + + x86SetJ8(ptr); + } + else +#endif + { + JAE32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 6 ) ); + } +} + +void VuBaseBlock::Recompile() +{ + if( type & BLOCKTYPE_ANALYZED ) return; + + x86Align(16); + pcode = x86Ptr; + +#ifdef _DEBUG + MOV32ItoM((uptr)&s_vufnheader, s_pFnHeader->startpc); + MOV32ItoM((uptr)&VU->VI[REG_TPC], startpc); + MOV32ItoM((uptr)&s_svulast, startpc); + list::iterator itparent; + for(itparent = parents.begin(); itparent != parents.end(); ++itparent) { + if( (*itparent)->blocks.size()==1 && (*itparent)->blocks.front()->startpc == startpc && + ((*itparent)->insts.size() < 2 || (----(*itparent)->insts.end())->regs[0].pipe != VUPIPE_BRANCH) ) { + MOV32ItoM((uptr)&skipparent, (*itparent)->startpc); + break; + } + } + + if( itparent == parents.end() ) MOV32ItoM((uptr)&skipparent, -1); + + MOV32ItoR(EAX, s_vu); + CALLFunc((uptr)svudispfn); +#endif + + s_pCurBlock = this; + s_needFlush = 3; + pc = startpc; + branch = 0; + s_recWriteQ = s_recWriteP = 0; + s_XGKICKReg = -1; + s_ScheduleXGKICK = 0; + + s_ClipRead = s_PrevClipWrite = (uptr)&VU->VI[REG_CLIP_FLAG]; + s_StatusRead = s_PrevStatusWrite = (uptr)&VU->VI[REG_STATUS_FLAG]; + s_MACRead = s_PrevMACWrite = (uptr)&VU->VI[REG_MAC_FLAG]; + s_PrevIWrite = (uptr)&VU->VI[REG_I]; + s_JumpX86 = 0; + s_UnconditionalDelay = 0; + + memcpy(xmmregs, startregs, sizeof(xmmregs)); +#ifdef SUPERVU_X86CACHING + if( nStartx86 >= 0 ) + memcpy(x86regs, &s_vecRegArray[nStartx86], sizeof(x86regs)); + else _initX86regs(); +#else + _initX86regs(); +#endif + + list::iterator itinst; + FORIT(itinst, insts) { + s_pCurInst = &(*itinst); + if( s_JumpX86 > 0 ) { + if( !x86regs[s_JumpX86].inuse ) { + // load + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_READ); + } + x86regs[s_JumpX86].needed = 1; + } +#ifdef __x86_64__ + // check X86ARG1 + if( x86regs[X86ARG1].inuse && x86regs[X86ARG1].type == X86TYPE_FNARG ) { + x86regs[X86ARG1].needed = 1; + } +#endif + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) { + assert( x86regs[s_XGKICKReg].inuse ); + x86regs[s_XGKICKReg].needed = 1; + } + itinst->Recompile(itinst, vuxyz); + + if( s_ScheduleXGKICK > 0 ) { + if( s_ScheduleXGKICK-- == 1 ) { + recSVUMI_XGKICK_(VU); + } + } + } + assert( pc == endpc ); + assert( s_ScheduleXGKICK == 0 ); + + // flush flags + if( s_PrevClipWrite != (uptr)&VU->VI[REG_CLIP_FLAG] ) { + MOV32MtoR(EAX, s_PrevClipWrite); + MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); + } + if( s_PrevStatusWrite != (uptr)&VU->VI[REG_STATUS_FLAG] ) { + // only lower 8 bits valid! + MOVZX32M8toR(EAX, s_PrevStatusWrite); + MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); + } + if( s_PrevMACWrite != (uptr)&VU->VI[REG_MAC_FLAG] ) { + // only lower 8 bits valid! + MOVZX32M8toR(EAX, s_PrevMACWrite); + MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); + } +// if( s_StatusRead != (uptr)&VU->VI[REG_STATUS_FLAG] ) { +// // only lower 8 bits valid! +// MOVZX32M8toR(EAX, s_StatusRead); +// MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); +// } +// if( s_MACRead != (uptr)&VU->VI[REG_MAC_FLAG] ) { +// // only lower 8 bits valid! +// MOVZX32M8toR(EAX, s_MACRead); +// MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); +// } + if( s_PrevIWrite != (uptr)&VU->VI[REG_I] ) { + MOV32ItoM((uptr)&VU->VI[REG_I], *(u32*)s_PrevIWrite); // never changes + } + + ADD32ItoM((uptr)&s_TotalVUCycles, cycles); + + // compute branches, jumps, eop + if( type & BLOCKTYPE_HASEOP ) { + // end + _freeXMMregs(); + _freeX86regs(); + AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag + AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); + if( !branch ) MOV32ItoM((uptr)&VU->VI[REG_TPC], endpc); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + } + else { + + u32 livevars[2] = {0}; + + list::iterator lastinst = GetInstIterAtPc(endpc-8); + lastinst++; + + if( lastinst != insts.end() ) { + livevars[0] = lastinst->livevars[0]; + livevars[1] = lastinst->livevars[1]; + } + else { + // take from children + if( blocks.size() > 0 ) { + LISTBLOCKS::iterator itchild; + FORIT(itchild, blocks) { + livevars[0] |= (*itchild)->insts.front().livevars[0]; + livevars[1] |= (*itchild)->insts.front().livevars[1]; + } + } + else { + livevars[0] = ~0; + livevars[1] = ~0; + } + } + + SuperVUFreeXMMregs(livevars); + + // get rid of any writes, otherwise _freeX86regs will write + x86regs[s_JumpX86].mode &= ~MODE_WRITE; + +#ifdef __x86_64__ + bool bValidX86Arg = false; // if false, then use _x86GetAddr(X86TYPE_FNARG, reg); + if( x86regs[X86ARG1].inuse ) { + bValidX86Arg = true; + if( x86regs[X86ARG1].type==X86TYPE_FNARG ) + x86regs[X86ARG1].mode &= ~MODE_WRITE; + } +#endif + + if( branch == 1 ) { + if( !x86regs[s_JumpX86].inuse ) { + assert( x86regs[s_JumpX86].type == X86TYPE_VUJUMP ); + s_JumpX86 = 0xffffffff; // notify to jump from g_recWriteback + } + } + + // align VI regs +#ifdef SUPERVU_X86CACHING + if( nEndx86 >= 0 ) { + _x86regs* endx86 = &s_vecRegArray[nEndx86]; + for(int i = 0; i < X86REGS; ++i) { + if( endx86[i].inuse ) { + + if( s_JumpX86 == i && x86regs[s_JumpX86].inuse ) { + x86regs[s_JumpX86].inuse = 0; + x86regs[EAX].inuse = 1; + MOV32RtoR(EAX, s_JumpX86); + s_JumpX86 = EAX; + } + + if( x86regs[i].inuse ) { + if( x86regs[i].type == endx86[i].type && x86regs[i].reg == endx86[i].reg ) { + _freeX86reg(i); + // will continue to use it + continue; + } + + if( x86regs[i].type == (X86TYPE_VI|(s_vu?X86TYPE_VU1:0)) ) { +#ifdef SUPERVU_INTERCACHING + if( livevars[0] & (1<startpc); + + switch(branch) { + case 1: // branch, esi has new prog + + SuperVUTestVU0Condition(0); + + if( s_JumpX86 == 0xffffffff ) + JMP32M((uptr)&g_recWriteback); + else + JMPR(s_JumpX86); + + break; + case 4: // jalr + pChildJumps[0] = (u32*)0xffffffff; + // fall through + + case 0x10: // jump, esi has new vupc + { + _freeXMMregs(); + _freeX86regs(); + + SuperVUTestVU0Condition(8); + +#ifdef __x86_64__ + // check that X86ARG1 is still valid + if( !bValidX86Arg ) + MOV32MtoR(X86ARG1, _x86GetAddr(X86TYPE_FNARG, 0)); + MOV32ItoR(X86ARG2, s_vu); +#endif + // already onto stack + CALLFunc((uptr)SuperVUGetProgram); +#ifndef __x86_64__ + ADD32ItoR(ESP, 8); +#endif + JMPR(EAX); + + break; + } + + case 0x13: // jr with uncon branch, uncond branch takes precendence (dropship) + { +// s32 delta = (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) << 3; +// ADD32ItoRmOffset(ESP, delta, 0); +#ifndef __x86_64__ + ADD32ItoR(ESP, 8); // restore +#endif + pChildJumps[0] = (u32*)((uptr)JMP32(0)|0x80000000); + + break; + } + case 0: + case 3: // unconditional branch + pChildJumps[s_UnconditionalDelay] = (u32*)((uptr)JMP32(0)|0x80000000); + break; + + default: +#ifdef PCSX2_DEVBUILD + SysPrintf("Bad branch %x\n", branch); +#endif + assert(0); + break; + } + } + + pendcode = x86Ptr; + type |= BLOCKTYPE_ANALYZED; + + LISTBLOCKS::iterator itchild; + FORIT(itchild, blocks) { + (*itchild)->Recompile(); + } +} + +#define GET_VUXYZMODE(reg) 0//((vuxyz&(1<<(reg)))?MODE_VUXYZ:0) + +int VuInstruction::SetCachedRegs(int upper, u32 vuxyz) +{ + if( vfread0[upper] >= 0 ) { + SuperVUFreeXMMreg(vfread0[upper], XMMTYPE_VFREG, regs[upper].VFread0); + _allocVFtoXMMreg(VU, vfread0[upper], regs[upper].VFread0, MODE_READ|GET_VUXYZMODE(regs[upper].VFread0)); + } + if( vfread1[upper] >= 0 ) { + SuperVUFreeXMMreg(vfread1[upper], XMMTYPE_VFREG, regs[upper].VFread1); + _allocVFtoXMMreg(VU, vfread1[upper], regs[upper].VFread1, MODE_READ|GET_VUXYZMODE(regs[upper].VFread1)); + } + if( vfacc[upper] >= 0 && (regs[upper].VIread&(1<= 0 ) { + assert( regs[upper].VFwrite > 0); + SuperVUFreeXMMreg(vfwrite[upper], XMMTYPE_VFREG, regs[upper].VFwrite); + _allocVFtoXMMreg(VU, vfwrite[upper], regs[upper].VFwrite, + MODE_WRITE|(regs[upper].VFwxyzw != 0xf?MODE_READ:0)|GET_VUXYZMODE(regs[upper].VFwrite)); + } + if( vfacc[upper] >= 0 && (regs[upper].VIwrite&(1<= 0 ) info |= PROCESS_EE_SET_S(vfread0[upper]); + if( vfread1[upper] >= 0 ) info |= PROCESS_EE_SET_T(vfread1[upper]); + if( vfacc[upper] >= 0 ) info |= PROCESS_VU_SET_ACC(vfacc[upper]); + if( vfwrite[upper] >= 0 ) { + if( regs[upper].VFwrite == _Ft_ && vfread1[upper] < 0 ) { + info |= PROCESS_EE_SET_T(vfwrite[upper]); + } + else { + assert( regs[upper].VFwrite == _Fd_ ); + info |= PROCESS_EE_SET_D(vfwrite[upper]); + } + } + + if( !(vffree[upper]&VFFREE_INVALID0) ) { + SuperVUFreeXMMreg(vffree[upper]&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, vffree[upper]&0xf); + } + info |= PROCESS_VU_SET_TEMP(vffree[upper]&0xf); + + if( vfflush[upper] >= 0 ) { + SuperVUFreeXMMreg(vfflush[upper], XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, vfflush[upper]); + } + + if( upper && (regs[upper].VIwrite & (1 << REG_CLIP_FLAG)) ) { + // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC + assert( vfwrite[upper] == -1 ); + SuperVUFreeXMMreg((vffree[upper]>>8)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); + info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); + + SuperVUFreeXMMreg((vffree[upper]>>16)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>16)&0xf); + info |= PROCESS_EE_SET_ACC((vffree[upper]>>16)&0xf); + + _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore + _freeXMMreg((vffree[upper]>>16)&0xf); // don't need anymore + } + else if( regs[upper].VIwrite & (1<>8)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); + info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); + _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore + } + + if( vfflush[upper] >= 0 ) _freeXMMreg(vfflush[upper]); + if( !(vffree[upper]&VFFREE_INVALID0) ) + _freeXMMreg(vffree[upper]&0xf); // don't need anymore + + if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<::iterator& itinst, u32 vuxyz) +{ + static PCSX2_ALIGNED16(VECTOR _VF); + static PCSX2_ALIGNED16(VECTOR _VFc); + u32 *ptr; + u8* pjmp; + int vfregstore=0, viregstore=0; + + assert( s_pCurInst == this); + s_WriteToReadQ = 0; + + ptr = (u32*)&VU->Micro[ pc ]; + + if( type & INST_Q_READ ) + SuperVUFlush(0, (ptr[0] == 0x800003bf)||!!(regs[0].VIwrite & (1<startpc || nParentPc >= (int)pc) ) { + +// if( !s_vu ) { +// for(int j = 0; j < ARRAYSIZE(badaddrs); ++j) { +// if( badaddrs[j] == nParentPc ) +// goto NoParent; +// } +// } + + list::iterator itblock; + FORIT(itblock, s_listBlocks) { + if( nParentPc >= (*itblock)->startpc && nParentPc < (*itblock)->endpc ) { + pparentinst = &(*(*itblock)->GetInstIterAtPc(nParentPc)); + //if( !s_vu ) SysPrintf("%x ", nParentPc); + if( find(s_pCurBlock->parents.begin(), s_pCurBlock->parents.end(), *itblock) != s_pCurBlock->parents.end() ) + nParentCheckForExecution = (*itblock)->startpc; + break; + } + } + + assert( pparentinst != NULL ); + } +#endif + + if( type & INST_CLIP_WRITE ) { + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) + // reading from out of this block, so already flushed to mem + s_ClipRead = (uptr)&VU->VI[REG_CLIP_FLAG]; + else { + s_ClipRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pClipWrite; + } + } + + // before modifying, check if they will ever be read + if( s_pCurBlock->type & BLOCKTYPE_MACFLAGS ) { + + u8 outofblock=0; + if( type & INST_STATUS_WRITE ) { + + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { + + // reading from out of this block, so already flushed to mem + if( pparentinst != NULL ) { //&& pparentinst->pStatusWrite != NULL ) { + + // might not have processed it yet, so reserve a mem loc + if( pparentinst->pStatusWrite == NULL ) { + pparentinst->pStatusWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pparentinst->pStatusWrite, 0); + } + +// if( s_pCurBlock->prevFlagsOutOfBlock && s_StatusRead != NULL ) { +// // or instead since don't now which parent we came from +// MOV32MtoR(EAX, pparentinst->pStatusWrite); +// OR32RtoM(s_StatusRead, EAX); +// MOV32ItoM(pparentinst->pStatusWrite, 0); +// } + + if( nParentCheckForExecution >= 0 ) { + + // don't now which parent we came from, so have to check +// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); +// if( s_StatusRead != NULL ) +// MOV32MtoR(EAX, s_StatusRead); +// else +// MOV32MtoR(EAX, (uptr)&VU->VI[REG_STATUS_FLAG]); +// s_StatusRead = tempstatus; + if( s_StatusRead == NULL ) + s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; + + CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); + u8* jptr = JNE8(0); + MOV32MtoR(EAX, pparentinst->pStatusWrite); + MOV32ItoM(pparentinst->pStatusWrite, 0); + MOV32RtoM(s_StatusRead, EAX); + x86SetJ8(jptr); + } + else { + uptr tempstatus = (uptr)SuperVUStaticAlloc(4); + MOV32MtoR(EAX, pparentinst->pStatusWrite); + MOV32RtoM(tempstatus, EAX); + MOV32ItoM(pparentinst->pStatusWrite, 0); + s_StatusRead = tempstatus; + } + + outofblock = 2; + } + else + s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; + } + else { + s_StatusRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pStatusWrite; +// if( pc >= (u32)s_pCurBlock->endpc-8 ) { +// // towards the end, so variable might be leaded to another block (silent hill 4) +// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); +// MOV32MtoR(EAX, s_StatusRead); +// MOV32RtoM(tempstatus, EAX); +// MOV32ItoM(s_StatusRead, 0); +// s_StatusRead = tempstatus; +// } + } + } + if( type & INST_MAC_WRITE ) { + + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { + // reading from out of this block, so already flushed to mem + + if( pparentinst != NULL ) {//&& pparentinst->pMACWrite != NULL ) { + // necessary for (katamari) + // towards the end, so variable might be leaked to another block (silent hill 4) + + // might not have processed it yet, so reserve a mem loc + if( pparentinst->pMACWrite == NULL ) { + pparentinst->pMACWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pparentinst->pMACWrite, 0); + } + +// if( s_pCurBlock->prevFlagsOutOfBlock && s_MACRead != NULL ) { +// // or instead since don't now which parent we came from +// MOV32MtoR(EAX, pparentinst->pMACWrite); +// OR32RtoM(s_MACRead, EAX); +// MOV32ItoM(pparentinst->pMACWrite, 0); +// } + if( nParentCheckForExecution >= 0 ) { + + // don't now which parent we came from, so have to check +// uptr tempmac = (uptr)SuperVUStaticAlloc(4); +// if( s_MACRead != NULL ) +// MOV32MtoR(EAX, s_MACRead); +// else +// MOV32MtoR(EAX, (uptr)&VU->VI[REG_MAC_FLAG]); +// s_MACRead = tempmac; + + if( s_MACRead == NULL ) + s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; + + CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); + u8* jptr = JNE8(0); + MOV32MtoR(EAX, pparentinst->pMACWrite); + MOV32ItoM(pparentinst->pMACWrite, 0); + MOV32RtoM(s_MACRead, EAX); + x86SetJ8(jptr); + } + else { + uptr tempMAC = (uptr)SuperVUStaticAlloc(4); + MOV32MtoR(EAX, pparentinst->pMACWrite); + MOV32RtoM(tempMAC, EAX); + MOV32ItoM(pparentinst->pMACWrite, 0); + s_MACRead = tempMAC; + } + + outofblock = 2; + } + else + s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; + +// if( pc >= (u32)s_pCurBlock->endpc-8 ) { +// // towards the end, so variable might be leaked to another block (silent hill 4) +// uptr tempMAC = (uptr)SuperVUStaticAlloc(4); +// MOV32MtoR(EAX, s_MACRead); +// MOV32RtoM(tempMAC, EAX); +// MOV32ItoM(s_MACRead, 0); +// s_MACRead = tempMAC; +// } + } + else { + s_MACRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pMACWrite; + } + } + + s_pCurBlock->prevFlagsOutOfBlock = outofblock; + } + else if( pparentinst != NULL) { + // make sure to reset the mac and status flags! (katamari) + if( pparentinst->pStatusWrite != NULL ) + MOV32ItoM(pparentinst->pStatusWrite, 0); + if( pparentinst->pMACWrite != NULL ) + MOV32ItoM(pparentinst->pMACWrite, 0); + } + + assert( s_ClipRead != 0 ); + assert( s_MACRead != 0 ); + assert( s_StatusRead != 0 ); + + return; + } + + s_pCurBlock->prevFlagsOutOfBlock = 0; + +#ifdef _DEBUG +// CMP32ItoM((u32)ptr, ptr[0]); +// j8Ptr[0] = JNE8(0); +// CMP32ItoM((u32)(ptr+1), ptr[1]); +// j8Ptr[1] = JNE8(0); +// j8Ptr[2] = JMP8(0); +// x86SetJ8( j8Ptr[0] ); +// x86SetJ8( j8Ptr[1] ); +// _callFunctionArg3((uptr)checkvucodefn, MEM_CONSTTAG, MEM_CONSTTAG, MEM_CONSTTAG, pc, s_vu, ptr[0]); +// x86SetJ8( j8Ptr[ 2 ] ); + + MOV32ItoR(EAX, pc); +#endif + + assert( !(type & (INST_CLIP_WRITE|INST_STATUS_WRITE|INST_MAC_WRITE)) ); + pc += 8; + + list::const_iterator itinst2; + + if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<type & BLOCKTYPE_MACFLAGS ) { + if( pMACWrite == 0 ) { + pMACWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pMACWrite, 0); + } + if( pStatusWrite == 0 ) { + pStatusWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pStatusWrite, 0); + } + } + else { + assert( s_StatusRead == (uptr)&VU->VI[REG_STATUS_FLAG] ); + assert( s_MACRead == (uptr)&VU->VI[REG_MAC_FLAG] ); + pMACWrite = s_MACRead; + pStatusWrite = s_StatusRead; + } + } + + if( pClipWrite == 0 && ((regs[0].VIwrite|regs[1].VIwrite) & (1<insts.end() ) { + if( (itinst2->regs[0].VIread|itinst2->regs[0].VIwrite|itinst2->regs[1].VIread|itinst2->regs[1].VIwrite) && (1<flags, VUFLAG_MFLAGSET); + } + if (ptr[1] & 0x10000000) { // D flag + TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x400:0x004); + u8* ptr = JZ8(0); + OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x200:0x002); + _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); + x86SetJ8(ptr); + } + if (ptr[1] & 0x08000000) { // T flag + TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x800:0x008); + u8* ptr = JZ8(0); + OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x400:0x004); + _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); + x86SetJ8(ptr); + } + + // check upper flags + if (ptr[1] & 0x80000000) { // I flag + + assert( !(regs[0].VIwrite & ((1<code = ptr[1]; + s_vuInfo = SetCachedRegs(1, vuxyz); + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + + recSVU_UPPER_OPCODE[ VU->code & 0x3f ](); + + s_PrevIWrite = (uptr)ptr; + _clearNeededXMMregs(); + _clearNeededX86regs(); + } + else { + if( regs[0].VIwrite & (1<insts.end()); + u32* codeptr2 = ptr+2; + + while(itinst2 != s_pCurBlock->insts.end() ) { + if( !(itinst2->type & INST_DUMMY) && ((itinst2->regs[0].VIwrite&(1<type & INST_Q_WRITE) && itinst2->nParentPc == pc-8 ) { + break; + } + if( itinst2->type & INST_Q_READ ) { + cacheq = 1; + break; + } + if( itinst2->type & INST_DUMMY ) { + ++itinst2; + continue; + } + codeptr2 += 2; + ++itinst2; + } + + if( itinst2 == s_pCurBlock->insts.end() ) + cacheq = 1; + + int x86temp = -1; + if( cacheq ) + x86temp = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + + // new is written so flush old + // if type & INST_Q_READ, already flushed + if( !(type & INST_Q_READ) && s_recWriteQ == 0 ) MOV32MtoR(EAX, (uptr)&s_writeQ); + + if( cacheq ) + MOV32MtoR(x86temp, (uptr)&s_TotalVUCycles); + + if( !(type & INST_Q_READ) ) { + if( s_recWriteQ == 0 ) { + OR32RtoR(EAX, EAX); + pjmp = JS8(0); + MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); + MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); + x86SetJ8(pjmp); + } + else if( s_needFlush & 1 ) { + MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); + MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); + s_needFlush &= ~1; + } + } + + // write new Q + if( cacheq ) { + assert(s_pCurInst->pqcycles>1); + ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); + MOV32RtoM((uptr)&s_writeQ, x86temp); + s_needFlush |= 1; + } + else { + // won't be writing back + s_WriteToReadQ = 1; + s_needFlush &= ~1; + MOV32ItoM((uptr)&s_writeQ, 0x80000001); + } + + s_recWriteQ = s_pCurInst->info.cycle+s_pCurInst->pqcycles; + + if( x86temp >= 0 ) + _freeX86reg(x86temp); + } + + if( regs[0].VIwrite & (1<pqcycles>1); + ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); + MOV32RtoM((uptr)&s_writeP, x86temp); + s_needFlush |= 2; + + s_recWriteP = s_pCurInst->info.cycle+s_pCurInst->pqcycles; + + _freeX86reg(x86temp); + } + + if( ptr[0] == 0x800003bf ) // waitq + SuperVUFlush(0, 1); + + if( ptr[0] == 0x800007bf ) // waitp + SuperVUFlush(1, 1); + +#ifdef PCSX2_DEVBUILD + if ( regs[1].VIread & regs[0].VIwrite & ~((1<startpc); + } +#endif + + u32 modewrite = 0; + if( vfwrite[1] >= 0 && xmmregs[vfwrite[1]].inuse && xmmregs[vfwrite[1]].type == XMMTYPE_VFREG && xmmregs[vfwrite[1]].reg == regs[1].VFwrite ) + modewrite = xmmregs[vfwrite[1]].mode & MODE_WRITE; + + VU->code = ptr[1]; + s_vuInfo = SetCachedRegs(1, vuxyz); + + if (vfwrite[1] >= 0) { + assert( regs[1].VFwrite > 0 ); + + if (vfwrite[0] == vfwrite[1]) { + //SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle %x\n", s_pCurBlock->startpc); + } + + if (vfread0[0] == vfwrite[1] || vfread1[0] == vfwrite[1] ) { + assert( regs[0].VFread0 == regs[1].VFwrite || regs[0].VFread1 == regs[1].VFwrite ); + assert( vfflush[0] >= 0 ); + if( modewrite ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[regs[1].VFwrite], (x86SSERegType)vfwrite[1]); + } + vfregstore = 1; + } + } + + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + + recSVU_UPPER_OPCODE[ VU->code & 0x3f ](); + _clearNeededXMMregs(); + _clearNeededX86regs(); + + // necessary because status can be set by both upper and lower + if( regs[1].VIwrite & (1<code = ptr[0]; + s_vuInfo = SetCachedRegs(0, vuxyz); + + if( vfregstore ) { + // load + SSE_MOVAPS_M128_to_XMM(vfflush[0], (uptr)&VU->VF[regs[1].VFwrite]); + + assert( xmmregs[vfwrite[1]].mode & MODE_WRITE ); + + // replace with vfflush + if( _Fs_ == regs[1].VFwrite ) { + s_vuInfo &= ~PROCESS_EE_SET_S(0xf); + s_vuInfo |= PROCESS_EE_SET_S(vfflush[0]); + } + if( _Ft_ == regs[1].VFwrite ) { + s_vuInfo &= ~PROCESS_EE_SET_T(0xf); + s_vuInfo |= PROCESS_EE_SET_T(vfflush[0]); + } + + xmmregs[vfflush[0]].mode |= MODE_NOFLUSH|MODE_WRITE; // so that lower inst doesn't flush + } + + // notify vuinsts that upper inst is a fmac + if( regs[1].pipe == VUPIPE_FMAC ) + s_vuInfo |= PROCESS_VU_SET_FMAC(); + + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + +#ifdef SUPERVU_VIBRANCHDELAY + if( type & INST_CACHE_VI ) { + assert( vicached >= 0 ); + int cachedreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), vicached, MODE_READ); + MOV32RtoM((uptr)&s_VIBranchDelay, cachedreg); + } +#endif + + // check if inst before branch and the write is the same as the read in the branch (wipeout) + int oldreg=0; +// if( pc == s_pCurBlock->endpc-16 ) { +// itinst2 = itinst; ++itinst2; +// if( itinst2->regs[0].pipe == VUPIPE_BRANCH && (itinst->regs[0].VIwrite&itinst2->regs[0].VIread) ) { +// +// CALLFunc((u32)branchfn); +// assert( itinst->regs[0].VIwrite & 0xffff ); +// SysPrintf("vi write before branch\n"); +// for(s_CacheVIReg = 0; s_CacheVIReg < 16; ++s_CacheVIReg) { +// if( itinst->regs[0].VIwrite & (1<endpc-8 && s_CacheVIReg >= 0 ) { +// assert( s_CacheVIX86 > 0 && x86regs[s_CacheVIX86].inuse && x86regs[s_CacheVIX86].reg == s_CacheVIReg && x86regs[s_CacheVIX86].type == X86TYPE_VITEMP ); +// +// oldreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), s_CacheVIReg, MODE_READ); +// x86regs[s_CacheVIX86].needed = 1; +// assert( x86regs[oldreg].mode & MODE_WRITE ); +// +// x86regs[s_CacheVIX86].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); +// x86regs[oldreg].type = X86TYPE_VITEMP; +// } + + recSVU_LOWER_OPCODE[ VU->code >> 25 ](); + +// if( pc == s_pCurBlock->endpc-8 && s_CacheVIReg >= 0 ) { +// // revert +// x86regs[s_CacheVIX86].inuse = 0; +// x86regs[oldreg].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); +// } + + _clearNeededXMMregs(); + _clearNeededX86regs(); + } + + // clip is always written so ok + if( (regs[0].VIwrite|regs[1].VIwrite) & (1<code); + int curjump = 0; + + if( s_pCurInst->type & INST_BRANCH_DELAY ) { + assert( (branch&0x17)!=0x10 && (branch&0x17)!=4 ); // no jump handlig for now + + if( (branch & 0x7) == 3 ) { + // previous was a direct jump + curjump = 1; + } + else if( branch & 1 ) curjump = 2; + } + + assert( s_JumpX86 > 0 ); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[curjump] = (u32*)x86Ptr-1; + + if( !(s_pCurInst->type & INST_BRANCH_DELAY) ) { + j8Ptr[1] = JMP8(0); + x86SetJ8( j8Ptr[ 0 ] ); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), pc+8); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[curjump+1] = (u32*)x86Ptr-1; + + x86SetJ8( j8Ptr[ 1 ] ); + } + else + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +// supervu specific insts +void recSVUMI_IBQ_prep() +{ + int fsreg, ftreg; + + if( _Fs_ == 0 ) { +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { + ftreg = -1; + } + else +#endif + { + ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( ftreg >= 0 ) { + CMP16ItoR( ftreg, 0 ); + } + else CMP16ItoM(SuperVUGetVIAddr(_Ft_, 1), 0); + } + else if( _Ft_ == 0 ) { +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = -1; + } + else +#endif + { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR( fsreg, 0 ); + } + else CMP16ItoM(SuperVUGetVIAddr(_Fs_, 1), 0); + + } + else { + _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_); + +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = -1; + } + else +#endif + { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { + ftreg = -1; + + if( fsreg <= 0 ) { + // allocate fsreg + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = _allocX86reg(-1, X86TYPE_TEMP, 0, MODE_READ|MODE_WRITE); + MOV32MtoR(fsreg, SuperVUGetVIAddr(_Fs_, 1)); + } + else + fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + } + else +#endif + { + ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + if( ftreg >= 0 ) { + CMP16RtoR( fsreg, ftreg ); + } + else CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); + } + else if( ftreg >= 0 ) { + CMP16MtoR(ftreg, SuperVUGetVIAddr(_Fs_, 1)); + } + else { + fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); + } + } +} + +void recSVUMI_IBEQ() +{ + recSVUMI_IBQ_prep(); + j8Ptr[ 0 ] = JNE8( 0 ); + recSVUMI_BranchHandle(); +} + +void recSVUMI_IBGEZ() +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + OR16RtoR(fsreg, fsreg); + j8Ptr[ 0 ] = JS8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JL8( 0 ); + } + + recSVUMI_BranchHandle(); +} + +void recSVUMI_IBGTZ() +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR(fsreg, 0); + j8Ptr[ 0 ] = JLE8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JLE8( 0 ); + } + recSVUMI_BranchHandle(); +} + +void recSVUMI_IBLEZ() +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR(fsreg, 0); + j8Ptr[ 0 ] = JG8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JG8( 0 ); + } + recSVUMI_BranchHandle(); +} + +void recSVUMI_IBLTZ() +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + OR16RtoR(fsreg, fsreg); + j8Ptr[ 0 ] = JNS8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JGE8( 0 ); + } + recSVUMI_BranchHandle(); +} + +void recSVUMI_IBNE() +{ + recSVUMI_IBQ_prep(); + j8Ptr[ 0 ] = JE8( 0 ); + recSVUMI_BranchHandle(); +} + +void recSVUMI_B() +{ + // supervu will take care of the rest + int bpc = _recbranchAddr(VU->code); + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + + // loops to self, so check condition + if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { + SuperVUTestVU0Condition(0); + } + + if( s_pCurBlock->blocks.size() > 1 ) { + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; + s_UnconditionalDelay = 1; + } + + branch |= 3; +} + +void recSVUMI_BAL() +{ + int bpc = _recbranchAddr(VU->code); + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + + // loops to self, so check condition + if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { + SuperVUTestVU0Condition(0); + } + + if ( _Ft_ ) { + _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); + MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); + } + + if( s_pCurBlock->blocks.size() > 1 ) { + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; + s_UnconditionalDelay = 1; + } + + branch |= 3; +} + +void recSVUMI_JR() +{ + int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + CWDE(); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); + + if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { +#ifdef __x86_64__ + _allocX86reg(X86ARG1, X86TYPE_FNARG, 0, MODE_READ|MODE_WRITE); + MOV32RtoR(X86ARG1, EAX); +#else + PUSH32I(s_vu); + PUSH32R(EAX); +#endif + } + branch |= 0x10; // 0x08 is reserved +} + +void recSVUMI_JALR() +{ + _addNeededX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_); + + int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + CWDE(); // necessary, charlie and chocolate factory gives bad addrs, but graphics are ok + + if ( _Ft_ ) { + _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); + MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); + } + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); + + if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { +#ifdef __x86_64__ + _allocX86reg(X86ARG1, X86TYPE_FNARG, 0, MODE_READ|MODE_WRITE); + MOV32RtoR(X86ARG1, EAX); +#else + PUSH32I(s_vu); + PUSH32R(EAX); +#endif + } + + branch |= 4; +} + +#ifdef SUPERVU_COUNT +void StopSVUCounter() +{ + QueryPerformanceCounter(&svufinal); + svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); +} + +void StartSVUCounter() +{ + QueryPerformanceCounter(&svubase); +} +#endif + +#ifdef PCSX2_DEVBUILD +void vu1xgkick(u32* pMem, u32 addr) +{ + assert( addr < 0x4000 ); +#ifdef SUPERVU_COUNT + StopSVUCounter(); +#endif + +#ifdef _DEBUG + static int scount = 0; + //static int curesp; + //__asm mov curesp, esp; + scount++; + +// if( scount > 1500 ) { +// __Log("xgkick 0x%x (%d)\n", addr, scount); +// iDumpVU1Registers(); +// for(int i = 0; i < 0x400; ++i) { +// __Log("%x: %x %x %x %x\n", i, *(int*)(VU1.Mem+16*i), *(int*)(VU1.Mem+16*i+4), *(int*)(VU1.Mem+16*i+8), *(int*)(VU1.Mem+16*i+12)); +// } +// } + + if( vudump & 8 ) { + __Log("xgkick 0x%x (%d)\n", addr, scount); + } +#endif + + GSGIFTRANSFER1(pMem, addr); + +#ifdef SUPERVU_COUNT + StartSVUCounter(); +#endif +} + +//extern u32 vudump; +//void countfn() +//{ +// static int scount = 0; +// scount++; +// +// if( scount > 16 ) { +// __Log("xgkick %d\n", scount); +// vudump |= 8; +// } +//} + +#endif + +void recSVUMI_XGKICK_( VURegs *VU ) +{ + assert( s_XGKICKReg > 0 && x86regs[s_XGKICKReg].inuse && x86regs[s_XGKICKReg].type == X86TYPE_VITEMP); + + x86regs[s_XGKICKReg].inuse = 0; // so free doesn't flush + _freeX86regs(); + _freeXMMregs(); + +#ifdef __x86_64__ + if( X86ARG2 != s_XGKICKReg ) + MOV32RtoR(X86ARG2, s_XGKICKReg); + MOV32ItoR(X86ARG1, (uptr)VU->Mem); +#else + PUSH32R(s_XGKICKReg); + PUSH32I((uptr)VU->Mem); +#endif + + //CALLFunc((u32)countfn); + + if( CHECK_MULTIGS ) { + CALLFunc((uptr)VU1XGKICK_MTGSTransfer); +#ifndef __x86_64__ + ADD32ItoR(ESP, 8); +#endif + } + else { +#ifdef PCSX2_DEVBUILD + CALLFunc((uptr)vu1xgkick); +#ifndef __x86_64__ + ADD32ItoR(ESP, 8); +#endif +#else + CALLFunc((uptr)GSgifTransfer1); +#endif + } + + s_ScheduleXGKICK = 0; +} + +void recSVUMI_XGKICK( VURegs *VU, int info ) +{ + if( s_ScheduleXGKICK ) { + // second xgkick, so launch the first + recSVUMI_XGKICK_(VU); + } + + int fsreg = _allocX86reg(X86ARG2, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + _freeX86reg(fsreg); // flush + x86regs[fsreg].inuse = 1; + x86regs[fsreg].type = X86TYPE_VITEMP; + x86regs[fsreg].needed = 1; + x86regs[fsreg].mode = MODE_WRITE|MODE_READ; + SHL32ItoR(fsreg, 4); + AND32ItoR(fsreg, 0x3fff); + s_XGKICKReg = fsreg; + + if( !SUPERVU_XGKICKDELAY || pc == s_pCurBlock->endpc ) { + recSVUMI_XGKICK_(VU); + } + else { + if( g_VUGameFixes & VUFIX_XGKICKDELAY2 ) + s_ScheduleXGKICK = min((u32)4, (s_pCurBlock->endpc-pc)/8); + else + s_ScheduleXGKICK = 2; + } +} + +// upper inst +void recSVUMI_ABS() { recVUMI_ABS(VU, s_vuInfo); } + +void recSVUMI_ADD() { recVUMI_ADD(VU, s_vuInfo); } +void recSVUMI_ADDi() { recVUMI_ADDi(VU, s_vuInfo); } +void recSVUMI_ADDq() { recVUMI_ADDq(VU, s_vuInfo); } +void recSVUMI_ADDx() { recVUMI_ADDx(VU, s_vuInfo); } +void recSVUMI_ADDy() { recVUMI_ADDy(VU, s_vuInfo); } +void recSVUMI_ADDz() { recVUMI_ADDz(VU, s_vuInfo); } +void recSVUMI_ADDw() { recVUMI_ADDw(VU, s_vuInfo); } + +void recSVUMI_ADDA() { recVUMI_ADDA(VU, s_vuInfo); } +void recSVUMI_ADDAi() { recVUMI_ADDAi(VU, s_vuInfo); } +void recSVUMI_ADDAq() { recVUMI_ADDAq(VU, s_vuInfo); } +void recSVUMI_ADDAx() { recVUMI_ADDAx(VU, s_vuInfo); } +void recSVUMI_ADDAy() { recVUMI_ADDAy(VU, s_vuInfo); } +void recSVUMI_ADDAz() { recVUMI_ADDAz(VU, s_vuInfo); } +void recSVUMI_ADDAw() { recVUMI_ADDAw(VU, s_vuInfo); } + +void recSVUMI_SUB() { recVUMI_SUB(VU, s_vuInfo); } +void recSVUMI_SUBi() { recVUMI_SUBi(VU, s_vuInfo); } +void recSVUMI_SUBq() { recVUMI_SUBq(VU, s_vuInfo); } +void recSVUMI_SUBx() { recVUMI_SUBx(VU, s_vuInfo); } +void recSVUMI_SUBy() { recVUMI_SUBy(VU, s_vuInfo); } +void recSVUMI_SUBz() { recVUMI_SUBz(VU, s_vuInfo); } +void recSVUMI_SUBw() { recVUMI_SUBw(VU, s_vuInfo); } + +void recSVUMI_SUBA() { recVUMI_SUBA(VU, s_vuInfo); } +void recSVUMI_SUBAi() { recVUMI_SUBAi(VU, s_vuInfo); } +void recSVUMI_SUBAq() { recVUMI_SUBAq(VU, s_vuInfo); } +void recSVUMI_SUBAx() { recVUMI_SUBAx(VU, s_vuInfo); } +void recSVUMI_SUBAy() { recVUMI_SUBAy(VU, s_vuInfo); } +void recSVUMI_SUBAz() { recVUMI_SUBAz(VU, s_vuInfo); } +void recSVUMI_SUBAw() { recVUMI_SUBAw(VU, s_vuInfo); } + +void recSVUMI_MUL() { recVUMI_MUL(VU, s_vuInfo); } +void recSVUMI_MULi() { recVUMI_MULi(VU, s_vuInfo); } +void recSVUMI_MULq() { recVUMI_MULq(VU, s_vuInfo); } +void recSVUMI_MULx() { recVUMI_MULx(VU, s_vuInfo); } +void recSVUMI_MULy() { recVUMI_MULy(VU, s_vuInfo); } +void recSVUMI_MULz() { recVUMI_MULz(VU, s_vuInfo); } +void recSVUMI_MULw() { recVUMI_MULw(VU, s_vuInfo); } + +void recSVUMI_MULA() { recVUMI_MULA(VU, s_vuInfo); } +void recSVUMI_MULAi() { recVUMI_MULAi(VU, s_vuInfo); } +void recSVUMI_MULAq() { recVUMI_MULAq(VU, s_vuInfo); } +void recSVUMI_MULAx() { recVUMI_MULAx(VU, s_vuInfo); } +void recSVUMI_MULAy() { recVUMI_MULAy(VU, s_vuInfo); } +void recSVUMI_MULAz() { recVUMI_MULAz(VU, s_vuInfo); } +void recSVUMI_MULAw() { recVUMI_MULAw(VU, s_vuInfo); } + +void recSVUMI_MADD() { recVUMI_MADD(VU, s_vuInfo); } +void recSVUMI_MADDi() { recVUMI_MADDi(VU, s_vuInfo); } +void recSVUMI_MADDq() { recVUMI_MADDq(VU, s_vuInfo); } +void recSVUMI_MADDx() { recVUMI_MADDx(VU, s_vuInfo); } +void recSVUMI_MADDy() { recVUMI_MADDy(VU, s_vuInfo); } +void recSVUMI_MADDz() { recVUMI_MADDz(VU, s_vuInfo); } +void recSVUMI_MADDw() { recVUMI_MADDw(VU, s_vuInfo); } + +void recSVUMI_MADDA() { recVUMI_MADDA(VU, s_vuInfo); } +void recSVUMI_MADDAi() { recVUMI_MADDAi(VU, s_vuInfo); } +void recSVUMI_MADDAq() { recVUMI_MADDAq(VU, s_vuInfo); } +void recSVUMI_MADDAx() { recVUMI_MADDAx(VU, s_vuInfo); } +void recSVUMI_MADDAy() { recVUMI_MADDAy(VU, s_vuInfo); } +void recSVUMI_MADDAz() { recVUMI_MADDAz(VU, s_vuInfo); } +void recSVUMI_MADDAw() { recVUMI_MADDAw(VU, s_vuInfo); } + +void recSVUMI_MSUB() { recVUMI_MSUB(VU, s_vuInfo); } +void recSVUMI_MSUBi() { recVUMI_MSUBi(VU, s_vuInfo); } +void recSVUMI_MSUBq() { recVUMI_MSUBq(VU, s_vuInfo); } +void recSVUMI_MSUBx() { recVUMI_MSUBx(VU, s_vuInfo); } +void recSVUMI_MSUBy() { recVUMI_MSUBy(VU, s_vuInfo); } +void recSVUMI_MSUBz() { recVUMI_MSUBz(VU, s_vuInfo); } +void recSVUMI_MSUBw() { recVUMI_MSUBw(VU, s_vuInfo); } + +void recSVUMI_MSUBA() { recVUMI_MSUBA(VU, s_vuInfo); } +void recSVUMI_MSUBAi() { recVUMI_MSUBAi(VU, s_vuInfo); } +void recSVUMI_MSUBAq() { recVUMI_MSUBAq(VU, s_vuInfo); } +void recSVUMI_MSUBAx() { recVUMI_MSUBAx(VU, s_vuInfo); } +void recSVUMI_MSUBAy() { recVUMI_MSUBAy(VU, s_vuInfo); } +void recSVUMI_MSUBAz() { recVUMI_MSUBAz(VU, s_vuInfo); } +void recSVUMI_MSUBAw() { recVUMI_MSUBAw(VU, s_vuInfo); } + +void recSVUMI_MAX() { recVUMI_MAX(VU, s_vuInfo); } +void recSVUMI_MAXi() { recVUMI_MAXi(VU, s_vuInfo); } +void recSVUMI_MAXx() { recVUMI_MAXx(VU, s_vuInfo); } +void recSVUMI_MAXy() { recVUMI_MAXy(VU, s_vuInfo); } +void recSVUMI_MAXz() { recVUMI_MAXz(VU, s_vuInfo); } +void recSVUMI_MAXw() { recVUMI_MAXw(VU, s_vuInfo); } + +void recSVUMI_MINI() { recVUMI_MINI(VU, s_vuInfo); } +void recSVUMI_MINIi() { recVUMI_MINIi(VU, s_vuInfo); } +void recSVUMI_MINIx() { recVUMI_MINIx(VU, s_vuInfo); } +void recSVUMI_MINIy() { recVUMI_MINIy(VU, s_vuInfo); } +void recSVUMI_MINIz() { recVUMI_MINIz(VU, s_vuInfo); } +void recSVUMI_MINIw() { recVUMI_MINIw(VU, s_vuInfo); } + +void recSVUMI_FTOI0() { recVUMI_FTOI0(VU, s_vuInfo); } +void recSVUMI_FTOI4() { recVUMI_FTOI4(VU, s_vuInfo); } +void recSVUMI_FTOI12() { recVUMI_FTOI12(VU, s_vuInfo); } +void recSVUMI_FTOI15() { recVUMI_FTOI15(VU, s_vuInfo); } +void recSVUMI_ITOF0() { recVUMI_ITOF0(VU, s_vuInfo); } +void recSVUMI_ITOF4() { recVUMI_ITOF4(VU, s_vuInfo); } +void recSVUMI_ITOF12() { recVUMI_ITOF12(VU, s_vuInfo); } +void recSVUMI_ITOF15() { recVUMI_ITOF15(VU, s_vuInfo); } + +void recSVUMI_OPMULA() { recVUMI_OPMULA(VU, s_vuInfo); } +void recSVUMI_OPMSUB() { recVUMI_OPMSUB(VU, s_vuInfo); } +void recSVUMI_NOP() +{ + //ffxii text disappearing bug + // NOP gets set that it will write the status flag. If it leaves it alone + // s_PrevStatusWrite will get replaced with pStatusWrite, which is garbage and stuff breaks + /*if( (s_vuInfo & PROCESS_VU_UPDATEFLAGS) ) + return;*/ + + // this is just a hack + //s_pCurInst->regs[1].VIwrite &= ~((1<code >> 6 ) & 0x1f ]( ); +} + +void recSVU_UPPER_FD_01( void ) +{ + recSVU_UPPER_FD_01_TABLE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVU_UPPER_FD_10( void ) +{ + recSVU_UPPER_FD_10_TABLE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVU_UPPER_FD_11( void ) +{ + recSVU_UPPER_FD_11_TABLE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVULowerOP( void ) +{ + recSVULowerOP_OPCODE[ VU->code & 0x3f ]( ); +} + +void recSVULowerOP_T3_00( void ) +{ + recSVULowerOP_T3_00_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVULowerOP_T3_01( void ) +{ + recSVULowerOP_T3_01_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVULowerOP_T3_10( void ) +{ + recSVULowerOP_T3_10_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVULowerOP_T3_11( void ) +{ + recSVULowerOP_T3_11_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( ); +} + +void recSVUunknown( void ) +{ + SysPrintf("Unknown SVU micromode opcode called\n"); +} + +#endif // PCX2_NORECBUILD diff --git a/pcsx2/x86/iVUzerorec.h b/pcsx2/x86/iVUzerorec.h new file mode 100644 index 0000000000..ba595a5b95 --- /dev/null +++ b/pcsx2/x86/iVUzerorec.h @@ -0,0 +1,49 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// Super VU recompiler - author: zerofrog(@gmail.com) + +#ifndef VU1_SUPER_RECOMPILER +#define VU1_SUPER_RECOMPILER + +#ifdef __cplusplus +extern "C" { +#endif + +void SuperVUInit(int vuindex); // if vuindex is -1, inits the global VU resources +void SuperVUDestroy(int vuindex); // if vuindex is -1, destroys everything +void SuperVUReset(int vuindex); // if vuindex is -1, resets everything + +void SuperVUExecuteProgram(u32 startpc, int vuindex); +void SuperVUClear(u32 startpc, u32 size, int vuindex); + +u64 SuperVUGetRecTimes(int clear); + +// read = 0, will write to reg +// read = 1, will read from reg +// read = 2, addr of previously written reg (used for status and clip flags) +u32 SuperVUGetVIAddr(int reg, int read); + +// if p == 0, flush q else flush p; if wait is != 0, waits for p/q +void SuperVUFlush(int p, int wait); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pcsx2/x86/iVif.cpp b/pcsx2/x86/iVif.cpp new file mode 100644 index 0000000000..99bfcd4d62 --- /dev/null +++ b/pcsx2/x86/iVif.cpp @@ -0,0 +1,160 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Common.h" +#include "ix86/ix86.h" +#include "Vif.h" +#include "VUmicro.h" + +#include + +extern VIFregisters *_vifRegs; +extern u32* _vifMaskRegs; +extern u32* _vifRow, _vifCol; + +// sse2 highly optimized vif (~200 separate functions are built) zerofrog(@gmail.com) +extern u32 g_vif1Masks[48], g_vif0Masks[48]; +extern u32 g_vif1HasMask3[4], g_vif0HasMask3[4]; + +//static const u32 writearr[4] = { 0xffffffff, 0, 0, 0 }; +//static const u32 rowarr[4] = { 0, 0xffffffff, 0, 0 }; +//static const u32 colarr[4] = { 0, 0, 0xffffffff, 0 }; +//static const u32 updatearr[4] = {0xffffffff, 0xffffffff, 0xffffffff, 0 }; + +// arranged in writearr, rowarr, colarr, updatearr +static PCSX2_ALIGNED16(u32 s_maskarr[16][4]) = { + 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, + 0xffff0000, 0x0000ffff, 0x00000000, 0xffffffff, + 0xffff0000, 0x00000000, 0x0000ffff, 0xffffffff, + 0xffff0000, 0x00000000, 0x00000000, 0xffff0000, + 0x0000ffff, 0xffff0000, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff, + 0x00000000, 0xffff0000, 0x00000000, 0xffff0000, + 0x0000ffff, 0x00000000, 0xffff0000, 0xffffffff, + 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x00000000, 0x00000000, 0x0000ffff, + 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, + 0x00000000, 0x00000000, 0x0000ffff, 0x0000ffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +extern u8 s_maskwrite[256]; +PCSX2_ALIGNED16(u32 s_TempDecompress[4]) = {0}; + +#if defined(_MSC_VER) // gcc functions can be found in iVif.S + +#include +#include + +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) +{ + u32 i; + u32 prev = 0; + if( !cpucaps.hasStreamingSIMD2Extensions ) return; + FreezeXMMRegs(1); + for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { + + prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); + hasmask[i] = prev; + + if( (mask&0xff) != (oldmask&0xff) ) { + __m128i r0, r1, r2, r3; + r0 = _mm_load_si128((__m128i*)&s_maskarr[mask&15][0]); + r2 = _mm_unpackhi_epi16(r0, r0); + r0 = _mm_unpacklo_epi16(r0, r0); + + r1 = _mm_load_si128((__m128i*)&s_maskarr[(mask>>4)&15][0]); + r3 = _mm_unpackhi_epi16(r1, r1); + r1 = _mm_unpacklo_epi16(r1, r1); + + _mm_storel_pi((__m64*)&vif1masks[0], *(__m128*)&r0); + _mm_storel_pi((__m64*)&vif1masks[2], *(__m128*)&r1); + _mm_storeh_pi((__m64*)&vif1masks[4], *(__m128*)&r0); + _mm_storeh_pi((__m64*)&vif1masks[6], *(__m128*)&r1); + + _mm_storel_pi((__m64*)&vif1masks[8], *(__m128*)&r2); + _mm_storel_pi((__m64*)&vif1masks[10], *(__m128*)&r3); + _mm_storeh_pi((__m64*)&vif1masks[12], *(__m128*)&r2); + _mm_storeh_pi((__m64*)&vif1masks[14], *(__m128*)&r3); + } + } + FreezeXMMRegs(0); +} + + +#else // gcc + +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) +{ + u32 i; + u32 prev = 0; + if( !cpucaps.hasStreamingSIMD2Extensions ) return; + FreezeXMMRegs(1); + + for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { + + prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); + hasmask[i] = prev; + + if( (mask&0xff) != (oldmask&0xff) ) { + u8* p0 = (u8*)&s_maskarr[mask&15][0]; + u8* p1 = (u8*)&s_maskarr[(mask>>4)&15][0]; + + __asm__(".intel_syntax\n" + "movaps %%xmm0, [%0]\n" + "movaps %%xmm1, [%1]\n" + "movaps %%xmm2, %%xmm0\n" + "punpcklwd %%xmm0, %%xmm0\n" + "punpckhwd %%xmm2, %%xmm2\n" + "movaps %%xmm3, %%xmm1\n" + "punpcklwd %%xmm1, %%xmm1\n" + "punpckhwd %%xmm3, %%xmm3\n" + "movq [%2], %%xmm0\n" + "movq [%2+8], %%xmm1\n" + "movhps [%2+16], %%xmm0\n" + "movhps [%2+24], %%xmm1\n" + "movq [%2+32], %%xmm2\n" + "movq [%2+40], %%xmm3\n" + "movhps [%2+48], %%xmm2\n" + "movhps [%2+56], %%xmm3\n" + ".att_syntax\n" : : "r"(p0), "r"(p1), "r"(vif1masks) ); + } + } + FreezeXMMRegs(0); +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ir5900tables.c b/pcsx2/x86/ir5900tables.c new file mode 100644 index 0000000000..375a9900e2 --- /dev/null +++ b/pcsx2/x86/ir5900tables.c @@ -0,0 +1,1285 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// Holds instruction tables for the r5900 recompiler + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +#include "Common.h" +#include "Memory.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iR5900AritImm.h" +#include "iR5900Arit.h" +#include "iR5900MultDiv.h" +#include "iR5900Shift.h" +#include "iR5900Branch.h" +#include "iR5900Jump.h" +#include "iR5900LoadStore.h" +#include "iR5900Move.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" + +//////////////////////////////////////////////////// +static void recNULL( void ) +{ + SysPrintf("EE: Unimplemented op %x\n", cpuRegs.code); +} + +//////////////////////////////////////////////////// +static void recREGIMM( void ) +{ + recREG[ _Rt_ ]( ); +} + +//////////////////////////////////////////////////// +static void recSPECIAL( void ) +{ + recSPC[ _Funct_ ]( ); +} + +//////////////////////////////////////////////////// +static void recCOP0( void ) +{ + recCP0[ _Rs_ ]( ); +} + +//////////////////////////////////////////////////// +static void recCOP0BC0( void ) +{ + recCP0BC0[ ( cpuRegs.code >> 16 ) & 0x03 ]( ); +} + +//////////////////////////////////////////////////// +static void recCOP0C0( void ) +{ + recCP0C0[ _Funct_ ]( ); +} + +//////////////////////////////////////////////////// +static void recCOP1( void ) { + recCP1[ _Rs_ ]( ); +} + +//////////////////////////////////////////////////// +static void recMMI( void ) +{ + recMMIt[ _Funct_ ]( ); +} + + +/********************************************************** +* UNHANDLED YET OPCODES +* +**********************************************************/ + +//////////////////////////////////////////////////// +//REC_SYS(PREF); +//////////////////////////////////////////////////// +//REC_SYS(MFSA); +//////////////////////////////////////////////////// +//REC_SYS(MTSA); +//////////////////////////////////////////////////// +REC_SYS(TGE); +//////////////////////////////////////////////////// +REC_SYS(TGEU); +//////////////////////////////////////////////////// +REC_SYS(TLT); +//////////////////////////////////////////////////// +REC_SYS(TLTU); +//////////////////////////////////////////////////// +REC_SYS(TEQ); +//////////////////////////////////////////////////// +REC_SYS(TNE); +//////////////////////////////////////////////////// +REC_SYS(TGEI); +//////////////////////////////////////////////////// +REC_SYS(TGEIU); +//////////////////////////////////////////////////// +REC_SYS(TLTI); +//////////////////////////////////////////////////// +REC_SYS(TLTIU); +//////////////////////////////////////////////////// +REC_SYS(TEQI); +//////////////////////////////////////////////////// +REC_SYS(TNEI); +//////////////////////////////////////////////////// +//REC_SYS(MTSAB); +//////////////////////////////////////////////////// +//REC_SYS(MTSAH); +//////////////////////////////////////////////////// +REC_SYS(CACHE); + +/* +void recTGE( void ) +{ +} + +void recTGEU( void ) +{ +} + +void recTLT( void ) +{ +} + +void recTLTU( void ) +{ +} + +void recTEQ( void ) +{ +} + +void recTNE( void ) +{ +} + +void recTGEI( void ) +{ +} + +void recTGEIU( void ) +{ +} + +void recTLTI( void ) +{ +} + +void recTLTIU( void ) +{ +} + +void recTEQI( void ) +{ +} + +void recTNEI( void ) +{ +} + +*/ + +///////////////////////////////// +// Foward-Prob Function Tables // +///////////////////////////////// +extern void recCOP2( void ); +extern void recSYSCALL( void ); +extern void recBREAK( void ); +extern void recPREF( void ); +extern void recSYNC( void ); +extern void recMFSA( void ); +extern void recMTSA( void ); +extern void recMTSAB( void ); +extern void recMTSAH( void ); + +void (*recBSC[64] )() = { + recSPECIAL, recREGIMM, recJ, recJAL, recBEQ, recBNE, recBLEZ, recBGTZ, + recADDI, recADDIU, recSLTI, recSLTIU, recANDI, recORI, recXORI, recLUI, + recCOP0, recCOP1, recCOP2, recNULL, recBEQL, recBNEL, recBLEZL, recBGTZL, + recDADDI, recDADDIU, recLDL, recLDR, recMMI, recNULL, recLQ, recSQ, + recLB, recLH, recLWL, recLW, recLBU, recLHU, recLWR, recLWU, + recSB, recSH, recSWL, recSW, recSDL, recSDR, recSWR, recCACHE, + recNULL, recLWC1, recNULL, recPREF, recNULL, recNULL, recLQC2, recLD, + recNULL, recSWC1, recNULL, recNULL, recNULL, recNULL, recSQC2, recSD +}; + +#ifdef PCSX2_VIRTUAL_MEM +// coissued insts +void (*recBSC_co[64] )() = { + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recLDL_co, recLDR_co, recNULL, recNULL, recLQ_co, recSQ_co, + recLB_co, recLH_co, recLWL_co, recLW_co, recLBU_co, recLHU_co, recLWR_co, recLWU_co, + recSB_co, recSH_co, recSWL_co, recSW_co, recSDL_co, recSDR_co, recSWR_co, recNULL, + recNULL, recLWC1_co, recNULL, recNULL, recNULL, recNULL, recLQC2_co, recLD_co, + recNULL, recSWC1_co, recNULL, recNULL, recNULL, recNULL, recSQC2_co, recSD_co +}; +#endif + +void (*recSPC[64] )() = { + recSLL, recNULL, recSRL, recSRA, recSLLV, recNULL, recSRLV, recSRAV, + recJR, recJALR, recMOVZ, recMOVN, recSYSCALL, recBREAK, recNULL, recSYNC, + recMFHI, recMTHI, recMFLO, recMTLO, recDSLLV, recNULL, recDSRLV, recDSRAV, + recMULT, recMULTU, recDIV, recDIVU, recNULL, recNULL, recNULL, recNULL, + recADD, recADDU, recSUB, recSUBU, recAND, recOR, recXOR, recNOR, + recMFSA, recMTSA, recSLT, recSLTU, recDADD, recDADDU, recDSUB, recDSUBU, + recTGE, recTGEU, recTLT, recTLTU, recTEQ, recNULL, recTNE, recNULL, + recDSLL, recNULL, recDSRL, recDSRA, recDSLL32, recNULL, recDSRL32, recDSRA32 +}; + +void (*recREG[32] )() = { + recBLTZ, recBGEZ, recBLTZL, recBGEZL, recNULL, recNULL, recNULL, recNULL, + recTGEI, recTGEIU, recTLTI, recTLTIU, recTEQI, recNULL, recTNEI, recNULL, + recBLTZAL, recBGEZAL, recBLTZALL, recBGEZALL, recNULL, recNULL, recNULL, recNULL, + recMTSAB, recMTSAH, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP0[32] )() = { + recMFC0, recNULL, recNULL, recNULL, recMTC0, recNULL, recNULL, recNULL, + recCOP0BC0, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recCOP0C0, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP0BC0[32] )() = { + recBC0F, recBC0T, recBC0FL, recBC0TL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP0C0[64] )() = { + recNULL, recTLBR, recTLBWI, recNULL, recNULL, recNULL, recTLBWR, recNULL, + recTLBP, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recERET, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recEI, recDI, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP1[32] )() = { + recMFC1, recNULL, recCFC1, recNULL, recMTC1, recNULL, recCTC1, recNULL, + recCOP1_BC1, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recCOP1_S, recNULL, recNULL, recNULL, recCOP1_W, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP1BC1[32] )() = { + recBC1F, recBC1T, recBC1FL, recBC1TL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP1S[64] )() = { + recADD_S, recSUB_S, recMUL_S, recDIV_S, recSQRT_S, recABS_S, recMOV_S, recNEG_S, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recRSQRT_S, recNULL, + recADDA_S, recSUBA_S, recMULA_S, recNULL, recMADD_S, recMSUB_S, recMADDA_S, recMSUBA_S, + recNULL, recNULL, recNULL, recNULL, recCVT_W, recNULL, recNULL, recNULL, + recMAX_S, recMIN_S, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recC_F, recNULL, recC_EQ, recNULL, recC_LT, recNULL, recC_LE, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recCP1W[64] )() = { + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recCVT_S, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, +}; + +void (*recMMIt[64] )() = { + recMADD, recMADDU, recNULL, recNULL, recPLZCW, recNULL, recNULL, recNULL, + recMMI0, recMMI2, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recMFHI1, recMTHI1, recMFLO1, recMTLO1, recNULL, recNULL, recNULL, recNULL, + recMULT1, recMULTU1, recDIV1, recDIVU1, recNULL, recNULL, recNULL, recNULL, + recMADD1, recMADDU1, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recMMI1 , recMMI3, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recPMFHL, recPMTHL, recNULL, recNULL, recPSLLH, recNULL, recPSRLH, recPSRAH, + recNULL, recNULL, recNULL, recNULL, recPSLLW, recNULL, recPSRLW, recPSRAW, +}; + +void (*recMMI0t[32] )() = { + recPADDW, recPSUBW, recPCGTW, recPMAXW, + recPADDH, recPSUBH, recPCGTH, recPMAXH, + recPADDB, recPSUBB, recPCGTB, recNULL, + recNULL, recNULL, recNULL, recNULL, + recPADDSW, recPSUBSW, recPEXTLW, recPPACW, + recPADDSH, recPSUBSH, recPEXTLH, recPPACH, + recPADDSB, recPSUBSB, recPEXTLB, recPPACB, + recNULL, recNULL, recPEXT5, recPPAC5, +}; + +void (*recMMI1t[32] )() = { + recNULL, recPABSW, recPCEQW, recPMINW, + recPADSBH, recPABSH, recPCEQH, recPMINH, + recNULL, recNULL, recPCEQB, recNULL, + recNULL, recNULL, recNULL, recNULL, + recPADDUW, recPSUBUW, recPEXTUW, recNULL, + recPADDUH, recPSUBUH, recPEXTUH, recNULL, + recPADDUB, recPSUBUB, recPEXTUB, recQFSRV, + recNULL, recNULL, recNULL, recNULL, +}; + +void (*recMMI2t[32] )() = { + recPMADDW, recNULL, recPSLLVW, recPSRLVW, + recPMSUBW, recNULL, recNULL, recNULL, + recPMFHI, recPMFLO, recPINTH, recNULL, + recPMULTW, recPDIVW, recPCPYLD, recNULL, + recPMADDH, recPHMADH, recPAND, recPXOR, + recPMSUBH, recPHMSBH, recNULL, recNULL, + recNULL, recNULL, recPEXEH, recPREVH, + recPMULTH, recPDIVBW, recPEXEW, recPROT3W, +}; + +void (*recMMI3t[32] )() = { + recPMADDUW, recNULL, recNULL, recPSRAVW, + recNULL, recNULL, recNULL, recNULL, + recPMTHI, recPMTLO, recPINTEH, recNULL, + recPMULTUW, recPDIVUW, recPCPYUD, recNULL, + recNULL, recNULL, recPOR, recPNOR, + recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recPEXCH, recPCPYH, + recNULL, recNULL, recPEXCW, recNULL, +}; + +//////////////////////////////////////////////// +// Back-Prob Function Tables - Gathering Info // +//////////////////////////////////////////////// +#define rpropSetRead(reg, mask) { \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + prev->regs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; \ + pinst->regs[reg] |= EEINST_USED; \ + if( reg ) pinst->info = ((mask)&(EEINST_MMX|EEINST_XMM)); \ + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 0); \ +} \ + +#define rpropSetWrite0(reg, mask, live) { \ + prev->regs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + pinst->regs[reg] |= EEINST_USED; \ + prev->regs[reg] |= EEINST_USED; \ + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 1); \ +} + +#define rpropSetWrite(reg, mask) { \ + rpropSetWrite0(reg, mask, EEINST_LIVE0); \ +} \ + +#define rpropSetFast(write1, read1, read2, mask) { \ + if( write1 ) { rpropSetWrite(write1, mask); } \ + if( read1 ) { rpropSetRead(read1, mask); } \ + if( read2 ) { rpropSetRead(read2, mask); } \ +} \ + +#define rpropSetLOHI(write1, read1, read2, mask, lo, hi) { \ + if( write1 ) { rpropSetWrite(write1, mask); } \ + if( (lo) & MODE_WRITE ) { rpropSetWrite(XMMGPR_LO, mask); } \ + if( (hi) & MODE_WRITE ) { rpropSetWrite(XMMGPR_HI, mask); } \ + if( read1 ) { rpropSetRead(read1, mask); } \ + if( read2 ) { rpropSetRead(read2, mask); } \ + if( (lo) & MODE_READ ) { rpropSetRead(XMMGPR_LO, mask); } \ + if( (hi) & MODE_READ ) { rpropSetRead(XMMGPR_HI, mask); } \ +} \ + +// FPU regs +#define rpropSetFPURead(reg, mask) { \ + if( !(pinst->fpuregs[reg] & EEINST_USED) ) \ + pinst->fpuregs[reg] |= EEINST_LASTUSE; \ + prev->fpuregs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; \ + pinst->fpuregs[reg] |= EEINST_USED; \ + if( reg ) pinst->info = ((mask)&(EEINST_MMX|EEINST_XMM)); \ + if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 0); \ + else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 0); \ +} \ + +#define rpropSetFPUWrite0(reg, mask, live) { \ + prev->fpuregs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); \ + if( !(pinst->fpuregs[reg] & EEINST_USED) ) \ + pinst->fpuregs[reg] |= EEINST_LASTUSE; \ + pinst->fpuregs[reg] |= EEINST_USED; \ + prev->fpuregs[reg] |= EEINST_USED; \ + if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 1); \ + else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 1); \ +} + +#define rpropSetFPUWrite(reg, mask) { \ + rpropSetFPUWrite0(reg, mask, EEINST_LIVE0); \ +} \ + + +void rpropBSC(EEINST* prev, EEINST* pinst); +void rpropSPECIAL(EEINST* prev, EEINST* pinst); +void rpropREGIMM(EEINST* prev, EEINST* pinst); +void rpropCP0(EEINST* prev, EEINST* pinst); +void rpropCP1(EEINST* prev, EEINST* pinst); +void rpropCP2(EEINST* prev, EEINST* pinst); +void rpropMMI(EEINST* prev, EEINST* pinst); +void rpropMMI0(EEINST* prev, EEINST* pinst); +void rpropMMI1(EEINST* prev, EEINST* pinst); +void rpropMMI2(EEINST* prev, EEINST* pinst); +void rpropMMI3(EEINST* prev, EEINST* pinst); + +#define EEINST_REALXMM (cpucaps.hasStreamingSIMDExtensions?EEINST_XMM:0) + +//SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, +//ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, +//COP0, COP1, COP2, NULL, BEQL, BNEL, BLEZL, BGTZL, +//DADDI, DADDIU, LDL, LDR, MMI, NULL, LQ, SQ, +//LB, LH, LWL, LW, LBU, LHU, LWR, LWU, +//SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, +//NULL, LWC1, NULL, PREF, NULL, NULL, LQC2, LD, +//NULL, SWC1, NULL, NULL, NULL, NULL, SQC2, SD +void rpropBSC(EEINST* prev, EEINST* pinst) +{ + switch(cpuRegs.code >> 26) { + case 0: rpropSPECIAL(prev, pinst); break; + case 1: rpropREGIMM(prev, pinst); break; + case 2: // j + break; + case 3: // jal + rpropSetWrite(31, EEINST_LIVE1); + break; + case 4: // beq + case 5: // bne + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst->info |= (cpucaps.hasStreamingSIMD2Extensions?(EEINST_REALXMM|EEINST_MMX):0); + break; + + case 20: // beql + case 21: // bnel + // reset since don't know which path to go + _recClearInst(prev); + prev->info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst->info |= (cpucaps.hasStreamingSIMD2Extensions?(EEINST_REALXMM|EEINST_MMX):0); + break; + + case 6: // blez + case 7: // bgtz + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 22: // blezl + case 23: // bgtzl + // reset since don't know which path to go + _recClearInst(prev); + prev->info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // daddi + case 25: // daddiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|((_Rs_!=0&&cpucaps.hasStreamingSIMD2Extensions)?EEINST_MMX:0)); + break; + + case 8: // addi + case 9: // addiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + pinst->info |= EEINST_MMX; + break; + + case 10: // slti + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + break; + case 11: // sltiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + break; + + case 12: // andi + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, (_Rs_!=_Rt_?EEINST_MMX:0)); + pinst->info |= EEINST_MMX; + break; + case 13: // ori + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); + pinst->info |= EEINST_MMX; + break; + case 14: // xori + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); + pinst->info |= EEINST_MMX; + break; + + case 15: // lui + rpropSetWrite(_Rt_, EEINST_LIVE1); + break; + + case 16: rpropCP0(prev, pinst); break; + case 17: rpropCP1(prev, pinst); break; + case 18: rpropCP2(prev, pinst); break; + + // loads + case 34: // lwl + case 38: // lwr + case 26: // ldl + case 27: // ldr + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 32: case 33: case 35: case 36: case 37: case 39: + case 55: // LD + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 28: rpropMMI(prev, pinst); break; + + case 30: // lq + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_LIVE2); + rpropSetRead(_Rs_, 0); + pinst->info |= EEINST_MMX; + pinst->info |= EEINST_REALXMM; + break; + + case 31: // sq + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + pinst->info |= EEINST_MMX; + pinst->info |= EEINST_REALXMM; + break; + + // 4 byte stores + case 40: case 41: case 42: case 43: case 46: + rpropSetRead(_Rt_, 0); + rpropSetRead(_Rs_, 0); + pinst->info |= EEINST_MMX; + pinst->info |= EEINST_REALXMM; + break; + + case 44: // sdl + case 45: // sdr + case 63: // sd + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX|EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 49: // lwc1 + rpropSetFPUWrite(_Rt_, EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 57: // swc1 + rpropSetFPURead(_Rt_, EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 54: // lqc2 + case 62: // sqc2 + rpropSetRead(_Rs_, 0); + break; + + default: + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=0?EEINST_MMX:0)); + break; + } +} + +//SLL, NULL, SRL, SRA, SLLV, NULL, SRLV, SRAV, +//JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, NULL, SYNC, +//MFHI, MTHI, MFLO, MTLO, DSLLV, NULL, DSRLV, DSRAV, +//MULT, MULTU, DIV, DIVU, NULL, NULL, NULL, NULL, +//ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, +//MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, +//TGE, TGEU, TLT, TLTU, TEQ, NULL, TNE, NULL, +//DSLL, NULL, DSRL, DSRA, DSLL32, NULL, DSRL32, DSRA32 +void rpropSPECIAL(EEINST* prev, EEINST* pinst) +{ + int temp; + switch(_Funct_) { + case 0: // SLL + case 2: // SRL + case 3: // SRA + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_MMX); + break; + + case 4: // sllv + case 6: // srlv + case 7: // srav + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_MMX); + rpropSetRead(_Rt_, EEINST_MMX); + break; + + case 8: // JR + rpropSetRead(_Rs_, 0); + break; + case 9: // JALR + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 10: // movz + case 11: // movn + // do not write _Rd_! + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rd_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + _recFillRegister(pinst, XMMTYPE_GPRREG, _Rd_, 1); + break; + + case 12: // syscall + case 13: // break + _recClearInst(prev); + prev->info = 0; + break; + case 15: // sync + break; + + case 16: // mfhi + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, (pinst->regs[_Rd_]&EEINST_MMX|EEINST_REALXMM)|EEINST_LIVE1); + break; + case 17: // mthi + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + case 18: // mflo + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, (pinst->regs[_Rd_]&EEINST_MMX|EEINST_REALXMM)|EEINST_LIVE1); + break; + case 19: // mtlo + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 20: // dsllv + case 22: // dsrlv + case 23: // dsrav + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_MMX); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); + break; + + case 24: // mult + // can do unsigned mult only if HI isn't used + //temp = (pinst->regs[XMMGPR_HI]&(EEINST_LIVE0|EEINST_LIVE1))?0:(cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0); + temp = 0; + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, temp); + rpropSetRead(_Rt_, temp); + pinst->info |= temp; + break; + case 25: // multu + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, (cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + rpropSetRead(_Rt_, (cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + if( cpucaps.hasStreamingSIMD2Extensions ) pinst->info |= EEINST_MMX; + break; + + case 26: // div + case 27: // divu + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + rpropSetRead(_Rt_, 0); + //pinst->info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 32: // add + case 33: // addu + case 34: // sub + case 35: // subu + rpropSetWrite(_Rd_, EEINST_LIVE1); + if( _Rs_ ) rpropSetRead(_Rs_, 0); + if( _Rt_ ) rpropSetRead(_Rt_, 0); + pinst->info |= EEINST_MMX; + break; + + case 36: // and + case 37: // or + case 38: // xor + case 39: // nor + // if rd == rs or rt, keep live1 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, (pinst->regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + rpropSetRead(_Rt_, (pinst->regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + break; + + case 40: // mfsa + rpropSetWrite(_Rd_, EEINST_LIVE1); + break; + case 41: // mtsa + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); + break; + + case 42: // slt + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + break; + + case 43: // sltu + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + break; + + case 44: // dadd + case 45: // daddu + case 46: // dsub + case 47: // dsubu + rpropSetWrite(_Rd_, EEINST_LIVE1); + if( _Rs_ == 0 || _Rt_ == 0 ) { + // just a copy, so don't force mmx + rpropSetRead(_Rs_, (pinst->regs[_Rd_]&EEINST_LIVE1)); + rpropSetRead(_Rt_, (pinst->regs[_Rd_]&EEINST_LIVE1)); + } + else { + rpropSetRead(_Rs_, (pinst->regs[_Rd_]&EEINST_LIVE1)|(cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + rpropSetRead(_Rt_, (pinst->regs[_Rd_]&EEINST_LIVE1)|(cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + } + if( cpucaps.hasStreamingSIMD2Extensions ) pinst->info |= EEINST_MMX; + break; + + // traps + case 48: case 49: case 50: case 51: case 52: case 54: + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + break; + + case 56: // dsll + case 58: // dsrl + case 59: // dsra + case 62: // dsrl32 + case 63: // dsra32 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1|(cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + pinst->info |= EEINST_MMX; + break; + + case 60: // dsll32 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, (cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + pinst->info |= EEINST_MMX; + break; + + default: + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); + break; + } +} + +//BLTZ, BGEZ, BLTZL, BGEZL, NULL, NULL, NULL, NULL, +//TGEI, TGEIU, TLTI, TLTIU, TEQI, NULL, TNEI, NULL, +//BLTZAL, BGEZAL, BLTZALL, BGEZALL, NULL, NULL, NULL, NULL, +//MTSAB, MTSAH, NULL, NULL, NULL, NULL, NULL, NULL, +void rpropREGIMM(EEINST* prev, EEINST* pinst) +{ + switch(_Rt_) { + case 0: // bltz + case 1: // bgez + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + pinst->info |= EEINST_REALXMM; + break; + + case 2: // bltzl + case 3: // bgezl + // reset since don't know which path to go + _recClearInst(prev); + prev->info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst->info |= EEINST_MMX; + pinst->info |= EEINST_REALXMM; + break; + + // traps + case 8: + case 9: + case 10: + case 11: + case 12: + case 14: + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 16: // bltzal + case 17: // bgezal + // do not write 31 + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 18: // bltzall + case 19: // bgezall + // reset since don't know which path to go + _recClearInst(prev); + prev->info = 0; + // do not write 31 + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // mtsab + case 25: // mtsah + rpropSetRead(_Rs_, 0); + break; + default: + assert(0); + break; + } +} + +//MFC0, NULL, NULL, NULL, MTC0, NULL, NULL, NULL, +//COP0BC0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//COP0C0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +void rpropCP0(EEINST* prev, EEINST* pinst) +{ + switch(_Rs_) { + case 0: // mfc0 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 4: + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 8: // cop0bc0 + _recClearInst(prev); + prev->info = 0; + break; + case 16: // cop0c0 + _recClearInst(prev); + prev->info = 0; + break; + } +} + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +//ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, RSQRT_S, NULL, +//ADDA_S, SUBA_S, MULA_S, NULL, MADD_S, MSUB_S, MADDA_S, MSUBA_S, +//NULL, NULL, NULL, NULL, CVT_W, NULL, NULL, NULL, +//MAX_S, MIN_S, NULL, NULL, NULL, NULL, NULL, NULL, +//C_F, NULL, C_EQ, NULL, C_LT, NULL, C_LE, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +void rpropCP1(EEINST* prev, EEINST* pinst) +{ + switch(_Rs_) { + case 0: // mfc1 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + case 2: // cfc1 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); + break; + case 4: // mtc1 + rpropSetFPUWrite(_Fs_, EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 6: // ctc1 + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); + break; + case 8: // bc1 + // reset since don't know which path to go + _recClearInst(prev); + prev->info = 0; + break; + case 16: + // floating point ops + pinst->info |= EEINST_REALXMM; + switch( _Funct_ ) { + case 0: // add.s + case 1: // sub.s + case 2: // mul.s + case 3: // div.s + case 22: // rsqrt.s + case 40: // max.s + case 41: // min.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 4: // sqrt.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 5: // abs.s + case 6: // mov.s + case 7: // neg.s + case 36: // cvt.w + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + case 24: // adda.s + case 25: // suba.s + case 26: // mula.s + rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 28: // madd.s + case 29: // msub.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + + case 30: // madda.s + case 31: // msuba.s + rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + + case 48: // c.f + case 50: // c.eq + case 52: // c.lt + case 54: // c.le + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + default: assert(0); + } + break; + case 20: + assert( _Funct_ == 32 ); // CVT.S.W + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + default: + assert(0); + } +} + +#undef _Ft_ +#undef _Fs_ +#undef _Fd_ + +void rpropCP2(EEINST* prev, EEINST* pinst) +{ + switch(_Rs_) { + case 1: // qmfc2 + rpropSetWrite(_Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + + case 2: // cfc2 + rpropSetWrite(_Rt_, EEINST_LIVE1); + break; + + case 5: // qmtc2 + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 6: // ctc2 + rpropSetRead(_Rt_, 0); + break; + + case 8: // bc2 + break; + + default: + // vu macro mode insts + pinst->info |= 2; + break; + } +} + +//MADD, MADDU, NULL, NULL, PLZCW, NULL, NULL, NULL, +//MMI0, MMI2, NULL, NULL, NULL, NULL, NULL, NULL, +//MFHI1, MTHI1, MFLO1, MTLO1, NULL, NULL, NULL, NULL, +//MULT1, MULTU1, DIV1, DIVU1, NULL, NULL, NULL, NULL, +//MADD1, MADDU1, NULL, NULL, NULL, NULL, NULL, NULL, +//MMI1 , MMI3, NULL, NULL, NULL, NULL, NULL, NULL, +//PMFHL, PMTHL, NULL, NULL, PSLLH, NULL, PSRLH, PSRAH, +//NULL, NULL, NULL, NULL, PSLLW, NULL, PSRLW, PSRAW, +void rpropMMI(EEINST* prev, EEINST* pinst) +{ + int temp; + switch(cpuRegs.code&0x3f) { + case 0: // madd + case 1: // maddu + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE1, MODE_READ|MODE_WRITE, MODE_READ|MODE_WRITE); + break; + case 4: // plzcw + rpropSetFast(_Rd_, _Rs_, 0, EEINST_LIVE1); + break; + case 8: rpropMMI0(prev, pinst); break; + case 9: rpropMMI2(prev, pinst); break; + + case 16: // mfhi1 + rpropSetWrite(_Rd_, EEINST_LIVE1); + temp = ((pinst->regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); + rpropSetRead(XMMGPR_HI, temp|EEINST_LIVE2); + break; + case 17: // mthi1 + rpropSetWrite0(XMMGPR_HI, EEINST_LIVE2, 0); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + case 18: // mflo1 + rpropSetWrite(_Rd_, EEINST_LIVE1); + temp = ((pinst->regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); + rpropSetRead(XMMGPR_LO, temp|EEINST_LIVE2); + break; + case 19: // mtlo1 + rpropSetWrite0(XMMGPR_LO, EEINST_LIVE2, 0); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // mult1 + temp = (pinst->regs[XMMGPR_HI]&(EEINST_LIVE2))?0:(cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0); + rpropSetWrite0(XMMGPR_LO, EEINST_LIVE2, 0); + rpropSetWrite0(XMMGPR_HI, EEINST_LIVE2, 0); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, temp); + rpropSetRead(_Rt_, temp); + pinst->info |= temp; + break; + case 25: // multu1 + rpropSetWrite0(XMMGPR_LO, EEINST_LIVE2, 0); + rpropSetWrite0(XMMGPR_HI, EEINST_LIVE2, 0); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, (cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + rpropSetRead(_Rt_, (cpucaps.hasStreamingSIMD2Extensions?EEINST_MMX:0)); + if( cpucaps.hasStreamingSIMD2Extensions ) pinst->info |= EEINST_MMX; + break; + + case 26: // div1 + case 27: // divu1 + rpropSetWrite0(XMMGPR_LO, EEINST_LIVE2, 0); + rpropSetWrite0(XMMGPR_HI, EEINST_LIVE2, 0); + rpropSetRead(_Rs_, 0); + rpropSetRead(_Rt_, 0); + //pinst->info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 32: // madd1 + case 33: // maddu1 + rpropSetWrite0(XMMGPR_LO, EEINST_LIVE2, 0); + rpropSetWrite0(XMMGPR_HI, EEINST_LIVE2, 0); + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, EEINST_LIVE2); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2); + break; + + case 40: rpropMMI1(prev, pinst); break; + case 41: rpropMMI3(prev, pinst); break; + + case 48: // pmfhl + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 49: // pmthl + rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +//recPADDW, PSUBW, PCGTW, PMAXW, +//PADDH, PSUBH, PCGTH, PMAXH, +//PADDB, PSUBB, PCGTB, NULL, +//NULL, NULL, NULL, NULL, +//PADDSW, PSUBSW, PEXTLW, PPACW, +//PADDSH, PSUBSH, PEXTLH, PPACH, +//PADDSB, PSUBSB, PEXTLB, PPACB, +//NULL, NULL, PEXT5, PPAC5, +void rpropMMI0(EEINST* prev, EEINST* pinst) +{ + switch((cpuRegs.code>>6)&0x1f) { + case 16: // paddsw + case 17: // psubsw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 18: // pextlw + case 22: // pextlh + case 26: // pextlb + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + + case 30: // pext5 + case 31: // ppac5 + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +void rpropMMI1(EEINST* prev, EEINST* pinst) +{ + switch((cpuRegs.code>>6)&0x1f) { + case 1: // pabsw + case 5: // pabsh + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 17: // psubuw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 18: // pextuw + case 22: // pextuh + case 26: // pextub + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +void rpropMMI2(EEINST* prev, EEINST* pinst) +{ + switch((cpuRegs.code>>6)&0x1f) { + case 0: // pmaddw + case 4: // pmsubw + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1, MODE_READ|MODE_WRITE, MODE_READ|MODE_WRITE); + break; + case 2: // psllvw + case 3: // psllvw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); + break; + case 8: // pmfhi + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 9: // pmflo + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 10: // pinth + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 12: // pmultw, + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1, MODE_WRITE, MODE_WRITE); + break; + case 13: // pdivw + rpropSetLOHI(0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1, MODE_WRITE, MODE_WRITE); + break; + case 14: // pcpyld + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 16: // pmaddh + case 17: // phmadh + case 20: // pmsubh + case 21: // phmsbh + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM, MODE_READ|MODE_WRITE, MODE_READ|MODE_WRITE); + break; + + case 26: // pexeh + case 27: // prevh + case 30: // pexew + case 31: // prot3w + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 28: // pmulth + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM, MODE_WRITE, MODE_WRITE); + break; + case 29: // pdivbw + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1, MODE_WRITE, MODE_WRITE); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +void rpropMMI3(EEINST* prev, EEINST* pinst) +{ + switch((cpuRegs.code>>6)&0x1f) { + case 0: // pmadduw + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM, MODE_READ|MODE_WRITE, MODE_READ|MODE_WRITE); + break; + case 3: // psravw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); + break; + + case 8: // pmthi + rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 9: // pmtlo + rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 12: // pmultuw, + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM, MODE_WRITE, MODE_WRITE); + break; + case 13: // pdivuw + rpropSetLOHI(0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1, MODE_WRITE, MODE_WRITE); + break; + case 14: // pcpyud + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); + break; + + case 26: // pexch + case 27: // pcpyh + case 30: // pexcw + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/aR5900-32.S b/pcsx2/x86/ix86-32/aR5900-32.S new file mode 100644 index 0000000000..1e2ae01135 --- /dev/null +++ b/pcsx2/x86/ix86-32/aR5900-32.S @@ -0,0 +1,211 @@ +// iR5900.c assembly routines +// zerofrog(@gmail.com) +.intel_syntax + +.extern cpuRegs +.extern recRecompile +//.extern recLUT +.extern lbase +.extern s_pCurBlock_ltime + +#define BLOCKTYPE_STARTPC 4 // startpc offset +#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot + +#define BASEBLOCK_SIZE 2 // in dwords +#define PCOFFSET 0x2a8 + +#define REG_PC %ecx +#define REG_BLOCK %esi + +.globl Dispatcher +Dispatcher: + # EDX contains the jump addr to modify + push %edx + + # calc PC_GETBLOCK + # ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [cpuRegs + PCOFFSET] + mov REG_BLOCK, %eax + mov REG_PC, %eax + shr %eax, 16 + and REG_BLOCK, 0xffff + shl %eax, 2 + add %eax, dword ptr [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, dword ptr [%eax] + + // check if startpc == cpuRegs.pc + //and %ecx, 0x5fffffff // remove higher bits + cmp REG_PC, dword ptr [REG_BLOCK+BLOCKTYPE_STARTPC] + je Dispatcher_CheckPtr + + // recompile + push REG_BLOCK + push REG_PC // pc + call recRecompile + add %esp, 4 // pop old param + pop REG_BLOCK +Dispatcher_CheckPtr: + mov REG_BLOCK, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test REG_BLOCK, REG_BLOCK + jnz Dispatcher_CallFn + // throw an exception + int 10 + +Dispatcher_CallFn: +#endif + + and REG_BLOCK, 0x0fffffff + mov %edx, REG_BLOCK + pop %ecx // x86Ptr to mod + sub %edx, %ecx + sub %edx, 4 + mov dword ptr [%ecx], %edx + + jmp REG_BLOCK + +.globl DispatcherClear +DispatcherClear: + // EDX contains the current pc + mov dword ptr [cpuRegs + PCOFFSET], %edx + + // calc PC_GETBLOCK + # ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, %edx + mov REG_BLOCK, %edx + shr %eax, 16 + and REG_BLOCK, 0xffff + shl %eax, 2 + add %eax, dword ptr [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, dword ptr [%eax] + + cmp %edx, dword ptr [REG_BLOCK + 4] + jne DispatcherClear_Recompile + + add %esp, 4 // ignore stack + mov %eax, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test %eax, %eax + jnz DispatcherClear_CallFn + # throw an exception + int 10 + +DispatcherClear_CallFn: +#endif + + and %eax, 0x0fffffff + jmp %eax + +DispatcherClear_Recompile: + push REG_BLOCK + push %edx + call recRecompile + add %esp, 4 // pop old param + pop REG_BLOCK + mov %eax, dword ptr [REG_BLOCK] + + pop %ecx // old fnptr + + and %eax, 0x0fffffff + mov byte ptr [%ecx], 0xe9 // jmp32 + mov %edx, %eax + sub %edx, %ecx + sub %edx, 5 + mov dword ptr [%ecx+1], %edx + + jmp %eax + + +// called when jumping to variable pc address +.globl DispatcherReg +DispatcherReg: + + //s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + mov %edx, dword ptr [cpuRegs+PCOFFSET] + mov %ecx, %edx + + shr %edx, 14 + and %edx, 0xfffffffc + add %edx, [recLUT] + mov %edx, dword ptr [%edx] + + mov %eax, %ecx + and %eax, 0xfffc + // %edx += 2*%eax + shl %eax, 1 + add %edx, %eax + + // check if startpc == cpuRegs.pc + mov %eax, %ecx + //and %eax, 0x5fffffff // remove higher bits + cmp %eax, dword ptr [%edx+BLOCKTYPE_STARTPC] + jne DispatcherReg_recomp + + mov %eax, dword ptr [%edx] + +#ifdef _DEBUG + test %eax, %eax + jnz CallFn2 + # throw an exception + int 10 + +CallFn2: + +#endif + + and %eax, 0x0fffffff + jmp %eax // fnptr + +DispatcherReg_recomp: + sub %esp, 8 + mov dword ptr [%esp+4], %edx + mov dword ptr [%esp], %ecx + call recRecompile + mov %edx, dword ptr [%esp+4] + add %esp, 8 + + mov %eax, dword ptr [%edx] + and %eax, 0x0fffffff + jmp %eax // fnptr + + +.globl _StartPerfCounter +_StartPerfCounter: + + push %eax + push %ebx + push %ecx + + rdtsc + mov dword ptr [lbase], %eax + mov dword ptr [lbase + 4], %edx + + pop %ecx + pop %ebx + pop %eax + ret + +.globl _StopPerfCounter +_StopPerfCounter: + + push %eax + push %ebx + push %ecx + + rdtsc + + sub %eax, dword ptr [lbase] + sbb %edx, dword ptr [lbase + 4] + mov %ecx, s_pCurBlock_ltime + add %eax, dword ptr [%ecx] + adc %edx, dword ptr [%ecx + 4] + mov dword ptr [%ecx], %eax + mov dword ptr [%ecx + 4], %edx + pop %ecx + pop %ebx + pop %eax + ret diff --git a/pcsx2/x86/ix86-32/aVif_proc-32.asm b/pcsx2/x86/ix86-32/aVif_proc-32.asm new file mode 100644 index 0000000000..12c8b969b4 --- /dev/null +++ b/pcsx2/x86/ix86-32/aVif_proc-32.asm @@ -0,0 +1,1839 @@ + +.686 +.model flat, c +.mmx +.xmm + + +extern _vifRegs:ptr +extern _vifMaskRegs:ptr +extern _vifRow:ptr +extern s_TempDecompress:ptr + + +.code + +UNPACK_Write0_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [edi+DEST_OFFSET], r0 + endm + +UNPACK_Write1_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [edi], r0 + add edi, ecx + endm + +UNPACK_Write0_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write0_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + +UNPACK_Write1_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write1_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + + +UNPACK_Write0_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + + movdqa xmm3, [eax + 64*(CL) + 48] + pand r0, xmm3 + pandn xmm3, [edi] + por r0, xmm3 + MOVDQA [edi], r0 + add edi, 16 + endm + + +UNPACK_Write1_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + + movdqa xmm3, [eax + 64*(0) + 48] + pand r0, xmm3 + pandn xmm3, [edi] + por r0, xmm3 + MOVDQA [edi], r0 + add edi, ecx + endm + +UNPACK_Mask_SSE_0 macro r0 + pand r0, xmm3 + por r0, xmm5 + endm + + + + +UNPACK_Mask_SSE_1 macro r0 + + pand r0, xmm3 + por r0, xmm5 + pand xmm3, xmm6 + paddd r0, xmm3 + endm + + + +UNPACK_Mask_SSE_2 macro r0 + + + pand r0, xmm3 + pand xmm3, xmm6 + paddd xmm6, r0 + por r0, xmm5 + paddd r0, xmm3 + endm + +UNPACK_WriteMask_SSE_0 macro r0 + UNPACK_Mask_SSE_0 r0 + endm +UNPACK_WriteMask_SSE_1 macro r0 + UNPACK_Mask_SSE_1 r0 + endm +UNPACK_WriteMask_SSE_2 macro r0 + UNPACK_Mask_SSE_2 r0 + endm + +UNPACK_Regular_SSE_0 macro r0 + endm + +UNPACK_Regular_SSE_1 macro r0 + paddd r0, xmm6 + endm + +UNPACK_Regular_SSE_2 macro r0 + paddd r0, xmm6 + movdqa xmm6, r0 + endm + + +UNPACK_Setup_Mask_SSE macro CL + mov eax, [_vifMaskRegs] + movdqa xmm4, [eax + 64*(CL) + 16] + movdqa xmm5, [eax + 64*(CL) + 32] + movdqa xmm3, [eax + 64*(CL)] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Start_Setup_Mask_SSE_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + +UNPACK_Start_Setup_Mask_SSE_1 macro CL + mov eax, [_vifMaskRegs] + movdqa xmm4, [eax + 64*(CL) + 16] + movdqa xmm5, [eax + 64*(CL) + 32] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Start_Setup_Mask_SSE_2 macro CL + endm + +UNPACK_Setup_Mask_SSE_0_1 macro CL + endm +UNPACK_Setup_Mask_SSE_1_1 macro CL + mov eax, [_vifMaskRegs] + movdqa xmm3, [eax + 64*(0)] + endm + + +UNPACK_Setup_Mask_SSE_2_1 macro CL + + mov eax, [_vifMaskRegs] + movdqa xmm4, [eax + 64*(0) + 16] + movdqa xmm5, [eax + 64*(0) + 32] + movdqa xmm3, [eax + 64*(0)] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Setup_Mask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + + +UNPACK_Setup_WriteMask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_0_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_1_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_2_1 macro CL + UNPACK_Setup_Mask_SSE_2_1 CL + endm + +UNPACK_Start_Setup_WriteMask_SSE_0 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_1 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_2 macro CL + UNPACK_Start_Setup_Mask_SSE_2 CL + endm + +UNPACK_Start_Setup_Regular_SSE_0 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_1 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_2 macro CL + endm +UNPACK_Setup_Regular_SSE_0_0 macro CL + endm +UNPACK_Setup_Regular_SSE_1_0 macro CL + endm +UNPACK_Setup_Regular_SSE_2_0 macro CL + endm +UNPACK_Setup_Regular_SSE_0_1 macro CL + endm +UNPACK_Setup_Regular_SSE_1_1 macro CL + endm +UNPACK_Setup_Regular_SSE_2_1 macro CL + endm + +UNPACK_INC_DST_0_Regular macro qw + add edi, (16*qw) + endm +UNPACK_INC_DST_1_Regular macro qw + endm +UNPACK_INC_DST_0_Mask macro qw + add edi, (16*qw) + endm +UNPACK_INC_DST_1_Mask macro qw + endm +UNPACK_INC_DST_0_WriteMask macro qw + endm +UNPACK_INC_DST_1_WriteMask macro qw + endm + + +UNPACK4_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm7 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm7, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + endm + + +UNPACK3_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + endm + +UNPACK2_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 2 + endm + +UNPACK1_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 1 + endm + + + +UNPACK_S_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm7, [esi] + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_S_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm2, [esi] + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_S_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm1, QWORD PTR [esi] + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_S_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_S_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_S_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm7, QWORD PTR [esi] + punpcklwd xmm7, xmm7 + UNPACK_RIGHTSHIFT xmm7, 16 + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_S_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm2, QWORD PTR [esi] + punpcklwd xmm2, xmm2 + UNPACK_RIGHTSHIFT xmm2, 16 + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + add esi, 6 + endm + +UNPACK_S_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm1, dword ptr [esi] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm1, 16 + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_S_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 2 + endm + +UNPACK_S_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_S_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movd xmm7, dword ptr [esi] + punpcklbw xmm7, xmm7 + punpcklwd xmm7, xmm7 + UNPACK_RIGHTSHIFT xmm7, 24 + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_S_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd xmm2, dword ptr [esi] + punpcklbw xmm2, xmm2 + punpcklwd xmm2, xmm2 + UNPACK_RIGHTSHIFT xmm2, 24 + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 3 + endm + +UNPACK_S_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm1, dword ptr [esi] + punpcklbw xmm1, xmm1 + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm1, 24 + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 2 + endm + +UNPACK_S_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + inc esi + endm + +UNPACK_S_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V2_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + MOVDQA xmm0, [esi] + MOVDQA xmm2, [esi+16] + + pshufd xmm1, xmm0, 0eeh + pshufd xmm7, xmm2, 0eeh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V2_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+8] + movq xmm2, QWORD PTR [esi+16] + movq xmm7, QWORD PTR [esi+24] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V2_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + MOVDQA xmm0, [esi] + movq xmm2, QWORD PTR [esi+16] + pshufd xmm1, xmm0, 0eeh + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V2_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+8] + movq xmm2, QWORD PTR [esi+16] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V2_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+8] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V2_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V2_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V2_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + punpckhwd xmm2, [esi] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + add esi, 16 + endm + +UNPACK_V2_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + pxor xmm0, xmm0 + pxor xmm2, xmm2 + movdqu xmm0, [esi] + + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V2_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + punpckhwd xmm2, [esi] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V2_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V2_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + UNPACK_RIGHTSHIFT xmm0, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V2_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V2_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + UNPACK_RIGHTSHIFT xmm0, 16 + + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_V2_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + + +UNPACK_V2_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + + punpcklbw xmm0, xmm0 + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V2_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + + punpcklbw xmm0, xmm0 + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 6 + endm + +UNPACK_V2_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_V2_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 2 + endm + +UNPACK_V2_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V3_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [esi] + movdqu xmm1, [esi+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + + MOVDQA xmm7, [esi+32] + movdqu xmm2, [esi+24] + psrldq xmm7, 4 + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm7 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm7, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + + add esi, 48 + endm + +UNPACK_V3_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [esi] + movdqu xmm1, [esi+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + movdqu xmm2, [esi+24] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + + add esi, 36 + endm + +UNPACK_V3_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_2x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [esi] + movdqu xmm1, [esi+12] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V3_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_1x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [esi] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V3_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqu + endm + + +UNPACK_V3_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+6] + + punpcklwd xmm0, xmm0 + movq xmm2, QWORD PTR [esi+12] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 16 + movq xmm7, QWORD PTR [esi+18] + UNPACK_RIGHTSHIFT xmm1, 16 + punpcklwd xmm2, xmm2 + punpcklwd xmm7, xmm7 + + UNPACK_RIGHTSHIFT xmm2, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V3_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+6] + + punpcklwd xmm0, xmm0 + movq xmm2, QWORD PTR [esi+12] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 16 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 18 + endm + +UNPACK_V3_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+6] + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V3_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 6 + endm + +UNPACK_V3_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V3_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm1, QWORD PTR [esi] + movq xmm7, QWORD PTR [esi+6] + + punpcklbw xmm1, xmm1 + punpcklbw xmm7, xmm7 + punpcklwd xmm0, xmm1 + psrldq xmm1, 6 + punpcklwd xmm2, xmm7 + psrldq xmm7, 6 + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 24 + punpcklwd xmm7, xmm7 + + UNPACK_RIGHTSHIFT xmm2, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm7, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V3_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + movd xmm1, dword ptr [esi+3] + + punpcklbw xmm0, xmm0 + movd xmm2, dword ptr [esi+6] + punpcklbw xmm1, xmm1 + punpcklwd xmm0, xmm0 + punpcklbw xmm2, xmm2 + + punpcklwd xmm1, xmm1 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 9 + endm + +UNPACK_V3_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + movd xmm1, dword ptr [esi+3] + + punpcklbw xmm0, xmm0 + punpcklbw xmm1, xmm1 + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 6 + endm + +UNPACK_V3_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 3 + endm + +UNPACK_V3_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V4_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [esi] + movdqa xmm1, [esi+16] + movdqa xmm2, [esi+32] + movdqa xmm7, [esi+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 64 + endm + +UNPACK_V4_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + movdqu xmm1, [esi+16] + movdqu xmm2, [esi+32] + movdqu xmm7, [esi+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 64 + endm + +UNPACK_V4_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [esi] + movdqa xmm1, [esi+16] + movdqa xmm2, [esi+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 48 + endm + +UNPACK_V4_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + movdqu xmm1, [esi+16] + movdqu xmm2, [esi+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 48 + endm + +UNPACK_V4_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [esi] + movdqa xmm1, [esi+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V4_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + movdqu xmm1, [esi+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V4_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [esi] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V4_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + + +UNPACK_V4_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + + punpcklwd xmm0, [esi] + punpckhwd xmm1, [esi] + punpcklwd xmm2, [esi+16] + punpckhwd xmm7, [esi+16] + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V4_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + movdqu xmm2, [esi+16] + + punpckhwd xmm1, xmm0 + punpckhwd xmm7, xmm2 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 32 + endm + +UNPACK_V4_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + punpckhwd xmm1, [esi] + punpcklwd xmm2, [esi+16] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V4_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + movq xmm2, QWORD PTR [esi+16] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 24 + endm + +UNPACK_V4_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + punpckhwd xmm1, [esi] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V4_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movq xmm1, QWORD PTR [esi+8] + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V4_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [esi] + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V4_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + + +UNPACK_V4_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [esi] + punpckhbw xmm2, [esi] + + punpckhwd xmm1, xmm0 + punpckhwd xmm7, xmm2 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm7, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V4_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [esi] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm7, xmm2 + punpckhwd xmm1, xmm0 + punpcklwd xmm2, xmm2 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm7, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 16 + endm + +UNPACK_V4_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [esi] + punpckhbw xmm2, [esi] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V4_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + movd xmm2, dword ptr [esi+8] + + punpcklbw xmm0, xmm0 + punpcklbw xmm2, xmm2 + + punpckhwd xmm1, xmm0 + punpcklwd xmm2, xmm2 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 12 + endm + +UNPACK_V4_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [esi] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V4_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [esi] + + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V4_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [esi] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_V4_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [esi] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + + +DECOMPRESS_RGBA macro OFFSET + mov bl, al + shl bl, 3 + mov byte ptr [s_TempDecompress+OFFSET], bl + + mov bx, ax + shr bx, 2 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+1], bl + + mov bx, ax + shr bx, 7 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+2], bl + mov bx, ax + shr bx, 8 + and bx, 080h + mov byte ptr [s_TempDecompress+OFFSET+3], bl + endm + +UNPACK_V4_5SSE_4 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [esi] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [esi+4] + DECOMPRESS_RGBA 8 + + shr eax, 16 + DECOMPRESS_RGBA 12 + + ;; have to use movaps instead of movdqa + movaps xmm0, [s_TempDecompress] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm7, xmm2 + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + psrld xmm0, 24 + psrld xmm1, 24 + psrld xmm2, 24 + psrld xmm7, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 8 + endm + +UNPACK_V4_5SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_3 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [esi] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [esi] + DECOMPRESS_RGBA 8 + + ;; have to use movaps instead of movdqa + movaps xmm0, [s_TempDecompress] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + psrld xmm0, 24 + psrld xmm1, 24 + psrld xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 6 + endm + +UNPACK_V4_5SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_2 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [esi] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + movq xmm0, QWORD PTR [s_TempDecompress] + + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + psrld xmm0, 24 + psrld xmm1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 4 + endm + +UNPACK_V4_5SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_1 macro CL, TOTALCL, MaskType, ModeType + mov ax, word ptr [esi] + DECOMPRESS_RGBA 0 + + movd xmm0, DWORD PTR [s_TempDecompress] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + + psrld xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add esi, 2 + endm + +UNPACK_V4_5SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +SAVE_ROW_REG_BASE macro + mov eax, [_vifRow] + movdqa [eax], xmm6 + mov eax, [_vifRegs] + movss dword ptr [eax+0100h], xmm6 + psrldq xmm6, 4 + movss dword ptr [eax+0110h], xmm6 + psrldq xmm6, 4 + movss dword ptr [eax+0120h], xmm6 + psrldq xmm6, 4 + movss dword ptr [eax+0130h], xmm6 + endm + +SAVE_NO_REG macro + endm + +INIT_ARGS macro + mov edi, dword ptr [esp+4+12] + mov esi, dword ptr [esp+8+12] + mov edx, dword ptr [esp+12+12] + endm + +INC_STACK macro reg + add esp, 4 + endm + + + + + +defUNPACK_SkippingWrite macro name, MaskType, ModeType, qsize, sign, SAVE_ROW_REG +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType) proc public + push edi + push esi + push ebx + + INIT_ARGS + mov eax, [_vifRegs] + movzx ecx, byte ptr [eax + 040h] + movzx ebx, byte ptr [eax + 041h] + sub ecx, ebx + shl ecx, 4 + + cmp ebx, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1) + cmp ebx, 2 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2) + cmp ebx, 3 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1): + @CatStr(UNPACK_Start_Setup_, MaskType, _SSE_, ModeType) 0 + + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + + add ecx, 16 + + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16): + + test esi, 15 + jz @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned) + + @CatStr(UNPACK_, name, SSE_1) 0, 1, MaskType, ModeType + + cmp edx, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec) + sub edx, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned): + + cmp edx, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp edx, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + cmp edx, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3) + prefetchnta [esi + 64] + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4): + @CatStr(UNPACK_, name, SSE_4A) 0, 1, MaskType, ModeType + + cmp edx, (8*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4) + sub edx, (4*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4): + + sub edx, (4*qsize) + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + cmp edx, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp edx, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3): + @CatStr(UNPACK_, name, SSE_3A) 0, 1, MaskType, ModeType + + sub edx, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2): + @CatStr(UNPACK_, name, SSE_2A) 0, 1, MaskType, ModeType + + sub edx, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1): + @CatStr(UNPACK_, name, SSE_1A) 0, 1, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec): + sub edx, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3): + SAVE_ROW_REG + mov eax, edx + pop ebx + pop esi + pop edi + + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2): + cmp edx, (2*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + + add edi, ecx + cmp edx, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2) + sub edx, (2*qsize) + + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2): + sub edx, (2*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3): + cmp edx, qsize + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4) + + + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + sub edx, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4): + + SAVE_ROW_REG + mov eax, edx + pop ebx + pop esi + pop edi + + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3): + cmp edx, (3*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + add edi, ecx + cmp edx, (6*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2) + sub edx, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2): + sub edx, (3*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5): + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) + + cmp edx, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3) + + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + sub edx, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3): + sub edx, qsize + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4): + SAVE_ROW_REG + mov eax, edx + pop ebx + pop esi + pop edi + + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4): + sub ebx, 3 + push ecx + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack): + cmp edx, (3*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3) + cmp edx, (2*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2) + + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + + sub edx, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + + sub edx, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + + sub edx, (3*qsize) + mov ecx, ebx + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX): + + + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + + @CatStr(UNPACK_, name, SSE_1) 3, 0, MaskType, ModeType + + sub edx, qsize + cmp ecx, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop) + sub ecx, 1 + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop): + add edi, [esp] + cmp edx, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done): + + SAVE_ROW_REG + INC_STACK() + mov eax, edx + pop ebx + pop esi + pop edi + + ret +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType endp) +endm + +UNPACK_RIGHTSHIFT macro reg, shift + psrld reg, shift + endm + +defUNPACK_SkippingWrite2 macro name, qsize + defUNPACK_SkippingWrite name, Regular, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, u, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2 S_32, 4 +defUNPACK_SkippingWrite2 S_16, 2 +defUNPACK_SkippingWrite2 S_8, 1 +defUNPACK_SkippingWrite2 V2_32, 8 +defUNPACK_SkippingWrite2 V2_16, 4 +defUNPACK_SkippingWrite2 V2_8, 2 +defUNPACK_SkippingWrite2 V3_32, 12 +defUNPACK_SkippingWrite2 V3_16, 6 +defUNPACK_SkippingWrite2 V3_8, 3 +defUNPACK_SkippingWrite2 V4_32, 16 +defUNPACK_SkippingWrite2 V4_16, 8 +defUNPACK_SkippingWrite2 V4_8, 4 +defUNPACK_SkippingWrite2 V4_5, 2 + +UNPACK_RIGHTSHIFT macro reg, shift + psrad reg, shift + endm + + +defUNPACK_SkippingWrite2a macro name, qsize + defUNPACK_SkippingWrite name, Mask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, s, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2a S_16, 2 +defUNPACK_SkippingWrite2a S_8, 1 +defUNPACK_SkippingWrite2a V2_16, 4 +defUNPACK_SkippingWrite2a V2_8, 2 +defUNPACK_SkippingWrite2a V3_16, 6 +defUNPACK_SkippingWrite2a V3_8, 3 +defUNPACK_SkippingWrite2a V4_16, 8 +defUNPACK_SkippingWrite2a V4_8, 4 + +end diff --git a/pcsx2/x86/ix86-32/iCore-32.cpp b/pcsx2/x86/ix86-32/iCore-32.cpp new file mode 100644 index 0000000000..7bf2fd17e4 --- /dev/null +++ b/pcsx2/x86/ix86-32/iCore-32.cpp @@ -0,0 +1,1227 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include +#include + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_WIN32) +#include +#endif + +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "iCore.h" +#include "R3000A.h" + +u16 x86FpuState, iCWstate; +u16 g_mmxAllocCounter = 0; + +// used to make sure regs don't get changed while in recompiler +// use FreezeMMXRegs, FreezeXMMRegs +u8 g_globalMMXSaved = 0; + +#ifdef _DEBUG +char g_globalMMXLocked = 0; +#endif + +PCSX2_ALIGNED16(u64 g_globalMMXData[8]); + +// X86 caching +extern _x86regs x86regs[X86REGS]; +int g_x86checknext; +extern u16 g_x86AllocCounter; + +} // end extern "C" + +#include +using namespace std; + +// use special x86 register allocation for ia32 +#ifndef __x86_64__ + +void _initX86regs() { + memset(x86regs, 0, sizeof(x86regs)); + g_x86AllocCounter = 0; + g_x86checknext = 0; +} + +u32 _x86GetAddr(int type, int reg) +{ + switch(type&~X86TYPE_VU1) { + case X86TYPE_GPR: return (u32)&cpuRegs.GPR.r[reg]; + case X86TYPE_VI: { + //assert( reg < 16 || reg == REG_R ); + return (type&X86TYPE_VU1)?(u32)&VU1.VI[reg]:(u32)&VU0.VI[reg]; + } + case X86TYPE_MEMOFFSET: return 0; + case X86TYPE_VIMEMOFFSET: return 0; + case X86TYPE_VUQREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_Q]:(u32)&VU0.VI[REG_Q]; + case X86TYPE_VUPREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_P]:(u32)&VU0.VI[REG_P]; + case X86TYPE_VUQWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.q:(u32)&VU0.q; + case X86TYPE_VUPWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.p:(u32)&VU0.p; + case X86TYPE_PSX: return (u32)&psxRegs.GPR.r[reg]; + case X86TYPE_PCWRITEBACK: + return (u32)&g_recWriteback; + case X86TYPE_VUJUMP: + return (u32)&g_recWriteback; + default: assert(0); + } + + return 0; +} + +int _getFreeX86reg(int mode) +{ + int i, tempi; + u32 bestcount = 0x10000; + + int maxreg = (mode&MODE_8BITREG)?4:X86REGS; + + for (i=0; i= maxreg ) continue; + if( (mode&MODE_NOFRAME) && reg==EBP ) continue; + + if (x86regs[reg].inuse == 0) { + g_x86checknext = (reg+1)%X86REGS; + return reg; + } + } + + tempi = -1; + for (i=1; i= 0 && reg < 32 ); + +// if( X86_ISVI(type) ) +// assert( reg < 16 || reg == REG_R ); + + // don't alloc EAX and ESP,EBP if MODE_NOFRAME + int oldmode = mode; + int noframe = mode&MODE_NOFRAME; + int maxreg = (mode&MODE_8BITREG)?4:X86REGS; + mode &= ~(MODE_NOFRAME|MODE_8BITREG); + int readfromreg = -1; + + if( type != X86TYPE_TEMP ) { + + if( maxreg < X86REGS ) { + // make sure reg isn't in the higher regs + + for(i = maxreg; i < X86REGS; ++i) { + if (!x86regs[i].inuse || x86regs[i].type != type || x86regs[i].reg != reg) continue; + + if( mode & MODE_READ ) { + readfromreg = i; + x86regs[i].inuse = 0; + break; + } + else if( mode & MODE_WRITE ) { + x86regs[i].inuse = 0; + break; + } + } + } + + for (i=1; i= maxreg) ) { + if( x86regs[i].mode & MODE_READ ) + readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= x86regs[i].mode&MODE_WRITE; + x86regs[i].inuse = 0; + break; + } + + if( x86reg >= 0 ) { + // requested specific reg, so return that instead + if( i != x86reg ) { + if( x86regs[i].mode & MODE_READ ) readfromreg = i; + //if( x86regs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= x86regs[i].mode&MODE_WRITE; + x86regs[i].inuse = 0; + break; + } + } + + if( type != X86TYPE_TEMP && !(x86regs[i].mode & MODE_READ) && (mode&MODE_READ)) { + + if( type == X86TYPE_GPR ) _flushConstReg(reg); + + if( X86_ISVI(type) && reg < 16 ) MOVZX32M16toR(i, _x86GetAddr(type, reg)); + else MOV32MtoR(i, _x86GetAddr(type, reg)); + + x86regs[i].mode |= MODE_READ; + } + + x86regs[i].needed = 1; + x86regs[i].mode|= mode; + return i; + } + } + + if (x86reg == -1) { + x86reg = _getFreeX86reg(oldmode); + } + else { + _freeX86reg(x86reg); + } + + x86regs[x86reg].type = type; + x86regs[x86reg].reg = reg; + x86regs[x86reg].mode = mode; + x86regs[x86reg].needed = 1; + x86regs[x86reg].inuse = 1; + + if( mode & MODE_READ ) { + if( readfromreg >= 0 ) MOV32RtoR(x86reg, readfromreg); + else { + if( type == X86TYPE_GPR ) { + + if( reg == 0 ) { + XOR32RtoR(x86reg, x86reg); + } + else { + _flushConstReg(reg); + _deleteMMXreg(MMX_GPR+reg, 1); + _deleteGPRtoXMMreg(reg, 1); + + _eeMoveGPRtoR(x86reg, reg); + + _deleteMMXreg(MMX_GPR+reg, 0); + _deleteGPRtoXMMreg(reg, 0); + } + } + else { + if( X86_ISVI(type) && reg < 16 ) { + if( reg == 0 ) XOR32RtoR(x86reg, x86reg); + else MOVZX32M16toR(x86reg, _x86GetAddr(type, reg)); + } + else MOV32MtoR(x86reg, _x86GetAddr(type, reg)); + } + } +} + + return x86reg; +} + +int _checkX86reg(int type, int reg, int mode) +{ + int i; + + for (i=0; i= 0 && x86reg < X86REGS ); + + if( x86regs[x86reg].inuse && (x86regs[x86reg].mode&MODE_WRITE) ) { + x86regs[x86reg].mode &= ~MODE_WRITE; + + if( X86_ISVI(x86regs[x86reg].type) && x86regs[x86reg].reg < 16 ) { + MOV16RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + } + else + MOV32RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + } + + x86regs[x86reg].inuse = 0; +} + +void _freeX86regs() { + int i; + + for (i=0; i= MMX_GPR && reg < MMX_GPR+32 ) return &cpuRegs.GPR.r[reg&31]; + if( reg >= MMX_FPU && reg < MMX_FPU+32 ) return &fpuRegs.fpr[reg&31]; + if( reg >= MMX_COP0 && reg < MMX_COP0+32 ) return &cpuRegs.CP0.r[reg&31]; + + assert( 0 ); + return NULL; +} + +int _getFreeMMXreg() +{ + int i, tempi; + u32 bestcount = 0x10000; + + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR] & (EEINST_LIVE0|EEINST_LIVE1)) ) { + _freeMMXreg(i); + return i; + } + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + _freeMMXreg(i); + return i; + } + } + } + + // check for future xmm usage + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg] & EEINST_MMX) ) { + _freeMMXreg(i); + return i; + } + } + } + + tempi = -1; + for (i=0; i= 0 ) { + if (cpucaps.hasStreamingSIMD2Extensions) { + SSE_MOVHPS_XMM_to_M64((u32)_MMXGetAddr(reg)+8, xmmreg); + if( mode & MODE_READ ) + SSE2_MOVDQ2Q_XMM_to_MM(mmxreg, xmmreg); + + if( xmmregs[xmmreg].mode & MODE_WRITE ) + mmxregs[mmxreg].mode |= MODE_WRITE; + + // don't flush + xmmregs[xmmreg].inuse = 0; + } + else { + _freeXMMreg(xmmreg); + + if( (mode & MODE_READHALF) || (MMX_IS32BITS(reg)&&(mode&MODE_READ)) ) { + MOVDMtoMMX(mmxreg, (u32)_MMXGetAddr(reg)); + } + else if( mode & MODE_READ ) { + MOVQMtoR(mmxreg, (u32)_MMXGetAddr(reg)); + } + + } + } + else { + if( MMX_ISGPR(reg) ) { + if(mode&(MODE_READHALF|MODE_READ)) _flushConstReg(reg-MMX_GPR); + } + + if( (mode & MODE_READHALF) || (MMX_IS32BITS(reg)&&(mode&MODE_READ)) ) { + MOVDMtoMMX(mmxreg, (u32)_MMXGetAddr(reg)); + } + else if( mode & MODE_READ ) { + MOVQMtoR(mmxreg, (u32)_MMXGetAddr(reg)); + } + } + } + + return mmxreg; +} + +int _checkMMXreg(int reg, int mode) +{ + int i; + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !EEINST_ISLIVE64(mmxregs[i].reg-MMX_GPR) ) { + return 1; + } + } + } + + // check for dead regs + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + return 1; + } + } + } + + return 0; +} + +void _freeMMXreg(int mmxreg) +{ + assert( mmxreg < MMXREGS ); + if (!mmxregs[mmxreg].inuse) return; + + if (mmxregs[mmxreg].mode & MODE_WRITE ) { + + if( mmxregs[mmxreg].reg >= MMX_GPR && mmxregs[mmxreg].reg < MMX_GPR+32 ) + assert( !(g_cpuHasConstReg & (1<<(mmxregs[mmxreg].reg-MMX_GPR))) ); + + assert( mmxregs[mmxreg].reg != MMX_GPR ); + + if( MMX_IS32BITS(mmxregs[mmxreg].reg) ) + MOVDMMXtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); + else + MOVQRtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); + + SetMMXstate(); + } + + mmxregs[mmxreg].mode &= ~MODE_WRITE; + mmxregs[mmxreg].inuse = 0; +} + +void _moveMMXreg(int mmxreg) +{ + int i; + if( !mmxregs[mmxreg].inuse ) return; + + for (i=0; i>16)&0x1f].UL[0]); + } + else if( IS_PSXCONSTREG(arg) ) { + PUSH32I(g_psxConstRegs[(arg>>16)&0x1f]); + } + else if( IS_MEMORYREG(arg) ) PUSH32M(argmem); + else { + assert( (arg&0xfff0) == 0 ); + // assume it is a GPR reg + PUSH32R(arg&0xf); + } +} + +void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem) +{ + _callPushArg(arg1, arg1mem, -1); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 4); +} + +void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem) +{ + _callPushArg(arg2, arg2mem, -1); + _callPushArg(arg1, arg1mem, -1); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 8); +} + +void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem) +{ + _callPushArg(arg3, arg3mem, -1); + _callPushArg(arg2, arg2mem, -1); + _callPushArg(arg1, arg1mem, -1); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 12); +} + +// EE +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoR( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { + SSE2_MOVD_XMM_to_R(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE) ) { + MOVD32MMXtoR(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(to, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + } + } +} + +void _eeMoveGPRtoM(u32 to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_M32(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVDMMXtoM(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoM(to, EAX ); + } + } +} + +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoRmOffset( to, g_cpuConstRegs[fromgpr].UL[0], 0 ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_Rm(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVD32MMXtoRm(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoRm(to, EAX ); + } + } +} + +void _recPushReg(int mmreg) +{ + if( IS_XMMREG(mmreg) ) { + SUB32ItoR(ESP, 4); + SSEX_MOVD_XMM_to_Rm(ESP, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + SUB32ItoR(ESP, 4); + MOVD32MMXtoRm(ESP, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + PUSH32I(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + PUSH32I(g_psxConstRegs[(mmreg>>16)&0x1f]); + } + else { + assert( (mmreg&0xfff0) == 0 ); + PUSH32R(mmreg); + } +} + +void _signExtendSFtoM(u32 mem) +{ + LAHF(); + SAR16ItoR(EAX, 15); + CWDE(); + MOV32RtoM(mem, EAX ); +} + +int _signExtendMtoMMX(x86MMXRegType to, u32 mem) +{ + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVDMtoMMX(t0reg, mem); + MOVQRtoR(to, t0reg); + PSRADItoR(t0reg, 31); + PUNPCKLDQRtoR(to, t0reg); + _freeMMXreg(t0reg); + return to; +} + +int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg) +{ + assert( to >= 0 && from >= 0 ); + if( !EEINST_ISLIVE1(gprreg) ) { + EEINST_RESETHASLIVE1(gprreg); + if( to != from ) MOVQRtoR(to, from); + return to; + } + + if( to == from ) return _signExtendGPRtoMMX(to, gprreg, 0); + if( !(g_pCurInstInfo->regs[gprfromreg]&EEINST_LASTUSE) ) { + if( EEINST_ISLIVE64(gprfromreg) ) { + MOVQRtoR(to, from); + return _signExtendGPRtoMMX(to, gprreg, 0); + } + } + + // from is free for use + SetMMXstate(); + + if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { + + if( EEINST_ISLIVE64(gprfromreg) ) { + _freeMMXreg(from); + } + + MOVQRtoR(to, from); + PSRADItoR(from, 31); + PUNPCKLDQRtoR(to, from); + return to; + } + else { + MOVQRtoR(to, from); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], from); + PSRADItoR(from, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], from); + mmxregs[to].inuse = 0; + return -1; + } + + assert(0); +} + +int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift) +{ + assert( to >= 0 && shift >= 0 ); + if( !EEINST_ISLIVE1(gprreg) ) { + if( shift > 0 ) PSRADItoR(to, shift); + EEINST_RESETHASLIVE1(gprreg); + return to; + } + + SetMMXstate(); + + if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, to); + PSRADItoR(to, 31); + if( shift > 0 ) PSRADItoR(t0reg, shift); + PUNPCKLDQRtoR(t0reg, to); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[to]; + mmxregs[to].inuse = 0; + return t0reg; + } + else { + // will be used in the future as mmx + if( shift > 0 ) PSRADItoR(to, shift); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); + PSRADItoR(to, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); + + // read again + MOVQMtoR(to, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); + mmxregs[to].mode &= ~MODE_WRITE; + return to; + } + } + else { + if( shift > 0 ) PSRADItoR(to, shift); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); + PSRADItoR(to, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); + mmxregs[to].inuse = 0; + return -1; + } + + assert(0); +} + +int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode) +{ + if( pinst->regs[reg] & EEINST_MMX ) return _allocMMXreg(-1, MMX_GPR+reg, mode); + + return _checkMMXreg(MMX_GPR+reg, mode); +} + +void _recMove128MtoM(u32 to, u32 from) +{ + MOV32MtoR(EAX, from); + MOV32MtoR(EDX, from+4); + MOV32RtoM(to, EAX); + MOV32RtoM(to+4, EDX); + MOV32MtoR(EAX, from+8); + MOV32MtoR(EDX, from+12); + MOV32RtoM(to+8, EAX); + MOV32RtoM(to+12, EDX); +} + +void _recMove128RmOffsettoM(u32 to, u32 offset) +{ + MOV32RmtoROffset(EAX, ECX, offset); + MOV32RmtoROffset(EDX, ECX, offset+4); + MOV32RtoM(to, EAX); + MOV32RtoM(to+4, EDX); + MOV32RmtoROffset(EAX, ECX, offset+8); + MOV32RmtoROffset(EDX, ECX, offset+12); + MOV32RtoM(to+8, EAX); + MOV32RtoM(to+12, EDX); +} + +void _recMove128MtoRmOffset(u32 offset, u32 from) +{ + MOV32MtoR(EAX, from); + MOV32MtoR(EDX, from+4); + MOV32RtoRmOffset(ECX, EAX, offset); + MOV32RtoRmOffset(ECX, EDX, offset+4); + MOV32MtoR(EAX, from+8); + MOV32MtoR(EDX, from+12); + MOV32RtoRmOffset(ECX, EAX, offset+8); + MOV32RtoRmOffset(ECX, EDX, offset+12); +} + +static PCSX2_ALIGNED16(u32 s_ones[2]) = {0xffffffff, 0xffffffff}; + +void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op) +{ + switch(op) { + case 0: PANDRtoR(to, from); break; + case 1: PORRtoR(to, from); break; + case 2: PXORRtoR(to, from); break; + case 3: + PORRtoR(to, from); + PXORMtoR(to, (u32)&s_ones[0]); + break; + } +} + +void LogicalOpMtoR(x86MMXRegType to, u32 from, int op) +{ + switch(op) { + case 0: PANDMtoR(to, from); break; + case 1: PORMtoR(to, from); break; + case 2: PXORMtoR(to, from); break; + case 3: + PORRtoR(to, from); + PXORMtoR(to, (u32)&s_ones[0]); + break; + } +} + +void LogicalOp32RtoM(u32 to, x86IntRegType from, int op) +{ + switch(op) { + case 0: AND32RtoM(to, from); break; + case 1: OR32RtoM(to, from); break; + case 2: XOR32RtoM(to, from); break; + case 3: OR32RtoM(to, from); break; + } +} + +void LogicalOp32MtoR(x86IntRegType to, u32 from, int op) +{ + switch(op) { + case 0: AND32MtoR(to, from); break; + case 1: OR32MtoR(to, from); break; + case 2: XOR32MtoR(to, from); break; + case 3: OR32MtoR(to, from); break; + } +} + +void LogicalOp32ItoR(x86IntRegType to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoR(to, from); break; + case 1: OR32ItoR(to, from); break; + case 2: XOR32ItoR(to, from); break; + case 3: OR32ItoR(to, from); break; + } +} + +void LogicalOp32ItoM(u32 to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoM(to, from); break; + case 1: OR32ItoM(to, from); break; + case 2: XOR32ItoM(to, from); break; + case 3: OR32ItoM(to, from); break; + } +} diff --git a/pcsx2/x86/ix86-32/iR5900-32.c b/pcsx2/x86/ix86-32/iR5900-32.c new file mode 100644 index 0000000000..f3bf4195b6 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900-32.c @@ -0,0 +1,3323 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 +// Recompiled completely rewritten to add block level recompilation/reg-caching/ +// liveness analysis/constant propagation Apr06 (zerofrog@gmail.com) + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +#include "Common.h" +#include "Memory.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iR5900AritImm.h" +#include "iR5900Arit.h" +#include "iR5900MultDiv.h" +#include "iR5900Shift.h" +#include "iR5900Branch.h" +#include "iR5900Jump.h" +#include "iR5900LoadStore.h" +#include "iR5900Move.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" +#include "iVUmicro.h" +#include "iVU0micro.h" +#include "iVU1micro.h" +#include "VU.h" +#include "VUmicro.h" + +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +u32 maxrecmem = 0; +uptr *recLUT; + +#define X86 +#define RECSTACK_SIZE 0x00010000 + +#define EE_NUMBLOCKS (1<<15) + +static char *recMem = NULL; // the recompiled blocks will be here +static char* recStack = NULL; // stack mem +static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here +static BASEBLOCK *recROM = NULL; // and here +static BASEBLOCK *recROM1 = NULL; // also here +static BASEBLOCKEX *recBlocks = NULL; +static char *recPtr = NULL, *recStackPtr = NULL; +static EEINST* s_pInstCache = NULL; +static u32 s_nInstCacheSize = 0; + +u32 g_EEFreezeRegs = 0; // if set, should freeze the regs + +static BASEBLOCK* s_pCurBlock = NULL; +static BASEBLOCKEX* s_pCurBlockEx = NULL; +static BASEBLOCK* s_pDispatchBlock = NULL; +static u32 s_nEndBlock = 0; // what pc the current block ends +static u32 s_nHasDelay = 0; + +static u32 s_nNextBlock = 0; // next free block in recBlocks + +extern void (*recBSC[64])(); +extern void (*recBSC_co[64])(); +void rpropBSC(EEINST* prev, EEINST* pinst); + +// save states for branches +static u16 s_savex86FpuState, s_saveiCWstate; +static GPR_reg64 s_ConstGPRreg; +static u32 s_saveConstGPRreg = 0, s_saveHasConstReg = 0, s_saveFlushedConstReg = 0, s_saveRegHasLive1 = 0, s_saveRegHasSignExt = 0; +static EEINST* s_psaveInstInfo = NULL; + +u32 s_nBlockCycles = 0; // cycles of current block recompiling +static u32 s_savenBlockCycles = 0; + +void recCOP2RecompileInst(); +int recCOP2AnalyzeBlock(u32 startpc, u32 endpc); +void recCOP2EndBlock(void); + +#ifdef _DEBUG +u32 dumplog = 0; +#else +#define dumplog 0 +#endif + +u32 pc; // recompiler pc +int branch; // set for branch + +//#ifdef PCSX2_DEVBUILD +LARGE_INTEGER lbase = {0}, lfinal = {0}; +static u32 s_startcount = 0; +//#endif + +char *txt0 = "EAX = %x : ECX = %x : EDX = %x\n"; +char *txt0RC = "EAX = %x : EBX = %x : ECX = %x : EDX = %x : ESI = %x : EDI = %x\n"; +char *txt1 = "REG[%d] = %x_%x\n"; +char *txt2 = "M32 = %x\n"; + +void _cop2AnalyzeOp(EEINST* pinst, int dostalls); // reccop2.c +static void iBranchTest(u32 newpc, u32 cpuBranch); +void recRecompile( u32 startpc ); +void recCOP22( void ); + +BASEBLOCKEX* PC_GETBLOCKEX(BASEBLOCK* p) +{ +// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); +// if( pex >= recBlocks && pex < recBlocks+EE_NUMBLOCKS ) +// return pex; + + // otherwise, use the sorted list + return GetBaseBlockEx(p->startpc, 0); +} + +//////////////////////////////////////////////////// +void iDumpBlock( int startpc, char * ptr ) +{ + FILE *f; + char filename[ 256 ]; + u32 i, j; + EEINST* pcur; + extern char *disRNameGPR[]; + u8 used[34]; + u8 fpuused[33]; + int numused, count, fpunumused; + + SysPrintf( "dump1 %x:%x, %x\n", startpc, pc, cpuRegs.cycle ); +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf( filename, "dumps\\dump%.8X.txt", startpc); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/dump%.8X.txt", startpc); +#endif + + fflush( stdout ); +// f = fopen( "dump1", "wb" ); +// fwrite( ptr, 1, (u32)x86Ptr - (u32)ptr, f ); +// fclose( f ); +// +// sprintf( command, "objdump -D --target=binary --architecture=i386 dump1 > %s", filename ); +// system( command ); + + f = fopen( filename, "w" ); + + if( disR5900GetSym(startpc) != NULL ) + fprintf(f, "%s\n", disR5900GetSym(startpc)); + for ( i = startpc; i < s_nEndBlock; i += 4 ) { + fprintf( f, "%s\n", disR5900Fasm( PSMu32( i ), i ) ); + } + + // write the instruction info + + fprintf(f, "\n\nlive0 - %x, live1 - %x, live2 - %x, lastuse - %x\nmmx - %x, xmm - %x, used - %x\n", + EEINST_LIVE0, EEINST_LIVE1, EEINST_LIVE2, EEINST_LASTUSE, EEINST_MMX, EEINST_XMM, EEINST_USED); + + memset(used, 0, sizeof(used)); + numused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( s_pInstCache->regs[i] & EEINST_USED ) { + used[i] = 1; + numused++; + } + } + + memset(fpuused, 0, sizeof(fpuused)); + fpunumused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( s_pInstCache->fpuregs[i] & EEINST_USED ) { + fpuused[i] = 1; + fpunumused++; + } + } + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%2d ", i); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%2d ", i); + } + fprintf(f, "\n"); + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%s ", i<32?"FR":"FA"); + } + fprintf(f, "\n"); + + pcur = s_pInstCache+1; + for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { + fprintf(f, "%2d: %2.2x ", i+1, pcur->info); + + count = 1; + for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { + if( used[j] ) { + fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&countfpuregs); j++) { + if( fpuused[j] ) { + fprintf(f, "%2.2x%s", pcur->fpuregs[j], ((count%8)&&count>26) { + case 26: // ldl + case 27: // ldr + case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: + case 55: // LD + case 30: // lq + return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt + } + return 0; +} + +u8 _eeIsLoadStoreCoIssue(u32 firstcode, u32 secondcode) +{ + switch(firstcode>>26) { + case 34: // lwl + return (secondcode>>26)==38; + case 38: // lwr + return (secondcode>>26)==34; + case 42: // swl + return (secondcode>>26)==46; + case 46: // swr + return (secondcode>>26)==42; + case 26: // ldl + return (secondcode>>26)==27; + case 27: // ldr + return (secondcode>>26)==26; + case 44: // sdl + return (secondcode>>26)==45; + case 45: // sdr + return (secondcode>>26)==44; + + case 32: case 33: case 35: case 36: case 37: case 39: + case 55: // LD + + // stores + case 40: case 41: case 43: + case 63: // sd + return (secondcode>>26)==(firstcode>>26); + + case 30: // lq + case 31: // sq + case 49: // lwc1 + case 57: // swc1 + case 54: // lqc2 + case 62: // sqc2 + return (secondcode>>26)==(firstcode>>26)&&cpucaps.hasStreamingSIMDExtensions; + } + return 0; +} + +u8 _eeIsLoadStoreCoX(u32 tempcode) +{ + switch( tempcode>>26 ) { + case 30: case 31: case 49: case 57: case 55: case 63: + return 1; + } + return 0; +} + +void _eeFlushAllUnused() +{ + int i; + for(i = 0; i < 34; ++i) { + if( pc < s_nEndBlock ) { + if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) + continue; + } + else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) + continue; + + if( i < 32 && GPR_IS_CONST1(i) ) _flushConstReg(i); + else { + _deleteMMXreg(MMX_GPR+i, 1); + _deleteGPRtoXMMreg(i, 1); + } + } + + //TODO when used info is done for FPU and VU0 + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse && xmmregs[i].type != XMMTYPE_GPRREG ) + _freeXMMreg(i); + } +} + +u32* _eeGetConstReg(int reg) +{ + assert( GPR_IS_CONST1( reg ) ); + + if( g_cpuFlushedConstReg & (1<regs[xmmregs[i].reg]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, xmmregs[i].reg) ) { + _freeXMMreg(i); + xmmregs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushMMXunused() +{ + int i; + for (i=0; iregs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR) ) { + _freeMMXreg(i); + mmxregs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushUnusedConstReg() +{ + int i; + for(i = 1; i < 32; ++i) { + if( (g_cpuHasConstReg & (1<regs[reg]&EEINST_LASTUSE) ) { + if( usemmx ) return _allocMMXreg(-1, MMX_GPR+reg, mode); + return _allocGPRtoXMMreg(-1, reg, mode); + } + + return -1; +} + +#define PROCESS_EE_SETMODES(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// ignores XMMINFO_READS, XMMINFO_READT, and XMMINFO_READD_LO from xmminfo +// core of reg caching +void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo) +{ + int mmreg1, mmreg2, mmreg3, mmtemp, moded; + + if ( ! _Rd_ && (xmminfo&XMMINFO_WRITED) ) return; + + if( xmminfo&XMMINFO_WRITED) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( xmminfo & XMMINFO_WRITED ) { + _deleteMMXreg(MMX_GPR+_Rd_, 2); + _deleteGPRtoXMMreg(_Rd_, 2); + } + if( xmminfo&XMMINFO_WRITED ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + moded = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededMMXreg(MMX_GPR+MMX_LO); + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededMMXreg(MMX_GPR+MMX_HI); + _addNeededMMXreg(MMX_GPR+_Rs_); + _addNeededMMXreg(MMX_GPR+_Rt_); + + if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { + int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; + int vreg = creg == _Rs_ ? _Rt_ : _Rs_; + +// if(g_pCurInstInfo->regs[vreg]&EEINST_MMX) { +// mmreg1 = _allocMMXreg(-1, MMX_GPR+vreg, MODE_READ); +// _addNeededMMXreg(MMX_GPR+vreg); +// } + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, vreg, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX; + + if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); + else info |= PROCESS_EE_SETMODES(mmreg1); + + if( xmminfo & XMMINFO_WRITED ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); + + if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVE64(vreg)) ) { + if( EEINST_ISLIVE64(vreg) ) { + _freeMMXreg(mmreg1); + if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; + else info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else if( mmreg3 < 0 ) mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + SetMMXstate(); + if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); + else consttcode(info|PROCESS_EE_SET_S(mmreg1)); + _clearNeededMMXregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + else { + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 || mmreg2 >= 0 ) { + int info = PROCESS_EE_MMX; + + // do it all in mmx + if( mmreg1 < 0 ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rs_, MODE_READ); + if( mmreg2 < 0 ) mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + + info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); + + // check for last used, if so don't alloc a new MMX reg + if( xmminfo & XMMINFO_WRITED ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); + + if( mmreg3 < 0 ) { + if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_)) ) { + if( EEINST_ISLIVE64(_Rt_) ) { + _freeMMXreg(mmreg2); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg2].inuse = 1; + mmxregs[mmreg2].reg = _Rd_; + mmxregs[mmreg2].mode = moded; + mmreg3 = mmreg2; + } + else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_)) ) { + if( EEINST_ISLIVE64(_Rs_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); + } + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededMMXregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededGPRtoXMMreg(XMMGPR_LO); + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededGPRtoXMMreg(XMMGPR_HI); + _addNeededGPRtoXMMreg(_Rs_); + _addNeededGPRtoXMMreg(_Rt_); + + if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { + int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; + int vreg = creg == _Rs_ ? _Rt_ : _Rs_; + +// if(g_pCurInstInfo->regs[vreg]&EEINST_XMM) { +// mmreg1 = _allocGPRtoXMMreg(-1, vreg, MODE_READ); +// _addNeededGPRtoXMMreg(vreg); +// } + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, vreg, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM; + + if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); + else info |= PROCESS_EE_SETMODES(mmreg1); + + if( xmminfo & XMMINFO_WRITED ) { + + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(vreg)) ) { + _freeXMMreg(mmreg1); + if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; + else info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else if( mmreg3 < 0 ) mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); + else consttcode(info|PROCESS_EE_SET_S(mmreg1)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + else { + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 || mmreg2 >= 0 ) { + int info = PROCESS_EE_XMM; + + // do it all in xmm + if( mmreg1 < 0 ) mmreg1 = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + if( mmreg2 < 0 ) mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + + info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); + + if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, moded); + + if( mmreg3 < 0 ) { + if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(mmreg2); + info &= ~PROCESS_EE_MODEWRITET; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg2].inuse = 1; + xmmregs[mmreg2].reg = _Rd_; + xmmregs[mmreg2].mode = moded; + mmreg3 = mmreg2; + } + else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + } + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + if( xmminfo&XMMINFO_WRITED ) + _deleteGPRtoXMMreg(_Rd_, (xmminfo&XMMINFO_READD)?0:2); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + if( xmminfo&XMMINFO_WRITED ) + _deleteMMXreg(MMX_GPR+_Rd_, (xmminfo&XMMINFO_READD)?0:2); + + // don't delete, fn will take care of them +// if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { +// _deleteGPRtoXMMreg(XMMGPR_LO, (xmminfo&XMMINFO_READLO)?1:0); +// _deleteMMXreg(MMX_GPR+MMX_LO, (xmminfo&XMMINFO_READLO)?1:0); +// } +// if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { +// _deleteGPRtoXMMreg(XMMGPR_HI, (xmminfo&XMMINFO_READHI)?1:0); +// _deleteMMXreg(MMX_GPR+MMX_HI, (xmminfo&XMMINFO_READHI)?1:0); +// } + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rt_ ) return; + + CHECK_SAVE_REG(_Rt_); + _eeProcessHasLive(_Rt_, 0); + EEINST_RESETSIGNEXT(_Rt_); + + if( GPR_IS_CONST1(_Rs_) ) { + _deleteMMXreg(MMX_GPR+_Rt_, 2); + _deleteGPRtoXMMreg(_Rt_, 2); + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX|PROCESS_EE_SETMODES(mmreg1); + + // check for last used, if so don't alloc a new MMX reg + _addNeededMMXreg(MMX_GPR+_Rt_); + mmreg2 = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + if( EEINST_ISLIVE64(_Rs_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rt_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rt_; + mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededMMXregs(); + GPR_DEL_CONST(_Rt_); + return; + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODES(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rt_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rt_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rt_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rt_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 2); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rd_ ) return; + + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + + if( GPR_IS_CONST1(_Rt_) ) { + _deleteMMXreg(MMX_GPR+_Rd_, 2); + _deleteGPRtoXMMreg(_Rd_, 2); + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX|PROCESS_EE_SETMODET(mmreg1); + + // check for last used, if so don't alloc a new MMX reg + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg2 = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + if( EEINST_ISLIVE64(_Rt_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); + _clearNeededMMXregs(); + GPR_DEL_CONST(_Rd_); + return; + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODET(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITET; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rd_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rd_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 2); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt op rs +void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode) +{ + assert(0); + // for now, don't support xmm + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + multicode(0); +} + +// Simple Code Templates // + +// rd = rs op rt +void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rd_, 0); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rt_ ) + return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rt_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 0); + + if( GPR_IS_CONST1(_Rs_) ) { + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + + if( GPR_IS_CONST1(_Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rd = rt MULT rs (SPECIAL) +void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT) +{ + assert(0); + // for now, don't support xmm + if( MULT ) { + CHECK_SAVE_REG(_Rd_); + _deleteGPRtoXMMreg(_Rd_, 0); + } + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( MULT && _Rd_ ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTS); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + multicode(0); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); +} + +// EE XMM allocation code +int eeRecompileCodeXMM(int xmminfo) +{ + int info = PROCESS_EE_XMM; + + // save state + if( xmminfo & XMMINFO_WRITED ) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + // flush consts + if( xmminfo & XMMINFO_READT ) { + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + } + if( xmminfo & XMMINFO_READS) { + if( GPR_IS_CONST1( _Rs_ ) && !(g_cpuFlushedConstReg&(1<<_Rs_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rs_); + } + } + + if( xmminfo & XMMINFO_WRITED ) { + GPR_DEL_CONST(_Rd_); + } + + // add needed + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + _addNeededGPRtoXMMreg(XMMGPR_LO); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + _addNeededGPRtoXMMreg(XMMGPR_HI); + } + if( xmminfo & XMMINFO_READS) _addNeededGPRtoXMMreg(_Rs_); + if( xmminfo & XMMINFO_READT) _addNeededGPRtoXMMreg(_Rt_); + if( xmminfo & XMMINFO_WRITED ) _addNeededGPRtoXMMreg(_Rd_); + + // allocate + if( xmminfo & XMMINFO_READS) { + int reg = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + info |= PROCESS_EE_SET_S(reg)|PROCESS_EE_SETMODES(reg); + } + if( xmminfo & XMMINFO_READT) { + int reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + info |= PROCESS_EE_SET_T(reg)|PROCESS_EE_SETMODET(reg); + } + + if( xmminfo & XMMINFO_WRITED ) { + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?((xmminfo&XMMINFO_READD_LO)?(MODE_READ|MODE_READHALF):MODE_READ):0); + + int regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, readd); + + if( regd < 0 ) { + if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READT) && (_Rt_ == 0 || (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(EEREC_T); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[EEREC_T].inuse = 1; + xmmregs[EEREC_T].reg = _Rd_; + xmmregs[EEREC_T].mode = readd; + regd = EEREC_T; + } + else if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READS) && (_Rs_ == 0 || (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(EEREC_S); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[EEREC_S].inuse = 1; + xmmregs[EEREC_S].reg = _Rd_; + xmmregs[EEREC_S].mode = readd; + regd = EEREC_S; + } + else regd = _allocGPRtoXMMreg(-1, _Rd_, readd); + } + + info |= PROCESS_EE_SET_D(regd); + } + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + info |= PROCESS_EE_SET_LO(_allocGPRtoXMMreg(-1, XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0))); + info |= PROCESS_EE_LO; + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + info |= PROCESS_EE_SET_HI(_allocGPRtoXMMreg(-1, XMMGPR_HI, ((xmminfo&XMMINFO_READHI)?MODE_READ:0)|((xmminfo&XMMINFO_WRITEHI)?MODE_WRITE:0))); + info |= PROCESS_EE_HI; + } + return info; +} + +// EE COP1(FPU) XMM allocation code +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define PROCESS_EE_SETMODES_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// rd = rs op rt +void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR_INFO fpucode, int xmminfo) +{ + int mmregs=-1, mmregt=-1, mmregd=-1, mmregacc=-1; + + if( EE_FPU_REGCACHING && cpucaps.hasStreamingSIMDExtensions ) { + int info = PROCESS_EE_XMM; + + if( xmminfo & XMMINFO_READS ) _addNeededFPtoXMMreg(_Fs_); + if( xmminfo & XMMINFO_READT ) _addNeededFPtoXMMreg(_Ft_); + if( xmminfo & (XMMINFO_WRITED|XMMINFO_READD) ) _addNeededFPtoXMMreg(_Fd_); + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) _addNeededFPACCtoXMMreg(); + + if( xmminfo & XMMINFO_READT ) { + if( g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE ) mmregt = _checkXMMreg(XMMTYPE_FPREG, _Ft_, MODE_READ); + else mmregt = _allocFPtoXMMreg(-1, _Ft_, MODE_READ); + } + + if( xmminfo & XMMINFO_READS ) { + if( (!(xmminfo&XMMINFO_READT)||mmregt>=0) && (g_pCurInstInfo->fpuregs[_Fs_] & EEINST_LASTUSE) ) + mmregs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + else mmregs = _allocFPtoXMMreg(-1, _Fs_, MODE_READ); + } + + if( mmregs >= 0 ) info |= PROCESS_EE_SETMODES_XMM(mmregs); + if( mmregt >= 0 ) info |= PROCESS_EE_SETMODET_XMM(mmregt); + + if( xmminfo & XMMINFO_READD ) { + assert( xmminfo & XMMINFO_WRITED ); + mmregd = _allocFPtoXMMreg(-1, _Fd_, MODE_READ); + } + + if( xmminfo & XMMINFO_READACC ) { + if( !(xmminfo&XMMINFO_WRITEACC) && (g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE) ) + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, MODE_READ); + else mmregacc = _allocFPACCtoXMMreg(-1, MODE_READ); + } + + if( xmminfo & XMMINFO_WRITEACC ) { + + // check for last used, if so don't alloc a new XMM reg + int readacc = MODE_WRITE|((xmminfo&XMMINFO_READACC)?MODE_READ:0); + + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, readacc); + + if( mmregacc < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = 0; + xmmregs[mmregt].mode = readacc; + xmmregs[mmregt].type = XMMTYPE_FPACC; + mmregacc = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = 0; + xmmregs[mmregs].mode = readacc; + xmmregs[mmregs].type = XMMTYPE_FPACC; + mmregacc = mmregs; + } + else mmregacc = _allocFPACCtoXMMreg(-1, readacc); + } + + xmmregs[mmregacc].mode |= MODE_WRITE; + } + else if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + if( xmminfo&XMMINFO_READD ) mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + else mmregd = _checkXMMreg(XMMTYPE_FPREG, _Fd_, readd); + + if( mmregd < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = _Fd_; + xmmregs[mmregt].mode = readd; + mmregd = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = _Fd_; + xmmregs[mmregs].mode = readd; + mmregd = mmregs; + } + else if( (xmminfo&XMMINFO_READACC) && mmregacc >= 0 && (FPUINST_LASTUSE(XMMFPU_ACC) || !FPUINST_ISLIVE(XMMFPU_ACC)) ) { + if( FPUINST_ISLIVE(XMMFPU_ACC) ) + _freeXMMreg(mmregacc); + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregacc].inuse = 1; + xmmregs[mmregacc].reg = _Fd_; + xmmregs[mmregacc].mode = readd; + xmmregs[mmregacc].type = XMMTYPE_FPREG; + mmregd = mmregacc; + } + else mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + } + } + + assert( mmregs >= 0 || mmregt >= 0 || mmregd >= 0 || mmregacc >= 0 ); + + if( xmminfo & XMMINFO_WRITED ) { + assert( mmregd >= 0 ); + info |= PROCESS_EE_SET_D(mmregd); + } + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) { + if( mmregacc >= 0 ) info |= PROCESS_EE_SET_ACC(mmregacc)|PROCESS_EE_ACC; + else assert( !(xmminfo&XMMINFO_WRITEACC)); + } + + if( xmminfo & XMMINFO_READS ) { + if( mmregs >= 0 ) info |= PROCESS_EE_SET_S(mmregs)|PROCESS_EE_S; + } + if( xmminfo & XMMINFO_READT ) { + if( mmregt >= 0 ) info |= PROCESS_EE_SET_T(mmregt)|PROCESS_EE_T; + } + + // at least one must be in xmm + if( (xmminfo & (XMMINFO_READS|XMMINFO_READT)) == (XMMINFO_READS|XMMINFO_READT) ) { + assert( mmregs >= 0 || mmregt >= 0 ); + } + + xmmcode(info); + _clearNeededXMMregs(); + return; + } + + if( xmminfo & XMMINFO_READS ) _deleteFPtoXMMreg(_Fs_, 0); + if( xmminfo & XMMINFO_READT ) _deleteFPtoXMMreg(_Ft_, 0); + if( xmminfo & (XMMINFO_READD|XMMINFO_WRITED) ) _deleteFPtoXMMreg(_Fd_, 0); + if( xmminfo & (XMMINFO_READACC|XMMINFO_WRITEACC) ) _deleteFPtoXMMreg(XMMFPU_ACC, 0); + fpucode(0); +} + +#undef _Ft_ +#undef _Fs_ +#undef _Fd_ + +//////////////////////////////////////////////////// +extern u8 g_MACFlagTransform[256]; // for vus + +u32 g_sseMXCSR = 0x9fc0; // disable all exception, round to 0, flush to 0 +u32 g_sseVUMXCSR = 0xff80; // set to 0xffc0 to enable DAZ + +void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR) +{ + // SSE STATE // + // WARNING: do not touch unless you know what you are doing + + if( cpucaps.hasStreamingSIMDExtensions ) { + g_sseMXCSR = sseMXCSR; + g_sseVUMXCSR = sseVUMXCSR; + // do NOT set Denormals-Are-Zero flag (charlie and chocfac messes up) + // Update 11/05/08 - Doesnt seem to effect it anymore, for the speed boost, its on :p + //g_sseMXCSR = 0x9f80; // changing the rounding mode to 0x2000 (near) kills grandia III! + // changing the rounding mode to 0x0000 or 0x4000 totally kills gitaroo + // so... grandia III wins (you can change individual games with the 'roundmode' patch command) + +#ifdef _MSC_VER + __asm ldmxcsr g_sseMXCSR; // set the new sse control +#else + __asm__("ldmxcsr %0" : : "m"(g_sseMXCSR) ); +#endif + //g_sseVUMXCSR = g_sseMXCSR|0x6000; + } +} + +#define REC_CACHEMEM 0x01000000 + +int recInit( void ) +{ + int i; + const u8 macarr[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; + + recLUT = (uptr*) _aligned_malloc( 0x010000 * sizeof(uptr), 16 ); + memset( recLUT, 0, 0x010000 * sizeof(uptr) ); + + // can't have upper 4 bits nonzero! + recMem = (char*)SysMmap(0x0d000000, REC_CACHEMEM); + + // 32 alignment necessary + recRAM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x02000000 , 4*sizeof(BASEBLOCK)); + recROM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x00400000 , 4*sizeof(BASEBLOCK)); + recROM1= (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x00040000 , 4*sizeof(BASEBLOCK)); + recBlocks = (BASEBLOCKEX*) _aligned_malloc( sizeof(BASEBLOCKEX)*EE_NUMBLOCKS, 16); + recStack = (char*)malloc( RECSTACK_SIZE ); + + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + + if ( recBlocks == NULL || recRAM == NULL || recROM == NULL || recROM1 == NULL || recMem == NULL || recLUT == NULL ) { + SysMessage( _( "Error allocating memory" ) ); + return -1; + } + + for ( i = 0x0000; i < 0x0200; i++ ) + { + recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ]; + } + + for ( i = 0x0000; i < 0x0040; i++ ) + { + recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ]; + } + + for ( i = 0x0000; i < 0x0004; i++ ) + { + recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ]; + } + + memcpy( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) ); + memcpy( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) ); + + memset(recMem, 0xcd, REC_CACHEMEM); + memset(recStack, 0, RECSTACK_SIZE); + + // SSE3 detection, manually create the code + x86SetPtr(recMem); + SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0); + RET(); + + cpudetectSSE3(recMem); + + x86SetPtr(recMem); + SSE4_DPPS_XMM_to_XMM(XMM0, XMM0, 0); + RET(); + + cpudetectSSE4(recMem); + + SysPrintf( "x86Init: \n" ); + SysPrintf( "\tCPU vender name = %s\n", cpuinfo.x86ID ); + SysPrintf( "\tFamilyID = %x\n", cpuinfo.x86StepID ); + SysPrintf( "\tx86Family = %s\n", cpuinfo.x86Fam ); + SysPrintf( "\tCPU speed = %d.%03d Ghz\n", cpuinfo.cpuspeed / 1000, cpuinfo.cpuspeed%1000); + SysPrintf( "\tx86PType = %s\n", cpuinfo.x86Type ); + SysPrintf( "\tx86Flags = %8.8x %8.8x\n", cpuinfo.x86Flags, cpuinfo.x86Flags2 ); + SysPrintf( "\tx86EFlags = %8.8x\n", cpuinfo.x86EFlags ); + SysPrintf( "Features: \n" ); + SysPrintf( "\t%sDetected MMX\n", cpucaps.hasMultimediaExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE\n", cpucaps.hasStreamingSIMDExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE2\n", cpucaps.hasStreamingSIMD2Extensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE3\n", cpucaps.hasStreamingSIMD3Extensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE4.1\n", cpucaps.hasStreamingSIMD4Extensions ? "" : "Not " ); + + if ( cpuinfo.x86ID[0] == 'A' ) //AMD cpu + { + SysPrintf( " Extented AMD Features: \n" ); + SysPrintf( "\t%sDetected MMX2\n", cpucaps.hasMultimediaExtensionsExt ? "" : "Not " ); + SysPrintf( "\t%sDetected 3DNOW\n", cpucaps.has3DNOWInstructionExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected 3DNOW2\n", cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not " ); + } + if ( !( cpucaps.hasMultimediaExtensions ) ) + { + SysMessage( _( "Processor doesn't supports MMX, can't run recompiler without that" ) ); + return -1; + } + + x86FpuState = FPU_STATE; + + SuperVUInit(-1); + + for(i = 0; i < 256; ++i) { + g_MACFlagTransform[i] = macarr[i>>4]|(macarr[i&15]<<4); + } + + SetCPUState(g_sseMXCSR, g_sseVUMXCSR); + + return 0; +} + +//////////////////////////////////////////////////// +void recReset( void ) { +#ifdef PCSX2_DEVBUILD + SysPrintf("EE Recompiler data reset\n"); +#endif + + s_nNextBlock = 0; + maxrecmem = 0; + memset( recRAM, 0, sizeof(BASEBLOCK)/4*0x02000000 ); + memset( recROM, 0, sizeof(BASEBLOCK)/4*0x00400000 ); + memset( recROM1, 0, sizeof(BASEBLOCK)/4*0x00040000 ); + memset( recBlocks, 0, sizeof(BASEBLOCKEX)*EE_NUMBLOCKS ); + if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + ResetBaseBlockEx(0); + +#ifdef _MSC_VER + __asm emms; +#else + __asm__("emms"); +#endif + +#ifdef _DEBUG + // don't clear since save states won't work + //memset(recMem, 0xcd, REC_CACHEMEM); +#endif + + recPtr = recMem; + recStackPtr = recStack; + x86FpuState = FPU_STATE; + iCWstate = 0; + + branch = 0; +} + +void recShutdown( void ) +{ + if ( recMem == NULL ) { + return; + } + + _aligned_free( recLUT ); + SysMunmap((uptr)recMem, REC_CACHEMEM); recMem = NULL; + _aligned_free( recRAM ); recRAM = NULL; + _aligned_free( recROM ); recROM = NULL; + _aligned_free( recROM1 ); recROM1 = NULL; + _aligned_free( recBlocks ); recBlocks = NULL; + free( s_pInstCache ); s_pInstCache = NULL; s_nInstCacheSize = 0; + + SuperVUDestroy(-1); + + x86Shutdown( ); +} + +void recEnableVU0micro(int enable) { +} + +void recEnableVU1micro(int enable) { +} + +#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code +static u32 s_uSaveESP = 0, s_uSaveEBP; + +static void execute( void ) +{ +#ifdef _DEBUG + u8* fnptr; + u32 oldesi; +#else + R5900FNPTR pfn; +#endif + BASEBLOCK* pblock = PC_GETBLOCK(cpuRegs.pc); + + if ( !pblock->pFnptr || pblock->startpc != cpuRegs.pc ) { + recRecompile(cpuRegs.pc); + } + + assert( pblock->pFnptr != 0 ); + g_EEFreezeRegs = 1; + + // skip the POPs +#ifdef _DEBUG + fnptr = (u8*)pblock->pFnptr; + +#ifdef _MSC_VER + __asm { + // save data + mov oldesi, esi + mov s_uSaveESP, esp + sub s_uSaveESP, 8 + mov s_uSaveEBP, ebp + push ebp + + call fnptr // jump into function + // restore data + pop ebp + mov esi, oldesi + } +#else + + __asm__("movl %%esi, %0\n" + "movl %%esp, %1\n" + "sub $8, %1\n" + "push %%ebp\n" + "call *%2\n" + "pop %%ebp\n" + "movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) ); +#endif // _MSC_VER + +#else + +#ifdef _MSC_VER + pfn = ((R5900FNPTR)pblock->pFnptr); + // use call instead of pfn() + __asm call pfn; +#else + ((R5900FNPTR)pblock->pFnptr)(); +#endif + +#endif + + g_EEFreezeRegs = 0; +} + +void recStep( void ) { +} + +void recExecute( void ) { + //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);//ABOVE_NORMAL_PRIORITY_CLASS); + //SetThreadAffinityMask(GetCurrentThread(), 0); + if( Config.Options & PCSX2_EEREC ) Config.Options |= PCSX2_COP2REC; + + for (;;) + execute(); +} + +void recExecuteBlock( void ) { + execute(); +} + +//////////////////////////////////////////////////// +extern u32 g_nextBranchCycle; + +u32 g_lastpc = 0; +u32 g_EEDispatchTemp; +u32 s_pCurBlock_ltime; + +#ifdef _MSC_VER + +// jumped to when invalid pc address +__declspec(naked,noreturn) void Dispatcher() +{ + // EDX contains the jump addr to modify + __asm push edx + + // calc PC_GETBLOCK + s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + + __asm { + mov eax, s_pDispatchBlock + + // check if startpc == cpuRegs.pc + mov ecx, cpuRegs.pc + //and ecx, 0x5fffffff // remove higher bits + cmp ecx, dword ptr [eax+BLOCKTYPE_STARTPC] + je CheckPtr + + // recompile + push cpuRegs.pc // pc + call recRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock +CheckPtr: + mov eax, dword ptr [eax] + } + +#ifdef _DEBUG + __asm mov g_EEDispatchTemp, eax + assert( g_EEDispatchTemp ); +#endif + +// __asm { +// test eax, 0x40000000 // BLOCKTYPE_NEEDCLEAR +// jz Done +// // move new pc +// and eax, 0x0fffffff +// mov ecx, cpuRegs.pc +// mov dword ptr [eax+1], ecx +// } + __asm { + and eax, 0x0fffffff + mov edx, eax + pop ecx // x86Ptr to mod + sub edx, ecx + sub edx, 4 + mov dword ptr [ecx], edx + + jmp eax + } +} + +__declspec(naked,noreturn) void DispatcherClear() +{ + // EDX contains the current pc + __asm mov cpuRegs.pc, edx + __asm push edx + + // calc PC_GETBLOCK + s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + + if( s_pDispatchBlock->startpc == cpuRegs.pc ) { + assert( s_pDispatchBlock->pFnptr != 0 ); + + // already modded the code, jump to the new place + __asm { + pop edx + add esp, 4 // ignore stack + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + and eax, 0x0fffffff + jmp eax + } + } + + __asm { + call recRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + + pop ecx // old fnptr + + and eax, 0x0fffffff + mov byte ptr [ecx], 0xe9 // jmp32 + mov edx, eax + sub edx, ecx + sub edx, 5 + mov dword ptr [ecx+1], edx + + jmp eax + } +} + +// called when jumping to variable pc address +__declspec(naked,noreturn) void DispatcherReg() +{ + __asm { + //s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + mov edx, cpuRegs.pc + mov ecx, edx + } + + __asm { + shr edx, 14 + and edx, 0xfffffffc + add edx, recLUT + mov edx, dword ptr [edx] + + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // check if startpc == cpuRegs.pc + mov eax, ecx + //and eax, 0x5fffffff // remove higher bits + cmp eax, dword ptr [edx+BLOCKTYPE_STARTPC] + jne recomp + + mov eax, dword ptr [edx] + } + +#ifdef _DEBUG + __asm mov g_EEDispatchTemp, eax + assert( g_EEDispatchTemp ); +#endif + + __asm { + and eax, 0x0fffffff + jmp eax // fnptr + +recomp: + sub esp, 8 + mov dword ptr [esp+4], edx + mov dword ptr [esp], ecx + call recRecompile + mov edx, dword ptr [esp+4] + add esp, 8 + + mov eax, dword ptr [edx] + and eax, 0x0fffffff + jmp eax // fnptr + } +} + +#ifdef PCSX2_DEVBUILD +__declspec(naked) void _StartPerfCounter() +{ + __asm { + push eax + push ebx + push ecx + + rdtsc + mov dword ptr [offset lbase], eax + mov dword ptr [offset lbase + 4], edx + + pop ecx + pop ebx + pop eax + ret + } +} + +__declspec(naked) void _StopPerfCounter() +{ + __asm { + push eax + push ebx + push ecx + + rdtsc + + sub eax, dword ptr [offset lbase] + sbb edx, dword ptr [offset lbase + 4] + mov ecx, s_pCurBlock_ltime + add eax, dword ptr [ecx] + adc edx, dword ptr [ecx + 4] + mov dword ptr [ecx], eax + mov dword ptr [ecx + 4], edx + pop ecx + pop ebx + pop eax + ret + } +} + +#endif // PCSX2_DEVBUILD + +#else // _MSC_VER + +extern void Dispatcher(); +extern void DispatcherClear(); +extern void DispatcherReg(); +extern void _StartPerfCounter(); +extern void _StopPerfCounter(); + +#endif + +#ifdef PCSX2_DEVBUILD +void StartPerfCounter() +{ +#ifdef PCSX2_DEVBUILD + if( s_startcount ) { + CALLFunc((u32)_StartPerfCounter); + } +#endif +} + +void StopPerfCounter() +{ +#ifdef PCSX2_DEVBUILD + if( s_startcount ) { + MOV32ItoM((u32)&s_pCurBlock_ltime, (u32)&s_pCurBlockEx->ltime); + CALLFunc((u32)_StopPerfCounter); + } +#endif +} +#endif + +//////////////////////////////////////////////////// +void recClear64(BASEBLOCK* p) +{ + int left = 4 - ((u32)p % 16)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); +} + +void recClear128(BASEBLOCK* p) +{ + int left = 4 - ((u32)p % 32)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); + if( left > 2 && *(u32*)(p+2) ) recClearMem(p+2); + if( left > 3 && *(u32*)(p+3) ) recClearMem(p+3); +} + +void recClear( u32 Addr, u32 Size ) +{ + u32 i; + for(i = 0; i < Size; ++i, Addr+=4) { + REC_CLEARM(Addr); + } +} + +#define EE_MIN_BLOCK_BYTES 15 + +void recClearMem(BASEBLOCK* p) +{ + BASEBLOCKEX* pexblock; + BASEBLOCK* pstart; + int lastdelay; + + // necessary since recompiler doesn't call femms/emms +#ifdef _MSC_VER + if (cpucaps.has3DNOWInstructionExtensions) __asm femms; + else __asm emms; +#else + if( cpucaps.has3DNOWInstructionExtensions )__asm__("femms"); + else __asm__("emms"); +#endif + + assert( p != NULL ); + + if( p->uType & BLOCKTYPE_DELAYSLOT ) { + recClearMem(p-1); + if( p->pFnptr == 0 ) + return; + } + + assert( p->pFnptr != 0 ); + assert( p->startpc ); + + x86Ptr = (s8*)p->pFnptr; + + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, p->startpc); + PUSH32I((u32)x86Ptr); // will be replaced by JMP32 + JMP32((u32)DispatcherClear - ( (u32)x86Ptr + 5 )); + assert( x86Ptr == (s8*)p->pFnptr + EE_MIN_BLOCK_BYTES ); + + pstart = PC_GETBLOCK(p->startpc); + pexblock = PC_GETBLOCKEX(pstart); + assert( pexblock->startpc == pstart->startpc ); + + if( pexblock->startpc != pstart->startpc ) { + // some bug with ffx after beating a big snake in sewers + RemoveBaseBlockEx(pexblock, 0); + pexblock->size = 0; + pexblock->startpc = 0; + return; + } + +// if( pexblock->pOldFnptr ) { +// // have to mod oldfnptr too +// x86Ptr = pexblock->pOldFnptr; +// +// MOV32ItoR(EDX, p->startpc); +// JMP32((u32)DispatcherClear - ( (u32)x86Ptr + 5 )); +// } +// else +// pexblock->pOldFnptr = (u8*)p->pFnptr; + + // don't delete if last is delay + lastdelay = pexblock->size; + if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { + assert( pstart[pexblock->size-1].pFnptr != pstart->pFnptr ); + if( pstart[pexblock->size-1].pFnptr != 0 ) { + pstart[pexblock->size-1].uType = 0; + --lastdelay; + } + } + + memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + + RemoveBaseBlockEx(pexblock, 0); + pexblock->size = 0; + pexblock->startpc = 0; +} + +// check for end of bios +void CheckForBIOSEnd() +{ + MOV32MtoR(EAX, (int)&cpuRegs.pc); + + CMP32ItoR(EAX, 0x00200008); + j8Ptr[0] = JE8(0); + + CMP32ItoR(EAX, 0x00100008); + j8Ptr[1] = JE8(0); + + // return + j8Ptr[2] = JMP8(0); + + x86SetJ8( j8Ptr[0] ); + x86SetJ8( j8Ptr[1] ); + + // bios end + RET2(); + + x86SetJ8( j8Ptr[2] ); +} + +static int *s_pCode; + +void SetBranchReg( u32 reg ) +{ + branch = 1; + + if( reg != 0xffffffff ) { +// if( GPR_IS_CONST1(reg) ) +// MOV32ItoM( (u32)&cpuRegs.pc, g_cpuConstRegs[reg].UL[0] ); +// else { +// int mmreg; +// +// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ)) >= 0 ) { +// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); +// } +// else if( (mmreg = _checkMMXreg(MMX_GPR+reg, MODE_READ)) >= 0 ) { +// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); +// SetMMXstate(); +// } +// else { +// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ reg ].UL[ 0 ] ); +// MOV32RtoM((u32)&cpuRegs.pc, EAX); +// } +// } + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, reg); + + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((int)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (u32)&g_recWriteback); + MOV32RtoM((int)&cpuRegs.pc, EAX); + } + } + +// CMP32ItoM((u32)&cpuRegs.pc, 0); +// j8Ptr[5] = JNE8(0); +// CALLFunc((u32)tempfn); +// x86SetJ8( j8Ptr[5] ); + + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(0xffffffff, 1); + if( bExecBIOS ) CheckForBIOSEnd(); + + JMP32((u32)DispatcherReg - ( (u32)x86Ptr + 5 )); +} + +void SetBranchImm( u32 imm ) +{ + u32* ptr; + branch = 1; + + assert( imm ); + + // end the current block + MOV32ItoM( (u32)&cpuRegs.pc, imm ); + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(imm, imm <= pc); + if( bExecBIOS ) CheckForBIOSEnd(); + + MOV32ItoR(EDX, 0); + ptr = (u32*)(x86Ptr-4); + *ptr = (u32)JMP32((u32)Dispatcher - ( (u32)x86Ptr + 5 )); +} + +void SaveBranchState() +{ + s_savex86FpuState = x86FpuState; + s_saveiCWstate = iCWstate; + s_savenBlockCycles = s_nBlockCycles; + s_saveConstGPRreg = 0xffffffff; // indicate searching + s_saveHasConstReg = g_cpuHasConstReg; + s_saveFlushedConstReg = g_cpuFlushedConstReg; + s_psaveInstInfo = g_pCurInstInfo; + s_saveRegHasLive1 = g_cpuRegHasLive1; + s_saveRegHasSignExt = g_cpuRegHasSignExt; + + // save all mmx regs + memcpy(s_saveMMXregs, mmxregs, sizeof(mmxregs)); + memcpy(s_saveXMMregs, xmmregs, sizeof(xmmregs)); +} + +void LoadBranchState() +{ + x86FpuState = s_savex86FpuState; + iCWstate = s_saveiCWstate; + s_nBlockCycles = s_savenBlockCycles; + + if( s_saveConstGPRreg != 0xffffffff ) { + assert( s_saveConstGPRreg > 0 ); + + // make sure right GPR was saved + assert( g_cpuHasConstReg == s_saveHasConstReg || (g_cpuHasConstReg ^ s_saveHasConstReg) == (1<visited, 1 ); + } +#endif + +#ifdef _DEBUG + //CALLFunc((u32)testfpu); +#endif + + if( !USE_FAST_BRANCHES || cpuBranch ) { + MOV32MtoR(ECX, (int)&cpuRegs.cycle); + ADD32ItoR(ECX, s_nBlockCycles*EECYCLE_MULT); // NOTE: mulitply cycles here, 6/5 ratio stops pal ffx from randomly crashing, but crashes jakI + MOV32RtoM((int)&cpuRegs.cycle, ECX); // update cycles + } + else { + ADD32ItoM((int)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); + return; + } + + SUB32MtoR(ECX, (int)&g_nextBranchCycle); + + // check if should branch + j8Ptr[0] = JS8( 0 ); + + // has to be in the middle of Save/LoadBranchState + CALLFunc( (int)cpuBranchTest ); + + if( newpc != 0xffffffff ) { + CMP32ItoM((int)&cpuRegs.pc, newpc); + JNE32((u32)DispatcherReg - ( (u32)x86Ptr + 6 )); + } + + x86SetJ8( j8Ptr[0] ); +} + + +//////////////////////////////////////////////////// +#ifndef CP2_RECOMPILE + +REC_SYS(COP2); + +#else + +void recCOP2( void ) +{ +#ifdef CPU_LOG + CPU_LOG( "Recompiling COP2:%s\n", disR5900Fasm( cpuRegs.code, cpuRegs.pc ) ); +#endif + + if ( !cpucaps.hasStreamingSIMDExtensions ) { + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (u32)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + g_cpuHasConstReg = 1; // reset all since COP2 can change regs + CALLFunc( (u32)COP2 ); + + CMP32ItoM((int)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((u32)&cpuRegs.cycle, s_nBlockCycles); + JMP32((u32)DispatcherReg - ( (u32)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + } + else + { + recCOP22( ); + } +} + +#endif + +//////////////////////////////////////////////////// +void recSYSCALL( void ) { + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (u32)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_NODESTROY); + CALLFunc( (u32)SYSCALL ); + + CMP32ItoM((int)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((u32)&cpuRegs.cycle, s_nBlockCycles); + JMP32((u32)DispatcherReg - ( (u32)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +//////////////////////////////////////////////////// +void recBREAK( void ) { + MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (u32)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BREAK ); + + CMP32ItoM((int)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((u32)&cpuRegs.cycle, s_nBlockCycles); + RET(); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +//////////////////////////////////////////////////// +//static void recCACHE( void ) { +// MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code ); +// MOV32ItoM( (u32)&cpuRegs.pc, pc ); +// iFlushCall(FLUSH_EVERYTHING); +// CALLFunc( (u32)CACHE ); +// //branch = 2; +// +// CMP32ItoM((int)&cpuRegs.pc, pc); +// j8Ptr[0] = JE8(0); +// RET(); +// x86SetJ8(j8Ptr[0]); +//} + + +void recPREF( void ) +{ +} + +void recSYNC( void ) +{ +} + +void recMFSA( void ) +{ + int mmreg; + if (!_Rd_) return; + + mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + if( mmreg >= 0 ) { + SSE_MOVLPS_M64_to_XMM(mmreg, (u32)&cpuRegs.sa); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) >= 0 ) { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.sa); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (u32)&cpuRegs.sa); + _deleteEEreg(_Rd_, 0); + MOV32RtoM((u32)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[1], 0); + } +} + +void recMTSA( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((u32)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] ); + } + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { + SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.sa, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { + MOVDMMXtoM((u32)&cpuRegs.sa, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV32RtoM((u32)&cpuRegs.sa, EAX); + } + } +} + +void recMTSAB( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((u32)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0xF); + XOR32ItoR(EAX, _Imm_&0xf); + SHL32ItoR(EAX, 3); + MOV32RtoM((u32)&cpuRegs.sa, EAX); + } +} + +void recMTSAH( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((u32)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0x7); + XOR32ItoR(EAX, _Imm_&0x7); + SHL32ItoR(EAX, 4); + MOV32RtoM((u32)&cpuRegs.sa, EAX); + } +} + +static void checkcodefn() +{ + int pctemp; + +#ifdef _MSC_VER + __asm mov pctemp, eax; +#else + __asm__("movl %%eax, %0" : "=m"(pctemp) ); +#endif + + SysPrintf("code changed! %x\n", pctemp); + assert(0); +} + +void checkpchanged(u32 startpc) +{ + assert(0); +} + +//#ifdef _DEBUG +//#define CHECK_XMMCHANGED() CALLFunc((u32)checkxmmchanged); +//#else +//#define CHECK_XMMCHANGED() +//#endif +// +//static void checkxmmchanged() +//{ +// assert( !g_globalMMXSaved ); +// assert( !g_globalXMMSaved ); +//} + +u32 recompileCodeSafe(u32 temppc) +{ + BASEBLOCK* pblock = PC_GETBLOCK(temppc); + + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pc == pblock->startpc ) + return 0; + } + + return 1; +} + +void recompileNextInstruction(int delayslot) +{ + static u8 s_bFlushReg = 1; + int i, count; + + BASEBLOCK* pblock = PC_GETBLOCK(pc); + + // need *ppblock != s_pCurBlock because of branches + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( !delayslot && pc == pblock->startpc ) { + // code already in place, so jump to it and exit recomp + assert( PC_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((u32)&cpuRegs.pc, pc); + +// if( pexblock->pOldFnptr ) { +// // code already in place, so jump to it and exit recomp +// JMP32((u32)pexblock->pOldFnptr - ((u32)x86Ptr + 5)); +// branch = 3; +// return; +// } + + JMP32((u32)pblock->pFnptr - ((u32)x86Ptr + 5)); + branch = 3; + return; + } + else { + + if( !(delayslot && pblock->startpc == pc) ) { + s8* oldX86 = x86Ptr; + //__Log("clear block %x\n", pblock->startpc); + recClearMem(pblock); + x86Ptr = oldX86; + if( delayslot ) + SysPrintf("delay slot %x\n", pc); + } + } + } + + if( delayslot ) + pblock->uType = BLOCKTYPE_DELAYSLOT; + + s_pCode = (int *)PSM( pc ); + assert(s_pCode); + +#ifdef _DEBUG + MOV32ItoR(EAX, pc); +#endif + + cpuRegs.code = *(int *)s_pCode; + s_nBlockCycles++; + pc += 4; + +//#ifdef _DEBUG +// CMP32ItoM((u32)s_pCode, cpuRegs.code); +// j8Ptr[0] = JE8(0); +// MOV32ItoR(EAX, pc); +// CALLFunc((u32)checkcodefn); +// x86SetJ8( j8Ptr[ 0 ] ); +// +// if( !delayslot ) { +// CMP32ItoM((u32)&cpuRegs.pc, s_pCurBlockEx->startpc); +// j8Ptr[0] = JB8(0); +// CMP32ItoM((u32)&cpuRegs.pc, pc); +// j8Ptr[1] = JA8(0); +// j8Ptr[2] = JMP8(0); +// x86SetJ8( j8Ptr[ 0 ] ); +// x86SetJ8( j8Ptr[ 1 ] ); +// PUSH32I(s_pCurBlockEx->startpc); +// CALLFunc((u32)checkpchanged); +// ADD32ItoR(ESP, 4); +// x86SetJ8( j8Ptr[ 2 ] ); +// } +//#endif + + g_pCurInstInfo++; + + // reorder register priorities +// for(i = 0; i < X86REGS; ++i) { +// if( x86regs[i].inuse ) { +// if( count > 0 ) mmxregs[i].counter = 1000-count; +// else mmxregs[i].counter = 0; +// } +// } + + for(i = 0; i < MMXREGS; ++i) { + if( mmxregs[i].inuse ) { + assert( MMX_ISGPR(mmxregs[i].reg) ); + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR); + if( count > 0 ) mmxregs[i].counter = 1000-count; + else mmxregs[i].counter = 0; + } + } + + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse ) { + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, xmmregs[i].type, xmmregs[i].reg); + if( count > 0 ) xmmregs[i].counter = 1000-count; + else xmmregs[i].counter = 0; + } + } + + // peephole optimizations + if( g_pCurInstInfo->info & EEINSTINFO_COREC ) { + +#ifdef PCSX2_VIRTUAL_MEM + if( g_pCurInstInfo->numpeeps > 1 ) { + switch(cpuRegs.code>>26) { + case 30: recLQ_coX(g_pCurInstInfo->numpeeps); break; + case 31: recSQ_coX(g_pCurInstInfo->numpeeps); break; + case 49: recLWC1_coX(g_pCurInstInfo->numpeeps); break; + case 57: recSWC1_coX(g_pCurInstInfo->numpeeps); break; + case 55: recLD_coX(g_pCurInstInfo->numpeeps); break; + case 63: recSD_coX(g_pCurInstInfo->numpeeps); break; + default: + assert(0); + } + + pc += g_pCurInstInfo->numpeeps*4; + s_nBlockCycles += g_pCurInstInfo->numpeeps; + g_pCurInstInfo += g_pCurInstInfo->numpeeps; + } + else { + recBSC_co[cpuRegs.code>>26](); + pc += 4; + s_nBlockCycles++; + g_pCurInstInfo++; + } +#else + assert(0); +#endif + } + else { + assert( !(g_pCurInstInfo->info & EEINSTINFO_NOREC) ); + + // if this instruction is a jump or a branch, exit right away + if( delayslot ) { + switch(cpuRegs.code>>26) { + case 1: + switch(_Rt_) { + case 0: case 1: case 2: case 3: case 0x10: case 0x11: case 0x12: case 0x13: + SysPrintf("branch %x in delay slot!\n", cpuRegs.code); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + return; + } + break; + + case 2: case 3: case 4: case 5: case 6: case 7: case 0x14: case 0x15: case 0x16: case 0x17: + SysPrintf("branch %x in delay slot!\n", cpuRegs.code); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + return; + } + } + recBSC[ cpuRegs.code >> 26 ](); + } + + if( !delayslot ) { + if( s_bFlushReg ) { + //if( !_flushUnusedConstReg() ) { + int flushed = 0; + if( _getNumMMXwrite() > 3 ) flushed = _flushMMXunused(); + if( !flushed && _getNumXMMwrite() > 2 ) _flushXMMunused(); + s_bFlushReg = !flushed; +// } +// else s_bFlushReg = 0; + } + else s_bFlushReg = 1; + } + else s_bFlushReg = 1; + + //CHECK_XMMCHANGED(); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + +// _freeXMMregs(); +// _freeMMXregs(); +// _flushCachedRegs(); +// g_cpuHasConstReg = 1; +} + +//__declspec(naked) void iDummyBlock() +//{ +//// g_lastpc = cpuRegs.pc; +//// +//// do { +//// cpuRegs.cycle = g_nextBranchCycle; +//// cpuBranchTest(); +//// } while(g_lastpc == cpuRegs.pc); +//// +//// __asm jmp DispatcherReg +// __asm { +//RepDummy: +// add cpuRegs.cycle, 9 +// call cpuBranchTest +// cmp cpuRegs.pc, 0x81fc0 +// je RepDummy +// jmp DispatcherReg +// } +//} + +//////////////////////////////////////////////////// +#include "R3000A.h" +#include "PsxCounters.h" +#include "PsxMem.h" +extern tIPU_BP g_BP; + +extern u32 psxdump; +extern u32 psxNextCounter, psxNextsCounter; +extern void iDumpPsxRegisters(u32 startpc, u32 temp); +extern Counter counters[6]; +extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX +extern int rdram_sdevid; + +void iDumpRegisters(u32 startpc, u32 temp) +{ + int i; + char* pstr = temp ? "t" : ""; + const u32 dmacs[] = {0x8000, 0x9000, 0xa000, 0xb000, 0xb400, 0xc000, 0xc400, 0xc800, 0xd000, 0xd400 }; + extern char *disRNameGPR[]; + char* psymb; + + psymb = disR5900GetSym(startpc); + + if( psymb != NULL ) + __Log("%sreg(%s): %x %x c:%x\n", pstr, psymb, startpc, cpuRegs.interrupt, cpuRegs.cycle); + else + __Log("%sreg: %x %x c:%x\n", pstr, startpc, cpuRegs.interrupt, cpuRegs.cycle); + for(i = 1; i < 32; ++i) __Log("%s: %x_%x_%x_%x\n", disRNameGPR[i], cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0]); + //for(i = 0; i < 32; i+=4) __Log("cp%d: %x_%x_%x_%x\n", i, cpuRegs.CP0.r[i], cpuRegs.CP0.r[i+1], cpuRegs.CP0.r[i+2], cpuRegs.CP0.r[i+3]); + //for(i = 0; i < 32; ++i) __Log("%sf%d: %f %x\n", pstr, i, fpuRegs.fpr[i].f, fpuRegs.fprc[i]); + //for(i = 1; i < 32; ++i) __Log("%svf%d: %f %f %f %f, vi: %x\n", pstr, i, VU0.VF[i].F[3], VU0.VF[i].F[2], VU0.VF[i].F[1], VU0.VF[i].F[0], VU0.VI[i].UL); + for(i = 0; i < 32; ++i) __Log("%sf%d: %x %x\n", pstr, i, fpuRegs.fpr[i].UL, fpuRegs.fprc[i]); + for(i = 1; i < 32; ++i) __Log("%svf%d: %x %x %x %x, vi: %x\n", pstr, i, VU0.VF[i].UL[3], VU0.VF[i].UL[2], VU0.VF[i].UL[1], VU0.VF[i].UL[0], VU0.VI[i].UL); + __Log("%svfACC: %x %x %x %x\n", pstr, VU0.ACC.UL[3], VU0.ACC.UL[2], VU0.ACC.UL[1], VU0.ACC.UL[0]); + __Log("%sLO: %x_%x_%x_%x, HI: %x_%x_%x_%x\n", pstr, cpuRegs.LO.UL[3], cpuRegs.LO.UL[2], cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], + cpuRegs.HI.UL[3], cpuRegs.HI.UL[2], cpuRegs.HI.UL[1], cpuRegs.HI.UL[0]); + __Log("%sCycle: %x %x, Count: %x\n", pstr, cpuRegs.cycle, g_nextBranchCycle, cpuRegs.CP0.n.Count); + iDumpPsxRegisters(psxRegs.pc, temp); + + __Log("f410,30,40: %x %x %x, %d %d\n", psHu32(0xf410), psHu32(0xf430), psHu32(0xf440), rdram_sdevid, rdram_devices); + __Log("cyc11: %x %x; vu0: %x, vu1: %x\n", cpuRegs.sCycle[1], cpuRegs.eCycle[1], VU0.cycle, VU1.cycle); + + __Log("%scounters: %x %x; psx: %x %x\n", pstr, nextsCounter, nextCounter, psxNextsCounter, psxNextCounter); + for(i = 0; i < 4; ++i) { + __Log("eetimer%d: count: %x mode: %x target: %x %x; %x %x; %x %x %x %x\n", i, + counters[i].count, counters[i].mode, counters[i].target, counters[i].hold, counters[i].rate, + counters[i].interrupt, counters[i].Cycle, counters[i].sCycle, counters[i].CycleT, counters[i].sCycleT); + } + __Log("VIF0_STAT = %x, VIF1_STAT = %x\n", psHu32(0x3800), psHu32(0x3C00)); + __Log("ipu %x %x %x %x; bp: %x %x %x %x\n", psHu32(0x2000), psHu32(0x2010), psHu32(0x2020), psHu32(0x2030), g_BP.BP, g_BP.bufferhasnew, g_BP.FP, g_BP.IFC); + __Log("gif: %x %x %x\n", psHu32(0x3000), psHu32(0x3010), psHu32(0x3020)); + for(i = 0; i < ARRAYSIZE(dmacs); ++i) { + DMACh* p = (DMACh*)(PS2MEM_HW+dmacs[i]); + __Log("dma%d c%x m%x q%x t%x s%x\n", i, p->chcr, p->madr, p->qwc, p->tadr, p->sadr); + } + __Log("dmac %x %x %x %x\n", psHu32(DMAC_CTRL), psHu32(DMAC_STAT), psHu32(DMAC_RBSR), psHu32(DMAC_RBOR)); + __Log("intc %x %x\n", psHu32(INTC_STAT), psHu32(INTC_MASK)); + __Log("sif: %x %x %x %x %x\n", psHu32(0xf200), psHu32(0xf220), psHu32(0xf230), psHu32(0xf240), psHu32(0xf260)); +} + +extern u32 psxdump; + +static void printfn() +{ + static int lastrec = 0; + static int curcount = 0, count2 = 0; + const int skip = 0; + static int i; + + assert( !g_globalMMXSaved ); + assert( !g_globalXMMSaved ); + + if( (dumplog&2) && g_lastpc != 0x81fc0 ) {//&& lastrec != g_lastpc ) { + curcount++; + + if( curcount > skip ) { + iDumpRegisters(g_lastpc, 1); + curcount = 0; + } + + lastrec = g_lastpc; + } +} + +u32 s_recblocks[] = {0}; + +void badespfn() { + assert(0); + SysPrintf("Bad esp!\n"); +} + +#define OPTIMIZE_COP2 0//CHECK_VU0REC + +void recRecompile( u32 startpc ) +{ + u32 i = 0; + u32 branchTo; + u32 willbranch3 = 0; + u32* ptr; + u32 usecop2; + +#ifdef _DEBUG + //dumplog |= 4; + if( dumplog & 4 ) + iDumpRegisters(startpc, 0); +#endif + + assert( startpc ); + + // if recPtr reached the mem limit reset whole mem + if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { + recReset(); + } + if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) { +#ifdef _DEBUG + SysPrintf("stack reset\n"); +#endif + recReset(); + } + + s_pCurBlock = PC_GETBLOCK(startpc); + + if( s_pCurBlock->pFnptr ) { + // clear if already taken + assert( s_pCurBlock->startpc < startpc ); + recClearMem(s_pCurBlock); + } + + if( s_pCurBlock->startpc == startpc ) { + s_pCurBlockEx = PC_GETBLOCKEX(s_pCurBlock); + assert( s_pCurBlockEx->startpc == startpc ); + } + else { + s_pCurBlockEx = NULL; + for(i = 0; i < EE_NUMBLOCKS; ++i) { + if( recBlocks[(i+s_nNextBlock)%EE_NUMBLOCKS].size == 0 ) { + s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%EE_NUMBLOCKS; + s_nNextBlock = (i+s_nNextBlock+1)%EE_NUMBLOCKS; + break; + } + } + + if( s_pCurBlockEx == NULL ) { + //SysPrintf("ee reset (blocks)\n"); + recReset(); + s_nNextBlock = 0; + s_pCurBlockEx = recBlocks; + } + + s_pCurBlockEx->startpc = startpc; + } + + x86SetPtr( recPtr ); + x86Align(16); + recPtr = x86Ptr; + s_pCurBlock->pFnptr = (u32)x86Ptr; + s_pCurBlock->startpc = startpc; + + // slower +// if( startpc == 0x81fc0 ) { +// +// MOV32MtoR(ECX, (u32)&g_nextBranchCycle); +// MOV32RtoM((u32)&cpuRegs.cycle, ECX); +// //ADD32ItoR(ECX, 9); +// //ADD32ItoM((u32)&cpuRegs.cycle, 512); +// CALLFunc((u32)cpuBranchTest); +// CMP32ItoM((u32)&cpuRegs.pc, 0x81fc0); +// JE8(s_pCurBlock->pFnptr - (u32)(x86Ptr+2) ); +// JMP32((u32)DispatcherReg - (u32)(x86Ptr+5)); +// +// pc = startpc + 9*4; +// assert( (pc-startpc)>>2 <= 0xffff ); +// s_pCurBlockEx->size = (pc-startpc)>>2; +// +// for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { +// s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; +// s_pCurBlock[i].startpc = s_pCurBlock->startpc; +// } +// +// // don't overwrite if delay slot +// if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { +// s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; +// s_pCurBlock[i].startpc = s_pCurBlock->startpc; +// } +// +// // set the block ptr +// AddBaseBlockEx(s_pCurBlockEx, 0); +// +// if( !(pc&0x10000000) ) +// maxrecmem = max( (pc&~0xa0000000), maxrecmem ); +// +// recPtr = x86Ptr; +// return; +// } + + branch = 0; + + // reset recomp state variables + s_nBlockCycles = 0; + pc = startpc; + x86FpuState = FPU_STATE; + iCWstate = 0; + s_saveConstGPRreg = 0; + g_cpuHasConstReg = g_cpuFlushedConstReg = 1; + g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff; + g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0; + _recClearWritebacks(); + assert( g_cpuConstRegs[0].UD[0] == 0 ); + + _initX86regs(); + _initXMMregs(); + _initMMXregs(); + +#ifdef _DEBUG + // for debugging purposes + MOV32ItoM((u32)&g_lastpc, pc); + CALLFunc((u32)printfn); + +// CMP32MtoR(EBP, (u32)&s_uSaveEBP); +// j8Ptr[0] = JE8(0); +// CALLFunc((u32)badespfn); +// x86SetJ8(j8Ptr[0]); +#endif + + // go until the next branch + i = startpc; + s_nEndBlock = 0xffffffff; + s_nHasDelay = 0; + + while(1) { + BASEBLOCK* pblock = PC_GETBLOCK(i); + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( i == pblock->startpc ) { + // branch = 3 + willbranch3 = 1; + s_nEndBlock = i; + break; + } + } + + cpuRegs.code = *(int *)PSM(i); + + switch(cpuRegs.code >> 26) { + case 0: // special + + if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR + s_nEndBlock = i + 8; + s_nHasDelay = 1; + goto StartRecomp; + } + + break; + case 1: // regimm + + if( _Rt_ < 4 || (_Rt_ >= 16 && _Rt_ < 20) ) { + // branches + if( _Rt_ == 2 && _Rt_ == 3 && _Rt_ == 18 && _Rt_ == 19 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + break; + + case 2: // J + case 3: // JAL + s_nHasDelay = 1; + s_nEndBlock = i + 8; + goto StartRecomp; + + // branches + case 4: case 5: case 6: case 7: + case 20: case 21: case 22: case 23: + + if( (cpuRegs.code >> 26) >= 20 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + + case 16: // cp0 + if( _Rs_ == 16 ) { + if( _Funct_ == 24 ) { // eret + s_nEndBlock = i+4; + goto StartRecomp; + } + } + + break; + case 17: // cp1 + case 18: // cp2 + if( _Rs_ == 8 ) { + // BC1F, BC1T, BC1FL, BC1TL + // BC2F, BC2T, BC2FL, BC2TL + if( _Rt_ >= 2 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + break; + } + + i += 4; + } + +StartRecomp: + + // rec info // + { + EEINST* pcur; + + if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { + free(s_pInstCache); + s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; + s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); + assert( s_pInstCache != NULL ); + } + + pcur = s_pInstCache + (s_nEndBlock-startpc)/4; + _recClearInst(pcur); + pcur->info = 0; + + for(i = s_nEndBlock; i > startpc; i -= 4 ) { + cpuRegs.code = *(int *)PSM(i-4); + pcur[-1] = pcur[0]; + rpropBSC(pcur-1, pcur); + pcur--; + } + } + + // analyze instructions // + { + usecop2 = 0; + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock; i += 4) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(i); + + // cop2 // + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + + if( !usecop2 ) { + // init + if( OPTIMIZE_COP2 ) { + memset(VU0.fmac,0,sizeof(VU0.fmac)); + memset(&VU0.fdiv,0,sizeof(VU0.fdiv)); + memset(&VU0.efu,0,sizeof(VU0.efu)); + } + vucycle = 0; + usecop2 = 1; + } + + VU0.code = cpuRegs.code; + _cop2AnalyzeOp(g_pCurInstInfo, OPTIMIZE_COP2); + continue; + } + + if( usecop2 ) vucycle++; + + // peephole optimizations // +#ifdef PCSX2_VIRTUAL_MEM + if( i < s_nEndBlock-4 && recompileCodeSafe(i) ) { + u32 curcode = cpuRegs.code; + u32 nextcode = *(u32*)PSM(i+4); + if( _eeIsLoadStoreCoIssue(curcode, nextcode) && recBSC_co[curcode>>26] != NULL ) { + + // rs has to be the same, and cannot be just written + if( ((curcode >> 21) & 0x1F) == ((nextcode >> 21) & 0x1F) && !_eeLoadWritesRs(curcode) ) { + + if( _eeIsLoadStoreCoX(curcode) && ((nextcode>>16)&0x1f) != ((curcode>>21)&0x1f) ) { + // see how many stores there are + u32 j; + // use xmmregs since only supporting lwc1,lq,swc1,sq + for(j = i+8; j < s_nEndBlock && j < i+4*XMMREGS; j += 4 ) { + u32 nncode = *(u32*)PSM(j); + if( (nncode>>26) != (curcode>>26) || ((curcode>>21)&0x1f) != ((nncode>>21)&0x1f) || + _eeLoadWritesRs(nncode)) + break; + } + + if( j > i+8 ) { + u32 num = (j-i)>>2; // number of stores that can coissue + assert( num <= XMMREGS ); + + g_pCurInstInfo[0].numpeeps = num-1; + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + + while(i < j-4) { + g_pCurInstInfo++; + g_pCurInstInfo[0].info |= EEINSTINFO_NOREC; + i += 4; + } + + continue; + } + + // fall through + } + + // unaligned loadstores + + // if LWL, check if LWR and that offsets are +3 away + switch(curcode >> 26) { + case 0x22: // LWL + if( (nextcode>>26) != 0x26 || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x26: // LWR + if( (nextcode>>26) != 0x22 || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x2a: // SWL + if( (nextcode>>26) != 0x2e || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x2e: // SWR + if( (nextcode>>26) != 0x2a || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x1a: // LDL + if( (nextcode>>26) != 0x1b || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x1b: // LWR + if( (nextcode>>26) != 0x1aa || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + + case 0x2c: // SWL + if( (nextcode>>26) != 0x2d || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x2d: // SWR + if( (nextcode>>26) != 0x2c || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + } + + // good enough + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + g_pCurInstInfo[0].numpeeps = 1; + g_pCurInstInfo[1].info |= EEINSTINFO_NOREC; + g_pCurInstInfo++; + i += 4; + continue; + } + } + } +#endif // end peephole + } + + if( usecop2 ) { + // add necessary mac writebacks + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock-4; i += 4) { + g_pCurInstInfo++; + + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + } + } + } + } + + // perf counters // +#ifdef PCSX2_DEVBUILD + s_startcount = 0; +// if( pc+32 < s_nEndBlock ) { +// // only blocks with more than 8 insts +// //PUSH32I((u32)&lbase); +// //CALLFunc((u32)QueryPerformanceCounter); +// lbase.QuadPart = GetCPUTick(); +// s_startcount = 1; +// } +#endif + +#ifdef _DEBUG + // dump code + for(i = 0; i < ARRAYSIZE(s_recblocks); ++i) { + if( startpc == s_recblocks[i] ) { + iDumpBlock(startpc, recPtr); + } + } + + if( (dumplog & 1) ) //|| usecop2 ) + iDumpBlock(startpc, recPtr); +#endif + + // finally recompile // + g_pCurInstInfo = s_pInstCache; + while (!branch && pc < s_nEndBlock) { + recompileNextInstruction(0); + } + +#ifdef _DEBUG + if( (dumplog & 1) ) + iDumpBlock(startpc, recPtr); +#endif + + assert( (pc-startpc)>>2 <= 0xffff ); + s_pCurBlockEx->size = (pc-startpc)>>2; + + for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // don't overwrite if delay slot + if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // set the block ptr + AddBaseBlockEx(s_pCurBlockEx, 0); +// if( p[1].startpc == p[0].startpc + 4 ) { +// assert( p[1].pFnptr != 0 ); +// // already fn in place, so add to list +// AddBaseBlockEx(s_pCurBlockEx, 0); +// } +// else +// *(BASEBLOCKEX**)(p+1) = pex; +// } + + //PC_SETBLOCKEX(s_pCurBlock, s_pCurBlockEx); + + if( !(pc&0x10000000) ) + maxrecmem = max( (pc&~0xa0000000), maxrecmem ); + + if( branch == 2 ) { + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(0xffffffff, 1); + if( bExecBIOS ) CheckForBIOSEnd(); + + JMP32((u32)DispatcherReg - ( (u32)x86Ptr + 5 )); + } + else { + assert( branch != 3 ); + if( branch ) assert( !willbranch3 ); + else ADD32ItoM((int)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); + + if( willbranch3 ) { + BASEBLOCK* pblock = PC_GETBLOCK(s_nEndBlock); + assert( pc == s_nEndBlock ); + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((u32)&cpuRegs.pc, pc); + JMP32((u32)pblock->pFnptr - ((u32)x86Ptr + 5)); + branch = 3; + } + else if( !branch ) { + // didn't branch, but had to stop + MOV32ItoM( (u32)&cpuRegs.pc, pc ); + + iFlushCall(FLUSH_EVERYTHING); + + ptr = JMP32(0); + } + } + + assert( x86Ptr >= (s8*)s_pCurBlock->pFnptr + EE_MIN_BLOCK_BYTES ); + assert( x86Ptr < recMem+REC_CACHEMEM ); + assert( recStackPtr < recStack+RECSTACK_SIZE ); + assert( x86FpuState == 0 ); + + recPtr = x86Ptr; + + assert( (g_cpuHasConstReg&g_cpuFlushedConstReg) == g_cpuHasConstReg ); + + if( !branch ) { + BASEBLOCK* pcurblock = s_pCurBlock; + u32 nEndBlock = s_nEndBlock; + s_pCurBlock = PC_GETBLOCK(pc); + assert( ptr != NULL ); + + if( s_pCurBlock->startpc != pc ) + recRecompile(pc); + + if( pcurblock->startpc == startpc ) { + assert( pcurblock->pFnptr ); + assert( s_pCurBlock->startpc == nEndBlock ); + *ptr = s_pCurBlock->pFnptr - ( (u32)ptr + 4 ); + } + else { + recRecompile(startpc); + assert( pcurblock->pFnptr != 0 ); + } + } +} + +R5900cpu recCpu = { + recInit, + recReset, + recStep, + recExecute, + recExecuteBlock, + recExecuteVU0Block, + recExecuteVU1Block, + recEnableVU0micro, + recEnableVU1micro, + recClear, + recClearVU0, + recClearVU1, + recShutdown +}; + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900Arit.c b/pcsx2/x86/ix86-32/iR5900Arit.c new file mode 100644 index 0000000000..e1d21d5968 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900Arit.c @@ -0,0 +1,2001 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +// NOTE: The reason ADD/SUB/etc are so large is because they are very commonly +// used and recompiler needs to cover ALL possible usages to minimize code size (zerofrog) + +#ifndef ARITHMETIC_RECOMPILE + +REC_FUNC(ADD); +REC_FUNC(ADDU); +REC_FUNC(DADD); +REC_FUNC(DADDU); +REC_FUNC(SUB); +REC_FUNC(SUBU); +REC_FUNC(DSUB); +REC_FUNC(DSUBU); +REC_FUNC(AND); +REC_FUNC(OR); +REC_FUNC(XOR); +REC_FUNC(NOR); +REC_FUNC(SLT); +REC_FUNC(SLTU); + +#elif defined(EE_CONST_PROP) + +//// ADD +void recADD_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] + g_cpuConstRegs[_Rt_].SL[0]; +} + +void recADD_constv(int info, int creg, int vreg) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] ) { + u32* ptempmem; + + ptempmem = _eeGetConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PADDDMtoR(EEREC_D, (u32)ptempmem); + + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + // just move and sign extend + if( EEINST_HASLIVE1(vreg) ) { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + else { + _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, mmreg, vreg); + } + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[ creg ].UL[0]) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + if( EEINST_HASLIVE1(vreg) && EEINST_ISLIVE1(_Rd_) ) { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[creg].UL[0] ) { + MOVDMtoMMX(mmreg, (u32)_eeGetConstReg(creg)); + PADDDMtoR(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) { + _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } + else { + if( _Rd_ == vreg ) { + ADD32ItoM((int)&cpuRegs.GPR.r[_Rd_].UL[ 0 ], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + if( g_cpuConstRegs[ creg ].UL[0] ) + ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[0] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +// s is constant +void recADD_consts(int info) +{ + recADD_constv(info, _Rs_, _Rt_); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rt_); +} + +// t is constant +void recADD_constt(int info) +{ + recADD_constv(info, _Rt_, _Rs_); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); +} + +// nothing is constant +void recADD_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PADDDRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PADDDRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_T); + PADDDRtoR(EEREC_D, EEREC_S); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + // sign extend + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + EEINST_RESETHASLIVE1(_Rd_); + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); + PADDDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); + } + else { + if( _Rd_ == _Rs_ ) { + if( _Rd_ == _Rt_ ) SHL32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 1); // mult by 2 + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + } + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + + return; + } + else if( _Rd_ == _Rt_ ) { + EEINST_RESETHASLIVE1(_Rd_); + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( _Rs_ != _Rt_ ) ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else SHL32ItoR(EAX, 1); // mult by 2 + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +EERECOMPILE_CODE0(ADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//// ADDU +void recADDU( void ) +{ + recADD( ); +} + +//// DADD +void recDADD_const( void ) +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] + g_cpuConstRegs[_Rt_].SD[0]; +} + +void recDADD_constv(int info, int creg, int vreg) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( g_cpuConstRegs[ creg ].UD[0] ) { + + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PADDQMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + if( g_cpuConstRegs[ creg ].UD[0] ) PADDQMtoR(mmreg, (u32)_eeGetConstReg(creg)); + } + else { + + if( g_cpuConstRegs[ creg ].UL[0] == 0 && g_cpuConstRegs[ creg ].UL[1] == 0 && _hasFreeMMXreg() ) { + // copy + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + if( EEINST_ISLIVE1(_Rd_) ) MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + else { + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + if( _Rd_ == vreg ) { + + if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ creg ].UL[ 0 ] || g_cpuConstRegs[ creg ].UL[ 1 ]) ) { + ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); + ADC32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ creg ].UL[ 1 ] ); + } + else if( g_cpuConstRegs[ creg ].UL[ 0 ] ) { + EEINST_RESETHASLIVE1(_Rd_); + ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); + } + + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32ItoR( EDX, g_cpuConstRegs[ creg ].UL[ 1 ] ); + } + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDADD_consts(int info) +{ + recDADD_constv(info, _Rs_, _Rt_); +} + +void recDADD_constt(int info) +{ + recDADD_constv(info, _Rt_, _Rs_); +} + +void recDADD_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( EEREC_D == EEREC_S ) PADDQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PADDQRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_T); + PADDQRtoR(EEREC_D, EEREC_S); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if( _Rs_ != _Rt_ ) PADDQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else PSLLQItoR(mmreg, 1); // mult by 2 + } + else { + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +EERECOMPILE_CODE0(DADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//// DADDU +void recDADDU( void ) +{ + recDADD( ); +} + +//// SUB + +void recSUB_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] - g_cpuConstRegs[_Rt_].SL[0]; +} + +void recSUB_consts(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + if( g_cpuConstRegs[ _Rs_ ].UL[0] ) { + + if( EEREC_D != EEREC_T ) { + MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + PSUBDRtoR(EEREC_D, EEREC_T); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVDMtoMMX(t0reg, (u32)_eeGetConstReg(_Rs_)); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + // just move and sign extend + if( EEREC_D != EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + PSUBDRtoR(EEREC_D, EEREC_T); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + } + else { + if( _Rd_ == _Rt_ ) { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) SUB32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rs_ ].UL[ 0 ]); + NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) { + MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + NEG32R(EAX); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } +} + +void recSUB_constt(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + if( g_cpuConstRegs[ _Rt_ ].UL[0] ) { + + u32* ptempmem = _eeGetConstReg(_Rt_); + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PSUBDMtoR(EEREC_D, (u32)ptempmem); + + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + // just move and sign extend + if( EEINST_HASLIVE1(_Rs_) ) { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + } + else { + _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, EEREC_S, _Rs_); + } + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[_Rt_].UL[0]) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + if( EEINST_HASLIVE1(_Rs_) && EEINST_ISLIVE1(_Rd_) ) { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[_Rt_].UL[0] ) { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PSUBDMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) { + _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + else { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } + else { + if( _Rd_ == _Rs_ ) { + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { + SUB32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rt_ ].UL[ 0 ]); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) + SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +void recSUB_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PSUBDRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + info = (info&~PROCESS_EE_SET_D(0xf))|PROCESS_EE_SET_D(t0reg); + } + else { + MOVQRtoR(EEREC_D, EEREC_S); + PSUBDRtoR(EEREC_D, EEREC_T); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + // sign extend + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_)) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + EEINST_RESETHASLIVE1(_Rd_); + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); + PSUBDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); + } + else { + if( !EEINST_ISLIVE1(_Rd_) ) { + if( _Rd_ == _Rs_) { + EEINST_RESETHASLIVE1(_Rd_); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + return; + } + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } +} + +EERECOMPILE_CODE0(SUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SUBU +void recSUBU( void ) +{ + recSUB( ); +} + +//// DSUB +void recDSUB_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] - g_cpuConstRegs[_Rt_].SD[0]; +} + +void recDSUB_consts(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( g_cpuConstRegs[ _Rs_ ].UD[0] ) { + + // flush + if( EEREC_D != EEREC_T ) { + MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + PSUBQRtoR(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (u32)_eeGetConstReg(_Rs_)); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + } + else { + // just move and sign extend + if( EEREC_D != EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + PSUBQRtoR(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (u32)_eeGetConstReg(_Rs_)); + PSUBQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] || g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ) { + MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32ItoR( EDX, g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + else { + + if( _Rd_ == _Rt_ ) { + // negate _Rt_ all in memory + if( EEINST_ISLIVE1(_Rd_) ) { + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + NEG32M((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + ADC32ItoR(EDX, 0); + NEG32R(EDX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); + } + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + // take negative of 64bit number + NEG32R(EAX); + + if( EEINST_ISLIVE1(_Rd_) ) { + ADC32ItoR(EDX, 0); + NEG32R(EDX); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDSUB_constt(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( g_cpuConstRegs[ _Rt_ ].UD[0] ) { + + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PSUBQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rt_)); + } + else { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if( g_cpuConstRegs[_Rt_].UD[0] ) PSUBQMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); + } + else { + + if( _Rd_ == _Rs_ ) { + if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ]) ) { + SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + SBB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); + } + else if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { + EEINST_RESETHASLIVE1(_Rd_); + SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + } + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ) { + SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32ItoR( EDX, g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDSUB_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( EEREC_D == EEREC_S ) PSUBQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + MOVQRtoR(EEREC_D, EEREC_S); + PSUBQRtoR(EEREC_D, EEREC_T); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[ 0 ]); + PSUBQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); + } + else { + if( _Rd_ == _Rs_ ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +EERECOMPILE_CODE0(DSUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSUBU +void recDSUBU( void ) +{ + recDSUB( ); +} + +//// AND +void recAND_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & g_cpuConstRegs[_Rt_].UD[0]; +} + +void recAND_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PANDMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + PXORRtoR(EEREC_D, EEREC_D); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + PANDMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + else { + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + + if( _Rd_ == vreg ) { + AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] != 0xffffffff ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + AND32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) + AND32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ], 0); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, 0); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recAND_consts(int info) +{ + recAND_constv(info, _Rs_, _Rt_); +} + +void recAND_constt(int info) +{ + recAND_constv(info, _Rt_, _Rs_); +} + +void recLogicalOp(int info, int op) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + if( EEREC_D == EEREC_S ) LogicalOpRtoR(EEREC_D, EEREC_T, op); + else if( EEREC_D == EEREC_T ) LogicalOpRtoR(EEREC_D, EEREC_S, op); + else { + MOVQRtoR(EEREC_D, EEREC_S); + LogicalOpRtoR(EEREC_D, EEREC_T, op); + } + } + else if( (g_pCurInstInfo->regs[_Rs_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int rsreg, rtreg, rdreg; + _addNeededMMXreg(MMX_GPR+_Rs_); + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + rsreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + rtreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + SetMMXstate(); + + if( rdreg == rsreg ) { + if( rtreg >= 0 ) LogicalOpRtoR(rdreg, rtreg, op); + else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ], op); + } + else { + if( rdreg != rtreg ) { + if( rtreg >= 0 ) MOVQRtoR(rdreg, rtreg); + else MOVQMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ]); + } + + if( rsreg >= 0 ) LogicalOpRtoR(rdreg, rsreg, op); + else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rs_ ], op); + } + } + else { + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX, op ); + if( EEINST_ISLIVE1(_Rd_) ) + LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ] + 4, EDX, op ); + if( op == 3 ) { + NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]+4); + } + + if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ] + 4 ); + LogicalOp32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ], op ); + if( EEINST_ISLIVE1(_Rd_) ) + LogicalOp32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ] + 4, op ); + + if( op == 3 ) { + NOT32R(EAX); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32R(ECX); + } + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } +} + +void recAND_(int info) +{ + recLogicalOp(info, 0); +} + +EERECOMPILE_CODE0(AND, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// OR +void recOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]; +} + +void recOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + } + else { + if( _Rd_ == vreg ) { + OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + + if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recOR_consts(int info) +{ + recOR_constv(info, _Rs_, _Rt_); +} + +void recOR_constt(int info) +{ + recOR_constv(info, _Rt_, _Rs_); +} + +void recOR_(int info) +{ + recLogicalOp(info, 1); +} + +EERECOMPILE_CODE0(OR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// XOR +void recXOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ g_cpuConstRegs[_Rt_].UD[0]; +} + +void recXOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PXORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + PXORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + } + else { + if( _Rd_ == vreg ) { + XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + + if( g_cpuConstRegs[ creg ].UL[0] ) XOR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) XOR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recXOR_consts(int info) +{ + recXOR_constv(info, _Rs_, _Rt_); +} + +void recXOR_constt(int info) +{ + recXOR_constv(info, _Rt_, _Rs_); +} + +void recXOR_(int info) +{ + recLogicalOp(info, 2); +} + +EERECOMPILE_CODE0(XOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// NOR +void recNOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] =~(g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]); +} + +void recNOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PORMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + + // take the NOT + PCMPEQDRtoR( t0reg,t0reg); + PXORRtoR( EEREC_D,t0reg); + _freeMMXreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + PCMPEQDRtoR( t0reg,t0reg); + if( g_cpuConstRegs[ creg ].UD[0] ) PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + + // take the NOT + PXORRtoR( rdreg,t0reg); + + _freeMMXreg(t0reg); + } + else { + if( _Rd_ == vreg ) { + NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[1]); + + if( g_cpuConstRegs[creg].UL[0] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], ~g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], ~g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + NOT32R(EAX); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32R(ECX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recNOR_consts(int info) +{ + recNOR_constv(info, _Rs_, _Rt_); +} + +void recNOR_constt(int info) +{ + recNOR_constv(info, _Rt_, _Rs_); +} + +void recNOR_(int info) +{ + recLogicalOp(info, 3); +} + +EERECOMPILE_CODE0(NOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SLT - test with silent hill, lemans +void recSLT_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < g_cpuConstRegs[_Rt_].SD[0]; +} + +static u32 s_sltconst = 0x80000000; +static u32 s_sltconst64[2] = {0, 0x80000000}; +u32 s_sltone = 1; + +void recSLTs_consts(int info, int sign) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( _Rs_ == _Rt_ ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( g_cpuConstRegs[_Rs_].UL[1] == (g_cpuConstRegs[_Rs_].SL[0]<0?0xffffffff:0) && EEINST_ISSIGNEXT(_Rt_) ) { + // just compare the lower values + if( sign ) { + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PCMPGTDMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } + else { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = g_cpuConstRegs[_Rs_].UL[0]^0x80000000; + ptempmem[1] = 0; + + if( EEREC_D != EEREC_T ) { + MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); + PXORRtoR(EEREC_D, EEREC_T); + } + else { + PXORMtoR(EEREC_D, (u32)&s_sltconst); + } + + PCMPGTDMtoR(EEREC_D, (u32)ptempmem); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } + + return; + } + else { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + + // fall through + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + } + } + + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + CMP32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + j8Ptr[1] = JBE8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +// SLT with one operand coming from mem (compares only low 32 bits) +void recSLTmemconstt(int regd, int regs, u32 mem, int sign) +{ + // just compare the lower values + int t0reg; + + if( sign ) { + if( regd == regs ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, mem); + PCMPGTDRtoR(t0reg, regs); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[regd]; + mmxregs[regd].inuse = 0; + } + else { + MOVQMtoR(regd, mem); + PCMPGTDRtoR(regd, regs); + + PUNPCKLDQRtoR(regd, regd); + PSRLQItoR(regd, 63); + } + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( regd == regs ) { + MOVQMtoR(t0reg, mem); + PXORMtoR(regs, (u32)&s_sltconst); + PCMPGTDRtoR(t0reg, regs); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[regd]; + mmxregs[regd].inuse = 0; + } + else { + MOVQRtoR(t0reg, regs); + MOVQMtoR(regd, mem); + PXORMtoR(t0reg, (u32)&s_sltconst); + PCMPGTDRtoR(regd, t0reg); + + PUNPCKLDQRtoR(regd, regd); + PSRLQItoR(regd, 63); + _freeMMXreg(t0reg); + } + } +} + +void recSLTs_constt(int info, int sign) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + if( _Rs_ == _Rt_ ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( EEINST_ISSIGNEXT(_Rs_) && g_cpuConstRegs[_Rt_].UL[1] == (g_cpuConstRegs[_Rt_].SL[0]<0?0xffffffff:0) ) { + // just compare the lower values + if( sign ) { + recSLTmemconstt(EEREC_D, EEREC_S, (u32)_eeGetConstReg(_Rt_), 1); + } + else { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = g_cpuConstRegs[_Rt_].UL[0]^0x80000000; + ptempmem[1] = 0; + + recSLTmemconstt(EEREC_D, EEREC_S, (u32)ptempmem, 0); + } + + return; + } + else { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + + // fall through + } + } + + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + CMP32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLTs_(int info, int sign) +{ + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLT_consts(int info) +{ + recSLTs_consts(info, 1); +} + +void recSLT_constt(int info) +{ + recSLTs_constt(info, 1); +} + +void recSLT_(int info) +{ + int t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( !(info & PROCESS_EE_MMX) ) { + recSLTs_(info, 1); + return; + } + + if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + recSLTs_(info, 1); + return; + } + + if( EEREC_S == EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + // just compare the lower values + if( EEREC_D == EEREC_S ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_T); + PCMPGTDRtoR(t0reg, EEREC_S); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PCMPGTDRtoR(EEREC_D, EEREC_S); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } +} + +EERECOMPILE_CODE0(SLT, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +// SLTU - test with silent hill, lemans +void recSLTU_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < g_cpuConstRegs[_Rt_].UD[0]; +} + +void recSLTU_consts(int info) +{ + recSLTs_consts(info, 0); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLTU_constt(int info) +{ + recSLTs_constt(info, 0); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLTU_(int info) +{ + int t1reg; + + assert( !(info & PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rd_); + + if( !(info & PROCESS_EE_MMX) ) { + recSLTs_(info, 0); + return; + } + + if( EEREC_S == EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + recSLTs_(info, 0); + return; + } + + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOVDMtoMMX(t1reg, (u32)&s_sltconst); + + if( EEREC_D == EEREC_S ) { + PXORRtoR(EEREC_S, t1reg); + PXORRtoR(t1reg, EEREC_T); + PCMPGTDRtoR(t1reg, EEREC_S); + + PUNPCKLDQRtoR(t1reg, t1reg); + PSRLQItoR(t1reg, 63); + + // swap regs + mmxregs[t1reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + if( EEREC_D != EEREC_T ) { + MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); + PXORRtoR(t1reg, EEREC_S); + PXORRtoR(EEREC_D, EEREC_T); + } + else { + PXORRtoR(EEREC_D, t1reg); + PXORRtoR(t1reg, EEREC_S); + } + + PCMPGTDRtoR(EEREC_D, t1reg); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + + _freeMMXreg(t1reg); + } +} + +EERECOMPILE_CODE0(SLTU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +#else + +//////////////////////////////////////////////////// +void recADD( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recADDU( void ) +{ + recADD( ); +} + +//////////////////////////////////////////////////// +void recDADD( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recDADDU( void ) +{ + recDADD( ); +} + +//////////////////////////////////////////////////// +void recSUB( void ) +{ + if ( ! _Rd_ ) return; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSUBU( void ) +{ + recSUB( ); +} + +//////////////////////////////////////////////////// +void recDSUB( void ) +{ + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDSUBU( void ) +{ + recDSUB( ); +} + +//////////////////////////////////////////////////// +void recAND( void ) +{ + if ( ! _Rd_ ) + { + return; + } + if ( ( _Rt_ == 0 ) || ( _Rs_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + } + else + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PANDRtoR( MM0, MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + +} + +//////////////////////////////////////////////////// +void recOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0x0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0x0 ); + } + else if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + else if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + else + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PORRtoR( MM0, MM1 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } +} + +//////////////////////////////////////////////////// +void recXOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0x0); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0x0); + return; + } + + if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + return; + } + + if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PXORRtoR( MM0, MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recNOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0xffffffff); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0xffffffff); + return; + } + + if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PCMPEQDRtoR( MM1,MM1); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); + return; + } + + if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + PCMPEQDRtoR( MM1,MM1); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + PCMPEQDRtoR( MM1,MM1); + PORMtoR( MM0,(int)&cpuRegs.GPR.r[ _Rt_ ] ); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +// test with silent hill, lemans +void recSLT( void ) +{ + if ( ! _Rd_ ) + return; + + MOV32ItoR(EAX, 1); + + if( _Rs_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); + j8Ptr[0] = JG8( 0 ); + j8Ptr[2] = JL8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + j8Ptr[1] = JA8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else if( _Rt_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recSLTU( void ) +{ + MOV32ItoR(EAX, 1); + + if( _Rs_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); + j8Ptr[0] = JA8( 0 ); + j8Ptr[2] = JB8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + j8Ptr[1] = JA8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else if( _Rt_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900AritImm.c b/pcsx2/x86/ix86-32/iR5900AritImm.c new file mode 100644 index 0000000000..c61be65d45 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900AritImm.c @@ -0,0 +1,663 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ + +#ifndef ARITHMETICIMM_RECOMPILE + +REC_FUNC(ADDI); +REC_FUNC(ADDIU); +REC_FUNC(DADDI); +REC_FUNC(DADDIU); +REC_FUNC(ANDI); +REC_FUNC(ORI); +REC_FUNC(XORI); + +REC_FUNC(SLTI); +REC_FUNC(SLTIU); + +#elif defined(EE_CONST_PROP) + +//// ADDI +void recADDI_const( void ) +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] + _Imm_; +} + +void recADDI_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rs_); + + if( info & PROCESS_EE_MMX ) { + if( _Imm_ != 0 ) { + + u32* ptempmem = recAllocStackMem(4, 4); + ptempmem[0] = _Imm_; + + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + PADDDMtoR(EEREC_T, (u32)ptempmem); + if( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(EEREC_T, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + // just move and sign extend + if( !EEINST_HASLIVE1(_Rs_) ) { + + if( EEINST_ISLIVE1(_Rt_) ) + _signExtendGPRMMXtoMMX(EEREC_T, _Rt_, EEREC_S, _Rs_); + else + EEINST_RESETHASLIVE1(_Rt_); + } + else { + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + } + return; + } + + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && (_Rt_ != _Rs_) ) { + int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + SetMMXstate(); + + if( _Imm_ != 0 ) { + u32* ptempmem = recAllocStackMem(4, 4); + ptempmem[0] = _Imm_; + + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PADDDMtoR(rtreg, (u32)ptempmem); + + if( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + // just move and sign extend + if( !EEINST_HASLIVE1(_Rs_) ) { + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + } + } + else { + if( _Rt_ == _Rs_ ) { + ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); + if( EEINST_ISLIVE1(_Rt_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( EAX, _Imm_ ); + + if( EEINST_ISLIVE1(_Rt_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + } + } +} + +EERECOMPILE_CODEX(eeRecompileCode1, ADDI); + +//////////////////////////////////////////////////// +void recADDIU( void ) +{ + recADDI( ); +} + +//////////////////////////////////////////////////// +void recDADDI_const( void ) +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] + _Imm_; +} + +void recDADDI_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + assert( cpucaps.hasStreamingSIMD2Extensions ); + + if( _Imm_ != 0 ) { + + // flush + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _Imm_; + ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + PADDQMtoR(EEREC_T, (u32)ptempmem); + } + else { + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + return; + } + + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + int rtreg; + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _Imm_; + ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; + + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PADDQMtoR(rtreg, (u32)ptempmem); + } + else { + if( _Rt_ == _Rs_ ) { + ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); + ADC32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], _Imm_<0?0xffffffff:0); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rt_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + + if( EEINST_ISLIVE1(_Rt_) ) { + ADC32ItoR( EDX, _Imm_ < 0?0xffffffff:0); + } + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rt_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rt_); + } + } +} + +EERECOMPILE_CODEX(eeRecompileCode1, DADDI); + +//// DADDIU +void recDADDIU( void ) +{ + recDADDI( ); +} + +//// SLTIU +void recSLTIU_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < (u64)(_Imm_); +} + +extern void recSLTmemconstt(int regd, int regs, u32 mem, int sign); +extern u32 s_sltone; + +void recSLTIU_(int info) +{ + if( info & PROCESS_EE_MMX ) { + if( EEINST_ISSIGNEXT(_Rs_) ) { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = ((s32)(_Imm_))^0x80000000; + ptempmem[1] = 0; + recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 0); + EEINST_SETSIGNEXT(_Rt_); + return; + } + + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S + } + + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + EEINST_SETSIGNEXT(_Rt_); +} + +EERECOMPILE_CODEX(eeRecompileCode1, SLTIU); + +//// SLTI +void recSLTI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < (s64)(_Imm_); +} + +void recSLTI_(int info) +{ + if( info & PROCESS_EE_MMX) { + + if( EEINST_ISSIGNEXT(_Rs_) ) { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = _Imm_; + ptempmem[1] = 0; + recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 1); + EEINST_SETSIGNEXT(_Rt_); + return; + } + + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S + } + + // test silent hill if modding + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + EEINST_SETSIGNEXT(_Rt_); +} + +EERECOMPILE_CODEX(eeRecompileCode1, SLTI); + +//// ANDI +void recANDI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & (s64)_ImmU_; +} + +extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); +extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); +extern void LogicalOp32RtoM(u32 to, x86IntRegType from, int op); +extern void LogicalOp32MtoR(x86IntRegType to, u32 from, int op); +extern void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); +extern void LogicalOp32ItoM(u32 to, u32 from, int op); + +void recLogicalOpI(int info, int op) +{ + if( info & PROCESS_EE_MMX ) { + SetMMXstate(); + + if( _ImmU_ != 0 ) { + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _ImmU_; + ptempmem[1] = 0; + + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + LogicalOpMtoR(EEREC_T, (u32)ptempmem, op); + } + else { + if( op == 0 ) PXORRtoR(EEREC_T, EEREC_T); + else { + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + } + return; + } + + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && ((_Rt_ != _Rs_) || (_ImmU_==0)) ) { + int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + u32* ptempmem; + + SetMMXstate(); + + ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _ImmU_; + ptempmem[1] = 0; + + if( op == 0 ) { + if ( _ImmU_ != 0 ) { + if( _ImmU_ == 0xffff ) { + // take a shortcut + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] - 2); + PSRLDItoR(rtreg, 16); + } + else { + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PANDMtoR(rtreg, (u32)ptempmem); + } + } + else PXORRtoR(rtreg, rtreg); + } + else { + MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if ( _ImmU_ != 0 ) LogicalOpMtoR(rtreg, (u32)ptempmem, op); + } + } + else { + if ( _ImmU_ != 0 ) + { + if( _Rt_ == _Rs_ ) { + LogicalOp32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _ImmU_, op); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( op != 0 && EEINST_ISLIVE1(_Rt_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + LogicalOp32ItoR( EAX, _ImmU_, op); + if( op != 0 && EEINST_ISLIVE1(_Rt_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + + if( op == 0 ) { + if( EEINST_ISLIVE1(_Rt_ ) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + } + else + { + if( op == 0 ) { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + } + else { + if( _Rt_ != _Rs_ ) { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + } + + if( !EEINST_ISLIVE1(_Rt_) ) EEINST_RESETHASLIVE1(_Rt_); + } + } +} + +void recANDI_(int info) +{ + recLogicalOpI(info, 0); +} + +EERECOMPILE_CODEX(eeRecompileCode1, ANDI); + +//////////////////////////////////////////////////// +void recORI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | (s64)_ImmU_; +} + +void recORI_(int info) +{ + recLogicalOpI(info, 1); +} + +EERECOMPILE_CODEX(eeRecompileCode1, ORI); + +//////////////////////////////////////////////////// +void recXORI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ (s64)_ImmU_; +} + +void recXORI_(int info) +{ + recLogicalOpI(info, 2); +} + +EERECOMPILE_CODEX(eeRecompileCode1, XORI); + +#else + +//////////////////////////////////////////////////// +void recADDI( void ) +{ + if ( ! _Rt_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recADDIU( void ) +{ + recADDI( ); +} + +//////////////////////////////////////////////////// +void recDADDI( void ) +{ +#ifdef __x86_64_ + if ( ! _Rt_ ) + { + return; + } + + MOV64MtoR( RAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD64ItoR( EAX, _Imm_ ); + } + MOV64RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX ); +#else + if ( ! _Rt_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + if ( _Imm_ < 0 ) + { + ADC32ItoR( EDX, 0xffffffff ); + } + else + { + ADC32ItoR( EDX, 0 ); + } + } + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); +#endif +} + +//////////////////////////////////////////////////// +void recDADDIU( void ) +{ + recDADDI( ); +} + +//////////////////////////////////////////////////// +void recSLTIU( void ) +{ + if ( ! _Rt_ ) + return; + + MOV32ItoR(EAX, 1); + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recSLTI( void ) +{ + if ( ! _Rt_ ) + return; + + // test silent hill if modding + MOV32ItoR(EAX, 1); + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recANDI( void ) +{ + if ( ! _Rt_ ) + { + return; + } + if ( _ImmU_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( EAX, _ImmU_ ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + else + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + } + +} + +//////////////////////////////////////////////////// +static u64 _imm = 0; // temp immediate + +void recORI( void ) +{ + if ( ! _Rt_ ) + return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + if ( _ImmU_ != 0 ) + { + MOV32ItoM( (int)&_imm, _ImmU_ ); + MOVQMtoR( MM1, (int)&_imm ); + PORRtoR( MM0, MM1 ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recXORI( void ) +{ + if ( ! _Rt_ ) + return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + if ( _ImmU_ != 0 ) + { + MOV32ItoM( (int)&_imm, _ImmU_ ); + MOVQMtoR( MM1, (int)&_imm ); + PXORRtoR( MM0, MM1 ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ], MM0 ); + SetMMXstate(); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900Branch.c b/pcsx2/x86/ix86-32/iR5900Branch.c new file mode 100644 index 0000000000..a83099a3e5 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900Branch.c @@ -0,0 +1,1154 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#ifndef BRANCH_RECOMPILE + +REC_SYS(BEQ); +REC_SYS(BEQL); +REC_SYS(BNE); +REC_SYS(BNEL); +REC_SYS(BLTZ); +REC_SYS(BGTZ); +REC_SYS(BLEZ); +REC_SYS(BGEZ); +REC_SYS(BGTZL); +REC_SYS(BLTZL); +REC_SYS(BLTZAL); +REC_SYS(BLTZALL); +REC_SYS(BLEZL); +REC_SYS(BGEZL); +REC_SYS(BGEZAL); +REC_SYS(BGEZALL); + +#else + +#if defined(EE_CONST_PROP) + +void recSetBranchEQ(int info, int bne, int process) +{ + if( info & PROCESS_EE_MMX ) { + int t0reg; + + SetMMXstate(); + + if( process & PROCESS_CONSTS ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _deleteMMXreg(_Rt_, 1); + mmxregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_T); + } + + _flushConstReg(_Rs_); + PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + + if( t0reg != EEREC_T ) _freeMMXreg(t0reg); + } + else if( process & PROCESS_CONSTT ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + _deleteMMXreg(_Rs_, 1); + mmxregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + } + + _flushConstReg(_Rt_); + PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + + if( t0reg != EEREC_S ) _freeMMXreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + _deleteMMXreg(_Rs_, 1); + mmxregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + PCMPEQDRtoR(t0reg, EEREC_T); + } + else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _deleteMMXreg(_Rt_, 1); + mmxregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + PCMPEQDRtoR(t0reg, EEREC_S); + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PCMPEQDRtoR(t0reg, EEREC_T); + } + + if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeMMXreg(t0reg); + } + + PMOVMSKBMMXtoR(EAX, t0reg); + + _eeFlushAllUnused(); + + CMP8ItoR( EAX, 0xff ); + + if( bne ) j32Ptr[ 1 ] = JE32( 0 ); + else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); + } + else if( info & PROCESS_EE_XMM ) { + int t0reg; + + if( process & PROCESS_CONSTS ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { + _deleteGPRtoXMMreg(_Rt_, 1); + xmmregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_T); + } + + _flushConstReg(_Rs_); + SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + + + if( t0reg != EEREC_T ) _freeXMMreg(t0reg); + } + else if( process & PROCESS_CONSTT ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _deleteGPRtoXMMreg(_Rs_, 1); + xmmregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); + } + + _flushConstReg(_Rt_); + SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + + if( t0reg != EEREC_S ) _freeXMMreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _deleteGPRtoXMMreg(_Rs_, 1); + xmmregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); + } + else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { + _deleteGPRtoXMMreg(_Rt_, 1); + xmmregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_S); + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); + } + + if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeXMMreg(t0reg); + } + + SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); + + _eeFlushAllUnused(); + + AND8ItoR(EAX, 3); + CMP8ItoR( EAX, 0x3 ); + + if( bne ) j32Ptr[ 1 ] = JE32( 0 ); + else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); + } + else { + + _eeFlushAllUnused(); + + if( bne ) { + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + + x86SetJ8( j8Ptr[0] ); + } + else { + // beq + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + } + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); +} + +void recSetBranchL(int ltz) +{ + int regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); + + if( regs >= 0 ) { + + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + SetMMXstate(); + + PXORRtoR(t0reg, t0reg); + PCMPGTDRtoR(t0reg, regs); + PMOVMSKBMMXtoR(EAX, t0reg); + + _freeMMXreg(t0reg); + _eeFlushAllUnused(); + + TEST8ItoR( EAX, 0x80 ); + + if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); + else j32Ptr[ 0 ] = JNZ32( 0 ); + + return; + } + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + + if( regs >= 0 ) { + + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE_XORPS_XMM_to_XMM(t0reg, t0reg); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, regs); + SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); + + _freeXMMreg(t0reg); + _eeFlushAllUnused(); + + TEST8ItoR( EAX, 2 ); + + if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); + else j32Ptr[ 0 ] = JNZ32( 0 ); + + return; + } + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + if( ltz ) j32Ptr[ 0 ] = JGE32( 0 ); + else j32Ptr[ 0 ] = JL32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); +} + +//// BEQ +void recBEQ_const() +{ + u32 branchTo; + + if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) + branchTo = ((s32)_Imm_ * 4) + pc; + else + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); +} + +void recBEQ_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else + { + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + } +} + +void recBEQ_(int info) { recBEQ_process(info, 0); } +void recBEQ_consts(int info) { recBEQ_process(info, PROCESS_CONSTS); } +void recBEQ_constt(int info) { recBEQ_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BEQ, XMMINFO_READS|XMMINFO_READT); + +//// BNE +void recBNE_const() +{ + u32 branchTo; + + if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) + branchTo = ((s32)_Imm_ * 4) + pc; + else + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); +} + +void recBNE_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + recompileNextInstruction(1); + SetBranchImm(pc); + return; + } + + recSetBranchEQ(info, 1, process); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +void recBNE_(int info) { recBNE_process(info, 0); } +void recBNE_consts(int info) { recBNE_process(info, PROCESS_CONSTS); } +void recBNE_constt(int info) { recBNE_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BNE, XMMINFO_READS|XMMINFO_READT); + +//// BEQL +void recBEQL_const() +{ + if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) { + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else { + SetBranchImm( pc+4 ); + } +} + +void recBEQL_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +void recBEQL_(int info) { recBEQL_process(info, 0); } +void recBEQL_consts(int info) { recBEQL_process(info, PROCESS_CONSTS); } +void recBEQL_constt(int info) { recBEQL_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BEQL, XMMINFO_READS|XMMINFO_READT); + +//// BNEL +void recBNEL_const() +{ + if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) { + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recompileNextInstruction(1); + SetBranchImm(branchTo); + } + else { + SetBranchImm( pc+4 ); + } +} + +void recBNEL_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + SetBranchImm(pc+4); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + LoadBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); +} + +void recBNEL_(int info) { recBNEL_process(info, 0); } +void recBNEL_consts(int info) { recBNEL_process(info, PROCESS_CONSTS); } +void recBNEL_constt(int info) { recBNEL_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BNEL, XMMINFO_READS|XMMINFO_READT); + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +//void recBLTZAL( void ) +//{ +// SysPrintf("BLTZAL\n"); +// _eeFlushAllUnused(); +// MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); +// MOV32ItoM( (int)&cpuRegs.pc, pc ); +// iFlushCall(FLUSH_EVERYTHING); +// CALLFunc( (int)BLTZAL ); +// branch = 2; +//} + +//////////////////////////////////////////////////// +void recBLTZAL(int info) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + SysPrintf("BLTZAL\n"); + _eeOnWriteReg(31, 0); + _eeFlushAllUnused(); + + _deleteEEreg(31, 0); + MOV32ItoM((u32)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((u32)&cpuRegs.GPR.r[31].UL[1], 0); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(1); + + SaveBranchState(); + + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZAL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if( GPR_IS_CONST1(_Rs_) ) { + // will always branch + _deleteEEreg(31, 0); + MOV32ItoM((u32)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((u32)&cpuRegs.GPR.r[31].UL[1], 0); + + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else { + SysPrintf("BGEZAL\n"); + + _eeFlushAllUnused(); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZAL ); + branch = 2; + } +} + +//////////////////////////////////////////////////// +void recBLTZALL( void ) +{ + SysPrintf("BLTZALL\n"); + _eeFlushAllUnused(); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZALL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZALL( void ) +{ + SysPrintf("BGEZALL\n"); + _eeFlushAllUnused(); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZALL ); + branch = 2; +} + +#else + + +//////////////////////////////////////////////////// +void recBEQ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + } +} + +//////////////////////////////////////////////////// +void recBNE( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm(pc); + return; + } + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JE32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBEQL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBNEL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + SetBranchImm(pc+4); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + LoadBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLTZAL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZAL( void ) +{ + SysPrintf("BGEZAL\n"); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBLTZALL( void ) +{ + SysPrintf("BLTZALL\n"); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZALL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZALL( void ) +{ + SysPrintf("BGEZALL\n"); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZALL ); + branch = 2; +} + +#endif + +//// BLEZ +void recBLEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j8Ptr[ 0 ] = JL8( 0 ); + j32Ptr[ 1 ] = JG32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JNZ32( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//// BGTZ +void recBGTZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j8Ptr[ 0 ] = JG8( 0 ); + j32Ptr[ 1 ] = JL32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JZ32( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +#ifdef EE_CONST_PROP +void recBLTZ() +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(1); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(0); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(1); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + + +//////////////////////////////////////////////////// +void recBGEZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +#else +void recBLTZ( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZ ); + branch = 2; +} + +void recBGEZ( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZ ); + branch = 2; +} + +void recBLTZL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZL ); + branch = 2; +} + +void recBGEZL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZL ); + branch = 2; +} + +#endif + + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLEZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j32Ptr[ 0 ] = JL32( 0 ); + j32Ptr[ 1 ] = JG32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JNZ32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j32Ptr[ 0 ] = JG32( 0 ); + j32Ptr[ 1 ] = JL32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JZ32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + + + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900Jump.c b/pcsx2/x86/ix86-32/iR5900Jump.c new file mode 100644 index 0000000000..0679b0bf86 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900Jump.c @@ -0,0 +1,136 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +#ifndef JUMP_RECOMPILE + +REC_SYS(J); +REC_SYS(JAL); +REC_SYS(JR); +REC_SYS(JALR); + +#else + +//////////////////////////////////////////////////// +void recJ( void ) +{ + // SET_FPUSTATE; + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +//////////////////////////////////////////////////// +void recJAL( void ) +{ + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + _deleteEEreg(31, 0); + GPR_SET_CONST(31); + g_cpuConstRegs[31].UL[0] = pc + 4; + g_cpuConstRegs[31].UL[1] = 0; + + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ + +//////////////////////////////////////////////////// +void recJR( void ) +{ + SetBranchReg( _Rs_); +} + +//////////////////////////////////////////////////// +void recJALR( void ) +{ + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, _Rs_); + // uncomment when there are NO instructions that need to call interpreter +// int mmreg; +// if( GPR_IS_CONST1(_Rs_) ) +// MOV32ItoM( (u32)&cpuRegs.pc, g_cpuConstRegs[_Rs_].UL[0] ); +// else { +// int mmreg; +// +// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { +// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); +// } +// else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { +// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); +// SetMMXstate(); +// } +// else { +// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); +// MOV32RtoM((u32)&cpuRegs.pc, EAX); +// } +// } + + if ( _Rd_ ) + { + _deleteEEreg(_Rd_, 0); + GPR_SET_CONST(_Rd_); + g_cpuConstRegs[_Rd_].UL[0] = pc + 4; + g_cpuConstRegs[_Rd_].UL[1] = 0; + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((int)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (u32)&g_recWriteback); + MOV32RtoM((int)&cpuRegs.pc, EAX); + } + + SetBranchReg(0xffffffff); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900LoadStore.c b/pcsx2/x86/ix86-32/iR5900LoadStore.c new file mode 100644 index 0000000000..902a6ec673 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900LoadStore.c @@ -0,0 +1,4297 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +#ifndef LOADSTORE_RECOMPILE + +REC_FUNC(LB); +REC_FUNC(LBU); +REC_FUNC(LH); +REC_FUNC(LHU); +REC_FUNC(LW); +REC_FUNC(LWU); +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(LD); +REC_FUNC(LDR); +REC_FUNC(LDL); +REC_FUNC(LQ); +REC_FUNC(SB); +REC_FUNC(SH); +REC_FUNC(SW); +REC_FUNC(SWL); +REC_FUNC(SWR); +REC_FUNC(SD); +REC_FUNC(SDL); +REC_FUNC(SDR); +REC_FUNC(SQ); +REC_FUNC(LWC1); +REC_FUNC(SWC1); +REC_FUNC(LQC2); +REC_FUNC(SQC2); + +void SetFastMemory(int bSetFast) {} + +#else + +PCSX2_ALIGNED16(u64 retValues[2]); +extern u32 maxrecmem; +static u32 s_bCachingMem = 0; +static u32 s_nAddMemOffset = 0; +static u32 s_tempaddr = 0; + +void _eeOnLoadWrite(int reg) +{ + int regt; + + if( !reg ) return; + + _eeOnWriteReg(reg, 1); + regt = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ); + + if( regt >= 0 ) { + if( xmmregs[regt].mode & MODE_WRITE ) { + if( cpucaps.hasStreamingSIMD2Extensions && (reg != _Rs_) ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(regt, regt); + SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); + } + else SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); + } + xmmregs[regt].inuse = 0; + } +} + +#ifdef PCSX2_VIRTUAL_MEM + +extern void iMemRead32Check(); + +#define _Imm_co_ (*(s16*)PSM(pc)) + +// perf counters +#ifdef PCSX2_DEVBUILD +extern void StartPerfCounter(); +extern void StopPerfCounter(); +#else +#define StartPerfCounter() +#define StopPerfCounter() +#endif + +//////////////////////////////////////////////////// +//#define REC_SLOWREAD +//#define REC_SLOWWRITE +#define REC_FORCEMMX 0 + +// if sp, always mem write +int _eeIsMemWrite() { return _Rs_==29||_Rs_== 31||_Rs_==26||_Rs_==27; } // sp, ra, k0, k1 +// gp can be 1000a020 (jak1) + +void recTransferX86ToReg(int x86reg, int gprreg, int sign) +{ + //if( !REC_FORCEMMX ) assert( _checkMMXreg(MMX_GPR+gprreg, MODE_WRITE) == -1 ); + if( sign ) { + if( x86reg == EAX && EEINST_ISLIVE1(gprreg) ) CDQ(); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); + + if(EEINST_ISLIVE1(gprreg)) { + if( x86reg == EAX ) MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], EDX ); + else { + SAR32ItoR(x86reg, 31); + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], x86reg ); + } + } + else { + EEINST_RESETHASLIVE1(gprreg); + } + } + else { + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); + if(EEINST_ISLIVE1(gprreg)) MOV32ItoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(gprreg); + } +} + +#ifdef _DEBUG +void testaddrs() +{ + register int tempaddr; + + __asm mov tempaddr, ecx + //__asm mov incaddr, edx + + assert( (tempaddr < 0x40000000) || (tempaddr&0xd0000000)==0x50000000 || (tempaddr >= 0x80000000 && tempaddr < 0xc0000000) ); + //assert( (tempaddr>>28) == ((tempaddr+incaddr)>>28) ); + + __asm mov ecx, tempaddr +} +#endif + +#define SET_HWLOC() { \ + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[2]); \ + else x86SetJ8(j8Ptr[0]); \ + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[3]); \ + else x86SetJ8(j8Ptr[3]); \ + if (x86FpuState==MMX_STATE) { \ + if (cpucaps.has3DNOWInstructionExtensions) FEMMS(); \ + else EMMS(); \ + } \ + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); \ + if( s_bCachingMem & 4 ) AND32ItoR(ECX, 0x5fffffff); \ +} \ + +static u16 g_MemMasks0[16] = {0x00f0, 0x80f1, 0x00f2, 0x00f3, + 0x00f1, 0x00f5, 0x00f1, 0x00f5, + 0x00f5, 0x80f5, 0x00f5, 0x80f5, + 0x00f1, 0x00f1, 0x00f1, 0x00f5 }; +static u16 g_MemMasks8[16] = {0x0080, 0x8081, 0x0082, 0x0083, + 0x0081, 0x0085, 0x0081, 0x0085, + 0x0085, 0x8085, 0x0085, 0x8085, + 0x0081, 0x0081, 0x0081, 0x0085 }; +static u16 g_MemMasks16[16] ={0x0000, 0x8001, 0x0002, 0x0003, + 0x0001, 0x0005, 0x0001, 0x0005, + 0x0005, 0x8005, 0x0005, 0x8005, + 0x0001, 0x0001, 0x0001, 0x0005 }; + +static int s_bFastMemory = 0; +void SetFastMemory(int bSetFast) +{ + s_bFastMemory = bSetFast; + if( bSetFast) { + g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f0; g_MemMasks0[3] = 0x00f1; + g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0080; g_MemMasks8[3] = 0x0081; + g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0000; g_MemMasks16[3] = 0x0001; + } + else { + g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f2; g_MemMasks0[3] = 0x00f3; + g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0082; g_MemMasks8[3] = 0x0083; + g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0002; g_MemMasks16[3] = 0x0003; + } +} + +void assertmem() +{ + __asm mov s_tempaddr, ecx + __asm mov s_bCachingMem, edx + SysPrintf("%x(%x) not mem write!\n", s_tempaddr, s_bCachingMem); + assert(0); +} + +int _eePrepareReg(int gprreg) +{ + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); + + if( mmreg >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { + mmreg |= MEM_XMMTAG; + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { + if( mmxregs[mmreg].mode&MODE_WRITE ) mmreg |= MEM_MMXTAG; + else { + mmxregs[mmreg].needed = 0; // coX can possibly use all regs + mmreg = 0; + } + } + else { + mmreg = 0; + } + + return mmreg; +} + +int _eePrepareReg_coX(int gprreg, int num) +{ + int mmreg = _eePrepareReg(gprreg); + + if( (mmreg&MEM_MMXTAG) && num == 7 ) { + if( mmxregs[mmreg&0xf].mode & MODE_WRITE ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg], mmreg&0xf); + mmxregs[mmreg&0xf].mode &= ~MODE_WRITE; + mmxregs[mmreg&0xf].needed = 0; + } + } + + return mmreg; +} + +// returns true if should also include harware writes +int recSetMemLocation(int regs, int imm, int mmreg, int msize, int j32) +{ + s_bCachingMem = j32 ? 2 : 0; + s_nAddMemOffset = 0; + + //int num; + if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { + SSE2_MOVD_XMM_to_R(ECX, mmreg&0xf); + } + else if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { + MOVD32MMXtoR(ECX, mmreg&0xf); + SetMMXstate(); + } + else { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ regs ].UL[ 0 ] ); + } + + if ( imm != 0 ) ADD32ItoR( ECX, imm ); + + LoadCW(); + +#ifdef _DEBUG + //CALLFunc((u32)testaddrs); +#endif + + + // 32bit version (faster?) +// MOV32RtoR(EAX, ECX); +// ROR32ItoR(ECX, 28); +// SHR32ItoR(EAX, 28); +// MOV32RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 2); +// AND8RtoR(ECX, EAX); +// ROR32ItoR(ECX, 4); +// // do extra alignment masks here +// OR32RtoR(EAX, EAX); + + if( _eeIsMemWrite() ) { + u8* ptr; + CMP32ItoR(ECX, 0x40000000); + ptr = JB8(0); + if( msize == 1 ) AND32ItoR(ECX, 0x5ffffff8); + else if( msize == 2 ) AND32ItoR(ECX, 0x5ffffff0); + else AND32ItoR(ECX, 0x5fffffff); + x86SetJ8(ptr); + if( msize == 1 ) AND8ItoR(ECX, 0xf8); + else if( msize == 2 ) AND8ItoR(ECX, 0xf0); +#ifdef _DEBUG + MOV32RtoR(EAX, ECX); + SHR32ItoR(EAX, 28); + CMP32ItoR(EAX, 1); + ptr = JNE8(0); + MOV32ItoR(EDX, _Rs_); + CALLFunc((u32)assertmem); + x86SetJ8(ptr); +#endif + return 0; + } + else { + // 16 bit version + MOV32RtoR(EAX, ECX); + ROR32ItoR(ECX, 28); + SHR32ItoR(EAX, 28); + MOV16RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 1); + AND8RtoR(ECX, EAX); + ROR32ItoR(ECX, 4); + + OR16RtoR(EAX, EAX); + + if( s_bCachingMem & 2 ) j32Ptr[2] = j32Ptr[3] = JS32(0); + else j8Ptr[0] = j8Ptr[3] = JS8(0); + } + + return 1; +} + + +void recLoad32(u32 bit, u32 imm, u32 sign) +{ + int mmreg = -1; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + // do const processing + int ineax = 0; + + _eeOnLoadWrite(_Rt_); + if( bit == 32 ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_MMXTAG; + else mmreg = EAX; + } + else { + _deleteEEreg(_Rt_, 0); + mmreg = EAX; + } + + switch(bit) { + case 8: ineax = recMemConstRead8(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); break; + case 16: + assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 2 == 0 ); + ineax = recMemConstRead16(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); + break; + case 32: + // used by LWL/LWR + //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 4 == 0 ); + ineax = recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm); + break; + } + + if( ineax || !(mmreg&MEM_MMXTAG) ) { + if( mmreg&MEM_MMXTAG ) mmxregs[mmreg&0xf].inuse = 0; + recTransferX86ToReg(EAX, _Rt_, sign); + } + else { + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + + if( REC_FORCEMMX ) mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + else _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, imm, mmregs, 0, 0); + + if( mmreg >= 0 ) { + MOVD32RmOffsettoMMX(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset-(32-bit)/8); + if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); + } + else { + switch(bit) { + case 8: + if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + case 16: + if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + case 32: + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + switch(bit) { + case 8: + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + break; + case 16: + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + break; + case 32: + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + if( mmreg >= 0 ) { + if( EEINST_ISLIVE1(_Rt_) ) MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_]); + else MOVD32RtoMMX(mmreg, EAX); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +void recLoad32_co(u32 bit, u32 sign) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1 = -1, mmreg2 = -1; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int ineax = 0; + u32 written = 0; + + _eeOnLoadWrite(_Rt_); + _eeOnLoadWrite(nextrt); + + if( bit == 32 ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_MMXTAG; + else mmreg1 = EBX; + + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_MMXTAG; + else mmreg2 = EAX; + } + else { + _deleteEEreg(_Rt_, 0); + _deleteEEreg(nextrt, 0); + mmreg1 = EBX; + mmreg2 = EAX; + } + + // do const processing + switch(bit) { + case 8: + if( recMemConstRead8(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead8(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); + break; + case 16: + if( recMemConstRead16(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead16(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); + break; + case 32: + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); + break; + } + + if( !written && _Rt_ ) { + if( mmreg1&MEM_MMXTAG ) { + assert( mmxregs[mmreg1&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg1&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg1&0xf, 32-bit); + } + else recTransferX86ToReg(mmreg1, _Rt_, sign); + } + if( nextrt ) { + g_pCurInstInfo++; + if( !ineax && (mmreg2 & MEM_MMXTAG) ) { + assert( mmxregs[mmreg2&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg2&0xf, nextrt, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg2&0xf, 32-bit); + } + else { + if( mmreg2&MEM_MMXTAG ) mmxregs[mmreg2&0xf].inuse = 0; + recTransferX86ToReg(mmreg2, nextrt, sign); + } + g_pCurInstInfo--; + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + assert( !REC_FORCEMMX ); + + _eeOnLoadWrite(_Rt_); + _eeOnLoadWrite(nextrt); + _deleteEEreg(_Rt_, 0); + _deleteEEreg(nextrt, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + switch(bit) { + case 8: + if( sign ) { + MOVSX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOVZX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + break; + case 16: + if( sign ) { + MOVSX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOVZX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + break; + case 32: + MOV32RmtoROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EBX, _Rt_, sign); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + switch(bit) { + case 8: + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + break; + case 16: + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + break; + case 32: + MOV32RtoM((u32)&s_tempaddr, ECX); + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + break; + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( nextrt ) { + g_pCurInstInfo++; + recTransferX86ToReg(EAX, nextrt, sign); + g_pCurInstInfo--; + } + } +} + +void recLB( void ) { recLoad32(8, _Imm_, 1); } +void recLB_co( void ) { recLoad32_co(8, 1); } +void recLBU( void ) { recLoad32(8, _Imm_, 0); } +void recLBU_co( void ) { recLoad32_co(8, 0); } +void recLH( void ) { recLoad32(16, _Imm_, 1); } +void recLH_co( void ) { recLoad32_co(16, 1); } +void recLHU( void ) { recLoad32(16, _Imm_, 0); } +void recLHU_co( void ) { recLoad32_co(16, 0); } +void recLW( void ) { recLoad32(32, _Imm_, 1); } +void recLW_co( void ) { recLoad32_co(32, 1); } +void recLWU( void ) { recLoad32(32, _Imm_, 0); } +void recLWU_co( void ) { recLoad32_co(32, 0); } + +//////////////////////////////////////////////////// + +// paired with LWR +void recLWL_co(void) { recLoad32(32, _Imm_-3, 1); } + +void recLWL( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + if( _Rt_ ) { + u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + _eeMoveGPRtoR(ECX, _Rt_); + SHL32ItoR(EAX, 24-shift*8); + AND32ItoR(ECX, (0xffffff>>(shift*8))); + OR32RtoR(EAX, ECX); + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, 1); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + iMemRead32Check(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + + x86SetJ8(j8Ptr[1]); + } + + if ( _Rt_ ) { + // mem << LWL_SHIFT[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + SHL32CLtoR(EAX); + + // mov temp and compute _rt_ & LWL_MASK[shift] + MOV32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff); + SAR32CLtoR(EDX); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32RtoR(EDX, ECX); + + // combine + OR32RtoR(EAX, EDX); + recTransferX86ToReg(EAX, _Rt_, 1); + } + } +} + +//////////////////////////////////////////////////// + +// paired with LWL +void recLWR_co(void) { recLoad32(32, _Imm_, 1); } + +void recLWR( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + if( _Rt_ ) { + u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + _eeMoveGPRtoR(ECX, _Rt_); + SHL32ItoR(EAX, shift*8); + AND32ItoR(ECX, (0xffffff00<<(24-shift*8))); + OR32RtoR(EAX, ECX); + + recTransferX86ToReg(EAX, _Rt_, 1); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + iMemRead32Check(); + + PUSH32R(ECX); + AND32ItoR(ECX, ~3); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + + x86SetJ8(j8Ptr[1]); + } + + if ( _Rt_ ) + { + // mem << LWL_SHIFT[shift] + MOV32RtoR(ECX, EDX); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 3); // *8 + SHR32CLtoR(EAX); + + // mov temp and compute _rt_ & LWL_MASK[shift] + MOV32RtoR(EDX, ECX); + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff00); + SHL32CLtoR(EDX); + _eeMoveGPRtoR(ECX, _Rt_); + AND32RtoR(ECX, EDX); + + // combine + OR32RtoR(EAX, ECX); + + recTransferX86ToReg(EAX, _Rt_, 1); + } + } +} + +//////////////////////////////////////////////////// +void recLoad64(u32 imm, int align) +{ + int mmreg; + int mask = align ? ~7 : ~0; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + // also used by LDL/LDR + //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 8 == 0 ); + + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( _Rt_ && mmreg >= 0 ) { + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg); + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + } + else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); + assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else { + if( !_hasFreeMMXreg() && _hasFreeXMMreg() ) { + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ|MODE_WRITE); + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); + assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, t0reg); + + if( _Rt_ ) { + SetMMXstate(); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UD[0], t0reg); + } + + _freeMMXreg(t0reg); + } + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + if( _Rt_ && (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + MOVQRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + ADD32ItoR(ESP, 4); + } + + SetMMXstate(); + } + else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + SSE_MOVLPSRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + SSE_MOVLPS_M64_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + ADD32ItoR(ESP, 4); + } + } + else { + int t0reg = _Rt_ ? _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE) : -1; + + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + if( t0reg >= 0 ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + SetMMXstate(); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + if( _Rt_ ) { + //_deleteEEreg(_Rt_, 0); + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else PUSH32I( (int)&retValues[0] ); + + CALLFunc( (int)recMemRead64 ); + ADD32ItoR(ESP, 4); + + if( t0reg >= 0 ) MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); +} + +void recLD(void) { recLoad64(_Imm_, 1); } + +void recLD_co( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLD(); + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc); + recLD(); + g_pCurInstInfo--; // incremented later + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + int mmreg1 = -1, mmreg2 = -1, t0reg = -1, t1reg = -1; + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); + if( nextrt ) _eeOnWriteReg(nextrt, 0); + + if( _Rt_ ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 < 0 ) { + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); + if( mmreg1 >= 0 ) mmreg1 |= 0x8000; + } + + if( mmreg1 < 0 && _hasFreeMMXreg() ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + } + + if( nextrt ) { + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 < 0 ) { + mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE|MODE_READ); + if( mmreg2 >= 0 ) mmreg2 |= 0x8000; + } + + if( mmreg2 < 0 && _hasFreeMMXreg() ) mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_WRITE); + } + + if( mmreg1 < 0 || mmreg2 < 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( mmreg1 < 0 && mmreg2 < 0 && _hasFreeMMXreg() ) { + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + else t1reg = t0reg; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 1, 0); + + if( mmreg1 >= 0 ) { + if( mmreg1 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVQRmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _Rt_ ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], t0reg); + } + } + + if( mmreg2 >= 0 ) { + if( mmreg2 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + else MOVQRmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + if( nextrt ) { + MOVQRmtoROffset(t1reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQRtoM((int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ], t1reg); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( mmreg1 >= 0 ) { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + + if( mmreg1 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + else MOVQMtoR(mmreg1, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + else { + if( _Rt_ ) { + _deleteEEreg(_Rt_, 0); + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else PUSH32I( (int)&retValues[0] ); + + CALLFunc( (int)recMemRead64 ); + } + + MOV32MtoR(ECX, (u32)&s_tempaddr); + + if( mmreg2 >= 0 ) { + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead64 ); + + if( mmreg2 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); + else MOVQMtoR(mmreg2, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); + } + else { + if( nextrt ) { + _deleteEEreg(nextrt, 0); + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); + } + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead64 ); + } + + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + + if( mmreg1 < 0 || mmreg2 < 0 || !(mmreg1&0x8000) || !(mmreg2&0x8000) ) SetMMXstate(); + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + if( t0reg != t1reg && t1reg >= 0 ) _freeMMXreg(t1reg); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + } +} + +void recLD_coX( int num ) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLD(); + + for(i = 0; i < num; ++i) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc+i*4); + recLD(); + } + + g_pCurInstInfo -= num; // incremented later + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + _eeOnWriteReg(nextrts[i], 0); + } + + if( _Rt_ ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg < 0 ) { + mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; + } + else mmreg |= MEM_MMXTAG; + } + + for(i = 0; i < num; ++i) { + mmregs[i] = _allocCheckGPRtoMMX(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); + if( mmregs[i] < 0 ) { + mmregs[i] = _allocCheckGPRtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE|MODE_READ); + if( mmregs[i] >= 0 ) mmregs[i] |= MEM_XMMTAG; + else mmregs[i] = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_WRITE)|MEM_MMXTAG; + } + else mmregs[i] |= MEM_MMXTAG; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 1, 0); + + if( mmreg >= 0 ) { + if( mmreg & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + + for(i = 0; i < num; ++i) { + u32 off = PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; + + if( mmregs[i] >= 0 ) { + if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmregs[i]&0xf, ECX, off); + else MOVQRmtoROffset(mmregs[i]&0xf, ECX, off); + } + } + + if( dohw ) { + if( (s_bCachingMem & 2) || num > 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( mmreg >= 0 ) { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + + if( mmreg & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + else MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + else { + PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead64 ); + } + + for(i = 0; i < num; ++i ) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + + if( mmregs[i] >= 0 ) { + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); + CALLFunc( (int)recMemRead64 ); + + if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); + else MOVQMtoR(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); + } + else { + MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + CALLFunc( (int)recMemRead64 ); + } + } + + ADD32ItoR(ESP, 4); + + if( (s_bCachingMem & 2) || num > 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + } +} + +//////////////////////////////////////////////////// +void recLDL_co(void) { + recLoad64(_Imm_-7, 0); } + +void recLDL( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + else { + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + } + + if( _Rt_ ) + _deleteEEreg(_Rt_, _Rt_==_Rs_); + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDL ); +} + +//////////////////////////////////////////////////// +void recLDR_co(void) { recLoad64(_Imm_, 0); } + +void recLDR( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + else { + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + } + + if( _Rt_ ) + _deleteEEreg(_Rt_, _Rt_==_Rs_); + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDR ); +} + +//////////////////////////////////////////////////// +void recLQ( void ) +{ + int mmreg = -1; +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + // malice hits this + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Rt_ ) { + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_XMM) || !(g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) ) { + _deleteMMXreg(MMX_GPR+_Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + else { + int t0reg; + _deleteGPRtoXMMreg(_Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + mmreg |= t0reg<<4; + } + } + else { + mmreg = _allocTempXMMreg(XMMT_INT, -1); + } + + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + if( !_Rt_ ) _freeXMMreg(mmreg); + if( IS_MMXREG(mmreg) ) { + // flush temp + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], (mmreg>>4)&0xf); + _freeMMXreg((mmreg>>4)&0xf); + } + else assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else +#endif + { + int dohw; + int mmregs; + int t0reg = -1; + + if( !cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) + _flushConstReg(_Rs_); + + mmregs = _eePrepareReg(_Rs_); + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + + // check if can process mmx + if( _hasFreeMMXreg() ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) { + mmreg |= MEM_MMXTAG; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+_Rt_, 2); + + if( mmreg < 0 ) { + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + } + } + + if( mmreg < 0 ) { + _deleteEEreg(_Rt_, 1); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Rt_ ) { + if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); + } + else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CALLFunc( (int)recMemRead128 ); + + if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + ADD32ItoR(ESP, 4); + } + } + else { + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + ADD32ItoR(ESP, 4); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + } + + _clearNeededXMMregs(); // needed since allocing +} + +void recLQ_co( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLQ(); + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc); + recLQ(); + g_pCurInstInfo--; // incremented later + } + else +#endif + { + int dohw; + int t0reg = -1; + int mmregs = _eePrepareReg(_Rs_); + + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1 = -1, mmreg2 = -1; + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + + if( _hasFreeMMXreg() ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) { + mmreg1 |= MEM_MMXTAG; + if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+_Rt_, 2); + + if( mmreg1 < 0 ) { + mmreg1 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; + } + } + + if( nextrt ) { + _eeOnWriteReg(nextrt, 0); + + if( _hasFreeMMXreg() ) { + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) { + mmreg2 |= MEM_MMXTAG; + if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+nextrt, 2); + + if( mmreg2 < 0 ) { + mmreg2 = _allocGPRtoXMMreg(-1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; + } + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Rt_ ) { + if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOVQRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); + } + else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + } + + if( nextrt ) { + if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + MOVQRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQRtoM((u32)&cpuRegs.GPR.r[nextrt].UL[2], t0reg); + } + else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[nextrt].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( nextrt ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrt].UL[0], 0); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead128 ); + + if( _Rt_) { + if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) MOVQMtoR(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + if( nextrt ) { + if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) MOVQMtoR(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ]); + else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ] ); + } + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + } +} + +// coissues more than 2 LQs +void recLQ_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLQ(); + + for(i = 0; i < num; ++i) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc+i*4); + recLQ(); + } + + g_pCurInstInfo -= num; // incremented later + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + + if( _Rt_ ) _deleteMMXreg(MMX_GPR+_Rt_, 2); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + if( nextrts[i] ) _deleteMMXreg(MMX_GPR+nextrts[i], 2); + } + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + + for(i = 0; i < num; ++i) { + if( nextrts[i] ) { + _eeOnWriteReg(nextrts[i], 0); + mmregs[i] = _allocGPRtoXMMreg(-1, nextrts[i], MODE_WRITE); + } + else mmregs[i] = -1; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 2, 1); + + if( _Rt_ ) SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + u32 off = s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; + if( nextrts[i] ) SSEX_MOVDQARmtoROffset(mmregs[i], ECX, PS2MEM_BASE_+off&~0xf); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + if( _Rt_) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + + if( nextrts[i] ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + CALLFunc( (int)recMemRead128 ); + if( nextrts[i] ) SSEX_MOVDQA_M128_to_XMM(mmregs[i], (int)&cpuRegs.GPR.r[ nextrts[i] ].UL[ 0 ] ); + } + + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +//////////////////////////////////////////////////// +extern void recClear64(BASEBLOCK* p); +extern void recClear128(BASEBLOCK* p); + +// check if clearing executable code, size is in dwords +void recMemConstClear(u32 mem, u32 size) +{ + // NOTE! This assumes recLUT never changes its mapping + if( !recLUT[mem>>16] ) + return; + + //iFlushCall(0); // just in case + + // check if mem is executable, and clear it + //CMP32ItoM((u32)&maxrecmem, mem); + //j8Ptr[5] = JBE8(0); + + // can clear now + if( size == 1 ) { + CMP32ItoM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JE8(0); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((u32)recClearMem); + ADD32ItoR(ESP, 4); + x86SetJ8(j8Ptr[6]); + } + else if( size == 2 ) { + // need to clear 8 bytes + + CMP32I8toM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+8, 0); + j8Ptr[7] = JNE8(0); + + j8Ptr[8] = JMP8(0); + + // call clear + x86SetJ8( j8Ptr[7] ); + x86SetJ8( j8Ptr[6] ); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((u32)recClear64); + ADD32ItoR(ESP, 4); + + x86SetJ8( j8Ptr[8] ); + } + else { + assert( size == 4 ); + // need to clear 16 bytes + + CMP32I8toM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK), 0); + j8Ptr[7] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*2, 0); + j8Ptr[8] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*3, 0); + j8Ptr[9] = JNE8(0); + + j8Ptr[10] = JMP8(0); + + // call clear + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + x86SetJ8( j8Ptr[8] ); + x86SetJ8( j8Ptr[9] ); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((u32)recClear128); + ADD32ItoR(ESP, 4); + + x86SetJ8( j8Ptr[10] ); + } + + //x86SetJ8(j8Ptr[5]); +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear32() +{ + _asm { + mov edx, ecx + shr edx, 14 + and dl, 0xfc + add edx, recLUT + test dword ptr [edx], 0xffffffff + jnz Clear32 + ret +Clear32: + // recLUT[mem>>16] + (mem&0xfffc) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + cmp dword ptr [edx], 0 + je ClearRet + sub esp, 4 + mov dword ptr [esp], edx + call recClearMem + add esp, 4 +ClearRet: + ret + } +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear64() +{ + __asm { + // check if mem is executable, and clear it + mov edx, ecx + shr edx, 14 + and edx, 0xfffffffc + add edx, recLUT + cmp dword ptr [edx], 0 + jne Clear64 + ret +Clear64: + // recLUT[mem>>16] + (mem&0xffff) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // note: have to check both blocks + cmp dword ptr [edx], 0 + jne DoClear0 + cmp dword ptr [edx+8], 0 + jne DoClear1 + ret + +DoClear1: + add edx, 8 +DoClear0: + sub esp, 4 + mov dword ptr [esp], edx + call recClear64 + add esp, 4 + ret + } +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear128() +{ + __asm { + // check if mem is executable, and clear it + mov edx, ecx + shr edx, 14 + and edx, 0xfffffffc + add edx, recLUT + cmp dword ptr [edx], 0 + jne Clear128 + ret +Clear128: + // recLUT[mem>>16] + (mem&0xffff) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // note: have to check all 4 blocks + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + ret + +DoClear: + sub esp, 4 + mov dword ptr [esp], edx + call recClear128 + add esp, 4 + ret + } +} + +void recStore_raw(EEINST* pinst, int bit, int x86reg, int gprreg, u32 offset) +{ + if( bit == 128 ) { + int mmreg; + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + + SetMMXstate(); + } + else { + + if( GPR_IS_CONST1( gprreg ) ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); + + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + SetMMXstate(); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + } + else { + if( _hasFreeXMMreg() ) { + mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ); + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + _freeXMMreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( _hasFreeMMXreg() ) { + int t0reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); +// MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); +// MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset+8); + } + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + } + } + return; + } + + if( GPR_IS_CONST1( gprreg ) ) { + switch(bit) { + case 8: MOV8ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 16: MOV16ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 32: MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 64: + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + break; + } + } + else { + int mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ); + if( mmreg < 0 ) { + mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); + if( mmreg >= 0 ) mmreg |= 0x8000; + } + + if( bit == 64 ) { + //sd + if( mmreg >= 0 ) { + if( mmreg & 0x8000 ) { + SSE_MOVLPSRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + } + else { + MOVQRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + SetMMXstate(); + } + } + else { + if( (mmreg = _allocCheckGPRtoMMX(pinst, gprreg, MODE_READ)) >= 0 ) { + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_GPR+gprreg, MODE_READ); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); + } + } + } + else if( bit == 32 ) { + // sw + if( mmreg >= 0 ) { + if( mmreg & 0x8000) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + } + else { + MOVD32MMXtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + SetMMXstate(); + } + } + else { + MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); + } + } + else { + // sb, sh + if( mmreg >= 0) { + if( mmreg & 0x8000) { + if( !(xmmregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; + } + else { + if( !(mmxregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; + } + } + + if( mmreg >= 0) { + if( mmreg & 0x8000 ) SSE2_MOVD_XMM_to_R(x86reg, mmreg&0xf); + else { + MOVD32MMXtoR(x86reg, mmreg&0xf); + SetMMXstate(); + } + } + else { + switch(bit) { + case 8: MOV8MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 16: MOV16MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 32: MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + } + } + + switch(bit) { + case 8: MOV8RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + case 16: MOV16RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + case 32: MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + } + } + } +} + +void recStore_call(int bit, int gprreg, u32 offset) +{ + // some type of hardware write + if( GPR_IS_CONST1( gprreg ) ) { + if( bit == 128 ) { + if( gprreg > 0 ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); + MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], g_cpuConstRegs[gprreg].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], g_cpuConstRegs[gprreg].UL[1]); + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else if( bit == 64 ) { + if( !(g_cpuFlushedConstReg&(1<= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + if( mmxregs[mmreg].mode & MODE_WRITE ) { + MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else if( bit == 64 ) { + // sd + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVLPS_XMM_to_M64((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + if( mmxregs[mmreg].mode & MODE_WRITE ) { + MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + SetMMXstate(); + } + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else { + // sb, sh, sw + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { + SSE2_MOVD_XMM_to_R(EAX, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE)) { + MOVD32MMXtoR(EAX, mmreg); + SetMMXstate(); + } + else { + switch(bit) { + case 8: MOV8MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 16: MOV16MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 32: MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + } + } + } + } + + if( offset != 0 ) ADD32ItoR(ECX, offset); + + // some type of hardware write + switch(bit) { + case 8: CALLFunc( (int)recMemWrite8 ); break; + case 16: CALLFunc( (int)recMemWrite16 ); break; + case 32: CALLFunc( (int)recMemWrite32 ); break; + case 64: CALLFunc( (int)recMemWrite64 ); break; + case 128: CALLFunc( (int)recMemWrite128 ); break; + } +} + +int _eePrepConstWrite128(int gprreg) +{ + int mmreg = 0; + + if( GPR_IS_CONST1(gprreg) ) { + if( gprreg ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); + _freeMMXreg(mmreg); + mmreg |= (gprreg<<16)|MEM_EECONSTTAG; + } + else { + mmreg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_PXOR_XMM_to_XMM(mmreg, mmreg); + _freeXMMreg(mmreg); + mmreg |= MEM_XMMTAG; + } + } + else { + if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { + int mmregtemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmregtemp, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); + mmreg |= (mmregtemp<<4)|MEM_MMXTAG; + _freeMMXreg(mmregtemp); + } + else mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ)|MEM_XMMTAG; + } + + return mmreg; +} + +void recStore(int bit, u32 imm, int align) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + u32 addr = g_cpuConstRegs[_Rs_].UL[0]+imm; + int doclear = 0; + StopPerfCounter(); + switch(bit) { + case 8: + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite8(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + + break; + case 16: + assert( (addr)%2 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite16(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + + break; + case 32: + // used by SWL/SWR + //assert( (addr)%4 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite32(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + break; + case 64: + { + //assert( (addr)%8 == 0 ); + int mask = align ? ~7 : ~0; + + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite64(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite64(addr&mask, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else { + mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + doclear = recMemConstWrite64(addr&mask, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + + if( doclear ) { + recMemConstClear((addr)&~7, 2); + } + + break; + } + case 128: + //assert( (addr)%16 == 0 ); + + if( recMemConstWrite128((addr)&~15, _eePrepConstWrite128(_Rt_)) ) { + CMP32ItoM((u32)&maxrecmem, addr); + j8Ptr[0] = JB8(0); + recMemConstClear((addr)&~15, 4); + x86SetJ8(j8Ptr[0]); + } + + break; + } + + StartPerfCounter(); + } + else +#endif + { + int dohw; + int mmregs; + + if( !cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, imm, mmregs, align ? bit/64 : 0, 0); + + recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); + + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (u32)&maxrecmem); + + if( s_bCachingMem & 2 ) j32Ptr[4] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + if( bit < 32 || !align ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((u32)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((u32)recWriteMemClear64); + else CALLFunc((u32)recWriteMemClear128); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[5] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + StopPerfCounter(); + recStore_call(bit, _Rt_, s_nAddMemOffset); + StartPerfCounter(); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[1]); + } + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing +} + +void recStore_co(int bit, int align) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + u32 addr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_; + u32 coaddr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_; + int mmreg, t0reg = -1, mmreg2; + int doclear = 0; + + switch(bit) { + case 8: + if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear |= recMemConstWrite8(addr, EAX); + } + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite8(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite8(coaddr, EAX); + } + break; + case 16: + assert( (addr)%2 == 0 ); + assert( (coaddr)%2 == 0 ); + + if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear |= recMemConstWrite16(addr, EAX); + } + + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite16(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite16(coaddr, EAX); + } + break; + case 32: + assert( (addr)%4 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite32(addr, EAX); + } + + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite32(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { + doclear |= recMemConstWrite32(coaddr, mmreg|MEM_XMMTAG|(nextrt<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+nextrt, MODE_READ)) >= 0 ) { + doclear |= recMemConstWrite32(coaddr, mmreg|MEM_MMXTAG|(nextrt<<16)); + } + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite32(coaddr, EAX); + } + + break; + case 64: + { + int mask = align ? ~7 : ~0; + //assert( (addr)%8 == 0 ); + + if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(_Rt_<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); + + if( GPR_IS_CONST1(nextrt) ) mmreg2 = MEM_EECONSTTAG|(nextrt<<16); + else if( (mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { + mmreg2 |= MEM_XMMTAG|(nextrt<<16); + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_READ)|MEM_MMXTAG|(nextrt<<16); + + doclear = recMemConstWrite64((addr)&mask, mmreg); + doclear |= recMemConstWrite64((coaddr)&mask, mmreg2); + doclear <<= 1; + break; + } + case 128: + assert( (addr)%16 == 0 ); + + mmreg = _eePrepConstWrite128(_Rt_); + mmreg2 = _eePrepConstWrite128(nextrt); + doclear = recMemConstWrite128((addr)&~15, mmreg); + doclear |= recMemConstWrite128((coaddr)&~15, mmreg2); + doclear <<= 2; + break; + } + + if( doclear ) { + u8* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+(_Imm_ < _Imm_co_ ? _Imm_ : _Imm_co_)); + ptr = JB8(0); + recMemConstClear((addr)&~(doclear*4-1), doclear); + recMemConstClear((coaddr)&~(doclear*4-1), doclear); + x86SetJ8A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + int off = _Imm_co_-_Imm_; + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align ? bit/64 : 0, bit==128); + + recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); + recStore_raw(g_pCurInstInfo+1, bit, EBX, nextrt, s_nAddMemOffset+off); + + // clear the writes, do only one camera (with the lowest addr) + if( off < 0 ) ADD32ItoR(ECX, s_nAddMemOffset+off); + else if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (u32)&maxrecmem); + + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((u32)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((u32)recWriteMemClear64); + else CALLFunc((u32)recWriteMemClear128); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( off < 0 ) ADD32ItoR(ECX, -off); + else ADD32ItoR(ECX, off); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((u32)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((u32)recWriteMemClear64); + else CALLFunc((u32)recWriteMemClear128); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(bit, _Rt_, s_nAddMemOffset); + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(bit, nextrt, s_nAddMemOffset+_Imm_co_-_Imm_); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + } + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing +} + +void recSB( void ) { recStore(8, _Imm_, 1); } +void recSB_co( void ) { recStore_co(8, 1); } +void recSH( void ) { recStore(16, _Imm_, 1); } +void recSH_co( void ) { recStore_co(16, 1); } +void recSW( void ) { recStore(32, _Imm_, 1); } +void recSW_co( void ) { recStore_co(32, 1); } + +//////////////////////////////////////////////////// +void recSWL_co(void) { recStore(32, _Imm_-3, 0); } + +void recSWL( void ) +{ +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32ItoR(EAX, 0xffffff00<<(shift*8)); + SHR32ItoR(ECX, 24-shift*8); + OR32RtoR(EAX, ECX); + + if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + PUSH32R(ECX); + XOR32RtoR(EDI, EDI); + + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + MOV8ItoR(EDI, 0xff); + + x86SetJ8(j8Ptr[1]); + } + + _eeMoveGPRtoR(EBX, _Rt_); + + // oldmem is in EAX + // mem >> SWL_SHIFT[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + SHR32CLtoR(EBX); + + // mov temp and compute _rt_ & SWL_MASK[shift] + MOV32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff00); + SHL32CLtoR(EDX); + AND32RtoR(EAX, EDX); + + // combine + OR32RtoR(EAX, EBX); + + POP32R(ECX); + + // read the old mem again + TEST32RtoR(EDI, EDI); + j8Ptr[0] = JNZ8(0); + + // manual write + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + CALLFunc( (int)recMemWrite32 ); + + x86SetJ8(j8Ptr[1]); + } +} + +//////////////////////////////////////////////////// +void recSWR_co(void) { recStore(32, _Imm_, 0); } + +void recSWR( void ) +{ +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32ItoR(EAX, 0x00ffffff>>(24-shift*8)); + SHL32ItoR(ECX, shift*8); + OR32RtoR(EAX, ECX); + + if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + XOR32RtoR(EDI, EDI); + + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + MOV8ItoR(EDI, 0xff); + + x86SetJ8(j8Ptr[1]); + } + + _eeMoveGPRtoR(EBX, _Rt_); + + // oldmem is in EAX + // mem << SWR_SHIFT[shift] + MOV32RtoR(ECX, EDX); + SHL32CLtoR(EBX); + + // mov temp and compute _rt_ & SWR_MASK[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0x00ffffff); + SHR32CLtoR(EDX); + AND32RtoR(EAX, EDX); + + // combine + OR32RtoR(EAX, EBX); + + POP32R(ECX); + + // read the old mem again + TEST32RtoR(EDI, EDI); + j8Ptr[0] = JNZ8(0); + + // manual write + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + CALLFunc( (int)recMemWrite32 ); + + x86SetJ8(j8Ptr[1]); + } +} + +void recSD( void ) { recStore(64, _Imm_, 1); } +void recSD_co( void ) { recStore_co(64, 1); } + +// coissues more than 2 SDs +void recSD_coX(int num, int align) +{ + int i; + int mmreg = -1; + int nextrts[XMMREGS]; + u32 mask = align ? ~7 : ~0; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int minimm = _Imm_; + int t0reg = -1; + int doclear = 0; + + if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(_Rt_<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); + doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&mask, mmreg); + + for(i = 0; i < num; ++i) { + int imm = (*(s16*)PSM(pc+i*4)); + if( minimm > imm ) minimm = imm; + + if( GPR_IS_CONST1(nextrts[i]) ) mmreg = MEM_EECONSTTAG|(nextrts[i]<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrts[i], MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(nextrts[i]<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_READ)|MEM_MMXTAG|(nextrts[i]<<16); + doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&mask, mmreg); + } + + if( doclear ) { + u32* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); + ptr = JB32(0); + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~7, 4); + + for(i = 0; i < num; ++i) { + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~7, 2); + } + x86SetJ32A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg_coX(_Rs_, num); + int minoff = 0; + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align, 1); + + recStore_raw(g_pCurInstInfo, 64, EAX, _Rt_, s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + recStore_raw(g_pCurInstInfo+i+1, 64, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + // clear the writes + minoff = _Imm_; + for(i = 0; i < num; ++i) { + if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); + } + + if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); + CMP32MtoR(ECX, (u32)&maxrecmem); + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); + CALLFunc((u32)recWriteMemClear64); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); + CALLFunc((u32)recWriteMemClear64); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(64, _Rt_, s_nAddMemOffset); + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(64, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing + } +} + +//////////////////////////////////////////////////// +void recSDL_co(void) { recStore(64, _Imm_-7, 0); } + +void recSDL( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDL ); +} + +//////////////////////////////////////////////////// +void recSDR_co(void) { recStore(64, _Imm_, 0); } + +void recSDR( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDR ); +} + +//////////////////////////////////////////////////// +void recSQ( void ) { recStore(128, _Imm_, 1); } +void recSQ_co( void ) { recStore_co(128, 1); } + +// coissues more than 2 SQs +void recSQ_coX(int num) +{ + int i; + int mmreg = -1; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int minimm = _Imm_; + int t0reg = -1; + int doclear = 0; + + mmreg = _eePrepConstWrite128(_Rt_); + doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + for(i = 0; i < num; ++i) { + int imm = (*(s16*)PSM(pc+i*4)); + if( minimm > imm ) minimm = imm; + + mmreg = _eePrepConstWrite128(nextrts[i]); + doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+imm)&~15, mmreg); + } + + if( doclear ) { + u32* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); + ptr = JB32(0); + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, 4); + + for(i = 0; i < num; ++i) { + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~15, 4); + } + x86SetJ32A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg_coX(_Rs_, num); + int minoff = 0; + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 1); + + recStore_raw(g_pCurInstInfo, 128, EAX, _Rt_, s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + recStore_raw(g_pCurInstInfo+i+1, 128, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + // clear the writes + minoff = _Imm_; + for(i = 0; i < num; ++i) { + if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); + } + + if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); + CMP32MtoR(ECX, (u32)&maxrecmem); + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); + CALLFunc((u32)recWriteMemClear128); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); + CALLFunc((u32)recWriteMemClear128); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(128, _Rt_, s_nAddMemOffset); + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(128, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing + } +} + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +//////////////////////////////////////////////////// +void recLWC1( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int mmreg; + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + mmreg = EAX; + } + + if( !(mmreg&MEM_XMMTAG) ) + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + else +#endif + { + int dohw; + int regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + int mmregs = _eePrepareReg(_Rs_); + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( regt >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + + if( regt >= 0 ) SSE2_MOVD_R_to_XMM(regt, EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +void recLWC1_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + u32 written = 0; + int ineax, mmreg1, mmreg2; + + mmreg1 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; + else mmreg1 = EBX; + + mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; + else mmreg2 = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg1&MEM_XMMTAG ) xmmregs[mmreg1&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + written = 1; + } + ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); + + if( !written ) { + if( !(mmreg1&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + } + + if( ineax || !(mmreg2 & MEM_XMMTAG) ) { + if( mmreg2&MEM_XMMTAG ) xmmregs[mmreg2&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + } + else +#endif + { + int dohw; + int regt, regtnext; + int mmregs = _eePrepareReg(_Rs_); + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + regtnext = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( regt >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + if( regtnext >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regtnext, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + PUSH32R(ECX); + CALLFunc( (int)recMemRead32 ); + POP32R(ECX); + + if( regt >= 0 ) { + SSE2_MOVD_R_to_XMM(regt, EAX); + } + else { + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead32 ); + + if( regtnext >= 0 ) { + SSE2_MOVD_R_to_XMM(regtnext, EAX); + } + else { + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recLWC1_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int ineax; + u32 written = 0; + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + written = 1; + } + else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + // recompile two at a time + for(i = 0; i < num-1; i += 2) { + nextrts[0] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + nextrts[1] = ((*(u32*)(PSM(pc+i*4+4)) >> 16) & 0x1F); + + written = 0; + mmregs[0] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[0], MODE_WRITE); + if( mmregs[0] >= 0 ) mmregs[0] |= MEM_XMMTAG; + else mmregs[0] = EBX; + + mmregs[1] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+2, nextrts[1], MODE_WRITE); + if( mmregs[1] >= 0 ) mmregs[1] |= MEM_XMMTAG; + else mmregs[1] = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmregs[0], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { + if( mmregs[0]&MEM_XMMTAG ) xmmregs[mmregs[0]&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); + written = 1; + } + ineax = recMemConstRead32(mmregs[1], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4+4))); + + if( !written ) { + if( !(mmregs[0]&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); + } + + if( ineax || !(mmregs[1] & MEM_XMMTAG) ) { + if( mmregs[1]&MEM_XMMTAG ) xmmregs[mmregs[1]&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[1] ].UL, EAX ); + } + } + + if( i < num ) { + // one left + int nextrt = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrt, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EBX ); + written = 1; + } + else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + _deleteMMXreg(MMX_FPU+nextrts[i], 2); + } + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + + for(i = 0; i < num; ++i) { + mmregs[i] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); + + if( mmreg >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + for(i = 0; i < num; ++i) { + if( mmregs[i] >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(mmregs[i], ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead32 ); + + if( mmreg >= 0 ) SSE2_MOVD_R_to_XMM(mmreg, EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + CALLFunc( (int)recMemRead32 ); + + if( mmregs[i] >= 0 ) SSE2_MOVD_R_to_XMM(mmregs[i], EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +//////////////////////////////////////////////////// +void recSWC1( void ) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( mmreg >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + // some type of hardware write + if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + + CALLFunc( (int)recMemWrite32 ); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +void recSWC1_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int mmreg; + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrt<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, mmreg); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + int mmreg1, mmreg2; + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + assert( _checkMMXreg(MMX_FPU+nextrt, MODE_READ) == -1 ); + + mmreg1 = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + mmreg2 = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if(mmreg1 >= 0 ) { + if( mmreg2 >= 0 ) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + } + else { + if( mmreg2 >= 0 ) { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32MtoR(EDX, (int)&fpuRegs.fpr[ nextrt ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + // some type of hardware write + if( mmreg1 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg1); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + CALLFunc( (int)recMemWrite32 ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + if( mmreg2 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg2); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + CALLFunc( (int)recMemWrite32 ); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recSWC1_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + + for(i = 0; i < num; ++i) { + mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrts[i]<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)), mmreg); + } + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + + for(i = 0; i < num; ++i) { + assert( _checkMMXreg(MMX_FPU+nextrts[i], MODE_READ) == -1 ); + mmregs[i] = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); + + if( mmreg >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + + for(i = 0; i < num; ++i) { + if( mmregs[i] >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmregs[i], PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + // some type of hardware write + if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + CALLFunc( (int)recMemWrite32 ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + if( mmregs[i] >= 0 && (xmmregs[mmregs[i]].mode&MODE_WRITE) ) SSE2_MOVD_XMM_to_R(EAX, mmregs[i]); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + CALLFunc( (int)recMemWrite32 ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +//////////////////////////////////////////////////// + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +void recLQC2( void ) +{ + int mmreg; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + else mmreg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + if( !_Ft_ ) _freeXMMreg(mmreg); + } + else +#endif + { + int dohw, mmregs; + + if( !cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + + if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Ft_ ) { + s8* rawreadptr = x86Ptr; + + if( mmreg >= 0 ) { + SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&VU0.VF[_Ft_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + CALLFunc( (int)recMemRead128 ); + if( mmreg >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0] ); + ADD32ItoR(ESP, 4); + + x86SetJ8(j8Ptr[1]); + } + } + else { + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + ADD32ItoR(ESP, 4); + + x86SetJ8(j8Ptr[1]); + } + } + } + + _clearNeededXMMregs(); // needed since allocing +} + +void recLQC2_co( void ) +{ + int mmreg1 = -1, mmreg2 = -1, t0reg = -1; + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + else t0reg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1 >= 0 ? mmreg1 : t0reg); + + if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); + else if( t0reg < 0 ) t0reg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2 >= 0 ? mmreg2 : t0reg); + + if( t0reg >= 0 ) _freeXMMreg(t0reg); + } + else +#endif + { + s8* rawreadptr; + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + if( mmreg1 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); + if( mmreg2 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( _Ft_ ) PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + + if( mmreg1 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0] ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + + if( nextrt ) MOV32ItoRmOffset(ESP, (int)&VU0.VF[nextrt].UD[0], 0 ); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); + CALLFunc( (int)recMemRead128 ); + + if( mmreg2 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0] ); + + ADD32ItoR(ESP, 4); + x86SetJ8(j8Ptr[1]); + } + } + + _clearNeededXMMregs(); // needed since allocing +} + +//////////////////////////////////////////////////// +void recSQC2( void ) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); + + mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + } + else +#endif + { + s8* rawreadptr; + int dohw, mmregs; + + if( cpucaps.hasStreamingSIMDExtensions && GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + + if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _hasFreeXMMreg() ) { + mmreg = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + _freeXMMreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UD[0]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UL[2]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset+8); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); + } + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + // some type of hardware write + if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg); + } + } + + MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + x86SetJ8A(j8Ptr[1]); + } + } +} + +void recSQC2_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1, mmreg2; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); + + mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; + mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_READ)|MEM_XMMTAG; + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1); + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2); + } + else +#endif + { + s8* rawreadptr; + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + mmreg1 = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ); + mmreg2 = _checkXMMreg(XMMTYPE_VFREG, nextrt, MODE_READ); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + + if( mmreg1 >= 0 ) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _hasFreeXMMreg() ) { + mmreg1 = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + _freeXMMreg(mmreg1); + } + else if( _hasFreeMMXreg() ) { + mmreg1 = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); + MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UL[2]); + MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset+8); + SetMMXstate(); + _freeMMXreg(mmreg1); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); + } + } + + if( mmreg2 >= 0 ) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + if( _hasFreeXMMreg() ) { + mmreg2 = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + _freeXMMreg(mmreg2); + } + else if( _hasFreeMMXreg() ) { + mmreg2 = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UD[0]); + MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UL[2]); + MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + SetMMXstate(); + _freeMMXreg(mmreg2); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+4); + MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+12); + } + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + // some type of hardware write + if( mmreg1 >= 0) { + if( xmmregs[mmreg1].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg1); + } + } + + MOV32RtoM((u32)&s_tempaddr, ECX); + + MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + if( mmreg2 >= 0) { + if( xmmregs[mmreg2].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[nextrt].UD[0], mmreg2); + } + } + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + + MOV32ItoR(EAX, (int)&VU0.VF[nextrt].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + x86SetJ8A(j8Ptr[1]); + } + } +} + +#else + +PCSX2_ALIGNED16(u32 dummyValue[4]); + +void SetFastMemory(int bSetFast) +{ + // nothing +} + +//////////////////////////////////////////////////// +void recLB( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead8 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVSX32R8toR( EAX, EAX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLBU( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead8 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVZX32R8toR( EAX, EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLH( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead16 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + MOVSX32R16toR( EAX, EAX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLHU( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + CALLFunc( (int)memRead16 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVZX32R16toR( EAX, EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLW( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&dummyValue[0]); + PUSH32R( EAX ); + + CALLFunc( (int)memRead32 ); + ADD32ItoR( ESP, 8 ); + + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLWU( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&dummyValue[0]); + PUSH32R( EAX ); + CALLFunc( (int)memRead32 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + } +} + +//////////////////////////////////////////////////// +void recLWL( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LWL ); +} + +//////////////////////////////////////////////////// +void recLWR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LWR ); +} + +//////////////////////////////////////////////////// +extern void MOV64RmtoR( x86IntRegType to, x86IntRegType from ); + +void recLD( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + if ( _Rt_ ) + { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else + { + PUSH32I( (int)&dummyValue[0] ); + } + PUSH32R( EAX ); + CALLFunc( (int)memRead64 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recLDL( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDL ); +} + +//////////////////////////////////////////////////// +void recLDR( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDR ); +} + +//////////////////////////////////////////////////// +void recLQ( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_); + } + AND32ItoR( EAX, ~0xf ); + + if ( _Rt_ ) + { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else + { + PUSH32I( (int)&dummyValue[0] ); + } + PUSH32R( EAX ); + CALLFunc( (int)memRead128 ); + ADD32ItoR( ESP, 8 ); + +} + +//////////////////////////////////////////////////// +void recSB( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_); + } + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite8 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recSH( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite16 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recSW( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite32 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recSWL( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SWL ); +} + +//////////////////////////////////////////////////// +void recSWR( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SWR ); +} + +//////////////////////////////////////////////////// +void recSD( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite64 ); + ADD32ItoR( ESP, 12 ); +} + +//////////////////////////////////////////////////// +void recSDL( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDL ); +} + +//////////////////////////////////////////////////// +void recSDR( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDR ); +} + +//////////////////////////////////////////////////// +void recSQ( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + AND32ItoR( EAX, ~0xf ); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite128 ); + ADD32ItoR( ESP, 8 ); +} + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +//////////////////////////////////////////////////// +void recLWC1( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteFPtoXMMreg(_Rt_, 2); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&fpuRegs.fpr[ _Rt_ ].UL ); + PUSH32R( EAX ); + CALLFunc( (int)memRead32 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recSWC1( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteFPtoXMMreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32M( (int)&fpuRegs.fpr[ _Rt_ ].UL ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite32 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +void recLQC2( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteVFtoXMMreg(_Ft_, 0, 2); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_); + } + + if ( _Rt_ ) + { + PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + } + else + { + PUSH32I( (int)&dummyValue[0] ); + } + PUSH32R( EAX ); + CALLFunc( (int)memRead128 ); + ADD32ItoR( ESP, 8 ); +} + +//////////////////////////////////////////////////// +void recSQC2( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteVFtoXMMreg(_Ft_, 0, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite128 ); + ADD32ItoR( ESP, 8 ); +} + +#endif + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900Move.c b/pcsx2/x86/ix86-32/iR5900Move.c new file mode 100644 index 0000000000..62e7be7647 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900Move.c @@ -0,0 +1,841 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef MOVE_RECOMPILE + +REC_FUNC(LUI,_Rt_); +REC_FUNC(MFLO,0); +REC_FUNC(MFHI,0); +REC_FUNC(MTLO,0); +REC_FUNC(MTHI,0); + +REC_FUNC( MFHI1 ); +REC_FUNC( MFLO1 ); +REC_FUNC( MTHI1 ); +REC_FUNC( MTLO1 ); + +REC_FUNC(MOVZ); +REC_FUNC(MOVN); + +#elif defined(EE_CONST_PROP) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ + +//// LUI +void recLUI(int info) +{ + int mmreg; + if(!_Rt_) return; + + _eeOnWriteReg(_Rt_, 1); + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE)) >= 0 ) { + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); + } + xmmregs[mmreg].inuse = 0; + } + + _deleteEEreg(_Rt_, 0); + GPR_SET_CONST(_Rt_); + g_cpuConstRegs[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); +} + +//////////////////////////////////////////////////// +void recMFHILO(int hi) +{ + int reghi, regd, xmmhilo; + if ( ! _Rd_ ) + return; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); + + _eeOnWriteReg(_Rd_, 0); + + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regd >= 0 ) { + assert( regd != reghi ); + + xmmregs[regd].inuse = 0; + + if( cpucaps.hasStreamingSIMD2Extensions ) { + SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[0], reghi); + } + else { + SSE_MOVLPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[0], reghi); + } + + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[2], regd); + } + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SSE2_MOVDQ2Q_XMM_to_MM(regd, reghi); + } + else { + _deleteEEreg(_Rd_, 0); + SSE2_MOVQ_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + } + else { + reghi = _checkMMXreg(MMX_GPR+xmmhilo, MODE_READ); + + if( reghi >= 0 ) { + + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) { + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], regd); + } + xmmregs[regd].inuse = 0; + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + else { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(regd, reghi); + xmmregs[regd].mode |= MODE_WRITE; + } + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + SetMMXstate(); + + if( regd >= 0 ) { + MOVQRtoR(regd, reghi); + } + else { + _deleteEEreg(_Rd_, 0); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + } + else { + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) SSE_MOVLPS_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + else SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SetMMXstate(); + MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + } + else { + _deleteEEreg(_Rd_, 0); + MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 0 ] : (int)&cpuRegs.LO.UL[ 0 ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 1 ] : (int)&cpuRegs.LO.UL[ 1 ]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } +} + +void recMTHILO(int hi) +{ + int reghi, regs, xmmhilo; + u32 addrhilo; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + assert( reghi != regs ); + + if( cpucaps.hasStreamingSIMD2Extensions ) { + _deleteGPRtoXMMreg(_Rs_, 0); + SSE2_PUNPCKHQDQ_XMM_to_XMM(reghi, reghi); + SSE2_PUNPCKLQDQ_XMM_to_XMM(regs, reghi); + + // swap regs + xmmregs[regs] = xmmregs[reghi]; + xmmregs[reghi].inuse = 0; + xmmregs[regs].mode |= MODE_WRITE; + } + else { + SSE2EMU_MOVSD_XMM_to_XMM(reghi, regs); + xmmregs[reghi].mode |= MODE_WRITE; + } + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); + + if( regs >= 0 ) { + + if( EEINST_ISLIVE2(xmmhilo) ) { + if( xmmregs[reghi].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64(addrhilo+8, reghi); + } + xmmregs[reghi].inuse = 0; + MOVQRtoM(addrhilo, regs); + } + else { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(reghi, regs); + xmmregs[reghi].mode |= MODE_WRITE; + } + } + else { + _flushConstReg(_Rs_); + SSE_MOVLPS_M64_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + xmmregs[reghi].mode |= MODE_WRITE; + } + } + } + else { + reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, xmmhilo, MODE_WRITE); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + //SetMMXstate(); + SSE2_MOVDQ2Q_XMM_to_MM(reghi, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoR(reghi, regs); + } + else { + _flushConstReg(_Rs_); + MOVQMtoR(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + } + } + } + else { + if( regs >= 0 ) { + SSE2_MOVQ_XMM_to_M64(addrhilo, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoM(addrhilo, regs); + } + else { + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM(addrhilo, g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM(addrhilo+4, g_cpuConstRegs[_Rs_].UL[1] ); + } + else { + _deleteEEreg(_Rs_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM( addrhilo, EAX ); + MOV32RtoM( addrhilo+4, EDX ); + } + } + } + } + } +} + +void recMFHI( void ) +{ + recMFHILO(1); +} + +void recMFLO( void ) +{ + recMFHILO(0); +} + +void recMTHI( void ) +{ + recMTHILO(1); +} + +void recMTLO( void ) +{ + recMTHILO(0); +} + +//////////////////////////////////////////////////// +void recMFHILO1(int hi) +{ + int reghi, regd, xmmhilo; + if ( ! _Rd_ ) + return; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); + + _eeOnWriteReg(_Rd_, 0); + + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regd >= 0 ) { + SSEX_MOVHLPS_XMM_to_XMM(regd, reghi); + xmmregs[regd].mode |= MODE_WRITE; + } + else { + _deleteEEreg(_Rd_, 0); + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + else { + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) { + if( cpucaps.hasStreamingSIMD2Extensions ) { + SSE2_PUNPCKHQDQ_M128_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + SSE2_PSHUFD_XMM_to_XMM(regd, regd, 0x4e); + } + else { + SSE_MOVLPS_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); + } + } + else { + SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); + } + + xmmregs[regd].mode |= MODE_WRITE; + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SetMMXstate(); + MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); + } + else { + _deleteEEreg(_Rd_, 0); + MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 2 ] : (int)&cpuRegs.LO.UL[ 2 ]); + MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 3 ] : (int)&cpuRegs.LO.UL[ 3 ]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + } + } +} + +void recMTHILO1(int hi) +{ + int reghi, regs, xmmhilo; + u32 addrhilo; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, xmmhilo, MODE_WRITE|MODE_READ); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + if( cpucaps.hasStreamingSIMD2Extensions ) SSE2_PUNPCKLQDQ_XMM_to_XMM(reghi, regs); + else SSE_MOVLHPS_XMM_to_XMM(reghi, regs); + } + else { + _deleteEEreg(_Rs_, 1); + if( cpucaps.hasStreamingSIMD2Extensions ) SSE2_PUNPCKLQDQ_M128_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + else SSE_MOVHPS_M64_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ]); + + } + } + else { + if( regs >= 0 ) { + SSE2_MOVQ_XMM_to_M64(addrhilo+8, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoM(addrhilo+8, regs); + } + else { + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM(addrhilo+8, g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM(addrhilo+12, g_cpuConstRegs[_Rs_].UL[1] ); + } + else { + _deleteEEreg(_Rs_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM( addrhilo+8, EAX ); + MOV32RtoM( addrhilo+12, EDX ); + } + } + } + } +} + +void recMFHI1( void ) +{ + recMFHILO1(1); +} + +void recMFLO1( void ) +{ + recMFHILO1(0); +} + +void recMTHI1( void ) +{ + recMTHILO1(1); +} + +void recMTLO1( void ) +{ + recMTHILO1(0); +} + +//// MOVZ +void recMOVZtemp_const() +{ + GPR_DEL_CONST(_Rd_); + _deleteEEreg(_Rd_, 1); + _eeOnWriteReg(_Rd_, 0); + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); + } +} + +static PCSX2_ALIGNED16(s_zero[4]) = {0,0,0xffffffff, 0xffffffff}; + +void recMOVZtemp_consts(int info) +{ + if( info & PROCESS_EE_MMX ) { + + u32* mem; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JNE8( 0 ); + + if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; + else { + mem = recAllocStackMem(8,8); + + mem[0] = g_cpuConstRegs[_Rs_].UL[0]; + mem[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + + MOVQMtoR(EEREC_D, (u32)mem); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + + x86SetJ8( j8Ptr[ 0 ] ); +} + +void recMOVZtemp_constt(int info) +{ + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + if( info & PROCESS_EE_MMX ) { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + return; + } + + if( _hasFreeXMMreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + } +} + +void recMOVZtemp_(int info) +{ + int t0reg = -1; + + if( info & PROCESS_EE_MMX ) { + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JNE8( 0 ); + + MOVQRtoR(EEREC_D, EEREC_S); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + if( _hasFreeXMMreg() ) + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + if( t0reg >= 0 ) { + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + + x86SetJ8( j8Ptr[ 0 ] ); + SetMMXstate(); +} + +EERECOMPILE_CODE0(MOVZtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); + +void recMOVZ() +{ + if( _Rs_ == _Rd_ ) + return; + + if( GPR_IS_CONST1(_Rd_) ) { + + if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { + // remove the const, since move is conditional + _deleteEEreg(_Rd_, 0); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); + } + else { + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; + g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + return; + } + } + + recMOVZtemp(); +} + +//// MOVN +void recMOVNtemp_const() +{ + GPR_DEL_CONST(_Rd_); + _deleteEEreg(_Rd_, 1); + _eeOnWriteReg(_Rd_, 0); + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); + } +} + +void recMOVNtemp_consts(int info) +{ + if( info & PROCESS_EE_MMX ) { + + u32* mem; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JE8( 0 ); + + if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; + else { + mem = recAllocStackMem(8,8); + + mem[0] = g_cpuConstRegs[_Rs_].UL[0]; + mem[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + + MOVQMtoR(EEREC_D, (u32)mem); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + + x86SetJ8( j8Ptr[ 0 ] ); +} + +void recMOVNtemp_constt(int info) +{ + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + if( _hasFreeXMMreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + } +} + +void recMOVNtemp_(int info) +{ + int t0reg=-1; + + if( info & PROCESS_EE_MMX ) { + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JE8( 0 ); + + MOVQRtoR(EEREC_D, EEREC_S); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + if( _hasFreeXMMreg() ) + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + if( t0reg >= 0 ) { + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + + x86SetJ8( j8Ptr[ 0 ] ); + + SetMMXstate(); +} + +EERECOMPILE_CODE0(MOVNtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); + +void recMOVN() +{ + if( _Rs_ == _Rd_ ) + return; + + if( GPR_IS_CONST1(_Rd_) ) { + + if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { + // remove the const, since move is conditional + _deleteEEreg(_Rd_, 0); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); + MOV32ItoM((u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); + } + else { + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; + g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + return; + } + } + + recMOVNtemp(); +} + +#else + +//////////////////////////////////////////////////// +void recLUI( void ) +{ + if(!_Rt_) return; + if ( _Imm_ < 0 ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0xffffffff ); //V + } + else + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); //V + } +} + +//////////////////////////////////////////////////// +void recMFHI( void ) +{ + + if ( ! _Rd_ ) + { + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.HI.UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMFLO( void ) +{ + + if ( ! _Rd_ ) + { + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.LO.UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMTHI( void ) +{ + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.HI.UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMTLO( void ) +{ + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.LO.UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMOVZ( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +//////////////////////////////////////////////////// +void recMOVN( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +REC_FUNC( MFHI1, 0 ); +REC_FUNC( MFLO1, 0 ); +REC_FUNC( MTHI1, 0 ); +REC_FUNC( MTLO1, 0 ); + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900MultDiv.c b/pcsx2/x86/ix86-32/iR5900MultDiv.c new file mode 100644 index 0000000000..1d55b07eca --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900MultDiv.c @@ -0,0 +1,958 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +#ifndef MULTDIV_RECOMPILE + +REC_FUNC(MULT); +REC_FUNC(MULTU); +REC_FUNC( MULT1 ); +REC_FUNC( MULTU1 ); + +REC_FUNC(DIV); +REC_FUNC(DIVU); +REC_FUNC( DIV1 ); +REC_FUNC( DIVU1 ); + +REC_FUNC( MADD ); +REC_FUNC( MADDU ); +REC_FUNC( MADD1 ); +REC_FUNC( MADDU1 ); + +#elif defined(EE_CONST_PROP) + +// if upper is 1, write in upper 64 bits of LO/HI +void recWritebackHILO(int info, int writed, int upper) +{ + int regd, reglo = -1, reghi, savedlo = 0; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) + MOV32RtoR( ECX, EDX ); + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + + _deleteMMXreg(XMMGPR_LO, 2); + + if( (reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ)) >= 0 ) { + if( xmmregs[reglo].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); + else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); + } + + xmmregs[reglo].inuse = 0; + reglo = -1; + } + + CDQ(); + MOV32RtoM( loaddr, EAX ); + MOV32RtoM( loaddr+4, EDX ); + savedlo = 1; + } + + if ( writed && _Rd_ ) + { + _eeOnWriteReg(_Rd_, 1); + + regd = -1; + if( g_pCurInstInfo->regs[_Rd_] & EEINST_MMX ) { + + if( savedlo ) { + regd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + MOVQMtoR(regd, loaddr); + } + } + else if( g_pCurInstInfo->regs[_Rd_] & EEINST_XMM ) { + if( savedlo ) { + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE|MODE_READ); + if( regd >= 0 ) { + SSE_MOVLPS_M64_to_XMM(regd, loaddr); + regd |= 0x8000; + } + } + } + + if( regd < 0 ) { + _deleteEEreg(_Rd_, 0); + + if( EEINST_ISLIVE1(_Rd_) && !savedlo ) CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rd_) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else EEINST_RESETHASLIVE1(_Rd_); + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + _deleteMMXreg(XMMGPR_HI, 2); + + if( (reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ)) >= 0 ) { + if( xmmregs[reghi].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); + else SSE_MOVHPS_XMM_to_M64(hiaddr+8, reghi); + } + + xmmregs[reghi].inuse = 0; + reghi = -1; + } + + MOV32RtoM(hiaddr, ECX ); + SAR32ItoR(ECX, 31); + MOV32RtoM(hiaddr+4, ECX ); + } +} + +void recWritebackHILOMMX(int info, int regsource, int writed, int upper) +{ + int regd, t0reg, t1reg = -1; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + SetMMXstate(); + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, regsource); + PSRADItoR(t0reg, 31); // shift in 0s + + if( (g_pCurInstInfo->regs[XMMGPR_LO] & testlive) || (writed && _Rd_) ) { + if( (g_pCurInstInfo->regs[XMMGPR_HI] & testlive) ) + { + if( !_hasFreeMMXreg() ) { + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) + _deleteMMXreg(MMX_GPR+MMX_HI, 2); + } + + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t1reg, regsource); + } + + PUNPCKLDQRtoR(regsource, t0reg); + } + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + int reglo; + if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { + MOVQRtoR(reglo, regsource); + } + else { + reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ); + + MOVQRtoM(loaddr, regsource); + + if( reglo >= 0 ) { + if( xmmregs[reglo].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); + else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); + } + xmmregs[reglo].inuse = 0; + reglo = -1; + } + } + } + + if ( writed && _Rd_ ) + { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + if( regd != regsource ) MOVQRtoR(regd, regsource); + } + else { + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ); + + if( regd >= 0 ) { + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + // lo written + SSE_MOVLPS_M64_to_XMM(regd, loaddr); + xmmregs[regd].mode |= MODE_WRITE; + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); + + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[_Rd_].UL[2], regd); + } + + xmmregs[regd].inuse = 0; + } + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); + } + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + + int mmreg = -1, reghi; + + if( t1reg >= 0 ) { + PUNPCKHDQRtoR(t1reg, t0reg); + mmreg = t1reg; + } + else { + // can't modify regsource + PUNPCKHDQRtoR(t0reg, regsource); + mmreg = t0reg; + PSHUFWRtoR(t0reg, t0reg, 0x4e); + } + + if( upper ) { + reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ); + if( reghi >= 0 ) { + if( xmmregs[reghi].mode & MODE_WRITE ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); + } + + xmmregs[reghi].inuse = 0; + MOVQRtoM(hiaddr, mmreg); + } + else { + _deleteGPRtoXMMreg(XMMGPR_HI, 2); + _deleteMMXreg(MMX_GPR+MMX_HI, 2); + mmxregs[mmreg].mode = MODE_WRITE; + mmxregs[mmreg].reg = MMX_GPR+MMX_HI; + + if( t1reg >= 0 ) t1reg = -1; + else t0reg = -1; + } + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg&0xf); + if( t1reg >= 0 ) _freeMMXreg(t1reg&0xf); +} + +void recWritebackConstHILO(u64 res, int writed, int upper) +{ + int reglo, reghi; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res & 0xffffffff; + ptr[1] = (res&0x80000000)?0xffffffff:0; + MOVQMtoR(reglo, (u32)ptr); + } + else { + reglo = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE|MODE_READ); + + if( reglo >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res & 0xffffffff; + ptr[1] = (res&0x80000000)?0xffffffff:0; + if( upper ) SSE_MOVHPS_M64_to_XMM(reglo, (u32)ptr); + else SSE_MOVLPS_M64_to_XMM(reglo, (u32)ptr); + } + else { + MOV32ItoM(loaddr, res & 0xffffffff); + MOV32ItoM(loaddr+4, (res&0x80000000)?0xffffffff:0); + } + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + + if( !upper && (reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE)) >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res >> 32; + ptr[1] = (res>>63)?0xffffffff:0; + MOVQMtoR(reghi, (u32)ptr); + } + else { + reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE|MODE_READ); + + if( reghi >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res >> 32; + ptr[1] = (res>>63)?0xffffffff:0; + if( upper ) SSE_MOVHPS_M64_to_XMM(reghi, (u32)ptr); + else SSE_MOVLPS_M64_to_XMM(reghi, (u32)ptr); + } + else { + _deleteEEreg(XMMGPR_HI, 0); + MOV32ItoM(hiaddr, res >> 32); + MOV32ItoM(hiaddr+4, (res>>63)?0xffffffff:0); + } + } + } + + if (!writed || !_Rd_) return; + g_cpuConstRegs[_Rd_].UD[0] = (s32)(res & 0xffffffff); //that is the difference +} + +//// MULT +void recMULT_const() +{ + s64 res = (s64)g_cpuConstRegs[_Rs_].SL[0] * (s64)g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO(res, 1, 0); +} + +void recMULTUsuper(int info, int upper, int process); +void recMULTsuper(int info, int upper, int process) +{ + assert( !(info&PROCESS_EE_MMX) ); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( process & PROCESS_CONSTS ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if( process & PROCESS_CONSTT) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + + recWritebackHILO(info, 1, upper); +} + +//void recMULT_process(int info, int process) +//{ +// if( EEINST_ISLIVE64(XMMGPR_HI) || !(info&PROCESS_EE_MMX) ) { +// recMULTsuper(info, 0, process); +// } +// else { +// // EEREC_D isn't set +// int mmregd; +// +// if( _Rd_ ) { +// assert(EEREC_D == 0); +// mmregd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); +// +// if( mmregd < 0 ) { +// if( !(process&PROCESS_CONSTS) && ((g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rs_)) ) { +// _freeMMXreg(EEREC_S); +// _deleteGPRtoXMMreg(_Rd_, 2); +// mmxregs[EEREC_S].inuse = 1; +// mmxregs[EEREC_S].reg = _Rd_; +// mmxregs[EEREC_S].mode = MODE_WRITE; +// mmregd = EEREC_S; +// } +// else if( !(process&PROCESS_CONSTT) && ((g_pCurInstInfo->regs[_Rt_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rt_)) ) { +// _freeMMXreg(EEREC_T); +// _deleteGPRtoXMMreg(_Rd_, 2); +// mmxregs[EEREC_T].inuse = 1; +// mmxregs[EEREC_T].reg = _Rd_; +// mmxregs[EEREC_T].mode = MODE_WRITE; +// mmregd = EEREC_T; +// } +// else mmregd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); +// } +// +// info |= PROCESS_EE_SET_D(mmregd); +// } +// recMULTUsuper(info, 0, process); +// } +// +// // sometimes _Rd_ can be const +// if( _Rd_ ) _eeOnWriteReg(_Rd_, 1); +//} + +void recMULT_(int info) +{ + //recMULT_process(info, 0); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, 0); + } + else recMULTUsuper(info, 0, 0); +} + +void recMULT_consts(int info) +{ + //recMULT_process(info, PROCESS_CONSTS); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, PROCESS_CONSTS); + } + else recMULTUsuper(info, 0, PROCESS_CONSTS); +} + +void recMULT_constt(int info) +{ + //recMULT_process(info, PROCESS_CONSTT); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, PROCESS_CONSTT); + } + else recMULTUsuper(info, 0, PROCESS_CONSTT); +} + +// don't set XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI +EERECOMPILE_CODE0(MULT, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//// MULTU +void recMULTU_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 0); +} + +void recMULTUsuper(int info, int upper, int process) +{ + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( (info & PROCESS_EE_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { + + if( !_Rd_ ) { + // need some temp reg + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + assert( EEREC_D == 0 ); + info |= PROCESS_EE_SET_D(t0reg); + } + + if( process & PROCESS_CONSTS ) { + u32* ptempmem = _eeGetConstReg(_Rs_); + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PMULUDQMtoR(EEREC_D, (u32)ptempmem); + } + else if( process & PROCESS_CONSTT ) { + u32* ptempmem = _eeGetConstReg(_Rt_); + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PMULUDQMtoR(EEREC_D, (u32)ptempmem); + } + else { + if( EEREC_D == EEREC_S ) PMULUDQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PMULUDQRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_S); + PMULUDQRtoR(EEREC_D, EEREC_T); + } + } + + recWritebackHILOMMX(info, EEREC_D, 1, upper); + + if( !_Rd_ ) _freeMMXreg(EEREC_D); + return; + } + + if( info & PROCESS_EE_MMX ) { + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_].UL[0], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + _deleteMMXreg(MMX_GPR+_Rd_, 0); + } + + if( process & PROCESS_CONSTS ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EDX, EEREC_T); + MUL32R(EDX); + } + else + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if( process & PROCESS_CONSTT) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EDX, EEREC_S); + MUL32R(EDX); + } + else + MUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EAX, EEREC_S); + MOVD32MMXtoR(EDX, EEREC_T); + MUL32R(EDX); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + } + + recWritebackHILO(info, 1, upper); +} + +void recMULTU_(int info) +{ + recMULTUsuper(info, 0, 0); +} + +void recMULTU_consts(int info) +{ + recMULTUsuper(info, 0, PROCESS_CONSTS); +} + +void recMULTU_constt(int info) +{ + recMULTUsuper(info, 0, PROCESS_CONSTT); +} + +// don't specify XMMINFO_WRITELO or XMMINFO_WRITEHI, that is taken care of +EERECOMPILE_CODE0(MULTU, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//////////////////////////////////////////////////// +void recMULT1_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 1); +} + +void recMULT1_(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, 0); + } + else recMULTUsuper(info, 1, 0); +} + +void recMULT1_consts(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, PROCESS_CONSTS); + } + else recMULTUsuper(info, 1, PROCESS_CONSTS); +} + +void recMULT1_constt(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, PROCESS_CONSTT); + } + else recMULTUsuper(info, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(MULT1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//////////////////////////////////////////////////// +void recMULTU1_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 1); +} + +void recMULTU1_(int info) +{ + recMULTUsuper(info, 1, 0); +} + +void recMULTU1_consts(int info) +{ + recMULTUsuper(info, 1, PROCESS_CONSTS); +} + +void recMULTU1_constt(int info) +{ + recMULTUsuper(info, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(MULTU1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//// DIV +void recDIV_const() +{ + if (g_cpuConstRegs[_Rt_].SL[0] != 0) { + s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; + s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); + } +} + +void recDIVsuper(int info, int sign, int upper, int process) +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( process & PROCESS_CONSTT ) { + if( !g_cpuConstRegs[_Rt_].UL[0] ) + return; + MOV32ItoR( ECX, g_cpuConstRegs[_Rt_].UL[0] ); + } + else { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + } + + if( process & PROCESS_CONSTS ) + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + + if( sign ) { + CDQ(); + IDIV32R( ECX ); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R( ECX ); + } + if( !(process & PROCESS_CONSTT) ) x86SetJ8( j8Ptr[ 0 ] ); + + // need to execute regardless of bad divide + recWritebackHILO(info, 0, upper); +} + +void recDIV_(int info) +{ + recDIVsuper(info, 1, 0, 0); +} + +void recDIV_consts(int info) +{ + recDIVsuper(info, 1, 0, PROCESS_CONSTS); +} + +void recDIV_constt(int info) +{ + recDIVsuper(info, 1, 0, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); + +//// DIVU +void recDIVU_const() +{ + if (g_cpuConstRegs[_Rt_].UL[0] != 0) { + u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; + u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); + } +} + +void recDIVU_(int info) +{ + recDIVsuper(info, 0, 0, 0); +} + +void recDIVU_consts(int info) +{ + recDIVsuper(info, 0, 0, PROCESS_CONSTS); +} + +void recDIVU_constt(int info) +{ + recDIVsuper(info, 0, 0, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIVU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); + +void recDIV1_const() +{ + if (g_cpuConstRegs[_Rt_].SL[0] != 0) { + s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; + s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); + } +} + +void recDIV1_(int info) +{ + recDIVsuper(info, 1, 1, 0); +} + +void recDIV1_consts(int info) +{ + recDIVsuper(info, 1, 1, PROCESS_CONSTS); +} + +void recDIV1_constt(int info) +{ + recDIVsuper(info, 1, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIV1, XMMINFO_READS|XMMINFO_READT); + +void recDIVU1_const() +{ + if (g_cpuConstRegs[_Rt_].UL[0] != 0) { + u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; + u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); + } +} + +void recDIVU1_(int info) +{ + recDIVsuper(info, 0, 1, 0); +} + +void recDIVU1_consts(int info) +{ + recDIVsuper(info, 0, 1, PROCESS_CONSTS); +} + +void recDIVU1_constt(int info) +{ + recDIVsuper(info, 0, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIVU1, XMMINFO_READS|XMMINFO_READT); + +//do EEINST_SETSIGNEXT +REC_FUNC( MADD, _Rd_ ); + +static PCSX2_ALIGNED16(u32 s_MaddMask[]) = { 0x80000000, 0, 0x80000000, 0 }; + +void recMADDU() +{ + _eeOnWriteReg(_Rd_, 1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + u64 result = ((u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + + // dadd + MOV32MtoR( EAX, (int)&cpuRegs.LO.UL[ 0 ] ); + MOV32MtoR( ECX, (int)&cpuRegs.HI.UL[ 0 ] ); + ADD32ItoR( EAX, (u32)result&0xffffffff ); + ADC32ItoR( ECX, (u32)(result>>32) ); + CDQ(); + if( _Rd_) { + _deleteEEreg(_Rd_, 0); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + + MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); + + MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); + MOV32RtoR(EAX, ECX); + CDQ(); + MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); + return; + } + + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if ( GPR_IS_CONST1(_Rt_) ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + + MOV32RtoR( ECX, EDX ); + ADD32MtoR( EAX, (u32)&cpuRegs.LO.UL[0] ); + ADC32MtoR( ECX, (u32)&cpuRegs.HI.UL[0] ); + CDQ(); + if( _Rd_ ) { + _deleteEEreg(_Rd_, 0); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + + MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); + + MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); + MOV32RtoR(EAX, ECX); + CDQ(); + MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); +} + +void recMADD1() +{ + SysPrintf("MADD1 email zero if abnormal behavior\n"); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + REC_FUNC_INLINE( MADD1, _Rd_ ); +} + +void recMADDU1() +{ + SysPrintf("MADDU1 email zero if abnormal behavior\n"); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + REC_FUNC_INLINE( MADDU1, _Rd_ ); +} + +#else + +//////////////////////////////////////////////////// +void recMULT( void ) +{ + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ ) + { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recMULTU( void ) +{ + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ != 0 ) + { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDIV( void ) +{ + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); +// XOR32RtoR( EDX,EDX ); + CDQ(); + IDIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +//////////////////////////////////////////////////// +void recDIVU( void ) +{ + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + XOR32RtoR( EDX, EDX ); + // CDQ(); + DIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX,ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + x86SetJ8( j8Ptr[ 0 ] ); + +} + +REC_FUNC( MULT1, _Rd_ ); +REC_FUNC( MULTU1, _Rd_ ); +REC_FUNC( DIV1, _Rd_ ); +REC_FUNC( DIVU1, _Rd_ ); + +REC_FUNC( MADD, _Rd_ ); +REC_FUNC( MADDU, _Rd_ ); +REC_FUNC( MADD1, _Rd_ ); +REC_FUNC( MADDU1, _Rd_ ); + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-32/iR5900Shift.c b/pcsx2/x86/ix86-32/iR5900Shift.c new file mode 100644 index 0000000000..b5900630c7 --- /dev/null +++ b/pcsx2/x86/ix86-32/iR5900Shift.c @@ -0,0 +1,1354 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef SHIFT_RECOMPILE + +REC_FUNC(SLL); +REC_FUNC(SRL); +REC_FUNC(SRA); +REC_FUNC(DSLL); +REC_FUNC(DSRL); +REC_FUNC(DSRA); +REC_FUNC(DSLL32); +REC_FUNC(DSRL32); +REC_FUNC(DSRA32); + +REC_FUNC(SLLV); +REC_FUNC(SRLV); +REC_FUNC(SRAV); +REC_FUNC(DSLLV); +REC_FUNC(DSRLV); +REC_FUNC(DSRAV); + +#elif defined(EE_CONST_PROP) + +//// SLL +void recSLL_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << _Sa_); +} + +void recSLLs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( g_pCurInstInfo->regs[_Rd_]&EEINST_MMX ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) + { + SHL32ItoR( EAX, sa ); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSLLDItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSLLDItoR(rdreg, sa); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(rdreg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLL_(int info) +{ + recSLLs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SLL); + +//// SRL +void recSRL_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> _Sa_); +} + +void recSRLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) SHR32ItoR( EAX, sa); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLDItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + // rdreg already sign extended + PSLLQItoR(rdreg, 32); + PSRLQItoR(rdreg, 32+sa); +// t0reg = _allocMMXreg(-1, MMX_TEMP, 0); +// +// // it is a signed shift +// PSRLDItoR(rdreg, sa); +// MOVQRtoR(t0reg, rdreg); +// PSRADItoR(t0reg, 31); +// +// take lower dword of rdreg and lower dword of t0reg +// PUNPCKLDQRtoR(rdreg, t0reg); +// _freeMMXreg(t0reg); + } +} + +void recSRL_(int info) +{ + recSRLs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SRL); + +//// SRA +void recSRA_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> _Sa_); +} + +void recSRAs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) SAR32ItoR( EAX, sa); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, sa); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRADItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRADItoR(rdreg, sa); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(rdreg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(t0reg, rdreg); + + // swap regs + mmxregs[t0reg] = mmxregs[rdreg]; + mmxregs[rdreg].inuse = 0; + } +} + +void recSRA_(int info) +{ + recSRAs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SRA); + +//////////////////////////////////////////////////// +void recDSLL_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << _Sa_); +} + +void recDSLLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSLLQItoR(rdreg, sa); +} + +void recDSLL_(int info) +{ + recDSLLs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSLL); + +//////////////////////////////////////////////////// +void recDSRL_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> _Sa_); +} + +void recDSRLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSRLQItoR(rdreg, sa); +} + +void recDSRL_(int info) +{ + recDSRLs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRL); + +//// DSRA +void recDSRA_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> _Sa_); +} + +void recDSRAs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, sa); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLQItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, rtreg); + + // it is a signed shift + PSRADItoR(t0reg, sa); + PSRLQItoR(rdreg, sa); + + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + } +} + +void recDSRA_(int info) +{ + recDSRAs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRA); + +///// DSLL32 +void recDSLL32_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (_Sa_+32)); +} + +void recDSLL32s_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) + { + SHL32ItoR( EAX, sa ); + } + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSLLQItoR(rdreg, sa+32); +} + +void recDSLL32_(int info) +{ + recDSLL32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSLL32); + +//// DSRL32 +void recDSRL32_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (_Sa_+32)); +} + +void recDSRL32s_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + if ( sa != 0 ) SHR32ItoR( EAX, sa ); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSRLQItoR(rdreg, sa+32); +} + +void recDSRL32_(int info) +{ + recDSRL32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRL32); + +//// DSRA32 +void recDSRA32_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> (_Sa_+32)); +} + +void recDSRA32s_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CDQ( ); + if ( sa != 0 ) SAR32ItoR( EAX, sa ); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else EEINST_RESETHASLIVE1(_Rd_); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, 31); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + if( sa ) PSRADItoR(rdreg, sa); + PUNPCKHDQRtoR(rdreg, rdreg); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, rtreg); + + // it is a signed shift + if( sa ) { + PSRADItoR(rdreg, sa); + PSRADItoR(t0reg, 31); + + // take higher dword of rdreg and lower dword of t0reg + PUNPCKHDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + } + else { + // better timing + PSRADItoR(rdreg, 31); + + // take higher dword of rdreg and lower dword of t0reg + PUNPCKHDQRtoR(t0reg, rdreg); + + // swap + mmxregs[t0reg] = mmxregs[rdreg]; + mmxregs[rdreg].inuse = 0; + } +} + +void recDSRA32_(int info) +{ + recDSRA32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRA32); + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ + +PCSX2_ALIGNED16(u32 s_sa[4]) = {0x1f, 0, 0x3f, 0}; + +int recSetShiftV(int info, int* rsreg, int* rtreg, int* rdreg, int* rstemp, int forcemmx, int shift64) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + *rtreg = EEREC_T; + *rdreg = EEREC_D; + *rsreg = EEREC_S; + + // make sure to take only low 5 bits of *rsreg + if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_)) { + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(*rstemp, *rsreg); + *rsreg = *rstemp; + } + else { + if( *rsreg != *rdreg ) { + _freeMMXreg(*rsreg); + mmxregs[*rsreg].inuse = 0; + } + } + + PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); + + if( EEREC_D == EEREC_S ) { + // need to be separate + int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + *rdreg = mmreg; + mmxregs[mmreg] = mmxregs[EEREC_S]; + mmxregs[EEREC_S].inuse = 0; + } + } + else if( forcemmx || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + *rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND32ItoR(EAX, shift64?0x3f:0x1f); + MOVD32RtoMMX(*rstemp, EAX); + *rsreg = *rstemp; + } + else { + return 0; + } + + if( *rtreg != *rdreg ) MOVQRtoR(*rdreg, *rtreg); + return 1; +} + +void recSetConstShiftV(int info, int* rsreg, int* rdreg, int* rstemp, int shift64) +{ + if( info & PROCESS_EE_MMX ) { + *rdreg = EEREC_D; + *rsreg = EEREC_S; + + // make sure to take only low 5 bits of *rsreg + if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_) ) { + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(*rstemp, *rsreg); + *rsreg = *rstemp; + } + else { + if( *rsreg != *rdreg ) { + _freeMMXreg(*rsreg); + mmxregs[*rsreg].inuse = 0; + } + } + + PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); + + + if( EEREC_D == EEREC_S ) { + // need to be separate + int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + *rdreg = mmreg; + mmxregs[mmreg] = mmxregs[EEREC_S]; + mmxregs[EEREC_S].inuse = 0; + } + } + else { + _addNeededMMXreg(MMX_GPR+_Rd_); + *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND32ItoR(EAX, shift64?0x3f:0x1f); + MOVD32RtoMMX(*rstemp, EAX); + *rsreg = *rstemp; + } + + _flushConstReg(_Rt_); +} + +void recMoveSignToRd(int info) +{ + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + + if( info & PROCESS_EE_MMX ) { + mmxregs[EEREC_D].inuse = 0; + } +} + +//// SLLV +void recSLLV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSLLV_consts(int info) +{ + recSLLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLLV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info & PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSLLDRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSLLDRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SRLV +void recSRLV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSRLV_consts(int info) +{ + recSRLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRLV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLDRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRLDRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SRAV +void recSRAV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSRAV_consts(int info) +{ + recSRAs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRAV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRAV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRADRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRADRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSLLV +void recDSLLV_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSLLV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSLLs_(info, sa); + else recDSLL32s_(info, sa-32); +} + +void recDSLLV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1; + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PSLLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSLLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1; + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PSLLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSRLV +void recDSRLV_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSRLV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSRLs_(info, sa); + else recDSRL32s_(info, sa-32); +} + +void recDSRLV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1; + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PSRLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSRLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1; + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PSRLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSRAV +void recDSRAV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s64)(g_cpuConstRegs[_Rt_].SD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSRAV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSRAs_(info, sa); + else recDSRA32s_(info, sa-32); +} + +void recDSRAV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1, t0reg, t1reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PXORRtoR(t0reg, t0reg); + + // calc high bit + MOVQRtoR(t1reg, rdreg); + PCMPGTDRtoR(t0reg, rdreg); + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + + // shift highest bit, 64 - eax + MOV32ItoR(EAX, 64); + MOVD32RtoMMX(t1reg, EAX); + PSUBDRtoR(t1reg, rsreg); + + // right logical shift + PSRLQRtoR(rdreg, rsreg); + PSLLQRtoR(t0reg, t1reg); // highest bits + + PORRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + _freeMMXreg(t1reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSRAV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg, t1reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PXORRtoR(t0reg, t0reg); + + // calc high bit + MOVQRtoR(t1reg, rdreg); + PCMPGTDRtoR(t0reg, rdreg); + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + + // shift highest bit, 64 - eax + MOV32ItoR(EAX, 64); + MOVD32RtoMMX(t1reg, EAX); + PSUBDRtoR(t1reg, rsreg); + + // right logical shift + PSRLQRtoR(rdreg, rsreg); + PSLLQRtoR(t0reg, t1reg); // highest bits + + PORRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + _freeMMXreg(t1reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +#else + +//////////////////////////////////////////////////// +void recDSRA( void ) +{ + if( !_Rd_ ) return; //? + + if ( _Sa_ != 0 ) { + // it is a signed shift + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOVQRtoR(MM1, MM0); + PSRADItoR(MM0, _Sa_); + PSRLQItoR(MM1, _Sa_); + + PUNPCKHDQRtoR(MM0, MM0); // shift to lower + // take lower dword of MM1 and lower dword of MM0 + + PUNPCKLDQRtoR(MM1, MM0); + + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM1); + } + else { + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recDSRA32(void) +{ + if( !_Rd_ ) return; //? + + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CDQ(); + + if ( _Sa_ != 0 ) + { + SAR32ItoR( EAX, _Sa_ ); + } + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); +} + +//////////////////////////////////////////////////// +void recSLL( void ) +{ + if ( ! _Rd_ ) + return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SHL32ItoR( EAX, _Sa_ ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recSRL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SHR32ItoR( EAX, _Sa_); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRA( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SAR32ItoR( EAX, _Sa_); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDSLL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Sa_ != 0 ) + { + PSLLQItoR( MM0, _Sa_ ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Sa_ != 0 ) + { + PSRLQItoR( MM0, _Sa_ ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recDSLL32( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( _Sa_ == 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PSLLQItoR( MM0, _Sa_ + 32 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRL32( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + + if ( _Sa_ == 0 ) + { + MOV32MtoR( EAX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PSRLQItoR( MM0, _Sa_ + 32 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ + +//////////////////////////////////////////////////// + + +//////////////////////////////////////////////////// +void recSLLV( void ) +{ + + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRLV( void ) +{ + + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRAV( void ) +{ + if ( ! _Rd_ ) return; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +static u64 _sa = 0; +void recDSLLV( void ) +{ + if ( ! _Rd_ ) return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOV32RtoM( (int)&_sa, EAX ); + PSLLQMtoR( MM0, (int)&_sa ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRLV( void ) +{ + if ( ! _Rd_ ) return; + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOV32RtoM( (int)&_sa, EAX ); + PSRLQMtoR( MM0, (int)&_sa ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} +//////////////////////////////////////////////////////////////// +void recDSRAV( void ) +{ + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + if ( _Rs_ != 0 ) { + PXORRtoR(MM1, MM1); + + // calc high bit + MOVQRtoR(MM2, MM0); + PUNPCKHDQRtoR(MM2, MM2); // shift to lower + PCMPGTDRtoR(MM1, MM2); + + // it is a signed shift + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOVD32RtoMMX(MM2, EAX); // amount to shift + NOT32R(EAX); + ADD32ItoR(EAX, 65); + + // right logical shift + PSRLQRtoR(MM0, MM2); + + // shift highest bit, 64 - eax + MOVD32RtoMMX(MM2, EAX); + PSLLQRtoR(MM1, MM2); // highest bits + + PORRtoR(MM0, MM1); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + + SetMMXstate(); +} +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/aR3000A-64.asm b/pcsx2/x86/ix86-64/aR3000A-64.asm new file mode 100644 index 0000000000..8c3d9b5f0e --- /dev/null +++ b/pcsx2/x86/ix86-64/aR3000A-64.asm @@ -0,0 +1,190 @@ +extern psxRegs:abs +extern psxRecLUT:abs +extern psxRecRecompile:near +extern EEsCycle:abs + +.code + +R3000AInterceptor proc public + sub rsp, 48 + jmp rdx +R3000AInterceptor endp + +R3000AExecute proc public + + ;;while (EEsCycle > 0) { + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + +Execute_CheckCycles: + cmp dword ptr [EEsCycle], 0 + jle Execute_Exit + + ;;if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) + ;; psxRecRecompile(psxRegs.pc); + + mov eax, dword ptr [psxRegs + 0208h] + mov ecx, eax + mov r12d, eax + shl rax, 32 + shr rax, 48 + and r12, 0fffch + shl rax, 3 + add rax, [psxRecLUT] + shl r12, 1 + add r12, [rax] + + mov r8d, [r12+4] + mov r9d, ecx + and r8d, 05fffffffh + and r9d, 05fffffffh + cmp r8d, r9d + jne Execute_Recompile + mov edx, [r12] + and rdx, 0fffffffh ;; pFnptr + jnz Execute_Function + +Execute_Recompile: + call psxRecRecompile + mov edx, [r12] + and rdx, 0fffffffh ;; pFnptr + +Execute_Function: + call R3000AInterceptor + + jmp Execute_CheckCycles + +Execute_Exit: + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret + +R3000AExecute endp + +psxDispatcher proc public + + mov [rsp+40], rdx + + mov eax, dword ptr [psxRegs + 0208h] + mov ecx, eax + mov r12d, eax + shl rax, 32 + shr rax, 48 + and r12, 0fffch + shl rax, 3 + add rax, [psxRecLUT] + shl r12, 1 + add r12, [rax] + + + mov eax, ecx + mov edx, [r12+4] + and eax, 5fffffffh + and edx, 5fffffffh + cmp eax, edx + je psxDispatcher_CheckPtr + + call psxRecRecompile +psxDispatcher_CheckPtr: + mov r12d, dword ptr [r12] + + and r12, 00fffffffh + mov rdx, r12 + mov rcx, [rsp+40] + sub rdx, rcx + sub rdx, 4 + mov [rcx], edx + + jmp r12 +psxDispatcher endp + +psxDispatcherClear proc public + + mov dword ptr [psxRegs + 0208h], edx + mov eax, edx + + + + mov r12d, edx + shl rax, 32 + shr rax, 48 + and r12, 0fffch + shl rax, 3 + add rax, [psxRecLUT] + shl r12, 1 + add r12, [rax] + + + mov ecx, edx + mov eax, ecx + mov edx, [r12+4] + and eax, 5fffffffh + and edx, 5fffffffh + cmp eax, edx + jne psxDispatcherClear_Recompile + + mov eax, dword ptr [r12] + + and rax, 00fffffffh + jmp rax + +psxDispatcherClear_Recompile: + call psxRecRecompile + mov eax, dword ptr [r12] + + + and rax, 00fffffffh + mov byte ptr [r15], 0e9h + mov rdx, rax + sub rdx, r15 + sub rdx, 5 + mov [r15+1], edx + + jmp rax +psxDispatcherClear endp + + +psxDispatcherReg proc public + + mov eax, dword ptr [psxRegs + 0208h] + mov ecx, eax + mov r12d, eax + shl rax, 32 + shr rax, 48 + and r12, 0fffch + shl rax, 3 + add rax, [psxRecLUT] + shl r12, 1 + add r12, [rax] + + + cmp ecx, dword ptr [r12+4] + jne psxDispatcherReg_recomp + + mov r12d, dword ptr [r12] + + and r12, 00fffffffh + jmp r12 + +psxDispatcherReg_recomp: + call psxRecRecompile + + mov eax, dword ptr [r12] + and rax, 00fffffffh + jmp rax + +psxDispatcherReg endp + +end diff --git a/pcsx2/x86/ix86-64/aR5900-64.S b/pcsx2/x86/ix86-64/aR5900-64.S new file mode 100644 index 0000000000..0f1c361549 --- /dev/null +++ b/pcsx2/x86/ix86-64/aR5900-64.S @@ -0,0 +1,249 @@ +// iR5900.c assembly routines +// zerofrog(@gmail.com) +.intel_syntax + +.extern cpuRegs +.extern recRecompile +.extern recLUT +.extern lbase +.extern s_pCurBlock_ltime +.extern g_EEFreezeRegs + +#define BLOCKTYPE_STARTPC 4 // startpc offset +#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot + +#define BASEBLOCK_SIZE 2 // in dwords +#define PCOFFSET 0x2a8 + +#define REG_PC %edi +#define REG_BLOCK %r14 // preserved across calls +#define REG_BLOCKd %r14d + +.globl R5900Execute +R5900Execute: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + // calc PC_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [cpuRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // g_EEFreezeRegs = 1; + mov dword ptr [g_EEFreezeRegs], 1 + + cmp REG_PC, [REG_BLOCK+4] + jne Execute_Recompile + mov %edx, [REG_BLOCK] + and %rdx, 0xfffffff // pFnptr + jnz Execute_Function + +Execute_Recompile: + call recRecompile + mov %edx, [REG_BLOCK] + and %rdx, 0xfffffff // pFnptr + +Execute_Function: + call %rdx + + // g_EEFreezeRegs = 0; + mov dword ptr [g_EEFreezeRegs], 0 + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + + ret + +.globl Dispatcher +Dispatcher: + // EDX contains the jump addr to modify + push %rdx + + // calc PC_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov %eax, dword ptr [cpuRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // check if startpc == cpuRegs.pc + //and %ecx, 0x5fffffff // remove higher bits + cmp REG_PC, dword ptr [REG_BLOCK+BLOCKTYPE_STARTPC] + je Dispatcher_CheckPtr + + // recompile + call recRecompile +Dispatcher_CheckPtr: + mov REG_BLOCKd, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test REG_BLOCKd, REG_BLOCKd + jnz Dispatcher_CallFn + // throw an exception + int 10 + +Dispatcher_CallFn: +#endif + + and REG_BLOCK, 0x0fffffff + mov %rdx, REG_BLOCK + pop %rcx // x86Ptr to mod + sub %rdx, %rcx + sub %rdx, 4 + mov [%rcx], %edx + + jmp REG_BLOCK + + +.globl DispatcherClear +DispatcherClear: + // EDX contains the current pc + mov dword ptr [cpuRegs + PCOFFSET], %edx + mov %eax, %edx + + // calc PC_GETBLOCK + // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + mov REG_BLOCKd, %edx + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + cmp %edx, dword ptr [REG_BLOCK + BLOCKTYPE_STARTPC] + jne DispatcherClear_Recompile + + mov %eax, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test %eax, %eax + jnz DispatcherClear_CallFn + // throw an exception + int 10 + +DispatcherClear_CallFn: +#endif + + and %rax, 0x0fffffff + jmp %rax + +DispatcherClear_Recompile: + mov REG_PC, %edx + call recRecompile + mov %eax, dword ptr [REG_BLOCK] + + // r15 holds the prev x86 pointer + and %rax, 0x0fffffff + mov byte ptr [%r15], 0xe9 // jmp32 + mov %rdx, %rax + sub %rdx, %r15 + sub %rdx, 5 + mov [%r15+1], %edx + + jmp %rax + + + +// called when jumping to variable pc address +.globl DispatcherReg +DispatcherReg: + //s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc) + mov %eax, dword ptr [cpuRegs + PCOFFSET] + mov REG_PC, %eax + mov REG_BLOCKd, %eax + shl %rax, 32 + shr %rax, 48 + and REG_BLOCK, 0xfffc + shl %rax, 3 + add %rax, [recLUT] + shl REG_BLOCK, 1 + add REG_BLOCK, [%rax] + + // check if startpc == cpuRegs.pc + //and %eax, 0x5fffffff // remove higher bits + cmp REG_PC, dword ptr [REG_BLOCK+BLOCKTYPE_STARTPC] + jne DispatcherReg_recomp + + mov REG_BLOCKd, dword ptr [REG_BLOCK] + +#ifdef _DEBUG + test REG_BLOCKd, REG_BLOCKd + jnz CallFn2 + // throw an exception + int 10 + +CallFn2: + +#endif + + and REG_BLOCK, 0x0fffffff + jmp REG_BLOCK // fnptr + +DispatcherReg_recomp: + call recRecompile + + mov %eax, dword ptr [REG_BLOCK] + and %rax, 0x0fffffff + jmp %rax // fnptr + + +.globl _StartPerfCounter +_StartPerfCounter: + + push %rax + push %rbx + push %rcx + + rdtsc + mov dword ptr [lbase], %eax + mov dword ptr [lbase + 4], %edx + + pop %rcx + pop %rbx + pop %rax + ret + +.globl _StopPerfCounter +_StopPerfCounter: + + push %rax + push %rbx + push %rcx + + rdtsc + + sub %eax, dword ptr [lbase] + sbb %edx, dword ptr [lbase + 4] + mov %ecx, s_pCurBlock_ltime + add %eax, dword ptr [%ecx] + adc %edx, dword ptr [%ecx + 4] + mov dword ptr [%ecx], %eax + mov dword ptr [%ecx + 4], %edx + pop %rcx + pop %rbx + pop %rax + ret diff --git a/pcsx2/x86/ix86-64/aR5900-64.asm b/pcsx2/x86/ix86-64/aR5900-64.asm new file mode 100644 index 0000000000..4f026c9486 --- /dev/null +++ b/pcsx2/x86/ix86-64/aR5900-64.asm @@ -0,0 +1,261 @@ +extern cpuRegs:abs +extern recRecompile:near +extern recLUT:abs +extern lbase:abs +extern s_pCurBlock_ltime:abs + +extern g_globalXMMData:abs +extern g_globalXMMSaved:abs +extern g_EEFreezeRegs:abs + +.code + +FreezeXMMRegs_ proc public + ;;assert( g_EEFreezeRegs ); + test ecx, ecx + jz XMMRestore + + cmp byte ptr [g_globalXMMSaved], 0 + jne XMMSaveEnd + + mov byte ptr [g_globalXMMSaved], 1 + + movaps xmmword ptr [g_globalXMMData + 000h], xmm0 + movaps xmmword ptr [g_globalXMMData + 010h], xmm1 + movaps xmmword ptr [g_globalXMMData + 020h], xmm2 + movaps xmmword ptr [g_globalXMMData + 030h], xmm3 + movaps xmmword ptr [g_globalXMMData + 040h], xmm4 + movaps xmmword ptr [g_globalXMMData + 050h], xmm5 + movaps xmmword ptr [g_globalXMMData + 060h], xmm6 + movaps xmmword ptr [g_globalXMMData + 070h], xmm7 + +XMMSaveEnd: + ret + +XMMRestore: + + cmp byte ptr [g_globalXMMSaved], 0 + je XMMSaveEnd + + mov byte ptr [g_globalXMMSaved], 0 + + ;; TODO: really need to backup all regs? + movaps xmm0, xmmword ptr [g_globalXMMData + 000h] + movaps xmm1, xmmword ptr [g_globalXMMData + 010h] + movaps xmm2, xmmword ptr [g_globalXMMData + 020h] + movaps xmm3, xmmword ptr [g_globalXMMData + 030h] + movaps xmm4, xmmword ptr [g_globalXMMData + 040h] + movaps xmm5, xmmword ptr [g_globalXMMData + 050h] + movaps xmm6, xmmword ptr [g_globalXMMData + 060h] + movaps xmm7, xmmword ptr [g_globalXMMData + 070h] + +XMMRestoreEnd: + ret + +FreezeXMMRegs_ endp + +R5900Interceptor proc public + sub rsp, 48 + jmp rdx +R5900Interceptor endp + +R5900Execute proc public + + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + + ;;BASEBLOCK* pblock = PC_GETBLOCK(cpuRegs.pc); + mov eax, dword ptr [cpuRegs + 02a8h] + mov ecx, eax + mov r14d, eax + shl rax, 32 + shr rax, 48 + and r14, 0fffch + shl rax, 3 + add rax, [recLUT] + shl r14, 1 + add r14, [rax] + + ;; g_EEFreezeRegs = 1; + mov dword ptr [g_EEFreezeRegs], 1 + + cmp ecx, [r14+4] + jne Execute_Recompile + mov edx, [r14] + and rdx, 0fffffffh ;; pFnptr + jnz Execute_Function + +Execute_Recompile: + call recRecompile + mov edx, [r14] + and rdx, 0fffffffh ;; pFnptr + +Execute_Function: + call R5900Interceptor + + ;; g_EEFreezeRegs = 0; + mov dword ptr [g_EEFreezeRegs], 0 + + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + + ret + +R5900Execute endp + +Dispatcher proc public + + mov [rsp+40], rdx + + mov eax, dword ptr [cpuRegs + 02a8h] + mov ecx, eax + mov r14d, eax + shl rax, 32 + shr rax, 48 + and r14, 0fffch + shl rax, 3 + add rax, [recLUT] + shl r14, 1 + add r14, [rax] + + + + cmp ecx, dword ptr [r14+4] + je Dispatcher_CheckPtr + + + call recRecompile +Dispatcher_CheckPtr: + mov r14d, dword ptr [r14] + + and r14, 0fffffffh + mov rdx, r14 + mov rcx, [rsp+40] + sub rdx, rcx + sub rdx, 4 + mov [rcx], edx + + jmp r14 +Dispatcher endp + +DispatcherClear proc public + + mov dword ptr [cpuRegs + 02a8h], edx + mov eax, edx + + + + mov r14d, edx + shl rax, 32 + shr rax, 48 + and r14, 0fffch + shl rax, 3 + add rax, [recLUT] + shl r14, 1 + add r14, [rax] + + cmp edx, dword ptr [r14 + 4] + jne DispatcherClear_Recompile + + mov eax, dword ptr [r14] + + and rax, 0fffffffh + jmp rax + +DispatcherClear_Recompile: + mov ecx, edx + call recRecompile + mov eax, dword ptr [r14] + + + and rax, 0fffffffh + mov byte ptr [r15], 0e9h + mov rdx, rax + sub rdx, r15 + sub rdx, 5 + mov [r15+1], edx + + jmp rax +DispatcherClear endp + + + +DispatcherReg proc public + + mov eax, dword ptr [cpuRegs + 02a8h] + mov ecx, eax + mov r14d, eax + shl rax, 32 + shr rax, 48 + and r14, 0fffch + shl rax, 3 + add rax, [recLUT] + shl r14, 1 + add r14, [rax] + + + + cmp ecx, dword ptr [r14+4] + jne DispatcherReg_recomp + + mov r14d, dword ptr [r14] + + and r14, 0fffffffh + jmp r14 + +DispatcherReg_recomp: + call recRecompile + + mov eax, dword ptr [r14] + and rax, 0fffffffh + jmp rax +DispatcherReg endp + +_StartPerfCounter proc public + push rax + push rbx + push rcx + + rdtsc + mov dword ptr [lbase], eax + mov dword ptr [lbase + 4], edx + + pop rcx + pop rbx + pop rax + ret +_StartPerfCounter endp + +_StopPerfCounter proc public + push rax + push rbx + push rcx + + rdtsc + + sub eax, dword ptr [lbase] + sbb edx, dword ptr [lbase + 4] + mov ecx, [s_pCurBlock_ltime] + add eax, dword ptr [ecx] + adc edx, dword ptr [ecx + 4] + mov dword ptr [ecx], eax + mov dword ptr [ecx + 4], edx + pop rcx + pop rbx + pop rax + ret +_StopPerfCounter endp + +end diff --git a/pcsx2/x86/ix86-64/aVUzerorec-64.asm b/pcsx2/x86/ix86-64/aVUzerorec-64.asm new file mode 100644 index 0000000000..4bf72c1bb4 --- /dev/null +++ b/pcsx2/x86/ix86-64/aVUzerorec-64.asm @@ -0,0 +1,126 @@ +;; iR3000A.c assembly routines +;; zerofrog(@gmail.com) +extern svudispfntemp:near +extern QueryPerformanceCounter:near +extern s_TotalVUCycles:abs +extern s_callstack:ptr +extern s_vu1esp:abs +extern s_writeQ:abs +extern s_writeP:abs +extern g_curdebugvu:abs +extern SuperVUGetProgram:near +extern SuperVUCleanupProgram:near +extern g_sseVUMXCSR:abs +extern g_sseMXCSR:abs + +extern svubase:abs + +.code + +;; SuperVUExecuteProgram(u32 startpc, int vuindex) +SuperVUExecuteProgram proc public + + ;; uncomment only if SUPERVU_COUNT is defined + ;; { + ;push rcx + ;push rdx + ;mov rcx, svubase + ;sub rsp,32 + ;call QueryPerformanceCounter + ;add rsp,32 + ;pop rdx + ;pop rcx + ;; } + + mov rax, [rsp] + mov dword ptr [s_TotalVUCycles], 0 + + sub rsp, 48-8+80 + mov [rsp+48], rcx + mov [rsp+56], rdx + + mov [s_callstack], rax + + call SuperVUGetProgram + + mov [rsp+64], rbp + mov [rsp+72], rsi + mov [rsp+80], rdi + mov [rsp+88], rbx + mov [rsp+96], r12 + mov [rsp+104], r13 + mov [rsp+112], r14 + mov [rsp+120], r15 + + ;; _DEBUG + ;;mov [s_vu1esp], rsp + + ldmxcsr [g_sseVUMXCSR] + mov dword ptr [s_writeQ], 0ffffffffh + mov dword ptr [s_writeP], 0ffffffffh + jmp rax +SuperVUExecuteProgram endp + +SuperVUEndProgram proc public + ;; restore cpu state + ldmxcsr [g_sseMXCSR] + + mov rcx, [rsp+48] + mov rdx, [rsp+56] + mov rbp, [rsp+64] + mov rsi, [rsp+72] + mov rdi, [rsp+80] + mov rbx, [rsp+88] + mov r12, [rsp+96] + mov r13, [rsp+104] + mov r14, [rsp+112] + mov r15, [rsp+120] + + ;; _DEBUG + ;;sub [s_vu1esp], rsp + + add rsp, 128-32 + call SuperVUCleanupProgram + add rsp, 32 + jmp [s_callstack] ;; so returns correctly +SuperVUEndProgram endp + +svudispfn proc public + mov [g_curdebugvu], rax + push rcx + push rdx + push rbp + push rsi + push rdi + push rbx + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + sub rsp, 32 + call svudispfntemp + add rsp, 32 + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbx + pop rdi + pop rsi + pop rbp + pop rdx + pop rcx + ret +svudispfn endp + +end diff --git a/pcsx2/x86/ix86-64/aVif_proc-64.asm b/pcsx2/x86/ix86-64/aVif_proc-64.asm new file mode 100644 index 0000000000..d263b48f15 --- /dev/null +++ b/pcsx2/x86/ix86-64/aVif_proc-64.asm @@ -0,0 +1,1827 @@ +extern _vifRegs:abs +extern _vifMaskRegs:abs +extern _vifRow:abs +extern _vifCol:abs +extern s_TempDecompress:abs + + +.code + +UNPACK_Write0_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [rcx+DEST_OFFSET], r0 + endm + +UNPACK_Write1_Regular macro r0, CL, DEST_OFFSET, MOVDQA + MOVDQA [rcx], r0 + add rcx, rdi + endm + +UNPACK_Write0_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write0_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + +UNPACK_Write1_Mask macro r0, CL, DEST_OFFSET, MOVDQA + UNPACK_Write1_Regular r0, CL, DEST_OFFSET, MOVDQA + endm + + +UNPACK_Write0_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + + movdqa xmm3, [rax + 64*(CL) + 48] + pand r0, xmm3 + pandn xmm3, [rcx] + por r0, xmm3 + MOVDQA [rcx], r0 + add rcx, 16 + endm + + +UNPACK_Write1_WriteMask macro r0, CL, DEST_OFFSET, MOVDQA + + movdqa xmm3, [rax + 64*(0) + 48] + pand r0, xmm3 + pandn xmm3, [rcx] + por r0, xmm3 + MOVDQA [rcx], r0 + add rcx, rdi + endm + +UNPACK_Mask_SSE_0 macro r0 + pand r0, xmm3 + por r0, xmm5 + endm + + + + +UNPACK_Mask_SSE_1 macro r0 + + pand r0, xmm3 + por r0, xmm5 + pand xmm3, xmm6 + paddd r0, xmm3 + endm + + + +UNPACK_Mask_SSE_2 macro r0 + + + pand r0, xmm3 + pand xmm3, xmm6 + paddd xmm6, r0 + por r0, xmm5 + paddd r0, xmm3 + endm + +UNPACK_WriteMask_SSE_0 macro r0 + UNPACK_Mask_SSE_0 r0 + endm +UNPACK_WriteMask_SSE_1 macro r0 + UNPACK_Mask_SSE_1 r0 + endm +UNPACK_WriteMask_SSE_2 macro r0 + UNPACK_Mask_SSE_2 r0 + endm + +UNPACK_Regular_SSE_0 macro r0 + endm + +UNPACK_Regular_SSE_1 macro r0 + paddd r0, xmm6 + endm + +UNPACK_Regular_SSE_2 macro r0 + paddd r0, xmm6 + movdqa xmm6, r0 + endm + + +UNPACK_Setup_Mask_SSE macro CL + mov rax, [_vifMaskRegs] + movdqa xmm4, [rax + 64*(CL) + 16] + movdqa xmm5, [rax + 64*(CL) + 32] + movdqa xmm3, [rax + 64*(CL)] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Start_Setup_Mask_SSE_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + +UNPACK_Start_Setup_Mask_SSE_1 macro CL + mov rax, [_vifMaskRegs] + movdqa xmm4, [rax + 64*(CL) + 16] + movdqa xmm5, [rax + 64*(CL) + 32] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Start_Setup_Mask_SSE_2 macro CL + endm + +UNPACK_Setup_Mask_SSE_0_1 macro CL + endm +UNPACK_Setup_Mask_SSE_1_1 macro CL + mov rax, [_vifMaskRegs] + movdqa xmm3, [rax + 64*(0)] + endm + + +UNPACK_Setup_Mask_SSE_2_1 macro CL + + mov rax, [_vifMaskRegs] + movdqa xmm4, [rax + 64*(0) + 16] + movdqa xmm5, [rax + 64*(0) + 32] + movdqa xmm3, [rax + 64*(0)] + pand xmm4, xmm6 + pand xmm5, xmm7 + por xmm5, xmm4 + endm + +UNPACK_Setup_Mask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_Mask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm + + +UNPACK_Setup_WriteMask_SSE_0_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_1_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_2_0 macro CL + UNPACK_Setup_Mask_SSE CL + endm +UNPACK_Setup_WriteMask_SSE_0_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_1_1 macro CL + UNPACK_Setup_Mask_SSE_1_1 CL + endm + +UNPACK_Setup_WriteMask_SSE_2_1 macro CL + UNPACK_Setup_Mask_SSE_2_1 CL + endm + +UNPACK_Start_Setup_WriteMask_SSE_0 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_1 macro CL + UNPACK_Start_Setup_Mask_SSE_1 CL + endm +UNPACK_Start_Setup_WriteMask_SSE_2 macro CL + UNPACK_Start_Setup_Mask_SSE_2 CL + endm + +UNPACK_Start_Setup_Regular_SSE_0 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_1 macro CL + endm +UNPACK_Start_Setup_Regular_SSE_2 macro CL + endm +UNPACK_Setup_Regular_SSE_0_0 macro CL + endm +UNPACK_Setup_Regular_SSE_1_0 macro CL + endm +UNPACK_Setup_Regular_SSE_2_0 macro CL + endm +UNPACK_Setup_Regular_SSE_0_1 macro CL + endm +UNPACK_Setup_Regular_SSE_1_1 macro CL + endm +UNPACK_Setup_Regular_SSE_2_1 macro CL + endm + +UNPACK_INC_DST_0_Regular macro qw + add rcx, (16*qw) + endm +UNPACK_INC_DST_1_Regular macro qw + endm +UNPACK_INC_DST_0_Mask macro qw + add rcx, (16*qw) + endm +UNPACK_INC_DST_1_Mask macro qw + endm +UNPACK_INC_DST_0_WriteMask macro qw + endm +UNPACK_INC_DST_1_WriteMask macro qw + endm + + +UNPACK4_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm7 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm7, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + endm + + +UNPACK3_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + endm + +UNPACK2_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 2 + endm + +UNPACK1_SSE macro CL, TOTALCL, MaskType, ModeType + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 1 + endm + + + +UNPACK_S_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm7, [rdx] + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_S_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm2, [rdx] + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_S_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_S_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_S_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm1, QWORD PTR [rdx] + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_S_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_S_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_S_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm7, QWORD PTR [rdx] + punpcklwd xmm7, xmm7 + UNPACK_RIGHTSHIFT xmm7, 16 + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_S_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm2, QWORD PTR [rdx] + punpcklwd xmm2, xmm2 + UNPACK_RIGHTSHIFT xmm2, 16 + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + add rdx, 6 + endm + +UNPACK_S_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm1, dword ptr [rdx] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm1, 16 + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_S_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 2 + endm + +UNPACK_S_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_S_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movd xmm7, dword ptr [rdx] + punpcklbw xmm7, xmm7 + punpcklwd xmm7, xmm7 + UNPACK_RIGHTSHIFT xmm7, 24 + + pshufd xmm0, xmm7, 0 + pshufd xmm1, xmm7, 055h + pshufd xmm2, xmm7, 0aah + pshufd xmm7, xmm7, 0ffh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_S_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd xmm2, dword ptr [rdx] + punpcklbw xmm2, xmm2 + punpcklwd xmm2, xmm2 + UNPACK_RIGHTSHIFT xmm2, 24 + + pshufd xmm0, xmm2, 0 + pshufd xmm1, xmm2, 055h + pshufd xmm2, xmm2, 0aah + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 3 + endm + +UNPACK_S_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm1, dword ptr [rdx] + punpcklbw xmm1, xmm1 + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm1, 24 + + pshufd xmm0, xmm1, 0 + pshufd xmm1, xmm1, 055h + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 2 + endm + +UNPACK_S_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_S_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + pshufd xmm0, xmm0, 0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + inc rdx + endm + +UNPACK_S_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_S_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V2_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + MOVDQA xmm0, [rdx] + MOVDQA xmm2, [rdx+16] + + pshufd xmm1, xmm0, 0eeh + pshufd xmm7, xmm2, 0eeh + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V2_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+8] + movq xmm2, QWORD PTR [rdx+16] + movq xmm7, QWORD PTR [rdx+24] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V2_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + MOVDQA xmm0, [rdx] + movq xmm2, QWORD PTR [rdx+16] + pshufd xmm1, xmm0, 0eeh + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V2_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+8] + movq xmm2, QWORD PTR [rdx+16] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V2_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+8] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V2_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V2_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_32SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V2_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + punpckhwd xmm2, [rdx] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + add rdx, 16 + endm + +UNPACK_V2_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V2_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + punpckhwd xmm2, [rdx] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V2_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V2_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + UNPACK_RIGHTSHIFT xmm0, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V2_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V2_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + UNPACK_RIGHTSHIFT xmm0, 16 + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_V2_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + + + +UNPACK_V2_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + + punpcklbw xmm0, xmm0 + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + + punpckhqdq xmm1, xmm0 + punpckhqdq xmm7, xmm2 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + punpckhqdq xmm7, xmm7 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V2_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + + punpcklbw xmm0, xmm0 + punpckhwd xmm2, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpcklqdq xmm2, xmm2 + punpckhqdq xmm1, xmm1 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 6 + endm + +UNPACK_V2_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + + punpckhqdq xmm1, xmm0 + + punpcklqdq xmm0, xmm0 + punpckhqdq xmm1, xmm1 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_V2_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V2_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + punpcklqdq xmm0, xmm0 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 2 + endm + +UNPACK_V2_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V2_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V3_32SSE_4x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [rdx] + movdqu xmm1, [rdx+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+0 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + + MOVDQA xmm7, [rdx+32] + movdqu xmm2, [rdx+24] + psrldq xmm7, 4 + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+3 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm7 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm7, CL+3, 48, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 4 + + add rdx, 48 + endm + +UNPACK_V3_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_4x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_3x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [rdx] + movdqu xmm1, [rdx+12] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm0 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm0, CL, 0, movdqa + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+1 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm1 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm1, CL+1, 16, movdqa + + movdqu xmm2, [rdx+24] + + @CatStr(UNPACK_Setup_, MaskType, _SSE_, ModeType, _, TOTALCL) CL+2 + @CatStr(UNPACK_, MaskType, _SSE_, ModeType) xmm2 + @CatStr(UNPACK_Write, TOTALCL, _, MaskType) xmm2, CL+2, 32, movdqa + + @CatStr(UNPACK_INC_DST_, TOTALCL, _, MaskType) 3 + + add rdx, 36 + endm + +UNPACK_V3_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_3x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_2x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [rdx] + movdqu xmm1, [rdx+12] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V3_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_2x CL, TOTALCL, MaskType, ModeType, movdqu + endm + +UNPACK_V3_32SSE_1x macro CL, TOTALCL, MaskType, ModeType, MOVDQA + MOVDQA xmm0, [rdx] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V3_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqa + endm +UNPACK_V3_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_32SSE_1x CL, TOTALCL, MaskType, ModeType, movdqu + endm + + +UNPACK_V3_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+6] + + punpcklwd xmm0, xmm0 + movq xmm2, QWORD PTR [rdx+12] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 16 + movq xmm7, QWORD PTR [rdx+18] + UNPACK_RIGHTSHIFT xmm1, 16 + punpcklwd xmm2, xmm2 + punpcklwd xmm7, xmm7 + + UNPACK_RIGHTSHIFT xmm2, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V3_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+6] + + punpcklwd xmm0, xmm0 + movq xmm2, QWORD PTR [rdx+12] + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 16 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 18 + endm + +UNPACK_V3_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+6] + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V3_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 6 + endm + +UNPACK_V3_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_16SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V3_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movq xmm1, QWORD PTR [rdx] + movq xmm7, QWORD PTR [rdx+6] + + punpcklbw xmm1, xmm1 + punpcklbw xmm7, xmm7 + punpcklwd xmm0, xmm1 + psrldq xmm1, 6 + punpcklwd xmm2, xmm7 + psrldq xmm7, 6 + punpcklwd xmm1, xmm1 + UNPACK_RIGHTSHIFT xmm0, 24 + punpcklwd xmm7, xmm7 + + UNPACK_RIGHTSHIFT xmm2, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm7, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V3_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + movd xmm1, dword ptr [rdx+3] + + punpcklbw xmm0, xmm0 + movd xmm2, dword ptr [rdx+6] + punpcklbw xmm1, xmm1 + punpcklwd xmm0, xmm0 + punpcklbw xmm2, xmm2 + + punpcklwd xmm1, xmm1 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 9 + endm + +UNPACK_V3_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + movd xmm1, dword ptr [rdx+3] + + punpcklbw xmm0, xmm0 + punpcklbw xmm1, xmm1 + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 6 + endm + +UNPACK_V3_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V3_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 3 + endm + +UNPACK_V3_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V3_8SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +UNPACK_V4_32SSE_4A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [rdx] + movdqa xmm1, [rdx+16] + movdqa xmm2, [rdx+32] + movdqa xmm7, [rdx+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 64 + endm + +UNPACK_V4_32SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + movdqu xmm1, [rdx+16] + movdqu xmm2, [rdx+32] + movdqu xmm7, [rdx+48] + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 64 + endm + +UNPACK_V4_32SSE_3A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [rdx] + movdqa xmm1, [rdx+16] + movdqa xmm2, [rdx+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 48 + endm + +UNPACK_V4_32SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + movdqu xmm1, [rdx+16] + movdqu xmm2, [rdx+32] + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 48 + endm + +UNPACK_V4_32SSE_2A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [rdx] + movdqa xmm1, [rdx+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V4_32SSE_2 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + movdqu xmm1, [rdx+16] + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V4_32SSE_1A macro CL, TOTALCL, MaskType, ModeType + movdqa xmm0, [rdx] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V4_32SSE_1 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + + +UNPACK_V4_16SSE_4A macro CL, TOTALCL, MaskType, ModeType + + punpcklwd xmm0, [rdx] + punpckhwd xmm1, [rdx] + punpcklwd xmm2, [rdx+16] + punpckhwd xmm7, [rdx+16] + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V4_16SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + movdqu xmm2, [rdx+16] + + punpckhwd xmm1, xmm0 + punpckhwd xmm7, xmm2 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm7, 16 + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 32 + endm + +UNPACK_V4_16SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + punpckhwd xmm1, [rdx] + punpcklwd xmm2, [rdx+16] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V4_16SSE_3 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + movq xmm2, QWORD PTR [rdx+16] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + UNPACK_RIGHTSHIFT xmm2, 16 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 24 + endm + +UNPACK_V4_16SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + punpckhwd xmm1, [rdx] + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V4_16SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movq xmm1, QWORD PTR [rdx+8] + + punpcklwd xmm0, xmm0 + punpcklwd xmm1, xmm1 + + UNPACK_RIGHTSHIFT xmm0, 16 + UNPACK_RIGHTSHIFT xmm1, 16 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V4_16SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklwd xmm0, [rdx] + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V4_16SSE_1 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 16 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + + +UNPACK_V4_8SSE_4A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [rdx] + punpckhbw xmm2, [rdx] + + punpckhwd xmm1, xmm0 + punpckhwd xmm7, xmm2 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm7, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V4_8SSE_4 macro CL, TOTALCL, MaskType, ModeType + movdqu xmm0, [rdx] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm7, xmm2 + punpckhwd xmm1, xmm0 + punpcklwd xmm2, xmm2 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm7, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm1, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 16 + endm + +UNPACK_V4_8SSE_3A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [rdx] + punpckhbw xmm2, [rdx] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V4_8SSE_3 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + movd xmm2, dword ptr [rdx+8] + + punpcklbw xmm0, xmm0 + punpcklbw xmm2, xmm2 + + punpckhwd xmm1, xmm0 + punpcklwd xmm2, xmm2 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + UNPACK_RIGHTSHIFT xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 12 + endm + +UNPACK_V4_8SSE_2A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [rdx] + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V4_8SSE_2 macro CL, TOTALCL, MaskType, ModeType + movq xmm0, QWORD PTR [rdx] + + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + UNPACK_RIGHTSHIFT xmm1, 24 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V4_8SSE_1A macro CL, TOTALCL, MaskType, ModeType + punpcklbw xmm0, [rdx] + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_V4_8SSE_1 macro CL, TOTALCL, MaskType, ModeType + movd xmm0, dword ptr [rdx] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + UNPACK_RIGHTSHIFT xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + + +DECOMPRESS_RGBA macro OFFSET + mov bl, al + shl bl, 3 + mov byte ptr [s_TempDecompress+OFFSET], bl + + mov bx, ax + shr bx, 2 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+1], bl + + mov bx, ax + shr bx, 7 + and bx, 0f8h + mov byte ptr [s_TempDecompress+OFFSET+2], bl + mov bx, ax + shr bx, 8 + and bx, 080h + mov byte ptr [s_TempDecompress+OFFSET+3], bl + endm + +UNPACK_V4_5SSE_4 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [rdx] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [rdx+4] + DECOMPRESS_RGBA 8 + + shr eax, 16 + DECOMPRESS_RGBA 12 + + + movdqa xmm0, XMMWORD PTR [s_TempDecompress] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm7, xmm2 + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + psrld xmm0, 24 + psrld xmm1, 24 + psrld xmm2, 24 + psrld xmm7, 24 + + UNPACK4_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 8 + endm + +UNPACK_V4_5SSE_4A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_4 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_3 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [rdx] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + mov eax, dword ptr [rdx] + DECOMPRESS_RGBA 8 + + + movdqa xmm0, XMMWORD PTR [s_TempDecompress] + + punpckhbw xmm2, xmm0 + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + punpcklwd xmm2, xmm2 + + psrld xmm0, 24 + psrld xmm1, 24 + psrld xmm2, 24 + + UNPACK3_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 6 + endm + +UNPACK_V4_5SSE_3A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_3 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_2 macro CL, TOTALCL, MaskType, ModeType + mov eax, dword ptr [rdx] + DECOMPRESS_RGBA 0 + + shr eax, 16 + DECOMPRESS_RGBA 4 + + movq xmm0, QWORD PTR [s_TempDecompress] + + punpcklbw xmm0, xmm0 + + punpckhwd xmm1, xmm0 + punpcklwd xmm0, xmm0 + + psrld xmm0, 24 + psrld xmm1, 24 + + UNPACK2_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 4 + endm + +UNPACK_V4_5SSE_2A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_2 CL, TOTALCL, MaskType, ModeType + endm + +UNPACK_V4_5SSE_1 macro CL, TOTALCL, MaskType, ModeType + mov ax, word ptr [rdx] + DECOMPRESS_RGBA 0 + + movd xmm0, DWORD PTR [s_TempDecompress] + punpcklbw xmm0, xmm0 + punpcklwd xmm0, xmm0 + + psrld xmm0, 24 + + UNPACK1_SSE CL, TOTALCL, MaskType, ModeType + + add rdx, 2 + endm + +UNPACK_V4_5SSE_1A macro CL, TOTALCL, MaskType, ModeType + UNPACK_V4_5SSE_1 CL, TOTALCL, MaskType, ModeType + endm + + +SAVE_ROW_REG_BASE macro + mov rax, [_vifRow] + movdqa [rax], xmm6 + mov rax, [_vifRegs] + movss dword ptr [rax+0100h], xmm6 + psrldq xmm6, 4 + movss dword ptr [rax+0110h], xmm6 + psrldq xmm6, 4 + movss dword ptr [rax+0120h], xmm6 + psrldq xmm6, 4 + movss dword ptr [rax+0130h], xmm6 + endm + +SAVE_NO_REG macro + endm + + + +INIT_ARGS macro + mov rax, qword ptr [_vifRow] + mov r9, qword ptr [_vifCol] + movaps xmm6, XMMWORD PTR [rax] + movaps xmm7, XMMWORD PTR [r9] + endm + +INC_STACK macro reg + add rsp, 8 + endm + + + +defUNPACK_SkippingWrite macro name, MaskType, ModeType, qsize, sign, SAVE_ROW_REG +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType) proc public + + push rdi + INIT_ARGS + mov rax, [_vifRegs] + movzx rdi, byte ptr [rax + 040h] + movzx r9, byte ptr [rax + 041h] + sub rdi, r9 + shl rdi, 4 + + cmp r9d, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1) + cmp r9d, 2 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2) + cmp r9d, 3 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL1): + @CatStr(UNPACK_Start_Setup_, MaskType, _SSE_, ModeType) 0 + + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + + add rdi, 16 + + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16): + + test rdx, 15 + jz @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned) + + @CatStr(UNPACK_, name, SSE_1) 0, 1, MaskType, ModeType + + cmp r8d, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec) + sub r8d, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Align16) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_UnpackAligned): + + cmp r8d, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp r8d, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + cmp r8d, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3) + prefetchnta [rdx + 64] + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4): + @CatStr(UNPACK_, name, SSE_4A) 0, 1, MaskType, ModeType + + cmp r8d, (8*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4) + sub r8d, (4*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack4) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneUnpack4): + + sub r8d, (4*qsize) + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + cmp r8d, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1) + cmp r8d, (3*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2) + + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack3): + @CatStr(UNPACK_, name, SSE_3A) 0, 1, MaskType, ModeType + + sub r8d, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack2): + @CatStr(UNPACK_, name, SSE_2A) 0, 1, MaskType, ModeType + + sub r8d, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Unpack1): + @CatStr(UNPACK_, name, SSE_1A) 0, 1, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_DoneWithDec): + sub r8d, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C1_Done3): + SAVE_ROW_REG + mov eax, r8d + + pop rdi + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL2): + cmp r8d, (2*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + + add rcx, rdi + cmp r8d, (4*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2) + sub r8d, (2*qsize) + + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Unpack) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done2): + sub r8d, (2*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done3): + cmp r8d, qsize + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4) + + + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + sub r8d, qsize +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C2_Done4): + + SAVE_ROW_REG + mov eax, r8d + + pop rdi + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL3): + cmp r8d, (3*qsize) + + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + add rcx, rdi + cmp r8d, (6*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2) + sub r8d, (3*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done2): + sub r8d, (3*qsize) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done5): + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) + + cmp r8d, (2*qsize) + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3) + + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + sub r8d, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done3): + sub r8d, qsize + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C3_Done4): + SAVE_ROW_REG + mov eax, r8d + + pop rdi + + ret + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _WL4): + sub r9, 3 + push rdi + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack): + cmp r8d, (3*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3) + cmp r8d, (2*qsize) + jge @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2) + + @CatStr(UNPACK_, name, SSE_1) 0, 0, MaskType, ModeType + + + sub r8d, qsize + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack2): + @CatStr(UNPACK_, name, SSE_2) 0, 0, MaskType, ModeType + + + sub r8d, (2*qsize) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack3): + @CatStr(UNPACK_, name, SSE_3) 0, 0, MaskType, ModeType + + + sub r8d, (3*qsize) + mov rdi, r9 + +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX): + + + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + + @CatStr(UNPACK_, name, SSE_1) 3, 0, MaskType, ModeType + + sub r8d, qsize + cmp rdi, 1 + je @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop) + sub rdi, 1 + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_UnpackX) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_DoneLoop): + add rcx, [rsp] + cmp r8d, qsize + jl @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done) + jmp @CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Unpack) +@CatStr(name, _, sign, _, MaskType, _, ModeType, _C4_Done): + + SAVE_ROW_REG + INC_STACK() + mov eax, r8d + + + pop rdi + ret +@CatStr(UNPACK_SkippingWrite_, name, _, sign, _, MaskType, _, ModeType endp) +endm + +UNPACK_RIGHTSHIFT macro reg, shift + psrld reg, shift + endm + +defUNPACK_SkippingWrite2 macro name, qsize + defUNPACK_SkippingWrite name, Regular, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, u, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, u, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, u, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2 S_32, 4 +defUNPACK_SkippingWrite2 S_16, 2 +defUNPACK_SkippingWrite2 S_8, 1 +defUNPACK_SkippingWrite2 V2_32, 8 +defUNPACK_SkippingWrite2 V2_16, 4 +defUNPACK_SkippingWrite2 V2_8, 2 +defUNPACK_SkippingWrite2 V3_32, 12 +defUNPACK_SkippingWrite2 V3_16, 6 +defUNPACK_SkippingWrite2 V3_8, 3 +defUNPACK_SkippingWrite2 V4_32, 16 +defUNPACK_SkippingWrite2 V4_16, 8 +defUNPACK_SkippingWrite2 V4_8, 4 +defUNPACK_SkippingWrite2 V4_5, 2 + +UNPACK_RIGHTSHIFT macro reg, shift + psrad reg, shift + endm + + +defUNPACK_SkippingWrite2a macro name, qsize + defUNPACK_SkippingWrite name, Mask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Regular, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, Mask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, Mask, 2, qsize, s, SAVE_ROW_REG_BASE + defUNPACK_SkippingWrite name, WriteMask, 0, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 1, qsize, s, SAVE_NO_REG + defUNPACK_SkippingWrite name, WriteMask, 2, qsize, s, SAVE_ROW_REG_BASE + endm + +defUNPACK_SkippingWrite2a S_16, 2 +defUNPACK_SkippingWrite2a S_8, 1 +defUNPACK_SkippingWrite2a V2_16, 4 +defUNPACK_SkippingWrite2a V2_8, 2 +defUNPACK_SkippingWrite2a V3_16, 6 +defUNPACK_SkippingWrite2a V3_8, 3 +defUNPACK_SkippingWrite2a V4_16, 8 +defUNPACK_SkippingWrite2a V4_8, 4 + +end diff --git a/pcsx2/x86/ix86-64/fast_routines-64.asm b/pcsx2/x86/ix86-64/fast_routines-64.asm new file mode 100644 index 0000000000..77e2744ff5 --- /dev/null +++ b/pcsx2/x86/ix86-64/fast_routines-64.asm @@ -0,0 +1,294 @@ +; Pcsx2 - Pc Ps2 Emulator +; Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +;; Fast assembly routines for x86-64 masm compiler +;; zerofrog(@gmail.com) +.code + +;; mmx memcmp implementation, size has to be a multiple of 8 +;; returns 0 is equal, nonzero value if not equal +;; ~10 times faster than standard memcmp +;; (zerofrog) +;; u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +memcmp_mmx proc public + + cmp r8d, 32 + jl memcmp_Done4 + + ;; custom test first 8 to make sure things are ok + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + movq mm2, [rdx+16] + pmovmskb eax, mm0 + movq mm3, [rdx+24] + + ;; check if eq + cmp eax, 0ffh + je memcmp_NextComp + mov eax, 1 + jmp memcmp_End + +memcmp_NextComp: + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ;; check if eq + cmp eax, 0ffh + je memcmp_ContinueTest + mov eax, 1 + jmp memcmp_End + + cmp r8d, 64 + jl memcmp_Done8 + +memcmp_Cmp8: + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pcmpeqd mm4, [rcx+32] + pand mm0, mm2 + pcmpeqd mm5, [rcx+40] + pand mm0, mm3 + pcmpeqd mm6, [rcx+48] + pand mm0, mm4 + pcmpeqd mm7, [rcx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + ;; check if eq + cmp eax, 0ffh + je memcmp_Continue + mov eax, 1 + jmp memcmp_End + +memcmp_Continue: + sub r8d, 64 + add rdx, 64 + add rcx, 64 +memcmp_ContinueTest: + cmp r8d, 64 + jge memcmp_Cmp8 + +memcmp_Done8: + test r8d, 020h + jz memcmp_Done4 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ;; check if eq + cmp eax, 0ffh + je memcmp_Done4 + mov eax, 1 + jmp memcmp_End + +memcmp_Done4: + cmp r8d, 24 + jne memcmp_Done2 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + ;; check if eq + cmp eax, 0ffh + je memcmp_Done + mov eax, 1 + jmp memcmp_End + +memcmp_Done2: + cmp r8d, 16 + jne memcmp_Done1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + ;; check if eq + cmp eax, 0ffh + je memcmp_Done + mov eax, 1 + jmp memcmp_End + +memcmp_Done1: + cmp r8d, 8 + jne memcmp_Done + + mov eax, [rdx] + mov rdx, [rdx+4] + cmp eax, [rcx] + je memcmp_Next + mov eax, 1 + jmp memcmp_End + +memcmp_Next: + cmp rdx, [rcx+4] + je memcmp_Done + mov eax, 1 + jmp memcmp_End + +memcmp_Done: + xor eax, eax + +memcmp_End: + emms + ret +memcmp_mmx endp + +;; memxor_mmx +memxor_mmx proc public + + cmp r8d, 64 + jl memxor_Setup4 + + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + sub r8d, 64 + add rdx, 64 + cmp r8d, 64 + jl memxor_End8 + +memxor_Cmp8: + pxor mm0, [rdx] + pxor mm1, [rdx+8] + pxor mm2, [rdx+16] + pxor mm3, [rdx+24] + pxor mm4, [rdx+32] + pxor mm5, [rdx+40] + pxor mm6, [rdx+48] + pxor mm7, [rdx+56] + + sub r8d, 64 + add rdx, 64 + cmp r8d, 64 + jge memxor_Cmp8 + +memxor_End8: + pxor mm0, mm4 + pxor mm1, mm5 + pxor mm2, mm6 + pxor mm3, mm7 + + cmp r8d, 32 + jl memxor_End4 + pxor mm0, [rdx] + pxor mm1, [rdx+8] + pxor mm2, [rdx+16] + pxor mm3, [rdx+24] + sub r8d, 32 + add rdx, 32 + jmp memxor_End4 + +memxor_Setup4: + cmp r8d, 32 + jl memxor_Setup2 + + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + sub r8d, 32 + add rdx, 32 + +memxor_End4: + pxor mm0, mm2 + pxor mm1, mm3 + + cmp r8d, 16 + jl memxor_End2 + pxor mm0, [rdx] + pxor mm1, [rdx+8] + sub r8d, 16 + add rdx, 16 + jmp memxor_End2 + +memxor_Setup2: + cmp r8d, 16 + jl memxor_Setup1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + sub r8d, 16 + add rdx, 16 + +memxor_End2: + pxor mm0, mm1 + + cmp r8d, 8 + jl memxor_End1 + pxor mm0, [rdx] +memxor_End1: + movq [rcx], mm0 + jmp memxor_End + +memxor_Setup1: + movq mm0, [rdx] + movq [rcx], mm0 +memxor_End: + emms + ret + +memxor_mmx endp + +end \ No newline at end of file diff --git a/pcsx2/x86/ix86-64/iCore-64.cpp b/pcsx2/x86/ix86-64/iCore-64.cpp new file mode 100644 index 0000000000..3446f9b686 --- /dev/null +++ b/pcsx2/x86/ix86-64/iCore-64.cpp @@ -0,0 +1,720 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +extern "C" { + +#if defined(_WIN32) +#include +#endif + +#include "PS2Etypes.h" +#include "System.h" +#include "R5900.h" +#include "Vif.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "iCore.h" +#include "R3000A.h" + +u16 x86FpuState, iCWstate; +u16 g_mmxAllocCounter = 0; + +// X86 caching +extern _x86regs x86regs[X86REGS]; +extern u16 g_x86AllocCounter; + +} // end extern "C" + +u32 g_recFnArgs[4]; + +#include +using namespace std; + +// use special x86 register allocation for ia32 +void _initX86regs() { + memset(x86regs, 0, sizeof(x86regs)); + g_x86AllocCounter = 0; +} + +uptr _x86GetAddr(int type, int reg) +{ + switch(type&~X86TYPE_VU1) { + case X86TYPE_GPR: return (uptr)&cpuRegs.GPR.r[reg]; + case X86TYPE_VI: { + //assert( reg < 16 || reg == REG_R ); + return (type&X86TYPE_VU1)?(uptr)&VU1.VI[reg]:(uptr)&VU0.VI[reg]; + } + case X86TYPE_MEMOFFSET: return 0; + case X86TYPE_VIMEMOFFSET: return 0; + case X86TYPE_VUQREAD: return (type&X86TYPE_VU1)?(uptr)&VU1.VI[REG_Q]:(uptr)&VU0.VI[REG_Q]; + case X86TYPE_VUPREAD: return (type&X86TYPE_VU1)?(uptr)&VU1.VI[REG_P]:(uptr)&VU0.VI[REG_P]; + case X86TYPE_VUQWRITE: return (type&X86TYPE_VU1)?(uptr)&VU1.q:(uptr)&VU0.q; + case X86TYPE_VUPWRITE: return (type&X86TYPE_VU1)?(uptr)&VU1.p:(uptr)&VU0.p; + case X86TYPE_PSX: return (uptr)&psxRegs.GPR.r[reg]; + case X86TYPE_PCWRITEBACK: + return (uptr)&g_recWriteback; + case X86TYPE_VUJUMP: + return (uptr)&g_recWriteback; + case X86TYPE_FNARG: + return (uptr)&g_recFnArgs[reg]; + default: assert(0); + } + + return 0; +} + +int _getFreeX86reg(int mode) +{ + int i, tempi; + u32 bestcount = 0x10000; + x86IntRegType* pregs = (mode&MODE_8BITREG)?g_x868bitregs:g_x86allregs; + int maxreg = (mode&MODE_8BITREG)?ARRAYSIZE(g_x868bitregs):ARRAYSIZE(g_x86allregs); + + if( !(mode&MODE_8BITREG) && (mode&0x80000000) ) { + // prioritize the temp registers + for (i=0; i= 0 && reg < 32 ); + +// if( X86_ISVI(type) ) +// assert( reg < 16 || reg == REG_R ); + + // don't alloc EAX and ESP,EBP if MODE_NOFRAME + int oldmode = mode; + int noframe = mode&MODE_NOFRAME; + int mode8bit = mode&MODE_8BITREG; + x86IntRegType* pregs = (mode&MODE_8BITREG)?g_x868bitregs:g_x86allregs; + int maxreg = (mode&MODE_8BITREG)?ARRAYSIZE(g_x868bitregs):ARRAYSIZE(g_x86allregs); + mode &= ~(MODE_NOFRAME|MODE_8BITREG); + int readfromreg = -1; + + + if( type != X86TYPE_TEMP ) { + + if( mode8bit ) { + // make sure reg isn't in the non8bit regs + + for(j = 0; j < ARRAYSIZE(g_x86non8bitregs); ++j) { + int i = g_x86non8bitregs[j]; + if (!x86regs[i].inuse || x86regs[i].type != type || x86regs[i].reg != reg) + continue; + + if( mode & MODE_READ ) { + readfromreg = i; + x86regs[i].inuse = 0; + break; + } + else if( mode & MODE_WRITE ) { + x86regs[i].inuse = 0; + break; + } + } + } + + for (j=0; j= 0 ) { + // requested specific reg, so return that instead + if( i != x86reg ) { + if( x86regs[i].mode & MODE_READ ) readfromreg = i; + //if( x86regs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= x86regs[i].mode&MODE_WRITE; + x86regs[i].inuse = 0; + break; + } + } + + if( type != X86TYPE_TEMP && !(x86regs[i].mode & MODE_READ) && (mode&MODE_READ)) { + + if( type == X86TYPE_GPR ) { + + if( reg == 0 ) XOR64RtoR(i, i); + else { + if( GPR_IS_CONST1(reg) ) + MOV64ItoR(i, g_cpuConstRegs[reg].UD[0]); + else + MOV64MtoR(i, _x86GetAddr(type, reg)); + } + } + else if( X86_ISVI(type) && reg < 16 ) MOVZX32M16toR(i, _x86GetAddr(type, reg)); + else // the rest are 32 bit + MOV32MtoR(i, _x86GetAddr(type, reg)); + + x86regs[i].mode |= MODE_READ; + } + + x86regs[i].needed = 1; + x86regs[i].mode|= mode; + return i; + } + } + + // currently only gpr regs are const + if( type == X86TYPE_GPR && (mode & MODE_WRITE) && reg < 32 ) { + //assert( !(g_cpuHasConstReg & (1<= 0 ) MOV64RtoR(x86reg, readfromreg); + else { + if( type == X86TYPE_GPR ) { + + if( reg == 0 ) { + if( mode & MODE_READ ) + XOR64RtoR(x86reg, x86reg); + return x86reg; + } + + int xmmreg; + if( (xmmreg = _checkXMMreg(XMMTYPE_GPRREG, reg, 0)) >= 0 ) { + // destroy the xmm reg, but don't flush + SSE_MOVHPS_XMM_to_M64(_x86GetAddr(type, reg)+8, xmmreg); + + if( mode & MODE_READ ) + SSE2_MOVQ_XMM_to_R(x86reg, xmmreg); + + if( xmmregs[xmmreg].mode & MODE_WRITE ) + x86regs[x86reg].mode |= MODE_WRITE; + + // don't flush + xmmregs[xmmreg].inuse = 0; + } + else { + if( mode & MODE_READ ) { + if( GPR_IS_CONST1(reg) ) + MOV64ItoR(x86reg, g_cpuConstRegs[reg].UD[0]); + else + MOV64MtoR(x86reg, _x86GetAddr(type, reg)); + } + } + } + else if( mode & MODE_READ ) { + if( X86_ISVI(type) && reg < 16 ) { + if( reg == 0 ) XOR32RtoR(x86reg, x86reg); + else MOVZX32M16toR(x86reg, _x86GetAddr(type, reg)); + } + else MOV32MtoR(x86reg, _x86GetAddr(type, reg)); + } + } + + return x86reg; +} + +int _checkX86reg(int type, int reg, int mode) +{ + int i; + + for (i=0; i= 0 && x86reg < X86REGS ); + + if( x86regs[x86reg].inuse && (x86regs[x86reg].mode&MODE_WRITE) ) { + + if( x86regs[x86reg].type == X86TYPE_GPR ) + MOV64RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + if( X86_ISVI(x86regs[x86reg].type) && x86regs[x86reg].reg < 16 ) + MOV16RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + else + MOV32RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + } + + x86regs[x86reg].mode &= ~MODE_WRITE; + x86regs[x86reg].inuse = 0; +} + +void _flushX86regs() +{ + int i; + + for (i=0; iregs[x86regs[i].reg]&EEINST_USED) ) { + return 1; + } + } + } + return 0; +} + +// EE +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV64ItoR( to, g_cpuConstRegs[fromgpr].UD[0] ); + else { + int mmreg; + + if( (mmreg = _checkX86reg(X86TYPE_GPR, fromgpr, MODE_READ)) >= 0) { + MOV64RtoR(to, mmreg); + } + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { + SSE2_MOVQ_XMM_to_R(to, mmreg); + } + else { + MOV64MtoR(to, (uptr)&cpuRegs.GPR.r[ fromgpr ].UD[ 0 ] ); + } + } +} + +// 32 bit move +void _eeMoveGPRtoM(u32 to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkX86reg(X86TYPE_GPR, fromgpr, MODE_READ)) >= 0 ) { + MOV32RtoM(to, mmreg); + } + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_M32(to, mmreg); + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ fromgpr ].UD[ 0 ] ); + MOV32RtoM(to, EAX ); + } + } +} + +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV64ItoRmOffset( to, g_cpuConstRegs[fromgpr].UD[0], 0 ); + else { + int mmreg; + + if( (mmreg = _checkX86reg(X86TYPE_GPR, fromgpr, MODE_READ)) >= 0 ) { + MOV64RtoRmOffset(to, mmreg, 0); + } + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_Rm(to, mmreg); + } + else { + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[ fromgpr ].UD[ 0 ] ); + MOV64RtoRmOffset(to, RAX, 0 ); + } + } +} + +void _callPushArg(u32 arg, uptr argmem, x86IntRegType X86ARG) +{ + if( IS_X86REG(arg) ) { + if( (arg&0xff) != X86ARG ) { + _freeX86reg(X86ARG); + MOV64RtoR(X86ARG, (arg&0xf)); + } + } + else if( IS_GPRREG(arg) ) { + _allocX86reg(X86ARG, X86TYPE_GPR, arg&0xff, MODE_READ); + } + else if( IS_CONSTREG(arg) ) { + _freeX86reg(X86ARG); + MOV32ItoR(X86ARG, argmem); + } + else if( IS_EECONSTREG(arg) ) { + _freeX86reg(X86ARG); + MOV32ItoR(X86ARG, g_cpuConstRegs[(arg>>16)&0x1f].UD[0]); + } + else if( IS_PSXCONSTREG(arg) ) { + _freeX86reg(X86ARG); + MOV32ItoR(X86ARG, g_psxConstRegs[(arg>>16)&0x1f]); + } + else if( IS_MEMORYREG(arg) ) { + _freeX86reg(X86ARG); + MOV64MtoR(X86ARG, argmem); + } + else if( IS_XMMREG(arg) ) { + _freeX86reg(X86ARG); + SSEX_MOVD_XMM_to_Rm(X86ARG, arg&0xf); + } + else { + assert((arg&0xfff0)==0); + _freeX86reg(X86ARG); + MOV64RtoR(X86ARG, (arg&0xf)); + } +} + +void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem) +{ + _callPushArg(arg1, arg1mem, X86ARG1); + CALLFunc((uptr)fn); +} + +void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem) +{ + _callPushArg(arg1, arg1mem, X86ARG1); + _callPushArg(arg2, arg2mem, X86ARG2); + CALLFunc((uptr)fn); +} + +void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem) +{ + _callPushArg(arg1, arg1mem, X86ARG1); + _callPushArg(arg2, arg2mem, X86ARG2); + _callPushArg(arg3, arg3mem, X86ARG3); + CALLFunc((uptr)fn); +} + +void _recPushReg(int mmreg) +{ + assert(0); +} + +void _signExtendSFtoM(u32 mem) +{ + assert(0); +} + +void _recMove128MtoM(u32 to, u32 from) +{ + MOV64MtoR(RAX, from); + MOV64RtoM(to, RAX); + MOV64MtoR(RAX, from+8); + MOV64RtoM(to+8, RAX); +} + +void _recMove128RmOffsettoM(u32 to, u32 offset) +{ + MOV64RmOffsettoR(RAX, RCX, offset); + MOV64RtoM(to, RAX); + MOV64RmOffsettoR(RAX, RCX, offset+8); + MOV64RtoM(to+8, RAX); +} + +void _recMove128MtoRmOffset(u32 offset, u32 from) +{ + MOV64MtoR(RAX, from); + MOV64RtoRmOffset(RCX, RAX, offset); + MOV64MtoR(RAX, from+8); + MOV64RtoRmOffset(RCX, RAX, offset+8); +} + +// 32 bit +void LogicalOp32RtoM(uptr to, x86IntRegType from, int op) +{ + switch(op) { + case 0: AND32RtoM(to, from); break; + case 1: OR32RtoM(to, from); break; + case 2: XOR32RtoM(to, from); break; + case 3: OR32RtoM(to, from); break; + } +} + +void LogicalOp32MtoR(x86IntRegType to, uptr from, int op) +{ + switch(op) { + case 0: AND32MtoR(to, from); break; + case 1: OR32MtoR(to, from); break; + case 2: XOR32MtoR(to, from); break; + case 3: OR32MtoR(to, from); break; + } +} + +void LogicalOp32ItoR(x86IntRegType to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoR(to, from); break; + case 1: OR32ItoR(to, from); break; + case 2: XOR32ItoR(to, from); break; + case 3: OR32ItoR(to, from); break; + } +} + +void LogicalOp32ItoM(uptr to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoM(to, from); break; + case 1: OR32ItoM(to, from); break; + case 2: XOR32ItoM(to, from); break; + case 3: OR32ItoM(to, from); break; + } +} + +// 64 bit +void LogicalOp64RtoR(x86IntRegType to, x86IntRegType from, int op) +{ + switch(op) { + case 0: AND64RtoR(to, from); break; + case 1: OR64RtoR(to, from); break; + case 2: XOR64RtoR(to, from); break; + case 3: OR64RtoR(to, from); break; + } +} + +void LogicalOp64RtoM(uptr to, x86IntRegType from, int op) +{ + switch(op) { + case 0: AND64RtoM(to, from); break; + case 1: OR64RtoM(to, from); break; + case 2: XOR64RtoM(to, from); break; + case 3: OR64RtoM(to, from); break; + } +} + +void LogicalOp64MtoR(x86IntRegType to, uptr from, int op) +{ + switch(op) { + case 0: AND64MtoR(to, from); break; + case 1: OR64MtoR(to, from); break; + case 2: XOR64MtoR(to, from); break; + case 3: OR64MtoR(to, from); break; + } +} + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900-64.c b/pcsx2/x86/ix86-64/iR5900-64.c new file mode 100644 index 0000000000..a7d2650a16 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900-64.c @@ -0,0 +1,2754 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// 64 bit recompiler - difference between 32bit is that mmx is gone +// and x86 regs are now cached (also fancier block linking) (zerofrog) + +// liveness analysis/constant propagation Apr06 (zerofrog@gmail.com) +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include + +#include "Common.h" +#include "Memory.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iR5900AritImm.h" +#include "iR5900Arit.h" +#include "iR5900MultDiv.h" +#include "iR5900Shift.h" +#include "iR5900Branch.h" +#include "iR5900Jump.h" +#include "iR5900LoadStore.h" +#include "iR5900Move.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCP0.h" +#include "iVUmicro.h" +#include "iVU0micro.h" +#include "iVU1micro.h" +#include "VU.h" +#include "VUmicro.h" + +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +u32 maxrecmem = 0; +uptr *recLUT=NULL; + +#define X86 +#define RECSTACK_SIZE 0x00010000 + +#define EE_NUMBLOCKS (1<<15) + +static char *recMem = NULL; // the recompiled blocks will be here +static char* recStack = NULL; // stack mem +static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here +static BASEBLOCK *recROM = NULL; // and here +static BASEBLOCK *recROM1 = NULL; // also here +static BASEBLOCKEX *recBlocks = NULL; +static char *recPtr = NULL, *recStackPtr = NULL; +static EEINST* s_pInstCache = NULL; +static u32 s_nInstCacheSize = 0; + +u32 g_EEFreezeRegs = 0; // if set, should freeze the regs + +static BASEBLOCK* s_pCurBlock = NULL; +static BASEBLOCKEX* s_pCurBlockEx = NULL; +static BASEBLOCK* s_pDispatchBlock = NULL; +static u32 s_nEndBlock = 0; // what pc the current block ends +static u32 s_nHasDelay = 0; + +static u32 s_nNextBlock = 0; // next free block in recBlocks + +extern void (*recBSC[64])(); +extern void (*recBSC_co[64])(); +extern void rpropBSC(EEINST* prev, EEINST* pinst); + +// save states for branches +static u16 s_savex86FpuState, s_saveiCWstate; +static GPR_reg64 s_ConstGPRreg; +static u32 s_saveConstGPRreg = 0, s_saveHasConstReg = 0, s_saveFlushedConstReg = 0, s_saveRegHasLive1 = 0, s_saveRegHasSignExt = 0; +static EEINST* s_psaveInstInfo = NULL; + +u32 s_nBlockCycles = 0; // cycles of current block recompiling +static u32 s_savenBlockCycles = 0; + +void recCOP2RecompileInst(); +int recCOP2AnalyzeBlock(u32 startpc, u32 endpc); +void recCOP2EndBlock(void); + +#ifdef _DEBUG +u32 dumplog = 0; +#else +#define dumplog 0 +#endif + +u32 pc; // recompiler pc +int branch; // set for branch + +//#ifdef PCSX2_DEVBUILD +LARGE_INTEGER lbase = {0}, lfinal = {0}; +static u32 s_startcount = 0; +//#endif + +void _cop2AnalyzeOp(EEINST* pinst, int dostalls); // reccop2.c +static void iBranchTest(u32 newpc, u32 cpuBranch); +void recRecompile( u32 startpc ); +void recCOP22( void ); + +BASEBLOCKEX* PC_GETBLOCKEX(BASEBLOCK* p) +{ +// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); +// if( pex >= recBlocks && pex < recBlocks+EE_NUMBLOCKS ) +// return pex; + + // otherwise, use the sorted list + return GetBaseBlockEx(p->startpc, 0); +} + +//////////////////////////////////////////////////// +void iDumpBlock( int startpc, char * ptr ) +{ + FILE *f; + char filename[ 256 ]; + u32 i, j; + EEINST* pcur; + extern char *disRNameGPR[]; + u8 used[34]; + u8 fpuused[33]; + int numused, count, fpunumused; + char command[256]; + + SysPrintf( "dump %x:%x, %x\n", startpc, pc, cpuRegs.cycle ); +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf( filename, "dumps\\dump%.8X.txt", startpc); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/dump%.8X.txt", startpc); +#endif + + fflush( stdout ); + + f = fopen( filename, "w" ); + + for ( i = startpc; i < s_nEndBlock; i += 4 ) { + fprintf( f, "%s\n", disR5900Fasm( PSMu32( i ), i ) ); + } + + // write the instruction info + + fprintf(f, "\n\nlive0 - %x, live1 - %x, live2 - %x, lastuse - %x\nxmm - %x, used - %x\n", + EEINST_LIVE0, EEINST_LIVE1, EEINST_LIVE2, EEINST_LASTUSE, EEINST_XMM, EEINST_USED); + + memset(used, 0, sizeof(used)); + numused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( s_pInstCache->regs[i] & EEINST_USED ) { + used[i] = 1; + numused++; + } + } + + memset(fpuused, 0, sizeof(fpuused)); + fpunumused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( s_pInstCache->fpuregs[i] & EEINST_USED ) { + fpuused[i] = 1; + fpunumused++; + } + } + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%2d ", i); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%2d ", i); + } + fprintf(f, "\n"); + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%s ", i<32?"FR":"FA"); + } + fprintf(f, "\n"); + + pcur = s_pInstCache+1; + for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { + fprintf(f, "%2d: %2.2x ", i+1, pcur->info); + + count = 1; + for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { + if( used[j] ) { + fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&countfpuregs); j++) { + if( fpuused[j] ) { + fprintf(f, "%2.2x%s", pcur->fpuregs[j], ((count%8)&&count tempdump", filename ); + system( command ); + sprintf(command, "mv tempdump %s", filename); + system(command); + f = fopen( filename, "a+" ); +#endif +} + +u8 _eeLoadWritesRs(u32 tempcode) +{ + switch(tempcode>>26) { + case 26: // ldl + case 27: // ldr + case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: + case 55: // LD + case 30: // lq + return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt + } + return 0; +} + +u8 _eeIsLoadStoreCoIssue(u32 firstcode, u32 secondcode) +{ + switch(firstcode>>26) { + case 34: // lwl + return (secondcode>>26)==38; + case 38: // lwr + return (secondcode>>26)==34; + case 42: // swl + return (secondcode>>26)==46; + case 46: // swr + return (secondcode>>26)==42; + case 26: // ldl + return (secondcode>>26)==27; + case 27: // ldr + return (secondcode>>26)==26; + case 44: // sdl + return (secondcode>>26)==45; + case 45: // sdr + return (secondcode>>26)==44; + + case 32: case 33: case 35: case 36: case 37: case 39: + case 55: // LD + + // stores + case 40: case 41: case 43: + case 63: // sd + return (secondcode>>26)==(firstcode>>26); + + case 30: // lq + case 31: // sq + case 49: // lwc1 + case 57: // swc1 + case 54: // lqc2 + case 62: // sqc2 + return (secondcode>>26)==(firstcode>>26)&&cpucaps.hasStreamingSIMDExtensions; + } + return 0; +} + +u8 _eeIsLoadStoreCoX(u32 tempcode) +{ + switch( tempcode>>26 ) { + case 30: case 31: case 49: case 57: case 55: case 63: + return 1; + } + return 0; +} + +void _eeFlushAllUnused() +{ + int i; + for(i = 0; i < 34; ++i) { + if( pc < s_nEndBlock ) { + if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) + continue; + } + else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) + continue; + + if( i < 32 && GPR_IS_CONST1(i) ) _flushConstReg(i); + else { + _deleteGPRtoXMMreg(i, 1); + } + } + + //TODO when used info is done for FPU and VU0 + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse && xmmregs[i].type != XMMTYPE_GPRREG ) + _freeXMMreg(i); + } + for(i = 0; i < X86REGS; ++i) { + if( x86regs[i].inuse && x86regs[i].type != X86TYPE_GPR ) + _freeX86reg(i); + } +} + +u32* _eeGetConstReg(int reg) +{ + assert( GPR_IS_CONST1( reg ) ); + + if( g_cpuFlushedConstReg & (1<regs[xmmregs[i].reg]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, xmmregs[i].reg) ) { + _freeXMMreg(i); + xmmregs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushX86unused() +{ + int i; + for (i=0; iregs[x86regs[i].reg]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, x86regs[i].reg) ) { + _freeX86reg(i); + x86regs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushUnusedConstReg() +{ + int i; + for(i = 1; i < 32; ++i) { + if( (g_cpuHasConstReg & (1<>31) == g_cpuConstRegs[i].SL[1] ) + MOV64I32toM((uptr)&cpuRegs.GPR.r[i].UD[0], g_cpuConstRegs[i].UL[0]); + else { + MOV32ItoM((uptr)&cpuRegs.GPR.r[i].UL[0], g_cpuConstRegs[i].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[i].UL[1], g_cpuConstRegs[i].UL[1]); + } + + g_cpuFlushedConstReg |= 1<>31) == g_cpuConstRegs[reg].SL[1] ) + MOV64I32toM((uptr)&cpuRegs.GPR.r[reg].UD[0], g_cpuConstRegs[reg].UL[0]); + else { + MOV32ItoM((uptr)&cpuRegs.GPR.r[reg].UL[0], g_cpuConstRegs[reg].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[reg].UL[1], g_cpuConstRegs[reg].UL[1]); + } + + g_cpuFlushedConstReg |= (1<>31) == g_cpuConstRegs[i].SL[1] ) + MOV64I32toM((uptr)&cpuRegs.GPR.r[i].UD[0], g_cpuConstRegs[i].UL[0]); + else { + MOV32ItoM((uptr)&cpuRegs.GPR.r[i].UL[0], g_cpuConstRegs[i].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[i].UL[1], g_cpuConstRegs[i].UL[1]); + } + g_cpuFlushedConstReg |= 1<regs[reg]&EEINST_LASTUSE) ) { + if( usex86 ) return _allocX86reg(-1, X86TYPE_GPR, reg, mode); + return _allocGPRtoXMMreg(-1, reg, mode); + } + + return -1; +} + +#define PROCESS_EE_SETMODES(mmreg) 0//((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET(mmreg) 0//((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// ignores XMMINFO_READS, XMMINFO_READT, and XMMINFO_READD_LO from xmminfo +// core of reg caching +void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo) +{ + int mmreg1, mmreg2, mmreg3, mmtemp, moded; + + if ( ! _Rd_ && (xmminfo&XMMINFO_WRITED) ) return; + + if( xmminfo&XMMINFO_WRITED) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( xmminfo & XMMINFO_WRITED ) { + _deleteGPRtoXMMreg(_Rd_, 2); + } + if( xmminfo&XMMINFO_WRITED ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + moded = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededGPRtoXMMreg(XMMGPR_LO); + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededGPRtoXMMreg(XMMGPR_HI); + _addNeededGPRtoXMMreg(_Rs_); + _addNeededGPRtoXMMreg(_Rt_); + + if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { + int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; + int vreg = creg == _Rs_ ? _Rt_ : _Rs_; + +// if(g_pCurInstInfo->regs[vreg]&EEINST_XMM) { +// mmreg1 = _allocGPRtoXMMreg(-1, vreg, MODE_READ); +// _addNeededGPRtoXMMreg(vreg); +// } + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, vreg, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM; + + if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); + else info |= PROCESS_EE_SETMODES(mmreg1); + + if( xmminfo & XMMINFO_WRITED ) { + + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(vreg)) ) { + _freeXMMreg(mmreg1); + if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; + else info &= ~PROCESS_EE_MODEWRITES; + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else if( mmreg3 < 0 ) mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); + else consttcode(info|PROCESS_EE_SET_S(mmreg1)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + else { + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 || mmreg2 >= 0 ) { + int info = PROCESS_EE_XMM; + + // do it all in xmm + if( mmreg1 < 0 ) mmreg1 = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + if( mmreg2 < 0 ) mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + + info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); + + if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, moded); + + if( mmreg3 < 0 ) { + if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(mmreg2); + info &= ~PROCESS_EE_MODEWRITET; + xmmregs[mmreg2].inuse = 1; + xmmregs[mmreg2].reg = _Rd_; + xmmregs[mmreg2].mode = moded; + mmreg3 = mmreg2; + } + else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + } + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + if( xmminfo&XMMINFO_WRITED ) + _deleteGPRtoXMMreg(_Rd_, (xmminfo&XMMINFO_READD)?0:2); + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rt_ ) return; + + CHECK_SAVE_REG(_Rt_); + _eeProcessHasLive(_Rt_, 0); + EEINST_RESETSIGNEXT(_Rt_); + + if( GPR_IS_CONST1(_Rs_) ) { + _deleteGPRtoXMMreg(_Rt_, 2); + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODES(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rt_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rt_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rt_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rd_ ) return; + + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + + if( GPR_IS_CONST1(_Rt_) ) { + _deleteGPRtoXMMreg(_Rd_, 2); + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODET(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITET; + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rd_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rd_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt op rs +void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode) +{ + assert(0); + // for now, don't support xmm + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + multicode(0); +} + +// Simple Code Templates // + +// rd = rs op rt +void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rt_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rt_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 0); + + if( GPR_IS_CONST1(_Rs_) ) { + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + + if( GPR_IS_CONST1(_Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rd = rt MULT rs (SPECIAL) +void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT) +{ + assert(0); + // for now, don't support xmm + if( MULT ) { + CHECK_SAVE_REG(_Rd_); + _deleteGPRtoXMMreg(_Rd_, 0); + } + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( MULT && _Rd_ ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTS); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + multicode(0); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); +} + +// EE XMM allocation code +int eeRecompileCodeXMM(int xmminfo) +{ + int info = PROCESS_EE_XMM; + + // save state + if( xmminfo & XMMINFO_WRITED ) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + // flush consts + if( xmminfo & XMMINFO_READT ) { + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + } + if( xmminfo & XMMINFO_READS) { + if( GPR_IS_CONST1( _Rs_ ) && !(g_cpuFlushedConstReg&(1<<_Rs_)) ) { + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rs_); + } + } + + if( xmminfo & XMMINFO_WRITED ) { + GPR_DEL_CONST(_Rd_); + } + + // add needed + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + _addNeededGPRtoXMMreg(XMMGPR_LO); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + _addNeededGPRtoXMMreg(XMMGPR_HI); + } + if( xmminfo & XMMINFO_READS) _addNeededGPRtoXMMreg(_Rs_); + if( xmminfo & XMMINFO_READT) _addNeededGPRtoXMMreg(_Rt_); + if( xmminfo & XMMINFO_WRITED ) _addNeededGPRtoXMMreg(_Rd_); + + // allocate + if( xmminfo & XMMINFO_READS) { + int reg = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + info |= PROCESS_EE_SET_S(reg)|PROCESS_EE_SETMODES(reg); + } + if( xmminfo & XMMINFO_READT) { + int reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + info |= PROCESS_EE_SET_T(reg)|PROCESS_EE_SETMODET(reg); + } + + if( xmminfo & XMMINFO_WRITED ) { + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?((xmminfo&XMMINFO_READD_LO)?(MODE_READ|MODE_READHALF):MODE_READ):0); + + int regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, readd); + + if( regd < 0 ) { + if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READT) && (_Rt_ == 0 || (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(EEREC_T); + _deleteX86reg(X86TYPE_GPR, _Rd_, 2); + xmmregs[EEREC_T].inuse = 1; + xmmregs[EEREC_T].reg = _Rd_; + xmmregs[EEREC_T].mode = readd; + regd = EEREC_T; + } + else if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READS) && (_Rs_ == 0 || (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(EEREC_S); + _deleteX86reg(X86TYPE_GPR, _Rd_, 2); + xmmregs[EEREC_S].inuse = 1; + xmmregs[EEREC_S].reg = _Rd_; + xmmregs[EEREC_S].mode = readd; + regd = EEREC_S; + } + else regd = _allocGPRtoXMMreg(-1, _Rd_, readd); + } + + info |= PROCESS_EE_SET_D(regd); + } + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + info |= PROCESS_EE_SET_LO(_allocGPRtoXMMreg(-1, XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0))); + info |= PROCESS_EE_LO; + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + info |= PROCESS_EE_SET_HI(_allocGPRtoXMMreg(-1, XMMGPR_HI, ((xmminfo&XMMINFO_READHI)?MODE_READ:0)|((xmminfo&XMMINFO_WRITEHI)?MODE_WRITE:0))); + info |= PROCESS_EE_HI; + } + return info; +} + +// EE COP1(FPU) XMM allocation code +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define PROCESS_EE_SETMODES_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// rd = rs op rt +void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR_INFO fpucode, int xmminfo) +{ + int mmregs=-1, mmregt=-1, mmregd=-1, mmregacc=-1; + if( fpucode == NULL || (EE_FPU_REGCACHING && cpucaps.hasStreamingSIMDExtensions) ) { + int info = PROCESS_EE_XMM; + + if( xmminfo & XMMINFO_READS ) _addNeededFPtoXMMreg(_Fs_); + if( xmminfo & XMMINFO_READT ) _addNeededFPtoXMMreg(_Ft_); + if( xmminfo & (XMMINFO_WRITED|XMMINFO_READD) ) _addNeededFPtoXMMreg(_Fd_); + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) _addNeededFPACCtoXMMreg(); + + if( xmminfo & XMMINFO_READT ) { + if( g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE ) mmregt = _checkXMMreg(XMMTYPE_FPREG, _Ft_, MODE_READ); + else mmregt = _allocFPtoXMMreg(-1, _Ft_, MODE_READ); + } + + if( xmminfo & XMMINFO_READS ) { + if( (!(xmminfo&XMMINFO_READT)||mmregt>=0) && (g_pCurInstInfo->fpuregs[_Fs_] & EEINST_LASTUSE) ) + mmregs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + else mmregs = _allocFPtoXMMreg(-1, _Fs_, MODE_READ); + } + + if( mmregs >= 0 ) info |= PROCESS_EE_SETMODES_XMM(mmregs); + if( mmregt >= 0 ) info |= PROCESS_EE_SETMODET_XMM(mmregt); + + if( xmminfo & XMMINFO_READD ) { + assert( xmminfo & XMMINFO_WRITED ); + mmregd = _allocFPtoXMMreg(-1, _Fd_, MODE_READ); + } + + if( xmminfo & XMMINFO_READACC ) { + if( !(xmminfo&XMMINFO_WRITEACC) && (g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE) ) + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, MODE_READ); + else mmregacc = _allocFPACCtoXMMreg(-1, MODE_READ); + } + + if( xmminfo & XMMINFO_WRITEACC ) { + + // check for last used, if so don't alloc a new XMM reg + int readacc = MODE_WRITE|((xmminfo&XMMINFO_READACC)?MODE_READ:0); + + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, readacc); + + if( mmregacc < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = 0; + xmmregs[mmregt].mode = readacc; + xmmregs[mmregt].type = XMMTYPE_FPACC; + mmregacc = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = 0; + xmmregs[mmregs].mode = readacc; + xmmregs[mmregs].type = XMMTYPE_FPACC; + mmregacc = mmregs; + } + else mmregacc = _allocFPACCtoXMMreg(-1, readacc); + } + + xmmregs[mmregacc].mode |= MODE_WRITE; + } + else if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + if( xmminfo&XMMINFO_READD ) mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + else mmregd = _checkXMMreg(XMMTYPE_FPREG, _Fd_, readd); + + if( mmregd < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = _Fd_; + xmmregs[mmregt].mode = readd; + mmregd = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = _Fd_; + xmmregs[mmregs].mode = readd; + mmregd = mmregs; + } + else if( (xmminfo&XMMINFO_READACC) && mmregacc >= 0 && (FPUINST_LASTUSE(XMMFPU_ACC) || !FPUINST_ISLIVE(XMMFPU_ACC)) ) { + if( FPUINST_ISLIVE(XMMFPU_ACC) ) + _freeXMMreg(mmregacc); + xmmregs[mmregacc].inuse = 1; + xmmregs[mmregacc].reg = _Fd_; + xmmregs[mmregacc].mode = readd; + xmmregs[mmregacc].type = XMMTYPE_FPREG; + mmregd = mmregacc; + } + else mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + } + } + + assert( mmregs >= 0 || mmregt >= 0 || mmregd >= 0 || mmregacc >= 0 ); + + if( xmminfo & XMMINFO_WRITED ) { + assert( mmregd >= 0 ); + info |= PROCESS_EE_SET_D(mmregd); + } + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) { + if( mmregacc >= 0 ) info |= PROCESS_EE_SET_ACC(mmregacc)|PROCESS_EE_ACC; + else assert( !(xmminfo&XMMINFO_WRITEACC)); + } + + if( xmminfo & XMMINFO_READS ) { + if( mmregs >= 0 ) info |= PROCESS_EE_SET_S(mmregs)|PROCESS_EE_S; + } + if( xmminfo & XMMINFO_READT ) { + if( mmregt >= 0 ) info |= PROCESS_EE_SET_T(mmregt)|PROCESS_EE_T; + } + + // at least one must be in xmm + if( (xmminfo & (XMMINFO_READS|XMMINFO_READT)) == (XMMINFO_READS|XMMINFO_READT) ) { + assert( mmregs >= 0 || mmregt >= 0 ); + } + + xmmcode(info); + _clearNeededXMMregs(); + return; + } + + if( xmminfo & XMMINFO_READS ) _deleteFPtoXMMreg(_Fs_, 0); + if( xmminfo & XMMINFO_READT ) _deleteFPtoXMMreg(_Ft_, 0); + if( xmminfo & (XMMINFO_READD|XMMINFO_WRITED) ) _deleteFPtoXMMreg(_Fd_, 0); + if( xmminfo & (XMMINFO_READACC|XMMINFO_WRITEACC) ) _deleteFPtoXMMreg(XMMFPU_ACC, 0); + fpucode(0); +} + +#undef _Ft_ +#undef _Fs_ +#undef _Fd_ + +//////////////////////////////////////////////////// +extern u8 g_MACFlagTransform[256]; // for vus + +u32 g_sseMXCSR = 0x9f80; // disable all exception, round to 0, flush to 0 +u32 g_sseVUMXCSR = 0xff80; + +#if defined(_MSC_VER) +#include +#endif + +void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR) +{ + // SSE STATE // + // WARNING: do not touch unless you know what you are doing + + if( cpucaps.hasStreamingSIMDExtensions ) { + g_sseMXCSR = sseMXCSR; + g_sseVUMXCSR = sseVUMXCSR; + // do NOT set Denormals-Are-Zero flag (charlie and chocfac messes up) + //g_sseMXCSR = 0x9f80; // changing the rounding mode to 0x2000 (near) kills grandia III! + // changing the rounding mode to 0x0000 or 0x4000 totally kills gitaroo + // so... grandia III wins (you can change individual games with the 'roundmode' patch command) + +#ifdef _MSC_VER + _mm_setcsr(g_sseMXCSR); // set the new sse control +#else + __asm__("ldmxcsr %0" : : "m"(g_sseMXCSR) ); +#endif + //g_sseVUMXCSR = g_sseMXCSR|0x6000; + } +} + +extern BOOL install_my_handler(); + +#define REC_CACHEMEM 0x01000000 + +int recInit( void ) +{ + int i; + u32 startaddr; + const u8 macarr[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; + + startaddr = 0x0d000000; + while(!(startaddr & 0xf0000000)) { + recMem = (char*)SysMmap(startaddr, REC_CACHEMEM); + if( (uptr)recMem & 0xf0000000 ) { + SysMunmap((uptr)recMem, REC_CACHEMEM); recMem = NULL; + startaddr += 0x00100000; + continue; + } + else break; + } + + if( (uptr)recMem & 0xf0000000 ) { + SysPrintf("R5900 bad rec memory allocation\n"); + return 1; + } + + recLUT = (uptr*) _aligned_malloc( 0x010000 * sizeof(uptr), 16 ); + memset( recLUT, 0, 0x010000 * sizeof(uptr) ); + + // 32 alignment necessary + recRAM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x02000000 , 4*sizeof(BASEBLOCK)); + recROM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x00400000 , 4*sizeof(BASEBLOCK)); + recROM1= (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*0x00040000 , 4*sizeof(BASEBLOCK)); + recBlocks = (BASEBLOCKEX*) _aligned_malloc( sizeof(BASEBLOCKEX)*EE_NUMBLOCKS, 16); + recStack = (char*)malloc( RECSTACK_SIZE ); + + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + + if ( recBlocks == NULL || recRAM == NULL || recROM == NULL || recROM1 == NULL || recMem == NULL || recLUT == NULL ) { + SysMessage( _( "Error allocating memory" ) ); + return -1; + } + + for ( i = 0x0000; i < 0x0200; i++ ) + { + recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ]; + } + + for ( i = 0x0000; i < 0x0040; i++ ) + { + recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ]; + } + + for ( i = 0x0000; i < 0x0004; i++ ) + { + recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ]; + } + + memcpy( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) ); + memcpy( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) ); + + memset(recMem, 0xcd, REC_CACHEMEM); + memset(recStack, 0, RECSTACK_SIZE); + + // SSE3 detection, manually create the code + x86SetPtr(recMem); + SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0); + RET(); + cpudetectSSE3(recMem); + + SysPrintf( "x86Init: \n" ); + SysPrintf( "\tCPU vender name = %s\n", cpuinfo.x86ID ); + SysPrintf( "\tFamilyID = %x\n", cpuinfo.x86StepID ); + SysPrintf( "\tx86Family = %s\n", cpuinfo.x86Fam ); + SysPrintf( "\tCPU speed = %d.%03d Ghz\n", cpuinfo.cpuspeed / 1000, cpuinfo.cpuspeed%1000); + SysPrintf( "\tx86PType = %s\n", cpuinfo.x86Type ); + SysPrintf( "\tx86Flags = %8.8x\n", cpuinfo.x86Flags ); + SysPrintf( "\tx86EFlags = %8.8x\n", cpuinfo.x86EFlags ); + SysPrintf( "Features: \n" ); + SysPrintf( "\t%sDetected MMX\n", cpucaps.hasMultimediaExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE\n", cpucaps.hasStreamingSIMDExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE2\n", cpucaps.hasStreamingSIMD2Extensions ? "" : "Not " ); + SysPrintf( "\t%sDetected SSE3\n", cpucaps.hasStreamingSIMD3Extensions ? "" : "Not " ); + + if ( cpuinfo.x86ID[0] == 'A' ) //AMD cpu + { + SysPrintf( " Extented AMD Features: \n" ); + SysPrintf( "\t%sDetected MMX2\n", cpucaps.hasMultimediaExtensionsExt ? "" : "Not " ); + SysPrintf( "\t%sDetected 3DNOW\n", cpucaps.has3DNOWInstructionExtensions ? "" : "Not " ); + SysPrintf( "\t%sDetected 3DNOW2\n", cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not " ); + } + if ( !( cpucaps.hasMultimediaExtensions ) ) + { + SysMessage( _( "Processor doesn't supports MMX, can't run recompiler without that" ) ); + return -1; + } + + SuperVUInit(-1); + + for(i = 0; i < 256; ++i) { + g_MACFlagTransform[i] = macarr[i>>4]|(macarr[i&15]<<4); + } + + SetCPUState(g_sseMXCSR, g_sseVUMXCSR); + + return 0; +} + +//////////////////////////////////////////////////// +void recReset( void ) { +#ifdef PCSX2_DEVBUILD + SysPrintf("EE Recompiler data reset\n"); +#endif + + s_nNextBlock = 0; + maxrecmem = 0; + memset( recRAM, 0, sizeof(BASEBLOCK)/4*0x02000000 ); + memset( recROM, 0, sizeof(BASEBLOCK)/4*0x00400000 ); + memset( recROM1, 0, sizeof(BASEBLOCK)/4*0x00040000 ); + memset( recBlocks, 0, sizeof(BASEBLOCKEX)*EE_NUMBLOCKS ); + if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + ResetBaseBlockEx(0); + +#ifdef _DEBUG + // don't clear since save states won't work + //memset(recMem, 0xcd, REC_CACHEMEM); +#endif + + recPtr = recMem; + recStackPtr = recStack; + iCWstate = 0; + + branch = 0; +} + +void recShutdown( void ) +{ + if ( recMem == NULL ) { + return; + } + + _aligned_free( recLUT ); + SysMunmap((uptr)recMem, REC_CACHEMEM); recMem = NULL; + _aligned_free( recRAM ); recRAM = NULL; + _aligned_free( recROM ); recROM = NULL; + _aligned_free( recROM1 ); recROM1 = NULL; + _aligned_free( recBlocks ); recBlocks = NULL; + free( s_pInstCache ); s_pInstCache = NULL; s_nInstCacheSize = 0; + + SuperVUDestroy(-1); + + x86Shutdown( ); +} + +void recEnableVU0micro(int enable) { +} + +void recEnableVU1micro(int enable) { +} + +void R5900Execute(); + +void recStep( void ) { +} + +void recExecute( void ) { + //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);//ABOVE_NORMAL_PRIORITY_CLASS); + //SetThreadAffinityMask(GetCurrentThread(), 0); + if( Config.Options & PCSX2_EEREC ) Config.Options |= PCSX2_COP2REC; + + for (;;) + R5900Execute(); +} + +void recExecuteBlock( void ) { + R5900Execute(); +} + +//////////////////////////////////////////////////// +extern u32 g_nextBranchCycle; + +u32 g_lastpc = 0; +u32 g_EEDispatchTemp; +u32 s_pCurBlock_ltime; + +extern void Dispatcher(); +extern void DispatcherClear(); +extern void DispatcherReg(); +extern void _StartPerfCounter(); +extern void _StopPerfCounter(); + +//////////////////////////////////////////////////// +void recClear64(BASEBLOCK* p) +{ + int left = 4 - ((uptr)p % 16)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); +} + +void recClear128(BASEBLOCK* p) +{ + int left = 4 - ((uptr)p % 32)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); + if( left > 2 && *(u32*)(p+2) ) recClearMem(p+2); + if( left > 3 && *(u32*)(p+3) ) recClearMem(p+3); +} + +void recClear( u32 Addr, u32 Size ) +{ + u32 i; + for(i = 0; i < Size; ++i, Addr+=4) { + REC_CLEARM(Addr); + } +} + +#define EE_MIN_BLOCK_BYTES 16 + +void recClearMem(BASEBLOCK* p) +{ + BASEBLOCKEX* pexblock; + BASEBLOCK* pstart; + int lastdelay; + + assert( p != NULL ); + + if( p->uType & BLOCKTYPE_DELAYSLOT ) { + recClearMem(p-1); + if( p->pFnptr == 0 ) + return; + } + + assert( p->pFnptr != 0 ); + assert( p->startpc ); + + x86Ptr = (s8*)p->pFnptr; + + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, p->startpc); + assert( (uptr)x86Ptr <= 0xffffffff ); + MOV32ItoR(R15, (uptr)x86Ptr); // will be replaced by JMP32 + JMP32((uptr)DispatcherClear - ( (uptr)x86Ptr + 5 )); + assert( x86Ptr == (s8*)p->pFnptr + EE_MIN_BLOCK_BYTES ); + + pstart = PC_GETBLOCK(p->startpc); + pexblock = PC_GETBLOCKEX(pstart); + assert( pexblock->startpc == pstart->startpc ); + +// if( pexblock->pOldFnptr ) { +// // have to mod oldfnptr too +// x86Ptr = pexblock->pOldFnptr; +// +// MOV32ItoR(EDX, p->startpc); +// JMP32((u32)DispatcherClear - ( (u32)x86Ptr + 5 )); +// } +// else +// pexblock->pOldFnptr = (u8*)p->pFnptr; + + // don't delete if last is delay + lastdelay = pexblock->size; + if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { + assert( pstart[pexblock->size-1].pFnptr != pstart->pFnptr ); + if( pstart[pexblock->size-1].pFnptr != 0 ) { + pstart[pexblock->size-1].uType = 0; + --lastdelay; + } + } + + memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + + RemoveBaseBlockEx(pexblock, 0); + pexblock->size = 0; + pexblock->startpc = 0; +} + +// check for end of bios +void CheckForBIOSEnd() +{ + MOV32MtoR(EAX, (uptr)&cpuRegs.pc); + + CMP32ItoR(EAX, 0x00200008); + j8Ptr[0] = JE8(0); + + CMP32ItoR(EAX, 0x00100008); + j8Ptr[1] = JE8(0); + + // return + j8Ptr[2] = JMP8(0); + + x86SetJ8( j8Ptr[0] ); + x86SetJ8( j8Ptr[1] ); + + // bios end + if( REC_INC_STACK ) + ADD64ItoR(RSP, REC_INC_STACK); + RET2(); + + x86SetJ8( j8Ptr[2] ); +} + +static int *s_pCode; + +void SetBranchReg( u32 reg ) +{ + branch = 1; + + if( reg != 0xffffffff ) { +// if( GPR_IS_CONST1(reg) ) +// MOV32ItoM( (uptr)&cpuRegs.pc, g_cpuConstRegs[reg].UL[0] ); +// else { +// int mmreg; +// +// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ)) >= 0 ) { +// SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.pc, mmreg); +// } +// else { +// MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ reg ].UL[ 0 ] ); +// MOV32RtoM((uptr)&cpuRegs.pc, EAX); +// } +// } + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, reg); + + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((uptr)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (uptr)&g_recWriteback); + MOV32RtoM((uptr)&cpuRegs.pc, EAX); + } + } + +// CMP32ItoM((uptr)&cpuRegs.pc, 0); +// j8Ptr[5] = JNE8(0); +// CALLFunc((uptr)tempfn); +// x86SetJ8( j8Ptr[5] ); + + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(0xffffffff, 1); + if( bExecBIOS ) CheckForBIOSEnd(); + + JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); +} + +void SetBranchImm( u32 imm ) +{ + u32* ptr; + branch = 1; + + assert( imm ); + + // end the current block + MOV32ItoM( (uptr)&cpuRegs.pc, imm ); + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(imm, imm <= pc); + if( bExecBIOS ) CheckForBIOSEnd(); + + MOV32ItoR(EDX, 0); + ptr = (u32*)(x86Ptr-4); + *ptr = (u32)JMP32((uptr)Dispatcher - ( (uptr)x86Ptr + 5 )); +} + +void SaveBranchState() +{ + s_savex86FpuState = x86FpuState; + s_saveiCWstate = iCWstate; + s_savenBlockCycles = s_nBlockCycles; + s_saveConstGPRreg = 0xffffffff; // indicate searching + s_saveHasConstReg = g_cpuHasConstReg; + s_saveFlushedConstReg = g_cpuFlushedConstReg; + s_psaveInstInfo = g_pCurInstInfo; + s_saveRegHasLive1 = g_cpuRegHasLive1; + s_saveRegHasSignExt = g_cpuRegHasSignExt; + + // save all mmx regs + memcpy(s_saveXMMregs, xmmregs, sizeof(xmmregs)); + memcpy(s_saveX86regs, x86regs, sizeof(x86regs)); +} + +void LoadBranchState() +{ + x86FpuState = s_savex86FpuState; + iCWstate = s_saveiCWstate; + s_nBlockCycles = s_savenBlockCycles; + + if( s_saveConstGPRreg != 0xffffffff ) { + assert( s_saveConstGPRreg > 0 ); + + // make sure right GPR was saved + assert( g_cpuHasConstReg == s_saveHasConstReg || (g_cpuHasConstReg ^ s_saveHasConstReg) == (1<ltime); + CALLFunc((uptr)_StopPerfCounter); + } +#endif +} + +#define USE_FAST_BRANCHES 0 + +//void testfpu() +//{ +// int i; +// for(i = 0; i < 32; ++i ) { +// if( fpuRegs.fpr[i].UL== 0x7f800000 || fpuRegs.fpr[i].UL == 0xffc00000) { +// SysPrintf("bad fpu: %x %x %x\n", i, cpuRegs.cycle, g_lastpc); +// } +// +// if( VU0.VF[i].UL[0] == 0xffc00000 || //(VU0.VF[i].UL[1]&0xffc00000) == 0xffc00000 || +// VU0.VF[i].UL[0] == 0x7f800000) { +// SysPrintf("bad vu0: %x %x %x\n", i, cpuRegs.cycle, g_lastpc); +// } +// } +//} + +//static void cleanup() +//{ +// assert( !g_globalXMMSaved ); +//} + +static void iBranchTest(u32 newpc, u32 cpuBranch) +{ +#ifdef PCSX2_DEVBUILD + if( s_startcount ) { + StopPerfCounter(); + ADD32ItoM( (uptr)&s_pCurBlockEx->visited, 1 ); + } +#endif + +#ifdef _DEBUG + //CALLFunc((uptr)testfpu); +#endif + + if( !USE_FAST_BRANCHES || cpuBranch ) { + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + ADD32ItoR(ECX, s_nBlockCycles*9/8); // NOTE: mulitply cycles here, 6/5 ratio stops pal ffx from randomly crashing, but crashes jakI + MOV32RtoM((uptr)&cpuRegs.cycle, ECX); // update cycles + } + else { + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles*9/8); + return; + } + + SUB32MtoR(ECX, (uptr)&g_nextBranchCycle); + + // check if should branch + j8Ptr[0] = JS8( 0 ); + + // has to be in the middle of Save/LoadBranchState + CALLFunc( (int)cpuBranchTest ); + + if( newpc != 0xffffffff ) { + CMP32ItoM((uptr)&cpuRegs.pc, newpc); + JNE32((uptr)DispatcherReg - ( (uptr)x86Ptr + 6 )); + } + + x86SetJ8( j8Ptr[0] ); +} + + +//////////////////////////////////////////////////// +#ifndef CP2_RECOMPILE + +REC_SYS(COP2); + +#else + +void recCOP2( void ) +{ +#ifdef CPU_LOG + CPU_LOG( "Recompiling COP2:%s\n", disR5900Fasm( cpuRegs.code, cpuRegs.pc ) ); +#endif + + if ( !cpucaps.hasStreamingSIMDExtensions ) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + g_cpuHasConstReg = 1; // reset all since COP2 can change regs + CALLFunc( (u32)COP2 ); + + CMP32ItoM((uptr)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles); + JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + } + else + { + recCOP22( ); + } +} + +#endif + +//////////////////////////////////////////////////// +void recSYSCALL( void ) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_NODESTROY); + CALLFunc( (u32)SYSCALL ); + + CMP32ItoM((uptr)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles); + JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +//////////////////////////////////////////////////// +void recBREAK( void ) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BREAK ); + + CMP32ItoM((uptr)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles); + + if( REC_INC_STACK ) + ADD64ItoR(RSP, REC_INC_STACK); + RET(); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +//////////////////////////////////////////////////// +//static void recCACHE( void ) { +// MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); +// MOV32ItoM( (uptr)&cpuRegs.pc, pc ); +// iFlushCall(FLUSH_EVERYTHING); +// CALLFunc( (u32)CACHE ); +// //branch = 2; +// +// CMP32ItoM((uptr)&cpuRegs.pc, pc); +// j8Ptr[0] = JE8(0); +// RET(); +// x86SetJ8(j8Ptr[0]); +//} + + +void recPREF( void ) +{ +} + +void recSYNC( void ) +{ +} + +void recMFSA( void ) +{ + int mmreg; + if (!_Rd_) return; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE)) >= 0 ) { + SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.sa); + } + else { + MOV64MtoR(RAX, (uptr)&cpuRegs.sa); + _deleteEEreg(_Rd_, 0); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } + //else { + // mmreg = _allocX86reg(-1, X86TYPE_GPR, _Rd_, MODE_WRITE); + // MOV64MtoR(mmreg, (uptr)&cpuRegs.sa); + //} +} + +void recMTSA( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] ); + } + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { + SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.sa, mmreg); + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } + } +} + +void recMTSAB( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0xF); + XOR32ItoR(EAX, _Imm_&0xf); + SHL32ItoR(EAX, 3); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } +} + +void recMTSAH( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0x7); + XOR32RtoR(EAX, _Imm_&0x7); + SHL32ItoR(EAX, 4); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } +} + +#if !defined(_MSC_VER) +static void checkcodefn() +{ + int pctemp; + + __asm__("movl %%eax, %0" : "=m"(pctemp) ); + + SysPrintf("code changed! %x\n", pctemp); + assert(0); +} +#endif + +void checkpchanged(u32 startpc) +{ + assert(0); +} + +//#ifdef _DEBUG +//#define CHECK_XMMCHANGED() CALLFunc((uptr)checkxmmchanged); +//#else +//#define CHECK_XMMCHANGED() +//#endif +// +//static void checkxmmchanged() +//{ +// assert( !g_globalXMMSaved ); +//} + +u32 recompileCodeSafe(u32 temppc) +{ + BASEBLOCK* pblock = PC_GETBLOCK(temppc); + + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pc == pblock->startpc ) + return 0; + } + + return 1; +} + +void recompileNextInstruction(int delayslot) +{ + static u8 s_bFlushReg = 1; + int i, count; + + BASEBLOCK* pblock = PC_GETBLOCK(pc); + + // need *ppblock != s_pCurBlock because of branches + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( !delayslot && pc == pblock->startpc ) { + // code already in place, so jump to it and exit recomp + assert( PC_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&cpuRegs.pc, pc); + +// if( pexblock->pOldFnptr ) { +// // code already in place, so jump to it and exit recomp +// JMP32((u32)pexblock->pOldFnptr - ((u32)x86Ptr + 5)); +// branch = 3; +// return; +// } + + JMP32((uptr)pblock->pFnptr - ((uptr)x86Ptr + 5)); + branch = 3; + return; + } + else { + + if( !(delayslot && pblock->startpc == pc) ) { + s8* oldX86 = x86Ptr; + //__Log("clear block %x\n", pblock->startpc); + recClearMem(pblock); + x86Ptr = oldX86; + if( delayslot ) + SysPrintf("delay slot %x\n", pc); + } + } + } + + if( delayslot ) + pblock->uType = BLOCKTYPE_DELAYSLOT; + + s_pCode = (int *)PSM( pc ); + assert(s_pCode); + +#ifdef _DEBUG + MOV32ItoR(EAX, pc); +#endif + + cpuRegs.code = *(int *)s_pCode; + s_nBlockCycles++; + pc += 4; + +//#ifdef _DEBUG +// CMP32ItoM((u32)s_pCode, cpuRegs.code); +// j8Ptr[0] = JE8(0); +// MOV32ItoR(EAX, pc); +// CALLFunc((uptr)checkcodefn); +// x86SetJ8( j8Ptr[ 0 ] ); +// +// if( !delayslot ) { +// CMP32ItoM((uptr)&cpuRegs.pc, s_pCurBlockEx->startpc); +// j8Ptr[0] = JB8(0); +// CMP32ItoM((uptr)&cpuRegs.pc, pc); +// j8Ptr[1] = JA8(0); +// j8Ptr[2] = JMP8(0); +// x86SetJ8( j8Ptr[ 0 ] ); +// x86SetJ8( j8Ptr[ 1 ] ); +// PUSH32I(s_pCurBlockEx->startpc); +// CALLFunc((uptr)checkpchanged); +// ADD32ItoR(ESP, 4); +// x86SetJ8( j8Ptr[ 2 ] ); +// } +//#endif + + g_pCurInstInfo++; + + // reorder register priorities + for(i = 0; i < X86REGS; ++i) { + if( x86regs[i].inuse ) { + if( x86regs[i].type == X86TYPE_GPR ) { + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, XMMTYPE_GPRREG, x86regs[i].reg); + if( count > 0 ) x86regs[i].counter = 1000-count; + else x86regs[i].counter = 0; + } + else x86regs[i].counter = 0; + } + } + + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse ) { + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, xmmregs[i].type, xmmregs[i].reg); + if( count > 0 ) xmmregs[i].counter = 1000-count; + else xmmregs[i].counter = 0; + } + } + + // peephole optimizations + if( g_pCurInstInfo->info & EEINSTINFO_COREC ) { + +#ifdef PCSX2_VIRTUAL_MEM + if( g_pCurInstInfo->numpeeps > 1 ) { + switch(cpuRegs.code>>26) { + case 30: recLQ_coX(g_pCurInstInfo->numpeeps); break; + case 31: recSQ_coX(g_pCurInstInfo->numpeeps); break; + case 49: recLWC1_coX(g_pCurInstInfo->numpeeps); break; + case 57: recSWC1_coX(g_pCurInstInfo->numpeeps); break; + case 55: recLD_coX(g_pCurInstInfo->numpeeps); break; + case 63: recSD_coX(g_pCurInstInfo->numpeeps); break; + default: + assert(0); + } + + pc += g_pCurInstInfo->numpeeps*4; + s_nBlockCycles += g_pCurInstInfo->numpeeps; + g_pCurInstInfo += g_pCurInstInfo->numpeeps; + } + else { + recBSC_co[cpuRegs.code>>26](); + pc += 4; + s_nBlockCycles++; + g_pCurInstInfo++; + } +#else + assert(0); +#endif + } + else { + assert( !(g_pCurInstInfo->info & EEINSTINFO_NOREC) ); + + // if this instruction is a jump or a branch, exit right away + if( delayslot ) { + switch(cpuRegs.code>>26) { + case 1: + switch(_Rt_) { + case 0: case 1: case 2: case 3: case 0x10: case 0x11: case 0x12: case 0x13: + SysPrintf("branch %x in delay slot!\n", cpuRegs.code); + _clearNeededX86regs(); + _clearNeededXMMregs(); + return; + } + break; + + case 2: case 3: case 4: case 5: case 6: case 7: case 0x14: case 0x15: case 0x16: case 0x17: + SysPrintf("branch %x in delay slot!\n", cpuRegs.code); + _clearNeededX86regs(); + _clearNeededXMMregs(); + return; + } + } + recBSC[ cpuRegs.code >> 26 ](); + } + + if( !delayslot ) { + if( s_bFlushReg ) { + //if( !_flushUnusedConstReg() ) { + int flushed = 0; + if( !flushed && _getNumXMMwrite() > 2 ) _flushXMMunused(); + s_bFlushReg = !flushed; +// } +// else s_bFlushReg = 0; + } + else s_bFlushReg = 1; + } + else s_bFlushReg = 1; + + //CHECK_XMMCHANGED(); + _clearNeededX86regs(); + _clearNeededXMMregs(); + + // for now + _freeXMMregs(); + _flushCachedRegs(); + g_cpuHasConstReg = 0; +} + +//////////////////////////////////////////////////// +#include "R3000A.h" +#include "PsxCounters.h" +#include "PsxMem.h" +extern tIPU_BP g_BP; + +extern u32 psxdump; +extern u32 psxNextCounter, psxNextsCounter; +extern void iDumpPsxRegisters(u32 startpc, u32 temp); +extern Counter counters[6]; + +void iDumpRegisters(u32 startpc, u32 temp) +{ + int i; + char* pstr = temp ? "t" : ""; + const u32 dmacs[] = {0x8000, 0x9000, 0xa000, 0xb000, 0xb400, 0xc000, 0xc400, 0xc800, 0xd000, 0xd400 }; + extern char *disRNameGPR[]; + + __Log("%sreg: %x %x\n", pstr, startpc, cpuRegs.interrupt); + for(i = 1; i < 32; ++i) __Log("%s: %x_%x_%x_%x\n", disRNameGPR[i], cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0]); + //for(i = 0; i < 32; ++i) __Log("%sf%d: %f %x\n", pstr, i, fpuRegs.fpr[i].f, fpuRegs.fprc[i]); + //for(i = 1; i < 32; ++i) __Log("%svf%d: %f %f %f %f, vi: %x\n", pstr, i, VU0.VF[i].F[3], VU0.VF[i].F[2], VU0.VF[i].F[1], VU0.VF[i].F[0], VU0.VI[i].UL); + for(i = 0; i < 32; ++i) __Log("%sf%d: %x %x\n", pstr, i, fpuRegs.fpr[i].UL, fpuRegs.fprc[i]); + for(i = 1; i < 32; ++i) __Log("%svf%d: %x %x %x %x, vi: %x\n", pstr, i, VU0.VF[i].UL[3], VU0.VF[i].UL[2], VU0.VF[i].UL[1], VU0.VF[i].UL[0], VU0.VI[i].UL); + __Log("%svfACC: %x %x %x %x\n", pstr, VU0.ACC.UL[3], VU0.ACC.UL[2], VU0.ACC.UL[1], VU0.ACC.UL[0]); + __Log("%sLO: %x_%x_%x_%x, HI: %x_%x_%x_%x\n", pstr, cpuRegs.LO.UL[3], cpuRegs.LO.UL[2], cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], + cpuRegs.HI.UL[3], cpuRegs.HI.UL[2], cpuRegs.HI.UL[1], cpuRegs.HI.UL[0]); + __Log("%sCycle: %x %x, Count: %x\n", pstr, cpuRegs.cycle, g_nextBranchCycle, cpuRegs.CP0.n.Count); + iDumpPsxRegisters(psxRegs.pc, temp); + + __Log("cyc11: %x %x; vu0: %x, vu1: %x\n", cpuRegs.sCycle[1], cpuRegs.eCycle[1], VU0.cycle, VU1.cycle); + + __Log("%scounters: %x %x; psx: %x %x\n", pstr, nextsCounter, nextCounter, psxNextsCounter, psxNextCounter); + for(i = 0; i < 4; ++i) { + __Log("eetimer%d: count: %x mode: %x target: %x %x; %x %x; %x %x %x %x\n", i, + counters[i].count, counters[i].mode, counters[i].target, counters[i].hold, counters[i].rate, + counters[i].interrupt, counters[i].Cycle, counters[i].sCycle, counters[i].CycleT, counters[i].sCycleT); + } + __Log("VIF0_STAT = %x, VIF1_STAT = %x\n", psHu32(0x3800), psHu32(0x3C00)); + __Log("ipu %x %x %x %x; bp: %x %x %x %x\n", psHu32(0x2000), psHu32(0x2010), psHu32(0x2020), psHu32(0x2030), g_BP.BP, g_BP.bufferhasnew, g_BP.FP, g_BP.IFC); + __Log("gif: %x %x %x\n", psHu32(0x3000), psHu32(0x3010), psHu32(0x3020)); + for(i = 0; i < ARRAYSIZE(dmacs); ++i) { + DMACh* p = (DMACh*)(PS2MEM_HW+dmacs[i]); + __Log("dma%d c%x m%x q%x t%x s%x\n", i, p->chcr, p->madr, p->qwc, p->tadr, p->sadr); + } + __Log("dmac %x %x %x %x\n", psHu32(DMAC_CTRL), psHu32(DMAC_STAT), psHu32(DMAC_RBSR), psHu32(DMAC_RBOR)); + __Log("intc %x %x\n", psHu32(INTC_STAT), psHu32(INTC_MASK)); + __Log("sif: %x %x %x %x %x\n", psHu32(0xf200), psHu32(0xf220), psHu32(0xf230), psHu32(0xf240), psHu32(0xf260)); +} + +extern u32 psxdump; + +static void printfn() +{ + static int lastrec = 0; + static int curcount = 0, count2 = 0; + const int skip = 0; + static int i; + + assert( !g_globalXMMSaved ); + +#ifdef _DEBUG + //__asm stmxcsr i + //assert( i = g_sseMXCSR ); +#endif + + if( (dumplog&2) ) {//&& lastrec != g_lastpc ) { + + curcount++; + + if( curcount > skip ) { + iDumpRegisters(g_lastpc, 1); + curcount = 0; + } + + lastrec = g_lastpc; + } +} + +u32 s_recblocks[] = {0}; + +void badespfn() { + assert(0); + SysPrintf("Bad esp!\n"); +} + +#define OPTIMIZE_COP2 0//CHECK_VU0REC + +void recRecompile( u32 startpc ) +{ + u32 i = 0; + u32 branchTo; + u32 willbranch3 = 0; + u32* ptr; + u32 usecop2; + +#ifdef _DEBUG + //dumplog |= 4; + if( dumplog & 4 ) + iDumpRegisters(startpc, 0); +#endif + + assert( startpc ); + + // if recPtr reached the mem limit reset whole mem + if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { + recReset(); + } + if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) { +#ifdef _DEBUG + SysPrintf("stack reset\n"); +#endif + recReset(); + } + + s_pCurBlock = PC_GETBLOCK(startpc); + + if( s_pCurBlock->pFnptr ) { + // clear if already taken + assert( s_pCurBlock->startpc < startpc ); + recClearMem(s_pCurBlock); + } + + if( s_pCurBlock->startpc == startpc ) { + s_pCurBlockEx = PC_GETBLOCKEX(s_pCurBlock); + assert( s_pCurBlockEx->startpc == startpc ); + } + else { + s_pCurBlockEx = NULL; + for(i = 0; i < EE_NUMBLOCKS; ++i) { + if( recBlocks[(i+s_nNextBlock)%EE_NUMBLOCKS].size == 0 ) { + s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%EE_NUMBLOCKS; + s_nNextBlock = (i+s_nNextBlock+1)%EE_NUMBLOCKS; + break; + } + } + + if( s_pCurBlockEx == NULL ) { + //SysPrintf("ee reset (blocks)\n"); + recReset(); + s_nNextBlock = 0; + s_pCurBlockEx = recBlocks; + } + + s_pCurBlockEx->startpc = startpc; + } + + x86SetPtr( recPtr ); + x86Align(16); + recPtr = x86Ptr; + + assert( (uptr)x86Ptr <= 0xffffffff ); + s_pCurBlock->pFnptr = (u32)x86Ptr; + s_pCurBlock->startpc = startpc; + + branch = 0; + + // reset recomp state variables + s_nBlockCycles = 0; + pc = startpc; + iCWstate = 0; + s_saveConstGPRreg = 0; + g_cpuHasConstReg = g_cpuFlushedConstReg = 1; + g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff; + g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0; + _recClearWritebacks(); + assert( g_cpuConstRegs[0].UD[0] == 0 ); + + _initX86regs(); + _initXMMregs(); + +#ifdef _DEBUG + //CMP64MtoR(RSP, (uptr)&s_uSaveESP); + //j8Ptr[0] = JE8(0); + //CALLFunc((uptr)badespfn); + //x86SetJ8(j8Ptr[0]); + + // for debugging purposes + MOV32ItoM((uptr)&g_lastpc, pc); + CALLFunc((uptr)printfn); +#endif + + // go until the next branch + i = startpc; + s_nEndBlock = 0xffffffff; + s_nHasDelay = 0; + + while(1) { + BASEBLOCK* pblock = PC_GETBLOCK(i); + if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( i == pblock->startpc ) { + // branch = 3 + willbranch3 = 1; + s_nEndBlock = i; + break; + } + } + + cpuRegs.code = *(int *)PSM(i); + + switch(cpuRegs.code >> 26) { + case 0: // special + + if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR + s_nEndBlock = i + 8; + s_nHasDelay = 1; + goto StartRecomp; + } + + break; + case 1: // regimm + + if( _Rt_ < 4 || (_Rt_ >= 16 && _Rt_ < 20) ) { + // branches + if( _Rt_ == 2 && _Rt_ == 3 && _Rt_ == 18 && _Rt_ == 19 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + break; + + case 2: // J + case 3: // JAL + s_nHasDelay = 1; + s_nEndBlock = i + 8; + goto StartRecomp; + + // branches + case 4: case 5: case 6: case 7: + case 20: case 21: case 22: case 23: + + if( (cpuRegs.code >> 26) >= 20 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + + case 16: // cp0 + if( _Rs_ == 16 ) { + if( _Funct_ == 24 ) { // eret + s_nEndBlock = i+4; + goto StartRecomp; + } + } + + break; + case 17: // cp1 + case 18: // cp2 + if( _Rs_ == 8 ) { + // BC1F, BC1T, BC1FL, BC1TL + // BC2F, BC2T, BC2FL, BC2TL + if( _Rt_ >= 2 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + break; + } + + i += 4; + } + +StartRecomp: + + // rec info // + { + EEINST* pcur; + + if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { + free(s_pInstCache); + s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; + s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); + assert( s_pInstCache != NULL ); + } + + pcur = s_pInstCache + (s_nEndBlock-startpc)/4; + _recClearInst(pcur); + pcur->info = 0; + + for(i = s_nEndBlock; i > startpc; i -= 4 ) { + cpuRegs.code = *(int *)PSM(i-4); + pcur[-1] = pcur[0]; + rpropBSC(pcur-1, pcur); + pcur--; + } + } + + // analyze instructions // + { + usecop2 = 0; + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock; i += 4) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(i); + + // cop2 // + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + + if( !usecop2 ) { + // init + if( OPTIMIZE_COP2 ) { + memset(VU0.fmac,0,sizeof(VU0.fmac)); + memset(&VU0.fdiv,0,sizeof(VU0.fdiv)); + memset(&VU0.efu,0,sizeof(VU0.efu)); + } + vucycle = 0; + usecop2 = 1; + } + + VU0.code = cpuRegs.code; + _cop2AnalyzeOp(g_pCurInstInfo, OPTIMIZE_COP2); + continue; + } + + if( usecop2 ) vucycle++; + + // peephole optimizations // +#ifdef PCSX2_VIRTUAL_MEM + if( i < s_nEndBlock-4 && recompileCodeSafe(i) ) { + u32 curcode = cpuRegs.code; + u32 nextcode = *(u32*)PSM(i+4); + if( _eeIsLoadStoreCoIssue(curcode, nextcode) && recBSC_co[curcode>>26] != NULL ) { + + // rs has to be the same, and cannot be just written + if( ((curcode >> 21) & 0x1F) == ((nextcode >> 21) & 0x1F) && !_eeLoadWritesRs(curcode) ) { + + if( _eeIsLoadStoreCoX(curcode) && ((nextcode>>16)&0x1f) != ((curcode>>21)&0x1f) ) { + // see how many stores there are + u32 j; + // use xmmregs since only supporting lwc1,lq,swc1,sq + for(j = i+8; j < s_nEndBlock && j < i+4*XMMREGS; j += 4 ) { + u32 nncode = *(u32*)PSM(j); + if( (nncode>>26) != (curcode>>26) || ((curcode>>21)&0x1f) != ((nncode>>21)&0x1f) || + _eeLoadWritesRs(nncode)) + break; + } + + if( j > i+8 ) { + u32 num = (j-i)>>2; // number of stores that can coissue + assert( num <= XMMREGS ); + + g_pCurInstInfo[0].numpeeps = num-1; + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + + while(i < j-4) { + g_pCurInstInfo++; + g_pCurInstInfo[0].info |= EEINSTINFO_NOREC; + i += 4; + } + + continue; + } + + // fall through + } + + // unaligned loadstores + + // if LWL, check if LWR and that offsets are +3 away + switch(curcode >> 26) { + case 0x22: // LWL + if( (nextcode>>26) != 0x26 || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x26: // LWR + if( (nextcode>>26) != 0x22 || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x2a: // SWL + if( (nextcode>>26) != 0x2e || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x2e: // SWR + if( (nextcode>>26) != 0x2a || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x1a: // LDL + if( (nextcode>>26) != 0x1b || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x1b: // LWR + if( (nextcode>>26) != 0x1aa || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + + case 0x2c: // SWL + if( (nextcode>>26) != 0x2d || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x2d: // SWR + if( (nextcode>>26) != 0x2c || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + } + + // good enough + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + g_pCurInstInfo[0].numpeeps = 1; + g_pCurInstInfo[1].info |= EEINSTINFO_NOREC; + g_pCurInstInfo++; + i += 4; + continue; + } + } + } +#endif // end peephole + } + + if( usecop2 ) { + // add necessary mac writebacks + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock-4; i += 4) { + g_pCurInstInfo++; + + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + } + } + } + } + + // perf counters // +#ifdef PCSX2_DEVBUILD + s_startcount = 0; +// if( pc+32 < s_nEndBlock ) { +// // only blocks with more than 8 insts +// //PUSH32I((uptr)&lbase); +// //CALLFunc((uptr)QueryPerformanceCounter); +// lbase.QuadPart = GetCPUTick(); +// s_startcount = 1; +// } +#endif + +#ifdef _DEBUG + // dump code + for(i = 0; i < ARRAYSIZE(s_recblocks); ++i) { + if( startpc == s_recblocks[i] ) { + iDumpBlock(startpc, recPtr); + } + } + + if( (dumplog & 1) ) //|| usecop2 ) + iDumpBlock(startpc, recPtr); +#endif + + // finally recompile // + g_pCurInstInfo = s_pInstCache; + while (!branch && pc < s_nEndBlock) { + recompileNextInstruction(0); + } + +#ifdef _DEBUG + if( (dumplog & 1) ) + iDumpBlock(startpc, recPtr); +#endif + + assert( (pc-startpc)>>2 <= 0xffff ); + s_pCurBlockEx->size = (pc-startpc)>>2; + + for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // don't overwrite if delay slot + if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { + s_pCurBlock[i].pFnptr = s_pCurBlock->pFnptr; + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // set the block ptr + AddBaseBlockEx(s_pCurBlockEx, 0); +// if( p[1].startpc == p[0].startpc + 4 ) { +// assert( p[1].pFnptr != 0 ); +// // already fn in place, so add to list +// AddBaseBlockEx(s_pCurBlockEx, 0); +// } +// else +// *(BASEBLOCKEX**)(p+1) = pex; +// } + + //PC_SETBLOCKEX(s_pCurBlock, s_pCurBlockEx); + + if( !(pc&0x10000000) ) + maxrecmem = max( (pc&~0xa0000000), maxrecmem ); + + if( branch == 2 ) { + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(0xffffffff, 1); + if( bExecBIOS ) CheckForBIOSEnd(); + + JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); + } + else { + assert( branch != 3 ); + if( branch ) assert( !willbranch3 ); + else ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles*9/8); + + if( willbranch3 ) { + BASEBLOCK* pblock = PC_GETBLOCK(s_nEndBlock); + assert( pc == s_nEndBlock ); + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&cpuRegs.pc, pc); + JMP32((uptr)pblock->pFnptr - ((uptr)x86Ptr + 5)); + branch = 3; + } + else if( !branch ) { + // didn't branch, but had to stop + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + + iFlushCall(FLUSH_EVERYTHING); + + ptr = JMP32(0); + } + } + + assert( x86Ptr >= (s8*)s_pCurBlock->pFnptr + EE_MIN_BLOCK_BYTES ); + assert( x86Ptr < recMem+REC_CACHEMEM ); + assert( recStackPtr < recStack+RECSTACK_SIZE ); + assert( x86FpuState == 0 ); + + recPtr = x86Ptr; + + assert( (g_cpuHasConstReg&g_cpuFlushedConstReg) == g_cpuHasConstReg ); + + if( !branch ) { + BASEBLOCK* pcurblock = s_pCurBlock; + u32 nEndBlock = s_nEndBlock; + s_pCurBlock = PC_GETBLOCK(pc); + assert( ptr != NULL ); + + if( s_pCurBlock->startpc != pc ) + recRecompile(pc); + + if( pcurblock->startpc == startpc ) { + assert( pcurblock->pFnptr ); + assert( s_pCurBlock->startpc == nEndBlock ); + *ptr = s_pCurBlock->pFnptr - ( (uptr)ptr + 4 ); + } + else { + recRecompile(startpc); + assert( pcurblock->pFnptr != 0 ); + } + } +} + +R5900cpu recCpu = { + recInit, + recReset, + recStep, + recExecute, + recExecuteBlock, + recExecuteVU0Block, + recExecuteVU1Block, + recEnableVU0micro, + recEnableVU1micro, + recClear, + recClearVU0, + recClearVU1, + recShutdown +}; + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900Arit-64.c b/pcsx2/x86/ix86-64/iR5900Arit-64.c new file mode 100644 index 0000000000..dec9712c27 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900Arit-64.c @@ -0,0 +1,213 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +#ifndef ARITHMETIC_RECOMPILE + +REC_FUNC(ADD); +REC_FUNC(ADDU); +REC_FUNC(DADD); +REC_FUNC(DADDU); +REC_FUNC(SUB); +REC_FUNC(SUBU); +REC_FUNC(DSUB); +REC_FUNC(DSUBU); +REC_FUNC(AND); +REC_FUNC(OR); +REC_FUNC(XOR); +REC_FUNC(NOR); +REC_FUNC(SLT); +REC_FUNC(SLTU); + +#else + +//////////////////////////////////////////////////// +void recADD( void ) { + if (!_Rd_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if (_Rt_ != 0) { + ADD32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recADDU( void ) +{ + recADD( ); +} + +//////////////////////////////////////////////////// +void recDADD( void ) { + if (!_Rd_) return; + + MOV64MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Rt_ != 0 ) { + ADD64MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); +} + +//////////////////////////////////////////////////// +void recDADDU( void ) +{ + recDADD( ); +} + +//////////////////////////////////////////////////// +void recSUB( void ) { + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Rt_ != 0 ) { + SUB32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recSUBU( void ) +{ + recSUB( ); +} + +//////////////////////////////////////////////////// +void recDSUB( void ) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Rt_ != 0 ) { + SUB64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSUBU( void ) +{ + recDSUB( ); +} + +//////////////////////////////////////////////////// +void recAND( void ) { + if (!_Rd_) return; + + if (_Rt_ == _Rd_) { // Rd&= Rs + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } else if (_Rs_ == _Rd_) { // Rd&= Rt + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + AND64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } else { // Rd = Rs & Rt + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } +} + +//////////////////////////////////////////////////// +void recOR( void ) { + if (!_Rd_) return; + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) { + XOR64RtoR(RAX, RAX); + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[0], RAX ); + } else if ( _Rs_ == 0 ) { + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } + else if ( _Rt_ == 0 ) { + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } + else { + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + OR64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); + } +} + +//////////////////////////////////////////////////// +void recXOR( void ) { + if (!_Rd_) return; + + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + XOR64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); +} + +//////////////////////////////////////////////////// +void recNOR( void ) { + if (!_Rd_) return; + + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + OR64MtoR(RAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + NOT64R(RAX); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); +} + +//////////////////////////////////////////////////// +void recSLT( void ) { + if (!_Rd_) return; + + MOV64MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + CMP64MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + SETL8R (EAX); + AND64I32toR(EAX, 0xff); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); +} + +//////////////////////////////////////////////////// +void recSLTU( void ) { + if (!_Rd_) return; + + MOV64MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + CMP64MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + SBB64RtoR(EAX, EAX); + NEG64R (EAX); + MOV64RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], RAX); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900AritImm-64.c b/pcsx2/x86/ix86-64/iR5900AritImm-64.c new file mode 100644 index 0000000000..fb1733eee6 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900AritImm-64.c @@ -0,0 +1,169 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +#ifndef ARITHMETICIMM_RECOMPILE + +REC_FUNC(ADDI); +REC_FUNC(ADDIU); +REC_FUNC(DADDI); +REC_FUNC(DADDIU); +REC_FUNC(ANDI); +REC_FUNC(ORI); +REC_FUNC(XORI); + +REC_FUNC(SLTI); +REC_FUNC(SLTIU); + +#else + +//////////////////////////////////////////////////// +void recADDI( void ) { + if (!_Rt_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if (_Imm_ != 0) { + ADD32ItoR( EAX, _Imm_ ); + } + + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recADDIU( void ) +{ + recADDI( ); +} + +//////////////////////////////////////////////////// +void recDADDI( void ) { + int rsreg; + int rtreg; + + if (!_Rt_) return; + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD64ItoR( EAX, _Imm_ ); + } + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDADDIU( void ) +{ + recDADDI( ); +} + +//////////////////////////////////////////////////// +void recSLTIU( void ) +{ + if ( ! _Rt_ ) return; + + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP64I32toR(RAX, _Imm_); + SETB8R (EAX); + AND64I32toR(EAX, 0xff); + MOV64RtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX); +} + +//////////////////////////////////////////////////// +void recSLTI( void ) +{ + if ( ! _Rt_ ) + return; + + MOV64MtoR(RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP64I32toR(RAX, _Imm_); + SETL8R (EAX); + AND64I32toR(EAX, 0xff); + MOV64RtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX); +} + +//////////////////////////////////////////////////// +void recANDI( void ) { + if (!_Rt_) return; + + if ( _ImmU_ != 0 ) { + if (_Rs_ == _Rt_) { + MOV32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + AND32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _ImmU_ ); + } + else { + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( EAX, _ImmU_ ); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + } + else { + MOV32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + } +} + +//////////////////////////////////////////////////// +void recORI( void ) { + if (!_Rt_) return; + + if (_Rs_ == _Rt_) { + OR32ItoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], _ImmU_ ); + } else { + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + if ( _ImmU_ != 0 ) { + OR64ItoR( RAX, _ImmU_ ); + } + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], RAX ); + } +} + +//////////////////////////////////////////////////// +void recXORI( void ) { + if (!_Rt_) return; + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + XOR64ItoR( RAX, _ImmU_ ); + MOV64RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], RAX ); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900Branch-64.c b/pcsx2/x86/ix86-64/iR5900Branch-64.c new file mode 100644 index 0000000000..4e988ace69 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900Branch-64.c @@ -0,0 +1,537 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#ifndef BRANCH_RECOMPILE + +REC_SYS(BEQ); +REC_SYS(BEQL); +REC_SYS(BNE); +REC_SYS(BNEL); +REC_SYS(BLTZ); +REC_SYS(BGTZ); +REC_SYS(BLEZ); +REC_SYS(BGEZ); +REC_SYS(BGTZL); +REC_SYS(BLTZL); +REC_SYS(BLTZAL); +REC_SYS(BLTZALL); +REC_SYS(BLEZL); +REC_SYS(BGEZL); +REC_SYS(BGEZAL); +REC_SYS(BGEZALL); + +#else + +u32 target; +//////////////////////////////////////////////////// +void recBEQ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededX86regs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else + { + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + } +} + +//////////////////////////////////////////////////// +void recBNE( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededX86regs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm(pc); + return; + } + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLTZAL( void ) +{ + SysPrintf("BLTZAL\n"); + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BLTZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZAL( void ) +{ + SysPrintf("BGEZAL\n"); + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BGEZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBLEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JL32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGTZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JGE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JLE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JG32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLEZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededX86regs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JL32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededX86regs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JGE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JLE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZL( void ) +{ +u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + XOR64RtoR(RAX, RAX); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + j32Ptr[ 0 ] = JG32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZALL( void ) +{ + SysPrintf("BLTZALL\n"); + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BLTZALL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZALL( void ) +{ + SysPrintf("BGEZALL\n"); + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (u32)BGEZALL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBEQL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBNEL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP64MtoR( RAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + _clearNeededX86regs(); + _clearNeededXMMregs(); + + SaveBranchState(); + SetBranchImm(pc+4); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + LoadBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900Jump-64.c b/pcsx2/x86/ix86-64/iR5900Jump-64.c new file mode 100644 index 0000000000..da94b78d29 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900Jump-64.c @@ -0,0 +1,114 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +#ifndef JUMP_RECOMPILE + +REC_SYS(J); +REC_SYS(JAL); +REC_SYS(JR); +REC_SYS(JALR); + +#else + +//////////////////////////////////////////////////// +void recJ( void ) +{ + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +//////////////////////////////////////////////////// +void recJAL( void ) +{ + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + _deleteEEreg(31, 0); + GPR_SET_CONST(31); + g_cpuConstRegs[31].UL[0] = pc + 4; + g_cpuConstRegs[31].UL[1] = 0; + + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ + +//////////////////////////////////////////////////// +void recJR( void ) +{ + SetBranchReg( _Rs_ ); +} + +//////////////////////////////////////////////////// +void recJALR( void ) +{ + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, _Rs_); + + if ( _Rd_ ) { + _deleteEEreg(_Rd_, 0); + GPR_SET_CONST(_Rd_); + g_cpuConstRegs[_Rd_].UL[0] = pc + 4; + g_cpuConstRegs[_Rd_].UL[1] = 0; + } + + _clearNeededX86regs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((int)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (u32)&g_recWriteback); + MOV32RtoM((int)&cpuRegs.pc, EAX); + } + + SetBranchReg(0xffffffff); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900LoadStore-64.c b/pcsx2/x86/ix86-64/iR5900LoadStore-64.c new file mode 100644 index 0000000000..5d4b276850 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900LoadStore-64.c @@ -0,0 +1,423 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "VU0.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +#ifndef LOADSTORE_RECOMPILE + +REC_FUNC(LB); +REC_FUNC(LBU); +REC_FUNC(LH); +REC_FUNC(LHU); +REC_FUNC(LW); +REC_FUNC(LWU); +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(LD); +REC_FUNC(LDR); +REC_FUNC(LDL); +REC_FUNC(LQ); +REC_FUNC(SB); +REC_FUNC(SH); +REC_FUNC(SW); +REC_FUNC(SWL); +REC_FUNC(SWR); +REC_FUNC(SD); +REC_FUNC(SDL); +REC_FUNC(SDR); +REC_FUNC(SQ); +REC_FUNC(LWC1); +REC_FUNC(SWC1); +REC_FUNC(LQC2); +REC_FUNC(SQC2); + +void SetFastMemory(int bSetFast) {} + +#else + +static int s_bFastMemory = 0; +void SetFastMemory(int bSetFast) +{ + s_bFastMemory = bSetFast; +} + +u64 retValue; +u64 dummyValue[ 4 ]; + +//////////////////////////////////////////////////// +void recLB( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc( (uptr)memRead8RS ); +} + +//////////////////////////////////////////////////// +void recLBU( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + iFlushCall(FLUSH_EVERYTHING); + CALLFunc((uptr)memRead8RU ); +} + +//////////////////////////////////////////////////// +void recLH( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ){ + ADD32ItoR( X86ARG1, _Imm_ ); + } + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + iFlushCall(FLUSH_EVERYTHING); + CALLFunc((uptr)memRead16RS ); +} + +//////////////////////////////////////////////////// +void recLHU( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc((uptr)memRead16RU ); +} + +void tests() { + SysPrintf("Err\n"); +} + +//////////////////////////////////////////////////// +void recLW( void ) { + int rsreg; + int rtreg; + int t0reg; + int t1reg; + int t2reg; + + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc((uptr)memRead32RS ); +} + +//////////////////////////////////////////////////// +void recLWU( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc((uptr)memRead32RU ); +} + +void recLWL( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)LWL ); +} + +void recLWR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)LWR ); +} + +void recLD( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc((uptr)memRead64 ); +} + +void recLDL( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)LDL ); +} + +void recLDR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)LDR ); +} + +void recLQ( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_); + } + AND32ItoR( X86ARG1, ~0xf ); + + if ( _Rt_ ) { + MOV64ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } else { + MOV64ItoR( X86ARG2, (uptr)&dummyValue ); + } + CALLFunc((uptr)memRead128 ); +} + +//////////////////////////////////////////////////// +void recSB( void ) { + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_); + } + MOV32MtoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc((uptr)memWrite8 ); +} + +void recSH( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + MOV32MtoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc((uptr)memWrite16 ); +} + +void recSW( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + MOV32MtoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc((uptr)memWrite32 ); +} + +void recSWL( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)SWL ); +} + +void recSWR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)SWR ); +} + +void recSD( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + MOV64MtoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc((uptr)memWrite64 ); +} + +void recSDL( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)SDL ); +} + +void recSDR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc((uptr)SDR ); +} + +void recSQ( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) { + ADD32ItoR( X86ARG1, _Imm_ ); + } + AND32ItoR( X86ARG1, ~0xf ); + + MOV32ItoR( X86ARG2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc((uptr)memWrite128 ); +} + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +// Load and store for COP1 +// Format: OP rt, offset(base) +void recLWC1( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( X86ARG1, _Imm_ ); + MOV64ItoR( X86ARG2, (uptr)&fpuRegs.fpr[ _Ft_ ].UL ); + + CALLFunc((uptr)memRead32 ); +} + +void recSWC1( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( X86ARG1, _Imm_ ); + + MOV32MtoR( X86ARG2, (uptr)&fpuRegs.fpr[ _Ft_ ].UL ); + + CALLFunc((uptr)memWrite32 ); +} + +void recLQC2( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( X86ARG1, _Imm_); + + if ( _Rt_ ) + MOV64ItoR(X86ARG2, (uptr)&VU0.VF[_Ft_].UD[0] ); + else + MOV64ItoR(X86ARG2, (uptr)&dummyValue ); + + CALLFunc((uptr)memRead128 ); +} + +void recSQC2( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + + MOV32MtoR( X86ARG1, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( X86ARG1, _Imm_ ); + + MOV64ItoR(X86ARG2, (uptr)&VU0.VF[_Ft_].UD[0] ); + + CALLFunc((uptr)memWrite128 ); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900Move-64.c b/pcsx2/x86/ix86-64/iR5900Move-64.c new file mode 100644 index 0000000000..cb62a547a6 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900Move-64.c @@ -0,0 +1,85 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef MOVE_RECOMPILE + +REC_FUNC(LUI); +REC_FUNC(MFLO); +REC_FUNC(MFHI); +REC_FUNC(MTLO); +REC_FUNC(MTHI); +REC_FUNC(MOVZ); +REC_FUNC(MOVN); + +REC_FUNC( MFHI1 ); +REC_FUNC( MFLO1 ); +REC_FUNC( MTHI1 ); +REC_FUNC( MTLO1 ); + +#else +REC_FUNC(MFLO, _Rd_); +REC_FUNC(MFHI, _Rd_); +REC_FUNC(MTLO, 0); +REC_FUNC(MTHI, 0); +REC_FUNC(MOVZ, _Rd_); +REC_FUNC(MOVN, _Rd_); + +REC_FUNC( MFHI1, _Rd_ ); +REC_FUNC( MFLO1, _Rd_ ); +REC_FUNC( MTHI1, 0 ); +REC_FUNC( MTLO1, 0 ); + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ + +//////////////////////////////////////////////////// +void recLUI( void ) { + int rtreg; + + if (!_Rt_) return; + + MOV64I32toM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (s32)(_Imm_ << 16)); +} + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900MultDiv-64.c b/pcsx2/x86/ix86-64/iR5900MultDiv-64.c new file mode 100644 index 0000000000..7555c66cf0 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900MultDiv-64.c @@ -0,0 +1,164 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +#ifndef MULTDIV_RECOMPILE + +REC_FUNC(MULT); +REC_FUNC(MULTU); +REC_FUNC( MULT1 ); +REC_FUNC( MULTU1 ); + +REC_FUNC(DIV); +REC_FUNC(DIVU); +REC_FUNC( DIV1 ); +REC_FUNC( DIVU1 ); + +REC_FUNC( MADD ); +REC_FUNC( MADDU ); +REC_FUNC( MADD1 ); +REC_FUNC( MADDU1 );; + +#else + +//////////////////////////////////////////////////// +void recMULT( void ) +{ + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ ) + { + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recMULTU( void ) +{ + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MUL32M( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ != 0 ) + { + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 1 ], EDX ); +} + +REC_FUNC( MULT1, _Rd_ ); +REC_FUNC( MULTU1, _Rd_ ); + +//////////////////////////////////////////////////// +void recDIV( void ) +{ + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); +// XOR32RtoR( EDX,EDX ); + CDQ(); + IDIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 1 ], EDX ); + + x86SetJ8( j8Ptr[ 0 ] ); +} + +//////////////////////////////////////////////////// +void recDIVU( void ) +{ + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + XOR32RtoR( EDX, EDX ); + // CDQ(); + DIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX,ECX ); + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[ 1 ], EDX ); + x86SetJ8( j8Ptr[ 0 ] ); +} + +REC_FUNC( DIV1, _Rd_ ); +REC_FUNC( DIVU1, _Rd_ ); + +REC_FUNC( MADD, _Rd_ ); +REC_FUNC( MADDU, _Rd_ ); +REC_FUNC( MADD1, _Rd_ ); +REC_FUNC( MADDU1, _Rd_ ); + +#endif + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86-64/iR5900Shift-64.c b/pcsx2/x86/ix86-64/iR5900Shift-64.c new file mode 100644 index 0000000000..450927d4c1 --- /dev/null +++ b/pcsx2/x86/ix86-64/iR5900Shift-64.c @@ -0,0 +1,264 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include + +#include "Common.h" +#include "InterTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef SHIFT_RECOMPILE + +REC_FUNC(SLL); +REC_FUNC(SRL); +REC_FUNC(SRA); +REC_FUNC(DSLL); +REC_FUNC(DSRL); +REC_FUNC(DSRA); +REC_FUNC(DSLL32); +REC_FUNC(DSRL32); +REC_FUNC(DSRA32); + +REC_FUNC(SLLV); +REC_FUNC(SRLV); +REC_FUNC(SRAV); +REC_FUNC(DSLLV); +REC_FUNC(DSRLV); +REC_FUNC(DSRAV); + +#else + + +//////////////////////////////////////////////////// +void recDSRA( void ) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) { + SAR64ItoR( RAX, _Sa_ ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSRA32(void) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SAR64ItoR( RAX, _Sa_ + 32 ); + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recSLL(void) { + if (!_Rd_) return; + + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + if (_Sa_ != 0) { + SHL32ItoR(EAX, _Sa_); + } + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EDX); +} + +//////////////////////////////////////////////////// +void recSRL(void) { + if (!_Rd_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + if (_Sa_ != 0) { + SHR32ItoR(EAX, _Sa_); + } + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EDX); +} + +//////////////////////////////////////////////////// +void recSRA(void) { + if (!_Rd_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) { + SAR32ItoR( EAX, _Sa_); + } + CDQ(); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recDSLL(void) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) { + SHL64ItoR( RAX, _Sa_ ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSRL( void ) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) { + SHR64ItoR( RAX, _Sa_ ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSLL32(void) { + + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SHL64ItoR( RAX, _Sa_ + 32 ); + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSRL32( void ) { + + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SHR64ItoR( RAX, _Sa_ + 32 ); + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ + + +//////////////////////////////////////////////////// +void recSLLV( void ) { + if (!_Rd_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + } + CDQ(); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recSRLV( void ) { + if (!_Rd_) return; + + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recSRAV( void ) { + if (!_Rd_) return; + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recDSLLV( void ) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x3f ); + SHL64CLtoR( RAX ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSRLV( void ) { + + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x3f ); + SHR64CLtoR( RAX ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +//////////////////////////////////////////////////// +void recDSRAV( void ) { + if (!_Rd_) return; + + MOV64MtoR( RAX, (u64)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x3f ); + SAR64CLtoR( RAX ); + } + MOV64RtoM( (u64)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], RAX ); +} + +#endif + + +#endif // PCSX2_NORECBUILD diff --git a/pcsx2/x86/ix86/Makefile.am b/pcsx2/x86/ix86/Makefile.am new file mode 100644 index 0000000000..b54ef7af0b --- /dev/null +++ b/pcsx2/x86/ix86/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I@srcdir@/.. -I@srcdir@/../../ +noinst_LIBRARIES = libix86.a + +libix86_a_SOURCES = ix86_3dnow.c ix86.c ix86_cpudetect.c ix86_fpu.c ix86.h ix86_sse.c + +if X86_64 +else +libix86_a_SOURCES += ix86_mmx.c +endif diff --git a/pcsx2/x86/ix86/ix86.c b/pcsx2/x86/ix86/ix86.c new file mode 100644 index 0000000000..6d0664fe3e --- /dev/null +++ b/pcsx2/x86/ix86/ix86.c @@ -0,0 +1,3277 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * ix86 core v0.6.2 + * Authors: linuzappz + * alexey silinov + * goldfinger + * zerofrog(@gmail.com) + */ + +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include +#include "ix86.h" + +#define SWAP(x, y) { *(u32*)&y ^= *(u32*)&x; *(u32*)&x ^= *(u32*)&y; *(u32*)&y ^= *(u32*)&x; } + +#ifdef __x86_64__ + +#ifdef _MSC_VER +// visual studio calling convention +x86IntRegType g_x86savedregs[] = { RBX, RBP, RSI, RDI, R12, R13, R14, R15 }; +x86IntRegType g_x86tempregs[] = { R8, R9, R10, R11, RDX, RCX }; + +// arranged in savedreg -> tempreg order +x86IntRegType g_x86allregs[14] = { RBX, RBP, RSI, RDI, R12, R13, R14, R15, R8, R9, R10, R11, RDX, RCX }; + +#else +// standard calling convention + +// registers saved by calling functions (no need to flush them across calls) +x86IntRegType g_x86savedregs[] = { RBX, RBP, R12, R13, R14, R15 }; +// temp registers that need to be saved across calls +x86IntRegType g_x86tempregs[] = { RCX, RDX, R8, R9, R10, R11, RSI, RDI }; + +// arranged in savedreg -> tempreg order +x86IntRegType g_x86allregs[14] = { RBX, RBP, R12, R13, R14, R15, RCX, RDX, R8, R9, R10, R11, RSI, RDI }; + +#endif + +x86IntRegType g_x868bitregs[11] = { RBX, R12, R13, R14, R15, RCX, RDX, R8, R9, R10, R11 }; +x86IntRegType g_x86non8bitregs[3] = { RBP, RSI, RDI }; + +#endif // __x86_64__ + +s8 *x86Ptr; +u8 *j8Ptr[32]; +u32 *j32Ptr[32]; + +extern void SysPrintf(char *fmt, ...); + +void WriteRmOffset(x86IntRegType to, int offset) +{ + if( (to&7) == ESP ) { + if( offset == 0 ) { + ModRM( 0, 0, 4 ); + ModRM( 0, ESP, 4 ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, 0, 4 ); + ModRM( 0, ESP, 4 ); + write8(offset); + } + else { + ModRM( 2, 0, 4 ); + ModRM( 0, ESP, 4 ); + write32(offset); + } + } + else { + if( offset == 0 ) { + ModRM( 0, 0, to ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, 0, to ); + write8(offset); + } + else { + ModRM( 2, 0, to ); + write32(offset); + } + } +} + +void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset) +{ + if ((from&7) == ESP) { + if( offset == 0 ) { + ModRM( 0, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + write8(offset); + } + else { + ModRM( 2, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + write32(offset); + } + } + else { + if( offset == 0 ) { + ModRM( 0, to, from ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } + } +} + +// This function is just for rec debugging purposes +void CheckX86Ptr( void ) +{ +} + +void write64( u64 val ) +{ +#ifdef _DEBUG + CheckX86Ptr( ); +#endif + + *(u64*)x86Ptr = val; + x86Ptr += 8; +} + +void ModRM( int mod, int rm, int reg ) +{ + write8( ( mod << 6 ) | ( (rm & 7) << 3 ) | ( reg & 7 ) ); +} + +void SibSB( int ss, int rm, int index ) +{ + write8( ( ss << 6 ) | ( rm << 3 ) | ( index ) ); +} + +void SET8R( int cc, int to ) +{ + RexB(0, to); + write8( 0x0F ); + write8( cc ); + write8( 0xC0 | ( to ) ); +} + +u8* J8Rel( int cc, int to ) +{ + write8( cc ); + write8( to ); + return x86Ptr - 1; +} + +u16* J16Rel( int cc, u32 to ) +{ + write16( 0x0F66 ); + write8( cc ); + write16( to ); + return (u16*)( x86Ptr - 2 ); +} + +u32* J32Rel( int cc, u32 to ) +{ + write8( 0x0F ); + write8( cc ); + write32( to ); + return (u32*)( x86Ptr - 4 ); +} + +void CMOV32RtoR( int cc, int to, int from ) +{ + RexRB(0,to, from); + write8( 0x0F ); + write8( cc ); + ModRM( 3, to, from ); +} + +void CMOV32MtoR( int cc, int to, uptr from ) +{ + RexR(0, to); + write8( 0x0F ); + write8( cc ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +//////////////////////////////////////////////////// +void x86SetPtr( char* ptr ) +{ + x86Ptr = ptr; +} + +//////////////////////////////////////////////////// +void x86Shutdown( void ) +{ +} + +//////////////////////////////////////////////////// +void x86SetJ8( u8* j8 ) +{ + u32 jump = ( x86Ptr - (s8*)j8 ) - 1; + + if ( jump > 0x7f ) { + assert(0); + SysPrintf( "j8 greater than 0x7f!!\n" ); + } + *j8 = (u8)jump; +} + +void x86SetJ8A( u8* j8 ) +{ + u32 jump = ( x86Ptr - (s8*)j8 ) - 1; + + if ( jump > 0x7f ) { + assert(0); + SysPrintf( "j8 greater than 0x7f!!\n" ); + } + + if( ((uptr)x86Ptr&0xf) > 4 ) { + + uptr newjump = jump + 16-((uptr)x86Ptr&0xf); + + if( newjump <= 0x7f ) { + jump = newjump; + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + } + } + *j8 = (u8)jump; +} + +void x86SetJ16( u16 *j16 ) +{ + // doesn't work + u32 jump = ( x86Ptr - (s8*)j16 ) - 2; + + if ( jump > 0x7fff ) { + assert(0); + SysPrintf( "j16 greater than 0x7fff!!\n" ); + } + *j16 = (u16)jump; +} + +void x86SetJ16A( u16 *j16 ) +{ + if( ((uptr)x86Ptr&0xf) > 4 ) { + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + } + x86SetJ16(j16); +} + +//////////////////////////////////////////////////// +void x86SetJ32( u32* j32 ) +{ + *j32 = ( x86Ptr - (s8*)j32 ) - 4; +} + +void x86SetJ32A( u32* j32 ) +{ + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + x86SetJ32(j32); +} + +//////////////////////////////////////////////////// +void x86Align( int bytes ) +{ + // fordward align + x86Ptr = (s8*)( ( (uptr)x86Ptr + bytes - 1) & ~( bytes - 1 ) ); +} + +/********************/ +/* IX86 intructions */ +/********************/ + +void STC( void ) +{ + write8( 0xF9 ); +} + +void CLC( void ) +{ + write8( 0xF8 ); +} + +//////////////////////////////////// +// mov instructions / +//////////////////////////////////// + +/* mov r64 to r64 */ +void MOV64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x89 ); + ModRM( 3, from, to ); +} + +/* mov r64 to m64 */ +void MOV64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1, from); + write8( 0x89 ); + ModRM( 0, from, DISP32 ); + write32( (u32)MEMADDR(to, 4) ); +} + +/* mov m64 to r64 */ +void MOV64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x8B ); + ModRM( 0, to, DISP32 ); + write32( (u32)MEMADDR(from, 4) ); +} + +/* mov imm32 to m64 */ +void MOV64I32toM(uptr to, u32 from ) +{ + Rex(1, 0, 0, 0); + write8( 0xC7 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +// mov imm64 to r64 +void MOV64ItoR( x86IntRegType to, u64 from) +{ + RexB(1, to); + write8( 0xB8 | (to & 0x7) ); + write64( from ); +} + +/* mov imm32 to r64 */ +void MOV64I32toR( x86IntRegType to, s32 from ) +{ + RexB(1, to); + write8( 0xC7 ); + ModRM( 0, 0, to ); + write32( from ); +} + +// mov imm64 to [r64+off] +void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset) +{ + RexB(1,to); + write8( 0xC7 ); + WriteRmOffset(to, offset); + write32(from); +} + +// mov [r64+offset] to r64 +void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ) +{ + RexRB(1, to, from); + write8( 0x8B ); + WriteRmOffsetFrom(to, from, offset); +} + +/* mov [r64][r64*scale] to r64 */ +void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(1, to, from2, from); + write8( 0x8B ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + +/* mov r64 to [r64+offset] */ +void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ) +{ + RexRB(1,from,to); + write8( 0x89 ); + WriteRmOffsetFrom(from, to, offset); +} + +/* mov r64 to [r64][r64*scale] */ +void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(1, to, from2, from); + write8( 0x89 ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + + +/* mov r32 to r32 */ +void MOV32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x89 ); + ModRM( 3, from, to ); +} + +/* mov r32 to m32 */ +void MOV32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0, from); + write8( 0x89 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* mov m32 to r32 */ +void MOV32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0, to); + write8( 0x8B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* mov [r32] to r32 */ +void MOV32RmtoR( x86IntRegType to, x86IntRegType from ) { + RexRB(0, to, from); + write8(0x8B); + WriteRmOffsetFrom(to, from, 0); +} + +void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ) { + RexRB(0, to, from); + write8( 0x8B ); + WriteRmOffsetFrom(to, from, offset); +} + +/* mov [r32+r32*scale] to r32 */ +void MOV32RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(0,to,from2,from); + write8( 0x8B ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + +// mov r32 to [r32<> 3); + if ( to == EAX) { + write8( 0x05 ); + } else { + write8( 0x81 ); + ModRM( 3, 0, to ); + } + write32( from ); +} + +/* add m64 to r64 */ +void ADD64MtoR( x86IntRegType to, uptr from ) +{ + Rex(1, to >> 3, 0, 0); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* add r64 to r64 */ +void ADD64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x01 ); + ModRM( 3, from, to ); +} + +/* add imm32 to r32 */ +void ADD32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0, to); + if ( to == EAX) { + write8( 0x05 ); + } + else { + write8( 0x81 ); + ModRM( 3, 0, to ); + } + write32( from ); +} + +/* add imm32 to m32 */ +void ADD32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +// add imm32 to [r32+off] +void ADD32ItoRmOffset( x86IntRegType to, u32 from, int offset) +{ + RexB(0,to); + write8( 0x81 ); + WriteRmOffset(to,offset); + write32(from); +} + +/* add r32 to r32 */ +void ADD32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x01 ); + ModRM( 3, from, to ); +} + +/* add r32 to m32 */ +void ADD32RtoM(uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x01 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* add m32 to r32 */ +void ADD32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// add r16 to r16 +void ADD16RtoR( x86IntRegType to , x86IntRegType from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x03 ); + ModRM( 3, to, from ); +} + +/* add imm16 to r16 */ +void ADD16ItoR( x86IntRegType to, u16 from ) +{ + write8( 0x66 ); + RexB(0,to); + if ( to == EAX) + { + write8( 0x05 ); + } + else + { + write8( 0x81 ); + ModRM( 3, 0, to ); + } + write16( from ); +} + +/* add imm16 to m16 */ +void ADD16ItoM( uptr to, u16 from ) +{ + write8( 0x66 ); + write8( 0x81 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* add r16 to m16 */ +void ADD16RtoM(uptr to, x86IntRegType from ) +{ + write8( 0x66 ); + RexR(0,from); + write8( 0x01 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* add m16 to r16 */ +void ADD16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// add m8 to r8 +void ADD8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x02 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* adc imm32 to r32 */ +void ADC32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x15 ); + } + else { + write8( 0x81 ); + ModRM( 3, 2, to ); + } + write32( from ); +} + +/* adc imm32 to m32 */ +void ADC32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* adc r32 to r32 */ +void ADC32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x11 ); + ModRM( 3, from, to ); +} + +/* adc m32 to r32 */ +void ADC32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x13 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// adc r32 to m32 +void ADC32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x11 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* inc r32 */ +void INC32R( x86IntRegType to ) +{ + X86_64ASSERT(); + write8( 0x40 + to ); +} + +/* inc m32 */ +void INC32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* inc r16 */ +void INC16R( x86IntRegType to ) +{ + X86_64ASSERT(); + write8( 0x66 ); + write8( 0x40 + to ); +} + +/* inc m16 */ +void INC16M( u32 to ) +{ + write8( 0x66 ); + write8( 0xFF ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 4) ); +} + + +/* sub imm32 to r64 */ +void SUB64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x2D ); + } + else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write32( from ); +} + +/* sub r64 to r64 */ +void SUB64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x29 ); + ModRM( 3, from, to ); +} + +/* sub m64 to r64 */ +void SUB64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sub imm32 to r32 */ +void SUB32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x2D ); + } + else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write32( from ); +} + +/* sub imm32 to m32 */ +void SUB32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* sub r32 to r32 */ +void SUB32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x29 ); + ModRM( 3, from, to ); +} + +/* sub m32 to r32 */ +void SUB32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// sub r32 to m32 +void SUB32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x29 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// sub r16 to r16 +void SUB16RtoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x2b ); + ModRM( 3, to, from ); +} + +/* sub imm16 to r16 */ +void SUB16ItoR( x86IntRegType to, u16 from ) { + write8( 0x66 ); + RexB(0,to); + if ( to == EAX ) { + write8( 0x2D ); + } else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write16( from ); +} + +/* sub imm16 to m16 */ +void SUB16ItoM( uptr to, u16 from ) { + write8( 0x66 ); + write8( 0x81 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* sub m16 to r16 */ +void SUB16MtoR( x86IntRegType to, uptr from ) { + write8( 0x66 ); + RexR(0,to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sbb r64 to r64 */ +void SBB64RtoR( x86IntRegType to, x86IntRegType from ) { + RexRB(1, from,to); + write8( 0x19 ); + ModRM( 3, from, to ); +} + +/* sbb imm32 to r32 */ +void SBB32ItoR( x86IntRegType to, u32 from ) { + RexB(0,to); + if ( to == EAX ) { + write8( 0x1D ); + } else { + write8( 0x81 ); + ModRM( 3, 3, to ); + } + write32( from ); +} + +/* sbb imm32 to m32 */ +void SBB32ItoM( uptr to, u32 from ) { + write8( 0x81 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* sbb r32 to r32 */ +void SBB32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x19 ); + ModRM( 3, from, to ); +} + +/* sbb m32 to r32 */ +void SBB32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x1B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sbb r32 to m32 */ +void SBB32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x19 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* dec r32 */ +void DEC32R( x86IntRegType to ) +{ + X86_64ASSERT(); + write8( 0x48 + to ); +} + +/* dec m32 */ +void DEC32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* dec r16 */ +void DEC16R( x86IntRegType to ) +{ + X86_64ASSERT(); + write8( 0x66 ); + write8( 0x48 + to ); +} + +/* dec m16 */ +void DEC16M( u32 to ) +{ + write8( 0x66 ); + write8( 0xFF ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* mul eax by r32 to edx:eax */ +void MUL32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 4, from ); +} + +/* imul eax by r32 to edx:eax */ +void IMUL32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 5, from ); +} + +/* mul eax by m32 to edx:eax */ +void MUL32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* imul eax by m32 to edx:eax */ +void IMUL32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* imul r32 by r32 to r32 */ +void IMUL32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,to,from); + write16( 0xAF0F ); + ModRM( 3, to, from ); +} + +/* div eax by r32 to edx:eax */ +void DIV32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 6, from ); +} + +/* idiv eax by r32 to edx:eax */ +void IDIV32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 7, from ); +} + +/* div eax by m32 to edx:eax */ +void DIV32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* idiv eax by m32 to edx:eax */ +void IDIV32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +//////////////////////////////////// +// shifting instructions / +//////////////////////////////////// + +/* shl imm8 to r64 */ +void SHL64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1, to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 4, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shl cl to r64 */ +void SHL64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 4, to ); +} + +/* shr imm8 to r64 */ +void SHR64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1,to); + if ( from == 1 ) { + write8( 0xD1 ); + ModRM( 3, 5, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 5, to ); + write8( from ); +} + +/* shr cl to r64 */ +void SHR64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 5, to ); +} + +/* shl imm8 to r32 */ +void SHL32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0, to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shl imm8 to m32 */ +void SHL32ItoM( uptr to, u8 from ) +{ + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 4) ); + } + else + { + write8( 0xC1 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); + } +} + +/* shl cl to r32 */ +void SHL32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 4, to ); +} + +// shl imm8 to r16 +void SHL16ItoR( x86IntRegType to, u8 from ) +{ + write8(0x66); + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +// shl imm8 to r8 +void SHL8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD0 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC0 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shr imm8 to r32 */ +void SHR32ItoR( x86IntRegType to, u8 from ) { + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE8 | (to & 0x7) ); + } + else + { + write8( 0xC1 ); + ModRM( 3, 5, to ); + write8( from ); + } +} + +/* shr imm8 to m32 */ +void SHR32ItoM( uptr to, u8 from ) +{ + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 4) ); + } + else + { + write8( 0xC1 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); + } +} + +/* shr cl to r32 */ +void SHR32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 5, to ); +} + +// shr imm8 to r8 +void SHR8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD0 ); + write8( 0xE8 | (to & 0x7) ); + } + else + { + write8( 0xC0 ); + ModRM( 3, 5, to ); + write8( from ); + } +} + +/* sar imm8 to r64 */ +void SAR64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +/* sar cl to r64 */ +void SAR64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 7, to ); +} + +/* sar imm8 to r32 */ +void SAR32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +/* sar imm8 to m32 */ +void SAR32ItoM( uptr to, u8 from ) +{ + write8( 0xC1 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* sar cl to r32 */ +void SAR32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 7, to ); +} + +// sar imm8 to r16 +void SAR16ItoR( x86IntRegType to, u8 from ) +{ + write8(0x66); + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +void ROR32ItoR( x86IntRegType to,u8 from ) +{ + RexB(0,to); + if ( from == 1 ) { + write8( 0xd1 ); + write8( 0xc8 | to ); + } + else + { + write8( 0xc1 ); + write8( 0xc8 | to ); + write8( from ); + } +} + +void RCR32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) { + write8( 0xd1 ); + write8( 0xd8 | to ); + } + else + { + write8( 0xc1 ); + write8( 0xd8 | to ); + write8( from ); + } +} + +// shld imm8 to r32 +void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + RexRB(0,from,to); + write8( 0x0F ); + write8( 0xA4 ); + ModRM( 3, from, to ); + write8( shift ); +} + +// shrd imm8 to r32 +void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + RexRB(0,from,to); + write8( 0x0F ); + write8( 0xAC ); + ModRM( 3, from, to ); + write8( shift ); +} + +//////////////////////////////////// +// logical instructions / +//////////////////////////////////// + +/* or imm32 to r32 */ +void OR64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x0D ); + } else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write32( from ); +} + +/* or m64 to r64 */ +void OR64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* or r64 to r64 */ +void OR64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +// or r32 to m64 +void OR64RtoM(uptr to, x86IntRegType from ) +{ + RexR(1,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* or imm32 to r32 */ +void OR32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x0D ); + } + else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write32( from ); +} + +/* or imm32 to m32 */ +void OR32ItoM(uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* or r32 to r32 */ +void OR32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +/* or r32 to m32 */ +void OR32RtoM(uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* or m32 to r32 */ +void OR32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// or r16 to r16 +void OR16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,from,to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +// or imm16 to r16 +void OR16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) { + write8( 0x0D ); + } + else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write16( from ); +} + +// or imm16 to m316 +void OR16ItoM( uptr to, u16 from ) +{ + write8(0x66); + write8( 0x81 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* or m16 to r16 */ +void OR16MtoR( x86IntRegType to, uptr from ) +{ + write8(0x66); + RexR(0,to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// or r16 to m16 +void OR16RtoM( uptr to, x86IntRegType from ) +{ + write8(0x66); + RexR(0,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// or r8 to r8 +void OR8RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x08 ); + ModRM( 3, from, to ); +} + +// or r8 to m8 +void OR8RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x08 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// or imm8 to m8 +void OR8ItoM( uptr to, u8 from ) +{ + write8( 0x80 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +// or m8 to r8 +void OR8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x0A ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* xor imm32 to r64 */ +void XOR64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1,to); + if ( to == EAX ) { + write8( 0x35 ); + } else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write32( from ); +} + +/* xor r64 to r64 */ +void XOR64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor m64 to r64 */ +void XOR64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x33 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* xor r64 to m64 */ +void XOR64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* xor imm32 to r32 */ +void XOR32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x35 ); + } + else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write32( from ); +} + +/* xor imm32 to m32 */ +void XOR32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* xor r32 to r32 */ +void XOR32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor r16 to r16 */ +void XOR16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8( 0x66 ); + RexRB(0,from,to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor r32 to m32 */ +void XOR32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* xor m32 to r32 */ +void XOR32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x33 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// xor imm16 to r16 +void XOR16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) { + write8( 0x35 ); + } + else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write16( from ); +} + +// xor r16 to m16 +void XOR16RtoM( uptr to, x86IntRegType from ) +{ + write8(0x66); + RexR(0,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and imm32 to r64 */ +void AND64I32toR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x25 ); + } else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + } + write32( from ); +} + +/* and m64 to r64 */ +void AND64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* and r64 to m64 */ +void AND64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1, from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and r64 to r64 */ +void AND64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x21 ); + ModRM( 3, from, to ); +} + +/* and imm32 to m64 */ +void AND64I32toM( uptr to, u32 from ) +{ + Rex(1,0,0,0); + write8( 0x81 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* and imm32 to r32 */ +void AND32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x25 ); + } else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + } + write32( from ); +} + +/* and sign ext imm8 to r32 */ +void AND32I8toR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 3, 0x4, to ); + write8( from ); +} + +/* and imm32 to m32 */ +void AND32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* and sign ext imm8 to m32 */ +void AND32I8toM( uptr to, u8 from ) +{ + write8( 0x83 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* and r32 to r32 */ +void AND32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x21 ); + ModRM( 3, from, to ); +} + +/* and r32 to m32 */ +void AND32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m32 to r32 */ +void AND32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// and r16 to r16 +void AND16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x23 ); + ModRM( 3, to, from ); +} + +/* and imm16 to r16 */ +void AND16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) { + write8( 0x25 ); + } else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + } + write16( from ); +} + +/* and imm16 to m16 */ +void AND16ItoM( uptr to, u16 from ) +{ + write8( 0x8166 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* and r16 to m16 */ +void AND16RtoM( uptr to, x86IntRegType from ) +{ + write8( 0x66 ); + RexR(0,from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m16 to r16 */ +void AND16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* and imm8 to r8 */ +void AND8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x24 ); + } else { + write8( 0x80 ); + ModRM( 3, 0x4, to ); + } + write8( from ); +} + +/* and imm8 to m8 */ +void AND8ItoM( uptr to, u8 from ) +{ + write8( 0x80 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +// and r8 to r8 +void AND8RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,to,from); + write8( 0x22 ); + ModRM( 3, to, from ); +} + +/* and r8 to m8 */ +void AND8RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x20 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m8 to r8 */ +void AND8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x22 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* not r64 */ +void NOT64R( x86IntRegType from ) +{ + RexB(1, from); + write8( 0xF7 ); + ModRM( 3, 2, from ); +} + +/* not r32 */ +void NOT32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 2, from ); +} + +// not m32 +void NOT32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* neg r64 */ +void NEG64R( x86IntRegType from ) +{ + RexB(1, from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +/* neg r32 */ +void NEG32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +void NEG32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* neg r16 */ +void NEG16R( x86IntRegType from ) +{ + write8( 0x66 ); + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +//////////////////////////////////// +// jump instructions / +//////////////////////////////////// + +u8* JMP( uptr to ) { + uptr jump = ( x86Ptr - (s8*)to ) - 1; + + if ( jump > 0x7f ) { + assert( to <= 0xffffffff ); + return (u8*)JMP32( to ); + } else { + return (u8*)JMP8( to ); + } +} + +/* jmp rel8 */ +u8* JMP8( u8 to ) +{ + write8( 0xEB ); + write8( to ); + return x86Ptr - 1; +} + +/* jmp rel32 */ +u32* JMP32( uptr to ) +{ + assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff ); + write8( 0xE9 ); + write32( to ); + return (u32*)(x86Ptr - 4 ); +} + +/* jmp r32/r64 */ +void JMPR( x86IntRegType to ) +{ + RexB(0, to); + write8( 0xFF ); + ModRM( 3, 4, to ); +} + +// jmp m32 +void JMP32M( uptr to ) +{ + write8( 0xFF ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 4)); +} + +/* jp rel8 */ +u8* JP8( u8 to ) { + return J8Rel( 0x7A, to ); +} + +/* jnp rel8 */ +u8* JNP8( u8 to ) { + return J8Rel( 0x7B, to ); +} + +/* je rel8 */ +u8* JE8( u8 to ) { + return J8Rel( 0x74, to ); +} + +/* jz rel8 */ +u8* JZ8( u8 to ) +{ + return J8Rel( 0x74, to ); +} + +/* js rel8 */ +u8* JS8( u8 to ) +{ + return J8Rel( 0x78, to ); +} + +/* jns rel8 */ +u8* JNS8( u8 to ) +{ + return J8Rel( 0x79, to ); +} + +/* jg rel8 */ +u8* JG8( u8 to ) +{ + return J8Rel( 0x7F, to ); +} + +/* jge rel8 */ +u8* JGE8( u8 to ) +{ + return J8Rel( 0x7D, to ); +} + +/* jl rel8 */ +u8* JL8( u8 to ) +{ + return J8Rel( 0x7C, to ); +} + +/* ja rel8 */ +u8* JA8( u8 to ) +{ + return J8Rel( 0x77, to ); +} + +u8* JAE8( u8 to ) +{ + return J8Rel( 0x73, to ); +} + +/* jb rel8 */ +u8* JB8( u8 to ) +{ + return J8Rel( 0x72, to ); +} + +/* jbe rel8 */ +u8* JBE8( u8 to ) +{ + return J8Rel( 0x76, to ); +} + +/* jle rel8 */ +u8* JLE8( u8 to ) +{ + return J8Rel( 0x7E, to ); +} + +/* jne rel8 */ +u8* JNE8( u8 to ) +{ + return J8Rel( 0x75, to ); +} + +/* jnz rel8 */ +u8* JNZ8( u8 to ) +{ + return J8Rel( 0x75, to ); +} + +/* jng rel8 */ +u8* JNG8( u8 to ) +{ + return J8Rel( 0x7E, to ); +} + +/* jnge rel8 */ +u8* JNGE8( u8 to ) +{ + return J8Rel( 0x7C, to ); +} + +/* jnl rel8 */ +u8* JNL8( u8 to ) +{ + return J8Rel( 0x7D, to ); +} + +/* jnle rel8 */ +u8* JNLE8( u8 to ) +{ + return J8Rel( 0x7F, to ); +} + +/* jo rel8 */ +u8* JO8( u8 to ) +{ + return J8Rel( 0x70, to ); +} + +/* jno rel8 */ +u8* JNO8( u8 to ) +{ + return J8Rel( 0x71, to ); +} + +// jb rel8 +u16* JB16( u16 to ) +{ + return J16Rel( 0x82, to ); +} + +// jb rel32 +u32* JB32( u32 to ) +{ + return J32Rel( 0x82, to ); +} + +/* je rel32 */ +u32* JE32( u32 to ) +{ + return J32Rel( 0x84, to ); +} + +/* jz rel32 */ +u32* JZ32( u32 to ) +{ + return J32Rel( 0x84, to ); +} + +/* jg rel32 */ +u32* JG32( u32 to ) +{ + return J32Rel( 0x8F, to ); +} + +/* jge rel32 */ +u32* JGE32( u32 to ) +{ + return J32Rel( 0x8D, to ); +} + +/* jl rel32 */ +u32* JL32( u32 to ) +{ + return J32Rel( 0x8C, to ); +} + +/* jle rel32 */ +u32* JLE32( u32 to ) +{ + return J32Rel( 0x8E, to ); +} + +/* jae rel32 */ +u32* JAE32( u32 to ) +{ + return J32Rel( 0x83, to ); +} + +/* jne rel32 */ +u32* JNE32( u32 to ) +{ + return J32Rel( 0x85, to ); +} + +/* jnz rel32 */ +u32* JNZ32( u32 to ) +{ + return J32Rel( 0x85, to ); +} + +/* jng rel32 */ +u32* JNG32( u32 to ) +{ + return J32Rel( 0x8E, to ); +} + +/* jnge rel32 */ +u32* JNGE32( u32 to ) +{ + return J32Rel( 0x8C, to ); +} + +/* jnl rel32 */ +u32* JNL32( u32 to ) +{ + return J32Rel( 0x8D, to ); +} + +/* jnle rel32 */ +u32* JNLE32( u32 to ) +{ + return J32Rel( 0x8F, to ); +} + +/* jo rel32 */ +u32* JO32( u32 to ) +{ + return J32Rel( 0x80, to ); +} + +/* jno rel32 */ +u32* JNO32( u32 to ) +{ + return J32Rel( 0x81, to ); +} + +// js rel32 +u32* JS32( u32 to ) +{ + return J32Rel( 0x88, to ); +} + + +/* call func */ +void CALLFunc( uptr func ) +{ + func -= ( (uptr)x86Ptr + 5 ); + assert( (sptr)func <= 0x7fffffff && (sptr)func >= -0x7fffffff ); + CALL32(func); +} + +/* call rel32 */ +void CALL32( u32 to ) +{ + write8( 0xE8 ); + write32( to ); +} + +/* call r32 */ +void CALL32R( x86IntRegType to ) +{ + write8( 0xFF ); + ModRM( 3, 2, to ); +} + +/* call r64 */ +void CALL64R( x86IntRegType to ) +{ + RexB(0, to); + write8( 0xFF ); + ModRM( 3, 2, to ); +} + +/* call m32 */ +void CALL32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +//////////////////////////////////// +// misc instructions / +//////////////////////////////////// + +/* cmp imm32 to r64 */ +void CMP64I32toR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x3D ); + } + else { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write32( from ); +} + +/* cmp m64 to r64 */ +void CMP64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp r64 to r64 +void CMP64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp imm32 to r32 */ +void CMP32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x3D ); + } + else { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write32( from ); +} + +/* cmp imm32 to m32 */ +void CMP32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* cmp r32 to r32 */ +void CMP32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp m32 to r32 */ +void CMP32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp imm8 to [r32] +void CMP32I8toRm( x86IntRegType to, u8 from) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 0, 7, to ); + write8(from); +} + +// cmp imm32 to [r32+off] +void CMP32I8toRmOffset8( x86IntRegType to, u8 from, u8 off) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 1, 7, to ); + write8(off); + write8(from); +} + +// cmp imm8 to [r32] +void CMP32I8toM( uptr to, u8 from) +{ + write8( 0x83 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* cmp imm16 to r16 */ +void CMP16ItoR( x86IntRegType to, u16 from ) +{ + write8( 0x66 ); + RexB(0,to); + if ( to == EAX ) + { + write8( 0x3D ); + } + else + { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write16( from ); +} + +/* cmp imm16 to m16 */ +void CMP16ItoM( uptr to, u16 from ) +{ + write8( 0x66 ); + write8( 0x81 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* cmp r16 to r16 */ +void CMP16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8( 0x66 ); + RexRB(0,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp m16 to r16 */ +void CMP16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp imm8 to r8 +void CMP8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0x3C ); + } + else + { + write8( 0x80 ); + ModRM( 3, 7, to ); + } + write8( from ); +} + +// cmp m8 to r8 +void CMP8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x3A ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* test imm32 to r32 */ +void TEST32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA9 ); + } + else + { + write8( 0xF7 ); + ModRM( 3, 0, to ); + } + write32( from ); +} + +void TEST32ItoM( uptr to, u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* test r32 to r32 */ +void TEST32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x85 ); + ModRM( 3, from, to ); +} + +// test imm32 to [r32] +void TEST32ItoRm( x86IntRegType to, u32 from ) +{ + RexB(0,to); + write8( 0xF7 ); + ModRM( 0, 0, to ); + write32(from); +} + +// test imm16 to r16 +void TEST16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA9 ); + } + else + { + write8( 0xF7 ); + ModRM( 3, 0, to ); + } + write16( from ); +} + +// test r16 to r16 +void TEST16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,from,to); + write16( 0x85 ); + ModRM( 3, from, to ); +} + +// test imm8 to r8 +void TEST8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA8 ); + } + else + { + write8( 0xF6 ); + ModRM( 3, 0, to ); + } + write8( from ); +} + +// test imm8 to r8 +void TEST8ItoM( uptr to, u8 from ) +{ + write8( 0xF6 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* sets r8 */ +void SETS8R( x86IntRegType to ) +{ + SET8R( 0x98, to ); +} + +/* setl r8 */ +void SETL8R( x86IntRegType to ) +{ + SET8R( 0x9C, to ); +} + +// setge r8 +void SETGE8R( x86IntRegType to ) { SET8R(0x9d, to); } +// setg r8 +void SETG8R( x86IntRegType to ) { SET8R(0x9f, to); } +// seta r8 +void SETA8R( x86IntRegType to ) { SET8R(0x97, to); } +// setae r8 +void SETAE8R( x86IntRegType to ) { SET8R(0x99, to); } +/* setb r8 */ +void SETB8R( x86IntRegType to ) { SET8R( 0x92, to ); } +/* setb r8 */ +void SETNZ8R( x86IntRegType to ) { SET8R( 0x95, to ); } +// setz r8 +void SETZ8R( x86IntRegType to ) { SET8R(0x94, to); } +// sete r8 +void SETE8R( x86IntRegType to ) { SET8R(0x94, to); } + +/* push imm32 */ +void PUSH32I( u32 from ) +{ + X86_64ASSERT(); + write8( 0x68 ); + write32( from ); +} + +#ifdef __x86_64__ + +/* push r32 */ +void PUSH32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0x51 | from ); +} + +/* push m32 */ +void PUSH32M( uptr from ) +{ + write8( 0xFF ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pop r64 */ +void POP64R( x86IntRegType from ) { + RexB(0,from); + write8( 0x59 | from ); +} + +void PUSHR(x86IntRegType from) { PUSH32R(from); } +void POPR(x86IntRegType from) { POP64R(from); } + +#else + +/* push r32 */ +void PUSH32R( x86IntRegType from ) { write8( 0x50 | from ); } + +/* push m32 */ +void PUSH32M( u32 from ) +{ + write8( 0xFF ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pop r32 */ +void POP32R( x86IntRegType from ) { write8( 0x58 | from ); } + +/* pushad */ +void PUSHA32( void ) { write8( 0x60 ); } + +/* popad */ +void POPA32( void ) { write8( 0x61 ); } + +void PUSHR(x86IntRegType from) { PUSH32R(from); } +void POPR(x86IntRegType from) { POP32R(from); } + +#endif + + +/* pushfd */ +void PUSHFD( void ) { write8( 0x9C ); } +/* popfd */ +void POPFD( void ) { write8( 0x9D ); } + +void RET( void ) { write8( 0xC3 ); } +void RET2( void ) { write16( 0xc3f3 ); } + +void CBW( void ) { write16( 0x9866 ); } +void CWD( void ) { write8( 0x98 ); } +void CDQ( void ) { write8( 0x99 ); } +void CWDE() { write8(0x98); } + +#ifdef __x86_64__ +void CDQE( void ) { RexR(1,0); write8( 0x98 ); } +#endif + +void LAHF() { write8(0x9f); } +void SAHF() { write8(0x9e); } + +void BT32ItoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0xBA0F ); + write8( 0xE0 | to ); + write8( from ); +} + +void BSRRtoR(x86IntRegType to, x86IntRegType from) +{ + write16( 0xBD0F ); + ModRM( 3, from, to ); +} + +void BSWAP32R( x86IntRegType to ) +{ + write8( 0x0F ); + write8( 0xC8 + to ); +} + +// to = from + offset +void LEA16RtoR(x86IntRegType to, x86IntRegType from, u16 offset) +{ + write8(0x66); + LEA32RtoR(to, from, offset); +} + +void LEA32RtoR(x86IntRegType to, x86IntRegType from, u32 offset) +{ + RexRB(0,to,from); + write8(0x8d); + + if( (from&7) == ESP ) { + if( offset == 0 ) { + ModRM(1, to, from); + write8(0x24); + } + else if( offset < 128 ) { + ModRM(1, to, from); + write8(0x24); + write8(offset); + } + else { + ModRM(2, to, from); + write8(0x24); + write32(offset); + } + } + else { + if( offset == 0 && from != EBP && from!=ESP ) { + ModRM(0, to, from); + } + else if( offset < 128 ) { + ModRM(1, to, from); + write8(offset); + } + else { + ModRM(2, to, from); + write32(offset); + } + } +} + +// to = from0 + from1 +void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) +{ + write8(0x66); + LEA32RRtoR(to, from0, from1); +} + +void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) +{ + RexRXB(0, to, from0, from1); + write8(0x8d); + + if( (from1&7) == EBP ) { + ModRM(1, to, 4); + ModRM(0, from0, from1); + write8(0); + } + else { + ModRM(0, to, 4); + ModRM(0, from0, from1); + } +} + +// to = from << scale (max is 3) +void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale) +{ + write8(0x66); + LEA32RStoR(to, from, scale); +} + +void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale) +{ + if( to == from ) { + SHL32ItoR(to, scale); + return; + } + + if( from != ESP ) { + RexRXB(0,to,from,0); + write8(0x8d); + ModRM(0, to, 4); + ModRM(scale, from, 5); + write32(0); + } + else { + assert( to != ESP ); + MOV32RtoR(to, from); + LEA32RStoR(to, to, scale); + } +} + +#endif diff --git a/pcsx2/x86/ix86/ix86.h b/pcsx2/x86/ix86/ix86.h new file mode 100644 index 0000000000..cebaca2a13 --- /dev/null +++ b/pcsx2/x86/ix86/ix86.h @@ -0,0 +1,1810 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* + * ix86 definitions v0.6.2 + * Authors: linuzappz + * alexey silinov + * goldfinger + * shadow < shadow@pcsx2.net > + */ + +#ifndef __IX86_H__ +#define __IX86_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "PS2Etypes.h" // Basic types header + +#ifdef __x86_64__ +#define XMMREGS 16 +#define X86REGS 16 +#else +#define XMMREGS 8 +#define X86REGS 8 +#endif + +#define MMXREGS 8 + +#define SIB 4 +#define DISP32 5 + +// general types +typedef int x86IntRegType; +#define EAX 0 +#define EBX 3 +#define ECX 1 +#define EDX 2 +#define ESI 6 +#define EDI 7 +#define EBP 5 +#define ESP 4 + +#ifdef __x86_64__ +#define RAX 0 +#define RBX 3 +#define RCX 1 +#define RDX 2 +#define RSI 6 +#define RDI 7 +#define RBP 5 +#define RSP 4 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define X86_TEMP RAX // don't allocate anything + +#ifdef _MSC_VER +extern x86IntRegType g_x86savedregs[8]; +extern x86IntRegType g_x86tempregs[6]; +#else +extern x86IntRegType g_x86savedregs[6]; +extern x86IntRegType g_x86tempregs[8]; +#endif + +extern x86IntRegType g_x86allregs[14]; // all registers that can be used by the recs +extern x86IntRegType g_x868bitregs[11]; +extern x86IntRegType g_x86non8bitregs[3]; + +#ifdef _MSC_VER +#define X86ARG1 RCX +#define X86ARG2 RDX +#define X86ARG3 R8 +#define X86ARG4 R9 +#else +#define X86ARG1 RDI +#define X86ARG2 RSI +#define X86ARG3 RDX +#define X86ARG4 RCX +#endif + +#else + +#define X86ARG1 EAX +#define X86ARG2 ECX +#define X86ARG3 EDX +#define X86ARG4 EBX + +#endif // __x86_64__ + +#define MM0 0 +#define MM1 1 +#define MM2 2 +#define MM3 3 +#define MM4 4 +#define MM5 5 +#define MM6 6 +#define MM7 7 + +typedef int x86MMXRegType; + +#define XMM0 0 +#define XMM1 1 +#define XMM2 2 +#define XMM3 3 +#define XMM4 4 +#define XMM5 5 +#define XMM6 6 +#define XMM7 7 +#define XMM8 8 +#define XMM9 9 +#define XMM10 10 +#define XMM11 11 +#define XMM12 12 +#define XMM13 13 +#define XMM14 14 +#define XMM15 15 + +typedef int x86SSERegType; + +typedef enum +{ + XMMT_INT = 0, // integer (sse2 only) + XMMT_FPS = 1, // floating point + //XMMT_FPD = 3, // double +} XMMSSEType; + +extern XMMSSEType g_xmmtypes[XMMREGS]; + +void cpudetectInit( void );//this is all that needs to be called and will fill up the below structs + +//cpu capabilities structure +typedef struct { + u32 hasFloatingPointUnit; + u32 hasVirtual8086ModeEnhancements; + u32 hasDebuggingExtensions; + u32 hasPageSizeExtensions; + u32 hasTimeStampCounter; + u32 hasModelSpecificRegisters; + u32 hasPhysicalAddressExtension; + u32 hasCOMPXCHG8BInstruction; + u32 hasAdvancedProgrammableInterruptController; + u32 hasSEPFastSystemCall; + u32 hasMemoryTypeRangeRegisters; + u32 hasPTEGlobalFlag; + u32 hasMachineCheckArchitecture; + u32 hasConditionalMoveAndCompareInstructions; + u32 hasFGPageAttributeTable; + u32 has36bitPageSizeExtension; + u32 hasProcessorSerialNumber; + u32 hasCFLUSHInstruction; + u32 hasDebugStore; + u32 hasACPIThermalMonitorAndClockControl; + u32 hasMultimediaExtensions; + u32 hasFastStreamingSIMDExtensionsSaveRestore; + u32 hasStreamingSIMDExtensions; + u32 hasStreamingSIMD2Extensions; + u32 hasSelfSnoop; + u32 hasHyperThreading; + u32 hasThermalMonitor; + u32 hasIntel64BitArchitecture; + u32 hasStreamingSIMD3Extensions; + u32 hasStreamingSIMD4Extensions; + //that is only for AMDs + u32 hasMultimediaExtensionsExt; + u32 hasAMD64BitArchitecture; + u32 has3DNOWInstructionExtensionsExt; + u32 has3DNOWInstructionExtensions; +} CAPABILITIES; + +extern CAPABILITIES cpucaps; + +typedef struct { + + u32 x86Family; // Processor Family + u32 x86Model; // Processor Model + u32 x86PType; // Processor Type + u32 x86StepID; // Stepping ID + u32 x86Flags; // Feature Flags + u32 x86Flags2; // More Feature Flags + u32 x86EFlags; // Extended Feature Flags + //all the above returns hex values + s8 x86ID[16]; // Vendor ID //the vendor creator (in %s) + s8 x86Type[20]; //cpu type in char format //the cpu type (in %s) + s8 x86Fam[50]; // family in char format //the original cpu name string (in %s) + u32 cpuspeed; // speed of cpu //this will give cpu speed (in %d) +} CPUINFO; + +extern CPUINFO cpuinfo; + +extern s8 *x86Ptr; +extern u8 *j8Ptr[32]; +extern u32 *j32Ptr[32]; + + +#ifdef __x86_64__ +#define X86_64ASSERT() assert(0) +#define MEMADDR(addr, oplen) ((addr) - ((u64)x86Ptr + ((u64)oplen))) +#else +#define X86_64ASSERT() +#define MEMADDR(addr, oplen) (addr) +#endif + +#ifdef __x86_64__ +#define Rex( w, r, x, b ) write8( 0x40 | ((w) << 3) | ((r) << 2) | ((x) << 1) | (b) ); +#define RexR(w, reg) if( w||(reg)>=8 ) { Rex(w, (reg)>=8, 0, 0); } +#define RexB(w, base) if( w||(base)>=8 ) { Rex(w, 0, 0, (base)>=8); } +#define RexRB(w, reg, base) if( w || (reg) >= 8 || (base)>=8 ) { Rex(w, (reg)>=8, 0, (base)>=8); } +#define RexRXB(w, reg, index, base) if( w||(reg) >= 8 || (index) >= 8 || (base) >= 8 ) { \ + Rex(w, (reg)>=8, (index)>=8, (base)>=8); \ + } +#else +#define Rex(w,r,x,b) assert(0); +#define RexR(w, reg) if( w||(reg)>=8 ) assert(0); +#define RexB(w, base) if( w||(base)>=8 ) assert(0); +#define RexRB(w, reg, base) if( w||(reg) >= 8 || (base)>=8 ) assert(0); +#define RexRXB(w, reg, index, base) if( w||(reg) >= 8 || (index) >= 8 || (base) >= 8 ) assert(0); +#endif + +void write8( int val ); +void write16( int val ); +void write32( u32 val ); +void write64( u64 val ); + + +void x86SetPtr( char *ptr ); +void x86Shutdown( void ); + +void x86SetJ8( u8 *j8 ); +void x86SetJ8A( u8 *j8 ); +void x86SetJ16( u16 *j16 ); +void x86SetJ16A( u16 *j16 ); +void x86SetJ32( u32 *j32 ); +void x86SetJ32A( u32 *j32 ); + +void x86Align( int bytes ); +u64 GetCPUTick( void ); + +// General Helper functions +void ModRM( int mod, int rm, int reg ); +void SibSB( int ss, int rm, int index ); +void SET8R( int cc, int to ); +u8* J8Rel( int cc, int to ); +u32* J32Rel( int cc, u32 to ); +void CMOV32RtoR( int cc, int to, int from ); +void CMOV32MtoR( int cc, int to, uptr from ); + +//****************** +// IX86 intructions +//****************** + +// +// * scale values: +// * 0 - *1 +// * 1 - *2 +// * 2 - *4 +// * 3 - *8 +// + +void STC( void ); +void CLC( void ); + +//////////////////////////////////// +// mov instructions // +//////////////////////////////////// + +// mov r64 to r64 +void MOV64RtoR( x86IntRegType to, x86IntRegType from ); +// mov r64 to m64 +void MOV64RtoM( uptr to, x86IntRegType from ); +// mov m64 to r64 +void MOV64MtoR( x86IntRegType to, uptr from ); +// mov sign ext imm32 to m64 +void MOV64I32toM( uptr to, u32 from ); +// mov sign ext imm32 to r64 +void MOV64I32toR( x86IntRegType to, s32 from); +// mov imm64 to r64 +void MOV64ItoR( x86IntRegType to, u64 from); +// mov imm64 to [r64+off] +void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset); +// mov [r64+offset] to r64 +void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ); +// mov [r64][r64*scale] to r64 +void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); +// mov r64 to [r64+offset] +void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ); +// mov r64 to [r64][r64*scale] +void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); + +// mov r32 to r32 +void MOV32RtoR( x86IntRegType to, x86IntRegType from ); +// mov r32 to m32 +void MOV32RtoM( uptr to, x86IntRegType from ); +// mov m32 to r32 +void MOV32MtoR( x86IntRegType to, uptr from ); +// mov [r32] to r32 +void MOV32RmtoR( x86IntRegType to, x86IntRegType from ); +void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ); +// mov [r32][r32< subtract ST(0) from ST(1), store in ST(1) and POP stack +void FSUBP( void ); +// fmul ST(src) to fpu reg stack ST(0) +void FMUL32Rto0( x86IntRegType src ); +// fmul ST(0) to fpu reg stack ST(src) +void FMUL320toR( x86IntRegType src ); +// fdiv ST(src) to fpu reg stack ST(0) +void FDIV32Rto0( x86IntRegType src ); +// fdiv ST(0) to fpu reg stack ST(src) +void FDIV320toR( x86IntRegType src ); +// fdiv ST(0) to fpu reg stack ST(src), pop stack, store in ST(src) +void FDIV320toRP( x86IntRegType src ); + +// fadd m32 to fpu reg stack +void FADD32( u32 from ); +// fsub m32 to fpu reg stack +void FSUB32( u32 from ); +// fmul m32 to fpu reg stack +void FMUL32( u32 from ); +// fdiv m32 to fpu reg stack +void FDIV32( u32 from ); +// fcomi st, st( i) +void FCOMI( x86IntRegType src ); +// fcomip st, st( i) +void FCOMIP( x86IntRegType src ); +// fucomi st, st( i) +void FUCOMI( x86IntRegType src ); +// fucomip st, st( i) +void FUCOMIP( x86IntRegType src ); +// fcom m32 to fpu reg stack +void FCOM32( u32 from ); +// fabs fpu reg stack +void FABS( void ); +// fsqrt fpu reg stack +void FSQRT( void ); +// ftan fpu reg stack +void FPATAN( void ); +// fsin fpu reg stack +void FSIN( void ); +// fchs fpu reg stack +void FCHS( void ); + +// fcmovb fpu reg to fpu reg stack +void FCMOVB32( x86IntRegType from ); +// fcmove fpu reg to fpu reg stack +void FCMOVE32( x86IntRegType from ); +// fcmovbe fpu reg to fpu reg stack +void FCMOVBE32( x86IntRegType from ); +// fcmovu fpu reg to fpu reg stack +void FCMOVU32( x86IntRegType from ); +// fcmovnb fpu reg to fpu reg stack +void FCMOVNB32( x86IntRegType from ); +// fcmovne fpu reg to fpu reg stack +void FCMOVNE32( x86IntRegType from ); +// fcmovnbe fpu reg to fpu reg stack +void FCMOVNBE32( x86IntRegType from ); +// fcmovnu fpu reg to fpu reg stack +void FCMOVNU32( x86IntRegType from ); +void FCOMP32( u32 from ); +void FNSTSWtoAX( void ); + +// probably a little extreme here, but x86-64 should NOT use MMX +#ifdef __x86_64__ + +#define MMXONLY(code) + +#else + +#define MMXONLY(code) code + +//****************** +// MMX instructions +//****************** + +// r64 = mm + +// movq m64 to r64 +void MOVQMtoR( x86MMXRegType to, uptr from ); +// movq r64 to m64 +void MOVQRtoM( uptr to, x86MMXRegType from ); + +// pand r64 to r64 +void PANDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pand m64 to r64 ; +void PANDMtoR( x86MMXRegType to, uptr from ); +// pandn r64 to r64 +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pandn r64 to r64 +void PANDNMtoR( x86MMXRegType to, uptr from ); +// por r64 to r64 +void PORRtoR( x86MMXRegType to, x86MMXRegType from ); +// por m64 to r64 +void PORMtoR( x86MMXRegType to, uptr from ); +// pxor r64 to r64 +void PXORRtoR( x86MMXRegType to, x86MMXRegType from ); +// pxor m64 to r64 +void PXORMtoR( x86MMXRegType to, uptr from ); + +// psllq r64 to r64 +void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psllq m64 to r64 +void PSLLQMtoR( x86MMXRegType to, uptr from ); +// psllq imm8 to r64 +void PSLLQItoR( x86MMXRegType to, u8 from ); +// psrlq r64 to r64 +void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psrlq m64 to r64 +void PSRLQMtoR( x86MMXRegType to, uptr from ); +// psrlq imm8 to r64 +void PSRLQItoR( x86MMXRegType to, u8 from ); + +// paddusb r64 to r64 +void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusb m64 to r64 +void PADDUSBMtoR( x86MMXRegType to, uptr from ); +// paddusw r64 to r64 +void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusw m64 to r64 +void PADDUSWMtoR( x86MMXRegType to, uptr from ); + +// paddb r64 to r64 +void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddb m64 to r64 +void PADDBMtoR( x86MMXRegType to, uptr from ); +// paddw r64 to r64 +void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddw m64 to r64 +void PADDWMtoR( x86MMXRegType to, uptr from ); +// paddd r64 to r64 +void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddd m64 to r64 +void PADDDMtoR( x86MMXRegType to, uptr from ); +void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ); + +// paddq m64 to r64 (sse2 only?) +void PADDQMtoR( x86MMXRegType to, uptr from ); +// paddq r64 to r64 (sse2 only?) +void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ); + +void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ); + +void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBDMtoR( x86MMXRegType to, uptr from ); + +// psubq m64 to r64 (sse2 only?) +void PSUBQMtoR( x86MMXRegType to, uptr from ); +// psubq r64 to r64 (sse2 only?) +void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ); + +// pmuludq m64 to r64 (sse2 only?) +void PMULUDQMtoR( x86MMXRegType to, uptr from ); +// pmuludq r64 to r64 (sse2 only?) +void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ); + +void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQDMtoR( x86MMXRegType to, uptr from ); +void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTDMtoR( x86MMXRegType to, uptr from ); +void PSRLWItoR( x86MMXRegType to, u8 from ); +void PSRLDItoR( x86MMXRegType to, u8 from ); +void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSLLWItoR( x86MMXRegType to, u8 from ); +void PSLLDItoR( x86MMXRegType to, u8 from ); +void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSRAWItoR( x86MMXRegType to, u8 from ); +void PSRADItoR( x86MMXRegType to, u8 from ); +void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ); +void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ); +void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ); +void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ); +void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ); +void MOVQ64ItoR( x86MMXRegType reg, u64 i ); //Prototype.Todo add all consts to end of block.not after jr $+8 +void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ); +void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ); +void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); +void MOVDMtoMMX( x86MMXRegType to, uptr from ); +void MOVDMMXtoM( uptr to, x86MMXRegType from ); +void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ); +void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ); +void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ); +void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ); +void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ); +void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); +void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ); +void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8); +void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8); +void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from); + +// emms +void EMMS( void ); + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word 64bits +//********************************************************************************** +void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from); +void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from); + +void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from); + +void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); +void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); + +#endif // !__x86_64__ + +//********************* +// SSE instructions * +//********************* +void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ); +void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ); + +void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ); +void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ); +void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ); + +void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ); +void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ); +void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ); +void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ); +void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ); +void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVLPSRtoRm( x86SSERegType to, x86IntRegType from ); +void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); + +void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); +void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ); +void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ); + +void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); + +void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); +void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); + +void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ); + +void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +#ifndef __x86_64__ +void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); +void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); +void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ); +void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ); +void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ); +#endif +void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ); +void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from); +void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from); +void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from); +void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from); + +void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); +void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ); +void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +// VectorPath +void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); + +void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); +void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); + +void SSE_STMXCSR( uptr from ); +void SSE_LDMXCSR( uptr from ); + + +//********************* +// SSE 2 Instructions* +//********************* +void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from); +void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from); + +void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from); +void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from); + +void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); +void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ); + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word +//********************************************************************************** +void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from); + +//**********************************************************************************/ +//PUNPCKHWD: Unpack 16bit high +//********************************************************************************** +void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from); + +// mult by half words +void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from); +void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from); + + +//**********************************************************************************/ +//PMOVMSKB: Create 16bit mask from signs of 8bit integers +//********************************************************************************** +void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from); + +void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from); +void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from); + +//**********************************************************************************/ +//PEXTRW,PINSRW: Packed Extract/Insert Word * +//********************************************************************************** +void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ); +void SSE_PINSRW_R32_to_XMM(x86SSERegType from, x86IntRegType to, u8 imm8 ); + + +//**********************************************************************************/ +//PSUBx: Subtract Packed Integers * +//********************************************************************************** +void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ); +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PCMPxx: Compare Packed Integers * +//********************************************************************************** +void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ); +void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ); +//**********************************************************************************/ +//MOVD: Move Dword(32bit) to /from XMM reg * +//********************************************************************************** +void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); +void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); +void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ); +void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); +void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +#ifdef __x86_64__ +void SSE2_MOVQ_XMM_to_R( x86IntRegType to, x86SSERegType from ); +void SSE2_MOVQ_R_to_XMM( x86SSERegType to, x86IntRegType from ); +#endif + +//**********************************************************************************/ +//POR : SSE Bitwise OR * +//********************************************************************************** +void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ); + +void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from); + +void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from); +void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from); + +// SSE4.1 + +#ifndef _MM_MK_INSERTPS_NDX +#define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField)<<6) | ((dstField)<<4) | (zeroMask)) +#endif + +void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); +void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8); +void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); +void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8); +void SSE4_BLENDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); + +//********************* +// SSE-X - uses both SSE,SSE2 code and tries to keep consistensies between the data +// Uses g_xmmtypes to infer the correct type. +//********************* +void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ); +void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ); +void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); +void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); +void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); +void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); + +void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +//********************* +// 3DNOW instructions * +//********************* +void FEMMS( void ); +void PFCMPEQMtoR( x86IntRegType to, uptr from ); +void PFCMPGTMtoR( x86IntRegType to, uptr from ); +void PFCMPGEMtoR( x86IntRegType to, uptr from ); +void PFADDMtoR( x86IntRegType to, uptr from ); +void PFADDRtoR( x86IntRegType to, x86IntRegType from ); +void PFSUBMtoR( x86IntRegType to, uptr from ); +void PFSUBRtoR( x86IntRegType to, x86IntRegType from ); +void PFMULMtoR( x86IntRegType to, uptr from ); +void PFMULRtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPMtoR( x86IntRegType to, uptr from ); +void PFRCPRtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ); +void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ); +void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ); +void PF2IDMtoR( x86IntRegType to, uptr from ); +void PF2IDRtoR( x86IntRegType to, x86IntRegType from ); +void PI2FDMtoR( x86IntRegType to, uptr from ); +void PI2FDRtoR( x86IntRegType to, x86IntRegType from ); +void PFMAXMtoR( x86IntRegType to, uptr from ); +void PFMAXRtoR( x86IntRegType to, x86IntRegType from ); +void PFMINMtoR( x86IntRegType to, uptr from ); +void PFMINRtoR( x86IntRegType to, x86IntRegType from ); + +void SSE2EMU_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from); +void SSE2EMU_MOVQ_M64_to_XMM( x86SSERegType to, uptr from); +void SSE2EMU_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from); +void SSE2EMU_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +void SSE2EMU_MOVD_XMM_to_RmOffset(x86IntRegType to, x86SSERegType from, int offset ); + +#ifndef __x86_64__ +void SSE2EMU_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); +void SSE2EMU_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); +#endif + +/* SSE2 emulated functions for SSE CPU's by kekko*/ + +void SSE2EMU_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SSE2EMU_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); +void SSE2EMU_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +void SSE2EMU_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); +void SSE2EMU_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +void SSE2EMU_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); + +//////////////////////////////////////////////////// +#ifdef _DEBUG +#define WRITECHECK() CheckX86Ptr() +#else +#define WRITECHECK() +#endif + +#define write8(val ) { \ + *(u8*)x86Ptr = (u8)val; \ + x86Ptr++; \ +} \ + +#define write16(val ) \ +{ \ + *(u16*)x86Ptr = (u16)val; \ + x86Ptr += 2; \ +} \ + +#define write24(val ) \ +{ \ + *(u8*)x86Ptr = (u8)(val & 0xff); \ + x86Ptr++; \ + *(u8*)x86Ptr = (u8)((val >> 8) & 0xff); \ + x86Ptr++; \ + *(u8*)x86Ptr = (u8)((val >> 16) & 0xff); \ + x86Ptr++; \ +} \ + +#define write32( val ) \ +{ \ + *(u32*)x86Ptr = val; \ + x86Ptr += 4; \ +} \ + +#ifdef __cplusplus +} +#endif + +#endif // __IX86_H__ diff --git a/pcsx2/x86/ix86/ix86_3dnow.c b/pcsx2/x86/ix86/ix86_3dnow.c new file mode 100644 index 0000000000..5a92ff48bb --- /dev/null +++ b/pcsx2/x86/ix86/ix86_3dnow.c @@ -0,0 +1,205 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "ix86.h" + +/**********************/ +/* 3DNOW instructions */ +/**********************/ + +/* femms */ +void FEMMS( void ) +{ + write16( 0x0E0F ); +} + +void PFCMPEQMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xB0 ); +} + +void PFCMPGTMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xA0 ); +} + +void PFCMPGEMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x90 ); +} + +void PFADDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x9E ); +} + +void PFADDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x9E ); +} + +void PFSUBMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x9A ); +} + +void PFSUBRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x9A ); +} + +void PFMULMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xB4 ); +} + +void PFMULRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xB4 ); +} + +void PFRCPMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x96 ); +} + +void PFRCPRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x96 ); +} + +void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA6 ); +} + +void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xB6 ); +} + +void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x97 ); +} + +void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA7 ); +} + +void PF2IDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x1D ); +} + +void PF2IDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x1D ); +} + +void PI2FDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x0D ); +} + +void PI2FDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x0D ); +} + +void PFMAXMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xA4 ); +} + +void PFMAXRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA4 ); +} + +void PFMINMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x94 ); +} + +void PFMINRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x94 ); +} + +#endif diff --git a/pcsx2/x86/ix86/ix86_cpudetect.c b/pcsx2/x86/ix86/ix86_cpudetect.c new file mode 100644 index 0000000000..ecdd74e035 --- /dev/null +++ b/pcsx2/x86/ix86/ix86_cpudetect.c @@ -0,0 +1,317 @@ +/* Cpudetection lib + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#if defined (_WIN32) +#include +#endif + +#include +#include + +#include "ix86.h" + +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + void __cpuid(int* CPUInfo, int InfoType); + unsigned __int64 __rdtsc(); + + #pragma intrinsic(__cpuid) + #pragma intrinsic(__rdtsc) + +#endif + +CAPABILITIES cpucaps; +CPUINFO cpuinfo; + +#define cpuid(cmd,a,b,c,d) \ + __asm__ __volatile__("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) : "0" (cmd)) + +extern s32 iCpuId( u32 cmd, u32 *regs ) +{ + int flag=1; + +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + __cpuid( regs, cmd ); + + return 0; + +#elif defined (_MSC_VER) + +#ifdef __x86_64__ + assert(0); +#else // __x86_64__ + __asm + { + push ebx; + push edi; + + pushfd; + pop eax; + mov edx, eax; + xor eax, 1 << 21; + push eax; + popfd; + pushfd; + pop eax; + xor eax, edx; + mov flag, eax; + } + if ( ! flag ) + { + return -1; + } + + __asm + { + mov eax, cmd; + cpuid; + mov edi, [regs] + mov [edi], eax; + mov [edi+4], ebx; + mov [edi+8], ecx; + mov [edi+12], edx; + + pop edi; + pop ebx; + } +#endif // __x86_64__ + return 0; + + +#else + +#ifndef __x86_64__ + // see if we can use cpuid + __asm__ __volatile__ ( + "sub $0x18, %%esp\n" + "pushf\n" + "pop %%eax\n" + "mov %%eax, %%edx\n" + "xor $0x200000, %%eax\n" + "push %%eax\n" + "popf\n" + "pushf\n" + "pop %%eax\n" + "xor %%edx, %%eax\n" + "mov %%eax, %0\n" + "add $0x18, %%esp\n" + "cmpl $0x0,%%eax\n" + "jne 1f\n" + "mov $0xffffffff, %%eax\n" + "leave\n" + "ret\n" + "1:\n" + : "=r"(flag) : + ); +#endif + + cpuid(cmd, regs[0], regs[1], regs[2], regs[3]); + return 0; + +#endif // _MSC_VER +} + +u64 GetCPUTick( void ) +{ +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + return __rdtsc(); + +#elif defined(__MSCW32__) && !defined(__x86_64__) + + __asm rdtsc; + +#else + + u32 _a, _d; + __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d)); + return (u64)_a | ((u64)_d << 32); + +#endif +} + +#if defined __LINUX__ + +#include +#include + +#endif + +s64 CPUSpeedHz( unsigned int time ) +{ + s64 timeStart, + timeStop; + s64 startTick, + endTick; + s64 overhead; + + if( ! cpucaps.hasTimeStampCounter ) + { + return 0; //check if function is supported + } + + overhead = GetCPUTick() - GetCPUTick(); + + timeStart = timeGetTime( ); + while( timeGetTime( ) == timeStart ) + { + timeStart = timeGetTime( ); + } + for(;;) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > 1 ) + { + startTick = GetCPUTick( ); + break; + } + } + + timeStart = timeStop; + for(;;) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > time ) + { + endTick = GetCPUTick( ); + break; + } + } + + return (s64)( ( endTick - startTick ) + ( overhead ) ); +} + +//////////////////////////////////////////////////// +int arr[] = {0x65746e49, 0x2952286c, 0x726f4320, 0x4d542865, + 0x51203229,0x20646175,0x20555043,0x20202020 , + 0x20202020,0x20402020,0x36362e32,0x7a4847}; + +void cpudetectInit( void ) +{ + u32 regs[ 4 ]; + u32 cmds; + int cputype=0; // Cpu type + //AMD 64 STUFF + u32 x86_64_8BITBRANDID; + u32 x86_64_12BITBRANDID; + memset( cpuinfo.x86ID, 0, sizeof( cpuinfo.x86ID ) ); + cpuinfo.x86Family = 0; + cpuinfo.x86Model = 0; + cpuinfo.x86PType = 0; + cpuinfo.x86StepID = 0; + cpuinfo.x86Flags = 0; + cpuinfo.x86EFlags = 0; + + if ( iCpuId( 0, regs ) == -1 ) return; + + cmds = regs[ 0 ]; + ((u32*)cpuinfo.x86ID)[ 0 ] = regs[ 1 ]; + ((u32*)cpuinfo.x86ID)[ 1 ] = regs[ 3 ]; + ((u32*)cpuinfo.x86ID)[ 2 ] = regs[ 2 ]; + if ( cmds >= 0x00000001 ) + { + if ( iCpuId( 0x00000001, regs ) != -1 ) + { + cpuinfo.x86StepID = regs[ 0 ] & 0xf; + cpuinfo.x86Model = (regs[ 0 ] >> 4) & 0xf; + cpuinfo.x86Family = (regs[ 0 ] >> 8) & 0xf; + cpuinfo.x86PType = (regs[ 0 ] >> 12) & 0x3; + x86_64_8BITBRANDID = regs[1] & 0xff; + cpuinfo.x86Flags = regs[ 3 ]; + cpuinfo.x86Flags2 = regs[ 2 ]; + } + } + if ( iCpuId( 0x80000000, regs ) != -1 ) + { + cmds = regs[ 0 ]; + if ( cmds >= 0x80000001 ) + { + if ( iCpuId( 0x80000001, regs ) != -1 ) + { + x86_64_12BITBRANDID = regs[1] & 0xfff; + cpuinfo.x86EFlags = regs[ 3 ]; + + } + } + } + + switch(cpuinfo.x86PType) + { + case 0: + strcpy( cpuinfo.x86Type, "Standard OEM"); + break; + case 1: + strcpy( cpuinfo.x86Type, "Overdrive"); + break; + case 2: + strcpy( cpuinfo.x86Type, "Dual"); + break; + case 3: + strcpy( cpuinfo.x86Type, "Reserved"); + break; + default: + strcpy( cpuinfo.x86Type, "Unknown"); + break; + } + if ( cpuinfo.x86ID[ 0 ] == 'G' ){ cputype=0;}//trick lines but if you know a way better ;p + if ( cpuinfo.x86ID[ 0 ] == 'A' ){ cputype=1;} + + memset(cpuinfo.x86Fam, 0, sizeof(cpuinfo.x86Fam)); + iCpuId( 0x80000002, (u32*)cpuinfo.x86Fam); + iCpuId( 0x80000003, (u32*)(cpuinfo.x86Fam+16)); + iCpuId( 0x80000004, (u32*)(cpuinfo.x86Fam+32)); + + //capabilities + cpucaps.hasFloatingPointUnit = ( cpuinfo.x86Flags >> 0 ) & 1; + cpucaps.hasVirtual8086ModeEnhancements = ( cpuinfo.x86Flags >> 1 ) & 1; + cpucaps.hasDebuggingExtensions = ( cpuinfo.x86Flags >> 2 ) & 1; + cpucaps.hasPageSizeExtensions = ( cpuinfo.x86Flags >> 3 ) & 1; + cpucaps.hasTimeStampCounter = ( cpuinfo.x86Flags >> 4 ) & 1; + cpucaps.hasModelSpecificRegisters = ( cpuinfo.x86Flags >> 5 ) & 1; + cpucaps.hasPhysicalAddressExtension = ( cpuinfo.x86Flags >> 6 ) & 1; + cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 7 ) & 1; + cpucaps.hasCOMPXCHG8BInstruction = ( cpuinfo.x86Flags >> 8 ) & 1; + cpucaps.hasAdvancedProgrammableInterruptController = ( cpuinfo.x86Flags >> 9 ) & 1; + cpucaps.hasSEPFastSystemCall = ( cpuinfo.x86Flags >> 11 ) & 1; + cpucaps.hasMemoryTypeRangeRegisters = ( cpuinfo.x86Flags >> 12 ) & 1; + cpucaps.hasPTEGlobalFlag = ( cpuinfo.x86Flags >> 13 ) & 1; + cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 14 ) & 1; + cpucaps.hasConditionalMoveAndCompareInstructions = ( cpuinfo.x86Flags >> 15 ) & 1; + cpucaps.hasFGPageAttributeTable = ( cpuinfo.x86Flags >> 16 ) & 1; + cpucaps.has36bitPageSizeExtension = ( cpuinfo.x86Flags >> 17 ) & 1; + cpucaps.hasProcessorSerialNumber = ( cpuinfo.x86Flags >> 18 ) & 1; + cpucaps.hasCFLUSHInstruction = ( cpuinfo.x86Flags >> 19 ) & 1; + cpucaps.hasDebugStore = ( cpuinfo.x86Flags >> 21 ) & 1; + cpucaps.hasACPIThermalMonitorAndClockControl = ( cpuinfo.x86Flags >> 22 ) & 1; + cpucaps.hasMultimediaExtensions = ( cpuinfo.x86Flags >> 23 ) & 1; //mmx + cpucaps.hasFastStreamingSIMDExtensionsSaveRestore = ( cpuinfo.x86Flags >> 24 ) & 1; + cpucaps.hasStreamingSIMDExtensions = ( cpuinfo.x86Flags >> 25 ) & 1; //sse + cpucaps.hasStreamingSIMD2Extensions = ( cpuinfo.x86Flags >> 26 ) & 1; //sse2 + cpucaps.hasStreamingSIMD4Extensions = ( cpuinfo.x86Flags2 >> 19 ) & 1; //sse4.1 + cpucaps.hasSelfSnoop = ( cpuinfo.x86Flags >> 27 ) & 1; + cpucaps.hasHyperThreading = ( cpuinfo.x86Flags >> 28 ) & 1; + cpucaps.hasThermalMonitor = ( cpuinfo.x86Flags >> 29 ) & 1; + cpucaps.hasIntel64BitArchitecture = ( cpuinfo.x86Flags >> 30 ) & 1; + //that is only for AMDs + cpucaps.hasMultimediaExtensionsExt = ( cpuinfo.x86EFlags >> 22 ) & 1; //mmx2 + cpucaps.hasAMD64BitArchitecture = ( cpuinfo.x86EFlags >> 29 ) & 1; //64bit cpu + cpucaps.has3DNOWInstructionExtensionsExt = ( cpuinfo.x86EFlags >> 30 ) & 1; //3dnow+ + cpucaps.has3DNOWInstructionExtensions = ( cpuinfo.x86EFlags >> 31 ) & 1; //3dnow + cpuinfo.cpuspeed = (u32 )(CPUSpeedHz( 1000 ) / 1000000); +} diff --git a/pcsx2/x86/ix86/ix86_fpu.c b/pcsx2/x86/ix86/ix86_fpu.c new file mode 100644 index 0000000000..477132dafc --- /dev/null +++ b/pcsx2/x86/ix86/ix86_fpu.c @@ -0,0 +1,291 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include +#include "ix86.h" + +/********************/ +/* FPU instructions */ +/********************/ + +/* fild m32 to fpu reg stack */ +void FILD32( u32 from ) +{ + write8( 0xDB ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fistp m32 from fpu reg stack */ +void FISTP32( u32 from ) +{ + write8( 0xDB ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fld m32 to fpu reg stack */ +void FLD32( u32 from ) +{ + write8( 0xD9 ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// fld st(i) +void FLD(int st) { write16(0xc0d9+(st<<8)); } + +void FLD1() { write16(0xe8d9); } +void FLDL2E() { write16(0xead9); } + +/* fst m32 from fpu reg stack */ +void FST32( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* fstp m32 from fpu reg stack */ +void FSTP32( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// fstp st(i) +void FSTP(int st) { write16(0xd8dd+(st<<8)); } + +/* fldcw fpu control word from m16 */ +void FLDCW( u32 from ) +{ + write8( 0xD9 ); + ModRM( 0, 0x5, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fnstcw fpu control word to m16 */ +void FNSTCW( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x7, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +void FNSTSWtoAX( void ) +{ + write16( 0xE0DF ); +} + +void FXAM() +{ + write16(0xe5d9); +} + +void FDECSTP() { write16(0xf6d9); } +void FRNDINT() { write16(0xfcd9); } +void FXCH(int st) { write16(0xc8d9+(st<<8)); } +void F2XM1() { write16(0xf0d9); } +void FSCALE() { write16(0xfdd9); } + +/* fadd ST(src) to fpu reg stack ST(0) */ +void FADD32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xC0 + src ); +} + +/* fadd ST(0) to fpu reg stack ST(src) */ +void FADD320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xC0 + src ); +} + +/* fsub ST(src) to fpu reg stack ST(0) */ +void FSUB32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xE0 + src ); +} + +/* fsub ST(0) to fpu reg stack ST(src) */ +void FSUB320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xE8 + src ); +} + +/* fsubp -> substract ST(0) from ST(1), store in ST(1) and POP stack */ +void FSUBP( void ) +{ + write8( 0xDE ); + write8( 0xE9 ); +} + +/* fmul ST(src) to fpu reg stack ST(0) */ +void FMUL32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xC8 + src ); +} + +/* fmul ST(0) to fpu reg stack ST(src) */ +void FMUL320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xC8 + src ); +} + +/* fdiv ST(src) to fpu reg stack ST(0) */ +void FDIV32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xF0 + src ); +} + +/* fdiv ST(0) to fpu reg stack ST(src) */ +void FDIV320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xF8 + src ); +} + +void FDIV320toRP( x86IntRegType src ) +{ + write8( 0xDE ); + write8( 0xF8 + src ); +} + +/* fadd m32 to fpu reg stack */ +void FADD32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fsub m32 to fpu reg stack */ +void FSUB32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fmul m32 to fpu reg stack */ +void FMUL32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x1, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fdiv m32 to fpu reg stack */ +void FDIV32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fabs fpu reg stack */ +void FABS( void ) +{ + write16( 0xE1D9 ); +} + +/* fsqrt fpu reg stack */ +void FSQRT( void ) +{ + write16( 0xFAD9 ); +} + +void FPATAN(void) { write16(0xf3d9); } +void FSIN(void) { write16(0xfed9); } + +/* fchs fpu reg stack */ +void FCHS( void ) +{ + write16( 0xE0D9 ); +} + +/* fcomi st, st(i) */ +void FCOMI( x86IntRegType src ) +{ + write8( 0xDB ); + write8( 0xF0 + src ); +} + +/* fcomip st, st(i) */ +void FCOMIP( x86IntRegType src ) +{ + write8( 0xDF ); + write8( 0xF0 + src ); +} + +/* fucomi st, st(i) */ +void FUCOMI( x86IntRegType src ) +{ + write8( 0xDB ); + write8( 0xE8 + src ); +} + +/* fucomip st, st(i) */ +void FUCOMIP( x86IntRegType src ) +{ + write8( 0xDF ); + write8( 0xE8 + src ); +} + +/* fcom m32 to fpu reg stack */ +void FCOM32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fcomp m32 to fpu reg stack */ +void FCOMP32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +#define FCMOV32( low, high ) \ + { \ + write8( low ); \ + write8( high + from ); \ + } + +void FCMOVB32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC0 ); } +void FCMOVE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC8 ); } +void FCMOVBE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD0 ); } +void FCMOVU32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD8 ); } +void FCMOVNB32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC0 ); } +void FCMOVNE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC8 ); } +void FCMOVNBE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD0 ); } +void FCMOVNU32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD8 ); } + +#endif diff --git a/pcsx2/x86/ix86/ix86_mmx.c b/pcsx2/x86/ix86/ix86_mmx.c new file mode 100644 index 0000000000..7a043d7321 --- /dev/null +++ b/pcsx2/x86/ix86/ix86_mmx.c @@ -0,0 +1,653 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include "ix86.h" + +#include + +/********************/ +/* MMX instructions */ +/********************/ + +// r64 = mm + +/* movq m64 to r64 */ +void MOVQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x6F0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* movq r64 to m64 */ +void MOVQRtoM( uptr to, x86MMXRegType from ) +{ + write16( 0x7F0F ); + ModRM( 0, from, DISP32 ); + write32(MEMADDR(to, 4)); +} + +/* pand r64 to r64 */ +void PANDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDB0F ); + ModRM( 3, to, from ); +} + +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDF0F ); + ModRM( 3, to, from ); +} + +/* por r64 to r64 */ +void PORRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEB0F ); + ModRM( 3, to, from ); +} + +/* pxor r64 to r64 */ +void PXORRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEF0F ); + ModRM( 3, to, from ); +} + +/* psllq r64 to r64 */ +void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF30F ); + ModRM( 3, to, from ); +} + +/* psllq m64 to r64 */ +void PSLLQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xF30F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* psllq imm8 to r64 */ +void PSLLQItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x730F ); + ModRM( 3, 6, to); + write8( from ); +} + +/* psrlq r64 to r64 */ +void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD30F ); + ModRM( 3, to, from ); +} + +/* psrlq m64 to r64 */ +void PSRLQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xD30F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* psrlq imm8 to r64 */ +void PSRLQItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x730F ); + ModRM( 3, 2, to); + write8( from ); +} + +/* paddusb r64 to r64 */ +void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDC0F ); + ModRM( 3, to, from ); +} + +/* paddusb m64 to r64 */ +void PADDUSBMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDC0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddusw r64 to r64 */ +void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDD0F ); + ModRM( 3, to, from ); +} + +/* paddusw m64 to r64 */ +void PADDUSWMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDD0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddb r64 to r64 */ +void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFC0F ); + ModRM( 3, to, from ); +} + +/* paddb m64 to r64 */ +void PADDBMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFC0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddw r64 to r64 */ +void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFD0F ); + ModRM( 3, to, from ); +} + +/* paddw m64 to r64 */ +void PADDWMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFD0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddd r64 to r64 */ +void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFE0F ); + ModRM( 3, to, from ); +} + +/* paddd m64 to r64 */ +void PADDDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFE0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* emms */ +void EMMS( void ) +{ + write16( 0x770F ); +} + +void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEC0F ); + ModRM( 3, to, from ); +} + +void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xED0F ); + ModRM( 3, to, from ); +} + +// paddq m64 to r64 (sse2 only?) +void PADDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xD40F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// paddq r64 to r64 (sse2 only?) +void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD40F ); + ModRM( 3, to, from ); +} + +void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE80F ); + ModRM( 3, to, from ); +} + +void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE90F ); + ModRM( 3, to, from ); +} + + +void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF80F ); + ModRM( 3, to, from ); +} + +void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF90F ); + ModRM( 3, to, from ); +} + +void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFA0F ); + ModRM( 3, to, from ); +} + +void PSUBDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFA0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PSUBUSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD80F ); + ModRM( 3, to, from ); +} + +void PSUBUSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD90F ); + ModRM( 3, to, from ); +} + +// psubq m64 to r64 (sse2 only?) +void PSUBQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// psubq r64 to r64 (sse2 only?) +void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFB0F ); + ModRM( 3, to, from ); +} + +// pmuludq m64 to r64 (sse2 only?) +void PMULUDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xF40F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// pmuludq r64 to r64 (sse2 only?) +void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF40F ); + ModRM( 3, to, from ); +} + +void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x740F ); + ModRM( 3, to, from ); +} + +void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x750F ); + ModRM( 3, to, from ); +} + +void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x760F ); + ModRM( 3, to, from ); +} + +void PCMPEQDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x760F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x640F ); + ModRM( 3, to, from ); +} + +void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x650F ); + ModRM( 3, to, from ); +} + +void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x660F ); + ModRM( 3, to, from ); +} + +void PCMPGTDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x660F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PSRLWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 2 , to ); + write8( from ); +} + +void PSRLDItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 2 , to ); + write8( from ); +} + +void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD20F ); + ModRM( 3, to, from ); +} + +void PSLLWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 6 , to ); + write8( from ); +} + +void PSLLDItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 6 , to ); + write8( from ); +} + +void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF20F ); + ModRM( 3, to, from ); +} + +void PSRAWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 4 , to ); + write8( from ); +} + +void PSRADItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 4 , to ); + write8( from ); +} + +void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE20F ); + ModRM( 3, to, from ); +} + +/* por m64 to r64 */ +void PORMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xEB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pxor m64 to r64 */ +void PXORMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xEF0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pand m64 to r64 */ +void PANDMtoR( x86MMXRegType to, uptr from ) +{ + //u64 rip = (u64)x86Ptr + 7; + write16( 0xDB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PANDNMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDF0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x6A0F ); + ModRM( 3, to, from ); +} + +void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x6A0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x620F ); + ModRM( 3, to, from ); +} + +void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x620F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void MOVQ64ItoR( x86MMXRegType reg, u64 i ) +{ + MOVQMtoR( reg, ( u32 )(x86Ptr) + 2 + 7 ); + JMP8( 8 ); + write64( i ); +} + +void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x6F0F ); + ModRM( 3, to, from ); +} + +void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ) +{ + write16( 0x6F0F ); + + if( offset < 128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } +} + +void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) +{ + write16( 0x7F0F ); + + if( offset < 128 ) { + ModRM( 1, from , to ); + write8(offset); + } + else { + ModRM( 2, from, to ); + write32(offset); + } +} + +/* movd m32 to r64 */ +void MOVDMtoMMX( x86MMXRegType to, uptr from ) +{ + write16( 0x6E0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* movd r64 to m32 */ +void MOVDMMXtoM( uptr to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ) +{ + write16( 0x6E0F ); + ModRM( 3, to, from ); +} + +void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ) +{ + write16( 0x6E0F ); + ModRM( 0, to, from ); +} + +void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ) +{ + write16( 0x6E0F ); + + if( offset < 128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } +} + +void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 3, from, to ); +} + +void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 0, from, to ); + if( to >= 4 ) { + // no idea why + assert( to == ESP ); + write8(0x24); + } + +} + +void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) +{ + write16( 0x7E0F ); + + if( offset < 128 ) { + ModRM( 1, from, to ); + write8(offset); + } + else { + ModRM( 2, from, to ); + write32(offset); + } +} + +///* movd r32 to r64 */ +//void MOVD32MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) +//{ +// write16( 0x6E0F ); +// ModRM( 3, to, from ); +//} +// +///* movq r64 to r32 */ +//void MOVD64MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) +//{ +// write16( 0x7E0F ); +// ModRM( 3, from, to ); +//} + +// untested +void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from) +{ + write16( 0x630F ); + ModRM( 3, to, from ); +} + +void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from) +{ + write16( 0x6B0F ); + ModRM( 3, to, from ); +} + +void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from) +{ + write16( 0xD70F ); + ModRM( 3, to, from ); +} + +void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ) +{ + if (to > 7 || from > 7) Rex(1, to >> 3, 0, from >> 3); + write16( 0xc40f ); + ModRM( 3, to, from ); + write8( imm8 ); +} + +void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8) +{ + write16(0x700f); + ModRM( 3, to, from ); + write8(imm8); +} + +void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8) +{ + write16( 0x700f ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); + write8(imm8); +} + +void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from) +{ + write16(0xf70f); + ModRM( 3, to, from ); +} + +#endif diff --git a/pcsx2/x86/ix86/ix86_sse.c b/pcsx2/x86/ix86/ix86_sse.c new file mode 100644 index 0000000000..f0d463cab4 --- /dev/null +++ b/pcsx2/x86/ix86/ix86_sse.c @@ -0,0 +1,1543 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +// stop compiling if NORECBUILD build (only for Visual Studio) +#if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) + +#include +#include "ix86.h" + +PCSX2_ALIGNED16(unsigned int p[4]); +PCSX2_ALIGNED16(unsigned int p2[4]); +PCSX2_ALIGNED16(float f[4]); + + +XMMSSEType g_xmmtypes[XMMREGS] = {0}; + +/********************/ +/* SSE instructions */ +/********************/ + +#define SSEMtoR( code, overb ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( to < XMMREGS ) ; \ + RexR(0, to); \ + write16( code ); \ + ModRM( 0, to, DISP32 ); \ + write32( MEMADDR(from, 4 + overb) ); \ + +#define SSERtoM( code, overb ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( from < XMMREGS) ; \ + RexR(0, from); \ + write16( code ); \ + ModRM( 0, from, DISP32 ); \ + write32( MEMADDR(to, 4 + overb) ); \ + +#define SSE_SS_MtoR( code, overb ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( to < XMMREGS ) ; \ + write8( 0xf3 ); \ + RexR(0, to); \ + write16( code ); \ + ModRM( 0, to, DISP32 ); \ + write32( MEMADDR(from, 4 + overb) ); \ + +#define SSE_SS_RtoM( code, overb ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( from < XMMREGS) ; \ + write8( 0xf3 ); \ + RexR(0, from); \ + write16( code ); \ + ModRM( 0, from, DISP32 ); \ + write32( MEMADDR(to, 4 + overb) ); \ + +#define SSERtoR( code ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( to < XMMREGS && from < XMMREGS) ; \ + RexRB(0, to, from); \ + write16( code ); \ + ModRM( 3, to, from ); + +#define SSEMtoR66( code ) \ + write8( 0x66 ); \ + SSEMtoR( code, 0 ); + +#define SSERtoM66( code ) \ + write8( 0x66 ); \ + SSERtoM( code, 0 ); + +#define SSERtoR66( code ) \ + write8( 0x66 ); \ + SSERtoR( code ); + +#define _SSERtoR66( code ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( to < XMMREGS && from < XMMREGS) ; \ + write8( 0x66 ); \ + RexRB(0, from, to); \ + write16( code ); \ + ModRM( 3, from, to ); + +#define SSE_SS_RtoR( code ) \ + assert( cpucaps.hasStreamingSIMDExtensions ); \ + assert( to < XMMREGS && from < XMMREGS) ; \ + write8( 0xf3 ); \ + RexRB(0, to, from); \ + write16( code ); \ + ModRM( 3, to, from ); + +#define CMPPSMtoR( op ) \ + SSEMtoR( 0xc20f, 1 ); \ + write8( op ); + +#define CMPPSRtoR( op ) \ + SSERtoR( 0xc20f ); \ + write8( op ); + +#define CMPSSMtoR( op ) \ + SSE_SS_MtoR( 0xc20f, 1 ); \ + write8( op ); + +#define CMPSSRtoR( op ) \ + SSE_SS_RtoR( 0xc20f ); \ + write8( op ); + + + +void WriteRmOffset(x86IntRegType to, int offset); +void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset); + +/* movups [r32][r32*scale] to xmm1 */ +void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRXB(0, to, from2, from); + write16( 0x100f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movups xmm1 to [r32][r32*scale] */ +void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRXB(1, to, from2, from); + write16( 0x110f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movups [r32] to r32 */ +void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, to, from); + write16( 0x100f ); + ModRM( 0, to, from ); +} + +/* movups r32 to [r32] */ +void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16( 0x110f ); + ModRM( 0, from, to ); +} + +/* movlps [r32] to r32 */ +void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(1, to, from); + write16( 0x120f ); + ModRM( 0, to, from ); +} + +void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, to, from); + write16( 0x120f ); + WriteRmOffsetFrom(to, from, offset); +} + +/* movaps r32 to [r32] */ +void SSE_MOVLPSRtoRm( x86IntRegType to, x86IntRegType from ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16( 0x130f ); + ModRM( 0, from, to ); +} + +void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16( 0x130f ); + WriteRmOffsetFrom(from, to, offset); +} + +/* movaps [r32][r32*scale] to xmm1 */ +void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( cpucaps.hasStreamingSIMDExtensions && from != EBP ); + RexRXB(0, to, from2, from); + write16( 0x280f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movaps xmm1 to [r32][r32*scale] */ +void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( cpucaps.hasStreamingSIMDExtensions && from != EBP ); + RexRXB(0, to, from2, from); + write16( 0x290f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +// movaps [r32+offset] to r32 +void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, to, from); + write16( 0x280f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movaps r32 to [r32+offset] +void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16( 0x290f ); + WriteRmOffsetFrom(from, to, offset); +} + +// movdqa [r32+offset] to r32 +void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + write8(0x66); + RexRB(0, to, from); + write16( 0x6f0f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movdqa r32 to [r32+offset] +void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + write8(0x66); + RexRB(0, from, to); + write16( 0x7f0f ); + WriteRmOffsetFrom(from, to, offset); +} + +// movups [r32+offset] to r32 +void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x100f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movups r32 to [r32+offset] +void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16( 0x110f ); + WriteRmOffsetFrom(from, to, offset); +} + +//**********************************************************************************/ +//MOVAPS: Move aligned Packed Single Precision FP values * +//********************************************************************************** +void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x280f, 0 ); } +void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x290f, 0 ); } +void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x280f ); } + +void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x100f, 0 ); } +void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x110f, 0 ); } + +void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE2EMU_MOVSD_XMM_to_XMM(to, from); + else { + write8(0xf2); + SSERtoR( 0x100f); + } +} + +void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE2EMU_MOVQ_M64_to_XMM(to, from); + else { + write8(0xf3); SSEMtoR( 0x7e0f, 0); + } +} + +void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE2EMU_MOVQ_XMM_to_XMM(to, from); + else { + write8(0xf3); SSERtoR( 0x7e0f); + } +} + +void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE_MOVLPS_XMM_to_M64(to, from); + else { + SSERtoM66(0xd60f); + } +} + +#ifndef __x86_64__ +void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE2EMU_MOVDQ2Q_XMM_to_MM(to, from); + else { + write8(0xf2); + SSERtoR( 0xd60f); + } +} +void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) SSE2EMU_MOVQ2DQ_MM_to_XMM(to, from); + else { + write8(0xf3); + SSERtoR( 0xd60f); + } +} +#endif + +//**********************************************************************************/ +//MOVSS: Move Scalar Single-Precision FP value * +//********************************************************************************** +void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x100f, 0 ); } +void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { SSE_SS_RtoM( 0x110f, 0 ); } +void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + write8(0xf3); + RexRB(0, from, to); + write16(0x110f); + ModRM(0, from, to); +} + +void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x100f ); } + +void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + write8(0xf3); + RexRB(0, to, from); + write16( 0x100f ); + WriteRmOffsetFrom(to, from, offset); +} + +void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + write8(0xf3); + RexRB(0, from, to); + write16(0x110f); + WriteRmOffsetFrom(from, to, offset); +} + +void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xf70f ); } +//**********************************************************************************/ +//MOVLPS: Move low Packed Single-Precision FP * +//********************************************************************************** +void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x120f, 0 ); } +void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x130f, 0 ); } + +void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, to, from); + write16( 0x120f ); + WriteRmOffsetFrom(to, from, offset); +} + +void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + RexRB(0, from, to); + write16(0x130f); + WriteRmOffsetFrom(from, to, offset); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVHPS: Move High Packed Single-Precision FP * +//********************************************************************************** +void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x160f, 0 ); } +void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x170f, 0 ); } + +void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, to, from); + write16( 0x160f ); + WriteRmOffsetFrom(to, from, offset); +} + +void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + assert( cpucaps.hasStreamingSIMDExtensions ); + RexRB(0, from, to); + write16(0x170f); + WriteRmOffsetFrom(from, to, offset); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVLHPS: Moved packed Single-Precision FP low to high * +//********************************************************************************** +void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x160f ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVHLPS: Moved packed Single-Precision FP High to Low * +//********************************************************************************** +void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x120f ); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ANDPS: Logical Bit-wise AND for Single FP * +//********************************************************************************** +void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x540f, 0 ); } +void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x540f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ANDNPS : Logical Bit-wise AND NOT of Single-precision FP values * +//********************************************************************************** +void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x550f, 0 ); } +void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x550f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RCPPS : Packed Single-Precision FP Reciprocal * +//********************************************************************************** +void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x530f ); } +void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x530f, 0 ); } + +void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR(0x530f); } +void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR(0x530f, 0); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ORPS : Bit-wise Logical OR of Single-Precision FP Data * +//********************************************************************************** +void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x560f, 0 ); } +void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x560f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//XORPS : Bitwise Logical XOR of Single-Precision FP Values * +//********************************************************************************** + +void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x570f, 0 ); } +void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x570f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ADDPS : ADD Packed Single-Precision FP Values * +//********************************************************************************** +void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x580f, 0 ); } +void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x580f ); } + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ADDSS : ADD Scalar Single-Precision FP Values * +//********************************************************************************** +void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x580f, 0 ); } +void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x580f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SUBPS: Packed Single-Precision FP Subtract * +//********************************************************************************** +void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5c0f, 0 ); } +void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5c0f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SUBSS : Scalar Single-Precision FP Subtract * +//********************************************************************************** +void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5c0f, 0 ); } +void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5c0f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MULPS : Packed Single-Precision FP Multiply * +//********************************************************************************** +void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x590f, 0 ); } +void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x590f ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MULSS : Scalar Single-Precision FP Multiply * +//********************************************************************************** +void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x590f, 0 ); } +void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x590f ); } + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//Packed Single-Precission FP compare (CMPccPS) * +//********************************************************************************** +//missing SSE_CMPPS_I8_to_XMM +// SSE_CMPPS_M32_to_XMM +// SSE_CMPPS_XMM_to_XMM +void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 0 ); } +void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 0 ); } +void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 1 ); } +void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 1 ); } +void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 2 ); } +void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 2 ); } +void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 3 ); } +void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 3 ); } +void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 4 ); } +void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 4 ); } +void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 5 ); } +void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 5 ); } +void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 6 ); } +void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 6 ); } +void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 7 ); } +void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 7 ); } + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//Scalar Single-Precission FP compare (CMPccSS) * +//********************************************************************************** +//missing SSE_CMPSS_I8_to_XMM +// SSE_CMPSS_M32_to_XMM +// SSE_CMPSS_XMM_to_XMM +void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 0 ); } +void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 0 ); } +void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 1 ); } +void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 1 ); } +void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 2 ); } +void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 2 ); } +void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 3 ); } +void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 3 ); } +void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 4 ); } +void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 4 ); } +void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 5 ); } +void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 5 ); } +void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 6 ); } +void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 6 ); } +void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 7 ); } +void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 7 ); } + +void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ) +{ + RexR(0, to); + write16( 0x2e0f ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + RexRB(0, to, from); + write16( 0x2e0f ); + ModRM( 3, to, from ); +} + +////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RSQRTPS : Packed Single-Precision FP Square Root Reciprocal * +//********************************************************************************** +void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x520f, 0 ); } +void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x520f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RSQRTSS : Scalar Single-Precision FP Square Root Reciprocal * +//********************************************************************************** +void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x520f, 0 ); } +void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x520f ); } + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SQRTPS : Packed Single-Precision FP Square Root * +//********************************************************************************** +void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x510f, 0 ); } +void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x510f ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SQRTSS : Scalar Single-Precision FP Square Root * +//********************************************************************************** +void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x510f, 0 ); } +void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x510f ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MAXPS: Return Packed Single-Precision FP Maximum * +//********************************************************************************** +void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5f0f, 0 ); } +void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5f0f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MAXSS: Return Scalar Single-Precision FP Maximum * +//********************************************************************************** +void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5f0f, 0 ); } +void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5f0f ); } + +#ifndef __x86_64__ +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTPI2PS: Packed Signed INT32 to Packed Single FP Conversion * +//********************************************************************************** +void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x2a0f, 0 ); } +void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ) { SSERtoR( 0x2a0f ); } + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTPS2PI: Packed Single FP to Packed Signed INT32 Conversion * +//********************************************************************************** +void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ) { SSEMtoR( 0x2d0f, 0 ); } +void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ) { SSERtoR( 0x2d0f ); } +#endif + +void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from) { write8(0xf3); SSEMtoR(0x2c0f, 0); } +void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from) +{ + write8(0xf3); + RexRB(0, to, from); + write16(0x2c0f); + ModRM(3, to, from); +} + +void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x2a0f, 0); } +void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from) +{ + write8(0xf3); + RexRB(0, to, from); + write16(0x2a0f); + ModRM(3, to, from); +} + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTDQ2PS: Packed Signed INT32 to Packed Single Precision FP Conversion * +//********************************************************************************** +void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5b0f, 0 ); } +void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5b0f ); } + +//**********************************************************************************/ +//CVTPS2DQ: Packed Single Precision FP to Packed Signed INT32 Conversion * +//********************************************************************************** +void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5b0f ); } +void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5b0f ); } + +void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { write8(0xf3); SSERtoR(0x5b0f); } +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MINPS: Return Packed Single-Precision FP Minimum * +//********************************************************************************** +void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5d0f, 0 ); } +void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5d0f ); } + +////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MINSS: Return Scalar Single-Precision FP Minimum * +//********************************************************************************** +void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5d0f, 0 ); } +void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5d0f ); } + +#ifndef __x86_64__ +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PMAXSW: Packed Signed Integer Word Maximum * +//********************************************************************************** +//missing + // SSE_PMAXSW_M64_to_MM +// SSE2_PMAXSW_M128_to_XMM +// SSE2_PMAXSW_XMM_to_XMM +void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEE0F ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PMINSW: Packed Signed Integer Word Minimum * +//********************************************************************************** +//missing + // SSE_PMINSW_M64_to_MM +// SSE2_PMINSW_M128_to_XMM +// SSE2_PMINSW_XMM_to_XMM +void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEA0F ); } +#endif + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SHUFPS: Shuffle Packed Single-Precision FP Values * +//********************************************************************************** +void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { SSERtoR( 0xC60F ); write8( imm8 ); } +void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR( 0xC60F, 1 ); write8( imm8 ); } + +void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ) +{ + RexRB(0, to, from); + write16(0xc60f); + WriteRmOffsetFrom(to, from, offset); + write8(imm8); +} + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PSHUFD: Shuffle Packed DoubleWords * +//********************************************************************************** +void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE2EMU_PSHUFD_XMM_to_XMM(to, from, imm8); + } + else { + SSERtoR66( 0x700F ); + write8( imm8 ); + } +} +void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR66( 0x700F ); write8( imm8 ); } + +void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF2); SSERtoR(0x700F); write8(imm8); } +void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF2); SSEMtoR(0x700F, 1); write8(imm8); } +void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF3); SSERtoR(0x700F); write8(imm8); } +void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF3); SSEMtoR(0x700F, 1); write8(imm8); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//UNPCKLPS: Unpack and Interleave low Packed Single-Precision FP Data * +//********************************************************************************** +void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x140f, 0); } +void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x140F ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//UNPCKHPS: Unpack and Interleave High Packed Single-Precision FP Data * +//********************************************************************************** +void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x150f, 0); } +void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x150F ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//DIVPS : Packed Single-Precision FP Divide * +//********************************************************************************** +void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5e0F, 0 ); } +void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5e0F ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//DIVSS : Scalar Single-Precision FP Divide * +//********************************************************************************** +void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5e0F, 0 ); } +void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5e0F ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//STMXCSR : Store Streaming SIMD Extension Control/Status * +//********************************************************************************** +void SSE_STMXCSR( uptr from ) { + write16( 0xAE0F ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//LDMXCSR : Load Streaming SIMD Extension Control/Status * +//********************************************************************************** +void SSE_LDMXCSR( uptr from ) { + write16( 0xAE0F ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PADDB,PADDW,PADDD : Add Packed Integers * +//********************************************************************************** +void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFC0F ); } +void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFC0F ); } +void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFD0F ); } +void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFD0F ); } +void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFE0F ); } +void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFE0F ); } + +void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD40F ); } +void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ) { SSEMtoR66( 0xD40F ); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PCMPxx: Compare Packed Integers * +//********************************************************************************** +void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x640F ); } +void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x640F ); } +void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x650F ); } +void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x650F ); } +void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x660F ); } +void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x660F ); } +void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x740F ); } +void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x740F ); } +void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x750F ); } +void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x750F ); } +void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE_CMPEQPS_XMM_to_XMM(to, from); + } + else { + SSERtoR66( 0x760F ); + } +} + +void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE_CMPEQPS_M128_to_XMM(to, from); + } + else { + SSEMtoR66( 0x760F ); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PEXTRW,PINSRW: Packed Extract/Insert Word * +//********************************************************************************** +void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ){ SSERtoR66(0xC50F); write8( imm8 ); } +void SSE_PINSRW_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8 ){ SSERtoR66(0xC40F); write8( imm8 ); } + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PSUBx: Subtract Packed Integers * +//********************************************************************************** +void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF80F ); } +void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF80F ); } +void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF90F ); } +void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF90F ); } +void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFA0F ); } +void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFA0F ); } +void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFB0F ); } +void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFB0F ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVD: Move Dword(32bit) to /from XMM reg * +//********************************************************************************** +void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66(0x6E0F); } +void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE2EMU_MOVD_R_to_XMM(to, from); + } + else { + SSERtoR66(0x6E0F); + } +} + +void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0, to, from); + write16( 0x6e0f ); + ModRM( 0, to, from); +} + +void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + write8(0x66); + RexRB(0, to, from); + write16( 0x6e0f ); + WriteRmOffsetFrom(to, from, offset); +} + +void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) { SSERtoM66(0x7E0F); } +void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ) { + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE2EMU_MOVD_XMM_to_R(to, from); + } + else { + _SSERtoR66(0x7E0F); + } +} + +void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + write8(0x66); + RexRB(0, from, to); + write16( 0x7e0f ); + ModRM( 0, from, to ); +} + +void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + if( !cpucaps.hasStreamingSIMD2Extensions ) { + SSE2EMU_MOVD_XMM_to_RmOffset(to, from, offset); + } + else { + write8(0x66); + RexRB(0, from, to); + write16( 0x7e0f ); + WriteRmOffsetFrom(from, to, offset); + } +} + +#ifdef __x86_64__ +void SSE2_MOVQ_XMM_to_R( x86IntRegType to, x86SSERegType from ) +{ + assert( from < XMMREGS); + write8( 0x66 ); + RexRB(1, from, to); + write16( 0x7e0f ); + ModRM( 3, from, to ); +} + +void SSE2_MOVQ_R_to_XMM( x86SSERegType to, x86IntRegType from ) +{ + assert( to < XMMREGS); + write8(0x66); + RexRB(1, to, from); + write16( 0x6e0f ); + ModRM( 3, to, from ); +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//POR : SSE Bitwise OR * +//********************************************************************************** +void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xEB0F ); } +void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xEB0F ); } + +// logical and to &= from +void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDB0F ); } +void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDB0F ); } + +// to = (~to) & from +void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDF0F ); } +void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDF0F ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PXOR : SSE Bitwise XOR * +//********************************************************************************** +void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEF0F ); } +void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEF0F ) }; +/////////////////////////////////////////////////////////////////////////////////////// + +void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from) {SSEMtoR66(0x6F0F); } +void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ){SSERtoM66(0x7F0F);} +void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { SSERtoR66(0x6F0F); } + +void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xF3); SSEMtoR(0x6F0F, 0); } +void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from) { write8(0xF3); SSERtoM(0x7F0F, 0); } +void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { write8(0xF3); SSERtoR(0x6F0F); } + +// shift right logical + +void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD10F); } +void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD10F); } +void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD20F); } +void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD20F); } +void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD30F); } +void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD30F); } +void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 3 , to ); + write8( imm8 ); +} + +// shift right arithmetic + +void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE10F); } +void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE10F); } +void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 4 , to ); + write8( imm8 ); +} + +void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE20F); } +void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE20F); } +void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 4 , to ); + write8( imm8 ); +} + +// shift left logical + +void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF10F); } +void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF10F); } +void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF20F); } +void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF20F); } +void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF30F); } +void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF30F); } +void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 7 , to ); + write8( imm8 ); +} + + +void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEE0F ); } +void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEE0F ); } + +void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDE0F ); } +void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDE0F ); } + +void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEA0F ); } +void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEA0F ); } + +void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDA0F ); } +void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDA0F ); } + +// + +void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEC0F ); } +void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEC0F ); } + +void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xED0F ); } +void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xED0F ); } + +void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE80F ); } +void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE80F ); } + +void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE90F ); } +void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE90F ); } + +void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD80F ); } +void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD80F ); } +void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD90F ); } +void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD90F ); } + +void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDC0F ); } +void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDC0F ); } +void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDD0F ); } +void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDD0F ); } + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word +//********************************************************************************** +void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x630F ); } +void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x630F ); } +void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6B0F ); } +void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6B0F ); } + +void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x670F ); } +void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x670F ); } + +//**********************************************************************************/ +//PUNPCKHWD: Unpack 16bit high +//********************************************************************************** +void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x600F ); } +void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x600F ); } + +void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x680F ); } +void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x680F ); } + +void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x610F ); } +void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x610F ); } +void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x690F ); } +void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x690F ); } + +void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x620F ); } +void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x620F ); } +void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6A0F ); } +void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6A0F ); } + +void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6C0F ); } +void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6C0F ); } + +void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6D0F ); } +void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6D0F ); } + +void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xD50F ); } +void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xD50F ); } +void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xE50F ); } +void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xE50F ); } + +void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xF40F ); } +void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xF40F ); } + +void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0xD70F); } + +void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR(0x500F); } +void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0x500F); } + +void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf2); SSERtoR( 0x7c0f ); } +void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from){ write8(0xf2); SSEMtoR( 0x7c0f, 0 ); } + +void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { + write8(0xf3); + RexRB(0, to, from); + write16( 0x120f); + ModRM( 3, to, from ); +} + +void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x120f, 0); } +void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf3); SSERtoR(0x160f); } +void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x160f, 0); } + +// SSE4.1 + +void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + write24(0x403A0F); + ModRM(3, to, from); + write8(imm8); +} + +void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8) +{ + const int overb = 0; // TODO: x64? + + write8(0x66); + write24(0x403A0F); + ModRM(0, to, DISP32); + write32(MEMADDR(from, 4 + overb)); + write8(imm8); +} + +void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x213A0F); + ModRM(3, to, from); + write8(imm8); +} + +void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x173A0F); + ModRM(3, to, from); + write8(imm8); +} + +void SSE4_BLENDPS_XMM_to_XMM(x86IntRegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x0C3A0F); + ModRM(3, to, from); + write8(imm8); +} + +// SSE-X +void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQA_M128_to_XMM(to, from); + else SSE_MOVAPS_M128_to_XMM(to, from); +} + +void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_M128(to, from); + else SSE_MOVAPS_XMM_to_M128(to, from); +} + +void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_XMM(to, from); + else SSE_MOVAPS_XMM_to_XMM(to, from); +} + +void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQARmtoROffset(to, from, offset); + else SSE_MOVAPSRmtoROffset(to, from, offset); +} + +void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQARtoRmOffset(to, from, offset); + else SSE_MOVAPSRtoRmOffset(to, from, offset); +} + +void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQU_M128_to_XMM(to, from); + else SSE_MOVAPS_M128_to_XMM(to, from); +} + +void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_M128(to, from); + else SSE_MOVAPS_XMM_to_M128(to, from); +} + +void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_XMM(to, from); + else SSE_MOVAPS_XMM_to_XMM(to, from); +} + +void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_M32_to_XMM(to, from); + else SSE_MOVSS_M32_to_XMM(to, from); +} + +void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_M32(to, from); + else SSE_MOVSS_XMM_to_M32(to, from); +} + +void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_Rm(to, from); + else SSE_MOVSS_XMM_to_Rm(to, from); +} + +void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_RmOffset_to_XMM(to, from, offset); + else SSE_MOVSS_RmOffset_to_XMM(to, from, offset); +} + +void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_RmOffset(to, from, offset); + else SSE_MOVSS_XMM_to_RmOffset(to, from, offset); +} + +void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_POR_M128_to_XMM(to, from); + else SSE_ORPS_M128_to_XMM(to, from); +} + +void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_POR_XMM_to_XMM(to, from); + else SSE_ORPS_XMM_to_XMM(to, from); +} + +void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_PXOR_M128_to_XMM(to, from); + else SSE_XORPS_M128_to_XMM(to, from); +} + +void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_PXOR_XMM_to_XMM(to, from); + else SSE_XORPS_XMM_to_XMM(to, from); +} + +void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_PAND_M128_to_XMM(to, from); + else SSE_ANDPS_M128_to_XMM(to, from); +} + +void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_PAND_XMM_to_XMM(to, from); + else SSE_ANDPS_XMM_to_XMM(to, from); +} + +void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_PANDN_M128_to_XMM(to, from); + else SSE_ANDNPS_M128_to_XMM(to, from); +} + +void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_PANDN_XMM_to_XMM(to, from); + else SSE_ANDNPS_XMM_to_XMM(to, from); +} + +void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKLDQ_M128_to_XMM(to, from); + else SSE_UNPCKLPS_M128_to_XMM(to, from); +} + +void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKLDQ_XMM_to_XMM(to, from); + else SSE_UNPCKLPS_XMM_to_XMM(to, from); +} + +void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKHDQ_M128_to_XMM(to, from); + else SSE_UNPCKHPS_M128_to_XMM(to, from); +} + +void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKHDQ_XMM_to_XMM(to, from); + else SSE_UNPCKHPS_XMM_to_XMM(to, from); +} + +void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( cpucaps.hasStreamingSIMD2Extensions && g_xmmtypes[from] == XMMT_INT ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(to, from); + if( to != from ) SSE2_PSHUFD_XMM_to_XMM(to, to, 0x4e); + } + else { + SSE_MOVHLPS_XMM_to_XMM(to, from); + } +} + +// SSE2 emulation +void SSE2EMU_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from) +{ + SSE_SHUFPS_XMM_to_XMM(to, from, 0x4e); + SSE_SHUFPS_XMM_to_XMM(to, to, 0x4e); +} + +void SSE2EMU_MOVQ_M64_to_XMM( x86SSERegType to, uptr from) +{ + SSE_XORPS_XMM_to_XMM(to, to); + SSE_MOVLPS_M64_to_XMM(to, from); +} + +void SSE2EMU_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from) +{ + SSE_XORPS_XMM_to_XMM(to, to); + SSE2EMU_MOVSD_XMM_to_XMM(to, from); +} + +void SSE2EMU_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + MOV32RmtoROffset(EAX, from, offset); + MOV32ItoM((u32)p+4, 0); + MOV32ItoM((u32)p+8, 0); + MOV32RtoM((u32)p, EAX); + MOV32ItoM((u32)p+12, 0); + SSE_MOVAPS_M128_to_XMM(to, (u32)p); +} + +void SSE2EMU_MOVD_XMM_to_RmOffset(x86IntRegType to, x86SSERegType from, int offset ) +{ + SSE_MOVSS_XMM_to_M32((u32)p, from); + MOV32MtoR(EAX, (u32)p); + MOV32RtoRmOffset(to, EAX, offset); +} + +#ifndef __x86_64__ +extern void SetMMXstate(); + +void SSE2EMU_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from) +{ + SSE_MOVLPS_XMM_to_M64((u32)p, from); + MOVQMtoR(to, (u32)p); + SetMMXstate(); +} + +void SSE2EMU_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from) +{ + MOVQRtoM((u32)p, from); + SSE_MOVLPS_M64_to_XMM(to, (u32)p); + SetMMXstate(); +} +#endif + +/****************************************************************************/ +/* SSE2 Emulated functions for SSE CPU's by kekko */ +/****************************************************************************/ +void SSE2EMU_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { + MOV32ItoR(EAX, (u32)&p); + MOV32ItoR(EBX, (u32)&p2); + SSE_MOVUPSRtoRm(EAX, from); + + MOV32ItoR(ECX, (u32)imm8); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 2); + ADD32RtoR(ECX, EAX); + MOV32RmtoR(ECX, ECX); + MOV32RtoRm(EBX, ECX); + + ADD32ItoR(EBX, 4); + MOV32ItoR(ECX, (u32)imm8); + SHR32ItoR(ECX, 2); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 2); + ADD32RtoR(ECX, EAX); + MOV32RmtoR(ECX, ECX); + MOV32RtoRm(EBX, ECX); + + ADD32ItoR(EBX, 4); + MOV32ItoR(ECX, (u32)imm8); + SHR32ItoR(ECX, 4); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 2); + ADD32RtoR(ECX, EAX); + MOV32RmtoR(ECX, ECX); + MOV32RtoRm(EBX, ECX); + + ADD32ItoR(EBX, 4); + MOV32ItoR(ECX, (u32)imm8); + SHR32ItoR(ECX, 6); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 2); + ADD32RtoR(ECX, EAX); + MOV32RmtoR(ECX, ECX); + MOV32RtoRm(EBX, ECX); + + SUB32ItoR(EBX, 12); + + SSE_MOVUPSRmtoR(to, EBX); +} + +void SSE2EMU_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ) { + MOV32ItoR(to, (u32)&p); + SSE_MOVUPSRtoRm(to, from); + MOV32RmtoR(to, to); +} + +#ifndef __x86_64__ +extern void SetFPUstate(); +extern void _freeMMXreg(int mmxreg); +#endif + +void SSE2EMU_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { +#ifndef __x86_64__ + SetFPUstate(); + _freeMMXreg(7); +#endif + SSE_MOVAPS_XMM_to_M128((u32)f, from); + + FLD32((u32)&f[0]); + FISTP32((u32)&p2[0]); + FLD32((u32)&f[1]); + FISTP32((u32)&p2[1]); + FLD32((u32)&f[2]); + FISTP32((u32)&p2[2]); + FLD32((u32)&f[3]); + FISTP32((u32)&p2[3]); + + SSE_MOVAPS_M128_to_XMM(to, (u32)p2); +} + +void SSE2EMU_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ) { +#ifndef __x86_64__ + SetFPUstate(); + _freeMMXreg(7); +#endif + FILD32((u32)from); + FSTP32((u32)&f[0]); + FILD32((u32)from+4); + FSTP32((u32)&f[1]); + FILD32((u32)from+8); + FSTP32((u32)&f[2]); + FILD32((u32)from+12); + FSTP32((u32)&f[3]); + + SSE_MOVAPS_M128_to_XMM(to, (u32)f); +} + +void SSE2EMU_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) { + MOV32ItoR(EAX, (u32)&p); + SSE_MOVUPSRtoRm(EAX, from); + MOV32RmtoR(EAX, EAX); + MOV32RtoM(to, EAX); +} + +void SSE2EMU_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ) { + MOV32ItoM((u32)p+4, 0); + MOV32ItoM((u32)p+8, 0); + MOV32RtoM((u32)p, from); + MOV32ItoM((u32)p+12, 0); + SSE_MOVAPS_M128_to_XMM(to, (u32)p); +} + +#endif diff --git a/pcsx2/xmlpatchloader.cpp b/pcsx2/xmlpatchloader.cpp new file mode 100644 index 0000000000..05b6705462 --- /dev/null +++ b/pcsx2/xmlpatchloader.cpp @@ -0,0 +1,397 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include +#include + +using namespace std; +extern "C" int g_ZeroGSOptions; + +#include "tinyxml/tinyxml.h" + +extern "C" { +# include "PS2Etypes.h" +# include "Patch.h" + +# ifdef _WIN32 +# include + struct AppData { + HWND hWnd; // Main window handle + HINSTANCE hInstance; // Application instance + HMENU hMenu; // Main window menu + HANDLE hConsole; + } extern gApp; +# endif + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + + void SysPrintf(char *fmt, ...); + int LoadPatch(char *patchfile); +} + +#if !defined(_WIN32) && !defined(__MINGW32__) +#ifndef strnicmp +#define strnicmp strncasecmp +#endif + +#ifndef stricmp +#define stricmp strcasecmp +#endif +#endif + +#include "../cheatscpp.h" + +int LoadGroup(TiXmlNode *group, int parent); + +Group::Group(int nParent,bool nEnabled, string &nTitle): + parentIndex(nParent),enabled(nEnabled),title(nTitle) +{ +} + +Patch::Patch(int patch, int grp, bool en, string &ttl): + title(ttl), + group(grp), + enabled(en), + patchIndex(patch) +{ +} + +Patch Patch::operator =(const Patch&p) +{ + title.assign(p.title); + group=p.group; + enabled=p.enabled; + patchIndex=p.patchIndex; + return *this; +} + + +vector groups; +vector patches; + +int LoadPatch(char *crc) +{ + char pfile[256]; + sprintf(pfile,"patches\\%s.xml",crc); + + patchnumber=0; + + TiXmlDocument doc( pfile ); + bool loadOkay = doc.LoadFile(); + if ( !loadOkay ) + { + //SysPrintf("XML Patch Loader: Could not load file '%s'. Error='%s'.\n", pfile, doc.ErrorDesc() ); + return -1; + } else SysPrintf("XML Patch Loader: '%s' Found\n", pfile); + + TiXmlNode *root = doc.FirstChild("GAME"); + if(!root) + { + SysPrintf("XML Patch Loader: Root node is not GAME, invalid patch file.\n"); + return -1; + } + + TiXmlElement *rootelement = root->ToElement(); + + const char *title=rootelement->Attribute("title"); + if(title) + SysPrintf("XML Patch Loader: Game Title: %s\n",title); + + int result=LoadGroup(root,-1); + if(result) { + patchnumber=0; + return result; + } + +#ifdef _WIN32 + if (gApp.hConsole) + { + if(title) + SetConsoleTitle(title); + else + SetConsoleTitle(""); + } + +#endif + + return 0; +} + + +int LoadGroup(TiXmlNode *group,int gParent) +{ + + TiXmlElement *groupelement = group->ToElement(); + + const char *gtitle=groupelement->Attribute("title"); + if(gtitle) + SysPrintf("XML Patch Loader: Group Title: %s\n",gtitle); + + const char *enable=groupelement->Attribute("enabled"); + bool gEnabled=true; + if(enable) + { + if(strcmp(enable,"false")==0) + { + SysPrintf("XML Patch Loader: Group is disabled.\n"); + gEnabled=false; + } + } + + TiXmlNode *comment = group->FirstChild("COMMENT"); + if(comment) + { + TiXmlElement *cmelement = comment->ToElement(); + const char *comment = cmelement->GetText(); + if(comment) + SysPrintf("XML Patch Loader: Group Comment:\n%s\n---\n",comment); + } + + string t; + + if(gtitle) + t.assign(gtitle); + else + t.clear(); + + Group gp=Group(gParent,gEnabled,t); + groups.push_back(gp); + + int gIndex=groups.size()-1; + + +#ifndef PCSX2_NORECBUILD + // only valid for recompilers + TiXmlNode *fastmemory=group->FirstChild("FASTMEMORY"); + if(fastmemory!=NULL) + SetFastMemory(1); +#endif + + TiXmlNode *zerogs=group->FirstChild("ZEROGS"); + if(zerogs!=NULL) + { + TiXmlElement *rm=zerogs->ToElement(); + const char* pid = rm->FirstAttribute()->Value(); + if( pid != NULL ) sscanf(pid, "%x", &g_ZeroGSOptions); + else SysPrintf("zerogs attribute wrong"); + } + + TiXmlNode *roundmode=group->FirstChild("ROUNDMODE"); + if(roundmode!=NULL) + { + int eetype=0x0000; + int vutype=0x6000; + + TiXmlElement *rm=roundmode->ToElement(); + if(rm!=NULL) + { + const char *eetext=rm->Attribute("ee"); + const char *vutext=rm->Attribute("vu"); + + if(eetext != NULL) { + eetype = 0xffff; + if( stricmp(eetext, "near") == 0 ) { + eetype = 0x0000; + } + else if( stricmp(eetext, "down") == 0 ) { + eetype = 0x2000; + } + else if( stricmp(eetext, "up") == 0 ) { + eetype = 0x4000; + } + else if( stricmp(eetext, "chop") == 0 ) { + eetype = 0x6000; + } + } + + if(vutext != NULL) { + vutype = 0xffff; + if( stricmp(vutext, "near") == 0 ) { + vutype = 0x0000; + } + else if( stricmp(vutext, "down") == 0 ) { + vutype = 0x2000; + } + else if( stricmp(vutext, "up") == 0 ) { + vutype = 0x4000; + } + else if( stricmp(vutext, "chop") == 0 ) { + vutype = 0x6000; + } + } + } + if(( eetype == 0xffff )||( vutype == 0xffff )) { + printf("XML Patch Loader: WARNING: Invalid value in ROUNDMODE.\n"); + } + else { + SetRoundMode(eetype,vutype); + } + } + + TiXmlNode *cpatch = group->FirstChild("PATCH"); + while(cpatch) + { + TiXmlElement *celement = cpatch->ToElement(); + if(!celement) + { + SysPrintf("XML Patch Loader: ERROR: Couldn't convert node to element.\n" ); + return -1; + } + + + const char *ptitle=celement->Attribute("title"); + const char *penable=celement->Attribute("enabled"); + const char *applymode=celement->Attribute("applymode"); + const char *place=celement->Attribute("place"); + const char *address=celement->Attribute("address"); + const char *size=celement->Attribute("size"); + const char *value=celement->Attribute("value"); + + if(ptitle) { + SysPrintf("XML Patch Loader: Patch title: %s\n", ptitle); + } + + bool penabled=gEnabled; + if(penable) + { + if(strcmp(penable,"false")==0) + { + SysPrintf("XML Patch Loader: Patch is disabled.\n"); + penabled=false; + } + } + + if(!applymode) applymode="frame"; + if(!place) place="EE"; + if(!address) { + SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain an address.\n"); + return -1; + } + if(!value) { + SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain a value.\n"); + return -1; + } + if(!size) { + SysPrintf("XML Patch Loader: WARNING: Patch doesn't contain the size. Trying to deduce from the value size.\n"); + switch(strlen(value)) + { + case 8: + case 7: + case 6: + case 5: + size="32"; + break; + case 4: + case 3: + size="16"; + break; + case 2: + case 1: + size="8"; + break; + case 0: + size="0"; + break; + default: + size="64"; + break; + } + } + + if(strcmp(applymode,"startup")==0) + { + patch[patchnumber].placetopatch=0; + } else + if(strcmp(applymode,"vsync")==0) + { + patch[patchnumber].placetopatch=1; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid applymode attribute.\n"); + patchnumber=0; + return -1; + } + + if(strcmp(place,"EE")==0) + { + patch[patchnumber].cpu=1; + } else + if(strcmp(place,"IOP")==0) + { + patch[patchnumber].cpu=2; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid place attribute.\n"); + patchnumber=0; + return -1; + } + + if(strcmp(size,"64")==0) + { + patch[patchnumber].type=4; + } else + if(strcmp(size,"32")==0) + { + patch[patchnumber].type=3; + } else + if(strcmp(size,"16")==0) + { + patch[patchnumber].type=2; + } else + if(strcmp(size,"8")==0) + { + patch[patchnumber].type=1; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid size attribute.\n"); + patchnumber=0; + return -1; + } + + sscanf( address, "%X", &patch[ patchnumber ].addr ); + sscanf( value, "%I64X", &patch[ patchnumber ].data ); + + patch[patchnumber].enabled=penabled?1:0; + + string pt; + + if(ptitle) + pt.assign(ptitle); + else + pt.clear(); + + Patch p=Patch(patchnumber,gIndex,penabled,pt); + patches.push_back(p); + + patchnumber++; + + cpatch = cpatch->NextSibling("PATCH"); + } + + cpatch = group->FirstChild("GROUP"); + while(cpatch) { + int result=LoadGroup(cpatch,gIndex); + if(result) return result; + cpatch = cpatch->NextSibling("GROUP"); + } + + return 0; +} diff --git a/pcsx2/zlib/ChangeLog b/pcsx2/zlib/ChangeLog new file mode 100644 index 0000000000..85b82536b9 --- /dev/null +++ b/pcsx2/zlib/ChangeLog @@ -0,0 +1,722 @@ + + ChangeLog file for zlib + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occuring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id: ChangeLog,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/pcsx2/zlib/Makefile.am b/pcsx2/zlib/Makefile.am new file mode 100644 index 0000000000..ff26496e22 --- /dev/null +++ b/pcsx2/zlib/Makefile.am @@ -0,0 +1,6 @@ +noinst_LIBRARIES = libpcsx2zlib.a + +libpcsx2zlib_a_SOURCES = \ +adler32.c crc32.c deflate.h inffast.c inflate.c inftrees.h trees.h zlib.h \ +crc32.h gzio.c inffast.h inflate.h uncompr.c zutil.c \ +compress.c deflate.c infback.c inffixed.h inftrees.c trees.c zconf.h zutil.h diff --git a/pcsx2/zlib/README b/pcsx2/zlib/README new file mode 100644 index 0000000000..718aab288a --- /dev/null +++ b/pcsx2/zlib/README @@ -0,0 +1,126 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.1 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install" For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or +descrip.mms. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.1 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/pcsx2/zlib/adler32.c b/pcsx2/zlib/adler32.c new file mode 100644 index 0000000000..bc0842f01b --- /dev/null +++ b/pcsx2/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/pcsx2/zlib/compress.c b/pcsx2/zlib/compress.c new file mode 100644 index 0000000000..e7ea2c518b --- /dev/null +++ b/pcsx2/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/pcsx2/zlib/crc32.c b/pcsx2/zlib/crc32.c new file mode 100644 index 0000000000..aa8b984a34 --- /dev/null +++ b/pcsx2/zlib/crc32.c @@ -0,0 +1,311 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/pcsx2/zlib/crc32.h b/pcsx2/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/pcsx2/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/pcsx2/zlib/deflate.c b/pcsx2/zlib/deflate.c new file mode 100644 index 0000000000..efe7b63aba --- /dev/null +++ b/pcsx2/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/pcsx2/zlib/deflate.h b/pcsx2/zlib/deflate.h new file mode 100644 index 0000000000..26775e9d12 --- /dev/null +++ b/pcsx2/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/pcsx2/zlib/gzio.c b/pcsx2/zlib/gzio.c new file mode 100644 index 0000000000..4cfd64fc45 --- /dev/null +++ b/pcsx2/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/pcsx2/zlib/infback.c b/pcsx2/zlib/infback.c new file mode 100644 index 0000000000..5cf5d22cf9 --- /dev/null +++ b/pcsx2/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/pcsx2/zlib/inffast.c b/pcsx2/zlib/inffast.c new file mode 100644 index 0000000000..63aa4402fc --- /dev/null +++ b/pcsx2/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/pcsx2/zlib/inffast.h b/pcsx2/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/pcsx2/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/pcsx2/zlib/inffixed.h b/pcsx2/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/pcsx2/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/pcsx2/zlib/inflate.c b/pcsx2/zlib/inflate.c new file mode 100644 index 0000000000..71fe3ccd0e --- /dev/null +++ b/pcsx2/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/pcsx2/zlib/inflate.h b/pcsx2/zlib/inflate.h new file mode 100644 index 0000000000..b6965127b9 --- /dev/null +++ b/pcsx2/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/pcsx2/zlib/inftrees.c b/pcsx2/zlib/inftrees.c new file mode 100644 index 0000000000..55fd27b601 --- /dev/null +++ b/pcsx2/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/pcsx2/zlib/inftrees.h b/pcsx2/zlib/inftrees.h new file mode 100644 index 0000000000..1dbfe53a6a --- /dev/null +++ b/pcsx2/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/pcsx2/zlib/trees.c b/pcsx2/zlib/trees.c new file mode 100644 index 0000000000..d0bce9f2f1 --- /dev/null +++ b/pcsx2/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/pcsx2/zlib/trees.h b/pcsx2/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/pcsx2/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/pcsx2/zlib/uncompr.c b/pcsx2/zlib/uncompr.c new file mode 100644 index 0000000000..82ebef75f8 --- /dev/null +++ b/pcsx2/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/pcsx2/zlib/zconf.h b/pcsx2/zlib/zconf.h new file mode 100644 index 0000000000..b073c9e60d --- /dev/null +++ b/pcsx2/zlib/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/pcsx2/zlib/zlib.h b/pcsx2/zlib/zlib.h new file mode 100644 index 0000000000..d54ac9433f --- /dev/null +++ b/pcsx2/zlib/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/pcsx2/zlib/zutil.c b/pcsx2/zlib/zutil.c new file mode 100644 index 0000000000..db137f8a48 --- /dev/null +++ b/pcsx2/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/pcsx2/zlib/zutil.h b/pcsx2/zlib/zutil.h new file mode 100644 index 0000000000..e300f7c767 --- /dev/null +++ b/pcsx2/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/build.sh b/plugins/build.sh new file mode 100644 index 0000000000..bb2ab17500 --- /dev/null +++ b/plugins/build.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +curdir=`pwd` + +cd ${curdir}/gs +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/cdvd +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/dev9 +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/fw +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/pad +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/spu2 +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/usb +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/plugins/cdvd/CDVDbin/readme.ps1.txt b/plugins/cdvd/CDVDbin/readme.ps1.txt new file mode 100644 index 0000000000..7fd7f29a49 --- /dev/null +++ b/plugins/cdvd/CDVDbin/readme.ps1.txt @@ -0,0 +1,52 @@ +CDiso FPSE plugin +================= + +This software is distributed "AS IS" and the authors decline all responsability for all damages (hardware, software and economic) derived by the use of this software. + + +What's this? +------------ +This plugin allows you to load in FPSE ISO images of games directly from your hard-disk. +There is no need of any configiration, just select it: when you run FPSE it will pop up a dialog where you can choose the image to load. + + +Install +------- +Put CDiso.dll in the plugin directory of FPSE. +Select the plugin with the FPSE config tool. + + +What's new +---------- +1.0: first release... it compiles & works (at least on my sistem) :-) + + +Known issues +------------ +If you move around the "Select iso" dialog it will close and you will have to restart FPSE. + + +Notes +----- +I'm not an experienced programmer and I don't want to take credit of work that I've not done... +The plugin is _heavily_ based on the sources of CDctrl plugin (I think by LDChen) found on Bero's page (www.geocities.co.jp/Playtown/2004) and on the open source cdriso PSEmu plugin for linux by Linuzappz. +They've done most of the work, I've introduced most of the bugs ;-) + + +Sources +------- +I've decided to release the sources of the plugin and you should have found them togheter with the dll and this readme. +The sources are not covered by any license so you can do with them whatever you want, but if you find a bug or implement a new feature it would be very nice if you let me know and if you help me to improve this plugin instead of starting another one... This is the best I can do at the moment and having some feedback would help me to learn programming better! + +To compile you'll need the FPSE SDK that can be found at the FPSE site: +http://fpse.emuunlim.com + + +Thanks to the FPSE team and to all the PSX emulation scene. + + +_xobro_@tin.it + + + + diff --git a/plugins/cdvd/CDVDbin/readme.txt b/plugins/cdvd/CDVDbin/readme.txt new file mode 100644 index 0000000000..ba5ec0af0f --- /dev/null +++ b/plugins/cdvd/CDVDbin/readme.txt @@ -0,0 +1,94 @@ +CDVDbin v0.67 +--------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Using: +----- + Place the file "CDVDbin.dll" in the Plugins directory + of the Emulator to use it. + If you have a cdaudio image, go to config dialog of the plugin and check + "Force CD Audio on detection failure". CDDA support is limmited in this + version. + +Note: +----- +-I'm using a method for detection of images that can lead to misdetections. + So, if the plugin shows a dialog box that says that the image is an ISO + and you KNOW it is a BIN (2352 bytes/sector) or BIN that is in fact an ISO, + please notice me. +-The detection might work on some other image formats. You can check the + "Debug messages" box in config dialog and then open the image using + "All files" filter. If the image works and it is not a *known* type, + please notice me. +-Officialy known types: (bytes/sec) + bin(+cue), //2352 + toc info file + iso, //2048 (it is not recommended to use such) + img(+ccd+sub), //2352 + toc info file + subchannel file + bwi, //2353 (i don't know much about this type) + mdf(+mds), //2352/2448 + toc info file (2448-2352=96 => full subchannel) + nrg //2048/2352/2448 as mdf type, the subq info is in the file, + at the end of the image there are toc infos +-A splitted image is a sequence of files that have a common name and a trailing + number. The number starts from 0 or 1. To choose such an image in Open dialog, + select "All Files" filter and pick one of the splits. + +Thanks: +------ + Xobro, this is a port of his FPSE cd plugin + Linuzappz + +Changes: +------- + v0.67: + * Up to date to the latest CDVD specs v3 (0.4.3) + * Bugfix for small files + + v0.66: + * Added "All Files" filter + * Added some CDDA support :P + * Support for splitted image files + * Support for *.mds + + v0.65: + * Up to date to the latest CDVD specs v2 (0.4.0) + * Added support for RAW+SUBQ images (2352+96=2448 bytes/sector) + * Easier detection, ready for subq;) + + v0.64: + * Up to date to the latest CDVD specs + * Better detection of images (ISO2048/RAW2352) + This allows one to use an incomplete/bad image + * Added *.nrg support (Nero images) + + v0.63: + * Added *.bwi to open dialog (Blind Write images) + + v0.62: + * Small fix to file pointer in order to handle + big files (64bit pointer). (hi bositman;) + + v0.61: + * Added *.img to open dialog (CloneCD images) + + v0.6: + * Changed for PS2E Definitions v0.2.9 (beta) specs; CDVDopen() + * Fixed OFN_NOCHANGEDIR issue; thx linuzappz;) + + v0.5: + * Added a config dialog + + v0.4: + + v0.3: + * Automatic iso/bin detection + + v0.2: + + v0.1: + * First Release/Port + * Tested with Pcsx2 + + Email: diff --git a/plugins/cdvd/CDVDbin/src/CDVD.h b/plugins/cdvd/CDVDbin/src/CDVD.h new file mode 100644 index 0000000000..41179fb0bb --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVD.h @@ -0,0 +1,90 @@ +#ifndef __CDVD_H__ +#define __CDVD_H__ + +#include + +#define CDVDdefs +#include "PS2Edefs.h" + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(__WIN32__) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +#endif /* __CDVD_H__ */ \ No newline at end of file diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.c b/plugins/cdvd/CDVDbin/src/CDVDbin.c new file mode 100644 index 0000000000..18be273329 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.c @@ -0,0 +1,679 @@ + /****************************************************************************\ + * CDVDbin PLUGIN for PS2 emus (PCSX2) based on + * CDiso PLUGIN for FPSE + * + * + * AUTHOR: Xobro, mail: _xobro_@tin.it + * + * WHAT'S NEW: It compiles and it seems to work! ;-) + * + * TO DO: cue/ccd reading; tracks stuff; + * subchannel reading + * registry or ini save of iso/bin name + * detection of other types of CD/DVD + * proper audio support + * + * PORTED BY FLORIN + * +\****************************************************************************/ + +#include +#include +#include + +#include "CDVD.h" +#include "resource.h" + +///////////////////////////////////////////////////////////////// +// Internal variables & defines +///////////////////////////////////////////////////////////////// +#define OpenFile(a) CreateFile(a, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,\ + NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) + +static HANDLE hinstance = (HANDLE)-1; + +#define RAW_SECTOR_SIZE 2352 +#define DATA_SECTOR_SIZE 2048 // not used at the moment +#define RAWQ_SECTOR_SIZE (RAW_SECTOR_SIZE+96) +//#define ?_SECTOR_SIZE (RAW_SECTOR_SIZE+16) + +//#define MSF2SECT(m,s,f) (((m)*60+(s)-2)*75+(f)) + +#define INT2BCD(a) ((a)/10*16+(a)%10) + +static HANDLE hISOFile; + +#define MAXFILENAMELENGHT 512 +char ISOFileName[MAXFILENAMELENGHT] = {0}, format[MAXFILENAMELENGHT] = {0}; + +static int sectorsize, //0==2048; 1==2352; 2==2448 + offset, cdtype, cdtraystatus, debug=0, forcecdda=0; + +static u8 readBuffer[RAWQ_SECTOR_SIZE], *pbuffer, *subqbuffer; +static u32 first, last, crt; +static __int64 unitsize; +static cdvdTN diskInfo={0, 0}; +static cdvdTD tracks[100]; + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = lba / (60*75); + *s = (lba / 75) % 60; + *f = lba % 75; +} + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +///////////////////////////////////////////////////////////////// +// generic plugin stuff +///////////////////////////////////////////////////////////////// +const unsigned char version = PS2E_CDVD_VERSION; // CDVD library v2 +const unsigned char revision = VERSION; +const unsigned char build = BUILD; // increase that with each version + +static char *libraryName = "CDVDbin Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_CDVD; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return version<<16|revision<<8|build; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "CDVDbin Msg", 0); +} + +///////////////////////////////////////////////////////////////// +// CDVDinit: plugin init +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDinit() { + //some defaults + hISOFile = NULL; + cdtype=CDVD_TYPE_NODISC; // no image loaded + cdtraystatus=CDVD_TRAY_OPEN; // no image loaded + sectorsize=0; // *bad* value + offset=0; // no offset in the file + // till the beginning of the data + return 0; +} + +HANDLE detectMultipleSplits(__int64 *filesize){ + __int64 size; + HANDLE h; + int len, filenamelen=strlen(ISOFileName); + + first=last=0; + + for (len=filenamelen; len && ISOFileName[len-1]>='0' && ISOFileName[len-1]<='9'; len--); + ISOFileName[len]=0; + len=filenamelen-len; + if (len){ + sprintf(format, "%s%%0%dd", ISOFileName, len); + + for (first=0; first<2; first++){//check for first if it is 0 or 1 + sprintf(ISOFileName, format, first); + if ((h = OpenFile(ISOFileName)) != INVALID_HANDLE_VALUE){ + for (last=first; h != INVALID_HANDLE_VALUE; h = OpenFile(ISOFileName)){ + (*(u32*)(&size))=GetFileSize(h, ((u32*)(&size))+1); + *filesize+=size; + CloseHandle(h); + sprintf(ISOFileName, format, ++last); + } + last--; + if (last>first && debug) + SysMessage("Found multiple files (%d->%d) with format:\n\"%s\"\n" + "Total size=%I64d / Unit size=%I64d", + first, last, format, *filesize, (*filesize-size)/(last-first)); + break; + } + } + if (first == 2) return INVALID_HANDLE_VALUE; + }else + strcpy(format, ISOFileName); + + sprintf(ISOFileName, format, crt=first); + return OpenFile(ISOFileName); +} + +int detect(__int64 filesize){ + register struct cdVolDesc *volDesc; + register u32 sectors; + + if (CDVDreadTrack(16, CDVD_MODE_2048) == -1) { + SysMessage("file too small"); + return CDVD_TYPE_ILLEGAL; + } + volDesc = (struct cdVolDesc *)CDVDgetBuffer(); + if (memcmp(volDesc->volID, "CD001", 5)) + return CDVD_TYPE_DETCT; + + if (memcmp(volDesc->sysIdName, "PLAYSTATION", 11)) + SysMessage("Warrning: Not a Playstation disc?"); + + sectors=(u32)(filesize / sectorsize); + + diskInfo.strack =1; + diskInfo.etrack =1; + memset(tracks, 0, sizeof(cdvdTD) * 100); + tracks[0].lsn=sectors-offset; + tracks[0].type =(volDesc->rootToc.tocSize == DATA_SECTOR_SIZE) ? + CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD; //simple & lame detection:p + + tracks[1].lsn=0; + tracks[1].type =CDVD_MODE2_TRACK; + + if (debug || (filesize % sectorsize)) + SysMessage("%s (%d bytes/sector - offset=%d) %s %simage detected\n" + "Datasize: %I64d\n" + "Sectors: %d LSN:%d\n%s", + offset ? "NRG" : + sectorsize==DATA_SECTOR_SIZE ? "ISO" : + sectorsize==RAW_SECTOR_SIZE ? "RAW" : "RAW+SUBQ", + sectorsize, offset, + volDesc->rootToc.tocSize == DATA_SECTOR_SIZE ? "CD" : "DVD", + last>first ? "splitted " : "", + filesize, sectors, + tracks[0].lsn, + filesize % sectorsize ? "Warrning: Truncated!" : ""); + + return tracks[0].type; +} + +///////////////////////////////////////////////////////////////// +// CDVDopen: CD hw init +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDopen() { + __int64 filesize=0; + + OPENFILENAME ofn = {sizeof(OPENFILENAME), // size + NULL, // owner + NULL, // hInstance + "CD/DVD images (*.bin;*.iso;*.img;*.bwi;*.mdf;*.nrg)\0*.bin;*.iso;*.img;*.bwi;*.mdf;*.nrg\0" + "RAW(2352) CD/DVD images (*.bin;*.img;*.bwi;*.mdf)\0*.bin;*.img;*.bwi;*.mdf\0" + "ISO(2048) CD/DVD images (*.iso)\0*.iso\0" + "NERO CD/DVD images (*.nrg)\0*.nrg\0" + "All Files (*.*)\0*.*\0" + ,// filter + 0, // custom filter + 0, // max custom filter + 0, // filter index + (char *)&ISOFileName, // file name + MAXFILENAMELENGHT, // max filename lenght + 0, // file title + 0, // max file title + NULL, // initial dir + "Select a CD/DVD image...", // title + OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,// flags + 0, // file offset + 0, // file extension + 0, // def ext + 0, // cust data + 0, // hook + 0}; // template + + //clean any old stuff + if (hISOFile){ + CloseHandle(hISOFile); + hISOFile = NULL; + } + + cdtype=CDVD_TYPE_NODISC; // no image loaded + cdtraystatus=CDVD_TRAY_OPEN; // no image loaded + + if (!ISOFileName[0]) + if(!GetOpenFileName(&ofn)) //Common open file dialog + return 0; + //no image/dusc loaded => null plugin + + //detect & open the selected file (or first if more than 1) + hISOFile = detectMultipleSplits(&filesize); + + cdtraystatus=CDVD_TRAY_CLOSE; + cdtype=CDVD_TYPE_UNKNOWN; + + if (hISOFile == INVALID_HANDLE_VALUE){ + SysMessage("error opening the file\n"); + cdtype=CDVD_TYPE_ILLEGAL; + return 0; + } + + (*(u32*)(&unitsize))=GetFileSize(hISOFile, ((u32*)(&unitsize))+1); + if (!filesize) filesize=unitsize;//in case of non-splitted images + + sectorsize=DATA_SECTOR_SIZE; offset=0; //ISO 2048 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + sectorsize=RAW_SECTOR_SIZE; offset=0; //RAW 2352 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + sectorsize=RAWQ_SECTOR_SIZE; offset=0; //RAWQ 2448 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + filesize-=156;//ending junk + + sectorsize=DATA_SECTOR_SIZE; offset=150; //NERO ISO 2048 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + sectorsize=RAW_SECTOR_SIZE; offset=150; //NERO RAW 2352 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + sectorsize=RAWQ_SECTOR_SIZE; offset=150; //NERO RAWQ 2448 detection + cdtype=detect(filesize); + if (cdtype!=CDVD_TYPE_DETCT) return 0; + + if (forcecdda && (filesize>RAW_SECTOR_SIZE)){ + u32 sectors=(u32)(filesize/(sectorsize=RAW_SECTOR_SIZE)); + offset=0; //FIXME: offset for nero images + + memset(tracks, 0, sizeof(cdvdTD) * 100); + diskInfo.strack =1; + diskInfo.etrack =1; + tracks[0].lsn=sectors-offset; + tracks[0].type =cdtype=CDVD_TYPE_CDDA;//DVDV; + + tracks[1].lsn=0; + tracks[1].type =CDVD_AUDIO_TRACK; + + if (debug) + SysMessage("CDDA (%d bytes/sector - offset=%d) image\n" + "Datasize: %I64d\n" + "Sectors: %d LSN:%d\n", + sectorsize, offset, + filesize, sectors, + tracks[0].lsn); + return 0; + } + + //nothing detected + SysMessage("The file you picked is not a usable cd/dvd image\n"); + CloseHandle(hISOFile); + hISOFile=NULL; + cdtraystatus=CDVD_TRAY_OPEN; + cdtype=CDVD_TYPE_NODISC; + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDclose: CD shutdown +///////////////////////////////////////////////////////////////// +void CALLBACK CDVDclose() { + CloseHandle(hISOFile); + CDVDinit(); +} + +///////////////////////////////////////////////////////////////// +// CDVDshutdown: plugin shutdown +///////////////////////////////////////////////////////////////// +void CALLBACK CDVDshutdown() { +} + +///////////////////////////////////////////////////////////////// +// CDVDreadTrack: read 1(one) sector/frame (2352 bytes) +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + u32 nbytesRead, chunk; + s32 Ret; + __int64 filepos; + + pbuffer = readBuffer; + subqbuffer = readBuffer+RAW_SECTOR_SIZE; + + memset(readBuffer, 0, RAWQ_SECTOR_SIZE); + + //if no iso selected act as a null CD plugin + if (hISOFile == NULL) + return 0; + + // Set the file pointer at the right sector + filepos=(__int64)(lsn+offset)*sectorsize; + chunk=(u32)(filepos / unitsize); + filepos-=chunk * unitsize; + chunk+=first; + if (chunk!=crt){ + crt=chunk; + CloseHandle(hISOFile); + sprintf(ISOFileName, format, crt); + hISOFile=OpenFile(ISOFileName); + } + SetFilePointer (hISOFile, + *(u32*)(&filepos), + ((u32*)(&filepos))+1, + FILE_BEGIN); + + Ret = ReadFile(hISOFile, + readBuffer+(sectorsize==DATA_SECTOR_SIZE?12+12:0), + sectorsize, &nbytesRead, NULL); + + if (Ret && nbytesRead < (u32)sectorsize && crtctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDgetTN: tracks number +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + //if no iso selected act as a null CD plugin + if (hISOFile == NULL){ + Buffer->strack = 1; + Buffer->etrack = 1; + return 0; + } + + //should be read from .cue + memcpy(Buffer, &diskInfo, sizeof(cdvdTN)); + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDgetTD: track start end addresses +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer) { + //if no iso selected act as a null CD plugin + if (hISOFile == NULL) + return -1; + + if (Track>diskInfo.etrack) + return -1; + + memcpy(Buffer, &tracks[Track], sizeof(cdvdTD)); + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDgetTOC: get comlpete toc +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDgetTOC(void* toc) { + u8 type = CDVDgetDiskType(); + u8* tocBuff = (u8*)toc; + + if( type == CDVD_TYPE_DVDV || + type == CDVD_TYPE_PS2DVD) + { + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm; + s32 i, err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDgetDiskType: type of the disc: CD/DVD +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDgetDiskType() { + if (debug) SysMessage("CDVDgetType() == %02X", cdtype); + return cdtype; +} + +///////////////////////////////////////////////////////////////// +// CDVDgetTrayStatus: the status of the tray +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDgetTrayStatus() { + if (debug) SysMessage("CDVDgetTrayStatus() == %02X", cdtraystatus); + return cdtraystatus; +} + +///////////////////////////////////////////////////////////////// +// CDVDctrlTrayOpen: open the disc tray +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} + +///////////////////////////////////////////////////////////////// +// CDVDctrlTrayClose: close the disc tray +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + OPENFILENAME ofn = {sizeof(OPENFILENAME), // size + NULL, // owner + NULL, // hInstance + "CD/DVD images (*.bin;*.iso;*.img;*.bwi;*.mdf;*.nrg)\0*.bin;*.iso;*.img;*.bwi;*.mdf;*.nrg\0" + "RAW(2352) CD/DVD images (*.bin;*.img;*.bwi;*.mdf)\0*.bin;*.img;*.bwi;*.mdf\0" + "ISO(2048) CD/DVD images (*.iso)\0*.iso\0" + "NERO CD/DVD images (*.nrg)\0*.nrg\0" + "All Files (*.*)\0*.*\0" + ,// filter + 0, // custom filter + 0, // max custom filter + 0, // filter index + (char *)&ISOFileName, // file name + MAXFILENAMELENGHT, // max filename lenght + 0, // file title + 0, // max file title + NULL, // initial dir + "Select a CD/DVD image...",// title + OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,// flags + 0, // file offset + 0, // file extension + 0, // def ext + 0, // cust data + 0, // hook + 0}; // template + + switch(uMsg) { + case WM_INITDIALOG: + CheckDlgButton(hW, IDC_DEBUG, debug ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hW, IDC_CDDA, forcecdda ? BST_CHECKED : BST_UNCHECKED); + if (ISOFileName && *ISOFileName){ + SetDlgItemText(hW, IDC_FILE, ISOFileName); + CheckDlgButton(hW, IDC_FILE, BST_CHECKED); + }else + CheckDlgButton(hW, IDC_FILE, BST_UNCHECKED); + return TRUE; + + case WM_COMMAND: + switch(HIWORD(wParam)){ + case BN_CLICKED: + switch(LOWORD(wParam)) { + case IDC_FILE: + if (!IsDlgButtonChecked(hW, IDC_FILE)){ + CheckDlgButton(hW, IDC_FILE, BST_UNCHECKED); + ISOFileName[0]='\0'; + SetDlgItemText(hW, IDC_FILE, "Choose a CD/DVD bin or iso image..."); + }else{ + if (GetOpenFileName(&ofn)){ + CheckDlgButton(hW, IDC_FILE, BST_CHECKED); + SetDlgItemText(hW, IDC_FILE, ISOFileName); + }else + CheckDlgButton(hW, IDC_FILE, BST_UNCHECKED); + } + return TRUE; + + case IDOK: + debug=IsDlgButtonChecked(hW, IDC_DEBUG); + forcecdda=IsDlgButtonChecked(hW, IDC_CDDA); + EndDialog(hW, FALSE); + return TRUE; + } + } + + } + return FALSE; +} + +///////////////////////////////////////////////////////////////// +// CDVDconfigure: config dialog, if any... +///////////////////////////////////////////////////////////////// +void CALLBACK CDVDconfigure(){ + DialogBox(hinstance, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +///////////////////////////////////////////////////////////////// +// CDVDabout: about dialog, if any... +///////////////////////////////////////////////////////////////// +void CALLBACK CDVDabout() { + SysMessage("%s %d.%d\n" + "PS1 version by: Xobro, mail: _xobro_@tin.it\n" + "PS2 version by: Florin, mail: florin@ngemu.com", libraryName, revision, build); +} + +///////////////////////////////////////////////////////////////// +// CDVDtest: test hw and report if it works +///////////////////////////////////////////////////////////////// +s32 CALLBACK CDVDtest() { + FILE *f; + + if (cdtype==CDVD_TYPE_ILLEGAL) + return -1; + + if (*ISOFileName == 0) + return 0; + + f = fopen(ISOFileName, "rb"); + if (f == NULL) + return -1; + fclose(f); + + return 0; //if (sectorsize==2048) return 40;//PSE_CDR_WARN_LAMECD; +} + +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved){ + hinstance = (HINSTANCE)hModule; + return TRUE; +} diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.def b/plugins/cdvd/CDVDbin/src/CDVDbin.def new file mode 100644 index 0000000000..5264ca2f4e --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.def @@ -0,0 +1,29 @@ +; CDVDbin.def : Declares the module parameters for the DLL. + +LIBRARY "CDVDbin" +DESCRIPTION 'CDVD BIN/ISO Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDreadTrack @9 + CDVDgetBuffer @10 + CDVDreadSubQ @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDgetTOC @14 + CDVDgetDiskType @15 + CDVDgetTrayStatus @16 + CDVDctrlTrayOpen @17 + CDVDctrlTrayClose @18 + + CDVDconfigure @19 + CDVDtest @20 + CDVDabout @21 + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.dsp b/plugins/cdvd/CDVDbin/src/CDVDbin.dsp new file mode 100644 index 0000000000..64d8708a03 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.dsp @@ -0,0 +1,139 @@ +# Microsoft Developer Studio Project File - Name="CDVDbin" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=CDVDBIN - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "CDVDbin.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "CDVDbin.mak" CFG="CDVDBIN - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CDVDbin - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CDVDbin - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CDVDbin - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDBIN_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDBIN_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=67 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\CDVDbin.dll" + +!ELSEIF "$(CFG)" == "CDVDbin - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "CDVDbin___Win32_Debug" +# PROP BASE Intermediate_Dir "CDVDbin___Win32_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "CDVDbin___Win32_Debug" +# PROP Intermediate_Dir "CDVDbin___Win32_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDBIN_EXPORTS" /D "__WIN32__" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MT /W3 /GX /Od /D "WIN32" /D "DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDBIN_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=67 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"D:\TEMP2\emus\pcsx2.042\Plugins\CDVDbin.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\CDVDbin.dll" + +!ENDIF + +# Begin Target + +# Name "CDVDbin - Win32 Release" +# Name "CDVDbin - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\CDVDbin.c +# End Source File +# Begin Source File + +SOURCE=.\CDVDbin.def +# End Source File +# Begin Source File + +SOURCE=.\CDVDbin.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="C:\Program Files\Microsoft Visual Studio\Vc98\Include\Basetsd.h" +# End Source File +# Begin Source File + +SOURCE=.\CDVD.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Etypes.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\readme.ps1.txt +# End Source File +# Begin Source File + +SOURCE=..\readme.txt +# End Source File +# End Target +# End Project diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.dsw b/plugins/cdvd/CDVDbin/src/CDVDbin.dsw new file mode 100644 index 0000000000..e44885f2cc --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CDVDbin"=".\CDVDbin.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.ncb b/plugins/cdvd/CDVDbin/src/CDVDbin.ncb new file mode 100644 index 0000000000000000000000000000000000000000..e24d9bc91177ce1670460d38f80b9b57eebe8af8 GIT binary patch literal 52224 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 literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.rc b/plugins/cdvd/CDVDbin/src/CDVDbin.rc new file mode 100644 index 0000000000..8503a3d46e --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.rc @@ -0,0 +1,151 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Romanian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ROM) +#ifdef _WIN32 +LANGUAGE LANG_ROMANIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 266, 68 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure CDVDbin" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Close",IDOK,209,47,50,14 + CONTROL "Choose a CD/DVD bin or iso image...",IDC_FILE,"Button", + BS_AUTOCHECKBOX | BS_PUSHLIKE | BS_MULTILINE | + WS_TABSTOP,7,20,252,21 + LTEXT "Click this to choose an image to use or else you will be asked for one at runtime:", + IDC_STATIC,7,7,252,11 + CONTROL "Debug Messages",IDC_DEBUG,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,51,69,10 + CONTROL "Force CD Audio on detection failure",IDC_CDDA,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,79,51,125,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO MOVEABLE PURE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,6,6 + PRODUCTVERSION 1,0,6,6 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "simple and easy bin/iso plugin; thanks Xobro; it is not optimised in either way; it is for testing & to serve as a template\0" + VALUE "CompanyName", "-\0" + VALUE "FileDescription", "CDVDbin\0" + VALUE "FileVersion", "1, 0, 6, 7\0" + VALUE "InternalName", "CDVDbin\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "CDVDbin.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "CDVDbin/iso plugin for P©SX2\0" + VALUE "ProductVersion", "1, 0, 6, 7\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // Romanian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.sln b/plugins/cdvd/CDVDbin/src/CDVDbin.sln new file mode 100644 index 0000000000..ab5d55ed77 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDbin", "CDVDbin.vcproj", "{50921BF5-D9DE-4264-92CF-7001E117CFC3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.ActiveCfg = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.Build.0 = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.ActiveCfg = Release|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.sln.old b/plugins/cdvd/CDVDbin/src/CDVDbin.sln.old new file mode 100644 index 0000000000..0e67c48c26 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.sln.old @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDbin", "CDVDbin.vcproj", "{50921BF5-D9DE-4264-92CF-7001E117CFC3}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.ActiveCfg = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.Build.0 = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.ActiveCfg = Release|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.suo b/plugins/cdvd/CDVDbin/src/CDVDbin.suo new file mode 100644 index 0000000000000000000000000000000000000000..401ec8daa3331d8918a546ba7d14937ed6533632 GIT binary patch literal 8704 zcmeHMOKclO82+84G-=ZG{h&ZGO<$D8IB81LRs}V7l156J5~oQIkt*BSv~C@5u-%uM zN2NvV~)nFhJf(e6Q=s9?EB4Jv%Uo5^IXMiEpO;2zq6 zJK(j>mf<3ll=oub5@0>B0oVv!3Ty%{12zLGbK(Nr+dD8MCVpx0O1C6XCglR8TRyCn zMOm9)UE;IXe*Nf&iElph)MDIaDiL55hV*v_$13-b&Ht_g>JaeXIbMOP@Yd@0FW=7kDth!)cj< zTw+Ql#rW7RHJ&w?k2YH_efsSlAVJ$PWuoia2Wb1JFW?&4&%M^;bh#33tAJb+d07iw z2V4)lAGiU?u@BniMwAcR^+!-{0=57*1GfOT0=EIT10MzM06qrX3Dh*XRze%v+U<6$ zCI9IjpWnOi_Dg^szIvc8&jtAXK41XPG3b0;*&_8mh4-k8%UR$U`hzk8j3}EJLvIqj zV>anr%{l70_~i*{!>IhxPJZXgzn+WslK=+QI*x!l6CNcAOP&-jtSyF>(W8vX0P0cI zpTd|4<$Fiamcq)z80D1^+Rk9rG4y-ICx_vihwxiz(*{?!r#^fBHXKQMvS)M_mRIxZi2eOk&lPeoj*?9Xf@+C`JUp6XUa? zo;jK9!~SzGNt>W1E%9LJr3?t=X&hr>9Q!f>UUJr?-{(UQ=fa1@o%RLRx+-}x9#Vh& zkcA)7Bp?T+Lw2L|yLzJ7FZM)LkEX%z-B50u`@2ftsmp+I^;{=E*SzIHxXxs@*JO`s zpZCA*p|-ErGKb1Gc`jlZe%Tv@UPWPPleT6#b^ZwYQm}zyp1=?NW4>T%UwQh+GX(P$ zLNWR}7Yt(8)4{@Ih-msA5_S zxt#$unt=9O5};SeU*Y}|+Csf*J{dmHs=eNA_am}l1ZmH1z)9Ni>z2DN(`{9o_ zE^UiUcBsbYYa8OX8(Icm$UJxJ`loMpduWAp2l?qGjx&tWQ{Xa%n85Re2Rk{N=05Ee zRtx+;|jVHlg@R9&B$Bsh+ z^wE~zp2?-P4$7$uTu0%tc)~W2RrB^Ej@cUJ3YGM#++92fqq2uX`O z?%0{fU1NRl>!d{BIhMC8<9S?K9%xFffHB6pZ{U9CTY%HH=3gEGte(Ck1uZ5I=WHHl zW|~~dOu+q%GNMZ256|R!Chdor2lMpD%$qW`yfwKf4x~@oG-8&;M_auQq4>lecocFW z)i9)E05v~WT*&3w_V5|SrYhpUbN%@mHe>pd4a=*b@5QWjw&C6z_DFlDJ?2}+eA!%S ze^8kIvFnUy%%>9IusWO9w;I)aujyCok9n`RENGmKMGbGjOr(=$Tq%8BFq~Ey_mX1+ z{oYXYq%o;pmj+|uxOu|cJswM&Nv?ePfEkI!4ezKC@%EU>N%eU{-rJIZIXPt}j6_;> zE**^}#?5o7-0-?X!vp=CtT_;mO-0Oba@;!gyaVT{sFVlf{X6}x21=;|mZE^Dy50kfTDd!=_)!`knrt9xa9JfVX{VsEBEw zT?)~2x39P9)18;QekXk$@A_2sWP+3PZW2Y`*MdGzSF0+Z--)q|*97i=Dl2vFv^x{9 z#ua)p{x_kM>3ucp&*iq(|3A6=#|to8>ZEc!g~;Q~Sh@c1#ccZjpMn!t(4lp&-1R%B e?rT~3%-4&Cx?g;$_gZ|U@20bFq5l8hfqwzgnS!AJ literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj b/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj new file mode 100644 index 0000000000..8f3ea90513 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj.old b/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj.old new file mode 100644 index 0000000000..5f24ecdabd --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin.vcproj.old @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin_2003.sln b/plugins/cdvd/CDVDbin/src/CDVDbin_2003.sln new file mode 100644 index 0000000000..75d28e9c19 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin_2003.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDbin", "CDVDbin_2003.vcproj", "{50921BF5-D9DE-4264-92CF-7001E117CFC3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.ActiveCfg = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug.Build.0 = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.ActiveCfg = Release|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin_2003.vcproj b/plugins/cdvd/CDVDbin/src/CDVDbin_2003.vcproj new file mode 100644 index 0000000000..8f3ea90513 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin_2003.vcproj @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.sln b/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.sln new file mode 100644 index 0000000000..883127d072 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDbin", "CDVDbin_vsnet2005beta1.vcproj", "{50921BF5-D9DE-4264-92CF-7001E117CFC3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|Win64 (AMD64) = Debug|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug|Win32.ActiveCfg = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug|Win32.Build.0 = Debug|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug|Win64 (AMD64).ActiveCfg = Debug|Win64 (AMD64) + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Debug|Win64 (AMD64).Build.0 = Debug|Win64 (AMD64) + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release|Win32.ActiveCfg = Release|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release|Win32.Build.0 = Release|Win32 + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {50921BF5-D9DE-4264-92CF-7001E117CFC3}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.vcproj b/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.vcproj new file mode 100644 index 0000000000..01339df1f5 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbin_vsnet2005beta1.vcproj @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDbin/src/CDVDbinro.rc b/plugins/cdvd/CDVDbin/src/CDVDbinro.rc new file mode 100644 index 0000000000..38da02e4ba --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/CDVDbinro.rc @@ -0,0 +1,141 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Romanian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ROM) +#ifdef _WIN32 +LANGUAGE LANG_ROMANIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 267, 69 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configurare CDVDbin" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "Închide",IDOK,210,48,50,14 + CONTROL "Alegeþi o imagine bin sau iso de CD/DVD...",IDC_FILE, + "Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | BS_MULTILINE | + WS_TABSTOP,7,20,253,21 + LTEXT "Apasã pentru a alege o imagine de folosit sau altfel veþi fi întrebat în timpul rulãrii:", + IDC_STATIC,7,7,253,11 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 62 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,6,1 + PRODUCTVERSION 1,0,6,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041804b0" + BEGIN + VALUE "Comments", "plugin simplu de bin/iso; mulþumiri lui Xobro; nu e optimizat de nici un fel; a fost fãcut pentru teste si sã serveascã de exemplu" + VALUE "CompanyName", "-" + VALUE "FileDescription", "CDVDbin" + VALUE "FileVersion", "1, 0, 6, 1" + VALUE "InternalName", "CDVDbin" + VALUE "LegalCopyright", "Copyright © 2002" + VALUE "OriginalFilename", "CDVDbin.dll" + VALUE "ProductName", "plugin CDVDbin/iso pentru P©SX2" + VALUE "ProductVersion", "1, 0, 6, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x418, 1200 + END +END + +#endif // Romanian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/cdvd/CDVDbin/src/PS2Edefs.h b/plugins/cdvd/CDVDbin/src/PS2Edefs.h new file mode 100644 index 0000000000..2380136e1b --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/PS2Edefs.h @@ -0,0 +1,723 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.9 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetCSR(u64 *csr); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetCSR)(u64 * csr); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetCSR GSsetCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDbin/src/PS2Etypes.h b/plugins/cdvd/CDVDbin/src/PS2Etypes.h new file mode 100644 index 0000000000..1ff2b7cfc6 --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) || defined(__WIN32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDbin/src/resource.h b/plugins/cdvd/CDVDbin/src/resource.h new file mode 100644 index 0000000000..b4142cb1ff --- /dev/null +++ b/plugins/cdvd/CDVDbin/src/resource.h @@ -0,0 +1,19 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CDVDbin.rc +// +#define IDD_CONFIG 101 +#define IDC_FILE 1000 +#define IDC_DEBUG 1001 +#define IDC_CDDA 1002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/cdvd/CDVDdraft/Src/AboutBox.cpp b/plugins/cdvd/CDVDdraft/Src/AboutBox.cpp new file mode 100644 index 0000000000..4f73dd8b9a --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/AboutBox.cpp @@ -0,0 +1,43 @@ +// AboutBox.cpp : implementation file +// + +#include "stdafx.h" +#include "cdvddraft.h" +#include "AboutBox.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutBox dialog + + +CAboutBox::CAboutBox(CWnd* pParent /*=NULL*/) + : CDialog(CAboutBox::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutBox) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutBox::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutBox) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutBox, CDialog) + //{{AFX_MSG_MAP(CAboutBox) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAboutBox message handlers diff --git a/plugins/cdvd/CDVDdraft/Src/AboutBox.h b/plugins/cdvd/CDVDdraft/Src/AboutBox.h new file mode 100644 index 0000000000..5c704029ea --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/AboutBox.h @@ -0,0 +1,46 @@ +#if !defined(AFX_ABOUTBOX_H__D58937A1_2304_11D7_8E29_0050DA15DE89__INCLUDED_) +#define AFX_ABOUTBOX_H__D58937A1_2304_11D7_8E29_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AboutBox.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutBox dialog + +class CAboutBox : public CDialog +{ +// Construction +public: + CAboutBox(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutBox) + enum { IDD = IDD_ABOUT }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutBox) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutBox) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTBOX_H__D58937A1_2304_11D7_8E29_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/Config.cpp b/plugins/cdvd/CDVDdraft/Src/Config.cpp new file mode 100644 index 0000000000..426681e9fa --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/Config.cpp @@ -0,0 +1,172 @@ +// Config.cpp : implementation file +// + +#include "stdafx.h" +#include "cdvddraft.h" +#include "Config.h" +#include + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CConfig dialog + + +CConfig::CConfig(CWnd* pParent /*=NULL*/) + : CDialog(CConfig::IDD, pParent) +{ + //{{AFX_DATA_INIT(CConfig) + m_nInterface = 0; + m_nBuffMode = 0; + m_nDrive = 0; + m_nReadMode = 0; + //}}AFX_DATA_INIT +} + +void CConfig::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConfig) + DDX_Control(pDX, IDC_DRIVE, m_ctrlDrive); + DDX_CBIndex(pDX, IDC_INTERFACE, m_nInterface); + DDX_CBIndex(pDX, IDC_PREFETCH, m_nBuffMode); + DDX_CBIndex(pDX, IDC_DRIVE, m_nDrive); + DDX_CBIndex(pDX, IDC_READMODE, m_nReadMode); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CConfig, CDialog) + //{{AFX_MSG_MAP(CConfig) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CConfig message handlers +BOOL CConfig::OnInitDialog() +{ + int nResult = CDialog::OnInitDialog(); + + TRACE("on init dialog.\n"); + int curr_intf = (CDVD_INTERFACE_TYPE) + cdvd_init(CDVD_INTF_UNKNOWN); + + int init_okay = CDVD_ERROR_FAIL; + + if(curr_intf == CDVD_INTF_UNKNOWN) + { + if(CCdvd::Aspi_CheckValidInstallation() + == CDVD_ERROR_SUCCESS) + { + init_okay = cdvd_init(CDVD_INTF_ASPI); + TRACE("config: init_aspi: %ld\n", init_okay); + } + else if(CCdvd::GetWin32OSType() == WINNTNEW) + { + TRACE("config: init_ioctl: %ld\n", init_okay); + init_okay = cdvd_init(CDVD_INTF_IOCTL); + } + else + { + curr_intf = CDVD_INTF_UNKNOWN; + TRACE("config: init_unknown: %ld\n", init_okay); + } + } + // else already either init to ioctl or aspi + else + { + TRACE("config: already previously init.\n"); + init_okay = CDVD_ERROR_SUCCESS; + } + + if(init_okay == CDVD_ERROR_SUCCESS) + { + ADAPTERINFO info; + int ndrives = cdvd_getnumdrives(); + + if(ndrives > 0) + { + for(int i = 0; i < ndrives; i++) + { + CString str; + info = cdvd_getadapterdetail(i); + str.Format(_T(" %d:%d:%d %s"), + info.ha, info.id, info.lun, info.name + ); + TRACE("str: %s\n", str); + m_ctrlDrive.InsertString(i, str); + } + } + else + { + MessageBox(_T("Unable to locate c/dvd drives on this computer\n"), + _T("Drive Error"), + MB_OK|MB_ICONERROR); + } + + if(curr_intf == CDVD_INTF_UNKNOWN && + init_okay == CDVD_ERROR_SUCCESS) + cdvd_shutdown(); + } + + LoadConfig(); + + return TRUE; +} + +void CConfig::OnOK() +{ + SaveConfig(); + CDialog::OnOK(); +} + +///////////////////////////////////////////////////////////////////////////// +// save/load stuff +BOOL CConfig::SaveConfig() +{ + CRegKey rKey; + + if(rKey.Create(HKEY_CURRENT_USER, PLUGIN_REG_PATH) == ERROR_SUCCESS) + { + UpdateData(TRUE); + if(m_nDrive != -1) + { + rKey.SetValue(m_nDrive, _T("DriveNum")); + rKey.SetValue(m_nBuffMode, _T("BuffMode")); + rKey.SetValue(m_nInterface, _T("Interface")); + rKey.SetValue(m_nReadMode, _T("ReadMode")); + } + rKey.Close(); + } + + return TRUE; +} + +BOOL CConfig::LoadConfig() +{ + CRegKey rKey; + + if(rKey.Create(HKEY_CURRENT_USER, PLUGIN_REG_PATH) == ERROR_SUCCESS) + { + DWORD val; + + if(rKey.QueryValue(val, _T("DriveNum")) == ERROR_SUCCESS) + m_nDrive = val; + if(rKey.QueryValue(val, _T("BuffMode")) == ERROR_SUCCESS) + m_nBuffMode = val; + if(rKey.QueryValue(val, _T("Interface")) == ERROR_SUCCESS) + m_nInterface = val; + if(rKey.QueryValue(val, _T("ReadMode")) == ERROR_SUCCESS) + m_nReadMode = val; + + UpdateData(FALSE); + rKey.Close(); + } + + return TRUE; +} diff --git a/plugins/cdvd/CDVDdraft/Src/Config.h b/plugins/cdvd/CDVDdraft/Src/Config.h new file mode 100644 index 0000000000..5fee7f2d9c --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/Config.h @@ -0,0 +1,54 @@ +#if !defined(AFX_CONFIG_H__A5E8FC61_C0A7_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CONFIG_H__A5E8FC61_C0A7_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Config.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConfig dialog + +class CConfig : public CDialog +{ +// Construction +public: + CConfig(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CConfig) + enum { IDD = IDD_CONFIG }; + CComboBox m_ctrlDrive; + int m_nInterface; + int m_nBuffMode; + int m_nDrive; + int m_nReadMode; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConfig) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL SaveConfig(); + virtual BOOL LoadConfig(); + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CConfig) + // NOTE: the ClassWizard will add member functions here + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONFIG_H__A5E8FC61_C0A7_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/PS2Edefs.h b/plugins/cdvd/CDVDdraft/Src/PS2Edefs.h new file mode 100644 index 0000000000..2380136e1b --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/PS2Edefs.h @@ -0,0 +1,723 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.9 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetCSR(u64 *csr); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetCSR)(u64 * csr); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetCSR GSsetCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDdraft/Src/PS2Etypes.h b/plugins/cdvd/CDVDdraft/Src/PS2Etypes.h new file mode 100644 index 0000000000..3a63c58b85 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDdraft/Src/ReadMe.txt b/plugins/cdvd/CDVDdraft/Src/ReadMe.txt new file mode 100644 index 0000000000..69fa721b2d --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/ReadMe.txt @@ -0,0 +1,66 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : cdvddraft +======================================================================== + + +AppWizard has created this cdvddraft DLL for you. This DLL not only +demonstrates the basics of using the Microsoft Foundation classes but +is also a starting point for writing your DLL. + +This file contains a summary of what you will find in each of the files that +make up your cdvddraft DLL. + +cdvddraft.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +cdvddraft.h + This is the main header file for the DLL. It declares the + CCdvddraftApp class. + +cdvddraft.cpp + This is the main DLL source file. It contains the class CCdvddraftApp. + + +cdvddraft.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +cdvddraft.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +res\cdvddraft.rc2 + This file contains resources that are not edited by Microsoft + Visual C++. You should place all resources not editable by + the resource editor in this file. + +cdvddraft.def + This file contains information about the DLL that must be + provided to run with Microsoft Windows. It defines parameters + such as the name and description of the DLL. It also exports + functions from the DLL. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named cdvddraft.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDdraft/Src/StdAfx.cpp b/plugins/cdvd/CDVDdraft/Src/StdAfx.cpp new file mode 100644 index 0000000000..e6db7477ab --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// cdvddraft.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/plugins/cdvd/CDVDdraft/Src/StdAfx.h b/plugins/cdvd/CDVDdraft/Src/StdAfx.h new file mode 100644 index 0000000000..ebaf2ce4bc --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/StdAfx.h @@ -0,0 +1,41 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A0D50EAA_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_STDAFX_H__A0D50EAA_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC OLE classes +#include // MFC OLE dialog classes +#include // MFC Automation classes +#endif // _AFX_NO_OLE_SUPPORT + + +#ifndef _AFX_NO_DB_SUPPORT +#include // MFC ODBC database classes +#endif // _AFX_NO_DB_SUPPORT + +#ifndef _AFX_NO_DAO_SUPPORT +#include // MFC DAO database classes +#endif // _AFX_NO_DAO_SUPPORT + +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A0D50EAA_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/aspi.cpp b/plugins/cdvd/CDVDdraft/Src/aspi.cpp new file mode 100644 index 0000000000..5720c31a1b --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/aspi.cpp @@ -0,0 +1,842 @@ +// Aspi.cpp: implementation of the aspi methods +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "cdvd.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +#define MOVESCSIDWORD(pdwSrc,pdwDst) \ +{\ + ((PBYTE)(pdwDst))[0] = ((PBYTE)(pdwSrc))[3];\ + ((PBYTE)(pdwDst))[1] = ((PBYTE)(pdwSrc))[2];\ + ((PBYTE)(pdwDst))[2] = ((PBYTE)(pdwSrc))[1];\ + ((PBYTE)(pdwDst))[3] = ((PBYTE)(pdwSrc))[0];\ +} + +#define MOVESCSIWORD(pwSrc,pwDst) \ +{\ + ((PBYTE)(pwDst))[0] = ((PBYTE)(pwSrc))[1];\ + ((PBYTE)(pwDst))[1] = ((PBYTE)(pwSrc))[0];\ +} + + +/***********************************************************/ +/* ASPI Init/Shutdown related methods */ +/***********************************************************/ + +// using MFC classes, no aspi in other systems. +int CCdvd::Aspi_CheckValidInstallation() +{ + int retval = CDVD_ERROR_FAIL; + + CFileStatus fstat; + TCHAR szDir[MAX_PATH]; + + if(GetSystemDirectory(szDir,MAX_PATH)) + { + CString directory = szDir; + WIN32OSTYPE ostype = GetWin32OSType(); + + if(ostype != WINNTNEW && ostype != WINNTOLD) + { + if(CFile::GetStatus(directory+_T("\\wnaspi32.dll"), fstat) && + CFile::GetStatus(directory+_T("\\winaspi.dll"), fstat) && + CFile::GetStatus(directory+_T("\\iosubsys\\apix.vxd"), fstat)) + { + retval = CDVD_ERROR_SUCCESS; + } + } + else + { + if(CFile::GetStatus(directory+_T("\\wnaspi32.dll"), fstat) && + CFile::GetStatus(directory+_T("\\drivers\\aspi32.sys"), fstat)) + { + retval = CDVD_ERROR_SUCCESS; + } + } + } + else + { + // are you crazy? o_O, no fucking windows directory? o_O + retval = CDVD_ERROR_FAIL; + } + + return retval; + +} + +// called once to init Aspi +int CCdvd::Aspi_Init() +{ + int retval = CDVD_ERROR_FAIL; + if(m_bAspiInitialized) + return CDVD_ERROR_SUCCESS; + + if(Aspi_CheckValidInstallation() == CDVD_ERROR_SUCCESS) + { + if((m_hAspi = AfxLoadLibrary("WNASPI32")) != NULL) + { + SendASPI32Command = (CDROMSendASPI32Command) GetProcAddress(m_hAspi,"SendASPI32Command"); + GetASPI32SupportInfo = (CDROMGetASPI32SupportInfo) GetProcAddress(m_hAspi,"GetASPI32SupportInfo"); + + if(SendASPI32Command != NULL && + GetASPI32SupportInfo != NULL) + { + UI32 support_info = GetASPI32SupportInfo(); + if( HIBYTE(LOWORD(support_info)) != SS_COMP && + HIBYTE(LOWORD(support_info)) != SS_NO_ADAPTERS ) + { + Aspi_Shutdown(); + } + else + { + if(InitializeBuffers() == CDVD_ERROR_SUCCESS) + { + if(Aspi_ScsiBusScan() == CDVD_ERROR_SUCCESS) + { + SetCurrentBuffer(0); + m_bAspiInitialized = TRUE; + retval = CDVD_ERROR_SUCCESS; + GetNumSectors = Aspi_GetNumSectors; + GetToc = Aspi_GetToc; + // GetHeader = Aspi_GetHeader; + SetSpeed = Aspi_SetSpeed; + Stop = Aspi_Stop; + SetSectorSize = Aspi_SetSectorSize; + Play = Aspi_Play; + TestReady = Aspi_TestReady; + ReadSector = Dummy_T4; + UpdateInterfaceObject(); + } + } + } + } + else + { + Aspi_Shutdown(); + } + } + } + + return retval; +} + +// shuts down aspi +int CCdvd::Aspi_Shutdown() +{ + int retval = CDVD_ERROR_SUCCESS; + + // gota detect the read_mode first before i do this + // but just reset to 2048 for now. + Aspi_SetSectorSize(CDVD_SECTOR_SIZE_DVD); + + // the old ASPI drivers suck shit to hell and damnation, + // freeing them up immediately after init will crash sometimes + ::Sleep(200); + + if(m_hAspi != NULL) + AfxFreeLibrary(m_hAspi); + m_hAspi = NULL; + + SendASPI32Command = NULL; + GetASPI32SupportInfo = NULL; + + GetNumSectors = Dummy_T1; + GetToc = Dummy_T1; + Stop = Dummy_T1; + Play = Dummy_T3; + TestReady = Dummy_T1; +// GetHeader = Dummy_T1; + SetSpeed = Dummy_T2; + SetSectorSize = Dummy_T2; + ReadSector = Dummy_T4; + UpdateInterfaceObject(); + + ShutdownBuffers(); + + m_bAspiInitialized = FALSE; + + return retval; +} + +// open a drive for reading +int CCdvd::Aspi_OpenDrive(int drv_num) +{ + int retval = CDVD_ERROR_SUCCESS; + CloseDrive(); + m_nCurrentDrive = drv_num; + + return retval; +} + +// dummy for now +int CCdvd::Aspi_CloseDrive() +{ + int retval = CDVD_ERROR_SUCCESS; + m_nCurrentDrive = -1; + + return retval; +} + +// get srb status +int CCdvd::Aspi_GetSrbStatus(int srb_num) +{ + int retval = CDVD_SRB_ERROR; + switch(m_nCurrentReadMode) + { + case CDVD_READ_MMC: retval = m_srbReadCd [srb_num].SRB_Status; break; + case CDVD_READ_SCSI10: retval = m_srbRead10 [srb_num].SRB_Status; break; + case CDVD_READ_D8: retval = m_srbReadMat [srb_num].SRB_Status; break; + case CDVD_READ_D410: retval = m_srbReadSony[srb_num].SRB_Status; break; + case CDVD_READ_D412: retval = m_srbReadNec [srb_num].SRB_Status; break; + default: break; + } + + if(retval == SS_COMP) retval = CDVD_SRB_COMPLETED; + else if(retval == SS_PENDING) retval = CDVD_SRB_PENDING; + else //if(retval == SS_ERR) + retval = CDVD_SRB_ERROR; + + return retval; +} + +// set read mode +int CCdvd::Aspi_SetReadMode(CDVD_READ_MODE read_mode) +{ + int retval = CDVD_ERROR_SUCCESS; + + switch(read_mode) + { + case CDVD_READ_MMC: ReadSector = Aspi_ReadSector_mmc; break; + case CDVD_READ_SCSI10: TRACE("cdvdlib: setting scsi10 readmode.\n"); + ReadSector = Aspi_ReadSector_scsi10; + if(((this)->*(SetSectorSize))((m_nMmcDataMode == CDVD_MMC_DATAMODE_RAW) ? + CDVD_SECTOR_SIZE_CD : CDVD_SECTOR_SIZE_DVD) != CDVD_ERROR_SUCCESS) + { + retval = CDVD_ERROR_FAIL; + } + break; + case CDVD_READ_D8: ReadSector = Aspi_ReadSector_matsu; break; + case CDVD_READ_D410: ReadSector = Aspi_ReadSector_sony; break; + case CDVD_READ_D412: ReadSector = Aspi_ReadSector_nec; break; + default: retval = CDVD_ERROR_FAIL; break; + } + + UpdateInterfaceObject(); + + return retval; +} + +// search for scsi adapters with c/dvd drives. +int CCdvd::Aspi_ScsiBusScan() +{ + int retval = CDVD_ERROR_SUCCESS; + + SRB_HAInquiry srbHAInquiry; + m_nDrives = 0; + memset(m_drvDetails, 0, CDVD_MAX_SUPPORTED_DRIVES * sizeof(ADAPTERINFO)); + memset(&srbHAInquiry, 0, sizeof (SRB_HAInquiry) ); + + srbHAInquiry.SRB_Cmd = SC_HA_INQUIRY; + srbHAInquiry.SRB_HaId = 0; + + SendASPI32Command ((LPSRB) &srbHAInquiry); + if (srbHAInquiry.SRB_Status != SS_COMP) + { + return CDVD_ERROR_FAIL; + } + + UI08 HA_Count = srbHAInquiry.HA_Count; + srbHAInquiry.HA_ManagerId[16] = 0; + + for (UI08 HA_num = 0; HA_num < HA_Count; HA_num++) + { + char szHA_num[10]; + itoa((int) HA_num, szHA_num, 10); + memset(&srbHAInquiry, 0, sizeof(SRB_HAInquiry)); + srbHAInquiry.SRB_Cmd = SC_HA_INQUIRY; + srbHAInquiry.SRB_HaId = HA_num; + + SendASPI32Command ((LPSRB) &srbHAInquiry); + if (srbHAInquiry.SRB_Status != SS_COMP) + { + return CDVD_ERROR_FAIL; + } + else + { + srbHAInquiry.HA_Identifier[16] = 0; + for (UI08 SCSI_Id = 0; SCSI_Id < 8; SCSI_Id++) + { + char szSCSI_Id[10]; + itoa ((int) SCSI_Id, szSCSI_Id, 10); + for(UI08 SCSI_Lun = 0; SCSI_Lun < 8; SCSI_Lun++) + { + char szSCSI_Lun[10]; + itoa ((int) SCSI_Lun, szSCSI_Lun, 10); + + SRB_GDEVBlock srbGDEVBlock; + memset(&srbGDEVBlock, 0, sizeof(srbGDEVBlock)); + srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE; + srbGDEVBlock.SRB_HaId = HA_num; + srbGDEVBlock.SRB_Target = SCSI_Id; + srbGDEVBlock.SRB_Lun = SCSI_Lun; + SendASPI32Command ((LPSRB) &srbGDEVBlock); + if (srbGDEVBlock.SRB_Status != SS_COMP || + srbGDEVBlock.SRB_DeviceType != DTYPE_CDROM) continue; + + char temp[40]; + if(Aspi_ScsiInquiry(HA_num, SCSI_Id, SCSI_Lun, temp) == CDVD_ERROR_SUCCESS) + { + if(m_nDrives < CDVD_MAX_SUPPORTED_DRIVES) + { + TRACE("drive %ld: [%ld:%ld:%ld] - %s %s\n", m_nDrives, HA_num, SCSI_Id, SCSI_Lun, + m_drvDetails[m_nDrives].hostname, + temp); + m_drvDetails[m_nDrives].ha = HA_num; + m_drvDetails[m_nDrives].id = SCSI_Id; + m_drvDetails[m_nDrives].lun = SCSI_Lun; + strcpy(m_drvDetails[m_nDrives].hostname, (const char*) srbHAInquiry.HA_Identifier); + strcpy(m_drvDetails[m_nDrives].name, temp); + ++m_nDrives; + } + else + { + break; + } + } + else + { + retval = CDVD_ERROR_FAIL; + break; + } + } + } + } + } + + return retval; +} + +// retrieve ha info +int CCdvd::Aspi_ScsiInquiry(UI08 ha, UI08 id, UI08 lun, char *destination) +{ + int retval = CDVD_ERROR_SUCCESS; + + UI08 buffer[36]; + SRB_ExecSCSICmd srb; + + memset(buffer, 0x20, sizeof(buffer)); + memset(&srb, 0, sizeof(SRB_ExecSCSICmd)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = ha; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_Target = id; + srb.SRB_Lun = lun; + srb.SRB_BufLen = 36; + srb.SRB_BufPointer = buffer; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_CDBLen = 6; + srb.CDBByte[0] = SCSI_INQUIRY; + srb.CDBByte[4] = 36; // allocation length per buffer + + if (Aspi_ExecuteSrb(srb, NULL, 0) == CDVD_ERROR_SUCCESS) + { + memcpy(destination, buffer + 8, 27); + destination[27] = '\0'; + } + else + { + destination[0] = '\0'; + } + + return retval; +} + +/***********************************************************/ +/* ASPI Execute SRB */ +/***********************************************************/ +// if HANDLE = NULL, SRB is synchronous, else its asynchronous +int CCdvd::Aspi_ExecuteSrb(SRB_ExecSCSICmd &srbExec, HANDLE *handle, int nretry) +{ + int retval = CDVD_ERROR_SUCCESS; + + ++nretry; + // lets do sync with handle == NULL + if(handle == NULL) + { + TRACE("executing synchronous SRB.\n"); + while(nretry) + { + HANDLE heventExec = CreateEvent( NULL, TRUE, FALSE, NULL ); + if(heventExec) // do event based notification + { + srbExec.SRB_Flags |= SRB_EVENT_NOTIFY; + srbExec.SRB_PostProc = (LPVOID)heventExec; + + DWORD dwASPIStatus = SendASPI32Command((LPSRB) &srbExec); + if(dwASPIStatus == SS_ERR) + { + CloseHandle(heventExec); + return CDVD_ERROR_FAIL; + } + + if(dwASPIStatus == SS_PENDING) + { + WaitForSingleObject(heventExec, INFINITE); + } + CloseHandle(heventExec); + } + else // do shitty polling + { + SendASPI32Command((LPSRB)&srbExec); + while(srbExec.SRB_Status == SS_PENDING); + } + + TRACE("SRB_Status: %ld\n", srbExec.SRB_Status); + if( srbExec.SRB_Status != SS_COMP ) + { + if(nretry-- && + (srbExec.SRB_TargStat != STATUS_CHKCOND || + (srbExec.SenseArea[2] & 0x0F) != KEY_UNITATT) ) + { + UI08 sense = srbExec.SenseArea[2] & 0x0F; + UI08 asc = srbExec.SenseArea[12]; + UI08 ascq = srbExec.SenseArea[13]; + TRACE("sensekey: %02Xh, %02Xh, %02Xh\n", sense, asc, ascq); + continue; + } + } + else + { + // we're done. + break; + } + } + } + else + { + TRACE("executing asynchronous SRB.\n"); + + ResetEvent(*handle); + srbExec.SRB_Flags |= SRB_EVENT_NOTIFY; + srbExec.SRB_PostProc = *handle; + + DWORD dwASPIStatus = SendASPI32Command((LPSRB) &srbExec); + + if(dwASPIStatus == SS_ERR) + { + SetEvent(*handle); + TRACE("SRB unrecoverable error.\n"); + return CDVD_ERROR_FAIL; + } + + if(dwASPIStatus == SS_PENDING) + { + TRACE("SRB Pending completion.\n"); + return CDVD_ERROR_PENDING; + } + + TRACE("SRB completed immediately.\n"); + } + + if(nretry == 0) retval = CDVD_ERROR_FAIL; + return retval; +} + +/***********************************************************/ +/* ASPI C/DVD Methods */ +/***********************************************************/ + +// read using mmc 0xbe command +int CCdvd::Aspi_ReadSector_mmc(int sect, HANDLE *handle) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + m_srbReadCd[m_nCurrentBuffer].SRB_Cmd = SC_EXEC_SCSI_CMD; + m_srbReadCd[m_nCurrentBuffer].SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + m_srbReadCd[m_nCurrentBuffer].SRB_Flags = SRB_DIR_IN | SRB_ENABLE_RESIDUAL_COUNT; + m_srbReadCd[m_nCurrentBuffer].SRB_Target = m_drvDetails[m_nCurrentDrive].id; + m_srbReadCd[m_nCurrentBuffer].SRB_BufPointer = m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer; + m_srbReadCd[m_nCurrentBuffer].SRB_BufLen = m_ReadBuffer[m_nCurrentBuffer].AB_BufLen; + m_srbReadCd[m_nCurrentBuffer].SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + m_srbReadCd[m_nCurrentBuffer].SRB_SenseLen = SENSE_LEN; + + m_srbReadCd[m_nCurrentBuffer].SRB_CDBLen = 12; + m_srbReadCd[m_nCurrentBuffer].CDBByte[0] = 0xBE; + m_srbReadCd[m_nCurrentBuffer].CDBByte[1] = 0x00; + m_srbReadCd[m_nCurrentBuffer].CDBByte[2] = HIBYTE(HIWORD(sect)); + m_srbReadCd[m_nCurrentBuffer].CDBByte[3] = LOBYTE(HIWORD(sect)); + m_srbReadCd[m_nCurrentBuffer].CDBByte[4] = HIBYTE(LOWORD(sect)); + m_srbReadCd[m_nCurrentBuffer].CDBByte[5] = LOBYTE(LOWORD(sect)); + m_srbReadCd[m_nCurrentBuffer].CDBByte[6] = 0x00; + m_srbReadCd[m_nCurrentBuffer].CDBByte[7] = 0x00; + m_srbReadCd[m_nCurrentBuffer].CDBByte[8] = CDVD_NUM_SECTORS_PER_BUFF; + m_srbReadCd[m_nCurrentBuffer].CDBByte[9] = (UI08) m_nMmcDataMode; + m_srbReadCd[m_nCurrentBuffer].CDBByte[10] = 0x00; + m_srbReadCd[m_nCurrentBuffer].CDBByte[11] = 0x00; + + return Aspi_ExecuteSrb(m_srbReadCd[m_nCurrentBuffer], handle, CDVD_MAX_RETRY); +} + +// read using scsi-10 (0x28) command, size is dependent on SetSectorSize +int CCdvd::Aspi_ReadSector_scsi10(int sect, HANDLE *handle) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + m_srbRead10[m_nCurrentBuffer].SRB_Cmd = SC_EXEC_SCSI_CMD; + m_srbRead10[m_nCurrentBuffer].SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + m_srbRead10[m_nCurrentBuffer].SRB_Flags = SRB_DIR_IN;// | SRB_ENABLE_RESIDUAL_COUNT; + m_srbRead10[m_nCurrentBuffer].SRB_Target = m_drvDetails[m_nCurrentDrive].id; + m_srbRead10[m_nCurrentBuffer].SRB_BufPointer = m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer; + m_srbRead10[m_nCurrentBuffer].SRB_BufLen = m_ReadBuffer[m_nCurrentBuffer].AB_BufLen; + m_srbRead10[m_nCurrentBuffer].SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + m_srbRead10[m_nCurrentBuffer].SRB_SenseLen = SENSE_LEN; + + m_srbRead10[m_nCurrentBuffer].SRB_CDBLen = 10; + m_srbRead10[m_nCurrentBuffer].CDBByte[0] = 0x28; + m_srbRead10[m_nCurrentBuffer].CDBByte[1] = 0x00; + m_srbRead10[m_nCurrentBuffer].CDBByte[2] = HIBYTE(HIWORD(sect)); + m_srbRead10[m_nCurrentBuffer].CDBByte[3] = LOBYTE(HIWORD(sect)); + m_srbRead10[m_nCurrentBuffer].CDBByte[4] = HIBYTE(LOWORD(sect)); + m_srbRead10[m_nCurrentBuffer].CDBByte[5] = LOBYTE(LOWORD(sect)); + m_srbRead10[m_nCurrentBuffer].CDBByte[6] = 0x00; + m_srbRead10[m_nCurrentBuffer].CDBByte[7] = 0x00; + m_srbRead10[m_nCurrentBuffer].CDBByte[8] = CDVD_NUM_SECTORS_PER_BUFF; + m_srbRead10[m_nCurrentBuffer].CDBByte[9] = 0x00; + + return Aspi_ExecuteSrb(m_srbRead10[m_nCurrentBuffer], handle, CDVD_MAX_RETRY); +} + +// read using proprietary matsushita command, heck if it works +int CCdvd::Aspi_ReadSector_matsu(int sect, HANDLE *handle) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + m_srbReadMat[m_nCurrentBuffer].SRB_Cmd = SC_EXEC_SCSI_CMD; + m_srbReadMat[m_nCurrentBuffer].SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + m_srbReadMat[m_nCurrentBuffer].SRB_Flags = SRB_DIR_IN | SRB_ENABLE_RESIDUAL_COUNT; + m_srbReadMat[m_nCurrentBuffer].SRB_Target = m_drvDetails[m_nCurrentDrive].id; + m_srbReadMat[m_nCurrentBuffer].SRB_BufPointer = m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer; + m_srbReadMat[m_nCurrentBuffer].SRB_BufLen = m_ReadBuffer[m_nCurrentBuffer].AB_BufLen; + m_srbReadMat[m_nCurrentBuffer].SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + m_srbReadMat[m_nCurrentBuffer].SRB_SenseLen = SENSE_LEN; + + m_srbReadMat[m_nCurrentBuffer].SRB_CDBLen = 12; + m_srbReadMat[m_nCurrentBuffer].CDBByte[0] = 0xd4; + m_srbReadMat[m_nCurrentBuffer].CDBByte[1] = 0x00; + m_srbReadMat[m_nCurrentBuffer].CDBByte[2] = HIBYTE(HIWORD(sect)); + m_srbReadMat[m_nCurrentBuffer].CDBByte[3] = LOBYTE(HIWORD(sect)); + m_srbReadMat[m_nCurrentBuffer].CDBByte[4] = HIBYTE(LOWORD(sect)); + m_srbReadMat[m_nCurrentBuffer].CDBByte[5] = LOBYTE(LOWORD(sect)); + m_srbReadMat[m_nCurrentBuffer].CDBByte[6] = 0x00; + m_srbReadMat[m_nCurrentBuffer].CDBByte[7] = 0x00; + m_srbReadMat[m_nCurrentBuffer].CDBByte[8] = CDVD_NUM_SECTORS_PER_BUFF; + m_srbReadMat[m_nCurrentBuffer].CDBByte[9] = 0x00; + m_srbReadMat[m_nCurrentBuffer].CDBByte[10] = 0x00; + m_srbReadMat[m_nCurrentBuffer].CDBByte[11] = 0x00; + + return Aspi_ExecuteSrb(m_srbReadMat[m_nCurrentBuffer], handle, CDVD_MAX_RETRY); +} + +// read using proprietary sony command, heck if it works +int CCdvd::Aspi_ReadSector_sony(int sect, HANDLE *handle) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + m_srbReadSony[m_nCurrentBuffer].SRB_Cmd = SC_EXEC_SCSI_CMD; + m_srbReadSony[m_nCurrentBuffer].SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + m_srbReadSony[m_nCurrentBuffer].SRB_Flags = SRB_DIR_IN | SRB_ENABLE_RESIDUAL_COUNT; + m_srbReadSony[m_nCurrentBuffer].SRB_Target = m_drvDetails[m_nCurrentDrive].id; + m_srbReadSony[m_nCurrentBuffer].SRB_BufPointer = m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer; + m_srbReadSony[m_nCurrentBuffer].SRB_BufLen = m_ReadBuffer[m_nCurrentBuffer].AB_BufLen; + m_srbReadSony[m_nCurrentBuffer].SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + m_srbReadSony[m_nCurrentBuffer].SRB_SenseLen = SENSE_LEN; + + m_srbReadSony[m_nCurrentBuffer].SRB_CDBLen = 12; + m_srbReadSony[m_nCurrentBuffer].CDBByte[0] = 0xd8; + m_srbReadSony[m_nCurrentBuffer].CDBByte[1] = 0x00; + m_srbReadSony[m_nCurrentBuffer].CDBByte[2] = HIBYTE(HIWORD(sect)); + m_srbReadSony[m_nCurrentBuffer].CDBByte[3] = LOBYTE(HIWORD(sect)); + m_srbReadSony[m_nCurrentBuffer].CDBByte[4] = HIBYTE(LOWORD(sect)); + m_srbReadSony[m_nCurrentBuffer].CDBByte[5] = LOBYTE(LOWORD(sect)); + m_srbReadSony[m_nCurrentBuffer].CDBByte[6] = 0x00; + m_srbReadSony[m_nCurrentBuffer].CDBByte[7] = 0x00; + m_srbReadSony[m_nCurrentBuffer].CDBByte[8] = CDVD_NUM_SECTORS_PER_BUFF; + m_srbReadSony[m_nCurrentBuffer].CDBByte[9] = 0x00; + m_srbReadSony[m_nCurrentBuffer].CDBByte[10] = 0x00; + m_srbReadSony[m_nCurrentBuffer].CDBByte[11] = 0x00; + + return Aspi_ExecuteSrb(m_srbReadSony[m_nCurrentBuffer], handle, CDVD_MAX_RETRY); +} + +// read using proprietary nec command, heck if it works +int CCdvd::Aspi_ReadSector_nec(int sect, HANDLE *handle) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + m_srbReadNec[m_nCurrentBuffer].SRB_Cmd = SC_EXEC_SCSI_CMD; + m_srbReadNec[m_nCurrentBuffer].SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + m_srbReadNec[m_nCurrentBuffer].SRB_Flags = SRB_DIR_IN | SRB_ENABLE_RESIDUAL_COUNT; + m_srbReadNec[m_nCurrentBuffer].SRB_Target = m_drvDetails[m_nCurrentDrive].id; + m_srbReadNec[m_nCurrentBuffer].SRB_BufPointer = m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer; + m_srbReadNec[m_nCurrentBuffer].SRB_BufLen = m_ReadBuffer[m_nCurrentBuffer].AB_BufLen; + m_srbReadNec[m_nCurrentBuffer].SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + m_srbReadNec[m_nCurrentBuffer].SRB_SenseLen = SENSE_LEN; + + m_srbReadNec[m_nCurrentBuffer].SRB_CDBLen = 10; + m_srbReadNec[m_nCurrentBuffer].CDBByte[0] = 0xd4; + m_srbReadNec[m_nCurrentBuffer].CDBByte[1] = 0x00; + m_srbReadNec[m_nCurrentBuffer].CDBByte[2] = HIBYTE(HIWORD(sect)); + m_srbReadNec[m_nCurrentBuffer].CDBByte[3] = LOBYTE(HIWORD(sect)); + m_srbReadNec[m_nCurrentBuffer].CDBByte[4] = HIBYTE(LOWORD(sect)); + m_srbReadNec[m_nCurrentBuffer].CDBByte[5] = LOBYTE(LOWORD(sect)); + m_srbReadNec[m_nCurrentBuffer].CDBByte[6] = 0x00; + m_srbReadNec[m_nCurrentBuffer].CDBByte[7] = 0x00; + m_srbReadNec[m_nCurrentBuffer].CDBByte[8] = CDVD_NUM_SECTORS_PER_BUFF; + m_srbReadNec[m_nCurrentBuffer].CDBByte[9] = 0x00; + + return Aspi_ExecuteSrb(m_srbReadNec[m_nCurrentBuffer], handle, CDVD_MAX_RETRY); +} + +// retrieve number of sectors present in c/dvd media +int CCdvd::Aspi_GetNumSectors() +{ + _ASSERT(m_bAspiInitialized == TRUE); + + SRB_ExecSCSICmd srb; + UI08 capacity[8]; + UI32 max_sector; + + memset(&srb, 0, sizeof(SRB_ExecSCSICmd)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_BufLen = 8; + srb.SRB_BufPointer = capacity; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_CDBLen = 10; + + srb.CDBByte[0] = SCSI_RD_CAPAC; + + + if(Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY) + != CDVD_ERROR_SUCCESS) + return 0; // no sectors found + + MOVESCSIDWORD(&capacity[0], &max_sector); + + return max_sector+1; +} + +// retrieve TOC data +int CCdvd::Aspi_GetToc() +{ + _ASSERT(m_bAspiInitialized == TRUE); + + SRB_ExecSCSICmd srb; + UI08 buff[804]; + memset(buff, 0, sizeof(buff)); + memset (&srb, 0, sizeof(SRB_ExecSCSICmd)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_BufPointer = buff; + srb.SRB_BufLen = sizeof(buff); + srb.SRB_CDBLen = 10; + srb.CDBByte[0] = SCSI_READ_TOC; + srb.CDBByte[6] = 0; + srb.CDBByte[7] = 0x03; + srb.CDBByte[8] = 0x24; + + if(Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY) + != CDVD_ERROR_SUCCESS) + return CDVD_ERROR_FAIL; + + if(ExtractTocData(buff) != CDVD_ERROR_SUCCESS) + return CDVD_ERROR_FAIL; + + return CDVD_ERROR_SUCCESS; +} + +// set cdrom speed +int CCdvd::Aspi_SetSpeed(int speed) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + SRB_ExecSCSICmd srb; + UI16 kbSpeed = 0xFFFF; + switch(speed) + { + case 0: kbSpeed = 0xFFFF; break; + case 1: kbSpeed = 176; break; + case 2: kbSpeed = 353; break; + case 3: kbSpeed = 528; break; + case 4: kbSpeed = 706; break; + case 5: kbSpeed = 1400; break; + case 6: kbSpeed = 2800; break; + default: kbSpeed = 0xFFFF; break; // max + } + + memset(&srb,0,sizeof(srb)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_Flags = SRB_DIR_OUT; //|SRB_ENABLE_RESIDUAL_COUNT; + srb.SRB_SenseLen = SENSE_LEN; + + srb.SRB_CDBLen = 12; + srb.CDBByte[0] = 0xBB; + srb.CDBByte[2] = HIBYTE(kbSpeed); + srb.CDBByte[3] = LOBYTE(kbSpeed); + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} + +// used for scsi only, sets sector size (i.e, 2352, 2048) +int CCdvd::Aspi_SetSectorSize(int sect_size) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + TRACE("sectorsize: %ld\n", sect_size); + MODESELHEADER mh; + SRB_ExecSCSICmd srb; + + memset (&srb, 0, sizeof(SRB_ExecSCSICmd)); + memset (&mh, 0, sizeof(MODESELHEADER)); + + mh.block_desc_length = 0x08; + mh.block_length_med = HIBYTE(LOWORD(sect_size)); + mh.block_length_lo = LOBYTE(LOWORD(sect_size)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_Flags = SRB_DIR_OUT; + srb.SRB_BufLen = sizeof(mh); + srb.SRB_BufPointer = (UI08 *) &mh; + srb.SRB_CDBLen = 6; + srb.CDBByte[0] = 0x15; + srb.CDBByte[1] = 0x10; + srb.CDBByte[4] = 0x0C; + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} + +// start cddda playback, dunno if it works right really.. :p +int CCdvd::Aspi_Play(int sect_start, int sect_stop) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + SRB_ExecSCSICmd srb; + + memset( &srb, 0, sizeof(SRB_ExecSCSICmd) ); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_CDBLen = 12; + + srb.CDBByte[0] = 0xa5; + srb.CDBByte[2] = HIBYTE(HIWORD(sect_start)); + srb.CDBByte[3] = LOBYTE(HIWORD(sect_start)); + srb.CDBByte[4] = HIBYTE(LOWORD(sect_start)); + srb.CDBByte[5] = LOBYTE(LOWORD(sect_start)); + srb.CDBByte[6] = HIBYTE(HIWORD(sect_stop)); + srb.CDBByte[7] = LOBYTE(HIWORD(sect_stop)); + srb.CDBByte[8] = HIBYTE(LOWORD(sect_stop)); + srb.CDBByte[9] = LOBYTE(LOWORD(sect_stop)); +// srb.CDBByte[10] = 0x8F; + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} + +// stop cdda playback, dunno if it works right really.. :p +int CCdvd::Aspi_Stop() +{ + _ASSERT(m_bAspiInitialized == TRUE); + + SRB_ExecSCSICmd srb; + + memset(&srb, 0, sizeof(SRB_ExecSCSICmd)); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_CDBLen = 10; + srb.CDBByte[0] = 0x4E; + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} + +// detect if media/LUN is ready, legacy command, +// can prolly be substituted with GetMediaType(), with some modifs +int CCdvd::Aspi_TestReady() +{ + SRB_ExecSCSICmd srb; + + memset (&srb, 0, sizeof(SRB_ExecSCSICmd)); + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_CDBLen = 6; + srb.CDBByte[0] = SCSI_TST_U_RDY; + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} + +// retrieve feature details +int CCdvd::Aspi_GetConfiguration(UI16 feature, UI08 *dest, UI32 dest_size) +{ + _ASSERT(m_bAspiInitialized == TRUE); + + int retval = CDVD_ERROR_SUCCESS; + + SRB_ExecSCSICmd srb; + memset(&srb, 0, sizeof(SRB_ExecSCSICmd)); + memset(dest, 0, dest_size); + + srb.SRB_Cmd = SC_EXEC_SCSI_CMD; + srb.SRB_HaId = m_drvDetails[m_nCurrentDrive].ha; + srb.SRB_Target = m_drvDetails[m_nCurrentDrive].id; + srb.SRB_Lun = m_drvDetails[m_nCurrentDrive].lun; + srb.SRB_Flags = SRB_DIR_IN; + srb.SRB_SenseLen = SENSE_LEN; + srb.SRB_BufPointer = dest; + srb.SRB_BufLen = dest_size; + + srb.SRB_CDBLen = 12; + srb.CDBByte[0] = 0x46; + srb.CDBByte[1] = 0x02; // return a single feature set ONLY. + srb.CDBByte[2] = HIBYTE(feature); + srb.CDBByte[3] = LOBYTE(feature); + srb.CDBByte[7] = HIBYTE(dest_size); + srb.CDBByte[8] = LOBYTE(dest_size); + + return Aspi_ExecuteSrb(srb, NULL, CDVD_MAX_RETRY); +} diff --git a/plugins/cdvd/CDVDdraft/Src/bitmap1.bmp b/plugins/cdvd/CDVDdraft/Src/bitmap1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0067b8dda25c09f18a64b4921c8d7a1aaa401658 GIT binary patch literal 3726 zcma)4T9J?T`QCY@ zi6Z<4UlO8d$+7j;`tQ=mS8vT#O0$5h>;XS^I(RGWr>XX^x5c$JXQHp>NYNs2TAqsF1- zE?YkP1k49dl_nIiMs+AaZ{+@j^(@*&l~VnBce!(0lz9VbT?b@1Nn0Ajqr?V~}7u7x}*w(c=ca;&kx%%Eei+T>QhZhdia8^dvrMiD1xY=o>D zA8);%dt@zom%7^y*9Du^KiMQ_{4y(|^u;ehcJ8yCx9|)l->nP!n&32TRJ#KVLtK1s z$JTC6HePv6%X7=t6v$7|=Dz=X$CAc)Ij@TKzF`)DM5#S4yrDkpe(1Dib>2H{Bj>gj z+hZV{7v3M+z~)=sM=7o;T4E6*o2nJ`4j1fCf)%)CAB&ny9n$^ZPC= zc&mnPatwPiC=WhkM~15^;9A97Y#3#XYsZ!_um@+MJtv3`24Ft$LR$y6yNcCbI>F}4 zcErnN=F^XKgJPB_Agz~hpuY6lYO;A}b0!Z|=E|uTrJUq zG6+7UT0XeDtsdk03RZ0^k|~guvH^CZG%SM4Lp?YazXb+J62bZThubbfqu}l zjs?38BMtNPH`Yp>sr;6L#hFnR6^IVuSo$^$T4(U`glBMsVk5rWvUxmXP4>!5=Jev4 z(N~C?HP&hY<}d+UM5}7SyNb;V8%m$*U)-6%7E@%-f&xtv*m}Z>T{K0A2nVLo=7H=M zv~>~Q2TSb(tNQ9O*0J)`8TMv14i#pBT5add@7TFx)0#9_d1t{os!>jy;j93MVjoHN zIS=du@x~GP?GKL}66AR?Jqbv3_5@Z0G90Y(kxLy5FQ+?uVM7UyFnqzz6vHm2rgm&S z?E2aU7Lu~nG03LfrXJ{kL{ztNHv#x#j>8Rjr6jV-~VPI zPQ2~3+GyZ2rKWEk?uLDlj;6^I+hNn<@rWg@aZ*&phUQB@_Ir&Q=zKGguT68#l-nNo zen|-^Ip;N}YwR=~2`9#(gq9ah7{UoJwZyetuCeN~h5ZjM4xSsrYts-St=P#KnDHZ8%A~-9m-G4qGe~y zrGd~1#J56~8Q-;qmz$7YDpZyWIP`(-px)c%Q3PzpI)w8x?BnB6?TJPElp3(rh;CGs z(A&|J8y80b?)^GVV2kkwPMB+1TfDQ2r6Qe22d^FoN8PH3dK$S2Wm&jeTw#a4i_@% literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDdraft/Src/cdvd.cpp b/plugins/cdvd/CDVDdraft/Src/cdvd.cpp new file mode 100644 index 0000000000..f8d434791e --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvd.cpp @@ -0,0 +1,616 @@ +// Cdvd.cpp: implementation of the CCdvd class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "Cdvd.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +#if defined(CDVD_SIMPLE_INTERFACE) +// our fuckup method of interfacing ;p +CCdvd OBJECT_HOLDER_CDVD; +CDVD_INTF_FUNC_T1 FUNCTION_GETNUMSECTORS; +CDVD_INTF_FUNC_T1 FUNCTION_GETTOC; +CDVD_INTF_FUNC_T1 FUNCTION_TESTREADY; +CDVD_INTF_FUNC_T2 FUNCTION_SETSPEED; +CDVD_INTF_FUNC_T1 FUNCTION_STOP; +CDVD_INTF_FUNC_T2 FUNCTION_SETSECTORSIZE; +CDVD_INTF_FUNC_T3 FUNCTION_PLAY; +CDVD_INTF_FUNC_T4 FUNCTION_READSECTOR; + +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CCdvd::CCdvd() +{ + m_hIoctlDrv = NULL; + m_hAspi = NULL; + m_bAspiInitialized = FALSE; + m_bIoctlInitialized = FALSE; + m_bDriveOpened = FALSE; + m_nCurrentDrive = -1; + m_nCurrentBuffer = 0; + m_nDrives = 0; + m_IntfType = CDVD_INTF_UNKNOWN; + m_nMmcDataMode = CDVD_MMC_DATAMODE_RAW; + m_nCurrentReadMode = CDVD_READ_MMC; + + memset(m_drvDetails, 0, CDVD_MAX_SUPPORTED_DRIVES * sizeof(ADAPTERINFO)); + memset(m_srbReadCd, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd)); + memset(m_srbRead10, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd)); + memset(m_srbReadMat, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd)); + memset(m_srbReadSony, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd)); + memset(m_srbReadNec, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd)); + memset(m_sptwbReadCd, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF)); + memset(m_sptwbRead10, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF)); + memset(m_sptwbReadMat, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF)); + memset(m_sptwbReadSony, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF)); + memset(m_sptwbReadNec, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF)); + + memset(&m_tocDetails, 0, sizeof(TOCDATA)); + + GetNumSectors = Dummy_T1; + GetToc = Dummy_T1; + Stop = Dummy_T1; + Play = Dummy_T3; + TestReady = Dummy_T1; +// GetHeader = Dummy_T1; + SetSpeed = Dummy_T2; + SetSectorSize = Dummy_T2; + ReadSector = Dummy_T4; + + UpdateInterfaceObject(); +} + +CCdvd::~CCdvd() +{ + CloseDrive(); + Shutdown(); +} + +// based on msdn example +WIN32OSTYPE CCdvd::GetWin32OSType() +{ + WIN32OSTYPE wintype; + UI32 version; + OSVERSIONINFO *osvi; + + version = GetVersion(); + if(version < 0x80000000) + { + osvi = (OSVERSIONINFO *) malloc(sizeof(OSVERSIONINFO)); + if (osvi) + { + memset(osvi, 0, sizeof(OSVERSIONINFO)); + osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(osvi); + if (osvi->dwMajorVersion >= 4L) + wintype = WINNTNEW; + else + wintype = WINNTOLD; + + free(osvi); + } + } + else if (LOBYTE(LOWORD(version)) < 4L) + wintype = WIN32S; + else + wintype = WIN95; + + return wintype; +} + +// Initializes an interface, only one should be initialized. :) +int CCdvd::Init(CDVD_INTERFACE_TYPE intf_type) +{ + int retval = CDVD_ERROR_SUCCESS; + + switch(intf_type) + { + case CDVD_INTF_ASPI: + m_IntfType = CDVD_INTF_ASPI; + Aspi_Init(); + break; + //case CDVD_INTF_IOCTL: + // m_IntfType = CDVD_INTF_IOCTL; + // Ioctl_Init(); + // break; + case CDVD_INTF_UNKNOWN: + if(m_bAspiInitialized) + retval = CDVD_INTF_ASPI; + else + if(m_bIoctlInitialized) retval = CDVD_INTF_IOCTL; + else + retval = CDVD_INTF_UNKNOWN; + break; + + default: + retval = CDVD_ERROR_FAIL; + break; + } + + return retval; +} + +// shutsdown previously opened interface +int CCdvd::Shutdown() +{ + int retval = CDVD_ERROR_SUCCESS; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: + Aspi_Shutdown(); + break; + //case CDVD_INTF_IOCTL: + // Ioctl_Shutdown(); + // break; + default: break; + } + + m_IntfType = CDVD_INTF_UNKNOWN; + + return retval; +} + +// retrieve number of c/dvd drives +int CCdvd::GetNumDrives() const +{ + return m_nDrives; +} + +// open a drive for reading +int CCdvd::OpenDrive(int drv_num) +{ + int retval = CDVD_ERROR_FAIL; + _ASSERT(drv_num < CDVD_MAX_SUPPORTED_DRIVES); + + // run-time check, for now. + if(drv_num > (int) m_nDrives) + return CDVD_ERROR_FAIL; + + m_bDriveOpened = FALSE; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: + if(Aspi_OpenDrive(drv_num) == CDVD_ERROR_SUCCESS) + { + m_bDriveOpened = TRUE; + retval = CDVD_ERROR_SUCCESS; + } + break; + //case CDVD_INTF_IOCTL: + // if(Ioctl_OpenDrive(drv_num) == CDVD_ERROR_SUCCESS) + // { + // m_bDriveOpened = TRUE; + // retval = CDVD_ERROR_SUCCESS; + // } + default: break; + } + + return retval; +} + +// close a previously opened drive +int CCdvd::CloseDrive() +{ + int retval = CDVD_ERROR_SUCCESS; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: Aspi_CloseDrive(); break; + //case CDVD_INTF_IOCTL: Ioctl_CloseDrive(); break; + default: break; + } + + return retval; +} + +// allocate and initialize buffers for BOTH aspi and ioctl +int CCdvd::InitializeBuffers() +{ + int retval = CDVD_ERROR_SUCCESS; + UI32 result = 0xFFFFFFFF; + for(int i=0; i < CDVD_NUM_BUFFERS; i++) + { + if(m_ReadBuffer[i].AB_BufPointer != NULL) continue; + m_ReadBuffer[i].AB_BufLen = CDVD_NUM_SECTORS_PER_BUFF * CDVD_SECTOR_SIZE_CD; + m_ReadBuffer[i].AB_BufPointer = (PBYTE) VirtualAlloc + ( + NULL, + m_ReadBuffer[i].AB_BufLen, + MEM_COMMIT, + PAGE_READWRITE + ); + + result &= (UI32) m_ReadBuffer[i].AB_BufPointer; + if(m_ReadBuffer[i].AB_BufPointer != NULL) + memset(m_ReadBuffer[i].AB_BufPointer, 0, m_ReadBuffer[i].AB_BufLen); + } + + if(result == 0) + { + ShutdownBuffers(); + retval = CDVD_ERROR_FAIL; + TRACE("unable to allocate all buffers\n"); + } + + return retval; +} + +// free-up previously allocated buffers +int CCdvd::ShutdownBuffers() +{ + int retval = CDVD_ERROR_SUCCESS; + + for(int i=0; i < CDVD_NUM_BUFFERS; i++) + { + if(m_ReadBuffer[i].AB_BufPointer != NULL) + VirtualFree( m_ReadBuffer[i].AB_BufPointer, 0, MEM_RELEASE ); + m_ReadBuffer[i].AB_BufPointer = NULL; + m_ReadBuffer[i].AB_BufLen = 0; + } + + return retval; +} + +// set the current buffer to be used +// only 2! at the moment +int CCdvd::SetCurrentBuffer(int buf_num) +{ + int retval = CDVD_ERROR_SUCCESS; + if(buf_num >= CDVD_NUM_BUFFERS) + return CDVD_ERROR_FAIL; + + m_nCurrentBuffer = buf_num; + + return retval; +} + +// this is terribly WRONG :P, but i dont care, works most of the time :p +int CCdvd::ExtractTocData(UI08 *buffer) +{ + int retval = CDVD_ERROR_SUCCESS; + LPTOCDATA pdata = (LPTOCDATA) buffer; + + memcpy(&m_tocDetails, buffer, sizeof(TOCDATA)); + + int total_tracks = 0; + int mediatype = GetCdvdMediaType(); + + UI32 numRead = ((UI32) pdata->datalen_byte1) << 8 | (UI32) (pdata->datalen_byte0); + SetCurrentBuffer(0); + + memset(&m_trkDetails, 0, sizeof(DECODEDTRACKINFO)); + + int offset = 4; + for(int i = 0; i < pdata->last_track_num; i++) + { + offset = i*8+4; + LPTOCTRACKDESCRIPTOR pdesc = (LPTOCTRACKDESCRIPTOR) (buffer + offset); + + UI32 start_track = ((UI32) pdesc->lba_byte3) << 24 | + ((UI32) pdesc->lba_byte2) << 16 | + ((UI32) pdesc->lba_byte1) << 8 | + (UI32) pdesc->lba_byte0; + + // track types, 0x00 - cdda, 0x01 - data, 0x02 - cdxa + UI08 tracktype = 0; + if(mediatype == CDVD_MEDIATYPE_DVD) + { + tracktype = 0x01; // data sector + } + else if(((this)->*(ReadSector))(start_track, NULL) == CDVD_ERROR_SUCCESS) + { + tracktype = (UI08) * (m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer+15); + } + else + { + // skip setting info for this track, and try to proceed with others + ++total_tracks; + continue; + } + // okay, something is fucked.. just lie and say its a cdda :p + if(tracktype > 2) tracktype = 0; + + m_trkDetails.track_offset[i] = start_track; + m_trkDetails.track_type[i] = tracktype; + + TRACE("track %ld -> start_at: %ld with type: %ld\n", i, start_track, tracktype); + ++total_tracks; + } + + if(total_tracks) m_trkDetails.total_tracks = total_tracks; + + return retval; +} + +// set read mode (i.e. mmc, scsi10 etc). +// Note: only mmc and scsi10 is enabled +// i've disabled all goddamn proprietary read modes +// on this version (sony, nec, matsushita) +int CCdvd::SetReadMode(CDVD_READ_MODE read_mode, int data_mode) +{ + _ASSERT(read_mode >= CDVD_READ_MMC && read_mode <= CDVD_READ_SCSI10); + + m_nCurrentReadMode = read_mode; + m_nMmcDataMode = data_mode; + + int retval = CDVD_ERROR_SUCCESS; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: + retval = Aspi_SetReadMode(read_mode); + break; + //case CDVD_INTF_IOCTL: + // retval = Ioctl_SetReadMode(); + // break; + default: + retval = CDVD_ERROR_FAIL; + break; + } + + return CDVD_ERROR_SUCCESS; +} + +// returns CDVD_ERROR_PENDING if SS_PENDING, CDVD_ERROR_SUCCESS if SS_COMP +// and CDVD_ERROR_FAIL if you are a dumbass and you haven't set any read_mode +int CCdvd::GetSrbStatus(int srb_num) +{ + int retval = CDVD_ERROR_SUCCESS; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: + retval = Aspi_GetSrbStatus(srb_num); + break; + //case CDVD_INTF_IOCTL: + // retval = Ioctl_GetSrbStatus(srb_num); + // break; + default: + retval = CDVD_ERROR_FAIL; + break; + } + + return retval; +} + +int CCdvd::GetCdvdConfiguration(UI16 feature, UI08 *dest, UI32 dest_size) +{ + int retval = CDVD_ERROR_SUCCESS; + switch(m_IntfType) + { + case CDVD_INTF_ASPI: + retval = Aspi_GetConfiguration(feature, dest, dest_size); + break; + //case CDVD_INTF_IOCTL: + // retval = Ioctl_GetConfiguration(feature, dest, dest_size); + // break; + default: + retval = CDVD_ERROR_FAIL; + break; + } + + return retval; +} + +const UI16 CDVD_FEATURE_READCD = 0x001E; +const UI16 CDVD_FEATURE_READDVD = 0x001F; + +// as the name says +int CCdvd::GetCdvdDriveType() +{ + int drivetype = CDVD_DRIVETYPE_UNKNOWN; + UI08 buffer[1024]; + UI16 feature_available = 0; + BOOL is_cdromdrive = FALSE; + BOOL is_dvddrive = FALSE; + + if(GetCdvdConfiguration(CDVD_FEATURE_READCD, buffer, sizeof(buffer)) + == CDVD_ERROR_SUCCESS) + { + feature_available = (UI16) buffer[8] << 8 | (UI16) buffer[9]; + if(feature_available == CDVD_FEATURE_READCD) + { + is_cdromdrive = TRUE; + } + } + + if(GetCdvdConfiguration(CDVD_FEATURE_READDVD, buffer, sizeof(buffer)) + == CDVD_ERROR_SUCCESS) + { + feature_available = (UI16) buffer[8] << 8 | (UI16) buffer[9]; + if(feature_available == CDVD_FEATURE_READDVD) + { + is_dvddrive = TRUE; + } + } + + if(is_dvddrive && is_cdromdrive) drivetype = CDVD_DRIVETYPE_CDVD; + if(is_dvddrive && !is_cdromdrive) drivetype = CDVD_DRIVETYPE_DVD; + if(!is_dvddrive && is_cdromdrive) drivetype = CDVD_DRIVETYPE_CD; + + return drivetype; +} + +// as the naem says +int CCdvd::GetCdvdMediaType() +{ + int mediatype = CDVD_MEDIATYPE_UNKNOWN; + UI08 buffer[1024]; + UI08 media; + + if(GetCdvdConfiguration(CDVD_FEATURE_READCD, buffer, sizeof(buffer)) + == CDVD_ERROR_SUCCESS) + { + media = buffer[10] & 0x01; // current loaded media is a cdrom if "Current" bit is on + if(media) + { + return CDVD_MEDIATYPE_CD; + } + } + + if(GetCdvdConfiguration(CDVD_FEATURE_READDVD, buffer, sizeof(buffer)) + == CDVD_ERROR_SUCCESS) + { + media = buffer[10] & 0x01; // current loaded media is a dvd if "Current" bit is on + if(media) + { + return CDVD_MEDIATYPE_DVD; + } + } + + return mediatype; +} + +// automatically detect read_mode as well as set it. +int CCdvd::DetectAndSetReadMode() +{ +#define CHECKMODE(m) memset(m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer, 0xCC, m_ReadBuffer[m_nCurrentBuffer].AB_BufLen); \ + SetReadMode((m), m_nMmcDataMode);\ + if(((this)->*(ReadSector))(0, NULL) == CDVD_ERROR_SUCCESS){\ + if(*((UI32*) m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer) != 0xCCCCCCCC){\ + TRACE("data: %08Xh, detected read mode: %ld\n", *((UI32*) m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer), (m));\ + return (m);\ + }\ + } + + int retval = CDVD_ERROR_FAIL; + if(GetCdvdDriveType() != CDVD_DRIVETYPE_UNKNOWN) + { + int mediatype = GetCdvdMediaType(); + if(mediatype != CDVD_MEDIATYPE_UNKNOWN) // no freaking media present dipshit + { + if(mediatype == CDVD_MEDIATYPE_DVD) + { + m_nMmcDataMode = CDVD_MMC_DATAMODE_USER; + } + else if(mediatype == CDVD_MEDIATYPE_CD) + { + m_nMmcDataMode = CDVD_MMC_DATAMODE_RAW; + } + + // start checking which one will work; + + SetCurrentBuffer(0); + + // lets try scsi10 first, since scsi10/scsi12 is mandatory for dvd's + if(((this)->*(SetSectorSize))((m_nMmcDataMode == CDVD_MMC_DATAMODE_RAW) ? + CDVD_SECTOR_SIZE_CD : CDVD_SECTOR_SIZE_DVD) == CDVD_ERROR_SUCCESS) + { + CHECKMODE(CDVD_READ_SCSI10); + } + + // then check for mmc + CHECKMODE(CDVD_READ_MMC); + // mmc doesnt work? lets try the others + + TRACE("cdvdlib: failed to retrieve mode. \n"); + // disabled all other read_modes for now. + //CHECKMODE(CDVD_READ_D8); + //CHECKMODE(CDVD_READ_D410); + //CHECKMODE(CDVD_READ_D412); + } + } + + return retval; +} + +// update the global interface for some magic +void CCdvd::UpdateInterfaceObject() +{ +#if defined(CDVD_SIMPLE_INTERFACE) + + FUNCTION_GETNUMSECTORS = GetNumSectors; + FUNCTION_GETTOC = GetToc; + FUNCTION_TESTREADY = TestReady; + FUNCTION_SETSPEED = SetSpeed; + FUNCTION_STOP = Stop; + FUNCTION_SETSECTORSIZE = SetSectorSize; + FUNCTION_PLAY = Play; + FUNCTION_READSECTOR = ReadSector; + +#endif + +} + +TOCDATA CCdvd::GetTocData() +{ + TOCDATA dummy; + + if(m_nCurrentDrive == -1) + { + memset(&dummy, 0, sizeof(TOCDATA)); + return dummy; + } + + return m_tocDetails; +} + +DECODEDTRACKINFO CCdvd::GetTrackDetail() +{ + DECODEDTRACKINFO dummy; + + if(m_nCurrentDrive == -1) + { + memset(&dummy, 0, sizeof(DECODEDTRACKINFO)); + return dummy; + } + + return m_trkDetails; +} + +UI08 *CCdvd::GetBufferAddress(int buff_num) const +{ + _ASSERT(buff_num < CDVD_NUM_BUFFERS); + + return m_ReadBuffer[buff_num].AB_BufPointer; +} + +ADAPTERINFO CCdvd::GetAdapterDetail(int drv_num) +{ + _ASSERT(drv_num < CDVD_MAX_SUPPORTED_DRIVES); + ADAPTERINFO dummy; + + if(m_nDrives == 0) + { + memset(&dummy, 0, sizeof(ADAPTERINFO)); + return dummy; + } + + return m_drvDetails[drv_num]; +} + + +/***********************************************************/ +/* DUMMY C/DVD Methods */ +/***********************************************************/ +int CCdvd::Dummy_T1() +{ + TRACE("cdvdlib: dummy_t1\n"); + return CDVD_ERROR_UNINITIALIZED; +} + +int CCdvd::Dummy_T2(int a) +{ + TRACE("cdvdlib: dummy_t2\n"); + return CDVD_ERROR_UNINITIALIZED; +} + +int CCdvd::Dummy_T3(int a, int b) +{ + TRACE("cdvdlib: dummy_t3\n"); + return CDVD_ERROR_UNINITIALIZED; +} + +int CCdvd::Dummy_T4(int a, HANDLE *b) +{ + TRACE("cdvdlib: dummy_t4\n"); + return CDVD_ERROR_UNINITIALIZED; +} + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvd.h b/plugins/cdvd/CDVDdraft/Src/cdvd.h new file mode 100644 index 0000000000..affd77558f --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvd.h @@ -0,0 +1,252 @@ +// Cdvd.h: interface for the CCdvd class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CDVD_H__1189B8A5_BC21_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CDVD_H__1189B8A5_BC21_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include +#include +#include +#include "winaspi/wnaspi32.h" +#include "winaspi/scsidefs.h" +#include "constants.h" +#include "typedefs.h" + +#define CDVD_SIMPLE_INTERFACE + +// [normal sequence of operation] +// 1. [open] +// Init -> GetNumDrives -> OpenDrive -> SetReadMode -> (DO WHATEVER, read, toc, etc) +// 2. [close] +// CloseDrive -> Shutdown; +// 3. [synchrounous read] +// ReadSector -> (verify if successful) +// 4. [asynchronous read] +// ReadSector -> GetSrbStatus -> (verify if successful) + +// CDVD class, don't complain. +class CCdvd +{ + // public interfaces only +public: + + int Init(CDVD_INTERFACE_TYPE intf_type); // initialize an interface, closes previously opened one. + int Shutdown(); // shutsdown an interface + int GetNumDrives() const; // get num of c/dvd drives available + int OpenDrive(int drv_num); // open a drive + int CloseDrive(); // close previously opened drive + int SetCurrentBuffer(int buf_num); // currently there are ONLY 2! + + // call, when doing asynchronous requests to retrieve an srb status (i.e. buffer0 = srb0) + // the return value is only valid when an asynchronous read was previously issued + int GetSrbStatus(int srb_num); + + // manually set read_mode, if mmc mode is specified, data_filter is also set. + // data_mode can be CDVD_MMC_DATAMODE_RAW / CDVD_MMC_DATAMODE_USER + // note that CDVD_MMC_DATAMODE_USER should always be used for DVD medias, + // and the only read_mode's enabled are CDVD_READ_MMC and CDVD_READ_SCSI10 + // i've disabled all the other modes in this version (unlike the previous one.) + int SetReadMode(CDVD_READ_MODE read_mode, int data_mode = CDVD_MMC_DATAMODE_RAW); + + // determine drive type + int GetCdvdDriveType(); + + // determine media type + int GetCdvdMediaType(); + + // automatically detect media type, read_type and set it. + // returns detected read mode, else CDVD_ERROR_FAIL if error + int DetectAndSetReadMode(); + + UI08 *GetBufferAddress(int buff_num) const; + + CDVD_INTF_FUNC_T1 GetNumSectors; + CDVD_INTF_FUNC_T1 GetToc; + CDVD_INTF_FUNC_T1 TestReady; + CDVD_INTF_FUNC_T2 SetSpeed; + CDVD_INTF_FUNC_T1 Stop; + CDVD_INTF_FUNC_T2 SetSectorSize; + CDVD_INTF_FUNC_T3 Play; + CDVD_INTF_FUNC_T4 ReadSector; + + ADAPTERINFO GetAdapterDetail(int drv_num); + + // for both gettrackdetail and gettocdata + // only valid if there was previous call to GetToc; + DECODEDTRACKINFO GetTrackDetail(); + TOCDATA GetTocData(); + + // auxilliary function + static WIN32OSTYPE GetWin32OSType(); + static int Aspi_CheckValidInstallation(); + +protected: + + int Aspi_Init(); + int Aspi_Shutdown(); + int Aspi_OpenDrive (int drv_num); + int Aspi_CloseDrive (); + int Aspi_GetSrbStatus (int srb_num); + int Aspi_GetNumSectors(); + int Aspi_TestReady (); // legacy + int Aspi_GetToc (); // legacy + //int Aspi_GetHeader (); + int Aspi_SetSpeed (int speed); + int Aspi_Stop (); + int Aspi_SetSectorSize(int sect_size); + int Aspi_Play (int sect_start, int sect_stop); + int Aspi_SetReadMode (CDVD_READ_MODE read_mode); + + // if handle is not NULL, then the read is asynchronous + int Aspi_ReadSector_mmc (int sect, HANDLE *handle = NULL); + int Aspi_ReadSector_scsi10 (int sect, HANDLE *handle = NULL); + int Aspi_ReadSector_matsu (int sect, HANDLE *handle = NULL); + int Aspi_ReadSector_sony (int sect, HANDLE *handle = NULL); + int Aspi_ReadSector_nec (int sect, HANDLE *handle = NULL); + + // retrieve a configuration from the cdvd drive + int Aspi_GetConfiguration(UI16 feature, UI08 *dest, UI32 dest_size); + + int Ioctl_Init(); + int Ioctl_Shutdown(); + int Ioctl_OpenDrive (int drv_num); + int Ioctl_CloseDrive (); + int Ioctl_GetSrbStatus (int srb_num); + int Ioctl_GetNumSectors(); + int Ioctl_TestReady (); // legacy + int Ioctl_GetToc (); // legacy + //int Ioctl_GetHeader (); + int Ioctl_SetSpeed (int speed); + int Ioctl_Stop (); + int Ioctl_SetSectorSize(int sect_size); + int Ioctl_Play (int sect_start, int sect_stop); + int Ioctl_SetReadMode (CDVD_READ_MODE read_mode); + + // if handle is not NULL, read is still NOT ASYNCHRONOUS, + // stupid IOCTL BLOCKS OVERLAPPED OPERATIONS -_- + int Ioctl_ReadSector_mmc (int sect, HANDLE *handle = NULL); + int Ioctl_ReadSector_scsi10 (int sect, HANDLE *handle = NULL); + int Ioctl_ReadSector_matsu (int sect, HANDLE *handle = NULL); + int Ioctl_ReadSector_sony (int sect, HANDLE *handle = NULL); + int Ioctl_ReadSector_nec (int sect, HANDLE *handle = NULL); + + // retrieve a configuration from the cdvd drive + int Ioctl_GetConfiguration(UI16 feature, UI08 *dest, UI32 dest_size); + + // dummy functions, used for init only so that stupid mofu's + // calling no-initialized interfaces won't crash + int Dummy_T1(); + int Dummy_T2(int a); + int Dummy_T3(int a, int b); + int Dummy_T4(int a, HANDLE *b = NULL); + +protected: + int Aspi_ScsiBusScan(); + int Aspi_ScsiInquiry(UI08 ha, UI08 id, UI08 lun, char *destination); + int Aspi_ExecuteSrb(SRB_ExecSCSICmd &srbExec, HANDLE *handle, int nretry); + + int Ioctl_ScsiBusScan(); + int Ioctl_AddAdapter(int adptr_num, UI08 *buffer); + + int InitializeBuffers(); + int ShutdownBuffers(); + int ExtractTocData(UI08 *buffer); + int GetCdvdConfiguration(UI16 feature, UI08 *dest, UI32 dest_size); + + void UpdateInterfaceObject(); + +protected: + + ADAPTERINFO m_drvDetails[CDVD_MAX_SUPPORTED_DRIVES]; + TOCDATA m_tocDetails ; + DECODEDTRACKINFO m_trkDetails; + + SI32 m_nCurrentDrive; + SI32 m_nCurrentBuffer; + + HANDLE m_hIoctlDrv; + HINSTANCE m_hAspi; + BOOL m_bAspiInitialized; + BOOL m_bIoctlInitialized; + BOOL m_bDriveOpened; + UI32 m_nDrives; + SI32 m_nMmcDataMode; + + CDVD_INTERFACE_TYPE m_IntfType; + CDVD_READ_MODE m_nCurrentReadMode; + +protected: + + CDROMSendASPI32Command SendASPI32Command; + CDROMGetASPI32SupportInfo GetASPI32SupportInfo; + ASPI32BUFF m_ReadBuffer[CDVD_NUM_BUFFERS]; // our buffers + + // SRB's for ASPI + SRB_ExecSCSICmd m_srbReadCd [CDVD_NUM_BUFFERS]; + SRB_ExecSCSICmd m_srbRead10 [CDVD_NUM_BUFFERS]; + SRB_ExecSCSICmd m_srbReadMat [CDVD_NUM_BUFFERS]; + SRB_ExecSCSICmd m_srbReadSony[CDVD_NUM_BUFFERS]; + SRB_ExecSCSICmd m_srbReadNec [CDVD_NUM_BUFFERS]; + + // SRB's for IOCTL + SPTD_WITH_SENSE_BUFF m_sptwbReadCd [CDVD_NUM_BUFFERS]; + SPTD_WITH_SENSE_BUFF m_sptwbRead10 [CDVD_NUM_BUFFERS]; + SPTD_WITH_SENSE_BUFF m_sptwbReadMat [CDVD_NUM_BUFFERS]; + SPTD_WITH_SENSE_BUFF m_sptwbReadSony[CDVD_NUM_BUFFERS]; + SPTD_WITH_SENSE_BUFF m_sptwbReadNec [CDVD_NUM_BUFFERS]; + +public: + CCdvd(); + virtual ~CCdvd(); + +}; + +#if defined(CDVD_SIMPLE_INTERFACE) +// declare our global interface functions ;P +EXTERN CCdvd OBJECT_HOLDER_CDVD; +EXTERN CDVD_INTF_FUNC_T1 FUNCTION_GETNUMSECTORS; +EXTERN CDVD_INTF_FUNC_T1 FUNCTION_GETTOC; +EXTERN CDVD_INTF_FUNC_T1 FUNCTION_TESTREADY; +EXTERN CDVD_INTF_FUNC_T2 FUNCTION_SETSPEED; +EXTERN CDVD_INTF_FUNC_T1 FUNCTION_STOP; +EXTERN CDVD_INTF_FUNC_T2 FUNCTION_SETSECTORSIZE; +EXTERN CDVD_INTF_FUNC_T3 FUNCTION_PLAY; +EXTERN CDVD_INTF_FUNC_T4 FUNCTION_READSECTOR; + +// this is where the weird shit starts +// wrap C++ to C, who said i didn't obfuscate :P + +#define cdvd_getnumsectors (OBJECT_HOLDER_CDVD.*FUNCTION_GETNUMSECTORS) +#define cdvd_gettoc (OBJECT_HOLDER_CDVD.*FUNCTION_GETTOC) +#define cdvd_testready (OBJECT_HOLDER_CDVD.*FUNCTION_TESTREADY) +#define cdvd_setspeed (OBJECT_HOLDER_CDVD.*FUNCTION_SETSPEED) +#define cdvd_stop (OBJECT_HOLDER_CDVD.*FUNCTION_STOP) +#define cdvd_setsectorsize (OBJECT_HOLDER_CDVD.*FUNCTION_SETSECTORSIZE) +#define cdvd_play (OBJECT_HOLDER_CDVD.*FUNCTION_PLAY) +#define cdvd_readsector (OBJECT_HOLDER_CDVD.*FUNCTION_READSECTOR) + +#define cdvd_init (OBJECT_HOLDER_CDVD.Init) +#define cdvd_shutdown (OBJECT_HOLDER_CDVD.Shutdown) +#define cdvd_getnumdrives (OBJECT_HOLDER_CDVD.GetNumDrives) +#define cdvd_opendrive (OBJECT_HOLDER_CDVD.OpenDrive) +#define cdvd_closedrive (OBJECT_HOLDER_CDVD.CloseDrive) +#define cdvd_setcurrentbuffer (OBJECT_HOLDER_CDVD.SetCurrentBuffer) +#define cdvd_getsrbstatus (OBJECT_HOLDER_CDVD.GetSrbStatus) +#define cdvd_setreadmode (OBJECT_HOLDER_CDVD.SetReadMode) +#define cdvd_getmediatype (OBJECT_HOLDER_CDVD.GetCdvdMediaType) +#define cdvd_getdrivetype (OBJECT_HOLDER_CDVD.GetCdvdDriveType) +#define cdvd_getadapterdetail (OBJECT_HOLDER_CDVD.GetAdapterDetail) +#define cdvd_gettocdata (OBJECT_HOLDER_CDVD.GetTocData) +#define cdvd_gettrackdetail (OBJECT_HOLDER_CDVD.GetTrackDetail) +#define cdvd_detectandsetreadmode (OBJECT_HOLDER_CDVD.DetectAndSetReadMode) +#define cdvd_getbufferaddress (OBJECT_HOLDER_CDVD.GetBufferAddress) + +#endif + +#endif // !defined(AFX_CDVD_H__1189B8A5_BC21_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/cdvdcompat.cpp b/plugins/cdvd/CDVDdraft/Src/cdvdcompat.cpp new file mode 100644 index 0000000000..8340227f3b --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvdcompat.cpp @@ -0,0 +1,194 @@ +// cdvdcompat.cpp: implementation of the cdvdcompat class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "cdvddraft.h" +#include "cdvdcompat.h" +#include "cdvdmisc.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +/////////////////////////////////////////////////////////////////////////// +// test cdrom-from old interface ;p // +// added for psemupro compatibility and testing only! // +// although, its seems more stable than my old one hehe.. // +/////////////////////////////////////////////////////////////////////////// + +static char *libraryName = "PSEmuPro (C/DVD) Compatibility Driver"; +const unsigned char version = 1; +const unsigned char revision = 0; +const unsigned char build = 22; + +#define INT2BCD(n) ((n)/10)*16 + (n)%10 +#define BCD2INT(n) ((n & 0x0F) + 10 * ( (n & 0xF0) >> 4)) +#define MSF2SECT(m,s,f) (((m)*60 + (s) - 2)*75 + (f) ) +#define SECT2MSF(sect,m,s,f){ (f) =(UI08)(sect%75);(s) =(UI08)(((sect - (f))/75)%60);(m) = (UI08)((((sect - (f))/75)-(s))/60); } +#define NORMALIZE(m,s,f) { while((f) >= 75){ (f) -= 75; (s) += 1; } while((s) >= 60){ (s) -= 60; (m) += 1;} } + +/*************************************************************************/ +/* psemupro library identifier functions */ +/*************************************************************************/ +char * CALLBACK PSEgetLibName() +{ + return libraryName; +} + +unsigned int CALLBACK PSEgetLibType() +{ + return 1; // PSE_LT_CDR +} + +unsigned int CALLBACK PSEgetLibVersion() +{ + return version<<16|revision<<8|build; +} + +/*************************************************************************/ +/* psemupro config/test functions */ +/*************************************************************************/ + +int CALLBACK CDRconfigure(void) +{ + CDVDconfigure(); + return CDVD_ERROR_SUCCESS; +} + +void CALLBACK CDRabout(void) +{ + CDVDabout(); +} + +int CALLBACK CDRtest(void) +{ + return CDVDtest(); +} + +/*************************************************************************/ +/* psemupro library init/shutdown functions */ +/*************************************************************************/ + +int CALLBACK CDRinit() +{ + return CDVDinit(); +} + +int CALLBACK CDRshutdown() +{ + CDVDshutdown(); + return CDVD_ERROR_SUCCESS; +} + +int CALLBACK CDRopen() +{ + return CDVDopen(); +} + +int CALLBACK CDRclose() +{ + CDVDclose(); + return CDVD_ERROR_SUCCESS; +} + +/*************************************************************************/ +/* psemupro library cdrom functions */ +/*************************************************************************/ + +int CALLBACK CDRgetTN(cdvdTN *buffer) +{ + return CDVDgetTN(buffer); +} + +int CALLBACK CDRgetTD(unsigned char track, unsigned char *buffer) +{ +/* cdvdTD td; + + int retval = CDVDgetTD(track, &td); + + if(retval == CDVD_ERROR_FAIL) + return CDVD_ERROR_FAIL; + + //SECT2MSF(retval, m, s, f); + + NORMALIZE(td.minute, td.second, td.frame); + + buffer[0] = INT2BCD(td.minute); + buffer[2] = INT2BCD(td.frame); + + if(track == 0) + { + buffer[1] = INT2BCD(td.second); + } + else + { + // (add 0:2:0 to convert to pysical addr) + buffer[1] = INT2BCD(td.second+2); + }*/ + + return CDVD_ERROR_SUCCESS; +} + +int CALLBACK CDRreadTrack(unsigned char *time) +{ + int lsn = MSF2SECT(BCD2INT(time[0]), BCD2INT(time[1]), BCD2INT(time[2])); + + return CDVDreadTrack(lsn, CDVD_MODE_2352); +} + +unsigned char *CALLBACK CDRgetBuffer(void) +{ + return (CDVDgetBuffer() + 12); +} + +// heck if i know if this works -_- +int CALLBACK CDRplay(unsigned char *sector) +{ + flush_all(); + int sect = MSF2SECT(sector[0], sector[1], sector[2]); + cdvd_play(sect, 0xFFFFFF); + + return CDVD_ERROR_SUCCESS; +} + +int CALLBACK CDRstop(void) +{ + flush_all(); + cdvd_stop(); + + return CDVD_ERROR_SUCCESS; +} + +/*************************************************************************/ +/* psemupro library extended functions */ +/*************************************************************************/ +typedef struct tagCDRSTAT +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time + +} CDRSTAT, *LPCDRSTAT; + +int CALLBACK CDRgetStatus(LPCDRSTAT stat) +{ + memset(stat, 0, sizeof(CDRSTAT)); + + stat->Type = 0x01; //always data for now.. + + if(cdvd_testready() != CDVD_ERROR_SUCCESS) + { + stat->Type = 0xff; + stat->Status |= 0x10; + } + else + { + // new disc, flush cashe markers + flush_all(); + } + + return CDVD_ERROR_SUCCESS; +} diff --git a/plugins/cdvd/CDVDdraft/Src/cdvdcompat.h b/plugins/cdvd/CDVDdraft/Src/cdvdcompat.h new file mode 100644 index 0000000000..b99cb05cda --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvdcompat.h @@ -0,0 +1,20 @@ +// cdvdcompat.h: interface for the cdvdcompat class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CDVDCOMPAT_H__0980F843_C2E7_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CDVDCOMPAT_H__0980F843_C2E7_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class cdvdcompat +{ +public: + cdvdcompat(); + virtual ~cdvdcompat(); + +}; + +#endif // !defined(AFX_CDVDCOMPAT_H__0980F843_C2E7_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.aps b/plugins/cdvd/CDVDdraft/Src/cdvddraft.aps new file mode 100644 index 0000000000000000000000000000000000000000..8e31285b90e0b8eeda410e39fd5c2641280fdee8 GIT binary patch literal 38612 zcmbt-37BJ7b>``I8_5++5y%84o{y9rX51dITU%`=1hhO=DXo%(r0NX^eeLeH>51K~ zl-sBP6NzT2VwtH-)?qRUB?c95hh=}I!noji#AD!n>`1WYLR_QpE@OL^rVDPIBnGaO>Wuo%Ux12fq zw6kY7PTzLPe!6Mn3`m8?`!eoRUNdB6T&rBJrHylUUA%ka%(w%S28=$2QRS)d2AW2ILtHP^fBvPf66OQ~0?b=Qh5j$JlG4^}w|>IDbKZJ4gqPb$Z8wcBj^C^lFW2ld|+MI>7nd z=@z@SG9A7#djs7-@P#rtP%gDQy<)w#(&*KLYL_ybS%g%lBM#JUwt(aml5voBZDo~x z6%>|ruu`+zZLR@aQee&ji;a^&stU;)q||Izf_4}Y|W~ok3Fkq*4D(F>CHi~N~HU$>y^h60( zYbOFNG?S}S(LmKYqEc(DXg}FHnz}CMm3FPw3fjt@3yhOnF<7%*3mVRb6kWab3q7S0?FC70wN`;(FtJ*MW)PwKwCyf^R^76;{-`iF_4LoqpQ5 zH=3#n>jayGH4Ub!wM>zXnyGIlZY|@1tC-|RIbi5v7Cg!Db-j~5l#5P=sM0r3+xRe* zQF_r%jvs`319iCVqJ~sze${*f3ze{kHfDk;(63v#S^8-mLD5DbVxE3OC97Ji2N(>FbM(64y&uU=~$)t(mUQ$E;f1?5`NL~N0M&*JT%6%NNg-ZK3k zi*$lInxai;k^aDf>y1iNN25f4Xr0?Z=v<~hQqISb$ma2=o62YCPo;aY-7YqCADhi* z>C+M`7dz!5=FOaQ`5gV3#Jb$~so8=;^YrI2R80yLTA;s>Xs1=L>8!}l(_botyK6oB zW)Fo7eJ*kiP8f0_OP^P+-23yG7@Sa1E9B@4)}0Gg&2bGE8j1!__A^ySEhc3GgWDwj%7En;>jxQp~Pg{b8Kh7p}n^BMZOa^|kGXPvY34dq;I zw%0IItRiR?z(R(`3TPrjYmE*jJYivBmP_A?Fx4iw_Nnn8ht<-zT@0xSvpk340@|w?-13O`zs6w9 zL3q^S!1IXwG)^#+n>-><2h1!XlFp%Mzj=Uh6hoed3v@6BpK3POYAW4%43$?T;=J@z zaa*862YA-S16_}o0VUlHVdX$6i|~4Cz0-@pETt{j4kGsgU1i;i>)obka!ZKKj72+Z z=+(j!T0$m2*kbi!dnK?~maZ09O?RM6*&IE@I#+@&##L3COW8clS_IW7&{Kz{Y=ItX zff6q_R2eO0=jn%|j8b`lEUc|zCK=|9jqbxdV)2ASG*Ta~!omCk>pWYTmXWQGkVrTj zETfh@QUcu2xQLcfLH@l2!n(1HO8sLDxU1dk!q|0soieYgSO^w-^cV@OHT4{ z0G#Z|SB`FUKu&4|=IJI0a)fpNt3xc%5eaj&C5*vS!clvwW)>(b5$GN;nbyfbk>@1V zEq0F9O?{}M)bkcx!zyC6R##(QHCv^53sr*7(PFub33s!t2GDAyNQ)Nd`7BR&kq%z7 z)6Ev*`JIKb^f(KlHUoj0MtjTAPg-ofp{D*E8A#02<1G|Qh)Hu z+3q5M;6yoSb)jid;xG{jEHhFMd88awEom)SLw5Ue^0Z

lhGxLV;E-p~aK^W`m=o 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 wcw9d=LU{K)_y12X#Cn= g_sectstart[i] && + rq_sector < (g_sectstart[i] + CDVD_NUM_SECTORS_PER_BUFF) + && g_sectstart[i] != -1) + { + rq_isinbuff = TRUE; + g_current_buffnum = i; + break; + } + } + + if(rq_isinbuff == TRUE) + { + // bufffilled? else + if(g_filled[g_current_buffnum] == FALSE) + { + int ret = WaitForSingleObject(g_handle[g_current_buffnum], INFINITE); // ->> check error here! + if(g_status[g_current_buffnum] == CDVD_ERROR_FAIL || + cdvd_getsrbstatus(g_current_buffnum) != CDVD_SRB_COMPLETED) // there was an error + { + TRACE("CDVDreadTrack: error srb not completed1 stat: %ld, srb: %ld\n", g_status[g_current_buffnum], + cdvd_getsrbstatus(g_current_buffnum)); + TRACE("CDVDreadTrack: waitret: %ld, extended: %ld\n", ret, GetLastError()); + //----------------------------------------- + // one last try, we might get lucky :p + cdvd_setcurrentbuffer(g_current_buffnum); + g_status[g_current_buffnum] = cdvd_readsector(rq_sector, NULL); + if(g_status[g_current_buffnum] != CDVD_ERROR_SUCCESS) + return CDVD_ERROR_FAIL; + else + return CDVD_ERROR_SUCCESS; + //----------------------------------------- + //return CDVD_ERROR_FAIL; + } + + g_filled[g_current_buffnum] = TRUE; + } + + int sect_in_buff = rq_sector - g_sectstart[g_current_buffnum]; + + // okay, just send another async read (prefetch) + // ONLY supports 2 buffers + if(g_current_buffmode == CDVD_BUFFER_ASYNC) + { + int altbuff = !g_current_buffnum; + if(g_sectstart[g_current_buffnum] > g_sectstart[altbuff]) + { + TRACE("CDVDreadTrack: sending prefetch.\n"); + WaitForSingleObject(g_handle[altbuff], INFINITE); + g_sectstart[altbuff] = g_sectstart[g_current_buffnum] + CDVD_NUM_SECTORS_PER_BUFF; + cdvd_setcurrentbuffer(altbuff); + _ASSERTE(g_handle[altbuff] != NULL); + g_status[altbuff] = cdvd_readsector(g_sectstart[altbuff], &g_handle[altbuff]); + g_filled[altbuff] = FALSE; + } + } + + g_current_buff = cdvd_getbufferaddress(g_current_buffnum); + static const UI32 mode_pad[] = {0, 12, 24, 24}; + + if(g_current_medtype == CDVD_MEDIATYPE_DVD) + { + g_request_offset = sect_in_buff * CDVD_SECTOR_SIZE_DVD; + } + else + { + g_request_offset = (sect_in_buff * CDVD_SECTOR_SIZE_CD) + mode_pad[mode]; + } + + return CDVD_ERROR_SUCCESS; + } + else + { + for(int i=0; i < max_loop; i++) + { + // wait for any previous srb's pending + if(g_filled[i] == FALSE && + cdvd_getsrbstatus(i) == CDVD_SRB_PENDING) + WaitForSingleObject(g_handle[i], INFINITE); + + g_sectstart[i] = rq_sector + (CDVD_NUM_SECTORS_PER_BUFF * i); + cdvd_setcurrentbuffer(i); + _ASSERTE(g_handle[i] != NULL); + g_status[i] = cdvd_readsector(g_sectstart[i], &g_handle[i]); + + if(g_current_buffmode == CDVD_BUFFER_SYNC) + { + WaitForSingleObject(g_handle[i], INFINITE); + if(g_status[g_current_buffnum] == CDVD_ERROR_FAIL || + cdvd_getsrbstatus(i) != CDVD_SRB_COMPLETED) + { + TRACE("CDVDreadTrack: error srb not completed1 stat: %ld, srb: %ld\n", g_status[i], + cdvd_getsrbstatus(i)); + return CDVD_ERROR_FAIL; + } + g_filled[i] = TRUE; + } + else + { + g_filled[i] = FALSE; + } + } + } + } + + return CDVD_ERROR_SUCCESS; +} + +// getbuffer, retrieve previously read sector buffer +unsigned char *CALLBACK CDVDgetBuffer() +{ + return (g_current_buff + g_request_offset); +} + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + // fake it + u8 min, sec, frm; + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +// retrieve track number +int CALLBACK CDVDgetTN(cdvdTN *buffer) +{ + CHECKLIBRARYOPENED(); + + if(cdvd_gettoc() != CDVD_ERROR_SUCCESS) + return CDVD_ERROR_FAIL; + + g_current_tocdata = cdvd_gettocdata(); + + if(g_current_tocdata.first_track_num == 0 || + g_current_tocdata.last_track_num == 0) + { + //fail? then lie ;P + buffer->strack = 1; + buffer->etrack = 1; + return CDVD_ERROR_SUCCESS; // TODO: or fail??? + } + + buffer->strack = g_current_tocdata.first_track_num; + buffer->etrack = g_current_tocdata.last_track_num; + + //printf("s: %ld, e: %ld\n", buffer->strack, buffer->etrack); + return CDVD_ERROR_SUCCESS; +} + +// retrives total sects OR offset of track +int CALLBACK CDVDgetTD(unsigned char track, cdvdTD *buffer) +{ + CHECKLIBRARYOPENED(); + + if(track == 0) + { + buffer->lsn = cdvd_getnumsectors(); + buffer->type = 0x00; // well, dunno if its even needed here. + + return CDVD_ERROR_SUCCESS; + } + + if(track > 0xAA) // max tracks per session + return CDVD_ERROR_FAIL; + if(cdvd_gettoc() != CDVD_ERROR_SUCCESS) + return CDVD_ERROR_FAIL; + + g_current_trkinfo = cdvd_gettrackdetail(); + + // okay, not sure if you need to add a 0:2:0 lead-in for cds? + buffer->lsn = g_current_trkinfo.track_offset[track-1]; + + switch(g_current_medtype) + { + case CDVD_MEDIATYPE_DVD: + buffer->type = CDVD_MODE1_TRACK; // always data track + break; + case CDVD_MEDIATYPE_CD: + switch(g_current_trkinfo.track_type[track-1]) + { + case 0x01: buffer->type = CDVD_MODE1_TRACK; break; + case 0x02: buffer->type = CDVD_MODE2_TRACK; break; + default: buffer->type = CDVD_AUDIO_TRACK; break; // for 0x00 and everything else + } + break; + default: + buffer->type = CDVD_AUDIO_TRACK; // lets lie. + break; + } + + return CDVD_ERROR_SUCCESS; //g_current_trkinfo.track_offset[track-1]; +} + +s32 CALLBACK CDVDgetTOC(void* toc) { + u8 type = CDVDgetDiskType(); + u8* tocBuff = (u8*)toc; + + if( type == CDVD_TYPE_DVDV || + type == CDVD_TYPE_PS2DVD) + { + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm; + s32 i, err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +// return bogus data for now +int CALLBACK CDVDgetDiskType() +{ + CHECKLIBRARYOPENED(); + + int mediatype = cdvd_getmediatype(); + + // TODO: need to retrieve dvd subtype here + if(mediatype == CDVD_MEDIATYPE_DVD) + return CDVD_TYPE_PS2DVD; + + // TODO: need to retrieve cd subtype here + if(mediatype == CDVD_MEDIATYPE_CD) + return CDVD_TYPE_PS2CD; + + return CDVD_TYPE_UNKNOWN; +} + +// return bogus data for now +int CALLBACK CDVDgetTrayStatus() +{ + CHECKLIBRARYOPENED(); + + return CDVD_TRAY_CLOSE; +} + +s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} +s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.def b/plugins/cdvd/CDVDdraft/Src/cdvddraft.def new file mode 100644 index 0000000000..27cd348c9d --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.def @@ -0,0 +1,49 @@ +; cdvddraft.def : Declares the module parameters for the DLL. + +LIBRARY "cdvddraft" +DESCRIPTION 'cdvddraft Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + + CDVDinit + CDVDshutdown + CDVDopen + CDVDclose + CDVDreadTrack + CDVDgetBuffer + CDVDreadSubQ + CDVDgetTN + CDVDgetTD + CDVDgetTOC + + CDVDconfigure + CDVDtest + CDVDabout + CDVDgetDiskType + CDVDgetTrayStatus + CDVDctrlTrayOpen + CDVDctrlTrayClose + + PS2EgetLibType + PS2EgetLibName + PS2EgetLibVersion2 + + PSEgetLibType + PSEgetLibName + PSEgetLibVersion + + CDRinit + CDRshutdown + CDRopen + CDRclose + CDRconfigure + CDRabout + CDRtest + CDRgetTN + CDRgetTD + CDRreadTrack + CDRgetBuffer + CDRplay + CDRstop + CDRgetStatus diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.dep b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dep new file mode 100644 index 0000000000..7456158efe --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dep @@ -0,0 +1,138 @@ +# Microsoft Developer Studio Generated Dependency File, included by cdvddraft.mak + +.\Config.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\cdvddraft.h"\ + ".\Config.h"\ + ".\constants.h"\ + ".\PS2Edefs.h"\ + ".\PS2Etypes.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\AboutBox.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\AboutBox.h"\ + ".\cdvd.h"\ + ".\cdvddraft.h"\ + ".\constants.h"\ + ".\PS2Edefs.h"\ + ".\PS2Etypes.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\cdvdcompat.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\cdvdcompat.h"\ + ".\cdvddraft.h"\ + ".\cdvdmisc.h"\ + ".\constants.h"\ + ".\PS2Edefs.h"\ + ".\PS2Etypes.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\cdvddraft.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\AboutBox.h"\ + ".\cdvd.h"\ + ".\cdvddraft.h"\ + ".\cdvdmisc.h"\ + ".\Config.h"\ + ".\constants.h"\ + ".\PS2Edefs.h"\ + ".\PS2Etypes.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\cdvddraft.rc : \ + ".\bitmap1.bmp"\ + ".\res\cdvddraft.rc2"\ + + +.\cdvdmisc.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\cdvddraft.h"\ + ".\cdvdmisc.h"\ + ".\constants.h"\ + ".\PS2Edefs.h"\ + ".\PS2Etypes.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\StdAfx.cpp : \ + "..\mssdk\include\basetsd.h"\ + ".\StdAfx.h"\ + + +.\aspi.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\constants.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\cdvd.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\constants.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + + +.\ioctl.cpp : \ + "..\program files\microsoft visual studio\vc98\include\devioctl.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddcdrm.h"\ + "..\program files\microsoft visual studio\vc98\include\ntdddisk.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddscsi.h"\ + "..\program files\microsoft visual studio\vc98\include\ntddstor.h"\ + ".\cdvd.h"\ + ".\constants.h"\ + ".\typedefs.h"\ + ".\winaspi\scsidefs.h"\ + ".\winaspi\wnaspi32.h"\ + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsp b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsp new file mode 100644 index 0000000000..9e9b93a5ff --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsp @@ -0,0 +1,219 @@ +# Microsoft Developer Studio Project File - Name="cdvddraft" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cdvddraft - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cdvddraft.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cdvddraft.mak" CFG="cdvddraft - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cdvddraft - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cdvddraft - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cdvddraft - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /def:".\cdvddraft.def" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "cdvddraft - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__MSCW32__" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__MSCW32__" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\cdvddraft.def" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "cdvddraft - Win32 Release" +# Name "cdvddraft - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "config" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Config.cpp +# End Source File +# Begin Source File + +SOURCE=.\Config.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\AboutBox.cpp +# End Source File +# Begin Source File + +SOURCE=.\cdvdcompat.cpp +# End Source File +# Begin Source File + +SOURCE=.\cdvddraft.cpp +# End Source File +# Begin Source File + +SOURCE=.\cdvddraft.def +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\cdvddraft.rc +# End Source File +# Begin Source File + +SOURCE=.\cdvdmisc.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\AboutBox.h +# End Source File +# Begin Source File + +SOURCE=.\cdvddraft.h +# End Source File +# Begin Source File + +SOURCE=.\cdvdmisc.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\bitmap1.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\cdvddraft.rc2 +# End Source File +# End Group +# Begin Group "cdvdlib" + +# PROP Default_Filter "" +# Begin Group "headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\cdvd.h +# End Source File +# Begin Source File + +SOURCE=.\constants.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Etypes.h +# End Source File +# Begin Source File + +SOURCE=.\typedefs.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\aspi.cpp +# End Source File +# Begin Source File + +SOURCE=.\cdvd.cpp +# End Source File +# Begin Source File + +SOURCE=.\ioctl.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsw b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsw new file mode 100644 index 0000000000..6ebcb10dde --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cdvddraft"=".\cdvddraft.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.h b/plugins/cdvd/CDVDdraft/Src/cdvddraft.h new file mode 100644 index 0000000000..615ff3d1b2 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.h @@ -0,0 +1,56 @@ +// cdvddraft.h : main header file for the CDVDDRAFT DLL +// + +#if !defined(AFX_CDVDDRAFT_H__A0D50EA8_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CDVDDRAFT_H__A0D50EA8_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#define __WIN32__ + +#include "resource.h" // main symbols +#include "ps2etypes.h" +#include "ps2edefs.h" + +#include "cdvd.h" + +#define PLUGIN_REG_PATH _T("Software\\PS2EPlugin\\CDVD\\CdvdXeven") + +/*************************************************************************/ +/* ps2emu library identifier functions */ +/*************************************************************************/ + +unsigned int CALLBACK PS2EgetLibType(); +char *CALLBACK PS2EgetLibName(); +unsigned int CALLBACK PS2EgetLibVersion2(unsigned int type); + +/*************************************************************************/ +/* ps2emu config/test functions */ +/*************************************************************************/ + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +int CALLBACK CDVDtest(); + +/*************************************************************************/ +/* ps2emu library c/dvd functions */ +/*************************************************************************/ + +int CALLBACK CDVDinit(); +void CALLBACK CDVDshutdown(); +int CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +int CALLBACK CDVDreadTrack(unsigned int lsn, int mode); +unsigned char *CALLBACK CDVDgetBuffer(); +int CALLBACK CDVDgetTN(cdvdTN *buffer); +int CALLBACK CDVDgetTD(unsigned char track, cdvdTD *buffer); +int CALLBACK CDVDgetType(); +int CALLBACK CDVDgetTrayStatus(); + +#endif // !defined(AFX_CDVDDRAFT_H__A0D50EA8_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.opt b/plugins/cdvd/CDVDdraft/Src/cdvddraft.opt new file mode 100644 index 0000000000000000000000000000000000000000..aaf488626627ebab6643d50318d1e6b35bb4745d GIT binary patch literal 65024 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 literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.plg b/plugins/cdvd/CDVDdraft/Src/cdvddraft.plg new file mode 100644 index 0000000000..3751e4659a --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.plg @@ -0,0 +1,68 @@ + + +

+

Build Log

+

+--------------------Configuration: cdvddraft - Win32 Release-------------------- +

+

Command Lines

+Creating command line "rc.exe /l 0x409 /fo"Release/cdvddraft.res" /d "NDEBUG" /d "_AFXDLL" "C:\cdvddraft\cdvddraft.rc"" +Creating temporary file "C:\WINDOWS\TEMP\RSP4241.TMP" with contents +[ +/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Fp"Release/cdvddraft.pch" /Yu"stdafx.h" /Fo"Release/" /Fd"Release/" /FD /c +"C:\cdvddraft\Config.cpp" +"C:\cdvddraft\AboutBox.cpp" +"C:\cdvddraft\cdvdcompat.cpp" +"C:\cdvddraft\cdvddraft.cpp" +"C:\cdvddraft\cdvdmisc.cpp" +"C:\cdvddraft\aspi.cpp" +"C:\cdvddraft\cdvd.cpp" +"C:\cdvddraft\ioctl.cpp" +] +Creating command line "cl.exe @C:\WINDOWS\TEMP\RSP4241.TMP" +Creating temporary file "C:\WINDOWS\TEMP\RSP4242.TMP" with contents +[ +/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Fp"Release/cdvddraft.pch" /Yc"stdafx.h" /Fo"Release/" /Fd"Release/" /FD /c +"C:\cdvddraft\StdAfx.cpp" +] +Creating command line "cl.exe @C:\WINDOWS\TEMP\RSP4242.TMP" +Creating temporary file "C:\WINDOWS\TEMP\RSP4243.TMP" with contents +[ +/nologo /subsystem:windows /dll /incremental:no /pdb:"Release/cdvddraft.pdb" /machine:I386 /def:".\cdvddraft.def" /out:"Release/cdvddraft.dll" /implib:"Release/cdvddraft.lib" +.\Release\Config.obj +.\Release\AboutBox.obj +.\Release\cdvdcompat.obj +.\Release\cdvddraft.obj +.\Release\cdvdmisc.obj +.\Release\StdAfx.obj +.\Release\aspi.obj +.\Release\cdvd.obj +.\Release\ioctl.obj +.\Release\cdvddraft.res +] +Creating command line "link.exe @C:\WINDOWS\TEMP\RSP4243.TMP" +

Output Window

+Compiling resources... +Compiling... +StdAfx.cpp +Compiling... +Config.cpp +AboutBox.cpp +cdvdcompat.cpp +cdvddraft.cpp +cdvdmisc.cpp +aspi.cpp +cdvd.cpp +ioctl.cpp +Generating Code... +Linking... +link: executing 'C:\PROGRA~1\MICROS~5\VC98\BIN\link.exe' + Creating library Release/cdvddraft.lib and object Release/cdvddraft.exp + + + +

Results

+cdvddraft.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft.rc b/plugins/cdvd/CDVDdraft/Src/cdvddraft.rc new file mode 100644 index 0000000000..a1ba632fb3 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft.rc @@ -0,0 +1,227 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\cdvddraft.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "cdvddraft DLL\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "cdvddraft\0" + VALUE "LegalCopyright", "Copyright (C) 2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "cdvddraft.DLL\0" + VALUE "ProductName", "cdvddraft Dynamic Link Library\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 236, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure C/DVD Plugin" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,45,97,50,14 + LTEXT "Interface:",IDC_STATIC,8,36,48,8 + PUSHBUTTON "Cancel",IDCANCEL,144,97,50,14 + LTEXT "Read Mode:",IDC_STATIC,134,36,48,8 + COMBOBOX IDC_DRIVE,8,17,218,95,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Buffering Mode:",IDC_STATIC,8,65,65,8 + LTEXT "Drive:",IDC_STATIC,8,7,23,8 + COMBOBOX IDC_INTERFACE,8,46,99,47,CBS_DROPDOWNLIST | WS_DISABLED | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_READMODE,128,46,98,58,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + GROUPBOX "",IDC_STATIC,1,1,231,114 + COMBOBOX IDC_PREFETCH,8,75,99,47,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 186, 125 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,71,104,50,14 + LTEXT "Coded by Xeven",IDC_STATIC,69,9,61,8 + CONTROL 7010,IDC_STATIC,"Static",SS_BITMAP,67,31,57,50 + LTEXT "http://batard.psxfanatics.com",IDC_STATIC,48,18,97,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 231 + TOPMARGIN, 7 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 118 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_CONFIG DLGINIT +BEGIN + IDC_INTERFACE, 0x403, 5, 0 +0x5341, 0x4950, "\000" + IDC_INTERFACE, 0x403, 6, 0 +0x4f49, 0x5443, 0x004c, + IDC_READMODE, 0x403, 11, 0 +0x5541, 0x4f54, 0x4544, 0x4554, 0x5443, "\000" + IDC_READMODE, 0x403, 7, 0 +0x4552, 0x4441, 0x4443, "\000" + IDC_READMODE, 0x403, 7, 0 +0x4353, 0x4953, 0x3031, "\000" + IDC_PREFETCH, 0x403, 12, 0 +0x5953, 0x434e, 0x5248, 0x4e4f, 0x554f, 0x0053, + IDC_PREFETCH, 0x403, 13, 0 +0x5341, 0x4e59, 0x4843, 0x4f52, 0x4f4e, 0x5355, "\000" + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP DISCARDABLE "bitmap1.bmp" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\cdvddraft.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.sln b/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.sln new file mode 100644 index 0000000000..5eaa33fdac --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdvddraft", "cdvddraft_2003.vcproj", "{1FAB7EBD-BE78-4375-B134-F5295148C5EA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1FAB7EBD-BE78-4375-B134-F5295148C5EA}.Debug.ActiveCfg = Debug|Win32 + {1FAB7EBD-BE78-4375-B134-F5295148C5EA}.Debug.Build.0 = Debug|Win32 + {1FAB7EBD-BE78-4375-B134-F5295148C5EA}.Release.ActiveCfg = Release|Win32 + {1FAB7EBD-BE78-4375-B134-F5295148C5EA}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.vcproj b/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.vcproj new file mode 100644 index 0000000000..5cc6908b87 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvddraft_2003.vcproj @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDdraft/Src/cdvdmisc.cpp b/plugins/cdvd/CDVDdraft/Src/cdvdmisc.cpp new file mode 100644 index 0000000000..8b848e8e71 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvdmisc.cpp @@ -0,0 +1,93 @@ +// cdvdmisc.cpp: implementation of the cdvdmisc class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "cdvddraft.h" +#include "cdvdmisc.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +extern int g_status [CDVD_NUM_BUFFERS]; // status of read to buffer-n +extern HANDLE g_handle [CDVD_NUM_BUFFERS]; // handle used to read to buffer-n +extern int g_sectstart[CDVD_NUM_BUFFERS]; // start of sector read to buffer-n +extern BOOL g_filled [CDVD_NUM_BUFFERS]; // check if buffer-n was filled +extern CDVD_BUFFER_MODE g_current_buffmode; +extern CDVD_INTERFACE_TYPE g_current_intftype; +extern int g_current_drivenum; +extern CDVD_READ_MODE g_current_readmode; + +int init_buffersandflags() +{ + for(int i=0; i +int load_registrysettings() +{ + CRegKey rKey; + + if(rKey.Create(HKEY_CURRENT_USER, PLUGIN_REG_PATH) == ERROR_SUCCESS) + { + DWORD val; + + g_current_readmode = CDVD_READ_UNKNOWN; + if(rKey.QueryValue(val, _T("DriveNum")) == ERROR_SUCCESS) + g_current_drivenum = val; + if(rKey.QueryValue(val, _T("BuffMode")) == ERROR_SUCCESS) + g_current_buffmode = (CDVD_BUFFER_MODE) val; + TRACE("---- buffmode: %ld -----\n", g_current_buffmode); + if(rKey.QueryValue(val, _T("Interface")) == ERROR_SUCCESS) + g_current_intftype = (CDVD_INTERFACE_TYPE) val; + if(rKey.QueryValue(val, _T("ReadMode")) == ERROR_SUCCESS) + { + if(val == 0) g_current_readmode = CDVD_READ_UNKNOWN; + else + g_current_readmode = (CDVD_READ_MODE) (val - 1); + } + rKey.Close(); + } + else return CDVD_ERROR_FAIL; + + return CDVD_ERROR_SUCCESS; +} \ No newline at end of file diff --git a/plugins/cdvd/CDVDdraft/Src/cdvdmisc.h b/plugins/cdvd/CDVDdraft/Src/cdvdmisc.h new file mode 100644 index 0000000000..7a3b78b6ec --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/cdvdmisc.h @@ -0,0 +1,17 @@ +// cdvdmisc.h: interface for the cdvdmisc class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CDVDMISC_H__A0D50EB2_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CDVDMISC_H__A0D50EB2_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +int init_buffersandflags(); +int shut_buffersandflags(); +int load_registrysettings(); +int flush_all(); + +#endif // !defined(AFX_CDVDMISC_H__A0D50EB2_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/constants.h b/plugins/cdvd/CDVDdraft/Src/constants.h new file mode 100644 index 0000000000..23a9814c4e --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/constants.h @@ -0,0 +1,109 @@ +// constants.h: interface for the constants class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CONSTANTS_H__A0D50EAF_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_CONSTANTS_H__A0D50EAF_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// win32 o/s types +typedef enum WIN32OSTYPE +{ + WIN32S, + WIN95, + WINNTOLD, + WINNTNEW +}; + +// available read modes supported (only mmc & scsi10 are enabled atm) +typedef enum CDVD_READ_MODE +{ + CDVD_READ_MMC = 0, + CDVD_READ_SCSI10 = 1, + CDVD_READ_D8 = 2, // disabled + CDVD_READ_D410 = 3, // disabled + CDVD_READ_D412 = 4, // disabled + CDVD_READ_UNKNOWN = 5, + CDVD_READ_RESERVE = 6, +}; + +// available buffer modes supported (only sync & async are enabled atm) +typedef enum CDVD_BUFFER_MODE +{ + CDVD_BUFFER_SYNC = 0, + CDVD_BUFFER_ASYNC = 1, + CDVD_BUFFER_SINGLE = 2, // unused + CDVD_BUFFER_UNKNOWN = 3, // unused + CDVD_BUFFER_RESERVE = 4 +}; + +// available interfaces (only aspi & ioctl are enabled atm) +typedef enum CDVD_INTERFACE_TYPE +{ + CDVD_INTF_ASPI = 0, + CDVD_INTF_IOCTL = 1, + CDVD_INTF_IOCTL_RAW = 2, // unused + CDVD_INTF_UNKNOWN = 3, // unused + CDVD_INTF_RESERVE = 4 +}; + +// return codes +const int CDVD_ERROR_SUCCESS = 0; +const int CDVD_ERROR_FAIL = -1; +const int CDVD_ERROR_UNINITIALIZED = -2; +const int CDVD_ERROR_PENDING = 1; + +// srb codes +const int CDVD_SRB_ERROR = -1; +const int CDVD_SRB_COMPLETED = 0; +const int CDVD_SRB_PENDING = 1; + +// max number of c/dvd drives to be supported +const int CDVD_MAX_SUPPORTED_DRIVES = 26; + +// max number of sectors returned per read +const int CDVD_NUM_SECTORS_PER_BUFF = 26; + +// num buffers selectable (used by c/dvd reads) +const int CDVD_NUM_BUFFERS = 2; + +// supported sector sizes +const int CDVD_SECTOR_SIZE_CD = 2352; +const int CDVD_SECTOR_SIZE_DVD = 2048; + +// retry for srb +const int CDVD_MAX_RETRY = 2; + +// mmc datamodes (indicates return fields) +const int CDVD_MMC_DATAMODE_RAW = 0xF8; +const int CDVD_MMC_DATAMODE_USER = 0x10; + +// c/dvd drive types +const int CDVD_DRIVETYPE_UNKNOWN = -1; // everything is fucked, dunno what type of drive it is +const int CDVD_DRIVETYPE_CD = 1; // it's a cd ONLY drive +const int CDVD_DRIVETYPE_DVD = 2; // it's a dvd ONLY drive +const int CDVD_DRIVETYPE_CDVD = 3; // it's a c/dvd drive (read's both cdrom & dvd's) + +// c/dvd media types +const int CDVD_MEDIATYPE_UNKNOWN = -1; // everything is fucked, unknown dumbfuck media +const int CDVD_MEDIATYPE_CD = 1; // its a cd, yay (yes i know there's various types of cd's) +const int CDVD_MEDIATYPE_DVD = 2; // it's a dvd, (okay various types of dvd and all that shit, but who cares) + +// prelim, unused +const int CDVD_CDTYPE_UNKNOWN = -1; +const int CDVD_CDTYPE_CDDA = 0; +const int CDVD_CDTYPE_DATA = 1; +const int CDVD_CDTYPE_CDXA = 2; + +// prelim, unused +const int CDVD_DVDTYPE_UNKNOWN = -1; +const int CDVD_DVDTYPE_DVDROM = 0; +const int CDVD_DVDTYPE_DVDMINRW = 1; +const int CDVD_DVDTYPE_DVDPLSRW = 2; +const int CDVD_DVDTYPE_DVDRAM = 3; + + +#endif // !defined(AFX_CONSTANTS_H__A0D50EAF_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/ioctl.cpp b/plugins/cdvd/CDVDdraft/Src/ioctl.cpp new file mode 100644 index 0000000000..f0cf3b171e --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/ioctl.cpp @@ -0,0 +1,208 @@ +// Ioctl.cpp: implementation of the ioctl methods +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "cdvd.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +/***********************************************************/ +/* IOCTL Init/Shutdown related methods */ +/***********************************************************/ +int CCdvd::Ioctl_Init() +{ + int retval = CDVD_ERROR_FAIL; + + if(m_bIoctlInitialized) + return CDVD_ERROR_SUCCESS; + + + + return retval; +} + +// shuts down ioctl +int CCdvd::Ioctl_Shutdown() +{ + int retval = CDVD_ERROR_SUCCESS; + + + GetNumSectors = Dummy_T1; + GetToc = Dummy_T1; + Stop = Dummy_T1; + Play = Dummy_T3; + TestReady = Dummy_T1; + SetSpeed = Dummy_T2; + SetSectorSize = Dummy_T2; + ReadSector = Dummy_T4; + UpdateInterfaceObject(); + + ShutdownBuffers(); + return retval; +} + +// open a drive for reading +int CCdvd::Ioctl_OpenDrive(int drv_num) +{ + int retval = CDVD_ERROR_SUCCESS; + CloseDrive(); + m_nCurrentDrive = drv_num; + + return retval; +} + +// dummy for now +int CCdvd::Ioctl_CloseDrive() +{ + int retval = CDVD_ERROR_SUCCESS; + m_nCurrentDrive = -1; + + return retval; +} + +// get srb status +int CCdvd::Ioctl_GetSrbStatus(int srb_num) +{ + int retval = CDVD_SRB_ERROR; + switch(m_nCurrentReadMode) + { + case CDVD_READ_MMC: + case CDVD_READ_SCSI10: + case CDVD_READ_D8: + case CDVD_READ_D410: + case CDVD_READ_D412: + default: break; + } + + if(retval == SS_COMP) retval = CDVD_SRB_COMPLETED; + else if(retval == SS_PENDING) retval = CDVD_SRB_PENDING; + else retval = CDVD_SRB_ERROR; + + return retval; +} + +// set read mode +int CCdvd::Ioctl_SetReadMode(CDVD_READ_MODE read_mode) +{ + int retval = CDVD_ERROR_SUCCESS; + + switch(read_mode) + { + case CDVD_READ_MMC: + case CDVD_READ_SCSI10: + case CDVD_READ_D8: + case CDVD_READ_D410: + case CDVD_READ_D412: + default: retval = CDVD_ERROR_FAIL; break; + } + + UpdateInterfaceObject(); + + return retval; +} + +// search for scsi adapters with c/dvd drives. +int CCdvd::Ioctl_ScsiBusScan() +{ + int retval = CDVD_ERROR_SUCCESS; + + HANDLE handle; + char adapter_name[16]; + UI08 buffer[2048]; + int adapter_num = 0; + + memset(m_drvDetails, 0, CDVD_MAX_SUPPORTED_DRIVES * sizeof(ADAPTERINFO)); + + m_nDrives = 0; + for(;;) + { + wsprintf(adapter_name,"\\\\.\\SCSI%d:", adapter_num); + + ++adapter_num; + + if((handle = CreateFile(adapter_name, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL)) == INVALID_HANDLE_VALUE) + { + break; // no more scsi adapters + } + + UI32 nreturned; + if(DeviceIoControl(handle, + IOCTL_SCSI_GET_INQUIRY_DATA, + NULL, + 0, + buffer, + sizeof(buffer), + &nreturned, + FALSE) == 0) + { + continue; // failed + } + + Ioctl_AddAdapter(adapter_num, buffer); + } + + return retval; +} + +// add an adapter to the adapter list +int CCdvd::Ioctl_AddAdapter(int adptr_num, UI08 *buffer) +{ + int retval = CDVD_ERROR_SUCCESS; + + SCSI_ADAPTER_BUS_INFO *adapter_info = (SCSI_ADAPTER_BUS_INFO *) buffer; + char string[40]; + + memset(string, 0, sizeof(string)); + + for (int i = 0; i < adapter_info->NumberOfBuses; i++) + { + SCSI_INQUIRY_DATA *inquiry_data = + (PSCSI_INQUIRY_DATA) (buffer + adapter_info->BusData[i].InquiryDataOffset); + + //while + if(adapter_info->BusData[i].InquiryDataOffset) + { + if(inquiry_data->InquiryData[0] == 0x05) // c/dvd drive + { + m_drvDetails[m_nDrives].ha = adptr_num; + m_drvDetails[m_nDrives].id = inquiry_data->TargetId; + m_drvDetails[m_nDrives].lun = inquiry_data->Lun; + m_drvDetails[m_nDrives].hostname[0] = '\0'; + + memcpy(m_drvDetails[m_nDrives].name, + &inquiry_data->InquiryData[8] + 9, 27); + + m_drvDetails[m_nDrives].name[27] = '\0'; + ++m_nDrives; + } + + if(inquiry_data->NextInquiryDataOffset == 0) + { + break; + } + + inquiry_data = (SCSI_INQUIRY_DATA *) (buffer + inquiry_data->NextInquiryDataOffset); + } + } + + return retval; +} + +/***********************************************************/ +/* IOCTL Execute SRB */ +/***********************************************************/ + +/***********************************************************/ +/* ASPI C/DVD Methods */ +/***********************************************************/ diff --git a/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries b/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries new file mode 100644 index 0000000000..964ba3fcb0 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries @@ -0,0 +1,2 @@ +/cdvddraft.rc2/1.1.1.1/Wed Aug 27 00:52:39 2003// +D diff --git a/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries.Extra b/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries.Extra new file mode 100644 index 0000000000..c2ebd7b816 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/res/CVS/Entries.Extra @@ -0,0 +1 @@ +/cdvddraft.rc2/// diff --git a/plugins/cdvd/CDVDdraft/Src/res/CVS/Repository b/plugins/cdvd/CDVDdraft/Src/res/CVS/Repository new file mode 100644 index 0000000000..7dfbb18921 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/res/CVS/Repository @@ -0,0 +1 @@ +plugins/cdvd/CDVDdraft/Src/res diff --git a/plugins/cdvd/CDVDdraft/Src/res/CVS/Root b/plugins/cdvd/CDVDdraft/Src/res/CVS/Root new file mode 100644 index 0000000000..288eecb9dd --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/res/CVS/Root @@ -0,0 +1 @@ +:ext:aumatt@cvs.sourceforge.net:/cvsroot/pcsx2 diff --git a/plugins/cdvd/CDVDdraft/Src/res/cdvddraft.rc2 b/plugins/cdvd/CDVDdraft/Src/res/cdvddraft.rc2 new file mode 100644 index 0000000000..fe545830a8 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/res/cdvddraft.rc2 @@ -0,0 +1,13 @@ +// +// CDVDDRAFT.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDdraft/Src/resource.h b/plugins/cdvd/CDVDdraft/Src/resource.h new file mode 100644 index 0000000000..d97fa4ec1b --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cdvddraft.rc +// +#define IDD_CONFIG 7000 +#define IDC_COMBO1 7001 +#define IDC_DRIVE 7001 +#define IDC_COMBO2 7002 +#define IDC_INTERFACE 7002 +#define IDC_COMBO3 7003 +#define IDC_READMODE 7003 +#define IDC_PREFETCH 7004 +#define IDD_ABOUT 7007 +#define IDB_BITMAP1 7010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 7011 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 7000 +#define _APS_NEXT_SYMED_VALUE 7000 +#endif +#endif diff --git a/plugins/cdvd/CDVDdraft/Src/typedefs.h b/plugins/cdvd/CDVDdraft/Src/typedefs.h new file mode 100644 index 0000000000..4027655a1b --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/typedefs.h @@ -0,0 +1,125 @@ +// typedefs.h: interface for the typedefs class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TYPEDEFS_H__A0D50EB0_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) +#define AFX_TYPEDEFS_H__A0D50EB0_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#if !defined(UI32) +typedef unsigned long UI32; +#endif + +#if !defined(SI32) +typedef long SI32; +#endif + +#if !defined(UI16) +typedef unsigned short UI16; +#endif + +#if !defined(SI16) +typedef short SI16; +#endif + +#if !defined(UI08) +typedef unsigned char UI08; +#endif + +#if !defined(SI08) +typedef char SI08; +#endif + +#if !defined(MAX_PATH) +const int MAX_PATH = 256; +#endif + +#if !defined(EXTERN) +#define EXTERN extern +#endif + +class CCdvd; + +typedef int (CCdvd::*CDVD_INTF_FUNC_T1)(); +typedef int (CCdvd::*CDVD_INTF_FUNC_T2)(int a); +typedef int (CCdvd::*CDVD_INTF_FUNC_T3)(int a, int b); +typedef int (CCdvd::*CDVD_INTF_FUNC_T4)(int a, HANDLE *b); +typedef DWORD (*CDROMSendASPI32Command)(LPSRB); +typedef DWORD (*CDROMGetASPI32SupportInfo)(void); + +// adapater info +typedef struct tagADAPTERINFO +{ + UI08 ha; + UI08 id; + UI08 lun; + char hostname[MAX_PATH]; + char name[MAX_PATH]; + +} ADAPTERINFO, *LPADAPTERINFO; + +// SPTI command buffer +typedef struct tagSPTD_WITH_SENSE_BUFF +{ + SCSI_PASS_THROUGH_DIRECT sptd; + UI32 filler; + UI08 sensebuff[32]; + +} SPTD_WITH_SENSE_BUFF, *PSPTD_WITH_SENSE_BUFF; + +// scsi mode/block selection header +typedef struct tagMODESELHEADER +{ + UI08 reserved1; + UI08 medium; + UI08 reserved2; + UI08 block_desc_length; + UI08 density; + UI08 number_of_blocks_hi; + UI08 number_of_blocks_med; + UI08 number_of_blocks_lo; + UI08 reserved3; + UI08 block_length_hi; + UI08 block_length_med; + UI08 block_length_lo; + +} MODESELHEADER, *PMODESELHEADER; + +// toc track descriptor definition +typedef struct tagTOCTRACKDESCRIPTOR +{ + UI08 reserved1; + UI08 adr_control; + UI08 track_num; // based 1 + UI08 reserved2; + UI08 lba_byte3; + UI08 lba_byte2; + UI08 lba_byte1; + UI08 lba_byte0; + +} TOCTRACK_DESCRIPTOR, *LPTOCTRACKDESCRIPTOR; + +// toc data definition +typedef struct tagTOCDATA +{ + UI08 datalen_byte1; + UI08 datalen_byte0; + UI08 first_track_num; //based 1 + UI08 last_track_num; //based 1 + +} TOCDATA, *LPTOCDATA; + +// information recovered per track (start offset & track_type only) +typedef struct tagDECODEDTRACKINFO +{ + UI32 track_offset[256]; + UI08 track_type[256]; + UI32 total_tracks; + +} DECODEDTRACKINFO, *LPDECODEDTRACKINFO; + + +#endif // !defined(AFX_TYPEDEFS_H__A0D50EB0_BD80_11D7_8E2C_0050DA15DE89__INCLUDED_) diff --git a/plugins/cdvd/CDVDdraft/Src/winaspi/scsidefs.h b/plugins/cdvd/CDVDdraft/Src/winaspi/scsidefs.h new file mode 100644 index 0000000000..4f4555a967 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/winaspi/scsidefs.h @@ -0,0 +1,279 @@ +#pragma pack(1) + +//*************************************************************************** +// +// Name: SCSIDEFS.H +// +// Description: SCSI definitions ('C' Language) +// +//*************************************************************************** + +//*************************************************************************** +// %%% TARGET STATUS VALUES %%% +//*************************************************************************** +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full + +//*************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//*************************************************************************** +#define MAXLUN 7 // Maximum Logical Unit Id +#define MAXTARG 7 // Maximum Target Id +#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs +#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Commands for all Device Types %%% +//*************************************************************************** +#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_COPY 0x18 // Copy (O) +#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) +#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) +#define SCSI_LOG_SELECT 0x4C // Log Select (O) +#define SCSI_LOG_SENSE 0x4D // Log Sense (O) +#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) +#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) +#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) +#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) +#define SCSI_READ_BUFF 0x3C // Read Buffer (O) +#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) +#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) +#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Direct Access Devices %%% +//*************************************************************************** +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) +#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) +#define SCSI_PREFETCH 0x34 // Prefetch (O) +#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) +#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) +#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) +#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) +#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) +#define SCSI_READ_LONG 0x3E // Read Long (O) +#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) +#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) +#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) +#define SCSI_REZERO 0x01 // Rezero Unit (O) +#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) +#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) +#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) +#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) +#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) +#define SCSI_SET_LIMIT 0x33 // Set Limits (O) +#define SCSI_START_STP 0x1B // Start/Stop Unit (O) +#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) +#define SCSI_VERIFY 0x2F // Verify (O) +#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) +#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) +#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) +#define SCSI_WRITE_LONG 0x3F // Write Long (O) +#define SCSI_WRITE_SAME 0x41 // Write Same (O) + +//*************************************************************************** +// %%% Commands Unique to Sequential Access Devices %%% +//*************************************************************************** +#define SCSI_ERASE 0x19 // Erase (MANDATORY) +#define SCSI_LOAD_UN 0x1B // Load/Unload (O) +#define SCSI_LOCATE 0x2B // Locate (O) +#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) +#define SCSI_READ_POS 0x34 // Read Position (O) +#define SCSI_READ_REV 0x0F // Read Reverse (O) +#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) +#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) +#define SCSI_REWIND 0x01 // Rewind (MANDATORY) +#define SCSI_SPACE 0x11 // Space (MANDATORY) +#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) +#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Printer Devices %%% +//*************************************************************************** +#define SCSI_PRINT 0x0A // Print (MANDATORY) +#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) +#define SCSI_STOP_PNT 0x1B // Stop Print (O) +#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Processor Devices %%% +//*************************************************************************** +#define SCSI_RECEIVE 0x08 // Receive (O) +#define SCSI_SEND 0x0A // Send (O) + +//*************************************************************************** +// %%% Commands Unique to Write-Once Devices %%% +//*************************************************************************** +#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) +#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) +#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) +#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) +#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) +#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) +#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) +#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) +#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) +#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) +#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) +#define SCSI_WRITE12 0xAA // Write 12-Byte (O) +#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) +#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) + +//*************************************************************************** +// %%% Commands Unique to CD-ROM Devices %%% +//*************************************************************************** +#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) +#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) +#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) +#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) +#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) +#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) +#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) +#define SCSI_READHEADER 0x44 // Read Header (O) +#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) +#define SCSI_READ_TOC 0x43 // Read TOC (O) + +//*************************************************************************** +// %%% Commands Unique to Scanner Devices %%% +//*************************************************************************** +#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) +#define SCSI_GETWINDOW 0x25 // Get Window (O) +#define SCSI_OBJECTPOS 0x31 // Object Postion (O) +#define SCSI_SCAN 0x1B // Scan (O) +#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Optical Memory Devices %%% +//*************************************************************************** +#define SCSI_UpdateBlk 0x3D // Update Block (O) + +//*************************************************************************** +// %%% Commands Unique to Medium Changer Devices %%% +//*************************************************************************** +#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) +#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) +#define SCSI_POSTOELEM 0x2B // Position to Element (O) +#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) +#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) + +//*************************************************************************** +// %%% Commands Unique to Communication Devices %%% +//*************************************************************************** +#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) +#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) +#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) +#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) +#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) +#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% END OF SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Request Sense Data Format %%% +//*************************************************************************** +typedef struct { + + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier + BYTE FieldRepUCode; // Field Replaceable Unit Code + BYTE SenKeySpec15; // Sense Key Specific 15th byte + BYTE SenKeySpec16; // Sense Key Specific 16th byte + BYTE SenKeySpec17; // Sense Key Specific 17th byte + BYTE AddSenseBytes; // Additional Sense Bytes + +} SENSE_DATA_FMT; + +//*************************************************************************** +// %%% REQUEST SENSE ERROR CODE %%% +//*************************************************************************** +#define SERROR_CURRENT 0x70 // Current Errors +#define SERROR_DEFERED 0x71 // Deferred Errors + +//*************************************************************************** +// %%% REQUEST SENSE BIT DEFINITIONS %%% +//*************************************************************************** +#define SENSE_VALID 0x80 // Byte 0 Bit 7 +#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 +#define SENSE_EOM 0x40 // Byte 2 Bit 6 +#define SENSE_ILI 0x20 // Byte 2 Bit 5 + +//*************************************************************************** +// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% +//*************************************************************************** +#define KEY_NOSENSE 0x00 // No Sense +#define KEY_RECERROR 0x01 // Recovered Error +#define KEY_NOTREADY 0x02 // Not Ready +#define KEY_MEDIUMERR 0x03 // Medium Error +#define KEY_HARDERROR 0x04 // Hardware Error +#define KEY_ILLGLREQ 0x05 // Illegal Request +#define KEY_UNITATT 0x06 // Unit Attention +#define KEY_DATAPROT 0x07 // Data Protect +#define KEY_BLANKCHK 0x08 // Blank Check +#define KEY_VENDSPEC 0x09 // Vendor Specific +#define KEY_COPYABORT 0x0A // Copy Abort +#define KEY_EQUAL 0x0C // Equal (Search) +#define KEY_VOLOVRFLW 0x0D // Volume Overflow +#define KEY_MISCOMP 0x0E // Miscompare (Search) +#define KEY_RESERVED 0x0F // Reserved + +//*************************************************************************** +// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% +//*************************************************************************** +#define DTYPE_DASD 0x00 // Disk Device +#define DTYPE_SEQD 0x01 // Tape Device +#define DTYPE_PRNT 0x02 // Printer +#define DTYPE_PROC 0x03 // Processor +#define DTYPE_WORM 0x04 // Write-once read-multiple +#define DTYPE_CROM 0x05 // CD-ROM device +#define DTYPE_CDROM 0x05 // CD-ROM device +#define DTYPE_SCAN 0x06 // Scanner device +#define DTYPE_OPTI 0x07 // Optical memory device +#define DTYPE_JUKE 0x08 // Medium Changer device +#define DTYPE_COMM 0x09 // Communications device +#define DTYPE_RESL 0x0A // Reserved (low) +#define DTYPE_RESH 0x1E // Reserved (high) +#define DTYPE_UNKNOWN 0x1F // Unknown or no device type + +//*************************************************************************** +// %%% ANSI APPROVED VERSION DEFINITIONS %%% +//*************************************************************************** +#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand +#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) +#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 +#define ANSI_RESLO 0x3 // Reserved (low) +#define ANSI_RESHI 0x7 // Reserved (high) + +#pragma pack() diff --git a/plugins/cdvd/CDVDdraft/Src/winaspi/wnaspi32.h b/plugins/cdvd/CDVDdraft/Src/winaspi/wnaspi32.h new file mode 100644 index 0000000000..99cd6fa3d1 --- /dev/null +++ b/plugins/cdvd/CDVDdraft/Src/winaspi/wnaspi32.h @@ -0,0 +1,325 @@ +/****************************************************************************** +** +** Module Name: wnaspi32.h +** +** Description: Header file for ASPI for Win32. This header includes +** macro and type declarations, and can be included without +** modification when using Borland C++ or Microsoft Visual +** C++ with 32-bit compilation. If you are using a different +** compiler then you MUST ensure that structures are packed +** onto byte alignments, and that C++ name mangling is turned +** off. +** +** Notes: This file created using 4 spaces per tab. +** +******************************************************************************/ + +#ifndef __WNASPI32_H__ +#define __WNASPI32_H__ + +/* +** Make sure structures are packed and undecorated. +*/ + +#ifdef __BORLANDC__ +#pragma option -a1 +#endif //__BORLANDC__ + +#ifdef _MSC_VER +#pragma pack(1) +#endif //__MSC_VER + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +//***************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//***************************************************************************** + +#define SENSE_LEN 14 // Default sense buffer length +#define SRB_DIR_SCSI 0x00 // Direction determined by SCSI +#define SRB_POSTING 0x01 // Enable ASPI posting +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 // Enable residual byte count reporting +#define SRB_DIR_IN 0x08 // Transfer from SCSI target to host +#define SRB_DIR_OUT 0x10 // Transfer from host to SCSI target +#define SRB_EVENT_NOTIFY 0x40 // Enable ASPI event notification + +#define RESIDUAL_COUNT_SUPPORTED 0x02 // Extended buffer flag +#define MAX_SRB_TIMEOUT 108000lu // 30 hour maximum timeout in s +#define DEFAULT_SRB_TIMEOUT 108000lu // Max timeout by default + + +//***************************************************************************** +// %%% ASPI Command Definitions %%% +//***************************************************************************** + +#define SC_HA_INQUIRY 0x00 // Host adapter inquiry +#define SC_GET_DEV_TYPE 0x01 // Get device type +#define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI command +#define SC_ABORT_SRB 0x03 // Abort an SRB +#define SC_RESET_DEV 0x04 // SCSI bus device reset +#define SC_SET_HA_PARMS 0x05 // Set HA parameters +#define SC_GET_DISK_INFO 0x06 // Get Disk information +#define SC_RESCAN_SCSI_BUS 0x07 // ReBuild SCSI device map +#define SC_GETSET_TIMEOUTS 0x08 // Get/Set target timeouts + +//***************************************************************************** +// %%% SRB Status %%% +//***************************************************************************** + +#define SS_PENDING 0x00 // SRB being processed +#define SS_COMP 0x01 // SRB completed without error +#define SS_ABORTED 0x02 // SRB aborted +#define SS_ABORT_FAIL 0x03 // Unable to abort SRB +#define SS_ERR 0x04 // SRB completed with error + +#define SS_INVALID_CMD 0x80 // Invalid ASPI command +#define SS_INVALID_HA 0x81 // Invalid host adapter number +#define SS_NO_DEVICE 0x82 // SCSI device not installed + +#define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB +#define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Windows +#define SS_BUFFER_ALIGN 0xE1 // Buffer not aligned (replaces OLD_MANAGER in Win32) +#define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode +#define SS_NO_ASPI 0xE3 // No ASPI managers resident +#define SS_FAILED_INIT 0xE4 // ASPI for windows failed init +#define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute cmd +#define SS_BUFFER_TO_BIG 0xE6 // Buffer size to big to handle! +#define SS_MISMATCHED_COMPONENTS 0xE7 // The DLLs/EXEs of ASPI don't version check +#define SS_NO_ADAPTERS 0xE8 // No host adapters to manage +#define SS_INSUFFICIENT_RESOURCES 0xE9 // Couldn't allocate resources needed to init +#define SS_ASPI_IS_SHUTDOWN 0xEA // Call came to ASPI after PROCESS_DETACH +#define SS_BAD_INSTALL 0xEB // The DLL or other components are installed wrong + +//***************************************************************************** +// %%% Host Adapter Status %%% +//***************************************************************************** + +#define HASTAT_OK 0x00 // Host adapter did not detect an // error +#define HASTAT_SEL_TO 0x11 // Selection Timeout +#define HASTAT_DO_DU 0x12 // Data overrun data underrun +#define HASTAT_BUS_FREE 0x13 // Unexpected bus free +#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence // failure +#define HASTAT_TIMEOUT 0x09 // Timed out while SRB was waiting to beprocessed. +#define HASTAT_COMMAND_TIMEOUT 0x0B // Adapter timed out processing SRB. +#define HASTAT_MESSAGE_REJECT 0x0D // While processing SRB, the // adapter received a MESSAGE +#define HASTAT_BUS_RESET 0x0E // A bus reset was detected. +#define HASTAT_PARITY_ERROR 0x0F // A parity error was detected. +#define HASTAT_REQUEST_SENSE_FAILED 0x10 // The adapter failed in issuing + +//***************************************************************************** +// %%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY (0) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_HA_INQUIRY + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE HA_Count; // 08/008 Number of host adapters present + BYTE HA_SCSI_ID; // 09/009 SCSI ID of host adapter + BYTE HA_ManagerId[16]; // 0A/010 String describing the manager + BYTE HA_Identifier[16]; // 1A/026 String describing the host adapter + BYTE HA_Unique[16]; // 2A/042 Host Adapter Unique parameters + WORD HA_Rsvd1; // 3A/058 Reserved, MUST = 0 +} +SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry; + +//***************************************************************************** +// %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_GET_DEV_TYPE + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved, MUST = 0 + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + BYTE SRB_DeviceType; // 0A/010 Target's peripheral device type + BYTE SRB_Rsvd1; // 0B/011 Reserved, MUST = 0 +} +SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock; + +//***************************************************************************** +// %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_EXEC_SCSI_CMD + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + WORD SRB_Rsvd1; // 0A/010 Reserved for Alignment + DWORD SRB_BufLen; // 0C/012 Data Allocation Length + BYTE FAR *SRB_BufPointer; // 10/016 Data Buffer Pointer + BYTE SRB_SenseLen; // 14/020 Sense Allocation Length + BYTE SRB_CDBLen; // 15/021 CDB Length + BYTE SRB_HaStat; // 16/022 Host Adapter Status + BYTE SRB_TargStat; // 17/023 Target Status + VOID FAR *SRB_PostProc; // 18/024 Post routine + BYTE SRB_Rsvd2[20]; // 1C/028 Reserved, MUST = 0 + BYTE CDBByte[16]; // 30/048 SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // 50/064 Request Sense buffer +} +SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd; + +//***************************************************************************** +// %%% SRB - ABORT AN SRB - SC_ABORT_SRB (3) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_ABORT_SRB + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + VOID FAR *SRB_ToAbort; // 08/008 Pointer to SRB to abort +} +SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort; + +//***************************************************************************** +// %%% SRB - BUS DEVICE RESET - SC_RESET_DEV (4) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_RESET_DEV + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + BYTE SRB_Rsvd1[12]; // 0A/010 Reserved for Alignment + BYTE SRB_HaStat; // 16/022 Host Adapter Status + BYTE SRB_TargStat; // 17/023 Target Status + VOID FAR *SRB_PostProc; // 18/024 Post routine + BYTE SRB_Rsvd2[36]; // 1C/028 Reserved, MUST = 0 +} +SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset; + +//***************************************************************************** +// %%% SRB - GET DISK INFORMATION - SC_GET_DISK_INFO %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_GET_DISK_INFO + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved, MUST = 0 + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + BYTE SRB_DriveFlags; // 0A/010 Driver flags + BYTE SRB_Int13HDriveInfo; // 0B/011 Host Adapter Status + BYTE SRB_Heads; // 0C/012 Preferred number of heads translation + BYTE SRB_Sectors; // 0D/013 Preferred number of sectors translation + BYTE SRB_Rsvd1[10]; // 0E/014 Reserved, MUST = 0 +} +SRB_GetDiskInfo, *PSRB_GetDiskInfo, FAR *LPSRB_GetDiskInfo; + +//***************************************************************************** +// %%% SRB - RESCAN SCSI BUS(ES) ON SCSIPORT %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_RESCAN_SCSI_BUS + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved, MUST = 0 + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 +} +SRB_RescanPort, *PSRB_RescanPort, FAR *LPSRB_RescanPort; + +//***************************************************************************** +// %%% SRB - GET/SET TARGET TIMEOUTS %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_GETSET_TIMEOUTS + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + DWORD SRB_Timeout; // 0A/010 Timeout in half seconds +} +SRB_GetSetTimeouts, *PSRB_GetSetTimeouts, FAR *LPSRB_GetSetTimeouts; + +//***************************************************************************** +// %%% ASPIBUFF - Structure For Controllng I/O Buffers %%% +//***************************************************************************** + +typedef struct tag_ASPI32BUFF // Offset +{ // HX/DEC + PBYTE AB_BufPointer; // 00/000 Pointer to the ASPI allocated buffer + DWORD AB_BufLen; // 04/004 Length in bytes of the buffer + DWORD AB_ZeroFill; // 08/008 Flag set to 1 if buffer should be zeroed + DWORD AB_Reserved; // 0C/012 Reserved +} +ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF; + +//***************************************************************************** +// %%% PROTOTYPES - User Callable ASPI for Win32 Functions %%% +//***************************************************************************** + +typedef void *LPSRB; + +#if defined(__BORLANDC__) + +DWORD _import GetASPI32SupportInfo( void ); +DWORD _import SendASPI32Command( LPSRB ); +BOOL _import GetASPI32Buffer( PASPI32BUFF ); +BOOL _import FreeASPI32Buffer( PASPI32BUFF ); +BOOL _import TranslateASPI32Address( PDWORD, PDWORD ); + +#elif defined(_MSC_VER) + +__declspec(dllimport) DWORD GetASPI32SupportInfo( void ); +__declspec(dllimport) DWORD SendASPI32Command( LPSRB ); +__declspec(dllimport) BOOL GetASPI32Buffer( PASPI32BUFF ); +__declspec(dllimport) BOOL FreeASPI32Buffer( PASPI32BUFF ); +__declspec(dllimport) BOOL TranslateASPI32Address( PDWORD, PDWORD ); + +#else + +extern DWORD GetASPI32SupportInfo( void ); +extern DWORD GetASPI32Command( LPSRB ); +extern BOOL GetASPI32Buffer( PASPI32BUFF ); +extern BOOL FreeASPI32Buffer( PASPI32BUFF ); +extern BOOL TranslateASPI32Address( PDWORD, PDWORD ); + +#endif + +/* +** Restore compiler default packing and close off the C declarations. +*/ + +#ifdef __BORLANDC__ +#pragma option -a. +#endif //__BORLANDC__ + +#ifdef _MSC_VER +#pragma pack() +#endif //_MSC_VER + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //__WNASPI32_H__ diff --git a/plugins/cdvd/CDVDiso/ReadMe.txt b/plugins/cdvd/CDVDiso/ReadMe.txt new file mode 100644 index 0000000000..b1a915352f --- /dev/null +++ b/plugins/cdvd/CDVDiso/ReadMe.txt @@ -0,0 +1,78 @@ +CDVDiso v0.5 +------------ + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Linux requeriments: +------------------ + You need the GTK library, compiled with GTK v1.2.5, + the Zlib library (v1.1.3) and the bz2 library (v1.0.0). + +Usage: +----- + Place the file "libCDVDiso.so" (linux) or "CDVDiso.dll" (win32) at the Plugin + directory of the Emulator to use it. + + Linux only: Also place the cfgCDVDiso file at your $HOME directory or at the + Emulator directory. + +Configuration: +------------- + You can either write the iso you want to use in the config dialog, or everytime + you run the emu open it, if you're doing this don't write anything in the dialog. + +Creating an iso (linux only): +--------------- + To create an iso you can use the buttons 'Create Iso' or 'Create Compressed Iso', + the file will be the one in the Iso Edit, and the Cdrom Device is the cdrom that + will be used as source. + The compression method is specified by the Compression Method Combo. + + Note: This will fail if the file in the Iso Edit already exists (if it's + compressed the .Z or .bz suffix will be added). + +Compressed isos: +--------------- + You must create them by the Compress Iso button, this will create a .Z or .bz + file (the compressed image) and a .Z.table or .bz.index file (this is a table, + for speed reasons), both will be created in the same dir the selected iso + image, the original image will not be deleted and/or changed, and also you can + decompress the compressed iso with Decompress Iso button. + The compression method is specified by the Compression Method Combo. + + Note: you only can decompress the images with the Decompress button, not with + compress or bzip2. + +Compression Method: +------------------ + .Z - compress faster: this will compress faster, but not as good as the .bz. + .bz - compress better: will compress better, but slower. + +Changes: +------- + v0.5: + * Added block dumping code + * Added BZ2/Z2 format ;) + * Added optimaze asm code of zlib with vsnet2003 only. Compression / Uncompression should be faster now (shadow) + * Added Vsnet2005 beta1 project files + amd64 asm optimaze code for zlib (shadow) + + v0.4: + * Rewrote mostly ;) + * .bz is still unsupported + + v0.3: + * Better Iso detection, thx florin :) + * Updated to PS2Edefs v0.4.5 + + v0.2: + * Added support for isos using 2048 blocksize + * Nero images are supported + * Better extension filtering + + v0.1: + * First Release + * Tested with Pcsx2 + + Email: diff --git a/plugins/cdvd/CDVDiso/build.sh b/plugins/cdvd/CDVDiso/build.sh new file mode 100644 index 0000000000..3f569fbc03 --- /dev/null +++ b/plugins/cdvd/CDVDiso/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +curdir=`pwd` + +echo ---------------- +echo Building CDVDiso +echo ---------------- + +cd ${curdir}/src/Linux +make $@ + +# copy the files +if [ -s cfgCDVDiso ] && [ -s libCDVDiso.so ] +then +cp cfgCDVDiso libCDVDiso.so ${PCSX2PLUGINS} +fi diff --git a/plugins/cdvd/CDVDiso/src/CDVDiso.h b/plugins/cdvd/CDVDiso/src/CDVDiso.h new file mode 100644 index 0000000000..7cc9de5a84 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/CDVDiso.h @@ -0,0 +1,80 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 + */ + + +#ifdef __MSCW32__ +#pragma warning(disable:4018) +#endif + +#define CDVDdefs +#include "PS2Edefs.h" +#include "libiso.h" + +#define CDVD_LOG __Log +extern FILE *cdvdLog; + +void __Log(char *fmt, ...); + +#define VERBOSE 1 + +char IsoFile[256]; +#define DEV_DEF "" +char CdDev[256]; +#define CDDEV_DEF "/dev/cdrom" +int BlockDump; +isoFile *fdump; + +isoFile *iso; + +typedef struct { + int slsn; + int elsn; +#ifdef __WIN32__ + HANDLE handle; +#else + FILE *handle; +#endif +} _cdIso; +_cdIso cdIso[8]; + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +#define MSF2SECT(m,s,f) (((m)*60+(s)-2)*75+(f)) + +extern unsigned char cdbuffer[]; +unsigned char *pbuffer; +int cdblocksize; +int cdblockofs; +int cdoffset; +int cdtype; +int cdblocks; + +int Zmode; // 1 Z - 2 bz2 +int fmode; // 0 - file / 1 - Zfile +char *Ztable; + +extern char *methods[]; + +void UpdateZmode(); +void CfgOpenFile(); +void SysMessage(char *fmt, ...); + diff --git a/plugins/cdvd/CDVDiso/src/CDVDisop.c b/plugins/cdvd/CDVDiso/src/CDVDisop.c new file mode 100644 index 0000000000..a4bfae0ab0 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/CDVDisop.c @@ -0,0 +1,418 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "CDVDiso.h" +#include "Config.h" + +#ifndef MAX_PATH +#define MAX_PATH 255 +#endif + +FILE *cdvdLog = NULL; + +char *methods[] = { + ".Z - compress faster", + ".BZ - compress better", + NULL +}; + +#ifdef _DEBUG +char *LibName = "Linuzappz Iso CDVD (Debug) "; +#else +char *LibName = "Linuzappz Iso CDVD "; +#endif + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 7; + +unsigned char cdbuffer[CD_FRAMESIZE_RAW * 10] = {0}; + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = lba / (60*75); + *s = (lba / 75) % 60; + *f = lba % 75; +} + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +char* CALLBACK PS2EgetLibName() { + return LibName; +} + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_CDVD; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version << 16) | (revision << 8) | build; +} + +#ifdef _DEBUG +void __Log(char *fmt, ...) { + va_list list; + + if( cdvdLog == NULL ) + return; + + va_start(list, fmt); + vfprintf(cdvdLog, fmt, list); + va_end(list); +} +#else +#define __Log 0&& +#endif + + +s32 CALLBACK CDVDinit() { +#ifdef _DEBUG + cdvdLog = fopen("logs/cdvdLog.txt", "w"); + if (cdvdLog == NULL) { + cdvdLog = fopen("cdvdLog.txt", "w"); + if (cdvdLog == NULL) { + SysMessage("Can't create cdvdLog.txt"); return -1; + } + } + setvbuf(cdvdLog, NULL, _IONBF, 0); + CDVD_LOG("CDVDinit\n"); +#endif + memset(cdIso, 0, sizeof(cdIso)); + return 0; +} + +void CALLBACK CDVDshutdown() { +#ifdef CDVD_LOG + if( cdvdLog != NULL ) + fclose(cdvdLog); +#endif +} + +s32 CALLBACK CDVDopen(const char* pTitle) { + LoadConf(); + + if( pTitle != NULL ) strcpy(IsoFile, pTitle); + + if (*IsoFile == 0) { + char temp[256]; + + CfgOpenFile(); + + LoadConf(); + strcpy(temp, IsoFile); + *IsoFile = 0; + SaveConf(); + strcpy(IsoFile, temp); + } + + iso = isoOpen(IsoFile); + if (iso == NULL) { + SysMessage("Error loading %s\n", IsoFile); + return -1; + } + + if (iso->type == ISOTYPE_DVD) { + cdtype = CDVD_TYPE_PS2DVD; + } else + if (iso->type == ISOTYPE_AUDIO) { + cdtype = CDVD_TYPE_CDDA; + } else { + cdtype = CDVD_TYPE_PS2CD; + } + + if (BlockDump) { + char fname_only[MAX_PATH]; + char* p, *plast; + +#ifdef _WIN32 + char fname[MAX_PATH],ext[MAX_PATH]; + _splitpath(IsoFile,NULL,NULL,fname,ext); + _makepath(fname_only,NULL,NULL,fname,NULL); +#else + plast = p = strchr(IsoFile, '/'); + while(p != NULL) { + plast = p; + p = strchr(p+1, '/'); + } + + if( plast != NULL ) strcpy(fname_only, plast+1); + else strcpy(fname_only, IsoFile); + + plast = p = strchr(fname_only, '.'); + while(p != NULL) { + plast = p; + p = strchr(p+1, '.'); + } + + if( plast != NULL ) *plast = 0; + +#endif + strcat(fname_only, ".dump"); + fdump = isoCreate(fname_only, ISOFLAGS_BLOCKDUMP); + if (fdump) { + isoSetFormat(fdump, iso->blockofs, iso->blocksize, iso->blocks); + } + } else { + fdump = NULL; + } + + return 0; +} + +void CALLBACK CDVDclose() { + isoClose(iso); + if (fdump != NULL) { + isoClose(fdump); + } +} + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + // fake it + u8 min, sec, frm; + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + Buffer->strack = 1; + Buffer->etrack = 1; + + return 0; +} + +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer) { + if (Track == 0) { + Buffer->lsn = iso->blocks; + } else { + Buffer->type = CDVD_MODE1_TRACK; + Buffer->lsn = 0; + } + + return 0; +} + +static int layer1start = -1; +s32 CALLBACK CDVDgetTOC(void* toc) { + u8 type = CDVDgetDiskType(); + u8* tocBuff = (u8*)toc; + + //__Log("CDVDgetTOC\n"); + + if( type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD) + { + int i; + + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + + if( layer1start != -2 && iso->blocks >= 0x300000 ) { + int off = iso->blockofs; + char* tempbuffer; + + // dual sided + tocBuff[ 0] = 0x24; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x41; + tocBuff[ 5] = 0x95; + + tocBuff[14] = 0x60; // dual sided, ptp + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + + // search for it + if( layer1start == -1 ) { + printf("CDVD: searching for layer1..."); + tempbuffer = (char*)malloc(CD_FRAMESIZE_RAW * 10); + for(layer1start = (iso->blocks/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) { + isoReadBlock(iso, tempbuffer, layer1start); + // CD001 + if( tempbuffer[off+1] == 0x43 && tempbuffer[off+2] == 0x44 && tempbuffer[off+3] == 0x30 && tempbuffer[off+4] == 0x30 && tempbuffer[off+5] == 0x31 ) { + break; + } + } + free(tempbuffer); + + if( layer1start == 0x200010 ) { + printf("Couldn't find second layer on dual layer... ignoring\n"); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + layer1start = -2; + return 0; + } + + printf("found at 0x%8.8x\n", layer1start); + layer1start = layer1start+0x30000-1; + } + + tocBuff[20] = layer1start>>24; + tocBuff[21] = (layer1start>>16)&0xff; + tocBuff[22] = (layer1start>>8)&0xff; + tocBuff[23] = (layer1start>>0)&0xff; + } + else { + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm; + s32 i, err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + int _lsn = lsn; + + //__Log("CDVDreadTrack: %x %x\n", lsn, mode); + if (_lsn < 0) { +// lsn = 2097152 + (-_lsn); + lsn = iso->blocks - (-_lsn); + } +// printf ("CDRreadTrack %d\n", lsn); + + isoReadBlock(iso, cdbuffer, lsn); + if (fdump != NULL) { + isoWriteBlock(fdump, cdbuffer, lsn); + } + + pbuffer = cdbuffer; + switch (mode) { + case CDVD_MODE_2352: break; + case CDVD_MODE_2340: pbuffer+= 12; break; + case CDVD_MODE_2328: pbuffer+= 24; break; + case CDVD_MODE_2048: pbuffer+= 24; break; + } + + return 0; +} + +u8* CALLBACK CDVDgetBuffer() { + return pbuffer; +} + +s32 CALLBACK CDVDgetDiskType() { + return cdtype; +} + +s32 CALLBACK CDVDgetTrayStatus() { + return CDVD_TRAY_CLOSE; +} + +s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} +s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + + +s32 CALLBACK CDVDtest() { + if (*IsoFile == 0) + return 0; + + iso = isoOpen(IsoFile); + if (iso == NULL) return -1; + isoClose(iso); + + return 0; +} + diff --git a/plugins/cdvd/CDVDiso/src/Linux/CDVDiso.glade b/plugins/cdvd/CDVDiso/src/Linux/CDVDiso.glade new file mode 100644 index 0000000000..4123673b28 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/CDVDiso.glade @@ -0,0 +1,368 @@ + + + + + cdriso + cdriso + + + + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + CDVD Config Dialog + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkHBox + hbox1 + False + 10 + + 0 + True + True + + + + GtkEntry + GtkEntry_Iso + True + True + True + 0 + + + 0 + True + True + + + + + GtkButton + button5 + True + + clicked + OnFileSel + Tue, 19 Feb 2002 05:35:24 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + + GtkHBox + hbox2 + False + 10 + + 0 + False + False + + + + GtkProgressBar + GtkProgressBar_Progress + 0 + 0 + 100 + GTK_PROGRESS_CONTINUOUS + GTK_PROGRESS_LEFT_TO_RIGHT + False + False + %P %% + 0.5 + 0.5 + + 0 + True + False + + + + + GtkButton + button6 + 61 + True + + clicked + OnStop + Tue, 19 Feb 2002 05:34:11 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + False + GTK_PACK_END + + + + + + GtkHBox + hbox4 + False + 5 + + 0 + True + True + + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Method + False + True + False + True + False + + + 0 + True + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + GtkButton_Compress + True + True + + clicked + OnCompress + Tue, 19 Feb 2002 05:40:44 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + GtkButton_Decompress + True + True + + clicked + OnDecompress + Tue, 19 Feb 2002 06:56:17 GMT + + + GTK_RELIEF_NORMAL + + + + + GtkHBox + hbox3 + False + 5 + + 0 + False + False + + + + GtkLabel + label1 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkEntry + GtkEntry_CdDev + True + True + True + 0 + + + 0 + True + True + + + + + + GtkHButtonBox + hbuttonbox3 + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + GtkButton_Create + True + True + + clicked + OnCreate + Tue, 19 Feb 2002 21:06:29 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + GtkButton_CreateZ + True + True + + clicked + OnCreateZ + Tue, 19 Feb 2002 21:06:19 GMT + + + GTK_RELIEF_NORMAL + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnOk + Tue, 19 Feb 2002 05:42:17 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnCancel + Tue, 19 Feb 2002 05:42:24 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Linux/Config.c b/plugins/cdvd/CDVDiso/src/Linux/Config.c new file mode 100644 index 0000000000..c5eea547b5 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/Config.c @@ -0,0 +1,59 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 +#include +#include +#include +#include + +#include "CDVDiso.h" + +void LoadConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + strcpy(IsoFile, DEV_DEF); + strcpy(CdDev, CDDEV_DEF); + return; + } + fscanf(f, "IsoFile = %[^\n]\n", IsoFile); + fscanf(f, "CdDev = %[^\n]\n", CdDev); + if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix + if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); + fclose(f); +} + +void SaveConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fprintf(f, "IsoFile = %s\n", IsoFile); + fprintf(f, "CdDev = %s\n", CdDev); + fclose(f); +} + diff --git a/plugins/cdvd/CDVDiso/src/Linux/Config.h b/plugins/cdvd/CDVDiso/src/Linux/Config.h new file mode 100644 index 0000000000..d1df0d3e72 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/Config.h @@ -0,0 +1,20 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/cdvd/CDVDiso/src/Linux/Linux.c b/plugins/cdvd/CDVDiso/src/Linux/Linux.c new file mode 100644 index 0000000000..70947b559f --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/Linux.c @@ -0,0 +1,76 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 +#include +#include +#include +#include + +#include "Config.h" +#include "CDVDiso.h" + +void ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgCDVDiso"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + strcpy(cfg, "./cfg/cfgCDVDiso"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + sprintf(cfg, "%s/cfgCDVDiso", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + printf("cfgCDVDiso file not found!\n"); +} + +void CDVDconfigure() { + ExecCfg("configure"); +} + +void CDVDabout() { + ExecCfg("about"); +} + +void CfgOpenFile() { + ExecCfg("open"); +} + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[256]; + char cmd[256]; + + va_start(list, fmt); + vsprintf(tmp, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", tmp); + ExecCfg(cmd); +} diff --git a/plugins/cdvd/CDVDiso/src/Linux/Makefile b/plugins/cdvd/CDVDiso/src/Linux/Makefile new file mode 100644 index 0000000000..e222069790 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/Makefile @@ -0,0 +1,33 @@ + +CC = gcc + +PLUGIN = libCDVDiso.so +CFG = cfgCDVDiso +MKISO = mkiso +CFLAGS = -fPIC -Wall -g -I.. -I. -D__LINUX__ +OBJS = ../CDVDisop.o Config.o Linux.o ../libiso.o +CFGOBJS = conf.o interface.o support.o ${OBJS} +LIBS = -lz -lbz2 -lstdc++ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) ${LIBS} +CFLAGS += $(shell pkg-config --cflags gtk+-2.0) +DEPS:= $(OBJS:.o=.d) $(CFGOBJS:.o=.d) + +all: plugin cfg +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFGOBJS} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/cdvd/CDVDiso/src/Linux/callbacks.c b/plugins/cdvd/CDVDiso/src/Linux/callbacks.c new file mode 100644 index 0000000000..3fe79a9cac --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/callbacks.c @@ -0,0 +1,98 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnFileSel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnStop (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCreate (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCompress (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConfig_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConfig_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnOk (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnDecompress (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCreate (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCreateZ (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/cdvd/CDVDiso/src/Linux/callbacks.h b/plugins/cdvd/CDVDiso/src/Linux/callbacks.h new file mode 100644 index 0000000000..0d24ea4086 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/callbacks.h @@ -0,0 +1,46 @@ +#include + + +void +OnFileSel (GtkButton *button, + gpointer user_data); + +void +OnStop (GtkButton *button, + gpointer user_data); + +void +OnCreate (GtkButton *button, + gpointer user_data); + +void +OnCompress (GtkButton *button, + gpointer user_data); + +void +OnConfig_Ok (GtkButton *button, + gpointer user_data); + +void +OnConfig_Cancel (GtkButton *button, + gpointer user_data); + +void +OnOk (GtkButton *button, + gpointer user_data); + +void +OnCancel (GtkButton *button, + gpointer user_data); + +void +OnDecompress (GtkButton *button, + gpointer user_data); + +void +OnCreate (GtkButton *button, + gpointer user_data); + +void +OnCreateZ (GtkButton *button, + gpointer user_data); diff --git a/plugins/cdvd/CDVDiso/src/Linux/conf.c b/plugins/cdvd/CDVDiso/src/Linux/conf.c new file mode 100644 index 0000000000..9f2c132cea --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/conf.c @@ -0,0 +1,865 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "CDVDiso.h" +#include "Config.h" + +unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + +extern char *LibName; + +extern const unsigned char revision; +extern const unsigned char build; + +GtkWidget *FileSel; + +void OnFile_Ok() { + gchar *File; + + gtk_widget_hide(FileSel); + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(IsoFile, File); + gtk_main_quit(); +} + +void OnFile_Cancel() { + gtk_widget_hide(FileSel); + gtk_main_quit(); +} + +void _CDRopen() { + GtkWidget *Ok, *Cancel; + + FileSel = gtk_file_selection_new("Select Iso File"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnFile_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", + GTK_SIGNAL_FUNC(OnFile_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); + + gtk_main(); + + SaveConf(); +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +static void SysMessageLoc(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + int w; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + w = strlen(msg) * 6 + 20; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(MsgDlg, w, 70); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "cdriso Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 0); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *ConfDlg; +GtkWidget *Edit, *CdEdit; +GtkWidget *FileSel; +GtkWidget *Progress; +GtkWidget *BtnCompress; +GtkWidget *BtnDecompress; +GtkWidget *BtnCreate; +GtkWidget *BtnCreateZ; +GtkWidget *Method; + +GList *methodlist; +extern char *methods[]; + +int stop; + +void OnOk(GtkMenuItem * menuitem, gpointer userdata) { + char *tmp; + + stop=1; + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + tmp = gtk_entry_get_text(GTK_ENTRY(CdEdit)); + strcpy(CdDev, tmp); + SaveConf(); + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnCancel(GtkMenuItem * menuitem, gpointer userdata) { + stop=1; + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnFileSel_Ok() { + gchar *File; + + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + gtk_entry_set_text(GTK_ENTRY(Edit), File); + gtk_widget_destroy(FileSel); +} + +void OnFileSel_Cancel() { + gtk_widget_destroy(FileSel); +} + +void OnFileSel() { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new("Select Psx Iso File"); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), IsoFile); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnStop() { + stop=1; +} + +void UpdZmode() { + char *tmp; + + tmp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(Method)->entry)); + if (!strcmp(tmp, methods[0])) Zmode = 1; + else Zmode = 2; +} + +char buffer[2352 * 10]; + +void OnCompress() { + struct stat buf; + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + char *tmp; + int ret; + isoFile *src; + isoFile *dst; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + UpdZmode(); + + if (Zmode == 1) sprintf(Zfile, "%s.Z2", IsoFile); + if (Zmode == 2) sprintf(Zfile, "%s.BZ2", IsoFile); + + if (stat(Zfile, &buf) != -1) { + char str[256]; + return; +/* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + dst = isoCreate(Zfile, Zmode == 1 ? ISOFLAGS_Z2 : ISOFLAGS_BZ2); + if (dst == NULL) return; + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), (lsn * 100) / src->blocks); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) { + if (ret == -1) { + SysMessageLoc("Error compressing iso image"); + } else { + SysMessageLoc("Iso image compressed OK"); + } + } +} + +void OnDecompress() { +#if 0 + struct stat buf; + FILE *f; + unsigned long c=0, p=0, s; + char table[256]; + char *tmp; + int blocks; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (strstr(IsoFile, ".Z") != NULL) Zmode = 1; + else Zmode = 2; + + strcpy(table, IsoFile); + if (Zmode == 1) strcat(table, ".table"); + else strcat(table, ".index"); + + if (stat(table, &buf) == -1) { + return; + } + if (Zmode == 1) c = s = buf.st_size / 6; + else c = s = (buf.st_size / 4) - 1; + f = fopen(table, "rb"); + Ztable = (char*)malloc(buf.st_size); + fread(Ztable, 1, buf.st_size, f); + fclose(f); + + cdHandle[0] = fopen(IsoFile, "rb"); + if (cdHandle[0] == NULL) { + return; + } + + if (Zmode == 1) IsoFile[strlen(IsoFile) - 2] = 0; + else IsoFile[strlen(IsoFile) - 3] = 0; + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + return; + } + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop=0; + + if (Zmode == 1) { + blocks = 1; + } else { + blocks = 10; + } + + while (c--) { + unsigned long size, pos, ssize; + float per; + + if (Zmode == 1) { + pos = *(unsigned long*)&Ztable[p * 6]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned short*)&Ztable[p * 6 + 4]; + fread(Zbuf, 1, ssize, cdHandle[0]); + } else { + pos = *(unsigned long*)&Ztable[p * 4]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned long*)&Ztable[p * 4 + 4] - pos; + fread(Zbuf, 1, ssize, cdHandle[0]); + } + + size = CD_FRAMESIZE_RAW * blocks; + if (Zmode == 1) uncompress(cdbuffer, &size, Zbuf, ssize); + else BZ2_bzBuffToBuffDecompress(cdbuffer, (unsigned int*)&size, Zbuf, ssize, 0, 0); + + fwrite(cdbuffer, 1, size, f); + + p++; + + per = ((float)p / s); + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + fclose(f); + fclose(cdHandle[0]); cdHandle[0] = NULL; + free(Ztable); Ztable = NULL; + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Decompressed OK"); +#endif +} + +#define CD_LEADOUT (0xaa) +unsigned char param[4]; +int cddev = -1; + +union { + struct cdrom_msf msf; + unsigned char buf[CD_FRAMESIZE_RAW]; +} cr; + +void incSector() { + param[2]++; + if (param[2] == 75) { + param[2] = 0; + param[1]++; + } + if (param[1] == 60) { + param[1] = 0; + param[0]++; + } +} + +long CDR_open(void) { + if (cddev != -1) + return 0; + cddev = open(CdDev, O_RDONLY); + if (cddev == -1) { + printf("CDR: Could not open %s\n", CdDev); + return -1; + } + + return 0; +} + +long CDR_close(void) { + if (cddev == -1) return 0; + close(cddev); + cddev = -1; + + return 0; +} + +// return Starting and Ending Track +// buffer: +// byte 0 - start track +// byte 1 - end track +long CDR_getTN(unsigned char *buffer) { + struct cdrom_tochdr toc; + + if (ioctl(cddev, CDROMREADTOCHDR, &toc) == -1) return -1; + + buffer[0] = toc.cdth_trk0; // start track + buffer[1] = toc.cdth_trk1; // end track + + return 0; +} + +// return Track Time +// buffer: +// byte 0 - frame +// byte 1 - second +// byte 2 - minute +long CDR_getTD(unsigned char track, unsigned char *buffer) { + struct cdrom_tocentry entry; + + if (track == 0) track = 0xaa; // total time + entry.cdte_track = track; + entry.cdte_format = CDROM_MSF; + + if (ioctl(cddev, CDROMREADTOCENTRY, &entry) == -1) return -1; + + buffer[0] = entry.cdte_addr.msf.minute; /* minute */ + buffer[1] = entry.cdte_addr.msf.second; /* second */ + buffer[2] = entry.cdte_addr.msf.frame; /* frame */ + + return 0; +} + +// read track +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame +char *CDR_readTrack(unsigned char *time) { + cr.msf.cdmsf_min0 = time[0]; + cr.msf.cdmsf_sec0 = time[1]; + cr.msf.cdmsf_frame0 = time[2]; + + if (ioctl(cddev, CDROMREADRAW, &cr) == -1) return NULL; + return cr.buf; +} + + +void OnCreate() { + FILE *f; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p=0,s; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char *tmp; +#ifdef VERBOSE + unsigned long count = 0; + int i=0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (stat(IsoFile, &buf) == 0) { + printf("File %s Already exists\n", IsoFile); + return; + } + + if (CDR_open() == -1) { + return; + } + + if (CDR_getTD(ftrack, start) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + if (CDR_getTD(ltrack, end) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]); + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) { /* loop until end */ + float per; + + if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) + break; + buffer = CDR_readTrack(param); + if (buffer == NULL) { + int i; + + for (i=0; i<10; i++) { + buffer = CDR_readTrack(param); + if (buffer != NULL) break; + } + if (buffer == NULL) { + printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); + buffer = bufferz; + buffer[12] = param[0]; + buffer[13] = param[1]; + buffer[14] = param[2]; + buffer[15] = 0x2; + } + } + fwrite(buffer, 1, 2352, f); +#ifdef VERBOSE + count+= CD_FRAMESIZE_RAW; + + printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); + if ((time(NULL) - Ttime) != 0) { + i = (count / 1024) / (time(NULL) - Ttime); + printf("( %5dKbytes/s, %dX)", i, i / 150); + } + putchar(13); + fflush(stdout); +#endif + + incSector(); + + p++; + per = ((float)p / s); + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + + Ttime = time(NULL) - Ttime; + Tm = gmtime(&Ttime); + printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Created OK"); +} + +void OnCreateZ() { + FILE *f; + FILE *t; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p=0,s,c=0; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char table[256]; + char *tmp; + int b, blocks; +#ifdef VERBOSE + unsigned long count = 0; + int i=0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + UpdZmode(); + + if (Zmode == 1) { + blocks = 1; + if (strstr(IsoFile, ".Z") == NULL) strcat(IsoFile, ".Z"); + } else { + blocks = 10; + if (strstr(IsoFile, ".bz") == NULL) strcat(IsoFile, ".bz"); + } + if (stat(IsoFile, &buf) == 0) { + printf("File %s Already exists\n", IsoFile); + return; + } + + strcpy(table, IsoFile); + if (Zmode == 1) strcat(table, ".table"); + else strcat(table, ".index"); + + t = fopen(table, "wb"); + if (t == NULL) { + return; + } + + if (CDR_open() == -1) { + return; + } + + if (CDR_getTD(ftrack, start) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + if (CDR_getTD(ltrack, end) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]) / blocks; + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) { /* loop until end */ + unsigned long size; + unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + float per; + + for (b=0; btm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + fclose(t); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Compressed Iso Image Created OK"); +} + +long CDRconfigure(void) { + int i; + + LoadConf(); + + ConfDlg = create_Config(); + + Edit = lookup_widget(ConfDlg, "GtkEntry_Iso"); + gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + CdEdit = lookup_widget(ConfDlg, "GtkEntry_CdDev"); + gtk_entry_set_text(GTK_ENTRY(CdEdit), CdDev); + + Progress = lookup_widget(ConfDlg, "GtkProgressBar_Progress"); + + BtnCompress = lookup_widget(ConfDlg, "GtkButton_Compress"); + BtnDecompress = lookup_widget(ConfDlg, "GtkButton_Decompress"); + BtnCreate = lookup_widget(ConfDlg, "GtkButton_Create"); + BtnCreateZ = lookup_widget(ConfDlg, "GtkButton_CreateZ"); + + methodlist = NULL; + for (i=0; i<2; i++) + methodlist = g_list_append(methodlist, methods[i]); + Method = lookup_widget(ConfDlg, "GtkCombo_Method"); + gtk_combo_set_popdown_strings(GTK_COMBO(Method), methodlist); + if (strstr(IsoFile, ".Z") != NULL) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[0]); + else gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[1]); + + gtk_widget_show_all(ConfDlg); + gtk_main(); + + return 0; +} + +GtkWidget *AboutDlg; + +void OnAboutOk(GtkMenuItem * menuitem, gpointer userdata) { + gtk_widget_hide(AboutDlg); + gtk_main_quit(); +} + +void CDRabout(void) { + GtkWidget *Label; + GtkWidget *Ok; + GtkWidget *Box, *BBox; + char AboutText[255]; + + sprintf(AboutText, "%s %d.%d\n", LibName, revision, build); + + AboutDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(AboutDlg, 260, 80); + gtk_window_set_title(GTK_WINDOW(AboutDlg), "CDVD About Dialog"); + gtk_window_set_position(GTK_WINDOW(AboutDlg), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(AboutDlg), 10); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(AboutDlg), Box); + gtk_widget_show(Box); + + Label = gtk_label_new(AboutText); + gtk_box_pack_start(GTK_BOX(Box), Label, FALSE, FALSE, 0); + gtk_widget_show(Label); + + BBox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), BBox, FALSE, FALSE, 0); + gtk_widget_show(BBox); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnAboutOk), NULL); + gtk_container_add(GTK_CONTAINER(BBox), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(AboutDlg); + gtk_main(); +} + +int main(int argc, char *argv[]) { + if (argc < 2) return 0; + + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "open")) { + _CDRopen(); + } else if (!strcmp(argv[1], "configure")) { + CDRconfigure(); + } else if (!strcmp(argv[1], "message")) { + if (argc > 2) SysMessageLoc(argv[2]); + } else { + CDRabout(); + } + + return 0; +} + + diff --git a/plugins/cdvd/CDVDiso/src/Linux/interface.c b/plugins/cdvd/CDVDiso/src/Linux/interface.c new file mode 100644 index 0000000000..bec825dd97 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/interface.c @@ -0,0 +1,253 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *hbox1; + GtkWidget *GtkEntry_Iso; + GtkWidget *button5; + GtkWidget *hbox2; + GtkWidget *GtkProgressBar_Progress; + GtkWidget *button6; + GtkWidget *hbox4; + GtkWidget *label2; + GtkWidget *GtkCombo_Method; + GtkWidget *combo_entry1; + GtkWidget *hbuttonbox2; + GtkWidget *GtkButton_Compress; + GtkWidget *GtkButton_Decompress; + GtkWidget *hbox3; + GtkWidget *label1; + GtkWidget *GtkEntry_CdDev; + GtkWidget *hbuttonbox3; + GtkWidget *GtkButton_Create; + GtkWidget *GtkButton_CreateZ; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "CDVD Config Dialog"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + hbox1 = gtk_hbox_new (FALSE, 10); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0); + + GtkEntry_Iso = gtk_entry_new (); + gtk_widget_ref (GtkEntry_Iso); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkEntry_Iso", GtkEntry_Iso, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkEntry_Iso); + gtk_box_pack_start (GTK_BOX (hbox1), GtkEntry_Iso, TRUE, TRUE, 0); + + button5 = gtk_button_new_with_label ("Select Iso"); + gtk_widget_ref (button5); + gtk_object_set_data_full (GTK_OBJECT (Config), "button5", button5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button5); + gtk_box_pack_start (GTK_BOX (hbox1), button5, FALSE, FALSE, 0); + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, FALSE, 0); + + GtkProgressBar_Progress = gtk_progress_bar_new (); + gtk_widget_ref (GtkProgressBar_Progress); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkProgressBar_Progress", GtkProgressBar_Progress, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkProgressBar_Progress); + gtk_box_pack_start (GTK_BOX (hbox2), GtkProgressBar_Progress, TRUE, FALSE, 0); + + button6 = gtk_button_new_with_label ("Stop"); + gtk_widget_ref (button6); + gtk_object_set_data_full (GTK_OBJECT (Config), "button6", button6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button6); + gtk_box_pack_end (GTK_BOX (hbox2), button6, FALSE, FALSE, 0); + gtk_widget_set_usize (button6, 61, -2); + + hbox4 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox4); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox4", hbox4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox4); + gtk_box_pack_start (GTK_BOX (vbox1), hbox4, TRUE, TRUE, 0); + + label2 = gtk_label_new ("Compression Method:"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (Config), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (hbox4), label2, FALSE, FALSE, 0); + + GtkCombo_Method = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Method); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Method", GtkCombo_Method, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Method); + gtk_box_pack_start (GTK_BOX (hbox4), GtkCombo_Method, TRUE, FALSE, 0); + + combo_entry1 = GTK_COMBO (GtkCombo_Method)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox2, TRUE, TRUE, 0); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox2), 0); + + GtkButton_Compress = gtk_button_new_with_label ("Compress Iso"); + gtk_widget_ref (GtkButton_Compress); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkButton_Compress", GtkButton_Compress, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkButton_Compress); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), GtkButton_Compress); + GTK_WIDGET_SET_FLAGS (GtkButton_Compress, GTK_CAN_DEFAULT); + + GtkButton_Decompress = gtk_button_new_with_label ("Decompress Iso"); + gtk_widget_ref (GtkButton_Decompress); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkButton_Decompress", GtkButton_Decompress, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkButton_Decompress); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), GtkButton_Decompress); + GTK_WIDGET_SET_FLAGS (GtkButton_Decompress, GTK_CAN_DEFAULT); + + hbox3 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox3); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox3", hbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox3); + gtk_box_pack_start (GTK_BOX (vbox1), hbox3, FALSE, FALSE, 0); + + label1 = gtk_label_new ("Cdrom Device: "); + gtk_widget_ref (label1); + gtk_object_set_data_full (GTK_OBJECT (Config), "label1", label1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label1); + gtk_box_pack_start (GTK_BOX (hbox3), label1, FALSE, FALSE, 0); + + GtkEntry_CdDev = gtk_entry_new (); + gtk_widget_ref (GtkEntry_CdDev); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkEntry_CdDev", GtkEntry_CdDev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkEntry_CdDev); + gtk_box_pack_start (GTK_BOX (hbox3), GtkEntry_CdDev, TRUE, TRUE, 0); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox3); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox3", hbuttonbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox3, TRUE, TRUE, 0); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox3), 0); + + GtkButton_Create = gtk_button_new_with_label ("Create Iso"); + gtk_widget_ref (GtkButton_Create); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkButton_Create", GtkButton_Create, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkButton_Create); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_Create); + GTK_WIDGET_SET_FLAGS (GtkButton_Create, GTK_CAN_DEFAULT); + + GtkButton_CreateZ = gtk_button_new_with_label ("Create Compressed Iso"); + gtk_widget_ref (GtkButton_CreateZ); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkButton_CreateZ", GtkButton_CreateZ, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkButton_CreateZ); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_CreateZ); + GTK_WIDGET_SET_FLAGS (GtkButton_CreateZ, GTK_CAN_DEFAULT); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox1), 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button5), "clicked", + GTK_SIGNAL_FUNC (OnFileSel), + NULL); + gtk_signal_connect (GTK_OBJECT (button6), "clicked", + GTK_SIGNAL_FUNC (OnStop), + NULL); + gtk_signal_connect (GTK_OBJECT (GtkButton_Compress), "clicked", + GTK_SIGNAL_FUNC (OnCompress), + NULL); + gtk_signal_connect (GTK_OBJECT (GtkButton_Decompress), "clicked", + GTK_SIGNAL_FUNC (OnDecompress), + NULL); + gtk_signal_connect (GTK_OBJECT (GtkButton_Create), "clicked", + GTK_SIGNAL_FUNC (OnCreate), + NULL); + gtk_signal_connect (GTK_OBJECT (GtkButton_CreateZ), "clicked", + GTK_SIGNAL_FUNC (OnCreateZ), + NULL); + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnOk), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnCancel), + NULL); + + return Config; +} + diff --git a/plugins/cdvd/CDVDiso/src/Linux/interface.h b/plugins/cdvd/CDVDiso/src/Linux/interface.h new file mode 100644 index 0000000000..3f7353bb70 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/interface.h @@ -0,0 +1,5 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); diff --git a/plugins/cdvd/CDVDiso/src/Linux/support.c b/plugins/cdvd/CDVDiso/src/Linux/support.c new file mode 100644 index 0000000000..a917d4f069 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/cdvd/CDVDiso/src/Linux/support.h b/plugins/cdvd/CDVDiso/src/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/cdvd/CDVDiso/src/PS2Edefs.h b/plugins/cdvd/CDVDiso/src/PS2Edefs.h new file mode 100644 index 0000000000..ef33df3686 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/PS2Edefs.h @@ -0,0 +1,812 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDiso/src/PS2Etypes.h b/plugins/cdvd/CDVDiso/src/PS2Etypes.h new file mode 100644 index 0000000000..3a63c58b85 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.sln b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.sln new file mode 100644 index 0000000000..b1a6c9e5e7 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "CDVDiso 2005 x64.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|x64.ActiveCfg = Release|x64 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.vcproj b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.vcproj new file mode 100644 index 0000000000..9a730e6e69 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso 2005 x64.vcproj @@ -0,0 +1,563 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.def b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.def new file mode 100644 index 0000000000..cb35900ec7 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.def @@ -0,0 +1,29 @@ +; CDVDiso.def : Declares the module parameters for the DLL. + +LIBRARY "CDVDiso" +DESCRIPTION 'CDVDiso Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDreadTrack @9 + CDVDgetBuffer @10 + CDVDreadSubQ @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDgetTOC @14 + CDVDgetDiskType @15 + CDVDgetTrayStatus @16 + CDVDctrlTrayOpen @17 + CDVDctrlTrayClose @18 + + CDVDconfigure @19 + CDVDtest @20 + CDVDabout @21 + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsp b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsp new file mode 100644 index 0000000000..3fcc620ecb --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="CDVDiso" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=CDVDiso - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "CDVDiso.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "CDVDiso.mak" CFG="CDVDiso - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CDVDiso - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "__MSCW32__" /D "_MBCS" /D "_USRDLL" /D "CDVDiso_EXPORTS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "./" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "__MSCW32__" /D "_MBCS" /D "_USRDLL" /D "CDVDiso_EXPORTS" /D "__WIN32__" /D "_LARGEFILE_SOURCE" /D _FILE_OFFSET_BITS=64 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x408 /d "NDEBUG" +# ADD RSC /l 0x408 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib libbz2.lib zlib.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" +# SUBTRACT LINK32 /nodefaultlib +# Begin Target + +# Name "CDVDiso - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\CDVDiso.c +# End Source File +# Begin Source File + +SOURCE=.\CDVDiso.def +# End Source File +# Begin Source File + +SOURCE=.\Config.c +# End Source File +# Begin Source File + +SOURCE=..\libiso.c +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\CDVDiso.h +# End Source File +# Begin Source File + +SOURCE=.\Config.h +# End Source File +# Begin Source File + +SOURCE=..\libiso.h +# End Source File +# Begin Source File + +SOURCE=..\PS2Edefs.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\CDVDiso.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsw b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsw new file mode 100644 index 0000000000..df2f33843c --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.dsw @@ -0,0 +1,30 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CDVDiso"=".\CDVDiso.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.rc b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.rc new file mode 100644 index 0000000000..f43e8764fa --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.rc @@ -0,0 +1,134 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 161 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,105,140,50,14 + EDITTEXT IDC_ISOFILE,10,10,145,14,ES_AUTOHSCROLL + PUSHBUTTON "Cancel",IDCANCEL,160,140,50,14 + PUSHBUTTON "Select Iso",IDC_SELECTISO,160,10,45,14 + PUSHBUTTON "Compress Iso",IDC_COMPRESSISO,33,75,65,14 + PUSHBUTTON "Decompress Iso",IDC_DECOMPRESSISO,113,75,65,14 + COMBOBOX IDC_METHOD,120,55,85,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER | + 0x1,10,35,145,14 + LTEXT "Compression Method:",IDC_STATIC,29,57,69,8 + PUSHBUTTON "Stop",IDC_STOP,160,35,45,14 + GROUPBOX "",IDC_STATIC,5,0,205,95 + GROUPBOX "Options",IDC_STATIC,5,100,205,30 + CONTROL "Enable Block Dump => ""ISO name.dump""",IDC_BLOCKDUMP, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,115,148,10 +END + +IDD_ABOUT DIALOG 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "CDVDabout" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "CDVDiso Driver",IDC_NAME,70,10,50,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Thanks to:\n mooby - coding hints and .bz support\n Brenden Conte - linux conf bugfix", + IDC_STATIC,10,45,160,25 + LTEXT "Author: linuzappz ",IDC_STATIC, + 20,20,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 154 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.sln b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.sln new file mode 100644 index 0000000000..0e80670450 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "CDVDiso.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.vcproj b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.vcproj new file mode 100644 index 0000000000..9c3b584ee6 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso.vcproj @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.sln b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.sln new file mode 100644 index 0000000000..6f640e6963 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "CDVDiso_2003.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.vcproj b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.vcproj new file mode 100644 index 0000000000..3699f46e6b --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2003.vcproj @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.sln b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.sln new file mode 100644 index 0000000000..b8f64bbc80 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso", "CDVDiso_2005.vcproj", "{BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Debug|Win32.Build.0 = Debug|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.ActiveCfg = Release|Win32 + {BB27CC2C-28D1-4438-A0DF-3E120D01EDEC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.vcproj b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.vcproj new file mode 100644 index 0000000000..c58ca58f04 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2005.vcproj @@ -0,0 +1,538 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2008.vcproj b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2008.vcproj new file mode 100644 index 0000000000..0ebc5f77a4 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/CDVDiso_2008.vcproj @@ -0,0 +1,537 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDiso/src/Win32/Config.c b/plugins/cdvd/CDVDiso/src/Win32/Config.c new file mode 100644 index 0000000000..ecf4d4cf25 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/Config.c @@ -0,0 +1,45 @@ +#include +#include + +#include "CDVDiso.h" + +#define GetKeyV(name, var, s, t) \ + size = s; type = t; \ + RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); + +#define GetKeyVdw(name, var) \ + GetKeyV(name, var, 4, REG_DWORD); + +#define SetKeyV(name, var, s, t) \ + RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); + +#define SetKeyVdw(name, var) \ + SetKeyV(name, var, 4, REG_DWORD); + +void SaveConf() { + HKEY myKey; + DWORD myDisp; + + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); + + SetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + SetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} + +void LoadConf() { + HKEY myKey; + DWORD type, size; + + memset(IsoFile, 0, sizeof(IsoFile)); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, KEY_ALL_ACCESS, &myKey)!=ERROR_SUCCESS) { + SaveConf(); return; + } + + GetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + GetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} diff --git a/plugins/cdvd/CDVDiso/src/Win32/Config.h b/plugins/cdvd/CDVDiso/src/Win32/Config.h new file mode 100644 index 0000000000..0ce9be191d --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/Config.h @@ -0,0 +1,3 @@ +void SaveConf(); +void LoadConf(); + diff --git a/plugins/cdvd/CDVDiso/src/Win32/Makefile b/plugins/cdvd/CDVDiso/src/Win32/Makefile new file mode 100644 index 0000000000..483698ad3a --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/Makefile @@ -0,0 +1,57 @@ +# +# Makefile for MINGW32 +# + + +all: cdvdiso + +PLUGIN = CDVDiso.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 #-lintl +RESOBJ = cdvdiso.o + +OBJS = ../CDVDiso.o ../libiso.o +OBJS+= Config.o Win32.o ${RESOBJ} +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o +OBJS+= ../bzip2/blocksort.o ../bzip2/bzlib.o \ + ../bzip2/compress.o ../bzip2/crctable.o \ + ../bzip2/decompress.o ../bzip2/huffman.o \ + ../bzip2/randtable.o + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include -I../zlib -I../bzip2 ${FLAGS} + +cdvdiso: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean cdvdiso + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: CDVDiso.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + + \ No newline at end of file diff --git a/plugins/cdvd/CDVDiso/src/Win32/Win32.c b/plugins/cdvd/CDVDiso/src/Win32/Win32.c new file mode 100644 index 0000000000..7c9c88c373 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/Win32.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "Config.h" +#include "CDVDiso.h" +#include "resource.h" + +HINSTANCE hInst; +#define MAXFILENAME 256 + +u8 Zbuf[2352 * 10 * 2]; +HWND hDlg; +HWND hProgress; +HWND hIsoFile; +HWND hMethod; +HWND hBlockDump; +int stop; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "CDVDiso Msg", 0); +} + +int _GetFile(char *out) { + OPENFILENAME ofn; + char szFileName[MAXFILENAME]; + char szFileTitle[MAXFILENAME]; + + memset(&szFileName, 0, sizeof(szFileName)); + memset(&szFileTitle, 0, sizeof(szFileTitle)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = GetActiveWindow(); + ofn.lpstrFilter = "Supported Formats\0*.bin;*.iso;*.img;*.nrg;*.mdf;*.Z;*.Z2;*.BZ2;*.dump\0Cd Iso Format (*.bin;*.iso;*.img;*.nrg;*.mdf)\0*.bin;*.iso;*.img;*.nrg;*.mdf\0Compressed Z Iso Format (*.Z;*.Z2)\0*.Z;*.Z2\0Compressed BZ Iso Format (*.BZ2)\0*.BZ2\0Block Dumps (*.dump)\0*.dump\0All Files\0*.*\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAXFILENAME; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = MAXFILENAME; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = NULL; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { + strcpy(out, szFileName); + return 1; + } + + return 0; +} + +void CfgOpenFile() { + if (_GetFile(IsoFile) == 1) + SaveConf(); +} + +void UpdZmode() { + if (ComboBox_GetCurSel(hMethod) == 0) { + Zmode = 1; + } else { + Zmode = 2; + } +} + + +void SysUpdate() { + MSG msg; + + while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void OnCompress() { + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + int ret; + isoFile *src; + isoFile *dst; + + Edit_GetText(hIsoFile, IsoFile, 256); + UpdZmode(); + + if (Zmode == 1) { + sprintf(Zfile, "%s.Z2", IsoFile); + } else { + sprintf(Zfile, "%s.BZ2", IsoFile); + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + if (Zmode == 1) { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } else { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) Edit_SetText(hIsoFile, Zfile); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) { + if (ret == -1) { + SysMessage("Error compressing iso image"); + } else { + SysMessage("Iso image compressed OK"); + } + } +} + +void OnDecompress() { + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret; + + Edit_GetText(hIsoFile, IsoFile, 256); + + src = isoOpen(IsoFile); + if (src == NULL) return; + + strcpy(file, IsoFile); + if (src->flags & ISOFLAGS_Z) { + file[strlen(file) - 2] = 0; + } else + if (src->flags & ISOFLAGS_Z2) { + file[strlen(file) - 3] = 0; + } else + if (src->flags & ISOFLAGS_BZ2) { + file[strlen(file) - 3] = 0; + } else { + SysMessage("%s is not a compressed image", IsoFile); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + if (!stop) Edit_SetText(hIsoFile, file); + + isoClose(src); + isoClose(dst); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) { + if (ret == -1) { + SysMessage("Error decompressing iso image"); + } else { + SysMessage("Iso image decompressed OK"); + } + } +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + int i; + + switch(uMsg) { + case WM_INITDIALOG: + hDlg = hW; + LoadConf(); + + hProgress = GetDlgItem(hW, IDC_PROGRESS); + hIsoFile = GetDlgItem(hW, IDC_ISOFILE); + hMethod = GetDlgItem(hW, IDC_METHOD); + hBlockDump = GetDlgItem(hW, IDC_BLOCKDUMP); + + for (i=0; methods[i] != NULL; i++) { + ComboBox_AddString(hMethod, methods[i]); + } + + Edit_SetText(hIsoFile, IsoFile); + ComboBox_SetCurSel(hMethod, 0); +/* if (strstr(IsoFile, ".Z") != NULL) + ComboBox_SetCurSel(hMethod, 1); + else ComboBox_SetCurSel(hMethod, 0);*/ + Button_SetCheck(hBlockDump, BlockDump); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_SELECTISO: + if (_GetFile(IsoFile) == 1) + Edit_SetText(hIsoFile, IsoFile); + return TRUE; + + case IDC_COMPRESSISO: + OnCompress(); + return TRUE; + + case IDC_DECOMPRESSISO: + OnDecompress(); + return TRUE; + + case IDC_STOP: + stop = 1; + return TRUE; + + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + Edit_GetText(hIsoFile, IsoFile, 256); + BlockDump = Button_GetCheck(hBlockDump); + + SaveConf(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK CDVDconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK CDVDabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/cdvd/CDVDiso/src/Win32/afxresmw.h b/plugins/cdvd/CDVDiso/src/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/cdvd/CDVDiso/src/Win32/plugin.def b/plugins/cdvd/CDVDiso/src/Win32/plugin.def new file mode 100644 index 0000000000..4d19ae2002 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/plugin.def @@ -0,0 +1,21 @@ +EXPORTS + PS2EgetLibType = PS2EgetLibType@0 @2 + PS2EgetLibName = PS2EgetLibName@0 @3 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @4 + CDVDinit = CDVDinit@0 @5 + CDVDshutdown = CDVDshutdown@0 @6 + CDVDopen = CDVDopen@0 @7 + CDVDclose = CDVDclose@0 @8 + CDVDreadTrack = CDVDreadTrack@8 @9 + CDVDgetBuffer = CDVDgetBuffer@0 @10 + CDVDreadSubQ = CDVDreadSubQ@8 @11 + CDVDgetTN = CDVDgetTN@4 @12 + CDVDgetTD = CDVDgetTD@8 @13 + CDVDgetTOC = CDVDgetTOC@4 @14 + CDVDgetDiskType = CDVDgetDiskType@0 @15 + CDVDgetTrayStatus = CDVDgetTrayStatus@0 @16 + CDVDctrlTrayOpen = CDVDctrlTrayOpen@0 @17 + CDVDctrlTrayClose = CDVDctrlTrayClose@0 @18 + CDVDconfigure = CDVDconfigure@0 @19 + CDVDtest = CDVDtest@0 @20 + CDVDabout = CDVDabout@0 @21 diff --git a/plugins/cdvd/CDVDiso/src/Win32/resource.h b/plugins/cdvd/CDVDiso/src/Win32/resource.h new file mode 100644 index 0000000000..fe2358810f --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/Win32/resource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CDVDiso.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_ISOFILE 1000 +#define IDC_SELECTISO 1001 +#define IDC_COMPRESSISO 1002 +#define IDC_DECOMPRESSISO 1003 +#define IDC_METHOD 1004 +#define IDC_PROGRESS 1005 +#define IDC_STOP 1006 +#define IDC_BLOCKDUMP 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + diff --git a/plugins/cdvd/CDVDiso/src/bzip2/LICENSE b/plugins/cdvd/CDVDiso/src/bzip2/LICENSE new file mode 100644 index 0000000000..4458e35bb5 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/LICENSE @@ -0,0 +1,43 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2006 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + +Julian Seward, Cambridge, UK. +jseward@bzip.org +bzip2/libbzip2 version 1.0.4 of 20 December 2006 + +-------------------------------------------------------------------------- diff --git a/plugins/cdvd/CDVDiso/src/bzip2/README b/plugins/cdvd/CDVDiso/src/bzip2/README new file mode 100644 index 0000000000..b18c096b9e --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/README @@ -0,0 +1,205 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (http://www.bzip.org). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.0 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.2 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.3 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.4 ? + + See the CHANGES file. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) diff --git a/plugins/cdvd/CDVDiso/src/bzip2/blocksort.c b/plugins/cdvd/CDVDiso/src/bzip2/blocksort.c new file mode 100644 index 0000000000..8535c93c8d --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/bzlib.c b/plugins/cdvd/CDVDiso/src/bzip2/bzlib.c new file mode 100644 index 0000000000..79c34a5400 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/bzlib.c @@ -0,0 +1,1571 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/bzlib.h b/plugins/cdvd/CDVDiso/src/bzip2/bzlib.h new file mode 100644 index 0000000000..fdb0dbe7b0 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/bzlib.h @@ -0,0 +1,282 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/bzlib_private.h b/plugins/cdvd/CDVDiso/src/bzip2/bzlib_private.h new file mode 100644 index 0000000000..d0a05546ef --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/bzlib_private.h @@ -0,0 +1,503 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.4, 20-Dec-2006" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/compress.c b/plugins/cdvd/CDVDiso/src/bzip2/compress.c new file mode 100644 index 0000000000..d98d5c0bd8 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/crctable.c b/plugins/cdvd/CDVDiso/src/bzip2/crctable.c new file mode 100644 index 0000000000..bc7e2ae39d --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/decompress.c b/plugins/cdvd/CDVDiso/src/bzip2/decompress.c new file mode 100644 index 0000000000..124cc8ddc7 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/decompress.c @@ -0,0 +1,626 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/huffman.c b/plugins/cdvd/CDVDiso/src/bzip2/huffman.c new file mode 100644 index 0000000000..be4dc024dc --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/bzip2/randtable.c b/plugins/cdvd/CDVDiso/src/bzip2/randtable.c new file mode 100644 index 0000000000..d186335e0e --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/bzip2/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDiso/src/libiso.c b/plugins/cdvd/CDVDiso/src/libiso.c new file mode 100644 index 0000000000..f30d825320 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/libiso.c @@ -0,0 +1,933 @@ +#define __USE_LARGEFILE64 +#define __USE_FILE_OFFSET64 +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __WIN32__ +#include +#endif + +#include "PS2Etypes.h" +#include "CDVDiso.h" +#include "libiso.h" + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(__WIN32__) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + + +#ifdef __WIN32__ +void *_openfile(const char *filename, int flags) { + HANDLE handle; + +// printf("_openfile %s, %d\n", filename, flags & O_RDONLY); + if (flags & O_WRONLY) { + int _flags = CREATE_NEW; + if (flags & O_CREAT) _flags = CREATE_ALWAYS; + handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, _flags, 0, NULL); + } else { + handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + } + + return handle == INVALID_HANDLE_VALUE ? NULL : handle; +} + +u64 _tellfile(void *handle) { + u64 ofs; + DWORD *_ofs = (DWORD*)&ofs; + _ofs[1] = 0; + _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); + return ofs; +} + +int _seekfile(void *handle, u64 offset, int whence) { + u64 ofs = (u64)offset; + DWORD *_ofs = (DWORD*)&ofs; +// printf("_seekfile %p, %d_%d\n", handle, _ofs[1], _ofs[0]); + if (whence == SEEK_SET) { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); + } else { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_END); + } + return 0; +} + +int _readfile(void *handle, void *dst, int size) { + DWORD ret; + +// printf("_readfile %p %d\n", handle, size); + ReadFile(handle, dst, size, &ret, NULL); +// printf("_readfile ret %d; %d\n", ret, GetLastError()); + return ret; +} + +int _writefile(void *handle, void *src, int size) { + DWORD ret; + +// printf("_writefile %p, %d\n", handle, size); +// _seekfile(handle, _tellfile(handle)); + WriteFile(handle, src, size, &ret, NULL); +// printf("_writefile ret %d\n", ret); + return ret; +} + +void _closefile(void *handle) { + CloseHandle(handle); +} + +#else + +void *_openfile(const char *filename, int flags) { + printf("_openfile %s %x\n", filename, flags); + +#ifdef __WIN32__ + if (flags & O_WRONLY) + return fopen64(filename, "wb"); + else return fopen64(filename, "rb"); +#else + if (flags & O_WRONLY) + return fopen64(filename, "wb"); + else return fopen64(filename, "rb"); +#endif +} + +#include + +u64 _tellfile(void *handle) { + u64 cursize = ftell(handle); + if(cursize == -1 ) { + // try 64bit + cursize = ftello64(handle); + if( cursize < -1 ) { + // zero top 32 bits + cursize &= 0xffffffff; + } + } + return cursize; +} + +int _seekfile(void *handle, u64 offset, int whence) { + int seekerr = fseeko64(handle, offset, whence); + if( seekerr == -1 ) + printf("failed to seek\n"); + return seekerr; +} + +int _readfile(void *handle, void *dst, int size) { + return fread(dst, 1, size, handle); +} + +int _writefile(void *handle, void *src, int size) { + return fwrite(src, 1, size, handle); +} + +void _closefile(void *handle) { + fclose(handle); +} + +#endif + +int detect(isoFile *iso) { + char buf[2448]; + struct cdVolDesc *volDesc; + + if (isoReadBlock(iso, buf, 16) == -1) return -1; + volDesc = (struct cdVolDesc *)(buf + 24); + if (strncmp(volDesc->volID, "CD001", 5)) return 0; + + if (volDesc->rootToc.tocSize == 2048) { + iso->type = ISOTYPE_CD; + } else { + iso->type = ISOTYPE_DVD; + } + + return 1; +} + +int _isoReadZtable(isoFile *iso) { + void *handle; + char table[256]; + int size; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + iso->Ztable = (char*)malloc(size); + if (iso->Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, iso->Ztable, size); + _closefile(handle); + + iso->blocks = size / 6; + + return 0; +} + +int _isoReadZ2table(isoFile *iso) { + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks*8); + if (iso->Ztable == NULL) { + return -1; + } + + ofs=16; + for (i=0; iblocks; i++) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + free(Ztable); + + return 0; +} + +int _isoReadBZ2table(isoFile *iso) { + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks*8); + if (iso->Ztable == NULL) { + return -1; + } + + ofs=16; + for (i=0; iblocks/16; i++) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + if (iso->blocks & 0xf) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + free(Ztable); + + return 0; +} + +int _isoReadDtable(isoFile *iso) { + int ret; + int i; + + _seekfile(iso->handle, 0, SEEK_END); + iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize+4); + iso->dtable = (u32*)malloc(iso->dtablesize*4); + + for (i=0; idtablesize; i++) { + _seekfile(iso->handle, 16+(iso->blocksize+4)*i, SEEK_SET); + ret = _readfile(iso->handle, &iso->dtable[i], 4); + if (ret < 4) { + return -1; + } + } + + return 0; +} + +int isoDetect(isoFile *iso) { // based on florin's CDVDbin detection code :) + char buf[32]; + int len; + + iso->type = ISOTYPE_ILLEGAL; + + len = strlen(iso->filename); + if (len >= 2) { + if (!strncmp(iso->filename+(len-2), ".Z", 2)) { + iso->flags = ISOFLAGS_Z; + iso->blocksize = 2352; + _isoReadZtable(iso); + return detect(iso) == 1 ? 0 : -1; + } + } + + _seekfile(iso->handle, 0, SEEK_SET); + _readfile(iso->handle, buf, 4); + if (strncmp(buf, "BDV2", 4) == 0) { + iso->flags = ISOFLAGS_BLOCKDUMP; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadDtable(iso); + return detect(iso) == 1 ? 0 : -1; + } else + if (strncmp(buf, "Z V2", 4) == 0) { + iso->flags = ISOFLAGS_Z2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } else + if (strncmp(buf, "BZV2", 4) == 0) { + iso->flags = ISOFLAGS_BZ2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + iso->buflsn = -1; + iso->buffer = malloc(iso->blocksize*16); + if (iso->buffer == NULL) return -1; + _isoReadBZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } else { + iso->blocks = 16; + } + + // ISO 2048 + iso->blocksize = 2048; iso->offset = 0; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2336 + iso->blocksize = 2336; iso->offset = 0; iso->blockofs = 16; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO ISO 2048 + iso->blocksize = 2048; iso->offset = 150*2048; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // NERO RAW 2352 + iso->blocksize = 2352; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO RAWQ 2448 + iso->blocksize = 2448; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // ISO 2048 + iso->blocksize = 2048; iso->offset = -8; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + iso->offset = 0; + iso->blocksize = 2352; + iso->type = ISOTYPE_AUDIO; + return 0; + + return -1; +} + +isoFile *isoOpen(const char *filename) { + isoFile *iso; + int i; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + + iso->handle = _openfile(iso->filename, O_RDONLY); + if (iso->handle == NULL) { + printf("Errorr loading %s\n", iso->filename); + return NULL; + } + + if (isoDetect(iso) == -1) return NULL; + + printf("detected blocksize = %d\n", iso->blocksize); + + if (strlen(iso->filename) > 3 && + strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0) { + _closefile(iso->handle); + iso->flags|= ISOFLAGS_MULTI; + iso->blocks = 0; + for (i=0; i<8; i++) { + iso->filename[strlen(iso->filename) - 1] = '0' + i; + iso->multih[i].handle = _openfile(iso->filename, O_RDONLY); + if (iso->multih[i].handle == NULL) { + break; + } + iso->multih[i].slsn = iso->blocks; + _seekfile(iso->multih[i].handle, 0, SEEK_END); + iso->blocks+= (u32)((_tellfile(iso->multih[i].handle) - iso->offset) / + (iso->blocksize)); + iso->multih[i].elsn = iso->blocks-1; + } + + if (i == 0) { + return NULL; + } + } + + if (iso->flags == 0) { + _seekfile(iso->handle, 0, SEEK_END); + iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / + (iso->blocksize)); + } + + + printf("isoOpen: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + printf("type = %d\n", iso->type); + + return iso; +} + +isoFile *isoCreate(const char *filename, int flags) { + isoFile *iso; + char Zfile[256]; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + iso->flags = flags; + iso->offset = 0; + iso->blockofs = 24; + iso->blocksize = CD_FRAMESIZE_RAW; + iso->blocksize = 2048; + + if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2)) { + sprintf(Zfile, "%s.table", iso->filename); + iso->htable = _openfile(Zfile, O_WRONLY); + if (iso->htable == NULL) { + return NULL; + } + } + + iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT); + if (iso->handle == NULL) { + printf("Error loading %s\n", iso->filename); + return NULL; + } + printf("isoCreate: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + + return iso; +} + +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) { + iso->blocksize = blocksize; + iso->blocks = blocks; + iso->blockofs = blockofs; + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + if (iso->flags & ISOFLAGS_Z2) { + if (_writefile(iso->handle, "Z V2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + if (iso->flags & ISOFLAGS_BZ2) { + if (_writefile(iso->handle, "BZV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + iso->buflsn = -1; + iso->buffer = malloc(iso->blocksize*16); + if (iso->buffer == NULL) return -1; + } + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + + return 0; +} + +s32 MSFtoLSN(u8 *Time) { + u32 lsn; + + lsn = Time[2]; + lsn+=(Time[1] - 2) * 75; + lsn+= Time[0] * 75 * 60; + return lsn; +} + +void LSNtoMSF(u8 *Time, s32 lsn) { + u8 m, s, f; + + lsn += 150; + m = lsn / 4500; // minuten + lsn = lsn - m * 4500; // minuten rest + s = lsn / 75; // sekunden + f = lsn - (s * 75); // sekunden rest + Time[0] = itob(m); Time[1] = itob(s); Time[2] = itob(f); +} + +int _isoReadBlock(isoFile *iso, char *dst, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int _isoReadBlockZ(isoFile *iso, char *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW*2]; + int ret; + +// printf("_isoReadBlockZ %d, %d\n", lsn, iso->blocksize); + pos = *(unsigned long*)&iso->Ztable[lsn * 6]; + p = *(unsigned short*)&iso->Ztable[lsn * 6 + 4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = CD_FRAMESIZE_RAW; + uncompress(dst, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockZ2(isoFile *iso, char *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[16*1024]; + int ret; + +// printf("_isoReadBlockZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*)&iso->Ztable[lsn*8]; + p = *(u32*)&iso->Ztable[lsn*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize; + uncompress(dst + iso->blockofs, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockBZ2(isoFile *iso, char *dst, int lsn) { + u32 pos, p; + u32 size; + u8 Zbuf[64*1024]; + int ret; + + if ((lsn/16) == iso->buflsn) { + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer+(iso->blocksize*(lsn&0xf)), iso->blocksize); + return 0; + } + + iso->buflsn = lsn/16; +// printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*)&iso->Ztable[(lsn/16)*8]; + p = *(u32*)&iso->Ztable[(lsn/16)*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize*64; + ret = BZ2_bzBuffToBuffDecompress(iso->buffer, &size, Zbuf, p, 0, 0); + if (ret != BZ_OK) { + printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + printf("%d, %d\n", pos, p); + printf("error on BZ2: %d\n", ret); + } + + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer+(iso->blocksize*(lsn&0xf)), iso->blocksize); + + return 0; +} + +int _isoReadBlockD(isoFile *iso, char *dst, int lsn) { + int ret; + int i; + +// printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + for (i=0; idtablesize;i++) { + if (iso->dtable[i] != lsn) continue; + + _seekfile(iso->handle, 16+i*(iso->blocksize+4)+4, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) return -1; + + return 0; + } + printf("block %d not found in dump\n", lsn); + + return -1; +} + +int _isoReadBlockM(isoFile *iso, char *dst, int lsn) { + u64 ofs; + int ret; + int i; + + for (i=0; i<8; i++) { + if (lsn >= iso->multih[i].slsn && + lsn <= iso->multih[i].elsn) { + break; + } + } + if (i==8) return -1; + + ofs = (u64)(lsn-iso->multih[i].slsn) * iso->blocksize + iso->offset; +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->multih[i].handle, ofs, SEEK_SET); + ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int isoReadBlock(isoFile *iso, char *dst, int lsn) { + int ret; + + if (lsn > iso->blocks) { + printf("isoReadBlock: %d > %d\n", lsn, iso->blocks); + return -1; + } + if (iso->flags & ISOFLAGS_Z) { + ret = _isoReadBlockZ(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoReadBlockZ2(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoReadBlockD(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_MULTI) { + ret = _isoReadBlockM(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_BZ2) { + ret = _isoReadBlockBZ2(iso, dst, lsn); + } else + ret = _isoReadBlock(iso, dst, lsn); + if (ret == -1) return ret; + + if (iso->type == ISOTYPE_CD) { + LSNtoMSF(dst+12, lsn); + dst[15] = 2; + } + + return 0; +} + + +int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockZ(isoFile *iso, u8 *src, int lsn) { + u32 pos; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 2352; + compress(Zbuf, &size, src, 2352); +// printf("_isoWriteBlockZ %d\n", size); + + pos = (u32)_tellfile(iso->handle); + ret = _writefile(iso->htable, (u8*)&pos, 4); + if (ret < 4) return -1; + ret = _writefile(iso->htable, (u8*)&size, 2); + if (ret < 2) return -1; + + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockZ2(isoFile *iso, u8 *src, int lsn) { + uLongf size; + u8 Zbuf[1024*16]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 1024*16; + compress(Zbuf, &size, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlockZ %d\n", size); + + ret = _writefile(iso->htable, (u8*)&size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) { + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + ret = _writefile(iso->handle, &lsn, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockBZ2(isoFile *iso, u8 *src, int lsn) { + u32 size; + u8 Zbuf[64*1024]; + int blocks; + int ret; + + memcpy(iso->buffer+(iso->blocksize*(lsn&0xf)), src + iso->blockofs, iso->blocksize); + + if (lsn == (iso->blocks-1)) { + blocks = (lsn & 0xf)+1; + } else { + blocks = 16; + if ((lsn & 0xf) != 0xf) return 0; + } + +// printf("_isoWriteBlockBZ2 %d\n", iso->blocksize); + size = 64*1024; + ret = BZ2_bzBuffToBuffCompress(Zbuf, (u32*)&size, iso->buffer, iso->blocksize*blocks, 9, 0, 30); + if (ret != BZ_OK) { + printf("error on BZ2: %d\n", ret); + } +// printf("_isoWriteBlockBZ2 %d\n", size); + + ret = _writefile(iso->htable, (u8*)&size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int isoWriteBlock(isoFile *iso, char *src, int lsn) { + int ret; + + if (iso->flags & ISOFLAGS_Z) { + ret = _isoWriteBlockZ(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoWriteBlockZ2(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoWriteBlockD(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_BZ2) { + ret = _isoWriteBlockBZ2(iso, src, lsn); + } else + ret = _isoWriteBlock(iso, src, lsn); + if (ret == -1) return ret; + + return 0; +} + +void isoClose(isoFile *iso) { + if (iso->handle) { + _closefile(iso->handle); + } + if (iso->htable) { + _closefile(iso->htable); + } + if (iso->buffer) { + free(iso->buffer); + } + free(iso); +} + diff --git a/plugins/cdvd/CDVDiso/src/libiso.h b/plugins/cdvd/CDVDiso/src/libiso.h new file mode 100644 index 0000000000..458d5607c3 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/libiso.h @@ -0,0 +1,65 @@ +#ifndef __LIBISO_H__ +#define __LIBISO_H__ + +#ifdef __MSCW32__ +#pragma warning(disable:4018) +#endif + +#define ISOTYPE_ILLEGAL 0 +#define ISOTYPE_CD 1 +#define ISOTYPE_DVD 2 +#define ISOTYPE_AUDIO 3 + +#define ISOFLAGS_Z 0x0001 +#define ISOFLAGS_Z2 0x0002 +#define ISOFLAGS_BLOCKDUMP 0x0004 +#define ISOFLAGS_MULTI 0x0008 +#define ISOFLAGS_BZ2 0x0010 + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +typedef struct { + u32 slsn; + u32 elsn; + void *handle; +} _multih; + +typedef struct { + char filename[256]; + u32 type; + u32 flags; + u32 offset; + u32 blockofs; + u32 blocksize; + u32 blocks; + void *handle; + void *htable; + char *Ztable; + u32 *dtable; + int dtablesize; + _multih multih[8]; + int buflsn; + char *buffer; +} isoFile; + + +isoFile *isoOpen(const char *filename); +isoFile *isoCreate(const char *filename, int mode); +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +int isoDetect(isoFile *iso); +int isoReadBlock(isoFile *iso, char *dst, int lsn); +int isoWriteBlock(isoFile *iso, char *src, int lsn); +void isoClose(isoFile *iso); + +void *_openfile(const char *filename, int flags); +u64 _tellfile(void *handle); +int _seekfile(void *handle, u64 offset, int whence); +int _readfile(void *handle, void *dst, int size); +int _writefile(void *handle, void *src, int size); +void _closefile(void *handle); + +#endif /* __LIBISO_H__ */ diff --git a/plugins/cdvd/CDVDiso/src/mkiso/Makefile b/plugins/cdvd/CDVDiso/src/mkiso/Makefile new file mode 100644 index 0000000000..052c8b55a3 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/mkiso/Makefile @@ -0,0 +1,26 @@ + +CC = gcc + +MKISO = mkiso +CFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -I.. -I. -D__LINUX__ -I../zlib +OBJS = mkiso.o ../libiso.o +LIBS = +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o + +DEPS:= $(OBJS:.o=.d) + +all: mkiso + +mkiso: ${OBJS} + rm -f ${MKISO} + ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} + strip ${MKISO} + +clean: + rm -f ${OBJS} ${DEPS} ${MKISO} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/cdvd/CDVDiso/src/mkiso/Makefile.mingw b/plugins/cdvd/CDVDiso/src/mkiso/Makefile.mingw new file mode 100644 index 0000000000..c85439923e --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/mkiso/Makefile.mingw @@ -0,0 +1,31 @@ + +CC = gcc + +MKISO = mkiso.exe +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +CFLAGS = -Wall ${OPTIMIZE} -I.. -I. -D__WIN32__ -I../zlib -I../bzip2 +OBJS = mkiso.o ../libiso.o +LIBS = +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o +OBJS+= ../bzip2/blocksort.o ../bzip2/huffman.o \ + ../bzip2/crctable.o ../bzip2/randtable.o \ + ../bzip2/compress.o ../bzip2/decompress.o \ + ../bzip2/bzlib.o + +DEPS:= $(OBJS:.o=.d) + +all: mkiso + +mkiso: ${OBJS} + rm -f ${MKISO} + ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} + strip ${MKISO} + +clean: + rm -f ${OBJS} ${DEPS} ${MKISO} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/cdvd/CDVDiso/src/mkiso/mkiso.c b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.c new file mode 100644 index 0000000000..70e6da7fa7 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.c @@ -0,0 +1,153 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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 +#include +#include +#include + +#include "CDVDiso.h" + + +void Compress(char *filename, int mode) { + struct stat buf; + u32 lsn; + u8 cdbuff[1024*16]; + char Zfile[256]; + int ret=0; + isoFile *src; + isoFile *dst; + + if (mode == 1) { + sprintf(Zfile, "%s.Z2", filename); + } else { + sprintf(Zfile, "%s.BZ2", filename); + } + + if (stat(Zfile, &buf) != -1) { + printf("'%s' already exists\n", Zfile); + return; +/* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + printf("src %s; dst %s\n", filename, Zfile); + src = isoOpen(filename); + if (src == NULL) return; + + if (mode == 1) { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } else { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + if (dst == NULL) return; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + isoClose(src); + isoClose(dst); + + if (ret == -1) { + printf("Error compressing iso image\n"); + } else { + printf("Iso image compressed OK\n"); + } +} + +void Decompress(char *filename) { + struct stat buf; + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret=0; + + src = isoOpen(filename); + if (src == NULL) return; + + strcpy(file, filename); + if (src->flags & ISOFLAGS_Z) { + file[strlen(file) - 2] = 0; + } else + if (src->flags & ISOFLAGS_Z2) { + file[strlen(file) - 3] = 0; + } else + if (src->flags & ISOFLAGS_BZ2) { + file[strlen(file) - 3] = 0; + } else { + printf("%s is not a compressed image\n", filename); + return; + } + if (stat(file, &buf) != -1) { + char str[256]; + sprintf(str, "'%s' already exists", file); + isoClose(src); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + + isoClose(src); + isoClose(dst); + + if (ret == -1) { + printf("Error decompressing iso image\n"); + } else { + printf("Iso image decompressed OK\n"); + } +} + + +int main(int argc, char *argv[]) { + if (argc < 3) return 0; + + if (argv[1][0] == 'c') { + Compress(argv[2], 1); + } else + if (argv[1][0] == 'C') { + Compress(argv[2], 2); + } else + if (argv[1][0] == 'd') { + Decompress(argv[2]); + } + + return 0; +} diff --git a/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsp b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsp new file mode 100644 index 0000000000..85e41361e0 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="mkiso" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mkiso - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mkiso.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mkiso.mak" CFG="mkiso - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mkiso - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mkiso - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mkiso - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D "__MSCW32__" /YX /FD /c +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mkiso - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "./" /I "../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x2c0a /d "_DEBUG" +# ADD RSC /l 0x2c0a /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib zlib.lib libbz2.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mkiso - Win32 Release" +# Name "mkiso - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\libiso.c +# End Source File +# Begin Source File + +SOURCE=.\mkiso.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "zlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\zlib\adler32.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\compress.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\crc32.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\crc32.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\deflate.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\deflate.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\gvmat32c.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\gzio.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\infback.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffas8664.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffast.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffast.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffixed.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inflate.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inflate.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inftrees.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inftrees.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\trees.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\trees.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\uncompr.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\zconf.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\zlib.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\zutil.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\zutil.h +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsw b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsw new file mode 100644 index 0000000000..81430b0e7e --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/mkiso/mkiso.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mkiso"=.\mkiso.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/cdvd/CDVDiso/src/zlib/ChangeLog b/plugins/cdvd/CDVDiso/src/zlib/ChangeLog new file mode 100644 index 0000000000..1ac946309b --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/ChangeLog @@ -0,0 +1,855 @@ + + ChangeLog file for zlib + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/plugins/cdvd/CDVDiso/src/zlib/README b/plugins/cdvd/CDVDiso/src/zlib/README new file mode 100644 index 0000000000..80f71ae856 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/README @@ -0,0 +1,125 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.3 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.3 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2004 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/plugins/cdvd/CDVDiso/src/zlib/adler32.c b/plugins/cdvd/CDVDiso/src/zlib/adler32.c new file mode 100644 index 0000000000..f201d6701e --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/compress.c b/plugins/cdvd/CDVDiso/src/zlib/compress.c new file mode 100644 index 0000000000..d37e84f5e3 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/crc32.c b/plugins/cdvd/CDVDiso/src/zlib/crc32.c new file mode 100644 index 0000000000..32814c20c8 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/crc32.h b/plugins/cdvd/CDVDiso/src/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/cdvd/CDVDiso/src/zlib/deflate.c b/plugins/cdvd/CDVDiso/src/zlib/deflate.c new file mode 100644 index 0000000000..529f716b7a --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/plugins/cdvd/CDVDiso/src/zlib/deflate.h b/plugins/cdvd/CDVDiso/src/zlib/deflate.h new file mode 100644 index 0000000000..222c53e043 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/gvmat32.obj b/plugins/cdvd/CDVDiso/src/zlib/gvmat32.obj new file mode 100644 index 0000000000000000000000000000000000000000..b215511b0b4c7a0e25957aaea71516367e689507 GIT binary patch literal 10137 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 WW3{ysJC^V-X2vvN#VBA!9Ps}|LQHM| literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDiso/src/zlib/gvmat32c.c b/plugins/cdvd/CDVDiso/src/zlib/gvmat32c.c new file mode 100644 index 0000000000..7ad2b27943 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/gvmat32c.c @@ -0,0 +1,62 @@ +/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86 + * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. + * File written by Gilles Vollant, by modifiying the longest_match + * from Jean-loup Gailly in deflate.c + * it prepare all parameters and call the assembly longest_match_gvasm + * longest_match execute standard C code is wmask != 0x7fff + * (assembly code is faster with a fixed wmask) + * + * Read comment at beginning of gvmat32.asm for more information + */ + +#if defined(ASMV) && (!defined(NOOLDPENTIUMCODE)) +#include "deflate.h" + +/* if your C compiler don't add underline before function name, + define ADD_UNDERLINE_ASMFUNC */ +#ifdef ADD_UNDERLINE_ASMFUNC +#define longest_match_7fff _longest_match_7fff +#define longest_match_686 _longest_match_686 +#define cpudetect32 _cpudetect32 +#endif + + +unsigned long cpudetect32(); + +uInt longest_match_c( + deflate_state *s, + IPos cur_match); /* current match */ + + +uInt longest_match_7fff( + deflate_state *s, + IPos cur_match); /* current match */ + +uInt longest_match_686( + deflate_state *s, + IPos cur_match); /* current match */ + + +static uInt iIsPPro=2; + +void match_init () +{ + iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0; +} + +uInt longest_match( + deflate_state *s, + IPos cur_match) /* current match */ +{ + if (iIsPPro!=0) + return longest_match_686(s,cur_match); + + if (s->w_mask != 0x7fff) + return longest_match_686(s,cur_match); + + /* now ((s->w_mask == 0x7fff) && (iIsPPro==0)) */ + return longest_match_7fff(s,cur_match); +} + + +#endif /* defined(ASMV) && (!defined(NOOLDPENTIUMCODE)) */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/gvmat64.obj b/plugins/cdvd/CDVDiso/src/zlib/gvmat64.obj new file mode 100644 index 0000000000000000000000000000000000000000..ce31fc14bbbc97429b22f70e48bfa575b4e809ce GIT binary patch literal 4215 zcmb8yeQ*@z9l-J5B{8IXjd#3*R9S{Al>(V0gcuU2NjTtAFAP$uj9g1Ed%0W6Ki$dZ z^Lu{#?C$eCxA#1It(%Kv>EfY{{!$TL2DY+vWKG(R75xPw2lL7*)Meq1%38ze@J0EH zi}kXwx2!eN(z(L-z3j0khlt!&C^E}EkST+D@iyA^7H8|tA}FC<`J1X2=)TQ&JkXu? z^#{5`zLSCOnD3O|JQD0~^_>k;IB)*uKF%=@>{tIA>djpb5Y&BjTjAl;1({=q-}k!v zIkDI5dXl`~+_pneciiu3KJM>c>^mAXuMe2}?jpOOCpJ==%|A4KaiVF%hlOTC&9q{d z$n?ww2n&&-EOdFvoK!v+?KZ;uDX|^BgLg z@2`8!v$>rMbbTV?63?A2!~+%6osLRPd6j18DlK$W^5s<;Ggzr}+v&-UY8Plh_J*Gk z+b!GFmdRw==GXbWo=r;$>3J_*DF{4&{ws=XO+5!^lyKeadR{D5dd7^XWUmdFMU{c+ zMYWxi0;a#RBrx4yThcj7#a$jK(^*QUC~)|c-sbM@ z9CG-SmvX^WS75_i66h(aZJKg;b^-TVKf9r>?~b8rY_lW!@g&aooBjUouB~*V&hI
!37YEBAv)hz zs)bYW>Y8eObu_(Fk5ibcCpyy6cr+Dh)x)V&B;FERt1nNqM)bC1BCa)`nI`xjmN+tqVq5{IOVQT`byCQCUfwLaJeFs;fdPR>i~V>Z&q| za*or+u+wqzy0)J?GkW3Oi*D621$BEz?B}ANli#XtVsGkut+spEH`@8}B8JNG&$tY` zP{W^~2RGmd+=!!b6Mh3X;{@D>-@>2bG~ABmxC5(kC)VK4uomyd+4vA%i+ivUA4Weu zf&qLK7vN*~ef$+J!F?FQUt<`bzzFiqHg3TK*n!Vt3J>8bd=A&)OSm3iM*1kPAbpcw zq)&1Ld+=3M58W}OFY+edhi~D7_%_m3c^7G`yoYM~`6E7sC-52kGd_n*GvFLJ%F&_CA856J&C*nAqgjeDeyb8;Zx<(c1Sc{xv)Z;gC9&(Nm z#H;aooQyZ(G+c_DYb?VV7{zM*F_ggUypHSecX%uQ z9&g7t@D6+%4SWabgYh2H2jc{8#*?@OKg2unBfJ|w!F%uwZo{*<9nawoJdgC%xPZG+ z3Pc{nA@~rwaSxW_BRCZI;%NLOj>AWBJTexB5BKA@k+Co;@M*jT4`MAogWtgya1OqR z0c329W_%eJA!B6Rh`kuX*YI6DX3H2EYE62a+)Qx|CH#MuebXP#liB`vfMBct=Xc=H(*cRT0%eb)ce}Wh^&b`G;y88et;KGcW=EP_OQfDX zx6H94O>Q7k51m_XvLj7mM8m9HhaG9MfoQmu+hRwW>>?Ur<#yYVCQlHJv~o||ktVMa zjk0n_?TEe+jkakg_WCTN18Mejk9v|>`0R( zMC!f6Eg?IiZ$wvGxehy`Z$wvFxh-}?--yOrx!rc8NfG5@YotH_>~bmbs>wuc1q^Dj zxYUqwG?y>R%hxYY#5>BOt@rO)FX~OVQ1X94smY|!m3`Mz*BRLIe?2jCs1^2qw)|gC zszrq^_1me;Q7`{jlj=pGYnJ19wxEuw%_X{8AlOu=)TA|#@%hTFO&zh?tO9F1XWJP* zIJPP5VRlt#ATyKbDMw~5CG{4QtFw@jdXLFvLX^~-N-nd467L~-8TH0CmI}E#x09LZ z$aIsbcVxDc2@YnmvkEJ2-gWj;N3Hk#*}XVOq*nf1rjLwz2gqgKB*ThjXM*;GqSp0X zoj*}Wt;D&EdOuTZ>Odx_W-VqBwW + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/infback.c b/plugins/cdvd/CDVDiso/src/zlib/infback.c new file mode 100644 index 0000000000..1e03e1bab0 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/inffas32.obj b/plugins/cdvd/CDVDiso/src/zlib/inffas32.obj new file mode 100644 index 0000000000000000000000000000000000000000..52e8ccd3998d5c2ae795295fd12b1bc031539983 GIT binary patch literal 14899 zcmb`O33L?2*2iyE1qhwM1OZt@7-2vl7*LQ!R6vkLgX}vvW|=@BnZe8?0Uojig=9oF zaRo%wCxY^Pir|7uKx7qB+z@0Fkr;h!`cP5w{cm?=dK%*L&iUq?`SI`DRn^s1x2h($ ziewQ(-Ii6l?OLcU2Mt@)oPs}QZjzx`v0w&NR51Erh#-;#k&Ff4WltO-bp#)ZDS2K~JF^{?v65y^eHyn_AZw@lRJuxJ{=Uyg`@YhJ7RI75(9K zB}x#@>q9+Lf+2UhFD;Os=^yLv9!U4OGjami?(XAqGK21J{&ZhXFyN;Jnf|<#tju(G zR%XbTlakds%jX{(8s|nnAC=!r&kTlA{AoVR8ZNuc9ts5987VpL)ReRd6fWaBp%$d@ z<=4V1Q6qf2;5!{(PEdvfWk^tl1Z7B2h6H6uP=*9$NKl3ZWk^tl1Z7B2h6H6uP=*9$ zNPw@vSK(U)Ul+cO@a=-{bbQN(4IMIQX~Fkhe+!2^!^6`Wgonn2E33T)-^CU7@U$u% z?5P#b@{A7Ol@Pu=KC$HdSE_Voi9nsyuENotn+vl%%?pz~3E^Hn!u@(9M=Y-5U+0$! z_e>Pp#6r=ildc3njGOR8+ZVcvr!e*nLOh zPL`ewPxahfa0_mcbj>c5MEMi?4;nCVX*k9+vz>>?P0N;!Y`ZtqqwOZw%9$5>`TV)L z9cTXH5Baik+synm)9>q(+uW?QYi04t*n%Ujf}bnrUU_~q(G1F!rSaP;nS}$ThNZb8 zBS(xHUOH#Nj0>*(YHc@Vyi~Mn#+C%GQMi@|FBRM5({RkfqTMYI?)zc(rrdhPClgk8 zn(9e#J&+2Q?}RtXf3IX1WO#4!cL_z?S0%V+|A=B|9Cd}7cH9-LQB>k6wde!0ifGi9 z`GtLy&iXw&jHY_e5t4iEOkhGS-xys7UWL&sinKc4T` z!*jyh!|<*1`|;q8T+c&Dt9BMl^|YZ}Phzn;joWoQ7w6rRSd7}C@})y@H86738~59E z-k#S=g*@%l>BKXMTp;I2GSi?~RKE?b8%FZf;&eJyY`HbOUBCSmsCBr^mGAOz4VSw7 z9*=AK*DimSC&o4XJJ+cl;nAMhQnA3buejiMcm5SF|4%Oetp)GLxXxWH*y?tbZgU+t z;+l5EHT_^Xrogp+x68jHvBc>`4e*Yp7rj|h1Jdki_Ms!_Be-y=77BOyx4WhlC!TB) ze?P3GKKkPaqDJwq11DY6PP(SUarvR)FN#YO5=-!GF84)U?yw5V-5=#9TU@hVK+^C| zwDY;Ya1w5YlIzfcn3oGKh}_prUwNfpcxMHkVkYM4Eo}PBA*()In`y=6FSs)t6E4|p zwmtjQ+6vO3%i`6paLioGbDX||%CAHowafAyH~UWKkMf2meq{R1xzf9Ebw}i?tM;4b zw%_1>OY?rY&wP|uKaxIyeFiCF%PrxZmcN+q=0UyRz|-l?`ao%`Rqjx{bsfjo4WjNP z@DPi-CRAkj{X0Ucuy@^X*9L_NrKD%XTp9j~Z-#e;`!^^qQHf`YkE+D|g_Gh7N45*^ znm5|hpwnnit=w9P=fZU{!`D*h!oy<g7>;E8#U%`?-n|O`@9xbrd#03mg*BxWtb$ZnRka_BDU0#h>EFPZhIbzTdFc` zfvRq*eNYLeItyi$+!ZUUrE1`g^(mVki#iOWs^D-kz!4M&j-+^S6jcL9Qvx`KYJjO! z8%(3R-~_q~%%ZD7KQ#ga)EK;%nt?gg5)4rim`m4#dDIS^MD4-J)DfIQH-S^BD|jE> z22Q7*;0(G0oJn_q1vCJhO@qM)XgD~BMuUZv0v1s^7^V#HK^hCrqw(N;3V;hJ2V6)Y za1rH#i)k{rgri4}ecl5%?rM1TLe6;BtBxTtSb4Pt#IxB`pV^p%vhB z^bGh*4i4K8V=o|1oDh0RF58yWX54fF9fjj6l zxRcI+yXY*qn|=a6px?lc>347+T?9Wde}{ca0$%tTDe!Zu1b#tP!2MJW{E}SY0jdoi zq&nbNbTxR08i9w&10JDf;8AJ;9-~&^*VGz3PS=CqPzUe?bppSo&R_}M4t__y!0%}Q z_#gakCOSofz|%AsJVQgkvost$Pouz}X$<%)dBF>m0{%v6;O~?HUZing8I1>}$Oe_T z7mN`>u#(6FtBXmXOH2V1#8j}3mVkEdwi~$#kd%(pa4SZN+fJ;Os_=uPQJ|+U-<01qu6ZznB zF&TVH+y|}@)4`Qu2KbDa4L&O#0G|_u;Pc`^aFv)3z91HXtHlyzBd=7pj4uYSFL*VD)82E)a4(=Bx!2{wu@Sr#i9ujB4!{R)6MEn9C z6Bod*#qZ!Z0)Hmc38BDmMJ2FAQ~|#eRl!mb2YxTAfjU|l%`yh@G$8^}@M)p88j zNP0oHOaZTvX<%dN1DnaQ;I%RnY$3D3mNEn;$vm)~oDAM5{{eQ8)4`5%7T8J70dJB; zU}rfGyjd;;Z;=m!-Q=TScliX^LoNk-%BR3yawXVXJ_q)ZtH3+t8t_iJ7Q9RT8|)|7 zf&JwMaDaRh94y}khsaIfP`Mc#F5d%3$oIifatAnC?gUfh9xzpY0;bC^K%e{)%#eq{ z@$x7*K^_OQI6gW|y0dwS!U{Ib1L-JQJSN;a(NrhiF`LYr?MaF_tWgK{) ztOib(3E&J_6Pzip1ZT;5V1aA^&X$e9IkE{jS2hC+Wec!KwgSVlH8@}104|X2z=g5{ zxJY&a7t5Q$CGuAA5!nNLRQ3WNlYPJ^Wiq%__5+v6f#7mE7<@{O0$0c};4?A>d{(A` z&&jdi^D+}$B?I7Uc`vv|2Ei9)F1S`s0{MmhXZe$YStAxfR?icY~kEJ>aME6Yz8SIrxSA65KDp0>6~U!2|LHcup!SWjt6StApRk8eplc3!aws!85WUcviZ> zbJ7F;B%6W%m94;^WfJ&{YzzJ>Zv=mn9l+mZC$LO*21(rlO4S8asv8)ix`UO}?OFBSA#&88Uof-Bfwf}6j)o00qdv~u&zo2>nR^tUyTK? zR+(T!H34+1Z15Tt02`|y*hJ-n9yJ+ks{R39tL_7vtLb11H4|*93cy5lKiFE$0o$lT zu&oM%?bJN5y_yepPz%A1YBAVJEdg&;kAhv)<6t+n47^P}4R%-m1n*R9z-09@*jK#* z4pHmCp=v!iT)hR3P@BM!YBQLswt;DCH<+&WfaBH2-~{zKn57Pa+3FB@uQ~?isN-Nz zod83s1k6+4gZb(|;3Rb#yic76r>S4SS?U7#fGPv$D1pCB=BgO5P*nkoR8=sn;=u=1 zb#R`l0Y0Q^f%Das;6ha&T%;O;i%b>e8}Lch4qUF< zgDX^L@M(1mxKiB;u2Q#yFQ{JNOX?1At?CQDtoniL)c|mV8Vqh!!@;-JNbnss8r-Dr z28&e+xLKuxTT}+PRgDARSL4BLDjVFcCW0TT5V%+6fght4f%p0Z$==;YsHGasVPC9$4*f{*{cJ@-txe)7Xe}~0>lmN zRJD@5Y2$op6U;Q;fZylM&Yo1)zF$4rn;!6{1tw0up6@tw=I5kL^rqwla{cMv{7ip( zAitKK)39@1Wm{_`dsEWWy{Va@AZo)^M+=p|R8=!eRv<9(THAQF{T@0vUjD)y9B*PL ztasV#asqF5aBL$xQSD^!SYIf*1b(eLc7keXwT!HkkPi(N3_0H?)1MjQTY4AsF$QhhPMSR|eh7M$SQ?mkT6I$3sH7fUk3S5O>x}}}e{bx_Tv=1;!ve0an zlk?5mc0qCc>gZKAJDoWa9-qajl$^Q|EPN} zoh|(#ukQGIb|1RR=UJ5Eofw$tbQDanf9Vi4?82&Ok8{>Oe_Upk&s-Ip^GjsRM6DCi zP3iP5B)Vk2(36%ki@Bxgi>xdaJ05RVn$B0ztQ6g0&MI)(6}ivlPrk$-I6=ie5t)pf&TFkyoXy#A6)lcV&x!U8&hP9Pr+@JMR`xh* z{6{^nM+#E^zbzPlXFYW`d__LPFW?*+(Z9}|YvpBADK7)gB$2+2UQYk^Z!c$cFMFJx zxt$)Wf2{;VSOv4aIL{FBIXyn8f1Wtq!(KFP`S!Wfv>Fg{Cws%$LS=#TDRGFLwSw4xLbT&-|L&*6; zC@r$IIGe{_xSTnn$A)uURpeaGywT0)tY`&&=xoMI-o#l~d#;Hdsg5OEFQ5P0NOks# zbKE=cIeYBSXA@^myY4&?|In$N10yoXqSjx|?rau&0(9E#-zw1+bu^dx3#Wpg2hL8p z#JB(Cx5?!`?0lh$e1~5sdQJVK*?@n?4Z%;!y7Lf1~yix9~AFP#~~JNDFcyW#Jo-0Jz5#Wdu-R5Hr`=l zWzd6A%}v_^tqkHFvlgc9pIRA+Y9cOX+O}$CAf|{YnQ1H0${^m4YGvAZH;R>k_#5`& zOj}c}4C(`wWZL>_Wgwnq?VHEZM6C=&kPsFz(>=s9-v@)m?qKCJdwyIhg#BpP59C7T}8b=%_w%WOqRt61(>SE>{s+B<; z%k65~IFifCAdb;ma|B0dSsC;clr?^z(aNBWP#!ZcM^RZB#1YeOrtLGW3_1m6`S>}l z4B`lzqT7J+>D}%a1-DZ~8Lo0(g0@>ZPar}`Ld;_Y9Y2%0@D}z=*S!3Z@ ztqj@@W%s0oxcuU)H^L7ku)o9S-R%AkHw)>s{+ z73MIgYs_?6S{YObWsReGTA|KRx0~sn)e7wl)zh?X(#oJ?P`yms39SrLRm;am6|K;w zP`%A`&9pM;Ca9*S?N+TYhe7o*ZTDzp&=e?Z4Vb2tK~F&4VWwNI71|Wanm2Z9WzdgM z*1YkvRtD8D%ICG(S{ZaB)SYH|owPD&6x3Cw&8w9`xlq1EK2i4cK zP1XwY0n}ZlZLwAct%B-j+FsPkpsi5WT(?6j%vVtT&2&e!GU#Wh0jBLYtuT(_%jc3S zv@)nEl;s;Ov@)nClr@*!p_M`RKv{EBx>i`XpsevWRV#xQL0Mzr5v>eb2W7o4ALM0a z&>pB{vwk0Ig|QE1%?IbS!n#nce9lSG3hM%t%gozcD}#DK-C^2#Yh_Rllr{GAv@+-+ zD66d&X=TuAs6J-iwOYYXp{%jBTPyeml+{NkwKC{;C~Le4EE%jY_MxnCbgfnfb%wI$ z`z~4;GziLC7lvttwF1hTcXPEeXf~AP2XnPD=xHcxZhuZIjD0Ap&o^m>c80pse7BFa z!gzzS)~%nl!W@P)mCaS}>=}b%N#Pp1gb9^NNbEPBNyBi5-}_tpYl`xY~-3L z!RP)jR+MHi8@U7}+~DOOzQ>+ty)obCwTeG%u`1RIYPPmi#=llu^BiU8y4$o{Ijl56 zSkfbD%A>HHOpqJ(sR_mJ&;Rei`Xr@hluNT@9~W=>XT(fNSymcuGrsMkB%fvBvP_Ga zt0TXdfc)4|au^mqkzl7;3CVk?mWBVq z=V&FL*0R&Q3dwu1w&fj2KIvs!K8ECdZrj3V2p@LT@E2Hk7uilz17+|@BioV$3-2r2 zmY%TinE=}|78c&=w=I)l;WH?<<$hTBM4)Y%k1O6kwk=Cx;ZuFKWi75ej{5N54ZP24 zr}+RDJ}F{bj>5uco@~o0SolP&ZQ;KrHajeQs*O)x+G!fV!ly88OLJKGETe7d01KaM zv@AMqj&m>N7C0RBLK;46Xy+OX3!mh(Eqo4*&$`)`TwL)fG~2=_&G^KUZCM5j|Ngfv ze142i?bsGRC&uS*Y|CL-T01P?!@{Rt>@@s;cKE!AZE1{B`2>S)xdj$JD_~prBo*(( z+m=*Vc$eL_OoWAZ&~3{sSa?U=vRF|qoB@bf7UTY9fA3p+PQkI{*iS_|dvn#?%#7sx zgB?3(4jmbaWU6SJh@zspQ6U$YFRP>uQR0>}Uc}K17^7pWxV(H5G%5{bbgUW=wr=vi z4pjN0D|k!Xtzb*q%wuggLq=jq73?wNcKOCKWOOCCb@Zz^1Erir$5|oy>5+!yeuM4u zceUGuUrAq;zt*MME3Pl6LfMg<(NX7UyW=IJUgDBHSY(OpXF!+xM)Vdd%$Kw+ESEMB zOp(~G&R{;&a$(aGqMqz@NHg}vWk$9XabbsJaS@63LPtk%qi^w!Ag=B3BB$m5G-&Uz zMUq>)V3A9+rU)~$p@K~&nC((^r$yR7YIKzMuJfVgR&$Zl7tt~0OAB;#oG#rON)^>j b=dK`}j9N#BpK%!#vd7gWu}oN;F + * Please use the copyright conditions above. + * + * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant + * + * inffas8664.c call function inffas8664fnc in inffasx64.asm + * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + * + */ + +#include +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ + + + + typedef struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } type_ar; +#ifdef ASMINF + +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + type_ar ar; + void inffas8664fnc(struct inffast_ar * par); + + + +#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->write; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + + inffas8664fnc(&ar); + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = (unsigned long)ar.hold; + state->bits = ar.bits; + return; +} + +#endif diff --git a/plugins/cdvd/CDVDiso/src/zlib/inffast.c b/plugins/cdvd/CDVDiso/src/zlib/inffast.c new file mode 100644 index 0000000000..fa31cad905 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/inffast.h b/plugins/cdvd/CDVDiso/src/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/cdvd/CDVDiso/src/zlib/inffasx64.obj b/plugins/cdvd/CDVDiso/src/zlib/inffasx64.obj new file mode 100644 index 0000000000000000000000000000000000000000..be18d9da5fc30aee47203f57e615da1d25f0c1bf GIT binary patch literal 5881 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 literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDiso/src/zlib/inffixed.h b/plugins/cdvd/CDVDiso/src/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/cdvd/CDVDiso/src/zlib/inflate.c b/plugins/cdvd/CDVDiso/src/zlib/inflate.c new file mode 100644 index 0000000000..33ea902928 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/inflate.h b/plugins/cdvd/CDVDiso/src/zlib/inflate.h new file mode 100644 index 0000000000..fbbc871432 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/cdvd/CDVDiso/src/zlib/inftrees.c b/plugins/cdvd/CDVDiso/src/zlib/inftrees.c new file mode 100644 index 0000000000..38ded81c36 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/inftrees.h b/plugins/cdvd/CDVDiso/src/zlib/inftrees.h new file mode 100644 index 0000000000..dc0fd567ea --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/cdvd/CDVDiso/src/zlib/trees.c b/plugins/cdvd/CDVDiso/src/zlib/trees.c new file mode 100644 index 0000000000..7a04802862 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/trees.h b/plugins/cdvd/CDVDiso/src/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/cdvd/CDVDiso/src/zlib/uncompr.c b/plugins/cdvd/CDVDiso/src/zlib/uncompr.c new file mode 100644 index 0000000000..ad6db0a67c --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/cdvd/CDVDiso/src/zlib/zconf.h b/plugins/cdvd/CDVDiso/src/zlib/zconf.h new file mode 100644 index 0000000000..e3b0c962e3 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/zlib.h b/plugins/cdvd/CDVDiso/src/zlib/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/zutil.c b/plugins/cdvd/CDVDiso/src/zlib/zutil.c new file mode 100644 index 0000000000..0f4bd7871d --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/cdvd/CDVDiso/src/zlib/zutil.h b/plugins/cdvd/CDVDiso/src/zlib/zutil.h new file mode 100644 index 0000000000..0ba6e02087 --- /dev/null +++ b/plugins/cdvd/CDVDiso/src/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/cdvd/CDVDisoEFP/ChangeLog.txt b/plugins/cdvd/CDVDisoEFP/ChangeLog.txt new file mode 100644 index 0000000000..525e384214 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/ChangeLog.txt @@ -0,0 +1,58 @@ +CDVDisoEFP v0.6 Changes: +-------------------- + + v0.6: + * Completely re-wrote screens (efp) + * Used device access sources from CDVDlinuz to get data from DVDs. (efp) + * Added ability to read devices from Windows XP (efp) + Note: only ISO and CDDA seem to be readable from CDs at this time. + If your trying to get another format, use Linux. + DVD5 is readable. Don't have a DVD9 game to test. (I think - efp) + * Separated image file access by OS. (Linux, Windows) (efp) + * Separated Multi-file/Compression/Image-Typing to their own source files. (efp) + * Added a few entries to the Image Typing database, based on Linux CD-ROM sources (efp) + * Added Table Rebuild (for those who lost .table files.) (efp) + * Put in a separate source program to compare two ISOs for data accuracy. (efp) + * Renamed executables and config files (so not to conflict with CDVDiso) (efp) + * Internalized the .INI File code (to allow use in other OS-es besides Windows) (efp) + * Added temporarily a .toc file saving track info (for PS1 and Music CDs) (efp) + * Added a new compression format. (BZip2 Size) (efp) + * Added .glade files at linuzappz's request (efp) + * Upgraded to 0.6.0 beta PS2Edef.h definitions (efp) + + * Data buffer start position re-set for CDs. (shadow caught the problem while testing) + * Supported images grouped in "Browse" button (shadow's suggestion) + * Initial Image reminder added to Windows CDVDOpen() (shadow's suggestion) + * used 64 bit fstat (fstat64) for correct sizes on >2GB files in Linux (efp) + * Adjusted CD types to allow for PS2 CDs (shadow pointed out an example iso) + * Added changing CDs/DVDs while emulation stopped (shadow's suggestion) + Built in an "open tray" delay when switching media. (efp) + * Added ".img" to Image Filter (although .cue/.sub files aren't tapped.) (efp) + * Added ".nrg" to Image Filter (shadow's suggestion) + * In Windows, when newly selected from the PCSX2 configure screen, CDVDinit() + (as well as InitConf()) are not called. Fixed (EFP) + + v0.5: + * Added block dumping code + * Added BZ2/Z2 format ;) + * Added optimaze asm code of zlib with vsnet2003 only. Compression / Uncompression should be faster now (shadow) + * Added Vsnet2005 beta1 project files + amd64 asm optimaze code for zlib (shadow) + + v0.4: + * Rewrote mostly ;) + * .bz is still unsupported + + v0.3: + * Better Iso detection, thx florin :) + * Updated to PS2Edefs v0.4.5 + + v0.2: + * Added support for isos using 2048 blocksize + * Nero images are supported + * Better extension filtering + + v0.1: + * First Release + * Tested with Pcsx2 + + Email: diff --git a/plugins/cdvd/CDVDisoEFP/build.sh b/plugins/cdvd/CDVDisoEFP/build.sh new file mode 100644 index 0000000000..c7fd593d87 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +curdir=`pwd` + +echo ------------------- +echo Building CDVDisoEFP +echo ------------------- + +cd ${curdir}/src/Linux +make $@ + +if [ -s cfgCDVDisoEFP ] && [ -s libCDVDisoEFP.so ] +then +# copy the files +cp cfgCDVDisoEFP libCDVDisoEFP.so ${PCSX2PLUGINS} +fi diff --git a/plugins/cdvd/CDVDisoEFP/license.txt b/plugins/cdvd/CDVDisoEFP/license.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/license.txt @@ -0,0 +1,342 @@ + 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/plugins/cdvd/CDVDisoEFP/readme.txt b/plugins/cdvd/CDVDisoEFP/readme.txt new file mode 100644 index 0000000000..fca4b91e6d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/readme.txt @@ -0,0 +1,55 @@ +CDVDiso v0.6 +------------ + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Linux requirements: +------------------ + You need the GTK library, compiled with GTK v2.6.1 (at least). + +Usage: +----- + For those using Windows, place the file "CDVDisoEFP.dll" in the Plugin + directory of the Emulator to use it. + + For Linux users, place the file "libCDVDisoEFP.so" in the plugin + directory of the Emulator. Also, place the file "cfgCDVDisoEFP" in the "cfg" + directory of the Emulator to use it. + +Configuration: +------------- + You must select the iso you want to use in the Configuration dialog. You + will come back to this dialog should the Emulator want another disc. + +Creating an iso (linux, Windows XP only): +--------------- + To create an iso you can use the button 'Make Image'. The file + will be the one in the Iso Edit, and the Source Device is the CDRom or + DVD drive that will have the disc you want to make an image of. + The compression method is specified by the Compression Method Combo. + + Note: This will fail if the file already exists (if it's compressed + a .z or .bz2 suffix will be added). + +Compressed isos: +--------------- + You can create them using the Convert button. This will create a .Z or .bz + file (the compressed image) and a .z.table or .bz2.table file (this is a + table, for speed reasons.) Both will be created in the same dir as the + selected image. The original image will not be deleted and/or changed. Also, + you can decompress a compressed image by selecting "None" in the + Compression Method Combo. + + Note: you only can decompress the images with this program; not with + compress or bzip2. + +Compression Method: +------------------ + .z speed - fast compression, small blocks, table in memory. + .bz2 speed - average compression, 32k - 40k blocks, table in memory. + .bz2 size - best compression, 60k - 62k blocks, table on file. + + + Email: diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/CD.c b/plugins/cdvd/CDVDisoEFP/src/Linux/CD.c new file mode 100644 index 0000000000..ab5796c8c3 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/CD.c @@ -0,0 +1,367 @@ +/* CD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // strerror() +#include // open() +#include // ioctl() +#include // open() +#include // lseek(), open() +#include // close(), lseek(), (sleep()) + +#include // CD/DVD based ioctl() and defines. + +#include "../convert.h" +#include "logfile.h" +#include "device.h" +#include "CD.h" + + +// Constants +u8 *playstationcdname = "PLAYSTATION\0"; +u8 *ps1name = "CD-XA001\0"; + +// CD-ROM temp storage structures (see linux/cdrom.h for details) +struct cdrom_tochdr cdheader; +struct cdrom_tocentry cdtrack; +struct cdrom_subchnl subchannel; +u8 cdtempbuffer[2352]; + +int cdmode; // mode of last CDVDreadTrack call (important for CDs) + + +// Internal Functions + +void InitCDSectorInfo() { + cdmode = -1; +} // END InitSectorInfo(); + + +// Function Calls from CDVD.c + +void InitCDInfo() { + InitCDSectorInfo(); +} // END InitDiscType() + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + s32result = 0; + + if(buffer == NULL) return(-1); + + // The CD way of figuring out where to read. + LBAtoMSF(lsn, buffer); + + switch(mode) { + case CDVD_MODE_2048: + case CDVD_MODE_2328: + case CDVD_MODE_2340: + case CDVD_MODE_2352: + errno = 4; // Interrupted system call... (simulated the first time) + while(errno == 4) { + errno = 0; + s32result = ioctl(devicehandle, CDROMREADRAW, buffer); + } // ENDWHILE- Continually being interrupted by the system... + break; + case CDVD_MODE_2368: // Unimplemented... as yet. + default: +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Unknown Mode %i", mode); +#endif /* VERBOSE_WARNINGS */ + return(-1); // Illegal Read Mode? Abort + break; + } // ENDSWITCH- Which read mode should we choose? + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitCDSectorInfo(); + return(-1); + } // ENDIF- Trouble getting a track count? + + cdmode = mode; // Save mode for buffer positioning later. + return(0); // Call accomplished +} // END CDreadTrack() + +s32 CDgetBufferOffset() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetBufferOffset()"); +#endif /* VERBOSE_FUNCTION */ + + switch(cdmode) { + case CDVD_MODE_2048: + return(0+24); + case CDVD_MODE_2328: + return(0+24); + case CDVD_MODE_2340: + return(0+12); + case CDVD_MODE_2352: + return(0+0); + case CDVD_MODE_2368: // Unimplemented... as yet. + default: +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Unknown Mode %i", cdmode); +#endif /* VERBOSE_WARNINGS */ + return(0); // Not to worry. for now. + } // ENDSWITCH- where should we put the buffer pointer? +} // END CDgetBuffer() + +// I, personally, don't see the big deal with SubQ +// However, sooner or later I'll incorporate it into the Cache Buffer system +// (backward compatibility, and all that) +s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { + int tempmode; + s32 s32result; + + s32result = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDreadSubQ()"); +#endif /* VERBOSE_FUNCTION */ + + tempmode = cdmode; + if(tempmode == -1) tempmode = CDVD_MODE_2352; + CDreadTrack(lsn, tempmode, cdtempbuffer); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(s32result); + } // ENDIF- Trouble? + + subchannel.cdsc_format = CDROM_MSF; + s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(s32result); + } // ENDIF- Trouble? + + if(subq != NULL) { + subq->mode = subchannel.cdsc_adr; + subq->ctrl = subchannel.cdsc_ctrl; + subq->trackNum = subchannel.cdsc_trk; + subq->trackIndex = subchannel.cdsc_ind; + subq->trackM = subchannel.cdsc_reladdr.msf.minute; + subq->trackS = subchannel.cdsc_reladdr.msf.second; + subq->trackF = subchannel.cdsc_reladdr.msf.frame; + subq->discM = subchannel.cdsc_absaddr.msf.minute; + subq->discS = subchannel.cdsc_absaddr.msf.second; + subq->discF = subchannel.cdsc_absaddr.msf.frame; + } // ENDIF- Did the caller want all this data? + + return(0); +} // END CDVDreadSubQ() + +s32 CDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + if(cdvdtn != NULL) { + cdvdtn->strack = cdheader.cdth_trk0; + cdvdtn->etrack = cdheader.cdth_trk1; + } // ENDIF- programmer actually WANTS this info? + + return(0); // Call accomplished +} // END CDVDgetTN() + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + u8 j; + u16 k; + char temptime[3]; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + j = newtrack; + if(j == CDROM_LEADOUT) j = 0; + + if(j == 0) { + k = 27; + } else { + k = j * 10 + 37; + } // ENDIF- Where to start hunting for this number? + + if(cdvdtd != NULL) { + cdvdtd->type = tocbuffer[j*10 + 30]; + + temptime[0] = BCDTOHEX(tocbuffer[k]); + temptime[1] = BCDTOHEX(tocbuffer[k + 1]); + temptime[2] = BCDTOHEX(tocbuffer[k + 2]); + cdvdtd->lsn = MSFtoLBA(temptime); + } // ENDIF- Does the caller REALLY want this data? + + return(0); // Call accomplished +} // END CDVDgetTD() + +s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { + s32 offset; + s32 s32result; + int i; + u8 j; + int tempdisctype; + + offset = 0; + errno = 0; + i = 0; + j = 0; + tempdisctype = CDVD_TYPE_UNKNOWN; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); + if((s32result != 0) || (errno != 0)) { + return(-1); + } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort + disctype = CDVD_TYPE_DETCTCD; + + switch(ioctldisktype) { + case CDS_AUDIO: +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected CDDA Audio disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_CDDA; + tocbuffer[0] = 0x01; + break; + + case CDS_DATA_1: + case CDS_MIXED: +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tocbuffer[0] = 0x41; + + CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); + offset = CDgetBufferOffset(); + i = 0; + while((*(playstationcdname + i) != 0) && + (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; + if(*(playstationcdname + i) == 0) { + i = 0; + while((*(ps1name + i) != 0) && + (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; + if(*(ps1name + i) == 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PSCD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation 2 CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2CD; + } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) + } else { + tempdisctype = CDVD_TYPE_UNKNOWN; + } // ENDIF- Did we find the Playstation name? + break; + + default: + return(-1); + } // ENDSWITCH- What has ioctl disc type come up with? + + // Collect TN data + cdheader.cdth_trk0 = 0; + cdheader.cdth_trk1 = 0; + + s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", + s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + cdheader.cdth_trk0 = 1; + cdheader.cdth_trk1 = 1; + } // ENDIF- Failed to read in track count? Assume 1 track. +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Track Number Range: %i-%i", + cdheader.cdth_trk0, cdheader.cdth_trk1); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[2] = 0xA0; + tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); + tocbuffer[12] = 0xA1; + tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); + + // Collect disc TD data + cdtrack.cdte_track = CDROM_LEADOUT; + cdtrack.cdte_format = CDROM_LBA; + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", + s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Trouble getting a track count? + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Total Time: %i:%i", + tocbuffer[27], tocbuffer[28]); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + // Collect track TD data + for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { + cdtrack.cdte_track = j; // j-1? + cdtrack.cdte_format = CDROM_LBA; + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", + j, s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + // No more here... + + } else { + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", + j, + cdtrack.cdte_datamode, + tocbuffer[j*10+37], + tocbuffer[j*10+38], + tocbuffer[j*10+39]); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; + tocbuffer[j*10 + 32] = HEXTOBCD(j); + tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); + tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); + tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); + } // ENDIF- Trouble getting a track count? + } // NEXT j- Reading each track's info in turn + + errno = 0; + disctype = tempdisctype; // Trigger the fact we have the info (finally) + return(disctype); +} // END CDVDgetDiskType() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/CD.h b/plugins/cdvd/CDVDisoEFP/src/Linux/CD.h new file mode 100644 index 0000000000..2546cbaabd --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/CD.h @@ -0,0 +1,46 @@ +/* CD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __CD_H__ +#define __CD_H__ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "../PS2Edefs.h" + + +// Exported Functions + +extern void InitCDInfo(); +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 CDgetBufferOffset(); +extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); +extern s32 CDgetTN(cdvdTN *cdvdtn); +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 CDgetDiskType(s32 ioctldisktype); + + +#endif /* __CD_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.c b/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.c new file mode 100644 index 0000000000..e5ad373caf --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.c @@ -0,0 +1,450 @@ +/* CDVDiso.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ +#define CDVDdefs +#include "PS2Edefs.h" + +#include "conf.h" +#include "actualfile.h" +#include "isofile.h" +#include "logfile.h" +#include "convert.h" +#include "version.h" +#include "CDVDiso.h" + + +struct IsoFile *isofile; +char isobuffer[2448]; +char isocdcheck[2448]; +int isomode; +int deviceopencount; // 0 = Closed, 1+ = Open + + +char* CALLBACK PS2EgetLibName() { + return(libname); +} // END PS2EgetLibName() + + +u32 CALLBACK PS2EgetLibType() { + return(PS2E_LT_CDVD); +} // END PS2getLibType() + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return((version << 16) | (revision << 8) | build); +} + + +s32 CALLBACK CDVDinit() { + int i; + + InitLog(); + if(OpenLog() != 0) return(-1); // Couldn't open Log File? Abort. + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDinit()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + InitConf(); + + isofile = NULL; + isomode = -1; + for(i = 0; i < 2048; i++) isocdcheck[i] = 0; + deviceopencount = 0; + + return(0); +} // END CDVDinit() + + +void CALLBACK CDVDshutdown() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDshutdown()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + isofile = IsoFileClose(isofile); + CloseLog(); +} // END CDVDshutdown() + + +s32 CALLBACK CDVDopen(const char* pTitleFilename) { + int retval; + int i; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDopen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + LoadConf(); + + if( pTitleFilename != NULL ) strcpy(conf.isoname, pTitleFilename); + + if((conf.isoname[0] == 0) || + ((conf.startconfigure != 0) && (deviceopencount == 0)) || + ((conf.restartconfigure != 0) && (deviceopencount > 0))) { + ExecCfg("configure"); + LoadConf(); + } // ENDIF- Haven't initialized the configure program yet? Do so now. + + isofile = IsoFileOpenForRead(conf.isoname); + if(isofile == NULL) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Failed to open ISO file!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + // return(-1); // Taken out for "NULL" device simulation + for(i = 0; i < 2048; i++) isocdcheck[i] = 0; + return(0); + } // ENDIF- Trouble opening file? Abort. + + retval = IsoFileSeek(isofile, 16); + if(retval != 0) return(-1); + retval = IsoFileRead(isofile, isobuffer); + if(retval != 0) return(-1); + + if(deviceopencount > 0) { + i = 0; + while((i < 2048) && (isocdcheck[i] == isobuffer[i])) i++; + if(i == 2048) deviceopencount = 0; // Same CD/DVD? No delay. + } // ENDIF- Is this a restart? Check for disc change. + + for(i = 0; i < 2048; i++) isocdcheck[i] = isobuffer[i]; + + return(0); +} // END CDVDopen() + + +void CALLBACK CDVDclose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDclose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + isofile = IsoFileClose(isofile); + deviceopencount = 50; +} // END CDVDclose() + + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + char temptime[3]; + int i; + int pos; + u32 tracklsn; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDreadSubQ()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) return(-1); + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + return(-1); // DVDs don't have SubQ data + } // ENDIF- Trying to get a SubQ from a DVD? + + // fake it + i = BCDTOHEX(isofile->toc[7]); + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + tracklsn = MSFtoLBA(temptime); + while((i < BCDTOHEX(isofile->toc[17])) && (tracklsn < lsn)) { + i++; + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + tracklsn = MSFtoLBA(temptime); + } // ENDIF- Loop through tracks searching for lsn track + i--; + + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = HEXTOBCD(i); + subq->trackIndex = HEXTOBCD(i); + + LBAtoMSF(lsn - tracklsn, temptime); + subq->trackM = HEXTOBCD(temptime[0]); + subq->trackS = HEXTOBCD(temptime[1]); + subq->trackF = HEXTOBCD(temptime[2]); + + subq->pad = 0; + + // lba_to_msf(lsn + (2*75), &min, &sec, &frm); + LBAtoMSF(lsn, temptime); + subq->discM = HEXTOBCD(temptime[0]); + subq->discS = HEXTOBCD(temptime[1]); + subq->discF = HEXTOBCD(temptime[2]); + + return(0); +} // END CDVDreadSubQ() + + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + if(isofile == NULL) return(-1); + if(deviceopencount > 0) return(-1); + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + Buffer->strack = 1; + Buffer->etrack = 1; + } else { + Buffer->strack = BCDTOHEX(isofile->toc[7]); + Buffer->etrack = BCDTOHEX(isofile->toc[17]); + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + return(0); +} // END CDVDgetTN() + + +s32 CALLBACK CDVDgetTD(u8 track, cdvdTD *Buffer) { + u8 actualtrack; + int pos; + char temptime[3]; + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) return(-1); + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + actualtrack = track; + if(actualtrack == 0xaa) actualtrack = 0; + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + if (actualtrack <= 1) { + Buffer->type = 0; + Buffer->lsn = isofile->filesectorsize; + } else { + Buffer->type = CDVD_MODE1_TRACK; + Buffer->lsn = 0; + } // ENDIF- Whole disc? (or single track?) + } else { + if (actualtrack == 0) { + Buffer->type = 0; + temptime[0] = BCDTOHEX(isofile->toc[27]); + temptime[1] = BCDTOHEX(isofile->toc[28]); + temptime[2] = BCDTOHEX(isofile->toc[29]); + Buffer->lsn = MSFtoLBA(temptime); + } else { + pos = actualtrack * 10; + pos += 30; + Buffer->type = isofile->toc[pos]; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + Buffer->lsn = MSFtoLBA(temptime); + } // ENDIF- Whole disc? (or single track?) + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + return(0); +} // END CDVDgetTD() + + +s32 CALLBACK CDVDgetTOC(void* toc) { + int i; + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) return(-1); + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTOC()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + for(i = 0; i < 2048; i++) *(((char *) toc) + i) = isofile->toc[i]; + return(0); +} // END CDVDgetTOC() + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + int retval; + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + return(-1); + } // ENDIF- Simulate a temporarily open device? + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDreadTrack(%u)", lsn); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + retval = IsoFileSeek(isofile, (off64_t) lsn); + if(retval != 0) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Trouble finding the sector!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(-1); + } // ENDIF- Trouble finding the sector? + + retval = IsoFileRead(isofile, isobuffer); + if(retval != 0) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Trouble reading the sector!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(-1); + } // ENDIF- Trouble finding the sector? + + isomode = mode; + return(0); +} // END CDVDreadTrack() + + +u8* CALLBACK CDVDgetBuffer() { + int offset; + + if(isofile == NULL) return(NULL); + if(deviceopencount > 0) return(NULL); + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetBuffer()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + offset = 0; + switch(isomode) { + case CDVD_MODE_2352: + offset = 0; + break; + case CDVD_MODE_2340: + offset = 12; + break; + case CDVD_MODE_2328: + case CDVD_MODE_2048: + offset = 24; + break; + } // ENDSWITCH isomode- offset to where data it wants is. + + if(offset > isofile->blockoffset) offset = isofile->blockoffset; + + return(isobuffer + offset); +} // END CDVDgetBuffer() + + +s32 CALLBACK CDVDgetDiskType() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(CDVD_TYPE_NODISC); + if(deviceopencount > 0) { + deviceopencount--; + return(CDVD_TYPE_DETCT); + } // ENDIF- Simulate a temporarily open device? + + return(isofile->cdvdtype); +} // END CDVDgetDiskType() + + +s32 CALLBACK CDVDgetTrayStatus() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTrayStatus()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(CDVD_TRAY_OPEN); + if(deviceopencount > 30) { + deviceopencount--; + return(CDVD_TRAY_OPEN); + } // ENDIF- Simulate a temporarily open device? + + return(CDVD_TRAY_CLOSE); +} // END CDVDgetTrayStatus() + + +s32 CALLBACK CDVDctrlTrayOpen() { + int i; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDctrlTrayOpen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + // Close() + isofile = IsoFileClose(isofile); + deviceopencount = 50; + + // and re-Open() + if((conf.isoname[0] == 0) || + ((conf.restartconfigure != 0) && (deviceopencount > 0))) { + ExecCfg("configure"); + LoadConf(); + } // ENDIF- Haven't initialized the configure program yet? Do so now. + + isofile = IsoFileOpenForRead(conf.isoname); + if(isofile == NULL) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Failed to open ISO file!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + } // ENDIF- Trouble opening file? Abort. + + if(deviceopencount > 0) { + i = 0; + while((i < 2048) && (isocdcheck[i] == isobuffer[i])) i++; + if(i == 2048) deviceopencount = 0; // Same CD/DVD? No delay. + } // ENDIF- Is this a restart? Check for disc change. + + for(i = 0; i < 2048; i++) isocdcheck[i] = isobuffer[i]; + + return(0); +} // END CDVDctrlTrayOpen() + + +s32 CALLBACK CDVDctrlTrayClose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDctrlTrayClose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(0); +} // END CDVDctrlTrayClose() + + +void CALLBACK CDVDconfigure() { + ExecCfg("configure"); +} // END CDVDconfigure() + + +s32 CALLBACK CDVDtest() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDtest()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + InitConf(); // Odd... hasn't CDVDinit been called yet? + LoadConf(); + + if(conf.isoname[0] == 0) return(0); // No name chosen yet. Catch on Open() + if(IsIsoFile(conf.isoname) == 0) return(0); // Valid name. Go. + return(-1); // Invalid name - reconfigure first. + // Note really need this? Why not just return(0)... +} // END CDVDtest() + + +void CALLBACK CDVDabout() { + ExecCfg("about"); +} // END CDVDabout() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.h b/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.h new file mode 100644 index 0000000000..8cd9301e5b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/CDVDiso.h @@ -0,0 +1,29 @@ +/* CDVDiso.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CDVDISO_H +#define CDVDISO_H + + +// #define VERBOSE_FUNCTION_INTERFACE + + +#endif /* CDVDISO_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.c b/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.c new file mode 100644 index 0000000000..8bf18ae205 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.c @@ -0,0 +1,582 @@ +/* DVD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // strerror(), memset(), memcpy() +#include // open() +#include // ioctl() +#include // open() +#include // lseek(), open() +#include // close(), lseek(), (sleep()) + +#include // CD/DVD based ioctl() and defines. + +#include "logfile.h" +#include "device.h" +#include "DVD.h" + + +// Constants +u8 *playstationname = "PLAYSTATION\0"; + +// DVD storage structures (see linux/cdrom.h for details) +dvd_struct dvdphysical; +dvd_struct dvdcopyright[DVD_LAYERS]; +dvd_struct dvdbca; +dvd_struct dvdmanufact[DVD_LAYERS]; + +u32 dvdlastlsn; +u8 dvdtempbuffer[2064]; + + +// Internal Functions + +void InitDVDSectorInfo() { + dvdlastlsn = 0xffffffff; +} // END InitSectorInfo(); + +void HexDump(u8 *strptr, u8 count) { + int i; + u8 ch[2]; + char hexline[81]; + int hexlinepos; + + ch[1] = 0; + + if(count == 0) count = 16; + if((count < 1) || (count > 16)) return; + + hexlinepos = 0; + hexlinepos += sprintf(&hexline[hexlinepos], "CDVD driver: "); + + for(i = 0; i < count; i++) { + hexlinepos += sprintf(&hexline[hexlinepos], "%.2x ", (*(strptr + i)) * 1); + } // NEXT i- printing each new Hex number + + for(i = 0; i < count; i++) { + if((*(strptr + i) < 32) || (*(strptr + i) > 127)) { + hexlinepos += sprintf(&hexline[hexlinepos], "."); + } else { + ch[0] = *(strptr + i); + hexlinepos += sprintf(&hexline[hexlinepos], "%s", ch); + } // ENDIF- Is this an unprintable character? + } // NEXT i- printing each new character + PrintLog(hexline); +} // ENDIF HexDump() + + +//// DVD Structure Functions + +s32 DVDreadPhysical() { + s32 s32result; + u8 i; + + errno = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadPhysical()\n"); +#endif /* VERBOSE_FUNCTION */ + + memset(&dvdphysical, 0, sizeof(dvd_struct)); + dvdphysical.type = DVD_STRUCT_PHYSICAL; + + i = DVD_LAYERS; + while(i > 0) { + i--; + dvdphysical.physical.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdphysical); + } // ENDWHILE- reading in all physical layers... + + if((s32result == -1) || (errno != 0)) { + dvdphysical.type = 0xFF; +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Physical structure: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with reading Layer 0 of the physical data? Abort + + i = 3; + while((i > 0) && (dvdphysical.physical.layer[i].end_sector == 0)) i--; + dvdphysical.physical.layer_num = i; + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Physical Characteristics"); + PrintLog("CDVD driver: Number of Layers: %i", + (s32) dvdphysical.physical.layer_num + 1); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + PrintLog("CDVD driver: Layer Number %i", i); + switch(dvdphysical.physical.layer[i].book_type) { + case 0: + PrintLog("CDVD driver: Book Type: DVD-ROM"); + break; + case 1: + PrintLog("CDVD driver: Book Type: DVD-RAM"); + break; + case 2: + PrintLog("CDVD driver: Book Type: DVD-R"); + break; + case 3: + PrintLog("CDVD driver: Book Type: DVD-RW"); + break; + case 9: + PrintLog("CDVD driver: Book Type: DVD+RW"); + break; + default: + PrintLog("CDVD driver: Book Type: Unknown (%i)", + dvdphysical.physical.layer[i].book_type); + break; + } // ENDSWITCH- Displaying the Book Type + PrintLog("CDVD driver: Book Version %i", + dvdphysical.physical.layer[i].book_version); + switch(dvdphysical.physical.layer[i].min_rate) { + case 0: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-ROM"); + break; + case 1: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RAM"); + break; + case 2: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-R"); + break; + case 3: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RW"); + break; + case 9: + PrintLog("CDVD driver: Use Minimum Rate for: DVD+RW"); + break; + default: + PrintLog("CDVD driver: Use Minimum Rate for: Unknown (%i)", + dvdphysical.physical.layer[i].min_rate); + break; + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + switch(dvdphysical.physical.layer[i].disc_size) { + case 0: + PrintLog("CDVD driver: Physical Disk Size: 120mm"); + break; + case 1: + PrintLog("CDVD driver: Physical Disk Size: 80mm"); + break; + default: + PrintLog("CDVD driver: Physical Disk Size: Unknown (%i)", + dvdphysical.physical.layer[i].disc_size); + break; + } // ENDSWITCH- What's the Disk Size? + switch(dvdphysical.physical.layer[i].layer_type) { + case 1: + PrintLog("CDVD driver: Layer Type: Read-Only"); + break; + case 2: + PrintLog("CDVD driver: Layer Type: Recordable"); + break; + case 4: + PrintLog("CDVD driver: Layer Type: Rewritable"); + break; + default: + PrintLog("CDVD driver: Layer Type: Unknown (%i)", + dvdphysical.physical.layer[i].layer_type); + break; + } // ENDSWITCH- Displaying the Layer Type + switch(dvdphysical.physical.layer[i].track_path) { + case 0: + PrintLog("CDVD driver: Track Path: PTP"); + break; + case 1: + PrintLog("CDVD driver: Track Path: OTP"); + break; + default: + PrintLog("CDVD driver: Track Path: Unknown (%i)", + dvdphysical.physical.layer[i].track_path); + break; + } // ENDSWITCH- What's Track Path Layout? + // PrintLog("CDVD driver: Disc Size %i Layer Type %i Track Path %i Nlayers %i", + // dvdphysical.physical.layer[i].nlayers); + switch(dvdphysical.physical.layer[i].track_density) { + case 0: + PrintLog("CDVD driver: Track Density: .74 m/track"); + break; + case 1: + PrintLog("CDVD driver: Track Density: .8 m/track"); + break; + case 2: + PrintLog("CDVD driver: Track Density: .615 m/track"); + break; + default: + PrintLog("CDVD driver: Track Density: Unknown (%i)", + dvdphysical.physical.layer[i].track_density); + break; + } // ENDSWITCH- Displaying the Track Density + switch(dvdphysical.physical.layer[i].linear_density) { + case 0: + PrintLog("CDVD driver: Linear Density: .267 m/bit"); + break; + case 1: + PrintLog("CDVD driver: Linear Density: .293 m/bit"); + break; + case 2: + PrintLog("CDVD driver: Linear Density: .409 to .435 m/bit"); + break; + case 4: + PrintLog("CDVD driver: Linear Density: .280 to .291 m/bit"); + break; + case 8: + PrintLog("CDVD driver: Linear Density: .353 m/bit"); + break; + default: + PrintLog("CDVD driver: Linear Density: Unknown (%i)", + dvdphysical.physical.layer[i].linear_density); + break; + } // ENDSWITCH- Displaying the Linear Density + if(dvdphysical.physical.layer[i].start_sector == 0x30000) { + PrintLog("CDVD driver: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + dvdphysical.physical.layer[i].start_sector); + } else if(dvdphysical.physical.layer[i].start_sector == 0x31000) { + PrintLog("CDVD driver: Starting Sector: %lu (DVD-RAM, DVD+RW)", + dvdphysical.physical.layer[i].start_sector); + } else { + PrintLog("CDVD driver: Starting Sector: %lu", + dvdphysical.physical.layer[i].start_sector); + } // ENDLONGIF- What does the starting sector tell us? + PrintLog("CDVD driver: End of Layer 0: %lu", + dvdphysical.physical.layer[i].end_sector_l0); + PrintLog("CDVD driver: Ending Sector: %lu", + dvdphysical.physical.layer[i].end_sector); + if(dvdphysical.physical.layer[i].bca != 0) + PrintLog("CDVD driver: BCA data present"); + } // NEXT i- Work our way through each layer... +#endif /* VERBOSE_DISC_INFO */ + + return(0); // Success. Physical data stored for perusal. +} // END DVDreadPhysical() + +s32 DVDreadCopyright() { + s32 s32result; + u8 i; + int successflag; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadCopyright()"); +#endif /* VERBOSE_FUNCTION */ + + successflag = 0; + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + memset(&dvdcopyright[i], 0, sizeof(dvd_struct)); + dvdcopyright[i].type = DVD_STRUCT_COPYRIGHT; + dvdcopyright[i].copyright.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdcopyright[i]); + if(s32result == 0) { + successflag = 1; + } else { + dvdcopyright[i].type = 0xFF; + } // ENDIF- + } // NEXT i- Getting copyright data for every known layer + + if(successflag == 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Copyright info: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Copyright Information\n"); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + if(dvdcopyright[i].type != 0xFF) { + PrintLog("CDVD driver: Layer Number %i CPST %i RMI %i", + dvdcopyright[i].copyright.layer_num, + dvdcopyright[i].copyright.cpst, + dvdcopyright[i].copyright.rmi); + } // ENDIF- Were we successful reading this one? + } // NEXT i- Printing out all copyright info found... +#endif /* VERBOSE_DISC_INFO */ + + errno = 0; + return(0); // Success. Copyright data stored for perusal. +} // END DVDreadCopyright() + +s32 DVDreadBCA() { + s32 s32result; + int i; + + i = 0; + errno = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadBCA()"); +#endif /* VERBOSE_FUNCTION */ + + memset(&dvdbca, 0, sizeof(dvd_struct)); + dvdbca.type = DVD_STRUCT_BCA; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdbca); + if((s32result == -1) || (errno != 0)) { + dvdbca.type = 0xFF; +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting BCA: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: BCA Length %i Value:", + dvdbca.bca.len); + for(i = 0; i < 188-15; i += 16) { + HexDump(dvdbca.bca.value+i, 16); + } // NEXT i- dumping whole key data +#endif /* VERBOSE_DISC_INFO */ + + return(0); // Success. BCA data stored for perusal. +} // END DVDreadBCA() + +s32 DVDreadManufact() { + s32 s32result; + u8 i; + int successflag; + int j; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadManufact()"); +#endif /* VERBOSE_FUNCTION */ + + j = 0; + successflag = 0; + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + memset(&dvdmanufact[i], 0, sizeof(dvd_struct)); + dvdmanufact[i].type = DVD_STRUCT_MANUFACT; + dvdmanufact[i].manufact.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdmanufact[i]); + if((s32result != 0) || (errno != 0)) { + dvdmanufact[i].type = 0xFF; + } else { + successflag = 1; + } // ENDIF- Did we fail to read in some manufacturer data? + } // NEXT i- Collecting manufacturer data from all layers + + if(successflag == 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Manufact: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Manufact Data"); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + if(dvdmanufact[i].type != 0xFF) { + PrintLog("CDVD driver: Layer %i Length %i Value:", + dvdmanufact[i].manufact.layer_num, + dvdmanufact[i].manufact.len); + for(j = 0; j < 128-15; j += 16) { + HexDump(dvdmanufact[i].manufact.value+j, 16); + } // NEXT j- dumping whole key data + } // ENDIF- Do we have data at this layer? + } // NEXT i- Running through all the layers +#endif /* VERBOSE_DISC_INFO */ + + errno = 0; + return(0); // Success. Manufacturer's data stored for perusal. +} // END DVDreadManufact() + + +// External Functions + +// Function Calls from CDVD.c + +void InitDVDInfo() { + int j; + + dvdphysical.type = 0xFF; // Using for empty=0xff, full!=0xff test + dvdbca.type = 0xFF; + for(j = 0; j < DVD_LAYERS; j++) { + dvdcopyright[j].type = 0xFF; + dvdmanufact[j].type = 0xFF; + } // NEXT j- Zeroing each layer of data + InitDVDSectorInfo(); +} // END InitDiscType() + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + off64_t offsettarget; + off64_t offsetresult; + + errno = 0; + s32result = 0; + offsetresult = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + if(lsn != dvdlastlsn + 1) { + offsettarget = lsn; + offsettarget *= 2048; + errno = 4; + while(errno == 4) { + errno = 0; + offsetresult = lseek64(devicehandle, offsettarget, SEEK_SET); + } // ENDWHILE- waiting for the system interruptions to cease. + if((offsetresult < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error on seek: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitDVDSectorInfo(); + return(-1); + } // ENDIF- trouble with seek? Reset pointer and abort + } // ENDIF- Do we have to seek a new position to read? + + errno = 4; + while(errno == 4) { + errno = 0; + s32result = read(devicehandle, buffer, 2048); + } // ENDWHILE- waiting for the system interruptions to cease. + if((s32result != 2048) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: DVD Short Block, Size: %i", s32result); + PrintLog("CDVD driver: Error: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitDVDSectorInfo(); + return(-1); + } // ENDIF- Trouble reading the data? Reset pointer and abort + + dvdlastlsn = lsn; + return(0); // Call accomplished +} // END DVDreadTrack() + +s32 DVDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + // Going to treat this as one large track for now. + if(cdvdtn != NULL) { + cdvdtn->strack = 1; + cdvdtn->etrack = 1; + } // ENDIF- programmer actually WANTS this info? + + return(0); // Call accomplished +} // END DVDgetTN() + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + if((newtrack >= 2) && (newtrack != CDROM_LEADOUT)) return(-1); + + if(cdvdtd != NULL) { + cdvdtd->lsn = dvdphysical.physical.layer[0].end_sector + - dvdphysical.physical.layer[0].start_sector + + 1; + cdvdtd->type = CDVD_MODE_2048; + } // ENDIF- Does the caller REALLY want this data? + + return(0); // Call accomplished +} // END DVDgetTD() + +s32 DVDgetDiskType(s32 ioctldisktype) { + s32 s32result; + int i; + s32 tempdisctype; + + errno = 0; + s32result = 0; + i = 0; + tempdisctype = CDVD_TYPE_UNKNOWN; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + if((ioctldisktype != CDS_DATA_1) && (ioctldisktype != CDS_MIXED)) { + return(-1); + } // ENDIF- Not a data disc we know of? Abort then + + s32result = DVDreadPhysical(); + if((s32result != 0) || (errno != 0)) { + return(-1); + } // ENDIF- Error reading the DVD physical structure? Not a DVD after all. + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: DVD Found (Dual-Sided)"); +#endif /* VERBOSE_DISC_TYPE */ + disctype = CDVD_TYPE_DETCTDVDD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: DVD Found (Single-Sided)"); +#endif /* VERBOSE_DISC_TYPE */ + disctype = CDVD_TYPE_DETCTDVDS; + } // ENDIF- Definitely a DVD. Size Test? + + // Read in the rest of the structures... + DVDreadCopyright(); + DVDreadBCA(); + DVDreadManufact(); + + // Test for "Playstation" header + s32result = DVDreadTrack(16, CDVD_MODE_2048, dvdtempbuffer); + if(s32result != 0) { + return(-1); + } else { + i = 0; + while((*(playstationname + i) != 0) && + (*(playstationname + i) == dvdtempbuffer[8 + i])) { + i++; + } // ENDWHILE- Checking each letter of PLAYSTATION name for a match + if(*(playstationname + i) == 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation 2 DVD"); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2DVD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Guessing it's a Video DVD"); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_DVDV; + } // ENDIF- Did we find the Playstation name? + } // ENDIF- Error reading disc volume information? Invalidate Disc + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { + tocbuffer[0] = 0x24; // Dual-Sided DVD + tocbuffer[4] = 0x41; + tocbuffer[5] = 0x95; + } else { + tocbuffer[0] = 0x04; // Single-Sided DVD + tocbuffer[4] = 0x86; + tocbuffer[5] = 0x72; + } // ENDIF- Are there too many sectors for a single-sided disc? + + tocbuffer[1] = 0x02; + tocbuffer[2] = 0xF2; + tocbuffer[3] = 0x00; + + tocbuffer[16] = 0x00; + tocbuffer[17] = 0x03; + tocbuffer[18] = 0x00; + tocbuffer[19] = 0x00; + + disctype = tempdisctype; // Triggers the fact the other info is available + return(disctype); +} // END DVDgetDiskType() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.h b/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.h new file mode 100644 index 0000000000..7dbc1c7c0d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/DVD.h @@ -0,0 +1,45 @@ +/* DVD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DVD_H__ +#define __DVD_H__ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +// Exported Functions + +extern void HexDump(u8 *strptr, u8 count); +extern void InitDVDInfo(); +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DVDgetTN(cdvdTN *cdvdtn); +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 DVDgetDiskType(s32 ioctldisktype); + + +#endif /* __DVD_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/Makefile b/plugins/cdvd/CDVDisoEFP/src/Linux/Makefile new file mode 100644 index 0000000000..1fee325f34 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/Makefile @@ -0,0 +1,91 @@ + +PLUGIN = libCDVDisoEFP.so +PLUGINOBJS = CDVDiso.o +PLUGINHEADERS = CDVDiso.h +PLUGINFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -D_LARGEFILE64_SOURCE \ + -I.. -I. -I./Linux +PLUGINLIBS = -lz -lbz2 + +CFG = cfgCDVDisoEFP +CFGOBJS = interface.o aboutbox.o mainbox.o selectionbox.o \ + devicebox.o conversionbox.o progressbox.o messagebox.o \ + tablerebuild.o device.o CD.o DVD.o +CFGHEADERS = interface.h aboutbox.h mainbox.h selectionbox.h \ + devicebox.h conversionbox.h progressbox.h messagebox.h \ + tablerebuild.h device.h CD.h DVD.h +CFGFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -D_LARGEFILE64_SOURCE \ + -I.. -I. -I./Linux +CFGLIBS = -lz -lbz2 + +COMP = compCDVDisoEFP +COMPOBJS = comparisonbox.o progressbox.o messagebox.o \ + comparisondummy.o +COMPHEADERS = progressbox.h messagebox.h + +SHAREDOBJS = ../version.o actualfile.o ../isofile.o conf.o logfile.o \ + ../imagetype.o ../multifile.o ../isocompress.o ../convert.o \ + ../gzipv1.o ../blockv2.o ../gzipv2.o ../ecma119.o \ + ../bzip2v3.o ../bzip2v2.o \ + ../toc.o ../ini.o +SHAREDHEADERS = ../version.h actualfile.h ../isofile.h conf.h logfile.h \ + ../imagetype.h ../multifile.h ../isocompress.h ../convert.h \ + ../gzipv1.h ../blockv2.h ../gzipv2.h ../bzip2v2.h ../ecma119.h \ + ../toc.h ../ini.h ../bzip2v3.h + + +CC = gcc + +GTKFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +//GTKFLAGS += -DG_DISABLE_DEPRECATED \ +// -DGDK_DISABLE_DEPRECATED \ +// -DGDK_PIXBUF_DISABLE_DEPRECATED \ +// -DGTK_DISABLE_DEPRECATED + +GTKLIBS = $(shell pkg-config --libs gtk+-2.0) +# Do we need to remove "-rdynamic" as well? Or is that just the main program? + + +all: plugin cfg +install: all + +release: plugin cfg + cp $(PLUGIN) ../.. + cp $(CFG) ../.. + +plugin: $(PLUGINOBJS) $(SHAREDOBJS) + rm -f $(PLUGIN) + $(CC) -shared -Wl,-soname,$(PLUGIN) $(PLUGINFLAGS) $(PLUGINLIBS) \ + $(PLUGINOBJS) $(SHAREDOBJS) -o $(PLUGIN) + strip --strip-unneeded --strip-debug $(PLUGIN) + +cfg: $(CFGOBJS) $(SHAREDOBJS) + rm -f $(CFG) + $(CC) $(CFGFLAGS) $(GTKFLAGS) $(CFGLIBS) $(GTKLIBS) \ + $(CFGOBJS) $(SHAREDOBJS) -o $(CFG) + strip $(CFG) + +compare: $(COMPOBJS) $(SHAREDOBJS) + rm -f $(COMP) + $(CC) $(CFGFLAGS) $(GTKFLAGS) $(CFGLIBS) $(GTKLIBS) \ + $(COMPOBJS) $(SHAREDOBJS) -o $(COMP) + strip $(COMP) + +$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c + $(CC) $(PLUGINFLAGS) -c $< -o $@ + +$(CFGOBJS) ../comparisonbox.o ../comparisondummy.o: %.o: %.c + $(CC) $(CFGFLAGS) $(GTKFLAGS) -c $< -o $@ + +.PHONY : clean allclean +clean: + -rm -f $(PLUGINOBJS) $(PLUGIN) $(CFGOBJS) $(CFG) \ + $(COMP) $(COMPOBJS) $(SHAREDOBJS) + -rm -f *~ temp.txt ../*~ ../temp.txt ../../*~ + +allclean: + -rm -f $(PLUGINOBJS) $(PLUGIN) $(CFGOBJS) $(CFG) \ + $(COMP) $(COMPOBJS) $(SHAREDOBJS) + -rm -f *~ temp.txt ../*~ ../temp.txt ../../*~ + -rm -f ../../$(PLUGIN) ../../$(CFG) + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.c new file mode 100644 index 0000000000..80b73f5e53 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.c @@ -0,0 +1,106 @@ +/* aboutbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() + +#include // gtk_button_new_with_label() +#include // gtk_container_add() +#include // gtk_hbutton_box_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "version.h" +#include "aboutbox.h" + + +struct AboutBoxData aboutbox; + + +gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + if(aboutbox.window != NULL) { + gtk_widget_destroy(aboutbox.window); + aboutbox.window = NULL; + } // ENDIF- Do we have an About Box still? + + gtk_main_quit(); + return(TRUE); +} // END AboutBoxCancelEvent() + + +void AboutBoxDisplay() { + GtkWidget *item; + GtkWidget *container; + GtkWidget *vbox1; + char templine[256]; + + aboutbox.window = NULL; + aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); + gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDisoEFP"); + gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); + gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); + + g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", + G_CALLBACK(AboutBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + sprintf(templine, "%s v%i.%i", libname, revision, build); + item = gtk_label_new(templine); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + item = gtk_label_new("Current Author: efp"); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + item = gtk_label_new("Original code by: linuzappz & shadow"); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + container = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); + gtk_widget_show(container); + + item = gtk_button_new_with_label("Ok"); + gtk_container_add(GTK_CONTAINER(container), item); + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(AboutBoxCancelEvent), NULL); + item = NULL; + container = NULL; + vbox1 = NULL; + + gtk_widget_show(aboutbox.window); + gtk_main(); +} // END AboutDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.glade new file mode 100644 index 0000000000..cb099be18b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.glade @@ -0,0 +1,118 @@ + + + + + + + + True + About CDVDiso + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + True + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + CDVDiso ISO Driver v0.6 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Author: linuzappz <linuzappz@hotmail.com> + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Modified by: shadow, efp + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.h new file mode 100644 index 0000000000..bf1df52ca0 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/aboutbox.h @@ -0,0 +1,39 @@ +/* aboutbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef ABOUTBOX_H +#define ABOUTBOX_H + + +#include + + +struct AboutBoxData { + GtkWidget *window; // GtkWindow - About Box +}; + +extern struct AboutBoxData aboutbox; + + +extern void AboutBoxDisplay(); + + +#endif /* ABOUTBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.c b/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.c new file mode 100644 index 0000000000..64eaa69a7b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.c @@ -0,0 +1,222 @@ +/* actualfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // errno +#include // open() +#include // rename() +#include // strerror() +#include // stat64(), open(), fstat() +#include // stat64(), open(), fstat(), lseek64() +#include // stat64(), fstat(), lseek64(), read(), close(), write() +// unlink() + +#include "logfile.h" +#include "actualfile.h" + + +int IsActualFile(const char *filename) { + int retval; + struct stat64 filestat; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: IsActualFile(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = stat64(filename, &filestat); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error retrieving stats on %s", filename); + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); // Name doesn't exist. + } // ENDIF- Trouble getting stat on a file? + + if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. + return(0); // Yep, that's a file. +} // END IsActualFile() + + +void ActualFileDelete(const char *filename) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + unlink(filename); +} // END ActualFileDelete() + + +void ActualFileRename(const char *origname, const char *newname) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + rename(origname, newname); + return; +} // END ActualFileRename() + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + int newhandle; + + if(filename == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + newhandle = open(filename, O_RDONLY | O_LARGEFILE); + if((newhandle < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s\n", filename); + PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForRead() + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + int retval; + struct stat64 filestat; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSize()\n"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = fstat64(handle, &filestat); + if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. + return(filestat.st_size); +} // END ActualFileSize() + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + off64_t moved; + + if(handle < 0) return(-1); + if(position < 0) return(-1); // Maybe... position = 0? + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + moved = lseek64(handle, position, SEEK_SET); + if(errno != 0) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error on seek (%lli)", position); + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(0); +} // END ActualFileSeek() + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + + if(handle == ACTUALHANDLENULL) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = read(handle, buffer, bytes); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error reading from file!"); + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + // return(-1); + } // ENDIF- Error? Abort + + return(retval); // Send back how many bytes read +} // END ActualFileRead() + + +void ActualFileClose(ACTUALHANDLE handle) { + if(handle < 0) return; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileClose()"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + close(handle); + return; +} // END ActualFileClose() + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + int newhandle; + + if(filename == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); + if((newhandle < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s", filename); + PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForWrite() + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + + if(handle < 0) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = write(handle, buffer, bytes); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error writing to file!"); + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + // return(-1); + } // ENDIF- Error? Abort + + return(retval); // Send back how many bytes written +} // END ActualFileWrite() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.h b/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.h new file mode 100644 index 0000000000..a678b634d6 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/actualfile.h @@ -0,0 +1,50 @@ +/* actualfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef ACTUALFILE_H +#define ACTUALFILE_H + + +#include // off64_t + + +#define ACTUALHANDLE int +#define ACTUALHANDLENULL -1 + +// #define VERBOSE_FUNCTION_ACTUALFILE +// #define VERBOSE_WARNING_ACTUALFILE + + +extern int IsActualFile(const char *filename); +extern void ActualFileDelete(const char *filename); +extern void ActualFileRename(const char *origname, const char *newname); + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); +extern off64_t ActualFileSize(ACTUALHANDLE handle); +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); +extern void ActualFileClose(ACTUALHANDLE handle); + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + +#endif /* ACTUALFILE_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.c new file mode 100644 index 0000000000..3eb216bef1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.c @@ -0,0 +1,415 @@ +/* comparisonbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcpy() + +#include // gtk_button_new_with_label() +#include // gtk_container_add() +#include // gtk_entry_new() +#include // gtk_file_selection_set_filename() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_hseparator_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_vbox_new() +#include +#include // gtk_window_new() + +#include "logfile.h" +#include "conf.h" +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +#include "multifile.h" // multinames[] +#include "tablerebuild.h" // IsoTableRebuild() +#include "progressbox.h" +#include "messagebox.h" + + +struct MainBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *file1; // GtkEntry + GtkWidget *desc1; // GtkLabel + GtkWidget *file2; // GtkEntry + GtkWidget *desc2; // GtkLabel + GtkWidget *okbutton; // GtkButton + // Leaving the Cancel button unblocked... for emergency shutdown + + int stop; // Variable signal to stop long processes +}; + + +struct MainBoxData mainbox; + + +void MainBoxDestroy() { + if(mainbox.window != NULL) { + gtk_widget_destroy(mainbox.window); + mainbox.window = NULL; + mainbox.file1 = NULL; + mainbox.desc1 = NULL; + mainbox.file2 = NULL; + mainbox.desc2 = NULL; + mainbox.okbutton = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + gtk_widget_set_sensitive(mainbox.file1, FALSE); + gtk_widget_set_sensitive(mainbox.file2, FALSE); + gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + gtk_window_iconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxUnfocus() + + +gint MainBoxFile1Event(GtkWidget *widget, GdkEvent event, gpointer data) { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -3) { + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a valid image file"); + return(TRUE); + } // ENDIF- Not an Image file? + + if(returnval == -4) { + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Missing Table File (will rebuild)"); + return(TRUE); + } // ENDIF- Missing Compression seek table? + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + gtk_label_set_text(GTK_LABEL(mainbox.desc1), templine); + tempfile = IsoFileClose(tempfile); + return(TRUE); +} // END MainBoxFileEvent() + + +gint MainBoxFile2Event(GtkWidget *widget, GdkEvent event, gpointer data) { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -3) { + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a valid image file"); + return(TRUE); + } // ENDIF- Not an Image file? + + if(returnval == -4) { + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Missing Table File (will rebuild)"); + return(TRUE); + } // ENDIF- Missing Compression seek table? + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + gtk_label_set_text(GTK_LABEL(mainbox.desc2), templine); + tempfile = IsoFileClose(tempfile); + return(TRUE); +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + GdkEvent event; + + MainBoxFile1Event(NULL, event, NULL); + MainBoxFile2Event(NULL, event, NULL); + + gtk_widget_set_sensitive(mainbox.file1, TRUE); + gtk_widget_set_sensitive(mainbox.file2, TRUE); + gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file1); + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxRefocus() + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + mainbox.stop = 1; // Halt all long processess... + + MessageBoxDestroy(); + ProgressBoxDestroy(); + MainBoxDestroy(); + + gtk_main_quit(); + return(TRUE); +} // END MainBoxCancelEvent() + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + const char *tempisoname1; + const char *tempisoname2; + struct IsoFile *tempiso1; + struct IsoFile *tempiso2; + int stop; + off64_t endsector; + off64_t sector; + int retval; + char tempblock1[2448]; + char tempblock2[2448]; + int i; + + MainBoxUnfocus(); + + tempisoname1 = gtk_entry_get_text(GTK_ENTRY(mainbox.file1)); + tempisoname2 = gtk_entry_get_text(GTK_ENTRY(mainbox.file2)); + tempiso1 = NULL; + tempiso2 = NULL; + + tempiso1 = IsoFileOpenForRead(tempisoname1); + if(tempiso1 == NULL) { + MainBoxRefocus(); + MessageBoxShow("First file is not a Valid Image File.", 0); + tempisoname1 = NULL; + tempisoname2 = NULL; + return(TRUE); + } // ENDIF- Not an ISO file? Message and Stop here. + + tempiso2 = IsoFileOpenForRead(tempisoname2); + if(tempiso2 == NULL) { + MainBoxRefocus(); + MessageBoxShow("Second file is not a Valid Image File.", 0); + tempiso1 = IsoFileClose(tempiso1); + tempisoname1 = NULL; + tempisoname2 = NULL; + return(TRUE); + } // ENDIF- Not an ISO file? Message and Stop here. + + if(tempiso1->blocksize != tempiso2->blocksize) { + MainBoxRefocus(); + MessageBoxShow("Block sizes in Image files do not match.", 0); + tempiso1 = IsoFileClose(tempiso1); + tempiso2 = IsoFileClose(tempiso2); + tempisoname1 = NULL; + tempisoname2 = NULL; + return(TRUE); + } // ENDIF- Not an ISO file? Message and Stop here. + + if(tempiso1->multi == 1) { + i = 0; + while((i < 10) && + (IsoFileSeek(tempiso1, tempiso1->multisectorend[i] + 1) == 0)) i++; + endsector = tempiso1->multisectorend[tempiso1->multiend]; + } else { + endsector = tempiso1->filesectorsize; + } // ENDIF- Get ending sector from multifile? (Or single file?) + IsoFileSeek(tempiso1, 0); + + if(tempiso2->multi == 1) { + i = 0; + while((i < 10) && + (IsoFileSeek(tempiso2, tempiso2->multisectorend[i] + 1) == 0)) i++; + sector = tempiso2->multisectorend[tempiso2->multiend]; + } else { + sector = tempiso2->filesectorsize; + } // ENDIF- Get ending sector from multifile? (Or single file?) + IsoFileSeek(tempiso2, 0); + if(sector != endsector) { + MainBoxRefocus(); + MessageBoxShow("Number of blocks in Image files do not match.", 0); + tempiso1 = IsoFileClose(tempiso1); + tempiso2 = IsoFileClose(tempiso2); + tempisoname1 = NULL; + tempisoname2 = NULL; + return(TRUE); + } // ENDIF- Number of blocks don't match? Say so. + + sprintf(tempblock1, "%s == %s ?", tempisoname1, tempisoname2); + ProgressBoxStart(tempblock1, endsector); + + stop = 0; + mainbox.stop = 0; + progressbox.stop = 0; + while((stop == 0) && (tempiso1->sectorpos < endsector)) { + retval = IsoFileRead(tempiso1, tempblock1); + if(retval < 0) { + MainBoxRefocus(); + MessageBoxShow("Trouble reading first file.", 0); + stop = 1; + } else { + retval = IsoFileRead(tempiso2, tempblock2); + if(retval < 0) { + MainBoxRefocus(); + MessageBoxShow("Trouble reading second file.", 0); + stop = 1; + } else { + i = 0; + while((i < tempiso1->blocksize) && (tempblock1[i] == tempblock2[i])) i++; + if(i < tempiso1->blocksize) { + MainBoxRefocus(); + MessageBoxShow("Trouble reading second file.", 0); + stop = 1; + } // ENDIF- Sectors don't match? Say so. + } // ENDIF- Trouble reading second file? + } // ENDIF- Trouble reading first file? + + ProgressBoxTick(tempiso1->sectorpos); + while(gtk_events_pending()) gtk_main_iteration(); + + if(mainbox.stop != 0) stop = 2; + if(progressbox.stop != 0) stop = 2; + } // ENDWHILE- Comparing two files... sector by sector + + if(stop == 0) { + MainBoxRefocus(); + MessageBoxShow("Images Match.", 0); + } // ENDIF- Everything checked out? Say so. + tempiso1 = IsoFileClose(tempiso1); + tempiso2 = IsoFileClose(tempiso2); + tempisoname1 = NULL; + tempisoname2 = NULL; + return(TRUE); +} // END MainBoxOKEvent() + + +void MainBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Comparsion"); + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + // gtk_window_set_resizable(GTK_WINDOW(mainbox.window), FALSE); + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + G_CALLBACK(MainBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("First Iso File:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + mainbox.file1 = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file1, TRUE, TRUE, 0); + gtk_widget_show(mainbox.file1); + g_signal_connect(G_OBJECT(mainbox.file1), "changed", + G_CALLBACK(MainBoxFile1Event), NULL); + hbox1 = NULL; + + mainbox.desc1 = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc1, FALSE, FALSE, 0); + gtk_widget_show(mainbox.desc1); + + item = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + item = NULL; + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Second Iso File:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + mainbox.file2 = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file2, TRUE, TRUE, 0); + gtk_widget_show(mainbox.file2); + g_signal_connect(G_OBJECT(mainbox.file2), "changed", + G_CALLBACK(MainBoxFile2Event), NULL); + hbox1 = NULL; + + mainbox.desc2 = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc2, FALSE, FALSE, 0); + gtk_widget_show(mainbox.desc2); + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + mainbox.okbutton = gtk_button_new_with_label("Compare"); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); + gtk_widget_show(mainbox.okbutton); + g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", + G_CALLBACK(MainBoxOKEvent), NULL); + + item = gtk_button_new_with_label("Exit"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(MainBoxCancelEvent), NULL); + item = NULL; + hbox1 = NULL; + vbox1 = NULL; + + // We held off setting the name until now... so description would show. + gtk_entry_set_text(GTK_ENTRY(mainbox.file1), conf.isoname); + gtk_entry_set_text(GTK_ENTRY(mainbox.file2), conf.isoname); +} // END MainBoxDisplay() + + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + OpenLog(); + InitConf(); + LoadConf(); + MainBoxDisplay(); + ProgressBoxDisplay(); + MessageBoxDisplay(); + + gtk_widget_show_all(mainbox.window); + gtk_main(); + CloseLog(); + return(0); +} // END main() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.glade new file mode 100644 index 0000000000..8ca32e1410 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisonbox.glade @@ -0,0 +1,227 @@ + + + + + + + + 5 + True + CDVDiso Comparison + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + False + 0 + + + + True + First Iso File: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 5 + True + True + + + + + 0 + True + True + + + + + + True + File Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Second Iso File: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 5 + True + True + + + + + 0 + True + True + + + + + + True + File Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Compare + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Exit + True + GTK_RELIEF_NORMAL + True + + + + + 5 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/comparisondummy.c b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisondummy.c new file mode 100644 index 0000000000..ebedf17b26 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/comparisondummy.c @@ -0,0 +1,24 @@ +/* comparisondummy.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +void ConversionBoxRefocus() { return; } + +void DeviceBoxRefocus() { return; } diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/conf.c b/plugins/cdvd/CDVDisoEFP/src/Linux/conf.c new file mode 100644 index 0000000000..cd75fe4812 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/conf.c @@ -0,0 +1,204 @@ +/* conf.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // getenv() +#include // strerror() +#include // mkdir(), stat() +#include // mkdir(), stat() +#include // stat() + +// #define CDVDdefs +// #include "../PS2Edefs.h" +#include "logfile.h" +#include "../ini.h" +#include "conf.h" + + +const char *cfgname[] = { \ + "./cfg/cfgCDVDisoEFP", \ + "../cfg/cfgCDVDisoEFP", \ + "./cfgCDVDisoEFP", \ + "../cfgCDVDisoEFP", \ + "./plugins/cfgCDVDisoEFP", \ + "../plugins/cfgCDVDisoEFP", \ + NULL }; + +const char *confnames[] = { "IsoFile", "CdDev", NULL }; +const u8 defaultdevice[] = DEFAULT_DEVICE; +const char defaulthome[] = "../inis"; +const char defaultdirectory[] = ".PS2E"; +const char defaultfile[] = "CDVDisoEFP.ini"; + +char confdirname[256]; +char conffilename[256]; + +CDVDconf conf; + + +void ExecCfg(char *arg) { + int nameptr; + struct stat filestat; + char templine[256]; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: ExecCfg(%s)", arg); +#endif /* VERBOSE FUNCTION_CONF */ + errno = 0; + nameptr = 0; + while((cfgname[nameptr] != NULL) && + (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; + errno = 0; + + if(cfgname[nameptr] == NULL) { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: Couldn't find configuration program!"); +#endif /* VERBOSE_FUNCTION_CONF */ + return; + } // ENDIF- Did not find the executable? + + sprintf(templine, "%s %s", cfgname[nameptr], arg); + system(templine); +} // END ExecCfg() + + +void InitConf() { + int i; + int pos; + char *envptr; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: InitConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + conf.isoname[0] = 0; // Empty the iso name + + i = 0; + while((i < 255) && defaultdevice[i] != 0) { + conf.devicename[i] = defaultdevice[i]; + i++; + } // ENDWHILE- copying the default CD/DVD name in + conf.devicename[i] = 0; // 0-terminate the device name + + // Locating directory and file positions + pos = 0; + envptr = getenv("HOME"); + if(envptr == NULL) { + // = + i = 0; + while((pos < 253) && (defaulthome[i] != 0)) { + confdirname[pos] = defaulthome[i]; + conffilename[pos] = defaulthome[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + } else { + // = / + i = 0; + while((pos < 253) && (*(envptr + i) != 0)) { + confdirname[pos] = *(envptr + i); + conffilename[pos] = *(envptr + i); + pos++; + i++; + } // ENDWHILE- copying home directory info in + + if(confdirname[pos-1] != '/') { + confdirname[pos] = '/'; + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultdirectory[i] != 0)) { + confdirname[pos] = defaultdirectory[i]; + conffilename[pos] = defaultdirectory[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + } // ENDIF- No Home directory? + + confdirname[pos] = 0; // Directory reference finished + + // += / + if(conffilename[pos-1] != '/') { + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultfile[i] != 0)) { + conffilename[pos] = defaultfile[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + conffilename[pos] = 0; // File reference finished + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: Directory: %s\n", confdirname); + PrintLog("CDVD config: File: %s\n", conffilename); +#endif /* VERBOSE_FUNCTION_CONF */ +} // END InitConf() + + +void LoadConf() { + int retval; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: LoadConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); + if(retval < 0) { + sprintf(conf.isoname, "[Put an Image Name here]"); + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + if(retval < 0) { + sprintf(conf.devicename, "/dev/dvd"); + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); + if(retval < 0) { + conf.startconfigure = 0; // False + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); + if(retval < 0) { + conf.restartconfigure = 1; // True + } // ENDIF- Couldn't find keyword? Fill in a default +} // END LoadConf() + + +void SaveConf() { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: SaveConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + mkdir(confdirname, 0755); + + INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); + INISaveString(conffilename, "Settings", "Device", conf.devicename); + INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); + INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); +} // END SaveConf() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/conf.h b/plugins/cdvd/CDVDisoEFP/src/Linux/conf.h new file mode 100644 index 0000000000..42bb401da6 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/conf.h @@ -0,0 +1,54 @@ +/* conf.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef CONF_H +#define CONF_H + + +#define CDVDdefs +#include "../PS2Edefs.h" + + +#define VERBOSE_FUNCTION_CONF + + +// Configuration Data + +typedef struct { + u8 isoname[256]; + u8 devicename[256]; + unsigned int startconfigure; + unsigned int restartconfigure; +} CDVDconf; +extern CDVDconf conf; + +#define DEFAULT_DEVICE "K:\\" + + +// Configuration Functions + +extern void InitConf(); +extern void LoadConf(); +extern void SaveConf(); + +extern void ExecCfg(char *arg); + + +#endif /* CONF_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.c new file mode 100644 index 0000000000..7bd5501c64 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.c @@ -0,0 +1,388 @@ +/* conversionbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcpy() +#include // off64_t + +#include // gtk_button_new_with_label() +#include // gtk_combo_box_new() +#include // gtk_check_button_new() +#include // gtk_container_add() +#include // gtk_entry_new() +#include // gtk_file_selection_set_filename() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_hseparator_new() +#include // gtk_label_new() +#include // gtk_main_iteration() +#include // gtk_toggle_button_get_active() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +#include "imagetype.h" // imagedata[] +#include "multifile.h" // multinames[] +#include "toc.h" +#include "progressbox.h" +#include "messagebox.h" +#include "selectionbox.h" +#include "mainbox.h" +#include "conversionbox.h" + + +struct ConversionBoxData conversionbox; + + +void ConversionBoxDestroy() { + if(conversionbox.window != NULL) { + gtk_widget_destroy(conversionbox.window); + conversionbox.window = NULL; + conversionbox.file = NULL; + conversionbox.selectbutton = NULL; + conversionbox.filedesc = NULL; + conversionbox.compress = NULL; + conversionbox.multi = NULL; + conversionbox.okbutton = NULL; + conversionbox.cancelbutton = NULL; + } // ENDIF- Do we have a Main Window still? +} // END ConversionBoxDestroy() + + +void ConversionBoxUnfocus() { + gtk_widget_set_sensitive(conversionbox.file, FALSE); + gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); + gtk_widget_set_sensitive(conversionbox.compress, FALSE); + gtk_widget_set_sensitive(conversionbox.multi, FALSE); + gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); + gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); + // gtk_window_iconify(GTK_WINDOW(conversionbox.window)); + gtk_widget_hide(conversionbox.window); +} // END ConversionBoxUnfocus() + + +gint ConversionBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), "File Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + "File Type: Not a file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -3) { + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + "File Type: Not a valid image file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -4) { + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + "File Type: Missing Table File (will rebuild)"); + return(TRUE); + } // ENDIF- Not a regular file? + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), templine); + tempfile = IsoFileClose(tempfile); + return(TRUE); +} // END ConversionBoxFileEvent() + + +void ConversionBoxRefocus() { + GdkEvent event; + + ConversionBoxFileEvent(NULL, event, NULL); + + gtk_widget_set_sensitive(conversionbox.file, TRUE); + gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); + gtk_widget_set_sensitive(conversionbox.compress, TRUE); + gtk_widget_set_sensitive(conversionbox.multi, TRUE); + gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); + gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); + gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + gtk_widget_show_all(conversionbox.window); + gtk_window_deiconify(GTK_WINDOW(conversionbox.window)); +} // END ConversionBoxRefocus() + + +gint ConversionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + gtk_widget_hide(conversionbox.window); + MainBoxRefocus(); + return(TRUE); +} // END ConversionBoxCancelEvent() + + +gint ConversionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + char templine[256]; + char tempblock[2352]; + const char *filename; + int compressmethod; + int multi; + struct IsoFile *fromfile; + struct IsoFile *tofile; + int i; + off64_t endsector; + int stop; + int retval; + + ConversionBoxUnfocus(); + + filename = gtk_entry_get_text(GTK_ENTRY(conversionbox.file)); + if(IsIsoFile(filename) < 0) { + filename = NULL; + MessageBoxShow("Not a valid file", 3); + return(TRUE); + } // ENDIF- Not an Iso File? Stop early. + + compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(conversionbox.compress)); + if(compressmethod > 0) compressmethod += 2; + multi = 0; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(conversionbox.multi)) == TRUE) + multi = 1; + + fromfile = NULL; + fromfile = IsoFileOpenForRead(filename); + if(fromfile == NULL) { + filename = NULL; + MessageBoxShow("Cannot opening the source file", 3); + return(TRUE); + } // ENDIF- Not an Iso File? Stop early. + + if((compressmethod == fromfile->compress) && + (multi == fromfile->multi)) { + fromfile = IsoFileClose(fromfile); + filename = NULL; + MessageBoxShow("Compress/Multifile methods match - no need to convert", 3); + return(TRUE); + } // ENDIF- Not an Iso File? Stop early. + + tofile = IsoFileOpenForWrite(filename, + GetImageTypeConvertTo(fromfile->imagetype), + multi, + compressmethod); + if(tofile == NULL) { + fromfile = IsoFileClose(fromfile); + filename = NULL; + MessageBoxShow("Cannot create the new file", 3); + return(TRUE); + } // ENDIF- Not an Iso File? Stop early. + + if(fromfile->multi == 1) { + i = 0; + while((i < 10) && + (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; + endsector = fromfile->multisectorend[fromfile->multiend]; + } else { + endsector = fromfile->filesectorsize; + } // ENDIF- Get ending sector from multifile? (Or single file?) + IsoFileSeek(fromfile, 0); + + // Open Progress Bar + sprintf(templine, "%s: %s%s -> %s%s", + filename, + multinames[fromfile->multi], + compressdesc[fromfile->compress], + multinames[tofile->multi], + compressdesc[tofile->compress]); + ProgressBoxStart(templine, endsector); + + tofile->cdvdtype = fromfile->cdvdtype; + for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; + + stop = 0; + mainbox.stop = 0; + progressbox.stop = 0; + while((stop == 0) && (tofile->sectorpos < endsector)) { + retval = IsoFileRead(fromfile, tempblock); + if(retval < 0) { + MessageBoxShow("Trouble reading source file", 3); + stop = 1; + } else { + retval = IsoFileWrite(tofile, tempblock); + if(retval < 0) { + MessageBoxShow("Trouble writing new file", 3); + stop = 1; + } // ENDIF- Trouble writing out the next block? + } // ENDIF- Trouble reading in the next block? + + ProgressBoxTick(tofile->sectorpos); + while(gtk_events_pending()) gtk_main_iteration(); + + if(mainbox.stop != 0) stop = 2; + if(progressbox.stop != 0) stop = 2; + } // ENDWHILE- Not stopped for some reason... + + ProgressBoxStop(); + + if(stop == 0) { + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + strcpy(templine, tofile->name); + + // fromfile = IsoFileCloseAndDelete(fromfile); + fromfile = IsoFileClose(fromfile); + + IsoSaveTOC(tofile); + tofile = IsoFileClose(tofile); + gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); + + } else { + fromfile = IsoFileClose(fromfile); + tofile = IsoFileCloseAndDelete(tofile); + } // ENDIF- Did we succeed in the transfer? + + if(stop != 1) ConversionBoxRefocus(); + if(stop == 0) ConversionBoxCancelEvent(widget, event, data); + return(TRUE); +} // END ConversionBoxOKEvent() + + +gint ConversionBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + ConversionBoxUnfocus(); + + // Transfer file name to file selection + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + selectionbox.wherefrom = 3; // From the Conversion Window + SelectionBoxRefocus(); + return(TRUE); +} // END ConversionBoxBrowseEvent() + + +void ConversionBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + int nameptr; + + conversionbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(conversionbox.window), 5); + gtk_window_set_title(GTK_WINDOW(conversionbox.window), "CDVDisoEFP File Conversion"); + gtk_window_set_position(GTK_WINDOW(conversionbox.window), GTK_WIN_POS_CENTER); + + g_signal_connect(G_OBJECT(conversionbox.window), "delete_event", + G_CALLBACK(ConversionBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(conversionbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Iso File:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + conversionbox.file = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.file, TRUE, TRUE, 0); + gtk_widget_show(conversionbox.file); + g_signal_connect(G_OBJECT(conversionbox.file), "changed", + G_CALLBACK(ConversionBoxFileEvent), NULL); + + conversionbox.selectbutton = gtk_button_new_with_label("Browse"); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.selectbutton, FALSE, FALSE, 0); + gtk_widget_show(conversionbox.selectbutton); + g_signal_connect(G_OBJECT(conversionbox.selectbutton), "clicked", + G_CALLBACK(ConversionBoxBrowseEvent), NULL); + hbox1 = NULL; + + conversionbox.filedesc = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), conversionbox.filedesc, FALSE, FALSE, 0); + gtk_widget_show(conversionbox.filedesc); + // ConversionBoxFileEvent(NULL, 0, NULL); // Work out compromise later... + + item = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + item = NULL; + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Change Compression To:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + conversionbox.compress = gtk_combo_box_new_text(); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.compress, FALSE, FALSE, 0); + nameptr = 0; + while(compressnames[nameptr] != NULL) { + gtk_combo_box_append_text(GTK_COMBO_BOX(conversionbox.compress), + compressnames[nameptr]); + nameptr++; + } // ENDWHILE- loading compression types into combo box + gtk_combo_box_set_active(GTK_COMBO_BOX(conversionbox.compress), 0); // Temp Line + gtk_widget_show(conversionbox.compress); + hbox1 = NULL; + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Multiple Files (all under 2 GB):"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + conversionbox.multi = gtk_check_button_new(); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.multi, FALSE, FALSE, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(conversionbox.multi), FALSE); + gtk_widget_show(conversionbox.multi); + hbox1 = NULL; + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + conversionbox.okbutton = gtk_button_new_with_label("Change File"); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.okbutton, TRUE, TRUE, 0); + gtk_widget_show(conversionbox.okbutton); + g_signal_connect(G_OBJECT(conversionbox.okbutton), "clicked", + G_CALLBACK(ConversionBoxOKEvent), NULL); + + conversionbox.cancelbutton = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.cancelbutton, TRUE, TRUE, 0); + gtk_widget_show(conversionbox.cancelbutton); + g_signal_connect(G_OBJECT(conversionbox.cancelbutton), "clicked", + G_CALLBACK(ConversionBoxCancelEvent), NULL); + hbox1 = NULL; + vbox1 = NULL; +} // END ConversionBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.glade new file mode 100644 index 0000000000..d51c5d3004 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.glade @@ -0,0 +1,272 @@ + + + + + + + + 5 + True + CDVDiso File Conversion + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + False + 0 + + + + True + Iso File: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + + True + True + Browse + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + File Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Change Compression To: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + None +GZip (for speed) +BZip2 (for speed) +BZip2 (for size) + + + + 5 + True + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Multiple Files (all under 2 GB): + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Change File + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.h new file mode 100644 index 0000000000..d583837943 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/conversionbox.h @@ -0,0 +1,47 @@ +/* conversionbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CONVERSIONBOX_H +#define CONVERSIONBOX_H + + +#include + + +struct ConversionBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *file; // GtkEntry + GtkWidget *selectbutton; // GtkButton + GtkWidget *filedesc; // GtkLabel + GtkWidget *compress; // GtkComboBox + GtkWidget *multi; // GtkCheckButton + GtkWidget *okbutton; // GtkButton + GtkWidget *cancelbutton; // GtkButton +}; + +extern struct ConversionBoxData conversionbox; + +extern void ConversionBoxDestroy(); +extern void ConversionBoxRefocus(); +extern void ConversionBoxDisplay(); + + +#endif /* CONVERSIONBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/device.c b/plugins/cdvd/CDVDisoEFP/src/Linux/device.c new file mode 100644 index 0000000000..51efeea883 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/device.c @@ -0,0 +1,418 @@ +/* device.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // open() +#include // NULL +#include // getenv() +#include // strerror() +#include // ioctl() +#include // open() +#include // open() +#include // time_t, time(), struct timeval +#include // close(), select() + +#include // CD/DVD based ioctl() and defines. + +#include "logfile.h" +#include "conf.h" +#include "CD.h" +#include "DVD.h" +#include "device.h" + + +// Globals + +int devicehandle; // File Handle for the device/drive +s32 devicecapability; // Capability Flags +time_t lasttime; // Time marker (in case something gets called too often) +s32 traystatus; // Is the CD/DVD tray open? + +s32 disctype; // Type of disc in drive (Video DVD, PSX CD, etc.) +u8 tocbuffer[2048]; + + +void DeviceInit() { + devicehandle = -1; + devicecapability = 0; + lasttime = time(NULL); + + InitDisc(); +} // END DeviceInit() + + +// Called by DeviceOpen(), DeviceGetDiskType() +void InitDisc() { + int i; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: InitDisc()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if((disctype == CDVD_TYPE_PS2DVD) || + (disctype == CDVD_TYPE_DVDV)) { + InitDVDInfo(); + } // ENDIF- Clean out DVD Disc Info? + + if((disctype == CDVD_TYPE_PS2CD) || + (disctype == CDVD_TYPE_PS2CDDA) || + (disctype == CDVD_TYPE_PSCD) || + (disctype == CDVD_TYPE_PSCDDA) || + (disctype == CDVD_TYPE_CDDA)) { + InitCDInfo(); + } // ENDIF- Clean out DVD Disc Info? + + disctype = CDVD_TYPE_NODISC; + for(i = 0; i > sizeof(tocbuffer); i++) tocbuffer[i] = 0x00; +} // END InitDisc() + + +s32 DiscInserted() { + if(devicehandle == -1) return(-1); + if(traystatus == CDVD_TRAY_OPEN) return(-1); + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + if(disctype == CDVD_TYPE_DETCT) return(-1); + if(disctype == CDVD_TYPE_NODISC) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DiscInserted()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + return(0); +} // END DiscInserted() + + +// Called by DeviceTrayStatus() and CDVDopen() +s32 DeviceOpen() { + // s32 s32result; + + errno = 0; + + if(devicehandle != -1) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVD device: Device already open!"); +#endif /* VERBOSE_WARNING_DEVICE */ + return(0); + } // ENDIF- Is the CD/DVD already in use? That's fine. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + // InitConf(); + // LoadConf(); // Should be done once before making this call + + devicehandle = open(conf.devicename, O_RDONLY | O_NONBLOCK); + if(devicehandle == -1) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Error opening device: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Failed to open device? Abort + + // Note: Hmm. Need a minimum capability in case this fails? + devicecapability = ioctl(devicehandle, CDROM_GET_CAPABILITY); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Error getting device capabilities: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + close(devicehandle); + devicehandle = -1; + devicecapability = 0; + return(-1); + } // ENDIF- Can't read drive capabilities? Close and Abort. + +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD device: Device Type(s)"); + if(devicecapability < CDC_CD_R) PrintLog("CDVD device: CD"); + if(devicecapability & CDC_CD_R) PrintLog("CDVD device: CD-R"); + if(devicecapability & CDC_CD_RW) PrintLog("CDVD device: CD-RW"); + if(devicecapability & CDC_DVD) PrintLog("CDVD device: DVD"); + if(devicecapability & CDC_DVD_R) PrintLog("CDVD device: DVD-R"); + if(devicecapability & CDC_DVD_RAM) PrintLog("CDVD device: DVD-RAM"); +#endif /* VERBOSE_DISC_TYPE */ +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD device: Device Capabilities:"); + if(devicecapability & CDC_CLOSE_TRAY) PrintLog("CDVD device: Can close a tray"); + if(devicecapability & CDC_OPEN_TRAY) PrintLog("CDVD device: Can open a tray"); + // if(devicecapability & CDC_LOCK) PrintLog("CDVD device: Can lock the drive door"); + if(devicecapability & CDC_SELECT_SPEED) PrintLog("CDVD device: Can change spin speed"); + // if(devicecapability & CDC_SELECT_DISC) PrintLog("CDVD device: Can change disks (multi-disk tray)"); + // if(devicecapability & CDC_MULTI_SESSION) PrintLog("CDVD device: Can read multi-session disks"); + // if(devicecapability & CDC_MCN) PrintLog("CDVD device: Can read Medium Catalog Numbers (maybe)"); + if(devicecapability & CDC_MEDIA_CHANGED) PrintLog("CDVD device: Can tell if the disc was changed"); + if(devicecapability & CDC_PLAY_AUDIO) PrintLog("CDVD device: Can play audio disks"); + // if(devicecapability & CDC_RESET) PrintLog("CDVD device: Can reset the device"); + //if(devicecapability & CDC_IOCTLS) PrintLog("CDVD device: Odd IOCTLs. Not sure of compatability"); + if(devicecapability & CDC_DRIVE_STATUS) PrintLog("CDVD device: Can monitor the drive tray"); + +#endif /* VERBOSE_DISC_INFO */ + + ////// Should be called after an open (instead of inside of one) + // InitDisc(); + // traystatus = CDVD_TRAY_OPEN; // Start with Tray Open + // DeviceTrayStatus(); // Now find out for sure. + + return(0); // Device opened and ready for use. +} // END DeviceOpen() + + +// Called by DeviceTrayStatus(), CDVDclose(), and CDVDshutdown() +void DeviceClose() { + // s32 s32result; + int zerospeed; + + zerospeed = 0; + + if(devicehandle == -1) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: Device already closed"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + return; + } // ENDIF- Device already closed? Ok. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + InitDisc(); + close(devicehandle); + devicehandle = -1; + devicecapability = 0; + return; +} // END CDVDclose() + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceReadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(DiscInserted() == -1) return(-1); + + // Get that data + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + s32result = DVDreadTrack(lsn, mode, buffer); + } else { + s32result = CDreadTrack(lsn, mode, buffer); + } //ENDIF- Read a DVD sector or a CD sector? + + return(s32result); +} // END DeviceReadTrack() + + +s32 DeviceBufferOffset() { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceBufferOffset()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(0); + } else { + return(CDgetBufferOffset()); + } // ENDIF- Is this a DVD? +} // END DeviceBufferOffset() + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(track, cdvdtd)); + } else { + return(CDgetTD(track, cdvdtd)); + } // ENDIF- Is this a DVD? +} // END DeviceGetTD() + + +// Called by DeviceTrayStatus() +s32 DeviceGetDiskType() { + s32 s32result; + s32 ioctldisktype; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if(traystatus == CDVD_TRAY_OPEN) { + return(disctype); + } // ENDIF- Is the device tray open? No disc to check yet. + + if(disctype != CDVD_TYPE_NODISC) { + return(disctype); + } // ENDIF- Already checked? Drive still closed? Disc hasn't changed. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceGetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + disctype = CDVD_TYPE_DETCT; + + ioctldisktype = ioctl(devicehandle, CDROM_DISC_STATUS); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble reading Disc Type!"); + PrintLog("CDVD device: Error: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + disctype = CDVD_TYPE_UNKNOWN; + return(disctype); + } // ENDIF- Trouble probing for a disc? + + s32result = DVDgetDiskType(ioctldisktype); + if(s32result != -1) { + return(disctype); + } // ENDIF- Did we find a disc type? + + s32result = CDgetDiskType(ioctldisktype); + if(s32result != -1) { + return(disctype); + } // ENDIF- Did we find a disc type? + + disctype = CDVD_TYPE_UNKNOWN; // Not a CD? Not a DVD? Is is peanut butter? + return(disctype); +} // END CDVDgetDiskType() + + +// Called by PollLoop() and CDVDgetTrayStatus() +s32 DeviceTrayStatus() { + s32 s32result; + + errno = 0; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayStatus()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_DRIVE_STATUS) != 0) { + s32result = ioctl(devicehandle, CDROM_DRIVE_STATUS); + if(s32result < 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble reading Drive Status!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + s32result = CDS_TRAY_OPEN; + } // ENDIF- Failure to get status? Assume it's open. + errno = 0; + + } else { + s32result = ioctl(devicehandle, CDROM_DISC_STATUS); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble detecting Disc Status presense!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + s32result = CDS_TRAY_OPEN; + errno = 0; + } // ENDIF- Trouble? + if(s32result == CDS_NO_DISC) { + s32result = CDS_TRAY_OPEN; + } // ENDIF- Is there no disc in the device? Guess the tray is open + } // ENDIF- Can we poll the tray directly? (Or look at disc status instead?) + + if(s32result == CDS_TRAY_OPEN) { + traystatus = CDVD_TRAY_OPEN; + if(disctype != CDVD_TYPE_NODISC) { + DeviceClose(); // Kind of severe way of flushing all buffers. + DeviceOpen(); + InitDisc(); + } // ENDIF- Tray just opened... clear disc info + } else { + traystatus = CDVD_TRAY_CLOSE; + if(disctype == CDVD_TYPE_NODISC) { + DeviceGetDiskType(); + } // ENDIF- Tray just closed? Get disc information + } // ENDIF- Do we detect an open tray? + return(traystatus); +} // END CDVD_getTrayStatus() + + +s32 DeviceTrayOpen() { + s32 s32result; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_OPEN_TRAY) == 0) { + return(-1); + } // ENDIF- Don't have open capability? Error out. + + // Tray already open? Exit. + if(traystatus == CDVD_TRAY_OPEN) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + s32result = ioctl(devicehandle, CDROMEJECT); +#ifdef VERBOSE_WARNINGS + if((s32result != 0) || (errno != 0)) { + PrintLog("CDVD device: Could not open the tray!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); + } // ENDIF- Trouble? +#endif /* VERBOSE_WARNINGS */ + return(s32result); +} // END DeviceTrayOpen() + + +s32 DeviceTrayClose() { + s32 s32result; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_CLOSE_TRAY) == 0) { + return(-1); + } // ENDIF- Don't have close capability? Error out. + + // Tray already closed? Exit. + if(traystatus == CDVD_TRAY_CLOSE) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + s32result = ioctl(devicehandle, CDROMCLOSETRAY); +#ifdef VERBOSE_WARNINGS + if((s32result != 0) || (errno != 0)) { + PrintLog("CDVD device: Could not close the tray!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); + } // ENDIF- Trouble? +#endif /* VERBOSE_WARNINGS */ + return(s32result); +} // END DeviceTrayClose() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/device.h b/plugins/cdvd/CDVDisoEFP/src/Linux/device.h new file mode 100644 index 0000000000..0d0d8ffe49 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/device.h @@ -0,0 +1,69 @@ +/* device.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + + +#include // time_t + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ +#define CDVDdefs +#include "../PS2Edefs.h" + + +// #define VERBOSE_FUNCTION_DEVICE +// #define VERBOSE_WARNINGS +#define VERBOSE_DISC_TYPE +#define VERBOSE_DISC_INFO + + +// Device Data + +extern int devicehandle; +extern s32 devicecapability; // Need to export? + +extern time_t lasttime; +extern s32 traystatus; +extern s32 disctype; +extern u8 tocbuffer[]; + + +// Device Functions + +extern void DeviceInit(); +extern void InitDisc(); +extern s32 DiscInserted(); +extern s32 DeviceOpen(); +extern void DeviceClose(); +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DeviceBufferOffset(); +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); +extern s32 DeviceGetDiskType(); +extern s32 DeviceTrayStatus(); +extern s32 DeviceTrayOpen(); +extern s32 DeviceTrayClose(); + + +#endif /* __DEVICE_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.c new file mode 100644 index 0000000000..ff0f56679e --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.c @@ -0,0 +1,443 @@ +/* devicebox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcpy() +#include // stat() +#include // stat() +#include // stat() + +#include // gtk_button_new_with_label() +#include // gtk_combo_box_new() +#include // gtk_check_button_new() +#include // gtk_container_add() +#include // gtk_entry_new() +#include // gtk_file_selection_set_filename() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_hseparator_new() +#include // gtk_label_new() +#include // gtk_main_iteration() +#include // gtk_toggle_button_get_active() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ +#define CDVDdefs +#include "PS2Edefs.h" + +#include "conf.h" +#include "device.h" +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +// #include "imagetype.h" // imagedata[].name +#include "multifile.h" // multinames[] +#include "toc.h" +#include "progressbox.h" +#include "messagebox.h" +#include "selectionbox.h" +#include "mainbox.h" +#include "devicebox.h" + + +struct DeviceBoxData devicebox; + + +void DeviceBoxDestroy() { + if(devicebox.window != NULL) { + gtk_widget_destroy(devicebox.window); + devicebox.window = NULL; + devicebox.device = NULL; + devicebox.devicedesc = NULL; + devicebox.file = NULL; + devicebox.selectbutton = NULL; + devicebox.filedesc = NULL; + devicebox.compress = NULL; + devicebox.multi = NULL; + devicebox.okbutton = NULL; + devicebox.cancelbutton = NULL; + } // ENDIF- Do we have a Main Window still? +} // END DeviceBoxDestroy() + + +void DeviceBoxUnfocus() { + gtk_widget_set_sensitive(devicebox.device, FALSE); + gtk_widget_set_sensitive(devicebox.file, FALSE); + gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); + gtk_widget_set_sensitive(devicebox.compress, FALSE); + gtk_widget_set_sensitive(devicebox.multi, FALSE); + gtk_widget_set_sensitive(devicebox.okbutton, FALSE); + gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); + gtk_widget_hide(devicebox.window); + // gtk_window_iconify(GTK_WINDOW(devicebox.window)); +} // END DeviceBoxUnfocus() + + +gint DeviceBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + struct stat filestat; + int returnval; + + returnval = stat(gtk_entry_get_text(GTK_ENTRY(devicebox.device)), &filestat); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(S_ISDIR(filestat.st_mode) != 0) { + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Not a device"); + return(TRUE); + } // ENDIF- Not a regular file? + + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Device Likely"); + return(TRUE); +} // END DeviceBoxDeviceEvent() + + +gint DeviceBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -3) { + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a valid image file"); + return(TRUE); + } // ENDIF- Not an image file? + + if(returnval == -4) { + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Missing Table File (will rebuild)"); + return(TRUE); + } // ENDIF- Not a regular file? + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), templine); + tempfile = IsoFileClose(tempfile); + return(TRUE); +} // END DeviceBoxFileEvent() + + +void DeviceBoxRefocus() { + GdkEvent event; + + DeviceBoxDeviceEvent(NULL, event, NULL); + DeviceBoxFileEvent(NULL, event, NULL); + + gtk_widget_set_sensitive(devicebox.device, TRUE); + gtk_widget_set_sensitive(devicebox.file, TRUE); + gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); + gtk_widget_set_sensitive(devicebox.compress, TRUE); + gtk_widget_set_sensitive(devicebox.multi, TRUE); + gtk_widget_set_sensitive(devicebox.okbutton, TRUE); + gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); + gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + gtk_widget_show_all(devicebox.window); + gtk_window_deiconify(GTK_WINDOW(devicebox.window)); +} // END DeviceBoxRefocus() + + +gint DeviceBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + gtk_widget_hide(devicebox.window); + MainBoxRefocus(); + return(TRUE); +} // END DeviceBoxCancelEvent() + + +gint DeviceBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + char templine[256]; + u8 tempbuffer[2352]; + struct IsoFile *tofile; + const char *tempdevice; + s32 retval; + cdvdTD cdvdtd; + int stop; + int compressmethod; + int multi; + int imagetype; + int i; + + DeviceBoxUnfocus(); + + tempdevice = gtk_entry_get_text(GTK_ENTRY(devicebox.device)); + strcpy(conf.devicename, tempdevice); // Temporarily put in new device name + tempdevice = NULL; + retval = DeviceOpen(); + if(retval != 0) { + DeviceClose(); + MessageBoxShow("Could not open the device", 2); + return(TRUE); + } // ENDIF- Trouble opening device? Abort here. + + DeviceTrayStatus(); + retval = DiscInserted(); + if(retval != 0) { + DeviceClose(); + MessageBoxShow("No disc in the device\r\nPlease put a disc in and try again.", 2); + return(TRUE); + } // ENDIF- Trouble opening device? Abort here. + + retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector + if(retval < 0) { + DeviceClose(); + MessageBoxShow("Could not retrieve disc sector size", 2); + return(TRUE); + } // ENDIF- Trouble getting disc sector count? + + compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(devicebox.compress)); + if(compressmethod > 0) compressmethod += 2; + multi = 0; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(devicebox.multi)) == TRUE) + multi = 1; + + imagetype = 0; + if((disctype != CDVD_TYPE_PS2DVD) && + (disctype != CDVD_TYPE_DVDV)) imagetype = 8; + + tofile = IsoFileOpenForWrite(gtk_entry_get_text(GTK_ENTRY(devicebox.file)), + imagetype, + multi, + compressmethod); + if(tofile == NULL) { + DeviceClose(); + MessageBoxShow("Could not create the new ISO file", 2); + return(TRUE); + } // ENDIF- Trouble opening the ISO file? + + // Open Progress Bar + sprintf(templine, "%s -> %s", + gtk_entry_get_text(GTK_ENTRY(devicebox.device)), tofile->name); + ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); + + tofile->cdvdtype = disctype; + for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; + + stop = 0; + mainbox.stop = 0; + progressbox.stop = 0; + while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { + if(imagetype == 0) { + retval = DeviceReadTrack((u32) tofile->sectorpos, + CDVD_MODE_2048, + tempbuffer); + } else { + retval = DeviceReadTrack((u32) tofile->sectorpos, + CDVD_MODE_2352, + tempbuffer); + } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) + if(retval < 0) { + for(i = 0; i < 2352; i++) { + tempbuffer[i] = 0; + } // NEXT i- Zeroing the buffer + } // ENDIF- Trouble reading next block? + retval = IsoFileWrite(tofile, tempbuffer); + if(retval < 0) { + MessageBoxShow("Trouble writing new file", 3); + stop = 1; + } // ENDIF- Trouble writing out the next block? + + ProgressBoxTick(tofile->sectorpos); + while(gtk_events_pending()) gtk_main_iteration(); + + if(mainbox.stop != 0) stop = 2; + if(progressbox.stop != 0) stop = 2; + } // ENDWHILE- No reason found to stop... + + ProgressBoxStop(); + + if(stop == 0) { + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + strcpy(templine, tofile->name); + } // ENDIF- Did we succeed with the transfer? + + DeviceClose(); + if(stop == 0) { + IsoSaveTOC(tofile); + tofile = IsoFileClose(tofile); + gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); + } else { + tofile = IsoFileCloseAndDelete(tofile); + } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) + + if(stop != 1) DeviceBoxRefocus(); + if(stop == 0) DeviceBoxCancelEvent(widget, event, data); + return(TRUE); +} // END DeviceBoxOKEvent() + + +gint DeviceBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + DeviceBoxUnfocus(); + + // Transfer file name to file selection + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + selectionbox.wherefrom = 2; // From the Device Window + SelectionBoxRefocus(); + return(TRUE); +} // END DeviceBoxBrowseEvent() + + +void DeviceBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + int nameptr; + + devicebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(devicebox.window), 5); + gtk_window_set_title(GTK_WINDOW(devicebox.window), "CDVDisoEFP ISO Creation"); + gtk_window_set_position(GTK_WINDOW(devicebox.window), GTK_WIN_POS_CENTER); + + g_signal_connect(G_OBJECT(devicebox.window), "delete_event", + G_CALLBACK(DeviceBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(devicebox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Source CD/DVD Device:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + devicebox.device = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.device, TRUE, TRUE, 0); + gtk_widget_show(devicebox.device); + g_signal_connect(G_OBJECT(devicebox.device), "changed", + G_CALLBACK(DeviceBoxDeviceEvent), NULL); + hbox1 = NULL; + + devicebox.devicedesc = gtk_label_new("Device Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), devicebox.devicedesc, FALSE, FALSE, 0); + gtk_widget_show(devicebox.devicedesc); + + item = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + item = NULL; + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Iso File:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + devicebox.file = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.file, TRUE, TRUE, 0); + gtk_widget_show(devicebox.file); + g_signal_connect(G_OBJECT(devicebox.file), "changed", + G_CALLBACK(DeviceBoxFileEvent), NULL); + + devicebox.selectbutton = gtk_button_new_with_label("Browse"); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.selectbutton, FALSE, FALSE, 0); + gtk_widget_show(devicebox.selectbutton); + g_signal_connect(G_OBJECT(devicebox.selectbutton), "clicked", + G_CALLBACK(DeviceBoxBrowseEvent), NULL); + hbox1 = NULL; + + devicebox.filedesc = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), devicebox.filedesc, FALSE, FALSE, 0); + gtk_widget_show(devicebox.filedesc); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("New File Compression:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + devicebox.compress = gtk_combo_box_new_text(); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.compress, FALSE, FALSE, 0); + nameptr = 0; + while(compressnames[nameptr] != NULL) { + gtk_combo_box_append_text(GTK_COMBO_BOX(devicebox.compress), + compressnames[nameptr]); + nameptr++; + } // ENDWHILE- loading compression types into combo box + gtk_combo_box_set_active(GTK_COMBO_BOX(devicebox.compress), 0); // Temp Line + gtk_widget_show(devicebox.compress); + hbox1 = NULL; + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Multiple Files (all under 2 GB):"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + devicebox.multi = gtk_check_button_new(); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.multi, FALSE, FALSE, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(devicebox.multi), FALSE); + gtk_widget_show(devicebox.multi); + hbox1 = NULL; + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + devicebox.okbutton = gtk_button_new_with_label("Make File"); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.okbutton, TRUE, TRUE, 0); + gtk_widget_show(devicebox.okbutton); + g_signal_connect(G_OBJECT(devicebox.okbutton), "clicked", + G_CALLBACK(DeviceBoxOKEvent), NULL); + + devicebox.cancelbutton = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.cancelbutton, TRUE, TRUE, 0); + gtk_widget_show(devicebox.cancelbutton); + g_signal_connect(G_OBJECT(devicebox.cancelbutton), "clicked", + G_CALLBACK(DeviceBoxCancelEvent), NULL); + hbox1 = NULL; + vbox1 = NULL; + + // Device text not set until now to get the correct description. + gtk_entry_set_text(GTK_ENTRY(devicebox.device), conf.devicename); + + DeviceInit(); // Initialize device access +} // END DeviceBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.glade new file mode 100644 index 0000000000..168c5e5a33 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.glade @@ -0,0 +1,345 @@ + + + + + + + 5 + True + CDVDiso ISO Creation + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + False + 0 + + + + True + Source CD/DVD Device: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + /dev/dvd + True + * + False + + + 5 + True + True + + + + + 0 + True + True + + + + + + True + Device Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Iso File: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 5 + True + True + + + + + + True + True + Browse + True + GTK_RELIEF_NORMAL + True + + + 5 + False + False + + + + + 0 + True + True + + + + + + True + File Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + New File Compression: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + None +GZip (for speed) +BZip2 (for speed) +BZip2 (for size) + + + + 5 + True + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Multiple Files (all under 2GB): + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Make File + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.h new file mode 100644 index 0000000000..ecf748ad92 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/devicebox.h @@ -0,0 +1,50 @@ +/* devicebox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef DEVICEBOX_H +#define DEVICEBOX_H + + +#include + + +struct DeviceBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *device; // GtkEntry + GtkWidget *devicedesc; // GtkLabel + GtkWidget *file; // GtkEntry + GtkWidget *selectbutton; // GtkButton + GtkWidget *filedesc; // GtkLabel + GtkWidget *compress; // GtkComboBox + GtkWidget *multi; // GtkCheckButton + GtkWidget *okbutton; // GtkButton + GtkWidget *cancelbutton; // GtkButton +}; + +extern struct DeviceBoxData devicebox; + +extern void DeviceBoxDestroy(); +// extern void DeviceBoxUnfocus(); +extern void DeviceBoxRefocus(); +extern void DeviceBoxDisplay(); + + +#endif /* DEVICEBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/interface.c b/plugins/cdvd/CDVDisoEFP/src/Linux/interface.c new file mode 100644 index 0000000000..af63d8f450 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/interface.c @@ -0,0 +1,67 @@ +/* interface.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcmp() + +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_widget_show_all() + +#include "logfile.h" +#include "conf.h" +#include "aboutbox.h" +#include "mainbox.h" +#include "devicebox.h" +#include "selectionbox.h" +#include "progressbox.h" +#include "messagebox.h" +#include "conversionbox.h" +#include "interface.h" + + +int main(int argc, char *argv[]) { + if(argc != 2) return(1); + + gtk_init(NULL, NULL); + + if(!strcmp(argv[1], "about")) { + AboutBoxDisplay(); + return(0); + } else if (!strcmp(argv[1], "configure")) { + OpenLog(); + InitConf(); + LoadConf(); + MainBoxDisplay(); + DeviceBoxDisplay(); + ConversionBoxDisplay(); + ProgressBoxDisplay(); + MessageBoxDisplay(); + SelectionBoxDisplay(); + + gtk_widget_show_all(mainbox.window); + gtk_main(); + CloseLog(); + return(0); + } // ENDLONGIF- Which display would you like to see? + + return(1); // No Displays chosen? Abort! +} // END main() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/interface.h b/plugins/cdvd/CDVDisoEFP/src/Linux/interface.h new file mode 100644 index 0000000000..a23946f677 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/interface.h @@ -0,0 +1,29 @@ +/* interface.h + * Copyright (C) 2002-2004 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef INTERFACE_H +#define INTERFACE_H + + +// Place holder... for now + + +#endif /* INTERFACE_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.c b/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.c new file mode 100644 index 0000000000..27c6fe879b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.c @@ -0,0 +1,90 @@ +/* logfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // open +#include // vsprintf() +#include // va_start(), va_end(), vsprintf() +#include // mkdir(), open() +#include // mkdir(), open() +#include // close(), write(), unlink() + +#include "logfile.h" + + +int logfile; +char logfiletemp[2048]; + + +void InitLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + mkdir("./logs", 0755); + + unlink("./logs/CDVDlog.txt"); +#endif /* VERBOSE LOGFILE */ +} // END InitLog(); + + +int OpenLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + logfile = -1; + logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); + if(logfile == -1) return(-1); +#endif /* VERBOSE LOGFILE */ + + return(0); +} // END OpenLog(); + + +void CloseLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + if(logfile != -1) { + close(logfile); + logfile = -1; + } // ENDIF- Is the log file actually open? Close it. +#endif /* VERBOSE LOGFILE */ +} // END CloseLog() + + +void PrintLog(const char *fmt, ...) { + // Token comment line +#ifdef VERBOSE_LOGFILE + va_list list; + int len; + + if(logfile == -1) return; // Log file not open. + + va_start(list, fmt); + vsprintf(logfiletemp, fmt, list); + va_end(list); + + len = 0; + while((len < 2048) && (logfiletemp[len] != 0)) len++; + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + write(logfile, logfiletemp, len); + write(logfile, "\r\n", 2); // ... and write out your own. +#endif /* VERBOSE LOGFILE */ +} // END PrintLog() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.h b/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.h new file mode 100644 index 0000000000..8cee990080 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/logfile.h @@ -0,0 +1,35 @@ +/* logfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef LOGFILE_H +#define LOGFILE_H + + +#define VERBOSE_LOGFILE + + +extern void InitLog(); +extern int OpenLog(); +extern void CloseLog(); +extern void PrintLog(const char *format, ...); + + +#endif /* LOGFILE_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.c new file mode 100644 index 0000000000..d9989d5b1a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.c @@ -0,0 +1,324 @@ +/* mainbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcpy() + +#include // gtk_button_new_with_label() +#include // gtk_check_button_new_with_label() +#include // gtk_container_add() +#include // gtk_entry_new() +#include // gtk_file_selection_set_filename() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_toggle_button_set_active(), (_get_) +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "conf.h" +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +// #include "imagetype.h" // imagedata[].name +#include "multifile.h" // multinames[] +#include "tablerebuild.h" // IsoTableRebuild() +#include "devicebox.h" +#include "conversionbox.h" +#include "progressbox.h" +#include "messagebox.h" +#include "selectionbox.h" +#include "mainbox.h" + + +struct MainBoxData mainbox; + + +void MainBoxDestroy() { + if(mainbox.window != NULL) { + gtk_widget_destroy(mainbox.window); + mainbox.window = NULL; + mainbox.file = NULL; + mainbox.selectbutton = NULL; + mainbox.desc = NULL; + mainbox.startcheck = NULL; + mainbox.restartcheck = NULL; + mainbox.okbutton = NULL; + mainbox.devbutton = NULL; + mainbox.convbutton = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + gtk_widget_set_sensitive(mainbox.file, FALSE); + gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); + gtk_widget_set_sensitive(mainbox.startcheck, FALSE); + gtk_widget_set_sensitive(mainbox.restartcheck, FALSE); + gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + gtk_widget_set_sensitive(mainbox.devbutton, FALSE); + gtk_widget_set_sensitive(mainbox.convbutton, FALSE); + gtk_window_iconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxUnfocus() + + +gint MainBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + if(returnval == -1) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a file"); + return(TRUE); + } // ENDIF- Not a regular file? + + if(returnval == -3) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a valid image file"); + return(TRUE); + } // ENDIF- Not an Image file? + + if(returnval == -4) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Missing Table File (will rebuild)"); + return(TRUE); + } // ENDIF- Missing Compression seek table? + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + gtk_label_set_text(GTK_LABEL(mainbox.desc), templine); + tempfile = IsoFileClose(tempfile); + return(TRUE); +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + GdkEvent event; + + MainBoxFileEvent(NULL, event, NULL); + + gtk_widget_set_sensitive(mainbox.file, TRUE); + gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); + gtk_widget_set_sensitive(mainbox.startcheck, TRUE); + gtk_widget_set_sensitive(mainbox.restartcheck, TRUE); + gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + gtk_widget_set_sensitive(mainbox.devbutton, TRUE); + gtk_widget_set_sensitive(mainbox.convbutton, TRUE); + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxRefocus() + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + mainbox.stop = 1; // Halt all long processess... + + MessageBoxDestroy(); + SelectionBoxDestroy(); + ProgressBoxDestroy(); + ConversionBoxDestroy(); + DeviceBoxDestroy(); + MainBoxDestroy(); + + gtk_main_quit(); + return(TRUE); +} // END MainBoxCancelEvent() + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + const char *tempisoname; + + MainBoxUnfocus(); + + tempisoname = gtk_entry_get_text(GTK_ENTRY(mainbox.file)); + if(*(tempisoname) != 0) { + if(IsIsoFile(tempisoname) == -4) { + IsoTableRebuild(tempisoname); + MainBoxRefocus(); + return(TRUE); + } // ENDIF- Do we need to rebuild an image file's index before using it? + + if(IsIsoFile(tempisoname) < 0) { + tempisoname = NULL; + MainBoxRefocus(); + MessageBoxShow("Not a Valid Image File.", 1); + return(TRUE); + } // ENDIF- Not an ISO file? Message and Stop here. + } // ENDIF- Is there an ISO file to check out? + + strcpy(conf.isoname, tempisoname); + tempisoname = NULL; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.startcheck)) == FALSE) { + conf.startconfigure = 0; // FALSE + } else { + conf.startconfigure = 1; // TRUE + } // ENDIF- Was this check button turned off? + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck)) == FALSE) { + conf.restartconfigure = 0; // FALSE + } else { + conf.restartconfigure = 1; // TRUE + } // ENDIF- Was this check button turned off? + + SaveConf(); + + MainBoxCancelEvent(widget, event, data); + return(TRUE); +} // END MainBoxOKEvent() + + +gint MainBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + MainBoxUnfocus(); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + selectionbox.wherefrom = 1; // From the Main Window + SelectionBoxRefocus(); + return(TRUE); +} // END MainBoxBrowseEvent() + + +gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + MainBoxUnfocus(); + + gtk_entry_set_text(GTK_ENTRY(devicebox.file), + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + gtk_widget_show_all(devicebox.window); + return(TRUE); +} // END MainBoxBrowseEvent() + + +gint MainBoxConversionEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + MainBoxUnfocus(); + + gtk_entry_set_text(GTK_ENTRY(conversionbox.file), + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + gtk_widget_show_all(conversionbox.window); + return(TRUE); +} // END MainBoxBrowseEvent() + + +void MainBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Configuration"); + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + G_CALLBACK(MainBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("Iso File:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + mainbox.file = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file, TRUE, TRUE, 0); + gtk_widget_show(mainbox.file); + g_signal_connect(G_OBJECT(mainbox.file), "changed", + G_CALLBACK(MainBoxFileEvent), NULL); + + mainbox.selectbutton = gtk_button_new_with_label("Browse"); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.selectbutton, FALSE, FALSE, 0); + gtk_widget_show(mainbox.selectbutton); + g_signal_connect(G_OBJECT(mainbox.selectbutton), "clicked", + G_CALLBACK(MainBoxBrowseEvent), NULL); + hbox1 = NULL; + + mainbox.desc = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); + gtk_widget_show(mainbox.desc); + + // hbox1 = gtk_hbox_new(FALSE, 10); + // gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + // gtk_widget_show(hbox1); + + mainbox.startcheck = gtk_check_button_new_with_label("Show Configure screen when starting emulation"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.startcheck, FALSE, FALSE, 0); + gtk_widget_show(mainbox.startcheck); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), FALSE); + if(conf.startconfigure != 0) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), TRUE); + } // ENDIF- Is this box supposed to be checked? + + mainbox.restartcheck = gtk_check_button_new_with_label("Show Configure screen when restarting emulation"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.restartcheck, FALSE, FALSE, 0); + gtk_widget_show(mainbox.restartcheck); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), FALSE); + if(conf.restartconfigure != 0) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), TRUE); + } // ENDIF- Is this box supposed to be checked? + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + mainbox.okbutton = gtk_button_new_with_label("Ok"); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); + gtk_widget_show(mainbox.okbutton); + g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", + G_CALLBACK(MainBoxOKEvent), NULL); + + mainbox.devbutton = gtk_button_new_with_label("Get from Disc"); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.devbutton, TRUE, TRUE, 0); + gtk_widget_show(mainbox.devbutton); + g_signal_connect(G_OBJECT(mainbox.devbutton), "clicked", + G_CALLBACK(MainBoxDeviceEvent), NULL); + + mainbox.convbutton = gtk_button_new_with_label("Convert"); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.convbutton, TRUE, TRUE, 0); + gtk_widget_show(mainbox.convbutton); + g_signal_connect(G_OBJECT(mainbox.convbutton), "clicked", + G_CALLBACK(MainBoxConversionEvent), NULL); + + item = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(MainBoxCancelEvent), NULL); + item = NULL; + hbox1 = NULL; + vbox1 = NULL; + + // We held off setting the name until now... so description would show. + gtk_entry_set_text(GTK_ENTRY(mainbox.file), conf.isoname); +} // END MainBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.glade new file mode 100644 index 0000000000..a2329186e5 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.glade @@ -0,0 +1,219 @@ + + + + + + + 5 + True + CDVDiso Configuration + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + False + 0 + + + + True + Iso File: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 5 + True + True + + + + + + True + True + Browse + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + File Type: --- + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + Show Configure screen when starting emulation + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Show Configure screen when restarting emulation + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Get from Disc + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Convert + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.h new file mode 100644 index 0000000000..52f8403891 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/mainbox.h @@ -0,0 +1,50 @@ +/* mainbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef MAINBOX_H +#define MAINBOX_H + + +#include + + +struct MainBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *file; // GtkEntry + GtkWidget *selectbutton; // GtkButton + GtkWidget *desc; // GtkLabel + GtkWidget *startcheck; // GtkCheckBox + GtkWidget *restartcheck; // GtkCheckBox + GtkWidget *devbutton; // GtkButton + GtkWidget *convbutton; // GtkButton + GtkWidget *okbutton; // GtkButton + // Leaving the Cancel button unblocked... for emergency shutdown + + int stop; // Variable signal to stop long processes +}; + +extern struct MainBoxData mainbox; + +extern void MainBoxRefocus(); +extern void MainBoxDisplay(); + + +#endif /* MAINBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.c new file mode 100644 index 0000000000..845aba31e8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.c @@ -0,0 +1,113 @@ +/* messagebox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL + +#include // gtk_button_new_with_label() +#include // gtk_hbutton_box_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "mainbox.h" +#include "devicebox.h" +#include "conversionbox.h" +#include "messagebox.h" + + +struct MessageBoxData messagebox; + + +void MessageBoxDestroy() { + if(messagebox.window != NULL) { + gtk_widget_destroy(messagebox.window); + messagebox.window = NULL; + messagebox.desc = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MessageBoxDestroy() + + +void MessageBoxShow(char *message, int wherefrom) { + gtk_label_set_text(GTK_LABEL(messagebox.desc), message); + messagebox.wherefrom = wherefrom; + + gtk_widget_show_all(messagebox.window); + gtk_window_deiconify(GTK_WINDOW(messagebox.window)); +} // END MessageBox() + + +gint MessageBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + gtk_widget_hide(messagebox.window); + + switch(messagebox.wherefrom) { + case 1: + MainBoxRefocus(); + break; + case 2: + DeviceBoxRefocus(); + break; + case 3: + ConversionBoxRefocus(); + break; + } // ENDSWITCH- Whose window do I get to re-focus when this is done? + + return(TRUE); +} // END MessageBoxCancelEvent() + + +void MessageBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + + messagebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(messagebox.window), 5); + gtk_window_set_title(GTK_WINDOW(messagebox.window), "CDVDisoEFP"); + gtk_window_set_position(GTK_WINDOW(messagebox.window), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(messagebox.window), FALSE); + + g_signal_connect(G_OBJECT(messagebox.window), "delete_event", + G_CALLBACK(MessageBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(messagebox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + messagebox.desc = gtk_label_new("Hi There!\r\nHow are you doing?"); + gtk_box_pack_start(GTK_BOX(vbox1), messagebox.desc, FALSE, FALSE, 0); + gtk_widget_show(messagebox.desc); + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(MessageBoxCancelEvent), NULL); + item = NULL; + hbox1 = NULL; + vbox1 = NULL; +} // END MessageBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.glade new file mode 100644 index 0000000000..4529f9a406 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.glade @@ -0,0 +1,76 @@ + + + + + + + + True + CDVDiso + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + Hello there +How are you doing? + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + button1 + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.h new file mode 100644 index 0000000000..94ccb3ccc1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/messagebox.h @@ -0,0 +1,43 @@ +/* messagebox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef MESSAGEBOX_H +#define MESSAGEBOX_H + + +#include + + +struct MessageBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *desc; // GtkLabel + + int wherefrom; // Whom do I refocus when the message is read? +}; + +extern struct MessageBoxData messagebox; + +extern void MessageBoxDestroy(); +extern void MessageBoxShow(char *message, int wherefrom); +extern void MessageBoxDisplay(); + + +#endif /* MESSAGEBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.c new file mode 100644 index 0000000000..10fd1733b8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.c @@ -0,0 +1,144 @@ +/* progressbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // off64_t + +#include // gtk_button_new_with_label() +#include // gtk_container_add() +#include // gtk_file_selection_set_filename() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_label_new() +#include // gtk_main_iteration(), gtk_events_pending() +#include // gtk_progress_bar_new() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "progressbox.h" + + +struct ProgressBoxData progressbox; +char progressboxline[256]; + + +void ProgressBoxDestroy() { + if(progressbox.window != NULL) { + gtk_widget_destroy(progressbox.window); + progressbox.window = NULL; + progressbox.desc = NULL; + } // ENDIF- Do we have a Main Window still? +} // END ProgressBoxDestroy() + + +void ProgressBoxStart(char *description, off64_t maximum) { + gtk_label_set_text(GTK_LABEL(progressbox.desc), description); + + progressbox.max = maximum; + progressbox.gmax = maximum; + progressbox.lastpct = 100; + progressbox.stop = 0; + + ProgressBoxTick(0); + gtk_widget_show_all(progressbox.window); + gtk_window_deiconify(GTK_WINDOW(progressbox.window)); +} // END ProgressBoxStart() + + +void ProgressBoxTick(off64_t current) { + gdouble gcur; + off64_t thispct; + + gcur = current; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbox.bar), + gcur / progressbox.gmax); + + sprintf(progressboxline, "%llu of %llu", current, progressbox.max); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progressbox.bar), progressboxline); + + if(progressbox.max >= 100) { + thispct = current / ( progressbox.max / 100 ); + if(thispct != progressbox.lastpct) { + sprintf(progressboxline, "%llu%% CDVDisoEFP Progress", thispct); + gtk_window_set_title(GTK_WINDOW(progressbox.window), progressboxline); + progressbox.lastpct = thispct; + } // ENDIF- Change in percentage? (Avoiding title flicker) + } // ENDIF- Our maximum # over 100? (Avoiding divide-by-zero error) + + while(gtk_events_pending()) gtk_main_iteration(); // Give time for window to redraw. +} // END ProgressBoxTick() + + +void ProgressBoxStop() { + gtk_widget_hide(progressbox.window); + gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); +} // END ProgressBoxStop() + + +gint ProgressBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + progressbox.stop = 1; + + return(TRUE); +} // END ProgressBoxCancelEvent() + + +void ProgressBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + + progressbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(progressbox.window), 5); + gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); + gtk_window_set_position(GTK_WINDOW(progressbox.window), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(progressbox.window), FALSE); + + g_signal_connect(G_OBJECT(progressbox.window), "delete_event", + G_CALLBACK(ProgressBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(progressbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + progressbox.desc = gtk_label_new("Twiddling Thumbs"); + gtk_box_pack_start(GTK_BOX(vbox1), progressbox.desc, FALSE, FALSE, 0); + gtk_widget_show(progressbox.desc); + + progressbox.bar = gtk_progress_bar_new(); + gtk_box_pack_start(GTK_BOX(vbox1), progressbox.bar, FALSE, FALSE, 0); + gtk_widget_show(progressbox.bar); + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(ProgressBoxCancelEvent), NULL); + item = NULL; + hbox1 = NULL; + vbox1 = NULL; +} // END ProgressBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.glade new file mode 100644 index 0000000000..02229256d1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.glade @@ -0,0 +1,95 @@ + + + + + + + + True + CDVDiso Progress + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + True + False + 0 + + + + True + /dev/dvd -> /usr/src/iso/GameImage.iso + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + Progress Bar: 12758 of 131509 + True + * + False + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.h new file mode 100644 index 0000000000..3b2eff5c51 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/progressbox.h @@ -0,0 +1,55 @@ +/* progressbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef PROGRESSBOX_H +#define PROGRESSBOX_H + + +#include // off64_t + +#include // GtkWidget + + +extern const char *compressnames[]; + +struct ProgressBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *desc; // GtkLabel - What are we showing progress on? + GtkWidget *bar; // GtkProgressBar + + off64_t max; + gdouble gmax; + off64_t lastpct; + + int stop; // Someone pressed the Stop button +}; + +extern struct ProgressBoxData progressbox; + + +extern void ProgressBoxStart(char *description, off64_t maximum); +extern void ProgressBoxTick(off64_t current); +extern void ProgressBoxStop(); +extern void ProgressBoxDestroy(); +extern void ProgressBoxDisplay(); + + +#endif /* MAINBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.c b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.c new file mode 100644 index 0000000000..a33a55944f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.c @@ -0,0 +1,102 @@ +/* selectionbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL + +#include // g_signal_connect() +#include // gtk_entry_set_text() +#include // gtk_file_selection_new() + +#include "devicebox.h" +#include "conversionbox.h" +#include "selectionbox.h" +#include "mainbox.h" + + +struct SelectionBoxData selectionbox; + + +void SelectionBoxDestroy() { + if(selectionbox.window != NULL) { + gtk_widget_destroy(selectionbox.window); + selectionbox.window = NULL; + } // ENDIF- Do we have a Main Window still? +} // END SelectionBoxDestroy() + + +void SelectionBoxRefresh() { +} // END SelectionBoxRefresh() + + +void SelectionBoxUnfocus() { + gtk_widget_hide(selectionbox.window); +} // END SelectionBoxUnfocus() + + +void SelectionBoxRefocus() { + gtk_widget_show(selectionbox.window); +} // END SelectionBoxRefocus() + + +gint SelectionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + SelectionBoxUnfocus(); + switch(selectionbox.wherefrom) { + case 1: + gtk_entry_set_text(GTK_ENTRY(mainbox.file), + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + MainBoxRefocus(); + break; + case 2: + gtk_entry_set_text(GTK_ENTRY(devicebox.file), + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + DeviceBoxRefocus(); + break; + case 3: + gtk_entry_set_text(GTK_ENTRY(conversionbox.file), + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + ConversionBoxRefocus(); + break; + } // ENDSWITCH wherefrom- What Box called us? + return(TRUE); +} // END SelectionBoxCancelEvent() + + +gint SelectionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + // Validate listed file(?) + + // Transfer file name to calling window? + + SelectionBoxCancelEvent(widget, event, data); + return(TRUE); +} // END SelectionBoxOKEvent() + + +void SelectionBoxDisplay() { + selectionbox.window = gtk_file_selection_new("Select an ISO file"); + g_signal_connect(G_OBJECT(selectionbox.window), "delete_event", + G_CALLBACK(SelectionBoxCancelEvent), NULL); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->ok_button), + "clicked", G_CALLBACK(SelectionBoxOKEvent), NULL); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->cancel_button), + "clicked", G_CALLBACK(SelectionBoxCancelEvent), NULL); + + selectionbox.wherefrom = 0; // Called by no one... yet. +} // END SelectionBoxDisplay() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.glade b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.glade new file mode 100644 index 0000000000..a57b9e4f2e --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.glade @@ -0,0 +1,44 @@ + + + + + + + + 10 + True + Select an ISO File + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.h b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.h new file mode 100644 index 0000000000..d79febb38f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/selectionbox.h @@ -0,0 +1,46 @@ +/* selectionbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef SELECTIONBOX_H +#define SELECTIONBOX_H + + +#include + + +struct SelectionBoxData { + GtkWidget *window; // GtkWindow + + int wherefrom; // Which box called you? + // 1 = MainBox + // 2 = DeviceBox + // 3 = ConversionBox +}; + +extern struct SelectionBoxData selectionbox; + + +extern void SelectionBoxDestroy(); +extern void SelectionBoxRefocus(); +extern void SelectionBoxDisplay(); + + +#endif /* SELECTIONBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.c b/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.c new file mode 100644 index 0000000000..3d913ecee2 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.c @@ -0,0 +1,190 @@ +/* tablerebuild.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // malloc() + +// #include // gtk_main_iteration() + +#include "mainbox.h" +#include "progressbox.h" +#include "isofile.h" +#include "multifile.h" +#include "isocompress.h" // CompressClose() +#include "gzipv1.h" +#include "gzipv2.h" +#include "bzip2v2.h" +#include "bzip2v3.h" +#include "actualfile.h" // ACTUALHANDLENULL + + +void IsoTableRebuild(const char *filename) { + struct IsoFile *datafile; + struct IsoFile *tablefile; + int retval; + char tempblock[65536]; + int stop; + + struct TableData table; + + datafile = IsoFileOpenForRead(filename); + + // Note: This is the start of the "Multifile" process. It's commented + // out so at least we can rebuild 1 part of a multifile at a time. + // IsoNameStripExt(datafile); + // IsoNameStripMulti(datafile); + + // Prep tablefile to hold ONLY a table (no data) + tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + if(tablefile == NULL) { + datafile = IsoFileClose(datafile); + return; + } // ENDIF- Failed to allocate? Abort. + + tablefile->sectorpos = 0; + tablefile->openforread = 0; + tablefile->filebytepos = 0; + tablefile->filebytesize = 0; + tablefile->filesectorpos = 0; + tablefile->filesectorsize = 0; + tablefile->handle = ACTUALHANDLENULL; + + tablefile->namepos = 0; + while((tablefile->namepos < 255) && + (*(filename + tablefile->namepos) != 0)) { + tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); + tablefile->namepos++; + } // ENDWHILE- Copying file name into tablefile + tablefile->name[tablefile->namepos] = 0; // And 0-terminate. + + tablefile->imageheader = datafile->imageheader; + tablefile->blocksize = datafile->blocksize; + tablefile->blockoffset = datafile->blockoffset; + tablefile->cdvdtype = 0; // Not important right now. + + tablefile->compress = datafile->compress; + tablefile->compresspos = datafile->compresspos; + tablefile->numsectors = datafile->numsectors; + tablefile->tabledata = NULL; + + switch(tablefile->compress) { + case 1: + retval = GZipV1OpenTableForWrite(tablefile); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2OpenTableForWrite(tablefile); + break; + case 4: + retval = BZip2V2OpenTableForWrite(tablefile); + break; + case 5: + retval = BZip2V3OpenTableForWrite(tablefile); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Which table are we writing out? + if(retval < 0) { + datafile = IsoFileClose(datafile); + return; + } // ENDIF- Failed to open table file? Abort + + sprintf(tempblock, "Rebuilding table for %s", datafile->name); + ProgressBoxStart(tempblock, datafile->filebytesize); + + stop = 0; + mainbox.stop = 0; + progressbox.stop = 0; + while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { + switch(datafile->compress) { + case 1: + retval = GZipV1Read(datafile, 0, tempblock); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2Read(datafile, 0, tempblock); + break; + case 4: + retval = BZip2V2Read(datafile, 0, tempblock); + break; + case 5: + retval = BZip2V3Read(datafile, 0, tempblock); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Scanning for the next complete compressed block + + if(retval <= 0) { +#ifdef FUNCTION_WARNING_TABLEREBUILD + PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); +#endif /* FUNCTION_WARNING_TABLEREBUILD */ + stop = 1; + } else { + table.offset = datafile->filebytepos - retval; + table.size = retval; + switch(tablefile->compress) { + case 1: + retval = GZipV1WriteTable(tablefile, table); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2WriteTable(tablefile, table); + break; + case 4: + retval = BZip2V2WriteTable(tablefile, table); + break; + case 5: + retval = BZip2V3WriteTable(tablefile, table); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Writing out the relavent table facts + if(retval < 0) stop = 1; + } // ENDIF- Do we have a valid record to write an entry for? + + ProgressBoxTick(datafile->filebytepos); + // while(gtk_events_pending()) gtk_main_iteration(); + + if(mainbox.stop != 0) stop = 2; + if(progressbox.stop != 0) stop = 2; + } // ENDWHILE- Read in the data file and writing a table, 1 block at a time + + ProgressBoxStop(); + + CompressClose(tablefile); // Guarentee the table is flushed and closed. + if(stop != 0) { + ActualFileDelete(tablefile->tablename); + } // ENDIF- Aborted or trouble? Delete the table file + tablefile = IsoFileClose(tablefile); + datafile = IsoFileClose(datafile); + + return; +} // END IsoTableRebuild() diff --git a/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.h b/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.h new file mode 100644 index 0000000000..731911d29a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Linux/tablerebuild.h @@ -0,0 +1,32 @@ +/* tablerebuild.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef TABLEREBUILD_H +#define TABLEREBUILD_H + + +// #define FUNCTION_WARNING_TABLEREBUILD + + +extern void IsoTableRebuild(const char *filename); + + +#endif /* TABLEREBUILD_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/PS2Edefs.h b/plugins/cdvd/CDVDisoEFP/src/PS2Edefs.h new file mode 100644 index 0000000000..620a7c87fc --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/PS2Edefs.h @@ -0,0 +1,812 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(off64_t *mem); +void CALLBACK GSreadFIFO2(off64_t *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(off64_t *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(off64_t *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/PS2Etypes.h b/plugins/cdvd/CDVDisoEFP/src/PS2Etypes.h new file mode 100644 index 0000000000..04ad5599a0 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/PS2Etypes.h @@ -0,0 +1,75 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/CD.c b/plugins/cdvd/CDVDisoEFP/src/Win32/CD.c new file mode 100644 index 0000000000..469a2dcb71 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/CD.c @@ -0,0 +1,774 @@ +/* CD.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_CDROM... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "../convert.h" // MSFtoLBA(), HEXTOBCD() + +#include "actualfile.h" + +#include "device.h" // tocbuffer[], FinishCommand() + +#include "CD.h" + + + + + +int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA + +DWORD cdblocksize; // 2048 to 2352 + +int cdoffset; // 0, 8, 16, or 24 + +int cdmode; + + + + + +void InitCDInfo() { + + actualcdmode = -1; + + cdblocksize = 2048; + + cdmode = -1; + +} // END InitCDInfo() + + + + + +s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { + + RAW_READ_INFO rawinfo; + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + LARGE_INTEGER targetpos; + + int i; + + + + if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVD CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(actualcdmode >= 0) { + + rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. + + rawinfo.SectorCount = 1; + + rawinfo.TrackMode = actualcdmode; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_RAW_READ, + + &rawinfo, + + sizeof(RAW_READ_INFO), + + buffer, + + 2352, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Couldn't read a sector raw!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + } else { + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer + 24, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Couldn't read a cooked sector!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with seek? Report it. + + + + for(i = 0; i < 24; i++) *(buffer + i) = 0; + + for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; + + } // ENDIF- Could we read a raw sector? Read another one! + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", + + byteswritten, cdblocksize); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + cdmode = mode; + + cdblocksize = byteswritten; + + return(0); + +} // END CDreadTrackPass() + + + + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + + int retval; + + int lastmode; + + int i; + + + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Same mode doesn't work. Scanning..."); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + lastmode = actualcdmode; + + actualcdmode = 2; + + while(actualcdmode >= -1) { + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + actualcdmode--; + + } // ENDWHILE- Searching each mode for a way to read the sector + + actualcdmode = lastmode; // None worked? Go back to first mode. + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: No modes work. Failing sector!"); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + for(i = 0; i < 2352; i++) *(buffer + i) = 0; + + return(-1); + +} // END CDreadTrack() + + + + + +s32 CDgetBufferOffset() { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVD CD: CDgetBufferOffset()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + // Send a whole CDDA record in? + + if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); + + + + // Otherwise, send the start of the data block in... + + return(cdoffset); + +} // END CDgetBufferOffset() + + + + + +s32 CDreadSubQ() { + + return(-1); + +} // END CDreadSubQ() + + + + + +s32 CDgetTN(cdvdTN *cdvdtn) { + + cdvdtn->strack = BCDTOHEX(tocbuffer[7]); + + cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); + + return(0); + +} // END CDgetTN() + + + + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + + u8 actualtrack; + + int pos; + + char temptime[3]; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso CD: CDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + actualtrack = newtrack; + + if(actualtrack == 0xaa) actualtrack = 0; + + + + if(actualtrack == 0) { + + cdvdtd->type = 0; + + temptime[0] = BCDTOHEX(tocbuffer[27]); + + temptime[1] = BCDTOHEX(tocbuffer[28]); + + temptime[2] = BCDTOHEX(tocbuffer[29]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } else { + + pos = actualtrack * 10; + + pos += 30; + + cdvdtd->type = tocbuffer[pos]; + + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } // ENDIF- Whole disc? (or single track?) + + + + return(0); + +} // END CDgetTD() + + + + + +s32 CDgetDiskType() { + + CDROM_TOC cdinfo; + + BOOL boolresult; + + int retval; + + DWORD byteswritten; + + DWORD errcode; + + u8 iso9660name[] = "CD001\0"; + + u8 playstationname[] = "PLAYSTATION\0"; + + u8 ps1name[] = "CD-XA001\0"; + + u8 tempbuffer[2448]; + + int tempdisctype; + + int i; + + int pos; + + unsigned long volumesize; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso CD: CDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + actualcdmode = 2; + + retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + disctype = tempdisctype; + + return(-1); + + } // ENDIF- Couldn't read the directory sector? Abort. + + + + disctype = CDVD_TYPE_DETCTCD; + + tempdisctype = CDVD_TYPE_CDDA; + + + + cdoffset = 0; + + i = 0; + + while((cdoffset <= 24) && (iso9660name[i] != 0)) { + + i = 0; + + while((iso9660name[i] != 0) && + + (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; + + if(iso9660name[i] != 0) cdoffset += 8; + + } // ENDWHILE- Trying to find a working offset for a ISO9660 record. + + + + if(iso9660name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a CDDA (Music CD)."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_CDDA; + + tocbuffer[0] = 0x01; + + + + } else { + + tocbuffer[0] = 0x41; + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; + + if(playstationname[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a non-Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + } else { + + i = 0; + + while((ps1name[i] != 0) && + + (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; + + if(ps1name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation 2 CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2CD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PSCD; + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) + + + + // Build the Fake TOC + + tocbuffer[2] = 0xA0; + + tocbuffer[7] = HEXTOBCD(1); // Starting Track + + tocbuffer[12] = 0xA1; + + tocbuffer[17] = HEXTOBCD(1); // Ending Track + + + + volumesize = tempbuffer[84]; // Volume size (big endian) + + volumesize *= 256; + + volumesize += tempbuffer[85]; + + volumesize *= 256; + + volumesize += tempbuffer[86]; + + volumesize *= 256; + + volumesize += tempbuffer[87]; + +#ifdef VERBOSE_DISC_INFO + + if(tempdisctype != CDVD_TYPE_CDDA) { + + PrintLog("CDVDiso CD: ISO9660 size %llu", volumesize); + + } // ENDIF- Data CD? Print size in blocks. + +#endif /* VERBOSE_DISC_INFO */ + + + + LBAtoMSF(volumesize, &tocbuffer[27]); + + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + + + tocbuffer[40] = 0x02; // Data Mode + + tocbuffer[42] = 0x01; // Track # + + LBAtoMSF(0, &tocbuffer[47]); + + tocbuffer[47] = HEXTOBCD(tocbuffer[47]); + + tocbuffer[48] = HEXTOBCD(tocbuffer[48]); + + tocbuffer[49] = HEXTOBCD(tocbuffer[49]); + + + + // Can we get the REAL TOC? + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_READ_TOC, + + NULL, + + 0, + + &cdinfo, + + sizeof(CDROM_TOC), + + &byteswritten, + + NULL); + + + + if(boolresult == FALSE) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Can't get TOC!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + disctype = tempdisctype; + + return(disctype); + + } // ENDIF- Can't read the TOC? Accept the fake TOC then. + + + + // Fill in the pieces of the REAL TOC. + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC First Track: %u Last Track: %u", + + cdinfo.FirstTrack, cdinfo.LastTrack); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); + + tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); + + + + // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { + + for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", + + cdinfo.TrackData[i].TrackNumber, + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1, + + cdinfo.TrackData[i].Control * 1); + +#endif /* VERBOSE_DISC_INFO */ + + pos = i * 10 + 40; + + tocbuffer[pos] = cdinfo.TrackData[i].Control; + + tocbuffer[pos + 2] = HEXTOBCD(i + 1); + + tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + } // NEXT i- Transferring Track data to the PS2 TOC + + + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC Disc Size: %u:%u.%u", + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + + + disctype = tempdisctype; + + return(disctype); + +} // END CDgetDiskType() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/CD.h b/plugins/cdvd/CDVDisoEFP/src/Win32/CD.h new file mode 100644 index 0000000000..6bff6d8e82 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/CD.h @@ -0,0 +1,44 @@ +/* CD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CD_H +#define CD_H + + +#include // DWORD + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern DWORD cdblocksize; + + +extern void InitCDInfo(); +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 CDgetBufferOffset(); +extern s32 CDreadSubQ(); +extern s32 CDgetTN(cdvdTN *cdvdtn); +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 CDgetDiskType(); + + +#endif /* CD_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.c b/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.c new file mode 100644 index 0000000000..27cf979d55 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.c @@ -0,0 +1,570 @@ +/* CDVDiso.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // BOOL, CALLBACK, APIENTRY +#include // NULL + +#define CDVDdefs +#include "../PS2Edefs.h" + +#include "conf.h" +#include "actualfile.h" +#include "../isofile.h" +#include "logfile.h" +#include "../convert.h" +#include "../version.h" +#include "screens.h" +#include "mainbox.h" // Initialize mainboxwindow +#include "progressbox.h" // Initialize progressboxwindow +#include "conversionbox.h" // Initialize conversionboxwindow +#include "devicebox.h" // Initialize deviceboxwindow +#include "CDVDiso.h" + + +struct IsoFile *isofile; +char isobuffer[2448]; +char isocdcheck[2048]; +int isomode; +int deviceopencount; + +HINSTANCE progmodule; + + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD param, + LPVOID reserved) { + + + switch(param) { + case DLL_PROCESS_ATTACH: + progmodule = hModule; + // mainboxwindow = NULL; + // progressboxwindow = NULL; + // conversionboxwindow = NULL; + // deviceboxwindow = NULL; + return(TRUE); + break; + case DLL_PROCESS_DETACH: + // CDVDshutdown(); + return(TRUE); + break; + case DLL_THREAD_ATTACH: + return(TRUE); + break; + case DLL_THREAD_DETACH: + return(TRUE); + break; + } // ENDSWITCH param- What does the OS want with us? + + return(FALSE); // Wasn't on list? Wasn't handled. +} // END DllMain() + + +char* CALLBACK PS2EgetLibName() { + return(libname); +} // END PS2EgetLibName() + + +u32 CALLBACK PS2EgetLibType() { + return(PS2E_LT_CDVD); +} // END PS2getLibType() + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return((version << 16) | (revision << 8) | build); +} // END PS2EgetLibVersion2() + + +s32 CALLBACK CDVDinit() { + int i; + + InitLog(); + if(OpenLog() != 0) return(-1); // Couldn't open Log File? Abort. + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDinit()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + InitConf(); + + isofile = NULL; + isomode = -1; + deviceopencount = 0; + for(i = 0; i < 2048; i++) isocdcheck[i] = 0; + + mainboxwindow = NULL; + progressboxwindow = NULL; + conversionboxwindow = NULL; + deviceboxwindow = NULL; + + return(0); +} // END CDVDinit() + + +void CALLBACK CDVDshutdown() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDshutdown()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + isofile = IsoFileClose(isofile); + + // Close Windows as well? (Just in case) + + CloseLog(); +} // END CDVDshutdown() + + +s32 CALLBACK CDVDopen(const char* pTitleFilename) { + HWND lastwindow; + int i; + int retval; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDopen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + lastwindow = GetActiveWindow(); + LoadConf(); + + if( pTitleFilename != NULL ) strcpy(conf.isoname, pTitleFilename); + + if((conf.isoname[0] == 0) || (conf.isoname[0] == '[') || + ((conf.startconfigure == 1) && (deviceopencount == 0)) || + ((conf.restartconfigure == 1) && (deviceopencount > 0))) { + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0200), + lastwindow, + (DLGPROC)MainBoxCallback); + SetActiveWindow(lastwindow); + LoadConf(); + // Blank out the name in config file afterwards? Seems excessive. + } // ENDIF- Haven't initialized the configure program yet? Do so now. + lastwindow = NULL; + + isofile = IsoFileOpenForRead(conf.isoname); + if(isofile == NULL) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Failed to open ISO file!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + // return(-1); // Removed to simulate disc not in drive. + for(i = 0; i < 2048; i++) isocdcheck[i] = 0; + return(0); + } // ENDIF- Trouble opening file? Abort. + + retval = IsoFileSeek(isofile, 16); + if(retval != 0) return(-1); + retval = IsoFileRead(isofile, isobuffer); + if(retval != 0) return(-1); + + if(deviceopencount > 0) { + i = 0; + while((i < 2048) && (isocdcheck[i] == isobuffer[i])) i++; + if(i == 2048) deviceopencount = 0; // Same CD/DVD? No delay. + } // ENDIF- Is this a restart? Check for disc change. + + for(i = 0; i < 2048; i++) isocdcheck[i] = isobuffer[i]; + + return(0); +} // END CDVDopen() + + +void CALLBACK CDVDclose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDclose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + isofile = IsoFileClose(isofile); + deviceopencount = 50; +} // END CDVDclose() + + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + char temptime[3]; + int i; + int pos; + u32 tracklsn; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDreadSubQ()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(-1); + } // ENDIF- Still simulating device tray open? + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + return(-1); // DVDs don't have SubQ data + } // ENDIF- Trying to get a SubQ from a DVD? + + // fake it + i = BCDTOHEX(isofile->toc[7]); + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + tracklsn = MSFtoLBA(temptime); + while((i < BCDTOHEX(isofile->toc[17])) && (tracklsn < lsn)) { + i++; + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + tracklsn = MSFtoLBA(temptime); + } // ENDIF- Loop through tracks searching for lsn track + i--; + + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = HEXTOBCD(i); + subq->trackIndex = HEXTOBCD(i); + + LBAtoMSF(lsn - tracklsn, temptime); + subq->trackM = HEXTOBCD(temptime[0]); + subq->trackS = HEXTOBCD(temptime[1]); + subq->trackF = HEXTOBCD(temptime[2]); + + subq->pad = 0; + + // lba_to_msf(lsn + (2*75), &min, &sec, &frm); + LBAtoMSF(lsn, temptime); + subq->discM = HEXTOBCD(temptime[0]); + subq->discS = HEXTOBCD(temptime[1]); + subq->discF = HEXTOBCD(temptime[2]); + + return(0); +} // END CDVDreadSubQ() + + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(-1); + } // ENDIF- Still simulating device tray open? + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + Buffer->strack = 1; + Buffer->etrack = 1; + } else { + Buffer->strack = BCDTOHEX(isofile->toc[7]); + Buffer->etrack = BCDTOHEX(isofile->toc[17]); + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + return(0); +} // END CDVDgetTN() + + +s32 CALLBACK CDVDgetTD(u8 track, cdvdTD *Buffer) { + u8 actualtrack; + int pos; + char temptime[3]; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(-1); + } // ENDIF- Still simulating device tray open? + + actualtrack = track; + if(actualtrack == 0xaa) actualtrack = 0; + + if((isofile->cdvdtype == CDVD_TYPE_PS2DVD) || + (isofile->cdvdtype == CDVD_TYPE_DVDV)) { + if (actualtrack <= 1) { + Buffer->type = 0; + Buffer->lsn = isofile->filesectorsize; + } else { + Buffer->type = CDVD_MODE1_TRACK; + Buffer->lsn = 0; + } // ENDIF- Whole disc? (or single track?) + } else { + if (actualtrack == 0) { + Buffer->type = 0; + temptime[0] = BCDTOHEX(isofile->toc[27]); + temptime[1] = BCDTOHEX(isofile->toc[28]); + temptime[2] = BCDTOHEX(isofile->toc[29]); + Buffer->lsn = MSFtoLBA(temptime); + } else { + pos = actualtrack * 10; + pos += 30; + Buffer->type = isofile->toc[pos]; + temptime[0] = BCDTOHEX(isofile->toc[pos + 7]); + temptime[1] = BCDTOHEX(isofile->toc[pos + 8]); + temptime[2] = BCDTOHEX(isofile->toc[pos + 9]); + Buffer->lsn = MSFtoLBA(temptime); + } // ENDIF- Whole disc? (or single track?) + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + return(0); +} // END CDVDgetTD() + + +s32 CALLBACK CDVDgetTOC(void* toc) { + int i; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetTOC()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(-1); + } // ENDIF- Still simulating device tray open? + + for(i = 0; i < 2048; i++) *(((char *) toc) + i) = isofile->toc[i]; + return(0); +} // END CDVDgetTOC() + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + int retval; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDreadTrack(%u)", lsn); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(-1); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(-1); + } // ENDIF- Still simulating device tray open? + + retval = IsoFileSeek(isofile, (off64_t) lsn); + if(retval != 0) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Trouble finding the sector!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(-1); + } // ENDIF- Trouble finding the sector? + + retval = IsoFileRead(isofile, isobuffer); + if(retval != 0) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Trouble reading the sector!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(-1); + } // ENDIF- Trouble finding the sector? + + isomode = mode; + return(0); +} // END CDVDreadTrack() + + +u8* CALLBACK CDVDgetBuffer() { + int offset; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDgetBuffer()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(NULL); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(NULL); + } // ENDIF- Still simulating device tray open? + + offset = 0; + switch(isomode) { + case CDVD_MODE_2352: + offset = 0; + break; + case CDVD_MODE_2340: + offset = 12; + break; + case CDVD_MODE_2328: + case CDVD_MODE_2048: + offset = 24; + break; + } // ENDSWITCH isomode- offset to where data it wants is. + + if(offset > isofile->blockoffset) offset = isofile->blockoffset; + + return(isobuffer + offset); +} // END CDVDgetBuffer() + + +s32 CALLBACK CDVDgetDiskType() { +#ifdef VERBOSE_FUNCTION_INTERFACE + // PrintLog("CDVDiso interface: CDVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(CDVD_TYPE_NODISC); + if(deviceopencount > 0) { + deviceopencount--; + if(deviceopencount > 0) return(CDVD_TYPE_DETCT); + } // ENDIF- Still simulating device tray open? + + return(isofile->cdvdtype); +} // END CDVDgetDiskType() + + +s32 CALLBACK CDVDgetTrayStatus() { +#ifdef VERBOSE_FUNCTION_INTERFACE + // PrintLog("CDVDiso interface: CDVDgetTrayStatus()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(isofile == NULL) return(CDVD_TRAY_OPEN); + if(deviceopencount > 30) { + deviceopencount--; + return(CDVD_TRAY_OPEN); + } // ENDIF- Still simulating device tray open? + + return(CDVD_TRAY_CLOSE); +} // END CDVDgetTrayStatus() + + +s32 CALLBACK CDVDctrlTrayOpen() { + HWND lastwindow; + int i; + int retval; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDctrlTrayOpen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + // CDVDclose(); + isofile = IsoFileClose(isofile); + deviceopencount = 50; + + // CDVDopen(); + lastwindow = GetActiveWindow(); + LoadConf(); + if((conf.isoname[0] == 0) || (conf.isoname[0] == '[') || + ((conf.restartconfigure == 1) && (deviceopencount > 0))) { + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0200), + lastwindow, + (DLGPROC)MainBoxCallback); + SetActiveWindow(lastwindow); + LoadConf(); + // Blank out the name in config file afterwards? Seems excessive. + } // ENDIF- Haven't initialized the configure program yet? Do so now. + lastwindow = NULL; + deviceopencount = 0; // Temp line! + // NOTE: What happened to repetitive polling when disc not in drive? + + isofile = IsoFileOpenForRead(conf.isoname); + if(isofile == NULL) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: Failed to open ISO file!"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + // return(-1); // Removed to simulate disc not in drive. + for(i = 0; i < 2048; i++) isocdcheck[i] = 0; + return(0); + } // ENDIF- Trouble opening file? Abort. + + retval = IsoFileSeek(isofile, 16); + if(retval != 0) return(-1); + retval = IsoFileRead(isofile, isobuffer); + if(retval != 0) return(-1); + + if(deviceopencount > 0) { + i = 0; + while((i < 2048) && (isocdcheck[i] == isobuffer[i])) i++; + if(i == 2048) deviceopencount = 0; // Same CD/DVD? No delay. + } // ENDIF- Is this a restart? Check for disc change. + + for(i = 0; i < 2048; i++) isocdcheck[i] = isobuffer[i]; + + return(0); +} // END CDVDctrlTrayOpen() + + +s32 CALLBACK CDVDctrlTrayClose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDctrlTrayClose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + return(0); +} // END CDVDctrlTrayClose() + + +s32 CALLBACK CDVDtest() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDiso interface: CDVDtest()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + // InitConf(); // Shouldn't need this. Doesn't CDVDInit() get called first? + LoadConf(); + + if(conf.isoname[0] == 0) return(0); // No name chosen yet. Catch on Open() + if(IsIsoFile(conf.isoname) == 0) return(0); // Valid name. Go. + return(-1); // Invalid name - reconfigure first. + // Note really need this? Why not just return(0)... +} // END CDVDtest() + + +void CALLBACK CDVDconfigure() { + HWND lastwindow; + + lastwindow = GetActiveWindow(); + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0200), + lastwindow, + (DLGPROC)MainBoxCallback); + SetActiveWindow(lastwindow); + lastwindow = NULL; + return; +} // END CDVDconfigure() + + +BOOL CALLBACK AboutCallback(HWND window, UINT msg, WPARAM param, LPARAM param2) { + switch(msg) { + case WM_COMMAND: + switch(LOWORD(param)) { + case IDC_0104: // "Ok" Button + EndDialog(window, FALSE); + return(TRUE); + break; + } // ENDSWITCH param- Which Windows Message Command? + + case WM_CLOSE: + EndDialog(window, FALSE); + return(TRUE); + break; + } // ENDSWITCH msg- what message has been sent to this window? + + return(FALSE); // Not a recognisable message. Pass it back to the OS. +} // END AboutCallback() + +void CALLBACK CDVDabout() { + HWND lastwindow; + + lastwindow = GetActiveWindow(); + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0100), + lastwindow, + (DLGPROC)AboutCallback); + SetActiveWindow(lastwindow); + return; +} // END CDVDabout() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.h b/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.h new file mode 100644 index 0000000000..61aab42bc4 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/CDVDiso.h @@ -0,0 +1,36 @@ +/* CDVDiso.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CDVDISO_H +#define CDVDISO_H + + +#include // HINSTANCE + + +// #define VERBOSE_FUNCTION_INTERFACE + + +extern HINSTANCE progmodule; +extern char isobuffer[]; + + +#endif /* CDVDISO_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.c b/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.c new file mode 100644 index 0000000000..18f5c6563f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.c @@ -0,0 +1,796 @@ +/* DVD.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_DVD... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "device.h" // FinishCommand() + + + + + +struct { + + DVD_DESCRIPTOR_HEADER h; + + DVD_LAYER_DESCRIPTOR d; + +} layer; + +// DVD_LAYER_DESCRIPTOR layer; + +// DVD_COPYRIGHT_DESCRIPTOR copyright; + +// DVD_DISK_KEY_DESCRIPTOR disckey; + +// DVD_BCA_DESCRIPTOR bca; + +// DVD_MANUFACTURER_DESCRIPTOR manufact; + + + + + +void InitDVDInfo() { + + layer.d.EndDataSector = 0; + +} // END InitDVDInfo() + + + + + +s32 DVDGetStructures() { + + DVD_SESSION_ID sessionid; + + DVD_READ_STRUCTURE request; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + s32 retval; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetStructures()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_START_SESSION, + + NULL, + + 0, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't start session!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't start a user session on the DVD drive? Fail. + + + + request.BlockByteOffset.QuadPart = 0; + + request.Format = DvdPhysicalDescriptor; + + request.SessionId = sessionid; + + request.LayerNumber = 0; + + retval = 0; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_READ_STRUCTURE, + + &request, + + sizeof(DVD_READ_STRUCTURE), + + &layer, + + sizeof(layer), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't get layer data!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + retval = -1; + + } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. + + + +#ifdef VERBOSE_DISC_INFO + + switch(layer.d.BookType) { + + case 0: + + PrintLog("CDVDiso DVD: Book Type: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Book Type: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Book Type: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDiso DVD: Book Type: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDiso DVD: Book Type: DVD+RW"); + + break; + + default: + + PrintLog("CDVDiso DVD: Book Type: Unknown (%i)", layer.d.BookType); + + break; + + } // ENDSWITCH- Displaying the Book Type + + PrintLog("CDVDiso DVD: Book Version %i", layer.d.BookVersion); + + switch(layer.d.MinimumRate) { + + case 0: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD+RW"); + + break; + + default: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); + + break; + + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + + switch(layer.d.DiskSize) { + + case 0: + + PrintLog("CDVDiso DVD: Physical Disk Size: 120mm"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Physical Disk Size: 80mm"); + + break; + + default: + + PrintLog("CDVDiso DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); + + break; + + } // ENDSWITCH- What's the Disk Size? + + switch(layer.d.LayerType) { + + case 1: + + PrintLog("CDVDiso DVD: Layer Type: Read-Only"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Layer Type: Recordable"); + + break; + + case 4: + + PrintLog("CDVDiso DVD: Layer Type: Rewritable"); + + break; + + default: + + PrintLog("CDVDiso DVD: Layer Type: Unknown (%i)", layer.d.LayerType); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.TrackPath) { + + case 0: + + PrintLog("CDVDiso DVD: Track Path: PTP"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Track Path: OTP"); + + break; + + default: + + PrintLog("CDVDiso DVD: Track Path: Unknown (%i)", layer.d.TrackPath); + + break; + + } // ENDSWITCH- What's Track Path Layout? + + PrintLog("CDVDiso DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); + + switch(layer.d.TrackDensity) { + + case 0: + + PrintLog("CDVDiso DVD: Track Density: .74 m/track"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Track Density: .8 m/track"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Track Density: .615 m/track"); + + break; + + default: + + PrintLog("CDVDiso DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.LinearDensity) { + + case 0: + + PrintLog("CDVDiso DVD: Linear Density: .267 m/bit"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Linear Density: .293 m/bit"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Linear Density: .409 to .435 m/bit"); + + break; + + case 4: + + PrintLog("CDVDiso DVD: Linear Density: .280 to .291 m/bit"); + + break; + + case 8: + + PrintLog("CDVDiso DVD: Linear Density: .353 m/bit"); + + break; + + default: + + PrintLog("CDVDiso DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); + + break; + + } // ENDSWITCH- Displaying the Book Type + + if(layer.d.StartingDataSector == 0x30000) { + + PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + + layer.d.StartingDataSector); + + } else if(layer.d.StartingDataSector == 0x31000) { + + PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", + + layer.d.StartingDataSector); + + } else { + + PrintLog("CDVDiso DVD: Starting Sector: %lu", layer.d.StartingDataSector); + + } // ENDLONGIF- What does the starting sector tell us? + + PrintLog("CDVDiso DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); + + PrintLog("CDVDiso DVD: Ending Sector: %lu", layer.d.EndDataSector); + + if(layer.d.BCAFlag != 0) PrintLog("CDVDiso DVD: BCA data present"); + +#endif /* VERBOSE_DISC_INFO */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_END_SESSION, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + NULL, + + 0, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't end the session!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + } // ENDIF- Couldn't end the user session? Report it. + + + + return(retval); + +} // END DVDGetStructures() + + + + + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + + LARGE_INTEGER targetpos; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDreadTrack(%lu)", lsn); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't read sector!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with the command? Report it. + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", + + byteswritten, 2048); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Didn't get enough bytes? Report and Abort! + + + + return(0); + +} // END DVDreadTrack() + + + + + +s32 DVDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetTN()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(cdvdtn != NULL) { + + cdvdtn->strack = 1; + + cdvdtn->etrack = 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTN() + + + + + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track + + + + if(cdvdtd != NULL) { + + cdvdtd->type = 0; + + cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTD() + + + + + +s32 DVDgetDiskType() { + + char playstationname[] = "PLAYSTATION\0"; + + int retval; + + s32 tempdisctype; + + char tempbuffer[2048]; + + int i; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + retval = DVDGetStructures(); + + if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. + + if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. + + + + retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + return(-1); + + } // ENDIF- Couldn't read the ISO9660 volume track? Fail. + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + if(layer.d.NumberOfLayers == 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso DVD: Found Single-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDS; + + } else { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso DVD: Found Dual-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDD; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[8 + i])) i++; + + if(playstationname[i] == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDiso DVD: Found Playstation 2 DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2DVD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDiso DVD: Guessing it's a Video DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_DVDV; + + } // ENDIF- Is this a playstation disc? + + + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + + + + if(layer.d.NumberOfLayers == 0) { + + tocbuffer[0] = 0x04; + + tocbuffer[4] = 0x86; + + tocbuffer[5] = 0x72; + + } else { + + tocbuffer[0] = 0x24; + + tocbuffer[4] = 0x41; + + tocbuffer[5] = 0x95; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + tocbuffer[1] = 0x02; + + tocbuffer[2] = 0xF2; + + tocbuffer[3] = 0x00; + + + + tocbuffer[16] = 0x00; + + tocbuffer[17] = 0x03; + + tocbuffer[18] = 0x00; + + tocbuffer[19] = 0x00; + + + + disctype = tempdisctype; + + return(disctype); + +} // END DVDgetDiskType() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.h b/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.h new file mode 100644 index 0000000000..3876101750 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/DVD.h @@ -0,0 +1,37 @@ +/* DVD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef DVD_H +#define DVD_H + + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern void InitDVDInfo(); +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DVDgetTN(cdvdTN *cdvdtn); +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 DVDgetDiskType(); + + +#endif /* DVD_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32 b/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32 new file mode 100644 index 0000000000..d499a79abd --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32 @@ -0,0 +1,59 @@ +all: plugin + +PLUGIN = CDVDisoEFP.dll +CC = mingw32-gcc.exe + +PLUGINOBJS = CDVDiso.o mainbox.o tablerebuild.o progressbox.o conversionbox.o \ + devicebox.o device.o DVD.o CD.o +PLUGINHEADERS = CDVDiso.h mainbox.h tablerebuild.h progressbox.h conversionbox.h \ + devicebox.h device.h DVD.h CD.h +PLUGINFLAGS = -Wall -O2 -D_WIN32 -D_LARGEFILE64_SOURCE -I.. -I. -I./Win32 -mwindows +PLUGINLIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lkernel32 \ + -luser32 --subsystem,windows +# Note: Don't think we need all the above libs... will pare down later. + +SHAREDOBJS = ..\\version.o conf.o ..\\isofile.o actualfile.o logfile.o \ + ..\\imagetype.o ..\\multifile.o ..\\isocompress.o ..\\convert.o \ + ..\\gzipv1.o ..\\blockv2.o ..\\gzipv2.o ..\\bzip2v2.o ..\\ecma119.o \ + ..\\toc.o ..\\ini.o ..\\bzip2v3.o \ + ..\\zlib\\adler32.o ..\\zlib\\compress.o ..\\zlib\\crc32.o \ + ..\\zlib\\gzio.o ..\\zlib\\uncompr.o ..\\zlib\\deflate.o \ + ..\\zlib\\trees.o ..\\zlib\\zutil.o ..\\zlib\\inflate.o \ + ..\\zlib\\infback.o ..\\zlib\\inftrees.o ..\\zlib\\inffast.o \ + ..\\bzip2\\blocksort.o ..\\bzip2\\bzlib.o ..\\bzip2\\compress.o \ + ..\\bzip2\\crctable.o ..\\bzip2\\decompress.o ..\\bzip2\\huffman.o \ + ..\\bzip2\\randtable.o +SHAREDHEADERS = ..\\version.h conf.h ..\\isofile.h actualfile.h logfile.h \ + ..\\imagetype.h ..\\multifile.h ..\\isocompress.h ..\\convert.h \ + ..\\gzipv1.h ..\\blockv2.o ..\\gzipv2.h ..\\bzip2v2.h ..\\ecma119.h \ + ..\\toc.h ..\\ini.h ..\\bzip2v3.o + + + +WINDRES = windres.exe + + + +release: plugin + copy $(PLUGIN) ..\\.. + +plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res + -del $(PLUGIN) + dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) + strip --strip-unneeded --strip-debug $(PLUGIN) + +$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c + $(CC) $(PLUGINFLAGS) -c $< -o $@ + +screens.res: screens.rc + $(WINDRES) -i screens.rc -J rc -o screens.res -O coff + +.PHONY : clean allclean +clean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + +allclean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + -del temp.txt err.txt ..\\temp.txt ..\\err.txt + -del ..\\..\\$(PLUGIN) + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak b/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak new file mode 100644 index 0000000000..6e9077ff01 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak @@ -0,0 +1,57 @@ + +PLUGIN = CDVDisoEFP.dll +PLUGINOBJS = CDVDiso.o mainbox.o tablerebuild.o progressbox.o conversionbox.o \ + devicebox.o device.o DVD.o CD.o +PLUGINHEADERS = CDVDiso.h mainbox.h tablerebuild.h progressbox.h conversionbox.h \ + devicebox.h device.h DVD.h CD.h +PLUGINFLAGS = -Wall -O2 -D_LARGEFILE64_SOURCE -I.. -I. -I./Win32 -mwindows +PLUGINLIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lkernel32 \ + -luser32 --subsystem,windows +# Note: Don't think we need all the above libs... will pare down later. + +SHAREDOBJS = ..\\version.o conf.o ..\\isofile.o actualfile.o logfile.o \ + ..\\imagetype.o ..\\multifile.o ..\\isocompress.o ..\\convert.o \ + ..\\gzipv1.o ..\\blockv2.o ..\\gzipv2.o ..\\bzip2v2.o ..\\ecma119.o \ + ..\\toc.o ..\\ini.o ..\\bzip2v3.o \ + ..\\zlib\\adler32.o ..\\zlib\\compress.o ..\\zlib\\crc32.o \ + ..\\zlib\\gzio.o ..\\zlib\\uncompr.o ..\\zlib\\deflate.o \ + ..\\zlib\\trees.o ..\\zlib\\zutil.o ..\\zlib\\inflate.o \ + ..\\zlib\\infback.o ..\\zlib\\inftrees.o ..\\zlib\\inffast.o \ + ..\\bzip2\\blocksort.o ..\\bzip2\\bzlib.o ..\\bzip2\\compress.o \ + ..\\bzip2\\crctable.o ..\\bzip2\\decompress.o ..\\bzip2\\huffman.o \ + ..\\bzip2\\randtable.o +SHAREDHEADERS = ..\\version.h conf.h ..\\isofile.h actualfile.h logfile.h \ + ..\\imagetype.h ..\\multifile.h ..\\isocompress.h ..\\convert.h \ + ..\\gzipv1.h ..\\blockv2.o ..\\gzipv2.h ..\\bzip2v2.h ..\\ecma119.h \ + ..\\toc.h ..\\ini.h ..\\bzip2v3.o + + +CC = mingw32-gcc.exe +WINDRES = windres.exe + + +all: plugin + +release: plugin + copy $(PLUGIN) ..\\.. + +plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res + -del $(PLUGIN) + dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) + strip --strip-unneeded --strip-debug $(PLUGIN) + +$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c + $(CC) $(PLUGINFLAGS) -c $< -o $@ + +screens.res: screens.rc + $(WINDRES) -i screens.rc -J rc -o screens.res -O coff + +.PHONY : clean allclean +clean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + +allclean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + -del temp.txt err.txt ..\\temp.txt ..\\err.txt + -del ..\\..\\$(PLUGIN) + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.c b/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.c new file mode 100644 index 0000000000..864bf91717 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.c @@ -0,0 +1,506 @@ +/* actualfile.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + + + +#include // NULL + + + +#include "logfile.h" + +#include "actualfile.h" + + + + + +int IsActualFile(const char *filename) { + + DWORD retval; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: IsActualFile(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = GetFileAttributes(filename); + + if(retval == INVALID_FILE_ATTRIBUTES) return(-1); // Name doesn't exist. + + if((retval & FILE_ATTRIBUTE_DIRECTORY) != 0) return(-2); + + + + return(0); // Yep, that's a file. + +} // END IsActualFile() + + + + + +void ActualFileDelete(const char *filename) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + DeleteFile(filename); + +} // END ActualFileDelete() + + + + + +void ActualFileRename(const char *origname, const char *newname) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s->%s)", origname, newname); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + MoveFile(origname, newname); + + return; + +} // END ActualFileRename() + + + + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + + HANDLE newhandle; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + newhandle = CreateFile(filename, + + GENERIC_READ, + + FILE_SHARE_READ, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_RANDOM_ACCESS, + + NULL); + + if(newhandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(NULL); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForRead() + + + + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + + int retval; + + BY_HANDLE_FILE_INFORMATION info; + + off64_t retsize; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSize()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = GetFileInformationByHandle(handle, &info); + + if(retval == 0) return(-1); // Handle doesn't exist... + + + + retsize = info.nFileSizeHigh; + + retsize *= 0x10000; + + retsize *= 0x10000; + + retsize += info.nFileSizeLow; + + return(retsize); + +} // END ActualFileSize() + + + + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + + // int retval; + + LARGE_INTEGER realpos; + + DWORD errcode; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(position < 0) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSeek(%llu)", position); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + realpos.QuadPart = position; + +////// WinXP code for seek + +// retval = SetFilePointerEx(handle, + +// realpos, + +// NULL, + +// FILE_BEGIN); + +// if(retval == 0) { + + + +////// Win98 code for seek + + realpos.LowPart = SetFilePointer(handle, + + realpos.LowPart, + + &realpos.HighPart, + + FILE_BEGIN); + + errcode = GetLastError(); + + if((realpos.LowPart == 0xFFFFFFFF) && (errcode != NO_ERROR)) { + + + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error on seek (%llu)", position); + + PrintError("CDVDiso file", errcode); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(0); + +} // END ActualFileSeek() + + + + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + DWORD bytesread; + +#ifdef VERBOSE_WARNING_ACTUALFILE + + DWORD errcode; + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = ReadFile(handle, buffer, bytes, &bytesread, NULL); + + if(retval == 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + errcode = GetLastError(); + + PrintLog("CDVDiso file: Error reading from file"); + + PrintError("CDVDiso file", errcode); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + if(bytesread < bytes) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Short Block! Only read %i out of %i bytes", bytesread, bytes); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + } // ENDIF- Error? Abort + + + + return(bytesread); // Send back how many bytes read + +} // END ActualFileRead() + + + + + +void ActualFileClose(ACTUALHANDLE handle) { + + if(handle == NULL) return; + + if(handle == INVALID_HANDLE_VALUE) return; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileClose()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + CloseHandle(handle); + + return; + +} // END ActualFileClose() + + + + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + + HANDLE newhandle; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + newhandle = CreateFile(filename, + + GENERIC_WRITE, + + 0, + + NULL, + + CREATE_ALWAYS, + + FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + if(newhandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(NULL); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForWrite() + + + + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + DWORD byteswritten; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = WriteFile(handle, buffer, bytes, &byteswritten, NULL); + + if(retval == 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error writing to file!"); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(byteswritten); // Send back how many bytes written + +} // END ActualFileWrite() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.h b/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.h new file mode 100644 index 0000000000..f1cc9c421b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/actualfile.h @@ -0,0 +1,104 @@ +/* actualfile.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ACTUALFILE_H + +#define ACTUALFILE_H + + + + + +#include + + + +#include // off64_t +#include "PS2Etypes.h" + + + + +#define ACTUALHANDLE HANDLE + +#define ACTUALHANDLENULL NULL + + + +// #define VERBOSE_FUNCTION_ACTUALFILE + +// #define VERBOSE_WARNING_ACTUALFILE + + + + + +extern int IsActualFile(const char *filename); + +extern void ActualFileDelete(const char *filename); + +extern void ActualFileRename(const char *origname, const char *newname); + + + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); + +extern off64_t ActualFileSize(ACTUALHANDLE handle); + +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); + +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); + +extern void ActualFileClose(ACTUALHANDLE handle); + + + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); + +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + + + + +#endif /* ACTUALFILE_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/conf.c b/plugins/cdvd/CDVDisoEFP/src/Win32/conf.c new file mode 100644 index 0000000000..467a317b1a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/conf.c @@ -0,0 +1,195 @@ +/* conf.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // getenv() +#include // strerror() +#include // mkdir(), stat() +#include // mkdir(), stat(), fork() +#include // stat(), fork(), execlp() + +#include // CreateProcess() + +// #define CDVDdefs +// #include "../PS2Edefs.h" +#include "../PS2Etypes.h" // u8 +#include "logfile.h" +#include "../ini.h" +#include "conf.h" + + +const char *confnames[] = { "IsoFile", "Device", "OpenOnStart", "OpenOnRestart", NULL }; +const u8 defaultdevice[] = DEFAULT_DEVICE; +const char defaulthome[] = "inis"; +const char defaultdirectory[] = "HideMe.PS2E"; +const char defaultfile[] = "CDVDisoEFP.ini"; + +char confdirname[256]; +char conffilename[256]; + +CDVDconf conf; + + +void InitConf() { + DWORD retval; + int i; + int pos; + char *envptr; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: InitConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + conf.isoname[0] = 0; // Empty the iso name + + i = 0; + while((i < 255) && defaultdevice[i] != 0) { + conf.devicename[i] = defaultdevice[i]; + i++; + } // ENDWHILE- copying the default CD/DVD name in + conf.devicename[i] = 0; // 0-terminate the device name + + // Locating directory and file positions + pos = 0; + envptr = NULL; + // envptr = getenv("HOME"); + if(envptr == NULL) { + // = + retval = GetCurrentDirectory(253, confdirname); + if(retval > 0) { + pos = retval; + } else { + pos = 2; + confdirname[0] = '.'; + confdirname[1] = '\\'; + } // ENDIF- Did we retrieve a directory reference? + + i = 0; + while(i < pos) { + conffilename[i] = confdirname[i]; + i++; + } // ENDWHILE- Copying dir info (so far) into file info + + if(confdirname[pos-1] != '\\') { + confdirname[pos] = '\\'; + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaulthome[i] != 0)) { + confdirname[pos] = defaulthome[i]; + conffilename[pos] = defaulthome[i]; + pos++; + i++; + } // ENDWHILE- putting an offset where to store ini data + + } else { + // = / + i = 0; + while((pos < 253) && (*(envptr + i) != 0)) { + confdirname[pos] = *(envptr + i); + conffilename[pos] = *(envptr + i); + pos++; + i++; + } // ENDWHILE- copying home directory info in + + if(confdirname[pos-1] != '\\') { + confdirname[pos] = '\\'; + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultdirectory[i] != 0)) { + confdirname[pos] = defaultdirectory[i]; + conffilename[pos] = defaultdirectory[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + } // ENDIF- No Home directory? + + confdirname[pos] = 0; // Directory reference finished + + // += / + if(conffilename[pos-1] != '\\') { + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultfile[i] != 0)) { + conffilename[pos] = defaultfile[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + conffilename[pos] = 0; // File reference finished + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: Directory: %s", confdirname); + PrintLog("CDVD config: File: %s", conffilename); +#endif /* VERBOSE_FUNCTION_CONF */ +} // END InitConf() + + +void LoadConf() { + int retval; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: LoadConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); + if(retval < 0) { + sprintf(conf.isoname, "[Put an Image File here]"); + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + if(retval < 0) { + sprintf(conf.devicename, "D:"); + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); + if(retval < 0) { + conf.startconfigure = 0; // FALSE + } // ENDIF- Couldn't find keyword? Fill in a default + + retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); + if(retval < 0) { + conf.restartconfigure = 1; // TRUE + } // ENDIF- Couldn't find keyword? Fill in a default +} // END LoadConf() + + +void SaveConf() { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: SaveConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + mkdir(confdirname); + + INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); + INISaveString(conffilename, "Settings", "Device", conf.devicename); + INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); + INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); +} // END SaveConf() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/conf.h b/plugins/cdvd/CDVDisoEFP/src/Win32/conf.h new file mode 100644 index 0000000000..42bb401da6 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/conf.h @@ -0,0 +1,54 @@ +/* conf.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef CONF_H +#define CONF_H + + +#define CDVDdefs +#include "../PS2Edefs.h" + + +#define VERBOSE_FUNCTION_CONF + + +// Configuration Data + +typedef struct { + u8 isoname[256]; + u8 devicename[256]; + unsigned int startconfigure; + unsigned int restartconfigure; +} CDVDconf; +extern CDVDconf conf; + +#define DEFAULT_DEVICE "K:\\" + + +// Configuration Functions + +extern void InitConf(); +extern void LoadConf(); +extern void SaveConf(); + +extern void ExecCfg(char *arg); + + +#endif /* CONF_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.c b/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.c new file mode 100644 index 0000000000..03ee140015 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.c @@ -0,0 +1,750 @@ +/* conversionbox.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // ComboBox_AddString(), CheckDlgButton() + +#include // NULL + +// #include + + + +#include // sprintf() + +#include // strcpy() + +#include // off64_t + + + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +#include "imagetype.h" // imagedata[] + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "mainbox.h" + +#include "screens.h" // DLG_..., IDC_... + +#include "conversionbox.h" + + + + + +HWND conversionboxwindow; + + + + + +void ConversionBoxDestroy() { + + if(conversionboxwindow != NULL) { + + EndDialog(conversionboxwindow, FALSE); + + conversionboxwindow = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END ConversionBoxDestroy() + + + + + +void ConversionBoxUnfocus() { + + // gtk_widget_set_sensitive(conversionbox.file, FALSE); + + // gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); + + // gtk_widget_set_sensitive(conversionbox.compress, FALSE); + + // gtk_widget_set_sensitive(conversionbox.multi, FALSE); + + // gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); + + // gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); + + ShowWindow(conversionboxwindow, SW_HIDE); + +} // END ConversionBoxUnfocus() + + + + + +void ConversionBoxFileEvent() { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + GetDlgItemText(conversionboxwindow, IDC_0402, templine, 256); + + returnval = IsIsoFile(templine); + + if(returnval == -1) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a valid image file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -4) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Missing Table File (will rebuild)"); + + return; + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(templine); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + SetDlgItemText(conversionboxwindow, IDC_0404, templine); + + tempfile = IsoFileClose(tempfile); + + return; + +} // END ConversionBoxFileEvent() + + + + + +void ConversionBoxRefocus() { + + ConversionBoxFileEvent(); + + + + // gtk_widget_set_sensitive(conversionbox.file, TRUE); + + // gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); + + // gtk_widget_set_sensitive(conversionbox.compress, TRUE); + + // gtk_widget_set_sensitive(conversionbox.multi, TRUE); + + // gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); + + // gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); + + // gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + + ShowWindow(conversionboxwindow, SW_SHOW); + + SetActiveWindow(conversionboxwindow); + +} // END ConversionBoxRefocus() + + + + + +void ConversionBoxCancelEvent() { + + // ShowWindow(conversionboxwindow, SW_HIDE); + + ConversionBoxDestroy(); + + MainBoxRefocus(); + + return; + +} // END ConversionBoxCancelEvent() + + + + + +void ConversionBoxOKEvent() { + + char templine[256]; + + char tempblock[2352]; + + char filename[256]; + + HWND tempitem; + + int compressmethod; + + int multi; + + struct IsoFile *fromfile; + + struct IsoFile *tofile; + + int i; + + off64_t endsector; + + int stop; + + int retval; + + + + ConversionBoxUnfocus(); + + + + GetDlgItemText(conversionboxwindow, IDC_0402, filename, 256); + + if(IsIsoFile(filename) < 0) { + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Not a Valid Image File.", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + tempitem = GetDlgItem(conversionboxwindow, IDC_0406); + + compressmethod = ComboBox_GetCurSel(tempitem); + + tempitem = NULL; + + if(compressmethod > 0) compressmethod += 2; + + + + multi = 0; + + if(IsDlgButtonChecked(conversionboxwindow, IDC_0408)) multi = 1; + + + + fromfile = NULL; + + fromfile = IsoFileOpenForRead(filename); + + if(fromfile == NULL) { + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Cannot opening the source file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + if((compressmethod == fromfile->compress) && + + (multi == fromfile->multi)) { + + fromfile = IsoFileClose(fromfile); + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Compress/Multifile methods match - no need to convert", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + tofile = IsoFileOpenForWrite(filename, + + GetImageTypeConvertTo(fromfile->imagetype), + + multi, + + compressmethod); + + if(tofile == NULL) { + + fromfile = IsoFileClose(fromfile); + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Cannot create the new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + if(fromfile->multi == 1) { + + i = 0; + + while((i < 10) && + + (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; + + endsector = fromfile->multisectorend[fromfile->multiend]; + + } else { + + endsector = fromfile->filesectorsize; + + } // ENDIF- Get ending sector from multifile? (Or single file?) + + IsoFileSeek(fromfile, 0); + + + + // Open Progress Bar + + sprintf(templine, "%s: %s%s -> %s%s", + + filename, + + multinames[fromfile->multi], + + compressdesc[fromfile->compress], + + multinames[tofile->multi], + + compressdesc[tofile->compress]); + + ProgressBoxStart(templine, endsector); + + + + tofile->cdvdtype = fromfile->cdvdtype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; + + + + stop = 0; + + mainboxstop = 0; + + progressboxstop = 0; + + while((stop == 0) && (tofile->sectorpos < endsector)) { + + retval = IsoFileRead(fromfile, tempblock); + + if(retval < 0) { + + MessageBox(conversionboxwindow, + + "Trouble reading source file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } else { + + retval = IsoFileWrite(tofile, tempblock); + + if(retval < 0) { + + MessageBox(conversionboxwindow, + + "Trouble writing new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + } // ENDIF- Trouble reading in the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + + + if(mainboxstop != 0) stop = 2; + + if(progressboxstop != 0) stop = 2; + + } // ENDWHILE- Not stopped for some reason... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + + + // fromfile = IsoFileCloseAndDelete(fromfile); + + fromfile = IsoFileClose(fromfile); + + + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + SetDlgItemText(mainboxwindow, IDC_0202, templine); + + + + } else { + + fromfile = IsoFileClose(fromfile); + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- Did we succeed in the transfer? + + + + ConversionBoxRefocus(); + + if(stop == 0) ConversionBoxCancelEvent(); + + return; + +} // END ConversionBoxOKEvent() + + + + + +void ConversionBoxBrowseEvent() { + + OPENFILENAME filebox; + + char newfilename[256]; + + BOOL returnbool; + + + + filebox.lStructSize = sizeof(filebox); + + filebox.hwndOwner = conversionboxwindow; + + filebox.hInstance = NULL; + + filebox.lpstrFilter = fileselection; + + filebox.lpstrCustomFilter = NULL; + + filebox.nFilterIndex = 0; + + filebox.lpstrFile = newfilename; + + filebox.nMaxFile = 256; + + filebox.lpstrFileTitle = NULL; + + filebox.nMaxFileTitle = 0; + + filebox.lpstrInitialDir = NULL; + + filebox.lpstrTitle = NULL; + + filebox.Flags = OFN_FILEMUSTEXIST + + | OFN_NOCHANGEDIR + + | OFN_HIDEREADONLY; + + filebox.nFileOffset = 0; + + filebox.nFileExtension = 0; + + filebox.lpstrDefExt = NULL; + + filebox.lCustData = 0; + + filebox.lpfnHook = NULL; + + filebox.lpTemplateName = NULL; + + + + GetDlgItemText(conversionboxwindow, IDC_0402, newfilename, 256); + + returnbool = GetOpenFileName(&filebox); + + if(returnbool != FALSE) { + + SetDlgItemText(conversionboxwindow, IDC_0402, newfilename); + + } // ENDIF- User actually selected a name? Save it. + + + + return; + +} // END ConversionBoxBrowseEvent() + + + + + +void ConversionBoxDisplay() { + + char templine[256]; + + HWND itemptr; + + int itemcount; + + + + // Adjust window position? + + + + // Pull the name from the Main Window... for a starting place. + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + + SetDlgItemText(conversionboxwindow, IDC_0402, templine); + + + + // ConversionBoxFileEvent(); // Needed? + + + + itemptr = GetDlgItem(conversionboxwindow, IDC_0406); // Compression Combo + + itemcount = 0; + + while(compressnames[itemcount] != NULL) { + + ComboBox_AddString(itemptr, compressnames[itemcount]); + + itemcount++; + + } // ENDWHILE- loading compression types into combo box + + ComboBox_SetCurSel(itemptr, 0); // First Selection? + + itemptr = NULL; + + + + CheckDlgButton(conversionboxwindow, IDC_0408, FALSE); // Start unchecked + + + + return; + +} // END ConversionBoxDisplay() + + + + + +BOOL CALLBACK ConversionBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + conversionboxwindow = window; + + ConversionBoxDisplay(); // Final touches to this window + + return(FALSE); // Let Windows display this window + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner was hit. + + ConversionBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0402: // Filename Edit Box + + ConversionBoxFileEvent(); // Describe the File's current type... + + return(FALSE); // Let Windows edit the text. + + break; + + + + case IDC_0403: // "Browse" Button + + ConversionBoxBrowseEvent(); + + return(TRUE); + + break; + + + + case IDC_0409: // "Change File" Button + + ConversionBoxOKEvent(); + + return(TRUE); + + break; + + + + case IDC_0410: // "Cancel" Button + + ConversionBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which object got the message? + + } // ENDSWITCH msg- what message has been sent to this window? + + + + return(FALSE); + +} // END ConversionBoxEventLoop() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.h b/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.h new file mode 100644 index 0000000000..91a7ffe7a1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/conversionbox.h @@ -0,0 +1,40 @@ +/* conversionbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CONVERSIONBOX_H +#define CONVERSIONBOX_H + + +#include // HWND + + +extern HWND conversionboxwindow; + +extern void ConversionBoxDestroy(); +extern void ConversionBoxRefocus(); +extern void ConversionBoxDisplay(); +extern BOOL CALLBACK ConversionBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2); + + +#endif /* CONVERSIONBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/device.c b/plugins/cdvd/CDVDisoEFP/src/Win32/device.c new file mode 100644 index 0000000000..2b45636503 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/device.c @@ -0,0 +1,586 @@ +/* device.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include // IOCTL_CDROM..., IOCTL_STORAGE... +#include // IOCTL_DISK... +#include // sprintf() +#include // time_t + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" +#include "conf.h" +#include "CD.h" +#include "DVD.h" +#include "device.h" + + +HANDLE devicehandle; +OVERLAPPED waitevent; + +time_t lasttime; +s32 traystatus; +int traystatusmethod; +s32 disctype; +char tocbuffer[2048]; + + +void DeviceInit() { + devicehandle = NULL; + waitevent.hEvent = NULL; + waitevent.Internal = 0; + waitevent.InternalHigh = 0; + waitevent.Offset = 0; + waitevent.OffsetHigh = 0; + lasttime = 0; + + InitDisc(); +} // END DeviceInit() + + +void InitDisc() { + int i; + + InitCDInfo(); + InitDVDInfo(); + traystatus = CDVD_TRAY_OPEN; + traystatusmethod = 0; // Poll all until one works + disctype = CDVD_TYPE_NODISC; + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; +} // END InitDisc() + + +s32 DiscInserted() { + if(traystatus != CDVD_TRAY_CLOSE) return(-1); + + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + if(disctype == CDVD_TYPE_DETCT) return(-1); + if(disctype == CDVD_TYPE_NODISC) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DiscInserted()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + return(0); +} // END DiscInserted() + + +// Returns errcode (or 0 if successful) +DWORD FinishCommand(BOOL boolresult) { + DWORD errcode; + DWORD waitcode; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: FinishCommand()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(boolresult == TRUE) { + ResetEvent(waitevent.hEvent); + return(0); + } // ENDIF- Device is ready? Say so. + + errcode = GetLastError(); + if(errcode == ERROR_IO_PENDING) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: Waiting for completion."); +#endif /* VERBOSE_FUNCTION_DEVICE */ + waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait + if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { + errcode = GetLastError(); + } else if(waitcode == WAIT_TIMEOUT) { + errcode = 21; + CancelIo(devicehandle); // Speculative Line + } else { + ResetEvent(waitevent.hEvent); + return(0); // Success! + } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) + } // ENDIF- Should we wait for the call to finish? + + ResetEvent(waitevent.hEvent); + return(errcode); +} // END DeviceCommand() + + +s32 DeviceOpen() { + char tempname[256]; + UINT drivetype; + DWORD errcode; + + if(conf.devicename[0] == 0) return(-1); + + if(devicehandle != NULL) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + // InitConf(); + // LoadConf(); // Should be done at least once before this call + + // Root Directory reference + if(conf.devicename[1] == 0) { + sprintf(tempname, "%s:\\", conf.devicename); + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + sprintf(tempname, "%s\\", conf.devicename); + } else { + sprintf(tempname, "%s", conf.devicename); + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + drivetype = GetDriveType(tempname); + if(drivetype != DRIVE_CDROM) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Not a CD-ROM!"); + PrintLog("CDVDiso device: (Came back: %u)", drivetype); + errcode = GetLastError(); + if(errcode > 0) PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Not a CD-ROM? Say so! + // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? + + // Device Reference + if(conf.devicename[1] == 0) { + sprintf(tempname, "\\\\.\\%s:", conf.devicename); + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + sprintf(tempname, "\\\\.\\%s", conf.devicename); + } else { + sprintf(tempname, "%s", conf.devicename); + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + devicehandle = CreateFile(tempname, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if(devicehandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Couldn't open device read-only! Read-Write perhaps?"); + errcode = GetLastError(); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + devicehandle = CreateFile(tempname, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) + + if(devicehandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Couldn't open device!"); + errcode = GetLastError(); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + devicehandle = NULL; + return(-1); + } // ENDIF- Couldn't open that way either? Abort. + + waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(waitevent.hEvent == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Couldn't open event handler!"); + errcode = GetLastError(); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + waitevent.hEvent = NULL; + CloseHandle(devicehandle); + devicehandle = NULL; + } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. + + // More here... DeviceIoControl? for Drive Capabilities + // DEVICE_CAPABILITIES? + + ////// Should be done just after the first DeviceOpen(); + // InitDisc(); // ? + // DeviceTrayStatus(); + + return(0); +} // END DeviceOpen() + + +void DeviceClose() { + if(devicehandle == NULL) return; + + if(devicehandle == INVALID_HANDLE_VALUE) { + devicehandle = NULL; + return; + } // ENDIF- Bad value? Just clear the value. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(waitevent.hEvent != NULL) { + if(waitevent.hEvent != INVALID_HANDLE_VALUE) { + CancelIo(devicehandle); + CloseHandle(waitevent.hEvent); + } // ENDIF- Is this handle actually open? + waitevent.hEvent = NULL; + waitevent.Offset = 0; + waitevent.OffsetHigh = 0; + } // ENDIF- Reset the event handle? + + CloseHandle(devicehandle); + devicehandle = NULL; + return; +} // END DeviceClose() + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDreadTrack(lsn, mode, buffer)); + } else { + return(CDreadTrack(lsn, mode, buffer)); + } // ENDIF- Is this a DVD? +} // END DeviceReadTrack() + + +s32 DeviceBufferOffset() { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(0); + } else { + return(CDgetBufferOffset()); + } // ENDIF- Is this a DVD? + + return(-1); +} // END DeviceBufferOffset() + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(track, cdvdtd)); + } else { + return(CDgetTD(track, cdvdtd)); + } // ENDIF- Is this a DVD? + + return(-1); +} // END DeviceGetTD() + + +s32 DeviceGetDiskType() { + s32 s32result; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_OPEN) return(disctype); + + if(disctype != CDVD_TYPE_NODISC) return(disctype); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceGetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + disctype = CDVD_TYPE_DETCT; + + s32result = DVDgetDiskType(); + if(s32result != -1) return(disctype); + + s32result = CDgetDiskType(); + if(s32result != -1) return(disctype); + + disctype = CDVD_TYPE_UNKNOWN; + return(disctype); +} // END DeviceGetDiskType() + + +BOOL DeviceTrayStatusStorage() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + // this is the only way to detect if a disc is ready for action. + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = GetLastError(); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Trouble detecting drive status (STORAGE)!"); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusStorage() + + +BOOL DeviceTrayStatusCDRom() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + // this is the only way to detect if a disc is ready for action. + + boolresult = DeviceIoControl(devicehandle, + IOCTL_CDROM_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = GetLastError(); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Trouble detecting drive status (CDROM)!"); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusCDRom() + + +BOOL DeviceTrayStatusDisk() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + // this is the only way to detect if a disc is ready for action. + + boolresult = DeviceIoControl(devicehandle, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = GetLastError(); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Trouble detecting drive status (DISK)!"); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusDisk() + + +s32 DeviceTrayStatus() { + BOOL boolresult; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceTrayStatus()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + switch(traystatusmethod) { + case 1: + boolresult = DeviceTrayStatusStorage(); + break; + case 2: + boolresult = DeviceTrayStatusCDRom(); + break; + case 3: + boolresult = DeviceTrayStatusDisk(); + break; + default: + boolresult = FALSE; + break; + } // ENDSWITCH traystatusmethod- One method already working? Try it again. + + if(boolresult == FALSE) { + traystatusmethod = 0; + boolresult = DeviceTrayStatusStorage(); + if(boolresult == TRUE) { + traystatusmethod = 1; + } else { + boolresult = DeviceTrayStatusCDRom(); + if(boolresult == TRUE) { + traystatusmethod = 2; + } else { + boolresult = DeviceTrayStatusDisk(); + if(boolresult == TRUE) traystatusmethod = 3; + } // ENDIF- Did we succeed with CDRom? + } // ENDIF- Did we succeed with Storage? + } // Single call to already working test just failed? Test them all. + + if(boolresult == FALSE) { + if(traystatus == CDVD_TRAY_CLOSE) { + traystatus = CDVD_TRAY_OPEN; + DeviceClose(); + DeviceOpen(); + InitDisc(); + } // ENDIF- Just opened? clear disc info + return(traystatus); + } // ENDIF- Still failed? Assume no disc in drive then. + + if(traystatus == CDVD_TRAY_OPEN) { + traystatus = CDVD_TRAY_CLOSE; + DeviceGetDiskType(); + return(traystatus); + } // ENDIF- Just closed? Get disc information + + return(traystatus); +} // END DeviceTrayStatus() + + +s32 DeviceTrayOpen() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_OPEN) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceOpenTray()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_EJECT_MEDIA, + NULL, + 0, + NULL, + 0, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Couldn't signal media to eject! (STORAGE)"); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_DISK_EJECT_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- Storage Call failed? Try Disk call. + +// if(boolresult == FALSE) { +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDiso device: Couldn't signal media to eject! (DISK)"); +// PrintError("CDVDiso device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Disk Call failed as well? Give it up. + + return(0); +} // END DeviceTrayOpen() + + +s32 DeviceTrayClose() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_CLOSE) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDiso device: DeviceCloseTray()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_LOAD_MEDIA, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDiso device: Couldn't signal media to load! (STORAGE)"); + PrintError("CDVDiso device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_CDROM_LOAD_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- Storage call failed. CDRom call? + +// if(boolresult == FALSE) { +// errcode = GetLastError(); +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDiso device: Couldn't signal media to load! (CDROM)"); +// PrintError("CDVDiso device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_DISK_LOAD_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- CDRom call failed. Disk call? + +// if(boolresult == FALSE) { +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDiso device: Couldn't signal media to load! (DISK)"); +// PrintError("CDVDiso device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Media not available? + + return(0); +} // END DeviceTrayClose() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/device.h b/plugins/cdvd/CDVDisoEFP/src/Win32/device.h new file mode 100644 index 0000000000..608f13dd86 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/device.h @@ -0,0 +1,64 @@ +/* device.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + + +#include // BOOL, DWORD + +#include // time_t + +#define CDVDdefs +#include "../PS2Edefs.h" + + +// #define VERBOSE_FUNCTION_DEVICE +// #define VERBOSE_WARNING_DEVICE +#define VERBOSE_DISC_TYPE +#define VERBOSE_DISC_INFO + + +extern HANDLE devicehandle; +extern OVERLAPPED waitevent; + +extern time_t lasttime; +extern s32 traystatus; +extern s32 disctype; +extern char tocbuffer[]; + + +extern void DeviceInit(); +extern void InitDisc(); +extern s32 DiscInserted(); +extern DWORD FinishCommand(BOOL boolresult); + +extern s32 DeviceOpen(); +extern void DeviceClose(); +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DeviceBufferOffset(); +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); +extern s32 DeviceGetDiskType(); +extern s32 DeviceTrayStatus(); +extern s32 DeviceTrayOpen(); +extern s32 DeviceTrayClose(); + + +#endif /* __DEVICE_H__ */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.c b/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.c new file mode 100644 index 0000000000..c5c25fc3d8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.c @@ -0,0 +1,818 @@ +/* devicebox.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // ComboBox_AddString() + +#include // NULL + + + +#include // sprintf() + +#include // strcpy() + +#include // stat() + +#include // stat() + +#include // stat() + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "conf.h" + +#include "device.h" + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +// #include "imagetype.h" // imagedata[].name + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "mainbox.h" + +#include "screens.h" + +#include "devicebox.h" + + + + + +HWND deviceboxwindow; + + + + + +void DeviceBoxDestroy() { + + if(deviceboxwindow != NULL) { + + EndDialog(deviceboxwindow, FALSE); + + deviceboxwindow = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END DeviceBoxDestroy() + + + + + +void DeviceBoxUnfocus() { + + // gtk_widget_set_sensitive(devicebox.device, FALSE); + + // gtk_widget_set_sensitive(devicebox.file, FALSE); + + // gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); + + // gtk_widget_set_sensitive(devicebox.compress, FALSE); + + // gtk_widget_set_sensitive(devicebox.multi, FALSE); + + // gtk_widget_set_sensitive(devicebox.okbutton, FALSE); + + // gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); + + ShowWindow(deviceboxwindow, SW_HIDE); + +} // END DeviceBoxUnfocus() + + + + + +void DeviceBoxDeviceEvent() { + + char tempdevice[256]; + + struct stat filestat; + + int returnval; + + + + GetDlgItemText(deviceboxwindow, IDC_0302, tempdevice, 256); + + returnval = stat(tempdevice, &filestat); + + if(returnval == -1) { + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(S_ISDIR(filestat.st_mode) != 0) { + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Not a device"); + + return; + + } // ENDIF- Not a regular file? + + + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Device Likely"); + + return; + +} // END DeviceBoxDeviceEvent() + + + + + +void DeviceBoxFileEvent() { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); + + returnval = IsIsoFile(templine); + + if(returnval == -1) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a valid image file"); + + return; + + } // ENDIF- Not an image file? + + + + if(returnval == -4) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Missing Table File (will rebuild)"); + + return; + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(templine); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + SetDlgItemText(deviceboxwindow, IDC_0307, templine); + + tempfile = IsoFileClose(tempfile); + + return; + +} // END DeviceBoxFileEvent() + + + + + +void DeviceBoxRefocus() { + + DeviceBoxDeviceEvent(); + + DeviceBoxFileEvent(); + + + + // gtk_widget_set_sensitive(devicebox.device, TRUE); + + // gtk_widget_set_sensitive(devicebox.file, TRUE); + + // gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); + + // gtk_widget_set_sensitive(devicebox.compress, TRUE); + + // gtk_widget_set_sensitive(devicebox.multi, TRUE); + + // gtk_widget_set_sensitive(devicebox.okbutton, TRUE); + + // gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); + + // gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + + ShowWindow(deviceboxwindow, SW_SHOW); + + SetActiveWindow(deviceboxwindow); + +} // END DeviceBoxRefocus() + + + + + +void DeviceBoxCancelEvent() { + + // ShowWindow(deviceboxwindow, SW_HIDE); + + DeviceBoxDestroy(); + + MainBoxRefocus(); + + return; + +} // END DeviceBoxCancelEvent() + + + + + +void DeviceBoxOKEvent() { + + char templine[256]; + + u8 tempbuffer[2352]; + + struct IsoFile *tofile; + + s32 retval; + + cdvdTD cdvdtd; + + int stop; + + HWND tempitem; + + int compressmethod; + + int multi; + + int imagetype; + + int i; + + + + DeviceBoxUnfocus(); + + + + GetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename, 256); + + retval = DeviceOpen(); + + if(retval != 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not open the device", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening device? Abort here. + + + + DeviceTrayStatus(); + + retval = DiscInserted(); + + if(retval != 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "No disc in the device\r\nPlease put a disc in and try again.", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening device? Abort here. + + + + retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector + + if(retval < 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not retrieve disc sector size", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble getting disc sector count? + + + + tempitem = GetDlgItem(deviceboxwindow, IDC_0309); + + compressmethod = ComboBox_GetCurSel(tempitem); + + tempitem = NULL; + + if(compressmethod > 0) compressmethod += 2; + + + + multi = 0; + + if(IsDlgButtonChecked(deviceboxwindow, IDC_0311)) multi = 1; + + + + imagetype = 0; + + if((disctype != CDVD_TYPE_PS2DVD) && + + (disctype != CDVD_TYPE_DVDV)) imagetype = 8; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); + + tofile = IsoFileOpenForWrite(templine, + + imagetype, + + multi, + + compressmethod); + + if(tofile == NULL) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not create the new ISO file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening the ISO file? + + + + // Open Progress Bar + + sprintf(templine, "%s -> %s", conf.devicename, tofile->name); + + ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); + + + + tofile->cdvdtype = disctype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; + + + + stop = 0; + + mainboxstop = 0; + + progressboxstop = 0; + + while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { + + if(imagetype == 0) { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2048, + + tempbuffer); + + } else { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2352, + + tempbuffer); + + } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) + + if(retval < 0) { + + for(i = 0; i < 2352; i++) { + + tempbuffer[i] = 0; + + } // NEXT i- Zeroing the buffer + + } // ENDIF- Trouble reading next block? + + retval = IsoFileWrite(tofile, tempbuffer); + + if(retval < 0) { + + MessageBox(deviceboxwindow, + + "Trouble writing new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + + + if(mainboxstop != 0) stop = 2; + + if(progressboxstop != 0) stop = 2; + + } // ENDWHILE- No reason found to stop... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + } // ENDIF- Did we succeed with the transfer? + + + + DeviceClose(); + + if(stop == 0) { + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + SetDlgItemText(mainboxwindow, IDC_0202, templine); + + } else { + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) + + + + DeviceBoxRefocus(); + + if(stop == 0) DeviceBoxCancelEvent(); + + return; + +} // END DeviceBoxOKEvent() + + + + + +void DeviceBoxBrowseEvent() { + + OPENFILENAME filebox; + + char newfilename[256]; + + BOOL returnbool; + + + + filebox.lStructSize = sizeof(filebox); + + filebox.hwndOwner = deviceboxwindow; + + filebox.hInstance = NULL; + + filebox.lpstrFilter = fileselection; + + filebox.lpstrCustomFilter = NULL; + + filebox.nFilterIndex = 0; + + filebox.lpstrFile = newfilename; + + filebox.nMaxFile = 256; + + filebox.lpstrFileTitle = NULL; + + filebox.nMaxFileTitle = 0; + + filebox.lpstrInitialDir = NULL; + + filebox.lpstrTitle = NULL; + + filebox.Flags = OFN_PATHMUSTEXIST + + | OFN_NOCHANGEDIR + + | OFN_HIDEREADONLY; + + filebox.nFileOffset = 0; + + filebox.nFileExtension = 0; + + filebox.lpstrDefExt = NULL; + + filebox.lCustData = 0; + + filebox.lpfnHook = NULL; + + filebox.lpTemplateName = NULL; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, newfilename, 256); + + returnbool = GetOpenFileName(&filebox); + + if(returnbool != FALSE) { + + SetDlgItemText(deviceboxwindow, IDC_0305, newfilename); + + } // ENDIF- User actually selected a name? Save it. + + + + return; + +} // END DeviceBoxBrowseEvent() + + + + + +void DeviceBoxDisplay() { + + char templine[256]; + + HWND itemptr; + + int itemcount; + + + + // Adjust Window Position? + + + + SetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename); + + + + // DeviceBoxDeviceEvent(); // Needed? + + + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + + SetDlgItemText(deviceboxwindow, IDC_0305, templine); + + + + // DeviceBoxFileEvent(); // Needed? + + + + itemptr = GetDlgItem(deviceboxwindow, IDC_0309); // Compression Combo + + itemcount = 0; + + while(compressnames[itemcount] != NULL) { + + ComboBox_AddString(itemptr, compressnames[itemcount]); + + itemcount++; + + } // ENDWHILE- loading compression types into combo box + + ComboBox_SetCurSel(itemptr, 0); // First Selection? + + itemptr = NULL; + + + + CheckDlgButton(deviceboxwindow, IDC_0311, FALSE); // Start unchecked + + + + DeviceInit(); // Initialize device access + +} // END DeviceBoxDisplay() + + + + + +BOOL CALLBACK DeviceBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + deviceboxwindow = window; + + DeviceBoxDisplay(); // Final touches to this window + + return(FALSE); // Let Windows display this window + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner was hit. + + DeviceBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0302: // Device Edit Box + + DeviceBoxDeviceEvent(); + + return(FALSE); + + break; + + + + case IDC_0305: // Filename Edit Box + + DeviceBoxFileEvent(); + + return(FALSE); + + break; + + + + case IDC_0306: // "Browse" Button + + DeviceBoxBrowseEvent(); + + return(TRUE); + + break; + + + + case IDC_0312: // "Make File" Button + + DeviceBoxOKEvent(); + + return(TRUE); + + break; + + + + case IDC_0313: // "Cancel" Button + + DeviceBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which object got the message? + + } // ENDSWITCH msg- What message has been sent to this window? + + + + return(FALSE); + +} // END DeviceBoxCallback() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.h b/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.h new file mode 100644 index 0000000000..bf699f5d1d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/devicebox.h @@ -0,0 +1,41 @@ +/* devicebox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef DEVICEBOX_H +#define DEVICEBOX_H + + +#include // HWND + + +extern HWND deviceboxwindow; + +extern void DeviceBoxDestroy(); +// extern void DeviceBoxUnfocus(); +extern void DeviceBoxRefocus(); +extern void DeviceBoxDisplay(); +extern BOOL CALLBACK DeviceBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2); + + +#endif /* DEVICEBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.c b/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.c new file mode 100644 index 0000000000..28f82eb088 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.c @@ -0,0 +1,119 @@ +/* logfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include + +// #include // open() +// #include // mkdir() +#include // NULL +#include // vsprintf() +#include // va_start(), va_end(), vsprintf() +// #include // open() +// #include // open() + +#include "logfile.h" + + +HANDLE logfile; +char logfiletemp[2048]; + + +void InitLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + CreateDirectory("logs", NULL); + + DeleteFile("logs\\CDVDlog.txt"); + logfile = NULL; +#endif /* VERBOSE LOGFILE */ +} // END InitLog(); + + +int OpenLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + logfile = CreateFile("logs\\CDVDlog.txt", + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if(logfile == INVALID_HANDLE_VALUE) { + logfile = NULL; + return(-1); + } // ENDIF- Failed to open? Say so. +#endif /* VERBOSE LOGFILE */ + + return(0); +} // END OpenLog(); + + +void CloseLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + if(logfile != NULL) { + CloseHandle(logfile); + logfile = NULL; + } // ENDIF- Is the log file actually open? Close it. +#endif /* VERBOSE LOGFILE */ +} // END CloseLog() + + +void PrintLog(const char *fmt, ...) { + DWORD byteswritten; + + // Token comment line +#ifdef VERBOSE_LOGFILE + va_list list; + int len; + + if(logfile == NULL) return; // Log file not open... yet. + + va_start(list, fmt); + vsprintf(logfiletemp, fmt, list); + va_end(list); + + len = 0; + while((len < 2048) && (logfiletemp[len] != 0)) len++; + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); + WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); +#endif /* VERBOSE LOGFILE */ +} // END PrintLog() + +void PrintError(const char *header, DWORD errcode) { +#ifdef VERBOSE_LOGFILE + TCHAR errmsg[256]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, + NULL, + errcode, + 0, + errmsg, + 256, + NULL); + PrintLog("%s: (%u) %s", header, errcode, errmsg); +#endif /* VERBOSE_WARNING_DEVICE */ +} // END PrintError() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.h b/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.h new file mode 100644 index 0000000000..ff6e3b0c1c --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/logfile.h @@ -0,0 +1,39 @@ +/* logfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef LOGFILE_H +#define LOGFILE_H + + +#include // Just for DWORD + + +#define VERBOSE_LOGFILE + + +extern void InitLog(); +extern int OpenLog(); +extern void CloseLog(); +extern void PrintLog(const char *format, ...); +extern void PrintError(const char *header, DWORD errcode); + + +#endif /* LOGFILE_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.c b/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.c new file mode 100644 index 0000000000..fe5488497e --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.c @@ -0,0 +1,309 @@ +/* mainbox.c + * Copyright (C) 2002-2005 CDVDiso 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 +#include // Button_ +#include // NULL + +#include // sprintf() +#include // strcpy() + +#include "conf.h" +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +// #include "imagetype.h" // imagedata[].name +#include "multifile.h" // multinames[] +#include "tablerebuild.h" // IsoTableRebuild() +#include "devicebox.h" +#include "conversionbox.h" +#include "progressbox.h" +#include "screens.h" // DLG_, IDC_ +#include "CDVDiso.h" // progmodule +#include "mainbox.h" + + +const char fileselection[] = "\Disc Image Files (*.bin,*.img,*.iso,*.nrg)\0*.bin;*.img;*.iso;*.nrg\0\All Files (*.*)\0*.*\0\\0\0"; + + +HWND mainboxwindow; +int mainboxstop; + + +void MainBoxDestroy() { + if(progressboxwindow != NULL) { + ProgressBoxDestroy(); + } // ENDIF- Do we have a Progress Window still? + + if(mainboxwindow != NULL) { + EndDialog(mainboxwindow, FALSE); + mainboxwindow = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + // EnableWindow(?) + // gtk_widget_set_sensitive(mainbox.file, FALSE); + // gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.devbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.convbutton, FALSE); + ShowWindow(mainboxwindow, SW_HIDE); +} // END MainBoxUnfocus() + + +void MainBoxFileEvent() { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + returnval = IsIsoFile(templine); + if(returnval == -1) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: ---"); + return; + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a file"); + return; + } // ENDIF- Not a regular file? + + if(returnval == -3) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a valid image file"); + return; + } // ENDIF- Not an Image file? + + if(returnval == -4) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Missing Table File (will rebuild)"); + return; + } // ENDIF- Missing Compression seek table? + + tempfile = IsoFileOpenForRead(templine); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + SetDlgItemText(mainboxwindow, IDC_0204, templine); + tempfile = IsoFileClose(tempfile); + return; +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + MainBoxFileEvent(); + + // gtk_widget_set_sensitive(mainbox.file, TRUE); + // gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.devbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.convbutton, TRUE); + // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); + // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? + ShowWindow(mainboxwindow, SW_SHOW); + SetActiveWindow(mainboxwindow); +} // END MainBoxRefocus() + + +void MainBoxCancelEvent() { + mainboxstop = 1; // Halt all long processess... + + MainBoxDestroy(); + return; +} // END MainBoxCancelEvent() + + +void MainBoxOKEvent() { + char tempisoname[256]; + + MainBoxUnfocus(); + + GetDlgItemText(mainboxwindow, IDC_0202, tempisoname, 256); + if(*(tempisoname) != 0) { + if(IsIsoFile(tempisoname) == -4) { + IsoTableRebuild(tempisoname); + MainBoxRefocus(); + return; + } // ENDIF- Do we need to rebuild an image file's index before using it? + + if(IsIsoFile(tempisoname) < 0) { + MainBoxRefocus(); + MessageBox(mainboxwindow, + "Not a Valid Image File.", + "CDVDisoEFP Message", + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + return; + } // ENDIF- Not an ISO file? Message and Stop here. + } // ENDIF- Do we have a name to check out? + + strcpy(conf.isoname, tempisoname); + if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0209)) == BST_UNCHECKED) { + conf.startconfigure = 0; // FALSE + } else { + conf.startconfigure = 1; // TRUE + } // ENDIF- Was this checkbox unchecked? + if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0210)) == BST_UNCHECKED) { + conf.restartconfigure = 0; // FALSE + } else { + conf.restartconfigure = 1; // TRUE + } // ENDIF- Was this checkbox unchecked? + SaveConf(); + + MainBoxCancelEvent(); + return; +} // END MainBoxOKEvent() + + +void MainBoxBrowseEvent() { + OPENFILENAME filebox; + char newfilename[256]; + BOOL returnbool; + + filebox.lStructSize = sizeof(filebox); + filebox.hwndOwner = mainboxwindow; + filebox.hInstance = NULL; + filebox.lpstrFilter = fileselection; + filebox.lpstrCustomFilter = NULL; + filebox.nFilterIndex = 0; + filebox.lpstrFile = newfilename; + filebox.nMaxFile = 256; + filebox.lpstrFileTitle = NULL; + filebox.nMaxFileTitle = 0; + filebox.lpstrInitialDir = NULL; + filebox.lpstrTitle = NULL; + filebox.Flags = OFN_FILEMUSTEXIST + | OFN_NOCHANGEDIR + | OFN_HIDEREADONLY; + filebox.nFileOffset = 0; + filebox.nFileExtension = 0; + filebox.lpstrDefExt = NULL; + filebox.lCustData = 0; + filebox.lpfnHook = NULL; + filebox.lpTemplateName = NULL; + + GetDlgItemText(mainboxwindow, IDC_0202, newfilename, 256); + returnbool = GetOpenFileName(&filebox); + if(returnbool != FALSE) { + SetDlgItemText(mainboxwindow, IDC_0202, newfilename); + } // ENDIF- User actually selected a name? Save it. + + return; +} // END MainBoxBrowseEvent() + + +void MainBoxDeviceEvent() { + MainBoxUnfocus(); + + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0300), + mainboxwindow, + (DLGPROC)DeviceBoxCallback); + return; +} // END MainBoxBrowseEvent() + + +void MainBoxConversionEvent() { + MainBoxUnfocus(); + + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0400), + mainboxwindow, + (DLGPROC)ConversionBoxCallback); + return; +} // END MainBoxBrowseEvent() + + +void MainBoxDisplay() { + LoadConf(); + + // Adjust window position? + + // We held off setting the name until now... so description would show. + SetDlgItemText(mainboxwindow, IDC_0202, conf.isoname); + if(conf.startconfigure == 0) { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_UNCHECKED); + } else { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_CHECKED); + } // ENDIF- Do we need to uncheck this box? + if(conf.restartconfigure == 0) { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_UNCHECKED); + } else { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_CHECKED); + } // ENDIF- Do we need to uncheck this box? + + // First Time - Show the window + ShowWindow(mainboxwindow, SW_SHOWNORMAL); +} // END MainBoxDisplay() + + +BOOL CALLBACK MainBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2) { + switch(msg) { + case WM_INITDIALOG: + mainboxwindow = window; + MainBoxDisplay(); // In this case, final touches to this window. + ProgressBoxDisplay(); // Create the Progress Box at this time. + return(FALSE); // And let Windows display this window. + break; + + case WM_CLOSE: // The "X" in the upper right corner was hit. + MainBoxCancelEvent(); + return(TRUE); + break; + + case WM_COMMAND: + // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? + + switch(LOWORD(param)) { + case IDC_0202: // Filename Edit Box + MainBoxFileEvent(); // Describe the File's type... + return(FALSE); // Let Windows handle the actual 'edit' processing... + break; + + case IDC_0203: // "Browse" Button + MainBoxBrowseEvent(); + return(TRUE); + break; + + case IDC_0205: // "Ok" Button + MainBoxOKEvent(); + return(TRUE); + break; + + case IDC_0206: // "Get from Disc" Button + MainBoxDeviceEvent(); + return(TRUE); + break; + + case IDC_0207: // "Convert" Button + MainBoxConversionEvent(); + return(TRUE); + break; + + case IDC_0208: // "Cancel" Button + MainBoxCancelEvent(); + return(TRUE); + break; + } // ENDSWITCH param- Which object got the message? + } // ENDSWITCH msg- what message has been sent to this window? + + return(FALSE); // Not a recognized message? Tell Windows to handle it. +} // END MainBoxEventLoop() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.h b/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.h new file mode 100644 index 0000000000..639c9c9730 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/mainbox.h @@ -0,0 +1,43 @@ +/* mainbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef MAINBOX_H +#define MAINBOX_H + + +#include // HWND + + +extern const char fileselection[]; + +extern HWND mainboxwindow; +extern int mainboxstop; + + +extern void MainBoxRefocus(); +extern void MainBoxDisplay(); +extern BOOL CALLBACK MainBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2); + + +#endif /* MAINBOX_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/make.bat b/plugins/cdvd/CDVDisoEFP/src/Win32/make.bat new file mode 100644 index 0000000000..fc4b70f966 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/make.bat @@ -0,0 +1 @@ +mingw32-make -f Makefile.MinGW32 %1 diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/makeming.bat b/plugins/cdvd/CDVDisoEFP/src/Win32/makeming.bat new file mode 100644 index 0000000000..5e988536e2 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/makeming.bat @@ -0,0 +1 @@ +make -f Makefile.MinGW32 %1 diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/plugin.def b/plugins/cdvd/CDVDisoEFP/src/Win32/plugin.def new file mode 100644 index 0000000000..d7b55eab83 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/plugin.def @@ -0,0 +1,21 @@ +EXPORTS + PS2EgetLibType = PS2EgetLibType@0 @2 + PS2EgetLibName = PS2EgetLibName@0 @3 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @4 + CDVDinit = CDVDinit@0 @5 + CDVDshutdown = CDVDshutdown@0 @6 + CDVDopen = CDVDopen@4 @7 + CDVDclose = CDVDclose@0 @8 + CDVDreadTrack = CDVDreadTrack@8 @9 + CDVDgetBuffer = CDVDgetBuffer@0 @10 + CDVDreadSubQ = CDVDreadSubQ@8 @11 + CDVDgetTN = CDVDgetTN@4 @12 + CDVDgetTD = CDVDgetTD@8 @13 + CDVDgetTOC = CDVDgetTOC@4 @14 + CDVDgetDiskType = CDVDgetDiskType@0 @15 + CDVDgetTrayStatus = CDVDgetTrayStatus@0 @16 + CDVDctrlTrayOpen = CDVDctrlTrayOpen@0 @17 + CDVDctrlTrayClose = CDVDctrlTrayClose@0 @18 + CDVDconfigure = CDVDconfigure@0 @19 + CDVDtest = CDVDtest@0 @20 + CDVDabout = CDVDabout@0 @21 diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.c b/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.c new file mode 100644 index 0000000000..0666c6e7b1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.c @@ -0,0 +1,340 @@ +/* progressbox.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // Enable_Button() + +#include // NULL + +#include // PBM_... + + + +#include // sprintf() + +#include // strcat() + +#include // off64_t + + + +#include "CDVDiso.h" // progmodule + +#include "screens.h" + +#include "mainbox.h" + +#include "progressbox.h" + + + + + +HWND progressboxwindow; + +HWND progressboxbar; + +int progressboxstop; + + + +off64_t progressboxmax; + +off64_t progressboxlastpct; + +char progressboxline[256]; + +char progressboxmaxchar[16]; + + + + + +void ProgressBoxDestroy() { + + if(progressboxwindow != NULL) { + + DestroyWindow(progressboxwindow); + + progressboxwindow = NULL; + + progressboxbar = NULL; + + } // ENDIF- Do we have a Progress Window still? + + return; + +} // END ProgressBoxDestroy() + + + + + +void ProgressBoxStart(char *description, off64_t maximum) { + + SetDlgItemText(progressboxwindow, IDC_0501, description); + + + + progressboxmax = maximum; + + sprintf(progressboxmaxchar, "%llu", maximum); + + progressboxlastpct = 100; + + progressboxstop = 0; + + + + ProgressBoxTick(0); + + ShowWindow(progressboxwindow, SW_SHOW); + + SetForegroundWindow(progressboxwindow); + + return; + +} // END ProgressBoxStart() + + + + + +void ProgressBoxTick(off64_t current) { + + off64_t thispct; + + MSG msg; + + BOOL returnbool; + + + + sprintf(progressboxline, "%llu of ", current); + + strcat(progressboxline, progressboxmaxchar); + + SetDlgItemText(progressboxwindow, IDC_0503, progressboxline); + + + + if(progressboxmax >= 30000 ) { + + SendMessage(progressboxbar, PBM_SETPOS, current / (progressboxmax / 30000), 0); + + } else { + + SendMessage(progressboxbar, PBM_SETPOS, (current * 30000) / progressboxmax, 0); + + } // ENDIF- Our maximum # over 30000? (Avoiding divide-by-zero error) + + + + if(progressboxmax >= 100) { + + thispct = current / ( progressboxmax / 100 ); + + if(thispct != progressboxlastpct) { + + sprintf(progressboxline, "%llu%% CDVDisoEFP Progress", thispct); + + SetWindowText(progressboxwindow, progressboxline); + + progressboxlastpct = thispct; + + } // ENDIF- Change in percentage? (Avoiding title flicker) + + } // ENDIF- Our maximum # over 100? (Avoiding divide-by-zero error) + + + + returnbool = PeekMessage(&msg, progressboxwindow, 0, 0, PM_REMOVE); + + while(returnbool != FALSE) { + + TranslateMessage(&msg); + + DispatchMessage(&msg); + + returnbool = PeekMessage(&msg, progressboxwindow, 0, 0, PM_REMOVE); + + } // ENDWHILE- Updating the progress window display as needed + + return; + +} // END ProgressBoxTick() + + + + + +void ProgressBoxStop() { + + ShowWindow(progressboxwindow, SW_HIDE); + + SetWindowText(progressboxwindow, "CDVDisoEFP Progress"); + + return; + +} // END ProgressBoxStop() + + + + + +void ProgressBoxCancelEvent() { + + progressboxstop = 1; + + + + return; + +} // END ProgressBoxCancelEvent() + + + + + +BOOL CALLBACK ProgressBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + return(TRUE); + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner is hit. + + ProgressBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0504: + + ProgressBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which item got the message? + + + + // Hmm. Custom control? (for WM_GETFONT and WM_SETFONT msgs?) + + } // ENDSWITCH msg- what message has been sent to this window? + + + + return(FALSE); // Not a recognized message? Tell Windows to handle it. + +} // ENDIF ProgressBoxCallback() + + + + + +void ProgressBoxDisplay() { + + // ? progressload + + LPARAM range; + + + + InitCommonControls(); + + // progressload. + + // progressload. = ICC_PROGRESS_CLASS + + // InitCommonControlsEx(&progressload); + + + + progressboxwindow = CreateDialog(progmodule, + + MAKEINTRESOURCE(DLG_0500), + + mainboxwindow, + + (DLGPROC) ProgressBoxCallback); + + + + progressboxbar = GetDlgItem(progressboxwindow, IDC_0502); + + range = MAKELPARAM(0, 30000); // Widen the range for granularity + + SendMessage(progressboxbar, PBM_SETRANGE, 0, range); + + + + ShowWindow(progressboxwindow, SW_SHOWNORMAL); + + ShowWindow(progressboxwindow, SW_HIDE); + + return; + +} // END ProgressBoxDisplay() + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.h b/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.h new file mode 100644 index 0000000000..c8a2925f3a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/progressbox.h @@ -0,0 +1,89 @@ +/* progressbox.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef PROGRESSBOX_H + +#define PROGRESSBOX_H + + + + + +#include + + + +#include // off64_t +#include "PS2Etypes.h" + + + + + +extern const char *compressnames[]; + + + +extern HWND progressboxwindow; + +extern int progressboxstop; + + + + + +extern void ProgressBoxStart(char *description, off64_t maximum); + +extern void ProgressBoxTick(off64_t current); + +extern void ProgressBoxStop(); + +extern void ProgressBoxDestroy(); + +extern void ProgressBoxDisplay(); + + + + + +#endif /* MAINBOX_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/screens.h b/plugins/cdvd/CDVDisoEFP/src/Win32/screens.h new file mode 100644 index 0000000000..8824d9c247 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/screens.h @@ -0,0 +1,37 @@ +/* Weditres generated include file. Do NOT edit */ +#include +#define DLG_0100 100 +#define IDC_0104 104 +#define DLG_0200 200 +#define IDC_0202 202 +#define IDC_0203 203 +#define IDC_0204 204 +#define IDC_0205 205 +#define IDC_0206 206 +#define IDC_0207 207 +#define IDC_0208 208 +#define IDC_0209 209 +#define IDC_0210 210 +#define DLG_0300 300 +#define IDC_0302 302 +#define IDC_0303 303 +#define IDC_0305 305 +#define IDC_0306 306 +#define IDC_0307 307 +#define IDC_0309 309 +#define IDC_0311 311 +#define IDC_0312 312 +#define IDC_0313 313 +#define DLG_0400 400 +#define IDC_0402 402 +#define IDC_0403 403 +#define IDC_0404 404 +#define IDC_0406 406 +#define IDC_0408 408 +#define IDC_0409 409 +#define IDC_0410 410 +#define DLG_0500 500 +#define IDC_0501 501 +#define IDC_0502 502 +#define IDC_0503 503 +#define IDC_0504 504 diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/screens.rc b/plugins/cdvd/CDVDisoEFP/src/Win32/screens.rc new file mode 100644 index 0000000000..fe5b24827d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/screens.rc @@ -0,0 +1,82 @@ +/* Wedit generated resource file */ +#ifdef __LCC__ +#include +#endif +#include "screens.h" + + +DLG_0100 DIALOG 2, 2, 140, 59 +STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "About CDVDisoEFP" +FONT 8, "MS Sans Serif" +BEGIN + CTEXT "EFP Iso CDVD Driver v0.6", 101, 11, 6, 118, 12 + CTEXT "Current Author: efp", 102, 12, 16, 118, 12 + CTEXT "Original code by: linuzappz && shadow", 103, 12, 26, 118, 12 + PUSHBUTTON "Ok", IDC_0104, 50, 37, 40, 14 +END + +DLG_0200 DIALOG 4, 2, 241, 73 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDisoEFP Configuration" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Iso File:", 201, 14, 8, 27, 12 + EDITTEXT IDC_0202, 43, 7, 149, 12, ES_AUTOHSCROLL + PUSHBUTTON "Browse", IDC_0203, 197, 6, 34, 12 + CTEXT "File Type: ---", IDC_0204, 10, 21, 220, 12 + PUSHBUTTON "Ok", IDC_0205, 15, 53, 48, 14 + PUSHBUTTON "Get from Disc", IDC_0206, 69, 53, 48, 14 + PUSHBUTTON "Convert", IDC_0207, 123, 53, 48, 14 + PUSHBUTTON "Cancel", IDC_0208, 177, 53, 48, 14 + AUTOCHECKBOX "Show Configure screen when starting emulation", IDC_0209, 13, 32, 179, 10 + AUTOCHECKBOX "Show Configure screen when restarting emulation", IDC_0210, 13, 41, 180, 10 +END + +DLG_0300 DIALOG 3, 1, 255, 124 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDisoEFP ISO Creation" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Source CD/DVD Device:", 301, 10, 8, 80, 12 + EDITTEXT IDC_0302, 92, 7, 153, 12, ES_AUTOHSCROLL + CTEXT "Device Type: ---", IDC_0303, 10, 22, 234, 12 + LTEXT "Iso File:", 304, 11, 39, 26, 12 + EDITTEXT IDC_0305, 37, 38, 172, 12, ES_AUTOHSCROLL + PUSHBUTTON "Browse", IDC_0306, 214, 37, 31, 14 + CTEXT "File Type: ---", IDC_0307, 9, 52, 236, 12 + LTEXT "New File Compression:", 308, 10, 71, 72, 12 + COMBOBOX IDC_0309, 83, 69, 100, 48, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Multiple Files (all under 2 GB):", 310, 10, 83, 94, 12 + AUTOCHECKBOX "", IDC_0311, 107, 83, 40, 10 + PUSHBUTTON "Make File", IDC_0312, 9, 104, 40, 14 + PUSHBUTTON "Cancel", IDC_0313, 205, 104, 40, 14 +END + +DLG_0400 DIALOG 4, 2, 234, 89 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDisoEFP File Conversion" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Iso File:", 401, 11, 7, 25, 12 + EDITTEXT IDC_0402, 37, 7, 146, 12, ES_AUTOHSCROLL + PUSHBUTTON "Browse", IDC_0403, 189, 6, 35, 12 + CTEXT "File Type: ---", IDC_0404, 10, 21, 214, 12 + LTEXT "Change Compression To:", 405, 9, 38, 81, 12 + COMBOBOX IDC_0406, 91, 36, 100, 50, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Multiple Files (all under 2 GB):", 407, 10, 51, 94, 12 + AUTOCHECKBOX "", IDC_0408, 105, 51, 40, 10 + PUSHBUTTON "Change File", IDC_0409, 10, 69, 40, 14 + PUSHBUTTON "Cancel", IDC_0410, 184, 68, 40, 14 +END + +DLG_0500 DIALOG 3, 0, 273, 66 +STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDisoEFP Progress" +FONT 8, "MS Sans Serif" +BEGIN + CTEXT "Twiddling my Thumbs", IDC_0501, 9, 7, 255, 12 + CONTROL "", IDC_0502, "msctls_progress32", 0x1 | WS_CLIPSIBLINGS, 8, 19, 257, 11 + CTEXT "10 of 10", 503, 10, 32, 254, 12 + PUSHBUTTON "Cancel", IDC_0504, 118, 45, 40, 14 +END diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.c b/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.c new file mode 100644 index 0000000000..090767b89d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.c @@ -0,0 +1,187 @@ +/* tablerebuild.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // malloc() + +#include "mainbox.h" +#include "progressbox.h" +#include "isofile.h" +#include "multifile.h" +#include "isocompress.h" // CompressClose() +#include "gzipv1.h" +#include "gzipv2.h" +#include "bzip2v2.h" +#include "bzip2v3.h" +#include "actualfile.h" // ACTUALHANDLENULL + + +void IsoTableRebuild(const char *filename) { + struct IsoFile *datafile; + struct IsoFile *tablefile; + int retval; + char tempblock[65536]; + int stop; + + struct TableData table; + + datafile = IsoFileOpenForRead(filename); + + // Note: This is the start of the "Multifile" process. It's commented + // out so at least we can rebuild 1 part of a multifile at a time. + // IsoNameStripExt(datafile); + // IsoNameStripMulti(datafile); + + // Prep tablefile to hold ONLY a table (no data) + tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + if(tablefile == NULL) { + datafile = IsoFileClose(datafile); + return; + } // ENDIF- Failed to allocate? Abort. + + tablefile->sectorpos = 0; + tablefile->openforread = 0; + tablefile->filebytepos = 0; + tablefile->filebytesize = 0; + tablefile->filesectorpos = 0; + tablefile->filesectorsize = 0; + tablefile->handle = ACTUALHANDLENULL; + + tablefile->namepos = 0; + while((tablefile->namepos < 255) && + (*(filename + tablefile->namepos) != 0)) { + tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); + tablefile->namepos++; + } // ENDWHILE- Copying file name into tablefile + tablefile->name[tablefile->namepos] = 0; // And 0-terminate. + + tablefile->imageheader = datafile->imageheader; + tablefile->blocksize = datafile->blocksize; + tablefile->blockoffset = datafile->blockoffset; + tablefile->cdvdtype = 0; // Not important right now. + + tablefile->compress = datafile->compress; + tablefile->compresspos = datafile->compresspos; + tablefile->numsectors = datafile->numsectors; + tablefile->tabledata = NULL; + + switch(tablefile->compress) { + case 1: + retval = GZipV1OpenTableForWrite(tablefile); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2OpenTableForWrite(tablefile); + break; + case 4: + retval = BZip2V2OpenTableForWrite(tablefile); + break; + case 5: + retval = BZip2V3OpenTableForWrite(tablefile); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Which table are we writing out? + if(retval < 0) { + datafile = IsoFileClose(datafile); + return; + } // ENDIF- Failed to open table file? Abort + + sprintf(tempblock, "Rebuilding table for %s", datafile->name); + ProgressBoxStart(tempblock, datafile->filebytesize); + + stop = 0; + mainboxstop = 0; + progressboxstop = 0; + while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { + switch(datafile->compress) { + case 1: + retval = GZipV1Read(datafile, 0, tempblock); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2Read(datafile, 0, tempblock); + break; + case 4: + retval = BZip2V2Read(datafile, 0, tempblock); + break; + case 5: + retval = BZip2V3Read(datafile, 0, tempblock); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Scanning for the next complete compressed block + + if(retval <= 0) { +#ifdef FUNCTION_WARNING_TABLEREBUILD + PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); +#endif /* FUNCTION_WARNING_TABLEREBUILD */ + stop = 1; + } else { + table.offset = datafile->filebytepos - retval; + table.size = retval; + switch(tablefile->compress) { + case 1: + retval = GZipV1WriteTable(tablefile, table); + break; + case 2: + retval = -1; + break; + case 3: + retval = GZipV2WriteTable(tablefile, table); + break; + case 4: + retval = BZip2V2WriteTable(tablefile, table); + break; + case 5: + retval = BZip2V3WriteTable(tablefile, table); + break; + default: + retval = -1; + break; + } // ENDSWITCH compress- Writing out the relavent table facts + if(retval < 0) stop = 1; + } // ENDIF- Do we have a valid record to write an entry for? + + ProgressBoxTick(datafile->filebytepos); + + if(mainboxstop != 0) stop = 2; + if(progressboxstop != 0) stop = 2; + } // ENDWHILE- Read in the data file and writing a table, 1 block at a time + + ProgressBoxStop(); + + CompressClose(tablefile); // Guarentee the table is flushed and closed. + if(stop != 0) { + ActualFileDelete(tablefile->tablename); + } // ENDIF- Aborted or trouble? Delete the table file + tablefile = IsoFileClose(tablefile); + datafile = IsoFileClose(datafile); + + return; +} // END IsoTableRebuild() diff --git a/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.h b/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.h new file mode 100644 index 0000000000..731911d29a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/Win32/tablerebuild.h @@ -0,0 +1,32 @@ +/* tablerebuild.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef TABLEREBUILD_H +#define TABLEREBUILD_H + + +// #define FUNCTION_WARNING_TABLEREBUILD + + +extern void IsoTableRebuild(const char *filename); + + +#endif /* TABLEREBUILD_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/blockv2.c b/plugins/cdvd/CDVDisoEFP/src/blockv2.c new file mode 100644 index 0000000000..9d7453fb76 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/blockv2.c @@ -0,0 +1,612 @@ +/* blockv2.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "blockv2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BlockV2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BlockV2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + off64_t offset; + + int tableoffset; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct BlockV2Header); + + tableoffset = 0; + + for(i = 0; i < isofile->filesectorsize; i++) { + + retval = BlockV2Seek(isofile, offset); + + if(retval != 0) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Failed to find sector %i!", i); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble finding a lsn id? Fail. + + + + retval = ActualFileRead(isofile->handle, + + sizeof(int), + + (char *) &j); + + if(retval != sizeof(int)) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Failed to read in sector %i!", i); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble reading in a lsn id? Table damaged... fail. + + + + tablemap.table.offset = ConvertEndianUInt(j); // Actually, a lsn. + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += isofile->blocksize + 4; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + isofile->tablehandle = ACTUALHANDLENULL; + + + + return(0); + +} // END BlockV2OpenTableForRead() + + + + + +int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector) { + + int i; + + int tableoffset; + + union TableMap tablemap; + + off64_t filesectorstart; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + if((isofile->filesectorpos >= 0) && + + (isofile->filesectorpos < isofile->filesectorsize)) { + + tableoffset = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); + + if(sector == tablemap.table.offset) { + + return(0); + + } // ENDIF- Are we already pointing at the right sector? + + + + } else { + + isofile->filesectorpos = 0; + + tablemap.table.offset = -1; + + } // ENDIF- Is the file sector pointer within table limits? + + + + filesectorstart = isofile->filesectorpos; + + isofile->filesectorpos++; + + if(isofile->filesectorpos >= isofile->filesectorsize) + + isofile->filesectorpos = 0; + + while((isofile->filesectorpos != filesectorstart) && + + (tablemap.table.offset != sector)) { + + tableoffset = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); + + + + if(tablemap.table.offset != sector) { + + isofile->filesectorpos++; + + if(isofile->filesectorpos >= isofile->filesectorsize) + + isofile->filesectorpos = 0; + + } // ENDIF- Still didn't find it? move to next sector. + + } // ENDWHILE- Scanning through whole sector list (starting at current pos) + + + + if(isofile->filesectorpos == filesectorstart) { + + return(-1); + + } // ENDIF- Did we loop through the whole file... and not find this sector? + + + + return(0); + +} // END BlockV2SeekTable() + + + + + +int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table) { + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + table->offset = sizeof(int) + isofile->blocksize; + + table->offset *= isofile->filesectorpos; + + table->offset += sizeof(struct BlockV2Header) + 4; + + table->size = isofile->blocksize; + + isofile->filesectorpos++; + + return(0); + +} // END BlockV2ReadTable() + + + + + +int BlockV2OpenTableForWrite(struct IsoFile *isofile) { + + return(-1); + +} // END BlockV2OpenTableForWrite() + + + + + +int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table) { + + return(-1); + +} // END BlockV2WriteTable() + + + + + +int BlockV2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BlockV2Header header; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 1; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BlockV2Header), + + (char *) &header); + + if(retval != sizeof(struct BlockV2Header)) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'D') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Not a block dump v2 header!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + // isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorsize = isofile->filebytesize; + + isofile->filesectorsize -= 16; + + isofile->filesectorsize /= (isofile->blocksize + sizeof(int)); + + isofile->filesectorpos = 0; + + return(0); + +} // END BlockV2OpenForRead() + + + + + +int BlockV2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't find the start of the block!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BlockV2Seek() + + + + + +int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + retval = ActualFileRead(isofile->handle, isofile->blocksize, buffer); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != isofile->blocksize) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + return(isofile->blocksize); + +} // END BlockV2Read() + + + + + +int BlockV2OpenForWrite(struct IsoFile *isofile) { + + return(-1); + +} // END BlockV2OpenForWrite() + + + + + +int BlockV2Write(struct IsoFile *isofile, char *buffer) { + + return(-1); + +} // END BlockV2Write() + + + + + +void BlockV2Close(struct IsoFile *isofile) { + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Close()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + if(isofile->handle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BlockV2Close() + diff --git a/plugins/cdvd/CDVDisoEFP/src/blockv2.h b/plugins/cdvd/CDVDisoEFP/src/blockv2.h new file mode 100644 index 0000000000..500e99c0e6 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/blockv2.h @@ -0,0 +1,104 @@ +/* blockv2.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BLOCKV2_H + +#define BLOCKV2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BLOCKV2 + +// #define VERBOSE_WARNING_BLOCKV2 + + + + + +extern int BlockV2OpenTableForRead(struct IsoFile *isofile); + +extern int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BlockV2OpenTableForWrite(struct IsoFile *isofile); + +extern int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BlockV2OpenForRead(struct IsoFile *isofile); + +extern int BlockV2Seek(struct IsoFile *isofile, off64_t sector); + +extern int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BlockV2Close(struct IsoFile *isofile); + + + +extern int BlockV2OpenForWrite(struct IsoFile *isofile); + +extern int BlockV2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BLOCKV2_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/LICENSE b/plugins/cdvd/CDVDisoEFP/src/bzip2/LICENSE new file mode 100644 index 0000000000..b5e5348c55 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/LICENSE @@ -0,0 +1,40 @@ + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + +Julian Seward, Cambridge, UK. +jseward@acm.org +bzip2/libbzip2 version 1.0.3 of 15 February 2005 + diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/README b/plugins/cdvd/CDVDisoEFP/src/bzip2/README new file mode 100644 index 0000000000..f49d9e927b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/README @@ -0,0 +1,185 @@ + +This is the README for bzip2, a block-sorting file compressor, version +1.0.3. This version is fully compatible with the previous public +releases, versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1 and 1.0.2. + +bzip2-1.0.3 is distributed under a BSD-style license. For details, +see the file LICENSE. + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. A statement about Y2K issues +is now included in the file Y2K_INFO. + + +HOW TO BUILD -- UNIX + +Type `make'. This builds the library libbz2.a and then the +programs bzip2 and bzip2recover. Six self-tests are run. +If the self-tests complete ok, carry on to installation: + +To install in /usr/bin, /usr/lib, /usr/man and /usr/include, type + make install +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + make install PREFIX=/xxx/yyy +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + make -n install or + make -n install PREFIX=/xxx/yyy respectively. +The -n instructs make to show the commands it would execute, but +not actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. Sorry. I do encourage library clients to +make the effort to upgrade to use version 1.0, since it is both faster +and more robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web page (http://sources.redhat.com/bzip2). Look there. +However (FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + nmake -f makefile.msc +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program (attempts to) compress data by performing several + non-trivial transformations on it. Unless you are 100% familiar + with *all* the algorithms contained herein, and with the + consequences of modifying them, you should NOT meddle with the + compression or decompression machinery. Incorrect changes can and + very likely *will* lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. Indeed, + I very much hope the opposite is true. bzip2 has been carefully + constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2 does not use any patented + algorithms. However, I do not have the resources to carry out + a patent search. Therefore I cannot give any guarantee of the + above statement. + +End of legalities. + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.0 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.2 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.3 ? + + See the CHANGES file. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1 and +1.0.2, and the changes in bzip2 are largely a result of this feedback. +I thank you for your comments. + +At least for the time being, bzip2's "home" is (or can be reached via) +http://www.bzip.org + +Julian Seward +jseward@bzip.org + +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/blocksort.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/blocksort.c new file mode 100644 index 0000000000..02554cc472 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/blocksort.c @@ -0,0 +1,1141 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. + + To get some idea how the block sorting algorithms in this file + work, read my paper + On the Performance of BWT Sorting Algorithms + in Proceedings of the IEEE Data Compression Conference 2000, + Snowbird, Utah, USA, 27-30 March 2000. The main sort in this + file implements the algorithm called cache in the paper. +--*/ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.c new file mode 100644 index 0000000000..5704dc4bba --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.c @@ -0,0 +1,1616 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + +/*-- + CHANGES + ~~~~~~~ + 0.9.0 -- original version. + + 0.9.0a/b -- no changes in this file. + + 0.9.0c + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +--*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo + (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.0c". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp = ((bzFile *)b)->handle; + + if (b==NULL) {return;} + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.h b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.h new file mode 100644 index 0000000000..d3cc8cfde1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib.h @@ -0,0 +1,323 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo + (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib_private.h b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib_private.h new file mode 100644 index 0000000000..0bc1bfe7cb --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/bzlib_private.h @@ -0,0 +1,537 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.3, 15-Feb-2005" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) +#else +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) /* */ +#define VPrintf0(zf) /* */ +#define VPrintf1(zf,za1) /* */ +#define VPrintf2(zf,za1,za2) /* */ +#define VPrintf3(zf,za1,za2,za3) /* */ +#define VPrintf4(zf,za1,za2,za3,za4) /* */ +#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */ +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/compress.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/compress.c new file mode 100644 index 0000000000..f6ff751f41 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/compress.c @@ -0,0 +1,716 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + +/*-- + CHANGES + ~~~~~~~ + 0.9.0 -- original version. + + 0.9.0a/b -- no changes in this file. + + 0.9.0c + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files +--*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/crctable.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/crctable.c new file mode 100644 index 0000000000..26e424299a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/crctable.c @@ -0,0 +1,144 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/decompress.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/decompress.c new file mode 100644 index 0000000000..ce02afa1cc --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/decompress.c @@ -0,0 +1,666 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/huffman.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/huffman.c new file mode 100644 index 0000000000..a15a2591ab --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/huffman.c @@ -0,0 +1,245 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2/randtable.c b/plugins/cdvd/CDVDisoEFP/src/bzip2/randtable.c new file mode 100644 index 0000000000..27b28d1ab8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2/randtable.c @@ -0,0 +1,124 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2v2.c b/plugins/cdvd/CDVDisoEFP/src/bzip2v2.c new file mode 100644 index 0000000000..e93811af03 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2v2.c @@ -0,0 +1,1052 @@ +/* bzip2v2.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "bzip2/bzlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +// #include "convert.h" + +#include "bzip2v2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BZip2V2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct BZip2V2Table { + + unsigned int size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BZip2V2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t numentries; + + off64_t offset; + + off64_t actual; + + int tableoffset; + + struct BZip2V2Table table; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + numentries = isofile->filesectorsize / 16; + + if((isofile->filesectorsize % 16) != 0) numentries++; + + offset = numentries * sizeof(struct BZip2V2Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(numentries * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct BZip2V2Header); + + tableoffset = 0; + + for(i = 0; i < numentries; i++) { + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct BZip2V2Table), + + (char *) &table); + + if(retval != sizeof(struct BZip2V2Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Failed to read in entry %i!", i); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Trouble reading in a size? Table damaged... fail. + + + + tablemap.table.offset = offset; + + tablemap.table.size = ConvertEndianUInt(table.size); + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += tablemap.table.size; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + return(0); + +} // END BZip2V2OpenTableForRead() + + + + + +int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->filesectorpos = sector; + + isofile->compsector = isofile->filesectorsize + isofile->numsectors; + + return(0); + +} // END BZip2V2SeekTable() + + + + + +int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table) { + + off64_t target; + + union TableMap tablemap; + + off64_t i; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + target = (isofile->filesectorpos / isofile->numsectors) + + * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + target + i); + + + + table->offset = tablemap.table.offset; + + table->size = tablemap.table.size; + + return(0); + +} // END BZip2V2ReadTable() + + + + + +int BZip2V2OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + // isofile->filesectorsize = 0; + + return(0); + +} // END BZip2V2OpenTableForWrite() + + + + + +int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct BZip2V2Table bv2table; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + tempint = table.size; + + bv2table.size = ConvertEndianUInt(tempint); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct BZip2V2Table), + + (char *) &bv2table); + + if(retval != sizeof(struct BZip2V2Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END BZip2V2WriteTable() + + + + + +int BZip2V2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BZip2V2Header header; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 16; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BZip2V2Header), + + (char *) &header); + + if(retval != sizeof(struct BZip2V2Header)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'Z') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Not a bzip2 v2 compression header!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorpos = 0; + + isofile->compsector = header.numblocks + isofile->numsectors; + + return(0); + +} // END BZip2V2OpenForRead() + + + + + +int BZip2V2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BZip2V2Seek() + + + + + +int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned int blocklen; + + bz_stream strm; + + unsigned int tempin; + + char tempblock[65536]; + + unsigned int tempout; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, bytes, 0, 0); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = BZ_OK; + + while((tempin < 65536) && (tempout < isofile->blocksize * isofile->numsectors)) { + + strm.bzalloc = NULL; + + strm.bzfree = NULL; + + strm.opaque = NULL; + + retval = BZ2_bzDecompressInit ( &strm, 0, 0 ); + + if (retval != BZ_OK) return(-1); + + + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 65536; + + + + retval = BZ_OK; + + while((tempin < 65536) && (retval == BZ_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + BZ2_bzDecompressEnd(&strm); + + return(-1); + + } // ENDIF- Trouble reading a piece of compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = BZ2_bzDecompress(&strm); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = 65536 - strm.avail_out; + + BZ2_bzDecompressEnd(&strm); + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != BZ_STREAM_END) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Failed to decode block! (Returned %i", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Not a clean cutoff of a buffer? Say so. + + + + if(tempin == 65536) return(-1); + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END BZip2V2Read() + + + + + +int BZip2V2OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct BZip2V2Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct BZip2V2Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct BZip2V2Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct BZip2V2Header); + + isofile->numsectors = 16; + + isofile->filesectorsize = 0; + + isofile->filesectorpos = 0; + + isofile->compsector = 0; + + return(0); + +} // END BZip2V2OpenForWrite() + + + + + +int BZip2V2Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned int blocklen; + + char tempblock[65536]; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Write()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffCompress(tempblock, + + &blocklen, + + buffer, + + isofile->blocksize * isofile->numsectors, + + 9, 0, 250); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + return(blocklen); // Not in list? Fail. + +} // END BZip2V2Write() + + + + + +void BZip2V2Close(struct IsoFile *isofile) { + + struct BZip2V2Header header; + + struct TableData table; + + int compptr; + + int i; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Close()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + if((isofile->tablehandle != ACTUALHANDLENULL) && + + (isofile->handle != ACTUALHANDLENULL)) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + retval = BZip2V2Write(isofile, isofile->compblock); + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + BZip2V2WriteTable(isofile, table); + + isofile->compsector = isofile->filesectorpos; + + } // ENDIF - still have buffers to write? + + } // ENDIF- Opened for write? Don't forget to flush the file buffer! + + } // ENDIF- Are both the data file and table files open? + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + BZip2V2Write(isofile, isofile->compblock); + + } // ENDIF - still have buffers to write? + + header.id[0] = 'B'; + + header.id[1] = 'Z'; + + header.id[2] = 'V'; + + header.id[3] = '2'; + + header.blocksize = ConvertEndianUInt(isofile->blocksize); + + header.numblocks = ConvertEndianUInt(isofile->filesectorsize); + + header.blockoffset = ConvertEndianUInt(isofile->blockoffset); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct BZip2V2Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BZip2V2Close() + diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2v2.h b/plugins/cdvd/CDVDisoEFP/src/bzip2v2.h new file mode 100644 index 0000000000..8ecd464ce4 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2v2.h @@ -0,0 +1,104 @@ +/* bzip2v2.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BZIP2V2_H + +#define BZIP2V2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BZIP2V2 + +// #define VERBOSE_WARNING_BZIP2V2 + + + + + +extern int BZip2V2OpenTableForRead(struct IsoFile *isofile); + +extern int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BZip2V2OpenTableForWrite(struct IsoFile *isofile); + +extern int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BZip2V2OpenForRead(struct IsoFile *isofile); + +extern int BZip2V2Seek(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BZip2V2Close(struct IsoFile *isofile); + + + +extern int BZip2V2OpenForWrite(struct IsoFile *isofile); + +extern int BZip2V2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BZIP2V2_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2v3.c b/plugins/cdvd/CDVDisoEFP/src/bzip2v3.c new file mode 100644 index 0000000000..2c1b2539c7 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2v3.c @@ -0,0 +1,968 @@ +/* bzip2v3.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "bzip2/bzlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "convert.h" + +#include "bzip2v3.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BZip2V3Header { + + char id[4]; + + unsigned short blocksize; + + off64_t numblocks; + + unsigned short blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct BZip2V3Table { + + off64_t offset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BZip2V3OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t numentries; + + off64_t offset; + + off64_t actual; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + numentries = isofile->filesectorsize / isofile->numsectors; + + if((isofile->filesectorsize % isofile->numsectors) != 0) numentries++; + + offset = numentries * sizeof(struct BZip2V3Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + return(0); + +} // END BZip2V3OpenTableForRead() + + + + + +int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector) { + + off64_t target; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + target = sector / isofile->numsectors; + + target *= sizeof(struct BZip2V3Table); + + retval = ActualFileSeek(isofile->tablehandle, target); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't find sector!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble finding the place? Fail. + + + + isofile->filesectorpos = sector; + + isofile->compsector = isofile->filesectorsize + isofile->numsectors; + + return(0); + +} // END BZip2V3SeekTable() + + + + + +int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table) { + + int retval; + + struct BZip2V3Table temptable; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct BZip2V3Table), + + (char *) &temptable); + + if(retval != sizeof(struct BZip2V3Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't read table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + table->offset = ConvertEndianOffset(temptable.offset); + + table->size = 0; + + return(0); + +} // END BZip2V3ReadTable() + + + + + +int BZip2V3OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + // isofile->filesectorsize = 0; + + return(0); + +} // END BZip2V3OpenTableForWrite() + + + + + +int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct BZip2V3Table bv3table; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + bv3table.offset = ConvertEndianOffset(table.offset); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct BZip2V3Table), + + (char *) &bv3table); + + if(retval != sizeof(struct BZip2V3Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END BZip2V3WriteTable() + + + + + +int BZip2V3OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BZip2V3Header header; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BZip2V3Header), + + (char *) &header); + + if(retval != sizeof(struct BZip2V3Header)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'Z') || + + (header.id[2] != 'V') || + + (header.id[3] != '3')) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Not a bzip2 v3 compression header!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUShort(header.blocksize); + + isofile->filesectorsize = ConvertEndianOffset(header.numblocks); + + isofile->blockoffset = ConvertEndianUShort(header.blockoffset); + + isofile->numsectors = (65536 / isofile->blocksize) - 1; + + isofile->filesectorpos = 0; + + isofile->compsector = header.numblocks + isofile->numsectors; + + return(0); + +} // END BZip2V3OpenForRead() + + + + + +int BZip2V3Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BZip2V3Seek() + + + + + +int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned short tempsize; + + char tempblock[65536]; + + unsigned int blocklen; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Read()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileRead(isofile->handle, + + sizeof(unsigned short), + + (char *) &tempsize); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != sizeof(unsigned short)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempsize = ConvertEndianUShort(tempsize); + + + + retval = ActualFileRead(isofile->handle, tempsize, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != tempsize) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, tempsize, 0, 0); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(tempsize + sizeof(unsigned short)); + +} // END BZip2V3Read() + + + + + +int BZip2V3OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct BZip2V3Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct BZip2V3Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct BZip2V3Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct BZip2V3Header); + + isofile->numsectors = (65536 / isofile->blocksize) - 1; + + isofile->filesectorsize = 0; + + isofile->filesectorpos = 0; + + isofile->compsector = 0; + + return(0); + +} // END BZip2V3OpenForWrite() + + + + + +int BZip2V3Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned int blocklen; + + char tempblock[65536]; + + unsigned short tempsize; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Write()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffCompress(tempblock, + + &blocklen, + + buffer, + + isofile->blocksize * isofile->numsectors, + + 9, 0, 250); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + tempsize = blocklen; + + tempsize = ConvertEndianUShort(tempsize); + + retval = ActualFileWrite(isofile->handle, + + sizeof(unsigned short), + + (char *) &tempsize); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < sizeof(unsigned short)) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", + + retval, sizeof(unsigned short)); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + return(blocklen + sizeof(unsigned short)); // Not in list? Fail. + +} // END BZip2V3Write() + + + + + +void BZip2V3Close(struct IsoFile *isofile) { + + struct BZip2V3Header header; + + struct TableData table; + + int compptr; + + int i; + + int retval; + + unsigned short tempsize; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Close()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + if((isofile->tablehandle != ACTUALHANDLENULL) && + + (isofile->handle != ACTUALHANDLENULL)) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + retval = BZip2V3Write(isofile, isofile->compblock); + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + BZip2V3WriteTable(isofile, table); + + isofile->compsector = isofile->filesectorpos; + + } // ENDIF - still have buffers to write? + + } // ENDIF- Opened for write? Don't forget to flush the file buffer! + + } // ENDIF- Both data file and table file are open? + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + BZip2V3Write(isofile, isofile->compblock); + + } // ENDIF - still have buffers to write? + + header.id[0] = 'B'; + + header.id[1] = 'Z'; + + header.id[2] = 'V'; + + header.id[3] = '3'; + + tempsize = isofile->blocksize; + + header.blocksize = ConvertEndianUShort(tempsize); + + header.numblocks = ConvertEndianOffset(isofile->filesectorsize); + + tempsize = isofile->blockoffset; + + header.blockoffset = ConvertEndianUShort(tempsize); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct BZip2V3Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BZip2V3Close() + diff --git a/plugins/cdvd/CDVDisoEFP/src/bzip2v3.h b/plugins/cdvd/CDVDisoEFP/src/bzip2v3.h new file mode 100644 index 0000000000..ab54e7c567 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/bzip2v3.h @@ -0,0 +1,104 @@ +/* bzip2v3.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BZIP2V3_H + +#define BZIP2V3_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BZIP2V3 + +// #define VERBOSE_WARNING_BZIP2V3 + + + + + +extern int BZip2V3OpenTableForRead(struct IsoFile *isofile); + +extern int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BZip2V3OpenTableForWrite(struct IsoFile *isofile); + +extern int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BZip2V3OpenForRead(struct IsoFile *isofile); + +extern int BZip2V3Seek(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BZip2V3Close(struct IsoFile *isofile); + + + +extern int BZip2V3OpenForWrite(struct IsoFile *isofile); + +extern int BZip2V3Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BZIP2V3_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/convert.c b/plugins/cdvd/CDVDisoEFP/src/convert.c new file mode 100644 index 0000000000..5edbe9ea3f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/convert.c @@ -0,0 +1,118 @@ +/* convert.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include + +#include "convert.h" + + +off64_t ConvertEndianOffset(off64_t number) { +#ifndef CONVERTLITTLEENDIAN + union { + off64_t n; + char c[sizeof(off64_t)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(off64_t); i++) + newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianOffset() + + +unsigned int ConvertEndianUInt(unsigned int number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned int n; + char c[sizeof(unsigned int)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned int); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUInt() + + +unsigned short ConvertEndianUShort(unsigned short number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned short n; + char c[sizeof(unsigned short)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned short); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUShort() + + +// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. +void LBAtoMSF(unsigned long lsn, char *buffer) { + unsigned long templsn; + + if(lsn >= 0xFFFFFFFF - 150) { + *(buffer + 2) = 75-1; + *(buffer + 1) = 60-1; + *(buffer) = 100-1; + } // ENDIF- Out of range? + + templsn = lsn; + templsn += 150; // 2 second offset (75 Frames * 2 Seconds) + *(buffer + 2) = templsn % 75; // Remainder in frames + templsn -= *(buffer + 2); + templsn /= 75; + *(buffer + 1) = templsn % 60; // Remainder in seconds + templsn -= *(buffer + 1); + templsn /= 60; + *(buffer) = templsn; // Leftover quotient in minutes +} // END LBAtoMSF() + + +unsigned long MSFtoLBA(char *buffer) { + unsigned long templsn; + + if(buffer == NULL) return(0xFFFFFFFF); + + templsn = *(buffer); // Minutes + templsn *= 60; + templsn += *(buffer + 1); // Seconds + templsn *= 75; + templsn += *(buffer + 2); // Frames + if(templsn < 150) return(0xFFFFFFFF); + templsn -= 150; // Offset + + return(templsn); +} // END MSFtoLBA() diff --git a/plugins/cdvd/CDVDisoEFP/src/convert.h b/plugins/cdvd/CDVDisoEFP/src/convert.h new file mode 100644 index 0000000000..3933382a0a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/convert.h @@ -0,0 +1,50 @@ +/* convert.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CONVERT_H +#define CONVERT_H + + +#include // off64_t +#include "PS2Etypes.h" +#ifdef __linux__ +#include "endian.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CONVERTLITTLEENDIAN +#endif /* __BYTE_ORDER */ +#endif /* __linux__ */ + +#ifdef _WIN32 +#define CONVERTLITTLEENDIAN +#endif /* _WIN32 */ + +#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) +#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) + + +extern off64_t ConvertEndianOffset(off64_t number); +extern unsigned int ConvertEndianUInt(unsigned int number); +extern unsigned short ConvertEndianUShort(unsigned short number); + +extern void LBAtoMSF(unsigned long lsn, char *buffer); +extern unsigned long MSFtoLBA(char *buffer); + +#endif /* CONVERT_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/ecma119.c b/plugins/cdvd/CDVDisoEFP/src/ecma119.c new file mode 100644 index 0000000000..24f2e4eb1c --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/ecma119.c @@ -0,0 +1,59 @@ +/* ecma119.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include + +// #ifndef __LINUX__ +// #ifdef __linux__ +// #define __LINUX__ +// #endif /* __linux__ */ +// #endif /* No __LINUX__ */ + +// #define CDVDdefs +// #include "PS2Edefs.h" + +#include "ecma119.h" + + +const char ECMA119VolumeIDstdid[] = "CD001\0"; + + +int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume) { + int i; + + if(volume == NULL) return(-1); + + // Volume ID + if(volume->id.voltype != 1) return(-1); // Incorrect volume type + if(volume->id.version != 1) return(-1); // Not a Standard Version? + i = 0; + while((ECMA119VolumeIDstdid[i] != 0) && + (ECMA119VolumeIDstdid[i] == volume->id.stdid[i])) i++; + if(ECMA119VolumeIDstdid[i] != 0) return(-1); // "CD001" did not match? + + // Looks like numblocksle might give us maximum sector count... + // Looks like blocksizele can be compared to blocksize stored in isofile... + + return(0); +} // END ValidateECMA119PrimaryVolume() + + +// Not sure the Partition Volume will be much help... diff --git a/plugins/cdvd/CDVDisoEFP/src/ecma119.h b/plugins/cdvd/CDVDisoEFP/src/ecma119.h new file mode 100644 index 0000000000..494e65908e --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/ecma119.h @@ -0,0 +1,468 @@ +/* ecma119.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ECMA119_H + +#define ECMA119_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + + + +// ECMA119 was sent to ISO to be fast-tracked into ISO 9660 + +// ECMA119 can be found at http://www.ecma.ch, somewhere. + + + +// Throughout these definitions, number pairs in both big-endian and + +// little-endian varieties are stored next to each other. To separate + +// the pairs a 'le' suffix has been attached to little-endian numbers, and + +// a 'be' suffix to big-endian ones. + + + +// All 'unused' entries should be set to (or tested for) 0x00. + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct ECMA119ASCIITime { + + char year[4]; + + char month[2]; + + char day[2]; + + char hour[2]; + + char min[2]; + + char sec[2]; + + char hundredthsec[2]; + + char offsetgmt; // 15 min intervals, from -48 to +52 + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119DateTime { + + unsigned char year; // 1900+year, that is. + + unsigned char month; + + unsigned char day; + + unsigned char hour; + + unsigned char minute; + + unsigned char sec; + + signed char offsetgmt; // In 15 min intervals, from -48 to +52 + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119DirectoryRecord { + + unsigned char reclen; // Length of this record + + unsigned char attlen; // Extended Attribute Record Length + + + + unsigned long externlocle; // Location of Extent + + unsigned long externlocbe; + + + + struct ECMA119DateTime recorded; // Recording Date and Time + + + + unsigned char flags; // File Flags + + unsigned char interleave; // Interleave Gap Size + + + + unsigned short seqnole; // Volume Sequence No. + + unsigned short seqnobe; + + + + unsigned short idlen; + + char id[223]; + + // Note: sometimes a OS uses the end of this record for it's own use. + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119RootDirectoryRecord { + + unsigned char reclen; // Length of this record + + unsigned char attlen; // Extended Attribute Record Length + + + + unsigned long externlocle; // Location of Extent + + unsigned long externlocbe; + + + + struct ECMA119DateTime recorded; // Recording Date and Time + + + + unsigned char flags; // File Flags + + unsigned char interleave; // Interleave Gap Size + + + + unsigned short seqnole; // Volume Sequence No. + + unsigned short seqnobe; + + + + unsigned short idlen; + + char id[1]; // Probably for the '.' (But I'm just guessing :) + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119VolumeID { + + unsigned char voltype; + + // 0 = Boot Record + + // 1 = Primary Volume Descriptor (PrimaryVolume below) + + // 2 = Supplementary Volume Descriptor + + // 3 = Partition Descriptor (PartitionVolume below) + + // 4 - 254 Reserved + + // 255 = End-of-Descriptor-Set + + + + char stdid[5]; // Standard Identifier. Always "CD001" + + + + unsigned char version; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119PrimaryVolume { + + struct ECMA119VolumeID id; + + // id.voltype should be 1 (for this type of volume) + + // id.version should be 1 (standard) + + + + char unused1; + + + + char systemid[32]; + + char volumeid[32]; + + + + char unused2[8]; + + + + unsigned long numblocksle; // Total logical blocks. (on Media? or just + + unsigned long numblocksbe; // in volume?) + + + + char unused3[32]; + + + + unsigned short volumesetsizele; // Volume Set size of the volume. (?) + + unsigned short volumesetsizebe; + + + + unsigned short ordinalle; // Count of which descriptor this is in the Volume + + unsigned short ordinalbe; // set. + + + + unsigned short blocksizele; // Size of a Logical Block + + unsigned short blocksizebe; + + + + unsigned long pathtablesizele; // Path Table Size + + unsigned long pathtablesizebe; + + + + unsigned long typelpathtablelocation; // (le) Location of a Type L Path Table + + + + unsigned long typelopttablelocation; // (le) Location of an Optional Type L + + + + unsigned long typempathtablelocation; // (be) Location of a Type M Path Table + + + + unsigned long typemopttablelocation; // (be) Location of an Optional Type M + + + + struct ECMA119RootDirectoryRecord root; + + + + char volumesetid[128]; // Volume Set ID + + + + char publisher[128]; // Publisher + + + + char datapreparer[128]; // Data Preparer + + + + char application[128]; // Application ID + + + + char copyrightfile[37]; // Copyright File Identifier + + + + char abstractfile[37]; // Abstract File Identifier + + + + char bibliograchicfile[37]; // Bibliographic File Identifier + + + + struct ECMA119ASCIITime volcreatedate; // Date Created + + struct ECMA119ASCIITime volmodifydate; // Last Date Modified + + struct ECMA119ASCIITime volexpiredate; // Date data expires + + struct ECMA119ASCIITime voleffectivedata; // Date data becomes accurate (effective) + + + + unsigned char filestructversion; // File Structure Version + + // Should be 1 = Standard + + + + char unused4; + + + + char applicationuse[512]; // For use by an application + + + + char unused5[653]; // Rounds this out to 2048 bytes... + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +// struct ECMA119PartitionVolume { + +// struct ECMA119VolumeID id; + +// #ifdef _WIN32 + +// }; + +// #else + +// } __attribute__ ((packed)); + +// #endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +extern int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume); + +// extern int ValidateECMA119PartitionVolume(struct ECMA119PartitionVolume volume); + + + + + +#endif /* ECMA119_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/gzipv1.c b/plugins/cdvd/CDVDisoEFP/src/gzipv1.c new file mode 100644 index 0000000000..bdd73de01d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/gzipv1.c @@ -0,0 +1,844 @@ +/* gzipv1.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" + +#include "isocompress.h" // TableData + +#include "actualfile.h" + +#include "gzipv1.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct GZipV1Table { + + unsigned int offset; // Data file position + + unsigned short size; // of Compressed data + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int GZipV1OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = ActualFileSize(isofile->tablehandle) + + / sizeof(struct GZipV1Table); + + + + return(0); + +} // END GZipV1OpenTableForRead() + + + + + +int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector) { + + off64_t target; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + target = sector * sizeof(struct GZipV1Table); + + retval = ActualFileSeek(isofile->tablehandle, target); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't find sector!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble finding the place? Fail. + + + + isofile->filesectorpos = sector; + + return(0); + +} // END GZipV1SeekTable() + + + + + +int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table) { + + int retval; + + struct GZipV1Table temptable; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct GZipV1Table), + + (char *) &temptable); + + if(retval != sizeof(struct GZipV1Table)) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't read table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + table->offset = ConvertEndianUInt(temptable.offset); + + table->size = ConvertEndianUShort(temptable.size); + + isofile->filesectorpos++; + + return(0); + +} // END GZipV1ReadTable() + + + + + +int GZipV1OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV1OpenTableForWrite() + + + + + +int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct GZipV1Table temptable; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + tempint = table.offset; + + temptable.offset = ConvertEndianUInt(tempint); + + temptable.size = ConvertEndianUShort(table.size); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct GZipV1Table), + + (char *) &temptable); + + if(retval != sizeof(struct GZipV1Table)) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END GZipV1WriteTable() + + + + + +int GZipV1OpenForRead(struct IsoFile *isofile) { + + int retval; + + char tempblock[2448]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->blocksize = 2352; + + isofile->blockoffset = 0; // Don't panic. "imagetype.c" will test later. + + isofile->numsectors = 1; // Sectors per block + + + + retval = GZipV1Read(isofile, 2448, tempblock); + + if(retval != 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't decode the first block. Not compressed?"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + + + ActualFileSeek(isofile->handle, 0); // Restart at top of file + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + return(0); + +} // END GZipV1OpenForRead() + + + + + +int GZipV1Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END GZipV1Seek() + + + + + +int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned long blocklen; + + z_stream strm; + + unsigned long tempin; + + char tempblock[2800]; + + unsigned long tempout; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = isofile->blocksize; + + retval = uncompress(buffer, &blocklen, tempblock, bytes); + + if(retval != Z_OK) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = Z_OK; + + while((tempin < 2800) && (tempout < 2352)) { + + + + strm.zalloc = (alloc_func)0; + + strm.zfree = (free_func)0; + + + + strm.next_in = tempblock; + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 2800; + + + + retval = inflateInit(&strm); + + if (retval != Z_OK) return(-1); + + + + while((tempin < 2800) && (retval == Z_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = inflate(&strm, Z_NO_FLUSH); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = strm.total_out; + + inflateEnd(&strm); + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: tempin=%lu tempout=%lu retval=%i", + + tempin, tempout, retval); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != Z_STREAM_END) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Failed to decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + if(tempin == 2800) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Overfilled input buffer for only %llu bytes!", tempout); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END GZipV1Read() + + + + + +int GZipV1OpenForWrite(struct IsoFile *isofile) { + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = 0; + + isofile->filebytepos = 0; + + return(0); + +} // END GZipV1OpenForWrite() + + + + + +int GZipV1Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned long blocklen; + + char tempblock[2800]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Write()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + blocklen = 2800; + + retval = compress2(tempblock, &blocklen, + + buffer, 2352, + + Z_BEST_COMPRESSION); + + if(retval != Z_OK) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + isofile->filesectorpos++; + + + + return(blocklen); + +} // END GZipV1Write() + + + + + +void GZipV1Close(struct IsoFile *isofile) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Close()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + // Flush Write data... if any was held in the compression block area. + + // In this case, though... nothing's held there. + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + return; + +} // END GZipV1Close() + diff --git a/plugins/cdvd/CDVDisoEFP/src/gzipv1.h b/plugins/cdvd/CDVDisoEFP/src/gzipv1.h new file mode 100644 index 0000000000..c47981fc07 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/gzipv1.h @@ -0,0 +1,104 @@ +/* gzipv1.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef GZIPV1_H + +#define GZIPV1_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_GZIPV1 + +// #define VERBOSE_WARNING_GZIPV1 + + + + + +extern int GZipV1OpenTableForRead(struct IsoFile *isofile); + +extern int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int GZipV1OpenTableForWrite(struct IsoFile *isofile); + +extern int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int GZipV1OpenForRead(struct IsoFile *isofile); + +extern int GZipV1Seek(struct IsoFile *isofile, off64_t sector); + +extern int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void GZipV1Close(struct IsoFile *isofile); + + + +extern int GZipV1OpenForWrite(struct IsoFile *isofile); + +extern int GZipV1Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* GZIPV1_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/gzipv2.c b/plugins/cdvd/CDVDisoEFP/src/gzipv2.c new file mode 100644 index 0000000000..3a82174ba4 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/gzipv2.c @@ -0,0 +1,980 @@ +/* gzipv2.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "gzipv2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct GZipV2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct GZipV2Table { + + unsigned int size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int GZipV2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t offset; + + off64_t actual; + + int tableoffset; + + struct GZipV2Table table; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + offset = isofile->filesectorsize * sizeof(struct GZipV2Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct GZipV2Header); + + tableoffset = 0; + + for(i = 0; i < isofile->filesectorsize; i++) { + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct GZipV2Table), + + (char *) &table); + + if(retval != sizeof(struct GZipV2Table)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Failed to read in sector %i!", i); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Trouble reading in a size? Table damaged... fail. + + + + tablemap.table.offset = offset; + + tablemap.table.size = ConvertEndianUInt(table.size); + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += table.size; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + return(0); + +} // END GZipV2OpenTableForRead() + + + + + +int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->filesectorpos = sector; + + return(0); + +} // END GZipV2SeekTable() + + + + + +int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table) { + + off64_t target; + + union TableMap tablemap; + + off64_t i; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + target = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + target + i); + + + + table->offset = tablemap.table.offset; + + table->size = tablemap.table.size; + + isofile->filesectorpos++; + + return(0); + +} // END GZipV2ReadTable() + + + + + +int GZipV2OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV2OpenTableForWrite() + + + + + +int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct GZipV2Table gv2table; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + tempint = table.size; + + gv2table.size = ConvertEndianUInt(tempint); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct GZipV2Table), + + (char *) &gv2table); + + if(retval != sizeof(unsigned int)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END GZipV2WriteTable() + + + + + +int GZipV2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct GZipV2Header header; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 1; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct GZipV2Header), + + (char *) &header); + + if(retval != sizeof(struct GZipV2Header)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'Z') || + + (header.id[1] != ' ') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Not a gzip v2 compression header!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorpos = 0; + + return(0); + +} // END GZipV2OpenForRead() + + + + + +int GZipV2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END GZipV2Seek() + + + + + +int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned long blocklen; + + z_stream strm; + + unsigned long tempin; + + char tempblock[2800]; + + unsigned long tempout; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = isofile->blocksize; + + retval = uncompress(buffer, &blocklen, tempblock, bytes); + + if(retval != Z_OK) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = Z_OK; + + while((tempin < 2800) && (tempout < isofile->blocksize * isofile->numsectors)) { + + + + strm.zalloc = (alloc_func)0; + + strm.zfree = (free_func)0; + + + + strm.next_in = tempblock; + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 2800; + + + + retval = inflateInit(&strm); + + if (retval != Z_OK) return(-1); + + + + while((tempin < 2800) && (retval == Z_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = inflate(&strm, Z_NO_FLUSH); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = 2800 - strm.avail_out; + + inflateEnd(&strm); + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != Z_STREAM_END) return(-1); + + + + if(tempin == 2800) return(-1); + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END GZipV2Read() + + + + + +int GZipV2OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct GZipV2Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct GZipV2Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct GZipV2Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct GZipV2Header); + + isofile->filesectorpos = 0; + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV2OpenForWrite() + + + + + +int GZipV2Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned long blocklen; + + char tempblock[2800]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Write()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + blocklen = 2800; + + retval = compress2(tempblock, &blocklen, + + buffer, isofile->blocksize, + + Z_BEST_COMPRESSION); + + if(retval != Z_OK) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + isofile->filesectorpos++; + + + + return(blocklen); // Not in list? Fail. + +} // END GZipV2Write() + + + + + +void GZipV2Close(struct IsoFile *isofile) { + + struct GZipV2Header header; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Close()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + header.id[0] = 'Z'; + + header.id[1] = ' '; + + header.id[2] = 'V'; + + header.id[3] = '2'; + + tempint = isofile->blocksize; + + header.blocksize = ConvertEndianUInt(tempint); + + tempint = isofile->filesectorsize; + + header.numblocks = ConvertEndianUInt(tempint); + + tempint = isofile->blockoffset; + + header.blockoffset = ConvertEndianUInt(tempint); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct GZipV2Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END GZipV2Close() + diff --git a/plugins/cdvd/CDVDisoEFP/src/gzipv2.h b/plugins/cdvd/CDVDisoEFP/src/gzipv2.h new file mode 100644 index 0000000000..b91219c737 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/gzipv2.h @@ -0,0 +1,104 @@ +/* gzipv2.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef GZIPV2_H + +#define GZIPV2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_GZIPV2 + +// #define VERBOSE_WARNING_GZIPV2 + + + + + +extern int GZipV2OpenTableForRead(struct IsoFile *isofile); + +extern int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int GZipV2OpenTableForWrite(struct IsoFile *isofile); + +extern int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int GZipV2OpenForRead(struct IsoFile *isofile); + +extern int GZipV2Seek(struct IsoFile *isofile, off64_t sector); + +extern int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void GZipV2Close(struct IsoFile *isofile); + + + +extern int GZipV2OpenForWrite(struct IsoFile *isofile); + +extern int GZipV2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* GZIPV2_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/imagetype.c b/plugins/cdvd/CDVDisoEFP/src/imagetype.c new file mode 100644 index 0000000000..8b6785f6a0 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/imagetype.c @@ -0,0 +1,306 @@ +/* imagetype.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // off64_t + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + +#include "actualfile.h" + +#include "imagetype.h" + + + + + +// Based (mostly) off of florin's CDVDbin detection code, twice removed + +// with some additions from the header. + +struct ImageTypes imagedata[] = { + + { "ISO 2048", 2048, 0, 0, 0 }, + + { "YellowBook 2064", 2064, 0, 16, 1 }, + + { "RAW 2064", 2064, 0, 0, 2 }, + + { "GreenBook 2072", 2072, 0, 24, 3 }, + + { "RAW 2072", 2072, 0, 0, 4 }, + + { "RAW 2324", 2324, 0, 0, 5 }, + + { "RAW 2328", 2328, 0, 0, 6 }, + + { "RAW 2336", 2336, 0, 0, 7 }, + + { "GreenBook 2352", 2352, 0, 24, 8 }, + + { "YellowBook 2352", 2352, 0, 16, 9 }, + + { "RedBook 2352", 2352, 0, 0, 10 }, + + { "RAWQ 2448", 2448, 0, 0, 11 }, + + + + { "NERO ISO 2048", 2048, 150*2048, 0, 0 }, + + { "NERO GreenBook 2352", 2352, 150*2352, 24, 8 }, + + { "NERO YellowBook 2352", 2352, 150*2352, 16, 9 }, + + { "NERO RedBook 2352", 2352, 150*2352, 0, 10 }, + + { "NERO RAWQ 2448", 2448, 150*2448, 0, 11 }, + + + + { "Alt ISO 2048", 2048, 8, 0, 0 }, + + { "Alt RAW 2336", 2336, 8, 0, 7 }, + + { "Alt GreenBook 2352", 2352, 8, 24, 8 }, + + { "Alt YellowBook 2352", 2352, 8, 16, 9 }, + + { "Alt RedBook 2352", 2352, 8, 0, 10 }, + + { "Alt RAWQ 2448", 2448, 8, 0, 11 }, + + { NULL, 0, 0, 0, 0 } + +}; + + + + + +#define REDBOOK2352 10 + + + + + +void GetImageType(struct IsoFile *isofile, int imagetype) { + + int temptype; + + int i; + + + + temptype = imagetype; + + if((temptype < 0) || (temptype > 22)) temptype = REDBOOK2352; + + + + i = 0; + + while((i < 40) && (*(imagedata[temptype].name + i) != 0)) { + + isofile->imagename[i] = *(imagedata[temptype].name + i); + + i++; + + } // ENDWHILE- filling in the image name + + isofile->imagename[i] = 0; // And 0-terminate. + + + + isofile->blocksize = imagedata[temptype].blocksize; + + isofile->imageheader = imagedata[temptype].fileoffset; + + isofile->blockoffset = imagedata[temptype].dataoffset; + +} // END GetImageType() + + + + + +int GetImageTypeConvertTo(int imagetype) { + + return(imagedata[imagetype].conversiontype); + +} // END GetImageTypeConvertTo() + + + + + +int DetectImageType(struct IsoFile *isofile) { + + char comparestr[] = "CD001"; + + int newtype; + + off64_t targetpos; + + char teststr[2448]; + + int dataoffset; + + int i; + + int retval; + + + + newtype = 0; + + if(isofile->compress > 0) { + + IsoFileSeek(isofile, 16); + + IsoFileRead(isofile, teststr); + + + + while(imagedata[newtype].name != NULL) { + + if((isofile->blocksize == imagedata[newtype].blocksize) && + + (isofile->imageheader == imagedata[newtype].fileoffset)) { + + dataoffset = imagedata[newtype].dataoffset + 1; + + i = 0; + + while((i < 5) && (teststr[dataoffset + i] == comparestr[i])) i++; + + if(i == 5) { + + GetImageType(isofile, newtype); + + return(newtype); + + } // ENDIF- Did we find a match? + + } // ENDIF- Do these pieces match the compression storage pieces? + + newtype++; + + } // ENDWHILE- looking for the image type that fits the stats + + + + } else { + + while(imagedata[newtype].name != NULL) { + + targetpos = (16 * imagedata[newtype].blocksize) + + + imagedata[newtype].fileoffset + + + imagedata[newtype].dataoffset + + + 1; // Moves to start of string + + retval = ActualFileSeek(isofile->handle, targetpos); + + if(retval == 0) { + + retval = ActualFileRead(isofile->handle, 5, teststr); + + if(retval == 5) { + + i = 0; + + while((i < 5) && (teststr[i] == comparestr[i])) i++; + + if(i == 5) { + + ActualFileSeek(isofile->handle, isofile->imageheader); + + GetImageType(isofile, newtype); + + return(newtype); + + } // ENDIF- Did we find a match? + + } // ENDIF- Could we read in the test string? Cool! Test it. + + } // ENDIF- Could actually get to this point? + + newtype++; + + } // ENDWHILE- looking for the directory header string "CD001" + + ActualFileSeek(isofile->handle, isofile->imageheader); + + } // ENDIF- Do we match type to compression stats? (Or search against raw data?) + + + + GetImageType(isofile, REDBOOK2352); + + return(REDBOOK2352); // Couldn't find it? Guess it's RAW 2352, then. (Audio CD?) + +} // END ImageDetect() + diff --git a/plugins/cdvd/CDVDisoEFP/src/imagetype.h b/plugins/cdvd/CDVDisoEFP/src/imagetype.h new file mode 100644 index 0000000000..20448cc053 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/imagetype.h @@ -0,0 +1,112 @@ +/* imagetype.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef IMAGETYPE_H + +#define IMAGETYPE_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + + + + + +struct ImageTypes { + + char *name; + + off64_t blocksize; + + off64_t fileoffset; + + int dataoffset; + + int conversiontype; // For conversionbox to write a new file as. + +}; + + + +// Note: Worked around since a failure occurred with MSVCRT.DLL. It couldn't + +// printf a char string inside an array of structures. Don't know why. + +// extern struct ImageTypes imagedata[]; + + + + + +extern void GetImageType(struct IsoFile *isofile, int imagetype); + +extern int GetImageTypeConvertTo(int imagetype); + +extern int DetectImageType(struct IsoFile *isofile); + + + + + +#endif /* IMAGETYPE_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/ini.c b/plugins/cdvd/CDVDisoEFP/src/ini.c new file mode 100644 index 0000000000..a00dac8f38 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/ini.c @@ -0,0 +1,689 @@ +/* ini.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() + +#include "logfile.h" +#include "actualfile.h" +#include "ini.h" + + +const char INIext[] = ".ini"; +const char INInewext[] = ".new"; + + +// Returns: position where new extensions should be added. +int INIRemoveExt(char *argname, char *tempname) { + int i; + int j; + int k; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: RemoveExt(%s)", argname); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i <= INIMAXLEN) && (*(argname + i) != 0)) { + *(tempname + i) = *(argname + i); + i++; + } // ENDWHILE- Copying the argument name into a temporary area; + *(tempname + i) = 0; // And 0-terminate + k = i; + k--; + + j = 0; + while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; + j--; + + while((j >= 0) && (*(tempname + k) == INIext[j])) { + k--; + j--; + } // ENDWHILE- Comparing the ending characters to the INI ext. + if(j < 0) { + k++; + i = k; + *(tempname + i) = 0; // 0-terminate, cutting off ".ini" + } // ENDIF- Do we have a match? Then remove the end chars. + + return(i); +} // END INIRemoveExt() + + +void INIAddInExt(char *tempname, int temppos) { + int i; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { + *(tempname + temppos + i) = INIext[i]; + i++; + } // ENDWHILE- Attaching extenstion to filename + *(tempname + temppos + i) = 0; // And 0-terminate +} // END INIAddInExt() + + +void INIAddOutExt(char *tempname, int temppos) { + int i; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { + *(tempname + temppos + i) = INInewext[i]; + i++; + } // ENDWHILE- Attaching extenstion to filename + *(tempname + temppos + i) = 0; // And 0-terminate +} // END INIAddInExt() + + +// Returns number of bytes read to get line (0 means end-of-file) +int INIReadLine(ACTUALHANDLE infile, char *buffer) { + int charcount; + int i; + char tempin[2]; + int retflag; + int retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: ReadLine()"); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + i = 0; + tempin[1] = 0; + retflag = 0; + + while((i < INIMAXLEN) && (retflag < 2)) { + retval = ActualFileRead(infile, 1, tempin); + charcount++; + if(retval != 1) { + retflag = 2; + charcount--; + + } else if(tempin[0] == '\n') { + retflag = 2; + + } else if(tempin[0] >= ' ') { + *(buffer + i) = tempin[0]; + i++; + } // ENDLONGIF- How do we react to the next character? + } // ENDWHILE- Loading up on characters until an End-of-Line appears + *(buffer + i) = 0; // And 0-terminate + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Line: %s", buffer); +#endif /* VERBOSE_FUNCTION_INI */ + + return(charcount); +} // END INIReadLine() +// Note: Do we need to back-skip a char if something other \n follows \r? + + +// Returns: number of bytes to get to start of section (or -1) +int INIFindSection(ACTUALHANDLE infile, char *section) { + int charcount; + int i; + int retflag; + int retval; + char scanbuffer[INIMAXLEN+1]; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: FindSection(%s)", section); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + retflag = 0; + + while(retflag == 0) { + retval = INIReadLine(infile, scanbuffer); + if(retval == 0) return(-1); // EOF? Stop here. + + if(scanbuffer[0] == '[') { + i = 0; + while((i < INIMAXLEN) && + (*(section + i) != 0) && + (*(section + i) == scanbuffer[i + 1])) i++; + if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { + if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { + retflag = 1; + } // ENDIF- End marks look good? Return successful. + } // ENDIF- Do we have a section match? + } // ENDIF- Does this look like a section header? + + if(retflag == 0) charcount += retval; + } // ENDWHILE- Scanning lines for the correct [Section] header. + + return(charcount); +} // END INIFindSection() + + +// Returns: number of bytes to get to start of keyword (or -1) +int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { + int charcount; + int i; + int j; + int retflag; + int retval; + char scanbuffer[INIMAXLEN+1]; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + retflag = 0; + + while(retflag == 0) { + retval = INIReadLine(infile, scanbuffer); + if(retval == 0) return(-1); // EOF? Stop here. + if(scanbuffer[0] == '[') return(-1); // New section? Stop here. + + i = 0; + while((i < INIMAXLEN) && + (*(keyword + i) != 0) && + (*(keyword + i) == scanbuffer[i])) i++; + if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { + if(scanbuffer[i] == '=') { + retflag = 1; + if(buffer != NULL) { + i++; + j = 0; + while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { + *(buffer + j) = scanbuffer[i]; + i++; + j++; + } // ENDWHILE- Copying the value out to the outbound buffer. + *(buffer + j) = 0; // And 0-terminate. + } // ENDIF- Return the value as well? + } // ENDIF- End marks look good? Return successful. + } // ENDIF- Do we have a section match? + + if(retflag == 0) charcount += retval; + } // ENDWHILE- Scanning lines for the correct [Section] header. + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Value: %s", buffer); +#endif /* VERBOSE_FUNCTION_INI */ + + return(charcount); +} // END INIFindKeyWord() + + +// Returns: number of bytes left to write... (from charcount back) +int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { + char buffer[4096]; + int i; + int chunk; + int retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Copy(%i)", charcount); +#endif /* VERBOSE_FUNCTION_INI */ + + i = charcount; + chunk = 4096; + if(i < chunk) chunk = i; + while(chunk > 0) { + retval = ActualFileRead(infile, chunk, buffer); + if(retval <= 0) return(i); // Trouble? Stop here. + if(retval < chunk) chunk = retval; // Short block? Note it. + + retval = ActualFileWrite(outfile, chunk, buffer); + if(retval <= 0) return(i); // Trouble? Stop here. + i -= retval; + if(retval < chunk) return(i); // Short block written? Stop here. + + chunk = 4096; + if(i < chunk) chunk = i; + } // ENDWHILE- Copying a section of file across, one chunk at a time. + + return(0); +} // END INICopyToPos() + + +int INISaveString(char *file, char *section, char *keyword, char *value) { + char inname[INIMAXLEN+1]; + char outname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + ACTUALHANDLE outfile; + int i; + int retval; + char templine[INIMAXLEN+1]; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + if(keyword == NULL) return(-1); + if(value == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", + file, section, keyword, value); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + INIAddInExt(inname, filepos); + INIAddOutExt(outname, filepos); + + filepos = 0; + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new file"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(inname); + if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. + + sprintf(templine, "[%s]\r\n", section); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + if(retval < i) { + ActualFileDelete(inname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + return(0); + } // ENDIF- No input file? Create a brand new .ini file then. + + retval = INIFindSection(infile, section); + if(retval < 0) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new section"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); // Move ini to beginning of file... + INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... + + sprintf(templine, "\r\n[%s]\r\n", section); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + if(retval < i) { + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); + } // ENDIF- Couldn't find the section? Make a new one! + + filepos = retval; + ActualFileSeek(infile, filepos); + filepos += INIReadLine(infile, templine); // Get section line's byte count + + retval = INIFindKeyword(infile, keyword, NULL); + if(retval < 0) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + ActualFileSeek(infile, filepos); + retval = INIReadLine(infile, templine); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + while((retval > 0) && (templine[i] == '=')) { + filepos += retval; + retval = INIReadLine(infile, templine); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + } // ENDWHILE- skimming to the bottom of the section + + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + } else { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: replacing keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + filepos += retval; // Position just before old version of keyword + + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + INIReadLine(infile, templine); // Read past old keyword/value... + + // Replace with new value + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + } // ENDIF- Need to add a new keyword? + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); +} // END INISaveString() + + +int INILoadString(char *file, char *section, char *keyword, char *buffer) { + char inname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + int retval; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + if(keyword == NULL) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", + file, section, keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + INIAddInExt(inname, filepos); + + filepos = 0; + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) return(-1); + + retval = INIFindSection(infile, section); + if(retval < 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Didn't find it? Abort. + + retval = INIFindKeyword(infile, keyword, buffer); + if(retval < 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Didn't find it? Abort. + + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(0); +} // END INILoadString() + + +int INIRemove(char *file, char *section, char *keyword) { + char inname[INIMAXLEN+1]; + char outname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + ACTUALHANDLE outfile; + char templine[INIMAXLEN+1]; + int i; + int retval; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Remove(%s, %s, %s)", + file, section, keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + INIAddInExt(inname, filepos); + INIAddOutExt(outname, filepos); + + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) return(-1); + + retval = INIFindSection(infile, section); + if(retval == -1) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't even find the section? Abort + + filepos = retval; + if(keyword == NULL) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: removing section"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to the section? Abort. + + templine[0] = 0; + retval = 1; + while((retval > 0) && (templine[0] != '[')) { + retval = INIReadLine(infile, templine); + } // ENDWHILE- Read to the start of the next section... or EOF. + + if(templine[0] == '[') { + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + } // ENDIF- Are there other sections after this one? Save them then. + + } else { + filepos = retval; + ActualFileSeek(infile, filepos); + filepos += INIReadLine(infile, templine); // Get section line's byte count + + retval = INIFindKeyword(infile, keyword, NULL); + if(retval == -1) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't find the keyword? Abort + filepos += retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: removing keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + INIReadLine(infile, templine); // Read (and discard) the keyword line + } // ENDIF- Wipe out the whole section? Or just a keyword? + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); +} // END INIRemove() + + +int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { + char numvalue[INIMAXLEN+1]; + + sprintf(numvalue, "%u", value); + return(INISaveString(file, section, keyword, numvalue)); +} // END INISaveUInt() + + +int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { + char numvalue[INIMAXLEN+1]; + int retval; + unsigned int value; + // unsigned int sign; // Not needed in unsigned numbers + int pos; + + if(buffer == NULL) return(-1); + *(buffer) = 0; + + retval = INILoadString(file, section, keyword, numvalue); + if(retval < 0) return(retval); + + value = 0; + // sign = 1; // Start positive + pos = 0; + + // Note: skip leading spaces? (Shouldn't have to, I hope) + + // if(numvalue[pos] == '-') { + // pos++; + // sign = -1; + // } // ENDIF- Negative sign check + + while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { + if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? + + if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { + value *= 10; + value += numvalue[pos] - '0'; + pos++; + } else { + numvalue[pos] = 0; + } // ENDIF- Add a digit in? Or stop searching for digits? + } // ENDWHILE- Adding digits of info to our ever-increasing value + + // value *= sign + *(buffer) = value; + return(0); +} // END INILoadUInt() diff --git a/plugins/cdvd/CDVDisoEFP/src/ini.h b/plugins/cdvd/CDVDisoEFP/src/ini.h new file mode 100644 index 0000000000..fbd2349cf5 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/ini.h @@ -0,0 +1,64 @@ +/* ini.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef INI_H +#define INI_H + + +// #ifndef __LINUX__ +// #ifdef __linux__ +// #define __LINUX__ +// #endif /* __linux__ */ +// #endif /* No __LINUX__ */ + +// #define CDVDdefs +// #include "PS2Edefs.h" + + +// File format: +// [section] +// keyword=value + +// file - Name of the INI file +// section - Section within the file +// keyword - Identifier for a value +// value - value to store with a keyword in a section in the file +// buffer - place to retrieve the value of a keyword + +// return values: 0 = success, -1 = failure + + +// #define VERBOSE_FUNCTION_INI + +#define INIMAXLEN 255 + + +extern int INISaveString(char *file, char *section, char *keyword, char *value); +extern int INILoadString(char *file, char *section, char *keyword, char *buffer); + +extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); +extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); + +// NULL in the keyword below removes the whole section. +extern int INIRemove(char *file, char *section, char *keyword); + + +#endif /* INI_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/isocompress.c b/plugins/cdvd/CDVDisoEFP/src/isocompress.c new file mode 100644 index 0000000000..5385342027 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/isocompress.c @@ -0,0 +1,914 @@ +/* isocompress.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "isofile.h" + +#include "actualfile.h" + +#include "gzipv1.h" + +#include "blockv2.h" + +#include "gzipv2.h" + +#include "bzip2v2.h" + +#include "bzip2v3.h" + +#include "isocompress.h" + + + + + +const char *compressnames[] = { + + "No Compression", + + ".Z (zlib) for speed", + + ".BZ2 (bzip2) for speed", + + ".bz2 (bzip2) for size", + + NULL }; // Compress types 0, 3, 4, and 5 + + + +const char *compressdesc[] = { + + "", + + " zlib orig", + + " block.dump", + + " zlib speed", + + " bzip2 speed", + + " bzip2 size", + + NULL }; + + + +const char *compressid[] = { + + "BVD2", + + "Z V2", + + "BZV2", + + "BZV3", + + NULL }; // Starts at compress type 2 + + + +struct CompressExt compressext[] = { + + { ".z", 1 }, + + { ".Z", 1 }, + + { ".bz2", 5 }, + + { ".BZ2", 3 }, + + { ".bZ2", 3 }, + + { ".Bz2", 3 }, + + { ".bz", 3 }, + + { ".BZ", 3 }, + + { ".bZ", 3 }, + + { ".Bz", 3 }, + + { ".dump", 2 }, + + { NULL, 0 } + +}; + + + + + +int IsoNameStripCompress(struct IsoFile *isofile) { + + int tempext; + + int tempnamepos; + + int tempextpos; + + int retmethod; + + + + retmethod = 0; + + tempext = 0; + + while(compressext[tempext].name != NULL) { + + tempextpos = 0; + + while(*(compressext[tempext].name + tempextpos) != 0) tempextpos++; + + + + tempnamepos = isofile->namepos; + + while((tempnamepos > 0) && (tempextpos > 0) && + + (isofile->name[tempnamepos - 1] == *(compressext[tempext].name + tempextpos - 1))) { + + tempnamepos--; + + tempextpos--; + + } // ENDWHILE- Comparing one extension to the end of the file name + + if(tempextpos == 0) { + + isofile->namepos = tempnamepos; // Move name pointer in front of ext. + + return(compressext[tempext].method); // Found a match... say which one. + + } else { + + tempext++; // Next ext in the list to test... + + } // ENDIF- Did we find a match? + + } // ENDWHILE- looking through extension list + + + + return(0); // No compress extension found. + +} // END IsoNameStripCompress() + + + + + +int CompressOpenForRead(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1OpenForRead(isofile); + + if(retval >= 0) retval = GZipV1OpenTableForRead(isofile); + + break; + + case 2: + + retval = BlockV2OpenForRead(isofile); + + if(retval >= 0) retval = BlockV2OpenTableForRead(isofile); + + break; + + case 3: + + retval = GZipV2OpenForRead(isofile); + + if(retval >= 0) retval = GZipV2OpenTableForRead(isofile); + + break; + + case 4: + + retval = BZip2V2OpenForRead(isofile); + + if(retval >= 0) retval = BZip2V2OpenTableForRead(isofile); + + break; + + case 5: + + retval = BZip2V3OpenForRead(isofile); + + if(retval >= 0) retval = BZip2V3OpenTableForRead(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressOpenForRead() + + + + + +int CompressSeek(struct IsoFile *isofile, off64_t sector) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Seek(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1SeekTable(isofile, sector); + + break; + + case 2: + + retval = BlockV2SeekTable(isofile, sector); + + break; + + case 3: + + retval = GZipV2SeekTable(isofile, sector); + + break; + + case 4: + + retval = BZip2V2SeekTable(isofile, sector); + + break; + + case 5: + + retval = BZip2V3SeekTable(isofile, sector); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressSeek() + + + + + +int CompressRead(struct IsoFile *isofile, char *buffer) { + + struct TableData table; + + int retval; + + int compptr; + + int i; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Read()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = GZipV1Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = GZipV1Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + case 2: + + retval = BlockV2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BlockV2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = BlockV2Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + + + case 3: + + retval = GZipV2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = GZipV2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = GZipV2Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + case 4: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + + + retval = BZip2V2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BZip2V2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = BZip2V2Read(isofile, table.size, isofile->compblock); + + isofile->compsector = isofile->filesectorpos / isofile->numsectors; + + isofile->compsector *= isofile->numsectors; + + } // ENDIF- Are we still on track? + + } // ENDIF- Did we have to read in another block? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { + + retval = -1; + + } else { + + for(i = 0; i < isofile->blocksize; i++) + + *(buffer + i) = isofile->compblock[compptr + i]; + + isofile->filesectorpos++; + + } // ENDIF- Not a good buffer pointer? Say so. + + } // ENDIF- Do we have a valid buffer to draw from? + + break; + + + + case 5: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + + + if(isofile->filesectorpos != isofile->compsector + isofile->numsectors) { + + retval = BZip2V3ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BZip2V3Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + } // ENDIF- Not the next block in the batch? Seek then. + + + + if(retval >= 0) { + + retval = BZip2V3Read(isofile, 0, isofile->compblock); + + isofile->compsector = isofile->filesectorpos / isofile->numsectors; + + isofile->compsector *= isofile->numsectors; + + } // ENDIF- Are we still on track? + + } // ENDIF- Did we have to read in another block? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { + + retval = -1; + + } else { + + for(i = 0; i < isofile->blocksize; i++) + + *(buffer + i) = isofile->compblock[compptr + i]; + + isofile->filesectorpos++; + + } // ENDIF- Not a good buffer pointer? Say so. + + } // ENDIF- Do we have a valid buffer to draw from? + + break; + + + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + if(retval >= 0) retval = isofile->blocksize; + + return(retval); + +} // END CompressRead() + + + + + +void CompressClose(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Close()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + GZipV1Close(isofile); + + break; + + case 2: + + BlockV2Close(isofile); + + break; + + case 3: + + GZipV2Close(isofile); + + break; + + case 4: + + BZip2V2Close(isofile); + + break; + + case 5: + + BZip2V3Close(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return; + +} // END CompressClose() + + + + + +int CompressOpenForWrite(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1OpenForWrite(isofile); + + if(retval >= 0) retval = GZipV1OpenTableForWrite(isofile); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2OpenForWrite(isofile); + + if(retval >= 0) retval = GZipV2OpenTableForWrite(isofile); + + break; + + case 4: + + retval = BZip2V2OpenForWrite(isofile); + + if(retval >= 0) retval = BZip2V2OpenTableForWrite(isofile); + + break; + + case 5: + + retval = BZip2V3OpenForWrite(isofile); + + if(retval >= 0) retval = BZip2V3OpenTableForWrite(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressOpenForWrite() + + + + + +int CompressWrite(struct IsoFile *isofile, char *buffer) { + + struct TableData table; + + int compptr; + + int retval; + + int i; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Write()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1Write(isofile, buffer); + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = GZipV1WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + break; + + + + case 2: + + retval = -1; + + break; + + + + case 3: + + retval = GZipV2Write(isofile, buffer); + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = GZipV2WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + break; + + + + case 4: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + retval = BZip2V2Write(isofile, isofile->compblock); + + isofile->compsector += isofile->numsectors; + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = BZip2V2WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + } // ENDIF- Do we have a full buffer to write out? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = 0; i < isofile->blocksize; i++) + + isofile->compblock[compptr + i] = *(buffer + i); + + } // ENDIF- Do we have a valid buffer to draw from? + + isofile->filesectorpos++; + + break; + + + + case 5: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + retval = BZip2V3Write(isofile, isofile->compblock); + + isofile->compsector += isofile->numsectors; + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = BZip2V3WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + } // ENDIF- Do we have a full buffer to write out? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = 0; i < isofile->blocksize; i++) + + isofile->compblock[compptr + i] = *(buffer + i); + + } // ENDIF- Do we have a valid buffer to draw from? + + isofile->filesectorpos++; + + break; + + + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + if(retval >= 0) retval = isofile->blocksize; + + return(retval); + +} // END CompressWrite() + diff --git a/plugins/cdvd/CDVDisoEFP/src/isocompress.h b/plugins/cdvd/CDVDisoEFP/src/isocompress.h new file mode 100644 index 0000000000..f566d0f43c --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/isocompress.h @@ -0,0 +1,158 @@ +/* isocompress.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ISOCOMPRESS_H + +#define ISOCOMPRESS_H + + + + + +#include + + + +#include "isofile.h" + +#include "actualfile.h" + + + + + +// #define VERBOSE_FUNCTION_ISOCOMPRESS + +// #define VERBOSE_WARNING_ISOCOMPRESS + + + + + +struct CompressExt { + + const char *name; + + int method; + +}; + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct TableData { + + off64_t offset; + + unsigned short size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +union TableMap { + + struct TableData table; + + char ch[sizeof(struct TableData)]; + +}; + + + + + +extern const char *compressnames[]; + +extern const char *compressdesc[]; + + + +extern struct CompressExt compressext[]; + + + + + +extern int IsoNameStripCompress(struct IsoFile *isofile); + + + +// 0 = success, -1 = Failure w/data, -2 = Failure w/table + +extern int CompressOpenForRead(struct IsoFile *isofile); + + + +extern int CompressSeek(struct IsoFile *isofile, off64_t sector); + +extern int CompressRead(struct IsoFile *isofile, char *buffer); + +extern void CompressClose(struct IsoFile *isofile); + + + +extern int CompressOpenForWrite(struct IsoFile *isofile); + +extern int CompressWrite(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* ISOCOMPRESS_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/isofile.c b/plugins/cdvd/CDVDisoEFP/src/isofile.c new file mode 100644 index 0000000000..a655b597d2 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/isofile.c @@ -0,0 +1,1292 @@ +/* isofile.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "multifile.h" + +#include "isocompress.h" + +#include "actualfile.h" + +#include "imagetype.h" + +#include "toc.h" + +#include "ecma119.h" + +#include "isofile.h" + + + + + +const char *isofileext[] = { + + ".iso", + + ".bin", + + ".img", + + NULL + +}; + + + +const char *cdname = "CD-XA001\0"; + +const char *playstationid = "PLAYSTATION\0"; + +// const char ps1/2name? + + + +// Internal functions + + + +void IsoNameStripExt(struct IsoFile *isofile) { + + int tempext; + + int tempnamepos; + + int tempextpos; + + + + tempext = 0; + + while(isofileext[tempext] != NULL) { + + tempextpos = 0; + + while(*(isofileext[tempext] + tempextpos) != 0) tempextpos++; + + + + tempnamepos = isofile->namepos; + + while((tempnamepos > 0) && (tempextpos > 0) && + + (isofile->name[tempnamepos - 1] == *(isofileext[tempext] + tempextpos - 1))) { + + tempnamepos--; + + tempextpos--; + + } // ENDWHILE- Comparing one extension to the end of the file name + + if(tempextpos == 0) { + + isofile->namepos = tempnamepos; // Move name pointer in front of ext. + + tempext = 0; // ... and test the list all over again. + + } else { + + tempext++; // Next ext in the list to test... + + } // ENDIF- Did we find a match? + + } // ENDWHILE- looking through extension list + +} // END IsoNameStripExt() + + + + + +// External functions + + + +struct IsoFile *IsoFileOpenForRead(const char *filename) { + + struct IsoFile *newfile; + + int retval; + + int i; + + char tempblock[2448]; + + struct tocTN toctn; + + struct tocTD toctd; + +// union { + +// struct ECMA119PrimaryVolume vol; + +// char ch[sizeof(struct ECMA119PrimaryVolume)]; + +// } *volcheck; + + union { + + struct ECMA119PrimaryVolume *vol; + + char *ch; + + } volcheck; + + + + newfile = NULL; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(newfile == NULL) return(NULL); + + + + newfile->sectorpos = 0; + + newfile->openforread = 1; // Read-only ISO + + newfile->filebytepos = 0; + + newfile->filesectorpos = 0; + + newfile->blocksize = 0; // Flags as non-detected yet (Compress vs. Image) + + newfile->tabledata = NULL; + + + + newfile->namepos = 0; + + while((newfile->namepos < 255) && + + (*(filename + newfile->namepos) != 0)) { + + newfile->name[newfile->namepos] = *(filename + newfile->namepos); + + newfile->namepos++; + + } // ENDWHILE- copying the file name in... + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + IsoNameStripExt(newfile); // Ex: -I00.Z[.bin] + + + + // File Compression name detection + + newfile->compress = IsoNameStripCompress(newfile); // Ex: -I00.bin[.Z] + + newfile->compresspos = newfile->namepos; + + + + // Test File name compression + + retval = -1; + + if(newfile->compress > 0) { + + retval = CompressOpenForRead(newfile); + + if(retval == -1) CompressClose(newfile); + + } // ENDIF- Have a compression type hint? Test it out + + + + if(retval == -1) { + + newfile->compress = 5; + + while((newfile->compress > 0) && (retval == -1)) { + + retval = CompressOpenForRead(newfile); + + if(retval == -1) { + + CompressClose(newfile); + + newfile->compress--; + + } // ENDIF- Failed to open? Close it... and try the next one. + + } // ENDWHILE- Trying to find a compression scheme that will work... + + + + if(newfile->compress == 0) { + + newfile->handle = ActualFileOpenForRead(newfile->name); + + if(newfile->handle == ACTUALHANDLENULL) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Failed to open? Abort. + + newfile->filebytesize = ActualFileSize(newfile->handle); + + } // ENDIF- No compression? Open it uncompressed. + + } // ENDIF- Temp- failed to open? Abort... + + + + // Compressed data file with no table? Return prematurely... + + // Condition detection: compress > 0, tablehandle == ACTUALHANDLENULL + + if(retval == -2) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Data file with no table!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(newfile); + + } // ENDIF- + + + + newfile->imagetype = DetectImageType(newfile); + + + + if(newfile->compress == 0) { + + newfile->filesectorsize = newfile->filebytesize / newfile->blocksize; + + } // ENDIF- Now that blocksize is known, raw file sectors can be figured out + + + + IsoNameStripExt(newfile); // Ex: -I00[.bin].Z + + + + IsoNameStripMulti(newfile); // Ex: [-I00].bin.Z + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Filename: %s", filename); + + if(newfile->multi > 0) PrintLog("CDVD isofile: Multiple <2GB files."); + + PrintLog("CDVD isofile: Compression Method: %s", + + compressdesc[newfile->compress]); + + PrintLog("CDVD isofile: Image Type: %s", + + newfile->imagename); + + PrintLog("CDVD isofile: Block Size: %lli", newfile->blocksize); + + PrintLog("CDVD isofile: Total Sectors (of first file): %lli", + + newfile->filesectorsize); + +#endif /* VERBOSE_DISC_INFO */ + + + + // Load a TOC from a .toc file (is there is one) + + retval = IsoLoadTOC(newfile); + + if(retval == 0) return(newfile); + + + + // Get the volume sector for disc type test + + retval = IsoFileSeek(newfile, 16); + + if(retval < 0) { + + newfile = IsoFileClose(newfile); + + return(NULL); + + } // ENDIF- Could not find the directory sector? Abort. + + retval = IsoFileRead(newfile, tempblock); + + if(retval < 0) { + + newfile = IsoFileClose(newfile); + + return(NULL); + + } // ENDIF- Could not read the directory sector? Abort. + + + + volcheck.ch = tempblock; + + volcheck.ch += newfile->blockoffset; + + if(ValidateECMA119PrimaryVolume(volcheck.vol) != 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Not an ISO9660 disc! Music CD perhaps?"); + +#endif /* VERBOSE_DISC_INFO */ + + newfile->cdvdtype = CDVD_TYPE_CDDA; + + + + } else { + + // Is this a playstation image? + + i = 0; + + while((*(playstationid + i) != 0) && + + (*(playstationid + i) == tempblock[newfile->blockoffset + 8 + i])) i++; + + if(*(playstationid + i) != 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Not a Playstation Disc!"); + +#endif /* VERBOSE_DISC_INFO */ + + newfile->cdvdtype = CDVD_TYPE_DVDV; + + } else { + + newfile->cdvdtype = CDVD_TYPE_PS2DVD; + + } // ENDIF- Is this not a Playstation 1 image? + + // Sidenote: if the emulator is just playing Playstation 2 images, we could + + // just invalidate the image file right here. + + } // ENDIF- Not an ISO9660 disc? Assume Music CD. + + + + if(newfile->cdvdtype == CDVD_TYPE_PS2DVD) { + + // Is this a Playstation CD image? + + i = 0; + + while((*(cdname + i) != 0) && + + (*(cdname + i) == tempblock[newfile->blockoffset + 1024 + i])) i++; + + if(*(cdname + i) == 0) { + + newfile->cdvdtype = CDVD_TYPE_PSCD; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a Playstation 1 CD."); + +#endif /* VERBOSE_DISC_INFO */ + + } else { + + if(newfile->blocksize != 2048) { + + newfile->cdvdtype = CDVD_TYPE_PS2CD; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a Playstation 2 CD."); + +#endif /* VERBOSE_DISC_INFO */ + + } else { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + } // ENDIF- Is the blocksize not 2048? CD image then. + + } // ENDIF- Is this a PS1 CD image? + + } // ENDIF- Is this a Playstation image? + + volcheck.ch = NULL; + + + + if((newfile->cdvdtype == CDVD_TYPE_DVDV) && + + (newfile->blocksize == 2352)) newfile->cdvdtype = CDVD_TYPE_CDDA; + + + + // Slap together a TOC based on the above guesswork. + + IsoInitTOC(newfile); + + if((newfile->cdvdtype != CDVD_TYPE_PS2DVD) && + + (newfile->cdvdtype != CDVD_TYPE_DVDV)) { + + toctn.strack = 1; + + toctn.etrack = 1; + + IsoAddTNToTOC(newfile, toctn); + + + + toctd.type = 0; + + toctd.lsn = newfile->filesectorsize; + + IsoAddTDToTOC(newfile, 0xAA, toctd); + + + + toctd.type = 0; // ? + + if(newfile->cdvdtype == CDVD_TYPE_CDDA) { + + toctd.type = CDVD_AUDIO_TRACK; // Music track assumed + + } else { + + toctd.type = CDVD_MODE1_TRACK; // Data track assumed + + } // ENDIF- Is this track a music or data track? + + toctd.lsn = 0; + + IsoAddTDToTOC(newfile, 1, toctd); + + } // ENDIF- Is this a CD? Single track for all sectors + + + + return(newfile); + +} // END IsoFileOpenForRead() + + + + + +int IsIsoFile(const char *filename) { + + int retval; + + struct IsoFile *tempfile; + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsIsoFile()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + retval = IsActualFile(filename); + + if(retval < 0) return(retval); // Not a regular file? Report it. + + + + tempfile = NULL; + + tempfile = IsoFileOpenForRead(filename); + + if(tempfile == NULL) return(-3); // Not an image file? Report it. + + + + retval = 0; + + if((tempfile->compress > 0) && + + (tempfile->tablehandle == ACTUALHANDLENULL) && + + (tempfile->tabledata == NULL)) retval = -4; + + + + tempfile = IsoFileClose(tempfile); + + return(retval); + +} // END IsIsoFile() + + + + + +int IsoFileSeek(struct IsoFile *file, off64_t sector) { + + int retval; + + + + if(file == NULL) return(-1); + + if(sector < 0) return(-1); + + + + if(sector == file->sectorpos) return(0); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileSeek(%llu)", sector); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->multi > 0) { + + retval = MultiFileSeek(file, sector); + + } else if(file->compress > 0) { + + retval = CompressSeek(file, sector); + + } else { + + retval = ActualFileSeek(file->handle, + + (sector * file->blocksize) + file->imageheader); + + if(retval == 0) { + + file->filesectorpos = sector; + + file->filebytepos = (sector * file->blocksize) + file->imageheader; + + } // ENDIF- Succeeded? Adjust internal pointers + + } // ENDLONGIF- Seek right file? Or compressed block? Or Raw block? + + + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble finding the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + + + file->sectorpos = sector; + + return(0); + +} // END IsoFileSeek() + + + + + +int IsoFileRead(struct IsoFile *file, char *block) { + + int retval; + + + + if(file == NULL) return(-1); + + if(block == NULL) return(-1); + + if(file->openforread == 0) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileRead(%i)", file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->multi > 0) { + + retval = MultiFileRead(file, block); + + } else if(file->compress > 0) { + + retval = CompressRead(file, block); + + } else { + + if(file->sectorpos >= file->filesectorsize) return(-1); + + retval = ActualFileRead(file->handle, + + file->blocksize, + + block); + + if(retval > 0) file->filebytepos += retval; + + if(retval == file->blocksize) file->filesectorpos++; + + } // ENDLONGIF- Read right file? Or compressed block? Or Raw block? + + + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble reading the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + + + if(retval < file->blocksize) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Short block! Got %i out of %i bytes", + + retval, file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Didn't get enough bytes? Say so! + + + + file->sectorpos++; + + return(0); + +} // END IsoFileRead() + + + + + +struct IsoFile *IsoFileClose(struct IsoFile *file) { + + if(file == NULL) return(NULL); + + + + if(file->handle != ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileClose()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->compress > 0) { + + CompressClose(file); + + } else { + + ActualFileClose(file->handle); + + file->handle = ACTUALHANDLENULL; + + } // ENDIF- Compressed File? Close (and flush) compression too. + + } // ENDIF- Open Handle? Close the file + + + + free(file); + + return(NULL); + +} // END IsoFileClose() + + + + + +struct IsoFile *IsoFileOpenForWrite(const char *filename, + + int imagetype, + + int multi, + + int compress) { + + struct IsoFile *newfile; + + + + newfile = NULL; + + + + if(filename == NULL) return(NULL); + + if((imagetype < 0) || (imagetype > 11)) return(NULL); + + if((compress < 0) || (compress > 5)) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileOpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(newfile == NULL) return(NULL); + + + + newfile->sectorpos = 0; + + newfile->openforread = 0; // Write-only file + + newfile->filebytesize = 0; + + newfile->filebytepos = 0; + + newfile->filesectorsize = 0; + + newfile->filesectorpos = 0; + + + + // if(toc != NULL) { + + // for(i = 0; i < 2048; i++) newfile->toc[i] = *(toc + i); + + // } else { + + // for(i = 0; i < 2048; i++) newfile->toc[i] = 0; + + // } // ENDIF- Do we have a PS2 Table of Contents to save out as well? + + + + newfile->namepos = 0; + + while((newfile->namepos < 255) && + + (*(filename + newfile->namepos) != 0)) { + + newfile->name[newfile->namepos] = *(filename + newfile->namepos); + + newfile->namepos++; + + } // ENDWHILE- copying the file name in... + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + IsoNameStripExt(newfile); + + IsoNameStripCompress(newfile); + + IsoNameStripExt(newfile); + + IsoNameStripMulti(newfile); + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + newfile->imagetype = imagetype; + + GetImageType(newfile, imagetype); + + newfile->cdvdtype = CDVD_TYPE_PS2DVD; // Does it matter here? Nope. + + + + newfile->multi = multi; + + if(newfile->multi > 0) { + + newfile->name[newfile->namepos + 0] = '-'; + + newfile->name[newfile->namepos + 1] = 'I'; + + newfile->name[newfile->namepos + 2] = '0'; + + newfile->name[newfile->namepos + 3] = '0'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->multipos = newfile->namepos + 3; + + newfile->namepos += 4; + + newfile->multistart = 0; + + newfile->multiend = 0; + + newfile->multinow = 0; + + newfile->multioffset = 0; + + newfile->multisectorend[0] = 0; + + } // ENDIF- Are we creating a multi-file? + + + + newfile->compress = compress; + + switch(newfile->compress) { + + case 1: + + case 3: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'Z'; + + newfile->name[newfile->namepos + 2] = 0; + + newfile->namepos += 2; + + break; + + + + case 2: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'd'; + + newfile->name[newfile->namepos + 2] = 'u'; + + newfile->name[newfile->namepos + 3] = 'm'; + + newfile->name[newfile->namepos + 4] = 'p'; + + newfile->name[newfile->namepos + 5] = 0; + + newfile->namepos += 5; + + break; + + + + case 4: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'B'; + + newfile->name[newfile->namepos + 2] = 'Z'; + + newfile->name[newfile->namepos + 3] = '2'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->namepos += 4; + + break; + + + + case 5: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'b'; + + newfile->name[newfile->namepos + 2] = 'z'; + + newfile->name[newfile->namepos + 3] = '2'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->namepos += 4; + + break; + + + + case 0: + + default: + + break; + + } // ENDSWITCH compress- which compression extension should we add on? + + + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 4] = 0; + + if(newfile->blocksize == 2048) { + + newfile->name[newfile->namepos + 1] = 'i'; + + newfile->name[newfile->namepos + 2] = 's'; + + newfile->name[newfile->namepos + 3] = 'o'; + + } else { + + newfile->name[newfile->namepos + 1] = 'b'; + + newfile->name[newfile->namepos + 2] = 'i'; + + newfile->name[newfile->namepos + 3] = 'n'; + + } // ENDIF- Is this a true ISO (or just a raw BIN file?) + + newfile->namepos += 4; + + + + if(IsActualFile(newfile->name) == 0) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Does the destination file already exist? + + + + if(newfile->compress > 0) { + + CompressOpenForWrite(newfile); + + if((newfile->handle != ACTUALHANDLENULL) && + + (newfile->tablehandle == ACTUALHANDLENULL)) { + + ActualFileClose(newfile->handle); + + newfile->handle = ACTUALHANDLENULL; + + } // ENDIF Data file created, but table file stopped? Close and remove data + + } else { + + newfile->handle = ActualFileOpenForWrite(newfile->name); + + } // ENDIF- Writing out a compressed file? + + + + if(newfile->handle == ACTUALHANDLENULL) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Couldn't create file? Abort + + + + return(newfile); + +} // END IsoFileOpenForWrite() + + + + + +int IsoFileWrite(struct IsoFile *file, char *block) { + + int byteswritten; + + + + if(file == NULL) return(-1); + + if(block == NULL) return(-1); + + if(file->openforread == 1) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + byteswritten = 0; + + if(file->multi > 0) { + + byteswritten = MultiFileWrite(file, block); + + } else if(file->compress > 0) { + + byteswritten = CompressWrite(file, block); + + } else { + + byteswritten = ActualFileWrite(file->handle, + + file->blocksize, + + block); + + if(byteswritten > 0) file->filebytepos += byteswritten; + + if(byteswritten == file->blocksize) file->filesectorpos++; + + } // ENDLONGIF- Write to different file? Compressed block? or Raw? + + if(byteswritten < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble writing the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + if(file->filebytepos > file->filebytesize) + + file->filebytesize = file->filebytepos; + + + + if(byteswritten < file->blocksize) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Short block! Wrote %i out of %i bytes", + + byteswritten, file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Didn't write enough bytes? Say so! + + if(file->filesectorpos > file->filesectorsize) + + file->filesectorsize = file->filesectorpos; + + + + file->sectorpos++; + + return(0); + +} // END IsoFileWrite() + + + + + +struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file) { + + int i; + + + + if(file == NULL) return(NULL); + + + + if(file->handle != ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileCloseAndDelete()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->compress > 0) { + + CompressClose(file); + + } else { + + ActualFileClose(file->handle); + + file->handle = ACTUALHANDLENULL; + + } // ENDIF- Compressed File? Close (and flush) compression too. + + } // ENDIF- Open Handle? Close the file + + + + if(file->multi == 1) { + + for(i = file->multistart; i <= file->multiend; i++) { + + file->name[file->multipos] = '0' + i; + + ActualFileDelete(file->name); + + if(file->compress > 0) { + + file->tablename[file->multipos] = '0' + i; + + ActualFileDelete(file->tablename); + + } // ENDIF- Get the table file too? + + } // NEXT i- iterate through each multi-file name, removing it. + + } else { + + ActualFileDelete(file->name); + + if(file->compress > 0) { + + ActualFileDelete(file->tablename); + + } // ENDIF- Get the table file too? + + } // ENDIF- Do we have to remove multiple files? + + + + free(file); + + return(NULL); + +} // END IsoFileCloseAndDelete() + diff --git a/plugins/cdvd/CDVDisoEFP/src/isofile.h b/plugins/cdvd/CDVDisoEFP/src/isofile.h new file mode 100644 index 0000000000..93dff0e6c7 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/isofile.h @@ -0,0 +1,246 @@ +/* isofile.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ISOFILE_H + +#define ISOFILE_H + + + + + +#include // off64_t + + + +#include "actualfile.h" + + + + + +// #define VERBOSE_FUNCTION_ISOFILE + +#define VERBOSE_DISC_INFO + + + + + +struct IsoFile { + + // *** Primary Data area + + char name[256]; + + int namepos; // Used for detection of components within name + + ACTUALHANDLE handle; + + off64_t sectorpos; // Overall. + + // blocks (char [2352]) provided by users + + + + // *** Derived Stats from Primary Data + + int openforread; // 1 = Yes, 0 = No + + off64_t filebytesize; + + off64_t filebytepos; + + off64_t filesectorsize; + + off64_t filesectorpos; + + int cdvdtype; // for GetDiskType call + + char toc[2048]; // for GetTOC call + + + + // From imagetype.h + + int imagetype; + + char imagename[40]; + + off64_t imageheader; // Header bytes in every file... + + off64_t blocksize; // sized to add quickly to other off64_t counters + + int blockoffset; // Where to place data in block + + + + // from isocompress.h + + int compress; // Compression Method used (0 = none, 1...) + + int compresspos; // Start pos of ".Z", ".BZ", etc... + + char tablename[256]; + + ACTUALHANDLE tablehandle; + + char compblock[65536]; // Temporary storage of uncompressed sectors. + + off64_t compsector; // First sector of the compblock[] + + off64_t numsectors; // Number of sectors in a compression block + + char *tabledata; // Table holding area + + + + // From multifile.h + + int multi; // 0 = Single File, 1 = Multiple Files + + int multipos; // Position of Multi # ('0'-'9') + + off64_t multisectorend[10]; // Ending sector of each file... + + off64_t multioffset; // To help with seek calls. Sector offset. + + int multistart; // Starting file number (0-1) + + int multiend; // Ending file number (?-9) + + int multinow; // Current open file number + + + + // *** (Specific) Compression Data area + +}; + + + + + +// Read-only section + +// IsoFiles opened for read are treated as random-access files + + + +extern int IsIsoFile(const char *filename); + +// Returns an image type (positive or zero) or an error (negative) + + + +extern struct IsoFile *IsoFileOpenForRead(const char *filename); + +// Will seek blocksize and compression method on it's own. + + + +extern int IsoFileSeek(struct IsoFile *file, off64_t sector); + +// Sector, not byte. + + + +extern int IsoFileRead(struct IsoFile *file, char *block); + +// Buffers should be at least of "blocksize" size. 2352 bytes, please. + + + + + +// Write-only section + +// IsoFiles opened for write are treated as sequential files (still written + +// out a block at a time, though, to be read in later as random-access) + +// No plans are made to make writes random-access at this time. + + + +extern struct IsoFile *IsoFileOpenForWrite(const char *filename, + + int imagetype, + + int multi, + + int compress); + + + +extern int IsoFileWrite(struct IsoFile *file, char *block); + +// Uncompressed buffers, please. + +// Will compress with this call (if it's necessary.) + + + + + +// Calls used for all Isofiles + + + +extern struct IsoFile *IsoFileClose(struct IsoFile *file); + +// Use return variable to NULL the file pointer. + +// Ex: lastfile = IsoFileClose(lastfile); + + + +extern struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file); + +// For failure to finish writing out a file(set). + + + + + +#endif /* ISOFILE_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/multifile.c b/plugins/cdvd/CDVDisoEFP/src/multifile.c new file mode 100644 index 0000000000..9c261740df --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/multifile.c @@ -0,0 +1,578 @@ +/* multifile.c + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // off64_t + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "isofile.h" + +#include "isocompress.h" + +#include "actualfile.h" + +#include "multifile.h" + + + + + +#define FILESIZELIMIT 2000000000 + + + + + +char *multinames[] = { + + "", + + "Multiple ", + + NULL }; + + + + + +void IsoNameStripMulti(struct IsoFile *isofile) { + + isofile->multi = 0; + + if(isofile->namepos < 2) return; // Not enough digits + + if(isofile->name[isofile->namepos - 1] < '0') return; // Ex: -I0[0] + + if(isofile->name[isofile->namepos - 1] > '1') return; // Ex: -I0[1] + + if(isofile->name[isofile->namepos - 2] != '0') return; // Ex: -I[0]0 + + + + isofile->multi = 1; + + isofile->multipos = isofile->namepos - 1; + + isofile->namepos -= 2; + + isofile->multistart = isofile->name[isofile->multipos] - '0'; + + isofile->multiend = isofile->multistart; + + isofile->multinow = isofile->multistart; + + isofile->multisectorend[0] = 0; // Sometimes the file name starts with '1' + + isofile->multisectorend[isofile->multistart] = isofile->filesectorsize; + + isofile->multioffset = 0; + + + + if(isofile->namepos < 1) return; + + if(isofile->name[isofile->namepos - 1] != 'I') return; // Ex: -[I]00 + + isofile->namepos--; + + + + if(isofile->namepos < 2) return; // Filename doesn't start with '-' + + if(isofile->name[isofile->namepos - 1] != '-') return; // Ex: [-]I00 + + isofile->namepos--; + + + + return; + +} // END IsoNameStripMulti() + + + + + +int MultiFileSeek(struct IsoFile *isofile, off64_t sector) { + + int multinext; + + int retval; + + off64_t tempfilesector; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileSeek(%llu)", sector); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + multinext = isofile->multinow; + + + + // Do we need to back up a file or so? + + while((multinext > isofile->multistart) && + + (sector < isofile->multisectorend[multinext - 1])) multinext--; + + + + // Do we need to go forward a file or two (that we know about?) + + while((multinext < isofile->multiend) && + + (sector >= isofile->multisectorend[multinext])) multinext++; + + + + // Do we need to go forward a file or two (that we *don't* know about?) + + while((multinext < 9) && + + (sector >= isofile->multisectorend[multinext])) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + multinext++; + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + retval = CompressOpenForRead(isofile); + + + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + retval = 0; + + if(isofile->handle == ACTUALHANDLENULL) { + + retval = -1; + + + + } else { + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Failed to open the file raw? + + } // ENDIF- Compressed or non-compressed? What a question. + + + + if(retval < 0) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + multinext--; + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + CompressOpenForRead(isofile); + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Compressed or non-compressed? What a question. + + + + isofile->multinow = multinext; + + if(isofile->multinow == 0) { + + isofile->multioffset = 0; + + } else { + + isofile->multioffset = isofile->multisectorend[isofile->multinow - 1]; + + } // ENDIF- At the start of the list? Offset 0. + + return(-1); + + } // ENDIF- Failed to open next in series? Revert and abort. + + + + isofile->multinow = multinext; + + isofile->multiend = multinext; + + isofile->multioffset = isofile->multisectorend[multinext - 1]; + + isofile->multisectorend[multinext] = isofile->multisectorend[multinext - 1] + + + isofile->filesectorsize; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD multifile: File %i opened, %llu sectors found (%llu sectors total)", + + multinext, + + isofile->filesectorsize, + + isofile->multisectorend[multinext]); + +#endif /* VERBOSE_DISC_INFO */ + + } // ENDWHILE- searching through new files for a high enough end-mark + + + + if(multinext != isofile->multinow) { + +#ifdef VERBOSE_WARNING_MULTIFILE + + PrintLog("CDVD multifile: Changing to File %i", multinext); + +#endif /* VERBOSE_WARNING_MULTIFILE */ + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + CompressOpenForRead(isofile); + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) return(-1); // Couldn't re-open? + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Compressed or non-compressed? What a question. + + + + isofile->multinow = multinext; + + if(multinext == 0) { + + isofile->multioffset = 0; + + } else { + + isofile->multioffset = isofile->multisectorend[multinext - 1]; + + } // ENDIF- At the start of the list? Offset 0. + + } // ENDIF- Not looking at the same file? Change to the new one. + + + + tempfilesector = sector - isofile->multioffset; + + if(isofile->compress > 0) { + + return(CompressSeek(isofile, tempfilesector)); + + } else { + + retval = ActualFileSeek(isofile->handle, + + (tempfilesector * isofile->blocksize) + + + isofile->imageheader); + + if(retval == 0) { + + isofile->filesectorpos = sector; + + isofile->filebytepos = (sector * isofile->blocksize) + + + isofile->imageheader; + + } // ENDIF- Sucessful? Adjust internals + + return(retval); + + } // ENDIF- Seek a position in a compressed file? + +} // END MultiFileSeek() + + + + + +int MultiFileRead(struct IsoFile *isofile, char *block) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileRead()"); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + if(isofile->filesectorpos >= isofile->filesectorsize) + + MultiFileSeek(isofile, isofile->sectorpos); + + + + if(isofile->compress > 0) { + + return(CompressRead(isofile, block)); + + } else { + + retval = ActualFileRead(isofile->handle, isofile->blocksize, block); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval == isofile->blocksize) isofile->filesectorpos++; + + return(retval); + + } // ENDIF- Read a compressed sector? + +} // END MultiFileRead() + + + + + +int MultiFileWrite(struct IsoFile *isofile, char *block) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileWrite()"); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + if(isofile->filebytesize + isofile->blocksize > FILESIZELIMIT) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + if(isofile->multinow == 9) return(-1); // Over 10 files? Overflow! + + + + isofile->multioffset += isofile->filesectorsize; + + isofile->multinow++; + + isofile->multiend++; + +#ifdef VERBOSE_WARNING_MULTIFILE + + PrintLog("CDVD multifile: Changing to File %i", isofile->multinow); + +#endif /* VERBOSE_WARNING_MULTIFILE */ + + + + isofile->name[isofile->multipos] = '0' + isofile->multinow; + + if(isofile->compress > 0) { + + retval = CompressOpenForWrite(isofile); + + } else { + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + retval = -1; + + } else { + + retval = 0; + + isofile->filebytesize = 0; + + isofile->filesectorsize = 0; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Trouble opening next file? + + } // ENDIF- Opening the next compressed file? (Or uncompressed?) + + if(retval < 0) return(-1); // Couldn't open another file? Abort. + + } // ENDIF- Hit the size limit? Move on to next file... + + + + if(isofile->compress > 0) { + + return(CompressWrite(isofile, block)); + + } else { + + retval = ActualFileWrite(isofile->handle, isofile->blocksize, block); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval == isofile->blocksize) isofile->filesectorpos++; + + return(retval); + + } // ENDIF- Write a compressed sector? + +} // END MultiFileWrite() + diff --git a/plugins/cdvd/CDVDisoEFP/src/multifile.h b/plugins/cdvd/CDVDisoEFP/src/multifile.h new file mode 100644 index 0000000000..66b81778a5 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/multifile.h @@ -0,0 +1,106 @@ +/* multifile.h + + * Copyright (C) 2002-2005 PCSX2 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 + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef MULTIFILE_H + +#define MULTIFILE_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + + + + + +// #define VERBOSE_FUNCTION_MULTIFILE + +// #define VERBOSE_WARNING_MULTIFILE + + + + + +extern char *multinames[]; + + + + + +extern void IsoNameStripMulti(struct IsoFile *isofile); + + + +extern int MultiFileSeek(struct IsoFile *isofile, off64_t sector); + +extern int MultiFileRead(struct IsoFile *isofile, char *block); + + + +extern int MultiFileWrite(struct IsoFile *isofile, char *block); + + + + + +#endif /* MULTIFILE_H */ + diff --git a/plugins/cdvd/CDVDisoEFP/src/toc.c b/plugins/cdvd/CDVDisoEFP/src/toc.c new file mode 100644 index 0000000000..7a87b87df1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/toc.c @@ -0,0 +1,358 @@ +/* toc.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // off64_t + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" +#include "convert.h" +#include "isofile.h" +#include "actualfile.h" + +#include "toc.h" + + +// PCSX2's .toc file format: +// 1 unsigned char - CDVD_TYPE_???? +// 1 tocTN +// As many tocTDs as it takes. + + +extern void IsoInitTOC(struct IsoFile *isofile) { + int i; + off64_t sectorsize; + + if(isofile == NULL) return; + +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: IsoInitTOC()"); +#endif /* VERBOSE_FUNCTION_TOC */ + + if(isofile->multi > 0) { + sectorsize = isofile->multisectorend[isofile->multiend]; + } else { + sectorsize = isofile->filesectorsize; + } // ENDIF- Establish largest sector from multifile? (or single file?) + + for(i = 0; i < 2048; i++) isofile->toc[i] = 0; + switch(isofile->cdvdtype) { + case CDVD_TYPE_DVDV: + case CDVD_TYPE_PS2DVD: + if((isofile->filesectorsize > (2048*1024)) || + (isofile->multi > 0)) { + isofile->toc[0] = 0x24; // Dual-Sided DVD (?) + isofile->toc[4] = 0x41; + isofile->toc[5] = 0x95; + } else { + isofile->toc[0] = 0x04; // Single-Sided DVD (?) + isofile->toc[4] = 0x86; + isofile->toc[5] = 0x72; + } // ENDIF- Too many sectors for a single-layered disc? + + isofile->toc[1] = 0x02; + isofile->toc[2] = 0xF2; + isofile->toc[3] = 0x00; + + isofile->toc[16] = 0x00; + isofile->toc[17] = 0x03; + isofile->toc[18] = 0x00; + isofile->toc[19] = 0x00; + return; // DVD's don't have tracks. Might track multisession later... + break; + + case CDVD_TYPE_PS2CD: + case CDVD_TYPE_PSCD: + isofile->toc[0] = 0x41; + break; + case CDVD_TYPE_CDDA: + isofile->toc[0] = 0x01; + break; + default: + break; + } // ENDSWITCH isofile->cdvdtype - Which TOC for which type? + + // CD Details here... (tracks and stuff) + isofile->toc[2] = 0xA0; + isofile->toc[7] = 0x01; // Starting Track No. + isofile->toc[12] = 0xA1; + isofile->toc[17] = 0x01; // Ending Track No. + + isofile->toc[22] = 0xA2; + LBAtoMSF(sectorsize, &isofile->toc[27]); + isofile->toc[27] = HEXTOBCD(isofile->toc[27]); + isofile->toc[28] = HEXTOBCD(isofile->toc[28]); + isofile->toc[29] = HEXTOBCD(isofile->toc[29]); + + isofile->toc[40] = 0x02; // YellowBook? Data Mode? + isofile->toc[42] = 0x01; // Track No. + LBAtoMSF(0, &isofile->toc[47]); + isofile->toc[47] = HEXTOBCD(isofile->toc[47]); + isofile->toc[48] = HEXTOBCD(isofile->toc[48]); + isofile->toc[49] = HEXTOBCD(isofile->toc[49]); +} // END IsoInitTOC() + + +extern void IsoAddTNToTOC(struct IsoFile *isofile, struct tocTN toctn) { + if(isofile == NULL) return; + +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: IsoAddTNToTOC()"); +#endif /* VERBOSE_FUNCTION_TOC */ + + isofile->toc[7] = HEXTOBCD(toctn.strack); + isofile->toc[17] = HEXTOBCD(toctn.etrack); + return; +} // END IsoAddTNToTOC() + + +extern void IsoAddTDToTOC(struct IsoFile *isofile, + unsigned char track, + struct tocTD toctd) { + int temptrack; + int position; + +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: IsoAddTNToTOC(%u)", track); +#endif /* VERBOSE_FUNCTION_TOC */ + + if(isofile == NULL) return; + + temptrack = track; + if(temptrack == 0xAA) temptrack = 0; + if(temptrack > 99) return; // Only up to 99 tracks allowed. + + if(temptrack == 0) { + LBAtoMSF(toctd.lsn, &isofile->toc[27]); + isofile->toc[27] = HEXTOBCD(isofile->toc[27]); + isofile->toc[28] = HEXTOBCD(isofile->toc[28]); + isofile->toc[29] = HEXTOBCD(isofile->toc[29]); + + } else { + position = temptrack * 10; + position += 30; + isofile->toc[position] = toctd.type; + isofile->toc[position + 2] = HEXTOBCD(temptrack); + LBAtoMSF(toctd.lsn, &isofile->toc[position + 7]); + isofile->toc[position + 7] = HEXTOBCD(isofile->toc[position + 7]); + isofile->toc[position + 8] = HEXTOBCD(isofile->toc[position + 8]); + isofile->toc[position + 9] = HEXTOBCD(isofile->toc[position + 9]); + } // ENDIF- Is this a lead-out? (or an actual track?) +} // END IsoAddTDToTOC() + + +extern int IsoLoadTOC(struct IsoFile *isofile) { + char tocext[] = ".toc\0"; + char tocheader[5]; + ACTUALHANDLE tochandle; + char tocname[256]; + int i; + int j; + int retval; + unsigned char cdvdtype; + struct tocTN toctn; + struct tocTD toctd; + + if(isofile == NULL) return(-1); + + i = 0; + while((i < 256) && (isofile->name[i] != 0)) { + tocname[i] = isofile->name[i]; + i++; + } // ENDWHILE- Copying the data name to the toc name + j = 0; + while((i < 256) && (tocext[j] != 0)) { + tocname[i] = tocext[j]; + i++; + j++; + } // ENDWHILE- Append ".toc" to end of name + tocname[i] = 0; // And 0-terminate + + tochandle = ActualFileOpenForRead(tocname); + if(tochandle == ACTUALHANDLENULL) return(-1); + + retval = ActualFileRead(tochandle, 4, tocheader); + if(retval < 4) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Trouble reading the 'toc' file? + + if((tocheader[0] != 'T') || + (tocheader[1] != 'O') || + (tocheader[2] != 'C') || + (tocheader[3] != '1')) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Not a 'toc' file after all? + +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: IsoLoadTOC(%s)", tocname); +#endif /* VERBOSE_FUNCTION_TOC */ + + retval = ActualFileRead(tochandle, 1, (char *) &cdvdtype); + if(retval < 1) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Trouble reading the 'toc' file? + + isofile->cdvdtype = cdvdtype; + IsoInitTOC(isofile); + + if((cdvdtype != CDVD_TYPE_PS2DVD) && (cdvdtype != CDVD_TYPE_DVDV)) { + retval = ActualFileRead(tochandle, sizeof(struct tocTN), (char *) &toctn); + if(retval < sizeof(struct tocTN)) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Trouble reading the 'toc' file? + + if((toctn.strack > 99) || (toctn.etrack > 99)) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Track numbers out of range? +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: Start Track %u End Track %u", + toctn.strack, toctn.etrack); +#endif /* VERBOSE_FUNCTION_TOC */ + IsoAddTNToTOC(isofile, toctn); + + retval = ActualFileRead(tochandle, sizeof(struct tocTD), (char *) &toctd); + if(retval < sizeof(struct tocTD)) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Trouble reading the 'toc' file? + + if(toctd.type != 0) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Track numbers out of range? +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: Total Sectors: %lu", toctd.lsn); +#endif /* VERBOSE_FUNCTION_TOC */ + IsoAddTDToTOC(isofile, 0xAA, toctd); + + for(i = toctn.strack; i <= toctn.etrack; i++) { + + retval = ActualFileRead(tochandle, sizeof(struct tocTD), (char *) &toctd); + if(retval < sizeof(struct tocTD)) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Trouble reading the 'toc' file? +#ifdef VERBOSE_FUNCTION_TOC + PrintLog("CDVDiso TOC: Track %u Type %u Sector Start: %lu", + i, toctd.type, toctd.lsn); +#endif /* VERBOSE_FUNCTION_TOC */ + IsoAddTDToTOC(isofile, i, toctd); + } // NEXT i- read in each track + } // ENDIF- Not a DVD? (Then read in CD track data) + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + + return(0); +} // END IsoLoadTOC() + + +extern int IsoSaveTOC(struct IsoFile *isofile) { + char tocext[] = ".toc\0"; + char tocheader[] = "TOC1\0"; + ACTUALHANDLE tochandle; + char tocname[256]; + int i; + int j; + int retval; + unsigned char cdvdtype; + struct tocTN toctn; + struct tocTD toctd; + char temptime[3]; + + if(isofile == NULL) return(-1); + + i = 0; + while((i < 256) && (isofile->name[i] != 0)) { + tocname[i] = isofile->name[i]; + i++; + } // ENDWHILE- Copying the data name to the toc name + j = 0; + while((i < 256) && (tocext[j] != 0)) { + tocname[i] = tocext[j]; + i++; + j++; + } // ENDWHILE- Append ".toc" to end of name + tocname[i] = 0; // And 0-terminate + + ActualFileDelete(tocname); + tochandle = ActualFileOpenForWrite(tocname); + if(tochandle == ACTUALHANDLENULL) return(-1); + + retval = ActualFileWrite(tochandle, 4, tocheader); + if(retval < 4) { + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + ActualFileDelete(tocname); + return(-1); + } // ENDIF- Trouble writing to the 'toc' file? + + cdvdtype = isofile->cdvdtype; + ActualFileWrite(tochandle, 1, (char *) &cdvdtype); + + if((cdvdtype != CDVD_TYPE_PS2DVD) && (cdvdtype != CDVD_TYPE_DVDV)) { + toctn.strack = BCDTOHEX(isofile->toc[7]); + toctn.etrack = BCDTOHEX(isofile->toc[17]); + ActualFileWrite(tochandle, sizeof(struct tocTN), (char *) &toctn); + + // Leadout Data + toctd.type = 0; + temptime[0] = BCDTOHEX(isofile->toc[27]); + temptime[1] = BCDTOHEX(isofile->toc[28]); + temptime[2] = BCDTOHEX(isofile->toc[29]); + toctd.lsn = MSFtoLBA(temptime); + ActualFileWrite(tochandle, sizeof(struct tocTD), (char *) &toctd); + + for(i = toctn.strack; i <= toctn.etrack; i++) { + j = i * 10 + 30; + toctd.type = isofile->toc[j]; + temptime[0] = BCDTOHEX(isofile->toc[j + 7]); + temptime[1] = BCDTOHEX(isofile->toc[j + 8]); + temptime[2] = BCDTOHEX(isofile->toc[j + 9]); + toctd.lsn = MSFtoLBA(temptime); + ActualFileWrite(tochandle, sizeof(struct tocTD), (char *) &toctd); + } // NEXT i- write out each track + } // ENDIF- Not a DVD? (Then output CD track data) + ActualFileClose(tochandle); + tochandle = ACTUALHANDLENULL; + + return(0); +} // END IsoSaveTOC() diff --git a/plugins/cdvd/CDVDisoEFP/src/toc.h b/plugins/cdvd/CDVDisoEFP/src/toc.h new file mode 100644 index 0000000000..26dc7e4554 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/toc.h @@ -0,0 +1,84 @@ +/* toc.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef TOC_H +#define TOC_H + + +// #ifndef __LINUX__ +// #ifdef __linux__ +// #define __LINUX__ +// #endif /* __linux__ */ +// #endif /* No __LINUX__ */ + +// #define CDVDdefs +// #include "PS2Edefs.h" + +#include "isofile.h" + + +// #define VERBOSE_FUNCTION_TOC + + +#ifdef _WIN32 +#pragma pack(1) +#endif /* _WIN32 */ + +struct tocTD { + unsigned long lsn; + unsigned char type; +#ifdef _WIN32 +}; +#else +} __attribute__ ((packed)); +#endif /* _WIN32 */ + +struct tocTN { + unsigned char strack; + unsigned char etrack; +#ifdef _WIN32 +}; +#else +} __attribute__ ((packed)); +#endif /* _WIN32 */ + +#ifdef _WIN32 +#pragma pack() +#endif /* _WIN32 */ + + +// PCSX2's .toc file format: +// 1 unsigned char - CDVD_TYPE_???? +// 1 tocTN +// As many tocTDs as it takes. + + +extern void IsoInitTOC(struct IsoFile *isofile); +extern void IsoAddTNToTOC(struct IsoFile *isofile, struct tocTN toctn); +extern void IsoAddTDToTOC(struct IsoFile *isofile, + unsigned char track, + struct tocTD toctd); + +extern int IsoLoadTOC(struct IsoFile *isofile); +extern int IsoSaveTOC(struct IsoFile *isofile); + + +#endif /* TOC_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/version.c b/plugins/cdvd/CDVDisoEFP/src/version.c new file mode 100644 index 0000000000..f8d053f30f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/version.c @@ -0,0 +1,36 @@ +/* version.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +char *libname = "EFP Iso CDVD Driver"; + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 6; diff --git a/plugins/cdvd/CDVDisoEFP/src/version.h b/plugins/cdvd/CDVDisoEFP/src/version.h new file mode 100644 index 0000000000..774ce3b29a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/version.h @@ -0,0 +1,43 @@ +/* version.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef VERSION_H +#define VERSION_H + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern char *libname; + +extern const unsigned char version; +extern const unsigned char revision; +extern const unsigned char build; + + +#endif /* VERSION_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/ChangeLog b/plugins/cdvd/CDVDisoEFP/src/zlib/ChangeLog new file mode 100644 index 0000000000..9e5e28e52f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/ChangeLog @@ -0,0 +1,722 @@ + + ChangeLog file for zlib + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occuring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id: ChangeLog,v 1.1 2005/07/12 22:08:51 petersoneugene Exp $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/README b/plugins/cdvd/CDVDisoEFP/src/zlib/README new file mode 100644 index 0000000000..266edd4edb --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/README @@ -0,0 +1,126 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.1 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install" For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or +descrip.mms. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.1 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/adler32.c b/plugins/cdvd/CDVDisoEFP/src/zlib/adler32.c new file mode 100644 index 0000000000..bc0842f01b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/compress.c b/plugins/cdvd/CDVDisoEFP/src/zlib/compress.c new file mode 100644 index 0000000000..e7ea2c518b --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.c b/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.c new file mode 100644 index 0000000000..aa8b984a34 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.c @@ -0,0 +1,311 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.h b/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.c b/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.c new file mode 100644 index 0000000000..efe7b63aba --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.h b/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.h new file mode 100644 index 0000000000..26775e9d12 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/gzio.c b/plugins/cdvd/CDVDisoEFP/src/zlib/gzio.c new file mode 100644 index 0000000000..4cfd64fc45 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/infback.c b/plugins/cdvd/CDVDisoEFP/src/zlib/infback.c new file mode 100644 index 0000000000..5cf5d22cf9 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.c b/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.c new file mode 100644 index 0000000000..63aa4402fc --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.h b/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inffixed.h b/plugins/cdvd/CDVDisoEFP/src/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.c b/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.c new file mode 100644 index 0000000000..71fe3ccd0e --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.h b/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.h new file mode 100644 index 0000000000..b6965127b9 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.c b/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.c new file mode 100644 index 0000000000..55fd27b601 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.h b/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.h new file mode 100644 index 0000000000..1dbfe53a6a --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/trees.c b/plugins/cdvd/CDVDisoEFP/src/zlib/trees.c new file mode 100644 index 0000000000..d0bce9f2f1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/trees.h b/plugins/cdvd/CDVDisoEFP/src/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/uncompr.c b/plugins/cdvd/CDVDisoEFP/src/zlib/uncompr.c new file mode 100644 index 0000000000..82ebef75f8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/zconf.h b/plugins/cdvd/CDVDisoEFP/src/zlib/zconf.h new file mode 100644 index 0000000000..f4cfc216e1 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(_WIN32)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h b/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h new file mode 100644 index 0000000000..d54ac9433f --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h.bak b/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h.bak new file mode 100644 index 0000000000..530c64c4d8 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/zlib.h.bak @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.c b/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.c new file mode 100644 index 0000000000..db137f8a48 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.h b/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.h new file mode 100644 index 0000000000..e300f7c767 --- /dev/null +++ b/plugins/cdvd/CDVDisoEFP/src/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/cdvd/CDVDlinuz/ChangeLog.txt b/plugins/cdvd/CDVDlinuz/ChangeLog.txt new file mode 100644 index 0000000000..dd0b7ebdf6 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/ChangeLog.txt @@ -0,0 +1,43 @@ +Changes: +------- + CDVDlinuz v0.4 (efp): + * Moved all "threaded" code to CDVDEFP (actual directory) (efp) + * Copied mid-level (not low-level) device drivers from CDVDisoEFP (efp) + * In Windows, when newly selected from the PCSX2 configure screen, CDVDinit() + (as well as InitConf()) are not called. Fixed. (efp) + + CDVDEFP v0.3 (efp): + * Protection against "Interrupted system call" errors enhanced (threading) + * Simplified ReadLoop completion detection code (threading) + * Separated buffer.c from device.c for cross-CDVD portability. + + CDVDEFP v0.2 (efp): + * Separated out device command calls (for easier maintainability) + * Added a read cache (currently sized at 512kb) + * Added threading code (pthreads, because it's portable) + * With threading comes tray polling (currently at 1/sec) + * With threading comes a read-ahead function (currently set to 64kb) + + CDVDEFP v0.1 (efp): + * Updated to 0.6.0 (beta) specs + * Removed Glade influence in Configure/About interfaces + * Added O_NONBLOCK so disc is not required to be in drive when Pcsx2 starts + discs can now be switched out at will. + * Separated CD and DVD access calls for better maintainability + * Removed 2GB byte limitation to DVD sector calls + * Collected all info on disc when disc is first inserted + * Expanded disc type detection to meet 0.6.0 specs. + CD/DVD detection. PS1/PS2/CDDA/other detection. + * Multilevel Debug info added (currently controlled by #defines) + + CDVDlinuz v0.3 (linuzappz): + * Updated to 0.4.3 specs + + CDVDlinuz v0.2 (linuzappz): + * Updated to 0.2.9 specs + + CDVDlinuz v0.1 (linuzappz): + * First Release + * Tested with Pcsx2 + + Email: diff --git a/plugins/cdvd/CDVDlinuz/License.txt b/plugins/cdvd/CDVDlinuz/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/License.txt @@ -0,0 +1,342 @@ + 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/plugins/cdvd/CDVDlinuz/Src/Linux/CD.c b/plugins/cdvd/CDVDlinuz/Src/Linux/CD.c new file mode 100644 index 0000000000..ab5796c8c3 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/CD.c @@ -0,0 +1,367 @@ +/* CD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // strerror() +#include // open() +#include // ioctl() +#include // open() +#include // lseek(), open() +#include // close(), lseek(), (sleep()) + +#include // CD/DVD based ioctl() and defines. + +#include "../convert.h" +#include "logfile.h" +#include "device.h" +#include "CD.h" + + +// Constants +u8 *playstationcdname = "PLAYSTATION\0"; +u8 *ps1name = "CD-XA001\0"; + +// CD-ROM temp storage structures (see linux/cdrom.h for details) +struct cdrom_tochdr cdheader; +struct cdrom_tocentry cdtrack; +struct cdrom_subchnl subchannel; +u8 cdtempbuffer[2352]; + +int cdmode; // mode of last CDVDreadTrack call (important for CDs) + + +// Internal Functions + +void InitCDSectorInfo() { + cdmode = -1; +} // END InitSectorInfo(); + + +// Function Calls from CDVD.c + +void InitCDInfo() { + InitCDSectorInfo(); +} // END InitDiscType() + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + s32result = 0; + + if(buffer == NULL) return(-1); + + // The CD way of figuring out where to read. + LBAtoMSF(lsn, buffer); + + switch(mode) { + case CDVD_MODE_2048: + case CDVD_MODE_2328: + case CDVD_MODE_2340: + case CDVD_MODE_2352: + errno = 4; // Interrupted system call... (simulated the first time) + while(errno == 4) { + errno = 0; + s32result = ioctl(devicehandle, CDROMREADRAW, buffer); + } // ENDWHILE- Continually being interrupted by the system... + break; + case CDVD_MODE_2368: // Unimplemented... as yet. + default: +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Unknown Mode %i", mode); +#endif /* VERBOSE_WARNINGS */ + return(-1); // Illegal Read Mode? Abort + break; + } // ENDSWITCH- Which read mode should we choose? + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitCDSectorInfo(); + return(-1); + } // ENDIF- Trouble getting a track count? + + cdmode = mode; // Save mode for buffer positioning later. + return(0); // Call accomplished +} // END CDreadTrack() + +s32 CDgetBufferOffset() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetBufferOffset()"); +#endif /* VERBOSE_FUNCTION */ + + switch(cdmode) { + case CDVD_MODE_2048: + return(0+24); + case CDVD_MODE_2328: + return(0+24); + case CDVD_MODE_2340: + return(0+12); + case CDVD_MODE_2352: + return(0+0); + case CDVD_MODE_2368: // Unimplemented... as yet. + default: +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Unknown Mode %i", cdmode); +#endif /* VERBOSE_WARNINGS */ + return(0); // Not to worry. for now. + } // ENDSWITCH- where should we put the buffer pointer? +} // END CDgetBuffer() + +// I, personally, don't see the big deal with SubQ +// However, sooner or later I'll incorporate it into the Cache Buffer system +// (backward compatibility, and all that) +s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { + int tempmode; + s32 s32result; + + s32result = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDreadSubQ()"); +#endif /* VERBOSE_FUNCTION */ + + tempmode = cdmode; + if(tempmode == -1) tempmode = CDVD_MODE_2352; + CDreadTrack(lsn, tempmode, cdtempbuffer); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(s32result); + } // ENDIF- Trouble? + + subchannel.cdsc_format = CDROM_MSF; + s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(s32result); + } // ENDIF- Trouble? + + if(subq != NULL) { + subq->mode = subchannel.cdsc_adr; + subq->ctrl = subchannel.cdsc_ctrl; + subq->trackNum = subchannel.cdsc_trk; + subq->trackIndex = subchannel.cdsc_ind; + subq->trackM = subchannel.cdsc_reladdr.msf.minute; + subq->trackS = subchannel.cdsc_reladdr.msf.second; + subq->trackF = subchannel.cdsc_reladdr.msf.frame; + subq->discM = subchannel.cdsc_absaddr.msf.minute; + subq->discS = subchannel.cdsc_absaddr.msf.second; + subq->discF = subchannel.cdsc_absaddr.msf.frame; + } // ENDIF- Did the caller want all this data? + + return(0); +} // END CDVDreadSubQ() + +s32 CDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + if(cdvdtn != NULL) { + cdvdtn->strack = cdheader.cdth_trk0; + cdvdtn->etrack = cdheader.cdth_trk1; + } // ENDIF- programmer actually WANTS this info? + + return(0); // Call accomplished +} // END CDVDgetTN() + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + u8 j; + u16 k; + char temptime[3]; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + j = newtrack; + if(j == CDROM_LEADOUT) j = 0; + + if(j == 0) { + k = 27; + } else { + k = j * 10 + 37; + } // ENDIF- Where to start hunting for this number? + + if(cdvdtd != NULL) { + cdvdtd->type = tocbuffer[j*10 + 30]; + + temptime[0] = BCDTOHEX(tocbuffer[k]); + temptime[1] = BCDTOHEX(tocbuffer[k + 1]); + temptime[2] = BCDTOHEX(tocbuffer[k + 2]); + cdvdtd->lsn = MSFtoLBA(temptime); + } // ENDIF- Does the caller REALLY want this data? + + return(0); // Call accomplished +} // END CDVDgetTD() + +s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { + s32 offset; + s32 s32result; + int i; + u8 j; + int tempdisctype; + + offset = 0; + errno = 0; + i = 0; + j = 0; + tempdisctype = CDVD_TYPE_UNKNOWN; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); + if((s32result != 0) || (errno != 0)) { + return(-1); + } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort + disctype = CDVD_TYPE_DETCTCD; + + switch(ioctldisktype) { + case CDS_AUDIO: +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected CDDA Audio disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_CDDA; + tocbuffer[0] = 0x01; + break; + + case CDS_DATA_1: + case CDS_MIXED: +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tocbuffer[0] = 0x41; + + CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); + offset = CDgetBufferOffset(); + i = 0; + while((*(playstationcdname + i) != 0) && + (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; + if(*(playstationcdname + i) == 0) { + i = 0; + while((*(ps1name + i) != 0) && + (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; + if(*(ps1name + i) == 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PSCD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation 2 CD disc."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2CD; + } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) + } else { + tempdisctype = CDVD_TYPE_UNKNOWN; + } // ENDIF- Did we find the Playstation name? + break; + + default: + return(-1); + } // ENDSWITCH- What has ioctl disc type come up with? + + // Collect TN data + cdheader.cdth_trk0 = 0; + cdheader.cdth_trk1 = 0; + + s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", + s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + cdheader.cdth_trk0 = 1; + cdheader.cdth_trk1 = 1; + } // ENDIF- Failed to read in track count? Assume 1 track. +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Track Number Range: %i-%i", + cdheader.cdth_trk0, cdheader.cdth_trk1); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[2] = 0xA0; + tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); + tocbuffer[12] = 0xA1; + tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); + + // Collect disc TD data + cdtrack.cdte_track = CDROM_LEADOUT; + cdtrack.cdte_format = CDROM_LBA; + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", + s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Trouble getting a track count? + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Total Time: %i:%i", + tocbuffer[27], tocbuffer[28]); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + // Collect track TD data + for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { + cdtrack.cdte_track = j; // j-1? + cdtrack.cdte_format = CDROM_LBA; + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + if((s32result == -1) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", + j, s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + // No more here... + + } else { + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", + j, + cdtrack.cdte_datamode, + tocbuffer[j*10+37], + tocbuffer[j*10+38], + tocbuffer[j*10+39]); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; + tocbuffer[j*10 + 32] = HEXTOBCD(j); + tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); + tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); + tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); + } // ENDIF- Trouble getting a track count? + } // NEXT j- Reading each track's info in turn + + errno = 0; + disctype = tempdisctype; // Trigger the fact we have the info (finally) + return(disctype); +} // END CDVDgetDiskType() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/CD.h b/plugins/cdvd/CDVDlinuz/Src/Linux/CD.h new file mode 100644 index 0000000000..2546cbaabd --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/CD.h @@ -0,0 +1,46 @@ +/* CD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __CD_H__ +#define __CD_H__ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "../PS2Edefs.h" + + +// Exported Functions + +extern void InitCDInfo(); +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 CDgetBufferOffset(); +extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); +extern s32 CDgetTN(cdvdTN *cdvdtn); +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 CDgetDiskType(s32 ioctldisktype); + + +#endif /* __CD_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.c b/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.c new file mode 100644 index 0000000000..7ff0daa844 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.c @@ -0,0 +1,368 @@ +/* CDVDlinuz.c + * Copyright (C) 2002-2005 CDVDlinuz 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 // errno +#include // open() +#include // NULL +#include // printf() +#include // getenv(), system() +#include // strerror(), sprintf() +#include // ioctl() +#include // stat() +#include // stat() +#include // time_t, time(), struct timeval +#include // stat() + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" +// #include "PS2Etypes.h" + +#include "CDVDlinuz.h" + +#include "buffer.h" +#include "conf.h" +#include "logfile.h" +#include "CD.h" // InitCDInfo() +#include "DVD.h" // InitDVDInfo() +#include "device.h" + +#include "../version.h" + + +// Globals + +time_t lasttime; + + +// Interface Functions + +u32 CALLBACK PS2EgetLibType() { + return(PS2E_LT_CDVD); // Library Type CDVD +} // END PS2EgetLibType() + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return((version<<16)|(revision<<8)|build); +} // END PS2EgetLibVersion2() + + +char* CALLBACK PS2EgetLibName() { + return(libname); +} // END PS2EgetLibName() + + +s32 CALLBACK CDVDinit() { + errno = 0; + + InitLog(); + if(OpenLog() != 0) return(-1); + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDinit()"); +#endif /* VERBOSE_FUNCTION */ + + InitConf(); + + devicehandle = -1; + devicecapability = 0; + lasttime = time(NULL); + + // Initialize DVD.c and CD.c as well + InitDisc(); + InitDVDInfo(); + InitCDInfo(); + + return(0); +} // END CDVDinit() + + +void CALLBACK CDVDshutdown() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDshutdown()"); +#endif /* VERBOSE_FUNCTION */ + + DeviceClose(); + CloseLog(); +} // END CDVDshutdown() + + +s32 CALLBACK CDVDopen(const char* pTitleFilename) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDopen()"); +#endif /* VERBOSE_FUNCTION */ + + InitBuffer(); + + LoadConf(); + + errno = 0; + s32result = DeviceOpen(); + if(s32result != 0) return(s32result); + if(errno != 0) return(-1); + + return(0); +} // END CDVDopen(); + + +void CALLBACK CDVDclose() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDclose()"); +#endif /* VERBOSE_FUNCTION */ + + DeviceClose(); +} // END CDVDclose() + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + s32result = 0; + errno = 0; + + if(DiscInserted() == -1) return(-1); + + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it's the right one? + } // ENDIF- Are we already pointing at the buffer? + + userbuffer = FindListBuffer(lsn); + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it was the right one? + } // ENDIF- Was a buffer found in the cache? + + replacebuffer++; + if(replacebuffer >= BUFFERMAX) replacebuffer = 0; + userbuffer = replacebuffer; + + if(bufferlist[replacebuffer].upsort != 0xffff) { + RemoveListBuffer(replacebuffer); + } // ENDIF- Reference already in place? Remove it. + + s32result = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); + bufferlist[replacebuffer].lsn = lsn; + bufferlist[replacebuffer].mode = mode; + bufferlist[replacebuffer].offset = DeviceBufferOffset(); + + if((s32result != 0) || (errno != 0)) { + bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. + } else { + if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { + if(mode == CDVD_MODE_2352) { + CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); + errno = 0; + } // ENDIF- Read subq as well? + } // ENDIF- Read a DVD buffer or a CD buffer? + } // ENDIF-Read ok? Fill out rest of buffer info. + AddListBuffer(replacebuffer); + return(s32result); +} // END CDVDreadTrack() + + +u8* CALLBACK CDVDgetBuffer() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetBuffer()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(NULL); + + if(userbuffer == 0xffff) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Not pointing to a buffer!"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // No buffer reference? + } // ENDIF- user buffer not pointing at anything? Abort + + if(bufferlist[userbuffer].mode < 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Error in buffer!"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // Bad Sector? + } // ENDIF- Trouble reading physical sector? Tell them. + + return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); +} // END CDVDgetBuffer() + + +// Note: without the lsn, I could pull the SubQ data directly from +// the stored buffer (in buffer.h). Oh, well. +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ *subq) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDreadSubQ(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + // DVDs don't have SubQ data + if(disctype == CDVD_TYPE_PS2DVD) return(-1); + if(disctype == CDVD_TYPE_DVDV) return(-1); + + return(CDreadSubQ(lsn, subq)); +} // END CDVDreadSubQ() + + +s32 CALLBACK CDVDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTN(cdvdtn)); + } else { + return(CDgetTN(cdvdtn)); + } // ENDIF- Are we looking at a DVD? +} // END CDVDgetTN() + + +s32 CALLBACK CDVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(newtrack, cdvdtd)); + } else { + return(CDgetTD(newtrack, cdvdtd)); + } // ENDIF- Are we looking at a DVD? +} // END CDVDgetTD() + + +s32 CALLBACK CDVDgetTOC(void *toc) { + // A structure to fill in, or at least some documentation on what + // the PS2 expects from this call would be more helpful than a + // "void *". + + union { + void *voidptr; + u8 *u8ptr; + } tocptr; + s32 i; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTOC()"); +#endif /* VERBOSE_FUNCTION */ + + if(toc == NULL) return(-1); + if(DiscInserted() == -1) return(-1); + + tocptr.voidptr = toc; + for(i = 0; i < 1024; i++) *(tocptr.u8ptr + i) = tocbuffer[i]; + tocptr.voidptr = NULL; + + return(0); +} // END CDVDgetTOC() + + +s32 CALLBACK CDVDgetDiskType() { +#ifdef VERBOSE_FUNCTION + // Called way too often in boot part of bios to be left in. + // PrintLog("CDVD interface: CDVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(disctype); +} // END CDVDgetDiskType() + + +s32 CALLBACK CDVDgetTrayStatus() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTrayStatus()"); +#endif /* VERBOSE_FUNCTION */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(traystatus); +} // END CDVDgetTrayStatus() + + +s32 CALLBACK CDVDctrlTrayOpen() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDctrlTrayOpen()"); +#endif /* VERBOSE_FUNCTION */ + + return(DeviceTrayOpen()); +} // END CDVDctrlTrayOpen() + + +s32 CALLBACK CDVDctrlTrayClose() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDctrlTrayClose()"); +#endif /* VERBOSE_FUNCTION */ + + return(DeviceTrayClose()); +} // END CDVDctrlTrayClose() + + +void CALLBACK CDVDconfigure() { + ExecCfg("configure"); +} // END CDVDconfigure() + + +void CALLBACK CDVDabout() { + ExecCfg("about"); +} // END CDVDabout() + + +s32 CALLBACK CDVDtest() { + s32 s32result; + + errno = 0; + + if(devicehandle != -1) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Device already open"); +#endif /* VERBOSE_WARNINGS */ + return(0); + } // ENDIF- Is the CD/DVD already in use? That's fine. + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDtest()"); +#endif /* VERBOSE_FUNCTION */ + + s32result = DeviceOpen(); + DeviceClose(); + return(s32result); +} // END CDVDtest() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.h b/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.h new file mode 100644 index 0000000000..69a4add14d --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/CDVDlinuz.h @@ -0,0 +1,31 @@ +/* CDVDlinuz.h + * Copyright (C) 2002-2005 CDVDlinuz 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 + */ + +#ifndef __CDVDLINUZ_H__ +#define __CDVDLINUZ_H__ + + +// #define VERBOSE_WARNINGS +// #define VERBOSE_FUNCTION +#define VERBOSE_DISC_INFO +#define VERBOSE_DISC_TYPE + +#define READ_AHEAD_BUFFERS 32 + + +#endif /* __CDVDLINUZ_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.c b/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.c new file mode 100644 index 0000000000..516faa7eda --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.c @@ -0,0 +1,584 @@ +/* DVD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // strerror(), memset(), memcpy() +#include // open() +#include // ioctl() +#include // open() +#include // lseek(), open() +#include // close(), lseek(), (sleep()) + +#include // CD/DVD based ioctl() and defines. + +#include "logfile.h" +#include "device.h" +#include "DVD.h" + +#include "../PS2Etypes.h" // u8, u32 + + +// Constants +u8 *playstationname = "PLAYSTATION\0"; + +// DVD storage structures (see linux/cdrom.h for details) +dvd_struct dvdphysical; +dvd_struct dvdcopyright[DVD_LAYERS]; +dvd_struct dvdbca; +dvd_struct dvdmanufact[DVD_LAYERS]; + +u32 dvdlastlsn; +u8 dvdtempbuffer[2064]; + + +// Internal Functions + +void InitDVDSectorInfo() { + dvdlastlsn = 0xffffffff; +} // END InitSectorInfo(); + +void HexDump(u8 *strptr, u8 count) { + int i; + u8 ch[2]; + char hexline[81]; + int hexlinepos; + + ch[1] = 0; + + if(count == 0) count = 16; + if((count < 1) || (count > 16)) return; + + hexlinepos = 0; + hexlinepos += sprintf(&hexline[hexlinepos], "CDVD driver: "); + + for(i = 0; i < count; i++) { + hexlinepos += sprintf(&hexline[hexlinepos], "%.2x ", (*(strptr + i)) * 1); + } // NEXT i- printing each new Hex number + + for(i = 0; i < count; i++) { + if((*(strptr + i) < 32) || (*(strptr + i) > 127)) { + hexlinepos += sprintf(&hexline[hexlinepos], "."); + } else { + ch[0] = *(strptr + i); + hexlinepos += sprintf(&hexline[hexlinepos], "%s", ch); + } // ENDIF- Is this an unprintable character? + } // NEXT i- printing each new character + PrintLog(hexline); +} // ENDIF HexDump() + + +//// DVD Structure Functions + +s32 DVDreadPhysical() { + s32 s32result; + u8 i; + + errno = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadPhysical()\n"); +#endif /* VERBOSE_FUNCTION */ + + memset(&dvdphysical, 0, sizeof(dvd_struct)); + dvdphysical.type = DVD_STRUCT_PHYSICAL; + + i = DVD_LAYERS; + while(i > 0) { + i--; + dvdphysical.physical.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdphysical); + } // ENDWHILE- reading in all physical layers... + + if((s32result == -1) || (errno != 0)) { + dvdphysical.type = 0xFF; +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Physical structure: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with reading Layer 0 of the physical data? Abort + + i = 3; + while((i > 0) && (dvdphysical.physical.layer[i].end_sector == 0)) i--; + dvdphysical.physical.layer_num = i; + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Physical Characteristics"); + PrintLog("CDVD driver: Number of Layers: %i", + (s32) dvdphysical.physical.layer_num + 1); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + PrintLog("CDVD driver: Layer Number %i", i); + switch(dvdphysical.physical.layer[i].book_type) { + case 0: + PrintLog("CDVD driver: Book Type: DVD-ROM"); + break; + case 1: + PrintLog("CDVD driver: Book Type: DVD-RAM"); + break; + case 2: + PrintLog("CDVD driver: Book Type: DVD-R"); + break; + case 3: + PrintLog("CDVD driver: Book Type: DVD-RW"); + break; + case 9: + PrintLog("CDVD driver: Book Type: DVD+RW"); + break; + default: + PrintLog("CDVD driver: Book Type: Unknown (%i)", + dvdphysical.physical.layer[i].book_type); + break; + } // ENDSWITCH- Displaying the Book Type + PrintLog("CDVD driver: Book Version %i", + dvdphysical.physical.layer[i].book_version); + switch(dvdphysical.physical.layer[i].min_rate) { + case 0: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-ROM"); + break; + case 1: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RAM"); + break; + case 2: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-R"); + break; + case 3: + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RW"); + break; + case 9: + PrintLog("CDVD driver: Use Minimum Rate for: DVD+RW"); + break; + default: + PrintLog("CDVD driver: Use Minimum Rate for: Unknown (%i)", + dvdphysical.physical.layer[i].min_rate); + break; + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + switch(dvdphysical.physical.layer[i].disc_size) { + case 0: + PrintLog("CDVD driver: Physical Disk Size: 120mm"); + break; + case 1: + PrintLog("CDVD driver: Physical Disk Size: 80mm"); + break; + default: + PrintLog("CDVD driver: Physical Disk Size: Unknown (%i)", + dvdphysical.physical.layer[i].disc_size); + break; + } // ENDSWITCH- What's the Disk Size? + switch(dvdphysical.physical.layer[i].layer_type) { + case 1: + PrintLog("CDVD driver: Layer Type: Read-Only"); + break; + case 2: + PrintLog("CDVD driver: Layer Type: Recordable"); + break; + case 4: + PrintLog("CDVD driver: Layer Type: Rewritable"); + break; + default: + PrintLog("CDVD driver: Layer Type: Unknown (%i)", + dvdphysical.physical.layer[i].layer_type); + break; + } // ENDSWITCH- Displaying the Layer Type + switch(dvdphysical.physical.layer[i].track_path) { + case 0: + PrintLog("CDVD driver: Track Path: PTP"); + break; + case 1: + PrintLog("CDVD driver: Track Path: OTP"); + break; + default: + PrintLog("CDVD driver: Track Path: Unknown (%i)", + dvdphysical.physical.layer[i].track_path); + break; + } // ENDSWITCH- What's Track Path Layout? + // PrintLog("CDVD driver: Disc Size %i Layer Type %i Track Path %i Nlayers %i", + // dvdphysical.physical.layer[i].nlayers); + switch(dvdphysical.physical.layer[i].track_density) { + case 0: + PrintLog("CDVD driver: Track Density: .74 m/track"); + break; + case 1: + PrintLog("CDVD driver: Track Density: .8 m/track"); + break; + case 2: + PrintLog("CDVD driver: Track Density: .615 m/track"); + break; + default: + PrintLog("CDVD driver: Track Density: Unknown (%i)", + dvdphysical.physical.layer[i].track_density); + break; + } // ENDSWITCH- Displaying the Track Density + switch(dvdphysical.physical.layer[i].linear_density) { + case 0: + PrintLog("CDVD driver: Linear Density: .267 m/bit"); + break; + case 1: + PrintLog("CDVD driver: Linear Density: .293 m/bit"); + break; + case 2: + PrintLog("CDVD driver: Linear Density: .409 to .435 m/bit"); + break; + case 4: + PrintLog("CDVD driver: Linear Density: .280 to .291 m/bit"); + break; + case 8: + PrintLog("CDVD driver: Linear Density: .353 m/bit"); + break; + default: + PrintLog("CDVD driver: Linear Density: Unknown (%i)", + dvdphysical.physical.layer[i].linear_density); + break; + } // ENDSWITCH- Displaying the Linear Density + if(dvdphysical.physical.layer[i].start_sector == 0x30000) { + PrintLog("CDVD driver: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + dvdphysical.physical.layer[i].start_sector); + } else if(dvdphysical.physical.layer[i].start_sector == 0x31000) { + PrintLog("CDVD driver: Starting Sector: %lu (DVD-RAM, DVD+RW)", + dvdphysical.physical.layer[i].start_sector); + } else { + PrintLog("CDVD driver: Starting Sector: %lu", + dvdphysical.physical.layer[i].start_sector); + } // ENDLONGIF- What does the starting sector tell us? + PrintLog("CDVD driver: End of Layer 0: %lu", + dvdphysical.physical.layer[i].end_sector_l0); + PrintLog("CDVD driver: Ending Sector: %lu", + dvdphysical.physical.layer[i].end_sector); + if(dvdphysical.physical.layer[i].bca != 0) + PrintLog("CDVD driver: BCA data present"); + } // NEXT i- Work our way through each layer... +#endif /* VERBOSE_DISC_INFO */ + + return(0); // Success. Physical data stored for perusal. +} // END DVDreadPhysical() + +s32 DVDreadCopyright() { + s32 s32result; + u8 i; + int successflag; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadCopyright()"); +#endif /* VERBOSE_FUNCTION */ + + successflag = 0; + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + memset(&dvdcopyright[i], 0, sizeof(dvd_struct)); + dvdcopyright[i].type = DVD_STRUCT_COPYRIGHT; + dvdcopyright[i].copyright.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdcopyright[i]); + if(s32result == 0) { + successflag = 1; + } else { + dvdcopyright[i].type = 0xFF; + } // ENDIF- + } // NEXT i- Getting copyright data for every known layer + + if(successflag == 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Copyright info: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Copyright Information\n"); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + if(dvdcopyright[i].type != 0xFF) { + PrintLog("CDVD driver: Layer Number %i CPST %i RMI %i", + dvdcopyright[i].copyright.layer_num, + dvdcopyright[i].copyright.cpst, + dvdcopyright[i].copyright.rmi); + } // ENDIF- Were we successful reading this one? + } // NEXT i- Printing out all copyright info found... +#endif /* VERBOSE_DISC_INFO */ + + errno = 0; + return(0); // Success. Copyright data stored for perusal. +} // END DVDreadCopyright() + +s32 DVDreadBCA() { + s32 s32result; + int i; + + i = 0; + errno = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadBCA()"); +#endif /* VERBOSE_FUNCTION */ + + memset(&dvdbca, 0, sizeof(dvd_struct)); + dvdbca.type = DVD_STRUCT_BCA; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdbca); + if((s32result == -1) || (errno != 0)) { + dvdbca.type = 0xFF; +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting BCA: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: BCA Length %i Value:", + dvdbca.bca.len); + for(i = 0; i < 188-15; i += 16) { + HexDump(dvdbca.bca.value+i, 16); + } // NEXT i- dumping whole key data +#endif /* VERBOSE_DISC_INFO */ + + return(0); // Success. BCA data stored for perusal. +} // END DVDreadBCA() + +s32 DVDreadManufact() { + s32 s32result; + u8 i; + int successflag; + int j; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadManufact()"); +#endif /* VERBOSE_FUNCTION */ + + j = 0; + successflag = 0; + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + memset(&dvdmanufact[i], 0, sizeof(dvd_struct)); + dvdmanufact[i].type = DVD_STRUCT_MANUFACT; + dvdmanufact[i].manufact.layer_num = i; + errno = 0; + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdmanufact[i]); + if((s32result != 0) || (errno != 0)) { + dvdmanufact[i].type = 0xFF; + } else { + successflag = 1; + } // ENDIF- Did we fail to read in some manufacturer data? + } // NEXT i- Collecting manufacturer data from all layers + + if(successflag == 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error getting Manufact: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Problem with read of physical data? + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD driver: Manufact Data"); + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + if(dvdmanufact[i].type != 0xFF) { + PrintLog("CDVD driver: Layer %i Length %i Value:", + dvdmanufact[i].manufact.layer_num, + dvdmanufact[i].manufact.len); + for(j = 0; j < 128-15; j += 16) { + HexDump(dvdmanufact[i].manufact.value+j, 16); + } // NEXT j- dumping whole key data + } // ENDIF- Do we have data at this layer? + } // NEXT i- Running through all the layers +#endif /* VERBOSE_DISC_INFO */ + + errno = 0; + return(0); // Success. Manufacturer's data stored for perusal. +} // END DVDreadManufact() + + +// External Functions + +// Function Calls from CDVD.c + +void InitDVDInfo() { + int j; + + dvdphysical.type = 0xFF; // Using for empty=0xff, full!=0xff test + dvdbca.type = 0xFF; + for(j = 0; j < DVD_LAYERS; j++) { + dvdcopyright[j].type = 0xFF; + dvdmanufact[j].type = 0xFF; + } // NEXT j- Zeroing each layer of data + InitDVDSectorInfo(); +} // END InitDiscType() + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + off64_t offsettarget; + off64_t offsetresult; + + errno = 0; + s32result = 0; + offsetresult = 0; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + if(lsn != dvdlastlsn + 1) { + offsettarget = lsn; + offsettarget *= 2048; + errno = 4; + while(errno == 4) { + errno = 0; + offsetresult = lseek64(devicehandle, offsettarget, SEEK_SET); + } // ENDWHILE- waiting for the system interruptions to cease. + if((offsetresult < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: Error on seek: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitDVDSectorInfo(); + return(-1); + } // ENDIF- trouble with seek? Reset pointer and abort + } // ENDIF- Do we have to seek a new position to read? + + errno = 4; + while(errno == 4) { + errno = 0; + s32result = read(devicehandle, buffer, 2048); + } // ENDWHILE- waiting for the system interruptions to cease. + if((s32result != 2048) || (errno != 0)) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD driver: DVD Short Block, Size: %i", s32result); + PrintLog("CDVD driver: Error: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + InitDVDSectorInfo(); + return(-1); + } // ENDIF- Trouble reading the data? Reset pointer and abort + + dvdlastlsn = lsn; + return(0); // Call accomplished +} // END DVDreadTrack() + +s32 DVDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + // Going to treat this as one large track for now. + if(cdvdtn != NULL) { + cdvdtn->strack = 1; + cdvdtn->etrack = 1; + } // ENDIF- programmer actually WANTS this info? + + return(0); // Call accomplished +} // END DVDgetTN() + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + if((newtrack >= 2) && (newtrack != CDROM_LEADOUT)) return(-1); + + if(cdvdtd != NULL) { + cdvdtd->lsn = dvdphysical.physical.layer[0].end_sector + - dvdphysical.physical.layer[0].start_sector + + 1; + cdvdtd->type = CDVD_MODE_2048; + } // ENDIF- Does the caller REALLY want this data? + + return(0); // Call accomplished +} // END DVDgetTD() + +s32 DVDgetDiskType(s32 ioctldisktype) { + s32 s32result; + int i; + s32 tempdisctype; + + errno = 0; + s32result = 0; + i = 0; + tempdisctype = CDVD_TYPE_UNKNOWN; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: DVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + if((ioctldisktype != CDS_DATA_1) && (ioctldisktype != CDS_MIXED)) { + return(-1); + } // ENDIF- Not a data disc we know of? Abort then + + s32result = DVDreadPhysical(); + if((s32result != 0) || (errno != 0)) { + return(-1); + } // ENDIF- Error reading the DVD physical structure? Not a DVD after all. + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: DVD Found (Dual-Sided)"); +#endif /* VERBOSE_DISC_TYPE */ + disctype = CDVD_TYPE_DETCTDVDD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: DVD Found (Single-Sided)"); +#endif /* VERBOSE_DISC_TYPE */ + disctype = CDVD_TYPE_DETCTDVDS; + } // ENDIF- Definitely a DVD. Size Test? + + // Read in the rest of the structures... + DVDreadCopyright(); + DVDreadBCA(); + DVDreadManufact(); + + // Test for "Playstation" header + s32result = DVDreadTrack(16, CDVD_MODE_2048, dvdtempbuffer); + if(s32result != 0) { + return(-1); + } else { + i = 0; + while((*(playstationname + i) != 0) && + (*(playstationname + i) == dvdtempbuffer[8 + i])) { + i++; + } // ENDWHILE- Checking each letter of PLAYSTATION name for a match + if(*(playstationname + i) == 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Detected Playstation 2 DVD"); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2DVD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD driver: Guessing it's a Video DVD"); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_DVDV; + } // ENDIF- Did we find the Playstation name? + } // ENDIF- Error reading disc volume information? Invalidate Disc + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { + tocbuffer[0] = 0x24; // Dual-Sided DVD + tocbuffer[4] = 0x41; + tocbuffer[5] = 0x95; + } else { + tocbuffer[0] = 0x04; // Single-Sided DVD + tocbuffer[4] = 0x86; + tocbuffer[5] = 0x72; + } // ENDIF- Are there too many sectors for a single-sided disc? + + tocbuffer[1] = 0x02; + tocbuffer[2] = 0xF2; + tocbuffer[3] = 0x00; + + tocbuffer[16] = 0x00; + tocbuffer[17] = 0x03; + tocbuffer[18] = 0x00; + tocbuffer[19] = 0x00; + + disctype = tempdisctype; // Triggers the fact the other info is available + return(disctype); +} // END DVDgetDiskType() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.h b/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.h new file mode 100644 index 0000000000..7dbc1c7c0d --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/DVD.h @@ -0,0 +1,45 @@ +/* DVD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DVD_H__ +#define __DVD_H__ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +// Exported Functions + +extern void HexDump(u8 *strptr, u8 count); +extern void InitDVDInfo(); +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DVDgetTN(cdvdTN *cdvdtn); +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 DVDgetDiskType(s32 ioctldisktype); + + +#endif /* __DVD_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/Makefile b/plugins/cdvd/CDVDlinuz/Src/Linux/Makefile new file mode 100644 index 0000000000..be45567df9 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/Makefile @@ -0,0 +1,71 @@ + +PLUGIN = libCDVDlinuz.so +PLUGINOBJS = CDVDlinuz.o ../buffer.o +PLUGINHEADERS = CDVDlinuz.h ../buffer.h +PLUGINFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -D_LARGEFILE64_SOURCE \ + -I.. -I. -I./Linux +PLUGINLIBS = + +CFG = cfgCDVDlinuz +CFGOBJS = aboutbox.o mainbox.o interface.o +CFGHEADERS = aboutbox.h mainbox.h interface.h +CFGFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -D_LARGEFILE64_SOURCE \ + -I.. -I. -I./Linux +CFGLIBS = + +SHAREDOBJS = actualfile.o conf.o logfile.o \ + device.o CD.o DVD.o \ + ../convert.o ../ini.o ../version.o +SHAREDHEADERS = actualfile.h conf.h logfile.h \ + device.h CD.h DVD.h \ + ../convert.h ../ini.h ../version.h + + +CC = gcc + +GTKFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +//GTKFLAGS += -DG_DISABLE_DEPRECATED \ +// -DGDK_DISABLE_DEPRECATED \ +// -DGDK_PIXBUF_DISABLE_DEPRECATED \ +// -DGTK_DISABLE_DEPRECATED + +GTKLIBS = $(shell pkg-config --libs gtk+-2.0) +# Do we need to remove "-rdynamic" as well? Or is that just the main program? + + +all: plugin cfg +install: all + +release: plugin cfg + cp $(PLUGIN) ../.. + cp $(CFG) ../.. + +plugin: $(PLUGINOBJS) $(SHAREDOBJS) +# rm -f $(PLUGIN) + $(CC) -shared -Wl,-soname,$(PLUGIN) $(PLUGINFLAGS) $(PLUGINLIBS) \ + $(PLUGINOBJS) $(SHAREDOBJS) -o $(PLUGIN) + strip --strip-unneeded --strip-debug $(PLUGIN) + +cfg: $(CFGOBJS) $(SHAREDOBJS) +# rm -f $(CFG) + $(CC) $(CFGFLAGS) $(GTKFLAGS) $(CFGLIBS) $(GTKLIBS) \ + $(CFGOBJS) $(SHAREDOBJS) -o $(CFG) + strip $(CFG) + +$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c + $(CC) $(PLUGINFLAGS) -c $< -o $@ + +$(CFGOBJS): %.o: %.c + $(CC) $(CFGFLAGS) $(GTKFLAGS) -c $< -o $@ + +.PHONY : clean allclean +clean: + -rm -f $(PLUGINOBJS) $(PLUGIN) $(CFGOBJS) $(CFG) $(SHAREDOBJS) + -rm -f *~ temp.txt ../*~ ../temp.txt ../../*~ + +allclean: + -rm -f $(PLUGINOBJS) $(PLUGIN) $(CFGOBJS) $(CFG) $(SHAREDOBJS) + -rm -f *~ temp.txt ../*~ ../temp.txt ../../*~ + -rm -f ../../$(PLUGIN) ../../$(CFG) + diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.c b/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.c new file mode 100644 index 0000000000..9408d0bc8e --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.c @@ -0,0 +1,106 @@ +/* aboutbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() + +#include // gtk_button_new_with_label() +#include // gtk_container_add() +#include // gtk_hbutton_box_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "version.h" +#include "aboutbox.h" + + +struct AboutBoxData aboutbox; + + +gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + if(aboutbox.window != NULL) { + gtk_widget_destroy(aboutbox.window); + aboutbox.window = NULL; + } // ENDIF- Do we have an About Box still? + + gtk_main_quit(); + return(TRUE); +} // END AboutBoxCancelEvent() + + +void AboutBoxDisplay() { + GtkWidget *item; + GtkWidget *container; + GtkWidget *vbox1; + char templine[256]; + + aboutbox.window = NULL; + aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); + gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDlinuz"); + gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); + gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); + + g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", + G_CALLBACK(AboutBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + sprintf(templine, "%s v%i.%i", libname, revision, build); + item = gtk_label_new(templine); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + item = gtk_label_new("Current Author: efp"); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + item = gtk_label_new("Original code by: linuzappz & shadow"); + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + container = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); + gtk_widget_show(container); + + item = gtk_button_new_with_label("Ok"); + gtk_container_add(GTK_CONTAINER(container), item); + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(AboutBoxCancelEvent), NULL); + item = NULL; + container = NULL; + vbox1 = NULL; + + gtk_widget_show(aboutbox.window); + gtk_main(); +} // END AboutDisplay() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.h b/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.h new file mode 100644 index 0000000000..bf1df52ca0 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/aboutbox.h @@ -0,0 +1,39 @@ +/* aboutbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef ABOUTBOX_H +#define ABOUTBOX_H + + +#include + + +struct AboutBoxData { + GtkWidget *window; // GtkWindow - About Box +}; + +extern struct AboutBoxData aboutbox; + + +extern void AboutBoxDisplay(); + + +#endif /* ABOUTBOX_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.c b/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.c new file mode 100644 index 0000000000..64eaa69a7b --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.c @@ -0,0 +1,222 @@ +/* actualfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // errno +#include // open() +#include // rename() +#include // strerror() +#include // stat64(), open(), fstat() +#include // stat64(), open(), fstat(), lseek64() +#include // stat64(), fstat(), lseek64(), read(), close(), write() +// unlink() + +#include "logfile.h" +#include "actualfile.h" + + +int IsActualFile(const char *filename) { + int retval; + struct stat64 filestat; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: IsActualFile(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = stat64(filename, &filestat); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error retrieving stats on %s", filename); + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); // Name doesn't exist. + } // ENDIF- Trouble getting stat on a file? + + if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. + return(0); // Yep, that's a file. +} // END IsActualFile() + + +void ActualFileDelete(const char *filename) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + unlink(filename); +} // END ActualFileDelete() + + +void ActualFileRename(const char *origname, const char *newname) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + rename(origname, newname); + return; +} // END ActualFileRename() + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + int newhandle; + + if(filename == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + newhandle = open(filename, O_RDONLY | O_LARGEFILE); + if((newhandle < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s\n", filename); + PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForRead() + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + int retval; + struct stat64 filestat; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSize()\n"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = fstat64(handle, &filestat); + if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. + return(filestat.st_size); +} // END ActualFileSize() + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + off64_t moved; + + if(handle < 0) return(-1); + if(position < 0) return(-1); // Maybe... position = 0? + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + moved = lseek64(handle, position, SEEK_SET); + if(errno != 0) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error on seek (%lli)", position); + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(0); +} // END ActualFileSeek() + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + + if(handle == ACTUALHANDLENULL) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = read(handle, buffer, bytes); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error reading from file!"); + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + // return(-1); + } // ENDIF- Error? Abort + + return(retval); // Send back how many bytes read +} // END ActualFileRead() + + +void ActualFileClose(ACTUALHANDLE handle) { + if(handle < 0) return; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileClose()"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + close(handle); + return; +} // END ActualFileClose() + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + int newhandle; + + if(filename == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); + if((newhandle < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s", filename); + PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForWrite() + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + + if(handle < 0) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + errno = 0; + retval = write(handle, buffer, bytes); + if((retval < 0) || (errno != 0)) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error writing to file!"); + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + // return(-1); + } // ENDIF- Error? Abort + + return(retval); // Send back how many bytes written +} // END ActualFileWrite() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.h b/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.h new file mode 100644 index 0000000000..a678b634d6 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/actualfile.h @@ -0,0 +1,50 @@ +/* actualfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef ACTUALFILE_H +#define ACTUALFILE_H + + +#include // off64_t + + +#define ACTUALHANDLE int +#define ACTUALHANDLENULL -1 + +// #define VERBOSE_FUNCTION_ACTUALFILE +// #define VERBOSE_WARNING_ACTUALFILE + + +extern int IsActualFile(const char *filename); +extern void ActualFileDelete(const char *filename); +extern void ActualFileRename(const char *origname, const char *newname); + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); +extern off64_t ActualFileSize(ACTUALHANDLE handle); +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); +extern void ActualFileClose(ACTUALHANDLE handle); + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + +#endif /* ACTUALFILE_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/conf.c b/plugins/cdvd/CDVDlinuz/Src/Linux/conf.c new file mode 100644 index 0000000000..330af46023 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/conf.c @@ -0,0 +1,184 @@ +/* conf.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // getenv() +#include // strerror() +#include // mkdir(), stat() +#include // mkdir(), stat() +#include // stat() + +// #define CDVDdefs +// #include "../PS2Edefs.h" +#include "logfile.h" +#include "../ini.h" +#include "conf.h" + + +const char *cfgname[] = { \ + "./cfg/cfgCDVDlinuz", \ + "../cfg/cfgCDVDlinuz", \ + "./plugins/cfgCDVDlinuz", \ + "../plugins/cfgCDVDlinuz", \ + "./cfgCDVDlinuz", \ + "../cfgCDVDlinuz", \ + NULL }; + +const char *confnames[] = { "Device", NULL }; +const u8 defaultdevice[] = DEFAULT_DEVICE; +const char defaulthome[] = "../inis"; +const char defaultdirectory[] = ".PS2E"; +const char defaultfile[] = "CDVDlinuz.ini"; + +char confdirname[256]; +char conffilename[256]; + +CDVDconf conf; + + +void ExecCfg(char *arg) { + int nameptr; + struct stat filestat; + char templine[256]; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: ExecCfg(%s)", arg); +#endif /* VERBOSE FUNCTION_CONF */ + errno = 0; + nameptr = 0; + while((cfgname[nameptr] != NULL) && + (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; + errno = 0; + + if(cfgname[nameptr] == NULL) { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: Couldn't find configuration program!"); +#endif /* VERBOSE_FUNCTION_CONF */ + return; + } // ENDIF- Did not find the executable? + + sprintf(templine, "%s %s", cfgname[nameptr], arg); + system(templine); +} // END ExecCfg() + + +void InitConf() { + int i; + int pos; + char *envptr; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: InitConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + i = 0; + while((i < 255) && defaultdevice[i] != 0) { + conf.devicename[i] = defaultdevice[i]; + i++; + } // ENDWHILE- copying the default CD/DVD name in + conf.devicename[i] = 0; // 0-terminate the device name + + // Locating directory and file positions + pos = 0; + envptr = getenv("HOME"); + if(envptr == NULL) { + // = + i = 0; + while((pos < 253) && (defaulthome[i] != 0)) { + confdirname[pos] = defaulthome[i]; + conffilename[pos] = defaulthome[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + } else { + // = / + i = 0; + while((pos < 253) && (*(envptr + i) != 0)) { + confdirname[pos] = *(envptr + i); + conffilename[pos] = *(envptr + i); + pos++; + i++; + } // ENDWHILE- copying home directory info in + + if(confdirname[pos-1] != '/') { + confdirname[pos] = '/'; + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultdirectory[i] != 0)) { + confdirname[pos] = defaultdirectory[i]; + conffilename[pos] = defaultdirectory[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + } // ENDIF- No Home directory? + + confdirname[pos] = 0; // Directory reference finished + + // += / + if(conffilename[pos-1] != '/') { + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultfile[i] != 0)) { + conffilename[pos] = defaultfile[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + conffilename[pos] = 0; // File reference finished + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: Directory: %s\n", confdirname); + PrintLog("CDVD config: File: %s\n", conffilename); +#endif /* VERBOSE_FUNCTION_CONF */ +} // END InitConf() + + +void LoadConf() { + int retval; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: LoadConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + if(retval < 0) { + sprintf(conf.devicename, "/dev/dvd"); + } // ENDIF- Couldn't find keyword? Fill in a default +} // END LoadConf() + + +void SaveConf() { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: SaveConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + mkdir(confdirname, 0755); + + INISaveString(conffilename, "Settings", "Device", conf.devicename); +} // END SaveConf() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/conf.h b/plugins/cdvd/CDVDlinuz/Src/Linux/conf.h new file mode 100644 index 0000000000..b66dfd05c1 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/conf.h @@ -0,0 +1,57 @@ +/* conf.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef CONF_H +#define CONF_H + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "../PS2Edefs.h" + + +#define VERBOSE_FUNCTION_CONF + + +// Configuration Data + +typedef struct { + u8 devicename[256]; +} CDVDconf; +extern CDVDconf conf; + +#define DEFAULT_DEVICE "/dev/cdrom" + + +// Configuration Functions + +extern void InitConf(); +extern void LoadConf(); +extern void SaveConf(); + +extern void ExecCfg(char *arg); + + +#endif /* CONF_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/device.c b/plugins/cdvd/CDVDlinuz/Src/Linux/device.c new file mode 100644 index 0000000000..b45f883da4 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/device.c @@ -0,0 +1,420 @@ +/* device.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // open() +#include // NULL +#include // getenv() +#include // strerror() +#include // ioctl() +#include // open() +#include // open() +#include // time_t, time(), struct timeval +#include // close(), select() + +#include // CD/DVD based ioctl() and defines. + +// missing on some files for some reason......... +#ifndef CDC_IOCTLS +#define CDC_IOCTLS 0x400 +#endif + +#include "logfile.h" +#include "conf.h" +#include "CD.h" +#include "DVD.h" +#include "device.h" + +#include "../PS2Etypes.h" // u32, u8, s32 + + +// Globals + +int devicehandle; // File Handle for the device/drive +s32 devicecapability; // Capability Flags +time_t lasttime; // Time marker (in case something gets called too often) +s32 traystatus; // Is the CD/DVD tray open? + +s32 disctype; // Type of disc in drive (Video DVD, PSX CD, etc.) +u8 tocbuffer[2048]; + + +void DeviceInit() { + devicehandle = -1; + devicecapability = 0; + lasttime = time(NULL); + + InitDisc(); +} // END DeviceInit() + + +// Called by DeviceOpen(), DeviceGetDiskType() +void InitDisc() { + int i; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: InitDisc()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if((disctype == CDVD_TYPE_PS2DVD) || + (disctype == CDVD_TYPE_DVDV)) { + InitDVDInfo(); + } // ENDIF- Clean out DVD Disc Info? + + if((disctype == CDVD_TYPE_PS2CD) || + (disctype == CDVD_TYPE_PS2CDDA) || + (disctype == CDVD_TYPE_PSCD) || + (disctype == CDVD_TYPE_PSCDDA) || + (disctype == CDVD_TYPE_CDDA)) { + InitCDInfo(); + } // ENDIF- Clean out DVD Disc Info? + + disctype = CDVD_TYPE_NODISC; + for(i = 0; i > sizeof(tocbuffer); i++) tocbuffer[i] = 0x00; +} // END InitDisc() + + +s32 DiscInserted() { + if(devicehandle == -1) return(-1); + if(traystatus == CDVD_TRAY_OPEN) return(-1); + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + if(disctype == CDVD_TYPE_DETCT) return(-1); + if(disctype == CDVD_TYPE_NODISC) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DiscInserted()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + return(0); +} // END DiscInserted() + + +// Called by DeviceTrayStatus() and CDVDopen() +s32 DeviceOpen() { + // s32 s32result; + + errno = 0; + + if(devicehandle != -1) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVD device: Device already open!"); +#endif /* VERBOSE_WARNING_DEVICE */ + return(0); + } // ENDIF- Is the CD/DVD already in use? That's fine. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + // InitConf(); + // LoadConf(); // Should be done once before making this call + + devicehandle = open(conf.devicename, O_RDONLY | O_NONBLOCK); + if(devicehandle == -1) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Error opening device: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + return(-1); + } // ENDIF- Failed to open device? Abort + + // Note: Hmm. Need a minimum capability in case this fails? + devicecapability = ioctl(devicehandle, CDROM_GET_CAPABILITY); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Error getting device capabilities: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + close(devicehandle); + devicehandle = -1; + devicecapability = 0; + return(-1); + } // ENDIF- Can't read drive capabilities? Close and Abort. + +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVD device: Device Type(s)"); + if(devicecapability < CDC_CD_R) PrintLog("CDVD device: CD"); + if(devicecapability & CDC_CD_R) PrintLog("CDVD device: CD-R"); + if(devicecapability & CDC_CD_RW) PrintLog("CDVD device: CD-RW"); + if(devicecapability & CDC_DVD) PrintLog("CDVD device: DVD"); + if(devicecapability & CDC_DVD_R) PrintLog("CDVD device: DVD-R"); + if(devicecapability & CDC_DVD_RAM) PrintLog("CDVD device: DVD-RAM"); +#endif /* VERBOSE_DISC_TYPE */ +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVD device: Device Capabilities:"); + if(devicecapability & CDC_CLOSE_TRAY) PrintLog("CDVD device: Can close a tray"); + if(devicecapability & CDC_OPEN_TRAY) PrintLog("CDVD device: Can open a tray"); + // if(devicecapability & CDC_LOCK) PrintLog("CDVD device: Can lock the drive door"); + if(devicecapability & CDC_SELECT_SPEED) PrintLog("CDVD device: Can change spin speed"); + // if(devicecapability & CDC_SELECT_DISC) PrintLog("CDVD device: Can change disks (multi-disk tray)"); + // if(devicecapability & CDC_MULTI_SESSION) PrintLog("CDVD device: Can read multi-session disks"); + // if(devicecapability & CDC_MCN) PrintLog("CDVD device: Can read Medium Catalog Numbers (maybe)"); + if(devicecapability & CDC_MEDIA_CHANGED) PrintLog("CDVD device: Can tell if the disc was changed"); + if(devicecapability & CDC_PLAY_AUDIO) PrintLog("CDVD device: Can play audio disks"); + // if(devicecapability & CDC_RESET) PrintLog("CDVD device: Can reset the device"); + if(devicecapability & CDC_IOCTLS) PrintLog("CDVD device: Odd IOCTLs. Not sure of compatability"); + if(devicecapability & CDC_DRIVE_STATUS) PrintLog("CDVD device: Can monitor the drive tray"); +#endif /* VERBOSE_DISC_INFO */ + + ////// Should be called after an open (instead of inside of one) + // InitDisc(); + // traystatus = CDVD_TRAY_OPEN; // Start with Tray Open + // DeviceTrayStatus(); // Now find out for sure. + + return(0); // Device opened and ready for use. +} // END DeviceOpen() + + +// Called by DeviceTrayStatus(), CDVDclose(), and CDVDshutdown() +void DeviceClose() { + if(devicehandle == -1) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: Device already closed"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + return; + } // ENDIF- Device already closed? Ok. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + InitDisc(); + close(devicehandle); + devicehandle = -1; + devicecapability = 0; + return; +} // END CDVDclose() + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceReadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(DiscInserted() == -1) return(-1); + + // Get that data + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + s32result = DVDreadTrack(lsn, mode, buffer); + } else { + s32result = CDreadTrack(lsn, mode, buffer); + } //ENDIF- Read a DVD sector or a CD sector? + + return(s32result); +} // END DeviceReadTrack() + + +s32 DeviceBufferOffset() { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceBufferOffset()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(0); + } else { + return(CDgetBufferOffset()); + } // ENDIF- Is this a DVD? +} // END DeviceBufferOffset() + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(track, cdvdtd)); + } else { + return(CDgetTD(track, cdvdtd)); + } // ENDIF- Is this a DVD? +} // END DeviceGetTD() + + +// Called by DeviceTrayStatus() +s32 DeviceGetDiskType() { + s32 s32result; + s32 ioctldisktype; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if(traystatus == CDVD_TRAY_OPEN) { + return(disctype); + } // ENDIF- Is the device tray open? No disc to check yet. + + if(disctype != CDVD_TYPE_NODISC) { + return(disctype); + } // ENDIF- Already checked? Drive still closed? Disc hasn't changed. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceGetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + disctype = CDVD_TYPE_DETCT; + + ioctldisktype = ioctl(devicehandle, CDROM_DISC_STATUS); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble reading Disc Type!"); + PrintLog("CDVD device: Error: %i:%s", errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + disctype = CDVD_TYPE_UNKNOWN; + return(disctype); + } // ENDIF- Trouble probing for a disc? + + s32result = DVDgetDiskType(ioctldisktype); + if(s32result != -1) { + return(disctype); + } // ENDIF- Did we find a disc type? + + s32result = CDgetDiskType(ioctldisktype); + if(s32result != -1) { + return(disctype); + } // ENDIF- Did we find a disc type? + + disctype = CDVD_TYPE_UNKNOWN; // Not a CD? Not a DVD? Is is peanut butter? + return(disctype); +} // END CDVDgetDiskType() + + +// Called by PollLoop() and CDVDgetTrayStatus() +s32 DeviceTrayStatus() { + s32 s32result; + + errno = 0; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayStatus()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_DRIVE_STATUS) != 0) { + s32result = ioctl(devicehandle, CDROM_DRIVE_STATUS); + if(s32result < 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble reading Drive Status!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + s32result = CDS_TRAY_OPEN; + } // ENDIF- Failure to get status? Assume it's open. + errno = 0; + + } else { + s32result = ioctl(devicehandle, CDROM_DISC_STATUS); + if(errno != 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD device: Trouble detecting Disc Status presense!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); +#endif /* VERBOSE_WARNINGS */ + s32result = CDS_TRAY_OPEN; + errno = 0; + } // ENDIF- Trouble? + if(s32result == CDS_NO_DISC) { + s32result = CDS_TRAY_OPEN; + } // ENDIF- Is there no disc in the device? Guess the tray is open + } // ENDIF- Can we poll the tray directly? (Or look at disc status instead?) + + if(s32result == CDS_TRAY_OPEN) { + traystatus = CDVD_TRAY_OPEN; + if(disctype != CDVD_TYPE_NODISC) { + DeviceClose(); // Kind of severe way of flushing all buffers. + DeviceOpen(); + InitDisc(); + } // ENDIF- Tray just opened... clear disc info + } else { + traystatus = CDVD_TRAY_CLOSE; + if(disctype == CDVD_TYPE_NODISC) { + DeviceGetDiskType(); + } // ENDIF- Tray just closed? Get disc information + } // ENDIF- Do we detect an open tray? + return(traystatus); +} // END CDVD_getTrayStatus() + + +s32 DeviceTrayOpen() { + s32 s32result; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_OPEN_TRAY) == 0) { + return(-1); + } // ENDIF- Don't have open capability? Error out. + + // Tray already open? Exit. + if(traystatus == CDVD_TRAY_OPEN) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + s32result = ioctl(devicehandle, CDROMEJECT); +#ifdef VERBOSE_WARNINGS + if((s32result != 0) || (errno != 0)) { + PrintLog("CDVD device: Could not open the tray!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); + } // ENDIF- Trouble? +#endif /* VERBOSE_WARNINGS */ + return(s32result); +} // END DeviceTrayOpen() + + +s32 DeviceTrayClose() { + s32 s32result; + + errno = 0; + + if(devicehandle == -1) { + return(-1); + } // ENDIF- Someone forget to open the device? + + if((devicecapability & CDC_CLOSE_TRAY) == 0) { + return(-1); + } // ENDIF- Don't have close capability? Error out. + + // Tray already closed? Exit. + if(traystatus == CDVD_TRAY_CLOSE) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD device: DeviceTrayClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + s32result = ioctl(devicehandle, CDROMCLOSETRAY); +#ifdef VERBOSE_WARNINGS + if((s32result != 0) || (errno != 0)) { + PrintLog("CDVD device: Could not close the tray!"); + PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); + } // ENDIF- Trouble? +#endif /* VERBOSE_WARNINGS */ + return(s32result); +} // END DeviceTrayClose() + diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/device.h b/plugins/cdvd/CDVDlinuz/Src/Linux/device.h new file mode 100644 index 0000000000..0d0d8ffe49 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/device.h @@ -0,0 +1,69 @@ +/* device.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + + +#include // time_t + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ +#define CDVDdefs +#include "../PS2Edefs.h" + + +// #define VERBOSE_FUNCTION_DEVICE +// #define VERBOSE_WARNINGS +#define VERBOSE_DISC_TYPE +#define VERBOSE_DISC_INFO + + +// Device Data + +extern int devicehandle; +extern s32 devicecapability; // Need to export? + +extern time_t lasttime; +extern s32 traystatus; +extern s32 disctype; +extern u8 tocbuffer[]; + + +// Device Functions + +extern void DeviceInit(); +extern void InitDisc(); +extern s32 DiscInserted(); +extern s32 DeviceOpen(); +extern void DeviceClose(); +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DeviceBufferOffset(); +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); +extern s32 DeviceGetDiskType(); +extern s32 DeviceTrayStatus(); +extern s32 DeviceTrayOpen(); +extern s32 DeviceTrayClose(); + + +#endif /* __DEVICE_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/interface.c b/plugins/cdvd/CDVDlinuz/Src/Linux/interface.c new file mode 100644 index 0000000000..5a354d9808 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/interface.c @@ -0,0 +1,57 @@ +/* interface.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcmp() + +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_widget_show_all() + +#include "logfile.h" +#include "conf.h" +#include "aboutbox.h" +#include "mainbox.h" + + +int main(int argc, char *argv[]) { + if(argc != 2) return(1); + + gtk_init(NULL, NULL); + + if(!strcmp(argv[1], "about")) { + AboutBoxDisplay(); + return(0); + + } else if (!strcmp(argv[1], "configure")) { + OpenLog(); + InitConf(); + LoadConf(); + MainBoxDisplay(); + + gtk_widget_show_all(mainbox.window); + gtk_main(); + CloseLog(); + return(0); + } // ENDLONGIF- Which display would you like to see? + + return(1); // No Displays chosen? Abort! +} // END main() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.c b/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.c new file mode 100644 index 0000000000..27c6fe879b --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.c @@ -0,0 +1,90 @@ +/* logfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // open +#include // vsprintf() +#include // va_start(), va_end(), vsprintf() +#include // mkdir(), open() +#include // mkdir(), open() +#include // close(), write(), unlink() + +#include "logfile.h" + + +int logfile; +char logfiletemp[2048]; + + +void InitLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + mkdir("./logs", 0755); + + unlink("./logs/CDVDlog.txt"); +#endif /* VERBOSE LOGFILE */ +} // END InitLog(); + + +int OpenLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + logfile = -1; + logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); + if(logfile == -1) return(-1); +#endif /* VERBOSE LOGFILE */ + + return(0); +} // END OpenLog(); + + +void CloseLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + if(logfile != -1) { + close(logfile); + logfile = -1; + } // ENDIF- Is the log file actually open? Close it. +#endif /* VERBOSE LOGFILE */ +} // END CloseLog() + + +void PrintLog(const char *fmt, ...) { + // Token comment line +#ifdef VERBOSE_LOGFILE + va_list list; + int len; + + if(logfile == -1) return; // Log file not open. + + va_start(list, fmt); + vsprintf(logfiletemp, fmt, list); + va_end(list); + + len = 0; + while((len < 2048) && (logfiletemp[len] != 0)) len++; + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + write(logfile, logfiletemp, len); + write(logfile, "\r\n", 2); // ... and write out your own. +#endif /* VERBOSE LOGFILE */ +} // END PrintLog() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.h b/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.h new file mode 100644 index 0000000000..8cee990080 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/logfile.h @@ -0,0 +1,35 @@ +/* logfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef LOGFILE_H +#define LOGFILE_H + + +#define VERBOSE_LOGFILE + + +extern void InitLog(); +extern int OpenLog(); +extern void CloseLog(); +extern void PrintLog(const char *format, ...); + + +#endif /* LOGFILE_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.c b/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.c new file mode 100644 index 0000000000..c6423e21a6 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.c @@ -0,0 +1,187 @@ +/* mainbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() +#include // strcpy() +#include // stat() +#include // stat() +#include // stat() + +#include // gtk_button_new_with_label() +#include // gtk_container_add() +#include // gtk_entry_new() +#include // gtk_hbutton_box_new() +#include // gtk_hbox_new() +#include // gtk_label_new() +#include // gtk_init(), gtk_main(), gtk_main_quit() +#include // gtk_vbox_new() +#include // gtk_window_new() + +#include "conf.h" +// #include "logfile.h" +#include "device.h" // DeviceOpen(), DeviceClose() +#include "mainbox.h" + + +struct MainBoxData mainbox; + + +void MainBoxDestroy() { + if(mainbox.window != NULL) { + gtk_widget_destroy(mainbox.window); + mainbox.window = NULL; + mainbox.device = NULL; + mainbox.desc = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + gtk_widget_set_sensitive(mainbox.device, FALSE); + gtk_window_iconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxUnfocus() + + +gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + struct stat filestat; + int retval; + + retval = stat(gtk_entry_get_text(GTK_ENTRY(mainbox.device)), &filestat); + if(retval == -1) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: ---"); + return(TRUE); + } // ENDIF- Not a name of any sort? + + if(S_ISDIR(filestat.st_mode) != 0) { + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Not a device"); + return(TRUE); + } // ENDIF- Not a regular file? + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Device Likely"); + return(TRUE); +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + GdkEvent event; + + MainBoxDeviceEvent(NULL, event, NULL); + + gtk_widget_set_sensitive(mainbox.device, TRUE); + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); +} // END MainBoxRefocus() + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + MainBoxDestroy(); + + gtk_main_quit(); + return(TRUE); +} // END MainBoxCancelEvent() + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + const char *tempdevice; + int retval; + + MainBoxUnfocus(); + + tempdevice = gtk_entry_get_text(GTK_ENTRY(mainbox.device)); + strcpy(conf.devicename, tempdevice); // Temporarily put in new device name + tempdevice = NULL; + if(*(conf.devicename) != 0) { + retval = DeviceOpen(); // Test by opening the device. + DeviceClose(); // Failed or not, close it. + if(retval != 0) { + MainBoxRefocus(); + return(TRUE); + } // ENDIF- Not an ISO file? Message and Stop here. + } // ENDIF- Is there an ISO file to check out? + + SaveConf(); + + MainBoxCancelEvent(widget, event, data); + return(TRUE); +} // END MainBoxOKEvent() + + +void MainBoxDisplay() { + GtkWidget *item; + GtkWidget *hbox1; + GtkWidget *vbox1; + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDlinuz Configuration"); + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + G_CALLBACK(MainBoxCancelEvent), NULL); + + vbox1 = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + gtk_widget_show(vbox1); + + hbox1 = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_label_new("CD/DVD Device:"); + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + gtk_widget_show(item); + item = NULL; + + mainbox.device = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.device, TRUE, TRUE, 0); + gtk_widget_show(mainbox.device); + g_signal_connect(G_OBJECT(mainbox.device), "changed", + G_CALLBACK(MainBoxDeviceEvent), NULL); + hbox1 = NULL; + + mainbox.desc = gtk_label_new("File Type: ---"); + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); + gtk_widget_show(mainbox.desc); + + hbox1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + gtk_widget_show(hbox1); + + item = gtk_button_new_with_label("Ok"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(MainBoxOKEvent), NULL); + + item = gtk_button_new_with_label("Cancel"); + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + gtk_widget_show(item); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(MainBoxCancelEvent), NULL); + item = NULL; + hbox1 = NULL; + vbox1 = NULL; + + // We held off setting the name until now... so description would show. + gtk_entry_set_text(GTK_ENTRY(mainbox.device), conf.devicename); +} // END MainBoxDisplay() diff --git a/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.h b/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.h new file mode 100644 index 0000000000..c862063ee1 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Linux/mainbox.h @@ -0,0 +1,41 @@ +/* mainbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef MAINBOX_H +#define MAINBOX_H + + +#include + + +struct MainBoxData { + GtkWidget *window; // GtkWindow + GtkWidget *device; // GtkEntry + GtkWidget *desc; // GtkLabel +}; + +extern struct MainBoxData mainbox; + +// extern void MainBoxRefocus(); +extern void MainBoxDisplay(); + + +#endif /* MAINBOX_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/PS2Edefs.h b/plugins/cdvd/CDVDlinuz/Src/PS2Edefs.h new file mode 100644 index 0000000000..ef33df3686 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/PS2Edefs.h @@ -0,0 +1,812 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/PS2Etypes.h b/plugins/cdvd/CDVDlinuz/Src/PS2Etypes.h new file mode 100644 index 0000000000..1d605708aa --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/CD.c b/plugins/cdvd/CDVDlinuz/Src/Win32/CD.c new file mode 100644 index 0000000000..24c64999b3 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/CD.c @@ -0,0 +1,387 @@ +/* CD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include // IOCTL_CDROM... + +#include // off64_t + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" +#include "../convert.h" // MSFtoLBA(), HEXTOBCD() +#include "actualfile.h" +#include "device.h" // tocbuffer[], FinishCommand() +#include "CD.h" + + +int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA +DWORD cdblocksize; // 2048 to 2352 +int cdoffset; // 0, 8, 16, or 24 +int cdmode; + + +void InitCDInfo() { + actualcdmode = -1; + cdblocksize = 2048; + cdmode = -1; +} // END InitCDInfo() + + +s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { + RAW_READ_INFO rawinfo; + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + LARGE_INTEGER targetpos; + int i; + + if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(actualcdmode >= 0) { + rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. + rawinfo.SectorCount = 1; + rawinfo.TrackMode = actualcdmode; + boolresult = DeviceIoControl(devicehandle, + IOCTL_CDROM_RAW_READ, + &rawinfo, + sizeof(RAW_READ_INFO), + buffer, + 2352, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz CD: Couldn't read a sector raw!"); + PrintError("CDVDlinuz CD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + } else { + targetpos.QuadPart = lsn * 2048; + waitevent.Offset = targetpos.LowPart; + waitevent.OffsetHigh = targetpos.HighPart; + + boolresult = ReadFile(devicehandle, + buffer + 24, + 2048, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz CD: Couldn't read a cooked sector!"); + PrintError("CDVDlinuz CD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Trouble with seek? Report it. + + for(i = 0; i < 24; i++) *(buffer + i) = 0; + for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; + } // ENDIF- Could we read a raw sector? Read another one! + + if(boolresult == FALSE) { + boolresult = GetOverlappedResult(devicehandle, + &waitevent, + &byteswritten, + FALSE); + } // ENDIF- Did the initial call not complete? Get byteswritten for + // the completed call. + + if(byteswritten < 2048) { +#ifdef VERBOSE_WARNING_DEVICE + errcode = GetLastError(); + PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", + byteswritten, cdblocksize); + PrintError("CDVDlinuz CD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + cdmode = mode; + cdblocksize = byteswritten; + return(0); +} // END CDreadTrackPass() + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + int retval; + int lastmode; + int i; + + retval = CDreadTrackPass(lsn, mode, buffer); + if(retval >= 0) return(retval); + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz CD: Same mode doesn't work. Scanning..."); +#endif /* VERBOSE_WARNING_DEVICE */ + + lastmode = actualcdmode; + actualcdmode = 2; + while(actualcdmode >= -1) { + retval = CDreadTrackPass(lsn, mode, buffer); + if(retval >= 0) return(retval); + actualcdmode--; + } // ENDWHILE- Searching each mode for a way to read the sector + actualcdmode = lastmode; // None worked? Go back to first mode. + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz CD: No modes work. Failing sector!"); +#endif /* VERBOSE_WARNING_DEVICE */ + + for(i = 0; i < 2352; i++) *(buffer + i) = 0; + return(-1); +} // END CDreadTrack() + + +s32 CDgetBufferOffset() { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVD CD: CDgetBufferOffset()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + // Send a whole CDDA record in? + if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); + + // Otherwise, send the start of the data block in... + return(cdoffset); +} // END CDgetBufferOffset() + + +s32 CDreadSubQ() { + return(-1); +} // END CDreadSubQ() + + +s32 CDgetTN(cdvdTN *cdvdtn) { + cdvdtn->strack = BCDTOHEX(tocbuffer[7]); + cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); + return(0); +} // END CDgetTN() + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + u8 actualtrack; + int pos; + char temptime[3]; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz CD: CDgetTD()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + actualtrack = newtrack; + if(actualtrack == 0xaa) actualtrack = 0; + + if(actualtrack == 0) { + cdvdtd->type = 0; + temptime[0] = BCDTOHEX(tocbuffer[27]); + temptime[1] = BCDTOHEX(tocbuffer[28]); + temptime[2] = BCDTOHEX(tocbuffer[29]); + cdvdtd->lsn = MSFtoLBA(temptime); + } else { + pos = actualtrack * 10; + pos += 30; + cdvdtd->type = tocbuffer[pos]; + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + cdvdtd->lsn = MSFtoLBA(temptime); + } // ENDIF- Whole disc? (or single track?) + + return(0); +} // END CDgetTD() + + +s32 CDgetDiskType() { + CDROM_TOC cdinfo; + BOOL boolresult; + int retval; + DWORD byteswritten; + DWORD errcode; + u8 iso9660name[] = "CD001\0"; + u8 playstationname[] = "PLAYSTATION\0"; + u8 ps1name[] = "CD-XA001\0"; + u8 tempbuffer[2448]; + int tempdisctype; + int i; + int pos; + unsigned long volumesize; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz CD: CDgetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + tempdisctype = CDVD_TYPE_UNKNOWN; + + actualcdmode = 2; + retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); + if(retval < 0) { + disctype = tempdisctype; + return(-1); + } // ENDIF- Couldn't read the directory sector? Abort. + + disctype = CDVD_TYPE_DETCTCD; + tempdisctype = CDVD_TYPE_CDDA; + + cdoffset = 0; + i = 0; + while((cdoffset <= 24) && (iso9660name[i] != 0)) { + i = 0; + while((iso9660name[i] != 0) && + (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; + if(iso9660name[i] != 0) cdoffset += 8; + } // ENDWHILE- Trying to find a working offset for a ISO9660 record. + + if(iso9660name[i] != 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("Detected a CDDA (Music CD)."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_CDDA; + tocbuffer[0] = 0x01; + + } else { + tocbuffer[0] = 0x41; + i = 0; + while((playstationname[i] != 0) && + (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; + if(playstationname[i] != 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("Detected a non-Playstation CD."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_UNKNOWN; + + } else { + i = 0; + while((ps1name[i] != 0) && + (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; + if(ps1name[i] != 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("Detected a Playstation 2 CD."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2CD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("Detected a Playstation CD."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PSCD; + } // ENDIF- Is this not a PlayStation Disc? + } // ENDIF- Is this not a PlayStation Disc? + } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) + + // Build the Fake TOC + tocbuffer[2] = 0xA0; + tocbuffer[7] = HEXTOBCD(1); // Starting Track + tocbuffer[12] = 0xA1; + tocbuffer[17] = HEXTOBCD(1); // Ending Track + + volumesize = tempbuffer[84]; // Volume size (big endian) + volumesize *= 256; + volumesize += tempbuffer[85]; + volumesize *= 256; + volumesize += tempbuffer[86]; + volumesize *= 256; + volumesize += tempbuffer[87]; +#ifdef VERBOSE_DISC_INFO + if(tempdisctype != CDVD_TYPE_CDDA) { + PrintLog("CDVDlinuz CD: ISO9660 size %llu", volumesize); + } // ENDIF- Data CD? Print size in blocks. +#endif /* VERBOSE_DISC_INFO */ + + LBAtoMSF(volumesize, &tocbuffer[27]); + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + tocbuffer[40] = 0x02; // Data Mode + tocbuffer[42] = 0x01; // Track # + LBAtoMSF(0, &tocbuffer[47]); + tocbuffer[47] = HEXTOBCD(tocbuffer[47]); + tocbuffer[48] = HEXTOBCD(tocbuffer[48]); + tocbuffer[49] = HEXTOBCD(tocbuffer[49]); + + // Can we get the REAL TOC? + boolresult = DeviceIoControl(devicehandle, + IOCTL_CDROM_READ_TOC, + NULL, + 0, + &cdinfo, + sizeof(CDROM_TOC), + &byteswritten, + NULL); + + if(boolresult == FALSE) { +#ifdef VERBOSE_WARNING_DEVICE + errcode = GetLastError(); + PrintLog("CDVDlinuz CD: Can't get TOC!"); + PrintError("CDVDlinuz CD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + disctype = tempdisctype; + return(disctype); + } // ENDIF- Can't read the TOC? Accept the fake TOC then. + + // Fill in the pieces of the REAL TOC. +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVDlinuz CD: TOC First Track: %u Last Track: %u", + cdinfo.FirstTrack, cdinfo.LastTrack); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); + tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); + + // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { + for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVDlinuz CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", + cdinfo.TrackData[i].TrackNumber, + cdinfo.TrackData[i].Address[1] * 1, + cdinfo.TrackData[i].Address[2] * 1, + cdinfo.TrackData[i].Address[3] * 1, + cdinfo.TrackData[i].Control * 1); +#endif /* VERBOSE_DISC_INFO */ + pos = i * 10 + 40; + tocbuffer[pos] = cdinfo.TrackData[i].Control; + tocbuffer[pos + 2] = HEXTOBCD(i + 1); + tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + } // NEXT i- Transferring Track data to the PS2 TOC + + +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVDlinuz CD: TOC Disc Size: %u:%u.%u", + cdinfo.TrackData[i].Address[1] * 1, + cdinfo.TrackData[i].Address[2] * 1, + cdinfo.TrackData[i].Address[3] * 1); +#endif /* VERBOSE_DISC_INFO */ + tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + disctype = tempdisctype; + return(disctype); +} // END CDgetDiskType() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/CD.h b/plugins/cdvd/CDVDlinuz/Src/Win32/CD.h new file mode 100644 index 0000000000..6bff6d8e82 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/CD.h @@ -0,0 +1,44 @@ +/* CD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CD_H +#define CD_H + + +#include // DWORD + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern DWORD cdblocksize; + + +extern void InitCDInfo(); +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 CDgetBufferOffset(); +extern s32 CDreadSubQ(); +extern s32 CDgetTN(cdvdTN *cdvdtn); +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 CDgetDiskType(); + + +#endif /* CD_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.c b/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.c new file mode 100644 index 0000000000..a4ebc64229 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.c @@ -0,0 +1,434 @@ +/* CDVDlinuz.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // BOOL, CALLBACK, APIENTRY +#include // NULL + +#include // time(), time_t + +#define CDVDdefs +#include "../PS2Edefs.h" + +#include "device.h" +#include "CD.h" +#include "DVD.h" +#include "../buffer.h" +#include "../convert.h" +#include "conf.h" +#include "logfile.h" +#include "../version.h" +#include "screens.h" +#include "mainbox.h" // Initialize mainboxwindow +#include "CDVDlinuz.h" + + +HINSTANCE progmodule; + + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD param, + LPVOID reserved) { + + + switch(param) { + case DLL_PROCESS_ATTACH: + progmodule = hModule; + // mainboxwindow = NULL; + return(TRUE); + break; + case DLL_PROCESS_DETACH: + // CDVDshutdown(); + return(TRUE); + break; + case DLL_THREAD_ATTACH: + return(TRUE); + break; + case DLL_THREAD_DETACH: + return(TRUE); + break; + } // ENDSWITCH param- What does the OS want with us? + + return(FALSE); // Wasn't on list? Wasn't handled. +} // END DllMain() + + +char* CALLBACK PS2EgetLibName() { + return(libname); +} // END PS2EgetLibName() + + +u32 CALLBACK PS2EgetLibType() { + return(PS2E_LT_CDVD); +} // END PS2getLibType() + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return((version << 16) | (revision << 8) | build); +} // END PS2EgetLibVersion2() + + +s32 CALLBACK CDVDinit() { + InitLog(); + if(OpenLog() != 0) return(-1); // Couldn't open Log File? Abort. + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDinit()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + InitConf(); + + DeviceInit(); + InitCDInfo(); + InitDVDInfo(); + + mainboxwindow = NULL; + + return(0); +} // END CDVDinit() + + +void CALLBACK CDVDshutdown() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDshutdown()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + DeviceClose(); + + // Close Windows as well? (Just in case) + + CloseLog(); +} // END CDVDshutdown() + + +s32 CALLBACK CDVDopen() { + int retval; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDopen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + InitBuffer(); + + LoadConf(); + + retval = DeviceOpen(); + if(retval == 0) { + DeviceTrayStatus(); + } // ENDIF- Did we open the device? Poll for media. + return(retval); +} // END CDVDopen() + + +void CALLBACK CDVDclose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDclose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + DeviceClose(); +} // END CDVDclose() + + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + char temptime[3]; + int i; + int pos; + u32 tracklsn; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDreadSubQ()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(DiscInserted() != 0) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(-1); // DVDs don't have SubQ data + } // ENDIF- Trying to get a SubQ from a DVD? + + // fake it + i = BCDTOHEX(tocbuffer[7]); + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + tracklsn = MSFtoLBA(temptime); + while((i < BCDTOHEX(tocbuffer[17])) && (tracklsn < lsn)) { + i++; + pos = i * 10; + pos += 30; + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + tracklsn = MSFtoLBA(temptime); + } // ENDIF- Loop through tracks searching for lsn track + i--; + + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = HEXTOBCD(i); + subq->trackIndex = HEXTOBCD(i); + + LBAtoMSF(lsn - tracklsn, temptime); + subq->trackM = HEXTOBCD(temptime[0]); + subq->trackS = HEXTOBCD(temptime[1]); + subq->trackF = HEXTOBCD(temptime[2]); + + subq->pad = 0; + + // lba_to_msf(lsn + (2*75), &min, &sec, &frm); + LBAtoMSF(lsn, temptime); + subq->discM = HEXTOBCD(temptime[0]); + subq->discS = HEXTOBCD(temptime[1]); + subq->discF = HEXTOBCD(temptime[2]); + return(0); +} // END CDVDreadSubQ() + + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(DiscInserted() != 0) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + Buffer->strack = 1; + Buffer->etrack = 1; + } else { + Buffer->strack = BCDTOHEX(tocbuffer[7]); + Buffer->etrack = BCDTOHEX(tocbuffer[17]); + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + return(0); +} // END CDVDgetTN() + + +s32 CALLBACK CDVDgetTD(u8 track, cdvdTD *buffer) { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + return(DeviceGetTD(track, buffer)); +} // END CDVDgetTD() + + +s32 CALLBACK CDVDgetTOC(void* toc) { + int i; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetTOC()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(DiscInserted() != 0) return(-1); + + for(i = 0; i < 2048; i++) *(((char *) toc) + i) = tocbuffer[i]; + return(0); +} // END CDVDgetTOC() + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + int retval; + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDreadTrack(%u)", lsn); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(DiscInserted() == -1) return(-1); + + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it's the right one? + } // ENDIF- Are we already pointing at the buffer? + + userbuffer = FindListBuffer(lsn); + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it was the right one? + } // ENDIF- Was a buffer found in the cache? + + replacebuffer++; + if(replacebuffer >= BUFFERMAX) replacebuffer = 0; + userbuffer = replacebuffer; + + if(bufferlist[replacebuffer].upsort != 0xffff) { + RemoveListBuffer(replacebuffer); + } // ENDIF- Reference already in place? Remove it. + + retval = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); + bufferlist[replacebuffer].lsn = lsn; + bufferlist[replacebuffer].mode = mode; + bufferlist[replacebuffer].offset = DeviceBufferOffset(); + + if(retval != 0) { + bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. + } else { + if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { + if(mode == CDVD_MODE_2352) { + CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); + } // ENDIF- Read subq as well? + } // ENDIF- Read a DVD buffer or a CD buffer? + } // ENDIF-Read ok? Fill out rest of buffer info. + AddListBuffer(replacebuffer); + return(retval); +} // END CDVDreadTrack() + + +u8* CALLBACK CDVDgetBuffer() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetBuffer()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(DiscInserted() == -1) return(NULL); + + if(userbuffer == 0xffff) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVDlinuz interface: Not pointing to a buffer!"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // No buffer reference? + } // ENDIF- user buffer not pointing at anything? Abort + + if(bufferlist[userbuffer].mode < 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVDlinuz interface: Error retrieving sector (ReadTrack call)"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // Bad Sector? + } // ENDIF- Trouble reading physical sector? Tell them. + + return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); +} // END CDVDgetBuffer() + + +s32 CALLBACK CDVDgetDiskType() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(disctype); +} // END CDVDgetDiskType() + + +s32 CALLBACK CDVDgetTrayStatus() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDgetTrayStatus()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(traystatus); +} // END CDVDgetTrayStatus() + + +s32 CALLBACK CDVDctrlTrayOpen() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDctrlTrayOpen()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + return(DeviceTrayOpen()); +} // END CDVDctrlTrayOpen() + + +s32 CALLBACK CDVDctrlTrayClose() { +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDctrlTrayClose()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + return(DeviceTrayClose()); +} // END CDVDctrlTrayClose() + + +s32 CALLBACK CDVDtest() { + int retval; + + errno = 0; + + if(devicehandle != NULL) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVDlinuz interface: Device already open"); +#endif /* VERBOSE_WARNINGS */ + return(0); + } // ENDIF- Is the CD/DVD already in use? That's fine. + +#ifdef VERBOSE_FUNCTION_INTERFACE + PrintLog("CDVDlinuz interface: CDVDtest()"); +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + retval = DeviceOpen(); + DeviceClose(); + return(retval); +} // END CDVDtest() + + +void CALLBACK CDVDconfigure() { + HWND lastwindow; + + lastwindow = GetActiveWindow(); + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0200), + lastwindow, + (DLGPROC)MainBoxCallback); + SetActiveWindow(lastwindow); + lastwindow = NULL; + return; +} // END CDVDconfigure() + + +BOOL CALLBACK AboutCallback(HWND window, UINT msg, WPARAM param, LPARAM param2) { + switch(msg) { + case WM_COMMAND: + switch(LOWORD(param)) { + case IDC_0104: // "Ok" Button + EndDialog(window, FALSE); + return(TRUE); + break; + } // ENDSWITCH param- Which Windows Message Command? + + case WM_CLOSE: + EndDialog(window, FALSE); + return(TRUE); + break; + } // ENDSWITCH msg- what message has been sent to this window? + + return(FALSE); // Not a recognisable message. Pass it back to the OS. +} // END AboutCallback() + +void CALLBACK CDVDabout() { + HWND lastwindow; + + lastwindow = GetActiveWindow(); + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0100), + lastwindow, + (DLGPROC)AboutCallback); + SetActiveWindow(lastwindow); + return; +} // END CDVDabout() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.h b/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.h new file mode 100644 index 0000000000..e93973fa68 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/CDVDlinuz.h @@ -0,0 +1,40 @@ +/* CDVDlinuz.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CDVDLINUZ_H +#define CDVDLINUZ_H + + +#include // HINSTANCE + + +// #define VERBOSE_WARNINGS +// #define VERBOSE_FUNCTION_INTERFACE +#define VERBOSE_DISC_INFO +#define VERBOSE_DISC_TYPE + +#define READ_AHEAD_BUFFERS 32 + + +extern HINSTANCE progmodule; + + +#endif /* CDVDLINUZ_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.c b/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.c new file mode 100644 index 0000000000..92854d6a5b --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.c @@ -0,0 +1,398 @@ +/* DVD.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include // IOCTL_DVD... + +#include // off64_t + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" +#include "device.h" // FinishCommand() + + +struct { + DVD_DESCRIPTOR_HEADER h; + DVD_LAYER_DESCRIPTOR d; +} layer; +// DVD_LAYER_DESCRIPTOR layer; +// DVD_COPYRIGHT_DESCRIPTOR copyright; +// DVD_DISK_KEY_DESCRIPTOR disckey; +// DVD_BCA_DESCRIPTOR bca; +// DVD_MANUFACTURER_DESCRIPTOR manufact; + + +void InitDVDInfo() { + layer.d.EndDataSector = 0; +} // END InitDVDInfo() + + +s32 DVDGetStructures() { + DVD_SESSION_ID sessionid; + DVD_READ_STRUCTURE request; + DWORD byteswritten; + BOOL boolresult; + DWORD errcode; + s32 retval; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz DVD: DVDgetStructures()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_DVD_START_SESSION, + NULL, + 0, + &sessionid, + sizeof(DVD_SESSION_ID), + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz DVD: Couldn't start session!"); + PrintError("CDVDlinuz DVD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Couldn't start a user session on the DVD drive? Fail. + + request.BlockByteOffset.QuadPart = 0; + request.Format = DvdPhysicalDescriptor; + request.SessionId = sessionid; + request.LayerNumber = 0; + retval = 0; + boolresult = DeviceIoControl(devicehandle, + IOCTL_DVD_READ_STRUCTURE, + &request, + sizeof(DVD_READ_STRUCTURE), + &layer, + sizeof(layer), + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz DVD: Couldn't get layer data!"); + PrintError("CDVDlinuz DVD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + retval = -1; + } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. + +#ifdef VERBOSE_DISC_INFO + switch(layer.d.BookType) { + case 0: + PrintLog("CDVDlinuz DVD: Book Type: DVD-ROM"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Book Type: DVD-RAM"); + break; + case 2: + PrintLog("CDVDlinuz DVD: Book Type: DVD-R"); + break; + case 3: + PrintLog("CDVDlinuz DVD: Book Type: DVD-RW"); + break; + case 9: + PrintLog("CDVDlinuz DVD: Book Type: DVD+RW"); + break; + default: + PrintLog("CDVDlinuz DVD: Book Type: Unknown (%i)", layer.d.BookType); + break; + } // ENDSWITCH- Displaying the Book Type + PrintLog("CDVDlinuz DVD: Book Version %i", layer.d.BookVersion); + switch(layer.d.MinimumRate) { + case 0: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-ROM"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RAM"); + break; + case 2: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-R"); + break; + case 3: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RW"); + break; + case 9: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD+RW"); + break; + default: + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); + break; + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + switch(layer.d.DiskSize) { + case 0: + PrintLog("CDVDlinuz DVD: Physical Disk Size: 120mm"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Physical Disk Size: 80mm"); + break; + default: + PrintLog("CDVDlinuz DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); + break; + } // ENDSWITCH- What's the Disk Size? + switch(layer.d.LayerType) { + case 1: + PrintLog("CDVDlinuz DVD: Layer Type: Read-Only"); + break; + case 2: + PrintLog("CDVDlinuz DVD: Layer Type: Recordable"); + break; + case 4: + PrintLog("CDVDlinuz DVD: Layer Type: Rewritable"); + break; + default: + PrintLog("CDVDlinuz DVD: Layer Type: Unknown (%i)", layer.d.LayerType); + break; + } // ENDSWITCH- Displaying the Layer Type + switch(layer.d.TrackPath) { + case 0: + PrintLog("CDVDlinuz DVD: Track Path: PTP"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Track Path: OTP"); + break; + default: + PrintLog("CDVDlinuz DVD: Track Path: Unknown (%i)", layer.d.TrackPath); + break; + } // ENDSWITCH- What's Track Path Layout? + PrintLog("CDVDlinuz DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); + switch(layer.d.TrackDensity) { + case 0: + PrintLog("CDVDlinuz DVD: Track Density: .74 m/track"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Track Density: .8 m/track"); + break; + case 2: + PrintLog("CDVDlinuz DVD: Track Density: .615 m/track"); + break; + default: + PrintLog("CDVDlinuz DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); + break; + } // ENDSWITCH- Displaying the Layer Type + switch(layer.d.LinearDensity) { + case 0: + PrintLog("CDVDlinuz DVD: Linear Density: .267 m/bit"); + break; + case 1: + PrintLog("CDVDlinuz DVD: Linear Density: .293 m/bit"); + break; + case 2: + PrintLog("CDVDlinuz DVD: Linear Density: .409 to .435 m/bit"); + break; + case 4: + PrintLog("CDVDlinuz DVD: Linear Density: .280 to .291 m/bit"); + break; + case 8: + PrintLog("CDVDlinuz DVD: Linear Density: .353 m/bit"); + break; + default: + PrintLog("CDVDlinuz DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); + break; + } // ENDSWITCH- Displaying the Book Type + if(layer.d.StartingDataSector == 0x30000) { + PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + layer.d.StartingDataSector); + } else if(layer.d.StartingDataSector == 0x31000) { + PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", + layer.d.StartingDataSector); + } else { + PrintLog("CDVDlinuz DVD: Starting Sector: %lu", layer.d.StartingDataSector); + } // ENDLONGIF- What does the starting sector tell us? + PrintLog("CDVDlinuz DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); + PrintLog("CDVDlinuz DVD: Ending Sector: %lu", layer.d.EndDataSector); + if(layer.d.BCAFlag != 0) PrintLog("CDVDlinuz DVD: BCA data present"); +#endif /* VERBOSE_DISC_INFO */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_DVD_END_SESSION, + &sessionid, + sizeof(DVD_SESSION_ID), + NULL, + 0, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz DVD: Couldn't end the session!"); + PrintError("CDVDlinuz DVD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + } // ENDIF- Couldn't end the user session? Report it. + + return(retval); +} // END DVDGetStructures() + + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + LARGE_INTEGER targetpos; + DWORD byteswritten; + BOOL boolresult; + DWORD errcode; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz DVD: DVDreadTrack(%lu)", lsn); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + targetpos.QuadPart = lsn * 2048; + waitevent.Offset = targetpos.LowPart; + waitevent.OffsetHigh = targetpos.HighPart; + + boolresult = ReadFile(devicehandle, + buffer, + 2048, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz DVD: Couldn't read sector!"); + PrintError("CDVDlinuz DVD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Trouble with the command? Report it. + + if(boolresult == FALSE) { + boolresult = GetOverlappedResult(devicehandle, + &waitevent, + &byteswritten, + FALSE); + } // ENDIF- Did the initial call not complete? Get byteswritten for + // the completed call. + + if(byteswritten < 2048) { +#ifdef VERBOSE_WARNING_DEVICE + errcode = GetLastError(); + PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", + byteswritten, 2048); + PrintError("CDVDlinuz CD", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Didn't get enough bytes? Report and Abort! + + return(0); +} // END DVDreadTrack() + + +s32 DVDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz DVD: DVDgetTN()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(cdvdtn != NULL) { + cdvdtn->strack = 1; + cdvdtn->etrack = 1; + } // ENDIF- Does the user really want this data? + return(0); +} // END DVDgetTN() + + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz DVD: DVDgetTD()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track + + if(cdvdtd != NULL) { + cdvdtd->type = 0; + cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; + } // ENDIF- Does the user really want this data? + return(0); +} // END DVDgetTD() + + +s32 DVDgetDiskType() { + char playstationname[] = "PLAYSTATION\0"; + int retval; + s32 tempdisctype; + char tempbuffer[2048]; + int i; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz DVD: DVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + retval = DVDGetStructures(); + if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. + if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. + + retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); + if(retval < 0) { + return(-1); + } // ENDIF- Couldn't read the ISO9660 volume track? Fail. + + tempdisctype = CDVD_TYPE_UNKNOWN; + if(layer.d.NumberOfLayers == 0) { +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVDlinuz DVD: Found Single-Sided DVD."); +#endif /* VERBOSE_DISC_INFO */ + disctype = CDVD_TYPE_DETCTDVDS; + } else { +#ifdef VERBOSE_DISC_INFO + PrintLog("CDVDlinuz DVD: Found Dual-Sided DVD."); +#endif /* VERBOSE_DISC_INFO */ + disctype = CDVD_TYPE_DETCTDVDD; + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + i = 0; + while((playstationname[i] != 0) && + (playstationname[i] == tempbuffer[8 + i])) i++; + if(playstationname[i] == 0) { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVDlinuz DVD: Found Playstation 2 DVD."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_PS2DVD; + } else { +#ifdef VERBOSE_DISC_TYPE + PrintLog("CDVDlinuz DVD: Guessing it's a Video DVD."); +#endif /* VERBOSE_DISC_TYPE */ + tempdisctype = CDVD_TYPE_DVDV; + } // ENDIF- Is this a playstation disc? + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + + if(layer.d.NumberOfLayers == 0) { + tocbuffer[0] = 0x04; + tocbuffer[4] = 0x86; + tocbuffer[5] = 0x72; + } else { + tocbuffer[0] = 0x24; + tocbuffer[4] = 0x41; + tocbuffer[5] = 0x95; + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + tocbuffer[1] = 0x02; + tocbuffer[2] = 0xF2; + tocbuffer[3] = 0x00; + + tocbuffer[16] = 0x00; + tocbuffer[17] = 0x03; + tocbuffer[18] = 0x00; + tocbuffer[19] = 0x00; + + disctype = tempdisctype; + return(disctype); +} // END DVDgetDiskType() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.h b/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.h new file mode 100644 index 0000000000..3876101750 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/DVD.h @@ -0,0 +1,37 @@ +/* DVD.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef DVD_H +#define DVD_H + + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern void InitDVDInfo(); +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DVDgetTN(cdvdTN *cdvdtn); +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); +extern s32 DVDgetDiskType(); + + +#endif /* DVD_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/Makefile.MinGW32 b/plugins/cdvd/CDVDlinuz/Src/Win32/Makefile.MinGW32 new file mode 100644 index 0000000000..f3cf50c2e4 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/Makefile.MinGW32 @@ -0,0 +1,43 @@ + +PLUGIN = CDVDlinuz.dll +PLUGINOBJS = CDVDlinuz.o mainbox.o +PLUGINHEADERS = CDVDlinuz.h mainbox.h +PLUGINFLAGS = -Wall -O2 -D_LARGEFILE64_SOURCE -I.. -I. -I.\\Win32 +PLUGINLIBS = + +# In this case, SHARED marks files that don't need Windows Display components +SHAREDOBJS = device.o CD.o DVD.o logfile.o actualfile.o conf.o \ + ..\\ini.o ..\\buffer.o ..\\version.o ..\\convert.o +SHAREDHEADERS = device.h CD.h DVD.h logfile.h actualfile.h conf.h \ + ..\\ini.h ..\\buffer.h ..\\version.h ..\\convert.h + + +CC = mingw32-gcc.exe +WINDRES = windres.exe + + +all: plugin + +release: plugin + copy $(PLUGIN) ..\\.. + +plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res + -del $(PLUGIN) + dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) + strip --strip-unneeded --strip-debug $(PLUGIN) + +$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c + $(CC) $(PLUGINFLAGS) -c $< -o $@ + +screens.res: screens.rc + $(WINDRES) -i screens.rc -J rc -o screens.res -O coff + +.PHONY : clean allclean +clean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + +allclean: + -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res + -del temp.txt err.txt ..\\temp.txt ..\\err.txt + -del ..\\..\\$(PLUGIN) + diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.c b/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.c new file mode 100644 index 0000000000..b2a5f23c2c --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.c @@ -0,0 +1,253 @@ +/* actualfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include + +#include // NULL + +#include "logfile.h" +#include "actualfile.h" + + +int IsActualFile(const char *filename) { + DWORD retval; + + if(filename == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: IsActualFile(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + retval = GetFileAttributes(filename); + if(retval == INVALID_FILE_ATTRIBUTES) return(-1); // Name doesn't exist. + if((retval & FILE_ATTRIBUTE_DIRECTORY) != 0) return(-2); + + return(0); // Yep, that's a file. +} // END IsActualFile() + + +void ActualFileDelete(const char *filename) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + DeleteFile(filename); +} // END ActualFileDelete() + + +void ActualFileRename(const char *origname, const char *newname) { +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileDelete(%s->%s)", origname, newname); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + MoveFile(origname, newname); + return; +} // END ActualFileRename() + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + HANDLE newhandle; + + if(filename == NULL) return(NULL); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + newhandle = CreateFile(filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, + NULL); + if(newhandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s", filename); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(NULL); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForRead() + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + int retval; + BY_HANDLE_FILE_INFORMATION info; + off64_t retsize; + + if(handle == NULL) return(-1); + if(handle == INVALID_HANDLE_VALUE) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSize()"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + retval = GetFileInformationByHandle(handle, &info); + if(retval == 0) return(-1); // Handle doesn't exist... + + retsize = info.nFileSizeHigh; + retsize *= 0x10000; + retsize *= 0x10000; + retsize += info.nFileSizeLow; + return(retsize); +} // END ActualFileSize() + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + // int retval; + LARGE_INTEGER realpos; + DWORD errcode; + + if(handle == NULL) return(-1); + if(handle == INVALID_HANDLE_VALUE) return(-1); + if(position < 0) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileSeek(%llu)", position); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + realpos.QuadPart = position; +////// WinXP code for seek +// retval = SetFilePointerEx(handle, +// realpos, +// NULL, +// FILE_BEGIN); +// if(retval == 0) { + +////// Win98 code for seek + realpos.LowPart = SetFilePointer(handle, + realpos.LowPart, + &realpos.HighPart, + FILE_BEGIN); + errcode = GetLastError(); + if((realpos.LowPart == 0xFFFFFFFF) && (errcode != NO_ERROR)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error on seek (%llu)", position); + PrintError("CDVDiso file", errcode); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + + return(0); +} // END ActualFileSeek() + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + DWORD bytesread; +#ifdef VERBOSE_WARNING_ACTUALFILE + DWORD errcode; +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + if(handle == NULL) return(-1); + if(handle == INVALID_HANDLE_VALUE) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + retval = ReadFile(handle, buffer, bytes, &bytesread, NULL); + if(retval == 0) { +#ifdef VERBOSE_WARNING_ACTUALFILE + errcode = GetLastError(); + PrintLog("CDVDiso file: Error reading from file"); + PrintError("CDVDiso file", errcode); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(-1); + } // ENDIF- Error? Abort + if(bytesread < bytes) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Short Block! Only read %i out of %i bytes", bytesread, bytes); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + } // ENDIF- Error? Abort + + return(bytesread); // Send back how many bytes read +} // END ActualFileRead() + + +void ActualFileClose(ACTUALHANDLE handle) { + if(handle == NULL) return; + if(handle == INVALID_HANDLE_VALUE) return; + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileClose()"); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + CloseHandle(handle); + return; +} // END ActualFileClose() + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + HANDLE newhandle; + + if(filename == NULL) return(NULL); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + newhandle = CreateFile(filename, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if(newhandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error opening file %s", filename); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + return(NULL); + } // ENDIF- Error? Abort + + return(newhandle); +} // END ActualFileOpenForWrite() + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + int retval; + DWORD byteswritten; + + if(handle == NULL) return(-1); + if(handle == INVALID_HANDLE_VALUE) return(-1); + if(bytes < 1) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + retval = WriteFile(handle, buffer, bytes, &byteswritten, NULL); + if(retval == 0) { +#ifdef VERBOSE_WARNING_ACTUALFILE + PrintLog("CDVDiso file: Error writing to file!"); +#endif /* VERBOSE_WARNING_ACTUALFILE */ + // return(-1); + } // ENDIF- Error? Abort + + return(byteswritten); // Send back how many bytes written +} // END ActualFileWrite() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.h b/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.h new file mode 100644 index 0000000000..6c215f36ed --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/actualfile.h @@ -0,0 +1,52 @@ +/* actualfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef ACTUALFILE_H +#define ACTUALFILE_H + + +#include + +#include // off64_t + + +#define ACTUALHANDLE HANDLE +#define ACTUALHANDLENULL NULL + +// #define VERBOSE_FUNCTION_ACTUALFILE +// #define VERBOSE_WARNING_ACTUALFILE + + +extern int IsActualFile(const char *filename); +extern void ActualFileDelete(const char *filename); +extern void ActualFileRename(const char *origname, const char *newname); + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); +extern off64_t ActualFileSize(ACTUALHANDLE handle); +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); +extern void ActualFileClose(ACTUALHANDLE handle); + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + +#endif /* ACTUALFILE_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/conf.c b/plugins/cdvd/CDVDlinuz/Src/Win32/conf.c new file mode 100644 index 0000000000..1fe44672a1 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/conf.c @@ -0,0 +1,175 @@ +/* conf.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // getenv() +#include // strerror() +#include // mkdir(), stat() +#include // mkdir(), stat(), fork() +#include // stat(), fork(), execlp() + +#include // CreateProcess() + +// #define CDVDdefs +// #include "../PS2Edefs.h" +#include "../PS2Etypes.h" // u8 +#include "logfile.h" +#include "../ini.h" +#include "conf.h" + + +const char *confnames[] = { "Device", NULL }; +const u8 defaultdevice[] = DEFAULT_DEVICE; +const char defaulthome[] = "inis"; +const char defaultdirectory[] = "HideMe.PS2E"; +const char defaultfile[] = "CDVDlinuz.ini"; + +char confdirname[256]; +char conffilename[256]; + +CDVDconf conf; + + +void InitConf() { + DWORD retval; + int i; + int pos; + char *envptr; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: InitConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + i = 0; + while((i < 255) && defaultdevice[i] != 0) { + conf.devicename[i] = defaultdevice[i]; + i++; + } // ENDWHILE- copying the default CD/DVD name in + conf.devicename[i] = 0; // 0-terminate the device name + + // Locating directory and file positions + pos = 0; + envptr = NULL; + // envptr = getenv("HOME"); + if(envptr == NULL) { + // = + retval = GetCurrentDirectory(253, confdirname); + if(retval > 0) { + pos = retval; + } else { + pos = 2; + confdirname[0] = '.'; + confdirname[1] = '\\'; + } // ENDIF- Did we retrieve a directory reference? + + i = 0; + while(i < pos) { + conffilename[i] = confdirname[i]; + i++; + } // ENDWHILE- Copying dir info (so far) into file info + + if(confdirname[pos-1] != '\\') { + confdirname[pos] = '\\'; + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaulthome[i] != 0)) { + confdirname[pos] = defaulthome[i]; + conffilename[pos] = defaulthome[i]; + pos++; + i++; + } // ENDWHILE- putting an offset where to store ini data + + } else { + // = / + i = 0; + while((pos < 253) && (*(envptr + i) != 0)) { + confdirname[pos] = *(envptr + i); + conffilename[pos] = *(envptr + i); + pos++; + i++; + } // ENDWHILE- copying home directory info in + + if(confdirname[pos-1] != '\\') { + confdirname[pos] = '\\'; + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultdirectory[i] != 0)) { + confdirname[pos] = defaultdirectory[i]; + conffilename[pos] = defaultdirectory[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + } // ENDIF- No Home directory? + + confdirname[pos] = 0; // Directory reference finished + + // += / + if(conffilename[pos-1] != '\\') { + conffilename[pos] = '\\'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultfile[i] != 0)) { + conffilename[pos] = defaultfile[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + conffilename[pos] = 0; // File reference finished + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: Directory: %s", confdirname); + PrintLog("CDVD config: File: %s", conffilename); +#endif /* VERBOSE_FUNCTION_CONF */ +} // END InitConf() + + +void LoadConf() { + int retval; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: LoadConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + if(retval < 0) { + sprintf(conf.devicename, "D:"); + } // ENDIF- Couldn't find keyword? Fill in a default +} // END LoadConf() + + +void SaveConf() { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: SaveConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + mkdir(confdirname); + + INISaveString(conffilename, "Settings", "Device", conf.devicename); +} // END SaveConf() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/conf.h b/plugins/cdvd/CDVDlinuz/Src/Win32/conf.h new file mode 100644 index 0000000000..406ed03512 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/conf.h @@ -0,0 +1,49 @@ +/* conf.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef CONF_H +#define CONF_H + + +#define CDVDdefs +#include "../PS2Edefs.h" + + +#define VERBOSE_FUNCTION_CONF + + +// Configuration Data + +typedef struct { + u8 devicename[256]; +} CDVDconf; +extern CDVDconf conf; + +#define DEFAULT_DEVICE "K:\\" + + +// Configuration Functions + +extern void InitConf(); +extern void LoadConf(); +extern void SaveConf(); + + +#endif /* CONF_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/device.c b/plugins/cdvd/CDVDlinuz/Src/Win32/device.c new file mode 100644 index 0000000000..527c142978 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/device.c @@ -0,0 +1,583 @@ +/* device.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include // IOCTL_CDROM..., IOCTL_STORAGE... +#include // IOCTL_DISK... +#include // sprintf() +#include // time_t + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" +#include "conf.h" +#include "CD.h" +#include "DVD.h" +#include "device.h" + + +HANDLE devicehandle; +OVERLAPPED waitevent; + +time_t lasttime; +s32 traystatus; +int traystatusmethod; +s32 disctype; +char tocbuffer[2048]; + + +void DeviceInit() { + devicehandle = NULL; + waitevent.hEvent = NULL; + waitevent.Internal = 0; + waitevent.InternalHigh = 0; + waitevent.Offset = 0; + waitevent.OffsetHigh = 0; + lasttime = 0; + + InitDisc(); +} // END DeviceInit() + + +void InitDisc() { + int i; + + InitCDInfo(); + InitDVDInfo(); + traystatus = CDVD_TRAY_OPEN; + traystatusmethod = 0; // Poll all until one works + disctype = CDVD_TYPE_NODISC; + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; +} // END InitDisc() + + +s32 DiscInserted() { + if(traystatus != CDVD_TRAY_CLOSE) return(-1); + + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + if(disctype == CDVD_TYPE_DETCT) return(-1); + if(disctype == CDVD_TYPE_NODISC) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DiscInserted()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + return(0); +} // END DiscInserted() + + +// Returns errcode (or 0 if successful) +DWORD FinishCommand(BOOL boolresult) { + DWORD errcode; + DWORD waitcode; + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: FinishCommand()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(boolresult == TRUE) { + ResetEvent(waitevent.hEvent); + return(0); + } // ENDIF- Device is ready? Say so. + + errcode = GetLastError(); + if(errcode == ERROR_IO_PENDING) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: Waiting for completion."); +#endif /* VERBOSE_FUNCTION_DEVICE */ + waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait + if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { + errcode = GetLastError(); + } else if(waitcode == WAIT_TIMEOUT) { + errcode = 21; + CancelIo(devicehandle); // Speculative Line + } else { + ResetEvent(waitevent.hEvent); + return(0); // Success! + } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) + } // ENDIF- Should we wait for the call to finish? + + ResetEvent(waitevent.hEvent); + return(errcode); +} // END DeviceCommand() + + +s32 DeviceOpen() { + char tempname[256]; + UINT drivetype; + DWORD errcode; + + if(conf.devicename[0] == 0) return(-1); + + if(devicehandle != NULL) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceOpen()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + // InitConf(); + // LoadConf(); // Should be done at least once before this call + + // Root Directory reference + if(conf.devicename[1] == 0) { + sprintf(tempname, "%s:\\", conf.devicename); + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + sprintf(tempname, "%s\\", conf.devicename); + } else { + sprintf(tempname, "%s", conf.devicename); + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + drivetype = GetDriveType(tempname); + if(drivetype != DRIVE_CDROM) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Not a CD-ROM!"); + PrintLog("CDVDlinuz device: (Came back: %u)", drivetype); + errcode = GetLastError(); + if(errcode > 0) PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Not a CD-ROM? Say so! + // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? + + // Device Reference + if(conf.devicename[1] == 0) { + sprintf(tempname, "\\\\.\\%s:", conf.devicename); + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + sprintf(tempname, "\\\\.\\%s", conf.devicename); + } else { + sprintf(tempname, "%s", conf.devicename); + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + devicehandle = CreateFile(tempname, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if(devicehandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Couldn't open device read-only! Read-Write perhaps?"); + errcode = GetLastError(); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + devicehandle = CreateFile(tempname, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) + + if(devicehandle == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Couldn't open device!"); + errcode = GetLastError(); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + devicehandle = NULL; + return(-1); + } // ENDIF- Couldn't open that way either? Abort. + + waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(waitevent.hEvent == INVALID_HANDLE_VALUE) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Couldn't open event handler!"); + errcode = GetLastError(); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + waitevent.hEvent = NULL; + CloseHandle(devicehandle); + devicehandle = NULL; + } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. + + // More here... DeviceIoControl? for Drive Capabilities + // DEVICE_CAPABILITIES? + + ////// Should be done just after the first DeviceOpen(); + // InitDisc(); // ? + // DeviceTrayStatus(); + + return(0); +} // END DeviceOpen() + + +void DeviceClose() { + if(devicehandle == NULL) return; + + if(devicehandle == INVALID_HANDLE_VALUE) { + devicehandle = NULL; + return; + } // ENDIF- Bad value? Just clear the value. + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceClose()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + if(waitevent.hEvent != NULL) { + if(waitevent.hEvent != INVALID_HANDLE_VALUE) { + CancelIo(devicehandle); + CloseHandle(waitevent.hEvent); + } // ENDIF- Is this handle actually open? + waitevent.hEvent = NULL; + waitevent.Offset = 0; + waitevent.OffsetHigh = 0; + } // ENDIF- Reset the event handle? + + CloseHandle(devicehandle); + devicehandle = NULL; + return; +} // END DeviceClose() + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDreadTrack(lsn, mode, buffer)); + } else { + return(CDreadTrack(lsn, mode, buffer)); + } // ENDIF- Is this a DVD? +} // END DeviceReadTrack() + + +s32 DeviceBufferOffset() { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(0); + } else { + return(CDgetBufferOffset()); + } // ENDIF- Is this a DVD? + + return(-1); +} // END DeviceBufferOffset() + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(track, cdvdtd)); + } else { + return(CDgetTD(track, cdvdtd)); + } // ENDIF- Is this a DVD? + + return(-1); +} // END DeviceGetTD() + + +s32 DeviceGetDiskType() { + s32 s32result; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_OPEN) return(disctype); + + if(disctype != CDVD_TYPE_NODISC) return(disctype); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceGetDiskType()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + disctype = CDVD_TYPE_DETCT; + + s32result = DVDgetDiskType(); + if(s32result != -1) return(disctype); + + s32result = CDgetDiskType(); + if(s32result != -1) return(disctype); + + disctype = CDVD_TYPE_UNKNOWN; + return(disctype); +} // END DeviceGetDiskType() + + +BOOL DeviceTrayStatusStorage() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = FinishCommand(boolresult); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Trouble detecting drive status (STORAGE)!"); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusStorage() + + +BOOL DeviceTrayStatusCDRom() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + boolresult = DeviceIoControl(devicehandle, + IOCTL_CDROM_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = FinishCommand(boolresult); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Trouble detecting drive status (CDROM)!"); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusCDRom() + + +BOOL DeviceTrayStatusDisk() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + boolresult = DeviceIoControl(devicehandle, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = FinishCommand(boolresult); + + if(errcode == 0) return(TRUE); + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Trouble detecting drive status (DISK)!"); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + return(FALSE); +} // END DeviceTrayStatusDisk() + + +s32 DeviceTrayStatus() { + BOOL boolresult; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceTrayStatus()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + switch(traystatusmethod) { + case 1: + boolresult = DeviceTrayStatusStorage(); + break; + case 2: + boolresult = DeviceTrayStatusCDRom(); + break; + case 3: + boolresult = DeviceTrayStatusDisk(); + break; + default: + boolresult = FALSE; + break; + } // ENDSWITCH traystatusmethod- One method already working? Try it again. + + if(boolresult == FALSE) { + traystatusmethod = 0; + boolresult = DeviceTrayStatusStorage(); + if(boolresult == TRUE) { + traystatusmethod = 1; + } else { + boolresult = DeviceTrayStatusCDRom(); + if(boolresult == TRUE) { + traystatusmethod = 2; + } else { + boolresult = DeviceTrayStatusDisk(); + if(boolresult == TRUE) traystatusmethod = 3; + } // ENDIF- Did we succeed with CDRom? + } // ENDIF- Did we succeed with Storage? + } // Single call to already working test just failed? Test them all. + + if(boolresult == FALSE) { + if(traystatus == CDVD_TRAY_CLOSE) { +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: Tray just opened!"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + traystatus = CDVD_TRAY_OPEN; + DeviceClose(); + DeviceOpen(); + InitDisc(); + } // ENDIF- Just opened? clear disc info + return(traystatus); + } // ENDIF- Still failed? Assume no disc in drive then. + + if(traystatus == CDVD_TRAY_OPEN) { + traystatus = CDVD_TRAY_CLOSE; +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: Tray just closed!"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + DeviceGetDiskType(); + return(traystatus); + } // ENDIF- Just closed? Get disc information + + return(traystatus); +} // END DeviceTrayStatus() + + +s32 DeviceTrayOpen() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_OPEN) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceOpenTray()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_EJECT_MEDIA, + NULL, + 0, + NULL, + 0, + &byteswritten, + &waitevent); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Couldn't signal media to eject! (STORAGE)"); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_DISK_EJECT_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- Storage Call failed? Try Disk call. + +// if(boolresult == FALSE) { +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDlinuz device: Couldn't signal media to eject! (DISK)"); +// PrintError("CDVDlinuz device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Disk Call failed as well? Give it up. + + return(0); +} // END DeviceTrayOpen() + + +s32 DeviceTrayClose() { + BOOL boolresult; + DWORD byteswritten; + DWORD errcode; + + if(devicehandle == NULL) return(-1); + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + if(traystatus == CDVD_TRAY_CLOSE) return(0); + +#ifdef VERBOSE_FUNCTION_DEVICE + PrintLog("CDVDlinuz device: DeviceCloseTray()"); +#endif /* VERBOSE_FUNCTION_DEVICE */ + + boolresult = DeviceIoControl(devicehandle, + IOCTL_STORAGE_LOAD_MEDIA, + NULL, + 0, + NULL, + 0, + &byteswritten, + NULL); + errcode = FinishCommand(boolresult); + + if(errcode != 0) { +#ifdef VERBOSE_WARNING_DEVICE + PrintLog("CDVDlinuz device: Couldn't signal media to load! (STORAGE)"); + PrintError("CDVDlinuz device", errcode); +#endif /* VERBOSE_WARNING_DEVICE */ +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_CDROM_LOAD_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- Storage call failed. CDRom call? + +// if(boolresult == FALSE) { +// errcode = GetLastError(); +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDlinuz device: Couldn't signal media to load! (CDROM)"); +// PrintError("CDVDlinuz device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ +// boolresult = DeviceIoControl(devicehandle, +// IOCTL_DISK_LOAD_MEDIA, +// NULL, +// 0, +// NULL, +// 0, +// &byteswritten, +// NULL); +// } // ENDIF- CDRom call failed. Disk call? + +// if(boolresult == FALSE) { +// #ifdef VERBOSE_WARNING_DEVICE +// PrintLog("CDVDlinuz device: Couldn't signal media to load! (DISK)"); +// PrintError("CDVDlinuz device", errcode); +// #endif /* VERBOSE_WARNING_DEVICE */ + return(-1); + } // ENDIF- Media not available? + + return(0); +} // END DeviceTrayClose() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/device.h b/plugins/cdvd/CDVDlinuz/Src/Win32/device.h new file mode 100644 index 0000000000..608f13dd86 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/device.h @@ -0,0 +1,64 @@ +/* device.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + + +#include // BOOL, DWORD + +#include // time_t + +#define CDVDdefs +#include "../PS2Edefs.h" + + +// #define VERBOSE_FUNCTION_DEVICE +// #define VERBOSE_WARNING_DEVICE +#define VERBOSE_DISC_TYPE +#define VERBOSE_DISC_INFO + + +extern HANDLE devicehandle; +extern OVERLAPPED waitevent; + +extern time_t lasttime; +extern s32 traystatus; +extern s32 disctype; +extern char tocbuffer[]; + + +extern void DeviceInit(); +extern void InitDisc(); +extern s32 DiscInserted(); +extern DWORD FinishCommand(BOOL boolresult); + +extern s32 DeviceOpen(); +extern void DeviceClose(); +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); +extern s32 DeviceBufferOffset(); +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); +extern s32 DeviceGetDiskType(); +extern s32 DeviceTrayStatus(); +extern s32 DeviceTrayOpen(); +extern s32 DeviceTrayClose(); + + +#endif /* __DEVICE_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.c b/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.c new file mode 100644 index 0000000000..28f82eb088 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.c @@ -0,0 +1,119 @@ +/* logfile.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include + +// #include // open() +// #include // mkdir() +#include // NULL +#include // vsprintf() +#include // va_start(), va_end(), vsprintf() +// #include // open() +// #include // open() + +#include "logfile.h" + + +HANDLE logfile; +char logfiletemp[2048]; + + +void InitLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + CreateDirectory("logs", NULL); + + DeleteFile("logs\\CDVDlog.txt"); + logfile = NULL; +#endif /* VERBOSE LOGFILE */ +} // END InitLog(); + + +int OpenLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + logfile = CreateFile("logs\\CDVDlog.txt", + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if(logfile == INVALID_HANDLE_VALUE) { + logfile = NULL; + return(-1); + } // ENDIF- Failed to open? Say so. +#endif /* VERBOSE LOGFILE */ + + return(0); +} // END OpenLog(); + + +void CloseLog() { + // Token comment line +#ifdef VERBOSE_LOGFILE + if(logfile != NULL) { + CloseHandle(logfile); + logfile = NULL; + } // ENDIF- Is the log file actually open? Close it. +#endif /* VERBOSE LOGFILE */ +} // END CloseLog() + + +void PrintLog(const char *fmt, ...) { + DWORD byteswritten; + + // Token comment line +#ifdef VERBOSE_LOGFILE + va_list list; + int len; + + if(logfile == NULL) return; // Log file not open... yet. + + va_start(list, fmt); + vsprintf(logfiletemp, fmt, list); + va_end(list); + + len = 0; + while((len < 2048) && (logfiletemp[len] != 0)) len++; + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); + WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); +#endif /* VERBOSE LOGFILE */ +} // END PrintLog() + +void PrintError(const char *header, DWORD errcode) { +#ifdef VERBOSE_LOGFILE + TCHAR errmsg[256]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, + NULL, + errcode, + 0, + errmsg, + 256, + NULL); + PrintLog("%s: (%u) %s", header, errcode, errmsg); +#endif /* VERBOSE_WARNING_DEVICE */ +} // END PrintError() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.h b/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.h new file mode 100644 index 0000000000..ff6e3b0c1c --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/logfile.h @@ -0,0 +1,39 @@ +/* logfile.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef LOGFILE_H +#define LOGFILE_H + + +#include // Just for DWORD + + +#define VERBOSE_LOGFILE + + +extern void InitLog(); +extern int OpenLog(); +extern void CloseLog(); +extern void PrintLog(const char *format, ...); +extern void PrintError(const char *header, DWORD errcode); + + +#endif /* LOGFILE_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.c b/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.c new file mode 100644 index 0000000000..0c7c9f8794 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.c @@ -0,0 +1,173 @@ +/* mainbox.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +// #include // Button_ +#include // NULL + +#include // sprintf() +#include // strcpy() +#include // stat() +#include // stat() +#include // stat() + +#include "conf.h" +#include "device.h" +// #include "imagetype.h" // imagedata[].name +#include "screens.h" // DLG_, IDC_ +#include "CDVDlinuz.h" // progmodule +#include "mainbox.h" + + +HWND mainboxwindow; + + +void MainBoxDestroy() { + if(mainboxwindow != NULL) { + EndDialog(mainboxwindow, FALSE); + mainboxwindow = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + // EnableWindow(?) + // gtk_widget_set_sensitive(mainbox.device, FALSE); + ShowWindow(mainboxwindow, SW_HIDE); +} // END MainBoxUnfocus() + + +void MainBoxDeviceEvent() { + char tempdevice[256]; + struct stat filestat; + int returnval; + + GetDlgItemText(mainboxwindow, IDC_0202, tempdevice, 256); + returnval = stat(tempdevice, &filestat); + if(returnval == -1) { + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: ---"); + return; + } // ENDIF- Not a name of any sort? + + if(S_ISDIR(filestat.st_mode) != 0) { + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Not a device"); + return; + } // ENDIF- Not a regular file? + + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Device Likely"); + return; +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + MainBoxDeviceEvent(); + + // gtk_widget_set_sensitive(mainbox.device, TRUE); + // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); + // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? + ShowWindow(mainboxwindow, SW_SHOW); + SetActiveWindow(mainboxwindow); +} // END MainBoxRefocus() + + +void MainBoxCancelEvent() { + MainBoxDestroy(); + return; +} // END MainBoxCancelEvent() + + +void MainBoxOKEvent() { + int retval; + + MainBoxUnfocus(); + + GetDlgItemText(mainboxwindow, IDC_0202, conf.devicename, 256); + retval = DeviceOpen(); + DeviceClose(); + if(retval != 0) { + MainBoxRefocus(); + MessageBox(mainboxwindow, + "Could not open the device", + "CDVDlinuz Message", + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + return; + } // ENDIF- Trouble opening device? Abort here. + + SaveConf(); + + MainBoxCancelEvent(); + return; +} // END MainBoxOKEvent() + + +void MainBoxDisplay() { + InitConf(); // Man, am I boiling mad! CDVDinit() should have been called first! + LoadConf(); + + // Adjust window position? + + // We held off setting the name until now... so description would show. + SetDlgItemText(mainboxwindow, IDC_0202, conf.devicename); + + // First Time - Show the window + ShowWindow(mainboxwindow, SW_SHOWNORMAL); +} // END MainBoxDisplay() + + +BOOL CALLBACK MainBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2) { + switch(msg) { + case WM_INITDIALOG: + mainboxwindow = window; + MainBoxDisplay(); // In this case, final touches to this window. + return(FALSE); // And let Windows display this window. + break; + + case WM_CLOSE: // The "X" in the upper right corner was hit. + MainBoxCancelEvent(); + return(TRUE); + break; + + case WM_COMMAND: + // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? + + switch(LOWORD(param)) { + case IDC_0202: // Devicename Edit Box + MainBoxDeviceEvent(); // Describe the File's type... + return(FALSE); // Let Windows handle the actual 'edit' processing... + break; + + case IDC_0204: // "Ok" Button + MainBoxOKEvent(); + return(TRUE); + break; + + case IDC_0205: // "Cancel" Button + MainBoxCancelEvent(); + return(TRUE); + break; + } // ENDSWITCH param- Which object got the message? + } // ENDSWITCH msg- what message has been sent to this window? + + return(FALSE); // Not a recognized message? Tell Windows to handle it. +} // END MainBoxEventLoop() diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.h b/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.h new file mode 100644 index 0000000000..850ab6cdcb --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/mainbox.h @@ -0,0 +1,42 @@ +/* mainbox.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef MAINBOX_H +#define MAINBOX_H + + +#include // HWND + + +extern const char fileselection[]; + +extern HWND mainboxwindow; + + +extern void MainBoxRefocus(); +extern void MainBoxDisplay(); +extern BOOL CALLBACK MainBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2); + + +#endif /* MAINBOX_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/make.bat b/plugins/cdvd/CDVDlinuz/Src/Win32/make.bat new file mode 100644 index 0000000000..fc4b70f966 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/make.bat @@ -0,0 +1 @@ +mingw32-make -f Makefile.MinGW32 %1 diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/plugin.def b/plugins/cdvd/CDVDlinuz/Src/Win32/plugin.def new file mode 100644 index 0000000000..ecd0afb546 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/plugin.def @@ -0,0 +1,21 @@ +EXPORTS + PS2EgetLibType = PS2EgetLibType@0 @2 + PS2EgetLibName = PS2EgetLibName@0 @3 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @4 + CDVDinit = CDVDinit@0 @5 + CDVDshutdown = CDVDshutdown@0 @6 + CDVDopen = CDVDopen@0 @7 + CDVDclose = CDVDclose@0 @8 + CDVDreadTrack = CDVDreadTrack@8 @9 + CDVDgetBuffer = CDVDgetBuffer@0 @10 + CDVDreadSubQ = CDVDreadSubQ@8 @11 + CDVDgetTN = CDVDgetTN@4 @12 + CDVDgetTD = CDVDgetTD@8 @13 + CDVDgetTOC = CDVDgetTOC@4 @14 + CDVDgetDiskType = CDVDgetDiskType@0 @15 + CDVDgetTrayStatus = CDVDgetTrayStatus@0 @16 + CDVDctrlTrayOpen = CDVDctrlTrayOpen@0 @17 + CDVDctrlTrayClose = CDVDctrlTrayClose@0 @18 + CDVDconfigure = CDVDconfigure@0 @19 + CDVDtest = CDVDtest@0 @20 + CDVDabout = CDVDabout@0 @21 diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/screens.h b/plugins/cdvd/CDVDlinuz/Src/Win32/screens.h new file mode 100644 index 0000000000..7f147436ab --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/screens.h @@ -0,0 +1,9 @@ +/* Weditres generated include file. Do NOT edit */ +#include +#define DLG_0100 100 +#define IDC_0104 104 +#define DLG_0200 200 +#define IDC_0202 202 +#define IDC_0203 203 +#define IDC_0204 204 +#define IDC_0205 205 diff --git a/plugins/cdvd/CDVDlinuz/Src/Win32/screens.rc b/plugins/cdvd/CDVDlinuz/Src/Win32/screens.rc new file mode 100644 index 0000000000..897844757a --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/Win32/screens.rc @@ -0,0 +1,29 @@ +/* Wedit generated resource file */ +#ifdef __LCC__ +#include +#endif +#include "screens.h" + + +DLG_0100 DIALOG 2, 2, 140, 59 +STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "About CDVDlinuz" +FONT 8, "MS Sans Serif" +BEGIN + CTEXT "EFP polling CDVD Driver v0.4", 101, 11, 6, 118, 12 + CTEXT "Current Author: efp", 102, 12, 16, 118, 12 + CTEXT "Original code by: linuzappz && shadow", 103, 12, 26, 118, 12 + PUSHBUTTON "Ok", IDC_0104, 50, 37, 40, 14 +END + +DLG_0200 DIALOG 4, 2, 241, 50 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDlinuz Configuration" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "CD/DVD device:", 201, 14, 8, 59, 12 + EDITTEXT IDC_0202, 71, 7, 164, 12, ES_AUTOHSCROLL + CTEXT "Device Type: ---", IDC_0203, 10, 21, 220, 12 + PUSHBUTTON "Ok", IDC_0204, 15, 31, 48, 14 + PUSHBUTTON "Cancel", IDC_0205, 177, 31, 48, 14 +END diff --git a/plugins/cdvd/CDVDlinuz/Src/buffer.c b/plugins/cdvd/CDVDlinuz/Src/buffer.c new file mode 100644 index 0000000000..60e63e4023 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/buffer.c @@ -0,0 +1,525 @@ +/* buffer.c + * Copyright (C) 2002-2005 CDVDlinuz 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 // errno +#include // NULL +#include // printf() +#include // strerror() + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + +#include "logfile.h" + +#include "buffer.h" + + +// Globals + +struct BufferSortEmpty { + u16 sortptr; +}; + +struct BufferSort { + u16 upptr; + u16 uppos; + + u32 mask; + u32 divisor; + + struct { + u8 isdata; + u16 ptr; + } lower[256]; + u16 ptrcount; + u16 firstptr; +}; + +struct BufferSortEmpty buffersortempty[BUFFERMAX]; +u16 buffersortemptystart; +u16 buffersortemptyend; + +struct BufferSort buffersort[BUFFERMAX]; +u8 buffersortstartisdata; +u16 buffersortstart; + +struct BufferList bufferlist[BUFFERMAX]; +u16 userbuffer; +u16 replacebuffer; + + +void InitBuffer() { + u16 i; + u16 j; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: InitBuffer()"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + buffersortemptystart = 0; + buffersortemptyend = 0; + for(i = 0; i < BUFFERMAX; i++) { + buffersortempty[i].sortptr = i; + } // NEXT i- Saying all buffersort[] entries are open. + + buffersortstart = 0xffff; + buffersortstartisdata = 2; + for(i = 0; i < BUFFERMAX; i++) { + for(j = 0; j < 256; j++) buffersort[i].lower[j].isdata = 2; + // buffersort[i].ptrcount = 0; + } // NEXT i- Saying all buffersort[] entries are open. + + for(i = 0; i < BUFFERMAX; i++) { + bufferlist[i].upsort = 0xffff; + } // NEXT i- Clearing out the buffer pointers + userbuffer = 0xffff; + replacebuffer = BUFFERMAX - 1; +} // END InitBuffer(); + + +u16 AllocSortBuffer() { + u16 newbuffer; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: AllocSortBuffer()"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + newbuffer = buffersortempty[buffersortemptyend].sortptr; + buffersortempty[buffersortemptyend].sortptr = BUFFERMAX; + buffersortemptyend++; + if(buffersortemptyend > BUFFERMAX - 1) buffersortemptyend = 0; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Sort Buffer %u", newbuffer); +#endif /* VERBOSE_FUNCTION_BUFFER */ + +#ifdef VERBOSE_WARNINGS_BUFFER + if(buffersortemptyend == buffersortemptystart) { + PrintLog("Completely out of Sort Buffers to allocate now!"); + } // ENDIF- Out of Sort Buffers? Say so! +#endif /* VERBOSE_WARNINGS_BUFFER */ + + return(newbuffer); +} // END AllocSortBuffer() + + +void ReleaseSortBuffer(u16 oldbuffer) { +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: ReleaseSortBuffer(%u)", oldbuffer); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + buffersortempty[buffersortemptystart].sortptr = oldbuffer; + buffersortemptystart++; + if(buffersortemptystart > BUFFERMAX - 1) buffersortemptystart = 0; +} // END ReleaseSortBuffer() + + +// Returns either index in buffersort... or closest insertion point. +// Make lsn == buffersort[int].lsn test for exact match +u16 FindListBuffer(u32 lsn) { + u16 current; + u8 isdata; + u32 index; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: FindListBuffer(%u)", lsn); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + if(buffersortstart == 0xffff) return(0xffff); // Buffer empty? Exit + + if(buffersortstartisdata == 1) { + if(bufferlist[buffersortstart].lsn != lsn) return(0xffff); + return(buffersortstart); + } // ENDIF- Only one Record in Buffer? + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Searching..."); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + current = buffersortstart; + isdata = 0; + while(isdata == 0) { + index = lsn; + index &= buffersort[current].mask; + index /= buffersort[current].divisor; + isdata = buffersort[current].lower[index].isdata; + current = buffersort[current].lower[index].ptr; + } // ENDWHILE- still haven't found data + + if(isdata == 2) return(0xffff); // Pointing at empty entry? + if(bufferlist[current].lsn != lsn) return(0xffff); // LSNs don't match? + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Found."); +#endif /* VERBOSE_FUNCTION_BUFFER */ + return(current); +} // END FindListBuffer() + + +// Removes buffer from the buffersort list +// bufnum = The bufferlist pointer +void RemoveListBuffer(u16 bufnum) { + u16 current; + u16 currentpos; + + u16 upperlink; + u16 upperindex; + + u16 lowerlink; + u8 lowerisdata; + + u32 index; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: RemoveListBuffer(%u)", bufnum); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + if(bufferlist[bufnum].upsort == 0xffff) return; // No link to break. + + current = bufferlist[bufnum].upsort; + currentpos = bufferlist[bufnum].uppos; + bufferlist[bufnum].upsort = 0xffff; + + if(current == 0xfffe) { + buffersortstart = 0xffff; + buffersortstartisdata = 2; +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Buffer emptied"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + return; + } // ENDIF- Last link broken... empty buffer now. + + lowerlink = 0xffff; + lowerisdata = 2; + + // Remove Lower Pointer + buffersort[current].lower[currentpos].isdata = 2; + if(currentpos == buffersort[current].firstptr) { + index = currentpos + 1; + while((index < 256) && (buffersort[current].lower[index].isdata == 2)) index++; + buffersort[current].firstptr = index; + } // ENDIF- Do we need to move firstptr to an active entry? + buffersort[current].ptrcount--; +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Pointer count for sort buffer %u: %u", + current, buffersort[current].ptrcount); +#endif /* VERBOSE_FUNCTION_BUFFER */ + if(buffersort[current].ptrcount > 1) return; // Still 2+ branches left + + // Find Lower Link + index = buffersort[current].firstptr; + lowerlink = buffersort[current].lower[index].ptr; + lowerisdata = buffersort[current].lower[index].isdata; + buffersort[current].lower[index].isdata = 2; + + // Find and Break Upper Link + upperlink = buffersort[current].upptr; + upperindex = buffersort[current].uppos; + + if(upperlink == 0xffff) { + buffersortstart = lowerlink; + buffersortstartisdata = lowerisdata; + } else { + buffersort[upperlink].lower[upperindex].ptr = lowerlink; + buffersort[upperlink].lower[upperindex].isdata = lowerisdata; + } // ENDIF- Did we hit the top of the web? + + // Break Lower Link + if(lowerisdata == 1) { + if(upperlink == 0xffff) { + bufferlist[lowerlink].upsort = 0xfffe; +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Buffer down to 1 record now"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + } else { + bufferlist[lowerlink].upsort = upperlink; + bufferlist[lowerlink].uppos = upperindex; + } // ENDIF- Is this the last active buffersort? + } else { + buffersort[lowerlink].upptr = upperlink; + buffersort[lowerlink].uppos = upperindex; + } // ENDIF- Was this a BufferList link? + + // Cleanup in aisle 5.... + ReleaseSortBuffer(current); + return; +} // END RemoveListBuffer() + + +// Adds buffer to the buffersort list +// bufnum = The bufferlist pointer +void AddListBuffer(u16 bufnum) { + u32 newmask; + u32 newdivisor; + + u16 newbuffer; + u32 newvalue; + + u16 current; + u32 currentvalue; + u8 currentisdata; + + u16 prevbuffer; + u32 prevvalue; + + u16 comparebuffer; + u8 compareisdata; + u32 comparevalue; + +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: AddListBuffer(%u)", bufnum); +#endif /* VERBOSE_FUNCTION_BUFFER */ + + // Already in list? Oh, re-sorting? Got it covered. + if(bufferlist[bufnum].upsort != 0xffff) RemoveListBuffer(bufnum); + + if(buffersortstartisdata == 2) { + buffersortstart = bufnum; + buffersortstartisdata = 1; + bufferlist[bufnum].upsort = 0xfffe; +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Buffer up to 1 record now"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + return; + } // ENDIF- Empty list? Set for just 1 entry. + + if(buffersortstartisdata == 1) { + newmask = 0xff000000; + newdivisor = 0x01000000; + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; + while((newdivisor != 0x00000001) && (newvalue == currentvalue)) { + newmask /= 0x0100; + newdivisor /= 0x0100; + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; + } // ENDWHILE- trying to find a difference between the LSNs + + if(newvalue == currentvalue) { + bufferlist[buffersortstart].upsort = 0xffff; + bufferlist[bufnum].upsort = 0xfffe; + buffersortstart = bufnum; + return; + + } else { + newbuffer = AllocSortBuffer(); + buffersort[newbuffer].upptr = 0xffff; + buffersort[newbuffer].mask = newmask; + buffersort[newbuffer].divisor = newdivisor; + buffersort[newbuffer].lower[currentvalue].isdata = 1; + buffersort[newbuffer].lower[currentvalue].ptr = buffersortstart; + buffersort[newbuffer].lower[newvalue].isdata = 1; + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + buffersort[newbuffer].ptrcount = 2; + buffersort[newbuffer].firstptr = currentvalue; + if(newvalue < buffersort[newbuffer].firstptr) + buffersort[newbuffer].firstptr = newvalue; + + bufferlist[buffersortstart].upsort = newbuffer; + bufferlist[buffersortstart].uppos = currentvalue; + buffersortstart = newbuffer; + buffersortstartisdata = 0; + + bufferlist[bufnum].upsort = newbuffer; + bufferlist[bufnum].uppos = newvalue; +#ifdef VERBOSE_FUNCTION_BUFFER + PrintLog("CDVD buffer: Buffer up to 2 records now"); +#endif /* VERBOSE_FUNCTION_BUFFER */ + return; + } // ENDIF- Same LSN? Shift pointer in response. Else, add a Sort Record. + } // ENDIF- Only 1 record? Check if we need a Sort Record. + + newmask = 0xff000000; + newdivisor = 0x01000000; + prevbuffer = 0xffff; + prevvalue = 0; + current = buffersortstart; + currentisdata = 0; + while(currentisdata == 0) { + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + if(buffersort[current].mask != newmask) { + comparebuffer = current; + compareisdata = 0; + while(compareisdata == 0) { + comparevalue = buffersort[comparebuffer].firstptr; + compareisdata = buffersort[comparebuffer].lower[comparevalue].isdata; + comparebuffer = buffersort[comparebuffer].lower[comparevalue].ptr; + } // ENDWHILE- looking for an another buffer to compare to... + + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + if(newvalue != comparevalue) { + // Add buffersort here (comparevalue/newvalue) + newbuffer = AllocSortBuffer(); + buffersort[newbuffer].upptr = buffersort[current].upptr; + buffersort[newbuffer].uppos = buffersort[current].uppos; + buffersort[newbuffer].mask = newmask; + buffersort[newbuffer].divisor = newdivisor; + buffersort[newbuffer].lower[comparevalue].isdata = 0; + buffersort[newbuffer].lower[comparevalue].ptr = current; + buffersort[newbuffer].lower[newvalue].isdata = 1; + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + buffersort[newbuffer].ptrcount = 2; + buffersort[newbuffer].firstptr = comparevalue; + if(newvalue < buffersort[newbuffer].firstptr) + buffersort[newbuffer].firstptr = newvalue; + + if(buffersort[newbuffer].upptr == 0xffff) { + buffersortstart = newbuffer; + } else { + buffersort[prevbuffer].lower[prevvalue].isdata = 0; + buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; + if(prevvalue < buffersort[prevbuffer].firstptr) + buffersort[prevbuffer].firstptr = prevvalue; + } // ENDIF- Do we need to adjust to buffersortstart connection? + buffersort[current].upptr = newbuffer; + buffersort[current].uppos = comparevalue; + bufferlist[bufnum].upsort = newbuffer; + bufferlist[bufnum].uppos = newvalue; + return; + } // ENDIF- Don't match? Add a buffersort here to say that! + + compareisdata = 0; + newmask /= 0x0100; + newdivisor /= 0x0100; + + } else { + currentisdata = buffersort[current].lower[newvalue].isdata; + prevbuffer = current; + prevvalue = newvalue; + if(currentisdata == 0) { + current = buffersort[current].lower[newvalue].ptr; + newmask /= 0x0100; + newdivisor /= 0x0100; + if(newdivisor == 0) { +#ifdef VERBOSE_WARNINGS_BUFFER + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (detected in search)"); +#endif /* VERBOSE_WARNINGS_BUFFER */ + return; + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + } // ENDIF- Do we have to go through another level of sort data? + } // ENDIF- We don't have a comparison on this byte? + } // ENDWHILE- looking for his level... + + if(buffersort[current].lower[newvalue].isdata == 2) { + buffersort[current].lower[newvalue].isdata = 1; + buffersort[current].lower[newvalue].ptr = bufnum; + buffersort[current].ptrcount++; + if(newvalue < buffersort[current].firstptr) + buffersort[current].firstptr = newvalue; + bufferlist[bufnum].upsort = current; + bufferlist[bufnum].uppos = newvalue; + return; + } // ENDIF- an empty slot? Fill it in. + + comparebuffer = buffersort[current].lower[newvalue].ptr; + if(bufferlist[bufnum].lsn == bufferlist[comparebuffer].lsn) { + buffersort[current].lower[newvalue].ptr = bufnum; + bufferlist[bufnum].upsort = current; + bufferlist[bufnum].uppos = newvalue; + bufferlist[comparebuffer].upsort = 0xffff; + return; + } // ENDIF- Same LSN? Replace! + + // Calc new position based on new separation markers... + newmask /= 0x0100; + newdivisor /= 0x0100; + if(newdivisor == 0) { +#ifdef VERBOSE_WARNINGS_BUFFER + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add initial)"); +#endif /* VERBOSE_WARNINGS_BUFFER */ + return; + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + while((newmask != 0x000000ff) && (comparevalue == newvalue)) { + newmask /= 0x0100; + newdivisor /= 0x0100; + if(newdivisor == 0) { +#ifdef VERBOSE_WARNINGS_BUFFER + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add loop)"); +#endif /* VERBOSE_WARNINGS_BUFFER */ + return; + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + } // ENDWHILE- continuing to scan for difference between the two numbers + + newbuffer = AllocSortBuffer(); + buffersort[newbuffer].upptr = prevbuffer; + buffersort[newbuffer].uppos = prevvalue; + buffersort[newbuffer].mask = newmask; + buffersort[newbuffer].divisor = newdivisor; + buffersort[newbuffer].lower[comparevalue].isdata = 1; + buffersort[newbuffer].lower[comparevalue].ptr = comparebuffer; + buffersort[newbuffer].lower[newvalue].isdata = 1; + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + buffersort[newbuffer].ptrcount = 2; + buffersort[newbuffer].firstptr = comparevalue; + if(newvalue < buffersort[newbuffer].firstptr) + buffersort[newbuffer].firstptr = newvalue; + + buffersort[prevbuffer].lower[prevvalue].isdata = 0; + buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; + bufferlist[comparebuffer].upsort = newbuffer; + bufferlist[comparebuffer].uppos = comparevalue; + bufferlist[bufnum].upsort = newbuffer; + bufferlist[bufnum].uppos = newvalue; +} // END AddListBuffer() + +#ifdef VERBOSE_WARNINGS_BUFFER +void PrintSortBuffers() { + u16 h; + u16 i; + u16 j; + + printf("CDVD buffer: Sort Buffer Dump\n"); + printf("CDVD buffer: Top Pointer: isdata %u ptr %u\n", + buffersortstartisdata, buffersortstart); + for(i = 0; i < BUFFERMAX; i++) { + + h = 0; + while((h < BUFFERMAX) && (buffersortempty[h].sortptr != i)) h++; + + if(h == BUFFERMAX) { + printf("CDVD buffer: Sort Buffer:%u Mask:%x Divisor:%x\n", + i, buffersort[i].mask, buffersort[i].divisor); + printf("CDVD buffer: Up Ptr:%u Up Pos:%u First Down Ptr:%u Ptr Count: %u\n", + buffersort[i].upptr, + buffersort[i].uppos, + buffersort[i].firstptr, + buffersort[i].ptrcount); + printf("CDVD buffer: "); + for(j = 0; j < 256; j++) { + if(buffersort[i].lower[j].isdata == 1) printf(" D"); + if(buffersort[i].lower[j].isdata == 0) printf(" L"); + if(buffersort[i].lower[j].isdata < 2) { + printf("%u:%u", j, buffersort[i].lower[j].ptr); + } // ENDIF- We have active data? Print it. + } // NEXT j- Scanning lower 256 pointers for active ones... + printf("\n"); + } // ENDIF- Not found in inactive list? Must be active! Print it. + } // NEXT i- looking at all the Allocated Buffers... +} // END PrintSortBuffers() +#endif /* VERBOSE_WARNINGS_BUFFER */ diff --git a/plugins/cdvd/CDVDlinuz/Src/buffer.h b/plugins/cdvd/CDVDlinuz/Src/buffer.h new file mode 100644 index 0000000000..fefe605061 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/buffer.h @@ -0,0 +1,67 @@ +/* buffer.h + * Copyright (C) 2002-2005 CDVDlinuz 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 + */ + +#ifndef __BUFFER_H__ +#define __BUFFER_H__ + + +#define CDVDdefs +#include "PS2Edefs.h" + + +// #define VERBOSE_FUNCTION_BUFFER +// #define VERBOSE_WARNINGS_BUFFER + +// Remember, each buffer set is about 5k (packed. might be 4x that in-memory) +// Minimum: 16 Maximum: 32760 +#define BUFFERMAX 256 + + +// Buffer Structures + +struct BufferList { + u16 upsort; // Don't alter this variable + u16 uppos; // Don't alter this variable + + u32 lsn; + int mode; // -1 means error + u8 buffer[2368]; + u8 offset; + cdvdSubQ subq; +}; + + +// Exported Variables + +extern struct BufferList bufferlist[]; +extern u16 userbuffer; +extern u16 replacebuffer; + + +// Exported Functions + +extern void InitBuffer(); +extern u16 FindListBuffer(u32 lsn); +extern void RemoveListBuffer(u16 oldbuffer); +extern void AddListBuffer(u16 newbuffer); +#ifdef VERBOSE_WARNINGS_BUFFER +extern void PrintSortBuffers(); +#endif /* VERBOSE_WARNINGS_BUFFER */ + + +#endif /* __BUFFER_H__ */ diff --git a/plugins/cdvd/CDVDlinuz/Src/convert.c b/plugins/cdvd/CDVDlinuz/Src/convert.c new file mode 100644 index 0000000000..9e6a62a2da --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/convert.c @@ -0,0 +1,118 @@ +/* convert.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include + +#include "convert.h" + + +off64_t ConvertEndianOffset(off64_t number) { +#ifndef CONVERTLITTLEENDIAN + union { + off64_t n; + char c[sizeof(off64_t)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(off64_t); i++) + newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianOffset() + + +unsigned int ConvertEndianUInt(unsigned int number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned int n; + char c[sizeof(unsigned int)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned int); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUInt() + + +unsigned short ConvertEndianUShort(unsigned short number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned short n; + char c[sizeof(unsigned short)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned short); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUShort() + + +// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. +void LBAtoMSF(unsigned long lsn, char *buffer) { + unsigned long templsn; + + if(lsn >= 0xFFFFFFFF - 150) { + *(buffer + 2) = 75-1; + *(buffer + 1) = 60-1; + *(buffer) = 100-1; + } // ENDIF- Out of range? + + templsn = lsn; + templsn += 150; // 2 second offset (75 Frames * 2 Seconds) + *(buffer + 2) = templsn % 75; // Remainder in frames + templsn -= *(buffer + 2); + templsn /= 75; + *(buffer + 1) = templsn % 60; // Remainder in seconds + templsn -= *(buffer + 1); + templsn /= 60; + *(buffer) = templsn; // Leftover quotient in minutes +} // END LBAtoMSF() + + +unsigned long MSFtoLBA(char *buffer) { + unsigned long templsn; + + if(buffer == NULL) return(0xFFFFFFFF); + + templsn = *(buffer); // Minutes + templsn *= 60; + templsn += *(buffer + 1); // Seconds + templsn *= 75; + templsn += *(buffer + 2); // Frames + if(templsn < 150) return(0xFFFFFFFF); + templsn -= 150; // Offset + + return(templsn); +} // END MSFtoLBA() diff --git a/plugins/cdvd/CDVDlinuz/Src/convert.h b/plugins/cdvd/CDVDlinuz/Src/convert.h new file mode 100644 index 0000000000..0806f7bd7f --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/convert.h @@ -0,0 +1,50 @@ +/* convert.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CONVERT_H +#define CONVERT_H + + +#include // off64_t + +#ifdef __linux__ +#include "endian.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CONVERTLITTLEENDIAN +#endif /* __BYTE_ORDER */ +#endif /* __linux__ */ + +#ifdef __WIN32__ +#define CONVERTLITTLEENDIAN +#endif /* __WIN32__ */ + +#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) +#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) + + +extern off64_t ConvertEndianOffset(off64_t number); +extern unsigned int ConvertEndianUInt(unsigned int number); +extern unsigned short ConvertEndianUShort(unsigned short number); + +extern void LBAtoMSF(unsigned long lsn, char *buffer); +extern unsigned long MSFtoLBA(char *buffer); + +#endif /* CONVERT_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/ini.c b/plugins/cdvd/CDVDlinuz/Src/ini.c new file mode 100644 index 0000000000..a00dac8f38 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/ini.c @@ -0,0 +1,689 @@ +/* ini.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include // NULL +#include // sprintf() + +#include "logfile.h" +#include "actualfile.h" +#include "ini.h" + + +const char INIext[] = ".ini"; +const char INInewext[] = ".new"; + + +// Returns: position where new extensions should be added. +int INIRemoveExt(char *argname, char *tempname) { + int i; + int j; + int k; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: RemoveExt(%s)", argname); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i <= INIMAXLEN) && (*(argname + i) != 0)) { + *(tempname + i) = *(argname + i); + i++; + } // ENDWHILE- Copying the argument name into a temporary area; + *(tempname + i) = 0; // And 0-terminate + k = i; + k--; + + j = 0; + while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; + j--; + + while((j >= 0) && (*(tempname + k) == INIext[j])) { + k--; + j--; + } // ENDWHILE- Comparing the ending characters to the INI ext. + if(j < 0) { + k++; + i = k; + *(tempname + i) = 0; // 0-terminate, cutting off ".ini" + } // ENDIF- Do we have a match? Then remove the end chars. + + return(i); +} // END INIRemoveExt() + + +void INIAddInExt(char *tempname, int temppos) { + int i; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { + *(tempname + temppos + i) = INIext[i]; + i++; + } // ENDWHILE- Attaching extenstion to filename + *(tempname + temppos + i) = 0; // And 0-terminate +} // END INIAddInExt() + + +void INIAddOutExt(char *tempname, int temppos) { + int i; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); +#endif /* VERBOSE_FUNCTION_INI */ + + i = 0; + while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { + *(tempname + temppos + i) = INInewext[i]; + i++; + } // ENDWHILE- Attaching extenstion to filename + *(tempname + temppos + i) = 0; // And 0-terminate +} // END INIAddInExt() + + +// Returns number of bytes read to get line (0 means end-of-file) +int INIReadLine(ACTUALHANDLE infile, char *buffer) { + int charcount; + int i; + char tempin[2]; + int retflag; + int retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: ReadLine()"); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + i = 0; + tempin[1] = 0; + retflag = 0; + + while((i < INIMAXLEN) && (retflag < 2)) { + retval = ActualFileRead(infile, 1, tempin); + charcount++; + if(retval != 1) { + retflag = 2; + charcount--; + + } else if(tempin[0] == '\n') { + retflag = 2; + + } else if(tempin[0] >= ' ') { + *(buffer + i) = tempin[0]; + i++; + } // ENDLONGIF- How do we react to the next character? + } // ENDWHILE- Loading up on characters until an End-of-Line appears + *(buffer + i) = 0; // And 0-terminate + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Line: %s", buffer); +#endif /* VERBOSE_FUNCTION_INI */ + + return(charcount); +} // END INIReadLine() +// Note: Do we need to back-skip a char if something other \n follows \r? + + +// Returns: number of bytes to get to start of section (or -1) +int INIFindSection(ACTUALHANDLE infile, char *section) { + int charcount; + int i; + int retflag; + int retval; + char scanbuffer[INIMAXLEN+1]; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: FindSection(%s)", section); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + retflag = 0; + + while(retflag == 0) { + retval = INIReadLine(infile, scanbuffer); + if(retval == 0) return(-1); // EOF? Stop here. + + if(scanbuffer[0] == '[') { + i = 0; + while((i < INIMAXLEN) && + (*(section + i) != 0) && + (*(section + i) == scanbuffer[i + 1])) i++; + if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { + if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { + retflag = 1; + } // ENDIF- End marks look good? Return successful. + } // ENDIF- Do we have a section match? + } // ENDIF- Does this look like a section header? + + if(retflag == 0) charcount += retval; + } // ENDWHILE- Scanning lines for the correct [Section] header. + + return(charcount); +} // END INIFindSection() + + +// Returns: number of bytes to get to start of keyword (or -1) +int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { + int charcount; + int i; + int j; + int retflag; + int retval; + char scanbuffer[INIMAXLEN+1]; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + charcount = 0; + retflag = 0; + + while(retflag == 0) { + retval = INIReadLine(infile, scanbuffer); + if(retval == 0) return(-1); // EOF? Stop here. + if(scanbuffer[0] == '[') return(-1); // New section? Stop here. + + i = 0; + while((i < INIMAXLEN) && + (*(keyword + i) != 0) && + (*(keyword + i) == scanbuffer[i])) i++; + if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { + if(scanbuffer[i] == '=') { + retflag = 1; + if(buffer != NULL) { + i++; + j = 0; + while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { + *(buffer + j) = scanbuffer[i]; + i++; + j++; + } // ENDWHILE- Copying the value out to the outbound buffer. + *(buffer + j) = 0; // And 0-terminate. + } // ENDIF- Return the value as well? + } // ENDIF- End marks look good? Return successful. + } // ENDIF- Do we have a section match? + + if(retflag == 0) charcount += retval; + } // ENDWHILE- Scanning lines for the correct [Section] header. + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Value: %s", buffer); +#endif /* VERBOSE_FUNCTION_INI */ + + return(charcount); +} // END INIFindKeyWord() + + +// Returns: number of bytes left to write... (from charcount back) +int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { + char buffer[4096]; + int i; + int chunk; + int retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Copy(%i)", charcount); +#endif /* VERBOSE_FUNCTION_INI */ + + i = charcount; + chunk = 4096; + if(i < chunk) chunk = i; + while(chunk > 0) { + retval = ActualFileRead(infile, chunk, buffer); + if(retval <= 0) return(i); // Trouble? Stop here. + if(retval < chunk) chunk = retval; // Short block? Note it. + + retval = ActualFileWrite(outfile, chunk, buffer); + if(retval <= 0) return(i); // Trouble? Stop here. + i -= retval; + if(retval < chunk) return(i); // Short block written? Stop here. + + chunk = 4096; + if(i < chunk) chunk = i; + } // ENDWHILE- Copying a section of file across, one chunk at a time. + + return(0); +} // END INICopyToPos() + + +int INISaveString(char *file, char *section, char *keyword, char *value) { + char inname[INIMAXLEN+1]; + char outname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + ACTUALHANDLE outfile; + int i; + int retval; + char templine[INIMAXLEN+1]; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + if(keyword == NULL) return(-1); + if(value == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", + file, section, keyword, value); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + INIAddInExt(inname, filepos); + INIAddOutExt(outname, filepos); + + filepos = 0; + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new file"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(inname); + if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. + + sprintf(templine, "[%s]\r\n", section); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + if(retval < i) { + ActualFileDelete(inname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + return(0); + } // ENDIF- No input file? Create a brand new .ini file then. + + retval = INIFindSection(infile, section); + if(retval < 0) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new section"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); // Move ini to beginning of file... + INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... + + sprintf(templine, "\r\n[%s]\r\n", section); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + if(retval < i) { + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); + } // ENDIF- Couldn't find the section? Make a new one! + + filepos = retval; + ActualFileSeek(infile, filepos); + filepos += INIReadLine(infile, templine); // Get section line's byte count + + retval = INIFindKeyword(infile, keyword, NULL); + if(retval < 0) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: creating new keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + ActualFileSeek(infile, filepos); + retval = INIReadLine(infile, templine); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + while((retval > 0) && (templine[i] == '=')) { + filepos += retval; + retval = INIReadLine(infile, templine); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + } // ENDWHILE- skimming to the bottom of the section + + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + + } else { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: replacing keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + filepos += retval; // Position just before old version of keyword + + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + INIReadLine(infile, templine); // Read past old keyword/value... + + // Replace with new value + sprintf(templine, "%s=%s\r\n", keyword, value); + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + } // ENDIF- Need to add a new keyword? + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); +} // END INISaveString() + + +int INILoadString(char *file, char *section, char *keyword, char *buffer) { + char inname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + int retval; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + if(keyword == NULL) return(-1); + if(buffer == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", + file, section, keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + INIAddInExt(inname, filepos); + + filepos = 0; + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) return(-1); + + retval = INIFindSection(infile, section); + if(retval < 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Didn't find it? Abort. + + retval = INIFindKeyword(infile, keyword, buffer); + if(retval < 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Didn't find it? Abort. + + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(0); +} // END INILoadString() + + +int INIRemove(char *file, char *section, char *keyword) { + char inname[INIMAXLEN+1]; + char outname[INIMAXLEN+1]; + int filepos; + ACTUALHANDLE infile; + ACTUALHANDLE outfile; + char templine[INIMAXLEN+1]; + int i; + int retval; + + if(file == NULL) return(-1); + if(section == NULL) return(-1); + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: Remove(%s, %s, %s)", + file, section, keyword); +#endif /* VERBOSE_FUNCTION_INI */ + + filepos = INIRemoveExt(file, inname); + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + INIAddInExt(inname, filepos); + INIAddOutExt(outname, filepos); + + infile = ActualFileOpenForRead(inname); + if(infile == ACTUALHANDLENULL) return(-1); + + retval = INIFindSection(infile, section); + if(retval == -1) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't even find the section? Abort + + filepos = retval; + if(keyword == NULL) { +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: removing section"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to the section? Abort. + + templine[0] = 0; + retval = 1; + while((retval > 0) && (templine[0] != '[')) { + retval = INIReadLine(infile, templine); + } // ENDWHILE- Read to the start of the next section... or EOF. + + if(templine[0] == '[') { + i = 0; + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + retval = ActualFileWrite(outfile, i, templine); + if(retval < i) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing it out? Abort. + } // ENDIF- Are there other sections after this one? Save them then. + + } else { + filepos = retval; + ActualFileSeek(infile, filepos); + filepos += INIReadLine(infile, templine); // Get section line's byte count + + retval = INIFindKeyword(infile, keyword, NULL); + if(retval == -1) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't find the keyword? Abort + filepos += retval; + +#ifdef VERBOSE_FUNCTION_INI + PrintLog("CDVDiso ini: removing keyword"); +#endif /* VERBOSE_FUNCTION_INI */ + outfile = ActualFileOpenForWrite(outname); + if(outfile == ACTUALHANDLENULL) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + return(-1); + } // ENDIF- Couldn't open a temp file? Abort + + ActualFileSeek(infile, 0); + retval = INICopy(infile, outfile, filepos); + if(retval > 0) { + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(outname); + return(-1); + } // ENDIF- Trouble writing everything up to keyword? Abort. + + INIReadLine(infile, templine); // Read (and discard) the keyword line + } // ENDIF- Wipe out the whole section? Or just a keyword? + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + ActualFileClose(infile); + infile = ACTUALHANDLENULL; + ActualFileClose(outfile); + outfile = ACTUALHANDLENULL; + ActualFileDelete(inname); + ActualFileRename(outname, inname); + return(0); +} // END INIRemove() + + +int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { + char numvalue[INIMAXLEN+1]; + + sprintf(numvalue, "%u", value); + return(INISaveString(file, section, keyword, numvalue)); +} // END INISaveUInt() + + +int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { + char numvalue[INIMAXLEN+1]; + int retval; + unsigned int value; + // unsigned int sign; // Not needed in unsigned numbers + int pos; + + if(buffer == NULL) return(-1); + *(buffer) = 0; + + retval = INILoadString(file, section, keyword, numvalue); + if(retval < 0) return(retval); + + value = 0; + // sign = 1; // Start positive + pos = 0; + + // Note: skip leading spaces? (Shouldn't have to, I hope) + + // if(numvalue[pos] == '-') { + // pos++; + // sign = -1; + // } // ENDIF- Negative sign check + + while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { + if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? + + if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { + value *= 10; + value += numvalue[pos] - '0'; + pos++; + } else { + numvalue[pos] = 0; + } // ENDIF- Add a digit in? Or stop searching for digits? + } // ENDWHILE- Adding digits of info to our ever-increasing value + + // value *= sign + *(buffer) = value; + return(0); +} // END INILoadUInt() diff --git a/plugins/cdvd/CDVDlinuz/Src/ini.h b/plugins/cdvd/CDVDlinuz/Src/ini.h new file mode 100644 index 0000000000..fbd2349cf5 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/ini.h @@ -0,0 +1,64 @@ +/* ini.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef INI_H +#define INI_H + + +// #ifndef __LINUX__ +// #ifdef __linux__ +// #define __LINUX__ +// #endif /* __linux__ */ +// #endif /* No __LINUX__ */ + +// #define CDVDdefs +// #include "PS2Edefs.h" + + +// File format: +// [section] +// keyword=value + +// file - Name of the INI file +// section - Section within the file +// keyword - Identifier for a value +// value - value to store with a keyword in a section in the file +// buffer - place to retrieve the value of a keyword + +// return values: 0 = success, -1 = failure + + +// #define VERBOSE_FUNCTION_INI + +#define INIMAXLEN 255 + + +extern int INISaveString(char *file, char *section, char *keyword, char *value); +extern int INILoadString(char *file, char *section, char *keyword, char *buffer); + +extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); +extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); + +// NULL in the keyword below removes the whole section. +extern int INIRemove(char *file, char *section, char *keyword); + + +#endif /* INI_H */ diff --git a/plugins/cdvd/CDVDlinuz/Src/version.c b/plugins/cdvd/CDVDlinuz/Src/version.c new file mode 100644 index 0000000000..c2b9b2dc87 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/version.c @@ -0,0 +1,36 @@ +/* version.c + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +char *libname = "EFP polling CDVD Driver"; + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 4; diff --git a/plugins/cdvd/CDVDlinuz/Src/version.h b/plugins/cdvd/CDVDlinuz/Src/version.h new file mode 100644 index 0000000000..774ce3b29a --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/Src/version.h @@ -0,0 +1,43 @@ +/* version.h + * Copyright (C) 2002-2005 PCSX2 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 + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef VERSION_H +#define VERSION_H + + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" + + +extern char *libname; + +extern const unsigned char version; +extern const unsigned char revision; +extern const unsigned char build; + + +#endif /* VERSION_H */ diff --git a/plugins/cdvd/CDVDlinuz/build.sh b/plugins/cdvd/CDVDlinuz/build.sh new file mode 100644 index 0000000000..523ab08bef --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +curdir=`pwd` + +echo ------------------ +echo Building CDVDlinuz +echo ------------------ + +cd ${curdir}/Src/Linux +make $@ + +if [ -s cfgCDVDlinuz ] && [ -s libCDVDlinuz.so ] +then +# copy the files +cp cfgCDVDlinuz libCDVDlinuz.so ${PCSX2PLUGINS} +fi diff --git a/plugins/cdvd/CDVDlinuz/readme.txt b/plugins/cdvd/CDVDlinuz/readme.txt new file mode 100644 index 0000000000..93fa7a7697 --- /dev/null +++ b/plugins/cdvd/CDVDlinuz/readme.txt @@ -0,0 +1,37 @@ +CDVDlinuz v0.4 +-------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + + Modified by efp to work with DVDs as well + +To install in Windows: +----- + Place the file "CDVDlinuz.dll" in the "plugins" directory. + +To install in Linux: +----- + Place the file "libCDVDlinuz.so" in the "plugins/" directory. + Place the file "cfgCDVDlinuz" in the "cfg/" directory. + +To activate in PCSX2: +----- + Start up PCSX2. + Select "Configuration", then "Plugins and Bios". + In the "Cdvdrom" pull-down menu, you should see: + "EFP polling CDVD Driver v.04" + Select it. + Then press the "Configure" button under it. + In the "CDVDlinuz Configuration" screen, type in where your CD or DVD +device can be found. + (In Linux, devices look like "/dev/") + (In Windows, devices look like "D:". There are other types of references to +devices, but they haven't been tested.) + Press to "OK" button to save your selection. + Finally, put a CD or DVD in the selected drive, and run PCSX2. + + Keep in mind the above instructions only cover the "CD/DVD" portion of +PCSX2. All configuration options must be attended to before PCSX2 could run +correctly. diff --git a/plugins/cdvd/CDVDnull/ReadMe.txt b/plugins/cdvd/CDVDnull/ReadMe.txt new file mode 100644 index 0000000000..24a667467c --- /dev/null +++ b/plugins/cdvd/CDVDnull/ReadMe.txt @@ -0,0 +1,39 @@ +CDVDnull v0.6 +--------------- + + This is an extension to use with playstation2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Using: +----- + Place the file "CDVDnull.dll" at the Plugins directory + of the Emulator to use it. + +Changes: +------- + v0.6: + * added vsnet2003 project files. + * added support for functions in new plugin version + + v0.5: + * added vsnet2005beta1 project files. 64bit plugin should be okay now (Not tested!) + + v0.4: + * updated to 0.4.3 specifications + + v0.3: + * updated to 0.4.0 specifications + + v0.2: + * add the 0.2.9 specifications + * CDVDopen refixed + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + diff --git a/plugins/cdvd/CDVDnull/Src/CDVD.c b/plugins/cdvd/CDVDnull/Src/CDVD.c new file mode 100644 index 0000000000..5f338b6983 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVD.c @@ -0,0 +1,146 @@ +#include + +#include "CDVD.h" + + +char *LibName = "CDVDnull Driver"; + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 6; + + +char* CALLBACK PS2EgetLibName() { + return LibName; +} + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_CDVD; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version << 16) | (revision << 8) | build; +} + +#ifdef _WIN32 +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + + MessageBox(0, tmp, "CDVDnull Msg", 0); +} +#else + +void SysMessage(char *fmt, ...) { + /*GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main();*/ +} + +#endif + +s32 CALLBACK CDVDinit() { + return 0; +} + +s32 CALLBACK CDVDopen(const char* pTitle) { + return 0; +} + +void CALLBACK CDVDclose() { +} + +void CALLBACK CDVDshutdown() { +} + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + return -1; +} + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer() { + return NULL; +} + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + return -1; +} + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + return -1; +} + +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer) { + return -1; +} + +s32 CALLBACK CDVDgetTOC(void* toc) { + return -1; +} + +s32 CALLBACK CDVDgetDiskType() { + return CDVD_TYPE_NODISC; +} + +s32 CALLBACK CDVDgetTrayStatus() { + return CDVD_TRAY_CLOSE; +} + +s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} + +s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + +void CALLBACK CDVDconfigure() { + SysMessage("Nothing to Configure"); +} + +void CALLBACK CDVDabout() { + SysMessage("%s %d.%d", LibName, revision, build); +} + +s32 CALLBACK CDVDtest() { + return 0; +} diff --git a/plugins/cdvd/CDVDnull/Src/CDVD.h b/plugins/cdvd/CDVDnull/Src/CDVD.h new file mode 100644 index 0000000000..942449130e --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVD.h @@ -0,0 +1,11 @@ +#ifndef __CDVD_H__ +#define __CDVD_H__ + +#ifdef _WIN32 +#include +#endif + +#define CDVDdefs +#include "PS2Edefs.h" + +#endif /* __CDVD_H__ */ diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.def b/plugins/cdvd/CDVDnull/Src/CDVDnull.def new file mode 100644 index 0000000000..18fb48080a --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull.def @@ -0,0 +1,29 @@ +; CDVDnull.def : Declares the module parameters for the DLL. + +LIBRARY "CDVDnull" +DESCRIPTION 'CDVD Null Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDreadTrack @9 + CDVDgetBuffer @10 + CDVDreadSubQ @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDgetTOC @14 + CDVDgetDiskType @15 + CDVDgetTrayStatus @16 + CDVDctrlTrayOpen @17 + CDVDctrlTrayClose @18 + + CDVDconfigure @19 + CDVDtest @20 + CDVDabout @21 + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.dsp b/plugins/cdvd/CDVDnull/Src/CDVDnull.dsp new file mode 100644 index 0000000000..5e02435d1f --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="CDVDnull" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=CDVDNULL - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "CDVDnull.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "CDVDnull.mak" CFG="CDVDNULL - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CDVDnull - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "__MSCW32__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDNULL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "__MSCW32__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDNULL_EXPORTS" /D "__WIN32__" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# Begin Target + +# Name "CDVDnull - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\CDVD.c +# End Source File +# Begin Source File + +SOURCE=.\CDVDnull.def +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\CDVD.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Etypes.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.dsw b/plugins/cdvd/CDVDnull/Src/CDVDnull.dsw new file mode 100644 index 0000000000..ca22d5ba79 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CDVDnull"=".\CDVDnull.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.opt b/plugins/cdvd/CDVDnull/Src/CDVDnull.opt new file mode 100644 index 0000000000000000000000000000000000000000..13a3499ad319ec9623dbe40f3db4ac98e2582e95 GIT binary patch literal 53760 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

+ +

+

Build Log

+

+--------------------Configuration: CDVDnull - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\marcelo\LOCALS~1\Temp\RSP89.tmp" with contents +[ +/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CDVDNULL_EXPORTS" /D "__WIN32__" /Fo"Release/" /Fd"Release/" /FD /c +"C:\pcsx2\plugins\cdvd\CDVDnull\Src\CDVD.c" +] +Creating command line "xicl6.exe @C:\DOCUME~1\marcelo\LOCALS~1\Temp\RSP89.tmp" +Creating temporary file "C:\DOCUME~1\marcelo\LOCALS~1\Temp\RSP8A.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /pdb:"Release/CDVDnull.pdb" /machine:I386 /def:".\CDVDnull.def" /out:"Release/CDVDnull.dll" /implib:"Release/CDVDnull.lib" +.\Release\CDVD.obj +] +Creating command line "xilink6.exe @C:\DOCUME~1\marcelo\LOCALS~1\Temp\RSP8A.tmp" +

Output Window

+Compiling... +CDVD.c +Linking... +xilink6: executing 'C:\PROGRA~1\MICROS~2\VC98\Bin\link.exe' + Creating library Release/CDVDnull.lib and object Release/CDVDnull.exp + + + +

Results

+CDVDnull.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.sln b/plugins/cdvd/CDVDnull/Src/CDVDnull.sln new file mode 100644 index 0000000000..4336fc793a --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDnull", "CDVDnull.vcproj", "{F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release.ActiveCfg = Release|Win32 + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull.vcproj b/plugins/cdvd/CDVDnull/Src/CDVDnull.vcproj new file mode 100644 index 0000000000..632c7b4250 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull.vcproj @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.sln b/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.sln new file mode 100644 index 0000000000..c0b7d9093e --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDnull", "CDVDnull_2003.vcproj", "{F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release.ActiveCfg = Release|Win32 + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.vcproj b/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.vcproj new file mode 100644 index 0000000000..863e3909e7 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_2003.vcproj @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.sln b/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.sln new file mode 100644 index 0000000000..28148839fa --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDnull", "CDVDnull_2005_x64.vcproj", "{F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release|x64.ActiveCfg = amd64|x64 + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release|x64.Build.0 = amd64|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.vcproj b/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.vcproj new file mode 100644 index 0000000000..466b0f3052 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_2005_x64.vcproj @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.sln b/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.sln new file mode 100644 index 0000000000..349a3a17ab --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDnull", "CDVDnull_vsnet2005beta1.vcproj", "{F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release|Win32.ActiveCfg = Release|Win32 + {F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.vcproj b/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.vcproj new file mode 100644 index 0000000000..097ba19f38 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/CDVDnull_vsnet2005beta1.vcproj @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDnull/Src/Makefile b/plugins/cdvd/CDVDnull/Src/Makefile new file mode 100644 index 0000000000..8331e1cee4 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/Makefile @@ -0,0 +1,50 @@ +# +# Makefile for MINGW32 +# + + +all: cdvdnull +install: all + +PLUGIN = libCDVDnull.so + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = +LIBS = +RESOBJ = cdvdnull.o + +OBJS = CDVD.o + + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} -fPIC + +cdvdnull: ${OBJS} +# dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean cdvdnull + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: CDVDnull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} diff --git a/plugins/cdvd/CDVDnull/Src/PS2Edefs.h b/plugins/cdvd/CDVDnull/Src/PS2Edefs.h new file mode 100644 index 0000000000..3e9707049b --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/PS2Edefs.h @@ -0,0 +1,827 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDnull/Src/PS2Etypes.h b/plugins/cdvd/CDVDnull/Src/PS2Etypes.h new file mode 100644 index 0000000000..1ad73e273d --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDnull/Src/plugin.def b/plugins/cdvd/CDVDnull/Src/plugin.def new file mode 100644 index 0000000000..4d19ae2002 --- /dev/null +++ b/plugins/cdvd/CDVDnull/Src/plugin.def @@ -0,0 +1,21 @@ +EXPORTS + PS2EgetLibType = PS2EgetLibType@0 @2 + PS2EgetLibName = PS2EgetLibName@0 @3 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @4 + CDVDinit = CDVDinit@0 @5 + CDVDshutdown = CDVDshutdown@0 @6 + CDVDopen = CDVDopen@0 @7 + CDVDclose = CDVDclose@0 @8 + CDVDreadTrack = CDVDreadTrack@8 @9 + CDVDgetBuffer = CDVDgetBuffer@0 @10 + CDVDreadSubQ = CDVDreadSubQ@8 @11 + CDVDgetTN = CDVDgetTN@4 @12 + CDVDgetTD = CDVDgetTD@8 @13 + CDVDgetTOC = CDVDgetTOC@4 @14 + CDVDgetDiskType = CDVDgetDiskType@0 @15 + CDVDgetTrayStatus = CDVDgetTrayStatus@0 @16 + CDVDctrlTrayOpen = CDVDctrlTrayOpen@0 @17 + CDVDctrlTrayClose = CDVDctrlTrayClose@0 @18 + CDVDconfigure = CDVDconfigure@0 @19 + CDVDtest = CDVDtest@0 @20 + CDVDabout = CDVDabout@0 @21 diff --git a/plugins/cdvd/CDVDnull/build.sh b/plugins/cdvd/CDVDnull/build.sh new file mode 100644 index 0000000000..cc8792b0b5 --- /dev/null +++ b/plugins/cdvd/CDVDnull/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +curdir=`pwd` + +echo ----------------- +echo Building CDVDnull +echo ----------------- +cd ${curdir}/Src +make $@ + +# copy the files +cp libCDVDnull.so ${PCSX2PLUGINS} diff --git a/plugins/cdvd/CDVDpeops/CDVDiso.c b/plugins/cdvd/CDVDpeops/CDVDiso.c new file mode 100644 index 0000000000..d15d1ff55c --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CDVDiso.c @@ -0,0 +1,822 @@ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + * Fixed CdRead by linuzappz + */ + +#include +#ifdef __LINUX__ +#define strnicmp strncasecmp +#endif + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +struct dir_toc_data{ + unsigned int start_LBA; + unsigned int num_sectors; + unsigned int num_entries; + unsigned int current_entry; + unsigned int current_sector; + unsigned int current_sector_offset; + unsigned int inc_dirs; + unsigned char extension_list[128+1]; +}; + +//static u8 cdVolDescriptor[2048]; +static struct dir_toc_data getDirTocData; +static struct cdVolDesc CDVolDesc; + +void _splitpath2(const char *constpath, char *dir, char *fname){ + // 255 char max path-length is an ISO9660 restriction + // we must change this for Joliet or relaxed iso restriction support + static char pathcopy[1024+1]; + + char* slash; + + strncpy(pathcopy, constpath, 1024); + + slash = strrchr (pathcopy, '/'); + + // if the path doesn't contain a '/' then look for a '\' + if (!slash) + slash = strrchr (pathcopy, (int)'\\'); + + // if a slash was found + if (slash != NULL) + { + // null terminate the path + slash[0] = 0; + // and copy the path into 'dir' + strncpy(dir, pathcopy, 1024); + dir[255]=0; + + // copy the filename into 'fname' + strncpy(fname, slash+1, 128); + fname[128]=0; + } + else + { + dir[0] = 0; + + strncpy(fname, pathcopy, 128); + fname[128]=0; + } + +} + +// Used in findfile +int tolower(int c); +int strcasecmp(const char *s1, const char *s2){ + while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) + { + s1++; + s2++; + } + + return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); +} + +// Copy a TOC Entry from the CD native format to our tidier format +void TocEntryCopy(struct TocEntry* tocEntry, struct dirTocEntry* internalTocEntry){ + int i; + int filenamelen; + + tocEntry->fileSize = internalTocEntry->fileSize; + tocEntry->fileLBA = internalTocEntry->fileLBA; + tocEntry->fileProperties = internalTocEntry->fileProperties; + memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); + + if (CDVolDesc.filesystemType == 2){ + // This is a Joliet Filesystem, so use Unicode to ISO string copy + + filenamelen = internalTocEntry->filenameLength/2; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + for (i=0; i < filenamelen; i++) + tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; + + tocEntry->filename[filenamelen] = 0; + } + else{ + filenamelen = internalTocEntry->filenameLength; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + // use normal string copy + strncpy(tocEntry->filename,internalTocEntry->filename,128); + tocEntry->filename[filenamelen] = 0; + } +} + +// Check if a TOC Entry matches our extension list +int TocEntryCompare(char* filename, char* extensions){ + static char ext_list[129]; + + char* token; + + char* ext_point; + + strncpy(ext_list,extensions,128); + ext_list[128]=0; + + token = strtok( ext_list, " ," ); + while( token != NULL ) + { + // if 'token' matches extension of 'filename' + // then return a match + ext_point = strrchr(filename,'.'); + + if (strnicmp(ext_point, token, strlen(token)) == 0) + return (TRUE); + + /* Get next token: */ + token = strtok( NULL, " ," ); + } + + // If not match found then return FALSE + return (FALSE); + +} + +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ + +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + int rmode; + + switch (mode->datapattern) { + case CdSecS2048: + rmode = CDVD_MODE_2048; break; + case CdSecS2328: + rmode = CDVD_MODE_2328; break; + case CdSecS2340: + rmode = CDVD_MODE_2340; break; + default: + return 0; + } + + for (i=0; idatapattern){ + case CdSecS2048: + memcpy((void*)((uptr)buf+2048*i), buff, 2048);break;//only data + case CdSecS2328: + memcpy((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub + case CdSecS2340: + memcpy((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync + } + } + return 1; +} + +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + + for (i=lsn; i<(lsn+sectors); i++){ + if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) + return 0; + buff = CDVDgetBuffer(); + if (buff==NULL) return 0; + +// switch (mode->datapattern){ +// case CdSecS2064: + ((u32*)buf)[0] = i + 0x30000; + memcpy((u8*)buf+12, buff, 2048); + (u8*)buf+= 2064; break; +// default: +// return 0; +// } + } + + return 1; +} + +/************************************************************** +* The functions below are not exported for normal file-system * +* operations, but are used by the file-system operations, and * +* may also be exported for use via RPC * +**************************************************************/ + +int CDVD_GetVolumeDescriptor(void){ + // Read until we find the last valid Volume Descriptor + int volDescSector; + + static struct cdVolDesc localVolDesc; + +#ifdef DEBUG + printf("CDVD_GetVolumeDescriptor called\n"); +#endif + + for (volDescSector = 16; volDescSector<20; volDescSector++) + { + CdRead(volDescSector,1,&localVolDesc,&cdReadMode); +// CdSync(0x00); + + // If this is still a volume Descriptor + if (strncmp(localVolDesc.volID, "CD001", 5) == 0) + { + if ((localVolDesc.filesystemType == 1) || + (localVolDesc.filesystemType == 2)) + { + memcpy(&CDVolDesc, &localVolDesc, sizeof(struct cdVolDesc)); + } + } + else + break; + } + +#ifdef DEBUG + if (CDVolDesc.filesystemType == 1) + printf("CD FileSystem is ISO9660\n"); + else if (CDVolDesc.filesystemType == 2) + printf("CD FileSystem is Joliet\n"); + else printf("Could not detect CD FileSystem type\n"); +#endif +// CdStop(); + + return TRUE; +} + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry){ + static char filename[128+1]; + static char pathname[1024+1]; + static char toc[2048]; + char* dirname; + + + static struct TocEntry localTocEntry; // used for internal checking only + + int found_dir; + + int num_dir_sectors; + int current_sector; + + int dir_lba; + + struct dirTocEntry* tocEntryPointer; + +#ifdef DEBUG + printf("CDVD_findfile called\n"); +#endif + + //make sure we have good cdReadMode + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; + + _splitpath2(fname, pathname, filename); + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + current_sector = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + + while( dirname != NULL ) + { + found_dir = FALSE; +/* + while(tocEntryPointer->length > 0) + { + // while there are still more directory entries then search through + // for the one we want + + if (tocEntryPointer->fileProperties & 0x02) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcasecmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } +*/ + while(1) + { + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) + { + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) + { + return -1; + } +// CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + else + { + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + + if (tocEntryPointer->fileProperties & 0x02) + { + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + { + return -1; + } + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) + { + return -1; + } +// CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + } + + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + dir_lba = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + while (num_dir_sectors > 0) + { + while(tocEntryPointer->length != 0) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || + ((filename[strlen(filename)-2] == ';') && + (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && + (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) + { + // if the filename matches then copy the toc Entry + tocEntry->fileLBA = localTocEntry.fileLBA; + tocEntry->fileProperties = localTocEntry.fileProperties; + tocEntry->fileSize = localTocEntry.fileSize; + + strcpy(tocEntry->filename, localTocEntry.filename); + memcpy(tocEntry->date, localTocEntry.date, 7); + +#ifdef DEBUG + printf("CDVD_findfile: found file\n"); +#endif + + return TRUE; + } + + (char*)tocEntryPointer += tocEntryPointer->length; + } + + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + dir_lba++; + + if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ + return -1; + } +// CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + } + + return FALSE; +} + +// This is the RPC-ready function which takes the request to start the tocEntry retrieval +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ +// int dir_depth = 1; + static char toc[2048]; + char* dirname; + int found_dir; + int num_dir_sectors; + unsigned int toc_entry_num; + struct dirTocEntry* tocEntryPointer; + static struct TocEntry localTocEntry; + int current_sector; + + // store the extension list statically for the retrieve function + strncpy(getDirTocData.extension_list, extensions, 128); + getDirTocData.extension_list[128]=0; + + getDirTocData.inc_dirs = inc_dirs; + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); +#endif + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; + current_sector = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + // use strtok to get the next dir name + + // if there isnt one, then assume we want the LBA + // for the current one, and exit the while loop + + // if there is another dir name then increment dir_depth + // and look through dir table entries until we find the right name + // if we dont find the right name + // before finding an entry at a higher level (lower num), then return nothing + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + while( dirname != NULL ){ + found_dir = FALSE; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + else{ + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + if (tocEntryPointer->fileProperties & 0x02){ + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0){ + // if the name matches then we've found the directory + found_dir = TRUE; +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); + RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); +#endif + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + return -1; + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // We know how much data we need to read in from the DirTocHeader + // but we need to read in at least 1 sector before we can get this value + + // Now we need to COUNT the number of entries (dont do anything with info at this point) + // so set the tocEntryPointer to point to the first actual file entry + + // This is a bit of a waste of reads since we're not actually copying the data out yet, + // but we dont know how big this TOC might be, so we cant allocate a specific size + + (char*)tocEntryPointer = toc; + + // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. + getDirTocData.start_LBA = localTocEntry.fileLBA; + getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; + getDirTocData.num_entries = 0; + getDirTocData.current_entry = 0; + getDirTocData.current_sector = getDirTocData.start_LBA; + getDirTocData.current_sector_offset = 0; + + num_dir_sectors = getDirTocData.num_sectors; + + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + toc_entry_num=0; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ + // decrease the number of dirs remaining + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + (char*)tocEntryPointer = toc; + +// continue; + } + else{ + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + return (toc_entry_num); + } + } + + // We've found a file/dir in this directory + // now check if it matches our extension list (if there is one) + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if (localTocEntry.fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs){ + toc_entry_num++; + } + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + } + else{ + toc_entry_num++; + } + } + + (char*)tocEntryPointer += tocEntryPointer->length; + + } + + + // THIS SHOULD BE UNREACHABLE - + // since we are trying to count ALL matching entries, rather than upto a limit + + + // STORE total number of TOC entries + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + + + // we've reached the toc entry limit, so return how many we've done + return (toc_entry_num); + +} + +// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries +// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries){ + static char toc[2048]; + int toc_entry_num; + + struct dirTocEntry* tocEntryPointer; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + if (getDirTocData.current_entry == 0){ + // if this is the first read then make sure we point to the first real entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; + } + else{ + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + + if (req_entries > 128) + req_entries = 128; + + for (toc_entry_num=0; toc_entry_num < req_entries;){ + if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ + // decrease the number of dirs remaining + getDirTocData.num_sectors--; + + if (getDirTocData.num_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + getDirTocData.current_sector_offset = 0; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + +// continue; + } + else{ + return (toc_entry_num); + } + } + + // This must be incremented even if the filename doesnt match extension list + getDirTocData.current_entry++; + + // We've found a file in this directory + // now check if it matches our extension list (if there is one) + + // Copy the entry regardless, as it makes the comparison easier + // if it doesn't match then it will just be overwritten + TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); + + if (tocEntry[toc_entry_num].fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs) { + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + + } + else{ + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + } +/* + if (strlen(getDirTocData.extension_list) > 0) + { + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) + { + + // increment this here, rather than in the main for loop + // since this should count the number of matching entries + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else + { + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } +*/ + } + return (toc_entry_num); +} diff --git a/plugins/cdvd/CDVDpeops/CDVDiso.h b/plugins/cdvd/CDVDpeops/CDVDiso.h new file mode 100644 index 0000000000..72b0552280 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CDVDiso.h @@ -0,0 +1,131 @@ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISO_H__ +#define __CDVDISO_H__ + +#include "CDVDlib.h" + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries); + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(__WIN32__) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTableEntry +{ + u8 dirNameLength; + u8 reserved; + u32 dirTOCLBA; + u16 dirDepth; + u8 dirName[32]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTocEntry +{ + short length; + unsigned int fileLBA; + unsigned int fileLBA_bigend; + unsigned int fileSize; + unsigned int fileSize_bigend; + unsigned char dateStamp[6]; + unsigned char reserved1; + unsigned char fileProperties; + unsigned char reserved2[6]; + unsigned char filenameLength; + unsigned char filename[128]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif // This is the internal format on the CD +// TocEntry structure contains only the important stuff needed for export + +#if defined(__WIN32__) +#pragma pack() +#endif + +#endif//__CDVDISO_H__ diff --git a/plugins/cdvd/CDVDpeops/CDVDisodrv.c b/plugins/cdvd/CDVDpeops/CDVDisodrv.c new file mode 100644 index 0000000000..180f89c189 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CDVDisodrv.c @@ -0,0 +1,264 @@ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#include + +#include "CDVDlib.h" +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +CdRMode cdReadMode; + +struct fdtable{ +//int fd; + int fileSize; + int LBA; + int filePos; +}; + +static struct fdtable fd_table[16]; +static int fd_used[16]; +static int files_open=0; +static int inited=FALSE; + +/************************************************************* +* The functions below are the normal file-system operations, * +* used to provide a standard filesystem interface * +*************************************************************/ + +////////////////////////////////////////////////////////////////////// +// CDVDFS_init +// called by 80000592 sceCdInit() +////////////////////////////////////////////////////////////////////// +void CDVDFS_init(){ + + if (inited) return;//might change in the future as a param; forceInit/Reset + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); + RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); + RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); +#endif + + //CdInit(0); already called by plugin loading system ;) + + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; //isofs driver only needs + //2KB sectors + + memset(fd_table, 0, sizeof(fd_table)); + memset(fd_used, 0, 16*sizeof(int)); + + inited = TRUE; + + return; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_open +// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_open(char *name, int mode){ + register int j; + static struct TocEntry tocEntry; + + // check if the file exists + if (CDVD_findfile(name, &tocEntry) != TRUE) + return -1; + + if(mode != 1) return -2; //SCE_RDONLY + + // set up a new file descriptor + for(j=0; j < 16; j++) if(fd_used[j] == 0) break; + if(j >= 16) return -3; + + fd_used[j] = 1; + files_open++; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); +#endif + + fd_table[j].fileSize = tocEntry.fileSize; + fd_table[j].LBA = tocEntry.fileLBA; + fd_table[j].filePos = 0; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); +#endif + + return j; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_lseek +// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_lseek(int fd, int offset, int whence){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + switch(whence){ + case SEEK_SET: + fd_table[fd].filePos = offset; + break; + + case SEEK_CUR: + fd_table[fd].filePos += offset; + break; + + case SEEK_END: + fd_table[fd].filePos = fd_table[fd].fileSize + offset; + break; + + default: + return -1; + } + + if (fd_table[fd].filePos < 0) + fd_table[fd].filePos = 0; + + if (fd_table[fd].filePos > fd_table[fd].fileSize) + fd_table[fd].filePos = fd_table[fd].fileSize; + + return fd_table[fd].filePos; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_read +// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_read( int fd, char *buffer, int size ){ +// int start_sector; + int off_sector; +// int num_sectors; + + //static char local_buffer[2024*2048]; //4MB + static char lb[2048]; //2KB + //Start, Aligned, End + int ssector, asector, esector; + int ssize=0, asize, esize; + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + // A few sanity checks + if (fd_table[fd].filePos > fd_table[fd].fileSize){ + // We cant start reading from past the beginning of the file + return 0; // File exists but we couldnt read anything from it + } + + if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) + size = fd_table[fd].fileSize - fd_table[fd].filePos; + + // Now work out where we want to start reading from + asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + if (off_sector){ + ssize = min(2048 - off_sector, size); + size -= ssize; + asector++; + } + asize = size & 0xFFFFF800; + esize = size & 0x000007FF; + esector=asector + (asize >> 11); + size += ssize; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); +#endif + + if (ssize){ if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + memcpy(buffer, lb + off_sector, ssize); + } + if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + if (esize){ if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + memcpy(buffer+ssize+asize, lb, esize); + } +/*********************** + // Now work out where we want to start reading from + start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + num_sectors = ((off_sector + size) >> 11) + 1; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); +#endif + + // Read the data (we only ever get 16KB max request at once) + if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + //CdSync(0); hm, a wait function maybe... + + memcpy(buffer,local_buffer+off_sector,size); +**************************/ + fd_table[fd].filePos += size; + + return (size); +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_write +// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" +// hehe, this ain't a CD writing option :D +////////////////////////////////////////////////////////////////////// +int CDVDFS_write( int fd, char * buffer, int size ){ + if(size == 0) return 0; + else return -1; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_close +// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_close( int fd){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); +#endif + + fd_used[fd] = 0; + files_open--; + + return 0; +} + diff --git a/plugins/cdvd/CDVDpeops/CDVDisodrv.h b/plugins/cdvd/CDVDpeops/CDVDisodrv.h new file mode 100644 index 0000000000..dcf8545a86 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CDVDisodrv.h @@ -0,0 +1,22 @@ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISODRV_H__ +#define __CDVDISODRV_H__ + +//#include "Common.h" +#include "CDVDlib.h" + +extern CdRMode cdReadMode; + +/* Filing-system exported functions */ +void CDVDFS_init(); +int CDVDFS_open(char *name, int mode); +int CDVDFS_lseek(int fd, int offset, int whence); +int CDVDFS_read( int fd, char * buffer, int size ); +int CDVDFS_write( int fd, char * buffer, int size ); +int CDVDFS_close( int fd); + +#endif//__CDVDISODRV_H__ diff --git a/plugins/cdvd/CDVDpeops/CDVDlib.h b/plugins/cdvd/CDVDpeops/CDVDlib.h new file mode 100644 index 0000000000..f2c2f87fb8 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CDVDlib.h @@ -0,0 +1,189 @@ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Linux kernel headers + * Modified by Florin for PCSX2 emu + */ + +#ifndef _CDVDLIB_H +#define _CDVDLIB_H + +#define __WIN32__ +#define __MSCW32__ +#define CDVDdefs +#include "PS2Etypes.h" +#include "PS2Edefs.h" + +// Macros for READ Data pattan +#define CdSecS2048 0 // sector size 2048 +#define CdSecS2328 1 // sector size 2328 +#define CdSecS2340 2 // sector size 2340 + +//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ +//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ + +/* + * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, + * 2340, or 2352 bytes long. + * Sector types of the standard CD-ROM data formats: + * + * format sector type user data size (bytes) + * ----------------------------------------------------------------------------- + * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) + * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) + * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) + * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) + * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) + * + * + * The layout of the standard CD-ROM data formats: + * ----------------------------------------------------------------------------- + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | + * | 12 - 4 - 8 - 2324 - 4 | + * + */ + +// Macros for Spindle control +#define CdSpinMax 0 +#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. +#define CdSpinStm 0 // Recommended stream rotation speed. + +// Macros for TrayReq +#define CdTrayOpen 0 +#define CdTrayClose 1 +#define CdTrayCheck 2 + +/* + * Macros for sceCdGetDiskType() //comments translated from japanese;) + */ +#define SCECdIllgalMedia 0xff + /* ILIMEDIA (Illegal Media) + A non-PS / non-PS2 Disc. */ +#define SCECdDVDV 0xfe + /* DVDV (DVD Video) + A non-PS / non-PS2 Disc, but a DVD Video Disc */ +#define SCECdCDDA 0xfd + /* CDDA (CD DA) + A non-PS / non-PS2 Disc that include a DA track */ +#define SCECdPS2DVD 0x14 + /* PS2DVD PS2 consumer DVD. */ +#define SCECdPS2CDDA 0x13 + /* PS2CDDA PS2 consumer CD that includes a DA track */ +#define SCECdPS2CD 0x12 + /* PS2CD PS2 consumer CD that does not include a DA track */ +#define SCECdPSCDDA 0x11 + /* PSCDDA PS CD that includes a DA track */ +#define SCECdPSCD 0x10 + /* PSCD PS CD that does not include a DA track */ +#define SCECdDETCT 0x01 + /* DETCT (Detecting) Disc distinction action */ +#define SCECdNODISC 0x00 + /* NODISC (No disc) No disc entered */ + +/* + * Media mode + */ +#define SCECdCD 1 +#define SCECdDVD 2 + +typedef struct { + u8 stat; // 0: normal. Any other: error + u8 second; // second (BCD value) + u8 minute; // minute (BCD value) + u8 hour; // hour (BCD value) + u8 week; // week (BCD value) + u8 day; // day (BCD value) + u8 month; // month (BCD value) + u8 year; // year (BCD value) +} CdCLOCK; + +typedef struct { + u32 lsn; // Logical sector number of file + u32 size; // File size (in bytes) + char name[16]; // Filename + u8 date[8]; // 1th: Seconds + // 2th: Minutes + // 3th: Hours + // 4th: Date + // 5th: Month + // 6th 7th: Year (4 digits) +} CdlFILE; + +typedef struct { + u8 minute; // Minutes + u8 second; // Seconds + u8 sector; // Sector + u8 track; // Track number +} CdlLOCCD; + +typedef struct { + u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) + u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. + // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. + u8 datapattern; // SCECdSecS2048: Data size 2048 bytes + // SCECdSecS2328: 2328 bytes + // SCECdSecS2340: 2340 bytes + u8 pad; // Padding data produced by alignment. +} CdRMode; + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct TocEntry +{ + u32 fileLBA; + u32 fileSize; + u8 fileProperties; + u8 padding1[3]; + u8 filename[128+1]; + u8 date[7]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +#if defined(__WIN32__) +#pragma pack() +#endif + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +/* +int CdBreak(void); +int CdCallback( void (*func)() ); +int CdDiskReady(int mode); +int CdGetDiskType(void); +int CdGetError(void); +u32 CdGetReadPos(void); +int CdGetToc(u8 *toc); +int CdInit(int init_mode); +CdlLOCCD *CdIntToPos(int i, CdlLOCCD *p); +int CdPause(void); +int CdPosToInt(CdlLOCCD *p);*/ +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +/*int CdReadClock(CdCLOCK *rtc); +int CdSearchFile (CdlFILE *fp, const char *name); +int CdSeek(u32 lsn); +int CdStandby(void); +int CdStatus(void); +int CdStop(void); +int CdSync(int mode); +int CdTrayReq(int mode, u32 *traycnt); +*/ +#endif // _CDVDLIB_H diff --git a/plugins/cdvd/CDVDpeops/CLEAN.BAT b/plugins/cdvd/CDVDpeops/CLEAN.BAT new file mode 100644 index 0000000000..cbeb91c994 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CLEAN.BAT @@ -0,0 +1,3 @@ +del *.o +del *.c~ +del *.h~ \ No newline at end of file diff --git a/plugins/cdvd/CDVDpeops/Cdr.c b/plugins/cdvd/CDVDpeops/Cdr.c new file mode 100644 index 0000000000..fd38b659de --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Cdr.c @@ -0,0 +1,935 @@ +/*************************************************************************** + cdr.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - added an hack in CDVDgetTD for big dvds +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops cdvd release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#include +#include "resource.h" +#define _IN_CDR +#include "externals.h" +#define CDVDdefs +#include "PS2Etypes.h" +#include "PS2Edefs.h" +#include "libiso.h" + +#ifdef DBGOUT +#define SMALLDEBUG 1 +#include +#endif + +///////////////////////////////////////////////////////// +// PCSX2 CDVD interface: + +EXPORT_GCC char * CALLBACK PS2EgetLibName(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type); +EXPORT_GCC long CALLBACK CDVDinit(); +EXPORT_GCC void CALLBACK CDVDshutdown(); +EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle); +EXPORT_GCC void CALLBACK CDVDclose(); +EXPORT_GCC long CALLBACK CDVDtest(); +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode); +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer(); +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer); +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer); +EXPORT_GCC long CALLBACK CDVDgetDiskType(); +EXPORT_GCC long CALLBACK CDVDgetTrayStatus(); + +///////////////////////////////////////////////////////// + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 1; +const unsigned char build = 3; + +#ifdef _DEBUG +char *libraryName = "P.E.Op.S. CDVD (Debug, CDDA mod)"; +#else +char *libraryName = "P.E.Op.S. CDVD (CDDA mod)"; +#endif + +///////////////////////////////////////////////////////// + +BOOL bIsOpen=FALSE; // flag: open called once +BOOL bCDDAPlay=FALSE; // flag: audio is playing +int iCDROK=0; // !=0: cd is ok +int iCDType=CDVD_TYPE_UNKNOWN; // CD/DVD +int iCheckTrayStatus=0; // if 0 : report tray as closed, else try a real check +void *fdump; + +///////////////////////////////////////////////////////// +// usual info funcs + +EXPORT_GCC char * CALLBACK PS2EgetLibName() +{ + return libraryName; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType() +{ + return PS2E_LT_CDVD; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + return version<<16|revision<<8|build; +} +/* +EXPORT_GCC unsigned long CALLBACK PS2EgetCpuPlatform(void) +{ + return PS2E_X86; +// return PS2E_X86_64; +}*/ + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = (u8)(lba / (60*75)); + *s = (u8)((lba / 75) % 60); + *f = (u8)(lba % 75); +} + +///////////////////////////////////////////////////////// +// init: called once at library load + +EXPORT_GCC long CALLBACK CDVDinit() +{ + szSUBF[0]=0; // just init the filename buffers + szPPF[0] =0; + return 0; +} + +///////////////////////////////////////////////////////// +// shutdown: called once at final exit + +EXPORT_GCC void CALLBACK CDVDshutdown() +{ +} + +///////////////////////////////////////////////////////// +// open: called, when games starts/cd has been changed + +int CheckDiskType(int baseType); + +EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle) +{ + int i,audioTracks,dataTracks; + cdvdTD T; + if(bIsOpen) // double-open check (if the main emu coder doesn't know what he is doing ;) + { + if(iCDROK<=0) return -1; + else return 0; + } + + bIsOpen=TRUE; // ok, open func called once + + ReadConfig(); // read user config + + BuildPPFCache(); // build ppf cache + + BuildSUBCache(); // build sub cache + + CreateREADBufs(); // setup generic read buffers + + CreateGenEvent(); // create read event + + iCDROK=OpenGenCD(iCD_AD,iCD_TA,iCD_LU); // generic open, setup read func + + if(iCDROK<=0) {iCDROK=0;return -1;} + + ReadTOC(); // read the toc + + SetGenCDSpeed(0); // try to change the reading speed (if wanted) + + iCDType=CDVD_TYPE_UNKNOWN; // let's look after the disc type + // (funny stuff taken from Xobro's/Florin's bin plugin) + if(CDVDreadTrack(16,CDVD_MODE_2048)==0) + { + struct cdVolDesc *volDesc; + volDesc=(struct cdVolDesc *)CDVDgetBuffer(); + if(volDesc) + { + +//todo: CDVD_TYPE_CDDA + + if(volDesc->rootToc.tocSize==2048) + iCDType = CDVD_TYPE_DETCTCD; + else iCDType = CDVD_TYPE_DETCTDVDS; + } + } + + fprintf(stderr," * CDVD Disk Open: %d tracks (%d to %d):\n",sTOC.cLastTrack-sTOC.cFirstTrack+1,sTOC.cFirstTrack,sTOC.cLastTrack); + + audioTracks=dataTracks=0; + for(i=sTOC.cFirstTrack;i<=sTOC.cLastTrack;i++) + { + CDVDgetTD(i,&T); + if(T.type==CDVD_AUDIO_TRACK) { + audioTracks++; + fprintf(stderr," * * Track %d: Audio (%d sectors)\n",i,T.lsn); + } + else { + dataTracks++; + fprintf(stderr," * * Track %d: Data (Mode %d) (%d sectors)\n",i,((T.type==CDVD_MODE1_TRACK)?1:2),T.lsn); + } + } + if((dataTracks==0)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if(dataTracks>0) + iCDType=CheckDiskType(iCDType); + + if((iCDType==CDVD_TYPE_ILLEGAL)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if((iCDType==CDVD_TYPE_PS2CD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PS2CDDA; + else if((iCDType==CDVD_TYPE_PSCD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PSCDDA; + + switch(iCDType) { + case CDVD_TYPE_ILLEGAL: // Illegal Disc + fprintf(stderr," * Disk Type: Illegal Disk.\n");break; + case CDVD_TYPE_DVDV: // DVD Video + fprintf(stderr," * Disk Type: DVD Video.\n");break; + case CDVD_TYPE_CDDA: // Audio CD + fprintf(stderr," * Disk Type: CDDA.\n");break; + case CDVD_TYPE_PS2DVD: // PS2 DVD + fprintf(stderr," * Disk Type: PS2 DVD.\n");break; + case CDVD_TYPE_PS2CDDA: // PS2 CD (with audio) + fprintf(stderr," * Disk Type: PS2 CD+Audio.\n");break; + case CDVD_TYPE_PS2CD: // PS2 CD + fprintf(stderr," * Disk Type: PS2 CD.\n");break; + case CDVD_TYPE_PSCDDA: // PS CD (with audio) + fprintf(stderr," * Disk Type: PS1 CD+Audio.\n");break; + case CDVD_TYPE_PSCD: // PS CD + fprintf(stderr," * Disk Type: PS1 CD.\n");break; + case CDVD_TYPE_UNKNOWN: // Unknown + fprintf(stderr," * Disk Type: Unknown.\n");break; + case CDVD_TYPE_NODISC: // No Disc + fprintf(stderr," * Disk Type: No Disc.\n");break; + } + +/* if (iBlockDump)*/ { +// fdump = isoCreate("block.dump", ISOFLAGS_BLOCKDUMP); + fdump = NULL; + if (fdump) { + cdvdTD buf; + CDVDgetTD(0, &buf); + isoSetFormat(fdump, 0, 2352, buf.lsn); + } + } /*else { + fdump = NULL; + }*/ + + + return 0; // ok, done +} + +///////////////////////////////////////////////////////// +// close: called when emulation stops + +EXPORT_GCC void CALLBACK CDVDclose() +{ + if(!bIsOpen) return; // no open? no close... + + if (fdump != NULL) { + isoClose(fdump); + } + bIsOpen=FALSE; // no more open + + LockGenCDAccess(); // make sure that no more reading is happening + + if(iCDROK) // cd was ok? + { + if(bCDDAPlay) {DoCDDAPlay(0);bCDDAPlay=FALSE;} // -> cdda playing? stop it + SetGenCDSpeed(1); // -> repair speed + CloseGenCD(); // -> cd not used anymore + } + + UnlockGenCDAccess(); + + FreeREADBufs(); // free read bufs + FreeGenEvent(); // free event + FreePPFCache(); // free ppf cache + FreeSUBCache(); // free sub cache +} + +///////////////////////////////////////////////////////// +// test: ah, well, always fine + +EXPORT_GCC long CALLBACK CDVDtest() +{ + return 0; +} + +///////////////////////////////////////////////////////// +// readSubQ: read subq from disc (only cds have subq data) +EXPORT_GCC long CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) +{ + u8 min, sec, frm; + + if(!bIsOpen) CDVDopen("DVD"); // usual checks + if(!iCDROK) return -1; + + // fake it + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +///////////////////////////////////////////////////////// +// gettoc: ps2 style TOC +static int layer1start = -1; +EXPORT_GCC long CALLBACK CDVDgetTOC(void* toc) +{ + u32 type; + u8* tocBuff = (u8*)toc; + + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? + + type = CDVDgetDiskType(); + + if( type == CDVD_TYPE_DVDV || + type == CDVD_TYPE_PS2DVD) + { + u32 lastaddr; + + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + + lastaddr = GetLastTrack1Addr(); + if(layer1start > 0 || (layer1start != -2 && lastaddr > 0x280000) ) { + int off = 0; + FRAMEBUF* f = (FRAMEBUF*)malloc(sizeof(FRAMEBUF)); + + f->dwBufLen = iUsedBlockSize; + f->dwFrameCnt = 1; + + + // dual sided + tocBuff[ 0] = 0x24; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x41; + tocBuff[ 5] = 0x95; + + tocBuff[14] = 0x60; // dual sided, ptp + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + + if( layer1start == -1 ) { + // search for it + printf("PeopsCDVD: searching for layer1... "); + for(layer1start = (lastaddr/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) { + f->dwFrame = layer1start; + if( pReadFunc(TRUE,f) != SS_COMP ) { + layer1start = 0x200010; + break; + } + // CD001 + if( f->BufData[off+1] == 0x43 && f->BufData[off+2] == 0x44 && f->BufData[off+3] == 0x30 && f->BufData[off+4] == 0x30 && f->BufData[off+5] == 0x31 ) { + break; + } + } + + if( layer1start >= 0x200010 ) { + printf("Couldn't find second layer on dual layer... ignoring\n"); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + layer1start = -2; + return 0; + } + + printf("found at 0x%8.8x\n", layer1start); + layer1start = layer1start+0x30000-1; + } + + tocBuff[20] = layer1start>>24; + tocBuff[21] = (layer1start>>16)&0xff; + tocBuff[22] = (layer1start>>8)&0xff; + tocBuff[23] = (layer1start>>0)&0xff; + + free(f); + } + else { + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm,i; + s32 err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + tocBuff[29] = itob(frm); + + fprintf(stderr,"Track 0: %d mins %d secs %d frames\n",min,sec,frm); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + fprintf(stderr,"Track %d: %d mins %d secs %d frames\n",i,min,sec,frm); + } + } + else + return -1; + + return 0; +} + +///////////////////////////////////////////////////////// +// gettn: first/last track num + +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer) +{ + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) // cd not ok? + { + Buffer->strack=1; + Buffer->etrack=1; + return -1; + } + + ReadTOC(); // read the TOC + + Buffer->strack=sTOC.cFirstTrack; // get the infos + Buffer->etrack=sTOC.cLastTrack; + + return 0; +} + +///////////////////////////////////////////////////////// +// gettd: track addr + +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer) +{ + unsigned long lu,i; + unsigned char buffer[2352]; + unsigned char *buf; + u8 t1; + + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? bye + + ReadTOC(); // read toc + +/* +// PSEmu style: + if(track==0) // 0 = last track + { + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + addr2time(lu,buffer); + } + else // others: track n + { + lu=reOrder(sTOC.tracks[track-1].lAddr); + addr2time(lu,buffer); + } + + Buffer->minute = buffer[1]; + Buffer->second = buffer[2]; + Buffer->frame = buffer[3]; + Buffer->type = iCDType; +#ifdef DBGOUT + auxprintf("Read Toc %d: %u\n",track,lu); +#endif +*/ + + lu=0; + if(track==0) + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + else + lu=reOrder(sTOC.tracks[track].lAddr); + //addr2time(lu,buffer); + + Buffer->lsn=lu; + + if(track==0) + Buffer->type = iCDType; + else + { + lu=0; + for(i=sTOC.cFirstTrack;itype=t1; + } + + return 0; +} + +///////////////////////////////////////////////////////// +// readtrack: start reading at given address + +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode) +{ + if(!bIsOpen) CDVDopen("DVD"); // usual checks + if(!iCDROK) return -1; + if(bCDDAPlay) bCDDAPlay=FALSE; + +#ifdef DBGOUT + auxprintf("Read Track %u: %d\n",lsn,mode); +#endif + + lLastAccessedAddr=lsn; // store read track values (for getbuffer) + iLastAccessedMode=mode; + + if(!pReadTrackFunc(lLastAccessedAddr)) // start reading + return -1; + + return 0; +} + +///////////////////////////////////////////////////////// +// getbuffer: will be called after readtrack, to get ptr +// to data + +// small helper buffer to get bigger block sizes +unsigned char cDataAndSub[2368]; + +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer() +{ + unsigned char * pbuffer; + + if(!bIsOpen) CDVDopen("DVD"); + + if(pGetPtrFunc) pGetPtrFunc(); // get ptr on thread modes + + pbuffer=pCurrReadBuf; // init buffer pointer + if (fdump != NULL) { + isoWriteBlock(fdump, pbuffer, lLastAccessedAddr); + } + + if(iLastAccessedMode!=iUsedMode) + { + switch(iLastAccessedMode) // what does the emu want? + {//------------------------------------------------// + case CDVD_MODE_2048: + { + if(iUsedBlockSize==2352) pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2352: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + } + }break; + //------------------------------------------------// + case CDVD_MODE_2340: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+12,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=12; + }break; + //------------------------------------------------// + case CDVD_MODE_2328: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+0,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2368: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + +/* +// NO SUBCHANNEL SUPPORT RIGHT NOW!!! + { + if(subHead) // some sub file? + CheckSUBCache(lLastAccessedAddr); // -> get cached subs + else + if(iUseSubReading!=1 && pCurrSubBuf) // no direct cd sub read? + FakeSubData(lLastAccessedAddr); // -> fake the data + memcpy(cDataAndSub,pCurrReadBuf,2352); + if(pCurrSubBuf) + memcpy(cDataAndSub+2352,pCurrSubBuf+12,16); + pbuffer=cDataAndSub; + } +*/ + + } + }break; + //------------------------------------------------// + } + } + +#ifdef DBGOUT + auxprintf("get buf %d\n",iLastAccessedMode); + +/* +{ + int k; + for(k=0;k<2352;k++) + auxprintf("%02x ",*(pbuffer+k)); + auxprintf("\n\n"); +} +*/ +#endif + + return pbuffer; +} + +///////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK CDVDgetDiskType() +{ + return iCDType; +} + +///////////////////////////////////////////////////////// +// CDVDgetTrayStatus + +EXPORT_GCC long CALLBACK CDVDgetTrayStatus() +{ + static time_t to=0; + static long lLastTrayState=CDVD_TRAY_CLOSE; + + if(to==time(NULL)) return lLastTrayState; // we only check once per second + to = time(NULL); + + lLastTrayState=CDVD_TRAY_CLOSE; // init state with "closed" + + if(iCheckTrayStatus) // user really want a tray check + { + int iStatus; + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + lLastTrayState=CDVD_TRAY_OPEN; + } + +#ifdef DBGOUT +auxprintf("check %d -> %d\n",to,lLastTrayState); +#endif + + + return lLastTrayState; +} + +EXPORT_GCC s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} + +EXPORT_GCC s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + + + +///////////////////////////////////////////////////////// +// configure: shows config window + +EXPORT_GCC void CALLBACK CDVDconfigure() +{ + if(iCDROK) // mmm... someone has already called Open? bad + {MessageBeep((UINT)-1);return;} + + CreateGenEvent(); // we need an event handle + + DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIG), // call dialog + GetActiveWindow(),(DLGPROC)CDRDlgProc); + + FreeGenEvent(); // free event handle +} + +///////////////////////////////////////////////////////// +// about: shows about window + +EXPORT_GCC void CALLBACK CDVDabout() +{ + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +/* +// CURRENTLY UNUSED OLD STUFF FROM PSX CD PLUGIN: + +///////////////////////////////////////////////////////// +// audioplay: PLAYSECTOR is NOT BCD coded !!! + +EXPORT_GCC long CALLBACK CDRplay(unsigned char * sector) +{ + if(!bIsOpen) CDVDopen(); + if(!iCDROK) return PSE_ERR_FATAL; + + if(!DoCDDAPlay(time2addr(sector))) // start playing + return PSE_CDR_ERR_NOREAD; + + bCDDAPlay=TRUE; // raise flag: we are playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// audiostop: stops cdda playing + +EXPORT_GCC long CALLBACK CDRstop(void) +{ + if(!bCDDAPlay) return PSE_ERR_FATAL; + + DoCDDAPlay(0); // stop cdda + + bCDDAPlay=FALSE; // reset flag: no more playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// getdriveletter + +EXPORT_GCC char CALLBACK CDRgetDriveLetter(void) +{ + if(!iCDROK) return 0; // not open? no way to get the letter + + if(iInterfaceMode==2 || iInterfaceMode==3) // w2k/xp: easy + { + return MapIOCTLDriveLetter(iCD_AD,iCD_TA,iCD_LU); + } + else // but with aspi??? + { // -> no idea yet (maybe registry read...pfff) + } + + return 0; +} + +///////////////////////////////////////////////////////// +// getstatus: pcsx func... poorly supported here +// problem is: func will be called often, which +// would block all of my cdr reading if I would use +// lotsa scsi commands + +struct CdrStat +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time +}; + +struct CdrStat ostat; + +// reads cdr status +// type: +// 0x00 - unknown +// 0x01 - data +// 0x02 - audio +// 0xff - no cdrom +// status: +// 0x00 - unknown +// 0x02 - error +// 0x08 - seek error +// 0x10 - shell open +// 0x20 - reading +// 0x40 - seeking +// 0x80 - playing +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame + + +EXPORT_GCC long CALLBACK CDRgetStatus(struct CdrStat *stat) +{ + int iStatus; + static time_t to; + + if(!bCDDAPlay) // if not playing update stat only once in a second + { + if(to get pos + stat->Type = 0x02; // -> audio + if(pB) + { + stat->Status|=0x80; // --> playing flag + stat->Time[0]=pB[18]; // --> and curr play time + stat->Time[1]=pB[19]; + stat->Time[2]=pB[20]; + } + } + else // cdda not playing? + { + stat->Type = 0x01; // -> data + } + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + { // no cdrom? + stat->Type = 0xff; + stat->Status|= 0x10; + } + + memcpy(&ostat, stat, sizeof(struct CdrStat)); + + return 0; +} + +///////////////////////////////////////////////////////// +*/ diff --git a/plugins/cdvd/CDVDpeops/Cdr.c.bak b/plugins/cdvd/CDVDpeops/Cdr.c.bak new file mode 100644 index 0000000000..7a6100ebe5 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Cdr.c.bak @@ -0,0 +1,848 @@ +/*************************************************************************** + cdr.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - added an hack in CDVDgetTD for big dvds +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops cdvd release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#include +#include "resource.h" +#define _IN_CDR +#include "externals.h" +#include "libiso.h" + +#ifdef DBGOUT +#define SMALLDEBUG 1 +#include +#endif + +///////////////////////////////////////////////////////// +// PCSX2 CDVD interface: + +EXPORT_GCC char * CALLBACK PS2EgetLibName(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type); +EXPORT_GCC long CALLBACK CDVDinit(); +EXPORT_GCC void CALLBACK CDVDshutdown(); +EXPORT_GCC long CALLBACK CDVDopen(); +EXPORT_GCC void CALLBACK CDVDclose(); +EXPORT_GCC long CALLBACK CDVDtest(); +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode); +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer(); +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer); +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer); +EXPORT_GCC long CALLBACK CDVDgetDiskType(); +EXPORT_GCC long CALLBACK CDVDgetTrayStatus(); + +///////////////////////////////////////////////////////// + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 1; +const unsigned char build = 2; +char *libraryName = "P.E.Op.S. CDVD Driver (CDDA mod)"; + +///////////////////////////////////////////////////////// + +BOOL bIsOpen=FALSE; // flag: open called once +BOOL bCDDAPlay=FALSE; // flag: audio is playing +int iCDROK=0; // !=0: cd is ok +int iCDType=CDVD_TYPE_UNKNOWN; // CD/DVD +int iCheckTrayStatus=0; // if 0 : report tray as closed, else try a real check +void *fdump; + +///////////////////////////////////////////////////////// +// usual info funcs + +EXPORT_GCC char * CALLBACK PS2EgetLibName() +{ + return libraryName; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType() +{ + return PS2E_LT_CDVD; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + return version<<16|revision<<8|build; +} +/* +EXPORT_GCC unsigned long CALLBACK PS2EgetCpuPlatform(void) +{ + return PS2E_X86; +// return PS2E_X86_64; +}*/ + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = lba / (60*75); + *s = (lba / 75) % 60; + *f = lba % 75; +} + +///////////////////////////////////////////////////////// +// init: called once at library load + +EXPORT_GCC long CALLBACK CDVDinit() +{ + szSUBF[0]=0; // just init the filename buffers + szPPF[0] =0; + return 0; +} + +///////////////////////////////////////////////////////// +// shutdown: called once at final exit + +EXPORT_GCC void CALLBACK CDVDshutdown() +{ +} + +///////////////////////////////////////////////////////// +// open: called, when games starts/cd has been changed + +int CheckDiskType(int baseType); + +EXPORT_GCC long CALLBACK CDVDopen() +{ + int i,audioTracks,dataTracks; + cdvdTD T; + if(bIsOpen) // double-open check (if the main emu coder doesn't know what he is doing ;) + { + if(iCDROK<=0) return -1; + else return 0; + } + + bIsOpen=TRUE; // ok, open func called once + + ReadConfig(); // read user config + + BuildPPFCache(); // build ppf cache + + BuildSUBCache(); // build sub cache + + CreateREADBufs(); // setup generic read buffers + + CreateGenEvent(); // create read event + + iCDROK=OpenGenCD(iCD_AD,iCD_TA,iCD_LU); // generic open, setup read func + + if(iCDROK<=0) {iCDROK=0;return -1;} + + ReadTOC(); // read the toc + + SetGenCDSpeed(0); // try to change the reading speed (if wanted) + + iCDType=CDVD_TYPE_UNKNOWN; // let's look after the disc type + // (funny stuff taken from Xobro's/Florin's bin plugin) + if(CDVDreadTrack(16,CDVD_MODE_2048)==0) + { + struct cdVolDesc *volDesc; + volDesc=(struct cdVolDesc *)CDVDgetBuffer(); + if(volDesc) + { + +//todo: CDVD_TYPE_CDDA + + if(volDesc->rootToc.tocSize==2048) + iCDType = CDVD_TYPE_DETCTCD; + else iCDType = CDVD_TYPE_DETCTDVDS; + } + } + + fprintf(stderr," * CDVD Disk Open: %d tracks (%d to %d):\n",sTOC.cLastTrack-sTOC.cFirstTrack+1,sTOC.cFirstTrack,sTOC.cLastTrack); + + audioTracks=dataTracks=0; + for(i=sTOC.cFirstTrack;i<=sTOC.cLastTrack;i++) + { + CDVDgetTD(i,&T); + if(T.type==CDVD_AUDIO_TRACK) { + audioTracks++; + fprintf(stderr," * * Track %d: Audio (%d sectors)\n",i,T.lsn); + } + else { + dataTracks++; + fprintf(stderr," * * Track %d: Data (Mode %d) (%d sectors)\n",i,((T.type==CDVD_MODE1_TRACK)?1:2),T.lsn); + } + } + if((dataTracks==0)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if(dataTracks>0) + iCDType=CheckDiskType(iCDType); + + if((iCDType==CDVD_TYPE_ILLEGAL)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if((iCDType==CDVD_TYPE_PS2CD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PS2CDDA; + else if((iCDType==CDVD_TYPE_PSCD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PSCDDA; + + switch(iCDType) { + case CDVD_TYPE_ILLEGAL: // Illegal Disc + fprintf(stderr," * Disk Type: Illegal Disk.\n");break; + case CDVD_TYPE_DVDV: // DVD Video + fprintf(stderr," * Disk Type: DVD Video.\n");break; + case CDVD_TYPE_CDDA: // Audio CD + fprintf(stderr," * Disk Type: CDDA.\n");break; + case CDVD_TYPE_PS2DVD: // PS2 DVD + fprintf(stderr," * Disk Type: PS2 DVD.\n");break; + case CDVD_TYPE_PS2CDDA: // PS2 CD (with audio) + fprintf(stderr," * Disk Type: PS2 CD+Audio.\n");break; + case CDVD_TYPE_PS2CD: // PS2 CD + fprintf(stderr," * Disk Type: PS2 CD.\n");break; + case CDVD_TYPE_PSCDDA: // PS CD (with audio) + fprintf(stderr," * Disk Type: PS1 CD+Audio.\n");break; + case CDVD_TYPE_PSCD: // PS CD + fprintf(stderr," * Disk Type: PS1 CD.\n");break; + case CDVD_TYPE_UNKNOWN: // Unknown + fprintf(stderr," * Disk Type: Unknown.\n");break; + case CDVD_TYPE_NODISC: // No Disc + fprintf(stderr," * Disk Type: No Disc.\n");break; + } + +/* if (iBlockDump)*/ { +// fdump = isoCreate("block.dump", ISOFLAGS_BLOCKDUMP); + fdump = NULL; + if (fdump) { + cdvdTD buf; + CDVDgetTD(0, &buf); + isoSetFormat(fdump, 0, 2352, buf.lsn); + } + } /*else { + fdump = NULL; + }*/ + + + return 0; // ok, done +} + +///////////////////////////////////////////////////////// +// close: called when emulation stops + +EXPORT_GCC void CALLBACK CDVDclose() +{ + if(!bIsOpen) return; // no open? no close... + + if (fdump != NULL) { + isoClose(fdump); + } + bIsOpen=FALSE; // no more open + + LockGenCDAccess(); // make sure that no more reading is happening + + if(iCDROK) // cd was ok? + { + if(bCDDAPlay) {DoCDDAPlay(0);bCDDAPlay=FALSE;} // -> cdda playing? stop it + SetGenCDSpeed(1); // -> repair speed + CloseGenCD(); // -> cd not used anymore + } + + UnlockGenCDAccess(); + + FreeREADBufs(); // free read bufs + FreeGenEvent(); // free event + FreePPFCache(); // free ppf cache + FreeSUBCache(); // free sub cache +} + +///////////////////////////////////////////////////////// +// test: ah, well, always fine + +EXPORT_GCC long CALLBACK CDVDtest() +{ + return 0; +} + +///////////////////////////////////////////////////////// +// readSubQ: read subq from disc (only cds have subq data) +EXPORT_GCC long CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) +{ + if(!bIsOpen) CDVDopen(); // usual checks + if(!iCDROK) return -1; + + // fake it + u8 min, sec, frm; + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +///////////////////////////////////////////////////////// +// gettoc: ps2 style TOC +EXPORT_GCC long CALLBACK CDVDgetTOC(void* toc) +{ + u32 type; + u8* tocBuff = (u8*)toc; + + if(!bIsOpen) CDVDopen(); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? + + type = CDVDgetDiskType(); + + if( type == CDVD_TYPE_DVDV || + type == CDVD_TYPE_PS2DVD) + { + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm,i; + s32 err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + tocBuff[29] = itob(frm); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +EXPORT_GCC long CALLBACK CDVDctrlTrayOpen() +{ + return 0; +} + +EXPORT_GCC long CALLBACK CDVDctrlTrayClose() +{ + return 0; +} + + +///////////////////////////////////////////////////////// +// gettn: first/last track num + +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer) +{ + if(!bIsOpen) CDVDopen(); // not open? funny emu... + + if(!iCDROK) // cd not ok? + { + Buffer->strack=1; + Buffer->etrack=1; + return -1; + } + + ReadTOC(); // read the TOC + + Buffer->strack=sTOC.cFirstTrack; // get the infos + Buffer->etrack=sTOC.cLastTrack; + + return 0; +} + +///////////////////////////////////////////////////////// +// gettd: track addr + +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer) +{ + unsigned long lu,i; + unsigned char buffer[2352]; + unsigned char *buf; + u8 t1; + + if(!bIsOpen) CDVDopen(); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? bye + + ReadTOC(); // read toc + +/* +// PSEmu style: + if(track==0) // 0 = last track + { + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + addr2time(lu,buffer); + } + else // others: track n + { + lu=reOrder(sTOC.tracks[track-1].lAddr); + addr2time(lu,buffer); + } + + Buffer->minute = buffer[1]; + Buffer->second = buffer[2]; + Buffer->frame = buffer[3]; + Buffer->type = iCDType; +#ifdef DBGOUT + auxprintf("Read Toc %d: %u\n",track,lu); +#endif +*/ + + lu=0; + if(track==0) + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + else + lu=reOrder(sTOC.tracks[track].lAddr); + //addr2time(lu,buffer); + + Buffer->lsn=lu; + + if(track==0) + Buffer->type = iCDType; + else + { + lu=0; + for(i=sTOC.cFirstTrack;itype=t1; + } + + return 0; +} + +///////////////////////////////////////////////////////// +// readtrack: start reading at given address + +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode) +{ + if(!bIsOpen) CDVDopen(); // usual checks + if(!iCDROK) return -1; + if(bCDDAPlay) bCDDAPlay=FALSE; + +#ifdef DBGOUT + auxprintf("Read Track %u: %d\n",lsn,mode); +#endif + + lLastAccessedAddr=lsn; // store read track values (for getbuffer) + iLastAccessedMode=mode; + + if(!pReadTrackFunc(lLastAccessedAddr)) // start reading + return -1; + + return 0; +} + +///////////////////////////////////////////////////////// +// getbuffer: will be called after readtrack, to get ptr +// to data + +// small helper buffer to get bigger block sizes +unsigned char cDataAndSub[2368]; + +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer() +{ + unsigned char * pbuffer; + + if(!bIsOpen) CDVDopen(); + + if(pGetPtrFunc) pGetPtrFunc(); // get ptr on thread modes + + pbuffer=pCurrReadBuf; // init buffer pointer + + if(iLastAccessedMode!=iUsedMode) + { + switch(iLastAccessedMode) // what does the emu want? + {//------------------------------------------------// + case CDVD_MODE_2048: + { + if(iUsedBlockSize==2352) pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2352: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + } + }break; + //------------------------------------------------// + case CDVD_MODE_2340: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+12,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=12; + }break; + //------------------------------------------------// + case CDVD_MODE_2328: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+0,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2368: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + +/* +// NO SUBCHANNEL SUPPORT RIGHT NOW!!! + { + if(subHead) // some sub file? + CheckSUBCache(lLastAccessedAddr); // -> get cached subs + else + if(iUseSubReading!=1 && pCurrSubBuf) // no direct cd sub read? + FakeSubData(lLastAccessedAddr); // -> fake the data + memcpy(cDataAndSub,pCurrReadBuf,2352); + if(pCurrSubBuf) + memcpy(cDataAndSub+2352,pCurrSubBuf+12,16); + pbuffer=cDataAndSub; + } +*/ + + } + }break; + //------------------------------------------------// + } + } + +#ifdef DBGOUT + auxprintf("get buf %d\n",iLastAccessedMode); + +/* +{ + int k; + for(k=0;k<2352;k++) + auxprintf("%02x ",*(pbuffer+k)); + auxprintf("\n\n"); +} +*/ +#endif + + return pbuffer; +} + +///////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK CDVDgetDiskType() +{ + return iCDType; +} + +///////////////////////////////////////////////////////// +// CDVDgetTrayStatus + +EXPORT_GCC long CALLBACK CDVDgetTrayStatus() +{ + static time_t to=0; + static long lLastTrayState=CDVD_TRAY_CLOSE; + + if(to==time(NULL)) return lLastTrayState; // we only check once per second + to = time(NULL); + + lLastTrayState=CDVD_TRAY_CLOSE; // init state with "closed" + + if(iCheckTrayStatus) // user really want a tray check + { + int iStatus; + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + lLastTrayState=CDVD_TRAY_OPEN; + } + +#ifdef DBGOUT +auxprintf("check %d -> %d\n",to,lLastTrayState); +#endif + + + return lLastTrayState; +} + + +///////////////////////////////////////////////////////// +// configure: shows config window + +EXPORT_GCC void CALLBACK CDVDconfigure() +{ + if(iCDROK) // mmm... someone has already called Open? bad + {MessageBeep((UINT)-1);return;} + + CreateGenEvent(); // we need an event handle + + DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIG), // call dialog + GetActiveWindow(),(DLGPROC)CDRDlgProc); + + FreeGenEvent(); // free event handle +} + +///////////////////////////////////////////////////////// +// about: shows about window + +EXPORT_GCC void CALLBACK CDVDabout() +{ + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +/* +// CURRENTLY UNUSED OLD STUFF FROM PSX CD PLUGIN: + +///////////////////////////////////////////////////////// +// audioplay: PLAYSECTOR is NOT BCD coded !!! + +EXPORT_GCC long CALLBACK CDRplay(unsigned char * sector) +{ + if(!bIsOpen) CDVDopen(); + if(!iCDROK) return PSE_ERR_FATAL; + + if(!DoCDDAPlay(time2addr(sector))) // start playing + return PSE_CDR_ERR_NOREAD; + + bCDDAPlay=TRUE; // raise flag: we are playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// audiostop: stops cdda playing + +EXPORT_GCC long CALLBACK CDRstop(void) +{ + if(!bCDDAPlay) return PSE_ERR_FATAL; + + DoCDDAPlay(0); // stop cdda + + bCDDAPlay=FALSE; // reset flag: no more playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// getdriveletter + +EXPORT_GCC char CALLBACK CDRgetDriveLetter(void) +{ + if(!iCDROK) return 0; // not open? no way to get the letter + + if(iInterfaceMode==2 || iInterfaceMode==3) // w2k/xp: easy + { + return MapIOCTLDriveLetter(iCD_AD,iCD_TA,iCD_LU); + } + else // but with aspi??? + { // -> no idea yet (maybe registry read...pfff) + } + + return 0; +} + +///////////////////////////////////////////////////////// +// getstatus: pcsx func... poorly supported here +// problem is: func will be called often, which +// would block all of my cdr reading if I would use +// lotsa scsi commands + +struct CdrStat +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time +}; + +struct CdrStat ostat; + +// reads cdr status +// type: +// 0x00 - unknown +// 0x01 - data +// 0x02 - audio +// 0xff - no cdrom +// status: +// 0x00 - unknown +// 0x02 - error +// 0x08 - seek error +// 0x10 - shell open +// 0x20 - reading +// 0x40 - seeking +// 0x80 - playing +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame + + +EXPORT_GCC long CALLBACK CDRgetStatus(struct CdrStat *stat) +{ + int iStatus; + static time_t to; + + if(!bCDDAPlay) // if not playing update stat only once in a second + { + if(to get pos + stat->Type = 0x02; // -> audio + if(pB) + { + stat->Status|=0x80; // --> playing flag + stat->Time[0]=pB[18]; // --> and curr play time + stat->Time[1]=pB[19]; + stat->Time[2]=pB[20]; + } + } + else // cdda not playing? + { + stat->Type = 0x01; // -> data + } + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + { // no cdrom? + stat->Type = 0xff; + stat->Status|= 0x10; + } + + memcpy(&ostat, stat, sizeof(struct CdrStat)); + + return 0; +} + +///////////////////////////////////////////////////////// +*/ diff --git a/plugins/cdvd/CDVDpeops/Cfg.c b/plugins/cdvd/CDVDpeops/Cfg.c new file mode 100644 index 0000000000..c7ac3bca0f --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Cfg.c @@ -0,0 +1,527 @@ +/*************************************************************************** + cfg.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +//////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "resource.h" +#define _IN_CFG +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// read config from registry + +void ReadConfig(void) +{ + HKEY myKey;DWORD temp,type,size; + + // init values + + iCD_AD=-1; + iCD_TA=-1; + iCD_LU=-1; + iRType=0; + iUseSpeedLimit=0; + iSpeedLimit=2; + iNoWait=0; + iMaxRetry=5; + iShowReadErr=0; + iUsePPF=0; + iUseSubReading=0; + iUseDataCache=0; + iCheckTrayStatus=0; + memset(szPPF,0,260); + memset(szSUBF,0,260); + + // read values + + if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"Adapter",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_AD=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"Target",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_TA=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"LUN",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_LU=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseCaching",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseCaching=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseDataCache",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseDataCache=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseSpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseSpeedLimit=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"SpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iSpeedLimit=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"NoWait",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iNoWait=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"CheckTrayStatus",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCheckTrayStatus=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"MaxRetry",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iMaxRetry=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"ShowReadErr",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iShowReadErr=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UsePPF",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUsePPF=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseSubReading",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseSubReading=(int)temp; + size=259; + RegQueryValueEx(myKey,"PPFFile",0,&type,(LPBYTE)szPPF,&size); + size=259; + RegQueryValueEx(myKey,"SCFile",0,&type,(LPBYTE)szSUBF,&size); + + RegCloseKey(myKey); + } + + // disabled for now + iUsePPF=0; +} + +//////////////////////////////////////////////////////////////////////// +// write user config + +void WriteConfig(void) +{ + HKEY myKey;DWORD myDisp,temp; + + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); + temp=iInterfaceMode; + RegSetValueEx(myKey,"InterfaceMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_AD; + RegSetValueEx(myKey,"Adapter",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_TA; + RegSetValueEx(myKey,"Target",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_LU; + RegSetValueEx(myKey,"LUN",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseCaching; + RegSetValueEx(myKey,"UseCaching",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseDataCache; + RegSetValueEx(myKey,"UseDataCache",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseSpeedLimit; + RegSetValueEx(myKey,"UseSpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iSpeedLimit; + RegSetValueEx(myKey,"SpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iNoWait; + RegSetValueEx(myKey,"NoWait",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCheckTrayStatus ; + RegSetValueEx(myKey,"CheckTrayStatus",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iMaxRetry; + RegSetValueEx(myKey,"MaxRetry",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iShowReadErr; + RegSetValueEx(myKey,"ShowReadErr",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUsePPF; + RegSetValueEx(myKey,"UsePPF",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseSubReading; + RegSetValueEx(myKey,"UseSubReading",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + + RegSetValueEx(myKey,"PPFFile",0,REG_BINARY,(LPBYTE)szPPF,259); + RegSetValueEx(myKey,"SCFile",0,REG_BINARY,(LPBYTE)szSUBF,259); + + RegCloseKey(myKey); +} + +//////////////////////////////////////////////////////////////////////// +// choose ppf/sbi/m3s file name + +void OnChooseFile(HWND hW,int iFType) +{ + OPENFILENAME ofn;char szB[260];BOOL b; + + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.hwndOwner=hW; + ofn.hInstance=NULL; + if(iFType==0) ofn.lpstrFilter="PPF Files\0*.PPF\0\0\0"; + else if(iFType==1) ofn.lpstrFilter="SBI Files\0*.SBI\0M3S Files\0*.M3S\0\0\0"; + else if(iFType==2) ofn.lpstrFilter="SUB Files\0*.SUB\0\0\0"; + else if(iFType==3) ofn.lpstrFilter="SBI Files\0*.SBI\0\0\0"; + else ofn.lpstrFilter="M3S Files\0*.M3S\0\0\0"; + + ofn.lpstrCustomFilter=NULL; + ofn.nMaxCustFilter=0; + ofn.nFilterIndex=0; + if(iFType==0) GetDlgItemText(hW,IDC_PPFFILE,szB,259); + else if(iFType==1) GetDlgItemText(hW,IDC_SUBFILE,szB,259); + else if(iFType==2) GetDlgItemText(hW,IDC_SUBFILEEDIT,szB,259); + else if(iFType==3) GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); + else GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); + + ofn.lpstrFile=szB; + ofn.nMaxFile=259; + ofn.lpstrFileTitle=NULL; + ofn.nMaxFileTitle=0; + ofn.lpstrInitialDir=NULL; + ofn.lpstrTitle=NULL; + if(iFType<3) + ofn.Flags=OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_HIDEREADONLY; + else + ofn.Flags=OFN_CREATEPROMPT|OFN_NOCHANGEDIR|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT; + ofn.nFileOffset=0; + ofn.nFileExtension=0; + ofn.lpstrDefExt=0; + ofn.lCustData=0; + ofn.lpfnHook=NULL; + ofn.lpTemplateName=NULL; + + if(iFType<3) + b=GetOpenFileName(&ofn); + else b=GetSaveFileName(&ofn); + + if(b) + { + if(iFType==0) SetDlgItemText(hW,IDC_PPFFILE,szB); + else if(iFType==1) SetDlgItemText(hW,IDC_SUBFILE,szB); + else if(iFType==2) SetDlgItemText(hW,IDC_SUBFILEEDIT,szB); + else if(iFType==3) SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); + else SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); + } +} + +//////////////////////////////////////////////////////////////////////// +// file drive combo + +void EnumDrives(HWND hW) +{ + HWND hWC;char szB[256];int i=0,k=0,iNum; + char * p, * pBuf, * pN; + + hWC=GetDlgItem(hW,IDC_DRIVE); + ComboBox_ResetContent(hWC); + ComboBox_AddString(hWC,"NONE"); // add always existing 'none' + + wsprintf(szB,"[%d:%d:%d",iCD_AD,iCD_TA,iCD_LU); // make current user info text + + pN=pBuf=(char *)malloc(32768); + memset(pBuf,0,32768); + iNum=GetGenCDDrives(pBuf); // get the system cd drives list + + for(i=0;i add drive name + p=strchr(pN,']'); + if(p) + { + *p=0; + if(strcmp(szB,pN)==0) k=i+1; // -> is it the current user drive? sel it + *p=']'; + } + pN+=strlen(pN)+1; // next drive in buffer + } + + free(pBuf); + + ComboBox_SetCurSel(hWC,k); // do the drive sel +} + +//////////////////////////////////////////////////////////////////////// +// get curr selected drive + +void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL) +{ + HWND hWC=GetDlgItem(hW,IDC_DRIVE); + char szB[256];int i;char * p; + + i=ComboBox_GetCurSel(hWC); + if(i<=0) // none selected + { + *iA=-1;*iT=-1;*iL=-1; + MessageBox(hW,"Please select a cdrom drive!","Config error",MB_OK|MB_ICONINFORMATION); + return; + } + + ComboBox_GetLBText(hWC,i,szB); // get cd text + p=szB+1; + *iA=atoi(p); // get AD,TA,LU + p=strchr(szB,':')+1; + *iT=atoi(p); + p=strchr(p,':')+1; + *iL=atoi(p); +} + +//////////////////////////////////////////////////////////////////////// +// interface mode has changed + +void OnIMode(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_IMODE); + int iM = ComboBox_GetCurSel(hWC); + + GetCDRInfos(hW,&iCD_AD,&iCD_TA,&iCD_LU); // get sel drive + CloseGenInterface(); // close current interface + iInterfaceMode=iM; // set new interface mode + OpenGenInterface(); // open new interface + ComboBox_SetCurSel(hWC,iInterfaceMode); // sel interface again (maybe it was not supported on open) + EnumDrives(hW); // enum drives again +} + +//////////////////////////////////////////////////////////////////////// +// cache mode has changed + +void OnCache(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_CACHE); + if(ComboBox_GetCurSel(hWC)<=0) + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + else ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_SHOW); +} + +//////////////////////////////////////////////////////////////////////// +// show/hide files depending on subc mode + +void ShowSubFileStuff(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_SUBCHAN0); + int iShow,iSel=ComboBox_GetCurSel(hWC); + + if(iSel==2) iShow=SW_SHOW; + else iShow=SW_HIDE; + + ShowWindow(GetDlgItem(hW,IDC_SFSTATIC),iShow); + ShowWindow(GetDlgItem(hW,IDC_SUBFILE),iShow); + ShowWindow(GetDlgItem(hW,IDC_CHOOSESUBF),iShow); + + if(iSel==1) + { + ComboBox_SetCurSel(GetDlgItem(hW,IDC_CACHE),0); + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + } +} + +//////////////////////////////////////////////////////////////////////// +// init dialog + +BOOL OnInitCDRDialog(HWND hW) +{ + HWND hWC;int i=0; + + ReadConfig(); // read config + + hWC=GetDlgItem(hW,IDC_IMODE); // interface + ComboBox_AddString(hWC,"NONE"); + ComboBox_AddString(hWC,"W9X/ME - ASPI scsi commands"); + ComboBox_AddString(hWC,"W2K/XP - IOCTL scsi commands"); + +// not supported with my dvd drive - DISABLED! +// ComboBox_AddString(hWC,"W2K/XP - IOCTL raw reading"); + + ComboBox_SetCurSel(hWC,iInterfaceMode); + + EnumDrives(hW); // enum drives + + hWC=GetDlgItem(hW,IDC_CACHE); // caching + ComboBox_AddString(hWC,"None - reads one sector"); + ComboBox_AddString(hWC,"Read ahead - fast, reads more sectors at once"); + ComboBox_AddString(hWC,"Async read - faster, additional asynchronous reads"); + ComboBox_AddString(hWC,"Thread read - fast with IOCTL, always async reads"); + ComboBox_AddString(hWC,"Smooth read - for drives with ps2 cd/dvd reading troubles"); + ComboBox_SetCurSel(hWC,iUseCaching); + + if(iUseDataCache) + CheckDlgButton(hW,IDC_DATACACHE,TRUE); + if(!iUseCaching) + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + + if(iUseSpeedLimit) // speed limit + CheckDlgButton(hW,IDC_SPEEDLIMIT,TRUE); + + if(iNoWait) // wait for drive + CheckDlgButton(hW,IDC_NOWAIT,TRUE); + + if(iCheckTrayStatus) // tray status + CheckDlgButton(hW,IDC_TRAYSTATE,TRUE); + + SetDlgItemInt(hW,IDC_RETRY,iMaxRetry,FALSE); // retry on error + if(iMaxRetry) CheckDlgButton(hW,IDC_TRYAGAIN,TRUE); + if(iShowReadErr) CheckDlgButton(hW,IDC_SHOWREADERR,TRUE); + + hWC=GetDlgItem(hW,IDC_SUBCHAN0); // subchannel mode + ComboBox_AddString(hWC,"Don't read subchannels"); + ComboBox_AddString(hWC,"Read subchannels (slow, few drives support it, best chances with BE mode)"); + ComboBox_AddString(hWC,"Use subchannel SBI/M3S info file (recommended)"); + ComboBox_SetCurSel(hWC,iUseSubReading); + + ShowSubFileStuff(hW); // show/hide subc controls + + hWC=GetDlgItem(hW,IDC_SPEED); // speed limit + ComboBox_AddString(hWC,"2 X"); + ComboBox_AddString(hWC,"4 X"); + ComboBox_AddString(hWC,"8 X"); + ComboBox_AddString(hWC,"16 X"); + + i=0; + if(iSpeedLimit==4) i=1; + if(iSpeedLimit==8) i=2; + if(iSpeedLimit==16) i=3; + + ComboBox_SetCurSel(hWC,i); + + if(iUsePPF) CheckDlgButton(hW,IDC_USEPPF,TRUE); // ppf + SetDlgItemText(hW,IDC_PPFFILE,szPPF); + SetDlgItemText(hW,IDC_SUBFILE,szSUBF); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// + +void OnCDROK(HWND hW) +{ + int iA,iT,iL,iR; + HWND hWC=GetDlgItem(hW,IDC_RTYPE); + + GetCDRInfos(hW,&iA,&iT,&iL); + if(iA==-1) return; + + hWC=GetDlgItem(hW,IDC_CACHE); + iUseCaching=ComboBox_GetCurSel(hWC); + if(iUseCaching<0) iUseCaching=0; + if(iUseCaching>4) iUseCaching=4; + + iCD_AD=iA;iCD_TA=iT;iCD_LU=iL; + + if(IsDlgButtonChecked(hW,IDC_SPEEDLIMIT)) + iUseSpeedLimit=1; + else iUseSpeedLimit=0; + + iUseSubReading=0; + hWC=GetDlgItem(hW,IDC_SUBCHAN0); + iUseSubReading=ComboBox_GetCurSel(hWC); + if(iUseSubReading<0) iUseSubReading=0; + if(iUseSubReading>2) iUseSubReading=2; + if(iUseSubReading==1) iUseCaching=0; + + if(IsDlgButtonChecked(hW,IDC_DATACACHE)) + iUseDataCache=1; + else iUseDataCache=0; + if(iUseCaching==0) iUseDataCache=0; + + if(IsDlgButtonChecked(hW,IDC_NOWAIT)) + iNoWait=1; + else iNoWait=0; + + if(IsDlgButtonChecked(hW,IDC_TRAYSTATE)) + iCheckTrayStatus=1; + else iCheckTrayStatus=0; + + iMaxRetry=GetDlgItemInt(hW,IDC_RETRY,NULL,FALSE); + if(iMaxRetry<1) iMaxRetry=1; + if(iMaxRetry>10) iMaxRetry=10; + if(!IsDlgButtonChecked(hW,IDC_TRYAGAIN)) iMaxRetry=0; + + if(IsDlgButtonChecked(hW,IDC_SHOWREADERR)) + iShowReadErr=1; + else iShowReadErr=0; + + hWC=GetDlgItem(hW,IDC_SPEED); + iR=ComboBox_GetCurSel(hWC); + + iSpeedLimit=2; + if(iR==1) iSpeedLimit=4; + if(iR==2) iSpeedLimit=8; + if(iR==3) iSpeedLimit=16; + + if(IsDlgButtonChecked(hW,IDC_USEPPF)) + iUsePPF=1; + else iUsePPF=0; + + GetDlgItemText(hW,IDC_PPFFILE,szPPF,259); + GetDlgItemText(hW,IDC_SUBFILE,szSUBF,259); + + WriteConfig(); // write registry + + EndDialog(hW,TRUE); +} + +//////////////////////////////////////////////////////////////////////// + +void OnCDRCancel(HWND hW) +{ + EndDialog(hW,FALSE); +} + +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return OnInitCDRDialog(hW); + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDC_SUBCHAN0: if(HIWORD(wParam)==CBN_SELCHANGE) + {ShowSubFileStuff(hW);return TRUE;} + case IDC_IMODE: if(HIWORD(wParam)==CBN_SELCHANGE) + {OnIMode(hW);return TRUE;} + break; + case IDC_CACHE: if(HIWORD(wParam)==CBN_SELCHANGE) + {OnCache(hW);return TRUE;} + break; + case IDCANCEL: OnCDRCancel(hW); return TRUE; + case IDOK: OnCDROK(hW); return TRUE; + case IDC_CHOOSEFILE: OnChooseFile(hW,0);return TRUE; + case IDC_CHOOSESUBF: OnChooseFile(hW,1);return TRUE; + } + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDCANCEL: EndDialog(hW,FALSE);return TRUE; + case IDOK: EndDialog(hW,FALSE);return TRUE; + } + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + diff --git a/plugins/cdvd/CDVDpeops/CheckDiskType.c b/plugins/cdvd/CDVDpeops/CheckDiskType.c new file mode 100644 index 0000000000..4719c3997f --- /dev/null +++ b/plugins/cdvd/CDVDpeops/CheckDiskType.c @@ -0,0 +1,41 @@ + +#include +#include "CDVDlib.h" +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +int CheckDiskType(int baseType){ + int f; + char buffer[256];//if a file is longer...it should be shorter :D + char *pos; + static struct TocEntry tocEntry; + + CDVDFS_init(); + + // check if the file exists + if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ + if (CDVD_findfile("VIDEO_TS/VIDEO_TS.IFO;1", &tocEntry) != TRUE) + if (CDVD_findfile("PSX.EXE;1", &tocEntry) != TRUE) + return CDVD_TYPE_ILLEGAL; + else + return CDVD_TYPE_PSCD; + else + return CDVD_TYPE_DVDV; + } + + f=CDVDFS_open("SYSTEM.CNF;1", 1); + CDVDFS_read(f, buffer, 256); + CDVDFS_close(f); + + buffer[tocEntry.fileSize]='\0'; + + pos=strstr(buffer, "BOOT2"); + if (pos==NULL){ + pos=strstr(buffer, "BOOT"); + if (pos==NULL) { + return CDVD_TYPE_ILLEGAL; + } + return CDVD_TYPE_PSCD; + } + return (baseType==CDVD_TYPE_DETCTCD)?CDVD_TYPE_PS2CD:CDVD_TYPE_PS2DVD; +} diff --git a/plugins/cdvd/CDVDpeops/Ioctrl.c b/plugins/cdvd/CDVDpeops/Ioctrl.c new file mode 100644 index 0000000000..62a38d2960 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Ioctrl.c @@ -0,0 +1,383 @@ +/*************************************************************************** + ioctrl.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_IOCTL +#include "externals.h" + +///////////////////////////////////////////////////////// + +HANDLE hIOCTL=NULL; // global drive file handle +DWORD dwIOCTLAttr=0; // open attribute +OVERLAPPED ovcIOCTL; // global overlapped struct +SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; // global read bufs +RAW_READ_INFO rawIOCTL; + +///////////////////////////////////////////////////////// +// open drive + +void OpenIOCTLHandle(int iA,int iT,int iL) +{ + char cLetter; + + if(hIOCTL) return; + + cLetter=MapIOCTLDriveLetter(iA,iT,iL); // get drive + + if(!cLetter) return; + + hIOCTL=OpenIOCTLFile(cLetter, // open drive + (iUseCaching==2)?TRUE:FALSE); // (caching:2 -> overlapped) +} + +///////////////////////////////////////////////////////// +// close drive + +void CloseIOCTLHandle(void) +{ + if(hIOCTL) CloseHandle(hIOCTL); + hIOCTL=NULL; +} + +///////////////////////////////////////////////////////// +// get drive letter by a,t,l + +char MapIOCTLDriveLetter(int iA,int iT,int iL) +{ + char cLetter[4];int iDA,iDT,iDL;HANDLE hF; + + strcpy(cLetter,"C:\\"); + + for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) + { + if(GetDriveType(cLetter)==DRIVE_CDROM) + { + hF=OpenIOCTLFile(cLetter[0],FALSE); + GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); + CloseHandle(hF); + if(iA==iDA && iT==iDT && iL==iDL) + return cLetter[0]; + } + } + return 0; +} + +///////////////////////////////////////////////////////// +// get cd drive list, using ioctl, not aspi + +int GetIOCTLCDDrives(char * pDList) +{ + char cLetter[4];int iDA,iDT,iDL;HANDLE hF; + int iCnt=0;char * p=pDList; + + strcpy(cLetter,"C:\\"); + + for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) + { + if(GetDriveType(cLetter)==DRIVE_CDROM) + { + hF=OpenIOCTLFile(cLetter[0],FALSE); + GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); + CloseHandle(hF); + if(iDA!=-1 && iDT!=-1 && iDL!=-1) + { + wsprintf(p,"[%d:%d:%d] Drive %c:", + iDA,iDT,iDL,cLetter[0]); + p+=strlen(p)+1; + iCnt++; + } + } + } + + return iCnt; +} + +///////////////////////////////////////////////////////// +// open drive in sync/async mode + +HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync) +{ + HANDLE hF;char szFName[16]; + OSVERSIONINFO ov;DWORD dwFlags; + + if(bAsync) dwIOCTLAttr=FILE_FLAG_OVERLAPPED; + else dwIOCTLAttr=0; + + memset(&ov,0,sizeof(OSVERSIONINFO)); + ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); + GetVersionEx(&ov); + + if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && + (ov.dwMajorVersion>4)) + dwFlags = GENERIC_READ|GENERIC_WRITE; // add gen write on W2k/XP + else dwFlags = GENERIC_READ; + + wsprintf(szFName, "\\\\.\\%c:",cLetter); + + hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // open drive + NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); + + if(hF==INVALID_HANDLE_VALUE) // mmm... no success? + { + dwFlags^=GENERIC_WRITE; // -> try write toggle + hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // -> open drive again + NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); + if(hF==INVALID_HANDLE_VALUE) return NULL; + } + + return hF; +} + +///////////////////////////////////////////////////////// +// get a,t,l + +void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL) +{ + char szBuf[1024];PSCSI_ADDRESS pSA;DWORD dwRet; + + *iDA=*iDT=*iDL=-1; + if(hF==NULL) return; + + memset(szBuf,0,1024); + + pSA=(PSCSI_ADDRESS)szBuf; + pSA->Length=sizeof(SCSI_ADDRESS); + + if(!DeviceIoControl(hF,IOCTL_SCSI_GET_ADDRESS,NULL, + 0,pSA,sizeof(SCSI_ADDRESS), + &dwRet,NULL)) + return; + + *iDA = pSA->PortNumber; + *iDT = pSA->TargetId; + *iDL = pSA->Lun; +} + +///////////////////////////////////////////////////////// +// we fake the aspi call in ioctl scsi mode + +DWORD IOCTLSendASPI32Command(LPSRB pSRB) +{ + LPSRB_ExecSCSICmd pSC;DWORD dwRet;BOOL bStat; + + if(!pSRB) return SS_ERR; + + if(hIOCTL==NULL || + pSRB->SRB_Cmd!=SC_EXEC_SCSI_CMD) // we only fake exec aspi scsi commands + { + pSRB->SRB_Status=SS_ERR; + return SS_ERR; + } + + pSC=(LPSRB_ExecSCSICmd)pSRB; + + memset(&sptIOCTL,0,sizeof(sptIOCTL)); + + sptIOCTL.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + sptIOCTL.spt.CdbLength = pSC->SRB_CDBLen; + sptIOCTL.spt.DataTransferLength = pSC->SRB_BufLen; + sptIOCTL.spt.TimeOutValue = 60; + sptIOCTL.spt.DataBuffer = pSC->SRB_BufPointer; + sptIOCTL.spt.SenseInfoLength = 14; + sptIOCTL.spt.TargetId = pSC->SRB_Target; + sptIOCTL.spt.Lun = pSC->SRB_Lun; + sptIOCTL.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + if(pSC->SRB_Flags&SRB_DIR_IN) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_IN; + else if(pSC->SRB_Flags&SRB_DIR_OUT) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_OUT; + else sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; + memcpy(sptIOCTL.spt.Cdb,pSC->CDBByte,pSC->SRB_CDBLen); + + if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? + { + ovcIOCTL.Internal=0; + ovcIOCTL.InternalHigh=0; + ovcIOCTL.Offset=0; + ovcIOCTL.OffsetHigh=0; + ovcIOCTL.hEvent=hEvent; + bStat = DeviceIoControl(hIOCTL, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sptIOCTL, + sizeof(sptIOCTL), + &sptIOCTL, + sizeof(sptIOCTL), + &dwRet, + &ovcIOCTL); + } + else // sync? + { + bStat = DeviceIoControl(hIOCTL, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sptIOCTL, + sizeof(sptIOCTL), + &sptIOCTL, + sizeof(sptIOCTL), + &dwRet, + NULL); + } + + if(!bStat) // some err? + { + DWORD dwErrCode; + dwErrCode=GetLastError(); + if(dwErrCode==ERROR_IO_PENDING) // -> pending? + { + pSC->SRB_Status=SS_COMP; // --> ok + return SS_PENDING; + } + pSC->SRB_Status=SS_ERR; // -> else error + return SS_ERR; + } + + pSC->SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// special raw mode... works on TEAC532S, for example + +DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwRet;BOOL bStat; + + if(hIOCTL==NULL) return SS_ERR; + + rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; // 2048 is needed here + rawIOCTL.SectorCount = f->dwFrameCnt; + rawIOCTL.TrackMode = XAForm2;//CDDA;//YellowMode2;//XAForm2; + + if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? + { + ovcIOCTL.Internal=0; + ovcIOCTL.InternalHigh=0; + ovcIOCTL.Offset=0; + ovcIOCTL.OffsetHigh=0; + ovcIOCTL.hEvent=hEvent; + ResetEvent(hEvent); + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen,//2048, + &dwRet, &ovcIOCTL); + } + else // sync? + { + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen,//2048, + &dwRet,NULL); + } + + if(!bStat) + { + DWORD dwErrCode; + dwErrCode=GetLastError(); + +#ifdef DBGOUT +auxprintf("errorcode %d\n", dwErrCode); +#endif + + if(dwErrCode==ERROR_IO_PENDING) + { + // we do a wait here, not later... no real async mode anyway + // bDoWaiting=TRUE; + + WaitGenEvent(0xFFFFFFFF); + } + else + { + sx.SRB_Status=SS_ERR; + return SS_ERR; + } + } + + sx.SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// special raw + special sub... dunno if this really +// works on any drive (teac is working, but giving unprecise +// subdata) + +DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwRet;BOOL bStat; + SUB_Q_CHANNEL_DATA qd;unsigned char * p; + CDROM_SUB_Q_DATA_FORMAT qf; + + if(hIOCTL==NULL) return SS_ERR; + + rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; + rawIOCTL.SectorCount = f->dwFrameCnt; + rawIOCTL.TrackMode = XAForm2; + + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen, + &dwRet,NULL); + + if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} + + qf.Format=IOCTL_CDROM_CURRENT_POSITION; + qf.Track=1; + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_READ_Q_CHANNEL, + &qf,sizeof(CDROM_SUB_Q_DATA_FORMAT), + &qd,sizeof(SUB_Q_CHANNEL_DATA), + &dwRet,NULL); + + p=(unsigned char*)&qd; + + SubCData[12]=(p[5]<<4)|(p[5]>>4); + SubCData[13]=p[6]; + SubCData[14]=p[7]; + SubCData[15]=p[13]; + SubCData[16]=p[14]; + SubCData[17]=p[15]; + SubCData[18]=0; + SubCData[19]=p[9]; + SubCData[20]=p[10]; + SubCData[21]=p[11]; + + SubCData[15]=itob(SubCData[15]); + SubCData[16]=itob(SubCData[16]); + SubCData[17]=itob(SubCData[17]); + + SubCData[19]=itob(SubCData[19]); + SubCData[20]=itob(SubCData[20]); + SubCData[21]=itob(SubCData[21]); + + if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} + + sx.SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/Makefile.win b/plugins/cdvd/CDVDpeops/Makefile.win new file mode 100644 index 0000000000..c860068e9f --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Makefile.win @@ -0,0 +1,72 @@ +# Project: cdvdPeops +# Makefile created by Dev-C++ 4.9.9.0 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = cdvdPeops_private.res +OBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) +LINKOBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) +LIBS = -L"D:/vs/Dev-Cpp/lib" -lkernel32 -luser32 -ladvapi32 -lcomdlg32 --add-stdcall-alias +INCS = -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" +CXXINCS = -I"D:/vs/Dev-Cpp/include/c++" -I"D:/vs/Dev-Cpp/include/c++/mingw32" -I"D:/vs/Dev-Cpp/include/c++/backward" -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" +BIN = ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 +CFLAGS = $(INCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 + +.PHONY: all all-before all-after clean clean-custom + +all: all-before ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll all-after + + +clean: clean-custom + rm -f $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.def +STATICLIB=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Release/cdr.o: cdr.c + $(CC) -c cdr.c -o Release/cdr.o $(CFLAGS) + +Release/cdvdPeops.o: cdvdPeops.c + $(CC) -c cdvdPeops.c -o Release/cdvdPeops.o $(CFLAGS) + +Release/cfg.o: cfg.c + $(CC) -c cfg.c -o Release/cfg.o $(CFLAGS) + +Release/generic.o: generic.c + $(CC) -c generic.c -o Release/generic.o $(CFLAGS) + +Release/ioctrl.o: ioctrl.c + $(CC) -c ioctrl.c -o Release/ioctrl.o $(CFLAGS) + +Release/ppf.o: ppf.c + $(CC) -c ppf.c -o Release/ppf.o $(CFLAGS) + +Release/read.o: read.c + $(CC) -c read.c -o Release/read.o $(CFLAGS) + +Release/scsi.o: scsi.c + $(CC) -c scsi.c -o Release/scsi.o $(CFLAGS) + +Release/StdAfx.o: StdAfx.c + $(CC) -c StdAfx.c -o Release/StdAfx.o $(CFLAGS) + +Release/sub.o: sub.c + $(CC) -c sub.c -o Release/sub.o $(CFLAGS) + +Release/toc.o: toc.c + $(CC) -c toc.c -o Release/toc.o $(CFLAGS) + +Release/cdda.o: cdda.c + $(CC) -c cdda.c -o Release/cdda.o $(CFLAGS) + +Release/i386.o: i386.asm + nasmw.exe -f win32 -D__WIN32__ -D__i386__ i386.asm -o release\i386.o + +cdvdPeops_private.res: cdvdPeops_private.rc ../../../src/cdvdPeops/src/cdvdPeops.rc + $(WINDRES) -i cdvdPeops_private.rc -I rc -o cdvdPeops_private.res -O coff diff --git a/plugins/cdvd/CDVDpeops/PS2Edefs.h b/plugins/cdvd/CDVDpeops/PS2Edefs.h new file mode 100644 index 0000000000..48093ae147 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/PS2Edefs.h @@ -0,0 +1,789 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetCSR(u64 *csr); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetCSR)(u64 * csr); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetCSR GSsetCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/cdvd/CDVDpeops/PS2Etypes.h b/plugins/cdvd/CDVDpeops/PS2Etypes.h new file mode 100644 index 0000000000..3a63c58b85 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/cdvd/CDVDpeops/ReadMe.txt b/plugins/cdvd/CDVDpeops/ReadMe.txt new file mode 100644 index 0000000000..3eff73e5c1 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/ReadMe.txt @@ -0,0 +1,37 @@ +======================================================================== + DYNAMIC LINK LIBRARY : cdrPeops +======================================================================== + + +AppWizard has created this cdrPeops DLL for you. + +This file contains a summary of what you will find in each of the files that +make up your cdrPeops application. + +cdrPeops.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +cdrPeops.cpp + This is the main DLL source file. + +cdrPeops.h + This file contains your DLL exports. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named cdrPeops.pch and a precompiled types file named StdAfx.obj. + + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/Scsi.c b/plugins/cdvd/CDVDpeops/Scsi.c new file mode 100644 index 0000000000..7f1f9e5460 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/Scsi.c @@ -0,0 +1,1134 @@ +/*************************************************************************** + scsi.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_SCSI +#include "externals.h" + +///////////////////////////////////////////////////////// + +SRB_ExecSCSICmd sx; // used with all (non-waiting) read funcs +BOOL bDoWaiting=FALSE; // flag for async reads + +///////////////////////////////////////////////////////// +// returns device type + +int GetSCSIDevice(int iA,int iT,int iL) +{ + SRB_GDEVBlock s;DWORD dwStatus; + + memset(&s,0,sizeof(SRB_GDEVBlock)); + s.SRB_Cmd = SC_GET_DEV_TYPE; + s.SRB_HaID = iA; + s.SRB_Target = iT; + s.SRB_Lun = iL; + + ResetEvent(hEvent); + + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + {WaitGenEvent(30000);dwStatus=s.SRB_Status;} + + if(dwStatus==SS_COMP) return s.SRB_DeviceType; + + return -1; +} + +///////////////////////////////////////////////////////// + +int GetSCSIStatus(int iA,int iT,int iL) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + char ret[0x324]; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x324; + s.SRB_BufPointer = (BYTE FAR *)ret; + s.SRB_SenseLen = 0x0E; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x00; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(30000); + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// +// fills toc infos + +DWORD GetSCSITOC(LPTOC toc) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x324; + s.SRB_BufPointer = (BYTE FAR *)toc; + s.SRB_SenseLen = 0x0E; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x43; + s.CDBByte[1] = 0x00; // 0x02 for MSF + s.CDBByte[7] = 0x03; + s.CDBByte[8] = 0x24; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(30000); + + if(s.SRB_Status!=SS_COMP) return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// enum all cd drives into 32k buffer, return num of drives + +int GetSCSICDDrives(char * pDList) +{ + int iCnt=0,iA,iT,iL;char * p=pDList; + SRB_HAInquiry si;SRB_GDEVBlock sd; + SRB_ExecSCSICmd s;int iNumA;char szBuf[100]; + DWORD dw,dwStatus; + + if(!pGetASPI32SupportInfo) return 0; + + dw=pGetASPI32SupportInfo(); + + if(HIBYTE(LOWORD(dw))!=SS_COMP) return 0; + iNumA=(int)LOBYTE(LOWORD(dw)); + + for(iA=0;iA> 24) & 0xFF); + s.CDBByte[3] = (unsigned char)((start >> 16) & 0xFF); + s.CDBByte[4] = (unsigned char)((start >> 8) & 0xFF); + s.CDBByte[5] = (unsigned char)((start & 0xFF)); + s.CDBByte[6] = (unsigned char)((len >> 24) & 0xFF); + s.CDBByte[7] = (unsigned char)((len >> 16) & 0xFF); + s.CDBByte[8] = (unsigned char)((len >> 8) & 0xFF); + s.CDBByte[9] = (unsigned char)(len & 0xFF); + } + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(10000); + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// +// do (unprecise) sub channel read on audio play + +unsigned char * GetSCSIAudioSub(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + unsigned char cB[20]; + + memset(cB,0,20); + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = 20;//44; + s.SRB_BufPointer = cB; + s.SRB_CDBLen = 10; + + s.CDBByte[0] = 0x42; + s.CDBByte[1] = (iCD_LU<<5)|2; // lun & msf + s.CDBByte[2] = 0x40; // subq + s.CDBByte[3] = 0x01; // curr pos info + s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) + s.CDBByte[7] = 0; // alloc len + s.CDBByte[8] = 20;//44; + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) return NULL; + + SubAData[12]=(cB[5]<<4)|(cB[5]>>4); + SubAData[13]=cB[6]; + SubAData[14]=cB[7]; + SubAData[15]=itob(cB[13]); + SubAData[16]=itob(cB[14]); + SubAData[17]=itob(cB[15]); + SubAData[18]=0; + SubAData[19]=itob(cB[9]); + SubAData[20]=itob(cB[10]); + SubAData[21]=itob(cB[11]); + + return SubAData; +} + +///////////////////////////////////////////////////////// +// test, if drive is ready (doesn't work on all drives) + +BOOL TestSCSIUnitReady(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0; + s.SRB_BufPointer = 0; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x00; + s.CDBByte[1] = iCD_LU << 5; + + ResetEvent(hEvent); + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + WaitGenEvent(1000); + + if(s.SRB_Status!=SS_COMP) + return FALSE; + + if(s.SRB_TargStat==STATUS_GOOD) return TRUE; // will always be GOOD with ioctl, so no problem here + + return FALSE; +} + +///////////////////////////////////////////////////////// +// change the read speed (not supported on all drives) + +DWORD SetSCSISpeed(DWORD dwSpeed) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_OUT | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 12; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0xBB; + s.CDBByte[2] = (BYTE)(dwSpeed >> 8); + s.CDBByte[3] = (BYTE)dwSpeed; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// all the different SCSI read commands can be found here +// 'bWait' is a flag, if the command should wait until +// completed, or if the func can return as soon as possible +// (async reading). Attention: 'bWait' is not really used +// in the Sub-channel commands yet (sub is done always +// blocking, and just 'one sector' reads are done, caching=0) +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// BE: used by most ATAPI drives +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + //s.CDBByte[1] = 0x04; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen + 16; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + //s.CDBByte[1] = 0x04; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! + sx.CDBByte[10] = 0x2; + + ResetEvent(hEvent ); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memcpy(&SubCData[12],&f->BufData[2352],16); + + SubCData[15]=itob(SubCData[15]); + SubCData[16]=itob(SubCData[16]); + SubCData[17]=itob(SubCData[17]); + + SubCData[19]=itob(SubCData[19]); + SubCData[20]=itob(SubCData[20]); + SubCData[21]=itob(SubCData[21]); + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// different sub reading for lite-on ltd163d... +// 16 bytes subc data is encoded in 96 bytes... + +DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen + 96; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + DecodeSub_BE_2_1(&f->BufData[2352]); + + memcpy(&SubCData[12],&f->BufData[2352],16); + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// 28: used by most SCSI drives +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_2(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + int i; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30, 0x23, 6, 0, 0, 0, 0, 0, 0x80 }; + BYTE init2[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48, 1, 6, 32, 7, 0, 0, 0, 0 }; + + for(i=0;i<2;i++) + { + memset( &s, 0, sizeof( s ) ); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x14; + s.SRB_BufPointer = (i==0)?init1:init2; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[1] = 0x10; + s.CDBByte[4] = 0x14; + + ResetEvent(hEvent); + + dwStatus=pSendASPI32Command((LPSRB)&s); + if (dwStatus == SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + } + + pDeInitFunc = DeInitSCSI_28; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_1(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30 }; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + pDeInitFunc = DeInitSCSI_28; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_2048(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x08, 0x0 }; + + pDeInitFunc = DeInitSCSI_28; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD DeInitSCSI_28(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 8, 83, 0, 0, 0, 0, 0, 8, 0 }; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + if(iRType==MODE_28_2) + { + if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; + } + else + { + if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; + } + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// DVD MODE + +DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + InitSCSI_28_2048(); + + //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = 0xF8; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + InitSCSI_28_2048(); + + //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + // NO F8 + //sx.CDBByte[9] = 0xF8; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + + +///////////////////////////////////////////////////////// +// stupid subc reading on Teac 532S + +char tbuf[2368]; + +DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + if(iRType==MODE_28_2) + { + if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; + } + else + { + if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; + } + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368; + sx.SRB_BufPointer = tbuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xD8; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[9] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[10] = 1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memcpy(&SubCData[12],&tbuf[2352],16); + + return SS_COMP; +} + + +///////////////////////////////////////////////////////// +// various simple scsi sub data read funcs... used for +// ripping and subread checking... first 2352 bytes can +// be trash after read, only the bytes after are important +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// + +int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368*iNum; + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[8] = iNum; + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x2; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command( (LPSRB)&sx ); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// + +int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2448*iNum; // special! 96 bytes instead of 16 + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[8] = iNum; + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// + +int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368*iNum; + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xD8; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[9] = iNum; + sx.CDBByte[10] = 1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// +// liteon subdata decoding + +void DecodeSub_BE_2_1(unsigned char * pBuf) +{ + int i,j; + unsigned char * pS=pBuf; + unsigned char c; + + for(i=0;i<12;i++) + { + c=0; + for(j=7;j>=0;j--,pS++) + { + if(*pS & 0x40) c|=(1<dwFrame = 16; // we check on addr 16 (should be available on all ps2 cds/dvds) + f->dwFrameCnt = 1; + f->dwBufLen = iBlock[i]; + + pDeInitFunc = NULL; + iRType=iModes[i]; // set global read mode + GetGenReadFunc(iRType); // get read func pointer + + for(j=0;j<3;j++) // try it 3 times + { + memset(f->BufData,0xAA,f->dwBufLen); // fill buf with AA + dwStatus=pReadFunc(TRUE,f); // do the read + +#ifdef DBGOUT +auxprintf("status %d\n",dwStatus); +#endif + + if(dwStatus!=SS_COMP) continue; // error? try again + + p=&(f->BufData[0]); + +#ifdef DBGOUT +auxprintf("check mode %d\n",i); +#endif + + for(k=0,iCnt=0;k<(int)f->dwBufLen;k+=4,p+=4) // now check the returned data + { +#ifdef DBGOUT +// auxprintf("%08x ",*((DWORD *)p)); +#endif + + if(*((DWORD *)p)==0xAAAAAAAA) // -> still AA? bad + iCnt++; + else iCnt=0; + + if(iCnt>=8) {dwStatus=SS_ERR;break;} // -> if we have found many AA's, the reading was bad + } + + if(dwStatus==SS_COMP) // reading was a success, no AA's? + { + iRType = iModes[i]; // -> set found mode + iUsedBlockSize = iBlock[i]; + if(iUsedBlockSize==2352) + iUsedMode=CDVD_MODE_2352; + else iUsedMode=CDVD_MODE_2048; + +#ifdef DBGOUT +auxprintf("mode found %d\n",i); +#endif + + return dwStatus; // -> bye + } + } + if(pDeInitFunc) pDeInitFunc(); // deinit, try next mode + } + + return dwStatus; +} + +///////////////////////////////////////////////////////// +// dummy read dunc + +DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f) +{ + return SS_ERR; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/StdAfx.c b/plugins/cdvd/CDVDpeops/StdAfx.c new file mode 100644 index 0000000000..cf47398ca1 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/StdAfx.c @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// cdvdPeops.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/cdvd/CDVDpeops/StdAfx.h b/plugins/cdvd/CDVDpeops/StdAfx.h new file mode 100644 index 0000000000..d0b6fbb405 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/StdAfx.h @@ -0,0 +1,82 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) +#define AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _GCC +#define EXPORT_GCC __declspec (dllexport) +#else +#define EXPORT_GCC +#endif + +// Insert your headers here +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// special setup for MinGW/Dev-C++ ################### // +// (I don't want to change PS2Edefs.h/PS2Etypes.h) + +#undef __WIN32__ + +typedef char s8; +typedef short s16; +typedef long s32; +#ifdef _GCC +typedef long long s64; +#else +typedef __int64 s64; +#endif + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +#ifdef _GCC +typedef unsigned long long u64; +#else +typedef unsigned __int64 u64; +#endif + +#include "PS2Edefs.h" + +#define __WIN32__ + +// ################################################### // + + +#include "wnaspi32.h" +#include "scsidefs.h" + +#include "defines.h" +#include "cdda.h" +#include "cdr.h" +#include "cfg.h" +#include "generic.h" +#include "ioctrl.h" +#include "ppf.h" +#include "read.h" +#include "scsi.h" +#include "sub.h" +#include "toc.h" + +//#define DBGOUT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) diff --git a/plugins/cdvd/CDVDpeops/build.sh b/plugins/cdvd/CDVDpeops/build.sh new file mode 100644 index 0000000000..5ce4a49edf --- /dev/null +++ b/plugins/cdvd/CDVDpeops/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +curdir=`pwd` + +echo ------------------ +echo Building CDVDpeops +echo ------------------ + +cd ${curdir}/src/Linux +make $@ + +# copy the files +if [ -s cfgCDVDpeops ] && [ -s libCDVDpeops.so ] +then +cp cfgCDVDpeops libCDVDpeops.so ${PCSX2PLUGINS} +fi diff --git a/plugins/cdvd/CDVDpeops/cdda.c b/plugins/cdvd/CDVDpeops/cdda.c new file mode 100644 index 0000000000..dc0180b59a --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdda.c @@ -0,0 +1,80 @@ +/*************************************************************************** + cdda.c - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_CDDA +#include "externals.h" + +///////////////////////////////////////////////////////// +// starts/stops audio playing (addr==0 -> stop) +// note: no cdda support in PS2 plugins yet + +BOOL DoCDDAPlay(unsigned long addr) +{ + DWORD dw; + + LockGenCDAccess(); + + if(addr) dw=PlaySCSIAudio(addr,lMaxAddr-addr); // start playing (til end of cd) +// mmm... this stop doesn't work right +// else dw=PlayFunc(0,1); + else // funny stop... but seems to work + { + unsigned char cdb[3000]; + FRAMEBUF * f=(FRAMEBUF *)cdb; + + f->dwFrame = 16; // -> use an existing address (16 will ever exist on ps2 cds/dvds) + f->dwFrameCnt = 1; + f->dwBufLen = 2352; + + dw=pReadFunc(1,f); // -> do a simply sync read... seems to stop all audio playing + } + + UnlockGenCDAccess(); + + if(dw!=SS_COMP) return FALSE; + return TRUE; +} + +///////////////////////////////////////////////////////// +// get curr playing pos + +unsigned char * GetCDDAPlayPosition(void) +{ + unsigned char * pos; + + LockGenCDAccess(); + + pos=GetSCSIAudioSub(); // get the pos (scsi command) + + UnlockGenCDAccess(); + + return pos; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/cdda.h b/plugins/cdvd/CDVDpeops/cdda.h new file mode 100644 index 0000000000..b51a8d9171 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdda.h @@ -0,0 +1,28 @@ +/*************************************************************************** + cdda.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +BOOL DoCDDAPlay(unsigned long addr); +unsigned char * GetCDDAPlayPosition(void); diff --git a/plugins/cdvd/CDVDpeops/cdr.h b/plugins/cdvd/CDVDpeops/cdr.h new file mode 100644 index 0000000000..97492cf620 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdr.h @@ -0,0 +1,27 @@ +/*************************************************************************** + cdr.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// nothing yet diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.aps b/plugins/cdvd/CDVDpeops/cdvdPeops.aps new file mode 100644 index 0000000000000000000000000000000000000000..057382fddee8eeb5ef8ae2b598c6b3ec764560b7 GIT binary patch literal 23964 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 Hx8eLB@))32 literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.c b/plugins/cdvd/CDVDpeops/cdvdPeops.c new file mode 100644 index 0000000000..a1e5c04966 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.c @@ -0,0 +1,89 @@ +/*************************************************************************** + cdvdPeops.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// cdrPeops.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "cdvdPeops.h" +#define _IN_PEOPS +#include "externals.h" + +///////////////////////////////////////////////////////// + +HINSTANCE hInst=0; + +///////////////////////////////////////////////////////// +// get selected interface mode from registry: needed, +// if user has w2k and aspi available, so the plugin +// can know, what he wants to use + +int iGetUserInterfaceMode(void) +{ + HKEY myKey;DWORD temp;DWORD type;DWORD size; + int iRet=0; + + if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"InterfaceMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iRet=(int)temp; + RegCloseKey(myKey); + } + return iRet; +} + +///////////////////////////////////////////////////////// +// dll entry point + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + hInst=(HINSTANCE)hModule; + + switch (ul_reason_for_call) + {//--------------------------------------------------// + case DLL_PROCESS_ATTACH: + iInterfaceMode=iGetUserInterfaceMode(); // get interface on startup + OpenGenInterface(); // open interface (can be changed in the config window) + break; + //--------------------------------------------------// + case DLL_PROCESS_DETACH: + CloseGenInterface(); // close interface + break; + //--------------------------------------------------// + case DLL_THREAD_ATTACH: + break; + //--------------------------------------------------// + case DLL_THREAD_DETACH: + break; + //--------------------------------------------------// + } + return TRUE; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.def b/plugins/cdvd/CDVDpeops/cdvdPeops.def new file mode 100644 index 0000000000..90bdc5c8a9 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.def @@ -0,0 +1,30 @@ +; cdvdPeops.def : Declares the module parameters for the DLL. + +LIBRARY "cdvdPeops" + +EXPORTS + ; Explicit exports can go here + + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDconfigure @9 + CDVDabout @10 + CDVDtest @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDreadTrack @14 + CDVDgetBuffer @15 + CDVDgetDiskType @16 + CDVDgetTrayStatus @17 + CDVDreadSubQ @18 + CDVDgetTOC @19 + CDVDctrlTrayOpen @20 + CDVDctrlTrayClose @21 +; PS2EgetCpuPlatform @18 + + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.def.bak b/plugins/cdvd/CDVDpeops/cdvdPeops.def.bak new file mode 100644 index 0000000000..55d1203109 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.def.bak @@ -0,0 +1,30 @@ +; cdvdPeops.def : Declares the module parameters for the DLL. + +LIBRARY "cdvdPeops" + +EXPORTS + ; Explicit exports can go here + + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDconfigure @9 + CDVDabout @10 + CDVDtest @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDreadTrack @14 + CDVDgetBuffer @15 + CDVDgetDiskType @16 + CDVDgetTrayStatus @17 + PS2EgetCpuPlatform @18 + CDVDreadSubQ @19 + CDVDgetTOC @20 + CDVDctrlTrayOpen @21 + CDVDctrlTrayClose @22 + + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.dev b/plugins/cdvd/CDVDpeops/cdvdPeops.dev new file mode 100644 index 0000000000..968ed2bc77 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.dev @@ -0,0 +1,418 @@ +[Project] +FileName=cdvdPeops.dev +Name=cdvdPeops +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC_@@_ +CppCompiler=-D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC_@@_ +Includes=d:\vs\vc98\MFC\include +Linker=-lkernel32 -luser32 -ladvapi32 -lcomdlg32 --add-stdcall-alias_@@_ +Libs= +UnitCount=37 +Folders="Documentation files","Header Files","Resource Files","Source Files" +ObjFiles= +PrivateResource=cdvdPeops_private.rc +ResourceIncludes= +MakeIncludes= +Icon= +ExeOutput=..\..\..\emus\pcsx2_0.6\plugins +ObjectOutput=Release +OverrideOutput=1 +OverrideOutputName=cdvdPeops.dll +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile=OwnMakefile.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000001001000000000 + +[Unit1] +FileName=cdr.c +CompileCpp=0 +Folder="Source Files" +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=cdvdPeops.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=cdvdPeops.def +Folder="Source Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=cfg.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=generic.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=ioctrl.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=ppf.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=read.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=scsi.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=StdAfx.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=sub.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=toc.c +Folder="Source Files" +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=cdda.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=cdr.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=cdvdPeops.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=cfg.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=defines.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=externals.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=generic.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=ioctrl.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=ppf.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=read.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=resource.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=scsi.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=scsidefs.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=StdAfx.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=sub.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=toc.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=wnaspi32.h +Folder="Header Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=cdvdPeops.rc +Folder="Resource Files" +Compile=1 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=changelog.txt +Folder="Documentation files" +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=filemap.txt +Folder="Documentation files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=license.txt +Folder="Documentation files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=cdda.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c cdda.c -o cdda.o $(CFLAGS) + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=cdvdPeops.exe +ProductName=cdvdPeops +ProductVersion=0.1 +AutoIncBuildNr=0 + +[Unit35] +FileName=i386.asm +Folder=Source Files +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=1 +BuildCmd=nasmw.exe -f win32 -D__WIN32__ -D__i386__ i386.asm -o release\i386.o + +[Unit36] +FileName=PS2Edefs.h +CompileCpp=1 +Folder=Header Files +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=PS2Etypes.h +CompileCpp=1 +Folder=Header Files +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.dsp b/plugins/cdvd/CDVDpeops/cdvdPeops.dsp new file mode 100644 index 0000000000..1d4555c0ef --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.dsp @@ -0,0 +1,251 @@ +# Microsoft Developer Studio Project File - Name="cdvdPeops" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cdvdPeops - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cdvdPeops.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cdvdPeops.mak" CFG="cdvdPeops - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cdvdPeops - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cdvdPeops - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cdvdPeops - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib advapi32.lib comdlg32.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy release\*.dll d:\emus\pcsx2_07\plugins +# End Special Build Tool + +!ELSEIF "$(CFG)" == "cdvdPeops - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cdvdPeops - Win32 Release" +# Name "cdvdPeops - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\cdda.c +# End Source File +# Begin Source File + +SOURCE=.\cdr.c +# End Source File +# Begin Source File + +SOURCE=.\cdvdPeops.c +# End Source File +# Begin Source File + +SOURCE=.\cdvdPeops.def +# End Source File +# Begin Source File + +SOURCE=.\cfg.c +# End Source File +# Begin Source File + +SOURCE=.\generic.c +# End Source File +# Begin Source File + +SOURCE=.\ioctrl.c +# End Source File +# Begin Source File + +SOURCE=.\ppf.c +# End Source File +# Begin Source File + +SOURCE=.\read.c +# End Source File +# Begin Source File + +SOURCE=.\scsi.c +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.c +# End Source File +# Begin Source File + +SOURCE=.\sub.c +# End Source File +# Begin Source File + +SOURCE=.\toc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\cdda.h +# End Source File +# Begin Source File + +SOURCE=.\cdr.h +# End Source File +# Begin Source File + +SOURCE=.\cdvdPeops.h +# End Source File +# Begin Source File + +SOURCE=.\cfg.h +# End Source File +# Begin Source File + +SOURCE=.\defines.h +# End Source File +# Begin Source File + +SOURCE=.\externals.h +# End Source File +# Begin Source File + +SOURCE=.\generic.h +# End Source File +# Begin Source File + +SOURCE=.\ioctrl.h +# End Source File +# Begin Source File + +SOURCE=.\ppf.h +# End Source File +# Begin Source File + +SOURCE=".\PSEmu Plugin Defs.h" +# End Source File +# Begin Source File + +SOURCE=.\read.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\scsi.h +# End Source File +# Begin Source File + +SOURCE=.\scsidefs.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\sub.h +# End Source File +# Begin Source File + +SOURCE=.\toc.h +# End Source File +# Begin Source File + +SOURCE=.\wnaspi32.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\cdvdPeops.rc +# End Source File +# End Group +# Begin Group "Documentation files" + +# PROP Default_Filter "txt" +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# Begin Source File + +SOURCE=.\filemap.txt +# End Source File +# Begin Source File + +SOURCE=.\license.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.dsw b/plugins/cdvd/CDVDpeops/cdvdPeops.dsw new file mode 100644 index 0000000000..55e36029fc --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cdvdPeops"=.\cdvdPeops.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.h b/plugins/cdvd/CDVDpeops/cdvdPeops.h new file mode 100644 index 0000000000..87d277e88a --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.h @@ -0,0 +1,25 @@ +/*************************************************************************** + cdvdPeops.h - description + ------------------- + begin : Wed Nov 12 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.layout b/plugins/cdvd/CDVDpeops/cdvdPeops.layout new file mode 100644 index 0000000000..ebcf4cfa69 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.layout @@ -0,0 +1,238 @@ +[Editor_26] +CursorCol=1 +CursorRow=19 +TopLine=12 +LeftChar=1 +Open=0 +Top=0 +[Editors] +Order=0,35,11,4,10 +Focused=35 +[Editor_0] +Open=1 +Top=0 +CursorCol=39 +CursorRow=60 +TopLine=36 +LeftChar=1 +[Editor_1] +Open=0 +Top=0 +CursorCol=1 +CursorRow=23 +TopLine=1 +LeftChar=1 +[Editor_2] +Open=0 +Top=0 +CursorCol=2 +CursorRow=26 +TopLine=1 +LeftChar=1 +[Editor_3] +Open=0 +Top=0 +CursorCol=1 +CursorRow=438 +TopLine=428 +LeftChar=1 +[Editor_4] +Open=1 +Top=0 +CursorCol=19 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_5] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_6] +Open=0 +Top=0 +CursorCol=20 +CursorRow=20 +TopLine=1 +LeftChar=1 +[Editor_7] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_8] +Open=0 +Top=0 +CursorCol=19 +CursorRow=95 +TopLine=94 +LeftChar=1 +[Editor_9] +Open=0 +Top=0 +CursorCol=1 +CursorRow=8 +TopLine=1 +LeftChar=1 +[Editor_10] +Open=1 +Top=0 +CursorCol=17 +CursorRow=167 +TopLine=156 +LeftChar=1 +[Editor_11] +Open=1 +Top=0 +CursorCol=7 +CursorRow=99 +TopLine=70 +LeftChar=1 +[Editor_12] +Open=0 +Top=0 +[Editor_13] +Open=0 +Top=0 +CursorCol=27 +CursorRow=19 +TopLine=2 +LeftChar=1 +[Editor_14] +Open=0 +Top=0 +[Editor_15] +Open=0 +Top=0 +[Editor_16] +Open=0 +Top=0 +CursorCol=9 +CursorRow=112 +TopLine=95 +LeftChar=1 +[Editor_17] +Open=0 +Top=0 +CursorCol=1 +CursorRow=42 +TopLine=31 +LeftChar=1 +[Editor_18] +Open=0 +Top=0 +CursorCol=15 +CursorRow=15 +TopLine=16 +LeftChar=1 +[Editor_19] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_20] +Open=0 +Top=0 +[Editor_21] +Open=0 +Top=0 +[Editor_22] +Open=0 +Top=0 +[Editor_23] +Open=0 +Top=0 +CursorCol=18 +CursorRow=32 +TopLine=20 +LeftChar=1 +[Editor_24] +Open=0 +Top=0 +CursorCol=16 +CursorRow=258 +TopLine=544 +LeftChar=1 +[Editor_25] +Open=0 +Top=0 +CursorCol=1 +CursorRow=19 +TopLine=47 +LeftChar=1 +[Editor_27] +Open=0 +Top=0 +CursorCol=16 +CursorRow=22 +TopLine=1 +LeftChar=1 +[Editor_28] +Open=0 +Top=0 +CursorCol=83 +CursorRow=281 +TopLine=187 +LeftChar=1 +[Editor_29] +Open=0 +Top=0 +CursorCol=17 +CursorRow=210 +TopLine=1 +LeftChar=1 +[Editor_30] +Open=0 +Top=0 +CursorCol=47 +CursorRow=5 +TopLine=1 +LeftChar=1 +[Editor_31] +Open=0 +Top=0 +CursorCol=34 +CursorRow=19 +TopLine=1 +LeftChar=1 +[Editor_32] +Open=0 +Top=0 +CursorCol=13 +CursorRow=269 +TopLine=257 +LeftChar=1 +[Editor_33] +Open=0 +Top=0 +CursorCol=29 +CursorRow=20 +TopLine=1 +LeftChar=1 +[Editor_34] +Open=0 +Top=0 +CursorCol=1 +CursorRow=26 +TopLine=1 +LeftChar=1 +[Editor_35] +CursorCol=15 +CursorRow=282 +TopLine=39 +LeftChar=1 +Open=1 +Top=1 +[Editor_36] +Open=0 +Top=0 +CursorCol=1 +CursorRow=29 +TopLine=1 +LeftChar=1 diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.opt b/plugins/cdvd/CDVDpeops/cdvdPeops.opt new file mode 100644 index 0000000000000000000000000000000000000000..ed0495e33340205fae97c306affb7116c4f4e310 GIT binary patch literal 50688 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 B(#`+? literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.plg b/plugins/cdvd/CDVDpeops/cdvdPeops.plg new file mode 100644 index 0000000000..c020cb436b --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.plg @@ -0,0 +1,96 @@ + + +
+

Build Log

+

+--------------------Configuration: cdvdPeops - Win32 Release-------------------- +

+

Command Lines

+Creating command line "rc.exe /l 0x407 /fo"Release/cdvdPeops.res" /d "NDEBUG" "D:\src\cdvdPeops\src\cdvdPeops.rc"" +Creating temporary file "E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSP9E.tmp" with contents +[ +/nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR"Release/" /Fp"Release/cdvdPeops.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"D:\src\cdvdPeops\src\cdda.c" +"D:\src\cdvdPeops\src\cdr.c" +"D:\src\cdvdPeops\src\cdvdPeops.c" +"D:\src\cdvdPeops\src\cfg.c" +"D:\src\cdvdPeops\src\generic.c" +"D:\src\cdvdPeops\src\ioctrl.c" +"D:\src\cdvdPeops\src\ppf.c" +"D:\src\cdvdPeops\src\read.c" +"D:\src\cdvdPeops\src\scsi.c" +"D:\src\cdvdPeops\src\StdAfx.c" +"D:\src\cdvdPeops\src\sub.c" +"D:\src\cdvdPeops\src\toc.c" +] +Creating command line "cl.exe @E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSP9E.tmp" +Creating temporary file "E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSP9F.tmp" with contents +[ +kernel32.lib user32.lib advapi32.lib comdlg32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"Release/cdvdPeops.pdb" /machine:I386 /def:".\cdvdPeops.def" /out:"Release/cdvdPeops.dll" /implib:"Release/cdvdPeops.lib" +.\Release\cdda.obj +.\Release\cdr.obj +.\Release\cdvdPeops.obj +.\Release\cfg.obj +.\Release\generic.obj +.\Release\ioctrl.obj +.\Release\ppf.obj +.\Release\read.obj +.\Release\scsi.obj +.\Release\StdAfx.obj +.\Release\sub.obj +.\Release\toc.obj +.\Release\cdvdPeops.res +] +Creating command line "link.exe @E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSP9F.tmp" +

Output Window

+Compiling resources... +Compiling... +cdda.c +cdr.c +cdvdPeops.c +cfg.c +generic.c +ioctrl.c +ppf.c +read.c +scsi.c +StdAfx.c +sub.c +toc.c +Linking... + Creating library Release/cdvdPeops.lib and object Release/cdvdPeops.exp +Creating temporary file "E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSPA3.tmp" with contents +[ +/nologo /o"Release/cdvdPeops.bsc" +.\Release\cdda.sbr +.\Release\cdr.sbr +.\Release\cdvdPeops.sbr +.\Release\cfg.sbr +.\Release\generic.sbr +.\Release\ioctrl.sbr +.\Release\ppf.sbr +.\Release\read.sbr +.\Release\scsi.sbr +.\Release\StdAfx.sbr +.\Release\sub.sbr +.\Release\toc.sbr] +Creating command line "bscmake.exe @E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSPA3.tmp" +Creating browse info file... +

Output Window

+Creating temporary file "E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSPA4.bat" with contents +[ +@echo off +copy release\*.dll d:\emus\pcsx2_07\plugins +] +Creating command line "E:\DOCUME~1\Pete1\LOCALS~1\Temp\RSPA4.bat" + +release\cdvdPeops.dll + 1 file(s) copied. + + + +

Results

+cdvdPeops.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.rc b/plugins/cdvd/CDVDpeops/cdvdPeops.rc new file mode 100644 index 0000000000..83e137a969 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.rc @@ -0,0 +1,235 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,2,0 + PRODUCTVERSION 1,0,2,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040704b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Pete Bernert and the P.E.Op.S. team\0" + VALUE "FileDescription", "cdvdPeops\0" + VALUE "FileVersion", "1, 0, 2, 0\0" + VALUE "InternalName", "cdvdPeops\0" + VALUE "LegalCopyright", "Copyright © 2003-2004\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "cdvdPeops.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "cdvdPeops\0" + VALUE "ProductVersion", "1, 0, 2, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x407, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 287, 239 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure the P.E.Op.S. ASPI/IOCTL PS2 CDVD Driver..." +FONT 8, "MS Sans Serif" +BEGIN + COMBOBOX IDC_IMODE,63,6,199,52,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_DRIVE,63,22,199,52,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_CACHE,63,39,199,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Use additional 4 MByte data cache",IDC_DATACACHE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,63,55,156,11 + CONTROL "Try to limit speed (not supported by all drives)", + IDC_SPEEDLIMIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13, + 76,156,11 + COMBOBOX IDC_SPEED,204,75,33,93,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Don't wait until drive is ready (needed by a few drives)", + IDC_NOWAIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,89, + 198,11 + CONTROL "Check tray state (not tested, you can leave that off)", + IDC_TRAYSTATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13, + 102,186,11 + CONTROL "Try again on reading error. Retry count (1-10):", + IDC_TRYAGAIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13, + 129,156,11 + EDITTEXT IDC_RETRY,204,128,33,13,ES_AUTOHSCROLL + CONTROL "Show message box on reading error",IDC_SHOWREADERR, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,142,156,11 + CONTROL "Use PPF patch file:",IDC_USEPPF,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,13,168,74,11 + EDITTEXT IDC_PPFFILE,89,168,167,12,ES_AUTOHSCROLL | WS_DISABLED + PUSHBUTTON "...",IDC_CHOOSEFILE,259,168,13,12,WS_DISABLED + COMBOBOX IDC_SUBCHAN0,13,197,261,52,CBS_DROPDOWNLIST | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_SUBFILE,63,197,193,12,ES_AUTOHSCROLL | WS_DISABLED + PUSHBUTTON "...",IDC_CHOOSESUBF,259,197,13,12,WS_DISABLED + DEFPUSHBUTTON "OK",IDOK,63,221,50,14 + PUSHBUTTON "Cancel",IDCANCEL,175,221,50,14 + RTEXT "Drive:",IDC_STATIC,37,24,21,11 + RTEXT "Caching mode:",IDC_STATIC,9,41,49,11 + GROUPBOX "Error handling",IDC_STATIC,6,119,275,38 + GROUPBOX "PPF patches",IDC_STATIC,6,158,275,28 + GROUPBOX "Misc",IDC_STATIC,6,66,275,52 + RTEXT "Interface:",IDC_STATIC,15,8,43,11 + GROUPBOX "Subchannel reading",IDC_STATIC,6,187,275,29 + RTEXT "File:",IDC_SFSTATIC,26,198,30,11,SS_CENTERIMAGE +END + +IDD_ABOUT DIALOGEX 0, 0, 238, 210 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About the P.E.Op.S. ASPI/IOCTL PS2 CDVD Driver..." +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,98,188,44,14 + RTEXT "Version :",IDC_STATIC,5,5,74,9 + RTEXT "Release date :",IDC_STATIC,5,16,74,9 + RTEXT "Coded by :",IDC_STATIC,5,27,74,9 + RTEXT "Pete's EMail :",IDC_STATIC,5,40,74,9 + RTEXT "Pete's homepage :",IDC_STATIC,5,51,74,9 + LTEXT "1.2",IDC_STATIC,82,5,154,9 + LTEXT "25.12.2004",IDC_STATIC,81,16,154,9 + LTEXT "Pete Bernert and the P.E.Op.S. team",IDC_STATIC,81,27, + 154,9 + LTEXT "BlackDove@addcom.de",IDC_STATIC,81,39,154,9 + LTEXT "http://www.pbernert.com",IDC_STATIC,81,51,154,9 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,9,100,218,81, + WS_EX_DLGMODALFRAME + RTEXT "Thanks to :",IDC_STATIC,16,109,38,9 + LTEXT "the PCSX2 team - special thanx to shadow for kicking my ass", + IDC_STATIC,57,109,161,18 + LTEXT "My girlfriend Heike... because everything I do wouldn't be the same without her", + IDC_STATIC,57,130,161,19 + RTEXT "P.E.Op.S. homepage :",IDC_STATIC,5,80,74,9 + LTEXT "https://sourceforge.net/projects/peops/",IDC_STATIC,81, + 80,154,9 + RTEXT "linuzappz :",IDC_STATIC,10,63,69,10 + LTEXT "http://www.pcsx.net",IDC_STATIC,81,63,142,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 280 + TOPMARGIN, 7 + BOTTOMMARGIN, 232 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 231 + TOPMARGIN, 7 + BOTTOMMARGIN, 203 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.sln b/plugins/cdvd/CDVDpeops/cdvdPeops.sln new file mode 100644 index 0000000000..3793c5cbad --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdvdPeops", "cdvdPeops.vcproj", "{74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Debug.ActiveCfg = Debug|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Debug.Build.0 = Debug|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Release.ActiveCfg = Release|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops.vcproj b/plugins/cdvd/CDVDpeops/cdvdPeops.vcproj new file mode 100644 index 0000000000..d41dd3a44c --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops.vcproj @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops_2005.sln b/plugins/cdvd/CDVDpeops/cdvdPeops_2005.sln new file mode 100644 index 0000000000..8f88a950c3 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops_2005.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdvdPeops", "cdvdPeops_2005.vcproj", "{74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Debug|Win32.ActiveCfg = Debug|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Debug|Win32.Build.0 = Debug|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Release|Win32.ActiveCfg = Release|Win32 + {74689B0D-A4E7-4D0E-A2D8-8A30EA455BC6}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops_2005.vcproj b/plugins/cdvd/CDVDpeops/cdvdPeops_2005.vcproj new file mode 100644 index 0000000000..bee2498b69 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops_2005.vcproj @@ -0,0 +1,649 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops_private.h b/plugins/cdvd/CDVDpeops/cdvdPeops_private.h new file mode 100644 index 0000000000..18a8395542 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops_private.h @@ -0,0 +1,23 @@ +// THIS FILE WILL BE OVERWRITTEN BY DEV-C++! +// DO NOT EDIT! + +#ifndef CDVDPEOPS_PRIVATE_H +#define CDVDPEOPS_PRIVATE_H + +// VERSION DEFINITIONS +#define VER_STRING "0.1.1.1" +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_RELEASE 1 +#define VER_BUILD 1 +#define COMPANY_NAME "" +#define FILE_VERSION "0.1" +#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" +#define INTERNAL_NAME "" +#define LEGAL_COPYRIGHT "" +#define LEGAL_TRADEMARKS "" +#define ORIGINAL_FILENAME "cdvdPeops.exe" +#define PRODUCT_NAME "cdvdPeops" +#define PRODUCT_VERSION "0.1" + +#endif //CDVDPEOPS_PRIVATE_H diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops_private.rc b/plugins/cdvd/CDVDpeops/cdvdPeops_private.rc new file mode 100644 index 0000000000..ae59fb028f --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cdvdPeops_private.rc @@ -0,0 +1,4 @@ +// THIS FILE WILL BE OVERWRITTEN BY DEV-C++! +// DO NOT EDIT! + +#include "cdvdPeops.rc" diff --git a/plugins/cdvd/CDVDpeops/cdvdPeops_private.res b/plugins/cdvd/CDVDpeops/cdvdPeops_private.res new file mode 100644 index 0000000000000000000000000000000000000000..73dde28c621dce1432cf712a4a113338b41a6e36 GIT binary patch literal 4584 zcmcIo%WqUw82`<50C`laL}I|l#VAFEK4>F>kd!_k7AYMlG+<)PbUH0#+v#LxN`X}& zA#ueYV2Ht$xRQk{A4y%HE?5|rCb~9J!M8*c@%Q`AJ#+6J23Q!+mmvaAI6DZ{35=GUvYHbA2UWVY##lcrDhy-O9}pCM?VN za!Jii)_*2-%j!YQql76GF^vUOP@s%8oU}TN4(#JIN_jgl#wS2O>nw)R$!8RUIEsTD z&2n@H>p=`*oKL`~LYk*Yr^0>u0S{q>>jFMG@~m1*^F{KP-Zy6jsShjh1$yy&%bhzH zG{6$gZLqoTn$ERzt{>kg=29Weow$UxxZN^9DQo;mYTy`ANa7qO`73g~Xfrv?afd~6)zYFucPaD6`S!oer%$LR-C}+#CNj+-;hb& zZoC&Mn=}y+Ly2{Jl24gEnx8;c)iZ1@DVZn(ST{t^qa>F zch|@*XPl~R%L=kbq%ZX~BktQcbB6LPu$G-ltYEeZkGO!4QmCm-{8&Y2B= zZouPhnBz&2hD29h6lp?Z)9lNqE1Z+(2ROpM@Jmm5!zHZ>eK)rA=^}#N&W#vU&Y8bn zXKOQBaf>!Q7tTfaE*id{8t{!#U-PExIdZJ>C#2HT1jkRaeh}KaFEf0B+^^sO?ea?l zAAe@DJoWoYwM;%WI}Nh7yrmGA$7r1(t@p4FzsBTYM7Ft>)D`kthu=82RF4&Q=0hCU zup-rqKV$w(J=t6zuHiH8{i`Y6Yex6)2D+)x&VBfXG3#OG1@Rr_sqw}6!3W`d+U5r- zWr6kBAB%h5rheUO+PS;FPV^K(ywA+hI+JzHF_atam9*#j z)E1+?#8~Y8D&S7xnIsxV!C{K_y~BM^hWqZel>9>_T0g+`z2W*1(yS7lD<1zNjNdQS z@eh-`&Rc~xmn4zRBbpzR=2IcfF`mZ>lUTSFEfmFk42jE-PCMB*GEzNFerq$*>;8mi z$z~xuD6g%z&Q08~y5BrrasL0zWn`7QUq18r6TN8V-TrV$Z zr@sXB&k_29%NNb|_S|Q$Vwd8UqKS)INeZT=>=Ekd?U;_b885oMLh5xodl+qrbvv+& zE4$Fc_YT%w%9d1l+exPsMhcCHUbLc<$IV$W zDW~U{V&gH!qt)E^H4dA9j*+UOevud(i+rn%xVOaYbTo`tGv+7m7SznXySVRNa?|P7 z8HjG8gS<5!w>zfSY(TmE{V7i*?#`wivXAne<5RVfN$NoNkSW#`)-#4(Z?hy-Ki{u_hQ{E zqYN<2l|mU1r*1E^?3L&%@;Fh5{7so%w$)1A)O2=Sw9~!45{J&VJL}novv>E+{=p|u zK9_CkbJfu6s)nROX$zsIb(T9Qhdiv4-l==ho9yM;ui8j~BV}tRfeZH(E9-rgC)S}ohPJerY?|r<#joG)( zA@+xHh?!{A7Jiz!^^g0iOtBw5eU1z={H4RTufDYbogR6NJkRGfjEz`mq&Y(*-d-8?dINPZ{OBIB(*p_eG4c?7iftb+lp(x3|XEZ z4SC7RLg4MJo~+kQM~ck)x&xjyep#b&iaR8^zFd`CCqqU~FIuC#yk}9&0IDb Ux|?3Dx0dUz_`f$gb1g>kU*jg);Q#;t literal 0 HcmV?d00001 diff --git a/plugins/cdvd/CDVDpeops/cfg.h b/plugins/cdvd/CDVDpeops/cfg.h new file mode 100644 index 0000000000..dfa285b4d5 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/cfg.h @@ -0,0 +1,47 @@ +/*************************************************************************** + cfg.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void ReadConfig(void); +void WriteConfig(void); +void OnChooseFile(HWND hW,int iFType); +void EnumDrives(HWND hW); +void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL); +void OnIMode(HWND hW); +void OnCache(HWND hW); +void ShowSubFileStuff(HWND hW); +BOOL OnInitCDRDialog(HWND hW); +void OnCDRAuto(HWND hW); +void ShowProgress(HWND hW,long lact,long lmin,long lmax); +void WriteDiffSub(FILE * xfile,int i,unsigned char * lpX,int iM,BOOL b3Min); +BOOL OnCreateSubFileEx(HWND hW,HWND hWX,BOOL b3Min); +BOOL OnCreateSubEx(HWND hW,HWND hWX,int iM,BOOL b3Min); +void StartSubReading(HWND hW,HWND hWX); +BOOL CALLBACK SubDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +void OnCreateSub(HWND hW); +void OnCDROK(HWND hW); +void OnCDRCancel(HWND hW); +BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/plugins/cdvd/CDVDpeops/changelog.txt b/plugins/cdvd/CDVDpeops/changelog.txt new file mode 100644 index 0000000000..83c8f0a391 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/changelog.txt @@ -0,0 +1,19 @@ +######################################################################### + +Version 1.2 +----------- +- Pete: added an hack in CDVDgetTD for big dvds +- Pete: fixed a track size calculation bug + + +Version 1.1 +----------- +- Pete: added dvd support for Plextor PX-708A + +Version 1.0 +----------- +- First release + Pete Bernert: ported the P.E.Op.S. PSX cdr plugin to PS2 needs + +######################################################################### + diff --git a/plugins/cdvd/CDVDpeops/defines.h b/plugins/cdvd/CDVDpeops/defines.h new file mode 100644 index 0000000000..5ead0e7501 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/defines.h @@ -0,0 +1,212 @@ +/*************************************************************************** + defines.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +// general buffer for reading several frames + +#pragma pack(1) + +typedef struct _FRAMEBUF +{ + DWORD dwFrame; + DWORD dwFrameCnt; + DWORD dwBufLen; + unsigned char BufData[1024*1024]; +} FRAMEBUF; + +#pragma pack() + +// raw ioctl structs: + +typedef enum _TRACK_MODE_TYPE +{ + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +typedef struct _RAW_READ_INFO +{ + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +// sub cache: + +typedef struct +{ + long addr; + void * pNext; + unsigned char subq[10]; +} SUB_DATA; + +typedef struct +{ + long addr; + void * pNext; +} SUB_CACHE; + +// ppf cache: + +typedef struct +{ + long addr; + void * pNext; + long pos; + long anz; + // memdata +} PPF_DATA; + +typedef struct +{ + long addr; + void * pNext; +} PPF_CACHE; + +///////////////////////////////////////////////////////// + +#define MODE_BE_1 1 +#define MODE_BE_2 2 +#define MODE_28_1 3 +#define MODE_28_2 4 +#define MODE_28_2048 5 +#define MODE_28_2048_Ex 6 + +#define itob(i) ((i)/10*16 + (i)%10) +#define btoi(b) ((b)/16*10 + (b)%16) +#define itod(i) ((((i)/10)<<4) + ((i)%10)) +#define dtoi(b) ((((b)>>4)&0xf)*10 + (((b)&0xf)%10)) + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time); +void addr2timeB(unsigned long addr, unsigned char *time); +unsigned long time2addr(unsigned char *time); +unsigned long time2addrB(unsigned char *time); +#ifdef _GCC +#define reOrder i386_reOrder +#endif +unsigned long reOrder(unsigned long value); + +///////////////////////////////////////////////////////// +// debug helper + +#ifndef _IN_CDR +#ifdef DBGOUT +void auxprintf (LPCTSTR pFormat, ...); +#endif +#endif + +///////////////////////////////////////////////////////// + +typedef DWORD (*READFUNC)(BOOL bWait,FRAMEBUF * f); +typedef DWORD (*DEINITFUNC)(void); +typedef BOOL (*READTRACKFUNC)(unsigned long addr); +typedef void (*GETPTRFUNC)(void); + +///////////////////////////////////////////////////////// + +#define WAITFOREVER 0xFFFFFFFF +#define WAITSUB 10000 +#define FRAMEBUFEXTRA 12 +#define CDSECTOR 2352 +#define MAXCACHEBLOCK 26 +#define MAXCDBUFFER (((MAXCACHEBLOCK+1)*(CDSECTOR+16))+240) + +///////////////////////////////////////////////////////// + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#pragma pack(1) + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +}; //+22 + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +}; + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +}; + +#pragma pack() + + diff --git a/plugins/cdvd/CDVDpeops/defines.h.bak b/plugins/cdvd/CDVDpeops/defines.h.bak new file mode 100644 index 0000000000..7926e945e7 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/defines.h.bak @@ -0,0 +1,213 @@ +/*************************************************************************** + defines.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +// general buffer for reading several frames + +#pragma pack(1) + +typedef struct _FRAMEBUF +{ + DWORD dwFrame; + DWORD dwFrameCnt; + DWORD dwBufLen; + unsigned char BufData[1024*1024]; +} FRAMEBUF; + +#pragma pack() + +// raw ioctl structs: + +typedef enum _TRACK_MODE_TYPE +{ + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +typedef struct _RAW_READ_INFO +{ + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +// sub cache: + +typedef struct +{ + long addr; + void * pNext; + unsigned char subq[10]; +} SUB_DATA; + +typedef struct +{ + long addr; + void * pNext; +} SUB_CACHE; + +// ppf cache: + +typedef struct +{ + long addr; + void * pNext; + long pos; + long anz; + // memdata +} PPF_DATA; + +typedef struct +{ + long addr; + void * pNext; +} PPF_CACHE; + +///////////////////////////////////////////////////////// + +#define MODE_BE_1 1 +#define MODE_BE_2 2 +#define MODE_28_1 3 +#define MODE_28_2 4 +#define MODE_28_2048 5 +#define MODE_28_2048_Ex 6 + +u8 __inline itob(u32 i); + +#define btoi(b) ((b)/16*10 + (b)%16) +#define itod(i) ((((i)/10)<<4) + ((i)%10)) +#define dtoi(b) ((((b)>>4)&0xf)*10 + (((b)&0xf)%10)) + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time); +void addr2timeB(unsigned long addr, unsigned char *time); +unsigned long time2addr(unsigned char *time); +unsigned long time2addrB(unsigned char *time); +#ifdef _GCC +#define reOrder i386_reOrder +#endif +unsigned long reOrder(unsigned long value); + +///////////////////////////////////////////////////////// +// debug helper + +#ifndef _IN_CDR +#ifdef DBGOUT +void auxprintf (LPCTSTR pFormat, ...); +#endif +#endif + +///////////////////////////////////////////////////////// + +typedef DWORD (*READFUNC)(BOOL bWait,FRAMEBUF * f); +typedef DWORD (*DEINITFUNC)(void); +typedef BOOL (*READTRACKFUNC)(unsigned long addr); +typedef void (*GETPTRFUNC)(void); + +///////////////////////////////////////////////////////// + +#define WAITFOREVER 0xFFFFFFFF +#define WAITSUB 10000 +#define FRAMEBUFEXTRA 12 +#define CDSECTOR 2352 +#define MAXCACHEBLOCK 26 +#define MAXCDBUFFER (((MAXCACHEBLOCK+1)*(CDSECTOR+16))+240) + +///////////////////////////////////////////////////////// + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#pragma pack(1) + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +}; //+22 + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +}; + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +}; + +#pragma pack() + + diff --git a/plugins/cdvd/CDVDpeops/externals.h b/plugins/cdvd/CDVDpeops/externals.h new file mode 100644 index 0000000000..95d8d3c667 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/externals.h @@ -0,0 +1,177 @@ +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDDA + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDR + +extern BOOL bIsOpen; +extern BOOL bCDDAPlay; +extern int iCDROK; +extern char *libraryName; +extern int iCheckTrayStatus; +extern void *fdump; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PEOPS + +extern HINSTANCE hInst; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CFG + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_GENERIC + +extern int iCD_AD; +extern int iCD_TA; +extern int iCD_LU; +extern int iRType; +extern int iUseSpeedLimit; +extern int iSpeedLimit; +extern int iNoWait; +extern int iMaxRetry; +extern int iShowReadErr; +extern HANDLE hEvent; +extern HINSTANCE hASPI; +extern READFUNC pReadFunc; +extern DEINITFUNC pDeInitFunc; +extern int iInterfaceMode; +extern int iWantedBlockSize; +extern int iUsedBlockSize; +extern int iUsedMode; +extern int iBlockDump; + +extern DWORD (*pGetASPI32SupportInfo)(void); +extern DWORD (*pSendASPI32Command)(LPSRB); + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_IOCTL + +extern HANDLE hIOCTL; +extern DWORD dwIOCTLAttr; +extern OVERLAPPED ovcIOCTL; +extern SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; +extern RAW_READ_INFO rawIOCTL; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PPF + +extern int iUsePPF; +extern char szPPF[]; +extern PPF_CACHE * ppfCache; +extern PPF_DATA * ppfHead; +extern int iPPFNum; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_READ + +extern READTRACKFUNC pReadTrackFunc; +extern GETPTRFUNC pGetPtrFunc; + +extern int iUseCaching; +extern int iUseDataCache; +extern int iTryAsync; +extern int iBufSel; + +extern unsigned char * pMainBuffer; +extern unsigned char * pCurrReadBuf; +extern unsigned char * pFirstReadBuf; +extern unsigned char * pAsyncBuffer; + +extern unsigned long lMaxAddr; +extern unsigned long lLastAddr; +extern unsigned long lLastAsyncAddr; + +extern unsigned char * ptrBuffer[]; +extern unsigned char * pAsyncFirstReadBuf[]; +extern unsigned long lLastAccessedAddr; +extern int iLastAccessedMode; + +extern HANDLE hReadThread; +extern BOOL bThreadEnded; +extern HANDLE hThreadEvent[]; +extern HANDLE hThreadMutex[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SCSI + +extern SRB_ExecSCSICmd sx; +extern BOOL bDoWaiting; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SUB + +extern unsigned char * pCurrSubBuf; +extern int iUseSubReading; +extern char szSUBF[]; +extern SUB_CACHE * subCache; +extern SUB_DATA * subHead; +extern int iSUBNum; +extern unsigned char SubCData[]; +extern unsigned char SubAData[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_TOC + +extern TOC sTOC; + +#endif + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/externals.h.bak b/plugins/cdvd/CDVDpeops/externals.h.bak new file mode 100644 index 0000000000..c0ffb37b71 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/externals.h.bak @@ -0,0 +1,175 @@ +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDDA + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDR + +extern BOOL bIsOpen; +extern BOOL bCDDAPlay; +extern int iCDROK; +extern char *libraryName; +extern int iCheckTrayStatus; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PEOPS + +extern HINSTANCE hInst; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CFG + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_GENERIC + +extern int iCD_AD; +extern int iCD_TA; +extern int iCD_LU; +extern int iRType; +extern int iUseSpeedLimit; +extern int iSpeedLimit; +extern int iNoWait; +extern int iMaxRetry; +extern int iShowReadErr; +extern HANDLE hEvent; +extern HINSTANCE hASPI; +extern READFUNC pReadFunc; +extern DEINITFUNC pDeInitFunc; +extern int iInterfaceMode; +extern int iWantedBlockSize; +extern int iUsedBlockSize; +extern int iUsedMode; + +extern DWORD (*pGetASPI32SupportInfo)(void); +extern DWORD (*pSendASPI32Command)(LPSRB); + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_IOCTL + +extern HANDLE hIOCTL; +extern DWORD dwIOCTLAttr; +extern OVERLAPPED ovcIOCTL; +extern SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; +extern RAW_READ_INFO rawIOCTL; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PPF + +extern int iUsePPF; +extern char szPPF[]; +extern PPF_CACHE * ppfCache; +extern PPF_DATA * ppfHead; +extern int iPPFNum; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_READ + +extern READTRACKFUNC pReadTrackFunc; +extern GETPTRFUNC pGetPtrFunc; + +extern int iUseCaching; +extern int iUseDataCache; +extern int iTryAsync; +extern int iBufSel; + +extern unsigned char * pMainBuffer; +extern unsigned char * pCurrReadBuf; +extern unsigned char * pFirstReadBuf; +extern unsigned char * pAsyncBuffer; + +extern unsigned long lMaxAddr; +extern unsigned long lLastAddr; +extern unsigned long lLastAsyncAddr; + +extern unsigned char * ptrBuffer[]; +extern unsigned char * pAsyncFirstReadBuf[]; +extern unsigned long lLastAccessedAddr; +extern int iLastAccessedMode; + +extern HANDLE hReadThread; +extern BOOL bThreadEnded; +extern HANDLE hThreadEvent[]; +extern HANDLE hThreadMutex[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SCSI + +extern SRB_ExecSCSICmd sx; +extern BOOL bDoWaiting; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SUB + +extern unsigned char * pCurrSubBuf; +extern int iUseSubReading; +extern char szSUBF[]; +extern SUB_CACHE * subCache; +extern SUB_DATA * subHead; +extern int iSUBNum; +extern unsigned char SubCData[]; +extern unsigned char SubAData[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_TOC + +extern TOC sTOC; + +#endif + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/filemap.txt b/plugins/cdvd/CDVDpeops/filemap.txt new file mode 100644 index 0000000000..e111546181 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/filemap.txt @@ -0,0 +1,52 @@ +######################################################################### + +- cdr.c / cdr.h + main plugin interface funcs + +- cdda.c / cdda.h + audio playing funcs + +- cfg.c / cfg.h + configuration dialogs/file reading funcs + +- cdvdPeops.* + Windows dll related files (including msvc/devc++ project files) + +- generic.c / generic.h + generic stuff + +- ioctrl.c / ioctrl.h + w2k/xp ioctl functions + +- ppf.c / ppf.h + ppf caching funcs + +- read.c / read.h + the different read caching modes + +- scsi.c / scsi.h + all the used scsi commands + +- stdafx.h + main include file + +- sub.c / sub.h + sub data caching + +- toc.c / toc.h + toc related funcs + +- externals.h + generic defines/external vars + +- defines.h + typedef structs/defines/inline funcs + +- resource.h + Windows resource header + +- i386.asm + NASM funcs + +######################################################################### + diff --git a/plugins/cdvd/CDVDpeops/generic.c b/plugins/cdvd/CDVDpeops/generic.c new file mode 100644 index 0000000000..f54a29555d --- /dev/null +++ b/plugins/cdvd/CDVDpeops/generic.c @@ -0,0 +1,386 @@ +/*************************************************************************** + generic.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - repaired time2addr/addr2time +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_GENERIC +#include "externals.h" + +///////////////////////////////////////////////////////// + +int iCD_AD=-1; // drive address +int iCD_TA=-1; +int iCD_LU=-1; +int iRType=0; // read mode +int iUseSpeedLimit=0; // speed limit use +int iSpeedLimit=2; // speed 2x +int iNoWait=0; // wait +int iMaxRetry=5; // retry on error +int iShowReadErr=0; // show msg on error +HANDLE hEvent=NULL; // global event +HINSTANCE hASPI=NULL; // aspi lib +READFUNC pReadFunc=NULL; // read func +DEINITFUNC pDeInitFunc=NULL; // deinit func +int iInterfaceMode=1; // interface (aspi/ioctrlscsi/ioctrlraw) +int iWantedBlockSize=2352; +int iUsedBlockSize=2352; +int iUsedMode=CDVD_MODE_2352; +int iBlockDump=0; + +DWORD (*pGetASPI32SupportInfo)(void); // ptrs to aspi funcs +DWORD (*pSendASPI32Command)(LPSRB); + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time) +{ + addr+=150; + time[3] = (unsigned char)(addr%75); + addr/=75; + time[2]=(unsigned char)(addr%60); + addr/=60; + time[1]=(unsigned char)(addr%100); + time[0]=(unsigned char)(addr/100); +} + +void addr2timeB(unsigned long addr, unsigned char *time) +{ + time[3] = itob((unsigned char)(addr%75)); + addr/=75; + time[2]=itob((unsigned char)(addr%60)); + addr/=60; + time[1]=itob((unsigned char)(addr%100)); + time[0]=itob((unsigned char)(addr/100)); +} + +unsigned long time2addr(unsigned char *time) +{ + unsigned long addr; + + addr = time[0]*100; + addr += time[1]; + addr *= 60; + + addr = (addr + time[2])*75; + addr += time[3]; + addr -= 150; + return addr; +} + +unsigned long time2addrB(unsigned char *time) +{ + unsigned long addr; + + addr = (btoi(time[0]))*100; + addr += btoi(time[1]); + addr *= 60; + addr = (addr + btoi(time[2]))*75; + addr += btoi(time[3]); + addr -= 150; + return addr; +} + +#ifndef _GCC + +#ifdef __x86_64__ +unsigned long reOrder(unsigned long value) +{ + return ((value&0xff)<<24)|((value&0xff00)<<8)|((value&0xff0000)>>8)|(value>>24); +} +#else +unsigned long reOrder(unsigned long value) +{ +#pragma warning (disable: 4035) + __asm + { + mov eax,value + bswap eax + } +} +#endif +#endif + +///////////////////////////////////////////////////////// + +void CreateGenEvent(void) +{ + hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); +} + +///////////////////////////////////////////////////////// + +void FreeGenEvent(void) +{ + if(hEvent) CloseHandle(hEvent); + hEvent=0; +} + +///////////////////////////////////////////////////////// + +DWORD WaitGenEvent(DWORD dwMS) +{ + if(hASPI) // aspi event + return WaitForSingleObject(hEvent,dwMS); + else + { // ioctl overlapped (always waiting til finished, dwMS not used) + DWORD dwR=0; + GetOverlappedResult(hIOCTL,&ovcIOCTL,&dwR,TRUE); + return 0; + } +} + +///////////////////////////////////////////////////////// + +void LockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + WaitForSingleObject(hThreadMutex[0],INFINITE); // -> wait until all reading is done + else // async prefetch? + if(bDoWaiting) // -> async operation has to finish first + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} +} + +///////////////////////////////////////////////////////// + +void UnlockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + ReleaseMutex(hThreadMutex[0]); // -> we are finished with our special command, now reading can go on +} + +///////////////////////////////////////////////////////// + +void WaitUntilDriveIsReady(void) +{ + if(iNoWait==0) + { + while(TestSCSIUnitReady()==0) Sleep(500); + } +} + +///////////////////////////////////////////////////////// + +void SetGenCDSpeed(int iReset) +{ + if(iUseSpeedLimit) + { + if(bDoWaiting) // still a command running? wait + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} + + if(iReset) SetSCSISpeed(0xFFFF); + else + if(SetSCSISpeed(176*iSpeedLimit)<=0) + { + MessageBox(GetActiveWindow(), + "Failure: cannot change the drive speed!", + "cdvdPeops... speed limitation", + MB_OK|MB_ICONEXCLAMATION); + iUseSpeedLimit=0; + } + } +} + +///////////////////////////////////////////////////////// +// checks, which direct subchannel reading type is supported + +void GetBESubReadFunc(void) +{ + unsigned char * pB=(unsigned char *)malloc(4096); + + pReadFunc = ReadSCSI_BE_Sub; // pre-init read func + + WaitUntilDriveIsReady(); // wait before first read + + ReadSub_BE_2(0,pB,1); // first (unchecked) read + if(!ReadSub_BE_2(0,pB,1)) // read again, and check this time + { // -> read failed? + if(ReadSub_BE_2_1(0,pB,1)) // -> try different sub reading + { // --> success? mmm... let us check the data + DecodeSub_BE_2_1(pB+2352); // --> decode sub + if(*(pB+2352)==0x41) // --> check the first decoded byte + pReadFunc = ReadSCSI_BE_Sub_1; // ---> wow, byte is ok + } + } + free(pB); +} + +///////////////////////////////////////////////////////// + +int GetGenReadFunc(int iRM) +{ + switch(iRM) // scsi read mode + { + // ------------------------------------------------ // + case MODE_BE_1: + case MODE_BE_2: + { + if(iUseSubReading==1) + GetBESubReadFunc(); + else pReadFunc = ReadSCSI_BE; + } break; + // ------------------------------------------------ // + case MODE_28_1: + case MODE_28_2: + { + if(iUseSubReading==1) + pReadFunc = ReadSCSI_28_Sub; + else pReadFunc = ReadSCSI_28; + } break; + // ------------------------------------------------ // + case MODE_28_2048: + { + pReadFunc = ReadSCSI_28_2048; + } break; + // ------------------------------------------------ // + case MODE_28_2048_Ex: + { + pReadFunc = ReadSCSI_28_2048_Ex; + } break; + // ------------------------------------------------ // + default: + { + pReadFunc = ReadSCSI_Dummy; + } return -3; + // ------------------------------------------------ // + } + return 1; +} + +///////////////////////////////////////////////////////// + +int OpenGenCD(int iA,int iT,int iL) +{ + pDeInitFunc = NULL; // init de-init func + pReadFunc = ReadSCSI_Dummy; // init (dummy) read func + + if(iA==-1) return -1; // not configured properly + + // -------------------------------------------------- // + + if(iInterfaceMode>1) // ioctrl interfaces? + { + OpenIOCTLHandle(iA,iT,iL); // open w2k/xp ioctrl device + if(hIOCTL==NULL) return -2; // no cdrom available + + if(iInterfaceMode==3) // special ioctl RAW mode? + { // -> get special reading funcs (non-scsi!) + if(iUseSubReading==1) + pReadFunc = ReadIOCTL_Raw_Sub; + else pReadFunc = ReadIOCTL_Raw; + + WaitUntilDriveIsReady(); + return 1; + } + } + else // aspi interface? + { + int iDevice=GetSCSIDevice(iA,iT,iL); // get device type + if(iDevice!=DTYPE_CDROM) return -2; // no cdrom? bye + } + + if(CheckSCSIReadMode()==SS_COMP) + WaitUntilDriveIsReady(); + else + { + CloseIOCTLHandle(); + return -3; + } + + return 1; +} + +///////////////////////////////////////////////////////// + +void CloseGenCD(void) +{ + iCDROK=0; // no more cd available + if(pDeInitFunc) pDeInitFunc(); // deinit, if needed + pDeInitFunc = NULL; + pReadFunc = ReadSCSI_Dummy; + CloseIOCTLHandle(); // close ioctl drive file (if used) +} + +///////////////////////////////////////////////////////// + +void OpenGenInterface(void) +{ + hASPI=NULL; + + if(iInterfaceMode==0) return; // no interface? no fun + else + if(iInterfaceMode==1) // aspi + { + hASPI=LoadLibrary("WNASPI32.DLL"); + if(hASPI) + { + pGetASPI32SupportInfo = + (DWORD(*)(void)) GetProcAddress(hASPI,"GetASPI32SupportInfo"); + pSendASPI32Command = + (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command"); + + if(!pGetASPI32SupportInfo || !pSendASPI32Command) + { + iInterfaceMode=0; + return; + } + } + } + else // ioctl + { + if(iInterfaceMode<2 || iInterfaceMode>3) iInterfaceMode=2; + pGetASPI32SupportInfo = NULL; + pSendASPI32Command = IOCTLSendASPI32Command; + } +} + +///////////////////////////////////////////////////////// + +void CloseGenInterface(void) +{ + pGetASPI32SupportInfo=NULL; // clear funcs + pSendASPI32Command=NULL; + + if(hASPI) // free aspi + { + FreeLibrary(hASPI); + hASPI=NULL; + } + else CloseIOCTLHandle(); // or close ioctl file +} + +///////////////////////////////////////////////////////// + +int GetGenCDDrives(char * pDList) +{ + if(hASPI) return GetSCSICDDrives(pDList); // aspi? use it + return GetIOCTLCDDrives(pDList); // or use ioctl +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/generic.c.bak b/plugins/cdvd/CDVDpeops/generic.c.bak new file mode 100644 index 0000000000..30cf7eba25 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/generic.c.bak @@ -0,0 +1,377 @@ +/*************************************************************************** + generic.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - repaired time2addr/addr2time +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_GENERIC +#include "externals.h" + +///////////////////////////////////////////////////////// + +int iCD_AD=-1; // drive address +int iCD_TA=-1; +int iCD_LU=-1; +int iRType=0; // read mode +int iUseSpeedLimit=0; // speed limit use +int iSpeedLimit=2; // speed 2x +int iNoWait=0; // wait +int iMaxRetry=5; // retry on error +int iShowReadErr=0; // show msg on error +HANDLE hEvent=NULL; // global event +HINSTANCE hASPI=NULL; // aspi lib +READFUNC pReadFunc=NULL; // read func +DEINITFUNC pDeInitFunc=NULL; // deinit func +int iInterfaceMode=1; // interface (aspi/ioctrlscsi/ioctrlraw) +int iWantedBlockSize=2352; +int iUsedBlockSize=2352; +int iUsedMode=CDVD_MODE_2352; + +DWORD (*pGetASPI32SupportInfo)(void); // ptrs to aspi funcs +DWORD (*pSendASPI32Command)(LPSRB); + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time) +{ + addr+=150; + time[3] = (unsigned char)(addr%75); + addr/=75; + time[2]=(unsigned char)(addr%60); + addr/=60; + time[1]=(unsigned char)(addr%100); + time[0]=(unsigned char)(addr/100); +} + +void addr2timeB(unsigned long addr, unsigned char *time) +{ + time[3] = itob((unsigned char)(addr%75)); + addr/=75; + time[2]=itob((unsigned char)(addr%60)); + addr/=60; + time[1]=itob((unsigned char)(addr%100)); + time[0]=itob((unsigned char)(addr/100)); +} + +unsigned long time2addr(unsigned char *time) +{ + unsigned long addr; + + addr = time[0]*100; + addr += time[1]; + addr *= 60; + + addr = (addr + time[2])*75; + addr += time[3]; + addr -= 150; + return addr; +} + +unsigned long time2addrB(unsigned char *time) +{ + unsigned long addr; + + addr = (btoi(time[0]))*100; + addr += btoi(time[1]); + addr *= 60; + addr = (addr + btoi(time[2]))*75; + addr += btoi(time[3]); + addr -= 150; + return addr; +} + +#ifndef _GCC +unsigned long reOrder(unsigned long value) +{ +#pragma warning (disable: 4035) + __asm + { + mov eax,value + bswap eax + } +} +#endif + +///////////////////////////////////////////////////////// + +void CreateGenEvent(void) +{ + hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); +} + +///////////////////////////////////////////////////////// + +void FreeGenEvent(void) +{ + if(hEvent) CloseHandle(hEvent); + hEvent=0; +} + +///////////////////////////////////////////////////////// + +DWORD WaitGenEvent(DWORD dwMS) +{ + if(hASPI) // aspi event + return WaitForSingleObject(hEvent,dwMS); + else + { // ioctl overlapped (always waiting til finished, dwMS not used) + DWORD dwR=0; + GetOverlappedResult(hIOCTL,&ovcIOCTL,&dwR,TRUE); + return 0; + } +} + +///////////////////////////////////////////////////////// + +void LockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + WaitForSingleObject(hThreadMutex[0],INFINITE); // -> wait until all reading is done + else // async prefetch? + if(bDoWaiting) // -> async operation has to finish first + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} +} + +///////////////////////////////////////////////////////// + +void UnlockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + ReleaseMutex(hThreadMutex[0]); // -> we are finished with our special command, now reading can go on +} + +///////////////////////////////////////////////////////// + +void WaitUntilDriveIsReady(void) +{ + if(iNoWait==0) + { + while(TestSCSIUnitReady()==0) Sleep(500); + } +} + +///////////////////////////////////////////////////////// + +void SetGenCDSpeed(int iReset) +{ + if(iUseSpeedLimit) + { + if(bDoWaiting) // still a command running? wait + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} + + if(iReset) SetSCSISpeed(0xFFFF); + else + if(SetSCSISpeed(176*iSpeedLimit)<=0) + { + MessageBox(GetActiveWindow(), + "Failure: cannot change the drive speed!", + "cdvdPeops... speed limitation", + MB_OK|MB_ICONEXCLAMATION); + iUseSpeedLimit=0; + } + } +} + +///////////////////////////////////////////////////////// +// checks, which direct subchannel reading type is supported + +void GetBESubReadFunc(void) +{ + unsigned char * pB=(unsigned char *)malloc(4096); + + pReadFunc = ReadSCSI_BE_Sub; // pre-init read func + + WaitUntilDriveIsReady(); // wait before first read + + ReadSub_BE_2(0,pB,1); // first (unchecked) read + if(!ReadSub_BE_2(0,pB,1)) // read again, and check this time + { // -> read failed? + if(ReadSub_BE_2_1(0,pB,1)) // -> try different sub reading + { // --> success? mmm... let us check the data + DecodeSub_BE_2_1(pB+2352); // --> decode sub + if(*(pB+2352)==0x41) // --> check the first decoded byte + pReadFunc = ReadSCSI_BE_Sub_1; // ---> wow, byte is ok + } + } + free(pB); +} + +///////////////////////////////////////////////////////// + +int GetGenReadFunc(int iRM) +{ + switch(iRM) // scsi read mode + { + // ------------------------------------------------ // + case MODE_BE_1: + case MODE_BE_2: + { + if(iUseSubReading==1) + GetBESubReadFunc(); + else pReadFunc = ReadSCSI_BE; + } break; + // ------------------------------------------------ // + case MODE_28_1: + case MODE_28_2: + { + if(iUseSubReading==1) + pReadFunc = ReadSCSI_28_Sub; + else pReadFunc = ReadSCSI_28; + } break; + // ------------------------------------------------ // + case MODE_28_2048: + { + pReadFunc = ReadSCSI_28_2048; + } break; + // ------------------------------------------------ // + case MODE_28_2048_Ex: + { + pReadFunc = ReadSCSI_28_2048_Ex; + } break; + // ------------------------------------------------ // + default: + { + pReadFunc = ReadSCSI_Dummy; + } return -3; + // ------------------------------------------------ // + } + return 1; +} + +///////////////////////////////////////////////////////// + +int OpenGenCD(int iA,int iT,int iL) +{ + pDeInitFunc = NULL; // init de-init func + pReadFunc = ReadSCSI_Dummy; // init (dummy) read func + + if(iA==-1) return -1; // not configured properly + + // -------------------------------------------------- // + + if(iInterfaceMode>1) // ioctrl interfaces? + { + OpenIOCTLHandle(iA,iT,iL); // open w2k/xp ioctrl device + if(hIOCTL==NULL) return -2; // no cdrom available + + if(iInterfaceMode==3) // special ioctl RAW mode? + { // -> get special reading funcs (non-scsi!) + if(iUseSubReading==1) + pReadFunc = ReadIOCTL_Raw_Sub; + else pReadFunc = ReadIOCTL_Raw; + + WaitUntilDriveIsReady(); + return 1; + } + } + else // aspi interface? + { + int iDevice=GetSCSIDevice(iA,iT,iL); // get device type + if(iDevice!=DTYPE_CDROM) return -2; // no cdrom? bye + } + + if(CheckSCSIReadMode()==SS_COMP) + WaitUntilDriveIsReady(); + else + { + CloseIOCTLHandle(); + return -3; + } + + return 1; +} + +///////////////////////////////////////////////////////// + +void CloseGenCD(void) +{ + iCDROK=0; // no more cd available + if(pDeInitFunc) pDeInitFunc(); // deinit, if needed + pDeInitFunc = NULL; + pReadFunc = ReadSCSI_Dummy; + CloseIOCTLHandle(); // close ioctl drive file (if used) +} + +///////////////////////////////////////////////////////// + +void OpenGenInterface(void) +{ + hASPI=NULL; + + if(iInterfaceMode==0) return; // no interface? no fun + else + if(iInterfaceMode==1) // aspi + { + hASPI=LoadLibrary("WNASPI32.DLL"); + if(hASPI) + { + pGetASPI32SupportInfo = + (DWORD(*)(void)) GetProcAddress(hASPI,"GetASPI32SupportInfo"); + pSendASPI32Command = + (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command"); + + if(!pGetASPI32SupportInfo || !pSendASPI32Command) + { + iInterfaceMode=0; + return; + } + } + } + else // ioctl + { + if(iInterfaceMode<2 || iInterfaceMode>3) iInterfaceMode=2; + pGetASPI32SupportInfo = NULL; + pSendASPI32Command = IOCTLSendASPI32Command; + } +} + +///////////////////////////////////////////////////////// + +void CloseGenInterface(void) +{ + pGetASPI32SupportInfo=NULL; // clear funcs + pSendASPI32Command=NULL; + + if(hASPI) // free aspi + { + FreeLibrary(hASPI); + hASPI=NULL; + } + else CloseIOCTLHandle(); // or close ioctl file +} + +///////////////////////////////////////////////////////// + +int GetGenCDDrives(char * pDList) +{ + if(hASPI) return GetSCSICDDrives(pDList); // aspi? use it + return GetIOCTLCDDrives(pDList); // or use ioctl +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/generic.h b/plugins/cdvd/CDVDpeops/generic.h new file mode 100644 index 0000000000..0313e50f0b --- /dev/null +++ b/plugins/cdvd/CDVDpeops/generic.h @@ -0,0 +1,41 @@ +/*************************************************************************** + generic.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void CreateGenEvent(void); +void FreeGenEvent(void); +DWORD WaitGenEvent(DWORD dwMS); +void LockGenCDAccess(void); +void UnlockGenCDAccess(void); +void WaitUntilDriveIsReady(void); +void SetGenCDSpeed(int iReset); +void GetBESubReadFunc(void); +int GetGenReadFunc(int iRM); +int OpenGenCD(int iA,int iT,int iL); +void CloseGenCD(void); +void OpenGenInterface(void); +void CloseGenInterface(void); +int GetGenCDDrives(char * pDList); + diff --git a/plugins/cdvd/CDVDpeops/i386.asm b/plugins/cdvd/CDVDpeops/i386.asm new file mode 100644 index 0000000000..e6f11ac0ac --- /dev/null +++ b/plugins/cdvd/CDVDpeops/i386.asm @@ -0,0 +1,32 @@ +; i386.asm - description +; ------------------- +; begin : Sun Nov 08 2001 +; copyright : (C) 2001 by Pete Bernert +; email : BlackDove@addcom.de + +; 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. See also the license.txt file for * +; additional informations. * + + +bits 32 + +section .text + +%include "macros.inc" + +;----------------------------------------------------------------- +NEWSYM i386_reOrder + push ebp + mov ebp, esp + + mov eax, [ebp+8] + bswap eax + + mov esp, ebp + pop ebp + ret + + diff --git a/plugins/cdvd/CDVDpeops/ioctrl.h b/plugins/cdvd/CDVDpeops/ioctrl.h new file mode 100644 index 0000000000..f105c963e0 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/ioctrl.h @@ -0,0 +1,35 @@ +/*************************************************************************** + ioctrl.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void OpenIOCTLHandle(int iA,int iT,int iL); +void CloseIOCTLHandle(void); +char MapIOCTLDriveLetter(int iA,int iT,int iL); +int GetIOCTLCDDrives(char * pDList); +HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync); +void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL); +DWORD IOCTLSendASPI32Command(LPSRB pSrb); +DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f); +DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f); diff --git a/plugins/cdvd/CDVDpeops/libiso.c b/plugins/cdvd/CDVDpeops/libiso.c new file mode 100644 index 0000000000..899a8c98c6 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/libiso.c @@ -0,0 +1,732 @@ +#include +#include +#include +#include +#include +#include +//#include + +#define __MSCW32__ +#ifdef __WIN32__ +#include +#endif + +#include "PS2Etypes.h" +//#include "CDVDiso.h" +#include "libiso.h" + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(__WIN32__) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + + +#ifdef __WIN32__ +void *_openfile(const char *filename, int flags) { + HANDLE handle; + +// printf("_openfile %s, %d\n", filename, flags & O_RDONLY); + if (flags & O_WRONLY) { + int _flags = CREATE_NEW; + if (flags & O_CREAT) _flags = CREATE_ALWAYS; + handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, _flags, 0, NULL); + } else { + handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + } + + return handle == INVALID_HANDLE_VALUE ? NULL : handle; +} + +u64 _tellfile(void *handle) { + u64 ofs; + DWORD *_ofs = (DWORD*)&ofs; + _ofs[1] = 0; + _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); + return ofs; +} + +int _seekfile(void *handle, u64 offset, int whence) { + u64 ofs = (u64)offset; + DWORD *_ofs = (DWORD*)&ofs; +// printf("_seekfile %p, %d_%d\n", handle, _ofs[1], _ofs[0]); + if (whence == SEEK_SET) { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); + } else { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_END); + } + return 0; +} + +int _readfile(void *handle, void *dst, int size) { + DWORD ret; + +// printf("_readfile %p %d\n", handle, size); + ReadFile(handle, dst, size, &ret, NULL); +// printf("_readfile ret %d; %d\n", ret, GetLastError()); + return ret; +} + +int _writefile(void *handle, void *src, int size) { + DWORD ret; + +// printf("_writefile %p, %d\n", handle, size); +// _seekfile(handle, _tellfile(handle)); + WriteFile(handle, src, size, &ret, NULL); +// printf("_writefile ret %d\n", ret); + return ret; +} + +void _closefile(void *handle) { + CloseHandle(handle); +} + +#else + +void *_openfile(const char *filename, int flags) { + printf("_openfile %s %x\n", filename, flags); + if (flags & O_WRONLY) + return fopen(filename, "wb"); + else return fopen(filename, "rb"); +} + +u64 _tellfile(void *handle) { + return ftell(handle); +} + +int _seekfile(void *handle, u64 offset, int whence) { + return fseek(handle, offset, whence); +} + +int _readfile(void *handle, void *dst, int size) { + return fread(dst, 1, size, handle); +} + +int _writefile(void *handle, void *src, int size) { + return fwrite(src, 1, size, handle); +} + +void _closefile(void *handle) { + fclose(handle); +} + +#endif + +int detect(isoFile *iso) { + char buf[2448]; + struct cdVolDesc *volDesc; + + if (isoReadBlock(iso, buf, 16) == -1) return -1; + volDesc = (struct cdVolDesc *)(buf + 24); + if (strncmp(volDesc->volID, "CD001", 5)) return 0; + + if (volDesc->rootToc.tocSize == 2048) { + iso->type = ISOTYPE_CD; + } else { + iso->type = ISOTYPE_DVD; + } + + return 1; +} + +int _isoReadZtable(isoFile *iso) { + void *handle; + char table[256]; + int size; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = (int)_tellfile(handle); + iso->Ztable = (char*)malloc(size); + if (iso->Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, iso->Ztable, size); + _closefile(handle); + + iso->blocks = size / 6; + + return 0; +} + +int _isoReadZ2table(isoFile *iso) { + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = (int)_tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks*8); + if (iso->Ztable == NULL) { + return -1; + } + + ofs=16; + for (i=0; iblocks; i++) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + free(Ztable); + + return 0; +} + +int _isoReadDtable(isoFile *iso) { + int ret; + int i; + + _seekfile(iso->handle, 0, SEEK_END); + iso->dtablesize = (int)(_tellfile(iso->handle) - 16) / (iso->blocksize+4); + iso->dtable = (u32*)malloc(iso->dtablesize*4); + + for (i=0; idtablesize; i++) { + _seekfile(iso->handle, 16+(iso->blocksize+4)*i, SEEK_SET); + ret = _readfile(iso->handle, &iso->dtable[i], 4); + if (ret < 4) { + return -1; + } + } + + return 0; +} + +int isoDetect(isoFile *iso) { // based on florin's CDVDbin detection code :) + char buf[32]; + int len; + + iso->type = ISOTYPE_ILLEGAL; + + len = strlen(iso->filename); + if (len >= 2) { + if (!strncmp(iso->filename+(len-2), ".Z", 2)) { + iso->flags = ISOFLAGS_Z; + iso->blocksize = 2352; + _isoReadZtable(iso); + return detect(iso) == 1 ? 0 : -1; + } + } + + _seekfile(iso->handle, 0, SEEK_SET); + _readfile(iso->handle, buf, 4); + if (strncmp(buf, "BDV2", 4) == 0) { + iso->flags = ISOFLAGS_BLOCKDUMP; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadDtable(iso); + return detect(iso) == 1 ? 0 : -1; + } else + if (strncmp(buf, "Z V2", 4) == 0) { + iso->flags = ISOFLAGS_Z2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } else { + iso->blocks = 16; + } + + // ISO 2048 + iso->blocksize = 2048; iso->offset = 0; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2336 + iso->blocksize = 2336; iso->offset = 0; iso->blockofs = 16; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO ISO 2048 + iso->blocksize = 2048; iso->offset = 150*2048; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // NERO RAW 2352 + iso->blocksize = 2352; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO RAWQ 2448 + iso->blocksize = 2448; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // ISO 2048 + iso->blocksize = 2048; iso->offset = -8; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + iso->offset = 0; + iso->blocksize = 2352; + iso->type = ISOTYPE_AUDIO; + return 0; + + return -1; +} + +isoFile *isoOpen(const char *filename) { + isoFile *iso; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + + iso->handle = _openfile(iso->filename, O_RDONLY); + if (iso->handle == NULL) { + printf("Error loading %s\n", iso->filename); + return NULL; + } + + if (isoDetect(iso) == -1) return NULL; + + if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BLOCKDUMP)) { + } else { + _seekfile(iso->handle, 0, SEEK_END); + iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / + (iso->blocksize)); + } +/* + if (strlen(IsoFile) > 3 && + !strncmp(IsoFile + (strlen(IsoFile) - 3), "I00", 3)) { + int i; + int llsn=0; + + for (i=0; i<8; i++) { + IsoFile[strlen(IsoFile) - 1] = '0' + i; + if (stat(IsoFile, &buf) == -1) break; + cdIndexs[i].slsn = llsn; + llsn+= buf.st_size / cdblocksize; + cdIndexs[i].elsn = llsn-1; + cdHandle[i] = fopen(IsoFile, "rb"); + if (cdHandle[i] == NULL) break; + } + + if (i == 0) { + SysMessage("Error loading %s\n", IsoFile); + return -1; + } + fmode = 3; + } else*//* { + iso->handle = _openfile(iso->filename, O_RDONLY); + if (iso->handle == NULL) { + printf("Error loading %s\n", iso->filename); + return NULL; + } + }*/ + + printf("isoOpen: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + printf("type = %d\n", iso->type); + + return iso; +} + +isoFile *isoCreate(const char *filename, int flags) { + isoFile *iso; + char Zfile[256]; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + iso->flags = flags; + iso->offset = 0; + iso->blockofs = 24; + iso->blocksize = CD_FRAMESIZE_RAW; + iso->blocksize = 2048; + + if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2)) { + sprintf(Zfile, "%s.table", iso->filename); + iso->htable = _openfile(Zfile, O_WRONLY); + if (iso->htable == NULL) { + return NULL; + } + } + + iso->handle = _openfile(iso->filename, O_WRONLY); + if (iso->handle == NULL) { + printf("Error loading %s\n", iso->filename); + return NULL; + } + printf("isoCreate: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + + return iso; +} + +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) { + iso->blocksize = blocksize; + iso->blocks = blocks; + iso->blockofs = blockofs; + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + if (iso->flags & ISOFLAGS_Z2) { + if (_writefile(iso->handle, "Z V2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + + return 0; +} + +s32 MSFtoLSN(u8 *Time) { + u32 lsn; + + lsn = Time[2]; + lsn+=(Time[1] - 2) * 75; + lsn+= Time[0] * 75 * 60; + return lsn; +} + +void LSNtoMSF(u8 *Time, s32 lsn) { + u8 m, s, f; + + lsn += 150; + m = lsn / 4500; // minuten + lsn = lsn - m * 4500; // minuten rest + s = lsn / 75; // sekunden + f = lsn - (s * 75); // sekunden rest + Time[0] = itob(m); Time[1] = itob(s); Time[2] = itob(f); +} + +int _isoReadBlock(isoFile *iso, char *dst, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} +/* +int _isoReadBlockZ(isoFile *iso, char *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW*2]; + int ret; + +// printf("_isoReadBlockZ %d, %d\n", lsn, iso->blocksize); + pos = *(unsigned long*)&iso->Ztable[lsn * 6]; + p = *(unsigned short*)&iso->Ztable[lsn * 6 + 4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = CD_FRAMESIZE_RAW; + uncompress(dst, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockZ2(isoFile *iso, char *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[16*1024]; + int ret; + +// printf("_isoReadBlockZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*)&iso->Ztable[lsn*8]; + p = *(u32*)&iso->Ztable[lsn*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize; + uncompress(dst + iso->blockofs, &size, Zbuf, p); + + return 0; +} +*/ +int _isoReadBlockD(isoFile *iso, char *dst, int lsn) { + int ret; + int i; + +// printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + for (i=0; idtablesize;i++) { + if (iso->dtable[i] != lsn) continue; + + _seekfile(iso->handle, 16+i*(iso->blocksize+4)+4, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) return -1; + + return 0; + } + printf("block %d not found in dump\n", lsn); + + return -1; +} + +int isoReadBlock(isoFile *iso, char *dst, int lsn) { + int ret; + + if (lsn > iso->blocks) { + printf("isoReadBlock: %d > %d\n", lsn, iso->blocks); + return -1; + } +/* if (iso->flags & ISOFLAGS_Z) { + ret = _isoReadBlockZ(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoReadBlockZ2(iso, dst, lsn); + } else +*/ if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoReadBlockD(iso, dst, lsn); + } else + ret = _isoReadBlock(iso, dst, lsn); + if (ret == -1) return ret; + + if (iso->type == ISOTYPE_CD) { + LSNtoMSF(dst+12, lsn); + dst[15] = 2; + } + + return 0; +} + + +int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} +/* +int _isoWriteBlockZ(isoFile *iso, u8 *src, int lsn) { + u32 pos; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 2352; + compress(Zbuf, &size, src, 2352); +// printf("_isoWriteBlockZ %d\n", size); + + pos = (u32)_tellfile(iso->handle); + ret = _writefile(iso->htable, (u8*)&pos, 4); + if (ret < 4) return -1; + ret = _writefile(iso->htable, (u8*)&size, 2); + if (ret < 2) return -1; + + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockZ2(isoFile *iso, u8 *src, int lsn) { + uLongf size; + u8 Zbuf[1024*16]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 1024*16; + compress(Zbuf, &size, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlockZ %d\n", size); + + ret = _writefile(iso->htable, (u8*)&size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} +*/ +int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) { + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + ret = _writefile(iso->handle, &lsn, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int isoWriteBlock(isoFile *iso, char *src, int lsn) { + int ret; + +/* if (iso->flags & ISOFLAGS_Z) { + ret = _isoWriteBlockZ(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoWriteBlockZ2(iso, src, lsn); + } else +*/ if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoWriteBlockD(iso, src, lsn); + } else + ret = _isoWriteBlock(iso, src, lsn); + if (ret == -1) return ret; + + return 0; +} + +void isoClose(isoFile *iso) { + if (iso->handle) { + _closefile(iso->handle); + } + if (iso->htable) { + _closefile(iso->htable); + } + free(iso); +} + diff --git a/plugins/cdvd/CDVDpeops/libiso.h b/plugins/cdvd/CDVDpeops/libiso.h new file mode 100644 index 0000000000..461f792db7 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/libiso.h @@ -0,0 +1,59 @@ +#ifndef __LIBISO_H__ +#define __LIBISO_H__ + +#ifdef __MSCW32__ +#pragma warning(disable:4018) +#endif + +#define CDVDdefs +#include "PS2Etypes.h" +#include "PS2Edefs.h" + +#define ISOTYPE_ILLEGAL 0 +#define ISOTYPE_CD 1 +#define ISOTYPE_DVD 2 +#define ISOTYPE_AUDIO 3 + +#define ISOFLAGS_Z 0x1 +#define ISOFLAGS_Z2 0x2 +#define ISOFLAGS_BLOCKDUMP 0x4 + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +typedef struct { + char filename[256]; + u32 type; + u32 flags; + u32 offset; + u32 blockofs; + u32 blocksize; + u32 blocks; + void *handle; + void *htable; + char *Ztable; + u32 *dtable; + int dtablesize; + char buffer[CD_FRAMESIZE_RAW * 10]; +} isoFile; + + +isoFile *isoOpen(const char *filename); +isoFile *isoCreate(const char *filename, int mode); +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +int isoDetect(isoFile *iso); +int isoReadBlock(isoFile *iso, char *dst, int lsn); +int isoWriteBlock(isoFile *iso, char *src, int lsn); +void isoClose(isoFile *iso); + +void *_openfile(const char *filename, int flags); +u64 _tellfile(void *handle); +int _seekfile(void *handle, u64 offset, int whence); +int _readfile(void *handle, void *dst, int size); +int _writefile(void *handle, void *src, int size); +void _closefile(void *handle); + +#endif /* __LIBISO_H__ */ diff --git a/plugins/cdvd/CDVDpeops/license.txt b/plugins/cdvd/CDVDpeops/license.txt new file mode 100644 index 0000000000..e51338c2ca --- /dev/null +++ b/plugins/cdvd/CDVDpeops/license.txt @@ -0,0 +1,282 @@ +######################################################################### + + 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 diff --git a/plugins/cdvd/CDVDpeops/macros.inc b/plugins/cdvd/CDVDpeops/macros.inc new file mode 100644 index 0000000000..47829285b8 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/macros.inc @@ -0,0 +1,40 @@ +; macros.inc - description +; ------------------- +; begin : Sun Nov 08 2001 +; based on ZSNES macros.mac +; email : linuzappz@pcsx.net + +; 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. See also the license.txt file for * +; additional informations. * + + +%ifdef __WIN32__ + +%imacro EXTSYM 1-* +%rep %0 + extern _%1 + %define %1 _%1 +%rotate 1 +%endrep +%endmacro + +%imacro NEWSYM 1 + global _%1 + _%1: + %1: +%endmacro + +%else + +%define EXTSYM extern + +%imacro NEWSYM 1 + global %1 + %1: +%endmacro + +%endif + diff --git a/plugins/cdvd/CDVDpeops/mingw/afxres.h b/plugins/cdvd/CDVDpeops/mingw/afxres.h new file mode 100644 index 0000000000..060e13b308 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/mingw/afxres.h @@ -0,0 +1,2 @@ +#include +#define IDC_STATIC -1 diff --git a/plugins/cdvd/CDVDpeops/ppf.c b/plugins/cdvd/CDVDpeops/ppf.c new file mode 100644 index 0000000000..c9f755da74 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/ppf.c @@ -0,0 +1,353 @@ +/*************************************************************************** + ppf.c - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/02/14 - Pete +// - fixed a bug reading PPF3 patches reported by Zydio +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_PPF +#include "externals.h" + +///////////////////////////////////////////////////////// + +int iUsePPF=0; +char szPPF[260]; +PPF_CACHE * ppfCache=NULL; +PPF_DATA * ppfHead=NULL; +int iPPFNum=0; + +///////////////////////////////////////////////////////// +// works like sub cache... using a linked data list, and address array + +void FillPPFCache(void) +{ + PPF_DATA * p;PPF_CACHE * pc; + long lastaddr; + + p=ppfHead; + lastaddr=-1; + iPPFNum=0; + + while(p) + { + if(p->addr!=lastaddr) iPPFNum++; + lastaddr=p->addr; + p=(PPF_DATA *)p->pNext; + } + + if(!iPPFNum) return; + + pc=ppfCache=(PPF_CACHE *)malloc(iPPFNum*sizeof(PPF_CACHE)); + + iPPFNum--; + p=ppfHead; + lastaddr=-1; + + while(p) + { + if(p->addr!=lastaddr) + { + pc->addr=p->addr; + pc->pNext=(void *)p; + pc++; + } + lastaddr=p->addr; + p=(PPF_DATA *)p->pNext; + } +} + +///////////////////////////////////////////////////////// + +void FreePPFCache(void) +{ + PPF_DATA * p=ppfHead; + void * pn; + + while(p) + { + pn=p->pNext; + free(p); + p=(PPF_DATA *)pn; + } + ppfHead=NULL; + + if(ppfCache) free(ppfCache); + ppfCache=NULL; +} + +///////////////////////////////////////////////////////// + +void CheckPPFCache(long addr,unsigned char * pB) +{ + PPF_CACHE * pcstart, * pcend, * pcpos; + + pcstart=ppfCache; + if(addraddr) return; + pcend=ppfCache+iPPFNum; + if(addr>pcend->addr) return; + + while(1) + { + if(addr==pcend->addr) {pcpos=pcend;break;} + + pcpos=pcstart+(pcend-pcstart)/2; + if(pcpos==pcstart) break; + if(addraddr) + { + pcend=pcpos; + continue; + } + if(addr>pcpos->addr) + { + pcstart=pcpos; + continue; + } + break; + } + + if(addr==pcpos->addr) + { + PPF_DATA * p=(PPF_DATA *)pcpos->pNext; + while(p && p->addr==addr) + { + memcpy(pB+p->pos,p+1,p->anz); + p=(PPF_DATA *)p->pNext; + } + } +} + +///////////////////////////////////////////////////////// + +void AddToPPF(long ladr,long pos,long anz,char * ppfmem) +{ + if(!ppfHead) + { + ppfHead=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); + ppfHead->addr=ladr; + ppfHead->pNext=NULL; + ppfHead->pos=pos; + ppfHead->anz=anz; + memcpy(ppfHead+1,ppfmem,anz); + iPPFNum=1; + } + else + { + PPF_DATA * p=ppfHead; + PPF_DATA * plast=NULL; + PPF_DATA * padd; + while(p) + { + if(ladraddr) break; + if(ladr==p->addr) + { + while(p && ladr==p->addr && pos>p->pos) + { + plast=p; + p=(PPF_DATA *)p->pNext; + } + break; + } + plast=p; + p=(PPF_DATA *)p->pNext; + } + padd=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); + padd->addr=ladr; + padd->pNext=(void *)p; + padd->pos=pos; + padd->anz=anz; + memcpy(padd+1,ppfmem,anz); + iPPFNum++; + if(plast==NULL) + ppfHead=padd; + else plast->pNext=(void *)padd; + } +} + +///////////////////////////////////////////////////////// +// build ppf cache, if wanted + +void BuildPPFCache(void) +{ + FILE * ppffile; + char buffer[5]; + char method,undo=0,blockcheck=0; + int dizlen, dizyn, dizlensave=0; + char ppfmem[512]; + int count,seekpos, pos; + //unsigned char anz; + unsigned int anz; // new! avoids stupid overflows + long ladr,off,anx; + + ppfHead=NULL; + + if(iUsePPF==0) return; // no ppf cache wanted? + if(szPPF[0]==0) return; // no ppf file given? + + ppffile=fopen(szPPF, "rb"); + if(ppffile==0) + { + MessageBox(NULL,"No PPF file found!",libraryName,MB_OK); + return; + } + + memset(buffer,0,5); + fread(buffer, 3, 1, ppffile); + + if(strcmp(buffer,"PPF")) + { + MessageBox(NULL,"No PPF file format!",libraryName,MB_OK); + fclose(ppffile); + return; + } + + fseek(ppffile, 5, SEEK_SET); + fread(&method, 1, 1,ppffile); + + switch(method) + { + case 0: // ppf1 + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + count-=56; + seekpos=56; + break; + + case 1: // ppf2 + fseek(ppffile, -8,SEEK_END); + + memset(buffer,0,5); + fread(buffer, 4, 1,ppffile); + if(strcmp(".DIZ", buffer)) + { + dizyn=0; + } + else + { + fread(&dizlen, 4, 1, ppffile); + dizyn=1; + dizlensave=dizlen; + } + + fseek(ppffile, 56, SEEK_SET); + fread(&dizlen, 4, 1,ppffile); + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + if(dizyn==0) + { + count-=1084; + seekpos=1084; + } + else + { + count-=1084; + count-=38; + count-=dizlensave; + seekpos=1084; + } + break; + + case 2: // ppf3 + fseek(ppffile, 57, SEEK_SET); + fread(&blockcheck, 1, 1,ppffile); + fseek(ppffile, 58, SEEK_SET); + fread(&undo, 1, 1,ppffile); + + fseek(ppffile, -6,SEEK_END); + memset(buffer,0,5); + fread(buffer, 4, 1,ppffile); + dizlen=0; + if(!strcmp(".DIZ", buffer)) + { + fseek(ppffile, -2,SEEK_END); + fread(&dizlen, 2, 1, ppffile); + dizlen+=36; + } + + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + count-=dizlen; + + if(blockcheck) + { + seekpos=1084; + count-=1084; + } + else + { + seekpos=60; + count-=60; + } + + break; + + default: + fclose(ppffile); + MessageBox(NULL,"Unknown PPF format!",libraryName,MB_OK); + return; + } + + do // now do the data reading + { + fseek(ppffile, seekpos, SEEK_SET); + fread(&pos, 4, 1, ppffile); + + if(method==2) fread(buffer, 4, 1, ppffile); // skip 4 bytes on ppf3 (no int64 support here) + + anz=0; // new! init anz (since it's no unsigned char anymore) + fread(&anz, 1, 1, ppffile); + fread(ppfmem, anz, 1, ppffile); + + ladr=pos/2352; + off=pos%2352; + + if(off+anz>2352) + { + anx=off+anz-2352; + anz-=(unsigned char)anx; + AddToPPF(ladr+1,0,anx,ppfmem+anz); + } + + AddToPPF(ladr,off,anz,ppfmem); // add to link list + + if(method==2) // adjust ppf3 size + { + if(undo) anz+=anz; + anz+=4; + } + + seekpos=seekpos+5+anz; + count=count-5-anz; + } + while(count!=0); // loop til end + + fclose(ppffile); + + FillPPFCache(); // build address array +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/ppf.h b/plugins/cdvd/CDVDpeops/ppf.h new file mode 100644 index 0000000000..af20e48900 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/ppf.h @@ -0,0 +1,32 @@ +/*************************************************************************** + ppf.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void FillPPFCache(void); +void FreePPFCache(void); +void CheckPPFCache(long addr,unsigned char * pB); +void AddToPPF(long ladr,long pos,long anz,char * ppfmem); +void BuildPPFCache(void); + diff --git a/plugins/cdvd/CDVDpeops/read.c b/plugins/cdvd/CDVDpeops/read.c new file mode 100644 index 0000000000..e0de2045a9 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/read.c @@ -0,0 +1,910 @@ +/*************************************************************************** + read.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_READ +#include "externals.h" + +///////////////////////////////////////////////////////// + +READTRACKFUNC pReadTrackFunc=NULL; +GETPTRFUNC pGetPtrFunc=NULL; + +int iUseCaching=0; +int iTryAsync=0; +int iBufSel=0; + +unsigned char * pMainBuffer=0; +unsigned char * pCurrReadBuf=0; +unsigned char * pFirstReadBuf=0; +unsigned char * pAsyncBuffer=0; + +unsigned long lMaxAddr=0; +unsigned long lLastAddr = 0xFFFFFFFF; +unsigned long lLastAsyncAddr = 0xFFFFFFFF; +unsigned long lNeededAddr = 0xFFFFFFFF; +unsigned long lLastAccessedAddr = 0xFFFFFFFF; +int iLastAccessedMode=0; + +unsigned char * ptrBuffer[2]; +unsigned char * pAsyncFirstReadBuf[2]; + + +#define MAXQSIZE 16 +#define MAXQFETCH 8 + +unsigned long lAddrQ[MAXQSIZE]; +int iQPos=0; +int iQIdle=0; +int iQLockPos=-1; + +///////////////////////////////////////////////////////// +// thread helper vars + +HANDLE hReadThread = NULL; +BOOL bThreadEnded = FALSE; +HANDLE hThreadEvent[3]; +HANDLE hThreadMutex[2]; + +///////////////////////////////////////////////////////// +// internal MAXDATACACHE*64KB (4MB) data cache + +#define MAXDATACACHE 64 +unsigned long lDataCacheAddr[MAXDATACACHE]; +unsigned char * pDataCacheBuf[MAXDATACACHE]; +BOOL bDataCacheHit=FALSE; +int iUseDataCache=0; + +///////////////////////////////////////////////////////// +// main init func + +void CreateREADBufs(void) +{ + switch(iUseCaching) + { + case 4: iUseDataCache = 2; // use a special data cache on threadex reading + pReadTrackFunc = DoReadThreadEx; + pGetPtrFunc = GetREADThreadExPtr; break; + case 3: pReadTrackFunc = DoReadThread; + pGetPtrFunc = GetREADThreadPtr; break; + case 2: pReadTrackFunc = DoReadAsync; + pGetPtrFunc = NULL; break; + default: pReadTrackFunc = DoRead; + pGetPtrFunc = NULL; break; + } + + hThreadEvent[0]=NULL; // clear events/mutex + hThreadEvent[1]=NULL; + hThreadEvent[2]=NULL; + hThreadMutex[0]=NULL; + hThreadMutex[1]=NULL; + + AllocDataCache(); // build data cache, if wanted + + lLastAddr = 0xFFFFFFFF; + lLastAsyncAddr = 0xFFFFFFFF; + iBufSel = 0; + + if(iUseCaching) // some caching? need bigger buffer + pMainBuffer=(unsigned char *)malloc(MAXCDBUFFER); + else pMainBuffer=(unsigned char *)malloc(CDSECTOR+208+96); + + pCurrReadBuf=pFirstReadBuf=pMainBuffer+FRAMEBUFEXTRA; + + if(iUseCaching>=2) // async/thread mode + { + pAsyncBuffer=(unsigned char *)malloc(MAXCDBUFFER); + ptrBuffer[0]=pMainBuffer; + ptrBuffer[1]=pAsyncBuffer; + pAsyncFirstReadBuf[0]=pFirstReadBuf; + pAsyncFirstReadBuf[1]=pAsyncBuffer+FRAMEBUFEXTRA; + + if(iUseCaching>=3) // thread mode + { + DWORD dw; + bThreadEnded = FALSE; + + for(dw=0;dw<3;dw++) // -> create events + { + hThreadEvent[dw]=CreateEvent(NULL,TRUE,FALSE,NULL); + ResetEvent(hThreadEvent[dw]); + } + for(dw=0;dw<2;dw++) // -> create mutex + { + hThreadMutex[dw]=CreateMutex(NULL,FALSE,NULL); + } + if(iUseCaching==3) // -> create thread + hReadThread=CreateThread(NULL,0,READThread,0,0,&dw); + else + { + for(dw=0;dw signal: end thread + while(!bThreadEnded) {Sleep(5L);} // -> wait til ended + WaitForSingleObject(hThreadMutex[1],INFINITE); + ReleaseMutex(hThreadMutex[1]); + hReadThread=NULL; // -> clear handle + } + + if(hThreadEvent[0]) CloseHandle(hThreadEvent[0]); // kill events/mutex + if(hThreadEvent[1]) CloseHandle(hThreadEvent[1]); + if(hThreadEvent[2]) CloseHandle(hThreadEvent[2]); + if(hThreadMutex[0]) CloseHandle(hThreadMutex[0]); + if(hThreadMutex[1]) CloseHandle(hThreadMutex[1]); + + if(pMainBuffer) free(pMainBuffer); // free main data buf + pMainBuffer=NULL; + if(pAsyncBuffer) free(pAsyncBuffer); // free async data buf + pAsyncBuffer=NULL; + + FreeDataCache(); +} + +///////////////////////////////////////////////////////// +// retry on readng error (blocking) + +BOOL bReadRetry(FRAMEBUF * f) +{ + int iRetry=0; + + while (iRetry tell it to user + { + char szB[64]; + wsprintf(szB,"Read error on address %08lx!",f->dwFrame); + MessageBox(NULL,szB,libraryName,MB_OK); + } + return FALSE; // -> tell emu: bad + } + + return TRUE; +} + +//////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// sync modes (caching 0 and 1) +// just reads one or more blocks, and always waits until +// reading is done +///////////////////////////////////////////////////////// + +BOOL DoRead(unsigned long addr) +{ + FRAMEBUF * f; + + //////////////////////////////////////////////////////// + + if(iUseCaching && // cache block available? + lLastAddr!=0xFFFFFFFF && + addr>=lLastAddr && // and addr in block? + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pFirstReadBuf+ // -> calc data ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // -> apply ppf + return TRUE; // -> done + } + + //////////////////////////////////////////////////////// + + if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes + return TRUE; // -> also fine + + //////////////////////////////////////////////////////// + + f=(FRAMEBUF *)pMainBuffer; // setup read for one sector + + f->dwFrameCnt = 1; + f->dwBufLen = iUsedBlockSize; + f->dwFrame = addr; + + pCurrReadBuf=pFirstReadBuf; + + //////////////////////////////////////////////////////// + + if(iUseCaching) // cache block? + { + if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; // -> set bigger read + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + lLastAddr = addr; // -> store addr of block + } + else + { + lLastAddr=0xFFFFFFFF; // no caching, no block addr + } + } + + //////////////////////////////////////////////////////// + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a waiting read + { + if(!bReadRetry(f)) return FALSE; // and retry on error + } + + if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and whole 64 k read block? + AddToDataCache(addr,pFirstReadBuf); // -> add the complete data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf + + return TRUE; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// async mode (caching 2) +// this mode works fine with ASPI... +// the first read will be done sync, though, only the +// additional pre-fetching will be done async... +// well, with mdecs most reads will be prefetched, so +// speed is good... with IOCTL this mode is more like +// a 'double sync' reading, since IOCTL seems always +// to be blocking (see also notes for caching mode 3) +///////////////////////////////////////////////////////// + +BOOL DoReadAsync(unsigned long addr) +{ + FRAMEBUF * f; + + //////////////////////////////////////////////////////// + // 1. check if data is in already filled buffer + + if(lLastAddr!=0xFFFFFFFF && + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ + ((addr-lLastAddr)*iUsedBlockSize); + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + + iTryAsync=0; + return TRUE; + } + + //////////////////////////////////////////////////////// + // check data cache + + if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes + return TRUE; // -> also fine + + //////////////////////////////////////////////////////// + // 2. not in main buffer? wait for async to be finished + + if(bDoWaiting) + { + WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE; + if(sx.SRB_Status!=SS_COMP) lLastAsyncAddr=0xFFFFFFFF; + } + + //////////////////////////////////////////////////////// + // 3. check in asyncbuffer. if yes, swap buffers and do next async read + + if(lLastAsyncAddr!=0xFFFFFFFF && + addr>=lLastAsyncAddr && + addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) + { + int iAsyncSel=iBufSel; // store old buf num + if(iBufSel==0) iBufSel=1; else iBufSel=0; // toggle to new num + + lLastAddr=lLastAsyncAddr; // set adr of block + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // set data ptr + ((addr-lLastAddr)*iUsedBlockSize); + + if(iUseDataCache) // data cache used? + AddToDataCache(lLastAddr,pAsyncFirstReadBuf[iBufSel]); // -> add the complete 64k data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf + + iTryAsync=0; // data was async, reset count + addr=lLastAddr+MAXCACHEBLOCK+1; // calc adr of next prefetch + if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + f->dwFrame = addr; + + lLastAsyncAddr=addr; // store prefetch addr + + if(pReadFunc(FALSE,f)!=SS_COMP) // start the async read + lLastAsyncAddr=0xFFFFFFFF; // -> if no success, no async prefetch buf available + + return TRUE; + } + + //////////////////////////////////////////////////////// + // here we do a sync read + + iBufSel=0; // read in buf 0 + + f=(FRAMEBUF *)ptrBuffer[0]; + f->dwFrame = addr; + + pCurrReadBuf=pFirstReadBuf; + + //////////////////////////////////////////////////////// + // if it's possible, we do a bigger read + + if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + lLastAddr = addr; + } + else + { + f->dwFrameCnt = 1; + f->dwBufLen = iUsedBlockSize; + lLastAddr = 0xFFFFFFFF; + } + + //////////////////////////////////////////////////////// + // start read, wait til finished + + if(pReadFunc(TRUE,f)!=SS_COMP) + { + if(!bReadRetry(f)) return FALSE; + } + + if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and complete 64k block? + AddToDataCache(addr,pAsyncFirstReadBuf[0]); // -> add the complete data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + + //////////////////////////////////////////////////////// + // start additional async prefetch read, if it's ok + + iTryAsync++; + if(iTryAsync>1) {iTryAsync=2;return TRUE;} // prefetches seems to be useless right now, so turn them off until next real read + + addr+=MAXCACHEBLOCK+1; // prefetch addr + if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + f->dwFrame = addr; + + lLastAsyncAddr= addr; + + if(pReadFunc(FALSE,f)!=SS_COMP) // start the async prefetch + lLastAsyncAddr=0xFFFFFFFF; + + return TRUE; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// thread mode (caching 3) +// this mode helps with slower drives using the IOCTL +// interface (since that one seems to do always blocking +// reads, even when they are done overlapped). +// With ASPI, the thread mode performance will be more or less +// the same as with async caching mode 2... +// thread reading would be much more powerful, if the main +// emu would do: +// ... +// CDRreadTrack() +// ... do some other stuff here ... +// CDRgetBuffer() +// ... +// but lazy main emu coders seem to prefer: +// ... +// CDRreadTrack() +// CDRgetBuffer() +// ... +// so there is no time between the calls to do a good +// asynchronous read... sad, sad... +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// reading thread... sleeps until a new read is signaled + +DWORD WINAPI READThread(LPVOID lpParameter) +{ + FRAMEBUF * f; + + while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised + INFINITE)==WAIT_OBJECT_0) + { + WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + ResetEvent(hThreadEvent[0]); // ok, kick event has been handled + SetEvent(hThreadEvent[2]); // set flag: we have started the read + + lLastAsyncAddr = lNeededAddr; // setup read and vars + f=(FRAMEBUF *)ptrBuffer[!iBufSel]; // !iSel = async buffer + f->dwFrame = lNeededAddr; + f->dwFrameCnt = min((lMaxAddr-lNeededAddr+1),(MAXCACHEBLOCK+1)); + f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; + + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read + { + bReadRetry(f); // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with tread reading... life is hard :) + } + + ReleaseMutex(hThreadMutex[0]); // ok, read has done + } + + bThreadEnded=1; + return 0; +} + +///////////////////////////////////////////////////////// +// emu says: we need data at given addr soon... +// so, if we don't have it in any buffer, we kick a read +// ... called on CDRreadTrack() + +BOOL DoReadThread(unsigned long addr) +{ + if(!hReadThread) return FALSE; // no thread, no fun + + bDataCacheHit=FALSE; // init data cache hit flag (even if no cache is used...) + + if(lLastAddr!=0xFFFFFFFF && // data is in curr data buffer? + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + return TRUE; // -> fine + + if(iUseDataCache && CheckDataCache(addr)) // data cache used and data is in cache? set read ptr, if yes + {bDataCacheHit=TRUE;return TRUE;} // -> and raise 'hit' flag, so we don't need to do anything in 'getbuffer' + + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait to access 'buffer 1 vars' + + if(lLastAsyncAddr!=0xFFFFFFFF && // data is (or will be soon if reading is going on in thread now) in async buffer? + addr>=lLastAsyncAddr && + addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) + { + ReleaseMutex(hThreadMutex[1]); // -> fine + return TRUE; + } + // data is not in buf0 and not in buf1: + lNeededAddr=addr; // set needed adr (mutex is active, so it's safe to change that) + ResetEvent(hThreadEvent[2]); // reset "read has started" flag + SetEvent(hThreadEvent[0]); // set "start read" flag... the read will start reading soon after + ReleaseMutex(hThreadMutex[1]); // done with var access + return TRUE; +} + +///////////////////////////////////////////////////////// +// emu says: gimme ptr to needed data... this will +// automatically do an async data prefetch read as well +// ... called on CDRgetBuffer() + +void GetREADThreadPtr(void) +{ + unsigned long addr=lLastAccessedAddr; + + if(bDataCacheHit) return; // if we had a data cache hit, the readbuf ptr is already fine, nothing else to do + + if(lLastAddr!=0xFFFFFFFF && // data is in buffer 0? + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> ok, return curr data buffer ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + return; + } + + WaitForSingleObject(hThreadEvent[2],INFINITE); // wait until reading has started (it will take a small time after the read start kick, so we have to go sure that it has _really_ started) + WaitForSingleObject(hThreadMutex[0],INFINITE); // wait until reading has finished + + lLastAddr=lLastAsyncAddr; // move data to from async data to curr data buffer (by toggling iSel) + iBufSel=!iBufSel; + lLastAsyncAddr=0xFFFFFFFF; // nothing in async data buffer now + + lNeededAddr=addr+MAXCACHEBLOCK+1; // prefetch read addr + ResetEvent(hThreadEvent[2]); // reset "read has started" flag + SetEvent(hThreadEvent[0]); // signal for start next read + ReleaseMutex(hThreadMutex[0]); // ok, now reading in buffer 1 can start + + if(iUseDataCache) // data cache used? can be less then 64 kb with thread reading, but that doesn't matter here... will be either 64 k or (max-addr) sectors + AddToDataCache(lLastAddr, + pAsyncFirstReadBuf[iBufSel]); // -> add the complete data to cache + + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> return the curr data buffer ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// special thread mode (caching 4) +// this mode helps with certain drives +// basically it does the following: +// It has a queue for n prefetch reads. If the main emu is +// asking for an addr, the mode will check, if +// this addr is a) getting read right now, b) already +// in our 4 MB cache, c) already in the q. +// If no condition matches, it will add it in q... +// the same is done with the next n/2 addr blocks, so +// the q will keep the drive busy... also, if everything +// is cached (and the q is empty), we will add additional +// addresses to read, also to keep the drive busy, and to +// do the needed reading as soon as possible :) + +///////////////////////////////////////////////////////// +// reading thread... + +DWORD WINAPI READThreadEx(LPVOID lpParameter) +{ + FRAMEBUF * f; + + while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised + INFINITE)==WAIT_OBJECT_0) + { + while(1) + { + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + ResetEvent(hThreadEvent[0]); // ok, kick event has been handled + + if(lAddrQ[iQPos]==0xFFFFFFFF) // nothing to do? strange :) + {ReleaseMutex(hThreadMutex[1]);break;} + + f=(FRAMEBUF *)ptrBuffer[0]; + lNeededAddr = lAddrQ[iQPos]; // store it in 'Neededaddr' for checks outside the thread + f->dwFrame = lNeededAddr; + f->dwFrameCnt = min((lMaxAddr-f->dwFrame+1),(MAXCACHEBLOCK+1)); + f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; + + lAddrQ[iQPos++]=0xFFFFFFFF; // set this slot as 'done' + if(iQPos>=MAXQSIZE) iQPos=0; // amnd inc the head pos + + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now + if(!iCDROK) + { + ReleaseMutex(hThreadMutex[0]); + break; + } + + if(bCDDAPlay) // some cdda security... + { // it should just prevent prefetch reads happening in cdda mode, if this one breaks a 'needed' read, we are lost... + lNeededAddr=0xFFFFFFFF; // so maybe we should remove this check? mmm, we will see + ReleaseMutex(hThreadMutex[0]); + break; + } + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read + { // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with thread reading... life is hard :) + bReadRetry(f); // but at least our 'wait for data in cache' getptr will not wait forever (just returning wrong data, ehehe) + } + + ReleaseMutex(hThreadMutex[0]); // ok, read has done + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + lNeededAddr=0xFFFFFFFF; // no read is now active + AddToDataCache(f->dwFrame,pFirstReadBuf); // add the complete data to cache + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + //------------------------------------------------// + if(WaitForSingleObject(hThreadEvent[0],0)!=WAIT_OBJECT_0) + Sleep(1); // if nobody has started a new kick, let's sleep awhile to give Windows more room to breath + } + } + + bThreadEnded=1; + return 0; +} + +///////////////////////////////////////////////////////// +// emu says: we need data at given addr soon... +// so, if we don't have it in any buffer, we kick a read +// ... called on CDRreadTrack() + +//#define THREADEX_STRAIGHT + +BOOL DoReadThreadEx(unsigned long addr) +{ + int i,k,j=0; + + if(!hReadThread) return FALSE; // no thread, no fun + + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access + +//-----------------------------------------------------// +// straight reading try... should have been faster, but +// in 'real life' this approach keeps the cdrom drive +// spinning too much, giving other pc resources no room +// to breath... by increasing the thread 'Sleep' value +// the performance can get better, but then the annoying +// breaks we wanted to fight will show up again... +// so this type is disabled as long as nobody enables the +// define again :) + +#ifdef THREADEX_STRAIGHT + + if(addr>=lNeededAddr && + addr<=(lNeededAddr+MAXCACHEBLOCK)) + { + ReleaseMutex(hThreadMutex[1]); + return TRUE; + } + + for(k=0;k=lDataCacheAddr[i] && // -> addr found? + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no prefetch read overwrites its content + break; + } + } + if(i!=MAXDATACACHE) // found in data cache? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content + else break; // here is the first unknown addr + } + + if(addr>=lMaxAddr) // check, if addr too big + { + ReleaseMutex(hThreadMutex[1]); + if(k==0) return FALSE; // -> if it's the main addr, there is an error + return TRUE; // -> otherwise we can't simply cache that addr + } + + for(i=0;i=lAddrQ[i] && // -> addr will be read soon? + addr<=(lAddrQ[i]+MAXCACHEBLOCK)) + { + addr=lAddrQ[i]; // --> take this aligned addr for new header + break; + } + } + + for(i=0;i=lMaxAddr) break; + } + + for(;i=lNeededAddr && // addr is getting read right now? + addr<=(lNeededAddr+MAXCACHEBLOCK)) // -> ok, we do nothing with it + {addr=addr+MAXCACHEBLOCK+1;continue;} + + for(i=0;i=lDataCacheAddr[i] && // -> addr found? + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no other prefetch read overwrites its content + break; + } + } + if(i!=MAXDATACACHE) // found in data cache? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content + + for(i=0;i=lAddrQ[i] && // -> addr will be read soon? + addr<=(lAddrQ[i]+MAXCACHEBLOCK)) + { + if(k==0 && i!=iQPos) // curr needed addr is not on top of the q? + { + addr=lAddrQ[i]; // -> get the addr (our main addr is in it, but that one is more aligned to prev reads) + for(i=0;i clear whole q (we will fill the slots in that loop again) + i=MAXQSIZE; // -> sign for storing the addr in q + } + break; + } + } + if(i!=MAXQSIZE) // found in q? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we will have its content soon + + // not in q or data cache? + if(k==0) lAddrQ[iQPos]=addr; // -> if it's the main addr, store it on top of list + else // -> if it's a prefetch addr, try to store it elsewhere at the end of the q + { + j=iQPos; + for(i=0;i=MAXQSIZE) j=0; + } + } + + SetEvent(hThreadEvent[0]); // kick a read, if neccessary + addr=addr+MAXCACHEBLOCK+1; // next prefetch addr + if(addr>=lMaxAddr) break; // security, for detecting if we are at the end of cd + } + + //----------------------------------------------------// ok, and here's something to keep the drive busy... + + if(lAddrQ[iQPos]==0xFFFFFFFF && addr10) // more then x times? + { + iQIdle=0; + lAddrQ[iQPos]=addr; // we add the farest prefetch addr + SetEvent(hThreadEvent[0]); // and do an additional kick + } + } + else iQIdle=0; // not idling? ok + + //----------------------------------------------------// + +#endif + + ReleaseMutex(hThreadMutex[1]); + + return TRUE; +} + +///////////////////////////////////////////////////////// +// emu says: gimme ptr to needed data... this will +// automatically do an async data prefetch read as well +// ... called on CDRgetBuffer() + +void GetREADThreadExPtr(void) +{ + unsigned long addr=lLastAccessedAddr; + + while(1) + { + if(bThreadEnded) return; // main emu is already closing (thread is down)? bye + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access + if(CheckDataCache(addr)) // data now in cache? + { + ReleaseMutex(hThreadMutex[1]); // -> ok, done + return; + } + ReleaseMutex(hThreadMutex[1]); // else try again (no sleep here, we are blocking everything anyway) + } + +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// simple data cache + +void AllocDataCache(void) +{ + bDataCacheHit=FALSE; // init thread cache hit flag + if(!iUseCaching) iUseDataCache=0; // security: no additinal data cache, if no caching active + if(iUseDataCache) + { + int i; + for(i=0;i=MAXDATACACHE) iPos=0;} // -> don't use that pos, use next one + lDataCacheAddr[iPos]=addr; + memcpy(pDataCacheBuf[iPos],pB, + MAXCDBUFFER-FRAMEBUFEXTRA); + iPos++; if(iPos>=MAXDATACACHE) iPos=0; +} + +///////////////////////////////////////////////////////// +// easy data cache check: loop MAXDATACACHE blocks, set ptr if addr found + +BOOL CheckDataCache(unsigned long addr) +{ + int i; + + for(i=0;i=lDataCacheAddr[i] && + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + pCurrReadBuf=pDataCacheBuf[i]+ + ((addr-lDataCacheAddr[i])*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + return TRUE; + } + } + return FALSE; +} + +///////////////////////////////////////////////////////// + diff --git a/plugins/cdvd/CDVDpeops/read.h b/plugins/cdvd/CDVDpeops/read.h new file mode 100644 index 0000000000..8d475e3ebe --- /dev/null +++ b/plugins/cdvd/CDVDpeops/read.h @@ -0,0 +1,41 @@ +/*************************************************************************** + read.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void CreateREADBufs(void); +void FreeREADBufs(void); +BOOL bReadRetry(FRAMEBUF * f); +BOOL DoReadAsync(unsigned long addr); +BOOL DoRead(unsigned long addr); +DWORD WINAPI READThread(LPVOID lpParameter); +BOOL DoReadThread(unsigned long addr); +void GetREADThreadPtr(void); +DWORD WINAPI READThreadEx(LPVOID lpParameter); +BOOL DoReadThreadEx(unsigned long addr); +void GetREADThreadExPtr(void); +void AllocDataCache(void); +void FreeDataCache(void); +void AddToDataCache(unsigned long addr,unsigned char * pB); +BOOL CheckDataCache(unsigned long addr); diff --git a/plugins/cdvd/CDVDpeops/readme_1_2.txt b/plugins/cdvd/CDVDpeops/readme_1_2.txt new file mode 100644 index 0000000000..1a31d5b341 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/readme_1_2.txt @@ -0,0 +1,198 @@ +P.E.Op.S. PS2 CDVD emulation plugin +--------------------------------------------------------------------------- + +The P.E.Op.S. PS2 CDVD plugin is based on the P.E.Op.S. PSX +CDR plugin which is based on Pete's CDR ASPI/IOCTL plugin +for Windows. + +--------------------------------------------------------------------------- +Introduction - 19.11.2003 +---------------------------------------------------------------------------- + +PS2 emulation is growing. + +Oh, don't get me wrong, it will still need a lot of time until +you can really play your favourite PS2 games on the PC (ehe... +and I remember how I got flamed away nearly two years ago by +die-hard know-it-alls when I predicted that it will need at +least 'a couple of years' for 'playable' PS2 emulation). + +But yeah, it is growing. Lotsa nice guys are spending their +free time coding on PCSX2, for example. One of them is Shadow... +and he never gets tired to ask me for some PS2 plugins, ehe. + +Well, what to say? Last week I had some free time as well, +Shadow asked for a CDVD plugin, and so I got to work. I took +the P.E.Op.S. cdr sources, added the PCSX2 interface, changed +some lines of code, asked a few stupid questions (hi to +linuzappz), tested it with a few PS2 dvds and cds, and it was +done. + +Of course it's not 100% complete. There are a few (but not +important) things missing, more cd/dvd modes have to get +investigated and added, etc. But basically I hope it will +work just fine with the current PCSX2 version. So go on, +and give it a try :) + +---------------------------------------------------------------------------- + +Requirements: + +* A cdrom/dvd drive (yeah, you need a dvd drive to play dvds... + no emails please telling me that your cd drive doesn't work + correctly with dvds). +* The ASPI layer with W9x/ME +* Nothing special with W2K/WXP +* Some PS2 cds/dvds. + +---------------------------------------------------------------------------- + +Installation: + +just copy the file cdvdPeops.dll into your PCSX2 \plugins +directory, that's all. + +---------------------------------------------------------------------------- + +Configuration (similar to the P.E.Op.S. psx cdr plugin): + +You HAVE TO configure the plugin before you use +it the first time. There are only a few options +available: + +0) Interface +----------------- + +If you are using W9x/ME, you have to use the ASPI Interface. +If you are using NT/W2K/XP, you have the free choice: +ASPI (if it's installed), or IOCTL scsi commands. + +1) Drive +-------------- + +Well, that's self-explaining. Just select the drive +you want to use. "NONE" is NO drive... you have to +select a real one. + +2.) Caching +------------------------------------- + +To get more speed, there are five caching modes: +None, Read ahead, Async, Thread and Smooth. + +- 'None' is the slowest mode, but it should work on +most drives. +- 'Read ahead' will read more sectors at once, speeding up +mdecs. There is a small chance that a few drives cannot +do it, so set it to 'None', if you are having troubles. +- The 'Async mode' will do read ahead and some additional +'intelligent' asynchronous reads... that mode is recommended +with the ASPI interface, it can squeeze some more speed +out of your drive :) +- The 'Thread mode' will speed up the IOCTL interfaces, +since that ones can't do real async reading. So, when +you are using W2K/XP, and you have no ASPI installed, +try this mode for best speed. +- Some drives will have speed problems reading ps2 +cds/dvds, this caching mode will try to solve such issues. + + +Also available: an additional data cache option, which +will store up to 4 MBytes of already read sectors. This +can speed up certain games, which are re-reading the +same range of sectors again and again. + + +3.) Speed limitation +------------------------------- + +Some drives will work better (less noisy and smoother) +if you limit the drive speed. Not all drives are supporting +the "set speed" command I am using, though. +If your drive doesn't support it, a message will be displayed +on startup. There are some tools in the net which will +offer the same function, prolly for a wider range of drives, +so you can also try one of them, if the plugin speed limit fails. + + +4.) Don't wait til drive is ready +----------------------------------------------- + +By default my plugin is asking the cd/dvd drive on startup, +if its state is ready (that means: a cd is inserted and the +drive can start reading). +A few drives will not answer that question (bah, bah, bah), +and the screen will stay black... forever :) +If you are encoutering that problem, you can turn on the +"Don't wait..." option, but be warned: it can cause problems +(blue screens, for example) if the plugin starts reading and +there is a problem with the drive... + + +5.) Check drive tray state +----------------------------------------------- +PCSX2 may ask the plugin if the tray is open or closed. If +this option is turned off, the plugion always will respond +"closed". If this option is enabled, the plugin will try +to ask the drive for the tray state. Since I couldn't test +this option yet, I suggest to leave it off (and honestly, +are you able to run a multi-dvd game which needs disc +changing right now in PCSX2?) :) + + +6.) Try again on reading error +----------------------------------------------- +It might happen that your drive can't read a certain sector at +the first time, if your cd/dvd is scratched. Therefore I've added +that option, by activating it you can tell the plugin to try it +up to 10 times again before reporting the read error to the +main emu. +If you want, you can also activate some error message box, +if a sector is not readable (just to inform you something is +going wrong). + + +7.) Use PPF patches (not available yet) +--------------------------------------- + +- TODO :) + + +8.) Subchannel reading (not available yet) +------------------------------------------ + +- MAYBE TODO :) + +---------------------------------------------------------------------------- + +Conclusion: + +You never ever can escape your Shadow ;) + +For version infos read the "version.txt" file. + +And, peops, have fun! + +Pete Bernert + +---------------------------------------------------------------------------- + +P.E.Op.S. page on sourceforge: https://sourceforge.net/projects/peops/ + +P.E.Op.S. developer: + +Pete Bernert http://www.pbernert.com +Lewpy http://lewpy.psxemu.com/ +lu_zero http://brsk.virtualave.net/lu_zero/ +linuzappz http://www.pcsx.net +Darko Matesic http://mrdario.tripod.com +syo http://www.geocities.co.jp/SiliconValley-Bay/2072/ + +---------------------------------------------------------------------------- + +Disclaimer/Licence: + +This plugin is under GPL... check out the license.txt file in the /src +directory for details. + +---------------------------------------------------------------------------- diff --git a/plugins/cdvd/CDVDpeops/resource.h b/plugins/cdvd/CDVDpeops/resource.h new file mode 100644 index 0000000000..3e2e235509 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/resource.h @@ -0,0 +1,56 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cdvdPeops.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_SUB 104 +#define IDC_DRIVE 1000 +#define IDC_RTYPE 1001 +#define IDC_AUTO 1002 +#define IDC_CACHE 1003 +#define IDC_SPEEDLIMIT 1004 +#define IDC_SPEED 1005 +#define IDC_NOWAIT 1006 +#define IDC_RETRY 1007 +#define IDC_SHOWREADERR 1008 +#define IDC_TRYAGAIN 1009 +#define IDC_USEPPF 1010 +#define IDC_PPFFILE 1011 +#define IDC_CHOOSEFILE 1012 +#define IDC_IMODE 1013 +#define IDC_RAWTXT 1014 +#define IDC_TRAYSTATE 1014 +#define IDC_SUBCHAN0 1015 +#define IDC_SUBCHAN1 1016 +#define IDC_DATACACHE 1016 +#define IDC_SUBCHAN2 1017 +#define IDC_SUBFILE 1018 +#define IDC_CHOOSESUBF 1019 +#define IDC_CREATESUB 1020 +#define IDC_CHOOSEOUTF 1020 +#define IDC_SUBTYPE 1021 +#define IDC_SUBSTATIC 1023 +#define IDC_WAITSTATIC 1024 +#define IDC_SUBFRAME 1026 +#define IDC_SUBOUTSTATIC 1027 +#define IDC_SUBFILEEDIT 1028 +#define IDC_SUBOUTSTATIC2 1029 +#define IDC_OUTFILEEDIT 1030 +#define IDC_SUBMODE1 1031 +#define IDC_SUBMODE2 1032 +#define IDC_SUBOUTSTATIC3 1033 +#define IDC_SUBFILL 1034 +#define IDC_SUBOUTSTATIC4 1035 +#define IDC_SFSTATIC 1035 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1036 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/cdvd/CDVDpeops/scsi.h b/plugins/cdvd/CDVDpeops/scsi.h new file mode 100644 index 0000000000..5a5603126d --- /dev/null +++ b/plugins/cdvd/CDVDpeops/scsi.h @@ -0,0 +1,55 @@ +/*************************************************************************** + scsi.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/28 - linuzappz +// - added GetSCSIStatus +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +int GetSCSIDevice(int iA,int iT,int iL); +int GetSCSIStatus(int iA,int iT,int iL); +DWORD GetSCSITOC(LPTOC toc); +int GetSCSICDDrives(char * pDList); +DWORD PlaySCSIAudio(unsigned long start,unsigned long len); +unsigned char * GetSCSIAudioSub(void); +BOOL TestSCSIUnitReady(void); +DWORD SetSCSISpeed(DWORD dwSpeed); +DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f); +DWORD InitSCSI_28_1(void); +DWORD InitSCSI_28_2(void); +DWORD DeInitSCSI_28(void); +DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f); +DWORD InitSCSI_28_2048(void); +DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f); +int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum); +int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum); +int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum); +void DecodeSub_BE_2_1(unsigned char * pBuf); +DWORD CheckSCSIReadMode(void); +DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f); + diff --git a/plugins/cdvd/CDVDpeops/scsidefs.h b/plugins/cdvd/CDVDpeops/scsidefs.h new file mode 100644 index 0000000000..180b21c546 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/scsidefs.h @@ -0,0 +1,579 @@ +//*************************************************************************** +// +// Name: SCSIDEFS.H +// +// Description: SCSI definitions ('C' Language) +// +//*************************************************************************** + +//*************************************************************************** +// %%% TARGET STATUS VALUES %%% +//*************************************************************************** +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full + +//*************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//*************************************************************************** +#define MAXLUN 7 // Maximum Logical Unit Id +#define MAXTARG 7 // Maximum Target Id +#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs +#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Commands for all Device Types %%% +//*************************************************************************** +#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_COPY 0x18 // Copy (O) +#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) +#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) +#define SCSI_LOG_SELECT 0x4C // Log Select (O) +#define SCSI_LOG_SENSE 0x4D // Log Sense (O) +#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) +#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) +#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) +#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) +#define SCSI_READ_BUFF 0x3C // Read Buffer (O) +#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) +#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) +#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Direct Access Devices %%% +//*************************************************************************** +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) +#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) +#define SCSI_PREFETCH 0x34 // Prefetch (O) +#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) +#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) +#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) +#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) +#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) +#define SCSI_READ_LONG 0x3E // Read Long (O) +#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) +#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) +#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) +#define SCSI_REZERO 0x01 // Rezero Unit (O) +#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) +#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) +#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) +#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) +#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) +#define SCSI_SET_LIMIT 0x33 // Set Limits (O) +#define SCSI_START_STP 0x1B // Start/Stop Unit (O) +#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) +#define SCSI_VERIFY 0x2F // Verify (O) +#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) +#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) +#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) +#define SCSI_WRITE_LONG 0x3F // Write Long (O) +#define SCSI_WRITE_SAME 0x41 // Write Same (O) + +//*************************************************************************** +// %%% Commands Unique to Sequential Access Devices %%% +//*************************************************************************** +#define SCSI_ERASE 0x19 // Erase (MANDATORY) +#define SCSI_LOAD_UN 0x1B // Load/Unload (O) +#define SCSI_LOCATE 0x2B // Locate (O) +#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) +#define SCSI_READ_POS 0x34 // Read Position (O) +#define SCSI_READ_REV 0x0F // Read Reverse (O) +#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) +#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) +#define SCSI_REWIND 0x01 // Rewind (MANDATORY) +#define SCSI_SPACE 0x11 // Space (MANDATORY) +#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) +#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Printer Devices %%% +//*************************************************************************** +#define SCSI_PRINT 0x0A // Print (MANDATORY) +#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) +#define SCSI_STOP_PNT 0x1B // Stop Print (O) +#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Processor Devices %%% +//*************************************************************************** +#define SCSI_RECEIVE 0x08 // Receive (O) +#define SCSI_SEND 0x0A // Send (O) + +//*************************************************************************** +// %%% Commands Unique to Write-Once Devices %%% +//*************************************************************************** +#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) +#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) +#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) +#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) +#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) +#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) +#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) +#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) +#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) +#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) +#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) +#define SCSI_WRITE12 0xAA // Write 12-Byte (O) +#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) +#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) + +//*************************************************************************** +// %%% Commands Unique to CD-ROM Devices %%% +//*************************************************************************** +#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) +#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) +#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) +#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) +#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) +#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) +#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) +#define SCSI_READHEADER 0x44 // Read Header (O) +#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) +#define SCSI_READ_TOC 0x43 // Read TOC (O) + +//*************************************************************************** +// %%% Commands Unique to Scanner Devices %%% +//*************************************************************************** +#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) +#define SCSI_GETWINDOW 0x25 // Get Window (O) +#define SCSI_OBJECTPOS 0x31 // Object Postion (O) +#define SCSI_SCAN 0x1B // Scan (O) +#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Optical Memory Devices %%% +//*************************************************************************** +#define SCSI_UpdateBlk 0x3D // Update Block (O) + +//*************************************************************************** +// %%% Commands Unique to Medium Changer Devices %%% +//*************************************************************************** +#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) +#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) +#define SCSI_POSTOELEM 0x2B // Position to Element (O) +#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) +#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) + +//*************************************************************************** +// %%% Commands Unique to Communication Devices %%% +//*************************************************************************** +#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) +#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) +#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) +#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) +#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) +#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% END OF SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Request Sense Data Format %%% +//*************************************************************************** +typedef struct { + + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier + BYTE FieldRepUCode; // Field Replaceable Unit Code + BYTE SenKeySpec15; // Sense Key Specific 15th byte + BYTE SenKeySpec16; // Sense Key Specific 16th byte + BYTE SenKeySpec17; // Sense Key Specific 17th byte + BYTE AddSenseBytes; // Additional Sense Bytes + +} SENSE_DATA_FMT; + +//*************************************************************************** +// %%% REQUEST SENSE ERROR CODE %%% +//*************************************************************************** +#define SERROR_CURRENT 0x70 // Current Errors +#define SERROR_DEFERED 0x71 // Deferred Errors + +//*************************************************************************** +// %%% REQUEST SENSE BIT DEFINITIONS %%% +//*************************************************************************** +#define SENSE_VALID 0x80 // Byte 0 Bit 7 +#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 +#define SENSE_EOM 0x40 // Byte 2 Bit 6 +#define SENSE_ILI 0x20 // Byte 2 Bit 5 + +//*************************************************************************** +// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% +//*************************************************************************** +#define KEY_NOSENSE 0x00 // No Sense +#define KEY_RECERROR 0x01 // Recovered Error +#define KEY_NOTREADY 0x02 // Not Ready +#define KEY_MEDIUMERR 0x03 // Medium Error +#define KEY_HARDERROR 0x04 // Hardware Error +#define KEY_ILLGLREQ 0x05 // Illegal Request +#define KEY_UNITATT 0x06 // Unit Attention +#define KEY_DATAPROT 0x07 // Data Protect +#define KEY_BLANKCHK 0x08 // Blank Check +#define KEY_VENDSPEC 0x09 // Vendor Specific +#define KEY_COPYABORT 0x0A // Copy Abort +#define KEY_EQUAL 0x0C // Equal (Search) +#define KEY_VOLOVRFLW 0x0D // Volume Overflow +#define KEY_MISCOMP 0x0E // Miscompare (Search) +#define KEY_RESERVED 0x0F // Reserved + +//*************************************************************************** +// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% +//*************************************************************************** +#define DTYPE_DASD 0x00 // Disk Device +#define DTYPE_SEQD 0x01 // Tape Device +#define DTYPE_PRNT 0x02 // Printer +#define DTYPE_PROC 0x03 // Processor +#define DTYPE_WORM 0x04 // Write-once read-multiple +#define DTYPE_CROM 0x05 // CD-ROM device +#define DTYPE_CDROM 0x05 // CD-ROM device +#define DTYPE_SCAN 0x06 // Scanner device +#define DTYPE_OPTI 0x07 // Optical memory device +#define DTYPE_JUKE 0x08 // Medium Changer device +#define DTYPE_COMM 0x09 // Communications device +#define DTYPE_RESL 0x0A // Reserved (low) +#define DTYPE_RESH 0x1E // Reserved (high) +#define DTYPE_UNKNOWN 0x1F // Unknown or no device type + +//*************************************************************************** +// %%% ANSI APPROVED VERSION DEFINITIONS %%% +//*************************************************************************** +#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand +#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) +#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 +#define ANSI_RESLO 0x3 // Reserved (low) +#define ANSI_RESHI 0x7 // Reserved (high) + + +//////////////////////////////////////////////////////////////// + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + + +typedef struct { + SCSI_PASS_THROUGH spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; + UCHAR ucDataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; + + +typedef struct { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + + + +typedef struct { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +} SCSI_BUS_DATA, *PSCSI_BUS_DATA; + + +typedef struct { + UCHAR NumberOfBusses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + + +typedef struct { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + + +typedef struct { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} SCSI_ADDRESS, *PSCSI_ADDRESS; + + +/* + * method codes + */ +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + * file access values + */ +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS (0x0001) +#define FILE_WRITE_ACCESS (0x0002) + + +#define IOCTL_SCSI_BASE 0x00000004 + +/* + * constants for DataIn member of SCSI_PASS_THROUGH* structures + */ +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* + * Standard IOCTL define + */ +#define CTL_CODE( DevType, Function, Method, Access ) ( \ + ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define FILE_DEVICE_CD_ROM 0x00000002 +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + +// +// CD ROM Sub-Q Channel Data Format +// + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval : 1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + + +// IOCTL_DISK_SET_CACHE allows the caller to get or set the state of the disk +// read/write caches. +// +// If the structure is provided as the input buffer for the ioctl the read & +// write caches will be enabled or disabled depending on the parameters +// provided. +// +// If the structure is provided as an output buffer for the ioctl the state +// of the read & write caches will be returned. If both input and outut buffers +// are provided the output buffer will contain the cache state BEFORE any +// changes are made + + +typedef enum { + EqualPriority, + KeepPrefetchedData, + KeepReadData +} DISK_CACHE_RETENTION_PRIORITY; + +#define FILE_DEVICE_DISK 0x00000007 +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef struct _DISK_CACHE_INFORMATION { + + // + // on return indicates that the device is capable of saving any parameters + // in non-volatile storage. On send indicates that the device should + // save the state in non-volatile storage. + // + + BOOLEAN ParametersSavable; + + // + // Indicates whether the write and read caches are enabled. + // + + BOOLEAN ReadCacheEnabled; + BOOLEAN WriteCacheEnabled; + + // + // Controls the likelyhood of data remaining in the cache depending on how + // it got there. Data cached from a READ or WRITE operation may be given + // higher, lower or equal priority to data entered into the cache for other + // means (like prefetch) + // + + DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; + DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; + + // + // Requests for a larger number of blocks than this may have prefetching + // disabled. If this value is set to 0 prefetch will be disabled. + // + + USHORT DisablePrefetchTransferLength; + + // + // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then + // the minimum and maximum values should be treated as a block count + // (BlockPrefetch) + // + + BOOLEAN PrefetchScalar; + + // + // Contains the minimum and maximum amount of data which will be + // will be prefetched into the cache on a disk operation. This value + // may either be a scalar multiplier of the transfer length of the request, + // or an abolute number of disk blocks. PrefetchScalar (above) indicates + // which interpretation is used. + // + + union { + struct { + USHORT Minimum; + USHORT Maximum; + + // + // The maximum number of blocks which will be prefetched - useful + // with the scalar limits to set definite upper limits. + // + + USHORT MaximumBlocks; + } ScalarPrefetch; + + struct { + USHORT Minimum; + USHORT Maximum; + } BlockPrefetch; + }; + +} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; + diff --git a/plugins/cdvd/CDVDpeops/sub.c b/plugins/cdvd/CDVDpeops/sub.c new file mode 100644 index 0000000000..073ecf7d8c --- /dev/null +++ b/plugins/cdvd/CDVDpeops/sub.c @@ -0,0 +1,321 @@ +/*************************************************************************** + sub.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_SUB +#include "externals.h" + +/* TODO (#1#): SUB CHANNEL STUFF */ + +///////////////////////////////////////////////////////// + +unsigned char * pCurrSubBuf=NULL; // ptr to emu sub data (or NULL) +int iUseSubReading=0; // subdata support (by file or directly) +char szSUBF[260]; // sub file name +SUB_CACHE * subCache=NULL; // cache memory +SUB_DATA * subHead=NULL; +int iSUBNum=0; // number of subdata cached +unsigned char SubCData[96]; // global data subc buffer +unsigned char SubAData[96]; // global audio subc buffer + +///////////////////////////////////////////////////////// + +void BuildSUBCache(void) +{ + FILE * subfile; + unsigned char buffer[16], * p; + SUB_DATA * plast=NULL,* px; + + if(iUseSubReading) // some subreading wanted? + { + if(iUseSubReading==1) iUseCaching=0; // -> direct read? no caching done, only 1 sector reads + memset(SubCData,0,96); // -> init subc + pCurrSubBuf=SubCData; // -> set global ptr + } + else // no plugin subreading? + { + pCurrSubBuf=NULL; // -> return NULL as subc buffer to emu + } + + memset(SubAData,0,96); // init audio subc buffer + + if(iUseSubReading!=2) return; // no subfile wanted? + if(szSUBF[0]==0) return; // no filename given? + + subfile=fopen(szSUBF, "rb"); // open subfile + if(subfile==0) + { + MessageBox(NULL,"No SBI/M3S file found!",libraryName,MB_OK); + return; + } + + memset(buffer,0,5); // read header + fread(buffer, 4, 1, subfile); + + iSUBNum=0;subHead=NULL; + + if(strcmp((char *)buffer,"SBI")==0) // ah, SBI file + { + while(fread(buffer, 4, 1, subfile)==1) // -> read record header + { + iSUBNum++; // -> one more sub cache block + px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); // -> get cache buff +//!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -> and fill it... + +/* TODO (#1#): addr2time subchannel */ + + + px->addr=time2addrB(buffer); + + px->pNext=NULL; + + px->subq[0]=0x41; + px->subq[1]=0x01; + px->subq[2]=0x01; + p=&px->subq[3]; + addr2timeB(px->addr,p); + px->subq[6]=0x00; + p=&px->subq[7]; + addr2timeB(px->addr+150,p); + + if(buffer[3]==1) + { + fread(px->subq,10, 1, subfile); + } + else if(buffer[3]==2) + { + fread(&px->subq[3],3, 1, subfile); + } + else if(buffer[3]==3) + { + fread(&px->subq[7],3, 1, subfile); + } + + if(plast==NULL) // add new cache block to linked list + { + plast=subHead=px; + } + else + { + plast->pNext=px;plast=px; + } + } + } + else // M3S file? + { // -> read data, and store all + unsigned char min,sec,frame,xmin,xsec,xframe; // -> subs which are different from + BOOL b1,b2,goon=TRUE;int iNum=0; // -> the expected calculated values + + xmin=2; + xsec=58; + xframe=0; + min=3; + sec=0; + frame=0; + + fread(buffer+4, 12, 1, subfile); + do + { + if(itod(min) != buffer[7]|| + itod(sec) != buffer[8]|| + itod(frame) != buffer[9]) + b1=TRUE; else b1=FALSE; + + if(itod(xmin) != buffer[3]|| + itod(xsec) != buffer[4]|| + itod(xframe) != buffer[5]) + b2=TRUE; else b2=FALSE; + + if(buffer[1]!=1) b1=b2=TRUE; + if(buffer[2]!=1) b1=b2=TRUE; + + if(b1 || b2) + { + iSUBNum++; + px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); + px->pNext=NULL; + memcpy(px->subq,buffer,10); + buffer[7]=itod(min); + buffer[8]=itod(sec); + buffer[9]=itod(frame); +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + px->addr=time2addrB(&buffer[7]); + + if(plast==NULL) + {plast=subHead=px;} + else {plast->pNext=px;plast=px;} + } + + xframe=xframe+1; + if(xframe>74) + { + xsec+=1; + xframe-=75; + if(xsec>59) + { + xmin+=1; + xsec-=60; + if(xmin>99) + { + goon=FALSE; + } + } + } + + frame=frame+1; + if(frame>74) + { + sec+=1; + frame-=75; + if(sec>59) + { + min+=1; + sec-=60; + if(min>99) + { + goon=FALSE; + } + } + } + iNum++; + if(iNum>(60*75)) goon=FALSE; + } + while(goon && (fread(buffer, 16, 1, subfile)==1)); + + if(iNum!=(60*75)) goon=FALSE; + else + if(iSUBNum==(60*75)) goon=FALSE; + + if(!goon) + { + MessageBox(NULL,"Bad SBI/M3S file!",libraryName,MB_OK); + fclose(subfile); + FreeSUBCache(); + return; + } + } + + subCache=NULL; + if(iSUBNum) // something in cache? + { // -> create an array with the used addresses, for fast searching access + SUB_CACHE * psc;int i; + subCache=(SUB_CACHE *)malloc(iSUBNum*sizeof(SUB_CACHE)); + psc=subCache;px=subHead; + for(i=0;ipNext) + { + psc->addr = px->addr; + psc->pNext = (void *)px; + } + iSUBNum--; + } + + fclose(subfile); +} + +///////////////////////////////////////////////////////// +// func for calculating 'right' subdata + +void FakeSubData(unsigned long adr) +{ + SubCData[12]=0x41; + SubCData[13]=0x01; + SubCData[14]=0x01; + + /* TODO (#1#): addr2time fake sub data + */ + + +//!!!!!!!!!!!!!!!!!!!!!!!???? + addr2timeB(adr, &SubCData[15]); +// SubCData[18]=0x00; + addr2timeB(adr+150,&SubCData[19]); +} + +///////////////////////////////////////////////////////// +// check, if for a given addr we have special subdata in cache + +void CheckSUBCache(long addr) +{ + SUB_CACHE * pcstart, * pcend, * pcpos; + + pcstart=subCache; // ptrs to address arrays (start/end) + pcend =subCache+iSUBNum; + + if(addr>=pcstart->addr && // easy check, if given addr is between start/end + addr<=pcend->addr) + { + while(1) // now search for sub + { + if(addr==pcend->addr) {pcpos=pcend;break;} // got it! break + + pcpos=pcstart+(pcend-pcstart)/2; // get the 'middle' address + if(pcpos==pcstart) break; // no more checks can be done + if(addraddr) // look further... + { + pcend=pcpos; + continue; + } + if(addr>pcpos->addr) + { + pcstart=pcpos; + continue; + } + break; + } + + if(addr==pcpos->addr) // found some cached data? + { + SUB_DATA * p=(SUB_DATA *)pcpos->pNext; // -> ptr to data + memcpy(&SubCData[12],p->subq,10); // -> get the data + return; // -> done + } + } + + FakeSubData(addr); // no subcdata avail, so fake right one +} + +///////////////////////////////////////////////////////// +// free all sub cache bufs + +void FreeSUBCache(void) +{ + SUB_DATA * p=subHead; + void * pn; + while(p) + { + pn=p->pNext; + free(p); + p=(SUB_DATA *)pn; + } + subHead=NULL; + + if(subCache) free(subCache); + subCache=NULL; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/sub.h b/plugins/cdvd/CDVDpeops/sub.h new file mode 100644 index 0000000000..50aa7d6167 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/sub.h @@ -0,0 +1,30 @@ +/*************************************************************************** + sub.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void BuildSUBCache(void); +void FakeSubData(unsigned long adr); +void CheckSUBCache(long addr); +void FreeSUBCache(void); diff --git a/plugins/cdvd/CDVDpeops/toc.c b/plugins/cdvd/CDVDpeops/toc.c new file mode 100644 index 0000000000..a7e23f9f23 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/toc.c @@ -0,0 +1,105 @@ +/*************************************************************************** + toc.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_TOC +#include "externals.h" + +///////////////////////////////////////////////////////// + +TOC sTOC; + +///////////////////////////////////////////////////////// +// read toc + + +void ReadTOC(void) +{ + unsigned char xbuffer[4];DWORD dwStatus; + + LockGenCDAccess(); + + memset(&(sTOC),0,sizeof(sTOC)); // init toc infos + + dwStatus=GetSCSITOC((LPTOC)&sTOC); // get toc by scsi... may change that for ioctrl in xp/2k? + + UnlockGenCDAccess(); + + if(dwStatus!=SS_COMP) return; + +#ifdef DBGOUT + auxprintf("TOC Last %d, max %08x,%08x\n",sTOC.cLastTrack,sTOC.tracks[sTOC.cLastTrack].lAddr,reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr)); +#endif + // re-order it to psemu pro standards + addr2time(reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr),xbuffer); + +#ifdef DBGOUT + auxprintf("TOC %d, %d, %d, %d\n", + xbuffer[0],xbuffer[1],xbuffer[2],xbuffer[3] ); +#endif + + xbuffer[0]=itob(xbuffer[0]); + xbuffer[1]=itob(xbuffer[1]); + xbuffer[2]=itob(xbuffer[2]); + xbuffer[3]=itob(xbuffer[3]); + lMaxAddr=time2addrB(xbuffer); // get max data adr +} + +///////////////////////////////////////////////////////// +// get the highest address of first (=data) track + +unsigned long GetLastTrack1Addr(void) +{ + unsigned char xbuffer[4];DWORD dwStatus; + unsigned long lmax; + TOC xTOC; + + LockGenCDAccess(); + + memset(&(xTOC),0,sizeof(xTOC)); + + dwStatus=GetSCSITOC((LPTOC)&xTOC); + + UnlockGenCDAccess(); + + if(dwStatus!=SS_COMP) return 0; + + addr2time(reOrder(xTOC.tracks[1].lAddr),xbuffer); + + xbuffer[0]=itob(xbuffer[0]); + xbuffer[1]=itob(xbuffer[1]); + xbuffer[2]=itob(xbuffer[2]); + xbuffer[3]=itob(xbuffer[3]); + + lmax=time2addrB(xbuffer); + if(lmax<150) return 0; + + return lmax-150; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/cdvd/CDVDpeops/toc.h b/plugins/cdvd/CDVDpeops/toc.h new file mode 100644 index 0000000000..03d31c357b --- /dev/null +++ b/plugins/cdvd/CDVDpeops/toc.h @@ -0,0 +1,28 @@ +/*************************************************************************** + toc.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void ReadTOC(void); +unsigned long GetLastTrack1Addr(void); diff --git a/plugins/cdvd/CDVDpeops/version_1_2.txt b/plugins/cdvd/CDVDpeops/version_1_2.txt new file mode 100644 index 0000000000..560e71cc61 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/version_1_2.txt @@ -0,0 +1,61 @@ +-------------------------------------------------------------------------- +25. December, 2004 Version 1.2 + +- The plugin is tested with PCSX2 0.7! + +- I've repaired a stupid bug concerning calculating the track sizes. + +- I've added an hack for big DVDs (fake minute info in the CDVDgetTD + function). + + +-------------------------------------------------------------------------- +29. March, 2004 Version 1.1 + +- Ah, to make it short: I've got some times this weekend, tried the + PCSX2 0.6 version, noticed that my relatively new Plextor PX-708A + drive didn't work with the P.E.Op.S. dvd plugin, and therefore + added a new good working reading mode. + + So, if you had just some error message like 'unable to open dvd + plugin' with PCSX2 and the P.E.Op.S. dvd plugin in the past, chances + are high that this version will now give better results on your + system. At least I was able to see the first intro screens of some + games without problems :) + + +-------------------------------------------------------------------------- + +19. November, 2003 Version 1.0 + +- What to say? Blame Shadow of the PCSX2 team... he wanted + a PS2 CDVD plugin from me, and he didn't give up asking until + I made one, sigh ;) + + Ok, I have done this plugin using my old P.E.Op.S. PSX cdr + plugin sources, so you will notice some similaries, of course. + + This plugin is able to play PS2 CDs and PS2 DVDs in your + PC's CD/DVD drives, and since all the old P.E.Op.S. cdr read + caching modes are available, the speed should be fine as well. + + For the plugin settings, check out the included readme file + (but if you are familar with the P.E.Op.S. cdr config, you + will not have much troubles... the new plugin's config is even + easier to use, since you don't have to specify a read method). + + I cannot say much about compatibility (since I did the plugin + in a few hours last weekend, and I only have a Liteon DVD drive + for tests available right now), but I think it's free of major + bugs, so feel free to try it. + + Some stuff is not available right now: PPF support and subchannel + reading, for example (but both are not very important at the + moment, imho). + + The sources of the plugin (license: GPL) can be found on the + P.E.Op.S. site on sourceforge, I've added a MS VisualStudio 6 + project file, as well as a Bloodshed Dev-C++ one (you will + also need NASM for this one). + + Ok, have fun :) diff --git a/plugins/cdvd/CDVDpeops/wnaspi32.h b/plugins/cdvd/CDVDpeops/wnaspi32.h new file mode 100644 index 0000000000..fabc0f33b3 --- /dev/null +++ b/plugins/cdvd/CDVDpeops/wnaspi32.h @@ -0,0 +1,354 @@ +/****************************************************************************** +** +** Module Name: wnaspi32.h +** +** Description: Header file for ASPI for Win32. This header includes +** macro and type declarations, and can be included without +** modification when using Borland C++ or Microsoft Visual +** C++ with 32-bit compilation. If you are using a different +** compiler then you MUST ensure that structures are packed +** onto byte alignments, and that C++ name mangling is turned +** off. +** +** Notes: This file created using 4 spaces per tab. +** +******************************************************************************/ + +#ifndef __WNASPI32_H__ +#define __WNASPI32_H__ + +/* +** Make sure structures are packed and undecorated. +*/ + +#ifdef __BORLANDC__ +#pragma option -a1 +#endif //__BORLANDC__ + +#ifdef _MSC_VER +#pragma pack(1) +#endif //__MSC_VER + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +//***************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//***************************************************************************** + +#define SENSE_LEN 14 // Default sense buffer length +#define SRB_DIR_SCSI 0x00 // Direction determined by SCSI +#define SRB_POSTING 0x01 // Enable ASPI posting +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 // Enable residual byte count reporting +#define SRB_DIR_IN 0x08 // Transfer from SCSI target to host +#define SRB_DIR_OUT 0x10 // Transfer from host to SCSI target +#define SRB_EVENT_NOTIFY 0x40 // Enable ASPI event notification + +#define RESIDUAL_COUNT_SUPPORTED 0x02 // Extended buffer flag +#define MAX_SRB_TIMEOUT 108000lu // 30 hour maximum timeout in s +#define DEFAULT_SRB_TIMEOUT 108000lu // Max timeout by default + + +//***************************************************************************** +// %%% ASPI Command Definitions %%% +//***************************************************************************** + +#define SC_HA_INQUIRY 0x00 // Host adapter inquiry +#define SC_GET_DEV_TYPE 0x01 // Get device type +#define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI command +#define SC_ABORT_SRB 0x03 // Abort an SRB +#define SC_RESET_DEV 0x04 // SCSI bus device reset +#define SC_SET_HA_PARMS 0x05 // Set HA parameters +#define SC_GET_DISK_INFO 0x06 // Get Disk information +#define SC_RESCAN_SCSI_BUS 0x07 // ReBuild SCSI device map +#define SC_GETSET_TIMEOUTS 0x08 // Get/Set target timeouts + +//***************************************************************************** +// %%% SRB Status %%% +//***************************************************************************** + +#define SS_PENDING 0x00 // SRB being processed +#define SS_COMP 0x01 // SRB completed without error +#define SS_ABORTED 0x02 // SRB aborted +#define SS_ABORT_FAIL 0x03 // Unable to abort SRB +#define SS_ERR 0x04 // SRB completed with error + +#define SS_INVALID_CMD 0x80 // Invalid ASPI command +#define SS_INVALID_HA 0x81 // Invalid host adapter number +#define SS_NO_DEVICE 0x82 // SCSI device not installed + +#define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB +#define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Windows +#define SS_BUFFER_ALIGN 0xE1 // Buffer not aligned (replaces OLD_MANAGER in Win32) +#define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode +#define SS_NO_ASPI 0xE3 // No ASPI managers resident +#define SS_FAILED_INIT 0xE4 // ASPI for windows failed init +#define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute cmd +#define SS_BUFFER_TO_BIG 0xE6 // Buffer size to big to handle! +#define SS_MISMATCHED_COMPONENTS 0xE7 // The DLLs/EXEs of ASPI don't version check +#define SS_NO_ADAPTERS 0xE8 // No host adapters to manage +#define SS_INSUFFICIENT_RESOURCES 0xE9 // Couldn't allocate resources needed to init +#define SS_ASPI_IS_SHUTDOWN 0xEA // Call came to ASPI after PROCESS_DETACH +#define SS_BAD_INSTALL 0xEB // The DLL or other components are installed wrong + +//***************************************************************************** +// %%% Host Adapter Status %%% +//***************************************************************************** + +#define HASTAT_OK 0x00 // Host adapter did not detect an // error +#define HASTAT_SEL_TO 0x11 // Selection Timeout +#define HASTAT_DO_DU 0x12 // Data overrun data underrun +#define HASTAT_BUS_FREE 0x13 // Unexpected bus free +#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence // failure +#define HASTAT_TIMEOUT 0x09 // Timed out while SRB was waiting to beprocessed. +#define HASTAT_COMMAND_TIMEOUT 0x0B // Adapter timed out processing SRB. +#define HASTAT_MESSAGE_REJECT 0x0D // While processing SRB, the // adapter received a MESSAGE +#define HASTAT_BUS_RESET 0x0E // A bus reset was detected. +#define HASTAT_PARITY_ERROR 0x0F // A parity error was detected. +#define HASTAT_REQUEST_SENSE_FAILED 0x10 // The adapter failed in issuing + +//***************************************************************************** +// %%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY (0) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_HA_INQUIRY + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE HA_Count; // 08/008 Number of host adapters present + BYTE HA_SCSI_ID; // 09/009 SCSI ID of host adapter + BYTE HA_ManagerId[16]; // 0A/010 String describing the manager + BYTE HA_Identifier[16]; // 1A/026 String describing the host adapter + BYTE HA_Unique[16]; // 2A/042 Host Adapter Unique parameters + WORD HA_Rsvd1; // 3A/058 Reserved, MUST = 0 +} +SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry; + +//***************************************************************************** +// %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1) %%% +//***************************************************************************** + +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaID; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + BYTE SRB_Target; /* 08/008 Target's SCSI ID */ + BYTE SRB_Lun; /* 09/009 Target's LUN number */ + BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */ + BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */ + BYTE pad[68]; +} SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock; + +//***************************************************************************** +// %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_EXEC_SCSI_CMD + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + WORD SRB_Rsvd1; // 0A/010 Reserved for Alignment + DWORD SRB_BufLen; // 0C/012 Data Allocation Length + BYTE FAR *SRB_BufPointer; // 10/016 Data Buffer Pointer + BYTE SRB_SenseLen; // 14/020 Sense Allocation Length + BYTE SRB_CDBLen; // 15/021 CDB Length + BYTE SRB_HaStat; // 16/022 Host Adapter Status + BYTE SRB_TargStat; // 17/023 Target Status + VOID FAR *SRB_PostProc; // 18/024 Post routine + BYTE SRB_Rsvd2[20]; // 1C/028 Reserved, MUST = 0 + BYTE CDBByte[16]; // 30/048 SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // 50/064 Request Sense buffer +} +SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd; + +//***************************************************************************** +// %%% SRB - ABORT AN SRB - SC_ABORT_SRB (3) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_ABORT_SRB + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + VOID FAR *SRB_ToAbort; // 08/008 Pointer to SRB to abort +} +SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort; + +//***************************************************************************** +// %%% SRB - BUS DEVICE RESET - SC_RESET_DEV (4) %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_RESET_DEV + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + BYTE SRB_Rsvd1[12]; // 0A/010 Reserved for Alignment + BYTE SRB_HaStat; // 16/022 Host Adapter Status + BYTE SRB_TargStat; // 17/023 Target Status + VOID FAR *SRB_PostProc; // 18/024 Post routine + BYTE SRB_Rsvd2[36]; // 1C/028 Reserved, MUST = 0 +} +SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset; + +//***************************************************************************** +// %%% SRB - GET DISK INFORMATION - SC_GET_DISK_INFO %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_GET_DISK_INFO + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved, MUST = 0 + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + BYTE SRB_DriveFlags; // 0A/010 Driver flags + BYTE SRB_Int13HDriveInfo; // 0B/011 Host Adapter Status + BYTE SRB_Heads; // 0C/012 Preferred number of heads translation + BYTE SRB_Sectors; // 0D/013 Preferred number of sectors translation + BYTE SRB_Rsvd1[10]; // 0E/014 Reserved, MUST = 0 +} +SRB_GetDiskInfo, *PSRB_GetDiskInfo, FAR *LPSRB_GetDiskInfo; + +//***************************************************************************** +// %%% SRB - RESCAN SCSI BUS(ES) ON SCSIPORT %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_RESCAN_SCSI_BUS + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 Reserved, MUST = 0 + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 +} +SRB_RescanPort, *PSRB_RescanPort, FAR *LPSRB_RescanPort; + +//***************************************************************************** +// %%% SRB - GET/SET TARGET TIMEOUTS %%% +//***************************************************************************** + +typedef struct // Offset +{ // HX/DEC + BYTE SRB_Cmd; // 00/000 ASPI command code = SC_GETSET_TIMEOUTS + BYTE SRB_Status; // 01/001 ASPI command status byte + BYTE SRB_HaId; // 02/002 ASPI host adapter number + BYTE SRB_Flags; // 03/003 ASPI request flags + DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0 + BYTE SRB_Target; // 08/008 Target's SCSI ID + BYTE SRB_Lun; // 09/009 Target's LUN number + DWORD SRB_Timeout; // 0A/010 Timeout in half seconds +} +SRB_GetSetTimeouts, *PSRB_GetSetTimeouts, FAR *LPSRB_GetSetTimeouts; + +//***************************************************************************** +// %%% ASPIBUFF - Structure For Controllng I/O Buffers %%% +//***************************************************************************** + +typedef struct tag_ASPI32BUFF // Offset +{ // HX/DEC + PBYTE AB_BufPointer; // 00/000 Pointer to the ASPI allocated buffer + DWORD AB_BufLen; // 04/004 Length in bytes of the buffer + DWORD AB_ZeroFill; // 08/008 Flag set to 1 if buffer should be zeroed + DWORD AB_Reserved; // 0C/012 Reserved +} +ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF; + +//***************************************************************************** +// %%% TOC structures %%% +//***************************************************************************** + +typedef struct +{ + unsigned char reserved1; + unsigned char cAdrCtrl; + unsigned char cTrackNum; + unsigned char reserved2; + unsigned long lAddr; +} TOC_TRACK; + +typedef struct +{ + unsigned short usTocDataLen; + unsigned char cFirstTrack; + unsigned char cLastTrack; + TOC_TRACK tracks[100]; +} TOC, *PTOC, FAR *LPTOC; + +//***************************************************************************** +// %%% PROTOTYPES - User Callable ASPI for Win32 Functions %%% +//***************************************************************************** + +typedef struct +{ + BYTE SRB_Cmd; + BYTE SRB_Status; + BYTE SRB_HaId; + BYTE SRB_Flags; + DWORD SRB_Hdr_Rsvd; +} SRB, *PSRB, FAR *LPSRB; + + +#if defined(__BORLANDC__) + +DWORD _import GetASPI32SupportInfo( void ); +DWORD _import SendASPI32Command( LPSRB ); +BOOL _import GetASPI32Buffer( PASPI32BUFF ); +BOOL _import FreeASPI32Buffer( PASPI32BUFF ); +BOOL _import TranslateASPI32Address( PDWORD, PDWORD ); + +#elif defined(_MSC_VER) + +__declspec(dllimport) DWORD GetASPI32SupportInfo( void ); +__declspec(dllimport) DWORD SendASPI32Command( LPSRB ); +__declspec(dllimport) BOOL GetASPI32Buffer( PASPI32BUFF ); +__declspec(dllimport) BOOL FreeASPI32Buffer( PASPI32BUFF ); +__declspec(dllimport) BOOL TranslateASPI32Address( PDWORD, PDWORD ); + +#else + +extern DWORD GetASPI32SupportInfo( void ); +extern DWORD GetASPI32Command( LPSRB ); +extern BOOL GetASPI32Buffer( PASPI32BUFF ); +extern BOOL FreeASPI32Buffer( PASPI32BUFF ); +extern BOOL TranslateASPI32Address( PDWORD, PDWORD ); + +#endif + +/* +** Restore compiler default packing and close off the C declarations. +*/ + +#ifdef __BORLANDC__ +#pragma option -a. +#endif //__BORLANDC__ + +#ifdef _MSC_VER +#pragma pack() +#endif //_MSC_VER + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //__WNASPI32_H__ diff --git a/plugins/cdvd/build.sh b/plugins/cdvd/build.sh new file mode 100644 index 0000000000..d6013398b3 --- /dev/null +++ b/plugins/cdvd/build.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +echo ------------------------ +echo Building CDVD plugins... +echo ------------------------ + +curdir=`pwd` + +cd ${curdir}/CDVDiso +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/CDVDisoEFP +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/CDVDlinuz +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/CDVDnull +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/plugins/dev9/DEV9linuz/DEV9.c b/plugins/dev9/DEV9linuz/DEV9.c new file mode 100644 index 0000000000..9769985323 --- /dev/null +++ b/plugins/dev9/DEV9linuz/DEV9.c @@ -0,0 +1,1292 @@ +#include +#include +#include +#include + +#include "DEV9.h" +#include "socks.h" +#include "Config.h" + +#ifdef __WIN32__ +#pragma warning(disable:4244) + +HINSTANCE hInst=NULL; +#endif + +//#define HDD_48BIT + +const u8 eeprom[] = { + 0x00, // MAC ADDR: 00:0A:E6:71:55:34 +/* 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, + 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,*/ + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +char ata_cmds[256][256]; +void (*ata_cmdf[256])(int irq); + +#define INIT_ATA_CMD(num, name, func) \ + strcpy(ata_cmds[num], name); \ + ata_cmdf[num] = func; + +void ata_unknown(int irq); +void ata_nop(int irq); +void ata_recalibrate(int irq); +void ata_readsec(int irq); +void ata_readdma(int irq); +void ata_readdma_ext(int irq); +void ata_writedma(int irq); +void ata_writedma_ext(int irq); +void ata_specify(int irq); +void ata_flushcache(int irq); +void ata_identify(int irq); +void ata_pidentify(int irq); +void ata_setidle(int irq); +void ata_setfeatures(int irq); +void ata_smart(int irq); +void ata_specify(int irq); + +int Log = 1; + +const unsigned char version = PS2E_DEV9_VERSION; +const unsigned char revision = 0; +const unsigned char build = 2; // increase that with each version + +static char *libraryName = "DEV9linuz Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_DEV9; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + +// if (!Log) return; + + va_start(list, fmt); + vfprintf(dev9Log, fmt, list); + va_end(list); +} + +#ifdef __WIN32__ +void _set_sparse(void *handle) { + DWORD bytes=0; + printf("%d\n", DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytes, NULL)); + printf("%d\n", GetLastError()); +} + +static void *_openfile(const char *filename, int flags) { + void *ret; +// printf("_openfile %s: %d;%d\n", filename, flags & O_RDONLY, flags & O_RDWR); + if (flags & O_RDWR) { + ret = CreateFile(filename, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (ret == INVALID_HANDLE_VALUE) { + ret = CreateFile(filename, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if (ret == INVALID_HANDLE_VALUE) return NULL; + } + } else + if (flags & O_WRONLY) { + ret = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + if (ret == INVALID_HANDLE_VALUE) return NULL; + } else { + ret = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (ret == INVALID_HANDLE_VALUE) return NULL; + } + _set_sparse(ret); + return ret; +} + +static u64 _tellfile(void *handle) { + u64 ofs; + u32 *_ofs = (u32*)&ofs; + _ofs[1] = 0; + _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); + DEV9_LOG("_tellfile %p, %x_%x\n", handle, _ofs[1], _ofs[0]); + return ofs; +} + +static int _seekfile(void *handle, u64 offset) { + u64 ofs = (u64)offset; + u32 *_ofs = (u32*)&ofs; + DEV9_LOG("_seekfile %p, %x_%x\n", handle, _ofs[1], _ofs[0]); + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); + return 0; +} +/* +static void dump(u8 *ptr, int size) { + int i; + DEV9_LOG("dump: "); + for (i=0; ir_status&= ~ATA_STAT_BUSY; + ata_cmdf[dev9.atacmd](1); + } + dev9Ru16(SPD_R_INTR_STAT)|= dev9.irqcause; +#ifdef DEV9_LOG + DEV9_LOG("_DEV9irqHandler %x, %x\n", dev9Ru16(SPD_R_INTR_STAT), dev9Ru16(SPD_R_INTR_MASK)); +#endif + if (dev9Ru16(SPD_R_INTR_STAT) & dev9Ru16(SPD_R_INTR_MASK)) return 1; + return 0; +} + +DEV9handler CALLBACK DEV9irqHandler(void) { + return (DEV9handler)_DEV9irqHandler; +} + +void _DEV9irq(int cause, int cycles) { +#ifdef DEV9_LOG + DEV9_LOG("_DEV9irq %x, %x\n", cause, dev9Ru16(SPD_R_INTR_MASK)); +#endif + + dev9.irqcause|= cause; + DEV9irq(cycles); +} + + +u8 CALLBACK DEV9read8(u32 addr) { + u8 hard; + + switch (addr) { + case SPD_R_PIO_DATA: + hard = dev9.eeprom[dev9.eeprompos++]; + break; + + case DEV9_R_REV: + hard = 0x30; // expansion bay + break; + + case ATA_R_CONTROL: + case ATA_R_STATUS: + case ATA_R_NSECTOR: + return DEV9read16(addr); + + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u8)FLASHread32(addr, 1); + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + return (u8)DVRread32(addr, 1); + } + + hard = dev9Ru8(addr); +#ifdef DEV9_LOG + DEV9_LOG("*Unknown 8bit read at address %lx value %x\n", addr, hard); +#endif + return hard; + } + +#ifdef DEV9_LOG + DEV9_LOG("*Known 8bit read at address %lx value %x\n", addr, hard); +#endif + return hard; +} + +u16 CALLBACK DEV9read16(u32 addr) { + u16 hard; + + switch (addr) { +#ifdef DEV9_LOG + case SMAP_R_EMAC3_MODE0_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_MODE0_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_MODE0_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_MODE0_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_MODE1_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_MODE1_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_MODE1_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_MODE1_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_RxMODE_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_RxMODE_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_RxMODE_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_RxMODE_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_INTR_STAT_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_INTR_STAT_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_INTR_STAT_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_INTR_STAT_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_INTR_ENABLE_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_INTR_ENABLE_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_INTR_ENABLE_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_INTR_ENABLE_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_TxMODE0_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_TxMODE0_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_H 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_TxMODE1_L: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_L 16bit read %x\n", hard); + return hard; + + case SMAP_R_EMAC3_TxMODE1_H: + hard = dev9Ru16(addr); + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_H 16bit read %x\n", hard); + return hard; +#endif + +/* case SPD_R_INTR_STAT: + return 0xff; +*/ + case DEV9_R_REV: + hard = 0x0030; // expansion bay + break; + + case SPD_R_REV_1: + hard = 0x0011; +#ifdef DEV9_LOG + DEV9_LOG("STD_R_REV_1 16bit read %x\n", hard); +#endif + return hard; + + case SPD_R_REV_3: + // bit 0: smap + // bit 1: hdd + // bit 5: flash + hard = 0; + if (config.hddEnable) { + hard|= 0x2; + } + if (config.ethEnable) { + hard|= 0x1; + } + hard|= 0x10 | 0x20;//dvr | flash + break; + + case SPD_R_0e: + hard = 0x0002; + break; + + case ATA_R_CONTROL: + hard = 0x0040; // we're always ready :D +#ifdef DEV9_LOG + DEV9_LOG("ATA_R_CONTROL 16bit read %x\n", hard); +#endif + return hard; + + case ATA_R_DATA: + hard = dev9.atabuf[dev9.atacount++]; dev9.atasize--; + if (dev9.atasize <= 0) { + ata_hwport->r_status&= ~ATA_STAT_DRQ; + } +#ifdef DEV9_LOG + DEV9_LOG("ATA_R_DATA 16bit read %x\n", hard); +#endif + return hard; + + case ATA_R_STATUS: + if (dev9Ru16(ATA_R_SELECT) & 0x10) { + hard = 0x0001; + } else { + hard = ata_hwport->r_status | 0x0040; // we're always ready :D + } +#ifdef DEV9_LOG + DEV9_LOG("ATA_R_STATUS 16bit read %x\n", hard); +#endif + return hard; + + case ATA_R_NSECTOR: + if ((dev9Ru16(ATA_R_SELECT) >> 4) != 0) { + hard = 0x0000; + } else { + hard = 0x0001; + } +#ifdef DEV9_LOG + DEV9_LOG("ATA_R_NSECTOR 16bit read %x\n", hard); +#endif + return hard; + + default: + if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) { + switch (addr & 0x7) { + case 0: // ctrl_stat + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("TX_CTRL_STAT[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); +#endif + return hard; + case 2: // unknown + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("TX_UNKNOWN[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); +#endif + return hard; + case 4: // length + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("TX_LENGTH[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); +#endif + return hard; + case 6: // pointer + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("TX_POINTER[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); +#endif + return hard; + } + } + if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) { + switch (addr & 0x7) { + case 0: // ctrl_stat + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("RX_CTRL_STAT[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); +#endif + return hard; + case 2: // unknown + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("RX_UNKNOWN[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); +#endif + return hard; + case 4: // length + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("RX_LENGTH[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); +#endif + return hard; + case 6: // pointer + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("RX_POINTER[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); +#endif + return hard; + } + } + + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u16)FLASHread32(addr, 2); + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + return (u16)DVRread32(addr, 2); + } + + hard = dev9Ru16(addr); +#ifdef DEV9_LOG + DEV9_LOG("*Unknown 16bit read at address %lx value %x\n", addr, hard); +#endif + return hard; + } + +#ifdef DEV9_LOG + DEV9_LOG("*Known 16bit read at address %lx value %x\n", addr, hard); +#endif + return hard; +} + +u32 CALLBACK DEV9read32(u32 addr) { + u32 hard; + + switch (addr) { + case SMAP_R_RXFIFO_DATA: + hard = *(u32*)&dev9.buffer[dev9Ru32(SMAP_R_RXFIFO_RD_PTR)]; + dev9Ru32(SMAP_R_RXFIFO_RD_PTR)+= 4; +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_RXFIFO_DATA 32bit read %x\n", hard); +#endif + return hard; + + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u32)FLASHread32(addr, 4); + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + return (u32)DVRread32(addr, 4); + } + + hard = dev9Ru32(addr); +#ifdef DEV9_LOG + DEV9_LOG("*Unkwnown 32bit read at address %lx\n", addr); +#endif + return hard; + } + +#ifdef DEV9_LOG + DEV9_LOG("*Known 32bit read at address %lx: %lx\n", addr, hard); +#endif + return hard; +} + +void CALLBACK DEV9write8(u32 addr, u8 value) { + switch (addr) { + case 0x10000020: + dev9Ru16(SPD_R_INTR_STAT) = 0xff; + break; + + case ATA_R_STATUS: + DEV9write16(addr, value); + return; + + case SMAP_R_RXFIFO_FRAME_DEC: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_RXFIFO_FRAME_DEC 8bit write %x\n", value); +#endif +// dev9Ru8(addr) = 0; // blah :P + dev9Ru8(addr) = value; + return; + + case SPD_R_PIO_DIR: +#ifdef DEV9_LOG + DEV9_LOG("SPD_R_PIO_DIR 8bit write %x\n", value); +#endif + if (value == 0xe1) dev9.eeprompos = 0; + if (value == 0xe0) dev9.eeprompos = 0; + return; + + case SPD_R_PIO_DATA: +#ifdef DEV9_LOG + DEV9_LOG("SPD_R_PIO_DATA 8bit write %x\n", value); +#endif + dev9Ru8(addr) = value; + return; + + case SMAP_R_TXFIFO_CTRL: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_TXFIFO_CTRL 8bit write %x\n", value); +#endif + value&= ~SMAP_TXFIFO_RESET; + return; + + case SMAP_R_RXFIFO_CTRL: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_RXFIFO_CTRL 8bit write %x\n", value); +#endif + value&= ~SMAP_RXFIFO_RESET; + return; + +#ifdef DEV9_LOG + case ATA_R_DATA: + DEV9_LOG("ATA_R_DATA 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_ERROR: + DEV9_LOG("ATA_R_ERROR 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_NSECTOR: + DEV9_LOG("ATA_R_NSECTOR 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_SECTOR: + DEV9_LOG("ATA_R_SECTOR 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_LCYL: + DEV9_LOG("ATA_R_LCYC 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_HCYL: + DEV9_LOG("ATA_R_HCYC 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_SELECT: + DEV9_LOG("ATA_R_SELECT 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; + + case ATA_R_CONTROL: + DEV9_LOG("ATA_R_CONTROL 8bit write %x\n", value); + dev9Ru8(addr) = value; + return; +#endif + + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 1); + return; + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + DVRwrite32(addr, (u32)value, 1); + dev9Ru8(addr) = value; + return; + } + + dev9Ru8(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Unknown 8bit write at address %lx value %x\n", addr, value); +#endif + return; + } + dev9Ru8(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Known 8bit write at address %lx value %x\n", addr, value); +#endif +} + +u32 _ata_getlba() { + u32 lba; + + if (ata_hwport->r_select & 0x40) { + lba = (ata_hwport->r_sector & 0xff); + lba|= (ata_hwport->r_lcyl & 0xff) << 8; + lba|= (ata_hwport->r_hcyl & 0xff) << 16; +#ifdef HDD_48BIT + lba|= ((ata_hwport->r_sector >> 8) & 0xff) << 24; +#else + lba|= (ata_hwport->r_select & 0x0f) << 24; +#endif + } else { +#ifdef DEV9_LOG + DEV9_LOG("fixme: lba not set\n"); +#endif + return -1; + } + + return lba; +} + +int _ata_seek() { + u32 lba; + + lba = _ata_getlba(); +#ifdef DEV9_LOG + DEV9_LOG("_ata_seek: lba=%x\n", lba); +#endif + if (lba == -1) return -1; + if (_seekfile(hdd, (u64)lba*512) != 0) { +#ifdef DEV9_LOG + DEV9_LOG("fseek error: %s\n", strerror(errno)); +#endif + return -1; + } + + return 0; +} + + +void ata_unknown(int irq) { +#ifdef DEV9_LOG + DEV9_LOG("ata_unknown\n"); +#endif + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + dev9Ru16(ATA_R_STATUS)|= ATA_STAT_ERR; + dev9Ru16(ATA_R_ERROR) = 0x01; +} + +void ata_nop(int irq) { + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); +} + +void ata_recalibrate(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_readsec(int irq) { + if (irq) { + if (_seekfile(hdd, dev9.atasector*512) != 0) { +#ifdef DEV9_LOG + DEV9_LOG("fseek error: %s\n", strerror(errno)); +#endif + dev9Ru16(ATA_R_STATUS)|= ATA_STAT_ERR; + dev9Ru16(ATA_R_ERROR) = 0x01; + return; + } + dev9.atasize = 512; + dev9.atacount = 0; +#ifdef DEV9_LOG + DEV9_LOG("read 512 bytes from %x\n", ftell(hdd) / 512); +#endif + if (_readfile(hdd, dev9.atabuf, 512) == 0) { + memset(dev9.atabuf, 0, 512); +// printf("fread error: %s\n", strerror(errno)); return; + } + + ata_hwport->r_status|= ATA_STAT_DRQ; + dev9.atasector++; + dev9.atansector--; + if (dev9.atansector > 0) { + _DEV9irq(0x1, 0x1000); + } + + return; + } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + dev9.atansector = ata_hwport->r_nsector == 0 ? 256 : ata_hwport->r_nsector; + dev9.atasector = _ata_getlba(); + if (dev9.atasector == -1) { + dev9Ru16(ATA_R_STATUS)|= ATA_STAT_ERR; + dev9Ru16(ATA_R_ERROR) = 0x01; + return; + } + + _DEV9irq(0x1, 0x1000); +} + +void ata_specify(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_flushcache(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_readdma(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_readdma_ext(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_writedma(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_writedma_ext(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_pidentify(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_identify(int irq) { + struct hd_driveid *id = (struct hd_driveid *)dev9.atabuf; + + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + memset(id, 0, sizeof(struct hd_driveid)); + id->lba_capacity = config.HddSize * 1024*2; + id->cyls = (id->lba_capacity/16)/63; + id->heads = 16; + id->sectors = 63; + +#ifdef HDD_48BIT + id->command_set_2|= 1<<10; // 48bit + id->lba_capacity_2 = (u64)config.HddSize * 1024*2; +#endif +#ifdef DEV9_LOG + DEV9_LOG("id->lba_capacity=%x\n", id->lba_capacity); + DEV9_LOG("id->lba_capacity2=%x\n", id->lba_capacity_2); +#endif + + id->capability = 0x3; // DMA | LBA + + id->model[1] = 'D'; + id->model[0] = 'E'; + id->model[3] = 'V'; + id->model[2] = '9'; + id->model[5] = ' '; + id->model[4] = 'H'; + id->model[7] = 'D'; + id->model[6] = 'D'; + dev9.atasize = 256; dev9.atacount = 0; + ata_hwport->r_status|= ATA_STAT_DRQ | ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_setidle(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_setfeatures(int irq) { + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); + + ata_hwport->r_status|= ATA_STAT_BUSY; + _DEV9irq(0x1, 0x1000); +} + +void ata_smart(int irq) { +#ifdef DEV9_LOG + DEV9_LOG("ata_smart: irq=%x r_error=%x\n", irq, ata_hwport->r_error); +#endif + if (irq) { ata_hwport->r_status&= ~ATA_STAT_BUSY; return; } + + switch (ata_hwport->r_error) { // no IO + case SMART_ENABLE: + _DEV9irq(0x1, 0x1000); + break; + + default: +#ifdef DEV9_LOG + DEV9_LOG("ata_smart: unknown cmd %x\n", ata_hwport->r_error); +#endif + } + + ata_hwport->r_error = 0; + ata_hwport->r_status&= ~(ATA_STAT_DRQ | ATA_STAT_ERR); +} + +void ata_cmd(u8 value) { +#ifdef DEV9_LOG + DEV9_LOG("ata_cmd: %s (%2.2x)\n", ata_cmds[value], value); +#endif + + dev9.atacmd = value; + ata_cmdf[dev9.atacmd](0); +} + +void CALLBACK DEV9write16(u32 addr, u16 value) { + switch (addr) { + case ATA_R_STATUS: +#ifdef DEV9_LOG + DEV9_LOG("ATA_R_STATUS 16bit write %x\n", value); +#endif + ata_cmd(value); + return; + + case SMAP_R_INTR_CLR: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_INTR_CLR 16bit write %x\n", value); +#endif + dev9Ru16(SPD_R_INTR_STAT)&= ~value; + return; + + case SMAP_R_TXFIFO_WR_PTR: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_TXFIFO_WR_PTR 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_MODE0_L: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_MODE0_L 16bit write %x\n", value); +#endif + dev9Ru16(addr) = (value & (~SMAP_E3_SOFT_RESET)) | SMAP_E3_TXMAC_IDLE | SMAP_E3_RXMAC_IDLE; + dev9Ru16(SMAP_R_EMAC3_STA_CTRL_H)|= SMAP_E3_PHY_OP_COMP; + return; + case SMAP_R_EMAC3_MODE0_H: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_MODE0_H 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_TxMODE0_L: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_L 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value & ~SMAP_E3_TX_GNP_0; + return; + case SMAP_R_EMAC3_TxMODE0_H: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_H 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_TxMODE1_L: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_L 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_TxMODE1_H: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_H 16bit write %x\n", value); +#endif + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_STA_CTRL_H: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_EMAC3_STA_CTRL_H 16bit write %x\n", value); +#endif + value|= SMAP_E3_PHY_OP_COMP; + if (value & (SMAP_E3_PHY_READ)) { + int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); + u16 val = dev9.phyregs[reg]; + switch (reg) { + case SMAP_DsPHYTER_BMSR: + val|= SMAP_PHY_BMSR_LINK | SMAP_PHY_BMSR_ANCP; + break; + case SMAP_DsPHYTER_PHYSTS: + val|= SMAP_PHY_STS_LINK | SMAP_PHY_STS_ANCP; + break; + } +#ifdef DEV9_LOG + DEV9_LOG("phy_read %d: %x\n", reg, val); +#endif + dev9Ru16(SMAP_R_EMAC3_STA_CTRL_L) = val; + } else + if (value & (SMAP_E3_PHY_WRITE)) { + int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); + u16 val = dev9Ru16(SMAP_R_EMAC3_STA_CTRL_L); + switch (reg) { + case SMAP_DsPHYTER_BMCR: + val&= ~SMAP_PHY_BMCR_RST; + val|= 0x1; + break; + } +#ifdef DEV9_LOG + DEV9_LOG("phy_write %d: %x\n", reg, val); +#endif + dev9.phyregs[reg] = val; + } + break; + default: + if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) { + switch (addr & 0x7) { + case 0: // ctrl_stat +#ifdef DEV9_LOG + DEV9_LOG("TX_CTRL_STAT[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); +#endif + if (value & SMAP_BD_TX_READY) { + u32 base = (SMAP_REGBASE + dev9Ru16(addr + 6)) & 0xffff; + +#ifdef DEV9_LOG + DEV9_LOG("sockSendData: base %x, size %d\n", base, dev9Ru16(addr + 4)); +#endif + sockSendData(&dev9.dev9R[base], dev9Ru16(addr + 4)); + _DEV9irq(SMAP_INTR_TXEND, 0x1000); + value&= ~SMAP_BD_TX_READY; + } + dev9Ru16(addr) = value; + return; + case 2: // unknown +#ifdef DEV9_LOG + DEV9_LOG("TX_UNKNOWN[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + case 4: // length +#ifdef DEV9_LOG + DEV9_LOG("TX_LENGTH[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + case 6: // pointer +#ifdef DEV9_LOG + DEV9_LOG("TX_POINTER[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + } + } + if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) { + switch (addr & 0x7) { + case 0: // ctrl_stat +#ifdef DEV9_LOG + DEV9_LOG("RX_CTRL_STAT[%d]: write %x\n", (addr - SMAP_BD_RX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + case 2: // unknown +#ifdef DEV9_LOG + DEV9_LOG("RX_UNKNOWN[%d]: write %x\n", (addr - SMAP_BD_RX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + case 4: // length +#ifdef DEV9_LOG + DEV9_LOG("RX_LENGTH[%d]: write %x\n", (addr - SMAP_BD_RX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + case 6: // pointer +#ifdef DEV9_LOG + DEV9_LOG("RX_POINTER[%d]: write %x\n", (addr - SMAP_BD_RX_BASE) / 8, value); +#endif + dev9Ru16(addr) = value; + return; + } + } + + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 2); + return; + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + DVRwrite32(addr, (u32)value, 2); + dev9Ru16(addr) = value; + return; + } + + dev9Ru16(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Unknown 16bit write at address %lx value %x\n", addr, value); +#endif + return; + } + dev9Ru16(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Known 16bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK DEV9write32(u32 addr, u32 value) { + switch (addr) { + case SMAP_R_TXFIFO_DATA: +#ifdef DEV9_LOG + DEV9_LOG("SMAP_R_TXFIFO_DATA 32bit write %x (ptr %x)\n", value, SMAP_TX_BASE + dev9Ru32(SMAP_R_TXFIFO_WR_PTR)); +#endif + dev9Ru32(SMAP_TX_BASE + dev9Ru32(SMAP_R_TXFIFO_WR_PTR)) = value; + dev9Ru32(SMAP_R_TXFIFO_WR_PTR)+= 4; + return; + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 4); + return; + } + if ((addr >= DVR_REGBASE) && (addr < (DVR_REGBASE + DVR_REGSIZE))) { + DVRwrite32(addr, (u32)value, 4); + dev9Ru32(addr) = value; + return; + } + + dev9Ru32(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Unknown 32bit write at address %lx write %x\n", addr, value); +#endif + return; + } + dev9Ru32(addr) = value; +#ifdef DEV9_LOG + DEV9_LOG("*Known 32bit write at address %lx value %lx\n", addr, value); +#endif +} + +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size) { +#ifdef DEV9_LOG + DEV9_LOG("*DEV9readDMA8Mem: size %x\n", size); +#endif + + if (_ata_seek() == -1) return; +#ifdef DEV9_LOG + DEV9_LOG("read %x bytes from %x\n", size, _tellfile(hdd) / 512); +#endif + + if (_readfile(hdd, pMem, size) == 0) { +#ifdef DEV9_LOG + DEV9_LOG("fread error: %s\n", strerror(errno)); +#endif + memset(pMem, 0, size); + return; + } +} + +void CALLBACK DEV9writeDMA8Mem(u32* pMem, int size) { +#ifdef DEV9_LOG + DEV9_LOG("*DEV9writeDMA8Mem: size %x\n", size); +#endif + + if (_ata_seek() == -1) return; +#ifdef DEV9_LOG + DEV9_LOG("write %x bytes from %x\n", size, _tellfile(hdd) / 512); +#endif + + if (_writefile(hdd, pMem, size) == 0) { +#ifdef DEV9_LOG + DEV9_LOG("fwrite error: %s\n", strerror(errno)); +#endif + return; + } +} + +void CALLBACK DEV9irqCallback(void (*callback)(int cycles)) { + DEV9irq = callback; +} + + +// extended funcs + +s32 CALLBACK DEV9test() { + return 0; +} + +void DEV9thread() { + smap_bd_t *pbd; + int bytes; + int rxbi = 0; + + if (config.ethEnable == 0) return; + +// if (sockOpen("d9n0") == -1) { + if (sockOpen(config.Eth) == -1) { + SysMessage("Can't open Device '%s'\n", config.Eth); + return; + } + ThreadRun = 1; + while (ThreadRun) { +#ifdef DEV9_LOG + DEV9_LOG("sockRecvData\n"); +#endif + bytes = sockRecvData(dev9.buffer, sizeof(dev9.buffer)); +#ifdef DEV9_LOG + DEV9_LOG("sockRecvData: %d\n", bytes); +#endif + if (bytes <= 0) continue; + + pbd = (smap_bd_t *)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff]; + pbd = &pbd[rxbi]; + if (!(pbd->ctrl_stat & SMAP_BD_RX_EMPTY)) { +#ifdef DEV9_LOG + DEV9_LOG("Discarding %d bytes (RX%d not ready)\n", bytes, rxbi); +#endif + printf("Discarding %d bytes (RX%d not ready)\n", bytes, rxbi); + continue; + } +#ifdef DEV9_LOG + DEV9_LOG("DEV9received %d bytes, rxbi %d\n", bytes, rxbi); +#endif + + rxbi++; + if (rxbi == (SMAP_BD_SIZE/8)) rxbi = 0; + + pbd->ctrl_stat&= ~SMAP_BD_RX_EMPTY; + pbd->length = bytes; +// dev9Ru8(SMAP_R_RXFIFO_FRAME_DEC) = 1; // guessing ;) + _DEV9irq(SMAP_INTR_RXEND, 0); + } +} + diff --git a/plugins/dev9/DEV9linuz/DEV9.h b/plugins/dev9/DEV9linuz/DEV9.h new file mode 100644 index 0000000000..76290c997a --- /dev/null +++ b/plugins/dev9/DEV9linuz/DEV9.h @@ -0,0 +1,1157 @@ +#ifndef __DEV9_H__ +#define __DEV9_H__ + +#include + +#define DEV9defs +#define WINVER 0x0500 +#define _WIN32_WINNT 0x0500 + +#include "PS2Edefs.h" + +#ifdef __WIN32__ + + +#define usleep(x) Sleep(x / 1000) +#include +#include +#include + +#else + +#include + +#define __inline inline + +#endif + +#define DEV9_LOG __Log + +#define ETH_DEF "eth0" +#define HDD_DEF "DEV9hdd.raw" + +typedef struct { + char Eth[256]; + char Hdd[256]; + int HddSize; + + int hddEnable; + int ethEnable; +} Config; + +Config config; + +typedef struct { + s8 dev9R[0x10000]; + int eeprompos; + u8 eeprom[65]; + u8 buffer[2048]; + u16 atabuf[1024]; + u32 atacount; + u32 atasize; + u16 phyregs[32]; + int irqcause; + u8 atacmd; + u32 atasector; + u32 atansector; +} dev9Struct; + +dev9Struct dev9; + +#define dev9Rs8(mem) dev9.dev9R[(mem) & 0xffff] +#define dev9Rs16(mem) (*(s16*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Rs32(mem) (*(s32*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru8(mem) (*(u8*) &dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru16(mem) (*(u16*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru32(mem) (*(u32*)&dev9.dev9R[(mem) & 0xffff]) + +void *hdd; +int ThreadRun; + +s32 _DEV9open(); +void _DEV9close(); +DEV9callback DEV9irq; +void DEV9thread(); + +FILE *dev9Log; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#define DEV9_R_REV 0x1f80146e + + +/* + * SPEED (ASIC on SMAP) register definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2smap iop driver, modified by linuzappz * + */ + +#define SPD_REGBASE 0x10000000 + +#define SPD_R_REV (SPD_REGBASE + 0x00) +#define SPD_R_REV_1 (SPD_REGBASE + 0x02) +#define SPD_R_REV_3 (SPD_REGBASE + 0x04) +#define SPD_R_0e (SPD_REGBASE + 0x0e) + +#define SPD_R_DMA_CTRL (SPD_REGBASE + 0x24) +#define SPD_R_INTR_STAT (SPD_REGBASE + 0x28) +#define SPD_R_INTR_MASK (SPD_REGBASE + 0x2a) +#define SPD_R_PIO_DIR (SPD_REGBASE + 0x2c) +#define SPD_R_PIO_DATA (SPD_REGBASE + 0x2e) +#define SPD_PP_DOUT (1<<4) /* Data output, read port */ +#define SPD_PP_DIN (1<<5) /* Data input, write port */ +#define SPD_PP_SCLK (1<<6) /* Clock, write port */ +#define SPD_PP_CSEL (1<<7) /* Chip select, write port */ +/* Operation codes */ +#define SPD_PP_OP_READ 2 +#define SPD_PP_OP_WRITE 1 +#define SPD_PP_OP_EWEN 0 +#define SPD_PP_OP_EWDS 0 + +#define SPD_R_XFR_CTRL (SPD_REGBASE + 0x32) +#define SPD_R_IF_CTRL (SPD_REGBASE + 0x64) +#define SPD_IF_ATA_RESET 0x80 +#define SPD_IF_DMA_ENABLE 0x04 +#define SPD_R_PIO_MODE (SPD_REGBASE + 0x70) +#define SPD_R_MWDMA_MODE (SPD_REGBASE + 0x72) +#define SPD_R_UDMA_MODE (SPD_REGBASE + 0x74) + + +/* + * SMAP (PS2 Network Adapter) register definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2smap iop driver, modified by linuzappz * + */ + + +/* SMAP interrupt status bits (selected from the SPEED device). */ +#define SMAP_INTR_EMAC3 (1<<6) +#define SMAP_INTR_RXEND (1<<5) +#define SMAP_INTR_TXEND (1<<4) +#define SMAP_INTR_RXDNV (1<<3) /* descriptor not valid */ +#define SMAP_INTR_TXDNV (1<<2) /* descriptor not valid */ +#define SMAP_INTR_CLR_ALL (SMAP_INTR_RXEND|SMAP_INTR_TXEND|SMAP_INTR_RXDNV) +#define SMAP_INTR_ENA_ALL (SMAP_INTR_EMAC3|SMAP_INTR_CLR_ALL) +#define SMAP_INTR_BITMSK 0x7C + +/* SMAP Register Definitions. */ + +#define SMAP_REGBASE (SPD_REGBASE + 0x100) + +#define SMAP_R_BD_MODE (SMAP_REGBASE + 0x02) +#define SMAP_BD_SWAP (1<<0) + +#define SMAP_R_INTR_CLR (SMAP_REGBASE + 0x28) + +/* SMAP FIFO Registers. */ + +#define SMAP_R_TXFIFO_CTRL (SMAP_REGBASE + 0xf00) +#define SMAP_TXFIFO_RESET (1<<0) +#define SMAP_TXFIFO_DMAEN (1<<1) +#define SMAP_R_TXFIFO_WR_PTR (SMAP_REGBASE + 0xf04) +#define SMAP_R_TXFIFO_SIZE (SMAP_REGBASE + 0xf08) +#define SMAP_R_TXFIFO_FRAME_CNT (SMAP_REGBASE + 0xf0C) +#define SMAP_R_TXFIFO_FRAME_INC (SMAP_REGBASE + 0xf10) +#define SMAP_R_TXFIFO_DATA (SMAP_REGBASE + 0x1000) + +#define SMAP_R_RXFIFO_CTRL (SMAP_REGBASE + 0xf30) +#define SMAP_RXFIFO_RESET (1<<0) +#define SMAP_RXFIFO_DMAEN (1<<1) +#define SMAP_R_RXFIFO_RD_PTR (SMAP_REGBASE + 0xf34) +#define SMAP_R_RXFIFO_SIZE (SMAP_REGBASE + 0xf38) +#define SMAP_R_RXFIFO_FRAME_CNT (SMAP_REGBASE + 0xf3C) +#define SMAP_R_RXFIFO_FRAME_DEC (SMAP_REGBASE + 0xf40) +#define SMAP_R_RXFIFO_DATA (SMAP_REGBASE + 0x1100) + +#define SMAP_R_FIFO_ADDR (SMAP_REGBASE + 0x1200) +#define SMAP_FIFO_CMD_READ (1<<1) +#define SMAP_FIFO_DATA_SWAP (1<<0) +#define SMAP_R_FIFO_DATA (SMAP_REGBASE + 0x1208) + +/* EMAC3 Registers. */ + +#define SMAP_EMAC3_REGBASE (SMAP_REGBASE + 0x1f00) + +#define SMAP_R_EMAC3_MODE0_L (SMAP_EMAC3_REGBASE + 0x00) +#define SMAP_E3_RXMAC_IDLE (1<<15) +#define SMAP_E3_TXMAC_IDLE (1<<14) +#define SMAP_E3_SOFT_RESET (1<<13) +#define SMAP_E3_TXMAC_ENABLE (1<<12) +#define SMAP_E3_RXMAC_ENABLE (1<<11) +#define SMAP_E3_WAKEUP_ENABLE (1<<10) +#define SMAP_R_EMAC3_MODE0_H (SMAP_EMAC3_REGBASE + 0x02) + +#define SMAP_R_EMAC3_MODE1 (SMAP_EMAC3_REGBASE + 0x04) +#define SMAP_R_EMAC3_MODE1_L (SMAP_EMAC3_REGBASE + 0x04) +#define SMAP_R_EMAC3_MODE1_H (SMAP_EMAC3_REGBASE + 0x06) +#define SMAP_E3_FDX_ENABLE (1<<31) +#define SMAP_E3_INLPBK_ENABLE (1<<30) /* internal loop back */ +#define SMAP_E3_VLAN_ENABLE (1<<29) +#define SMAP_E3_FLOWCTRL_ENABLE (1<<28) /* integrated flow ctrl(pause frame) */ +#define SMAP_E3_ALLOW_PF (1<<27) /* allow pause frame */ +#define SMAP_E3_ALLOW_EXTMNGIF (1<<25) /* allow external management IF */ +#define SMAP_E3_IGNORE_SQE (1<<24) +#define SMAP_E3_MEDIA_FREQ_BITSFT (22) +#define SMAP_E3_MEDIA_10M (0<<22) +#define SMAP_E3_MEDIA_100M (1<<22) +#define SMAP_E3_MEDIA_1000M (2<<22) +#define SMAP_E3_MEDIA_MSK (3<<22) +#define SMAP_E3_RXFIFO_SIZE_BITSFT (20) +#define SMAP_E3_RXFIFO_512 (0<<20) +#define SMAP_E3_RXFIFO_1K (1<<20) +#define SMAP_E3_RXFIFO_2K (2<<20) +#define SMAP_E3_RXFIFO_4K (3<<20) +#define SMAP_E3_TXFIFO_SIZE_BITSFT (18) +#define SMAP_E3_TXFIFO_512 (0<<18) +#define SMAP_E3_TXFIFO_1K (1<<18) +#define SMAP_E3_TXFIFO_2K (2<<18) +#define SMAP_E3_TXREQ0_BITSFT (15) +#define SMAP_E3_TXREQ0_SINGLE (0<<15) +#define SMAP_E3_TXREQ0_MULTI (1<<15) +#define SMAP_E3_TXREQ0_DEPEND (2<<15) +#define SMAP_E3_TXREQ1_BITSFT (13) +#define SMAP_E3_TXREQ1_SINGLE (0<<13) +#define SMAP_E3_TXREQ1_MULTI (1<<13) +#define SMAP_E3_TXREQ1_DEPEND (2<<13) +#define SMAP_E3_JUMBO_ENABLE (1<<12) + +#define SMAP_R_EMAC3_TxMODE0_L (SMAP_EMAC3_REGBASE + 0x08) +#define SMAP_E3_TX_GNP_0 (1<<15) /* get new packet */ +#define SMAP_E3_TX_GNP_1 (1<<14) /* get new packet */ +#define SMAP_E3_TX_GNP_DEPEND (1<<13) /* get new packet */ +#define SMAP_E3_TX_FIRST_CHANNEL (1<<12) +#define SMAP_R_EMAC3_TxMODE0_H (SMAP_EMAC3_REGBASE + 0x0A) + +#define SMAP_R_EMAC3_TxMODE1_L (SMAP_EMAC3_REGBASE + 0x0C) +#define SMAP_R_EMAC3_TxMODE1_H (SMAP_EMAC3_REGBASE + 0x0E) +#define SMAP_E3_TX_LOW_REQ_MSK (0x1F) /* low priority request */ +#define SMAP_E3_TX_LOW_REQ_BITSFT (27) /* low priority request */ +#define SMAP_E3_TX_URG_REQ_MSK (0xFF) /* urgent priority request */ +#define SMAP_E3_TX_URG_REQ_BITSFT (16) /* urgent priority request */ + +#define SMAP_R_EMAC3_RxMODE (SMAP_EMAC3_REGBASE + 0x10) +#define SMAP_R_EMAC3_RxMODE_L (SMAP_EMAC3_REGBASE + 0x10) +#define SMAP_R_EMAC3_RxMODE_H (SMAP_EMAC3_REGBASE + 0x12) +#define SMAP_E3_RX_STRIP_PAD (1<<31) +#define SMAP_E3_RX_STRIP_FCS (1<<30) +#define SMAP_E3_RX_RX_RUNT_FRAME (1<<29) +#define SMAP_E3_RX_RX_FCS_ERR (1<<28) +#define SMAP_E3_RX_RX_TOO_LONG_ERR (1<<27) +#define SMAP_E3_RX_RX_IN_RANGE_ERR (1<<26) +#define SMAP_E3_RX_PROP_PF (1<<25) /* propagate pause frame */ +#define SMAP_E3_RX_PROMISC (1<<24) +#define SMAP_E3_RX_PROMISC_MCAST (1<<23) +#define SMAP_E3_RX_INDIVID_ADDR (1<<22) +#define SMAP_E3_RX_INDIVID_HASH (1<<21) +#define SMAP_E3_RX_BCAST (1<<20) +#define SMAP_E3_RX_MCAST (1<<19) + +#define SMAP_R_EMAC3_INTR_STAT (SMAP_EMAC3_REGBASE + 0x14) +#define SMAP_R_EMAC3_INTR_STAT_L (SMAP_EMAC3_REGBASE + 0x14) +#define SMAP_R_EMAC3_INTR_STAT_H (SMAP_EMAC3_REGBASE + 0x16) +#define SMAP_R_EMAC3_INTR_ENABLE (SMAP_EMAC3_REGBASE + 0x18) +#define SMAP_R_EMAC3_INTR_ENABLE_L (SMAP_EMAC3_REGBASE + 0x18) +#define SMAP_R_EMAC3_INTR_ENABLE_H (SMAP_EMAC3_REGBASE + 0x1C) +#define SMAP_E3_INTR_OVERRUN (1<<25) /* this bit does NOT WORKED */ +#define SMAP_E3_INTR_PF (1<<24) +#define SMAP_E3_INTR_BAD_FRAME (1<<23) +#define SMAP_E3_INTR_RUNT_FRAME (1<<22) +#define SMAP_E3_INTR_SHORT_EVENT (1<<21) +#define SMAP_E3_INTR_ALIGN_ERR (1<<20) +#define SMAP_E3_INTR_BAD_FCS (1<<19) +#define SMAP_E3_INTR_TOO_LONG (1<<18) +#define SMAP_E3_INTR_OUT_RANGE_ERR (1<<17) +#define SMAP_E3_INTR_IN_RANGE_ERR (1<<16) +#define SMAP_E3_INTR_DEAD_DEPEND (1<<9) +#define SMAP_E3_INTR_DEAD_0 (1<<8) +#define SMAP_E3_INTR_SQE_ERR_0 (1<<7) +#define SMAP_E3_INTR_TX_ERR_0 (1<<6) +#define SMAP_E3_INTR_DEAD_1 (1<<5) +#define SMAP_E3_INTR_SQE_ERR_1 (1<<4) +#define SMAP_E3_INTR_TX_ERR_1 (1<<3) +#define SMAP_E3_INTR_MMAOP_SUCCESS (1<<1) +#define SMAP_E3_INTR_MMAOP_FAIL (1<<0) +#define SMAP_E3_INTR_ALL \ + (SMAP_E3_INTR_OVERRUN|SMAP_E3_INTR_PF|SMAP_E3_INTR_BAD_FRAME| \ + SMAP_E3_INTR_RUNT_FRAME|SMAP_E3_INTR_SHORT_EVENT| \ + SMAP_E3_INTR_ALIGN_ERR|SMAP_E3_INTR_BAD_FCS| \ + SMAP_E3_INTR_TOO_LONG|SMAP_E3_INTR_OUT_RANGE_ERR| \ + SMAP_E3_INTR_IN_RANGE_ERR| \ + SMAP_E3_INTR_DEAD_DEPEND|SMAP_E3_INTR_DEAD_0| \ + SMAP_E3_INTR_SQE_ERR_0|SMAP_E3_INTR_TX_ERR_0| \ + SMAP_E3_INTR_DEAD_1|SMAP_E3_INTR_SQE_ERR_1| \ + SMAP_E3_INTR_TX_ERR_1| \ + SMAP_E3_INTR_MMAOP_SUCCESS|SMAP_E3_INTR_MMAOP_FAIL) +#define SMAP_E3_DEAD_ALL \ + (SMAP_E3_INTR_DEAD_DEPEND|SMAP_E3_INTR_DEAD_0| \ + SMAP_E3_INTR_DEAD_1) + +#define SMAP_R_EMAC3_ADDR_HI (SMAP_EMAC3_REGBASE + 0x1C) +#define SMAP_R_EMAC3_ADDR_LO (SMAP_EMAC3_REGBASE + 0x20) + +#define SMAP_R_EMAC3_VLAN_TPID (SMAP_EMAC3_REGBASE + 0x24) +#define SMAP_E3_VLAN_ID_MSK 0xFFFF + +#define SMAP_R_EMAC3_VLAN_TCI (SMAP_EMAC3_REGBASE + 0x28) +#define SMAP_E3_VLAN_TCITAG_MSK 0xFFFF + +#define SMAP_R_EMAC3_PAUSE_TIMER (SMAP_EMAC3_REGBASE + 0x2C) +#define SMAP_E3_PTIMER_MSK 0xFFFF + +#define SMAP_R_EMAC3_INDIVID_HASH1 (SMAP_EMAC3_REGBASE + 0x30) +#define SMAP_R_EMAC3_INDIVID_HASH2 (SMAP_EMAC3_REGBASE + 0x34) +#define SMAP_R_EMAC3_INDIVID_HASH3 (SMAP_EMAC3_REGBASE + 0x38) +#define SMAP_R_EMAC3_INDIVID_HASH4 (SMAP_EMAC3_REGBASE + 0x3C) +#define SMAP_R_EMAC3_GROUP_HASH1 (SMAP_EMAC3_REGBASE + 0x40) +#define SMAP_R_EMAC3_GROUP_HASH2 (SMAP_EMAC3_REGBASE + 0x44) +#define SMAP_R_EMAC3_GROUP_HASH3 (SMAP_EMAC3_REGBASE + 0x48) +#define SMAP_R_EMAC3_GROUP_HASH4 (SMAP_EMAC3_REGBASE + 0x4C) +#define SMAP_E3_HASH_MSK 0xFFFF + +#define SMAP_R_EMAC3_LAST_SA_HI (SMAP_EMAC3_REGBASE + 0x50) +#define SMAP_R_EMAC3_LAST_SA_LO (SMAP_EMAC3_REGBASE + 0x54) + +#define SMAP_R_EMAC3_INTER_FRAME_GAP (SMAP_EMAC3_REGBASE + 0x58) +#define SMAP_E3_IFGAP_MSK 0x3F + +#define SMAP_R_EMAC3_STA_CTRL_L (SMAP_EMAC3_REGBASE + 0x5C) +#define SMAP_R_EMAC3_STA_CTRL_H (SMAP_EMAC3_REGBASE + 0x5E) +#define SMAP_E3_PHY_DATA_MSK (0xFFFF) +#define SMAP_E3_PHY_DATA_BITSFT (16) +#define SMAP_E3_PHY_OP_COMP (1<<15) /* operation complete */ +#define SMAP_E3_PHY_ERR_READ (1<<14) +#define SMAP_E3_PHY_STA_CMD_BITSFT (12) +#define SMAP_E3_PHY_READ (1<<12) +#define SMAP_E3_PHY_WRITE (2<<12) +#define SMAP_E3_PHY_OPBCLCK_BITSFT (10) +#define SMAP_E3_PHY_50M (0<<10) +#define SMAP_E3_PHY_66M (1<<10) +#define SMAP_E3_PHY_83M (2<<10) +#define SMAP_E3_PHY_100M (3<<10) +#define SMAP_E3_PHY_ADDR_MSK (0x1F) +#define SMAP_E3_PHY_ADDR_BITSFT (5) +#define SMAP_E3_PHY_REG_ADDR_MSK (0x1F) + +#define SMAP_R_EMAC3_TX_THRESHOLD (SMAP_EMAC3_REGBASE + 0x60) +#define SMAP_E3_TX_THRESHLD_MSK (0x1F) +#define SMAP_E3_TX_THRESHLD_BITSFT (27) + +#define SMAP_R_EMAC3_RX_WATERMARK (SMAP_EMAC3_REGBASE + 0x64) +#define SMAP_E3_RX_LO_WATER_MSK (0x1FF) +#define SMAP_E3_RX_LO_WATER_BITSFT (23) +#define SMAP_E3_RX_HI_WATER_MSK (0x1FF) +#define SMAP_E3_RX_HI_WATER_BITSFT (7) + +#define SMAP_R_EMAC3_TX_OCTETS (SMAP_EMAC3_REGBASE + 0x68) +#define SMAP_R_EMAC3_RX_OCTETS (SMAP_EMAC3_REGBASE + 0x6C) + +/* Buffer descriptors. */ + +typedef struct _smap_bd { + u16 ctrl_stat; + u16 reserved; /* must be zero */ + u16 length; /* number of bytes in pkt */ + u16 pointer; +} smap_bd_t; + +#define SMAP_BD_REGBASE (SMAP_REGBASE + 0x2f00) +#define SMAP_BD_TX_BASE (SMAP_BD_REGBASE + 0x0000) +#define SMAP_TX_BASE (SMAP_REGBASE + 0x1000) +#define SMAP_TX_BUFSIZE 4096 +#define SMAP_BD_RX_BASE (SMAP_BD_REGBASE + 0x0200) +#define SMAP_BD_SIZE 512 +#define SMAP_BD_MAX_ENTRY 64 + +/* TX Control */ +#define SMAP_BD_TX_READY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_TX_GENFCS (1<<9) /* generate FCS */ +#define SMAP_BD_TX_GENPAD (1<<8) /* generate padding */ +#define SMAP_BD_TX_INSSA (1<<7) /* insert source address */ +#define SMAP_BD_TX_RPLSA (1<<6) /* replace source address */ +#define SMAP_BD_TX_INSVLAN (1<<5) /* insert VLAN Tag */ +#define SMAP_BD_TX_RPLVLAN (1<<4) /* replace VLAN Tag */ + +/* TX Status */ +#define SMAP_BD_TX_READY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_TX_BADFCS (1<<9) /* bad FCS */ +#define SMAP_BD_TX_BADPKT (1<<8) /* bad previous pkt in dependent mode */ +#define SMAP_BD_TX_LOSSCR (1<<7) /* loss of carrior sense */ +#define SMAP_BD_TX_EDEFER (1<<6) /* excessive deferal */ +#define SMAP_BD_TX_ECOLL (1<<5) /* excessive collision */ +#define SMAP_BD_TX_LCOLL (1<<4) /* late collision */ +#define SMAP_BD_TX_MCOLL (1<<3) /* multiple collision */ +#define SMAP_BD_TX_SCOLL (1<<2) /* single collision */ +#define SMAP_BD_TX_UNDERRUN (1<<1) /* underrun */ +#define SMAP_BD_TX_SQE (1<<0) /* SQE */ + +#define SMAP_BD_TX_ERROR (SMAP_BD_TX_LOSSCR|SMAP_BD_TX_EDEFER|SMAP_BD_TX_ECOLL| \ + SMAP_BD_TX_LCOLL|SMAP_BD_TX_UNDERRUN) + +/* RX Control */ +#define SMAP_BD_RX_EMPTY (1<<15) /* set:driver, clear:HW */ + +/* RX Status */ +#define SMAP_BD_RX_EMPTY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_RX_OVERRUN (1<<9) /* overrun */ +#define SMAP_BD_RX_PFRM (1<<8) /* pause frame */ +#define SMAP_BD_RX_BADFRM (1<<7) /* bad frame */ +#define SMAP_BD_RX_RUNTFRM (1<<6) /* runt frame */ +#define SMAP_BD_RX_SHORTEVNT (1<<5) /* short event */ +#define SMAP_BD_RX_ALIGNERR (1<<4) /* alignment error */ +#define SMAP_BD_RX_BADFCS (1<<3) /* bad FCS */ +#define SMAP_BD_RX_FRMTOOLONG (1<<2) /* frame too long */ +#define SMAP_BD_RX_OUTRANGE (1<<1) /* out of range error */ +#define SMAP_BD_RX_INRANGE (1<<0) /* in range error */ + +#define SMAP_BD_RX_ERROR (SMAP_BD_RX_OVERRUN|SMAP_BD_RX_RUNTFRM|SMAP_BD_RX_SHORTEVNT| \ + SMAP_BD_RX_ALIGNERR|SMAP_BD_RX_BADFCS|SMAP_BD_RX_FRMTOOLONG| \ + SMAP_BD_RX_OUTRANGE|SMAP_BD_RX_INRANGE) + +/* PHY registers (National Semiconductor DP83846A). */ + +#define SMAP_NS_OUI 0x080017 +#define SMAP_DsPHYTER_ADDRESS 0x1 + +#define SMAP_DsPHYTER_BMCR 0x00 +#define SMAP_PHY_BMCR_RST (1<<15) /* ReSeT */ +#define SMAP_PHY_BMCR_LPBK (1<<14) /* LooPBacK */ +#define SMAP_PHY_BMCR_100M (1<<13) /* speed select, 1:100M, 0:10M */ +#define SMAP_PHY_BMCR_10M (0<<13) /* speed select, 1:100M, 0:10M */ +#define SMAP_PHY_BMCR_ANEN (1<<12) /* Auto-Negotiation ENable */ +#define SMAP_PHY_BMCR_PWDN (1<<11) /* PoWer DowN */ +#define SMAP_PHY_BMCR_ISOL (1<<10) /* ISOLate */ +#define SMAP_PHY_BMCR_RSAN (1<<9) /* ReStart Auto-Negotiation */ +#define SMAP_PHY_BMCR_DUPM (1<<8) /* DUPlex Mode, 1:FDX, 0:HDX */ +#define SMAP_PHY_BMCR_COLT (1<<7) /* COLlision Test */ + +#define SMAP_DsPHYTER_BMSR 0x01 +#define SMAP_PHY_BMSR_ANCP (1<<5) /* Auto-Negotiation ComPlete */ +#define SMAP_PHY_BMSR_LINK (1<<2) /* LINK status */ + +#define SMAP_DsPHYTER_PHYIDR1 0x02 +#define SMAP_PHY_IDR1_VAL (((SMAP_NS_OUI<<2)>>8)&0xffff) + +#define SMAP_DsPHYTER_PHYIDR2 0x03 +#define SMAP_PHY_IDR2_VMDL 0x2 /* Vendor MoDeL number */ +#define SMAP_PHY_IDR2_VAL \ + (((SMAP_NS_OUI<<10)&0xFC00)|((SMAP_PHY_IDR2_VMDL<<4)&0x3F0)) +#define SMAP_PHY_IDR2_MSK 0xFFF0 +#define SMAP_PHY_IDR2_REV_MSK 0x000F + +#define SMAP_DsPHYTER_ANAR 0x04 +#define SMAP_DsPHYTER_ANLPAR 0x05 +#define SMAP_DsPHYTER_ANLPARNP 0x05 +#define SMAP_DsPHYTER_ANER 0x06 +#define SMAP_DsPHYTER_ANNPTR 0x07 + +/* Extended registers. */ +#define SMAP_DsPHYTER_PHYSTS 0x10 +#define SMAP_PHY_STS_REL (1<<13) /* Receive Error Latch */ +#define SMAP_PHY_STS_POST (1<<12) /* POlarity STatus */ +#define SMAP_PHY_STS_FCSL (1<<11) /* False Carrier Sense Latch */ +#define SMAP_PHY_STS_SD (1<<10) /* 100BT unconditional Signal Detect */ +#define SMAP_PHY_STS_DSL (1<<9) /* 100BT DeScrambler Lock */ +#define SMAP_PHY_STS_PRCV (1<<8) /* Page ReCeiVed */ +#define SMAP_PHY_STS_RFLT (1<<6) /* Remote FauLT */ +#define SMAP_PHY_STS_JBDT (1<<5) /* JaBber DetecT */ +#define SMAP_PHY_STS_ANCP (1<<4) /* Auto-Negotiation ComPlete */ +#define SMAP_PHY_STS_LPBK (1<<3) /* LooPBacK status */ +#define SMAP_PHY_STS_DUPS (1<<2) /* DUPlex Status,1:FDX,0:HDX */ +#define SMAP_PHY_STS_FDX (1<<2) /* Full Duplex */ +#define SMAP_PHY_STS_HDX (0<<2) /* Half Duplex */ +#define SMAP_PHY_STS_SPDS (1<<1) /* SPeeD Status */ +#define SMAP_PHY_STS_10M (1<<1) /* 10Mbps */ +#define SMAP_PHY_STS_100M (0<<1) /* 100Mbps */ +#define SMAP_PHY_STS_LINK (1<<0) /* LINK status */ +#define SMAP_DsPHYTER_FCSCR 0x14 +#define SMAP_DsPHYTER_RECR 0x15 +#define SMAP_DsPHYTER_PCSR 0x16 +#define SMAP_DsPHYTER_PHYCTRL 0x19 +#define SMAP_DsPHYTER_10BTSCR 0x1A +#define SMAP_DsPHYTER_CDCTRL 0x1B + + +/* + * ATA hardware types and definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2drv iop driver, modified by linuzappz * + */ + + +#define ATA_DEV9_HDD_BASE (SPD_REGBASE + 0x40) +/* AIF on T10Ks - Not supported yet. */ +#define ATA_AIF_HDD_BASE (SPD_REGBASE + 0x4000000 + 0x60) + +/* A port contains all of the ATA controller registers. */ +typedef struct _ata_hwport { + u16 r_data; /* 00 */ + u16 r_error; /* 02 */ +#define r_feature r_error + u16 r_nsector; /* 04 */ + u16 r_sector; /* 06 */ + u16 r_lcyl; /* 08 */ + u16 r_hcyl; /* 0a */ + u16 r_select; /* 0c */ + u16 r_status; /* 0e */ +#define r_command r_status + u16 pad[6]; + u16 r_control; /* 1c */ +} ata_hwport_t; + +ata_hwport_t *ata_hwport; + +#define ATA_R_DATA (ATA_DEV9_HDD_BASE + 0x00) +#define ATA_R_ERROR (ATA_DEV9_HDD_BASE + 0x02) +#define ATA_R_NSECTOR (ATA_DEV9_HDD_BASE + 0x04) +#define ATA_R_SECTOR (ATA_DEV9_HDD_BASE + 0x06) +#define ATA_R_LCYL (ATA_DEV9_HDD_BASE + 0x08) +#define ATA_R_HCYL (ATA_DEV9_HDD_BASE + 0x0a) +#define ATA_R_SELECT (ATA_DEV9_HDD_BASE + 0x0c) +#define ATA_R_STATUS (ATA_DEV9_HDD_BASE + 0x0e) +#define ATA_R_CONTROL (ATA_DEV9_HDD_BASE + 0x1c) + +/* r_error bits. */ +#define ATA_ERR_MARK 0x01 +#define ATA_ERR_TRACK0 0x02 +#define ATA_ERR_ABORT 0x04 +#define ATA_ERR_MCR 0x08 +#define ATA_ERR_ID 0x10 +#define ATA_ERR_MC 0x20 +#define ATA_ERR_ECC 0x40 +#define ATA_ERR_ICRC 0x80 + +/* r_status bits. */ +#define ATA_STAT_ERR 0x01 +#define ATA_STAT_INDEX 0x02 +#define ATA_STAT_ECC 0x04 +#define ATA_STAT_DRQ 0x08 +#define ATA_STAT_SEEK 0x10 +#define ATA_STAT_WRERR 0x20 +#define ATA_STAT_READY 0x40 +#define ATA_STAT_BUSY 0x80 + + + + +/* ATA/ATAPI Commands pre T13 Spec */ +#define WIN_NOP 0x00 +/* + * 0x01->0x02 Reserved + */ +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* + * 0x04->0x07 Reserved + */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_DEVICE_RESET 0x08 +/* + * 0x09->0x0F Reserved + */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +/* + * 0x10->0x1F Reserved + */ +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ +#define WIN_READ_LONG 0x22 /* 28-Bit */ +#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +/* + * 0x28 + */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* + * 0x2A->0x2F Reserved + */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ +#define WIN_WRITE_LONG 0x32 /* 28-Bit */ +#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* + * 0x3A->0x3B Reserved + */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +/* + * 0x3D->0x3F Reserved + */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* + * 0x43->0x4F Reserved + */ +#define WIN_FORMAT 0x50 +/* + * 0x51->0x5F Reserved + */ +#define WIN_INIT 0x60 +/* + * 0x61->0x5F Reserved + */ +#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +#define WIN_STANDBYNOW2 0x94 +#define WIN_STANDBY2 0x96 +#define WIN_SETIDLE2 0x97 +#define WIN_CHECKPOWERMODE2 0x98 +#define WIN_SLEEPNOW2 0x99 +/* + * 0x9A VENDOR + */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +#define CFA_ERASE_SECTORS 0xC0 +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +#define WIN_GETMEDIASTATUS 0xDA +#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ +#define WIN_POSTBOOT 0xDC +#define WIN_PREBOOT 0xDD +#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ + /* SET_FEATURES 0x22 or 0xDD */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED +#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define EXABYTE_ENABLE_NEST 0xF0 +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define WIN_SECURITY_DISABLE 0xF6 +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +#define DISABLE_SEAGATE 0xFB + +/* WIN_SMART sub-commands */ + +#define SMART_READ_VALUES 0xD0 +#define SMART_READ_THRESHOLDS 0xD1 +#define SMART_AUTOSAVE 0xD2 +#define SMART_SAVE 0xD3 +#define SMART_IMMEDIATE_OFFLINE 0xD4 +#define SMART_READ_LOG_SECTOR 0xD5 +#define SMART_WRITE_LOG_SECTOR 0xD6 +#define SMART_WRITE_THRESHOLDS 0xD7 +#define SMART_ENABLE 0xD8 +#define SMART_DISABLE 0xD9 +#define SMART_STATUS 0xDA +#define SMART_AUTO_OFFLINE 0xDB + +/* Password used in TF4 & TF5 executing SMART commands */ + +#define SMART_LCYL_PASS 0x4F +#define SMART_HCYL_PASS 0xC2 + +/* WIN_SETFEATURES sub-commands */ +#define SETFEATURES_EN_8BIT 0x01 /* Enable 8-Bit Transfers */ +#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ +#define SETFEATURES_XFER 0x03 /* Set transfer mode */ +# define XFER_UDMA_7 0x47 /* 0100|0111 */ +# define XFER_UDMA_6 0x46 /* 0100|0110 */ +# define XFER_UDMA_5 0x45 /* 0100|0101 */ +# define XFER_UDMA_4 0x44 /* 0100|0100 */ +# define XFER_UDMA_3 0x43 /* 0100|0011 */ +# define XFER_UDMA_2 0x42 /* 0100|0010 */ +# define XFER_UDMA_1 0x41 /* 0100|0001 */ +# define XFER_UDMA_0 0x40 /* 0100|0000 */ +# define XFER_MW_DMA_2 0x22 /* 0010|0010 */ +# define XFER_MW_DMA_1 0x21 /* 0010|0001 */ +# define XFER_MW_DMA_0 0x20 /* 0010|0000 */ +# define XFER_SW_DMA_2 0x12 /* 0001|0010 */ +# define XFER_SW_DMA_1 0x11 /* 0001|0001 */ +# define XFER_SW_DMA_0 0x10 /* 0001|0000 */ +# define XFER_PIO_4 0x0C /* 0000|1100 */ +# define XFER_PIO_3 0x0B /* 0000|1011 */ +# define XFER_PIO_2 0x0A /* 0000|1010 */ +# define XFER_PIO_1 0x09 /* 0000|1001 */ +# define XFER_PIO_0 0x08 /* 0000|1000 */ +# define XFER_PIO_SLOW 0x00 /* 0000|0000 */ +#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ +#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ +#define SETFEATURES_EN_SAME_R 0x22 /* for a region ATA-1 */ +#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ +#define SETFEATURES_DIS_RETRY 0x33 /* Disable Retry */ +#define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ +#define SETFEATURES_RW_LONG 0x44 /* Set Lenght of VS bytes */ +#define SETFEATURES_SET_CACHE 0x54 /* Set Cache segments to SC Reg. Val */ +#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ +#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ +#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ +#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ +#define SETFEATURES_DIS_ECC 0x77 /* Disable ECC byte count */ +#define SETFEATURES_DIS_8BIT 0x81 /* Disable 8-Bit Transfers */ +#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ +#define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ +#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ +#define SETFEATURES_EN_ECC 0x88 /* Enable ECC byte count */ +#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ +#define SETFEATURES_EN_RETRY 0x99 /* Enable Retry */ +#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ +#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ +#define SETFEATURES_EN_REST 0xAC /* ATA-1 */ +#define SETFEATURES_4B_RW_LONG 0xBB /* Set Lenght of 4 bytes */ +#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */ +#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ +#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt ATAPI */ +#define SETFEATURES_EN_SAME_M 0xDD /* for a entire device ATA-1 */ +#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt ATAPI */ + +/* WIN_SECURITY sub-commands */ + +#define SECURITY_SET_PASSWORD 0xBA +#define SECURITY_UNLOCK 0xBB +#define SECURITY_ERASE_PREPARE 0xBC +#define SECURITY_ERASE_UNIT 0xBD +#define SECURITY_FREEZE_LOCK 0xBE +#define SECURITY_DISABLE_PASSWORD 0xBF + +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; + +/* BIG GEOMETRY */ +struct hd_big_geometry { + unsigned char heads; + unsigned char sectors; + unsigned int cylinders; + unsigned long start; +}; + +/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ +#define HDIO_GETGEO 0x0301 /* get device geometry */ +#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ +#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ +#define HDIO_GET_QDMA 0x0305 /* get use-qdma flag */ + +#define HDIO_SET_XFER 0x0306 /* set transfer rate via proc */ + +#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */ +#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ +#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ +#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ +#define HDIO_GET_DMA 0x030b /* get use-dma flag */ +#define HDIO_GET_NICE 0x030c /* get nice flags */ +#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ +#define HDIO_GET_WCACHE 0x030e /* get write cache mode on|off */ +#define HDIO_GET_ACOUSTIC 0x030f /* get acoustic value */ +#define HDIO_GET_ADDRESS 0x0310 /* */ + +#define HDIO_GET_BUSSTATE 0x031a /* get the bus state of the hwif */ +#define HDIO_TRISTATE_HWIF 0x031b /* execute a channel tristate */ +#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */ +#define HDIO_DRIVE_TASKFILE 0x031d /* execute raw taskfile */ +#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */ +#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ + +#define HDIO_DRIVE_CMD_AEB HDIO_DRIVE_TASK + +/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ +#define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */ +#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */ +#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */ +#define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */ +#define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ +#define HDIO_SET_DMA 0x0326 /* change use-dma flag */ +#define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ +#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */ +#define HDIO_SET_NICE 0x0329 /* set nice flags */ +#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */ +#define HDIO_SET_WCACHE 0x032b /* change write cache enable-disable */ +#define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */ +#define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */ +#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */ +#define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */ + +/* bus states */ +enum { + BUSSTATE_OFF = 0, + BUSSTATE_ON, + BUSSTATE_TRISTATE +}; + +/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */ +#define HDIO_GETGEO_BIG 0x0330 /* */ +#define HDIO_GETGEO_BIG_RAW 0x0331 /* */ + +#define HDIO_SET_IDE_SCSI 0x0338 +#define HDIO_SET_SCSI_IDE 0x0339 + +#define __NEW_HD_DRIVE_ID +/* structure returned by HDIO_GET_IDENTITY, + * as per ANSI NCITS ATA6 rev.1b spec + */ +struct hd_driveid { + unsigned short config; /* lots of obsolete bit flags */ + unsigned short cyls; /* Obsolete, "physical" cyls */ + unsigned short reserved2; /* reserved (word 2) */ + unsigned short heads; /* Obsolete, "physical" heads */ + unsigned short track_bytes; /* unformatted bytes per track */ + unsigned short sector_bytes; /* unformatted bytes per sector */ + unsigned short sectors; /* Obsolete, "physical" sectors per track */ + unsigned short vendor0; /* vendor unique */ + unsigned short vendor1; /* vendor unique */ + unsigned short vendor2; /* Retired vendor unique */ + unsigned char serial_no[20]; /* 0 = not_specified */ + unsigned short buf_type; /* Retired */ + unsigned short buf_size; /* Retired, 512 byte increments + * 0 = not_specified + */ + unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ + unsigned char fw_rev[8]; /* 0 = not_specified */ + unsigned char model[40]; /* 0 = not_specified */ + unsigned char max_multsect; /* 0=not_implemented */ + unsigned char vendor3; /* vendor unique */ + unsigned short dword_io; /* 0=not_implemented; 1=implemented */ + unsigned char vendor4; /* vendor unique */ + unsigned char capability; /* (upper byte of word 49) + * 3: IORDYsup + * 2: IORDYsw + * 1: LBA + * 0: DMA + */ + unsigned short reserved50; /* reserved (word 50) */ + unsigned char vendor5; /* Obsolete, vendor unique */ + unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned char vendor6; /* Obsolete, vendor unique */ + unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned short field_valid; /* (word 53) + * 2: ultra_ok word 88 + * 1: eide_ok words 64-70 + * 0: cur_ok words 54-58 + */ + unsigned short cur_cyls; /* Obsolete, logical cylinders */ + unsigned short cur_heads; /* Obsolete, l heads */ + unsigned short cur_sectors; /* Obsolete, l sectors per track */ + unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */ + unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */ + unsigned char multsect; /* current multiple sector count */ + unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ + unsigned int lba_capacity; /* Obsolete, total number of sectors */ + unsigned short dma_1word; /* Obsolete, single-word dma info */ + unsigned short dma_mword; /* multiple-word dma info */ + unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ + unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ + unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ + unsigned short eide_pio; /* min cycle time (ns), no IORDY */ + unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ + unsigned short words69_70[2]; /* reserved words 69-70 + * future command overlap and queuing + */ + /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ + unsigned short words71_74[4]; /* reserved words 71-74 + * for IDENTIFY PACKET DEVICE command + */ + unsigned short queue_depth; /* (word 75) + * 15:5 reserved + * 4:0 Maximum queue depth -1 + */ + unsigned short words76_79[4]; /* reserved words 76-79 */ + unsigned short major_rev_num; /* (word 80) */ + unsigned short minor_rev_num; /* (word 81) */ + unsigned short command_set_1; /* (word 82) supported + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short command_set_2; /* (word 83) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short cfsse; /* (word 84) + * cmd set-feature supported extensions + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging + * 4: Streaming Feature Set + * 3: Media Card Pass Through + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short cfs_enable_1; /* (word 85) + * command set-feature enabled + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short cfs_enable_2; /* (word 86) + * command set-feature enabled + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short csf_default; /* (word 87) + * command set-feature default + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging enabled + * 4: Valid CONFIGURE STREAM executed + * 3: Media Card Pass Through enabled + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short dma_ultra; /* (word 88) */ + unsigned short trseuc; /* time required for security erase */ + unsigned short trsEuc; /* time required for enhanced erase */ + unsigned short CurAPMvalues; /* current APM values */ + unsigned short mprc; /* master password revision code */ + unsigned short hw_config; /* hardware config (word 93) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: + * 12: + * 11: + * 10: + * 9: + * 8: + * 7: + * 6: + * 5: + * 4: + * 3: + * 2: + * 1: + * 0: Shall be ONE + */ + unsigned short acoustic; /* (word 94) + * 15:8 Vendor's recommended value + * 7:0 current value + */ + unsigned short msrqs; /* min stream request size */ + unsigned short sxfert; /* stream transfer time */ + unsigned short sal; /* stream access latency */ + unsigned int spg; /* stream performance granularity */ + u64 lba_capacity_2; /* 48-bit total number of sectors */ + unsigned short words104_125[22];/* reserved words 104-125 */ + unsigned short last_lun; /* (word 126) */ + unsigned short word127; /* (word 127) Feature Set + * Removable Media Notification + * 15:2 reserved + * 1:0 00 = not supported + * 01 = supported + * 10 = reserved + * 11 = reserved + */ + unsigned short dlf; /* (word 128) + * device lock function + * 15:9 reserved + * 8 security level 1:max 0:high + * 7:6 reserved + * 5 enhanced erase + * 4 expire + * 3 frozen + * 2 locked + * 1 en/disabled + * 0 capability + */ + unsigned short csfo; /* (word 129) + * current set features options + * 15:4 reserved + * 3: auto reassign + * 2: reverting + * 1: read-look-ahead + * 0: write cache + */ + unsigned short words130_155[26];/* reserved vendor words 130-155 */ + unsigned short word156; /* reserved vendor word 156 */ + unsigned short words157_159[3];/* reserved vendor words 157-159 */ + unsigned short cfa_power; /* (word 160) CFA Power Mode + * 15 word 160 supported + * 14 reserved + * 13 + * 12 + * 11:0 + */ + unsigned short words161_175[15];/* Reserved for CFA */ + unsigned short words176_205[30];/* Current Media Serial Number */ + unsigned short words206_254[49];/* reserved words 206-254 */ + unsigned short integrity_word; /* (word 255) + * 15:8 Checksum + * 7:0 Signature + */ +}; + +/* + * NAND Flash via Dev9 driver definitions + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2sdk iop driver * + */ + +#define FLASH_ID_64MBIT 0xe6 +#define FLASH_ID_128MBIT 0x73 +#define FLASH_ID_256MBIT 0x75 +#define FLASH_ID_512MBIT 0x76 +#define FLASH_ID_1024MBIT 0x79 + +/* SmartMedia commands. */ +#define SM_CMD_READ1 0x00 +#define SM_CMD_READ2 0x01 +#define SM_CMD_READ3 0x50 +#define SM_CMD_RESET 0xff +#define SM_CMD_WRITEDATA 0x80 +#define SM_CMD_PROGRAMPAGE 0x10 +#define SM_CMD_ERASEBLOCK 0x60 +#define SM_CMD_ERASECONFIRM 0xd0 +#define SM_CMD_GETSTATUS 0x70 +#define SM_CMD_READID 0x90 + +typedef struct { + u32 id; + u32 mbits; + u32 page_bytes; /* bytes/page */ + u32 block_pages; /* pages/block */ + u32 blocks; +} flash_info_t; + +/* +static flash_info_t devices[] = { + { FLASH_ID_64MBIT, 64, 528, 16, 1024 }, + { FLASH_ID_128MBIT, 128, 528, 32, 1024 }, + { FLASH_ID_256MBIT, 256, 528, 32, 2048 }, + { FLASH_ID_512MBIT, 512, 528, 32, 4096 }, + { FLASH_ID_1024MBIT, 1024, 528, 32, 8192 } +}; +#define NUM_DEVICES (sizeof(devices)/sizeof(flash_info_t)) +*/ + +// definitions added by Florin + +#define FLASH_REGBASE 0x10004800 + +#define FLASH_R_DATA (FLASH_REGBASE + 0x00) +#define FLASH_R_CMD (FLASH_REGBASE + 0x04) +#define FLASH_R_ADDR (FLASH_REGBASE + 0x08) +#define FLASH_R_CTRL (FLASH_REGBASE + 0x0C) +#define FLASH_PP_READY (1<<0) // r/w /BUSY +#define FLASH_PP_WRITE (1<<7) // -/w WRITE data +#define FLASH_PP_CSEL (1<<8) // -/w CS +#define FLASH_PP_READ (1<<11) // -/w READ data +#define FLASH_PP_NOECC (1<<12) // -/w ECC disabled +//#define FLASH_R_10 (FLASH_REGBASE + 0x10) +#define FLASH_R_ID (FLASH_REGBASE + 0x14) + +#define FLASH_REGSIZE 0x20 + +void CALLBACK FLASHinit(); +u32 CALLBACK FLASHread32(u32 addr, int size); +void CALLBACK FLASHwrite32(u32 addr, u32 value, int size); + +#define DVR_REGBASE 0x10004000 + +#define DVR_R_STAT (DVR_REGBASE + 0x200) +#define DVR_R_ACK (DVR_REGBASE + 0x204) +#define DVR_R_MASK (DVR_REGBASE + 0x208) +#define DVR_R_TASK (DVR_REGBASE + 0x230) + +#define DVR_REGSIZE 0x300 + +void CALLBACK DVRinit(); +u32 CALLBACK DVRread32(u32 addr, int size); +void CALLBACK DVRwrite32(u32 addr, u32 value, int size); + +#endif diff --git a/plugins/dev9/DEV9linuz/Linux/Config.c b/plugins/dev9/DEV9linuz/Linux/Config.c new file mode 100644 index 0000000000..5a7accdcf4 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/Config.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +#include "DEV9.h" + +void LoadConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/DEV9linuz.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + strcpy(config.Eth, ETH_DEF); + strcpy(config.Hdd, HDD_DEF); + config.HddSize = 1024; + return; + } + fscanf(f, "Eth = %[^\n]\n", config.Eth); + fscanf(f, "Hdd = %[^\n]\n", config.Hdd); + fscanf(f, "HddSize = %d\n", &config.HddSize); + if (*config.Eth == 0) strcpy(config.Eth, ETH_DEF); + if (*config.Hdd == 0) strcpy(config.Hdd, HDD_DEF); + if (config.HddSize == 0) config.HddSize = 1024; + fclose(f); +} + +void SaveConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/DEV9linuz.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fprintf(f, "Eth = %s\n", config.Eth); + fprintf(f, "Hdd = %s\n", config.Hdd); + fprintf(f, "HddSize = %d\n", config.HddSize); + fclose(f); +} + diff --git a/plugins/dev9/DEV9linuz/Linux/Config.h b/plugins/dev9/DEV9linuz/Linux/Config.h new file mode 100644 index 0000000000..62939290df --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/Config.h @@ -0,0 +1,2 @@ +void SaveConf(); +void LoadConf(); diff --git a/plugins/dev9/DEV9linuz/Linux/Linux.c b/plugins/dev9/DEV9linuz/Linux/Linux.c new file mode 100644 index 0000000000..9b1eeb3e85 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/Linux.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "DEV9.h" +#include "socks.h" + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgDEV9linuz"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgDEV9linuz"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgDEV9linuz", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgDEV9linuz file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void DEV9configure() { + ExecCfg("configure"); +} + +void DEV9about() { + ExecCfg("about"); +} + +void *_DEV9thread(void *arg) { + DEV9thread(); + return NULL; +} + +pthread_t thread; + +s32 _DEV9open() { + pthread_create(&thread, NULL, _DEV9thread, NULL); + + return 0; +} + +void _DEV9close() { + ThreadRun = 0; + pthread_join(thread, NULL); +} + diff --git a/plugins/dev9/DEV9linuz/Linux/Makefile b/plugins/dev9/DEV9linuz/Linux/Makefile new file mode 100644 index 0000000000..bf92b79563 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/Makefile @@ -0,0 +1,37 @@ + +PLUGIN = libDEV9linuz.so +CFG = cfgDEV9linuz +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer +OBJS = ../DEV9.o ../dvr.o ../flash.o +OBJS+= Linux.o Config.o socks.o +CFGOBJS = conf.o interface.o support.o Config.o +DEV9NETOBJS = dev9net.o +DEPS:= $(OBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell gtk-config --cflags) -D__LINUX__ +CFGLIBS = $(shell gtk-config --libs) + +CC = gcc + +all: plugin cfg dev9net + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +dev9net: + ${CC} -O2 -Wall -fno-strict-aliasing -D__KERNEL__ -DMODULE=1 -I/usr/src/linux/include -c -o dev9net.o dev9net.c + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/dev9/DEV9linuz/Linux/callbacks.c b/plugins/dev9/DEV9linuz/Linux/callbacks.c new file mode 100644 index 0000000000..fa070a7842 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/dev9/DEV9linuz/Linux/callbacks.h b/plugins/dev9/DEV9linuz/Linux/callbacks.h new file mode 100644 index 0000000000..22cf74a988 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/dev9/DEV9linuz/Linux/conf.c b/plugins/dev9/DEV9linuz/Linux/conf.c new file mode 100644 index 0000000000..cc27074239 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/conf.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" +#include "DEV9.h" +#include "Config.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "DEV9 Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; +GtkWidget *ComboEth; +GtkWidget *ComboHdd; +GList *ethdevs; +GList *hdddevs; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gchar *str; + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboEth)->entry)); + strcpy(config.Eth, str); + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboHdd)->entry)); + strcpy(config.Hdd, str); + + SaveConf(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void GetEthDevs() { +/* struct ifconf ifc; + int sock; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) return; +*/ + ethdevs = g_list_append(ethdevs, "disabled"); + ethdevs = g_list_append(ethdevs, "lo"); + ethdevs = g_list_append(ethdevs, "eth0"); +} + +void GetHddDevs() { +/* struct ifconf ifc; + int sock; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) return; +*/ + hdddevs = g_list_append(hdddevs, HDD_DEF); +} + +void CFGconfigure() { + Conf = create_Config(); + + LoadConf(); + + ComboEth = lookup_widget(Conf, "GtkCombo_Eth"); + ethdevs = NULL; + GetEthDevs(); + if (ethdevs) { + gtk_combo_set_popdown_strings(GTK_COMBO(ComboEth), ethdevs); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboEth)->entry), config.Eth); + } + + ComboHdd = lookup_widget(Conf, "GtkCombo_Hdd"); + hdddevs = NULL; + GetHddDevs(); + if (hdddevs) { + gtk_combo_set_popdown_strings(GTK_COMBO(ComboHdd), hdddevs); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboHdd)->entry), config.Hdd); + } + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/dev9/DEV9linuz/Linux/dev9linuz.glade b/plugins/dev9/DEV9linuz/Linux/dev9linuz.glade new file mode 100644 index 0000000000..715af05ed6 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/dev9linuz.glade @@ -0,0 +1,300 @@ + + + + + DEV9linuz + dev9linuz + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + DEV9config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox1 + 5 + True + 5 + + + GtkLabel + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Eth + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + + GtkFrame + frame3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox2 + 5 + True + 5 + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Hdd + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + True + True + 0 + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + DEV9about + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/dev9/DEV9linuz/Linux/dev9net.c b/plugins/dev9/DEV9linuz/Linux/dev9net.c new file mode 100644 index 0000000000..401ecaa220 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/dev9net.c @@ -0,0 +1,194 @@ +/* dummy.c: a d9n net driver + + The purpose of this driver is to provide a device to point a + route through, but not to actually transmit packets. + + Why? If you have a machine whose only connection is an occasional + PPP/SLIP/PLIP link, you can only connect to your own hostname + when the link is up. Otherwise you have to use localhost. + This isn't very consistent. + + One solution is to set up a d9n link using PPP/SLIP/PLIP, + but this seems (to me) too much overhead for too little gain. + This driver provides a small alternative. Thus you can do + + [when not running slip] + ifconfig d9n slip.addr.ess.here up + [to go to slip] + ifconfig d9n down + dip whatever + + This was written by looking at Donald Becker's skeleton driver + and the loopback driver. I then threw away anything that didn't + apply! Thanks to Alan Cox for the key clue on what to do with + misguided packets. + + Nick Holloway, 27th May 1994 + [I tweaked this explanation a little but that's all] + Alan Cox, 30th May 1994 +*/ + +/* To have statistics (just packets sent) define this */ + +#include +#include +#include +#include +#include +#include +#include + + +static char *edev; +static struct net_device *ndev; + +MODULE_PARM(edev, "s"); +MODULE_PARM_DESC(edev, + "name of the device from which to send packets"); + +static struct net_device dev_d9n; + + +static int d9n_xmit(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *d9n_get_stats(struct net_device *dev); +static int d9n_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int d9n_rx_hook(struct sk_buff *skb); +static int (*old_rx_hook)(struct sk_buff *skb); + + +/* fake multicast ability */ +static void set_multicast_list(struct net_device *dev) { +} + +#ifdef CONFIG_NET_FASTROUTE +static int d9n_accept_fastpath(struct net_device *dev, struct dst_entry *dst) { + return -1; +} +#endif + +static int __init d9n_init(struct net_device *dev) { + + /* Initialize the device structure. */ + + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_device_stats)); + + dev->get_stats = d9n_get_stats; + dev->hard_start_xmit = d9n_xmit; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = d9n_ioctl; +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = d9n_accept_fastpath; +#endif + + /* Fill in device structure with ethernet-generic values. */ + ether_setup(dev); + dev->tx_queue_len = 0; + dev->flags = 0; + + return 0; +} + +static int d9n_xmit(struct sk_buff *skb, struct net_device *dev) { + struct net_device_stats *stats = dev->priv; + + printk("d9n_xmit %d\n", skb->len); + +// dev_queue_xmit(skb); + stats->tx_packets++; + stats->tx_bytes+=skb->len; + + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *d9n_get_stats(struct net_device *dev) { + return dev->priv; +} + +static int d9n_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { + printk("d9n_ioctl\n"); + + if (!netif_running(dev)) + return -EINVAL; + +/* switch (cmd) { + case + }*/ + return 0; +} + +static int d9n_rx_hook(struct sk_buff *skb) { + struct sk_buff *skb2; + struct iphdr *iph; + unsigned char *ptr; + __u32 saddr; + int proto; + + printk("d9n_rx_hook: %d\n", skb->len); + ptr = skb->mac.ethernet->h_dest; + printk("h_dest: %02X:%02X:%02X:%02X:%02X:%02X.\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); + ptr = skb->mac.ethernet->h_source; + printk("h_source: %02X:%02X:%02X:%02X:%02X:%02X.\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); + + proto = ntohs(skb->mac.ethernet->h_proto); + if (proto != ETH_P_IP) { + return NET_RX_SUCCESS; + } + + printk("ETH_P_IP\n"); + iph = (struct iphdr*)skb->data; + printk("saddr=%08x, daddr=%08x\n", iph->saddr, iph->daddr); + + skb2 = skb_clone(skb, GFP_ATOMIC); + skb2->dev = &dev_d9n; + netif_rx(skb2); + + return NET_RX_SUCCESS; +} + +static int __init d9n_init_module(void) { + int err; + + printk("d9n_init_module\n"); + if (edev == NULL) { + printk(KERN_ERR "dev9net: please specify network device (dev='device'), aborting.\n"); + return -1; + } + ndev = dev_get_by_name(edev); + if (ndev == NULL) { + printk(KERN_ERR "dev9net: network device %s does not exists, aborting.\n", edev); + return -1; + } + + old_rx_hook = ndev->rx_hook; + ndev->rx_hook = d9n_rx_hook; + + dev_d9n.init = d9n_init; + SET_MODULE_OWNER(&dev_d9n); + + /* Find a name for this unit */ + err=dev_alloc_name(&dev_d9n,"d9n"); + if(err<0) + return err; + err = register_netdev(&dev_d9n); + printk("register_netdev: %d\n", err); + if (err<0) + return err; + return 0; +} + +static void __exit d9n_cleanup_module(void) { + unregister_netdev(&dev_d9n); + kfree(dev_d9n.priv); + + memset(&dev_d9n, 0, sizeof(dev_d9n)); + dev_d9n.init = d9n_init; + ndev->rx_hook = old_rx_hook; +} + +module_init(d9n_init_module); +module_exit(d9n_cleanup_module); +MODULE_LICENSE("GPL"); diff --git a/plugins/dev9/DEV9linuz/Linux/interface.c b/plugins/dev9/DEV9linuz/Linux/interface.c new file mode 100644 index 0000000000..a73c0861ed --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/interface.c @@ -0,0 +1,219 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/dev9/DEV9linuz/Linux/interface.h b/plugins/dev9/DEV9linuz/Linux/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/dev9/DEV9linuz/Linux/socks.c b/plugins/dev9/DEV9linuz/Linux/socks.c new file mode 100644 index 0000000000..3dfbbce7eb --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/socks.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socks.h" + +static int sock; +static int index; + +long sockOpen(char *Device) { + struct ifreq ifr; + int opts; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + printf("socket error\n"); return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, Device, sizeof(ifr.ifr_name)); + + if (ioctl(sock, SIOGIFINDEX, &ifr) == -1) { + printf("SIOGIFINDEX error\n"); return -1; + } + + index = ifr.ifr_ifindex; + close(sock); + + sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (sock == -1) return -1; +/* opts = fcntl(sock, F_GETFL); + if (opts < 0) return -1; + opts|= O_NONBLOCK; + fcntl(sock, F_SETFL, opts); +*/ + return 0; +} + +void sockClose() { + close(sock); +} + +long sockSendData(void *pData, int Size) { + struct sockaddr_ll addr; + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = index; + addr.sll_protocol = htons(ETH_P_ALL); + + return sendto(sock, pData, Size, 0, (struct sockaddr*)&addr, sizeof(addr)); +} + +long sockRecvData(void *pData, int Size) { + struct sockaddr_ll addr; + socklen_t len = sizeof(addr); + int ret; + +_start: + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = index; + addr.sll_protocol = htons(ETH_P_ALL); + + ret = recvfrom(sock, pData, Size, 0, (struct sockaddr*)&addr, &len); + return ret; +} + diff --git a/plugins/dev9/DEV9linuz/Linux/socks.h b/plugins/dev9/DEV9linuz/Linux/socks.h new file mode 100644 index 0000000000..dd900629a5 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/socks.h @@ -0,0 +1,22 @@ +#ifndef __SOCKS_H__ +#define __SOCKS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +long sockOpen(char *Device); +void sockClose(); +long sockSendData(void *pData, int Size); +long sockRecvData(void *pData, int Size); + +#endif /* __SOCKS_H__*/ diff --git a/plugins/dev9/DEV9linuz/Linux/support.c b/plugins/dev9/DEV9linuz/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/dev9/DEV9linuz/Linux/support.h b/plugins/dev9/DEV9linuz/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/dev9/DEV9linuz/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/dev9/DEV9linuz/PS2Edefs.h b/plugins/dev9/DEV9linuz/PS2Edefs.h new file mode 100644 index 0000000000..a52d86afe8 --- /dev/null +++ b/plugins/dev9/DEV9linuz/PS2Edefs.h @@ -0,0 +1,684 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.5 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0005 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0003 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { // NOT bcd coded + u8 minute; + u8 second; + u8 frame; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usualy 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdLoc:track type +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetType CDVDgetType; +_CDVDgetTrayStatus CDVDgetTrayStatus; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/dev9/DEV9linuz/PS2Etypes.h b/plugins/dev9/DEV9linuz/PS2Etypes.h new file mode 100644 index 0000000000..443ad4599a --- /dev/null +++ b/plugins/dev9/DEV9linuz/PS2Etypes.h @@ -0,0 +1,31 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__WIN32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#elif defined(__LINUX__) + +typedef char s8; +typedef short s16; +typedef long s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/dev9/DEV9linuz/Win32/Config.c b/plugins/dev9/DEV9linuz/Win32/Config.c new file mode 100644 index 0000000000..5068caf624 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Config.c @@ -0,0 +1,52 @@ +#include + +#include "DEV9.h" + +#define GetKeyV(name, var, s, t) \ + size = s; type = t; \ + RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); + +#define GetKeyVdw(name, var) \ + GetKeyV(name, var, 4, REG_DWORD); + +#define SetKeyV(name, var, s, t) \ + RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); + +#define SetKeyVdw(name, var) \ + SetKeyV(name, var, 4, REG_DWORD); + +void SaveConf() { + HKEY myKey; + DWORD myDisp; + + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\DEV9\\DEV9linuz", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); + SetKeyV("Eth", config.Eth, strlen(config.Eth), REG_SZ); + SetKeyV("Hdd", config.Hdd, strlen(config.Hdd), REG_SZ); + SetKeyVdw("HddSize", &config.HddSize); + SetKeyVdw("ethEnable", &config.ethEnable); + SetKeyVdw("hddEnable", &config.hddEnable); + + RegCloseKey(myKey); +} + +void LoadConf() { + HKEY myKey; + DWORD type, size; + + memset(&config, 0, sizeof(config)); + strcpy(config.Hdd, HDD_DEF); + config.HddSize=8*1024; + strcpy(config.Eth, ETH_DEF); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\DEV9\\DEV9linuz", 0, KEY_ALL_ACCESS, &myKey)!=ERROR_SUCCESS) { + SaveConf(); return; + } + GetKeyV("Eth", config.Eth, sizeof(config.Eth), REG_SZ); + GetKeyV("Hdd", config.Hdd, sizeof(config.Hdd), REG_SZ); + GetKeyVdw("HddSize", &config.HddSize); + GetKeyVdw("ethEnable", &config.ethEnable); + GetKeyVdw("hddEnable", &config.hddEnable); + + RegCloseKey(myKey); +} + diff --git a/plugins/dev9/DEV9linuz/Win32/Config.h b/plugins/dev9/DEV9linuz/Win32/Config.h new file mode 100644 index 0000000000..62939290df --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Config.h @@ -0,0 +1,2 @@ +void SaveConf(); +void LoadConf(); diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.def b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.def new file mode 100644 index 0000000000..40fd1574c8 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.def @@ -0,0 +1,29 @@ +; DEV9linuz.def : Declares the module parameters for the DLL. + +LIBRARY "DEV9linuz" +DESCRIPTION 'DEV9linuz Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + DEV9init @5 + DEV9shutdown @6 + DEV9open @7 + DEV9close @8 + DEV9read8 @9 + DEV9read16 @10 + DEV9read32 @11 + DEV9write8 @12 + DEV9write16 @13 + DEV9write32 @14 + DEV9readDMA8Mem @15 + DEV9writeDMA8Mem @16 + + DEV9configure @17 + DEV9test @18 + DEV9about @19 + DEV9irqCallback @20 + DEV9irqHandler @21 + diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsp b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsp new file mode 100644 index 0000000000..c6d1e05ece --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="DEV9linuz" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=DEV9linuz - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DEV9linuz.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DEV9linuz.mak" CFG="DEV9linuz - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DEV9linuz - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=snCl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEV9linuz_EXPORTS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "./" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEV9linuz_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=2 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x408 /d "NDEBUG" +# ADD RSC /l 0x408 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib packet.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" +# SUBTRACT LINK32 /nodefaultlib +# Begin Target + +# Name "DEV9linuz - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Config.c +# End Source File +# Begin Source File + +SOURCE=..\DEV9.c +# End Source File +# Begin Source File + +SOURCE=.\DEV9linuz.def +# End Source File +# Begin Source File + +SOURCE=..\dvr.c +# End Source File +# Begin Source File + +SOURCE=..\flash.c +# End Source File +# Begin Source File + +SOURCE=.\socks.c +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\DEV9.h +# End Source File +# Begin Source File + +SOURCE=..\PS2Edefs.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Dev9linuz.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsw b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsw new file mode 100644 index 0000000000..74c94b377f --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "DEV9linuz"=".\DEV9linuz.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.rc b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.rc new file mode 100644 index 0000000000..10ca317c41 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.rc @@ -0,0 +1,135 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifdef __MINGW32__ +#include "afxresmw.h" +#else +#include "afxres.h" +#endif + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Castilian) (unknown sub-lang: 0xB) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, 0xB +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 227, 170 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "HDD Configure" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,115,150,50,14 + PUSHBUTTON "Cancel",IDCANCEL,170,150,50,14 + COMBOBOX IDC_BAYTYPE,90,10,130,47,CBS_DROPDOWNLIST | CBS_SORT | + WS_DISABLED + LTEXT "DEV9 Type",IDC_STATIC,15,10,60,11,SS_CENTERIMAGE + LTEXT "Ethernet Device",IDC_STATIC,15,60,60,10,SS_CENTERIMAGE + COMBOBOX IDC_ETHDEV,85,60,130,45,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + GROUPBOX "Ethernet",IDC_STATIC,5,30,215,50 + CONTROL "Enabled",IDC_ETHENABLED,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,45,42,10 + LTEXT "HDD File",IDC_STATIC,15,115,60,10,SS_CENTERIMAGE + GROUPBOX "Hard Disk Drive",IDC_STATIC,5,85,215,50 + CONTROL "Enabled",IDC_HDDENABLED,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,100,42,10 + EDITTEXT IDC_HDDFILE,85,115,130,12,ES_AUTOHSCROLL +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 86 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "DEV9 About" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,65,50,14 + LTEXT "DEV9 Driver",IDC_NAME,59,7,42,8 + LTEXT "Author: linuzappz ",IDC_STATIC, + 17,31,141,10 + LTEXT "Shadow ",IDC_STATIC,43,47,112,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO MOVEABLE PURE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 220 + TOPMARGIN, 7 + BOTTOMMARGIN, 163 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Castilian) (unknown sub-lang: 0xB) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.sln b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.sln new file mode 100644 index 0000000000..d5994246e4 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DEV9linuz", "DEV9linuz.vcproj", "{BBE4E5FB-530A-4D18-A633-35AF0577B7F3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release.ActiveCfg = Release|Win32 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/dev9/DEV9linuz/Win32/DEV9linuz.vcproj b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.vcproj new file mode 100644 index 0000000000..d1ecb50c11 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/DEV9linuz.vcproj @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/DEV9linuz/Win32/Devioctl.h b/plugins/dev9/DEV9linuz/Win32/Devioctl.h new file mode 100644 index 0000000000..af8784bfd3 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Devioctl.h @@ -0,0 +1,90 @@ +/*++ BUILD Version: 0004 // Increment this if a change has global effects + Copyright (c) 1992-1993 Microsoft Corporation + Module Name: + devioctl.h + Revision History: + -- */ +// begin_winioctl +#ifndef _DEVIOCTL_ +#define _DEVIOCTL_ +// begin_ntddk begin_nthal begin_ntifs +// +// Define the various device type values. Note that values used by Microsoft +// Corporation are in the range 0-32767, and 32768-65535 are reserved for use +// by customers. +// +#define DEVICE_TYPE ULONG +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) +// +// Define the method codes for how buffers are passed for I/O and FS controls +// +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe +#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe +// end_ntddk end_nthal end_ntifs +#endif // _DEVIOCTL_ +// end_winioctl diff --git a/plugins/dev9/DEV9linuz/Win32/Makefile b/plugins/dev9/DEV9linuz/Win32/Makefile new file mode 100644 index 0000000000..accfa99154 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Makefile @@ -0,0 +1,52 @@ +# +# Makefile for MINGW32 +# + + +all: dev9linuz + +PLUGIN = DEV9linuz.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lPacket +RESOBJ = dev9linuz.o + +OBJS = ../DEV9.o +OBJS+= socks.o Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +dev9linuz: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} +# ${STRIP} ${PLUGIN} + +.PHONY: clean dev9linuz + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: DEV9linuz.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/dev9/DEV9linuz/Win32/Ntddndis.h b/plugins/dev9/DEV9linuz/Win32/Ntddndis.h new file mode 100644 index 0000000000..0b6298069c --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Ntddndis.h @@ -0,0 +1,1400 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + Copyright (c) 1990-1993 Microsoft Corporation + Module Name: + ntddndis.h + Abstract: + This is the include file that defines all constants and types for + accessing the Network driver interface device. + Author: + Steve Wood (stevewo) 27-May-1990 + Revision History: + Adam Barr (adamba) 04-Nov-1992 added the correct values for NDIS 3.0. + Jameel Hyder (jameelh) 01-Aug-95 added Pnp IoCTLs and structures + Kyle Brandon (kyleb) 09/24/96 added general co ndis oids. + -- */ +#ifndef _NTDDNDIS_ +#define _NTDDNDIS_ +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// +#define DD_NDIS_DEVICE_NAME "\\Device\\UNKNOWN" +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// +#define _NDIS_CONTROL_CODE(request,method) \ + CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS) +#define IOCTL_NDIS_QUERY_GLOBAL_STATS _NDIS_CONTROL_CODE( 0, METHOD_OUT_DIRECT ) +#define IOCTL_NDIS_QUERY_ALL_STATS _NDIS_CONTROL_CODE( 1, METHOD_OUT_DIRECT ) +#define IOCTL_NDIS_ADD_DEVICE _NDIS_CONTROL_CODE( 2, METHOD_BUFFERED ) +#define IOCTL_NDIS_DELETE_DEVICE _NDIS_CONTROL_CODE( 3, METHOD_BUFFERED ) +#define IOCTL_NDIS_TRANSLATE_NAME _NDIS_CONTROL_CODE( 4, METHOD_BUFFERED ) +#define IOCTL_NDIS_ADD_TDI_DEVICE _NDIS_CONTROL_CODE( 5, METHOD_BUFFERED ) +#define IOCTL_NDIS_NOTIFY_PROTOCOL _NDIS_CONTROL_CODE( 6, METHOD_BUFFERED ) +#define IOCTL_NDIS_GET_LOG_DATA _NDIS_CONTROL_CODE( 7, METHOD_OUT_DIRECT ) +// +// NtDeviceIoControlFile InputBuffer/OutputBuffer record structures for +// this device. +// +// +// This is the type of an NDIS OID value. +// +typedef ULONG NDIS_OID, *PNDIS_OID; +// +// IOCTL_NDIS_QUERY_ALL_STATS returns a sequence of these, packed +// together (no padding is required since statistics all have +// four or eight bytes of data). +// +typedef struct _NDIS_STATISTICS_VALUE { + NDIS_OID Oid; + ULONG DataLength; + UCHAR Data[1]; // variable length + +} NDIS_STATISTICS_VALUE, *PNDIS_STATISTICS_VALUE; + +// +// Structure used by TRANSLATE_NAME IOCTL +// +typedef struct _NET_PNP_ID { + ULONG ClassId; + ULONG Token; +} NET_PNP_ID, *PNET_PNP_ID; + +typedef struct _NET_PNP_TRANSLATE_LIST { + ULONG BytesNeeded; + NET_PNP_ID IdArray[ANYSIZE_ARRAY]; +} NET_PNP_TRANSLATE_LIST, *PNET_PNP_TRANSLATE_LIST; + +// +// Structure used to define a self-contained variable data structure +// +typedef struct _NDIS_VAR_DATA_DESC { + USHORT Length; // # of octects of data + + USHORT MaximumLength; // # of octects available + + LONG Offset; // Offset of data relative to the descriptor + +} NDIS_VAR_DATA_DESC, *PNDIS_VAR_DATA_DESC; + +// +// Object Identifiers used by NdisRequest Query/Set Information +// +// +// General Objects +// +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +// +// These are connection-oriented general OIDs. +// These replace the above OIDs for connection-oriented media. +// +#define OID_GEN_CO_SUPPORTED_LIST 0x00010101 +#define OID_GEN_CO_HARDWARE_STATUS 0x00010102 +#define OID_GEN_CO_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_CO_MEDIA_IN_USE 0x00010104 +#define OID_GEN_CO_LINK_SPEED 0x00010105 +#define OID_GEN_CO_VENDOR_ID 0x00010106 +#define OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107 +#define OID_GEN_CO_DRIVER_VERSION 0x00010108 +#define OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109 +#define OID_GEN_CO_MAC_OPTIONS 0x0001010A +#define OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B +#define OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C +#define OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D +#define OID_GEN_CO_GET_TIME_CAPS 0x00010201 +#define OID_GEN_CO_GET_NETCARD_TIME 0x00010202 +// +// These are connection-oriented statistics OIDs. +// +#define OID_GEN_CO_XMIT_PDUS_OK 0x00020101 +#define OID_GEN_CO_RCV_PDUS_OK 0x00020102 +#define OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103 +#define OID_GEN_CO_RCV_PDUS_ERROR 0x00020104 +#define OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105 +#define OID_GEN_CO_RCV_CRC_ERROR 0x00020201 +#define OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202 +#define OID_GEN_CO_BYTES_XMIT 0x00020203 +#define OID_GEN_CO_BYTES_RCV 0x00020204 +#define OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205 +#define OID_GEN_CO_NETCARD_LOAD 0x00020206 +// +// These are objects for Connection-oriented media call-managers and are not +// valid for ndis drivers. Under construction. +// +#define OID_CO_ADD_PVC 0xFF000001 +#define OID_CO_DELETE_PVC 0xFF000002 +#define OID_CO_GET_CALL_INFORMATION 0xFF000003 +#define OID_CO_ADD_ADDRESS 0xFF000004 +#define OID_CO_DELETE_ADDRESS 0xFF000005 +#define OID_CO_GET_ADDRESSES 0xFF000006 +#define OID_CO_ADDRESS_CHANGE 0xFF000007 +#define OID_CO_SIGNALING_ENABLED 0xFF000008 +#define OID_CO_SIGNALING_DISABLED 0xFF000009 +// +// 802.3 Objects (Ethernet) +// +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +// +// +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 +// +// 802.5 Objects (Token-Ring) +// +#define OID_802_5_PERMANENT_ADDRESS 0x02010101 +#define OID_802_5_CURRENT_ADDRESS 0x02010102 +#define OID_802_5_CURRENT_FUNCTIONAL 0x02010103 +#define OID_802_5_CURRENT_GROUP 0x02010104 +#define OID_802_5_LAST_OPEN_STATUS 0x02010105 +#define OID_802_5_CURRENT_RING_STATUS 0x02010106 +#define OID_802_5_CURRENT_RING_STATE 0x02010107 +#define OID_802_5_LINE_ERRORS 0x02020101 +#define OID_802_5_LOST_FRAMES 0x02020102 +#define OID_802_5_BURST_ERRORS 0x02020201 +#define OID_802_5_AC_ERRORS 0x02020202 +#define OID_802_5_ABORT_DELIMETERS 0x02020203 +#define OID_802_5_FRAME_COPIED_ERRORS 0x02020204 +#define OID_802_5_FREQUENCY_ERRORS 0x02020205 +#define OID_802_5_TOKEN_ERRORS 0x02020206 +#define OID_802_5_INTERNAL_ERRORS 0x02020207 +// +// FDDI Objects +// +#define OID_FDDI_LONG_PERMANENT_ADDR 0x03010101 +#define OID_FDDI_LONG_CURRENT_ADDR 0x03010102 +#define OID_FDDI_LONG_MULTICAST_LIST 0x03010103 +#define OID_FDDI_LONG_MAX_LIST_SIZE 0x03010104 +#define OID_FDDI_SHORT_PERMANENT_ADDR 0x03010105 +#define OID_FDDI_SHORT_CURRENT_ADDR 0x03010106 +#define OID_FDDI_SHORT_MULTICAST_LIST 0x03010107 +#define OID_FDDI_SHORT_MAX_LIST_SIZE 0x03010108 +#define OID_FDDI_ATTACHMENT_TYPE 0x03020101 +#define OID_FDDI_UPSTREAM_NODE_LONG 0x03020102 +#define OID_FDDI_DOWNSTREAM_NODE_LONG 0x03020103 +#define OID_FDDI_FRAME_ERRORS 0x03020104 +#define OID_FDDI_FRAMES_LOST 0x03020105 +#define OID_FDDI_RING_MGT_STATE 0x03020106 +#define OID_FDDI_LCT_FAILURES 0x03020107 +#define OID_FDDI_LEM_REJECTS 0x03020108 +#define OID_FDDI_LCONNECTION_STATE 0x03020109 +#define OID_FDDI_SMT_STATION_ID 0x03030201 +#define OID_FDDI_SMT_OP_VERSION_ID 0x03030202 +#define OID_FDDI_SMT_HI_VERSION_ID 0x03030203 +#define OID_FDDI_SMT_LO_VERSION_ID 0x03030204 +#define OID_FDDI_SMT_MANUFACTURER_DATA 0x03030205 +#define OID_FDDI_SMT_USER_DATA 0x03030206 +#define OID_FDDI_SMT_MIB_VERSION_ID 0x03030207 +#define OID_FDDI_SMT_MAC_CT 0x03030208 +#define OID_FDDI_SMT_NON_MASTER_CT 0x03030209 +#define OID_FDDI_SMT_MASTER_CT 0x0303020A +#define OID_FDDI_SMT_AVAILABLE_PATHS 0x0303020B +#define OID_FDDI_SMT_CONFIG_CAPABILITIES 0x0303020C +#define OID_FDDI_SMT_CONFIG_POLICY 0x0303020D +#define OID_FDDI_SMT_CONNECTION_POLICY 0x0303020E +#define OID_FDDI_SMT_T_NOTIFY 0x0303020F +#define OID_FDDI_SMT_STAT_RPT_POLICY 0x03030210 +#define OID_FDDI_SMT_TRACE_MAX_EXPIRATION 0x03030211 +#define OID_FDDI_SMT_PORT_INDEXES 0x03030212 +#define OID_FDDI_SMT_MAC_INDEXES 0x03030213 +#define OID_FDDI_SMT_BYPASS_PRESENT 0x03030214 +#define OID_FDDI_SMT_ECM_STATE 0x03030215 +#define OID_FDDI_SMT_CF_STATE 0x03030216 +#define OID_FDDI_SMT_HOLD_STATE 0x03030217 +#define OID_FDDI_SMT_REMOTE_DISCONNECT_FLAG 0x03030218 +#define OID_FDDI_SMT_STATION_STATUS 0x03030219 +#define OID_FDDI_SMT_PEER_WRAP_FLAG 0x0303021A +#define OID_FDDI_SMT_MSG_TIME_STAMP 0x0303021B +#define OID_FDDI_SMT_TRANSITION_TIME_STAMP 0x0303021C +#define OID_FDDI_SMT_SET_COUNT 0x0303021D +#define OID_FDDI_SMT_LAST_SET_STATION_ID 0x0303021E +#define OID_FDDI_MAC_FRAME_STATUS_FUNCTIONS 0x0303021F +#define OID_FDDI_MAC_BRIDGE_FUNCTIONS 0x03030220 +#define OID_FDDI_MAC_T_MAX_CAPABILITY 0x03030221 +#define OID_FDDI_MAC_TVX_CAPABILITY 0x03030222 +#define OID_FDDI_MAC_AVAILABLE_PATHS 0x03030223 +#define OID_FDDI_MAC_CURRENT_PATH 0x03030224 +#define OID_FDDI_MAC_UPSTREAM_NBR 0x03030225 +#define OID_FDDI_MAC_DOWNSTREAM_NBR 0x03030226 +#define OID_FDDI_MAC_OLD_UPSTREAM_NBR 0x03030227 +#define OID_FDDI_MAC_OLD_DOWNSTREAM_NBR 0x03030228 +#define OID_FDDI_MAC_DUP_ADDRESS_TEST 0x03030229 +#define OID_FDDI_MAC_REQUESTED_PATHS 0x0303022A +#define OID_FDDI_MAC_DOWNSTREAM_PORT_TYPE 0x0303022B +#define OID_FDDI_MAC_INDEX 0x0303022C +#define OID_FDDI_MAC_SMT_ADDRESS 0x0303022D +#define OID_FDDI_MAC_LONG_GRP_ADDRESS 0x0303022E +#define OID_FDDI_MAC_SHORT_GRP_ADDRESS 0x0303022F +#define OID_FDDI_MAC_T_REQ 0x03030230 +#define OID_FDDI_MAC_T_NEG 0x03030231 +#define OID_FDDI_MAC_T_MAX 0x03030232 +#define OID_FDDI_MAC_TVX_VALUE 0x03030233 +#define OID_FDDI_MAC_T_PRI0 0x03030234 +#define OID_FDDI_MAC_T_PRI1 0x03030235 +#define OID_FDDI_MAC_T_PRI2 0x03030236 +#define OID_FDDI_MAC_T_PRI3 0x03030237 +#define OID_FDDI_MAC_T_PRI4 0x03030238 +#define OID_FDDI_MAC_T_PRI5 0x03030239 +#define OID_FDDI_MAC_T_PRI6 0x0303023A +#define OID_FDDI_MAC_FRAME_CT 0x0303023B +#define OID_FDDI_MAC_COPIED_CT 0x0303023C +#define OID_FDDI_MAC_TRANSMIT_CT 0x0303023D +#define OID_FDDI_MAC_TOKEN_CT 0x0303023E +#define OID_FDDI_MAC_ERROR_CT 0x0303023F +#define OID_FDDI_MAC_LOST_CT 0x03030240 +#define OID_FDDI_MAC_TVX_EXPIRED_CT 0x03030241 +#define OID_FDDI_MAC_NOT_COPIED_CT 0x03030242 +#define OID_FDDI_MAC_LATE_CT 0x03030243 +#define OID_FDDI_MAC_RING_OP_CT 0x03030244 +#define OID_FDDI_MAC_FRAME_ERROR_THRESHOLD 0x03030245 +#define OID_FDDI_MAC_FRAME_ERROR_RATIO 0x03030246 +#define OID_FDDI_MAC_NOT_COPIED_THRESHOLD 0x03030247 +#define OID_FDDI_MAC_NOT_COPIED_RATIO 0x03030248 +#define OID_FDDI_MAC_RMT_STATE 0x03030249 +#define OID_FDDI_MAC_DA_FLAG 0x0303024A +#define OID_FDDI_MAC_UNDA_FLAG 0x0303024B +#define OID_FDDI_MAC_FRAME_ERROR_FLAG 0x0303024C +#define OID_FDDI_MAC_NOT_COPIED_FLAG 0x0303024D +#define OID_FDDI_MAC_MA_UNITDATA_AVAILABLE 0x0303024E +#define OID_FDDI_MAC_HARDWARE_PRESENT 0x0303024F +#define OID_FDDI_MAC_MA_UNITDATA_ENABLE 0x03030250 +#define OID_FDDI_PATH_INDEX 0x03030251 +#define OID_FDDI_PATH_RING_LATENCY 0x03030252 +#define OID_FDDI_PATH_TRACE_STATUS 0x03030253 +#define OID_FDDI_PATH_SBA_PAYLOAD 0x03030254 +#define OID_FDDI_PATH_SBA_OVERHEAD 0x03030255 +#define OID_FDDI_PATH_CONFIGURATION 0x03030256 +#define OID_FDDI_PATH_T_R_MODE 0x03030257 +#define OID_FDDI_PATH_SBA_AVAILABLE 0x03030258 +#define OID_FDDI_PATH_TVX_LOWER_BOUND 0x03030259 +#define OID_FDDI_PATH_T_MAX_LOWER_BOUND 0x0303025A +#define OID_FDDI_PATH_MAX_T_REQ 0x0303025B +#define OID_FDDI_PORT_MY_TYPE 0x0303025C +#define OID_FDDI_PORT_NEIGHBOR_TYPE 0x0303025D +#define OID_FDDI_PORT_CONNECTION_POLICIES 0x0303025E +#define OID_FDDI_PORT_MAC_INDICATED 0x0303025F +#define OID_FDDI_PORT_CURRENT_PATH 0x03030260 +#define OID_FDDI_PORT_REQUESTED_PATHS 0x03030261 +#define OID_FDDI_PORT_MAC_PLACEMENT 0x03030262 +#define OID_FDDI_PORT_AVAILABLE_PATHS 0x03030263 +#define OID_FDDI_PORT_MAC_LOOP_TIME 0x03030264 +#define OID_FDDI_PORT_PMD_CLASS 0x03030265 +#define OID_FDDI_PORT_CONNECTION_CAPABILITIES 0x03030266 +#define OID_FDDI_PORT_INDEX 0x03030267 +#define OID_FDDI_PORT_MAINT_LS 0x03030268 +#define OID_FDDI_PORT_BS_FLAG 0x03030269 +#define OID_FDDI_PORT_PC_LS 0x0303026A +#define OID_FDDI_PORT_EB_ERROR_CT 0x0303026B +#define OID_FDDI_PORT_LCT_FAIL_CT 0x0303026C +#define OID_FDDI_PORT_LER_ESTIMATE 0x0303026D +#define OID_FDDI_PORT_LEM_REJECT_CT 0x0303026E +#define OID_FDDI_PORT_LEM_CT 0x0303026F +#define OID_FDDI_PORT_LER_CUTOFF 0x03030270 +#define OID_FDDI_PORT_LER_ALARM 0x03030271 +#define OID_FDDI_PORT_CONNNECT_STATE 0x03030272 +#define OID_FDDI_PORT_PCM_STATE 0x03030273 +#define OID_FDDI_PORT_PC_WITHHOLD 0x03030274 +#define OID_FDDI_PORT_LER_FLAG 0x03030275 +#define OID_FDDI_PORT_HARDWARE_PRESENT 0x03030276 +#define OID_FDDI_SMT_STATION_ACTION 0x03030277 +#define OID_FDDI_PORT_ACTION 0x03030278 +#define OID_FDDI_IF_DESCR 0x03030279 +#define OID_FDDI_IF_TYPE 0x0303027A +#define OID_FDDI_IF_MTU 0x0303027B +#define OID_FDDI_IF_SPEED 0x0303027C +#define OID_FDDI_IF_PHYS_ADDRESS 0x0303027D +#define OID_FDDI_IF_ADMIN_STATUS 0x0303027E +#define OID_FDDI_IF_OPER_STATUS 0x0303027F +#define OID_FDDI_IF_LAST_CHANGE 0x03030280 +#define OID_FDDI_IF_IN_OCTETS 0x03030281 +#define OID_FDDI_IF_IN_UCAST_PKTS 0x03030282 +#define OID_FDDI_IF_IN_NUCAST_PKTS 0x03030283 +#define OID_FDDI_IF_IN_DISCARDS 0x03030284 +#define OID_FDDI_IF_IN_ERRORS 0x03030285 +#define OID_FDDI_IF_IN_UNKNOWN_PROTOS 0x03030286 +#define OID_FDDI_IF_OUT_OCTETS 0x03030287 +#define OID_FDDI_IF_OUT_UCAST_PKTS 0x03030288 +#define OID_FDDI_IF_OUT_NUCAST_PKTS 0x03030289 +#define OID_FDDI_IF_OUT_DISCARDS 0x0303028A +#define OID_FDDI_IF_OUT_ERRORS 0x0303028B +#define OID_FDDI_IF_OUT_QLEN 0x0303028C +#define OID_FDDI_IF_SPECIFIC 0x0303028D +// +// WAN objects +// +#define OID_WAN_PERMANENT_ADDRESS 0x04010101 +#define OID_WAN_CURRENT_ADDRESS 0x04010102 +#define OID_WAN_QUALITY_OF_SERVICE 0x04010103 +#define OID_WAN_PROTOCOL_TYPE 0x04010104 +#define OID_WAN_MEDIUM_SUBTYPE 0x04010105 +#define OID_WAN_HEADER_FORMAT 0x04010106 +#define OID_WAN_GET_INFO 0x04010107 +#define OID_WAN_SET_LINK_INFO 0x04010108 +#define OID_WAN_GET_LINK_INFO 0x04010109 +#define OID_WAN_LINE_COUNT 0x0401010A +#define OID_WAN_GET_BRIDGE_INFO 0x0401020A +#define OID_WAN_SET_BRIDGE_INFO 0x0401020B +#define OID_WAN_GET_COMP_INFO 0x0401020C +#define OID_WAN_SET_COMP_INFO 0x0401020D +#define OID_WAN_GET_STATS_INFO 0x0401020E +// +// LocalTalk objects +// +#define OID_LTALK_CURRENT_NODE_ID 0x05010102 +#define OID_LTALK_IN_BROADCASTS 0x05020101 +#define OID_LTALK_IN_LENGTH_ERRORS 0x05020102 +#define OID_LTALK_OUT_NO_HANDLERS 0x05020201 +#define OID_LTALK_COLLISIONS 0x05020202 +#define OID_LTALK_DEFERS 0x05020203 +#define OID_LTALK_NO_DATA_ERRORS 0x05020204 +#define OID_LTALK_RANDOM_CTS_ERRORS 0x05020205 +#define OID_LTALK_FCS_ERRORS 0x05020206 +// +// Arcnet objects +// +#define OID_ARCNET_PERMANENT_ADDRESS 0x06010101 +#define OID_ARCNET_CURRENT_ADDRESS 0x06010102 +#define OID_ARCNET_RECONFIGURATIONS 0x06020201 +// +// TAPI objects +// +#define OID_TAPI_ACCEPT 0x07030101 +#define OID_TAPI_ANSWER 0x07030102 +#define OID_TAPI_CLOSE 0x07030103 +#define OID_TAPI_CLOSE_CALL 0x07030104 +#define OID_TAPI_CONDITIONAL_MEDIA_DETECTION 0x07030105 +#define OID_TAPI_CONFIG_DIALOG 0x07030106 +#define OID_TAPI_DEV_SPECIFIC 0x07030107 +#define OID_TAPI_DIAL 0x07030108 +#define OID_TAPI_DROP 0x07030109 +#define OID_TAPI_GET_ADDRESS_CAPS 0x0703010A +#define OID_TAPI_GET_ADDRESS_ID 0x0703010B +#define OID_TAPI_GET_ADDRESS_STATUS 0x0703010C +#define OID_TAPI_GET_CALL_ADDRESS_ID 0x0703010D +#define OID_TAPI_GET_CALL_INFO 0x0703010E +#define OID_TAPI_GET_CALL_STATUS 0x0703010F +#define OID_TAPI_GET_DEV_CAPS 0x07030110 +#define OID_TAPI_GET_DEV_CONFIG 0x07030111 +#define OID_TAPI_GET_EXTENSION_ID 0x07030112 +#define OID_TAPI_GET_ID 0x07030113 +#define OID_TAPI_GET_LINE_DEV_STATUS 0x07030114 +#define OID_TAPI_MAKE_CALL 0x07030115 +#define OID_TAPI_NEGOTIATE_EXT_VERSION 0x07030116 +#define OID_TAPI_OPEN 0x07030117 +#define OID_TAPI_PROVIDER_INITIALIZE 0x07030118 +#define OID_TAPI_PROVIDER_SHUTDOWN 0x07030119 +#define OID_TAPI_SECURE_CALL 0x0703011A +#define OID_TAPI_SELECT_EXT_VERSION 0x0703011B +#define OID_TAPI_SEND_USER_USER_INFO 0x0703011C +#define OID_TAPI_SET_APP_SPECIFIC 0x0703011D +#define OID_TAPI_SET_CALL_PARAMS 0x0703011E +#define OID_TAPI_SET_DEFAULT_MEDIA_DETECTION 0x0703011F +#define OID_TAPI_SET_DEV_CONFIG 0x07030120 +#define OID_TAPI_SET_MEDIA_MODE 0x07030121 +#define OID_TAPI_SET_STATUS_MESSAGES 0x07030122 +// +// ATM Connection Oriented Ndis +// +#define OID_ATM_SUPPORTED_VC_RATES 0x08010101 +#define OID_ATM_SUPPORTED_SERVICE_CATEGORY 0x08010102 +#define OID_ATM_SUPPORTED_AAL_TYPES 0x08010103 +#define OID_ATM_HW_CURRENT_ADDRESS 0x08010104 +#define OID_ATM_MAX_ACTIVE_VCS 0x08010105 +#define OID_ATM_MAX_ACTIVE_VCI_BITS 0x08010106 +#define OID_ATM_MAX_ACTIVE_VPI_BITS 0x08010107 +#define OID_ATM_MAX_AAL0_PACKET_SIZE 0x08010108 +#define OID_ATM_MAX_AAL1_PACKET_SIZE 0x08010109 +#define OID_ATM_MAX_AAL34_PACKET_SIZE 0x0801010A +#define OID_ATM_MAX_AAL5_PACKET_SIZE 0x0801010B +#define OID_ATM_SIGNALING_VPIVCI 0x08010201 +#define OID_ATM_ASSIGNED_VPI 0x08010202 +#define OID_ATM_ACQUIRE_ACCESS_NET_RESOURCES 0x08010203 +#define OID_ATM_RELEASE_ACCESS_NET_RESOURCES 0x08010204 +#define OID_ATM_ILMI_VPIVCI 0x08010205 +#define OID_ATM_DIGITAL_BROADCAST_VPIVCI 0x08010206 +#define OID_ATM_GET_NEAREST_FLOW 0x08010207 +#define OID_ATM_ALIGNMENT_REQUIRED 0x08010208 +// +// ATM specific statistics OIDs. +// +#define OID_ATM_RCV_CELLS_OK 0x08020101 +#define OID_ATM_XMIT_CELLS_OK 0x08020102 +#define OID_ATM_RCV_CELLS_DROPPED 0x08020103 +#define OID_ATM_RCV_INVALID_VPI_VCI 0x08020201 +#define OID_ATM_CELLS_HEC_ERROR 0x08020202 +#define OID_ATM_RCV_REASSEMBLY_ERROR 0x08020203 +// +// PCCA (Wireless) object +// +// +// All WirelessWAN devices must support the following OIDs +// +#define OID_WW_GEN_NETWORK_TYPES_SUPPORTED 0x09010101 +#define OID_WW_GEN_NETWORK_TYPE_IN_USE 0x09010102 +#define OID_WW_GEN_HEADER_FORMATS_SUPPORTED 0x09010103 +#define OID_WW_GEN_HEADER_FORMAT_IN_USE 0x09010104 +#define OID_WW_GEN_INDICATION_REQUEST 0x09010105 +#define OID_WW_GEN_DEVICE_INFO 0x09010106 +#define OID_WW_GEN_OPERATION_MODE 0x09010107 +#define OID_WW_GEN_LOCK_STATUS 0x09010108 +#define OID_WW_GEN_DISABLE_TRANSMITTER 0x09010109 +#define OID_WW_GEN_NETWORK_ID 0x0901010A +#define OID_WW_GEN_PERMANENT_ADDRESS 0x0901010B +#define OID_WW_GEN_CURRENT_ADDRESS 0x0901010C +#define OID_WW_GEN_SUSPEND_DRIVER 0x0901010D +#define OID_WW_GEN_BASESTATION_ID 0x0901010E +#define OID_WW_GEN_CHANNEL_ID 0x0901010F +#define OID_WW_GEN_ENCRYPTION_SUPPORTED 0x09010110 +#define OID_WW_GEN_ENCRYPTION_IN_USE 0x09010111 +#define OID_WW_GEN_ENCRYPTION_STATE 0x09010112 +#define OID_WW_GEN_CHANNEL_QUALITY 0x09010113 +#define OID_WW_GEN_REGISTRATION_STATUS 0x09010114 +#define OID_WW_GEN_RADIO_LINK_SPEED 0x09010115 +#define OID_WW_GEN_LATENCY 0x09010116 +#define OID_WW_GEN_BATTERY_LEVEL 0x09010117 +#define OID_WW_GEN_EXTERNAL_POWER 0x09010118 +// +// Network Dependent OIDs - Mobitex: +// +#define OID_WW_MBX_SUBADDR 0x09050101 +// OID 0x09050102 is reserved and may not be used +#define OID_WW_MBX_FLEXLIST 0x09050103 +#define OID_WW_MBX_GROUPLIST 0x09050104 +#define OID_WW_MBX_TRAFFIC_AREA 0x09050105 +#define OID_WW_MBX_LIVE_DIE 0x09050106 +#define OID_WW_MBX_TEMP_DEFAULTLIST 0x09050107 +// +// Network Dependent OIDs - Pinpoint: +// +#define OID_WW_PIN_LOC_AUTHORIZE 0x09090101 +#define OID_WW_PIN_LAST_LOCATION 0x09090102 +#define OID_WW_PIN_LOC_FIX 0x09090103 +// +// Network Dependent - CDPD: +// +#define OID_WW_CDPD_SPNI 0x090D0101 +#define OID_WW_CDPD_WASI 0x090D0102 +#define OID_WW_CDPD_AREA_COLOR 0x090D0103 +#define OID_WW_CDPD_TX_POWER_LEVEL 0x090D0104 +#define OID_WW_CDPD_EID 0x090D0105 +#define OID_WW_CDPD_HEADER_COMPRESSION 0x090D0106 +#define OID_WW_CDPD_DATA_COMPRESSION 0x090D0107 +#define OID_WW_CDPD_CHANNEL_SELECT 0x090D0108 +#define OID_WW_CDPD_CHANNEL_STATE 0x090D0109 +#define OID_WW_CDPD_NEI 0x090D010A +#define OID_WW_CDPD_NEI_STATE 0x090D010B +#define OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER 0x090D010C +#define OID_WW_CDPD_SLEEP_MODE 0x090D010D +#define OID_WW_CDPD_CIRCUIT_SWITCHED 0x090D010E +#define OID_WW_CDPD_TEI 0x090D010F +#define OID_WW_CDPD_RSSI 0x090D0110 +// +// Network Dependent - Ardis: +// +#define OID_WW_ARD_SNDCP 0x09110101 +#define OID_WW_ARD_TMLY_MSG 0x09110102 +#define OID_WW_ARD_DATAGRAM 0x09110103 +// +// Network Dependent - DataTac: +// +#define OID_WW_TAC_COMPRESSION 0x09150101 +#define OID_WW_TAC_SET_CONFIG 0x09150102 +#define OID_WW_TAC_GET_STATUS 0x09150103 +#define OID_WW_TAC_USER_HEADER 0x09150104 +// +// Network Dependent - Metricom: +// +#define OID_WW_MET_FUNCTION 0x09190101 +// +// IRDA objects +// +#define OID_IRDA_RECEIVING 0x0A010100 +#define OID_IRDA_TURNAROUND_TIME 0x0A010101 +#define OID_IRDA_SUPPORTED_SPEEDS 0x0A010102 +#define OID_IRDA_LINK_SPEED 0x0A010103 +#define OID_IRDA_MEDIA_BUSY 0x0A010104 +#define OID_IRDA_EXTRA_RCV_BOFS 0x0A010200 +#define OID_IRDA_RATE_SNIFF 0x0A010201 +#define OID_IRDA_UNICAST_LIST 0x0A010202 +#define OID_IRDA_MAX_UNICAST_LIST_SIZE 0x0A010203 +#define OID_IRDA_MAX_RECEIVE_WINDOW_SIZE 0x0A010204 +#define OID_IRDA_MAX_SEND_WINDOW_SIZE 0x0A010205 +// +// Medium the Ndis Driver is running on (OID_GEN_MEDIA_SUPPORTED/ +// OID_GEN_MEDIA_IN_USE). +// +typedef enum _NDIS_MEDIUM { + NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumWan, + NdisMediumLocalTalk, + NdisMediumDix, // defined for convenience, not a real medium + NdisMediumArcnetRaw, + NdisMediumArcnet878_2, + NdisMediumAtm, + NdisMediumWirelessWan, + NdisMediumIrda, + NdisMediumMax // Not a real medium, defined as an upper-bound +} NDIS_MEDIUM, *PNDIS_MEDIUM; + +// +// Hardware status codes (OID_GEN_HARDWARE_STATUS). +// +typedef enum _NDIS_HARDWARE_STATUS { + NdisHardwareStatusReady, + NdisHardwareStatusInitializing, + NdisHardwareStatusReset, + NdisHardwareStatusClosing, + NdisHardwareStatusNotReady +} NDIS_HARDWARE_STATUS, *PNDIS_HARDWARE_STATUS; + +// +// this is the type passed in the OID_GEN_GET_TIME_CAPS request +// +typedef struct _GEN_GET_TIME_CAPS { + ULONG Flags; // Bits defined below + + ULONG ClockPrecision; +} GEN_GET_TIME_CAPS, *PGEN_GET_TIME_CAPS; + +#define READABLE_LOCAL_CLOCK 0x000000001 +#define CLOCK_NETWORK_DERIVED 0x000000002 +#define CLOCK_PRECISION 0x000000004 +#define RECEIVE_TIME_INDICATION_CAPABLE 0x000000008 +#define TIMED_SEND_CAPABLE 0x000000010 +#define TIME_STAMP_CAPABLE 0x000000020 +// +// +// this is the type passed in the OID_GEN_GET_NETCARD_TIME request +// +typedef struct _GEN_GET_NETCARD_TIME { + ULONG ReadTime; +} GEN_GET_NETCARD_TIME, *PGEN_GET_NETCARD_TIME; + +// +// Defines the attachment types for FDDI (OID_FDDI_ATTACHMENT_TYPE). +// +typedef enum _NDIS_FDDI_ATTACHMENT_TYPE { + NdisFddiTypeIsolated = 1, + NdisFddiTypeLocalA, + NdisFddiTypeLocalB, + NdisFddiTypeLocalAB, + NdisFddiTypeLocalS, + NdisFddiTypeWrapA, + NdisFddiTypeWrapB, + NdisFddiTypeWrapAB, + NdisFddiTypeWrapS, + NdisFddiTypeCWrapA, + NdisFddiTypeCWrapB, + NdisFddiTypeCWrapS, + NdisFddiTypeThrough +} NDIS_FDDI_ATTACHMENT_TYPE, *PNDIS_FDDI_ATTACHMENT_TYPE; + +// +// Defines the ring management states for FDDI (OID_FDDI_RING_MGT_STATE). +// +typedef enum _NDIS_FDDI_RING_MGT_STATE { + NdisFddiRingIsolated = 1, + NdisFddiRingNonOperational, + NdisFddiRingOperational, + NdisFddiRingDetect, + NdisFddiRingNonOperationalDup, + NdisFddiRingOperationalDup, + NdisFddiRingDirected, + NdisFddiRingTrace +} NDIS_FDDI_RING_MGT_STATE, *PNDIS_FDDI_RING_MGT_STATE; + +// +// Defines the Lconnection state for FDDI (OID_FDDI_LCONNECTION_STATE). +// +typedef enum _NDIS_FDDI_LCONNECTION_STATE { + NdisFddiStateOff = 1, + NdisFddiStateBreak, + NdisFddiStateTrace, + NdisFddiStateConnect, + NdisFddiStateNext, + NdisFddiStateSignal, + NdisFddiStateJoin, + NdisFddiStateVerify, + NdisFddiStateActive, + NdisFddiStateMaintenance +} NDIS_FDDI_LCONNECTION_STATE, *PNDIS_FDDI_LCONNECTION_STATE; + +// +// Defines the medium subtypes for WAN medium (OID_WAN_MEDIUM_SUBTYPE). +// +typedef enum _NDIS_WAN_MEDIUM_SUBTYPE { + NdisWanMediumHub, + NdisWanMediumX_25, + NdisWanMediumIsdn, + NdisWanMediumSerial, + NdisWanMediumFrameRelay, + NdisWanMediumAtm, + NdisWanMediumSonet, + NdisWanMediumSW56K +} NDIS_WAN_MEDIUM_SUBTYPE, *PNDIS_WAN_MEDIUM_SUBTYPE; + +// +// Defines the header format for WAN medium (OID_WAN_HEADER_FORMAT). +// +typedef enum _NDIS_WAN_HEADER_FORMAT { + NdisWanHeaderNative, // src/dest based on subtype, followed by NLPID + NdisWanHeaderEthernet // emulation of ethernet header +} NDIS_WAN_HEADER_FORMAT, *PNDIS_WAN_HEADER_FORMAT; + +// +// Defines the line quality on a WAN line (OID_WAN_QUALITY_OF_SERVICE). +// +typedef enum _NDIS_WAN_QUALITY { + NdisWanRaw, + NdisWanErrorControl, + NdisWanReliable +} NDIS_WAN_QUALITY, *PNDIS_WAN_QUALITY; + +// +// Defines the state of a token-ring adapter (OID_802_5_CURRENT_RING_STATE). +// +typedef enum _NDIS_802_5_RING_STATE { + NdisRingStateOpened = 1, + NdisRingStateClosed, + NdisRingStateOpening, + NdisRingStateClosing, + NdisRingStateOpenFailure, + NdisRingStateRingFailure +} NDIS_802_5_RING_STATE, *PNDIS_802_5_RING_STATE; + +// +// Defines the state of the LAN media +// +typedef enum _NDIS_MEDIA_STATE { + NdisMediaStateConnected, + NdisMediaStateDisconnected +} NDIS_MEDIA_STATE, *PNDIS_MEDIA_STATE; + +// +// The following is set on a per-packet basis as OOB data with NdisClass802_3Priority +// +typedef ULONG Priority_802_3; // 0-7 priority levels +// +// The following structure is used to query OID_GEN_CO_LINK_SPEED and +// OID_GEN_CO_MINIMUM_LINK_SPEED. The first OID will return the current +// link speed of the adapter. The second will return the minimum link speed +// the adapter is capable of. +// + +typedef struct _NDIS_CO_LINK_SPEED { + ULONG Outbound; + ULONG Inbound; +} NDIS_CO_LINK_SPEED, + +*PNDIS_CO_LINK_SPEED; +// +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER). +// +#define NDIS_PACKET_TYPE_DIRECTED 0x0001 +#define NDIS_PACKET_TYPE_MULTICAST 0x0002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004 +#define NDIS_PACKET_TYPE_BROADCAST 0x0008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020 +#define NDIS_PACKET_TYPE_SMT 0x0040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000 +#define NDIS_PACKET_TYPE_GROUP 0x1000 +// +// Ndis Token-Ring Ring Status Codes (OID_802_5_CURRENT_RING_STATUS). +// +#define NDIS_RING_SIGNAL_LOSS 0x00008000 +#define NDIS_RING_HARD_ERROR 0x00004000 +#define NDIS_RING_SOFT_ERROR 0x00002000 +#define NDIS_RING_TRANSMIT_BEACON 0x00001000 +#define NDIS_RING_LOBE_WIRE_FAULT 0x00000800 +#define NDIS_RING_AUTO_REMOVAL_ERROR 0x00000400 +#define NDIS_RING_REMOVE_RECEIVED 0x00000200 +#define NDIS_RING_COUNTER_OVERFLOW 0x00000100 +#define NDIS_RING_SINGLE_STATION 0x00000080 +#define NDIS_RING_RING_RECOVERY 0x00000040 +// +// Ndis protocol option bits (OID_GEN_PROTOCOL_OPTIONS). +// +#define NDIS_PROT_OPTION_ESTIMATED_LENGTH 0x00000001 +#define NDIS_PROT_OPTION_NO_LOOPBACK 0x00000002 +#define NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT 0x00000004 +// +// Ndis MAC option bits (OID_GEN_MAC_OPTIONS). +// +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 +// +// NDIS MAC option bits for OID_GEN_CO_MAC_OPTIONS. +// +#define NDIS_CO_MAC_OPTION_DYNAMIC_LINK_SPEED 0x00000001 +#ifdef IRDA +// +// The following is set on a per-packet basis as OOB data with NdisClassIrdaPacketInfo +// This is the per-packet info specified on a per-packet basis +// +typedef struct _NDIS_IRDA_PACKET_INFO { + UINT ExtraBOFs; + UINT MinTurnAroundTime; +} NDIS_IRDA_PACKET_INFO, *PNDIS_IRDA_PACKET_INFO; + +#endif +#ifdef WIRELESS_WAN +// +// Wireless WAN structure definitions +// +// +// currently defined Wireless network subtypes +// +typedef enum _NDIS_WW_NETWORK_TYPE { + NdisWWGeneric, + NdisWWMobitex, + NdisWWPinpoint, + NdisWWCDPD, + NdisWWArdis, + NdisWWDataTAC, + NdisWWMetricom, + NdisWWGSM, + NdisWWCDMA, + NdisWWTDMA, + NdisWWAMPS, + NdisWWInmarsat, + NdisWWpACT +} NDIS_WW_NETWORK_TYPE; + +// +// currently defined header formats +// +typedef enum _NDIS_WW_HEADER_FORMAT { + NdisWWDIXEthernetFrames, + NdisWWMPAKFrames, + NdisWWRDLAPFrames, + NdisWWMDC4800Frames +} NDIS_WW_HEADER_FORMAT; + +// +// currently defined encryption types +// +typedef enum _NDIS_WW_ENCRYPTION_TYPE { + NdisWWUnknownEncryption = -1, + NdisWWNoEncryption, + NdisWWDefaultEncryption +} NDIS_WW_ENCRYPTION_TYPE, *PNDIS_WW_ENCRYPTION_TYPE; + +// +// OID_WW_GEN_INDICATION_REQUEST +// +typedef struct _NDIS_WW_INDICATION_REQUEST { + NDIS_OID Oid; // IN + + UINT uIndicationFlag; // IN + + UINT uApplicationToken; // IN OUT + + HANDLE hIndicationHandle; // IN OUT + + INT iPollingInterval; // IN OUT + + NDIS_VAR_DATA_DESC InitialValue; // IN OUT + + NDIS_VAR_DATA_DESC OIDIndicationValue; // OUT - only valid after indication + + NDIS_VAR_DATA_DESC TriggerValue; // IN + +} NDIS_WW_INDICATION_REQUEST, *PNDIS_WW_INDICATION_REQUEST; + +#define OID_INDICATION_REQUEST_ENABLE 0x0000 +#define OID_INDICATION_REQUEST_CANCEL 0x0001 +// +// OID_WW_GEN_DEVICE_INFO +// +typedef struct _WW_DEVICE_INFO { + NDIS_VAR_DATA_DESC Manufacturer; + NDIS_VAR_DATA_DESC ModelNum; + NDIS_VAR_DATA_DESC SWVersionNum; + NDIS_VAR_DATA_DESC SerialNum; +} WW_DEVICE_INFO, *PWW_DEVICE_INFO; + +// +// OID_WW_GEN_OPERATION_MODE +// +typedef INT WW_OPERATION_MODE; // 0 = Normal mode + // 1 = Power saving mode + // -1 = mode unknown +// +// OID_WW_GEN_LOCK_STATUS +// + +typedef INT WW_LOCK_STATUS; // 0 = unlocked + // 1 = locked + // -1 = unknown lock status +// +// OID_WW_GEN_DISABLE_TRANSMITTER +// + +typedef INT WW_DISABLE_TRANSMITTER; // 0 = transmitter enabled + // 1 = transmitter disabled + // -1 = unknown value +// +// OID_WW_GEN_NETWORK_ID +// + +typedef NDIS_VAR_DATA_DESC WW_NETWORK_ID; +// +// OID_WW_GEN_PERMANENT_ADDRESS +// +typedef NDIS_VAR_DATA_DESC WW_PERMANENT_ADDRESS; +// +// OID_WW_GEN_CURRENT_ADDRESS +// +typedef struct _WW_CURRENT_ADDRESS { + NDIS_WW_HEADER_FORMAT Format; + NDIS_VAR_DATA_DESC Address; +} WW_CURRENT_ADDRESS, *PWW_CURRENT_ADDRESS; + +// +// OID_WW_GEN_SUSPEND_DRIVER +// +typedef BOOLEAN WW_SUSPEND_DRIVER; // 0 = driver operational + // 1 = driver suspended +// +// OID_WW_GEN_BASESTATION_ID +// + +typedef NDIS_VAR_DATA_DESC WW_BASESTATION_ID; +// +// OID_WW_GEN_CHANNEL_ID +// +typedef NDIS_VAR_DATA_DESC WW_CHANNEL_ID; +// +// OID_WW_GEN_ENCRYPTION_STATE +// +typedef BOOLEAN WW_ENCRYPTION_STATE; // 0 = if encryption is disabled + // 1 = if encryption is enabled +// +// OID_WW_GEN_CHANNEL_QUALITY +// + +typedef INT WW_CHANNEL_QUALITY; // 0 = Not in network contact, + // 1-100 = Quality of Channel (100 is highest quality). + // -1 = channel quality is unknown +// +// OID_WW_GEN_REGISTRATION_STATUS +// + +typedef INT WW_REGISTRATION_STATUS; // 0 = Registration denied + // 1 = Registration pending + // 2 = Registered + // -1 = unknown registration status +// +// OID_WW_GEN_RADIO_LINK_SPEED +// + +typedef UINT WW_RADIO_LINK_SPEED; // Bits per second. +// +// OID_WW_GEN_LATENCY +// + +typedef UINT WW_LATENCY; // milliseconds +// +// OID_WW_GEN_BATTERY_LEVEL +// + +typedef INT WW_BATTERY_LEVEL; // 0-100 = battery level in percentage + // (100=fully charged) + // -1 = unknown battery level. +// +// OID_WW_GEN_EXTERNAL_POWER +// + +typedef INT WW_EXTERNAL_POWER; // 0 = no external power connected + // 1 = external power connected + // -1 = unknown +// +// OID_WW_MET_FUNCTION +// + +typedef NDIS_VAR_DATA_DESC WW_MET_FUNCTION; +// +// OID_WW_TAC_COMPRESSION +// +typedef BOOLEAN WW_TAC_COMPRESSION; // Determines whether or not network level compression + // is being used. +// +// OID_WW_TAC_SET_CONFIG +// + +typedef struct _WW_TAC_SETCONFIG { + NDIS_VAR_DATA_DESC RCV_MODE; + NDIS_VAR_DATA_DESC TX_CONTROL; + NDIS_VAR_DATA_DESC RX_CONTROL; + NDIS_VAR_DATA_DESC FLOW_CONTROL; + NDIS_VAR_DATA_DESC RESET_CNF; + NDIS_VAR_DATA_DESC READ_CNF; +} WW_TAC_SETCONFIG, *PWW_TAC_SETCONFIG; + +// +// OID_WW_TAC_GET_STATUS +// +typedef struct _WW_TAC_GETSTATUS { + BOOLEAN Action; // Set = Execute command. + + NDIS_VAR_DATA_DESC Command; + NDIS_VAR_DATA_DESC Option; + NDIS_VAR_DATA_DESC Response; // The response to the requested command + // - max. length of string is 256 octets. + +} WW_TAC_GETSTATUS, *PWW_TAC_GETSTATUS; + +// +// OID_WW_TAC_USER_HEADER +// +typedef NDIS_VAR_DATA_DESC WW_TAC_USERHEADER; // This will hold the user header - Max. 64 octets. +// +// OID_WW_ARD_SNDCP +// + +typedef struct _WW_ARD_SNDCP { + NDIS_VAR_DATA_DESC Version; // The version of SNDCP protocol supported. + + INT BlockSize; // The block size used for SNDCP + + INT Window; // The window size used in SNDCP + +} WW_ARD_SNDCP, *PWW_ARD_SNDCP; + +// +// OID_WW_ARD_TMLY_MSG +// +typedef BOOLEAN WW_ARD_CHANNEL_STATUS; // The current status of the inbound RF Channel. +// +// OID_WW_ARD_DATAGRAM +// + +typedef struct _WW_ARD_DATAGRAM { + BOOLEAN LoadLevel; // Byte that contains the load level info. + + INT SessionTime; // Datagram session time remaining. + + NDIS_VAR_DATA_DESC HostAddr; // Host address. + + NDIS_VAR_DATA_DESC THostAddr; // Test host address. + +} WW_ARD_DATAGRAM, *PWW_ARD_DATAGRAM; + +// +// OID_WW_CDPD_SPNI +// +typedef struct _WW_CDPD_SPNI { + UINT SPNI[10]; //10 16-bit service provider network IDs + + INT OperatingMode; // 0 = ignore SPNI, + // 1 = require SPNI from list, + // 2 = prefer SPNI from list. + // 3 = exclude SPNI from list. + +} WW_CDPD_SPNI, *PWW_CDPD_SPNI; + +// +// OID_WW_CDPD_WASI +// +typedef struct _WW_CDPD_WIDE_AREA_SERVICE_ID { + UINT WASI[10]; //10 16-bit wide area service IDs + + INT OperatingMode; // 0 = ignore WASI, + // 1 = Require WASI from list, + // 2 = prefer WASI from list + // 3 = exclude WASI from list. + +} WW_CDPD_WIDE_AREA_SERVICE_ID, *PWW_CDPD_WIDE_AREA_SERVICE_ID; + +// +// OID_WW_CDPD_AREA_COLOR +// +typedef INT WW_CDPD_AREA_COLOR; +// +// OID_WW_CDPD_TX_POWER_LEVEL +// +typedef UINT WW_CDPD_TX_POWER_LEVEL; +// +// OID_WW_CDPD_EID +// +typedef NDIS_VAR_DATA_DESC WW_CDPD_EID; +// +// OID_WW_CDPD_HEADER_COMPRESSION +// +typedef INT WW_CDPD_HEADER_COMPRESSION; // 0 = no header compression, + // 1 = always compress headers, + // 2 = compress headers if MD-IS does + // -1 = unknown +// +// OID_WW_CDPD_DATA_COMPRESSION +// + +typedef INT WW_CDPD_DATA_COMPRESSION; // 0 = no data compression, + // 1 = data compression enabled + // -1 = unknown +// +// OID_WW_CDPD_CHANNEL_SELECT +// + +typedef struct _WW_CDPD_CHANNEL_SELECT { + UINT ChannelID; // channel number + + UINT fixedDuration; // duration in seconds + +} WW_CDPD_CHANNEL_SELECT, *PWW_CDPD_CHANNEL_SELECT; + +// +// OID_WW_CDPD_CHANNEL_STATE +// +typedef enum _WW_CDPD_CHANNEL_STATE { + CDPDChannelNotAvail, + CDPDChannelScanning, + CDPDChannelInitAcquired, + CDPDChannelAcquired, + CDPDChannelSleeping, + CDPDChannelWaking, + CDPDChannelCSDialing, + CDPDChannelCSRedial, + CDPDChannelCSAnswering, + CDPDChannelCSConnected, + CDPDChannelCSSuspended +} WW_CDPD_CHANNEL_STATE, *PWW_CDPD_CHANNEL_STATE; + +// +// OID_WW_CDPD_NEI +// +typedef enum _WW_CDPD_NEI_FORMAT { + CDPDNeiIPv4, + CDPDNeiCLNP, + CDPDNeiIPv6 +} WW_CDPD_NEI_FORMAT, *PWW_CDPD_NEI_FORMAT; +typedef enum _WW_CDPD_NEI_TYPE { + CDPDNeiIndividual, + CDPDNeiMulticast, + CDPDNeiBroadcast +} WW_CDPD_NEI_TYPE; +typedef struct _WW_CDPD_NEI { + UINT uNeiIndex; + WW_CDPD_NEI_FORMAT NeiFormat; + WW_CDPD_NEI_TYPE NeiType; + WORD NeiGmid; // group member identifier, only + // meaningful if NeiType == + // CDPDNeiMulticast + + NDIS_VAR_DATA_DESC NeiAddress; +} WW_CDPD_NEI; + +// +// OID_WW_CDPD_NEI_STATE +// +typedef enum _WW_CDPD_NEI_STATE { + CDPDUnknown, + CDPDRegistered, + CDPDDeregistered +} WW_CDPD_NEI_STATE, *PWW_CDPD_NEI_STATE; +typedef enum _WW_CDPD_NEI_SUB_STATE { + CDPDPending, // Registration pending + CDPDNoReason, // Registration denied - no reason given + CDPDMDISNotCapable, // Registration denied - MD-IS not capable of + // handling M-ES at this time + CDPDNEINotAuthorized, // Registration denied - NEI is not authorized to + // use this subnetwork + CDPDInsufficientAuth, // Registration denied - M-ES gave insufficient + // authentication credentials + CDPDUnsupportedAuth, // Registration denied - M-ES gave unsupported + // authentication credentials + CDPDUsageExceeded, // Registration denied - NEI has exceeded usage + // limitations + CDPDDeniedThisNetwork // Registration denied on this network, service + // may be obtained on alternate Service Provider + // network +} WW_CDPD_NEI_SUB_STATE; +typedef struct _WW_CDPD_NEI_REG_STATE { + UINT uNeiIndex; + WW_CDPD_NEI_STATE NeiState; + WW_CDPD_NEI_SUB_STATE NeiSubState; +} WW_CDPD_NEI_REG_STATE, *PWW_CDPD_NEI_REG_STATE; + +// +// OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER +// +typedef struct _WW_CDPD_SERVICE_PROVIDER_ID { + UINT SPI[10]; //10 16-bit service provider IDs + + INT OperatingMode; // 0 = ignore SPI, + // 1 = require SPI from list, + // 2 = prefer SPI from list. + // 3 = exclude SPI from list. + +} WW_CDPD_SERVICE_PROVIDER_ID, *PWW_CDPD_SERVICE_PROVIDER_ID; + +// +// OID_WW_CDPD_SLEEP_MODE +// +typedef INT WW_CDPD_SLEEP_MODE; +// +// OID_WW_CDPD_TEI +// +typedef ULONG WW_CDPD_TEI; +// +// OID_WW_CDPD_CIRCUIT_SWITCHED +// +typedef struct _WW_CDPD_CIRCUIT_SWITCHED { + INT service_preference; // -1 = unknown, + // 0 = always use packet switched CDPD, + // 1 = always use CS CDPD via AMPS, + // 2 = always use CS CDPD via PSTN, + // 3 = use circuit switched via AMPS only + // when packet switched is not available. + // 4 = use packet switched only when circuit + // switched via AMPS is not available. + // 5 = device manuf. defined service + // preference. + // 6 = device manuf. defined service + // preference. + + INT service_status; // -1 = unknown, + // 0 = packet switched CDPD, + // 1 = circuit switched CDPD via AMPS, + // 2 = circuit switched CDPD via PSTN. + + INT connect_rate; // CS connection bit rate (bits per second). + // 0 = no active connection, + // -1 = unknown + // Dial code last used to dial. + + NDIS_VAR_DATA_DESC dial_code[20]; + + UINT sid; // Current AMPS system ID + + INT a_b_side_selection; // -1 = unknown, + // 0 = no AMPS service + // 1 = AMPS "A" side channels selected + // 2 = AMPS "B" side channels selected + + INT AMPS_channel; // -1= unknown + // 0 = no AMPS service. + // 1-1023 = AMPS channel number in use + + UINT action; // 0 = no action + // 1 = suspend (hangup) + // 2 = dial + + // Default dial code for CS CDPD service + // encoded as specified in the CS CDPD + // implementor guidelines. + NDIS_VAR_DATA_DESC default_dial[20]; + + // Number for the CS CDPD network to call + // back the mobile, encoded as specified in + // the CS CDPD implementor guidelines. + NDIS_VAR_DATA_DESC call_back[20]; + + UINT sid_list[10]; // List of 10 16-bit preferred AMPS + // system IDs for CS CDPD. + + UINT inactivity_timer; // Wait time after last data before dropping + // call. + // 0-65535 = inactivity time limit (seconds). + + UINT receive_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT conn_resp_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT reconn_resp_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT disconn_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT NEI_reg_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT reconn_retry_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT link_reset_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT link_reset_ack_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT n401_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n402_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n404_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n405_retry_limit; // per CS-CDPD Implementor Guidelines. + +} WW_CDPD_CIRCUIT_SWITCHED, *WW_PCDPD_CIRCUIT_SWITCHED; +typedef UINT WW_CDPD_RSSI; +// +// OID_WW_PIN_LOC_AUTHORIZE +// +typedef INT WW_PIN_AUTHORIZED; // 0 = unauthorized + // 1 = authorized + // -1 = unknown +// +// OID_WW_PIN_LAST_LOCATION +// OID_WW_PIN_LOC_FIX +// + +typedef struct _WW_PIN_LOCATION { + INT Latitude; // Latitude in hundredths of a second + + INT Longitude; // Longitude in hundredths of a second + + INT Altitude; // Altitude in feet + + INT FixTime; // Time of the location fix, since midnight, local time (of the + // current day), in tenths of a second + + INT NetTime; // Current local network time of the current day, since midnight, + // in tenths of a second + + INT LocQuality; // 0-100 = location quality + + INT LatReg; // Latitude registration offset, in hundredths of a second + + INT LongReg; // Longitude registration offset, in hundredths of a second + + INT GMTOffset; // Offset in minutes of the local time zone from GMT + +} WW_PIN_LOCATION, *PWW_PIN_LOCATION; + +// +// The following is set on a per-packet basis as OOB data with NdisClassWirelessWanMbxMailbox +// +typedef ULONG WW_MBX_MAILBOX_FLAG; // 1 = set mailbox flag, 0 = do not set mailbox flag +// +// OID_WW_MBX_SUBADDR +// + +typedef struct _WW_MBX_PMAN { + BOOLEAN ACTION; // 0 = Login PMAN, 1 = Logout PMAN + + UINT MAN; + UCHAR PASSWORD[8]; // Password should be null for Logout and indications. + // Maximum length of password is 8 chars. + +} WW_MBX_PMAN, *PWW_MBX_PMAN; + +// +// OID_WW_MBX_FLEXLIST +// +typedef struct _WW_MBX_FLEXLIST { + INT count; // Number of MAN entries used. + // -1=unknown. + + UINT MAN[7]; // List of MANs. + +} WW_MBX_FLEXLIST; + +// +// OID_WW_MBX_GROUPLIST +// +typedef struct _WW_MBX_GROUPLIST { + INT count; // Number of MAN entries used. + // -1=unknown. + + UINT MAN[15]; // List of MANs. + +} WW_MBX_GROUPLIST; + +// +// OID_WW_MBX_TRAFFIC_AREA +// +typedef enum _WW_MBX_TRAFFIC_AREA { + unknown_traffic_area, // The driver has no information about the current traffic area. + in_traffic_area, // Mobile unit has entered a subscribed traffic area. + in_auth_traffic_area, // Mobile unit is outside traffic area but is authorized. + unauth_traffic_area // Mobile unit is outside traffic area but is un-authorized. +} WW_MBX_TRAFFIC_AREA; + +// +// OID_WW_MBX_LIVE_DIE +// +typedef INT WW_MBX_LIVE_DIE; // 0 = DIE last received + // 1 = LIVE last received + // -1 = unknown +// +// OID_WW_MBX_TEMP_DEFAULTLIST +// + +typedef struct _WW_MBX_CHANNEL_PAIR { + UINT Mobile_Tx; + UINT Mobile_Rx; +} WW_MBX_CHANNEL_PAIR, *PWW_MBX_CHANNEL_PAIR; +typedef struct _WW_MBX_TEMPDEFAULTLIST { + UINT Length; + WW_MBX_CHANNEL_PAIR ChannelPair[1]; +} WW_MBX_TEMPDEFAULTLIST, *WW_PMBX_TEMPDEFAULTLIST; + +#endif // WIRELESS_WAN +#endif // _NTDDNDIS_ diff --git a/plugins/dev9/DEV9linuz/Win32/Packet.lib b/plugins/dev9/DEV9linuz/Win32/Packet.lib new file mode 100644 index 0000000000000000000000000000000000000000..253d81f07f12821a08e74e5271c5d2c00170f722 GIT binary patch literal 8180 zcmcgxOLG%P5N_Fk!C)}*`z7Zs`l=7e>2}adb(%Evp34E?T26V zex6c)^K(l}bD5=u`Rl5F&ikBS%y_R`y#VkfKwkr(e-Gf|3xLt*Tt@B#Fd5wEGBygp zWPHn$*Z4$9zUMOX67eVlZ@7#-MLf!Y&1Lc}0F%KSm$7$fN0~rAS8m`FWd=Ez3_tM% z%M7CoJ>xQscqUV?xJ)nNH_A|&%M`Ym$#9a(47P#EjC%H;Z@kCA+-+z2!iul)IPB2JP@O2XJ%o>wCF7rPY<<3Y0e8g4ybWR=M@)8>`i> zHXB$?wQiR}Y`nx*mSaRyy+E$Es(V%|46j*vsk^q-SgDk4$7-p~Q4Abguo@Nqrb4M+ zN4CSDXyDkDTCKTVb}UoPx{YJj8&$`Irh0C_-Lj1JQawlJt!)bj&s42u;*eXlX4^6j zoND3dg5`Yu+pT}wsyh0lAdpySYu6h)O+(MHy}m`%y-{rx zo41+W_?)Ovl?3OaMXy!tJ`VXeCca76TN7~>Tca;Zl^&lM;a7twpy?1 zQ;bb!Xy3%~>usi6YgDX?S~oQuK3gq{Y&8o2jXr=qjNdOV0zAh&aeoA0e-LB&7{Jyz zz-yHE82ewM{>=cuQ`Fn|d^-t{L)<(3em((k17μK?xBP@WB;ej4D_6u=@r)A)TK z-;-#2inzyEz8~c}a$?GaUN{fupdU`b1dPBG48bs*gtIUUC!h!V;3AxcGcW*2NWlzT zfJqpGaTtX`n1%#&byU9FUoYm^X^Kw4Xc!V^P;E>is1LX_*YV}bT>v!!=R{p-I1r^o zLi1dSgnxr`ah0BFxz>=>jL|(1I%VSH70Hw*@))}PO(jlhfi<`$yoJKon_n+U6hak< z04yrF@k&4f0SF=HK&OT20to}b4b2BPJW9sVU5;iW)$yo>x*ye}Z$u_S%@wtx#36$g zV-_LKsg;PxV}|H1+?Ccs_a=%yEH3H}ObaP)Obwbdt0u!1LAtRTl%-xv-@cR6nwieD zv7ipG;hD*pW_>851{I4jNop6q-#e4Mi^(NZ9V)b~pD|DzzHVU>`bVU7OE% z=dG>YY@!>In@?8$O#o&E%u4`?vx!sq7V*OzhiL+{N%*hZH6f5;*&p{Q9^nQ52g{X; z^zdj+45a|16bV&)s3=0zXE^ zO0pXGl=Qe`ebUuQ7Hqa@WD{*eKpuNSOSjLb||S ziJx5cP0UYz^*_8P^AlF@kh?W|-Y=aEj>L;}}l4KGRX21Lvn zz2qTu@-^lvkBHNKl1)20NtTaTzH(8<@B{aY}{%@mI21<9tK@+1lI z(s+F7MKd2>li?Ot%$|Q6(g{< +#include "devioctl.h" +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + +// ioctls +#define FILE_DEVICE_PROTOCOL 0x8000 + +#define IOCTL_PROTOCOL_STATISTICS CTL_CODE(FILE_DEVICE_PROTOCOL, 2 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_RESET CTL_CODE(FILE_DEVICE_PROTOCOL, 3 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_READ CTL_CODE(FILE_DEVICE_PROTOCOL, 4 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_WRITE CTL_CODE(FILE_DEVICE_PROTOCOL, 5 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_MACNAME CTL_CODE(FILE_DEVICE_PROTOCOL, 6 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_OPEN CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CLOSE CTL_CODE(FILE_DEVICE_PROTOCOL, 8 , METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define pBIOCSETBUFFERSIZE 9592 ///< IOCTL code: set kernel buffer size. +#define pBIOCSETF 9030 ///< IOCTL code: set packet filtering program. +#define pBIOCGSTATS 9031 ///< IOCTL code: get the capture stats. +#define pBIOCSRTIMEOUT 7416 ///< IOCTL code: set the read timeout. +#define pBIOCSMODE 7412 ///< IOCTL code: set working mode. +#define pBIOCSWRITEREP 7413 ///< IOCTL code: set number of physical repetions of every packet written by the app. +#define pBIOCSMINTOCOPY 7414 ///< IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call. +#define pBIOCSETOID 2147483648 ///< IOCTL code: set an OID value. +#define pBIOCQUERYOID 2147483652 ///< IOCTL code: get an OID value. +#define pATTACHPROCESS 7117 ///< IOCTL code: attach a process to the driver. Used in Win9x only. +#define pDETACHPROCESS 7118 ///< IOCTL code: detach a process from the driver. Used in Win9x only. +#define pBIOCSETDUMPFILENAME 9029 ///< IOCTL code: set the name of a the file used by kernel dump mode. +#define pBIOCEVNAME 7415 ///< IOCTL code: get the name of the event that the driver signals when some data is present in the buffer. +#define pBIOCSENDPACKETSNOSYNC 9032 ///< IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps associated with the packets. +#define pBIOCSENDPACKETSSYNC 9033 ///< IOCTL code: Send a buffer containing multiple packets to the network, respecting the timestamps associated with the packets. +#define pBIOCSETDUMPLIMITS 9034 ///< IOCTL code: Set the dump file limits. See the PacketSetDumpLimits() function. +#define pBIOCISDUMPENDED 7411 ///< IOCTL code: Get the status of the kernel dump process. See the PacketIsDumpEnded() function. + +#define pBIOCSTIMEZONE 7471 ///< IOCTL code: set time zone. Used in Win9x only. + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + + +#define NdisMediumNull -1 // Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 // Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 // Custom linktype: NDIS doesn't provide an equivalent + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/* + * Desired design of maximum size and alignment. + * These are implementation specific. + */ +#define _SS_MAXSIZE 128 // Maximum size. +#define _SS_ALIGNSIZE (sizeof(__int64)) // Desired alignment. + +/* + * Definitions used for sockaddr_storage structure paddings design. + */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE \ + + _SS_ALIGNSIZE)) + +struct sockaddr_storage { + short ss_family; // Address family. + char __ss_pad1[_SS_PAD1SIZE]; // 6 byte pad, this is to make + // implementation specific pad up to + // alignment field that follows explicit + // in the data structure. + __int64 __ss_align; // Field to force desired structure. + char __ss_pad2[_SS_PAD2SIZE]; // 112 byte pad to achieve desired size; + // _SS_MAXSIZE value minus size of + // ss_family, __ss_pad1, and + // __ss_align fields is 112. +}; + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. + +/*! + \brief Contains comprehensive information about a network adapter. + + This structure is filled with all the accessory information that the user can need about an adapter installed + on his system. +*/ +typedef struct _ADAPTER_INFO +{ + struct _ADAPTER_INFO *Next; ///< Pointer to the next adapter in the list. + CHAR Name[ADAPTER_NAME_LENGTH + 1]; ///< Name of the device representing the adapter. + CHAR Description[ADAPTER_DESC_LENGTH + 1]; ///< Human understandable description of the adapter + UINT MacAddressLen; ///< Length of the link layer address. + UCHAR MacAddress[MAX_MAC_ADDR_LENGTH]; ///< Link layer address. + NetType LinkLayer; ///< Physical characteristics of this adapter. This NetType structure contains the link type and the speed of the adapter. + INT NNetworkAddresses; ///< Number of network layer addresses of this adapter. + npf_if_addr *NetworkAddresses; ///< Pointer to an array of npf_if_addr, each of which specifies a network address of this adapter. + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. +} +ADAPTER_INFO, *PADAPTER_INFO; + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + + +#if _DBG +#define ODS(_x) OutputDebugString(TEXT(_x)) +#define ODSEx(_x, _y) +#else +#ifdef _DEBUG_TO_FILE +/*! + \brief Macro to print a debug string. The behavior differs depending on the debug level +*/ +#define ODS(_x) { \ + FILE *f; \ + f = fopen("winpcap_debug.txt", "a"); \ + fprintf(f, "%s", _x); \ + fclose(f); \ +} +/*! + \brief Macro to print debug data with the printf convention. The behavior differs depending on + the debug level +*/ +#define ODSEx(_x, _y) { \ + FILE *f; \ + f = fopen("winpcap_debug.txt", "a"); \ + fprintf(f, _x, _y); \ + fclose(f); \ +} + + + +LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName); +#else +#define ODS(_x) +#define ODSEx(_x, _y) +#endif +#endif + +/* We load dinamically the dag library in order link it only when it's present on the system */ +#ifdef HAVE_DAG_API +typedef dagc_t* (*dagc_open_handler)(const char *source, unsigned flags, char *ebuf); ///< prototype used to dynamically load the dag dll +typedef void (*dagc_close_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_getlinktype_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_getlinkspeed_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_setsnaplen_handler)(dagc_t *dagcfd, unsigned snaplen); ///< prototype used to dynamically load the dag dll +typedef unsigned (*dagc_getfcslen_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_receive_handler)(dagc_t *dagcfd, u_char **buffer, u_int *bufsize); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_stats_handler)(dagc_t *dagcfd, dagc_stats_t *ps); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_wait_handler)(dagc_t *dagcfd, struct timeval *timeout); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_finddevs_handler)(dagc_if_t **alldevsp, char *ebuf); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_freedevs_handler)(dagc_if_t *alldevsp); ///< prototype used to dynamically load the dag dll +#endif // HAVE_DAG_API + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +// The following is used to check the adapter name in PacketOpenAdapterNPF and prevent +// opening of firewire adapters +#define FIREWIRE_SUBSTR L"1394" + +void PacketPopulateAdaptersInfoList(); +PWCHAR SChar2WChar(PCHAR string); +PCHAR WChar2SChar(PWCHAR string); +BOOL PacketGetFileVersion(LPTSTR FileName, PCHAR VersionBuff, UINT VersionBuffLen); +PADAPTER_INFO PacketFindAdInfo(PCHAR AdapterName); +BOOLEAN PacketUpdateAdInfo(PCHAR AdapterName); +BOOLEAN IsFireWire(TCHAR *AdapterDesc); + + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/plugins/dev9/DEV9linuz/Win32/Win32.c b/plugins/dev9/DEV9linuz/Win32/Win32.c new file mode 100644 index 0000000000..0df0870fec --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/Win32.c @@ -0,0 +1,132 @@ +#include +#include +#include + +#include "Config.h" +#include "resource.h" +#include "DEV9.h" +#include "socks.h" + +HINSTANCE hInst; +HANDLE handleDEV9Thread = NULL; +DWORD dwThreadId, dwThrdParam; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "Dev9linuz Msg", 0); +} + +void OnInitDialog(HWND hW) { + char *dev; + int i; + + LoadConf(); + + ComboBox_AddString(GetDlgItem(hW, IDC_BAYTYPE), "Expansion"); + ComboBox_AddString(GetDlgItem(hW, IDC_BAYTYPE), "PC Card"); + for (i=0; i +#include + +#define IDC_STATIC (-1) diff --git a/plugins/dev9/DEV9linuz/Win32/libpacket.a b/plugins/dev9/DEV9linuz/Win32/libpacket.a new file mode 100644 index 0000000000000000000000000000000000000000..b70fed022f676e746676cb82fb9f2c4623196a53 GIT binary patch literal 23732 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 literal 0 HcmV?d00001 diff --git a/plugins/dev9/DEV9linuz/Win32/plugin.def b/plugins/dev9/DEV9linuz/Win32/plugin.def new file mode 100644 index 0000000000..cf90edec15 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/plugin.def @@ -0,0 +1,24 @@ +EXPORTS + DEV9ThreadProc @4 + DEV9about = DEV9about@0 @5 + DEV9close = DEV9close@0 @6 + DEV9configure = DEV9configure@0 @7 + DEV9init = DEV9init@0 @8 + DEV9irq @9 DATA + DEV9irqCallback = DEV9irqCallback@4 @10 + DEV9irqHandler = DEV9irqHandler@0 @11 + DEV9open = DEV9open@4 @12 + DEV9read16 = DEV9read16@4 @13 + DEV9read32 = DEV9read32@4 @14 + DEV9read8 = DEV9read8@4 @15 + DEV9readDMA8Mem = DEV9readDMA8Mem@8 @16 + DEV9shutdown = DEV9shutdown@0 @17 + DEV9test = DEV9test@0 @18 + DEV9thread @19 + DEV9write16 = DEV9write16@8 @20 + DEV9write32 = DEV9write32@8 @21 + DEV9write8 = DEV9write8@8 @22 + DEV9writeDMA8Mem = DEV9writeDMA8Mem@8 @23 + PS2EgetLibName = PS2EgetLibName@0 @28 + PS2EgetLibType = PS2EgetLibType@0 @29 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @30 diff --git a/plugins/dev9/DEV9linuz/Win32/resource.h b/plugins/dev9/DEV9linuz/Win32/resource.h new file mode 100644 index 0000000000..fc9591a545 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by DEV9linuz.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_COMBO1 1007 +#define IDC_ETHDEV 1007 +#define IDC_BAYTYPE 1008 +#define IDC_ETHENABLED 1009 +#define IDC_HDDFILE 1010 +#define IDC_HDDENABLED 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/dev9/DEV9linuz/Win32/socks.c b/plugins/dev9/DEV9linuz/Win32/socks.c new file mode 100644 index 0000000000..1c8a0c94e5 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/socks.c @@ -0,0 +1,191 @@ +#include +#include + +#include "packet32.h" +#include "ntddndis.h" + +#include "socks.h" +#include "DEV9.h" + +#define BUFFER_SIZE (2048) + +LPADAPTER lpAdapter; +LPPACKET lpSendPacket; +LPPACKET lpRecvPacket; +u8 buffer[BUFFER_SIZE]; +u8 *buf; +int lbytes; +int tbytes; +typedef struct { + char name[256]; + char desc[256]; +} _Adapter; + +_Adapter AdapterList[16]; + +long sockOpen(char *Device) { + lpAdapter = PacketOpenAdapter(Device); + if (lpAdapter == NULL) return -1; + +#ifdef DEV9_LOG + DEV9_LOG("PacketOpenAdapter %s: %p\n", Device, lpAdapter); +#endif + + if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE){ + SysMessage("Warning: unable to set promiscuous mode!"); + } + + if(PacketSetBuff(lpAdapter,512000)==FALSE){ + SysMessage("Unable to set the kernel buffer!"); + return -1; + } + + if(PacketSetReadTimeout(lpAdapter,100)==FALSE){ + SysMessage("Warning: unable to set the read tiemout!"); + } + + if((lpRecvPacket = PacketAllocatePacket())==NULL){ + SysMessage("Error: failed to allocate the LPPACKET structure."); + return (-1); + } + if((lpSendPacket = PacketAllocatePacket())==NULL){ + SysMessage("Error: failed to allocate the LPPACKET structure."); + return (-1); + } + + lbytes=0; + tbytes=0; + + return 0; +} + +void sockClose() { + PacketCloseAdapter(lpAdapter); +} + +long sockSendData(void *pData, int Size) { + u8 *data = (u8*)pData; +// printf("_sendPacket %d (time=%d)\n", Size, timeGetTime()); + while (Size > 0) { + PacketInitPacket(lpSendPacket, data, Size > 1024 ? 1024 : Size); + if(PacketSendPacket(lpAdapter,lpSendPacket,FALSE)==FALSE){ + printf("Error: PacketSendPacket failed\n"); + return (-1); + } + data+= 1024; Size-= 1024; + PacketFreePacket(lpSendPacket); + } + + return 0; +} + +int _filterPacket(u8 *_buf) { +/* DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[5], _buf[4], _buf[3], _buf[2], _buf[1], _buf[0]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[11], _buf[10], _buf[9], _buf[8], _buf[7], _buf[6]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[17], _buf[16], _buf[15], _buf[14], _buf[13], _buf[12]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[23], _buf[22], _buf[21], _buf[20], _buf[19], _buf[18]); +*/ + if (_buf[0] == 0xff && _buf[1] == 0xff && _buf[2] == 0xff && + _buf[3] == 0xff && _buf[4] == 0xff && _buf[5] == 0xff) { + return 1; + } else + if (_buf[0] == 0x00 && _buf[1] == 0x00 && _buf[2] == 0x00 && + _buf[3] == 0x00 && _buf[4] == 0x00 && _buf[5] == 0x00) { + return 1; + } else + if (*((u16*)&_buf[12]) == 0x0806) { + printf("ARP\n"); + return 1; + } + + return 0; +} + +int _recvPacket(void *pData) { + struct bpf_hdr *hdr; + u8 *data; + int ret=0; + int size; + + while (lbytes > 0) { + hdr = (struct bpf_hdr *)buf; +// DEV9_LOG("hdr %d,%d,%d\n", hdr->bh_hdrlen, hdr->bh_caplen, hdr->bh_datalen); +// DEV9_LOG("lbytes %d\n", lbytes); + data = buf+hdr->bh_hdrlen; + size = Packet_WORDALIGN(hdr->bh_hdrlen+hdr->bh_datalen); + buf+= size; lbytes-= size; + if (_filterPacket(data)) { + struct bpf_stat stat; + + ret = hdr->bh_datalen; + memcpy(pData, data, ret); + if(PacketGetStats(lpAdapter,&stat)==FALSE){ + printf("Warning: unable to get stats from the kernel!\n"); + } +// printf("_recvPacket %d (tbytes=%d, packets=%d, lost=%d, time=%d)\n", ret, tbytes, stat.bs_recv,stat.bs_drop, timeGetTime()); +// printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", data[5], data[4], data[3], data[2], data[1], data[0]); + break; + } + } + + return ret; +} + +long sockRecvData(void *pData, int Size) { + int ret; + + ret = _recvPacket(pData); + if (ret > 0) return ret; + + PacketInitPacket(lpRecvPacket, buffer, BUFFER_SIZE); + if(PacketReceivePacket(lpAdapter,lpRecvPacket,TRUE)==FALSE){ + printf("Error: PacketReceivePacket failed"); + return (-1); + } + lbytes = lpRecvPacket->ulBytesReceived; + tbytes+= lbytes; +// DEV9_LOG("PacketReceivePacket %d:\n", lbytes); + if (lbytes == 0) return 0; + memcpy(buffer, lpRecvPacket->Buffer, lbytes); + buf = buffer; + PacketFreePacket(lpRecvPacket); + + return _recvPacket(pData); +} + +long sockGetDevicesNum() { + char AdapterName[8192]; // string that contains a list of the network adapters + ULONG AdapterLength; + char *temp,*temp1; + int i; + + AdapterLength = sizeof(AdapterName); + if(PacketGetAdapterNames(AdapterName,&AdapterLength)==FALSE){ + printf("Unable to retrieve the list of the adapters!\n"); + return -1; + } + temp=AdapterName; + temp1=AdapterName; + + i=0; + while (temp[0] != 0) { + strcpy(AdapterList[i++].name, temp); + temp+= strlen(temp)+1; + } + i=0; temp++; + while (temp[0] != 0) { + strcpy(AdapterList[i++].desc, temp); + temp+= strlen(temp)+1; + } + + return i; +} + +char *sockGetDevice(int index) { + return AdapterList[index].name; +} + +char *sockGetDeviceDesc(int index) { + return AdapterList[index].desc; +} + diff --git a/plugins/dev9/DEV9linuz/Win32/socks.h b/plugins/dev9/DEV9linuz/Win32/socks.h new file mode 100644 index 0000000000..22cf9ab151 --- /dev/null +++ b/plugins/dev9/DEV9linuz/Win32/socks.h @@ -0,0 +1,12 @@ +#ifndef __SOCKS_H__ +#define __SOCKS_H__ + +long sockOpen(char *Device); +void sockClose(); +long sockSendData(void *pData, int Size); +long sockRecvData(void *pData, int Size); +long sockGetDevicesNum(); +char *sockGetDevice(int index); +char *sockGetDeviceDesc(int index); + +#endif /* __SOCKS_H__*/ diff --git a/plugins/dev9/DEV9linuz/dvr.c b/plugins/dev9/DEV9linuz/dvr.c new file mode 100644 index 0000000000..21e36782cc --- /dev/null +++ b/plugins/dev9/DEV9linuz/dvr.c @@ -0,0 +1,67 @@ +// DVR code is dummy + +#include +#include "DEV9.h" + +#define DEV9_DVR_LOG DEV9_LOG + +void CALLBACK DVRinit(){ +} + +u32 CALLBACK DVRread32(u32 addr, int size) { + switch(addr) { + case DVR_R_STAT: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR STAT %dbit read\n", size*8); +#endif + return dev9Ru32(addr); + + case DVR_R_ACK: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR ACK %dbit read\n", size*8); +#endif + return dev9Ru32(addr); + + case DVR_R_MASK: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR MASK %dbit read\n", size*8); +#endif + return dev9Ru32(addr); + + case DVR_R_TASK: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR TASK %dbit read\n", size*8); +#endif + return 0x3E; + + default: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR Unkwnown %dbit read at address %lx\n", size*8, addr); +#endif + return 0; + } +} + +void CALLBACK DVRwrite32(u32 addr, u32 value, int size) { + + switch(addr & 0x1FFFFFFF) { + case DVR_R_ACK: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR ACK %dbit write 0x%08lX\n", size*8, value); +#endif + dev9Ru32(DVR_R_STAT) &= ~value;//ack the intrs + break; + + case DVR_R_MASK: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR MASK %dbit write 0x%08lX\n", size*8, value); +#endif + break; + + default: +#ifdef DEV9_DVR_LOG + DEV9_DVR_LOG("*DVR Unkwnown %dbit write at address 0x%08lX= 0x%08lX\n", size*8, addr, value); +#endif + break; + } +} diff --git a/plugins/dev9/DEV9linuz/flash.c b/plugins/dev9/DEV9linuz/flash.c new file mode 100644 index 0000000000..d38ef5b682 --- /dev/null +++ b/plugins/dev9/DEV9linuz/flash.c @@ -0,0 +1,289 @@ +// The code has been designed for 64Mb flash and uses as file support flash.ps2 + +#include +#include "DEV9.h" + +//#define DEV9_FLASH_LOG DEV9_LOG + +#define PAGE_SIZE_BITS 9 +#define PAGE_SIZE (1<>2), page+PAGE_SIZE+0*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 1*(PAGE_SIZE>>2), page+PAGE_SIZE+1*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 2*(PAGE_SIZE>>2), page+PAGE_SIZE+2*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 3*(PAGE_SIZE>>2), page+PAGE_SIZE+3*3);//(ECC_SIZE>>2)); +} + +static char* getCmdName(u32 cmd){ + switch(cmd) { + case SM_CMD_READ1: return "READ1"; + case SM_CMD_READ2: return "READ2"; + case SM_CMD_READ3: return "READ3"; + case SM_CMD_RESET: return "RESET"; + case SM_CMD_WRITEDATA: return "WRITEDATA"; + case SM_CMD_PROGRAMPAGE: return "PROGRAMPAGE"; + case SM_CMD_ERASEBLOCK: return "ERASEBLOCK"; + case SM_CMD_ERASECONFIRM: return "ERASECONFIRM"; + case SM_CMD_GETSTATUS: return "GETSTATUS"; + case SM_CMD_READID: return "READID"; + default: return "unknown"; + } +} + +void CALLBACK FLASHinit(){ + FILE *fd; + + id= FLASH_ID_64MBIT; + counter= 0; + addrbyte= 0; + + address = 0; + memset(data, 0xFF, PAGE_SIZE); + calculateECC(data); + ctrl = FLASH_PP_READY; + + if (fd=fopen("memcards\\flash.ps2", "rb")){ + fread(file, 1, CARD_SIZE_ECC, fd); + fclose(fd); + }else{ + memset(file, 0xFF, CARD_SIZE_ECC); +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("Working without a file. Copy mcd002.ps2 to flash.ps2\n"); +#endif + } +} + +u32 CALLBACK FLASHread32(u32 addr, int size) { + u32 value, refill= 0; + + switch(addr) { + case FLASH_R_DATA: + memcpy(&value, &data[counter], size); + counter += size; +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH DATA %dbit read 0x%08lX %s\n", size*8, value, (ctrl & FLASH_PP_READ) ? "READ_ENABLE" : "READ_DISABLE"); +#endif + if (cmd == SM_CMD_READ3){ + if (counter >= PAGE_SIZE_ECC){ + counter= PAGE_SIZE; + refill= 1; + } + }else{ + if ( (ctrl & FLASH_PP_NOECC) && (counter >= PAGE_SIZE)){ + counter %= PAGE_SIZE; + refill= 1; + }else + if (!(ctrl & FLASH_PP_NOECC) && (counter >= PAGE_SIZE_ECC)){ + counter %= PAGE_SIZE_ECC; + refill= 1; + } + } + + if (refill){ + ctrl &= ~FLASH_PP_READY; + address += PAGE_SIZE; + address %= CARD_SIZE; + memcpy(data, file+(address>>PAGE_SIZE_BITS)*PAGE_SIZE_ECC, PAGE_SIZE); + calculateECC(data); // calculate ECC; should be in the file already + ctrl |= FLASH_PP_READY; + } + + return value; + + case FLASH_R_CMD: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CMD %dbit read %s DENIED\n", size*8, getCmdName(cmd)); +#endif + return cmd; + + case FLASH_R_ADDR: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH ADDR %dbit read DENIED\n", size*8); +#endif + return 0; + + case FLASH_R_CTRL: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CTRL %dbit read 0x%08lX\n", size*8, ctrl); +#endif + return ctrl; + + case FLASH_R_ID: + if (cmd == SM_CMD_READID){ +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH ID %dbit read 0x%08lX\n", size*8, id); +#endif + return id;//0x98=Toshiba/0xEC=Samsung maker code should be returned first + }else + if (cmd == SM_CMD_GETSTATUS){ + value= 0x80 | ((ctrl & 1) << 6); // 0:0=pass, 6:ready/busy, 7:1=not protected +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH STATUS %dbit read 0x%08lX\n", size*8, value); +#endif + return value; + }//else fall off + + default: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH Unkwnown %dbit read at address %lx\n", size*8, addr); +#endif + return 0; + } +} + +void CALLBACK FLASHwrite32(u32 addr, u32 value, int size) { + + switch(addr & 0x1FFFFFFF) { + case FLASH_R_DATA: + +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH DATA %dbit write 0x%08lX %s\n", size*8, value, (ctrl & FLASH_PP_WRITE) ? "WRITE_ENABLE" : "WRITE_DISABLE"); +#endif + memcpy(&data[counter], &value, size); + counter += size; + counter %= PAGE_SIZE_ECC;//should not get past the last byte, but at the end + break; + + case FLASH_R_CMD: + if (!(ctrl & FLASH_PP_READY)){ + if ((value != SM_CMD_GETSTATUS) && (value != SM_CMD_RESET)){ +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CMD %dbit write %s ILLEGAL in busy mode - IGNORED\n", size*8, getCmdName(value)); +#endif + break; + } + } + if (cmd == SM_CMD_WRITEDATA){ + if ((value != SM_CMD_PROGRAMPAGE) && (value != SM_CMD_RESET)){ +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CMD %dbit write %s ILLEGAL after WRITEDATA cmd - IGNORED\n", size*8, getCmdName(value)); +#endif + ctrl &= ~FLASH_PP_READY;//go busy, reset is needed + break; + } + } +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CMD %dbit write %s\n", size*8, getCmdName(value)); +#endif + switch (value){ // A8 bit is encoded in READ cmd;) + case SM_CMD_READ1: counter= 0; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_READ2: counter= PAGE_SIZE/2; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_READ3: counter= PAGE_SIZE; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_RESET: FLASHinit(); break; + case SM_CMD_WRITEDATA: counter= 0; address= counter; addrbyte= 0; break; + case SM_CMD_ERASEBLOCK: counter= 0; memset(data, 0xFF, PAGE_SIZE); address= counter; addrbyte= 1; break; + case SM_CMD_PROGRAMPAGE: //fall + case SM_CMD_ERASECONFIRM: + ctrl &= ~FLASH_PP_READY; + calculateECC(data); + memcpy(file+(address/PAGE_SIZE)*PAGE_SIZE_ECC, data, PAGE_SIZE_ECC); + /*write2file*/ + ctrl |= FLASH_PP_READY; break; + case SM_CMD_GETSTATUS: break; + case SM_CMD_READID: counter= 0; address= counter; addrbyte= 0; break; + default: + ctrl &= ~FLASH_PP_READY; + return;//ignore any other command; go busy, reset is needed + } + cmd= value; + break; + + case FLASH_R_ADDR: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH ADDR %dbit write 0x%08lX\n", size*8, value); +#endif + address |= (value & 0xFF) << (addrbyte == 0 ? 0 : (1 + 8 * addrbyte)); + addrbyte++; +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH ADDR = 0x%08lX (addrbyte=%d)\n", address, addrbyte); +#endif + if (!(value & 0x100)){ // address is complete + if ((cmd == SM_CMD_READ1) || (cmd == SM_CMD_READ2) || (cmd == SM_CMD_READ3)) { + ctrl &= ~FLASH_PP_READY; + memcpy(data, file+(address>>PAGE_SIZE_BITS)*PAGE_SIZE_ECC, PAGE_SIZE); + calculateECC(data); // calculate ECC; should be in the file already + ctrl |= FLASH_PP_READY; + } + addrbyte= 0; // address reset +#ifdef DEV9_FLASH_LOG + { + u32 bytes, pages, blocks; + + blocks = address / BLOCK_SIZE; + pages = address-(blocks*BLOCK_SIZE); + bytes = pages % PAGE_SIZE; + pages = pages / PAGE_SIZE; + DEV9_FLASH_LOG("*FLASH ADDR = 0x%08lX (%d:%d:%d) (addrbyte=%d) FINAL\n", address, blocks, pages, bytes, addrbyte); + } +#endif + } + break; + + case FLASH_R_CTRL: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH CTRL %dbit write 0x%08lX\n", size*8, value); +#endif + ctrl = (ctrl & FLASH_PP_READY) | (value & ~FLASH_PP_READY); + break; + + case FLASH_R_ID: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH ID %dbit write 0x%08lX DENIED :P\n", size*8, value); +#endif + break; + + default: +#ifdef DEV9_FLASH_LOG + DEV9_FLASH_LOG("*FLASH Unkwnown %dbit write at address 0x%08lX= 0x%08lX IGNORED\n", size*8, addr, value); +#endif + break; + } +} + +static unsigned char xor_table[256]={ + 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00, + 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, + 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, + 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, + 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, + 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, + 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, + 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, + 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, + 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, + 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, + 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, + 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, + 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, + 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, + 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00}; + +static void xfromman_call20_calculateXors(unsigned char buffer[128], unsigned char xor[4]){ + register unsigned char a=0, b=0, c=0, i; + + for (i=0; i<128; i++){ + a ^= xor_table[buffer[i]]; + if (xor_table[buffer[i]] & 0x80){ + b ^= ~i; + c ^= i; + } + } + + xor[0]=(~a) & 0x77; + xor[1]=(~b) & 0x7F; + xor[2]=(~c) & 0x7F; +} diff --git a/plugins/dev9/build.sh b/plugins/dev9/build.sh new file mode 100644 index 0000000000..50d1c006bd --- /dev/null +++ b/plugins/dev9/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +echo ------------------------ +echo Building DEV9 plugins... +echo ------------------------ +curdir=`pwd` + +cd ${curdir}/dev9null +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/DEV9.cpp b/plugins/dev9/dev9ghzdrk/DEV9.cpp new file mode 100644 index 0000000000..05b009f73e --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/DEV9.cpp @@ -0,0 +1,603 @@ +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 +#include +#include +#include +#include +#include +#include +#include +#include +#define EXTERN +#include "DEV9.h" +#undef EXTERN +#include "Config.h" +#include "smap.h" +#include "ata.h" + +#ifdef __WIN32__ +#pragma warning(disable:4244) + +HINSTANCE hInst=NULL; +#endif + +//#define HDD_48BIT + +u8 eeprom[] = { + //0x6D, 0x76, 0x63, 0x61, 0x31, 0x30, 0x08, 0x01, + 0x76, 0x6D, 0x61, 0x63, 0x30, 0x31, 0x07, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +int Log = 1; + +u32 *iopPC; + +const unsigned char version = PS2E_DEV9_VERSION; +const unsigned char revision = 0; +const unsigned char build = 3; // increase that with each version + + +static char *libraryName = "GiGaHeRz's DEV9 Driver" +#ifdef _DEBUG + "(debug)" +#endif +; + +HANDLE hEeprom; +HANDLE mapping; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_DEV9; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + static int ticks=-1; + int nticks=GetTickCount(); + + if(ticks==-1) ticks=nticks; + +// if (!Log) return; + if(iopPC!=NULL) + { + fprintf(dev9Log,"[%10d + %4d, IOP PC = %08x] ",nticks,nticks-ticks,*iopPC); + } + else + { + fprintf(dev9Log,"[%10d + %4d] ",nticks,nticks-ticks); + } + ticks=nticks; + + va_start(list, fmt); + vfprintf(dev9Log, fmt, list); + va_end(list); +} + + +s32 CALLBACK DEV9init() +{ + +#ifdef DEV9_LOG_ENABLE + dev9Log = fopen("logs/dev9Log.txt", "w"); + setvbuf(dev9Log, NULL, _IONBF, 0); + DEV9_LOG("DEV9init\n"); +#endif + memset(&dev9, 0, sizeof(dev9)); + DEV9_LOG("DEV9init2\n"); + + DEV9_LOG("DEV9init3\n"); + + FLASHinit(); + + hEeprom = CreateFile( + "eeprom.dat", + GENERIC_READ|GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_WRITE_THROUGH, + NULL + ); + + if(hEeprom==INVALID_HANDLE_VALUE) + { + dev9.eeprom=(u16*)eeprom; + } + else + { + mapping=CreateFileMapping(hEeprom,NULL,PAGE_READWRITE,0,0,NULL); + if(mapping==INVALID_HANDLE_VALUE) + { + CloseHandle(hEeprom); + dev9.eeprom=(u16*)eeprom; + } + else + { + dev9.eeprom = (u16*)MapViewOfFile(mapping,FILE_MAP_WRITE,0,0,0); + if(dev9.eeprom==NULL) + { + CloseHandle(mapping); + CloseHandle(hEeprom); + dev9.eeprom=(u16*)eeprom; + } + } + } + + + { + int rxbi; + + for(rxbi=0;rxbi<(SMAP_BD_SIZE/8);rxbi++) + { + smap_bd_t *pbd = (smap_bd_t *)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff]; + pbd = &pbd[rxbi]; + + pbd->ctrl_stat = SMAP_BD_RX_EMPTY; + pbd->length = 0; + } + } + + DEV9_LOG("DEV9init ok\n"); + + return 0; +} + +void CALLBACK DEV9shutdown() { + DEV9_LOG("DEV9shutdown\n"); +#ifdef DEV9_LOG_ENABLE + fclose(dev9Log); +#endif +} + +s32 CALLBACK DEV9open(void *pDsp) +{ + DEV9_LOG("DEV9open\n"); + LoadConf(); + DEV9_LOG("open r+: %s\n", config.Hdd); + config.HddSize = 8*1024; + + iopPC = (u32*)pDsp; + +#ifdef ENABLE_ATA + ata_init(); +#endif + return _DEV9open(); +} + +void CALLBACK DEV9close() +{ + DEV9_LOG("DEV9close\n"); +#ifdef ENABLE_ATA + ata_term(); +#endif + _DEV9close(); +} + +int CALLBACK _DEV9irqHandler(void) +{ + //dev9Ru16(SPD_R_INTR_STAT)|= dev9.irqcause; + DEV9_LOG("_DEV9irqHandler %x, %x\n", dev9.irqcause, dev9Ru16(SPD_R_INTR_MASK)); + if (dev9.irqcause & dev9Ru16(SPD_R_INTR_MASK)) + return 1; + return 0; +} + +DEV9handler CALLBACK DEV9irqHandler(void) { + return (DEV9handler)_DEV9irqHandler; +} + +void _DEV9irq(int cause, int cycles) +{ + DEV9_LOG("_DEV9irq %x, %x\n", cause, dev9Ru16(SPD_R_INTR_MASK)); + + dev9.irqcause|= cause; + + if(cycles<1) + DEV9irq(1); + else + DEV9irq(cycles); +} + + +u8 CALLBACK DEV9read8(u32 addr) { + u8 hard; + if (addr>=ATA_DEV9_HDD_BASE && addr(addr); +#else + return 0; +#endif + } + if (addr>=SMAP_REGBASE && addr>11; + dev9.eeprom_bit++; + if(dev9.eeprom_bit==16) + { + dev9.eeprom_address++; + dev9.eeprom_bit=0; + } + } + else hard=0; + } + else hard=0; + return hard; + + case DEV9_R_REV: + hard = 0x32; // expansion bay + break; + + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u8)FLASHread32(addr, 1); + } + + hard = dev9Ru8(addr); + DEV9_LOG("*Unknown 8bit read at address %lx value %x\n", addr, hard); + return hard; + } + + DEV9_LOG("*Known 8bit read at address %lx value %x\n", addr, hard); + return hard; +} + +u16 CALLBACK DEV9read16(u32 addr) +{ + u16 hard; + if (addr>=ATA_DEV9_HDD_BASE && addr(addr); +#else + return 0; +#endif + } + if (addr>=SMAP_REGBASE && addr= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u16)FLASHread32(addr, 2); + } + + hard = dev9Ru16(addr); + DEV9_LOG("*Unknown 16bit read at address %lx value %x\n", addr, hard); + return hard; + } + + DEV9_LOG("*Known 16bit read at address %lx value %x\n", addr, hard); + return hard; +} + +u32 CALLBACK DEV9read32(u32 addr) +{ + u32 hard; + if (addr>=ATA_DEV9_HDD_BASE && addr(addr); +#else + return 0; +#endif + } + if (addr>=SMAP_REGBASE && addr= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + return (u32)FLASHread32(addr, 4); + } + + hard = dev9Ru32(addr); + DEV9_LOG("*Unknown 32bit read at address %lx value %x\n", addr, hard); + return hard; + } + + DEV9_LOG("*Known 32bit read at address %lx: %lx\n", addr, hard); + return hard; +} + +void CALLBACK DEV9write8(u32 addr, u8 value) +{ + if (addr>=ATA_DEV9_HDD_BASE && addr(addr,value); +#endif + return; + } + if (addr>=SMAP_REGBASE && addr>4)&3; + + return; + + case SPD_R_PIO_DATA: + //DEV9_LOG("SPD_R_PIO_DATA 8bit write %x\n", value); + + if((value&0xc0)!=0xc0) + return; + + switch(dev9.eeprom_state) + { + case EEPROM_READY: + dev9.eeprom_command=0; + dev9.eeprom_state++; + break; + case EEPROM_OPCD0: + dev9.eeprom_command = (value>>4)&2; + dev9.eeprom_state++; + dev9.eeprom_bit=0xFF; + break; + case EEPROM_OPCD1: + dev9.eeprom_command |= (value>>5)&1; + dev9.eeprom_state++; + break; + case EEPROM_ADDR0: + case EEPROM_ADDR1: + case EEPROM_ADDR2: + case EEPROM_ADDR3: + case EEPROM_ADDR4: + case EEPROM_ADDR5: + dev9.eeprom_address = + (dev9.eeprom_address&(63^(1<<(dev9.eeprom_state-EEPROM_ADDR0))))| + ((value>>(dev9.eeprom_state-EEPROM_ADDR0))&(0x20>>(dev9.eeprom_state-EEPROM_ADDR0))); + dev9.eeprom_state++; + break; + case EEPROM_TDATA: + { + if(dev9.eeprom_command==1) //write + { + dev9.eeprom[dev9.eeprom_address] = + (dev9.eeprom[dev9.eeprom_address]&(63^(1<>dev9.eeprom_bit)&(0x8000>>dev9.eeprom_bit)); + dev9.eeprom_bit++; + if(dev9.eeprom_bit==16) + { + dev9.eeprom_address++; + dev9.eeprom_bit=0; + } + } + } + break; + } + + return; + + default: + if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 1); + return; + } + + dev9Ru8(addr) = value; + DEV9_LOG("*Unknown 8bit write at address %lx value %x\n", addr, value); + return; + } + dev9Ru8(addr) = value; + DEV9_LOG("*Known 8bit write at address %lx value %x\n", addr, value); +} + +void CALLBACK DEV9write16(u32 addr, u16 value) +{ + if (addr>=ATA_DEV9_HDD_BASE && addr(addr,value); +#endif + return; + } + if (addr>=SMAP_REGBASE && addr= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 2); + return; + } + + dev9Ru16(addr) = value; + DEV9_LOG("*Unknown 16bit write at address %lx value %x\n", addr, value); + return; + } + dev9Ru16(addr) = value; + DEV9_LOG("*Known 16bit write at address %lx value %x\n", addr, value); +} + +void CALLBACK DEV9write32(u32 addr, u32 value) +{ + if (addr>=ATA_DEV9_HDD_BASE && addr(addr,value); +#endif + return; + } + if (addr>=SMAP_REGBASE && addr= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE))) { + FLASHwrite32(addr, (u32)value, 4); + return; + } + + dev9Ru32(addr) = value; + DEV9_LOG("*Unknown 32bit write at address %lx write %x\n", addr, value); + return; + } + dev9Ru32(addr) = value; + DEV9_LOG("*Known 32bit write at address %lx value %lx\n", addr, value); +} + +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size) +{ + DEV9_LOG("*DEV9readDMA8Mem: size %x\n", size); + emu_printf("rDMA\n"); + + smap_readDMA8Mem(pMem,size); +#ifdef ENABLE_ATA + ata_readDMA8Mem(pMem,size); +#endif +} + +void CALLBACK DEV9writeDMA8Mem(u32* pMem, int size) +{ + DEV9_LOG("*DEV9writeDMA8Mem: size %x\n", size); + emu_printf("wDMA\n"); + + smap_writeDMA8Mem(pMem,size); +#ifdef ENABLE_ATA + ata_writeDMA8Mem(pMem,size); +#endif +} + + +//plugin interface +void CALLBACK DEV9irqCallback(void (*callback)(int cycles)) { + DEV9irq = callback; +} + + +// extended funcs + +s32 CALLBACK DEV9test() { + return 0; +} + +int emu_printf(const char *fmt, ...) +{ + va_list vl; + int ret; + va_start(vl,fmt); + ret = vfprintf(stderr,fmt,vl); + va_end(vl); + return ret; +} \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/DEV9.h b/plugins/dev9/dev9ghzdrk/DEV9.h new file mode 100644 index 0000000000..068a12cb46 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/DEV9.h @@ -0,0 +1,629 @@ +#ifndef __DEV9_H__ +#define __DEV9_H__ + +#include +#ifndef EXTERN +#define EXTERN extern +#endif +#define DEV9defs +//#define WINVER 0x0600 +//#define _WIN32_WINNT 0x0500 + +#include "PS2Edefs.h" +#include "net.h" + +#ifdef __WIN32__ + +#define usleep(x) Sleep(x / 1000) +#include +#include +#include + +#else + +#include + +#define __inline inline + +#endif + +#define DEV9_LOG_ENABLE + +#ifdef DEV9_LOG_ENABLE +#define DEV9_LOG __Log +#else +#define DEV9_LOG(...) () +#endif + +void rx_process(NetPacket* pk); +bool rx_fifo_can_rx(); + +#define ETH_DEF "eth0" +#define HDD_DEF "DEV9hdd.raw" + + typedef struct { + char Eth[256]; + char Hdd[256]; + int HddSize; + + int hddEnable; + int ethEnable; +} Config; + +EXTERN Config config; + +typedef struct { + s8 dev9R[0x10000]; + u8 eeprom_state; + u8 eeprom_command; + u8 eeprom_address; + u8 eeprom_bit; + u8 eeprom_dir; + u16 *eeprom;//[32]; + + u32 rxbdi; + u8 rxfifo[16*1024]; + u16 rxfifo_wr_ptr; + + u32 txbdi; + u8 txfifo[16*1024]; + u16 txfifo_rd_ptr; + + u8 bd_swap; + u16 atabuf[1024]; + u32 atacount; + u32 atasize; + u16 phyregs[32]; + int irqcause; + u8 atacmd; + u32 atasector; + u32 atansector; +} dev9Struct; + +//EEPROM states +#define EEPROM_READY 0 +#define EEPROM_OPCD0 1 //waiting for first bit of opcode +#define EEPROM_OPCD1 2 //waiting for second bit of opcode +#define EEPROM_ADDR0 3 //waiting for address bits +#define EEPROM_ADDR1 4 +#define EEPROM_ADDR2 5 +#define EEPROM_ADDR3 6 +#define EEPROM_ADDR4 7 +#define EEPROM_ADDR5 8 +#define EEPROM_TDATA 9 //ready to send/receive data + +EXTERN dev9Struct dev9; + +#define dev9_rxfifo_write(x) (dev9.rxfifo[dev9.rxfifo_wr_ptr++]=x) + +#define dev9Rs8(mem) dev9.dev9R[(mem) & 0xffff] +#define dev9Rs16(mem) (*(s16*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Rs32(mem) (*(s32*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru8(mem) (*(u8*) &dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru16(mem) (*(u16*)&dev9.dev9R[(mem) & 0xffff]) +#define dev9Ru32(mem) (*(u32*)&dev9.dev9R[(mem) & 0xffff]) + +EXTERN int ThreadRun; + +s32 _DEV9open(); +void _DEV9close(); +EXTERN DEV9callback DEV9irq; +//void DEV9thread(); + +EXTERN FILE *dev9Log; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#define DEV9_R_REV 0x1f80146e + + +/* + * SPEED (ASIC on SMAP) register definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2smap iop driver, modified by linuzappz * + */ + +#define SPD_REGBASE 0x10000000 + +#define SPD_R_REV (SPD_REGBASE + 0x00) +#define SPD_R_REV_1 (SPD_REGBASE + 0x02) + // bit 0: smap + // bit 1: hdd + // bit 5: flash +#define SPD_R_REV_3 (SPD_REGBASE + 0x04) +#define SPD_R_0e (SPD_REGBASE + 0x0e) + +#define SPD_R_DMA_CTRL (SPD_REGBASE + 0x24) +#define SPD_R_INTR_STAT (SPD_REGBASE + 0x28) +#define SPD_R_INTR_MASK (SPD_REGBASE + 0x2a) +#define SPD_R_PIO_DIR (SPD_REGBASE + 0x2c) +#define SPD_R_PIO_DATA (SPD_REGBASE + 0x2e) +#define SPD_PP_DOUT (1<<4) /* Data output, read port */ +#define SPD_PP_DIN (1<<5) /* Data input, write port */ +#define SPD_PP_SCLK (1<<6) /* Clock, write port */ +#define SPD_PP_CSEL (1<<7) /* Chip select, write port */ +/* Operation codes */ +#define SPD_PP_OP_READ 2 +#define SPD_PP_OP_WRITE 1 +#define SPD_PP_OP_EWEN 0 +#define SPD_PP_OP_EWDS 0 + +#define SPD_R_XFR_CTRL (SPD_REGBASE + 0x32) +#define SPD_R_IF_CTRL (SPD_REGBASE + 0x64) +#define SPD_IF_ATA_RESET 0x80 +#define SPD_IF_DMA_ENABLE 0x04 +#define SPD_R_PIO_MODE (SPD_REGBASE + 0x70) +#define SPD_R_MWDMA_MODE (SPD_REGBASE + 0x72) +#define SPD_R_UDMA_MODE (SPD_REGBASE + 0x74) + + +/* + * SMAP (PS2 Network Adapter) register definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2smap iop driver, modified by linuzappz * + */ + + +/* SMAP interrupt status bits (selected from the SPEED device). */ +#define SMAP_INTR_EMAC3 (1<<6) +#define SMAP_INTR_RXEND (1<<5) +#define SMAP_INTR_TXEND (1<<4) +#define SMAP_INTR_RXDNV (1<<3) /* descriptor not valid */ +#define SMAP_INTR_TXDNV (1<<2) /* descriptor not valid */ +#define SMAP_INTR_CLR_ALL (SMAP_INTR_RXEND|SMAP_INTR_TXEND|SMAP_INTR_RXDNV) +#define SMAP_INTR_ENA_ALL (SMAP_INTR_EMAC3|SMAP_INTR_CLR_ALL) +#define SMAP_INTR_BITMSK 0x7C + +/* SMAP Register Definitions. */ + +#define SMAP_REGBASE (SPD_REGBASE + 0x100) + +#define SMAP_R_BD_MODE (SMAP_REGBASE + 0x02) +#define SMAP_BD_SWAP (1<<0) + +#define SMAP_R_INTR_CLR (SMAP_REGBASE + 0x28) + +/* SMAP FIFO Registers. */ + +#define SMAP_R_TXFIFO_CTRL (SMAP_REGBASE + 0xf00) +#define SMAP_TXFIFO_RESET (1<<0) +#define SMAP_TXFIFO_DMAEN (1<<1) +#define SMAP_R_TXFIFO_WR_PTR (SMAP_REGBASE + 0xf04) +#define SMAP_R_TXFIFO_SIZE (SMAP_REGBASE + 0xf08) +#define SMAP_R_TXFIFO_FRAME_CNT (SMAP_REGBASE + 0xf0C) +#define SMAP_R_TXFIFO_FRAME_INC (SMAP_REGBASE + 0xf10) +#define SMAP_R_TXFIFO_DATA (SMAP_REGBASE + 0x1000) + +#define SMAP_R_RXFIFO_CTRL (SMAP_REGBASE + 0xf30) +#define SMAP_RXFIFO_RESET (1<<0) +#define SMAP_RXFIFO_DMAEN (1<<1) +#define SMAP_R_RXFIFO_RD_PTR (SMAP_REGBASE + 0xf34) +#define SMAP_R_RXFIFO_SIZE (SMAP_REGBASE + 0xf38) +#define SMAP_R_RXFIFO_FRAME_CNT (SMAP_REGBASE + 0xf3C) +#define SMAP_R_RXFIFO_FRAME_DEC (SMAP_REGBASE + 0xf40) +#define SMAP_R_RXFIFO_DATA (SMAP_REGBASE + 0x1100) + +#define SMAP_R_FIFO_ADDR (SMAP_REGBASE + 0x1200) +#define SMAP_FIFO_CMD_READ (1<<1) +#define SMAP_FIFO_DATA_SWAP (1<<0) +#define SMAP_R_FIFO_DATA (SMAP_REGBASE + 0x1208) + +/* EMAC3 Registers. */ + +#define SMAP_EMAC3_REGBASE (SMAP_REGBASE + 0x1f00) + +#define SMAP_R_EMAC3_MODE0_L (SMAP_EMAC3_REGBASE + 0x00) +#define SMAP_E3_RXMAC_IDLE (1<<(15+16)) +#define SMAP_E3_TXMAC_IDLE (1<<(14+16)) +#define SMAP_E3_SOFT_RESET (1<<(13+16)) +#define SMAP_E3_TXMAC_ENABLE (1<<(12+16)) +#define SMAP_E3_RXMAC_ENABLE (1<<(11+16)) +#define SMAP_E3_WAKEUP_ENABLE (1<<(10+16)) +#define SMAP_R_EMAC3_MODE0_H (SMAP_EMAC3_REGBASE + 0x02) + +#define SMAP_R_EMAC3_MODE1 (SMAP_EMAC3_REGBASE + 0x04) +#define SMAP_R_EMAC3_MODE1_L (SMAP_EMAC3_REGBASE + 0x04) +#define SMAP_R_EMAC3_MODE1_H (SMAP_EMAC3_REGBASE + 0x06) +#define SMAP_E3_FDX_ENABLE (1<<31) +#define SMAP_E3_INLPBK_ENABLE (1<<30) /* internal loop back */ +#define SMAP_E3_VLAN_ENABLE (1<<29) +#define SMAP_E3_FLOWCTRL_ENABLE (1<<28) /* integrated flow ctrl(pause frame) */ +#define SMAP_E3_ALLOW_PF (1<<27) /* allow pause frame */ +#define SMAP_E3_ALLOW_EXTMNGIF (1<<25) /* allow external management IF */ +#define SMAP_E3_IGNORE_SQE (1<<24) +#define SMAP_E3_MEDIA_FREQ_BITSFT (22) +#define SMAP_E3_MEDIA_10M (0<<22) +#define SMAP_E3_MEDIA_100M (1<<22) +#define SMAP_E3_MEDIA_1000M (2<<22) +#define SMAP_E3_MEDIA_MSK (3<<22) +#define SMAP_E3_RXFIFO_SIZE_BITSFT (20) +#define SMAP_E3_RXFIFO_512 (0<<20) +#define SMAP_E3_RXFIFO_1K (1<<20) +#define SMAP_E3_RXFIFO_2K (2<<20) +#define SMAP_E3_RXFIFO_4K (3<<20) +#define SMAP_E3_TXFIFO_SIZE_BITSFT (18) +#define SMAP_E3_TXFIFO_512 (0<<18) +#define SMAP_E3_TXFIFO_1K (1<<18) +#define SMAP_E3_TXFIFO_2K (2<<18) +#define SMAP_E3_TXREQ0_BITSFT (15) +#define SMAP_E3_TXREQ0_SINGLE (0<<15) +#define SMAP_E3_TXREQ0_MULTI (1<<15) +#define SMAP_E3_TXREQ0_DEPEND (2<<15) +#define SMAP_E3_TXREQ1_BITSFT (13) +#define SMAP_E3_TXREQ1_SINGLE (0<<13) +#define SMAP_E3_TXREQ1_MULTI (1<<13) +#define SMAP_E3_TXREQ1_DEPEND (2<<13) +#define SMAP_E3_JUMBO_ENABLE (1<<12) + +#define SMAP_R_EMAC3_TxMODE0_L (SMAP_EMAC3_REGBASE + 0x08) +#define SMAP_E3_TX_GNP_0 (1<<(15+16)) /* get new packet */ +#define SMAP_E3_TX_GNP_1 (1<<(14+16)) /* get new packet */ +#define SMAP_E3_TX_GNP_DEPEND (1<<(13+16)) /* get new packet */ +#define SMAP_E3_TX_FIRST_CHANNEL (1<<(12+16)) +#define SMAP_R_EMAC3_TxMODE0_H (SMAP_EMAC3_REGBASE + 0x0A) + +#define SMAP_R_EMAC3_TxMODE1_L (SMAP_EMAC3_REGBASE + 0x0C) +#define SMAP_R_EMAC3_TxMODE1_H (SMAP_EMAC3_REGBASE + 0x0E) +#define SMAP_E3_TX_LOW_REQ_MSK (0x1F) /* low priority request */ +#define SMAP_E3_TX_LOW_REQ_BITSFT (27) /* low priority request */ +#define SMAP_E3_TX_URG_REQ_MSK (0xFF) /* urgent priority request */ +#define SMAP_E3_TX_URG_REQ_BITSFT (16) /* urgent priority request */ + +#define SMAP_R_EMAC3_RxMODE (SMAP_EMAC3_REGBASE + 0x10) +#define SMAP_R_EMAC3_RxMODE_L (SMAP_EMAC3_REGBASE + 0x10) +#define SMAP_R_EMAC3_RxMODE_H (SMAP_EMAC3_REGBASE + 0x12) +#define SMAP_E3_RX_STRIP_PAD (1<<31) +#define SMAP_E3_RX_STRIP_FCS (1<<30) +#define SMAP_E3_RX_RX_RUNT_FRAME (1<<29) +#define SMAP_E3_RX_RX_FCS_ERR (1<<28) +#define SMAP_E3_RX_RX_TOO_LONG_ERR (1<<27) +#define SMAP_E3_RX_RX_IN_RANGE_ERR (1<<26) +#define SMAP_E3_RX_PROP_PF (1<<25) /* propagate pause frame */ +#define SMAP_E3_RX_PROMISC (1<<24) +#define SMAP_E3_RX_PROMISC_MCAST (1<<23) +#define SMAP_E3_RX_INDIVID_ADDR (1<<22) +#define SMAP_E3_RX_INDIVID_HASH (1<<21) +#define SMAP_E3_RX_BCAST (1<<20) +#define SMAP_E3_RX_MCAST (1<<19) + +#define SMAP_R_EMAC3_INTR_STAT (SMAP_EMAC3_REGBASE + 0x14) +#define SMAP_R_EMAC3_INTR_STAT_L (SMAP_EMAC3_REGBASE + 0x14) +#define SMAP_R_EMAC3_INTR_STAT_H (SMAP_EMAC3_REGBASE + 0x16) +#define SMAP_R_EMAC3_INTR_ENABLE (SMAP_EMAC3_REGBASE + 0x18) +#define SMAP_R_EMAC3_INTR_ENABLE_L (SMAP_EMAC3_REGBASE + 0x18) +#define SMAP_R_EMAC3_INTR_ENABLE_H (SMAP_EMAC3_REGBASE + 0x1A) +#define SMAP_E3_INTR_OVERRUN (1<<25) /* this bit does NOT WORKED */ +#define SMAP_E3_INTR_PF (1<<24) +#define SMAP_E3_INTR_BAD_FRAME (1<<23) +#define SMAP_E3_INTR_RUNT_FRAME (1<<22) +#define SMAP_E3_INTR_SHORT_EVENT (1<<21) +#define SMAP_E3_INTR_ALIGN_ERR (1<<20) +#define SMAP_E3_INTR_BAD_FCS (1<<19) +#define SMAP_E3_INTR_TOO_LONG (1<<18) +#define SMAP_E3_INTR_OUT_RANGE_ERR (1<<17) +#define SMAP_E3_INTR_IN_RANGE_ERR (1<<16) +#define SMAP_E3_INTR_DEAD_DEPEND (1<<9) +#define SMAP_E3_INTR_DEAD_0 (1<<8) +#define SMAP_E3_INTR_SQE_ERR_0 (1<<7) +#define SMAP_E3_INTR_TX_ERR_0 (1<<6) +#define SMAP_E3_INTR_DEAD_1 (1<<5) +#define SMAP_E3_INTR_SQE_ERR_1 (1<<4) +#define SMAP_E3_INTR_TX_ERR_1 (1<<3) +#define SMAP_E3_INTR_MMAOP_SUCCESS (1<<1) +#define SMAP_E3_INTR_MMAOP_FAIL (1<<0) +#define SMAP_E3_INTR_ALL \ + (SMAP_E3_INTR_OVERRUN|SMAP_E3_INTR_PF|SMAP_E3_INTR_BAD_FRAME| \ + SMAP_E3_INTR_RUNT_FRAME|SMAP_E3_INTR_SHORT_EVENT| \ + SMAP_E3_INTR_ALIGN_ERR|SMAP_E3_INTR_BAD_FCS| \ + SMAP_E3_INTR_TOO_LONG|SMAP_E3_INTR_OUT_RANGE_ERR| \ + SMAP_E3_INTR_IN_RANGE_ERR| \ + SMAP_E3_INTR_DEAD_DEPEND|SMAP_E3_INTR_DEAD_0| \ + SMAP_E3_INTR_SQE_ERR_0|SMAP_E3_INTR_TX_ERR_0| \ + SMAP_E3_INTR_DEAD_1|SMAP_E3_INTR_SQE_ERR_1| \ + SMAP_E3_INTR_TX_ERR_1| \ + SMAP_E3_INTR_MMAOP_SUCCESS|SMAP_E3_INTR_MMAOP_FAIL) +#define SMAP_E3_DEAD_ALL \ + (SMAP_E3_INTR_DEAD_DEPEND|SMAP_E3_INTR_DEAD_0| \ + SMAP_E3_INTR_DEAD_1) + +#define SMAP_R_EMAC3_ADDR_HI (SMAP_EMAC3_REGBASE + 0x1C) +#define SMAP_R_EMAC3_ADDR_LO (SMAP_EMAC3_REGBASE + 0x20) +#define SMAP_R_EMAC3_ADDR_HI_L (SMAP_EMAC3_REGBASE + 0x1C) +#define SMAP_R_EMAC3_ADDR_HI_H (SMAP_EMAC3_REGBASE + 0x1E) +#define SMAP_R_EMAC3_ADDR_LO_L (SMAP_EMAC3_REGBASE + 0x20) +#define SMAP_R_EMAC3_ADDR_LO_H (SMAP_EMAC3_REGBASE + 0x22) + +#define SMAP_R_EMAC3_VLAN_TPID (SMAP_EMAC3_REGBASE + 0x24) +#define SMAP_E3_VLAN_ID_MSK 0xFFFF + +#define SMAP_R_EMAC3_VLAN_TCI (SMAP_EMAC3_REGBASE + 0x28) +#define SMAP_E3_VLAN_TCITAG_MSK 0xFFFF + +#define SMAP_R_EMAC3_PAUSE_TIMER (SMAP_EMAC3_REGBASE + 0x2C) +#define SMAP_R_EMAC3_PAUSE_TIMER_L (SMAP_EMAC3_REGBASE + 0x2C) +#define SMAP_R_EMAC3_PAUSE_TIMER_H (SMAP_EMAC3_REGBASE + 0x2E) +#define SMAP_E3_PTIMER_MSK 0xFFFF + +#define SMAP_R_EMAC3_INDIVID_HASH1 (SMAP_EMAC3_REGBASE + 0x30) +#define SMAP_R_EMAC3_INDIVID_HASH2 (SMAP_EMAC3_REGBASE + 0x34) +#define SMAP_R_EMAC3_INDIVID_HASH3 (SMAP_EMAC3_REGBASE + 0x38) +#define SMAP_R_EMAC3_INDIVID_HASH4 (SMAP_EMAC3_REGBASE + 0x3C) +#define SMAP_R_EMAC3_GROUP_HASH1 (SMAP_EMAC3_REGBASE + 0x40) +#define SMAP_R_EMAC3_GROUP_HASH2 (SMAP_EMAC3_REGBASE + 0x44) +#define SMAP_R_EMAC3_GROUP_HASH3 (SMAP_EMAC3_REGBASE + 0x48) +#define SMAP_R_EMAC3_GROUP_HASH4 (SMAP_EMAC3_REGBASE + 0x4C) +#define SMAP_E3_HASH_MSK 0xFFFF + +#define SMAP_R_EMAC3_LAST_SA_HI (SMAP_EMAC3_REGBASE + 0x50) +#define SMAP_R_EMAC3_LAST_SA_LO (SMAP_EMAC3_REGBASE + 0x54) + +#define SMAP_R_EMAC3_INTER_FRAME_GAP (SMAP_EMAC3_REGBASE + 0x58) +#define SMAP_R_EMAC3_INTER_FRAME_GAP_L (SMAP_EMAC3_REGBASE + 0x58) +#define SMAP_R_EMAC3_INTER_FRAME_GAP_H (SMAP_EMAC3_REGBASE + 0x5A) +#define SMAP_E3_IFGAP_MSK 0x3F + + +#define SMAP_R_EMAC3_STA_CTRL_L (SMAP_EMAC3_REGBASE + 0x5C) +#define SMAP_R_EMAC3_STA_CTRL_H (SMAP_EMAC3_REGBASE + 0x5E) +#define SMAP_E3_PHY_DATA_MSK (0xFFFF) +#define SMAP_E3_PHY_DATA_BITSFT (16) +#define SMAP_E3_PHY_OP_COMP (1<<15) /* operation complete */ +#define SMAP_E3_PHY_ERR_READ (1<<14) +#define SMAP_E3_PHY_STA_CMD_BITSFT (12) +#define SMAP_E3_PHY_READ (1<<12) +#define SMAP_E3_PHY_WRITE (2<<12) +#define SMAP_E3_PHY_OPBCLCK_BITSFT (10) +#define SMAP_E3_PHY_50M (0<<10) +#define SMAP_E3_PHY_66M (1<<10) +#define SMAP_E3_PHY_83M (2<<10) +#define SMAP_E3_PHY_100M (3<<10) +#define SMAP_E3_PHY_ADDR_MSK (0x1F) +#define SMAP_E3_PHY_ADDR_BITSFT (5) +#define SMAP_E3_PHY_REG_ADDR_MSK (0x1F) + +#define SMAP_R_EMAC3_TX_THRESHOLD (SMAP_EMAC3_REGBASE + 0x60) +#define SMAP_R_EMAC3_TX_THRESHOLD_L (SMAP_EMAC3_REGBASE + 0x60) +#define SMAP_R_EMAC3_TX_THRESHOLD_H (SMAP_EMAC3_REGBASE + 0x62) +#define SMAP_E3_TX_THRESHLD_MSK (0x1F) +#define SMAP_E3_TX_THRESHLD_BITSFT (27) + +#define SMAP_R_EMAC3_RX_WATERMARK (SMAP_EMAC3_REGBASE + 0x64) +#define SMAP_R_EMAC3_RX_WATERMARK_L (SMAP_EMAC3_REGBASE + 0x64) +#define SMAP_R_EMAC3_RX_WATERMARK_H (SMAP_EMAC3_REGBASE + 0x66) +#define SMAP_E3_RX_LO_WATER_MSK (0x1FF) +#define SMAP_E3_RX_LO_WATER_BITSFT (23) +#define SMAP_E3_RX_HI_WATER_MSK (0x1FF) +#define SMAP_E3_RX_HI_WATER_BITSFT (7) + +#define SMAP_R_EMAC3_TX_OCTETS (SMAP_EMAC3_REGBASE + 0x68) +#define SMAP_R_EMAC3_RX_OCTETS (SMAP_EMAC3_REGBASE + 0x6C) +#define SMAP_EMAC3_REGEND (SMAP_EMAC3_REGBASE + 0x6C + 4) + +/* Buffer descriptors. */ + +typedef struct _smap_bd { + u16 ctrl_stat; + u16 reserved; /* must be zero */ + u16 length; /* number of bytes in pkt */ + u16 pointer; +} smap_bd_t; + +#define SMAP_BD_REGBASE (SMAP_REGBASE + 0x2f00) +#define SMAP_BD_TX_BASE (SMAP_BD_REGBASE + 0x0000) +#define SMAP_BD_RX_BASE (SMAP_BD_REGBASE + 0x0200) +#define SMAP_BD_SIZE 512 +#define SMAP_BD_MAX_ENTRY 64 + +#define SMAP_TX_BASE (SMAP_REGBASE + 0x1000) +#define SMAP_TX_BUFSIZE 4096 + +/* TX Control */ +#define SMAP_BD_TX_READY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_TX_GENFCS (1<<9) /* generate FCS */ +#define SMAP_BD_TX_GENPAD (1<<8) /* generate padding */ +#define SMAP_BD_TX_INSSA (1<<7) /* insert source address */ +#define SMAP_BD_TX_RPLSA (1<<6) /* replace source address */ +#define SMAP_BD_TX_INSVLAN (1<<5) /* insert VLAN Tag */ +#define SMAP_BD_TX_RPLVLAN (1<<4) /* replace VLAN Tag */ + +/* TX Status */ +#define SMAP_BD_TX_READY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_TX_BADFCS (1<<9) /* bad FCS */ +#define SMAP_BD_TX_BADPKT (1<<8) /* bad previous pkt in dependent mode */ +#define SMAP_BD_TX_LOSSCR (1<<7) /* loss of carrior sense */ +#define SMAP_BD_TX_EDEFER (1<<6) /* excessive deferal */ +#define SMAP_BD_TX_ECOLL (1<<5) /* excessive collision */ +#define SMAP_BD_TX_LCOLL (1<<4) /* late collision */ +#define SMAP_BD_TX_MCOLL (1<<3) /* multiple collision */ +#define SMAP_BD_TX_SCOLL (1<<2) /* single collision */ +#define SMAP_BD_TX_UNDERRUN (1<<1) /* underrun */ +#define SMAP_BD_TX_SQE (1<<0) /* SQE */ + +#define SMAP_BD_TX_ERROR (SMAP_BD_TX_LOSSCR|SMAP_BD_TX_EDEFER|SMAP_BD_TX_ECOLL| \ + SMAP_BD_TX_LCOLL|SMAP_BD_TX_UNDERRUN) + +/* RX Control */ +#define SMAP_BD_RX_EMPTY (1<<15) /* set:driver, clear:HW */ + +/* RX Status */ +#define SMAP_BD_RX_EMPTY (1<<15) /* set:driver, clear:HW */ +#define SMAP_BD_RX_OVERRUN (1<<9) /* overrun */ +#define SMAP_BD_RX_PFRM (1<<8) /* pause frame */ +#define SMAP_BD_RX_BADFRM (1<<7) /* bad frame */ +#define SMAP_BD_RX_RUNTFRM (1<<6) /* runt frame */ +#define SMAP_BD_RX_SHORTEVNT (1<<5) /* short event */ +#define SMAP_BD_RX_ALIGNERR (1<<4) /* alignment error */ +#define SMAP_BD_RX_BADFCS (1<<3) /* bad FCS */ +#define SMAP_BD_RX_FRMTOOLONG (1<<2) /* frame too long */ +#define SMAP_BD_RX_OUTRANGE (1<<1) /* out of range error */ +#define SMAP_BD_RX_INRANGE (1<<0) /* in range error */ + +#define SMAP_BD_RX_ERROR (SMAP_BD_RX_OVERRUN|SMAP_BD_RX_RUNTFRM|SMAP_BD_RX_SHORTEVNT| \ + SMAP_BD_RX_ALIGNERR|SMAP_BD_RX_BADFCS|SMAP_BD_RX_FRMTOOLONG| \ + SMAP_BD_RX_OUTRANGE|SMAP_BD_RX_INRANGE) + +/* PHY registers (National Semiconductor DP83846A). */ + +#define SMAP_NS_OUI 0x080017 +#define SMAP_DsPHYTER_ADDRESS 0x1 + +#define SMAP_DsPHYTER_BMCR 0x00 +#define SMAP_PHY_BMCR_RST (1<<15) /* ReSeT */ +#define SMAP_PHY_BMCR_LPBK (1<<14) /* LooPBacK */ +#define SMAP_PHY_BMCR_100M (1<<13) /* speed select, 1:100M, 0:10M */ +#define SMAP_PHY_BMCR_10M (0<<13) /* speed select, 1:100M, 0:10M */ +#define SMAP_PHY_BMCR_ANEN (1<<12) /* Auto-Negotiation ENable */ +#define SMAP_PHY_BMCR_PWDN (1<<11) /* PoWer DowN */ +#define SMAP_PHY_BMCR_ISOL (1<<10) /* ISOLate */ +#define SMAP_PHY_BMCR_RSAN (1<<9) /* ReStart Auto-Negotiation */ +#define SMAP_PHY_BMCR_DUPM (1<<8) /* DUPlex Mode, 1:FDX, 0:HDX */ +#define SMAP_PHY_BMCR_COLT (1<<7) /* COLlision Test */ + +#define SMAP_DsPHYTER_BMSR 0x01 +#define SMAP_PHY_BMSR_ANCP (1<<5) /* Auto-Negotiation ComPlete */ +#define SMAP_PHY_BMSR_LINK (1<<2) /* LINK status */ + +#define SMAP_DsPHYTER_PHYIDR1 0x02 +#define SMAP_PHY_IDR1_VAL (((SMAP_NS_OUI<<2)>>8)&0xffff) + +#define SMAP_DsPHYTER_PHYIDR2 0x03 +#define SMAP_PHY_IDR2_VMDL 0x2 /* Vendor MoDeL number */ +#define SMAP_PHY_IDR2_VAL \ + (((SMAP_NS_OUI<<10)&0xFC00)|((SMAP_PHY_IDR2_VMDL<<4)&0x3F0)) +#define SMAP_PHY_IDR2_MSK 0xFFF0 +#define SMAP_PHY_IDR2_REV_MSK 0x000F + +#define SMAP_DsPHYTER_ANAR 0x04 +#define SMAP_DsPHYTER_ANLPAR 0x05 +#define SMAP_DsPHYTER_ANLPARNP 0x05 +#define SMAP_DsPHYTER_ANER 0x06 +#define SMAP_DsPHYTER_ANNPTR 0x07 + +/* Extended registers. */ +#define SMAP_DsPHYTER_PHYSTS 0x10 +#define SMAP_PHY_STS_REL (1<<13) /* Receive Error Latch */ +#define SMAP_PHY_STS_POST (1<<12) /* POlarity STatus */ +#define SMAP_PHY_STS_FCSL (1<<11) /* False Carrier Sense Latch */ +#define SMAP_PHY_STS_SD (1<<10) /* 100BT unconditional Signal Detect */ +#define SMAP_PHY_STS_DSL (1<<9) /* 100BT DeScrambler Lock */ +#define SMAP_PHY_STS_PRCV (1<<8) /* Page ReCeiVed */ +#define SMAP_PHY_STS_RFLT (1<<6) /* Remote FauLT */ +#define SMAP_PHY_STS_JBDT (1<<5) /* JaBber DetecT */ +#define SMAP_PHY_STS_ANCP (1<<4) /* Auto-Negotiation ComPlete */ +#define SMAP_PHY_STS_LPBK (1<<3) /* LooPBacK status */ +#define SMAP_PHY_STS_DUPS (1<<2) /* DUPlex Status,1:FDX,0:HDX */ +#define SMAP_PHY_STS_FDX (1<<2) /* Full Duplex */ +#define SMAP_PHY_STS_HDX (0<<2) /* Half Duplex */ +#define SMAP_PHY_STS_SPDS (1<<1) /* SPeeD Status */ +#define SMAP_PHY_STS_10M (1<<1) /* 10Mbps */ +#define SMAP_PHY_STS_100M (0<<1) /* 100Mbps */ +#define SMAP_PHY_STS_LINK (1<<0) /* LINK status */ +#define SMAP_DsPHYTER_FCSCR 0x14 +#define SMAP_DsPHYTER_RECR 0x15 +#define SMAP_DsPHYTER_PCSR 0x16 +#define SMAP_DsPHYTER_PHYCTRL 0x19 +#define SMAP_DsPHYTER_10BTSCR 0x1A +#define SMAP_DsPHYTER_CDCTRL 0x1B + +/* + * ATA hardware types and definitions. + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2drv iop driver, modified by linuzappz * + */ + + +#define ATA_DEV9_HDD_BASE (SPD_REGBASE + 0x40) +/* AIF on T10Ks - Not supported yet. */ +#define ATA_AIF_HDD_BASE (SPD_REGBASE + 0x4000000 + 0x60) + +#define ATA_R_DATA (ATA_DEV9_HDD_BASE + 0x00) +#define ATA_R_ERROR (ATA_DEV9_HDD_BASE + 0x02) +#define ATA_R_NSECTOR (ATA_DEV9_HDD_BASE + 0x04) +#define ATA_R_SECTOR (ATA_DEV9_HDD_BASE + 0x06) +#define ATA_R_LCYL (ATA_DEV9_HDD_BASE + 0x08) +#define ATA_R_HCYL (ATA_DEV9_HDD_BASE + 0x0a) +#define ATA_R_SELECT (ATA_DEV9_HDD_BASE + 0x0c) +#define ATA_R_STATUS (ATA_DEV9_HDD_BASE + 0x0e) +#define ATA_R_CONTROL (ATA_DEV9_HDD_BASE + 0x1c) +#define ATA_DEV9_INT (0x01) +#define ATA_DEV9_INT_DMA (0x02) //not sure rly +#define ATA_DEV9_HDD_END (ATA_R_CONTROL+4) +/* + * NAND Flash via Dev9 driver definitions + * + * Copyright (c) 2003 Marcus R. Brown + * + * * code included from the ps2sdk iop driver * + */ + +#define FLASH_ID_64MBIT 0xe6 +#define FLASH_ID_128MBIT 0x73 +#define FLASH_ID_256MBIT 0x75 +#define FLASH_ID_512MBIT 0x76 +#define FLASH_ID_1024MBIT 0x79 + +/* SmartMedia commands. */ +#define SM_CMD_READ1 0x00 +#define SM_CMD_READ2 0x01 +#define SM_CMD_READ3 0x50 +#define SM_CMD_RESET 0xff +#define SM_CMD_WRITEDATA 0x80 +#define SM_CMD_PROGRAMPAGE 0x10 +#define SM_CMD_ERASEBLOCK 0x60 +#define SM_CMD_ERASECONFIRM 0xd0 +#define SM_CMD_GETSTATUS 0x70 +#define SM_CMD_READID 0x90 + +typedef struct { + u32 id; + u32 mbits; + u32 page_bytes; /* bytes/page */ + u32 block_pages; /* pages/block */ + u32 blocks; +} flash_info_t; + +/* +static flash_info_t devices[] = { + { FLASH_ID_64MBIT, 64, 528, 16, 1024 }, + { FLASH_ID_128MBIT, 128, 528, 32, 1024 }, + { FLASH_ID_256MBIT, 256, 528, 32, 2048 }, + { FLASH_ID_512MBIT, 512, 528, 32, 4096 }, + { FLASH_ID_1024MBIT, 1024, 528, 32, 8192 } +}; +#define NUM_DEVICES (sizeof(devices)/sizeof(flash_info_t)) +*/ + +// definitions added by Florin + +#define FLASH_REGBASE 0x10004800 + +#define FLASH_R_DATA (FLASH_REGBASE + 0x00) +#define FLASH_R_CMD (FLASH_REGBASE + 0x04) +#define FLASH_R_ADDR (FLASH_REGBASE + 0x08) +#define FLASH_R_CTRL (FLASH_REGBASE + 0x0C) +#define FLASH_PP_READY (1<<0) // r/w /BUSY +#define FLASH_PP_WRITE (1<<7) // -/w WRITE data +#define FLASH_PP_CSEL (1<<8) // -/w CS +#define FLASH_PP_READ (1<<11) // -/w READ data +#define FLASH_PP_NOECC (1<<12) // -/w ECC disabled +//#define FLASH_R_10 (FLASH_REGBASE + 0x10) +#define FLASH_R_ID (FLASH_REGBASE + 0x14) + +#define FLASH_REGSIZE 0x20 + +void CALLBACK FLASHinit(); +u32 CALLBACK FLASHread32(u32 addr, int size); +void CALLBACK FLASHwrite32(u32 addr, u32 value, int size); +void _DEV9irq(int cause, int cycles); + +int emu_printf(const char *fmt, ...); + +#pragma warning(error:4013) +#endif diff --git a/plugins/dev9/dev9ghzdrk/PS2Edefs.h b/plugins/dev9/dev9ghzdrk/PS2Edefs.h new file mode 100644 index 0000000000..a52d86afe8 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/PS2Edefs.h @@ -0,0 +1,684 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.5 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0005 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0003 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { // NOT bcd coded + u8 minute; + u8 second; + u8 frame; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usualy 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdLoc:track type +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetType CDVDgetType; +_CDVDgetTrayStatus CDVDgetTrayStatus; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/dev9/dev9ghzdrk/PS2Etypes.h b/plugins/dev9/dev9ghzdrk/PS2Etypes.h new file mode 100644 index 0000000000..443ad4599a --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/PS2Etypes.h @@ -0,0 +1,31 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__WIN32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#elif defined(__LINUX__) + +typedef char s8; +typedef short s16; +typedef long s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/dev9/dev9ghzdrk/Win32/Config.cpp b/plugins/dev9/dev9ghzdrk/Win32/Config.cpp new file mode 100644 index 0000000000..1bc2dba17f --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/Config.cpp @@ -0,0 +1,55 @@ +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE +#include + +#include +#include "DEV9.h" + +#define GetKeyV(name, var, s, t) \ + size = s; type = t; \ + RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); + +#define GetKeyVdw(name, var) \ + GetKeyV(name, var, 4, REG_DWORD); + +#define SetKeyV(name, var, s, t) \ + RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); + +#define SetKeyVdw(name, var) \ + SetKeyV(name, var, 4, REG_DWORD); + +void SaveConf() { + HKEY myKey; + DWORD myDisp; + + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\DEV9\\DEV9linuz", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); + SetKeyV("Eth", config.Eth, strlen(config.Eth), REG_SZ); + SetKeyV("Hdd", config.Hdd, strlen(config.Hdd), REG_SZ); + SetKeyVdw("HddSize", &config.HddSize); + SetKeyVdw("ethEnable", &config.ethEnable); + SetKeyVdw("hddEnable", &config.hddEnable); + + RegCloseKey(myKey); +} + +void LoadConf() { + HKEY myKey; + DWORD type, size; + + memset(&config, 0, sizeof(config)); + strcpy(config.Hdd, HDD_DEF); + config.HddSize=8*1024; + strcpy(config.Eth, ETH_DEF); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\DEV9\\DEV9linuz", 0, KEY_ALL_ACCESS, &myKey)!=ERROR_SUCCESS) { + SaveConf(); return; + } + GetKeyV("Eth", config.Eth, sizeof(config.Eth), REG_SZ); + GetKeyV("Hdd", config.Hdd, sizeof(config.Hdd), REG_SZ); + GetKeyVdw("HddSize", &config.HddSize); + GetKeyVdw("ethEnable", &config.ethEnable); + GetKeyVdw("hddEnable", &config.hddEnable); + + RegCloseKey(myKey); +} + diff --git a/plugins/dev9/dev9ghzdrk/Win32/Config.h b/plugins/dev9/dev9ghzdrk/Win32/Config.h new file mode 100644 index 0000000000..62939290df --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/Config.h @@ -0,0 +1,2 @@ +void SaveConf(); +void LoadConf(); diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.aps b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.aps new file mode 100644 index 0000000000000000000000000000000000000000..f4ab3fd519d4311d26996292d23b2f0445a9116a GIT binary patch literal 35628 zcmd6QdAy`oS>}5?35g*jfXJ%Q2`K4E!u@Kww~B2#7N zp_A!OXB%b=2#k*4jLPWmr_PLGWM&X`1Z9`SWem82vdSu=;4&-$M1|>j-uImIo%fvY z)D1fS%*`+NR-NZL`~IGDo+cvNi~rA_HUHyd@N+f3Jq`bF(n0Fr@7c2}7QgT!`+*+$ zLqs<|>&WET>AP!3Zol=+O(#y?aQx0A_`iMA&G+7L>Xs`{-gfkkqel*&I9ab9=@kds zx1Kn8=H9DL9V2?hb#eF)NU*DP;WJ$Lm&%7r>D2Mlx1Bk4?D$nT6B04#^%mXnsNWlI zP_~-UdERMYTpngz^3HgB4oaQQXNT@$ly4RIzPd^m7>Dk7t255nX`Q~wI2H3vB-A)v zXq-Cv&U|MgK3nwgl2(lJ&amh)wM{4!j$yOc>ko!Z%~t6VrJJW_8C^`Y$S1SKs5mrV zOpDogd)h4)2lC-I`)kr;G>#N*<)fa38%TRb-x3l=^XYh4`bPwh)%a{@t8m`Av>r#~ ziuLG?ccWybP**OcyH1=m-}cbTf!X3fF`W&@qs3sn49?~@d))~*|<1K(K0iPX!`Dh17Uyy4p(iu;C#ndGP6@(zK3o(h5@o6ZCPMrI+#pQ`Rsu!jI%qo*myc9M)Sqy zczT#FSFHjC{sQ&Yl;b{nZs-k7Y94sw#-#m86Qo^AK-Qbs6n?z(6r#@3aClX zkD&eeC^y&|ofK?VO!6tGpH}I1TFLu|7K0v!q{(D4AIvdOBP7o4D?K*o4U4T}Hp@3G zn$i6p-7JQat#L18)aX^7QHH%JwmL5<=kN|Dj zbmvp{ZRt6rBl!!CqP>~eR@v_4s%z-eR{7zMQ<=)bcaPQV^daJrT0bdSnHV9 zRLki73PT%|GO5+*1IihzQ!c4moj&MY`xsb_bAvwQohL|+X^pieeK>Mo3*bm$Y_ zd0IH)M6id(Dt)1JE)H38Bcm^hE6)r(DHeyM z1R6DZ(7SV`%F+nI)agqe*q+(>A!{_~%i@l`&78Le9H0rRNna^_7?(Brs<`xuevU<< z;;z#_2qL=+OfjaQnyd6Rapqxk;hi)3x;Xd8(=9A8`-oa1SX;%)o@eNzh$H@Th{1F$&W8Yanyg^bA*Gum`MC~O1` zI=>_!;Eo@PYZ!PgSg~{b!p;}yuXf_ABi$EQV60DgM&roqNc<&Lf?fF3k@!beP>#j; zt<$3tD5gULH|Wt7`0#kVHIRJQF^zt666YPPq-~8JBl+e@aKXEWjv0np$kyXL!W*>h z*`fq9db|gxMd{w4CwTXKdp=fOu7%V*(WA31jB2iiS}5di_1G|A2Wt;(4}D{5qgbD=5jP#Q(Mm4Y0CzO5qBa`HJ`K3G(MF@bf`M@R zTyv?LEoNQbjBy~?Bhu9x*czMlSs&3}69Am;(pQb19e|wG60Fm;8sr3<@z=!IpzqQ! zCtJf!x=zDof9kKUQLYh~GO*A#*+7+dG&av?`-iqY^ik_w4{l+Hu{jvZoY&9#RCuUY z%=YKqE*9hCsZ5~#UQQbx=e4ewTg+CUp5q~2`*|p%{T@PV1~Ql780B4~p~tpIvMu1m z0IJiLhg^ufpfqrUMjnpG8+dQh*yGzHZo}NdWY+u~N8e`49J(-NBb3{-a>K2nZOgDy^(Y9xn)~1M5qXV9_RcxWS z<8bP9&{MWCA;g3R9rA?12=*-WNDL1#uSq+eH{lJ#c*IGUU8| zzsDo=zBdPAu?ump72AK>w3oz*7LQb-LYSvSs7!8LUO8JZAQJl6ix+>9j}1XFgMKPIpAG-3uyC zht7Boujv%lr8_+)kz=X0;BvPq@6lbJu!U)jYYl5CUP_r17Icqi^afb0D6miWdayH? zZ{-t>w^!+3dt8=S#!{@pXlL{S&k=h=5JZjsjfZ6i!Qm7=F=un>w;S~Rp0PdJKN=q# zd9+FQd2~AO2Z68A3q2?+R-LkSdXY!naM0bJPK#03jGyfmy|_x@z5IM2vptg6rk5DHBeUenb(<^kRL7rML`o zhPOulA;lZ!+oSHL+ZP~R>+~Nz42NyoaFz=4Q;AQUE5$J^G1|(E$NN8Xs2} zMnOO68886Ocn>38lFcNc%)LJygYdX;n^7=o^fNJoy=zLH{&P&3%`wky zEbJ-|!8GW<#GGl~8;lp7ZJcVDY+$MTUt>~dM~nanVU2z^2Di&huG7!Opzc>$)}mL& z1l>2YtW7^36E?O7vM$Q9obHc7*JZP;L%$G%);@<+cj;9gv<;~2ujSatrj`G(lsC!e zn^Ijcvb?&&>J88%``coN>1Qyw{9=V-mXtVp%T0b@e|gO^(!nVPd=p!PeyPGjjhXeC z53EVQyquj3 z+?F~9Eo{0+#^l=1S{c2;bFjQaheBhV$xxlOYV<~r+Wsa>hzyH_H#x{GMKQ+d$Q$%# zhhuQn;L2YnlQlire|m@&*`VU6DEDR$5;4ZleKI{k*neJq;NqPL|e7@n{(F}s1R z)uy+nNWAz#gVD^K-jQN@dk0e0p?7-DMgbd&UaFg%b?G-f2d48Br$@i#IX3rb4BdQc zT5zkN-}VHbeKYHrc>44^6$+Ld0~uh2f)&RDp5nTta4--XN=EPU6dRE+X0WCkN{!yF zC_J@|+~}XL((gwY7V5=RP9XbPp3xsfFc(;V47;L)o!96OBLX+Zazx1M^hXiS(<;`e zJ2KOoKpOPN5y_4Sy<#+w6Hg?iN$-hBu0Y({Jj>VUy%A@My%Qfg$U4W&IQcsLNyNfY zhaaNy7X4|2bDm~J!4_Slq)qRO@J-bFVj!#WEYIov5j+EKtcvj6p$|kb=IQ+<+@%jj zFb|;R_=yqnLlIt#`zBoleb__!6vI+k&z)8JNQCKn?qu}Q2N z_)G1FI=M zVKtN{{e4K0I}j5LD%0^n9OU-sd!b=3#qJIo& zzI=3Ztzpvmr;y0yjkxFIxmj7(S~-0!q>Ou=ZoIawVZ!)&NaG6{$w{Hs>eBxSxw8=t z;x{p1R%V%6t4C);GLQV2t7OYIlItO;yn<+tHK3bDV;fG$>eEWdLRPWF%h77=KwZOB zvM1!Ad>3{HUriqNvFC(zDV_s0RNHg6aWHHuu3e*ZLmFb9jAsKjreHs3!j~RgYuD+# zkjvwqw5&w=U?2RjkS!USPqB-_zRgD8r1L`(XR2Sg_S{~h3qpJ_LZd^gnJ+j$()ilA zX%>=fsq}ELh8?1rQw_C67lu@OU56VrOroiLwCUlY7t{TMX|#s@@k$haRyT+g)zsF{Rz5iye2iFj=yN*P}-{WP;{`h4W|w27m0#P<=2K9>%RAv-7E8 z`gmN(?cw4^2gA1{2-C;oL)hBIIG6VRL%)Ve140t%@&*UxxZf0uk|we_6X#$!P*vUy&8Q-1oQmQ4Zn~B z6ogQxr$-blNH@dI(QDA<5eeP4gWHnE3RmkjXFzWzx=z=7lnvlw zER}4u=$MCi`DiLzur}S`G1=-OFs#UqdsmZgbp*|f8r|d>CI{vYFNcad2RD0E)<`{! zZeuCcdV_9pU{~q_gMb|K*H_!?>vWq3xAG0##@j)V?e!Mj?g2U8#9=MktblF$S03Dy zOALI-3xC-5pYqUw0LtjJheqQb4%xfYnekSmJ3Ka@qT!9uKP1FDor$4hc2J-O-5EoY zKpYC(6#)lLU~6=D1T+rjl4I=V@9_}ts7j{ zNR8Zhyf1|!T!0z9Fa>TN5VS@wN}(p)I{iQjUt$Smji*3NKi^xr&!^$8Y+9bDepPcU|`(yL?a;3iu% zfo1fIF~$pRAT@eTjBHE`EF*x`>6c=xBQF>Dp6D;f&`yD4frIR?Nxu?<7~`;F$QfOu z{~4p*9h~j}TBl!)p^YiV2|z7+Z4BY9!RFlIZF*gd_prz{xkLm0wG`@diYEN)Dct53 zt@!mZERpjJ!wJVNhd0Coj@{=PrvPtEF>KCZ|9?{ioA$`Y|2KPNwgdC!mQ*}iSC*~Q zTRg}uJgx%LRx2EEg{!tjRB`6!*u0Jvja zuhp9C^t%aMOd1Tg=z#=0v58?uo8ILZodq^vg&arLYxP!xe$OGWvAC%1p(U>;3uN&< zo?`j}Un1d4_kuU*y)lk8*TFG%J`?ju0)aH?Ph!%+QIA((8)gSmpuPTSg5uWn1sd)9 zVw_L4&Gjop(W3XKa34UMJ`fY+_}<>&LJ&E9FlG!!5vM~RiaCbiBkIzJV~PvLlX~=L zG0DaxZ)!~07W9#rmerv0SA>Ip*{k?>vAd%2?S8oX~yN1I*W8m;Ty= zW}fkB=+WPJkWZtAIR+m&+jK_DA}i=`myygc!95Wdz5Z?)%Z&!i!%5)(_B@MVA#V?C z3T#w97vk8&V2>#m8Kih{1o-(X!)tP^ zVX!gSo9zmiq0jdm7`Tj4yAQ($TexscAZKX>4#O_gJZy8OcwA=&C>(`7JOFV3**8}$ zBq2BnyGY}`!GQr^favTTE~auaRNye|5t@P}=D2TqtDo%h23?#WVXjl0CS9UAFi-JT znwJ&hDX!Ud%;9N)^RP#1o{+}#(kfiwDC|+1U;}d2{sKo~kJdN`kPo?dcgkACao9I& z4j$_cy2W5zny3n#h&@I#R4BONHJh6`1P5c^qFG3bG4CT|8|H#Rk$35_nxl`#`0~Kx zG*||pOQfL3M;upjrWX731dXGu@mVEvOe$dseWE6q+(zcd0tV41X%_kg4qCW5_!G?n z_Rw$DB+d*>cT&2N7??x9O%wQ3Rmx6o;QI1~QS`|%4*~gVhBfplnqUu35gy+Pyk-(6{eGHd*e{cWBP2D0(iDaojz6x~7`ArEXD>X2j|g zbh+l>j=?VJ>(jnn$dW#sS6-nxE^R>tcQg7BwQd2&iKCz4Hcl}!L7xWw1npW& zy4FkArWmQ6(g9=*{)I9N>v$G1#-nZ)C&+QkH>5qHQ{W^GK7WpSmT>lL<%?BA_*|6+ z#2x&6p^93a023la5gheFp*od>FP_8Y!g;MDRWN^xV8g#KtIttcHP324vrD=-V(bi| zOdy9ne7CJ&Q_HNZ0%qXL{gwKDCR~VCAL(^4ZiJx05t`63I!$*|4WDnPTj>nlgy+yF z=>|GZcf!s5ZNv3ux)@G}1d{4$qAx)HJLr2}v~jZlxm$6h>r zzXP9dfZJ{O)#t|@1;xFfl^TFtih{>e#|F^W=C8^bEBcwU* zw^y#XdfdYw@S}Su`mO$o4y(VSr&hXX+>VzwuLrJ)({fcMEnnvIApLwD4C%{Q=k7s= zJ{SL=M^&K?q1nD(qm>n*4tnTXZ1=@CgfcDWcu&(XU(f~k)lSoV+d&UlGapA|S~s7} zo1d2XBIgxt{%n@x;c1(MAL_H9VAVjzc1L*T3^@PlSPtI3HcBjAf`FVCv-dD(b~Z|{ z_9DTbrvfUUy_jVH8zWU%)q_5jHv`%!NepRhFRK#tL0=VB2Yr%SEk$Efi`q`=FsQ&n zi*y8V+N?!7LbOFXhP*{uA(2H|A(2H|A(2HI2+t*2Uq_ljccJxlB{n>zuwP@rVZQcjpLT5^z?!qq`$3U+o4bC6jwDhHWB^m?SK z@mDTL5@JO;gl&iJs z;>=H$3XWWA4DeM1MYpdkLAM(j6Sh3h%-LWH#O`VgB4^XEn|ZM+6`EPvE7b0LtXF=S zZi2MCAmtv3RaFADVgSawOg%1Z<%1+7HIMU#^>QFqrNZUsHGx=_!YX1_3af}!RWK!1 zmB31|ssvV-{Nb=Qfi(;k)RRfeuqef<68=iDssvVwRVA=etSW)EOBkEkFaYDuYzSs=Tun zt1_-UGvMaE601_~p;(my0UY9B7pFm$38IW!rb7cuV~dg&id9vk zW?YF?fqOw7>I2t_k`G%LcMww63Jp)3af~1Y0NypgBLd)OWGr`t-ym8+fqO%wq*cwGLD(k zs$Q}>R)Dzqht;tHz}h859V-A_V`OzK0H(FYQdj|?rLaN(SBSmZm1_AM+*Txo75L=T zX{{^O@Yye?QNz+?d`ipS%2HTCxRDfAfW=Z+3XG+&6vVd}D^ger=an=sw9&R9Eu{tz zg zMls7Xfj~=P6}QC{X_*w3qF^hWkit>~_iQ{Vg{62h{)SRm3XP<&6cR~cDMUi#Esz;S zMG7l`rJ9(4)>TSj1q|$gs!~`>7}E3_K~Inrpjq16daIDaiao1~ZmW>Ois4WSOQFVE zCyxfS6qaJhoXxYYBn+>e6(+Y=V<{|!8%v*CsfrYqLbVi@at@`i6c9>bDWD>Sr7+pm zYAGy**(akORpw38;URgfq^x8EQx04h58O^uaXPwuDpFW+tU63y!ch98xFMG4&G{|C@h=f zE*G&BRw5Kf!DYQt3ag|om%>sMtKpH5!b*~)RhBANYOsV-ZdD2^8AMeIOVij`gljmV z6qY8G3Ni^PtRycXg{62H;gV8Vin2rsOEGLArlhbGt15+60Xd*jk4yHSrq|-dbXp2a zg}@A4LX4%b6r&=ARl#r@u$028fG8@ha}`v+37WlYidx#?POb=Xnd^Un6jmjoloVEl zq@}Pbpq9d_fUeWd*!DK>9VO4y)F3VC_6_DdL@dmYP8;~0u{OEy0 zM;%DSD}`_L+NM-l;v1e`XGX7VN=iZsOC{OHW=TrBO0AR2ppsHp)xb)c3QnyVAUlze z!cxIlm>(acrLZ(NC55GMo4=|Qmf|F&uoPTd0MSVVZ|id+5N?Fmcoiju0Y(5lclg?PFe~pX2nuiG0u6?Qdlt_NnyosB!v~j zkrY-8>-+v$9<)3;)KXGd%4v^Rpqg^M5L@0Oc*Q*<;zDm zSC+zx!b?eEMU-VySP^YkDXfUQyA)PLULu7Rv6e|;IoqXaT1hFaC?u5cu2NVLeVG(i zMB7ygE8;$c6jsE>nlZQdkk5mcoiiyGdb1)Ne!zEAp~L3M*nggcR1U zZ1>Co8w-}gD!COYtP=SKq_84xEQJ-p)-J}21@~r-rLZCvY70YbAcYk%Fh|5vSP=u) zMIrqcy+vawtdf_K!ivF23M+VJ#yCQdo+_N0M?4M!$(Rr!>wWXzu;;34_u}P(c_xrIS!0Rdo_l z6tleYQC8n6^ccqfe_d}O;$=-g512IhbVa^nyOAhh2nzosZmSB zC^dmj!qSjJorDT4)=8)ksyYc3N~DvJ!b6>e6r;>BbP`f{BybQ63AVK*bP_5dMZqK* zOUdvlQcIN?hK@idLB*hT5|p!+LI_$#RVP9Ds_G;tkWCe7orI+%DI@72=01<>sbNs= zvLW{*Z6;y?T6zBNPhMCjLB+;+LMI`?&^ieTIMhi<5ZqaSWCj9n35wQ9P_StyrO-i8 zttA$!6a<4otdpREc2MX$sBT+=S|>pTpwKXkU;wbJgieAADyfsO1TS?G6fW0F_^3-t z7&-|t7TifOIthNsYLgi2B$QzUN(x#hp~~Pbo7PFFGI*z8>?D#_=p-o4t~v<;FV;y2 z!KzL|fTwj50?IO-gcK>(NeDPtyReynACJU32?0+?`T;$35(0t^Nb4j7I0ul>NeDPe zorHj)LJ4&e0v6I@_I{yGLcq~>6V^!xz%qbPCn4szl9Q&A%dJLdgO>xMicUfhz*3!r zfVE5~As}&Pu&(3AE9&G$C$Oxs{@_xbgdia1A)r7fAs|?*8hBNmgcPx&laL~DIr`&- z0y+sPmK`KQorK+pu~vavWla|H4+JBt%XJchpkZavWT|neB?p|{brJ%q39h1(5O5w! zCt)|Tqz^g?0ml_!P{Ghi2uQYqm*^ySg3KqnyxW4TU3KwGYp5YTqf zNdQkN2V99<@4?&TbD=eG9z7f{85;P1P6Zvp?*WbQx}5)U^&VUZkL=+aKUzQG)bZ1| zojG;v_*HoF{#anU`!}z*wg0D{IC<>WGdCRHd)d(&??zx(-F(?2E<`xzJY-nR2-CtI z--;;q!u{;o^YA~vB$xO9&yWxJwPK_KI+h@W6??jBO&%lZg zTn_i(JO8~M{M)27Pa#$Jz~ux~7g#~!IQ||7{|@}V0X3n2kT<0D2FcrlOY_z*>*hXs z;h}A$=k0V6eNp%?l;9p4wC$V34cZpzwtc|^_nj+@U!~{CU+%-EMdT<`R;#!J?$WAP zzL8cf@3tp7MuXkk^`6PqDD5i{@@FLNx-D`^yYf9Hsq(+}puIerUXC{7+T&QbMw!EC zVC0hOo00lcD4%Dct$Y*8p7k!yK&Rs;oG$m z$_(gH)X{Bpm-s)ezF&t>onFXQh>P38wUTfyLHEPy$3IF&Pb$;T?eK1C4|@?dtBbhy z!mWtg7`t4Lc4TtGIlT!??t>;5+T|47(kbCmFd8KO=%aBCwxZDC} z7}Ym0uJhR5$EZa3wvBI$4aJo?=0}gyW{fgpDz`Xpba={-yt3O(#BN8dTYsbnfTl^ZmvdF?)CBo3WTE<{z{CuOhss;qxX`SUUK7_AIB){J2k7<7*H9 zdyY*6c`cY%TxZhYIS)u6I^V1zbR^f|yt~4=ADm%VbE>*CJbpd~8TD~hHBDG+ + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.opt b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.opt new file mode 100644 index 0000000000000000000000000000000000000000..5d2d83220c88c95ab9bfcbb36863f7a8b8211ede GIT binary patch literal 48640 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 + +
+

Build Log

+

+--------------------Configuration: DEV9linuz - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\Florin\LOCALS~1\Temp\RSP5C7.tmp" with contents +[ +/nologo /ML /W3 /GX /O2 /I "../" /I "./" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEV9linuz_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=2 /Fo"Release/" /Fd"Release/" /FD /c +"D:\Temporar\Npcsx2\plugins\dev9\DEV9linuz\flash.c" +] +Creating command line "snCl.exe @C:\DOCUME~1\Florin\LOCALS~1\Temp\RSP5C7.tmp" +Creating temporary file "C:\DOCUME~1\Florin\LOCALS~1\Temp\RSP5C8.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib packet.lib /nologo /dll /incremental:no /pdb:"Release/DEV9linuz.pdb" /machine:I386 /nodefaultlib:"msvcrt.lib" /def:".\DEV9linuz.def" /out:"Release/DEV9linuz.dll" /implib:"Release/DEV9linuz.lib" +.\Release\Config.obj +.\Release\DEV9.obj +.\Release\socks.obj +.\Release\Win32.obj +.\Release\Dev9linuz.res +.\Release\flash.obj +] +Creating command line "snLink.exe @C:\DOCUME~1\Florin\LOCALS~1\Temp\RSP5C8.tmp" +

Output Window

+Compiling... +snCL -- Detected win32 build...passing to cl.exe +flash.c + +NOTE: WINVER has been defined as 0x0500 or greater which enables +Windows NT 5.0 and Windows 98 features. When these headers were released, +Windows NT 5.0 beta 1 and Windows 98 beta 2.1 were the current versions. + +For this release when WINVER is defined as 0x0500 or greater, you can only +build beta or test applications. To build a retail application, +set WINVER to 0x0400 or visit http://www.microsoft.com/msdn/sdk +to see if retail Windows NT 5.0 or Windows 98 headers are available. + +See the SDK release notes for more information. + +Linking... +snCL -- Detected win32 build...passing to link.exe +snMonitor already running. + Creating library Release/DEV9linuz.lib and object Release/DEV9linuz.exp + + + +

Results

+DEV9linuz.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.rc b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.rc new file mode 100644 index 0000000000..2013fd27cf --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.rc @@ -0,0 +1,126 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 290, 170 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "HDD Configure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,115,150,50,14 + PUSHBUTTON "Cancel",IDCANCEL,233,150,50,14 + COMBOBOX IDC_BAYTYPE,60,10,223,47,CBS_DROPDOWNLIST | CBS_SORT | WS_DISABLED + LTEXT "DEV9 Type",IDC_STATIC,15,10,41,11,SS_CENTERIMAGE + LTEXT "Ethernet Device",IDC_STATIC,15,60,60,10,SS_CENTERIMAGE + COMBOBOX IDC_ETHDEV,83,60,193,82,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Ethernet",IDC_STATIC,7,30,276,50 + CONTROL "Enabled",IDC_ETHENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,45,42,10 + LTEXT "HDD File",IDC_STATIC,15,115,60,10,SS_CENTERIMAGE | WS_DISABLED + GROUPBOX "Hard Disk Drive (not yet properly implemented)",IDC_STATIC,7,90,276,50 + CONTROL "Enabled",IDC_HDDENABLED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,100,42,10 + EDITTEXT IDC_HDDFILE,85,115,191,12,ES_AUTOHSCROLL | WS_DISABLED +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "DEV9 About" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "DEV9 Driver",IDC_NAME,59,7,42,8 + LTEXT "Original Authors:\n\tlinuzappz \n\tShadow ",IDC_STATIC,7,18,141,30 + LTEXT "Fixed and improved by:\n\tgigahez \n\tdrk||Raziel",IDC_STATIC,7,49,155,27 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 283 + TOPMARGIN, 7 + BOTTOMMARGIN, 164 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.sln b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.sln new file mode 100644 index 0000000000..c2c0e89fa1 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DEV9linuz", "DEV9linuz.vcproj", "{BBE4E5FB-530A-4D18-A633-35AF0577B7F3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Debug|Win32.ActiveCfg = Debug|Win32 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Debug|Win32.Build.0 = Debug|Win32 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release|Win32.ActiveCfg = Release|Win32 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.vcproj b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.vcproj new file mode 100644 index 0000000000..997fcbf3ff --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz.vcproj @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.sln b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.sln new file mode 100644 index 0000000000..193cb1d56f --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DEV9linuz", "DEV9linuz_vs2005_x64.vcproj", "{BBE4E5FB-530A-4D18-A633-35AF0577B7F3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Debug|x64.ActiveCfg = Release|x64 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Debug|x64.Build.0 = Release|x64 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release|x64.ActiveCfg = Release|x64 + {BBE4E5FB-530A-4D18-A633-35AF0577B7F3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.vcproj b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.vcproj new file mode 100644 index 0000000000..4fffe9544b --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/DEV9linuz_vs2005_x64.vcproj @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/dev9ghzdrk/Win32/Devioctl.h b/plugins/dev9/dev9ghzdrk/Win32/Devioctl.h new file mode 100644 index 0000000000..af8784bfd3 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/Devioctl.h @@ -0,0 +1,90 @@ +/*++ BUILD Version: 0004 // Increment this if a change has global effects + Copyright (c) 1992-1993 Microsoft Corporation + Module Name: + devioctl.h + Revision History: + -- */ +// begin_winioctl +#ifndef _DEVIOCTL_ +#define _DEVIOCTL_ +// begin_ntddk begin_nthal begin_ntifs +// +// Define the various device type values. Note that values used by Microsoft +// Corporation are in the range 0-32767, and 32768-65535 are reserved for use +// by customers. +// +#define DEVICE_TYPE ULONG +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) +// +// Define the method codes for how buffers are passed for I/O and FS controls +// +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe +#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe +// end_ntddk end_nthal end_ntifs +#endif // _DEVIOCTL_ +// end_winioctl diff --git a/plugins/dev9/dev9ghzdrk/Win32/Makefile b/plugins/dev9/dev9ghzdrk/Win32/Makefile new file mode 100644 index 0000000000..accfa99154 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/Makefile @@ -0,0 +1,52 @@ +# +# Makefile for MINGW32 +# + + +all: dev9linuz + +PLUGIN = DEV9linuz.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lPacket +RESOBJ = dev9linuz.o + +OBJS = ../DEV9.o +OBJS+= socks.o Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +dev9linuz: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} +# ${STRIP} ${PLUGIN} + +.PHONY: clean dev9linuz + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: DEV9linuz.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/dev9/dev9ghzdrk/Win32/Packet.lib b/plugins/dev9/dev9ghzdrk/Win32/Packet.lib new file mode 100644 index 0000000000000000000000000000000000000000..253d81f07f12821a08e74e5271c5d2c00170f722 GIT binary patch literal 8180 zcmcgxOLG%P5N_Fk!C)}*`z7Zs`l=7e>2}adb(%Evp34E?T26V zex6c)^K(l}bD5=u`Rl5F&ikBS%y_R`y#VkfKwkr(e-Gf|3xLt*Tt@B#Fd5wEGBygp zWPHn$*Z4$9zUMOX67eVlZ@7#-MLf!Y&1Lc}0F%KSm$7$fN0~rAS8m`FWd=Ez3_tM% z%M7CoJ>xQscqUV?xJ)nNH_A|&%M`Ym$#9a(47P#EjC%H;Z@kCA+-+z2!iul)IPB2JP@O2XJ%o>wCF7rPY<<3Y0e8g4ybWR=M@)8>`i> zHXB$?wQiR}Y`nx*mSaRyy+E$Es(V%|46j*vsk^q-SgDk4$7-p~Q4Abguo@Nqrb4M+ zN4CSDXyDkDTCKTVb}UoPx{YJj8&$`Irh0C_-Lj1JQawlJt!)bj&s42u;*eXlX4^6j zoND3dg5`Yu+pT}wsyh0lAdpySYu6h)O+(MHy}m`%y-{rx zo41+W_?)Ovl?3OaMXy!tJ`VXeCca76TN7~>Tca;Zl^&lM;a7twpy?1 zQ;bb!Xy3%~>usi6YgDX?S~oQuK3gq{Y&8o2jXr=qjNdOV0zAh&aeoA0e-LB&7{Jyz zz-yHE82ewM{>=cuQ`Fn|d^-t{L)<(3em((k17μK?xBP@WB;ej4D_6u=@r)A)TK z-;-#2inzyEz8~c}a$?GaUN{fupdU`b1dPBG48bs*gtIUUC!h!V;3AxcGcW*2NWlzT zfJqpGaTtX`n1%#&byU9FUoYm^X^Kw4Xc!V^P;E>is1LX_*YV}bT>v!!=R{p-I1r^o zLi1dSgnxr`ah0BFxz>=>jL|(1I%VSH70Hw*@))}PO(jlhfi<`$yoJKon_n+U6hak< z04yrF@k&4f0SF=HK&OT20to}b4b2BPJW9sVU5;iW)$yo>x*ye}Z$u_S%@wtx#36$g zV-_LKsg;PxV}|H1+?Ccs_a=%yEH3H}ObaP)Obwbdt0u!1LAtRTl%-xv-@cR6nwieD zv7ipG;hD*pW_>851{I4jNop6q-#e4Mi^(NZ9V)b~pD|DzzHVU>`bVU7OE% z=dG>YY@!>In@?8$O#o&E%u4`?vx!sq7V*OzhiL+{N%*hZH6f5;*&p{Q9^nQ52g{X; z^zdj+45a|16bV&)s3=0zXE^ zO0pXGl=Qe`ebUuQ7Hqa@WD{*eKpuNSOSjLb||S ziJx5cP0UYz^*_8P^AlF@kh?W|-Y=aEj>L;}}l4KGRX21Lvn zz2qTu@-^lvkBHNKl1)20NtTaTzH(8<@B{aY}{%@mI21<9tK@+1lI z(s+F7MKd2>li?Ot%$|Q6(g{< +#include +#include +#include + +#include "Config.h" +#include "resource.h" +#include "DEV9.h" +#include "pcap.h" +#include "pcap_io.h" +#include "net.h" +#include "tap.h" + +extern HINSTANCE hInst; +//HANDLE handleDEV9Thread = NULL; +//DWORD dwThreadId, dwThrdParam; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "Dev9linuz Msg", 0); +} + +void OnInitDialog(HWND hW) { + char *dev; + //int i; + + LoadConf(); + + ComboBox_AddString(GetDlgItem(hW, IDC_BAYTYPE), "Expansion"); + ComboBox_AddString(GetDlgItem(hW, IDC_BAYTYPE), "PC Card"); + for (int j=0;j<2;j++) + { + for (int i=0; i * al=GetTapAdapters(); + for (int i=0; isize(); i++) { + + int itm=ComboBox_AddString(GetDlgItem(hW, IDC_ETHDEV), al[0][i].name.c_str()); + ComboBox_SetItemData(GetDlgItem(hW, IDC_ETHDEV),itm,strdup( al[0][i].guid.c_str())); + if (strcmp(al[0][i].guid.c_str(), config.Eth) == 0) { + ComboBox_SetCurSel(GetDlgItem(hW, IDC_ETHDEV), itm); + } + } + + Edit_SetText(GetDlgItem(hW, IDC_HDDFILE), config.Hdd); + + Button_SetCheck(GetDlgItem(hW, IDC_ETHENABLED), config.ethEnable); + Button_SetCheck(GetDlgItem(hW, IDC_HDDENABLED), config.hddEnable); +} + +void OnOk(HWND hW) { + int i = ComboBox_GetCurSel(GetDlgItem(hW, IDC_ETHDEV)); + char* ptr=(char*)ComboBox_GetItemData(GetDlgItem(hW, IDC_ETHDEV),i); + strcpy(config.Eth, ptr); + Edit_GetText(GetDlgItem(hW, IDC_HDDFILE), config.Hdd, 256); + + config.ethEnable = Button_GetCheck(GetDlgItem(hW, IDC_ETHENABLED)); + config.hddEnable = Button_GetCheck(GetDlgItem(hW, IDC_HDDENABLED)); + + SaveConf(); + + EndDialog(hW, TRUE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + OnOk(hW); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK DEV9configure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + //SysMessage("Nothing to Configure"); +} + +void CALLBACK DEV9about() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} +/* +UINT DEV9ThreadProc() { + DEV9thread(); + + return 0; +}*/ +NetAdapter* GetNetAdapter() +{ + if(config.Eth[0]=='p') + { + return new PCAPAdapter(); + } + else if (config.Eth[0]=='t') + { + return new TAPAdapter(); + } + else + return 0; +} +s32 _DEV9open() +{ + //handleDEV9Thread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) DEV9ThreadProc, &dwThrdParam, CREATE_SUSPENDED, &dwThreadId); + //SetThreadPriority(handleDEV9Thread,THREAD_PRIORITY_HIGHEST); + //ResumeThread (handleDEV9Thread); + NetAdapter* na=GetNetAdapter(); + if (!na) + emu_printf("Failed to GetNetAdapter()\n"); + InitNet( na); + return 0; +} + +void _DEV9close() { + //TerminateThread(handleDEV9Thread,0); + //handleDEV9Thread = NULL; + TermNet(); +} diff --git a/plugins/dev9/dev9ghzdrk/Win32/_Ntddndis.h b/plugins/dev9/dev9ghzdrk/Win32/_Ntddndis.h new file mode 100644 index 0000000000..0b6298069c --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/_Ntddndis.h @@ -0,0 +1,1400 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + Copyright (c) 1990-1993 Microsoft Corporation + Module Name: + ntddndis.h + Abstract: + This is the include file that defines all constants and types for + accessing the Network driver interface device. + Author: + Steve Wood (stevewo) 27-May-1990 + Revision History: + Adam Barr (adamba) 04-Nov-1992 added the correct values for NDIS 3.0. + Jameel Hyder (jameelh) 01-Aug-95 added Pnp IoCTLs and structures + Kyle Brandon (kyleb) 09/24/96 added general co ndis oids. + -- */ +#ifndef _NTDDNDIS_ +#define _NTDDNDIS_ +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// +#define DD_NDIS_DEVICE_NAME "\\Device\\UNKNOWN" +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// +#define _NDIS_CONTROL_CODE(request,method) \ + CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS) +#define IOCTL_NDIS_QUERY_GLOBAL_STATS _NDIS_CONTROL_CODE( 0, METHOD_OUT_DIRECT ) +#define IOCTL_NDIS_QUERY_ALL_STATS _NDIS_CONTROL_CODE( 1, METHOD_OUT_DIRECT ) +#define IOCTL_NDIS_ADD_DEVICE _NDIS_CONTROL_CODE( 2, METHOD_BUFFERED ) +#define IOCTL_NDIS_DELETE_DEVICE _NDIS_CONTROL_CODE( 3, METHOD_BUFFERED ) +#define IOCTL_NDIS_TRANSLATE_NAME _NDIS_CONTROL_CODE( 4, METHOD_BUFFERED ) +#define IOCTL_NDIS_ADD_TDI_DEVICE _NDIS_CONTROL_CODE( 5, METHOD_BUFFERED ) +#define IOCTL_NDIS_NOTIFY_PROTOCOL _NDIS_CONTROL_CODE( 6, METHOD_BUFFERED ) +#define IOCTL_NDIS_GET_LOG_DATA _NDIS_CONTROL_CODE( 7, METHOD_OUT_DIRECT ) +// +// NtDeviceIoControlFile InputBuffer/OutputBuffer record structures for +// this device. +// +// +// This is the type of an NDIS OID value. +// +typedef ULONG NDIS_OID, *PNDIS_OID; +// +// IOCTL_NDIS_QUERY_ALL_STATS returns a sequence of these, packed +// together (no padding is required since statistics all have +// four or eight bytes of data). +// +typedef struct _NDIS_STATISTICS_VALUE { + NDIS_OID Oid; + ULONG DataLength; + UCHAR Data[1]; // variable length + +} NDIS_STATISTICS_VALUE, *PNDIS_STATISTICS_VALUE; + +// +// Structure used by TRANSLATE_NAME IOCTL +// +typedef struct _NET_PNP_ID { + ULONG ClassId; + ULONG Token; +} NET_PNP_ID, *PNET_PNP_ID; + +typedef struct _NET_PNP_TRANSLATE_LIST { + ULONG BytesNeeded; + NET_PNP_ID IdArray[ANYSIZE_ARRAY]; +} NET_PNP_TRANSLATE_LIST, *PNET_PNP_TRANSLATE_LIST; + +// +// Structure used to define a self-contained variable data structure +// +typedef struct _NDIS_VAR_DATA_DESC { + USHORT Length; // # of octects of data + + USHORT MaximumLength; // # of octects available + + LONG Offset; // Offset of data relative to the descriptor + +} NDIS_VAR_DATA_DESC, *PNDIS_VAR_DATA_DESC; + +// +// Object Identifiers used by NdisRequest Query/Set Information +// +// +// General Objects +// +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +// +// These are connection-oriented general OIDs. +// These replace the above OIDs for connection-oriented media. +// +#define OID_GEN_CO_SUPPORTED_LIST 0x00010101 +#define OID_GEN_CO_HARDWARE_STATUS 0x00010102 +#define OID_GEN_CO_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_CO_MEDIA_IN_USE 0x00010104 +#define OID_GEN_CO_LINK_SPEED 0x00010105 +#define OID_GEN_CO_VENDOR_ID 0x00010106 +#define OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107 +#define OID_GEN_CO_DRIVER_VERSION 0x00010108 +#define OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109 +#define OID_GEN_CO_MAC_OPTIONS 0x0001010A +#define OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B +#define OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C +#define OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D +#define OID_GEN_CO_GET_TIME_CAPS 0x00010201 +#define OID_GEN_CO_GET_NETCARD_TIME 0x00010202 +// +// These are connection-oriented statistics OIDs. +// +#define OID_GEN_CO_XMIT_PDUS_OK 0x00020101 +#define OID_GEN_CO_RCV_PDUS_OK 0x00020102 +#define OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103 +#define OID_GEN_CO_RCV_PDUS_ERROR 0x00020104 +#define OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105 +#define OID_GEN_CO_RCV_CRC_ERROR 0x00020201 +#define OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202 +#define OID_GEN_CO_BYTES_XMIT 0x00020203 +#define OID_GEN_CO_BYTES_RCV 0x00020204 +#define OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205 +#define OID_GEN_CO_NETCARD_LOAD 0x00020206 +// +// These are objects for Connection-oriented media call-managers and are not +// valid for ndis drivers. Under construction. +// +#define OID_CO_ADD_PVC 0xFF000001 +#define OID_CO_DELETE_PVC 0xFF000002 +#define OID_CO_GET_CALL_INFORMATION 0xFF000003 +#define OID_CO_ADD_ADDRESS 0xFF000004 +#define OID_CO_DELETE_ADDRESS 0xFF000005 +#define OID_CO_GET_ADDRESSES 0xFF000006 +#define OID_CO_ADDRESS_CHANGE 0xFF000007 +#define OID_CO_SIGNALING_ENABLED 0xFF000008 +#define OID_CO_SIGNALING_DISABLED 0xFF000009 +// +// 802.3 Objects (Ethernet) +// +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +// +// +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 +// +// 802.5 Objects (Token-Ring) +// +#define OID_802_5_PERMANENT_ADDRESS 0x02010101 +#define OID_802_5_CURRENT_ADDRESS 0x02010102 +#define OID_802_5_CURRENT_FUNCTIONAL 0x02010103 +#define OID_802_5_CURRENT_GROUP 0x02010104 +#define OID_802_5_LAST_OPEN_STATUS 0x02010105 +#define OID_802_5_CURRENT_RING_STATUS 0x02010106 +#define OID_802_5_CURRENT_RING_STATE 0x02010107 +#define OID_802_5_LINE_ERRORS 0x02020101 +#define OID_802_5_LOST_FRAMES 0x02020102 +#define OID_802_5_BURST_ERRORS 0x02020201 +#define OID_802_5_AC_ERRORS 0x02020202 +#define OID_802_5_ABORT_DELIMETERS 0x02020203 +#define OID_802_5_FRAME_COPIED_ERRORS 0x02020204 +#define OID_802_5_FREQUENCY_ERRORS 0x02020205 +#define OID_802_5_TOKEN_ERRORS 0x02020206 +#define OID_802_5_INTERNAL_ERRORS 0x02020207 +// +// FDDI Objects +// +#define OID_FDDI_LONG_PERMANENT_ADDR 0x03010101 +#define OID_FDDI_LONG_CURRENT_ADDR 0x03010102 +#define OID_FDDI_LONG_MULTICAST_LIST 0x03010103 +#define OID_FDDI_LONG_MAX_LIST_SIZE 0x03010104 +#define OID_FDDI_SHORT_PERMANENT_ADDR 0x03010105 +#define OID_FDDI_SHORT_CURRENT_ADDR 0x03010106 +#define OID_FDDI_SHORT_MULTICAST_LIST 0x03010107 +#define OID_FDDI_SHORT_MAX_LIST_SIZE 0x03010108 +#define OID_FDDI_ATTACHMENT_TYPE 0x03020101 +#define OID_FDDI_UPSTREAM_NODE_LONG 0x03020102 +#define OID_FDDI_DOWNSTREAM_NODE_LONG 0x03020103 +#define OID_FDDI_FRAME_ERRORS 0x03020104 +#define OID_FDDI_FRAMES_LOST 0x03020105 +#define OID_FDDI_RING_MGT_STATE 0x03020106 +#define OID_FDDI_LCT_FAILURES 0x03020107 +#define OID_FDDI_LEM_REJECTS 0x03020108 +#define OID_FDDI_LCONNECTION_STATE 0x03020109 +#define OID_FDDI_SMT_STATION_ID 0x03030201 +#define OID_FDDI_SMT_OP_VERSION_ID 0x03030202 +#define OID_FDDI_SMT_HI_VERSION_ID 0x03030203 +#define OID_FDDI_SMT_LO_VERSION_ID 0x03030204 +#define OID_FDDI_SMT_MANUFACTURER_DATA 0x03030205 +#define OID_FDDI_SMT_USER_DATA 0x03030206 +#define OID_FDDI_SMT_MIB_VERSION_ID 0x03030207 +#define OID_FDDI_SMT_MAC_CT 0x03030208 +#define OID_FDDI_SMT_NON_MASTER_CT 0x03030209 +#define OID_FDDI_SMT_MASTER_CT 0x0303020A +#define OID_FDDI_SMT_AVAILABLE_PATHS 0x0303020B +#define OID_FDDI_SMT_CONFIG_CAPABILITIES 0x0303020C +#define OID_FDDI_SMT_CONFIG_POLICY 0x0303020D +#define OID_FDDI_SMT_CONNECTION_POLICY 0x0303020E +#define OID_FDDI_SMT_T_NOTIFY 0x0303020F +#define OID_FDDI_SMT_STAT_RPT_POLICY 0x03030210 +#define OID_FDDI_SMT_TRACE_MAX_EXPIRATION 0x03030211 +#define OID_FDDI_SMT_PORT_INDEXES 0x03030212 +#define OID_FDDI_SMT_MAC_INDEXES 0x03030213 +#define OID_FDDI_SMT_BYPASS_PRESENT 0x03030214 +#define OID_FDDI_SMT_ECM_STATE 0x03030215 +#define OID_FDDI_SMT_CF_STATE 0x03030216 +#define OID_FDDI_SMT_HOLD_STATE 0x03030217 +#define OID_FDDI_SMT_REMOTE_DISCONNECT_FLAG 0x03030218 +#define OID_FDDI_SMT_STATION_STATUS 0x03030219 +#define OID_FDDI_SMT_PEER_WRAP_FLAG 0x0303021A +#define OID_FDDI_SMT_MSG_TIME_STAMP 0x0303021B +#define OID_FDDI_SMT_TRANSITION_TIME_STAMP 0x0303021C +#define OID_FDDI_SMT_SET_COUNT 0x0303021D +#define OID_FDDI_SMT_LAST_SET_STATION_ID 0x0303021E +#define OID_FDDI_MAC_FRAME_STATUS_FUNCTIONS 0x0303021F +#define OID_FDDI_MAC_BRIDGE_FUNCTIONS 0x03030220 +#define OID_FDDI_MAC_T_MAX_CAPABILITY 0x03030221 +#define OID_FDDI_MAC_TVX_CAPABILITY 0x03030222 +#define OID_FDDI_MAC_AVAILABLE_PATHS 0x03030223 +#define OID_FDDI_MAC_CURRENT_PATH 0x03030224 +#define OID_FDDI_MAC_UPSTREAM_NBR 0x03030225 +#define OID_FDDI_MAC_DOWNSTREAM_NBR 0x03030226 +#define OID_FDDI_MAC_OLD_UPSTREAM_NBR 0x03030227 +#define OID_FDDI_MAC_OLD_DOWNSTREAM_NBR 0x03030228 +#define OID_FDDI_MAC_DUP_ADDRESS_TEST 0x03030229 +#define OID_FDDI_MAC_REQUESTED_PATHS 0x0303022A +#define OID_FDDI_MAC_DOWNSTREAM_PORT_TYPE 0x0303022B +#define OID_FDDI_MAC_INDEX 0x0303022C +#define OID_FDDI_MAC_SMT_ADDRESS 0x0303022D +#define OID_FDDI_MAC_LONG_GRP_ADDRESS 0x0303022E +#define OID_FDDI_MAC_SHORT_GRP_ADDRESS 0x0303022F +#define OID_FDDI_MAC_T_REQ 0x03030230 +#define OID_FDDI_MAC_T_NEG 0x03030231 +#define OID_FDDI_MAC_T_MAX 0x03030232 +#define OID_FDDI_MAC_TVX_VALUE 0x03030233 +#define OID_FDDI_MAC_T_PRI0 0x03030234 +#define OID_FDDI_MAC_T_PRI1 0x03030235 +#define OID_FDDI_MAC_T_PRI2 0x03030236 +#define OID_FDDI_MAC_T_PRI3 0x03030237 +#define OID_FDDI_MAC_T_PRI4 0x03030238 +#define OID_FDDI_MAC_T_PRI5 0x03030239 +#define OID_FDDI_MAC_T_PRI6 0x0303023A +#define OID_FDDI_MAC_FRAME_CT 0x0303023B +#define OID_FDDI_MAC_COPIED_CT 0x0303023C +#define OID_FDDI_MAC_TRANSMIT_CT 0x0303023D +#define OID_FDDI_MAC_TOKEN_CT 0x0303023E +#define OID_FDDI_MAC_ERROR_CT 0x0303023F +#define OID_FDDI_MAC_LOST_CT 0x03030240 +#define OID_FDDI_MAC_TVX_EXPIRED_CT 0x03030241 +#define OID_FDDI_MAC_NOT_COPIED_CT 0x03030242 +#define OID_FDDI_MAC_LATE_CT 0x03030243 +#define OID_FDDI_MAC_RING_OP_CT 0x03030244 +#define OID_FDDI_MAC_FRAME_ERROR_THRESHOLD 0x03030245 +#define OID_FDDI_MAC_FRAME_ERROR_RATIO 0x03030246 +#define OID_FDDI_MAC_NOT_COPIED_THRESHOLD 0x03030247 +#define OID_FDDI_MAC_NOT_COPIED_RATIO 0x03030248 +#define OID_FDDI_MAC_RMT_STATE 0x03030249 +#define OID_FDDI_MAC_DA_FLAG 0x0303024A +#define OID_FDDI_MAC_UNDA_FLAG 0x0303024B +#define OID_FDDI_MAC_FRAME_ERROR_FLAG 0x0303024C +#define OID_FDDI_MAC_NOT_COPIED_FLAG 0x0303024D +#define OID_FDDI_MAC_MA_UNITDATA_AVAILABLE 0x0303024E +#define OID_FDDI_MAC_HARDWARE_PRESENT 0x0303024F +#define OID_FDDI_MAC_MA_UNITDATA_ENABLE 0x03030250 +#define OID_FDDI_PATH_INDEX 0x03030251 +#define OID_FDDI_PATH_RING_LATENCY 0x03030252 +#define OID_FDDI_PATH_TRACE_STATUS 0x03030253 +#define OID_FDDI_PATH_SBA_PAYLOAD 0x03030254 +#define OID_FDDI_PATH_SBA_OVERHEAD 0x03030255 +#define OID_FDDI_PATH_CONFIGURATION 0x03030256 +#define OID_FDDI_PATH_T_R_MODE 0x03030257 +#define OID_FDDI_PATH_SBA_AVAILABLE 0x03030258 +#define OID_FDDI_PATH_TVX_LOWER_BOUND 0x03030259 +#define OID_FDDI_PATH_T_MAX_LOWER_BOUND 0x0303025A +#define OID_FDDI_PATH_MAX_T_REQ 0x0303025B +#define OID_FDDI_PORT_MY_TYPE 0x0303025C +#define OID_FDDI_PORT_NEIGHBOR_TYPE 0x0303025D +#define OID_FDDI_PORT_CONNECTION_POLICIES 0x0303025E +#define OID_FDDI_PORT_MAC_INDICATED 0x0303025F +#define OID_FDDI_PORT_CURRENT_PATH 0x03030260 +#define OID_FDDI_PORT_REQUESTED_PATHS 0x03030261 +#define OID_FDDI_PORT_MAC_PLACEMENT 0x03030262 +#define OID_FDDI_PORT_AVAILABLE_PATHS 0x03030263 +#define OID_FDDI_PORT_MAC_LOOP_TIME 0x03030264 +#define OID_FDDI_PORT_PMD_CLASS 0x03030265 +#define OID_FDDI_PORT_CONNECTION_CAPABILITIES 0x03030266 +#define OID_FDDI_PORT_INDEX 0x03030267 +#define OID_FDDI_PORT_MAINT_LS 0x03030268 +#define OID_FDDI_PORT_BS_FLAG 0x03030269 +#define OID_FDDI_PORT_PC_LS 0x0303026A +#define OID_FDDI_PORT_EB_ERROR_CT 0x0303026B +#define OID_FDDI_PORT_LCT_FAIL_CT 0x0303026C +#define OID_FDDI_PORT_LER_ESTIMATE 0x0303026D +#define OID_FDDI_PORT_LEM_REJECT_CT 0x0303026E +#define OID_FDDI_PORT_LEM_CT 0x0303026F +#define OID_FDDI_PORT_LER_CUTOFF 0x03030270 +#define OID_FDDI_PORT_LER_ALARM 0x03030271 +#define OID_FDDI_PORT_CONNNECT_STATE 0x03030272 +#define OID_FDDI_PORT_PCM_STATE 0x03030273 +#define OID_FDDI_PORT_PC_WITHHOLD 0x03030274 +#define OID_FDDI_PORT_LER_FLAG 0x03030275 +#define OID_FDDI_PORT_HARDWARE_PRESENT 0x03030276 +#define OID_FDDI_SMT_STATION_ACTION 0x03030277 +#define OID_FDDI_PORT_ACTION 0x03030278 +#define OID_FDDI_IF_DESCR 0x03030279 +#define OID_FDDI_IF_TYPE 0x0303027A +#define OID_FDDI_IF_MTU 0x0303027B +#define OID_FDDI_IF_SPEED 0x0303027C +#define OID_FDDI_IF_PHYS_ADDRESS 0x0303027D +#define OID_FDDI_IF_ADMIN_STATUS 0x0303027E +#define OID_FDDI_IF_OPER_STATUS 0x0303027F +#define OID_FDDI_IF_LAST_CHANGE 0x03030280 +#define OID_FDDI_IF_IN_OCTETS 0x03030281 +#define OID_FDDI_IF_IN_UCAST_PKTS 0x03030282 +#define OID_FDDI_IF_IN_NUCAST_PKTS 0x03030283 +#define OID_FDDI_IF_IN_DISCARDS 0x03030284 +#define OID_FDDI_IF_IN_ERRORS 0x03030285 +#define OID_FDDI_IF_IN_UNKNOWN_PROTOS 0x03030286 +#define OID_FDDI_IF_OUT_OCTETS 0x03030287 +#define OID_FDDI_IF_OUT_UCAST_PKTS 0x03030288 +#define OID_FDDI_IF_OUT_NUCAST_PKTS 0x03030289 +#define OID_FDDI_IF_OUT_DISCARDS 0x0303028A +#define OID_FDDI_IF_OUT_ERRORS 0x0303028B +#define OID_FDDI_IF_OUT_QLEN 0x0303028C +#define OID_FDDI_IF_SPECIFIC 0x0303028D +// +// WAN objects +// +#define OID_WAN_PERMANENT_ADDRESS 0x04010101 +#define OID_WAN_CURRENT_ADDRESS 0x04010102 +#define OID_WAN_QUALITY_OF_SERVICE 0x04010103 +#define OID_WAN_PROTOCOL_TYPE 0x04010104 +#define OID_WAN_MEDIUM_SUBTYPE 0x04010105 +#define OID_WAN_HEADER_FORMAT 0x04010106 +#define OID_WAN_GET_INFO 0x04010107 +#define OID_WAN_SET_LINK_INFO 0x04010108 +#define OID_WAN_GET_LINK_INFO 0x04010109 +#define OID_WAN_LINE_COUNT 0x0401010A +#define OID_WAN_GET_BRIDGE_INFO 0x0401020A +#define OID_WAN_SET_BRIDGE_INFO 0x0401020B +#define OID_WAN_GET_COMP_INFO 0x0401020C +#define OID_WAN_SET_COMP_INFO 0x0401020D +#define OID_WAN_GET_STATS_INFO 0x0401020E +// +// LocalTalk objects +// +#define OID_LTALK_CURRENT_NODE_ID 0x05010102 +#define OID_LTALK_IN_BROADCASTS 0x05020101 +#define OID_LTALK_IN_LENGTH_ERRORS 0x05020102 +#define OID_LTALK_OUT_NO_HANDLERS 0x05020201 +#define OID_LTALK_COLLISIONS 0x05020202 +#define OID_LTALK_DEFERS 0x05020203 +#define OID_LTALK_NO_DATA_ERRORS 0x05020204 +#define OID_LTALK_RANDOM_CTS_ERRORS 0x05020205 +#define OID_LTALK_FCS_ERRORS 0x05020206 +// +// Arcnet objects +// +#define OID_ARCNET_PERMANENT_ADDRESS 0x06010101 +#define OID_ARCNET_CURRENT_ADDRESS 0x06010102 +#define OID_ARCNET_RECONFIGURATIONS 0x06020201 +// +// TAPI objects +// +#define OID_TAPI_ACCEPT 0x07030101 +#define OID_TAPI_ANSWER 0x07030102 +#define OID_TAPI_CLOSE 0x07030103 +#define OID_TAPI_CLOSE_CALL 0x07030104 +#define OID_TAPI_CONDITIONAL_MEDIA_DETECTION 0x07030105 +#define OID_TAPI_CONFIG_DIALOG 0x07030106 +#define OID_TAPI_DEV_SPECIFIC 0x07030107 +#define OID_TAPI_DIAL 0x07030108 +#define OID_TAPI_DROP 0x07030109 +#define OID_TAPI_GET_ADDRESS_CAPS 0x0703010A +#define OID_TAPI_GET_ADDRESS_ID 0x0703010B +#define OID_TAPI_GET_ADDRESS_STATUS 0x0703010C +#define OID_TAPI_GET_CALL_ADDRESS_ID 0x0703010D +#define OID_TAPI_GET_CALL_INFO 0x0703010E +#define OID_TAPI_GET_CALL_STATUS 0x0703010F +#define OID_TAPI_GET_DEV_CAPS 0x07030110 +#define OID_TAPI_GET_DEV_CONFIG 0x07030111 +#define OID_TAPI_GET_EXTENSION_ID 0x07030112 +#define OID_TAPI_GET_ID 0x07030113 +#define OID_TAPI_GET_LINE_DEV_STATUS 0x07030114 +#define OID_TAPI_MAKE_CALL 0x07030115 +#define OID_TAPI_NEGOTIATE_EXT_VERSION 0x07030116 +#define OID_TAPI_OPEN 0x07030117 +#define OID_TAPI_PROVIDER_INITIALIZE 0x07030118 +#define OID_TAPI_PROVIDER_SHUTDOWN 0x07030119 +#define OID_TAPI_SECURE_CALL 0x0703011A +#define OID_TAPI_SELECT_EXT_VERSION 0x0703011B +#define OID_TAPI_SEND_USER_USER_INFO 0x0703011C +#define OID_TAPI_SET_APP_SPECIFIC 0x0703011D +#define OID_TAPI_SET_CALL_PARAMS 0x0703011E +#define OID_TAPI_SET_DEFAULT_MEDIA_DETECTION 0x0703011F +#define OID_TAPI_SET_DEV_CONFIG 0x07030120 +#define OID_TAPI_SET_MEDIA_MODE 0x07030121 +#define OID_TAPI_SET_STATUS_MESSAGES 0x07030122 +// +// ATM Connection Oriented Ndis +// +#define OID_ATM_SUPPORTED_VC_RATES 0x08010101 +#define OID_ATM_SUPPORTED_SERVICE_CATEGORY 0x08010102 +#define OID_ATM_SUPPORTED_AAL_TYPES 0x08010103 +#define OID_ATM_HW_CURRENT_ADDRESS 0x08010104 +#define OID_ATM_MAX_ACTIVE_VCS 0x08010105 +#define OID_ATM_MAX_ACTIVE_VCI_BITS 0x08010106 +#define OID_ATM_MAX_ACTIVE_VPI_BITS 0x08010107 +#define OID_ATM_MAX_AAL0_PACKET_SIZE 0x08010108 +#define OID_ATM_MAX_AAL1_PACKET_SIZE 0x08010109 +#define OID_ATM_MAX_AAL34_PACKET_SIZE 0x0801010A +#define OID_ATM_MAX_AAL5_PACKET_SIZE 0x0801010B +#define OID_ATM_SIGNALING_VPIVCI 0x08010201 +#define OID_ATM_ASSIGNED_VPI 0x08010202 +#define OID_ATM_ACQUIRE_ACCESS_NET_RESOURCES 0x08010203 +#define OID_ATM_RELEASE_ACCESS_NET_RESOURCES 0x08010204 +#define OID_ATM_ILMI_VPIVCI 0x08010205 +#define OID_ATM_DIGITAL_BROADCAST_VPIVCI 0x08010206 +#define OID_ATM_GET_NEAREST_FLOW 0x08010207 +#define OID_ATM_ALIGNMENT_REQUIRED 0x08010208 +// +// ATM specific statistics OIDs. +// +#define OID_ATM_RCV_CELLS_OK 0x08020101 +#define OID_ATM_XMIT_CELLS_OK 0x08020102 +#define OID_ATM_RCV_CELLS_DROPPED 0x08020103 +#define OID_ATM_RCV_INVALID_VPI_VCI 0x08020201 +#define OID_ATM_CELLS_HEC_ERROR 0x08020202 +#define OID_ATM_RCV_REASSEMBLY_ERROR 0x08020203 +// +// PCCA (Wireless) object +// +// +// All WirelessWAN devices must support the following OIDs +// +#define OID_WW_GEN_NETWORK_TYPES_SUPPORTED 0x09010101 +#define OID_WW_GEN_NETWORK_TYPE_IN_USE 0x09010102 +#define OID_WW_GEN_HEADER_FORMATS_SUPPORTED 0x09010103 +#define OID_WW_GEN_HEADER_FORMAT_IN_USE 0x09010104 +#define OID_WW_GEN_INDICATION_REQUEST 0x09010105 +#define OID_WW_GEN_DEVICE_INFO 0x09010106 +#define OID_WW_GEN_OPERATION_MODE 0x09010107 +#define OID_WW_GEN_LOCK_STATUS 0x09010108 +#define OID_WW_GEN_DISABLE_TRANSMITTER 0x09010109 +#define OID_WW_GEN_NETWORK_ID 0x0901010A +#define OID_WW_GEN_PERMANENT_ADDRESS 0x0901010B +#define OID_WW_GEN_CURRENT_ADDRESS 0x0901010C +#define OID_WW_GEN_SUSPEND_DRIVER 0x0901010D +#define OID_WW_GEN_BASESTATION_ID 0x0901010E +#define OID_WW_GEN_CHANNEL_ID 0x0901010F +#define OID_WW_GEN_ENCRYPTION_SUPPORTED 0x09010110 +#define OID_WW_GEN_ENCRYPTION_IN_USE 0x09010111 +#define OID_WW_GEN_ENCRYPTION_STATE 0x09010112 +#define OID_WW_GEN_CHANNEL_QUALITY 0x09010113 +#define OID_WW_GEN_REGISTRATION_STATUS 0x09010114 +#define OID_WW_GEN_RADIO_LINK_SPEED 0x09010115 +#define OID_WW_GEN_LATENCY 0x09010116 +#define OID_WW_GEN_BATTERY_LEVEL 0x09010117 +#define OID_WW_GEN_EXTERNAL_POWER 0x09010118 +// +// Network Dependent OIDs - Mobitex: +// +#define OID_WW_MBX_SUBADDR 0x09050101 +// OID 0x09050102 is reserved and may not be used +#define OID_WW_MBX_FLEXLIST 0x09050103 +#define OID_WW_MBX_GROUPLIST 0x09050104 +#define OID_WW_MBX_TRAFFIC_AREA 0x09050105 +#define OID_WW_MBX_LIVE_DIE 0x09050106 +#define OID_WW_MBX_TEMP_DEFAULTLIST 0x09050107 +// +// Network Dependent OIDs - Pinpoint: +// +#define OID_WW_PIN_LOC_AUTHORIZE 0x09090101 +#define OID_WW_PIN_LAST_LOCATION 0x09090102 +#define OID_WW_PIN_LOC_FIX 0x09090103 +// +// Network Dependent - CDPD: +// +#define OID_WW_CDPD_SPNI 0x090D0101 +#define OID_WW_CDPD_WASI 0x090D0102 +#define OID_WW_CDPD_AREA_COLOR 0x090D0103 +#define OID_WW_CDPD_TX_POWER_LEVEL 0x090D0104 +#define OID_WW_CDPD_EID 0x090D0105 +#define OID_WW_CDPD_HEADER_COMPRESSION 0x090D0106 +#define OID_WW_CDPD_DATA_COMPRESSION 0x090D0107 +#define OID_WW_CDPD_CHANNEL_SELECT 0x090D0108 +#define OID_WW_CDPD_CHANNEL_STATE 0x090D0109 +#define OID_WW_CDPD_NEI 0x090D010A +#define OID_WW_CDPD_NEI_STATE 0x090D010B +#define OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER 0x090D010C +#define OID_WW_CDPD_SLEEP_MODE 0x090D010D +#define OID_WW_CDPD_CIRCUIT_SWITCHED 0x090D010E +#define OID_WW_CDPD_TEI 0x090D010F +#define OID_WW_CDPD_RSSI 0x090D0110 +// +// Network Dependent - Ardis: +// +#define OID_WW_ARD_SNDCP 0x09110101 +#define OID_WW_ARD_TMLY_MSG 0x09110102 +#define OID_WW_ARD_DATAGRAM 0x09110103 +// +// Network Dependent - DataTac: +// +#define OID_WW_TAC_COMPRESSION 0x09150101 +#define OID_WW_TAC_SET_CONFIG 0x09150102 +#define OID_WW_TAC_GET_STATUS 0x09150103 +#define OID_WW_TAC_USER_HEADER 0x09150104 +// +// Network Dependent - Metricom: +// +#define OID_WW_MET_FUNCTION 0x09190101 +// +// IRDA objects +// +#define OID_IRDA_RECEIVING 0x0A010100 +#define OID_IRDA_TURNAROUND_TIME 0x0A010101 +#define OID_IRDA_SUPPORTED_SPEEDS 0x0A010102 +#define OID_IRDA_LINK_SPEED 0x0A010103 +#define OID_IRDA_MEDIA_BUSY 0x0A010104 +#define OID_IRDA_EXTRA_RCV_BOFS 0x0A010200 +#define OID_IRDA_RATE_SNIFF 0x0A010201 +#define OID_IRDA_UNICAST_LIST 0x0A010202 +#define OID_IRDA_MAX_UNICAST_LIST_SIZE 0x0A010203 +#define OID_IRDA_MAX_RECEIVE_WINDOW_SIZE 0x0A010204 +#define OID_IRDA_MAX_SEND_WINDOW_SIZE 0x0A010205 +// +// Medium the Ndis Driver is running on (OID_GEN_MEDIA_SUPPORTED/ +// OID_GEN_MEDIA_IN_USE). +// +typedef enum _NDIS_MEDIUM { + NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumWan, + NdisMediumLocalTalk, + NdisMediumDix, // defined for convenience, not a real medium + NdisMediumArcnetRaw, + NdisMediumArcnet878_2, + NdisMediumAtm, + NdisMediumWirelessWan, + NdisMediumIrda, + NdisMediumMax // Not a real medium, defined as an upper-bound +} NDIS_MEDIUM, *PNDIS_MEDIUM; + +// +// Hardware status codes (OID_GEN_HARDWARE_STATUS). +// +typedef enum _NDIS_HARDWARE_STATUS { + NdisHardwareStatusReady, + NdisHardwareStatusInitializing, + NdisHardwareStatusReset, + NdisHardwareStatusClosing, + NdisHardwareStatusNotReady +} NDIS_HARDWARE_STATUS, *PNDIS_HARDWARE_STATUS; + +// +// this is the type passed in the OID_GEN_GET_TIME_CAPS request +// +typedef struct _GEN_GET_TIME_CAPS { + ULONG Flags; // Bits defined below + + ULONG ClockPrecision; +} GEN_GET_TIME_CAPS, *PGEN_GET_TIME_CAPS; + +#define READABLE_LOCAL_CLOCK 0x000000001 +#define CLOCK_NETWORK_DERIVED 0x000000002 +#define CLOCK_PRECISION 0x000000004 +#define RECEIVE_TIME_INDICATION_CAPABLE 0x000000008 +#define TIMED_SEND_CAPABLE 0x000000010 +#define TIME_STAMP_CAPABLE 0x000000020 +// +// +// this is the type passed in the OID_GEN_GET_NETCARD_TIME request +// +typedef struct _GEN_GET_NETCARD_TIME { + ULONG ReadTime; +} GEN_GET_NETCARD_TIME, *PGEN_GET_NETCARD_TIME; + +// +// Defines the attachment types for FDDI (OID_FDDI_ATTACHMENT_TYPE). +// +typedef enum _NDIS_FDDI_ATTACHMENT_TYPE { + NdisFddiTypeIsolated = 1, + NdisFddiTypeLocalA, + NdisFddiTypeLocalB, + NdisFddiTypeLocalAB, + NdisFddiTypeLocalS, + NdisFddiTypeWrapA, + NdisFddiTypeWrapB, + NdisFddiTypeWrapAB, + NdisFddiTypeWrapS, + NdisFddiTypeCWrapA, + NdisFddiTypeCWrapB, + NdisFddiTypeCWrapS, + NdisFddiTypeThrough +} NDIS_FDDI_ATTACHMENT_TYPE, *PNDIS_FDDI_ATTACHMENT_TYPE; + +// +// Defines the ring management states for FDDI (OID_FDDI_RING_MGT_STATE). +// +typedef enum _NDIS_FDDI_RING_MGT_STATE { + NdisFddiRingIsolated = 1, + NdisFddiRingNonOperational, + NdisFddiRingOperational, + NdisFddiRingDetect, + NdisFddiRingNonOperationalDup, + NdisFddiRingOperationalDup, + NdisFddiRingDirected, + NdisFddiRingTrace +} NDIS_FDDI_RING_MGT_STATE, *PNDIS_FDDI_RING_MGT_STATE; + +// +// Defines the Lconnection state for FDDI (OID_FDDI_LCONNECTION_STATE). +// +typedef enum _NDIS_FDDI_LCONNECTION_STATE { + NdisFddiStateOff = 1, + NdisFddiStateBreak, + NdisFddiStateTrace, + NdisFddiStateConnect, + NdisFddiStateNext, + NdisFddiStateSignal, + NdisFddiStateJoin, + NdisFddiStateVerify, + NdisFddiStateActive, + NdisFddiStateMaintenance +} NDIS_FDDI_LCONNECTION_STATE, *PNDIS_FDDI_LCONNECTION_STATE; + +// +// Defines the medium subtypes for WAN medium (OID_WAN_MEDIUM_SUBTYPE). +// +typedef enum _NDIS_WAN_MEDIUM_SUBTYPE { + NdisWanMediumHub, + NdisWanMediumX_25, + NdisWanMediumIsdn, + NdisWanMediumSerial, + NdisWanMediumFrameRelay, + NdisWanMediumAtm, + NdisWanMediumSonet, + NdisWanMediumSW56K +} NDIS_WAN_MEDIUM_SUBTYPE, *PNDIS_WAN_MEDIUM_SUBTYPE; + +// +// Defines the header format for WAN medium (OID_WAN_HEADER_FORMAT). +// +typedef enum _NDIS_WAN_HEADER_FORMAT { + NdisWanHeaderNative, // src/dest based on subtype, followed by NLPID + NdisWanHeaderEthernet // emulation of ethernet header +} NDIS_WAN_HEADER_FORMAT, *PNDIS_WAN_HEADER_FORMAT; + +// +// Defines the line quality on a WAN line (OID_WAN_QUALITY_OF_SERVICE). +// +typedef enum _NDIS_WAN_QUALITY { + NdisWanRaw, + NdisWanErrorControl, + NdisWanReliable +} NDIS_WAN_QUALITY, *PNDIS_WAN_QUALITY; + +// +// Defines the state of a token-ring adapter (OID_802_5_CURRENT_RING_STATE). +// +typedef enum _NDIS_802_5_RING_STATE { + NdisRingStateOpened = 1, + NdisRingStateClosed, + NdisRingStateOpening, + NdisRingStateClosing, + NdisRingStateOpenFailure, + NdisRingStateRingFailure +} NDIS_802_5_RING_STATE, *PNDIS_802_5_RING_STATE; + +// +// Defines the state of the LAN media +// +typedef enum _NDIS_MEDIA_STATE { + NdisMediaStateConnected, + NdisMediaStateDisconnected +} NDIS_MEDIA_STATE, *PNDIS_MEDIA_STATE; + +// +// The following is set on a per-packet basis as OOB data with NdisClass802_3Priority +// +typedef ULONG Priority_802_3; // 0-7 priority levels +// +// The following structure is used to query OID_GEN_CO_LINK_SPEED and +// OID_GEN_CO_MINIMUM_LINK_SPEED. The first OID will return the current +// link speed of the adapter. The second will return the minimum link speed +// the adapter is capable of. +// + +typedef struct _NDIS_CO_LINK_SPEED { + ULONG Outbound; + ULONG Inbound; +} NDIS_CO_LINK_SPEED, + +*PNDIS_CO_LINK_SPEED; +// +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER). +// +#define NDIS_PACKET_TYPE_DIRECTED 0x0001 +#define NDIS_PACKET_TYPE_MULTICAST 0x0002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004 +#define NDIS_PACKET_TYPE_BROADCAST 0x0008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020 +#define NDIS_PACKET_TYPE_SMT 0x0040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000 +#define NDIS_PACKET_TYPE_GROUP 0x1000 +// +// Ndis Token-Ring Ring Status Codes (OID_802_5_CURRENT_RING_STATUS). +// +#define NDIS_RING_SIGNAL_LOSS 0x00008000 +#define NDIS_RING_HARD_ERROR 0x00004000 +#define NDIS_RING_SOFT_ERROR 0x00002000 +#define NDIS_RING_TRANSMIT_BEACON 0x00001000 +#define NDIS_RING_LOBE_WIRE_FAULT 0x00000800 +#define NDIS_RING_AUTO_REMOVAL_ERROR 0x00000400 +#define NDIS_RING_REMOVE_RECEIVED 0x00000200 +#define NDIS_RING_COUNTER_OVERFLOW 0x00000100 +#define NDIS_RING_SINGLE_STATION 0x00000080 +#define NDIS_RING_RING_RECOVERY 0x00000040 +// +// Ndis protocol option bits (OID_GEN_PROTOCOL_OPTIONS). +// +#define NDIS_PROT_OPTION_ESTIMATED_LENGTH 0x00000001 +#define NDIS_PROT_OPTION_NO_LOOPBACK 0x00000002 +#define NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT 0x00000004 +// +// Ndis MAC option bits (OID_GEN_MAC_OPTIONS). +// +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 +// +// NDIS MAC option bits for OID_GEN_CO_MAC_OPTIONS. +// +#define NDIS_CO_MAC_OPTION_DYNAMIC_LINK_SPEED 0x00000001 +#ifdef IRDA +// +// The following is set on a per-packet basis as OOB data with NdisClassIrdaPacketInfo +// This is the per-packet info specified on a per-packet basis +// +typedef struct _NDIS_IRDA_PACKET_INFO { + UINT ExtraBOFs; + UINT MinTurnAroundTime; +} NDIS_IRDA_PACKET_INFO, *PNDIS_IRDA_PACKET_INFO; + +#endif +#ifdef WIRELESS_WAN +// +// Wireless WAN structure definitions +// +// +// currently defined Wireless network subtypes +// +typedef enum _NDIS_WW_NETWORK_TYPE { + NdisWWGeneric, + NdisWWMobitex, + NdisWWPinpoint, + NdisWWCDPD, + NdisWWArdis, + NdisWWDataTAC, + NdisWWMetricom, + NdisWWGSM, + NdisWWCDMA, + NdisWWTDMA, + NdisWWAMPS, + NdisWWInmarsat, + NdisWWpACT +} NDIS_WW_NETWORK_TYPE; + +// +// currently defined header formats +// +typedef enum _NDIS_WW_HEADER_FORMAT { + NdisWWDIXEthernetFrames, + NdisWWMPAKFrames, + NdisWWRDLAPFrames, + NdisWWMDC4800Frames +} NDIS_WW_HEADER_FORMAT; + +// +// currently defined encryption types +// +typedef enum _NDIS_WW_ENCRYPTION_TYPE { + NdisWWUnknownEncryption = -1, + NdisWWNoEncryption, + NdisWWDefaultEncryption +} NDIS_WW_ENCRYPTION_TYPE, *PNDIS_WW_ENCRYPTION_TYPE; + +// +// OID_WW_GEN_INDICATION_REQUEST +// +typedef struct _NDIS_WW_INDICATION_REQUEST { + NDIS_OID Oid; // IN + + UINT uIndicationFlag; // IN + + UINT uApplicationToken; // IN OUT + + HANDLE hIndicationHandle; // IN OUT + + INT iPollingInterval; // IN OUT + + NDIS_VAR_DATA_DESC InitialValue; // IN OUT + + NDIS_VAR_DATA_DESC OIDIndicationValue; // OUT - only valid after indication + + NDIS_VAR_DATA_DESC TriggerValue; // IN + +} NDIS_WW_INDICATION_REQUEST, *PNDIS_WW_INDICATION_REQUEST; + +#define OID_INDICATION_REQUEST_ENABLE 0x0000 +#define OID_INDICATION_REQUEST_CANCEL 0x0001 +// +// OID_WW_GEN_DEVICE_INFO +// +typedef struct _WW_DEVICE_INFO { + NDIS_VAR_DATA_DESC Manufacturer; + NDIS_VAR_DATA_DESC ModelNum; + NDIS_VAR_DATA_DESC SWVersionNum; + NDIS_VAR_DATA_DESC SerialNum; +} WW_DEVICE_INFO, *PWW_DEVICE_INFO; + +// +// OID_WW_GEN_OPERATION_MODE +// +typedef INT WW_OPERATION_MODE; // 0 = Normal mode + // 1 = Power saving mode + // -1 = mode unknown +// +// OID_WW_GEN_LOCK_STATUS +// + +typedef INT WW_LOCK_STATUS; // 0 = unlocked + // 1 = locked + // -1 = unknown lock status +// +// OID_WW_GEN_DISABLE_TRANSMITTER +// + +typedef INT WW_DISABLE_TRANSMITTER; // 0 = transmitter enabled + // 1 = transmitter disabled + // -1 = unknown value +// +// OID_WW_GEN_NETWORK_ID +// + +typedef NDIS_VAR_DATA_DESC WW_NETWORK_ID; +// +// OID_WW_GEN_PERMANENT_ADDRESS +// +typedef NDIS_VAR_DATA_DESC WW_PERMANENT_ADDRESS; +// +// OID_WW_GEN_CURRENT_ADDRESS +// +typedef struct _WW_CURRENT_ADDRESS { + NDIS_WW_HEADER_FORMAT Format; + NDIS_VAR_DATA_DESC Address; +} WW_CURRENT_ADDRESS, *PWW_CURRENT_ADDRESS; + +// +// OID_WW_GEN_SUSPEND_DRIVER +// +typedef BOOLEAN WW_SUSPEND_DRIVER; // 0 = driver operational + // 1 = driver suspended +// +// OID_WW_GEN_BASESTATION_ID +// + +typedef NDIS_VAR_DATA_DESC WW_BASESTATION_ID; +// +// OID_WW_GEN_CHANNEL_ID +// +typedef NDIS_VAR_DATA_DESC WW_CHANNEL_ID; +// +// OID_WW_GEN_ENCRYPTION_STATE +// +typedef BOOLEAN WW_ENCRYPTION_STATE; // 0 = if encryption is disabled + // 1 = if encryption is enabled +// +// OID_WW_GEN_CHANNEL_QUALITY +// + +typedef INT WW_CHANNEL_QUALITY; // 0 = Not in network contact, + // 1-100 = Quality of Channel (100 is highest quality). + // -1 = channel quality is unknown +// +// OID_WW_GEN_REGISTRATION_STATUS +// + +typedef INT WW_REGISTRATION_STATUS; // 0 = Registration denied + // 1 = Registration pending + // 2 = Registered + // -1 = unknown registration status +// +// OID_WW_GEN_RADIO_LINK_SPEED +// + +typedef UINT WW_RADIO_LINK_SPEED; // Bits per second. +// +// OID_WW_GEN_LATENCY +// + +typedef UINT WW_LATENCY; // milliseconds +// +// OID_WW_GEN_BATTERY_LEVEL +// + +typedef INT WW_BATTERY_LEVEL; // 0-100 = battery level in percentage + // (100=fully charged) + // -1 = unknown battery level. +// +// OID_WW_GEN_EXTERNAL_POWER +// + +typedef INT WW_EXTERNAL_POWER; // 0 = no external power connected + // 1 = external power connected + // -1 = unknown +// +// OID_WW_MET_FUNCTION +// + +typedef NDIS_VAR_DATA_DESC WW_MET_FUNCTION; +// +// OID_WW_TAC_COMPRESSION +// +typedef BOOLEAN WW_TAC_COMPRESSION; // Determines whether or not network level compression + // is being used. +// +// OID_WW_TAC_SET_CONFIG +// + +typedef struct _WW_TAC_SETCONFIG { + NDIS_VAR_DATA_DESC RCV_MODE; + NDIS_VAR_DATA_DESC TX_CONTROL; + NDIS_VAR_DATA_DESC RX_CONTROL; + NDIS_VAR_DATA_DESC FLOW_CONTROL; + NDIS_VAR_DATA_DESC RESET_CNF; + NDIS_VAR_DATA_DESC READ_CNF; +} WW_TAC_SETCONFIG, *PWW_TAC_SETCONFIG; + +// +// OID_WW_TAC_GET_STATUS +// +typedef struct _WW_TAC_GETSTATUS { + BOOLEAN Action; // Set = Execute command. + + NDIS_VAR_DATA_DESC Command; + NDIS_VAR_DATA_DESC Option; + NDIS_VAR_DATA_DESC Response; // The response to the requested command + // - max. length of string is 256 octets. + +} WW_TAC_GETSTATUS, *PWW_TAC_GETSTATUS; + +// +// OID_WW_TAC_USER_HEADER +// +typedef NDIS_VAR_DATA_DESC WW_TAC_USERHEADER; // This will hold the user header - Max. 64 octets. +// +// OID_WW_ARD_SNDCP +// + +typedef struct _WW_ARD_SNDCP { + NDIS_VAR_DATA_DESC Version; // The version of SNDCP protocol supported. + + INT BlockSize; // The block size used for SNDCP + + INT Window; // The window size used in SNDCP + +} WW_ARD_SNDCP, *PWW_ARD_SNDCP; + +// +// OID_WW_ARD_TMLY_MSG +// +typedef BOOLEAN WW_ARD_CHANNEL_STATUS; // The current status of the inbound RF Channel. +// +// OID_WW_ARD_DATAGRAM +// + +typedef struct _WW_ARD_DATAGRAM { + BOOLEAN LoadLevel; // Byte that contains the load level info. + + INT SessionTime; // Datagram session time remaining. + + NDIS_VAR_DATA_DESC HostAddr; // Host address. + + NDIS_VAR_DATA_DESC THostAddr; // Test host address. + +} WW_ARD_DATAGRAM, *PWW_ARD_DATAGRAM; + +// +// OID_WW_CDPD_SPNI +// +typedef struct _WW_CDPD_SPNI { + UINT SPNI[10]; //10 16-bit service provider network IDs + + INT OperatingMode; // 0 = ignore SPNI, + // 1 = require SPNI from list, + // 2 = prefer SPNI from list. + // 3 = exclude SPNI from list. + +} WW_CDPD_SPNI, *PWW_CDPD_SPNI; + +// +// OID_WW_CDPD_WASI +// +typedef struct _WW_CDPD_WIDE_AREA_SERVICE_ID { + UINT WASI[10]; //10 16-bit wide area service IDs + + INT OperatingMode; // 0 = ignore WASI, + // 1 = Require WASI from list, + // 2 = prefer WASI from list + // 3 = exclude WASI from list. + +} WW_CDPD_WIDE_AREA_SERVICE_ID, *PWW_CDPD_WIDE_AREA_SERVICE_ID; + +// +// OID_WW_CDPD_AREA_COLOR +// +typedef INT WW_CDPD_AREA_COLOR; +// +// OID_WW_CDPD_TX_POWER_LEVEL +// +typedef UINT WW_CDPD_TX_POWER_LEVEL; +// +// OID_WW_CDPD_EID +// +typedef NDIS_VAR_DATA_DESC WW_CDPD_EID; +// +// OID_WW_CDPD_HEADER_COMPRESSION +// +typedef INT WW_CDPD_HEADER_COMPRESSION; // 0 = no header compression, + // 1 = always compress headers, + // 2 = compress headers if MD-IS does + // -1 = unknown +// +// OID_WW_CDPD_DATA_COMPRESSION +// + +typedef INT WW_CDPD_DATA_COMPRESSION; // 0 = no data compression, + // 1 = data compression enabled + // -1 = unknown +// +// OID_WW_CDPD_CHANNEL_SELECT +// + +typedef struct _WW_CDPD_CHANNEL_SELECT { + UINT ChannelID; // channel number + + UINT fixedDuration; // duration in seconds + +} WW_CDPD_CHANNEL_SELECT, *PWW_CDPD_CHANNEL_SELECT; + +// +// OID_WW_CDPD_CHANNEL_STATE +// +typedef enum _WW_CDPD_CHANNEL_STATE { + CDPDChannelNotAvail, + CDPDChannelScanning, + CDPDChannelInitAcquired, + CDPDChannelAcquired, + CDPDChannelSleeping, + CDPDChannelWaking, + CDPDChannelCSDialing, + CDPDChannelCSRedial, + CDPDChannelCSAnswering, + CDPDChannelCSConnected, + CDPDChannelCSSuspended +} WW_CDPD_CHANNEL_STATE, *PWW_CDPD_CHANNEL_STATE; + +// +// OID_WW_CDPD_NEI +// +typedef enum _WW_CDPD_NEI_FORMAT { + CDPDNeiIPv4, + CDPDNeiCLNP, + CDPDNeiIPv6 +} WW_CDPD_NEI_FORMAT, *PWW_CDPD_NEI_FORMAT; +typedef enum _WW_CDPD_NEI_TYPE { + CDPDNeiIndividual, + CDPDNeiMulticast, + CDPDNeiBroadcast +} WW_CDPD_NEI_TYPE; +typedef struct _WW_CDPD_NEI { + UINT uNeiIndex; + WW_CDPD_NEI_FORMAT NeiFormat; + WW_CDPD_NEI_TYPE NeiType; + WORD NeiGmid; // group member identifier, only + // meaningful if NeiType == + // CDPDNeiMulticast + + NDIS_VAR_DATA_DESC NeiAddress; +} WW_CDPD_NEI; + +// +// OID_WW_CDPD_NEI_STATE +// +typedef enum _WW_CDPD_NEI_STATE { + CDPDUnknown, + CDPDRegistered, + CDPDDeregistered +} WW_CDPD_NEI_STATE, *PWW_CDPD_NEI_STATE; +typedef enum _WW_CDPD_NEI_SUB_STATE { + CDPDPending, // Registration pending + CDPDNoReason, // Registration denied - no reason given + CDPDMDISNotCapable, // Registration denied - MD-IS not capable of + // handling M-ES at this time + CDPDNEINotAuthorized, // Registration denied - NEI is not authorized to + // use this subnetwork + CDPDInsufficientAuth, // Registration denied - M-ES gave insufficient + // authentication credentials + CDPDUnsupportedAuth, // Registration denied - M-ES gave unsupported + // authentication credentials + CDPDUsageExceeded, // Registration denied - NEI has exceeded usage + // limitations + CDPDDeniedThisNetwork // Registration denied on this network, service + // may be obtained on alternate Service Provider + // network +} WW_CDPD_NEI_SUB_STATE; +typedef struct _WW_CDPD_NEI_REG_STATE { + UINT uNeiIndex; + WW_CDPD_NEI_STATE NeiState; + WW_CDPD_NEI_SUB_STATE NeiSubState; +} WW_CDPD_NEI_REG_STATE, *PWW_CDPD_NEI_REG_STATE; + +// +// OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER +// +typedef struct _WW_CDPD_SERVICE_PROVIDER_ID { + UINT SPI[10]; //10 16-bit service provider IDs + + INT OperatingMode; // 0 = ignore SPI, + // 1 = require SPI from list, + // 2 = prefer SPI from list. + // 3 = exclude SPI from list. + +} WW_CDPD_SERVICE_PROVIDER_ID, *PWW_CDPD_SERVICE_PROVIDER_ID; + +// +// OID_WW_CDPD_SLEEP_MODE +// +typedef INT WW_CDPD_SLEEP_MODE; +// +// OID_WW_CDPD_TEI +// +typedef ULONG WW_CDPD_TEI; +// +// OID_WW_CDPD_CIRCUIT_SWITCHED +// +typedef struct _WW_CDPD_CIRCUIT_SWITCHED { + INT service_preference; // -1 = unknown, + // 0 = always use packet switched CDPD, + // 1 = always use CS CDPD via AMPS, + // 2 = always use CS CDPD via PSTN, + // 3 = use circuit switched via AMPS only + // when packet switched is not available. + // 4 = use packet switched only when circuit + // switched via AMPS is not available. + // 5 = device manuf. defined service + // preference. + // 6 = device manuf. defined service + // preference. + + INT service_status; // -1 = unknown, + // 0 = packet switched CDPD, + // 1 = circuit switched CDPD via AMPS, + // 2 = circuit switched CDPD via PSTN. + + INT connect_rate; // CS connection bit rate (bits per second). + // 0 = no active connection, + // -1 = unknown + // Dial code last used to dial. + + NDIS_VAR_DATA_DESC dial_code[20]; + + UINT sid; // Current AMPS system ID + + INT a_b_side_selection; // -1 = unknown, + // 0 = no AMPS service + // 1 = AMPS "A" side channels selected + // 2 = AMPS "B" side channels selected + + INT AMPS_channel; // -1= unknown + // 0 = no AMPS service. + // 1-1023 = AMPS channel number in use + + UINT action; // 0 = no action + // 1 = suspend (hangup) + // 2 = dial + + // Default dial code for CS CDPD service + // encoded as specified in the CS CDPD + // implementor guidelines. + NDIS_VAR_DATA_DESC default_dial[20]; + + // Number for the CS CDPD network to call + // back the mobile, encoded as specified in + // the CS CDPD implementor guidelines. + NDIS_VAR_DATA_DESC call_back[20]; + + UINT sid_list[10]; // List of 10 16-bit preferred AMPS + // system IDs for CS CDPD. + + UINT inactivity_timer; // Wait time after last data before dropping + // call. + // 0-65535 = inactivity time limit (seconds). + + UINT receive_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT conn_resp_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT reconn_resp_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT disconn_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT NEI_reg_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT reconn_retry_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT link_reset_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT link_reset_ack_timer; // secs. per CS-CDPD Implementor Guidelines. + + UINT n401_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n402_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n404_retry_limit; // per CS-CDPD Implementor Guidelines. + + UINT n405_retry_limit; // per CS-CDPD Implementor Guidelines. + +} WW_CDPD_CIRCUIT_SWITCHED, *WW_PCDPD_CIRCUIT_SWITCHED; +typedef UINT WW_CDPD_RSSI; +// +// OID_WW_PIN_LOC_AUTHORIZE +// +typedef INT WW_PIN_AUTHORIZED; // 0 = unauthorized + // 1 = authorized + // -1 = unknown +// +// OID_WW_PIN_LAST_LOCATION +// OID_WW_PIN_LOC_FIX +// + +typedef struct _WW_PIN_LOCATION { + INT Latitude; // Latitude in hundredths of a second + + INT Longitude; // Longitude in hundredths of a second + + INT Altitude; // Altitude in feet + + INT FixTime; // Time of the location fix, since midnight, local time (of the + // current day), in tenths of a second + + INT NetTime; // Current local network time of the current day, since midnight, + // in tenths of a second + + INT LocQuality; // 0-100 = location quality + + INT LatReg; // Latitude registration offset, in hundredths of a second + + INT LongReg; // Longitude registration offset, in hundredths of a second + + INT GMTOffset; // Offset in minutes of the local time zone from GMT + +} WW_PIN_LOCATION, *PWW_PIN_LOCATION; + +// +// The following is set on a per-packet basis as OOB data with NdisClassWirelessWanMbxMailbox +// +typedef ULONG WW_MBX_MAILBOX_FLAG; // 1 = set mailbox flag, 0 = do not set mailbox flag +// +// OID_WW_MBX_SUBADDR +// + +typedef struct _WW_MBX_PMAN { + BOOLEAN ACTION; // 0 = Login PMAN, 1 = Logout PMAN + + UINT MAN; + UCHAR PASSWORD[8]; // Password should be null for Logout and indications. + // Maximum length of password is 8 chars. + +} WW_MBX_PMAN, *PWW_MBX_PMAN; + +// +// OID_WW_MBX_FLEXLIST +// +typedef struct _WW_MBX_FLEXLIST { + INT count; // Number of MAN entries used. + // -1=unknown. + + UINT MAN[7]; // List of MANs. + +} WW_MBX_FLEXLIST; + +// +// OID_WW_MBX_GROUPLIST +// +typedef struct _WW_MBX_GROUPLIST { + INT count; // Number of MAN entries used. + // -1=unknown. + + UINT MAN[15]; // List of MANs. + +} WW_MBX_GROUPLIST; + +// +// OID_WW_MBX_TRAFFIC_AREA +// +typedef enum _WW_MBX_TRAFFIC_AREA { + unknown_traffic_area, // The driver has no information about the current traffic area. + in_traffic_area, // Mobile unit has entered a subscribed traffic area. + in_auth_traffic_area, // Mobile unit is outside traffic area but is authorized. + unauth_traffic_area // Mobile unit is outside traffic area but is un-authorized. +} WW_MBX_TRAFFIC_AREA; + +// +// OID_WW_MBX_LIVE_DIE +// +typedef INT WW_MBX_LIVE_DIE; // 0 = DIE last received + // 1 = LIVE last received + // -1 = unknown +// +// OID_WW_MBX_TEMP_DEFAULTLIST +// + +typedef struct _WW_MBX_CHANNEL_PAIR { + UINT Mobile_Tx; + UINT Mobile_Rx; +} WW_MBX_CHANNEL_PAIR, *PWW_MBX_CHANNEL_PAIR; +typedef struct _WW_MBX_TEMPDEFAULTLIST { + UINT Length; + WW_MBX_CHANNEL_PAIR ChannelPair[1]; +} WW_MBX_TEMPDEFAULTLIST, *WW_PMBX_TEMPDEFAULTLIST; + +#endif // WIRELESS_WAN +#endif // _NTDDNDIS_ diff --git a/plugins/dev9/dev9ghzdrk/Win32/afxresmw.h b/plugins/dev9/dev9ghzdrk/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/dev9/dev9ghzdrk/Win32/ata.cpp b/plugins/dev9/dev9ghzdrk/Win32/ata.cpp new file mode 100644 index 0000000000..14ddf0cbdc --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/ata.cpp @@ -0,0 +1,3442 @@ +/* + * QEMU IDE disk and CD-ROM Emulator + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "dev9.h" +#include "vl.h" + +/* debug IDE devices */ +//#define DEBUG_IDE +//#define DEBUG_IDE_ATAPI +//#define DEBUG_AIO + +#define USE_DMA_CDROM +#define QEMU_VERSION " PCSX2" +#define snprintf _snprintf + +#define le32_to_cpu(x) (x) +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SRV_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits of HD_NSECTOR */ +#define CD 0x01 +#define IO 0x02 +#define REL 0x04 +#define TAG_MASK 0xf8 + +#define IDE_CMD_RESET 0x04 +#define IDE_CMD_DISABLE_IRQ 0x02 + +/* ATA/ATAPI Commands pre T13 Spec */ +#define WIN_NOP 0x00 +/* + * 0x01->0x02 Reserved + */ +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* + * 0x04->0x07 Reserved + */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_DEVICE_RESET 0x08 +/* + * 0x09->0x0F Reserved + */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +/* + * 0x10->0x1F Reserved + */ +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ +#define WIN_READ_LONG 0x22 /* 28-Bit */ +#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +/* + * 0x28 + */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* + * 0x2A->0x2F Reserved + */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ +#define WIN_WRITE_LONG 0x32 /* 28-Bit */ +#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* + * 0x3A->0x3B Reserved + */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +/* + * 0x3D->0x3F Reserved + */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* + * 0x43->0x4F Reserved + */ +#define WIN_FORMAT 0x50 +/* + * 0x51->0x5F Reserved + */ +#define WIN_INIT 0x60 +/* + * 0x61->0x5F Reserved + */ +#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +#define WIN_STANDBYNOW2 0x94 +#define WIN_STANDBY2 0x96 +#define WIN_SETIDLE2 0x97 +#define WIN_CHECKPOWERMODE2 0x98 +#define WIN_SLEEPNOW2 0x99 +/* + * 0x9A VENDOR + */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +#define CFA_ERASE_SECTORS 0xC0 +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +#define WIN_GETMEDIASTATUS 0xDA +#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ +#define WIN_POSTBOOT 0xDC +#define WIN_PREBOOT 0xDD +#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ + /* SET_FEATURES 0x22 or 0xDD */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED +#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define EXABYTE_ENABLE_NEST 0xF0 +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define WIN_SECURITY_DISABLE 0xF6 +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +#define DISABLE_SEAGATE 0xFB + +/* set to 1 set disable mult support */ +#define MAX_MULT_SECTORS 16 + +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define GPCMD_BLANK 0xa1 +#define GPCMD_CLOSE_TRACK 0x5b +#define GPCMD_FLUSH_CACHE 0x35 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_GET_PERFORMANCE 0xac +#define GPCMD_INQUIRY 0x12 +#define GPCMD_LOAD_UNLOAD 0xa6 +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TI 0x48 +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_CDVD_CAPACITY 0x25 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_READ_DISC_INFO 0x51 +#define GPCMD_READ_DVD_STRUCTURE 0xad +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REPAIR_RZONE_TRACK 0x58 +#define GPCMD_REPORT_KEY 0xa4 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_RESERVE_RZONE_TRACK 0x53 +#define GPCMD_SCAN 0xba +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SEND_EVENT 0xa2 +#define GPCMD_SEND_KEY 0xa3 +#define GPCMD_SEND_OPC 0x54 +#define GPCMD_SET_READ_AHEAD 0xa7 +#define GPCMD_SET_STREAMING 0xb6 +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_WRITE_10 0x2a +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +/* This is listed as optional in ATAPI 2.6, but is (curiously) + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji + * Table 377 as an MMC command for SCSi devices though... Most ATAPI + * drives support it. */ +#define GPCMD_SET_SPEED 0xbb +/* This seems to be a SCSI specific CD-ROM opcode + * to play data at track/index */ +#define GPCMD_PLAYAUDIO_TI 0x48 +/* + * From MS Media Status Notification Support Specification. For + * older drives only. + */ +#define GPCMD_GET_MEDIA_STATUS 0xda + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_AUDIO_CTL_PAGE 0x0e +#define GPMODE_POWER_PAGE 0x1a +#define GPMODE_FAULT_FAIL_PAGE 0x1c +#define GPMODE_TO_PROTECT_PAGE 0x1d +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f +/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor + * of MODE_SENSE_POWER_PAGE */ +#define GPMODE_CDROM_PAGE 0x0d + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG 0xf8 + +/* same constants as bochs */ +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LOGICAL_BLOCK_OOR 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 + +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +struct IDEState; + +typedef void EndTransferFunc(struct IDEState *); + +/* NOTE: IDEState represents in fact one drive */ +typedef struct IDEState { + /* ide config */ + int is_cdrom; + int cylinders, heads, sectors; + int64_t nb_sectors; + int mult_sectors; + int identify_set; + uint16_t identify_data[256]; + SetIRQFunc *set_irq; + void *irq_opaque; + int irq; + //* PCIDevice *pci_dev; + struct BMDMAState *bmdma; + int drive_serial; + /* ide regs */ + uint8_t feature; + uint8_t error; + uint32_t nsector; + uint8_t sector; + uint8_t lcyl; + uint8_t hcyl; + /* other part of tf for lba48 support */ + uint8_t hob_feature; + uint8_t hob_nsector; + uint8_t hob_sector; + uint8_t hob_lcyl; + uint8_t hob_hcyl; + + uint8_t select; + uint8_t status; + + /* 0x3f6 command, only meaningful for drive 0 */ + uint8_t cmd; + /* set for lba48 access */ + uint8_t lba48; + /* depends on bit 4 in select, only meaningful for drive 0 */ + struct IDEState *cur_drive; + BlockDriverState *bs; + /* ATAPI specific */ + uint8_t sense_key; + uint8_t asc; + int packet_transfer_size; + int elementary_transfer_size; + int io_buffer_index; + int lba; + int cd_sector_size; + int atapi_dma; /* true if dma is requested for the packet cmd */ + /* ATA DMA state */ + int io_buffer_size; + /* PIO transfer handling */ + int req_nb_sectors; /* number of sectors per interrupt */ + EndTransferFunc *end_transfer_func; + uint8_t *data_ptr; + uint8_t *data_end; + uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; + QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ + uint32_t irq_count; /* counts IRQs when using win2k install hack */ +} IDEState; + +#define BM_STATUS_DMAING 0x01 +#define BM_STATUS_ERROR 0x02 +#define BM_STATUS_INT 0x04 + +#define BM_CMD_START 0x01 +#define BM_CMD_READ 0x08 + +#define IDE_TYPE_PIIX3 0 +#define IDE_TYPE_CMD646 1 + +/* CMD646 specific */ +#define MRDMODE 0x71 +#define MRDMODE_INTR_CH0 0x04 +#define MRDMODE_INTR_CH1 0x08 +#define MRDMODE_BLK_CH0 0x10 +#define MRDMODE_BLK_CH1 0x20 +#define UDIDETCR0 0x73 +#define UDIDETCR1 0x7B + +typedef struct BMDMAState { + uint8_t cmd; + uint8_t status; + uint32_t addr; + + // struct PCIIDEState *pci_dev; + /* current transfer state */ + uint32_t cur_addr; + uint32_t cur_prd_last; + uint32_t cur_prd_addr; + uint32_t cur_prd_len; + IDEState *ide_if; + BlockDriverCompletionFunc *dma_cb; + BlockDriverAIOCB *aiocb; +} BMDMAState; +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + int media_changed; + + /* async read/write emulation */ + + void *sync_aiocb; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs, translation; + int type; + char device_name[32]; +}; +#if 0 +typedef struct PCIIDEState { + PCIDevice dev; + IDEState ide_if[4]; + BMDMAState bmdma[2]; + int type; /* see IDE_TYPE_xxx */ +} PCIIDEState; +#endif +static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); + +void cpu_physical_memory_write(u32 addr,void* ptr,u32 sz); +void cpu_physical_memory_read(u32 addr,void* ptr,u32 sz); + +static void padstr(char *str, const char *src, int len) +{ + int i, v; + for(i = 0; i < len; i++) { + if (*src) + v = *src++; + else + v = ' '; + *(char *)((long)str ^ 1) = v; + str++; + } +} + +static void padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + for(i = 0; i < buf_size; i++) { + if (*src) + buf[i] = *src++; + else + buf[i] = ' '; + } +} + +static void put_le16(uint16_t *p, unsigned int v) +{ + *p = (v); +} + +static void ide_identify(IDEState *s) +{ + uint16_t *p; + unsigned int oldsize; + char buf[20]; + + if (s->identify_set) { + memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); + return; + } + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + put_le16(p + 0, 0x0040); + put_le16(p + 1, s->cylinders); + put_le16(p + 3, s->heads); + put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ + put_le16(p + 5, 512); /* XXX: retired, remove ? */ + put_le16(p + 6, s->sectors); + snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); + padstr((char *)(p + 10), buf, 20); /* serial number */ + put_le16(p + 20, 3); /* XXX: retired, remove ? */ + put_le16(p + 21, 512); /* cache size in sectors */ + put_le16(p + 22, 4); /* ecc bytes */ + padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */ +#if MAX_MULT_SECTORS > 1 + put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); +#endif + put_le16(p + 48, 1); /* dword I/O */ + put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */ + put_le16(p + 51, 0x200); /* PIO transfer cycle */ + put_le16(p + 52, 0x200); /* DMA transfer cycle */ + put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ + put_le16(p + 54, s->cylinders); + put_le16(p + 55, s->heads); + put_le16(p + 56, s->sectors); + oldsize = s->cylinders * s->heads * s->sectors; + put_le16(p + 57, oldsize); + put_le16(p + 58, oldsize >> 16); + if (s->mult_sectors) + put_le16(p + 59, 0x100 | s->mult_sectors); + put_le16(p + 60, s->nb_sectors); + put_le16(p + 61, s->nb_sectors >> 16); + put_le16(p + 63, 0x07); /* mdma0-2 supported */ + put_le16(p + 65, 120); + put_le16(p + 66, 120); + put_le16(p + 67, 120); + put_le16(p + 68, 120); + put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ + put_le16(p + 81, 0x16); /* conforms to ata5 */ + put_le16(p + 82, (1 << 14)); + /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ + put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); + put_le16(p + 84, (1 << 14)); + put_le16(p + 85, (1 << 14)); + /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ + put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); + put_le16(p + 87, (1 << 14)); + put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ + put_le16(p + 93, 1 | (1 << 14) | 0x2000); + put_le16(p + 100, s->nb_sectors); + put_le16(p + 101, s->nb_sectors >> 16); + put_le16(p + 102, s->nb_sectors >> 32); + put_le16(p + 103, s->nb_sectors >> 48); + + memcpy(s->identify_data, p, sizeof(s->identify_data)); + s->identify_set = 1; +} + +static void ide_atapi_identify(IDEState *s) +{ + uint16_t *p; + char buf[20]; + + if (s->identify_set) { + memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); + return; + } + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + /* Removable CDROM, 50us response, 12 byte packets */ + put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); + snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); + padstr((char *)(p + 10), buf, 20); /* serial number */ + put_le16(p + 20, 3); /* buffer type */ + put_le16(p + 21, 512); /* cache size in sectors */ + put_le16(p + 22, 4); /* ecc bytes */ + padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 27), "QEMU CD-ROM", 40); /* model */ + put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ +#ifdef USE_DMA_CDROM + put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ + put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */ + put_le16(p + 63, 7); /* mdma0-2 supported */ + put_le16(p + 64, 0x3f); /* PIO modes supported */ +#else + put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ + put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ + put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ + put_le16(p + 64, 1); /* PIO modes */ +#endif + put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ + put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ + put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ + put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ + + put_le16(p + 71, 30); /* in ns */ + put_le16(p + 72, 30); /* in ns */ + + put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ +#ifdef USE_DMA_CDROM + put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ +#endif + memcpy(s->identify_data, p, sizeof(s->identify_data)); + s->identify_set = 1; +} + +static void ide_set_signature(IDEState *s) +{ + s->select &= 0xf0; /* clear head */ + /* put signature */ + s->nsector = 1; + s->sector = 1; + if (s->is_cdrom) { + s->lcyl = 0x14; + s->hcyl = 0xeb; + } else if (s->bs) { + s->lcyl = 0; + s->hcyl = 0; + } else { + s->lcyl = 0xff; + s->hcyl = 0xff; + } +} + +static inline void ide_abort_command(IDEState *s) +{ + s->status = READY_STAT | ERR_STAT; + s->error = ABRT_ERR; +} + +static inline void ide_set_irq(IDEState *s) +{ + BMDMAState *bm = s->bmdma; + if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { + if (bm) { + bm->status |= BM_STATUS_INT; + } + s->set_irq(s->irq_opaque, s->irq, 1); + } +} + +/* prepare data transfer and tell what to do after */ +static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, + EndTransferFunc *end_transfer_func) +{ + s->end_transfer_func = end_transfer_func; + s->data_ptr = buf; + s->data_end = buf + size; + s->status |= DRQ_STAT; +} + +static void ide_transfer_stop(IDEState *s) +{ + s->end_transfer_func = ide_transfer_stop; + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer; + s->status &= ~DRQ_STAT; +} + +static int64_t ide_get_sector(IDEState *s) +{ + int64_t sector_num; + if (s->select & 0x40) { + /* lba */ + if (!s->lba48) { + sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | + (s->lcyl << 8) | s->sector; + } else { + sector_num = ((int64_t)s->hob_hcyl << 40) | + ((int64_t) s->hob_lcyl << 32) | + ((int64_t) s->hob_sector << 24) | + ((int64_t) s->hcyl << 16) | + ((int64_t) s->lcyl << 8) | s->sector; + } + } else { + sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + + (s->select & 0x0f) * s->sectors + (s->sector - 1); + } + return sector_num; +} + +static void ide_set_sector(IDEState *s, int64_t sector_num) +{ + unsigned int cyl, r; + if (s->select & 0x40) { + if (!s->lba48) { + s->select = (s->select & 0xf0) | (sector_num >> 24); + s->hcyl = (sector_num >> 16); + s->lcyl = (sector_num >> 8); + s->sector = (sector_num); + } else { + s->sector = sector_num; + s->lcyl = sector_num >> 8; + s->hcyl = sector_num >> 16; + s->hob_sector = sector_num >> 24; + s->hob_lcyl = sector_num >> 32; + s->hob_hcyl = sector_num >> 40; + } + } else { + cyl = sector_num / (s->heads * s->sectors); + r = sector_num % (s->heads * s->sectors); + s->hcyl = cyl >> 8; + s->lcyl = cyl; + s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f); + s->sector = (r % s->sectors) + 1; + } +} + +static void ide_sector_read(IDEState *s) +{ + int64_t sector_num; + int ret, n; + + s->status = READY_STAT | SEEK_STAT; + s->error = 0; /* not needed by IDE spec, but needed by Windows */ + sector_num = ide_get_sector(s); + n = s->nsector; + if (n == 0) { + /* no more sector to read from disk */ + ide_transfer_stop(s); + } else { +#if defined(DEBUG_IDE) + // printf("read sector=%Ld\n", sector_num); +#endif + printf("ATA: read sector=%Ld\n", sector_num); + + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); + ide_set_irq(s); + ide_set_sector(s, sector_num + n); + s->nsector -= n; + } +} + +/* return 0 if buffer completed */ +static int dma_buf_rw(BMDMAState *bm, int is_write) +{ + IDEState *s = bm->ide_if; + struct { + uint32_t addr; + uint32_t size; + } prd; + int l, len; + + for(;;) { + l = s->io_buffer_size - s->io_buffer_index; + if (l <= 0) + break; + if (bm->cur_prd_len == 0) { + /* end of table (with a fail safe of one page) */ + if (bm->cur_prd_last || + (bm->cur_addr - bm->addr) >= 4096) + return 0; + emu_printf("dma seems to have ended .. duno what the code i removed from here does.. chan dma ?\n"); + return 2; + /* + ///i wonder what is this + //lets hope its not bad to remove it here xD + cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); + bm->cur_addr += 8; + prd.addr = le32_to_cpu(prd.addr); + prd.size = le32_to_cpu(prd.size); + len = prd.size & 0xfffe; + if (len == 0) + len = 0x10000; + bm->cur_prd_len = len; + bm->cur_prd_addr = prd.addr; + bm->cur_prd_last = (prd.size & 0x80000000);*/ + } + if (l > bm->cur_prd_len) + l = bm->cur_prd_len; + if (l > 0) { + if (is_write) { + cpu_physical_memory_write(bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); + } else { + cpu_physical_memory_read(bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); + } + bm->cur_prd_addr += l; + bm->cur_prd_len -= l; + s->io_buffer_index += l; + } + } + return 1; +} + +/* XXX: handle errors */ +static void ide_read_dma_cb(void *opaque, int ret) +{ + BMDMAState* bm = (BMDMAState* )opaque; + IDEState *s = (IDEState*)bm->ide_if; + int n; + int64_t sector_num; + + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); + if (n > 0) { + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; + int dmrv=dma_buf_rw(bm, 1); + if ( dmrv== 0) + goto eot; + else if (dmrv==2) + { + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + return; //end of dma buffer (ha !) + } + } + + /* end of transfer ? */ + if (s->nsector == 0) { + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; + } + + /* launch next transfer */ + n = s->nsector; + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; +#ifdef DEBUG_AIO + printf("aio_read: sector_num=%lld n=%d\n", sector_num, n); +#endif + bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, + ide_read_dma_cb, bm); +} + +static void ide_sector_read_dma(IDEState *s) +{ + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; + s->io_buffer_index = 0; + s->io_buffer_size = 0; + ide_dma_start(s, ide_read_dma_cb); +} + +static void ide_sector_write_timer_cb(void *opaque) +{ + IDEState* s = (IDEState*)opaque; + ide_set_irq(s); +} + +static void ide_sector_write(IDEState *s) +{ + int64_t sector_num; + int ret, n, n1; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); +#if defined(DEBUG_IDE) + printf("write sector=%Ld\n", sector_num); +#endif + printf("ATA: write sector=%Ld\n", sector_num); + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + s->nsector -= n; + if (s->nsector == 0) { + /* no more sector to write */ + ide_transfer_stop(s); + } else { + n1 = s->nsector; + if (n1 > s->req_nb_sectors) + n1 = s->req_nb_sectors; + ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); + } + ide_set_sector(s, sector_num + n); + +#ifdef TARGET_I386 + if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { + /* It seems there is a bug in the Windows 2000 installer HDD + IDE driver which fills the disk with empty logs when the + IDE write IRQ comes too early. This hack tries to correct + that at the expense of slower write performances. Use this + option _only_ to install Windows 2000. You must disable it + for normal use. */ + qemu_mod_timer(s->sector_write_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); + } else +#endif + { + ide_set_irq(s); + } +} + +/* XXX: handle errors */ +static void ide_write_dma_cb(void *opaque, int ret) +{ + BMDMAState* bm =(BMDMAState*)opaque; + IDEState* s =(IDEState* ) bm->ide_if; + int n; + int64_t sector_num; + + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); + if (n > 0) { + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; + } + + /* end of transfer ? */ + if (s->nsector == 0) { + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; + } + + /* launch next transfer */ + n = s->nsector; + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; + + int dmrv=dma_buf_rw(bm, 0); + if ( dmrv== 0) + goto eot; + else if (dmrv==2) + { + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + return; //end of dma buffer (ha !) + } + +#ifdef DEBUG_AIO + printf("aio_write: sector_num=%lld n=%d\n", sector_num, n); +#endif + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, + ide_write_dma_cb, bm); +} + +static void ide_sector_write_dma(IDEState *s) +{ + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; + s->io_buffer_index = 0; + s->io_buffer_size = 0; + ide_dma_start(s, ide_write_dma_cb); +} + +static void ide_atapi_cmd_ok(IDEState *s) +{ + s->error = 0; + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +} + +static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) +{ +#ifdef DEBUG_IDE_ATAPI + //printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); +#endif + printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); + s->error = sense_key << 4; + s->status = READY_STAT | ERR_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + s->sense_key = sense_key; + s->asc = asc; + ide_set_irq(s); +} + +static inline void cpu_to_ube16(uint8_t *buf, int val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + +static inline int ube16_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static inline int ube32_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +static void cd_data_to_raw(uint8_t *buf, int lba) +{ + /* sync bytes */ + buf[0] = 0x00; + memset(buf + 1, 0xff, 10); + buf[11] = 0x00; + buf += 12; + /* MSF */ + lba_to_msf(buf, lba); + buf[3] = 0x01; /* mode 1 data */ + buf += 4; + /* data */ + buf += 2048; + /* XXX: ECC not computed */ + memset(buf, 0, 288); +} + +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, + int sector_size) +{ + int ret; + + switch(sector_size) { + case 2048: + ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); + break; + case 2352: + ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + if (ret < 0) + return ret; + cd_data_to_raw(buf, lba); + break; + default: + ret = -EIO; + break; + } + return ret; +} + +static void ide_atapi_io_error(IDEState *s, int ret) +{ + /* XXX: handle more errors */ + if (ret == -ENOMEDIUM) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } else { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + } +} + +/* The whole ATAPI transfer logic is handled in this function */ +static void ide_atapi_cmd_reply_end(IDEState *s) +{ + int byte_count_limit, size, ret; +#ifdef DEBUG_IDE_ATAPI + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", + s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); +#endif + if (s->packet_transfer_size <= 0) { + /* end of transfer */ + ide_transfer_stop(s); + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } else { + /* see if a new sector must be read */ + if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + if (ret < 0) { + ide_transfer_stop(s); + ide_atapi_io_error(s, ret); + return; + } + s->lba++; + s->io_buffer_index = 0; + } + if (s->elementary_transfer_size > 0) { + /* there are some data left to transmit in this elementary + transfer */ + size = s->cd_sector_size - s->io_buffer_index; + if (size > s->elementary_transfer_size) + size = s->elementary_transfer_size; + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + } else { + /* a new transfer is needed */ + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + byte_count_limit = s->lcyl | (s->hcyl << 8); +#ifdef DEBUG_IDE_ATAPI + printf("byte_count_limit=%d\n", byte_count_limit); +#endif + if (byte_count_limit == 0xffff) + byte_count_limit--; + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) + byte_count_limit--; + size = byte_count_limit; + } + s->lcyl = size; + s->hcyl = size >> 8; + s->elementary_transfer_size = size; + /* we cannot transmit more than one sector at a time */ + if (s->lba != -1) { + if (size > (s->cd_sector_size - s->io_buffer_index)) + size = (s->cd_sector_size - s->io_buffer_index); + } + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } + } +} + +/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ +static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) +{ + if (size > max_size) + size = max_size; + s->lba = -1; /* no sector read */ + s->packet_transfer_size = size; + s->io_buffer_size = size; /* dma: send the reply data as one chunk */ + s->elementary_transfer_size = 0; + s->io_buffer_index = 0; + + if (s->atapi_dma) { + s->status = READY_STAT | DRQ_STAT; + ide_dma_start(s, ide_atapi_cmd_read_dma_cb); + } else { + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); + } +} + +/* start a CD-CDROM read command */ +static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ + s->lba = lba; + s->packet_transfer_size = nb_sectors * sector_size; + s->elementary_transfer_size = 0; + s->io_buffer_index = sector_size; + s->cd_sector_size = sector_size; + + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); +} + +/* ATAPI DMA support */ + +/* XXX: handle read errors */ +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) +{ + BMDMAState* bm =(BMDMAState*) opaque; + IDEState* s =(IDEState*) bm->ide_if; + int data_offset, n; + + if (ret < 0) { + ide_atapi_io_error(s, ret); + goto eot; + } + + if (s->io_buffer_size > 0) { + /* + * For a cdrom read sector command (s->lba != -1), + * adjust the lba for the next s->io_buffer_size chunk + * and dma the current chunk. + * For a command != read (s->lba == -1), just transfer + * the reply data. + */ + if (s->lba != -1) { + if (s->cd_sector_size == 2352) { + n = 1; + cd_data_to_raw(s->io_buffer, s->lba); + } else { + n = s->io_buffer_size >> 11; + } + s->lba += n; + } + s->packet_transfer_size -= s->io_buffer_size; + if (dma_buf_rw(bm, 1) == 0) + goto eot; + } + + if (s->packet_transfer_size <= 0) { + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; + } + + s->io_buffer_index = 0; + if (s->cd_sector_size == 2352) { + n = 1; + s->io_buffer_size = s->cd_sector_size; + data_offset = 16; + } else { + n = s->packet_transfer_size >> 11; + if (n > (MAX_MULT_SECTORS / 4)) + n = (MAX_MULT_SECTORS / 4); + s->io_buffer_size = n * 2048; + data_offset = 0; + } +#ifdef DEBUG_AIO + printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); +#endif + bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, + s->io_buffer + data_offset, n * 4, + ide_atapi_cmd_read_dma_cb, bm); + if (!bm->aiocb) { + /* Note: media not present is the most likely case */ + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + goto eot; + } +} + +/* start a CD-CDROM read command with DMA */ +/* XXX: test if DMA is available */ +static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ + s->lba = lba; + s->packet_transfer_size = nb_sectors * sector_size; + s->io_buffer_index = 0; + s->io_buffer_size = 0; + s->cd_sector_size = sector_size; + + /* XXX: check if BUSY_STAT should be set */ + s->status = READY_STAT | DRQ_STAT | BUSY_STAT; + ide_dma_start(s, ide_atapi_cmd_read_dma_cb); +} + +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ +#ifdef DEBUG_IDE_ATAPI + printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", + lba, nb_sectors); +#endif + if (s->atapi_dma) { + ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); + } else { + ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); + } +} + +static void ide_atapi_cmd(IDEState *s) +{ + const uint8_t *packet; + uint8_t *buf; + int max_len; + + packet = s->io_buffer; + buf = s->io_buffer; +#ifdef DEBUG_IDE_ATAPI + { + int i; + printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); + for(i = 0; i < ATAPI_PACKET_SIZE; i++) { + printf(" %02x", packet[i]); + } + printf("\n"); + } +#endif + switch(s->io_buffer[0]) { + case GPCMD_TEST_UNIT_READY: + if (bdrv_is_inserted(s->bs)) { + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_MODE_SENSE_10: + { + int action, code; + max_len = ube16_to_cpu(packet + 7); + action = packet[2] >> 6; + code = packet[2] & 0x3f; + switch(action) { + case 0: /* current values */ + switch(code) { + case 0x01: /* error recovery */ + cpu_to_ube16(&buf[0], 16 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x01; + buf[9] = 0x06; + buf[10] = 0x00; + buf[11] = 0x05; + buf[12] = 0x00; + buf[13] = 0x00; + buf[14] = 0x00; + buf[15] = 0x00; + ide_atapi_cmd_reply(s, 16, max_len); + break; + case 0x2a: + cpu_to_ube16(&buf[0], 28 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x2a; + buf[9] = 0x12; + buf[10] = 0x00; + buf[11] = 0x00; + + buf[12] = 0x70; + buf[13] = 3 << 5; + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); + if (bdrv_is_locked(s->bs)) + buf[6] |= 1 << 1; + buf[15] = 0x00; + cpu_to_ube16(&buf[16], 706); + buf[18] = 0; + buf[19] = 2; + cpu_to_ube16(&buf[20], 512); + cpu_to_ube16(&buf[22], 706); + buf[24] = 0; + buf[25] = 0; + buf[26] = 0; + buf[27] = 0; + ide_atapi_cmd_reply(s, 28, max_len); + break; + default: + goto error_cmd; + } + break; + case 1: /* changeable values */ + goto error_cmd; + case 2: /* default values */ + goto error_cmd; + default: + case 3: /* saved values */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); + break; + } + } + break; + case GPCMD_REQUEST_SENSE: + max_len = packet[4]; + memset(buf, 0, 18); + buf[0] = 0x70 | (1 << 7); + buf[2] = s->sense_key; + buf[7] = 10; + buf[12] = s->asc; + ide_atapi_cmd_reply(s, 18, max_len); + break; + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + if (bdrv_is_inserted(s->bs)) { + bdrv_set_locked(s->bs, packet[4] & 1); + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_READ_10: + case GPCMD_READ_12: + { + int nb_sectors, lba; + + if (packet[0] == GPCMD_READ_10) + nb_sectors = ube16_to_cpu(packet + 7); + else + nb_sectors = ube32_to_cpu(packet + 6); + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + } + break; + case GPCMD_READ_CD: + { + int nb_sectors, lba, transfer_request; + + nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + transfer_request = packet[9]; + switch(transfer_request & 0xf8) { + case 0x00: + /* nothing */ + ide_atapi_cmd_ok(s); + break; + case 0x10: + /* normal read */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + break; + case 0xf8: + /* read all data */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2352); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_SEEK: + { + int lba; + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + lba = ube32_to_cpu(packet + 2); + if (lba >= total_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_START_STOP_UNIT: + { + int start, eject; + start = packet[4] & 1; + eject = (packet[4] >> 1) & 1; + + if (eject && !start) { + /* eject the disk */ + bdrv_eject(s->bs, 1); + } else if (eject && start) { + /* close the tray */ + bdrv_eject(s->bs, 0); + } + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_MECHANISM_STATUS: + { + max_len = ube16_to_cpu(packet + 8); + cpu_to_ube16(buf, 0); + /* no current LBA */ + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; + cpu_to_ube16(buf + 6, 0); + ide_atapi_cmd_reply(s, 8, max_len); + } + break; + case GPCMD_READ_TOC_PMA_ATIP: + { + int format, msf, start_track, len; + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + max_len = ube16_to_cpu(packet + 7); + format = packet[9] >> 6; + msf = (packet[1] >> 1) & 1; + start_track = packet[6]; + switch(format) { + case 0: + emu_printf("CDROM ?TOC?\n"); + len = -1;//cdrom_read_toc(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + ide_atapi_cmd_reply(s, 12, max_len); + break; + case 2: + emu_printf("CDROM ?TOC?\n"); + len = -1;// + // len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + default: + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_READ_CDVD_CAPACITY: + { + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, total_sectors - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); + } + break; + case GPCMD_INQUIRY: + max_len = packet[4]; + buf[0] = 0x05; /* CD-ROM */ + buf[1] = 0x80; /* removable */ + buf[2] = 0x00; /* ISO */ + buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ + buf[4] = 31; /* additionnal length */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* reserved */ + padstr8(buf + 8, 8, "QEMU"); + padstr8(buf + 16, 16, "QEMU CD-ROM"); + padstr8(buf + 32, 4, QEMU_VERSION); + ide_atapi_cmd_reply(s, 36, max_len); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_ILLEGAL_OPCODE); + break; + } +} + +/* called when the inserted state of the media has changed */ +static void cdrom_change_cb(void *opaque) +{ + IDEState* s = (IDEState*)opaque; + int64_t nb_sectors; + + /* XXX: send interrupt too */ + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; +} + +static void ide_cmd_lba48_transform(IDEState *s, int lba48) +{ + s->lba48 = lba48; + + /* handle the 'magic' 0 nsector count conversion here. to avoid + * fiddling with the rest of the read logic, we just store the + * full sector count in ->nsector and ignore ->hob_nsector from now + */ + if (!s->lba48) { + if (!s->nsector) + s->nsector = 256; + } else { + if (!s->nsector && !s->hob_nsector) + s->nsector = 65536; + else { + int lo = s->nsector; + int hi = s->hob_nsector; + + s->nsector = (hi << 8) | lo; + } + } +} + +static void ide_clear_hob(IDEState *ide_if) +{ + /* any write clears HOB high bit of device control register */ + ide_if[0].select &= ~(1 << 7); + ide_if[1].select &= ~(1 << 7); +} + +static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + IDEState *ide_if =(IDEState*)opaque; + IDEState *s; + int unit, n; + int lba48 = 0; + +#ifdef DEBUG_IDE + printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); +#endif + + addr &= 7; + switch(addr) { + case 0: + break; + case 1: + ide_clear_hob(ide_if); + /* NOTE: data is written to the two drives */ + ide_if[0].hob_feature = ide_if[0].feature; + ide_if[1].hob_feature = ide_if[1].feature; + ide_if[0].feature = val; + ide_if[1].feature = val; + break; + case 2: + ide_clear_hob(ide_if); + ide_if[0].hob_nsector = ide_if[0].nsector; + ide_if[1].hob_nsector = ide_if[1].nsector; + ide_if[0].nsector = val; + ide_if[1].nsector = val; + break; + case 3: + ide_clear_hob(ide_if); + ide_if[0].hob_sector = ide_if[0].sector; + ide_if[1].hob_sector = ide_if[1].sector; + ide_if[0].sector = val; + ide_if[1].sector = val; + break; + case 4: + ide_clear_hob(ide_if); + ide_if[0].hob_lcyl = ide_if[0].lcyl; + ide_if[1].hob_lcyl = ide_if[1].lcyl; + ide_if[0].lcyl = val; + ide_if[1].lcyl = val; + break; + case 5: + ide_clear_hob(ide_if); + ide_if[0].hob_hcyl = ide_if[0].hcyl; + ide_if[1].hob_hcyl = ide_if[1].hcyl; + ide_if[0].hcyl = val; + ide_if[1].hcyl = val; + break; + case 6: + /* FIXME: HOB readback uses bit 7 */ + ide_if[0].select = (val & ~0x10) | 0xa0; + ide_if[1].select = (val | 0x10) | 0xa0; + /* select drive */ + unit = (val >> 4) & 1; + s = ide_if + unit; + ide_if->cur_drive = s; + break; + default: + case 7: + /* command */ +#if defined(DEBUG_IDE) + printf("ide: CMD=%02x\n", val); +#endif + s = ide_if->cur_drive; + /* ignore commands to non existant slave */ + if (s != ide_if && !s->bs) + break; + + switch(val) { + case WIN_IDENTIFY: + if (s->bs && !s->is_cdrom) { + ide_identify(s); + s->status = READY_STAT | SEEK_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); + } else { + if (s->is_cdrom) { + ide_set_signature(s); + } + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_SPECIFY: + case WIN_RECAL: + s->error = 0; + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + break; + case WIN_SETMULT: + if (s->nsector > MAX_MULT_SECTORS || + s->nsector == 0 || + (s->nsector & (s->nsector - 1)) != 0) { + ide_abort_command(s); + } else { + s->mult_sectors = s->nsector; + s->status = READY_STAT; + } + ide_set_irq(s); + break; + case WIN_VERIFY_EXT: + lba48 = 1; + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + /* do sector number check ? */ + ide_cmd_lba48_transform(s, lba48); + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_READ_EXT: + lba48 = 1; + case WIN_READ: + case WIN_READ_ONCE: + if (!s->bs) + goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); + s->req_nb_sectors = 1; + ide_sector_read(s); + break; + case WIN_WRITE_EXT: + lba48 = 1; + case WIN_WRITE: + case WIN_WRITE_ONCE: + ide_cmd_lba48_transform(s, lba48); + s->error = 0; + s->status = SEEK_STAT | READY_STAT; + s->req_nb_sectors = 1; + ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); + break; + case WIN_MULTREAD_EXT: + lba48 = 1; + case WIN_MULTREAD: + if (!s->mult_sectors) + goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); + s->req_nb_sectors = s->mult_sectors; + ide_sector_read(s); + break; + case WIN_MULTWRITE_EXT: + lba48 = 1; + case WIN_MULTWRITE: + if (!s->mult_sectors) + goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); + s->error = 0; + s->status = SEEK_STAT | READY_STAT; + s->req_nb_sectors = s->mult_sectors; + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); + break; + case WIN_READDMA_EXT: + lba48 = 1; + case WIN_READDMA: + case WIN_READDMA_ONCE: + if (!s->bs) + goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); + ide_sector_read_dma(s); + break; + case WIN_WRITEDMA_EXT: + lba48 = 1; + case WIN_WRITEDMA: + case WIN_WRITEDMA_ONCE: + if (!s->bs) + goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); + ide_sector_write_dma(s); + break; + case WIN_READ_NATIVE_MAX_EXT: + lba48 = 1; + case WIN_READ_NATIVE_MAX: + ide_cmd_lba48_transform(s, lba48); + ide_set_sector(s, s->nb_sectors - 1); + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_CHECKPOWERMODE1: + s->nsector = 0xff; /* device active or idle */ + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_SETFEATURES: + if (!s->bs) + goto abort_cmd; + /* XXX: valid for CDROM ? */ + switch(s->feature) { + case 0x02: /* write cache enable */ + case 0x82: /* write cache disable */ + case 0xaa: /* read look-ahead enable */ + case 0x55: /* read look-ahead disable */ + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + break; + case 0x03: { /* set transfer mode */ + uint8_t val = s->nsector & 0x07; + + switch (s->nsector >> 3) { + case 0x00: /* pio default */ + case 0x01: /* pio mode */ + put_le16(s->identify_data + 63,0x07); + put_le16(s->identify_data + 88,0x3f); + break; + case 0x04: /* mdma mode */ + put_le16(s->identify_data + 63,0x07 | (1 << (val + 8))); + put_le16(s->identify_data + 88,0x3f); + break; + case 0x08: /* udma mode */ + put_le16(s->identify_data + 63,0x07); + put_le16(s->identify_data + 88,0x3f | (1 << (val + 8))); + break; + default: + goto abort_cmd; + } + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + break; + } + default: + goto abort_cmd; + } + break; + case WIN_FLUSH_CACHE: + case WIN_FLUSH_CACHE_EXT: + if (s->bs) + bdrv_flush(s->bs); + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_STANDBYNOW1: + case WIN_IDLEIMMEDIATE: + s->status = READY_STAT; + ide_set_irq(s); + break; + /* ATAPI commands */ + case WIN_PIDENTIFY: + if (s->is_cdrom) { + ide_atapi_identify(s); + s->status = READY_STAT | SEEK_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); + } else { + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_DIAGNOSE: + ide_set_signature(s); + s->status = 0x00; /* NOTE: READY is _not_ set */ + s->error = 0x01; + break; + case WIN_SRST: + if (!s->is_cdrom) + goto abort_cmd; + ide_set_signature(s); + s->status = 0x00; /* NOTE: READY is _not_ set */ + s->error = 0x01; + break; + case WIN_PACKETCMD: + if (!s->is_cdrom) + goto abort_cmd; + /* overlapping commands not supported */ + if (s->feature & 0x02) + goto abort_cmd; + s->atapi_dma = s->feature & 1; + s->nsector = 1; + ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, + ide_atapi_cmd); + break; + default: + abort_cmd: + ide_abort_command(s); + ide_set_irq(s); + break; + } + } +} + +static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) +{ + IDEState *ide_if = (IDEState*)opaque; + IDEState *s = (IDEState*)ide_if->cur_drive; + uint32_t addr; + int ret, hob; + + addr = addr1 & 7; + /* FIXME: HOB readback uses bit 7, but it's always set right now */ + //hob = s->select & (1 << 7); + hob = 0; + switch(addr) { + case 0: + ret = 0xff; + break; + case 1: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else if (!hob) + ret = s->error; + else + ret = s->hob_feature; + break; + case 2: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else if (!hob) + ret = s->nsector & 0xff; + else + ret = s->hob_nsector; + break; + case 3: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else if (!hob) + ret = s->sector; + else + ret = s->hob_sector; + break; + case 4: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else if (!hob) + ret = s->lcyl; + else + ret = s->hob_lcyl; + break; + case 5: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else if (!hob) + ret = s->hcyl; + else + ret = s->hob_hcyl; + break; + case 6: + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else + ret = s->select; + break; + default: + case 7: + if ((!ide_if[0].bs && !ide_if[1].bs) || + (s != ide_if && !s->bs)) + ret = 0; + else + ret = s->status; + s->set_irq(s->irq_opaque, s->irq, 0); + break; + } +#ifdef DEBUG_IDE + printf("ide: read addr=0x%x val=%02x\n", addr1, ret); +#endif + return ret; +} + +static uint32_t ide_status_read(void *opaque, uint32_t addr) +{ + IDEState *ide_if =(IDEState*) opaque; + IDEState *s = (IDEState*)ide_if->cur_drive; + int ret; + + if ((!ide_if[0].bs && !ide_if[1].bs) || + (s != ide_if && !s->bs)) + ret = 0; + else + ret = s->status; +#ifdef DEBUG_IDE + printf("ide: read status addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) +{ + IDEState *ide_if = (IDEState*)opaque; + IDEState *s; + int i; + +#ifdef DEBUG_IDE + printf("ide: write control addr=0x%x val=%02x\n", addr, val); +#endif + /* common for both drives */ + if (!(ide_if[0].cmd & IDE_CMD_RESET) && + (val & IDE_CMD_RESET)) { + /* reset low to high */ + for(i = 0;i < 2; i++) { + s = &ide_if[i]; + s->status = BUSY_STAT | SEEK_STAT; + s->error = 0x01; + } + } else if ((ide_if[0].cmd & IDE_CMD_RESET) && + !(val & IDE_CMD_RESET)) { + /* high to low */ + for(i = 0;i < 2; i++) { + s = &ide_if[i]; + if (s->is_cdrom) + s->status = 0x00; /* NOTE: READY is _not_ set */ + else + s->status = READY_STAT | SEEK_STAT; + ide_set_signature(s); + } + } + + ide_if[0].cmd = val; + ide_if[1].cmd = val; +} + +static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) +{ + IDEState *s = ((IDEState *)opaque)->cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +static uint32_t ide_data_readw(void *opaque, uint32_t addr) +{ + IDEState *s = ((IDEState *)opaque)->cur_drive; + uint8_t *p; + int ret; + p = s->data_ptr; + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) +{ + IDEState *s = ((IDEState *)opaque)->cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint32_t *)p = le32_to_cpu(val); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +static uint32_t ide_data_readl(void *opaque, uint32_t addr) +{ + IDEState *s = ((IDEState *)opaque)->cur_drive; + uint8_t *p; + int ret; + + p = s->data_ptr; + ret = cpu_to_le32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +static void ide_dummy_transfer_stop(IDEState *s) +{ + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer; + s->io_buffer[0] = 0xff; + s->io_buffer[1] = 0xff; + s->io_buffer[2] = 0xff; + s->io_buffer[3] = 0xff; +} + +static void ide_reset(IDEState *s) +{ + s->mult_sectors = MAX_MULT_SECTORS; + s->cur_drive = s; + s->select = 0xa0; + s->status = READY_STAT; + ide_set_signature(s); + /* init the transfer handler so that 0xffff is returned on data + accesses */ + s->end_transfer_func = ide_dummy_transfer_stop; + ide_dummy_transfer_stop(s); +} + +#pragma pack(1) +struct partition { + uint8_t boot_ind; /* 0x80 - active */ + uint8_t head; /* starting head */ + uint8_t sector; /* starting sector */ + uint8_t cyl; /* starting cylinder */ + uint8_t sys_ind; /* What partition type */ + uint8_t end_head; /* end head */ + uint8_t end_sector; /* end sector */ + uint8_t end_cyl; /* end cylinder */ + uint32_t start_sect; /* starting sector counting from 0 */ + uint32_t nr_sects; /* nr of sectors in partition */ +} ; + +/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ +static int guess_disk_lchs(IDEState *s, + int *pcylinders, int *pheads, int *psectors) +{ + uint8_t buf[512]; + int ret, i, heads, sectors, cylinders; + struct partition *p; + uint32_t nr_sects; + + ret = bdrv_read(s->bs, 0, buf, 1); + if (ret < 0) + return -1; + /* test msdos magic */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return -1; + for(i = 0; i < 4; i++) { + p = ((struct partition *)(buf + 0x1be)) + i; + nr_sects = le32_to_cpu(p->nr_sects); + if (nr_sects && p->end_head) { + /* We make the assumption that the partition terminates on + a cylinder boundary */ + heads = p->end_head + 1; + sectors = p->end_sector & 63; + if (sectors == 0) + continue; + cylinders = s->nb_sectors / (heads * sectors); + if (cylinders < 1 || cylinders > 16383) + continue; + *pheads = heads; + *psectors = sectors; + *pcylinders = cylinders; +#if 0 + printf("guessed geometry: LCHS=%d %d %d\n", + cylinders, heads, sectors); +#endif + return 0; + } + } + return -1; +} + +static void ide_init2(IDEState *ide_state, + BlockDriverState *hd0, BlockDriverState *hd1, + SetIRQFunc *set_irq, void *irq_opaque, int irq) +{ + IDEState *s; + static int drive_serial = 1; + int i, cylinders, heads, secs, translation, lba_detected = 0; + int64_t nb_sectors; + + for(i = 0; i < 2; i++) { + s = ide_state + i; + if (i == 0) + s->bs = hd0; + else + s->bs = hd1; + if (s->bs) + { + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); + translation = bdrv_get_translation_hint(s->bs); + if (cylinders != 0) { + s->cylinders = cylinders; + s->heads = heads; + s->sectors = secs; + } + else + { + if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) + { + if (heads > 16) { + /* if heads > 16, it means that a BIOS LBA + translation was active, so the default + hardware geometry is OK */ + lba_detected = 1; + goto default_geometry; + } + else + { + s->cylinders = cylinders; + s->heads = heads; + s->sectors = secs; + /* disable any translation to be in sync with + the logical geometry */ + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_NONE); + } + } + } + else + { +default_geometry: + /* if no geometry, use a standard physical disk geometry */ + cylinders = nb_sectors / (16 * 63); + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + s->cylinders = cylinders; + s->heads = 16; + s->sectors = 63; + if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) + { + if ((s->cylinders * s->heads) <= 131072) + { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_LARGE); + } + else + { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_LBA); + } + } + } + bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); + } + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { + s->is_cdrom = 1; + bdrv_set_change_cb(s->bs, cdrom_change_cb, s); + } + } + s->drive_serial = drive_serial++; + s->set_irq = set_irq; + s->irq_opaque = irq_opaque; + s->irq = irq; + s->sector_write_timer =0;//* qemu_new_timer(vm_clock, + //* ide_sector_write_timer_cb, s); + ide_reset(s); + } +} +#if 0 +static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) +{ + register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); + register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); + if (iobase2) { + register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state); + register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state); + } + + /* data ports */ + register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state); + register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state); + register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); + register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); +} + +/***********************************************************/ +/* ISA IDE definitions */ + +void isa_ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1) +{ + IDEState *ide_state; + + ide_state = qemu_mallocz(sizeof(IDEState) * 2); + if (!ide_state) + return; + + ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq); + ide_init_ioport(ide_state, iobase, iobase2); +} + +/***********************************************************/ +/* PCI IDE definitions */ + +static void cmd646_update_irq(PCIIDEState *d); + +static void ide_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIIDEState *d = (PCIIDEState *)pci_dev; + IDEState *ide_state; + + if (region_num <= 3) { + ide_state = &d->ide_if[(region_num >> 1) * 2]; + if (region_num & 1) { + register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state); + register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state); + } else { + register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state); + register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state); + + /* data ports */ + register_ioport_write(addr, 2, 2, ide_data_writew, ide_state); + register_ioport_read(addr, 2, 2, ide_data_readw, ide_state); + register_ioport_write(addr, 4, 4, ide_data_writel, ide_state); + register_ioport_read(addr, 4, 4, ide_data_readl, ide_state); + } + } +} + +#endif +static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) +{ + BMDMAState *bm = s->bmdma; + if(!bm) + return; + bm->ide_if = s; + bm->dma_cb = dma_cb; + bm->cur_prd_last = 0; + bm->cur_prd_addr = 0; + bm->cur_prd_len = 0; + if (bm->status & BM_STATUS_DMAING) { + bm->dma_cb(bm, 0); + } +} + +#if 0 +static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm =(BMDMAState*) opaque; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + if (!(val & BM_CMD_START)) { + /* XXX: do it better */ + if (bm->status & BM_STATUS_DMAING) { + bm->status &= ~BM_STATUS_DMAING; + /* cancel DMA request */ + bm->ide_if = NULL; + bm->dma_cb = NULL; + if (bm->aiocb) { +#ifdef DEBUG_AIO + printf("aio_cancel\n"); +#endif + bdrv_aio_cancel(bm->aiocb); + bm->aiocb = NULL; + } + } + bm->cmd = val & 0x09; + } else { + if (!(bm->status & BM_STATUS_DMAING)) { + bm->status |= BM_STATUS_DMAING; + /* start dma transfer if possible */ + if (bm->dma_cb) + bm->dma_cb(bm, 0); + } + bm->cmd = val & 0x09; + } +} + +static uint32_t bmdma_readb(void *opaque, uint32_t addr) +{ + BMDMAState *bm =(BMDMAState*) opaque; + PCIIDEState *pci_dev; + uint32_t val; + + switch(addr & 3) { + case 0: + val = bm->cmd; + break; + case 1: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + val = pci_dev->dev.config[MRDMODE]; + } else { + val = 0xff; + } + break; + case 2: + val = bm->status; + break; + case 3: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + if (bm == &pci_dev->bmdma[0]) + val = pci_dev->dev.config[UDIDETCR0]; + else + val = pci_dev->dev.config[UDIDETCR1]; + } else { + val = 0xff; + } + break; + default: + val = 0xff; + break; + } +#ifdef DEBUG_IDE + printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); +#endif + return val; +} + +static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; + PCIIDEState *pci_dev; +#ifdef DEBUG_IDE + printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); +#endif + switch(addr & 3) { + case 1: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + pci_dev->dev.config[MRDMODE] = + (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); + cmd646_update_irq(pci_dev); + } + break; + case 2: + bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); + break; + case 3: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + if (bm == &pci_dev->bmdma[0]) + pci_dev->dev.config[UDIDETCR0] = val; + else + pci_dev->dev.config[UDIDETCR1] = val; + } + break; + } +} + +static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = bm->addr; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + bm->addr = val & ~3; + bm->cur_addr = bm->addr; +} + +static void bmdma_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIIDEState *d = (PCIIDEState *)pci_dev; + int i; + + for(i = 0;i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + d->ide_if[2 * i].bmdma = bm; + d->ide_if[2 * i + 1].bmdma = bm; + bm->pci_dev = (PCIIDEState *)pci_dev; + + register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); + + register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); + register_ioport_read(addr, 4, 1, bmdma_readb, bm); + + register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); + register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); + addr += 8; + } +} + + +/* XXX: call it also when the MRDMODE is changed from the PCI config + registers */ +static void cmd646_update_irq(PCIIDEState *d) +{ + int pci_level; + pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) && + !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || + ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && + !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); + pci_set_irq((PCIDevice *)d, 0, pci_level); +} + +/* the PCI irq level is the logical OR of the two channels */ +static void cmd646_set_irq(void *opaque, int channel, int level) +{ + PCIIDEState *d = opaque; + int irq_mask; + + irq_mask = MRDMODE_INTR_CH0 << channel; + if (level) + d->dev.config[MRDMODE] |= irq_mask; + else + d->dev.config[MRDMODE] &= ~irq_mask; + cmd646_update_irq(d); +} + +/* CMD646 PCI IDE controller */ +void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, + int secondary_ide_enabled) +{ + PCIIDEState *d; + uint8_t *pci_conf; + int i; + + d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", + sizeof(PCIIDEState), + -1, + NULL, NULL); + d->type = IDE_TYPE_CMD646; + pci_conf = d->dev.config; + pci_conf[0x00] = 0x95; // CMD646 + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0x46; + pci_conf[0x03] = 0x06; + + pci_conf[0x08] = 0x07; // IDE controller revision + pci_conf[0x09] = 0x8f; + + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + if (secondary_ide_enabled) { + /* XXX: if not enabled, really disable the seconday IDE controller */ + pci_conf[0x51] = 0x80; /* enable IDE1 */ + } + + pci_register_io_region((PCIDevice *)d, 0, 0x8, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 1, 0x4, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 2, 0x8, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 3, 0x4, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); + + pci_conf[0x3d] = 0x01; // interrupt on pin 1 + + for(i = 0; i < 4; i++) + d->ide_if[i].pci_dev = (PCIDevice *)d; + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + cmd646_set_irq, d, 0); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + cmd646_set_irq, d, 1); +} + +static void pci_ide_save(QEMUFile* f, void *opaque) +{ + PCIIDEState *d = opaque; + int i; + + pci_device_save(&d->dev, f); + + for(i = 0; i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + qemu_put_8s(f, &bm->cmd); + qemu_put_8s(f, &bm->status); + qemu_put_be32s(f, &bm->addr); + /* XXX: if a transfer is pending, we do not save it yet */ + } + + /* per IDE interface data */ + for(i = 0; i < 2; i++) { + IDEState *s = &d->ide_if[i * 2]; + uint8_t drive1_selected; + qemu_put_8s(f, &s->cmd); + drive1_selected = (s->cur_drive != s); + qemu_put_8s(f, &drive1_selected); + } + + /* per IDE drive data */ + for(i = 0; i < 4; i++) { + IDEState *s = &d->ide_if[i]; + qemu_put_be32s(f, &s->mult_sectors); + qemu_put_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512); + } + qemu_put_8s(f, &s->feature); + qemu_put_8s(f, &s->error); + qemu_put_be32s(f, &s->nsector); + qemu_put_8s(f, &s->sector); + qemu_put_8s(f, &s->lcyl); + qemu_put_8s(f, &s->hcyl); + qemu_put_8s(f, &s->hob_feature); + qemu_put_8s(f, &s->hob_nsector); + qemu_put_8s(f, &s->hob_sector); + qemu_put_8s(f, &s->hob_lcyl); + qemu_put_8s(f, &s->hob_hcyl); + qemu_put_8s(f, &s->select); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->lba48); + + qemu_put_8s(f, &s->sense_key); + qemu_put_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ + } +} + +static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIIDEState *d = opaque; + int ret, i; + + if (version_id != 1) + return -EINVAL; + ret = pci_device_load(&d->dev, f); + if (ret < 0) + return ret; + + for(i = 0; i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + qemu_get_8s(f, &bm->cmd); + qemu_get_8s(f, &bm->status); + qemu_get_be32s(f, &bm->addr); + /* XXX: if a transfer is pending, we do not save it yet */ + } + + /* per IDE interface data */ + for(i = 0; i < 2; i++) { + IDEState *s = &d->ide_if[i * 2]; + uint8_t drive1_selected; + qemu_get_8s(f, &s->cmd); + qemu_get_8s(f, &drive1_selected); + s->cur_drive = &d->ide_if[i * 2 + (drive1_selected != 0)]; + } + + /* per IDE drive data */ + for(i = 0; i < 4; i++) { + IDEState *s = &d->ide_if[i]; + qemu_get_be32s(f, &s->mult_sectors); + qemu_get_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_get_buffer(f, (uint8_t *)s->identify_data, 512); + } + qemu_get_8s(f, &s->feature); + qemu_get_8s(f, &s->error); + qemu_get_be32s(f, &s->nsector); + qemu_get_8s(f, &s->sector); + qemu_get_8s(f, &s->lcyl); + qemu_get_8s(f, &s->hcyl); + qemu_get_8s(f, &s->hob_feature); + qemu_get_8s(f, &s->hob_nsector); + qemu_get_8s(f, &s->hob_sector); + qemu_get_8s(f, &s->hob_lcyl); + qemu_get_8s(f, &s->hob_hcyl); + qemu_get_8s(f, &s->select); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->lba48); + + qemu_get_8s(f, &s->sense_key); + qemu_get_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ + } + return 0; +} + +static void piix3_reset(PCIIDEState *d) +{ + uint8_t *pci_conf = d->dev.config; + + pci_conf[0x04] = 0x00; + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x80; /* FBC */ + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */ +} + +void pci_piix_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + /* register a function 1 of PIIX */ + d = (PCIIDEState *)pci_register_device(bus, "PIIX IDE", + sizeof(PCIIDEState), + devfn, + NULL, NULL); + d->type = IDE_TYPE_PIIX3; + + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x30; + pci_conf[0x03] = 0x12; + pci_conf[0x08] = 0x02; // Step A1 + pci_conf[0x09] = 0x80; // legacy ATA mode + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + piix3_reset(d); + + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); + + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + pic_set_irq_new, isa_pic, 14); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + pic_set_irq_new, isa_pic, 15); + ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); + ide_init_ioport(&d->ide_if[2], 0x170, 0x376); + + register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); +} + +/* hd_table must contain 4 block drivers */ +/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + /* register a function 1 of PIIX3 */ + d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", + sizeof(PCIIDEState), + devfn, + NULL, NULL); + d->type = IDE_TYPE_PIIX3; + + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x10; + pci_conf[0x03] = 0x70; + pci_conf[0x09] = 0x80; // legacy ATA mode + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + piix3_reset(d); + + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); + + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + pic_set_irq_new, isa_pic, 14); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + pic_set_irq_new, isa_pic, 15); + ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); + ide_init_ioport(&d->ide_if[2], 0x170, 0x376); + + register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); +} + +/***********************************************************/ +/* MacIO based PowerPC IDE */ + +/* PowerMac IDE memory IO */ +static void pmac_ide_writeb (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; + switch (addr) { + case 1 ... 7: + ide_ioport_write(opaque, addr, val); + break; + case 8: + case 22: + ide_cmd_write(opaque, 0, val); + break; + default: + break; + } +} + +static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) +{ + uint8_t retval; + + addr = (addr & 0xFFF) >> 4; + switch (addr) { + case 1 ... 7: + retval = ide_ioport_read(opaque, addr); + break; + case 8: + case 22: + retval = ide_status_read(opaque, 0); + break; + default: + retval = 0xFF; + break; + } + return retval; +} + +static void pmac_ide_writew (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + if (addr == 0) { + ide_data_writew(opaque, 0, val); + } +} + +static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) +{ + uint16_t retval; + + addr = (addr & 0xFFF) >> 4; + if (addr == 0) { + retval = ide_data_readw(opaque, 0); + } else { + retval = 0xFFFF; + } +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap16(retval); +#endif + return retval; +} + +static void pmac_ide_writel (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + if (addr == 0) { + ide_data_writel(opaque, 0, val); + } +} + +static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) +{ + uint32_t retval; + + addr = (addr & 0xFFF) >> 4; + if (addr == 0) { + retval = ide_data_readl(opaque, 0); + } else { + retval = 0xFFFFFFFF; + } +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap32(retval); +#endif + return retval; +} + +static CPUWriteMemoryFunc *pmac_ide_write[] = { + pmac_ide_writeb, + pmac_ide_writew, + pmac_ide_writel, +}; + +static CPUReadMemoryFunc *pmac_ide_read[] = { + pmac_ide_readb, + pmac_ide_readw, + pmac_ide_readl, +}; + +/* hd_table must contain 4 block drivers */ +/* PowerMac uses memory mapped registers, not I/O. Return the memory + I/O index to access the ide. */ +int pmac_ide_init (BlockDriverState **hd_table, + SetIRQFunc *set_irq, void *irq_opaque, int irq) +{ + IDEState *ide_if; + int pmac_ide_memory; + + ide_if = qemu_mallocz(sizeof(IDEState) * 2); + ide_init2(&ide_if[0], hd_table[0], hd_table[1], + set_irq, irq_opaque, irq); + + pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, + pmac_ide_write, &ide_if[0]); + return pmac_ide_memory; +} + +#endif +#define ATA_R_DATA (ATA_DEV9_HDD_BASE + 0x00) +#define ATA_R_ERROR (ATA_DEV9_HDD_BASE + 0x02) +#define ATA_R_NSECTOR (ATA_DEV9_HDD_BASE + 0x04) +#define ATA_R_SECTOR (ATA_DEV9_HDD_BASE + 0x06) +#define ATA_R_LCYL (ATA_DEV9_HDD_BASE + 0x08) +#define ATA_R_HCYL (ATA_DEV9_HDD_BASE + 0x0a) +#define ATA_R_SELECT (ATA_DEV9_HDD_BASE + 0x0c) +#define ATA_R_STATUS (ATA_DEV9_HDD_BASE + 0x0e) +#define ATA_R_CONTROL (ATA_DEV9_HDD_BASE + 0x1c) + +//Feature -> error +//command -> status + +//data : 1,2,4 +//command : 1 +IDEState ps2_hdd_data; +BMDMAState ps2_hdd_bmdma_data; +BlockDriverState ps2_hdd_bds_data; + +#define ps2_hdd (&ps2_hdd_data) +void dev9_ata_irq(void *opaque, int irq_num, int level) +{ + emu_printf("ATA INTERRUPT level %d\n",level); + if (level) + { + _DEV9irq(ATA_DEV9_INT,0); + } + else + { + dev9.irqcause&=~ATA_DEV9_INT; + _DEV9irq(0,0); + } + +} +HANDLE HddFile; +void ata_init() +{ + HddFile = ::CreateFile("d:\\ps2_hdd.raw", GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + DWORD dwTemp; + ::DeviceIoControl(HddFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL); + LARGE_INTEGER sp; + + //20 GBs + /* + //~7 GB + sp.LowPart=0xEFFFFFFF; + sp.HighPart=1; + */ + sp.QuadPart=(u64)20*1000*1000*1000; + + int64_t rcc=(sp.QuadPart/512/16/63)+1; + + ps2_hdd_bds_data.total_sectors=rcc*16*63; + sp.QuadPart=ps2_hdd_bds_data.total_sectors*512; + + ps2_hdd_bds_data.secs=0; + ps2_hdd_bds_data.heads=0; + ps2_hdd_bds_data.cyls=0; + + emu_printf("Hdd size #.2fGB\n",(double)sp.QuadPart/1024/1024/1024); + + ::SetFilePointerEx(HddFile, sp, 0, FILE_BEGIN); + ::SetEndOfFile(HddFile); + + + ide_init2(ps2_hdd,&ps2_hdd_bds_data,0,dev9_ata_irq,0,0); + ps2_hdd->bmdma=&ps2_hdd_bmdma_data; +} +void ata_term() +{ + ::CloseHandle(HddFile); +} +#define LOG_IRS (sz!=2) +template +u8 CALLBACK ata_read(u32 addr) +{ + //emu_printf("ata_read%d(0x%X)\n",sz*8,addr); + switch(addr) + { + case ATA_R_DATA: + if (sz==1) + { + emu_printf("ATA: Invalid ATA_R_DATA size: register cannot be readen using 8 bit\n"); + } + else if (sz==2) + { + return ide_data_readw(ps2_hdd,0); + } + else + { + return ide_data_readl(ps2_hdd,0); + } + break; + case ATA_R_ERROR: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_ERROR size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,1); + } + break; + case ATA_R_NSECTOR: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_NSECTOR size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,2); + } + break; + case ATA_R_SECTOR: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_SECTOR size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,3); + } + break; + case ATA_R_LCYL: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_LCYL size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,4); + } + break; + case ATA_R_HCYL: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_HCYL size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,5); + } + break; + case ATA_R_SELECT: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_SELECT size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,6); + } + break; + //command -> status + case ATA_R_STATUS: + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_STATUS size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_ioport_read(ps2_hdd,7); + } + break; + case ATA_R_CONTROL: + //ide_cmd -> seems to be control + if (sz!=1 && LOG_IRS) + { + emu_printf("ATA: Invalid ATA_R_STATUS size: register cannot be read w/o using 8 bit\n"); + } + //else + { + return ide_status_read(ps2_hdd,0); + } + break; + default: + DEV9_LOG("ATA: Unknown %d bit read @ %X,v=%X\n",sz*8,addr,dev9Ru8(addr)); + if (sz==1) + { + return dev9Ru8(addr); + } + else if (sz==2) + { + return dev9Ru16(addr); + } + else + { + return dev9Ru32(addr); + } + } + + DEV9_LOG("ATA: Unknown %d bit read @ %X,v=%X\n",sz*8,addr,0xdeadb33f); + return 0xdeadb33f; +} +#define LOG_IWS (value&~0xFF) +template +void CALLBACK ata_write(u32 addr, u32 value) +{ + //emu_printf("ata_write%d(0x%X,0x%X)\n",sz*8,addr,value); + switch(addr) + { + case ATA_R_DATA: + if (sz==1) + { + emu_printf("ATA: Invalid ATA_R_DATA size: register cannot be writen using 8 bit\n"); + } + else if (sz==2) + { + ide_data_writew(ps2_hdd,0,value); + } + else + { + ide_data_writel(ps2_hdd,0,value); + } + break; + case ATA_R_ERROR: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_ERROR(feature) size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,1,value); + } + break; + case ATA_R_NSECTOR: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_NSECTOR size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,2,value); + } + break; + case ATA_R_SECTOR: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_SECTOR size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,3,value); + } + break; + case ATA_R_LCYL: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_LCYL size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,4,value); + } + break; + case ATA_R_HCYL: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_HCYL size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,5,value); + } + break; + case ATA_R_SELECT: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_SELECT size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,6,value); + } + break; + //command -> status + case ATA_R_STATUS: + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_STATUS(command) size: register cannot be writen w/o using 8 bit\n"); + } + //else + { + ide_ioport_write(ps2_hdd,7,value); + } + break; + case ATA_R_CONTROL: + //ide_cmd -> seems to be control + if (sz!=1 && LOG_IWS) + { + emu_printf("ATA: Invalid ATA_R_CONTROL size: register cannot be writen w/o using 8 bit\n"); + } + // else + { + ide_cmd_write(ps2_hdd,7,value); + } + break; + default: + DEV9_LOG("ATA: Unknown %d bit write @ %X,v=%X\n",addr,value); + if (sz==1) + { + dev9Ru8(addr)=value; + } + else if (sz==2) + { + dev9Ru16(addr)=value; + } + else + { + dev9Ru32(addr)=value; + } + } +} + +u8* pMem_dma; +void do_dma(int size) +{ + BMDMAState* bm=ps2_hdd->bmdma; + bm->addr=0; + bm->cur_prd_addr = 0; + bm->cur_prd_len = size; + + if (!(bm->status & BM_STATUS_DMAING)) + { + bm->status |= BM_STATUS_DMAING; + /* start dma transfer if possible */ + if (bm->dma_cb) + bm->dma_cb(bm, 0); + else + emu_printf("DMA ERROR 2 !!!!@#!@#!@#!#!@#!@#$####################################################^#^\n"); + //bm->status&=~BM_STATUS_DMAING; + } + else + { + emu_printf("DMA ERROR 1 !!!!@#!@#!@#!#!@#!@#$####################################################^#^\n"); + } + + _DEV9irq(ATA_DEV9_INT_DMA,0); +} +void CALLBACK ata_readDMA8Mem(u32 *pMem, int size) +{ + size>>=1; + //#define SPD_R_IF_CTRL (SPD_REGBASE + 0x64) + //#define SPD_IF_ATA_RESET 0x80 + //#define SPD_IF_DMA_ENABLE 0x04 + pMem_dma=(u8*)pMem; + if (dev9Ru8(SPD_R_IF_CTRL)&SPD_IF_DMA_ENABLE) + { + emu_printf("ATA: ata_readDMA8Mem(0x%X,%d) :D\n",pMem,size); + do_dma(size); + //bm->cmd = val & 0x09; + } + else + { + emu_printf("ATA: ata_readDMA8Mem & SPD_IF_DMA_ENABLE disabled\n"); + } +} +void CALLBACK ata_writeDMA8Mem(u32 *pMem, int size) +{ + size>>=1; + pMem_dma=(u8*)pMem; + if (dev9Ru8(SPD_R_IF_CTRL)&SPD_IF_DMA_ENABLE) + { + emu_printf("ATA: ata_writeDMA8Mem(0x%X,%d) :D\n",pMem,size); + do_dma(size); + //bm->cmd = val & 0x09; + } + else + { + emu_printf("ATA: ata_writeDMA8Mem & SPD_IF_DMA_ENABLE disabled\n"); + } +} +void _template_hack_() +{ + ata_read<1>(0); + ata_read<2>(0); + ata_read<4>(0); + + ata_write<1>(0,0); + ata_write<2>(0,0); + ata_write<4>(0,0); +} +#define printme emu_printf("Called stub:" __FUNCTION__ "\n"); + +//memory access +void __cdecl cpu_physical_memory_write(u32 addr,void* ptr,u32 sz) +{ + printf("cpu_physical_memory_write(0x%X,0x%X,%d)\n",addr,ptr,sz); + //return; + memcpy(pMem_dma+addr,ptr,sz); +} +void __cdecl cpu_physical_memory_read(u32 addr,void* ptr,u32 sz) +{ + printf("cpu_physical_memory_read(0x%X,0x%X,%d)\n",addr,ptr,sz); + //return; + memcpy(ptr,pMem_dma+addr,sz); +} + +//IMAGE IO + + +//Async io emulation =) +BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + //printme + int ret; + ret = bdrv_read(bs, sector_num, buf, nb_sectors); + cb(opaque, ret); + return 0; +} +BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + //printme + int ret; + ret = bdrv_write(bs, sector_num, buf, nb_sectors); + cb(opaque, ret); + return 0; +} + +void bdrv_flush(BlockDriverState *bs) +{ + printme; + //return; + FlushFileBuffers(HddFile); +} +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + //printme; + //return 0; + if ((sector_num+nb_sectors)>bs->total_sectors) + { + emu_printf("ATA: ERROR , ((sector_num+nb_sectors)>bs->total_sectors)\n"); + return -1; + } + DWORD rv; + LARGE_INTEGER sp; + sp.QuadPart=sector_num*512; + + BOOL sfp=SetFilePointerEx(HddFile,sp,0,FILE_BEGIN); + if (!sfp) + { + emu_printf("SetFilePointerEx file failed\n"); + return -1; + } + + BOOL ss=ReadFile(HddFile,buf,nb_sectors*512,&rv,0); + if (!ss) + { + emu_printf("ReadFile file failed - %d\n",GetLastError()); + return -1; + } + emu_printf("Readed %d bytes from %d:%d@file\n",rv,sp.HighPart,sp.LowPart); + return 0; +} +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + //printme; + //return 0; + if ((sector_num+nb_sectors)>bs->total_sectors) + { + emu_printf("ATA: ERROR , ((sector_num+nb_sectors)>bs->total_sectors)\n"); + return -1; + } + DWORD rv; + LARGE_INTEGER sp; + sp.QuadPart=sector_num*512; + + BOOL sfp=SetFilePointerEx(HddFile,sp,0,FILE_BEGIN); + if (!sfp) + { + emu_printf("SetFilePointerEx file failed\n"); + return -1; + } + + BOOL ss=WriteFile(HddFile,buf,nb_sectors*512,&rv,0); + if (!ss) + { + emu_printf("WriteFile file failed - %d\n",GetLastError()); + return -1; + } + emu_printf("Writen %d bytes to %d:%d@file\n",rv,sp.HighPart,sp.LowPart); + return 0; +} + +void __cdecl bdrv_eject(struct BlockDriverState *,int) +{ + printme; +} +void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) +{ + printme; + //return; + *nb_sectors_ptr=bs->total_sectors; +} +void bdrv_set_locked(BlockDriverState *bs, int locked) +{ + printme; + //return; + bs->locked = locked; +} + +int __cdecl bdrv_is_locked(struct BlockDriverState *bs) +{ + printme; + return bs->locked; +} +int __cdecl bdrv_is_inserted(struct BlockDriverState *) +{ + printme; + return 1; +} + +void __cdecl bdrv_set_change_cb(struct BlockDriverState *,void (__cdecl*)(void *),void *) +{ + printme +} +int __cdecl bdrv_get_type_hint(struct BlockDriverState *) +{ + printme; + return BDRV_TYPE_HD; +} +void bdrv_set_geometry_hint(BlockDriverState *bs, + int cyls, int heads, int secs) +{ + printme; + //return; + bs->cyls = cyls; + bs->heads = heads; + bs->secs = secs; +} +void bdrv_set_translation_hint(BlockDriverState *bs, int translation) +{ + printme; + bs->translation = translation; +} +int bdrv_get_translation_hint(BlockDriverState *bs) +{ + printme; + //return 0; + return bs->translation; +} + +void bdrv_get_geometry_hint(BlockDriverState *bs, + int *pcyls, int *pheads, int *psecs) +{ + printme; + //return; + *pcyls = bs->cyls; + *pheads = bs->heads; + *psecs = bs->secs; +} \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/ata.h b/plugins/dev9/dev9ghzdrk/Win32/ata.h new file mode 100644 index 0000000000..9dfa78e5ff --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/ata.h @@ -0,0 +1,13 @@ +#pragma once +#include "dev9.h" + +void ata_init(); +void ata_term(); + +template +void CALLBACK ata_write(u32 addr, u32 value); +template +u8 CALLBACK ata_read(u32 addr); + +void CALLBACK ata_readDMA8Mem(u32 *pMem, int size); +void CALLBACK ata_writeDMA8Mem(u32 *pMem, int size); \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/icmp.cpp b/plugins/dev9/dev9ghzdrk/Win32/icmp.cpp new file mode 100644 index 0000000000..23d96bde8b --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/icmp.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include + +#include + +struct pending_icmp_request +{ + char ipaddress[4]; + HANDLE hEvent; + DWORD sTick; + DWORD timeOut; //ttl in ms + DWORD replyBufferSize; + char *replyBuffer; + char *requestData; + void *userdata; + + pending_icmp_request() + { + memset(this,0,sizeof(pending_icmp_request)); + } + + pending_icmp_request(pending_icmp_request&p) + { + memcpy(this,&p,sizeof(p)); + } +}; + +typedef std::list request_list; + +request_list ping_list; + +HANDLE hIP; + +int icmp_init() +{ + hIP = IcmpCreateFile(); + + if(hIP==INVALID_HANDLE_VALUE) + return -1; + + return 0; +} + +void icmp_start(unsigned char *ipaddr, int ttl, void *data, int datasize, void *udata) +{ + pending_icmp_request req; + + req.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + req.sTick = GetTickCount(); + req.timeOut = ttl; + + req.requestData = (char*)malloc(datasize); + memcpy(req.requestData,data,datasize); + + memcpy(req.ipaddress,ipaddr,4); + + req.replyBufferSize = (sizeof(ICMP_ECHO_REPLY) + sizeof(datasize)); + req.replyBuffer = (char*)malloc(replyBufferSize); + + req.userdata=udata; + + ping_list.push_back(req); + + IcmpSendEcho2(hIP,req.hEvent,NULL,NULL,*(DWORD*)ipaddr,req.requestData,58, + NULL,req.replyBuffer,replyBufferSize,ttl); + +} + +int icmp_check_replies(char *ipaddress, void **udata) +{ + for(request_list::iterator rit=ping_list.begin();rit!=ping_list.end();rit++) + { + if(WaitForSingleObject(rit->hEvent,0)==0) //handle is signaled, reply received. + { + if(IcmpParseReplies(rit->replyBuffer,rit->replyBufferSize)>0) + { + memcpy(ipaddress,rit->ipaddress,4); + + ping_list.remove(rit); + + return 1; //reply received + } + ResetEvent(rit->hEvent); + } + if(GetTickCount() >= (rit->sTick+rit->timeOut)) + { + memcpy(ipaddress,rit->ipaddress,4); + *udata = rit->userdata; + + ping_list.remove(rit); + + return 2; //timeout + } + } + return 0; +} + +void icmp_close() +{ + IcmpCloseHandle(hIP); +} \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/libpacket.a b/plugins/dev9/dev9ghzdrk/Win32/libpacket.a new file mode 100644 index 0000000000000000000000000000000000000000..b70fed022f676e746676cb82fb9f2c4623196a53 GIT binary patch literal 23732 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 literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/mtfifo.h b/plugins/dev9/dev9ghzdrk/Win32/mtfifo.h new file mode 100644 index 0000000000..dc86e5f4b2 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/mtfifo.h @@ -0,0 +1,70 @@ +#pragma once +#include +//a simple, mt-safe fifo template class +template +class mtfifo +{ + struct container + { + container(container* n,T d) + { + next=n; + data=d; + } + container* next;T data; + }; + container* start; + container* end; + + CRITICAL_SECTION cs; +public: + mtfifo() + { + InitializeCriticalSection(&cs); + } + ~mtfifo() + { + //no need to destroy the CS? i cant remember realy .. ;p + } + void put(T data) + { + EnterCriticalSection(&cs); + if (end==0) + { + end=start=new container(0,data); + } + else + { + end=end->next=new container(0,data); + } + LeaveCriticalSection(&cs); + } + //Note, this is partialy mt-safe, the get may fail even if that returned false + bool empty(){ return start==0;} + bool get(T& rvi) + { + container* rv; + EnterCriticalSection(&cs); + if (start==0) + { + rv=0; //error + + + } + else + { + rv=start; + start=rv->next; + if (!start) + end=0; //last item + } + LeaveCriticalSection(&cs); + + if(!rv) + return false; + rvi=rv->data; + delete rv; + + return true; + } +}; \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/net.cpp b/plugins/dev9/dev9ghzdrk/Win32/net.cpp new file mode 100644 index 0000000000..c0f2fe50a1 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/net.cpp @@ -0,0 +1,51 @@ +#include "net.h" +#include "Dev9.h" + +//mtfifo rx_fifo; +//mtfifo tx_fifo; + +NetAdapter* nif; +HANDLE rx_thread; + +volatile bool RxRunning=false; +//rx thread +DWORD WINAPI NetRxThread(LPVOID lpThreadParameter) +{ + NetPacket tmp; + while(RxRunning) + { + while(rx_fifo_can_rx() && nif->recv(&tmp)) + { + rx_process(&tmp); + } + + Sleep(10); + } + + return 0; +} + +void tx_put(NetPacket* pkt) +{ + nif->send(pkt); + //pkt must be copied if its not processed by here, since it can be allocated on the callers stack +} +void InitNet(NetAdapter* ad) +{ + nif=ad; + RxRunning=true; + + rx_thread=CreateThread(0,0,NetRxThread,0,CREATE_SUSPENDED,0); + + SetThreadPriority(rx_thread,THREAD_PRIORITY_HIGHEST); + ResumeThread(rx_thread); +} +void TermNet() +{ + RxRunning=false; + printf("Waiting for RX-net thread to terminate.."); + WaitForSingleObject(rx_thread,-1); + printf(".done\n"); + + delete nif; +} \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/net.h b/plugins/dev9/dev9ghzdrk/Win32/net.h new file mode 100644 index 0000000000..a131d57d15 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/net.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include //uh isnt memcpy @ stdlib ? + +struct NetPacket +{ + NetPacket() {size=0;} + NetPacket(void* ptr,int sz) {size=sz;memcpy(buffer,ptr,sz);} + + int size; + char buffer[2048-sizeof(int)];//1536 is realy needed, just pad up to 2048 bytes :) +}; +/* +extern mtfifo rx_fifo; +extern mtfifo tx_fifo; +*/ + +class NetAdapter +{ +public: + virtual bool blocks()=0; + virtual bool recv(NetPacket* pkt)=0; //gets a packet + virtual bool send(NetPacket* pkt)=0; //sends the packet and deletes it when done + virtual ~NetAdapter(){} +}; + +void tx_put(NetPacket* ptr); +void InitNet(NetAdapter* adapter); +void TermNet(); \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/packet32.h b/plugins/dev9/dev9ghzdrk/Win32/packet32.h new file mode 100644 index 0000000000..5e261a6448 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/packet32.h @@ -0,0 +1,450 @@ +/* + * Copyright (c) 1999 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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 Politecnico di Torino 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include +#include "devioctl.h" +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + +// ioctls +#define FILE_DEVICE_PROTOCOL 0x8000 + +#define IOCTL_PROTOCOL_STATISTICS CTL_CODE(FILE_DEVICE_PROTOCOL, 2 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_RESET CTL_CODE(FILE_DEVICE_PROTOCOL, 3 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_READ CTL_CODE(FILE_DEVICE_PROTOCOL, 4 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_WRITE CTL_CODE(FILE_DEVICE_PROTOCOL, 5 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_PROTOCOL_MACNAME CTL_CODE(FILE_DEVICE_PROTOCOL, 6 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_OPEN CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CLOSE CTL_CODE(FILE_DEVICE_PROTOCOL, 8 , METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define pBIOCSETBUFFERSIZE 9592 ///< IOCTL code: set kernel buffer size. +#define pBIOCSETF 9030 ///< IOCTL code: set packet filtering program. +#define pBIOCGSTATS 9031 ///< IOCTL code: get the capture stats. +#define pBIOCSRTIMEOUT 7416 ///< IOCTL code: set the read timeout. +#define pBIOCSMODE 7412 ///< IOCTL code: set working mode. +#define pBIOCSWRITEREP 7413 ///< IOCTL code: set number of physical repetions of every packet written by the app. +#define pBIOCSMINTOCOPY 7414 ///< IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call. +#define pBIOCSETOID 2147483648 ///< IOCTL code: set an OID value. +#define pBIOCQUERYOID 2147483652 ///< IOCTL code: get an OID value. +#define pATTACHPROCESS 7117 ///< IOCTL code: attach a process to the driver. Used in Win9x only. +#define pDETACHPROCESS 7118 ///< IOCTL code: detach a process from the driver. Used in Win9x only. +#define pBIOCSETDUMPFILENAME 9029 ///< IOCTL code: set the name of a the file used by kernel dump mode. +#define pBIOCEVNAME 7415 ///< IOCTL code: get the name of the event that the driver signals when some data is present in the buffer. +#define pBIOCSENDPACKETSNOSYNC 9032 ///< IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps associated with the packets. +#define pBIOCSENDPACKETSSYNC 9033 ///< IOCTL code: Send a buffer containing multiple packets to the network, respecting the timestamps associated with the packets. +#define pBIOCSETDUMPLIMITS 9034 ///< IOCTL code: Set the dump file limits. See the PacketSetDumpLimits() function. +#define pBIOCISDUMPENDED 7411 ///< IOCTL code: Get the status of the kernel dump process. See the PacketIsDumpEnded() function. + +#define pBIOCSTIMEZONE 7471 ///< IOCTL code: set time zone. Used in Win9x only. + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + + +#define NdisMediumNull -1 // Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 // Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 // Custom linktype: NDIS doesn't provide an equivalent + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/* + * Desired design of maximum size and alignment. + * These are implementation specific. + */ +#define _SS_MAXSIZE 128 // Maximum size. +#define _SS_ALIGNSIZE (sizeof(__int64)) // Desired alignment. + +/* + * Definitions used for sockaddr_storage structure paddings design. + */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE \ + + _SS_ALIGNSIZE)) +/* +struct sockaddr_storage { + short ss_family; // Address family. + char __ss_pad1[_SS_PAD1SIZE]; // 6 byte pad, this is to make + // implementation specific pad up to + // alignment field that follows explicit + // in the data structure. + __int64 __ss_align; // Field to force desired structure. + char __ss_pad2[_SS_PAD2SIZE]; // 112 byte pad to achieve desired size; + // _SS_MAXSIZE value minus size of + // ss_family, __ss_pad1, and + // __ss_align fields is 112. +}; +*/ +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. + +/*! + \brief Contains comprehensive information about a network adapter. + + This structure is filled with all the accessory information that the user can need about an adapter installed + on his system. +*/ +typedef struct _ADAPTER_INFO +{ + struct _ADAPTER_INFO *Next; ///< Pointer to the next adapter in the list. + CHAR Name[ADAPTER_NAME_LENGTH + 1]; ///< Name of the device representing the adapter. + CHAR Description[ADAPTER_DESC_LENGTH + 1]; ///< Human understandable description of the adapter + UINT MacAddressLen; ///< Length of the link layer address. + UCHAR MacAddress[MAX_MAC_ADDR_LENGTH]; ///< Link layer address. + NetType LinkLayer; ///< Physical characteristics of this adapter. This NetType structure contains the link type and the speed of the adapter. + INT NNetworkAddresses; ///< Number of network layer addresses of this adapter. + npf_if_addr *NetworkAddresses; ///< Pointer to an array of npf_if_addr, each of which specifies a network address of this adapter. + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. +} +ADAPTER_INFO, *PADAPTER_INFO; + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + + +#if _DBG +#define ODS(_x) OutputDebugString(TEXT(_x)) +#define ODSEx(_x, _y) +#else +#ifdef _DEBUG_TO_FILE +/*! + \brief Macro to print a debug string. The behavior differs depending on the debug level +*/ +#define ODS(_x) { \ + FILE *f; \ + f = fopen("winpcap_debug.txt", "a"); \ + fprintf(f, "%s", _x); \ + fclose(f); \ +} +/*! + \brief Macro to print debug data with the printf convention. The behavior differs depending on + the debug level +*/ +#define ODSEx(_x, _y) { \ + FILE *f; \ + f = fopen("winpcap_debug.txt", "a"); \ + fprintf(f, _x, _y); \ + fclose(f); \ +} + + + +LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName); +#else +#define ODS(_x) +#define ODSEx(_x, _y) +#endif +#endif + +/* We load dinamically the dag library in order link it only when it's present on the system */ +#ifdef HAVE_DAG_API +typedef dagc_t* (*dagc_open_handler)(const char *source, unsigned flags, char *ebuf); ///< prototype used to dynamically load the dag dll +typedef void (*dagc_close_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_getlinktype_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_getlinkspeed_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_setsnaplen_handler)(dagc_t *dagcfd, unsigned snaplen); ///< prototype used to dynamically load the dag dll +typedef unsigned (*dagc_getfcslen_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_receive_handler)(dagc_t *dagcfd, u_char **buffer, u_int *bufsize); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_stats_handler)(dagc_t *dagcfd, dagc_stats_t *ps); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_wait_handler)(dagc_t *dagcfd, struct timeval *timeout); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_finddevs_handler)(dagc_if_t **alldevsp, char *ebuf); ///< prototype used to dynamically load the dag dll +typedef int (*dagc_freedevs_handler)(dagc_if_t *alldevsp); ///< prototype used to dynamically load the dag dll +#endif // HAVE_DAG_API + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +// The following is used to check the adapter name in PacketOpenAdapterNPF and prevent +// opening of firewire adapters +#define FIREWIRE_SUBSTR L"1394" + +void PacketPopulateAdaptersInfoList(); +PWCHAR SChar2WChar(PCHAR string); +PCHAR WChar2SChar(PWCHAR string); +BOOL PacketGetFileVersion(LPTSTR FileName, PCHAR VersionBuff, UINT VersionBuffLen); +PADAPTER_INFO PacketFindAdInfo(PCHAR AdapterName); +BOOLEAN PacketUpdateAdInfo(PCHAR AdapterName); +BOOLEAN IsFireWire(TCHAR *AdapterDesc); + + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/plugins/dev9/dev9ghzdrk/Win32/pcap_io.h b/plugins/dev9/dev9ghzdrk/Win32/pcap_io.h new file mode 100644 index 0000000000..beca31bb72 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/pcap_io.h @@ -0,0 +1,161 @@ +#pragma once +#include "net.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push,1) + +typedef struct _ip_address +{ + u_char bytes[4]; +} ip_address; + +typedef struct _mac_address +{ + u_char bytes[6]; +} mac_address; + +typedef struct _ethernet_header +{ + mac_address dst; + mac_address src; + u_short protocol; +} ethernet_header; + +typedef struct _arp_packet +{ + u_short hw_type; + u_short protocol; + u_char h_addr_len; + u_char p_addr_len; + u_short operation; + mac_address h_src; + ip_address p_src; + mac_address h_dst; + ip_address p_dst; +} arp_packet; + +typedef struct _ip_header { + u_char ver_hlen; /* version << 4 | header length >> 2 */ + u_char type; /* type of service */ + u_short len; /* total length */ + u_short id; /* identification */ + u_short offset; /* fragment offset field */ + u_char ttl; /* time to live */ + u_char proto; /* protocol */ + u_short hdr_csum; /* checksum */ + ip_address src; /* source and dest address */ + ip_address dst; +} ip_header; + +/* Internet Control Message Protocol Constants and Packet Format */ + +/* ic_type field */ +#define ICT_ECHORP 0 /* Echo reply */ +#define ICT_DESTUR 3 /* Destination unreachable */ +#define ICT_SRCQ 4 /* Source quench */ +#define ICT_REDIRECT 5 /* Redirect message type */ +#define ICT_ECHORQ 8 /* Echo request */ +#define ICT_TIMEX 11 /* Time exceeded */ +#define ICT_PARAMP 12 /* Parameter Problem */ +#define ICT_TIMERQ 13 /* Timestamp request */ +#define ICT_TIMERP 14 /* Timestamp reply */ +#define ICT_INFORQ 15 /* Information request */ +#define ICT_INFORP 16 /* Information reply */ +#define ICT_MASKRQ 17 /* Mask request */ +#define ICT_MASKRP 18 /* Mask reply */ + +/* ic_code field */ +#define ICC_NETUR 0 /* dest unreachable, net unreachable */ +#define ICC_HOSTUR 1 /* dest unreachable, host unreachable */ +#define ICC_PROTOUR 2 /* dest unreachable, proto unreachable */ +#define ICC_PORTUR 3 /* dest unreachable, port unreachable */ +#define ICC_FNADF 4 /* dest unr, frag needed & don't frag */ +#define ICC_SRCRT 5 /* dest unreachable, src route failed */ + +#define ICC_NETRD 0 /* redirect: net */ +#define ICC_HOSTRD 1 /* redirect: host */ +#define IC_TOSNRD 2 /* redirect: type of service, net */ +#define IC_TOSHRD 3 /* redirect: type of service, host */ + +#define ICC_TIMEX 0 /* time exceeded, ttl */ +#define ICC_FTIMEX 1 /* time exceeded, frag */ + +#define IC_HLEN 8 /* octets */ +#define IC_PADLEN 3 /* pad length (octets) */ + +#define IC_RDTTL 300 /* ttl for redirect routes */ + + +/* ICMP packet format (following the IP header) */ +typedef struct _icmp_header { /* ICMP packet */ + char type; /* type of message (ICT_* above)*/ + char code; /* code (ICC_* above) */ + short csum; /* checksum of ICMP header+data */ + + union { + struct { + int ic1_id:16; /* echo type, a message id */ + int ic1_seq:16;/* echo type, a seq. number */ + } ic1; + ip_address ic2_gw; /* for redirect, gateway */ + struct { + char ic3_ptr;/* pointer, for ICT_PARAMP */ + char ic3_pad[IC_PADLEN]; + } ic3; + int ic4_mbz; /* must be zero */ + } icu; +} icmp_header; + +/*typedef struct _udp_header { + u16 src_port; + u16 dst_port; + u16 len; + u16 csum; +} udp_header;*/ + +typedef struct _full_arp_packet +{ + ethernet_header header; + arp_packet arp; +} full_arp_packet; + +#pragma pack(pop) + +#define ARP_REQUEST 0x0100 //values are big-endian + +extern mac_address virtual_mac; +extern mac_address broadcast_mac; + +extern ip_address virtual_ip; + +#define mac_compare(a,b) (memcmp(&(a),&(b),6)) +#define ip_compare(a,b) (memcmp(&(a),&(b),4)) + +/* +int pcap_io_init(char *adapter); +int pcap_io_send(void* packet, int plen); +int pcap_io_recv(void* packet, int max_len); +void pcap_io_close(); +*/ +int pcap_io_get_dev_num(); +char* pcap_io_get_dev_desc(int num,int md); +char* pcap_io_get_dev_name(int num,int md); + +#ifdef __cplusplus +} +#endif + +class PCAPAdapter : public NetAdapter +{ +public: + PCAPAdapter(); + virtual bool blocks(); + //gets a packet.rv :true success + virtual bool recv(NetPacket* pkt); + //sends the packet and deletes it when done (if successful).rv :true success + virtual bool send(NetPacket* pkt); + virtual ~PCAPAdapter(); +}; \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/plugin.def b/plugins/dev9/dev9ghzdrk/Win32/plugin.def new file mode 100644 index 0000000000..cf90edec15 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/plugin.def @@ -0,0 +1,24 @@ +EXPORTS + DEV9ThreadProc @4 + DEV9about = DEV9about@0 @5 + DEV9close = DEV9close@0 @6 + DEV9configure = DEV9configure@0 @7 + DEV9init = DEV9init@0 @8 + DEV9irq @9 DATA + DEV9irqCallback = DEV9irqCallback@4 @10 + DEV9irqHandler = DEV9irqHandler@0 @11 + DEV9open = DEV9open@4 @12 + DEV9read16 = DEV9read16@4 @13 + DEV9read32 = DEV9read32@4 @14 + DEV9read8 = DEV9read8@4 @15 + DEV9readDMA8Mem = DEV9readDMA8Mem@8 @16 + DEV9shutdown = DEV9shutdown@0 @17 + DEV9test = DEV9test@0 @18 + DEV9thread @19 + DEV9write16 = DEV9write16@8 @20 + DEV9write32 = DEV9write32@8 @21 + DEV9write8 = DEV9write8@8 @22 + DEV9writeDMA8Mem = DEV9writeDMA8Mem@8 @23 + PS2EgetLibName = PS2EgetLibName@0 @28 + PS2EgetLibType = PS2EgetLibType@0 @29 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @30 diff --git a/plugins/dev9/dev9ghzdrk/Win32/resource.h b/plugins/dev9/dev9ghzdrk/Win32/resource.h new file mode 100644 index 0000000000..fc9591a545 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by DEV9linuz.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_COMBO1 1007 +#define IDC_ETHDEV 1007 +#define IDC_BAYTYPE 1008 +#define IDC_ETHENABLED 1009 +#define IDC_HDDFILE 1010 +#define IDC_HDDENABLED 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/dev9/dev9ghzdrk/Win32/smap.cpp b/plugins/dev9/dev9ghzdrk/Win32/smap.cpp new file mode 100644 index 0000000000..d751677622 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/smap.cpp @@ -0,0 +1,875 @@ +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smap.h" +#include "net.h" +#include "pcap.h" +#include "pcap_io.h" +#include "tap.h" + +bool has_link=true; +/* +#define SMAP_BASE 0xb0000000 +#define SMAP_REG8(Offset) (*(u8 volatile*)(SMAP_BASE+(Offset))) +#define SMAP_REG16(Offset) (*(u16 volatile*)(SMAP_BASE+(Offset))) +#define SMAP_REG32(Offset) (*(u32 volatile*)(SMAP_BASE+(Offset))) + +u32 EMAC3REG_READ(u32 u32Offset) +{ + u32 hi=SMAP_REG16(u32Offset); + u32 lo=SMAP_REG16(u32Offset+2); + return (hi<<16)|lo; +} + + +void EMAC3REG_WRITE(u32 u32Offset,u32 u32V) +{ + SMAP_REG16(u32Offset)=((u32V>>16)&0xFFFF); + SMAP_REG16(u32Offset+2)=(u32V&0xFFFF); +} +#define SMAP_EMAC3_BASE 0x2000 +#define SMAP_EMAC3_STA_CTRL (SMAP_EMAC3_BASE+0x5C) +void test() +{ + printf ("EMAC3R 0x%08X raw read 0x%08X\n",EMAC3REG_READ(SMAP_EMAC3_STA_CTRL),SMAP_REG32(SMAP_EMAC3_STA_CTRL)); +}*/ + +//this can return a false positive, but its not problem since it may say it cant recv while it can (no harm done, just delay on packets) +bool rx_fifo_can_rx() +{ + //check if RX is on & stuff like that here + + //Check if there is space on RXBD + if (dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT)==64) + return false; + + //Check if there is space on fifo + int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR); + int space = sizeof(dev9.rxfifo) - + ((dev9.rxfifo_wr_ptr-rd_ptr)&16383); + + + if(space==0) + space = sizeof(dev9.rxfifo); + + if (space<1514) + return false; + + //we can recv a packet ! + return true; +} +void rx_process(NetPacket* pk) +{ + if (!rx_fifo_can_rx()) + { + emu_printf("ERROR : !rx_fifo_can_rx at rx_process\n"); + return; + } + smap_bd_t *pbd= ((smap_bd_t *)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff])+dev9.rxbdi; + + int bytes=(pk->size+3)&(~3); + + if (!(pbd->ctrl_stat & SMAP_BD_RX_EMPTY)) + { + emu_printf("ERROR : Discarding %d bytes (RX%d not ready)\n", bytes, dev9.rxbdi); + return; + } + + int pstart=(dev9.rxfifo_wr_ptr)&16383; + int i=0; + while(ibuffer[i++]); + dev9.rxfifo_wr_ptr&=16383; + } + + //increase RXBD + dev9.rxbdi++; + dev9.rxbdi&=(SMAP_BD_SIZE/8)-1; + + //Fill the BD with info ! + pbd->length = pk->size; + pbd->pointer = 0x4000 + pstart; + pbd->ctrl_stat&= ~SMAP_BD_RX_EMPTY; + + //increase frame count + u8* cntptr=&dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT); + +#ifdef WIN_X64 + *cntptr++; //no asm inline in x64 +#else + __asm + { + //this is silly + mov eax,[cntptr]; + lock inc byte ptr [eax] + } +#endif + + emu_printf("Got packet, %d bytes (%d fifo)\n", pk->size,bytes); + _DEV9irq(SMAP_INTR_RXEND,0);//now ? or when the fifo is full ? i guess now atm + //note that this _is_ wrong since the IOP interrupt system is not thread safe.. but nothing i can do about that +} + +bool tx_p_first=false; +u32 wswap(u32 d) +{ + return (d>>16)|(d<<16); +} +void tx_process() +{ + //we loop based on count ? or just *use* it ? + u32 cnt=dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT); + printf("tx_process : %d cnt frames !\n",cnt); + + if (!tx_p_first) + { + dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)=0; + tx_p_first=true; + //THIS IS A HACK.without that the stack wont init, i guess its missing e3/emac emulation .. + printf("WARN : First packet interrupt hack ..\n"); + _DEV9irq(SMAP_INTR_RXEND|SMAP_INTR_TXEND|SMAP_INTR_TXDNV,100); + return; + } + + NetPacket pk; + int fc=0; + for (fc=0;fcctrl_stat&SMAP_BD_TX_READY)) + { + //emu_printf("ERROR : !pbd->ctrl_stat&SMAP_BD_TX_READY\n"); + break; + } + if (pbd->length&3) + { + emu_printf("WARN : pbd->length not alligned %d\n",pbd->length); + } + + if(pbd->length>1514) + { + emu_printf("ERROR : Trying to send packet too big.\n"); + } + else + { + u32 base=(pbd->pointer-0x1000)&16383; + DEV9_LOG("Sending Packet from base %x, size %d\n", base, pbd->length); + emu_printf("Sending Packet from base %x, size %d\n", base, pbd->length); + + pk.size=pbd->length; + + if (!(pbd->pointer>=0x1000)) + { + emu_printf("ERROR: odd , !pbd->pointer>0x1000 | 0x%X %d\n", pbd->pointer, pbd->length); + } + //increase fifo pointer(s) + //uh does that even exist on real h/w ? + /* + if(dev9.txfifo_rd_ptr+pbd->length >= 16383) + { + //warp around ! + //first part + u32 was=16384-dev9.txfifo_rd_ptr; + memcpy(pk.buffer,dev9.txfifo+dev9.txfifo_rd_ptr,was); + //warp + dev9.txfifo_rd_ptr+=pbd->length; + dev9.txfifo_rd_ptr&=16383; + if (pbd->length!=was+dev9.txfifo_rd_ptr) + { + emu_printf("ERROR ON TX FIFO HANDLING, %x\n", dev9.txfifo_rd_ptr); + } + //second part + memcpy(pk.buffer+was,dev9.txfifo,pbd->length-was); + } + else + { //no warp or 'perfect' warp (reads end, resets to start + memcpy(pk.buffer,dev9.txfifo+dev9.txfifo_rd_ptr,pbd->length); + dev9.txfifo_rd_ptr+=pbd->length; + if (dev9.txfifo_rd_ptr==16384) + dev9.txfifo_rd_ptr=0; + } + + + + if (dev9.txfifo_rd_ptr&(~16383)) + { + emu_printf("ERROR ON TX FIFO HANDLING, %x\n", dev9.txfifo_rd_ptr); + } + */ + + if(base+pbd->length > 16384) + { + u32 was=16384-base; + memcpy(pk.buffer,dev9.txfifo+base,was); + memcpy(pk.buffer,dev9.txfifo,pbd->length-was); + printf("Warped read, was=%d, sz=%d, sz-was=%d\n",was,pbd->length,pbd->length-was); + } + else + { + memcpy(pk.buffer,dev9.txfifo+base,pbd->length); + } + tx_put(&pk); + } + + + pbd->ctrl_stat&= ~SMAP_BD_TX_READY; + + //increase TXBD + dev9.txbdi++; + dev9.txbdi&=(SMAP_BD_SIZE/8)-1; + + //decrease frame count -- this is not thread safe + dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)--; + } + + printf("processed %d frames, %d count, cnt = %d\n",fc,dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT),cnt); + //if some error/early exit signal TXDNV + if (fc!=cnt || cnt==0) + { + printf("WARN : (fc!=cnt || cnt==0) but packet send request was made oO..\n"); + _DEV9irq(SMAP_INTR_TXDNV,0); + } + //if we actualy send something send TXEND + if(fc!=0) + _DEV9irq(SMAP_INTR_TXEND,100);//now ? or when the fifo is empty ? i guess now atm +} + + +void emac3_write(u32 addr) +{ + u32 value=wswap(dev9Ru32(addr)); + switch(addr) + { + case SMAP_R_EMAC3_MODE0_L: + DEV9_LOG("SMAP: SMAP_R_EMAC3_MODE0 write %x\n", value); + value = (value & (~SMAP_E3_SOFT_RESET)) | SMAP_E3_TXMAC_IDLE | SMAP_E3_RXMAC_IDLE; + dev9Ru16(SMAP_R_EMAC3_STA_CTRL_H)|= SMAP_E3_PHY_OP_COMP; + break; + case SMAP_R_EMAC3_TxMODE0_L: + DEV9_LOG("SMAP: SMAP_R_EMAC3_TxMODE0_L write %x\n", value); + emu_printf("SMAP: SMAP_R_EMAC3_TxMODE0_L write %x\n", value); + //Process TX here ? + if (!value&SMAP_E3_TX_GNP_0) + emu_printf("SMAP_R_EMAC3_TxMODE0_L: SMAP_E3_TX_GNP_0 not set\n"); + + tx_process(); + value = value& ~SMAP_E3_TX_GNP_0; + if (value) + emu_printf("SMAP_R_EMAC3_TxMODE0_L: extra bits set !\n"); + break; + + case SMAP_R_EMAC3_TxMODE1_L: + emu_printf("SMAP_R_EMAC3_TxMODE1_L 32bit write %x\n", value); + break; + + + case SMAP_R_EMAC3_STA_CTRL_L: + DEV9_LOG("SMAP: SMAP_R_EMAC3_STA_CTRL write %x\n", value); + { + if (value & (SMAP_E3_PHY_READ)) + { + value|= SMAP_E3_PHY_OP_COMP; + int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); + u16 val = dev9.phyregs[reg]; + switch (reg) + { + case SMAP_DsPHYTER_BMSR: + if (has_link) + val|= SMAP_PHY_BMSR_LINK | SMAP_PHY_BMSR_ANCP; + break; + case SMAP_DsPHYTER_PHYSTS: + if (has_link) + val|= SMAP_PHY_STS_LINK |SMAP_PHY_STS_100M | SMAP_PHY_STS_FDX | SMAP_PHY_STS_ANCP; + break; + } + DEV9_LOG("phy_read %d: %x\n", reg, val); + value=(value&0xFFFF)|(val<<16); + } + if (value & (SMAP_E3_PHY_WRITE)) + { + value|= SMAP_E3_PHY_OP_COMP; + int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); + u16 val = value>>16; + switch (reg) + { + case SMAP_DsPHYTER_BMCR: + val&= ~SMAP_PHY_BMCR_RST; + val|= 0x1; + break; + } + DEV9_LOG("phy_write %d: %x\n", reg, val); + dev9.phyregs[reg] = val; + } + } + break; + default: + DEV9_LOG("SMAP: emac3 write %x=%x\n",addr, value); + } + dev9Ru32(addr)=wswap(value); +} +u8 CALLBACK smap_read8(u32 addr) +{ + switch(addr) + { + case SMAP_R_TXFIFO_FRAME_CNT: + printf("SMAP_R_TXFIFO_FRAME_CNT read 8\n"); + break; + case SMAP_R_RXFIFO_FRAME_CNT: + printf("SMAP_R_RXFIFO_FRAME_CNT read 8\n"); + break; + + case SMAP_R_BD_MODE: + return dev9.bd_swap; + + default: + DEV9_LOG("SMAP : Unknown 8 bit read @ %X,v=%X\n",addr,dev9Ru8(addr)); + return dev9Ru8(addr); + } + + DEV9_LOG("SMAP : error , 8 bit read @ %X,v=%X\n",addr,dev9Ru8(addr)); + return dev9Ru8(addr); +} +u16 CALLBACK smap_read16(u32 addr) +{ + if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) + { + int rv = dev9Ru16(addr); + if(dev9.bd_swap) + return (rv<<8)|(rv>>8); + return rv; + /* + switch (addr & 0x7) + { + case 0: // ctrl_stat + hard = dev9Ru16(addr); + //DEV9_LOG("TX_CTRL_STAT[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 2: // unknown + hard = dev9Ru16(addr); + //DEV9_LOG("TX_UNKNOWN[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 4: // length + hard = dev9Ru16(addr); + DEV9_LOG("TX_LENGTH[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 6: // pointer + hard = dev9Ru16(addr); + DEV9_LOG("TX_POINTER[%d]: read %x\n", (addr - SMAP_BD_TX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + } + */ + } + else if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) + { + int rv = dev9Ru16(addr); + if(dev9.bd_swap) + return (rv<<8)|(rv>>8); + return rv; + /* + switch (addr & 0x7) + { + case 0: // ctrl_stat + hard = dev9Ru16(addr); + //DEV9_LOG("RX_CTRL_STAT[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 2: // unknown + hard = dev9Ru16(addr); + //DEV9_LOG("RX_UNKNOWN[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 4: // length + hard = dev9Ru16(addr); + DEV9_LOG("RX_LENGTH[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + case 6: // pointer + hard = dev9Ru16(addr); + DEV9_LOG("RX_POINTER[%d]: read %x\n", (addr - SMAP_BD_RX_BASE) / 8, hard); + if(dev9.bd_swap) + return (hard<<8)|(hard>>8); + return hard; + } + */ + } + + switch(addr) + { +#ifdef DEV9_LOG_ENABLE + case SMAP_R_TXFIFO_FRAME_CNT: + printf("SMAP_R_TXFIFO_FRAME_CNT read 16\n"); + return dev9Ru16(addr); + case SMAP_R_RXFIFO_FRAME_CNT: + printf("SMAP_R_RXFIFO_FRAME_CNT read 16\n"); + return dev9Ru16(addr); + case SMAP_R_EMAC3_MODE0_L: + DEV9_LOG("SMAP_R_EMAC3_MODE0_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_MODE0_H: + DEV9_LOG("SMAP_R_EMAC3_MODE0_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_MODE1_L: + DEV9_LOG("SMAP_R_EMAC3_MODE1_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_MODE1_H: + DEV9_LOG("SMAP_R_EMAC3_MODE1_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_RxMODE_L: + DEV9_LOG("SMAP_R_EMAC3_RxMODE_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_RxMODE_H: + DEV9_LOG("SMAP_R_EMAC3_RxMODE_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_INTR_STAT_L: + DEV9_LOG("SMAP_R_EMAC3_INTR_STAT_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_INTR_STAT_H: + DEV9_LOG("SMAP_R_EMAC3_INTR_STAT_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_INTR_ENABLE_L: + DEV9_LOG("SMAP_R_EMAC3_INTR_ENABLE_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_INTR_ENABLE_H: + DEV9_LOG("SMAP_R_EMAC3_INTR_ENABLE_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_TxMODE0_L: + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_TxMODE0_H: + DEV9_LOG("SMAP_R_EMAC3_TxMODE0_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_TxMODE1_L: + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_TxMODE1_H: + DEV9_LOG("SMAP_R_EMAC3_TxMODE1_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_STA_CTRL_L: + DEV9_LOG("SMAP_R_EMAC3_STA_CTRL_L 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); + + case SMAP_R_EMAC3_STA_CTRL_H: + DEV9_LOG("SMAP_R_EMAC3_STA_CTRL_H 16bit read %x\n", dev9Ru16(addr)); + return dev9Ru16(addr); +#endif + default: + DEV9_LOG("SMAP : Unknown 16 bit read @ %X,v=%X\n",addr,dev9Ru16(addr)); + return dev9Ru16(addr); + } + + DEV9_LOG("SMAP : error , 16 bit read @ %X,v=%X\n",addr,dev9Ru16(addr)); + return dev9Ru16(addr); + +} +u32 CALLBACK smap_read32(u32 addr) +{ + if (addr>=SMAP_EMAC3_REGBASE && addr>24)|((rv>>8)&0xFF00)|((rv<<8)&0xFF0000); + + DEV9_LOG("SMAP_R_RXFIFO_DATA 32bit read %x\n", rv); + return rv; + } + default: + DEV9_LOG("SMAP : Unknown 32 bit read @ %X,v=%X\n",addr,dev9Ru32(addr)); + return dev9Ru32(addr); + } + + DEV9_LOG("SMAP : error , 32 bit read @ %X,v=%X\n",addr,dev9Ru32(addr)); + return dev9Ru32(addr); +} +void CALLBACK smap_write8(u32 addr, u8 value) +{ + switch(addr) + { + case SMAP_R_TXFIFO_FRAME_INC: + DEV9_LOG("SMAP_R_TXFIFO_FRAME_INC 8bit write %x\n", value); + { + dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)++; + } + return; + + case SMAP_R_RXFIFO_FRAME_DEC: + DEV9_LOG("SMAP_R_RXFIFO_FRAME_DEC 8bit write %x\n", value); + dev9Ru8(addr) = value; + { + u8* cntptr=&dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT); +#ifdef WIN_X64 + *cntptr--; //no asm inline in x64 +#else + __asm + { + //this is silly + mov eax,[cntptr]; + lock dec byte ptr [eax] + } +#endif + } + return; + + case SMAP_R_TXFIFO_CTRL: + DEV9_LOG("SMAP_R_TXFIFO_CTRL 8bit write %x\n", value); + if(value&SMAP_TXFIFO_RESET) + { + dev9.txbdi=0; + dev9.txfifo_rd_ptr=0; + dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)=0; //this actualy needs to be atomic (lock mov ...) + dev9Ru32(SMAP_R_TXFIFO_WR_PTR)=0; + dev9Ru32(SMAP_R_TXFIFO_SIZE)=16384; + } + value&= ~SMAP_TXFIFO_RESET; + dev9Ru8(addr) = value; + return; + + case SMAP_R_RXFIFO_CTRL: + DEV9_LOG("SMAP_R_RXFIFO_CTRL 8bit write %x\n", value); + if(value&SMAP_RXFIFO_RESET) + { + dev9.rxbdi=0; + dev9.rxfifo_wr_ptr=0; + dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT)=0; + dev9Ru32(SMAP_R_RXFIFO_RD_PTR)=0; + dev9Ru32(SMAP_R_RXFIFO_SIZE)=16384; + } + value&= ~SMAP_RXFIFO_RESET; + dev9Ru8(addr) = value; + return; + + case SMAP_R_BD_MODE: + if(value&SMAP_BD_SWAP) + { + DEV9_LOG("SMAP_R_BD_MODE: byteswapped.\n"); + emu_printf("BD Byteswapping enabled.\n"); + dev9.bd_swap=1; + } + else + { + DEV9_LOG("SMAP_R_BD_MODE: NOT byteswapped.\n"); + emu_printf("BD Byteswapping disabled.\n"); + dev9.bd_swap=0; + } + return; + default : + DEV9_LOG("SMAP : Unknown 8 bit write @ %X,v=%X\n",addr,value); + dev9Ru8(addr) = value; + return; + } + + DEV9_LOG("SMAP : error , 8 bit write @ %X,v=%X\n",addr,value); + dev9Ru8(addr) = value; +} +void CALLBACK smap_write16(u32 addr, u16 value) +{ + if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) { + if(dev9.bd_swap) + value = (value>>8)|(value<<8); + dev9Ru16(addr) = value; + /* + switch (addr & 0x7) + { + case 0: // ctrl_stat + DEV9_LOG("TX_CTRL_STAT[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); + //hacky + dev9Ru16(addr) = value; + return; + case 2: // unknown + //DEV9_LOG("TX_UNKNOWN[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); + dev9Ru16(addr) = value; + return; + case 4: // length + DEV9_LOG("TX_LENGTH[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); + dev9Ru16(addr) = value; + return; + case 6: // pointer + DEV9_LOG("TX_POINTER[%d]: write %x\n", (addr - SMAP_BD_TX_BASE) / 8, value); + dev9Ru16(addr) = value; + return; + } + */ + return; + } + else if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) + { + int rx_index=(addr - SMAP_BD_RX_BASE)>>3; + if(dev9.bd_swap) + value = (value>>8)|(value<<8); + dev9Ru16(addr) = value; +/* + switch (addr & 0x7) + { + case 0: // ctrl_stat + DEV9_LOG("RX_CTRL_STAT[%d]: write %x\n", rx_index, value); + dev9Ru16(addr) = value; + if(value&0x8000) + { + DEV9_LOG(" * * PACKET READ COMPLETE: rd_ptr=%d, wr_ptr=%d\n", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); + } + return; + case 2: // unknown + //DEV9_LOG("RX_UNKNOWN[%d]: write %x\n", rx_index, value); + dev9Ru16(addr) = value; + return; + case 4: // length + DEV9_LOG("RX_LENGTH[%d]: write %x\n", rx_index, value); + dev9Ru16(addr) = value; + return; + case 6: // pointer + DEV9_LOG("RX_POINTER[%d]: write %x\n", rx_index, value); + dev9Ru16(addr) = value; + return; + } + */ + return; + } + + switch(addr) + { + case SMAP_R_INTR_CLR: + DEV9_LOG("SMAP: SMAP_R_INTR_CLR 16bit write %x\n", value); + dev9.irqcause&= ~value; + return; + + case SMAP_R_TXFIFO_WR_PTR: + DEV9_LOG("SMAP: SMAP_R_TXFIFO_WR_PTR 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; +#define EMAC3_L_WRITE(name) \ + case name: \ + DEV9_LOG("SMAP: " #name " 16 bit write %x\n", value); \ + dev9Ru16(addr) = value; \ + return; + //handle L writes + EMAC3_L_WRITE(SMAP_R_EMAC3_MODE0_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_MODE1_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_TxMODE0_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_TxMODE1_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_RxMODE_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INTR_STAT_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INTR_ENABLE_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_ADDR_HI_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_ADDR_LO_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_VLAN_TPID ) + EMAC3_L_WRITE( SMAP_R_EMAC3_PAUSE_TIMER_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INDIVID_HASH1 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INDIVID_HASH2 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INDIVID_HASH3 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INDIVID_HASH4 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_GROUP_HASH1 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_GROUP_HASH2 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_GROUP_HASH3 ) + EMAC3_L_WRITE( SMAP_R_EMAC3_GROUP_HASH4 ) + + EMAC3_L_WRITE( SMAP_R_EMAC3_LAST_SA_HI ) + EMAC3_L_WRITE( SMAP_R_EMAC3_LAST_SA_LO ) + EMAC3_L_WRITE( SMAP_R_EMAC3_INTER_FRAME_GAP_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_STA_CTRL_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_TX_THRESHOLD_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_RX_WATERMARK_L ) + EMAC3_L_WRITE( SMAP_R_EMAC3_TX_OCTETS ) + EMAC3_L_WRITE( SMAP_R_EMAC3_RX_OCTETS ) + +#define EMAC3_H_WRITE(name) \ + case name: \ + DEV9_LOG("SMAP: " #name " 16 bit write %x\n", value); \ + dev9Ru16(addr) = value; \ + emac3_write(addr-2); \ + return; + //handle H writes + EMAC3_H_WRITE(SMAP_R_EMAC3_MODE0_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_MODE1_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_TxMODE0_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_TxMODE1_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_RxMODE_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INTR_STAT_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INTR_ENABLE_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_ADDR_HI_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_ADDR_LO_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_VLAN_TPID+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_PAUSE_TIMER_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INDIVID_HASH1+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INDIVID_HASH2+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INDIVID_HASH3+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INDIVID_HASH4+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_GROUP_HASH1+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_GROUP_HASH2+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_GROUP_HASH3+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_GROUP_HASH4+2 ) + + EMAC3_H_WRITE( SMAP_R_EMAC3_LAST_SA_HI+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_LAST_SA_LO+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_INTER_FRAME_GAP_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_STA_CTRL_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_TX_THRESHOLD_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_RX_WATERMARK_H ) + EMAC3_H_WRITE( SMAP_R_EMAC3_TX_OCTETS+2 ) + EMAC3_H_WRITE( SMAP_R_EMAC3_RX_OCTETS+2 ) +/* + case SMAP_R_EMAC3_MODE0_L: + DEV9_LOG("SMAP: SMAP_R_EMAC3_MODE0 write %x\n", value); + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_TxMODE0_L: + DEV9_LOG("SMAP: SMAP_R_EMAC3_TxMODE0_L 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_TxMODE1_L: + emu_printf("SMAP: SMAP_R_EMAC3_TxMODE1_L 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; + + case SMAP_R_EMAC3_TxMODE0_H: + emu_printf("SMAP: SMAP_R_EMAC3_TxMODE0_H 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; + + case SMAP_R_EMAC3_TxMODE1_H: + emu_printf("SMAP: SMAP_R_EMAC3_TxMODE1_H 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; + case SMAP_R_EMAC3_STA_CTRL_H: + DEV9_LOG("SMAP: SMAP_R_EMAC3_STA_CTRL_H 16bit write %x\n", value); + dev9Ru16(addr) = value; + return; + */ + + default : + DEV9_LOG("SMAP : Unknown 16 bit write @ %X,v=%X\n",addr,value); + dev9Ru16(addr) = value; + return; + } + + DEV9_LOG("SMAP : error , 16 bit write @ %X,v=%X\n",addr,value); + dev9Ru16(addr) = value; +} +void CALLBACK smap_write32(u32 addr, u32 value) +{ + if (addr>=SMAP_EMAC3_REGBASE && addr>16); + return; + } + switch(addr) + { + case SMAP_R_TXFIFO_DATA: + if(dev9.bd_swap) + value=(value<<24)|(value>>24)|((value>>8)&0xFF00)|((value<<8)&0xFF0000); + + DEV9_LOG("SMAP_R_TXFIFO_DATA 32bit write %x\n", value); + *((u32*)(dev9.txfifo+dev9Ru32(SMAP_R_TXFIFO_WR_PTR)))=value; + dev9Ru32(SMAP_R_TXFIFO_WR_PTR) = (dev9Ru32(SMAP_R_TXFIFO_WR_PTR)+4)&16383; + return; + default : + DEV9_LOG("SMAP : Unknown 32 bit write @ %X,v=%X\n",addr,value); + dev9Ru32(addr) = value; + return; + } + + DEV9_LOG("SMAP : error , 32 bit write @ %X,v=%X\n",addr,value); + dev9Ru32(addr) = value; +} +void CALLBACK smap_readDMA8Mem(u32 *pMem, int size) +{ + if(dev9Ru16(SMAP_R_RXFIFO_CTRL)&SMAP_RXFIFO_DMAEN) + { + dev9Ru32(SMAP_R_RXFIFO_RD_PTR)&=16383; + size>>=1; + DEV9_LOG(" * * SMAP DMA READ START: rd_ptr=%d, wr_ptr=%d\n", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); + while(size>0) + { + *pMem = *((u32*)(dev9.rxfifo+dev9Ru32(SMAP_R_RXFIFO_RD_PTR))); + pMem++; + dev9Ru32(SMAP_R_RXFIFO_RD_PTR) = (dev9Ru32(SMAP_R_RXFIFO_RD_PTR)+4)&16383; + + size-=4; + } + DEV9_LOG(" * * SMAP DMA READ END: rd_ptr=%d, wr_ptr=%d\n", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); + + dev9Ru16(SMAP_R_RXFIFO_CTRL) &= ~SMAP_RXFIFO_DMAEN; + } +} +void CALLBACK smap_writeDMA8Mem(u32* pMem, int size) +{ + if(dev9Ru16(SMAP_R_TXFIFO_CTRL)&SMAP_TXFIFO_DMAEN) + { + dev9Ru32(SMAP_R_TXFIFO_WR_PTR)&=16383; + size>>=1; + DEV9_LOG(" * * SMAP DMA WRITE START: wr_ptr=%d, rd_ptr=%d\n", dev9Ru32(SMAP_R_TXFIFO_WR_PTR), dev9.txfifo_rd_ptr); + while(size>0) + { + int value=*pMem; + // value=(value<<24)|(value>>24)|((value>>8)&0xFF00)|((value<<8)&0xFF0000); + pMem++; + + *((u32*)(dev9.txfifo+dev9Ru32(SMAP_R_TXFIFO_WR_PTR)))=value; + dev9Ru32(SMAP_R_TXFIFO_WR_PTR) = (dev9Ru32(SMAP_R_TXFIFO_WR_PTR)+4)&16383; + size-=4; + } + DEV9_LOG(" * * SMAP DMA WRITE END: wr_ptr=%d, rd_ptr=%d\n", dev9Ru32(SMAP_R_TXFIFO_WR_PTR), dev9.txfifo_rd_ptr); + + dev9Ru16(SMAP_R_TXFIFO_CTRL) &= ~SMAP_TXFIFO_DMAEN; + + } +} diff --git a/plugins/dev9/dev9ghzdrk/Win32/smap.h b/plugins/dev9/dev9ghzdrk/Win32/smap.h new file mode 100644 index 0000000000..d1bea98866 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/smap.h @@ -0,0 +1,13 @@ +#pragma once +#include "dev9.h" + +u8 CALLBACK smap_read8(u32 addr); +u16 CALLBACK smap_read16(u32 addr); +u32 CALLBACK smap_read32(u32 addr); + +void CALLBACK smap_write8(u32 addr, u8 value); +void CALLBACK smap_write16(u32 addr, u16 value); +void CALLBACK smap_write32(u32 addr, u32 value); + +void CALLBACK smap_readDMA8Mem(u32 *pMem, int size); +void CALLBACK smap_writeDMA8Mem(u32 *pMem, int size); \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/socket_io.cpp b/plugins/dev9/dev9ghzdrk/Win32/socket_io.cpp new file mode 100644 index 0000000000..bd8e306141 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/socket_io.cpp @@ -0,0 +1,294 @@ +#include +#include + +#include +extern "C" { +#include "dev9.h" +} +#include + +#include "pcap_io.h" + +#include +#include +#include + +//extern "C" int emu_printf(const char *fmt, ...); + +mac_address gateway_mac = { 0x76, 0x6D, 0x61, 0x63, 0x30, 0x32 }; +mac_address virtual_mac = { 0x76, 0x6D, 0x61, 0x63, 0x30, 0x31 }; +mac_address broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +//mac_address host_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +ip_address virtual_gway_ip = { 192, 168, 1, 1}; +ip_address virtual_host_ip = { 192, 168, 1, 2}; + +char namebuff[256]; + +FILE*packet_log; + +int pcap_io_running=0; + +class packet_info +{ +public: + int length; + s8 data[2048]; + + packet_info() + { + length=0; + memset(data,0,2048); + } + + packet_info(const packet_info& pkt) + { + length=pkt.length; + memcpy(data,pkt.data,length); + } + + packet_info(int l, void*d) + { + length=l; + memcpy(data,d,l); + } +}; + +std::queue recv_queue; + + +int ip_checksum(u16 *data, int length) +{ + int n=(length+1)>>1; + int s=0; + for(int i=0;i>16); + return s; +} + +// +int pcap_io_init(char *adapter) +{ + WSADATA wsaData; + + emu_printf(" * Socket IO: Initializing virtual gateway...",adapter); + + WSAStartup(0x0200,&wsaData); + + packet_log=fopen("logs/packet.log","w"); + + pcap_io_running=1; + + emu_printf("Ok.\n"); + return 0; +} + +int pcap_io_send(void* packet, int plen) +{ + emu_printf(" * Socket IO: Sending %d byte packet.\n",plen); + + if(packet_log) + { + int i=0; + int n=0; + + fprintf(packet_log,"PACKET SEND: %d BYTES\n",plen); + for(i=0,n=0;idst,broadcast_mac)==0) //broadcast packets + { + if(eth->protocol == 0x0608) //ARP + { + arp_packet *arp = (arp_packet*)((s8*)packet+sizeof(ethernet_header)); + if(arp->operation == 0x0100) //ARP request + { + if(ip_compare(arp->p_dst,virtual_gway_ip)==0) //it's trying to resolve the virtual gateway's mac addr + { + full_arp_packet p; + p.header.src = gateway_mac; + p.header.dst = eth->src; + p.header.protocol = 0x0608; + p.arp.h_addr_len=6; + p.arp.h_dst = eth->src; + p.arp.h_src = gateway_mac; + p.arp.p_addr_len = 4; + p.arp.p_dst = arp->p_src; + p.arp.p_src = virtual_gway_ip; + p.arp.protocol = 0x0008; + p.arp.operation = 0x0200; + + //packet_info pkt(sizeof(p),&p) + recv_queue.push(packet_info(sizeof(p),&p)); + } + } + } + } + else if(mac_compare(eth->dst,gateway_mac)==0) + { + if(eth->protocol == 0x0008) //IP + { + ip_header *ip = (ip_header*)((s8*)packet+sizeof(ethernet_header)); + + if((ip->proto == 0x11) && (ip->dst.bytes[0]!=192)) //UDP (non-local) + { + // + //if(ip-> + } + else + if(ip->proto == 0x01) //ICMP + { + if (ip_compare(ip->dst,virtual_gway_ip)==0) //PING to gateway + { + static u8 icmp_packet[1024]; + + memcpy(icmp_packet,packet,plen); + + ethernet_header *eh = (ethernet_header *)icmp_packet; + + eh->dst=eth->src; + eh->src=gateway_mac; + + ip_header *iph = (ip_header*)(eh+1); + + iph->dst = ip->src; + iph->src = virtual_gway_ip; + + iph->hdr_csum = 0; + + int sum = ip_checksum((u16*)iph,sizeof(ip_header)); + iph->hdr_csum = sum; + + icmp_header *ich = (icmp_header*)(iph+1); + + ich->type=0; + ich->code=0; + ich->csum=0; + + sum = ip_checksum((u16*)ich,iph->len-sizeof(ip_header)); + ich->csum = sum; + + recv_queue.push(packet_info(plen,&icmp_packet)); + + } + else if (ip->dst.bytes[0] != 192) //PING to external + { + static u8 icmp_packet[1024]; + + memcpy(icmp_packet,packet,plen); + + ethernet_header *eh = (ethernet_header *)icmp_packet; + + eh->dst=eth->src; + eh->src=gateway_mac; + + ip_header *iph = (ip_header*)(eh+1); + + iph->dst = ip->src; + iph->src = virtual_gway_ip; + + iph->hdr_csum = 0; + + int sum = ip_checksum((u16*)iph,sizeof(ip_header)); + iph->hdr_csum = sum; + + icmp_header *ich = (icmp_header*)(iph+1); + + ich->type=0; + ich->code=0; + ich->csum=0; + + sum = ip_checksum((u16*)ich,iph->len-sizeof(ip_header)); + ich->csum = sum; + + recv_queue.push(packet_info(plen,&icmp_packet)); + + } + } + } + } + + return 0; +} + +int pcap_io_recv(void* packet, int max_len) +{ + if(pcap_io_running<=0) + return -1; + + if(!recv_queue.empty()) + { + packet_info pkt(recv_queue.front()); + recv_queue.pop(); + + memcpy(packet,pkt.data,pkt.length); + + if(packet_log) + { + int i=0; + int n=0; + int plen=pkt.length; + + fprintf(packet_log,"PACKET RECV: %d BYTES\n",plen); + for(i=0,n=0;i +#include + +#include "packet32.h" +#include "ntddndis.h" + +#include "socks.h" +#include "DEV9.h" + +#define BUFFER_SIZE (2048) + +LPADAPTER lpAdapter; +LPPACKET lpSendPacket; +LPPACKET lpRecvPacket; +u8 buffer[BUFFER_SIZE]; +u8 *buf; +int lbytes; +int tbytes; +typedef struct { + char name[256]; + char desc[256]; +} _Adapter; + +_Adapter AdapterList[16]; + +long sockOpen(char *Device) { + lpAdapter = PacketOpenAdapter(Device); + if (lpAdapter == NULL) return -1; + +#ifdef DEV9_LOG + DEV9_LOG("PacketOpenAdapter %s: %p\n", Device, lpAdapter); +#endif + + if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE){ + SysMessage("Warning: unable to set promiscuous mode!"); + } + + if(PacketSetBuff(lpAdapter,512000)==FALSE){ + SysMessage("Unable to set the kernel buffer!"); + return -1; + } + + if(PacketSetReadTimeout(lpAdapter,100)==FALSE){ + SysMessage("Warning: unable to set the read tiemout!"); + } + + if((lpRecvPacket = PacketAllocatePacket())==NULL){ + SysMessage("Error: failed to allocate the LPPACKET structure."); + return (-1); + } + if((lpSendPacket = PacketAllocatePacket())==NULL){ + SysMessage("Error: failed to allocate the LPPACKET structure."); + return (-1); + } + + lbytes=0; + tbytes=0; + + return 0; +} + +void sockClose() { + PacketCloseAdapter(lpAdapter); +} + +long sockSendData(void *pData, int Size) { + u8 *data = (u8*)pData; +// printf("_sendPacket %d (time=%d)\n", Size, timeGetTime()); + while (Size > 0) { + PacketInitPacket(lpSendPacket, data, Size > 1024 ? 1024 : Size); + if(PacketSendPacket(lpAdapter,lpSendPacket,FALSE)==FALSE){ + printf("Error: PacketSendPacket failed\n"); + return (-1); + } + data+= 1024; Size-= 1024; + PacketFreePacket(lpSendPacket); + } + + return 0; +} + +int _filterPacket(u8 *_buf) { +/* DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[5], _buf[4], _buf[3], _buf[2], _buf[1], _buf[0]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[11], _buf[10], _buf[9], _buf[8], _buf[7], _buf[6]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[17], _buf[16], _buf[15], _buf[14], _buf[13], _buf[12]); + DEV9_LOG("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", _buf[23], _buf[22], _buf[21], _buf[20], _buf[19], _buf[18]); +*/ + if (_buf[0] == 0xff && _buf[1] == 0xff && _buf[2] == 0xff && + _buf[3] == 0xff && _buf[4] == 0xff && _buf[5] == 0xff) { + return 1; + } else + if (_buf[0] == 0x00 && _buf[1] == 0x00 && _buf[2] == 0x00 && + _buf[3] == 0x00 && _buf[4] == 0x00 && _buf[5] == 0x00) { + return 1; + } else + if (*((u16*)&_buf[12]) == 0x0806) { + printf("ARP\n"); + return 1; + } + + return 0; +} + +int _recvPacket(void *pData) { + struct bpf_hdr *hdr; + u8 *data; + int ret=0; + int size; + + while (lbytes > 0) { + hdr = (struct bpf_hdr *)buf; +// DEV9_LOG("hdr %d,%d,%d\n", hdr->bh_hdrlen, hdr->bh_caplen, hdr->bh_datalen); +// DEV9_LOG("lbytes %d\n", lbytes); + data = buf+hdr->bh_hdrlen; + size = Packet_WORDALIGN(hdr->bh_hdrlen+hdr->bh_datalen); + buf+= size; lbytes-= size; + if (_filterPacket(data)) { + struct bpf_stat stat; + + ret = hdr->bh_datalen; + memcpy(pData, data, ret); + if(PacketGetStats(lpAdapter,&stat)==FALSE){ + printf("Warning: unable to get stats from the kernel!\n"); + } +// printf("_recvPacket %d (tbytes=%d, packets=%d, lost=%d, time=%d)\n", ret, tbytes, stat.bs_recv,stat.bs_drop, timeGetTime()); +// printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", data[5], data[4], data[3], data[2], data[1], data[0]); + break; + } + } + + return ret; +} + +long sockRecvData(void *pData, int Size) { + int ret; + + ret = _recvPacket(pData); + if (ret > 0) return ret; + + PacketInitPacket(lpRecvPacket, buffer, BUFFER_SIZE); + if(PacketReceivePacket(lpAdapter,lpRecvPacket,TRUE)==FALSE){ + printf("Error: PacketReceivePacket failed"); + return (-1); + } + lbytes = lpRecvPacket->ulBytesReceived; + tbytes+= lbytes; +// DEV9_LOG("PacketReceivePacket %d:\n", lbytes); + if (lbytes == 0) return 0; + memcpy(buffer, lpRecvPacket->Buffer, lbytes); + buf = buffer; + PacketFreePacket(lpRecvPacket); + + return _recvPacket(pData); +} + +long sockGetDevicesNum() { + char AdapterName[8192]; // string that contains a list of the network adapters + ULONG AdapterLength; + char *temp,*temp1; + int i; + + AdapterLength = sizeof(AdapterName); + if(PacketGetAdapterNames(AdapterName,&AdapterLength)==FALSE){ + printf("Unable to retrieve the list of the adapters!\n"); + return -1; + } + temp=AdapterName; + temp1=AdapterName; + + i=0; + while (temp[0] != 0) { + strcpy(AdapterList[i++].name, temp); + temp+= strlen(temp)+1; + } + i=0; temp++; + while (temp[0] != 0) { + strcpy(AdapterList[i++].desc, temp); + temp+= strlen(temp)+1; + } + + return i; +} + +char *sockGetDevice(int index) { + return AdapterList[index].name; +} + +char *sockGetDeviceDesc(int index) { + return AdapterList[index].desc; +} + diff --git a/plugins/dev9/dev9ghzdrk/Win32/socks.h b/plugins/dev9/dev9ghzdrk/Win32/socks.h new file mode 100644 index 0000000000..22cf9ab151 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/socks.h @@ -0,0 +1,12 @@ +#ifndef __SOCKS_H__ +#define __SOCKS_H__ + +long sockOpen(char *Device); +void sockClose(); +long sockSendData(void *pData, int Size); +long sockRecvData(void *pData, int Size); +long sockGetDevicesNum(); +char *sockGetDevice(int index); +char *sockGetDeviceDesc(int index); + +#endif /* __SOCKS_H__*/ diff --git a/plugins/dev9/dev9ghzdrk/Win32/tap-win32.cpp b/plugins/dev9/dev9ghzdrk/Win32/tap-win32.cpp new file mode 100644 index 0000000000..9f328e2ea1 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/tap-win32.cpp @@ -0,0 +1,1080 @@ +/* + * TAP-Win32 -- A kernel driver to provide virtual tap device functionality + * on Windows. Originally derived from the CIPE-Win32 + * project by Damion K. Wilson, with extensive modifications by + * James Yonan. + * + * All source code which derives from the CIPE-Win32 project is + * Copyright (C) Damion K. Wilson, 2003, and is released under the + * GPL version 2 (see below). + * + * All other source code is Copyright (C) James Yonan, 2003-2004, + * and is released under the GPL version 2 (see below). + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include "tap.h" +#include "dev9.h" +#include + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define TAPSUFFIX ".tap" + +#ifdef WIN_X64 +#define TAP_COMPONENT_ID "tap0901" +#else +#define TAP_COMPONENT_ID "tap0801" +#endif + +vector* get_tap_reg () +{ + vector* names = new vector(); + HKEY adapter_key; + LONG status; + DWORD len; + + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + ADAPTER_KEY, + 0, + KEY_READ, + &adapter_key); + + if (status != ERROR_SUCCESS) + printf ( "Error opening registry key: %s", ADAPTER_KEY); + + while (true) + { + char enum_name[256]; + char unit_string[256]; + HKEY unit_key; + char component_id_string[] = "ComponentId"; + char component_id[256]; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + DWORD data_type; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + adapter_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) + printf ( "Error enumerating registry subkeys of key: %s", + ADAPTER_KEY); + + _snprintf (unit_string, sizeof(unit_string), "%s\\%s", + ADAPTER_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + unit_string, + 0, + KEY_READ, + &unit_key); + + if (status != ERROR_SUCCESS) + printf ( "Error opening registry key: %s", unit_string); + else + { + len = sizeof (component_id); + status = RegQueryValueEx( + unit_key, + component_id_string, + NULL, + &data_type, + (LPBYTE)component_id, + &len); + + if (status != ERROR_SUCCESS || data_type != REG_SZ) + printf ( "Error opening registry key: %s\\%s", + unit_string, component_id_string); + else + { + len = sizeof (net_cfg_instance_id); + status = RegQueryValueEx( + unit_key, + net_cfg_instance_id_string, + NULL, + &data_type, + (LPBYTE)net_cfg_instance_id, + &len); + + if (status == ERROR_SUCCESS && data_type == REG_SZ) + { + if(!memcmp(component_id, "tap",3)) + { + printf("*** Found possible tap adapter: %s\n",component_id); + + int version = atoi(component_id+3); + if(version>=800) + { + names->push_back(net_cfg_instance_id); + } + } + } + } + RegCloseKey (unit_key); + } + ++i; + } + + RegCloseKey (adapter_key); + return names; +} + +struct temp_11{string name;string guid;}; +vector* get_panel_reg () +{ + LONG status; + HKEY network_connections_key; + DWORD len; + vector* names = new vector(); + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + NETWORK_CONNECTIONS_KEY, + 0, + KEY_READ, + &network_connections_key); + + if (status != ERROR_SUCCESS) + printf ( "Error opening registry key: %s", NETWORK_CONNECTIONS_KEY); + + while (true) + { + char enum_name[256]; + char connection_string[256]; + HKEY connection_key; + char name_data[256]; + DWORD name_type; + const char name_string[] = "Name"; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + network_connections_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) + printf ( "Error enumerating registry subkeys of key: %s", + NETWORK_CONNECTIONS_KEY); + + _snprintf (connection_string, sizeof(connection_string), + "%s\\%s\\Connection", + NETWORK_CONNECTIONS_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + connection_string, + 0, + KEY_READ, + &connection_key); + + if (status != ERROR_SUCCESS) + printf ( "Error opening registry key: %s", connection_string); + else + { + len = sizeof (name_data); + status = RegQueryValueEx( + connection_key, + name_string, + NULL, + &name_type, + (LPBYTE)name_data, + &len); + + if (status != ERROR_SUCCESS || name_type != REG_SZ) + printf ( "Error opening registry key: %s\\%s\\%s", + NETWORK_CONNECTIONS_KEY, connection_string, name_string); + else + { + temp_11 t = {name_data,enum_name}; + names->push_back(t); + + } + RegCloseKey (connection_key); + } + ++i; + } + + RegCloseKey (network_connections_key); + + return names; +} + + +vector* GetTapAdapters() +{ + vector* rv = new vector(); + int links; + + vector *tap_reg = get_tap_reg (); + vector *panel_reg = get_panel_reg (); + + printf ( "\nAvailable TAP-WIN32 adapters [name, GUID]:\n"); + + /* loop through each TAP-Win32 adapter registry entry */ + for (size_t i = 0; isize();i++) + { + links = 0; + + /* loop through each network connections entry in the control panel */ + for (size_t j = 0; jsize();j++) + { + if (!strcmp ((*tap_reg)[i].c_str(), (*panel_reg)[j].guid.c_str())) + { + //printf ("'%s' %s\n", (*panel_reg)[j].name.c_str(),(*tap_reg)[i].c_str()); + tap_adapter t = { (*panel_reg)[j].name,(*tap_reg)[i]}; + t.guid= string("tap:") + t.guid; + t.name=string("tap:") + t.name; + rv->push_back(t); + ++links; + } + } + + if (links > 1) + { + //warn_panel_dup = true; + } + else if (links == 0) + { + /* a TAP adapter exists without a link from the network + connections control panel */ +// warn_panel_null = true; + printf ("[NULL] %s\n",(*tap_reg)[i].c_str()); + } + } + delete tap_reg,panel_reg; + return rv; +} + +//Set the connection status +static int TAPSetStatus(HANDLE handle, int status) +{ + unsigned long len = 0; + + return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof (status), + &status, sizeof (status), &len, NULL); +} +//Open the TAP adapter and set the connection to enabled :) +HANDLE TAPOpen(const char *device_guid) +{ + char device_path[256]; + + struct { + unsigned long major; + unsigned long minor; + unsigned long debug; + } version; + LONG version_len; + + _snprintf (device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAPSUFFIX); + + HANDLE handle = CreateFile ( + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 ); + + if (handle == INVALID_HANDLE_VALUE) { + return INVALID_HANDLE_VALUE; + } + + BOOL bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, + &version, sizeof (version), + &version, sizeof (version), (LPDWORD)&version_len, NULL); + + if (bret == FALSE) { + CloseHandle(handle); + return INVALID_HANDLE_VALUE; + } + + if (!TAPSetStatus(handle, TRUE)) { + return INVALID_HANDLE_VALUE; + } + + return handle; +} + + + +TAPAdapter::TAPAdapter() +{ + htap=TAPOpen(config.Eth+4); + + read.Offset = 0; + read.OffsetHigh = 0; + read.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + write.Offset = 0; + write.OffsetHigh = 0; + write.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + +} + +bool TAPAdapter::blocks() +{ + return true; //we use blocking io +} +u8 broadcast_adddrrrr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; +//gets a packet.rv :true success +bool TAPAdapter::recv(NetPacket* pkt) +{ + DWORD read_size; + BOOL result = ReadFile(htap, + pkt->buffer, + sizeof(pkt->buffer), + &read_size, + &read); + + if (!result) { + DWORD dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + WaitForSingleObject(read.hEvent, INFINITE); + result = GetOverlappedResult( htap, &read, + &read_size, FALSE); + if (!result) + { + + } + } + else { + + } + } + + + if (result) + { + if((memcmp(pkt->buffer,dev9.eeprom,6)!=0)&&(memcmp(pkt->buffer,&broadcast_adddrrrr,6)!=0)) + { + //ignore strange packets + return false; + } + + if(memcmp(pkt->buffer+6,dev9.eeprom,6)==0) + { + //avoid pcap looping packets + return false; + } + pkt->size=read_size; + return true; + } + else + return false; +} +//sends the packet .rv :true success +bool TAPAdapter::send(NetPacket* pkt) +{ + DWORD writen; + BOOL result = WriteFile(htap, + pkt->buffer, + pkt->size, + &writen, + &write); + + if (!result) { + DWORD dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + WaitForSingleObject(write.hEvent, INFINITE); + result = GetOverlappedResult( htap, &write, + &writen, FALSE); + if (!result) + { + + } + } + else { + + } + } + + if (result) + { + if (writen!=pkt->size) + return false; + + return true; + } + else + return false; +} +TAPAdapter::~TAPAdapter() +{ + CloseHandle(read.hEvent); + CloseHandle(write.hEvent); + TAPSetStatus(htap, FALSE); + CloseHandle(htap); +} + +//i leave these for reference, in case we need msth :p +#if 0==666 +//====================== +// Compile time configuration +//====================== + +//#define DEBUG_TAP_WIN32 1 + +#define TUN_ASYNCHRONOUS_WRITES 1 + +#define TUN_BUFFER_SIZE 1560 +#define TUN_MAX_BUFFER_COUNT 32 + +/* + * The data member "buffer" must be the first element in the tun_buffer + * structure. See the function, tap_win32_free_buffer. + */ +typedef struct tun_buffer_s { + unsigned char buffer [TUN_BUFFER_SIZE]; + unsigned long read_size; + struct tun_buffer_s* next; +} tun_buffer_t; + +typedef struct tap_win32_overlapped { + HANDLE handle; + HANDLE read_event; + HANDLE write_event; + HANDLE output_queue_semaphore; + HANDLE free_list_semaphore; + HANDLE tap_semaphore; + CRITICAL_SECTION output_queue_cs; + CRITICAL_SECTION free_list_cs; + OVERLAPPED read_overlapped; + OVERLAPPED write_overlapped; + tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT]; + tun_buffer_t* free_list; + tun_buffer_t* output_queue_front; + tun_buffer_t* output_queue_back; +} tap_win32_overlapped_t; + +static tap_win32_overlapped_t tap_overlapped; + +static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) +{ + tun_buffer_t* buffer = NULL; + WaitForSingleObject(overlapped->free_list_semaphore, INFINITE); + EnterCriticalSection(&overlapped->free_list_cs); + buffer = overlapped->free_list; +// assert(buffer != NULL); + overlapped->free_list = buffer->next; + LeaveCriticalSection(&overlapped->free_list_cs); + buffer->next = NULL; + return buffer; +} + +static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) +{ + EnterCriticalSection(&overlapped->free_list_cs); + buffer->next = overlapped->free_list; + overlapped->free_list = buffer; + LeaveCriticalSection(&overlapped->free_list_cs); + ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL); +} + +static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) +{ + tun_buffer_t* buffer = NULL; + DWORD result, timeout = block ? INFINITE : 0L; + + // Non-blocking call + result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); + + switch (result) + { + // The semaphore object was signaled. + case WAIT_OBJECT_0: + EnterCriticalSection(&overlapped->output_queue_cs); + + buffer = overlapped->output_queue_front; + overlapped->output_queue_front = buffer->next; + + if(overlapped->output_queue_front == NULL) { + overlapped->output_queue_back = NULL; + } + + LeaveCriticalSection(&overlapped->output_queue_cs); + break; + + // Semaphore was nonsignaled, so a time-out occurred. + case WAIT_TIMEOUT: + // Cannot open another window. + break; + } + + return buffer; +} + +static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) +{ + return get_buffer_from_output_queue(overlapped, 0); +} + +static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) +{ + EnterCriticalSection(&overlapped->output_queue_cs); + + if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) { + overlapped->output_queue_front = overlapped->output_queue_back = buffer; + } else { + buffer->next = NULL; + overlapped->output_queue_back->next = buffer; + overlapped->output_queue_back = buffer; + } + + LeaveCriticalSection(&overlapped->output_queue_cs); + + ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL); +} + + +static int is_tap_win32_dev(const char *guid) +{ + HKEY netcard_key; + LONG status; + DWORD len; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + ADAPTER_KEY, + 0, + KEY_READ, + &netcard_key); + + if (status != ERROR_SUCCESS) { + return FALSE; + } + + for (;;) { + char enum_name[256]; + char unit_string[256]; + HKEY unit_key; + char component_id_string[] = "ComponentId"; + char component_id[256]; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + DWORD data_type; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + netcard_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) { + return FALSE; + } + + _snprintf(unit_string, sizeof(unit_string), "%s\\%s", + ADAPTER_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + unit_string, + 0, + KEY_READ, + &unit_key); + + if (status != ERROR_SUCCESS) { + return FALSE; + } else { + len = sizeof (component_id); + status = RegQueryValueEx( + unit_key, + component_id_string, + NULL, + &data_type, + (LPBYTE)component_id, + &len); + + if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { + len = sizeof (net_cfg_instance_id); + status = RegQueryValueEx( + unit_key, + net_cfg_instance_id_string, + NULL, + &data_type, + (LPBYTE)net_cfg_instance_id, + &len); + + if (status == ERROR_SUCCESS && data_type == REG_SZ) { + if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/ + !strcmp (net_cfg_instance_id, guid)) { + RegCloseKey (unit_key); + RegCloseKey (netcard_key); + return TRUE; + } + } + } + RegCloseKey (unit_key); + } + ++i; + } + + RegCloseKey (netcard_key); + return FALSE; +} + +static int get_device_guid( + char *name, + int name_size, + char *actual_name, + int actual_name_size) +{ + LONG status; + HKEY control_net_key; + DWORD len; + int i = 0; + int stop = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + NETWORK_CONNECTIONS_KEY, + 0, + KEY_READ, + &control_net_key); + + if (status != ERROR_SUCCESS) { + return -1; + } + + while (!stop) + { + char enum_name[256]; + char connection_string[256]; + HKEY connection_key; + char name_data[256]; + DWORD name_type; + const char name_string[] = "Name"; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + control_net_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) { + return -1; + } + + _snprintf(connection_string, + sizeof(connection_string), + "%s\\%s\\Connection", + NETWORK_CONNECTIONS_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + connection_string, + 0, + KEY_READ, + &connection_key); + + if (status == ERROR_SUCCESS) { + len = sizeof (name_data); + status = RegQueryValueEx( + connection_key, + name_string, + NULL, + &name_type, + (LPBYTE)name_data, + &len); + + if (status != ERROR_SUCCESS || name_type != REG_SZ) { + return -1; + } + else { + if (is_tap_win32_dev(enum_name)) { + _snprintf(name, name_size, "%s", enum_name); + if (actual_name) { + if (strcmp(actual_name, "") != 0) { + if (strcmp(name_data, actual_name) != 0) { + RegCloseKey (connection_key); + ++i; + continue; + } + } + else { + _snprintf(actual_name, actual_name_size, "%s", name_data); + } + } + stop = 1; + } + } + + RegCloseKey (connection_key); + } + ++i; + } + + RegCloseKey (control_net_key); + + if (stop == 0) + return -1; + + return 0; +} + + + +static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle) +{ + overlapped->handle = handle; + + overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); + overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + overlapped->read_overlapped.Offset = 0; + overlapped->read_overlapped.OffsetHigh = 0; + overlapped->read_overlapped.hEvent = overlapped->read_event; + + overlapped->write_overlapped.Offset = 0; + overlapped->write_overlapped.OffsetHigh = 0; + overlapped->write_overlapped.hEvent = overlapped->write_event; + + InitializeCriticalSection(&overlapped->output_queue_cs); + InitializeCriticalSection(&overlapped->free_list_cs); + + overlapped->output_queue_semaphore = CreateSemaphore( + NULL, // default security attributes + 0, // initial count + TUN_MAX_BUFFER_COUNT, // maximum count + NULL); // unnamed semaphore + + if(!overlapped->output_queue_semaphore) { + fprintf(stderr, "error creating output queue semaphore!\n"); + } + + overlapped->free_list_semaphore = CreateSemaphore( + NULL, // default security attributes + TUN_MAX_BUFFER_COUNT, // initial count + TUN_MAX_BUFFER_COUNT, // maximum count + NULL); // unnamed semaphore + + if(!overlapped->free_list_semaphore) { + fprintf(stderr, "error creating free list semaphore!\n"); + } + + overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL; + + { + unsigned index; + for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) { + tun_buffer_t* element = &overlapped->buffers[index]; + element->next = overlapped->free_list; + overlapped->free_list = element; + } + } + /* To count buffers, initially no-signal. */ + overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL); + if(!overlapped->tap_semaphore) + fprintf(stderr, "error creating tap_semaphore.\n"); +} + +static int tap_win32_write(tap_win32_overlapped_t *overlapped, + const void *buffer, unsigned long size) +{ + unsigned long write_size; + BOOL result; + DWORD error; + + result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped, + &write_size, FALSE); + + if (!result && GetLastError() == ERROR_IO_INCOMPLETE) + WaitForSingleObject(overlapped->write_event, INFINITE); + + result = WriteFile(overlapped->handle, buffer, size, + &write_size, &overlapped->write_overlapped); + + if (!result) { + switch (error = GetLastError()) + { + case ERROR_IO_PENDING: +#ifndef TUN_ASYNCHRONOUS_WRITES + WaitForSingleObject(overlapped->write_event, INFINITE); +#endif + break; + default: + return -1; + } + } + + return 0; +} + +static DWORD WINAPI tap_win32_thread_entry(LPVOID param) +{ + tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param; + unsigned long read_size; + BOOL result; + DWORD dwError; + tun_buffer_t* buffer = get_buffer_from_free_list(overlapped); + + + for (;;) { + result = ReadFile(overlapped->handle, + buffer->buffer, + sizeof(buffer->buffer), + &read_size, + &overlapped->read_overlapped); + if (!result) { + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) { + WaitForSingleObject(overlapped->read_event, INFINITE); + result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, + &read_size, FALSE); + if (!result) { +#if DEBUG_TAP_WIN32 + LPVOID lpBuffer; + dwError = GetLastError(); + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) & lpBuffer, 0, NULL ); + fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer); + LocalFree( lpBuffer ); +#endif + } + } else { +#if DEBUG_TAP_WIN32 + LPVOID lpBuffer; + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) & lpBuffer, 0, NULL ); + fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer); + LocalFree( lpBuffer ); +#endif + } + } + + if(read_size > 0) { + buffer->read_size = read_size; + put_buffer_on_output_queue(overlapped, buffer); + ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL); + buffer = get_buffer_from_free_list(overlapped); + } + } + + return 0; +} + +typedef unsigned __int8 uint8_t; + +static int tap_win32_read(tap_win32_overlapped_t *overlapped, + uint8_t **pbuf, int max_size) +{ + int size = 0; + + tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped); + + if(buffer != NULL) { + *pbuf = buffer->buffer; + size = (int)buffer->read_size; + if(size > max_size) { + size = max_size; + } + } + + return size; +} + +static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, + char* pbuf) +{ + tun_buffer_t* buffer = (tun_buffer_t*)pbuf; + put_buffer_on_free_list(overlapped, buffer); +} + +static int tap_win32_open(tap_win32_overlapped_t **phandle, + const char *prefered_name) +{ + char device_path[256]; + char device_guid[0x100]; + int rc; + HANDLE handle; + BOOL bret; + char name_buffer[0x100] = {0, }; + struct { + unsigned long major; + unsigned long minor; + unsigned long debug; + } version; + LONG version_len; + DWORD idThread; + HANDLE hThread; + + if (prefered_name != NULL) + _snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name); + + rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer)); + if (rc) + return -1; + + _snprintf (device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAPSUFFIX); + + handle = CreateFile ( + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 ); + + if (handle == INVALID_HANDLE_VALUE) { + return -1; + } + + bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, + &version, sizeof (version), + &version, sizeof (version), (LPDWORD)&version_len, NULL); + + if (bret == FALSE) { + CloseHandle(handle); + return -1; + } + + if (!tap_win32_set_status(handle, TRUE)) { + return -1; + } + + tap_win32_overlapped_init(&tap_overlapped, handle); + + *phandle = &tap_overlapped; + + hThread = CreateThread(NULL, 0, tap_win32_thread_entry, + (LPVOID)&tap_overlapped, 0, &idThread); + return 0; +} + +/********************************************/ + + typedef struct TAPState { + tap_win32_overlapped_t *handle; + } TAPState; + +static void tap_receive(void *opaque, const uint8_t *buf, int size) +{ + TAPState *s = (TAPState *)opaque; + + tap_win32_write(s->handle, buf, size); +} + +static void tap_win32_send(void *opaque) +{ + TAPState *s = (TAPState *)opaque; + uint8_t *buf; + int max_size = 4096; + int size; + + size = tap_win32_read(s->handle, &buf, max_size); + if (size > 0) { + //qemu_send_packet(s->vc, buf, size); + tap_win32_free_buffer(s->handle, (char*)buf); + } +} + +int tap_win32_init(const char *ifname) +{ + TAPState *s = (TAPState *)malloc(sizeof(TAPState)); + if (!s) + return -1; + + memset(s,0,sizeof(TAPState)); + + if (tap_win32_open(&s->handle, ifname) < 0) { + printf("tap: Could not open '%s'\n", ifname); + return -1; + } + + return 0; +} + +#endif diff --git a/plugins/dev9/dev9ghzdrk/Win32/tap.h b/plugins/dev9/dev9ghzdrk/Win32/tap.h new file mode 100644 index 0000000000..a45f9b4b47 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/tap.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include "net.h" +using namespace std; + +struct tap_adapter +{ + string name; + string guid; +}; +vector* GetTapAdapters(); +class TAPAdapter : public NetAdapter +{ + HANDLE htap; + OVERLAPPED read,write; +public: + TAPAdapter(); + virtual bool blocks(); + //gets a packet.rv :true success + virtual bool recv(NetPacket* pkt); + //sends the packet and deletes it when done (if successful).rv :true success + virtual bool send(NetPacket* pkt); + virtual ~TAPAdapter(); +}; \ No newline at end of file diff --git a/plugins/dev9/dev9ghzdrk/Win32/vl.h b/plugins/dev9/dev9ghzdrk/Win32/vl.h new file mode 100644 index 0000000000..205b34a38b --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/Win32/vl.h @@ -0,0 +1,1419 @@ +/* + * QEMU System Emulator header + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef VL_H +#define VL_H + +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include +//#include +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +//typedef signed long int intptr_t; +//typedef unsigned long int uintptr_t; + +typedef signed long long int64_t; +typedef unsigned long long uint64_t; +typedef signed long long int intmax_t; +typedef unsigned long long int uintmax_t; + + +#include +#include +#include +#include +//#include +#include +#include + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif + +#ifdef _WIN32 +#include +#define fsync _commit +#define lseek _lseeki64 +#define ENOTSUP 4096 +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" +#endif + +#ifdef QEMU_TOOL + +/* we use QEMU_TOOL in the command line tools which do not depend on + the target CPU type */ +#include "config-host.h" +#include +#include "osdep.h" +#include "bswap.h" + +#else + +//#include "audio/audio.h" +//#include "cpu.h" + +#endif /* !defined(QEMU_TOOL) */ + +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/* cutils.c */ +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); + +/* vl.c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); + +void hw_error(const char *fmt, ...); + +extern const char *bios_dir; + +extern int vm_running; + +typedef struct vm_change_state_entry VMChangeStateEntry; +typedef void VMChangeStateHandler(void *opaque, int running); +typedef void VMStopHandler(void *opaque, int reason); + +VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, + void *opaque); +void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); + +int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque); +void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); + +void vm_start(void); +void vm_stop(int reason); + +typedef void QEMUResetHandler(void *opaque); + +void qemu_register_reset(QEMUResetHandler *func, void *opaque); +void qemu_system_reset_request(void); +void qemu_system_shutdown_request(void); +void qemu_system_powerdown_request(void); +#if !defined(TARGET_SPARC) +// Please implement a power failure function to signal the OS +#define qemu_system_powerdown() do{}while(0) +#else +void qemu_system_powerdown(void); +#endif + +void main_loop_wait(int timeout); + +extern int ram_size; +extern int bios_size; +extern int rtc_utc; +extern int cirrus_vga_enabled; +extern int graphic_width; +extern int graphic_height; +extern int graphic_depth; +extern const char *keyboard_layout; +extern int kqemu_allowed; +extern int win2k_install_hack; +extern int usb_enabled; +extern int smp_cpus; +extern int no_quit; +extern int semihosting_enabled; +extern int autostart; + +#define MAX_OPTION_ROMS 16 +extern const char *option_rom[MAX_OPTION_ROMS]; +extern int nb_option_roms; + +/* XXX: make it dynamic */ +#if defined (TARGET_PPC) || defined (TARGET_SPARC64) +#define BIOS_SIZE ((512 + 32) * 1024) +#elif defined(TARGET_MIPS) +#define BIOS_SIZE (4 * 1024 * 1024) +#else +#define BIOS_SIZE ((256 + 64) * 1024) +#endif + +/* keyboard/mouse support */ + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 + +typedef void QEMUPutKBDEvent(void *opaque, int keycode); +typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); + +typedef struct QEMUPutMouseEntry { + QEMUPutMouseEvent *qemu_put_mouse_event; + void *qemu_put_mouse_event_opaque; + int qemu_put_mouse_event_absolute; + char *qemu_put_mouse_event_name; + + /* used internally by qemu for handling mice */ + struct QEMUPutMouseEntry *next; +} QEMUPutMouseEntry; + +void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name); +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); + +void kbd_put_keycode(int keycode); +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); +int kbd_mouse_is_absolute(void); + +void do_info_mice(void); +void do_mouse_set(int index); + +/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx + constants) */ +#define QEMU_KEY_ESC1(c) ((c) | 0xe100) +#define QEMU_KEY_BACKSPACE 0x007f +#define QEMU_KEY_UP QEMU_KEY_ESC1('A') +#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') +#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') +#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') +#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) +#define QEMU_KEY_END QEMU_KEY_ESC1(4) +#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) +#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) +#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) + +#define QEMU_KEY_CTRL_UP 0xe400 +#define QEMU_KEY_CTRL_DOWN 0xe401 +#define QEMU_KEY_CTRL_LEFT 0xe402 +#define QEMU_KEY_CTRL_RIGHT 0xe403 +#define QEMU_KEY_CTRL_HOME 0xe404 +#define QEMU_KEY_CTRL_END 0xe405 +#define QEMU_KEY_CTRL_PAGEUP 0xe406 +#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 + +void kbd_put_keysym(int keysym); + +/* async I/O support */ + +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); +typedef void IOHandler(void *opaque); + +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); + +/* Polling handling */ + +/* return TRUE if no sleep should be done afterwards */ +typedef int PollingFunc(void *opaque); + +int qemu_add_polling_cb(PollingFunc *func, void *opaque); +void qemu_del_polling_cb(PollingFunc *func, void *opaque); + +#ifdef _WIN32 +/* Wait objects handling */ +typedef void WaitObjectFunc(void *opaque); + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +#endif + +typedef struct QEMUBH QEMUBH; + +/* character device */ + +#define CHR_EVENT_BREAK 0 /* serial break char */ +#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ +#define CHR_EVENT_RESET 2 /* new connection established */ + + +#define CHR_IOCTL_SERIAL_SET_PARAMS 1 +typedef struct { + int speed; + int parity; + int data_bits; + int stop_bits; +} QEMUSerialSetParams; + +#define CHR_IOCTL_SERIAL_SET_BREAK 2 + +#define CHR_IOCTL_PP_READ_DATA 3 +#define CHR_IOCTL_PP_WRITE_DATA 4 +#define CHR_IOCTL_PP_READ_CONTROL 5 +#define CHR_IOCTL_PP_WRITE_CONTROL 6 +#define CHR_IOCTL_PP_READ_STATUS 7 + +typedef void IOEventHandler(void *opaque, int event); + +typedef struct CharDriverState { + int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); + void (*chr_update_read_handler)(struct CharDriverState *s); + int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); + IOEventHandler *chr_event; + IOCanRWHandler *chr_can_read; + IOReadHandler *chr_read; + void *handler_opaque; + void (*chr_send_event)(struct CharDriverState *chr, int event); + void (*chr_close)(struct CharDriverState *chr); + void *opaque; + QEMUBH *bh; +} CharDriverState; + +CharDriverState *qemu_chr_open(const char *filename); +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); +void qemu_chr_send_event(CharDriverState *s, int event); +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque); +int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); +void qemu_chr_reset(CharDriverState *s); +int qemu_chr_can_read(CharDriverState *s); +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); + +/* consoles */ + +typedef struct DisplayState DisplayState; +typedef struct TextConsole TextConsole; + +typedef void (*vga_hw_update_ptr)(void *); +typedef void (*vga_hw_invalidate_ptr)(void *); +typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); + +TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, + vga_hw_invalidate_ptr invalidate, + vga_hw_screen_dump_ptr screen_dump, + void *opaque); +void vga_hw_update(void); +void vga_hw_invalidate(void); +void vga_hw_screen_dump(const char *filename); + +int is_graphic_console(void); +CharDriverState *text_console_init(DisplayState *ds); +void console_select(unsigned int index); + +/* serial ports */ + +#define MAX_SERIAL_PORTS 4 + +extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; + +/* parallel ports */ + +#define MAX_PARALLEL_PORTS 3 + +extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; + +/* VLANs support */ + +typedef struct VLANClientState VLANClientState; + +struct VLANClientState { + IOReadHandler *fd_read; + /* Packets may still be sent if this returns zero. It's used to + rate-limit the slirp code. */ + IOCanRWHandler *fd_can_read; + void *opaque; + struct VLANClientState *next; + struct VLANState *vlan; + char info_str[256]; +}; + +typedef struct VLANState { + int id; + VLANClientState *first_client; + struct VLANState *next; +} VLANState; + +VLANState *qemu_find_vlan(int id); +VLANClientState *qemu_new_vlan_client(VLANState *vlan, + IOReadHandler *fd_read, + IOCanRWHandler *fd_can_read, + void *opaque); +int qemu_can_send_packet(VLANClientState *vc); +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); +void qemu_handler_true(void *opaque); + +void do_info_network(void); + +/* TAP win32 */ +int tap_win32_init(VLANState *vlan, const char *ifname); + +/* NIC info */ + +#define MAX_NICS 8 + +typedef struct NICInfo { + uint8_t macaddr[6]; + const char *model; + VLANState *vlan; +} NICInfo; + +extern int nb_nics; +extern NICInfo nd_table[MAX_NICS]; + +/* timers */ + +typedef struct QEMUClock QEMUClock; +typedef struct QEMUTimer QEMUTimer; +typedef void QEMUTimerCB(void *opaque); + +/* The real time clock should be used only for stuff which does not + change the virtual machine state, as it is run even if the virtual + machine is stopped. The real time clock has a frequency of 1000 + Hz. */ +extern QEMUClock *rt_clock; + +/* The virtual clock is only run during the emulation. It is stopped + when the virtual machine is stopped. Virtual timers use a high + precision clock, usually cpu cycles (use ticks_per_sec). */ +extern QEMUClock *vm_clock; + +int64_t qemu_get_clock(QEMUClock *clock); + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); +void qemu_free_timer(QEMUTimer *ts); +void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +int qemu_timer_pending(QEMUTimer *ts); + +extern int64_t ticks_per_sec; +extern int pit_min_timer_count; + +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + +/* VM Load/Save */ + +typedef struct QEMUFile QEMUFile; + +QEMUFile *qemu_fopen(const char *filename, const char *mode); +void qemu_fflush(QEMUFile *f); +void qemu_fclose(QEMUFile *f); +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_byte(QEMUFile *f, int v); +void qemu_put_be16(QEMUFile *f, unsigned int v); +void qemu_put_be32(QEMUFile *f, unsigned int v); +void qemu_put_be64(QEMUFile *f, uint64_t v); +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +int qemu_get_byte(QEMUFile *f); +unsigned int qemu_get_be16(QEMUFile *f); +unsigned int qemu_get_be32(QEMUFile *f); +uint64_t qemu_get_be64(QEMUFile *f); + +static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) +{ + qemu_put_be64(f, *pv); +} + +static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) +{ + qemu_put_be32(f, *pv); +} + +static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) +{ + qemu_put_be16(f, *pv); +} + +static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) +{ + qemu_put_byte(f, *pv); +} + +static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) +{ + *pv = qemu_get_be64(f); +} + +static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) +{ + *pv = qemu_get_be32(f); +} + +static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) +{ + *pv = qemu_get_be16(f); +} + +static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) +{ + *pv = qemu_get_byte(f); +} + +#if TARGET_LONG_BITS == 64 +#define qemu_put_betl qemu_put_be64 +#define qemu_get_betl qemu_get_be64 +#define qemu_put_betls qemu_put_be64s +#define qemu_get_betls qemu_get_be64s +#else +#define qemu_put_betl qemu_put_be32 +#define qemu_get_betl qemu_get_be32 +#define qemu_put_betls qemu_put_be32s +#define qemu_get_betls qemu_get_be32s +#endif + +int64_t qemu_ftell(QEMUFile *f); +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); + +typedef void SaveStateHandler(QEMUFile *f, void *opaque); +typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); + +int register_savevm(const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque); +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); + +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + +void do_savevm(const char *name); +void do_loadvm(const char *name); +void do_delvm(const char *name); +void do_info_snapshots(void); + +/* bottom halves */ +typedef void QEMUBHFunc(void *opaque); + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +void qemu_bh_schedule(QEMUBH *bh); +void qemu_bh_cancel(QEMUBH *bh); +void qemu_bh_delete(QEMUBH *bh); +int qemu_bh_poll(void); + +/* block.c */ +typedef struct BlockDriverState BlockDriverState; +typedef struct BlockDriver BlockDriver; + +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_host_device; +extern BlockDriver bdrv_cow; +extern BlockDriver bdrv_qcow; +extern BlockDriver bdrv_vmdk; +extern BlockDriver bdrv_cloop; +extern BlockDriver bdrv_dmg; +extern BlockDriver bdrv_bochs; +extern BlockDriver bdrv_vpc; +extern BlockDriver bdrv_vvfat; +extern BlockDriver bdrv_qcow2; + +typedef struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; +} BlockDriverInfo; + +typedef struct QEMUSnapshotInfo { + char id_str[128]; /* unique snapshot id */ + /* the following fields are informative. They are not needed for + the consistency of the snapshot */ + char name[256]; /* user choosen name */ + uint32_t vm_state_size; /* VM state info size */ + uint32_t date_sec; /* UTC date of the snapshot */ + uint32_t date_nsec; + uint64_t vm_clock_nsec; /* VM clock relative to boot */ +} QEMUSnapshotInfo; + +#define BDRV_O_RDONLY 0x0000 +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_ACCESS 0x0003 +#define BDRV_O_CREAT 0x0004 /* create an empty file */ +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ +#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to + use a disk image format on top of + it (default for + bdrv_file_open()) */ + +void bdrv_init(void); +BlockDriver *bdrv_find_format(const char *format_name); +int bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_delete(BlockDriverState *bs); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags); +int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, + BlockDriver *drv); +void bdrv_close(BlockDriverState *bs); +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); +void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); +int bdrv_commit(BlockDriverState *bs); +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +/* async block I/O */ +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +void bdrv_aio_cancel(BlockDriverAIOCB *acb); + +void qemu_aio_init(void); +void qemu_aio_poll(void); +void qemu_aio_flush(void); +void qemu_aio_wait_start(void); +void qemu_aio_wait(void); +void qemu_aio_wait_end(void); + +/* Ensure contents are flushed to disk. */ +void bdrv_flush(BlockDriverState *bs); + +#define BDRV_TYPE_HD 0 +#define BDRV_TYPE_CDROM 1 +#define BDRV_TYPE_FLOPPY 2 +#define BIOS_ATA_TRANSLATION_AUTO 0 +#define BIOS_ATA_TRANSLATION_NONE 1 +#define BIOS_ATA_TRANSLATION_LBA 2 +#define BIOS_ATA_TRANSLATION_LARGE 3 +#define BIOS_ATA_TRANSLATION_RECHS 4 + +void bdrv_set_geometry_hint(BlockDriverState *bs, + int cyls, int heads, int secs); +void bdrv_set_type_hint(BlockDriverState *bs, int type); +void bdrv_set_translation_hint(BlockDriverState *bs, int translation); +void bdrv_get_geometry_hint(BlockDriverState *bs, + int *pcyls, int *pheads, int *psecs); +int bdrv_get_type_hint(BlockDriverState *bs); +int bdrv_get_translation_hint(BlockDriverState *bs); +int bdrv_is_removable(BlockDriverState *bs); +int bdrv_is_read_only(BlockDriverState *bs); +int bdrv_is_inserted(BlockDriverState *bs); +int bdrv_media_changed(BlockDriverState *bs); +int bdrv_is_locked(BlockDriverState *bs); +void bdrv_set_locked(BlockDriverState *bs, int locked); +void bdrv_eject(BlockDriverState *bs, int eject_flag); +void bdrv_set_change_cb(BlockDriverState *bs, + void (*change_cb)(void *opaque), void *opaque); +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); +void bdrv_info(void); +BlockDriverState *bdrv_find(const char *name); +void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); +int bdrv_is_encrypted(BlockDriverState *bs); +int bdrv_set_key(BlockDriverState *bs, const char *key); +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque); +const char *bdrv_get_device_name(BlockDriverState *bs); +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + +void bdrv_get_backing_filename(BlockDriverState *bs, + char *filename, int filename_size); +int bdrv_snapshot_create(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); +int bdrv_snapshot_goto(BlockDriverState *bs, + const char *snapshot_id); +int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); +int bdrv_snapshot_list(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); +char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); + +char *get_human_readable_size(char *buf, int buf_size, int64_t size); +int path_is_absolute(const char *path); +void path_combine(char *dest, int dest_size, + const char *base_path, + const char *filename); + +#ifndef QEMU_TOOL + +typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, + int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +typedef struct QEMUMachine { + const char *name; + const char *desc; + QEMUMachineInitFunc *init; + struct QEMUMachine *next; +} QEMUMachine; + +int qemu_register_machine(QEMUMachine *m); + +typedef void SetIRQFunc(void *opaque, int irq_num, int level); +typedef void IRQRequestFunc(void *opaque, int level); + +#ifdef ASDDasdasda0011 +/* ISA bus */ + +extern target_phys_addr_t isa_mem_base; + +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); + +int register_ioport_read(int start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(int start, int length, int size, + IOPortWriteFunc *func, void *opaque); +void isa_unassign_ioport(int start, int length); + +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size); + +/* PCI bus */ + +extern target_phys_addr_t pci_mem_base; + +typedef struct PCIBus PCIBus; +typedef struct PCIDevice PCIDevice; + +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, + uint32_t address, uint32_t data, int len); +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, + uint32_t address, int len); +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type); + +#define PCI_ADDRESS_SPACE_MEM 0x00 +#define PCI_ADDRESS_SPACE_IO 0x01 +#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 + +typedef struct PCIIORegion { + uint32_t addr; /* current PCI mapping address. -1 means not mapped */ + uint32_t size; + uint8_t type; + PCIMapIORegionFunc *map_func; +} PCIIORegion; + +#define PCI_ROM_SLOT 6 +#define PCI_NUM_REGIONS 7 + +#define PCI_DEVICES_MAX 64 + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +struct PCIDevice { + /* PCI config space */ + uint8_t config[256]; + + /* the following fields are read only */ + PCIBus *bus; + int devfn; + char name[64]; + PCIIORegion io_regions[PCI_NUM_REGIONS]; + + /* do not access the following fields */ + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + /* ??? This is a PC-specific hack, and should be removed. */ + int irq_index; + + /* Current IRQ levels. Used internally by the generic PCI code. */ + int irq_state[4]; +}; + +PCIDevice *pci_register_device(PCIBus *bus, const char *name, + int instance_size, int devfn, + PCIConfigReadFunc *config_read, + PCIConfigWriteFunc *config_write); + +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, + PCIMapIORegionFunc *map_func); + +void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level); + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len); +void pci_default_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +void pci_device_save(PCIDevice *s, QEMUFile *f); +int pci_device_load(PCIDevice *s, QEMUFile *f); + +typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level); +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *pic, int devfn_min, int nirq); + +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); +uint32_t pci_data_read(void *opaque, uint32_t addr, int len); +int pci_bus_num(PCIBus *s); +void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)); + +void pci_info(void); +PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, + pci_map_irq_fn map_irq, const char *name); + +/* prep_pci.c */ +PCIBus *pci_prep_init(void); + +/* grackle_pci.c */ +PCIBus *pci_grackle_init(uint32_t base, void *pic); + +/* unin_pci.c */ +PCIBus *pci_pmac_init(void *pic); + +/* apb_pci.c */ +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, + void *pic); + +PCIBus *pci_vpb_init(void *pic, int irq, int realview); + +/* piix_pci.c */ +PCIBus *i440fx_init(PCIDevice **pi440fx_state); +void i440fx_set_smm(PCIDevice *d, int val); +int piix3_init(PCIBus *bus, int devfn); +void i440fx_init_memory_mappings(PCIDevice *d); + +int piix4_init(PCIBus *bus, int devfn); + +/* openpic.c */ +typedef struct openpic_t openpic_t; +void openpic_set_irq(void *opaque, int n_IRQ, int level); +openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + CPUState **envp); + +/* heathrow_pic.c */ +typedef struct HeathrowPICS HeathrowPICS; +void heathrow_pic_set_irq(void *opaque, int num, int level); +HeathrowPICS *heathrow_pic_init(int *pmem_index); + +/* gt64xxx.c */ +PCIBus *pci_gt64120_init(void *pic); + +#ifdef HAS_AUDIO +struct soundhw { + const char *name; + const char *descr; + int enabled; + int isa; + union { + int (*init_isa) (AudioState *s); + int (*init_pci) (PCIBus *bus, AudioState *s); + } init; +}; + +extern struct soundhw soundhw[]; +#endif + +/* vga.c */ + +#define VGA_RAM_SIZE (8192 * 1024) + +struct DisplayState { + uint8_t *data; + int linesize; + int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ + int width; + int height; + void *opaque; + + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); + void (*dpy_resize)(struct DisplayState *s, int w, int h); + void (*dpy_refresh)(struct DisplayState *s); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); +}; + +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) +{ + s->dpy_update(s, x, y, w, h); +} + +static inline void dpy_resize(DisplayState *s, int w, int h) +{ + s->dpy_resize(s, w, h); +} + +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size); + +/* cirrus_vga.c */ +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + +/* sdl.c */ +void sdl_display_init(DisplayState *ds, int full_screen); + +/* cocoa.m */ +void cocoa_display_init(DisplayState *ds, int full_screen); + +/* vnc.c */ +void vnc_display_init(DisplayState *ds, const char *display); +void do_info_vnc(void); + +/* x_keymap.c */ +extern uint8_t _translate_keycode(const int key); + +/* ide.c */ +#define MAX_DISKS 4 + +extern BlockDriverState *bs_table[MAX_DISKS + 1]; + +void isa_ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1); +void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, + int secondary_ide_enabled); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); +int pmac_ide_init (BlockDriverState **hd_table, + SetIRQFunc *set_irq, void *irq_opaque, int irq); + +/* cdrom.c */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + +/* es1370.c */ +int es1370_init (PCIBus *bus, AudioState *s); + +/* sb16.c */ +int SB16_init (AudioState *s); + +/* adlib.c */ +int Adlib_init (AudioState *s); + +/* gus.c */ +int GUS_init (AudioState *s); + +/* dma.c */ +typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); +int DMA_get_channel_mode (int nchan); +int DMA_read_memory (int nchan, void *buf, int pos, int size); +int DMA_write_memory (int nchan, void *buf, int pos, int size); +void DMA_hold_DREQ (int nchan); +void DMA_release_DREQ (int nchan); +void DMA_schedule(int nchan); +void DMA_run (void); +void DMA_init (int high_page_enable); +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque); +/* fdc.c */ +#define MAX_FD 2 +extern BlockDriverState *fd_table[MAX_FD]; + +typedef struct fdctrl_t fdctrl_t; + +fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, + uint32_t io_base, + BlockDriverState **fds); +int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); + +/* ne2000.c */ + +void isa_ne2000_init(int base, int irq, NICInfo *nd); +void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* rtl8139.c */ + +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* pcnet.c */ + +void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); +void pcnet_h_reset(void *opaque); +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); + + +/* pckbd.c */ + +void kbd_init(void); + +/* mc146818rtc.c */ + +typedef struct RTCState RTCState; + +RTCState *rtc_init(int base, int irq); +void rtc_set_memory(RTCState *s, int addr, int val); +void rtc_set_date(RTCState *s, const struct tm *tm); + +/* serial.c */ + +typedef struct SerialState SerialState; +SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, + int base, int irq, CharDriverState *chr); +SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, + target_ulong base, int it_shift, + int irq, CharDriverState *chr); + +/* parallel.c */ + +typedef struct ParallelState ParallelState; +ParallelState *parallel_init(int base, int irq, CharDriverState *chr); + +/* i8259.c */ + +typedef struct PicState2 PicState2; +extern PicState2 *isa_pic; +void pic_set_irq(int irq, int level); +void pic_set_irq_new(void *opaque, int irq, int level); +PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, + void *alt_irq_opaque); +int pic_read_irq(PicState2 *s); +void pic_update_irq(PicState2 *s); +uint32_t pic_intack_read(PicState2 *s); +void pic_info(void); +void irq_info(void); + +/* APIC */ +typedef struct IOAPICState IOAPICState; + +int apic_init(CPUState *env); +int apic_get_interrupt(CPUState *env); +IOAPICState *ioapic_init(void); +void ioapic_set_irq(void *opaque, int vector, int level); + +/* i8254.c */ + +#define PIT_FREQ 1193182 + +typedef struct PITState PITState; + +PITState *pit_init(int base, int irq); +void pit_set_gate(PITState *pit, int channel, int val); +int pit_get_gate(PITState *pit, int channel); +int pit_get_initial_count(PITState *pit, int channel); +int pit_get_mode(PITState *pit, int channel); +int pit_get_out(PITState *pit, int channel, int64_t current_time); + +/* pcspk.c */ +void pcspk_init(PITState *); +int pcspk_audio_init(AudioState *); + +#include "hw/smbus.h" + +/* acpi.c */ +extern int acpi_enabled; +void piix4_pm_init(PCIBus *bus, int devfn); +void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); +void acpi_bios_init(void); + +/* smbus_eeprom.c */ +SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf); + +/* pc.c */ +extern QEMUMachine pc_machine; +extern QEMUMachine isapc_machine; +extern int fd_bootchk; + +void ioport_set_a20(int enable); +int ioport_get_a20(void); + +/* ppc.c */ +extern QEMUMachine prep_machine; +extern QEMUMachine core99_machine; +extern QEMUMachine heathrow_machine; + +/* mips_r4k.c */ +extern QEMUMachine mips_machine; + +/* mips_malta.c */ +extern QEMUMachine mips_malta_machine; + +/* mips_int */ +extern void cpu_mips_irq_request(void *opaque, int irq, int level); + +/* mips_timer.c */ +extern void cpu_mips_clock_init(CPUState *); +extern void cpu_mips_irqctrl_init (void); + +/* shix.c */ +extern QEMUMachine shix_machine; + +#ifdef TARGET_PPC +ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); +#endif +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); + +extern CPUWriteMemoryFunc *PPC_io_write[]; +extern CPUReadMemoryFunc *PPC_io_read[]; +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); + +/* sun4m.c */ +extern QEMUMachine sun4m_machine; +void pic_set_irq_cpu(int irq, int level, unsigned int cpu); + +/* iommu.c */ +void *iommu_init(uint32_t addr); +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write); +static inline void sparc_iommu_memory_read(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 0); +} + +static inline void sparc_iommu_memory_write(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 1); +} + +/* tcx.c */ +void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size, int width, int height); + +/* slavio_intctl.c */ +void *slavio_intctl_init(); +void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); +void slavio_pic_info(void *opaque); +void slavio_irq_info(void *opaque); +void slavio_pic_set_irq(void *opaque, int irq, int level); +void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); + +/* loader.c */ +int get_image_size(const char *filename); +int load_image(const char *filename, uint8_t *addr); +int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry); +int load_aout(const char *filename, uint8_t *addr); + +/* slavio_timer.c */ +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu); + +/* slavio_serial.c */ +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); +void slavio_serial_ms_kbd_init(int base, int irq); + +/* slavio_misc.c */ +void *slavio_misc_init(uint32_t base, int irq); +void slavio_set_power_fail(void *opaque, int power_failing); + +/* esp.c */ +void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); +void esp_reset(void *opaque); + +/* sparc32_dma.c */ +void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, + void *intctl); +void ledma_set_irq(void *opaque, int isr); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void espdma_raise_irq(void *opaque); +void espdma_clear_irq(void *opaque); +void espdma_memory_read(void *opaque, uint8_t *buf, int len); +void espdma_memory_write(void *opaque, uint8_t *buf, int len); +void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, + void *lance_opaque); + +/* cs4231.c */ +void cs_init(target_phys_addr_t base, int irq, void *intctl); + +/* sun4u.c */ +extern QEMUMachine sun4u_machine; + +/* NVRAM helpers */ +#include "hw/m48t59.h" + +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value); +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value); +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value); +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max); +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max); +void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, + uint32_t start, uint32_t count); +int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth); + +/* adb.c */ + +#define MAX_ADB_DEVICES 16 + +#define ADB_MAX_OUT_LEN 16 + +typedef struct ADBDevice ADBDevice; + +/* buf = NULL means polling */ +typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, + const uint8_t *buf, int len); +typedef int ADBDeviceReset(ADBDevice *d); + +struct ADBDevice { + struct ADBBusState *bus; + int devaddr; + int handler; + ADBDeviceRequest *devreq; + ADBDeviceReset *devreset; + void *opaque; +}; + +typedef struct ADBBusState { + ADBDevice devices[MAX_ADB_DEVICES]; + int nb_devices; + int poll_index; +} ADBBusState; + +int adb_request(ADBBusState *s, uint8_t *buf_out, + const uint8_t *buf, int len); +int adb_poll(ADBBusState *s, uint8_t *buf_out); + +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, + void *opaque); +void adb_kbd_init(ADBBusState *bus); +void adb_mouse_init(ADBBusState *bus); + +/* cuda.c */ + +extern ADBBusState adb_bus; +int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); + +#include "hw/usb.h" + +/* usb ports of the VM */ + +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach); + +#define VM_USB_HUB_SIZE 8 + +void do_usb_add(const char *devname); +void do_usb_del(const char *devname); +void usb_info(void); + +/* scsi-disk.c */ +enum scsi_reason { + SCSI_REASON_DONE, /* Command complete. */ + SCSI_REASON_DATA /* Transfer complete, more data required. */ +}; + +typedef struct SCSIDevice SCSIDevice; +typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, + uint32_t arg); + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + int tcq, + scsi_completionfn completion, + void *opaque); +void scsi_disk_destroy(SCSIDevice *s); + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); +/* SCSI data transfers are asynchrnonous. However, unlike the block IO + layer the completion routine may be called directly by + scsi_{read,write}_data. */ +void scsi_read_data(SCSIDevice *s, uint32_t tag); +int scsi_write_data(SCSIDevice *s, uint32_t tag); +void scsi_cancel_io(SCSIDevice *s, uint32_t tag); +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); + +/* lsi53c895a.c */ +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *lsi_scsi_init(PCIBus *bus, int devfn); + +/* integratorcp.c */ +extern QEMUMachine integratorcp926_machine; +extern QEMUMachine integratorcp1026_machine; + +/* versatilepb.c */ +extern QEMUMachine versatilepb_machine; +extern QEMUMachine versatileab_machine; + +/* realview.c */ +extern QEMUMachine realview_machine; + +/* ps2.c */ +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); +void ps2_write_mouse(void *, int val); +void ps2_write_keyboard(void *, int val); +uint32_t ps2_read_data(void *); +void ps2_queue(void *, int b); +void ps2_keyboard_set_translation(void *opaque, int mode); + +/* smc91c111.c */ +void smc91c111_init(NICInfo *, uint32_t, void *, int); + +/* pl110.c */ +void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int); + +/* pl011.c */ +void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr); + +/* pl050.c */ +void pl050_init(uint32_t base, void *pic, int irq, int is_mouse); + +/* pl080.c */ +void *pl080_init(uint32_t base, void *pic, int irq, int nchannels); + +/* pl190.c */ +void *pl190_init(uint32_t base, void *parent, int irq, int fiq); + +/* arm-timer.c */ +void sp804_init(uint32_t base, void *pic, int irq); +void icp_pit_init(uint32_t base, void *pic, int irq); + +/* arm_sysctl.c */ +void arm_sysctl_init(uint32_t base, uint32_t sys_id); + +/* arm_gic.c */ +void *arm_gic_init(uint32_t base, void *parent, int parent_irq); + +/* arm_boot.c */ + +void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + int board_id); + +/* sh7750.c */ +struct SH7750State; + +struct SH7750State *sh7750_init(CPUState * cpu); + +typedef struct { + /* The callback will be triggered if any of the designated lines change */ + uint16_t portamask_trigger; + uint16_t portbmask_trigger; + /* Return 0 if no action was taken */ + int (*port_change_cb) (uint16_t porta, uint16_t portb, + uint16_t * periph_pdtra, + uint16_t * periph_portdira, + uint16_t * periph_pdtrb, + uint16_t * periph_portdirb); +} sh7750_io_device; + +int sh7750_register_io_device(struct SH7750State *s, + sh7750_io_device * device); +/* tc58128.c */ +int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); + +/* NOR flash devices */ +typedef struct pflash_t pflash_t; + +pflash_t *pflash_register (target_ulong base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); + +#include "gdbstub.h" + +#endif /* defined(QEMU_TOOL) */ + +/* monitor.c */ +void monitor_init(CharDriverState *hd, int show_banner); +void term_puts(const char *str); +void term_vprintf(const char *fmt, va_list ap); +void term_printf(const char *fmt, ...); +void term_print_filename(const char *filename); +void term_flush(void); +void term_print_help(void); +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); + +/* readline.c */ +typedef void ReadLineFunc(void *opaque, const char *str); + +extern int completion_index; +void add_completion(const char *str); +void readline_handle_byte(int ch); +void readline_find_completion(const char *cmdline); +const char *readline_get_history(unsigned int index); +void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque); + +void kqemu_record_dump(void); +#endif + +#endif /* VL_H */ diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.dll b/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.dll new file mode 100644 index 0000000000000000000000000000000000000000..26a4a65d779e861a65e1221cfbb268e10d7a147a GIT binary patch literal 88696 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 literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.lib b/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/Packet.lib new file mode 100644 index 0000000000000000000000000000000000000000..bc9dba853308409bd98da2d296a919d44cb00585 GIT binary patch literal 8674 zcmcIp&2JM|5FaNYfj~nD`Tleus_2E1V3QzKRlZBW36X8uqgm`tS=IJ#?F}tldPS%Q z4*UzfQHcYWa-tH~9xA00w^kLm{sV{u>AZdWKKFTXaAIk)yEF6V_daIc%zK&s!m1VT ze%bwbQvJ=&F3hFU3+bzKD*saWIXk})zTWNzfE9qA8o-$c0DaE@Mkgr^?*R}RT%a`i z82LzJuPKeM0}$$OqcpM%K&bx>rP24OkJRr|n%n^(G?1k{5hrRP5?qf z?kb=i4>4 zJBonn=Im;TzNxA*U)QWRQbhsPT`HH|qUGBr%esu}Y*ZcJq%HHQe7$BH?aF+rnYD{H zPM*oECZZ}UWw&k{Cr*`6?VRmj`(fQFM`l?OP+eTv(C(I1v9OhqES0LfgLU(a_f{OMKpo)!m9m z+)h)qeIZbEGfu_Pml(TDw3&$NZ`28Ity;26s%=HUZD(B9yMtTivVGUO=eXM5ga}au z+Li=}Q`;_D-ZiUQDr*CYNDrPbukw6(9usD*2jIaOfMoI_J z%v5dt0Lvo)Z}9mZ`93~(Fw12J0IH}nIRWq-^*W~k-VLD)ZH(jdNfO}26u=BVpQ6p{ z`2Gm_KI*;2HV=`Wq1`>S^$Kla@`i5cfm6^6=b;nEU%lXFihGrtc zMtO82;jJTKgIWzYD&C5xTFQwgAcJ@7H2`gDNVmqk6WP>7N~VTHGUgc;!)007!L=&UK&D(2l;%Pl!+?}}DoAFR@pG^u;3oI+J! zl_j#r%KV7m>cZH~N%LW?t>np3i7_!sUahr=NzI0Y#r<5iB73{SZ?x6xo-a32{9hJm zQJ{(pRgdt0HO~mXR*|631<@f}COlKEBu9#-PejJd*|6}7#*SuEiXdHLDpsUu($tlh z(qufc6uyYBMkg9CIM7@ymCH1Te(0n*KbsEEoVU9(iFWws-v{geB>=M#z&`+qlLsCR|wox+#DB|XAlgyc({GR*lW$R~7*MY{lJd%KWDrwoe^ zeBV#@Z92u8TX%Q-yLTBU7#zWAXPgw#K?ZQ0wBQgv)=2zEtYbOGzX{ehejVn)UYgS8 z;$SY#?p{b7v;}eS8+M9z77`{uDM>>huaci!W+LJzzp#(+N&JM^J@oZ&W>v8|#hGq! zPa<5T$yuA9kL(_QAwb-${T$8$dq}gEW<27Ef3T16DMeR`iHP2x>_gH!wApQDM)8c$ z@Pg^Uewe--PH2+c{E^ViB*>mT9gOaHgBo6}o4lDcw}$CiGa?Du1m=P8oUhbet>C4u zn(>HZwh26`l4}Jmoid}HL$r2*rq_oOq}~}uE-H>IXrh>J1uw-mQq61dA_A)f9)XzI~ZfJk229A4^*IXB>CU~nH7 zWQev! literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.dll b/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.dll new file mode 100644 index 0000000000000000000000000000000000000000..1dd1f69709e730b8fc56c5288e9d6b55e6735163 GIT binary patch literal 244336 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
nPkf9gCRobL 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 b)KiE$;pThSdo}Q04ZK$a@72J6OAY*AStsGh literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.lib b/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..abacd5d3652d38e0116fced9b25df4f75fc667db GIT binary patch literal 17046 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 +#include +#include "DEV9.h" + +#define PAGE_SIZE_BITS 9 +#define PAGE_SIZE (1<>2), page+PAGE_SIZE+0*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 1*(PAGE_SIZE>>2), page+PAGE_SIZE+1*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 2*(PAGE_SIZE>>2), page+PAGE_SIZE+2*3);//(ECC_SIZE>>2)); + xfromman_call20_calculateXors(page + 3*(PAGE_SIZE>>2), page+PAGE_SIZE+3*3);//(ECC_SIZE>>2)); +} + +static char* getCmdName(u32 cmd){ + switch(cmd) { + case SM_CMD_READ1: return "READ1"; + case SM_CMD_READ2: return "READ2"; + case SM_CMD_READ3: return "READ3"; + case SM_CMD_RESET: return "RESET"; + case SM_CMD_WRITEDATA: return "WRITEDATA"; + case SM_CMD_PROGRAMPAGE: return "PROGRAMPAGE"; + case SM_CMD_ERASEBLOCK: return "ERASEBLOCK"; + case SM_CMD_ERASECONFIRM: return "ERASECONFIRM"; + case SM_CMD_GETSTATUS: return "GETSTATUS"; + case SM_CMD_READID: return "READID"; + default: return "unknown"; + } +} + +void CALLBACK FLASHinit(){ + FILE *fd; + + id= FLASH_ID_64MBIT; + counter= 0; + addrbyte= 0; + + address = 0; + memset(data, 0xFF, PAGE_SIZE); + calculateECC(data); + ctrl = FLASH_PP_READY; + + if (fd=fopen("flash.dat", "rb")){ + fread(file, 1, CARD_SIZE_ECC, fd); + fclose(fd); + }else + memset(file, 0xFF, CARD_SIZE_ECC); +} + +u32 CALLBACK FLASHread32(u32 addr, int size) { + u32 value, refill= 0; + + switch(addr) { + case FLASH_R_DATA: + memcpy(&value, &data[counter], size); + counter += size; + DEV9_LOG("*FLASH DATA %dbit read 0x%08lX %s\n", size*8, value, (ctrl & FLASH_PP_READ) ? "READ_ENABLE" : "READ_DISABLE"); + if (cmd == SM_CMD_READ3){ + if (counter >= PAGE_SIZE_ECC){ + counter= PAGE_SIZE; + refill= 1; + } + }else{ + if ( (ctrl & FLASH_PP_NOECC) && (counter >= PAGE_SIZE)){ + counter %= PAGE_SIZE; + refill= 1; + }else + if (!(ctrl & FLASH_PP_NOECC) && (counter >= PAGE_SIZE_ECC)){ + counter %= PAGE_SIZE_ECC; + refill= 1; + } + } + + if (refill){ + ctrl &= ~FLASH_PP_READY; + address += PAGE_SIZE; + address %= CARD_SIZE; + memcpy(data, file+(address>>PAGE_SIZE_BITS)*PAGE_SIZE_ECC, PAGE_SIZE); + calculateECC(data); // calculate ECC; should be in the file already + ctrl |= FLASH_PP_READY; + } + + return value; + + case FLASH_R_CMD: + DEV9_LOG("*FLASH CMD %dbit read %s DENIED\n", size*8, getCmdName(cmd)); + return cmd; + + case FLASH_R_ADDR: + DEV9_LOG("*FLASH ADDR %dbit read DENIED\n", size*8); + return 0; + + case FLASH_R_CTRL: + DEV9_LOG("*FLASH CTRL %dbit read 0x%08lX\n", size*8, ctrl); + return ctrl; + + case FLASH_R_ID: + if (cmd == SM_CMD_READID){ + DEV9_LOG("*FLASH ID %dbit read 0x%08lX\n", size*8, id); + return id;//0x98=Toshiba/0xEC=Samsung maker code should be returned first + }else + if (cmd == SM_CMD_GETSTATUS){ + value= 0x80 | ((ctrl & 1) << 6); // 0:0=pass, 6:ready/busy, 7:1=not protected + DEV9_LOG("*FLASH STATUS %dbit read 0x%08lX\n", size*8, value); + return value; + }//else fall off + + default: + DEV9_LOG("*FLASH Unkwnown %dbit read at address %lx\n", size*8, addr); + return 0; + } +} + +void CALLBACK FLASHwrite32(u32 addr, u32 value, int size) { + + switch(addr & 0x1FFFFFFF) { + case FLASH_R_DATA: + + DEV9_LOG("*FLASH DATA %dbit write 0x%08lX %s\n", size*8, value, (ctrl & FLASH_PP_WRITE) ? "WRITE_ENABLE" : "WRITE_DISABLE"); + memcpy(&data[counter], &value, size); + counter += size; + counter %= PAGE_SIZE_ECC;//should not get past the last byte, but at the end + break; + + case FLASH_R_CMD: + if (!(ctrl & FLASH_PP_READY)){ + if ((value != SM_CMD_GETSTATUS) && (value != SM_CMD_RESET)){ + DEV9_LOG("*FLASH CMD %dbit write %s ILLEGAL in busy mode - IGNORED\n", size*8, getCmdName(value)); + break; + } + } + if (cmd == SM_CMD_WRITEDATA){ + if ((value != SM_CMD_PROGRAMPAGE) && (value != SM_CMD_RESET)){ + DEV9_LOG("*FLASH CMD %dbit write %s ILLEGAL after WRITEDATA cmd - IGNORED\n", size*8, getCmdName(value)); + ctrl &= ~FLASH_PP_READY;//go busy, reset is needed + break; + } + } + DEV9_LOG("*FLASH CMD %dbit write %s\n", size*8, getCmdName(value)); + switch (value){ // A8 bit is encoded in READ cmd;) + case SM_CMD_READ1: counter= 0; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_READ2: counter= PAGE_SIZE/2; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_READ3: counter= PAGE_SIZE; if (cmd != SM_CMD_GETSTATUS) address= counter; addrbyte= 0; break; + case SM_CMD_RESET: FLASHinit(); break; + case SM_CMD_WRITEDATA: counter= 0; address= counter; addrbyte= 0; break; + case SM_CMD_ERASEBLOCK: counter= 0; memset(data, 0xFF, PAGE_SIZE); address= counter; addrbyte= 1; break; + case SM_CMD_PROGRAMPAGE: //fall + case SM_CMD_ERASECONFIRM: + ctrl &= ~FLASH_PP_READY; + calculateECC(data); + memcpy(file+(address/PAGE_SIZE)*PAGE_SIZE_ECC, data, PAGE_SIZE_ECC); + /*write2file*/ + ctrl |= FLASH_PP_READY; break; + case SM_CMD_GETSTATUS: break; + case SM_CMD_READID: counter= 0; address= counter; addrbyte= 0; break; + default: + ctrl &= ~FLASH_PP_READY; + return;//ignore any other command; go busy, reset is needed + } + cmd= value; + break; + + case FLASH_R_ADDR: + DEV9_LOG("*FLASH ADDR %dbit write 0x%08lX\n", size*8, value); + address |= (value & 0xFF) << (addrbyte == 0 ? 0 : (1 + 8 * addrbyte)); + addrbyte++; + DEV9_LOG("*FLASH ADDR = 0x%08lX (addrbyte=%d)\n", address, addrbyte); + if (!(value & 0x100)){ // address is complete + if ((cmd == SM_CMD_READ1) || (cmd == SM_CMD_READ2) || (cmd == SM_CMD_READ3)) { + ctrl &= ~FLASH_PP_READY; + memcpy(data, file+(address>>PAGE_SIZE_BITS)*PAGE_SIZE_ECC, PAGE_SIZE); + calculateECC(data); // calculate ECC; should be in the file already + ctrl |= FLASH_PP_READY; + } + addrbyte= 0; // address reset + { + u32 bytes, pages, blocks; + + blocks = address / BLOCK_SIZE; + pages = address-(blocks*BLOCK_SIZE); + bytes = pages % PAGE_SIZE; + pages = pages / PAGE_SIZE; + DEV9_LOG("*FLASH ADDR = 0x%08lX (%d:%d:%d) (addrbyte=%d) FINAL\n", address, blocks, pages, bytes, addrbyte); + } + } + break; + + case FLASH_R_CTRL: + DEV9_LOG("*FLASH CTRL %dbit write 0x%08lX\n", size*8, value); + ctrl = (ctrl & FLASH_PP_READY) | (value & ~FLASH_PP_READY); + break; + + case FLASH_R_ID: + DEV9_LOG("*FLASH ID %dbit write 0x%08lX DENIED :P\n", size*8, value); + break; + + default: + DEV9_LOG("*FLASH Unkwnown %dbit write at address 0x%08lX= 0x%08lX IGNORED\n", size*8, addr, value); + break; + } +} + +static unsigned char xor_table[256]={ + 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00, + 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, + 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, + 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, + 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, + 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, + 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, + 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, + 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, + 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, + 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, + 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, + 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, + 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, + 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, + 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00}; + +static void xfromman_call20_calculateXors(unsigned char buffer[128], unsigned char xor[4]){ + register unsigned char a=0, b=0, c=0, i; + + for (i=0; i<128; i++){ + a ^= xor_table[buffer[i]]; + if (xor_table[buffer[i]] & 0x80){ + b ^= ~i; + c ^= i; + } + } + + xor[0]=(~a) & 0x77; + xor[1]=(~b) & 0x7F; + xor[2]=(~c) & 0x7F; +} diff --git a/plugins/dev9/dev9ghzdrk/pcap_io.cpp b/plugins/dev9/dev9ghzdrk/pcap_io.cpp new file mode 100644 index 0000000000..e4e97f9619 --- /dev/null +++ b/plugins/dev9/dev9ghzdrk/pcap_io.cpp @@ -0,0 +1,419 @@ +#include +#include +#include "pcap.h" +#include "pcap_io.h" + +#include "dev9.h" +#include "net.h" + +#include + +enum pcap_m_e +{ + switched, + bridged +}; +pcap_m_e pcap_mode=switched; +mac_address virtual_mac = { 0x76, 0x6D, 0x61, 0x63, 0x30, 0x31 }; +//mac_address virtual_mac = { 0x6D, 0x76, 0x63, 0x61, 0x31, 0x30 }; +mac_address broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +ip_address virtual_ip = { 192, 168, 1, 4}; + +pcap_t *adhandle; +int pcap_io_running=0; + +char errbuf[PCAP_ERRBUF_SIZE]; + +char namebuff[256]; + +FILE*packet_log; + +pcap_dumper_t *dump_pcap; + +mac_address host_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// Fetches the MAC address and prints it +int GetMACAddress(char *adapter, mac_address* addr) +{ + static IP_ADAPTER_INFO AdapterInfo[128]; // Allocate information + // for up to 128 NICs + static PIP_ADAPTER_INFO pAdapterInfo; + ULONG dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer + + DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo + AdapterInfo, // [out] buffer to receive data + &dwBufLen); // [in] size of receive data buffer + if(dwStatus != ERROR_SUCCESS) // Verify return value is + return 0; // valid, no buffer overflow + + pAdapterInfo = AdapterInfo; // Contains pointer to + // current adapter info + do { + if(strcmp(pAdapterInfo->AdapterName,adapter+12)==0) + { + memcpy(addr,pAdapterInfo->Address,6); + return 1; + } + + pAdapterInfo = pAdapterInfo->Next; // Progress through + } + while(pAdapterInfo); // Terminate if last adapter + return 0; +} + +int pcap_io_init(char *adapter) +{ + int dlt; + char *dlt_name; + emu_printf("Opening adapter '%s'...",adapter); + + GetMACAddress(adapter,&host_mac); + + /* Open the adapter */ + if ((adhandle= pcap_open_live(adapter, // name of the device + 65536, // portion of the packet to capture. + // 65536 grants that the whole packet will be captured on all the MACs. + pcap_mode==switched?1:0, // promiscuous mode (nonzero means promiscuous) + 1, // read timeout + errbuf // error buffer + )) == NULL) + { + fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", adapter); + return -1; + } + + dlt = pcap_datalink(adhandle); + dlt_name = (char*)pcap_datalink_val_to_name(dlt); + + fprintf(stderr,"Device uses DLT %d: %s\n",dlt,dlt_name); + switch(dlt) + { + case DLT_EN10MB : + //case DLT_IEEE802_11: + break; + default: + SysMessage("ERROR: Unsupported DataLink Type (%d): %s",dlt,dlt_name); + pcap_close(adhandle); + return -1; + } + + if(pcap_setnonblock(adhandle,1,errbuf)==-1) + { + fprintf(stderr,"WARNING: Error setting non-blocking mode. Default mode will be used.\n"); + } + + packet_log=fopen("logs/packet.log","w"); + + dump_pcap = pcap_dump_open(adhandle,"logs/pkt_log.pcap"); + + pcap_io_running=1; + emu_printf("Ok.\n"); + return 0; +} + +int gettimeofday (struct timeval *tv, void* tz) +{ + unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ + + GetSystemTimeAsFileTime((LPFILETIME)&ns100); + tv->tv_usec = (long) ((ns100 / 10L) % 1000000L); + tv->tv_sec = (long) ((ns100 - 116444736000000000L) / 10000000L); + return (0); +} + +int pcap_io_send(void* packet, int plen) +{ + struct pcap_pkthdr ph; + + if(pcap_io_running<=0) + return -1; + emu_printf(" * pcap io: Sending %d byte packet.\n",plen); + + if (pcap_mode==bridged) + { + if(((ethernet_header*)packet)->protocol == 0x0008) //IP + { +#ifndef PLOT_VERSION + virtual_ip = ((ip_header*)((u8*)packet+sizeof(ethernet_header)))->src; +#endif + virtual_mac = ((ethernet_header*)packet)->src; + } + if(((ethernet_header*)packet)->protocol == 0x0608) //ARP + { +#ifndef PLOT_VERSION + virtual_ip = ((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->p_src; +#endif + virtual_mac = ((ethernet_header*)packet)->src; + + ((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->h_src = host_mac; + } + ((ethernet_header*)packet)->src = host_mac; + } + + if(dump_pcap) + { + gettimeofday(&ph.ts,NULL); + ph.caplen=plen; + ph.len=plen; + pcap_dump((u_char*)dump_pcap,&ph,(u_char*)packet); + } + + if(packet_log) + { + int i=0; + int n=0; + + fprintf(packet_log,"PACKET SEND: %d BYTES\n",plen); + for(i=0,n=0;idst,broadcast_mac)==0) + { + static char pack[65536]; + memcpy(pack,packet,plen); + + ((ethernet_header*)packet)->dst=host_mac; + pcap_sendpacket(adhandle, (u_char*)pack, plen); + } + } + + return pcap_sendpacket(adhandle, (u_char*)packet, plen); +} + +int pcap_io_recv(void* packet, int max_len) +{ + int res; + struct pcap_pkthdr *header; + const u_char *pkt_data1; + static u_char pkt_data[32768]; + + if(pcap_io_running<=0) + return -1; + + if((res = pcap_next_ex(adhandle, &header, &pkt_data1)) > 0) + { + ethernet_header *ph=(ethernet_header*)pkt_data; + + memcpy(pkt_data,pkt_data1,header->len); + + if (pcap_mode==bridged) + { + if(((ethernet_header*)pkt_data)->protocol == 0x0008) + { + ip_header *iph=((ip_header*)((u8*)pkt_data+sizeof(ethernet_header))); + if(ip_compare(iph->dst,virtual_ip)==0) + { + ((ethernet_header*)pkt_data)->dst = virtual_mac; + } + } + if(((ethernet_header*)pkt_data)->protocol == 0x0608) + { + arp_packet *aph=((arp_packet*)((u8*)pkt_data+sizeof(ethernet_header))); + if(ip_compare(aph->p_dst,virtual_ip)==0) + { + ((ethernet_header*)pkt_data)->dst = virtual_mac; + ((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->h_dst = virtual_mac; + } + } + } + + if((memcmp(pkt_data,dev9.eeprom,6)!=0)&&(memcmp(pkt_data,&broadcast_mac,6)!=0)) + { + //ignore strange packets + return 0; + } + + if(memcmp(pkt_data+6,dev9.eeprom,6)==0) + { + //avoid pcap looping packets + return 0; + } + + memcpy(packet,pkt_data,header->len); + + if(dump_pcap) + pcap_dump((u_char*)dump_pcap,header,(u_char*)packet); + + + if(packet_log) + { + int i=0; + int n=0; + int plen=header->len; + + fprintf(packet_log,"PACKET RECV: %d BYTES\n",plen); + for(i=0,n=0;ilen; + } + + return -1; +} + +void pcap_io_close() +{ + if(packet_log) + fclose(packet_log); + if(dump_pcap) + pcap_dump_close(dump_pcap); + pcap_close(adhandle); + pcap_io_running=0; +} + + +int pcap_io_get_dev_num() +{ + pcap_if_t *alldevs; + pcap_if_t *d; + int i=0; + + if(pcap_findalldevs(&alldevs, errbuf) == -1) + { + return 0; + } + + d=alldevs; + while(d!=NULL) {d=d->next; i++;} + + pcap_freealldevs(alldevs); + + return i; +} + +char* pcap_io_get_dev_name(int num,int md) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + int i=0; + + if(pcap_findalldevs(&alldevs, errbuf) == -1) + { + return NULL; + } + + d=alldevs; + while(d!=NULL) { + if(num==i) + { + if (!md) + strcpy(namebuff,"pcap switch:"); + else + strcpy(namebuff,"pcap bridge:"); + strcat(namebuff,d->name); + pcap_freealldevs(alldevs); + return namebuff; + } + d=d->next; i++; + } + + pcap_freealldevs(alldevs); + + return NULL; +} + +char* pcap_io_get_dev_desc(int num,int md) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + int i=0; + + if(pcap_findalldevs(&alldevs, errbuf) == -1) + { + return NULL; + } + + d=alldevs; + while(d!=NULL) { + if(num==i) + { + if (!md) + strcpy(namebuff,"pcap switch:"); + else + strcpy(namebuff,"pcap bridge:"); + strcat(namebuff,d->description); + pcap_freealldevs(alldevs); + return namebuff; + } + d=d->next; i++; + } + + pcap_freealldevs(alldevs); + + return NULL; +} + + +PCAPAdapter::PCAPAdapter() +{ + //if (config.ethEnable == 0) return; //whut? nada! + if (config.Eth[5]=='s') + pcap_mode=switched; + else + pcap_mode=bridged; + + if (pcap_io_init(config.Eth+12) == -1) { + SysMessage("Can't open Device '%s'\n", config.Eth); + } +} +bool PCAPAdapter::blocks() +{ + return false; +} +//gets a packet.rv :true success +bool PCAPAdapter::recv(NetPacket* pkt) +{ + int size=pcap_io_recv(pkt->buffer,sizeof(pkt->buffer)); + if(size<=0) + { + return false; + } + else + { + pkt->size=size; + return true; + } +} +//sends the packet .rv :true success +bool PCAPAdapter::send(NetPacket* pkt) +{ + if(pcap_io_send(pkt->buffer,pkt->size)) + { + return false; + } + else + { + return true; + } +} +PCAPAdapter::~PCAPAdapter() +{ + pcap_io_close(); +} diff --git a/plugins/dev9/dev9null/ReadMe.txt b/plugins/dev9/dev9null/ReadMe.txt new file mode 100644 index 0000000000..b9ca434c5a --- /dev/null +++ b/plugins/dev9/dev9null/ReadMe.txt @@ -0,0 +1,32 @@ +DEV9null v0.3 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "libDEV9null.so" (linux) or "DEV9null.dll" (win32) + at the Plugin directory of the Emulator to use it. + +Changes: +------- + v0.3: +*added vsnet2005beta1 project files. 64bit dll should work now (not tested!) + + v0.2: + *updated the specifications to 0.4.7 + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + linuzappz + shadow + + + diff --git a/plugins/dev9/dev9null/build.sh b/plugins/dev9/dev9null/build.sh new file mode 100644 index 0000000000..496e73341b --- /dev/null +++ b/plugins/dev9/dev9null/build.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo Building dev9null... +curdir=`pwd` + +cd ${curdir}/src +make $@ + +cp libDEV9null.so ${PCSX2PLUGINS} diff --git a/plugins/dev9/dev9null/src/DEV9.h b/plugins/dev9/dev9null/src/DEV9.h new file mode 100644 index 0000000000..73ce78e706 --- /dev/null +++ b/plugins/dev9/dev9null/src/DEV9.h @@ -0,0 +1,17 @@ +#ifndef __DEV9_H__ +#define __DEV9_H__ + +#include + +#define DEV9defs + +#include "PS2Edefs.h" + + +FILE *dev9Log; +void __Log(char *fmt, ...); +void (*DEV9irq)(); +void SysMessage(char *fmt, ...); + + +#endif diff --git a/plugins/dev9/dev9null/src/Dev9null.sln b/plugins/dev9/dev9null/src/Dev9null.sln new file mode 100644 index 0000000000..61bcaa6745 --- /dev/null +++ b/plugins/dev9/dev9null/src/Dev9null.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dev9null", "Dev9null.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/dev9/dev9null/src/Dev9null.vcproj b/plugins/dev9/dev9null/src/Dev9null.vcproj new file mode 100644 index 0000000000..88c3755aa7 --- /dev/null +++ b/plugins/dev9/dev9null/src/Dev9null.vcproj @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/dev9null/src/Dev9null_2005_x64.vcproj b/plugins/dev9/dev9null/src/Dev9null_2005_x64.vcproj new file mode 100644 index 0000000000..8bad17356d --- /dev/null +++ b/plugins/dev9/dev9null/src/Dev9null_2005_x64.vcproj @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.sln b/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.sln new file mode 100644 index 0000000000..4b73f6edfa --- /dev/null +++ b/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dev9null", "Dev9null_vsnet2005beta1.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + amd64|Win32 = amd64|Win32 + amd64|Win64 (AMD64) = amd64|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win32.ActiveCfg = amd64|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win32.Build.0 = amd64|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win64 (AMD64).ActiveCfg = amd64|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win64 (AMD64).Build.0 = amd64|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win32.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win32.Build.0 = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.vcproj b/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.vcproj new file mode 100644 index 0000000000..a3c91f5ec4 --- /dev/null +++ b/plugins/dev9/dev9null/src/Dev9null_vsnet2005beta1.vcproj @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dev9/dev9null/src/Makefile b/plugins/dev9/dev9null/src/Makefile new file mode 100644 index 0000000000..1b129e469b --- /dev/null +++ b/plugins/dev9/dev9null/src/Makefile @@ -0,0 +1,23 @@ + +CC = gcc + +PLUGIN = libDEV9null.so +CFLAGS+= -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ +OBJS = dev9null.o +DEPS:= $(OBJS:.o=.d) + +all: plugin +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +clean: + rm -f ${OBJS} ${DEPS} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/dev9/dev9null/src/Makefile.mingw b/plugins/dev9/dev9null/src/Makefile.mingw new file mode 100644 index 0000000000..20bc9ef896 --- /dev/null +++ b/plugins/dev9/dev9null/src/Makefile.mingw @@ -0,0 +1,51 @@ +# +# Makefile for MINGW32 +# + + +all: dev9null + +PLUGIN = DEV9null.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwinmm -lgdi32 -lcomdlg32 #-lintl -lwsock32 +RESOBJ = dev9nullrc.o + +OBJS = dev9null.o + + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} + +dev9null: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean dev9null + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: DEV9null.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + + \ No newline at end of file diff --git a/plugins/dev9/dev9null/src/PS2Edefs.h b/plugins/dev9/dev9null/src/PS2Edefs.h new file mode 100644 index 0000000000..b2f76c96de --- /dev/null +++ b/plugins/dev9/dev9null/src/PS2Edefs.h @@ -0,0 +1,848 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/dev9/dev9null/src/PS2Etypes.h b/plugins/dev9/dev9null/src/PS2Etypes.h new file mode 100644 index 0000000000..1ad73e273d --- /dev/null +++ b/plugins/dev9/dev9null/src/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/dev9/dev9null/src/dev9null.c b/plugins/dev9/dev9null/src/dev9null.c new file mode 100644 index 0000000000..cf4817a163 --- /dev/null +++ b/plugins/dev9/dev9null/src/dev9null.c @@ -0,0 +1,152 @@ + + +#ifdef _WIN32 + +#include +#include +#include + +#endif + +#include +#include +#include +#include +#include "PS2Etypes.h" +#include "DEV9.h" + +#ifdef _WIN32 + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "DEV9null Msg", 0); +} + +#else + +#include + +void SysMessage(char *fmt, ...) { +} + +#endif + +const unsigned char version = PS2E_DEV9_VERSION; +const unsigned char revision = 0; +const unsigned char build = 3; // increase that with each version + +static char *libraryName = "DEV9null Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_DEV9; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + +// if (!Log) return; + + va_start(list, fmt); + vfprintf(dev9Log, fmt, list); + va_end(list); +} + +s32 CALLBACK DEV9init() { + + return 0; +} + +void CALLBACK DEV9shutdown() { +} + +s32 CALLBACK DEV9open(void *pDsp) { + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + return 0; +} + +void CALLBACK DEV9close() { + +} + + +u8 CALLBACK DEV9read8(u32 addr) { + return 0; +} + +u16 CALLBACK DEV9read16(u32 addr) { + return 0; +} + +u32 CALLBACK DEV9read32(u32 addr) { + return 0; +} + +void CALLBACK DEV9write8(u32 addr, u8 value) { +} + +void CALLBACK DEV9write16(u32 addr, u16 value) { + +} + +void CALLBACK DEV9write32(u32 addr, u32 value) { + +} + +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size) { + +} + +void CALLBACK DEV9writeDMA8Mem(u32* pMem, int size) { + +} + + +void CALLBACK DEV9irqCallback(DEV9callback callback) { + +} + +DEV9handler CALLBACK DEV9irqHandler(void) { + return NULL; +} + + +// extended funcs + +s32 CALLBACK DEV9test() { + return 0; +} + +void CALLBACK DEV9configure() +{ + SysMessage("Nothing to Configure"); +} +void CALLBACK DEV9about(){} + +#ifdef _WIN32 + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +#endif diff --git a/plugins/dev9/dev9null/src/dev9null.def b/plugins/dev9/dev9null/src/dev9null.def new file mode 100644 index 0000000000..e3f3b7e976 --- /dev/null +++ b/plugins/dev9/dev9null/src/dev9null.def @@ -0,0 +1,27 @@ +; DEV9null.def : Declares the module parameters for the DLL. + +LIBRARY "DEV9null" +DESCRIPTION 'DEV9null Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + DEV9init @5 + DEV9shutdown @6 + DEV9open @7 + DEV9close @8 + DEV9read8 @9 + DEV9read16 @10 + DEV9read32 @11 + DEV9write8 @12 + DEV9write16 @13 + DEV9write32 @14 + DEV9readDMA8Mem @15 + DEV9writeDMA8Mem @16 + DEV9configure @17 + DEV9test @18 + DEV9about @19 + DEV9irqCallback @20 + DEV9irqHandler @21 diff --git a/plugins/fw/FWlinuz/FW.c b/plugins/fw/FWlinuz/FW.c new file mode 100644 index 0000000000..3ec311cbe6 --- /dev/null +++ b/plugins/fw/FWlinuz/FW.c @@ -0,0 +1,285 @@ +/* FW + * Copyright (C) 2004 PCSX2 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 +#include +#include + +#include "FW.h" + +const unsigned char version = PS2E_FW_VERSION; +const unsigned char revision = 0; +const unsigned char build = 1; // increase that with each version + +static char *libraryName = "FWlinuz Driver"; + +s8 *fwregs; +u8 phyregs[8]; +u8 portregs[3][8]; +u8 vidregs[8]; +u8 vderegs[8]; + +#define fwRs32(mem) (*(s32*)&fwregs[(mem) & 0xffff]) +#define fwRu32(mem) (*(u32*)&fwregs[(mem) & 0xffff]) + + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_FW; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log) return; + + va_start(list, fmt); + vfprintf(fwLog, fmt, list); + va_end(list); +} + +s32 CALLBACK FWinit() { + LoadConfig(); +#ifdef FW_LOG + fwLog = fopen("logs/fwLog.txt", "w"); + setvbuf(fwLog, NULL, _IONBF, 0); + FW_LOG("FWlinuz plugin version %d,%d\n",revision,build); + FW_LOG("FW init\n"); +#endif + + fwregs = (s8*)malloc(0x10000); + if (fwregs == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + memset(phyregs, 0, sizeof(phyregs)); + memset(portregs, 0, sizeof(portregs)); + memset(vidregs, 0, sizeof(vidregs)); + memset(vderegs, 0, sizeof(vderegs)); + fwRu32(0x8400) = 0xffc00001; + phyregs[0] = 0xc1; + portregs[0][0] = 0xe5; + vidregs[0] = 0x01; + + return 0; +} + +void CALLBACK FWshutdown() { + free(fwregs); + +#ifdef FW_LOG + fclose(fwLog); +#endif +} + +s32 CALLBACK FWopen(void *pDsp) { +#ifdef FW_LOG + FW_LOG("FW open\n"); +#endif + + return 0; +} + +void CALLBACK FWclose() { +} + +u32 CALLBACK FWread32(u32 addr) { + u32 ret=0; + + switch (addr) { + case 0x1f808410: + ret = 0x8; + break; + + default: + ret = fwRu32(addr); + break; + } +#ifdef FW_LOG + FW_LOG("FW read mem 0x%x: 0x%x\n", addr, ret); +#endif + + return ret; +} + +void _irq0(int num) { + fwRu32(0x8420)|= 1<> 24) & 0xf; + int port; + u8 value=0; + + PHYACC = (PHYACC & ~0xf00) | (reg << 8); + PHYACC&= ~0x80000000; + + if (reg > 7) { + reg-= 8; + switch (phyregs[7] & 0x7) { + case 0: + port = phyregs[7] >> 16; + if (port < 3) { + value = portregs[port][reg]; + } else { + value = 0; + } + printf("port[%d] read 0x%x: 0x%2.2x\n", port, reg, value); +#ifdef FW_LOG + FW_LOG("port[%d] read 0x%x: 0x%2.2x\n", port, reg, value); +#endif + break; + case 1: + value = vidregs[reg]; + printf("vid read 0x%x: 0x%2.2x\n", reg, value); +#ifdef FW_LOG + FW_LOG("vid read 0x%x: 0x%2.2x\n", reg, value); +#endif + break; + case 3: + value = 0x02; + printf("vid read 0x%x: 0x%2.2x\n", reg, value); +#ifdef FW_LOG + FW_LOG("vid read 0x%x: 0x%2.2x\n", reg, value); +#endif + break; + case 7: + printf("vde read 0x%x: 0x%2.2x\n", reg, vderegs[reg]); +#ifdef FW_LOG + FW_LOG("vde read 0x%x: 0x%2.2x\n", reg, vderegs[reg]); +#endif + value = vderegs[reg]; + break; + } + } else { + printf("phy read 0x%x: 0x%2.2x\n", reg, phyregs[reg]); +#ifdef FW_LOG + FW_LOG("phy read 0x%x: 0x%2.2x\n", reg, phyregs[reg]); +#endif + value = phyregs[reg]; + } + + PHYACC = (PHYACC & ~0xff) | value; + _irq0(30); +} + +void phy_write() { + int reg = (PHYACC >> 24) & 0xf; + int port; + u8 value = (PHYACC >> 16) & 0xff; + + if (reg > 7) { + reg-= 8; + switch (phyregs[7] & 0x7) { + case 0: + port = phyregs[7] >> 4; + printf("port[%d] write 0x%x: 0x%2.2x\n", port, reg, value); +#ifdef FW_LOG + FW_LOG("port[%d] write 0x%x: 0x%2.2x\n", port, reg, value); +#endif + if (port < 3) { + switch (reg) { + case 0x0: portregs[port][reg] = (portregs[port][reg] & 0x7f) | (value & ~0x7f); break; + case 0x1: portregs[port][reg] = (portregs[port][reg] & 0x07) | (value & ~0x07); break; + } + } + break; + + case 1: + printf("vid write 0x%x: 0x%2.2x\n", reg, value); +#ifdef FW_LOG + FW_LOG("vid write 0x%x: 0x%2.2x\n", reg, value); +#endif + break; + + case 7: + printf("vde write 0x%x: 0x%2.2x\n", reg, value); +#ifdef FW_LOG + FW_LOG("vde write 0x%x: 0x%2.2x\n", reg, value); +#endif + switch (reg) { + case 0x0: vderegs[reg] = value; break; + } + break; + } + } else { + printf("phy write 0x%x: 0x%2.2x\n", reg, value); +#ifdef FW_LOG + FW_LOG("phy write 0x%x: 0x%2.2x\n", reg, value); +#endif + switch (reg) { + case 0x0: break; + case 0x2: break; + case 0x3: break; + case 0x4: phyregs[reg] = (phyregs[reg] & 0x1c) | (value & ~0x1c); break; + case 0x6: break; + default: phyregs[reg] = value; + } + } + + PHYACC&= ~0x40000000; +} + +void CALLBACK FWwrite32(u32 addr, u32 value) { + switch (addr) { + case 0x1f808400: + fwRu32(addr) = (fwRu32(addr) & 0x003f0001) | (value & ~0x003f0001); + break; + + case 0x1f808414: + fwRu32(addr) = (fwRu32(addr) & 0xfff) | (value & ~0xfff); + if (value & 0x80000000) phy_read(); + if (value & 0x40000000) phy_write(); + break; + + case 0x1f808420: + case 0x1f808428: + case 0x1f808430: + fwRu32(addr) = (fwRu32(addr) & ~value); + break; + + default: + fwRu32(addr) = value; + break; + } +#ifdef FW_LOG + FW_LOG("FW write mem 0x%x: 0x%x\n", addr, value); +#endif +} + +void CALLBACK FWirqCallback(void (*callback)()) { + FWirq = callback; +} + +s32 CALLBACK FWfreeze(int mode, freezeData *data) { + return 0; +} + +s32 CALLBACK FWtest() { + return 0; +} + diff --git a/plugins/fw/FWlinuz/FW.h b/plugins/fw/FWlinuz/FW.h new file mode 100644 index 0000000000..d0719985ed --- /dev/null +++ b/plugins/fw/FWlinuz/FW.h @@ -0,0 +1,62 @@ +/* FireWire + * Copyright (C) 2004 PCSX2 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 + */ + + +#ifndef __FIREWIRE_H__ +#define __FIREWIRE_H__ + +#include + +#define FIREWIREdefs +#include "PS2Edefs.h" + +#ifdef __WIN32__ + +#include +#include + +#else + +#include + +#define __inline inline + +#endif + +#define FW_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; + +#define PHYACC fwRu32(0x8414) + + +void (*FWirq)(); + +void SaveConfig(); +void LoadConfig(); + +FILE *fwLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/fw/FWlinuz/License.txt b/plugins/fw/FWlinuz/License.txt new file mode 100644 index 0000000000..7d1f8605f8 --- /dev/null +++ b/plugins/fw/FWlinuz/License.txt @@ -0,0 +1,342 @@ + 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/plugins/fw/FWlinuz/Linux/Config.c b/plugins/fw/FWlinuz/Linux/Config.c new file mode 100644 index 0000000000..7f3b9e5a64 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/Config.c @@ -0,0 +1,51 @@ +/* FireWire + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include +#include +#include + +#include "FireWire.h" + +void LoadConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/FireWire.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + return; + } + fclose(f); +} + +void SaveConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/FireWire.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fclose(f); +} + diff --git a/plugins/fw/FWlinuz/Linux/Config.h b/plugins/fw/FWlinuz/Linux/Config.h new file mode 100644 index 0000000000..9eb36474fd --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/Config.h @@ -0,0 +1,20 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/fw/FWlinuz/Linux/Linux.c b/plugins/fw/FWlinuz/Linux/Linux.c new file mode 100644 index 0000000000..b12ef28c5c --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/Linux.c @@ -0,0 +1,75 @@ +/* FireWire + * Copyright (C) 2002-2004 FireWire 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 +#include +#include +#include +#include +#include +#include + +#include "FireWire.h" + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgFireWire"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgFireWire"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgFireWire", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgFireWire file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void FireWireconfigure() { + ExecCfg("configure"); +} + +void FireWireabout() { + ExecCfg("about"); +} + diff --git a/plugins/fw/FWlinuz/Linux/Makefile b/plugins/fw/FWlinuz/Linux/Makefile new file mode 100644 index 0000000000..d40d8c68f0 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/Makefile @@ -0,0 +1,34 @@ + +PLUGIN = libFireWire.so +CFG = cfgFireWire +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../FireWire.o +OBJS+= Linux.o Config.o +CFGOBJS = conf.o interface.o support.o Config.o +DEPS:= $(OBJS:.o=.d) +CFGDEPS:= $(CFGOBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell gtk-config --cflags) -D__LINUX__ +CFGLIBS = $(shell gtk-config --libs) + +CC = gcc + +all: plugin cfg + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/fw/FWlinuz/Linux/callbacks.c b/plugins/fw/FWlinuz/Linux/callbacks.c new file mode 100644 index 0000000000..fa070a7842 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/fw/FWlinuz/Linux/callbacks.h b/plugins/fw/FWlinuz/Linux/callbacks.h new file mode 100644 index 0000000000..22cf74a988 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/fw/FWlinuz/Linux/conf.c b/plugins/fw/FWlinuz/Linux/conf.c new file mode 100644 index 0000000000..6f42a8d899 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/conf.c @@ -0,0 +1,136 @@ +/* FireWire + * Copyright (C) 2002-2004 FireWire 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 +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" +#include "FireWire.h" +#include "Config.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "FireWire Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gchar *str; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CFGconfigure() { + Conf = create_Config(); + + LoadConfig(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/fw/FWlinuz/Linux/firewire.glade b/plugins/fw/FWlinuz/Linux/firewire.glade new file mode 100644 index 0000000000..6644e52247 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/firewire.glade @@ -0,0 +1,300 @@ + + + + + FireWire + dev9linuz + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + DEV9config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox1 + 5 + True + 5 + + + GtkLabel + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Eth + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + + GtkFrame + frame3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox2 + 5 + True + 5 + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Hdd + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + True + True + 0 + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + DEV9about + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/fw/FWlinuz/Linux/interface.c b/plugins/fw/FWlinuz/Linux/interface.c new file mode 100644 index 0000000000..a73c0861ed --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/interface.c @@ -0,0 +1,219 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/fw/FWlinuz/Linux/interface.h b/plugins/fw/FWlinuz/Linux/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/fw/FWlinuz/Linux/support.c b/plugins/fw/FWlinuz/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/fw/FWlinuz/Linux/support.h b/plugins/fw/FWlinuz/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/fw/FWlinuz/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/fw/FWlinuz/PS2Edefs.h b/plugins/fw/FWlinuz/PS2Edefs.h new file mode 100644 index 0000000000..b20cbbca8b --- /dev/null +++ b/plugins/fw/FWlinuz/PS2Edefs.h @@ -0,0 +1,724 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.0 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetCSR(u64 *csr); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetCSR)(u64 * csr); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetCSR GSsetCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/fw/FWlinuz/PS2Etypes.h b/plugins/fw/FWlinuz/PS2Etypes.h new file mode 100644 index 0000000000..3a63c58b85 --- /dev/null +++ b/plugins/fw/FWlinuz/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/fw/FWlinuz/ReadMe.txt b/plugins/fw/FWlinuz/ReadMe.txt new file mode 100644 index 0000000000..aede3fdef0 --- /dev/null +++ b/plugins/fw/FWlinuz/ReadMe.txt @@ -0,0 +1,25 @@ +FWlinuz v0.1 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "FWlinuz.so" (linux) or "FWlinuz.dll" (win32) + at the Plugin directory of the Emulator to use it. + +Changes: +------- + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + shadow + linuzappz + + + diff --git a/plugins/fw/FWlinuz/Win32/Config.c b/plugins/fw/FWlinuz/Win32/Config.c new file mode 100644 index 0000000000..1109f31cce --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/Config.c @@ -0,0 +1,45 @@ +#include + +#include "FW.h" + +extern HINSTANCE hInst; + +void SaveConfig() { + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\fwlinuz.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); +} + +void LoadConfig() { + FILE *fp; + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\fwlinuz.ini"); + fp=fopen("inis\\fwlinuz.ini","rt");//check if firewirenull.ini really exists + if (!fp) { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); +} + diff --git a/plugins/fw/FWlinuz/Win32/FWlinuz.def b/plugins/fw/FWlinuz/Win32/FWlinuz.def new file mode 100644 index 0000000000..dc1fd03968 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/FWlinuz.def @@ -0,0 +1,19 @@ +; FireWire.def : Declares the module parameters for the DLL. + +LIBRARY "FireWirePlugin" + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + FWinit @5 + FWshutdown @6 + FWopen @7 + FWclose @8 + FWread32 @11 + FWwrite32 @14 + FWirqCallback @15 + FWconfigure @17 + FWtest @18 + FWabout @19 diff --git a/plugins/fw/FWlinuz/Win32/FWlinuz.rc b/plugins/fw/FWlinuz/Win32/FWlinuz.rc new file mode 100644 index 0000000000..a084b7962b --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/FWlinuz.rc @@ -0,0 +1,123 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifdef __MINGW32__ +#include "afxresmw.h" +#else +#include "afxres.h" +#endif + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Firewireconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,48,100,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,100,50,14 + CONTROL "Enable Logging (for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,187,13 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "FireWire About" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "FireWire Driver",IDC_NAME,70,10,48,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Author: Shadow and linuzappz",IDC_STATIC,29,19,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/fw/FWlinuz/Win32/FWlinuz.sln b/plugins/fw/FWlinuz/Win32/FWlinuz.sln new file mode 100644 index 0000000000..95dd0df9c4 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/FWlinuz.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FireWireNull", "FireWireNull.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/fw/FWlinuz/Win32/FireWireNull.ncb b/plugins/fw/FWlinuz/Win32/FireWireNull.ncb new file mode 100644 index 0000000000000000000000000000000000000000..b2d6aa5d8f1e90aac5d7572ded439a758ae5e45d GIT binary patch literal 60416 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 DAK((* literal 0 HcmV?d00001 diff --git a/plugins/fw/FWlinuz/Win32/FireWireNull.sln b/plugins/fw/FWlinuz/Win32/FireWireNull.sln new file mode 100644 index 0000000000..c9d4c3aba2 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/FireWireNull.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FWlinuz", "FireWireNull.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/fw/FWlinuz/Win32/FireWireNull.suo b/plugins/fw/FWlinuz/Win32/FireWireNull.suo new file mode 100644 index 0000000000000000000000000000000000000000..f7f71bf1a745dfd650775ff75d17e4bc6df4846d GIT binary patch literal 8192 zcmeHLOKenC82+cF(()+fRS^|O%1flRv;|u55j)e?#!icEX<2l^bmq1U+?lB}w-f{t zcP1tpjWIECVSMb2ub8+pXj~Xs7>rRC#u!)_m$>kO3XI=(?zuD5={)X~VkGH*^WXEh z|2_YI&iP;Gd~;#-r8hs?cv*7bQK^(0sT#Q>tKWk$i7vc6_fkBDmvBWD~5<{7gQ`lkmP%l+! zo3AYK+mW{~9jbrfOAqNjr$PY^f@55cNiVohpw=ZP?GG;B^-|$k3))pc?uN_X1nx`0 zummM3$E8mqC@ndJw*i@){$z;(w}Ag@(9mYw@~6+FeGz(PM1~|Fe!UV?io1nf=u|5+ zqvf%w=e~D>KW&zF>6U-Czjkbyd*b*3_HjPWH`+h_K(-IydOP3OWYyQBUJtwzxB=J% zB;DO8?*ZNm+yuN2=mp*nV&V8qGDE)PiQzyW2dnj&k*V=`FcJ0+Mq-ofTH0g8j6~36eJ*(Bc9qq`|MvrZ zc#p}Hm@+Ms@I^7${TMvr4Bp)`ihlM@%QI+?s(LH*eyl8B`G|Yr=@!YV`{0rj95Y{SgS zm+{0cf6_Yf=VtZSk&W@=S)i@Qc2u9lS_UPGJ?h3>Otqt9h;`I0M*Spk0`v4D1~U3i zgW5!E2z}EMR`d5Fg7hOR7)E~!JbtsZLhDB`!akH7$3mGz8B*5p;(sm!_0_~ICzJ$^ zBu-o8|00nsXRgP{)j#f33~N7xy_r_4THFgj|CIeR3b@rj(thf}3s9KENyXL{4`Qor1j`nVWX9BBE?ax?> zlNlS(D+_i-UqDK}Gt%tW>u=BA-Tc>rH*>v(0{Y%uxS77(v2JC%N>um=D;^u9uJU6K z(%n>Qdqw)Hk7HLGg6}S(zHhkTyY8|NU zf!k^XT{9><(A$acd(m!%`nStjIit3nfrl!`vLD80;%P!C4j~xWhom#8yH69CHZpS&Q_CNRui!qNz`s7w^MJ&e^R{62$Oq8l z2Dq=a{X;*VyRsti{MOe#t9WDmRTbTSS-17u4;mVJKKc3b+3n-eHf1lh=QofSS&GYcT+4Ij;+(LW`_1DdV{|*ecU&kL7yqBA8z1e=j{+`Lx zc|%|+FA#(MbA@c*Of9dL-+18%sFvT;wLf%ixm;DXO8FBd|EiR~(o}z^YyYHc*V47? zy0%x6SN z8^J#ry*PY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/fw/FWlinuz/Win32/Makefile b/plugins/fw/FWlinuz/Win32/Makefile new file mode 100644 index 0000000000..b6e9f8e0f3 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/Makefile @@ -0,0 +1,52 @@ +# +# Makefile for MINGW32 +# + + +all: fwlinuz + +PLUGIN = FWlinuz.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = FWlinuz.o + +OBJS = ../FW.o +OBJS+= Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +fwlinuz: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} +# ${STRIP} ${PLUGIN} + +.PHONY: clean fwlinuz + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: FWlinuz.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/fw/FWlinuz/Win32/Win32.c b/plugins/fw/FWlinuz/Win32/Win32.c new file mode 100644 index 0000000000..e734c45640 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/Win32.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "resource.h" +#include "FW.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "FW Plugin Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK FWconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK FWabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/fw/FWlinuz/Win32/afxresmw.h b/plugins/fw/FWlinuz/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/fw/FWlinuz/Win32/plugin.def b/plugins/fw/FWlinuz/Win32/plugin.def new file mode 100644 index 0000000000..1ac66e0c58 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/plugin.def @@ -0,0 +1,15 @@ +EXPORTS + FWabout = FWabout@0 @3 + FWclose = FWclose@0 @4 + FWconfigure = FWconfigure@0 @5 + FWfreeze = FWfreeze@8 @6 + FWinit = FWinit@0 @7 + FWirqCallback = FWirqCallback@4 @9 + FWopen = FWopen@4 @10 + FWread32 = FWread32@4 @11 + FWshutdown = FWshutdown@0 @12 + FWtest = FWtest@0 @13 + FWwrite32 = FWwrite32@8 @14 + PS2EgetLibName = PS2EgetLibName@0 @16 + PS2EgetLibType = PS2EgetLibType@0 @17 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @18 diff --git a/plugins/fw/FWlinuz/Win32/resource.h b/plugins/fw/FWlinuz/Win32/resource.h new file mode 100644 index 0000000000..f8ab2765f1 --- /dev/null +++ b/plugins/fw/FWlinuz/Win32/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by FireWireNull.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/fw/FWnull/FW.c b/plugins/fw/FWnull/FW.c new file mode 100644 index 0000000000..37aeda8107 --- /dev/null +++ b/plugins/fw/FWnull/FW.c @@ -0,0 +1,147 @@ +/* FWnull + * Copyright (C) 2004-2005 PCSX2 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 +#include +#include + +#include "FW.h" + +const unsigned char version = PS2E_FW_VERSION; +const unsigned char revision = 0; +const unsigned char build = 4; // increase that with each version + +static char *libraryName = "FWnull Driver"; + +s8 *fwregs; + +#define fwRs32(mem) (*(s32*)&fwregs[(mem) & 0xffff]) +#define fwRu32(mem) (*(u32*)&fwregs[(mem) & 0xffff]) + + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_FW; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || fwLog == NULL) return; + + va_start(list, fmt); + vfprintf(fwLog, fmt, list); + va_end(list); +} + +s32 CALLBACK FWinit() { + LoadConfig(); +#ifdef FW_LOG + fwLog = fopen("logs/fwLog.txt", "w"); + if (fwLog) setvbuf(fwLog, NULL, _IONBF, 0); + FW_LOG("FWnull plugin version %d,%d\n",revision,build); + FW_LOG("FW init\n"); +#endif + + fwregs = (s8*)malloc(0x10000); + if (fwregs == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + + return 0; +} + +void CALLBACK FWshutdown() { + free(fwregs); + +#ifdef FW_LOG + if (fwLog) fclose(fwLog); +#endif +} + +s32 CALLBACK FWopen(void *pDsp) { +#ifdef FW_LOG + FW_LOG("FW open\n"); +#endif + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + + return 0; +} + +void CALLBACK FWclose() { +} + + + + +u32 CALLBACK FWread32(u32 addr) { + u32 ret=0; + + switch (addr) { + case 0x1f808410: + ret = 0x8; + break; + + default: + ret = fwRu32(addr); + } +#ifdef FW_LOG + FW_LOG("FW read mem 0x%x: 0x%x\n", addr, ret); +#endif + + return ret; +} + + + +void CALLBACK FWwrite32(u32 addr, u32 value) { + switch (addr) { + default: + fwRu32(addr) = value; + break; + } +#ifdef FW_LOG + FW_LOG("FW write mem 0x%x: 0x%x\n", addr, value); +#endif +} + +void CALLBACK FWirqCallback(void (*callback)()) { + FWirq = callback; +} + + +s32 CALLBACK FWfreeze(int mode, freezeData *data) { + return 0; +} + + +s32 CALLBACK FWtest() { + return 0; +} + diff --git a/plugins/fw/FWnull/FW.h b/plugins/fw/FWnull/FW.h new file mode 100644 index 0000000000..e124d356ac --- /dev/null +++ b/plugins/fw/FWnull/FW.h @@ -0,0 +1,59 @@ +/* FWnull + * Copyright (C) 2004-2005 PCSX2 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 + */ + + +#ifndef __FW_H__ +#define __FW_H__ + +#include + +#define FWdefs +#include "PS2Edefs.h" + +#ifdef _WIN32 + +#include +#include + +#else + +#include +#include + +#define __inline inline + +#endif + +#define FW_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; +void (*FWirq)(); + +void SaveConfig(); +void LoadConfig(); + +FILE *fwLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/fw/FWnull/License.txt b/plugins/fw/FWnull/License.txt new file mode 100644 index 0000000000..7d1f8605f8 --- /dev/null +++ b/plugins/fw/FWnull/License.txt @@ -0,0 +1,342 @@ + 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/plugins/fw/FWnull/Linux/Config.c b/plugins/fw/FWnull/Linux/Config.c new file mode 100644 index 0000000000..3eda6eb98f --- /dev/null +++ b/plugins/fw/FWnull/Linux/Config.c @@ -0,0 +1,51 @@ +/* FireWire + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include +#include +#include + +#include "FW.h" + +void LoadConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + return; + } + fclose(f); +} + +void SaveConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fclose(f); +} + diff --git a/plugins/fw/FWnull/Linux/Config.h b/plugins/fw/FWnull/Linux/Config.h new file mode 100644 index 0000000000..9eb36474fd --- /dev/null +++ b/plugins/fw/FWnull/Linux/Config.h @@ -0,0 +1,20 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/fw/FWnull/Linux/Linux.c b/plugins/fw/FWnull/Linux/Linux.c new file mode 100644 index 0000000000..9a70105daa --- /dev/null +++ b/plugins/fw/FWnull/Linux/Linux.c @@ -0,0 +1,75 @@ +/* FireWire + * Copyright (C) 2002-2004 FireWire 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 +#include +#include +#include +#include +#include +#include + +#include "FW.h" + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgFWnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgFWnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgFWnull", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgFWnull file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void FWconfigure() { + ExecCfg("configure"); +} + +void FWabout() { + ExecCfg("about"); +} + diff --git a/plugins/fw/FWnull/Linux/Makefile b/plugins/fw/FWnull/Linux/Makefile new file mode 100644 index 0000000000..28665dbbe7 --- /dev/null +++ b/plugins/fw/FWnull/Linux/Makefile @@ -0,0 +1,35 @@ + +PLUGIN = libFWnull.so +CFG = cfgFWnull +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../FW.o +OBJS+= Linux.o Config.o +CFGOBJS = conf.o interface.o support.o Config.o +DEPS:= $(OBJS:.o=.d) +CFGDEPS:= $(CFGOBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) + +CC = gcc + +all: plugin cfg +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/fw/FWnull/Linux/callbacks.c b/plugins/fw/FWnull/Linux/callbacks.c new file mode 100644 index 0000000000..fa070a7842 --- /dev/null +++ b/plugins/fw/FWnull/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/fw/FWnull/Linux/callbacks.h b/plugins/fw/FWnull/Linux/callbacks.h new file mode 100644 index 0000000000..22cf74a988 --- /dev/null +++ b/plugins/fw/FWnull/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/fw/FWnull/Linux/conf.c b/plugins/fw/FWnull/Linux/conf.c new file mode 100644 index 0000000000..2d3aa71204 --- /dev/null +++ b/plugins/fw/FWnull/Linux/conf.c @@ -0,0 +1,136 @@ +/* FireWire + * Copyright (C) 2002-2004 FireWire 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 +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" +#include "FW.h" +#include "Config.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "FireWire Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gchar *str; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CFGconfigure() { + Conf = create_Config(); + + LoadConfig(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/fw/FWnull/Linux/firewire.glade b/plugins/fw/FWnull/Linux/firewire.glade new file mode 100644 index 0000000000..6644e52247 --- /dev/null +++ b/plugins/fw/FWnull/Linux/firewire.glade @@ -0,0 +1,300 @@ + + + + + FireWire + dev9linuz + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + DEV9config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox1 + 5 + True + 5 + + + GtkLabel + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Eth + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + + GtkFrame + frame3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox2 + 5 + True + 5 + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Hdd + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + True + True + 0 + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + DEV9about + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/fw/FWnull/Linux/interface.c b/plugins/fw/FWnull/Linux/interface.c new file mode 100644 index 0000000000..a73c0861ed --- /dev/null +++ b/plugins/fw/FWnull/Linux/interface.c @@ -0,0 +1,219 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/fw/FWnull/Linux/interface.h b/plugins/fw/FWnull/Linux/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/fw/FWnull/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/fw/FWnull/Linux/support.c b/plugins/fw/FWnull/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/fw/FWnull/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/fw/FWnull/Linux/support.h b/plugins/fw/FWnull/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/fw/FWnull/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/fw/FWnull/PS2Edefs.h b/plugins/fw/FWnull/PS2Edefs.h new file mode 100644 index 0000000000..b2f76c96de --- /dev/null +++ b/plugins/fw/FWnull/PS2Edefs.h @@ -0,0 +1,848 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/fw/FWnull/PS2Etypes.h b/plugins/fw/FWnull/PS2Etypes.h new file mode 100644 index 0000000000..1ad73e273d --- /dev/null +++ b/plugins/fw/FWnull/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/fw/FWnull/ReadMe.txt b/plugins/fw/FWnull/ReadMe.txt new file mode 100644 index 0000000000..f2ae2f5baf --- /dev/null +++ b/plugins/fw/FWnull/ReadMe.txt @@ -0,0 +1,34 @@ +FireWire v0.3 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "FireWirePlugin.so" (linux) or "FireWirePlugin.dll" (win32) + at the Plugin directory of the Emulator to use it. + +Changes: +------- + v0.4: +*Added vsnet2005 beta1 support. 64bit dll should work okay (not tested yet!) + + v0.3: + *up to specs 0.5.5 + *added logging option and ini saving + + v0.2: + *new specs + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + shadow + linuzappz + + + diff --git a/plugins/fw/FWnull/Win32/Config.c b/plugins/fw/FWnull/Win32/Config.c new file mode 100644 index 0000000000..d1b14598aa --- /dev/null +++ b/plugins/fw/FWnull/Win32/Config.c @@ -0,0 +1,51 @@ +#include + +#include "FW.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\fwnull.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\fwnull.ini"); + fp=fopen("inis\\fwnull.ini","rt");//check if firewirenull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/fw/FWnull/Win32/FireWireNull.def b/plugins/fw/FWnull/Win32/FireWireNull.def new file mode 100644 index 0000000000..dc1fd03968 --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull.def @@ -0,0 +1,19 @@ +; FireWire.def : Declares the module parameters for the DLL. + +LIBRARY "FireWirePlugin" + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + FWinit @5 + FWshutdown @6 + FWopen @7 + FWclose @8 + FWread32 @11 + FWwrite32 @14 + FWirqCallback @15 + FWconfigure @17 + FWtest @18 + FWabout @19 diff --git a/plugins/fw/FWnull/Win32/FireWireNull.rc b/plugins/fw/FWnull/Win32/FireWireNull.rc new file mode 100644 index 0000000000..a084b7962b --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull.rc @@ -0,0 +1,123 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifdef __MINGW32__ +#include "afxresmw.h" +#else +#include "afxres.h" +#endif + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Firewireconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,48,100,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,100,50,14 + CONTROL "Enable Logging (for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,187,13 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "FireWire About" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "FireWire Driver",IDC_NAME,70,10,48,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Author: Shadow and linuzappz",IDC_STATIC,29,19,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/fw/FWnull/Win32/FireWireNull.sln b/plugins/fw/FWnull/Win32/FireWireNull.sln new file mode 100644 index 0000000000..95dd0df9c4 --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FireWireNull", "FireWireNull.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/fw/FWnull/Win32/FireWireNull.suo b/plugins/fw/FWnull/Win32/FireWireNull.suo new file mode 100644 index 0000000000000000000000000000000000000000..c194506856e6ee0d4e9ca8d32b2ace824efe05e5 GIT binary patch literal 7168 zcmeHMOK)366h3Yeng>ZAlmG#WY5EdstuzTulL!!rlMpFxN|Gj(h>#rn#&vV;YwYW$ z6;xu!4wXfJ01|5u8&<54y67qh2_dnf3&au@JPNc8-#7P;eeJ~W7EzRAojb2HbLMeg zGyZyG-wz*u-g8@u;8kgo`*rARdy4YF9iz{mW-^)jKq=Javom; zbJF#h3IiUNUA}#wp}ue)706XHZ6@gn)3PY@5|W_16Dh^r#wm=comqG1<4|w?z6AcY zuHS2~wNCR)v>jj_ZGdj`+JH{fcLDc!+V^|%y3bRndm8u*um|`o@Hyb~K+?S6rZ2i_ zFVe%nBfz6>9qD%9;qJh6@BVkbZJC?+=*HA7b8-4-Y<*4e%Q(G6{XpNcCum%bM-2bC zm9*2AsZ_2x7`DS4w*5kA#y=mqXe3mzGZ+t>R?I&UjoVh51bai)O58O3OU8( z_qKvk`?!@zSxF;ltH#cycrt3OXY%CDZ!CmnI9S)X8BeWP;dInL7f;4mwR_4)8tJgf z{8peYHv;T`1~@JwvMebvB`Y!5q9pWw85VIJ-$_|QIg2(Er6tumApOWU4%4u7^Z=%; z;CltOh}Q2ictnt^41U-C&<0RaEBA2X#!p?sAh@ikHOCa^CD>ydyf30u$@X#x@_zy; zZCADY8Rr}T5{miL>Kd5C8qUH}J8hSp$8qqdFQJXBmOuSu5J)KIPyffAPhl70m;vRW z92~8~|Izno|I?`a>bcQ>ybpBb*zxKy>}6OIIHO6d#Z)J{3|~jtqSwy=SFuh%d?3AV z7Stw6^Qg;8RIT4H0Xd7PU;*|0(udywHqs2zh|-4-|MfXgUQMiWRn0)p zM3+VWD>HKDS!^?k<&P(o#NN;2Y_e)s%Uc1+pO3Kuy+F0{Pueei_y9`tzluGjO)6n{ zo$iPgYLEY@uch=q1Sw5`E8}3t(ne8Y6t+E_!1^isydPD&e#VOn?r_w18$8q4bxMC; zQ*>l(K(1`)6>R}2`OVK}1pLWYgF9^5MBB@9iSK*sVg4qVV3C&8i7XpQx-zd zG!v&9SC%gfS)lz(p+s+#p&{tK2Yh zFT-M<1YI8}hfzC*_R}a2K=aPXHGD0|R~9nwNS0UT&!H`YS(Wodeb7JN2^hyw29Z<* z>K<(dp&WmG7Yjl&Y~Xeffc*15Qj7dQ33|p01ll>qTzZX;o~>flG1St3=@y5+_zV5d z@ve6L-5BJ1*Z$4I#$AF0&{vky@nW9d^1(XzAH)D5caQ*V{d$qy&8q0bD|Ni>(JOD2 zO~*QswpHER9;9rJ%4^{JAV&bx0!j)5u)?s?5)g!j6# z#c{;P22N`gr{=7j(p)(5C~B$!+R2{|9Qo$6-rlJ%e!P9{*h*qhiALA09`kNn@9g!> z5AJMy^~r>fwY*8wLoi0ArZPPXIpxhj zd%d2g_Hy)ty#3Jg(i=L`Mt@fx`2Iq^v?o0wpr8pMW_h9{$3~Fe#>pukA5!e2_=@)q$XI{_kv((%J(2odC(|OtR{AU2Z z#lUIsU8qodyn5-h=i@})P;F(Elh8k&kmDQ4r&WFpI2>B#w_NUbH`gI|RIW+>K+0ZC z@@J0fuUzi$T<&fzchAjr$flb+f&NpNOA<&wVY-^*_>Qf!bk?y5sxizu0t?JrrjfgU zbKb{+e20w|jOECrei@9TPhKuBY`71p>|O`xcTWBOIS<=M9poLHUNO&U`@yOIlsgUE cQx(=8Ls8#93tQ?dY2Hlh8= + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/fw/FWnull/Win32/FireWireNull_2005_x64.vcproj b/plugins/fw/FWnull/Win32/FireWireNull_2005_x64.vcproj new file mode 100644 index 0000000000..840da7efd2 --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull_2005_x64.vcproj @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.sln b/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.sln new file mode 100644 index 0000000000..8348796c93 --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FireWireNull", "FireWireNull_vsnet2005beta1.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + amd64|Win32 = amd64|Win32 + amd64|Win64 (AMD64) = amd64|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win32.ActiveCfg = amd64|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win32.Build.0 = amd64|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win64 (AMD64).ActiveCfg = amd64|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.amd64|Win64 (AMD64).Build.0 = amd64|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win32.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win32.Build.0 = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {F7181922-7377-4F67-9F50-10997B4613D8}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.vcproj b/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.vcproj new file mode 100644 index 0000000000..477f6c82d7 --- /dev/null +++ b/plugins/fw/FWnull/Win32/FireWireNull_vsnet2005beta1.vcproj @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/fw/FWnull/Win32/Makefile b/plugins/fw/FWnull/Win32/Makefile new file mode 100644 index 0000000000..82afda1120 --- /dev/null +++ b/plugins/fw/FWnull/Win32/Makefile @@ -0,0 +1,29 @@ + +RC = windres +STRIP = strip + +PLUGIN = FWnull.dll +CFLAGS = -Wall -O2 -fomit-frame-pointer -I.. -D__WIN32__ -D__MINGW32__ +LIBS = -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = FireWireNull.o +OBJS = ../FW.o Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +all: plugin + +plugin: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clear plugin + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} + +${RESOBJ}: FireWireNull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/fw/FWnull/Win32/Win32.c b/plugins/fw/FWnull/Win32/Win32.c new file mode 100644 index 0000000000..205bb8fac9 --- /dev/null +++ b/plugins/fw/FWnull/Win32/Win32.c @@ -0,0 +1,81 @@ +#include +#include +#include + + +#include "resource.h" +#include "FW.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "FW Plugin Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK FWconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK FWabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/fw/FWnull/Win32/afxresmw.h b/plugins/fw/FWnull/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/fw/FWnull/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/fw/FWnull/Win32/resource.h b/plugins/fw/FWnull/Win32/resource.h new file mode 100644 index 0000000000..f8ab2765f1 --- /dev/null +++ b/plugins/fw/FWnull/Win32/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by FireWireNull.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/fw/FWnull/build.sh b/plugins/fw/FWnull/build.sh new file mode 100644 index 0000000000..a7ad4f2a69 --- /dev/null +++ b/plugins/fw/FWnull/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo --------------- +echo Building FWnull +echo --------------- + +curdir=`pwd` + +cd ${curdir}/Linux +make $@ + +if [ -s cfgFWnull ] && [ -s libFWnull.so ] +then +cp cfgFWnull libFWnull.so ${PCSX2PLUGINS} +fi diff --git a/plugins/fw/build.sh b/plugins/fw/build.sh new file mode 100644 index 0000000000..f97fa19742 --- /dev/null +++ b/plugins/fw/build.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +echo ---------------------------- +echo Building FireWire plugins... +echo ---------------------------- + +curdir=`pwd` + +cd ${curdir}/FWnull +sh build.sh $@ + +#cd ${curdir}/FWlinuz +#sh build.sh $@ diff --git a/plugins/gs/GSsoft/License.txt b/plugins/gs/GSsoft/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/gs/GSsoft/License.txt @@ -0,0 +1,342 @@ + 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/plugins/gs/GSsoft/ReadMe.txt b/plugins/gs/GSsoft/ReadMe.txt new file mode 100644 index 0000000000..5b9f33f931 --- /dev/null +++ b/plugins/gs/GSsoft/ReadMe.txt @@ -0,0 +1,109 @@ +GSsoft v1.0 +----------- + + This is an extension to use with play station2 emulators + such as PCSX2. + The plugin is free open source code. + +Using: +----- + Place the file "GSsoft.dll" (Windows) or "GSsoft.so" (Linux) + at the Plugins directory of the Emulator to use it. + +Configuration: +------------- + Display Resolution: + Select the Resolution mode you want to use. + + Fullscreen: + Sets fullscreen mode (else windowed). + + Display FPS Count: + This will show on the start the frame per second count, + also you can change settings from here. + + Frameskip: + You can use this to improve a little speed (will skip some + frames). + +Quick Keys: +---------- + Delete - Show/Hide FPS Count. + End - Change selected setting in FPS Count. + PageUp/ + PageDn - Move up/down in the FPS Count. + +Changes: +------- + v1.0 + * Fixed GIFprocessReg with RGBAQ/STQ handling + + v0.9 + * Lots of fixes, implemented most psm's, thx to gabest + for helping me with some stuff + * Rewrote triangle algorithm, based on the 3DFC algo, + http://www.geocities.com/SiliconValley/Bay/1704 + * Both CRTs now are blended when both enabled + + v0.8 + * Up to 0.5.5 specs + * Several fixes + * Up to SDL 1.2.7 + * added sdl_gfxprimitives 1.5 inside source. No need to load external dll + * savings are now done in ini. + * cleanup some stuff + + v0.6 + * Added savestates support + * Partially fixed the local memory structure, big thanks to asadr/tyranid + * Fixed some bugs + * This version is a bit untested, so you may expect some crashes ;P + v0.5: + * Added Color.c/Texts.c + * Most _Z primitives are implemented + * Fixed lots of bugs + * Implemented Alpha Blending + * Implemented colorclamping + * New PS2Edefs v0.4.0 + + v0.41: + * Corrected VSync interlace bit + * Added FINISH handling + * Added From VRam transfers + + v0.4: + * Added Linux-SDL dir, thanks to Muad + * Added bugfix for ps2mame (thanks to asad) + * STQ stuff starts to work (thanks to Absolute0) + * Added GSgifTransfer2 support + * Also some internal changes + + v0.31: + * Fixed interlace modes + + v0.3: + * Added Draw.c/h for blits. + * Added ShowFullVRam option on FPS Count. + * Added some zBuffer support. + * Last vertex rgba is now ok. + * Added more stuff on GSwrite/read32/64 + + v0.2: + * 16bit mode should be fine always now + * Cursor will be disabled in windowed mode too + * Improved lots of stuff, psms now works (8bit textures) + * Added non-stretched blits + * Linux support under XWindows (GSsoftx) + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + linuzappz + [TyRaNiD] + shadow + + diff --git a/plugins/gs/GSsoft/Src/Cache.c b/plugins/gs/GSsoft/Src/Cache.c new file mode 100644 index 0000000000..08353cf00b --- /dev/null +++ b/plugins/gs/GSsoft/Src/Cache.c @@ -0,0 +1,201 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include + +#include "Draw.h" +#include "Mem.h" +#include "Page.h" +#include "Texts.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +typedef struct { + u32 *_data; + u32 *data; + tex0Info tex0; +} Cache; + +Cache *Texts; +Cache *Texture; +int TextureCount; + +int CacheInit() { + Texts = (Cache*)malloc(conf.cachesize * sizeof(Cache)); + memset(Texts, 0, conf.cachesize * sizeof(Cache)); + TextureCount = 0; + + return 0; +} + +void _CacheLoadTexture32(Cache *tex) { + s32 otick; + s32 tick; + u32 *mem; + u32 *ptr; + int u, v; + +#ifdef __GNUC__ + __asm__ __volatile__ ( + "rdtsc\n" + : "=a"(otick) : + ); +#else + __asm { + rdtsc + mov otick, eax + } +#endif + + ptr = tex->data; + for (v=0; vtex0.th; v++) { + for (u=0; utex0.tw; u+=8) { + mem = &vRamUL[getPixelAddress32(u, v, tex->tex0.tbp0, tex->tex0.tbw)]; +#ifdef __GNUC__ + __asm__ __volatile__ ( + "movsd %1, %%xmm0\n" + "movhps %2, %%xmm0\n" + "movaps %%xmm0, %0\n" + : "=m"(&ptr[0]) : "m"(&mem[0]), "m"(&mem[4]) + ); +#else + ptr[0] = mem[0]; ptr[1] = mem[1]; + ptr[2] = mem[4]; ptr[3] = mem[5]; + ptr[4] = mem[8]; ptr[5] = mem[9]; + ptr[6] = mem[12]; ptr[7] = mem[13]; +#endif + ptr+= 8; + } + + for (; utex0.tw; u++) { + *ptr++ = readPixel32(u, v, tex->tex0.tbp0, tex->tex0.tbw); + } + } + +#ifdef __GNUC__ + __asm__ __volatile__ ( + "rdtsc\n" + : "=a"(tick) : + ); +#else + __asm { + rdtsc + mov tick, eax + } +#endif + + printf("%d\n", tick - otick); +} + +void _CacheLoadTexture(Cache *tex) { + u32 *ptr; + int u, v; + + ptr = tex->data; + for (v=0; vtex0.th; v++) { + for (u=0; utex0.tw; u++) { + *ptr++ = GetTexturePixel32(u, v); + } + } +} + +void CacheLoadTexture(int i) { + Texts[i].tex0 = *tex0; + Texts[i]._data = malloc(Texts[i].tex0.th*Texts[i].tex0.tw*4+16); + Texts[i].data = _align16(Texts[i]._data); +/* if (Texts[i].tex0.psm == 0) { + _CacheLoadTexture32(&Texts[i]); + return; + }*/ + _CacheLoadTexture(&Texts[i]); +} + +void CacheFreeTexture(int i) { + free(Texts[i]._data); Texts[i]._data = NULL; +} + +int CacheSetTexture() { + int i; + +#ifdef GS_LOG + GS_LOG("CacheSetTexture\n"); +#endif + if (tex0->tbp0 == gs._gsfb[0].fbp || + tex0->tbp0 == gs._gsfb[1].fbp) { + return -1; + } + + for (i=0; i= conf.cachesize) TextureCount = 0; + CacheFreeTexture(i); + } + +#ifdef GS_LOG + GS_LOG("CacheSetTexture: %dx%d: %d\n", tex0->tw, tex0->th, i); +#endif + printf("CacheSetTexture: %x, %dx%d: %d\n", tex0->tbp0, tex0->tw, tex0->th, i); + CacheLoadTexture(i); + Texture = &Texts[i]; + return 0; +} + +u32 CacheGetTexturePixel32(int u, int v) { + wrapUV(&u, &v); + if (u < 0 || u >= Texture->tex0.tw) return 0; + if (v < 0 || v >= Texture->tex0.th) return 0; +#ifdef GS_LOG +// GS_LOG("CacheGetTexturePixel32 %dx%d\n", u, v); +#endif + return Texture->data[v*Texture->tex0.tw+u]; +} + +void CacheClear(u32 bp, int size) { + int i; + + for (i=0; i + +#include "GS.h" +#include "Soft.h" +#include "Texts.h" +#include "Color.h" +#include "Mem.h" + +/* blend 2 colours together and return the result */ +u32 blender(const u8 *A, const u8 *B, const int C, const u8 *D) { + int i; + u32 res = 0; + int temp; + + for (i = 0; i < 3; i++) { + temp = ((((int) A[i] - (int) B[i]) * C) >> 7) + (int)D[i]; + if (gs.colclamp) { + if (temp < 0x00) temp = 0x00; else + if (temp > 0xFF) temp = 0xFF; + } else { + temp&= 0xFF; + } + + res |= temp << (i << 3); + } + + return res; +} + +int scissorTest(int x, int y) { + if (x < scissor->x0 || x > scissor->x1) return -1; + if (y < scissor->y0 || y > scissor->y1) return -1; + + return 0; +} + +int dateTest32(int x, int y) { + if (test->date) { // Destination Alpha Test + u32 pixel = readPixel32(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 31) == 0) return -1; + } else { + if ((pixel >> 31) == 1) return -1; + } + } + + return 0; +} + +int dateTest16(int x, int y) { + if (test->date) { // Destination Alpha Test + u16 pixel = readPixel16(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 15) == 0) return -1; + } else { + if ((pixel >> 15) == 1) return -1; + } + } + + return 0; +} + +int dateTest16S(int x, int y) { + if (test->date) { // Destination Alpha Test + u16 pixel = readPixel16S(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 15) == 0) return -1; + } else { + if ((pixel >> 15) == 1) return -1; + } + } + + return 0; +} + +int dateTest32Z(int x, int y) { + if (test->date) { // Destination Alpha Test + u32 pixel = readPixel32Z(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 31) == 0) return -1; + } else { + if ((pixel >> 31) == 1) return -1; + } + } + + return 0; +} + +int dateTest16Z(int x, int y) { + if (test->date) { // Destination Alpha Test + u16 pixel = readPixel16Z(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 15) == 0) return -1; + } else { + if ((pixel >> 15) == 1) return -1; + } + } + + return 0; +} + +int dateTest16SZ(int x, int y) { + if (test->date) { // Destination Alpha Test + u16 pixel = readPixel16SZ(x, y, gsfb->fbp, gsfb->fbw); + if (test->datm) { + if ((pixel >> 15) == 0) return -1; + } else { + if ((pixel >> 15) == 1) return -1; + } + } + + return 0; +} + +int depthTest(int x, int y, u32 z) { +//GS_LOG("depthTest %dx%d %x\n", x, y, z); + switch (test->ztst) { + case ZTST_NEVER: + return -1; + + case ZTST_ALWAYS: + break; + + case ZTST_GEQUAL: + if (z < readPixelZ(x, y)) return -1; + break; + + case ZTST_GREATER: + if (z <= readPixelZ(x, y)) return -1; + break; + } + + return 0; +} + +int _alphaTest(u32 p) { + switch (test->atst) { + case ATST_NEVER: + return -1; + case ATST_ALWAYS: + break; + case ATST_LESS: + if ((p >> 24) < test->aref) break; + else return -1; + case ATST_LEQUAL: + if ((p >> 24) <= test->aref) break; + else return -1; + case ATST_EQUAL: + if ((p >> 24) == test->aref) break; + else return -1; + case ATST_GEQUAL: + if ((p >> 24) >= test->aref) break; + else return -1; + case ATST_GREATER: + if ((p >> 24) > test->aref) break; + else return -1; + case ATST_NOTEQUAL: + if ((p >> 24) != test->aref) break; + else return -1; + } + + return 0; +} + +int alphaTest(u32 p) { + if (test->ate == 0) return 0; + + if (_alphaTest(p) == -1) { + switch (test->afail) { + case AFAIL_KEEP: + return -1; + case AFAIL_FB_ONLY: + return 1; + case AFAIL_ZB_ONLY: + return 2; + case AFAIL_RGB_ONLY: + return 3; + } + } + + return 0; +} + +u32 fog(u32 p) { +/* if (prim->fge) { // Fogging + u8 r, g, b, a; + + r = ((F * (p >> 16)) >> 8) + + (((0xff - F) * fogcolr) >> 8); + p = (r << 16) | (g << 8) | b + }*/ + + return p; +} + +u32 (*procPixelABE) (int, int, u32); + +u32 _procPixelABE(u32 Cs, u32 Cd) { + u32 A, B, C, D, c; + + switch (alpha->a) { + case 0x00: A = Cs & 0xffffff; break; + case 0x01: A = Cd & 0xffffff; break; + default: A = 0; break; + } + + switch (alpha->b) { + case 0x00: B = Cs & 0xffffff; break; + case 0x01: B = Cd & 0xffffff; break; + default: B = 0; break; + } + + switch (alpha->c) { + case 0x00: C = Cs >> 24; break; + case 0x01: C = Cd >> 24; break; + case 0x02: C = alpha->fix; break; + default: C = 0; break; + } + + switch (alpha->d) { + case 0x00: D = Cs & 0xffffff; break; + case 0x01: D = Cd & 0xffffff; break; + default: D = 0; break; + } + c = blender((u8 *) &A, (u8 *) &B, C, (u8 *) &D); + c|= fba->fba << 31; +// printf("_procPixelABE (%d): %dx%d: %x, %x, %x, %x: %x (%d)\n", gs.pabe, x, y, A, B, C, D, c, alpha->c); + + return c; +} + +u32 _procPixelABE32(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel32(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE24(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel24(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE16(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel16to32(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE16S(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel16Sto32(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE32Z(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel32Z(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE24Z(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel24Z(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE16Z(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel16Zto32(x, y, gsfb->fbp, gsfb->fbw)); +} + +u32 _procPixelABE16SZ(int x, int y, u32 p) { + if (gs.pabe) { + if ((p >> 31) == 0) { // MSB = 0*/ + return p; + } + } + + return _procPixelABE(p, readPixel16SZto32(x, y, gsfb->fbp, gsfb->fbw)); +} + + +void _drawPixelAA1(int x, int y, u32 p) { +} + +////////////////////////////////// +// drawPixel + +void _drawPixel32(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest32(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (gsfb->fbm) { + p = (p & (~gsfb->fbm)) | (readPixel32(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } + + if (ret == 0 || ret == 1) { + writePixel32(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + writePixel24(x, y, p, gsfb->fbp, gsfb->fbw); + } +} + +void _drawPixel24(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (gsfb->fbm) { + p = (p & (~gsfb->fbm)) | (readPixel24(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } + writePixel24(x, y, p, gsfb->fbp, gsfb->fbw); +} + +void _drawPixel16(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest16(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (ret == 0 || ret == 1) { + if (gsfb->fbm) { + p = (RGBA32to16(p) & (~gsfb->fbm)) | (readPixel16(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } else { + p = RGBA32to16(p); + } + writePixel16(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + if (gsfb->fbm) { + u32 fbm = gsfb->fbm | 0x8000; + p = (RGBA32to16(p) & (~fbm)) | (readPixel16(x, y, gsfb->fbp, gsfb->fbw) & fbm); + } else { + p = (RGBA32to16(p) & ~0x8000) | (readPixel16(x, y, gsfb->fbp, gsfb->fbw) & 0x8000); + } + writePixel16(x, y, RGBA32to16(p), gsfb->fbp, gsfb->fbw); + } +} + +void _drawPixel16S(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest16S(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (ret == 0 || ret == 1) { + if (gsfb->fbm) { + p = (RGBA32to16(p) & (~gsfb->fbm)) | (readPixel16S(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } else { + p = RGBA32to16(p); + } + writePixel16S(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + if (gsfb->fbm) { + u32 fbm = gsfb->fbm | 0x8000; + p = (RGBA32to16(p) & (~fbm)) | (readPixel16S(x, y, gsfb->fbp, gsfb->fbw) & fbm); + } else { + p = (RGBA32to16(p) & ~0x8000) | (readPixel16S(x, y, gsfb->fbp, gsfb->fbw) & 0x8000); + } + writePixel16S(x, y, RGBA32to16(p), gsfb->fbp, gsfb->fbw); + } +} + +void _drawPixel32Z(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest32Z(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (gsfb->fbm) { + p = (p & (~gsfb->fbm)) | (readPixel32Z(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } + + if (ret == 0 || ret == 1) { + writePixel32Z(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + writePixel24Z(x, y, p, gsfb->fbp, gsfb->fbw); + } +} + +void _drawPixel24Z(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (gsfb->fbm) { + p = (p & (~gsfb->fbm)) | (readPixel24Z(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } + writePixel24Z(x, y, p, gsfb->fbp, gsfb->fbw); +} + +void _drawPixel16Z(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest16Z(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (ret == 0 || ret == 1) { + if (gsfb->fbm) { + p = (RGBA32to16(p) & (~gsfb->fbm)) | (readPixel16Z(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } else { + p = RGBA32to16(p); + } + writePixel16(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + if (gsfb->fbm) { + u32 fbm = gsfb->fbm | 0x8000; + p = (RGBA32to16(p) & (~fbm)) | (readPixel16Z(x, y, gsfb->fbp, gsfb->fbw) & fbm); + } else { + p = (RGBA32to16(p) & ~0x8000) | (readPixel16Z(x, y, gsfb->fbp, gsfb->fbw) & 0x8000); + } + writePixel16Z(x, y, RGBA32to16(p), gsfb->fbp, gsfb->fbw); + } +} + +void _drawPixel16SZ(int x, int y, u32 p) { + int ret; + + if (scissorTest(x, y)) return; + if (dateTest16SZ(x, y)) return; + ret = alphaTest(p); + if (ret == -1) return; + + if (prim->abe) { // alpha blending + p = procPixelABE(x, y, p); + } + + if (ret == 0 || ret == 1) { + if (gsfb->fbm) { + p = (RGBA32to16(p) & (~gsfb->fbm)) | (readPixel16SZ(x, y, gsfb->fbp, gsfb->fbw) & gsfb->fbm); + } else { + p = RGBA32to16(p); + } + writePixel16SZ(x, y, p, gsfb->fbp, gsfb->fbw); + } else + if (ret == 3) { + if (gsfb->fbm) { + u32 fbm = gsfb->fbm | 0x8000; + p = (RGBA32to16(p) & (~fbm)) | (readPixel16SZ(x, y, gsfb->fbp, gsfb->fbw) & fbm); + } else { + p = (RGBA32to16(p) & ~0x8000) | (readPixel16SZ(x, y, gsfb->fbp, gsfb->fbw) & 0x8000); + } + writePixel16SZ(x, y, RGBA32to16(p), gsfb->fbp, gsfb->fbw); + } +} + +////////////////////////////////// +// drawPixelF + + +void SETprocPixelABE() { + procPixelABE = 0; +#if 0 + if (alpha->a == 0) { + if (alpha->b == 0) { + } else + if (alpha->b == 1) { + } else { + if (alpha->c == 0) { + if (alpha->d == 0) { + } else + if (alpha->d == 1) { + switch (gsfb->psm) { + case 0x0: + if (gs.pabe) { + if (gs.colclamp) { + procPixelABE = _procPixelABE32_A0B2C0D1_PABE_CC; + } else { + procPixelABE = _procPixelABE32_A0B2C0D1_PABE; + } + } else { + if (gs.colclamp) { + procPixelABE = _procPixelABE32_A0B2C0D1_CC; + } else { + procPixelABE = _procPixelABE32_A0B2C0D1; + } + } + break; + case 0x2: procPixelABE = _procPixelABE16_A0B2C0D1; break; + } + } + } else + if (alpha->c == 1) { + } else + if (alpha->c == 2) { + } + } + } else + if (alpha->a == 1) { + if (alpha->b == 0) { + } else + if (alpha->b == 1) { + } else { + if (alpha->c == 0) { + if (alpha->d == 0) { + } else + if (alpha->d == 1) { + } + } else + if (alpha->c == 1) { + } else + if (alpha->c == 2) { + if (alpha->d == 0) { +/* switch (gsfb->psm) { + case 0x0: + if (gs.pabe) { + if (gs.colclamp) { + procPixelABE = _procPixelABE32_A1B2C2D0_PABE_CC; + } else { + procPixelABE = _procPixelABE32_A1B2C2D0_PABE; + } + } else { + if (gs.colclamp) { + procPixelABE = _procPixelABE32_A1B2C2D0_CC; + } else { + procPixelABE = _procPixelABE32_A1B2C2D0; + } + } + break; + }*/ + } else + if (alpha->d == 1) { + } + } + } + } else { + } +#endif + if (procPixelABE == 0) { +// printf("ABE default: %d,%d,%d,%d\n", alpha->a, alpha->b, alpha->c, alpha->d); + switch (gsfb->psm) { + case 0x0: procPixelABE = _procPixelABE32; break; + case 0x1: procPixelABE = _procPixelABE24; break; + case 0x2: procPixelABE = _procPixelABE16; break; + case 0xa: procPixelABE = _procPixelABE16S; break; + case 0x30:procPixelABE = _procPixelABE32Z; break; + case 0x31:procPixelABE = _procPixelABE24Z; break; + case 0x32:procPixelABE = _procPixelABE16Z; break; + case 0x3a:procPixelABE = _procPixelABE16SZ; break; + default: + if (gsfb->psm) printf("SETprocPixelABE psm == %d!!\n", gsfb->psm); + drawPixel = _drawPixel32; + break; + } + } +} + +void SETdrawPixel() { + drawPixel = 0; + if (drawPixel == 0) { + switch (gsfb->psm) { + case 0x1: drawPixel = _drawPixel24; break; + case 0x2: drawPixel = _drawPixel16; break; + case 0xa: drawPixel = _drawPixel16S; break; + case 0x30:drawPixel = _drawPixel32Z; break; + case 0x31:drawPixel = _drawPixel24Z; break; + case 0x32:drawPixel = _drawPixel16Z; break; + case 0x3a:drawPixel = _drawPixel16SZ; break; + default: // PSMT32 + if (gsfb->psm) printf("SETdrawPixel psm == %d!!\n", gsfb->psm); + drawPixel = _drawPixel32; + break; + } + } + + if (prim->abe) { // alpha blending + SETprocPixelABE(); + } +} + +void SETdrawPixelF() { +/* drawPixelF = 0; + if (drawPixelF == 0) { + switch (gsfb->psm) { + case 0x1: drawPixelF = _drawPixel24F; break; + case 0x2: drawPixelF = _drawPixel16F; break; + case 0xa: drawPixelF = _drawPixel16SF; break; + default: // PSMT32 + if (gsfb->psm) printf("SETdrawPixel psm == %d!!\n", gsfb->psm); + drawPixelF = _drawPixel32F; + break; + } + } + + if (prim->abe) { // alpha blending + SETprocPixelABE(); + }*/ +} + +////////////////////////////////// +// drawPixelZ + + +// zmsk = 0 +void _drawPixel32_Z(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel32Z(x, y, z, zbuf->zbp, gsfb->fbw); + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 2: // write z only + writePixel32Z(x, y, z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 1 +void _drawPixel32_Zmsk(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 0 +void _drawPixel24_Z(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel24Z(x, y, z, zbuf->zbp, gsfb->fbw); + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 2: // write z only + writePixel24Z(x, y, z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 1 +void _drawPixel24_Zmsk(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 0 +void _drawPixel16_Z(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel16Z(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 2: // write z only + writePixel16Z(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 1 +void _drawPixel16_Zmsk(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 0 +void _drawPixel16S_Z(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel16SZ(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 2: // write z only + writePixel16SZ(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + +// zmsk = 1 +void _drawPixel16S_Zmsk(int x, int y, u32 p, u32 z) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixel(x, y, p); + break; + + case 1: // write p only + drawPixel(x, y, p); + break; + + case 3: // write rgb only + drawPixel(x, y, p); + break; + } +} + + +////////////////////////////////// +// drawPixelZF + + +// zmsk = 0 +void _drawPixel32_ZF(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel32Z(x, y, z, zbuf->zbp, gsfb->fbw); + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 2: // write z only + writePixel32Z(x, y, z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 1 +void _drawPixel32_ZFmsk(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 0 +void _drawPixel24_ZF(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel24Z(x, y, z, zbuf->zbp, gsfb->fbw); + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 2: // write z only + writePixel24Z(x, y, z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 1 +void _drawPixel24_ZFmsk(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 0 +void _drawPixel16_ZF(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel16Z(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 2: // write z only + writePixel16Z(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 1 +void _drawPixel16_ZFmsk(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 0 +void _drawPixel16S_FZ(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + writePixel16SZ(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 2: // write z only + writePixel16SZ(x, y, (u16)z, zbuf->zbp, gsfb->fbw); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + +// zmsk = 1 +void _drawPixel16S_FZmsk(int x, int y, u32 p, u32 z, u32 f) { + int ret; + + if (scissorTest(x, y)) return; + if (depthTest(x, y, z)) return; + + ret = alphaTest(p); + switch (ret) { + case 0: // write p and z + drawPixelF(x, y, p, f); + break; + + case 1: // write p only + drawPixelF(x, y, p, f); + break; + + case 3: // write rgb only + drawPixelF(x, y, p, f); + break; + } +} + + +u32 _readPixel32Z(int x, int y) { + return readPixel32Z(x, y, zbuf->zbp, gsfb->fbw); +} + +u32 _readPixel24Z(int x, int y) { + return readPixel24Z(x, y, zbuf->zbp, gsfb->fbw); +} + +u32 _readPixel16Z(int x, int y) { + return readPixel16Z(x, y, zbuf->zbp, gsfb->fbw); +} + +u32 _readPixel16SZ(int x, int y) { + return readPixel16SZ(x, y, zbuf->zbp, gsfb->fbw); +} + +void SETdrawPixelZ() { + SETdrawPixel(); + switch (zbuf->psm) { + case 0x1: // PSMZ24 + if (zbuf->zmsk == 0) { + drawPixelZ = _drawPixel24_Z; + } else { + drawPixelZ = _drawPixel24_Zmsk; + } + readPixelZ = _readPixel24Z; break; + case 0x2: // PSMZ16 + if (zbuf->zmsk == 0) { + drawPixelZ = _drawPixel16_Z; + } else { + drawPixelZ = _drawPixel16_Zmsk; + } + readPixelZ = _readPixel16Z; break; + case 0xa: // PSMZ16S + if (zbuf->zmsk == 0) { + drawPixelZ = _drawPixel16S_Z; + } else { + drawPixelZ = _drawPixel16S_Zmsk; + } + readPixelZ = _readPixel16SZ; break; + default: + if (zbuf->psm) printf("unknown PSMZ psm %x\n", zbuf->psm); + if (zbuf->zmsk == 0) { + drawPixelZ = _drawPixel32_Z; + } else { + drawPixelZ = _drawPixel32_Zmsk; + } + readPixelZ = _readPixel32Z; break; + } +} + +void SETdrawPixelZF() { + SETdrawPixelF(); + switch (zbuf->psm) { + case 0x1: // PSMZ24 + if (zbuf->zmsk == 0) { + drawPixelZF = _drawPixel24_ZF; + } else { + drawPixelZF = _drawPixel24_ZFmsk; + } + readPixelZ = _readPixel24Z; break; + case 0x2: // PSMZ16 + if (zbuf->zmsk == 0) { + drawPixelZF = _drawPixel16_ZF; + } else { + drawPixelZF = _drawPixel16_ZFmsk; + } + readPixelZ = _readPixel16Z; break; + case 0xa: // PSMZ16S + if (zbuf->zmsk == 0) { + drawPixelZF = _drawPixel16S_FZ; + } else { + drawPixelZF = _drawPixel16S_FZmsk; + } + readPixelZ = _readPixel16SZ; break; + default: + if (zbuf->psm) printf("unknown PSMZ psm %x\n", zbuf->psm); + if (zbuf->zmsk == 0) { + drawPixelZF = _drawPixel32_ZF; + } else { + drawPixelZF = _drawPixel32_ZFmsk; + } + readPixelZ = _readPixel32Z; break; + } +} + +int af, rf, gf, bf; /* Colour of vertex */ + +void colSetCol(u32 crgba) { + af = (crgba >> 24) & 0xFF; + rf = (crgba >> 16) & 0xFF; + gf = (crgba >> 8) & 0xFF; + bf = (crgba ) & 0xFF; +} + +u32 colModulate(u32 texcol) { + u32 at, rt, gt, bt; /* Colour of texture */ + + rt = (texcol >> 16) & 0xFF; + gt = (texcol >> 8) & 0xFF; + bt = texcol & 0xFF; /* Extract colours from texture */ + + rt = (rt * rf) >> 7; + gt = (gt * gf) >> 7; + bt = (bt * bf) >> 7; + if(rt > 0xFF) rt = 0xFF; + if(gt > 0xFF) gt = 0xFF; + if(bt > 0xFF) bt = 0xFF; + + if (tex0->tcc) { // RGBA + at = (texcol >> 24) & 0xFF; + at = (at * af) >> 7; /* Multiply by colour value */ + if(at > 0xFF) at = 0xFF; + } else { // RGB + at = af; + } + + return (at << 24) | (rt << 16) | (gt << 8) | bt; +} + +u32 colHighlight(u32 texcol) { + u32 at, rt, gt, bt; /* Colour of texture */ + + rt = (texcol >> 16) & 0xFF; + gt = (texcol >> 8) & 0xFF; + bt = texcol & 0xFF; /* Extract colours from texture */ + + rt = ((rt * rf) >> 7) + af; + gt = ((gt * gf) >> 7) + af; + bt = ((bt * bf) >> 7) + af; + if(rt > 0xFF) rt = 0xFF; + if(gt > 0xFF) gt = 0xFF; + if(bt > 0xFF) bt = 0xFF; + + if (tex0->tcc) { // RGBA + at = (texcol >> 24) & 0xFF; + at = (at * af) >> 7; /* Multiply by colour value */ + if(at > 0xFF) at = 0xFF; + } else { // RGB + at = af; + } + + return (at << 24) | (rt << 16) | (gt << 8) | bt; +} + +u32 colHighlight2(u32 texcol) { + u32 at, rt, gt, bt; /* Colour of texture */ + + rt = (texcol >> 16) & 0xFF; + gt = (texcol >> 8) & 0xFF; + bt = texcol & 0xFF; /* Extract colours from texture */ + + rt = ((rt * rf) >> 7) + af; + gt = ((gt * gf) >> 7) + af; + bt = ((bt * bf) >> 7) + af; + if(rt > 0xFF) rt = 0xFF; + if(gt > 0xFF) gt = 0xFF; + if(bt > 0xFF) bt = 0xFF; + + if (tex0->tcc) { // RGBA + at = (texcol >> 24) & 0xFF; + } else { // RGB + at = af; + } + + return (at << 24) | (rt << 16) | (gt << 8) | bt; +} + diff --git a/plugins/gs/GSsoft/Src/Color.h b/plugins/gs/GSsoft/Src/Color.h new file mode 100644 index 0000000000..74b2db2cbf --- /dev/null +++ b/plugins/gs/GSsoft/Src/Color.h @@ -0,0 +1,40 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __COLOR_H__ +#define __COLOR_H__ + +void (*drawPixel) (int, int, u32); +void SETdrawPixel(); + +void (*drawPixelF) (int, int, u32, u32); +void SETdrawPixelF(); + +void (*drawPixelZ) (int, int, u32, u32); +u32 (*readPixelZ) (int, int); +void SETdrawPixelZ(); + +void (*drawPixelZF) (int, int, u32, u32, u32); +void SETdrawPixelZF(); + +void colSetCol(u32 crgba); +u32 colModulate(u32 texcol); +u32 colHighlight(u32 texcol); +u32 colHighlight2(u32 texcol); + +#endif /* __COLOR_H__ */ diff --git a/plugins/gs/GSsoft/Src/Draw.c b/plugins/gs/GSsoft/Src/Draw.c new file mode 100644 index 0000000000..e023c4a0a3 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Draw.c @@ -0,0 +1,530 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 "Draw.h" +#include "Mem.h" +#include "Page.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +void (*_ScrBlit)(u8 *, int, int, int, Rect *, u32, u32, u32); +void (*_ScrBlitMerge)(u8 *, int, int, int); + + +//////////////////// +// 15bit + +void _ScrBlit32to15(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u32 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x0000f8) << 7) | /* 0x7c00 */ + ((c & 0x00f800) >> 6) | /* 0x03e0 */ + ((c & 0xf80000) >> 19); /* 0x001f */ + } + } +} + +void _ScrBlit16to15(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x001f) << 10) | /* 0x7c00 */ + ((c & 0x03e0) ) | /* 0x03e0 */ + ((c & 0x7c00) >> 10); /* 0x001f */ + } + } +} + +void _ScrBlit16Sto15(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x001f) << 10) | /* 0x7c00 */ + ((c & 0x03e0) ) | /* 0x03e0 */ + ((c & 0x7c00) >> 10); /* 0x001f */ + } + } +} + +void ScrBlit15(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 psm, u32 bp, u32 bw) { + switch (psm) { + case 0x2: _ScrBlit16to15(scr, dw, dh, sp, gsScr, bp, bw); break; + case 0xA: _ScrBlit16Sto15(scr, dw, dh, sp, gsScr, bp, bw); break; + default: _ScrBlit32to15(scr, dw, dh, sp, gsScr, bp, bw); break; + } +} + +//////////////////// +// 16bit + +void _ScrBlit32to16(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u32 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x0000f8) << 8) | /* 0xf800 */ + ((c & 0x00fc00) >> 5) | /* 0x07e0 */ + ((c & 0xf80000) >> 19); /* 0x001f */ + } + } +} + +void _ScrBlit16to16(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x001f) << 11) | /* 0xf800 */ + ((c & 0x03e0) << 1) | /* 0x07e0 */ + ((c & 0x7c00) >> 10); /* 0x001f */ + } + } +} + +void _ScrBlit16Sto16(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u16 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + *pscr++= ((c & 0x001f) << 11) | /* 0xf800 */ + ((c & 0x03e0) << 1) | /* 0x07e0 */ + ((c & 0x7c00) >> 10); /* 0x001f */ + } + } +} + +void ScrBlit16(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 psm, u32 bp, u32 bw) { + switch (psm) { + case 0x2: _ScrBlit16to16(scr, dw, dh, sp, gsScr, bp, bw); break; + case 0xA: _ScrBlit16Sto16(scr, dw, dh, sp, gsScr, bp, bw); break; + default: _ScrBlit32to16(scr, dw, dh, sp, gsScr, bp, bw); break; + } +} + +//////////////////// +// 32bit + +void _ScrBlit32to32(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u8 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u32 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + pscr[0] = (c >> 16) & 0xff; + pscr[1] = (c >> 8) & 0xff; + pscr[2] = c & 0xff; + pscr+=4; + } + } +} + +void _ScrBlit16to32(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u8 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + pscr[0] = (c >> 7) & 0xf8; + pscr[1] = (c >> 2) & 0xf8; + pscr[2] = (c << 3) & 0xf8; + pscr+=4; + } + } +} + +void _ScrBlit16Sto32(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 bp, u32 bw) { + u8 *pscr; + int x, y; + int xpos, xinc; + int ypos, yinc; + u16 c; + + xinc = (gsScr->w << 16) / dw; + yinc = (gsScr->h << 16) / dh; + + for (y=0, ypos=gsScr->y<<16; yx<<16; x>16, ypos>>16, bp, bw); + pscr[0] = (c >> 7) & 0xf8; + pscr[1] = (c >> 2) & 0xf8; + pscr[2] = (c << 3) & 0xf8; + pscr+=4; + } + } +} + +void ScrBlit32(u8 *scr, int dw, int dh, int sp, Rect *gsScr, u32 psm, u32 bp, u32 bw) { + switch (psm) { + case 0x2: _ScrBlit16to32(scr, dw, dh, sp, gsScr, bp, bw); break; + case 0xA: _ScrBlit16Sto32(scr, dw, dh, sp, gsScr, bp, bw); break; + default: _ScrBlit32to32(scr, dw, dh, sp, gsScr, bp, bw); break; + } +} + + +void ScrBlitMerge15(u8 *scr, int dw, int dh, int sp) { + u32 (*_readPixel1)(int x, int y, u32 bp, u32 bw); + u32 (*_readPixel2)(int x, int y, u32 bp, u32 bw); + u16 *pscr; + int x, y; + int xpos1, xinc1; + int ypos1, yinc1; + int xpos2, xinc2; + int ypos2, yinc2; + u32 alpha; + u32 c1, c2; + u32 r1,g1,b1; + u32 r2,g2,b2; + + switch (gs.DISPFB[0].psm) { + case 0x2: _readPixel1 = readPixel16to32; break; + case 0xA: _readPixel1 = readPixel16Sto32; break; + default: _readPixel1 = readPixel32; break; + } + switch (gs.DISPFB[1].psm) { + case 0x2: _readPixel2 = readPixel16to32; break; + case 0xA: _readPixel2 = readPixel16Sto32; break; + default: _readPixel2 = readPixel32; break; + } + + xinc1 = (gs.DISPLAY[0].w << 16) / dw; + yinc1 = (gs.DISPLAY[0].h << 16) / dh; + + ypos1 = gs.DISPLAY[0].y<<16; + + xinc2 = (gs.DISPLAY[1].w << 16) / dw; + yinc2 = (gs.DISPLAY[1].h << 16) / dh; + + ypos2 = gs.DISPLAY[1].y<<16; + +// if (gs.PMODE.alp) alpha = gs.PMODE.alp; + alpha = 0x80; + + for (y=0; y>16, ypos1>>16, gs.DISPFB[0].fbp, gs.DISPFB[0].fbw); + r1 = (c1 >> 16) & 0xff; + g1 = (c1 >> 8) & 0xff; + b1 = (c1 ) & 0xff; + c2 = _readPixel2(xpos2>>16, ypos2>>16, gs.DISPFB[1].fbp, gs.DISPFB[1].fbw); + r2 = (c2 >> 16) & 0xff; + g2 = (c2 >> 8) & 0xff; + b2 = (c2 ) & 0xff; + + r1 = ((r1 * alpha) + (r2 * (0xff - alpha))) / alpha; + g1 = ((g1 * alpha) + (g2 * (0xff - alpha))) / alpha; + b1 = ((b1 * alpha) + (b2 * (0xff - alpha))) / alpha; + if (r1 > 0xff) r1 = 0xff; + if (g1 > 0xff) g1 = 0xff; + if (b1 > 0xff) b1 = 0xff; + + *pscr++= ((b1 >> 3) << 10) | /* 0x7c00 */ + ((g1 >> 3) << 5) | /* 0x03e0 */ + ((r1 >> 3) ); /* 0x001f */ + xpos1+= xinc1; + xpos2+= xinc2; + } + ypos1+= yinc1; + ypos2+= yinc2; + } +} + +void ScrBlitMerge16(u8 *scr, int dw, int dh, int sp) { + u32 (*_readPixel1)(int x, int y, u32 bp, u32 bw); + u32 (*_readPixel2)(int x, int y, u32 bp, u32 bw); + u16 *pscr; + int x, y; + int xpos1, xinc1; + int ypos1, yinc1; + int xpos2, xinc2; + int ypos2, yinc2; + u32 alpha; + u32 c1, c2; + u32 r1,g1,b1; + u32 r2,g2,b2; + + switch (gs.DISPFB[0].psm) { + case 0x2: _readPixel1 = readPixel16to32; break; + case 0xA: _readPixel1 = readPixel16Sto32; break; + default: _readPixel1 = readPixel32; break; + } + switch (gs.DISPFB[1].psm) { + case 0x2: _readPixel2 = readPixel16to32; break; + case 0xA: _readPixel2 = readPixel16Sto32; break; + default: _readPixel2 = readPixel32; break; + } + + xinc1 = (gs.DISPLAY[0].w << 16) / dw; + yinc1 = (gs.DISPLAY[0].h << 16) / dh; + + ypos1 = gs.DISPLAY[0].y<<16; + + xinc2 = (gs.DISPLAY[1].w << 16) / dw; + yinc2 = (gs.DISPLAY[1].h << 16) / dh; + + ypos2 = gs.DISPLAY[1].y<<16; + +// if (gs.PMODE.alp) alpha = gs.PMODE.alp; + alpha = 0x80; + + for (y=0; y>16, ypos1>>16, gs.DISPFB[0].fbp, gs.DISPFB[0].fbw); + r1 = (c1 >> 16) & 0xff; + g1 = (c1 >> 8) & 0xff; + b1 = (c1 ) & 0xff; + c2 = _readPixel2(xpos2>>16, ypos2>>16, gs.DISPFB[1].fbp, gs.DISPFB[1].fbw); + r2 = (c2 >> 16) & 0xff; + g2 = (c2 >> 8) & 0xff; + b2 = (c2 ) & 0xff; + + r1 = ((r1 * alpha) + (r2 * (0xff - alpha))) / alpha; + g1 = ((g1 * alpha) + (g2 * (0xff - alpha))) / alpha; + b1 = ((b1 * alpha) + (b2 * (0xff - alpha))) / alpha; + if (r1 > 0xff) r1 = 0xff; + if (g1 > 0xff) g1 = 0xff; + if (b1 > 0xff) b1 = 0xff; + + *pscr++= ((b1 >> 3) << 11) | /* 0xf800 */ + ((g1 >> 2) << 5) | /* 0x07e0 */ + ((r1 >> 3) ); /* 0x001f */ + xpos1+= xinc1; + xpos2+= xinc2; + } + ypos1+= yinc1; + ypos2+= yinc2; + } +} + +void ScrBlitMerge32(u8 *scr, int dw, int dh, int sp) { + u32 (*_readPixel1)(int x, int y, u32 bp, u32 bw); + u32 (*_readPixel2)(int x, int y, u32 bp, u32 bw); + u8 *pscr; + int x, y; + int xpos1, xinc1; + int ypos1, yinc1; + int xpos2, xinc2; + int ypos2, yinc2; + u32 alpha; + u32 c1, c2; + u32 r1,g1,b1; + u32 r2,g2,b2; + + switch (gs.DISPFB[0].psm) { + case 0x2: _readPixel1 = readPixel16to32; break; + case 0xA: _readPixel1 = readPixel16Sto32; break; + default: _readPixel1 = readPixel32; break; + } + switch (gs.DISPFB[1].psm) { + case 0x2: _readPixel2 = readPixel16to32; break; + case 0xA: _readPixel2 = readPixel16Sto32; break; + default: _readPixel2 = readPixel32; break; + } + + xinc1 = (gs.DISPLAY[0].w << 16) / dw; + yinc1 = (gs.DISPLAY[0].h << 16) / dh; + + ypos1 = gs.DISPLAY[0].y<<16; + + xinc2 = (gs.DISPLAY[1].w << 16) / dw; + yinc2 = (gs.DISPLAY[1].h << 16) / dh; + + ypos2 = gs.DISPLAY[1].y<<16; + +// if (gs.PMODE.alp) alpha = gs.PMODE.alp; + alpha = 0x80; + + for (y=0; y>16, ypos1>>16, gs.DISPFB[0].fbp, gs.DISPFB[0].fbw); + r1 = (c1 >> 16) & 0xff; + g1 = (c1 >> 8) & 0xff; + b1 = (c1 ) & 0xff; + c2 = _readPixel2(xpos2>>16, ypos2>>16, gs.DISPFB[1].fbp, gs.DISPFB[1].fbw); + r2 = (c2 >> 16) & 0xff; + g2 = (c2 >> 8) & 0xff; + b2 = (c2 ) & 0xff; + + r1 = ((r1 * alpha) + (r2 * (0xff - alpha))) / alpha; + g1 = ((g1 * alpha) + (g2 * (0xff - alpha))) / alpha; + b1 = ((b1 * alpha) + (b2 * (0xff - alpha))) / alpha; + if (r1 > 0xff) r1 = 0xff; + if (g1 > 0xff) g1 = 0xff; + if (b1 > 0xff) b1 = 0xff; + + pscr[0] = r1; + pscr[1] = g1; + pscr[2] = b1; + pscr+=4; + xpos1+= xinc1; + xpos2+= xinc2; + } + ypos1+= yinc1; + ypos2+= yinc2; + } +} + + +void ScrBlit(SDL_Surface *dst, int y) { + Rect gsScr; + + if (showfullvram) { + if (gs.PMODE.en[0]) { + gsScr.x = 0; + gsScr.y = 0; + gsScr.w = gs.DISPFB[0].fbw; + gsScr.h = gs.DISPFB[0].fbh; + + _ScrBlit((u8*)dst->pixels + y * dst->pitch, dst->w, dst->h-y, dst->pitch, &gsScr, gs.DISPFB[0].psm, 0, gs.DISPFB[0].fbw); + } else + if (gs.PMODE.en[1]) { + gsScr.x = 0; + gsScr.y = 0; + gsScr.w = gs.DISPFB[1].fbw; + gsScr.h = gs.DISPFB[1].fbh; + + _ScrBlit((u8*)dst->pixels + y * dst->pitch, dst->w, dst->h-y, dst->pitch, &gsScr, gs.DISPFB[1].psm, 0, gs.DISPFB[1].fbw); + } + return; + } + + if (gs.PMODE.en[0] && gs.PMODE.en[1]) { + _ScrBlitMerge((u8*)dst->pixels + y * dst->pitch, dst->w, dst->h-y, dst->pitch); + return; + } + + if (gs.PMODE.en[0]) { + gsScr.x = gs.DISPLAY[0].x; + gsScr.y = gs.DISPLAY[0].y; + gsScr.w = gs.DISPLAY[0].w; + gsScr.h = gs.DISPLAY[0].h; + _ScrBlit((u8*)dst->pixels + y * dst->pitch, dst->w, dst->h-y, dst->pitch, &gsScr, gs.DISPFB[0].psm, gs.DISPFB[0].fbp, gs.DISPFB[0].fbw); + } + + if (gs.PMODE.en[1]) { + gsScr.x = gs.DISPLAY[1].x; + gsScr.y = gs.DISPLAY[1].y; + gsScr.w = gs.DISPLAY[1].w; + gsScr.h = gs.DISPLAY[1].h; + _ScrBlit((u8*)dst->pixels + y * dst->pitch, dst->w, dst->h-y, dst->pitch, &gsScr, gs.DISPFB[1].psm, gs.DISPFB[1].fbp, gs.DISPFB[1].fbw); + } +} + + +void SETScrBlit(int bpp) { + switch (bpp) { + case 15: + _ScrBlit = ScrBlit15; + _ScrBlitMerge = ScrBlitMerge15; + break; + case 16: + _ScrBlit = ScrBlit16; + _ScrBlitMerge = ScrBlitMerge16; + break; + case 32: + _ScrBlit = ScrBlit32; + _ScrBlitMerge = ScrBlitMerge32; + break; + } +} diff --git a/plugins/gs/GSsoft/Src/Draw.h b/plugins/gs/GSsoft/Src/Draw.h new file mode 100644 index 0000000000..9c54f30757 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Draw.h @@ -0,0 +1,36 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __DRAW_H__ +#define __DRAW_H__ + +#include "GS.h" + +void SETScrBlit(int bpp); +void ScrBlit(SDL_Surface *dst, int y); + +#endif /* __DRAW_H__ */ + + + + + + + + + diff --git a/plugins/gs/GSsoft/Src/GS.c b/plugins/gs/GSsoft/Src/GS.c new file mode 100644 index 0000000000..766add4b02 --- /dev/null +++ b/plugins/gs/GSsoft/Src/GS.c @@ -0,0 +1,825 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Rec.h" +#include "Page.h" +#include "Transfer.h" +#include "Cache.h" +#include "Regs.h" +#if defined(__i386__) || defined(__x86_64__) +#include "ix86.h" +#endif + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +char *codeclist[] = { "MPEG1", /*"DIVX", "MPEG2",*/ NULL }; +char *filterslist[] = { "Disabled", "Scale2x", NULL }; + + +const unsigned char version = PS2E_GS_VERSION; +const unsigned char revision = 1; // revision and build gives plugin version +const unsigned char build = 0; + +static char *libraryName = "GSsoft Plugin"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +#ifdef __WIN32__ + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} + +#endif + +#ifdef GS_LOG +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.log || gsLog == NULL) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} +#endif + +void gsSetCtxt(int ctxt) { + if (gs.ctxt == ctxt) return; + gs.ctxt = ctxt; + +#ifdef GS_LOG + GS_LOG("gsSetCtxt %d\n", ctxt); +#endif + offset = &gs._offset[ctxt]; + test = &gs._test[ctxt]; + scissor = &gs._scissor[ctxt]; + tex0 = &gs._tex0[ctxt]; + tex1 = &gs._tex1[ctxt]; + tex2 = &gs._tex2[ctxt]; + clamp = &gs._clamp[ctxt]; + miptbp0 = &gs._miptbp0[ctxt]; + miptbp1 = &gs._miptbp1[ctxt]; + gsfb = &gs._gsfb[ctxt]; + alpha = &gs._alpha[ctxt]; + zbuf = &gs._zbuf[ctxt]; + fba = &gs._fba[ctxt]; +/* fBuf = vRam + gsfb->fbp * 4; + fBufUS = (u16*)fBuf; + fBufUL = (u32*)fBuf; + zBuf = vRam + zbuf->zbp * 4; + zBufUS = (u16*)zBuf; + zBufUL = (u32*)zBuf; + tBuf = vRam + (tex0->tbp0 & ~0x1f) * 256; + tBufUS = (u16*)tBuf; + tBufUL = (u32*)tBuf; + cBuf = vRam + (tex0->cbp & ~0x1f) * 256; + cBufUS = (u16*)cBuf; + cBufUL = (u32*)cBuf;*/ +} + +void GSreset() { + dBuf = vRam; + dBufUL = vRamUL; + + memset(&gs, 0, sizeof(gs)); + + gs.DISPLAY[0].w = 640; + gs.DISPLAY[0].h = 480; + gs.DISPLAY[1].w = 640; + gs.DISPLAY[1].h = 480; + + gs.DISPFB[0].fbw = 640; + gs.DISPFB[0].fbh = (1024*1024) / gs.DISPFB[0].fbw; + gs.DISPFB[1].fbw = 640; + gs.DISPFB[1].fbh = (1024*1024) / gs.DISPFB[1].fbw; + + gs._gsfb[0].fbw = 640; + gs._gsfb[0].fbh = (1024*1024) / gs._gsfb[0].fbw; + gs._gsfb[1].fbw = 640; + gs._gsfb[1].fbh = (1024*1024) / gs._gsfb[1].fbw; + + gs._scissor[0].x1 = 639; + gs._scissor[0].y1 = 479; + gs._scissor[1].x1 = 639; + gs._scissor[1].y1 = 479; + gs.ctxt = -1; + + gsSetCtxt(0); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.primC = 0; + + gs._tex0[0].tbw = 64; + gs._tex0[1].tbw = 64; + + gs.CSRr = 0x55190000; +} + +void *_align16(void *ptr) { + return (void*)(((uptr)ptr+0x10) & ~0xf); +} + +s32 CALLBACK GSinit() { +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog) setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + + _vRam = (u8*)malloc(4*1024*1024); vRam = _align16(_vRam); + if (vRam == NULL) return -1; + + vRamUS = (u16*)vRam; + vRamUL = (u32*)vRam; + + GSreset(); + norender = 0; +#ifdef GS_LOG + GS_LOG("GSinit ok\n"); +#endif + + return 0; +} + +void CALLBACK GSshutdown() { + free(_vRam); +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +s32 CALLBACK GSopen(void *pDsp, char *Title) { + s32 dsp; + +#ifdef GS_LOG + GS_LOG("GSopen\n"); +#endif + + LoadConfig(); + + strcpy(GStitle, Title); + + dsp = DXopen(); + if (dsp == 0) return -1; + *(s32*)pDsp = dsp; + + if (conf.record) recOpen(); + if (conf.cache) if (CacheInit() == -1) return -1; + + DXsetGSmode(640, gs.SYNCV.vfp & 1 ? gs.SYNCV.vdp : gs.SYNCV.vdp/2); + +#ifdef GS_LOG + GS_LOG("GSopen ok\n"); +#endif + + return 0; +} + +void CALLBACK GSclose() { + DXclose(); + + if (conf.record) recClose(); + if (conf.cache) CacheShutdown(); + +#ifdef __WIN32__ + DestroyWindow(GShwnd); +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSmakeSnapshot(char *path) { + FILE *bmpfile; + char filename[256]; + unsigned char header[0x36]; + long size; + unsigned char line[1024*3]; + int w,h; + short i,j; + unsigned char empty[2]={0,0}; + u32 color; + u32 snapshotnr = 0; + +// w = dispfb->fbw; +// h = dispfb->fbh - 20; + size = w*h*3 + 0x38; + + // fill in proper values for BMP + + // hardcoded BMP header + memset(header,0,0x36); + header[0]='B'; + header[1]='M'; + header[2]=size&0xff; + header[3]=(size>>8)&0xff; + header[4]=(size>>16)&0xff; + header[5]=(size>>24)&0xff; + header[0x0a]=0x36; + header[0x0e]=0x28; + header[0x12]=w%256; + header[0x13]=w/256; + header[0x16]=h%256; + header[0x17]=h/256; + header[0x1a]=0x01; + header[0x1c]=0x18; + header[0x26]=0x12; + header[0x27]=0x0B; + header[0x2A]=0x12; + header[0x2B]=0x0B; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.bmp", path, snapshotnr); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) + return; + + fwrite(header,0x36,1,bmpfile); + for(i=h-1;i>=0;i--) { + for(j=0;jfbw); + line[j*3+2]=(color )&0xff; + line[j*3+1]=(color>> 8)&0xff; + line[j*3+0]=(color>>16)&0xff; + } + fwrite(line,w*3,1,bmpfile); + } + fwrite(empty,0x2,1,bmpfile); + fclose(bmpfile); +} + +void CALLBACK GSvsync() { +#ifdef GS_LOG + GS_LOG("\nGSvsync\n\n"); +#endif + gs.interlace = 1 - gs.interlace; + + DXupdate(); + + ppf = 0; + bpf = 0; +} + +#define _FBmoveImage(spsm, dpsm) { \ + int x, y; \ + u32 pixel; \ + if (s->x < d->x) { \ + for(y=0; y=0; x--) { \ + pixel = readPixel##spsm(s->x + x, s->y + y, gs.srcbuf.bp, gs.srcbuf.bw); \ + writePixel##dpsm(d->x + x, d->y + y, pixel, gs.dstbuf.bp, gs.dstbuf.bw); \ + } \ + } \ + } else { \ + for(y=0; yx + x, s->y + y, gs.srcbuf.bp, gs.srcbuf.bw); \ + writePixel##dpsm(d->x + x, d->y + y, pixel, gs.dstbuf.bp, gs.dstbuf.bw); \ + } \ + } \ + } \ +} + +#define __FBmoveImage(bpp) \ +void FBmoveImage##bpp##to32(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 32); } \ +void FBmoveImage##bpp##to24(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 24); } \ +void FBmoveImage##bpp##to16(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 16); } \ +void FBmoveImage##bpp##to16S(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 16S); } \ +void FBmoveImage##bpp##to8(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 8); } \ +void FBmoveImage##bpp##to4(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 4); } \ +void FBmoveImage##bpp##to8H(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 8H); } \ +void FBmoveImage##bpp##to4HL(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 4HL); } \ +void FBmoveImage##bpp##to4HH(Point *s, Point *d, int w, int h) { _FBmoveImage(bpp, 4HH); } + +__FBmoveImage(32); +__FBmoveImage(24); +__FBmoveImage(16); +__FBmoveImage(16S); +__FBmoveImage(8); +__FBmoveImage(4); +__FBmoveImage(8H); +__FBmoveImage(4HL); +__FBmoveImage(4HH); + +#define _FBmoveImageTO(bpp) \ + switch (gs.srcbuf.psm) { \ + case 0x0: FBmoveImage32to##bpp(&s, &d, w, h); return; \ + case 0x1: FBmoveImage24to##bpp(&s, &d, w, h); return; \ + case 0x2: FBmoveImage16to##bpp(&s, &d, w, h); return; \ + case 0xA: FBmoveImage16to##bpp(&s, &d, w, h); return; \ + case 0x13: FBmoveImage8to##bpp(&s, &d, w, h); return; \ + case 0x14: FBmoveImage4to##bpp(&s, &d, w, h); return; \ + case 0x1B: FBmoveImage8Hto##bpp(&s, &d, w, h); return; \ + case 0x24: FBmoveImage4HLto##bpp(&s, &d, w, h); return; \ + case 0x2C: FBmoveImage4HHto##bpp(&s, &d, w, h); return; \ + } + +void FBmoveImage() { + Point s, d; + int sw, sh, dw, dh; + int w, h; + + s.x = gs.trxpos.sx; + s.y = gs.trxpos.sy; + d.x = gs.trxpos.dx; + d.y = gs.trxpos.dy; + sw = dw = gs.imageW; + sh = dh = gs.imageH; + + if (d.x >= gs.dstbuf.bw || d.y >= gs.dstbuf.bh) return; + if (s.x >= gs.srcbuf.bw || s.y >= gs.srcbuf.bh) return; + + if ((d.x + dw) < 0 || (d.y + dh) < 0) return; + if ((s.x + sw) < 0 || (s.y + sh) < 0) return; + + if (d.x < 0) { dw-= -d.x; d.x = 0; } + if (d.y < 0) { dh-= -d.y; d.y = 0; } + + if (s.x < 0) { sw-= -s.x; s.x = 0; } + if (s.y < 0) { sh-= -s.y; s.y = 0; } + + if ((d.x + dw) > gs.dstbuf.bw) dw = gs.dstbuf.bw; + if ((d.y + dh) > gs.dstbuf.bh) dh = gs.dstbuf.bh; + + if ((s.x + sw) > gs.srcbuf.bw) sw = gs.srcbuf.bw; + if ((s.y + sh) > gs.srcbuf.bh) sh = gs.srcbuf.bh; + + w = min(dw, sw); + h = min(dh, sh); + + switch (gs.dstbuf.psm) { + case 0x0: _FBmoveImageTO(32); break; + case 0x1: _FBmoveImageTO(24); break; + case 0x2: _FBmoveImageTO(16); break; + case 0xA: _FBmoveImageTO(16S); break; + case 0x13: _FBmoveImageTO(8); break; + case 0x14: _FBmoveImageTO(4); break; + case 0x1B: _FBmoveImageTO(8H); break; + case 0x24: _FBmoveImageTO(4HL); break; + case 0x2C: _FBmoveImageTO(4HH); break; + } + + printf("invalid FBmoveImage psm configuraton: %x to %x\n", gs.dstbuf.psm, gs.srcbuf.psm); +} + +u32 primP[2]; + +void GIFtag(pathInfo *path, u32 *data) { + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + path->tag.pre = (data[1] >> 14) & 0x1; + path->tag.prim = (data[1] >> 15) & 0x7ff; + path->tag.flg = (data[1] >> 26) & 0x3; + path->tag.nreg = data[1] >> 28; + if (path->tag.nreg == 0) path->tag.nreg = 16; + +#ifdef GS_LOG + GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", + data[3], data[2], data[1], data[0], + path->tag.eop, path->tag.nloop, path->tag.flg, path->tag.nreg, path->tag.pre); +#endif + + switch (path->tag.flg) { + case 0x0: + gs.regs = *(u64 *)(data+2); + gs.regn = 0; + path->mode = 1; + if (path->tag.pre) { + primP[0] = path->tag.prim; + primP[1] = 0; + + GSwrite(primP, 0); + } + break; + + case 0x1: + gs.regs = *(u64 *)(data+2); + gs.regn = 0; + path->mode = 2; + break; + + case 0x3: + case 0x2: +// if (gs.dstbuf.bw == 0) printf("gs.dstbuf == 0!!!\n"); + if (gs.imageTransfer == 0x2) { +/*#ifdef GS_LOG + GS_LOG("moveImage %dx%d %dx%d %dx%d (dir=%d)\n", + gs.trxpos.sx, gs.trxpos.sy, gs.trxpos.dx, gs.trxpos.dy, gs.imageW, gs.imageH, gs.trxpos.dir); +#endif + FBmoveImage();*/ + break; + } + path->mode = 3; +#ifdef GS_LOG + GS_LOG("imageTransfer size %lx, %dx%d %dx%d (psm=%x, bp=%x)\n", + path->tag.nloop, gs.trxpos.dx, gs.trxpos.dy, gs.imageW, gs.imageH, gs.dstbuf.psm, gs.dstbuf.bp); +#endif + break; + } +} + + +void GIFprocessReg(u32 *data, int reg) { + u32 out[2]; +// GS_LOG("GIFprocessReg %d %8.8x_%8.8x_%8.8x_%8.8x\n", reg, data[3], data[2], data[1], data[0]); + + switch (reg) { + case 0x0: // prim + out[0] = data[0]; + GSwrite(out, 0x0); + break; + + case 0x1: // rgbaq + out[0] = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + out[1] = gs.q; + GSwrite(out, 0x1); + break; + + case 0x2: // st + GSwrite(data, 0x2); + out[0] = gs.rgba; + out[1] = data[2]; + GSwrite(out, 0x1); + break; + + case 0x3: // uv + out[0] = (data[0] & 0x7fff) | + ((data[1] & 0x7fff) << 16); + GSwrite(out, 0x3); + break; + + case 0x4: // xyzf2 + out[0] = (data[0] & 0xffff) | + ((data[1] & 0xffff) << 16); + out[1] = ((data[2] >> 4) & 0xffffff) | + ((data[3] & 0xff0) << 20); + if ((data[3] >> 15) & 0x1) + GSwrite(out, 0xc); + else GSwrite(out, 0x4); + break; + + case 0x5: //xyz2 + out[0] = (data[0] & 0xffff) | + ((data[1] & 0xffff) << 16); + out[1] = data[2]; + if ((data[3] >> 15) & 0x1) + GSwrite(out, 0xd); + else GSwrite(out, 0x5); + break; + + case 0xe: // ad + GSwrite(data, data[2] & 0xff); + break; + + case 0xf: // nop + break; + + default: +#ifdef GS_LOG + GS_LOG("UNHANDLED GIFprocessReg %d %8.8x_%8.8x_%8.8x_%8.8x\n", reg, data[3], data[2], data[1], data[0]); +// GS_LOG("UNHANDLED %x!!!\n",reg); +#endif +// printf("UNHANDLED GIFprocessReg %d %8.8x_%8.8x_%8.8x_%8.8x\n", reg, data[3], data[2], data[1], data[0]); + GSwrite(data, reg); + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + int reg = (int)((gs.regs >> (gs.regn*4)) & 0xf); + + GIFprocessReg(pMem, reg); + gs.regn++; + if (path->tag.nreg == gs.regn) { + gs.regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((gs.regs >> (gs.regn*4)) & 0xf); + GSwrite(pMem, reg); + gs.regn++; + if (path->tag.nreg == gs.regn) { + gs.regn = 0; + path->tag.nloop--; + } +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) { + + while (size > 0) { + switch (path->mode) { + case 0: /* GIF TAG */ +/* if (path->tag.eop == 1) { + path->tag.eop = 0; + return; + }*/ + GIFtag(path, pMem); pMem+= 4; size--; + break; + + case 1: /* GIF PACKET */ + while (size > 0 && path->tag.nloop > 0) { + _GSgifPacket(path, pMem); + pMem+= 4; size--; + } + if (path->tag.nloop == 0 && + path->mode == 1) path->mode = 0; + break; + + case 2: /* GIF REGLIST */ + size*= 2; + while (size > 0 && path->tag.nloop > 0) { + _GSgifRegList(path, pMem); + pMem+= 2; size--; + } + if (size & 0x1) pMem+= 2; + size/= 2; + if (path->tag.nloop == 0 && + path->mode == 2) path->mode = 0; + break; + + case 3: /* GIF IMAGE */ + if (size < path->tag.nloop) { + FBtransferImage(pMem, size); + path->tag.nloop-= size; + return; + } else { + FBtransferImage(pMem, path->tag.nloop); + pMem+= path->tag.nloop*4; size-= path->tag.nloop; + path->tag.nloop = 0; path->mode = 0; + } + break; + + case 4: /* GIF IMAGE (FROM VRAM) */ +// if (size < path->tag.nloop) { + FBtransferImageSrc(pMem, size); + pMem+= size*4; path->tag.nloop-= size; + size = 0; path->mode = 0; +/* } else { + FBtransferImageSrc(pMem, path->tag.nloop); + pMem+= path->tag.nloop*4; size-= path->tag.nloop; + path->tag.nloop = 0; path->mode = 0; + }*/ + break; + } + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) { +#if defined(__i386__) || defined(__x86_64__) + u64 tick; + + tick = GetCPUTick(); +#endif + +#ifdef GS_LOG + GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); +#endif + + _GSgifTransfer(&gs.path2, pMem, size); + +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) { +#if defined(__i386__) || defined(__x86_64__) + u64 tick; + + tick = GetCPUTick(); +#endif + +#ifdef GS_LOG + GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); +#endif + + _GSgifTransfer(&gs.path3, pMem, size); + +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif +} + +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) { + u32 *data; + pathInfo *path = &gs.path1; +#if defined(__i386__) || defined(__x86_64__) + u64 tick; + + tick = GetCPUTick(); +#endif + + +#ifdef GS_LOG + GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); +#endif + + path->tag.eop = 0; + path->mode = 0; + for (;;) { + data = ((u8*)pMem)+(addr&0x3fff); + switch (path->mode) { + case 0: /* GIF TAG */ + if (path->tag.eop == 1) { /*if (addr > 0x4000) printf("meh %x\n", addr);*/ path->mode = 0; return; } + GIFtag(&gs.path1, data); addr+= 4*4; + if (path->tag.nloop == 0) { /*if (addr > 0x4000) printf("meh %x\n", addr);*/ path->mode = 0; return; } + break; + + case 1: /* GIF PACKET */ + _GSgifPacket(&gs.path1, data); + addr+= 4*4; + if (path->tag.nloop == 0 && + path->mode == 1) path->mode = 0; + break; + + case 2: /* GIF REGLIST */ + _GSgifRegList(&gs.path1, data); + addr+= 2*4; + if (path->tag.nloop == 0 && + path->mode == 2) { + if (addr & 2) addr+= 2*4; + path->mode = 0; + } + break; + + case 3: /* GIF IMAGE */ + FBtransferImage(pMem, 1); + addr+= 4*4; path->tag.nloop-= 1; + if (path->tag.nloop == 0) path->mode = 0; + break; + } + } +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif +} + +void CALLBACK GSreadFIFO(u64 *pMem) { +#if defined(__i386__) || defined(__x86_64__) + u64 tick; + + tick = GetCPUTick(); +#endif + +#ifdef GS_LOG + GS_LOG("GSreadFIFO\n"); +#endif + + FBtransferImageSrc(pMem, 1); + +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif +} + +#if 0 +void CALLBACK GSgifTransfer64(u32 *pMem) { +#ifdef GS_LOG + GS_LOG("GSgifTransfer64 (mode %d)\n", gs.gifMode); +#endif + GS_LOG("GSgifTransfer64 %8.8x+%8.8x\n", pMem[1], pMem[0]); + + switch (gs.gifMode) { + case 0: /* GIF TAG */ + printf("GIFTAG over Transfer64!!\n"); +// GIFtag(pMem); pMem+= 4; size--; + break; + + case 1: /* GIF PACKET */ + if (gs.buffsize == 1) { + gs.buffsize = 0; + memcpy(&gs.buff[1], pMem, 2*4); + _GSgifPacket((u32*)gs.buff); + } else { + gs.buffsize = 1; + memcpy(&gs.buff[0], pMem, 2*4); + } + break; + + case 2: /* GIF REGLIST */ + _GSgifRegList(pMem); + break; + + case 3: /* GIF IMAGE */ +/* if (size < gs.gtag.nloop) { + FBtransferImage(pMem, size); + gs.gtag.nloop-= size; + return; + } else { + FBtransferImage(pMem, gs.gtag.nloop); + pMem+= gs.gtag.nloop*4; size-= gs.gtag.nloop; + gs.gtag.nloop = 0; gs.gifMode = 0; + } +*/ break; + + case 4: /* GIF IMAGE (FROM VRAM) */ +// if (size < gs.gtag.nloop) { +/* FBtransferImageSrc(pMem, size); + pMem+= size*4; gs.gtag.nloop-= size; + size = 0; gs.gifMode = 0;*/ +/* } else { + FBtransferImageSrc(pMem, gs.gtag.nloop); + pMem+= gs.gtag.nloop*4; size-= gs.gtag.nloop; + gs.gtag.nloop = 0; gs.gifMode = 0; + }*/ + break; + } +} +#endif + +typedef struct { + u8 id[32]; + u8 vRam[4*1024*1024]; + GSinternal gs; +} GSfreezeData; + +s32 CALLBACK GSfreeze(int mode, freezeData *data) { + GSfreezeData *gsd; + + if (mode == FREEZE_LOAD) { + gsd = (GSfreezeData*)data->data; + if (data->size != sizeof(GSfreezeData)) { + SysMessage("GSsoft: freeze data size incorrect, %d != %d\n", data->size, sizeof(GSfreezeData)); + return 0; +// return -1; + } + if (strcmp(gsd->id, libraryName)) { + SysMessage("GSsoft: freeze data incorrect plugin\n"); + return -1; + } + memcpy(vRam, gsd->vRam, 4*1024*1024); + memcpy(&gs, &gsd->gs, sizeof(GSinternal)); + } else + if (mode == FREEZE_SAVE) { + data->size = sizeof(GSfreezeData); + gsd = (GSfreezeData*)data->data; + strcpy(gsd->id, libraryName); + memcpy(gsd->vRam, vRam, 4*1024*1024); + memcpy(&gsd->gs, &gs, sizeof(GSinternal)); + } + if (mode == FREEZE_SIZE) { + data->size = sizeof(GSfreezeData); + } + + return 0; +} + diff --git a/plugins/gs/GSsoft/Src/GS.h b/plugins/gs/GSsoft/Src/GS.h new file mode 100644 index 0000000000..38fd0a3005 --- /dev/null +++ b/plugins/gs/GSsoft/Src/GS.h @@ -0,0 +1,575 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __GS_H__ +#define __GS_H__ + +#include +#include + +#define GSdefs +#include "PS2Edefs.h" + +#ifdef __WIN32__ + +#include +#include + +HWND GShwnd; + +#else + +#include +#include +#include +#include + +#define __inline inline + +typedef int BOOL; + +//#define TRUE 1 +//#define FALSE 0 + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#endif + +///////////////////// + +#ifndef _RELEASE +#define GS_LOG __Log +#endif + +char GStitle[256]; + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +typedef struct { + int width; + int height; + int bpp; +} DXmode; + +typedef struct { + DXmode fmode; + DXmode wmode; + int fullscreen; + int fps; + int frameskip; + int record; + int cache; + int cachesize; + int codec; + int filter; +#ifdef GS_LOG + u32 log; +#endif + int dumptexts; +} GSconf; + +typedef struct { + int x, y, f; + u32 z; + int u, v; + u32 s, t, q; + u32 rgba; +} Vertex; + +DXmode modes[64]; +DXmode *cmode; +GSconf conf; +int norender; +int wireframe; +int showfullvram; +int fpspos; +int fpspress; +int ppf; +int bpf; +u64 gsticks; + +u8 *vRam; // Video Ram +u16 *vRamUS; +u32 *vRamUL; +u8 *_vRam; + +u8 *fBuf; // Frame Buffer +u16 *fBufUS; +u32 *fBufUL; + +u8 *dBuf; // Display Buffer +u16 *dBufUS; +u32 *dBufUL; + +u8 *zBuf; // Z Buffer +u16 *zBufUS; +u32 *zBufUL; + +u8 *iBuf; // Image Buffer +u16 *iBufUS; +u32 *iBufUL; + +u8 *tBuf; // Texture Buffer +u16 *tBufUS; +u32 *tBufUL; + +u8 *cBuf; // Clut Buffer +u16 *cBufUS; +u32 *cBufUL; + +extern char *codeclist[]; +extern char *filterslist[]; + +typedef struct { + int n; + int x, y; +} Block; + +typedef struct { + int nloop; + int eop; + int flg; + int nreg; + int prim; + int pre; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* privileged regs structs */ + + +typedef struct { + u32 fbp; + int fbw; + int fbh; + int psm; + int dbx; + int dby; +} dispfbInfo; + +typedef struct { + int inter; + int ffmd; + int dpms; +} smode2Info; + +typedef struct { + int rc; + int lc; + int t1248; + int slck; + int cmod; + int ex; + int prst; + int sint; + int xpck; + int pck2; + int spml; + int gcont; + int phs; + int pvs; + int pehs; + int pevs; + int clksel; + int nvck; + int slck2; + int vcksel; + int vhp; +} smode1Info; + +typedef struct { + int hfp; + int fbp; + int hseq; + int hsvs; + int hs; +} synch1Info; + +typedef struct { + int hb; + int hf; +} synch2Info; + +typedef struct { + int vfp; + int vfpe; + int vbp; + int vbpe; + int vdp; + int vs; +} syncvInfo; + +typedef struct { + int en[2]; + int crtmd; + int mmod; + int amod; + int slbg; + u32 alp; +} pmodeInfo; + +typedef struct { + u32 exbp; + u32 exbw; + int fbin; + int wffmd; + int emoda; + int emodc; + int wdx; + int wdy; +} extbufInfo; + +typedef struct { + u32 sigid; + u32 lblid; +} siglblidInfo; + +/* general purpose regs structs */ + +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + int fbm; +} frameInfo; + +frameInfo *gsfb; +Point *offset; +Rect2 *scissor; + +typedef struct { + int prim; + int iip; + int tme; + int fge; + int abe; + int aa1; + int fst; + int ctxt; + int fix; +} primInfo; + +primInfo *prim; + +typedef struct { + int ate; + int atst; + u32 aref; + int afail; + int date; + int datm; + int zte; + int ztst; +} pixTest; + +pixTest *test; + +#define ZTST_NEVER 0 +#define ZTST_ALWAYS 1 +#define ZTST_GEQUAL 2 +#define ZTST_GREATER 3 + +#define ATST_NEVER 0 +#define ATST_ALWAYS 1 +#define ATST_LESS 2 +#define ATST_LEQUAL 3 +#define ATST_EQUAL 4 +#define ATST_GEQUAL 5 +#define ATST_GREATER 6 +#define ATST_NOTEQUAL 7 + +#define AFAIL_KEEP 0 +#define AFAIL_FB_ONLY 1 +#define AFAIL_ZB_ONLY 2 +#define AFAIL_RGB_ONLY 3 + + +typedef struct { + int bp; + int bw; + int bh; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int psm; + int tw, th; + int tcc; + int tfx; + int cbp; + int cpsm; + int csm; +} tex0Info; + +tex0Info *tex0; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +tex1Info *tex1; + +typedef struct { + int psm; + int cbp; + int cpsm; + int csm; + int csa; + int cld; +} tex2Info; + +tex2Info *tex2; + +typedef struct { + int u, v; +} uvInfo; + +typedef struct { + int s, t; +} stInfo; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +clampInfo *clamp; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +miptbpInfo *miptbp0; +miptbpInfo *miptbp1; + +typedef struct { + int ta[2]; + int aem; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + int a, b, c, d; + int fix; +} alphaInfo; + +alphaInfo *alpha; + +typedef struct { + int zbp; + int psm; + int zmsk; +} zbufInfo; + +zbufInfo *zbuf; + +typedef struct { + int fba; +} fbaInfo; + +fbaInfo *fba; + +typedef struct { + int mode; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + u32 q; + int primC; + int psm; + int prac; + int dthe; + int colclamp; + int fogf; + int fogcol; + int smask; + int pabe; + u64 regs; + int regn; + u64 buff[2]; + int buffsize; + int ctxt; + + pmodeInfo PMODE; + smode1Info SMODE1; + smode2Info SMODE2; + u64 SRFSH; + synch1Info SYNCH1; + synch2Info SYNCH2; + syncvInfo SYNCV; + dispfbInfo DISPFB[2]; + Rect DISPLAY[2]; + extbufInfo EXTBUF; + Rect EXTDATA; + u32 EXTWRITE; + u32 BGCOLOR; + u32 CSRr; + u32 CSRw; + u32 IMR; + u32 BUSDIR; + siglblidInfo SIGLBLID; + + frameInfo _gsfb[2]; + Point _offset[2]; + Rect2 _scissor[2]; + primInfo _prim[2]; + pixTest _test[2]; + bufInfo srcbuf; + bufInfo dstbuf; + tex0Info _tex0[2]; + tex1Info _tex1[2]; + tex2Info _tex2[2]; + uvInfo uv; + stInfo st; + clampInfo _clamp[2]; + clutInfo clut; + miptbpInfo _miptbp0[2]; + miptbpInfo _miptbp1[2]; + texaInfo texa; + trxposInfo trxpos; + alphaInfo _alpha[2]; + zbufInfo _zbuf[2]; + fbaInfo _fba[2]; + + int imageTransfer; + int imageX, imageY, imageW, imageH; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + + int interlace; +} GSinternal; + +GSinternal gs; + + +FILE *gsLog; + +#ifdef GS_LOG +#define RDWR_LOG /*if (conf.log & 0x00000001)*/ __Log +#define TRAN_LOG /*if (conf.log & 0x00000002)*/ __Log +#define PREG_LOG /*if (conf.log & 0x00000004)*/ __Log +#define GREG_LOG /*if (conf.log & 0x00000008)*/ __Log +#define PRIM_LOG /*if (conf.log & 0x00000010)*/ __Log +#define DRAW_LOG /*if (conf.log & 0x00000020)*/ __Log +#define WARN_LOG /*if (conf.log & 0x00000040)*/ __Log +#endif + +void __Log(char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +s32 DXopen(); +void DXclose(); +int DXsetGSmode(int w, int h); +void DXupdate(); +int DXgetModes(); +int DXgetDrvs(); +void DXclearScr(); + +void GSreset(); + +void (*GSirq)(); + +void *_align16(void *ptr); +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) << 16) \ + +void gsSetCtxt(int ctxt); +void FBmoveImage(); +u32 TextureSizeGS(int width, int height, int psm); + +#endif diff --git a/plugins/gs/GSsoft/Src/Linux-SDL/Conf.c b/plugins/gs/GSsoft/Src/Linux-SDL/Conf.c new file mode 100644 index 0000000000..33a89c6ccc --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux-SDL/Conf.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +#include "../../nsx2.h" +#include "../gs.h" +#include "../../iniapi/iniapi.h" + + +void SaveConfig() { + FILE *f; + char cfg[255]; + + sprintf (cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0x755); + sprintf (cfg, "%s/.PS2E/GSsoftx.cfg", getenv("HOME")); + f = fopen(cfg,"w"); + if (f == NULL) return; + fwrite(&conf, 1, sizeof(conf), f); + fclose(f); +} + +void LoadConfig() { + FILE *f; + char cfg[255]; + int result; + + memset(&conf, 0, sizeof(conf)); + + /* Read config File */ + result = getini(nSX2ConfigFile,"Video","Width",cfg); + if ( result == 0 ) conf.mode.width = 320; + else conf.mode.width = atoi ( cfg ); + + result = getini(nSX2ConfigFile,"Video","Height",cfg); + if ( result == 0 ) conf.mode.height = 240; + else conf.mode.height = atoi ( cfg ); + + result = getini(nSX2ConfigFile,"Video","Bpp",cfg); + if ( result == 0 ) conf.mode.bpp = 16; + else conf.mode.bpp = atoi ( cfg ); + + result = getini(nSX2ConfigFile,"Video","Stretch",cfg); + if ( result == 0 ) conf.stretch = 1; + else conf.stretch = atoi ( cfg ); + /* + conf.mode.width = 640; + conf.mode.height = 480; + conf.mode.bpp = 16; + conf.fullscreen = 0; + conf.stretch = 0; + */ + + conf.fullscreen = 0; + + sprintf (cfg, "%s/.PS2E/GSsoftx.cfg", getenv("HOME")); + f = fopen(cfg,"r"); + if (f == NULL) return; + fread(&conf, 1, sizeof(conf), f); + fclose(f); +} + diff --git a/plugins/gs/GSsoft/Src/Linux-SDL/X11.c b/plugins/gs/GSsoft/Src/Linux-SDL/X11.c new file mode 100644 index 0000000000..6d163a845d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux-SDL/X11.c @@ -0,0 +1,279 @@ +#include + +#include "../gs.h" +#include "../Draw.h" + + +SDL_Surface *display; +SDL_Surface *visual; +SDL_Surface* gc; + +int screen; +int depth; + +char *buffd; +SDL_Surface *buffer; + + +SDL_Surface * TextGC; +char *textd; + +SDL_Surface *text; + +static int ShowFullVRam=0; + +void (*ScrBlit) (char *, char *, Rect *, int); + +int DXinit = 0; + +int DXswitchScrMode() { + DXclose(); + conf.fullscreen = 1 - conf.fullscreen; + return DXopen(); +} + +void DXclearScr() { + if (conf.fullscreen) { + + } else { + memset(buffd, 0, conf.mode.width * conf.mode.height * 4); + + SDL_BlitSurface ( GShwnd , NULL , buffer, NULL ); + + } +} + +void DXupdScrBlit() { + //printf("DXupdScrBlit : %d s:%d\n",depth,conf.stretch); + switch (depth) { + case 15: + if (conf.stretch) ScrBlit = ScrBlit15S; + else ScrBlit = ScrBlit15; + break; + case 16: + if (conf.stretch) ScrBlit = ScrBlit16S; + else ScrBlit = ScrBlit16; + break; + case 24: + if (conf.stretch) ScrBlit = ScrBlit24S; + else ScrBlit = ScrBlit24; + break; + case 32: + if (conf.stretch) ScrBlit = ScrBlit32S; + else ScrBlit = ScrBlit32; + break; + } +} + +int DXopen() { + + + u32 rmask, gmask, bmask, amask; + + if (DXinit == 1) return 0; + + + + + //printf("DXopen : %d \n",conf.fullscreen); + + if (conf.fullscreen) { + + return -1; + + } else { + + + buffd = malloc(conf.mode.width * conf.mode.height * 4); + if (buffd == NULL) return -1; + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif + + depth = conf.mode.bpp; + + buffer = SDL_GetVideoSurface(); + + if ( buffer == NULL ) printf("DXopenError : Create buffer\n"); + //else printf("DXopenOK : Create buffer\n"); + + + } + + DXinit = 1; + + DXupdScrBlit(); + DXclearScr(); + + return 0; +} + +void DXclose() { + DXinit = 0; + + if (conf.fullscreen) { + + } else { + SDL_FreeSurface ( buffer ); + } +} + +#include +int fpspos; +int fpspress; + +void DXupdate() { + Rect gsScr; + static time_t to; + static int fpscount, fpsc, fc; + int lPitch; + char *sbuff; + + fc++; + + if (conf.fps || conf.frameskip) { + if (time(NULL) > to) { + time(&to); + fpsc = fpscount; + fpscount = 0; + } + fpscount++; + } + + if (conf.frameskip) { + if ((fpscount % 3) == 0) { + norender = 1; + } else if (norender) { + norender = 0; + return; + } + } + + if (conf.fullscreen) { + conf.fps = 0; + // sbuff = dgaDev->data; + // lPitch = dgaDev->mode.imageWidth * (dgaDev->mode.bitsPerPixel / 8); + + sbuff = buffer->pixels; + lPitch = buffer->pitch; + + } else { + //sbuff = buffd; + //lPitch = buffer->bytes_per_line; + sbuff = (char * )buffer->pixels; + lPitch = buffer->pitch ; + + } + + if (ShowFullVRam) { + gsScr.x = 0; + gsScr.y = 0; + gsScr.w = gsdspfb->fbw; + gsScr.h = gsdspfb->fbh; + + ScrBlit(sbuff, vRam, &gsScr, lPitch); + + } else { + gsScr.x = gsmode->x + gsdspfb->dbx; + gsScr.y = gsmode->y + gsdspfb->dby; + gsScr.w = gsmode->w; + gsScr.h = gsmode->h; + + + //SDL_LockSurface( buffer ); + ScrBlit(sbuff, dBuf, &gsScr, lPitch); + //SDL_UnlockSurface ( buffer ); + + + } + + if (conf.fps && conf.fullscreen == 0) { + char title[256]; + char tmp[256]; + + if (fpspos < 0) fpspos = 0; +#ifndef GS_LOG + if (fpspos > 4) fpspos = 4; +#else + if (fpspos > 5) fpspos = 5; +#endif + switch (fpspos) { + case 0: // FrameSkip + sprintf(tmp, "Frameskip %s", conf.frameskip == 1 ? "On" : "Off"); + norender = 0; + break; + case 1: // FullScreen + sprintf(tmp, "Fullscreen %s", conf.fullscreen == 1 ? "On" : "Off"); + break; + case 2: // Stretch + sprintf(tmp, "Stretch %s", conf.stretch == 1 ? "On" : "Off"); + break; + case 3: // Misc stuff + sprintf(tmp, "GSmode: %dx%d - FC: %d", gsmode->w, gsmode->h, fc); + break; + case 4: // ShowFullVRam + sprintf(tmp, "ShowFullVRam %s", ShowFullVRam == 1 ? "On" : "Off"); + break; +#ifdef GS_LOG + case 5: // Log + sprintf(tmp, "Log %s - FC: %d", Log == 1 ? "On" : "Off", fc); + break; +#endif + } + if (fpspress) { + switch (fpspos) { + case 0: + conf.frameskip = 1 - conf.frameskip; + break; + case 1: + DXswitchScrMode(); + fpspress = 0; + return; + case 2: + conf.stretch = 1 - conf.stretch; + DXupdScrBlit(); + DXclearScr(); + fpspress = 0; + return; + case 4: + DXclearScr(); + ShowFullVRam = 1 - ShowFullVRam; + break; +#ifdef GS_LOG + case 5: + Log = 1 - Log; + break; +#endif + } + fpspress = 0; + } + + sprintf (title," FPS %d -- %s", fpsc, tmp); + + + +// XPutImage(display, GShwnd, gc, text, 0, 0, 0, 0, conf.mode.width, 15); +// XDrawString(display, GShwnd, TextGC, 0, 12, title, strlen(title)); + } + + if (conf.fullscreen == 0) { + //int i = conf.fps ? 15 : 0; + + SDL_Flip(buffer ); + + + } + +} + + + diff --git a/plugins/gs/GSsoft/Src/Linux/Conf.c b/plugins/gs/GSsoft/Src/Linux/Conf.c new file mode 100644 index 0000000000..f6e6fcc689 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/Conf.c @@ -0,0 +1,88 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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 +#include +#include +#include +#include +#include +#include "GS.h" + +void SaveConfig() { + FILE *f; + char cfg[255]; + + sprintf (cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf (cfg, "%s/.PS2E/GSsoftx.cfg", getenv("HOME")); + f = fopen(cfg,"w"); + if (f == NULL) return; + fprintf(f, "fmode.width = %d\n", conf.fmode.width); + fprintf(f, "fmode.height = %d\n", conf.fmode.height); + fprintf(f, "wmode.width = %d\n", conf.wmode.width); + fprintf(f, "wmode.height = %d\n", conf.wmode.height); + fprintf(f, "fullscreen = %d\n", conf.fullscreen); + fprintf(f, "fps = %d\n", conf.fps); + fprintf(f, "frameskip = %d\n", conf.frameskip); + fprintf(f, "record = %d\n", conf.record); + fprintf(f, "cache = %d\n", conf.cache); + fprintf(f, "cachesize = %d\n", conf.cachesize); + fprintf(f, "codec = %d\n", conf.codec); +#ifdef GS_LOG + fprintf(f, "log = %d\n", conf.log); +#endif + fclose(f); +} + +void LoadConfig() { + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + conf.fmode.width = 320; + conf.fmode.height = 240; + conf.wmode.width = 320; + conf.wmode.height = 240; + conf.fullscreen = 1; + conf.cachesize = 128; + conf.codec = 0; + + sprintf (cfg, "%s/.PS2E/GSsoftx.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) return; + fscanf(f, "fmode.width = %d\n", &conf.fmode.width); + fscanf(f, "fmode.height = %d\n", &conf.fmode.height); + fscanf(f, "wmode.width = %d\n", &conf.wmode.width); + fscanf(f, "wmode.height = %d\n", &conf.wmode.height); + fscanf(f, "fullscreen = %d\n", &conf.fullscreen); + fscanf(f, "fps = %d\n", &conf.fps); + fscanf(f, "frameskip = %d\n", &conf.frameskip); + fscanf(f, "record = %d\n", &conf.record); + fscanf(f, "cache = %d\n", &conf.cache); + fscanf(f, "cachesize = %d\n", &conf.cachesize); + fscanf(f, "codec = %d\n", &conf.codec); +#ifdef GS_LOG + fscanf(f, "log = %d\n", &conf.log); +#endif + fclose(f); + + if (conf.fullscreen) cmode = &conf.fmode; + else cmode = &conf.wmode; +} + diff --git a/plugins/gs/GSsoft/Src/Linux/Linux.c b/plugins/gs/GSsoft/Src/Linux/Linux.c new file mode 100644 index 0000000000..7cc472527d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/Linux.c @@ -0,0 +1,320 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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 +#include +#include +#include +#include + +#include "GS.h" +#include "interface.h" +#include "support.h" +#include "Linux.h" +#include "Rec.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + + +void CALLBACK GSkeyEvent(keyEvent *ev) { + switch (ev->event) { + case KEYPRESS: + switch (ev->key) { + case XK_Page_Up: + if (conf.fps) fpspos++; break; + case XK_Page_Down: + if (conf.fps) fpspos--; break; + case XK_End: + if (conf.fps) fpspress = 1; break; + case XK_Delete: + conf.fps = 1 - conf.fps; + break; + } + break; + } +} + +GtkWidget *Conf; +GtkWidget *Logging; +GtkWidget *ComboFRes; +GtkWidget *ComboWRes; +GtkWidget *ComboCacheSize; +GtkWidget *ComboCodec; +GtkWidget *ComboFilters; +GList *fresl; +GList *wresl; +GList *cachesizel; +GList *codecl; +GList *filtersl; + +void OnConf_Ok() { + GtkWidget *Btn; + char *str; + int i; + + Btn = lookup_widget(Conf, "GtkCheckButton_Fullscreen"); + conf.fullscreen = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboFRes)->entry)); + sscanf(str, "%dx%d", &conf.fmode.width, &conf.fmode.height); + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboWRes)->entry)); + sscanf(str, "%dx%d", &conf.wmode.width, &conf.wmode.height); + + Btn = lookup_widget(Conf, "GtkCheckButton_Fps"); + conf.fps = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + Btn = lookup_widget(Conf, "GtkCheckButton_Frameskip"); + conf.frameskip = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + Btn = lookup_widget(Conf, "GtkCheckButton_Record"); + conf.record = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + Btn = lookup_widget(Conf, "GtkCheckButton_Cache"); + conf.cache = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboCacheSize)->entry)); + sscanf(str, "%d", &conf.cachesize); + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboCodec)->entry)); + for (i=0; ; i++) { + if (codeclist[i] == NULL) break; + if (strcmp(str, codeclist[i]) == 0) { conf.codec = i; break; } + } + + str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ComboFilters)->entry)); + for (i=0; ; i++) { + if (filterslist[i] == NULL) break; + if (strcmp(str, filterslist[i]) == 0) { conf.filter = i; break; } + } + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel() { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Logging() { +#ifdef GS_LOG + GtkWidget *Btn; + + Logging = create_Logging(); + + Btn = lookup_widget(Logging, "GtkCheckButton_Log"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.log); + + gtk_widget_show_all(Logging); + gtk_main(); +#endif +} + +void OnLogging_Ok() { +#ifdef GS_LOG + GtkWidget *Btn; + + Btn = lookup_widget(Logging, "GtkCheckButton_Log"); + conf.log = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + + SaveConfig(); + + gtk_widget_destroy(Logging); + gtk_main_quit(); +#endif +} + +void OnLogging_Cancel() { + gtk_widget_destroy(Logging); + gtk_main_quit(); +} + +char mname[64][32]; + +void CALLBACK GSconfigure() { + GtkWidget *Btn; + char name[32]; + int nmodes, i; + + LoadConfig(); + + Conf = create_Config(); + + fresl = NULL; + ComboFRes = lookup_widget(Conf, "GtkCombo_FRes"); + nmodes = DXgetModes(); + for (i=0; ientry), name); + + wresl = NULL; + ComboWRes = lookup_widget(Conf, "GtkCombo_WRes"); + wresl = g_list_append(wresl, "320x240"); + wresl = g_list_append(wresl, "512x384"); + wresl = g_list_append(wresl, "640x480"); + wresl = g_list_append(wresl, "800x600"); + gtk_combo_set_popdown_strings(GTK_COMBO(ComboWRes), wresl); + sprintf(name, "%dx%d", conf.wmode.width, conf.wmode.height); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboWRes)->entry), name); + + Btn = lookup_widget(Conf, "GtkCheckButton_Fullscreen"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.fullscreen); + + Btn = lookup_widget(Conf, "GtkCheckButton_Fps"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.fps); + + Btn = lookup_widget(Conf, "GtkCheckButton_Frameskip"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.frameskip); + + Btn = lookup_widget(Conf, "GtkCheckButton_Record"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.record); + + Btn = lookup_widget(Conf, "GtkCheckButton_Cache"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), conf.cache); + + cachesizel = NULL; + ComboCacheSize = lookup_widget(Conf, "GtkCombo_CacheSize"); + cachesizel = g_list_append(cachesizel, "64"); + cachesizel = g_list_append(cachesizel, "128"); + cachesizel = g_list_append(cachesizel, "256"); + gtk_combo_set_popdown_strings(GTK_COMBO(ComboCacheSize), cachesizel); + sprintf(name, "%d", conf.cachesize); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboCacheSize)->entry), name); + + codecl = NULL; + ComboCodec = lookup_widget(Conf, "GtkCombo_Codec"); + for (i=0; ; i++) { + if (codeclist[i] == NULL) break; + codecl = g_list_append(codecl, codeclist[i]); + } + gtk_combo_set_popdown_strings(GTK_COMBO(ComboCodec), codecl); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboCodec)->entry), codeclist[conf.codec]); + + if (recExist() == -1) { + Btn = lookup_widget(Conf, "GtkFrame_Rec"); + gtk_widget_set_sensitive(Btn, FALSE); + } + + filtersl = NULL; + ComboFilters = lookup_widget(Conf, "GtkCombo_Filters"); + for (i=0; ; i++) { + if (filterslist[i] == NULL) break; + filtersl = g_list_append(filtersl, filterslist[i]); + } + gtk_combo_set_popdown_strings(GTK_COMBO(ComboFilters), filtersl); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(ComboFilters)->entry), filterslist[conf.filter]); + +#ifndef GS_LOG + Btn = lookup_widget(Conf, "GtkButton_Logging"); + gtk_widget_set_sensitive(Btn, FALSE); +#endif + + gtk_widget_show_all(Conf); + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok() { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK GSabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK GStest() { + return 0; +} + +void *SysLoadLibrary(char *lib) { + return dlopen(lib, RTLD_NOW | RTLD_GLOBAL); +} + +void *SysLoadSym(void *lib, char *sym) { + void *ret = dlsym(lib, sym); + if (ret == NULL) printf("null: %s\n", sym); + return dlsym(lib, sym); +} + +char *SysLibError() { + return dlerror(); +} + +void SysCloseLibrary(void *lib) { + dlclose(lib); +} + diff --git a/plugins/gs/GSsoft/Src/Linux/Linux.h b/plugins/gs/GSsoft/Src/Linux/Linux.h new file mode 100644 index 0000000000..bbac8648e2 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/Linux.h @@ -0,0 +1,24 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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 + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ + + + +#endif diff --git a/plugins/gs/GSsoft/Src/Linux/Makefile b/plugins/gs/GSsoft/Src/Linux/Makefile new file mode 100644 index 0000000000..8e9fb53cec --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/Makefile @@ -0,0 +1,46 @@ + + +CPU = $(shell gcc -dumpmachine) + +OPTIMIZE = -O2 -fomit-frame-pointer -ffast-math -fno-exceptions -m128bit-long-double +#OPTIMIZE = -g -O0 + + +PLUGIN = libGSsoft.so +CFLAGS+= -fPIC -Wall ${OPTIMIZE} -I. -I.. -I../x86 +OBJS = ../GS.o ../Prim.o ../Soft.o ../Draw.o \ + ../Texts.o ../Color.o ../Mem.o ../Rec.o \ + ../Page.o ../Transfer.o ../Cache.o \ + ../SDL.o ../scale2x.o ../Regs.o ../SDL_gfxPrimitives.o +OBJS+= Conf.o interface.o support.o Linux.o +OBJS+= ../x86/ix86_cpudetect.o + +DEPS:= $(OBJS:.o=.d) +LIBS = $(shell gtk-config --libs) $(shell sdl-config --libs) -ldl +CFLAGS+= $(shell gtk-config --cflags) $(shell sdl-config --cflags) -D__LINUX__ + + + +CC = gcc +NASM = nasm + +all: plugin + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} +# strip --strip-unneeded --strip-debug ${PLUGIN} + +test: ../test.o ../i386.o + ${CC} ${CFLAGS} ../test.o ../i386.o -o test ${LIBS} + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +../i386.o: ../i386.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +-include ${DEPS} diff --git a/plugins/gs/GSsoft/Src/Linux/callbacks.c b/plugins/gs/GSsoft/Src/Linux/callbacks.c new file mode 100644 index 0000000000..ab877b085d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/callbacks.c @@ -0,0 +1,58 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Logging (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnLogging_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnLogging_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/gs/GSsoft/Src/Linux/callbacks.h b/plugins/gs/GSsoft/Src/Linux/callbacks.h new file mode 100644 index 0000000000..ef017bce65 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/callbacks.h @@ -0,0 +1,26 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Logging (GtkButton *button, + gpointer user_data); + +void +OnLogging_Ok (GtkButton *button, + gpointer user_data); + +void +OnLogging_Cancel (GtkButton *button, + gpointer user_data); diff --git a/plugins/gs/GSsoft/Src/Linux/gssoft.glade b/plugins/gs/GSsoft/Src/Linux/gssoft.glade new file mode 100644 index 0000000000..1fba276de9 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/gssoft.glade @@ -0,0 +1,791 @@ + + + + + GSsoft + gssoft + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + GSconfig + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + False + False + + + GtkVBox + vbox4 + False + 0 + + + GtkHBox + hbox5 + False + 0 + + 0 + True + True + + + + GtkVBox + vbox1 + 5 + False + 5 + + 0 + True + True + + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkVBox + vbox8 + False + 0 + + + GtkHBox + hbox1 + 5 + False + 5 + + 0 + True + True + + + + GtkLabel + label1 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_FRes + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + False + True + 0 + + + + + + + GtkHBox + hbox6 + 5 + False + 5 + + 0 + True + True + + + + GtkLabel + label6 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_WRes + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + False + True + 0 + + + + + + + + + GtkFrame + frame1 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkTable + table1 + 5 + 3 + 2 + False + 5 + 5 + + + GtkCheckButton + GtkCheckButton_Fps + True + + False + True + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCheckButton + GtkCheckButton_Frameskip + True + + False + True + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCheckButton + GtkCheckButton_Fullscreen + True + + False + True + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCheckButton + GtkCheckButton_Stretch + True + + False + True + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label7 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCombo + GtkCombo_Filters + 120 + False + True + False + True + False + + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry4 + True + True + True + 0 + + + + + + + + + GtkVBox + vbox6 + 5 + False + 0 + + 0 + True + True + + + + GtkFrame + frame4 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkVBox + vbox5 + 5 + False + 0 + + + GtkCheckButton + GtkCheckButton_Cache + True + + False + True + + 0 + False + False + + + + + GtkHBox + hbox2 + False + 5 + + 0 + True + True + + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_CacheSize + 80 + False + True + False + True + False + + + 0 + True + False + + + + GtkEntry + GtkCombo:entry + combo-entry2 + True + True + True + 0 + + + + + + + + + GtkFrame + GtkFrame_Rec + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkVBox + vbox7 + 5 + False + 0 + + + GtkCheckButton + GtkCheckButton_Record + True + + False + True + + 0 + False + False + + + + + GtkCombo + GtkCombo_Codec + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry3 + True + True + True + 0 + + + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_END + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + GtkButton_Logging + True + True + + clicked + OnConf_Logging + Sat, 22 Nov 2003 04:35:59 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + GSabout + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label4 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + Logging + 5 + Logging + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox3 + False + 0 + + + GtkCheckButton + GtkCheckButton_Log + True + + False + True + + 0 + False + False + + + + + Placeholder + + + + GtkHButtonBox + hbuttonbox3 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button5 + True + True + + clicked + OnLogging_Ok + Sat, 22 Nov 2003 04:39:03 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button6 + True + True + + clicked + OnLogging_Cancel + Sat, 22 Nov 2003 04:40:17 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/gs/GSsoft/Src/Linux/interface.c b/plugins/gs/GSsoft/Src/Linux/interface.c new file mode 100644 index 0000000000..c1e260be8d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/interface.c @@ -0,0 +1,517 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox4; + GtkWidget *hbox5; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *vbox8; + GtkWidget *hbox1; + GtkWidget *label1; + GtkWidget *GtkCombo_FRes; + GtkWidget *combo_entry1; + GtkWidget *hbox6; + GtkWidget *label6; + GtkWidget *GtkCombo_WRes; + GtkWidget *entry1; + GtkWidget *frame1; + GtkWidget *table1; + GtkWidget *GtkCheckButton_Fps; + GtkWidget *GtkCheckButton_Frameskip; + GtkWidget *GtkCheckButton_Fullscreen; + GtkWidget *GtkCheckButton_Stretch; + GtkWidget *label7; + GtkWidget *GtkCombo_Filters; + GtkWidget *combo_entry4; + GtkWidget *vbox6; + GtkWidget *frame4; + GtkWidget *vbox5; + GtkWidget *GtkCheckButton_Cache; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_CacheSize; + GtkWidget *combo_entry2; + GtkWidget *GtkFrame_Rec; + GtkWidget *vbox7; + GtkWidget *GtkCheckButton_Record; + GtkWidget *GtkCombo_Codec; + GtkWidget *combo_entry3; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + GtkWidget *GtkButton_Logging; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "GSconfig"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + gtk_window_set_policy (GTK_WINDOW (Config), FALSE, FALSE, FALSE); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox4); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox4", vbox4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (Config), vbox4); + + hbox5 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox5); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox5", hbox5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox5); + gtk_box_pack_start (GTK_BOX (vbox4), hbox5, TRUE, TRUE, 0); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (hbox5), vbox1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Display Setup"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + vbox8 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox8); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox8", vbox8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox8); + gtk_container_add (GTK_CONTAINER (frame2), vbox8); + + hbox1 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox8), hbox1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label1 = gtk_label_new ("Fullscreen Resolution"); + gtk_widget_ref (label1); + gtk_object_set_data_full (GTK_OBJECT (Config), "label1", label1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label1); + gtk_box_pack_start (GTK_BOX (hbox1), label1, FALSE, FALSE, 0); + + GtkCombo_FRes = gtk_combo_new (); + gtk_widget_ref (GtkCombo_FRes); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_FRes", GtkCombo_FRes, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_FRes); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_FRes, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_FRes, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_FRes)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + gtk_entry_set_editable (GTK_ENTRY (combo_entry1), FALSE); + + hbox6 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox6); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox6", hbox6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox6); + gtk_box_pack_start (GTK_BOX (vbox8), hbox6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox6), 5); + + label6 = gtk_label_new ("Windowed Resolution"); + gtk_widget_ref (label6); + gtk_object_set_data_full (GTK_OBJECT (Config), "label6", label6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label6); + gtk_box_pack_start (GTK_BOX (hbox6), label6, FALSE, FALSE, 0); + + GtkCombo_WRes = gtk_combo_new (); + gtk_widget_ref (GtkCombo_WRes); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_WRes", GtkCombo_WRes, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_WRes); + gtk_box_pack_start (GTK_BOX (hbox6), GtkCombo_WRes, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_WRes, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_WRes)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + gtk_entry_set_editable (GTK_ENTRY (entry1), FALSE); + + frame1 = gtk_frame_new ("Options"); + gtk_widget_ref (frame1); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame1", frame1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0); + + table1 = gtk_table_new (3, 2, FALSE); + gtk_widget_ref (table1); + gtk_object_set_data_full (GTK_OBJECT (Config), "table1", table1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (frame1), table1); + gtk_container_set_border_width (GTK_CONTAINER (table1), 5); + gtk_table_set_row_spacings (GTK_TABLE (table1), 5); + gtk_table_set_col_spacings (GTK_TABLE (table1), 5); + + GtkCheckButton_Fps = gtk_check_button_new_with_label ("Display Fps Count"); + gtk_widget_ref (GtkCheckButton_Fps); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Fps", GtkCheckButton_Fps, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Fps); + gtk_table_attach (GTK_TABLE (table1), GtkCheckButton_Fps, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + GtkCheckButton_Frameskip = gtk_check_button_new_with_label ("Enable Frameskip"); + gtk_widget_ref (GtkCheckButton_Frameskip); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Frameskip", GtkCheckButton_Frameskip, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Frameskip); + gtk_table_attach (GTK_TABLE (table1), GtkCheckButton_Frameskip, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + GtkCheckButton_Fullscreen = gtk_check_button_new_with_label ("Enable Fullscreen"); + gtk_widget_ref (GtkCheckButton_Fullscreen); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Fullscreen", GtkCheckButton_Fullscreen, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Fullscreen); + gtk_table_attach (GTK_TABLE (table1), GtkCheckButton_Fullscreen, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + GtkCheckButton_Stretch = gtk_check_button_new_with_label ("Disable Stretching"); + gtk_widget_ref (GtkCheckButton_Stretch); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Stretch", GtkCheckButton_Stretch, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Stretch); + gtk_table_attach (GTK_TABLE (table1), GtkCheckButton_Stretch, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label7 = gtk_label_new ("Screen Filtering"); + gtk_widget_ref (label7); + gtk_object_set_data_full (GTK_OBJECT (Config), "label7", label7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label7); + gtk_table_attach (GTK_TABLE (table1), label7, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5); + + GtkCombo_Filters = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Filters); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Filters", GtkCombo_Filters, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Filters); + gtk_table_attach (GTK_TABLE (table1), GtkCombo_Filters, 1, 2, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (GtkCombo_Filters, 120, -2); + + combo_entry4 = GTK_COMBO (GtkCombo_Filters)->entry; + gtk_widget_ref (combo_entry4); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry4", combo_entry4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry4); + + vbox6 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox6); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox6", vbox6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox6); + gtk_box_pack_start (GTK_BOX (hbox5), vbox6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox6), 5); + + frame4 = gtk_frame_new ("Texture Caching"); + gtk_widget_ref (frame4); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame4", frame4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame4); + gtk_box_pack_start (GTK_BOX (vbox6), frame4, TRUE, TRUE, 0); + + vbox5 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox5); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox5", vbox5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox5); + gtk_container_add (GTK_CONTAINER (frame4), vbox5); + gtk_container_set_border_width (GTK_CONTAINER (vbox5), 5); + + GtkCheckButton_Cache = gtk_check_button_new_with_label ("Enable Texture Caching"); + gtk_widget_ref (GtkCheckButton_Cache); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Cache", GtkCheckButton_Cache, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Cache); + gtk_box_pack_start (GTK_BOX (vbox5), GtkCheckButton_Cache, FALSE, FALSE, 0); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox5), hbox2, TRUE, TRUE, 0); + + label5 = gtk_label_new ("Cache Size"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_CacheSize = gtk_combo_new (); + gtk_widget_ref (GtkCombo_CacheSize); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_CacheSize", GtkCombo_CacheSize, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_CacheSize); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_CacheSize, TRUE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_CacheSize, 80, -2); + + combo_entry2 = GTK_COMBO (GtkCombo_CacheSize)->entry; + gtk_widget_ref (combo_entry2); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry2", combo_entry2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry2); + + GtkFrame_Rec = gtk_frame_new ("Recording"); + gtk_widget_ref (GtkFrame_Rec); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkFrame_Rec", GtkFrame_Rec, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkFrame_Rec); + gtk_box_pack_start (GTK_BOX (vbox6), GtkFrame_Rec, TRUE, TRUE, 0); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox7); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox7", vbox7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (GtkFrame_Rec), vbox7); + gtk_container_set_border_width (GTK_CONTAINER (vbox7), 5); + + GtkCheckButton_Record = gtk_check_button_new_with_label ("Enable Recording"); + gtk_widget_ref (GtkCheckButton_Record); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Record", GtkCheckButton_Record, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Record); + gtk_box_pack_start (GTK_BOX (vbox7), GtkCheckButton_Record, FALSE, FALSE, 0); + + GtkCombo_Codec = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Codec); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Codec", GtkCombo_Codec, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Codec); + gtk_box_pack_start (GTK_BOX (vbox7), GtkCombo_Codec, FALSE, FALSE, 0); + + combo_entry3 = GTK_COMBO (GtkCombo_Codec)->entry; + gtk_widget_ref (combo_entry3); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry3", combo_entry3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry3); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox4), hbuttonbox1, TRUE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + GtkButton_Logging = gtk_button_new_with_label ("Logging..."); + gtk_widget_ref (GtkButton_Logging); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkButton_Logging", GtkButton_Logging, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkButton_Logging); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), GtkButton_Logging); + GTK_WIDGET_SET_FLAGS (GtkButton_Logging, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + gtk_signal_connect (GTK_OBJECT (GtkButton_Logging), "clicked", + GTK_SIGNAL_FUNC (OnConf_Logging), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *label4; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "GSabout"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("GSsoftx Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Authors: linuzappz \n [TyRaNiD]"); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + label4 = gtk_label_new ("Thanks to:\n\t\tshadow - conding support and help.\n\t\tPete Bernert - for the triangles code.\n\t\tAbsolute0 - help fixing bugs :)"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (About), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (vbox2), label4, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + +GtkWidget* +create_Logging (void) +{ + GtkWidget *Logging; + GtkWidget *vbox3; + GtkWidget *GtkCheckButton_Log; + GtkWidget *hbuttonbox3; + GtkWidget *button5; + GtkWidget *button6; + + Logging = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Logging), "Logging", Logging); + gtk_container_set_border_width (GTK_CONTAINER (Logging), 5); + gtk_window_set_title (GTK_WINDOW (Logging), "Logging"); + gtk_window_set_position (GTK_WINDOW (Logging), GTK_WIN_POS_CENTER); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox3); + gtk_object_set_data_full (GTK_OBJECT (Logging), "vbox3", vbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox3); + gtk_container_add (GTK_CONTAINER (Logging), vbox3); + + GtkCheckButton_Log = gtk_check_button_new_with_label ("Log"); + gtk_widget_ref (GtkCheckButton_Log); + gtk_object_set_data_full (GTK_OBJECT (Logging), "GtkCheckButton_Log", GtkCheckButton_Log, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Log); + gtk_box_pack_start (GTK_BOX (vbox3), GtkCheckButton_Log, FALSE, FALSE, 0); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox3); + gtk_object_set_data_full (GTK_OBJECT (Logging), "hbuttonbox3", hbuttonbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox3), hbuttonbox3, TRUE, TRUE, 0); + + button5 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button5); + gtk_object_set_data_full (GTK_OBJECT (Logging), "button5", button5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button5); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), button5); + GTK_WIDGET_SET_FLAGS (button5, GTK_CAN_DEFAULT); + + button6 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button6); + gtk_object_set_data_full (GTK_OBJECT (Logging), "button6", button6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button6); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), button6); + GTK_WIDGET_SET_FLAGS (button6, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button5), "clicked", + GTK_SIGNAL_FUNC (OnLogging_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button6), "clicked", + GTK_SIGNAL_FUNC (OnLogging_Cancel), + NULL); + + return Logging; +} + diff --git a/plugins/gs/GSsoft/Src/Linux/interface.h b/plugins/gs/GSsoft/Src/Linux/interface.h new file mode 100644 index 0000000000..3c4209ad30 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/interface.h @@ -0,0 +1,7 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); +GtkWidget* create_Logging (void); diff --git a/plugins/gs/GSsoft/Src/Linux/support.c b/plugins/gs/GSsoft/Src/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/gs/GSsoft/Src/Linux/support.h b/plugins/gs/GSsoft/Src/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/gs/GSsoft/Src/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/gs/GSsoft/Src/Mem.c b/plugins/gs/GSsoft/Src/Mem.c new file mode 100644 index 0000000000..7e44a048b2 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Mem.c @@ -0,0 +1,174 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Page.h" + + +void writePixel32(int x, int y, u32 pixel, u32 bp, u32 bw) { + vRamUL[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +void writePixel24(int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +void writePixel16(int x, int y, u16 pixel, u32 bp, u32 bw) { + vRamUS[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +void writePixel16S(int x, int y, u16 pixel, u32 bp, u32 bw) { + vRamUS[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +void writePixel8(int x, int y, u8 pixel, u32 bp, u32 bw) { + vRam[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +void writePixel8H(int x, int y, u8 pixel, u32 bp, u32 bw) { + ((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3] = pixel; +} + +void writePixel4(int x, int y, u8 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = vRam[addr/2]; + if (addr & 0x1) + vRam[addr/2] = (pix & 0x0f) | (pixel << 4); + else vRam[addr/2] = (pix & 0xf0) | (pixel); +} + +void writePixel4HL(int x, int y, u8 pixel, u32 bp, u32 bw) { + u8 *p = &((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3]; + *p = (*p & 0xf0) | pixel; +} + +void writePixel4HH(int x, int y, u8 pixel, u32 bp, u32 bw) { + u8 *p = &((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3]; + *p = (*p & 0x0f) | pixel; +} + + +void writePixel32Z(int x, int y, u32 pixel, u32 bp, u32 bw) { + vRamUL[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +void writePixel24Z(int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&vRamUL[getPixelAddress32Z(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +void writePixel16Z(int x, int y, u16 pixel, u32 bp, u32 bw) { + vRamUS[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +void writePixel16SZ(int x, int y, u16 pixel, u32 bp, u32 bw) { + vRamUS[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +u32 readPixel32(int x, int y, u32 bp, u32 bw) { + return vRamUL[getPixelAddress32(x, y, bp, bw)]; +} + +u32 readPixel24(int x, int y, u32 bp, u32 bw) { + return vRamUL[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +u16 readPixel16(int x, int y, u32 bp, u32 bw) { + return vRamUS[getPixelAddress16(x, y, bp, bw)]; +} + +u16 readPixel16S(int x, int y, u32 bp, u32 bw) { + return vRamUS[getPixelAddress16S(x, y, bp, bw)]; +} + +u8 readPixel8(int x, int y, u32 bp, u32 bw) { + return vRam[getPixelAddress8(x, y, bp, bw)]; +} + +u8 readPixel8H(int x, int y, u32 bp, u32 bw) { + return ((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3]; +} + +u8 readPixel4(int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = vRam[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +u8 readPixel4HL(int x, int y, u32 bp, u32 bw) { + u8 *p = &((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3]; + return *p & 0x0f; +} + +u8 readPixel4HH(int x, int y, u32 bp, u32 bw) { + u8 *p = &((u8*)&vRamUL[getPixelAddress32(x, y, bp, bw)])[3]; + return *p >> 4; +} + +/////////////// + +u32 readPixel32Z(int x, int y, u32 bp, u32 bw) { + return vRamUL[getPixelAddress32Z(x, y, bp, bw)]; +} + +u32 readPixel24Z(int x, int y, u32 bp, u32 bw) { + return vRamUL[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +u16 readPixel16Z(int x, int y, u32 bp, u32 bw) { + return vRamUS[getPixelAddress16Z(x, y, bp, bw)]; +} + +u16 readPixel16SZ(int x, int y, u32 bp, u32 bw) { + return vRamUS[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////// + +u32 readPixel16to32(int x, int y, u32 bp, u32 bw) { + return RGBA16to32(vRamUS[getPixelAddress16(x, y, bp, bw)]); +} + +u32 readPixel16Sto32(int x, int y, u32 bp, u32 bw) { + return RGBA16to32(vRamUS[getPixelAddress16S(x, y, bp, bw)]); +} + +/////////////// + +u32 readPixel16Zto32(int x, int y, u32 bp, u32 bw) { + return RGBA16to32(vRamUS[getPixelAddress16Z(x, y, bp, bw)]); +} + +u32 readPixel16SZto32(int x, int y, u32 bp, u32 bw) { + return RGBA16to32(vRamUS[getPixelAddress16SZ(x, y, bp, bw)]); +} + diff --git a/plugins/gs/GSsoft/Src/Mem.h b/plugins/gs/GSsoft/Src/Mem.h new file mode 100644 index 0000000000..389cb05205 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Mem.h @@ -0,0 +1,59 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + + +void writePixel32(int x, int y, u32 pixel, u32 bp, u32 bw); +void writePixel24(int x, int y, u32 pixel, u32 bp, u32 bw); +void writePixel16(int x, int y, u16 pixel, u32 bp, u32 bw); +void writePixel16S(int x, int y, u16 pixel, u32 bp, u32 bw); +void writePixel8(int x, int y, u8 pixel, u32 bp, u32 bw); +void writePixel8H(int x, int y, u8 pixel, u32 bp, u32 bw); +void writePixel4(int x, int y, u8 pixel, u32 bp, u32 bw); +void writePixel4HL(int x, int y, u8 pixel, u32 bp, u32 bw); +void writePixel4HH(int x, int y, u8 pixel, u32 bp, u32 bw); + +u32 readPixel32(int x, int y, u32 bp, u32 bw); +u32 readPixel24(int x, int y, u32 bp, u32 bw); +u16 readPixel16(int x, int y, u32 bp, u32 bw); +u16 readPixel16S(int x, int y, u32 bp, u32 bw); +u8 readPixel8(int x, int y, u32 bp, u32 bw); +u8 readPixel8H(int x, int y, u32 bp, u32 bw); +u8 readPixel4(int x, int y, u32 bp, u32 bw); +u8 readPixel4HL(int x, int y, u32 bp, u32 bw); +u8 readPixel4HH(int x, int y, u32 bp, u32 bw); + +void writePixel32Z(int x, int y, u32 pixel, u32 bp, u32 bw); +void writePixel24Z(int x, int y, u32 pixel, u32 bp, u32 bw); +void writePixel16Z(int x, int y, u16 pixel, u32 bp, u32 bw); +void writePixel16SZ(int x, int y, u16 pixel, u32 bp, u32 bw); + +u32 readPixel32Z(int x, int y, u32 bp, u32 bw); +u32 readPixel24Z(int x, int y, u32 bp, u32 bw); +u16 readPixel16Z(int x, int y, u32 bp, u32 bw); +u16 readPixel16SZ(int x, int y, u32 bp, u32 bw); + +u32 readPixel16to32(int x, int y, u32 bp, u32 bw); +u32 readPixel16Sto32(int x, int y, u32 bp, u32 bw); + +u32 readPixel16Zto32(int x, int y, u32 bp, u32 bw); +u32 readPixel16SZto32(int x, int y, u32 bp, u32 bw); + +#endif /* __MEM_H__ */ diff --git a/plugins/gs/GSsoft/Src/PS2Edefs.h b/plugins/gs/GSsoft/Src/PS2Edefs.h new file mode 100644 index 0000000000..6481d35877 --- /dev/null +++ b/plugins/gs/GSsoft/Src/PS2Edefs.h @@ -0,0 +1,696 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.7 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0003 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { // NOT bcd coded + u8 minute; + u8 second; + u8 frame; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usualy 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdLoc:track type +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetType CDVDgetType; +_CDVDgetTrayStatus CDVDgetTrayStatus; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/gs/GSsoft/Src/PS2Etypes.h b/plugins/gs/GSsoft/Src/PS2Etypes.h new file mode 100644 index 0000000000..3a63c58b85 --- /dev/null +++ b/plugins/gs/GSsoft/Src/PS2Etypes.h @@ -0,0 +1,43 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/gs/GSsoft/Src/Page.c b/plugins/gs/GSsoft/Src/Page.c new file mode 100644 index 0000000000..192b74a277 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Page.c @@ -0,0 +1,354 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include +#include +#include + +#include "GS.h" + +int blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +int blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +int blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +int blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +int blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +int blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +int blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +int blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +int columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +int columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +int columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +int columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress32: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable32[(y / 8) & 3][(x / 8) & 7]; + basepage = (bp >> 5) + ((y / 32) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 64 + columnTable32[y % 8][x % 8]; + if (word >= 0x100000) { +// GS_LOG("getPixelAddress32: %d, %d, %x, %x -> %x\n", x, y, bp, bw, word); + return 0; + } + return word; +} + +u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress16: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable16[(y / 8) & 7][(x / 16) & 3]; + basepage = (bp >> 5) + ((y / 64) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 128 + columnTable16[y % 8][x % 16]; +/* GS_LOG("block: %x\n", block); + GS_LOG("basepage: %x\n", basepage); + GS_LOG("word: %x\n", word);*/ + if (word >= 0x200000) return 0; + return word; +} + +u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress16: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable16S[(y / 8) & 7][(x / 16) & 3]; + basepage = (bp >> 5) + ((y / 64) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 128 + columnTable16[y % 8][x % 16]; +/* GS_LOG("block: %x\n", block); + GS_LOG("basepage: %x\n", basepage); + GS_LOG("word: %x\n", word);*/ + if (word >= 0x200000) return 0; + return word; +} + +u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress8: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable8[(y / 16) & 3][(x / 16) & 7]; + basepage = (bp >> 5) + ((y / 64) * ((bw+127)/128)) + x/128; + word = ((basepage * 32) + block) * 256 + columnTable8[y % 16][x % 16]; +// GS_LOG("block: %x\n", block); +// GS_LOG("basepage: %x\n", basepage); +// GS_LOG("word: %x\n", word); + if (word >= 0x400000) return 0; + return word; +} + +u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + + block = (bp & 0x1f) + blockTable4[(y / 16) & 7][(x / 32) & 3]; + basepage = (bp >> 5) + ((y / 128) * ((bw+127)/128)) + x/128; + word = ((basepage * 32) + block) * 512 + columnTable4[y % 16][x % 32]; + if (word >= 0x800000) return 0; + return word; +} + +u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress32: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable32Z[(y / 8) & 3][(x / 8) & 7]; + basepage = (bp >> 5) + ((y / 32) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 64 + (y % 8) * 8 + x % 8; + if (word >= 0x100000) return 0; + return word; +} + +u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress16: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable16Z[(y / 8) & 7][(x / 16) & 3]; + basepage = (bp >> 5) + ((y / 64) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 128 + (y % 8) * 16 + x % 16; +/* GS_LOG("block: %x\n", block); + GS_LOG("basepage: %x\n", basepage); + GS_LOG("word: %x\n", word);*/ + if (word >= 0x200000) return 0; + return word; +} + +u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 block; + u32 basepage; + u32 word; + +// GS_LOG("getPixelAddress16: %d, %d, %x, %x\n", x, y, bp, bw); + block = (bp & 0x1f) + blockTable16SZ[(y / 8) & 7][(x / 16) & 3]; + basepage = (bp >> 5) + ((y / 64) * (bw/64)) + x/64; + word = ((basepage * 32) + block) * 128 + (y % 8) * 16 + x % 16; +/* GS_LOG("block: %x\n", block); + GS_LOG("basepage: %x\n", basepage); + GS_LOG("word: %x\n", word);*/ + if (word >= 0x200000) return 0; + return word; +} + diff --git a/plugins/gs/GSsoft/Src/Page.h b/plugins/gs/GSsoft/Src/Page.h new file mode 100644 index 0000000000..3179ed6301 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Page.h @@ -0,0 +1,33 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __PAGE_H__ +#define __PAGE_H__ + +u32 getPixelAddress32(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress16(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress8(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress4(int x, int y, u32 bp, u32 bw); + +u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw); +u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw); + + +#endif /* __PAGE_H__ */ diff --git a/plugins/gs/GSsoft/Src/Prim.c b/plugins/gs/GSsoft/Src/Prim.c new file mode 100644 index 0000000000..45790840da --- /dev/null +++ b/plugins/gs/GSsoft/Src/Prim.c @@ -0,0 +1,390 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + +#include "GS.h" +#include "Soft.h" +#include "Mem.h" + + +__inline void stepGSvertex() { + int i; + + gs.primC--; + + for (i=0; itme) { + if (prim->fst) { + gs.gsvertex[i].u = gs.gsvertex[i+1].u; + gs.gsvertex[i].v = gs.gsvertex[i+1].v; + } else { + gs.gsvertex[i].s = gs.gsvertex[i+1].s; + gs.gsvertex[i].t = gs.gsvertex[i+1].t; + gs.gsvertex[i].q = gs.gsvertex[i+1].q; + } + } + + if (prim->iip) { + gs.gsvertex[i].rgba = gs.gsvertex[i+1].rgba; + } + } +} + +__inline void stepGSfanvertex() { + gs.primC--; + + gs.gsvertex[1].x = gs.gsvertex[2].x; + gs.gsvertex[1].y = gs.gsvertex[2].y; + gs.gsvertex[1].z = gs.gsvertex[2].z; + gs.gsvertex[1].f = gs.gsvertex[2].f; + + if (prim->tme) { + if (prim->fst) { + gs.gsvertex[1].u = gs.gsvertex[2].u; + gs.gsvertex[1].v = gs.gsvertex[2].v; + } else { + gs.gsvertex[1].s = gs.gsvertex[2].s; + gs.gsvertex[1].t = gs.gsvertex[2].t; + gs.gsvertex[1].q = gs.gsvertex[2].q; + } + } + + if (prim->iip) { + gs.gsvertex[1].rgba = gs.gsvertex[2].rgba; + } +} + +__inline void STQtoUV(Vertex *v, float q) { +#ifdef GS_LOG + GS_LOG("STQtoUV %f, %f, %f (tw=%d, th=%d)\n", + *(float*)&v->s, *(float*)&v->t, q, tex0->tw, tex0->th); +#endif + if (v->s == 0xffffffff) { printf("v->s == nan\n"); } + if (v->t == 0xffffffff) { printf("v->t == nan\n"); } + if (q == 0xffffffff) { printf("v->q == nan\n"); } + if (q == 0) { + v->u = (int)((float)(tex0->tw-1) * (*(float*)&v->s)); + v->v = (int)((float)(tex0->th-1) * (*(float*)&v->t)); + } else { + v->u = (int)((float)(tex0->tw-1) * (*(float*)&v->s / q)); + v->v = (int)((float)(tex0->th-1) * (*(float*)&v->t / q)); + } + if (v->u > tex0->tw) { +#ifdef GS_LOG + GS_LOG("*warning*: U > TW\n"); +#endif + } + if (v->v > tex0->th) { +#ifdef GS_LOG + GS_LOG("*warning*: V > TH\n"); +#endif + } +} + +void _primPoint(Vertex *vertex) { + Vertex v; + + memcpy(&v, vertex, sizeof(Vertex)); + +#ifdef GS_LOG + GS_LOG("primPoint %dx%d %lx\n", + v.x, v.y, gs.rgba); +#endif + + v.x -= offset->x; v.y -= offset->y; + + if (v.x < scissor->x0) return; + if (v.y < scissor->y0) return; + if (v.x > scissor->x1) return; + if (v.y > scissor->y1) return; + + if (v.x < 0) return; + if (v.x >= gsfb->fbw) return; + if (v.y < 0) return; + if (v.y >= gsfb->fbh) return; + + writePixel32(v.x, v.y, gs.rgba, gsfb->fbp, gsfb->fbw); +} + +void primPoint(Vertex *vertex) { + if (vertex && norender == 0) _primPoint(vertex); + + memset(gs.gsvertex, 0, sizeof(Vertex)); + gs.primC = 0; +} + +void _primLine(Vertex *vertex) { + Vertex v[2]; + + memcpy(v, vertex, sizeof(Vertex) * 2); + + v[0].x -= offset->x; v[0].y -= offset->y; + v[1].x -= offset->x; v[1].y -= offset->y; + +#ifdef GS_LOG + GS_LOG("primLine %dx%d %lx, %dx%d %lx\n", + v[0].x, v[0].y, v[0].rgba, + v[1].x, v[1].y, v[1].rgba); +#endif + if (prim->iip == 0) { + if (test->zte) + drawLineF_Z(v); + else drawLineF(v); + } else { + if (test->zte) + drawLineG_Z(v); + else drawLineG(v); + } +} + +void primLine(Vertex *vertex) { + if (vertex && norender == 0) _primLine(vertex); + + memset(gs.gsvertex, 0, sizeof(Vertex)*2); + gs.primC = 0; +} + +void primLineStrip(Vertex *vertex) { + if (vertex && norender == 0) _primLine(vertex); + + stepGSvertex(); +} + +void _primTriangle(Vertex *vertex) { + Vertex v[3]; + + memcpy(v, vertex, sizeof(Vertex) * 3); + + v[0].x -= offset->x; v[0].y -= offset->y; + v[1].x -= offset->x; v[1].y -= offset->y; + v[2].x -= offset->x; v[2].y -= offset->y; + +#ifdef GS_LOG + GS_LOG("primTriangle%s%s %dx%dx%x %lx - %dx%dx%x %lx - %dx%dx%x %lx (offset %dx%d)\n", + prim->iip == 0 ? "F" : "G", + prim->tme == 0 ? "" : "T", + v[0].x, v[0].y, v[0].z, v[0].rgba, + v[1].x, v[1].y, v[1].z, v[1].rgba, + v[2].x, v[2].y, v[2].z, v[2].rgba, + offset->x, offset->y); +#endif + + if (wireframe) { + drawLineF(&v[0]); + drawLineF(&v[1]); + memcpy(&v[1], &v[2], sizeof(Vertex)); + drawLineF(&v[0]); + return; + } + + if (prim->tme) { + if (tex0->tw == 0 || tex0->th == 0) return; + + if (prim->fst == 0) { +#ifdef GS_LOG + GS_LOG("stq: %fx%fx%f - %fx%fx%f - %fx%fx%f (tex0.tw=%d, tex0.th=%d)\n", + *(float*)&v[0].s, *(float*)&v[0].t, *(float*)&v[0].q, + *(float*)&v[1].s, *(float*)&v[1].t, *(float*)&v[1].q, + *(float*)&v[2].s, *(float*)&v[2].t, *(float*)&v[2].q, + tex0->tw, tex0->th); +#endif + + if (prim->iip) { + STQtoUV(&v[0], *(float*)&v[0].q); + STQtoUV(&v[1], *(float*)&v[1].q); + STQtoUV(&v[2], *(float*)&v[2].q); + } else { + STQtoUV(&v[0], *(float*)&gs.q); + STQtoUV(&v[1], *(float*)&gs.q); + STQtoUV(&v[2], *(float*)&gs.q); + } + } +#ifdef GS_LOG + GS_LOG("uv: %dx%d - %dx%d - %dx%d (tex0.tw=%d, tex0.th=%d)\n", + v[0].u, v[0].v, + v[1].u, v[1].v, v[2].u, v[2].v, + tex0->tw, tex0->th); +#endif + +#ifdef GS_LOG + GS_LOG("uv: %dx%d - %dx%d - %dx%d (tex0.tw=%d, tex0.th=%d)\n", + v[0].u, v[0].v, + v[1].u, v[1].v, v[2].u, v[2].v, + tex0->tw, tex0->th); +#endif + + if (prim->iip) { + if (test->zte) { + switch (tex0->tfx) { + case TEX_DECAL: drawTriangleGTDecal_Z(v); break; + case TEX_MODULATE: drawTriangleGTModulate_Z(v); break; + case TEX_HIGHLIGHT: drawTriangleGTHighlight_Z(v); break; + case TEX_HIGHLIGHT2: drawTriangleGTHighlight2_Z(v); break; + } + } else { + switch (tex0->tfx) { + case TEX_DECAL: drawTriangleGTDecal(v); break; + case TEX_MODULATE: drawTriangleGTModulate(v); break; + case TEX_HIGHLIGHT: drawTriangleGTHighlight(v); break; + case TEX_HIGHLIGHT2: drawTriangleGTHighlight2(v); break; + } + } + } else { + if(test->zte) { + switch (tex0->tfx) { + case TEX_DECAL: drawTriangleFTDecal_Z(v); break; + case TEX_MODULATE: drawTriangleFTModulate_Z(v); break; + case TEX_HIGHLIGHT: drawTriangleFTHighlight_Z(v); break; + case TEX_HIGHLIGHT2: drawTriangleFTHighlight2_Z(v); break; + } + } else { + switch (tex0->tfx) { + case TEX_DECAL: drawTriangleFTDecal(v); break; + case TEX_MODULATE: drawTriangleFTModulate(v); break; + case TEX_HIGHLIGHT: drawTriangleFTHighlight(v); break; + case TEX_HIGHLIGHT2: drawTriangleFTHighlight2(v); break; + } + } + } + } else { + if (prim->iip) { + if(test->zte) + drawTriangleG_Z(v); + else + drawTriangleG(v); + } else { + if(test->zte) + drawTriangleF_Z(v); + else + drawTriangleF(v); + } + } +} + +void primTriangle(Vertex *vertex) { + if (vertex && norender == 0) _primTriangle(vertex); + + memset(gs.gsvertex, 0, sizeof(Vertex)*3); + gs.primC = 0; +// if (conf.log) { DXupdate(); Sleep(250); } +} + +void primTriangleStrip(Vertex *vertex) { + if (vertex && norender == 0) _primTriangle(vertex); + + stepGSvertex(); +// if (conf.log) { DXupdate(); Sleep(250); } +} + +void primTriangleFan(Vertex *vertex) { + if (vertex && norender == 0) _primTriangle(vertex); + + stepGSfanvertex(); +// if (conf.log) { DXupdate(); Sleep(250); } +} + +void _primSprite(Vertex *vertex) { + Vertex v[2]; + + memcpy(v, vertex, sizeof(Vertex) * 2); + +#ifdef GS_LOG + GS_LOG("primSprite%s %dx%d %lx - %dx%d %lx (offset %dx%d) (tex %dx%d %dx%d)\n", + prim->tme == 0 ? "" : "T", + v[0].x, v[0].y, v[0].rgba, + v[1].x, v[1].y, v[1].rgba, + offset->x, offset->y, + v[0].u, v[0].v, + v[1].u, v[1].v); +#endif + + v[0].x -= offset->x; v[0].y -= offset->y; + v[1].x -= offset->x; v[1].y -= offset->y; + + if (v[0].x > v[1].x) { + int x; + x = v[0].x; v[0].x = v[1].x; v[1].x = x; + if (prim->tme) { + float f; + x = v[0].u; v[0].u = v[1].u; v[1].u = x; + f = v[0].s; v[0].s = v[1].s; v[1].s = f; + } + } + if (v[0].y > v[1].y) { + int y; + y = v[0].y; v[0].y = v[1].y; v[1].y = y; + if (prim->tme) { + float f; + y = v[0].v; v[0].v = v[1].v; v[1].v = y; + f = v[0].t; v[0].t = v[1].t; v[1].t = f; + } + } + + if (prim->tme) { + if (tex0->tw == 0 || tex0->th == 0) return; + + if (prim->fst == 0) { + STQtoUV(&v[0], *(float*)&gs.q); + STQtoUV(&v[1], *(float*)&gs.q); + } + + if(test->zte) { // If z buffer enabled + switch (tex0->tfx) { + case TEX_DECAL: drawSpriteTDecal_Z(v); break; + case TEX_MODULATE: drawSpriteTModulate_Z(v); break; + case TEX_HIGHLIGHT: drawSpriteTHighlight_Z(v); break; + case TEX_HIGHLIGHT2: drawSpriteTHighlight2_Z(v); break; + } + } else { + switch (tex0->tfx) { + case TEX_DECAL: drawSpriteTDecal(v); break; + case TEX_MODULATE: drawSpriteTModulate(v); break; + case TEX_HIGHLIGHT: drawSpriteTHighlight(v); break; + case TEX_HIGHLIGHT2: drawSpriteTHighlight2(v); break; + } + } + } else { + if(test->zte) // If z buffer enabled + drawSprite_Z(v); + else + drawSprite(v); + } +} + +void primSprite(Vertex *vertex) { + if (vertex && norender == 0) _primSprite(vertex); + + memset(gs.gsvertex, 0, sizeof(Vertex)*2); + gs.primC = 0; +// if (conf.log) { DXupdate(); Sleep(250); } +} + +void primNull(Vertex *v) { +} + +void (*primTable[8])(Vertex *v) = { + primPoint, primLine, primLineStrip, + primTriangle, primTriangleStrip, primTriangleFan, + primSprite, primNull +}; diff --git a/plugins/gs/GSsoft/Src/Rec.c b/plugins/gs/GSsoft/Src/Rec.c new file mode 100644 index 0000000000..918023f067 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Rec.c @@ -0,0 +1,285 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include + +#include "GS.h" +#include "Draw.h" +#include "Rec.h" + +AVFormatContext *output = NULL; +AVStream *stream; +AVFrame *picture; +AVFrame *yuv420p; +u8 *picture_buf; +int picture_size; +u8 *outbuf; +int outbuf_size; + +#define av_register_all _av_register_all +#define av_new_stream _av_new_stream +#define av_set_parameters _av_set_parameters +#define av_write_header _av_write_header +#define av_write_frame _av_write_frame +#define av_write_trailer _av_write_trailer +#define avpicture_fill _avpicture_fill +#define avpicture_get_size _avpicture_get_size +#define img_convert _img_convert +#define avcodec_alloc_frame _avcodec_alloc_frame +#define avcodec_open _avcodec_open +#define avcodec_find_encoder _avcodec_find_encoder +#define avcodec_encode_video _avcodec_encode_video +#define avcodec_close _avcodec_close +#define av_mallocz _av_mallocz +#define av_free _av_free +#define __av_freep ___av_freep +#define url_fopen _url_fopen +#define url_fclose _url_fclose +#define first_oformat _first_oformat + +void *avcodeclib; +void *avformatlib; + +#ifdef __WIN32__ +#define AVCODECLIB "avcodec.dll" +#define AVFORMATLIB "avformat.dll" +#else +#define AVCODECLIB "libavcodec.so" +#define AVFORMATLIB "libavformat.so" +#endif + +void (*av_register_all)(void); +AVStream *(*av_new_stream)(AVFormatContext *s, int id); +int (*av_set_parameters)(AVFormatContext *s, AVFormatParameters *ap); +int (*av_write_header)(AVFormatContext *s); +int (*av_write_frame)(AVFormatContext *s, int stream_index, const uint8_t *buf, + int size); +int (*av_write_trailer)(AVFormatContext *s); +int (*avpicture_fill)(AVPicture *picture, uint8_t *ptr, + int pix_fmt, int width, int height); +int (*avpicture_get_size)(int pix_fmt, int width, int height); +int (*img_convert)(AVPicture *dst, int dst_pix_fmt, + AVPicture *src, int pix_fmt, + int width, int height); +AVFrame *(*avcodec_alloc_frame)(void); +int (*avcodec_open)(AVCodecContext *avctx, AVCodec *codec); + +AVCodec *(*avcodec_find_encoder)(enum CodecID id); +int (*avcodec_encode_video)(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVFrame *pict); +int (*avcodec_close)(AVCodecContext *avctx); +void *(*av_mallocz)(unsigned int size); +void (*av_free)(void *ptr); +void (*__av_freep)(void **ptr); +int (*url_fopen)(URLContext **h, const char *filename, int flags); +int (*url_fclose)(URLContext *h); +AVOutputFormat **first_oformat; + +int recLoad() { + avcodeclib = SysLoadLibrary(AVCODECLIB); + if (avcodeclib == NULL) { + printf("Couldn't load %s: %s\n", AVCODECLIB, SysLibError()); + return -1; + } + avformatlib = SysLoadLibrary(AVFORMATLIB); + if (avformatlib == NULL) { + printf("Couldn't load %s: %s\n", AVFORMATLIB, SysLibError()); + return -1; + } + av_register_all = SysLoadSym(avformatlib, "av_register_all"); + av_new_stream = SysLoadSym(avformatlib, "av_new_stream"); + av_set_parameters = SysLoadSym(avformatlib, "av_set_parameters"); + av_write_header = SysLoadSym(avformatlib, "av_write_header"); + av_write_frame = SysLoadSym(avformatlib, "av_write_frame"); + av_write_trailer = SysLoadSym(avformatlib, "av_write_trailer"); + avpicture_fill = SysLoadSym(avcodeclib, "avpicture_fill"); + avpicture_get_size = SysLoadSym(avcodeclib, "avpicture_get_size"); + img_convert = SysLoadSym(avcodeclib, "img_convert"); + avcodec_alloc_frame = SysLoadSym(avcodeclib, "avcodec_alloc_frame"); + avcodec_open = SysLoadSym(avcodeclib, "avcodec_open"); + avcodec_find_encoder = SysLoadSym(avcodeclib, "avcodec_find_encoder"); + avcodec_encode_video = SysLoadSym(avcodeclib, "avcodec_encode_video"); + avcodec_close = SysLoadSym(avcodeclib, "avcodec_close"); + av_mallocz = SysLoadSym(avcodeclib, "av_mallocz"); + av_free = SysLoadSym(avcodeclib, "av_free"); + __av_freep = SysLoadSym(avcodeclib, "__av_freep"); + url_fopen = SysLoadSym(avformatlib, "url_fopen"); + url_fclose = SysLoadSym(avformatlib, "url_fclose"); + first_oformat = SysLoadSym(avformatlib, "first_oformat"); + + return 0; +} + +void recUnload() { + SysLoadLibrary(avcodeclib); + SysLoadLibrary(avformatlib); +} + +void recOpen() { + AVOutputFormat *fmt; + AVCodecContext *codec_ctx; + AVCodec *codec; + char filename[256]; + int video_codec; + + if (output != NULL) recClose(); + + if (recLoad() == -1) { + conf.record = 0; return; + } + + av_register_all(); + + switch (conf.codec) { + case 1: // divx + video_codec = CODEC_ID_MPEG4; + sprintf(filename, "gssoft.avi"); + break; + case 2: // mpeg2 + video_codec = CODEC_ID_MPEG2VIDEO; + sprintf(filename, "gssoft.mpg"); + break; + default: // mpeg1 + video_codec = CODEC_ID_MPEG1VIDEO; + sprintf(filename, "gssoft.mpg"); + break; + } + + fmt = *first_oformat; + while (fmt != NULL) { + if (fmt->video_codec == video_codec) break; + fmt = fmt->next; + } + if (fmt == NULL) { + SysMessage("codec not found"); + conf.record = 0; return; + } + + output = av_mallocz(sizeof(AVFormatContext)); + if (output == NULL) { + SysMessage("Out of Memory"); + conf.record = 0; return; + } + + output->oformat = fmt; + snprintf(output->filename, sizeof(output->filename), "%s", filename); + + stream = av_new_stream(output, 0); + if (stream == NULL) { + SysMessage("Out of Memory"); + conf.record = 0; return; + } + codec_ctx = &stream->codec; + codec_ctx->codec_id = video_codec; + codec_ctx->codec_type = CODEC_TYPE_VIDEO; + codec_ctx->bit_rate = 400000; + codec_ctx->width = cmode->width; + codec_ctx->height = cmode->height; + codec_ctx->frame_rate = gs.SMODE1.cmod & 1 ? 50 : 60; + codec_ctx->frame_rate_base = 1; + if (conf.codec == 0) { + codec_ctx->gop_size = 10; + codec_ctx->max_b_frames = 1; + } + + if (av_set_parameters(output, NULL) < 0) { + SysMessage("set parameters failed"); + conf.record = 0; return; + } + + codec = avcodec_find_encoder(codec_ctx->codec_id); + if (codec == NULL) { + SysMessage("codec not found"); + conf.record = 0; return; + } + if (avcodec_open(codec_ctx, codec) < 0) { + SysMessage("Unable to open codec"); + conf.record = 0; return; + } + + if (url_fopen(&output->pb, filename, URL_WRONLY) < 0) { + SysMessage("Unable to open %s for writing", filename); + conf.record = 0; return; + } + + av_write_header(output); + + picture = avcodec_alloc_frame(); + yuv420p = avcodec_alloc_frame(); + + outbuf_size = 100000; + outbuf = malloc(outbuf_size); + if (outbuf == NULL) { + SysMessage("Out of Memory"); + conf.record = 0; return; + } + + picture_size = avpicture_get_size(PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); + picture_buf = malloc(picture_size); + if (picture_buf == NULL) { + SysMessage("Out of Memory"); + conf.record = 0; return; + } + + avpicture_fill((AVPicture*)yuv420p, picture_buf, PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); +} + +void recFrame(char *sbuff, int lPitch, int bpp) { + int size; + int pix_fmt; + + picture->data[0] = sbuff; + picture->linesize[0] = lPitch; + switch (bpp) { + case 15: pix_fmt = PIX_FMT_RGB555; break; + case 16: pix_fmt = PIX_FMT_RGB565; break; + case 24: pix_fmt = PIX_FMT_RGB24; break; + case 32: pix_fmt = PIX_FMT_RGBA32; break; + default: return; + } + img_convert((AVPicture*)yuv420p, PIX_FMT_YUV420P, (AVPicture*)picture, pix_fmt, stream->codec.width, stream->codec.height); + size = avcodec_encode_video(&stream->codec, outbuf, outbuf_size, yuv420p); + if (size == -1) { + printf("error encoding frame\n"); return; + } + + av_write_frame(output, stream->index, outbuf, size); +} + +int recExist() { + if (recLoad() == -1) return -1; + recUnload(); + return 0; +} + +void recClose() { + avcodec_close(&stream->codec); + free(outbuf); + free(picture_buf); + free(picture); + free(yuv420p); + + av_write_trailer(output); + url_fclose(&output->pb); + av_freep(&output->streams[0]); + av_free(output); output = NULL; + + recUnload(); +} + diff --git a/plugins/gs/GSsoft/Src/Rec.h b/plugins/gs/GSsoft/Src/Rec.h new file mode 100644 index 0000000000..eeff7a8be7 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Rec.h @@ -0,0 +1,27 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __REC_H__ +#define __REC_H__ + +void recOpen(); +void recFrame(char *sbuff, int lPitch, int bpp); +int recExist(); +void recClose(); + +#endif /* __REC_H__ */ diff --git a/plugins/gs/GSsoft/Src/Regs.c b/plugins/gs/GSsoft/Src/Regs.c new file mode 100644 index 0000000000..9c123781c5 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Regs.c @@ -0,0 +1,1159 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Rec.h" +#include "Page.h" +#include "Transfer.h" +#include "Cache.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) + +#endif + +int primTableC[8] = {1, 2, 2, 3, 3, 3, 2, 0}; +void (*primTable[8])(Vertex *v); + +int pmode=0; + +void CSRwrite(u32 value) { + gs.CSRw = value; + if (value & 0x1) gs.CSRr&= ~0x1; + if (value & 0x2) gs.CSRr&= ~0x2; + if (value & 0x200) { // reset + GSreset(); + } +} + +void IMRwrite(u32 value) { + gs.IMR = value; +} + +void writePMODE(u32 *data) { +#ifdef PREG_LOG + PREG_LOG("GSwrite PMODE value %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + + gs.PMODE.en[0] = (data[0] ) & 0x1; + gs.PMODE.en[1] = (data[0] >> 1) & 0x1; + gs.PMODE.crtmd = (data[0] >> 2) & 0x7; + gs.PMODE.mmod = (data[0] >> 5) & 0x1; + gs.PMODE.amod = (data[0] >> 6) & 0x1; + gs.PMODE.slbg = (data[0] >> 7) & 0x1; + gs.PMODE.alp = (data[0] >> 8) & 0xff; +} + +void writeSMODE1(u32 *data) { + int cmod; + +#ifdef PREG_LOG + PREG_LOG("GSwrite SMODE1 value %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + cmod = (data[0] >> 13) & 0x3; + if (gs.SMODE1.cmod != cmod) { + gs.SMODE1.cmod = cmod; + if (conf.record) recOpen(); + } + + gs.SMODE1.rc = (data[0] ) & 0x7; + gs.SMODE1.lc = (data[0] >> 3) & 0x1f; + gs.SMODE1.t1248 = (data[0] >> 10) & 0x3; + gs.SMODE1.slck = (data[0] >> 12) & 0x1; +// gs.SMODE1.cmod = (data[0] >> 13) & 0x3; + gs.SMODE1.ex = (data[0] >> 15) & 0x1; + gs.SMODE1.prst = (data[0] >> 16) & 0x1; + gs.SMODE1.sint = (data[0] >> 17) & 0x1; + gs.SMODE1.xpck = (data[0] >> 18) & 0x1; + gs.SMODE1.pck2 = (data[0] >> 19) & 0x1; + gs.SMODE1.spml = (data[0] >> 21) & 0xf; + gs.SMODE1.gcont = (data[0] >> 25) & 0x1; + gs.SMODE1.phs = (data[0] >> 26) & 0x1; + gs.SMODE1.pvs = (data[0] >> 27) & 0x1; + gs.SMODE1.pehs = (data[0] >> 28) & 0x1; + gs.SMODE1.pevs = (data[0] >> 29) & 0x1; + gs.SMODE1.clksel= (data[0] >> 30) & 0x3; + gs.SMODE1.nvck = (data[1] ) & 0x1; + gs.SMODE1.slck2 = (data[1] >> 1) & 0x1; + gs.SMODE1.vcksel= (data[1] >> 2) & 0x3; + gs.SMODE1.vhp = (data[1] >> 4);// & 0x7; + + DXsetGSmode(640, gs.SYNCV.vfp & 1 ? gs.SYNCV.vdp : gs.SYNCV.vdp/2); +} + +void writeSMODE2(u32 *data) { +#ifdef PREG_LOG + PREG_LOG("GSwrite SMODE2 value %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + gs.SMODE2.inter = (data[0] ) & 0x1; + gs.SMODE2.ffmd = (data[0] >> 1) & 0x1; + gs.SMODE2.dpms = (data[0] >> 2) & 0x3; +} + +void writeSYNCH1(u32 *data) { +#ifdef PREG_LOG + PREG_LOG("GSwrite SYNCH1 value %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + gs.SYNCH1.hfp = (data[0] ) & 0x7ff; + gs.SYNCH1.fbp = (data[0] >> 11) & 0x7ff; + gs.SYNCH1.hseq = (data[0] >> 22) & 0x3ff; + gs.SYNCH1.hsvs = (data[1] ) & 0x7ff; + gs.SYNCH1.hs = (data[1] >> 11);// & 0x3ff; +} + +void writeSYNCH2(u32 *data) { +#ifdef PREG_LOG + PREG_LOG("GSwrite SYNCH2 value %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + gs.SYNCH2.hf = (data[0] ) & 0x7ff; + gs.SYNCH2.hb = (data[0] >> 11);//\ & 0x7ff; +} + +void writeSYNCHV(u32 *data) { + gs.SYNCV.vfp = (data[0] ) & 0x3ff; + gs.SYNCV.vfpe = (data[0] >> 10) & 0x3ff; + gs.SYNCV.vbp = (data[0] >> 20) & 0xfff; + gs.SYNCV.vbpe = (data[1] ) & 0x3ff; + gs.SYNCV.vdp = (data[1] >> 10) & 0x7ff; + gs.SYNCV.vs = (data[1] >> 21);//\ & 0x7ff; + +#ifdef PREG_LOG + PREG_LOG("GSwrite SYNCV value %8.8lx_%8.8lx: vfp=0x%x vfpe=0x%x vbp=0x%x vbpe=0x%x vdp=0x%x vs=0x%x\n", data[1], data[0], + gs.SYNCV.vfp, gs.SYNCV.vfpe, gs.SYNCV.vbp, gs.SYNCV.vbpe, gs.SYNCV.vdp, gs.SYNCV.vs); +#endif +} + +void writeDISPFB(u32 *data, int i) { +#ifdef PREG_LOG + PREG_LOG("GSwrite DISPFB%d value %8.8lx_%8.8lx\n", i+1, data[1], data[0]); +#endif + gs.DISPFB[i].fbp =((data[0] ) & 0x1ff) * 32; + gs.DISPFB[i].fbw =((data[0] >> 9) & 0x3f) * 64; + gs.DISPFB[i].psm = (data[0] >> 15) & 0x1f; + gs.DISPFB[i].dbx = (data[1] ) & 0x7ff; + gs.DISPFB[i].dby = (data[1] >> 11) & 0x7ff; + if (gs.DISPFB[i].fbw > 0) { + gs.DISPFB[i].fbh = ((4/TextureSizeGS(1, 1, gs.DISPFB[i].psm))*1024*1024) / gs.DISPFB[i].fbw; + } else { + gs.DISPFB[i].fbh = 1024*1024; + } +#ifdef PREG_LOG + PREG_LOG("dispfb%d fbp=0x%x fbw=%d fbh=%d psm=0x%x db %d,%d\n", i+1, + gs.DISPFB[i].fbp, gs.DISPFB[i].fbw, gs.DISPFB[i].fbh, + gs.DISPFB[i].psm, gs.DISPFB[i].dbx, gs.DISPFB[i].dby); +#endif +} + +void writeDISPLAY(u32 *data, int i) { + int magh, magv; + + magh = ((data[0] >> 23) & 0xf) + 1; + magv = ((data[0] >> 27) & 0x3) + 1; +// gs.DISPLAY[i].x = ((data[0] ) & 0xfff) / magh; +// gs.DISPLAY[i].y = ((data[0] >> 12) & 0x7ff) / magv; + gs.DISPLAY[i].w = (((data[1] ) & 0xfff) / magh) + 1; + gs.DISPLAY[i].h = (((data[1] >> 12) & 0x7ff) / magv) + 1; + +// if(((gs.SMODE2.inter == 0) || (gs.SMODE2.ffmd == 1)) && (gs.DISPLAY[1].h > 256)) + if (gs.SMODE2.inter && gs.SMODE2.ffmd) + gs.DISPLAY[i].h >>= 1; + +#ifdef PREG_LOG + PREG_LOG("GSwrite DISPLAY%d value %8.8lx_%8.8lx: mode = %dx%d %dx%d, magh=%d, magv=%d\n", + i+1, data[1], data[0], + gs.DISPLAY[i].x, gs.DISPLAY[i].y, gs.DISPLAY[i].w, + gs.DISPLAY[i].h, magh, magv); +#endif +} + +void BUSDIRwrite(u32 value) { + gs.BUSDIR = value; +} + +void CALLBACK GSwrite8(u32 mem, u8 value) { +} + +void CALLBACK GSwrite16(u32 mem, u16 value) { +} + +void CALLBACK GSwrite32(u32 mem, u32 value) { + u32 data[2]; + + data[0] = value; data[1] = 0; + switch (mem) { + case 0x12000000: // PMODE + writePMODE(data); + break; + + case 0x12000070: // DISPFB1 + writeDISPFB(data, 0); + break; + + case 0x12000090: // DISPFB2 + writeDISPFB(data, 1); + break; + + case 0x12001000: // CSR +#ifdef PREG_LOG + PREG_LOG("GSwrite32 CSR (%x) value %8.8lx\n", mem, value); +#endif + CSRwrite(value); + break; + + case 0x12001010: // IMR +#ifdef PREG_LOG + PREG_LOG("GSwrite32 IMR (%x) value %8.8lx\n", mem, value); +#endif + IMRwrite(value); + break; + + case 0x12001040: // BUSDIR + BUSDIRwrite(value); + break; + + case 0x12001080: // SIGLBLID +#ifdef PREG_LOG + PREG_LOG("GSwrite32 SIGLBLID (%x) value %8.8lx\n", mem, value); +#endif + gs.SIGLBLID.sigid = value; + break; + + default: +#ifdef PREG_LOG + PREG_LOG("GSwrite32 unknown mem %x value %8.8lx\n", mem, value); +#endif + break; + } +} + +void CALLBACK GSwrite64(u32 mem, u64 value) { + u32 data[2]; + + *(u64*)data = value; + switch (mem) { + case 0x12000000: // PMODE + writePMODE(data); + break; + + case 0x12000010: // SMODE1 + writeSMODE1(data); + break; + + case 0x12000020: // SMODE2 + writeSMODE2(data); + break; + + case 0x12000030: // SRFSH +#ifdef PREG_LOG + PREG_LOG("GSwrite64 SRFSH (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + + case 0x12000040: // SYNCH1 + writeSYNCH1(data); + break; + + case 0x12000050: // SYNCH2 + writeSYNCH2(data); + break; + + case 0x12000060: // SYNCV + writeSYNCHV(data); + break; + + case 0x12000070: // DISPFB1 + writeDISPFB(data, 0); + break; + + case 0x12000080: // DISPLAY1 + writeDISPLAY(data, 0); + break; + + case 0x12000090: // DISPFB2 + writeDISPFB(data, 1); + break; + + case 0x120000A0: // DISPLAY2 + writeDISPLAY(data, 1); + break; + + case 0x120000B0: // EXTBUF +#ifdef PREG_LOG + PREG_LOG("GSwrite64 EXTBUF (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + + case 0x120000C0: // EXTDATA +#ifdef PREG_LOG + PREG_LOG("GSwrite64 EXTDATA (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + + case 0x120000D0: // EXTWRITE +#ifdef PREG_LOG + PREG_LOG("GSwrite64 EXTWRITE (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + + case 0x120000E0: // BGCOLOR +#ifdef PREG_LOG + PREG_LOG("GSwrite64 BGCOLOR (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + + case 0x12001000: // CSR +#ifdef PREG_LOG + PREG_LOG("GSwrite64 CSR (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + CSRwrite(*data); + break; + + case 0x12001010: // IMR +#ifdef PREG_LOG + PREG_LOG("GSwrite64 IMR (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + IMRwrite(*data); + break; + + case 0x12001040: // BUSDIR + BUSDIRwrite(*data); + break; + + case 0x12001080: // SIGLBLID +#ifdef PREG_LOG + PREG_LOG("GSwrite64 SIGLBLID (%x) value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + gs.SIGLBLID.sigid = data[0]; + gs.SIGLBLID.lblid = data[1]; + break; + + default: +#ifdef PREG_LOG + PREG_LOG("GSwrite64 unknown mem %x value %8.8lx_%8.8lx\n", mem, *(data+1), *data); +#endif + break; + } +} + +u8 CALLBACK GSread8(u32 mem) { + u8 ret; + + ret = GSread32(mem & ~3) >> ((mem & 3) * 8); +/* switch (mem) { + case 0x12001000: // CSR + ret = gs.interlace << 13; + ret|= gs.CSRr; + return ret; + + case 0x12001080: // SIGLBLID + ret = gs.SIGLBLID.sigid; + break; + + default: + ret = 0; + break; + }*/ + +#ifdef PREG_LOG + PREG_LOG("GSread8 mem %x ret %8.8lx\n", mem, ret); +#endif + return ret; +} + +u16 CALLBACK GSread16(u32 mem) { + u16 ret; + + ret = GSread32(mem & ~3) >> ((mem & 3) * 8); +/* switch (mem) { + case 0x12001000: // CSR + ret = gs.interlace << 13; + ret|= gs.CSRr; + return ret; + + case 0x12001080: // SIGLBLID + ret = gs.SIGLBLID.sigid; + break; + + default: + ret = 0; + break; + }*/ + +#ifdef PREG_LOG + PREG_LOG("GSread16 mem %x ret %8.8lx\n", mem, ret); +#endif + return ret; +} + +u32 CALLBACK GSread32(u32 mem) { + u32 ret; + + switch (mem) { + case 0x12001000: // CSR +// gs.interlace = 1 - gs.interlace; + ret = gs.interlace << 13; + ret|= gs.CSRr; + return ret; + + case 0x12001080: // SIGLBLID + ret = gs.SIGLBLID.sigid; + break; + + default: + ret = 0; + break; + } + +#ifdef PREG_LOG + PREG_LOG("GSread32 mem %x ret %8.8lx\n", mem, ret); +#endif + return ret; +} + +u64 CALLBACK GSread64(u32 mem) { + u64 ret; + + switch (mem) { + case 0x12000400: // ??? +// gs.interlace = 1 - gs.interlace; + ret = gs.interlace << 13; + break; + + case 0x12001000: // CSR +// gs.interlace = 1 - gs.interlace; + ret = gs.interlace << 13; + ret|= gs.CSRr; + return ret; + + case 0x12001080: // SIGLBLID + ret = (u64)gs.SIGLBLID.sigid | + ((u64)gs.SIGLBLID.lblid << 32); + break; + + default: + ret = 0; + break; + } +#ifdef PREG_LOG + PREG_LOG("GSread64 mem %x ret %8.8lx_%8.8lx\n", mem, (u32)(ret>>32), (u32)ret); +#endif + return ret; +} + + +void primWrite(u32 *data) { + if (data[1] || data[0] & ~0x3ff) { +#ifdef WARN_LOG + WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + } + + prim->prim = (data[0] ) & 0x7; + if (gs.prac == 0) return; +// prim->prim = (data[0] ) & 0x7; + prim->iip = (data[0] >> 3) & 0x1; + prim->tme = (data[0] >> 4) & 0x1; + prim->fge = (data[0] >> 5) & 0x1; + prim->abe = (data[0] >> 6) & 0x1; + prim->aa1 = (data[0] >> 7) & 0x1; + prim->fst = (data[0] >> 8) & 0x1; + prim->ctxt = (data[0] >> 9) & 0x1; + prim->fix = (data[0] >> 10) & 0x1; + gsSetCtxt(prim->ctxt); + gs.primC = 0; + +#ifdef GREG_LOG + GREG_LOG("prim %8.8lx_%8.8lx prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + data[1], data[0], prim->prim, prim->iip, prim->tme, prim->fge, prim->abe, prim->aa1, prim->fst, prim->ctxt, prim->fix); +#endif +} + +void tex0Write(int i, u32 *data) { + gs._tex0[i].tbp0 = (data[0] & 0x3fff); + gs._tex0[i].tbw = ((data[0] >> 14) & 0x3f) * 64; + gs._tex0[i].psm = (data[0] >> 20) & 0x3f; + gs._tex0[i].tw = (data[0] >> 26) & 0xf; + if (gs._tex0[i].tw > 10) gs._tex0[i].tw = 10; + gs._tex0[i].tw = (int)pow(2, (double)gs._tex0[i].tw); + gs._tex0[i].th = ((data[0] >> 30) & 0x3) | ((data[1] & 0x3) << 2); + if (gs._tex0[i].th > 10) gs._tex0[i].th = 10; + gs._tex0[i].th = (int)pow(2, (double)gs._tex0[i].th); + gs._tex0[i].tcc = (data[1] >> 2) & 0x1; + gs._tex0[i].tfx = (data[1] >> 3) & 0x3; + gs._tex0[i].cbp = ((data[1] >> 5) & 0x3fff); + gs._tex0[i].cpsm = (data[1] >> 19) & 0xf; + gs._tex0[i].csm = (data[1] >> 23) & 0x1; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("tex0_%d %8.8lx_%8.8lx tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d\n", + i+1, data[1], data[0], + gs._tex0[i].tbp0, gs._tex0[i].tbw, gs._tex0[i].psm, gs._tex0[i].tw, + gs._tex0[i].th, gs._tex0[i].tcc, gs._tex0[i].tfx, gs._tex0[i].cbp, + gs._tex0[i].cpsm, gs._tex0[i].csm); +#endif + +/* if (conf.log) { + SetTexture(); + DumpTexture(); + }*/ + if (gs._tex0[i].tbw == 0) gs._tex0[i].tbw = 64; +} + +void frameWrite(int i, u32 *data) { + gs._gsfb[i].fbp = ((data[0] ) & 0x1ff) * 32; + gs._gsfb[i].fbw = ((data[0] >> 16) & 0x3f) * 64; + gs._gsfb[i].psm = (data[0] >> 24) & 0x3f; + gs._gsfb[i].fbm = data[1]; + if (gs._gsfb[i].fbw > 0) gs._gsfb[i].fbh = (1024*1024) / gs._gsfb[i].fbw; + else gs._gsfb[i].fbh = 1024*1024; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("frame_%d %8.8lx_%8.8lx: fbp=0x%x fbw=%d psm=0x%x fbm=0x%x\n", + i+1, data[1], data[0], + gs._gsfb[i].fbp, gs._gsfb[i].fbw, gs._gsfb[i].psm, gs._gsfb[i].fbm); +#endif +} + +void testWrite(int i, u32 *data) { + gs._test[i].ate = (data[0] ) & 0x1; + gs._test[i].atst = (data[0] >> 1) & 0x7; + gs._test[i].aref = (data[0] >> 4) & 0xff; + gs._test[i].afail = (data[0] >> 12) & 0x3; + gs._test[i].date = (data[0] >> 14) & 0x1; + gs._test[i].datm = (data[0] >> 15) & 0x1; + gs._test[i].zte = (data[0] >> 16) & 0x1; + gs._test[i].ztst = (data[0] >> 17) & 0x3; + +#ifdef GREG_LOG + GREG_LOG("test_%d %8.8lx_%8.8lx: ate=%x atst=%x aref=%x afail=%x date=%x datm%x zte=%x ztst=%x\n", + i+1, data[1], data[0], + gs._test[0].ate, gs._test[0].atst, gs._test[0].aref, + gs._test[0].afail, gs._test[0].date, gs._test[0].datm, + gs._test[0].zte, gs._test[0].ztst); +#endif +} + +void clampWrite(int i, u32 *data) { + gs._clamp[i].wms = (data[0] ) & 0x2; + gs._clamp[i].wmt = (data[0] >> 2) & 0x2; + gs._clamp[i].minu = (data[0] >> 4) & 0x3ff; + gs._clamp[i].maxu = (data[0] >> 14) & 0x3ff; + gs._clamp[i].minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + gs._clamp[i].maxv = (data[1] >> 2) & 0x3ff; + +#ifdef GREG_LOG + GREG_LOG("clamp_%d %8.8lx_%8.8lx: wms=%x wmt=%x minu=%x maxu=%x minv=%x maxv=%x\n", i, data[1], data[0], + gs._clamp[i].wms, gs._clamp[i].wmt, + gs._clamp[i].minu, gs._clamp[i].maxu, + gs._clamp[i].minv, gs._clamp[i].maxv); +#endif +} + +/* + * GSwrite: 128bit wide + */ +void GSwrite(u32 *data, int reg) { + int i; + + switch (reg) { + case 0x00: // prim + primWrite(data); + break; + + case 0x01: // rgbaq + gs.gsvertex[gs.primC].rgba = data[0]; + gs.gsvertex[gs.primC].q = data[1]; + gs.rgba = data[0]; + gs.q = data[1]; + +#ifdef GREG_LOG + GREG_LOG("rgbaq %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x02: // st + gs.gsvertex[gs.primC].s = data[0]; + gs.gsvertex[gs.primC].t = data[1]; + + +#ifdef GREG_LOG + GREG_LOG("st %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x03: // uv + gs.gsvertex[gs.primC].u = (data[0] >> 4) & 0x7ff; + gs.gsvertex[gs.primC].v = (data[0] >> (16+4)) & 0x7ff; + +#ifdef GREG_LOG + GREG_LOG("uv %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x04: // xyzf2 + gs.gsvertex[gs.primC].x = (data[0] >> 4) & 0xfff; + gs.gsvertex[gs.primC].y = (data[0] >> (16+4)) & 0xfff; + gs.gsvertex[gs.primC].z = data[1] & 0xffffff; + gs.gsvertex[gs.primC].f = data[1] >> 24; + gs.primC++; + +#ifdef GREG_LOG + GREG_LOG("xyzf2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + + if (gs.primC >= primTableC[prim->prim]) { +#ifdef GREG_LOG + GREG_LOG("prim %x\n", prim->prim); +#endif + primTable[prim->prim](gs.gsvertex); + ppf++; + } + break; + + case 0x05: // xyz2 + gs.gsvertex[gs.primC].x = (data[0] >> 4) & 0xfff; + gs.gsvertex[gs.primC].y = (data[0] >> (16+4)) & 0xfff; + gs.gsvertex[gs.primC].z = data[1]; + gs.primC++; + +#ifdef GREG_LOG + GREG_LOG("xyz2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + + if (gs.primC >= primTableC[prim->prim]) { +#ifdef GREG_LOG + GREG_LOG("prim %x\n", prim->prim); +#endif + primTable[prim->prim](gs.gsvertex); + ppf++; + } + break; + + case 0x06: // tex0_1 + tex0Write(0, data); + break; + + case 0x07: // tex0_2 + tex0Write(1, data); + break; + + case 0x08: // clamp_1 + clampWrite(0, data); + break; + + case 0x09: // clamp_2 + clampWrite(1, data); + break; + + case 0x0a: // fog + gs.fogf = data[1] >> 24; + +#ifdef GREG_LOG + GREG_LOG("fogH %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x0c: // xyzf3 + gs.gsvertex[gs.primC].x = (data[0] >> 4) & 0xfff; + gs.gsvertex[gs.primC].y = (data[0] >> (16+4)) & 0xfff; + gs.gsvertex[gs.primC].z = data[1] & 0xffffff; + gs.gsvertex[gs.primC].f = data[1] >> 24; + gs.primC++; + +#ifdef GREG_LOG + GREG_LOG("xyzf3 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + if (gs.primC >= primTableC[prim->prim]) { + primTable[prim->prim](NULL); + } + break; + + case 0x0d: // xyz3 + gs.gsvertex[gs.primC].x = (data[0] >> 4) & 0xfff; + gs.gsvertex[gs.primC].y = (data[0] >> (16+4)) & 0xfff; + gs.gsvertex[gs.primC].z = data[1]; + gs.primC++; + +#ifdef GREG_LOG + GREG_LOG("xyz3 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + if (gs.primC >= primTableC[prim->prim]) { + primTable[prim->prim](NULL); + } + break; + + case 0x14: // tex1_1 + gs._tex1[0].lcm = (data[0] ) & 0x1; + gs._tex1[0].mxl = (data[0] >> 2) & 0x7; + gs._tex1[0].mmag = (data[0] >> 5) & 0x1; + gs._tex1[0].mmin = (data[0] >> 6) & 0x7; + gs._tex1[0].mtba = (data[0] >> 9) & 0x1; + gs._tex1[0].l = (data[0] >> 19) & 0x3; + gs._tex1[0].k = (data[1] >> 4) & 0xff; + +#ifdef GREG_LOG + GREG_LOG("tex1_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x15: // tex1_2 + gs._tex1[1].lcm = (data[0] ) & 0x1; + gs._tex1[1].mxl = (data[0] >> 2) & 0x7; + gs._tex1[1].mmag = (data[0] >> 5) & 0x1; + gs._tex1[1].mmin = (data[0] >> 6) & 0x7; + gs._tex1[1].mtba = (data[0] >> 9) & 0x1; + gs._tex1[1].l = (data[0] >> 19) & 0x3; + gs._tex1[1].k = (data[1] >> 4) & 0xff; + +#ifdef GREG_LOG + GREG_LOG("tex1_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x16: // tex2_1 + gs._tex2[0].psm = (data[0] >> 20) & 0x3f; + gs._tex2[0].cbp = (data[1] >> 5) & 0x3fff; + gs._tex2[0].cpsm = (data[1] >> 19) & 0xf; + gs._tex2[0].csm = (data[1] >> 23) & 0x1; + gs._tex2[0].csa = (data[1] >> 24) & 0x1f; + gs._tex2[0].cld = (data[1] >> 29) & 0x7; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("tex2_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x17: // tex2_2 + gs._tex2[1].psm = (data[0] >> 20) & 0x3f; + gs._tex2[1].cbp = (data[1] >> 5) & 0x3fff; + gs._tex2[1].cpsm = (data[1] >> 19) & 0xf; + gs._tex2[1].csm = (data[1] >> 23) & 0x1; + gs._tex2[1].csa = (data[1] >> 24) & 0x1f; + gs._tex2[1].cld = (data[1] >> 29) & 0x7; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("tex2_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x18: // xyoffset_1 + gs._offset[0].x = (data[0] >> 4) & 0xfff; + gs._offset[0].y = (data[1] >> 4) & 0xfff; + +#ifdef GREG_LOG + GREG_LOG("xyoffset_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x19: // xyoffset_2 + gs._offset[1].x = (data[0] >> 4) & 0xfff; + gs._offset[1].y = (data[1] >> 4) & 0xfff; + +#ifdef GREG_LOG + GREG_LOG("xyoffset_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x1a: // prmodecont + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + +#ifdef GREG_LOG + GREG_LOG("prmodecont %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x1b: // prmode + if (gs.prac == 1) break; + prim->iip = (data[0] >> 3) & 0x1; + prim->tme = (data[0] >> 4) & 0x1; + prim->fge = (data[0] >> 5) & 0x1; + prim->abe = (data[0] >> 6) & 0x1; + prim->aa1 = (data[0] >> 7) & 0x1; + prim->fst = (data[0] >> 8) & 0x1; + prim->ctxt = (data[0] >> 9) & 0x1; + prim->fix = (data[0] >> 10) & 0x1; + gsSetCtxt(prim->ctxt); + gs.primC = 0; + +#ifdef GREG_LOG + GREG_LOG("prmode %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x1c: // texclut + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; + +#ifdef GREG_LOG + GREG_LOG("texclut %8.8lx_%8.8lx: cbw=%x, cou=%d, cov=%d\n", + data[1], data[0], gs.clut.cbw, gs.clut.cou, gs.clut.cov); +#endif + break; + + case 0x22: // scanmsk + gs.smask = data[0] & 0x3; + +#ifdef GREG_LOG + GREG_LOG("scanmsk %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x34: // miptbp1_1 + gs._miptbp0[0].tbp[0] = (data[0] ) & 0x3fff; + gs._miptbp0[0].tbw[0] = (data[0] >> 14) & 0x3f; + gs._miptbp0[0].tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + gs._miptbp0[0].tbw[1] = (data[1] >> 2) & 0x3f; + gs._miptbp0[0].tbp[2] = (data[1] >> 8) & 0x3fff; + gs._miptbp0[0].tbw[2] = (data[1] >> 22) & 0x3f; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("miptbp1_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x35: // miptbp1_2 + gs._miptbp0[1].tbp[0] = (data[0] ) & 0x3fff; + gs._miptbp0[1].tbw[0] = (data[0] >> 14) & 0x3f; + gs._miptbp0[1].tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + gs._miptbp0[1].tbw[1] = (data[1] >> 2) & 0x3f; + gs._miptbp0[1].tbp[2] = (data[1] >> 8) & 0x3fff; + gs._miptbp0[1].tbw[2] = (data[1] >> 22) & 0x3f; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("miptbp1_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x36: // miptbp2_1 + gs._miptbp1[0].tbp[0] = (data[0] ) & 0x3fff; + gs._miptbp1[0].tbw[0] = (data[0] >> 14) & 0x3f; + gs._miptbp1[0].tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + gs._miptbp1[0].tbw[1] = (data[1] >> 2) & 0x3f; + gs._miptbp1[0].tbp[2] = (data[1] >> 8) & 0x3fff; + gs._miptbp1[0].tbw[2] = (data[1] >> 22) & 0x3f; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("miptbp2_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x37: // miptbp2_2 + gs._miptbp1[1].tbp[0] = (data[0] ) & 0x3fff; + gs._miptbp1[1].tbw[0] = (data[0] >> 14) & 0x3f; + gs._miptbp1[1].tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + gs._miptbp1[1].tbw[1] = (data[1] >> 2) & 0x3f; + gs._miptbp1[1].tbp[2] = (data[1] >> 8) & 0x3fff; + gs._miptbp1[1].tbw[2] = (data[1] >> 22) & 0x3f; + gsSetCtxt(prim->ctxt); + +#ifdef GREG_LOG + GREG_LOG("miptbp2_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x3b: // texa + gs.texa.ta[0] = data[0] & 0xff; + gs.texa.aem = (data[0] >> 15) & 0x1; + gs.texa.ta[1] = data[1] & 0xff; + +#ifdef GREG_LOG + GREG_LOG("texa %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x3d: // fogcol + gs.fogcol = data[0] & 0xffffff; + +#ifdef GREG_LOG + GREG_LOG("fogcol %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x3f: // texflush +#ifdef GREG_LOG + GREG_LOG("texflush %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x40: // scissor_1 + gs._scissor[0].x0 = (data[0] ) & 0x7ff; + gs._scissor[0].x1 = (data[0] >> 16) & 0x7ff; + gs._scissor[0].y0 = (data[1] ) & 0x7ff; + gs._scissor[0].y1 = (data[1] >> 16) & 0x7ff; +#ifdef GREG_LOG + GREG_LOG("scissor_1 %8.8lx_%8.8lx: %dx%d - %dx%d\n", + data[1], data[0], + gs._scissor[0].x0, gs._scissor[0].y0, gs._scissor[0].x1, gs._scissor[0].y1); +#endif + break; + + case 0x41: // scissor_2 + gs._scissor[1].x0 = (data[0] ) & 0x7ff; + gs._scissor[1].x1 = (data[0] >> 16) & 0x7ff; + gs._scissor[1].y0 = (data[1] ) & 0x7ff; + gs._scissor[1].y1 = (data[1] >> 16) & 0x7ff; +#ifdef GREG_LOG + GREG_LOG("scissor_2 %8.8lx_%8.8lx: %dx%d - %dx%d\n", + data[1], data[0], + gs._scissor[1].x0, gs._scissor[1].y0, gs._scissor[1].x1, gs._scissor[1].y1); +#endif + break; + + case 0x42: // alpha_1 + gs._alpha[0].a = (data[0] ) & 0x3; + gs._alpha[0].b = (data[0] >> 2) & 0x3; + gs._alpha[0].c = (data[0] >> 4) & 0x3; + gs._alpha[0].d = (data[0] >> 6) & 0x3; + gs._alpha[0].fix = (data[1] ) & 0xff; + +#ifdef GREG_LOG + GREG_LOG("alpha_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x43: // alpha_2 + gs._alpha[1].a = (data[0] ) & 0x3; + gs._alpha[1].b = (data[0] >> 2) & 0x3; + gs._alpha[1].c = (data[0] >> 4) & 0x3; + gs._alpha[1].d = (data[0] >> 6) & 0x3; + gs._alpha[1].fix = (data[1] ) & 0xff; + +#ifdef GREG_LOG + GREG_LOG("alpha_2 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x44: // dimx +#ifdef GREG_LOG + GREG_LOG("dimx %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x45: // dthe + gs.dthe = data[0] & 0x1; + +#ifdef GREG_LOG + GREG_LOG("dthe %8.8lx_%8.8lx: dthe = %x\n", data[1], data[0], gs.dthe); +#endif + break; + + case 0x46: // colclamp + gs.colclamp = data[0] & 0x1; + +#ifdef GREG_LOG + GREG_LOG("colclamp %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x47: // test_1 + testWrite(0, data); + break; + + case 0x48: // test_2 + testWrite(1, data); + break; + + case 0x49: // pabe + gs.pabe = *data & 0x1; + +#ifdef GREG_LOG + GREG_LOG("pabe %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x4a: // fba_1 + gs._fba[0].fba = *data & 0x1; + +#ifdef GREG_LOG + GREG_LOG("fba_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x4b: // fba_2 + gs._fba[1].fba = *data & 0x1; + +#ifdef GREG_LOG + GREG_LOG("fba_1 %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x4c: // frame_1 + frameWrite(0, data); + break; + + case 0x4d: // frame_2 + frameWrite(1, data); + break; + + case 0x4e: // zbuf_1 + gs._zbuf[0].zbp = (data[0] & 0x1ff) * 32; + gs._zbuf[0].psm = (data[0] >> 24) & 0xf; + gs._zbuf[0].zmsk = data[1] & 0x1; + +#ifdef GREG_LOG + GREG_LOG("zbuf_1 %8.8lx_%8.8lx: zbp=%x psm=%x zmsk=%x\n", + data[1], data[0], + gs._zbuf[0].zbp, gs._zbuf[0].psm, gs._zbuf[0].zmsk); +#endif + break; + + case 0x4f: // zbuf_2 + gs._zbuf[1].zbp = (data[0] & 0x1ff) * 32; + gs._zbuf[1].psm = (data[0] >> 24) & 0xf; + gs._zbuf[1].zmsk = data[1] & 0x1; + +#ifdef GREG_LOG + GREG_LOG("zbuf_2 %8.8lx_%8.8lx: zbp=%x psm=%x zmsk=%x\n", + data[1], data[0], + gs._zbuf[1].zbp, gs._zbuf[1].psm, gs._zbuf[1].zmsk); +#endif + break; + + case 0x50: // bitbltbuf + gs.srcbuf.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbuf.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbuf.psm = (data[0] >> 24) & 0x3f; + if (gs.srcbuf.bw > 0) gs.srcbuf.bh = (1024*1024) / gs.srcbuf.bw; + else gs.srcbuf.bh = 1024*1024; + gs.dstbuf.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbuf.bw = ((data[1] >> 14) & 0x1ff) * 16; + gs.dstbuf.psm = (data[1] >> 24) & 0x3f; + if (gs.dstbuf.bw > 0) gs.dstbuf.bh = (1024*1024) / gs.dstbuf.bw; + else gs.dstbuf.bh = 1024*1024; + +#ifdef GREG_LOG + GREG_LOG("bitbltbuf %8.8lx_%8.8lx: sbp = %x, sbw = %d, spsm = %x, sbh = %d; dbp = %x, dbw = %d, dpsm = %x, dbh = %d\n", data[1], data[0], + gs.srcbuf.bp, gs.srcbuf.bw, gs.srcbuf.psm, gs.srcbuf.bh, + gs.dstbuf.bp, gs.dstbuf.bw, gs.dstbuf.psm, gs.dstbuf.bh); +#endif + + if (gs.dstbuf.bw == 0) gs.dstbuf.bw = 64; + break; + + case 0x51: // trxpos + gs.trxpos.sx = (data[0] ) & 0x7ff; + gs.trxpos.sy = (data[0] >> 16) & 0x7ff; + gs.trxpos.dx = (data[1] ) & 0x7ff; + gs.trxpos.dy = (data[1] >> 16) & 0x7ff; + gs.trxpos.dir = (data[1] >> 27) & 0x3; +#ifdef GREG_LOG + GREG_LOG("trxpos %8.8lx_%8.8lx: %dx%d %dx%d : dir=%d\n", data[1], data[0], + gs.trxpos.sx, gs.trxpos.sy, gs.trxpos.dx, gs.trxpos.dy, gs.trxpos.dir); +#endif + break; + + case 0x52: // trxreg + gs.imageW = data[0]; + gs.imageH = data[1]; + +#ifdef GREG_LOG + GREG_LOG("trxreg %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + break; + + case 0x53: // trxdir + gs.imageTransfer = data[0] & 0x3; + +#ifdef GREG_LOG + GREG_LOG("trxdir %8.8lx_%8.8lx: gs.imageTransfer = %x\n", data[1], data[0], gs.imageTransfer); +#endif + if (gs.imageTransfer == 0x2) { +#ifdef GREG_LOG + GREG_LOG("moveImage %dx%d %dx%d %dx%d (dir=%d)\n", + gs.trxpos.sx, gs.trxpos.sy, gs.trxpos.dx, gs.trxpos.dy, gs.imageW, gs.imageH, gs.trxpos.dir); +#endif + FBmoveImage(); + break; + } + if (gs.imageTransfer == 1) { +#ifdef GREG_LOG +// GREG_LOG("gs.imageTransferSrc size %lx, %dx%d %dx%d (psm=%x, bp=%x)\n", +// gs.gtag.nloop, gs.trxpos.sx, gs.trxpos.sy, gs.imageW, gs.imageH, gs.srcbuf.psm, gs.srcbuf.bp); +#endif + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + } else { + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + } + + break; + + case 0x60: // signal +#ifdef GREG_LOG + GREG_LOG("signal %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + for (i=0; i<32; i++) { + if (data[1] & (1< +#include +#include + +#include +#include +#include +//#include + +#include "GS.h" +#include "Draw.h" +#include "Rec.h" +#include "scale2x.h" +#if defined(__i386__) || defined(__x86_64__) +#include "ix86.h" +#endif + +SDL_Surface *surf1x; +SDL_Surface *surf2x; +SDL_Surface *surf; +SDL_SysWMinfo info; +//FPSmanager fps; +char gsmsg[256]; +u32 gsmsgscount; +u32 gsmsgcount; + +void DXclearScr() { + SDL_FillRect(surf, NULL, 0); +} + +s32 DXopen() { +#ifdef __LINUX__ + int screen; + int w, h; +#endif + + if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; + + surf = SDL_SetVideoMode(cmode->width, cmode->height, 0, conf.fullscreen ? SDL_FULLSCREEN | SDL_HWSURFACE : SDL_HWSURFACE); + if (surf == NULL) return -1; + + SDL_VERSION(&info.version); + if (SDL_GetWMInfo(&info) == 0) return -1; + +#ifdef __LINUX__ + info.info.x11.lock_func(); + screen = DefaultScreen(info.info.x11.display); + w = DisplayWidth(info.info.x11.display, screen); + h = DisplayHeight(info.info.x11.display, screen); + XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, + cmode->width < w ? (w - cmode->width) / 2 : 0, + cmode->height < h ? (h - cmode->height) / 2 : 0); + info.info.x11.unlock_func(); +#endif + + SDL_WM_SetCaption(GStitle, NULL); + + SETScrBlit(surf->format->BitsPerPixel); + DXclearScr(); + + surf1x = surf2x = NULL; + +// SDL_initFramerate(&fps); +// SDL_setFramerate(&fps, 60); + +#ifdef __WIN32__ + return (s32)info.window; +#else + return (s32)info.info.x11.display; +#endif +} + +void DXclose() { + SDL_Quit(); +} + +void DXcreateSurface1x(int w, int h) { + if (surf1x != NULL) { + if ((w == surf1x->w && + h == surf1x->h)) + return; + + SDL_FreeSurface(surf1x); surf1x = NULL; + } + +/* if (surf->flags & SDL_HWSURFACE) { + surf1x = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, + 0, 0, 0, 0, 0); + if (surf1x == NULL) printf("Error allocating video memory surface, trying with normal memory\n"); + }*/ + if (surf1x == NULL) { + surf1x = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, + surf->format->BitsPerPixel, surf->format->Rmask, + surf->format->Gmask, surf->format->Bmask, + surf->format->Amask); + if (surf1x == NULL) { + SysMessage("Error allocating surface\n"); + exit(1); + } + } +} + +void DXcreateSurface2x(int w, int h) { + if (surf2x != NULL) { + if ((w == surf2x->w && + h == surf2x->h)) + return; + + SDL_FreeSurface(surf2x); surf2x = NULL; + } + +/* if (surf->flags & SDL_HWSURFACE) { + surf2x = SDL_CreateRGBSurface(SDL_HWSURFACE, w*2, h*2, + 0, 0, 0, 0, 0); + if (surf2x == NULL) printf("Error allocating video memory surface, trying with normal memory\n"); + }*/ + if (surf2x == NULL) { + surf2x = SDL_CreateRGBSurface(SDL_SWSURFACE, w*2, h*2, + surf->format->BitsPerPixel, surf->format->Rmask, + surf->format->Gmask, surf->format->Bmask, + surf->format->Amask); + if (surf2x == NULL) conf.filter = 0; + } +} + +void DXblit(int y) { + if (conf.filter) { + SDL_Rect dst; + + if (surf1x == NULL) return; + + SDL_LockSurface(surf1x); + ScrBlit(surf1x, 0); + SDL_UnlockSurface(surf1x); + + scale2x(surf1x, surf2x); + + dst.x = 0; dst.y = y; + dst.w = surf->w; dst.h = surf->h - dst.y; + SDL_SoftStretch(surf2x, NULL, surf, &dst); + } else { + SDL_LockSurface(surf); + ScrBlit(surf, y); + SDL_UnlockSurface(surf); +/* SDL_LockSurface(surf1x); + + ScrBlit(surf1x); + + dst.x = 0; dst.y = y; + dst.w = surf->w; dst.h = surf->h - dst.y; +// SDL_BlitSurface(surf1x, NULL, surf, NULL); + SDL_LockSurface(surf); + SDL_SoftStretch(surf1x, NULL, surf, &dst); + SDL_UnlockSurface(surf); + + SDL_UnlockSurface(surf1x);*/ + } +} + +int DXsetGSmode(int w, int h) { + if (w <= 0 || h <= 0) return 0; + + DXcreateSurface1x(w, h); + if (conf.filter) DXcreateSurface2x(w, h); + return 0; +} + +void DXupdate() { + SDL_Rect rect; + static int to; + static int fpsc, fc; + static u64 cto; + int ticks; + u64 cticks; + int i; +#if defined(__i386__) || defined(__x86_64__) + u64 tick; + + tick = GetCPUTick(); +#endif + + fc++; + + if (conf.fps || conf.frameskip) { + ticks = SDL_GetTicks(); + fpsc = ticks - to; + to = ticks; + } +#if defined(__i386__) || defined(__x86_64__) + cticks = GetCPUTick() - cto; + cto = GetCPUTick(); +#endif + +/* if (conf.frameskip) { + if ((fpscount % 3) == 0) { + norender = 1; + } else if (norender) { + norender = 0; + } + }*/ + +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif + rect.x = 0; rect.y = 0; + rect.w = cmode->width; + rect.h = 15; + if (conf.fps || norender) { + char title[256]; + char tmp[256]; + + if (fpspos < 0) fpspos = 0; +#ifndef GS_LOG + if (fpspos > 5) fpspos = 5; +#else + if (fpspos > 6) fpspos = 6; +#endif + switch (fpspos) { + case 0: // NoRender + sprintf(tmp, "NoRender %s", norender == 1 ? "On" : "Off"); + break; + case 1: // WireFrame + sprintf(tmp, "WireFrame %s", wireframe == 1 ? "On" : "Off"); + break; + case 2: // ShowFullVRam + sprintf(tmp, "ShowFullVRam %s", showfullvram == 1 ? "On" : "Off"); + break; + case 3: // FrameSkip + sprintf(tmp, "Frameskip %s", conf.frameskip == 1 ? "On" : "Off"); + break; + case 4: // GSmode + if (gs.PMODE.en[0] && gs.PMODE.en[1]) { + sprintf(tmp, "GSmode %dx%d CRT1 %dx%d CRT2 %dx%d", surf1x->w, surf1x->h, gs.DISPLAY[0].w,gs.DISPLAY[0].h, gs.DISPLAY[1].w, gs.DISPLAY[1].h); + } else + if (gs.PMODE.en[0]) { + sprintf(tmp, "GSmode %dx%d CRT1 %dx%d", surf1x->w, surf1x->h, gs.DISPLAY[0].w,gs.DISPLAY[0].h); + } else { + sprintf(tmp, "GSmode %dx%d CRT2 %dx%d", surf1x->w, surf1x->h, gs.DISPLAY[1].w, gs.DISPLAY[1].h); + } + break; + case 5: // DumpTexts + sprintf(tmp, "DumpTexts %s", conf.dumptexts == 1 ? "On" : "Off"); + break; +#ifdef GS_LOG + case 6: // Log + sprintf(tmp, "Log %s", conf.log == 1 ? "On" : "Off"); + break; +#endif + } + if (fpspress) { + switch (fpspos) { + case 0: + norender = 1 - norender; + break; + case 1: + wireframe = 1 - wireframe; + break; + case 2: + showfullvram = 1 - showfullvram; + break; + case 3: + conf.frameskip = 1 - conf.frameskip; + norender = 0; + break; + case 4: + break; + case 5: + conf.dumptexts = 1 - conf.dumptexts; + break; +#ifdef GS_LOG + case 6: + conf.log = 1 - conf.log; + break; +#endif + } + fpspress = 0; + } + + if (cmode->width <= 320) { + sprintf(title, "FPS %.2f; %s; FC %d", 1000.0 / fpsc, tmp, fc); + + SDL_FillRect(surf, &rect, 0); + stringRGBA(surf, 4, rect.y+4, title, 0, 0xff, 0, 0xff); + rect.y+= 15; + + sprintf(title, "PPF %d; BPF %d; CPU %d%% - TICKS %lld", ppf, bpf, (u32)((gsticks*100)/cticks), cticks); + + SDL_FillRect(surf, &rect, 0); + stringRGBA(surf, 4, rect.y+4, title, 0, 0xff, 0, 0xff); + rect.y+= 15; + } else { + sprintf(title, "FPS %.2f; %s; FC %d; PPF %d; BPF %d; CPU %d%% - TICKS %lld", 1000.0 / fpsc, tmp, fc, ppf, bpf, (u32)((gsticks*100)/cticks), cticks); + + SDL_FillRect(surf, &rect, 0); + stringRGBA(surf, 4, rect.y+4, title, 0, 0xff, 0, 0xff); + rect.y+= 15; + } + } + gsticks = 0; + +#if defined(__i386__) || defined(__x86_64__) + tick = GetCPUTick(); +#endif + if (gsmsg[0]) { + char str[256]; + char *s = gsmsg; + int len = strlen(gsmsg); + + while (len>0) { + for (i=0; i<255; i++) { + if (len <= 0) break; + if (*s == '\n' || *s == '\0') { s++; break; } + str[i] = *s++; + } + if (i == 0) break; + str[i] = 0; + + SDL_FillRect(surf, &rect, 0); + stringRGBA(surf, 4, rect.y+4, str, 0, 0xff, 0, 0xff); + rect.y+= 15; + } + + if ((SDL_GetTicks() - gsmsgscount) >= gsmsgcount) gsmsg[0] = 0; + } + + if (norender == 0) { + DXblit(rect.y); + } + + if (conf.record) { + SDL_LockSurface(surf); + recFrame(surf->pixels, surf->pitch, surf->format->BitsPerPixel); + SDL_UnlockSurface(surf); + } + SDL_UpdateRect(surf, 0, 0, 0, 0); +#ifdef __WIN32__ + SDL_PumpEvents(); +#endif +#if defined(__i386__) || defined(__x86_64__) + gsticks+= GetCPUTick() - tick; +#endif +} + +int DXgetModes() { + SDL_Rect **rects; + int i; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; + + memset(modes, 0, sizeof(modes)); + rects = SDL_ListModes(NULL, SDL_FULLSCREEN); + if (rects == NULL) return -1; + + for (i=0; i<64; i++) { + if (rects[i] == NULL) break; + modes[i].width = rects[i]->w; + modes[i].height = rects[i]->h; + } + + SDL_Quit(); + + return i; +} + +void CALLBACK GSprintf(int timeout, char *fmt, ...) { + va_list list; + + va_start(list,fmt); + vsprintf(gsmsg,fmt,list); + va_end(list); + gsmsgscount = SDL_GetTicks(); + gsmsgcount = timeout*1000; +} + +void CALLBACK GSgetDriverInfo(GSdriverInfo *info) { + strcpy(info->name, "sdl"); + info->common = surf; +} diff --git a/plugins/gs/GSsoft/Src/SDL_gfxPrimitives.c b/plugins/gs/GSsoft/Src/SDL_gfxPrimitives.c new file mode 100644 index 0000000000..8a0d3fa467 --- /dev/null +++ b/plugins/gs/GSsoft/Src/SDL_gfxPrimitives.c @@ -0,0 +1,2561 @@ +/* + + SDL_gfxPrimitives - Graphics primitives for SDL surfaces + + Note: Does not lock or update surfaces. Implement in calling routine. + +*/ + +#include +#include +#include +#include + +#include + +#include "SDL_gfxPrimitives.h" +#include "SDL_gfxPrimitives_font.h" + +/* -===================- */ + +/* Define this flag to use surface blits for alpha blended drawing. */ +/* This is usually slower that direct surface calculations. */ + +#undef SURFACE_ALPHA_PIXEL + +/* ----- Defines for pixel clipping tests */ + +#define clip_xmin(surface) surface->clip_rect.x +#define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1 +#define clip_ymin(surface) surface->clip_rect.y +#define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1 + +/* ----- Pixel - fast, no blending, no locking, clipping */ + +int fastPixelColorNolock (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* Honor clipping setup at pixel level */ + if ( (x >= clip_xmin(dst)) && + (x <= clip_xmax(dst)) && + (y >= clip_ymin(dst)) && + (y <= clip_ymax(dst)) ) { + + /* Get destination format */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *)dst->pixels + y * dst->pitch + x * bpp; + switch(bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *)p = color; + break; + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *)p = color; + break; + } /* switch */ + + + } + + return(0); +} + +/* ----- Pixel - fast, no blending, no locking, no clipping */ + +/* (faster but dangerous, make sure we stay in surface bounds) */ + +int fastPixelColorNolockNoclip (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) +{ + int bpp; + Uint8 *p; + + /* Get destination format */ + bpp = dst->format->BytesPerPixel; + p = (Uint8 *)dst->pixels + y * dst->pitch + x * bpp; + switch(bpp) { + case 1: + *p = color; + break; + case 2: + *(Uint16 *)p = color; + break; + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (color >> 16) & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = color & 0xff; + } else { + p[0] = color & 0xff; + p[1] = (color >> 8) & 0xff; + p[2] = (color >> 16) & 0xff; + } + break; + case 4: + *(Uint32 *)p = color; + break; + } /* switch */ + + return(0); +} + +/* ----- Pixel - fast, no blending, locking, clipping */ + +int fastPixelColor (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) +{ + int result; + + /* Lock the surface */ + if ( SDL_MUSTLOCK(dst) ) { + if ( SDL_LockSurface(dst) < 0 ) { + return(-1); + } + } + + result=fastPixelColorNolock (dst,x,y,color); + + /* Unlock surface */ + if ( SDL_MUSTLOCK(dst) ) { + SDL_UnlockSurface (dst); + } + + return(result); +} + +/* ----- Pixel - fast, no blending, locking, RGB input */ + +int fastPixelRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* Setup color */ + color=SDL_MapRGBA(dst->format, r, g, b, a); + + /* Draw */ + return(fastPixelColor(dst, x, y, color)); + +} + +/* ----- Pixel - fast, no blending, no locking RGB input */ + +int fastPixelRGBANolock (SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* Setup color */ + color=SDL_MapRGBA(dst->format, r, g, b, a); + + /* Draw */ + return(fastPixelColorNolock(dst, x, y, color)); +} + +#ifdef SURFACE_ALPHA_PIXEL + +/* ----- Pixel - using single pixel blit with blending enabled if a<255 */ + +static SDL_Surface *gfxPrimitivesSinglePixel=NULL; + +int pixelColor (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) +{ + SDL_Rect srect; + SDL_Rect drect; + int result; + + /* Setup source rectangle for pixel */ + srect.x=0; + srect.y=0; + srect.w=1; + srect.h=1; + + /* Setup destination rectangle for pixel */ + drect.x=x; + drect.y=y; + drect.w=1; + drect.h=1; + + /* Create single pixel in 32bit RGBA format */ + if (gfxPrimitivesSinglePixel==NULL) { + gfxPrimitivesSinglePixel=SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA, 1, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + } + + /* Draw color into pixel*/ + SDL_FillRect (gfxPrimitivesSinglePixel, &srect, color); + + /* Draw pixel onto destination surface */ + result=SDL_BlitSurface (gfxPrimitivesSinglePixel, &srect, dst, &drect); + + return(result); +} + +#else + +/* PutPixel routine with alpha blending, input color in destination format */ + +int _putPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) +{ + Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; + Uint32 R,G,B,A = 0; + + if (x>=clip_xmin(surface) && x<=clip_xmax(surface) && y>=clip_ymin(surface) && y<=clip_ymax(surface)) { + + switch (surface->format->BytesPerPixel) { + case 1: { /* Assuming 8-bpp */ + if( alpha == 255 ){ + *((Uint8 *)surface->pixels + y*surface->pitch + x) = color; + } else { + Uint8 *pixel = (Uint8 *)surface->pixels + y*surface->pitch + x; + + Uint8 dR = surface->format->palette->colors[*pixel].r; + Uint8 dG = surface->format->palette->colors[*pixel].g; + Uint8 dB = surface->format->palette->colors[*pixel].b; + Uint8 sR = surface->format->palette->colors[color].r; + Uint8 sG = surface->format->palette->colors[color].g; + Uint8 sB = surface->format->palette->colors[color].b; + + dR = dR + ((sR-dR)*alpha >> 8); + dG = dG + ((sG-dG)*alpha >> 8); + dB = dB + ((sB-dB)*alpha >> 8); + + *pixel = SDL_MapRGB(surface->format, dR, dG, dB); + } + } + break; + + case 2: { /* Probably 15-bpp or 16-bpp */ + if ( alpha == 255 ) { + *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color; + } else { + Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x; + Uint32 dc = *pixel; + + R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask; + G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask; + B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask; + if( Amask ) + A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask; + + *pixel= R | G | B | A; + } + } + break; + + case 3: { /* Slow 24-bpp mode, usually not used */ + Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; + Uint8 rshift8=surface->format->Rshift/8; + Uint8 gshift8=surface->format->Gshift/8; + Uint8 bshift8=surface->format->Bshift/8; + Uint8 ashift8=surface->format->Ashift/8; + + + if ( alpha == 255 ) { + *(pix+rshift8) = color>>surface->format->Rshift; + *(pix+gshift8) = color>>surface->format->Gshift; + *(pix+bshift8) = color>>surface->format->Bshift; + *(pix+ashift8) = color>>surface->format->Ashift; + } else { + Uint8 dR, dG, dB, dA=0; + Uint8 sR, sG, sB, sA=0; + + pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; + + dR = *((pix)+rshift8); + dG = *((pix)+gshift8); + dB = *((pix)+bshift8); + dA = *((pix)+ashift8); + + sR = (color>>surface->format->Rshift)&0xff; + sG = (color>>surface->format->Gshift)&0xff; + sB = (color>>surface->format->Bshift)&0xff; + sA = (color>>surface->format->Ashift)&0xff; + + dR = dR + ((sR-dR)*alpha >> 8); + dG = dG + ((sG-dG)*alpha >> 8); + dB = dB + ((sB-dB)*alpha >> 8); + dA = dA + ((sA-dA)*alpha >> 8); + + *((pix)+rshift8) = dR; + *((pix)+gshift8) = dG; + *((pix)+bshift8) = dB; + *((pix)+ashift8) = dA; + } + } + break; + + case 4: { /* Probably 32-bpp */ + if ( alpha == 255 ) { + *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color; + } else { + Uint32 *pixel = (Uint32 *)surface->pixels + y*surface->pitch/4 + x; + Uint32 dc = *pixel; + + R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask; + G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask; + B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask; + if ( Amask ) + A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask; + + *pixel = R | G | B | A; + } + } + break; + } + } + + return(0); +} + +/* ----- Pixel - pixel draw with blending enabled if a<255 */ + +int pixelColor (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result=0; + + /* Lock the surface */ + if ( SDL_MUSTLOCK(dst) ) { + if ( SDL_LockSurface(dst) < 0 ) { + return(-1); + } + } + + /* Setup color */ + alpha=color &0x000000ff; + mcolor=SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* Draw */ + result = _putPixelAlpha(dst,x,y,mcolor,alpha); + + /* Unlock the surface */ + if (SDL_MUSTLOCK(dst) ) { + SDL_UnlockSurface(dst); + } + + return(result); +} + + +/* Filled rectangle with alpha blending, color in destination format */ + +int _filledRectAlpha (SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) +{ + Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; + Uint32 R,G,B,A=0; + Sint16 x,y; + + switch (surface->format->BytesPerPixel) { + case 1: { /* Assuming 8-bpp */ + Uint8 *row, *pixel; + Uint8 dR, dG, dB; + + Uint8 sR = surface->format->palette->colors[color].r; + Uint8 sG = surface->format->palette->colors[color].g; + Uint8 sB = surface->format->palette->colors[color].b; + + for(y = y1; y<=y2; y++){ + row = (Uint8 *)surface->pixels + y*surface->pitch; + for(x = x1; x <= x2; x++){ + pixel = row + x; + + dR = surface->format->palette->colors[*pixel].r; + dG = surface->format->palette->colors[*pixel].g; + dB = surface->format->palette->colors[*pixel].b; + + dR = dR + ((sR-dR)*alpha >> 8); + dG = dG + ((sG-dG)*alpha >> 8); + dB = dB + ((sB-dB)*alpha >> 8); + + *pixel = SDL_MapRGB(surface->format, dR, dG, dB); + } + } + } + break; + + case 2: { /* Probably 15-bpp or 16-bpp */ + Uint16 *row, *pixel; + Uint32 dR=(color & Rmask),dG=(color & Gmask),dB=(color & Bmask),dA=(color & Amask); + + for(y = y1; y<=y2; y++){ + row = (Uint16 *)surface->pixels + y*surface->pitch/2; + for(x = x1; x <= x2; x++){ + pixel = row + x; + + R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask; + G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask; + B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask; + if( Amask ) + A = ((*pixel & Amask) + (( dA - (*pixel & Amask) ) * alpha >> 8)) & Amask; + + *pixel= R | G | B | A; + } + } + } + break; + + case 3: { /* Slow 24-bpp mode, usually not used */ + Uint8 *row,*pix; + Uint8 dR, dG, dB, dA; + Uint8 rshift8=surface->format->Rshift/8; + Uint8 gshift8=surface->format->Gshift/8; + Uint8 bshift8=surface->format->Bshift/8; + Uint8 ashift8=surface->format->Ashift/8; + + Uint8 sR = (color>>surface->format->Rshift)&0xff; + Uint8 sG = (color>>surface->format->Gshift)&0xff; + Uint8 sB = (color>>surface->format->Bshift)&0xff; + Uint8 sA = (color>>surface->format->Ashift)&0xff; + + for(y = y1; y<=y2; y++){ + row = (Uint8 *)surface->pixels + y * surface->pitch; + for(x = x1; x <= x2; x++){ + pix = row + x*3; + + dR = *((pix)+rshift8); + dG = *((pix)+gshift8); + dB = *((pix)+bshift8); + dA = *((pix)+ashift8); + + dR = dR + ((sR-dR)*alpha >> 8); + dG = dG + ((sG-dG)*alpha >> 8); + dB = dB + ((sB-dB)*alpha >> 8); + dA = dA + ((sA-dA)*alpha >> 8); + + *((pix)+rshift8) = dR; + *((pix)+gshift8) = dG; + *((pix)+bshift8) = dB; + *((pix)+ashift8) = dA; + } + } + + } + break; + + case 4: { /* Probably 32-bpp */ + Uint32 *row, *pixel; + Uint32 dR=(color & Rmask),dG=(color & Gmask),dB=(color & Bmask),dA=(color & Amask); + + for(y = y1; y<=y2; y++){ + row = (Uint32 *)surface->pixels + y*surface->pitch/4; + for(x = x1; x <= x2; x++){ + pixel = row + x; + + R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask; + G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask; + B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask; + if( Amask ) + A = ((*pixel & Amask) + (( dA - (*pixel & Amask) ) * alpha >> 8)) & Amask; + + *pixel= R | G | B | A; + } + } + } + break; + } + + return(0); +} + +/* Draw rectangle with alpha enabled from RGBA color. */ + +int filledRectAlpha (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Uint8 alpha; + Uint32 mcolor; + int result=0; + + /* Lock the surface */ + if ( SDL_MUSTLOCK(dst) ) { + if ( SDL_LockSurface(dst) < 0 ) { + return(-1); + } + } + + /* Setup color */ + alpha = color & 0x000000ff; + mcolor=SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24, (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha); + + /* Draw */ + result = _filledRectAlpha(dst,x1,y1,x2,y2,mcolor,alpha); + + /* Unlock the surface */ + if (SDL_MUSTLOCK(dst) ) { + SDL_UnlockSurface(dst); + } + + return(result); +} + +/* Draw horizontal line with alpha enabled from RGBA color */ + +int HLineAlpha(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + return (filledRectAlpha(dst, x1, y, x2, y, color)); +} + + +/* Draw vertical line with alpha enabled from RGBA color */ + +int VLineAlpha(SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) +{ + return (filledRectAlpha(dst, x, y1, x, y2, color)); +} + +#endif + + +/* Pixel - using alpha weight on color for AA-drawing */ + +int pixelColorWeight (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) +{ + Uint32 a; + + /* Get alpha */ + a=(color & (Uint32)0x000000ff); + + /* Modify Alpha by weight */ + a = ((a*weight) >> 8); + + return(pixelColor (dst,x,y, (color & (Uint32)0xffffff00) | (Uint32)a )); +} + +int pixelRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + Uint32 color; + + /* Check Alpha */ + if (a==255) { + /* No alpha blending required */ + /* Setup color */ + color=SDL_MapRGBA(dst->format, r, g, b, a); + /* Draw */ + return(fastPixelColor (dst, x, y, color)); + } else { + /* Alpha blending required */ + /* Draw */ + return(pixelColor (dst, x, y, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a )); + } +} + +/* ----- Horizontal line */ + +#ifdef SURFACE_ALPHA_PIXEL + static SDL_Surface *gfxPrimitivesHline=NULL; +#endif + +int hlineColor (SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) +{ + Sint16 left,right,top,bottom; + Uint8 *pixel,*pixellast; + int dx; + int pixx, pixy; + Sint16 w; + Sint16 xtmp; + int result=-1; + Uint8 *colorptr; +#ifdef SURFACE_ALPHA_PIXEL + Uint32 a; + SDL_Rect srect; + SDL_Rect drect; +#endif + + /* Get clipping boundary */ + left = dst->clip_rect.x; + right = dst->clip_rect.x+dst->clip_rect.w-1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y+dst->clip_rect.h-1; + + /* Swap x1, x2 if required */ + if (x1>x2) { + xtmp=x1; x1=x2; x2=xtmp; + } + + /* Visible */ + if ((x1>right) || (x2bottom)) { + return(0); + } + + /* Clip x */ + if (x1right) { + x2=right; + } + + /* Calculate width */ + w=x2-x1; + + /* Sanity check on width */ + if (w<0) { + return(0); + } + + /* Alpha check */ + if ((color & 255)==255) { + + /* No alpha-blending required */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + /* More variable setup */ + dx=w; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8*)dst->pixels) + pixx * (int)x1 + pixy * (int)y; + + /* Draw */ + switch(dst->format->BytesPerPixel) { + case 1: + memset (pixel, color, dx); + break; + case 2: + pixellast = pixel + dx + dx; + for (; pixel<=pixellast; pixel += pixx) { + *(Uint16*)pixel = color; + } + break; + case 3: + pixellast = pixel + dx + dx + dx; + for (; pixel<=pixellast; pixel += pixx) { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4*/ + dx = dx + dx; + pixellast = pixel + dx + dx; + for (; pixel<=pixellast; pixel += pixx) { + *(Uint32*)pixel = color; + } + break; + } + + /* Unlock surface */ + SDL_UnlockSurface(dst); + + /* Set result code */ + result=0; + + } else { + + /* Alpha blending blit */ + +#ifdef SURFACE_ALPHA_PIXEL + + /* Adjust width for Rect setup */ + w++; + + /* Setup source rectangle for pixel */ + srect.x=0; + srect.y=0; + srect.w=w; + srect.h=1; + + /* Setup rectangle for destination line */ + drect.x=x1; + drect.y=y; + drect.w=w; + drect.h=1; + + /* Maybe deallocate existing surface if size is too small */ + if ((gfxPrimitivesHline!=NULL) && (gfxPrimitivesHline->wclip_rect.x; + right = dst->clip_rect.x+dst->clip_rect.w-1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y+dst->clip_rect.h-1; + + /* Swap y1, y2 if required */ + if (y1>y2) { + ytmp=y1; y1=y2; y2=ytmp; + } + + /* Visible */ + if ((y2bottom) || (xright)) { + return(0); + } + + /* Clip y */ + if (y1bottom) { + y2=bottom; + } + + /* Calculate height */ + h=y2-y1; + + /* Sanity check on height */ + if (h<0) { + return(0); + } + + /* Alpha check */ + if ((color & 255)==255) { + + /* No alpha-blending required */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + /* More variable setup */ + dy=h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8*)dst->pixels) + pixx * (int)x + pixy * (int)y1; + pixellast = pixel + pixy*dy; + + /* Draw */ + switch(dst->format->BytesPerPixel) { + case 1: + for (; pixel<=pixellast; pixel += pixy) { + *(Uint8*)pixel = color; + } + break; + case 2: + for (; pixel<=pixellast; pixel += pixy) { + *(Uint16*)pixel = color; + } + break; + case 3: + for (; pixel<=pixellast; pixel += pixy) { + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + } + break; + default: /* case 4*/ + for (; pixel<=pixellast; pixel += pixy) { + *(Uint32*)pixel = color; + } + break; + } + + /* Unlock surface */ + SDL_UnlockSurface(dst); + + /* Set result code */ + result=0; + + } else { + + /* Alpha blending blit */ + +#ifdef SURFACE_ALPHA_PIXEL + + /* Adjust height for Rect setup */ + h++; + + /* Setup source rectangle for pixel */ + srect.x=0; + srect.y=0; + srect.w=1; + srect.h=h; + + /* Setup rectangle for line */ + drect.x=x; + drect.y=y1; + drect.w=1; + drect.h=h; + + /* Maybe deallocate existing surface if size is too small */ + if ( (gfxPrimitivesVline!=NULL) && (gfxPrimitivesVline->hx2) { + xtmp=x1; x1=x2; x2=xtmp; + } + + /* Swap y1, y2 if required */ + if (y1>y2) { + ytmp=y1; y1=y2; y2=ytmp; + } + + /* Calculate width&height */ + w=x2-x1; + h=y2-y1; + + /* Sanity check */ + if ((w<0) || (h<0)) { + return(0); + } + + /* Test for special cases of straight lines or single point */ + if (x1==x2) { + if (y1==y2) { + return(pixelColor(dst, x1, y1, color)); + } else { + return(vlineColor(dst, x1, y1, y2, color)); + } + } else { + if (y1==y2) { + return(hlineColor(dst, x1, x2, y1, color)); + } + } + + /* Draw rectangle */ + result=0; + result |= vlineColor(dst, x1, y1, y2, color); + result |= vlineColor(dst, x2, y1, y2, color); + result |= hlineColor(dst, x1, x2, y1, color); + result |= hlineColor(dst, x1, x2, y2, color); + + return(result); + +} + +int rectangleRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(rectangleColor(dst, x1, y1, x2, y2, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* --------- Clipping routines for box/line */ + +/* Clipping based heavily on code from */ +/* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */ + +#define CLIP_LEFT_EDGE 0x1 +#define CLIP_RIGHT_EDGE 0x2 +#define CLIP_BOTTOM_EDGE 0x4 +#define CLIP_TOP_EDGE 0x8 +#define CLIP_INSIDE(a) (!a) +#define CLIP_REJECT(a,b) (a&b) +#define CLIP_ACCEPT(a,b) (!(a|b)) + +static int clipEncode (Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom) +{ + int code = 0; + if (x < left) { + code |= CLIP_LEFT_EDGE; + } else if (x > right) { + code |= CLIP_RIGHT_EDGE; + } + if (y < top) { + code |= CLIP_TOP_EDGE; + } else if (y > bottom) { + code |= CLIP_BOTTOM_EDGE; + } + return code; +} + +static int clipLine(SDL_Surface *dst, Sint16 *x1, Sint16 *y1, Sint16 *x2, Sint16 *y2) +{ + Sint16 left,right,top,bottom; + int code1, code2; + int draw = 0; + Sint16 swaptmp; + float m; + + /* Get clipping boundary */ + left = dst->clip_rect.x; + right = dst->clip_rect.x+dst->clip_rect.w-1; + top = dst->clip_rect.y; + bottom = dst->clip_rect.y+dst->clip_rect.h-1; + + while (1) { + code1 = clipEncode (*x1, *y1, left, top, right, bottom); + code2 = clipEncode (*x2, *y2, left, top, right, bottom); + if (CLIP_ACCEPT(code1, code2)) { + draw = 1; + break; + } else if (CLIP_REJECT(code1, code2)) + break; + else { + if(CLIP_INSIDE (code1)) { + swaptmp = *x2; *x2 = *x1; *x1 = swaptmp; + swaptmp = *y2; *y2 = *y1; *y1 = swaptmp; + swaptmp = code2; code2 = code1; code1 = swaptmp; + } + if (*x2 != *x1) { + m = (*y2 - *y1) / (float)(*x2 - *x1); + } else { + m = 1.0f; + } + if (code1 & CLIP_LEFT_EDGE) { + *y1 += (Sint16)((left - *x1) * m); + *x1 = left; + } else if (code1 & CLIP_RIGHT_EDGE) { + *y1 += (Sint16)((right - *x1) * m); + *x1 = right; + } else if (code1 & CLIP_BOTTOM_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16)((bottom - *y1) / m); + } + *y1 = bottom; + } else if (code1 & CLIP_TOP_EDGE) { + if (*x2 != *x1) { + *x1 += (Sint16)((top - *y1) / m); + } + *y1 = top; + } + } + } + + return draw; +} + +/* ----- Filled rectangle (Box) */ + +#ifdef SURFACE_ALPHA_PIXEL + static SDL_Surface *gfxPrimitivesBox=NULL; +#endif + +int boxColor (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + Uint8 *pixel, *pixellast; + int x, dx; + int dy; + int pixx, pixy; + Sint16 w,h,tmp; + int result; + Uint8 *colorptr; +#ifdef SURFACE_ALPHA_PIXEL + Uint32 a; + SDL_Rect srect; + SDL_Rect drect; +#endif + + /* Clip diagonal and test if we have to draw */ + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Test for special cases of straight lines or single point */ + if (x1==x2) { + if (y1y2) { + return(vlineColor(dst, x1, y2, y1, color)); + } else { + return(pixelColor(dst, x1, y1, color)); + } + } + if (y1==y2) { + if (x1x2) { + return(hlineColor(dst, x2, x1, y1, color)); + } + } + + /* Order coordinates */ + if (x1>x2) { + tmp=x1; + x1=x2; + x2=tmp; + } + if (y1>y2) { + tmp=y1; + y1=y2; + y2=tmp; + } + + /* Calculate width&height */ + w=x2-x1; + h=y2-y1; + + /* Alpha check */ + if ((color & 255)==255) { + + /* No alpha-blending required */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + /* More variable setup */ + dx=w; + dy=h; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8*)dst->pixels) + pixx * (int)x1 + pixy * (int)y1; + pixellast = pixel + pixx*dx + pixy*dy; + + /* Draw */ + switch(dst->format->BytesPerPixel) { + case 1: + for (; pixel<=pixellast; pixel += pixy) { + memset(pixel,(Uint8)color,dx); + } + break; + case 2: + pixy -= (pixx*dx); + for (; pixel<=pixellast; pixel += pixy) { + for (x=0; x> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + pixel += pixx; + } + } + break; + default: /* case 4*/ + pixy -= (pixx*dx); + for (; pixel<=pixellast; pixel += pixy) { + for (x=0; xwhy2) { + return(vlineColor(dst, x1, y2, y1, color)); + } else { + return(pixelColor(dst, x1, y1, color)); + } + } + if (y1==y2) { + if (x1x2) { + return(hlineColor(dst, x2, x1, y1, color)); + } + } + + /* Variable setup */ + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + /* Check for alpha blending */ + if ((color & 255)==255) { + + /* No alpha blending - use fast pixel routines */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + /* More variable setup */ + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8*)dst->pixels) + pixx * (int)x1 + pixy * (int)y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; dx = dy; dy = swaptmp; + swaptmp = pixx; pixx = pixy; pixy = swaptmp; + } + + /* Draw */ + x=0; + y=0; + switch(dst->format->BytesPerPixel) { + case 1: + for(; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; pixel += pixy; + } + } + break; + case 2: + for (; x < dx; x++, pixel += pixx) { + *(Uint16*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 3: + for(; x < dx; x++, pixel += pixx) { + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + default: /* case 4 */ + for(; x < dx; x++, pixel += pixx) { + *(Uint32*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + } + + /* Unlock surface */ + SDL_UnlockSurface(dst); + + } else { + + /* Alpha blending required - use single-pixel blits */ + + ax = ABS(dx) << 1; + ay = ABS(dy) << 1; + x = x1; + y = y1; + if (ax > ay) { + int d = ay - (ax >> 1); + while (x != x2) { + pixelColor(dst, x, y, color); + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } else { + int d = ax - (ay >> 1); + while (y != y2) { + pixelColor(dst, x, y, color); + if (d > 0 || ((d == 0) && (sy == 1))) { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } + pixelColor(dst, x, y, color); + + } + + return(0); +} + +int lineRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(lineColor(dst, x1, y1, x2, y2, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* AA Line */ + +#define AAlevels 256 +#define AAbits 8 + +/* + +This implementation of the Wu antialiasing code is based on Mike Abrash's +DDJ article which was reprinted as Chapter 42 of his Graphics Programming +Black Book, but has been optimized to work with SDL and utilizes 32-bit +fixed-point arithmetic. (A. Schiffler). + +*/ + +int aalineColorInt (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint) +{ + Sint32 xx0,yy0,xx1,yy1; + int result; + Uint32 intshift, erracc, erradj; + Uint32 erracctmp, wgt, wgtcompmask; + int dx, dy, tmp, xdir, y0p1, x0pxdir; + + /* Clip line and test if we have to draw */ + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Keep on working with 32bit numbers */ + xx0=x1; + yy0=y1; + xx1=x2; + yy1=y2; + + /* Reorder points if required */ + if (yy0 > yy1) { + tmp = yy0; yy0 = yy1; yy1 = tmp; + tmp = xx0; xx0 = xx1; xx1 = tmp; + } + + /* Calculate distance */ + dx = xx1 - xx0; + dy = yy1 - yy0; + + /* Adjust for negative dx and set xdir */ + if (dx >= 0) { + xdir=1; + } else { + xdir=-1; + dx=(-dx); + } + + /* Check for special cases */ + if (dx==0) { + /* Vertical line */ + return (vlineColor(dst,x1,y1,y2,color)); + } else if (dy==0) { + /* Horizontal line */ + return (hlineColor(dst,x1,x2,y1,color)); + } else if (dx==dy) { + /* Diagonal line */ + return (lineColor(dst,x1,y1,x2,y2,color)); + } + + /* Line is not horizontal, vertical or diagonal */ + result=0; + /* Zero accumulator */ + erracc = 0; + /* # of bits by which to shift erracc to get intensity level */ + intshift = 32 - AAbits; + /* Mask used to flip all bits in an intensity weighting */ + wgtcompmask = AAlevels - 1; + + /* Draw the initial pixel in the foreground color */ + result |= pixelColor (dst, x1, y1, color); + + /* x-major or y-major? */ + if (dy > dx) { + + /* y-major. Calculate 16-bit fixed point fractional part of a pixel that + X advances every time Y advances 1 pixel, truncating the result so that + we won't overrun the endpoint along the X axis */ + /* Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy; */ + erradj = ((dx << 16) / dy)<<16; + + /* draw all pixels other than the first and last */ + x0pxdir=xx0+xdir; + while (--dy) { + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* rollover in error accumulator, x coord advances */ + xx0=x0pxdir; + x0pxdir += xdir; + } + yy0++; /* y-major so always advance Y */ + + /* the AAbits most significant bits of erracc give us the intensity + weighting for this pixel, and the complement of the weighting for + the paired pixel. */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeight (dst, xx0, yy0, color, 255-wgt); + result |= pixelColorWeight (dst, x0pxdir, yy0, color, wgt); + } + + } else { + + /* x-major line. Calculate 16-bit fixed-point fractional part of a pixel + that Y advances each time X advances 1 pixel, truncating the result so + that we won't overrun the endpoint along the X axis. */ + /* Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx; */ + erradj = ((dy << 16) / dx)<<16; + + /* draw all pixels other than the first and last */ + y0p1=yy0+1; + while (--dx) { + + erracctmp = erracc; + erracc += erradj; + if (erracc <= erracctmp) { + /* Accumulator turned over, advance y */ + yy0=y0p1; + y0p1++; + } + xx0 += xdir; /* x-major so always advance X */ + /* the AAbits most significant bits of erracc give us the intensity + weighting for this pixel, and the complement of the weighting for + the paired pixel. */ + wgt = (erracc >> intshift) & 255; + result |= pixelColorWeight (dst, xx0, yy0, color, 255-wgt); + result |= pixelColorWeight (dst, xx0, y0p1, color, wgt); + } + } + + /* Do we have to draw the endpoint */ + if (draw_endpoint) { + /* Draw final pixel, always exactly intersected by the line and doesn't + need to be weighted. */ + result |= pixelColor (dst, x2, y2, color); + } + + return(result); +} + +int aalineColor (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + return(aalineColorInt(dst,x1,y1,x2,y1,color,1)); +} + +int aalineRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + return(aalineColorInt(dst, x1, y1, x2, y2, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a, 1)); +} + + +/* ----- Circle */ + +/* Note: Based on algorithm from sge library, modified by A. Schiffler */ +/* with multiple pixel-draw removal and other minor speedup changes. */ + +int circleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + int result; + Sint16 x1,y1,x2,y2; + Sint16 cx = 0; + Sint16 cy = r; + Sint16 ocx = (Sint16)0xffff; + Sint16 ocy = (Sint16)0xffff; + Sint16 df = 1 - r; + Sint16 d_e = 3; + Sint16 d_se = -2 * r + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + Uint8 *colorptr; + + /* Sanity check radius */ + if (r<0) { + return(-1); + } + + /* Special case for r=0 - draw a point */ + if (r==0) { + return(pixelColor (dst, x, y, color)); + } + + /* Test if bounding box of circle is visible */ + x1=x-r; + y1=y-r; + x2=x+r; + y2=y+r; + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Draw circle */ + result=0; + /* Alpha Check */ + if ((color & 255) ==255) { + + /* No Alpha - direct memory writes */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + /* Draw */ + do { + if ((ocy!=cy) || (ocx!=cx)) { + xpcx=x+cx; + xmcx=x-cx; + if (cy>0) { + ypcy=y+cy; + ymcy=y-cy; + result |= fastPixelColorNolock(dst,xmcx,ypcy,color); + result |= fastPixelColorNolock(dst,xpcx,ypcy,color); + result |= fastPixelColorNolock(dst,xmcx,ymcy,color); + result |= fastPixelColorNolock(dst,xpcx,ymcy,color); + } else { + result |= fastPixelColorNolock(dst,xmcx,y,color); + result |= fastPixelColorNolock(dst,xpcx,y,color); + } + ocy=cy; + xpcy=x+cy; + xmcy=x-cy; + if (cx>0) { + ypcx=y+cx; + ymcx=y-cx; + result |= fastPixelColorNolock(dst,xmcy,ypcx,color); + result |= fastPixelColorNolock(dst,xpcy,ypcx,color); + result |= fastPixelColorNolock(dst,xmcy,ymcx,color); + result |= fastPixelColorNolock(dst,xpcy,ymcx,color); + } else { + result |= fastPixelColorNolock(dst,xmcy,y,color); + result |= fastPixelColorNolock(dst,xpcy,y,color); + } + ocx=cx; + } + /* Update */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while(cx <= cy); + + /* Unlock surface */ + SDL_UnlockSurface(dst); + + } else { + + /* Using Alpha - blended pixel blits */ + + do { + /* Draw */ + if ((ocy!=cy) || (ocx!=cx)) { + xpcx=x+cx; + xmcx=x-cx; + if (cy>0) { + ypcy=y+cy; + ymcy=y-cy; + result |= pixelColor(dst,xmcx,ypcy,color); + result |= pixelColor(dst,xpcx,ypcy,color); + result |= pixelColor(dst,xmcx,ymcy,color); + result |= pixelColor(dst,xpcx,ymcy,color); + } else { + result |= pixelColor(dst,xmcx,y,color); + result |= pixelColor(dst,xpcx,y,color); + } + ocy=cy; + xpcy=x+cy; + xmcy=x-cy; + if (cx>0) { + ypcx=y+cx; + ymcx=y-cx; + result |= pixelColor(dst,xmcy,ypcx,color); + result |= pixelColor(dst,xpcy,ypcx,color); + result |= pixelColor(dst,xmcy,ymcx,color); + result |= pixelColor(dst,xpcy,ymcx,color); + } else { + result |= pixelColor(dst,xmcy,y,color); + result |= pixelColor(dst,xpcy,y,color); + } + ocx=cx; + } + /* Update */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while(cx <= cy); + + } /* Alpha check */ + + return(result); +} + +int circleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(circleColor(dst, x, y, rad, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* ----- AA Circle */ + +/* Low-speed antialiased circle implementation by drawing aalines. */ +/* Works best for larger radii. */ + +int aacircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + return (aaellipseColor(dst, x, y, r, r, color)); +} + +int aacircleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(aaellipseColor(dst, x, y, rad, rad, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* ----- Filled Circle */ + +/* Note: Based on algorithm from sge library with multiple-hline draw removal */ +/* and other speedup changes. */ + +int filledCircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color) +{ + int result; + Sint16 x1,y1,x2,y2; + Sint16 cx = 0; + Sint16 cy = r; + Sint16 ocx = (Sint16)0xffff; + Sint16 ocy = (Sint16)0xffff; + Sint16 df = 1 - r; + Sint16 d_e = 3; + Sint16 d_se = -2 * r + 5; + Sint16 xpcx, xmcx, xpcy, xmcy; + Sint16 ypcy, ymcy, ypcx, ymcx; + + /* Sanity check radius */ + if (r<0) { + return(-1); + } + + /* Special case for r=0 - draw a point */ + if (r==0) { + return(pixelColor (dst, x, y, color)); + } + + /* Test bounding box */ + x1=x-r; + y1=y-r; + x2=x+r; + y2=y+r; + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Draw */ + result=0; + do { + xpcx=x+cx; + xmcx=x-cx; + xpcy=x+cy; + xmcy=x-cy; + if (ocy!=cy) { + if (cy>0) { + ypcy=y+cy; + ymcy=y-cy; + result |= hlineColor(dst,xmcx,xpcx,ypcy,color); + result |= hlineColor(dst,xmcx,xpcx,ymcy,color); + } else { + result |= hlineColor(dst,xmcx,xpcx,y,color); + } + ocy=cy; + } + if (ocx!=cx) { + if (cx!=cy) { + if (cx>0) { + ypcx=y+cx; + ymcx=y-cx; + result |= hlineColor(dst,xmcy,xpcy,ymcx,color); + result |= hlineColor(dst,xmcy,xpcy,ypcx,color); + } else { + result |= hlineColor(dst,xmcy,xpcy,y,color); + } + } + ocx=cx; + } + /* Update */ + if (df < 0) { + df += d_e; + d_e += 2; + d_se += 2; + } else { + df += d_se; + d_e += 2; + d_se += 4; + cy--; + } + cx++; + } while(cx <= cy); + + return(result); +} + +int filledCircleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(filledCircleColor(dst, x, y, rad, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + + +/* ----- Ellipse */ + +/* Note: Based on algorithm from sge library with multiple-hline draw removal */ +/* and other speedup changes. */ + +int ellipseColor (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + int result; + Sint16 x1, y1, x2, y2; + int ix, iy; + int h, i, j, k; + int oh, oi, oj, ok; + int xmh, xph, ypk, ymk; + int xmi, xpi, ymj, ypj; + int xmj, xpj, ymi, ypi; + int xmk, xpk, ymh, yph; + Uint8 *colorptr; + + /* Sanity check radii */ + if ((rx<0) || (ry<0)) { + return(-1); + } + + /* Special case for rx=0 - draw a vline */ + if (rx==0) { + return(vlineColor (dst, x, y-ry, y+ry, color)); + } + /* Special case for ry=0 - draw a hline */ + if (ry==0) { + return(hlineColor (dst, x-rx, x+rx, y, color)); + } + + /* Test bounding box */ + x1=x-rx; + y1=y-ry; + x2=x+rx; + y2=y+ry; + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Init vars */ + oh = oi = oj = ok = 0xFFFF; + + /* Draw */ + result=0; + /* Check alpha */ + if ((color & 255)==255) { + + /* No Alpha - direct memory writes */ + + /* Setup color */ + colorptr=(Uint8 *)&color; + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { + color=SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); + } else { + color=SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); + } + + /* Lock surface */ + SDL_LockSurface(dst); + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok!=k) && (oj!=k)) || ((oj!=j) && (ok!=j)) || (k!=j)) { + xph=x+h; + xmh=x-h; + if (k>0) { + ypk=y+k; + ymk=y-k; + result |= fastPixelColorNolock (dst,xmh,ypk, color); + result |= fastPixelColorNolock (dst,xph,ypk, color); + result |= fastPixelColorNolock (dst,xmh,ymk, color); + result |= fastPixelColorNolock (dst,xph,ymk, color); + } else { + result |= fastPixelColorNolock (dst,xmh,y, color); + result |= fastPixelColorNolock (dst,xph,y, color); + } + ok=k; + xpi=x+i; + xmi=x-i; + if (j>0) { + ypj=y+j; + ymj=y-j; + result |= fastPixelColorNolock (dst,xmi,ypj, color); + result |= fastPixelColorNolock (dst,xpi,ypj, color); + result |= fastPixelColorNolock (dst,xmi,ymj, color); + result |= fastPixelColorNolock (dst,xpi,ymj, color); + } else { + result |= fastPixelColorNolock (dst,xmi,y, color); + result |= fastPixelColorNolock (dst,xpi,y, color); + } + oj=j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi!=i) && (oh!=i)) || ((oh!=h) && (oi!=h) && (i!=h))) { + xmj=x-j; + xpj=x+j; + if (i>0) { + ypi=y+i; + ymi=y-i; + result |= fastPixelColorNolock (dst,xmj,ypi,color); + result |= fastPixelColorNolock (dst,xpj,ypi,color); + result |= fastPixelColorNolock (dst,xmj,ymi,color); + result |= fastPixelColorNolock (dst,xpj,ymi,color); + } else { + result |= fastPixelColorNolock (dst,xmj,y,color); + result |= fastPixelColorNolock (dst,xpj,y,color); + } + oi=i; + xmk=x-k; + xpk=x+k; + if (h>0) { + yph=y+h; + ymh=y-h; + result |= fastPixelColorNolock (dst,xmk,yph,color); + result |= fastPixelColorNolock (dst,xpk,yph,color); + result |= fastPixelColorNolock (dst,xmk,ymh,color); + result |= fastPixelColorNolock (dst,xpk,ymh,color); + } else { + result |= fastPixelColorNolock (dst,xmk,y,color); + result |= fastPixelColorNolock (dst,xpk,y,color); + } + oh=h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while(i > h); + } + + /* Unlock surface */ + SDL_UnlockSurface(dst); + + } else { + + if (rx > ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if (((ok!=k) && (oj!=k)) || ((oj!=j) && (ok!=j)) || (k!=j)) { + xph=x+h; + xmh=x-h; + if (k>0) { + ypk=y+k; + ymk=y-k; + result |= pixelColor (dst,xmh,ypk, color); + result |= pixelColor (dst,xph,ypk, color); + result |= pixelColor (dst,xmh,ymk, color); + result |= pixelColor (dst,xph,ymk, color); + } else { + result |= pixelColor (dst,xmh,y, color); + result |= pixelColor (dst,xph,y, color); + } + ok=k; + xpi=x+i; + xmi=x-i; + if (j>0) { + ypj=y+j; + ymj=y-j; + result |= pixelColor (dst,xmi,ypj, color); + result |= pixelColor (dst,xpi,ypj, color); + result |= pixelColor (dst,xmi,ymj, color); + result |= pixelColor (dst,xpi,ymj, color); + } else { + result |= pixelColor (dst,xmi,y, color); + result |= pixelColor (dst,xpi,y, color); + } + oj=j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if (((oi!=i) && (oh!=i)) || ((oh!=h) && (oi!=h) && (i!=h))) { + xmj=x-j; + xpj=x+j; + if (i>0) { + ypi=y+i; + ymi=y-i; + result |= pixelColor (dst,xmj,ypi,color); + result |= pixelColor (dst,xpj,ypi,color); + result |= pixelColor (dst,xmj,ymi,color); + result |= pixelColor (dst,xpj,ymi,color); + } else { + result |= pixelColor (dst,xmj,y,color); + result |= pixelColor (dst,xpj,y,color); + } + oi=i; + xmk=x-k; + xpk=x+k; + if (h>0) { + yph=y+h; + ymh=y-h; + result |= pixelColor (dst,xmk,yph,color); + result |= pixelColor (dst,xpk,yph,color); + result |= pixelColor (dst,xmk,ymh,color); + result |= pixelColor (dst,xpk,ymh,color); + } else { + result |= pixelColor (dst,xmk,y,color); + result |= pixelColor (dst,xpk,y,color); + } + oh=h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while(i > h); + } + + } /* Alpha check */ + + return(result); +} + +int ellipseRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(ellipseColor(dst, x, y, rx, ry, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* ----- AA Ellipse */ + +/* Low-speed antialiased ellipse implementation by drawing aalines. */ +/* Works best for larger radii. */ + +int aaellipseColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) +{ + int result; + Sint16 x1, y1, x2, y2; + double angle; + double deltaAngle; + double drx, dry, dr; + int posX, posY, oldPosX, oldPosY; + int i, r; + + /* Sanity check radii */ + if ((rx<0) || (ry<0)) { + return(-1); + } + + /* Special case for rx=0 - draw a vline */ + if (rx==0) { + return(vlineColor (dst, x, y-ry, y+ry, color)); + } + /* Special case for ry=0 - draw a hline */ + if (ry==0) { + return(hlineColor (dst, x-rx, x+rx, y, color)); + } + + /* Test bounding box */ + x1=x-rx; + y1=y-ry; + x2=x+rx; + y2=y+ry; + if (!(clipLine(dst,&x1,&y1,&x2,&y2))) { + return(0); + } + + /* Draw */ + r=(rx+ry)>>1; + dr=(double)r; + drx=(double)rx; + dry=(double)ry; + deltaAngle=(2*M_PI)/dr; + angle=deltaAngle; + oldPosX=x+rx; + oldPosY=y; + + result=0; + for(i=0; i ry) { + ix = 0; + iy = rx * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * ry) / rx; + k = (i * ry) / rx; + + if ((ok!=k) && (oj!=k)) { + xph=x+h; + xmh=x-h; + if (k>0) { + result |= hlineColor (dst,xmh,xph,y+k,color); + result |= hlineColor (dst,xmh,xph,y-k,color); + } else { + result |= hlineColor (dst,xmh,xph,y,color); + } + ok=k; + } + if ((oj!=j) && (ok!=j) && (k!=j)) { + xmi=x-i; + xpi=x+i; + if (j>0) { + result |= hlineColor (dst,xmi,xpi,y+j,color); + result |= hlineColor (dst,xmi,xpi,y-j,color); + } else { + result |= hlineColor (dst,xmi,xpi,y ,color); + } + oj=j; + } + + ix = ix + iy / rx; + iy = iy - ix / rx; + + } while (i > h); + } else { + ix = 0; + iy = ry * 64; + + do { + h = (ix + 32) >> 6; + i = (iy + 32) >> 6; + j = (h * rx) / ry; + k = (i * rx) / ry; + + if ((oi!=i) && (oh!=i)) { + xmj=x-j; + xpj=x+j; + if (i>0) { + result |= hlineColor (dst,xmj,xpj,y+i,color); + result |= hlineColor (dst,xmj,xpj,y-i,color); + } else { + result |= hlineColor (dst,xmj,xpj,y,color); + } + oi=i; + } + if ((oh!=h) && (oi!=h) && (i!=h)) { + xmk=x-k; + xpk=x+k; + if (h>0) { + result |= hlineColor (dst,xmk,xpk,y+h,color); + result |= hlineColor (dst,xmk,xpk,y-h,color); + } else { + result |= hlineColor (dst,xmk,xpk,y ,color); + } + oh=h; + } + + ix = ix + iy / ry; + iy = iy - ix / ry; + + } while(i > h); + } + + return(result); +} + + +int filledEllipseRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(filledEllipseColor(dst, x, y, rx, ry, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +/* ---- Polygon */ + +int polygonColor (SDL_Surface *dst, Sint16 *vx, Sint16 *vy, int n, Uint32 color) +{ + int result; + int i; + Sint16 *x1, *y1, *x2, *y2; + + /* Sanity check */ + if (n<3) { + return(-1); + } + + /* Pointer setup */ + x1=x2=vx; + y1=y2=vy; + x2++; + y2++; + + /* Draw */ + result=0; + for (i=1; i maxy) { + maxy = vy[i]; + } + } + + /* Draw, scanning y */ + result=0; + for (y=miny; (y <= maxy); y++) { + ints = 0; + for (i=0; (i < n); i++) { + if (!i) { + ind1 = n-1; + ind2 = 0; + } else { + ind1 = i-1; + ind2 = i; + } + y1 = vy[ind1]; + y2 = vy[ind2]; + if (y1 < y2) { + x1 = vx[ind1]; + x2 = vx[ind2]; + } else if (y1 > y2) { + y2 = vy[ind1]; + y1 = vy[ind2]; + x2 = vx[ind1]; + x1 = vx[ind2]; + } else { + continue; + } + if ((y >= y1) && (y < y2)) { + gfxPrimitivesPolyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1; + } else if ((y == maxy) && (y > y1) && (y <= y2)) { + gfxPrimitivesPolyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1; + } + } + qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt); + + for (i=0; (ipixels; + memset (curpos, 0, 8*8*4); + + /* Drawing loop */ + for (iy=0; iy<8; iy++) { + bitpos=bits; + for (ix=0; ix<8; ix++) { + if ((*charpos & *bitpos)==*bitpos) { + memcpy(curpos,&color,4); + } + bitpos++; + curpos += 4;; + } + charpos++; + } + } + + /* Draw bitmap onto destination surface */ + result=SDL_BlitSurface (gfxPrimitivesFont[(unsigned char)c], &srect, dst, &drect); + + return(result); +} + +int characterRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + /* Draw */ + return(characterColor(dst, x, y, c, ((Uint32)r << 24) | ((Uint32)g << 16) | ((Uint32)b << 8) | (Uint32)a)); +} + +int stringColor (SDL_Surface *dst, Sint16 x, Sint16 y, char *c, Uint32 color) +{ + int result; + int i,length; + char *curchar; + int curx; + + length=strlen(c); + curchar=c; + curx=x; + result=0; + for (i=0; i +#ifndef M_PI + #define M_PI 3.141592654 +#endif + +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- Versioning */ + +#define SDL_GFXPRIMITIVES_MAJOR 1 +#define SDL_GFXPRIMITIVES_MINOR 5 + +/* ----- W32 DLL interface */ + +#ifdef WIN32 + #define DLLINTERFACE DECLSPEC +#else + #define DLLINTERFACE +#endif + +/* ----- Prototypes */ + +/* Note: all ___Color routines expect the color to be in format 0xRRGGBBAA */ + +/* Pixel */ + +DLLINTERFACE int pixelColor (SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color); +DLLINTERFACE int pixelRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Horizontal line */ + +DLLINTERFACE int hlineColor (SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color); +DLLINTERFACE int hlineRGBA (SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Vertical line */ + +DLLINTERFACE int vlineColor (SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color); +DLLINTERFACE int vlineRGBA (SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Rectangle */ + +DLLINTERFACE int rectangleColor (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); +DLLINTERFACE int rectangleRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled rectangle (Box) */ + +DLLINTERFACE int boxColor (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); +DLLINTERFACE int boxRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Line */ + +DLLINTERFACE int lineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); +DLLINTERFACE int lineRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Line */ +DLLINTERFACE int aalineColor (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); +DLLINTERFACE int aalineRGBA (SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Circle */ + +DLLINTERFACE int circleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); +DLLINTERFACE int circleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Circle */ + +DLLINTERFACE int aacircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); +DLLINTERFACE int aacircleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Circle */ + +DLLINTERFACE int filledCircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 r, Uint32 color); +DLLINTERFACE int filledCircleRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Ellipse */ + +DLLINTERFACE int ellipseColor (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); +DLLINTERFACE int ellipseRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* AA Ellipse */ + +DLLINTERFACE int aaellipseColor (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); +DLLINTERFACE int aaellipseRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Ellipse */ + +DLLINTERFACE int filledEllipseColor (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color); +DLLINTERFACE int filledEllipseRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Polygon */ + +DLLINTERFACE int polygonColor (SDL_Surface *dst, Sint16 *vx, Sint16 *vy, int n, Uint32 color); +DLLINTERFACE int polygonRGBA (SDL_Surface *dst, Sint16 *vx, Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Filled Polygon */ + +DLLINTERFACE int filledPolygonColor (SDL_Surface *dst, Sint16 *vx, Sint16 *vy, int n, int color); +DLLINTERFACE int filledPolygonRGBA (SDL_Surface *dst, Sint16 *vx, Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* 8x8 Characters/Strings */ + +DLLINTERFACE int characterColor (SDL_Surface *dst, Sint16 x, Sint16 y, char c, Uint32 color); +DLLINTERFACE int characterRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a); +DLLINTERFACE int stringColor (SDL_Surface *dst, Sint16 x, Sint16 y, char *c, Uint32 color); +DLLINTERFACE int stringRGBA (SDL_Surface *dst, Sint16 x, Sint16 y, char *c, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +}; +#endif + +#endif /* _SDL_gfxPrimitives_h */ diff --git a/plugins/gs/GSsoft/Src/SDL_gfxPrimitives_font.h b/plugins/gs/GSsoft/Src/SDL_gfxPrimitives_font.h new file mode 100644 index 0000000000..861f7248df --- /dev/null +++ b/plugins/gs/GSsoft/Src/SDL_gfxPrimitives_font.h @@ -0,0 +1,2567 @@ +/* ---- 8x8 font definition ---- */ + +#define GFX_FONTDATAMAX (8*256) + +static unsigned char gfxPrimitivesFontdata[GFX_FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; diff --git a/plugins/gs/GSsoft/Src/Soft.c b/plugins/gs/GSsoft/Src/Soft.c new file mode 100644 index 0000000000..e53862a326 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Soft.c @@ -0,0 +1,1504 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + +#include "GS.h" +#include "Soft.h" +#include "Texts.h" +#include "Color.h" +#include "Mem.h" + +#undef ABS +#define ABS(a) (((a)<0) ? -(a) : (a)) + +__inline int shl10idiv(int x, int y) { + s64 bi = x; + bi <<= 10; + return (int)(bi / y); +} + +__inline s64 shl10idiv64(s64 x, s64 y) { + s64 bi = x; + bi <<= 10; + return (s64)(bi / y); +} + +// + +void drawLineF(Vertex * v) { + int dx = v[1].x - v[0].x; + int dy = v[1].y - v[0].y; + int ax = ABS(dx) << 1; + int ay = ABS(dy) << 1; + int sx = (dx >= 0) ? 1 : -1; + int sy = (dy >= 0) ? 1 : -1; + int x = v[0].x; + int y = v[0].y; + +#ifdef GS_LOG + GS_LOG("drawLineF %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, gs.rgba); +#endif + + SETdrawPixel(); + + if (ax > ay) { + int d = ay - (ax >> 1); + while (x != v[1].x) { + drawPixel(x, y, gs.rgba); + + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } else { + int d = ax - (ay >> 1); + while (y != v[1].y) { + drawPixel(x, y, gs.rgba); + + if (d > 0 || (d == 0 && sy == 1)) { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} + +void drawLineF_F(Vertex * v) { + int dx = v[1].x - v[0].x; + int dy = v[1].y - v[0].y; + int ax = ABS(dx) << 1; + int ay = ABS(dy) << 1; + int sx = (dx >= 0) ? 1 : -1; + int sy = (dy >= 0) ? 1 : -1; + int x = v[0].x; + int y = v[0].y; + u32 f0, f1; + int df; + +#ifdef GS_LOG + GS_LOG("drawLineF_F %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, gs.rgba); +#endif + + SETdrawPixelF(); + + f0 = v[0].f << 16; + f1 = v[1].f << 16; + + if (ax > ay) { + int d = ay - (ax >> 1); + df = (f1 - f0) / dx; + while (x != v[1].x) { + drawPixelF(x, y, gs.rgba, f0 >> 16); + + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; d -= ax; + } + x += sx; d += ay; + f0+= df; + } + } else { + int d = ax - (ay >> 1); + df = (f1 - f0) / dy; + while (y != v[1].y) { + drawPixelF(x, y, gs.rgba, f0 >> 16); + + if (d > 0 || (d == 0 && sy == 1)) { + x += sx; d -= ay; + } + y += sy; d += ax; + f0+= df; + } + } +} + +void drawLineF_Z(Vertex * v) { + int dx = v[1].x - v[0].x; + int dy = v[1].y - v[0].y; + int ax = ABS(dx) << 1; + int ay = ABS(dy) << 1; + int sx = (dx >= 0) ? 1 : -1; + int sy = (dy >= 0) ? 1 : -1; + int x = v[0].x; + int y = v[0].y; + +#ifdef GS_LOG + GS_LOG("drawLineF_Z %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, gs.rgba); +#endif + + SETdrawPixelZ(); + + if (ax > ay) { + int d = ay - (ax >> 1); + while (x != v[1].x) { + drawPixelZ(x, y, gs.rgba, v[1].z); + + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; d -= ax; + } + x += sx; d += ay; + } + } else { + int d = ax - (ay >> 1); + while (y != v[1].y) { + drawPixelZ(x, y, gs.rgba, v[1].z); + + if (d > 0 || (d == 0 && sy == 1)) { + x += sx; d -= ay; + } + y += sy; d += ax; + } + } +} + +void drawLineG(Vertex * v) { + int dx = v[1].x - v[0].x; + int dy = v[1].y - v[0].y; + int ax = ABS(dx) << 1; + int ay = ABS(dy) << 1; + int sx = (dx >= 0) ? 1 : -1; + int sy = (dy >= 0) ? 1 : -1; + int x = v[0].x; + int y = v[0].y; + u32 r0, g0, b0, a0; + u32 r1, g1, b1, a1; + int dr, dg, db, da; + +#ifdef GS_LOG + GS_LOG("drawLineG %dx%d %x - %dx%d %x\n", + v[0].x, v[0].y, v[0].rgba, v[1].x, v[1].y, v[1].rgba); +#endif + + SETdrawPixel(); + + r0 = (v[0].rgba & 0x00ff0000); + g0 = (v[0].rgba & 0x0000ff00) << 8; + b0 = (v[0].rgba & 0x000000ff) << 16; + a0 = (v[0].rgba & 0xff000000) >> 8; + r1 = (v[1].rgba & 0x00ff0000); + g1 = (v[1].rgba & 0x0000ff00) << 8; + b1 = (v[1].rgba & 0x000000ff) << 16; + a1 = (v[1].rgba & 0xff000000) >> 8; + + if (ax > ay) { + int d = ay - (ax >> 1); + + if (dx == 0) return; + dr = ((int)r1 - (int)r0) / dx; + dg = ((int)g1 - (int)g0) / dx; + db = ((int)b1 - (int)b0) / dx; + da = ((int)a1 - (int)a0) / dx; + + while (x != v[1].x) { + drawPixel(x, y, ( r0 & 0xff0000) | + ((g0 & 0xff0000) >> 8) | + ((b0 & 0xff0000) >> 16) | + ((a0 & 0xff0000) << 8)); + + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; d += ay; + r0+= dr; g0+= dg; b0+= db; a0+= da; + } + } else { + int d = ax - (ay >> 1); + + if (dy == 0) return; + dr = ((int)r1 - (int)r0) / dy; + dg = ((int)g1 - (int)g0) / dy; + db = ((int)b1 - (int)b0) / dy; + da = ((int)a1 - (int)a0) / dy; + + while (y != v[1].y) { + drawPixel(x, y, ( r0 & 0xff0000) | + ((g0 & 0xff0000) >> 8) | + ((b0 & 0xff0000) >> 16) | + ((a0 & 0xff0000) << 8)); + + if (d > 0 || (d == 0 && sy == 1)) { + x += sx; + d -= ay; + } + y += sy; d += ax; + r0+= dr; g0+= dg; b0+= db; a0+= da; + } + } +} + +void drawLineG_Z(Vertex * v) { + int dx = v[1].x - v[0].x; + int dy = v[1].y - v[0].y; + int ax = ABS(dx) << 1; + int ay = ABS(dy) << 1; + int sx = (dx >= 0) ? 1 : -1; + int sy = (dy >= 0) ? 1 : -1; + int x = v[0].x; + int y = v[0].y; + u32 r0, g0, b0, a0; + u32 r1, g1, b1, a1; + int dr, dg, db, da; + +#ifdef GS_LOG + GS_LOG("drawLineG_Z %dx%d %x - %dx%d %x\n", + v[0].x, v[0].y, v[0].rgba, v[1].x, v[1].y, v[1].rgba); +#endif + + SETdrawPixelZ(); + + r0 = (v[0].rgba & 0x00ff0000); + g0 = (v[0].rgba & 0x0000ff00) << 8; + b0 = (v[0].rgba & 0x000000ff) << 16; + a0 = (v[0].rgba & 0xff000000) >> 8; + r1 = (v[1].rgba & 0x00ff0000); + g1 = (v[1].rgba & 0x0000ff00) << 8; + b1 = (v[1].rgba & 0x000000ff) << 16; + a1 = (v[1].rgba & 0xff000000) >> 8; + + if (ax > ay) { + int d = ay - (ax >> 1); + + if (dx == 0) return; + dr = ((int)r1 - (int)r0) / dx; + dg = ((int)g1 - (int)g0) / dx; + db = ((int)b1 - (int)b0) / dx; + da = ((int)a1 - (int)a0) / dx; + + while (x != v[1].x) { + drawPixelZ(x, y, ( r0 & 0xff0000) | + ((g0 & 0xff0000) >> 8) | + ((b0 & 0xff0000) >> 16) | + ((a0 & 0xff0000) << 8), v[1].z); + + if (d > 0 || (d == 0 && sx == 1)) { + y += sy; + d -= ax; + } + x += sx; d += ay; + r0+= dr; g0+= dg; b0+= db; + } + } else { + int d = ax - (ay >> 1); + + if (dy == 0) return; + dr = ((int)r1 - (int)r0) / dy; + dg = ((int)g1 - (int)g0) / dy; + db = ((int)b1 - (int)b0) / dy; + da = ((int)a1 - (int)a0) / dy; + + while (y != v[1].y) { + drawPixelZ(x, y, ( r0 & 0xff0000) | + ((g0 & 0xff0000) >> 8) | + ((b0 & 0xff0000) >> 16) | + ((a0 & 0xff0000) << 8), v[1].z); + + if (d > 0 || (d == 0 && sy == 1)) { + x += sx; + d -= ay; + } + y += sy; d += ax; + r0+= dr; g0+= dg; b0+= db; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawSprite(Vertex * v) { + int x, y; + +#ifdef GS_LOG + GS_LOG("drawSprite %dx%d - %dx%d %lx\n", + v[0].x, v[0].y, v[1].x, v[1].y, gs.rgba); +#endif + + SETdrawPixel(); + for (y = v[0].y; y < v[1].y; y++) + for (x = v[0].x; x < v[1].x; x++) + drawPixel(x, y, gs.rgba); +} + +void drawSprite_F(Vertex * v) { + int x, y; + +#ifdef GS_LOG + GS_LOG("drawSprite_F %dx%d - %dx%d %lx\n", + v[0].x, v[0].y, v[1].x, v[1].y, gs.rgba); +#endif + + SETdrawPixelF(); + for (y = v[0].y; y < v[1].y; y++) + for (x = v[0].x; x < v[1].x; x++) + drawPixelF(x, y, gs.rgba, v[1].f); +} + +void drawSprite_Z(Vertex * v) { + int x, y; + +#ifdef GS_LOG + GS_LOG("drawSprite_Z %dx%d %lx - %dx%d %lx\n", + v[0].x, v[0].y, v[0].rgba, v[1].x, v[1].y, v[1].rgba); +#endif + + SETdrawPixelZ(); + + for (y = v[0].y; y < v[1].y; y++) { + for (x = v[0].x; x < v[1].x; x++) { + drawPixelZ(x, y, gs.rgba, v[1].z); + } + } +} + +void drawSprite_ZF(Vertex * v) { + int x, y; + +#ifdef GS_LOG + GS_LOG("drawSprite_ZF %dx%d %lx - %dx%d %lx\n", + v[0].x, v[0].y, v[0].rgba, v[1].x, v[1].y, v[1].rgba); +#endif + + SETdrawPixelZF(); + + for (y = v[0].y; y < v[1].y; y++) { + for (x = v[0].x; x < v[1].x; x++) { + drawPixelZF(x, y, gs.rgba, v[1].z, v[1].f); + } + } +} + +//////////////////////////////////////////////////////////////////////// +// TEXTURED SPRITE +//////////////////////////////////////////////////////////////////////// + + +#define _drawSpriteT(ftx) \ + SetTexture(); \ + SETdrawPixel(); \ + \ + if (vx[1].x == vx[0].x) uinc = 0; \ + else uinc = ((vx[1].u - vx[0].u) << 16) / (vx[1].x - vx[0].x); \ + if (vx[1].y == vx[0].y) vinc = 0; \ + else vinc = ((vx[1].v - vx[0].v) << 16) / (vx[1].y - vx[0].y); \ + \ + for (y = vx[0].y, vpos = vx[0].v << 16; y < vx[1].y; y++, vpos+= vinc) { \ + v = vpos >> 16; \ + for (x = vx[0].x, upos = vx[0].u << 16; x < vx[1].x; x++, upos+= uinc) { \ + u = upos >> 16; \ + drawPixel(x, y, ftx); \ + } \ + } + +void drawSpriteTDecal(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTDecal %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + _drawSpriteT( + GetTexturePixel32(u, v) + ); +} + +void drawSpriteTModulate(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTModulate %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT( + colModulate(GetTexturePixel32(u, v)) + ); +} + +void drawSpriteTHighlight(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTHighlight %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT( + colHighlight(GetTexturePixel32(u, v)) + ); +} + +void drawSpriteTHighlight2(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTHighlight2 %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT( + colHighlight2(GetTexturePixel32(u, v)) + ); +} + +//////////////////////////////////////////////////////////////////////// +// TEXTURED SPRITE WITH Z-MAPPING +//////////////////////////////////////////////////////////////////////// + +#define _drawSpriteT_Z(ftx) \ + SetTexture(); \ + SETdrawPixelZ(); \ + \ + if (vx[1].x == vx[0].x) uinc = 0; \ + else uinc = ((vx[1].u - vx[0].u) << 16) / (vx[1].x - vx[0].x); \ + if (vx[1].y == vx[0].y) vinc = 0; \ + else vinc = ((vx[1].v - vx[0].v) << 16) / (vx[1].y - vx[0].y); \ + \ + for (y = vx[0].y, vpos = vx[0].v << 16; y < vx[1].y; y++, vpos+= vinc) { \ + v = vpos >> 16; \ + for (x = vx[0].x, upos = vx[0].u << 16; x < vx[1].x; x++, upos+= uinc) { \ + u = upos >> 16; \ + drawPixelZ(x, y, ftx, vx[1].z); \ + } \ + } + +void drawSpriteTDecal_Z(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTDecal_Z %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + _drawSpriteT_Z( + GetTexturePixel32(u, v) + ); +} + +void drawSpriteTModulate_Z(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTModulate_Z %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, tbp0=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->tbp0, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT_Z( + colModulate(GetTexturePixel32(u, v)) + ); +} + +void drawSpriteTHighlight_Z(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTHighlight_Z %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT_Z( + colHighlight(GetTexturePixel32(u, v)) + ); +} + +void drawSpriteTHighlight2_Z(Vertex * vx) { + int x, y; + int u, v; + int upos, uinc; + int vpos, vinc; + +#ifdef GS_LOG + GS_LOG("drawSpriteTHighlight2_Z %dx%d - %dx%d %lx; tex: %dx%d - %dx%d (psm=%x, cbp=%x, csm=%x, cpsm=%x)\n", + vx[0].x, vx[0].y, vx[1].x, vx[1].y, gs.rgba, + vx[0].u, vx[0].v, vx[1].u, vx[1].v, + tex0->psm, tex0->cbp, tex0->csm, tex0->cpsm); +#endif + + colSetCol(gs.rgba); + _drawSpriteT_Z( + colHighlight2(GetTexturePixel32(u, v)) + ); +} + + + +typedef struct { + s32 X, U, V; + s32 R, G, B, A; + s64 Z; +} tagPolyEdge; + +tagPolyEdge ForwardEdges[1024*8]; +tagPolyEdge BackwardEdges[1024*8]; + +#define drawTriangle(scanFunc, drawFunc) { \ + int i; \ + int nYMin, nYMax; \ + int nPosMin, nPosMax; \ + int nPos1, nPos2; \ + int nY; \ + \ + nYMin = v[0].y; \ + nYMax = v[0].y; \ + nPosMin = 0; \ + nPosMax = 0; \ + \ + for (i=1; i<3; i++) { \ + if (v[i].y > nYMax) { \ + nYMax = v[i].y; \ + nPosMax = i; \ + } \ + \ + if (v[i].y < nYMin) { \ + nYMin = v[i].y; \ + nPosMin = i; \ + } \ + } \ + \ + if (nYMax == nYMin) \ + return; \ + \ + nPos1 = nPosMin; \ + nPos2 = nPos1; \ + while (nPos1 != nPosMax) { \ + nPos2 ++; \ + if (nPos2 == 3) \ + nPos2 = 0; \ + \ + scanFunc(ForwardEdges, &v[nPos1], &v[nPos2]); \ + nPos1 = nPos2; \ + } \ + \ + nPos1 = nPosMin; \ + nPos2 = nPos1; \ + while (nPos1 != nPosMax) { \ + nPos2 --; \ + if (nPos2 == -1) \ + nPos2 = 2; \ + \ + scanFunc(BackwardEdges, &v[nPos1], &v[nPos2]); \ + nPos1 = nPos2; \ + } \ + \ + if (nYMin < 0) nYMin = 0; \ + for (nY = nYMin; nY < nYMax; nY++) { \ + if (BackwardEdges[nY].X < ForwardEdges[nY].X) { \ + drawFunc(nY, &BackwardEdges[nY], &ForwardEdges[nY]); \ + } else { \ + drawFunc(nY, &ForwardEdges[nY], &BackwardEdges[nY]); \ + } \ + } \ +} + + +void scanEdgeF(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + int nX, nY; + int nXInc; + + if (v1->y == v2->y) + return; + + nX = v1->x << 16; + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + } +} + +void drawHLineF(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { + int nX; + + if (stEdgeEnd->X <= stEdgeIni->X) { + return; + } + + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { + drawPixel(nX, nY, gs.rgba); + } +} + +void drawTriangleF(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleF %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); +#endif + + SETdrawPixel(); + + drawTriangle(scanEdgeF, drawHLineF); +} + +void scanEdgeFZ(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + s32 nX, nY; + s32 nXInc; + s64 nZ; + s64 nZInc; + + if (v1->y == v2->y) + return; + + nX = v1->x << 16; + nZ = (u64)v1->z << 16; + + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nZInc = ((s64)((s64)v2->z - v1->z) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nZ += nZInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].Z = nZ; nZ += nZInc; + } +} + +void drawHLineFZ(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { + s32 nX; + s64 nZ; + s64 nZInc; + + if (stEdgeEnd->X <= stEdgeIni->X) { + return; + } + + nZ = stEdgeIni->Z; + nZInc = (s64)((s64)stEdgeEnd->Z - stEdgeIni->Z) / (stEdgeEnd->X - stEdgeIni->X); + + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { + drawPixelZ(nX, nY, gs.rgba, (u32)(nZ >> 16)); + nZ += nZInc; + } +} + +void drawTriangleF_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleF_Z %dx%dx%lx - %dx%dx%lx - %dx%dx%lx rgba=%x\n", + v[0].x, v[0].y, v[0].z, v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z, gs.rgba); +#endif + + SETdrawPixelZ(); + + drawTriangle(scanEdgeFZ, drawHLineFZ); +} + + +void scanEdgeG(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + s32 nX, nY, nR, nG, nB, nA; + s32 nXInc, nRInc, nGInc, nBInc, nAInc; + s32 r1, g1, b1, a1; + s32 r2, g2, b2, a2; + + if (v1->y == v2->y) + return; + + b1 = (v1->rgba & 0x000000FF); + g1 = (v1->rgba & 0x0000FF00) >> 8; + r1 = (v1->rgba & 0x00FF0000) >> 16; + a1 = (v1->rgba & 0xFF000000) >> 24; + b2 = (v2->rgba & 0x000000FF); + g2 = (v2->rgba & 0x0000FF00) >> 8; + r2 = (v2->rgba & 0x00FF0000) >> 16; + a2 = (v2->rgba & 0xFF000000) >> 24; + + nX = v1->x << 16; + nR = r1 << 16; + nG = g1 << 16; + nB = b1 << 16; + nA = a1 << 16; + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nRInc = (( r2 - r1) << 16) / (v2->y - v1->y); + nGInc = (( g2 - g1) << 16) / (v2->y - v1->y); + nBInc = (( b2 - b1) << 16) / (v2->y - v1->y); + nAInc = (( a2 - a1) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nR += nRInc; + nG += nGInc; + nB += nBInc; + nA += nAInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].R = nR; nR += nRInc; + pastEdge[nY].G = nG; nG += nGInc; + pastEdge[nY].B = nB; nB += nBInc; + pastEdge[nY].A = nA; nA += nAInc; + } +} + +void drawHLineG(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { + s32 nX, nR, nG, nB, nA; + s32 nRInc, nGInc, nBInc, nAInc; + + if (stEdgeEnd->X <= stEdgeIni->X) { + return; + } + + nR = stEdgeIni->R; + nG = stEdgeIni->G; + nB = stEdgeIni->B; + nA = stEdgeIni->A; + nRInc = (stEdgeEnd->R - stEdgeIni->R) / (stEdgeEnd->X - stEdgeIni->X); + nGInc = (stEdgeEnd->G - stEdgeIni->G) / (stEdgeEnd->X - stEdgeIni->X); + nBInc = (stEdgeEnd->B - stEdgeIni->B) / (stEdgeEnd->X - stEdgeIni->X); + nAInc = (stEdgeEnd->A - stEdgeIni->A) / (stEdgeEnd->X - stEdgeIni->X); + + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { + drawPixel(nX, nY, ( nR & 0xff0000) | + ((nG & 0xff0000) >> 8) | + ((nB & 0xff0000) >> 16) | + ((nA & 0xff0000) << 8)); + nR += nRInc; nG += nGInc; nB += nBInc; nA += nAInc; + } +} + +void drawTriangleG(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleG %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, v[0].rgba); +#endif + + SETdrawPixel(); + + drawTriangle(scanEdgeG, drawHLineG); +} + + +void scanEdgeGZ(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + s32 nX, nY, nR, nG, nB, nA; + s32 nXInc, nRInc, nGInc, nBInc, nAInc; + s32 r1, g1, b1, a1; + s32 r2, g2, b2, a2; + s64 nZ; + s64 nZInc; + + if (v1->y == v2->y) + return; + + b1 = (v1->rgba & 0x000000FF); + g1 = (v1->rgba & 0x0000FF00) >> 8; + r1 = (v1->rgba & 0x00FF0000) >> 16; + a1 = (v1->rgba & 0xFF000000) >> 24; + b2 = (v2->rgba & 0x000000FF); + g2 = (v2->rgba & 0x0000FF00) >> 8; + r2 = (v2->rgba & 0x00FF0000) >> 16; + a2 = (v2->rgba & 0xFF000000) >> 24; + + nX = v1->x << 16; + nZ = (u64)v1->z << 16; + nR = r1 << 16; + nG = g1 << 16; + nB = b1 << 16; + nA = a1 << 16; + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nZInc = ((s64)((s64)v2->z - v1->z) << 16) / (v2->y - v1->y); + nRInc = (( r2 - r1) << 16) / (v2->y - v1->y); + nGInc = (( g2 - g1) << 16) / (v2->y - v1->y); + nBInc = (( b2 - b1) << 16) / (v2->y - v1->y); + nAInc = (( a2 - a1) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nZ += nZInc; + nR += nRInc; + nG += nGInc; + nB += nBInc; + nA += nAInc; + } + for (;nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].Z = nZ; nZ += nZInc; + pastEdge[nY].R = nR; nR += nRInc; + pastEdge[nY].G = nG; nG += nGInc; + pastEdge[nY].B = nB; nB += nBInc; + pastEdge[nY].A = nA; nA += nAInc; + } +} + +void drawHLineGZ(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { + s32 nX, nR, nG, nB, nA; + s32 nRInc, nGInc, nBInc, nAInc; + s64 nZ; + s64 nZInc; + + if (stEdgeEnd->X <= stEdgeIni->X) { + return; + } + + nZ = stEdgeIni->Z; + nR = stEdgeIni->R; + nG = stEdgeIni->G; + nB = stEdgeIni->B; + nA = stEdgeIni->A; + nZInc = (s64)((s64)stEdgeEnd->Z - stEdgeIni->Z) / (stEdgeEnd->X - stEdgeIni->X); + nRInc = (stEdgeEnd->R - stEdgeIni->R) / (stEdgeEnd->X - stEdgeIni->X); + nGInc = (stEdgeEnd->G - stEdgeIni->G) / (stEdgeEnd->X - stEdgeIni->X); + nBInc = (stEdgeEnd->B - stEdgeIni->B) / (stEdgeEnd->X - stEdgeIni->X); + nAInc = (stEdgeEnd->A - stEdgeIni->A) / (stEdgeEnd->X - stEdgeIni->X); + + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { + drawPixelZ(nX, nY, ( nR & 0xff0000) | + ((nG & 0xff0000) >> 8) | + ((nB & 0xff0000) >> 16) | + ((nA & 0xff0000) << 8), (u32)(nZ >> 16)); + nZ += nZInc; + nR += nRInc; nG += nGInc; nB += nBInc; nA += nAInc; + } +} + +void drawTriangleG_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleG_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, v[0].rgba); +#endif + + SETdrawPixelZ(); + + drawTriangle(scanEdgeGZ, drawHLineGZ); +} + + +void scanEdgeFT(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + int nX, nY, nU, nV; + int nXInc, nUInc, nVInc; + + if (v1->y == v2->y) + return; + + nX = v1->x << 16; + nU = v1->u << 16; + nV = v1->v << 16; + + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nUInc = ((v2->u - v1->u) << 16) / (v2->y - v1->y); + nVInc = ((v2->v - v1->v) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nU += nUInc; + nV += nVInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].U = nU; nU += nUInc; + pastEdge[nY].V = nV; nV += nVInc; + } +} + + +#define _drawHLineFT(name, ftx) \ +void drawHLineFT##name(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { \ + int nX, nU, nV; \ + int nUInc, nVInc; \ + \ + if (stEdgeEnd->X <= stEdgeIni->X) { \ + return; \ + } \ + \ + nX = stEdgeIni->X; \ + nU = stEdgeIni->U; \ + nV = stEdgeIni->V; \ + nUInc = (stEdgeEnd->U - stEdgeIni->U) / (stEdgeEnd->X - stEdgeIni->X); \ + nVInc = (stEdgeEnd->V - stEdgeIni->V) / (stEdgeEnd->X - stEdgeIni->X); \ + \ + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { \ + drawPixel(nX, nY, ftx); \ + nU += nUInc; nV += nVInc; \ + } \ +} + +_drawHLineFT(Decal, + GetTexturePixel32(nU >> 16, nV >> 16) +); +_drawHLineFT(Modulate, + colModulate(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineFT(Highlight, + colHighlight(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineFT(Highlight2, + colHighlight2(GetTexturePixel32(nU >> 16, nV >> 16)) +); + +void drawTriangleFTDecal(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTDecal %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + + drawTriangle(scanEdgeFT, drawHLineFTDecal); +} + +void drawTriangleFTModulate(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTModulate %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFT, drawHLineFTModulate); +} + +void drawTriangleFTHighlight(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTHighlight %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFT, drawHLineFTHighlight); +} + +void drawTriangleFTHighlight2(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTHighlight2 %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFT, drawHLineFTHighlight2); +} + +void scanEdgeFTZ(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + int nX, nY, nU, nV; + int nXInc, nUInc, nVInc; + s64 nZ; + s64 nZInc; + + if (v1->y == v2->y) + return; + + nX = v1->x << 16; + nZ = (u64)v1->z << 16; + nU = v1->u << 16; + nV = v1->v << 16; + + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nZInc = ((s64)((s64)v2->z - v1->z) << 16) / (v2->y - v1->y); + nUInc = ((v2->u - v1->u) << 16) / (v2->y - v1->y); + nVInc = ((v2->v - v1->v) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nZ += nZInc; + nU += nUInc; + nV += nVInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].Z = nZ; nZ += nZInc; + pastEdge[nY].U = nU; nU += nUInc; + pastEdge[nY].V = nV; nV += nVInc; + } +} + + +#define _drawHLineFTZ(name, ftx) \ +void drawHLineFTZ##name(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { \ + int nX, nU, nV; \ + int nUInc, nVInc; \ + s64 nZ; \ + s64 nZInc; \ + \ + if (stEdgeEnd->X <= stEdgeIni->X) { \ + return; \ + } \ + \ + nX = stEdgeIni->X; \ + nZ = stEdgeIni->Z; \ + nU = stEdgeIni->U; \ + nV = stEdgeIni->V; \ + nZInc = (s64)((s64)stEdgeEnd->Z - stEdgeIni->Z) / (stEdgeEnd->X - stEdgeIni->X); \ + nUInc = (stEdgeEnd->U - stEdgeIni->U) / (stEdgeEnd->X - stEdgeIni->X); \ + nVInc = (stEdgeEnd->V - stEdgeIni->V) / (stEdgeEnd->X - stEdgeIni->X); \ + \ + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { \ + drawPixelZ(nX, nY, ftx, (u32)(nZ >> 16)); \ + nZ += nZInc; \ + nU += nUInc; nV += nVInc; \ + } \ +} + +_drawHLineFTZ(Decal, + GetTexturePixel32(nU >> 16, nV >> 16) +); +_drawHLineFTZ(Modulate, + colModulate(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineFTZ(Highlight, + colHighlight(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineFTZ(Highlight2, + colHighlight2(GetTexturePixel32(nU >> 16, nV >> 16)) +); + +void drawTriangleFTDecal_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTDecal_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + + drawTriangle(scanEdgeFTZ, drawHLineFTZDecal); +} + +void drawTriangleFTModulate_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTModulate_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFTZ, drawHLineFTZModulate); +} + +void drawTriangleFTHighlight_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTHighlight_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFTZ, drawHLineFTZHighlight); +} + +void drawTriangleFTHighlight2_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleFTHighlight2_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + colSetCol(gs.rgba); + + drawTriangle(scanEdgeFTZ, drawHLineFTZHighlight2); +} + +/**************************/ +/* Gouraud Shaded/Textued */ + +void scanEdgeGT(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + s32 nX, nU, nV, nY, nR, nG, nB, nA; + s32 nXInc, nUInc, nVInc, nRInc, nGInc, nBInc, nAInc; + s32 r1, g1, b1, a1; + s32 r2, g2, b2, a2; + + if (v1->y == v2->y) + return; + + b1 = (v1->rgba & 0x000000FF); + g1 = (v1->rgba & 0x0000FF00) >> 8; + r1 = (v1->rgba & 0x00FF0000) >> 16; + a1 = (v1->rgba & 0xFF000000) >> 24; + b2 = (v2->rgba & 0x000000FF); + g2 = (v2->rgba & 0x0000FF00) >> 8; + r2 = (v2->rgba & 0x00FF0000) >> 16; + a2 = (v2->rgba & 0xFF000000) >> 24; + + nX = v1->x << 16; + nR = r1 << 16; + nG = g1 << 16; + nB = b1 << 16; + nA = a1 << 16; + nU = v1->u << 16; + nV = v1->v << 16; + + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nRInc = (( r2 - r1) << 16) / (v2->y - v1->y); + nGInc = (( g2 - g1) << 16) / (v2->y - v1->y); + nBInc = (( b2 - b1) << 16) / (v2->y - v1->y); + nAInc = (( a2 - a1) << 16) / (v2->y - v1->y); + nUInc = ((v2->u - v1->u) << 16) / (v2->y - v1->y); + nVInc = ((v2->v - v1->v) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nU += nUInc; + nV += nVInc; + nR += nRInc; + nG += nGInc; + nB += nBInc; + nA += nAInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].U = nU; nU += nUInc; + pastEdge[nY].V = nV; nV += nVInc; + pastEdge[nY].R = nR; nR += nRInc; + pastEdge[nY].G = nG; nG += nGInc; + pastEdge[nY].B = nB; nB += nBInc; + pastEdge[nY].A = nA; nA += nAInc; + } +} + +#define _drawHLineGT(name, ftx) \ +void drawHLineGT##name(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { \ + s32 nX, nU, nV, nR, nG, nB, nA; \ + s32 nUInc, nVInc, nRInc, nGInc, nBInc, nAInc; \ + \ + if (stEdgeEnd->X <= stEdgeIni->X) { \ + return; \ + } \ + \ + nR = stEdgeIni->R; \ + nG = stEdgeIni->G; \ + nB = stEdgeIni->B; \ + nA = stEdgeIni->A; \ + nU = stEdgeIni->U; \ + nV = stEdgeIni->V; \ + nRInc = (stEdgeEnd->R - stEdgeIni->R) / (stEdgeEnd->X - stEdgeIni->X); \ + nGInc = (stEdgeEnd->G - stEdgeIni->G) / (stEdgeEnd->X - stEdgeIni->X); \ + nBInc = (stEdgeEnd->B - stEdgeIni->B) / (stEdgeEnd->X - stEdgeIni->X); \ + nAInc = (stEdgeEnd->A - stEdgeIni->A) / (stEdgeEnd->X - stEdgeIni->X); \ + nUInc = (stEdgeEnd->U - stEdgeIni->U) / (stEdgeEnd->X - stEdgeIni->X); \ + nVInc = (stEdgeEnd->V - stEdgeIni->V) / (stEdgeEnd->X - stEdgeIni->X); \ + \ + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { \ + colSetCol(( nR & 0xff0000) | \ + ((nG & 0xff0000) >> 8) | \ + ((nB & 0xff0000) >> 16) | \ + ((nA & 0xff0000) << 8)); \ + drawPixel(nX, nY, ftx); \ + nU += nUInc; nV += nVInc; \ + nR += nRInc; nG += nGInc; nB += nBInc; nA += nAInc; \ + } \ +} + +_drawHLineGT(Modulate, + colModulate(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineGT(Highlight, + colHighlight(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineGT(Highlight2, + colHighlight2(GetTexturePixel32(nU >> 16, nV >> 16)) +); + + +void drawTriangleGTDecal(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTDecal %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + drawTriangleFTDecal(v); +} + +void drawTriangleGTModulate(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTModulate %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + + drawTriangle(scanEdgeGT, drawHLineGTModulate); +} + +void drawTriangleGTHighlight(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTHighlight %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + + drawTriangle(scanEdgeGT, drawHLineGTHighlight); +} + +void drawTriangleGTHighlight2(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTHighlight2 %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixel(); + + drawTriangle(scanEdgeGT, drawHLineGTHighlight2); +} + +void scanEdgeGTZ(tagPolyEdge* pastEdge, Vertex *v1, Vertex *v2) { + s32 nX, nU, nV, nY, nR, nG, nB, nA; + s32 nXInc, nUInc, nVInc, nRInc, nGInc, nBInc, nAInc; + s64 nZ; + s64 nZInc; + s32 r1, g1, b1, a1; + s32 r2, g2, b2, a2; + + if (v1->y == v2->y) + return; + + b1 = (v1->rgba & 0x000000FF); + g1 = (v1->rgba & 0x0000FF00) >> 8; + r1 = (v1->rgba & 0x00FF0000) >> 16; + a1 = (v1->rgba & 0xFF000000) >> 24; + b2 = (v2->rgba & 0x000000FF); + g2 = (v2->rgba & 0x0000FF00) >> 8; + r2 = (v2->rgba & 0x00FF0000) >> 16; + a2 = (v2->rgba & 0xFF000000) >> 24; + + nX = v1->x << 16; + nZ = (u64)v1->z << 16; + nR = r1 << 16; + nG = g1 << 16; + nB = b1 << 16; + nA = a1 << 16; + nU = v1->u << 16; + nV = v1->v << 16; + + nXInc = ((v2->x - v1->x) << 16) / (v2->y - v1->y); + nZInc = ((s64)((s64)v2->z - v1->z) << 16) / (v2->y - v1->y); + nRInc = (( r2 - r1) << 16) / (v2->y - v1->y); + nGInc = (( g2 - g1) << 16) / (v2->y - v1->y); + nBInc = (( b2 - b1) << 16) / (v2->y - v1->y); + nAInc = (( a2 - a1) << 16) / (v2->y - v1->y); + nUInc = ((v2->u - v1->u) << 16) / (v2->y - v1->y); + nVInc = ((v2->v - v1->v) << 16) / (v2->y - v1->y); + + for (nY = v1->y; nY < 0; nY++) { + nX += nXInc; + nZ += nZInc; + nU += nUInc; + nV += nVInc; + nR += nRInc; + nG += nGInc; + nB += nBInc; + nA += nAInc; + } + for (; nY < v2->y; nY++) { + pastEdge[nY].X = nX >> 16; nX += nXInc; + pastEdge[nY].Z = nZ; nZ += nZInc; + pastEdge[nY].U = nU; nU += nUInc; + pastEdge[nY].V = nV; nV += nVInc; + pastEdge[nY].R = nR; nR += nRInc; + pastEdge[nY].G = nG; nG += nGInc; + pastEdge[nY].B = nB; nB += nBInc; + pastEdge[nY].A = nA; nA += nAInc; + } +} + +#define _drawHLineGTZ(name, ftx) \ +void drawHLineGTZ##name(int nY, tagPolyEdge *stEdgeIni, tagPolyEdge *stEdgeEnd) { \ + s32 nX, nU, nV, nR, nG, nB, nA; \ + s32 nUInc, nVInc, nRInc, nGInc, nBInc, nAInc; \ + s64 nZ; \ + s64 nZInc; \ + \ + if (stEdgeEnd->X <= stEdgeIni->X) { \ + return; \ + } \ + \ + nZ = stEdgeIni->Z; \ + nR = stEdgeIni->R; \ + nG = stEdgeIni->G; \ + nB = stEdgeIni->B; \ + nA = stEdgeIni->A; \ + nU = stEdgeIni->U; \ + nV = stEdgeIni->V; \ + nZInc = (s64)((s64)stEdgeEnd->Z - stEdgeIni->Z) / (stEdgeEnd->X - stEdgeIni->X); \ + nRInc = (stEdgeEnd->R - stEdgeIni->R) / (stEdgeEnd->X - stEdgeIni->X); \ + nGInc = (stEdgeEnd->G - stEdgeIni->G) / (stEdgeEnd->X - stEdgeIni->X); \ + nBInc = (stEdgeEnd->B - stEdgeIni->B) / (stEdgeEnd->X - stEdgeIni->X); \ + nAInc = (stEdgeEnd->A - stEdgeIni->A) / (stEdgeEnd->X - stEdgeIni->X); \ + nUInc = (stEdgeEnd->U - stEdgeIni->U) / (stEdgeEnd->X - stEdgeIni->X); \ + nVInc = (stEdgeEnd->V - stEdgeIni->V) / (stEdgeEnd->X - stEdgeIni->X); \ + \ + for (nX = stEdgeIni->X; nX <= stEdgeEnd->X; nX++) { \ + colSetCol(( nR & 0xff0000) | \ + ((nG & 0xff0000) >> 8) | \ + ((nB & 0xff0000) >> 16) | \ + ((nA & 0xff0000) << 8)); \ + drawPixelZ(nX, nY, ftx, (u32)(nZ >> 16)); \ + nZ += nZInc; \ + nU += nUInc; nV += nVInc; \ + nR += nRInc; nG += nGInc; nB += nBInc; nA += nAInc; \ + } \ +} + +_drawHLineGTZ(Modulate, + colModulate(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineGTZ(Highlight, + colHighlight(GetTexturePixel32(nU >> 16, nV >> 16)) +); +_drawHLineGTZ(Highlight2, + colHighlight2(GetTexturePixel32(nU >> 16, nV >> 16)) +); + +void drawTriangleGTDecal_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTDecal_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + drawTriangleFTDecal_Z(v); +} + +void drawTriangleGTModulate_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTModulate_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + + drawTriangle(scanEdgeGTZ, drawHLineGTZModulate); +} + +void drawTriangleGTHighlight_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTHighlight_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + + drawTriangle(scanEdgeGTZ, drawHLineGTZHighlight); +} + +void drawTriangleGTHighlight2_Z(Vertex * v) { +#ifdef GS_LOG + GS_LOG("drawTriangleGTHighlight2_Z %dx%d - %dx%d - %dx%d rgba=%x\n", + v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, gs.rgba); + GS_LOG("uv: %xx%x - %xx%x - %xx%x\n", + v[0].u, v[0].v, v[1].u, v[1].v, v[2].u, v[2].v); +#endif + + SetTexture(); + SETdrawPixelZ(); + + drawTriangle(scanEdgeGTZ, drawHLineGTZHighlight2); +} + + +/* + 3DFC + http://www.geocities.com/SiliconValley/Bay/1704 + +*/ + diff --git a/plugins/gs/GSsoft/Src/Soft.h b/plugins/gs/GSsoft/Src/Soft.h new file mode 100644 index 0000000000..5fb5695aba --- /dev/null +++ b/plugins/gs/GSsoft/Src/Soft.h @@ -0,0 +1,107 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __SOFT_H__ +#define __SOFT_H__ + +void drawLineF(Vertex *v); +void drawLineF_Z(Vertex *v); +void drawLineF_F(Vertex *v); +void drawLineF_ZF(Vertex *v); + +void drawLineG(Vertex *v); +void drawLineG_Z(Vertex *v); +void drawLineG_F(Vertex *v); +void drawLineG_ZF(Vertex *v); + +void drawTriangleF(Vertex *v); +void drawTriangleF_Z(Vertex *v); +void drawTriangleF_F(Vertex *v); +void drawTriangleF_ZF(Vertex *v); + +void drawTriangleG(Vertex *v); +void drawTriangleG_Z(Vertex *v); +void drawTriangleG_F(Vertex *v); +void drawTriangleG_ZF(Vertex *v); + +void drawTriangleFTDecal(Vertex *v); +void drawTriangleFTDecal_Z(Vertex * v); +void drawTriangleFTDecal_F(Vertex * v); +void drawTriangleFTDecal_ZF(Vertex * v); + +void drawTriangleFTModulate(Vertex *v); +void drawTriangleFTModulate_Z(Vertex * v); +void drawTriangleFTModulate_F(Vertex * v); +void drawTriangleFTModulate_ZF(Vertex * v); + +void drawTriangleFTHighlight(Vertex *v); +void drawTriangleFTHighlight_Z(Vertex * v); +void drawTriangleFTHighlight_F(Vertex * v); +void drawTriangleFTHighlight_ZF(Vertex * v); + +void drawTriangleFTHighlight2(Vertex *v); +void drawTriangleFTHighlight2_Z(Vertex * v); +void drawTriangleFTHighlight2_F(Vertex * v); +void drawTriangleFTHighlight2_ZF(Vertex * v); + +void drawTriangleGTDecal(Vertex *v); +void drawTriangleGTDecal_Z(Vertex * v); +void drawTriangleGTDecal_F(Vertex * v); +void drawTriangleGTDecal_ZF(Vertex * v); + +void drawTriangleGTModulate(Vertex *v); +void drawTriangleGTModulate_Z(Vertex * v); +void drawTriangleGTModulate_F(Vertex * v); +void drawTriangleGTModulate_ZF(Vertex * v); + +void drawTriangleGTHighlight(Vertex *v); +void drawTriangleGTHighlight_Z(Vertex * v); +void drawTriangleGTHighlight_F(Vertex * v); +void drawTriangleGTHighlight_ZF(Vertex * v); + +void drawTriangleGTHighlight2(Vertex *v); +void drawTriangleGTHighlight2_Z(Vertex * v); +void drawTriangleGTHighlight2_F(Vertex * v); +void drawTriangleGTHighlight2_ZF(Vertex * v); + +void drawSprite(Vertex *v); +void drawSprite_Z(Vertex *v); +void drawSprite_F(Vertex *v); +void drawSprite_ZF(Vertex *v); + +void drawSpriteTDecal(Vertex *v); +void drawSpriteTDecal_Z(Vertex * v); +void drawSpriteTDecal_F(Vertex * v); +void drawSpriteTDecal_ZF(Vertex * v); + +void drawSpriteTModulate(Vertex *v); +void drawSpriteTModulate_Z(Vertex * v); +void drawSpriteTModulate_F(Vertex * v); +void drawSpriteTModulate_ZF(Vertex * v); + +void drawSpriteTHighlight(Vertex *v); +void drawSpriteTHighlight_Z(Vertex * v); +void drawSpriteTHighlight_F(Vertex * v); +void drawSpriteTHighlight_ZF(Vertex * v); + +void drawSpriteTHighlight2(Vertex *v); +void drawSpriteTHighlight2_Z(Vertex * v); +void drawSpriteTHighlight2_F(Vertex * v); +void drawSpriteTHighlight2_ZF(Vertex * v); + +#endif /* __SOFT_H__ */ diff --git a/plugins/gs/GSsoft/Src/System.h b/plugins/gs/GSsoft/Src/System.h new file mode 100644 index 0000000000..b855f3ef22 --- /dev/null +++ b/plugins/gs/GSsoft/Src/System.h @@ -0,0 +1,29 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +void SysMessage(char *fmt, ...); // Message used to print msg to users +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library + +#endif /* __SYSTEM_H__ */ diff --git a/plugins/gs/GSsoft/Src/Texts.c b/plugins/gs/GSsoft/Src/Texts.c new file mode 100644 index 0000000000..b87496e685 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Texts.c @@ -0,0 +1,544 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + +#include "GS.h" +#include "Texts.h" +#include "Mem.h" +#include "Cache.h" + +u32 clud[256]; + +void copy_clut32_8(u32 *clud) { + int x, y; + int cy; + int i; + + for (y=0, cy=0; y < 8; y++) { +// GS_LOG("clut1[%d];\n", cy); + for(x=0, i=0; x < 8; x++, i++) { + clud[y*32 + x] = readPixel32(i, cy, tex0->cbp, 64); +// GS_LOG("clut[%d] = %x\n", x, clud[y*32 + x]); + } + for(x=16; x < 24; x++, i++) { + clud[y*32 + x] = readPixel32(i, cy, tex0->cbp, 64); +// GS_LOG("clut[%d] = %x\n", x, clud[y*32 + x]); + } + cy++; + +// GS_LOG("clut2[%d];\n", cy); + for(x=8, i=0; x < 16; x++, i++) { + clud[y*32 + x] = readPixel32(i, cy, tex0->cbp, 64); +// GS_LOG("clut[%d] = %x\n", x, clud[y*32 + x]); + } + for(x=24; x < 32; x++, i++) { + clud[y*32 + x] = readPixel32(i, cy, tex0->cbp, 64); +// GS_LOG("clut[%d] = %x\n", x, clud[y*32 + x]); + } + cy++; + } +} + +void copy_clut32_4(u32 *clud) { + int x, y; + + for (y = 0; y < 2; y++) { + for(x = 0; x < 8; x++) { + clud[y*8 + x] = readPixel32(x, y, tex0->cbp, 64); +// GS_LOG("clut[%d] = %x\n", x, clud[y*8 + x]); + } + } +} + +u32 _readPixel16(int x, int y, u32 bp, u32 bw) { + u32 c = readPixel16(x, y, bp, bw); + u32 p; + + p = ((c & 0x7c00) << 9) | + ((c & 0x03e0) << 6) | + ((c & 0x001f) << 3); + if (gs.texa.aem) { + if (c & 0x8000) { + p|= gs.texa.ta[1] << 24; + } else { + if (p) p|= gs.texa.ta[0] << 24; + } + } else { + p|= gs.texa.ta[(c & 0x8000) >> 15] << 24; + } + + return p; +} + +u32 _readPixel16S(int x, int y, u32 bp, u32 bw) { + u32 c = readPixel16S(x, y, bp, bw); + u32 p; + + p = ((c & 0x7c00) << 9) | + ((c & 0x03e0) << 6) | + ((c & 0x001f) << 3); + if (gs.texa.aem) { + if (c & 0x8000) { + p|= gs.texa.ta[1] << 24; + } else { + if (p) p|= gs.texa.ta[0] << 24; + } + } else { + p|= gs.texa.ta[(c & 0x8000) >> 15] << 24; + } + + return p; +} + +u32 _readPixel24(int x, int y, u32 bp, u32 bw) { + u32 c = readPixel24(x, y, bp, bw); + + if (gs.texa.aem) { + if (c) c|= gs.texa.ta[0] << 24; + } else { + c|= gs.texa.ta[0] << 24; + } + + return c; +} + +void copy_clut16S_8_1(u32 *clup) { + int x, y; + int cy; + int i; + + for (y=0, cy=0; y < 8; y++) { + for(x=0, i=0; x < 8; x++, i++) { + clud[y*32 + x] = _readPixel16S(i, cy, tex0->cbp, 64); + } + for(x=16; x < 24; x++, i++) { + clud[y*32 + x] = _readPixel16S(i, cy, tex0->cbp, 64); + } + cy++; + + for(x=8, i=0; x < 16; x++, i++) { + clud[y*32 + x] = _readPixel16S(i, cy, tex0->cbp, 64); + } + for(x=24; x < 32; x++, i++) { + clud[y*32 + x] = _readPixel16S(i, cy, tex0->cbp, 64); + } + cy++; + } +} + +void copy_clut16S_8_2(u32 *clup) { + int i; + + for (i=0; i < 256; i++) { + clud[i] = _readPixel16S(gs.clut.cou + i, gs.clut.cov, tex0->cbp, gs.clut.cbw); + } +} + +void copy_clut16_8_1(u32 *clup) { + int x, y; + int cy; + int i; + + for (y=0, cy=0; y < 8; y++) { + for(x=0, i=0; x < 8; x++, i++) { + clud[y*32 + x] = _readPixel16(i, cy, tex0->cbp, 64); + } + for(x=16; x < 24; x++, i++) { + clud[y*32 + x] = _readPixel16(i, cy, tex0->cbp, 64); + } + cy++; + + for(x=8, i=0; x < 16; x++, i++) { + clud[y*32 + x] = _readPixel16(i, cy, tex0->cbp, 64); + } + for(x=24; x < 32; x++, i++) { + clud[y*32 + x] = _readPixel16(i, cy, tex0->cbp, 64); + } + cy++; + } +} + +void copy_clut16_8_2(u32 *clup) { + int i; + + for (i=0; i < 256; i++) { + clud[i] = _readPixel16(gs.clut.cou + i, gs.clut.cov, tex0->cbp, gs.clut.cbw); + } +} + +void copy_clut16_4_1(u32 *clud) { + int x, y; + + for (y = 0; y < 2; y++) { + for(x = 0; x < 8; x++) { + clud[y*8 + x] = _readPixel16(x, y, tex0->cbp, 64); + } + } +} + +void copy_clut16_4_2(u32 *clup) { + int i; + + for (i=0; i < 16; i++) { + clud[i] = _readPixel16(gs.clut.cou + i, gs.clut.cov, tex0->cbp, gs.clut.cbw); + } +} + +void copy_clut16S_4_1(u32 *clud) { + int x, y; + + for (y = 0; y < 2; y++) { + for(x = 0; x < 8; x++) { + clud[y*8 + x] = _readPixel16S(x, y, tex0->cbp, 64); + } + } +} + +void copy_clut16S_4_2(u32 *clup) { + int i; + + for (i=0; i < 16; i++) { + clud[i] = _readPixel16S(gs.clut.cou + i, gs.clut.cov, tex0->cbp, gs.clut.cbw); + } +} + +void wrapUV(int *u, int *v) { + switch (clamp->wms) { + case 0: // REPEAT + *u = *u % tex0->tw; + break; + + case 1: // CLAMP + if (*u < 0) *u = 0; + if (*u >= tex0->tw) *u = tex0->tw - 1; + break; + + case 2: // REGION_CLAMP + if (*u < clamp->minu) *u = clamp->minu; + if (*u > clamp->maxu) *u = clamp->maxu; + break; + + case 3: // REGION_REPEAT + printf("REGION_REPEAT\n"); + *u = (*u & clamp->minu) | clamp->maxu; + break; + } + + switch (clamp->wmt) { + case 0: // REPEAT + *v = *v % tex0->th; + break; + + case 1: // CLAMP + if (*v < 0) *v = 0; + if (*v >= tex0->th) *v = tex0->th - 1; + break; + + case 2: // REGION_CLAMP + if (*v < clamp->minv) *v = clamp->minv; + if (*v > clamp->maxv) *v = clamp->maxv; + break; + + case 3: // REGION_REPEAT + printf("REGION_REPEAT\n"); + *v = (*v & clamp->minv) | clamp->maxv; + break; + } +} + + + + +u32 _GetTexturePixel32_T32B(int u, int v) { + wrapUV(&u, &v); + return readPixel32(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_T24B(int u, int v) { + wrapUV(&u, &v); + return _readPixel24(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_T16B(int u, int v) { + wrapUV(&u, &v); + return _readPixel16(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_T16SB(int u, int v) { + wrapUV(&u, &v); + return _readPixel16S(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_T8B(int u, int v) { + wrapUV(&u, &v); + return clud[readPixel8(u, v, tex0->tbp0, tex0->tbw)]; +} + +u32 _GetTexturePixel32_T4B(int u, int v) { + wrapUV(&u, &v); + return clud[readPixel4(u, v, tex0->tbp0, tex0->tbw)]; +} + +u32 _GetTexturePixel32_T8HB(int u, int v) { + wrapUV(&u, &v); + return clud[readPixel8H(u, v, tex0->tbp0, tex0->tbw)]; +} + +u32 _GetTexturePixel32_T4HLB(int u, int v) { + wrapUV(&u, &v); + return clud[readPixel8H(u, v, tex0->tbp0, tex0->tbw) & 0xf]; +} + +u32 _GetTexturePixel32_T4HHB(int u, int v) { + wrapUV(&u, &v); + return clud[readPixel8H(u, v, tex0->tbp0, tex0->tbw) >> 4]; +} + +u32 _GetTexturePixel32_Z32B(int u, int v) { + wrapUV(&u, &v); + return readPixel32Z(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_Z24B(int u, int v) { + wrapUV(&u, &v); + return readPixel24Z(u, v, tex0->tbp0, tex0->tbw); +} + +/*u32 _GetTexturePixel32_Z16B(int u, int v) { + wrapUV(&u, &v); + return readPixel24Z(u, v, tex0->tbp0, tex0->tbw); +} + +u32 _GetTexturePixel32_Z16SB(int u, int v) { + wrapUV(&u, &v); + return readPixel24Z(u, v, tex0->tbp0, tex0->tbw); +}*/ + +void _SetGetTexturePixelB() { + switch (tex0->psm) { + case 0x00: // PSMCT32 + GetTexturePixel32 = _GetTexturePixel32_T32B; break; + case 0x01: // PSMCT24 + GetTexturePixel32 = _GetTexturePixel32_T24B; break; + case 0x02: // PSMCT16 + GetTexturePixel32 = _GetTexturePixel32_T16B; break; + case 0x0A: // PSMCT16S + GetTexturePixel32 = _GetTexturePixel32_T16SB;break; + case 0x13: // PSMT8 + GetTexturePixel32 = _GetTexturePixel32_T8B; break; + case 0x14: // PSMT4 + GetTexturePixel32 = _GetTexturePixel32_T4B; break; + case 0x1B: // PSMT8H + GetTexturePixel32 = _GetTexturePixel32_T8HB; break; + case 0x24: // PSMT4HL + GetTexturePixel32 = _GetTexturePixel32_T4HLB; break; + case 0x2C: // PSMT4HH + GetTexturePixel32 = _GetTexturePixel32_T4HHB; break; + case 0x30: // PSMZ32 + GetTexturePixel32 = _GetTexturePixel32_Z32B; break; +/* case 0x31: // PSMZ24 + GetTexturePixel32 = _GetTexturePixel32_Z24B; break; + case 0x32: // PSMZ16 + GetTexturePixel32 = _GetTexturePixel32_Z16B; break; + case 0x3A: // PSMZ16S + GetTexturePixel32 = _GetTexturePixel32_Z16SB; break;*/ + default: + printf("unhandled psm : %x\n", tex0->psm); + GetTexturePixel32 = _GetTexturePixel32_T32B; break; + } +} + +void SetTexture() { + int clutf=0; + + switch (tex0->psm) { + case 0x13: // PSMT8 + case 0x1B: // PSMT8H + clutf = 8; break; + case 0x14: // PSMT4 + case 0x24: // PSMT4HL + case 0x2C: // PSMT4HH + clutf = 4; break; + } + + if (clutf == 8) { + if (tex0->cpsm == 0) { + copy_clut32_8(clud); + } + if (tex0->cpsm == 0x2) { + if (tex0->csm == 0) { + copy_clut16_8_1(clud); + } else { + copy_clut16_8_2(clud); + } + } + if (tex0->cpsm == 0xa) { + if (tex0->csm == 0) { + copy_clut16S_8_1(clud); + } else { + copy_clut16S_8_2(clud); + } + } + } + + if (clutf == 4) { + if (tex0->cpsm == 0) { + copy_clut32_4(clud); + } + if (tex0->cpsm == 0x2) { + if (tex0->csm == 0) { + copy_clut16_4_1(clud); + } else { + copy_clut16_4_2(clud); + } + } + if (tex0->cpsm == 0xa) { + if (tex0->csm == 0) { + copy_clut16S_4_1(clud); + } else { + copy_clut16S_4_2(clud); + } + } + } + +/* if (tex0->tbp0 & 0x1f)*/ { + _SetGetTexturePixelB(); + } /*else + switch (tex0->psm) { + case 0x00: // PSMCT32 + GetTexturePixel32 = _GetTexturePixel32_T32; break; + case 0x01: // PSMCT24 + GetTexturePixel32 = _GetTexturePixel32_T24; break; + case 0x02: // PSMCT16 + case 0x0A: // PSMCT16S + GetTexturePixel32 = _GetTexturePixel32_T16; break; + case 0x13: // PSMT8 + GetTexturePixel32 = _GetTexturePixel32_T8; break; + case 0x14: // PSMT4 + GetTexturePixel32 = _GetTexturePixel32_T4; break; + case 0x1B: // PSMT8H + GetTexturePixel32 = _GetTexturePixel32_T8H; break; + case 0x24: // PSMT4HL + GetTexturePixel32 = _GetTexturePixel32_T4HL;break; + case 0x2C: // PSMT4HH + GetTexturePixel32 = _GetTexturePixel32_T4HH;break; + default: + printf("unhandled psm : %x\n", tex0->psm); + GetTexturePixel32 = _GetTexturePixel32_T32; break; + }*/ + + if (conf.cache) { + if (CacheSetTexture() == 0) { + GetTexturePixel32 = CacheGetTexturePixel32; + } + } +// if (tex0->tbp0 == 0x75680) + if (conf.dumptexts) DumpTexture(); +} + +u32 TextureSizeGS(int width, int height, int psm) { + switch (psm) { + case 0x00: // PSMCT32 + case 0x01: // PSMCT24 + case 0x1B: // PSMT8H + case 0x24: // PSMT4HL + case 0x2C: // PSMT4HH + return (width*height*4); + case 0x02: // PSMCT16 + case 0x0A: // PSMCT16S + return (width*height*2); + case 0x13: // PSMT8 + return (width*height ); + case 0x14: // PSMT4 + return (width*height/2); + default: + printf("unsupported PSM %d\n", psm); + return 0; + } +} + +void DumpTexture() { + FILE *bmpfile; + char filename[256]; + unsigned char header[0x36]; + long size; + unsigned char line[1024*3]; + int w,h; + short i,j; + unsigned char empty[2]={0,0}; + u32 color; + u32 snapshotnr = 0; + + w = tex0->tw; + h = tex0->th-20; + size = w*h*3 + 0x38; + printf("DumpTexture %d, %d\n", w, h); + + // fill in proper values for BMP + + // hardcoded BMP header + memset(header,0,0x36); + header[0]='B'; + header[1]='M'; + header[2]=size&0xff; + header[3]=(size>>8)&0xff; + header[4]=(size>>16)&0xff; + header[5]=(size>>24)&0xff; + header[0x0a]=0x36; + header[0x0e]=0x28; + header[0x12]=w%256; + header[0x13]=w/256; + header[0x16]=h%256; + header[0x17]=h/256; + header[0x1a]=0x01; + header[0x1c]=0x18; + header[0x26]=0x12; + header[0x27]=0x0B; + header[0x2A]=0x12; + header[0x2B]=0x0B; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"tex%03ld_%x.bmp", snapshotnr, tex0->tbp0); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) + return; + + fwrite(header,0x36,1,bmpfile); + for(i=h-1;i>=0;i--) { + for(j=0;j> 8)&0xff; + line[j*3+0]=(color>>16)&0xff; + } + fwrite(line,w*3,1,bmpfile); + } + fwrite(empty,0x2,1,bmpfile); + fclose(bmpfile); +} + diff --git a/plugins/gs/GSsoft/Src/Texts.h b/plugins/gs/GSsoft/Src/Texts.h new file mode 100644 index 0000000000..3610821e53 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Texts.h @@ -0,0 +1,28 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __TEXTS_H__ +#define __TEXTS_H__ + +void SetTexture(); +void DumpTexture(); +u32 TextureSizeGS(int width, int height, int psm); +u32 (*GetTexturePixel32)(int, int); +void wrapUV(int *u, int *v); + +#endif /* __TEXTS_H__ */ diff --git a/plugins/gs/GSsoft/Src/Transfer.c b/plugins/gs/GSsoft/Src/Transfer.c new file mode 100644 index 0000000000..167c9d8d1c --- /dev/null +++ b/plugins/gs/GSsoft/Src/Transfer.c @@ -0,0 +1,1328 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Rec.h" +#include "Page.h" +#include "Cache.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) + +#endif + +//#define _OPTIMIZE + + +/////////////////////////////// +// TransferPixel from/to vRam +// + +__inline void TransferPixel(u32 pixel) { + writePixel32(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixelB(u32 pixel) { + writePixel32(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel32Z(u32 pixel) { + writePixel32Z(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel24(u8 *pixel) { + u32 pix = pixel[0] | (pixel[1] << 8) | (pixel[2] << 16); + writePixel24(gs.imageX, gs.imageY, pix, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel24B(u8 *pixel) { + u32 pix = pixel[0] | (pixel[1] << 8) | (pixel[2] << 16); + writePixel24(gs.imageX, gs.imageY, pix, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel24Z(u8 *pixel) { + u32 pix = pixel[0] | (pixel[1] << 8) | (pixel[2] << 16); + writePixel24Z(gs.imageX, gs.imageY, pix, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16(u16 pixel) { + writePixel16(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16B(u16 pixel) { + writePixel16(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16Z(u16 pixel) { + writePixel16Z(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16S(u16 pixel) { + writePixel16S(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16SB(u16 pixel) { + writePixel16S(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel16SZ(u16 pixel) { + writePixel16SZ(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel8(u8 pixel) { + writePixel8(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel8B(u8 pixel) { + writePixel8(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel8H(u8 pixel) { + writePixel8H(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel8HB(u8 pixel) { + writePixel8H(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4(u8 pixel) { + writePixel4(gs.imageX, gs.imageY, pixel & 0xf, gs.dstbuf.bp, gs.dstbuf.bw); + writePixel4(gs.imageX+1, gs.imageY, pixel >> 4, gs.dstbuf.bp, gs.dstbuf.bw); + + gs.imageX+= 2; + if (gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4B(u8 pixel) { + writePixel4(gs.imageX, gs.imageY, pixel & 0xf, gs.dstbuf.bp, gs.dstbuf.bw); + writePixel4(gs.imageX+1, gs.imageY, pixel >> 4, gs.dstbuf.bp, gs.dstbuf.bw); + + gs.imageX+= 2; + if (gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4HL(u8 pixel) { + writePixel4HL(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4HLB(u8 pixel) { + writePixel4HL(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4HH(u8 pixel) { + writePixel4HH(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixel4HHB(u8 pixel) { + writePixel4HH(gs.imageX, gs.imageY, pixel, gs.dstbuf.bp, gs.dstbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +__inline void TransferPixelSrc(u32 *pixel) { + *pixel = readPixel32(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrcB(u32 *pixel) { + *pixel = readPixel32(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc32Z(u32 *pixel) { + *pixel = readPixel32Z(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc24(u8 *pixel) { + u32 pix = readPixel24(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + pixel[0] = ((u8*)pix)[0]; pixel[1] = ((u8*)pix)[1]; pixel[2] = ((u8*)pix)[2]; + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc24B(u8 *pixel) { + u32 pix = readPixel24(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + pixel[0] = ((u8*)pix)[0]; pixel[1] = ((u8*)pix)[1]; pixel[2] = ((u8*)pix)[2]; + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc24Z(u8 *pixel) { + u32 pix = readPixel24Z(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + pixel[0] = ((u8*)pix)[0]; pixel[1] = ((u8*)pix)[1]; pixel[2] = ((u8*)pix)[2]; + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16(u16 *pixel) { + *pixel = readPixel16(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16B(u16 *pixel) { + *pixel = readPixel16(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16Z(u16 *pixel) { + *pixel = readPixel16Z(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16S(u16 *pixel) { + *pixel = readPixel16S(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16SB(u16 *pixel) { + *pixel = readPixel16S(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc16SZ(u16 *pixel) { + *pixel = readPixel16SZ(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc8(u8 *pixel) { + *pixel = readPixel8(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc8B(u8 *pixel) { + *pixel = readPixel8(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc8H(u8 *pixel) { + *pixel = readPixel8H(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc8HB(u8 *pixel) { + *pixel = readPixel8H(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4(u8 *pixel) { + *pixel = readPixel4(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + gs.imageX+= 2; + if (gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4B(u8 *pixel) { + *pixel = readPixel4(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + gs.imageX+= 2; + if (gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4HL(u8 *pixel) { + *pixel = readPixel4HL(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4HLB(u8 *pixel) { + *pixel = readPixel4HL(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4HH(u8 *pixel) { + *pixel = readPixel4HH(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +__inline void TransferPixelSrc4HHB(u8 *pixel) { + *pixel = readPixel4HH(gs.imageX, gs.imageY, gs.srcbuf.bp, gs.srcbuf.bw); + + if (++gs.imageX == (gs.imageW + gs.trxpos.sx)) { + gs.imageX = gs.trxpos.sx; gs.imageY++; + } +} + +/////////////////////////////// +// FrameBuffer writes/reads +// + +void FBwrite(u32 *data) { + TransferPixel(data[0]); + TransferPixel(data[1]); + TransferPixel(data[2]); + TransferPixel(data[3]); +} + +void FBwriteB(u32 *data) { + TransferPixelB(data[0]); + TransferPixelB(data[1]); + TransferPixelB(data[2]); + TransferPixelB(data[3]); +} + +void FBwrite32Z(u32 *data) { + TransferPixel32Z(data[0]); + TransferPixel32Z(data[1]); + TransferPixel32Z(data[2]); + TransferPixel32Z(data[3]); +} + +void FBwrite_8x8(u32 *data) { + u32 *fb = (u32*)&vRamUL[getPixelAddress32(gs.imageX, gs.imageY, gs.dstbuf.bp, gs.dstbuf.bw)]; + u32 *data2 = data+gs.imageW; + +#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) + __asm__( + "movq 0(%1), %%xmm0\n" + "movq 8(%1), %%xmm1\n" + "movq 16(%1), %%xmm2\n" + "movq 24(%1), %%xmm3\n" + + "movhps 0(%2), %%xmm0\n" + "movhps 8(%2), %%xmm1\n" + "movhps 16(%2), %%xmm2\n" + "movhps 24(%2), %%xmm3\n" + + "movaps %%xmm0, 0(%0)\n" + "movaps %%xmm1, 16(%0)\n" + "movaps %%xmm2, 32(%0)\n" + "movaps %%xmm3, 48(%0)\n" + + :: "r"(fb), "r"(data), "r"(data2) + ); +#else + fb[0] = data[0]; fb[1] = data[1]; + fb[4] = data[2]; fb[5] = data[3]; + fb[8] = data[4]; fb[9] = data[5]; + fb[12] = data[6]; fb[13] = data[7]; + + fb[2] = data2[0]; fb[3] = data2[1]; + fb[6] = data2[2]; fb[7] = data2[3]; + fb[10] = data2[4]; fb[11] = data2[5]; + fb[14] = data2[6]; fb[15] = data2[7]; +#endif + + gs.imageX+= 8; + if (gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY+= 2; + } +} + +void FBwrite_8(u32 *data) { + u32 *fb = (u32*)&vRamUL[getPixelAddress32(gs.imageX, gs.imageY, gs.dstbuf.bp, gs.dstbuf.bw)]; + + fb[0] = data[0]; fb[1] = data[1]; + fb[4] = data[2]; fb[5] = data[3]; + fb[8] = data[4]; fb[9] = data[5]; + fb[12] = data[6]; fb[13] = data[7]; + + gs.imageX+= 8; + if (gs.imageX == (gs.imageW + gs.trxpos.dx)) { + gs.imageX = gs.trxpos.dx; gs.imageY++; + } +} + +void FBwrite24_3(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixel24((u8*)(data8+i*3)); + } +} + +void FBwrite24_3B(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixel24B((u8*)(data8+i*3)); + } +} + +void FBwrite24Z_3(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixel24Z((u8*)(data8+i*3)); + } +} + +void FBwrite16(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16(data16[0]); + TransferPixel16(data16[1]); + TransferPixel16(data16[2]); + TransferPixel16(data16[3]); +} + +void FBwrite16B(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16B(data16[0]); + TransferPixel16B(data16[1]); + TransferPixel16B(data16[2]); + TransferPixel16B(data16[3]); +} + +void FBwrite16Z(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16Z(data16[0]); + TransferPixel16Z(data16[1]); + TransferPixel16Z(data16[2]); + TransferPixel16Z(data16[3]); +} + +void FBwrite16S(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16S(data16[0]); + TransferPixel16S(data16[1]); + TransferPixel16S(data16[2]); + TransferPixel16S(data16[3]); +} + +void FBwrite16SB(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16SB(data16[0]); + TransferPixel16SB(data16[1]); + TransferPixel16SB(data16[2]); + TransferPixel16SB(data16[3]); +} + +void FBwrite16SZ(u32 *data) { + const u16 *data16 = (u16*)data; + TransferPixel16SZ(data16[0]); + TransferPixel16SZ(data16[1]); + TransferPixel16SZ(data16[2]); + TransferPixel16SZ(data16[3]); +} + +void FBwrite8(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel8(data8[0]); + TransferPixel8(data8[1]); + TransferPixel8(data8[2]); + TransferPixel8(data8[3]); +} + +void FBwrite8B(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel8B(data8[0]); + TransferPixel8B(data8[1]); + TransferPixel8B(data8[2]); + TransferPixel8B(data8[3]); +} + +void FBwrite8H(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel8H(data8[0]); + TransferPixel8H(data8[1]); + TransferPixel8H(data8[2]); + TransferPixel8H(data8[3]); +} + +void FBwrite8HB(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel8HB(data8[0]); + TransferPixel8HB(data8[1]); + TransferPixel8HB(data8[2]); + TransferPixel8HB(data8[3]); +} + +void FBwrite4(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4(data8[0]); + TransferPixel4(data8[1]); + TransferPixel4(data8[2]); + TransferPixel4(data8[3]); +} + +void FBwrite4B(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4B(data8[0]); + TransferPixel4B(data8[1]); + TransferPixel4B(data8[2]); + TransferPixel4B(data8[3]); +} + +void FBwrite4HL(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4HL(data8[0] & 0xf); + TransferPixel4HL(data8[0] >> 4); + TransferPixel4HL(data8[1] & 0xf); + TransferPixel4HL(data8[1] >> 4); + TransferPixel4HL(data8[2] & 0xf); + TransferPixel4HL(data8[2] >> 4); + TransferPixel4HL(data8[3] & 0xf); + TransferPixel4HL(data8[3] >> 4); +} + +void FBwrite4HLB(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4HLB(data8[0] & 0xf); + TransferPixel4HLB(data8[0] >> 4); + TransferPixel4HLB(data8[1] & 0xf); + TransferPixel4HLB(data8[1] >> 4); + TransferPixel4HLB(data8[2] & 0xf); + TransferPixel4HLB(data8[2] >> 4); + TransferPixel4HLB(data8[3] & 0xf); + TransferPixel4HLB(data8[3] >> 4); +} + +void FBwrite4HH(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4HH(data8[0] << 4); + TransferPixel4HH(data8[0] & 0xf0); + TransferPixel4HH(data8[1] << 4); + TransferPixel4HH(data8[1] & 0xf0); + TransferPixel4HH(data8[2] << 4); + TransferPixel4HH(data8[2] & 0xf0); + TransferPixel4HH(data8[3] << 4); + TransferPixel4HH(data8[3] & 0xf0); +} + +void FBwrite4HHB(u32 *data) { + const u8 *data8 = (u8*)data; + TransferPixel4HHB(data8[0] << 4); + TransferPixel4HHB(data8[0] & 0xf0); + TransferPixel4HHB(data8[1] << 4); + TransferPixel4HHB(data8[1] & 0xf0); + TransferPixel4HHB(data8[2] << 4); + TransferPixel4HHB(data8[2] & 0xf0); + TransferPixel4HHB(data8[3] << 4); + TransferPixel4HHB(data8[3] & 0xf0); +} + +void FBread(u32 *data) { + TransferPixelSrc(&data[0]); + TransferPixelSrc(&data[1]); + TransferPixelSrc(&data[2]); + TransferPixelSrc(&data[3]); +} + +void FBreadB(u32 *data) { + TransferPixelSrcB(&data[0]); + TransferPixelSrcB(&data[1]); + TransferPixelSrcB(&data[2]); + TransferPixelSrcB(&data[3]); +} + +void FBread32Z(u32 *data) { + TransferPixelSrc32Z(&data[0]); + TransferPixelSrc32Z(&data[1]); + TransferPixelSrc32Z(&data[2]); + TransferPixelSrc32Z(&data[3]); +} + +void FBread24_3(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixelSrc24((u8*)(data8+i*3)); + } +} + +void FBread24_3B(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixelSrc24B((u8*)(data8+i*3)); + } +} + +void FBread24Z_3(u32 *data) { + u8 *data8 = (u8*)data; + int i; + + for (i=0; i<16; i++) { + TransferPixelSrc24Z((u8*)(data8+i*3)); + } +} + +void FBread16(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16(&data16[0]); + TransferPixelSrc16(&data16[1]); + TransferPixelSrc16(&data16[2]); + TransferPixelSrc16(&data16[3]); +} + +void FBread16B(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16B(&data16[0]); + TransferPixelSrc16B(&data16[1]); + TransferPixelSrc16B(&data16[2]); + TransferPixelSrc16B(&data16[3]); +} + +void FBread16Z(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16Z(&data16[0]); + TransferPixelSrc16Z(&data16[1]); + TransferPixelSrc16Z(&data16[2]); + TransferPixelSrc16Z(&data16[3]); +} + +void FBread16S(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16S(&data16[0]); + TransferPixelSrc16S(&data16[1]); + TransferPixelSrc16S(&data16[2]); + TransferPixelSrc16S(&data16[3]); +} + +void FBread16SB(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16SB(&data16[0]); + TransferPixelSrc16SB(&data16[1]); + TransferPixelSrc16SB(&data16[2]); + TransferPixelSrc16SB(&data16[3]); +} + +void FBread16SZ(u32 *data) { + u16 *data16 = (u16*)data; + TransferPixelSrc16SZ(&data16[0]); + TransferPixelSrc16SZ(&data16[1]); + TransferPixelSrc16SZ(&data16[2]); + TransferPixelSrc16SZ(&data16[3]); +} + +void FBread8(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc8(&data8[0]); + TransferPixelSrc8(&data8[1]); + TransferPixelSrc8(&data8[2]); + TransferPixelSrc8(&data8[3]); +} + +void FBread8B(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc8B(&data8[0]); + TransferPixelSrc8B(&data8[1]); + TransferPixelSrc8B(&data8[2]); + TransferPixelSrc8B(&data8[3]); +} + +void FBread8H(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc8H(&data8[0]); + TransferPixelSrc8H(&data8[1]); + TransferPixelSrc8H(&data8[2]); + TransferPixelSrc8H(&data8[3]); +} + +void FBread8HB(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc8HB(&data8[0]); + TransferPixelSrc8HB(&data8[1]); + TransferPixelSrc8HB(&data8[2]); + TransferPixelSrc8HB(&data8[3]); +} + +void FBread4(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4(&data8[0]); + TransferPixelSrc4(&data8[1]); + TransferPixelSrc4(&data8[2]); + TransferPixelSrc4(&data8[3]); +} + +void FBread4B(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4B(&data8[0]); + TransferPixelSrc4B(&data8[1]); + TransferPixelSrc4B(&data8[2]); + TransferPixelSrc4B(&data8[3]); +} + +void FBread4HL(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4HL(&data8[0]); + TransferPixelSrc4HL(&data8[1]); + TransferPixelSrc4HL(&data8[2]); + TransferPixelSrc4HL(&data8[3]); +} + +void FBread4HLB(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4HLB(&data8[0]); + TransferPixelSrc4HLB(&data8[1]); + TransferPixelSrc4HLB(&data8[2]); + TransferPixelSrc4HLB(&data8[3]); +} + +void FBread4HH(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4HH(&data8[0]); + TransferPixelSrc4HH(&data8[1]); + TransferPixelSrc4HH(&data8[2]); + TransferPixelSrc4HH(&data8[3]); +} + +void FBread4HHB(u32 *data) { + u8 *data8 = (u8*)data; + TransferPixelSrc4HHB(&data8[0]); + TransferPixelSrc4HHB(&data8[1]); + TransferPixelSrc4HHB(&data8[2]); + TransferPixelSrc4HHB(&data8[3]); +} + +void FBtransferImageB(u32 *pMem, int size) { +// printf("GS IMAGE transferB %d, gs.dstbuf.psm=%x; %dx%d %dx%d (bp=%x)\n", size, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageW, gs.imageH, gs.dstbuf.bp); + + switch (gs.dstbuf.psm) { + case 0x01: // PSMCT24 + while (size >= 3) { + FBwrite24_3B(pMem); pMem+= 12; size-=3; + } + break; + + case 0x02: // PSMCT16 + while (size > 0) { + FBwrite16B(pMem); pMem+= 2; + FBwrite16B(pMem); pMem+= 2; size--; + } + break; + + case 0x0A: // PSMCT16S + while (size > 0) { + FBwrite16SB(pMem); pMem+= 2; + FBwrite16SB(pMem); pMem+= 2; size--; + } + break; + + case 0x13: // PSMT8 + while (size > 0) { + FBwrite8B(pMem); pMem++; + FBwrite8B(pMem); pMem++; + FBwrite8B(pMem); pMem++; + FBwrite8B(pMem); pMem++; size--; + } + break; + + case 0x14: // PSMT4 + while (size > 0) { + FBwrite4B(pMem); pMem++; + FBwrite4B(pMem); pMem++; + FBwrite4B(pMem); pMem++; + FBwrite4B(pMem); pMem++; size--; + } + break; + + case 0x1B: // PSMT8H + while (size > 0) { + FBwrite8HB(pMem); pMem++; + FBwrite8HB(pMem); pMem++; + FBwrite8HB(pMem); pMem++; + FBwrite8HB(pMem); pMem++; size--; + } + break; + + case 0x24: // PSMT4HL + while (size > 0) { + FBwrite4HLB(pMem); pMem++; + FBwrite4HLB(pMem); pMem++; + FBwrite4HLB(pMem); pMem++; + FBwrite4HLB(pMem); pMem++; size--; + } + break; + + case 0x2C: // PSMT4HH + while (size > 0) { + FBwrite4HHB(pMem); pMem++; + FBwrite4HHB(pMem); pMem++; + FBwrite4HHB(pMem); pMem++; + FBwrite4HHB(pMem); pMem++; size--; + } + break; + + case 0x30: // PSMZ32 + while (size > 0) { + FBwrite32Z(pMem); pMem+= 4; size--; + } + break; + + case 0x31: // PSMZ24 + while (size >= 3) { + FBwrite24Z_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x32: // PSMZ16 + while (size > 0) { + FBwrite16Z(pMem); pMem+= 2; + FBwrite16Z(pMem); pMem+= 2; size--; + } + break; + + case 0x3A: // PSMZ16S + while (size > 0) { + FBwrite16SZ(pMem); pMem+= 2; + FBwrite16SZ(pMem); pMem+= 2; size--; + } + break; + + default: + case 0x00: // PSMCT32 + if (gs.dstbuf.psm != 0) printf("gs.dstbuf.psm == %x!!\n", gs.dstbuf.psm); + while (size > 0) { + FBwriteB(pMem); pMem+= 4; size--; + } + break; + } +} + +void _TransferImage8(u32 *pMem, int size) { +/* if ((gs.imageX & 0x1f) == 0 && (gs.imageY & 0xf) == 0 && + ((gs.imageW + gs.trxpos.dx) & 0x1f) == 0) { + while (size > 2) { + FBwrite8B_8(pMem); pMem+= 4; size--; + } +#ifdef __i386__ + _sfence(); + _emms(); +#endif + }*/ + while (size > 0) { + FBwrite8(pMem); pMem++; + FBwrite8(pMem); pMem++; + FBwrite8(pMem); pMem++; + FBwrite8(pMem); pMem++; size--; + } +} + +void _TransferImage32(u32 *pMem, int size) { + int s2size; + size*= 4; + + if ((gs.imageX & 0x7) != 0 || (gs.imageY & 0x7) != 0) { + while (size > 0) { + TransferPixel(*pMem++); size--; + } + return; + } + + if ((gs.imageW & 0x7) == 0) { + s2size = gs.imageW*2; + while (size >= s2size) { + int i; + + for (i=0; i 0) { + if (gs.imageX < (gs.imageW-8)) { + while (size >= 2) { + FBwrite_8(pMem); pMem+= 8; size-= 8; + } +#ifdef __i386__ +// _sfence(); +// _emms(); +#endif + } + while (size > 0) { + TransferPixel(*pMem++); size--; + } + } +} + +void FBtransferImage(u32 *pMem, int size) { +#ifdef GS_LOG + GS_LOG("GS IMAGE transfer %d, gs.dstbuf.psm=%x; %dx%d\n", size, gs.dstbuf.psm, gs.imageW, gs.imageH); +#endif + bpf+= size*16; + + if (conf.cache) { + CacheClear(gs.dstbuf.bp, size*4); + } + +#ifndef _OPTIMIZE + FBtransferImageB(pMem, size); + return; +#endif + if (gs.dstbuf.bp & 0x1f) { + FBtransferImageB(pMem, size); + return; + } + + switch (gs.dstbuf.psm) { + case 0x01: // PSMCT24 + while (size >= 3) { + FBwrite24_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x02: // PSMCT16 + while (size > 0) { + FBwrite16(pMem); pMem+= 2; + FBwrite16(pMem); pMem+= 2; size--; + } + break; + + case 0x0A: // PSMCT16S + while (size > 0) { + FBwrite16S(pMem); pMem+= 2; + FBwrite16S(pMem); pMem+= 2; size--; + } + break; + + case 0x13: // PSMT8 + _TransferImage8(pMem, size); + break; + + case 0x14: // PSMT4 + while (size > 0) { + FBwrite4(pMem); pMem++; + FBwrite4(pMem); pMem++; + FBwrite4(pMem); pMem++; + FBwrite4(pMem); pMem++; size--; + } + break; + + case 0x1B: // PSMT8H + while (size > 0) { + FBwrite8H(pMem); pMem++; + FBwrite8H(pMem); pMem++; + FBwrite8H(pMem); pMem++; + FBwrite8H(pMem); pMem++; size--; + } + break; + + case 0x24: // PSMT4HL + while (size > 0) { + FBwrite4HL(pMem); pMem++; + FBwrite4HL(pMem); pMem++; + FBwrite4HL(pMem); pMem++; + FBwrite4HL(pMem); pMem++; size--; + } + break; + + case 0x2C: // PSMT4HH + while (size > 0) { + FBwrite4HH(pMem); pMem++; + FBwrite4HH(pMem); pMem++; + FBwrite4HH(pMem); pMem++; + FBwrite4HH(pMem); pMem++; size--; + } + break; + + case 0x30: // PSMZ32 + while (size > 0) { + FBwrite32Z(pMem); pMem+= 4; size--; + } + break; + + case 0x31: // PSMZ24 + while (size >= 3) { + FBwrite24Z_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x32: // PSMZ16 + while (size > 0) { + FBwrite16Z(pMem); pMem+= 2; + FBwrite16Z(pMem); pMem+= 2; size--; + } + break; + + case 0x3A: // PSMZ16S + while (size > 0) { + FBwrite16SZ(pMem); pMem+= 2; + FBwrite16SZ(pMem); pMem+= 2; size--; + } + break; + + default: + case 0x00: // PSMCT32 + if (gs.dstbuf.psm != 0) printf("gs.dstbuf.psm == %x!!\n", gs.dstbuf.psm); + _TransferImage32(pMem, size); + break; + } +} + +void FBtransferImageSrcB(u32 *pMem, int size) { +#ifdef GS_LOG + GS_LOG("GS IMAGE SRC transfer %d, gs.srcbuf.psm=%x\n", size, gs.srcbuf.psm); +#endif + + switch (gs.srcbuf.psm) { + case 0x01: // PSMCT24 + while (size >= 3) { + FBread24_3B(pMem); pMem+= 12; size-=3; + } + break; + + case 0x02: // PSMCT16 + while (size > 0) { + FBread16B(pMem); pMem+= 2; + FBread16B(pMem); pMem+= 2; size--; + } + break; + + case 0x0A: // PSMCT16S + while (size > 0) { + FBread16SB(pMem); pMem+= 2; + FBread16SB(pMem); pMem+= 2; size--; + } + break; + + case 0x13: // PSMT8 + while (size > 0) { + FBread8B(pMem); pMem++; + FBread8B(pMem); pMem++; + FBread8B(pMem); pMem++; + FBread8B(pMem); pMem++; size--; + } + break; + + case 0x14: // PSMT4 + while (size > 0) { + FBread4B(pMem); pMem++; + FBread4B(pMem); pMem++; + FBread4B(pMem); pMem++; + FBread4B(pMem); pMem++; size--; + } + break; + + case 0x1B: // PSMT8H + while (size > 0) { + FBread8HB(pMem); pMem++; + FBread8HB(pMem); pMem++; + FBread8HB(pMem); pMem++; + FBread8HB(pMem); pMem++; size--; + } + break; + + case 0x24: // PSMT4HL + while (size > 0) { + FBread4HLB(pMem); pMem++; + FBread4HLB(pMem); pMem++; + FBread4HLB(pMem); pMem++; + FBread4HLB(pMem); pMem++; size--; + } + break; + + case 0x2C: // PSMT4HH + while (size > 0) { + FBread4HHB(pMem); pMem++; + FBread4HHB(pMem); pMem++; + FBread4HHB(pMem); pMem++; + FBread4HHB(pMem); pMem++; size--; + } + break; + + case 0x30: // PSMZ32 + while (size > 0) { + FBread32Z(pMem); pMem+= 4; size--; + } + break; + + case 0x31: // PSMZ24 + while (size >= 3) { + FBread24Z_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x32: // PSMZ16 + while (size > 0) { + FBread16Z(pMem); pMem+= 2; + FBread16Z(pMem); pMem+= 2; size--; + } + break; + + case 0x3A: // PSMZ16S + while (size > 0) { + FBread16SZ(pMem); pMem+= 2; + FBread16SZ(pMem); pMem+= 2; size--; + } + break; + + default: + case 0x00: // PSMCT32 + if (gs.srcbuf.psm != 0) printf("gs.srcbuf.psm == %d!!\n", gs.srcbuf.psm); + while (size > 0) { + FBreadB(pMem); pMem+= 4; size--; + } + break; + } +} + +void FBtransferImageSrc(u32 *pMem, int size) { +#ifdef GS_LOG + GS_LOG("GS IMAGE SRC transfer %d, gs.srcbuf.psm=%x\n", size, gs.srcbuf.psm); +#endif + + if (gs.srcbuf.bp & 0x1f) { + FBtransferImageSrcB(pMem, size); + return; + } + + switch (gs.srcbuf.psm) { + case 0x01: // PSMCT24 + while (size >= 3) { + FBread24_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x02: // PSMCT16 + while (size > 0) { + FBread16(pMem); pMem+= 2; + FBread16(pMem); pMem+= 2; size--; + } + break; + + case 0x0A: // PSMCT16S + while (size > 0) { + FBread16S(pMem); pMem+= 2; + FBread16S(pMem); pMem+= 2; size--; + } + break; + + case 0x13: // PSMT8 + while (size> 0) { + FBread8(pMem); pMem++; + FBread8(pMem); pMem++; + FBread8(pMem); pMem++; + FBread8(pMem); pMem++; size--; + } + break; + + case 0x14: // PSMT4 + while (size > 0) { + FBread4(pMem); pMem++; + FBread4(pMem); pMem++; + FBread4(pMem); pMem++; + FBread4(pMem); pMem++; size--; + } + break; + + case 0x1B: // PSMT8H + while (size > 0) { + FBread8H(pMem); pMem++; + FBread8H(pMem); pMem++; + FBread8H(pMem); pMem++; + FBread8H(pMem); pMem++; size--; + } + break; + + case 0x24: // PSMT4HL + while (size > 0) { + FBread4HL(pMem); pMem++; + FBread4HL(pMem); pMem++; + FBread4HL(pMem); pMem++; + FBread4HL(pMem); pMem++; size--; + } + break; + + case 0x2C: // PSMT4HH + while (size > 0) { + FBread4HH(pMem); pMem++; + FBread4HH(pMem); pMem++; + FBread4HH(pMem); pMem++; + FBread4HH(pMem); pMem++; size--; + } + break; + + case 0x30: // PSMZ32 + while (size > 0) { + FBread32Z(pMem); pMem+= 4; size--; + } + break; + + case 0x31: // PSMZ24 + while (size >= 3) { + FBread24Z_3(pMem); pMem+= 12; size-=3; + } + break; + + case 0x32: // PSMZ16 + while (size > 0) { + FBread16Z(pMem); pMem+= 2; + FBread16Z(pMem); pMem+= 2; size--; + } + break; + + case 0x3A: // PSMZ16S + while (size > 0) { + FBread16SZ(pMem); pMem+= 2; + FBread16SZ(pMem); pMem+= 2; size--; + } + break; + + default: + case 0x00: // PSMCT32 + if (gs.srcbuf.psm != 0) printf("gs.srcbuf.psm == %d!!\n", gs.srcbuf.psm); + while (size > 0) { + FBread(pMem); pMem+= 4; size--; + } + break; + } +} + diff --git a/plugins/gs/GSsoft/Src/Transfer.h b/plugins/gs/GSsoft/Src/Transfer.h new file mode 100644 index 0000000000..122858e334 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Transfer.h @@ -0,0 +1,27 @@ +/* GSsoft + * Copyright (C) 2002-2005 GSsoft 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 + */ + +#ifndef __TRANSFER_H__ +#define __TRANSFER_H__ + +void FBtransferImageB(u32 *pMem, int size); +void FBtransferImage(u32 *pMem, int size); +void FBtransferImageSrcB(u32 *pMem, int size); +void FBtransferImageSrc(u32 *pMem, int size); + +#endif /* __TRANSFER_H__ */ diff --git a/plugins/gs/GSsoft/Src/Win32/Conf.c b/plugins/gs/GSsoft/Src/Win32/Conf.c new file mode 100644 index 0000000000..51a05303bd --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/Conf.c @@ -0,0 +1,110 @@ +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + GSconf *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\gssoft.ini"); + + sprintf(szValue,"%u",Conf1->fmode.height); + WritePrivateProfileString("Settings", "FmodeHeight",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->fmode.width); + WritePrivateProfileString("Settings", "FmodeWidth",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->wmode.height); + WritePrivateProfileString("Settings", "WmodeHeight",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->wmode.width); + WritePrivateProfileString("Settings", "WmodeWidth",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->fullscreen); + WritePrivateProfileString("Settings", "Fullscreen",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->fps); + WritePrivateProfileString("Settings", "Fps",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->frameskip); + WritePrivateProfileString("Settings", "FrameSkip",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->record); + WritePrivateProfileString("Settings", "Record",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->cache); + WritePrivateProfileString("Settings", "Cache",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->cachesize); + WritePrivateProfileString("Settings", "Cachesize",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->codec); + WritePrivateProfileString("Settings", "Codec",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->filter); + WritePrivateProfileString("Settings", "Filter",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->log); + WritePrivateProfileString("Settings", "Log",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + GSconf *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\gssoft.ini"); + fp=fopen("inis\\gssoft.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.fmode.width = 640; + conf.fmode.height = 480; + conf.wmode.width = 640; + conf.wmode.height = 480; + conf.fullscreen = 0; + conf.cachesize = 128; + SaveConfig();//save and return + return ; + } + fclose(fp); + + + + GetPrivateProfileString("Settings", "FmodeHeight", NULL, szValue, 20, szIniFile); + Conf1->fmode.height = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "FmodeWidth", NULL, szValue, 20, szIniFile); + Conf1->fmode.width= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "WmodeHeight", NULL, szValue, 20, szIniFile); + Conf1->wmode.height= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "WmodeWidth", NULL, szValue, 20, szIniFile); + Conf1->wmode.width= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Fullscreen", NULL, szValue, 20, szIniFile); + Conf1->fullscreen= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Fps", NULL, szValue, 20, szIniFile); + Conf1->fps= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "FrameSkip", NULL, szValue, 20, szIniFile); + Conf1->frameskip= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Record", NULL, szValue, 20, szIniFile); + Conf1->record = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Cache", NULL, szValue, 20, szIniFile); + Conf1->cache= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Cachesize", NULL, szValue, 20, szIniFile); + Conf1->cachesize= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Codec", NULL, szValue, 20, szIniFile); + Conf1->codec= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Filter", NULL, szValue, 20, szIniFile); + Conf1->filter= strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Log", NULL, szValue, 20, szIniFile); + Conf1->log = strtoul(szValue, NULL, 10); + + + if (conf.fullscreen) cmode = &conf.fmode; + else cmode = &conf.wmode; +} + diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.def b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.def new file mode 100644 index 0000000000..5b1024c26a --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.def @@ -0,0 +1,33 @@ +; GpuDx7.def : Declares the module parameters for the DLL. + +LIBRARY "GSsoftdx" +DESCRIPTION 'GSsoftdx dll' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + GSinit @5 + GSshutdown @6 + GSopen @7 + GSclose @8 + GSwrite32 @9 + GSwrite64 @10 + GSread32 @11 + GSread64 @12 + GSgifTransfer1 @13 + GSgifTransfer2 @14 + GSgifTransfer3 @15 + GSreadFIFO @16 + GSvsync @17 + GSmakeSnapshot @18 + GSkeyEvent @19 + GSfreeze @20 + GSconfigure @21 + GStest @22 + GSabout @23 + GSwrite8 @24 + GSread8 @25 + GSread16 @26 + GSwrite16 @27 diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsp b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsp new file mode 100644 index 0000000000..84be4598df --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsp @@ -0,0 +1,202 @@ +# Microsoft Developer Studio Project File - Name="GSsoftdx" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GSsoftdx - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GSsoftdx.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GSsoftdx.mak" CFG="GSsoftdx - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GSsoftdx - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GSSOFTDX_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../" /I "./" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GSSOFTDX_EXPORTS" /D "__WIN32__" /D "__MSCW32__" /D "__i386__" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib sdl_gfx.lib /nologo /dll /pdb:none /machine:I386 +# Begin Target + +# Name "GSsoftdx - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\Cache.c +# End Source File +# Begin Source File + +SOURCE=..\Color.c +# End Source File +# Begin Source File + +SOURCE=.\Conf.c +# End Source File +# Begin Source File + +SOURCE=..\Draw.c +# End Source File +# Begin Source File + +SOURCE=..\GS.c +# End Source File +# Begin Source File + +SOURCE=.\GSsoftdx.def +# End Source File +# Begin Source File + +SOURCE=..\Mem.c +# End Source File +# Begin Source File + +SOURCE=..\Page.c +# End Source File +# Begin Source File + +SOURCE=..\Prim.c +# End Source File +# Begin Source File + +SOURCE=..\Rec.c +# End Source File +# Begin Source File + +SOURCE=..\Regs.c +# End Source File +# Begin Source File + +SOURCE=..\scale2x.c +# End Source File +# Begin Source File + +SOURCE=..\SDL.c +# End Source File +# Begin Source File + +SOURCE=..\SDL_gfxPrimitives.c +# End Source File +# Begin Source File + +SOURCE=..\Soft.c +# End Source File +# Begin Source File + +SOURCE=..\Texts.c +# End Source File +# Begin Source File + +SOURCE=..\Transfer.c +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\Draw.h +# End Source File +# Begin Source File + +SOURCE=..\GS.h +# End Source File +# Begin Source File + +SOURCE=..\Mem.h +# End Source File +# Begin Source File + +SOURCE=.\plugin.h +# End Source File +# Begin Source File + +SOURCE=..\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=..\PS2Etypes.h +# End Source File +# Begin Source File + +SOURCE=..\Rec.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=..\Soft.h +# End Source File +# Begin Source File + +SOURCE=..\Texts.h +# End Source File +# Begin Source File + +SOURCE=.\Win32.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\GSsoftdx.rc +# End Source File +# Begin Source File + +SOURCE=.\Pcsx2.ico +# End Source File +# End Group +# Begin Group "Docs" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ReadMe.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsw b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsw new file mode 100644 index 0000000000..2eed447f37 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GSsoftdx"=".\GSsoftdx.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.ncb b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.ncb new file mode 100644 index 0000000000000000000000000000000000000000..6a64f15d3f8182c5b6e7f1f4627474c367021b63 GIT binary patch literal 273408 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

?_d1^a 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�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\n\t[TyRaNiD]", + IDC_STATIC,27,20,141,17 + LTEXT "Thanks to:\n shadow - coding support and help.\n Pete Bernert - for the triangles code.\n Absolute0 - help fixing bugs :)\n asadr - lots of help from him :)\n Gabest - fixes, hints, etc, etc ^^\n\nBeta Testers:\n bositman, CKemu, belmont, parotak", + IDC_STATIC,10,45,160,50 +END + +IDD_LOGGING DIALOG DISCARDABLE 0, 0, 152, 55 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,40,35,50,14 + PUSHBUTTON "Cancel",IDCANCEL,95,35,50,14 + CONTROL "Log",IDC_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,60, + 15,28,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO MOVEABLE PURE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 330 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 145 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Castilian) (unknown sub-lang: 0xB) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.sln b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.sln new file mode 100644 index 0000000000..e41509614a --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GSsoftdx", "GSsoftdx.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.suo b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.suo new file mode 100644 index 0000000000000000000000000000000000000000..e1cae98af9531c793dd2ab934ff93ce750ea49b8 GIT binary patch literal 8192 zcmeHMOKe+36un6rn)Khav=B-$O@EZyBzF37Q$CIDq>+-gBq8Y{LUQbv)a|n!Y^NW! zMeIN<5D0Y-5<3Kl4J*U~iA5Kv6%s;Xf#?FUY!`e=X=~1z_r`xaFHVYDDc8Dh=FQwU zcjnIh&G`DY^}l}nW%~^&ftRF7?q^%&v4Zvn)QJk#i8P|Z_xssw)@l?%bqO9J3Eab6 zm)U#RjFS7k9M}SE1+D_F0ImeC2Ce~ezllrm=u2Q&lK5rBB_ThD~rKMULj>;P^D?f~utl4iGE?m_uHa4*npx4nR}6W9gx+HL%13Faq( zfsVE}erz5NeQ>4!syQ}r6QZ0K+zK#C)DMg+YlFtwSj2Dzl8H z*$5<*@~77|Fo!ePi=>iprsh0$gFj;leWX+VjFU>+D)49gqvU5Gg&1Z)J*Wjck%g15 zhFY|`kFiI`pM~nL9+UCoEuf{xR#cycEW;AV9`#`@rrOa7#5(F0qrTQ@7h)iz?<}ZI zP>*2kvl3P7cZo-iAuAX~yB8k6Q+&|(F^q5kCC8ynq*2l)MBe+~=RkcmvC1hm13eS{ z{_xDmnrEr6DAj-NR06Ue!T!uDsn+%a(7y)e3XB5OK@@WWX}`7=uR8w=kSTpq6~}9H zsYm~5uhr~-2wEBkSLVT%hmGQmSy*M*i}h3YR{@=_pZVgbJsj;l1D+{Jo!Xzb6rC9x z(5npWioSr9eCB6!2>i9}JLSItyy-6&3wRGu3JYl~9qU29H;W1%QN?4kyxVxJ0j@lo z-PM@8>UgKe-|*34zoKj9J_GK^MYyA&bi*|rlzm9ny+}>_@O}VKH_D*wN4pz6o#IED z>PAl|$`D!u%8hk_<_PMS#2=msn8!KQKiXczR*+i!^;s+k%g6vL zfd~4}I|*$Am1s)awxZ#%-AF&joJ+6Kva>0ydRqBEa<<}d=_uAa>_5lb>H43+r$5{N z?>KziX~aav%4#-VnX}cpwGRHf@M%a7N?i>BsiA&o>waj88$s5m^w$r)_F`gQXbx+a z@mZJG*UbZ7&Q^BUvXw@;`_S9U2<&4J))KL; zoEcQ{$USIr0(7IlZ`|?27abk_U;TFD@~+8vw{k6OuC|+ZTRV=wpMCrGwQoNOsqn>9 zTH$Gup+@9GCyc7lyy_Bp9c!6yc*@JI_y~Yb)ip zsx`^qDCrTJuydx;<+M738L;K~MIqdO;s)3{(>slSyr;8fnZN&K9?aVhX5N&p=+ z)&}0ck}q=#r~ID-?K)*7g8SZt;u?mv8o=VLJD+D)o5i*|;&0*l%dN2*r^@YZb?~PW z9J1H{kF6Umawk{&H&?rxtKG9}DyF7|Nj_4?4k|w4vtxIUec90 i(Ee$68Y)v2xBBp^@1Kf$>U-0?S=Kkg!oGTx`TqxiM-_hn literal 0 HcmV?d00001 diff --git a/plugins/gs/GSsoft/Src/Win32/GSsoftdx.vcproj b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.vcproj new file mode 100644 index 0000000000..a0ef1d6e10 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/GSsoftdx.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/GSsoft/Src/Win32/Makefile b/plugins/gs/GSsoft/Src/Win32/Makefile new file mode 100644 index 0000000000..eaeff62515 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/Makefile @@ -0,0 +1,58 @@ +# +# GSsoft Makefile for MINGW32 +# + + +all: gssoft + +PLUGIN = GSsoft.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ $(shell sdl-config --cflags)# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 $(shell sdl-config --libs) #-lintl +RESOBJ = gssoft.o + +OBJS = ../GS.o ../Cache.o ../Color.o ../Draw.o ../Mem.o \ + ../Page.o ../Prim.o ../Rec.o ../Regs.o ../SDL.o \ + ../Soft.o ../Texts.o ../Transfer.o \ + ../scale2x.o ../SDL_gfxPrimitives.o +OBJS+= Conf.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include -I../ffmpeg ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +FLAGS+= -I../x86 +OBJS+= ../x86/ix86_cpudetect.o + +gssoft: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean gssoft + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: GSsoftdx.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/gs/GSsoft/Src/Win32/SDL.c b/plugins/gs/GSsoft/Src/Win32/SDL.c new file mode 100644 index 0000000000..50affb59be --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/SDL.c @@ -0,0 +1,225 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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 +#include +#include + +#include +#include +//#include + +#include "GS.h" +#include "Draw.h" +#include "Win32.h" +#include "Rec.h" + +SDL_Surface *surf; +SDL_SysWMinfo info; + +void DXclearScr() { + SDL_FillRect(surf, NULL, 0); +} + +s32 DXopen() { +#ifdef __LINUX__ + int screen; + int w, h; +#endif + + if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; + + surf = SDL_SetVideoMode(cmode->width, cmode->height, 0, conf.fullscreen ? SDL_FULLSCREEN : 0); + if (surf == NULL) return -1; + + SDL_VERSION(&info.version); + if (SDL_GetWMInfo(&info) == 0) return -1; + +#ifdef __LINUX__ + info.info.x11.lock_func(); + screen = DefaultScreen(info.info.x11.display); + w = DisplayWidth(info.info.x11.display, screen); + h = DisplayHeight(info.info.x11.display, screen); + XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, + cmode->width < w ? (w - cmode->width) / 2 : 0, + cmode->height < h ? (h - cmode->height) / 2 : 0); + info.info.x11.unlock_func(); +#endif + + SDL_WM_SetCaption(GStitle, NULL); + + SETScrBlit(surf->format->BitsPerPixel); + DXclearScr(); + +#ifdef __WIN32__ + return (s32)info.window; +#else + return (s32)info.info.x11.display; +#endif +} + +void DXclose() { + SDL_Quit(); +} + +#include + +void DXupdate() { + SDL_Rect rect; + static time_t to; + static int fpscount, fpsc, fc; + int lPitch; + char *sbuff; + + fc++; + + if (conf.fps || conf.frameskip) { + if (time(NULL) > to) { + time(&to); + fpsc = fpscount; + fpscount = 0; + } + fpscount++; + } + + if (conf.frameskip) { + if ((fpscount % 3) == 0) { + norender = 1; + } else if (norender) { + norender = 0; + } + } + + if (norender == 0) { + SDL_LockSurface(surf); + sbuff = surf->pixels; + lPitch = surf->pitch; + + ScrBlit(sbuff, lPitch); + if (conf.record) recFrame(sbuff, lPitch, surf->format->BitsPerPixel); + + SDL_UnlockSurface(surf); + } + + if (conf.fps) { + char title[256]; + char tmp[256]; + + if (fpspos < 0) fpspos = 0; +#ifndef GS_LOG + if (fpspos > 6) fpspos = 6; +#else + if (fpspos > 7) fpspos = 7; +#endif + switch (fpspos) { + case 0: // FrameSkip + sprintf(tmp, "Frameskip %s", conf.frameskip == 1 ? "On" : "Off"); + norender = 0; + break; + case 1: // Stretch + sprintf(tmp, "Stretch %s", conf.stretch == 1 ? "On" : "Off"); + break; + /*case 2: // Misc stuff + sprintf(tmp, "GSmode %dx%d", gsmode->w, gsmode->h); + break;*/ + case 3: // ShowFullVRam + sprintf(tmp, "ShowFullVRam %s", showfullvram == 1 ? "On" : "Off"); + break; + case 4: // NoAlphaBlending + sprintf(tmp, "NoAlphaBlending %s", noabe == 1 ? "On" : "Off"); + break; + case 5: // DisableRendering + sprintf(tmp, "DisableRendering %s", norender == 1 ? "On" : "Off"); + break; + case 6: // WireFrame + sprintf(tmp, "WireFrame %s", wireframe == 1 ? "On" : "Off"); + break; +#ifdef GS_LOG + case 7: // Log + sprintf(tmp, "Log %s", conf.log == 1 ? "On" : "Off"); + break; +#endif + } + if (fpspress) { + switch (fpspos) { + case 0: + conf.frameskip = 1 - conf.frameskip; + norender = 0; + break; + case 1: + conf.stretch = 1 - conf.stretch; + SETScrBlit(surf->format->BitsPerPixel); + DXclearScr(); + fpspress = 0; + return; + case 3: + DXclearScr(); + showfullvram = 1 - showfullvram; + break; + case 4: + noabe = 1 - noabe; + break; + case 5: + norender = 1 - norender; + break; + case 6: + wireframe = 1 - wireframe; + break; +#ifdef GS_LOG + case 7: + conf.log = 1 - conf.log; + break; +#endif + } + fpspress = 0; + } + + sprintf(title,"FPS %d -- %s - FC: %d", fpsc, tmp, fc); + + rect.x = 0; rect.y = 0; + rect.w = cmode->width; + rect.h = 15; + SDL_FillRect(surf, &rect, 0); +// stringRGBA(surf, 4, 4, title, 0, 0xff, 0, 0xff); + } + + SDL_UpdateRect(surf, 0, 0, 0, 0); + SDL_PumpEvents(); +} + +int DXgetModes() { + SDL_Rect **rects; + int i; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; + + memset(modes, 0, sizeof(modes)); + rects = SDL_ListModes(NULL, SDL_FULLSCREEN); + if (rects == NULL) return -1; + + for (i=0; i<64; i++) { + if (rects[i] == NULL) break; + modes[i].width = rects[i]->w; + modes[i].height = rects[i]->h; + } + + SDL_Quit(); + + return i; +} + diff --git a/plugins/gs/GSsoft/Src/Win32/Win32.c b/plugins/gs/GSsoft/Src/Win32/Win32.c new file mode 100644 index 0000000000..ff72e7105d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/Win32.c @@ -0,0 +1,274 @@ +#include +#include +#include + +#include "GS.h" +#include "Win32.h" +#include "Rec.h" + +HINSTANCE hInst=NULL; + +void CALLBACK GSkeyEvent(keyEvent *ev) { + switch (ev->event) { + case KEYPRESS: + switch (ev->key) { + case VK_PRIOR: + if (conf.fps) fpspos++; break; + case VK_NEXT: + if (conf.fps) fpspos--; break; + case VK_END: + if (conf.fps) fpspress = 1; break; + case VK_DELETE: + conf.fps = 1 - conf.fps; + break; + } + break; + } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +int CacheSizes[] = { 64, 128, 256, 0 }; + +DXmode wmodes[] = { + { 320, 240, 0 }, + { 512, 384, 0 }, + { 640, 480, 0 }, + { 800, 600, 0 }, + { 0, 0, 0 }, +}; + +void OnInitDialog(HWND hW) { + HWND hWC; + char str[256]; + int i, j; + int nmode; + + LoadConfig(); + if (recExist() == 0) { + EnableWindow (GetDlgItem(hW, IDC_RECORD), TRUE); + EnableWindow (GetDlgItem(hW, IDC_CODEC) , TRUE); + } else { + conf.record=0; + CheckDlgButton(hW,IDC_RECORD,BST_UNCHECKED); + EnableWindow (GetDlgItem(hW, IDC_RECORD), FALSE); + EnableWindow (GetDlgItem(hW, IDC_CODEC), FALSE); + } + for (i=0; ; i++) { + if (codeclist[i] == NULL) break; + ComboBox_AddString(GetDlgItem(hW, IDC_CODEC), codeclist[i]); + } + + ComboBox_SetCurSel(GetDlgItem(hW, IDC_CODEC), conf.codec); + nmode = DXgetModes(); + + hWC = GetDlgItem(hW, IDC_FRES); + for (i=0; i +#include + +#define IDC_STATIC (-1) diff --git a/plugins/gs/GSsoft/Src/Win32/plugin.def b/plugins/gs/GSsoft/Src/Win32/plugin.def new file mode 100644 index 0000000000..49ad02b7dc --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/plugin.def @@ -0,0 +1,31 @@ +EXPORTS + GSabout = GSabout@0 @90 + GSclose = GSclose@0 @91 + GSconfigure = GSconfigure@0 @92 + GSfreeze = GSfreeze@8 @93 + GSgetDriverInfo = GSgetDriverInfo@4 @94 + GSgifTransfer1 = GSgifTransfer1@8 @95 + GSgifTransfer2 = GSgifTransfer2@8 @96 + GSgifTransfer3 = GSgifTransfer3@8 @97 + GSinit = GSinit@0 @99 + GSirqCallback = GSirqCallback@4 @101 + GSkeyEvent = GSkeyEvent@4 @102 + GSmakeSnapshot = GSmakeSnapshot@4 @103 + GSopen = GSopen@8 @104 + GSprintf = GSprintf@0 @105 + GSread16 = GSread16@4 @106 + GSread32 = GSread32@4 @107 + GSread64 = GSread64@4 @108 + GSread8 = GSread8@4 @109 + GSreadFIFO = GSreadFIFO@4 @110 + GSreset @111 + GSshutdown = GSshutdown@0 @112 + GStest = GStest@0 @113 + GSvsync = GSvsync@0 @115 + GSwrite16 = GSwrite16@8 @117 + GSwrite32 = GSwrite32@8 @118 + GSwrite64 = GSwrite64@12 @119 + GSwrite8 = GSwrite8@8 @120 + PS2EgetLibName = PS2EgetLibName@0 @128 + PS2EgetLibType = PS2EgetLibType@0 @129 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @130 diff --git a/plugins/gs/GSsoft/Src/Win32/plugin.h b/plugins/gs/GSsoft/Src/Win32/plugin.h new file mode 100644 index 0000000000..ab4f6606e7 --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/plugin.h @@ -0,0 +1,18 @@ + + +typedef struct { + HINSTANCE havcodec; + void (__cdecl* avcodec_init)(void); + void (__cdecl* avcodec_register_all)(void); + AVCodec *(__cdecl* avcodec_find_encoder)(enum CodecID id); + AVCodecContext *(__cdecl* avcodec_alloc_context)(void); + AVFrame *(__cdecl* avcodec_alloc_frame)(void); + int (__cdecl* avcodec_open)(AVCodecContext *avctx, AVCodec *codec); + int (__cdecl* img_convert)(AVPicture *dst, int dst_pix_fmt, AVPicture *src, int pix_fmt, int width, int height); + int (__cdecl* avcodec_encode_video)(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict); + int (__cdecl* avcodec_close)(AVCodecContext *avctx); +} RECPLUGIN; + +extern RECPLUGIN recplugin; + + diff --git a/plugins/gs/GSsoft/Src/Win32/resource.h b/plugins/gs/GSsoft/Src/Win32/resource.h new file mode 100644 index 0000000000..e11e2fed9d --- /dev/null +++ b/plugins/gs/GSsoft/Src/Win32/resource.h @@ -0,0 +1,42 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by GSsoftdx.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_LOGGING 106 +#define IDC_CHECK1 1000 +#define IDC_FULLSCREEN 1000 +#define IDC_NAME 1000 +#define IDC_LOG 1000 +#define IDC_CHECK2 1001 +#define IDC_FPSCOUNT 1001 +#define IDC_CHECK5 1002 +#define IDC_FRAMESKIP 1002 +#define IDC_STRETCH 1003 +#define IDC_LOGGING 1004 +#define IDC_COMBO1 1005 +#define IDC_CACHE 1005 +#define IDC_CACHESIZE 1006 +#define IDC_CHECK3 1007 +#define IDC_RECORD 1007 +#define IDC_COMBO2 1008 +#define IDC_DSPRES 1008 +#define IDC_WRES 1008 +#define IDC_COMBO3 1009 +#define IDC_DDDRV 1009 +#define IDC_FRES 1009 +#define IDC_COMBO4 1012 +#define IDC_CODEC 1012 +#define IDC_FILTERS 1014 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/gs/GSsoft/Src/avcodec.h b/plugins/gs/GSsoft/Src/avcodec.h new file mode 100644 index 0000000000..e04bff5577 --- /dev/null +++ b/plugins/gs/GSsoft/Src/avcodec.h @@ -0,0 +1,1688 @@ +#ifndef AVCODEC_H +#define AVCODEC_H + +/** + * @file avcodec.h + * external api header. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +#define FFMPEG_VERSION_INT 0x000408 +#define FFMPEG_VERSION "0.4.8" +#define LIBAVCODEC_BUILD 4680 + +#define LIBAVCODEC_VERSION_INT FFMPEG_VERSION_INT +#define LIBAVCODEC_VERSION FFMPEG_VERSION + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s +#define LIBAVCODEC_IDENT "FFmpeg" LIBAVCODEC_VERSION "b" AV_STRINGIFY(LIBAVCODEC_BUILD) + +enum CodecID { + CODEC_ID_NONE, + CODEC_ID_MPEG1VIDEO, + CODEC_ID_MPEG2VIDEO, /* prefered ID for MPEG Video 1 or 2 decoding */ + CODEC_ID_MPEG2VIDEO_XVMC, + CODEC_ID_H263, + CODEC_ID_RV10, + CODEC_ID_MP2, + CODEC_ID_MP3, /* prefered ID for MPEG Audio layer 1, 2 or3 decoding */ + CODEC_ID_VORBIS, + CODEC_ID_AC3, + CODEC_ID_MJPEG, + CODEC_ID_MJPEGB, + CODEC_ID_LJPEG, + CODEC_ID_MPEG4, + CODEC_ID_RAWVIDEO, + CODEC_ID_MSMPEG4V1, + CODEC_ID_MSMPEG4V2, + CODEC_ID_MSMPEG4V3, + CODEC_ID_WMV1, + CODEC_ID_WMV2, + CODEC_ID_H263P, + CODEC_ID_H263I, + CODEC_ID_FLV1, + CODEC_ID_SVQ1, + CODEC_ID_SVQ3, + CODEC_ID_DVVIDEO, + CODEC_ID_DVAUDIO, + CODEC_ID_WMAV1, + CODEC_ID_WMAV2, + CODEC_ID_MACE3, + CODEC_ID_MACE6, + CODEC_ID_HUFFYUV, + CODEC_ID_CYUV, + CODEC_ID_H264, + CODEC_ID_INDEO3, + CODEC_ID_VP3, + CODEC_ID_AAC, + CODEC_ID_MPEG4AAC, + CODEC_ID_ASV1, + CODEC_ID_ASV2, + CODEC_ID_FFV1, + CODEC_ID_4XM, + CODEC_ID_VCR1, + CODEC_ID_CLJR, + CODEC_ID_MDEC, + CODEC_ID_ROQ, + CODEC_ID_INTERPLAY_VIDEO, + CODEC_ID_XAN_WC3, + CODEC_ID_XAN_WC4, + + /* various pcm "codecs" */ + CODEC_ID_PCM_S16LE, + CODEC_ID_PCM_S16BE, + CODEC_ID_PCM_U16LE, + CODEC_ID_PCM_U16BE, + CODEC_ID_PCM_S8, + CODEC_ID_PCM_U8, + CODEC_ID_PCM_MULAW, + CODEC_ID_PCM_ALAW, + + /* various adpcm codecs */ + CODEC_ID_ADPCM_IMA_QT, + CODEC_ID_ADPCM_IMA_WAV, + CODEC_ID_ADPCM_IMA_DK3, + CODEC_ID_ADPCM_IMA_DK4, + CODEC_ID_ADPCM_MS, + CODEC_ID_ADPCM_4XM, + + /* AMR */ + CODEC_ID_AMR_NB, + /* RealAudio codecs*/ + CODEC_ID_RA_144, + CODEC_ID_RA_288, + + /* various DPCM codecs */ + CODEC_ID_ROQ_DPCM, + CODEC_ID_INTERPLAY_DPCM, + CODEC_ID_XAN_DPCM, +}; + +/* CODEC_ID_MP3LAME is absolete */ +#define CODEC_ID_MP3LAME CODEC_ID_MP3 + +enum CodecType { + CODEC_TYPE_UNKNOWN = -1, + CODEC_TYPE_VIDEO, + CODEC_TYPE_AUDIO, +}; + +/** + * Pixel format. Notes: + * + * PIX_FMT_RGBA32 is handled in an endian-specific manner. A RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little endian CPU architectures and ARGB on + * big endian CPUs. + * + * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in PIX_FMT_RGBA32 described above (i.e., it is + * also endian-specific). + */ +enum PixelFormat { + PIX_FMT_YUV420P, ///< Planar YUV 4:2:0 (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUV422, + PIX_FMT_RGB24, ///< Packed pixel, 3 bytes per pixel, RGBRGB... + PIX_FMT_BGR24, ///< Packed pixel, 3 bytes per pixel, BGRBGR... + PIX_FMT_YUV422P, ///< Planar YUV 4:2:2 (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< Planar YUV 4:4:4 (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_RGBA32, ///< Packed pixel, 4 bytes per pixel, BGRABGRA..., stored in cpu endianness + PIX_FMT_YUV410P, ///< Planar YUV 4:1:0 (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< Planar YUV 4:1:1 (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_RGB565, ///< always stored in cpu endianness + PIX_FMT_RGB555, ///< always stored in cpu endianness, most significant bit to 1 + PIX_FMT_GRAY8, + PIX_FMT_MONOWHITE, ///< 0 is white + PIX_FMT_MONOBLACK, ///< 0 is black + PIX_FMT_PAL8, ///< 8 bit with RGBA palette + PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0 full scale (jpeg) + PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2 full scale (jpeg) + PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4 full scale (jpeg) + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h) + PIX_FMT_XVMC_MPEG2_IDCT, + PIX_FMT_NB, +}; + +/* currently unused, may be used if 24/32 bits samples ever supported */ +enum SampleFormat { + SAMPLE_FMT_S16 = 0, ///< signed 16 bits +}; + +/* in bytes */ +#define AVCODEC_MAX_AUDIO_FRAME_SIZE 131072 + +/** + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * this is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end
+ * Note, if the first 23 bits of the additional bytes are not 0 then damaged + * MPEG bitstreams could cause overread and segfault + */ +#define FF_INPUT_BUFFER_PADDING_SIZE 8 + +/* motion estimation type, EPZS by default */ +enum Motion_Est_ID { + ME_ZERO = 1, + ME_FULL, + ME_LOG, + ME_PHODS, + ME_EPZS, + ME_X1 +}; + +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // if this is 0 then quality_factor will be used instead + float quality_factor; +} RcOverride; + +/* only for ME compatiblity with old apps */ +extern int motion_estimation_method; + +/* ME algos sorted by quality */ +static const int Motion_Est_QTab[] = { ME_ZERO, ME_PHODS, ME_LOG, + ME_X1, ME_EPZS, ME_FULL }; + + +#define FF_MAX_B_FRAMES 8 + +/* encoding support + these flags can be passed in AVCodecContext.flags before initing + Note: note not everything is supported yet +*/ + +#define CODEC_FLAG_QSCALE 0x0002 ///< use fixed qscale +#define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed +#define CODEC_FLAG_QPEL 0x0010 ///< use qpel MC +#define CODEC_FLAG_GMC 0x0020 ///< use GMC +#define CODEC_FLAG_PART 0x0080 ///< use data partitioning +/* parent program gurantees that the input for b-frame containing streams is not written to + for at least s->max_b_frames+1 frames, if this is not set than the input will be copied */ +#define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#define CODEC_FLAG_PASS1 0x0200 ///< use internal 2pass ratecontrol in first pass mode +#define CODEC_FLAG_PASS2 0x0400 ///< use internal 2pass ratecontrol in second pass mode +#define CODEC_FLAG_EXTERN_HUFF 0x1000 ///< use external huffman table (for mjpeg) +#define CODEC_FLAG_GRAY 0x2000 ///< only decode/encode grayscale +#define CODEC_FLAG_EMU_EDGE 0x4000///< dont draw edges +#define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding +#define CODEC_FLAG_TRUNCATED 0x00010000 /** input bitstream might be truncated at a random location instead + of only at frame boundaries */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 ///< normalize adaptive quantization +#define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< use interlaced dct +#define CODEC_FLAG_LOW_DELAY 0x00080000 ///< force low delay +#define CODEC_FLAG_ALT_SCAN 0x00100000 ///< use alternate scan +#define CODEC_FLAG_TRELLIS_QUANT 0x00200000 ///< use trellis quantization +#define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< place global headers in extradata instead of every keyframe +#define CODEC_FLAG_BITEXACT 0x00800000 ///< use only bitexact stuff (except (i)dct) +/* Fx : Flag for h263+ extra options */ +#define CODEC_FLAG_H263P_AIC 0x01000000 ///< Advanced intra coding +#define CODEC_FLAG_H263P_UMV 0x02000000 ///< Unlimited motion vector +/* For advanced prediction mode, we reuse the 4MV flag */ +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Deblocking filter internal loop + * Slice structured + * Reference Picture Selection + * Independant Segment Decoding + * Alternative Inter * VLC + * Modified Quantization */ +/* /Fx */ +/* codec capabilities */ + +#define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 ///< decoder can use draw_horiz_band callback +/** + * Codec uses get_buffer() for allocating buffers. + * direct rendering method 1 + */ +#define CODEC_CAP_DR1 0x0002 +/* if 'parse_only' field is true, then avcodec_parse_frame() can be + used */ +#define CODEC_CAP_PARSE_ONLY 0x0004 +#define CODEC_CAP_TRUNCATED 0x0008 + +#define FF_COMMON_FRAME \ + /**\ + * pointer to the picture planes.\ + * this might be different from the first allocated byte\ + * - encoding: \ + * - decoding: \ + */\ + uint8_t *data[4];\ + int linesize[4];\ + /**\ + * pointer to the first allocated byte of the picture. can be used in get_buffer/release_buffer\ + * this isnt used by lavc unless the default get/release_buffer() is used\ + * - encoding: \ + * - decoding: \ + */\ + uint8_t *base[4];\ + /**\ + * 1 -> keyframe, 0-> not\ + * - encoding: set by lavc\ + * - decoding: set by lavc\ + */\ + int key_frame;\ +\ + /**\ + * picture type of the frame, see ?_TYPE below.\ + * - encoding: set by lavc for coded_picture (and set by user for input)\ + * - decoding: set by lavc\ + */\ + int pict_type;\ +\ + /**\ + * presentation timestamp in micro seconds (time when frame should be shown to user)\ + * if 0 then the frame_rate will be used as reference\ + * - encoding: MUST be set by user\ + * - decoding: set by lavc\ + */\ + int64_t pts;\ +\ + /**\ + * picture number in bitstream order.\ + * - encoding: set by\ + * - decoding: set by lavc\ + */\ + int coded_picture_number;\ + /**\ + * picture number in display order.\ + * - encoding: set by\ + * - decoding: set by lavc\ + */\ + int display_picture_number;\ +\ + /**\ + * quality (between 1 (good) and 31 (bad)) \ + * - encoding: set by lavc for coded_picture (and set by user for input)\ + * - decoding: set by lavc\ + */\ + float quality; \ +\ + /**\ + * buffer age (1->was last buffer and dint change, 2->..., ...).\ + * set to something large if the buffer has not been used yet \ + * - encoding: unused\ + * - decoding: MUST be set by get_buffer()\ + */\ + int age;\ +\ + /**\ + * is this picture used as reference\ + * - encoding: unused\ + * - decoding: set by lavc (before get_buffer() call))\ + */\ + int reference;\ +\ + /**\ + * QP table\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int8_t *qscale_table;\ + /**\ + * QP store stride\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int qstride;\ +\ + /**\ + * mbskip_table[mb]>=1 if MB didnt change\ + * stride= mb_width = (width+15)>>4\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + uint8_t *mbskip_table;\ +\ + /**\ + * for some private data of the user\ + * - encoding: unused\ + * - decoding: set by user\ + */\ + void *opaque;\ +\ + /**\ + * error\ + * - encoding: set by lavc if flags&CODEC_FLAG_PSNR\ + * - decoding: unused\ + */\ + uint64_t error[4];\ +\ + /**\ + * type of the buffer (to keep track of who has to dealloc data[*])\ + * - encoding: set by the one who allocs it\ + * - decoding: set by the one who allocs it\ + * Note: user allocated (direct rendering) & internal buffers can not coexist currently\ + */\ + int type;\ + \ + /**\ + * when decoding, this signal how much the picture must be delayed.\ + * extra_delay = repeat_pict / (2*fps)\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int repeat_pict;\ + \ + /**\ + * \ + */\ + int qscale_type;\ + +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 + +#define FF_BUFFER_TYPE_INTERNAL 1 +#define FF_BUFFER_TYPE_USER 2 ///< Direct rendering buffers (image is (de)allocated by user) +#define FF_BUFFER_TYPE_SHARED 4 ///< buffer from somewher else, dont dealloc image (data/base) +#define FF_BUFFER_TYPE_COPY 8 ///< just a (modified) copy of some other buffer, dont dealloc anything + + +#define FF_I_TYPE 1 // Intra +#define FF_P_TYPE 2 // Predicted +#define FF_B_TYPE 3 // Bi-dir predicted +#define FF_S_TYPE 4 // S(GMC)-VOP MPEG4 +#define FF_SI_TYPE 5 +#define FF_SP_TYPE 6 + +/** + * Audio Video Frame. + */ +typedef struct AVFrame { + FF_COMMON_FRAME +} AVFrame; + +#define DEFAULT_FRAME_RATE_BASE 1001000 + +/** + * main external api structure. + */ +typedef struct AVCodecContext { + /** + * the average bitrate. + * - encoding: set by user. unused for constant quantizer encoding + * - decoding: set by lavc. 0 or some bitrate if this info is available in the stream + */ + int bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: set by user. unused for constant quantizer encoding + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * CODEC_FLAG_*. + * - encoding: set by user. + * - decoding: set by user. + */ + int flags; + + /** + * some codecs needs additionnal format info. It is stored here + * - encoding: set by user. + * - decoding: set by lavc. (FIXME is this ok?) + */ + int sub_id; + + /** + * motion estimation algorithm used for video coding. + * - encoding: MUST be set by user. + * - decoding: unused + */ + int me_method; + + /** + * some codecs need / can use extra-data like huffman tables. + * mjpeg: huffman tables + * rv10: additional flags + * mpeg4: global headers (they can be in the bitstream or here) + * - encoding: set/allocated/freed by lavc. + * - decoding: set/allocated/freed by user. + */ + void *extradata; + int extradata_size; + + /* video only */ + /** + * frames per sec multiplied by frame_rate_base. + * for variable fps this is the precission, so if the timestamps + * can be specified in msec precssion then this is 1000*frame_rate_base + * - encoding: MUST be set by user + * - decoding: set by lavc. 0 or the frame_rate if available + */ + int frame_rate; + + /** + * width / height. + * - encoding: MUST be set by user. + * - decoding: set by user, some codecs might override / change it during playback + */ + int width, height; + +#define FF_ASPECT_SQUARE 1 +#define FF_ASPECT_4_3_625 2 +#define FF_ASPECT_4_3_525 3 +#define FF_ASPECT_16_9_625 4 +#define FF_ASPECT_16_9_525 5 +#define FF_ASPECT_EXTENDED 15 + + /** + * the number of pictures in a group of pitures, or 0 for intra_only. + * - encoding: set by user. + * - decoding: unused + */ + int gop_size; + + /** + * pixel format, see PIX_FMT_xxx. + * - encoding: FIXME: used by ffmpeg to decide whether an pix_fmt + * conversion is in order. This only works for + * codecs with one supported pix_fmt, we should + * do something for a generic case as well. + * - decoding: set by lavc. + */ + enum PixelFormat pix_fmt; + + /** + * Frame rate emulation. If not zero lower layer (i.e. format handler) + * has to read frames at native frame rate. + * - encoding: set by user. + * - decoding: unused. + */ + int rate_emu; + + /** + * if non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw an horizontal band. It improve cache usage. Not + * all codecs can do that. You must check the codec capabilities + * before + * - encoding: unused + * - decoding: set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + AVFrame *src, int offset[4], + int y, int type, int height); + + /* audio only */ + int sample_rate; ///< samples per sec + int channels; + int sample_fmt; ///< sample format, currenly unused + + /* the following data should not be initialized */ + int frame_size; ///< in samples, initialized when calling 'init' + int frame_number; ///< audio or video frame number + int real_pict_num; ///< returns the real picture number of previous encoded frame + + /** + * number of frames the decoded output will be delayed relative to + * the encoded input. + * - encoding: set by lavc. + * - decoding: unused + */ + int delay; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference etween frames. + * - encoding: set by user. + * - decoding: unused + */ + int max_qdiff; + + /** + * maximum number of b frames between non b frames. + * note: the output will be delayed by max_b_frames+1 relative to the input + * - encoding: set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between ip and b frames. + * - encoding: set by user. + * - decoding: unused + */ + float b_quant_factor; + + /** obsolete FIXME remove */ + int rc_strategy; + int b_frame_strategy; + + /** + * hurry up amount. + * - encoding: unused + * - decoding: set by user. 1-> skip b frames, 2-> skip idct/dequant too, 5-> skip everything except header + */ + int hurry_up; + + struct AVCodec *codec; + + void *priv_data; + + /* The following data is for RTP friendly coding */ + /* By now only H.263/H.263+/MPEG4 coder honours this */ + int rtp_mode; /* 1 for activate RTP friendly-mode */ + /* highers numbers represent more error-prone */ + /* enviroments, by now just "1" exist */ + + int rtp_payload_size; /* The size of the RTP payload, the coder will */ + /* do it's best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263 */ + /* This doesn't take account of any particular */ + /* headers inside the transmited RTP payload */ + + + /* The RTP callcack: This function is called */ + /* every time the encoder as a packet to send */ + /* Depends on the encoder if the data starts */ + /* with a Start Code (it should) H.263 does */ + void (*rtp_callback)(void *data, int size, int packet_number); + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int header_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int p_count; + int skip_count; + int misc_bits; + + /** + * number of bits used for the previously encoded frame. + * - encoding: set by lavc + * - decoding: unused + */ + int frame_bits; + + /** + * private data of the user, can be used to carry app specific stuff. + * - encoding: set by user + * - decoding: set by user + */ + void *opaque; + + char codec_name[32]; + enum CodecType codec_type; /* see CODEC_TYPE_xxx */ + enum CodecID codec_id; /* see CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * this is used to workaround some encoder bugs + * - encoding: set by user, if not then the default based on codec_id will be used + * - decoding: set by user, will be converted to upper case by lavc during init + */ + unsigned int codec_tag; + + /** + * workaround bugs in encoders which sometimes cannot be detected automatically. + * - encoding: unused + * - decoding: set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#define FF_BUG_OLD_MSMPEG4 2 +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AC_VLC 32 +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +//#define FF_BUG_FAKE_SCALABILITY 16 //autodetection should work 100% + + /** + * luma single coeff elimination threshold. + * - encoding: set by user + * - decoding: unused + */ + int luma_elim_threshold; + + /** + * chroma single coeff elimination threshold. + * - encoding: set by user + * - decoding: unused + */ + int chroma_elim_threshold; + + /** + * strictly follow the std (MPEG4, ...). + * - encoding: set by user + * - decoding: unused + */ + int strict_std_compliance; + + /** + * qscale offset between ip and b frames. + * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) + * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) + * - encoding: set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * error resilience higher values will detect more errors but may missdetect + * some more or less valid parts as errors. + * - encoding: unused + * - decoding: set by user + */ + int error_resilience; +#define FF_ER_CAREFULL 1 +#define FF_ER_COMPLIANT 2 +#define FF_ER_AGGRESSIVE 3 +#define FF_ER_VERY_AGGRESSIVE 4 + + /** + * called at the beginning of each frame to get a buffer for it. + * if pic.reference is set then the frame will be read later by lavc + * width and height should be rounded up to the next multiple of 16 + * - encoding: unused + * - decoding: set by lavc, user can override + */ + int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * called to release buffers which where allocated with get_buffer. + * a released buffer can be reused in get_buffer() + * pic.data[*] must be set to NULL + * - encoding: unused + * - decoding: set by lavc, user can override + */ + void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * is 1 if the decoded stream contains b frames, 0 otherwise. + * - encoding: unused + * - decoding: set by lavc + */ + int has_b_frames; + + int block_align; ///< used by some WAV based audio codecs + + int parse_only; /* - decoding only: if true, only parsing is done + (function avcodec_parse_frame()). The frame + data is returned. Only MPEG codecs support this now. */ + + /** + * 0-> h263 quant 1-> mpeg quant. + * - encoding: set by user. + * - decoding: unused + */ + int mpeg_quant; + + /** + * pass1 encoding statistics output buffer. + * - encoding: set by lavc + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer. + * concatenated stuff from stats_out of pass1 should be placed here + * - encoding: allocated/set/freed by user + * - decoding: unused + */ + char *stats_in; + + /** + * ratecontrol qmin qmax limiting method. + * 0-> clipping, 1-> use a nice continous function to limit qscale wthin qmin/qmax + * - encoding: set by user. + * - decoding: unused + */ + float rc_qsquish; + + float rc_qmod_amp; + int rc_qmod_freq; + + /** + * ratecontrol override, see RcOverride. + * - encoding: allocated/set/freed by user. + * - decoding: unused + */ + RcOverride *rc_override; + int rc_override_count; + + /** + * rate control equation. + * - encoding: set by user + * - decoding: unused + */ + char *rc_eq; + + /** + * maximum bitrate. + * - encoding: set by user. + * - decoding: unused + */ + int rc_max_rate; + + /** + * minimum bitrate. + * - encoding: set by user. + * - decoding: unused + */ + int rc_min_rate; + + /** + * decoder bitstream buffer size. + * - encoding: set by user. + * - decoding: unused + */ + int rc_buffer_size; + float rc_buffer_aggressivity; + + /** + * qscale factor between p and i frames. + * - encoding: set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between p and i frames. + * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) + * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) + * - encoding: set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * initial complexity for pass1 ratecontrol. + * - encoding: set by user. + * - decoding: unused + */ + float rc_initial_cplx; + + /** + * dct algorithm, see FF_DCT_* below. + * - encoding: set by user + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_MLIB 4 +#define FF_DCT_ALTIVEC 5 + + /** + * luminance masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float dark_masking; + + + /* for binary compatibility */ + int unused; + + /** + * idct algorithm, see FF_IDCT_* below. + * - encoding: set by user + * - decoding: set by user + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_LIBMPEG2MMX 4 +#define FF_IDCT_PS2 5 +#define FF_IDCT_MLIB 6 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#define FF_IDCT_SH4 9 +#define FF_IDCT_SIMPLEARM 10 + + /** + * slice count. + * - encoding: set by lavc + * - decoding: set by user (or 0) + */ + int slice_count; + /** + * slice offsets in the frame in bytes. + * - encoding: set/allocated by lavc + * - decoding: set/allocated by user (or NULL) + */ + int *slice_offset; + + /** + * error concealment flags. + * - encoding: unused + * - decoding: set by user + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 + + /** + * dsp_mask could be add used to disable unwanted CPU features + * CPU features (i.e. MMX, SSE. ...) + * + * with FORCE flag you may instead enable given CPU features + * (Dangerous: usable in case of misdetection, improper usage however will + * result into program crash) + */ + unsigned dsp_mask; +#define FF_MM_FORCE 0x80000000 /* force usage of selected flags (OR) */ + /* lower 16 bits - CPU features */ +#ifdef HAVE_MMX +#define FF_MM_MMX 0x0001 /* standard MMX */ +#define FF_MM_3DNOW 0x0004 /* AMD 3DNOW */ +#define FF_MM_MMXEXT 0x0002 /* SSE integer functions or AMD MMX ext */ +#define FF_MM_SSE 0x0008 /* SSE functions */ +#define FF_MM_SSE2 0x0010 /* PIV SSE2 functions */ +#endif /* HAVE_MMX */ + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: set by lavc + * - decoding: set by user + */ + int bits_per_sample; + + /** + * prediction method (needed for huffyuv). + * - encoding: set by user + * - decoding: unused + */ + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 + + /** + * aspect ratio (0 if unknown). + * - encoding: set by user. + * - decoding: set by lavc. + */ + float aspect_ratio; + + /** + * the picture in the bitstream. + * - encoding: set by lavc + * - decoding: set by lavc + */ + AVFrame *coded_frame; + + /** + * debug. + * - encoding: set by user. + * - decoding: set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#define FF_DEBUG_MV 32 +#define FF_DEBUG_VIS_MV 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#define FF_DEBUG_PTS 0x00000200 +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 + + /** + * error. + * - encoding: set by lavc if flags&CODEC_FLAG_PSNR + * - decoding: unused + */ + uint64_t error[4]; + + /** + * minimum MB quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int mb_qmin; + + /** + * maximum MB quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int mb_qmax; + + /** + * motion estimation compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock compare function (not supported yet). + * - encoding: set by user. + * - decoding: unused + */ + int mb_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape. + * - encoding: set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square). + * - encoding: set by user. + * - decoding: unused + */ + int last_predictor_count; + + /** + * pre pass for motion estimation. + * - encoding: set by user. + * - decoding: unused + */ + int pre_me; + + /** + * motion estimation pre pass compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME pre pass diamond size & shape. + * - encoding: set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality. + * - encoding: set by user. + * - decoding: unused + */ + int me_subpel_quality; + + /** + * callback to negotiate the pixelFormat. + * @param fmt is the list of formats which are supported by the codec, + * its terminated by -1 as 0 is a valid format, the formats are ordered by quality + * the first is allways the native one + * @return the choosen format + * - encoding: unused + * - decoding: set by user, if not set then the native format will always be choosen + */ + enum PixelFormat (*get_format)(struct AVCodecContext *s, enum PixelFormat * fmt); + + /** + * DTG active format information (additionnal aspect ratio + * information only used in DVB MPEG2 transport streams). 0 if + * not set. + * + * - encoding: unused. + * - decoding: set by decoder + */ + int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 + + /** + * Maximum motion estimation search range in subpel units. + * if 0 then no limit + * + * - encoding: set by user. + * - decoding: unused. + */ + int me_range; + + /** + * frame_rate_base. + * for variable fps this is 1 + * - encoding: set by user. + * - decoding: set by lavc. + * @todo move this after frame_rate + */ + + int frame_rate_base; + /** + * intra quantizer bias. + * - encoding: set by user. + * - decoding: unused + */ + int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 + + /** + * inter quantizer bias. + * - encoding: set by user. + * - decoding: unused + */ + int inter_quant_bias; + + /** + * color table ID. + * - encoding: unused. + * - decoding: which clrtable should be used for 8bit RGB images + * table have to be stored somewhere FIXME + */ + int color_table_id; + + /** + * internal_buffer count. + * Dont touch, used by lavc default_get_buffer() + */ + int internal_buffer_count; + + /** + * internal_buffers. + * Dont touch, used by lavc default_get_buffer() + */ + void *internal_buffer; + +#define FF_QUALITY_SCALE 256 + /** + * global quality for codecs which cannot change it per frame. + * this should be proportional to MPEG1/2/4 qscale. + * - encoding: set by user. + * - decoding: unused + */ + int global_quality; + +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 + /** + * coder type + * - encoding: set by user. + * - decoding: unused + */ + int coder_type; + + /** + * context model + * - encoding: set by user. + * - decoding: unused + */ + int context_model; + + /** + * slice flags + * - encoding: unused + * - decoding: set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + */ + int xvmc_acceleration; + + /** + * macroblock decision mode + * - encoding: set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distoration + + /** + * custom intra quantization matrix + * - encoding: set by user, can be NULL + * - decoding: set by lavc + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: set by user, can be NULL + * - decoding: set by lavc + */ + uint16_t *inter_matrix; + + /** + * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * this is used to workaround some encoder bugs + * - encoding: unused + * - decoding: set by user, will be converted to upper case by lavc during init + */ + unsigned int stream_codec_tag; + + /** + * scene change detection threshold. + * 0 is default, larger means fewer detected scene changes + * - encoding: set by user. + * - decoding: unused + */ + int scenechange_threshold; +} AVCodecContext; + + +/** + * AVOption. + */ +typedef struct AVOption { + /** options' name */ + const char *name; /* if name is NULL, it indicates a link to next */ + /** short English text help or const struct AVOption* subpointer */ + const char *help; // const struct AVOption* sub; + /** offset to context structure where the parsed value should be stored */ + int offset; + /** options' type */ + int type; +#define FF_OPT_TYPE_BOOL 1 ///< boolean - true,1,on (or simply presence) +#define FF_OPT_TYPE_DOUBLE 2 ///< double +#define FF_OPT_TYPE_INT 3 ///< integer +#define FF_OPT_TYPE_STRING 4 ///< string (finished with \0) +#define FF_OPT_TYPE_MASK 0x1f ///< mask for types - upper bits are various flags +//#define FF_OPT_TYPE_EXPERT 0x20 // flag for expert option +#define FF_OPT_TYPE_FLAG (FF_OPT_TYPE_BOOL | 0x40) +#define FF_OPT_TYPE_RCOVERRIDE (FF_OPT_TYPE_STRING | 0x80) + /** min value (min == max -> no limits) */ + double min; + /** maximum value for double/int */ + double max; + /** default boo [0,1]l/double/int value */ + double defval; + /** + * default string value (with optional semicolon delimited extra option-list + * i.e. option1;option2;option3 + * defval might select other then first argument as default + */ + const char *defstr; +#define FF_OPT_MAX_DEPTH 10 +} AVOption; + +/** + * Parse option(s) and sets fields in passed structure + * @param strct structure where the parsed results will be written + * @param list list with AVOptions + * @param opts string with options for parsing + */ +int avoption_parse(void* strct, const AVOption* list, const char* opts); + + +/** + * AVCodec. + */ +typedef struct AVCodec { + const char *name; + enum CodecType type; + int id; + int priv_data_size; + int (*init)(AVCodecContext *); + int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data); + int (*close)(AVCodecContext *); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, + uint8_t *buf, int buf_size); + int capabilities; + const AVOption *options; + struct AVCodec *next; + void (*flush)(AVCodecContext *); +} AVCodec; + +/** + * four components are given, that's all. + * the last component is alpha + */ +typedef struct AVPicture { + uint8_t *data[4]; + int linesize[4]; ///< number of bytes per line +} AVPicture; + +/** + * AVPaletteControl + * This structure defines a method for communicating palette changes + * between and demuxer and a decoder. + */ +typedef struct AVPaletteControl { + + /* demuxer sets this to 1 to indicate the palette has changed; + * decoder resets to 0 */ + int palette_changed; + + /* 256 3-byte RGB palette entries; the components should be + * formatted in the buffer as "RGBRGB..." and should be scaled to + * 8 bits if they originally represented 6-bit VGA palette + * components */ + unsigned char palette[256 * 3]; + +} AVPaletteControl; + +extern AVCodec ac3_encoder; +extern AVCodec mp2_encoder; +extern AVCodec mp3lame_encoder; +extern AVCodec oggvorbis_encoder; +extern AVCodec mpeg1video_encoder; +extern AVCodec mpeg2video_encoder; +extern AVCodec h263_encoder; +extern AVCodec h263p_encoder; +extern AVCodec flv_encoder; +extern AVCodec rv10_encoder; +extern AVCodec mjpeg_encoder; +extern AVCodec ljpeg_encoder; +extern AVCodec mpeg4_encoder; +extern AVCodec msmpeg4v1_encoder; +extern AVCodec msmpeg4v2_encoder; +extern AVCodec msmpeg4v3_encoder; +extern AVCodec wmv1_encoder; +extern AVCodec wmv2_encoder; +extern AVCodec huffyuv_encoder; +extern AVCodec h264_encoder; +extern AVCodec asv1_encoder; +extern AVCodec asv2_encoder; +extern AVCodec vcr1_encoder; +extern AVCodec ffv1_encoder; +extern AVCodec mdec_encoder; + +extern AVCodec h263_decoder; +extern AVCodec mpeg4_decoder; +extern AVCodec msmpeg4v1_decoder; +extern AVCodec msmpeg4v2_decoder; +extern AVCodec msmpeg4v3_decoder; +extern AVCodec wmv1_decoder; +extern AVCodec wmv2_decoder; +extern AVCodec mpeg1video_decoder; +extern AVCodec mpeg2video_decoder; +extern AVCodec mpeg_xvmc_decoder; +extern AVCodec h263i_decoder; +extern AVCodec flv_decoder; +extern AVCodec rv10_decoder; +extern AVCodec svq1_decoder; +extern AVCodec svq3_decoder; +extern AVCodec dvvideo_decoder; +extern AVCodec dvaudio_decoder; +extern AVCodec wmav1_decoder; +extern AVCodec wmav2_decoder; +extern AVCodec mjpeg_decoder; +extern AVCodec mjpegb_decoder; +extern AVCodec mp2_decoder; +extern AVCodec mp3_decoder; +extern AVCodec mace3_decoder; +extern AVCodec mace6_decoder; +extern AVCodec huffyuv_decoder; +extern AVCodec oggvorbis_decoder; +extern AVCodec cyuv_decoder; +extern AVCodec h264_decoder; +extern AVCodec indeo3_decoder; +extern AVCodec vp3_decoder; +extern AVCodec amr_nb_decoder; +extern AVCodec amr_nb_encoder; +extern AVCodec aac_decoder; +extern AVCodec mpeg4aac_decoder; +extern AVCodec asv1_decoder; +extern AVCodec asv2_decoder; +extern AVCodec vcr1_decoder; +extern AVCodec cljr_decoder; +extern AVCodec ffv1_decoder; +extern AVCodec fourxm_decoder; +extern AVCodec mdec_decoder; +extern AVCodec roq_decoder; +extern AVCodec interplay_video_decoder; +extern AVCodec xan_wc3_decoder; +extern AVCodec ra_144_decoder; +extern AVCodec ra_288_decoder; +extern AVCodec roq_dpcm_decoder; +extern AVCodec interplay_dpcm_decoder; +extern AVCodec xan_dpcm_decoder; + +/* pcm codecs */ +#define PCM_CODEC(id, name) \ +extern AVCodec name ## _decoder; \ +extern AVCodec name ## _encoder + +PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); +PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); +PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); +PCM_CODEC(CODEC_ID_PCM_U16BE, pcm_u16be); +PCM_CODEC(CODEC_ID_PCM_S8, pcm_s8); +PCM_CODEC(CODEC_ID_PCM_U8, pcm_u8); +PCM_CODEC(CODEC_ID_PCM_ALAW, pcm_alaw); +PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); + +/* adpcm codecs */ + +PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); +PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); +PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); +PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); +PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); +PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); + +#undef PCM_CODEC + +/* dummy raw video codec */ +extern AVCodec rawvideo_encoder; +extern AVCodec rawvideo_decoder; + +/* the following codecs use external GPL libs */ +extern AVCodec ac3_decoder; + +/* resample.c */ + +struct ReSampleContext; + +typedef struct ReSampleContext ReSampleContext; + +ReSampleContext *audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate); +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); +void audio_resample_close(ReSampleContext *s); + +/* YUV420 format is assumed ! */ + +struct ImgReSampleContext; + +typedef struct ImgReSampleContext ImgReSampleContext; + +ImgReSampleContext *img_resample_init(int output_width, int output_height, + int input_width, int input_height); + +ImgReSampleContext *img_resample_full_init(int owidth, int oheight, + int iwidth, int iheight, + int topBand, int bottomBand, + int leftBand, int rightBand); + +void img_resample(ImgReSampleContext *s, + AVPicture *output, AVPicture *input); + +void img_resample_close(ImgReSampleContext *s); + +int avpicture_fill(AVPicture *picture, uint8_t *ptr, + int pix_fmt, int width, int height); +int avpicture_layout(AVPicture* src, int pix_fmt, int width, int height, + unsigned char *dest, int dest_size); +int avpicture_get_size(int pix_fmt, int width, int height); +void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift); +const char *avcodec_get_pix_fmt_name(int pix_fmt); +enum PixelFormat avcodec_get_pix_fmt(const char* name); + +#define FF_LOSS_RESOLUTION 0x0001 /* loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /* loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /* loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /* loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /* loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /* loss of chroma (e.g. rgb to gray conversion) */ + +int avcodec_get_pix_fmt_loss(int dst_pix_fmt, int src_pix_fmt, + int has_alpha); +int avcodec_find_best_pix_fmt(int pix_fmt_mask, int src_pix_fmt, + int has_alpha, int *loss_ptr); + +#define FF_ALPHA_TRANSP 0x0001 /* image has some totally transparent pixels */ +#define FF_ALPHA_SEMI_TRANSP 0x0002 /* image has some transparent pixels */ +int img_get_alpha_info(AVPicture *src, int pix_fmt, int width, int height); + +/* convert among pixel formats */ +int img_convert(AVPicture *dst, int dst_pix_fmt, + AVPicture *src, int pix_fmt, + int width, int height); + +/* deinterlace a picture */ +int avpicture_deinterlace(AVPicture *dst, AVPicture *src, + int pix_fmt, int width, int height); + +/* external high level API */ + +extern AVCodec *first_avcodec; + +/* returns LIBAVCODEC_VERSION_INT constant */ +unsigned avcodec_version(void); +/* returns LIBAVCODEC_BUILD constant */ +unsigned avcodec_build(void); +void avcodec_init(void); + +void register_avcodec(AVCodec *format); +AVCodec *avcodec_find_encoder(enum CodecID id); +AVCodec *avcodec_find_encoder_by_name(const char *name); +AVCodec *avcodec_find_decoder(enum CodecID id); +AVCodec *avcodec_find_decoder_by_name(const char *name); +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +void avcodec_get_context_defaults(AVCodecContext *s); +AVCodecContext *avcodec_alloc_context(void); +AVFrame *avcodec_alloc_frame(void); + +int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); +void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); +void avcodec_default_free_buffers(AVCodecContext *s); + +/** + * opens / inits the AVCodecContext. + * not thread save! + */ +int avcodec_open(AVCodecContext *avctx, AVCodec *codec); + +int avcodec_decode_audio(AVCodecContext *avctx, int16_t *samples, + int *frame_size_ptr, + uint8_t *buf, int buf_size); +int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + uint8_t *buf, int buf_size); +int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, + int *data_size_ptr, + uint8_t *buf, int buf_size); +int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const short *samples); +int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVFrame *pict); + +int avcodec_close(AVCodecContext *avctx); + +void avcodec_register_all(void); + +void avcodec_flush_buffers(AVCodecContext *avctx); + +/* misc usefull functions */ + +/** + * returns a single letter to describe the picture type + */ +char av_get_pict_type_char(int pict_type); + +/** + * reduce a fraction. + * this is usefull for framerate calculations + * @param max the maximum allowed for dst_nom & dst_den + * @return 1 if exact, 0 otherwise + */ +int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max); + +/** + * rescale a 64bit integer. + * a simple a*b/c isnt possible as it can overflow + */ +int64_t av_rescale(int64_t a, int b, int c); + + +/** + * Interface for 0.5.0 version + * + * do not even think about it's usage for this moment + */ + +typedef struct { + /// compressed size used from given memory buffer + int size; + /// I/P/B frame type + int frame_type; +} avc_enc_result_t; + +/** + * Commands + * order can't be changed - once it was defined + */ +typedef enum { + // general commands + AVC_OPEN_BY_NAME = 0xACA000, + AVC_OPEN_BY_CODEC_ID, + AVC_OPEN_BY_FOURCC, + AVC_CLOSE, + + AVC_FLUSH, + // pin - struct { uint8_t* src, uint_t src_size } + // pout - struct { AVPicture* img, consumed_bytes, + AVC_DECODE, + // pin - struct { AVPicture* img, uint8_t* dest, uint_t dest_size } + // pout - uint_t used_from_dest_size + AVC_ENCODE, + + // query/get video commands + AVC_GET_VERSION = 0xACB000, + AVC_GET_WIDTH, + AVC_GET_HEIGHT, + AVC_GET_DELAY, + AVC_GET_QUANT_TABLE, + // ... + + // query/get audio commands + AVC_GET_FRAME_SIZE = 0xABC000, + + // maybe define some simple structure which + // might be passed to the user - but they can't + // contain any codec specific parts and these + // calls are usualy necessary only few times + + // set video commands + AVC_SET_WIDTH = 0xACD000, + AVC_SET_HEIGHT, + + // set video encoding commands + AVC_SET_FRAME_RATE = 0xACD800, + AVC_SET_QUALITY, + AVC_SET_HURRY_UP, + + // set audio commands + AVC_SET_SAMPLE_RATE = 0xACE000, + AVC_SET_CHANNELS, + +} avc_cmd_t; + +/** + * \param handle allocated private structure by libavcodec + * for initialization pass NULL - will be returned pout + * user is supposed to know nothing about its structure + * \param cmd type of operation to be performed + * \param pint input parameter + * \param pout output parameter + * + * \returns command status - eventually for query command it might return + * integer resulting value + */ +int avcodec(void* handle, avc_cmd_t cmd, void* pin, void* pout); + +/* memory */ +void *av_malloc(unsigned int size); +void *av_mallocz(unsigned int size); +void *av_realloc(void *ptr, unsigned int size); +void av_free(void *ptr); +char *av_strdup(const char *s); +void __av_freep(void **ptr); +#define av_freep(p) __av_freep((void **)(p)) +void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size); +/* for static data only */ +/* call av_free_static to release all staticaly allocated tables */ +void av_free_static(void); +void *__av_mallocz_static(void** location, unsigned int size); +#define av_mallocz_static(p, s) __av_mallocz_static((void **)(p), s) + +#ifdef __cplusplus +} +#endif + +#endif /* AVCODEC_H */ diff --git a/plugins/gs/GSsoft/Src/common.h b/plugins/gs/GSsoft/Src/common.h new file mode 100644 index 0000000000..1f815f537d --- /dev/null +++ b/plugins/gs/GSsoft/Src/common.h @@ -0,0 +1,1142 @@ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // printf("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //printf("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + printf("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + printf(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + printf("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + printf("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + printf("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/gs/GSsoft/Src/ffmpeg/avformat.h b/plugins/gs/GSsoft/Src/ffmpeg/avformat.h new file mode 100644 index 0000000000..6fb7cec1b8 --- /dev/null +++ b/plugins/gs/GSsoft/Src/ffmpeg/avformat.h @@ -0,0 +1,544 @@ +#ifndef AVFORMAT_H +#define AVFORMAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBAVFORMAT_BUILD 4608 + +#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT +#define LIBAVFORMAT_VERSION FFMPEG_VERSION +#define LIBAVFORMAT_IDENT "FFmpeg" FFMPEG_VERSION "b" AV_STRINGIFY(LIBAVFORMAT_BUILD) + +#include + +#include "avcodec.h" + +#include "avio.h" + +/* packet functions */ + +#ifndef MAXINT64 +#define MAXINT64 int64_t_C(0x7fffffffffffffff) +#endif + +#ifndef MININT64 +#define MININT64 int64_t_C(0x8000000000000000) +#endif + +#define AV_NOPTS_VALUE MININT64 +#define AV_TIME_BASE 1000000 + +typedef struct AVPacket { + int64_t pts; /* presentation time stamp in stream units (set av_set_pts_info) */ + uint8_t *data; + int size; + int stream_index; + int flags; + int duration; + void (*destruct)(struct AVPacket *); + void *priv; +} AVPacket; +#define PKT_FLAG_KEY 0x0001 + +static inline void av_init_packet(AVPacket *pkt) +{ + pkt->pts = AV_NOPTS_VALUE; + pkt->flags = 0; + pkt->stream_index = 0; +} + +int av_new_packet(AVPacket *pkt, int size); + +/** + * Free a packet + * + * @param pkt packet to free + */ +static inline void av_free_packet(AVPacket *pkt) +{ + if (pkt && pkt->destruct) { + pkt->destruct(pkt); + } +} + +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/* the exact value of the fractional number is: 'val + num / den'. num + is assumed to be such as 0 <= num < den */ +typedef struct AVFrac { + int64_t val, num, den; +} AVFrac; + +void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den); +void av_frac_add(AVFrac *f, int64_t incr); +void av_frac_set(AVFrac *f, int64_t val); + +/*************************************************/ +/* input/output formats */ + +struct AVFormatContext; + +/* this structure contains the data a format has to probe a file */ +typedef struct AVProbeData { + const char *filename; + unsigned char *buf; + int buf_size; +} AVProbeData; + +#define AVPROBE_SCORE_MAX 100 + +typedef struct AVFormatParameters { + int frame_rate; + int frame_rate_base; + int sample_rate; + int channels; + int width; + int height; + enum PixelFormat pix_fmt; + struct AVImageFormat *image_format; + int channel; /* used to select dv channel */ + const char *device; /* video4linux, audio or DV device */ + const char *standard; /* tv standard, NTSC, PAL, SECAM */ +} AVFormatParameters; + +#define AVFMT_NOFILE 0x0001 /* no file should be opened */ +#define AVFMT_NEEDNUMBER 0x0002 /* needs '%d' in filename */ +#define AVFMT_NOHEADER 0x0004 /* signal that no header is present + (streams are added dynamically) */ +#define AVFMT_SHOW_IDS 0x0008 /* show format stream IDs numbers */ +#define AVFMT_RAWPICTURE 0x0020 /* format wants AVPicture structure for + raw picture data */ + +typedef struct AVOutputFormat { + const char *name; + const char *long_name; + const char *mime_type; + const char *extensions; /* comma separated extensions */ + /* size of private data so that it can be allocated in the wrapper */ + int priv_data_size; + /* output support */ + enum CodecID audio_codec; /* default audio codec */ + enum CodecID video_codec; /* default video codec */ + int (*write_header)(struct AVFormatContext *); + int (*write_packet)(struct AVFormatContext *, + int stream_index, + const uint8_t *buf, int size, int64_t pts); + int (*write_trailer)(struct AVFormatContext *); + /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */ + int flags; + /* currently only used to set pixel format if not YUV420P */ + int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *); + /* private fields */ + struct AVOutputFormat *next; +} AVOutputFormat; + +typedef struct AVInputFormat { + const char *name; + const char *long_name; + /* size of private data so that it can be allocated in the wrapper */ + int priv_data_size; + /* tell if a given file has a chance of being parsing by this format */ + int (*read_probe)(AVProbeData *); + /* read the format header and initialize the AVFormatContext + structure. Return 0 if OK. 'ap' if non NULL contains + additionnal paramters. Only used in raw format right + now. 'av_new_stream' should be called to create new streams. */ + int (*read_header)(struct AVFormatContext *, + AVFormatParameters *ap); + /* read one packet and put it in 'pkt'. pts and flags are also + set. 'av_new_stream' can be called only if the flag + AVFMT_NOHEADER is used. */ + int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); + /* close the stream. The AVFormatContext and AVStreams are not + freed by this function */ + int (*read_close)(struct AVFormatContext *); + /* seek at or before a given pts (given in microsecond). The pts + origin is defined by the stream */ + int (*read_seek)(struct AVFormatContext *, int64_t pts); + /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_NOHEADER */ + int flags; + /* if extensions are defined, then no probe is done. You should + usually not use extension format guessing because it is not + reliable enough */ + const char *extensions; + /* general purpose read only value that the format can use */ + int value; + /* private fields */ + struct AVInputFormat *next; +} AVInputFormat; + +typedef struct AVStream { + int index; /* stream index in AVFormatContext */ + int id; /* format specific stream id */ + AVCodecContext codec; /* codec context */ + int r_frame_rate; /* real frame rate of the stream */ + int r_frame_rate_base;/* real frame rate base of the stream */ + void *priv_data; + /* internal data used in av_find_stream_info() */ + int codec_info_state; + int codec_info_nb_repeat_frames; + int codec_info_nb_real_frames; + /* PTS generation when outputing stream */ + AVFrac pts; + /* ffmpeg.c private use */ + int stream_copy; /* if TRUE, just copy stream */ + /* quality, as it has been removed from AVCodecContext and put in AVVideoFrame + * MN:dunno if thats the right place, for it */ + float quality; + /* decoding: position of the first frame of the component, in + AV_TIME_BASE fractional seconds. */ + int64_t start_time; + /* decoding: duration of the stream, in AV_TIME_BASE fractional + seconds. */ + int64_t duration; +} AVStream; + +#define MAX_STREAMS 20 + +/* format I/O context */ +typedef struct AVFormatContext { + /* can only be iformat or oformat, not both at the same time */ + struct AVInputFormat *iformat; + struct AVOutputFormat *oformat; + void *priv_data; + ByteIOContext pb; + int nb_streams; + AVStream *streams[MAX_STREAMS]; + char filename[1024]; /* input or output filename */ + /* stream info */ + char title[512]; + char author[512]; + char copyright[512]; + char comment[512]; + char album[512]; + int year; /* ID3 year, 0 if none */ + int track; /* track number, 0 if none */ + char genre[32]; /* ID3 genre */ + + int flags; /* format specific flags */ + /* private data for pts handling (do not modify directly) */ + int pts_wrap_bits; /* number of bits in pts (used for wrapping control) */ + int pts_num, pts_den; /* value to convert to seconds */ + /* This buffer is only needed when packets were already buffered but + not decoded, for example to get the codec parameters in mpeg + streams */ + struct AVPacketList *packet_buffer; + + /* decoding: position of the first frame of the component, in + AV_TIME_BASE fractional seconds. NEVER set this value directly: + it is deduced from the AVStream values. */ + int64_t start_time; + /* decoding: duration of the stream, in AV_TIME_BASE fractional + seconds. NEVER set this value directly: it is deduced from the + AVStream values. */ + int64_t duration; + /* decoding: total file size. 0 if unknown */ + int64_t file_size; + /* decoding: total stream bitrate in bit/s, 0 if not + available. Never set it directly if the file_size and the + duration are known as ffmpeg can compute it automatically. */ + int bit_rate; +} AVFormatContext; + +typedef struct AVPacketList { + AVPacket pkt; + struct AVPacketList *next; +} AVPacketList; + +extern AVInputFormat *first_iformat; +extern AVOutputFormat *first_oformat; + +/* still image support */ +struct AVInputImageContext; +typedef struct AVInputImageContext AVInputImageContext; + +typedef struct AVImageInfo { + enum PixelFormat pix_fmt; /* requested pixel format */ + int width; /* requested width */ + int height; /* requested height */ + int interleaved; /* image is interleaved (e.g. interleaved GIF) */ + AVPicture pict; /* returned allocated image */ +} AVImageInfo; + +/* AVImageFormat.flags field constants */ +#define AVIMAGE_INTERLEAVED 0x0001 /* image format support interleaved output */ + +typedef struct AVImageFormat { + const char *name; + const char *extensions; + /* tell if a given file has a chance of being parsing by this format */ + int (*img_probe)(AVProbeData *); + /* read a whole image. 'alloc_cb' is called when the image size is + known so that the caller can allocate the image. If 'allo_cb' + returns non zero, then the parsing is aborted. Return '0' if + OK. */ + int (*img_read)(ByteIOContext *, + int (*alloc_cb)(void *, AVImageInfo *info), void *); + /* write the image */ + int supported_pixel_formats; /* mask of supported formats for output */ + int (*img_write)(ByteIOContext *, AVImageInfo *); + int flags; + struct AVImageFormat *next; +} AVImageFormat; + +void av_register_image_format(AVImageFormat *img_fmt); +AVImageFormat *av_probe_image_format(AVProbeData *pd); +AVImageFormat *guess_image_format(const char *filename); +int av_read_image(ByteIOContext *pb, const char *filename, + AVImageFormat *fmt, + int (*alloc_cb)(void *, AVImageInfo *info), void *opaque); +int av_write_image(ByteIOContext *pb, AVImageFormat *fmt, AVImageInfo *img); + +extern AVImageFormat *first_image_format; + +extern AVImageFormat pnm_image_format; +extern AVImageFormat pbm_image_format; +extern AVImageFormat pgm_image_format; +extern AVImageFormat ppm_image_format; +extern AVImageFormat pam_image_format; +extern AVImageFormat pgmyuv_image_format; +extern AVImageFormat yuv_image_format; +#ifdef CONFIG_ZLIB +extern AVImageFormat png_image_format; +#endif +extern AVImageFormat jpeg_image_format; +extern AVImageFormat gif_image_format; + +/* XXX: use automatic init with either ELF sections or C file parser */ +/* modules */ + +/* mpeg.c */ +extern AVInputFormat mpegps_demux; +int mpegps_init(void); + +/* mpegts.c */ +extern AVInputFormat mpegts_demux; +int mpegts_init(void); + +/* rm.c */ +int rm_init(void); + +/* crc.c */ +int crc_init(void); + +/* img.c */ +int img_init(void); + +/* asf.c */ +int asf_init(void); + +/* avienc.c */ +int avienc_init(void); + +/* avidec.c */ +int avidec_init(void); + +/* swf.c */ +int swf_init(void); + +/* mov.c */ +int mov_init(void); + +/* movenc.c */ +int movenc_init(void); + +/* flvenc.c */ +int flvenc_init(void); + +/* flvdec.c */ +int flvdec_init(void); + +/* jpeg.c */ +int jpeg_init(void); + +/* gif.c */ +int gif_init(void); + +/* au.c */ +int au_init(void); + +/* amr.c */ +int amr_init(void); + +/* wav.c */ +int wav_init(void); + +/* raw.c */ +int raw_init(void); + +/* mp3.c */ +int mp3_init(void); + +/* yuv4mpeg.c */ +int yuv4mpeg_init(void); + +/* ogg.c */ +int ogg_init(void); + +/* dv.c */ +int dv_init(void); + +/* ffm.c */ +int ffm_init(void); + +/* rtsp.c */ +extern AVInputFormat redir_demux; +int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f); + +/* 4xm.c */ +int fourxm_init(void); + +/* psxstr.c */ +int str_init(void); + +/* idroq.c */ +int roq_init(void); + +/* ipmovie.c */ +int ipmovie_init(void); + +/* nut.c */ +int nut_init(void); + +/* wc3movie.c */ +int wc3_init(void); + +#include "rtp.h" + +#include "rtsp.h" + +/* yuv4mpeg.c */ +extern AVOutputFormat yuv4mpegpipe_oformat; + +/* utils.c */ +void av_register_input_format(AVInputFormat *format); +void av_register_output_format(AVOutputFormat *format); +AVOutputFormat *guess_stream_format(const char *short_name, + const char *filename, const char *mime_type); +AVOutputFormat *guess_format(const char *short_name, + const char *filename, const char *mime_type); + +void av_hex_dump(uint8_t *buf, int size); + +void av_register_all(void); + +typedef struct FifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; +} FifoBuffer; + +int fifo_init(FifoBuffer *f, int size); +void fifo_free(FifoBuffer *f); +int fifo_size(FifoBuffer *f, uint8_t *rptr); +int fifo_read(FifoBuffer *f, uint8_t *buf, int buf_size, uint8_t **rptr_ptr); +void fifo_write(FifoBuffer *f, uint8_t *buf, int size, uint8_t **wptr_ptr); + +/* media file input */ +AVInputFormat *av_find_input_format(const char *short_name); +AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); +int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, + AVInputFormat *fmt, + int buf_size, + AVFormatParameters *ap); + +#define AVERROR_UNKNOWN (-1) /* unknown error */ +#define AVERROR_IO (-2) /* i/o error */ +#define AVERROR_NUMEXPECTED (-3) /* number syntax expected in filename */ +#define AVERROR_INVALIDDATA (-4) /* invalid data found */ +#define AVERROR_NOMEM (-5) /* not enough memory */ +#define AVERROR_NOFMT (-6) /* unknown format */ + +int av_find_stream_info(AVFormatContext *ic); +int av_read_packet(AVFormatContext *s, AVPacket *pkt); +void av_close_input_file(AVFormatContext *s); +AVStream *av_new_stream(AVFormatContext *s, int id); +void av_set_pts_info(AVFormatContext *s, int pts_wrap_bits, + int pts_num, int pts_den); + +/* media file output */ +int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); +int av_write_header(AVFormatContext *s); +int av_write_frame(AVFormatContext *s, int stream_index, const uint8_t *buf, + int size); +int av_write_trailer(AVFormatContext *s); + +void dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output); +int parse_image_size(int *width_ptr, int *height_ptr, const char *str); +int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg); +int64_t parse_date(const char *datestr, int duration); + +int64_t av_gettime(void); + +/* ffm specific for ffserver */ +#define FFM_PACKET_SIZE 4096 +offset_t ffm_read_write_index(int fd); +void ffm_write_write_index(int fd, offset_t pos); +void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size); + +int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +int get_frame_filename(char *buf, int buf_size, + const char *path, int number); +int filename_number_test(const char *filename); + +/* grab specific */ +int video_grab_init(void); +int audio_init(void); + +/* DV1394 */ +int dv1394_init(void); + +#ifdef HAVE_AV_CONFIG_H + +#include "os_support.h" + +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); + +void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem); + +#ifdef __GNUC__ +#define dynarray_add(tab, nb_ptr, elem)\ +do {\ + typeof(tab) _tab = (tab);\ + typeof(elem) _elem = (elem);\ + (void)sizeof(**_tab == _elem); /* check that types are compatible */\ + __dynarray_add((unsigned long **)_tab, nb_ptr, (unsigned long)_elem);\ +} while(0) +#else +#define dynarray_add(tab, nb_ptr, elem)\ +do {\ + __dynarray_add((unsigned long **)(tab), nb_ptr, (unsigned long)(elem));\ +} while(0) +#endif + +time_t mktimegm(struct tm *tm); +const char *small_strptime(const char *p, const char *fmt, + struct tm *dt); + +struct in_addr; +int resolve_host(struct in_addr *sin_addr, const char *hostname); + +void url_split(char *proto, int proto_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url); + +int match_ext(const char *filename, const char *extensions); + +#endif /* HAVE_AV_CONFIG_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* AVFORMAT_H */ diff --git a/plugins/gs/GSsoft/Src/ffmpeg/avio.h b/plugins/gs/GSsoft/Src/ffmpeg/avio.h new file mode 100644 index 0000000000..952e8b67c8 --- /dev/null +++ b/plugins/gs/GSsoft/Src/ffmpeg/avio.h @@ -0,0 +1,169 @@ +#ifndef AVIO_H +#define AVIO_H + +/* output byte stream handling */ + +typedef int64_t offset_t; + +/* unbuffered I/O */ + +struct URLContext { + struct URLProtocol *prot; + int flags; + int is_streamed; /* true if streamed (no seek possible), default = false */ + int max_packet_size; /* if non zero, the stream is packetized with this max packet size */ + void *priv_data; + char filename[1]; /* specified filename */ +}; + +typedef struct URLContext URLContext; + +typedef struct URLPollEntry { + URLContext *handle; + int events; + int revents; +} URLPollEntry; + +#define URL_RDONLY 0 +#define URL_WRONLY 1 +#define URL_RDWR 2 + +typedef int URLInterruptCB(void); + +int url_open(URLContext **h, const char *filename, int flags); +int url_read(URLContext *h, unsigned char *buf, int size); +int url_write(URLContext *h, unsigned char *buf, int size); +offset_t url_seek(URLContext *h, offset_t pos, int whence); +int url_close(URLContext *h); +int url_exist(const char *filename); +offset_t url_filesize(URLContext *h); +int url_get_max_packet_size(URLContext *h); +void url_get_filename(URLContext *h, char *buf, int buf_size); + +/* the callback is called in blocking functions to test regulary if + asynchronous interruption is needed. -EINTR is returned in this + case by the interrupted function. 'NULL' means no interrupt + callback is given. */ +void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); + +/* not implemented */ +int url_poll(URLPollEntry *poll_table, int n, int timeout); + +typedef struct URLProtocol { + const char *name; + int (*url_open)(URLContext *h, const char *filename, int flags); + int (*url_read)(URLContext *h, unsigned char *buf, int size); + int (*url_write)(URLContext *h, unsigned char *buf, int size); + offset_t (*url_seek)(URLContext *h, offset_t pos, int whence); + int (*url_close)(URLContext *h); + struct URLProtocol *next; +} URLProtocol; + +extern URLProtocol *first_protocol; +extern URLInterruptCB *url_interrupt_cb; + +int register_protocol(URLProtocol *protocol); + +typedef struct { + unsigned char *buffer; + int buffer_size; + unsigned char *buf_ptr, *buf_end; + void *opaque; + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); + void (*write_packet)(void *opaque, uint8_t *buf, int buf_size); + int (*seek)(void *opaque, offset_t offset, int whence); + offset_t pos; /* position in the file of the current buffer */ + int must_flush; /* true if the next seek should flush */ + int eof_reached; /* true if eof reached */ + int write_flag; /* true if open for writing */ + int is_streamed; + int max_packet_size; +} ByteIOContext; + +int init_put_byte(ByteIOContext *s, + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + void (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*seek)(void *opaque, offset_t offset, int whence)); + +void put_byte(ByteIOContext *s, int b); +void put_buffer(ByteIOContext *s, const unsigned char *buf, int size); +void put_le64(ByteIOContext *s, uint64_t val); +void put_be64(ByteIOContext *s, uint64_t val); +void put_le32(ByteIOContext *s, unsigned int val); +void put_be32(ByteIOContext *s, unsigned int val); +void put_le16(ByteIOContext *s, unsigned int val); +void put_be16(ByteIOContext *s, unsigned int val); +void put_tag(ByteIOContext *s, const char *tag); + +void put_be64_double(ByteIOContext *s, double val); +void put_strz(ByteIOContext *s, const char *buf); + +offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence); +void url_fskip(ByteIOContext *s, offset_t offset); +offset_t url_ftell(ByteIOContext *s); +int url_feof(ByteIOContext *s); + +#define URL_EOF (-1) +int url_fgetc(ByteIOContext *s); +#ifdef __GNUC__ +int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +#else +int url_fprintf(ByteIOContext *s, const char *fmt, ...); +#endif +char *url_fgets(ByteIOContext *s, char *buf, int buf_size); + +void put_flush_packet(ByteIOContext *s); + +int get_buffer(ByteIOContext *s, unsigned char *buf, int size); +int get_byte(ByteIOContext *s); +unsigned int get_le32(ByteIOContext *s); +uint64_t get_le64(ByteIOContext *s); +unsigned int get_le16(ByteIOContext *s); + +double get_be64_double(ByteIOContext *s); +char *get_strz(ByteIOContext *s, char *buf, int maxlen); +unsigned int get_be16(ByteIOContext *s); +unsigned int get_be32(ByteIOContext *s); +uint64_t get_be64(ByteIOContext *s); + +static inline int url_is_streamed(ByteIOContext *s) +{ + return s->is_streamed; +} + +int url_fdopen(ByteIOContext *s, URLContext *h); +int url_setbufsize(ByteIOContext *s, int buf_size); +int url_fopen(ByteIOContext *s, const char *filename, int flags); +int url_fclose(ByteIOContext *s); +URLContext *url_fileno(ByteIOContext *s); +int url_fget_max_packet_size(ByteIOContext *s); + +int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags); +int url_close_buf(ByteIOContext *s); + +int url_open_dyn_buf(ByteIOContext *s); +int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size); +int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); + +/* file.c */ +extern URLProtocol file_protocol; +extern URLProtocol pipe_protocol; + +/* udp.c */ +extern URLProtocol udp_protocol; +int udp_set_remote_url(URLContext *h, const char *uri); +int udp_get_local_port(URLContext *h); +int udp_get_file_handle(URLContext *h); + +/* tcp.c */ +extern URLProtocol tcp_protocol; + +/* http.c */ +extern URLProtocol http_protocol; + +#endif + diff --git a/plugins/gs/GSsoft/Src/ffmpeg/rtp.h b/plugins/gs/GSsoft/Src/ffmpeg/rtp.h new file mode 100644 index 0000000000..d488be2c92 --- /dev/null +++ b/plugins/gs/GSsoft/Src/ffmpeg/rtp.h @@ -0,0 +1,40 @@ +/* + * RTP definitions + * Copyright (c) 2002 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef RTP_H +#define RTP_H + +#define RTP_MIN_PACKET_LENGTH 12 +#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */ + +int rtp_init(void); +int rtp_get_codec_info(AVCodecContext *codec, int payload_type); +int rtp_get_payload_type(AVCodecContext *codec); +int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt, + const unsigned char *buf, int len); + +extern AVOutputFormat rtp_mux; +extern AVInputFormat rtp_demux; + +int rtp_get_local_port(URLContext *h); +int rtp_set_remote_url(URLContext *h, const char *uri); +void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd); + +extern URLProtocol rtp_protocol; + +#endif /* RTP_H */ diff --git a/plugins/gs/GSsoft/Src/ffmpeg/rtsp.h b/plugins/gs/GSsoft/Src/ffmpeg/rtsp.h new file mode 100644 index 0000000000..a92483c485 --- /dev/null +++ b/plugins/gs/GSsoft/Src/ffmpeg/rtsp.h @@ -0,0 +1,90 @@ +/* + * RTSP definitions + * Copyright (c) 2002 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef RTSP_H +#define RTSP_H + +/* RTSP handling */ +enum RTSPStatusCode { +#define DEF(n, c, s) c = n, +#include "rtspcodes.h" +#undef DEF +}; + +enum RTSPProtocol { + RTSP_PROTOCOL_RTP_UDP = 0, + RTSP_PROTOCOL_RTP_TCP = 1, + RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2, +}; + +#define RTSP_DEFAULT_PORT 554 +#define RTSP_MAX_TRANSPORTS 8 +#define RTSP_TCP_MAX_PACKET_SIZE 1472 + +typedef struct RTSPTransportField { + int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */ + int port_min, port_max; /* RTP ports */ + int client_port_min, client_port_max; /* RTP ports */ + int server_port_min, server_port_max; /* RTP ports */ + int ttl; /* ttl value */ + uint32_t destination; /* destination IP address */ + enum RTSPProtocol protocol; +} RTSPTransportField; + +typedef struct RTSPHeader { + int content_length; + enum RTSPStatusCode status_code; /* response code from server */ + int nb_transports; + RTSPTransportField transports[RTSP_MAX_TRANSPORTS]; + int seq; /* sequence number */ + char session_id[512]; +} RTSPHeader; + +/* the callback can be used to extend the connection setup/teardown step */ +enum RTSPCallbackAction { + RTSP_ACTION_SERVER_SETUP, + RTSP_ACTION_SERVER_TEARDOWN, + RTSP_ACTION_CLIENT_SETUP, + RTSP_ACTION_CLIENT_TEARDOWN, +}; + +typedef struct RTSPActionServerSetup { + uint32_t ipaddr; + char transport_option[512]; +} RTSPActionServerSetup; + +typedef int FFRTSPCallback(enum RTSPCallbackAction action, + const char *session_id, + char *buf, int buf_size, + void *arg); + +void rtsp_set_callback(FFRTSPCallback *rtsp_cb); + +int rtsp_init(void); +void rtsp_parse_line(RTSPHeader *reply, const char *buf); + +extern int rtsp_default_protocols; +extern int rtsp_rtp_port_min; +extern int rtsp_rtp_port_max; +extern FFRTSPCallback *ff_rtsp_callback; +extern AVInputFormat rtsp_demux; + +int rtsp_pause(AVFormatContext *s); +int rtsp_resume(AVFormatContext *s); + +#endif /* RTSP_H */ diff --git a/plugins/gs/GSsoft/Src/ffmpeg/rtspcodes.h b/plugins/gs/GSsoft/Src/ffmpeg/rtspcodes.h new file mode 100644 index 0000000000..dbd2e51040 --- /dev/null +++ b/plugins/gs/GSsoft/Src/ffmpeg/rtspcodes.h @@ -0,0 +1,11 @@ +DEF(200, RTSP_STATUS_OK, "OK") +DEF(405, RTSP_STATUS_METHOD, "Method Not Allowed") +DEF(453, RTSP_STATUS_BANDWIDTH, "Not Enough Bandwidth") +DEF(454, RTSP_STATUS_SESSION, "Session Not Found") +DEF(455, RTSP_STATUS_STATE, "Method Not Valid in This State") +DEF(459, RTSP_STATUS_AGGREGATE, "Aggregate operation not allowed") +DEF(460, RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed") +DEF(461, RTSP_STATUS_TRANSPORT, "Unsupported transport") +DEF(500, RTSP_STATUS_INTERNAL, "Internal Server Error") +DEF(503, RTSP_STATUS_SERVICE, "Service Unavailable") +DEF(505, RTSP_STATUS_VERSION, "RTSP Version not supported") diff --git a/plugins/gs/GSsoft/Src/scale2x.c b/plugins/gs/GSsoft/Src/scale2x.c new file mode 100644 index 0000000000..7b6203bc2d --- /dev/null +++ b/plugins/gs/GSsoft/Src/scale2x.c @@ -0,0 +1,141 @@ +/* + This implements the AdvanceMAME Scale2x feature found on this page, + http://scale2x.sourceforge.net/ + + It is an incredibly simple and powerful image doubling routine that does + an astonishing job of doubling game graphic data while interpolating out + the jaggies. Congrats to the AdvanceMAME team, I'm very impressed and + surprised with this code! +*/ + + + +#include +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + + +#define READINT24(x) ((x)[0]<<16 | (x)[1]<<8 | (x)[2]) +#define WRITEINT24(x, i) {(x)[0]=i>>16; (x)[1]=(i>>8)&0xff; x[2]=i&0xff; } + +/* + this requires a destination surface already setup to be twice as + large as the source. oh, and formats must match too. this will just + blindly assume you didn't flounder. +*/ + +void scale2x(SDL_Surface *src, SDL_Surface *dst) +{ + int looph, loopw; + + Uint8* srcpix = (Uint8*)src->pixels; + Uint8* dstpix = (Uint8*)dst->pixels; + + const int srcpitch = src->pitch; + const int dstpitch = dst->pitch; + const int width = src->w; + const int height = src->h; + + SDL_LockSurface(src); + SDL_LockSurface(dst); + switch(src->format->BytesPerPixel) + { + case 1: { + Uint8 E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = *(Uint8*)(srcpix + (MAX(0,looph-1)*srcpitch) + (1*loopw)); + D = *(Uint8*)(srcpix + (looph*srcpitch) + (1*MAX(0,loopw-1))); + E = *(Uint8*)(srcpix + (looph*srcpitch) + (1*loopw)); + F = *(Uint8*)(srcpix + (looph*srcpitch) + (1*MIN(width-1,loopw+1))); + H = *(Uint8*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (1*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + *(Uint8*)(dstpix + looph*2*dstpitch + loopw*2*1) = E0; + *(Uint8*)(dstpix + looph*2*dstpitch + (loopw*2+1)*1) = E1; + *(Uint8*)(dstpix + (looph*2+1)*dstpitch + loopw*2*1) = E2; + *(Uint8*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*1) = E3; + } + }break;} + case 2: { + Uint16 E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = *(Uint16*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*loopw)); + D = *(Uint16*)(srcpix + (looph*srcpitch) + (2*MAX(0,loopw-1))); + E = *(Uint16*)(srcpix + (looph*srcpitch) + (2*loopw)); + F = *(Uint16*)(srcpix + (looph*srcpitch) + (2*MIN(width-1,loopw+1))); + H = *(Uint16*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + *(Uint16*)(dstpix + looph*2*dstpitch + loopw*2*2) = E0; + *(Uint16*)(dstpix + looph*2*dstpitch + (loopw*2+1)*2) = E1; + *(Uint16*)(dstpix + (looph*2+1)*dstpitch + loopw*2*2) = E2; + *(Uint16*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*2) = E3; + } + }break;} + case 3: { + int E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = READINT24(srcpix + (MAX(0,looph-1)*srcpitch) + (3*loopw)); + D = READINT24(srcpix + (looph*srcpitch) + (3*MAX(0,loopw-1))); + E = READINT24(srcpix + (looph*srcpitch) + (3*loopw)); + F = READINT24(srcpix + (looph*srcpitch) + (3*MIN(width-1,loopw+1))); + H = READINT24(srcpix + (MIN(height-1,looph+1)*srcpitch) + (3*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + WRITEINT24((dstpix + looph*2*dstpitch + loopw*2*3), E0); + WRITEINT24((dstpix + looph*2*dstpitch + (loopw*2+1)*3), E1); + WRITEINT24((dstpix + (looph*2+1)*dstpitch + loopw*2*3), E2); + WRITEINT24((dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*3), E3); + } + }break;} + default: { /*case 4:*/ + Uint32 E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = *(Uint32*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw)); + D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1))); + E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw)); + F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MIN(width-1,loopw+1))); + H = *(Uint32*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + *(Uint32*)(dstpix + looph*2*dstpitch + loopw*2*4) = E0; + *(Uint32*)(dstpix + looph*2*dstpitch + (loopw*2+1)*4) = E1; + *(Uint32*)(dstpix + (looph*2+1)*dstpitch + loopw*2*4) = E2; + *(Uint32*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*4) = E3; + } + }break;} + } + SDL_UnlockSurface(src); + SDL_UnlockSurface(dst); +} + diff --git a/plugins/gs/GSsoft/Src/scale2x.h b/plugins/gs/GSsoft/Src/scale2x.h new file mode 100644 index 0000000000..265a317421 --- /dev/null +++ b/plugins/gs/GSsoft/Src/scale2x.h @@ -0,0 +1,17 @@ +/* + This implements the AdvanceMAME Scale2x feature found on this page, + http://scale2x.sourceforge.net/ + + It is an incredibly simple and powerful image doubling routine that does + an astonishing job of doubling game graphic data while interpolating out + the jaggies. Congrats to the AdvanceMAME team, I'm very impressed and + surprised with this code! +*/ + + +#ifndef __SCALE2X_H__ +#define __SCALE2X_H__ + +void scale2x(SDL_Surface *src, SDL_Surface *dst); + +#endif /* __SCALE2X_H__ */ diff --git a/plugins/gs/GSsoft/Src/x86/ix86.h b/plugins/gs/GSsoft/Src/x86/ix86.h new file mode 100644 index 0000000000..500de53027 --- /dev/null +++ b/plugins/gs/GSsoft/Src/x86/ix86.h @@ -0,0 +1,1020 @@ +/* + * ix86 definitions v0.6.0 + * Authors: linuzappz + * alexey silinov + * goldfinger + * shadow < shadow@pcsx2.net > + */ + +#ifndef __IX86_H__ +#define __IX86_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "PS2Etypes.h" // Basic types header + +#define SIB 4 +#define DISP32 5 + +// general types +typedef enum +{ + EAX = 0, + EBX = 3, + ECX = 1, + EDX = 2, + ESI = 6, + EDI = 7, + EBP = 5, + ESP = 4, + + RAX = 0, + RBX = 3, + RCX = 1, + RDX = 2, + RSI = 6, + RDI = 7, + RBP = 5, + RSP = 4, + R8 = 8, + R9 = 9, + R10 =10, + R11 =11, + R12 =12, + R13 =13, + R14 =14, + R15 =15 + +} x86IntRegType; + +typedef enum +{ + MM0 = 0, + MM1 = 1, + MM2 = 2, + MM3 = 3, + MM4 = 4, + MM5 = 5, + MM6 = 6, + MM7 = 7 +} x86MMXRegType; + +typedef enum +{ + XMM0 = 0, + XMM1 = 1, + XMM2 = 2, + XMM3 = 3, + XMM4 = 4, + XMM5 = 5, + XMM6 = 6, + XMM7 = 7, + XMM8 = 8, + XMM9 = 9, + XMM10=10, + XMM11=11, + XMM12=12, + XMM13=13, + XMM14=14, + XMM15=15 + +} x86SSERegType; + + +extern u32 hasFloatingPointUnit; +extern u32 hasVirtual8086ModeEnhancements; +extern u32 hasDebuggingExtensions; +extern u32 hasPageSizeExtensions; +extern u32 hasTimeStampCounter; +extern u32 hasModelSpecificRegisters; +extern u32 hasPhysicalAddressExtension; +extern u32 hasMachineCheckArchitecture; +extern u32 hasCOMPXCHG8BInstruction; +extern u32 hasAdvancedProgrammableInterruptController; +extern u32 hasSEPFastSystemCall; +extern u32 hasMemoryTypeRangeRegisters; +extern u32 hasPTEGlobalFlag; +extern u32 hasMachineCheckArchitecture; +extern u32 hasConditionalMoveAndCompareInstructions; +extern u32 hasFGPageAttributeTable; +extern u32 has36bitPageSizeExtension; +extern u32 hasProcessorSerialNumber; +extern u32 hasCFLUSHInstruction; +extern u32 hasDebugStore; +extern u32 hasACPIThermalMonitorAndClockControl; +extern u32 hasMultimediaExtensions; +extern u32 hasFastStreamingSIMDExtensionsSaveRestore; +extern u32 hasStreamingSIMDExtensions; +extern u32 hasStreamingSIMD2Extensions; +extern u32 hasSelfSnoop; +extern u32 hasHyperThreading; +extern u32 hasThermalMonitor; +extern u32 hasIntel64BitArchitecture; +//that is only for AMDs +extern u32 hasMultimediaExtensionsExt; +extern u32 hasAMD64BitArchitecture; +extern u32 has3DNOWInstructionExtensionsExt; +extern u32 has3DNOWInstructionExtensions; + +extern s8 x86ID[16]; // Vendor ID +extern u32 x86Family; // Processor Family +extern u32 x86Model; // Processor Model +extern u32 x86PType; // Processor Type +extern u32 x86StepID; // Stepping ID +extern u32 x86Flags; // Feature Flags +extern u32 x86EFlags; // Extended Feature Flags +extern s8 x86Type[20]; //cpu type in char format +extern s8 x86Fam[50]; // family in char format +extern u32 cpuspeed; // Cpu speed +extern int cputype; // cpu type + +extern s8 *x86Ptr; +extern u8 *j8Ptr[32]; +extern u32 *j32Ptr[32]; + + +#ifdef __x86_64__ +#define MEMADDR(addr, oplen) ((addr) - ((u64)x86Ptr + ((u64)oplen))) +#else +#define MEMADDR(addr, oplen) (addr) +#endif + + + +void write8( u8 val ); +void write16( u16 val ); +void write32( u32 val ); +void write64( u64 val ); + +void x86Init( void ); +void x86SetPtr( char *ptr ); +void x86Shutdown( void ); +u64 GetCPUTick( void ); + +void x86SetJ8( u8 *j8 ); +void x86SetJ32( u32 *j32 ); +void x86Align( int bytes ); + +// General Helper functions + +void Rex( u8 w, u8 r, u8 x, u8 b ); +void ModRM( u8 mod, u8 rm, u8 reg ); +void SibSB( u8 ss, u8 rm, u8 index ); +void SET8R( u8 cc, u8 to ); +u8* J8Rel( u8 cc, u8 to ); +u32* J32Rel( u8 cc, u32 to ); +void CMOV32RtoR( u8 cc, u8 to, u8 from ); +void CMOV32MtoR( u8 cc, u8 to, u32 from ); + +//****************** +// IX86 intructions +//****************** + +// +// * scale values: +// * 0 - *1 +// * 1 - *2 +// * 2 - *4 +// * 3 - *8 +// + +void STC( void ); +void CLC( void ); + +//////////////////////////////////// +// mov instructions // +//////////////////////////////////// + +// mov r64 to r64 +void MOV64RtoR( x86IntRegType to, x86IntRegType from ); +// mov r64 to m64 +void MOV64RtoM( u64 to, x86IntRegType from ); +// mov m64 to r64 +void MOV64MtoR( x86IntRegType to, u64 from ); +// mov imm32 to m64 +void MOV64ItoM( u32 to, u32 from ); + +// mov r32 to r32 +void MOV32RtoR( x86IntRegType to, x86IntRegType from ); +// mov r32 to m32 +void MOV32RtoM( u32 to, x86IntRegType from ); +// mov m32 to r32 +void MOV32MtoR( x86IntRegType to, u32 from ); +// mov [r32] to r32 +void MOV32RmtoR( x86IntRegType to, x86IntRegType from ); +// mov [r32][r32*scale] to r32 +void MOV32RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale ); +// mov r32 to [r32] +void MOV32RtoRm( x86IntRegType to, x86IntRegType from ); +// mov r32 to [r32][r32*scale] +void MOV32RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale ); +// mov imm32 to r32 +void MOV32ItoR( x86IntRegType to, u32 from ); +// mov imm32 to m32 +void MOV32ItoM( u32 to, u32 from ); + +// mov r16 to m16 +void MOV16RtoM( u32 to, x86IntRegType from ); +// mov m16 to r16 +void MOV16MtoR( x86IntRegType to, u32 from ); +// mov imm16 to m16 +void MOV16ItoM( u32 to, u16 from ); +/* mov r16 to [r32][r32*scale] */ +void MOV16RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); + +// mov r8 to m8 +void MOV8RtoM( u32 to, x86IntRegType from ); +// mov m8 to r8 +void MOV8MtoR( x86IntRegType to, u32 from ); +// mov imm8 to m8 +void MOV8ItoM( u32 to, u8 from ); + +// movsx r8 to r32 +void MOVSX32R8toR( x86IntRegType to, x86IntRegType from ); +// movsx m8 to r32 +void MOVSX32M8toR( x86IntRegType to, u32 from ); +// movsx r16 to r32 +void MOVSX32R16toR( x86IntRegType to, x86IntRegType from ); +// movsx m16 to r32 +void MOVSX32M16toR( x86IntRegType to, u32 from ); + +// movzx r8 to r32 +void MOVZX32R8toR( x86IntRegType to, x86IntRegType from ); +// movzx m8 to r32 +void MOVZX32M8toR( x86IntRegType to, u32 from ); +// movzx r16 to r32 +void MOVZX32R16toR( x86IntRegType to, x86IntRegType from ); +// movzx m16 to r32 +void MOVZX32M16toR( x86IntRegType to, u32 from ); + +// cmovbe r32 to r32 +void CMOVBE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovbe m32 to r32 +void CMOVBE32MtoR( x86IntRegType to, u32 from ); +// cmovb r32 to r32 +void CMOVB32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovb m32 to r32 +void CMOVB32MtoR( x86IntRegType to, u32 from ); +// cmovae r32 to r32 +void CMOVAE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovae m32 to r32 +void CMOVAE32MtoR( x86IntRegType to, u32 from ); +// cmova r32 to r32 +void CMOVA32RtoR( x86IntRegType to, x86IntRegType from ); +// cmova m32 to r32 +void CMOVA32MtoR( x86IntRegType to, u32 from ); + +// cmovo r32 to r32 +void CMOVO32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovo m32 to r32 +void CMOVO32MtoR( x86IntRegType to, u32 from ); +// cmovp r32 to r32 +void CMOVP32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovp m32 to r32 +void CMOVP32MtoR( x86IntRegType to, u32 from ); +// cmovs r32 to r32 +void CMOVS32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovs m32 to r32 +void CMOVS32MtoR( x86IntRegType to, u32 from ); +// cmovno r32 to r32 +void CMOVNO32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovno m32 to r32 +void CMOVNO32MtoR( x86IntRegType to, u32 from ); +// cmovnp r32 to r32 +void CMOVNP32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovnp m32 to r32 +void CMOVNP32MtoR( x86IntRegType to, u32 from ); +// cmovns r32 to r32 +void CMOVNS32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovns m32 to r32 +void CMOVNS32MtoR( x86IntRegType to, u32 from ); + +// cmovne r32 to r32 +void CMOVNE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovne m32 to r32 +void CMOVNE32MtoR( x86IntRegType to, u32 from ); +// cmove r32 to r32 +void CMOVE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmove m32 to r32 +void CMOVE32MtoR( x86IntRegType to, u32 from ); +// cmovg r32 to r32 +void CMOVG32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovg m32 to r32 +void CMOVG32MtoR( x86IntRegType to, u32 from ); +// cmovge r32 to r32 +void CMOVGE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovge m32 to r32 +void CMOVGE32MtoR( x86IntRegType to, u32 from ); +// cmovl r32 to r32 +void CMOVL32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovl m32 to r32 +void CMOVL32MtoR( x86IntRegType to, u32 from ); +// cmovle r32 to r32 +void CMOVLE32RtoR( x86IntRegType to, x86IntRegType from ); +// cmovle m32 to r32 +void CMOVLE32MtoR( x86IntRegType to, u32 from ); + +//////////////////////////////////// +// arithmetic instructions // +//////////////////////////////////// + +// add imm32 to r64 +void ADD64ItoR( x86IntRegType to, u32 from ); +// add m64 to r64 +void ADD64MtoR( x86IntRegType to, u32 from ); + +// add imm32 to r32 +void ADD32ItoR( x86IntRegType to, u32 from ); +// add imm32 to m32 +void ADD32ItoM( u32 to, u32 from ); +// add r32 to r32 +void ADD32RtoR( x86IntRegType to, x86IntRegType from ); +// add r32 to m32 +void ADD32RtoM( u32 to, x86IntRegType from ); +// add m32 to r32 +void ADD32MtoR( x86IntRegType to, u32 from ); + +// add imm16 to r16 +void ADD16ItoR( x86IntRegType to, u16 from ); +// add imm16 to m16 +void ADD16ItoM( u32 to, u16 from ); +// add r16 to m16 +void ADD16RtoM( u32 to, x86IntRegType from ); +// add m16 to r16 +void ADD16MtoR( x86IntRegType to, u32 from ); + +// adc imm32 to r32 +void ADC32ItoR( x86IntRegType to, u32 from ); +// adc imm32 to m32 +void ADC32ItoM( u32 to, u32 from ); +// adc r32 to r32 +void ADC32RtoR( x86IntRegType to, x86IntRegType from ); +// adc m32 to r32 +void ADC32MtoR( x86IntRegType to, u32 from ); + +// inc r32 +void INC32R( x86IntRegType to ); +// inc m32 +void INC32M( u32 to ); +// inc r16 +void INC16R( x86IntRegType to ); +// inc m16 +void INC16M( u32 to ); + +// sub m64 to r64 +void SUB64MtoR( x86IntRegType to, u32 from ); + +// sub imm32 to r32 +void SUB32ItoR( x86IntRegType to, u32 from ); +// sub imm32 to m32 +void SUB32ItoM( u32 to, u32 from ) ; +// sub r32 to r32 +void SUB32RtoR( x86IntRegType to, x86IntRegType from ); +// sub m32 to r32 +void SUB32MtoR( x86IntRegType to, u32 from ); +// sub imm16 to r16 +void SUB16ItoR( x86IntRegType to, u16 from ); +// sub imm16 to m16 +void SUB16ItoM( u32 to, u16 from ) ; +// sub m16 to r16 +void SUB16MtoR( x86IntRegType to, u32 from ); + +// sbb r64 to r64 +void SBB64RtoR( x86IntRegType to, x86IntRegType from ); + +// sbb imm32 to r32 +void SBB32ItoR( x86IntRegType to, u32 from ); +// sbb imm32 to m32 +void SBB32ItoM( u32 to, u32 from ); +// sbb r32 to r32 +void SBB32RtoR( x86IntRegType to, x86IntRegType from ); +// sbb m32 to r32 +void SBB32MtoR( x86IntRegType to, u32 from ); + +// dec r32 +void DEC32R( x86IntRegType to ); +// dec m32 +void DEC32M( u32 to ); +// dec r16 +void DEC16R( x86IntRegType to ); +// dec m16 +void DEC16M( u32 to ); + +// mul eax by r32 to edx:eax +void MUL32R( x86IntRegType from ); +// mul eax by m32 to edx:eax +void MUL32M( u32 from ); + +// imul eax by r32 to edx:eax +void IMUL32R( x86IntRegType from ); +// imul eax by m32 to edx:eax +void IMUL32M( u32 from ); +// imul r32 by r32 to r32 +void IMUL32RtoR( x86IntRegType to, x86IntRegType from ); + +// div eax by r32 to edx:eax +void DIV32R( x86IntRegType from ); +// div eax by m32 to edx:eax +void DIV32M( u32 from ); + +// idiv eax by r32 to edx:eax +void IDIV32R( x86IntRegType from ); +// idiv eax by m32 to edx:eax +void IDIV32M( u32 from ); + +//////////////////////////////////// +// shifting instructions // +//////////////////////////////////// + +// shl imm8 to r64 +void SHL64ItoR( x86IntRegType to, u8 from ); +// shl cl to r64 +void SHL64CLtoR( x86IntRegType to ); +// shr imm8 to r64 +void SHR64ItoR( x86IntRegType to, u8 from ); +// shr cl to r64 +void SHR64CLtoR( x86IntRegType to ); +// sar imm8 to r64 +void SAR64ItoR( x86IntRegType to, u8 from ); +// sar cl to r64 +void SAR64CLtoR( x86IntRegType to ); + +// shl imm8 to r32 +void SHL32ItoR( x86IntRegType to, u8 from ); +/* shl imm8 to m32 */ +void SHL32ItoM( u32 to, u8 from ); +// shl cl to r32 +void SHL32CLtoR( x86IntRegType to ); + +// shr imm8 to r32 +void SHR32ItoR( x86IntRegType to, u8 from ); +/* shr imm8 to m32 */ +void SHR32ItoM( u32 to, u8 from ); +// shr cl to r32 +void SHR32CLtoR( x86IntRegType to ); + +// sar imm8 to r32 +void SAR32ItoR( x86IntRegType to, u8 from ); +// sar imm8 to m32 +void SAR32ItoM( u32 to, u8 from ); +// sar cl to r32 +void SAR32CLtoR( x86IntRegType to ); + +void RCR32ItoR( x86IntRegType to,u8 from ); +// shld imm8 to r32 +void SHLD32ItoR( u32 to, u32 from, u8 shift ); +// shrd imm8 to r32 +void SHRD32ItoR( u32 to, u32 from, u8 shift ); + +// sal imm8 to r32 +#define SAL32ItoR SHL32ItoR +// sal cl to r32 +#define SAL32CLtoR SHL32CLtoR + +// logical instructions + +// or imm32 to r64 +void OR64ItoR( x86IntRegType to, u32 from ); +// or m64 to r64 +void OR64MtoR( x86IntRegType to, u32 from ); + +// or imm32 to r32 +void OR32ItoR( x86IntRegType to, u32 from ); +// or imm32 to m32 +void OR32ItoM( u32 to, u32 from ); +// or r32 to r32 +void OR32RtoR( x86IntRegType to, x86IntRegType from ); +// or r32 to m32 +void OR32RtoM( u32 to, x86IntRegType from ); +// or m32 to r32 +void OR32MtoR( x86IntRegType to, u32 from ); +// or m16 to r16 +void OR16MtoR( x86IntRegType to, u32 from ); + +// xor imm32 to r64 +void XOR64ItoR( x86IntRegType to, u32 from ); +// xor r64 to r64 +void XOR64RtoR( x86IntRegType to, x86IntRegType from ); +// xor m64 to r64 +void XOR64MtoR( x86IntRegType to, u32 from ); + +// xor imm32 to r32 +void XOR32ItoR( x86IntRegType to, u32 from ); +// xor imm32 to m32 +void XOR32ItoM( u32 to, u32 from ); +// xor r32 to r32 +void XOR32RtoR( x86IntRegType to, x86IntRegType from ); +// xor r16 to r16 +void XOR16RtoR( x86IntRegType to, x86IntRegType from ); +// xor r32 to m32 +void XOR32RtoM( u32 to, x86IntRegType from ); +// xor m32 to r32 +void XOR32MtoR( x86IntRegType to, u32 from ); + +// and imm32 to r64 +void AND64ItoR( x86IntRegType to, u32 from ); +// and m64 to r64 +void AND64MtoR( x86IntRegType to, u32 from ); +// and r64 to m64 +void AND64RtoM( x86IntRegType to, u32 from ); + +// and imm32 to r32 +void AND32ItoR( x86IntRegType to, u32 from ); +// and imm32 to m32 +void AND32ItoM( u32 to, u32 from ); +// and r32 to r32 +void AND32RtoR( x86IntRegType to, x86IntRegType from ); +// and r32 to m32 +void AND32RtoM( u32 to, x86IntRegType from ); +// and m32 to r32 +void AND32MtoR( x86IntRegType to, u32 from ); +// and r16 to m16 +void AND16RtoM( u32 to, x86IntRegType from ); +// and m16 to r16 +void AND16MtoR( x86IntRegType to, u32 from ); + +// not r64 +void NOT64R( x86IntRegType from ); +// not r32 +void NOT32R( x86IntRegType from ); +// neg r64 +void NEG64R( x86IntRegType from ); +// neg r32 +void NEG32R( x86IntRegType from ); +// neg r16 +void NEG16R( x86IntRegType from ); + +//////////////////////////////////// +// jump instructions // +//////////////////////////////////// + +// jmp rel8 +u8* JMP8( u8 to ); + +// jmp rel32 +u32* JMP32( u32 to ); +// jmp r32 +void JMP32R( x86IntRegType to ); + +// jp rel8 +u8* JP8( u8 to ); +// jnp rel8 +u8* JNP8( u8 to ); +// je rel8 +u8* JE8( u8 to ); +// jz rel8 +u8* JZ8( u8 to ); +// jg rel8 +u8* JG8( u8 to ); +// jge rel8 +u8* JGE8( u8 to ); +// js rel8 +u8* JS8( u8 to ); +// jns rel8 +u8* JNS8( u8 to ); +// jl rel8 +u8* JL8( u8 to ); +// ja rel8 +u8* JA8( u8 to ); +// jae rel8 +u8* JAE8( u8 to ); +// jb rel8 +u8* JB8( u8 to ); +// jbe rel8 +u8* JBE8( u8 to ); +// jle rel8 +u8* JLE8( u8 to ); +// jne rel8 +u8* JNE8( u8 to ); +// jnz rel8 +u8* JNZ8( u8 to ); +// jng rel8 +u8* JNG8( u8 to ); +// jnge rel8 +u8* JNGE8( u8 to ); +// jnl rel8 +u8* JNL8( u8 to ); +// jnle rel8 +u8* JNLE8( u8 to ); +// jo rel8 +u8* JO8( u8 to ); +// jno rel8 +u8* JNO8( u8 to ); + +// je rel32 +u32* JE32( u32 to ); +// jz rel32 +u32* JZ32( u32 to ); +// jg rel32 +u32* JG32( u32 to ); +// jge rel32 +u32* JGE32( u32 to ); +// jl rel32 +u32* JL32( u32 to ); +// jle rel32 +u32* JLE32( u32 to ); +// jne rel32 +u32* JNE32( u32 to ); +// jnz rel32 +u32* JNZ32( u32 to ); +// jng rel32 +u32* JNG32( u32 to ); +// jnge rel32 +u32* JNGE32( u32 to ); +// jnl rel32 +u32* JNL32( u32 to ); +// jnle rel32 +u32* JNLE32( u32 to ); +// jo rel32 +u32* JO32( u32 to ); +// jno rel32 +u32* JNO32( u32 to ); + +// call func +void CALLFunc( u32 func); // based on CALL32 +// call rel32 +void CALL32( u32 to ); +// call r32 +void CALL32R( x86IntRegType to ); +// call m32 +void CALL32M( u32 to ); + +//////////////////////////////////// +// misc instructions // +//////////////////////////////////// + +// cmp imm32 to r64 +void CMP64ItoR( x86IntRegType to, u32 from ); +// cmp m64 to r64 +void CMP64MtoR( x86IntRegType to, u32 from ); + +// cmp imm32 to r32 +void CMP32ItoR( x86IntRegType to, u32 from ); +// cmp imm32 to m32 +void CMP32ItoM( u32 to, u32 from ); +// cmp r32 to r32 +void CMP32RtoR( x86IntRegType to, x86IntRegType from ); +// cmp m32 to r32 +void CMP32MtoR( x86IntRegType to, u32 from ); + +// cmp imm16 to r16 +void CMP16ItoR( x86IntRegType to, u16 from ); +// cmp imm16 to m16 +void CMP16ItoM( u32 to, u16 from ); +// cmp r16 to r16 +void CMP16RtoR( x86IntRegType to, x86IntRegType from ); +// cmp m16 to r16 +void CMP16MtoR( x86IntRegType to, u32 from ); + +// test imm32 to r32 +void TEST32ItoR( x86IntRegType to, u32 from ); +// test r32 to r32 +void TEST32RtoR( x86IntRegType to, x86IntRegType from ); + +// sets r8 +void SETS8R( x86IntRegType to ); +// setl r8 +void SETL8R( x86IntRegType to ); +// setb r8 +void SETB8R( x86IntRegType to ); +// setnz r8 +void SETNZ8R( x86IntRegType to ); + +// cbw +void CBW( void ); +// cwd +void CWD( void ); +// cdq +void CDQ( void ); + +// push r32 +void PUSH32R( x86IntRegType from ); +// push m32 +void PUSH32M( u32 from ); +// push imm32 +void PUSH32I( u32 from ); +// pop r32 +void POP32R( x86IntRegType from ); +// pushad +void PUSHA32( void ); +// popad +void POPA32( void ); +// pushfd +void PUSHFD( void ); +// popfd +void POPFD( void ); +// ret +void RET( void ); + +void BT32ItoR( x86IntRegType to, x86IntRegType from ); + +//****************** +// FPU instructions +//****************** + +// fild m32 to fpu reg stack +void FILD32( u32 from ); +// fistp m32 from fpu reg stack +void FISTP32( u32 from ); +// fld m32 to fpu reg stack +void FLD32( u32 from ); +// fst m32 from fpu reg stack +void FST32( u32 to ); +// fstp m32 from fpu reg stack +void FSTP32( u32 to ); + +// fldcw fpu control word from m16 +void FLDCW( u32 from ); +// fstcw fpu control word to m16 +void FNSTCW( u32 to ); + +// fadd ST(src) to fpu reg stack ST(0) +void FADD32Rto0( x86IntRegType src ); +// fadd ST(0) to fpu reg stack ST(src) +void FADD320toR( x86IntRegType src ); +// fsub ST(src) to fpu reg stack ST(0) +void FSUB32Rto0( x86IntRegType src ); +// fsub ST(0) to fpu reg stack ST(src) +void FSUB320toR( x86IntRegType src ); +// fsubp -> subtract ST(0) from ST(1), store in ST(1) and POP stack +void FSUBP( void ); +// fmul ST(src) to fpu reg stack ST(0) +void FMUL32Rto0( x86IntRegType src ); +// fmul ST(0) to fpu reg stack ST(src) +void FMUL320toR( x86IntRegType src ); +// fdiv ST(src) to fpu reg stack ST(0) +void FDIV32Rto0( x86IntRegType src ); +// fdiv ST(0) to fpu reg stack ST(src) +void FDIV320toR( x86IntRegType src ); + +// fadd m32 to fpu reg stack +void FADD32( u32 from ); +// fsub m32 to fpu reg stack +void FSUB32( u32 from ); +// fmul m32 to fpu reg stack +void FMUL32( u32 from ); +// fdiv m32 to fpu reg stack +void FDIV32( u32 from ); +// fcomi st, st( i) +void FCOMI( x86IntRegType src ); +// fcomip st, st( i) +void FCOMIP( x86IntRegType src ); +// fucomi st, st( i) +void FUCOMI( x86IntRegType src ); +// fucomip st, st( i) +void FUCOMIP( x86IntRegType src ); +// fcom m32 to fpu reg stack +void FCOM32( u32 from ); +// fabs fpu reg stack +void FABS( void ); +// fsqrt fpu reg stack +void FSQRT( void ); +// fchs fpu reg stack +void FCHS( void ); + +// fcmovb fpu reg to fpu reg stack +void FCMOVB32( x86IntRegType from ); +// fcmove fpu reg to fpu reg stack +void FCMOVE32( x86IntRegType from ); +// fcmovbe fpu reg to fpu reg stack +void FCMOVBE32( x86IntRegType from ); +// fcmovu fpu reg to fpu reg stack +void FCMOVU32( x86IntRegType from ); +// fcmovnb fpu reg to fpu reg stack +void FCMOVNB32( x86IntRegType from ); +// fcmovne fpu reg to fpu reg stack +void FCMOVNE32( x86IntRegType from ); +// fcmovnbe fpu reg to fpu reg stack +void FCMOVNBE32( x86IntRegType from ); +// fcmovnu fpu reg to fpu reg stack +void FCMOVNU32( x86IntRegType from ); +void FCOMP32( u32 from ); +void FNSTSWtoAX( void ); + +//****************** +// MMX instructions +//****************** + +// r64 = mm + +// movq m64 to r64 +void MOVQMtoR( x86MMXRegType to, u32 from ); +// movq r64 to m64 +void MOVQRtoM( u32 to, x86MMXRegType from ); + +// pand r64 to r64 +void PANDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pand m64 to r64 ; +void PANDMtoR( x86MMXRegType to, u32 from ); +// pandn r64 to r64 +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pandn r64 to r64 +void PANDNMtoR( x86MMXRegType to, u32 from ); +// por r64 to r64 +void PORRtoR( x86MMXRegType to, x86MMXRegType from ); +// por m64 to r64 +void PORMtoR( x86MMXRegType to, u32 from ); +// pxor r64 to r64 +void PXORRtoR( x86MMXRegType to, x86MMXRegType from ); +// pxor m64 to r64 +void PXORMtoR( x86MMXRegType to, u32 from ); + +// psllq r64 to r64 +void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psllq m64 to r64 +void PSLLQMtoR( x86MMXRegType to, u32 from ); +// psllq imm8 to r64 +void PSLLQItoR( x86MMXRegType to, u8 from ); +// psrlq r64 to r64 +void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psrlq m64 to r64 +void PSRLQMtoR( x86MMXRegType to, u32 from ); +// psrlq imm8 to r64 +void PSRLQItoR( x86MMXRegType to, u8 from ); + +// paddusb r64 to r64 +void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusb m64 to r64 +void PADDUSBMtoR( x86MMXRegType to, u32 from ); +// paddusw r64 to r64 +void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusw m64 to r64 +void PADDUSWMtoR( x86MMXRegType to, u32 from ); + +// paddb r64 to r64 +void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddb m64 to r64 +void PADDBMtoR( x86MMXRegType to, u32 from ); +// paddw r64 to r64 +void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddw m64 to r64 +void PADDWMtoR( x86MMXRegType to, u32 from ); +// paddd r64 to r64 +void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddd m64 to r64 +void PADDDMtoR( x86MMXRegType to, u32 from ); +void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PADDSDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBSDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ); +void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ); +void PSRLWItoR( x86MMXRegType to, u8 from ); +void PSRLDItoR( x86MMXRegType to, u8 from ); +void PSLLWItoR( x86MMXRegType to, u8 from ); +void PSLLDItoR( x86MMXRegType to, u8 from ); +void PSRAWItoR( x86MMXRegType to, u8 from ); +void PSRADItoR( x86MMXRegType to, u8 from ); +void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ); +void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ); +void MOVQ64ItoR( x86MMXRegType reg, u64 i ); //Prototype.Todo add all consts to end of block.not after jr $+8 +void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ); +void MOVDMtoMMX( x86MMXRegType to, u32 from ); +void MOVDMMXtoM( u32 to, x86MMXRegType from ); +void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ); +void MOVD64MMXtoR( x86IntRegType to, x86MMXRegType from ); +// emms +void EMMS( void ); + +//********************* +// SSE instructions * +//********************* +void MOVAPSMtoR( x86SSERegType to, u32 from ); +void MOVAPSRtoM( u32 to, x86SSERegType from ); +void MOVAPSRtoR( x86SSERegType to, x86SSERegType from ); + +void MOVSSMtoR( x86SSERegType to, u32 from ); +void MOVSSRtoM( u32 to, x86SSERegType from ); +void MOVSSRtoR( x86SSERegType to, x86SSERegType from ); + +void MOVLPSMtoR( x86SSERegType to, u32 from ); +void MOVLPSRtoM( u32 to, x86SSERegType from ); +void MOVHPSMtoR( x86SSERegType to, u32 from ); +void MOVHPSRtoM( u32 to, x86SSERegType from ); +void MOVLHPSRtoR( x86SSERegType to, x86SSERegType from ); +void MOVHLPSRtoR( x86SSERegType to, x86SSERegType from ); +void MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void MOVAPSRtoRm( x86IntRegType to, x86IntRegType from ); +void MOVAPSRmtoR( x86IntRegType to, x86IntRegType from ); +void MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +void MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ); +void MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ); +void ORPSMtoR( x86SSERegType to, u32 from ); +void ORPSRtoR( x86SSERegType to, x86SSERegType from ); +void XORPSMtoR( x86SSERegType to, u32 from ); +void XORPSRtoR( x86SSERegType to, x86SSERegType from ); +void ANDPSMtoR( x86SSERegType to, u32 from ); +void ANDPSRtoR( x86SSERegType to, x86SSERegType from ); +void ANDNPSMtoR( x86SSERegType to, u32 from ); +void ANDNPSRtoR( x86SSERegType to, x86SSERegType from ); +void ADDPSMtoR( x86SSERegType to, u32 from ); +void ADDPSRtoR( x86SSERegType to, x86SSERegType from ); +void SUBPSMtoR( x86SSERegType to, u32 from ); +void SUBPSRtoR( x86SSERegType to, x86SSERegType from ); +void MULPSMtoR( x86SSERegType to, u32 from ); +void MULPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPEQPSMtoR( x86SSERegType to, u32 from ); +void CMPLTPSMtoR( x86SSERegType to, u32 from ); +void CMPLEPSMtoR( x86SSERegType to, u32 from ); + +void CVTPS2DQMtoR( x86SSERegType to, u32 from ); +void CVTPS2DQRtoR( x86SSERegType to, x86SSERegType from ); + +void CVTDQ2PSDQMtoR( x86SSERegType to, u32 from ); +void CMPUNORDPSMtoR( x86SSERegType to, u32 from ); +void CMPNEPSMtoR( x86SSERegType to, u32 from ); +void CMPNLTPSMtoR( x86SSERegType to, u32 from ); +void CMPNLEPSMtoR( x86SSERegType to, u32 from ); +void CMPORDPSMtoR( x86SSERegType to, u32 from ); +void CMPEQPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPLTPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPLEPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPUNORDPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPNEPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPNLTPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPNLEPSRtoR( x86SSERegType to, x86SSERegType from ); +void CMPORDPSRtoR( x86SSERegType to, x86SSERegType from ); +void CVTPI2PSMtoR( x86SSERegType to, u32 from ); +void CVTPS2PIMtoR( x86SSERegType to, u32 from ); +void CVTPI2PSRtoR( x86SSERegType to, x86SSERegType from ); +void CVTPS2PIRtoR( x86SSERegType to, x86SSERegType from ); +void MAXPSMtoR( x86SSERegType to, u32 from ); +void MAXPSRtoR( x86SSERegType to, x86SSERegType from ); +void PMAXSWRtoR( x86SSERegType to, x86SSERegType from ); +void PMINSWRtoR( x86SSERegType to, x86SSERegType from ); +void MINPSMtoR( x86SSERegType to, u32 from ); +void MINPSRtoR( x86SSERegType to, x86SSERegType from ); +void RSQRTPSMtoR( x86SSERegType to, u32 from ); +void RSQRTPSRtoR( x86SSERegType to, x86SSERegType from ); +void SQRTPSMtoR( x86SSERegType to, u32 from ); +void SQRTPSRtoR( x86SSERegType to, x86SSERegType from ); +void UNPCKLPSRtoR( x86SSERegType to, x86SSERegType from ); +void UNPCKHPSRtoR( x86SSERegType to, x86SSERegType from ); +void SHUFPSRtoR( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void SHUFPSMtoR( x86SSERegType to, u32 from, u8 imm8 ); +void CVTDQ2PSMtoR( x86SSERegType to, u32 from ); + +void DIVPSMtoR( x86SSERegType to, u32 from ); +void DIVPSRtoR( x86SSERegType to, x86SSERegType from ); + +void DIVSSMtoR( x86SSERegType to, u32 from ); +void DIVSSRtoR( x86SSERegType to, x86SSERegType from ); + +void MOVDMtoXMM( x86SSERegType to, u32 from ); +void MOVDXMMtoM( u32 to, x86SSERegType from ); +void MOVD32RtoXMM( x86SSERegType to, x86IntRegType from ); +void MOVD64XMMtoR( x86IntRegType to, x86SSERegType from ); + +void PSHUFDRtoR( x86SSERegType to, x86SSERegType from, u8 imm8 ); +void PSHUFDMtoR( x86SSERegType to, u32 from, u8 imm8 ); + +void STMXCSR( u32 from ); +void LDMXCSR( u32 from ); + +//********************* +// 3DNOW instructions * +//********************* +void FEMMS( void ); +void PFCMPEQMtoR( x86IntRegType to, u32 from ); +void PFCMPGTMtoR( x86IntRegType to, u32 from ); +void PFCMPGEMtoR( x86IntRegType to, u32 from ); +void PFADDMtoR( x86IntRegType to, u32 from ); +void PFADDRtoR( x86IntRegType to, x86IntRegType from ); +void PFSUBMtoR( x86IntRegType to, u32 from ); +void PFSUBRtoR( x86IntRegType to, x86IntRegType from ); +void PFMULMtoR( x86IntRegType to, u32 from ); +void PFMULRtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPMtoR( x86IntRegType to, u32 from ); +void PFRCPRtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ); +void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ); +void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ); +void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ); +void PF2IDMtoR( x86IntRegType to, u32 from ); +void PF2IDRtoR( x86IntRegType to, x86IntRegType from ); +void PI2FDMtoR( x86IntRegType to, u32 from ); +void PI2FDRtoR( x86IntRegType to, x86IntRegType from ); +void PFMAXMtoR( x86IntRegType to, u32 from ); +void PFMAXRtoR( x86IntRegType to, x86IntRegType from ); +void PFMINMtoR( x86IntRegType to, u32 from ); +void PFMINRtoR( x86IntRegType to, x86IntRegType from ); + +#ifdef __cplusplus +} +#endif + +#endif // __IX86_H__ diff --git a/plugins/gs/GSsoft/Src/x86/ix86_cpudetect.c b/plugins/gs/GSsoft/Src/x86/ix86_cpudetect.c new file mode 100644 index 0000000000..b616ee63be --- /dev/null +++ b/plugins/gs/GSsoft/Src/x86/ix86_cpudetect.c @@ -0,0 +1,510 @@ + +#if defined (__WIN32__) + +#include + +#endif + +#include +#include +#include + +#include "ix86.h" + +#if defined (__VCNET2005__) + + void __cpuid(int* CPUInfo, int InfoType); + unsigned __int64 __rdtsc(); + + #pragma intrinsic(__cpuid) + #pragma intrinsic(__rdtsc) + +#endif + +u32 hasFloatingPointUnit; +u32 hasVirtual8086ModeEnhancements; +u32 hasDebuggingExtensions; +u32 hasPageSizeExtensions; +u32 hasTimeStampCounter; +u32 hasModelSpecificRegisters; +u32 hasPhysicalAddressExtension; +u32 hasMachineCheckArchitecture; +u32 hasCOMPXCHG8BInstruction; +u32 hasAdvancedProgrammableInterruptController; +u32 hasSEPFastSystemCall; +u32 hasMemoryTypeRangeRegisters; +u32 hasPTEGlobalFlag; +u32 hasMachineCheckArchitecture; +u32 hasConditionalMoveAndCompareInstructions; +u32 hasFGPageAttributeTable; +u32 has36bitPageSizeExtension; +u32 hasProcessorSerialNumber; +u32 hasCFLUSHInstruction; +u32 hasDebugStore; +u32 hasACPIThermalMonitorAndClockControl; +u32 hasMultimediaExtensions; +u32 hasFastStreamingSIMDExtensionsSaveRestore; +u32 hasStreamingSIMDExtensions; +u32 hasStreamingSIMD2Extensions; +u32 hasSelfSnoop; +u32 hasHyperThreading; +u32 hasThermalMonitor; +u32 hasIntel64BitArchitecture; +//that is only for AMDs +u32 hasMultimediaExtensionsExt; +u32 hasAMD64BitArchitecture; +u32 has3DNOWInstructionExtensionsExt; +u32 has3DNOWInstructionExtensions; + +s8 x86ID[16]; // Vendor ID +u32 x86Family; // Processor Family +u32 x86Model; // Processor Model +u32 x86PType; // Processor Type +u32 x86StepID; // Stepping ID +u32 x86Flags; // Feature Flags +u32 x86EFlags; // Extended Feature Flags +//AMD 64 STUFF +u32 x86_64_8BITBRANDID; +u32 x86_64_12BITBRANDID; +s8 x86Type[20]; //cpu type in char format +s8 x86Fam[50]; // family in char format +u32 cpuspeed; // speed of cpu +int cputype; // Cpu type + +static s32 iCpuId( u32 cmd, u32 *regs ) +{ + int flag; + +#if defined (__VCNET2005__) + + __cpuid( regs, cmd ); + + return 0; + +#elif defined (__MSCW32__) && !defined(__x86_64__) + __asm + { + push ebx; + push edi; + + pushfd; + pop eax; + mov edx, eax; + xor eax, 1 << 21; + push eax; + popfd; + pushfd; + pop eax; + xor eax, edx; + mov flag, eax; + } + if ( ! flag ) + { + return -1; + } + + __asm + { + mov eax, cmd; + cpuid; + mov edi, [regs] + mov [edi], eax; + mov [edi+4], ebx; + mov [edi+8], ecx; + mov [edi+12], edx; + + pop edi; + pop ebx; + } + + return 0; + + +#else + + __asm__ __volatile__ ( +#ifdef __x86_64__ + "sub $0x18, %%rsp\n" +#endif + "pushf\n" + "pop %%eax\n" + "mov %%eax, %%edx\n" + "xor $0x200000, %%eax\n" + "push %%eax\n" + "popf\n" + "pushf\n" + "pop %%eax\n" + "xor %%edx, %%eax\n" + "mov %%eax, %0\n" +#ifdef __x86_64__ + "add $0x18, %%rsp\n" +#endif + : "=r"(flag) : + ); + + if ( ! flag ) + { + return -1; + } + + __asm__ __volatile__ ( + "mov %4, %%eax\n" + "cpuid\n" + "mov %%eax, %0\n" + "mov %%ebx, %1\n" + "mov %%ecx, %2\n" + "mov %%edx, %3\n" + : "=m" (regs[0]), "=m" (regs[1]), + "=m" (regs[2]), "=m" (regs[3]) + : "m"(cmd) + : "eax", "ebx", "ecx", "edx" + ); + + return 0; +#endif +} + +u64 GetCPUTick( void ) +{ +#if defined (__VCNET2005__) + + return __rdtsc(); + +#elif defined(__MSCW32__) && !defined(__x86_64__) + + __asm rdtsc; + +#else + + u32 _a, _d; + __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d)); + return (u64)_a | ((u64)_d << 32); + +#endif +} + +#if defined __LINUX__ + +#include +#include + +u32 timeGetTime( void ) +{ + struct timeval tv; + gettimeofday( &tv, 0 ); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +#endif + +s64 CPUSpeedHz( unsigned int time ) +{ + s64 timeStart, + timeStop; + s64 startTick, + endTick; + s64 overhead; + + if( ! hasTimeStampCounter ) + { + return 0; //check if function is supported + } + + overhead = GetCPUTick() - GetCPUTick(); + + timeStart = timeGetTime( ); + while( timeGetTime( ) == timeStart ) + { + timeStart = timeGetTime( ); + } + while ( 1 ) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > 1 ) + { + startTick = GetCPUTick( ); + break; + } + } + + timeStart = timeStop; + while ( 1 ) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > time ) + { + endTick = GetCPUTick( ); + break; + } + } + + return (s64)( ( endTick - startTick ) + ( overhead ) ); +} +u32 AMDspeed; +s8 AMDspeedString[10]; +//////////////////////////////////////////////////// +void x86Init( void ) +{ + u32 regs[ 4 ]; + u32 cmds; + + memset( x86ID, 0, sizeof( x86ID ) ); + x86Family = 0; + x86Model = 0; + x86PType = 0; + x86StepID = 0; + x86Flags = 0; + x86EFlags = 0; + + if ( iCpuId( 0, regs ) == -1 ) return; + + cmds = regs[ 0 ]; + ((u32*)x86ID)[ 0 ] = regs[ 1 ]; + ((u32*)x86ID)[ 1 ] = regs[ 3 ]; + ((u32*)x86ID)[ 2 ] = regs[ 2 ]; + if ( cmds >= 0x00000001 ) + { + if ( iCpuId( 0x00000001, regs ) != -1 ) + { + x86StepID = regs[ 0 ] & 0xf; + x86Model = (regs[ 0 ] >> 4) & 0xf; + x86Family = (regs[ 0 ] >> 8) & 0xf; + x86PType = (regs[ 0 ] >> 12) & 0x3; + x86_64_8BITBRANDID = regs[1] & 0xff; + x86Flags = regs[ 3 ]; + } + } + if ( iCpuId( 0x80000000, regs ) != -1 ) + { + cmds = regs[ 0 ]; + if ( cmds >= 0x80000001 ) + { + if ( iCpuId( 0x80000001, regs ) != -1 ) + { + x86_64_12BITBRANDID = regs[1] & 0xfff; + x86EFlags = regs[ 3 ]; + + } + } + } + switch(x86PType) + { + case 0: + strcpy( x86Type, "Standard OEM"); + break; + case 1: + strcpy( x86Type, "Overdrive"); + break; + case 2: + strcpy( x86Type, "Dual"); + break; + case 3: + strcpy( x86Type, "Reserved"); + break; + default: + strcpy( x86Type, "Unknown"); + break; + } + if ( x86ID[ 0 ] == 'G' ){ cputype=0;}//trick lines but if you know a way better ;p + if ( x86ID[ 0 ] == 'A' ){ cputype=1;} + + if ( cputype == 0 ) //intel cpu + { + if( ( x86Family >= 7 ) && ( x86Family < 15 ) ) + { + strcpy( x86Fam, "Intel P6 family (Not PIV and Higher then PPro" ); + } + else + { + switch( x86Family ) + { + // Start at 486 because if it's below 486 there is no cpuid instruction + case 4: + strcpy( x86Fam, "Intel 486" ); + break; + case 5: + switch( x86Model ) + { + case 4: + case 8: // 0.25 µm + strcpy( x86Fam, "Intel Pentium (MMX)"); + break; + default: + strcpy( x86Fam, "Intel Pentium" ); + } + break; + case 6: + switch( x86Model ) + { + case 0: // Pentium pro (P6 A-Step) + case 1: // Pentium pro + strcpy( x86Fam, "Intel Pentium Pro" ); + break; + + case 2: // 66 MHz FSB + case 5: // Xeon/Celeron (0.25 µm) + case 6: // Internal L2 cache + strcpy( x86Fam, "Intel Pentium II" ); + break; + + case 7: // Xeon external L2 cache + case 8: // Xeon/Celeron with 256 KB on-die L2 cache + case 10: // Xeon/Celeron with 1 or 2 MB on-die L2 cache + case 11: // Xeon/Celeron with Tualatin core, on-die cache + strcpy( x86Fam, "Intel Pentium III" ); + break; + + default: + strcpy( x86Fam, "Intel Pentium Pro (Unknown)" ); + } + break; + case 15: + switch( x86Model ) + { + case 0: // Willamette (A-Step) + case 1: // Willamette + strcpy( x86Fam, "Willamette Intel Pentium IV" ); + break; + case 2: // Northwood + strcpy( x86Fam, "Northwood Intel Pentium IV" ); + break; + + default: + strcpy( x86Fam, "Intel Pentium IV (Unknown)" ); + break; + } + break; + default: + strcpy( x86Fam, "Unknown Intel CPU" ); + } + } + } + else if ( cputype == 1 ) //AMD cpu + { + if( x86Family >= 7 ) + { + if((x86_64_12BITBRANDID !=0) || (x86_64_8BITBRANDID !=0)) + { + if(x86_64_8BITBRANDID == 0 ) + { + switch((x86_64_12BITBRANDID >>6)& 0x3f) + { + case 4: + strcpy(x86Fam,"AMD Athlon(tm) 64 Processor"); + AMDspeed = 22 + (x86_64_12BITBRANDID & 0x1f); + //AMDspeedString = strtol(AMDspeed, (char**)NULL,10); + sprintf(AMDspeedString," %d",AMDspeed); + strcat(AMDspeedString,"00+"); + strcat(x86Fam,AMDspeedString); + break; + case 12: + strcpy(x86Fam,"AMD Opteron(tm) Processor"); + break; + default: + strcpy(x86Fam,"Unknown AMD 64 proccesor"); + + } + } + else //8bit brand id is non zero + { + strcpy(x86Fam,"Unsupported yet AMD64 cpu"); + } + } + else + { + strcpy( x86Fam, "AMD K7+" ); + } + } + else + { + switch ( x86Family ) + { + case 4: + switch( x86Model ) + { + case 14: + case 15: // Write-back enhanced + strcpy( x86Fam, "AMD 5x86" ); + break; + + case 3: // DX2 + case 7: // Write-back enhanced DX2 + case 8: // DX4 + case 9: // Write-back enhanced DX4 + strcpy( x86Fam, "AMD 486" ); + break; + + default: + strcpy( x86Fam, "AMD Unknown" ); + + } + break; + + case 5: + switch( x86Model) + { + case 0: // SSA 5 (75, 90 and 100 Mhz) + case 1: // 5k86 (PR 120 and 133 MHz) + case 2: // 5k86 (PR 166 MHz) + case 3: // K5 5k86 (PR 200 MHz) + strcpy( x86Fam, "AMD K5" ); + break; + + case 6: + case 7: // (0.25 µm) + case 8: // K6-2 + case 9: // K6-III + case 14: // K6-2+ / K6-III+ + strcpy( x86Fam, "AMD K6" ); + break; + + default: + strcpy( x86Fam, "AMD Unknown" ); + } + break; + case 6: + strcpy( x86Fam, "AMD K7" ); + break; + default: + strcpy( x86Fam, "Unknown AMD CPU" ); + } + } + } + //capabilities + hasFloatingPointUnit = ( x86Flags >> 0 ) & 1; + hasVirtual8086ModeEnhancements = ( x86Flags >> 1 ) & 1; + hasDebuggingExtensions = ( x86Flags >> 2 ) & 1; + hasPageSizeExtensions = ( x86Flags >> 3 ) & 1; + hasTimeStampCounter = ( x86Flags >> 4 ) & 1; + hasModelSpecificRegisters = ( x86Flags >> 5 ) & 1; + hasPhysicalAddressExtension = ( x86Flags >> 6 ) & 1; + hasMachineCheckArchitecture = ( x86Flags >> 7 ) & 1; + hasCOMPXCHG8BInstruction = ( x86Flags >> 8 ) & 1; + hasAdvancedProgrammableInterruptController = ( x86Flags >> 9 ) & 1; + hasSEPFastSystemCall = ( x86Flags >> 11 ) & 1; + hasMemoryTypeRangeRegisters = ( x86Flags >> 12 ) & 1; + hasPTEGlobalFlag = ( x86Flags >> 13 ) & 1; + hasMachineCheckArchitecture = ( x86Flags >> 14 ) & 1; + hasConditionalMoveAndCompareInstructions = ( x86Flags >> 15 ) & 1; + hasFGPageAttributeTable = ( x86Flags >> 16 ) & 1; + has36bitPageSizeExtension = ( x86Flags >> 17 ) & 1; + hasProcessorSerialNumber = ( x86Flags >> 18 ) & 1; + hasCFLUSHInstruction = ( x86Flags >> 19 ) & 1; + hasDebugStore = ( x86Flags >> 21 ) & 1; + hasACPIThermalMonitorAndClockControl = ( x86Flags >> 22 ) & 1; + hasMultimediaExtensions = ( x86Flags >> 23 ) & 1; //mmx + hasFastStreamingSIMDExtensionsSaveRestore = ( x86Flags >> 24 ) & 1; + hasStreamingSIMDExtensions = ( x86Flags >> 25 ) & 1; //sse + hasStreamingSIMD2Extensions = ( x86Flags >> 26 ) & 1; //sse2 + hasSelfSnoop = ( x86Flags >> 27 ) & 1; + hasHyperThreading = ( x86Flags >> 28 ) & 1; + hasThermalMonitor = ( x86Flags >> 29 ) & 1; + hasIntel64BitArchitecture = ( x86Flags >> 30 ) & 1; + //that is only for AMDs + hasMultimediaExtensionsExt = ( x86EFlags >> 22 ) & 1; //mmx2 + hasAMD64BitArchitecture = ( x86EFlags >> 29 ) & 1; //64bit cpu + has3DNOWInstructionExtensionsExt = ( x86EFlags >> 30 ) & 1; //3dnow+ + has3DNOWInstructionExtensions = ( x86EFlags >> 31 ) & 1; //3dnow + + cpuspeed = (u32 )(CPUSpeedHz( 1000 ) / 1000000); +} diff --git a/plugins/gs/build.sh b/plugins/gs/build.sh new file mode 100644 index 0000000000..5fd8813e3e --- /dev/null +++ b/plugins/gs/build.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +echo ---------------------------------------- +echo Building Graphics Synthesizer plugins... +echo ---------------------------------------- + +curdir=`pwd` + +cd ${curdir}/zerogs +sh build.sh $@ diff --git a/plugins/gs/gsdx9/GS.cpp b/plugins/gs/gsdx9/GS.cpp new file mode 100644 index 0000000000..78070540b4 --- /dev/null +++ b/plugins/gs/gsdx9/GS.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx9.h" +#include "GS.h" +#include "GSRendererHW.h" +#include "GSRendererSoft.h" +#include "GSRendererNull.h" +#include "GSWnd.h" +#include "GSSettingsDlg.h" + +#define PS2E_LT_GS 0x01 +#define PS2E_GS_VERSION 0x0006 +#define PS2E_DLL_VERSION 0x09 +#define PS2E_X86 0x01 // 32 bit +#define PS2E_X86_64 0x02 // 64 bit + +EXPORT_C_(UINT32) PS2EgetLibType() +{ + return PS2E_LT_GS; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + CString str = _T("GSdx9"); + +#if _M_AMD64 + str += _T(" 64-bit"); +#endif + + CList sl; + +#ifdef __INTEL_COMPILER + CString s; + s.Format(_T("Intel C++ %d.%02d"), __INTEL_COMPILER/100, __INTEL_COMPILER%100); + sl.AddTail(s); +#elif _MSC_VER + CString s; + s.Format(_T("MSVC %d.%02d"), _MSC_VER/100, _MSC_VER%100); + sl.AddTail(s); +#endif + +#if _M_IX86_FP >= 2 + sl.AddTail(_T("SSE2")); +#elif _M_IX86_FP >= 1 + sl.AddTail(_T("SSE")); +#endif + +#ifdef _OPENMP + sl.AddTail(_T("OpenMP")); +#endif + + POSITION pos = sl.GetHeadPosition(); + while(pos) + { + if(pos == sl.GetHeadPosition()) str += _T(" ("); + str += sl.GetNext(pos); + str += pos ? _T(", ") : _T(")"); + } + + static char buff[256]; + strncpy(buff, CStringA(str), min(countof(buff)-1, str.GetLength())); + return buff; +} + +EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) +{ + return (PS2E_GS_VERSION<<16)|(0x00<<8)|PS2E_DLL_VERSION; +} + +EXPORT_C_(UINT32) PS2EgetCpuPlatform() +{ +#if _M_AMD64 + return PS2E_X86_64; +#else + return PS2E_X86; +#endif +} + +////////////////// + +#define REPLAY_TITLE "Replay" + +static HRESULT s_hrCoInit = E_FAIL; +static CGSWnd s_hWnd; +static CAutoPtr s_gs; +static void (*s_fpGSirq)() = NULL; + +BYTE* g_pBasePS2Mem = NULL; + +EXPORT_C GSsetBaseMem(BYTE* pBasePS2Mem) +{ + g_pBasePS2Mem = pBasePS2Mem - 0x12000000; +} + +EXPORT_C_(INT32) GSinit() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + return 0; +} + +EXPORT_C GSshutdown() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); +} + +EXPORT_C_(INT32) GSopen(void* pDsp, char* Title, int multithread) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + // + + s_hrCoInit = ::CoInitialize(0); + + ASSERT(!s_gs); + s_gs.Free(); + + if(!s_hWnd.Create(_T("PCSX2"))) + return -1; + + HRESULT hr; + + switch(AfxGetApp()->GetProfileInt(_T("Settings"), _T("Renderer"), RENDERER_D3D_HW)) + { + case RENDERER_D3D_HW: s_gs.Attach(new GSRendererHW(s_hWnd, hr)); break; + // case RENDERER_D3D_SW_FX: s_gs.Attach(new GSRendererSoftFX(s_hWnd, hr)); break; + case RENDERER_D3D_SW_FP: s_gs.Attach(new GSRendererSoftFP(s_hWnd, hr)); break; + case RENDERER_D3D_NULL: s_gs.Attach(new GSRendererNull(s_hWnd, hr)); break; + } + + if(!s_gs || FAILED(hr)) + { + s_gs.Free(); + s_hWnd.DestroyWindow(); + return -1; + } + + // + + if(!IsWindow(s_hWnd)) + return -1; + + *(HWND*)pDsp = s_hWnd; + + s_gs->ResetDevice(); + + s_gs->GSirq(s_fpGSirq); + + s_gs->m_fMultiThreaded = !!multithread; + + if((!Title || strcmp(Title, REPLAY_TITLE) != 0) + && AfxGetApp()->GetProfileInt(_T("Settings"), _T("RecordState"), FALSE)) + { + CPath spath = AfxGetApp()->GetProfileString(_T("Settings"), _T("RecordStatePath"), _T("")); + CString fn; + fn.Format(_T("gsdx9_%s.gs"), CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); + spath.Append(fn); + s_gs->CaptureState(spath); + } + + s_hWnd.SetWindowText(CString(Title)); + + s_hWnd.Show(); + + return 0; +} + +EXPORT_C GSclose() +{ + s_hWnd.Show(false); + + ASSERT(s_gs); + s_gs.Free(); + + s_hWnd.DestroyWindow(); + + if(SUCCEEDED(s_hrCoInit)) ::CoUninitialize(); +} + +EXPORT_C GSreset() +{ + s_gs->Reset(); +} + +EXPORT_C GSwriteCSR(UINT32 csr) +{ + s_gs->WriteCSR(csr); +} + +EXPORT_C GSreadFIFO(BYTE* pMem) +{ + s_gs->ReadFIFO(pMem); +} + +EXPORT_C GSgifTransfer1(BYTE* pMem, UINT32 addr) +{ + s_gs->Transfer1(pMem, addr); +} + +EXPORT_C GSgifTransfer2(BYTE* pMem, UINT32 size) +{ + s_gs->Transfer2(pMem, size); +} + +EXPORT_C GSgifTransfer3(BYTE* pMem, UINT32 size) +{ + s_gs->Transfer3(pMem, size); +} + +extern int Path3hack; + +EXPORT_C GSgetLastTag(UINT64* ptag) +{ + *(UINT32*)ptag = Path3hack; + Path3hack = 0; +} + +EXPORT_C GSvsync(int field) +{ + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while(msg.message != WM_QUIT) + { + if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + // TODO + // Sleep(40); + s_gs->VSync(field); + break; + } + } +} + +//////// + +EXPORT_C_(UINT32) GSmakeSnapshot(char* path) +{ + return s_gs->MakeSnapshot(path); +} + + + +EXPORT_C GSkeyEvent(keyEvent* ev) +{ + if(ev->event != KEYPRESS) return; + + switch(ev->key) + { + case VK_INSERT: + s_gs->Capture(); + break; + + case VK_DELETE: + s_gs->ToggleOSD(); + break; + + default: + break; + } +} + +EXPORT_C_(INT32) GSfreeze(int mode, freezeData* data) +{ + if(mode == FREEZE_SAVE) + { + return s_gs->Freeze(data, false); + } + else if(mode == FREEZE_SIZE) + { + return s_gs->Freeze(data, true); + } + else if(mode == FREEZE_LOAD) + { + return s_gs->Defrost(data); + } + + return 0; +} + +EXPORT_C GSconfigure() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if(IDOK == CGSSettingsDlg().DoModal()) + { + GSshutdown(); + GSinit(); + } +} + +EXPORT_C_(INT32) GStest() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + int ret = 0; + + D3DCAPS9 caps; + ZeroMemory(&caps, sizeof(caps)); + caps.PixelShaderVersion = D3DPS_VERSION(0, 0); + + if(CComPtr pD3D = Direct3DCreate9(D3D_SDK_VERSION)) + { + pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, &caps); + + LPCTSTR yep = _T("^_^"), nope = _T(":'("); + + CString str, tmp; + + if(caps.PixelShaderVersion < D3DPS_VERSION(1, 4)) + ret = -1; + + tmp.Format(_T("%s Pixel Shader version %d.%d\n"), + caps.PixelShaderVersion >= D3DPS_VERSION(1, 4) ? yep : nope, + D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion), + D3DSHADER_VERSION_MINOR(caps.PixelShaderVersion)); + str += tmp; + + if(!(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND)) + ret = -1; + + tmp.Format(_T("%s Separate Alpha Blend\n"), + !!(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) ? yep : nope); + str += tmp; + + if(!(caps.SrcBlendCaps & D3DPBLENDCAPS_BLENDFACTOR) + || !(caps.DestBlendCaps & D3DPBLENDCAPS_BLENDFACTOR)) + ret = -1; + + tmp.Format(_T("%s Source Blend Factor\n"), + !!(caps.SrcBlendCaps & D3DPBLENDCAPS_BLENDFACTOR) ? yep : nope); + str += tmp; + + tmp.Format(_T("%s Destination Blend Factor\n"), + !!(caps.DestBlendCaps & D3DPBLENDCAPS_BLENDFACTOR) ? yep : nope); + str += tmp; + + AfxMessageBox(str); + } + else + { + ret = -1; + } + + return ret; +} + +EXPORT_C GSabout() +{ +} + +EXPORT_C GSirqCallback(void (*fpGSirq)()) +{ + s_fpGSirq = fpGSirq; + // if(s_gs) s_gs->GSirq(fpGSirq); +} + +///////////////// +/* +EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + if(!GSinit()) + { + HWND hWnd = NULL; + if(!GSopen((void*)&hWnd, REPLAY_TITLE)) + { + if(FILE* sfp = _tfopen(lpszCmdLine, _T("rb"))) + { + BYTE* buff = (BYTE*)_aligned_malloc(4*1024*1024, 16); + + while(!feof(sfp)) + { + switch(fgetc(sfp)) + { + case ST_WRITE: + { + GS_REG mem; + UINT64 value, mask; + fread(&mem, 4, 1, sfp); + fread(&value, 8, 1, sfp); + fread(&mask, 8, 1, sfp); + switch(mask) + { + case 0xff: GSwrite8(mem, (UINT8)value); break; + case 0xffff: GSwrite16(mem, (UINT16)value); break; + case 0xffffffff: GSwrite32(mem, (UINT32)value); break; + case 0xffffffffffffffff: GSwrite64(mem, value); break; + } + break; + } + case ST_TRANSFER: + { + UINT32 size = 0; + fread(&size, 4, 1, sfp); + UINT32 len = 0; + fread(&len, 4, 1, sfp); + if(len > 4*1024*1024) {ASSERT(0); break;} + fread(buff, len, 1, sfp); + GSgifTransfer3(buff, size); + break; + } + case ST_VSYNC: + GSvsync(); + break; + } + } + + _aligned_free(buff); + } + + GSclose(); + } + + GSshutdown(); + } +} +*/ \ No newline at end of file diff --git a/plugins/gs/gsdx9/GS.h b/plugins/gs/gsdx9/GS.h new file mode 100644 index 0000000000..89c20272a5 --- /dev/null +++ b/plugins/gs/gsdx9/GS.h @@ -0,0 +1,945 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * Special Notes: + * + * Register definitions and most of the enums originate from sps2dev-0.4.0 + * Copyright (C) 2002 Terratron Technologies Inc. All Rights Reserved. + * + */ + +#pragma once + +// + +#pragma pack(push, 1) + +// +// sps2registers.h +// + +enum GS_REG +{ + GS_PMODE = 0x12000000, + GS_SMODE1 = 0x12000010, + GS_SMODE2 = 0x12000020, + GS_SRFSH = 0x12000030, + GS_SYNCH1 = 0x12000040, + GS_SYNCH2 = 0x12000050, + GS_SYNCV = 0x12000060, + GS_DISPFB1 = 0x12000070, + GS_DISPLAY1 = 0x12000080, + GS_DISPFB2 = 0x12000090, + GS_DISPLAY2 = 0x120000a0, + GS_EXTBUF = 0x120000b0, + GS_EXTDATA = 0x120000c0, + GS_EXTWRITE = 0x120000d0, + GS_BGCOLOR = 0x120000e0, + GS_UNKNOWN = 0x12000400, + GS_CSR = 0x12001000, + GS_IMR = 0x12001010, + GS_BUSDIR = 0x12001040, + GS_SIGLBLID = 0x12001080 +}; + +enum GS_PRIM +{ + GS_POINTLIST = 0, + GS_LINELIST = 1, + GS_LINESTRIP = 2, + GS_TRIANGLELIST = 3, + GS_TRIANGLESTRIP = 4, + GS_TRIANGLEFAN = 5, + GS_SPRITE = 6, + GS_INVALID = 7, +}; + +enum GIF_REG +{ + GIF_REG_PRIM = 0x00, + GIF_REG_RGBA = 0x01, + GIF_REG_STQ = 0x02, + GIF_REG_UV = 0x03, + GIF_REG_XYZF2 = 0x04, + GIF_REG_XYZ2 = 0x05, + GIF_REG_TEX0_1 = 0x06, + GIF_REG_TEX0_2 = 0x07, + GIF_REG_CLAMP_1 = 0x08, + GIF_REG_CLAMP_2 = 0x09, + GIF_REG_FOG = 0x0a, + GIF_REG_XYZF3 = 0x0c, + GIF_REG_XYZ3 = 0x0d, + GIF_REG_A_D = 0x0e, + GIF_REG_NOP = 0x0f, +}; + +enum GIF_A_D_REG +{ + GIF_A_D_REG_PRIM = 0x00, + GIF_A_D_REG_RGBAQ = 0x01, + GIF_A_D_REG_ST = 0x02, + GIF_A_D_REG_UV = 0x03, + GIF_A_D_REG_XYZF2 = 0x04, + GIF_A_D_REG_XYZ2 = 0x05, + GIF_A_D_REG_TEX0_1 = 0x06, + GIF_A_D_REG_TEX0_2 = 0x07, + GIF_A_D_REG_CLAMP_1 = 0x08, + GIF_A_D_REG_CLAMP_2 = 0x09, + GIF_A_D_REG_FOG = 0x0a, + GIF_A_D_REG_XYZF3 = 0x0c, + GIF_A_D_REG_XYZ3 = 0x0d, + GIF_A_D_REG_NOP = 0x0f, + GIF_A_D_REG_TEX1_1 = 0x14, + GIF_A_D_REG_TEX1_2 = 0x15, + GIF_A_D_REG_TEX2_1 = 0x16, + GIF_A_D_REG_TEX2_2 = 0x17, + GIF_A_D_REG_XYOFFSET_1 = 0x18, + GIF_A_D_REG_XYOFFSET_2 = 0x19, + GIF_A_D_REG_PRMODECONT = 0x1a, + GIF_A_D_REG_PRMODE = 0x1b, + GIF_A_D_REG_TEXCLUT = 0x1c, + GIF_A_D_REG_SCANMSK = 0x22, + GIF_A_D_REG_MIPTBP1_1 = 0x34, + GIF_A_D_REG_MIPTBP1_2 = 0x35, + GIF_A_D_REG_MIPTBP2_1 = 0x36, + GIF_A_D_REG_MIPTBP2_2 = 0x37, + GIF_A_D_REG_TEXA = 0x3b, + GIF_A_D_REG_FOGCOL = 0x3d, + GIF_A_D_REG_TEXFLUSH = 0x3f, + GIF_A_D_REG_SCISSOR_1 = 0x40, + GIF_A_D_REG_SCISSOR_2 = 0x41, + GIF_A_D_REG_ALPHA_1 = 0x42, + GIF_A_D_REG_ALPHA_2 = 0x43, + GIF_A_D_REG_DIMX = 0x44, + GIF_A_D_REG_DTHE = 0x45, + GIF_A_D_REG_COLCLAMP = 0x46, + GIF_A_D_REG_TEST_1 = 0x47, + GIF_A_D_REG_TEST_2 = 0x48, + GIF_A_D_REG_PABE = 0x49, + GIF_A_D_REG_FBA_1 = 0x4a, + GIF_A_D_REG_FBA_2 = 0x4b, + GIF_A_D_REG_FRAME_1 = 0x4c, + GIF_A_D_REG_FRAME_2 = 0x4d, + GIF_A_D_REG_ZBUF_1 = 0x4e, + GIF_A_D_REG_ZBUF_2 = 0x4f, + GIF_A_D_REG_BITBLTBUF = 0x50, + GIF_A_D_REG_TRXPOS = 0x51, + GIF_A_D_REG_TRXREG = 0x52, + GIF_A_D_REG_TRXDIR = 0x53, + GIF_A_D_REG_HWREG = 0x54, + GIF_A_D_REG_SIGNAL = 0x60, + GIF_A_D_REG_FINISH = 0x61, + GIF_A_D_REG_LABEL = 0x62, +}; + +enum GIF_FLG +{ + GIF_FLG_PACKED = 0, + GIF_FLG_REGLIST = 1, + GIF_FLG_IMAGE = 2, + GIF_FLG_IMAGE2 = 3 +}; + +enum PSM +{ + PSM_PSMCT32 = 0, + PSM_PSMCT24 = 1, + PSM_PSMCT16 = 2, + PSM_PSMCT16S = 10, + PSM_PSMT8 = 19, + PSM_PSMT4 = 20, + PSM_PSMT8H = 27, + PSM_PSMT4HL = 36, + PSM_PSMT4HH = 44, + PSM_PSMZ32 = 48, + PSM_PSMZ24 = 49, + PSM_PSMZ16 = 50, + PSM_PSMZ16S = 58, +}; + +// +// sps2regstructs.h +// + +#define REG64(name) \ +union name \ +{ \ + UINT64 i64; \ + UINT32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + UINT64 ai64[2]; \ + UINT32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + UINT64 i64; \ + UINT32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + UINT64 ai64[2]; \ + UINT32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + UINT32 R:8; + UINT32 G:8; + UINT32 B:8; + UINT32 _PAD1:8; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + UINT32 DIR:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + UINT32 rSIGNAL:1; + UINT32 rFINISH:1; + UINT32 rHSINT:1; + UINT32 rVSINT:1; + UINT32 rEDWINT:1; + UINT32 rZERO1:1; + UINT32 rZERO2:1; + UINT32 r_PAD1:1; + UINT32 rFLUSH:1; + UINT32 rRESET:1; + UINT32 r_PAD2:2; + UINT32 rNFIELD:1; + UINT32 rFIELD:1; + UINT32 rFIFO:2; + UINT32 rREV:8; + UINT32 rID:8; + UINT32 wSIGNAL:1; + UINT32 wFINISH:1; + UINT32 wHSINT:1; + UINT32 wVSINT:1; + UINT32 wEDWINT:1; + UINT32 wZERO1:1; + UINT32 wZERO2:1; + UINT32 w_PAD1:1; + UINT32 wFLUSH:1; + UINT32 wRESET:1; + UINT32 w_PAD2:2; + UINT32 wNFIELD:1; + UINT32 wFIELD:1; + UINT32 wFIFO:2; + UINT32 wREV:8; + UINT32 wID:8; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + UINT32 FBP:9; + UINT32 FBW:6; + UINT32 PSM:5; + UINT32 _PAD:12; + UINT32 DBX:11; + UINT32 DBY:11; + UINT32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + UINT32 DX:12; + UINT32 DY:11; + UINT32 MAGH:4; + UINT32 MAGV:2; + UINT32 _PAD:3; + UINT32 DW:12; + UINT32 DH:11; + UINT32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + UINT32 EXBP:14; + UINT32 EXBW:6; + UINT32 FBIN:2; + UINT32 WFFMD:1; + UINT32 EMODA:2; + UINT32 EMODC:2; + UINT32 _PAD1:5; + UINT32 WDX:11; + UINT32 WDY:11; + UINT32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + UINT32 SX:12; + UINT32 SY:11; + UINT32 SMPH:4; + UINT32 SMPV:2; + UINT32 _PAD1:3; + UINT32 WW:12; + UINT32 WH:11; + UINT32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + UINT32 WRITE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + UINT32 _PAD1:8; + UINT32 SIGMSK:1; + UINT32 FINISHMSK:1; + UINT32 HSMSK:1; + UINT32 VSMSK:1; + UINT32 EDWMSK:1; + UINT32 _PAD2:19; + UINT32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + UINT32 EN1:1; + UINT32 EN2:1; + UINT32 CRTMD:3; + UINT32 MMOD:1; + UINT32 AMOD:1; + UINT32 SLBG:1; + UINT32 ALP:8; + UINT32 _PAD:16; + UINT32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + UINT32 SIGID:32; + UINT32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + UINT32 RC:3; + UINT32 LC:7; + UINT32 T1248:2; + UINT32 SLCK:1; + UINT32 CMOD:2; + UINT32 EX:1; + UINT32 PRST:1; + UINT32 SINT:1; + UINT32 XPCK:1; + UINT32 PCK2:2; + UINT32 SPML:4; + UINT32 GCONT:1; + UINT32 PHS:1; + UINT32 PVS:1; + UINT32 PEHS:1; + UINT32 PEVS:1; + UINT32 CLKSEL:2; + UINT32 NVCK:1; + UINT32 SLCK2:1; + UINT32 VCKSEL:2; + UINT32 VHP:1; + UINT32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + UINT32 INT:1; + UINT32 FFMD:1; + UINT32 DPMS:2; + UINT32 _PAD2:28; + UINT32 _PAD3:32; +REG_END + +REG64_SET(GSReg) + GSRegBGCOLOR BGCOLOR; + GSRegBUSDIR BUSDIR; + GSRegCSR CSR; + GSRegDISPFB DISPFB; + GSRegDISPLAY DISPLAY; + GSRegEXTBUF EXTBUF; + GSRegEXTDATA EXTDATA; + GSRegEXTWRITE EXTWRITE; + GSRegIMR IMR; + GSRegPMODE PMODE; + GSRegSIGLBLID SIGLBLID; + GSRegSMODE1 SMODE1; + GSRegSMODE2 SMODE2; +REG_SET_END + +// +// sps2tags.h +// + +#define SET_GIF_REG(gifTag, iRegNo, uiValue) \ + {((GIFTag*)&gifTag)->ai64[1] |= (((uiValue) & 0xf) << ((iRegNo) << 2));} + +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag + +REG128(GIFTag) + UINT32 NLOOP:15; + UINT32 EOP:1; + UINT32 _PAD1:16; + UINT32 _PAD2:14; + UINT32 PRE:1; + UINT32 PRIM:11; + UINT32 FLG:2; // enum GIF_FLG + UINT32 NREG:4; + UINT64 REGS:64; +REG_END + +// GIFReg + +REG64_(GIFReg, ALPHA) + UINT32 A:2; + UINT32 B:2; + UINT32 C:2; + UINT32 D:2; + UINT32 _PAD1:24; + UINT32 FIX:8; + UINT32 _PAD2:24; +REG_END + +REG64_(GIFReg, BITBLTBUF) + UINT32 SBP:14; + UINT32 _PAD1:2; + UINT32 SBW:6; + UINT32 _PAD2:2; + UINT32 SPSM:6; + UINT32 _PAD3:2; + UINT32 DBP:14; + UINT32 _PAD4:2; + UINT32 DBW:6; + UINT32 _PAD5:2; + UINT32 DPSM:6; + UINT32 _PAD6:2; +REG_END + +REG64_(GIFReg, CLAMP) + UINT64 WMS:2; + UINT64 WMT:2; + UINT64 MINU:10; + UINT64 MAXU:10; + UINT64 MINV:10; + UINT64 MAXV:10; + UINT64 _PAD:20; +REG_END + +REG64_(GIFReg, COLCLAMP) + UINT32 CLAMP:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, DIMX) + UINT32 DM00:3; + UINT32 _PAD00:1; + UINT32 DM01:3; + UINT32 _PAD01:1; + UINT32 DM02:3; + UINT32 _PAD02:1; + UINT32 DM03:3; + UINT32 _PAD03:1; + + UINT32 DM10:3; + UINT32 _PAD10:1; + UINT32 DM11:3; + UINT32 _PAD11:1; + UINT32 DM12:3; + UINT32 _PAD12:1; + UINT32 DM13:3; + UINT32 _PAD13:1; + + UINT32 DM20:3; + UINT32 _PAD20:1; + UINT32 DM21:3; + UINT32 _PAD21:1; + UINT32 DM22:3; + UINT32 _PAD22:1; + UINT32 DM23:3; + UINT32 _PAD23:1; + + UINT32 DM30:3; + UINT32 _PAD30:1; + UINT32 DM31:3; + UINT32 _PAD31:1; + UINT32 DM32:3; + UINT32 _PAD32:1; + UINT32 DM33:3; + UINT32 _PAD33:1; +REG_END + +REG64_(GIFReg, DTHE) + UINT32 DTHE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FBA) + UINT32 FBA:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FINISH) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FOG) + UINT32 _PAD1:32; + UINT32 _PAD2:24; + UINT32 F:8; +REG_END + +REG64_(GIFReg, FOGCOL) + UINT32 FCR:8; + UINT32 FCG:8; + UINT32 FCB:8; + UINT32 _PAD1:8; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FRAME) + UINT32 FBP:9; + UINT32 _PAD1:7; + UINT32 FBW:6; + UINT32 _PAD2:2; + UINT32 PSM:6; + UINT32 _PAD3:2; + UINT32 FBMSK:32; +REG_END2 + UINT32 Block() {return FBP<<5;} +REG_END2 + +REG64_(GIFReg, HWREG) + UINT32 DATA_LOWER:32; + UINT32 DATA_UPPER:32; +REG_END + +REG64_(GIFReg, LABEL) + UINT32 ID:32; + UINT32 IDMSK:32; +REG_END + +REG64_(GIFReg, MIPTBP1) + UINT64 TBP1:14; + UINT64 TBW1:6; + UINT64 TBP2:14; + UINT64 TBW2:6; + UINT64 TBP3:14; + UINT64 TBW3:6; + UINT64 _PAD:4; +REG_END + +REG64_(GIFReg, MIPTBP2) + UINT64 TBP4:14; + UINT64 TBW4:6; + UINT64 TBP5:14; + UINT64 TBW5:6; + UINT64 TBP6:14; + UINT64 TBW6:6; + UINT64 _PAD:4; +REG_END + +REG64_(GIFReg, NOP) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PABE) + UINT32 PABE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PRIM) + UINT32 PRIM:3; + UINT32 IIP:1; + UINT32 TME:1; + UINT32 FGE:1; + UINT32 ABE:1; + UINT32 AA1:1; + UINT32 FST:1; + UINT32 CTXT:1; + UINT32 FIX:1; + UINT32 _PAD1:21; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PRMODE) + UINT32 _PRIM:3; + UINT32 IIP:1; + UINT32 TME:1; + UINT32 FGE:1; + UINT32 ABE:1; + UINT32 AA1:1; + UINT32 FST:1; + UINT32 CTXT:1; + UINT32 FIX:1; + UINT32 _PAD2:21; + UINT32 _PAD3:32; +REG_END + +REG64_(GIFReg, PRMODECONT) + UINT32 AC:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, RGBAQ) + UINT32 R:8; + UINT32 G:8; + UINT32 B:8; + UINT32 A:8; + float Q; +REG_END + +REG64_(GIFReg, SCANMSK) + UINT32 MSK:2; + UINT32 _PAD1:30; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, SCISSOR) + UINT32 SCAX0:11; + UINT32 _PAD1:5; + UINT32 SCAX1:11; + UINT32 _PAD2:5; + UINT32 SCAY0:11; + UINT32 _PAD3:5; + UINT32 SCAY1:11; + UINT32 _PAD4:5; +REG_END + +REG64_(GIFReg, SIGNAL) + UINT32 ID:32; + UINT32 IDMSK:32; +REG_END + +REG64_(GIFReg, ST) + float S; + float T; +REG_END + +REG64_(GIFReg, TEST) + UINT32 ATE:1; + UINT32 ATST:3; + UINT32 AREF:8; + UINT32 AFAIL:2; + UINT32 DATE:1; + UINT32 DATM:1; + UINT32 ZTE:1; + UINT32 ZTST:2; + UINT32 _PAD1:13; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TEX0) + UINT64 TBP0:14; + UINT64 TBW:6; + UINT64 PSM:6; + UINT64 TW:4; + UINT64 TH:4; + UINT64 TCC:1; + UINT64 TFX:2; + UINT64 CBP:14; + UINT64 CPSM:4; + UINT64 CSM:1; + UINT64 CSA:5; + UINT64 CLD:3; +REG_END + +REG64_(GIFReg, TEX1) + UINT32 LCM:1; + UINT32 _PAD1:1; + UINT32 MXL:3; + UINT32 MMAG:1; + UINT32 MMIN:3; + UINT32 MTBA:1; + UINT32 _PAD2:9; + UINT32 L:2; + UINT32 _PAD3:11; + UINT32 K:12; + UINT32 _PAD4:20; +REG_END + +REG64_(GIFReg, TEX2) + UINT32 _PAD1:20; + UINT32 PSM:6; + UINT32 _PAD2:6; + UINT32 _PAD3:5; + UINT32 CBP:14; + UINT32 CPSM:4; + UINT32 CSM:1; + UINT32 CSA:5; + UINT32 CLD:3; +REG_END + +REG64_(GIFReg, TEXA) + UINT32 TA0:8; + UINT32 _PAD1:7; + UINT32 AEM:1; + UINT32 _PAD2:16; + UINT32 TA1:8; + UINT32 _PAD3:24; +REG_END + +REG64_(GIFReg, TEXCLUT) + UINT32 CBW:6; + UINT32 COU:6; + UINT32 COV:10; + UINT32 _PAD1:10; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TEXFLUSH) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TRXDIR) + UINT32 XDIR:2; + UINT32 _PAD1:30; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TRXPOS) + UINT32 SSAX:11; + UINT32 _PAD1:5; + UINT32 SSAY:11; + UINT32 _PAD2:5; + UINT32 DSAX:11; + UINT32 _PAD3:5; + UINT32 DSAY:11; + UINT32 DIR:2; + UINT32 _PAD4:3; +REG_END + +REG64_(GIFReg, TRXREG) + UINT32 RRW:12; + UINT32 _PAD1:20; + UINT32 RRH:12; + UINT32 _PAD2:20; +REG_END + +REG64_(GIFReg, UV) + UINT32 U:14; + UINT32 _PAD1:2; + UINT32 V:14; + UINT32 _PAD2:2; + UINT32 _PAD3:32; +REG_END + +REG64_(GIFReg, XYOFFSET) + UINT32 OFX:16; + UINT32 _PAD1:16; + UINT32 OFY:16; + UINT32 _PAD2:16; +REG_END + +REG64_(GIFReg, XYZ) + UINT32 X:16; + UINT32 Y:16; + UINT32 Z:32; +REG_END + +REG64_(GIFReg, XYZF) + UINT32 X:16; + UINT32 Y:16; + UINT32 Z:24; + UINT32 F:8; +REG_END + +REG64_(GIFReg, ZBUF) + UINT32 ZBP:9; + UINT32 _PAD1:15; + // UINT32 PSM:4; + // UINT32 _PAD2:4; + UINT32 PSM:6; + UINT32 _PAD2:2; + UINT32 ZMSK:1; + UINT32 _PAD3:31; +REG_END + +REG64_SET(GIFReg) + GIFRegALPHA ALPHA; + GIFRegBITBLTBUF BITBLTBUF; + GIFRegCLAMP CLAMP; + GIFRegCOLCLAMP COLCLAMP; + GIFRegDIMX DIMX; + GIFRegDTHE DTHE; + GIFRegFBA FBA; + GIFRegFINISH FINISH; + GIFRegFOG FOG; + GIFRegFOGCOL FOGCOL; + GIFRegFRAME FRAME; + GIFRegHWREG HWREG; + GIFRegLABEL LABEL; + GIFRegMIPTBP1 MIPTBP1; + GIFRegMIPTBP2 MIPTBP2; + GIFRegNOP NOP; + GIFRegPABE PABE; + GIFRegPRIM PRIM; + GIFRegPRMODE PRMODE; + GIFRegPRMODECONT PRMODECONT; + GIFRegRGBAQ RGBAQ; + GIFRegSCANMSK SCANMSK; + GIFRegSCISSOR SCISSOR; + GIFRegSIGNAL SIGNAL; + GIFRegST ST; + GIFRegTEST TEST; + GIFRegTEX0 TEX0; + GIFRegTEX1 TEX1; + GIFRegTEX2 TEX2; + GIFRegTEXA TEXA; + GIFRegTEXCLUT TEXCLUT; + GIFRegTEXFLUSH TEXFLUSH; + GIFRegTRXDIR TRXDIR; + GIFRegTRXPOS TRXPOS; + GIFRegTRXREG TRXREG; + GIFRegUV UV; + GIFRegXYOFFSET XYOFFSET; + GIFRegXYZ XYZ; + GIFRegXYZF XYZF; + GIFRegZBUF ZBUF; +REG_SET_END + +// GIFPacked + +REG128_(GIFPacked, PRIM) + UINT32 PRIM:11; + UINT32 _PAD1:21; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_(GIFPacked, RGBA) + UINT32 R:8; + UINT32 _PAD1:24; + UINT32 G:8; + UINT32 _PAD2:24; + UINT32 B:8; + UINT32 _PAD3:24; + UINT32 A:8; + UINT32 _PAD4:24; +REG_END + +REG128_(GIFPacked, STQ) + float S; + float T; + float Q; + UINT32 _PAD1:32; +REG_END + +REG128_(GIFPacked, UV) + UINT32 U:14; + UINT32 _PAD1:18; + UINT32 V:14; + UINT32 _PAD2:18; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_(GIFPacked, XYZF2) + UINT32 X:16; + UINT32 _PAD1:16; + UINT32 Y:16; + UINT32 _PAD2:16; + UINT32 _PAD3:4; + UINT32 Z:24; + UINT32 _PAD4:4; + UINT32 _PAD5:4; + UINT32 F:8; + UINT32 _PAD6:3; + UINT32 ADC:1; + UINT32 _PAD7:16; +REG_END + +REG128_(GIFPacked, XYZ2) + UINT32 X:16; + UINT32 _PAD1:16; + UINT32 Y:16; + UINT32 _PAD2:16; + UINT32 Z:32; + UINT32 _PAD3:15; + UINT32 ADC:1; + UINT32 _PAD4:16; +REG_END + +REG128_(GIFPacked, FOG) + UINT32 _PAD1:32; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:4; + UINT32 F:8; + UINT32 _PAD5:20; +REG_END + +REG128_(GIFPacked, A_D) + UINT64 DATA:64; + UINT32 ADDR:8; // enum GIF_A_D_REG + UINT32 _PAD1:24; + UINT32 _PAD2:32; +REG_END + +REG128_(GIFPacked, NOP) + UINT32 _PAD1:32; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_SET(GIFPackedReg) + GIFReg r; + GIFPackedPRIM PRIM; + GIFPackedRGBA RGBA; + GIFPackedSTQ STQ; + GIFPackedUV UV; + GIFPackedXYZF2 XYZF2; + GIFPackedXYZ2 XYZ2; + GIFPackedFOG FOG; + GIFPackedA_D A_D; + GIFPackedNOP NOP; +REG_SET_END + +#pragma pack(pop) + +enum {KEYPRESS=1, KEYRELEASE=2}; +struct keyEvent {UINT32 key, event;}; + +enum {FREEZE_LOAD=0, FREEZE_SAVE=1, FREEZE_SIZE=2}; +struct freezeData {int size; BYTE* data;}; + +enum stateType {ST_WRITE, ST_TRANSFER, ST_VSYNC}; diff --git a/plugins/gs/gsdx9/GSCapture.cpp b/plugins/gs/gsdx9/GSCapture.cpp new file mode 100644 index 0000000000..99ca45a49b --- /dev/null +++ b/plugins/gs/gsdx9/GSCapture.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSCapture.h" +#include "GSCaptureDlg.h" +#include +#include +// +// GSSource +// + +#ifdef __INTEL_COMPILER +interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")) +#else +[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface +#endif +IGSSource : public IUnknown +{ + STDMETHOD(DeliverNewSegment)() PURE; + STDMETHOD(DeliverFrame)(D3DLOCKED_RECT& r) PURE; + STDMETHOD(DeliverEOS)() PURE; +}; + +#ifdef __INTEL_COMPILER +class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")) +#else +[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class +#endif +GSSource : public CBaseFilter, public IGSSource +{ + CCritSec m_csLock; + CAutoPtr m_pOutput; + CSize m_size; + REFERENCE_TIME m_rtAvgTimePerFrame, m_rtNow; + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) + { + return + QI(IGSSource) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + class GSSourceOutputPin : public CBaseOutputPin + { + CMediaType m_mt; + + public: + GSSourceOutputPin(CMediaType& mt, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr) + : CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output") + , m_mt(mt) + { + } + + HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) + { + ASSERT(pAlloc && pProperties); + + HRESULT hr; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = m_mt.lSampleSize; + + ALLOCATOR_PROPERTIES Actual; + if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr; + + if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL; + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return S_OK; + } + + HRESULT CheckMediaType(const CMediaType* pmt) + { + return pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_RGB32 ? S_OK : E_FAIL; + } + + HRESULT GetMediaType(int iPosition, CMediaType* pmt) + { + CheckPointer(pmt, E_POINTER); + if(iPosition < 0) return E_INVALIDARG; + if(iPosition > 0) return VFW_S_NO_MORE_ITEMS; + *pmt = m_mt; + return S_OK; + } + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) + { + return E_NOTIMPL; + } + }; + +public: + GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr) + : CBaseFilter(NAME("GSSource"), pUnk, &m_csLock, __uuidof(this), &hr) + , m_pOutput(NULL) + , m_size(w, h) + , m_rtAvgTimePerFrame(10000000i64/fps) + , m_rtNow(0) + { + CMediaType mt; + + mt.majortype = MEDIATYPE_Video; + mt.subtype = MEDIASUBTYPE_RGB32; + mt.formattype = FORMAT_VideoInfo; + mt.lSampleSize = w*h*4; + + VIDEOINFOHEADER vih; + memset(&vih, 0, sizeof(vih)); + vih.AvgTimePerFrame = m_rtAvgTimePerFrame; + vih.bmiHeader.biSize = sizeof(vih.bmiHeader); + vih.bmiHeader.biCompression = BI_RGB; + vih.bmiHeader.biPlanes = 1; + vih.bmiHeader.biWidth = w; + vih.bmiHeader.biHeight = -h; + vih.bmiHeader.biBitCount = 32; + vih.bmiHeader.biSizeImage = w*h*4; + mt.SetFormat((BYTE*)&vih, sizeof(vih)); + + m_pOutput.Attach(new GSSourceOutputPin(mt, this, &m_csLock, hr)); + } + + DECLARE_IUNKNOWN; + + int GetPinCount() {return 1;} + CBasePin* GetPin(int n) {return n == 0 ? m_pOutput.m_p : NULL;} + + // IGSSource + + STDMETHODIMP DeliverNewSegment() + { + return m_pOutput->DeliverNewSegment(m_rtNow = 0, _I64_MAX, 1.0); + } + + STDMETHODIMP DeliverFrame(D3DLOCKED_RECT& r) + { + HRESULT hr; + + if(!m_pOutput || !m_pOutput->IsConnected()) return E_UNEXPECTED; + + CComPtr pSample; + if(FAILED(hr = m_pOutput->GetDeliveryBuffer(&pSample, NULL, NULL, 0))) + return hr; + + REFERENCE_TIME rtStart = m_rtNow, rtStop = m_rtNow + m_rtAvgTimePerFrame; + + pSample->SetTime(&rtStart, &rtStop); + pSample->SetSyncPoint(TRUE); + + BYTE* pSrc = (BYTE*)r.pBits; + int srcpitch = r.Pitch; + + BYTE* pDst = NULL; + pSample->GetPointer(&pDst); + CMediaType mt; + m_pOutput->GetMediaType(0, &mt); + int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth*4; + + int minpitch = min(srcpitch, dstpitch); + + for(int y = 0; y < m_size.cy; y++, pDst += dstpitch, pSrc += srcpitch) + memcpy(pDst, pSrc, minpitch); + + if(FAILED(hr = m_pOutput->Deliver(pSample))) + return hr; + + m_rtNow = rtStop; + + return S_OK; + } + + STDMETHODIMP DeliverEOS() + { + return m_pOutput->DeliverEndOfStream(); + } +}; + +// +// GSCapture +// + +GSCapture::GSCapture() +{ +} + +bool GSCapture::BeginCapture(IDirect3DDevice9* pD3Dev, int fps) +{ + ASSERT(pD3Dev != NULL && fps != 0); + + EndCapture(); + + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + GSCaptureDlg dlg; + dlg.DoModal(); + //if(IDOK != dlg.DoModal()) + // return false; + + HRESULT hr; + + int w, h; + w = 640, h = 480; // TODO + + CComPtr pRTSurf; + if(FAILED(hr = pD3Dev->CreateRenderTarget(w, h, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pRTSurf, NULL))) + return false; + + if(FAILED(hr = pD3Dev->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &m_pSysMemSurf, NULL))) + return false; + + // + + m_pGB.CoCreateInstance(CLSID_FilterGraph); + if(!m_pGB) return false; + + CComPtr pCGB; + pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2); + if(!pCGB) return false; + + pCGB->SetFiltergraph(m_pGB); + + CComPtr pMux; + if(FAILED(hr = pCGB->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &pMux, NULL))) + return false; + + m_pSrc = new GSSource(w, h, fps, NULL, hr); + if(FAILED(hr = m_pGB->AddFilter(m_pSrc, L"Source"))) + return false; + + if(FAILED(hr = m_pGB->AddFilter(dlg.m_pVidEnc, L"Encoder"))) + return false; + + if(FAILED(hr = pCGB->RenderStream(NULL, NULL, m_pSrc, dlg.m_pVidEnc, pMux))) + return false; + + hr = CComQIPtr(m_pGB)->Run(); + + hr = CComQIPtr(m_pSrc)->DeliverNewSegment(); + + m_pRTSurf = pRTSurf; + + return true; +} + +bool GSCapture::BeginFrame(int& w, int& h, IDirect3DSurface9** pRTSurf) +{ + if(!m_pRTSurf || !pRTSurf) return false; + + // FIXME: remember w, h from BeginCapture + D3DSURFACE_DESC desc; + if(FAILED(m_pRTSurf->GetDesc(&desc))) return false; + w = desc.Width; + h = desc.Height; + + (*pRTSurf = m_pRTSurf)->AddRef(); + + return true; +} + +bool GSCapture::EndFrame() +{ + if(m_pRTSurf == NULL || m_pSysMemSurf == NULL) {ASSERT(0); return false;} + + CComPtr pD3DDev; + D3DLOCKED_RECT r; + + if(FAILED(m_pRTSurf->GetDevice(&pD3DDev)) + || FAILED(pD3DDev->GetRenderTargetData(m_pRTSurf, m_pSysMemSurf)) + || FAILED(m_pSysMemSurf->LockRect(&r, NULL, D3DLOCK_READONLY))) + return false; + + CComQIPtr(m_pSrc)->DeliverFrame(r); + + m_pSysMemSurf->UnlockRect(); + + return true; +} + +bool GSCapture::EndCapture() +{ + m_pRTSurf = NULL; + m_pSysMemSurf = NULL; + + if(m_pSrc) CComQIPtr(m_pSrc)->DeliverEOS(); + if(m_pGB) CComQIPtr(m_pGB)->Stop(); + + m_pSrc = NULL; + m_pGB = NULL; + + return true; +} diff --git a/plugins/gs/gsdx9/GSCapture.h b/plugins/gs/gsdx9/GSCapture.h new file mode 100644 index 0000000000..8d6e05ee54 --- /dev/null +++ b/plugins/gs/gsdx9/GSCapture.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +class GSCapture +{ + CComPtr m_pRTSurf, m_pSysMemSurf; + + CComPtr m_pGB; + CComPtr m_pSrc; + +public: + GSCapture(); + + bool BeginCapture(IDirect3DDevice9* pD3Dev, int fps); + bool BeginFrame(int& w, int& h, IDirect3DSurface9** pRTSurf); + bool EndFrame(); + bool EndCapture(); + + bool IsCapturing() {return !!m_pRTSurf;} +}; diff --git a/plugins/gs/gsdx9/GSCaptureDlg.cpp b/plugins/gs/gsdx9/GSCaptureDlg.cpp new file mode 100644 index 0000000000..ccad461f0c --- /dev/null +++ b/plugins/gs/gsdx9/GSCaptureDlg.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +// GSCaptureDlg.cpp : implementation file +// + +#include "stdafx.h" +#include +#include "GSCaptureDlg.h" + +// GSCaptureDlg dialog + +IMPLEMENT_DYNAMIC(GSCaptureDlg, CDialog) +GSCaptureDlg::GSCaptureDlg(CWnd* pParent /*=NULL*/) + : CDialog(GSCaptureDlg::IDD, pParent) +{ + m_filename = AfxGetApp()->GetProfileString(_T("Capture"), _T("FileName")); +} + +GSCaptureDlg::~GSCaptureDlg() +{ +} + +int GSCaptureDlg::GetSelCodec(Codec& c) +{ + int iSel = m_codeclist.GetCurSel(); + if(iSel < 0) return 0; + + POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(iSel); + if(pos == NULL) return 2; + + c = m_codecs.GetAt(pos); + + if(!c.pBF) + { + c.pMoniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.pBF); + if(!c.pBF) return 0; + } + + return 1; +} + +LRESULT GSCaptureDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + if(message == WM_INITDIALOG) SendMessage(WM_KICKIDLE); + return(ret); +} + +void GSCaptureDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_filename); + DDX_Control(pDX, IDC_COMBO1, m_codeclist); +} + +BOOL GSCaptureDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + m_codecs.RemoveAll(); + + m_codeclist.ResetContent(); + m_codeclist.SetItemDataPtr(m_codeclist.AddString(_T("Uncompressed")), NULL); + + BeginEnumSysDev(CLSID_VideoCompressorCategory, pMoniker) + { + Codec c; + c.pMoniker = pMoniker; + + LPOLESTR strName = NULL; + if(FAILED(pMoniker->GetDisplayName(NULL, NULL, &strName))) + continue; + + c.DisplayName = strName; + CoTaskMemFree(strName); + + CComPtr pPB; + pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB); + + CComVariant var; + if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) + continue; + + c.FriendlyName = var.bstrVal; + + CStringW str = CStringW(c.DisplayName).MakeLower(); + if(str.Find(L"@device:dmo:") == 0) + c.FriendlyName = _T("(DMO) ") + c.FriendlyName; + else if(str.Find(L"@device:sw:") == 0) + c.FriendlyName = _T("(DS) ") + c.FriendlyName; + else if(str.Find(L"@device:cm:") == 0) + c.FriendlyName = _T("(VfW) ") + c.FriendlyName; + + m_codeclist.SetItemDataPtr(m_codeclist.AddString(c.FriendlyName), m_codecs.AddTail(c)); + } + EndEnumSysDev + + // + + CString DisplayNameToFind = AfxGetApp()->GetProfileString(_T("Capture"), _T("VideoCodecDisplayName")); + + for(int i = 0; i < m_codeclist.GetCount(); i++) + { + CString DisplayName; + + POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(i); + if(pos) DisplayName = m_codecs.GetAt(pos).DisplayName; + + if(DisplayName == DisplayNameToFind) + { + m_codeclist.SetCurSel(i); + break; + } + } + + // + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +BEGIN_MESSAGE_MAP(GSCaptureDlg, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) + ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOK) +END_MESSAGE_MAP() + +// GSCaptureDlg message handlers + +void GSCaptureDlg::OnKickIdle() +{ + UpdateDialogControls(this, false); +} + +void GSCaptureDlg::OnBnClickedButton1() +{ + UpdateData(); + + CFileDialog fd(FALSE, _T("avi"), m_filename, + OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST, + _T("Avi files (*.avi)|*.avi||"), this, 0); + + if(fd.DoModal() == IDOK) + { + m_filename = fd.GetPathName(); + UpdateData(FALSE); + } +} + +void GSCaptureDlg::OnBnClickedButton2() +{ + Codec c; + if(GetSelCodec(c) != 1) return; + + if(CComQIPtr pSPP = c.pBF) + { + CAUUID caGUID; + caGUID.pElems = NULL; + if(SUCCEEDED(pSPP->GetPages(&caGUID))) + { + IUnknown* lpUnk = NULL; + pSPP.QueryInterface(&lpUnk); + OleCreatePropertyFrame( + m_hWnd, 0, 0, CStringW(c.FriendlyName), + 1, (IUnknown**)&lpUnk, + caGUID.cElems, caGUID.pElems, + 0, 0, NULL); + lpUnk->Release(); + + if(caGUID.pElems) CoTaskMemFree(caGUID.pElems); + } + } + else if(CComQIPtr pAMVfWCD = c.pBF) + { + if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK) + pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd); + } +} + +void GSCaptureDlg::OnUpdateButton2(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_codeclist.GetCurSel() >= 0 && m_codeclist.GetItemDataPtr(m_codeclist.GetCurSel()) != NULL); +} + +void GSCaptureDlg::OnBnClickedOk() +{ + UpdateData(); + + Codec c; + if(GetSelCodec(c) == 0) return; + + m_pVidEnc = c.pBF; + + AfxGetApp()->WriteProfileString(_T("Capture"), _T("FileName"), m_filename); + AfxGetApp()->WriteProfileString(_T("Capture"), _T("VideoCodecDisplayName"), CString(c.DisplayName)); + + OnOK(); +} + +void GSCaptureDlg::OnUpdateOK(CCmdUI* pCmdUI) +{ + CString str; + GetDlgItem(IDC_EDIT1)->GetWindowText(str); + + pCmdUI->Enable(!str.IsEmpty() && m_codeclist.GetCurSel() >= 0); +} diff --git a/plugins/gs/gsdx9/GSCaptureDlg.h b/plugins/gs/gsdx9/GSCaptureDlg.h new file mode 100644 index 0000000000..758493f904 --- /dev/null +++ b/plugins/gs/gsdx9/GSCaptureDlg.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "resource.h" +#include "afxwin.h" + +// GSCaptureDlg dialog + +class GSCaptureDlg : public CDialog +{ + DECLARE_DYNAMIC(GSCaptureDlg) + +private: + struct Codec + { + CComPtr pMoniker; + CComPtr pBF; + CString FriendlyName; + CComBSTR DisplayName; + }; + + CList m_codecs; + + int GetSelCodec(Codec& c); + +public: + GSCaptureDlg(CWnd* pParent = NULL); // standard constructor + virtual ~GSCaptureDlg(); + + CComPtr m_pVidEnc; + +// Dialog Data + enum { IDD = IDD_CAPTURE }; + CString m_filename; + CComboBox m_codeclist; + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnKickIdle(); + afx_msg void OnBnClickedButton1(); + afx_msg void OnBnClickedButton2(); + afx_msg void OnUpdateButton2(CCmdUI* pCmdUI); + afx_msg void OnBnClickedOk(); + afx_msg void OnUpdateOK(CCmdUI* pCmdUI); +}; diff --git a/plugins/gs/gsdx9/GSHash.cpp b/plugins/gs/gsdx9/GSHash.cpp new file mode 100644 index 0000000000..cdc030360d --- /dev/null +++ b/plugins/gs/gsdx9/GSHash.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" + +static const DWORD s_crctable[256] = +{ + 0x00000000l, 0x90910101l, 0x91210201l, 0x01b00300l, + 0x92410401l, 0x02d00500l, 0x03600600l, 0x93f10701l, + 0x94810801l, 0x04100900l, 0x05a00a00l, 0x95310b01l, + 0x06c00c00l, 0x96510d01l, 0x97e10e01l, 0x07700f00l, + 0x99011001l, 0x09901100l, 0x08201200l, 0x98b11301l, + 0x0b401400l, 0x9bd11501l, 0x9a611601l, 0x0af01700l, + 0x0d801800l, 0x9d111901l, 0x9ca11a01l, 0x0c301b00l, + 0x9fc11c01l, 0x0f501d00l, 0x0ee01e00l, 0x9e711f01l, + 0x82012001l, 0x12902100l, 0x13202200l, 0x83b12301l, + 0x10402400l, 0x80d12501l, 0x81612601l, 0x11f02700l, + 0x16802800l, 0x86112901l, 0x87a12a01l, 0x17302b00l, + 0x84c12c01l, 0x14502d00l, 0x15e02e00l, 0x85712f01l, + 0x1b003000l, 0x8b913101l, 0x8a213201l, 0x1ab03300l, + 0x89413401l, 0x19d03500l, 0x18603600l, 0x88f13701l, + 0x8f813801l, 0x1f103900l, 0x1ea03a00l, 0x8e313b01l, + 0x1dc03c00l, 0x8d513d01l, 0x8ce13e01l, 0x1c703f00l, + 0xb4014001l, 0x24904100l, 0x25204200l, 0xb5b14301l, + 0x26404400l, 0xb6d14501l, 0xb7614601l, 0x27f04700l, + 0x20804800l, 0xb0114901l, 0xb1a14a01l, 0x21304b00l, + 0xb2c14c01l, 0x22504d00l, 0x23e04e00l, 0xb3714f01l, + 0x2d005000l, 0xbd915101l, 0xbc215201l, 0x2cb05300l, + 0xbf415401l, 0x2fd05500l, 0x2e605600l, 0xbef15701l, + 0xb9815801l, 0x29105900l, 0x28a05a00l, 0xb8315b01l, + 0x2bc05c00l, 0xbb515d01l, 0xbae15e01l, 0x2a705f00l, + 0x36006000l, 0xa6916101l, 0xa7216201l, 0x37b06300l, + 0xa4416401l, 0x34d06500l, 0x35606600l, 0xa5f16701l, + 0xa2816801l, 0x32106900l, 0x33a06a00l, 0xa3316b01l, + 0x30c06c00l, 0xa0516d01l, 0xa1e16e01l, 0x31706f00l, + 0xaf017001l, 0x3f907100l, 0x3e207200l, 0xaeb17301l, + 0x3d407400l, 0xadd17501l, 0xac617601l, 0x3cf07700l, + 0x3b807800l, 0xab117901l, 0xaaa17a01l, 0x3a307b00l, + 0xa9c17c01l, 0x39507d00l, 0x38e07e00l, 0xa8717f01l, + 0xd8018001l, 0x48908100l, 0x49208200l, 0xd9b18301l, + 0x4a408400l, 0xdad18501l, 0xdb618601l, 0x4bf08700l, + 0x4c808800l, 0xdc118901l, 0xdda18a01l, 0x4d308b00l, + 0xdec18c01l, 0x4e508d00l, 0x4fe08e00l, 0xdf718f01l, + 0x41009000l, 0xd1919101l, 0xd0219201l, 0x40b09300l, + 0xd3419401l, 0x43d09500l, 0x42609600l, 0xd2f19701l, + 0xd5819801l, 0x45109900l, 0x44a09a00l, 0xd4319b01l, + 0x47c09c00l, 0xd7519d01l, 0xd6e19e01l, 0x46709f00l, + 0x5a00a000l, 0xca91a101l, 0xcb21a201l, 0x5bb0a300l, + 0xc841a401l, 0x58d0a500l, 0x5960a600l, 0xc9f1a701l, + 0xce81a801l, 0x5e10a900l, 0x5fa0aa00l, 0xcf31ab01l, + 0x5cc0ac00l, 0xcc51ad01l, 0xcde1ae01l, 0x5d70af00l, + 0xc301b001l, 0x5390b100l, 0x5220b200l, 0xc2b1b301l, + 0x5140b400l, 0xc1d1b501l, 0xc061b601l, 0x50f0b700l, + 0x5780b800l, 0xc711b901l, 0xc6a1ba01l, 0x5630bb00l, + 0xc5c1bc01l, 0x5550bd00l, 0x54e0be00l, 0xc471bf01l, + 0x6c00c000l, 0xfc91c101l, 0xfd21c201l, 0x6db0c300l, + 0xfe41c401l, 0x6ed0c500l, 0x6f60c600l, 0xfff1c701l, + 0xf881c801l, 0x6810c900l, 0x69a0ca00l, 0xf931cb01l, + 0x6ac0cc00l, 0xfa51cd01l, 0xfbe1ce01l, 0x6b70cf00l, + 0xf501d001l, 0x6590d100l, 0x6420d200l, 0xf4b1d301l, + 0x6740d400l, 0xf7d1d501l, 0xf661d601l, 0x66f0d700l, + 0x6180d800l, 0xf111d901l, 0xf0a1da01l, 0x6030db00l, + 0xf3c1dc01l, 0x6350dd00l, 0x62e0de00l, 0xf271df01l, + 0xee01e001l, 0x7e90e100l, 0x7f20e200l, 0xefb1e301l, + 0x7c40e400l, 0xecd1e501l, 0xed61e601l, 0x7df0e700l, + 0x7a80e800l, 0xea11e901l, 0xeba1ea01l, 0x7b30eb00l, + 0xe8c1ec01l, 0x7850ed00l, 0x79e0ee00l, 0xe971ef01l, + 0x7700f000l, 0xe791f101l, 0xe621f201l, 0x76b0f300l, + 0xe541f401l, 0x75d0f500l, 0x7460f600l, 0xe4f1f701l, + 0xe381f801l, 0x7310f900l, 0x72a0fa00l, 0xe231fb01l, + 0x71c0fc00l, 0xe151fd01l, 0xe0e1fe01l, 0x7070ff00l +}; + +DWORD hash_crc(const CRect& r, int pitch, BYTE* p) +{ + if(r.Width() == 0) {ASSERT(0); return 0;} + + DWORD hash = 0xffffffff; + + for(int j = r.top; j < r.bottom; j++, p += pitch) + { + for(int i = r.left, x = 0; i < r.right; i++, x += 4) + { + hash = s_crctable[(hash ^ p[x+0]) & 0xff] ^ (hash >> 8); + hash = s_crctable[(hash ^ p[x+1]) & 0xff] ^ (hash >> 8); + hash = s_crctable[(hash ^ p[x+2]) & 0xff] ^ (hash >> 8); + hash = s_crctable[(hash ^ p[x+3]) & 0xff] ^ (hash >> 8); + } + } + + return hash; +} + +#define MOD_ADLER 65521 + +DWORD hash_adler(const CRect& r, int pitch, BYTE* p) +{ + if(r.Width() == 0) {ASSERT(0); return 0;} + + DWORD a = 1, b = 0; + + for(int j = r.top; j < r.bottom; j++, p += pitch) + { + for(int i = r.left, x = 0; i < r.right; i++, x += 4) + { + a += p[x+0]; b += a; + a += p[x+1]; b += a; + a += p[x+2]; b += a; + a += p[x+3]; b += a; + } + + a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + } + + // a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); + if(a >= MOD_ADLER) a -= MOD_ADLER; + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + if(b >= MOD_ADLER) b -= MOD_ADLER; + + return b << 16 | a; +} + +DWORD hash_checksum(const CRect& r, int pitch, BYTE* p) +{ + if(r.Width() == 0) {ASSERT(0); return 0;} + + DWORD hash = 0; + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 + if(r.Width() >= 4 && !((DWORD_PTR)p & 0xf) && !(pitch & 0xf)) + { + __m128i hash128 = _mm_setzero_si128(); + for(int j = r.top; j < r.bottom; j++, p += pitch) + { + hash128 = _mm_add_epi32(hash128, _mm_set1_epi32(j)); + for(int i = r.left, x = 0; i < r.right; i += 4, x++) + { + hash128 = _mm_shuffle_epi32(hash128, 0x93); + ////hash128 = _mm_shufflelo_epi16(hash128, 0x93); + //hash128 = _mm_shufflehi_epi16(hash128, 0x93); + hash128 = _mm_add_epi32(hash128, _mm_load_si128(&((__m128i*)p)[x])); + } + } + hash128 = _mm_add_epi32(hash128, _mm_srli_si128(hash128, 8)); + hash128 = _mm_add_epi32(hash128, _mm_srli_si128(hash128, 4)); + hash += _mm_cvtsi128_si32(hash128); + } + else +#endif + { + for(int j = r.top; j < r.bottom; j++, p += pitch) + { + hash += j; + for(int i = r.left, x = 0; i < r.right; i++, x++) + { + hash += ((DWORD*)p)[x]; + } + } + } + + return hash; +} \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSHash.h b/plugins/gs/gsdx9/GSHash.h new file mode 100644 index 0000000000..48a6adc7d3 --- /dev/null +++ b/plugins/gs/gsdx9/GSHash.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +extern DWORD hash_crc(const CRect& r, int pitch, BYTE* p); +extern DWORD hash_adler(const CRect& r, int pitch, BYTE* p); +extern DWORD hash_checksum(const CRect& r, int pitch, BYTE* p); diff --git a/plugins/gs/gsdx9/GSLocalMemory.cpp b/plugins/gs/gsdx9/GSLocalMemory.cpp new file mode 100644 index 0000000000..8d4e2bb6d5 --- /dev/null +++ b/plugins/gs/gsdx9/GSLocalMemory.cpp @@ -0,0 +1,2859 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * Special Notes: + * + * Based on Page.c from GSSoft + * Copyright (C) 2002-2004 GSsoft Team + * + */ + +#include "StdAfx.h" +#include "GSLocalMemory.h" +#include "x86.h" + +// + +static class cdscd +{ + CString toBin(UINT64 n, int bits) + { + CString str; + while(bits-- > 0) str += n&(1i64<= w && (r).Height() >= h && !((r).left&(w-1)) && !((r).top&(h-1)) && !((r).right&(w-1)) && !((r).bottom&(h-1))); \ + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 +#define BLOCK_PREFETCH(mem) \ + _mm_prefetch(&mem[16*0], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*2], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*4], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*6], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*8], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*10], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*12], _MM_HINT_T0); \ + _mm_prefetch(&mem[16*14], _MM_HINT_T0); \ + +#define BLOCK_PREFETCH_32(x, y, w) {const char* next = (const char*)&m_vm32[blockAddress32(x + (w), y, TEX0.TBP0, TEX0.TBW)]; BLOCK_PREFETCH(next);} +#define BLOCK_PREFETCH_16(x, y, w) {const char* next = (const char*)&m_vm16[blockAddress16(x + (w), y, TEX0.TBP0, TEX0.TBW)]; BLOCK_PREFETCH(next);} +#define BLOCK_PREFETCH_16S(x, y, w) {const char* next = (const char*)&m_vm16[blockAddress16S(x + (w), y, TEX0.TBP0, TEX0.TBW)]; BLOCK_PREFETCH(next);} +#define BLOCK_PREFETCH_8(x, y, w) {const char* next = (const char*)&m_vm8[blockAddress8(x + (w), y, TEX0.TBP0, TEX0.TBW)]; BLOCK_PREFETCH(next);} +#define BLOCK_PREFETCH_4(x, y, w) {const char* next = (const char*)&m_vm8[blockAddress4(x + (w), y, TEX0.TBP0, TEX0.TBW)>>1]; BLOCK_PREFETCH(next);} +#else +#define BLOCK_PREFETCH_32(x, y, w) +#define BLOCK_PREFETCH_16(x, y, w) +#define BLOCK_PREFETCH_16S(x, y, w) +#define BLOCK_PREFETCH_8(x, y, w) +#define BLOCK_PREFETCH_4(x, y, w) +#endif + +#define FOREACH_BLOCK_START(r, w, h, t) \ + for(int y = (r).top; y < (r).bottom; y += (h)) \ + { ASSERT_BLOCK(r, w, h); \ + BYTE* ptr = dst + (y-(r).top)*dstpitch; \ + for(int x = (r).left; x < (r).right; x += (w)) \ + { \ + BLOCK_PREFETCH_##t##(x + (w), y, w) \ + +#define FOREACH_BLOCK_END }} + +// + +DWORD GSLocalMemory::pageOffset32[32][32][64]; +DWORD GSLocalMemory::pageOffset32Z[32][32][64]; +DWORD GSLocalMemory::pageOffset16[32][64][64]; +DWORD GSLocalMemory::pageOffset16S[32][64][64]; +DWORD GSLocalMemory::pageOffset16Z[32][64][64]; +DWORD GSLocalMemory::pageOffset16SZ[32][64][64]; +DWORD GSLocalMemory::pageOffset8[32][64][128]; +DWORD GSLocalMemory::pageOffset4[32][128][128]; + +int GSLocalMemory::rowOffset32[2048]; +int GSLocalMemory::rowOffset32Z[2048]; +int GSLocalMemory::rowOffset16[2048]; +int GSLocalMemory::rowOffset16S[2048]; +int GSLocalMemory::rowOffset16Z[2048]; +int GSLocalMemory::rowOffset16SZ[2048]; +int GSLocalMemory::rowOffset8[2][2048]; +int GSLocalMemory::rowOffset4[2][2048]; + +// + +DWORD GSLocalMemory::m_xtbl[1024]; +DWORD GSLocalMemory::m_ytbl[1024]; + +// + +GSLocalMemory::psmtbl_t GSLocalMemory::m_psmtbl[64]; + +// + +GSLocalMemory::GSLocalMemory() + : m_fCLUTMayBeDirty(true) +{ + int len = 1024*1024*4*2; // *2 for safety... + + m_vm8 = (BYTE*)_aligned_malloc(len, 16); + memset(m_vm8, 0, len); + + m_pCLUT = (WORD*)_aligned_malloc(256*2*sizeof(WORD)*2, 16); + m_pCLUT32 = (DWORD*)_aligned_malloc(256*sizeof(DWORD), 16); + m_pCLUT64 = (UINT64*)_aligned_malloc(256*sizeof(UINT64), 16); + + for(int bp = 0; bp < 32; bp++) + { + for(int y = 0; y < 32; y++) for(int x = 0; x < 64; x++) + { + pageOffset32[bp][y][x] = pixelAddressOrg32(x, y, bp, 0); + pageOffset32Z[bp][y][x] = pixelAddressOrg32Z(x, y, bp, 0); + } + + for(int y = 0; y < 64; y++) for(int x = 0; x < 64; x++) + { + pageOffset16[bp][y][x] = pixelAddressOrg16(x, y, bp, 0); + pageOffset16S[bp][y][x] = pixelAddressOrg16S(x, y, bp, 0); + pageOffset16Z[bp][y][x] = pixelAddressOrg16Z(x, y, bp, 0); + pageOffset16SZ[bp][y][x] = pixelAddressOrg16SZ(x, y, bp, 0); + } + + for(int y = 0; y < 64; y++) for(int x = 0; x < 128; x++) + { + pageOffset8[bp][y][x] = pixelAddressOrg8(x, y, bp, 0); + } + + for(int y = 0; y < 128; y++) for(int x = 0; x < 128; x++) + { + pageOffset4[bp][y][x] = pixelAddressOrg4(x, y, bp, 0); + } + } + + { + for(int x = 0; x < countof(rowOffset32); x++) + rowOffset32[x] = (int)pixelAddress32(x, 0, 0, 32) - (int)pixelAddress32(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset32Z); x++) + rowOffset32Z[x] = (int)pixelAddress32Z(x, 0, 0, 32) - (int)pixelAddress32Z(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset16); x++) + rowOffset16[x] = (int)pixelAddress16(x, 0, 0, 32) - (int)pixelAddress16(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset16S); x++) + rowOffset16S[x] = (int)pixelAddress16S(x, 0, 0, 32) - (int)pixelAddress16S(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset16Z); x++) + rowOffset16Z[x] = (int)pixelAddress16Z(x, 0, 0, 32) - (int)pixelAddress16Z(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset16SZ); x++) + rowOffset16SZ[x] = (int)pixelAddress16SZ(x, 0, 0, 32) - (int)pixelAddress16SZ(0, 0, 0, 32); + + for(int x = 0; x < countof(rowOffset8[0]); x++) + rowOffset8[0][x] = (int)pixelAddress8(x, 0, 0, 32) - (int)pixelAddress8(0, 0, 0, 32), + rowOffset8[1][x] = (int)pixelAddress8(x, 2, 0, 32) - (int)pixelAddress8(0, 2, 0, 32); + + for(int x = 0; x < countof(rowOffset4[0]); x++) + rowOffset4[0][x] = (int)pixelAddress4(x, 0, 0, 32) - (int)pixelAddress4(0, 0, 0, 32), + rowOffset4[1][x] = (int)pixelAddress4(x, 2, 0, 32) - (int)pixelAddress4(0, 2, 0, 32); + } + + for(int i = 0; i < countof(m_psmtbl); i++) + { + m_psmtbl[i].pa = &GSLocalMemory::pixelAddress32; + m_psmtbl[i].ba = &GSLocalMemory::blockAddress32; + m_psmtbl[i].pga = &GSLocalMemory::pageAddress32; + m_psmtbl[i].rp = &GSLocalMemory::readPixel32; + m_psmtbl[i].rpa = &GSLocalMemory::readPixel32; + m_psmtbl[i].wp = &GSLocalMemory::writePixel32; + m_psmtbl[i].wpa = &GSLocalMemory::writePixel32; + m_psmtbl[i].rt = m_psmtbl[i].rtNP = m_psmtbl[i].rtP = &GSLocalMemory::readTexel32; + m_psmtbl[i].rta = &GSLocalMemory::readTexel32; + m_psmtbl[i].wfa = &GSLocalMemory::writePixel32; + m_psmtbl[i].st = &GSLocalMemory::SwizzleTexture32; + m_psmtbl[i].ust = m_psmtbl[i].ustP = m_psmtbl[i].ustNP = &GSLocalMemory::unSwizzleTexture32; + m_psmtbl[i].bpp = m_psmtbl[i].trbpp = 32; + m_psmtbl[i].pal = 0; + m_psmtbl[i].bs = CSize(8, 8); + for(int j = 0; j < 8; j++) m_psmtbl[i].rowOffset[j] = rowOffset32; + } + + m_psmtbl[PSM_PSMCT16].pa = &GSLocalMemory::pixelAddress16; + m_psmtbl[PSM_PSMCT16S].pa = &GSLocalMemory::pixelAddress16S; + m_psmtbl[PSM_PSMT8].pa = &GSLocalMemory::pixelAddress8; + m_psmtbl[PSM_PSMT4].pa = &GSLocalMemory::pixelAddress4; + m_psmtbl[PSM_PSMZ32].pa = &GSLocalMemory::pixelAddress32Z; + m_psmtbl[PSM_PSMZ24].pa = &GSLocalMemory::pixelAddress32Z; + m_psmtbl[PSM_PSMZ16].pa = &GSLocalMemory::pixelAddress16Z; + m_psmtbl[PSM_PSMZ16S].pa = &GSLocalMemory::pixelAddress16SZ; + + m_psmtbl[PSM_PSMCT16].ba = &GSLocalMemory::blockAddress16; + m_psmtbl[PSM_PSMCT16S].ba = &GSLocalMemory::blockAddress16S; + m_psmtbl[PSM_PSMT8].ba = &GSLocalMemory::blockAddress8; + m_psmtbl[PSM_PSMT4].ba = &GSLocalMemory::blockAddress4; + m_psmtbl[PSM_PSMZ32].ba = &GSLocalMemory::blockAddress32Z; + m_psmtbl[PSM_PSMZ24].ba = &GSLocalMemory::blockAddress32Z; + m_psmtbl[PSM_PSMZ16].ba = &GSLocalMemory::blockAddress16Z; + m_psmtbl[PSM_PSMZ16S].ba = &GSLocalMemory::blockAddress16SZ; + + m_psmtbl[PSM_PSMCT16].pga = &GSLocalMemory::pageAddress16; + m_psmtbl[PSM_PSMCT16S].pga = &GSLocalMemory::pageAddress16; + m_psmtbl[PSM_PSMZ16].pga = &GSLocalMemory::pageAddress16; + m_psmtbl[PSM_PSMZ16S].pga = &GSLocalMemory::pageAddress16; + m_psmtbl[PSM_PSMT8].pga = &GSLocalMemory::pageAddress8; + m_psmtbl[PSM_PSMT4].pga = &GSLocalMemory::pageAddress4; + + m_psmtbl[PSM_PSMCT24].rp = &GSLocalMemory::readPixel24; + m_psmtbl[PSM_PSMCT16].rp = &GSLocalMemory::readPixel16; + m_psmtbl[PSM_PSMCT16S].rp = &GSLocalMemory::readPixel16S; + m_psmtbl[PSM_PSMT8].rp = &GSLocalMemory::readPixel8; + m_psmtbl[PSM_PSMT4].rp = &GSLocalMemory::readPixel4; + m_psmtbl[PSM_PSMT8H].rp = &GSLocalMemory::readPixel8H; + m_psmtbl[PSM_PSMT4HL].rp = &GSLocalMemory::readPixel4HL; + m_psmtbl[PSM_PSMT4HH].rp = &GSLocalMemory::readPixel4HH; + m_psmtbl[PSM_PSMZ32].rp = &GSLocalMemory::readPixel32Z; + m_psmtbl[PSM_PSMZ24].rp = &GSLocalMemory::readPixel24Z; + m_psmtbl[PSM_PSMZ16].rp = &GSLocalMemory::readPixel16Z; + m_psmtbl[PSM_PSMZ16S].rp = &GSLocalMemory::readPixel16SZ; + + m_psmtbl[PSM_PSMCT24].rpa = &GSLocalMemory::readPixel24; + m_psmtbl[PSM_PSMCT16].rpa = &GSLocalMemory::readPixel16; + m_psmtbl[PSM_PSMCT16S].rpa = &GSLocalMemory::readPixel16S; + m_psmtbl[PSM_PSMT8].rpa = &GSLocalMemory::readPixel8; + m_psmtbl[PSM_PSMT4].rpa = &GSLocalMemory::readPixel4; + m_psmtbl[PSM_PSMT8H].rpa = &GSLocalMemory::readPixel8H; + m_psmtbl[PSM_PSMT4HL].rpa = &GSLocalMemory::readPixel4HL; + m_psmtbl[PSM_PSMT4HH].rpa = &GSLocalMemory::readPixel4HH; + m_psmtbl[PSM_PSMZ32].rpa = &GSLocalMemory::readPixel32Z; + m_psmtbl[PSM_PSMZ24].rpa = &GSLocalMemory::readPixel24Z; + m_psmtbl[PSM_PSMZ16].rpa = &GSLocalMemory::readPixel16Z; + m_psmtbl[PSM_PSMZ16S].rpa = &GSLocalMemory::readPixel16SZ; + + m_psmtbl[PSM_PSMCT32].wp = &GSLocalMemory::writePixel32; + m_psmtbl[PSM_PSMCT24].wp = &GSLocalMemory::writePixel24; + m_psmtbl[PSM_PSMCT16].wp = &GSLocalMemory::writePixel16; + m_psmtbl[PSM_PSMCT16S].wp = &GSLocalMemory::writePixel16S; + m_psmtbl[PSM_PSMT8].wp = &GSLocalMemory::writePixel8; + m_psmtbl[PSM_PSMT4].wp = &GSLocalMemory::writePixel4; + m_psmtbl[PSM_PSMT8H].wp = &GSLocalMemory::writePixel8H; + m_psmtbl[PSM_PSMT4HL].wp = &GSLocalMemory::writePixel4HL; + m_psmtbl[PSM_PSMT4HH].wp = &GSLocalMemory::writePixel4HH; + m_psmtbl[PSM_PSMZ32].wp = &GSLocalMemory::writePixel32Z; + m_psmtbl[PSM_PSMZ24].wp = &GSLocalMemory::writePixel24Z; + m_psmtbl[PSM_PSMZ16].wp = &GSLocalMemory::writePixel16Z; + m_psmtbl[PSM_PSMZ16S].wp = &GSLocalMemory::writePixel16SZ; + + m_psmtbl[PSM_PSMCT32].wpa = &GSLocalMemory::writePixel32; + m_psmtbl[PSM_PSMCT24].wpa = &GSLocalMemory::writePixel24; + m_psmtbl[PSM_PSMCT16].wpa = &GSLocalMemory::writePixel16; + m_psmtbl[PSM_PSMCT16S].wpa = &GSLocalMemory::writePixel16S; + m_psmtbl[PSM_PSMT8].wpa = &GSLocalMemory::writePixel8; + m_psmtbl[PSM_PSMT4].wpa = &GSLocalMemory::writePixel4; + m_psmtbl[PSM_PSMT8H].wpa = &GSLocalMemory::writePixel8H; + m_psmtbl[PSM_PSMT4HL].wpa = &GSLocalMemory::writePixel4HL; + m_psmtbl[PSM_PSMT4HH].wpa = &GSLocalMemory::writePixel4HH; + m_psmtbl[PSM_PSMZ32].wpa = &GSLocalMemory::writePixel32Z; + m_psmtbl[PSM_PSMZ24].wpa = &GSLocalMemory::writePixel24Z; + m_psmtbl[PSM_PSMZ16].wpa = &GSLocalMemory::writePixel16Z; + m_psmtbl[PSM_PSMZ16S].wpa = &GSLocalMemory::writePixel16SZ; + + m_psmtbl[PSM_PSMCT24].rt = &GSLocalMemory::readTexel24; + m_psmtbl[PSM_PSMCT16].rt = &GSLocalMemory::readTexel16; + m_psmtbl[PSM_PSMCT16S].rt = &GSLocalMemory::readTexel16S; + m_psmtbl[PSM_PSMT8].rt = &GSLocalMemory::readTexel8; + m_psmtbl[PSM_PSMT4].rt = &GSLocalMemory::readTexel4; + m_psmtbl[PSM_PSMT8H].rt = &GSLocalMemory::readTexel8H; + m_psmtbl[PSM_PSMT4HL].rt = &GSLocalMemory::readTexel4HL; + m_psmtbl[PSM_PSMT4HH].rt = &GSLocalMemory::readTexel4HH; + + m_psmtbl[PSM_PSMCT24].rta = &GSLocalMemory::readTexel24; + m_psmtbl[PSM_PSMCT16].rta = &GSLocalMemory::readTexel16; + m_psmtbl[PSM_PSMCT16S].rta = &GSLocalMemory::readTexel16S; + m_psmtbl[PSM_PSMT8].rta = &GSLocalMemory::readTexel8; + m_psmtbl[PSM_PSMT4].rta = &GSLocalMemory::readTexel4; + m_psmtbl[PSM_PSMT8H].rta = &GSLocalMemory::readTexel8H; + m_psmtbl[PSM_PSMT4HL].rta = &GSLocalMemory::readTexel4HL; + m_psmtbl[PSM_PSMT4HH].rta = &GSLocalMemory::readTexel4HH; + + m_psmtbl[PSM_PSMCT24].wfa = &GSLocalMemory::writePixel24; + m_psmtbl[PSM_PSMCT16].wfa = &GSLocalMemory::writeFrame16; + m_psmtbl[PSM_PSMCT16S].wfa = &GSLocalMemory::writeFrame16S; + + m_psmtbl[PSM_PSMCT16].rtP = &GSLocalMemory::readTexel16P; + m_psmtbl[PSM_PSMCT16S].rtP = &GSLocalMemory::readTexel16SP; + m_psmtbl[PSM_PSMT8].rtP = &GSLocalMemory::readTexel8P; + m_psmtbl[PSM_PSMT4].rtP = &GSLocalMemory::readTexel4P; + m_psmtbl[PSM_PSMT8H].rtP = &GSLocalMemory::readTexel8HP; + m_psmtbl[PSM_PSMT4HL].rtP = &GSLocalMemory::readTexel4HLP; + m_psmtbl[PSM_PSMT4HH].rtP = &GSLocalMemory::readTexel4HHP; + + m_psmtbl[PSM_PSMCT16].rtNP = &GSLocalMemory::readTexel16P; + m_psmtbl[PSM_PSMCT16S].rtNP = &GSLocalMemory::readTexel16SP; + m_psmtbl[PSM_PSMT8].rtNP = &GSLocalMemory::readTexel8; + m_psmtbl[PSM_PSMT4].rtNP = &GSLocalMemory::readTexel4; + m_psmtbl[PSM_PSMT8H].rtNP = &GSLocalMemory::readTexel8H; + m_psmtbl[PSM_PSMT4HL].rtNP = &GSLocalMemory::readTexel4HL; + m_psmtbl[PSM_PSMT4HH].rtNP = &GSLocalMemory::readTexel4HH; + + m_psmtbl[PSM_PSMCT24].st = &GSLocalMemory::SwizzleTexture24; + m_psmtbl[PSM_PSMCT16].st = &GSLocalMemory::SwizzleTexture16; + m_psmtbl[PSM_PSMCT16S].st = &GSLocalMemory::SwizzleTexture16S; + m_psmtbl[PSM_PSMT8].st = &GSLocalMemory::SwizzleTexture8; + m_psmtbl[PSM_PSMT4].st = &GSLocalMemory::SwizzleTexture4; + m_psmtbl[PSM_PSMT8H].st = &GSLocalMemory::SwizzleTexture8H; + m_psmtbl[PSM_PSMT4HL].st = &GSLocalMemory::SwizzleTexture4HL; + m_psmtbl[PSM_PSMT4HH].st = &GSLocalMemory::SwizzleTexture4HH; + + m_psmtbl[PSM_PSMCT24].ust = &GSLocalMemory::unSwizzleTexture24; + m_psmtbl[PSM_PSMCT16].ust = &GSLocalMemory::unSwizzleTexture16; + m_psmtbl[PSM_PSMCT16S].ust = &GSLocalMemory::unSwizzleTexture16S; + m_psmtbl[PSM_PSMT8].ust = &GSLocalMemory::unSwizzleTexture8; + m_psmtbl[PSM_PSMT4].ust = &GSLocalMemory::unSwizzleTexture4; + m_psmtbl[PSM_PSMT8H].ust = &GSLocalMemory::unSwizzleTexture8H; + m_psmtbl[PSM_PSMT4HL].ust = &GSLocalMemory::unSwizzleTexture4HL; + m_psmtbl[PSM_PSMT4HH].ust = &GSLocalMemory::unSwizzleTexture4HH; + + m_psmtbl[PSM_PSMCT16].ustP = &GSLocalMemory::unSwizzleTexture16P; + m_psmtbl[PSM_PSMCT16S].ustP = &GSLocalMemory::unSwizzleTexture16SP; + m_psmtbl[PSM_PSMT8].ustP = &GSLocalMemory::unSwizzleTexture8P; + m_psmtbl[PSM_PSMT4].ustP = &GSLocalMemory::unSwizzleTexture4P; + m_psmtbl[PSM_PSMT8H].ustP = &GSLocalMemory::unSwizzleTexture8HP; + m_psmtbl[PSM_PSMT4HL].ustP = &GSLocalMemory::unSwizzleTexture4HLP; + m_psmtbl[PSM_PSMT4HH].ustP = &GSLocalMemory::unSwizzleTexture4HHP; + + m_psmtbl[PSM_PSMCT16].ustNP = &GSLocalMemory::unSwizzleTexture16P; + m_psmtbl[PSM_PSMCT16S].ustNP = &GSLocalMemory::unSwizzleTexture16SP; + m_psmtbl[PSM_PSMT8].ustNP = &GSLocalMemory::unSwizzleTexture8NP; + m_psmtbl[PSM_PSMT4].ustNP = &GSLocalMemory::unSwizzleTexture4NP; + m_psmtbl[PSM_PSMT8H].ustNP = &GSLocalMemory::unSwizzleTexture8HNP; + m_psmtbl[PSM_PSMT4HL].ustNP = &GSLocalMemory::unSwizzleTexture4HLNP; + m_psmtbl[PSM_PSMT4HH].ustNP = &GSLocalMemory::unSwizzleTexture4HHNP; + + m_psmtbl[PSM_PSMT8].pal = m_psmtbl[PSM_PSMT8H].pal = 256; + m_psmtbl[PSM_PSMT4].pal = m_psmtbl[PSM_PSMT4HL].pal = m_psmtbl[PSM_PSMT4HH].pal = 16; + + m_psmtbl[PSM_PSMCT16].bpp = m_psmtbl[PSM_PSMCT16S].bpp = 16; + m_psmtbl[PSM_PSMT8].bpp = 8; + m_psmtbl[PSM_PSMT4].bpp = 4; + m_psmtbl[PSM_PSMZ16].bpp = m_psmtbl[PSM_PSMZ16S].bpp = 16; + + m_psmtbl[PSM_PSMCT24].trbpp = 24; + m_psmtbl[PSM_PSMCT16].trbpp = m_psmtbl[PSM_PSMCT16S].trbpp = 16; + m_psmtbl[PSM_PSMT8].trbpp = m_psmtbl[PSM_PSMT8H].trbpp = 8; + m_psmtbl[PSM_PSMT4].trbpp = m_psmtbl[PSM_PSMT4HL].trbpp = m_psmtbl[PSM_PSMT4HH].trbpp = 4; + m_psmtbl[PSM_PSMZ24].trbpp = 24; + m_psmtbl[PSM_PSMZ16].trbpp = m_psmtbl[PSM_PSMZ16S].trbpp = 16; + + m_psmtbl[PSM_PSMCT16].bs = m_psmtbl[PSM_PSMCT16S].bs = CSize(16, 8); + m_psmtbl[PSM_PSMT8].bs = CSize(16, 16); + m_psmtbl[PSM_PSMT4].bs = CSize(32, 32); + m_psmtbl[PSM_PSMZ16].bs = m_psmtbl[PSM_PSMZ16S].bs = CSize(16, 8); + + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMCT16].rowOffset[i] = rowOffset16; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMCT16S].rowOffset[i] = rowOffset16S; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMT8].rowOffset[i] = rowOffset8[((i+2)>>2)&1]; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMT4].rowOffset[i] = rowOffset4[((i+2)>>2)&1]; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMZ32].rowOffset[i] = rowOffset32Z; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMZ24].rowOffset[i] = rowOffset32Z; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMZ16].rowOffset[i] = rowOffset16Z; + for(int i = 0; i < 8; i++) m_psmtbl[PSM_PSMZ16S].rowOffset[i] = rowOffset16SZ; + + +#ifdef _OPENMP + // need real cpus, with HT it is only going to be slower now + omp_set_num_threads(omp_get_num_procs()); +#endif + +/* +// return; +// omp_set_num_threads(2); +// + { + int tmpsize = 1024*1024*2; + BYTE* tmp1 = new BYTE[tmpsize]; + BYTE* tmp2 = new BYTE[tmpsize]; + + for(int i = 0; i < 1024*1024; i++) + ((DWORD*)GetVM())[i] = rand()*0x12345678; + + GIFRegTEX0 TEX0; + TEX0.TBP0 = 0; + TEX0.TBW = 16; + GIFRegTEXA TEXA; + TEXA.AEM = 0; // 1 + + __declspec(align(32)) static DWORD dst[1024*1024]; + + int nthreads[] = {1,2,4,8}; + for(int j = 0; j < countof(nthreads); j++) + { + omp_set_num_threads(nthreads[j]); + + clock_t start = clock(); + + for(int i = 0; i < 1000; i++) + { + unSwizzleTexture32(CRect(0,0,1024,1024), (BYTE*)dst, 1024*4, TEX0, TEXA); + // for(int k = 0; k < tmpsize; k++) tmp2[k] = tmp1[k]; + } + + clock_t diff = clock() - start; + + CString str; + str.Format(_T("%d threads: %d ms"), nthreads[j], diff); + AfxMessageBox(str); + } + + omp_set_num_threads(2); + + delete [] tmp1; + delete [] tmp2; + } +*/ +} + +GSLocalMemory::~GSLocalMemory() +{ + _aligned_free(m_vm8); + _aligned_free(m_pCLUT); + _aligned_free(m_pCLUT32); + _aligned_free(m_pCLUT64); +} + +//////////////////// + +void GSLocalMemory::RoundDown(CSize& s, CSize bs) +{ + s.cx &= ~(bs.cx-1); + s.cy &= ~(bs.cy-1); +} + +void GSLocalMemory::RoundUp(CSize& s, CSize bs) +{ + s.cx = (s.cx + (bs.cx-1)) & ~(bs.cx-1); + s.cy = (s.cy + (bs.cy-1)) & ~(bs.cy-1); +} + +//////////////////// + +DWORD __fastcall GSLocalMemory::pageAddress32(int x, int y, DWORD bp, DWORD bw) +{ + return ((bp >> 5) + (y >> 5) * bw + (x >> 6)) << 11; +} + +DWORD __fastcall GSLocalMemory::pageAddress16(int x, int y, DWORD bp, DWORD bw) +{ + return ((bp >> 5) + (y >> 6) * bw + (x >> 6)) << 12; +} + +DWORD __fastcall GSLocalMemory::pageAddress8(int x, int y, DWORD bp, DWORD bw) +{ + return ((bp >> 5) + (y >> 6) * ((bw+1)>>1) + (x >> 7)) << 13; +} + +DWORD __fastcall GSLocalMemory::pageAddress4(int x, int y, DWORD bp, DWORD bw) +{ + return ((bp >> 5) + (y >> 7) * ((bw+1)>>1) + (x >> 7)) << 14; +} + +//////////////////// + +DWORD __fastcall GSLocalMemory::blockAddress32(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; + return (page + block) << 6; +} + +DWORD __fastcall GSLocalMemory::blockAddress16(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; +} + +DWORD __fastcall GSLocalMemory::blockAddress16S(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; +} + +DWORD __fastcall GSLocalMemory::blockAddress8(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 1) & ~0x1f) * ((bw+1)>>1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; + return (page + block) << 8; +} + +DWORD __fastcall GSLocalMemory::blockAddress4(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 2) & ~0x1f) * ((bw+1)>>1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; + return (page + block) << 9; +} + +DWORD __fastcall GSLocalMemory::blockAddress32Z(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; + return (page + block) << 6; +} + +DWORD __fastcall GSLocalMemory::blockAddress16Z(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; +} + +DWORD __fastcall GSLocalMemory::blockAddress16SZ(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; +} + +//////////////////// + +DWORD __fastcall GSLocalMemory::pixelAddressOrg32(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable32[(y >> 3) & 3][(x >> 3) & 7]; +// DWORD word = (((page << 5) + block) << 6) + columnTable32[y & 7][x & 7]; + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; + DWORD word = ((page + block) << 6) + columnTable32[y & 7][x & 7]; + ASSERT(word < 1024*1024); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg16(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable16[(y >> 3) & 7][(x >> 4) & 3]; +// DWORD word = (((page << 5) + block) << 7) + columnTable16[y & 7][x & 15]; + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg16S(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; +// DWORD word = (((page << 5) + block) << 7) + columnTable16[y & 7][x & 15]; + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg8(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 6) * ((bw+1)>>1) + (x >> 7); +// DWORD block = (bp & 0x1f) + blockTable8[(y >> 4) & 3][(x >> 4) & 7]; +// DWORD word = (((page << 5) + block) << 8) + columnTable8[y & 15][x & 15]; + DWORD page = bp + ((y >> 1) & ~0x1f) * ((bw+1)>>1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; + DWORD word = ((page + block) << 8) + columnTable8[y & 15][x & 15]; +// ASSERT(word < 1024*1024*4); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg4(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 7) * ((bw+1)>>1) + (x >> 7); +// DWORD block = (bp & 0x1f) + blockTable4[(y >> 4) & 7][(x >> 5) & 3]; +// DWORD word = (((page << 5) + block) << 9) + columnTable4[y & 15][x & 31]; + DWORD page = bp + ((y >> 2) & ~0x1f) * ((bw+1)>>1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; + DWORD word = ((page + block) << 9) + columnTable4[y & 15][x & 31]; + ASSERT(word < 1024*1024*8); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg32Z(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; +// DWORD word = (((page << 5) + block) << 6) + ((y & 7) << 3) + (x & 7); + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; + DWORD word = ((page + block) << 6) + ((y & 7) << 3) + (x & 7); + ASSERT(word < 1024*1024); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg16Z(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; +// DWORD word = (((page << 5) + block) << 7) + ((y & 7) << 4) + (x & 15); + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + ((y & 7) << 4) + (x & 15); + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddressOrg16SZ(int x, int y, DWORD bp, DWORD bw) +{ +// DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); +// DWORD block = (bp & 0x1f) + blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; +// DWORD word = (((page << 5) + block) << 7) + ((y & 7) << 4) + (x & 15); + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + ((y & 7) << 4) + (x & 15); + ASSERT(word < 1024*1024*2); + return word; +} + +//////////////////// + +DWORD __fastcall GSLocalMemory::pixelAddress32(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); + DWORD word = (page << 11) + pageOffset32[bp & 0x1f][y & 0x1f][x & 0x3f]; + ASSERT(word < 1024*1024); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress16(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16[bp & 0x1f][y & 0x3f][x & 0x3f]; + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress16S(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16S[bp & 0x1f][y & 0x3f][x & 0x3f]; + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress8(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 6) * ((bw+1)>>1) + (x >> 7); + DWORD word = (page << 13) + pageOffset8[bp & 0x1f][y & 0x3f][x & 0x7f]; + ASSERT(word < 1024*1024*4); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress4(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 7) * ((bw+1)>>1) + (x >> 7); + DWORD word = (page << 14) + pageOffset4[bp & 0x1f][y & 0x7f][x & 0x7f]; + ASSERT(word < 1024*1024*8); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress32Z(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); + DWORD word = (page << 11) + pageOffset32Z[bp & 0x1f][y & 0x1f][x & 0x3f]; + ASSERT(word < 1024*1024); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress16Z(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16Z[bp & 0x1f][y & 0x3f][x & 0x3f]; + ASSERT(word < 1024*1024*2); + return word; +} + +DWORD __fastcall GSLocalMemory::pixelAddress16SZ(int x, int y, DWORD bp, DWORD bw) +{ + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16SZ[bp & 0x1f][y & 0x3f][x & 0x3f]; + ASSERT(word < 1024*1024*2); + return word; +} + +//////////////////// + +void GSLocalMemory::writePixel32(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32(x, y, bp, bw); + m_vm32[addr] = c; +} + +void GSLocalMemory::writePixel24(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32(x, y, bp, bw); + m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); +} + +void GSLocalMemory::writePixel16(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress16(x, y, bp, bw); + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel16S(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress16S(x, y, bp, bw); + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel8(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress8(x, y, bp, bw); + m_vm8[addr] = (BYTE)c; +} + +void GSLocalMemory::writePixel8H(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32(x, y, bp, bw); + m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24); +} + +void GSLocalMemory::writePixel4(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress4(x, y, bp, bw); + int shift = (addr&1) << 2; addr >>= 1; + m_vm8[addr] = (BYTE)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift)); +} + +void GSLocalMemory::writePixel4HL(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32(x, y, bp, bw); + m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24); +} + +void GSLocalMemory::writePixel4HH(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32(x, y, bp, bw); + m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28); +} + +void GSLocalMemory::writePixel32Z(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32Z(x, y, bp, bw); + m_vm32[addr] = c; +} + +void GSLocalMemory::writePixel24Z(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress32Z(x, y, bp, bw); + m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); +} + +void GSLocalMemory::writePixel16Z(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress16Z(x, y, bp, bw); + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress16SZ(x, y, bp, bw); + m_vm16[addr] = (WORD)c; +} + +//////////////////// + +void GSLocalMemory::writeFrame16(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + c = ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f); + writePixel16(x, y, c, bp, bw); +} + +void GSLocalMemory::writeFrame16S(int x, int y, DWORD c, DWORD bp, DWORD bw) +{ + c = ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f); + writePixel16S(x, y, c, bp, bw); +} + +//////////////////// + +DWORD GSLocalMemory::readPixel32(int x, int y, DWORD bp, DWORD bw) +{ + return m_vm32[pixelAddress32(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel24(int x, int y, DWORD bp, DWORD bw) +{ + return m_vm32[pixelAddress32(x, y, bp, bw)] & 0x00ffffff; +} + +DWORD GSLocalMemory::readPixel16(int x, int y, DWORD bp, DWORD bw) +{ + return (DWORD)m_vm16[pixelAddress16(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel16S(int x, int y, DWORD bp, DWORD bw) +{ + return (DWORD)m_vm16[pixelAddress16S(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel8(int x, int y, DWORD bp, DWORD bw) +{ + return (DWORD)m_vm8[pixelAddress8(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel8H(int x, int y, DWORD bp, DWORD bw) +{ + return m_vm32[pixelAddress32(x, y, bp, bw)] >> 24; +} + +DWORD GSLocalMemory::readPixel4(int x, int y, DWORD bp, DWORD bw) +{ + DWORD addr = pixelAddress4(x, y, bp, bw); + return (m_vm8[addr>>1] >> ((addr&1) << 2)) & 0x0f; +} + +DWORD GSLocalMemory::readPixel4HL(int x, int y, DWORD bp, DWORD bw) +{ + return (m_vm32[pixelAddress32(x, y, bp, bw)] >> 24) & 0x0f; +} + +DWORD GSLocalMemory::readPixel4HH(int x, int y, DWORD bp, DWORD bw) +{ + return (m_vm32[pixelAddress32(x, y, bp, bw)] >> 28) & 0x0f; +} + +DWORD GSLocalMemory::readPixel32Z(int x, int y, DWORD bp, DWORD bw) +{ + return m_vm32[pixelAddress32Z(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel24Z(int x, int y, DWORD bp, DWORD bw) +{ + return m_vm32[pixelAddress32Z(x, y, bp, bw)] & 0x00ffffff; +} + +DWORD GSLocalMemory::readPixel16Z(int x, int y, DWORD bp, DWORD bw) +{ + return (DWORD)m_vm16[pixelAddress16Z(x, y, bp, bw)]; +} + +DWORD GSLocalMemory::readPixel16SZ(int x, int y, DWORD bp, DWORD bw) +{ + return (DWORD)m_vm16[pixelAddress16SZ(x, y, bp, bw)]; +} + +//////////////////// +/* +void GSLocalMemory::writePixel32(DWORD addr, DWORD c) +{ + m_vm32[addr] = c; +} + +void GSLocalMemory::writePixel24(DWORD addr, DWORD c) +{ + m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); +} + +void GSLocalMemory::writePixel16(DWORD addr, DWORD c) +{ + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel16S(DWORD addr, DWORD c) +{ + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel8(DWORD addr, DWORD c) +{ + m_vm8[addr] = (BYTE)c; +} + +void GSLocalMemory::writePixel8H(DWORD addr, DWORD c) +{ + m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24); +} + +void GSLocalMemory::writePixel4(DWORD addr, DWORD c) +{ + int shift = (addr&1) << 2; addr >>= 1; + m_vm8[addr] = (BYTE)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift)); +} + +void GSLocalMemory::writePixel4HL(DWORD addr, DWORD c) +{ + m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24); +} + +void GSLocalMemory::writePixel4HH(DWORD addr, DWORD c) +{ + m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28); +} + +void GSLocalMemory::writePixel32Z(DWORD addr, DWORD c) +{ + m_vm32[addr] = c; +} + +void GSLocalMemory::writePixel24Z(DWORD addr, DWORD c) +{ + m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); +} + +void GSLocalMemory::writePixel16Z(DWORD addr, DWORD c) +{ + m_vm16[addr] = (WORD)c; +} + +void GSLocalMemory::writePixel16SZ(DWORD addr, DWORD c) +{ + m_vm16[addr] = (WORD)c; +} + +//////////////////// + +void GSLocalMemory::writeFrame16(DWORD addr, DWORD c) +{ + writePixel16(addr, ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f)); +} + +void GSLocalMemory::writeFrame16S(DWORD addr, DWORD c) +{ + writePixel16S(addr, ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f)); +} + +//////////////////// + +DWORD GSLocalMemory::readPixel32(DWORD addr) +{ + return m_vm32[addr]; +} + +DWORD GSLocalMemory::readPixel24(DWORD addr) +{ + return m_vm32[addr] & 0x00ffffff; +} + +DWORD GSLocalMemory::readPixel16(DWORD addr) +{ + return (DWORD)m_vm16[addr]; +} + +DWORD GSLocalMemory::readPixel16S(DWORD addr) +{ + return (DWORD)m_vm16[addr]; +} + +DWORD GSLocalMemory::readPixel8(DWORD addr) +{ + return (DWORD)m_vm8[addr]; +} + +DWORD GSLocalMemory::readPixel8H(DWORD addr) +{ + return m_vm32[addr] >> 24; +} + +DWORD GSLocalMemory::readPixel4(DWORD addr) +{ + return (m_vm8[addr>>1] >> ((addr&1) << 2)) & 0x0f; +} + +DWORD GSLocalMemory::readPixel4HL(DWORD addr) +{ + return (m_vm32[addr] >> 24) & 0x0f; +} + +DWORD GSLocalMemory::readPixel4HH(DWORD addr) +{ + return (m_vm32[addr] >> 28) & 0x0f; +} + +DWORD GSLocalMemory::readPixel32Z(DWORD addr) +{ + return m_vm32[addr]; +} + +DWORD GSLocalMemory::readPixel24Z(DWORD addr) +{ + return m_vm32[addr] & 0x00ffffff; +} + +DWORD GSLocalMemory::readPixel16Z(DWORD addr) +{ + return (DWORD)m_vm16[addr]; +} + +DWORD GSLocalMemory::readPixel16SZ(DWORD addr) +{ + return (DWORD)m_vm16[addr]; +} +*/ +//////////////////// + +bool GSLocalMemory::FillRect(const CRect& r, DWORD c, DWORD psm, DWORD fbp, DWORD fbw) +{ + const psmtbl_t& tbl = m_psmtbl[psm]; + + writePixel wp = tbl.wp; + pixelAddress ba = tbl.ba; + + int w = tbl.bs.cx; + int h = tbl.bs.cy; + int bpp = tbl.bpp; + + int shift = 0; + + switch(bpp) + { + case 32: shift = 0; break; + case 16: shift = 1; c = (c&0xffff)*0x00010001; break; + case 8: shift = 2; c = (c&0xff)*0x01010101; break; + case 4: shift = 3; c = (c&0xf)*0x11111111; break; + } + + CRect clip((r.left+(w-1))&~(w-1), (r.top+(h-1))&~(h-1), r.right&~(w-1), r.bottom&~(h-1)); + + for(int y = r.top; y < clip.top; y++) + for(int x = r.left; x < r.right; x++) + (this->*wp)(x, y, c, fbp, fbw); + + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int ys = y, ye = y + h; ys < ye; ys++) + { + for(int x = r.left; x < clip.left; x++) + (this->*wp)(x, ys, c, fbp, fbw); + for(int x = clip.right; x < r.right; x++) + (this->*wp)(x, ys, c, fbp, fbw); + } + } + + if(psm == PSM_PSMCT24 || psm == PSM_PSMZ24) + { + c &= 0x00ffffff; + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int x = clip.left; x < clip.right; x += w) + { + DWORD* p = &m_vm32[ba(x, y, fbp, fbw)]; + for(int i = 0; i < 64; i++) + p[i] = (p[i]&0xff000000) | c; + } + } + } + else + { + for(int y = clip.top; y < clip.bottom; y += h) + for(int x = clip.left; x < clip.right; x += w) + memsetd(&m_vm8[ba(x, y, fbp, fbw) << 2 >> shift], c, 64); + } + + for(int y = clip.bottom; y < r.bottom; y++) + for(int x = r.left; x < r.right; x++) + (this->*wp)(x, y, c, fbp, fbw); + + return(true); +} + +//////////////////// + +void GSLocalMemory::WriteCLUT(GIFRegTEX0 TEX0, GIFRegTEXCLUT TEXCLUT) +{ + switch(TEX0.CLD) + { + default: + case 0: return; + case 1: break; + case 2: m_CBP[0] = TEX0.CBP; break; + case 3: m_CBP[1] = TEX0.CBP; break; + case 4: if(m_CBP[0] == TEX0.CBP) return; break; + case 5: if(m_CBP[1] == TEX0.CBP) return; break; + } + + { + if(!m_fCLUTMayBeDirty && m_prevTEX0.i64 == TEX0.i64 && m_prevTEXCLUT.i64 == TEXCLUT.i64) + return; + + m_prevTEX0 = TEX0; + m_prevTEXCLUT = TEXCLUT; + + m_fCLUTMayBeDirty = false; + } + + DWORD bp = TEX0.CBP; + DWORD bw = TEX0.CSM == 0 ? 1 : TEXCLUT.CBW; + + WORD* pCLUT = m_pCLUT + (TEX0.CSA<<4); + + // NOTE: TEX0.CPSM == PSM_PSMCT24 is non-standard, KH uses it + + if(TEX0.CSM == 0) + { + if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + WORD* vm = &m_vm16[TEX0.CPSM == PSM_PSMCT16 ? blockAddress16(0, 0, bp, bw) : blockAddress16S(0, 0, bp, bw)]; + + if(TEX0.PSM == PSM_PSMT8 || TEX0.PSM == PSM_PSMT8H) + { + WriteCLUT_T16_I8_CSM1(vm, pCLUT); + } + else if(TEX0.PSM == PSM_PSMT4HH || TEX0.PSM == PSM_PSMT4HL || TEX0.PSM == PSM_PSMT4) + { + WriteCLUT_T16_I4_CSM1(vm, pCLUT); + } + } + else if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + DWORD* vm = &m_vm32[blockAddress32(0, 0, bp, bw)]; + + if(TEX0.PSM == PSM_PSMT8 || TEX0.PSM == PSM_PSMT8H) + { + WriteCLUT_T32_I8_CSM1(vm, pCLUT); + } + else if(TEX0.PSM == PSM_PSMT4HH || TEX0.PSM == PSM_PSMT4HL || TEX0.PSM == PSM_PSMT4) + { + WriteCLUT_T32_I4_CSM1(vm, pCLUT); + } + } + } + else + { + readPixel rp = m_psmtbl[TEX0.CPSM].rp; + + int nPaletteEntries = m_psmtbl[TEX0.PSM].pal; + + ASSERT(nPaletteEntries == 0 || TEX0.CPSM == PSM_PSMCT16); // this is the only allowed format for CSM2, but we implement all of them, just in case... + + if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + for(int i = 0; i < nPaletteEntries; i++) + { + pCLUT[i] = (WORD)(this->*rp)((TEXCLUT.COU<<4) + i, TEXCLUT.COV, bp, bw); + } + } + else if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + for(int i = 0; i < nPaletteEntries; i++) + { + DWORD dw = (this->*rp)((TEXCLUT.COU<<4) + i, TEXCLUT.COV, bp, bw); + pCLUT[i] = (WORD)(dw & 0xffff); + pCLUT[i+256] = (WORD)(dw >> 16); + } + } + } +} + +// + +void GSLocalMemory::ReadCLUT(GIFRegTEX0 TEX0, GIFRegTEXA TEXA, DWORD* pCLUT32) +{ + ASSERT(pCLUT32); + + WORD* pCLUT = m_pCLUT + (TEX0.CSA<<4); + + if(TEX0.CPSM == PSM_PSMCT32) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT32_T32_I8(pCLUT, pCLUT32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadCLUT32_T32_I4(pCLUT, pCLUT32); + break; + } + } + else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT32_T16_I8(pCLUT, pCLUT32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadCLUT32_T16_I4(pCLUT, pCLUT32); + break; + } + } +} + +void GSLocalMemory::SetupCLUT(GIFRegTEX0 TEX0, GIFRegTEXA TEXA) +{ + // TODO: cache m_pCLUT* + + ReadCLUT(TEX0, TEXA, m_pCLUT32); + + switch(TEX0.PSM) + { + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + // sse2? + if(TEX0.CPSM == PSM_PSMCT32) + { + for(int j = 0, k = 0; j < 16; j++) + for(int i = 0; i < 16; i++, k++) + m_pCLUT64[k] = ((UINT64)m_pCLUT32[j] << 32) | m_pCLUT32[i]; + } + else + { + for(int j = 0, k = 0; j < 16; j++) + for(int i = 0; i < 16; i++, k++) + m_pCLUT64[k] = ((UINT64)m_pCLUT32[j] << 16) | (m_pCLUT32[i]&0xffff); + } + break; + } +} + +// + +void GSLocalMemory::ReadCLUT32(GIFRegTEX0 TEX0, GIFRegTEXA TEXA, DWORD* pCLUT32) +{ + ASSERT(pCLUT32); + + WORD* pCLUT = m_pCLUT + (TEX0.CSA<<4); + + if(TEX0.CPSM == PSM_PSMCT32) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT32_T32_I8(pCLUT, pCLUT32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadCLUT32_T32_I4(pCLUT, pCLUT32); + break; + } + } + else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + Expand16(pCLUT, pCLUT32, m_psmtbl[TEX0.PSM].pal, &TEXA); + } +} + +void GSLocalMemory::SetupCLUT32(GIFRegTEX0 TEX0, GIFRegTEXA TEXA) +{ + // TODO: cache m_pCLUT* + + ReadCLUT32(TEX0, TEXA, m_pCLUT32); + + switch(TEX0.PSM) + { + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + // sse2? + for(int j = 0, k = 0; j < 16; j++) + for(int i = 0; i < 16; i++, k++) + m_pCLUT64[k] = ((UINT64)m_pCLUT32[j] << 32) | m_pCLUT32[i]; + break; + } +} + +void GSLocalMemory::CopyCLUT32(DWORD* pCLUT32, int nPaletteEntries) +{ + memcpy(pCLUT32, m_pCLUT32, sizeof(DWORD)*nPaletteEntries); +} + +//////////////////// + +DWORD GSLocalMemory::readTexel32(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_vm32[pixelAddress32(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +DWORD GSLocalMemory::readTexel24(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand24To32(m_vm32[pixelAddress32(x, y, TEX0.TBP0, TEX0.TBW)], TEX0.ai32[1]&4, TEXA); +} + +DWORD GSLocalMemory::readTexel16(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand16To32(m_vm16[pixelAddress16(x, y, TEX0.TBP0, TEX0.TBW)], TEXA); +} + +DWORD GSLocalMemory::readTexel16S(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand16To32(m_vm16[pixelAddress16S(x, y, TEX0.TBP0, TEX0.TBW)], TEXA); +} + +DWORD GSLocalMemory::readTexel8(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel8(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +DWORD GSLocalMemory::readTexel8H(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel8H(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +DWORD GSLocalMemory::readTexel4(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +DWORD GSLocalMemory::readTexel4HL(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4HL(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +DWORD GSLocalMemory::readTexel4HH(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4HH(x, y, TEX0.TBP0, TEX0.TBW)]; +} + +//////////////////// +/* +DWORD GSLocalMemory::readTexel32(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_vm32[addr]; +} + +DWORD GSLocalMemory::readTexel24(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand24To32(m_vm32[addr], TEX0.ai32[1]&4, TEXA); +} + +DWORD GSLocalMemory::readTexel16(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand16To32(m_vm16[addr], TEXA); +} + +DWORD GSLocalMemory::readTexel16S(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return Expand16To32(m_vm16[addr], TEXA); +} + +DWORD GSLocalMemory::readTexel8(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel8(addr)]; +} + +DWORD GSLocalMemory::readTexel8H(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel8H(addr)]; +} + +DWORD GSLocalMemory::readTexel4(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4(addr)]; +} + +DWORD GSLocalMemory::readTexel4HL(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4HL(addr)]; +} + +DWORD GSLocalMemory::readTexel4HH(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return m_pCLUT32[readPixel4HH(addr)]; +} +*/ +//////////////////// + +static void SwizzleTextureStep(int& tx, int& ty, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ +// if(ty == TRXREG.RRH && tx == TRXPOS.DSAX) ASSERT(0); + + if(++tx == TRXREG.RRW) + { + tx = TRXPOS.DSAX; + ty++; + } +} + +#define IsTopLeftAligned(dsax, tx, ty, bw, bh) \ + (((dsax) & ((bw)-1)) == 0 && ((tx) & ((bw)-1)) == 0 && (dsax) == (tx) && ((ty) & ((bh)-1)) == 0) + +void GSLocalMemory::SwizzleTexture32(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)*4; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!fTopLeftAligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + if(fTopLeftAligned && tw >= 8 && th >= 8) + { + int twa = tw & ~7; + int tha = th & ~7; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 8) + { + for(int x = tx; x < twa; x += 8) + SwizzleBlock32u((BYTE*)&m_vm32[blockAddress32(x, ty, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*4, srcpitch); + + for(int i = 0; i < 8; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel32(x, ty, ((DWORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + if(len > 0 && tw >= 8 && th >= 2 && IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 2)) + { + int twa = tw & ~7; + int tha = th & ~1; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 2) + { + for(int x = tx; x < twa; x += 8) + SwizzleColumn32(ty, (BYTE*)&m_vm32[blockAddress32(x, ty&~7, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*4, srcpitch); + + for(int i = 0; i < 2; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel32(x, ty, ((DWORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + if((DWORD_PTR)src & 0xf) + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 8) + SwizzleBlock32u((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*4, srcpitch); + } + else + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 8) + SwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*4, srcpitch); + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)*3; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!fTopLeftAligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + __declspec(align(16)) DWORD block[8*8]; + + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch*8) + { + for(int x = tx; x < tw; x += 8) + { + BYTE* s = src + (x - tx)*3; + DWORD* d = block; + + for(int j = 0, diff = srcpitch - 8*3; j < 8; j++, s += diff, d += 8) + for(int i = 0; i < 8; i++, s += 3) + d[i] = (s[2]<<16)|(s[1]<<8)|s[0]; + + SwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], (BYTE*)block, sizeof(block)/8, 0x00ffffff); + } + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture16(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)*2; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 8); + + if(!fTopLeftAligned || (tw & 15) || (th & 7) || (len % srcpitch)) + { + if(fTopLeftAligned && tw >= 16 && th >= 8) + { + int twa = tw & ~15; + int tha = th & ~7; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 8) + { + for(int x = tx; x < twa; x += 16) + SwizzleBlock16u((BYTE*)&m_vm16[blockAddress16(x, ty, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + + for(int i = 0; i < 8; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel16(x, ty, ((WORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + if(len > 0 && tw >= 16 && th >= 2 && IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 2)) + { + int twa = tw & ~15; + int tha = th & ~1; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 2) + { + for(int x = tx; x < twa; x += 16) + SwizzleColumn16(ty, (BYTE*)&m_vm16[blockAddress16(x, ty&~7, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + + for(int i = 0; i < 2; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel16(x, ty, ((WORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + if((DWORD_PTR)src & 0xf) + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 16) + SwizzleBlock16u((BYTE*)&m_vm16[blockAddress16(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + } + else + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 16) + SwizzleBlock16((BYTE*)&m_vm16[blockAddress16(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture16S(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)*2; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 8); + + if(!fTopLeftAligned || (tw & 15) || (th & 7) || (len % srcpitch)) + { + if(fTopLeftAligned && tw >= 16 && th >= 8) + { + int twa = tw & ~15; + int tha = th & ~7; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 8) + { + for(int x = tx; x < twa; x += 16) + SwizzleBlock16u((BYTE*)&m_vm16[blockAddress16S(x, ty, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + + for(int i = 0; i < 8; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel16S(x, ty, ((WORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + if(len > 0 && tw >= 16 && th >= 2 && IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 2)) + { + int twa = tw & ~15; + int tha = th & ~1; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 2) + { + for(int x = tx; x < twa; x += 16) + SwizzleColumn16(ty, (BYTE*)&m_vm16[blockAddress16S(x, ty&~7, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + + for(int i = 0; i < 2; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel16S(x, ty, ((WORD*)src)[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + if((DWORD_PTR)src & 0xf) + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 16) + SwizzleBlock16((BYTE*)&m_vm16[blockAddress16S(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + } + else + { + for(int y = ty; y < th; y += 8, src += srcpitch*8) + for(int x = tx; x < tw; x += 16) + SwizzleBlock16((BYTE*)&m_vm16[blockAddress16S(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx)*2, srcpitch); + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture8(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = TRXREG.RRW - TRXPOS.DSAX; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 16); + + if(!fTopLeftAligned || (tw & 15) || (th & 15) || (len % srcpitch)) + { + if(fTopLeftAligned && tw >= 16 && th >= 16) + { + int twa = tw & ~15; + int tha = th & ~15; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 16) + { + for(int x = tx; x < twa; x += 16) + SwizzleBlock8u((BYTE*)&m_vm8[blockAddress8(x, ty, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx), srcpitch); + + for(int i = 0; i < 16; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel8(x, ty, src[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + if(len > 0 && tw >= 16 && th >= 4 && IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 16, 4)) + { + int twa = tw & ~15; + int tha = th & ~3; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 4) + { + for(int x = tx; x < twa; x += 16) + SwizzleColumn8(ty, (BYTE*)&m_vm8[blockAddress8(x, ty&~15, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx), srcpitch); + + for(int i = 0; i < 4; i++, ty++, src += srcpitch) + for(int x = twa; x < tw; x++) + writePixel8(x, ty, src[x - tx], BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + if((DWORD_PTR)src & 0xf) + { + for(int y = ty; y < th; y += 16, src += srcpitch*16) + for(int x = tx; x < tw; x += 16) + SwizzleBlock8u((BYTE*)&m_vm8[blockAddress8(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx), srcpitch); + } + else + { + for(int y = ty; y < th; y += 16, src += srcpitch*16) + for(int x = tx; x < tw; x += 16) + SwizzleBlock8((BYTE*)&m_vm8[blockAddress8(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], src + (x - tx), srcpitch); + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = TRXREG.RRW - TRXPOS.DSAX; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!fTopLeftAligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + __declspec(align(16)) DWORD block[8*8]; + + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch*8) + { + for(int x = tx; x < tw; x += 8) + { + BYTE* s = src + (x - tx); + DWORD* d = block; + + for(int j = 0; j < 8; j++, s += srcpitch, d += 8) + for(int i = 0; i < 8; i++) + d[i] = s[i] << 24; + + SwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], (BYTE*)block, sizeof(block)/8, 0xff000000); + } + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture4(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)/2; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 32, 16); + + if(!fTopLeftAligned || (tw & 31) || (th & 15) || (len % srcpitch)) + { + if(fTopLeftAligned && tw >= 32 && th >= 16) + { + int twa = tw & ~31; + int tha = th & ~15; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 16) + { + for(int x = tx; x < twa; x += 32) + SwizzleBlock4u((BYTE*)&m_vm8[blockAddress4(x, ty, BITBLTBUF.DBP, BITBLTBUF.DBW)>>1], src + (x - tx)/2, srcpitch); + + for(int i = 0; i < 16; i++, ty++, src += srcpitch) + { + BYTE* s = src + (twa - tx)/2; + + for(int x = twa; x < tw; x += 2, s++) + { + writePixel4(x, ty, *s&0xf, BITBLTBUF.DBP, BITBLTBUF.DBW), + writePixel4(x+1, ty, *s>>4, BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + } + } + + if(len > 0 && tw >= 32 && th >= 4 && IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 32, 4)) + { + int twa = tw & ~31; + int tha = th & ~3; + + len -= tha * srcpitch; + th -= tha; + + for(int j = 0; j < tha; j += 4) + { + for(int x = tx; x < twa; x += 32) + SwizzleColumn4(ty, (BYTE*)&m_vm8[blockAddress4(x, ty&~15, BITBLTBUF.DBP, BITBLTBUF.DBW)>>1], src + (x - tx)/2, srcpitch); + + for(int i = 0; i < 4; i++, ty++, src += srcpitch) + { + BYTE* s = src + (twa - tx)/2; + + for(int x = twa; x < tw; x += 2, s++) + { + writePixel4(x, ty, *s&0xf, BITBLTBUF.DBP, BITBLTBUF.DBW), + writePixel4(x+1, ty, *s>>4, BITBLTBUF.DBP, BITBLTBUF.DBW); + } + } + } + } + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + if((DWORD_PTR)src & 0xf) + { + for(int y = ty; y < th; y += 16, src += srcpitch*16) + for(int x = tx; x < tw; x += 32) + SwizzleBlock4u((BYTE*)&m_vm8[blockAddress4(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)>>1], src + (x - tx)/2, srcpitch); + } + else + { + for(int y = ty; y < th; y += 16, src += srcpitch*16) + for(int x = tx; x < tw; x += 32) + SwizzleBlock4((BYTE*)&m_vm8[blockAddress4(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)>>1], src + (x - tx)/2, srcpitch); + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)/2; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!fTopLeftAligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + __declspec(align(16)) DWORD block[8*8]; + + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch*8) + { + for(int x = tx; x < tw; x += 8) + { + BYTE* s = src + (x - tx)/2; + DWORD* d = block; + + for(int j = 0; j < 8; j++, s += srcpitch, d += 8) + for(int i = 0; i < 8/2; i++) + d[i*2] = (s[i]&0x0f) << 24, + d[i*2+1] = (s[i]&0xf0) << 20; + + SwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], (BYTE*)block, sizeof(block)/8, 0x0f000000); + } + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTexture4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX)/2; + int th = len / srcpitch; + + bool fTopLeftAligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!fTopLeftAligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + SwizzleTextureX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + __declspec(align(16)) DWORD block[8*8]; + + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch*8) + { + for(int x = tx; x < tw; x += 8) + { + BYTE* s = src + (x - tx)/2; + DWORD* d = block; + + for(int j = 0; j < 8; j++, s += srcpitch, d += 8) + for(int i = 0; i < 8/2; i++) + d[i*2] = (s[i]&0x0f) << 28, + d[i*2+1] = (s[i]&0xf0) << 24; + + SwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, BITBLTBUF.DBP, BITBLTBUF.DBW)], (BYTE*)block, sizeof(block)/8, 0xf0000000); + } + } + + ty = th; + } +} + +void GSLocalMemory::SwizzleTextureX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(len <= 0) return; + + BYTE* pb = (BYTE*)src; + WORD* pw = (WORD*)src; + DWORD* pd = (DWORD*)src; + + // if(ty >= (int)TRXREG.RRH) {ASSERT(0); return;} + + switch(BITBLTBUF.DPSM) + { + case PSM_PSMCT32: + for(len /= 4; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pd++) + writePixel32(tx, ty, *pd, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMCT24: + for(len /= 3; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb+=3) + writePixel24(tx, ty, *(DWORD*)pb, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMCT16: + for(len /= 2; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pw++) + writePixel16(tx, ty, *pw, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMCT16S: + for(len /= 2; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pw++) + writePixel16S(tx, ty, *pw, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMT8: + for(; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb++) + writePixel8(tx, ty, *pb, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMT4: + for(; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb++) + writePixel4(tx, ty, *pb&0xf, BITBLTBUF.DBP, BITBLTBUF.DBW), + writePixel4(tx+1, ty, *pb>>4, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMT8H: + for(; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb++) + writePixel8H(tx, ty, *pb, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMT4HL: + for(; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb++) + writePixel4HL(tx, ty, *pb&0xf, BITBLTBUF.DBP, BITBLTBUF.DBW), + writePixel4HL(tx+1, ty, *pb>>4, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMT4HH: + for(; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb++) + writePixel4HH(tx, ty, *pb&0xf, BITBLTBUF.DBP, BITBLTBUF.DBW), + writePixel4HH(tx+1, ty, *pb>>4, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMZ32: + for(len /= 4; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pd++) + writePixel32Z(tx, ty, *pd, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMZ24: + for(len /= 3; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pb+=3) + writePixel24Z(tx, ty, *(DWORD*)pb, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMZ16: + for(len /= 2; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pw++) + writePixel16Z(tx, ty, *pw, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + case PSM_PSMZ16S: + for(len /= 2; len-- > 0; SwizzleTextureStep(tx, ty, TRXPOS, TRXREG), pw++) + writePixel16SZ(tx, ty, *pw, BITBLTBUF.DBP, BITBLTBUF.DBW); + break; + } +} + +/////////////////// + +void GSLocalMemory::unSwizzleTexture32(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left)*4, dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture24(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + ExpandBlock24(block, (DWORD*)ptr + (x-r.left), dstpitch, &TEXA); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture16(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 8, 16) + { + __declspec(align(16)) WORD block[16*8]; + unSwizzleBlock16((BYTE*)&m_vm16[blockAddress16(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + ExpandBlock16(block, (DWORD*)ptr + (x-r.left), dstpitch, &TEXA); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture16S(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 8, 16S) + { + __declspec(align(16)) WORD block[16*8]; + unSwizzleBlock16((BYTE*)&m_vm16[blockAddress16S(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + ExpandBlock16(block, (DWORD*)ptr + (x-r.left), dstpitch, &TEXA); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture8(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 16, 8) + { + __declspec(align(16)) BYTE block[16*16]; + unSwizzleBlock8((BYTE*)&m_vm8[blockAddress8(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/16); + + BYTE* s = block; + BYTE* d = ptr + (x-r.left)*4; + + for(int j = 0; j < 16; j++, s += 16, d += dstpitch) + for(int i = 0; i < 16; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i]]; + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture8H(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + BYTE* d = ptr + (x-r.left)*4; + + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i] >> 24]; + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 32, 16, 4) + { + __declspec(align(16)) BYTE block[(32/2)*16]; + unSwizzleBlock4((BYTE*)&m_vm8[blockAddress4(x, y, TEX0.TBP0, TEX0.TBW)>>1], (BYTE*)block, sizeof(block)/16); + + BYTE* s = block; + BYTE* d = ptr + (x-r.left)*4; + + for(int j = 0; j < 16; j++, s += 32/2, d += dstpitch) + for(int i = 0; i < 32/2; i++) + ((UINT64*)d)[i] = m_pCLUT64[s[i]]; + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HL(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + BYTE* d = ptr + (x-r.left)*4; + + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[(s[i] >> 24)&0x0f]; + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HH(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + BYTE* d = ptr + (x-r.left)*4; + + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i] >> 28]; + } + FOREACH_BLOCK_END + } +} + +/////////////////// + +void GSLocalMemory::ReadTexture(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP) +{ + unSwizzleTexture st = m_psmtbl[TEX0.PSM].ust; + readTexel rt = m_psmtbl[TEX0.PSM].rt; + CSize bs = m_psmtbl[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) + || (CLAMP.WMS&2) || (CLAMP.WMT&2)) + { + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + } + else + { + (this->*st)(r, dst, dstpitch, TEX0, TEXA); + } +} + +//////////////////// + +DWORD GSLocalMemory::readTexel16P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel16(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel16SP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel16S(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel8P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel8(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel8HP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel8H(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel4P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel4(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel4HLP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel4HL(x, y, TEX0.TBP0, TEX0.TBW); +} + +DWORD GSLocalMemory::readTexel4HHP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + return readPixel4HH(x, y, TEX0.TBP0, TEX0.TBW); +} + +/////////////////// + +void GSLocalMemory::unSwizzleTexture16P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 8, 16) + { + unSwizzleBlock16((BYTE*)&m_vm16[blockAddress16(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left)*2, dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture16SP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 8, 16S) + { + unSwizzleBlock16((BYTE*)&m_vm16[blockAddress16S(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left)*2, dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture8P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 16, 8) + { + unSwizzleBlock8((BYTE*)&m_vm8[blockAddress8(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left), dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture8HP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + unSwizzleBlock8HP((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left), dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 32, 16, 4) + { + unSwizzleBlock4P((BYTE*)&m_vm8[blockAddress4(x, y, TEX0.TBP0, TEX0.TBW)>>1], ptr + (x-r.left), dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + unSwizzleBlock4HLP((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left), dstpitch); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + unSwizzleBlock4HHP((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], ptr + (x-r.left), dstpitch); + } + FOREACH_BLOCK_END + } +} + +/////////////////// + +void GSLocalMemory::ReadTextureP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP) +{ + unSwizzleTexture st = m_psmtbl[TEX0.PSM].ustP; + readTexel rt = m_psmtbl[TEX0.PSM].rtP; + CSize bs = m_psmtbl[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) + || (CLAMP.WMS&2) || (CLAMP.WMT&2)) + { + switch(TEX0.PSM) + { + default: + case PSM_PSMCT32: + case PSM_PSMCT24: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + } + } + else + { + (this->*st)(r, dst, dstpitch, TEX0, TEXA); + } +} + +/////////////////// + +void GSLocalMemory::unSwizzleTexture8NP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 16, 16, 8) + { + __declspec(align(16)) BYTE block[16*16]; + unSwizzleBlock8((BYTE*)&m_vm8[blockAddress8(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/16); + + BYTE* s = block; + + if(TEX0.CPSM == PSM_PSMCT32) + { + BYTE* d = ptr + (x-r.left)*4; + for(int j = 0; j < 16; j++, s += 16, d += dstpitch) + for(int i = 0; i < 16; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i]]; + } + else + { + BYTE* d = ptr + (x-r.left)*2; + for(int j = 0; j < 16; j++, s += 16, d += dstpitch) + for(int i = 0; i < 16; i++) + ((WORD*)d)[i] = (WORD)m_pCLUT32[s[i]]; + } + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + + if(TEX0.CPSM == PSM_PSMCT32) + { + BYTE* d = ptr + (x-r.left)*4; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i] >> 24]; + } + else + { + BYTE* d = ptr + (x-r.left)*2; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((WORD*)d)[i] = (WORD)m_pCLUT32[s[i] >> 24]; + } + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4NP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 32, 16, 4) + { + __declspec(align(16)) BYTE block[(32/2)*16]; + unSwizzleBlock4((BYTE*)&m_vm8[blockAddress4(x, y, TEX0.TBP0, TEX0.TBW)>>1], (BYTE*)block, sizeof(block)/16); + + BYTE* s = block; + + if(TEX0.CPSM == PSM_PSMCT32) + { + BYTE* d = ptr + (x-r.left)*4; + for(int j = 0; j < 16; j++, s += 32/2, d += dstpitch) + for(int i = 0; i < 32/2; i++) + ((UINT64*)d)[i] = m_pCLUT64[s[i]]; + } + else + { + BYTE* d = ptr + (x-r.left)*2; + for(int j = 0; j < 16; j++, s += 32/2, d += dstpitch) + for(int i = 0; i < 32/2; i++) + ((DWORD*)d)[i] = (DWORD)m_pCLUT64[s[i]]; + } + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + + if(TEX0.CPSM == PSM_PSMCT32) + { + BYTE* d = ptr + (x-r.left)*4; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[(s[i] >> 24)&0x0f]; + } + else + { + BYTE* d = ptr + (x-r.left)*2; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((WORD*)d)[i] = (WORD)m_pCLUT32[(s[i] >> 24)&0x0f]; + } + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::unSwizzleTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) +{ + #pragma omp parallel + { + #pragma omp for + FOREACH_BLOCK_START(r, 8, 8, 32) + { + __declspec(align(16)) DWORD block[8*8]; + unSwizzleBlock32((BYTE*)&m_vm32[blockAddress32(x, y, TEX0.TBP0, TEX0.TBW)], (BYTE*)block, sizeof(block)/8); + + DWORD* s = block; + + if(TEX0.CPSM == PSM_PSMCT32) + { + BYTE* d = ptr + (x-r.left)*4; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)d)[i] = m_pCLUT32[s[i] >> 28]; + } + else + { + BYTE* d = ptr + (x-r.left)*2; + for(int j = 0; j < 8; j++, s += 8, d += dstpitch) + for(int i = 0; i < 8; i++) + ((WORD*)d)[i] = (WORD)m_pCLUT32[s[i] >> 28]; + } + } + FOREACH_BLOCK_END + } +} + +/////////////////// + +void GSLocalMemory::ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP) +{ + unSwizzleTexture st = m_psmtbl[TEX0.PSM].ustNP; + readTexel rt = m_psmtbl[TEX0.PSM].rtNP; + + CSize bs = m_psmtbl[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) + || (CLAMP.WMS&2) || (CLAMP.WMT&2)) + { + switch(TEX0.PSM) + { + default: + case PSM_PSMCT32: + case PSM_PSMCT24: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + switch(TEX0.CPSM) + { + default: + case PSM_PSMCT32: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, st); + break; + } + break; + } + } + else + { + (this->*st)(r, dst, dstpitch, TEX0, TEXA); + } +} + +// + +template +void GSLocalMemory::ReadTexture(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP, readTexel rt, unSwizzleTexture st) +{ + // this function is not thread safe! + + CSize bs = m_psmtbl[TEX0.PSM].bs; + + CRect cr( + (r.left + (bs.cx-1)) & ~(bs.cx-1), + (r.top + (bs.cy-1)) & ~(bs.cy-1), + r.right & ~(bs.cx-1), + r.bottom & ~(bs.cy-1)); + + bool fAligned = ((DWORD_PTR)(dst + (cr.left-r.left)*sizeof(DstT)) & 0xf) == 0; + + if((CLAMP.WMS&2) || (CLAMP.WMT&2)) + { + DWORD wms = CLAMP.WMS, wmt = CLAMP.WMT; + DWORD minu = CLAMP.MINU, maxu = CLAMP.MAXU; + DWORD minv = CLAMP.MINV, maxv = CLAMP.MAXV; + + switch(wms) + { + default: for(int x = r.left; x < r.right; x++) m_xtbl[x] = x; break; + case 2: for(int x = r.left; x < r.right; x++) m_xtbl[x] = x < minu ? minu : x > maxu ? maxu : x; break; + case 3: for(int x = r.left; x < r.right; x++) m_xtbl[x] = (x & minu) | maxu; break; + } + + switch(wmt) + { + default: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = y; break; + case 2: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = y < minv ? minv : y > maxv ? maxv : y; break; + case 3: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = (y & minv) | maxv; break; + } + + if(fAligned && wms <= 2 && wmt <= 2) + { + // TODO: read clamped areas only once + + for(int y = r.top; y < cr.top; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + + if(!cr.IsRectEmpty()) + (this->*st)(cr, dst + (cr.left - r.left)*sizeof(DstT), dstpitch, TEX0, TEXA); + + for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) + { + for(int x = r.left, i = 0; x < cr.left; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + } + + for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + } + else + { + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + } + } + else + { + if(fAligned) + { + for(int y = r.top; y < cr.top; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(x, y, TEX0, TEXA); + + if(!cr.IsRectEmpty()) + (this->*st)(cr, dst + (cr.left - r.left)*sizeof(DstT), dstpitch, TEX0, TEXA); + + for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) + { + for(int x = r.left, i = 0; x < cr.left; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(x, y, TEX0, TEXA); + for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(x, y, TEX0, TEXA); + } + + for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(x, y, TEX0, TEXA); + } + else + { + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((DstT*)dst)[i] = (DstT)(this->*rt)(x, y, TEX0, TEXA); + } + } +} + +// + +HRESULT GSLocalMemory::SaveBMP(IDirect3DDevice9* pDev, LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h) +{ + CComPtr pTexture; + D3DLOCKED_RECT lr; + HRESULT hr = pDev->CreateTexture(w, h, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTexture, NULL); + if(FAILED(hr) || FAILED(pTexture->LockRect(0, &lr, NULL, 0))) return E_FAIL; + + readTexel rt = m_psmtbl[psm].rt; + GIFRegTEX0 TEX0; + TEX0.TBP0 = bp; + TEX0.TBW = bw; + TEX0.PSM = psm; + GIFRegTEXA TEXA; + TEXA.AEM = 0; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + + BYTE* p = (BYTE*)lr.pBits; + + for(int j = 0; j < h; j++, p += lr.Pitch) + for(int i = 0; i < w; i++) + ((DWORD*)p)[i] = (this->*rt)(i, j, TEX0, TEXA); + + pTexture->UnlockRect(0); + + return D3DXSaveTextureToFile(fn, D3DXIFF_BMP, pTexture, NULL); +} diff --git a/plugins/gs/gsdx9/GSLocalMemory.h b/plugins/gs/gsdx9/GSLocalMemory.h new file mode 100644 index 0000000000..440a79e2dd --- /dev/null +++ b/plugins/gs/gsdx9/GSLocalMemory.h @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#pragma warning(disable: 4244) // warning C4244: '=' : conversion from 'const UINT64' to 'int', possible loss of data + +#include "GS.h" +#include "GSTables.h" + +class GSLocalMemory +{ +public: + typedef DWORD (__fastcall *pixelAddress)(int x, int y, DWORD bp, DWORD bw); + typedef void (GSLocalMemory::*writePixel)(int x, int y, DWORD c, DWORD bp, DWORD bw); + typedef void (GSLocalMemory::*writeFrame)(int x, int y, DWORD c, DWORD bp, DWORD bw); + typedef DWORD (GSLocalMemory::*readPixel)(int x, int y, DWORD bp, DWORD bw); + typedef DWORD (GSLocalMemory::*readTexel)(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + typedef void (GSLocalMemory::*writePixelAddr)(DWORD addr, DWORD c); + typedef void (GSLocalMemory::*writeFrameAddr)(DWORD addr, DWORD c); + typedef DWORD (GSLocalMemory::*readPixelAddr)(DWORD addr); + typedef DWORD (GSLocalMemory::*readTexelAddr)(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + typedef void (GSLocalMemory::*SwizzleTexture)(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + typedef void (GSLocalMemory::*unSwizzleTexture)(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + typedef void (GSLocalMemory::*readTexture)(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP); + + typedef union + { + struct + { + pixelAddress pa, ba, pga; + readPixel rp; + readPixelAddr rpa; + writePixel wp; + writePixelAddr wpa; + readTexel rt, rtP, rtNP; + readTexelAddr rta; + writeFrameAddr wfa; + SwizzleTexture st; + unSwizzleTexture ust, ustP, ustNP; + DWORD bpp, pal, trbpp; + CSize bs; + int* rowOffset[8]; + }; + BYTE dummy[128]; + } psmtbl_t; + + static psmtbl_t m_psmtbl[64]; + +protected: + static DWORD pageOffset32[32][32][64]; + static DWORD pageOffset32Z[32][32][64]; + static DWORD pageOffset16[32][64][64]; + static DWORD pageOffset16S[32][64][64]; + static DWORD pageOffset16Z[32][64][64]; + static DWORD pageOffset16SZ[32][64][64]; + static DWORD pageOffset8[32][64][128]; + static DWORD pageOffset4[32][128][128]; + + static int rowOffset32[2048]; + static int rowOffset32Z[2048]; + static int rowOffset16[2048]; + static int rowOffset16S[2048]; + static int rowOffset16Z[2048]; + static int rowOffset16SZ[2048]; + static int rowOffset8[2][2048]; + static int rowOffset4[2][2048]; + + union {BYTE* m_vm8; WORD* m_vm16; DWORD* m_vm32;}; + + DWORD m_CBP[2]; + WORD* m_pCLUT; + DWORD* m_pCLUT32; + UINT64* m_pCLUT64; + + GIFRegTEX0 m_prevTEX0; + GIFRegTEXCLUT m_prevTEXCLUT; + bool m_fCLUTMayBeDirty; + +public: + GSLocalMemory(); + virtual ~GSLocalMemory(); + + static void RoundDown(CSize& s, CSize bs); + static void RoundUp(CSize& s, CSize bs); + + static DWORD Expand24To32(DWORD c, BYTE TCC, GIFRegTEXA& TEXA) + { + BYTE A = (!TEXA.AEM|(c&0xffffff)) ? TEXA.TA0 : 0; + return (A<<24) | (c&0xffffff); + } + + static DWORD Expand16To32(WORD c, GIFRegTEXA& TEXA) + { + BYTE A = (c&0x8000) ? TEXA.TA1 : (!TEXA.AEM|c) ? TEXA.TA0 : 0; + return (A << 24) | ((c&0x7c00) << 9) | ((c&0x03e0) << 6) | ((c&0x001f) << 3); + } + + BYTE* GetVM() {return m_vm8;} + + // address + + static DWORD __fastcall pageAddress32(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pageAddress16(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pageAddress8(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pageAddress4(int x, int y, DWORD bp, DWORD bw); + + static DWORD __fastcall blockAddress32(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress16(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress16S(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress8(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress4(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress32Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress16Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall blockAddress16SZ(int x, int y, DWORD bp, DWORD bw); + + static DWORD __fastcall pixelAddressOrg32(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg16(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg16S(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg8(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg4(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg32Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg16Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddressOrg16SZ(int x, int y, DWORD bp, DWORD bw); + + static DWORD __fastcall pixelAddress32(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress16(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress16S(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress8(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress4(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress32Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress16Z(int x, int y, DWORD bp, DWORD bw); + static DWORD __fastcall pixelAddress16SZ(int x, int y, DWORD bp, DWORD bw); + + // raw pixel R/W + + void writePixel32(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel24(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel16(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel16S(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel8(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel8H(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel4(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel4HL(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel4HH(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel32Z(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel24Z(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel16Z(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writePixel16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw); + + void writeFrame16(int x, int y, DWORD c, DWORD bp, DWORD bw); + void writeFrame16S(int x, int y, DWORD c, DWORD bp, DWORD bw); + + DWORD readPixel32(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel24(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel16(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel16S(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel8(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel8H(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel4(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel4HL(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel4HH(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel32Z(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel24Z(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel16Z(int x, int y, DWORD bp, DWORD bw); + DWORD readPixel16SZ(int x, int y, DWORD bp, DWORD bw); + + void writePixel32(DWORD addr, DWORD c) {m_vm32[addr] = c;} + void writePixel24(DWORD addr, DWORD c) {m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff);} + void writePixel16(DWORD addr, DWORD c) {m_vm16[addr] = (WORD)c;} + void writePixel16S(DWORD addr, DWORD c) {m_vm16[addr] = (WORD)c;} + void writePixel8(DWORD addr, DWORD c) {m_vm8[addr] = (BYTE)c;} + void writePixel8H(DWORD addr, DWORD c) {m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24);} + void writePixel4(DWORD addr, DWORD c) {int shift = (addr&1) << 2; addr >>= 1; m_vm8[addr] = (BYTE)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift));} + void writePixel4HL(DWORD addr, DWORD c) {m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24);} + void writePixel4HH(DWORD addr, DWORD c) {m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28);} + void writePixel32Z(DWORD addr, DWORD c) {m_vm32[addr] = c;} + void writePixel24Z(DWORD addr, DWORD c) {m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff);} + void writePixel16Z(DWORD addr, DWORD c) {m_vm16[addr] = (WORD)c;} + void writePixel16SZ(DWORD addr, DWORD c) {m_vm16[addr] = (WORD)c;} + + void writeFrame16(DWORD addr, DWORD c) {writePixel16(addr, ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f));} + void writeFrame16S(DWORD addr, DWORD c) {writePixel16S(addr, ((c>>16)&0x8000)|((c>>9)&0x7c00)|((c>>6)&0x03e0)|((c>>3)&0x001f));} + + DWORD readPixel32(DWORD addr) {return m_vm32[addr];} + DWORD readPixel24(DWORD addr) {return m_vm32[addr] & 0x00ffffff;} + DWORD readPixel16(DWORD addr) {return (DWORD)m_vm16[addr];} + DWORD readPixel16S(DWORD addr) {return (DWORD)m_vm16[addr];} + DWORD readPixel8(DWORD addr) {return (DWORD)m_vm8[addr];} + DWORD readPixel8H(DWORD addr) {return m_vm32[addr] >> 24;} + DWORD readPixel4(DWORD addr) {return (m_vm8[addr>>1] >> ((addr&1) << 2)) & 0x0f;} + DWORD readPixel4HL(DWORD addr) {return (m_vm32[addr] >> 24) & 0x0f;} + DWORD readPixel4HH(DWORD addr) {return (m_vm32[addr] >> 28) & 0x0f;} + DWORD readPixel32Z(DWORD addr) {return m_vm32[addr];} + DWORD readPixel24Z(DWORD addr) {return m_vm32[addr] & 0x00ffffff;} + DWORD readPixel16Z(DWORD addr) {return (DWORD)m_vm16[addr];} + DWORD readPixel16SZ(DWORD addr) {return (DWORD)m_vm16[addr];} + + // FillRect + + bool FillRect(const CRect& r, DWORD c, DWORD psm, DWORD fbp, DWORD fbw); + + // CLUT + + void InvalidateCLUT() {m_fCLUTMayBeDirty = true;} + void WriteCLUT(GIFRegTEX0 TEX0, GIFRegTEXCLUT TEXCLUT); + + void ReadCLUT(GIFRegTEX0 TEX0, GIFRegTEXA TEXA, DWORD* pCLUT32); + void SetupCLUT(GIFRegTEX0 TEX0, GIFRegTEXA TEXA); + + // expands 16->32 + void ReadCLUT32(GIFRegTEX0 TEX0, GIFRegTEXA TEXA, DWORD* pCLUT32); + void SetupCLUT32(GIFRegTEX0 TEX0, GIFRegTEXA TEXA); + void CopyCLUT32(DWORD* pCLUT32, int nPaletteEntries); + + // 32-only + + DWORD readTexel32(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel24(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel16(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel16S(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel8(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel8H(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4HL(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4HH(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + + DWORD readTexel32(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_vm32[addr];} + DWORD readTexel24(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return Expand24To32(m_vm32[addr], TEX0.ai32[1]&4, TEXA);} + DWORD readTexel16(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return Expand16To32(m_vm16[addr], TEXA);} + DWORD readTexel16S(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return Expand16To32(m_vm16[addr], TEXA);} + DWORD readTexel8(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_pCLUT32[readPixel8(addr)];} + DWORD readTexel8H(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_pCLUT32[readPixel8H(addr)];} + DWORD readTexel4(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_pCLUT32[readPixel4(addr)];} + DWORD readTexel4HL(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_pCLUT32[readPixel4HL(addr)];} + DWORD readTexel4HH(DWORD addr, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA) {return m_pCLUT32[readPixel4HH(addr)];} + + void SwizzleTexture32(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture16(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture16S(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture8(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture4(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTexture4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void SwizzleTextureX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + + void unSwizzleTexture32(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture24(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture16(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture16S(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture8(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture8H(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HL(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HH(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + + void ReadTexture(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP); + + // 32/16/8P + + DWORD readTexel16P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel16SP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel8P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel8HP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4P(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4HLP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + DWORD readTexel4HHP(int x, int y, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + + void unSwizzleTexture16P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture16SP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture8P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture8HP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4P(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + + void ReadTextureP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP); + + // 32/16 + + void unSwizzleTexture8NP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4NP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + void unSwizzleTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA); + + void ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP); + + // + + static DWORD m_xtbl[1024], m_ytbl[1024]; + + template + void ReadTexture(const CRect& r, BYTE* dst, int dstpitch, GIFRegTEX0& TEX0, GIFRegTEXA& TEXA, GIFRegCLAMP& CLAMP, readTexel rt, unSwizzleTexture st); + + // + + HRESULT SaveBMP(IDirect3DDevice9* pDev, LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h); +}; + +#pragma warning(default: 4244) \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSPerfMon.cpp b/plugins/gs/gsdx9/GSPerfMon.cpp new file mode 100644 index 0000000000..f62d122960 --- /dev/null +++ b/plugins/gs/gsdx9/GSPerfMon.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSPerfMon.h" + +#if _MSC_VER >= 1400 +extern "C" unsigned __int64 __rdtsc(); +#else +__declspec(naked) unsigned __int64 __rdtsc() {__asm rdtsc __asm ret} +#endif + +GSPerfMon::GSPerfMon() + : m_total(0), m_begin(0) + , m_frame(0), m_lastframe(0) +{ +} + +void GSPerfMon::IncCounter(counter_t c, double val) +{ + if(c == c_frame) + { + clock_t now = clock(); + if(m_lastframe != 0) + m_counters[c].AddTail(now - m_lastframe); + m_lastframe = now; + m_frame++; + } + else + { + m_counters[c].AddTail(val); + } +} + +void GSPerfMon::StartTimer() +{ + m_start = __rdtsc(); + if(m_begin == 0) m_begin = m_start; +} + +void GSPerfMon::StopTimer() +{ + if(m_start > 0) + { + m_total += __rdtsc() - m_start; + m_start = 0; + } +} + +CString GSPerfMon::ToString(double expected_fps) +{ + if(m_counters[c_frame].IsEmpty()) + return _T(""); + + double stats[c_last]; + + for(int i = 0; i < countof(m_counters); i++) + { + double sum = 0; + POSITION pos = m_counters[i].GetHeadPosition(); + while(pos) sum += m_counters[i].GetNext(pos); + stats[i] = sum / m_counters[c_frame].GetCount(); + } + + UINT64 start = m_start; + + if(start > 0) StopTimer(); + + double fps = 1000.0 / stats[c_frame]; + double cpu = 100.0 * m_total / (__rdtsc() - m_begin); + + CString str; + + str.Format(_T("frame: %I64d | cpu: %d%% | %.2f fps (%d%%) | %d ppf | %.2f kbpf | %.2f kbpf | %.2f kbpf"), + m_frame, + (int)(cpu), + (float)(fps), + (int)(100.0 * fps / expected_fps), + (int)(stats[c_prim]), + (float)(stats[c_swizzle] / 1024), + (float)(stats[c_unswizzle] / 1024), + (float)(stats[c_texture] / 1024)); + + for(int i = 0; i < countof(m_counters); i++) + m_counters[i].RemoveAll(); + m_total = m_begin = 0; + + if(start > 0) StartTimer(); + + return str; +} diff --git a/plugins/gs/gsdx9/GSPerfMon.h b/plugins/gs/gsdx9/GSPerfMon.h new file mode 100644 index 0000000000..9acb79a766 --- /dev/null +++ b/plugins/gs/gsdx9/GSPerfMon.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "x86.h" + +class GSPerfMon +{ +public: + enum counter_t {c_frame, c_prim, c_swizzle, c_unswizzle, c_texture, c_last}; + +protected: + CAtlList m_counters[c_last]; + UINT64 m_begin, m_total, m_start, m_frame; + clock_t m_lastframe; + +public: + GSPerfMon(); + + void IncCounter(counter_t c, double val = 0); + void StartTimer(), StopTimer(); + CString ToString(double expected_fps); + UINT64 GetFrame() {return m_frame;} +}; + +class GSPerfMonAutoTimer +{ + GSPerfMon* m_pm; + +public: + GSPerfMonAutoTimer(GSPerfMon& pm) {(m_pm = &pm)->StartTimer();} + ~GSPerfMonAutoTimer() {m_pm->StopTimer();} +}; \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSRegs.cpp b/plugins/gs/gsdx9/GSRegs.cpp new file mode 100644 index 0000000000..8b61a40b60 --- /dev/null +++ b/plugins/gs/gsdx9/GSRegs.cpp @@ -0,0 +1,1033 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSState.h" + +// GIFPackedRegHandler* + +void __fastcall GSState::GIFPackedRegHandlerNull(GIFPackedReg* r) +{ + LOG(_T("GIFPackedRegHandlerNull(%016I64x%016I64x)\n"), r->ai64[0], r->ai64[1]); +} + +void __fastcall GSState::GIFPackedRegHandlerPRIM(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFReg r2; + r2.PRIM.i64 = r->PRIM.PRIM; + GIFRegHandlerPRIM(&r2); +} + +void __fastcall GSState::GIFPackedRegHandlerRGBA(GIFPackedReg* r) +{ + LOG(_T("Packed RGBA(R=%x G=%x B=%x A=%x)\n"), + r->RGBA.R, + r->RGBA.G, + r->RGBA.B, + r->RGBA.A); + + m_v.RGBAQ.R = r->RGBA.R; + m_v.RGBAQ.G = r->RGBA.G; + m_v.RGBAQ.B = r->RGBA.B; + m_v.RGBAQ.A = r->RGBA.A; + m_v.RGBAQ.Q = m_q; +} + +void __fastcall GSState::GIFPackedRegHandlerSTQ(GIFPackedReg* r) +{ + LOG(_T("Packed STQ(S=%.4f T=%.4f, Q=%.4f)\n"), + r->STQ.S, + r->STQ.T, + r->STQ.Q); + + m_v.ST.S = r->STQ.S; + m_v.ST.T = r->STQ.T; + m_q = r->STQ.Q; +} + +void __fastcall GSState::GIFPackedRegHandlerUV(GIFPackedReg* r) +{ + LOG(_T("Packed UV(U=%.4f V=%.4f)\n"), + (float)r->UV.U/16, + (float)r->UV.V/16); + + m_v.UV.U = r->UV.U; + m_v.UV.V = r->UV.V; +} + +void __fastcall GSState::GIFPackedRegHandlerXYZF2(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + + LOG(_T("XYZF%d(X=%.2f Y=%.2f Z=%d F=%d)\n"), + 2 + r->XYZF2.ADC, + (float)r->XYZF2.X/16, + (float)r->XYZF2.Y/16, + r->XYZF2.Z, + r->XYZF2.F); + + m_v.XYZ.X = r->XYZF2.X; + m_v.XYZ.Y = r->XYZF2.Y; + m_v.XYZ.Z = r->XYZF2.Z; + m_v.FOG.F = r->XYZF2.F; + + VertexKick(r->XYZF2.ADC); +} + +void __fastcall GSState::GIFPackedRegHandlerXYZ2(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + + LOG(_T("XYZ%d(X=%.2f Y=%.2f Z=%d)\n"), + 2 + r->XYZ2.ADC, + (float)r->XYZ2.X/16, + (float)r->XYZ2.Y/16, + r->XYZ2.Z); + + m_v.XYZ.X = r->XYZ2.X; + m_v.XYZ.Y = r->XYZ2.Y; + m_v.XYZ.Z = r->XYZ2.Z; + + VertexKick(r->XYZ2.ADC); +} + +void __fastcall GSState::GIFPackedRegHandlerTEX0_1(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerTEX0_1((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerTEX0_2(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerTEX0_2((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerCLAMP_1(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerCLAMP_1((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerCLAMP_2(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerCLAMP_2((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerFOG(GIFPackedReg* r) +{ + LOG(_T("Packed FOG(F=%x)\n"), + r->FOG.F); + + m_v.FOG.F = r->FOG.F; +} + +void __fastcall GSState::GIFPackedRegHandlerXYZF3(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerXYZF3((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerXYZ3(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + GIFRegHandlerXYZ3((GIFReg*)&r->ai64[0]); +} + +void __fastcall GSState::GIFPackedRegHandlerA_D(GIFPackedReg* r) +{ + LOG(_T("Packed ")); + (this->*m_fpGIFRegHandlers[(BYTE)r->A_D.ADDR])(&r->r); +} + +void __fastcall GSState::GIFPackedRegHandlerNOP(GIFPackedReg* r) +{ + LOG(_T("Packed NOP(%016I64x%016I64x)\n"), r->ai64[0], r->ai64[1]); +} + +// GIFRegHandler* + +void __fastcall GSState::GIFRegHandlerNull(GIFReg* r) +{ + LOG(_T("*** WARNING *** GIFRegHandlerNull(%016I64x)\n"), r->i64); +} + +void __fastcall GSState::GIFRegHandlerPRIM(GIFReg* r) +{ + LOG(_T("PRIM(PRIM=%x IIP=%x TME=%x FGE=%x ABE=%x AA1=%x FST=%x CTXT=%x FIX=%x)\n"), + r->PRIM.PRIM, + r->PRIM.IIP, + r->PRIM.TME, + r->PRIM.FGE, + r->PRIM.ABE, + r->PRIM.AA1, + r->PRIM.FST, + r->PRIM.CTXT, + r->PRIM.FIX); + + if(m_de.PRIM.i64 != r->PRIM.i64) + FlushPrimInternal(); + + m_de.PRIM = r->PRIM; + m_de.PRMODE._PRIM = r->PRIM.PRIM; + + if(m_de.PRMODECONT.AC) + { + m_ctxt = &m_de.CTXT[m_de.PRIM.CTXT]; + } + + NewPrim(); +} + +void __fastcall GSState::GIFRegHandlerRGBAQ(GIFReg* r) +{ + LOG(_T("RGBAQ(R=%x G=%x B=%x A=%x Q=%.4f)\n"), + r->RGBAQ.R, + r->RGBAQ.G, + r->RGBAQ.B, + r->RGBAQ.A, + r->RGBAQ.Q); + + m_v.RGBAQ = r->RGBAQ; +} + +void __fastcall GSState::GIFRegHandlerST(GIFReg* r) +{ + LOG(_T("ST(S=%.4f T=%.4f)\n"), + r->ST.S, + r->ST.T); + + m_v.ST = r->ST; +} + +void __fastcall GSState::GIFRegHandlerUV(GIFReg* r) +{ + LOG(_T("UV(U=%.4f V=%.4f)\n"), + (float)r->UV.U/16, + (float)r->UV.V/16); + + m_v.UV = r->UV; +} + +void __fastcall GSState::GIFRegHandlerXYZF2(GIFReg* r) +{ + LOG(_T("XYZF2(X=%.2f Y=%.2f Z=%08x F=%d)\n"), + (float)r->XYZF.X/16, + (float)r->XYZF.Y/16, + r->XYZF.Z, + r->XYZF.F); +/* + m_v.XYZ.X = r->XYZF.X; + m_v.XYZ.Y = r->XYZF.Y; + m_v.XYZ.Z = r->XYZF.Z; + m_v.FOG.F = r->XYZF.F; +*/ + m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; + m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; + m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; + + VertexKick(false); +} + +void __fastcall GSState::GIFRegHandlerXYZ2(GIFReg* r) +{ + LOG(_T("XYZ2(X=%.2f Y=%.2f Z=%08x)\n"), + (float)r->XYZ.X/16, + (float)r->XYZ.Y/16, + r->XYZ.Z); + + m_v.XYZ = r->XYZ; + + VertexKick(false); +} + +void __fastcall GSState::GIFRegHandlerTEX0_1(GIFReg* r) +{ + LOG(_T("TEX0_1(TBP0=%I64x TBW=%I64d PSM=%I64x TW=%I64d TH=%I64d TCC=%I64x TFX=%I64x CBP=%I64x CPSM=%I64x CSM=%I64x CSA=%I64x CLD=%I64x)\n"), + r->TEX0.TBP0, + r->TEX0.TBW*64, + r->TEX0.PSM, + 1i64<TEX0.TW, + 1i64<TEX0.TH, + r->TEX0.TCC, + r->TEX0.TFX, + r->TEX0.CBP, + r->TEX0.CPSM, + r->TEX0.CSM, + r->TEX0.CSA, + r->TEX0.CLD); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].TEX0.i64 != r->TEX0.i64) + FlushPrimInternal(); + + m_de.CTXT[0].TEX0 = r->TEX0; + + //ASSERT(m_de.CTXT[0].TEX0.TW <= 10 && m_de.CTXT[0].TEX0.TH <= 10); + if(m_de.CTXT[0].TEX0.TW > 10) m_de.CTXT[0].TEX0.TW = 10; + if(m_de.CTXT[0].TEX0.TH > 10) m_de.CTXT[0].TEX0.TH = 10; + m_de.CTXT[0].TEX0.CPSM &= 0xa; // 1010b + + m_de.CTXT[0].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].TEX0.PSM]; + + FlushWriteTransfer(); + + m_lm.WriteCLUT(r->TEX0, m_de.TEXCLUT); +} + +void __fastcall GSState::GIFRegHandlerTEX0_2(GIFReg* r) +{ + LOG(_T("TEX0_2(TBP0=%I64x TBW=%I64d PSM=%I64x TW=%I64d TH=%I64d TCC=%I64x TFX=%I64x CBP=%I64x CPSM=%I64x CSM=%I64x CSA=%I64x CLD=%I64x)\n"), + r->TEX0.TBP0, + r->TEX0.TBW*64, + r->TEX0.PSM, + 1i64<TEX0.TW, + 1i64<TEX0.TH, + r->TEX0.TCC, + r->TEX0.TFX, + r->TEX0.CBP, + r->TEX0.CPSM, + r->TEX0.CSM, + r->TEX0.CSA, + r->TEX0.CLD); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].TEX0.i64 != r->TEX0.i64) + FlushPrimInternal(); + + m_de.CTXT[1].TEX0 = r->TEX0; + + //ASSERT(m_de.CTXT[1].TEX0.TW <= 10 && m_de.CTXT[1].TEX0.TH <= 10); + if(m_de.CTXT[1].TEX0.TW > 10) m_de.CTXT[1].TEX0.TW = 10; + if(m_de.CTXT[1].TEX0.TH > 10) m_de.CTXT[1].TEX0.TH = 10; + m_de.CTXT[1].TEX0.CPSM &= 0xa; // 1010b + + m_de.CTXT[1].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].TEX0.PSM]; + + FlushWriteTransfer(); + + m_lm.WriteCLUT(r->TEX0, m_de.TEXCLUT); +} + +void __fastcall GSState::GIFRegHandlerCLAMP_1(GIFReg* r) +{ + LOG(_T("CLAMP_1(WMS=%x WMT=%x MINU=%x MAXU=%x MINV=%x MAXV=%x)\n"), + r->CLAMP.WMS, + r->CLAMP.WMT, + r->CLAMP.MINU, + r->CLAMP.MAXU, + r->CLAMP.MINV, + r->CLAMP.MAXV); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].CLAMP.i64 != r->CLAMP.i64) + FlushPrimInternal(); + + m_de.CTXT[0].CLAMP = r->CLAMP; +} + +void __fastcall GSState::GIFRegHandlerCLAMP_2(GIFReg* r) +{ + LOG(_T("CLAMP_2(WMS=%x WMT=%x MINU=%x MAXU=%x MINV=%x MAXV=%x)\n"), + r->CLAMP.WMS, + r->CLAMP.WMT, + r->CLAMP.MINU, + r->CLAMP.MAXU, + r->CLAMP.MINV, + r->CLAMP.MAXV); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].CLAMP.i64 != r->CLAMP.i64) + FlushPrimInternal(); + + m_de.CTXT[1].CLAMP = r->CLAMP; +} + +void __fastcall GSState::GIFRegHandlerFOG(GIFReg* r) +{ + LOG(_T("FOG(F=%x)\n"), + r->FOG.F); + + m_v.FOG = r->FOG; +} + +void __fastcall GSState::GIFRegHandlerXYZF3(GIFReg* r) +{ + LOG(_T("XYZF3(X=%.2f Y=%.2f Z=%08x F=%d)\n"), + (float)r->XYZF.X/16, + (float)r->XYZF.Y/16, + r->XYZF.Z, + r->XYZF.F); +/* + m_v.XYZ.X = r->XYZF.X; + m_v.XYZ.Y = r->XYZF.Y; + m_v.XYZ.Z = r->XYZF.Z; + m_v.FOG.F = r->XYZF.F; +*/ + m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; + m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; + m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; + + VertexKick(true); +} + +void __fastcall GSState::GIFRegHandlerXYZ3(GIFReg* r) +{ + LOG(_T("XYZ3(X=%.2f Y=%.2f Z=%08x)\n"), + (float)r->XYZ.X/16, + (float)r->XYZ.Y/16, + r->XYZ.Z); + + m_v.XYZ = r->XYZ; + + VertexKick(true); +} + +void __fastcall GSState::GIFRegHandlerNOP(GIFReg* r) +{ + LOG(_T("NOP()\n")); +} + +void __fastcall GSState::GIFRegHandlerTEX1_1(GIFReg* r) +{ + LOG(_T("TEX1_1(LCM=%x MXL=%x MMAG=%x MMIN=%x MTBA=%x L=%x K=%x)\n"), + r->TEX1.LCM, + r->TEX1.MXL, + r->TEX1.MMAG, + r->TEX1.MMIN, + r->TEX1.MTBA, + r->TEX1.L, + r->TEX1.K); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].TEX1.i64 != r->TEX1.i64) + FlushPrimInternal(); + + m_de.CTXT[0].TEX1 = r->TEX1; +} + +void __fastcall GSState::GIFRegHandlerTEX1_2(GIFReg* r) +{ + LOG(_T("TEX1_2(LCM=%x MXL=%x MMAG=%x MMIN=%x MTBA=%x L=%x K=%x)\n"), + r->TEX1.LCM, + r->TEX1.MXL, + r->TEX1.MMAG, + r->TEX1.MMIN, + r->TEX1.MTBA, + r->TEX1.L, + r->TEX1.K); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].TEX1.i64 != r->TEX1.i64) + FlushPrimInternal(); + + m_de.CTXT[1].TEX1 = r->TEX1; +} + +void __fastcall GSState::GIFRegHandlerTEX2_1(GIFReg* r) +{ + LOG(_T("TEX2_1(PSM=%x CBP=%x CPSM=%x CSM=%x CSA=%x CLD=%x)\n"), + r->TEX2.PSM, + r->TEX2.CBP, + r->TEX2.CPSM, + r->TEX2.CSM, + r->TEX2.CSA, + r->TEX2.CLD); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].TEX2.i64 != r->TEX2.i64) + FlushPrimInternal(); + + m_de.CTXT[0].TEX2 = r->TEX2; + + FlushWriteTransfer(); + + m_lm.WriteCLUT(*(GIFRegTEX0*)&r->TEX2, m_de.TEXCLUT); +} + +void __fastcall GSState::GIFRegHandlerTEX2_2(GIFReg* r) +{ + LOG(_T("TEX2_2(PSM=%x CBP=%x CPSM=%x CSM=%x CSA=%x CLD=%x)\n"), + r->TEX2.PSM, + r->TEX2.CBP, + r->TEX2.CPSM, + r->TEX2.CSM, + r->TEX2.CSA, + r->TEX2.CLD); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].TEX2.i64 != r->TEX2.i64) + FlushPrimInternal(); + + m_de.CTXT[1].TEX2 = r->TEX2; + + FlushWriteTransfer(); + + m_lm.WriteCLUT(*(GIFRegTEX0*)&r->TEX2, m_de.TEXCLUT); +} + +void __fastcall GSState::GIFRegHandlerXYOFFSET_1(GIFReg* r) +{ + LOG(_T("XYOFFSET_1(OFX=%.2f OFY=%.2f)\n"), + (float)r->XYOFFSET.OFX/16, + (float)r->XYOFFSET.OFY/16); + + m_de.CTXT[0].XYOFFSET = r->XYOFFSET; +} + +void __fastcall GSState::GIFRegHandlerXYOFFSET_2(GIFReg* r) +{ + LOG(_T("XYOFFSET_2(OFX=%.2f OFY=%.2f)\n"), + (float)r->XYOFFSET.OFX/16, + (float)r->XYOFFSET.OFY/16); + + m_de.CTXT[1].XYOFFSET = r->XYOFFSET; +} + +void __fastcall GSState::GIFRegHandlerPRMODECONT(GIFReg* r) +{ + LOG(_T("PRMODECONT(AC=%x)\n"), + r->PRMODECONT.AC); + + if(m_de.PRMODECONT.i64 != r->PRMODECONT.i64) + { + FlushPrimInternal(); + } + + m_de.PRMODECONT = r->PRMODECONT; + + m_pPRIM = !m_de.PRMODECONT.AC ? (GIFRegPRIM*)&m_de.PRMODE : &m_de.PRIM; + m_ctxt = &m_de.CTXT[m_pPRIM->CTXT]; +} + +void __fastcall GSState::GIFRegHandlerPRMODE(GIFReg* r) +{ + LOG(_T("PRMODE(IIP=%x TME=%x FGE=%x ABE=%x AA1=%x FST=%x CTXT=%x FIX=%x)\n"), + r->PRMODE.IIP, + r->PRMODE.TME, + r->PRMODE.FGE, + r->PRMODE.ABE, + r->PRMODE.AA1, + r->PRMODE.FST, + r->PRMODE.CTXT, + r->PRMODE.FIX); + + if(!m_de.PRMODECONT.AC) + FlushPrimInternal(); + + UINT32 _PRIM = m_de.PRMODE._PRIM; + m_de.PRMODE = r->PRMODE; + m_de.PRMODE._PRIM = _PRIM; + + m_ctxt = &m_de.CTXT[m_pPRIM->CTXT]; +} + +void __fastcall GSState::GIFRegHandlerTEXCLUT(GIFReg* r) +{ + LOG(_T("TEXCLUT(CBW=%x COU=%x COV=%x)\n"), + r->TEXCLUT.CBW, + r->TEXCLUT.COU, + r->TEXCLUT.COV); + + if(m_de.TEXCLUT.i64 != r->TEXCLUT.i64) + FlushPrimInternal(); + + m_de.TEXCLUT = r->TEXCLUT; +} + +void __fastcall GSState::GIFRegHandlerSCANMSK(GIFReg* r) +{ + LOG(_T("SCANMSK(MSK=%x)\n"), + r->SCANMSK.MSK); + + if(m_de.SCANMSK.i64 != r->SCANMSK.i64) + FlushPrimInternal(); + + m_de.SCANMSK = r->SCANMSK; +} + +void __fastcall GSState::GIFRegHandlerMIPTBP1_1(GIFReg* r) +{ + LOG(_T("MIPTBP1_1(TBP1=%x TBW1=%x TBP2=%x TBW2=%x TBP3=%x TBW3=%x)\n"), + r->MIPTBP1.TBP1, + r->MIPTBP1.TBW1, + r->MIPTBP1.TBP2, + r->MIPTBP1.TBW2, + r->MIPTBP1.TBP3, + r->MIPTBP1.TBW3); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].MIPTBP1.i64 != r->MIPTBP1.i64) + FlushPrimInternal(); + + m_de.CTXT[0].MIPTBP1 = r->MIPTBP1; +} + +void __fastcall GSState::GIFRegHandlerMIPTBP1_2(GIFReg* r) +{ + LOG(_T("MIPTBP1_2(TBP1=%x TBW1=%x TBP2=%x TBW2=%x TBP3=%x TBW3=%x)\n"), + r->MIPTBP1.TBP1, + r->MIPTBP1.TBW1, + r->MIPTBP1.TBP2, + r->MIPTBP1.TBW2, + r->MIPTBP1.TBP3, + r->MIPTBP1.TBW3); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].MIPTBP1.i64 != r->MIPTBP1.i64) + FlushPrimInternal(); + + m_de.CTXT[1].MIPTBP1 = r->MIPTBP1; +} + +void __fastcall GSState::GIFRegHandlerMIPTBP2_1(GIFReg* r) +{ + LOG(_T("MIPTBP2_1(TBP4=%x TBW4=%x TBP5=%x TBW5=%x TBP6=%x TBW6=%x)\n"), + r->MIPTBP2.TBP4, + r->MIPTBP2.TBW4, + r->MIPTBP2.TBP5, + r->MIPTBP2.TBW5, + r->MIPTBP2.TBP6, + r->MIPTBP2.TBW6); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].MIPTBP2.i64 != r->MIPTBP2.i64) + FlushPrimInternal(); + + m_de.CTXT[0].MIPTBP2 = r->MIPTBP2; +} + +void __fastcall GSState::GIFRegHandlerMIPTBP2_2(GIFReg* r) +{ + LOG(_T("MIPTBP2_2(TBP4=%x TBW4=%x TBP5=%x TBW5=%x TBP6=%x TBW6=%x)\n"), + r->MIPTBP2.TBP4, + r->MIPTBP2.TBW4, + r->MIPTBP2.TBP5, + r->MIPTBP2.TBW5, + r->MIPTBP2.TBP6, + r->MIPTBP2.TBW6); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].MIPTBP2.i64 != r->MIPTBP2.i64) + FlushPrimInternal(); + + m_de.CTXT[1].MIPTBP2 = r->MIPTBP2; +} + +void __fastcall GSState::GIFRegHandlerTEXA(GIFReg* r) +{ + LOG(_T("TEXA(TA0=%x AEM=%x TA1=%x)\n"), + r->TEXA.TA0, + r->TEXA.AEM, + r->TEXA.TA1); + + if(m_de.TEXA.i64 != r->TEXA.i64) + FlushPrimInternal(); + + m_de.TEXA = r->TEXA; +} + +void __fastcall GSState::GIFRegHandlerFOGCOL(GIFReg* r) +{ + LOG(_T("FOGCOL(FCR=%x FCG=%x FCB=%x)\n"), + r->FOGCOL.FCR, + r->FOGCOL.FCG, + r->FOGCOL.FCB); + + if(m_de.FOGCOL.i64 != r->FOGCOL.i64) + FlushPrimInternal(); + + m_de.FOGCOL = r->FOGCOL; +} + +void __fastcall GSState::GIFRegHandlerTEXFLUSH(GIFReg* r) +{ + LOG(_T("TEXFLUSH()\n")); + + // what should we do here? +} + +void __fastcall GSState::GIFRegHandlerSCISSOR_1(GIFReg* r) +{ + LOG(_T("SCISSOR_1(SCAX0=%d SCAX1=%d SCAY0=%d SCAY1=%d)\n"), + r->SCISSOR.SCAX0, + r->SCISSOR.SCAX1, + r->SCISSOR.SCAY0, + r->SCISSOR.SCAY1); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].SCISSOR.i64 != r->SCISSOR.i64) + FlushPrimInternal(); + + m_de.CTXT[0].SCISSOR = r->SCISSOR; +} + +void __fastcall GSState::GIFRegHandlerSCISSOR_2(GIFReg* r) +{ + LOG(_T("SCISSOR_2(SCAX0=%d SCAX1=%d SCAY0=%d SCAY1=%d)\n"), + r->SCISSOR.SCAX0, + r->SCISSOR.SCAX1, + r->SCISSOR.SCAY0, + r->SCISSOR.SCAY1); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].SCISSOR.i64 != r->SCISSOR.i64) + FlushPrimInternal(); + + m_de.CTXT[1].SCISSOR = r->SCISSOR; +} + +void __fastcall GSState::GIFRegHandlerALPHA_1(GIFReg* r) +{ + LOG(_T("ALPHA_1(A=%x B=%x C=%x D=%x FIX=%x)\n"), + r->ALPHA.A, + r->ALPHA.B, + r->ALPHA.C, + r->ALPHA.D, + r->ALPHA.FIX); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].ALPHA.i64 != r->ALPHA.i64) + FlushPrimInternal(); + + m_de.CTXT[0].ALPHA = r->ALPHA; +} + +void __fastcall GSState::GIFRegHandlerALPHA_2(GIFReg* r) +{ + LOG(_T("ALPHA_2(A=%x B=%x C=%x D=%x FIX=%x)\n"), + r->ALPHA.A, + r->ALPHA.B, + r->ALPHA.C, + r->ALPHA.D, + r->ALPHA.FIX); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].ALPHA.i64 != r->ALPHA.i64) + FlushPrimInternal(); + + m_de.CTXT[1].ALPHA = r->ALPHA; +} + +void __fastcall GSState::GIFRegHandlerDIMX(GIFReg* r) +{ + LOG(_T("DIMX([%d,%d,%d,%d][%d,%d,%d,%d][%d,%d,%d,%d][%d,%d,%d,%d])\n"), + r->DIMX.DM00, + r->DIMX.DM01, + r->DIMX.DM02, + r->DIMX.DM03, + r->DIMX.DM10, + r->DIMX.DM11, + r->DIMX.DM12, + r->DIMX.DM13, + r->DIMX.DM20, + r->DIMX.DM21, + r->DIMX.DM22, + r->DIMX.DM23, + r->DIMX.DM30, + r->DIMX.DM31, + r->DIMX.DM32, + r->DIMX.DM33); + + if(m_de.DIMX.i64 != r->DIMX.i64) + FlushPrimInternal(); + + m_de.DIMX = r->DIMX; +} + +void __fastcall GSState::GIFRegHandlerDTHE(GIFReg* r) +{ + LOG(_T("DTHE(DTHE=%x)\n"), + r->DTHE.DTHE); + + if(m_de.DTHE.i64 != r->DTHE.i64) + FlushPrimInternal(); + + m_de.DTHE = r->DTHE; +} + +void __fastcall GSState::GIFRegHandlerCOLCLAMP(GIFReg* r) +{ + LOG(_T("COLCLAMP(CLAMP=%x)\n"), + r->COLCLAMP.CLAMP); + + if(m_de.COLCLAMP.i64 != r->COLCLAMP.i64) + FlushPrimInternal(); + + m_de.COLCLAMP = r->COLCLAMP; +} + +void __fastcall GSState::GIFRegHandlerTEST_1(GIFReg* r) +{ + LOG(_T("TEST_1(ATE=%x ATST=%x AREF=%x AFAIL=%x DATE=%x DATM=%x ZTE=%x ZTST=%x)\n"), + r->TEST.ATE, + r->TEST.ATST, + r->TEST.AREF, + r->TEST.AFAIL, + r->TEST.DATE, + r->TEST.DATM, + r->TEST.ZTE, + r->TEST.ZTST); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].TEST.i64 != r->TEST.i64) + FlushPrimInternal(); + + m_de.CTXT[0].TEST = r->TEST; +} + +void __fastcall GSState::GIFRegHandlerTEST_2(GIFReg* r) +{ + LOG(_T("TEST_2(ATE=%x ATST=%x AREF=%x AFAIL=%x DATE=%x DATM=%x ZTE=%x ZTST=%x)\n"), + r->TEST.ATE, + r->TEST.ATST, + r->TEST.AREF, + r->TEST.AFAIL, + r->TEST.DATE, + r->TEST.DATM, + r->TEST.ZTE, + r->TEST.ZTST); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].TEST.i64 != r->TEST.i64) + FlushPrimInternal(); + + m_de.CTXT[1].TEST = r->TEST; +} + +void __fastcall GSState::GIFRegHandlerPABE(GIFReg* r) +{ + LOG(_T("PABE(PABE=%x)\n"), + r->PABE.PABE); + + if(m_de.PABE.i64 != r->PABE.i64) + FlushPrimInternal(); + + m_de.PABE = r->PABE; +} + +void __fastcall GSState::GIFRegHandlerFBA_1(GIFReg* r) +{ + LOG(_T("FBA_1(FBA=%x)\n"), + r->FBA.FBA); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].FBA.i64 != r->FBA.i64) + FlushPrimInternal(); + + m_de.CTXT[0].FBA = r->FBA; +} + +void __fastcall GSState::GIFRegHandlerFBA_2(GIFReg* r) +{ + LOG(_T("FBA_2(FBA=%x)\n"), + r->FBA.FBA); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].FBA.i64 != r->FBA.i64) + FlushPrimInternal(); + + m_de.CTXT[1].FBA = r->FBA; +} + +void __fastcall GSState::GIFRegHandlerFRAME_1(GIFReg* r) +{ + LOG(_T("FRAME_1(FBP=%x FBW=%d PSM=%x FBMSK=%x)\n"), + r->FRAME.Block(), + r->FRAME.FBW*64, + r->FRAME.PSM, + r->FRAME.FBMSK); + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].FRAME.i64 != r->FRAME.i64) + FlushPrimInternal(); + + m_de.CTXT[0].FRAME = r->FRAME; + + m_de.CTXT[0].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].FRAME.PSM]; +} + +void __fastcall GSState::GIFRegHandlerFRAME_2(GIFReg* r) +{ + LOG(_T("FRAME_2(FBP=%x FBW=%d PSM=%x FBMSK=%x)\n"), + r->FRAME.Block(), + r->FRAME.FBW*64, + r->FRAME.PSM, + r->FRAME.FBMSK); + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].FRAME.i64 != r->FRAME.i64) + FlushPrimInternal(); + + m_de.CTXT[1].FRAME = r->FRAME; + + m_de.CTXT[1].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].FRAME.PSM]; +} + +void __fastcall GSState::GIFRegHandlerZBUF_1(GIFReg* r) +{ + LOG(_T("ZBUF_1(ZBP=%x PSM=%x ZMSK=%x)\n"), + r->ZBUF.ZBP<<5, + r->ZBUF.PSM, + r->ZBUF.ZMSK); + + r->ZBUF.PSM |= 0x30; + + if(m_pPRIM->CTXT == 0 && m_de.CTXT[0].ZBUF.i64 != r->ZBUF.i64) + FlushPrimInternal(); + + m_de.CTXT[0].ZBUF = r->ZBUF; + + if(m_de.CTXT[0].ZBUF.PSM != PSM_PSMZ32 + && m_de.CTXT[0].ZBUF.PSM != PSM_PSMZ24 + && m_de.CTXT[0].ZBUF.PSM != PSM_PSMZ16 + && m_de.CTXT[0].ZBUF.PSM != PSM_PSMZ16S) + m_de.CTXT[0].ZBUF.PSM = PSM_PSMZ32; + + m_de.CTXT[0].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].ZBUF.PSM]; +} + +void __fastcall GSState::GIFRegHandlerZBUF_2(GIFReg* r) +{ + LOG(_T("ZBUF_2(ZBP=%x PSM=%x ZMSK=%x)\n"), + r->ZBUF.ZBP<<5, + r->ZBUF.PSM, + r->ZBUF.ZMSK); + + r->ZBUF.PSM |= 0x30; + + if(m_pPRIM->CTXT == 1 && m_de.CTXT[1].ZBUF.i64 != r->ZBUF.i64) + FlushPrimInternal(); + + m_de.CTXT[1].ZBUF = r->ZBUF; + + if(m_de.CTXT[1].ZBUF.PSM != PSM_PSMZ32 + && m_de.CTXT[1].ZBUF.PSM != PSM_PSMZ24 + && m_de.CTXT[1].ZBUF.PSM != PSM_PSMZ16 + && m_de.CTXT[1].ZBUF.PSM != PSM_PSMZ16S) + m_de.CTXT[1].ZBUF.PSM = PSM_PSMZ32; + + m_de.CTXT[1].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].ZBUF.PSM]; +} + +void __fastcall GSState::GIFRegHandlerBITBLTBUF(GIFReg* r) +{ + LOG(_T("BITBLTBUF(SBP=%x SBW=%d SPSM=%x DBP=%x DBW=%d DPSM=%x)\n"), + r->BITBLTBUF.SBP, + r->BITBLTBUF.SBW*64, + r->BITBLTBUF.SPSM, + r->BITBLTBUF.DBP, + r->BITBLTBUF.DBW*64, + r->BITBLTBUF.DPSM); + + if(m_de.BITBLTBUF.i64 != r->BITBLTBUF.i64) + FlushWriteTransfer(); + + m_de.BITBLTBUF = r->BITBLTBUF; +} + +void __fastcall GSState::GIFRegHandlerTRXPOS(GIFReg* r) +{ + LOG(_T("TRXPOS(SSAX=%d SSAY=%d DSAX=%d DSAY=%d DIR=%d)\n"), + r->TRXPOS.SSAX, + r->TRXPOS.SSAY, + r->TRXPOS.DSAX, + r->TRXPOS.DSAY, + r->TRXPOS.DIR); + + if(m_de.TRXPOS.i64 != r->TRXPOS.i64) + FlushWriteTransfer(); + + m_de.TRXPOS = r->TRXPOS; +} + +void __fastcall GSState::GIFRegHandlerTRXREG(GIFReg* r) +{ + LOG(_T("TRXREG(RRW=%d RRH=%d)\n"), + r->TRXREG.RRW, + r->TRXREG.RRH); + + if(m_de.TRXREG.i64 != r->TRXREG.i64 || m_de.TRXREG2.i64 != r->TRXREG.i64) + FlushWriteTransfer(); + + m_de.TRXREG = m_de.TRXREG2 = r->TRXREG; +} + +void __fastcall GSState::GIFRegHandlerTRXDIR(GIFReg* r) +{ + LOG(_T("TRXDIR(XDIR=%d)\n"), + r->TRXDIR.XDIR); + + FlushWriteTransfer(); + + FlushPrimInternal(); + + m_de.TRXDIR = r->TRXDIR; + + switch(m_de.TRXDIR.XDIR) + { + case 0: // host -> local + m_x = m_de.TRXPOS.DSAX; + m_y = m_de.TRXPOS.DSAY; + m_de.TRXREG.RRW = m_x + m_de.TRXREG2.RRW; + m_de.TRXREG.RRH = m_y + m_de.TRXREG2.RRH; + break; + case 1: // local -> host + m_x = m_de.TRXPOS.SSAX; + m_y = m_de.TRXPOS.SSAY; + m_de.TRXREG.RRW = m_x + m_de.TRXREG2.RRW; + m_de.TRXREG.RRH = m_y + m_de.TRXREG2.RRH; + break; + case 2: // local -> local + MoveTransfer(); + break; + case 3: + ASSERT(0); + break; + } +} + +void __fastcall GSState::GIFRegHandlerHWREG(GIFReg* r) +{ + LOG(_T("HWREG(DATA_LOWER=%08x DATA_UPPER=%08x)\n"), + r->HWREG.DATA_LOWER, + r->HWREG.DATA_UPPER); + + // TODO + + ASSERT(0); +} + +void __fastcall GSState::GIFRegHandlerSIGNAL(GIFReg* r) +{ + LOG(_T("SIGNAL(ID=%08x IDMSK=%08x)\n"), + r->SIGNAL.ID, + r->SIGNAL.IDMSK); + + if(m_fMultiThreaded) return; + + m_rs.pSIGLBLID->SIGID = (m_rs.pSIGLBLID->SIGID & ~r->SIGNAL.IDMSK) | (r->SIGNAL.ID & r->SIGNAL.IDMSK); + + if(m_rs.pCSR->wSIGNAL) m_rs.pCSR->rSIGNAL = 1; + if(!m_rs.pIMR->SIGMSK && m_fpGSirq) m_fpGSirq(); +} + +void __fastcall GSState::GIFRegHandlerFINISH(GIFReg* r) +{ + LOG(_T("FINISH()\n")); + + if(m_fMultiThreaded) return; + + if(m_rs.pCSR->wFINISH) m_rs.pCSR->rFINISH = 1; + if(!m_rs.pIMR->FINISHMSK && m_fpGSirq) m_fpGSirq(); +} + +void __fastcall GSState::GIFRegHandlerLABEL(GIFReg* r) +{ + LOG(_T("LABEL(ID=%08x IDMSK=%08x)\n"), + r->LABEL.ID, + r->LABEL.IDMSK); + + if(m_fMultiThreaded) return; + + m_rs.pSIGLBLID->LBLID = (m_rs.pSIGLBLID->LBLID & ~r->LABEL.IDMSK) | (r->LABEL.ID & r->LABEL.IDMSK); +} + diff --git a/plugins/gs/gsdx9/GSRenderer.cpp b/plugins/gs/gsdx9/GSRenderer.cpp new file mode 100644 index 0000000000..0035211283 --- /dev/null +++ b/plugins/gs/gsdx9/GSRenderer.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRenderer.h" diff --git a/plugins/gs/gsdx9/GSRenderer.h b/plugins/gs/gsdx9/GSRenderer.h new file mode 100644 index 0000000000..6e27aa3bba --- /dev/null +++ b/plugins/gs/gsdx9/GSRenderer.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSState.h" + +template +class GSRenderer : public GSState +{ +protected: + GSVertexList m_vl; + + VERTEX* m_pVertices; + int m_nMaxVertices, m_nVertices, m_nPrims; + + void Reset() + { + m_nVertices = m_nPrims = 0; + m_vl.RemoveAll(); + __super::Reset(); + } + + void VertexKick(bool fSkip) + { + LOG(_T("VertexKick(%d)\n"), fSkip); + + static const int vmin[8] = {1, 2, 2, 3, 3, 3, 2, 1}; + + while(m_vl.GetCount() >= vmin[m_pPRIM->PRIM]) + { + if(m_nVertices+6 > m_nMaxVertices) + { + VERTEX* pVertices = (VERTEX*)_aligned_malloc(sizeof(VERTEX) * (m_nMaxVertices <<= 1), 16); + memcpy(pVertices, m_pVertices, m_nVertices*sizeof(VERTEX)); + _aligned_free(m_pVertices); + m_pVertices = pVertices; + } + + LOG(_T("DrawingKick %d\n"), m_pPRIM->PRIM); + + if(m_PRIM != m_pPRIM->PRIM && m_nVertices > 0) FlushPrimInternal(); + m_PRIM = m_pPRIM->PRIM; + + LOG2(_T("Prim (%d) %05x %05x %05x %04x\n"), + m_PRIM, + m_ctxt->FRAME.Block(), + m_pPRIM->TME ? (UINT32)m_ctxt->TEX0.TBP0 : 0xfffff, + m_pPRIM->TME ? (UINT32)m_ctxt->TEX0.CBP : 0xfffff, + (m_pPRIM->ABE || (m_PRIM == 1 || m_PRIM == 2) && m_pPRIM->AA1) + ? ((m_ctxt->ALPHA.A<<12)|(m_ctxt->ALPHA.B<<8)|(m_ctxt->ALPHA.C<<4)|m_ctxt->ALPHA.D) + : 0xffff); + + m_nVertices += DrawingKick(fSkip); + +#ifdef DEBUG_RENDERTARGETS + if(::GetAsyncKeyState(VK_SPACE)&0x80000000) {FlushPrimInternal(); Flip();} +#endif + } + } + + void NewPrim() {m_vl.RemoveAll();} + void FlushPrim() {m_PRIM = 8; m_nVertices = 0;} + +public: + GSRenderer(int w, int h, HWND hWnd, HRESULT& hr) + : GSState(w, h, hWnd, hr) + { + m_pVertices = (VERTEX*)_aligned_malloc(sizeof(VERTEX) * (m_nMaxVertices = 256), 16); + Reset(); + } + + ~GSRenderer() + { + _aligned_free(m_pVertices); + } +}; \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSRendererHW.cpp b/plugins/gs/gsdx9/GSRendererHW.cpp new file mode 100644 index 0000000000..52dce24886 --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererHW.cpp @@ -0,0 +1,1310 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRendererHW.h" + +#define INTERNALRESX 1024 +#define INTERNALRESY 1024 + +inline BYTE SCALE_ALPHA(BYTE a) +{ + return (((a)&0x80)?0xff:((a)<<1)); +} + +static const float one_over_log_2pow32 = 1.0f / (log(2.0f)*32); + +// + +GSRendererHW::GSRendererHW(HWND hWnd, HRESULT& hr) + : GSRenderer(INTERNALRESX, INTERNALRESY, hWnd, hr) +{ + Reset(); +} + +GSRendererHW::~GSRendererHW() +{ +} + +HRESULT GSRendererHW::ResetDevice(bool fForceWindowed) +{ + m_pRTs.RemoveAll(); + m_pDSs.RemoveAll(); + m_tc.RemoveAll(); + + return __super::ResetDevice(fForceWindowed); +} + +void GSRendererHW::Reset() +{ + m_primtype = D3DPT_FORCE_DWORD; + + m_tc.RemoveAll(); + + m_pRTs.RemoveAll(); + m_pDSs.RemoveAll(); + + POSITION pos = m_pRenderWnds.GetStartPosition(); + while(pos) + { + DWORD FBP; + CGSWnd* pWnd = NULL; + m_pRenderWnds.GetNextAssoc(pos, FBP, pWnd); + pWnd->DestroyWindow(); + delete pWnd; + } + m_pRenderWnds.RemoveAll(); + + __super::Reset(); +} + +void GSRendererHW::VertexKick(bool fSkip) +{ + GSVertexHW& v = m_vl.AddTail(); + + v.x = (float)((int)m_v.XYZ.X - (int)m_ctxt->XYOFFSET.OFX) * (1.0f/16); + v.y = (float)((int)m_v.XYZ.Y - (int)m_ctxt->XYOFFSET.OFY) * (1.0f/16); + //if(m_v.XYZ.Z && m_v.XYZ.Z < 0x100) m_v.XYZ.Z = 0x100; + //v.z = 1.0f * (m_v.XYZ.Z>>8)/(UINT_MAX>>8); + v.z = log(1.0f + m_v.XYZ.Z) * one_over_log_2pow32; + //v.z = (float)m_v.XYZ.Z / UINT_MAX; + //v.rhw = v.z ? 1.0f/v.z : 1.0f; + v.rhw = m_v.RGBAQ.Q > 0 ? m_v.RGBAQ.Q : 1.0f; // TODO + //v.rhw = m_v.RGBAQ.Q; + + v.color = m_v.RGBAQ.ai32[0]; + + if(m_pPRIM->TME) + { + if(m_pPRIM->FST) + { + v.tu = (float)(int)m_v.UV.U / (16 << m_ctxt->TEX0.TW); + v.tv = (float)(int)m_v.UV.V / (16 << m_ctxt->TEX0.TH); + v.rhw = 1.0f; + } + else + { + float w = m_v.RGBAQ.Q ? 1.0f / m_v.RGBAQ.Q : 1.0f; + v.tu = m_v.ST.S * w; + v.tv = m_v.ST.T * w; + } + } + else + { + v.a = SCALE_ALPHA(v.a); + } + + v.fog = (m_pPRIM->FGE ? m_v.FOG.F : 0xff) << 24; + + __super::VertexKick(fSkip); +} + +int GSRendererHW::DrawingKick(bool fSkip) +{ + GSVertexHW* pVertices = &m_pVertices[m_nVertices]; + int nVertices = 0; + + CRect sc(m_ctxt->SCISSOR.SCAX0, m_ctxt->SCISSOR.SCAY0, m_ctxt->SCISSOR.SCAX1+1, m_ctxt->SCISSOR.SCAY1+1); + + switch(m_PRIM) + { + case 3: // triangle list + m_primtype = D3DPT_TRIANGLELIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left && pVertices[nVertices-3].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top && pVertices[nVertices-3].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right && pVertices[nVertices-3].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom && pVertices[nVertices-3].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("TriList"))); + LOGV((pVertices[1], _T("TriList"))); + LOGV((pVertices[2], _T("TriList"))); + break; + case 4: // triangle strip + m_primtype = D3DPT_TRIANGLELIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.GetAt(0, pVertices[nVertices++]); + m_vl.GetAt(1, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left && pVertices[nVertices-3].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top && pVertices[nVertices-3].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right && pVertices[nVertices-3].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom && pVertices[nVertices-3].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("TriStrip"))); + LOGV((pVertices[1], _T("TriStrip"))); + LOGV((pVertices[2], _T("TriStrip"))); + break; + case 5: // triangle fan + m_primtype = D3DPT_TRIANGLELIST; + m_vl.GetAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(1, pVertices[nVertices++]); + m_vl.GetAt(1, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left && pVertices[nVertices-3].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top && pVertices[nVertices-3].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right && pVertices[nVertices-3].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom && pVertices[nVertices-3].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("TriFan"))); + LOGV((pVertices[1], _T("TriFan"))); + LOGV((pVertices[2], _T("TriFan"))); + break; + case 6: // sprite + m_primtype = D3DPT_TRIANGLELIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom) + return 0; + nVertices += 2; + +/* + float lod; + if(m_ctxt->TEX1.LCM) lod = -log(pVertices[nVertices-1].rhw)/log(2.0f) * (1 << m_ctxt->TEX1.L) + m_ctxt->TEX1.K; + else lod = m_ctxt->TEX1.K; + + int filter; + if(lod < 0) filter = m_ctxt->TEX1.MMAG&1; + else filter = m_ctxt->TEX1.MMIN&1; + +// if(!filter) + { + pVertices[nVertices-2].x -= 0.5f; + pVertices[nVertices-2].y -= 0.5f; + pVertices[nVertices-1].x -= 0.5f; + pVertices[nVertices-1].y -= 0.5f; + } +*/ + // ASSERT(pVertices[0].z == pVertices[1].z); + pVertices[0].z = pVertices[1].z; + pVertices[2] = pVertices[1]; + pVertices[3] = pVertices[1]; + pVertices[1].y = pVertices[0].y; + pVertices[1].tv = pVertices[0].tv; + pVertices[2].x = pVertices[0].x; + pVertices[2].tu = pVertices[0].tu; + LOGV((pVertices[0], _T("Sprite"))); + LOGV((pVertices[1], _T("Sprite"))); + LOGV((pVertices[2], _T("Sprite"))); + LOGV((pVertices[3], _T("Sprite"))); + nVertices += 2; + pVertices[5] = pVertices[3]; + pVertices[3] = pVertices[1]; + pVertices[4] = pVertices[2]; + break; + case 1: // line + m_primtype = D3DPT_LINELIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("LineList"))); + LOGV((pVertices[1], _T("LineList"))); + break; + case 2: // line strip + m_primtype = D3DPT_LINELIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.GetAt(0, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left && pVertices[nVertices-2].x < sc.left + || pVertices[nVertices-1].y < sc.top && pVertices[nVertices-2].y < sc.top + || pVertices[nVertices-1].x >= sc.right && pVertices[nVertices-2].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom && pVertices[nVertices-2].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("LineStrip"))); + LOGV((pVertices[1], _T("LineStrip"))); + break; + case 0: // point + m_primtype = D3DPT_POINTLIST; + m_vl.RemoveAt(0, pVertices[nVertices++]); + if(pVertices[nVertices-1].x < sc.left + || pVertices[nVertices-1].y < sc.top + || pVertices[nVertices-1].x >= sc.right + || pVertices[nVertices-1].y >= sc.bottom) + return 0; + LOGV((pVertices[0], _T("PointList"))); + break; + default: + //ASSERT(0); + m_vl.RemoveAll(); + return 0; + } +/* + int gt = 0; + for(int i = 0; i < nVertices; i++) + if(pVertices[i].rhw > 0) gt++; + if(gt != nVertices) + return 0; +*/ + if(fSkip || !m_rs.IsEnabled(0) && !m_rs.IsEnabled(1)) + return 0; + + if(!m_pPRIM->IIP) + { + pVertices[0].color = pVertices[nVertices-1].color; + if(m_PRIM == 6) pVertices[3].color = pVertices[5].color; + /*for(int i = nVertices-1; i > 0; i--) + pVertices[i-1].color = pVertices[i].color;*/ + } + + return nVertices; +} + +void GSRendererHW::FlushPrim() +{ + if(m_nVertices > 0 && !(m_pPRIM->TME && HasSharedBits(m_ctxt->TEX0.TBP0, m_ctxt->TEX0.PSM, m_ctxt->FRAME.Block(), m_ctxt->FRAME.PSM))) + do + { + int nPrims = 0; + + switch(m_primtype) + { + case D3DPT_TRIANGLELIST: ASSERT(!(m_nVertices%3)); nPrims = m_nVertices/3; break; + case D3DPT_TRIANGLESTRIP: ASSERT(m_nVertices > 2); nPrims = m_nVertices-2; break; + case D3DPT_TRIANGLEFAN: ASSERT(m_nVertices > 2); nPrims = m_nVertices-2; break; + case D3DPT_LINELIST: ASSERT(!(m_nVertices&1)); nPrims = m_nVertices/2; break; + case D3DPT_LINESTRIP: ASSERT(m_nVertices > 1); nPrims = m_nVertices-1; break; + case D3DPT_POINTLIST: nPrims = m_nVertices; break; + default: ASSERT(0); return; + } + + LOG(_T("FlushPrim(pt=%d, nVertices=%d, nPrims=%d)\n"), m_primtype, m_nVertices, nPrims); + + m_perfmon.IncCounter(GSPerfMon::c_prim, nPrims); + + ////////////////////// + + HRESULT hr; + + scale_t scale( + (float)m_bd.Width / (m_ctxt->FRAME.FBW*64), +// (float)m_bd.Width / m_rs.GetDispRect(m_rs.IsEnabled(1)?1:0).right, + (float)m_bd.Height / m_rs.GetDispRect(m_rs.IsEnabled(1)?1:0).bottom); + + ////////////////////// + + CComPtr pRT; + CComPtr pDS; + + bool fClearRT = false; + bool fClearDS = false; + + if(!m_pRTs.Lookup(m_ctxt->FRAME.Block(), pRT)) + { + hr = m_pD3DDev->CreateTexture(m_bd.Width, m_bd.Height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pRT, NULL); + if(S_OK != hr) {ASSERT(0); return;} + m_pRTs[m_ctxt->FRAME.Block()] = pRT; +#ifdef DEBUG_RENDERTARGETS + CGSWnd* pWnd = NULL; + if(!m_pRenderWnds.Lookup(m_ctxt->FRAME.Block(), pWnd)) + { + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + pWnd = new CGSWnd(); + CString str; str.Format(_T("%05x"), m_ctxt->FRAME.Block()); + pWnd->Create(str); + m_pRenderWnds[m_ctxt->FRAME.Block()] = pWnd; + pWnd->Show(); + } +#endif + fClearRT = true; + } + + if(!m_pDSs.Lookup(m_ctxt->ZBUF.ZBP, pDS)) + { + hr = m_pD3DDev->CreateDepthStencilSurface(m_bd.Width, m_bd.Height, m_fmtDepthStencil, D3DMULTISAMPLE_NONE, 0, FALSE, &pDS, NULL); + if(S_OK != hr) {ASSERT(0); return;} + m_pDSs[m_ctxt->ZBUF.ZBP] = pDS; + fClearDS = true; + } + + if(!pRT || !pDS) {ASSERT(0); return;} + + ////////////////////// + + GSTextureBase t; + + if(m_pPRIM->TME) + { +if(m_ctxt->TEX0.TBP0 == 0x800) +{ + int i = 0; +} + + bool fFetched = + m_fEnablePalettizedTextures && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) ? m_tc.FetchP(this, t) : + m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) ? m_tc.FetchNP(this, t) : + m_tc.Fetch(this, t); + + if(!fFetched) break; + + if(nPrims > 100 && t.m_pPalette) // TODO: find the optimal value for nPrims > ? + { + CComPtr pRT; + hr = m_pD3DDev->CreateTexture(t.m_desc.Width, t.m_desc.Height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pRT, NULL); + + CComPtr pRTSurf; + hr = pRT->GetSurfaceLevel(0, &pRTSurf); + hr = m_pD3DDev->SetRenderTarget(0, pRTSurf); + hr = m_pD3DDev->SetDepthStencilSurface(NULL); + + hr = m_pD3DDev->SetTexture(0, t.m_pTexture); + hr = m_pD3DDev->SetTexture(1, t.m_pPalette); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RGBA); + + hr = m_pD3DDev->SetPixelShader(m_pHLSLTFX[37]); + + struct + { + float x, y, z, rhw; + float tu, tv; + } + pVertices[] = + { + {0, 0, 0.5f, 2.0f, 0, 0}, + {(float)t.m_desc.Width, 0, 0.5f, 2.0f, 1, 0}, + {0, (float)t.m_desc.Height, 0.5f, 2.0f, 0, 1}, + {(float)t.m_desc.Width, (float)t.m_desc.Height, 0.5f, 2.0f, 1, 1}, + }; + + hr = m_pD3DDev->BeginScene(); + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + hr = m_pD3DDev->EndScene(); + + t.m_pTexture = pRT; + t.m_pPalette = NULL; + + t.m_pTexture->GetLevelDesc(0, &t.m_desc); + } + } + + ////////////////////// + + hr = m_pD3DDev->BeginScene(); + + ////////////////////// + + CComPtr pSurf; + hr = pRT->GetSurfaceLevel(0, &pSurf); + hr = m_pD3DDev->SetRenderTarget(0, pSurf); + hr = m_pD3DDev->SetDepthStencilSurface(pDS); + if(fClearRT) hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); + if(fClearDS) hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0f, 0); + + D3DSURFACE_DESC rd; + ZeroMemory(&rd, sizeof(rd)); + pRT->GetLevelDesc(0, &rd); + + ////////////////////// + + hr = m_pD3DDev->SetRenderState(D3DRS_SHADEMODE, m_pPRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); + + ////////////////////// + + float tsx = 1.0f, tsy = 1.0f; + + if(m_pPRIM->TME) + { + tsx = 1.0f * (1 << m_ctxt->TEX0.TW) / t.m_desc.Width * t.m_scale.x; + tsy = 1.0f * (1 << m_ctxt->TEX0.TH) / t.m_desc.Height * t.m_scale.y; + } + + ASSERT(abs(tsx - 1.0f) < 0.001 && abs(tsy - 1.0f) < 0.001); + + SetupTexture(t, tsx, tsy); + + ////////////////////// + + SetupAlphaBlend(); + + ////////////////////// + + SetupColorMask(); + + ////////////////////// + + SetupZBuffer(); + + ////////////////////// + + SetupAlphaTest(); + + ////////////////////// + + SetupScissor(scale); + + scale.Set(pRT); + + ////////////////////// + + // ASSERT(!m_de.PABE.PABE); // bios + // ASSERT(!m_ctxt->FBA.FBA); // bios + // ASSERT(!m_ctxt->TEST.DATE); // sfex3 (after the capcom logo), vf4 (first menu fading in) + + ////////////////////// + + { + // hr = m_pD3DDev->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + // hr = m_pD3DDev->SetTexture(1, pRT); + + GSVertexHW* pVertices = m_pVertices; + for(int i = m_nVertices; i-- > 0; pVertices++) + { + pVertices->x *= scale.x; + pVertices->y *= scale.y; + + // pVertices->tu2 = pVertices->x / rd.Width; + // pVertices->tv2 = pVertices->y / rd.Height; + + if(m_pPRIM->TME) + { + // FIXME + float base, fract; + fract = modf(pVertices->tu, &base); + fract *= tsx; + //ASSERT(-1 <= fract && fract <= 1.01); + pVertices->tu = base + fract; + fract = modf(pVertices->tv, &base); + fract *= tsy; + //ASSERT(-1 <= fract && fract <= 1.01); + pVertices->tv = base + fract; + } + +/* + if(m_pPRIM->TME) + { + pVertices->tu *= tsx; + pVertices->tv *= tsy; + } +*/ + if(m_pPRIM->FGE) + { + pVertices->fog = (pVertices->fog & 0xff000000) | (m_de.FOGCOL.ai32[0] & 0x00ffffff); + // D3DCOLOR_ARGB(pVertices->fog >> 24, m_de.FOGCOL.FCB, m_de.FOGCOL.FCG, m_de.FOGCOL.FCR) + } + } + } + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX1); + + if(1)//!m_de.PABE.PABE) + { + hr = m_pD3DDev->DrawPrimitiveUP(m_primtype, nPrims, m_pVertices, sizeof(GSVertexHW)); + } +/* else + { + ASSERT(!m_ctxt->TEST.ATE); // TODO + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, 0xfe); + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->DrawPrimitive(m_primtype, 0, nPrims); + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + hr = m_pD3DDev->DrawPrimitive(m_primtype, 0, nPrims); + } +*/ + if(m_ctxt->TEST.ATE && m_ctxt->TEST.AFAIL && m_ctxt->TEST.ATST != 1) + { + ASSERT(!m_de.PABE.PABE); + + static const DWORD iafunc[] = {D3DCMP_ALWAYS, D3DCMP_NEVER, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL}; + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, iafunc[m_ctxt->TEST.ATST]); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)SCALE_ALPHA(m_ctxt->TEST.AREF)); + + int mask = 0; + bool zwrite = false; + + switch(m_ctxt->TEST.AFAIL) + { + case 0: break; // keep + case 1: mask = D3DCOLORWRITEENABLE_RGBA; break; // fbuf + case 2: zwrite = true; break; // zbuf + case 3: mask = D3DCOLORWRITEENABLE_RGB; break; // fbuf w/o alpha + default: __assume(0); + } + + hr = m_pD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, zwrite); + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, mask); + + if(mask || zwrite) + hr = m_pD3DDev->DrawPrimitiveUP(m_primtype, nPrims, m_pVertices, sizeof(GSVertexHW)); + } + + hr = m_pD3DDev->EndScene(); + + ////////////////////// + + GIFRegTEX0 TEX0; + TEX0.TBP0 = m_ctxt->FRAME.Block(); + TEX0.TBW = m_ctxt->FRAME.FBW; + TEX0.PSM = m_ctxt->FRAME.PSM; + m_tc.AddRT(TEX0, pRT, scale); + } + while(0); + + m_primtype = D3DPT_FORCE_DWORD; + + __super::FlushPrim(); +} + +void GSRendererHW::Flip() +{ + HRESULT hr; + + FlipInfo rt[2]; + + for(int i = 0; i < countof(rt); i++) + { + if(!m_rs.IsEnabled(i)) continue; + + DWORD FBP = m_rs.pDISPFB[i]->FBP<<5; + +#ifdef DEBUG_RENDERTARGETS + if(::GetAsyncKeyState(VK_SPACE)&0x80000000) FBP = m_ctxt->FRAME.Block(); +#endif + + CSurfMap::CPair* pPair = m_pRTs.PLookup(FBP); + + if(!pPair) + { + for(CSurfMap::CPair* pPair2 = m_pRTs.PGetFirstAssoc(); + pPair2; + pPair2 = m_pRTs.PGetNextAssoc(pPair2)) + { + if(pPair2->key <= FBP && (!pPair || pPair2->key >= pPair->key)) + { + pPair = pPair2; + } + } + } + + if(!pPair) + { + CComPtr pRT; + + if(S_OK == m_pD3DDev->CreateTexture(m_bd.Width, m_bd.Height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pRT, NULL)) + { + m_pRTs[FBP] = pRT; + + EXECUTE_ASSERT(pPair = m_pRTs.PLookup(FBP)); + +#ifdef DEBUG_RENDERTARGETS + CGSWnd* pWnd = NULL; + if(!m_pRenderWnds.Lookup(m_ctxt->FRAME.Block(), pWnd)) + { + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + pWnd = new CGSWnd(); + CString str; str.Format(_T("%05x"), FBP); + pWnd->Create(str); + m_pRenderWnds[FBP] = pWnd; + pWnd->Show(); + } +#endif + + CRect r = m_rs.GetDispRect(m_rs.IsEnabled(1)?1:0); + + scale_t scale( + (float)m_bd.Width / (m_rs.pDISPFB[i]->FBW*64), + // (float)m_bd.Width / m_rs.GetDispRect(m_rs.IsEnabled(1)?1:0).right, + (float)m_bd.Height / r.bottom); + + scale.Set(pRT); + + GIFRegTEX0 TEX0; + TEX0.TBP0 = m_rs.pDISPFB[i]->FBP; + TEX0.TBW = m_rs.pDISPFB[i]->FBW; + TEX0.PSM = m_rs.pDISPFB[i]->PSM; + + m_tc.AddRT(TEX0, pRT, scale); + + GIFRegBITBLTBUF BITBLTBUF; + BITBLTBUF.DBP = TEX0.TBP0; + BITBLTBUF.DBW = TEX0.TBW; + BITBLTBUF.DPSM = TEX0.PSM; + + m_tc.InvalidateTexture(this, BITBLTBUF, r); + } + } + + if(pPair) + { + m_tc.ResetAge(pPair->key); + + rt[i].pRT = pPair->value; + + ZeroMemory(&rt[i].rd, sizeof(rt[i].rd)); + hr = rt[i].pRT->GetLevelDesc(0, &rt[i].rd); + + rt[i].scale.Get(rt[i].pRT); + } + } + + FinishFlip(rt); + +#ifdef DEBUG_RENDERTARGETS + CRect dst(0, 0, m_bd.Width, m_bd.Height); + + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if(!m_pRenderWnds.IsEmpty()) + { + POSITION pos = m_pRenderWnds.GetStartPosition(); + while(pos) + { + DWORD fbp; + CGSWnd* pWnd = NULL; + m_pRenderWnds.GetNextAssoc(pos, fbp, pWnd); + + CComPtr pRT; + if(m_pRTs.Lookup(fbp, pRT)) + { + D3DSURFACE_DESC rd; + ZeroMemory(&rd, sizeof(rd)); + hr = pRT->GetLevelDesc(0, &rd); + + hr = m_pD3DDev->SetTexture(0, pRT); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + scale_t scale(pRT); + + CRect rect = m_rs.GetDispRect(m_rs.IsEnabled(1)?1:0); + //CSize size = m_rs.GetSize(m_rs.IsEnabled(1)?1:0); + CRect src = CRect(0, 0, scale.x*rect.right, scale.y*rect.bottom); + + struct + { + float x, y, z, rhw; + float tu, tv; + } + pVertices[] = + { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / rd.Width, (float)src.top / rd.Height}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / rd.Width, (float)src.top / rd.Height}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / rd.Width, (float)src.bottom / rd.Height}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / rd.Width, (float)src.bottom / rd.Height}, + }; + + for(int i = 0; i < countof(pVertices); i++) + { + pVertices[i].x -= 0.5; + pVertices[i].y -= 0.5; + } + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + hr = m_pD3DDev->SetPixelShader(NULL); + + hr = m_pD3DDev->BeginScene(); + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + hr = m_pD3DDev->EndScene(); + + hr = m_pD3DDev->Present(NULL, NULL, pWnd->m_hWnd, NULL); + + hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); + + CString str; + str.Format(_T("PCSX2 - %05x - %05x"), fbp, m_ctxt->TEX0.TBP0); + if(fbp == (m_ctxt->FRAME.Block())) + { + // pWnd->SetFocus(); + str += _T(" - Drawing"); + } + pWnd->SetWindowText(str); + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while(msg.message != WM_QUIT) + { + if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#ifdef DEBUG_RENDERTARGETS + else if(!(::GetAsyncKeyState(VK_RCONTROL)&0x80000000)) + { + break; + } +#endif + } + +#ifdef DEBUG_RENDERTARGETS + if(::GetAsyncKeyState(VK_LCONTROL)&0x80000000) + Sleep(500); +#endif + } + else + { + if(IsWindow(pWnd->m_hWnd)) pWnd->DestroyWindow(); + m_pRenderWnds.RemoveKey(fbp); + } + + CString str; + str.Format(_T("PCSX2 - %05x - %05x"), m_ctxt->FRAME.Block(), m_ctxt->TEX0.TBP0); + SetWindowText(m_hWnd, str); + } + } + else + { + SetWindowText(m_hWnd, _T("PCSX2")); + } +#endif +} + +void GSRendererHW::EndFrame() +{ + m_tc.IncAge(m_pRTs); +} + +void GSRendererHW::InvalidateTexture(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) +{ + m_tc.InvalidateTexture(this, BITBLTBUF, &r); +} + +void GSRendererHW::InvalidateLocalMem(DWORD TBP0, DWORD BW, DWORD PSM, CRect r) +{ + m_tc.InvalidateLocalMem(this, TBP0, BW, PSM, &r); +} + +void GSRendererHW::MinMaxUV(int w, int h, CRect& r) +{ + r.SetRect(0, 0, w, h); + + uvmm_t uv; + CSize bsm; + + if(m_ctxt->CLAMP.WMS < 3 || m_ctxt->CLAMP.WMT < 3) + { + UVMinMax(m_nVertices, (vertex_t*)m_pVertices, &uv); + CSize bs = GSLocalMemory::m_psmtbl[m_ctxt->TEX0.PSM].bs; + bsm.SetSize(bs.cx-1, bs.cy-1); + } + + // FIXME: region clamp returns the right rect but we should still update the whole texture later in TC... + + if(m_ctxt->CLAMP.WMS < 3) + { + if(m_ctxt->CLAMP.WMS == 0) + { + float fmin = floor(uv.umin); + float fmax = floor(uv.umax); + + if(fmin != fmax) {uv.umin = 0; uv.umax = 1.0f;} + else {uv.umin -= fmin; uv.umax -= fmax;} + + // FIXME + if(uv.umin == 0 && uv.umax != 1.0f) uv.umax = 1.0f; + } + else if(m_ctxt->CLAMP.WMS == 1) + { + if(uv.umin < 0) uv.umin = 0; + if(uv.umax > 1.0f) uv.umax = 1.0f; + } + else if(m_ctxt->CLAMP.WMS == 2) + { + float minu = 1.0f * m_ctxt->CLAMP.MINU / w; + float maxu = 1.0f * m_ctxt->CLAMP.MAXU / w; + if(uv.umin < minu) uv.umin = minu; + if(uv.umax > maxu) uv.umax = maxu; + } + + r.left = max((int)(uv.umin * w) & ~bsm.cx, 0); + r.right = min(((int)(uv.umax * w) + bsm.cx + 1) & ~bsm.cx, w); + } + + if(m_ctxt->CLAMP.WMT < 3) + { + if(m_ctxt->CLAMP.WMT == 0) + { + float fmin = floor(uv.vmin); + float fmax = floor(uv.vmax); + + if(fmin != fmax) {uv.vmin = 0; uv.vmax = 1.0f;} + else {uv.vmin -= fmin; uv.vmax -= fmax;} + + // FIXME + if(uv.vmin == 0 && uv.vmax != 1.0f) uv.vmax = 1.0f; + } + else if(m_ctxt->CLAMP.WMT == 1) + { + if(uv.vmin < 0) uv.vmin = 0; + if(uv.vmax > 1.0f) uv.vmax = 1.0f; + } + else if(m_ctxt->CLAMP.WMT == 2) + { + float minv = 1.0f * m_ctxt->CLAMP.MINV / h; + float maxv = 1.0f * m_ctxt->CLAMP.MAXV / h; + if(uv.vmin < minv) uv.vmin = minv; + if(uv.vmax > maxv) uv.vmax = maxv; + } + + r.top = max((int)(uv.vmin * h) & ~bsm.cy, 0); + r.bottom = min(((int)(uv.vmax * h) + bsm.cy + 1) & ~bsm.cy, h); + } + + ASSERT(r.left <= r.right); + ASSERT(r.top <= r.bottom); +} + +void GSRendererHW::SetupTexture(const GSTextureBase& t, float tsx, float tsy) +{ + HRESULT hr; + + int tw = 0, th = 0; + float rw = 0, rh = 0; + + IDirect3DPixelShader9* pPixelShader = NULL; + + if(m_pPRIM->TME && t.m_pTexture) + { + tw = t.m_desc.Width; + th = t.m_desc.Height; + rw = 1.0f / tw; + rh = 1.0f / th; + + hr = m_pD3DDev->SetTexture(0, t.m_pTexture); + hr = m_pD3DDev->SetTexture(1, t.m_pPalette); + + D3DTEXTUREADDRESS u, v; + + switch(m_ctxt->CLAMP.WMS) + { + case 0: case 3: u = D3DTADDRESS_WRAP; break; // repeat + case 1: case 2: u = D3DTADDRESS_CLAMP; break; // clamp + default: __assume(0); + } + + switch(m_ctxt->CLAMP.WMT) + { + case 0: case 3: v = D3DTADDRESS_WRAP; break; // repeat + case 1: case 2: v = D3DTADDRESS_CLAMP; break; // clamp + default: __assume(0); + } + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, u); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, v); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, t.m_pPalette ? D3DTEXF_POINT : m_texfilter); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, t.m_pPalette ? D3DTEXF_POINT : m_texfilter); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, t.m_pPalette ? D3DTEXF_POINT : m_texfilter); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, t.m_pPalette ? D3DTEXF_POINT : m_texfilter); + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) && m_pHLSLTFX[m_ctxt->TEX0.TFX]) + { + int i = m_ctxt->TEX0.TFX; + + switch(t.m_desc.Format) + { + default: + ASSERT(0); + break; + case D3DFMT_A8R8G8B8: + //ASSERT(m_ctxt->TEX0.PSM != PSM_PSMCT24); // format must be D3DFMT_X8R8G8B8 for PSM_PSMCT24 + //if(m_ctxt->TEX0.PSM == PSM_PSMCT24) {i += 4; if(m_de.TEXA.AEM) i += 4;} + if(m_ctxt->TEX0.PSM == PSM_PSMT8H) i += 32; + break; + case D3DFMT_X8R8G8B8: + i += 4; if(m_de.TEXA.AEM) i += 4; + break; + case D3DFMT_A1R5G5B5: + i += 12; if(m_de.TEXA.AEM) i += 4; + break; + case D3DFMT_L8: + i += 24; + ASSERT(t.m_pPalette); + break; + } + + pPixelShader = m_pHLSLTFX[i]; + } + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 1)) + { + switch(m_ctxt->TEX0.TFX) + { + case 0: + if(!m_ctxt->TEX0.TCC) pPixelShader = m_pPixelShaders[0]; + else if(!t.m_fRT) pPixelShader = m_pPixelShaders[1]; + else pPixelShader = m_pPixelShaders[2]; + break; + case 1: + if(!t.m_fRT) pPixelShader = m_pPixelShaders[3]; + else pPixelShader = m_pPixelShaders[4]; + break; + case 2: + if(!m_ctxt->TEX0.TCC) pPixelShader = m_pPixelShaders[5]; + else if(!t.m_fRT) pPixelShader = m_pPixelShaders[6]; + else pPixelShader = m_pPixelShaders[7]; + break; + case 3: + if(!m_ctxt->TEX0.TCC) pPixelShader = m_pPixelShaders[8]; + else if(!t.m_fRT) pPixelShader = m_pPixelShaders[9]; + else pPixelShader = m_pPixelShaders[10]; + break; + default: + __assume(0); + } + } + + if(!pPixelShader) + { + int stage = 0; + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + hr = m_pD3DDev->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0); + + switch(m_ctxt->TEX0.TFX) + { + case 0: + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE2X); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + if(m_ctxt->TEX0.TCC) + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, t.m_fRT ? D3DTOP_MODULATE2X : D3DTOP_MODULATE4X); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + } + else + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + } + stage++; + break; + case 1: + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, t.m_fRT ? D3DTOP_SELECTARG1 : D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); + stage++; + break; + case 2: + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE2X); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + if(m_ctxt->TEX0.TCC) + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); + ASSERT(!t.m_fRT); // FIXME + } + stage++; + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_ALPHAREPLICATE|D3DTA_DIFFUSE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + stage++; + break; + case 3: + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE2X); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + if(m_ctxt->TEX0.TCC) + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + ASSERT(!t.m_fRT); // FIXME + } + stage++; + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_ALPHAREPLICATE|D3DTA_DIFFUSE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + stage++; + break; + default: + __assume(0); + } + + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + } + else + { + hr = m_pD3DDev->SetTexture(0, NULL); + hr = m_pD3DDev->SetTexture(1, NULL); + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) && m_pHLSLTFX[36]) + { + pPixelShader = m_pHLSLTFX[36]; + } + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 1) && m_pPixelShaders[11]) + { + pPixelShader = m_pPixelShaders[11]; + } + + if(!pPixelShader) + { + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + } + + float fConstData[][4] = + { + {(float)m_ctxt->TEX0.TCC - 0.5f, t.m_fRT ? 1.0f : 2.0f, min(2.0f * m_de.TEXA.TA0 / 255, 1), min(2.0f * m_de.TEXA.TA1 / 255, 1)}, + {(float)tw, (float)th, 0, 0}, + {rw, rh, 0, 0}, + {rw, 0, 0, 0}, + {0, rh, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData)); + + hr = m_pD3DDev->SetPixelShader(pPixelShader); +} + +void GSRendererHW::SetupAlphaBlend() +{ + HRESULT hr; + + DWORD ABE = FALSE; + hr = m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &ABE); + + bool fABE = m_pPRIM->ABE || (m_primtype == D3DPT_LINELIST || m_primtype == D3DPT_LINESTRIP) && m_pPRIM->AA1; // FIXME + if(fABE != !!ABE) + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, fABE); + if(fABE) + { + // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 + + BYTE FIX = SCALE_ALPHA(m_ctxt->ALPHA.FIX); + + hr = m_pD3DDev->SetRenderState(D3DRS_BLENDFACTOR, (0x010101*FIX)|(FIX<<24)); + + D3DBLENDOP op = D3DBLENDOP_ADD; + D3DBLEND src = D3DBLEND_SRCALPHA, dst = D3DBLEND_INVSRCALPHA; + + static const struct {bool bogus; D3DBLENDOP op; D3DBLEND src, dst;} blendmap[3*3*3*3] = + { + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F + {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As + {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(As + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad + {1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F + {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As + {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As + {1, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // * 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad + {1, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // * 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F + {1, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // * 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As + {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + }; + + // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021, 1201, 1211, 1221 + + int i = (((m_ctxt->ALPHA.A&3)*3+(m_ctxt->ALPHA.B&3))*3+(m_ctxt->ALPHA.C&3))*3+(m_ctxt->ALPHA.D&3); + + ASSERT(m_ctxt->ALPHA.A != 3); + ASSERT(m_ctxt->ALPHA.B != 3); + ASSERT(m_ctxt->ALPHA.C != 3); + ASSERT(m_ctxt->ALPHA.D != 3); + ASSERT(!blendmap[i].bogus); + + hr = m_pD3DDev->SetRenderState(D3DRS_BLENDOP, blendmap[i].op); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, blendmap[i].src); + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, blendmap[i].dst); + } +} + +void GSRendererHW::SetupColorMask() +{ + HRESULT hr; + + // close approx., to be tested... + int mask = D3DCOLORWRITEENABLE_RGBA; + if((m_ctxt->FRAME.FBMSK&0xff000000) == 0xff000000) mask &= ~D3DCOLORWRITEENABLE_ALPHA; + if((m_ctxt->FRAME.FBMSK&0x00ff0000) == 0x00ff0000) mask &= ~D3DCOLORWRITEENABLE_BLUE; + if((m_ctxt->FRAME.FBMSK&0x0000ff00) == 0x0000ff00) mask &= ~D3DCOLORWRITEENABLE_GREEN; + if((m_ctxt->FRAME.FBMSK&0x000000ff) == 0x000000ff) mask &= ~D3DCOLORWRITEENABLE_RED; + //if(m_ctxt->FRAME.PSM == PSM_PSMCT24) mask &= ~D3DCOLORWRITEENABLE_ALPHA; + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, mask); + + // ASSERT(m_ctxt->FRAME.FBMSK == 0); // wild arms (also 8H+pal on RT...) +} + +void GSRendererHW::SetupZBuffer() +{ + HRESULT hr; + + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, m_ctxt->TEST.ZTE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, !m_ctxt->ZBUF.ZMSK); + if(m_ctxt->TEST.ZTE) + { + static const DWORD zfunc[] = {D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_GREATEREQUAL, D3DCMP_GREATER}; + + hr = m_pD3DDev->SetRenderState(D3DRS_ZFUNC, zfunc[m_ctxt->TEST.ZTST]); +// hr = m_pD3DDev->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + + // FIXME + if(m_ctxt->ZBUF.ZMSK && m_ctxt->TEST.ZTST == 1) + { + for(int i = 0; i < m_nVertices; i++) + m_pVertices[i].z = 0; + } + } +} + +void GSRendererHW::SetupAlphaTest() +{ + HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, m_ctxt->TEST.ATE); + + if(m_ctxt->TEST.ATE) + { + static const DWORD afunc[] = {D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL}; + + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, afunc[m_ctxt->TEST.ATST]); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)SCALE_ALPHA(m_ctxt->TEST.AREF)); + } +} + +void GSRendererHW::SetupScissor(scale_t& s) +{ + HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + + CRect r( + (int)(s.x * m_ctxt->SCISSOR.SCAX0), + (int)(s.y * m_ctxt->SCISSOR.SCAY0), + (int)(s.x * (m_ctxt->SCISSOR.SCAX1+1)), + (int)(s.y * (m_ctxt->SCISSOR.SCAY1+1))); + + if(/*r.Width() == m_bd.Width &&*/ r.bottom > m_bd.Height && r.bottom <= m_bd.Height*2 + /*r.bottom == m_bd.Height*2*/ + ) + { + // TODO: isn't there a better way? what about s.x? +// s.y = s.y * m_bd.Height / r.bottom; + } + + r &= CRect(0, 0, m_bd.Width, m_bd.Height); + + hr = m_pD3DDev->SetScissorRect(r); +} diff --git a/plugins/gs/gsdx9/GSRendererHW.h b/plugins/gs/gsdx9/GSRendererHW.h new file mode 100644 index 0000000000..4c1d99789c --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererHW.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" + +#pragma pack(push, 1) +__declspec(align(16)) union GSVertexHW +{ + struct + { + float x, y, z, rhw; + union {struct {BYTE r, g, b, a;}; D3DCOLOR color;}; + D3DCOLOR fog; + float tu, tv; + }; + + struct {__m128i xmm[2];}; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + GSVertexHW& operator = (GSVertexHW& v) {xmm[0] = v.xmm[0]; xmm[1] = v.xmm[1]; return *this;} +#endif +}; +#pragma pack(pop) + +class GSRendererHW : public GSRenderer +{ +protected: + CSurfMap m_pRTs; + CSurfMap m_pDSs; + CAtlMap m_pRenderWnds; + + GSTextureCache m_tc; + + void SetupTexture(const GSTextureBase& t, float tsx, float tsy); + void SetupAlphaBlend(); + void SetupColorMask(); + void SetupZBuffer(); + void SetupAlphaTest(); + void SetupScissor(scale_t& s); + + void Reset(); + void VertexKick(bool fSkip); + int DrawingKick(bool fSkip); + void FlushPrim(); + void Flip(); + void EndFrame(); + void InvalidateTexture(const GIFRegBITBLTBUF& BITBLTBUF, CRect r); + void InvalidateLocalMem(DWORD BP, DWORD TBP0, DWORD PSM, CRect r); + void MinMaxUV(int w, int h, CRect& r); + + D3DPRIMITIVETYPE m_primtype; + +public: + GSRendererHW(HWND hWnd, HRESULT& hr); + ~GSRendererHW(); + + HRESULT ResetDevice(bool fForceWindowed = false); + + void LOGVERTEX(GSVertexHW& v, LPCTSTR type) + { + int tw = 1, th = 1; + if(m_pPRIM->TME) {tw = 1<TEX0.TW; th = 1<TEX0.TH;} + LOG2(_T("\t %s (%.2f, %.2f, %.2f, %.2f) (%08x) (%f, %f) (%f, %f)\n"), + type, + v.x, v.y, v.z, v.rhw, + v.color, v.tu, v.tv, + v.tu*tw, v.tv*th); + } +}; \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSRendererNull.cpp b/plugins/gs/gsdx9/GSRendererNull.cpp new file mode 100644 index 0000000000..e6b32a2748 --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererNull.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRendererNull.h" + +GSRendererNull::GSRendererNull(HWND hWnd, HRESULT& hr) + : GSRenderer(256, 256, hWnd, hr) +{ +} + +GSRendererNull::~GSRendererNull() +{ +} + +void GSRendererNull::VertexKick(bool fSkip) +{ + NULLVERTEX v; + + m_vl.AddTail(v); + + __super::VertexKick(fSkip); +} + +int GSRendererNull::DrawingKick(bool fSkip) +{ + NULLVERTEX v; + + switch(m_PRIM) + { + case 3: // triangle list + m_vl.RemoveAt(0, v); + m_vl.RemoveAt(0, v); + m_vl.RemoveAt(0, v); + break; + case 4: // triangle strip + m_vl.RemoveAt(0, v); + m_vl.GetAt(0, v); + m_vl.GetAt(1, v); + break; + case 5: // triangle fan + m_vl.GetAt(0, v); + m_vl.RemoveAt(1, v); + m_vl.GetAt(1, v); + break; + case 6: // sprite + m_vl.RemoveAt(0, v); + m_vl.RemoveAt(0, v); + break; + case 1: // line + m_vl.RemoveAt(0, v); + m_vl.RemoveAt(0, v); + break; + case 2: // line strip + m_vl.RemoveAt(0, v); + m_vl.GetAt(0, v); + break; + case 0: // point + m_vl.RemoveAt(0, v); + break; + default: + ASSERT(0); + m_vl.RemoveAll(); + return 0; + } + + if(!fSkip) + { + m_perfmon.IncCounter(GSPerfMon::c_prim, 1); + } + + return 0; +} + +void GSRendererNull::Flip() +{ + FlipInfo rt[2]; + FinishFlip(rt); +} + +void GSRendererNull::EndFrame() +{ +} diff --git a/plugins/gs/gsdx9/GSRendererNull.h b/plugins/gs/gsdx9/GSRendererNull.h new file mode 100644 index 0000000000..574a5364a3 --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererNull.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" + +#pragma pack(push, 1) +struct NULLVERTEX {/*DWORD dummy;*/}; +#pragma pack(pop) + +class GSRendererNull : public GSRenderer +{ +protected: + void VertexKick(bool fSkip); + int DrawingKick(bool fSkip); + void Flip(); + void EndFrame(); + +public: + GSRendererNull(HWND hWnd, HRESULT& hr); + ~GSRendererNull(); +}; \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSRendererSoft.cpp b/plugins/gs/gsdx9/GSRendererSoft.cpp new file mode 100644 index 0000000000..7018c52a17 --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererSoft.cpp @@ -0,0 +1,1113 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRendererSoft.h" +#include "x86.h" + +template +GSRendererSoft::GSRendererSoft(HWND hWnd, HRESULT& hr) + : GSRenderer(640, 512, hWnd, hr) +{ + Reset(); + + int i = SHRT_MIN; + BYTE j = 0; + for(; i < 0; i++, j++) m_clip[j] = 0, m_mask[j] = j; + for(; i < 256; i++, j++) m_clip[j] = (BYTE)i, m_mask[j] = j; + for(; i < SHRT_MAX; i++, j++) m_clip[j] = 255, m_mask[j] = j; + + m_uv = (uv_wrap_t*)_aligned_malloc(sizeof(uv_wrap_t), 16); + + // w00t :P + + #define InitATST(iZTST, iATST) \ + m_dv[iZTST][iATST] = &GSRendererSoft::DrawVertex; \ + + #define InitZTST(iZTST) \ + InitATST(iZTST, 0) \ + InitATST(iZTST, 1) \ + InitATST(iZTST, 2) \ + InitATST(iZTST, 3) \ + InitATST(iZTST, 4) \ + InitATST(iZTST, 5) \ + InitATST(iZTST, 6) \ + InitATST(iZTST, 7) \ + + #define InitDV() \ + InitZTST(0) \ + InitZTST(1) \ + InitZTST(2) \ + InitZTST(3) \ + + InitDV(); + + #define InitTFX(iLOD, bLCM, bTCC, iTFX) \ + m_dvtfx[iLOD][bLCM][bTCC][iTFX] = &GSRendererSoft::DrawVertexTFX; \ + + #define InitTCC(iLOD, bLCM, bTCC) \ + InitTFX(iLOD, bLCM, bTCC, 0) \ + InitTFX(iLOD, bLCM, bTCC, 1) \ + InitTFX(iLOD, bLCM, bTCC, 2) \ + InitTFX(iLOD, bLCM, bTCC, 3) \ + + #define InitLCM(iLOD, bLCM) \ + InitTCC(iLOD, bLCM, false) \ + InitTCC(iLOD, bLCM, true) \ + + #define InitLOD(iLOD) \ + InitLCM(iLOD, false) \ + InitLCM(iLOD, true) \ + + #define InitDVTFX() \ + InitLOD(0) \ + InitLOD(1) \ + InitLOD(2) \ + InitLOD(3) \ + + InitDVTFX(); +} + +template +GSRendererSoft::~GSRendererSoft() +{ + _aligned_free(m_uv); +} + +template +HRESULT GSRendererSoft::ResetDevice(bool fForceWindowed) +{ + m_pRT[0] = NULL; + m_pRT[1] = NULL; + + return __super::ResetDevice(fForceWindowed); +} + +template +void GSRendererSoft::Reset() +{ + m_primtype = PRIM_NONE; + m_pTexture = NULL; + + __super::Reset(); +} + +template +int GSRendererSoft::DrawingKick(bool fSkip) +{ + Vertex* pVertices = &m_pVertices[m_nVertices]; + int nVertices = 0; + + switch(m_PRIM) + { + case 3: // triangle list + m_primtype = PRIM_TRIANGLE; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + LOGV((pVertices[0], _T("TriList"))); + LOGV((pVertices[1], _T("TriList"))); + LOGV((pVertices[2], _T("TriList"))); + break; + case 4: // triangle strip + m_primtype = PRIM_TRIANGLE; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.GetAt(0, pVertices[nVertices++]); + m_vl.GetAt(1, pVertices[nVertices++]); + LOGV((pVertices[0], _T("TriStrip"))); + LOGV((pVertices[1], _T("TriStrip"))); + LOGV((pVertices[2], _T("TriStrip"))); + break; + case 5: // triangle fan + m_primtype = PRIM_TRIANGLE; + m_vl.GetAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(1, pVertices[nVertices++]); + m_vl.GetAt(1, pVertices[nVertices++]); + LOGV((pVertices[0], _T("TriFan"))); + LOGV((pVertices[1], _T("TriFan"))); + LOGV((pVertices[2], _T("TriFan"))); + break; + case 6: // sprite + m_primtype = PRIM_SPRITE; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + nVertices += 2; + pVertices[0].p.z = pVertices[1].p.z; + pVertices[0].p.q = pVertices[1].p.q; + pVertices[2] = pVertices[1]; + pVertices[3] = pVertices[1]; + pVertices[1].p.y = pVertices[0].p.y; + pVertices[1].t.y = pVertices[0].t.y; + pVertices[2].p.x = pVertices[0].p.x; + pVertices[2].t.x = pVertices[0].t.x; + LOGV((pVertices[0], _T("Sprite"))); + LOGV((pVertices[1], _T("Sprite"))); + LOGV((pVertices[2], _T("Sprite"))); + LOGV((pVertices[3], _T("Sprite"))); + /* + m_primtype = PRIM_TRIANGLE; + nVertices += 2; + pVertices[5] = pVertices[3]; + pVertices[3] = pVertices[1]; + pVertices[4] = pVertices[2]; + */ + break; + case 1: // line + m_primtype = PRIM_LINE; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.RemoveAt(0, pVertices[nVertices++]); + LOGV((pVertices[0], _T("LineList"))); + LOGV((pVertices[1], _T("LineList"))); + break; + case 2: // line strip + m_primtype = PRIM_LINE; + m_vl.RemoveAt(0, pVertices[nVertices++]); + m_vl.GetAt(0, pVertices[nVertices++]); + LOGV((pVertices[0], _T("LineStrip"))); + LOGV((pVertices[1], _T("LineStrip"))); + break; + case 0: // point + m_primtype = PRIM_POINT; + m_vl.RemoveAt(0, pVertices[nVertices++]); + LOGV((pVertices[0], _T("PointList"))); + break; + default: + ASSERT(0); + return 0; + } + + if(fSkip || !m_rs.IsEnabled(0) && !m_rs.IsEnabled(1)) + return 0; + + if(!m_pPRIM->IIP) + { + Vertex::Vector c = pVertices[nVertices-1].c; + for(int i = 0; i < nVertices-1; i++) + pVertices[i].c = c; + } + + return nVertices; +} + +template +void GSRendererSoft::FlushPrim() +{ + if(m_nVertices > 0) + { +CString fn; +static int s_savenum = 0; +s_savenum++; + +if(0) +//if(m_ctxt->FRAME.Block() == 0x008c0 && (DWORD)m_ctxt->TEX0.TBP0 == 0x03a98) +//if(m_ctxt->TEX0.PSM == 0x1b) +if(m_perfmon.GetFrame() >= 200) +{ +fn.Format(_T("g:/tmp/%04I64d_%06d_1f_%05x_%x.bmp"), m_perfmon.GetFrame(), s_savenum, m_ctxt->FRAME.Block(), m_ctxt->FRAME.PSM); +m_lm.SaveBMP(m_pD3DDev, fn, m_ctxt->FRAME.Block(), m_ctxt->FRAME.FBW, m_ctxt->FRAME.PSM, m_ctxt->FRAME.FBW*64, 224); + +if(m_pPRIM->TME) +{ +fn.Format(_T("g:/tmp/%04I64d_%06d_2t_%05x_%x.bmp"), m_perfmon.GetFrame(), s_savenum, (DWORD)m_ctxt->TEX0.TBP0, (DWORD)m_ctxt->TEX0.PSM); +m_lm.SaveBMP(m_pD3DDev, fn, m_ctxt->TEX0.TBP0, m_ctxt->TEX0.TBW, m_ctxt->TEX0.PSM, 1 << m_ctxt->TEX0.TW, 1 << m_ctxt->TEX0.TH); +} +} + + int iZTST = !m_ctxt->TEST.ZTE ? 1 : m_ctxt->TEST.ZTST; + int iATST = !m_ctxt->TEST.ATE ? 1 : m_ctxt->TEST.ATST; + + m_pDrawVertex = m_dv[iZTST][iATST]; + + if(m_pPRIM->TME) + { + int iLOD = (m_ctxt->TEX1.MMAG & 1) + (m_ctxt->TEX1.MMIN & 1); + int bLCM = m_ctxt->TEX1.LCM ? 1 : 0; + int bTCC = m_ctxt->TEX0.TCC ? 1 : 0; + int iTFX = m_ctxt->TEX0.TFX; + + if(m_pPRIM->FST) + { + iLOD = 3; + bLCM = m_ctxt->TEX1.K <= 0 && (m_ctxt->TEX1.MMAG & 1) || m_ctxt->TEX1.K > 0 && (m_ctxt->TEX1.MMIN & 1); + } + + m_pDrawVertexTFX = m_dvtfx[iLOD][bLCM][bTCC][iTFX]; + } + + SetupTexture(); + + m_scissor.SetRect( + max(m_ctxt->SCISSOR.SCAX0, 0), + max(m_ctxt->SCISSOR.SCAY0, 0), + min(m_ctxt->SCISSOR.SCAX1+1, m_ctxt->FRAME.FBW * 64), + min(m_ctxt->SCISSOR.SCAY1+1, 4096)); + + m_clamp = (m_de.COLCLAMP.CLAMP ? m_clip : m_mask) + 32768; + + int nPrims = 0; + Vertex* pVertices = m_pVertices; + + switch(m_primtype) + { + case PRIM_SPRITE: + ASSERT(!(m_nVertices&3)); + nPrims = m_nVertices / 4; + LOG(_T("FlushPrim(pt=%d, nVertices=%d, nPrims=%d)\n"), m_primtype, m_nVertices, nPrims); + for(int i = 0; i < nPrims; i++, pVertices += 4) DrawSprite(pVertices); + break; + case PRIM_TRIANGLE: + ASSERT(!(m_nVertices%3)); + nPrims = m_nVertices / 3; + LOG(_T("FlushPrim(pt=%d, nVertices=%d, nPrims=%d)\n"), m_primtype, m_nVertices, nPrims); + for(int i = 0; i < nPrims; i++, pVertices += 3) DrawTriangle(pVertices); + break; + case PRIM_LINE: + ASSERT(!(m_nVertices&1)); + nPrims = m_nVertices / 2; + LOG(_T("FlushPrim(pt=%d, nVertices=%d, nPrims=%d)\n"), m_primtype, m_nVertices, nPrims); + for(int i = 0; i < nPrims; i++, pVertices += 2) DrawLine(pVertices); + break; + case PRIM_POINT: + nPrims = m_nVertices; + LOG(_T("FlushPrim(pt=%d, nVertices=%d, nPrims=%d)\n"), m_primtype, m_nVertices, nPrims); + for(int i = 0; i < nPrims; i++, pVertices++) DrawPoint(pVertices); + break; + default: + ASSERT(m_nVertices == 0); + return; + } + + m_perfmon.IncCounter(GSPerfMon::c_prim, nPrims); + +if(0) +//if(m_ctxt->FRAME.Block() == 0x008c0 && (DWORD)m_ctxt->TEX0.TBP0 == 0x03a98) +//if(m_ctxt->TEX0.PSM == 0x1b) +if(m_perfmon.GetFrame() >= 200) +{ +fn.Format(_T("g:/tmp/%04I64d_%06d_3f_%05x_%x.bmp"), m_perfmon.GetFrame(), s_savenum, m_ctxt->FRAME.Block(), m_ctxt->FRAME.PSM); +m_lm.SaveBMP(m_pD3DDev, fn, m_ctxt->FRAME.Block(), m_ctxt->FRAME.FBW, m_ctxt->FRAME.PSM, m_ctxt->FRAME.FBW*64, 224); +} + } + + m_primtype = PRIM_NONE; + + __super::FlushPrim(); +} + +template +void GSRendererSoft::Flip() +{ + HRESULT hr; + + FlipInfo rt[2]; + + for(int i = 0; i < countof(rt); i++) + { + if(m_rs.IsEnabled(i)) + { + CRect rect = CRect(CPoint(0, 0), m_rs.GetDispRect(i).BottomRight()); + + //GSLocalMemory::RoundUp(, GSLocalMemory::GetBlockSize(m_rs.DISPFB[i].PSM)); + + ZeroMemory(&rt[i].rd, sizeof(rt[i].rd)); + if(m_pRT[i]) m_pRT[i]->GetLevelDesc(0, &rt[i].rd); + + if(rt[i].rd.Width != (UINT)rect.right || rt[i].rd.Height != (UINT)rect.bottom) + m_pRT[i] = NULL; + + if(!m_pRT[i]) + { + CComPtr pRT; + D3DLOCKED_RECT lr; + int nTries = 0, nMaxTries = 10; + do + { + pRT = NULL; + hr = m_pD3DDev->CreateTexture(rect.right, rect.bottom, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pRT, NULL); + if(FAILED(hr)) break; + if(SUCCEEDED(pRT->LockRect(0, &lr, NULL, 0))) + pRT->UnlockRect(0); + m_pRT[i] = pRT; + } + while((((DWORD_PTR)lr.pBits & 0xf) || (lr.Pitch & 0xf)) && ++nTries < nMaxTries); + + if(nTries == nMaxTries) continue; + + ZeroMemory(&rt[i].rd, sizeof(rt[i].rd)); + hr = m_pRT[i]->GetLevelDesc(0, &rt[i].rd); + } + + rt[i].pRT = m_pRT[i]; + + rt[i].scale = scale_t(1, 1); + + D3DLOCKED_RECT lr; + if(FAILED(hr = rt[i].pRT->LockRect(0, &lr, NULL, 0))) + continue; + + GIFRegTEX0 TEX0; + TEX0.TBP0 = m_rs.pDISPFB[i]->FBP<<5; + TEX0.TBW = m_rs.pDISPFB[i]->FBW; + TEX0.PSM = m_rs.pDISPFB[i]->PSM; + + GIFRegCLAMP CLAMP; + CLAMP.WMS = CLAMP.WMT = 1; + +#ifdef DEBUG_RENDERTARGETS + if(::GetAsyncKeyState(VK_SPACE)&0x80000000) + { + TEX0.TBP0 = m_ctxt->FRAME.Block(); + TEX0.TBW = m_ctxt->FRAME.FBW; + TEX0.PSM = m_ctxt->FRAME.PSM; + } + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while(msg.message != WM_QUIT) + { + if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else if(!(::GetAsyncKeyState(VK_RCONTROL)&0x80000000)) + { + break; + } + } + + if(::GetAsyncKeyState(VK_LCONTROL)&0x80000000) + Sleep(500); + +#endif + + m_lm.ReadTexture(rect, (BYTE*)lr.pBits, lr.Pitch, TEX0, m_de.TEXA, CLAMP); + + rt[i].pRT->UnlockRect(0); + } + } + + FinishFlip(rt); +} + +template +void GSRendererSoft::EndFrame() +{ +} + +template +void GSRendererSoft::RowInit(int x, int y) +{ + m_faddr_x0 = (m_ctxt->ftbl->pa)(0, y, m_ctxt->FRAME.FBP<<5, m_ctxt->FRAME.FBW); + m_zaddr_x0 = (m_ctxt->ztbl->pa)(0, y, m_ctxt->ZBUF.ZBP<<5, m_ctxt->FRAME.FBW); + + m_faddr_ro = &m_ctxt->ftbl->rowOffset[y&7][x]; + m_zaddr_ro = &m_ctxt->ztbl->rowOffset[y&7][x]; + + m_fx = x-1; // -1 because RowStep() will do +1, yea lame... + m_fy = y; + + RowStep(); +} + +template +void GSRendererSoft::RowStep() +{ + m_fx++; + + m_faddr = m_faddr_x0 + *m_faddr_ro++; + m_zaddr = m_zaddr_x0 + *m_zaddr_ro++; +} + +template +void GSRendererSoft::DrawPoint(Vertex* v) +{ + CPoint p = *v; + if(!m_scissor.PtInRect(p)) + { + RowInit(p.x, p.y); + (this->*m_pDrawVertex)(*v); + } +} + +template +void GSRendererSoft::DrawLine(Vertex* v) +{ + Vertex dv = v[1] - v[0]; + + Vertex::Vector dp = dv.p; + dp.x.abs(); + dp.y.abs(); + + int dx = (int)dp.x; + int dy = (int)dp.y; + + if(dx == 0 && dy == 0) return; + + int i = dx > dy ? 0 : 1; + + Vertex edge = v[0]; + Vertex dedge = dv / dp.v[i]; + + // TODO: clip with the scissor + + int steps = (int)dp.v[i]; + + while(steps-- > 0) + { + CPoint p = edge; + + if(m_scissor.PtInRect(p)) + { + RowInit(p.x, p.y); + (this->*m_pDrawVertex)(edge); + } + + edge += dedge; + } +} + +template +void GSRendererSoft::DrawTriangle(Vertex* v) +{ + if(v[1].p.y < v[0].p.y) {Exchange(&v[0], &v[1]);} + if(v[2].p.y < v[0].p.y) {Exchange(&v[0], &v[2]);} + if(v[2].p.y < v[1].p.y) {Exchange(&v[1], &v[2]);} + + if(!(v[0].p.y < v[2].p.y)) return; + + Vertex v01 = v[1] - v[0]; + Vertex v02 = v[2] - v[0]; + + Vertex::Scalar temp = v01.p.y / v02.p.y; + Vertex::Scalar longest = temp * v02.p.x - v01.p.x; + + int ledge, redge; + if(Vertex::Scalar(0) < longest) {ledge = 0; redge = 1; if(longest < Vertex::Scalar(1)) longest = Vertex::Scalar(1);} + else if(longest < Vertex::Scalar(0)) {ledge = 1; redge = 0; if(Vertex::Scalar(-1) < longest) longest = Vertex::Scalar(-1);} + else return; + + Vertex edge[2] = {v[0], v[0]}; + + Vertex dedge[2]; + dedge[0].p.y = dedge[1].p.y = Vertex::Scalar(1); + if(Vertex::Scalar(0) < v01.p.y) dedge[ledge] = v01 / v01.p.y; + if(Vertex::Scalar(0) < v02.p.y) dedge[redge] = v02 / v02.p.y; + + Vertex scan; + + Vertex dscan = (v02 * temp - v01) / longest; + dscan.p.y = 0; + + for(int i = 0; i < 2; i++, v++) + { + int top = edge[0].p.y.ceil_i(), bottom = v[1].p.y.ceil_i(); + if(top < m_scissor.top) top = min(m_scissor.top, bottom); + if(bottom > m_scissor.bottom) bottom = m_scissor.bottom; + if(edge[0].p.y < Vertex::Scalar(top)) // for(int j = 0; j < 2; j++) edge[j] += dedge[j] * ((float)top - edge[0].p.y); + { + Vertex::Scalar dy = Vertex::Scalar(top) - edge[0].p.y; + edge[0] += dedge[0] * dy; + edge[1].p.x += dedge[1].p.x * dy; + edge[0].p.y = edge[1].p.y = Vertex::Scalar(top); + } + + ASSERT(top >= bottom || (int)((edge[1].p.y - edge[0].p.y) * 10) == 0); +/* +static struct eb_t {Vertex scan; int top; int left; int steps;} eb[1024]; +int _top = top; +int _bottom = bottom; +*/ + for(; top < bottom; top++) + { + scan = edge[0]; + + int left = edge[0].p.x.ceil_i(), right = edge[1].p.x.ceil_i(); + if(left < m_scissor.left) left = m_scissor.left; + if(right > m_scissor.right) right = m_scissor.right; + if(edge[0].p.x < Vertex::Scalar(left)) + { + scan += dscan * (Vertex::Scalar(left) - edge[0].p.x); + scan.p.x = Vertex::Scalar(left); + } +/* +eb[top].scan = scan; +eb[top].top = top; +eb[top].left = left; +eb[top].steps = right - left; +*/ +///* + RowInit(left, top); + + for(int steps = right - left; steps > 0; steps--) + { + (this->*m_pDrawVertex)(scan); + scan += dscan; + RowStep(); + } +//*/ + // for(int j = 0; j < 2; j++) edge[j] += dedge[j]; + edge[0] += dedge[0]; + edge[1].p += dedge[1].p; + } +/* +top = _top; +bottom = _bottom; +for(; top < bottom; top++) +{ + eb_t& sl = eb[top]; + + RowInit(sl.left, top); + + for(; sl.steps > 0; sl.steps--) + { + (this->*m_pDrawVertex)(sl.scan); + sl.scan += dscan; + RowStep(); + } +} +*/ + if(v[1].p.y < v[2].p.y) + { + edge[ledge] = v[1]; + dedge[ledge] = (v[2] - v[1]) / (v[2].p.y - v[1].p.y); + edge[ledge] += dedge[ledge] * (edge[ledge].p.y.ceil_s() - edge[ledge].p.y); + } + } +} + +template +void GSRendererSoft::DrawSprite(Vertex* v) +{ + if(v[2].p.y < v[0].p.y) {Exchange(&v[0], &v[2]); Exchange(&v[1], &v[3]);} + if(v[1].p.x < v[0].p.x) {Exchange(&v[0], &v[1]); Exchange(&v[2], &v[3]);} + + if(v[0].p.x == v[1].p.x || v[0].p.y == v[2].p.y) return; + + Vertex v01 = v[1] - v[0]; + Vertex v02 = v[2] - v[0]; + + Vertex edge = v[0]; + Vertex dedge = v02 / v02.p.y; + Vertex scan; + Vertex dscan = v01 / v01.p.x; + + int top = v[0].p.y.ceil_i(), bottom = v[2].p.y.ceil_i(); + if(top < m_scissor.top) top = min(m_scissor.top, bottom); + if(bottom > m_scissor.bottom) bottom = m_scissor.bottom; + if(v[0].p.y < Vertex::Scalar(top)) edge += dedge * (Vertex::Scalar(top) - v[0].p.y); + + int left = v[0].p.x.ceil_i(), right = v[1].p.x.ceil_i(); + if(left < m_scissor.left) left = m_scissor.left; + if(right > m_scissor.right) right = m_scissor.right; + if(v[0].p.x < Vertex::Scalar(left)) edge += dscan * (Vertex::Scalar(left) - v[0].p.x); + + if(DrawFilledRect(left, top, right, bottom, edge)) + return; + + for(; top < bottom; top++) + { + scan = edge; + + RowInit(left, top); + + for(int steps = right - left; steps > 0; steps--) + { + (this->*m_pDrawVertex)(scan); + scan += dscan; + RowStep(); + } + + edge += dedge; + } +} + +template +bool GSRendererSoft::DrawFilledRect(int left, int top, int right, int bottom, const Vertex& v) +{ + if(left >= right || top >= bottom) + return false; + + ASSERT(top >= 0); + ASSERT(bottom >= 0); + + if(m_pPRIM->IIP + || m_ctxt->TEST.ZTE && m_ctxt->TEST.ZTST != 1 + || m_ctxt->TEST.ATE && m_ctxt->TEST.ATST != 1 + || m_ctxt->TEST.DATE + || m_pPRIM->TME + || m_pPRIM->ABE + || m_pPRIM->FGE + || m_de.DTHE.DTHE + || m_ctxt->FRAME.FBMSK) + return false; + + DWORD FBP = m_ctxt->FRAME.FBP<<5, FBW = m_ctxt->FRAME.FBW; + DWORD ZBP = m_ctxt->ZBUF.ZBP<<5; + + if(!m_ctxt->ZBUF.ZMSK) + { + m_lm.FillRect(CRect(left, top, right, bottom), v.GetZ(), m_ctxt->ZBUF.PSM, ZBP, FBW); + } + + __declspec(align(16)) union {struct {short Rf, Gf, Bf, Af;}; UINT64 Cui64;}; + Cui64 = v.c; + + Rf = m_clamp[Rf]; + Gf = m_clamp[Gf]; + Bf = m_clamp[Bf]; + Af |= m_ctxt->FBA.FBA << 7; + + DWORD Cdw; + + if(m_ctxt->FRAME.PSM == PSM_PSMCT16 || m_ctxt->FRAME.PSM == PSM_PSMCT16S) + { + Cdw = ((DWORD)(Rf&0xf8) >> 3) + | ((DWORD)(Gf&0xf8) << 2) + | ((DWORD)(Bf&0xf8) << 7) + | ((DWORD)(Af&0x80) << 8); + } + else + { +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + __m128i r0 = _mm_load_si128((__m128i*)&Cui64); + Cdw = (DWORD)_mm_cvtsi128_si32(_mm_packus_epi16(r0, r0)); +#else + Cdw = ((DWORD)(Rf&0xff) << 0) + | ((DWORD)(Gf&0xff) << 8) + | ((DWORD)(Bf&0xff) << 16) + | ((DWORD)(Af&0xff) << 24); +#endif + } + + m_lm.FillRect(CRect(left, top, right, bottom), Cdw, m_ctxt->FRAME.PSM, FBP, FBW); + + return true; +} + +template +template +void GSRendererSoft::DrawVertex(const Vertex& v) +{ + DWORD vz; + + switch(iZTST) + { + case 0: return; + case 1: break; + case 2: vz = v.GetZ(); if(vz < (m_lm.*m_ctxt->ztbl->rpa)(m_zaddr)) return; break; + case 3: vz = v.GetZ(); if(vz <= (m_lm.*m_ctxt->ztbl->rpa)(m_zaddr)) return; break; + default: __assume(0); + } + + union + { + struct {Vertex::Vector Cf, Cd, Ca;}; + struct {Vertex::Vector Cfda[3];}; + }; + + Cf = v.c; + + if(m_pPRIM->TME) + { + (this->*m_pDrawVertexTFX)(Cf, v); + } + + if(m_pPRIM->FGE) + { + Vertex::Scalar a = Cf.a; + Vertex::Vector Cfog((DWORD)m_de.FOGCOL.ai32[0]); + Cf = Cfog + (Cf - Cfog) * v.t.z; + Cf.a = a; + } + + BOOL ZMSK = m_ctxt->ZBUF.ZMSK; + DWORD FBMSK = m_ctxt->FRAME.FBMSK; + + bool fAlphaPass = true; + + BYTE Af = (BYTE)(int)Cf.a; + + switch(iATST) + { + case 0: fAlphaPass = false; break; + case 1: fAlphaPass = true; break; + case 2: fAlphaPass = Af < m_ctxt->TEST.AREF; break; + case 3: fAlphaPass = Af <= m_ctxt->TEST.AREF; break; + case 4: fAlphaPass = Af == m_ctxt->TEST.AREF; break; + case 5: fAlphaPass = Af >= m_ctxt->TEST.AREF; break; + case 6: fAlphaPass = Af > m_ctxt->TEST.AREF; break; + case 7: fAlphaPass = Af != m_ctxt->TEST.AREF; break; + default: __assume(0); + } + + if(!fAlphaPass) + { + switch(m_ctxt->TEST.AFAIL) + { + case 0: return; + case 1: ZMSK = 1; break; // RGBA + case 2: FBMSK = 0xffffffff; break; // Z + case 3: FBMSK = 0xff000000; ZMSK = 1; break; // RGB + default: __assume(0); + } + } + + if(!ZMSK) + { + if(iZTST != 2 && iZTST != 3) vz = v.GetZ(); + (m_lm.*m_ctxt->ztbl->wpa)(m_zaddr, vz); + } + + if(FBMSK != ~0) + { + if(m_ctxt->TEST.DATE && m_ctxt->FRAME.PSM <= PSM_PSMCT16S && m_ctxt->FRAME.PSM != PSM_PSMCT24) + { + BYTE A = (BYTE)((m_lm.*m_ctxt->ftbl->rpa)(m_faddr) >> (m_ctxt->FRAME.PSM == PSM_PSMCT32 ? 31 : 15)); + if(A ^ m_ctxt->TEST.DATM) return; + } + + // FIXME: for AA1 the value of Af should be calculated from the pixel coverage... + + bool fABE = (m_pPRIM->ABE || m_pPRIM->AA1 && (m_pPRIM->PRIM == 1 || m_pPRIM->PRIM == 2)) && (!m_de.PABE.PABE || (int)Cf.a >= 0x80); + + if(FBMSK || fABE) + { + GIFRegTEXA TEXA; + /* + TEXA.AEM = 0; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + */ + TEXA.ai32[0] = 0; + TEXA.ai32[1] = 0x80; + Cd = (m_lm.*m_ctxt->ftbl->rta)(m_faddr, m_ctxt->TEX0, TEXA); + } + + if(fABE) + { + Ca = Vertex::Vector(Vertex::Scalar(0)); + Ca.a = Vertex::Scalar((int)m_ctxt->ALPHA.FIX); + + Vertex::Scalar a = Cf.a; + Cf = ((Cfda[m_ctxt->ALPHA.A] - Cfda[m_ctxt->ALPHA.B]) * Cfda[m_ctxt->ALPHA.C].a >> 7) + Cfda[m_ctxt->ALPHA.D]; + Cf.a = a; + } + + DWORD Cdw; + + if(m_de.COLCLAMP.CLAMP && !m_de.DTHE.DTHE) + { + Cdw = Cf; + } + else + { + __declspec(align(16)) union {struct {short Rf, Gf, Bf, Af;}; UINT64 Cui64;}; + Cui64 = Cf; + + if(m_de.DTHE.DTHE) + { + short DMxy = (signed char)((*((WORD*)&m_de.DIMX.i64 + (m_fy&3)) >> ((m_fx&3)<<2)) << 5) >> 5; + Rf = (short)(Rf + DMxy); + Gf = (short)(Gf + DMxy); + Bf = (short)(Bf + DMxy); + } + + Rf = m_clamp[Rf]; + Gf = m_clamp[Gf]; + Bf = m_clamp[Bf]; + Af |= m_ctxt->FBA.FBA << 7; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + __m128i r0 = _mm_load_si128((__m128i*)&Cui64); + Cdw = (DWORD)_mm_cvtsi128_si32(_mm_packus_epi16(r0, r0)); +#else + Cdw = ((DWORD)(Rf&0xff) << 0) + | ((DWORD)(Gf&0xff) << 8) + | ((DWORD)(Bf&0xff) << 16) + | ((DWORD)(Af&0xff) << 24); +#endif + } + + if(FBMSK != 0) + { + Cdw = (Cdw & ~FBMSK) | ((DWORD)Cd & FBMSK); + } + + (m_lm.*m_ctxt->ftbl->wfa)(m_faddr, Cdw); + } +} + +static const float one_over_log2 = 1.0f / log(2.0f); + +template +template +void GSRendererSoft::DrawVertexTFX(typename Vertex::Vector& Cf, const Vertex& v) +{ + ASSERT(m_pPRIM->TME); + + Vertex::Vector t = v.t; + + bool fBiLinear = iLOD == 2; + + if(iLOD == 3) + { + fBiLinear = bLCM; + } + else + { + t.q.rcp(); + t *= t.q; + + if(iLOD == 1) + { + float lod = (float)(int)m_ctxt->TEX1.K; + if(!bLCM) lod += log(fabs((float)t.q)) * one_over_log2 * (1 << m_ctxt->TEX1.L); + fBiLinear = lod <= 0 && (m_ctxt->TEX1.MMAG & 1) || lod > 0 && (m_ctxt->TEX1.MMIN & 1); + } + } + + if(fBiLinear) t -= Vertex::Scalar(0.5f); + + __declspec(align(16)) short ituv[8] = + { + (short)(int)t.x, + (short)(int)t.x+1, + (short)(int)t.y, + (short)(int)t.y+1 + }; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + + __m128i uv = _mm_load_si128((__m128i*)ituv); + __m128i mask = _mm_load_si128((__m128i*)m_uv->mask); + __m128i region = _mm_or_si128(_mm_and_si128(uv, *(__m128i*)m_uv->and), *(__m128i*)m_uv->or); + __m128i clamp = _mm_min_epi16(_mm_max_epi16(uv, *(__m128i*)m_uv->min), *(__m128i*)m_uv->max); + _mm_store_si128((__m128i*)ituv, _mm_or_si128(_mm_and_si128(region, mask), _mm_andnot_si128(mask, clamp))); + +#else + + for(int i = 0; i < 4; i++) + { + short region = (ituv[i] & m_uv->and[i]) | m_uv->or[i]; + short clamp = ituv[i] < m_uv->min[i] ? m_uv->min[i] : ituv[i] > m_uv->max[i] ? m_uv->max[i] : ituv[i]; + ituv[i] = (region & m_uv->mask[i]) | (clamp & ~m_uv->mask[i]); + } + +#endif + + Vertex::Vector Ct[4]; + + if(fBiLinear) + { + if(0 && m_pTexture) + { + Ct[0] = m_pTexture[(ituv[2] << m_ctxt->TEX0.TW) + ituv[0]]; + Ct[1] = m_pTexture[(ituv[2] << m_ctxt->TEX0.TW) + ituv[1]]; + Ct[2] = m_pTexture[(ituv[3] << m_ctxt->TEX0.TW) + ituv[0]]; + Ct[3] = m_pTexture[(ituv[3] << m_ctxt->TEX0.TW) + ituv[1]]; + } + else + { + Ct[0] = (m_lm.*m_ctxt->ttbl->rt)(ituv[0], ituv[2], m_ctxt->TEX0, m_de.TEXA); + Ct[1] = (m_lm.*m_ctxt->ttbl->rt)(ituv[1], ituv[2], m_ctxt->TEX0, m_de.TEXA); + Ct[2] = (m_lm.*m_ctxt->ttbl->rt)(ituv[0], ituv[3], m_ctxt->TEX0, m_de.TEXA); + Ct[3] = (m_lm.*m_ctxt->ttbl->rt)(ituv[1], ituv[3], m_ctxt->TEX0, m_de.TEXA); + } + + Vertex::Vector ft = t - t.floor(); + + Ct[0] = Ct[0] + (Ct[1] - Ct[0]) * ft.x; + Ct[2] = Ct[2] + (Ct[3] - Ct[2]) * ft.x; + Ct[0] = Ct[0] + (Ct[2] - Ct[0]) * ft.y; + } + else + { + if(0 && m_pTexture) + { + Ct[0] = m_pTexture[(ituv[2] << m_ctxt->TEX0.TW) + ituv[0]]; + } + else + { + Ct[0] = (m_lm.*m_ctxt->ttbl->rt)(ituv[0], ituv[2], m_ctxt->TEX0, m_de.TEXA); + } + } + + Vertex::Scalar a = Cf.a; + + switch(iTFX) + { + case 0: + Cf = (Cf * Ct[0] >> 7); + if(!bTCC) Cf.a = a; + break; + case 1: + Cf = Ct[0]; + break; + case 2: + Cf = (Cf * Ct[0] >> 7) + Cf.a; + Cf.a = !bTCC ? a : (Ct[0].a + a); + break; + case 3: + Cf = (Cf * Ct[0] >> 7) + Cf.a; + Cf.a = !bTCC ? a : Ct[0].a; + break; + default: + __assume(0); + } + + Cf.sat(); +} + +template +void GSRendererSoft::SetupTexture() +{ + if(!m_pPRIM->TME) return; + + m_lm.SetupCLUT32(m_ctxt->TEX0, m_de.TEXA); + + // + + int tw = 1 << m_ctxt->TEX0.TW; + int th = 1 << m_ctxt->TEX0.TH; + + switch(m_ctxt->CLAMP.WMS) + { + case 0: m_uv->and[0] = (short)(tw-1); m_uv->or[0] = 0; m_uv->mask[0] = 0xffff; break; + case 1: m_uv->min[0] = 0; m_uv->max[0] = (short)(tw-1); m_uv->mask[0] = 0; break; + case 2: m_uv->min[0] = (short)m_ctxt->CLAMP.MINU; m_uv->max[0] = (short)m_ctxt->CLAMP.MAXU; m_uv->mask[0] = 0; break; + case 3: m_uv->and[0] = (short)m_ctxt->CLAMP.MINU; m_uv->or[0] = (short)m_ctxt->CLAMP.MAXU; m_uv->mask[0] = 0xffff; break; + default: __assume(0); + } + + m_uv->and[1] = m_uv->and[0]; + m_uv->or[1] = m_uv->or[0]; + m_uv->min[1] = m_uv->min[0]; + m_uv->max[1] = m_uv->max[0]; + m_uv->mask[1] = m_uv->mask[0]; + + switch(m_ctxt->CLAMP.WMT) + { + case 0: m_uv->and[2] = (short)(th-1); m_uv->or[2] = 0; m_uv->mask[2] = 0xffff; break; + case 1: m_uv->min[2] = 0; m_uv->max[2] = (short)(th-1); m_uv->mask[2] = 0; break; + case 2: m_uv->min[2] = (short)m_ctxt->CLAMP.MINV; m_uv->max[2] = (short)m_ctxt->CLAMP.MAXV; m_uv->mask[2] = 0; break; + case 3: m_uv->and[2] = (short)m_ctxt->CLAMP.MINV; m_uv->or[2] = (short)m_ctxt->CLAMP.MAXV; m_uv->mask[2] = 0xffff; break; + default: __assume(0); + } + + m_uv->and[3] = m_uv->and[2]; + m_uv->or[3] = m_uv->or[2]; + m_uv->min[3] = m_uv->min[2]; + m_uv->max[3] = m_uv->max[2]; + m_uv->mask[3] = m_uv->mask[2]; +} + +// +// GSRendererSoftFP +// + +GSRendererSoftFP::GSRendererSoftFP(HWND hWnd, HRESULT& hr) + : GSRendererSoft(hWnd, hr) +{ +} + +void GSRendererSoftFP::VertexKick(bool fSkip) +{ + GSSoftVertexFP& v = m_vl.AddTail(); + + v.c = (DWORD)m_v.RGBAQ.ai32[0]; + + v.p.x = (int)m_v.XYZ.X - (int)m_ctxt->XYOFFSET.OFX; + v.p.y = (int)m_v.XYZ.Y - (int)m_ctxt->XYOFFSET.OFY; + v.p *= GSSoftVertexFP::Scalar(1.0f/16); + v.p.z = (float)(m_v.XYZ.Z >> 16); + v.p.q = (float)(m_v.XYZ.Z & 0xffff); + + if(m_pPRIM->TME) + { + if(m_pPRIM->FST) + { + v.t.x = (float)(int)m_v.UV.U; + v.t.y = (float)(int)m_v.UV.V; + v.t *= GSSoftVertexFP::Scalar(1.0f/16); + v.t.q = 1.0f; + } + else + { + v.t.x = m_v.ST.S * (1 << m_ctxt->TEX0.TW); + v.t.y = m_v.ST.T * (1 << m_ctxt->TEX0.TH); + v.t.q = m_v.RGBAQ.Q; + } + } + + if(m_pPRIM->FGE) + { + v.t.z = (float)m_v.FOG.F * (1.0f/255); + } + + __super::VertexKick(fSkip); +} +/* +// +// GSRendererSoftFX +// + +GSRendererSoftFX::GSRendererSoftFX(HWND hWnd, HRESULT& hr) + : GSRendererSoft(hWnd, hr) +{ +} + +void GSRendererSoftFX::VertexKick(bool fSkip) +{ + GSSoftVertexFX& v = m_vl.AddTail(); + + v.c = (DWORD)m_v.RGBAQ.ai32[0]; + + v.p.x = ((int)m_v.XYZ.X - (int)m_ctxt->XYOFFSET.OFX) << 12; + v.p.y = ((int)m_v.XYZ.Y - (int)m_ctxt->XYOFFSET.OFY) << 12; + v.p.z = (int)((m_v.XYZ.Z & 0xffff0000) >> 1); + v.p.q = (int)((m_v.XYZ.Z & 0x0000ffff) << 15); + + if(m_pPRIM->TME) + { + if(m_pPRIM->FST) + { + v.t.x = ((int)m_v.UV.U << (12 >> m_ctxt->TEX0.TW)); + v.t.y = ((int)m_v.UV.V << (12 >> m_ctxt->TEX0.TH)); + v.t.q = 1<<16; + } + else + { + // TODO + v.t.x = m_v.ST.S; + v.t.y = m_v.ST.T; + v.t.q = m_v.RGBAQ.Q; + } + } + + if(m_pPRIM->FGE) + { + v.t.z = (int)m_v.FOG.F << 8; + } + + __super::VertexKick(fSkip); +} +*/ \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSRendererSoft.h b/plugins/gs/gsdx9/GSRendererSoft.h new file mode 100644 index 0000000000..978258ca8a --- /dev/null +++ b/plugins/gs/gsdx9/GSRendererSoft.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" + +template +class GSRendererSoft : public GSRenderer +{ +protected: + void Reset(); + int DrawingKick(bool fSkip); + void FlushPrim(); + void Flip(); + void EndFrame(); + + enum {PRIM_NONE, PRIM_SPRITE, PRIM_TRIANGLE, PRIM_LINE, PRIM_POINT} m_primtype; + + DWORD m_faddr_x0, m_faddr; + DWORD m_zaddr_x0, m_zaddr; + int* m_faddr_ro; + int* m_zaddr_ro; + int m_fx, m_fy; + void RowInit(int x, int y); + void RowStep(); + + void DrawPoint(Vertex* v); + void DrawLine(Vertex* v); + void DrawTriangle(Vertex* v); + void DrawSprite(Vertex* v); + bool DrawFilledRect(int left, int top, int right, int bottom, const Vertex& v); + + template + void DrawVertex(const Vertex& v); + + typedef void (GSRendererSoft::*DrawVertexPtr)(const Vertex& v); + DrawVertexPtr m_dv[4][8], m_pDrawVertex; + + template + void DrawVertexTFX(typename Vertex::Vector& Cf, const Vertex& v); + + typedef void (GSRendererSoft::*DrawVertexTFXPtr)(typename Vertex::Vector& Cf, const Vertex& v); + DrawVertexTFXPtr m_dvtfx[4][2][2][4], m_pDrawVertexTFX; + + CComPtr m_pRT[2]; + + DWORD* m_pTexture; + void SetupTexture(); + + struct uv_wrap_t {union {struct {short min[8], max[8];}; struct {short and[8], or[8];};}; unsigned short mask[8];}* m_uv; + + CRect m_scissor; + BYTE m_clip[65536]; + BYTE m_mask[65536]; + BYTE* m_clamp; + +public: + GSRendererSoft(HWND hWnd, HRESULT& hr); + ~GSRendererSoft(); + + HRESULT ResetDevice(bool fForceWindowed = false); + + void LOGVERTEX(Vertex& v, LPCTSTR type) + { + int tw = 1, th = 1; + if(m_de.PRIM.TME) {tw = 1<TEX0.TW; th = 1<TEX0.TH;} + LOG2(_T("- %s (%.2f, %.2f, %.2f, %.2f) (%08x) (%.3f, %.3f) (%.2f, %.2f)\n"), + type, + (float)v.p.x, (float)v.p.y, (float)v.p.z / UINT_MAX, (float)v.t.q, + (DWORD)v.c, + (float)v.t.x/tw, (float)v.t.y/th, (float)v.t.x, (float)v.t.y); + } +}; + +class GSRendererSoftFP : public GSRendererSoft +{ +protected: + void VertexKick(bool fSkip); + +public: + GSRendererSoftFP(HWND hWnd, HRESULT& hr); +}; +/* +class GSRendererSoftFX : public GSRendererSoft +{ +protected: + void VertexKick(bool fSkip); + //void DrawVertex(int x, int y, GSSoftVertexFX& v); + +public: + GSRendererSoftFX(HWND hWnd, HRESULT& hr); +}; +*/ \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSSettingsDlg.cpp b/plugins/gs/gsdx9/GSSettingsDlg.cpp new file mode 100644 index 0000000000..dad31f3424 --- /dev/null +++ b/plugins/gs/gsdx9/GSSettingsDlg.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx9.h" +#include "GSSettingsDlg.h" +#include + +static struct {int id; const TCHAR* name;} s_renderers[] = +{ + {RENDERER_D3D_HW, "Direct3D"}, + // {RENDERER_D3D_SW_FX, "Software (fixed)"}, + {RENDERER_D3D_SW_FP, "Software (float)"}, + {RENDERER_D3D_NULL, "Do not render"}, +}; + +static struct {DWORD id; const TCHAR* name;} s_psversions[] = +{ + {D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0")}, + {D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0")}, + {D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4")}, + {D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1")}, + {D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)")}, +}; + +IMPLEMENT_DYNAMIC(CGSSettingsDlg, CDialog) +CGSSettingsDlg::CGSSettingsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGSSettingsDlg::IDD, pParent) + , m_fEnablePalettizedTextures(FALSE) + , m_fEnableTvOut(FALSE) + , m_fNloopHack(FALSE) + , m_fRecordState(FALSE) + , m_fLinearTexFilter(TRUE) +{ +} + +CGSSettingsDlg::~CGSSettingsDlg() +{ +} + +void CGSSettingsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO3, m_resolution); + DDX_Control(pDX, IDC_COMBO1, m_renderer); + DDX_Control(pDX, IDC_COMBO4, m_psversion); + DDX_Check(pDX, IDC_CHECK1, m_fEnablePalettizedTextures); + DDX_Check(pDX, IDC_CHECK3, m_fEnableTvOut); + DDX_Check(pDX, IDC_CHECK2, m_fRecordState); + DDX_Check(pDX, IDC_CHECK5, m_fNloopHack); + DDX_Text(pDX, IDC_EDIT1, m_strRecordState); + DDX_Check(pDX, IDC_CHECK4, m_fLinearTexFilter); +} + +BEGIN_MESSAGE_MAP(CGSSettingsDlg, CDialog) + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) +END_MESSAGE_MAP() + +// CGSSettingsDlg message handlers + +BOOL CGSSettingsDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + CWinApp* pApp = AfxGetApp(); + + D3DCAPS9 caps; + ZeroMemory(&caps, sizeof(caps)); + caps.PixelShaderVersion = D3DPS_VERSION(0, 0); + + m_modes.RemoveAll(); + + // windowed + + { + D3DDISPLAYMODE mode; + memset(&mode, 0, sizeof(mode)); + m_modes.AddTail(mode); + + int iItem = m_resolution.AddString(_T("Windowed")); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + m_resolution.SetCurSel(iItem); + } + + // fullscreen + + if(CComPtr pD3D = Direct3DCreate9(D3D_SDK_VERSION)) + { + int ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); + int ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); + int ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); + + UINT nModes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); + for(UINT i = 0; i < nModes; i++) + { + D3DDISPLAYMODE mode; + if(S_OK == pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode)) + { + CString str; + str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate); + int iItem = m_resolution.AddString(str); + + m_modes.AddTail(mode); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + + if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate) + m_resolution.SetCurSel(iItem); + } + } + + pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, &caps); + } + + // renderer + + int renderer_id = pApp->GetProfileInt(_T("Settings"), _T("Renderer"), RENDERER_D3D_HW); + + for(int i = 0; i < countof(s_renderers); i++) + { + int iItem = m_renderer.AddString(s_renderers[i].name); + m_renderer.SetItemData(iItem, s_renderers[i].id); + if(s_renderers[i].id == renderer_id) m_renderer.SetCurSel(iItem); + } + + // shader + + DWORD psversion_id = pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)); + + for(int i = 0; i < countof(s_psversions); i++) + { + if(s_psversions[i].id > caps.PixelShaderVersion) continue; + int iItem = m_psversion.AddString(s_psversions[i].name); + m_psversion.SetItemData(iItem, s_psversions[i].id); + if(s_psversions[i].id == psversion_id) m_psversion.SetCurSel(iItem); + } + + // + + m_fEnablePalettizedTextures = pApp->GetProfileInt(_T("Settings"), _T("fEnablePalettizedTextures"), FALSE); + + // + + m_fLinearTexFilter = (D3DTEXTUREFILTERTYPE)pApp->GetProfileInt(_T("Settings"), _T("TexFilter"), D3DTEXF_LINEAR) == D3DTEXF_LINEAR; + + // + + m_fEnableTvOut = pApp->GetProfileInt(_T("Settings"), _T("fEnableTvOut"), FALSE); + + // + m_fNloopHack = pApp->GetProfileInt(_T("Settings"), _T("fNloopHack"), FALSE); + + // + m_fRecordState = pApp->GetProfileInt(_T("Settings"), _T("RecordState"), FALSE); + m_strRecordState = pApp->GetProfileString(_T("Settings"), _T("RecordStatePath"), _T("")); + + // + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CGSSettingsDlg::OnOK() +{ + CWinApp* pApp = AfxGetApp(); + + UpdateData(); + + if(m_resolution.GetCurSel() >= 0) + { + D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel())); + pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width); + pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height); + pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate); + } + + if(m_renderer.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("Renderer"), m_renderer.GetItemData(m_renderer.GetCurSel())); + } + + if(m_psversion.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), m_psversion.GetItemData(m_psversion.GetCurSel())); + } + + pApp->WriteProfileInt(_T("Settings"), _T("fEnablePalettizedTextures"), m_fEnablePalettizedTextures); + + pApp->WriteProfileInt(_T("Settings"), _T("TexFilter"), m_fLinearTexFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT); + + pApp->WriteProfileInt(_T("Settings"), _T("fEnableTvOut"), m_fEnableTvOut); + pApp->WriteProfileInt(_T("Settings"), _T("fNloopHack"), m_fNloopHack); + pApp->WriteProfileInt(_T("Settings"), _T("RecordState"), m_fRecordState); + pApp->WriteProfileString(_T("Settings"), _T("RecordStatePath"), m_strRecordState); + + __super::OnOK(); +} + +void CGSSettingsDlg::OnBnClickedButton1() +{ + TCHAR path[MAX_PATH]; + + BROWSEINFO bi; + bi.hwndOwner = m_hWnd; + bi.pidlRoot = NULL; + bi.pszDisplayName = path; + bi.lpszTitle = _T("Select path for the state file"); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_USENEWUI; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + + LPITEMIDLIST iil; + if(iil = SHBrowseForFolder(&bi)) + { + SHGetPathFromIDList(iil, path); + m_strRecordState = path; + UpdateData(FALSE); + } +} diff --git a/plugins/gs/gsdx9/GSSettingsDlg.h b/plugins/gs/gsdx9/GSSettingsDlg.h new file mode 100644 index 0000000000..d310cb10e6 --- /dev/null +++ b/plugins/gs/gsdx9/GSSettingsDlg.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "resource.h" +#include "afxwin.h" + +class CGSSettingsDlg : public CDialog +{ + DECLARE_DYNAMIC(CGSSettingsDlg) + +private: + CList m_modes; + +public: + CGSSettingsDlg(CWnd* pParent = NULL); // standard constructor + virtual ~CGSSettingsDlg(); + +// Dialog Data + enum { IDD = IDD_CONFIG }; + CComboBox m_resolution; + CComboBox m_renderer; + CComboBox m_psversion; + BOOL m_fEnablePalettizedTextures; + BOOL m_fEnableTvOut; + BOOL m_fRecordState; + BOOL m_fNloopHack; + CString m_strRecordState; + BOOL m_fLinearTexFilter; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButton1(); +}; diff --git a/plugins/gs/gsdx9/GSSoftVertex.cpp b/plugins/gs/gsdx9/GSSoftVertex.cpp new file mode 100644 index 0000000000..7fa406e44c --- /dev/null +++ b/plugins/gs/gsdx9/GSSoftVertex.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSSoftVertex.h" + +const __m128i _80000000 = _mm_set1_epi32(0x80000000); +const __m128i _4b000000 = _mm_set1_epi32(0x4b000000); +const __m128i _3f800000 = _mm_set1_epi32(0x3f800000); diff --git a/plugins/gs/gsdx9/GSSoftVertex.h b/plugins/gs/gsdx9/GSSoftVertex.h new file mode 100644 index 0000000000..e505a4c38d --- /dev/null +++ b/plugins/gs/gsdx9/GSSoftVertex.h @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +// +// GSSoftVertexFP +// + +extern const __m128i _80000000, _4b000000, _3f800000; + +__declspec(align(16)) union GSSoftVertexFP +{ + class __declspec(novtable) Scalar + { + float val; + + public: + Scalar() {} + explicit Scalar(float f) {val = f;} + explicit Scalar(int i) {val = (float)i;} + + float Value() const {return val;} + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + void sat() {_mm_store_ss(&val, _mm_min_ss(_mm_max_ss(_mm_set_ss(val), _mm_setzero_ps()), _mm_set_ss(255)));} + void rcp() {_mm_store_ss(&val, _mm_rcp_ss(_mm_set_ss(val)));} +#else + void sat() {val = val < 0 ? 0 : val > 255 ? 255 : val;} + void rcp() {val = 1.0f / val;} +#endif + void abs() {val = fabs(val);} + + Scalar floor_s() const {return Scalar(floor(val));} + int floor_i() const {return (int)floor(val);} + + Scalar ceil_s() const {return Scalar(-floor(-val));} + int ceil_i() const {return -(int)floor(-val);} + + void operator = (float f) {val = f;} + void operator = (int i) {val = (float)i;} + + operator float() const {return val;} + operator int() const {return (int)val;} + + void operator += (const Scalar& s) {val += s.val;} + void operator -= (const Scalar& s) {val -= s.val;} + void operator *= (const Scalar& s) {val *= s.val;} + void operator /= (const Scalar& s) {val /= s.val;} + + friend Scalar operator + (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val + s2.val);} + friend Scalar operator - (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val - s2.val);} + friend Scalar operator * (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val * s2.val);} + friend Scalar operator / (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val / s2.val);} + + friend Scalar operator + (const Scalar& s, int i) {return Scalar(s.val + i);} + friend Scalar operator - (const Scalar& s, int i) {return Scalar(s.val - i);} + friend Scalar operator * (const Scalar& s, int i) {return Scalar(s.val * i);} + friend Scalar operator / (const Scalar& s, int i) {return Scalar(s.val / i);} + + friend Scalar operator << (const Scalar& s, int i) {return Scalar(s.val * (1<> (const Scalar& s, int i) {return Scalar(s.val / (1<= 2 || defined(_M_AMD64) + union {__m128 xyzq; __m128 rgba;}; +#endif + }; + + Vector() {} + Vector(const Vector& v) {*this = v;} + Vector(Scalar s) {*this = s;} + Vector(Scalar s0, Scalar s1, Scalar s2, Scalar s3) {x = s0; y = s1; z = s2; q = s3;} + explicit Vector(DWORD dw) {*this = dw;} +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + Vector(__m128 f0123) {*this = f0123;} +#endif + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + + void operator = (const Vector& v) {xyzq = v.xyzq;} + void operator = (Scalar s) {xyzq = _mm_set1_ps(s);} + + void operator = (__m128 f0123) {xyzq = f0123;} + operator __m128() const {return xyzq;} + + void operator = (DWORD dw) {__m128i zero = _mm_setzero_si128(); xyzq = _mm_cvtepi32_ps(_mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(dw), zero), zero));} + operator DWORD() const {__m128i r0 = _mm_cvttps_epi32(xyzq); r0 = _mm_packs_epi32(r0, r0); r0 = _mm_packus_epi16(r0, r0); return (DWORD)_mm_cvtsi128_si32(r0);} + operator UINT64() const {__m128i r0 = _mm_cvttps_epi32(xyzq); r0 = _mm_packs_epi32(r0, r0); return *(UINT64*)&r0;} + + void sat() {xyzq = _mm_min_ps(_mm_max_ps(xyzq, _mm_setzero_ps()), _mm_set1_ps(255));} + void rcp() {xyzq = _mm_rcp_ps(xyzq);} + + Vector floor() + { + __m128 sign = _mm_and_ps(xyzq, *(__m128*)&_80000000); + __m128 r0 = _mm_or_ps(sign, *(__m128*)&_4b000000); + __m128 r1 = _mm_sub_ps(_mm_add_ps(xyzq, r0), r0); + __m128 r2 = _mm_sub_ps(r1, xyzq); + __m128 r3 = _mm_and_ps(_mm_cmpnle_ps(r2, sign), *(__m128*)&_3f800000); + __m128 r4 = _mm_sub_ps(r1, r3); + return r4; + } + + void operator += (const Vector& v) {xyzq = _mm_add_ps(xyzq, v);} + void operator -= (const Vector& v) {xyzq = _mm_sub_ps(xyzq, v);} + void operator *= (const Vector& v) {xyzq = _mm_mul_ps(xyzq, v);} + void operator /= (const Vector& v) {xyzq = _mm_div_ps(xyzq, v);} + +#else + + void operator = (const Vector& v) {x = v.x; y = v.y; z = v.z; q = v.q;} + void operator = (Scalar s) {x = y = z = q = s;} + + void operator = (DWORD dw) + { + x = Scalar((int)((dw>>0)&0xff)); + y = Scalar((int)((dw>>8)&0xff)); + z = Scalar((int)((dw>>16)&0xff)); + q = Scalar((int)((dw>>24)&0xff)); + } + + operator DWORD() const + { + return (DWORD)( + (((DWORD)(int)x&0xff)<<0) | + (((DWORD)(int)y&0xff)<<8) | + (((DWORD)(int)z&0xff)<<16) | + (((DWORD)(int)q&0xff)<<24)); + } + + operator UINT64() const + { + return (DWORD)( + (((UINT64)(int)x&0xffff)<<0) | + (((UINT64)(int)y&0xffff)<<16) | + (((UINT64)(int)z&0xffff)<<32) | + (((UINT64)(int)q&0xffff)<<48)); + } + + void sat() {x.sat(); y.sat(); z.sat(); q.sat();} + void rcp() {x.rcp(); y.rcp(); z.rcp(); q.rcp();} + + Vector floor() {return Vector(x.floor_s(), y.floor_s(), z.floor_s(), q.floor_s());} + + void operator += (const Vector& v) {*this = *this + v;} + void operator -= (const Vector& v) {*this = *this - v;} + void operator *= (const Vector& v) {*this = *this * v;} + void operator /= (const Vector& v) {*this = *this / v;} + +#endif + + friend Vector operator + (const Vector& v1, const Vector& v2); + friend Vector operator - (const Vector& v1, const Vector& v2); + friend Vector operator * (const Vector& v1, const Vector& v2); + friend Vector operator / (const Vector& v1, const Vector& v2); + + friend Vector operator + (const Vector& v, Scalar s); + friend Vector operator - (const Vector& v, Scalar s); + friend Vector operator * (const Vector& v, Scalar s); + friend Vector operator / (const Vector& v, Scalar s); + }; + + struct {__declspec(align(16)) Vector c, p, t;}; + struct {__declspec(align(16)) Vector sv[3];}; + struct {__declspec(align(16)) Scalar s[12];}; + + GSSoftVertexFP() {} + GSSoftVertexFP(const GSSoftVertexFP& v) {*this = v;} + + void operator = (const GSSoftVertexFP& v) {c = v.c; p = v.p; t = v.t;} + void operator += (const GSSoftVertexFP& v) {c += v.c; p += v.p; t += v.t;} + + operator CPoint() const {return CPoint((int)p.x, (int)p.y);} + + __forceinline DWORD GetZ() const + { + ASSERT((float)p.z >= 0 && (float)p.q >= 0); +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + __m128 z = _mm_shuffle_ps(p, p, _MM_SHUFFLE(2,2,2,2)); + __m128 q = _mm_shuffle_ps(p, p, _MM_SHUFFLE(3,3,3,3)); + // TODO: check if our floor is faster than doing ss->si->ss + int zh = _mm_cvttss_si32(z); + __m128 zhi = _mm_cvtsi32_ss(zhi, zh); + __m128 zhf = _mm_mul_ss(_mm_sub_ss(z, zhi), _mm_set_ss(65536)); + int zl = _mm_cvtss_si32(_mm_add_ss(zhf, q)); + return ((DWORD)zh << 16) + (DWORD)zl; +#else + // return ((DWORD)(int)p.z << 16) + (DWORD)(int)((p.z - p.z.floor_s())*65536 + p.q); + + int z = (int)p.z; + return ((DWORD)z << 16) + (DWORD)(((float)p.z - z)*65536 + (float)p.q); +#endif + } + +}; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_add_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_sub_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_mul_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_div_ps(v1, v2));} + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_add_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_sub_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_mul_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_div_ps(v, _mm_set1_ps(s)));} + +__forceinline GSSoftVertexFP::Vector operator << (const GSSoftVertexFP::Vector& v, int i) {return GSSoftVertexFP::Vector(_mm_mul_ps(v, _mm_set1_ps((float)(1 << i))));} +__forceinline GSSoftVertexFP::Vector operator >> (const GSSoftVertexFP::Vector& v, int i) {return GSSoftVertexFP::Vector(_mm_mul_ps(v, _mm_set1_ps(1.0f / (1 << i))));} + +#else + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.q + v2.q);} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.q - v2.q);} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.q * v2.q);} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.q / v2.q);} + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x + s, v.y + s, v.z + s, v.q + s);} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x - s, v.y - s, v.z - s, v.q - s);} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x * s, v.y * s, v.z * s, v.q * s);} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x / s, v.y / s, v.z / s, v.q / s);} + +__forceinline GSSoftVertexFP::Vector operator << (const GSSoftVertexFP::Vector& v, int i) {return GSSoftVertexFP::Vector(v.x << i, v.y << i, v.z << i, v.q << i);} +__forceinline GSSoftVertexFP::Vector operator >> (const GSSoftVertexFP::Vector& v, int i) {return GSSoftVertexFP::Vector(v.x >> i, v.y >> i, v.z >> i, v.q >> i);} + +#endif + +// + +template +__forceinline Vertex operator + (const Vertex& v1, const Vertex& v2) +{ + Vertex v0; + v0.c = v1.c + v2.c; + v0.p = v1.p + v2.p; + v0.t = v1.t + v2.t; + return v0; +} + +template +__forceinline Vertex operator - (const Vertex& v1, const Vertex& v2) +{ + Vertex v0; + v0.c = v1.c - v2.c; + v0.p = v1.p - v2.p; + v0.t = v1.t - v2.t; + return v0; +} + +template +__forceinline Vertex operator * (const Vertex& v, typename Vertex::Scalar s) +{ + Vertex v0; + Vertex::Vector vs(s); + v0.c = v.c * vs; + v0.p = v.p * vs; + v0.t = v.t * vs; + return v0; +} + +template +__forceinline Vertex operator / (const Vertex& v, typename Vertex::Scalar s) +{ + Vertex v0; + Vertex::Vector vs(s); + v0.c = v.c / vs; + v0.p = v.p / vs; + v0.t = v.t / vs; + return v0; +} + +template +__forceinline void Exchange(Vertex* RESTRICT v1, Vertex* RESTRICT v2) +{ + typename Vertex::Vector c = v1->c, p = v1->p, t = v1->t; + v1->c = v2->c; v1->p = v2->p; v1->t = v2->t; + v2->c = c; v2->p = p; v2->t = t; +} diff --git a/plugins/gs/gsdx9/GSSoftVertexFP.h b/plugins/gs/gsdx9/GSSoftVertexFP.h new file mode 100644 index 0000000000..10269456db --- /dev/null +++ b/plugins/gs/gsdx9/GSSoftVertexFP.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +// +// GSSoftVertexFP +// + +__declspec(align(16)) union GSSoftVertexFP +{ + class __declspec(novtable) Scalar + { + float val; + + public: + Scalar() {} + explicit Scalar(float f) {val = f;} + explicit Scalar(int i) {val = (float)i;} + + float Value() const {return val;} + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + void sat() {_mm_store_ss(&val, _mm_min_ss(_mm_max_ss(_mm_set_ss(val), _mm_setzero_ps()), _mm_set_ss(255)));} + void rcp() {_mm_store_ss(&val, _mm_rcp_ss(_mm_set_ss(val)));} +#else + void sat() {val = val < 0 ? 0 : val > 255 ? 255 : val;} + void rcp() {val = 1.0f / val;} +#endif + + void abss() {val = abs(val);} + + Scalar floors() const {return Scalar(floor(val));} + int floori() const {return (int)floor(val);} + + Scalar ceils() const {return Scalar(-floor(-val));} + int ceili() const {return -(int)floor(-val);} + + void operator = (float f) {val = f;} + void operator = (int i) {val = (float)i;} + + operator float() const {return val;} + operator int() const {return (int)val;} + + void operator += (const Scalar& s) {val += s.val;} + void operator -= (const Scalar& s) {val -= s.val;} + void operator *= (const Scalar& s) {val *= s.val;} + void operator /= (const Scalar& s) {val /= s.val;} + + friend Scalar operator + (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val + s2.val);} + friend Scalar operator - (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val - s2.val);} + friend Scalar operator * (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val * s2.val);} + friend Scalar operator / (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val / s2.val);} + + friend Scalar operator + (const Scalar& s1, int i) {return Scalar(s1.val + i);} + friend Scalar operator - (const Scalar& s1, int i) {return Scalar(s1.val - i);} + friend Scalar operator * (const Scalar& s1, int i) {return Scalar(s1.val * i);} + friend Scalar operator / (const Scalar& s1, int i) {return Scalar(s1.val / i);} + + friend bool operator == (const Scalar& s1, const Scalar& s2) {return s1.val == s2.val;} + friend bool operator <= (const Scalar& s1, const Scalar& s2) {return s1.val <= s2.val;} + friend bool operator < (const Scalar& s1, const Scalar& s2) {return s1.val < s2.val;} + }; + + __declspec(align(16)) class __declspec(novtable) Vector + { + public: + union + { + union {struct {Scalar x, y, z, q;}; struct {Scalar r, g, b, a;};}; + union {struct {Scalar v[4];}; struct {Scalar c[4];};}; +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + union {__m128 xyzq; __m128 rgba;}; +#endif + }; + + Vector() {} + Vector(const Vector& v) {*this = v;} + Vector(Scalar s) {*this = s;} + Vector(Scalar s0, Scalar s1, Scalar s2, Scalar s3) {x = s0; y = s1; z = s2; q = s3;} + explicit Vector(DWORD dw) {*this = dw;} +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + Vector(__m128 f0123) {*this = f0123;} +#endif + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + + void operator = (const Vector& v) {xyzq = v.xyzq;} + void operator = (__m128 f0123) {xyzq = f0123;} + void operator = (Scalar s) {xyzq = _mm_set1_ps(s);} + void operator = (DWORD dw) {__m128i zero = _mm_setzero_si128(); xyzq = _mm_cvtepi32_ps(_mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(dw), zero), zero));} + + operator __m128() const {return xyzq;} + operator DWORD() const {__m128i r0 = _mm_cvttps_epi32(xyzq); r0 = _mm_packs_epi32(r0, r0); r0 = _mm_packus_epi16(r0, r0); return (DWORD)_mm_cvtsi128_si32(r0);} + + void sat() {xyzq = _mm_min_ps(_mm_max_ps(xyzq, _mm_setzero_ps()), _mm_set1_ps(255));} + void rcp() {xyzq = _mm_rcp_ps(xyzq);} + + void operator += (const Vector& v) {xyzq = _mm_add_ps(xyzq, v);} + void operator -= (const Vector& v) {xyzq = _mm_sub_ps(xyzq, v);} + void operator *= (const Vector& v) {xyzq = _mm_mul_ps(xyzq, v);} + void operator /= (const Vector& v) {xyzq = _mm_div_ps(xyzq, v);} + +#else + + void operator = (const Vector& v) {x = v.x; y = v.y; z = v.z; q = v.q;} + void operator = (Scalar s) {x = y = z = q = s;} + void operator = (DWORD dw) + { + x = Scalar((int)(dw&0xff)); + y = Scalar((int)((dw>>8)&0xff)); + z = Scalar((int)((dw>>16)&0xff)); + q = Scalar((int)((dw>>24)&0xff)); + } + + operator DWORD() const + { + return (DWORD)((((DWORD)(int)x&0xff)<<0) | (((DWORD)(int)y&0xff)<<8) | (((DWORD)(int)z&0xff)<<16) | (((DWORD)(int)q&0xff)<<24)); + } + + void sat() {x.sat(); y.sat(); z.sat(); q.sat();} + void rcp() {x.rcp(); y.rcp(); z.rcp(); q.rcp();} + + void operator += (const Vector& v) {*this = *this + v;} + void operator -= (const Vector& v) {*this = *this - v;} + void operator *= (const Vector& v) {*this = *this * v;} + void operator /= (const Vector& v) {*this = *this / v;} + +#endif + + void absv() {x.abss(); y.abss(); z.abss(); q.abss();} + + friend Vector operator + (const Vector& v1, const Vector& v2); + friend Vector operator - (const Vector& v1, const Vector& v2); + friend Vector operator * (const Vector& v1, const Vector& v2); + friend Vector operator / (const Vector& v1, const Vector& v2); + + friend Vector operator + (const Vector& v, Scalar s); + friend Vector operator - (const Vector& v, Scalar s); + friend Vector operator * (const Vector& v, Scalar s); + friend Vector operator / (const Vector& v, Scalar s); + }; + + struct {__declspec(align(16)) Vector c, p, t;}; + struct {__declspec(align(16)) Vector sv[3];}; + struct {__declspec(align(16)) Scalar s[12];}; + + GSSoftVertexFP() {} + GSSoftVertexFP(const GSSoftVertexFP& v) {*this = v;} + + void operator = (const GSSoftVertexFP& v) {c = v.c; p = v.p; t = v.t;} + void operator += (const GSSoftVertexFP& v) {c += v.c; p += v.p; t += v.t;} + + operator CPoint() const {return CPoint((int)p.x, (int)p.y);} + + friend GSSoftVertexFP operator + (const GSSoftVertexFP& v1, const GSSoftVertexFP& v2); + friend GSSoftVertexFP operator - (const GSSoftVertexFP& v1, const GSSoftVertexFP& v2); + + friend GSSoftVertexFP operator * (const GSSoftVertexFP& v, Scalar s); + friend GSSoftVertexFP operator / (const GSSoftVertexFP& v, Scalar s); + + static void Exchange(GSSoftVertexFP* __restrict v1, GSSoftVertexFP* __restrict v2) + { + // GSSoftVertexFP v = *v1; *v1 = *v2; *v2 = v; + Vector c = v1->c, p = v1->p, t = v1->t; + v1->c = v2->c; v1->p = v2->p; v1->t = v2->t; + v2->c = c; v2->p = p; v2->t = t; + } + + //__forceinline DWORD GetZ() const {return ((DWORD)p.z<<16) + (DWORD)((p.z - floorf(p.z))*65536 + p.q);} + __forceinline DWORD GetZ() const + { + ASSERT((float)p.z >= 0 && (float)p.q >= 0); + int z = (int)p.z; + return ((DWORD)z << 16) + (DWORD)(((float)p.z - z)*65536 + (float)p.q); + } +}; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_add_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_sub_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_mul_ps(v1, v2));} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(_mm_div_ps(v1, v2));} + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_add_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_sub_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_mul_ps(v, _mm_set1_ps(s)));} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(_mm_div_ps(v, _mm_set1_ps(s)));} + +#else + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.q + v2.q);} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.q - v2.q);} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.q * v2.q);} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v1, const GSSoftVertexFP::Vector& v2) {return GSSoftVertexFP::Vector(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.q / v2.q);} + +__forceinline GSSoftVertexFP::Vector operator + (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x + s, v.y + s, v.z + s, v.q + s);} +__forceinline GSSoftVertexFP::Vector operator - (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x - s, v.y - s, v.z - s, v.q - s);} +__forceinline GSSoftVertexFP::Vector operator * (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x * s, v.y * s, v.z * s, v.q * s);} +__forceinline GSSoftVertexFP::Vector operator / (const GSSoftVertexFP::Vector& v, GSSoftVertexFP::Scalar s) {return GSSoftVertexFP::Vector(v.x / s, v.y / s, v.z / s, v.q / s);} + +#endif + +__forceinline GSSoftVertexFP operator + (const GSSoftVertexFP& v1, const GSSoftVertexFP& v2) +{ + GSSoftVertexFP v0; + v0.c = v1.c + v2.c; + v0.p = v1.p + v2.p; + v0.t = v1.t + v2.t; + return v0; +} + +__forceinline GSSoftVertexFP operator - (const GSSoftVertexFP& v1, const GSSoftVertexFP& v2) +{ + GSSoftVertexFP v0; + v0.c = v1.c - v2.c; + v0.p = v1.p - v2.p; + v0.t = v1.t - v2.t; + return v0; +} + +__forceinline GSSoftVertexFP operator * (const GSSoftVertexFP& v, GSSoftVertexFP::Scalar s) +{ + GSSoftVertexFP v0; + GSSoftVertexFP::Vector vs(s); + v0.c = v.c * vs; + v0.p = v.p * vs; + v0.t = v.t * vs; + return v0; +} + +__forceinline GSSoftVertexFP operator / (const GSSoftVertexFP& v, GSSoftVertexFP::Scalar s) +{ + GSSoftVertexFP v0; + GSSoftVertexFP::Vector vs(s); + v0.c = v.c / vs; + v0.p = v.p / vs; + v0.t = v.t / vs; + return v0; +} diff --git a/plugins/gs/gsdx9/GSSoftVertexFX.h b/plugins/gs/gsdx9/GSSoftVertexFX.h new file mode 100644 index 0000000000..b803426d9b --- /dev/null +++ b/plugins/gs/gsdx9/GSSoftVertexFX.h @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once +/* +inline int fixmul(int x, int y) +{ +#ifndef _M_AMD64 + __asm + { + mov eax, x + imul y + add eax, 0x8000 + adc edx, 0 + shrd eax, edx, 16 + } +#else + return (int)(((__int64)x * y + 0x8000) >> 16); +#endif +} +*/ +inline int fixmul(int x, int y) +{ +#ifndef _M_AMD64 + _asm + { + mov eax, x + imul y + shrd eax, edx, 16 + sar edx, 15 + jz Out2 + cmp edx, -1 + jz Out2 + ; call _set_errno_erange + mov eax, 0x7FFFFFFF + cmp x, 0 + jge Out1 + neg eax + Out1: + cmp y, 0 + jge Out2 + neg eax + Out2: + } +#else + return (int)(((__int64)x * y + 0x8000) >> 16); +#endif +} + +inline int fixdiv(int x, int y) +{ +#ifndef _M_AMD64 + _asm + { + push esi + + mov ecx, y + xor esi, esi + mov eax, x + or eax, eax + jns Out1 + neg eax + inc esi + Out1: + or ecx, ecx + jns Out2 + neg ecx + inc esi + Out2: + mov edx, eax + shr edx, 0x10 + shl eax, 0x10 + cmp edx, ecx + jae Out3 + div ecx + or eax, eax + jns Out4 + Out3: + ; call _set_errno_erange + mov eax, 0x7FFFFFFF + Out4: + test esi, 1 + je Out5 + neg eax + Out5: + pop esi + } +#else + return (int)(((__int64)x << 16) / y); +#endif +} + +// +// GSSoftVertexFX +// + +__declspec(align(16)) union GSSoftVertexFX +{ + class __declspec(novtable) Scalar + { + int val; + + public: + Scalar() {} + explicit Scalar(float f) {val = (int)(f*65536);} + explicit Scalar(int i) {val = i;} + + int Value() const {return val;} + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + void sat() {ASSERT(0); val = val < 0 ? 0 : val > (255<<16) ? (255<<16) : val;} // TODO + void rcp() {val = (int)(65536.0f*65536.0f / val);} // TODO +#else + void sat() {val = val < 0 ? 0 : val > (255<<16) ? (255<<16) : val;} + void rcp() {val = (int)(65536.0f*65536.0f / val);} +#endif + void abss() {val = abs(val);} + + Scalar floors() const {Scalar s; s.val = val & 0xffff0000; return s;} + int floori() const {return val >> 16;} + + Scalar ceils() const {Scalar s; s.val = (val + 0xffff) & 0xffff0000; return s;} + int ceili() const {return (val + 0xffff) >> 16;} + + void operator = (float f) {val = (int)(f*65536);} + void operator = (int i) {val = i;} + + operator float() const {return (float)val / 65536;} + operator int() const {return val >> 16;} + + void operator += (const Scalar& s) {val += s.val;} + void operator -= (const Scalar& s) {val -= s.val;} + void operator *= (const Scalar& s) {val = fixmul(val, s.val);} + void operator /= (const Scalar& s) {val = fixdiv(val, s.val);} + + friend Scalar operator + (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val + s2.val);} + friend Scalar operator - (const Scalar& s1, const Scalar& s2) {return Scalar(s1.val - s2.val);} + friend Scalar operator * (const Scalar& s1, const Scalar& s2) {return Scalar(fixmul(s1.val, s2.val));} + friend Scalar operator / (const Scalar& s1, const Scalar& s2) {return Scalar(fixdiv(s1.val, s2.val));} + + friend Scalar operator + (const Scalar& s1, int i) {return Scalar(s1.val + i);} + friend Scalar operator - (const Scalar& s1, int i) {return Scalar(s1.val - i);} + friend Scalar operator * (const Scalar& s1, int i) {return Scalar(s1.val * i);} + friend Scalar operator / (const Scalar& s1, int i) {return Scalar(s1.val / i);} + + friend bool operator == (const Scalar& s1, const Scalar& s2) {return s1.val == s2.val;} + friend bool operator <= (const Scalar& s1, const Scalar& s2) {return s1.val <= s2.val;} + friend bool operator < (const Scalar& s1, const Scalar& s2) {return s1.val < s2.val;} + }; + + __declspec(align(16)) class __declspec(novtable) Vector + { + public: + union + { + union {struct {Scalar x, y, z, q;}; struct {Scalar r, g, b, a;};}; + union {struct {Scalar v[4];}; struct {Scalar c[4];};}; +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + union {__m128i xyzq; __m128i rgba;}; +#endif + }; + + Vector() {} + Vector(const Vector& v) {*this = v;} + Vector(Scalar s) {*this = s;} + Vector(Scalar s0, Scalar s1, Scalar s2, Scalar s3) {x = s0; y = s1; z = s2; q = s3;} + explicit Vector(DWORD dw) {*this = dw;} +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + Vector(__m128i i0123) {*this = i0123;} +#endif + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + + void operator = (const Vector& v) {xyzq = v.xyzq;} + void operator = (__m128i i0123) {xyzq = i0123;} + void operator = (Scalar s) {xyzq = _mm_set1_epi32(s.Value());} + void operator = (DWORD dw) + { + __m128i zero = _mm_setzero_si128(); + xyzq = _mm_unpacklo_epi16(zero, _mm_unpacklo_epi8(_mm_cvtsi32_si128(dw), zero)); + } + + operator __m128i() const {return xyzq;} + operator DWORD() const + { + __m128i r0 = xyzq; + r0 = _mm_srli_si128(r0, 2); + r0 = _mm_packs_epi32(r0, r0); + r0 = _mm_packus_epi16(r0, r0); + return (DWORD)_mm_cvtsi128_si32(r0); + } + + void sat() {xyzq = _mm_and_si128(_mm_min_epi16(_mm_max_epi16(xyzq, _mm_setzero_si128()), _mm_set1_epi32(0x00ff0000)), _mm_set1_epi32(0xffff0000));} + void rcp() {ASSERT(0);} // TODO {xyzq = _mm_rcp_ps(xyzq);} + +#else + + void operator = (const Vector& v) {x = v.x; y = v.y; z = v.z; q = v.q;} + void operator = (Scalar s) {x = y = z = q = s;} + void operator = (DWORD dw) + { + x = (int)((dw & 0x000000ff) << 16); + y = (int)((dw & 0x0000ff00) << 8); + z = (int)((dw & 0x00ff0000) << 0); + q = (int)((dw & 0xff000000) >> 8); + } + + operator DWORD() const + { + return (DWORD)((((DWORD)(int)x&0xff)<<0) | (((DWORD)(int)y&0xff)<<8) | (((DWORD)(int)z&0xff)<<16) | (((DWORD)(int)q&0xff)<<24)); + } + + void sat() {x.sat(); y.sat(); z.sat(); q.sat();} + void rcp() {x.rcp(); y.rcp(); z.rcp(); q.rcp();} + +#endif + // TODO + void operator += (const Vector& v) {*this = *this + v;} + void operator -= (const Vector& v) {*this = *this - v;} + void operator *= (const Vector& v) {*this = *this * v;} + void operator /= (const Vector& v) {*this = *this / v;} + + void absv() {x.abss(); y.abss(); z.abss(); q.abss();} + + friend Vector operator + (const Vector& v1, const Vector& v2); + friend Vector operator - (const Vector& v1, const Vector& v2); + friend Vector operator * (const Vector& v1, const Vector& v2); + friend Vector operator / (const Vector& v1, const Vector& v2); + + friend Vector operator + (const Vector& v, Scalar s); + friend Vector operator - (const Vector& v, Scalar s); + friend Vector operator * (const Vector& v, Scalar s); + friend Vector operator / (const Vector& v, Scalar s); + }; + + struct {__declspec(align(16)) Vector c, p, t;}; + struct {__declspec(align(16)) Vector sv[3];}; + struct {__declspec(align(16)) Scalar s[12];}; + + GSSoftVertexFX() {} + GSSoftVertexFX(const GSSoftVertexFX& v) {*this = v;} + + void operator = (const GSSoftVertexFX& v) {c = v.c; p = v.p; t = v.t;} + void operator += (const GSSoftVertexFX& v) {c += v.c; p += v.p; t += v.t;} + + operator CPoint() const {return CPoint((int)p.x, (int)p.y);} + + friend GSSoftVertexFX operator + (const GSSoftVertexFX& v1, const GSSoftVertexFX& v2); + friend GSSoftVertexFX operator - (const GSSoftVertexFX& v1, const GSSoftVertexFX& v2); + + friend GSSoftVertexFX operator * (const GSSoftVertexFX& v, Scalar s); + friend GSSoftVertexFX operator / (const GSSoftVertexFX& v, Scalar s); + + static void Exchange(GSSoftVertexFX* __restrict v1, GSSoftVertexFX* __restrict v2) + { + // GSSoftVertexFX v = *v1; *v1 = *v2; *v2 = v; + Vector c = v1->c, p = v1->p, t = v1->t; + v1->c = v2->c; v1->p = v2->p; v1->t = v2->t; + v2->c = c; v2->p = p; v2->t = t; + } + + __forceinline DWORD GetZ() const + { + ASSERT((int)p.z >= 0 && (int)p.q >= 0); + return ((DWORD)(int)p.z << 1) + ((DWORD)(int)p.q >> 15); + } +}; + +#if _M_IX86_FP >= 2 || defined(_M_AMD64) + +__forceinline GSSoftVertexFX::Vector operator + (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(_mm_add_epi32(v1, v2));} +__forceinline GSSoftVertexFX::Vector operator - (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(_mm_sub_epi32(v1, v2));} +__forceinline GSSoftVertexFX::Vector operator * (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) +{ + // TODO + __m128 r1 = _mm_mul_ps(_mm_cvtepi32_ps(v1), _mm_set1_ps(1.0f/65536)); + __m128 r2 = _mm_cvtepi32_ps(v2); + __m128i r0 = _mm_cvtps_epi32(_mm_mul_ps(r1, r2)); + return GSSoftVertexFX::Vector(r0); +} +__forceinline GSSoftVertexFX::Vector operator / (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) +{ + // TODO + __m128 r1 = _mm_mul_ps(_mm_cvtepi32_ps(v1), _mm_set1_ps(65536)); + __m128 r2 = _mm_cvtepi32_ps(v2); + __m128i r0 = _mm_cvtps_epi32(_mm_div_ps(r1, r2)); + return GSSoftVertexFX::Vector(r0); +} + +__forceinline GSSoftVertexFX::Vector operator + (const GSSoftVertexFX::Vector& v, const GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(_mm_add_epi32(v, _mm_set1_epi32(s.Value())));} +__forceinline GSSoftVertexFX::Vector operator - (const GSSoftVertexFX::Vector& v, const GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(_mm_sub_epi32(v, _mm_set1_epi32(s.Value())));} +__forceinline GSSoftVertexFX::Vector operator * (const GSSoftVertexFX::Vector& v, const GSSoftVertexFX::Scalar s) +{ + // TODO + __m128 r1 = _mm_mul_ps(_mm_cvtepi32_ps(v), _mm_set1_ps(1.0f/65536)); + __m128 r2 = _mm_cvtepi32_ps(_mm_set1_epi32(s.Value())); + __m128i r0 = _mm_cvtps_epi32(_mm_mul_ps(r1, r2)); + return GSSoftVertexFX::Vector(r0); +} +__forceinline GSSoftVertexFX::Vector operator / (const GSSoftVertexFX::Vector& v, const GSSoftVertexFX::Scalar s) +{ + // TODO + __m128 r1 = _mm_mul_ps(_mm_cvtepi32_ps(v), _mm_set1_ps(65536)); + __m128 r2 = _mm_cvtepi32_ps(_mm_set1_epi32(s.Value())); + __m128i r0 = _mm_cvtps_epi32(_mm_div_ps(r1, r2)); + return GSSoftVertexFX::Vector(r0); +} + +#else + +__forceinline GSSoftVertexFX::Vector operator + (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.q + v2.q);} +__forceinline GSSoftVertexFX::Vector operator - (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.q - v2.q);} +__forceinline GSSoftVertexFX::Vector operator * (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.q * v2.q);} +__forceinline GSSoftVertexFX::Vector operator / (const GSSoftVertexFX::Vector& v1, const GSSoftVertexFX::Vector& v2) {return GSSoftVertexFX::Vector(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.q / v2.q);} + +__forceinline GSSoftVertexFX::Vector operator + (const GSSoftVertexFX::Vector& v, GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(v.x + s, v.y + s, v.z + s, v.q + s);} +__forceinline GSSoftVertexFX::Vector operator - (const GSSoftVertexFX::Vector& v, GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(v.x - s, v.y - s, v.z - s, v.q - s);} +__forceinline GSSoftVertexFX::Vector operator * (const GSSoftVertexFX::Vector& v, GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(v.x * s, v.y * s, v.z * s, v.q * s);} +__forceinline GSSoftVertexFX::Vector operator / (const GSSoftVertexFX::Vector& v, GSSoftVertexFX::Scalar s) {return GSSoftVertexFX::Vector(v.x / s, v.y / s, v.z / s, v.q / s);} + +#endif + +__forceinline GSSoftVertexFX operator + (const GSSoftVertexFX& v1, const GSSoftVertexFX& v2) +{ + GSSoftVertexFX v0; + v0.c = v1.c + v2.c; + v0.p = v1.p + v2.p; + v0.t = v1.t + v2.t; + return v0; +} + +__forceinline GSSoftVertexFX operator - (const GSSoftVertexFX& v1, const GSSoftVertexFX& v2) +{ + GSSoftVertexFX v0; + v0.c = v1.c - v2.c; + v0.p = v1.p - v2.p; + v0.t = v1.t - v2.t; + return v0; +} + +__forceinline GSSoftVertexFX operator * (const GSSoftVertexFX& v, GSSoftVertexFX::Scalar s) +{ + GSSoftVertexFX v0; + GSSoftVertexFX::Vector vs(s); + v0.c = v.c * vs; + v0.p = v.p * vs; + v0.t = v.t * vs; + return v0; +} + +__forceinline GSSoftVertexFX operator / (const GSSoftVertexFX& v, GSSoftVertexFX::Scalar s) +{ + GSSoftVertexFX v0; + GSSoftVertexFX::Vector vs(s); + v0.c = v.c / vs; + v0.p = v.p / vs; + v0.t = v.t / vs; + return v0; +} diff --git a/plugins/gs/gsdx9/GSState.cpp b/plugins/gs/gsdx9/GSState.cpp new file mode 100644 index 0000000000..bd0fdc9871 --- /dev/null +++ b/plugins/gs/gsdx9/GSState.cpp @@ -0,0 +1,1135 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSState.h" +#include "GSdx9.h" +#include "GSUtil.h" +#include "resource.h" + +// +// GSState +// + +GSState::GSState(int w, int h, HWND hWnd, HRESULT& hr) + : m_hWnd(hWnd) + , m_width(w) + , m_height(h) + , m_sfp(NULL) + , m_fp(NULL) + , m_iOSD(1) +{ + hr = E_FAIL; + + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CWinApp* pApp = AfxGetApp(); + + m_v.RGBAQ.Q = m_q = 1.0f; + + memset(m_path, 0, sizeof(m_path)); + + m_de.PRMODECONT.AC = 1; + m_pPRIM = &m_de.PRIM; + m_PRIM = 8; + + m_fpGSirq = NULL; + + m_ctxt = &m_de.CTXT[0]; + + m_pTrBuff = (BYTE*)_aligned_malloc(1024*1024*4, 16); + m_nTrBytes = 0; + + for(int i = 0; i < countof(m_fpGIFPackedRegHandlers); i++) + m_fpGIFPackedRegHandlers[i] = &GSState::GIFPackedRegHandlerNull; + + m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerPRIM; + m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA; + m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ; + m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerUV; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerXYZF2; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerXYZ2; + m_fpGIFPackedRegHandlers[GIF_REG_TEX0_1] = &GSState::GIFPackedRegHandlerTEX0_1; + m_fpGIFPackedRegHandlers[GIF_REG_TEX0_2] = &GSState::GIFPackedRegHandlerTEX0_2; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerCLAMP_1; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerCLAMP_2; + m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerFOG; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerXYZF3; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerXYZ3; + m_fpGIFPackedRegHandlers[GIF_REG_A_D] = &GSState::GIFPackedRegHandlerA_D; + m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP; + + for(int i = 0; i < countof(m_fpGIFRegHandlers); i++) + m_fpGIFRegHandlers[i] = &GSState::GIFRegHandlerNull; + + m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerPRIM; + m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ; + m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST; + m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerUV; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerXYZF2; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerXYZ2; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_1] = &GSState::GIFRegHandlerTEX0_1; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_2] = &GSState::GIFRegHandlerTEX0_2; + m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_1] = &GSState::GIFRegHandlerCLAMP_1; + m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_2] = &GSState::GIFRegHandlerCLAMP_2; + m_fpGIFRegHandlers[GIF_A_D_REG_FOG] = &GSState::GIFRegHandlerFOG; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerXYZF3; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerXYZ3; + m_fpGIFRegHandlers[GIF_A_D_REG_NOP] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_1] = &GSState::GIFRegHandlerTEX1_1; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_2] = &GSState::GIFRegHandlerTEX1_2; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_1] = &GSState::GIFRegHandlerTEX2_1; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_2] = &GSState::GIFRegHandlerTEX2_2; + m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_1] = &GSState::GIFRegHandlerXYOFFSET_1; + m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_2] = &GSState::GIFRegHandlerXYOFFSET_2; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerPRMODECONT; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerPRMODE; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXCLUT] = &GSState::GIFRegHandlerTEXCLUT; + m_fpGIFRegHandlers[GIF_A_D_REG_SCANMSK] = &GSState::GIFRegHandlerSCANMSK; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_1] = &GSState::GIFRegHandlerMIPTBP1_1; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_2] = &GSState::GIFRegHandlerMIPTBP1_2; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_1] = &GSState::GIFRegHandlerMIPTBP2_1; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_2] = &GSState::GIFRegHandlerMIPTBP2_2; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXA] = &GSState::GIFRegHandlerTEXA; + m_fpGIFRegHandlers[GIF_A_D_REG_FOGCOL] = &GSState::GIFRegHandlerFOGCOL; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXFLUSH] = &GSState::GIFRegHandlerTEXFLUSH; + m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_1] = &GSState::GIFRegHandlerSCISSOR_1; + m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_2] = &GSState::GIFRegHandlerSCISSOR_2; + m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_1] = &GSState::GIFRegHandlerALPHA_1; + m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_2] = &GSState::GIFRegHandlerALPHA_2; + m_fpGIFRegHandlers[GIF_A_D_REG_DIMX] = &GSState::GIFRegHandlerDIMX; + m_fpGIFRegHandlers[GIF_A_D_REG_DTHE] = &GSState::GIFRegHandlerDTHE; + m_fpGIFRegHandlers[GIF_A_D_REG_COLCLAMP] = &GSState::GIFRegHandlerCOLCLAMP; + m_fpGIFRegHandlers[GIF_A_D_REG_TEST_1] = &GSState::GIFRegHandlerTEST_1; + m_fpGIFRegHandlers[GIF_A_D_REG_TEST_2] = &GSState::GIFRegHandlerTEST_2; + m_fpGIFRegHandlers[GIF_A_D_REG_PABE] = &GSState::GIFRegHandlerPABE; + m_fpGIFRegHandlers[GIF_A_D_REG_FBA_1] = &GSState::GIFRegHandlerFBA_1; + m_fpGIFRegHandlers[GIF_A_D_REG_FBA_2] = &GSState::GIFRegHandlerFBA_2; + m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_1] = &GSState::GIFRegHandlerFRAME_1; + m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_2] = &GSState::GIFRegHandlerFRAME_2; + m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_1] = &GSState::GIFRegHandlerZBUF_1; + m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_2] = &GSState::GIFRegHandlerZBUF_2; + m_fpGIFRegHandlers[GIF_A_D_REG_BITBLTBUF] = &GSState::GIFRegHandlerBITBLTBUF; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXPOS] = &GSState::GIFRegHandlerTRXPOS; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXREG] = &GSState::GIFRegHandlerTRXREG; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXDIR] = &GSState::GIFRegHandlerTRXDIR; + m_fpGIFRegHandlers[GIF_A_D_REG_HWREG] = &GSState::GIFRegHandlerHWREG; + m_fpGIFRegHandlers[GIF_A_D_REG_SIGNAL] = &GSState::GIFRegHandlerSIGNAL; + m_fpGIFRegHandlers[GIF_A_D_REG_FINISH] = &GSState::GIFRegHandlerFINISH; + m_fpGIFRegHandlers[GIF_A_D_REG_LABEL] = &GSState::GIFRegHandlerLABEL; + + // DD + + CComPtr pDD; + if(FAILED(DirectDrawCreateEx(0, (void**)&pDD, IID_IDirectDraw7, 0))) + return; + + m_ddcaps.dwSize = sizeof(DDCAPS); + if(FAILED(pDD->GetCaps(&m_ddcaps, NULL))) + return; + + pDD = NULL; + + // D3D + + if(!(m_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) + && !(m_pD3D = Direct3DCreate9(D3D9b_SDK_VERSION))) + return; + + ZeroMemory(&m_caps, sizeof(m_caps)); + m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, &m_caps); + + m_fmtDepthStencil = + IsDepthFormatOk(m_pD3D, D3DFMT_D32, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8) ? D3DFMT_D32 : + IsDepthFormatOk(m_pD3D, D3DFMT_D24X8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8) ? D3DFMT_D24X8 : + D3DFMT_D16; + + // D3D Device + + if(FAILED(ResetDevice(true))) + return; + + // Shaders + + DWORD PixelShaderVersion = pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)); + + if(PixelShaderVersion > m_caps.PixelShaderVersion) + { + CString str; + str.Format(_T("Supported pixel shader version is too low!\n\nSupported: %d.%d\nSelected: %d.%d"), + D3DSHADER_VERSION_MAJOR(m_caps.PixelShaderVersion), D3DSHADER_VERSION_MINOR(m_caps.PixelShaderVersion), + D3DSHADER_VERSION_MAJOR(PixelShaderVersion), D3DSHADER_VERSION_MINOR(PixelShaderVersion)); + AfxMessageBox(str); + m_pD3DDev = NULL; + return; + } + + m_caps.PixelShaderVersion = min(PixelShaderVersion, m_caps.PixelShaderVersion); + + static const TCHAR* hlsl_tfx[] = + { + _T("main_tfx0_32"), _T("main_tfx1_32"), _T("main_tfx2_32"), _T("main_tfx3_32"), + _T("main_tfx0_24"), _T("main_tfx1_24"), _T("main_tfx2_24"), _T("main_tfx3_24"), + _T("main_tfx0_24AEM"), _T("main_tfx1_24AEM"), _T("main_tfx2_24AEM"), _T("main_tfx3_24AEM"), + _T("main_tfx0_16"), _T("main_tfx1_16"), _T("main_tfx2_16"), _T("main_tfx3_16"), + _T("main_tfx0_16AEM"), _T("main_tfx1_16AEM"), _T("main_tfx2_16AEM"), _T("main_tfx3_16AEM"), + _T("main_tfx0_8P_pt"), _T("main_tfx1_8P_pt"), _T("main_tfx2_8P_pt"), _T("main_tfx3_8P_pt"), + _T("main_tfx0_8P_ln"), _T("main_tfx1_8P_ln"), _T("main_tfx2_8P_ln"), _T("main_tfx3_8P_ln"), + _T("main_tfx0_8HP_pt"), _T("main_tfx1_8HP_pt"), _T("main_tfx2_8HP_pt"), _T("main_tfx3_8HP_pt"), + _T("main_tfx0_8HP_ln"), _T("main_tfx1_8HP_ln"), _T("main_tfx2_8HP_ln"), _T("main_tfx3_8HP_ln"), + _T("main_notfx"), + _T("main_8PTo32"), + }; + + // ps_3_0 + + if(m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + for(int i = 0; i < countof(hlsl_tfx); i++) + { + if(m_pHLSLTFX[i]) continue; + + CompileShaderFromResource(m_pD3DDev, IDR_HLSL_TFX, hlsl_tfx[i], _T("ps_3_0"), + D3DXSHADER_AVOID_FLOW_CONTROL|D3DXSHADER_PARTIALPRECISION, &m_pHLSLTFX[i]); + } + + for(int i = 0; i < 3; i++) + { + if(m_pHLSLMerge[i]) continue; + + CString main; + main.Format(_T("main%d"), i); + CompileShaderFromResource(m_pD3DDev, IDR_HLSL_MERGE, main, _T("ps_3_0"), + D3DXSHADER_AVOID_FLOW_CONTROL|D3DXSHADER_PARTIALPRECISION, &m_pHLSLMerge[i]); + } + } + + // ps_2_0 + + if(m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0)) + { + for(int i = 0; i < countof(hlsl_tfx); i++) + { + if(m_pHLSLTFX[i]) continue; + + CompileShaderFromResource(m_pD3DDev, IDR_HLSL_TFX, hlsl_tfx[i], _T("ps_2_0"), + D3DXSHADER_PARTIALPRECISION, &m_pHLSLTFX[i]); + } + + for(int i = 0; i < 3; i++) + { + if(m_pHLSLMerge[i]) continue; + + CString main; + main.Format(_T("main%d"), i); + CompileShaderFromResource(m_pD3DDev, IDR_HLSL_MERGE, main, _T("ps_2_0"), + D3DXSHADER_PARTIALPRECISION, &m_pHLSLMerge[i]); + } + } + + // ps_1_1 + ps_1_4 + + if(m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 1)) + { + static const UINT nShaderIDs[] = + { + IDR_PS11_TFX000, IDR_PS11_TFX010, IDR_PS11_TFX011, + IDR_PS11_TFX1x0, IDR_PS11_TFX1x1, + IDR_PS11_TFX200, IDR_PS11_TFX210, IDR_PS11_TFX211, + IDR_PS11_TFX300, IDR_PS11_TFX310, IDR_PS11_TFX311, + IDR_PS11_TFX4xx, + IDR_PS11_EN11, IDR_PS11_EN01, IDR_PS11_EN10, IDR_PS11_EN00, + IDR_PS14_EN11, IDR_PS14_EN01, IDR_PS14_EN10, IDR_PS14_EN00 + }; + + for(int i = 0; i < countof(nShaderIDs); i++) + { + if(m_pPixelShaders[i]) continue; + AssembleShaderFromResource(m_pD3DDev, nShaderIDs[i], 0, &m_pPixelShaders[i]); + } + + if(!m_pHLSLRedBlue) + { + CompileShaderFromResource(m_pD3DDev, IDR_HLSL_RB, _T("main"), _T("ps_1_1"), + D3DXSHADER_PARTIALPRECISION, &m_pHLSLRedBlue); + } + } + + // + + m_strDefaultTitle.ReleaseBufferSetLength(GetWindowText(m_hWnd, m_strDefaultTitle.GetBuffer(256), 256)); + + m_fEnablePalettizedTextures = !!pApp->GetProfileInt(_T("Settings"), _T("fEnablePalettizedTextures"), FALSE); + + m_fNloopHack = pApp->GetProfileInt(_T("Settings"), _T("fNloopHack"), FALSE); + + + // + + hr = S_OK; + + Reset(); + +#if defined(DEBUG_LOG) || defined(DEBUG_LOG2) + ::DeleteFile(_T("g:\\gs.txt")); + m_fp = _tfopen(_T("g:\\gs.txt"), _T("at")); +#endif + +// m_rs.pCSR->rREV = 0x20; + +/* + GSLocalMemory lm; + + int w = 512, h = 512; + + for(int y = 0; y < h; y++) + { + for(int x = 0; x < w; x++) + { + lm.writePixel24(x, y, (x * 255 / w) | ((y * 255 / h) << 8), 0x500, 8); + } + } + + for(int i = 16; i > 0; i--) + { + CString fn; + fn.Format(_T("g:/%02d.bmp"), i); + lm.SaveBMP(m_pD3DDev, fn, 0x500, i, PSM_PSMCT24, i*64, 512); + } +*/ +} + +GSState::~GSState() +{ + Reset(); + _aligned_free(m_pTrBuff); + if(m_sfp) fclose(m_sfp); + if(m_fp) fclose(m_fp); +} + +HRESULT GSState::ResetDevice(bool fForceWindowed) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + HMODULE hModule = AfxGetResourceHandle(); + CWinApp* pApp = AfxGetApp(); + + HRESULT hr; + + if(!m_pD3D) + return E_FAIL; + + m_pOrgRenderTarget = NULL; + m_pTmpRenderTarget = NULL; + m_pD3DXFont = NULL; + + ZeroMemory(&m_d3dpp, sizeof(m_d3dpp)); + m_d3dpp.Windowed = TRUE; + m_d3dpp.hDeviceWindow = m_hWnd; + m_d3dpp.SwapEffect = /*D3DSWAPEFFECT_COPY*/D3DSWAPEFFECT_DISCARD/*D3DSWAPEFFECT_FLIP*/; + m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + m_d3dpp.BackBufferWidth = m_width; + m_d3dpp.BackBufferHeight = m_height; + //m_d3dpp.BackBufferCount = 3; + m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + if(!!pApp->GetProfileInt(_T("Settings"), _T("fEnableTvOut"), FALSE)) + m_d3dpp.Flags |= D3DPRESENTFLAG_VIDEO; + + int ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); + int ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); + int ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); + + if(!fForceWindowed && ModeWidth > 0 && ModeHeight > 0 && ModeRefreshRate >= 0) + { + m_d3dpp.Windowed = FALSE; + m_d3dpp.BackBufferWidth = ModeWidth; + m_d3dpp.BackBufferHeight = ModeHeight; + m_d3dpp.FullScreen_RefreshRateInHz = ModeRefreshRate; + m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + + ::SetWindowLong(m_hWnd, GWL_STYLE, ::GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME)); + ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + ::SetMenu(m_hWnd, NULL); + + m_iOSD = 0; + } + + if(!m_pD3DDev) + { + if(FAILED(hr = m_pD3D->CreateDevice( + // m_pD3D->GetAdapterCount()-1, D3DDEVTYPE_REF, + D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, + m_hWnd, + m_caps.VertexProcessingCaps ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &m_d3dpp, &m_pD3DDev))) + return hr; + } + else + { + if(FAILED(hr = m_pD3DDev->Reset(&m_d3dpp))) + { + if(D3DERR_DEVICELOST == hr) + { + Sleep(1000); + if(FAILED(hr = m_pD3DDev->Reset(&m_d3dpp))) + return hr; + } + else + { + return hr; + } + } + } + + CComPtr pBackBuff; + hr = m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuff); + + ZeroMemory(&m_bd, sizeof(m_bd)); + pBackBuff->GetDesc(&m_bd); + + hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); + + hr = m_pD3DDev->GetRenderTarget(0, &m_pOrgRenderTarget); + + if(m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 1) && m_caps.PixelShaderVersion <= D3DPS_VERSION(1, 3) + && m_pHLSLRedBlue) + { + hr = m_pD3DDev->CreateTexture( + m_bd.Width, m_bd.Height, 0, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, + D3DPOOL_DEFAULT, &m_pTmpRenderTarget, NULL); + } + + D3DXFONT_DESC fd; + memset(&fd, 0, sizeof(fd)); + _tcscpy(fd.FaceName, _T("Arial")); + fd.Height = -(int)(sqrt((float)m_bd.Height) * 0.7); + hr = D3DXCreateFontIndirect(m_pD3DDev, &fd, &m_pD3DXFont); + + hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + + m_texfilter = (D3DTEXTUREFILTERTYPE)pApp->GetProfileInt(_T("Settings"), _T("TexFilter"), D3DTEXF_LINEAR); + + for(int i = 0; i < 8; i++) + { + hr = m_pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, m_texfilter); + hr = m_pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, m_texfilter); + // hr = m_pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, m_texfilter); + hr = m_pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + hr = m_pD3DDev->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + + return S_OK; +} + +UINT32 GSState::Freeze(freezeData* fd, bool fSizeOnly) +{ + int size = sizeof(m_version) + + sizeof(m_de) + sizeof(m_v) + + sizeof(m_x) + sizeof(m_y) + 1024*1024*4 + + sizeof(m_path) + sizeof(m_q) + /*+ sizeof(m_vl)*/; + + if(fSizeOnly) + { + fd->size = size; + return 0; + } + else if(!fd->data || fd->size < size) + { + return -1; + } + + FlushWriteTransfer(); + + FlushPrimInternal(); + + BYTE* data = fd->data; + memcpy(data, &m_version, sizeof(m_version)); data += sizeof(m_version); + memcpy(data, &m_de, sizeof(m_de)); data += sizeof(m_de); + memcpy(data, &m_v, sizeof(m_v)); data += sizeof(m_v); + memcpy(data, &m_x, sizeof(m_x)); data += sizeof(m_x); + memcpy(data, &m_y, sizeof(m_y)); data += sizeof(m_y); + memcpy(data, m_lm.GetVM(), 1024*1024*4); data += 1024*1024*4; + memcpy(data, m_path, sizeof(m_path)); data += sizeof(m_path); + memcpy(data, &m_q, sizeof(m_q)); data += sizeof(m_q); + // memcpy(data, &m_vl, sizeof(m_vl)); data += sizeof(m_vl); + + return 0; +} + +UINT32 GSState::Defrost(const freezeData* fd) +{ + if(!fd || !fd->data || fd->size == 0) + return -1; + + int size = sizeof(m_version) + + sizeof(m_de) + sizeof(m_v) + + sizeof(m_x) + sizeof(m_y) + 1024*1024*4 + + sizeof(m_path) + + sizeof(m_q) + /*+ sizeof(m_vl)*/; + + if(fd->size != size) + return -1; + + BYTE* data = fd->data; + + int version = 0; + memcpy(&version, data, sizeof(version)); data += sizeof(version); + if(m_version != version) return -1; + + FlushPrimInternal(); + + memcpy(&m_de, data, sizeof(m_de)); data += sizeof(m_de); + memcpy(&m_v, data, sizeof(m_v)); data += sizeof(m_v); + memcpy(&m_x, data, sizeof(m_x)); data += sizeof(m_x); + memcpy(&m_y, data, sizeof(m_y)); data += sizeof(m_y); + memcpy(m_lm.GetVM(), data, 1024*1024*4); data += 1024*1024*4; + memcpy(&m_path, data, sizeof(m_path)); data += sizeof(m_path); + memcpy(&m_q, data, sizeof(m_q)); data += sizeof(m_q); + // memcpy(&m_vl, data, sizeof(m_vl)); data += sizeof(m_vl); + + m_pPRIM = !m_de.PRMODECONT.AC ? (GIFRegPRIM*)&m_de.PRMODE : &m_de.PRIM; + + m_ctxt = &m_de.CTXT[m_pPRIM->CTXT]; + + m_de.CTXT[0].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].FRAME.PSM]; + m_de.CTXT[0].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].ZBUF.PSM]; + m_de.CTXT[0].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].TEX0.PSM]; + + m_de.CTXT[1].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].FRAME.PSM]; + m_de.CTXT[1].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].ZBUF.PSM]; + m_de.CTXT[1].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].TEX0.PSM]; + + return 0; +} + +void GSState::WriteCSR(UINT32 csr) +{ + m_rs.pCSR->ai32[1] = csr; +} + +void GSState::ReadFIFO(BYTE* pMem) +{ + GSPerfMonAutoTimer at(m_perfmon); + + FlushWriteTransfer(); + + LOG(_T("*** WARNING *** ReadFIFO(%08x)\n"), pMem); + ReadTransfer(pMem, 16); +} + +__declspec(align(16)) static BYTE tr1_buff[0x4000]; + +void GSState::Transfer1(BYTE* pMem, UINT32 addr) +{ +// GSPerfMonAutoTimer at(m_perfmon); + + LOG(_T("Transfer1(%08x, %d)\n"), pMem, addr); + + // TODO: this is too cheap... + addr &= 0x3fff; + memcpy(tr1_buff, pMem + addr, 0x4000 - addr); + memcpy(tr1_buff + 0x4000 - addr, pMem, addr); +/* + if((m_tag).NLOOP + && ((GIFTag*)tr1_buff)->NLOOP == 8 && ((GIFTag*)tr1_buff)->PRIM == 0x5b + && ((GIFTag*)tr1_buff)->NREG == 9 && ((GIFTag*)tr1_buff)->REGS == 0x0000000412412412ui64) + { + ASSERT(0); + } +*/ + ASSERT(m_path[1].m_tag.NLOOP == 0 && m_path[2].m_tag.NLOOP == 0); + + Transfer(tr1_buff, -1, m_path[0]); +} + +void GSState::Transfer2(BYTE* pMem, UINT32 size) +{ + ASSERT(m_path[0].m_tag.NLOOP == 0 && m_path[2].m_tag.NLOOP == 0); + + Transfer(pMem, size, m_path[1]); +} + +void GSState::Transfer3(BYTE* pMem, UINT32 size) +{ + ASSERT(m_path[0].m_tag.NLOOP == 0 && m_path[1].m_tag.NLOOP == 0); + + Transfer(pMem, size, m_path[2]); +} + +int Path3hack = 0; + +void GSState::Transfer(BYTE* pMem, UINT32 size, GIFPath& path) +{ + GSPerfMonAutoTimer at(m_perfmon); + + BYTE* pMemOrg = pMem; + UINT32 sizeOrg = size; + + while(size > 0) + { + LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + + bool fEOP = false; + + if(path.m_tag.NLOOP == 0) + { + path.m_tag = *(GIFTag*)pMem; + path.m_nreg = 0; + m_q = 1.0f; +/* + LOG(_T("GIFTag NLOOP=%x EOP=%x PRE=%x PRIM=%x FLG=%x NREG=%x REGS=%x\n"), + m_tag.NLOOP, + m_tag.EOP, + m_tag.PRE, + m_tag.PRIM, + m_tag.FLG, + m_tag.NREG, + m_tag.REGS); +*/ + pMem += sizeof(GIFTag); + size--; + if(&path == &m_path[2] && path.m_tag.EOP) Path3hack = 1; + if(path.m_tag.PRE) + { + LOG(_T("PRE ")); + GIFReg r; + r.i64 = path.m_tag.PRIM; + (this->*m_fpGIFRegHandlers[GIF_A_D_REG_PRIM])(&r); + } + + if(path.m_tag.EOP) + { + LOG(_T("EOP\n")); + fEOP = true; + } + else if(path.m_tag.NLOOP == 0) + { + if(m_fNloopHack && &path == &m_path[0]) + continue; + + LOG(_T("*** WARNING *** m_tag.NLOOP == 0 && EOP == 0\n")); + fEOP = true; + // ASSERT(0); + } + } + + UINT32 size_msb = size & (1<<31); + + switch(path.m_tag.FLG) + { + case GIF_FLG_PACKED: + for(GIFPackedReg* r = (GIFPackedReg*)pMem; path.m_tag.NLOOP > 0 && size > 0; r++, size--, pMem += sizeof(GIFPackedReg)) + { + DWORD reg = GET_GIF_REG(path.m_tag, path.m_nreg); + (this->*m_fpGIFPackedRegHandlers[reg])(r); + if((path.m_nreg = (path.m_nreg+1)&0xf) == path.m_tag.NREG) {path.m_nreg = 0; path.m_tag.NLOOP--;} + } + break; + case GIF_FLG_REGLIST: + size *= 2; + for(GIFReg* r = (GIFReg*)pMem; path.m_tag.NLOOP > 0 && size > 0; r++, size--, pMem += sizeof(GIFReg)) + { + DWORD reg = GET_GIF_REG(path.m_tag, path.m_nreg); + (this->*m_fpGIFRegHandlers[reg])(r); + if((path.m_nreg = (path.m_nreg+1)&0xf) == path.m_tag.NREG) {path.m_nreg = 0; path.m_tag.NLOOP--;} + } + if(size&1) pMem += sizeof(GIFReg); + size /= 2; + size |= size_msb; // a bit lame :P + break; + case GIF_FLG_IMAGE2: + LOG(_T("*** WARNING **** Unexpected GIFTag flag\n")); +path.m_tag.NLOOP = 0; +break; + ASSERT(0); + case GIF_FLG_IMAGE: + { + int len = min(size, path.m_tag.NLOOP); + //ASSERT(!(len&3)); + switch(m_de.TRXDIR.XDIR) + { + case 0: + WriteTransfer(pMem, len*16); + break; + case 1: + ReadTransfer(pMem, len*16); + break; + case 2: + //MoveTransfer(); + break; + case 3: + ASSERT(0); + break; + default: + __assume(0); + } + pMem += len*16; + path.m_tag.NLOOP -= len; + size -= len; + } + break; + default: + __assume(0); + } + + LOG(_T("Transfer(%08x, %d) END\n"), pMem, size); + + if(fEOP && (INT32)size <= 0) + { + break; + } + } + +#ifdef ENABLE_CAPTURE_STATE + if(m_sfp) + { + fputc(ST_TRANSFER, m_sfp); + fwrite(&sizeOrg, 4, 1, m_sfp); + UINT32 len = (UINT32)(pMem - pMemOrg); + fwrite(&len, 4, 1, m_sfp); + fwrite(pMemOrg, len, 1, m_sfp); + } +#endif +} + +UINT32 GSState::MakeSnapshot(char* path) +{ + GSPerfMonAutoTimer at(m_perfmon); + + CString fn; + fn.Format(_T("%sgsdx9_%s.bmp"), CString(path), CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); + return D3DXSaveSurfaceToFile(fn, D3DXIFF_BMP, m_pOrgRenderTarget, NULL, NULL); +} + +void GSState::Capture() +{ + GSPerfMonAutoTimer at(m_perfmon); + + if(!m_capture.IsCapturing()) m_capture.BeginCapture(m_pD3DDev, m_rs.GetFPS()); + else m_capture.EndCapture(); +} + +void GSState::ToggleOSD() +{ + if(m_d3dpp.Windowed) + { + if(m_iOSD == 1) SetWindowText(m_hWnd, m_strDefaultTitle); + m_iOSD = ++m_iOSD % 3; + } + else + { + m_iOSD = m_iOSD ? 0 : 2; + } +} + +void GSState::CaptureState(CString fn) +{ +#ifdef ENABLE_CAPTURE_STATE + if(!m_sfp) m_sfp = !fn.IsEmpty() ? _tfopen(fn, _T("wb")) : NULL; +#endif +} + +void GSState::VSync(int field) +{ + GSPerfMonAutoTimer at(m_perfmon); + + LOG(_T("VSync(%d) %d\n"), field, m_perfmon.GetFrame()); + + m_fField = !!field; + +#ifdef ENABLE_CAPTURE_STATE + if(m_sfp) fputc(ST_VSYNC, m_sfp); +#endif + + FlushPrimInternal(); + + Flip(); + + EndFrame(); +} + +void GSState::Reset() +{ + GSPerfMonAutoTimer at(m_perfmon); + + memset(&m_de, 0, sizeof(m_de)); + memset(m_path, 0, sizeof(m_path)); + memset(&m_v, 0, sizeof(m_v)); + +// m_de.PRMODECONT.AC = 1; + +// m_pPRIM = &m_de.PRIM; + m_PRIM = 8; + + m_ctxt = &m_de.CTXT[0]; + + m_de.CTXT[0].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].FRAME.PSM]; + m_de.CTXT[0].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].ZBUF.PSM]; + m_de.CTXT[0].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[0].TEX0.PSM]; + + m_de.CTXT[1].ftbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].FRAME.PSM]; + m_de.CTXT[1].ztbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].ZBUF.PSM]; + m_de.CTXT[1].ttbl = &GSLocalMemory::m_psmtbl[m_de.CTXT[1].TEX0.PSM]; + + if(m_pD3DDev) m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET/*|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL*/, 0, 1.0f, 0); +} + +void GSState::FinishFlip(FlipInfo rt[2]) +{ + HRESULT hr; + + bool fEN[2]; + CRect src[2]; + + for(int i = 0; i < countof(fEN); i++) + { + fEN[i] = m_rs.IsEnabled(i) && rt[i].pRT; + + if(fEN[i]) + { + CRect r = m_rs.GetDispRect(i); + + src[i] = CRect( + (int)(rt[i].scale.x * r.left), + (int)(rt[i].scale.y * r.top), + (int)(rt[i].scale.x * r.right), + (int)(rt[i].scale.y * r.bottom)); + + if(m_rs.pSMODE2->INT && m_rs.pSMODE2->FFMD) + src[i].bottom /= 2; + } + else + { + rt[i].rd.Width = rt[i].rd.Height = 1; // to avoid div by zero below + } + } + + CRect dst(0, 0, m_bd.Width, m_bd.Height); + + struct + { + float x, y, z, rhw; + float tu1, tv1; + float tu2, tv2; + } + pVertices[] = + { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, + (float)src[0].left / rt[0].rd.Width, (float)src[0].top / rt[0].rd.Height, + (float)src[1].left / rt[1].rd.Width, (float)src[1].top / rt[1].rd.Height}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, + (float)src[0].right / rt[0].rd.Width, (float)src[0].top / rt[0].rd.Height, + (float)src[1].right / rt[1].rd.Width, (float)src[1].top / rt[1].rd.Height}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, + (float)src[0].left / rt[0].rd.Width, (float)src[0].bottom / rt[0].rd.Height, + (float)src[1].left / rt[1].rd.Width, (float)src[1].bottom / rt[1].rd.Height}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, + (float)src[0].right / rt[0].rd.Width, (float)src[0].bottom / rt[0].rd.Height, + (float)src[1].right / rt[1].rd.Width, (float)src[1].bottom / rt[1].rd.Height}, + }; + +/* + if(m_rs.pSMODE2->INT) + { + if(!m_rs.pSMODE2->FFMD) + { + // m_rs.pCSR->rFIELD = 1 - m_rs.pCSR->rFIELD; + } + else if(!m_rs.pCSR->rFIELD) + { + // if(m_rs.pCSR->rFIELD == 0) m_rs.pCSR->rFIELD = 1; // FIXME: might stop a few games, but this is the only way to stop shaking the bios or sfae + + for(int i = 0; i < countof(pVertices); i++) + { + pVertices[i].tv1 += rt[0].scale.y*0.5f / rt[0].rd.Height; + pVertices[i].tv2 += rt[1].scale.y*0.5f / rt[1].rd.Height; + } + } + } +*/ + + if(m_fField /*m_rs.pCSR->rFIELD*/ && m_rs.pSMODE2->INT /*&& m_rs.pSMODE2->FFMD*/) + { + for(int i = 0; i < countof(pVertices); i++) + { + pVertices[i].tv1 += rt[0].scale.y*0.5f / rt[0].rd.Height; + pVertices[i].tv2 += rt[1].scale.y*0.5f / rt[1].rd.Height; + } + } + + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RGBA); + + hr = m_pD3DDev->SetTexture(0, rt[0].pRT); + hr = m_pD3DDev->SetTexture(1, rt[1].pRT); + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + hr = m_pD3DDev->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + IDirect3DPixelShader9* pPixelShader = NULL; + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) && m_pHLSLMerge[PS_M32]) + { + pPixelShader = m_pHLSLMerge[PS_M32]; + } + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 4)) + { + if(fEN[0] && fEN[1]) // RAO1 + RAO2 + { + pPixelShader = m_pPixelShaders[PS14_EN11]; + } + else if(fEN[0]) // RAO1 + { + pPixelShader = m_pPixelShaders[PS14_EN10]; + } + else if(fEN[1]) // RAO2 + { + pPixelShader = m_pPixelShaders[PS14_EN01]; + } + } + + if(!pPixelShader && m_caps.PixelShaderVersion >= D3DPS_VERSION(1, 1)) + { + if(fEN[0] && fEN[1]) // RAO1 + RAO2 + { + pPixelShader = m_pPixelShaders[PS11_EN11]; + } + else if(fEN[0]) // RAO1 + { + pPixelShader = m_pPixelShaders[PS11_EN10]; + } + else if(fEN[1]) // RAO2 + { + pPixelShader = m_pPixelShaders[PS11_EN01]; + } + } + + if(!pPixelShader) + { + int stage = 0; + + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + stage++; + + if(fEN[0] && fEN[1]) // RAO1 + RAO2 + { + if(m_rs.pPMODE->ALP < 0xff) + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_LERP); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, m_rs.pPMODE->SLBG ? D3DTA_CONSTANT : D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_ALPHAREPLICATE|(m_rs.pPMODE->MMOD ? D3DTA_CONSTANT : D3DTA_TEXTURE)); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_CONSTANT, D3DCOLOR_ARGB(m_rs.pPMODE->ALP, m_rs.pBGCOLOR->R, m_rs.pBGCOLOR->G, m_rs.pBGCOLOR->B)); + stage++; + } + } + else if(fEN[0]) // RAO1 + { + if(m_rs.pPMODE->ALP < 0xff) + { + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_ALPHAREPLICATE|(m_rs.pPMODE->MMOD ? D3DTA_CONSTANT : D3DTA_TEXTURE)); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_CONSTANT, D3DCOLOR_ARGB(m_rs.pPMODE->ALP, 0, 0, 0)); + stage++; + } + } + else if(fEN[1]) // RAO2 + { + hr = m_pD3DDev->SetTexture(0, rt[1].pRT); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 1); + + // FIXME + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + for(int i = 0; i < countof(pVertices); i++) + { + pVertices[i].tu1 = pVertices[i].tu2; + pVertices[i].tv1 = pVertices[i].tv2; + } + } + + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE); + hr = m_pD3DDev->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + + if(pPixelShader) + { + const float c[] = + { + (float)m_rs.pBGCOLOR->B / 255, (float)m_rs.pBGCOLOR->G / 255, (float)m_rs.pBGCOLOR->R / 255, (float)m_rs.pPMODE->ALP / 255, + (float)m_rs.pPMODE->AMOD - 0.1f, (float)m_rs.IsEnabled(0), (float)m_rs.IsEnabled(1), (float)m_rs.pPMODE->MMOD - 0.1f, + (float)m_de.TEXA.AEM, (float)m_de.TEXA.TA0 / 255, (float)m_de.TEXA.TA1 / 255, (float)m_rs.pPMODE->SLBG - 0.1f + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, c, countof(c)/4); + } + + if(fEN[0] || fEN[1]) + { + if(m_pTmpRenderTarget && m_pHLSLRedBlue) + { + CComPtr pSurf; + hr = m_pTmpRenderTarget->GetSurfaceLevel(0, &pSurf); + hr = m_pD3DDev->SetRenderTarget(0, pSurf); + } + else + { + hr = m_pD3DDev->SetRenderTarget(0, m_pOrgRenderTarget); + } + + hr = m_pD3DDev->BeginScene(); + + hr = m_pD3DDev->SetPixelShader(pPixelShader); + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_TEX2); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + int w, h; + CComPtr pRTSurf; + + if(m_capture.BeginFrame(w, h, &pRTSurf)) + { + pVertices[0].x = pVertices[0].y = pVertices[2].x = pVertices[1].y = 0; + pVertices[1].x = pVertices[3].x = (float)w; + pVertices[2].y = pVertices[3].y = (float)h; + for(int i = 0; i < countof(pVertices); i++) {pVertices[i].x -= 0.5; pVertices[i].y -= 0.5;} + hr = m_pD3DDev->SetRenderTarget(0, pRTSurf); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + m_capture.EndFrame(); + } + + hr = m_pD3DDev->EndScene(); + + if(m_pTmpRenderTarget && m_pHLSLRedBlue) + { + hr = m_pD3DDev->SetRenderTarget(0, m_pOrgRenderTarget); + hr = m_pD3DDev->SetTexture(0, m_pTmpRenderTarget); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + hr = m_pD3DDev->SetPixelShader(m_pHLSLRedBlue); + + struct + { + float x, y, z, rhw; + float tu, tv; + } + pVertices[] = + { + {0, 0, 0.5f, 2.0f, 0, 0}, + {(float)m_bd.Width, 0, 0.5f, 2.0f, 1, 0}, + {0, (float)m_bd.Height, 0.5f, 2.0f, 0, 1}, + {(float)m_bd.Width, (float)m_bd.Height, 0.5f, 2.0f, 1, 1}, + }; + + hr = m_pD3DDev->BeginScene(); + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + hr = m_pD3DDev->EndScene(); + } + } + + // + + m_perfmon.IncCounter(GSPerfMon::c_frame); + + static CString s_stats; + + if(!(m_perfmon.GetFrame()&15)) + { + s_stats = m_perfmon.ToString(m_rs.GetFPS()); + // stats.Format(_T("%s - %.2f MB"), CString(stats), 1.0f*m_pD3DDev->GetAvailableTextureMem()/1024/1024); + + if(m_iOSD == 1) + { + SetWindowText(m_hWnd, s_stats); + } + } + + if(m_iOSD == 2) + { + CString str; + str.Format( + _T("\n") + _T("SMODE2.INT=%d, SMODE2.FFMD=%d, XYOFFSET.OFY=%.2f, CSR.FIELD=%d, m_fField = %d\n") + _T("[%c] DBX=%d, DBY=%d, DW=%d, DH=%d | [%c] DBX=%d, DBY=%d, DW=%d, DH=%d\n"), + m_rs.pSMODE2->INT, m_rs.pSMODE2->FFMD, (float)m_ctxt->XYOFFSET.OFY / 16, m_rs.pCSR->rFIELD, m_fField, + fEN[0] ? 'o' : 'x', m_rs.pDISPFB[0]->DBX, m_rs.pDISPFB[0]->DBY, m_rs.pDISPLAY[0]->DW + 1, m_rs.pDISPLAY[0]->DH + 1, + fEN[1] ? 'o' : 'x', m_rs.pDISPFB[1]->DBX, m_rs.pDISPFB[1]->DBY, m_rs.pDISPLAY[1]->DW + 1, m_rs.pDISPLAY[1]->DH + 1); + + str = s_stats + str; + + hr = m_pD3DDev->BeginScene(); + CRect r = dst; + D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0); + if(m_pD3DXFont->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c)) + m_pD3DXFont->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c); + hr = m_pD3DDev->EndScene(); + } +/* + // this suxx + + REFERENCE_TIME rtTimePerFrame = 10000000i64 / m_rs.GetFPS(); + + REFERENCE_TIME rtNow = 0; + hr = m_pRefClock->GetTime(&rtNow); + + DWORD_PTR dwAdviseCookie = 0; + hr = m_pRefClock->AdviseTime((rtNow / rtTimePerFrame + 1) * rtTimePerFrame, 0, (HEVENT)(HANDLE)m_evVSync, &dwAdviseCookie); + if(!m_evVSync.Wait((DWORD)(rtTimePerFrame / 10000))) hr = m_pRefClock->Unadvise(dwAdviseCookie); +*/ + // + + hr = m_pD3DDev->Present(NULL, NULL, NULL, NULL); +} + +void GSState::FlushPrimInternal() +{ + FlushWriteTransfer(); + + FlushPrim(); +} diff --git a/plugins/gs/gsdx9/GSState.h b/plugins/gs/gsdx9/GSState.h new file mode 100644 index 0000000000..4699760b57 --- /dev/null +++ b/plugins/gs/gsdx9/GSState.h @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSWnd.h" +#include "GSLocalMemory.h" +#include "GSTextureCache.h" +#include "GSSoftVertex.h" +#include "GSVertexList.h" +#include "GSCapture.h" +#include "GSPerfMon.h" +// +//#define ENABLE_CAPTURE_STATE +// + +/* +//#define DEBUG_SAVETEXTURES +#define DEBUG_LOG +#define DEBUG_LOG2 +#define DEBUG_LOGVERTICES +#define DEBUG_RENDERTARGETS +*/ + +#define D3DCOLORWRITEENABLE_RGB (D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE) +#define D3DCOLORWRITEENABLE_RGBA (D3DCOLORWRITEENABLE_RGB|D3DCOLORWRITEENABLE_ALPHA) + +struct GSDrawingContext +{ + struct GSDrawingContext() {memset(this, 0, sizeof(*this));} + + GIFRegXYOFFSET XYOFFSET; + GIFRegTEX0 TEX0; + GIFRegTEX1 TEX1; + GIFRegTEX2 TEX2; + GIFRegCLAMP CLAMP; + GIFRegMIPTBP1 MIPTBP1; + GIFRegMIPTBP2 MIPTBP2; + GIFRegSCISSOR SCISSOR; + GIFRegALPHA ALPHA; + GIFRegTEST TEST; + GIFRegFBA FBA; + GIFRegFRAME FRAME; + GIFRegZBUF ZBUF; + + GSLocalMemory::psmtbl_t* ftbl; + GSLocalMemory::psmtbl_t* ztbl; + GSLocalMemory::psmtbl_t* ttbl; +}; + +struct GSDrawingEnvironment +{ + struct GSDrawingEnvironment() {memset(this, 0, sizeof(*this));} + + GIFRegPRIM PRIM; + GIFRegPRMODE PRMODE; + GIFRegPRMODECONT PRMODECONT; + GIFRegTEXCLUT TEXCLUT; + GIFRegSCANMSK SCANMSK; + GIFRegTEXA TEXA; + GIFRegFOGCOL FOGCOL; + GIFRegDIMX DIMX; + GIFRegDTHE DTHE; + GIFRegCOLCLAMP COLCLAMP; + GIFRegPABE PABE; + GSDrawingContext CTXT[2]; + + GIFRegBITBLTBUF BITBLTBUF; + GIFRegTRXDIR TRXDIR; + GIFRegTRXPOS TRXPOS; + GIFRegTRXREG TRXREG, TRXREG2; +}; + +struct GSRegSet +{ + GSRegPMODE* pPMODE; + GSRegSMODE1* pSMODE1; + GSRegSMODE2* pSMODE2; + GSRegDISPFB* pDISPFB[2]; + GSRegDISPLAY* pDISPLAY[2]; + GSRegEXTBUF* pEXTBUF; + GSRegEXTDATA* pEXTDATA; + GSRegEXTWRITE* pEXTWRITE; + GSRegBGCOLOR* pBGCOLOR; + GSRegCSR* pCSR; + GSRegIMR* pIMR; + GSRegBUSDIR* pBUSDIR; + GSRegSIGLBLID* pSIGLBLID; + + struct GSRegSet() + { + memset(this, 0, sizeof(*this)); + + extern BYTE* g_pBasePS2Mem; + + ASSERT(g_pBasePS2Mem); + + pPMODE = (GSRegPMODE*)(g_pBasePS2Mem + GS_PMODE); + pSMODE1 = (GSRegSMODE1*)(g_pBasePS2Mem + GS_SMODE1); + pSMODE2 = (GSRegSMODE2*)(g_pBasePS2Mem + GS_SMODE2); + // pSRFSH = (GSRegPMODE*)(g_pBasePS2Mem + GS_SRFSH); + // pSYNCH1 = (GSRegPMODE*)(g_pBasePS2Mem + GS_SYNCH1); + // pSYNCH2 = (GSRegPMODE*)(g_pBasePS2Mem + GS_SYNCH2); + // pSYNCV = (GSRegPMODE*)(g_pBasePS2Mem + GS_SYNCV); + pDISPFB[0] = (GSRegDISPFB*)(g_pBasePS2Mem + GS_DISPFB1); + pDISPFB[1] = (GSRegDISPFB*)(g_pBasePS2Mem + GS_DISPFB2); + pDISPLAY[0] = (GSRegDISPLAY*)(g_pBasePS2Mem + GS_DISPLAY1); + pDISPLAY[1] = (GSRegDISPLAY*)(g_pBasePS2Mem + GS_DISPLAY2); + pEXTBUF = (GSRegEXTBUF*)(g_pBasePS2Mem + GS_EXTBUF); + pEXTDATA = (GSRegEXTDATA*)(g_pBasePS2Mem + GS_EXTDATA); + pEXTWRITE = (GSRegEXTWRITE*)(g_pBasePS2Mem + GS_EXTWRITE); + pBGCOLOR = (GSRegBGCOLOR*)(g_pBasePS2Mem + GS_BGCOLOR); + pCSR = (GSRegCSR*)(g_pBasePS2Mem + GS_CSR); + pIMR = (GSRegIMR*)(g_pBasePS2Mem + GS_IMR); + pBUSDIR = (GSRegBUSDIR*)(g_pBasePS2Mem + GS_BUSDIR); + pSIGLBLID = (GSRegSIGLBLID*)(g_pBasePS2Mem + GS_SIGLBLID); + } + + CSize GetDispSize(int en) + { + ASSERT(en >= 0 && en < 2); + CSize size; + size.cx = (pDISPLAY[en]->DW + 1) / (pDISPLAY[en]->MAGH + 1); + size.cy = (pDISPLAY[en]->DH + 1) / (pDISPLAY[en]->MAGV + 1); + //if(pSMODE2->INT && pSMODE2->FFMD && size.cy > 1) size.cy >>= 1; + return size; + } + + CRect GetDispRect(int en) + { + ASSERT(en >= 0 && en < 2); + return CRect(CPoint(pDISPFB[en]->DBX, pDISPFB[en]->DBY), GetDispSize(en)); + } + + bool IsEnabled(int en) + { + ASSERT(en >= 0 && en < 2); + if(en == 0 && pPMODE->EN1) {return(pDISPLAY[0]->DW || pDISPLAY[0]->DH);} + else if(en == 1 && pPMODE->EN2) {return(pDISPLAY[1]->DW || pDISPLAY[1]->DH);} + return(false); + } + + int GetFPS() + { + return ((pSMODE1->CMOD&1) ? 50 : 60) / (pSMODE2->INT ? 1 : 2); + } +}; + +struct GSVertex +{ + GIFRegRGBAQ RGBAQ; + GIFRegST ST; + GIFRegUV UV; + GIFRegXYZ XYZ; + GIFRegFOG FOG; +}; + +struct GIFPath +{ + GIFTag m_tag; + int m_nreg; +}; + +class GSState +{ + friend class GSTextureCache; + +protected: + static const int m_version = 4; + + GIFPath m_path[3]; + GSLocalMemory m_lm; + GSDrawingEnvironment m_de; + GSDrawingContext* m_ctxt; + GSRegSet m_rs; + GSVertex m_v; + float m_q; + GSPerfMon m_perfmon; + GSCapture m_capture; + +private: + static const int m_nTrMaxBytes = 1024*1024*4; + int m_nTrBytes; + BYTE* m_pTrBuff; + int m_x, m_y; + void WriteStep(); + void ReadStep(); + void WriteTransfer(BYTE* pMem, int len); + void FlushWriteTransfer(); + void ReadTransfer(BYTE* pMem, int len); + void MoveTransfer(); + +protected: + HWND m_hWnd; + int m_width, m_height; + CComPtr m_pD3D; + CComPtr m_pD3DDev; + CComPtr m_pD3DXFont; + CComPtr m_pOrgRenderTarget; + CComPtr m_pTmpRenderTarget; + CComPtr m_pPixelShaders[20]; + CComPtr m_pHLSLTFX[38], m_pHLSLMerge[3], m_pHLSLRedBlue; + enum {PS11_EN11 = 12, PS11_EN01 = 13, PS11_EN10 = 14, PS11_EN00 = 15}; + enum {PS14_EN11 = 16, PS14_EN01 = 17, PS14_EN10 = 18, PS14_EN00 = 19}; + enum {PS_M16 = 0, PS_M24 = 1, PS_M32 = 2}; + D3DPRESENT_PARAMETERS m_d3dpp; + DDCAPS m_ddcaps; + D3DCAPS9 m_caps; + D3DSURFACE_DESC m_bd; + D3DFORMAT m_fmtDepthStencil; + bool m_fEnablePalettizedTextures; + bool m_fNloopHack; + bool m_fField; + D3DTEXTUREFILTERTYPE m_texfilter; + + virtual void VertexKick(bool fSkip) = 0; + virtual int DrawingKick(bool fSkip) = 0; + virtual void NewPrim() = 0; + virtual void FlushPrim() = 0; + virtual void Flip() = 0; + virtual void EndFrame() = 0; + virtual void InvalidateTexture(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {} + virtual void InvalidateLocalMem(DWORD TBP0, DWORD BW, DWORD PSM, CRect r) {} + virtual void MinMaxUV(int w, int h, CRect& r) {r.SetRect(0, 0, w, h);} + + struct FlipInfo {CComPtr pRT; D3DSURFACE_DESC rd; scale_t scale;}; + void FinishFlip(FlipInfo rt[2]); + + void FlushPrimInternal(); + + // + + + // FIXME: savestate + GIFRegPRIM* m_pPRIM; + UINT32 m_PRIM; + + void (*m_fpGSirq)(); + + typedef void (__fastcall GSState::*GIFPackedRegHandler)(GIFPackedReg* r); + GIFPackedRegHandler m_fpGIFPackedRegHandlers[16]; + + void __fastcall GIFPackedRegHandlerNull(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerPRIM(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerRGBA(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerSTQ(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerUV(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerXYZF2(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerXYZ2(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerTEX0_1(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerTEX0_2(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerCLAMP_1(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerCLAMP_2(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerFOG(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerXYZF3(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerXYZ3(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerA_D(GIFPackedReg* r); + void __fastcall GIFPackedRegHandlerNOP(GIFPackedReg* r); + + typedef void (__fastcall GSState::*GIFRegHandler)(GIFReg* r); + GIFRegHandler m_fpGIFRegHandlers[256]; + + void __fastcall GIFRegHandlerNull(GIFReg* r); + void __fastcall GIFRegHandlerPRIM(GIFReg* r); + void __fastcall GIFRegHandlerRGBAQ(GIFReg* r); + void __fastcall GIFRegHandlerST(GIFReg* r); + void __fastcall GIFRegHandlerUV(GIFReg* r); + void __fastcall GIFRegHandlerXYZF2(GIFReg* r); + void __fastcall GIFRegHandlerXYZ2(GIFReg* r); + void __fastcall GIFRegHandlerTEX0_1(GIFReg* r); + void __fastcall GIFRegHandlerTEX0_2(GIFReg* r); + void __fastcall GIFRegHandlerCLAMP_1(GIFReg* r); + void __fastcall GIFRegHandlerCLAMP_2(GIFReg* r); + void __fastcall GIFRegHandlerFOG(GIFReg* r); + void __fastcall GIFRegHandlerXYZF3(GIFReg* r); + void __fastcall GIFRegHandlerXYZ3(GIFReg* r); + void __fastcall GIFRegHandlerNOP(GIFReg* r); + void __fastcall GIFRegHandlerTEX1_1(GIFReg* r); + void __fastcall GIFRegHandlerTEX1_2(GIFReg* r); + void __fastcall GIFRegHandlerTEX2_1(GIFReg* r); + void __fastcall GIFRegHandlerTEX2_2(GIFReg* r); + void __fastcall GIFRegHandlerXYOFFSET_1(GIFReg* r); + void __fastcall GIFRegHandlerXYOFFSET_2(GIFReg* r); + void __fastcall GIFRegHandlerPRMODECONT(GIFReg* r); + void __fastcall GIFRegHandlerPRMODE(GIFReg* r); + void __fastcall GIFRegHandlerTEXCLUT(GIFReg* r); + void __fastcall GIFRegHandlerSCANMSK(GIFReg* r); + void __fastcall GIFRegHandlerMIPTBP1_1(GIFReg* r); + void __fastcall GIFRegHandlerMIPTBP1_2(GIFReg* r); + void __fastcall GIFRegHandlerMIPTBP2_1(GIFReg* r); + void __fastcall GIFRegHandlerMIPTBP2_2(GIFReg* r); + void __fastcall GIFRegHandlerTEXA(GIFReg* r); + void __fastcall GIFRegHandlerFOGCOL(GIFReg* r); + void __fastcall GIFRegHandlerTEXFLUSH(GIFReg* r); + void __fastcall GIFRegHandlerSCISSOR_1(GIFReg* r); + void __fastcall GIFRegHandlerSCISSOR_2(GIFReg* r); + void __fastcall GIFRegHandlerALPHA_1(GIFReg* r); + void __fastcall GIFRegHandlerALPHA_2(GIFReg* r); + void __fastcall GIFRegHandlerDIMX(GIFReg* r); + void __fastcall GIFRegHandlerDTHE(GIFReg* r); + void __fastcall GIFRegHandlerCOLCLAMP(GIFReg* r); + void __fastcall GIFRegHandlerTEST_1(GIFReg* r); + void __fastcall GIFRegHandlerTEST_2(GIFReg* r); + void __fastcall GIFRegHandlerPABE(GIFReg* r); + void __fastcall GIFRegHandlerFBA_1(GIFReg* r); + void __fastcall GIFRegHandlerFBA_2(GIFReg* r); + void __fastcall GIFRegHandlerFRAME_1(GIFReg* r); + void __fastcall GIFRegHandlerFRAME_2(GIFReg* r); + void __fastcall GIFRegHandlerZBUF_1(GIFReg* r); + void __fastcall GIFRegHandlerZBUF_2(GIFReg* r); + void __fastcall GIFRegHandlerBITBLTBUF(GIFReg* r); + void __fastcall GIFRegHandlerTRXPOS(GIFReg* r); + void __fastcall GIFRegHandlerTRXREG(GIFReg* r); + void __fastcall GIFRegHandlerTRXDIR(GIFReg* r); + void __fastcall GIFRegHandlerHWREG(GIFReg* r); + void __fastcall GIFRegHandlerSIGNAL(GIFReg* r); + void __fastcall GIFRegHandlerFINISH(GIFReg* r); + void __fastcall GIFRegHandlerLABEL(GIFReg* r); + +public: + GSState(int w, int h, HWND hWnd, HRESULT& hr); + virtual ~GSState(); + + bool m_fMultiThreaded; + + virtual HRESULT ResetDevice(bool fForceWindowed = false); + + UINT32 Freeze(freezeData* fd, bool fSizeOnly); + UINT32 Defrost(const freezeData* fd); + virtual void Reset(); + void WriteCSR(UINT32 csr); + void ReadFIFO(BYTE* pMem); + void Transfer1(BYTE* pMem, UINT32 addr); + void Transfer2(BYTE* pMem, UINT32 size); + void Transfer3(BYTE* pMem, UINT32 size); + void Transfer(BYTE* pMem, UINT32 size, GIFPath& path); + void VSync(int field); + + void GSirq(void (*fpGSirq)()) {m_fpGSirq = fpGSirq;} + + UINT32 MakeSnapshot(char* path); + void Capture(); + + CString m_strDefaultTitle; + int m_iOSD; + void ToggleOSD(); + + // state + void CaptureState(CString fn); + FILE* m_sfp; + + // logging + FILE* m_fp; + +#ifdef DEBUG_LOGVERTICES + #define LOGV(_x_) LOGVERTEX _x_ +#else + #define LOGV(_x_) +#endif + +#ifdef DEBUG_LOG + void LOG(LPCTSTR fmt, ...) + { + va_list args; + va_start(args, fmt); + //////////// +/* + if(_tcsstr(fmt, _T("VSync")) + || _tcsstr(fmt, _T("*** WARNING ***")) + // || _tcsstr(fmt, _T("Flush")) + || _tcsstr(fmt, _T("CSR")) + || _tcsstr(fmt, _T("DISP")) + || _tcsstr(fmt, _T("FRAME")) + || _tcsstr(fmt, _T("ZBUF")) + || _tcsstr(fmt, _T("SMODE")) + || _tcsstr(fmt, _T("PMODE")) + || _tcsstr(fmt, _T("BITBLTBUF")) + || _tcsstr(fmt, _T("TRX")) + // || _tcsstr(fmt, _T("PRIM")) + // || _tcsstr(fmt, _T("RGB")) + // || _tcsstr(fmt, _T("XYZ")) + // || _tcsstr(fmt, _T("ST")) + // || _tcsstr(fmt, _T("XYOFFSET")) + // || _tcsstr(fmt, _T("TEX")) + || _tcsstr(fmt, _T("TEX0")) + // || _tcsstr(fmt, _T("TEX2")) + // || _tcsstr(fmt, _T("TEXFLUSH")) + // || _tcsstr(fmt, _T("UV")) + // || _tcsstr(fmt, _T("FOG")) + // || _tcsstr(fmt, _T("ALPHA")) + // || _tcsstr(fmt, _T("TBP0")) == fmt + // || _tcsstr(fmt, _T("CBP")) == fmt + // || _tcsstr(fmt, _T("*TC2 ")) == fmt + ) +*/ + if(m_fp) + { + TCHAR buff[2048]; + _stprintf(buff, _T("%d: "), clock()); + _vstprintf(buff + strlen(buff), fmt, args); + _fputts(buff, m_fp); + fflush(m_fp); + } + va_end(args); + } +#else +#define LOG __noop +#endif + +#ifdef DEBUG_LOG2 + void LOG2(LPCTSTR fmt, ...) + { + va_list args; + va_start(args, fmt); + if(m_fp) + { + TCHAR buff[2048]; + _stprintf(buff, _T("%d: "), clock()); + _vstprintf(buff + strlen(buff), fmt, args); + _fputts(buff, m_fp); + } + va_end(args); + } +#else +#define LOG2 __noop +#endif +}; diff --git a/plugins/gs/gsdx9/GSTables.cpp b/plugins/gs/gsdx9/GSTables.cpp new file mode 100644 index 0000000000..9457505986 --- /dev/null +++ b/plugins/gs/gsdx9/GSTables.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "gstables.h" + +DWORD blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +DWORD blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +DWORD blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +DWORD blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +DWORD blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +DWORD blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +DWORD blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +DWORD blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +DWORD columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +DWORD columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +DWORD columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +DWORD columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; diff --git a/plugins/gs/gsdx9/GSTables.h b/plugins/gs/gsdx9/GSTables.h new file mode 100644 index 0000000000..73709c05d1 --- /dev/null +++ b/plugins/gs/gsdx9/GSTables.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +extern DWORD blockTable32[4][8]; +extern DWORD blockTable32Z[4][8]; +extern DWORD blockTable16[8][4]; +extern DWORD blockTable16S[8][4]; +extern DWORD blockTable16Z[8][4]; +extern DWORD blockTable16SZ[8][4]; +extern DWORD blockTable8[4][8]; +extern DWORD blockTable4[8][4]; +extern DWORD columnTable32[8][8]; +extern DWORD columnTable16[8][16]; +extern DWORD columnTable8[16][16]; +extern DWORD columnTable4[16][32]; diff --git a/plugins/gs/gsdx9/GSTextureCache.cpp b/plugins/gs/gsdx9/GSTextureCache.cpp new file mode 100644 index 0000000000..ede3304a8e --- /dev/null +++ b/plugins/gs/gsdx9/GSTextureCache.cpp @@ -0,0 +1,1226 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTextureCache.h" +#include "GSHash.h" +#include "GSRendererHW.h" + +// + +bool IsRenderTarget(IDirect3DTexture9* pTexture) +{ + D3DSURFACE_DESC desc; + memset(&desc, 0, sizeof(desc)); + return pTexture && S_OK == pTexture->GetLevelDesc(0, &desc) && (desc.Usage&D3DUSAGE_RENDERTARGET); +} + +bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm) +{ + if(sbp != dbp) return false; + + switch(spsm) + { + case PSM_PSMCT32: + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMT8: + case PSM_PSMT4: + return true; + case PSM_PSMCT24: + return !(dpsm == PSM_PSMT8H || dpsm == PSM_PSMT4HL || dpsm == PSM_PSMT4HH); + case PSM_PSMT8H: + return !(dpsm == PSM_PSMCT24); + case PSM_PSMT4HL: + return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HH); + case PSM_PSMT4HH: + return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HL); + } + + return true; +} + +// + +GSDirtyRect::GSDirtyRect(DWORD PSM, CRect r) +{ + m_PSM = PSM; + m_rcDirty = r; +} + +CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0) +{ + CRect rcDirty = m_rcDirty; + + CSize src = GSLocalMemory::m_psmtbl[m_PSM].bs; + rcDirty.left = (rcDirty.left) & ~(src.cx-1); + rcDirty.right = (rcDirty.right + (src.cx-1) /* + 1 */) & ~(src.cx-1); + rcDirty.top = (rcDirty.top) & ~(src.cy-1); + rcDirty.bottom = (rcDirty.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1); + + if(m_PSM != TEX0.PSM) + { + CSize dst = GSLocalMemory::m_psmtbl[TEX0.PSM].bs; + rcDirty.left = MulDiv(m_rcDirty.left, dst.cx, src.cx); + rcDirty.right = MulDiv(m_rcDirty.right, dst.cx, src.cx); + rcDirty.top = MulDiv(m_rcDirty.top, dst.cy, src.cy); + rcDirty.bottom = MulDiv(m_rcDirty.bottom, dst.cy, src.cy); + } + + rcDirty &= CRect(0, 0, 1<m_pTexture) {ASSERT(0); return E_FAIL;} + + int w = 1 << pt->m_TEX0.TW; + int h = 1 << pt->m_TEX0.TH; + + int bpp = 0; + D3DFORMAT fmt = D3DFMT_UNKNOWN; + D3DFORMAT palfmt = D3DFMT_UNKNOWN; + + switch(PSM) + { + default: + case PSM_PSMCT32: + bpp = 32; + fmt = D3DFMT_A8R8G8B8; + break; + case PSM_PSMCT24: + bpp = 32; + fmt = D3DFMT_X8R8G8B8; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + bpp = 16; + fmt = D3DFMT_A1R5G5B5; + break; + case PSM_PSMT8: + case PSM_PSMT4: + case PSM_PSMT8H: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + bpp = 8; + fmt = D3DFMT_L8; + palfmt = CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5; + break; + } + + pt->m_nBytes = w*h*bpp>>3; + + POSITION pos = m_pTexturePool.GetHeadPosition(); + while(pos) + { + IDirect3DTexture9* pTexture = m_pTexturePool.GetNext(pos); + + D3DSURFACE_DESC desc; + memset(&desc, 0, sizeof(desc)); + pTexture->GetLevelDesc(0, &desc); + + if(w == desc.Width && h == desc.Height && fmt == desc.Format && !IsTextureInCache(pTexture)) + { + pt->m_pTexture = pTexture; + pt->m_desc = desc; + break; + } + } + + if(!pt->m_pTexture) + { + while(m_pTexturePool.GetCount() > 20) + m_pTexturePool.RemoveTail(); + + if(FAILED(s->m_pD3DDev->CreateTexture(w, h, 1, 0, fmt, D3DPOOL_MANAGED, &pt->m_pTexture, NULL))) + return E_FAIL; + + pt->m_pTexture->GetLevelDesc(0, &pt->m_desc); + + m_pTexturePool.AddHead(pt->m_pTexture); + } + + if(bpp == 8) + { + if(FAILED(s->m_pD3DDev->CreateTexture(256, 1, 1, 0, palfmt, D3DPOOL_MANAGED, &pt->m_pPalette, NULL))) + { + pt->m_pTexture = NULL; + return E_FAIL; + } + } + + return S_OK; +} + +bool GSTextureCache::IsTextureInCache(IDirect3DTexture9* pTexture) +{ + POSITION pos = GetHeadPosition(); + while(pos) + { + if(GetNext(pos)->m_pTexture == pTexture) + return true; + } + + return false; +} + +void GSTextureCache::RemoveOldTextures(GSState* s) +{ + DWORD nBytes = 0; + + POSITION pos = GetHeadPosition(); + while(pos) nBytes += GetNext(pos)->m_nBytes; + + pos = GetTailPosition(); + while(pos && nBytes > 96*1024*1024/*s->m_ddcaps.dwVidMemTotal*/) + { +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 too many textures in cache (%d, %.2f MB)\n"), GetCount(), 1.0f*nBytes/1024/1024); +#endif + POSITION cur = pos; + + GSTexture* pt = GetPrev(pos); + if(!pt->m_fRT) + { + nBytes -= pt->m_nBytes; + RemoveAt(cur); + delete pt; + } + } +} + +static bool RectInRect(const RECT& inner, const RECT& outer) +{ + return outer.left <= inner.left && inner.right <= outer.right + && outer.top <= inner.top && inner.bottom <= outer.bottom; +} + +static bool RectInRectH(const RECT& inner, const RECT& outer) +{ + return outer.top <= inner.top && inner.bottom <= outer.bottom; +} + +static bool RectInRectV(const RECT& inner, const RECT& outer) +{ + return outer.left <= inner.left && inner.right <= outer.right; +} + +bool GSTextureCache::GetDirtyRect(GSState* s, GSTexture* pt, CRect& r) +{ + int w = 1 << pt->m_TEX0.TW; + int h = 1 << pt->m_TEX0.TH; + + r.SetRect(0, 0, w, h); + +// FIXME: kyo's left hand after being selected for player one (PS2-SNK_Vs_Capcom_SVC_Chaos_PAL_CDFull.iso) +// return true; + + s->MinMaxUV(w, h, r); + + CRect rcDirty = pt->m_rcDirty.GetDirtyRect(pt->m_TEX0); + CRect rcValid = pt->m_rcValid; + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 used %d,%d-%d,%d (%dx%d), valid %d,%d-%d,%d, dirty %d,%d-%d,%d\n"), r, w, h, rcValid, rcDirty); +#endif + + if(RectInRect(r, rcValid)) + { + if(rcDirty.IsRectEmpty()) return false; + else if(RectInRect(rcDirty, r)) r = rcDirty; + else if(RectInRect(rcDirty, rcValid)) r |= rcDirty; + else r = rcValid | rcDirty; + } + else + { + if(RectInRectH(r, rcValid) && (r.left >= rcValid.left || r.right <= rcValid.right)) + { + r.top = rcValid.top; + r.bottom = rcValid.bottom; + if(r.left < rcValid.left) r.right = rcValid.left; + else /*if(r.right > rcValid.right)*/ r.left = rcValid.right; + } + else if(RectInRectV(r, rcValid) && (r.top >= rcValid.top || r.bottom <= rcValid.bottom)) + { + r.left = rcValid.left; + r.right = rcValid.right; + if(r.top < rcValid.top) r.bottom = rcValid.top; + else /*if(r.bottom > rcValid.bottom)*/ r.top = rcValid.bottom; + } + else + { + r |= rcValid; + } + } + + return true; +} + +DWORD GSTextureCache::HashTexture(const CRect& r, int pitch, void* bits) +{ + // TODO: make the hash more unique + + BYTE* p = (BYTE*)bits; + DWORD hash = r.left + r.right + r.top + r.bottom + pitch + *(BYTE*)bits; + + if(r.Width() > 0) + { + int size = r.Width()*r.Height(); +/* + if(size <= 8*8) return rand(); // :P + else +*/ + if(size <= 16*16) hash += hash_crc(r, pitch, p); + else if(size <= 32*32) hash += hash_adler(r, pitch, p); + else hash += hash_checksum(r, pitch, p); + } + + return hash; +} + +HRESULT GSTextureCache::UpdateTexture(GSState* s, GSTexture* pt, GSLocalMemory::readTexture rt) +{ + CRect r; + if(!GetDirtyRect(s, pt, r)) + return S_OK; + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 updating texture %d,%d-%d,%d (%dx%d)\n"), r.left, r.top, r.right, r.bottom, 1 << pt->m_TEX0.TW, 1 << pt->m_TEX0.TH); +#endif + + int bpp = 0; + + switch(pt->m_desc.Format) + { + case D3DFMT_A8R8G8B8: bpp = 32; break; + case D3DFMT_X8R8G8B8: bpp = 32; break; + case D3DFMT_A1R5G5B5: bpp = 16; break; + case D3DFMT_L8: bpp = 8; break; + default: ASSERT(0); return E_FAIL; + } + + D3DLOCKED_RECT lr; + if(FAILED(pt->m_pTexture->LockRect(0, &lr, &r, D3DLOCK_NO_DIRTY_UPDATE))) {ASSERT(0); return E_FAIL;} + (s->m_lm.*rt)(r, (BYTE*)lr.pBits, lr.Pitch, s->m_ctxt->TEX0, s->m_de.TEXA, s->m_ctxt->CLAMP); + s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*bpp>>3); + pt->m_pTexture->UnlockRect(0); + + pt->m_rcValid |= r; + pt->m_rcDirty.RemoveAll(); + + const static DWORD limit = 7; + + if((pt->m_nHashDiff & limit) && pt->m_nHashDiff >= limit && pt->m_rcHash == pt->m_rcValid) // predicted to be dirty + { + pt->m_nHashDiff++; + } + else + { + if(FAILED(pt->m_pTexture->LockRect(0, &lr, &pt->m_rcValid, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY))) {ASSERT(0); return E_FAIL;} + DWORD dwHash = HashTexture( + CRect((pt->m_rcValid.left>>2)*(bpp>>3), pt->m_rcValid.top, (pt->m_rcValid.right>>2)*(bpp>>3), pt->m_rcValid.bottom), + lr.Pitch, lr.pBits); + pt->m_pTexture->UnlockRect(0); + + if(pt->m_rcHash != pt->m_rcValid) + { + pt->m_nHashDiff = 0; + pt->m_nHashSame = 0; + pt->m_rcHash = pt->m_rcValid; + pt->m_dwHash = dwHash; + } + else + { + if(pt->m_dwHash != dwHash) + { + pt->m_nHashDiff++; + pt->m_nHashSame = 0; + pt->m_dwHash = dwHash; + } + else + { + if(pt->m_nHashDiff < limit) r.SetRect(0, 0, 1, 1); + // else pt->m_dwHash is not reliable, must update + pt->m_nHashDiff = 0; + pt->m_nHashSame++; + } + } + } + + pt->m_pTexture->AddDirtyRect(&r); + pt->m_pTexture->PreLoad(); + s->m_perfmon.IncCounter(GSPerfMon::c_texture, r.Width()*r.Height()*bpp>>3); + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 texture was updated, valid %d,%dx%d,%d\n"), pt->m_rcValid); +#endif + +#ifdef DEBUG_SAVETEXTURES +if(s->m_ctxt->FRAME.Block() == 0x00000 && pt->m_TEX0.TBP0 == 0x02800) +{ + CString fn; + fn.Format(_T("c:\\%08I64x_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d-%I64d_%I64d-%I64d.bmp"), + pt->m_TEX0.TBP0, pt->m_TEX0.PSM, pt->m_TEX0.TBW, + pt->m_TEX0.TW, pt->m_TEX0.TH, + pt->m_CLAMP.WMS, pt->m_CLAMP.WMT, pt->m_CLAMP.MINU, pt->m_CLAMP.MAXU, pt->m_CLAMP.MINV, pt->m_CLAMP.MAXV); + D3DXSaveTextureToFile(fn, D3DXIFF_BMP, pt->m_pTexture, NULL); +} +#endif + + return S_OK; +} + +GSTexture* GSTextureCache::ConvertRTPitch(GSState* s, GSTexture* pt) +{ + if(pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW) + return pt; + + // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) + ASSERT(pt->m_TEX0.TBW > s->m_ctxt->TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) + + int bw = 64; + int bh = s->m_ctxt->TEX0.PSM == PSM_PSMCT32 || s->m_ctxt->TEX0.PSM == PSM_PSMCT24 ? 32 : 64; + + int sw = pt->m_TEX0.TBW << 6; + + int dw = s->m_ctxt->TEX0.TBW << 6; + int dh = 1 << s->m_ctxt->TEX0.TH; + + // TRACE(_T("ConvertRT: %05x %x %d -> %d\n"), (DWORD)s->m_ctxt->TEX0.TBP0, (DWORD)s->m_ctxt->TEX0.PSM, (DWORD)pt->m_TEX0.TBW, (DWORD)s->m_ctxt->TEX0.TBW); + + HRESULT hr; +/* +if(s->m_perfmon.GetFrame() > 400) +hr = D3DXSaveTextureToFile(_T("g:/1.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL); +*/ + D3DSURFACE_DESC desc; + hr = pt->m_pTexture->GetLevelDesc(0, &desc); + if(FAILED(hr)) return NULL; + + CComPtr pRT; + if(FAILED(hr = CreateRT(s, desc.Width, desc.Height, &pRT))) + return NULL; + + CComPtr pSrc, pDst; + hr = pRT->GetSurfaceLevel(0, &pSrc); + if(FAILED(hr)) return NULL; + hr = pt->m_pTexture->GetSurfaceLevel(0, &pDst); + if(FAILED(hr)) return NULL; + + hr = s->m_pD3DDev->StretchRect(pDst, NULL, pSrc, NULL, D3DTEXF_POINT); + if(FAILED(hr)) return NULL; + + scale_t scale(pt->m_pTexture); + + for(int dy = 0; dy < dh; dy += bh) + { + for(int dx = 0; dx < dw; dx += bw) + { + int o = dy * dw / bh + dx; + + int sx = o % sw; + int sy = o / sw; + + // TRACE(_T("%d,%d - %d,%d <= %d,%d - %d,%d\n"), dx, dy, dx + bw, dy + bh, sx, sy, sx + bw, sy + bh); + + CRect src, dst; + + src.left = (LONG)(scale.x * sx + 0.5f); + src.top = (LONG)(scale.y * sy + 0.5f); + src.right = (LONG)(scale.x * (sx + bw) + 0.5f); + src.bottom = (LONG)(scale.y * (sy + bh) + 0.5f); + + dst.left = (LONG)(scale.x * dx + 0.5f); + dst.top = (LONG)(scale.y * dy + 0.5f); + dst.right = (LONG)(scale.x * (dx + bw) + 0.5f); + dst.bottom = (LONG)(scale.y * (dy + bh) + 0.5f); + + hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, D3DTEXF_POINT); + + // TODO: this is quite a lot of StretchRect call, do it with one DrawPrimUP + } + } + + pt->m_TEX0.TW = s->m_ctxt->TEX0.TW; + pt->m_TEX0.TBW = s->m_ctxt->TEX0.TBW; +/* +if(s->m_perfmon.GetFrame() > 400) +hr = D3DXSaveTextureToFile(_T("g:/2.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL); +*/ + + return pt; +} + +GSTexture* GSTextureCache::ConvertRTWidthHeight(GSState* s, GSTexture* pt) +{ + int tw = pt->m_scale.x * (1 << s->m_ctxt->TEX0.TW); + int th = pt->m_scale.y * (1 << s->m_ctxt->TEX0.TH); + + int rw = pt->m_desc.Width; + int rh = pt->m_desc.Height; + + if(tw != rw || th != rh) + //if(tw < rw && th <= rh || tw <= rw && th < rh) + { + GSTexture* pt2 = new GSTexture(); + + pt2->m_pPalette = pt->m_pPalette; + pt2->m_fRT = pt->m_pPalette == NULL; + pt2->m_scale = pt->m_scale; + pt2->m_fTemp = true; + + POSITION pos = pt->m_pSubTextures.GetHeadPosition(); + while(pos) + { + IDirect3DTexture9* pTexture = pt->m_pSubTextures.GetNext(pos); + pTexture->GetLevelDesc(0, &pt2->m_desc); + scale_t scale(pTexture); + if(pt2->m_desc.Width == tw && pt2->m_desc.Height == th + && pt2->m_scale.x == scale.x && pt2->m_scale.y == scale.y) + { + pt2->m_pTexture = pTexture; + break; + } + } + + if(!pt2->m_pTexture) + { + CRect dst(0, 0, tw, th); + + if(tw > rw) + { + pt2->m_scale.x = pt2->m_scale.x * rw / tw; + dst.right = rw * rw / tw; + tw = rw; + } + + if(th > rh) + { + pt2->m_scale.y = pt2->m_scale.y * rh / th; + dst.bottom = rh * rh / th; + th = rh; + } + + CRect src(0, 0, tw, th); + + HRESULT hr; + + if(FAILED(hr = CreateRT(s, tw, th, &pt2->m_pTexture)) || FAILED(hr = pt2->m_pTexture->GetLevelDesc(0, &pt2->m_desc))) + { + delete pt2; + return false; + } + + CComPtr pSrc, pDst; + hr = pt->m_pTexture->GetSurfaceLevel(0, &pSrc); + hr = pt2->m_pTexture->GetSurfaceLevel(0, &pDst); + + ASSERT(pSrc); + ASSERT(pDst); + + hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, src == dst ? D3DTEXF_POINT : D3DTEXF_LINEAR); + + pt2->m_scale.Set(pt2->m_pTexture); + pt->m_pSubTextures.AddTail(pt2->m_pTexture); + } + + pt = pt2; + } + + return pt; +} + +HRESULT GSTextureCache::CreateRT(GSState* s, int w, int h, IDirect3DTexture9** ppRT) +{ + ASSERT(ppRT && *ppRT == NULL); + + HRESULT hr; + + POSITION pos = m_pRTPool.GetHeadPosition(); + while(pos) + { + IDirect3DTexture9* pRT = m_pRTPool.GetNext(pos); + D3DSURFACE_DESC desc; + pRT->GetLevelDesc(0, &desc); + if(desc.Width == w && desc.Height == h) + { + (*ppRT = pRT)->AddRef(); + return S_OK; + } + } + + hr = s->m_pD3DDev->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, ppRT, NULL); + if(FAILED(hr)) return hr; +/**/ + m_pRTPool.AddHead(*ppRT); + while(m_pRTPool.GetCount() > 3) m_pRTPool.RemoveTail(); + + return S_OK; +} + +GSTexture* GSTextureCache::ConvertRT(GSState* s, GSTexture* pt) +{ + ASSERT(pt->m_fRT); + + // FIXME: RT + 8h,4hl,4hh + + if(s->m_ctxt->TEX0.PSM == PSM_PSMT8H) + { + if(!pt->m_pPalette) + { + if(FAILED(s->m_pD3DDev->CreateTexture(256, 1, 1, 0, s->m_ctxt->TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, &pt->m_pPalette, NULL))) + return NULL; + } + } + else if(GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal) + { + return NULL; + } + + pt = ConvertRTPitch(s, pt); + + pt = ConvertRTWidthHeight(s, pt); + + return pt; +} + +bool GSTextureCache::Fetch(GSState* s, GSTextureBase& t) +{ + GSTexture* pt = NULL; + + int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal; + + DWORD clut[256]; + + if(nPaletteEntries) + { + s->m_lm.SetupCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA); + s->m_lm.CopyCLUT32(clut, nPaletteEntries); + } + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)\n"), + 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, + s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries); +#endif + + enum lookupresult {notfound, needsupdate, found} lr = notfound; + + POSITION pos = GetHeadPosition(); + while(pos && !pt) + { + POSITION cur = pos; + pt = GetNext(pos); + + if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM)) + { + if(pt->m_fRT) + { + lr = found; + + if(!(pt = ConvertRT(s, pt))) + return false; + } + else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW + && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH + && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64) + && s->m_de.TEXA.TA0 == pt->m_TEXA.TA0 && s->m_de.TEXA.TA1 == pt->m_TEXA.TA1 && s->m_de.TEXA.AEM == pt->m_TEXA.AEM + && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0])))) + { + lr = needsupdate; + } + } + + if(lr != notfound) {MoveToHead(cur); break;} + + pt = NULL; + } + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 lr = %s\n"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound")); +#endif + + if(lr == notfound) + { + pt = new GSTexture(); + + pt->m_TEX0 = s->m_ctxt->TEX0; + pt->m_CLAMP = s->m_ctxt->CLAMP; + pt->m_TEXA = s->m_de.TEXA; + + if(!SUCCEEDED(CreateTexture(s, pt, PSM_PSMCT32))) + { + delete pt; + return false; + } + + RemoveOldTextures(s); + + AddHead(pt); + + lr = needsupdate; + } + + ASSERT(pt); + + if(pt && nPaletteEntries) + { + memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0])); + } + + if(lr == needsupdate) + { + UpdateTexture(s, pt, &GSLocalMemory::ReadTexture); + + lr = found; + } + + if(lr == found) + { +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 texture was found, age %d -> 0\n"), pt->m_nAge); +#endif + pt->m_nAge = 0; + t = *pt; + if(pt->m_fTemp) delete pt; + return true; + } + + return false; +} + +bool GSTextureCache::FetchP(GSState* s, GSTextureBase& t) +{ + GSTexture* pt = NULL; + + int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal; + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)\n"), + 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, + s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries); +#endif + + enum lookupresult {notfound, needsupdate, found} lr = notfound; + + POSITION pos = GetHeadPosition(); + while(pos && !pt) + { + POSITION cur = pos; + pt = GetNext(pos); + + if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM)) + { + if(pt->m_fRT) + { + lr = found; + + if(!(pt = ConvertRT(s, pt))) + return false; + } + else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW + && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH + && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64)) + { + lr = needsupdate; + } + } + + if(lr != notfound) {MoveToHead(cur); break;} + + pt = NULL; + } + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 lr = %s\n"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound")); +#endif + + if(lr == notfound) + { + pt = new GSTexture(); + + pt->m_TEX0 = s->m_ctxt->TEX0; + pt->m_CLAMP = s->m_ctxt->CLAMP; + // pt->m_TEXA = s->m_de.TEXA; + + if(!SUCCEEDED(CreateTexture(s, pt, s->m_ctxt->TEX0.PSM, PSM_PSMCT32))) + { + delete pt; + return false; + } + + RemoveOldTextures(s); + + AddHead(pt); + + lr = needsupdate; + } + + ASSERT(pt); + + if(pt && pt->m_pPalette) + { + D3DLOCKED_RECT r; + if(FAILED(pt->m_pPalette->LockRect(0, &r, NULL, 0))) + return false; + s->m_lm.ReadCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA, (DWORD*)r.pBits); + pt->m_pPalette->UnlockRect(0); + s->m_perfmon.IncCounter(GSPerfMon::c_texture, 256*4); + } + + if(lr == needsupdate) + { + UpdateTexture(s, pt, &GSLocalMemory::ReadTextureP); + + lr = found; + } + + if(lr == found) + { +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 texture was found, age %d -> 0\n"), pt->m_nAge); +#endif + pt->m_nAge = 0; + t = *pt; + if(pt->m_fTemp) delete pt; + return true; + } + + return false; +} + +bool GSTextureCache::FetchNP(GSState* s, GSTextureBase& t) +{ + GSTexture* pt = NULL; + + int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal; + + DWORD clut[256]; + + if(nPaletteEntries) + { + s->m_lm.SetupCLUT(s->m_ctxt->TEX0, s->m_de.TEXA); + s->m_lm.CopyCLUT32(clut, nPaletteEntries); + } + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)\n"), + 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, + s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries); +#endif + + enum lookupresult {notfound, needsupdate, found} lr = notfound; + + POSITION pos = GetHeadPosition(); + while(pos && !pt) + { + POSITION cur = pos; + pt = GetNext(pos); + + if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM)) + { + if(pt->m_fRT) + { + lr = found; + + if(!(pt = ConvertRT(s, pt))) + return false; + } + else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW + && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH + && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64) + // && s->m_de.TEXA.TA0 == pt->m_TEXA.TA0 && s->m_de.TEXA.TA1 == pt->m_TEXA.TA1 && s->m_de.TEXA.AEM == pt->m_TEXA.AEM + && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0])))) + { + lr = needsupdate; + } + } + + if(lr != notfound) {MoveToHead(cur); break;} + + pt = NULL; + } + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 lr = %s\n"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound")); +#endif + + if(lr == notfound) + { + pt = new GSTexture(); + + pt->m_TEX0 = s->m_ctxt->TEX0; + pt->m_CLAMP = s->m_ctxt->CLAMP; + // pt->m_TEXA = s->m_de.TEXA; + + DWORD psm = s->m_ctxt->TEX0.PSM; + + switch(psm) + { + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + psm = s->m_ctxt->TEX0.CPSM; + break; + } + + if(!SUCCEEDED(CreateTexture(s, pt, psm))) + { + delete pt; + return false; + } + + RemoveOldTextures(s); + + AddHead(pt); + + lr = needsupdate; + } + + ASSERT(pt); + + if(pt && nPaletteEntries) + { + memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0])); + } + + if(lr == needsupdate) + { + UpdateTexture(s, pt, &GSLocalMemory::ReadTextureNP); + + lr = found; + } + + if(lr == found) + { +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 texture was found, age %d -> 0\n"), pt->m_nAge); +#endif + pt->m_nAge = 0; + t = *pt; + if(pt->m_fTemp) delete pt; + return true; + } + + return false; +} + +void GSTextureCache::IncAge(CSurfMap& pRTs) +{ + POSITION pos = GetHeadPosition(); + while(pos) + { + POSITION cur = pos; + GSTexture* pt = GetNext(pos); + pt->m_nAge++; + pt->m_nVsyncs++; + if(pt->m_nAge > 10 && (!pt->m_fRT || pRTs.GetCount() > 3)) + { + pRTs.RemoveKey(pt->m_TEX0.TBP0); + RemoveAt(cur); + delete pt; + } + } +} + +void GSTextureCache::ResetAge(DWORD TBP0) +{ + POSITION pos = GetHeadPosition(); + while(pos) + { + GSTexture* pt = GetNext(pos); + if(pt->m_TEX0.TBP0 == TBP0) pt->m_nAge = 0; + } +} + +void GSTextureCache::RemoveAll() +{ + while(GetCount()) delete RemoveHead(); + m_pTexturePool.RemoveAll(); + m_pRTPool.RemoveAll(); +} + +void GSTextureCache::InvalidateTexture(GSState* s, const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) +{ + GIFRegTEX0 TEX0; + TEX0.TBP0 = BITBLTBUF.DBP; + TEX0.TBW = BITBLTBUF.DBW; + TEX0.PSM = BITBLTBUF.DPSM; + TEX0.TCC = 0; + +#ifdef DEBUG_LOG + s->LOG(_T("*TC2 invalidate %05x %x (%d,%d-%d,%d)\n"), TEX0.TBP0, TEX0.PSM, r.left, r.top, r.right, r.bottom); +#endif + + POSITION pos = GetHeadPosition(); + while(pos) + { + POSITION cur = pos; + GSTexture* pt = GetNext(pos); + if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM)) + { + if(TEX0.TBW != pt->m_TEX0.TBW) + { + // if TEX0.TBW != pt->m_TEX0.TBW then this render target is more likely to + // be discarded by the game (means it doesn't want to transfer an image over + // another pre-rendered image) and can be refetched from local mem safely. + + RemoveAt(cur); + delete pt; + } + else if(pt->m_fRT) + { + // TEX0.TBW = pt->m_TEX0.TBW; + TEX0.PSM = pt->m_TEX0.PSM; + + if(TEX0.PSM == PSM_PSMCT32 || TEX0.PSM == PSM_PSMCT24 + || TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S) + { +// pt->m_rcDirty.AddHead(GSDirtyRect(PSM, r)); + + HRESULT hr; + + int tw = (r.Width() + 3) & ~3; + int th = r.Height(); + + CComPtr pSrc; + hr = s->m_pD3DDev->CreateTexture(tw, th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pSrc, NULL); + + D3DLOCKED_RECT lr; + if(pSrc && SUCCEEDED(pSrc->LockRect(0, &lr, NULL, 0))) + { + GIFRegTEXA TEXA; + TEXA.AEM = 1; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + + GIFRegCLAMP CLAMP; + CLAMP.WMS = 0; + CLAMP.WMT = 0; + + s->m_lm.ReadTexture(r, (BYTE*)lr.pBits, lr.Pitch, TEX0, TEXA, CLAMP); + s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*4); + + pSrc->UnlockRect(0); + + scale_t scale(pt->m_pTexture); + + CRect dst; + dst.left = (long)(scale.x * r.left + 0.5); + dst.top = (long)(scale.y * r.top + 0.5); + dst.right = (long)(scale.x * r.right + 0.5); + dst.bottom = (long)(scale.y * r.bottom + 0.5); + + // + + CComPtr pRTSurf; + hr = pt->m_pTexture->GetSurfaceLevel(0, &pRTSurf); + hr = s->m_pD3DDev->SetRenderTarget(0, pRTSurf); + hr = s->m_pD3DDev->SetDepthStencilSurface(NULL); + + hr = s->m_pD3DDev->SetTexture(0, pSrc); + hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + hr = s->m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = s->m_pD3DDev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + hr = s->m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + hr = s->m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + hr = s->m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + hr = s->m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RGBA); + + hr = s->m_pD3DDev->SetPixelShader(NULL); + + struct + { + float x, y, z, rhw; + float tu, tv; + } + pVertices[] = + { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, 0, 0}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, 1.0f * r.Width() / tw, 0}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, 0, 1}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, 1.0f * r.Width() / tw, 1}, + }; + + hr = s->m_pD3DDev->BeginScene(); + hr = s->m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = s->m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + hr = s->m_pD3DDev->EndScene(); + + } + } + else + { + RemoveAt(cur); + delete pt; + } + } + else + { + pt->m_rcDirty.AddHead(GSDirtyRect(TEX0.PSM, r)); + } + } + } +} + +void GSTextureCache::InvalidateLocalMem(GSState* s, DWORD TBP0, DWORD BW, DWORD PSM, const CRect& r) +{ + CComPtr pRT; + + POSITION pos = GetHeadPosition(); + while(pos) + { + POSITION cur = pos; + GSTexture* pt = GetNext(pos); + if(pt->m_TEX0.TBP0 == TBP0 && pt->m_fRT) + { + pRT = pt->m_pTexture; + break; + } + } + + if(!pRT) return; + + // TODO: add resizing +/* + HRESULT hr; + + D3DSURFACE_DESC desc; + hr = pRT->GetLevelDesc(0, &desc); + if(FAILED(hr)) return; + + CComPtr pVidMem; + hr = pRT->GetSurfaceLevel(0, &pVidMem); + if(FAILED(hr)) return; + + CComPtr pSysMem; + hr = s->m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pSysMem, NULL); + if(FAILED(hr)) return; + + hr = s->m_pD3DDev->GetRenderTargetData(pVidMem, pSysMem); + if(FAILED(hr)) return; + + D3DLOCKED_RECT lr; + hr = pSysMem->LockRect(&lr, &r, D3DLOCK_READONLY|D3DLOCK_NO_DIRTY_UPDATE); + if(SUCCEEDED(hr)) + { + BYTE* p = (BYTE*)lr.pBits; + + if(0 && r.left == 0 && r.top == 0 && PSM == PSM_PSMCT32) + { + } + else + { + GSLocalMemory::writeFrame wf = s->m_lm.GetWriteFrame(PSM); + + for(int y = r.top; y < r.bottom; y++, p += lr.Pitch) + { + for(int x = r.left; x < r.right; x++) + { + (s->m_lm.*wf)(x, y, ((DWORD*)p)[x], TBP0, BW); + } + } + } + + pSysMem->UnlockRect(); + } + */ +} + +void GSTextureCache::AddRT(GIFRegTEX0& TEX0, IDirect3DTexture9* pRT, scale_t scale) +{ + POSITION pos = GetHeadPosition(); + while(pos) + { + POSITION cur = pos; + GSTexture* pt = GetNext(pos); + if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM)) + { + RemoveAt(cur); + delete pt; + } + } + + GSTexture* pt = new GSTexture(); + pt->m_TEX0 = TEX0; + pt->m_pTexture = pRT; + pt->m_pTexture->GetLevelDesc(0, &pt->m_desc); + pt->m_scale = scale; + pt->m_fRT = true; + + AddHead(pt); +} diff --git a/plugins/gs/gsdx9/GSTextureCache.h b/plugins/gs/gsdx9/GSTextureCache.h new file mode 100644 index 0000000000..45c4ac42ab --- /dev/null +++ b/plugins/gs/gsdx9/GSTextureCache.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSLocalMemory.h" + +template class CSurfMap : public CMap, CComPtr& > {}; + +extern bool IsRenderTarget(IDirect3DTexture9* pTexture); +extern bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm); + +// TODO: get rid of this *PrivateData + +#ifdef __INTEL_COMPILER +struct __declspec(uuid("5D5EFE0E-5407-4BCF-855D-C46CBCD075FA")) +#else +[uuid("5D5EFE0E-5407-4BCF-855D-C46CBCD075FA")] struct +#endif +scale_t +{ + float x, y; + struct scale_t() {x = y = 1;} + struct scale_t(float x, float y) {this->x = x; this->y = y;} + struct scale_t(IDirect3DResource9* p) {Get(p);} + bool operator == (const struct scale_t& s) {return fabs(x - s.x) < 0.001 && fabs(y - s.y) < 0.001;} + void Set(IDirect3DResource9* p) {p->SetPrivateData(__uuidof(*this), this, sizeof(*this), 0);} + void Get(IDirect3DResource9* p) {DWORD size = sizeof(*this); p->GetPrivateData(__uuidof(*this), this, &size);} +}; + +class GSDirtyRect +{ + DWORD m_PSM; + CRect m_rcDirty; + +public: + GSDirtyRect() : m_PSM(PSM_PSMCT32), m_rcDirty(0, 0, 0, 0) {} + GSDirtyRect(DWORD PSM, CRect r); + CRect GetDirtyRect(const GIFRegTEX0& TEX0); +}; + +class GSDirtyRectList : public CAtlList +{ +public: + GSDirtyRectList() {} + GSDirtyRectList(const GSDirtyRectList& l) {*this = l;} + void operator = (const GSDirtyRectList& l); + CRect GetDirtyRect(const GIFRegTEX0& TEX0); +}; + +struct GSTextureBase +{ + CComPtr m_pTexture, m_pPalette; + scale_t m_scale; + bool m_fRT; + D3DSURFACE_DESC m_desc; + + GSTextureBase(); +}; + +struct GSTexture : public GSTextureBase +{ + GIFRegCLAMP m_CLAMP; + GIFRegTEX0 m_TEX0; + GIFRegTEXA m_TEXA; // * + DWORD m_clut[256]; // * + GSDirtyRectList m_rcDirty; + CRect m_rcValid; + CRect m_rcHash; + DWORD m_dwHash, m_nHashDiff, m_nHashSame; + DWORD m_nBytes; + int m_nAge, m_nVsyncs; + CInterfaceList m_pSubTextures; + bool m_fTemp; + + GSTexture(); +}; + +class GSState; + +class GSTextureCache : private CAtlList +{ +protected: + CInterfaceList m_pTexturePool; + HRESULT CreateTexture(GSState* s, GSTexture* pt, DWORD PSM, DWORD CPSM = PSM_PSMCT32); + bool IsTextureInCache(IDirect3DTexture9* pTexture); + void RemoveOldTextures(GSState* s); + bool GetDirtyRect(GSState* s, GSTexture* pt, CRect& r); + + DWORD HashTexture(const CRect& r, int pitch, void* bits); + HRESULT UpdateTexture(GSState* s, GSTexture* pt, GSLocalMemory::readTexture rt); + + GSTexture* ConvertRT(GSState* s, GSTexture* pt); + GSTexture* ConvertRTPitch(GSState* s, GSTexture* pt); + GSTexture* ConvertRTWidthHeight(GSState* s, GSTexture* pt); + + CInterfaceList m_pRTPool; + HRESULT CreateRT(GSState* s, int w, int h, IDirect3DTexture9** ppRT); + +public: + GSTextureCache(); + ~GSTextureCache(); + + bool Fetch(GSState* s, GSTextureBase& t); + bool FetchP(GSState* s, GSTextureBase& t); + bool FetchNP(GSState* s, GSTextureBase& t); + + void IncAge(CSurfMap& pRTs); + void ResetAge(DWORD TBP0); + void RemoveAll(); + void InvalidateTexture(GSState* s, const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r); + void InvalidateLocalMem(GSState* s, DWORD TBP0, DWORD BW, DWORD PSM, const CRect& r); + void AddRT(GIFRegTEX0& TEX0, IDirect3DTexture9* pRT, scale_t scale); +}; diff --git a/plugins/gs/gsdx9/GSTransfer.cpp b/plugins/gs/gsdx9/GSTransfer.cpp new file mode 100644 index 0000000000..d7c5efd507 --- /dev/null +++ b/plugins/gs/gsdx9/GSTransfer.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSState.h" + +void GSState::WriteStep() +{ +// if(m_y == m_de.TRXREG.RRH && m_x == m_de.TRXPOS.DSAX) ASSERT(0); + + if(++m_x == m_de.TRXREG.RRW) + { + m_x = m_de.TRXPOS.DSAX; + m_y++; + } +} + +void GSState::ReadStep() +{ +// if(m_y == m_de.TRXREG.RRH && m_x == m_de.TRXPOS.SSAX) ASSERT(0); + + if(++m_x == m_de.TRXREG.RRW) + { + m_x = m_de.TRXPOS.SSAX; + m_y++; + } +} + +void GSState::WriteTransfer(BYTE* pMem, int len) +{ + LOG(_T("*TC2 WriteTransfer %d,%d (psm=%d rr=%dx%d len=%d)\n"), m_x, m_y, m_de.BITBLTBUF.DPSM, m_de.TRXREG.RRW, m_de.TRXREG.RRH, len); + + if(len == 0) return; + + // TODO: hmmmm + if(m_pPRIM->TME && (m_de.BITBLTBUF.DBP == m_ctxt->TEX0.TBP0 || m_de.BITBLTBUF.DBP == m_ctxt->TEX0.CBP)) + FlushPrim(); + + int bpp = GSLocalMemory::m_psmtbl[m_de.BITBLTBUF.DPSM].trbpp; + int pitch = (m_de.TRXREG.RRW - m_de.TRXPOS.DSAX)*bpp>>3; + int height = len / pitch; + + if(m_nTrBytes > 0 || height < m_de.TRXREG.RRH - m_de.TRXPOS.DSAY) + { + LOG(_T("*TC2 WriteTransfer delayed\n")); + + ASSERT(len <= m_nTrMaxBytes); // transferring more than 4mb into a 4mb local mem doesn't make any sense + + len = min(m_nTrMaxBytes, len); + + if(m_nTrBytes + len > m_nTrMaxBytes) + FlushWriteTransfer(); + + memcpy(&m_pTrBuff[m_nTrBytes], pMem, len); + m_nTrBytes += len; + } + else + { + int x = m_x, y = m_y; + + (m_lm.*GSLocalMemory::m_psmtbl[m_de.BITBLTBUF.DPSM].st)(m_x, m_y, pMem, len, m_de.BITBLTBUF, m_de.TRXPOS, m_de.TRXREG); + + m_perfmon.IncCounter(GSPerfMon::c_swizzle, len); + + //ASSERT(m_de.TRXREG.RRH >= m_y - y); + + CRect r(m_de.TRXPOS.DSAX, y, m_de.TRXREG.RRW, min(m_x == m_de.TRXPOS.DSAX ? m_y : m_y+1, m_de.TRXREG.RRH)); + InvalidateTexture(m_de.BITBLTBUF, r); + + m_lm.InvalidateCLUT(); + } +} + +void GSState::FlushWriteTransfer() +{ + if(!m_nTrBytes) return; + + int x = m_x, y = m_y; + + LOG(_T("*TC2 FlushWriteTransfer %d,%d-%d,%d (psm=%d rr=%dx%d len=%d)\n"), x, y, m_x, m_y, m_de.BITBLTBUF.DPSM, m_de.TRXREG.RRW, m_de.TRXREG.RRH, m_nTrBytes); + + (m_lm.*GSLocalMemory::m_psmtbl[m_de.BITBLTBUF.DPSM].st)(m_x, m_y, m_pTrBuff, m_nTrBytes, m_de.BITBLTBUF, m_de.TRXPOS, m_de.TRXREG); + + m_perfmon.IncCounter(GSPerfMon::c_swizzle, m_nTrBytes); + + m_nTrBytes = 0; + + //ASSERT(m_de.TRXREG.RRH >= m_y - y); + + CRect r(m_de.TRXPOS.DSAX, y, m_de.TRXREG.RRW, min(m_x == m_de.TRXPOS.DSAX ? m_y : m_y+1, m_de.TRXREG.RRH)); + InvalidateTexture(m_de.BITBLTBUF, r); + + m_lm.InvalidateCLUT(); +} + +void GSState::ReadTransfer(BYTE* pMem, int len) +{ + BYTE* pb = (BYTE*)pMem; + WORD* pw = (WORD*)pMem; + DWORD* pd = (DWORD*)pMem; + + if(m_y >= (int)m_de.TRXREG.RRH) {ASSERT(0); return;} + + if(m_x == m_de.TRXPOS.SSAX && m_y == m_de.TRXPOS.SSAY) + { + CRect r(m_de.TRXPOS.SSAX, m_de.TRXPOS.SSAY, m_de.TRXREG.RRW, m_de.TRXREG.RRH); + InvalidateLocalMem(m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW, m_de.BITBLTBUF.SPSM, r); + } + + switch(m_de.BITBLTBUF.SPSM) + { + case PSM_PSMCT32: + for(len /= 4; len-- > 0; ReadStep(), pd++) + *pd = m_lm.readPixel32(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMCT24: + for(len /= 3; len-- > 0; ReadStep(), pb+=3) + { + DWORD dw = m_lm.readPixel24(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + pb[0] = ((BYTE*)&dw)[0]; pb[1] = ((BYTE*)&dw)[1]; pb[2] = ((BYTE*)&dw)[2]; + } + break; + case PSM_PSMCT16: + for(len /= 2; len-- > 0; ReadStep(), pw++) + *pw = (WORD)m_lm.readPixel16(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMCT16S: + for(len /= 2; len-- > 0; ReadStep(), pw++) + *pw = (WORD)m_lm.readPixel16S(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMT8: + for(; len-- > 0; ReadStep(), pb++) + *pb = (BYTE)m_lm.readPixel8(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMT4: + for(; len-- > 0; ReadStep(), ReadStep(), pb++) + *pb = (BYTE)(m_lm.readPixel4(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)&0x0f) + | (BYTE)(m_lm.readPixel4(m_x+1, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)<<4); + break; + case PSM_PSMT8H: + for(; len-- > 0; ReadStep(), pb++) + *pb = (BYTE)m_lm.readPixel8H(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMT4HL: + for(; len-- > 0; ReadStep(), ReadStep(), pb++) + *pb = (BYTE)(m_lm.readPixel4HL(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)&0x0f) + | (BYTE)(m_lm.readPixel4HL(m_x+1, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)<<4); + break; + case PSM_PSMT4HH: + for(; len-- > 0; ReadStep(), ReadStep(), pb++) + *pb = (BYTE)(m_lm.readPixel4HH(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)&0x0f) + | (BYTE)(m_lm.readPixel4HH(m_x+1, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW)<<4); + break; + case PSM_PSMZ32: + for(len /= 4; len-- > 0; ReadStep(), pd++) + *pd = m_lm.readPixel32Z(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMZ24: + for(len /= 3; len-- > 0; ReadStep(), pb+=3) + { + DWORD dw = m_lm.readPixel24Z(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + pb[0] = ((BYTE*)&dw)[0]; pb[1] = ((BYTE*)&dw)[1]; pb[2] = ((BYTE*)&dw)[2]; + } + break; + case PSM_PSMZ16: + for(len /= 2; len-- > 0; ReadStep(), pw++) + *pw = (WORD)m_lm.readPixel16Z(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + case PSM_PSMZ16S: + for(len /= 2; len-- > 0; ReadStep(), pw++) + *pw = (WORD)m_lm.readPixel16SZ(m_x, m_y, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW); + break; + } +} + +void GSState::MoveTransfer() +{ + GSLocalMemory::readPixel rp = GSLocalMemory::m_psmtbl[m_de.BITBLTBUF.SPSM].rp; + GSLocalMemory::writePixel wp = GSLocalMemory::m_psmtbl[m_de.BITBLTBUF.DPSM].wp; + + int sx = m_de.TRXPOS.SSAX; + int dx = m_de.TRXPOS.DSAX; + int sy = m_de.TRXPOS.SSAY; + int dy = m_de.TRXPOS.DSAY; + int w = m_de.TRXREG.RRW; + int h = m_de.TRXREG.RRH; + int xinc = 1; + int yinc = 1; + + if(sx < dx) sx += w-1, dx += w-1, xinc = -1; + if(sy < dy) sy += h-1, dy += h-1, yinc = -1; + + for(int y = 0; y < h; y++, sy += yinc, dy += yinc, sx -= xinc*w, dx -= xinc*w) + for(int x = 0; x < w; x++, sx += xinc, dx += xinc) + (m_lm.*wp)(dx, dy, (m_lm.*rp)(sx, sy, m_de.BITBLTBUF.SBP, m_de.BITBLTBUF.SBW), m_de.BITBLTBUF.DBP, m_de.BITBLTBUF.DBW); +} + + diff --git a/plugins/gs/gsdx9/GSUtil.cpp b/plugins/gs/gsdx9/GSUtil.cpp new file mode 100644 index 0000000000..1b4186d9cc --- /dev/null +++ b/plugins/gs/gsdx9/GSUtil.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx9.h" +#include "GSState.h" + +BOOL IsDepthFormatOk(IDirect3D9* pD3D, D3DFORMAT DepthFormat, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat) +{ + // Verify that the depth format exists. + HRESULT hr = pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, AdapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, DepthFormat); + if(FAILED(hr)) return FALSE; + + // Verify that the depth format is compatible. + hr = pD3D->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, CGSdx9App::D3DDEVTYPE_X, AdapterFormat, BackBufferFormat, DepthFormat); + return SUCCEEDED(hr); +} + +HRESULT CompileShaderFromResource(IDirect3DDevice9* pD3DDev, UINT id, CString entry, CString target, UINT flags, IDirect3DPixelShader9** ppPixelShader) +{ + CheckPointer(pD3DDev, E_POINTER); + CheckPointer(ppPixelShader, E_POINTER); + + CComPtr pShader, pErrorMsgs; + HRESULT hr = D3DXCompileShaderFromResource( + AfxGetResourceHandle(), MAKEINTRESOURCE(id), + NULL, NULL, + entry, target, flags, + &pShader, &pErrorMsgs, NULL); + ASSERT(SUCCEEDED(hr)); + + if(SUCCEEDED(hr)) + { + hr = pD3DDev->CreatePixelShader((DWORD*)pShader->GetBufferPointer(), ppPixelShader); + ASSERT(SUCCEEDED(hr)); + } + + return hr; +} + +HRESULT AssembleShaderFromResource(IDirect3DDevice9* pD3DDev, UINT id, UINT flags, IDirect3DPixelShader9** ppPixelShader) +{ + CheckPointer(pD3DDev, E_POINTER); + CheckPointer(ppPixelShader, E_POINTER); + + CComPtr pShader, pErrorMsgs; + HRESULT hr = D3DXAssembleShaderFromResource( + AfxGetResourceHandle(), MAKEINTRESOURCE(id), + NULL, NULL, + flags, + &pShader, &pErrorMsgs); + ASSERT(SUCCEEDED(hr)); + + if(SUCCEEDED(hr)) + { + hr = pD3DDev->CreatePixelShader((DWORD*)pShader->GetBufferPointer(), ppPixelShader); + ASSERT(SUCCEEDED(hr)); + } + + return hr; +} diff --git a/plugins/gs/gsdx9/GSUtil.h b/plugins/gs/gsdx9/GSUtil.h new file mode 100644 index 0000000000..b238b12cc6 --- /dev/null +++ b/plugins/gs/gsdx9/GSUtil.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +extern BOOL IsDepthFormatOk(IDirect3D9* pD3D, D3DFORMAT DepthFormat, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat); +extern HRESULT CompileShaderFromResource(IDirect3DDevice9* pD3DDev, UINT id, CString entry, CString target, UINT flags, IDirect3DPixelShader9** ppPixelShader); +extern HRESULT AssembleShaderFromResource(IDirect3DDevice9* pD3DDev, UINT id, UINT flags, IDirect3DPixelShader9** ppPixelShader); diff --git a/plugins/gs/gsdx9/GSVertexList.cpp b/plugins/gs/gsdx9/GSVertexList.cpp new file mode 100644 index 0000000000..a9e1e3bb23 --- /dev/null +++ b/plugins/gs/gsdx9/GSVertexList.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSVertexList.h" \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSVertexList.h b/plugins/gs/gsdx9/GSVertexList.h new file mode 100644 index 0000000000..88ba2d4ea1 --- /dev/null +++ b/plugins/gs/gsdx9/GSVertexList.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +template class GSVertexList +{ + VERTEX* m_v; + int m_head, m_tail, m_count; + +public: + GSVertexList() + { + m_v = (VERTEX*)_aligned_malloc(sizeof(VERTEX)*4, 16); + RemoveAll(); + } + + ~GSVertexList() + { + _aligned_free(m_v); + } + + void RemoveAll() + { + m_head = m_tail = m_count = 0; + } + + VERTEX& AddTail() + { + ASSERT(m_count < 4); + VERTEX& v = m_v[m_tail]; + m_tail = (m_tail+1)&3; + m_count++; + return v; + } + + void AddTail(VERTEX& v) + { + ASSERT(m_count < 4); + m_v[m_tail] = v; + m_tail = (m_tail+1)&3; + m_count++; + } + + void RemoveAt(int i, VERTEX& v) + { + GetAt(i, v); + i = (m_head+i)&3; + if(i == m_head) m_head = (m_head+1)&3; + else for(m_tail = (m_tail+4-1)&3; i != m_tail; i = (i+1)&3) m_v[i] = m_v[(i+1)&3]; + m_count--; + } + + void GetAt(int i, VERTEX& v) + { + ASSERT(m_count > 0); + v = m_v[(m_head+i)&3]; + } + + int GetCount() + { + return m_count; + } +}; \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSWnd.cpp b/plugins/gs/gsdx9/GSWnd.cpp new file mode 100644 index 0000000000..5e74d1c82d --- /dev/null +++ b/plugins/gs/gsdx9/GSWnd.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSWnd.h" + +IMPLEMENT_DYNCREATE(CGSWnd, CWnd) + +CGSWnd::CGSWnd() +{ +} + +BOOL CGSWnd::Create(LPCSTR pTitle) +{ + CRect r; + GetDesktopWindow()->GetWindowRect(r); + // r.DeflateRect(r.Width()*3/8, r.Height()*3/8); + r.DeflateRect(r.Width()/3, r.Height()/3); + LPCTSTR wndclass = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0/*(HBRUSH)(COLOR_BTNFACE + 1)*/, 0); + return CreateEx(0, wndclass, pTitle, WS_OVERLAPPEDWINDOW, r, NULL, 0); +} + +void CGSWnd::Show(bool bShow) +{ + if(bShow) + { + SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + SetForegroundWindow(); + ShowWindow(SW_SHOWNORMAL); + } + else + { + ShowWindow(SW_HIDE); + } +} + +BEGIN_MESSAGE_MAP(CGSWnd, CWnd) + ON_WM_CLOSE() +END_MESSAGE_MAP() + +void CGSWnd::OnClose() +{ + PostMessage(WM_QUIT); +} diff --git a/plugins/gs/gsdx9/GSWnd.h b/plugins/gs/gsdx9/GSWnd.h new file mode 100644 index 0000000000..82eb774859 --- /dev/null +++ b/plugins/gs/gsdx9/GSWnd.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +class CGSWnd : public CWnd +{ + DECLARE_DYNCREATE(CGSWnd) + +public: + CGSWnd(); + + BOOL Create(LPCSTR pTitle); + void Show(bool bShow = true); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnClose(); +}; diff --git a/plugins/gs/gsdx9/GSdx9.cpp b/plugins/gs/gsdx9/GSdx9.cpp new file mode 100644 index 0000000000..b07ab5e6a1 --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * Special Notes: + * + */ + +#include "stdafx.h" +#include "afxwin.h" +#include "GSdx9.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +// CGSdx9App + +BEGIN_MESSAGE_MAP(CGSdx9App, CWinApp) +END_MESSAGE_MAP() + +D3DDEVTYPE CGSdx9App::D3DDEVTYPE_X; + +// CGSdx9App construction + +CGSdx9App::CGSdx9App() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + + +// The one and only CGSdx9App object + +CGSdx9App theApp; + +// CGSdx9App initialization + +BOOL CGSdx9App::InitInstance() +{ + __super::InitInstance(); + + D3DDEVTYPE_X = D3DDEVTYPE_HAL; + + if(GetSystemMetrics(SM_REMOTESESSION)) + { + D3DDEVTYPE_X = D3DDEVTYPE_REF; + } + + return TRUE; +} diff --git a/plugins/gs/gsdx9/GSdx9.def b/plugins/gs/gsdx9/GSdx9.def new file mode 100644 index 0000000000..218e2b1859 --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9.def @@ -0,0 +1,31 @@ +; GSdx9.def : Declares the module parameters for the DLL. + +LIBRARY "GSdx9" + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType + PS2EgetLibName + PS2EgetLibVersion2 + PS2EgetCpuPlatform + GSsetBaseMem + GSinit + GSshutdown + GSopen + GSclose + GSreset + GSwriteCSR + GSgifTransfer1 + GSgifTransfer2 + GSgifTransfer3 + GSvsync + GSmakeSnapshot + GSkeyEvent + GSfreeze + GSconfigure + GStest + GSabout + GSreadFIFO + GSirqCallback + GSgetLastTag + ; GSReplay \ No newline at end of file diff --git a/plugins/gs/gsdx9/GSdx9.h b/plugins/gs/gsdx9/GSdx9.h new file mode 100644 index 0000000000..73fe174bbb --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + + +// CGSdx9App +// See GSdx9.cpp for the implementation of this class +// + +class CGSdx9App : public CWinApp +{ +public: + CGSdx9App(); + + static D3DDEVTYPE D3DDEVTYPE_X; + +// Overrides +public: + virtual BOOL InitInstance(); + + DECLARE_MESSAGE_MAP() +}; + +enum +{ + RENDERER_D3D_NULL, + RENDERER_D3D_SW_FX, + RENDERER_D3D_SW_FP, + RENDERER_D3D_HW +}; diff --git a/plugins/gs/gsdx9/GSdx9.icproj b/plugins/gs/gsdx9/GSdx9.icproj new file mode 100644 index 0000000000..fdf2a5314b --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9.icproj @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/gsdx9/GSdx9.rc b/plugins/gs/gsdx9/GSdx9.rc new file mode 100644 index 0000000000..f113b4a5fe --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9.rc @@ -0,0 +1,220 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Hungarian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_HUN) +#ifdef _WIN32 +LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#include ""res\\GSdx9.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Hungarian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_LOGO1 BITMAP "res\\logo1.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 189, 209 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Settings..." +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,43,188,50,14 + DEFPUSHBUTTON "OK",IDOK,98,188,50,14 + COMBOBOX IDC_COMBO1,64,72,118,69,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Renderer:",IDC_STATIC,7,74,34,8 + LTEXT "Resolution:",IDC_STATIC,7,59,37,8 + COMBOBOX IDC_COMBO3,64,57,118,125,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Shader:",IDC_STATIC,7,89,26,8 + COMBOBOX IDC_COMBO4,64,87,118,98,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT1,64,158,100,13,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "...",IDC_BUTTON1,165,158,17,14 + CONTROL "Record state",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,158,53,10 + CONTROL "Enable tv-out",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,132,57,10 + CONTROL "Enable palettized textures (D3D PS v2.0+, slow)", + IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_TOP | + WS_TABSTOP,7,105,175,10 + LTEXT """rundll32 gsdx9.dll,GSReplay gsdx9_*.gs"" to replay", + IDC_STATIC,14,174,168,9 + CONTROL "Linear texture filtering",IDC_CHECK4,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,118,87,10 + CONTROL 2024,IDC_STATIC,"Static",SS_BITMAP,7,7,175,44 + CONTROL "NLOOP 0 hack (fixes FFX)",IDC_CHECK5,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,145,98,10 +END + +IDD_CAPTURE DIALOGEX 0, 0, 279, 67 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Capture settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,140,46,50,14 + PUSHBUTTON "Cancel",IDCANCEL,88,46,50,14 + COMBOBOX IDC_COMBO1,7,27,207,122,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT1,7,7,207,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BUTTON1,222,7,50,14 + PUSHBUTTON "Config...",IDC_BUTTON2,222,26,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 182 + VERTGUIDE, 64 + VERTGUIDE, 182 + TOPMARGIN, 7 + BOTTOMMARGIN, 202 + HORZGUIDE, 150 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,9 + PRODUCTVERSION 1,0,0,9 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "Comments", "http://gabest.org/" + VALUE "CompanyName", "Gabest" + VALUE "FileDescription", "GS plugin for ps2 emulators" + VALUE "FileVersion", "1, 0, 0, 9" + VALUE "InternalName", "GSdx9.dll" + VALUE "LegalCopyright", "Copyright (c) 2004-2005 Gabest. All rights reserved." + VALUE "OriginalFilename", "GSdx9.dll" + VALUE "ProductName", "GSdx9" + VALUE "ProductVersion", "1, 0, 0, 9" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) +#include "res\GSdx9.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/gs/gsdx9/GSdx9_vs2005.sln b/plugins/gs/gsdx9/GSdx9_vs2005.sln new file mode 100644 index 0000000000..516d5d1098 --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9_vs2005.sln @@ -0,0 +1,54 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GSdx9", "GSdx9_vs2005.vcproj", "{345C9F24-0B9A-4289-B375-ADD3B63461B7}" + ProjectSection(ProjectDependencies) = postProject + {7CDC5863-9F36-468D-A634-6D7799E0A15E} = {7CDC5863-9F36-468D-A634-6D7799E0A15E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BaseClasses", "baseclasses\baseclasses.vcproj", "{7CDC5863-9F36-468D-A634-6D7799E0A15E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + DebugSSE2|Win32 = DebugSSE2|Win32 + DebugSSE2|x64 = DebugSSE2|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseSSE2|Win32 = ReleaseSSE2|Win32 + ReleaseSSE2|x64 = ReleaseSSE2|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Debug|Win32.ActiveCfg = Debug|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Debug|Win32.Build.0 = Debug|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Debug|x64.ActiveCfg = Debug|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Debug|x64.Build.0 = Debug|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.DebugSSE2|Win32.ActiveCfg = DebugSSE2|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.DebugSSE2|Win32.Build.0 = DebugSSE2|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.DebugSSE2|x64.ActiveCfg = DebugSSE2|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.DebugSSE2|x64.Build.0 = DebugSSE2|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Release|Win32.ActiveCfg = Release|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Release|Win32.Build.0 = Release|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Release|x64.ActiveCfg = Release|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.Release|x64.Build.0 = Release|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.ReleaseSSE2|Win32.ActiveCfg = ReleaseSSE2|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.ReleaseSSE2|Win32.Build.0 = ReleaseSSE2|Win32 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.ReleaseSSE2|x64.ActiveCfg = ReleaseSSE2|x64 + {345C9F24-0B9A-4289-B375-ADD3B63461B7}.ReleaseSSE2|x64.Build.0 = ReleaseSSE2|x64 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Debug|Win32.ActiveCfg = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Debug|Win32.Build.0 = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Debug|x64.ActiveCfg = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.DebugSSE2|Win32.ActiveCfg = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.DebugSSE2|Win32.Build.0 = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.DebugSSE2|x64.ActiveCfg = Debug|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Release|Win32.ActiveCfg = Release|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Release|Win32.Build.0 = Release|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.Release|x64.ActiveCfg = Release|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.ReleaseSSE2|Win32.ActiveCfg = Release|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.ReleaseSSE2|Win32.Build.0 = Release|Win32 + {7CDC5863-9F36-468D-A634-6D7799E0A15E}.ReleaseSSE2|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/gs/gsdx9/GSdx9_vs2005.vcproj b/plugins/gs/gsdx9/GSdx9_vs2005.vcproj new file mode 100644 index 0000000000..a646bc0c1b --- /dev/null +++ b/plugins/gs/gsdx9/GSdx9_vs2005.vcproj @@ -0,0 +1,1429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/gsdx9/baseclasses/Amvideo.h b/plugins/gs/gsdx9/baseclasses/Amvideo.h new file mode 100644 index 0000000000..d173c330a7 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/Amvideo.h @@ -0,0 +1,433 @@ +//------------------------------------------------------------------------------ +// File: AMVideo.h +// +// Desc: Video related definitions and interfaces for ActiveMovie. +// +// Copyright (c) 1992 - 2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMVIDEO__ +#define __AMVIDEO__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include + + +// This is an interface on the video renderer that provides information about +// DirectDraw with respect to its use by the renderer. For example it allows +// an application to get details of the surface and any hardware capabilities +// that are available. It also allows someone to adjust the surfaces that the +// renderer should use and furthermore even set the DirectDraw instance. We +// allow someone to set the DirectDraw instance because DirectDraw can only +// be opened once per process so it helps resolve conflicts. There is some +// duplication in this interface as the hardware/emulated/FOURCCs available +// can all be found through the IDirectDraw interface, this interface allows +// simple access to that information without calling the DirectDraw provider +// itself. The AMDDS prefix is ActiveMovie DirectDraw Switches abbreviated. + +#define AMDDS_NONE 0x00 // No use for DCI/DirectDraw +#define AMDDS_DCIPS 0x01 // Use DCI primary surface +#define AMDDS_PS 0x02 // Use DirectDraw primary +#define AMDDS_RGBOVR 0x04 // RGB overlay surfaces +#define AMDDS_YUVOVR 0x08 // YUV overlay surfaces +#define AMDDS_RGBOFF 0x10 // RGB offscreen surfaces +#define AMDDS_YUVOFF 0x20 // YUV offscreen surfaces +#define AMDDS_RGBFLP 0x40 // RGB flipping surfaces +#define AMDDS_YUVFLP 0x80 // YUV flipping surfaces +#define AMDDS_ALL 0xFF // ALL the previous flags +#define AMDDS_DEFAULT AMDDS_ALL // Use all available surfaces + +#define AMDDS_YUV (AMDDS_YUVOFF | AMDDS_YUVOVR | AMDDS_YUVFLP) +#define AMDDS_RGB (AMDDS_RGBOFF | AMDDS_RGBOVR | AMDDS_RGBFLP) +#define AMDDS_PRIMARY (AMDDS_DCIPS | AMDDS_PS) + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IDirectDrawVideo + +DECLARE_INTERFACE_(IDirectDrawVideo, IUnknown) +{ + // IUnknown methods + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + // IDirectDrawVideo methods + + STDMETHOD(GetSwitches)(THIS_ DWORD *pSwitches) PURE; + STDMETHOD(SetSwitches)(THIS_ DWORD Switches) PURE; + STDMETHOD(GetCaps)(THIS_ DDCAPS *pCaps) PURE; + STDMETHOD(GetEmulatedCaps)(THIS_ DDCAPS *pCaps) PURE; + STDMETHOD(GetSurfaceDesc)(THIS_ DDSURFACEDESC *pSurfaceDesc) PURE; + STDMETHOD(GetFourCCCodes)(THIS_ DWORD *pCount,DWORD *pCodes) PURE; + STDMETHOD(SetDirectDraw)(THIS_ LPDIRECTDRAW pDirectDraw) PURE; + STDMETHOD(GetDirectDraw)(THIS_ LPDIRECTDRAW *ppDirectDraw) PURE; + STDMETHOD(GetSurfaceType)(THIS_ DWORD *pSurfaceType) PURE; + STDMETHOD(SetDefault)(THIS) PURE; + STDMETHOD(UseScanLine)(THIS_ long UseScanLine) PURE; + STDMETHOD(CanUseScanLine)(THIS_ long *UseScanLine) PURE; + STDMETHOD(UseOverlayStretch)(THIS_ long UseOverlayStretch) PURE; + STDMETHOD(CanUseOverlayStretch)(THIS_ long *UseOverlayStretch) PURE; + STDMETHOD(UseWhenFullScreen)(THIS_ long UseWhenFullScreen) PURE; + STDMETHOD(WillUseFullScreen)(THIS_ long *UseWhenFullScreen) PURE; +}; + + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IQualProp + +DECLARE_INTERFACE_(IQualProp, IUnknown) +{ + // IUnknown methods + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + // Compare these with the functions in class CGargle in gargle.h + + STDMETHOD(get_FramesDroppedInRenderer)(THIS_ int *pcFrames) PURE; // Out + STDMETHOD(get_FramesDrawn)(THIS_ int *pcFramesDrawn) PURE; // Out + STDMETHOD(get_AvgFrameRate)(THIS_ int *piAvgFrameRate) PURE; // Out + STDMETHOD(get_Jitter)(THIS_ int *iJitter) PURE; // Out + STDMETHOD(get_AvgSyncOffset)(THIS_ int *piAvg) PURE; // Out + STDMETHOD(get_DevSyncOffset)(THIS_ int *piDev) PURE; // Out +}; + + +// This interface allows an application or plug in distributor to control a +// full screen renderer. The Modex renderer supports this interface. When +// connected a renderer should load the display modes it has available +// The number of modes available can be obtained through CountModes. Then +// information on each individual mode is available by calling GetModeInfo +// and IsModeAvailable. An application may enable and disable any modes +// by calling the SetEnabled flag with OATRUE or OAFALSE (not C/C++ TRUE +// and FALSE values) - the current value may be queried by IsModeEnabled + +// A more generic way of setting the modes enabled that is easier to use +// when writing applications is the clip loss factor. This defines the +// amount of video that can be lost when deciding which display mode to +// use. Assuming the decoder cannot compress the video then playing an +// MPEG file (say 352x288) into a 320x200 display will lose about 25% of +// the image. The clip loss factor specifies the upper range permissible. +// To allow typical MPEG video to be played in 320x200 it defaults to 25% + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IFullScreenVideo + +DECLARE_INTERFACE_(IFullScreenVideo, IUnknown) +{ + // IUnknown methods + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + // IFullScreenVideo methods + + STDMETHOD(CountModes)(THIS_ long *pModes) PURE; + STDMETHOD(GetModeInfo)(THIS_ long Mode,long *pWidth,long *pHeight,long *pDepth) PURE; + STDMETHOD(GetCurrentMode)(THIS_ long *pMode) PURE; + STDMETHOD(IsModeAvailable)(THIS_ long Mode) PURE; + STDMETHOD(IsModeEnabled)(THIS_ long Mode) PURE; + STDMETHOD(SetEnabled)(THIS_ long Mode,long bEnabled) PURE; + STDMETHOD(GetClipFactor)(THIS_ long *pClipFactor) PURE; + STDMETHOD(SetClipFactor)(THIS_ long ClipFactor) PURE; + STDMETHOD(SetMessageDrain)(THIS_ HWND hwnd) PURE; + STDMETHOD(GetMessageDrain)(THIS_ HWND *hwnd) PURE; + STDMETHOD(SetMonitor)(THIS_ long Monitor) PURE; + STDMETHOD(GetMonitor)(THIS_ long *Monitor) PURE; + STDMETHOD(HideOnDeactivate)(THIS_ long Hide) PURE; + STDMETHOD(IsHideOnDeactivate)(THIS) PURE; + STDMETHOD(SetCaption)(THIS_ BSTR strCaption) PURE; + STDMETHOD(GetCaption)(THIS_ BSTR *pstrCaption) PURE; + STDMETHOD(SetDefault)(THIS) PURE; +}; + + +// This adds the accelerator table capabilities in fullscreen. This is being +// added between the original runtime release and the full SDK release. We +// cannot just add the method to IFullScreenVideo as we don't want to force +// applications to have to ship the ActiveMovie support DLLs - this is very +// important to applications that plan on being downloaded over the Internet + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IFullScreenVideoEx + +DECLARE_INTERFACE_(IFullScreenVideoEx, IFullScreenVideo) +{ + // IUnknown methods + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + // IFullScreenVideo methods + + STDMETHOD(CountModes)(THIS_ long *pModes) PURE; + STDMETHOD(GetModeInfo)(THIS_ long Mode,long *pWidth,long *pHeight,long *pDepth) PURE; + STDMETHOD(GetCurrentMode)(THIS_ long *pMode) PURE; + STDMETHOD(IsModeAvailable)(THIS_ long Mode) PURE; + STDMETHOD(IsModeEnabled)(THIS_ long Mode) PURE; + STDMETHOD(SetEnabled)(THIS_ long Mode,long bEnabled) PURE; + STDMETHOD(GetClipFactor)(THIS_ long *pClipFactor) PURE; + STDMETHOD(SetClipFactor)(THIS_ long ClipFactor) PURE; + STDMETHOD(SetMessageDrain)(THIS_ HWND hwnd) PURE; + STDMETHOD(GetMessageDrain)(THIS_ HWND *hwnd) PURE; + STDMETHOD(SetMonitor)(THIS_ long Monitor) PURE; + STDMETHOD(GetMonitor)(THIS_ long *Monitor) PURE; + STDMETHOD(HideOnDeactivate)(THIS_ long Hide) PURE; + STDMETHOD(IsHideOnDeactivate)(THIS) PURE; + STDMETHOD(SetCaption)(THIS_ BSTR strCaption) PURE; + STDMETHOD(GetCaption)(THIS_ BSTR *pstrCaption) PURE; + STDMETHOD(SetDefault)(THIS) PURE; + + // IFullScreenVideoEx + + STDMETHOD(SetAcceleratorTable)(THIS_ HWND hwnd,HACCEL hAccel) PURE; + STDMETHOD(GetAcceleratorTable)(THIS_ HWND *phwnd,HACCEL *phAccel) PURE; + STDMETHOD(KeepPixelAspectRatio)(THIS_ long KeepAspect) PURE; + STDMETHOD(IsKeepPixelAspectRatio)(THIS_ long *pKeepAspect) PURE; +}; + + +// The SDK base classes contain a base video mixer class. Video mixing in a +// software environment is tricky because we typically have multiple streams +// each sending data at unpredictable times. To work with this we defined a +// pin that is the lead pin, when data arrives on this pin we do a mix. As +// an alternative we may not want to have a lead pin but output samples at +// predefined spaces, like one every 1/15 of a second, this interfaces also +// supports that mode of operations (there is a working video mixer sample) + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IBaseVideoMixer + +DECLARE_INTERFACE_(IBaseVideoMixer, IUnknown) +{ + STDMETHOD(SetLeadPin)(THIS_ int iPin) PURE; + STDMETHOD(GetLeadPin)(THIS_ int *piPin) PURE; + STDMETHOD(GetInputPinCount)(THIS_ int *piPinCount) PURE; + STDMETHOD(IsUsingClock)(THIS_ int *pbValue) PURE; + STDMETHOD(SetUsingClock)(THIS_ int bValue) PURE; + STDMETHOD(GetClockPeriod)(THIS_ int *pbValue) PURE; + STDMETHOD(SetClockPeriod)(THIS_ int bValue) PURE; +}; + +#define iPALETTE_COLORS 256 // Maximum colours in palette +#define iEGA_COLORS 16 // Number colours in EGA palette +#define iMASK_COLORS 3 // Maximum three components +#define iTRUECOLOR 16 // Minimum true colour device +#define iRED 0 // Index position for RED mask +#define iGREEN 1 // Index position for GREEN mask +#define iBLUE 2 // Index position for BLUE mask +#define iPALETTE 8 // Maximum colour depth using a palette +#define iMAXBITS 8 // Maximum bits per colour component + + +// Used for true colour images that also have a palette + +typedef struct tag_TRUECOLORINFO { + DWORD dwBitMasks[iMASK_COLORS]; + RGBQUAD bmiColors[iPALETTE_COLORS]; +} TRUECOLORINFO; + + +// The BITMAPINFOHEADER contains all the details about the video stream such +// as the actual image dimensions and their pixel depth. A source filter may +// also request that the sink take only a section of the video by providing a +// clipping rectangle in rcSource. In the worst case where the sink filter +// forgets to check this on connection it will simply render the whole thing +// which isn't a disaster. Ideally a sink filter will check the rcSource and +// if it doesn't support image extraction and the rectangle is not empty then +// it will reject the connection. A filter should use SetRectEmpty to reset a +// rectangle to all zeroes (and IsRectEmpty to later check the rectangle). +// The rcTarget specifies the destination rectangle for the video, for most +// source filters they will set this to all zeroes, a downstream filter may +// request that the video be placed in a particular area of the buffers it +// supplies in which case it will call QueryAccept with a non empty target + +typedef struct tagVIDEOINFOHEADER { + + RECT rcSource; // The bit we really want to use + RECT rcTarget; // Where the video should go + DWORD dwBitRate; // Approximate bit data rate + DWORD dwBitErrorRate; // Bit error rate for this stream + REFERENCE_TIME AvgTimePerFrame; // Average time per frame (100ns units) + + BITMAPINFOHEADER bmiHeader; + +} VIDEOINFOHEADER; + +// make sure the pbmi is initialized before using these macros +#define TRUECOLOR(pbmi) ((TRUECOLORINFO *)(((LPBYTE)&((pbmi)->bmiHeader)) \ + + (pbmi)->bmiHeader.biSize)) +#define COLORS(pbmi) ((RGBQUAD *)(((LPBYTE)&((pbmi)->bmiHeader)) \ + + (pbmi)->bmiHeader.biSize)) +#define BITMASKS(pbmi) ((DWORD *)(((LPBYTE)&((pbmi)->bmiHeader)) \ + + (pbmi)->bmiHeader.biSize)) + +// All the image based filters use this to communicate their media types. It's +// centred principally around the BITMAPINFO. This structure always contains a +// BITMAPINFOHEADER followed by a number of other fields depending on what the +// BITMAPINFOHEADER contains. If it contains details of a palettised format it +// will be followed by one or more RGBQUADs defining the palette. If it holds +// details of a true colour format then it may be followed by a set of three +// DWORD bit masks that specify where the RGB data can be found in the image +// (For more information regarding BITMAPINFOs see the Win32 documentation) + +// The rcSource and rcTarget fields are not for use by filters supplying the +// data. The destination (target) rectangle should be set to all zeroes. The +// source may also be zero filled or set with the dimensions of the video. So +// if the video is 352x288 pixels then set it to (0,0,352,288). These fields +// are mainly used by downstream filters that want to ask the source filter +// to place the image in a different position in an output buffer. So when +// using for example the primary surface the video renderer may ask a filter +// to place the video images in a destination position of (100,100,452,388) +// on the display since that's where the window is positioned on the display + +// !!! WARNING !!! +// DO NOT use this structure unless you are sure that the BITMAPINFOHEADER +// has a normal biSize == sizeof(BITMAPINFOHEADER) ! +// !!! WARNING !!! + +typedef struct tagVIDEOINFO { + + RECT rcSource; // The bit we really want to use + RECT rcTarget; // Where the video should go + DWORD dwBitRate; // Approximate bit data rate + DWORD dwBitErrorRate; // Bit error rate for this stream + REFERENCE_TIME AvgTimePerFrame; // Average time per frame (100ns units) + + BITMAPINFOHEADER bmiHeader; + + union { + RGBQUAD bmiColors[iPALETTE_COLORS]; // Colour palette + DWORD dwBitMasks[iMASK_COLORS]; // True colour masks + TRUECOLORINFO TrueColorInfo; // Both of the above + }; + +} VIDEOINFO; + +// These macros define some standard bitmap format sizes + +#define SIZE_EGA_PALETTE (iEGA_COLORS * sizeof(RGBQUAD)) +#define SIZE_PALETTE (iPALETTE_COLORS * sizeof(RGBQUAD)) +#define SIZE_MASKS (iMASK_COLORS * sizeof(DWORD)) +#define SIZE_PREHEADER (FIELD_OFFSET(VIDEOINFOHEADER,bmiHeader)) +#define SIZE_VIDEOHEADER (sizeof(BITMAPINFOHEADER) + SIZE_PREHEADER) +// !!! for abnormal biSizes +// #define SIZE_VIDEOHEADER(pbmi) ((pbmi)->bmiHeader.biSize + SIZE_PREHEADER) + +// DIBSIZE calculates the number of bytes required by an image + +#define WIDTHBYTES(bits) ((DWORD)(((bits)+31) & (~31)) / 8) +#define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((DWORD)(bi).biWidth * (DWORD)(bi).biBitCount) +#define _DIBSIZE(bi) (DIBWIDTHBYTES(bi) * (DWORD)(bi).biHeight) +#define DIBSIZE(bi) ((bi).biHeight < 0 ? (-1)*(_DIBSIZE(bi)) : _DIBSIZE(bi)) + +// This compares the bit masks between two VIDEOINFOHEADERs + +#define BIT_MASKS_MATCH(pbmi1,pbmi2) \ + (((pbmi1)->dwBitMasks[iRED] == (pbmi2)->dwBitMasks[iRED]) && \ + ((pbmi1)->dwBitMasks[iGREEN] == (pbmi2)->dwBitMasks[iGREEN]) && \ + ((pbmi1)->dwBitMasks[iBLUE] == (pbmi2)->dwBitMasks[iBLUE])) + +// These zero fill different parts of the VIDEOINFOHEADER structure + +// Only use these macros for pbmi's with a normal BITMAPINFOHEADER biSize +#define RESET_MASKS(pbmi) (ZeroMemory((PVOID)(pbmi)->dwBitFields,SIZE_MASKS)) +#define RESET_HEADER(pbmi) (ZeroMemory((PVOID)(pbmi),SIZE_VIDEOHEADER)) +#define RESET_PALETTE(pbmi) (ZeroMemory((PVOID)(pbmi)->bmiColors,SIZE_PALETTE)); + +#if 0 +// !!! This is the right way to do it, but may break existing code +#define RESET_MASKS(pbmi) (ZeroMemory((PVOID)(((LPBYTE)(pbmi)->bmiHeader) + \ + (pbmi)->bmiHeader.biSize,SIZE_MASKS))) +#define RESET_HEADER(pbmi) (ZeroMemory((PVOID)(pbmi), SIZE_PREHEADER + \ + sizeof(BITMAPINFOHEADER))) +#define RESET_PALETTE(pbmi) (ZeroMemory((PVOID)(((LPBYTE)(pbmi)->bmiHeader) + \ + (pbmi)->bmiHeader.biSize,SIZE_PALETTE)) +#endif + +// Other (hopefully) useful bits and bobs + +#define PALETTISED(pbmi) ((pbmi)->bmiHeader.biBitCount <= iPALETTE) +#define PALETTE_ENTRIES(pbmi) ((DWORD) 1 << (pbmi)->bmiHeader.biBitCount) + +// Returns the address of the BITMAPINFOHEADER from the VIDEOINFOHEADER +#define HEADER(pVideoInfo) (&(((VIDEOINFOHEADER *) (pVideoInfo))->bmiHeader)) + + +// MPEG variant - includes a DWORD length followed by the +// video sequence header after the video header. +// +// The sequence header includes the sequence header start code and the +// quantization matrices associated with the first sequence header in the +// stream so is a maximum of 140 bytes long. + +typedef struct tagMPEG1VIDEOINFO { + + VIDEOINFOHEADER hdr; // Compatible with VIDEOINFO + DWORD dwStartTimeCode; // 25-bit Group of pictures time code + // at start of data + DWORD cbSequenceHeader; // Length in bytes of bSequenceHeader + BYTE bSequenceHeader[1]; // Sequence header including + // quantization matrices if any +} MPEG1VIDEOINFO; + +#define MAX_SIZE_MPEG1_SEQUENCE_INFO 140 +#define SIZE_MPEG1VIDEOINFO(pv) (FIELD_OFFSET(MPEG1VIDEOINFO, bSequenceHeader[0]) + (pv)->cbSequenceHeader) +#define MPEG1_SEQUENCE_INFO(pv) ((const BYTE *)(pv)->bSequenceHeader) + + +// Analog video variant - Use this when the format is FORMAT_AnalogVideo +// +// rcSource defines the portion of the active video signal to use +// rcTarget defines the destination rectangle +// both of the above are relative to the dwActiveWidth and dwActiveHeight fields +// dwActiveWidth is currently set to 720 for all formats (but could change for HDTV) +// dwActiveHeight is 483 for NTSC and 575 for PAL/SECAM (but could change for HDTV) + +typedef struct tagAnalogVideoInfo { + RECT rcSource; // Width max is 720, height varies w/ TransmissionStd + RECT rcTarget; // Where the video should go + DWORD dwActiveWidth; // Always 720 (CCIR-601 active samples per line) + DWORD dwActiveHeight; // 483 for NTSC, 575 for PAL/SECAM + REFERENCE_TIME AvgTimePerFrame; // Normal ActiveMovie units (100 nS) +} ANALOGVIDEOINFO; + +// +// AM_KSPROPSETID_FrameStep property set definitions +// +typedef enum { + // Step + AM_PROPERTY_FRAMESTEP_STEP = 0x01, + AM_PROPERTY_FRAMESTEP_CANCEL = 0x02, + + // S_OK for these 2 means we can - S_FALSE if we can't + AM_PROPERTY_FRAMESTEP_CANSTEP = 0x03, + AM_PROPERTY_FRAMESTEP_CANSTEPMULTIPLE = 0x04 +} AM_PROPERTY_FRAMESTEP; + +typedef struct _AM_FRAMESTEP_STEP +{ + // 1 means step 1 frame forward + // 0 is invalid + // n (n > 1) means skip n - 1 frames and show the nth + DWORD dwFramesToStep; +} AM_FRAMESTEP_STEP; + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // __AMVIDEO__ + diff --git a/plugins/gs/gsdx9/baseclasses/activex.rcv b/plugins/gs/gsdx9/baseclasses/activex.rcv new file mode 100644 index 0000000000..8aef99bfa5 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/activex.rcv @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// File: Activex.rcv +// +// Desc: DirectShow base classes - this file defines the version resource +// used for the application. +// +// NOTE: All strings MUST have an explicit \0 for termination! +// +// For a complete description of the Version Resource, search the +// Microsoft Developer's Network (MSDN) CD-ROM for 'version resource'.. +// +// Copyright (c) 1992 - 2002, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _ACTIVEX_RCV_ +#define _ACTIVEX_RCV_ + +#ifndef WIN32 +#define WIN32 +#endif +#include + +#ifndef _ACTIVEX_VER_ +#include +#endif + +// +// Version flags. +// +// OFFICIAL and FINAL should be defined when appropriate. +// + +#ifndef OFFICIAL +#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD +#else +#define VER_PRIVATEBUILD 0 +#endif + +#ifndef FINAL +#define VER_PRERELEASE VS_FF_PRERELEASE +#else +#define VER_PRERELEASE 0 +#endif + +#ifdef DEBUG +#define VER_DEBUG VS_FF_DEBUG +#else +#define VER_DEBUG 0 +#endif + +// +// Version definitions +// + +#define VERSION_RES_FLAGSMASK 0x0030003FL +#define VERSION_RES_FLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG) + +#ifndef VERSION_RES_OS +#define VERSION_RES_OS VOS__WINDOWS32 +#endif + +#ifndef VERSION_RES_TYPE +#define VERSION_RES_TYPE VFT_DLL +#endif + +#ifndef VERSION_RES_SUBTYPE +#define VERSION_RES_SUBTYPE VFT2_UNKNOWN +#endif + +#define VERSION_RES_LANGUAGE 0x409 + +#ifndef VERSION_RES_CHARSET +#ifdef UNICODE +#define VERSION_RES_CHARSET 1200 +#else +#define VERSION_RES_CHARSET 1252 +#endif +#endif + +#ifndef VERSION_RES_ACTIVEX +#define VERSION_RES_ACTIVEX "Filter dll\0" +#endif + +#ifdef AMOVIE_SELF_REGISTER +#ifndef OLE_SELF_REGISTER +#define OLE_SELF_REGISTER +#endif +#endif + +#ifdef OLE_SELF_REGISTER +#ifdef AMOVIE_SELF_REGISTER +#define VERSION_RES_SELFREGISTER "AM20\0" +#else +#define VERSION_RES_SELFREGISTER "\0" +#endif +#endif + +// +// Version resource +// + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VERSION_RES_MAJOR_VER, VERSION_RES_MINOR_VER, 0, VERSION_RES_BUILD +PRODUCTVERSION VERSION_RES_MAJOR_VER, VERSION_RES_MINOR_VER, 0, VERSION_RES_BUILD +FILEFLAGSMASK VERSION_RES_FLAGSMASK +FILEFLAGS VERSION_RES_FLAGS +FILEOS VERSION_RES_OS +FILETYPE VERSION_RES_TYPE +FILESUBTYPE VERSION_RES_SUBTYPE +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", VERSION_RES_COMPANY_NAME + VALUE "Comment", VERSION_RES_COMMENT + VALUE "FileDescription", VERSION_RES_BIN_DESCRIPTION + VALUE "FileVersion", VERSION_RES_STRING + VALUE "InternalName", VERSION_RES_BIN_NAME + VALUE "LegalCopyright", VERSION_RES_COPYRIGHT + VALUE "OriginalFilename", VERSION_RES_BIN_NAME + VALUE "ProductName", VERSION_RES_PRODUCT_NAME +#ifdef DEBUG + VALUE "ProductVersion", VERSION_RES_STRING_D +#else + VALUE "ProductVersion", VERSION_RES_STRING +#endif + VALUE "ActiveMovie", VERSION_RES_ACTIVEX +#ifdef OLE_SELF_REGISTER + VALUE "OLESelfRegister", VERSION_RES_SELFREGISTER +#endif + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", VERSION_RES_LANGUAGE, VERSION_RES_CHARSET + END +END + +#endif +// _ACTIVEX_RCV_ diff --git a/plugins/gs/gsdx9/baseclasses/activex.ver b/plugins/gs/gsdx9/baseclasses/activex.ver new file mode 100644 index 0000000000..4786f68eea --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/activex.ver @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// File: Activex.ver +// +// Desc: DirectShow base classes - common versioning information for +// ACTIVEX binaries. +// +// Copyright (c) 1996-2002, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _ACTIVEX_VER_ +#define _ACTIVEX_VER_ + +// NOTE: all string resources that will be used in ACTIVEX.RCV for the +// version resource information *MUST* have an explicit \0 terminator! + +#define VERSION_RES_MAJOR_VER 9 +#define VERSION_RES_MINOR_VER 0 +#define VERSION_RES_BUILD 0 + +#define VERSION_RES_STRING_D "9.00 (Debug)\0" +#define VERSION_RES_STRING "9.00\0" + +#define VERSION_RES_PRODUCT_NAME "DirectX 9.0 Sample\0" +#define VERSION_RES_COMMENT "DirectShow Sample\0" +#define VERSION_RES_COMPANY_NAME "Microsoft Corporation\0" +#define VERSION_RES_COPYRIGHT "Copyright (C) 1992-2002 Microsoft Corporation\0" + +// The following defines are required on a file-by-file basis +// +// #define VERSION_RES_BIN_NAME "sample.ax\0" +// #define VERSION_RES_BIN_DESCRIPTION "Sample Filter\0" +// +// Also required, if you don't want the defaults, are +// +// #define VERSION_RES_ACTIVEX "Filter dll\0" (the default value) +// +// A string defining the type of component. +// +// #define VERSION_RES_TYPE VFT_DLL (default) +// VFT_APP +// VFT_VXD +// VFT_DRV +// VFT_FONT +// VFT_STATIC_LIB +// VFT_UNKNOWN +// +// #define VERSION_RES_SUBTYPE VFT2_UNKNOWN (default) +// VFT2_DRV_INSTALLABLE +// VFT2_DRV_SOUND +// +// +// See winver.h for further details + +#endif + diff --git a/plugins/gs/gsdx9/baseclasses/amaudio.h b/plugins/gs/gsdx9/baseclasses/amaudio.h new file mode 100644 index 0000000000..77fdd76569 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amaudio.h @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// File: AMAudio.h +// +// Desc: Audio related definitions and interfaces for ActiveMovie. +// +// Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMAUDIO__ +#define __AMAUDIO__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include +#include + +// This is the interface the audio renderer supports to give the application +// access to the direct sound object and the buffers it is using, to allow the +// application to use things like the 3D features of Direct Sound for the +// soundtrack of a movie being played with Active Movie. + +// be nice to our friends in C +#undef INTERFACE +#define INTERFACE IAMDirectSound + +DECLARE_INTERFACE_(IAMDirectSound,IUnknown) +{ + /* IUnknown methods */ + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /* IAMDirectSound methods */ + + STDMETHOD(GetDirectSoundInterface)(THIS_ LPDIRECTSOUND *lplpds) PURE; + STDMETHOD(GetPrimaryBufferInterface)(THIS_ LPDIRECTSOUNDBUFFER *lplpdsb) PURE; + STDMETHOD(GetSecondaryBufferInterface)(THIS_ LPDIRECTSOUNDBUFFER *lplpdsb) PURE; + STDMETHOD(ReleaseDirectSoundInterface)(THIS_ LPDIRECTSOUND lpds) PURE; + STDMETHOD(ReleasePrimaryBufferInterface)(THIS_ LPDIRECTSOUNDBUFFER lpdsb) PURE; + STDMETHOD(ReleaseSecondaryBufferInterface)(THIS_ LPDIRECTSOUNDBUFFER lpdsb) PURE; + STDMETHOD(SetFocusWindow)(THIS_ HWND, BOOL) PURE ; + STDMETHOD(GetFocusWindow)(THIS_ HWND *, BOOL*) PURE ; +}; + + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // __AMAUDIO__ + diff --git a/plugins/gs/gsdx9/baseclasses/amextra.cpp b/plugins/gs/gsdx9/baseclasses/amextra.cpp new file mode 100644 index 0000000000..a242cee859 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amextra.cpp @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// File: AMExtra.cpp +// +// Desc: DirectShow base classes - implements CRenderedInputPin class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include // Used for time critical log functions + +#include "amextra.h" + +#pragma warning(disable:4355) + +// Implements CRenderedInputPin class + +CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#ifdef UNICODE +CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#endif + +// Flush end of stream condition - caller should do any +// necessary stream level locking before calling this + +STDMETHODIMP CRenderedInputPin::EndOfStream() +{ + HRESULT hr = CheckStreaming(); + + // Do EC_COMPLETE handling for rendered pins + if (S_OK == hr && !m_bAtEndOfStream) { + m_bAtEndOfStream = TRUE; + FILTER_STATE fs; + EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); + if (fs == State_Running) { + DoCompleteHandling(); + } + } + return hr; +} + + +// Called to complete the flush + +STDMETHODIMP CRenderedInputPin::EndFlush() +{ + CAutoLock lck(m_pLock); + + // Clean up renderer state + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + + return CBaseInputPin::EndFlush(); +} + + +// Notify of Run() from filter + +HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + m_bCompleteNotified = FALSE; + if (m_bAtEndOfStream) { + DoCompleteHandling(); + } + return S_OK; +} + + +// Clear status on going into paused state + +HRESULT CRenderedInputPin::Active() +{ + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + return CBaseInputPin::Active(); +} + + +// Do stuff to deliver end of stream + +void CRenderedInputPin::DoCompleteHandling() +{ + ASSERT(m_bAtEndOfStream); + if (!m_bCompleteNotified) { + m_bCompleteNotified = TRUE; + m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); + } +} + diff --git a/plugins/gs/gsdx9/baseclasses/amextra.h b/plugins/gs/gsdx9/baseclasses/amextra.h new file mode 100644 index 0000000000..ddb067ffcf --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amextra.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// File: AMExtra.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMEXTRA__ +#define __AMEXTRA__ + +// Simple rendered input pin +// +// NOTE if your filter queues stuff before rendering then it may not be +// appropriate to use this class +// +// In that case queue the end of stream condition until the last sample +// is actually rendered and flush the condition appropriately + +class CRenderedInputPin : public CBaseInputPin +{ +public: + + CRenderedInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CRenderedInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + + // Override methods to track end of stream state + STDMETHODIMP EndOfStream(); + STDMETHODIMP EndFlush(); + + HRESULT Active(); + HRESULT Run(REFERENCE_TIME tStart); + +protected: + + // Member variables to track state + BOOL m_bAtEndOfStream; // Set by EndOfStream + BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE + +private: + void DoCompleteHandling(); +}; + +#endif // __AMEXTRA__ + diff --git a/plugins/gs/gsdx9/baseclasses/amfilter.cpp b/plugins/gs/gsdx9/baseclasses/amfilter.cpp new file mode 100644 index 0000000000..eb26cd276f --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amfilter.cpp @@ -0,0 +1,5203 @@ +//------------------------------------------------------------------------------ +// File: AMFilter.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for streams +// architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//===================================================================== +//===================================================================== +// The following classes are declared in this header: +// +// +// CBaseMediaFilter Basic IMediaFilter support (abstract class) +// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) +// CEnumPins Enumerate input and output pins +// CEnumMediaTypes Enumerate the preferred pin formats +// CBasePin Abstract base class for IPin interface +// CBaseOutputPin Adds data provider member functions +// CBaseInputPin Implements IMemInputPin interface +// CMediaSample Basic transport unit for IMemInputPin +// CBaseAllocator General list guff for most allocators +// CMemAllocator Implements memory buffer allocation +// +//===================================================================== +//===================================================================== + +#include + + + +//===================================================================== +// Helpers +//===================================================================== +STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator) +{ + return CoCreateInstance(CLSID_MemoryAllocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IMemAllocator, + (void **)ppAllocator); +} + +// Put this one here rather than in ctlutil.cpp to avoid linking +// anything brought in by ctlutil.cpp +STDAPI CreatePosPassThru( + LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + IUnknown **ppPassThru +) +{ + *ppPassThru = NULL; + IUnknown *pUnkSeek; + HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, + pAgg, + CLSCTX_INPROC_SERVER, + IID_IUnknown, + (void **)&pUnkSeek + ); + if (FAILED(hr)) { + return hr; + } + + ISeekingPassThru *pPassThru; + hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + hr = pPassThru->Init(bRenderer, pPin); + pPassThru->Release(); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + *ppPassThru = pUnkSeek; + return S_OK; +} + + + +#define CONNECT_TRACE_LEVEL 3 + +//===================================================================== +//===================================================================== +// Implements CBaseMediaFilter +//===================================================================== +//===================================================================== + + +/* Constructor */ + +CBaseMediaFilter::CBaseMediaFilter(const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL) +{ +} + + +/* Destructor */ + +CBaseMediaFilter::~CBaseMediaFilter() +{ + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBaseMediaFilter::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseMediaFilter::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ + +STDMETHODIMP +CBaseMediaFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseMediaFilter::SetSyncSource(IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseMediaFilter::GetSyncSource(IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + +/* Put the filter into a stopped state */ + +STDMETHODIMP +CBaseMediaFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Stopped; + return S_OK; +} + + +/* Put the filter into a paused state */ + +STDMETHODIMP +CBaseMediaFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Paused; + return S_OK; +} + + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseMediaFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseMediaFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + m_State = State_Running; + return S_OK; +} + + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseMediaFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseFilter +//===================================================================== +//===================================================================== + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, + void **ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IBaseFilter) { + return GetInterface((IBaseFilter *) this, ppv); + } else if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else if (riid == IID_IAMovieSetup) { + return GetInterface((IAMovieSetup *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +#ifdef DEBUG +STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() +{ + if (m_cRef == 1) { + KASSERT(m_pGraph == NULL); + } + return CUnknown::NonDelegatingRelease(); +} +#endif + + +/* Constructor */ + +CBaseFilter::CBaseFilter(const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); +} + +/* Passes in a redundant HRESULT argument */ + +CBaseFilter::CBaseFilter(TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid, + HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CBaseFilter::CBaseFilter(const CHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); +} +CBaseFilter::CBaseFilter(CHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid, + HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} +#endif + +/* Destructor */ + +CBaseFilter::~CBaseFilter() +{ + + // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink + // When we did we had the circular reference problem. Nothing would go away. + + delete[] m_pName; + + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseFilter::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ +STDMETHODIMP +CBaseFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseFilter::SetSyncSource(IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseFilter::GetSyncSource(IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + + +// override CBaseMediaFilter Stop method, to deactivate any pins this +// filter has. +STDMETHODIMP +CBaseFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + HRESULT hr = NOERROR; + + // notify all pins of the state change + if (m_State != State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins worrying + // about this state themselves. We ignore the return code to make + // sure everyone is inactivated regardless. The base input pin + // class can return an error if it has no allocator but Stop can + // be used to resync the graph state after something has gone bad + + if (pPin->IsConnected()) { + HRESULT hrTmp = pPin->Inactive(); + if (FAILED(hrTmp) && SUCCEEDED(hr)) { + hr = hrTmp; + } + } + } + } + + + m_State = State_Stopped; + return hr; +} + + +// override CBaseMediaFilter Pause method to activate any pins +// this filter has (also called from Run) + +STDMETHODIMP +CBaseFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + // notify all pins of the change to active state + if (m_State == State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Active(); + if (FAILED(hr)) { + return hr; + } + } + } + } + + + + m_State = State_Paused; + return S_OK; +} + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + // notify all pins of the change to active state + if (m_State != State_Running) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Run(tStart); + if (FAILED(hr)) { + return hr; + } + } + } + } + + + m_State = State_Running; + return S_OK; +} + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +/* Create an enumerator for the pins attached to this filter */ + +STDMETHODIMP +CBaseFilter::EnumPins(IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumPins(this, + NULL); + + return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; +} + + +// default behaviour of FindPin is to assume pins are named +// by their pin names +STDMETHODIMP +CBaseFilter::FindPin( + LPCWSTR Id, + IPin ** ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + // We're going to search the pin list so maintain integrity + CAutoLock lck(m_pLock); + int iCount = GetPinCount(); + for (int i = 0; i < iCount; i++) { + CBasePin *pPin = GetPin(i); + ASSERT(pPin != NULL); + + if (0 == lstrcmpW(pPin->Name(), Id)) { + // Found one that matches + // + // AddRef() and return it + *ppPin = pPin; + pPin->AddRef(); + return S_OK; + } + } + *ppPin = NULL; + return VFW_E_NOT_FOUND; +} + +/* Return information about this filter */ + +STDMETHODIMP +CBaseFilter::QueryFilterInfo(FILTER_INFO * pInfo) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); + + if (m_pName) { + lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); + } else { + pInfo->achName[0] = L'\0'; + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return NOERROR; +} + + +/* Provide the filter with a filter graph */ + +STDMETHODIMP +CBaseFilter::JoinFilterGraph( + IFilterGraph * pGraph, + LPCWSTR pName) +{ + CAutoLock cObjectLock(m_pLock); + + // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) + + m_pGraph = pGraph; + if (m_pGraph) { + HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, + (void**) &m_pSink); + if (FAILED(hr)) { + ASSERT(m_pSink == NULL); + } + else m_pSink->Release(); // we do NOT keep a reference on it. + } else { + // if graph pointer is null, then we should + // also release the IMediaEventSink on the same object - we don't + // refcount it, so just set it to null + m_pSink = NULL; + } + + + if (m_pName) { + delete[] m_pName; + m_pName = NULL; + } + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } else { + // !!! error here? + ASSERT(FALSE); + } + } + + + return NOERROR; +} + + +// return a Vendor information string. Optional - may return E_NOTIMPL. +// memory returned should be freed using CoTaskMemFree +// default implementation returns E_NOTIMPL +STDMETHODIMP +CBaseFilter::QueryVendorInfo( + LPWSTR* pVendorInfo) +{ + UNREFERENCED_PARAMETER(pVendorInfo); + return E_NOTIMPL; +} + + +// send an event notification to the filter graph if we know about it. +// returns S_OK if delivered, S_FALSE if the filter graph does not sink +// events, or an error otherwise. +HRESULT +CBaseFilter::NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2) +{ + // Snapshot so we don't have to lock up + IMediaEventSink *pSink = m_pSink; + if (pSink) { + if (EC_COMPLETE == EventCode) { + EventParam2 = (LONG_PTR)(IBaseFilter*)this; + } + + return pSink->Notify(EventCode, EventParam1, EventParam2); + } else { + return E_NOTIMPL; + } +} + +// Request reconnect +// pPin is the pin to reconnect +// pmt is the type to reconnect with - can be NULL +// Calls ReconnectEx on the filter graph +HRESULT +CBaseFilter::ReconnectPin( + IPin *pPin, + AM_MEDIA_TYPE const *pmt +) +{ + IFilterGraph2 *pGraph2; + if (m_pGraph != NULL) { + HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); + if (SUCCEEDED(hr)) { + hr = pGraph2->ReconnectEx(pPin, pmt); + pGraph2->Release(); + return hr; + } else { + return m_pGraph->Reconnect(pPin); + } + } else { + return E_NOINTERFACE; + } +} + + + +/* This is the same idea as the media type version does for type enumeration + on pins but for the list of pins available. So if the list of pins you + provide changes dynamically then either override this virtual function + to provide the version number, or more simply call IncrementPinVersion */ + +LONG CBaseFilter::GetPinVersion() +{ + return m_PinVersion; +} + + +/* Increment the current pin version cookie */ + +void CBaseFilter::IncrementPinVersion() +{ + InterlockedIncrement(&m_PinVersion); +} + +/* register filter */ + +STDMETHODIMP CBaseFilter::Register() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // init is ref counted so call just in case + // we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); + pIFM->Release(); + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + return NOERROR; +} + + +/* unregister filter */ + +STDMETHODIMP CBaseFilter::Unregister() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // OLE init is ref counted so call + // just in case we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); + + // release interface + // + pIFM->Release(); + } + + // clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumPins +//===================================================================== +//===================================================================== + + +CEnumPins::CEnumPins(CBaseFilter *pFilter, + CEnumPins *pEnumPins) : + m_Position(0), + m_PinCount(0), + m_pFilter(pFilter), + m_cRef(1), // Already ref counted + m_PinCache(NAME("Pin Cache")) +{ + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); +#endif + + /* We must be owned by a filter derived from CBaseFilter */ + + ASSERT(pFilter != NULL); + + /* Hold a reference count on our filter */ + m_pFilter->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumPins == NULL) { + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + } else { + ASSERT(m_Position <= m_PinCount); + m_Position = pEnumPins->m_Position; + m_PinCount = pEnumPins->m_PinCount; + m_Version = pEnumPins->m_Version; + m_PinCache.AddTail(&(pEnumPins->m_PinCache)); + } +} + + +/* Destructor releases the reference count on our filter NOTE since we hold + a reference count on the filter who created us we know it is safe to + release it, no access can be made to it afterwards though as we have just + caused the last reference count to go and the object to be deleted */ + +CEnumPins::~CEnumPins() +{ + m_pFilter->Release(); + +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumPins::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumPins || riid == IID_IUnknown) { + return GetInterface((IEnumPins *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumPins::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumPins::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumPins::Clone(IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumPins(m_pFilter, + this); + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Return the next pin after the current position */ + +STDMETHODIMP +CEnumPins::Next(ULONG cPins, // place this many pins... + IPin **ppPins, // ...in this array + ULONG *pcFetched) // actual count passed returned here +{ + CheckPointer(ppPins,E_POINTER); + ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); + + ASSERT(ppPins); + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cPins>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + // If we are out of sync, we should refresh the enumerator. + // This will reset the position and update the other members, but + // will not clear cache of pins we have already returned. + Refresh(); + } + + /* Calculate the number of available pins */ + + int cRealPins = min(m_PinCount - m_Position, (int) cPins); + if (cRealPins == 0) { + return S_FALSE; + } + + /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed + so we must QI for the IPin (which increments its reference count) + If while we are retrieving a pin from the filter an error occurs we + assume that our internal state is stale with respect to the filter + (for example someone has deleted a pin) so we + return VFW_E_ENUM_OUT_OF_SYNC */ + + while (cRealPins && (m_PinCount - m_Position)) { + + /* Get the next pin object from the filter */ + + CBasePin *pPin = m_pFilter->GetPin(m_Position++); + if (pPin == NULL) { + // If this happend, and it's not the first time through, then we've got a problem, + // since we should really go back and release the iPins, which we have previously + // AddRef'ed. + ASSERT( cFetched==0 ); + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* We only want to return this pin, if it is not in our cache */ + if (0 == m_PinCache.Find(pPin)) + { + /* From the object get an IPin interface */ + + *ppPins = pPin; + pPin->AddRef(); + + cFetched++; + ppPins++; + + m_PinCache.AddTail(pPin); + + cRealPins--; + + } + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return (cPins==cFetched ? NOERROR : S_FALSE); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumPins::Skip(ULONG cPins) +{ + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* Work out how many pins are left to skip over */ + /* We could position at the end if we are asked to skip too many... */ + /* ..which would match the base implementation for CEnumMediaTypes::Skip */ + + ULONG PinsLeft = m_PinCount - m_Position; + if (cPins > PinsLeft) { + return S_FALSE; + } + m_Position += cPins; + return NOERROR; +} + + +/* Set the current position back to the start */ +/* Reset has 4 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * Clear the cache of pins already returned + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Reset() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + + // Clear the cache + m_PinCache.RemoveAll(); + + return S_OK; +} + + +/* Set the current position back to the start */ +/* Refresh has 3 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Refresh() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumMediaTypes +//===================================================================== +//===================================================================== + + +CEnumMediaTypes::CEnumMediaTypes(CBasePin *pPin, + CEnumMediaTypes *pEnumMediaTypes) : + m_Position(0), + m_pPin(pPin), + m_cRef(1) +{ + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); +#endif + + /* We must be owned by a pin derived from CBasePin */ + + ASSERT(pPin != NULL); + + /* Hold a reference count on our pin */ + m_pPin->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumMediaTypes == NULL) { + m_Version = m_pPin->GetMediaTypeVersion(); + return; + } + + m_Position = pEnumMediaTypes->m_Position; + m_Version = pEnumMediaTypes->m_Version; +} + + +/* Destructor releases the reference count on our base pin. NOTE since we hold + a reference count on the pin who created us we know it is safe to release + it, no access can be made to it afterwards though as we might have just + caused the last reference count to go and the object to be deleted */ + +CEnumMediaTypes::~CEnumMediaTypes() +{ +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif + m_pPin->Release(); +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumMediaTypes::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { + return GetInterface((IEnumMediaTypes *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumMediaTypes::Clone(IEnumMediaTypes **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumMediaTypes(m_pPin, + this); + + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Enumerate the next pin(s) after the current position. The client using this + interface passes in a pointer to an array of pointers each of which will + be filled in with a pointer to a fully initialised media type format + Return NOERROR if it all works, + S_FALSE if fewer than cMediaTypes were enumerated. + VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by + state changes in the filter + The actual count always correctly reflects the number of types in the array. +*/ + +STDMETHODIMP +CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... + AM_MEDIA_TYPE **ppMediaTypes, // ...in this array + ULONG *pcFetched) // actual count passed +{ + CheckPointer(ppMediaTypes,E_POINTER); + ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cMediaTypes>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Return each media type by asking the filter for them in turn - If we + have an error code retured to us while we are retrieving a media type + we assume that our internal state is stale with respect to the filter + (for example the window size changing) so we return + VFW_E_ENUM_OUT_OF_SYNC */ + + while (cMediaTypes) { + + CMediaType cmt; + + HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); + if (S_OK != hr) { + break; + } + + /* We now have a CMediaType object that contains the next media type + but when we assign it to the array position we CANNOT just assign + the AM_MEDIA_TYPE structure because as soon as the object goes out of + scope it will delete the memory we have just copied. The function + we use is CreateMediaType which allocates a task memory block */ + + /* Transfer across the format block manually to save an allocate + and free on the format block and generally go faster */ + + *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (*ppMediaTypes == NULL) { + break; + } + + /* Do a regular copy */ + **ppMediaTypes = (AM_MEDIA_TYPE)cmt; + + /* Make sure the destructor doesn't free these */ + cmt.pbFormat = NULL; + cmt.cbFormat = NULL; + cmt.pUnk = NULL; + + + ppMediaTypes++; + cFetched++; + cMediaTypes--; + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return ( cMediaTypes==0 ? NOERROR : S_FALSE ); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumMediaTypes::Skip(ULONG cMediaTypes) +{ + // If we're skipping 0 elements we're guaranteed to skip the + // correct number of elements + if (cMediaTypes == 0) { + return S_OK; + } + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + m_Position += cMediaTypes; + + /* See if we're over the end */ + CMediaType cmt; + return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; +} + + +/* Set the current position back to the start */ +/* Reset has 3 simple steps: + * + * set position to head of list + * sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumMediaTypes::Reset() + +{ + m_Position = 0; + + // Bring the enumerator back into step with the current state. This + // may be a noop but ensures that the enumerator will be valid on the + // next call. + m_Version = m_pPin->GetMediaTypeVersion(); + return NOERROR; +} + + +//===================================================================== +//===================================================================== +// Implements CBasePin +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants its lifetime controlled by the external object */ + +/* Constructor */ + +CBasePin::CBasePin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } + } + +#ifdef DEBUG + m_cRef = 0; +#endif +} + +#ifdef UNICODE +CBasePin::CBasePin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } + } + +#ifdef DEBUG + m_cRef = 0; +#endif +} +#endif + +/* Destructor since a connected pin holds a reference count on us there is + no way that we can be deleted unless we are not currently connected */ + +CBasePin::~CBasePin() +{ + + // We don't call disconnect because if the filter is going away + // all the pins must have a reference count of zero so they must + // have been disconnected anyway - (but check the assumption) + ASSERT(m_Connected == FALSE); + + delete[] m_pName; + + // check the internal reference count is consistent + ASSERT(m_cRef == 0); +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBasePin::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IPin) { + return GetInterface((IPin *) this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface((IQualityControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Override to increment the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingAddRef() +{ + ASSERT(InterlockedIncrement(&m_cRef) > 0); + return m_pFilter->AddRef(); +} + + +/* Override to decrement the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingRelease() +{ + ASSERT(InterlockedDecrement(&m_cRef) >= 0); + return m_pFilter->Release(); +} + + +/* Displays pin connection information */ + +#ifdef DEBUG +void +CBasePin::DisplayPinInfo(IPin *pReceivePin) +{ + + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + PIN_INFO ConnectPinInfo; + PIN_INFO ReceivePinInfo; + + if (FAILED(QueryPinInfo(&ConnectPinInfo))) { + (void)StringCchCopyW(ConnectPinInfo.achName, NUMELMS(ConnectPinInfo.achName),L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ConnectPinInfo); + } + + if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { + (void)StringCchCopyW(ReceivePinInfo.achName, NUMELMS(ReceivePinInfo.achName),L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ReceivePinInfo); + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); + } +} +#endif + + +/* Displays general information on the pin media type */ + +#ifdef DEBUG +void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(pPin); + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), + GuidNames[*pmt->Type()])); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), + GuidNames[*pmt->Subtype()])); + } +} +#endif + +/* Asked to connect to a pin. A pin is always attached to an owning filter + object so we always delegate our locking to that object. We first of all + retrieve a media type enumerator for the input pin and see if we accept + any of the formats that it would ideally like, failing that we retrieve + our enumerator and see if it will accept any of our preferred types */ + +STDMETHODIMP +CBasePin::Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type +) +{ + CheckPointer(pReceivePin,E_POINTER); + ValidateReadPtr(pReceivePin,sizeof(IPin)); + CAutoLock cObjectLock(m_pLock); + DisplayPinInfo(pReceivePin); + + /* See if we are already connected */ + + if (m_Connected) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + + // Find a mutually agreeable media type - + // Pass in the template media type. If this is partially specified, + // each of the enumerated media types will need to be checked against + // it. If it is non-null and fully specified, we will just try to connect + // with this. + + const CMediaType * ptype = (CMediaType*)pmt; + HRESULT hr = AgreeMediaType(pReceivePin, ptype); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); + + + return NOERROR; +} + +// given a specific media type, attempt a connection (includes +// checking that the type is acceptable to this pin) +HRESULT +CBasePin::AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type +) +{ + // The caller should hold the filter lock becasue this function + // uses m_Connected. The caller should also hold the filter lock + // because this function calls SetMediaType(), IsStopped() and + // CompleteConnect(). + ASSERT(CritCheckIn(m_pLock)); + + // Check that the connection is valid -- need to do this for every + // connect attempt since BreakConnect will undo it. + HRESULT hr = CheckConnect(pReceivePin); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + return hr; + } + + DisplayTypeInfo(pReceivePin, pmt); + + /* Check we will accept this media type */ + + hr = CheckMediaType(pmt); + if (hr == NOERROR) { + + /* Make ourselves look connected otherwise ReceiveConnection + may not be able to complete the connection + */ + m_Connected = pReceivePin; + m_Connected->AddRef(); + hr = SetMediaType(pmt); + if (SUCCEEDED(hr)) { + /* See if the other pin will accept this type */ + + hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); + if (SUCCEEDED(hr)) { + /* Complete the connection */ + + hr = CompleteConnect(pReceivePin); + if (SUCCEEDED(hr)) { + return hr; + } else { + DbgLog((LOG_TRACE, + CONNECT_TRACE_LEVEL, + TEXT("Failed to complete connection"))); + pReceivePin->Disconnect(); + } + } + } + } else { + // we cannot use this media type + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // BreakConnect and release any connection here in case CheckMediaType + // failed, or if we set anything up during a call back during + // ReceiveConnection. + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + /* If failed then undo our state */ + if (m_Connected) { + m_Connected->Release(); + m_Connected = NULL; + } + + return hr; +} + +/* Given an enumerator we cycle through all the media types it proposes and + firstly suggest them to our derived pin class and if that succeeds try + them with the pin in a ReceiveConnection call. This means that if our pin + proposes a media type we still check in here that we can support it. This + is deliberate so that in simple cases the enumerator can hold all of the + media types even if some of them are not really currently available */ + +HRESULT CBasePin::TryMediaTypes( + IPin *pReceivePin, + const CMediaType *pmt, + IEnumMediaTypes *pEnum) +{ + /* Reset the current enumerator position */ + + HRESULT hr = pEnum->Reset(); + if (FAILED(hr)) { + return hr; + } + + CMediaType *pMediaType = NULL; + ULONG ulMediaCount = 0; + + // attempt to remember a specific error code if there is one + HRESULT hrFailure = S_OK; + + for (;;) { + + /* Retrieve the next media type NOTE each time round the loop the + enumerator interface will allocate another AM_MEDIA_TYPE structure + If we are successful then we copy it into our output object, if + not then we must delete the memory allocated before returning */ + + hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); + if (hr != S_OK) { + if (S_OK == hrFailure) { + hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + } + return hrFailure; + } + + + ASSERT(ulMediaCount == 1); + ASSERT(pMediaType); + + // check that this matches the partial type (if any) + + if ((pmt == NULL) || + pMediaType->MatchesPartial(pmt)) { + + hr = AttemptConnection(pReceivePin, pMediaType); + + // attempt to remember a specific error code + if (FAILED(hr) && + SUCCEEDED(hrFailure) && + (hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } else { + hr = VFW_E_NO_ACCEPTABLE_TYPES; + } + + DeleteMediaType(pMediaType); + + if (S_OK == hr) { + return hr; + } + } +} + + +/* This is called to make the connection, including the taask of finding + a media type for the pin connection. pmt is the proposed media type + from the Connect call: if this is fully specified, we will try that. + Otherwise we enumerate and try all the input pin's types first and + if that fails we then enumerate and try all our preferred media types. + For each media type we check it against pmt (if non-null and partially + specified) as well as checking that both pins will accept it. + */ + +HRESULT CBasePin::AgreeMediaType( + IPin *pReceivePin, + const CMediaType *pmt) +{ + ASSERT(pReceivePin); + IEnumMediaTypes *pEnumMediaTypes = NULL; + + // if the media type is fully specified then use that + if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { + + // if this media type fails, then we must fail the connection + // since if pmt is nonnull we are only allowed to connect + // using a type that matches it. + + return AttemptConnection(pReceivePin, pmt); + } + + + /* Try the other pin's enumerator */ + + HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + + for (int i = 0; i < 2; i++) { + HRESULT hr; + if (i == (int)m_bTryMyTypesFirst) { + hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); + } else { + hr = EnumMediaTypes(&pEnumMediaTypes); + } + if (SUCCEEDED(hr)) { + ASSERT(pEnumMediaTypes); + hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); + pEnumMediaTypes->Release(); + if (SUCCEEDED(hr)) { + return NOERROR; + } else { + // try to remember specific error codes if there are any + if ((hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } + } + } + + return hrFailure; +} + + +/* Called when we want to complete a connection to another filter. Failing + this will also fail the connection and disconnect the other pin as well */ + +HRESULT +CBasePin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +/* This is called to set the format for a pin connection - CheckMediaType + will have been called to check the connection format and if it didn't + return an error code then this (virtual) function will be invoked */ + +HRESULT +CBasePin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = m_mt.Set(*pmt); + if (FAILED(hr)) { + return hr; + } + + return NOERROR; +} + + +/* This is called during Connect() to provide a virtual method that can do + any specific check needed for connection such as QueryInterface. This + base class method just checks that the pin directions don't match */ + +HRESULT +CBasePin::CheckConnect(IPin * pPin) +{ + /* Check that pin directions DONT match */ + + PIN_DIRECTION pd; + pPin->QueryDirection(&pd); + + ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); + ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); + + // we should allow for non-input and non-output connections? + if (pd == m_dir) { + return VFW_E_INVALID_DIRECTION; + } + return NOERROR; +} + + +/* This is called when we realise we can't make a connection to the pin and + must undo anything we did in CheckConnect - override to release QIs done */ + +HRESULT +CBasePin::BreakConnect() +{ + return NOERROR; +} + + +/* Called normally by an output pin on an input pin to try and establish a + connection. +*/ + +STDMETHODIMP +CBasePin::ReceiveConnection( + IPin * pConnector, // this is the pin who we will connect to + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange +) +{ + CheckPointer(pConnector,E_POINTER); + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pConnector,sizeof(IPin)); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Are we already connected */ + if (m_Connected) { + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + HRESULT hr = CheckConnect(pConnector); + if (FAILED(hr)) { + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; + } + + /* Ask derived class if this media type is ok */ + + CMediaType * pcmt = (CMediaType*) pmt; + hr = CheckMediaType(pcmt); + if (hr != NOERROR) { + // no -we don't support this media type + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + + + return hr; + } + + /* Complete the connection */ + + m_Connected = pConnector; + m_Connected->AddRef(); + hr = SetMediaType(pcmt); + if (SUCCEEDED(hr)) { + hr = CompleteConnect(pConnector); + if (SUCCEEDED(hr)) { + + + return NOERROR; + } + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); + m_Connected->Release(); + m_Connected = NULL; + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; +} + + +/* Called when we want to terminate a pin connection */ + +STDMETHODIMP +CBasePin::Disconnect() +{ + CAutoLock cObjectLock(m_pLock); + + /* See if the filter is active */ + if (!IsStopped()) { + return VFW_E_NOT_STOPPED; + } + + return DisconnectInternal(); +} + +STDMETHODIMP +CBasePin::DisconnectInternal() +{ + ASSERT(CritCheckIn(m_pLock)); + + if (m_Connected) { + HRESULT hr = BreakConnect(); + if( FAILED( hr ) ) { + + + // There is usually a bug in the program if BreakConnect() fails. + DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); + return hr; + } + + m_Connected->Release(); + m_Connected = NULL; + + + return S_OK; + } else { + // no connection - not an error + + + return S_FALSE; + } +} + + +/* Return an AddRef()'d pointer to the connected pin if there is one */ +STDMETHODIMP +CBasePin::ConnectedTo( + IPin **ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // + // It's pointless to lock here. + // The caller should ensure integrity. + // + + IPin *pPin = m_Connected; + *ppPin = pPin; + if (pPin != NULL) { + pPin->AddRef(); + return S_OK; + } else { + ASSERT(*ppPin == NULL); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return the media type of the connection */ +STDMETHODIMP +CBasePin::ConnectionMediaType( + AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Copy constructor of m_mt allocates the memory */ + if (IsConnected()) { + CopyMediaType( pmt, &m_mt ); + return S_OK; + } else { + ((CMediaType *)pmt)->InitMediaType(); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return information about the filter we are connect to */ + +STDMETHODIMP +CBasePin::QueryPinInfo( + PIN_INFO * pInfo +) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); + + pInfo->pFilter = m_pFilter; + if (m_pFilter) { + m_pFilter->AddRef(); + } + + if (m_pName) { + lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); + } else { + pInfo->achName[0] = L'\0'; + } + + pInfo->dir = m_dir; + + return NOERROR; +} + +STDMETHODIMP +CBasePin::QueryDirection( + PIN_DIRECTION * pPinDir +) +{ + CheckPointer(pPinDir,E_POINTER); + ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); + + *pPinDir = m_dir; + return NOERROR; +} + +// Default QueryId to return the pin's name +STDMETHODIMP +CBasePin::QueryId( + LPWSTR * Id +) +{ + // We're not going away because someone's got a pointer to us + // so there's no need to lock + + return AMGetWideString(Name(), Id); +} + +/* Does this pin support this media type WARNING this interface function does + not lock the main object as it is meant to be asynchronous by nature - if + the media types you support depend on some internal state that is updated + dynamically then you will need to implement locking in a derived class */ + +STDMETHODIMP +CBasePin::QueryAccept( + const AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + + /* The CheckMediaType method is valid to return error codes if the media + type is horrible, an example might be E_INVALIDARG. What we do here + is map all the error codes into either S_OK or S_FALSE regardless */ + + HRESULT hr = CheckMediaType((CMediaType*)pmt); + if (FAILED(hr)) { + return S_FALSE; + } + // note that the only defined success codes should be S_OK and S_FALSE... + return hr; +} + + +/* This can be called to return an enumerator for the pin's list of preferred + media types. An input pin is not obliged to have any preferred formats + although it can do. For example, the window renderer has a preferred type + which describes a video image that matches the current window size. All + output pins should expose at least one preferred format otherwise it is + possible that neither pin has any types and so no connection is possible */ + +STDMETHODIMP +CBasePin::EnumMediaTypes( + IEnumMediaTypes **ppEnum +) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumMediaTypes(this, + NULL); + + if (*ppEnum == NULL) { + return E_OUTOFMEMORY; + } + + return NOERROR; +} + + + +/* This is a virtual function that returns a media type corresponding with + place iPosition in the list. This base class simply returns an error as + we support no media types by default but derived classes should override */ + +HRESULT CBasePin::GetMediaType(int iPosition, CMediaType *pMediaType) +{ + UNREFERENCED_PARAMETER(iPosition); + UNREFERENCED_PARAMETER(pMediaType); + return E_UNEXPECTED; +} + + +/* This is a virtual function that returns the current media type version. + The base class initialises the media type enumerators with the value 1 + By default we always returns that same value. A Derived class may change + the list of media types available and after doing so it should increment + the version either in a method derived from this, or more simply by just + incrementing the m_TypeVersion base pin variable. The type enumerators + call this when they want to see if their enumerations are out of date */ + +LONG CBasePin::GetMediaTypeVersion() +{ + return m_TypeVersion; +} + + +/* Increment the cookie representing the current media type version */ + +void CBasePin::IncrementTypeVersion() +{ + InterlockedIncrement(&m_TypeVersion); +} + + +/* Called by IMediaFilter implementation when the state changes from Stopped + to either paused or running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Active(void) +{ + return NOERROR; +} + +/* Called by IMediaFilter implementation when the state changes from + to either paused to running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + return NOERROR; +} + + +/* Also called by the IMediaFilter implementation when the state changes to + Stopped at which point you should decommit allocators and free hardware + resources you grabbed in the Active call (default is also to do nothing) */ + +HRESULT +CBasePin::Inactive(void) +{ + m_bRunTimeError = FALSE; + return NOERROR; +} + + +// Called when no more data will arrive +STDMETHODIMP +CBasePin::EndOfStream(void) +{ + return S_OK; +} + + +STDMETHODIMP +CBasePin::SetSink(IQualityControl * piqc) +{ + CAutoLock cObjectLock(m_pLock); + if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); + m_pQSink = piqc; + return NOERROR; +} // SetSink + + +STDMETHODIMP +CBasePin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + UNREFERENCED_PARAMETER(pSender); + DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); + return E_NOTIMPL; +} //Notify + + +// NewSegment notifies of the start/stop/rate applying to the data +// about to be received. Default implementation records data and +// returns S_OK. +// Override this to pass downstream. +STDMETHODIMP +CBasePin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + m_tStart = tStart; + m_tStop = tStop; + m_dRate = dRate; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseOutputPin +//===================================================================== +//===================================================================== + + +CBaseOutputPin::CBaseOutputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} + +#ifdef UNICODE +CBaseOutputPin::CBaseOutputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} +#endif + +/* This is called after a media type has been proposed + + Try to complete the connection by agreeing the allocator +*/ +HRESULT +CBaseOutputPin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return DecideAllocator(m_pInputPin, &m_pAllocator); +} + + +/* This method is called when the output pin is about to try and connect to + an input pin. It is at this point that you should try and grab any extra + interfaces that you need, in this case IMemInputPin. Because this is + only called if we are not currently connected we do NOT need to call + BreakConnect. This also makes it easier to derive classes from us as + BreakConnect is only called when we actually have to break a connection + (or a partly made connection) and not when we are checking a connection */ + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::CheckConnect(IPin * pPin) +{ + HRESULT hr = CBasePin::CheckConnect(pPin); + if (FAILED(hr)) { + return hr; + } + + // get an input pin and an allocator interface + hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); + if (FAILED(hr)) { + return hr; + } + return NOERROR; +} + + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::BreakConnect() +{ + /* Release any allocator we hold */ + + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a connection is broken. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + /* Release any input pin interface we hold */ + + if (m_pInputPin) { + m_pInputPin->Release(); + m_pInputPin = NULL; + } + return NOERROR; +} + + +/* This is called when the input pin didn't give us a valid allocator */ + +HRESULT +CBaseOutputPin::InitAllocator(IMemAllocator **ppAlloc) +{ + return CreateMemoryAllocator(ppAlloc); +} + + +/* Decide on an allocator, override this if you want to use your own allocator + Override DecideBufferSize to call SetProperties. If the input pin fails + the GetAllocator call then this will construct a CMemAllocator and call + DecideBufferSize on that, and if that fails then we are completely hosed. + If the you succeed the DecideBufferSize call, we will notify the input + pin of the selected allocator. NOTE this is called during Connect() which + therefore looks after grabbing and locking the object's critical section */ + +// We query the input pin for its requested properties and pass this to +// DecideBufferSize to allow it to fulfill requests that it is happy +// with (eg most people don't care about alignment and are thus happy to +// use the downstream pin's alignment request). + +HRESULT +CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc) +{ + HRESULT hr = NOERROR; + *ppAlloc = NULL; + + // get downstream prop request + // the derived class may modify this in DecideBufferSize, but + // we assume that he will consistently modify it the same way, + // so we only get it once + ALLOCATOR_PROPERTIES prop; + ZeroMemory(&prop, sizeof(prop)); + + // whatever he returns, we assume prop is either all zeros + // or he has filled it out. + pPin->GetAllocatorRequirements(&prop); + + // if he doesn't care about alignment, then set it to 1 + if (prop.cbAlign == 0) { + prop.cbAlign = 1; + } + + /* Try the allocator provided by the input pin */ + + hr = pPin->GetAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* If the GetAllocator failed we may not have an interface */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + + /* Try the output pin's allocator by the same method */ + + hr = InitAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + // note - the properties passed here are in the same + // structure as above and may have been modified by + // the previous call to DecideBufferSize + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* Likewise we may not have an interface to release */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + return hr; +} + + +/* This returns an empty sample buffer from the allocator WARNING the same + dangers and restrictions apply here as described below for Deliver() */ + +HRESULT +CBaseOutputPin::GetDeliveryBuffer(IMediaSample ** ppSample, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags) +{ + if (m_pAllocator != NULL) { + return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); + } else { + return E_NOINTERFACE; + } +} + + +/* Deliver a filled-in sample to the connected input pin. NOTE the object must + have locked itself before calling us otherwise we may get halfway through + executing this method only to find the filter graph has got in and + disconnected us from the input pin. If the filter has no worker threads + then the lock is best applied on Receive(), otherwise it should be done + when the worker thread is ready to deliver. There is a wee snag to worker + threads that this shows up. The worker thread must lock the object when + it is ready to deliver a sample, but it may have to wait until a state + change has completed, but that may never complete because the state change + is waiting for the worker thread to complete. The way to handle this is for + the state change code to grab the critical section, then set an abort event + for the worker thread, then release the critical section and wait for the + worker thread to see the event we set and then signal that it has finished + (with another event). At which point the state change code can complete */ + +// note (if you've still got any breath left after reading that) that you +// need to release the sample yourself after this call. if the connected +// input pin needs to hold onto the sample beyond the call, it will addref +// the sample itself. + +// of course you must release this one and call GetDeliveryBuffer for the +// next. You cannot reuse it directly. + +HRESULT +CBaseOutputPin::Deliver(IMediaSample * pSample) +{ + if (m_pInputPin == NULL) { + return VFW_E_NOT_CONNECTED; + } + + + return m_pInputPin->Receive(pSample); +} + + +// called from elsewhere in our filter to pass EOS downstream to +// our connected input pin +HRESULT +CBaseOutputPin::DeliverEndOfStream(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndOfStream(); +} + + +/* Commit the allocator's memory, this is called through IMediaFilter + which is responsible for locking the object before calling us */ + +HRESULT +CBaseOutputPin::Active(void) +{ + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Commit(); +} + + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseOutputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Decommit(); +} + +// we have a default handling of EndOfStream which is to return +// an error, since this should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndOfStream(void) +{ + return E_UNEXPECTED; +} + + +// BeginFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::BeginFlush(void) +{ + return E_UNEXPECTED; +} + +// EndFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndFlush(void) +{ + return E_UNEXPECTED; +} + +// call BeginFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverBeginFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->BeginFlush(); +} + +// call EndFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverEndFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndFlush(); +} +// deliver NewSegment to connected pin +HRESULT +CBaseOutputPin::DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->NewSegment(tStart, tStop, dRate); +} + + +//===================================================================== +//===================================================================== +// Implements CBaseInputPin +//===================================================================== +//===================================================================== + + +/* Constructor creates a default allocator object */ + +CBaseInputPin::CBaseInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} + +#ifdef UNICODE +CBaseInputPin::CBaseInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} +#endif + +/* Destructor releases it's reference count on the default allocator */ + +CBaseInputPin::~CBaseInputPin() +{ + if (m_pAllocator != NULL) { + m_pAllocator->Release(); + m_pAllocator = NULL; + } +} + + +// override this to publicise our interfaces +STDMETHODIMP +CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemInputPin) { + return GetInterface((IMemInputPin *) this, ppv); + } else { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Return the allocator interface that this input pin would like the output + pin to use. NOTE subsequent calls to GetAllocator should all return an + interface onto the SAME object so we create one object at the start + + Note: + The allocator is Release()'d on disconnect and replaced on + NotifyAllocator(). + + Override this to provide your own allocator. +*/ + +STDMETHODIMP +CBaseInputPin::GetAllocator( + IMemAllocator **ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pAllocator == NULL) { + HRESULT hr = CreateMemoryAllocator(&m_pAllocator); + if (FAILED(hr)) { + return hr; + } + } + ASSERT(m_pAllocator != NULL); + *ppAllocator = m_pAllocator; + m_pAllocator->AddRef(); + return NOERROR; +} + + +/* Tell the input pin which allocator the output pin is actually going to use + Override this if you care - NOTE the locking we do both here and also in + GetAllocator is unnecessary but derived classes that do something useful + will undoubtedly have to lock the object so this might help remind people */ + +STDMETHODIMP +CBaseInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + CAutoLock cObjectLock(m_pLock); + + IMemAllocator *pOldAllocator = m_pAllocator; + pAllocator->AddRef(); + m_pAllocator = pAllocator; + + if (pOldAllocator != NULL) { + pOldAllocator->Release(); + } + + // the readonly flag indicates whether samples from this allocator should + // be regarded as readonly - if true, then inplace transforms will not be + // allowed. + m_bReadOnly = (BYTE)bReadOnly; + return NOERROR; +} + + +HRESULT +CBaseInputPin::BreakConnect() +{ + /* We don't need our allocator any more */ + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a pin is disconnected. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + return S_OK; +} + + +/* Do something with this media sample - this base class checks to see if the + format has changed with this media sample and if so checks that the filter + will accept it, generating a run time error if not. Once we have raised a + run time error we set a flag so that no more samples will be accepted + + It is important that any filter should override this method and implement + synchronization so that samples are not processed when the pin is + disconnected etc +*/ + +STDMETHODIMP +CBaseInputPin::Receive(IMediaSample *pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + ASSERT(pSample); + + HRESULT hr = CheckStreaming(); + if (S_OK != hr) { + return hr; + } + + + + /* Check for IMediaSample2 */ + IMediaSample2 *pSample2; + if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); + pSample2->Release(); + if (FAILED(hr)) { + return hr; + } + } else { + /* Get the properties the hard way */ + m_SampleProps.cbData = sizeof(m_SampleProps); + m_SampleProps.dwTypeSpecificFlags = 0; + m_SampleProps.dwStreamId = AM_STREAM_MEDIA; + m_SampleProps.dwSampleFlags = 0; + if (S_OK == pSample->IsDiscontinuity()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + } + if (S_OK == pSample->IsPreroll()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; + } + if (S_OK == pSample->IsSyncPoint()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, + &m_SampleProps.tStop))) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | + AM_SAMPLE_STOPVALID; + } + if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; + } + pSample->GetPointer(&m_SampleProps.pbBuffer); + m_SampleProps.lActual = pSample->GetActualDataLength(); + m_SampleProps.cbBuffer = pSample->GetSize(); + } + + /* Has the format changed in this sample */ + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { + return NOERROR; + } + + /* Check the derived class accepts this format */ + /* This shouldn't fail as the source must call QueryAccept first */ + + hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); + + if (hr == NOERROR) { + return NOERROR; + } + + /* Raise a runtime error if we fail the media type */ + + m_bRunTimeError = TRUE; + EndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); + return VFW_E_INVALIDMEDIATYPE; +} + + +/* Receive multiple samples */ +STDMETHODIMP +CBaseInputPin::ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed) +{ + CheckPointer(pSamples,E_POINTER); + ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); + + HRESULT hr = S_OK; + *nSamplesProcessed = 0; + while (nSamples-- > 0) { + hr = Receive(pSamples[*nSamplesProcessed]); + + /* S_FALSE means don't send any more */ + if (hr != S_OK) { + break; + } + (*nSamplesProcessed)++; + } + return hr; +} + +/* See if Receive() might block */ +STDMETHODIMP +CBaseInputPin::ReceiveCanBlock() +{ + /* Ask all the output pins if they block + If there are no output pin assume we do block + */ + int cPins = m_pFilter->GetPinCount(); + int cOutputPins = 0; + for (int c = 0; c < cPins; c++) { + CBasePin *pPin = m_pFilter->GetPin(c); + PIN_DIRECTION pd; + HRESULT hr = pPin->QueryDirection(&pd); + if (FAILED(hr)) { + return hr; + } + + if (pd == PINDIR_OUTPUT) { + + IPin *pConnected; + hr = pPin->ConnectedTo(&pConnected); + if (SUCCEEDED(hr)) { + ASSERT(pConnected != NULL); + cOutputPins++; + IMemInputPin *pInputPin; + hr = pConnected->QueryInterface( + IID_IMemInputPin, + (void **)&pInputPin); + pConnected->Release(); + if (SUCCEEDED(hr)) { + hr = pInputPin->ReceiveCanBlock(); + pInputPin->Release(); + if (hr != S_FALSE) { + return S_OK; + } + } else { + /* There's a transport we don't understand here */ + return S_OK; + } + } + } + } + return cOutputPins == 0 ? S_OK : S_FALSE; +} + +// Default handling for BeginFlush - call at the beginning +// of your implementation (makes sure that all Receive calls +// fail). After calling this, you need to free any queued data +// and then call downstream. +STDMETHODIMP +CBaseInputPin::BeginFlush(void) +{ + // BeginFlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // if we are already in mid-flush, this is probably a mistake + // though not harmful - try to pick it up for now so I can think about it + ASSERT(!m_bFlushing); + + // first thing to do is ensure that no further Receive calls succeed + m_bFlushing = TRUE; + + // now discard any data and call downstream - must do that + // in derived classes + return S_OK; +} + +// default handling for EndFlush - call at end of your implementation +// - before calling this, ensure that there is no queued data and no thread +// pushing any more without a further receive, then call downstream, +// then call this method to clear the m_bFlushing flag and re-enable +// receives +STDMETHODIMP +CBaseInputPin::EndFlush(void) +{ + // Endlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // almost certainly a mistake if we are not in mid-flush + ASSERT(m_bFlushing); + + // before calling, sync with pushing thread and ensure + // no more data is going downstream, then call EndFlush on + // downstream pins. + + // now re-enable Receives + m_bFlushing = FALSE; + + // No more errors + m_bRunTimeError = FALSE; + + return S_OK; +} + + +STDMETHODIMP +CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + CheckPointer(pSender,E_POINTER); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + DbgBreak("IQuality::Notify called on an input pin"); + return NOERROR; +} // Notify + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseInputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + + m_bFlushing = FALSE; + + return m_pAllocator->Decommit(); +} + +// what requirements do we have of the allocator - override if you want +// to support other people's allocators but need a specific alignment +// or prefix. +STDMETHODIMP +CBaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps) +{ + UNREFERENCED_PARAMETER(pProps); + return E_NOTIMPL; +} + +// Check if it's OK to process data +// +HRESULT +CBaseInputPin::CheckStreaming() +{ + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bFlushing) { + return S_FALSE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; +} + +// Pass on the Quality notification q to +// a. Our QualityControl sink (if we have one) or else +// b. to our upstream filter +// and if that doesn't work, throw it away with a bad return code +HRESULT +CBaseInputPin::PassNotify(Quality& q) +{ + // We pass the message on, which means that we find the quality sink + // for our input pin and send it there + + DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); + if (m_pQSink!=NULL) { + return m_pQSink->Notify(m_pFilter, q); + } else { + // no sink set, so pass it upstream + HRESULT hr; + IQualityControl * pIQC; + + hr = VFW_E_NOT_FOUND; // default + if (m_Connected) { + m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); + + if (pIQC!=NULL) { + hr = pIQC->Notify(m_pFilter, q); + pIQC->Release(); + } + } + return hr; + } + +} // PassNotify + +//===================================================================== +//===================================================================== +// Memory allocation class, implements CMediaSample +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants it's lifetime controlled by the external object */ + +/* The last two parameters have default values of NULL and zero */ + +CMediaSample::CMediaSample(TCHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator) // Allocator +{ + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} + +#ifdef UNICODE +CMediaSample::CMediaSample(CHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator) // Allocator +{ + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} +#endif + +/* Destructor deletes the media type memory */ + +CMediaSample::~CMediaSample() +{ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + } +} + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CMediaSample::QueryInterface(REFIID riid, void **ppv) +{ + if (riid == IID_IMediaSample || + riid == IID_IMediaSample2 || + riid == IID_IUnknown) { + return GetInterface((IMediaSample *) this, ppv); + } else { + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CMediaSample::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + + +// -- CMediaSample lifetimes -- +// +// On final release of this sample buffer it is not deleted but +// returned to the freelist of the owning memory allocator +// +// The allocator may be waiting for the last buffer to be placed on the free +// list in order to decommit all the memory, so the ReleaseBuffer() call may +// result in this sample being deleted. We also need to hold a refcount on +// the allocator to stop that going away until we have finished with this. +// However, we cannot release the allocator before the ReleaseBuffer, as the +// release may cause us to be deleted. Similarly we can't do it afterwards. +// +// Thus we must leave it to the allocator to hold an addref on our behalf. +// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer +// is called, he releases himself, possibly causing us and him to be deleted. + + +STDMETHODIMP_(ULONG) +CMediaSample::Release() +{ + /* Decrement our own private reference count */ + LONG lRef; + if (m_cRef == 1) { + lRef = 0; + m_cRef = 0; + } else { + lRef = InterlockedDecrement(&m_cRef); + } + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), + this, m_cRef)); + + /* Did we release our final reference count */ + if (lRef == 0) { + /* Free all resources */ + if (m_dwFlags & Sample_TypeChanged) { + SetMediaType(NULL); + } + ASSERT(m_pMediaType == NULL); + m_dwFlags = 0; + m_dwTypeSpecificFlags = 0; + m_dwStreamId = AM_STREAM_MEDIA; + + /* This may cause us to be deleted */ + // Our refcount is reliably 0 thus no-one will mess with us + m_pAllocator->ReleaseBuffer(this); + } + return (ULONG)lRef; +} + + +// set the buffer pointer and length. Used by allocators that +// want variable sized pointers or pointers into already-read data. +// This is only available through a CMediaSample* not an IMediaSample* +// and so cannot be changed by clients. +HRESULT +CMediaSample::SetPointer(BYTE * ptr, LONG cBytes) +{ + m_pBuffer = ptr; // new buffer area (could be null) + m_cbBuffer = cBytes; // length of buffer + m_lActual = cBytes; // length of data in buffer (assume full) + + return S_OK; +} + + +// get me a read/write pointer to this buffer's memory. I will actually +// want to use sizeUsed bytes. +STDMETHODIMP +CMediaSample::GetPointer(BYTE ** ppBuffer) +{ + ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); + + // creator must have set pointer either during + // constructor or by SetPointer + ASSERT(m_pBuffer); + + *ppBuffer = m_pBuffer; + return NOERROR; +} + + +// return the size in bytes of this buffer +STDMETHODIMP_(LONG) +CMediaSample::GetSize(void) +{ + return m_cbBuffer; +} + + +// get the stream time at which this sample should start and finish. +STDMETHODIMP +CMediaSample::GetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); + + if (!(m_dwFlags & Sample_StopValid)) { + if (!(m_dwFlags & Sample_TimeValid)) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + *pTimeStart = m_Start; + + // Make sure old stuff works + *pTimeEnd = m_Start + 1; + return VFW_S_NO_STOP_TIME; + } + } + + *pTimeStart = m_Start; + *pTimeEnd = m_End; + return NOERROR; +} + + +// Set the stream time at which this sample should start and finish. +// NULL pointers means the time is reset +STDMETHODIMP +CMediaSample::SetTime( + REFERENCE_TIME * pTimeStart, + REFERENCE_TIME * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); + } else { + if (pTimeEnd == NULL) { + m_Start = *pTimeStart; + m_dwFlags |= Sample_TimeValid; + m_dwFlags &= ~Sample_StopValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_Start = *pTimeStart; + m_End = *pTimeEnd; + m_dwFlags |= Sample_TimeValid | Sample_StopValid; + } + } + return NOERROR; +} + + +// get the media times (eg bytes) for this sample +STDMETHODIMP +CMediaSample::GetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); + + if (!(m_dwFlags & Sample_MediaTimeValid)) { + return VFW_E_MEDIA_TIME_NOT_SET; + } + + *pTimeStart = m_MediaStart; + *pTimeEnd = (m_MediaStart + m_MediaEnd); + return NOERROR; +} + + +// Set the media times for this sample +STDMETHODIMP +CMediaSample::SetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~Sample_MediaTimeValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_MediaStart = *pTimeStart; + m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); + m_dwFlags |= Sample_MediaTimeValid; + } + return NOERROR; +} + + +STDMETHODIMP +CMediaSample::IsSyncPoint(void) +{ + if (m_dwFlags & Sample_SyncPoint) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) +{ + if (bIsSyncPoint) { + m_dwFlags |= Sample_SyncPoint; + } else { + m_dwFlags &= ~Sample_SyncPoint; + } + return NOERROR; +} + +// returns S_OK if there is a discontinuity in the data (this same is +// not a continuation of the previous stream of data +// - there has been a seek). +STDMETHODIMP +CMediaSample::IsDiscontinuity(void) +{ + if (m_dwFlags & Sample_Discontinuity) { + return S_OK; + } else { + return S_FALSE; + } +} + +// set the discontinuity property - TRUE if this sample is not a +// continuation, but a new sample after a seek. +STDMETHODIMP +CMediaSample::SetDiscontinuity(BOOL bDiscont) +{ + // should be TRUE or FALSE + if (bDiscont) { + m_dwFlags |= Sample_Discontinuity; + } else { + m_dwFlags &= ~Sample_Discontinuity; + } + return S_OK; +} + +STDMETHODIMP +CMediaSample::IsPreroll(void) +{ + if (m_dwFlags & Sample_Preroll) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetPreroll(BOOL bIsPreroll) +{ + if (bIsPreroll) { + m_dwFlags |= Sample_Preroll; + } else { + m_dwFlags &= ~Sample_Preroll; + } + return NOERROR; +} + +STDMETHODIMP_(LONG) +CMediaSample::GetActualDataLength(void) +{ + return m_lActual; +} + + +STDMETHODIMP +CMediaSample::SetActualDataLength(LONG lActual) +{ + if (lActual > m_cbBuffer) { + ASSERT(lActual <= GetSize()); + return VFW_E_BUFFER_OVERFLOW; + } + m_lActual = lActual; + return NOERROR; +} + + +/* These allow for limited format changes in band */ + +STDMETHODIMP +CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType) +{ + ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); + ASSERT(ppMediaType); + + /* Do we have a new media type for them */ + + if (!(m_dwFlags & Sample_TypeChanged)) { + ASSERT(m_pMediaType == NULL); + *ppMediaType = NULL; + return S_FALSE; + } + + ASSERT(m_pMediaType); + + /* Create a copy of our media type */ + + *ppMediaType = CreateMediaType(m_pMediaType); + if (*ppMediaType == NULL) { + return E_OUTOFMEMORY; + } + return NOERROR; +} + + +/* Mark this sample as having a different format type */ + +STDMETHODIMP +CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType) +{ + /* Delete the current media type */ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + m_pMediaType = NULL; + } + + /* Mechanism for resetting the format type */ + + if (pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return NOERROR; + } + + ASSERT(pMediaType); + ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); + + /* Take a copy of the media type */ + + m_pMediaType = CreateMediaType(pMediaType); + if (m_pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return E_OUTOFMEMORY; + } + + m_dwFlags |= Sample_TypeChanged; + return NOERROR; +} + +// Set and get properties (IMediaSample2) +STDMETHODIMP CMediaSample::GetProperties( + DWORD cbProperties, + BYTE * pbProperties +) +{ + if (0 != cbProperties) { + CheckPointer(pbProperties, E_POINTER); + // Return generic stuff up to the length + AM_SAMPLE2_PROPERTIES Props; + Props.cbData = (DWORD) (min(cbProperties, sizeof(Props))); + Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; + Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; + Props.pbBuffer = m_pBuffer; + Props.cbBuffer = m_cbBuffer; + Props.lActual = m_lActual; + Props.tStart = m_Start; + Props.tStop = m_End; + Props.dwStreamId = m_dwStreamId; + if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { + Props.pMediaType = m_pMediaType; + } else { + Props.pMediaType = NULL; + } + CopyMemory(pbProperties, &Props, Props.cbData); + } + return S_OK; +} + +#define CONTAINS_FIELD(type, field, offset) \ + ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) + +HRESULT CMediaSample::SetProperties( + DWORD cbProperties, + const BYTE * pbProperties +) +{ + + /* Generic properties */ + AM_MEDIA_TYPE *pMediaType = NULL; + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { + CheckPointer(pbProperties, E_POINTER); + AM_SAMPLE2_PROPERTIES *pProps = + (AM_SAMPLE2_PROPERTIES *)pbProperties; + + /* Don't use more data than is actually there */ + if (pProps->cbData < cbProperties) { + cbProperties = pProps->cbData; + } + /* We only handle IMediaSample2 */ + if (cbProperties > sizeof(*pProps) || + pProps->cbData > sizeof(*pProps)) { + return E_INVALIDARG; + } + /* Do checks first, the assignments (for backout) */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Check the flags */ + if (pProps->dwSampleFlags & + (~Sample_ValidFlags | Sample_MediaTimeValid)) { + return E_INVALIDARG; + } + /* Check a flag isn't being set for a property + not being provided + */ + if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && + !(m_dwFlags & AM_SAMPLE_TIMEVALID) && + !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + return E_INVALIDARG; + } + } + /* NB - can't SET the pointer or size */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { + + /* Check pbBuffer */ + if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { + + /* Check cbBuffer */ + if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && + CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + + /* Check lActual */ + if (pProps->cbBuffer < pProps->lActual) { + return E_INVALIDARG; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + + /* Check pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + CheckPointer(pProps->pMediaType, E_POINTER); + pMediaType = CreateMediaType(pProps->pMediaType); + if (pMediaType == NULL) { + return E_OUTOFMEMORY; + } + } + } + + /* Now do the assignments */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { + m_dwStreamId = pProps->dwStreamId; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Set the flags */ + m_dwFlags = pProps->dwSampleFlags | + (m_dwFlags & Sample_MediaTimeValid); + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } else { + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + /* Set lActual */ + m_lActual = pProps->lActual; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + + /* Set the times */ + m_End = pProps->tStop; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { + + /* Set the times */ + m_Start = pProps->tStart; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + /* Set pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + if (m_pMediaType != NULL) { + DeleteMediaType(m_pMediaType); + } + m_pMediaType = pMediaType; + } + } + + /* Fix up the type changed flag to correctly reflect the current state + If, for instance the input contained no type change but the + output does then if we don't do this we'd lose the + output media type. + */ + if (m_pMediaType) { + m_dwFlags |= Sample_TypeChanged; + } else { + m_dwFlags &= ~Sample_TypeChanged; + } + } + + return S_OK; +} + + +// +// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), +// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the +// connected input pin. The application thread calls Block(). The +// following class members can only be called by the streaming thread. +// +// Deliver() +// DeliverNewSegment() +// StartUsingOutputPin() +// StopUsingOutputPin() +// ChangeOutputFormat() +// ChangeMediaType() +// DynamicReconnect() +// +// The following class members can only be called by the application thread. +// +// Block() +// SynchronousBlockOutputPin() +// AsynchronousBlockOutputPin() +// + +CDynamicOutputPin::CDynamicOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} + +#ifdef UNICODE +CDynamicOutputPin::CDynamicOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} +#endif + +CDynamicOutputPin::~CDynamicOutputPin() +{ + if(NULL != m_hUnblockOutputPinEvent) { + // This call should not fail because we have access to m_hUnblockOutputPinEvent + // and m_hUnblockOutputPinEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); + } + + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent + // and m_hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } +} + +HRESULT CDynamicOutputPin::Initialize(void) +{ + m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. + TRUE, // This is a manual reset event. + TRUE, // The event is initially signaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == m_hUnblockOutputPinEvent) { + return AmGetLastErrorToHResult(); + } + + // Set flag to say we can reconnect while streaming. + SetReconnectWhenActive(true); + + return S_OK; +} + +STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if(riid == IID_IPinFlowControl) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + +STDMETHODIMP CDynamicOutputPin::Disconnect(void) +{ + CAutoLock cObjectLock(m_pLock); + return DisconnectInternal(); +} + +STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) +{ + const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; + + // Check for illegal flags. + if(dwBlockFlags & ~VALID_FLAGS) { + return E_INVALIDARG; + } + + // Make sure the event is unsignaled. + if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { + if( !::ResetEvent( hEvent ) ) { + return AmGetLastErrorToHResult(); + } + } + + // No flags are set if we are unblocking the output pin. + if(0 == dwBlockFlags) { + + // This parameter should be NULL because unblock operations are always synchronous. + // There is no need to notify the caller when the event is done. + if(NULL != hEvent) { + return E_INVALIDARG; + } + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + HRESULT hr; + + if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { + // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. + // If hEvent is not NULL, the block is asynchronous. + if(NULL == hEvent) { + hr = SynchronousBlockOutputPin(); + } else { + hr = AsynchronousBlockOutputPin(hEvent); + } + } else { + hr = UnblockOutputPin(); + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) +{ + HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. + FALSE, // This is an automatic reset event. + FALSE, // The event is initially unsignaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == hNotifyCallerPinBlockedEvent) { + return AmGetLastErrorToHResult(); + } + + HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); + if(FAILED(hr)) { + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + return hr; + } + + hr = WaitEvent(hNotifyCallerPinBlockedEvent); + + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) +{ + // This function holds the m_BlockStateLock because it uses + // m_dwBlockCallerThreadID, m_BlockState and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED != m_BlockState) { + if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { + return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; + } else { + return VFW_E_PIN_ALREADY_BLOCKED; + } + } + + BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), + hNotifyCallerPinBlockedEvent, + ::GetCurrentProcess(), + &m_hNotifyCallerPinBlockedEvent, + EVENT_MODIFY_STATE, + FALSE, + 0 ); + if( !fSuccess ) { + return AmGetLastErrorToHResult(); + } + + m_BlockState = PENDING; + m_dwBlockCallerThreadID = ::GetCurrentThreadId(); + + // The output pin cannot be blocked if the streaming thread is + // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() + // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it + // cannot be blocked if the streaming thread is calling DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). + if(!StreamingThreadUsingOutputPin()) { + + // The output pin can be immediately blocked. + BlockOutputPin(); + } + + return S_OK; +} + +void CDynamicOutputPin::BlockOutputPin(void) +{ + // The caller should always hold the m_BlockStateLock because this function + // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. + ASSERT(CritCheckIn(&m_BlockStateLock)); + + // This function should not be called if the streaming thread is modifying + // the connection state or it's passing data downstream. + ASSERT(!StreamingThreadUsingOutputPin()); + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); + + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + + m_BlockState = BLOCKED; + m_hNotifyCallerPinBlockedEvent = NULL; +} + +HRESULT CDynamicOutputPin::UnblockOutputPin(void) +{ + // UnblockOutputPin() holds the m_BlockStateLock because it + // uses m_BlockState, m_dwBlockCallerThreadID and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED == m_BlockState) { + return S_FALSE; + } + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); + + // Cancel the block operation if it's still pending. + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } + + m_BlockState = NOT_BLOCKED; + m_dwBlockCallerThreadID = 0; + m_hNotifyCallerPinBlockedEvent = NULL; + + return S_OK; +} + +HRESULT CDynamicOutputPin::StartUsingOutputPin(void) +{ + // The caller should not hold m_BlockStateLock. If the caller does, + // a deadlock could occur. + ASSERT(CritCheckOut(&m_BlockStateLock)); + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + // Are we in the middle of a block operation? + while(BLOCKED == m_BlockState) { + m_BlockStateLock.Unlock(); + + // If this ASSERT fires, a deadlock could occur. The caller should make sure + // that this thread never acquires the Block State lock more than once. + ASSERT(CritCheckOut( &m_BlockStateLock )); + + // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event + // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. + // See the Windows SDK documentation for more information on + // WaitForMultipleObjects(). + const DWORD UNBLOCK = WAIT_OBJECT_0; + const DWORD STOP = WAIT_OBJECT_0 + 1; + + HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; + DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); + + DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); + + m_BlockStateLock.Lock(); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + switch( dwReturnValue ) { + case UNBLOCK: + break; + + case STOP: + return VFW_E_STATE_CHANGED; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); + return E_UNEXPECTED; + } + } + + m_dwNumOutstandingOutputPinUsers++; + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + return S_OK; +} + +void CDynamicOutputPin::StopUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + m_dwNumOutstandingOutputPinUsers--; + + if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { + BlockOutputPin(); + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG +} + +bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + return (m_dwNumOutstandingOutputPinUsers > 0); +} + +void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) +{ + // This pointer is not addrefed because filters are not allowed to + // hold references to the filter graph manager. See the documentation for + // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. + m_pGraphConfig = pGraphConfig; + + m_hStopEvent = hStopEvent; +} + +HRESULT CDynamicOutputPin::Active(void) +{ + // Make sure the user initialized the object by calling SetConfigInfo(). + if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { + DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); + return E_FAIL; + } + + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::Active(); +} + +HRESULT CDynamicOutputPin::Inactive(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::Inactive(); +} + +HRESULT CDynamicOutputPin::DeliverBeginFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverBeginFlush(); +} + +HRESULT CDynamicOutputPin::DeliverEndFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverEndFlush(); +} + + +// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly +// reconnects the output pin. +HRESULT CDynamicOutputPin::ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // Callers should always pass a valid media type to ChangeOutputFormat() . + ASSERT(NULL != pmt); + + CMediaType cmt(*pmt); + HRESULT hr = ChangeMediaType(&cmt); + if (FAILED(hr)) { + return hr; + } + + hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); + if( FAILED( hr ) ) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // This function assumes the filter graph is running. + ASSERT(!IsStopped()); + + if(!IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + /* First check if the downstream pin will accept a dynamic + format change + */ + QzCComPtr pConnection; + + m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); + if(pConnection != NULL) { + + if(S_OK == pConnection->DynamicQueryAccept(pmt)) { + + HRESULT hr = ChangeMediaTypeHelper(pmt); + if(FAILED(hr)) { + return hr; + } + + return S_OK; + } + } + + /* Can't do the dynamic connection */ + return DynamicReconnect(pmt); +} + +HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + HRESULT hr = m_Connected->ReceiveConnection(this, pmt); + if(FAILED(hr)) { + return hr; + } + + hr = SetMediaType(pmt); + if(FAILED(hr)) { + return hr; + } + + // Does this pin use the local memory transport? + if(NULL != m_pInputPin) { + // This function assumes that m_pInputPin and m_Connected are + // two different interfaces to the same object. + ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); + + ALLOCATOR_PROPERTIES apInputPinRequirements; + apInputPinRequirements.cbAlign = 0; + apInputPinRequirements.cbBuffer = 0; + apInputPinRequirements.cbPrefix = 0; + apInputPinRequirements.cBuffers = 0; + + m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); + + // A zero allignment does not make any sense. + if(0 == apInputPinRequirements.cbAlign) { + apInputPinRequirements.cbAlign = 1; + } + + hr = m_pAllocator->Decommit(); + if(FAILED(hr)) { + return hr; + } + + hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); + if(FAILED(hr)) { + return hr; + } + + hr = m_pAllocator->Commit(); + if(FAILED(hr)) { + return hr; + } + + hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); + if(FAILED(hr)) { + return hr; + } + } + + return S_OK; +} + +// this method has to be called from the thread that is pushing data, +// and it's the caller's responsibility to make sure that the thread +// has no outstand samples because they cannot be delivered after a +// reconnect +// +HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { + return E_FAIL; + } + + HRESULT hr = m_pGraphConfig->Reconnect( + this, + NULL, + pmt, + NULL, + m_hStopEvent, + AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); + + return hr; +} + +HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if(SUCCEEDED(hr)) { + if(!IsStopped() && m_pAllocator) { + hr = m_pAllocator->Commit(); + ASSERT(hr != VFW_E_ALREADY_COMMITTED); + } + } + + return hr; +} + +#ifdef DEBUG +void CDynamicOutputPin::AssertValid(void) +{ + // Make sure the object was correctly initialized. + + // This ASSERT only fires if the object failed to initialize + // and the user ignored the constructor's return code (phr). + ASSERT(NULL != m_hUnblockOutputPinEvent); + + // If either of these ASSERTs fire, the user did not correctly call + // SetConfigInfo(). + ASSERT(NULL != m_hStopEvent); + ASSERT(NULL != m_pGraphConfig); + + // Make sure the block state is consistent. + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. + ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); + + // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete + // immediately. + ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || + ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); + + // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and + // the user is not trying to block the pin. + ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); + + // If this ASSERT fires, the streaming thread is using the output pin and the + // output pin is blocked. + ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); +} +#endif // DEBUG + +HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) +{ + const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; + + DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); + + switch( dwReturnValue ) { + case EVENT_SIGNALED: + return S_OK; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); + return E_UNEXPECTED; + } +} + +//===================================================================== +//===================================================================== +// Implements CBaseAllocator +//===================================================================== +//===================================================================== + + +/* Constructor overrides the default settings for the free list to request + that it be alertable (ie the list can be cast to a handle which can be + passed to WaitForSingleObject). Both of the allocator lists also ask for + object locking, the all list matches the object default settings but I + have included them here just so it is obvious what kind of list it is */ + +CBaseAllocator::CBaseAllocator(TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback + ) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} + +#ifdef UNICODE +CBaseAllocator::CBaseAllocator(CHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} +#endif + +/* Destructor */ + +CBaseAllocator::~CBaseAllocator() +{ + // we can't call Decommit here since that would mean a call to a + // pure virtual in destructor. + // We must assume that the derived class has gone into decommit state in + // its destructor. + + ASSERT(!m_bCommitted); + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + if (m_pNotify) { + m_pNotify->Release(); + } +} + + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemAllocator || + riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { + return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ + +STDMETHODIMP +CBaseAllocator::SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pRequest, E_POINTER); + CheckPointer(pActual, E_POINTER); + ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + /* Check the alignment requested */ + if (pRequest->cbAlign != 1) { + DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), + pRequest->cbAlign)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lAllocated != m_lFree.GetCount()) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + pActual->cbBuffer = m_lSize = pRequest->cbBuffer; + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::GetProperties( + ALLOCATOR_PROPERTIES * pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + + CAutoLock cObjectLock(this); + pActual->cbBuffer = m_lSize; + pActual->cBuffers = m_lCount; + pActual->cbAlign = m_lAlignment; + pActual->cbPrefix = m_lPrefix; + return NOERROR; +} + +// get container for a sample. Blocking, synchronous call to get the +// next free buffer (as represented by an IMediaSample interface). +// on return, the time etc properties will be invalid, but the buffer +// pointer and size will be correct. + +HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime, + DWORD dwFlags + ) +{ + UNREFERENCED_PARAMETER(pStartTime); + UNREFERENCED_PARAMETER(pEndTime); + UNREFERENCED_PARAMETER(dwFlags); + CMediaSample *pSample; + + *ppBuffer = NULL; + for (;;) + { + { // scope for lock + CAutoLock cObjectLock(this); + + /* Check we are committed */ + if (!m_bCommitted) { + return VFW_E_NOT_COMMITTED; + } + pSample = (CMediaSample *) m_lFree.RemoveHead(); + if (pSample == NULL) { + SetWaiting(); + } + } + + /* If we didn't get a sample then wait for the list to signal */ + + if (pSample) { + break; + } + if (dwFlags & AM_GBF_NOWAIT) { + return VFW_E_TIMEOUT; + } + ASSERT(m_hSem != NULL); + WaitForSingleObject(m_hSem, INFINITE); + } + + /* Addref the buffer up to one. On release + back to zero instead of being deleted, it will requeue itself by + calling the ReleaseBuffer member function. NOTE the owner of a + media sample must always be derived from CBaseAllocator */ + + + ASSERT(pSample->m_cRef == 0); + pSample->m_cRef = 1; + *ppBuffer = pSample; + + + return NOERROR; +} + + +/* Final release of a CMediaSample will call this */ + +STDMETHODIMP +CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + + + + BOOL bRelease = FALSE; + { + CAutoLock cal(this); + + /* Put back on the free list */ + + m_lFree.Add((CMediaSample *)pSample); + if (m_lWaiting != 0) { + NotifySample(); + } + + // if there is a pending Decommit, then we need to complete it by + // calling Free() when the last buffer is placed on the free list + + LONG l1 = m_lFree.GetCount(); + if (m_bDecommitInProgress && (l1 == m_lAllocated)) { + Free(); + m_bDecommitInProgress = FALSE; + bRelease = TRUE; + } + } + + if (m_pNotify) { + + ASSERT(m_fEnableReleaseCallback); + + // + // Note that this is not synchronized with setting up a notification + // method. + // + m_pNotify->NotifyRelease(); + } + + /* For each buffer there is one AddRef, made in GetBuffer and released + here. This may cause the allocator and all samples to be deleted */ + + if (bRelease) { + Release(); + } + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::SetNotify( + IMemAllocatorNotifyCallbackTemp* pNotify + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock lck(this); + if (pNotify) { + pNotify->AddRef(); + } + if (m_pNotify) { + m_pNotify->Release(); + } + m_pNotify = pNotify; + return S_OK; +} + +STDMETHODIMP +CBaseAllocator::GetFreeCount( + LONG* plBuffersFree + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock cObjectLock(this); + *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); + return NOERROR; +} + +void +CBaseAllocator::NotifySample() +{ + if (m_lWaiting != 0) { + ASSERT(m_hSem != NULL); + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } +} + +STDMETHODIMP +CBaseAllocator::Commit() +{ + /* Check we are not decommitted */ + CAutoLock cObjectLock(this); + + // cannot need to alloc or re-alloc if we are committed + if (m_bCommitted) { + return NOERROR; + } + + /* Allow GetBuffer calls */ + + m_bCommitted = TRUE; + + // is there a pending decommit ? if so, just cancel it + if (m_bDecommitInProgress) { + m_bDecommitInProgress = FALSE; + + // don't call Alloc at this point. He cannot allow SetProperties + // between Decommit and the last free, so the buffer size cannot have + // changed. And because some of the buffers are not free yet, he + // cannot re-alloc anyway. + return NOERROR; + } + + DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); + + // actually need to allocate the samples + HRESULT hr = Alloc(); + if (FAILED(hr)) { + m_bCommitted = FALSE; + return hr; + } + AddRef(); + return NOERROR; +} + + +STDMETHODIMP +CBaseAllocator::Decommit() +{ + BOOL bRelease = FALSE; + { + /* Check we are not already decommitted */ + CAutoLock cObjectLock(this); + if (m_bCommitted == FALSE) { + if (m_bDecommitInProgress == FALSE) { + return NOERROR; + } + } + + /* No more GetBuffer calls will succeed */ + m_bCommitted = FALSE; + + // are any buffers outstanding? + if (m_lFree.GetCount() < m_lAllocated) { + // please complete the decommit when last buffer is freed + m_bDecommitInProgress = TRUE; + } else { + m_bDecommitInProgress = FALSE; + + // need to complete the decommit here as there are no + // outstanding buffers + + Free(); + bRelease = TRUE; + } + + // Tell anyone waiting that they can go now so we can + // reject their call + NotifySample(); + } + + if (bRelease) { + Release(); + } + return NOERROR; +} + + +/* Base definition of allocation which checks we are ok to go ahead and do + the full allocation. We return S_FALSE if the requirements are the same */ + +HRESULT +CBaseAllocator::Alloc(void) +{ + /* Error if he hasn't set the size yet */ + if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { + return VFW_E_SIZENOTSET; + } + + /* should never get here while buffers outstanding */ + ASSERT(m_lFree.GetCount() == m_lAllocated); + + /* If the requirements haven't changed then don't reallocate */ + if (m_bChanged == FALSE) { + return S_FALSE; + } + + return NOERROR; +} + +/* Implement CBaseAllocator::CSampleList::Remove(pSample) + Removes pSample from the list +*/ +void +CBaseAllocator::CSampleList::Remove(CMediaSample * pSample) +{ + CMediaSample **pSearch; + for (pSearch = &m_List; + *pSearch != NULL; + pSearch = &(CBaseAllocator::NextSample(*pSearch))) { + if (*pSearch == pSample) { + *pSearch = CBaseAllocator::NextSample(pSample); + CBaseAllocator::NextSample(pSample) = NULL; + m_nOnList--; + return; + } + } + DbgBreak("Couldn't find sample in list"); +} + +//===================================================================== +//===================================================================== +// Implements CMemAllocator +//===================================================================== +//===================================================================== + + +/* This goes in the factory template table to create new instances */ +CUnknown *CMemAllocator::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) +{ + CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); + return pUnkRet; +} + +CMemAllocator::CMemAllocator( + TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} + +#ifdef UNICODE +CMemAllocator::CMemAllocator( + CHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} +#endif + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ +STDMETHODIMP +CMemAllocator::SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + SYSTEM_INFO SysInfo; + GetSystemInfo(&SysInfo); + + /* Check the alignment request is a power of 2 */ + if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { + DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), + pRequest->cbAlign)); + } + /* Check the alignment requested */ + if (pRequest->cbAlign == 0 || + (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { + DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), + pRequest->cbAlign, SysInfo.dwAllocationGranularity)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted == TRUE) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lFree.GetCount() < m_lAllocated) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + // round length up to alignment - remember that prefix is included in + // the alignment + LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; + LONG lRemainder = lSize % pRequest->cbAlign; + if (lRemainder != 0) { + lSize = lSize - lRemainder + pRequest->cbAlign; + } + pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); + + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +// override this to allocate our resources when Commit is called. +// +// note that our resources may be already allocated when this is called, +// since we don't free them on Decommit. We will only be called when in +// decommit state with all buffers free. +// +// object locked by caller +HRESULT +CMemAllocator::Alloc(void) +{ + CAutoLock lck(this); + + /* Check he has called SetProperties */ + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + /* If the requirements haven't changed then don't reallocate */ + if (hr == S_FALSE) { + ASSERT(m_pBuffer); + return NOERROR; + } + ASSERT(hr == S_OK); // we use this fact in the loop below + + /* Free the old resources */ + if (m_pBuffer) { + ReallyFree(); + } + + /* Compute the aligned size */ + LONG lAlignedSize = m_lSize + m_lPrefix; + if (m_lAlignment > 1) { + LONG lRemainder = lAlignedSize % m_lAlignment; + if (lRemainder != 0) { + lAlignedSize += (m_lAlignment - lRemainder); + } + } + + /* Create the contiguous memory block for the samples + making sure it's properly aligned (64K should be enough!) + */ + ASSERT(lAlignedSize % m_lAlignment == 0); + + m_pBuffer = (PBYTE)VirtualAlloc(NULL, + m_lCount * lAlignedSize, + MEM_COMMIT, + PAGE_READWRITE); + + if (m_pBuffer == NULL) { + return E_OUTOFMEMORY; + } + + LPBYTE pNext = m_pBuffer; + CMediaSample *pSample; + + ASSERT(m_lAllocated == 0); + + // Create the new samples - we have allocated m_lSize bytes for each sample + // plus m_lPrefix bytes per sample as a prefix. We set the pointer to + // the memory after the prefix - so that GetPointer() will return a pointer + // to m_lSize bytes. + for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { + + + pSample = new CMediaSample( + NAME("Default memory media sample"), + this, + &hr, + pNext + m_lPrefix, // GetPointer() value + m_lSize); // not including prefix + + ASSERT(SUCCEEDED(hr)); + if (pSample == NULL) { + return E_OUTOFMEMORY; + } + + // This CANNOT fail + m_lFree.Add(pSample); + } + + m_bChanged = FALSE; + return NOERROR; +} + + +// override this to free up any resources we have allocated. +// called from the base class on Decommit when all buffers have been +// returned to the free list. +// +// caller has already locked the object. + +// in our case, we keep the memory until we are deleted, so +// we do nothing here. The memory is deleted in the destructor by +// calling ReallyFree() +void +CMemAllocator::Free(void) +{ + return; +} + + +// called from the destructor (and from Alloc if changing size/count) to +// actually free up the memory +void +CMemAllocator::ReallyFree(void) +{ + /* Should never be deleting this unless all buffers are freed */ + + ASSERT(m_lAllocated == m_lFree.GetCount()); + + /* Free up all the CMediaSamples */ + + CMediaSample *pSample; + for (;;) { + pSample = m_lFree.RemoveHead(); + if (pSample != NULL) { + delete pSample; + } else { + break; + } + } + + m_lAllocated = 0; + + // free the block of buffer memory + if (m_pBuffer) { + EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); + m_pBuffer = NULL; + } +} + + +/* Destructor frees our memory resources */ + +CMemAllocator::~CMemAllocator() +{ + Decommit(); + ReallyFree(); +} + +// ------------------------------------------------------------------------ +// filter registration through IFilterMapper. used if IFilterMapper is +// not found (Quartz 1.0 install) + +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); + + + if( bRegister ) + { + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM->RegisterFilter( *(psetupdata->clsID) + , psetupdata->strName + , psetupdata->dwMerit ); + if( SUCCEEDED(hr) ) + { + // all its pins + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); + for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) + { + hr = pIFM->RegisterPin( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , psetupdata->lpPin[m1].bRendered + , psetupdata->lpPin[m1].bOutput + , psetupdata->lpPin[m1].bZero + , psetupdata->lpPin[m1].bMany + , *(psetupdata->lpPin[m1].clsConnectsToFilter) + , psetupdata->lpPin[m1].strConnectsToPin ); + + if( SUCCEEDED(hr) ) + { + // and each pin's media types + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); + for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) + { + hr = pIFM->RegisterPinType( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + } + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + +// Remove warnings about unreferenced inline functions +#pragma warning(disable:4514) + diff --git a/plugins/gs/gsdx9/baseclasses/amfilter.h b/plugins/gs/gsdx9/baseclasses/amfilter.h new file mode 100644 index 0000000000..47ffc0a5f0 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amfilter.h @@ -0,0 +1,1587 @@ +//------------------------------------------------------------------------------ +// File: AMFilter.h +// +// Desc: DirectShow base classes - efines class hierarchy for streams +// architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __FILTER__ +#define __FILTER__ + +/* The following classes are declared in this header: */ + +class CBaseMediaFilter; // IMediaFilter support +class CBaseFilter; // IBaseFilter,IMediaFilter support +class CBasePin; // Abstract base class for IPin interface +class CEnumPins; // Enumerate input and output pins +class CEnumMediaTypes; // Enumerate the pin's preferred formats +class CBaseOutputPin; // Adds data provider member functions +class CBaseInputPin; // Implements IMemInputPin interface +class CMediaSample; // Basic transport unit for IMemInputPin +class CBaseAllocator; // General list guff for most allocators +class CMemAllocator; // Implements memory buffer allocation + + +//===================================================================== +//===================================================================== +// +// QueryFilterInfo and QueryPinInfo AddRef the interface pointers +// they return. You can use the macro below to release the interface. +// +//===================================================================== +//===================================================================== + +#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); + +#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); + +//===================================================================== +//===================================================================== +// Defines CBaseMediaFilter +// +// Abstract base class implementing IMediaFilter. +// +// Typically you will derive your filter from CBaseFilter rather than +// this, unless you are implementing an object such as a plug-in +// distributor that needs to support IMediaFilter but not IBaseFilter. +// +// Note that IMediaFilter is derived from IPersist to allow query of +// class id. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseMediaFilter : public CUnknown, + public IMediaFilter +{ + +protected: + + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this filter's reference clock + // note: all filters in a filter graph use the same clock + + // offset from stream time to reference time + CRefTime m_tStart; + + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + +public: + + CBaseMediaFilter( + const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid); + + virtual ~CBaseMediaFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(IReferenceClock **pClock); + + // default implementation of Stop and Pause just record the + // state. Override to activate or de-activate your filter. + // Note that Run when called from Stopped state will call Pause + // to ensure activation, so if you are a source or transform + // you will probably not need to override Run. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? (running or paused) + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; +}; + +//===================================================================== +//===================================================================== +// Defines CBaseFilter +// +// An abstract class providing basic IBaseFilter support for pin +// enumeration and filter information reading. +// +// We cannot derive from CBaseMediaFilter since methods in IMediaFilter +// are also in IBaseFilter and would be ambiguous. Since much of the code +// assumes that they derive from a class that has m_State and other state +// directly available, we duplicate code from CBaseMediaFilter rather than +// having a member variable. +// +// Derive your filter from this, or from a derived object such as +// CTransformFilter. +//===================================================================== +//===================================================================== + + +class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown + public IBaseFilter, // The Filter Interface + public IAMovieSetup // For un/registration +{ + +friend class CBasePin; + +protected: + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this graph's ref clock + CRefTime m_tStart; // offset from stream time to reference time + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + + WCHAR *m_pName; // Full filter name + IFilterGraph *m_pGraph; // Graph we belong to + IMediaEventSink *m_pSink; // Called with notify events + LONG m_PinVersion; // Current pin version + +public: + + CBaseFilter( + const TCHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + HRESULT *phr); // General OLE return code +#ifdef UNICODE + CBaseFilter( + const CHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + CHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + HRESULT *phr); // General OLE return code +#endif + ~CBaseFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); +#ifdef DEBUG + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +#endif + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(IReferenceClock **pClock); + + + // override Stop and Pause so we can activate the pins. + // Note that Run will call Pause first if activation needed. + // Override these if you want to activate your filter rather than + // your pins. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; + + // Is this filter stopped (without locking) + BOOL IsStopped() { + return (m_State == State_Stopped); + }; + + // + // --- IBaseFilter methods --- + // + + // pin enumerator + STDMETHODIMP EnumPins( + IEnumPins ** ppEnum); + + + // default behaviour of FindPin assumes pin ids are their names + STDMETHODIMP FindPin( + LPCWSTR Id, + IPin ** ppPin + ); + + STDMETHODIMP QueryFilterInfo( + FILTER_INFO * pInfo); + + STDMETHODIMP JoinFilterGraph( + IFilterGraph * pGraph, + LPCWSTR pName); + + // return a Vendor information string. Optional - may return E_NOTIMPL. + // memory returned should be freed using CoTaskMemFree + // default implementation returns E_NOTIMPL + STDMETHODIMP QueryVendorInfo( + LPWSTR* pVendorInfo + ); + + // --- helper methods --- + + // send an event notification to the filter graph if we know about it. + // returns S_OK if delivered, S_FALSE if the filter graph does not sink + // events, or an error otherwise. + HRESULT NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2); + + // return the filter graph we belong to + IFilterGraph *GetFilterGraph() { + return m_pGraph; + } + + // Request reconnect + // pPin is the pin to reconnect + // pmt is the type to reconnect with - can be NULL + // Calls ReconnectEx on the filter graph + HRESULT ReconnectPin(IPin *pPin, AM_MEDIA_TYPE const *pmt); + + // find out the current pin version (used by enumerators) + virtual LONG GetPinVersion(); + void IncrementPinVersion(); + + // you need to supply these to access the pins from the enumerator + // and for default Stop and Pause/Run activation. + virtual int GetPinCount() PURE; + virtual CBasePin *GetPin(int n) PURE; + + // --- IAMovieSetup methods --- + + STDMETHODIMP Register(); // ask filter to register itself + STDMETHODIMP Unregister(); // and unregister itself + + // --- setup helper methods --- + // (override to return filters setup data) + + virtual LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } + +}; + + +//===================================================================== +//===================================================================== +// Defines CBasePin +// +// Abstract class that supports the basics of IPin +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl +{ + +protected: + + WCHAR * m_pName; // This pin's name + IPin *m_Connected; // Pin we have connected to + PIN_DIRECTION m_dir; // Direction of this pin + CCritSec *m_pLock; // Object we use for locking + bool m_bRunTimeError; // Run time error generated + bool m_bCanReconnectWhenActive; // OK to reconnect when active + bool m_bTryMyTypesFirst; // When connecting enumerate + // this pin's types first + CBaseFilter *m_pFilter; // Filter we were created by + IQualityControl *m_pQSink; // Target for Quality messages + LONG m_TypeVersion; // Holds current type version + CMediaType m_mt; // Media type of connection + + CRefTime m_tStart; // time from NewSegment call + CRefTime m_tStop; // time from NewSegment + double m_dRate; // rate from NewSegment + +#ifdef DEBUG + LONG m_cRef; // Ref count tracing +#endif + + // displays pin connection information + +#ifdef DEBUG + void DisplayPinInfo(IPin *pReceivePin); + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); +#else + void DisplayPinInfo(IPin *pReceivePin) {}; + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; +#endif + + // used to agree a media type for a pin connection + + // given a specific media type, attempt a connection (includes + // checking that the type is acceptable to this pin) + HRESULT + AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type + ); + + // try all the media types in this enumerator - for each that + // we accept, try to connect using ReceiveConnection. + HRESULT TryMediaTypes( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt, // proposed type from Connect + IEnumMediaTypes *pEnum); // try this enumerator + + // establish a connection with a suitable mediatype. Needs to + // propose a media type if the pmt pointer is null or partially + // specified - use TryMediaTypes on both our and then the other pin's + // enumerator until we find one that works. + HRESULT AgreeMediaType( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt); // proposed type from Connect + +public: + + CBasePin( + TCHAR *pObjectName, // Object description + CBaseFilter *pFilter, // Owning filter who knows about pins + CCritSec *pLock, // Object who implements the lock + HRESULT *phr, // General OLE return code + LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#ifdef UNICODE + CBasePin( + CHAR *pObjectName, // Object description + CBaseFilter *pFilter, // Owning filter who knows about pins + CCritSec *pLock, // Object who implements the lock + HRESULT *phr, // General OLE return code + LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#endif + virtual ~CBasePin(); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + + // --- IPin methods --- + + // take lead role in establishing a connection. Media type pointer + // may be null, or may point to partially-specified mediatype + // (subtype or format type may be GUID_NULL). + STDMETHODIMP Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ); + + // (passive) accept a connection from another pin + STDMETHODIMP ReceiveConnection( + IPin * pConnector, // this is the initiating connecting pin + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange + ); + + STDMETHODIMP Disconnect(); + + STDMETHODIMP ConnectedTo(IPin **pPin); + + STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + STDMETHODIMP QueryPinInfo( + PIN_INFO * pInfo + ); + + STDMETHODIMP QueryDirection( + PIN_DIRECTION * pPinDir + ); + + STDMETHODIMP QueryId( + LPWSTR * Id + ); + + // does the pin support this media type + STDMETHODIMP QueryAccept( + const AM_MEDIA_TYPE *pmt + ); + + // return an enumerator for this pins preferred media types + STDMETHODIMP EnumMediaTypes( + IEnumMediaTypes **ppEnum + ); + + // return an array of IPin* - the pins that this pin internally connects to + // All pins put in the array must be AddReffed (but no others) + // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE + // Default: return E_NOTIMPL + // The filter graph will interpret NOT_IMPL as any input pin connects to + // all visible output pins and vice versa. + // apPin can be NULL if nPin==0 (not otherwise). + STDMETHODIMP QueryInternalConnections( + IPin* *apPin, // array of IPin* + ULONG *nPin // on input, the number of slots + // on output the number of pins + ) { return E_NOTIMPL; } + + // Called when no more data will be sent + STDMETHODIMP EndOfStream(void); + + // Begin/EndFlush still PURE + + // NewSegment notifies of the start/stop/rate applying to the data + // about to be received. Default implementation records data and + // returns S_OK. + // Override this to pass downstream. + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + STDMETHODIMP SetSink(IQualityControl * piqc); + + // --- helper methods --- + + // Returns true if the pin is connected. false otherwise. + BOOL IsConnected(void) {return (m_Connected != NULL); }; + // Return the pin this is connected to (if any) + IPin * GetConnected() { return m_Connected; }; + + // Check if our filter is currently stopped + BOOL IsStopped() { + return (m_pFilter->m_State == State_Stopped); + }; + + // find out the current type version (used by enumerators) + virtual LONG GetMediaTypeVersion(); + void IncrementTypeVersion(); + + // switch the pin to active (paused or running) mode + // not an error to call this if already active + virtual HRESULT Active(void); + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Notify of Run() from filter + virtual HRESULT Run(REFERENCE_TIME tStart); + + // check if the pin can support this specific proposed type and format + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // set the connection to use this format (previously agreed) + virtual HRESULT SetMediaType(const CMediaType *); + + // check that the connection is ok before verifying it + // can be overridden eg to check what interfaces will be supported. + virtual HRESULT CheckConnect(IPin *); + + // Set and release resources required for a connection + virtual HRESULT BreakConnect(); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // returns the preferred formats for a pin + virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); + + // access to NewSegment values + REFERENCE_TIME CurrentStopTime() { + return m_tStop; + } + REFERENCE_TIME CurrentStartTime() { + return m_tStart; + } + double CurrentRate() { + return m_dRate; + } + + // Access name + LPWSTR Name() { return m_pName; }; + + // Can reconnectwhen active? + void SetReconnectWhenActive(bool bCanReconnect) + { + m_bCanReconnectWhenActive = bCanReconnect; + } + + bool CanReconnectWhenActive() + { + return m_bCanReconnectWhenActive; + } + +protected: + STDMETHODIMP DisconnectInternal(); +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumPins +// +// Pin enumerator class that works by calling CBaseFilter. This interface +// is provided by CBaseFilter::EnumPins and calls GetPinCount() and +// GetPin() to enumerate existing pins. Needs to be a separate object so +// that it can be cloned (creating an existing object at the same +// position in the enumeration) +// +//===================================================================== +//===================================================================== + +class CEnumPins : public IEnumPins // The interface we support +{ + int m_Position; // Current ordinal position + int m_PinCount; // Number of pins available + CBaseFilter *m_pFilter; // The filter who owns us + LONG m_Version; // Pin version information + LONG m_cRef; + + typedef CGenericList CPinList; + + CPinList m_PinCache; // These pointers have not been AddRef'ed and + // so they should not be dereferenced. They are + // merely kept to ID which pins have been enumerated. + +#ifdef DEBUG + DWORD m_dwCookie; +#endif + + /* If while we are retrieving a pin for example from the filter an error + occurs we assume that our internal state is stale with respect to the + filter (someone may have deleted all the pins). We can check before + starting whether or not the operation is likely to fail by asking the + filter what it's current version number is. If the filter has not + overriden the GetPinVersion method then this will always match */ + + BOOL AreWeOutOfSync() { + return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); + }; + + /* This method performs the same operations as Reset, except is does not clear + the cache of pins already enumerated. */ + + STDMETHODIMP Refresh(); + +public: + + CEnumPins( + CBaseFilter *pFilter, + CEnumPins *pEnumPins); + + virtual ~CEnumPins(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumPins + STDMETHODIMP Next( + ULONG cPins, // place this many pins... + IPin ** ppPins, // ...in this array of IPin* + ULONG * pcFetched // actual count passed returned here + ); + + STDMETHODIMP Skip(ULONG cPins); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(IEnumPins **ppEnum); + + +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumMediaTypes +// +// Enumerates the preferred formats for input and output pins +//===================================================================== +//===================================================================== + +class CEnumMediaTypes : public IEnumMediaTypes // The interface we support +{ + int m_Position; // Current ordinal position + CBasePin *m_pPin; // The pin who owns us + LONG m_Version; // Media type version value + LONG m_cRef; +#ifdef DEBUG + DWORD m_dwCookie; +#endif + + /* The media types a filter supports can be quite dynamic so we add to + the general IEnumXXXX interface the ability to be signaled when they + change via an event handle the connected filter supplies. Until the + Reset method is called after the state changes all further calls to + the enumerator (except Reset) will return E_UNEXPECTED error code */ + + BOOL AreWeOutOfSync() { + return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); + }; + +public: + + CEnumMediaTypes( + CBasePin *pPin, + CEnumMediaTypes *pEnumMediaTypes); + + virtual ~CEnumMediaTypes(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumMediaTypes + STDMETHODIMP Next( + ULONG cMediaTypes, // place this many pins... + AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array + ULONG * pcFetched // actual count passed + ); + + STDMETHODIMP Skip(ULONG cMediaTypes); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(IEnumMediaTypes **ppEnum); +}; + + + + +//===================================================================== +//===================================================================== +// Defines CBaseOutputPin +// +// class derived from CBasePin that can pass buffers to a connected pin +// that supports IMemInputPin. Supports IPin. +// +// Derive your output pin from this. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseOutputPin : public CBasePin +{ + +protected: + + IMemAllocator *m_pAllocator; + IMemInputPin *m_pInputPin; // interface on the downstreaminput pin + // set up in CheckConnect when we connect. + +public: + + CBaseOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CBaseOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + // override CompleteConnect() so we can negotiate an allocator + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // negotiate the allocator and its buffer size/count and other properties + // Calls DecideBufferSize to set properties + virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // override this to set the buffer size and count. Return an error + // if the size/count is not to your liking. + // The allocator properties passed in are those requested by the + // input pin - use eg the alignment and prefix members if you have + // no preference on these. + virtual HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES * ppropInputRequest + ) PURE; + + // returns an empty sample buffer from the allocator + virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // deliver a filled-in sample to the connected input pin + // note - you need to release it after calling this. The receiving + // pin will addref the sample if it needs to hold it beyond the + // call. + virtual HRESULT Deliver(IMediaSample *); + + // override this to control the connection + virtual HRESULT InitAllocator(IMemAllocator **ppAlloc); + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + + // override to call Commit and Decommit + HRESULT Active(void); + HRESULT Inactive(void); + + // we have a default handling of EndOfStream which is to return + // an error, since this should be called on input pins only + STDMETHODIMP EndOfStream(void); + + // called from elsewhere in our filter to pass EOS downstream to + // our connected input pin + virtual HRESULT DeliverEndOfStream(void); + + // same for Begin/EndFlush - we handle Begin/EndFlush since it + // is an error on an output pin, and we have Deliver methods to + // call the methods on the connected pin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + virtual HRESULT DeliverBeginFlush(void); + virtual HRESULT DeliverEndFlush(void); + + // deliver NewSegment to connected pin - you will need to + // override this if you queue any data in your output pin. + virtual HRESULT DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + // All inherited from CBasePin and not overridden here. + // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + // STDMETHODIMP SetSink(IQualityControl * piqc); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseInputPin +// +// derive your standard input pin from this. +// you need to supply GetMediaType and CheckConnect etc (see CBasePin), +// and you need to supply Receive to do something more useful. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseInputPin : public CBasePin, + public IMemInputPin +{ + +protected: + + IMemAllocator *m_pAllocator; // Default memory allocator + + // allocator is read-only, so received samples + // cannot be modified (probably only relevant to in-place + // transforms + BYTE m_bReadOnly; + + // in flushing state (between BeginFlush and EndFlush) + // if TRUE, all Receives are returned with S_FALSE + BYTE m_bFlushing; + + // Sample properties - initalized in Receive + AM_SAMPLE2_PROPERTIES m_SampleProps; + +public: + + CBaseInputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CBaseInputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + virtual ~CBaseInputPin(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // return the allocator interface that this input pin + // would like the output pin to use + STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); + + // tell the input pin which allocator the output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly); + + // do something with this media sample + STDMETHODIMP Receive(IMediaSample *pSample); + + // do something with these media samples + STDMETHODIMP ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed); + + // See if Receive() blocks + STDMETHODIMP ReceiveCanBlock(); + + // Default handling for BeginFlush - call at the beginning + // of your implementation (makes sure that all Receive calls + // fail). After calling this, you need to free any queued data + // and then call downstream. + STDMETHODIMP BeginFlush(void); + + // default handling for EndFlush - call at end of your implementation + // - before calling this, ensure that there is no queued data and no thread + // pushing any more without a further receive, then call downstream, + // then call this method to clear the m_bFlushing flag and re-enable + // receives + STDMETHODIMP EndFlush(void); + + // this method is optional (can return E_NOTIMPL). + // default implementation returns E_NOTIMPL. Override if you have + // specific alignment or prefix needs, but could use an upstream + // allocator + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps); + + // Release the pin's allocator. + HRESULT BreakConnect(); + + // helper method to check the read-only flag + BOOL IsReadOnly() { + return m_bReadOnly; + }; + + // helper method to see if we are flushing + BOOL IsFlushing() { + return m_bFlushing; + }; + + // Override this for checking whether it's OK to process samples + // Also call this from EndOfStream. + virtual HRESULT CheckStreaming(); + + // Pass a Quality notification on to the appropriate sink + HRESULT PassNotify(Quality& q); + + + //================================================================================ + // IQualityControl methods (from CBasePin) + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // no need to override: + // STDMETHODIMP SetSink(IQualityControl * piqc); + + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Return sample properties pointer + AM_SAMPLE2_PROPERTIES * SampleProps() { + ASSERT(m_SampleProps.cbData != 0); + return &m_SampleProps; + } + +}; + +/////////////////////////////////////////////////////////////////////////// +// CDynamicOutputPin +// + +class CDynamicOutputPin : public CBaseOutputPin, + public IPinFlowControl +{ +public: +#ifdef UNICODE + CDynamicOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + + CDynamicOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); + + ~CDynamicOutputPin(); + + // IUnknown Methods + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IPin Methods + STDMETHODIMP Disconnect(void); + + // IPinFlowControl Methods + STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); + + // Set graph config info + void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); + + #ifdef DEBUG + virtual HRESULT Deliver(IMediaSample *pSample); + virtual HRESULT DeliverEndOfStream(void); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + #endif // DEBUG + + HRESULT DeliverBeginFlush(void); + HRESULT DeliverEndFlush(void); + + HRESULT Inactive(void); + HRESULT Active(void); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + virtual HRESULT StartUsingOutputPin(void); + virtual void StopUsingOutputPin(void); + virtual bool StreamingThreadUsingOutputPin(void); + + HRESULT ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ); + HRESULT ChangeMediaType(const CMediaType *pmt); + HRESULT DynamicReconnect(const CMediaType *pmt); + +protected: + HRESULT SynchronousBlockOutputPin(void); + HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); + HRESULT UnblockOutputPin(void); + + void BlockOutputPin(void); + void ResetBlockState(void); + + static HRESULT WaitEvent(HANDLE hEvent); + + enum BLOCK_STATE + { + NOT_BLOCKED, + PENDING, + BLOCKED + }; + + // This lock should be held when the following class members are + // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, + // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. + CCritSec m_BlockStateLock; + + // This event should be signaled when the output pin is + // not blocked. This is a manual reset event. For more + // information on events, see the documentation for + // CreateEvent() in the Windows SDK. + HANDLE m_hUnblockOutputPinEvent; + + // This event will be signaled when block operation succeedes or + // when the user cancels the block operation. The block operation + // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) + // while the block operation is pending. + HANDLE m_hNotifyCallerPinBlockedEvent; + + // The state of the current block operation. + BLOCK_STATE m_BlockState; + + // The ID of the thread which last called IPinFlowControl::Block(). + // For more information on thread IDs, see the documentation for + // GetCurrentThreadID() in the Windows SDK. + DWORD m_dwBlockCallerThreadID; + + // The number of times StartUsingOutputPin() has been sucessfully + // called and a corresponding call to StopUsingOutputPin() has not + // been made. When this variable is greater than 0, the streaming + // thread is calling IPin::NewSegment(), IPin::EndOfStream(), + // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The + // streaming thread could also be calling: DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot + // be blocked while the output pin is being used. + DWORD m_dwNumOutstandingOutputPinUsers; + + // This event should be set when the IMediaFilter::Stop() is called. + // This is a manual reset event. It is also set when the output pin + // delivers a flush to the connected input pin. + HANDLE m_hStopEvent; + IGraphConfig* m_pGraphConfig; + + // TRUE if the output pin's allocator's samples are read only. + // Otherwise FALSE. For more information, see the documentation + // for IMemInputPin::NotifyAllocator(). + BOOL m_bPinUsesReadOnlyAllocator; + +private: + HRESULT Initialize(void); + HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); + + #ifdef DEBUG + void AssertValid(void); + #endif // DEBUG +}; + +class CAutoUsingOutputPin +{ +public: + CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ); + ~CAutoUsingOutputPin(); + +private: + CDynamicOutputPin* m_pOutputPin; +}; + +inline CAutoUsingOutputPin::CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ) : + m_pOutputPin(NULL) +{ + // The caller should always pass in valid pointers. + ASSERT( NULL != pOutputPin ); + ASSERT( NULL != phr ); + + // Make sure the user initialized phr. + ASSERT( S_OK == *phr ); + + HRESULT hr = pOutputPin->StartUsingOutputPin(); + if( FAILED( hr ) ) + { + *phr = hr; + return; + } + + m_pOutputPin = pOutputPin; +} + +inline CAutoUsingOutputPin::~CAutoUsingOutputPin() +{ + if( NULL != m_pOutputPin ) + { + m_pOutputPin->StopUsingOutputPin(); + } +} + +#ifdef DEBUG + +inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::Deliver(pSample); +} + +inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT( StreamingThreadUsingOutputPin() ); + + return CBaseOutputPin::DeliverEndOfStream(); +} + +inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); +} + +#endif // DEBUG + +//===================================================================== +//===================================================================== +// Memory allocators +// +// the shared memory transport between pins requires the input pin +// to provide a memory allocator that can provide sample objects. A +// sample object supports the IMediaSample interface. +// +// CBaseAllocator handles the management of free and busy samples. It +// allocates CMediaSample objects. CBaseAllocator is an abstract class: +// in particular it has no method of initializing the list of free +// samples. CMemAllocator is derived from CBaseAllocator and initializes +// the list of samples using memory from the standard IMalloc interface. +// +// If you want your buffers to live in some special area of memory, +// derive your allocator object from CBaseAllocator. If you derive your +// IMemInputPin interface object from CBaseMemInputPin, you will get +// CMemAllocator-based allocation etc for free and will just need to +// supply the Receive handling, and media type / format negotiation. +//===================================================================== +//===================================================================== + + +//===================================================================== +//===================================================================== +// Defines CMediaSample +// +// an object of this class supports IMediaSample and represents a buffer +// for media data with some associated properties. Releasing it returns +// it to a freelist managed by a CBaseAllocator derived object. +//===================================================================== +//===================================================================== + +class CMediaSample : public IMediaSample2 // The interface we support +{ + +protected: + + friend class CBaseAllocator; + + /* Values for dwFlags - these are used for backward compatiblity + only now - use AM_SAMPLE_xxx + */ + enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ + Sample_Preroll = 0x02, /* Is this a preroll sample */ + Sample_Discontinuity = 0x04, /* Set if start of new segment */ + Sample_TypeChanged = 0x08, /* Has the type changed */ + Sample_TimeValid = 0x10, /* Set if time is valid */ + Sample_MediaTimeValid = 0x20, /* Is the media time valid */ + Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ + Sample_StopValid = 0x100, /* Stop time valid */ + Sample_ValidFlags = 0x1FF + }; + + /* Properties, the media sample class can be a container for a format + change in which case we take a copy of a type through the SetMediaType + interface function and then return it when GetMediaType is called. As + we do no internal processing on it we leave it as a pointer */ + + DWORD m_dwFlags; /* Flags for this sample */ + /* Type specific flags are packed + into the top word + */ + DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ + LPBYTE m_pBuffer; /* Pointer to the complete buffer */ + LONG m_lActual; /* Length of data in this sample */ + LONG m_cbBuffer; /* Size of the buffer */ + CBaseAllocator *m_pAllocator; /* The allocator who owns us */ + CMediaSample *m_pNext; /* Chaining in free list */ + REFERENCE_TIME m_Start; /* Start sample time */ + REFERENCE_TIME m_End; /* End sample time */ + LONGLONG m_MediaStart; /* Real media start position */ + LONG m_MediaEnd; /* A difference to get the end */ + AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ + DWORD m_dwStreamId; /* Stream id */ +public: + LONG m_cRef; /* Reference count */ + + +public: + + CMediaSample( + TCHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer = NULL, + LONG length = 0); +#ifdef UNICODE + CMediaSample( + CHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer = NULL, + LONG length = 0); +#endif + + virtual ~CMediaSample(); + + /* Note the media sample does not delegate to its owner */ + + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // set the buffer pointer and length. Used by allocators that + // want variable sized pointers or pointers into already-read data. + // This is only available through a CMediaSample* not an IMediaSample* + // and so cannot be changed by clients. + HRESULT SetPointer(BYTE * ptr, LONG cBytes); + + // Get me a read/write pointer to this buffer's memory. + STDMETHODIMP GetPointer(BYTE ** ppBuffer); + + STDMETHODIMP_(LONG) GetSize(void); + + // get the stream time at which this sample should start and finish. + STDMETHODIMP GetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd + ); + + // Set the stream time at which this sample should start and finish. + STDMETHODIMP SetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd + ); + STDMETHODIMP IsSyncPoint(void); + STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); + STDMETHODIMP IsPreroll(void); + STDMETHODIMP SetPreroll(BOOL bIsPreroll); + + STDMETHODIMP_(LONG) GetActualDataLength(void); + STDMETHODIMP SetActualDataLength(LONG lActual); + + // these allow for limited format changes in band + + STDMETHODIMP GetMediaType(AM_MEDIA_TYPE **ppMediaType); + STDMETHODIMP SetMediaType(AM_MEDIA_TYPE *pMediaType); + + // returns S_OK if there is a discontinuity in the data (this same is + // not a continuation of the previous stream of data + // - there has been a seek). + STDMETHODIMP IsDiscontinuity(void); + // set the discontinuity property - TRUE if this sample is not a + // continuation, but a new sample after a seek. + STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); + + // get the media times for this sample + STDMETHODIMP GetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd + ); + + // Set the media times for this sample + STDMETHODIMP SetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd + ); + + // Set and get properties (IMediaSample2) + STDMETHODIMP GetProperties( + DWORD cbProperties, + BYTE * pbProperties + ); + + STDMETHODIMP SetProperties( + DWORD cbProperties, + const BYTE * pbProperties + ); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseAllocator +// +// Abstract base class that manages a list of media samples +// +// This class provides support for getting buffers from the free list, +// including handling of commit and (asynchronous) decommit. +// +// Derive from this class and override the Alloc and Free functions to +// allocate your CMediaSample (or derived) objects and add them to the +// free list, preparing them as necessary. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown + public IMemAllocatorCallbackTemp, // The interface we support + public CCritSec // Provides object locking +{ + class CSampleList; + friend class CSampleList; + + /* Trick to get at protected member in CMediaSample */ + static CMediaSample * &NextSample(CMediaSample *pSample) + { + return pSample->m_pNext; + }; + + /* Mini list class for the free list */ + class CSampleList + { + public: + CSampleList() : m_List(NULL), m_nOnList(0) {}; +#ifdef DEBUG + ~CSampleList() + { + ASSERT(m_nOnList == 0); + }; +#endif + CMediaSample *Head() const { return m_List; }; + CMediaSample *Next(CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; + int GetCount() const { return m_nOnList; }; + void Add(CMediaSample *pSample) + { + ASSERT(pSample != NULL); + CBaseAllocator::NextSample(pSample) = m_List; + m_List = pSample; + m_nOnList++; + }; + CMediaSample *RemoveHead() + { + CMediaSample *pSample = m_List; + if (pSample != NULL) { + m_List = CBaseAllocator::NextSample(m_List); + m_nOnList--; + } + return pSample; + }; + void Remove(CMediaSample *pSample); + + public: + CMediaSample *m_List; + int m_nOnList; + }; +protected: + + CSampleList m_lFree; // Free list + + /* Note to overriders of CBaseAllocator. + + We use a lazy signalling mechanism for waiting for samples. + This means we don't call the OS if no waits occur. + + In order to implement this: + + 1. When a new sample is added to m_lFree call NotifySample() which + calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and + sets m_lWaiting to 0. + This must all be done holding the allocator's critical section. + + 2. When waiting for a sample call SetWaiting() which increments + m_lWaiting BEFORE leaving the allocator's critical section. + + 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) + having left the allocator's critical section. The effect of + this is to remove 1 from the semaphore's count. You MUST call + this once having incremented m_lWaiting. + + The following are then true when the critical section is not held : + (let nWaiting = number about to wait or waiting) + + (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) + (2) m_lWaiting + Semaphore count == nWaiting + + We would deadlock if + nWaiting != 0 && + m_lFree.GetCount() != 0 && + Semaphore count == 0 + + But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so + from (2) Semaphore count == nWaiting (which is non-0) so the + deadlock can't happen. + */ + + HANDLE m_hSem; // For signalling + long m_lWaiting; // Waiting for a free element + long m_lCount; // how many buffers we have agreed to provide + long m_lAllocated; // how many buffers are currently allocated + long m_lSize; // agreed size of each buffer + long m_lAlignment; // agreed alignment + long m_lPrefix; // agreed prefix (preceeds GetPointer() value) + BOOL m_bChanged; // Have the buffer requirements changed + + // if true, we are decommitted and can't allocate memory + BOOL m_bCommitted; + // if true, the decommit has happened, but we haven't called Free yet + // as there are still outstanding buffers + BOOL m_bDecommitInProgress; + + // Notification interface + IMemAllocatorNotifyCallbackTemp *m_pNotify; + + BOOL m_fEnableReleaseCallback; + + // called to decommit the memory when the last buffer is freed + // pure virtual - need to override this + virtual void Free(void) PURE; + + // override to allocate the memory when commit called + virtual HRESULT Alloc(void); + +public: + + CBaseAllocator( + TCHAR *, LPUNKNOWN, HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#ifdef UNICODE + CBaseAllocator( + CHAR *, LPUNKNOWN, HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#endif + virtual ~CBaseAllocator(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + STDMETHODIMP SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual); + + // return the properties actually being used on this allocator + STDMETHODIMP GetProperties( + ALLOCATOR_PROPERTIES* pProps); + + // override Commit to allocate memory. We handle the GetBuffer + //state changes + STDMETHODIMP Commit(); + + // override this to handle the memory freeing. We handle any outstanding + // GetBuffer calls + STDMETHODIMP Decommit(); + + // get container for a sample. Blocking, synchronous call to get the + // next free buffer (as represented by an IMediaSample interface). + // on return, the time etc properties will be invalid, but the buffer + // pointer and size will be correct. The two time parameters are + // optional and either may be NULL, they may alternatively be set to + // the start and end times the sample will have attached to it + // bPrevFramesSkipped is not used (used only by the video renderer's + // allocator where it affects quality management in direct draw). + + STDMETHODIMP GetBuffer(IMediaSample **ppBuffer, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // final release of a CMediaSample will call this + STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); + // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); + + STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); + + STDMETHODIMP GetFreeCount(LONG *plBuffersFree); + + // Notify that a sample is available + void NotifySample(); + + // Notify that we're waiting for a sample + void SetWaiting() { m_lWaiting++; }; +}; + + +//===================================================================== +//===================================================================== +// Defines CMemAllocator +// +// this is an allocator based on CBaseAllocator that allocates sample +// buffers in main memory (from 'new'). You must call SetProperties +// before calling Commit. +// +// we don't free the memory when going into Decommit state. The simplest +// way to implement this without complicating CBaseAllocator is to +// have a Free() function, called to go into decommit state, that does +// nothing and a ReallyFree function called from our destructor that +// actually frees the memory. +//===================================================================== +//===================================================================== + +// Make me one from quartz.dll +STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator); + +class CMemAllocator : public CBaseAllocator +{ + +protected: + + LPBYTE m_pBuffer; // combined memory for all buffers + + // override to free the memory when decommit completes + // - we actually do nothing, and save the memory until deletion. + void Free(void); + + // called from the destructor (and from Alloc if changing size/count) to + // actually free up the memory + void ReallyFree(void); + + // overriden to allocate the memory when commit called + HRESULT Alloc(void); + +public: + /* This goes in the factory template table to create new instances */ + static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *); + + STDMETHODIMP SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual); + + CMemAllocator(TCHAR *, LPUNKNOWN, HRESULT *); +#ifdef UNICODE + CMemAllocator(CHAR *, LPUNKNOWN, HRESULT *); +#endif + ~CMemAllocator(); +}; + +// helper used by IAMovieSetup implementation +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ); + + +/////////////////////////////////////////////////////////////////////////// +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +/////////////////////////////////////////////////////////////////////////// + +#endif /* __FILTER__ */ + + + diff --git a/plugins/gs/gsdx9/baseclasses/amvideo.cpp b/plugins/gs/gsdx9/baseclasses/amvideo.cpp new file mode 100644 index 0000000000..4b2494f21e --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/amvideo.cpp @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// File: AMVideo.cpp +// +// Desc: DirectShow base classes - implements helper functions for +// bitmap formats. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include + +// These are bit field masks for true colour devices + +const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; +const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; +const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; + +// This maps bitmap subtypes into a bits per pixel value and also a +// name. unicode and ansi versions are stored because we have to +// return a pointer to a static string. +const struct { + const GUID *pSubtype; + WORD BitCount; + CHAR *pName; + WCHAR *wszName; +} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", + &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", + &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", + &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", + &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", + &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", + &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", + &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", + &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", + &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" +}; + +// Return the size of the bitmap as defined by this header + +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) +{ + return DIBSIZE(*pHeader); +} + + +// This is called if the header has a 16 bit colour depth and needs to work +// out the detailed type from the bit fields (either RGB 565 or RGB 555) + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) +{ + BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; + ASSERT(pbmiHeader->biBitCount == 16); + + // If its BI_RGB then it's RGB 555 by default + + if (pbmiHeader->biCompression == BI_RGB) { + return MEDIASUBTYPE_RGB555; + } + + // Compare the bit fields with RGB 555 + + DWORD *pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits555[0]) { + if (pMask[1] == bits555[1]) { + if (pMask[2] == bits555[2]) { + return MEDIASUBTYPE_RGB555; + } + } + } + + // Compare the bit fields with RGB 565 + + pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits565[0]) { + if (pMask[1] == bits565[1]) { + if (pMask[2] == bits565[2]) { + return MEDIASUBTYPE_RGB565; + } + } + } + return GUID_NULL; +} + + +// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is +// used to describe it in format negotiations. For example a video codec fills +// in the format block with a VIDEOINFO structure, it also fills in the major +// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit +// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 + +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) +{ + ASSERT(pbmiHeader); + + // If it's not RGB then create a GUID from the compression type + + if (pbmiHeader->biCompression != BI_RGB) { + if (pbmiHeader->biCompression != BI_BITFIELDS) { + FOURCCMap FourCCMap(pbmiHeader->biCompression); + return (const GUID) FourCCMap; + } + } + + // Map the RGB DIB bit depth to a image GUID + + switch(pbmiHeader->biBitCount) { + case 1 : return MEDIASUBTYPE_RGB1; + case 4 : return MEDIASUBTYPE_RGB4; + case 8 : return MEDIASUBTYPE_RGB8; + case 16 : return GetTrueColorType(pbmiHeader); + case 24 : return MEDIASUBTYPE_RGB24; + case 32 : return MEDIASUBTYPE_RGB32; + } + return GUID_NULL; +} + + +// Given a video bitmap subtype we return the number of bits per pixel it uses +// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the +// GUID subtype is not found in the table we return an invalid USHRT_MAX + +STDAPI_(WORD) GetBitCount(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + while (TRUE) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { + return USHRT_MAX; + } + if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { + return BitCountMap[iPosition].BitCount; + } + iPosition++; + } +} + + +// Given a bitmap subtype we return a description name that can be used for +// debug purposes. In a retail build this function still returns the names +// If the subtype isn't found in the lookup table we return string UNKNOWN + +int LocateSubtype(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + while (TRUE) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,*pSubtype) || + IsEqualGUID(*pMediaSubtype,GUID_NULL) + ) + { + break; + } + + iPosition++; + } + + return iPosition; +} + + + +STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].wszName; +} + +STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].pName; +} + +#ifndef GetSubtypeName +#error wxutil.h should have defined GetSubtypeName +#endif +#undef GetSubtypeName + +// this is here for people that linked to it directly; most people +// would use the header file that picks the A or W version. +STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype) +{ + return GetSubtypeNameA(pSubtype); +} + + +// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER +// This is really messy to deal with because it invariably has fields that +// follow it holding bit fields, palettes and the rest. This function gives +// the number of bytes required to hold a VIDEOINFO that represents it. This +// count includes the prefix information (like the rcSource rectangle) the +// BITMAPINFOHEADER field, and any other colour information on the end. +// +// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make +// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't +// right at the start of the VIDEOINFO (there are a number of other fields), +// +// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); +// + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) +{ + // Everyone has this to start with this + LONG Size = SIZE_PREHEADER + pHeader->biSize; + + ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); + + // Does this format use a palette, if the number of colours actually used + // is zero then it is set to the maximum that are allowed for that colour + // depth (an example is 256 for eight bits). Truecolour formats may also + // pass a palette with them in which case the used count is non zero + + // This would scare me. + ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); + + if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { + LONG Entries = (DWORD) 1 << pHeader->biBitCount; + if (pHeader->biClrUsed) { + Entries = pHeader->biClrUsed; + } + Size += Entries * sizeof(RGBQUAD); + } + + // Truecolour formats may have a BI_BITFIELDS specifier for compression + // type which means that room for three DWORDs should be allocated that + // specify where in each pixel the RGB colour components may be found + + if (pHeader->biCompression == BI_BITFIELDS) { + Size += SIZE_MASKS; + } + + // A BITMAPINFO for a palettised image may also contain a palette map that + // provides the information to map from a source palette to a destination + // palette during a BitBlt for example, because this information is only + // ever processed during drawing you don't normally store the palette map + // nor have any way of knowing if it is present in the data structure + + return Size; +} + + +// Returns TRUE if the VIDEOINFO contains a palette + +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (PALETTISED(pVideoInfo) == FALSE) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + return FALSE; + } + } + return TRUE; +} + + +// Return a pointer to the first entry in a palette + +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return TRUECOLOR(pVideoInfo)->bmiColors; + } + return COLORS(pVideoInfo); +} diff --git a/plugins/gs/gsdx9/baseclasses/audevcod.h b/plugins/gs/gsdx9/baseclasses/audevcod.h new file mode 100644 index 0000000000..d97d4ff6a7 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/audevcod.h @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// File: AudEvCod.h +// +// Desc: List of Audio device error event codes and the expected params. +// +// Copyright (c) 1999-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + + +#ifndef __AUDEVCOD__ +#define __AUDEVCOD__ + + +#define EC_SND_DEVICE_ERROR_BASE 0x0200 + +typedef enum _tagSND_DEVICE_ERROR { + + SNDDEV_ERROR_Open=1, + SNDDEV_ERROR_Close=2, + SNDDEV_ERROR_GetCaps=3, + SNDDEV_ERROR_PrepareHeader=4, + SNDDEV_ERROR_UnprepareHeader=5, + SNDDEV_ERROR_Reset=6, + SNDDEV_ERROR_Restart=7, + SNDDEV_ERROR_GetPosition=8, + SNDDEV_ERROR_Write=9, + SNDDEV_ERROR_Pause=10, + SNDDEV_ERROR_Stop=11, + SNDDEV_ERROR_Start=12, + SNDDEV_ERROR_AddBuffer=13, + SNDDEV_ERROR_Query=14, + +} SNDDEV_ERR; + + +// Sound device error event codes +// ============================== +// +// All audio device error events are always passed on to the application, and are +// never processed by the filter graph + + +#define EC_SNDDEV_IN_ERROR (EC_SND_DEVICE_ERROR_BASE + 0x00) +#define EC_SNDDEV_OUT_ERROR (EC_SND_DEVICE_ERROR_BASE + 0x01) +// Parameters: ( DWORD, DWORD) +// lParam1 is an enum SND_DEVICE_ERROR which notifies the app how the device was +// being accessed when the failure occurred. +// +// lParam2 is the error returned from the sound device call. +// + +#endif // __AUDEVCOD__ diff --git a/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj b/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj new file mode 100644 index 0000000000..77c3619736 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj.REFRACTION.Administrator.user b/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj.REFRACTION.Administrator.user new file mode 100644 index 0000000000..6a3b1f8b6c --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/baseclasses.vcproj.REFRACTION.Administrator.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/plugins/gs/gsdx9/baseclasses/cache.h b/plugins/gs/gsdx9/baseclasses/cache.h new file mode 100644 index 0000000000..d98f262f9c --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/cache.h @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// File: Cache.h +// +// Desc: DirectShow base classes - efines a non-MFC generic cache class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* This class implements a simple cache. A cache object is instantiated + with the number of items it is to hold. An item is a pointer to an + object derived from CBaseObject (helps reduce memory leaks). The cache + can then have objects added to it and removed from it. The cache size + is fixed at construction time and may therefore run out or be flooded. + If it runs out it returns a NULL pointer, if it fills up it also returns + a NULL pointer instead of a pointer to the object just inserted */ + +/* Making these classes inherit from CBaseObject does nothing for their + functionality but it allows us to check there are no memory leaks */ + +/* WARNING Be very careful when using this class, what it lets you do is + store and retrieve objects so that you can minimise object creation + which in turns improves efficiency. However the object you store is + exactly the same as the object you get back which means that it short + circuits the constructor initialisation phase. This means any class + variables the object has (eg pointers) are highly likely to be invalid. + Therefore ensure you reinitialise the object before using it again */ + + +#ifndef __CACHE__ +#define __CACHE__ + + +class CCache : CBaseObject { + + /* Make copy constructor and assignment operator inaccessible */ + + CCache(const CCache &refCache); + CCache &operator=(const CCache &refCache); + +private: + + /* These are initialised in the constructor. The first variable points to + an array of pointers, each of which points to a CBaseObject derived + object. The m_iCacheSize is the static fixed size for the cache and the + m_iUsed defines the number of places filled with objects at any time. + We fill the array of pointers from the start (ie m_ppObjects[0] first) + and then only add and remove objects from the end position, so in this + respect the array of object pointers should be treated as a stack */ + + CBaseObject **m_ppObjects; + const INT m_iCacheSize; + INT m_iUsed; + +public: + + CCache(TCHAR *pName,INT iItems); + virtual ~CCache(); + + /* Add an item to the cache */ + CBaseObject *AddToCache(CBaseObject *pObject); + + /* Remove an item from the cache */ + CBaseObject *RemoveFromCache(); + + /* Delete all the objects held in the cache */ + void RemoveAll(void); + + /* Return the cache size which is set during construction */ + INT GetCacheSize(void) const {return m_iCacheSize;}; +}; + +#endif /* __CACHE__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/combase.cpp b/plugins/gs/gsdx9/baseclasses/combase.cpp new file mode 100644 index 0000000000..3e092af3ca --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/combase.cpp @@ -0,0 +1,256 @@ +//------------------------------------------------------------------------------ +// File: ComBase.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for creating +// COM objects. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions + + +/* Define the static member variable */ + +LONG CBaseObject::m_cObjects = 0; + + +/* Constructor */ + +CBaseObject::CBaseObject(const TCHAR *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef DEBUG + +#ifdef UNICODE + m_dwCookie = DbgRegisterObjectCreation(0, pName); +#else + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif + +#endif +} + +#ifdef UNICODE +CBaseObject::CBaseObject(const char *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif +} +#endif + +HINSTANCE hlibOLEAut32; + +/* Destructor */ + +CBaseObject::~CBaseObject() +{ + /* Decrement the number of objects active */ + if (InterlockedDecrement(&m_cObjects) == 0) { + if (hlibOLEAut32) { + FreeLibrary(hlibOLEAut32); + + hlibOLEAut32 = 0; + } + }; + + +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + +static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); + +HINSTANCE LoadOLEAut32() +{ + if (hlibOLEAut32 == 0) { + + hlibOLEAut32 = LoadLibrary(szOle32Aut); + } + + return hlibOLEAut32; +} + + +/* Constructor */ + +// We know we use "this" in the initialization list, we also know we don't modify *phr. +#pragma warning( disable : 4355 4100 ) +CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk) +: CBaseObject(pName) +/* Start the object with a reference count of zero - when the */ +/* object is queried for it's first interface this may be */ +/* incremented depending on whether or not this object is */ +/* currently being aggregated upon */ +, m_cRef(0) +/* Set our pointer to our IUnknown interface. */ +/* If we have an outer, use its, otherwise use ours. */ +/* This pointer effectivly points to the owner of */ +/* this object and can be accessed by the GetOwner() method. */ +, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) + /* Why the double cast? Well, the inner cast is a type-safe cast */ + /* to pointer to a type from which we inherit. The second is */ + /* type-unsafe but works because INonDelegatingUnknown "behaves */ + /* like" IUnknown. (Only the names on the methods change.) */ +{ + // Everything we need to do has been done in the initializer list +} + +// This does the same as above except it has a useless HRESULT argument +// use the previous constructor, this is just left for compatibility... +CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : + CBaseObject(pName), + m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ +} + +#ifdef UNICODE +CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk) +: CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : + CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +#endif + +#pragma warning( default : 4355 4100 ) + + +/* QueryInterface */ + +STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + + /* We know only about IUnknown */ + + if (riid == IID_IUnknown) { + GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); + return NOERROR; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +/* We have to ensure that we DON'T use a max macro, since these will typically */ +/* lead to one of the parameters being evaluated twice. Since we are worried */ +/* about concurrency, we can't afford to access the m_cRef twice since we can't */ +/* afford to run the risk that its value having changed between accesses. */ + +template inline static T ourmax( const T & a, const T & b ) +{ + return a > b ? a : b; +} + +/* AddRef */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement( &m_cRef ); + ASSERT(lRef > 0); + DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), + m_dwCookie, m_cRef)); + return ourmax(ULONG(m_cRef), 1ul); +} + + +/* Release */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() +{ + /* If the reference count drops to zero delete ourselves */ + + LONG lRef = InterlockedDecrement( &m_cRef ); + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), + m_dwCookie, m_cRef)); + if (lRef == 0) { + + // COM rules say we must protect against re-entrancy. + // If we are an aggregator and we hold our own interfaces + // on the aggregatee, the QI for these interfaces will + // addref ourselves. So after doing the QI we must release + // a ref count on ourselves. Then, before releasing the + // private interface, we must addref ourselves. When we do + // this from the destructor here it will result in the ref + // count going to 1 and then back to 0 causing us to + // re-enter the destructor. Hence we add an extra refcount here + // once we know we will delete the object. + // for an example aggregator see filgraph\distrib.cpp. + + m_cRef++; + + delete this; + return ULONG(0); + } else { + return ourmax(ULONG(m_cRef), 1ul); + } +} + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = pUnk; + pUnk->AddRef(); + return NOERROR; +} + + +/* Compares two interfaces and returns TRUE if they are on the same object */ + +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) +{ + /* Different objects can't have the same interface pointer for + any interface + */ + if (pFirst == pSecond) { + return TRUE; + } + /* OK - do it the hard way - check if they have the same + IUnknown pointers - a single object can only have one of these + */ + LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface + LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface + HRESULT hr; // General OLE return code + + ASSERT(pFirst); + ASSERT(pSecond); + + /* See if the IUnknown pointers match */ + + hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown1); + + hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown2); + + /* Release the extra interfaces we hold */ + + pUnknown1->Release(); + pUnknown2->Release(); + return (pUnknown1 == pUnknown2); +} + diff --git a/plugins/gs/gsdx9/baseclasses/combase.h b/plugins/gs/gsdx9/baseclasses/combase.h new file mode 100644 index 0000000000..34d5ca65cd --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/combase.h @@ -0,0 +1,319 @@ +//------------------------------------------------------------------------------ +// File: ComBase.h +// +// Desc: DirectShow base classes - defines a class hierarchy for creating +// COM objects. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + +a. Derive your COM object from CUnknown + +b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * + and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls + to. The HRESULT * allows error codes to be passed around constructors and + the TCHAR * is a descriptive name that can be printed on the debugger. + + It is important that constructors only change the HRESULT * if they have + to set an ERROR code, if it was successful then leave it alone or you may + overwrite an error code from an object previously created. + + When you call a constructor the descriptive name should be in static store + as we do not copy the string. To stop large amounts of memory being used + in retail builds by all these static strings use the NAME macro, + + CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); + if (FAILED(hr)) { + return hr; + } + + In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class + knows not to do anything with objects that don't have a name. + +c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and + TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an + error, or just simply pass it through to the constructor. + + The object creation will fail in the class factory if the HRESULT indicates + an error (ie FAILED(HRESULT) == TRUE) + +d. Create a FactoryTemplate with your object's class id and CreateInstance + function. + +Then (for each interface) either + +Multiple inheritance + +1. Also derive it from ISomeInterface +2. Include DECLARE_IUNKNOWN in your class definition to declare + implementations of QueryInterface, AddRef and Release that + call the outer unknown +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Declare and implement the member functions of ISomeInterface. + +or: Nested interfaces + +1. Declare a class derived from CUnknown +2. Include DECLARE_IUNKNOWN in your class definition +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Implement the member functions of ISomeInterface. Use GetOwner() to + access the COM object class. + +And in your COM object class: + +5. Make the nested class a friend of the COM object class, and declare + an instance of the nested class as a member of the COM object class. + + NOTE that because you must always pass the outer unknown and an hResult + to the CUnknown constructor you cannot use a default constructor, in + other words you will have to make the member variable a pointer to the + class and make a NEW call in your constructor to actually create it. + +6. override the NonDelegatingQueryInterface with code like this: + + if (riid == IID_ISomeInterface) { + return m_pImplFilter-> + NonDelegatingQueryInterface(IID_ISomeInterface, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +You can have mixed classes which support some interfaces via multiple +inheritance and some via nested classes + +*/ + +#ifndef __COMBASE__ +#define __COMBASE__ + +// Filter Setup data structures no defined in axextend.idl + +typedef REGPINTYPES +AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; + +typedef REGFILTERPINS +AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; + +typedef struct _AMOVIESETUP_FILTER +{ + const CLSID * clsID; + const WCHAR * strName; + DWORD dwMerit; + UINT nPins; + const AMOVIESETUP_PIN * lpPin; +} +AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; + +/* The DLLENTRY module initialises the module handle on loading */ + +extern HINSTANCE g_hInst; + +/* On DLL load remember which platform we are running on */ + +extern DWORD g_amPlatform; +extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx + +/* Version of IUnknown that is renamed to allow a class to support both + non delegating and delegating IUnknowns in the same COM object */ + +#ifndef INONDELEGATINGUNKNOWN_DEFINED +DECLARE_INTERFACE(INonDelegatingUnknown) +{ + STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; + STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; +}; +#define INONDELEGATINGUNKNOWN_DEFINED +#endif + +typedef INonDelegatingUnknown *PNDUNKNOWN; + + +/* This is the base object class that supports active object counting. As + part of the debug facilities we trace every time a C++ object is created + or destroyed. The name of the object has to be passed up through the class + derivation list during construction as you cannot call virtual functions + in the constructor. The downside of all this is that every single object + constructor has to take an object name parameter that describes it */ + +class CBaseObject +{ + +private: + + // Disable the copy constructor and assignment by default so you will get + // compiler errors instead of unexpected behaviour if you pass objects + // by value or assign objects. + CBaseObject(const CBaseObject& objectSrc); // no implementation + void operator=(const CBaseObject& objectSrc); // no implementation + +private: + static LONG m_cObjects; /* Total number of objects active */ + +protected: +#ifdef DEBUG + DWORD m_dwCookie; /* Cookie identifying this object */ +#endif + + +public: + + /* These increment and decrement the number of active objects */ + + CBaseObject(const TCHAR *pName); +#ifdef UNICODE + CBaseObject(const char *pName); +#endif + ~CBaseObject(); + + /* Call this to find if there are any CUnknown derived objects active */ + + static LONG ObjectsActive() { + return m_cObjects; + }; +}; + + +/* An object that supports one or more COM interfaces will be based on + this class. It supports counting of total objects for DLLCanUnloadNow + support, and an implementation of the core non delegating IUnknown */ + +class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, + public CBaseObject +{ +private: + const LPUNKNOWN m_pUnknown; /* Owner of this object */ + +protected: /* So we can override NonDelegatingRelease() */ + volatile LONG m_cRef; /* Number of reference counts */ + +public: + + CUnknown(const TCHAR *pName, LPUNKNOWN pUnk); + virtual ~CUnknown() {}; + + // This is redundant, just use the other constructor + // as we never touch the HRESULT in this anyway + CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr); +#ifdef UNICODE + CUnknown(const char *pName, LPUNKNOWN pUnk); + CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr); +#endif + + /* Return the owner of this object */ + + LPUNKNOWN GetOwner() const { + return m_pUnknown; + }; + + /* Called from the class factory to create a new instance, it is + pure virtual so it must be overriden in your derived class */ + + /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ + + /* Non delegating unknown implementation */ + + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +}; + +#if (_MSC_VER <= 1200) +#pragma warning(disable:4211) + +/* The standard InterlockedXXX functions won't take volatiles */ +static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong ) +{ return InterlockedIncrement( const_cast( plong ) ); } + +static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong ) +{ return InterlockedDecrement( const_cast( plong ) ); } + +#pragma warning(default:4211) +#endif + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv); + +/* A function that can create a new COM object */ + +typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); + +/* A function (can be NULL) which is called from the DLL entrypoint + routine for each factory template: + + bLoading - TRUE on DLL load, FALSE on DLL unload + rclsid - the m_ClsID of the entry +*/ +typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); + +/* Create one of these per object class in an array so that + the default class factory code can create new instances */ + +class CFactoryTemplate { + +public: + + const WCHAR * m_Name; + const CLSID * m_ClsID; + LPFNNewCOMObject m_lpfnNew; + LPFNInitRoutine m_lpfnInit; + const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; + + BOOL IsClassID(REFCLSID rclsid) const { + return (IsEqualCLSID(*m_ClsID,rclsid)); + }; + + CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const { + CheckPointer(phr,NULL); + return m_lpfnNew(pUnk, phr); + }; +}; + + +/* You must override the (pure virtual) NonDelegatingQueryInterface to return + interface pointers (using GetInterface) to the interfaces your derived + class supports (the default implementation only supports IUnknown) */ + +#define DECLARE_IUNKNOWN \ + STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ + return GetOwner()->QueryInterface(riid,ppv); \ + }; \ + STDMETHODIMP_(ULONG) AddRef() { \ + return GetOwner()->AddRef(); \ + }; \ + STDMETHODIMP_(ULONG) Release() { \ + return GetOwner()->Release(); \ + }; + + + +HINSTANCE LoadOLEAut32(); + + +#endif /* __COMBASE__ */ + + + + diff --git a/plugins/gs/gsdx9/baseclasses/comlite.h b/plugins/gs/gsdx9/baseclasses/comlite.h new file mode 100644 index 0000000000..bfdf644e7f --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/comlite.h @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// File: COMLite.h +// +// Desc: This header file is to provide a migration path for users of +// ActiveMovie betas 1 and 2. +// +// Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _INC_COMLITE_ +#define _INC_COMLITE_ + +#define QzInitialize CoInitialize +#define QzUninitialize CoUninitialize +#define QzFreeUnusedLibraries CoFreeUnusedLibraries + +#define QzGetMalloc CoGetMalloc +#define QzTaskMemAlloc CoTaskMemAlloc +#define QzTaskMemRealloc CoTaskMemRealloc +#define QzTaskMemFree CoTaskMemFree +#define QzCreateFilterObject CoCreateInstance +#define QzCLSIDFromString CLSIDFromString +#define QzStringFromGUID2 StringFromGUID2 + +#endif // _INC_COMLITE_ diff --git a/plugins/gs/gsdx9/baseclasses/cprop.cpp b/plugins/gs/gsdx9/baseclasses/cprop.cpp new file mode 100644 index 0000000000..fdb0749010 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/cprop.cpp @@ -0,0 +1,380 @@ +//------------------------------------------------------------------------------ +// File: CProp.cpp +// +// Desc: DirectShow base classes - implements CBasePropertyPage class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +// Constructor for the base property page class. As described in the header +// file we must be initialised with dialog and title resource identifiers. +// The class supports IPropertyPage and overrides AddRef and Release calls +// to keep track of the reference counts. When the last count is released +// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces +// previously obtained by the property page when it had SetObjects called + +CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name + LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} + +#ifdef UNICODE +CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name + LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} +#endif + +// Increment our reference count + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement(&m_cRef); + ASSERT(lRef > 0); + return max(ULONG(m_cRef),1ul); +} + + +// Release a reference count and protect against reentrancy + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() +{ + // If the reference count drops to zero delete ourselves + + if (InterlockedDecrement(&m_cRef) == 0) { + m_cRef++; + SetPageSite(NULL); + SetObjects(0,NULL); + delete this; + return ULONG(0); + } else { + return max(ULONG(m_cRef),1ul); + } +} + + +// Expose our IPropertyPage interface + +STDMETHODIMP +CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv) +{ + if (riid == IID_IPropertyPage) { + return GetInterface((IPropertyPage *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// Get the page info so that the page site can size itself + +STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo) +{ + CheckPointer(pPageInfo,E_POINTER); + WCHAR wszTitle[STR_MAX_LENGTH]; + WideStringFromResource(wszTitle,m_TitleId); + + // Allocate dynamic memory for the property page title + + LPOLESTR pszTitle; + HRESULT hr = AMGetWideString(wszTitle, &pszTitle); + if (FAILED(hr)) { + NOTE("No caption memory"); + return hr; + } + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = pszTitle; + pPageInfo->pszDocString = NULL; + pPageInfo->pszHelpFile = NULL; + pPageInfo->dwHelpContext = 0; + + // Set defaults in case GetDialogSize fails + pPageInfo->size.cx = 340; + pPageInfo->size.cy = 150; + + GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); + return NOERROR; +} + + +// Handles the messages for our property window + +INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + CBasePropertyPage *pPropertyPage; + + switch (uMsg) { + + case WM_INITDIALOG: + + SetWindowLongPtr(hwnd, DWLP_USER, lParam); + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) lParam; + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + pPropertyPage->m_Dlg = hwnd; + } + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// Tells us the object that should be informed of the property changes + +STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk) +{ + if (cObjects == 1) { + + if ((ppUnk == NULL) || (*ppUnk == NULL)) { + return E_POINTER; + } + + // Set a flag to say that we have set the Object + m_bObjectSet = TRUE ; + return OnConnect(*ppUnk); + + } else if (cObjects == 0) { + + // Set a flag to say that we have not set the Object for the page + m_bObjectSet = FALSE ; + return OnDisconnect(); + } + + DbgBreak("No support for more than one object"); + return E_UNEXPECTED; +} + + +// Create the window we will use to edit properties + +STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, + LPCRECT pRect, + BOOL fModal) +{ + CheckPointer(pRect,E_POINTER); + + // Return failure if SetObject has not been called. + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + if (m_hwnd) { + return E_UNEXPECTED; + } + + m_hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(m_DialogId), + hwndParent, + DialogProc, + (LPARAM) this); + if (m_hwnd == NULL) { + return E_OUTOFMEMORY; + } + + OnActivate(); + Move(pRect); + return Show(SW_SHOWNORMAL); +} + + +// Set the position of the property page + +STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) +{ + CheckPointer(pRect,E_POINTER); + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + MoveWindow(m_hwnd, // Property page handle + pRect->left, // x coordinate + pRect->top, // y coordinate + WIDTH(pRect), // Overall window width + HEIGHT(pRect), // And likewise height + TRUE); // Should we repaint it + + return NOERROR; +} + + +// Display the property dialog + +STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) +{ + // Have we been activated yet + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Ignore wrong show flags + + if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { + return E_INVALIDARG; + } + + ShowWindow(m_hwnd,nCmdShow); + InvalidateRect(m_hwnd,NULL,TRUE); + return NOERROR; +} + + +// Destroy the property page dialog + +STDMETHODIMP CBasePropertyPage::Deactivate(void) +{ + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Remove WS_EX_CONTROLPARENT before DestroyWindow call + + DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); + dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); + + // Set m_hwnd to be NULL temporarily so the message handler + // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT + // style back in + HWND hwnd = m_hwnd; + m_hwnd = NULL; + SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); + m_hwnd = hwnd; + + OnDeactivate(); + + // Destroy the dialog window + + DestroyWindow(m_hwnd); + m_hwnd = NULL; + return NOERROR; +} + + +// Tells the application property page site + +STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite) +{ + if (pPageSite) { + + if (m_pPageSite) { + return E_UNEXPECTED; + } + + m_pPageSite = pPageSite; + m_pPageSite->AddRef(); + + } else { + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + m_pPageSite->Release(); + m_pPageSite = NULL; + } + return NOERROR; +} + + +// Apply any changes so far made + +STDMETHODIMP CBasePropertyPage::Apply() +{ + // In ActiveMovie 1.0 we used to check whether we had been activated or + // not. This is too constrictive. Apply should be allowed as long as + // SetObject was called to set an object. So we will no longer check to + // see if we have been activated (ie., m_hWnd != NULL), but instead + // make sure that m_bObjectSet is TRUE (ie., SetObject has been called). + + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + // Must have had a site set + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + // Has anything changed + + if (m_bDirty == FALSE) { + return NOERROR; + } + + // Commit derived class changes + + HRESULT hr = OnApplyChanges(); + if (SUCCEEDED(hr)) { + m_bDirty = FALSE; + } + return hr; +} + + +// Base class definition for message handling + +INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + // we would like the TAB key to move around the tab stops in our property + // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT + // style behind our back, so we need to switch it back on now behind its + // back. Otherwise the tab key will be useless in every page. + // + + CBasePropertyPage *pPropertyPage; + { + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + if (pPropertyPage->m_hwnd == NULL) { + return 0; + } + switch (uMsg) { + case WM_STYLECHANGING: + if (wParam == GWL_EXSTYLE) { + LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; + lpss->styleNew |= WS_EX_CONTROLPARENT; + return 0; + } + } + } + + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + diff --git a/plugins/gs/gsdx9/baseclasses/cprop.h b/plugins/gs/gsdx9/baseclasses/cprop.h new file mode 100644 index 0000000000..4e50350aa0 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/cprop.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// File: CProp.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CPROP__ +#define __CPROP__ + +// Base property page class. Filters typically expose custom properties by +// implementing special control interfaces, examples are IDirectDrawVideo +// and IQualProp on renderers. This allows property pages to be built that +// use the given interface. Applications such as the ActiveMovie OCX query +// filters for the property pages they support and expose them to the user +// +// This class provides all the framework for a property page. A property +// page is a COM object that supports IPropertyPage. We should be created +// with a resource ID for the dialog which we will load when required. We +// should also be given in the constructor a resource ID for a title string +// we will load from the DLLs STRINGTABLE. The property page titles must be +// stored in resource files so that they can be easily internationalised +// +// We have a number of virtual methods (not PURE) that may be overriden in +// derived classes to query for interfaces and so on. These functions have +// simple implementations here that just return NOERROR. Derived classes +// will almost definately have to override the message handler method called +// OnReceiveMessage. We have a static dialog procedure that calls the method +// so that derived classes don't have to fiddle around with the this pointer + +class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown +{ +protected: + + LPPROPERTYPAGESITE m_pPageSite; // Details for our property site + HWND m_hwnd; // Window handle for the page + HWND m_Dlg; // Actual dialog window handle + BOOL m_bDirty; // Has anything been changed + int m_TitleId; // Resource identifier for title + int m_DialogId; // Dialog resource identifier + + static INT_PTR CALLBACK DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +private: + BOOL m_bObjectSet ; // SetObject has been called or not. +public: + + CBasePropertyPage(TCHAR *pName, // Debug only name + LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId); // To get tital + +#ifdef UNICODE + CBasePropertyPage(CHAR *pName, + LPUNKNOWN pUnk, + int DialogId, + int TitleId); +#endif + virtual ~CBasePropertyPage() { }; + DECLARE_IUNKNOWN + + // Override these virtual methods + + virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; }; + virtual HRESULT OnDisconnect() { return NOERROR; }; + virtual HRESULT OnActivate() { return NOERROR; }; + virtual HRESULT OnDeactivate() { return NOERROR; }; + virtual HRESULT OnApplyChanges() { return NOERROR; }; + virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + + // These implement an IPropertyPage interface + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP SetPageSite(LPPROPERTYPAGESITE pPageSite); + STDMETHODIMP Activate(HWND hwndParent,LPCRECT prect,BOOL fModal); + STDMETHODIMP Deactivate(void); + STDMETHODIMP GetPageInfo(LPPROPPAGEINFO pPageInfo); + STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN *ppUnk); + STDMETHODIMP Show(UINT nCmdShow); + STDMETHODIMP Move(LPCRECT prect); + STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; } + STDMETHODIMP Apply(void); + STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; } + STDMETHODIMP TranslateAccelerator(LPMSG lpMsg) { return E_NOTIMPL; } +}; + +#endif // __CPROP__ + diff --git a/plugins/gs/gsdx9/baseclasses/ctlutil.cpp b/plugins/gs/gsdx9/baseclasses/ctlutil.cpp new file mode 100644 index 0000000000..64073d4fc9 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/ctlutil.cpp @@ -0,0 +1,2531 @@ +//------------------------------------------------------------------------------ +// File: CtlUtil.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + + +#include +#include +#include "seekpt.h" + +// 'bool' non standard reserved word +#pragma warning(disable:4237) + + +// --- CBaseDispatch implementation ---------- +CBaseDispatch::~CBaseDispatch() +{ + if (m_pti) { + m_pti->Release(); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CBaseDispatch::GetTypeInfoCount(UINT * pctinfo) +{ + CheckPointer(pctinfo,E_POINTER); + ValidateReadWritePtr(pctinfo,sizeof(UINT *)); + *pctinfo = 1; + return S_OK; +} + + +typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( + const OLECHAR FAR *szFile, + ITypeLib FAR* FAR* pptlib); + +typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, + WORD wVerMajor, + WORD wVerMinor, + LCID lcid, + ITypeLib FAR* FAR* pptlib); + +// attempt to find our type library + +STDMETHODIMP +CBaseDispatch::GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + CheckPointer(pptinfo,E_POINTER); + ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); + HRESULT hr; + + *pptinfo = NULL; + + // we only support one type element + if (0 != itinfo) { + return TYPE_E_ELEMENTNOTFOUND; + } + + if (NULL == pptinfo) { + return E_POINTER; + } + + // always look for neutral + if (NULL == m_pti) { + + LPLOADTYPELIB lpfnLoadTypeLib; + LPLOADREGTYPELIB lpfnLoadRegTypeLib; + ITypeLib *ptlib; + HINSTANCE hInst; + + static const char szTypeLib[] = "LoadTypeLib"; + static const char szRegTypeLib[] = "LoadRegTypeLib"; + static const WCHAR szControl[] = L"control.tlb"; + + // + // Try to get the Ole32Aut.dll module handle. + // + + hInst = LoadOLEAut32(); + if (hInst == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, + szRegTypeLib); + if (lpfnLoadRegTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 + lcid, &ptlib); + + if (FAILED(hr)) { + + // attempt to load directly - this will fill the + // registry in if it finds it + + lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); + if (lpfnLoadTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadTypeLib)(szControl, &ptlib); + if (FAILED(hr)) { + return hr; + } + } + + hr = ptlib->GetTypeInfoOfGuid( + riid, + &m_pti); + + ptlib->Release(); + + if (FAILED(hr)) { + return hr; + } + } + + *pptinfo = m_pti; + m_pti->AddRef(); + return S_OK; +} + + +STDMETHODIMP +CBaseDispatch::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + // although the IDispatch riid is dead, we use this to pass from + // the interface implementation class to us the iid we are talking about. + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); + + if (SUCCEEDED(hr)) { + hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); + + pti->Release(); + } + return hr; +} + + +// --- CMediaControl implementation --------- + +CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +// expose our interfaces IMediaControl and IUnknown + +STDMETHODIMP +CMediaControl::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaControl) { + return GetInterface( (IMediaControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaControl::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaControl::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaControl, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaControl::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaControl, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaControl::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaControl *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaEvent implementation ---------- + + +CMediaEvent::CMediaEvent(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + + +// expose our interfaces IMediaEvent and IUnknown + +STDMETHODIMP +CMediaEvent::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { + return GetInterface( (IMediaEventEx *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaEvent::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaEvent::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaEvent, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaEvent::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaEvent, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaEvent::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaEvent *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaPosition implementation ---------- + + +CMediaPosition::CMediaPosition(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +CMediaPosition::CMediaPosition(const TCHAR * name, + LPUNKNOWN pUnk, + HRESULT * phr) : + CUnknown(name, pUnk) +{ + UNREFERENCED_PARAMETER(phr); +} + + +// expose our interfaces IMediaPosition and IUnknown + +STDMETHODIMP +CMediaPosition::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaPosition) { + return GetInterface( (IMediaPosition *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaPosition::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaPosition::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaPosition, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaPosition::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaPosition, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaPosition::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaPosition *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IMediaPosition and IMediaSeeking pass through class ---------- + + +CPosPassThru::CPosPassThru(const TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + IPin *pPin) : + CMediaPosition(pName,pUnk), + m_pPin(pPin) +{ + if (pPin == NULL) { + *phr = E_POINTER; + return; + } +} + + +// Expose our IMediaSeeking and IMediaPosition interfaces + +STDMETHODIMP +CPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv,E_POINTER); + *ppv = NULL; + + if (riid == IID_IMediaSeeking) { + return GetInterface( static_cast(this), ppv); + } + return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); +} + + +// Return the IMediaPosition interface from our peer + +HRESULT +CPosPassThru::GetPeer(IMediaPosition ** ppMP) +{ + *ppMP = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaPosition * pMP; + hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMP = pMP; + return S_OK; +} + + +// Return the IMediaSeeking interface from our peer + +HRESULT +CPosPassThru::GetPeerSeeking(IMediaSeeking ** ppMS) +{ + *ppMS = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaSeeking * pMS; + hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMS = pMS; + return S_OK; +} + + +// --- IMediaSeeking methods ---------- + + +STDMETHODIMP +CPosPassThru::GetCapabilities(DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::CheckCapabilities(DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->CheckCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::IsFormatSupported(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsFormatSupported(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::QueryPreferredFormat(GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->QueryPreferredFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetTimeFormat(GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsUsingTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::GetPositions(LONGLONG *pCurrent, LONGLONG * pStop) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetPositions(pCurrent,pStop); + pMS->Release(); + return hr; +} + +HRESULT +CPosPassThru::GetSeekingLongLong +( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ) +, LONGLONG * pll +) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (SUCCEEDED(hr)) + { + hr = (pMS->*pMethod)(pll); + pMS->Release(); + } + return hr; +} + +// If we don't have a current position then ask upstream + +STDMETHODIMP +CPosPassThru::GetCurrentPosition(LONGLONG *pCurrent) +{ + // Can we report the current position + HRESULT hr = GetMediaTime(pCurrent,NULL); + if (SUCCEEDED(hr)) hr = NOERROR; + else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetStopPosition(LONGLONG *pStop) +{ + return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );; +} + +STDMETHODIMP +CPosPassThru::GetDuration(LONGLONG *pDuration) +{ + return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );; +} + + +STDMETHODIMP +CPosPassThru::GetPreroll(LONGLONG *pllPreroll) +{ + return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );; +} + + +STDMETHODIMP +CPosPassThru::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetAvailable( pEarliest, pLatest ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetRate(double * pdRate) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->GetRate(pdRate); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->SetRate(dRate); + pMS->Release(); + return hr; +} + + + + +// --- IMediaPosition methods ---------- + + +STDMETHODIMP +CPosPassThru::get_Duration(REFTIME * plength) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + + hr = pMP->get_Duration(plength); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_CurrentPosition(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_CurrentPosition(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_CurrentPosition(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_CurrentPosition(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_StopTime(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_StopTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_StopTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_StopTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_PrerollTime(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_PrerollTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_PrerollTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_PrerollTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_Rate(double * pdRate) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_Rate(pdRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_Rate(dRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekForward(LONG *pCanSeekForward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekForward(pCanSeekForward); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekBackward(LONG *pCanSeekBackward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekBackward(pCanSeekBackward); + pMP->Release(); + return hr; +} + + +// --- Implements the CRendererPosPassThru class ---------- + + +// Media times (eg current frame, field, sample etc) are passed through the +// filtergraph in media samples. When a renderer gets a sample with media +// times in it, it will call one of the RegisterMediaTime methods we expose +// (one takes an IMediaSample, the other takes the media times direct). We +// store the media times internally and return them in GetCurrentPosition. + +CRendererPosPassThru::CRendererPosPassThru(const TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + IPin *pPin) : + CPosPassThru(pName,pUnk,phr,pPin), + m_StartMedia(0), + m_EndMedia(0), + m_bReset(TRUE) +{ +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) +{ + ASSERT(pMediaSample); + LONGLONG StartMedia; + LONGLONG EndMedia; + + CAutoLock cAutoLock(&m_PositionLock); + + // Get the media times from the sample + + HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); + if (FAILED(hr)) + { + ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); + return hr; + } + + m_StartMedia = StartMedia; + m_EndMedia = EndMedia; + m_bReset = FALSE; + return NOERROR; +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = StartTime; + m_EndMedia = EndTime; + m_bReset = FALSE; + return NOERROR; +} + + +// Return the current media times registered in the object + +HRESULT +CRendererPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) +{ + ASSERT(pStartTime); + + CAutoLock cAutoLock(&m_PositionLock); + if (m_bReset == TRUE) { + return E_FAIL; + } + + // We don't have to return the end time + + HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); + if (pEndTime && SUCCEEDED(hr)) { + hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); + } + return hr; +} + + +// Resets the media times we hold + +HRESULT +CRendererPosPassThru::ResetMediaTime() +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = 0; + m_EndMedia = 0; + m_bReset = TRUE; + return NOERROR; +} + +// Intended to be called by the owing filter during EOS processing so +// that the media times can be adjusted to the stop time. This ensures +// that the GetCurrentPosition will actully get to the stop position. +HRESULT +CRendererPosPassThru::EOS() +{ + HRESULT hr; + + if ( m_bReset == TRUE ) hr = E_FAIL; + else + { + LONGLONG llStop; + if SUCCEEDED(hr=GetStopPosition(&llStop)) + { + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = + m_EndMedia = llStop; + } + } + return hr; +} + +// -- CSourceSeeking implementation ------------ + +CSourceSeeking::CSourceSeeking( + const TCHAR * pName, + LPUNKNOWN pUnk, + HRESULT* phr, + CCritSec * pLock) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_rtStart((long)0) +{ + m_rtStop = _I64_MAX / 2; + m_rtDuration = m_rtStop; + m_dRateSeeking = 1.0; + + m_dwSeekingCaps = AM_SEEKING_CanSeekForwards + | AM_SEEKING_CanSeekBackwards + | AM_SEEKING_CanSeekAbsolute + | AM_SEEKING_CanGetStopPos + | AM_SEEKING_CanGetDuration; +} + +HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if(riid == IID_IMediaSeeking) { + CheckPointer(ppv, E_POINTER); + return GetInterface(static_cast(this), ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + // only seeking in time (REFERENCE_TIME units) is supported + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::QueryPreferredFormat(GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + // nothing to set; just check that it's TIME_FORMAT_TIME + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; +} + +HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::GetTimeFormat(GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::GetDuration(LONGLONG *pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CAutoLock lock(m_pLock); + *pDuration = m_rtDuration; + return S_OK; +} + +HRESULT CSourceSeeking::GetStopPosition(LONGLONG *pStop) +{ + CheckPointer(pStop, E_POINTER); + CAutoLock lock(m_pLock); + *pStop = m_rtStop; + return S_OK; +} + +HRESULT CSourceSeeking::GetCurrentPosition(LONGLONG *pCurrent) +{ + // GetCurrentPosition is typically supported only in renderers and + // not in source filters. + return E_NOTIMPL; +} + +HRESULT CSourceSeeking::GetCapabilities( DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + *pCapabilities = m_dwSeekingCaps; + return S_OK; +} + +HRESULT CSourceSeeking::CheckCapabilities( DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + + // make sure all requested capabilities are in our mask + return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; +} + +HRESULT CSourceSeeking::ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ) +{ + CheckPointer(pTarget, E_POINTER); + // format guids can be null to indicate current format + + // since we only support TIME_FORMAT_MEDIA_TIME, we don't really + // offer any conversions. + if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) + { + if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) + { + *pTarget = Source; + return S_OK; + } + } + + return E_INVALIDARG; +} + + +HRESULT CSourceSeeking::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ) +{ + DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; + DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; + + if(StopFlags) { + CheckPointer(pStop, E_POINTER); + + // accept only relative, incremental, or absolute positioning + if(StopPosBits != StopFlags) { + return E_INVALIDARG; + } + } + + if(CurrentFlags) { + CheckPointer(pCurrent, E_POINTER); + if(StartPosBits != AM_SEEKING_AbsolutePositioning && + StartPosBits != AM_SEEKING_RelativePositioning) { + return E_INVALIDARG; + } + } + + + // scope for autolock + { + CAutoLock lock(m_pLock); + + // set start position + if(StartPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStart = *pCurrent; + } + else if(StartPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStart += *pCurrent; + } + + // set stop position + if(StopPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStop = *pStop; + } + else if(StopPosBits == AM_SEEKING_IncrementalPositioning) + { + m_rtStop = m_rtStart + *pStop; + } + else if(StopPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStop = m_rtStop + *pStop; + } + } + + + HRESULT hr = S_OK; + if(SUCCEEDED(hr) && StopPosBits) { + hr = ChangeStop(); + } + if(StartPosBits) { + hr = ChangeStart(); + } + + return hr; +} + + +HRESULT CSourceSeeking::GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ) +{ + if(pCurrent) { + *pCurrent = m_rtStart; + } + if(pStop) { + *pStop = m_rtStop; + } + + return S_OK;; +} + + +HRESULT CSourceSeeking::GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ) +{ + if(pEarliest) { + *pEarliest = 0; + } + if(pLatest) { + CAutoLock lock(m_pLock); + *pLatest = m_rtDuration; + } + return S_OK; +} + +HRESULT CSourceSeeking::SetRate( double dRate) +{ + { + CAutoLock lock(m_pLock); + m_dRateSeeking = dRate; + } + return ChangeRate(); +} + +HRESULT CSourceSeeking::GetRate( double * pdRate) +{ + CheckPointer(pdRate, E_POINTER); + CAutoLock lock(m_pLock); + *pdRate = m_dRateSeeking; + return S_OK; +} + +HRESULT CSourceSeeking::GetPreroll(LONGLONG *pPreroll) +{ + CheckPointer(pPreroll, E_POINTER); + *pPreroll = 0; + return S_OK; +} + + + + + +// --- CSourcePosition implementation ---------- + + +CSourcePosition::CSourcePosition(const TCHAR * pName, + LPUNKNOWN pUnk, + HRESULT* phr, + CCritSec * pLock) : + CMediaPosition(pName, pUnk), + m_pLock(pLock), + m_Start(CRefTime((LONGLONG)0)) +{ + m_Stop = _I64_MAX; + m_Rate = 1.0; +} + + +STDMETHODIMP +CSourcePosition::get_Duration(REFTIME * plength) +{ + CheckPointer(plength,E_POINTER); + ValidateReadWritePtr(plength,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *plength = m_Duration; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_CurrentPosition(REFTIME llTime) +{ + m_pLock->Lock(); + m_Start = llTime; + m_pLock->Unlock(); + + return ChangeStart(); +} + + +STDMETHODIMP +CSourcePosition::get_StopTime(REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *pllTime = m_Stop; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_StopTime(REFTIME llTime) +{ + m_pLock->Lock(); + m_Stop = llTime; + m_pLock->Unlock(); + + return ChangeStop(); +} + + +STDMETHODIMP +CSourcePosition::get_PrerollTime(REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::put_PrerollTime(REFTIME llTime) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::get_Rate(double * pdRate) +{ + CheckPointer(pdRate,E_POINTER); + ValidateReadWritePtr(pdRate,sizeof(double)); + CAutoLock lock(m_pLock); + + *pdRate = m_Rate; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_Rate(double dRate) +{ + m_pLock->Lock(); + m_Rate = dRate; + m_pLock->Unlock(); + + return ChangeRate(); +} + + +// By default we can seek forwards + +STDMETHODIMP +CSourcePosition::CanSeekForward(LONG *pCanSeekForward) +{ + CheckPointer(pCanSeekForward,E_POINTER); + *pCanSeekForward = OATRUE; + return S_OK; +} + + +// By default we can seek backwards + +STDMETHODIMP +CSourcePosition::CanSeekBackward(LONG *pCanSeekBackward) +{ + CheckPointer(pCanSeekBackward,E_POINTER); + *pCanSeekBackward = OATRUE; + return S_OK; +} + + +// --- Implementation of CBasicAudio class ---------- + + +CBasicAudio::CBasicAudio(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + +// overriden to publicise our interfaces + +STDMETHODIMP +CBasicAudio::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicAudio) { + return GetInterface( (IBasicAudio *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicAudio, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBasicAudio::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicAudio, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBasicAudio::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicAudio *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IVideoWindow implementation ---------- + +CBaseVideoWindow::CBaseVideoWindow(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IVideoWindow) { + return GetInterface( (IVideoWindow *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IVideoWindow, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IVideoWindow, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseVideoWindow::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IVideoWindow *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IBasicVideo implementation ---------- + + +CBaseBasicVideo::CBaseBasicVideo(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { + return GetInterface( static_cast(this), ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicVideo, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicVideo, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseBasicVideo::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicVideo *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- Implementation of Deferred Commands ---------- + + +CDispParams::CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr) +{ + cNamedArgs = 0; + rgdispidNamedArgs = NULL; + cArgs = nArgs; + + if (cArgs) { + rgvarg = new VARIANT[cArgs]; + if (NULL == rgvarg) { + cArgs = 0; + if (phr) { + *phr = E_OUTOFMEMORY; + } + return; + } + + for (UINT i = 0; i < cArgs; i++) { + + VARIANT * pDest = &rgvarg[i]; + VARIANT * pSrc = &pArgs[i]; + + pDest->vt = pSrc->vt; + switch(pDest->vt) { + + case VT_I4: + pDest->lVal = pSrc->lVal; + break; + + case VT_UI1: + pDest->bVal = pSrc->bVal; + break; + + case VT_I2: + pDest->iVal = pSrc->iVal; + break; + + case VT_R4: + pDest->fltVal = pSrc->fltVal; + break; + + case VT_R8: + pDest->dblVal = pSrc->dblVal; + break; + + case VT_BOOL: + pDest->boolVal = pSrc->boolVal; + break; + + case VT_ERROR: + pDest->scode = pSrc->scode; + break; + + case VT_CY: + pDest->cyVal = pSrc->cyVal; + break; + + case VT_DATE: + pDest->date = pSrc->date; + break; + + case VT_BSTR: + if (pSrc->bstrVal == NULL) { + pDest->bstrVal = NULL; + } else { + + // a BSTR is a WORD followed by a UNICODE string. + // the pointer points just after the WORD + + WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); + OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; + if (pch) { + WORD *pui = (WORD*)pch; + *pui = len; + pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); + CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); + } else { + cArgs = i; + if (phr) { + *phr = E_OUTOFMEMORY; + } + } + } + pDest->bstrVal = pSrc->bstrVal; + break; + + case VT_UNKNOWN: + pDest->punkVal = pSrc->punkVal; + pDest->punkVal->AddRef(); + break; + + case VT_DISPATCH: + pDest->pdispVal = pSrc->pdispVal; + pDest->pdispVal->AddRef(); + break; + + default: + // a type we haven't got round to adding yet! + ASSERT(0); + break; + } + } + + } else { + rgvarg = NULL; + } + +} + + +CDispParams::~CDispParams() +{ + for (UINT i = 0; i < cArgs; i++) { + switch(rgvarg[i].vt) { + case VT_BSTR: + if (rgvarg[i].bstrVal != NULL) { + OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); + delete pch; + } + break; + + case VT_UNKNOWN: + rgvarg[i].punkVal->Release(); + break; + + case VT_DISPATCH: + rgvarg[i].pdispVal->Release(); + break; + } + } + delete[] rgvarg; +} + + +// lifetime is controlled by refcounts (see defer.h) + +CDeferredCommand::CDeferredCommand( + CCmdQueue * pQ, + LPUNKNOWN pUnk, + HRESULT * phr, + LPUNKNOWN pUnkExecutor, + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long nArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ) : + CUnknown(NAME("DeferredCommand"), pUnk), + m_pQueue(pQ), + m_pUnk(pUnkExecutor), + m_iid(iid), + m_dispidMethod(dispidMethod), + m_wFlags(wFlags), + m_DispParams(nArgs, pDispParams, phr), + m_pvarResult(pvarResult), + m_bStream(bStream), + m_hrResult(E_ABORT) + +{ + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(time); + m_time = convertor; + + // no check of time validity - it's ok to queue a command that's + // already late + + // check iid is supportable on pUnk by QueryInterface for it + IUnknown * pInterface; + HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + *phr = hr; + return; + } + pInterface->Release(); + + + // !!! check dispidMethod and param/return types using typelib + ITypeInfo *pti; + hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); + if (FAILED(hr)) { + *phr = hr; + return; + } + // !!! some sort of ITypeInfo validity check here + pti->Release(); + + + // Fix up the dispid for put and get + if (wFlags == DISPATCH_PROPERTYPUT) { + m_DispParams.cNamedArgs = 1; + m_DispId = DISPID_PROPERTYPUT; + m_DispParams.rgdispidNamedArgs = &m_DispId; + } + + // all checks ok - add to queue + hr = pQ->Insert(this); + if (FAILED(hr)) { + *phr = hr; + } +} + + +// refcounts are held by caller of InvokeAt... and by list. So if +// we get here, we can't be on the list + +#if 0 +CDeferredCommand::~CDeferredCommand() +{ + // this assert is invalid since if the queue is deleted while we are + // still on the queue, we will have been removed by the queue and this + // m_pQueue will not have been modified. + // ASSERT(m_pQueue == NULL); + + // we don't hold a ref count on pUnk, which is the object that should + // execute the command. + // This is because there would otherwise be a circular refcount problem + // since pUnk probably owns the CmdQueue object that has a refcount + // on us. + // The lifetime of pUnk is guaranteed by it being part of, or lifetime + // controlled by, our parent object. As long as we are on the list, pUnk + // must be valid. Once we are off the list, we do not use pUnk. + +} +#endif + + +// overriden to publicise our interfaces + +STDMETHODIMP +CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IDeferredCommand) { + return GetInterface( (IDeferredCommand *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// remove from q. this will reduce the refcount by one (since the q +// holds a count) but can't make us go away since he must have a +// refcount in order to call this method. + +STDMETHODIMP +CDeferredCommand::Cancel() +{ + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + m_pQueue = NULL; + return S_OK; +} + + +STDMETHODIMP +CDeferredCommand::Confidence(LONG* pConfidence) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CDeferredCommand::GetHResult(HRESULT * phrResult) +{ + CheckPointer(phrResult,E_POINTER); + ValidateReadWritePtr(phrResult,sizeof(HRESULT)); + + if (m_pQueue != NULL) { + return E_ABORT; + } + *phrResult = m_hrResult; + return S_OK; +} + + +// set the time to be a new time (checking that it is valid) and +// then requeue + +STDMETHODIMP +CDeferredCommand::Postpone(REFTIME newtime) +{ + + // check that this time is not past + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(newtime); + + // check that the time has not passed + if (m_pQueue->CheckTime(convertor, IsStreamTime())) { + return VFW_E_TIME_ALREADY_PASSED; + } + + // extract from list + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + // change time + m_time = convertor; + + // requeue + hr = m_pQueue->Insert(this); + + return hr; +} + + +HRESULT +CDeferredCommand::Invoke() +{ + // check that we are still outstanding + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + // get the type info + ITypeInfo* pti; + HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); + if (FAILED(hr)) { + return hr; + } + + // qi for the expected interface and then invoke it. Note that we have to + // treat the returned interface as IUnknown since we don't know its type. + IUnknown* pInterface; + + hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + pti->Release(); + return hr; + } + + EXCEPINFO expinfo; + UINT uArgErr; + m_hrResult = pti->Invoke( + pInterface, + GetMethod(), + GetFlags(), + GetParams(), + GetResult(), + &expinfo, + &uArgErr); + + // release the interface we QI'd for + pInterface->Release(); + pti->Release(); + + + // remove from list whether or not successful + // or we loop indefinitely + hr = m_pQueue->Remove(this); + m_pQueue = NULL; + return hr; +} + + + +// --- CCmdQueue methods ---------- + + +CCmdQueue::CCmdQueue() : + m_listPresentation(NAME("Presentation time command list")), + m_listStream(NAME("Stream time command list")), + m_evDue(TRUE), // manual reset + m_dwAdvise(0), + m_pClock(NULL), + m_bRunning(FALSE) +{ +} + + +CCmdQueue::~CCmdQueue() +{ + // empty all our lists + + // we hold a refcount on each, so traverse and Release each + // entry then RemoveAll to empty the list + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); + pCmd->Release(); + } + m_listPresentation.RemoveAll(); + + pos = m_listStream.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listStream.GetNext(pos); + pCmd->Release(); + } + m_listStream.RemoveAll(); + + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } +} + + +// returns a new CDeferredCommand object that will be initialised with +// the parameters and will be added to the queue during construction. +// returns S_OK if successfully created otherwise an error and +// no object has been queued. + +HRESULT +CCmdQueue::New( + CDeferredCommand **ppCmd, + LPUNKNOWN pUnk, // this object will execute command + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream +) +{ + CAutoLock lock(&m_Lock); + + HRESULT hr = S_OK; + *ppCmd = NULL; + + CDeferredCommand* pCmd; + pCmd = new CDeferredCommand( + this, + NULL, // not aggregated + &hr, + pUnk, // this guy will execute + time, + iid, + dispidMethod, + wFlags, + cArgs, + pDispParams, + pvarResult, + puArgErr, + bStream); + + if (pCmd == NULL) { + hr = E_OUTOFMEMORY; + } else { + *ppCmd = pCmd; + } + return hr; +} + + +HRESULT +CCmdQueue::Insert(CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + + // addref the item + pCmd->AddRef(); + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + WXLIST_POSITION pos = pList->GetHeadPosition(); + + // seek past all items that are before us + while (pos && + (pList->Get(pos)->GetTime() <= pCmd->GetTime())) { + + pList->GetNext(pos); + } + + // now at end of list or in front of items that come later + if (!pos) { + pList->AddTail(pCmd); + } else { + pList->AddBefore(pos, pCmd); + } + + SetTimeAdvise(); + return S_OK; +} + + +HRESULT +CCmdQueue::Remove(CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + HRESULT hr = S_OK; + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + WXLIST_POSITION pos = pList->GetHeadPosition(); + + // traverse the list + while (pos && (pList->Get(pos) != pCmd)) { + pList->GetNext(pos); + } + + // did we drop off the end? + if (!pos) { + hr = VFW_E_NOT_FOUND; + } else { + + // found it - now take off list + pList->Remove(pos); + + // Insert did an AddRef, so release it + pCmd->Release(); + + // check that timer request is still for earliest time + SetTimeAdvise(); + } + return hr; +} + + +// set the clock used for timing + +HRESULT +CCmdQueue::SetSyncSource(IReferenceClock* pClock) +{ + CAutoLock lock(&m_Lock); + + // addref the new clock first in case they are the same + if (pClock) { + pClock->AddRef(); + } + + // kill any advise on the old clock + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } + m_pClock = pClock; + + // set up a new advise + SetTimeAdvise(); + return S_OK; +} + + +// set up a timer event with the reference clock + +void +CCmdQueue::SetTimeAdvise(void) +{ + // make sure we have a clock to use + if (!m_pClock) { + return; + } + + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + + // time 0 is earliest + CRefTime current; + + // find the earliest presentation time + if (m_listPresentation.GetCount() > 0) { + + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + current = m_listPresentation.Get(pos)->GetTime(); + } + + // if we're running, check the stream times too + if (m_bRunning) { + + CRefTime t; + + if (m_listStream.GetCount() > 0) { + + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + t = m_listStream.Get(pos)->GetTime(); + + // add on stream time offset to get presentation time + t += m_StreamTimeOffset; + + // is this earlier? + if ((current == TimeZero) || (t < current)) { + current = t; + } + } + } + + // need to change? + if ((current > TimeZero) && (current != m_tCurrentAdvise)) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + } + + // ask for time advice - the first two params are either + // stream time offset and stream time or + // presentation time and 0. we always use the latter + HRESULT hr = m_pClock->AdviseTime( + (REFERENCE_TIME)current, + TimeZero, + (HEVENT) HANDLE(m_evDue), + &m_dwAdvise); + + ASSERT(SUCCEEDED(hr)); + m_tCurrentAdvise = current; + } +} + + +// switch to run mode. Streamtime to Presentation time mapping known. + +HRESULT +CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) +{ + CAutoLock lock(&m_Lock); + + m_StreamTimeOffset = tStreamTimeOffset; + m_bRunning = TRUE; + + // ensure advise is accurate + SetTimeAdvise(); + return S_OK; +} + + +// switch to Stopped or Paused mode. Time mapping not known. + +HRESULT +CCmdQueue::EndRun() +{ + CAutoLock lock(&m_Lock); + + m_bRunning = FALSE; + + // check timer setting - stream times + SetTimeAdvise(); + return S_OK; +} + + +// return a pointer to the next due command. Blocks for msTimeout +// milliseconds until there is a due command. +// Stream-time commands will only become due between Run and Endrun calls. +// The command remains queued until invoked or cancelled. +// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout) +{ + // loop until we timeout or find a due command + for (;;) { + + { + CAutoLock lock(&m_Lock); + + + // find the earliest command + CDeferredCommand * pCmd = NULL; + + // check the presentation time and the + // stream time list to find the earliest + + if (m_listPresentation.GetCount() > 0) { + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + pCmd = m_listPresentation.Get(pos); + } + + if (m_bRunning && (m_listStream.GetCount() > 0)) { + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + CDeferredCommand* pStrm = m_listStream.Get(pos); + + CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; + if (!pCmd || (t < pCmd->GetTime())) { + pCmd = pStrm; + } + } + + // if we have found one, is it due? + if (pCmd) { + if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { + + // yes it's due - addref it + pCmd->AddRef(); + *ppCmd = pCmd; + return S_OK; + } + } + } + + // block until the advise is signalled + if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { + return E_ABORT; + } + } +} + + +// return a pointer to a command that will be due for a given time. +// Pass in a stream time here. The stream time offset will be passed +// in via the Run method. +// Commands remain queued until invoked or cancelled. +// This method will not block. It will report E_ABORT if there are no +// commands due yet. +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, CDeferredCommand**ppCmd) +{ + CAutoLock lock(&m_Lock); + + CRefTime tStream(rtStream); + + // find the earliest stream and presentation time commands + CDeferredCommand* pStream = NULL; + if (m_listStream.GetCount() > 0) { + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + pStream = m_listStream.Get(pos); + } + CDeferredCommand* pPresent = NULL; + if (m_listPresentation.GetCount() > 0) { + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + pPresent = m_listPresentation.Get(pos); + } + + // is there a presentation time that has passed already + if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { + pPresent->AddRef(); + *ppCmd = pPresent; + return S_OK; + } + + // is there a stream time command due before this stream time + if (pStream && (pStream->GetTime() <= tStream)) { + pPresent->AddRef(); + *ppCmd = pStream; + return S_OK; + } + + // if we are running, we can map presentation times to + // stream time. In this case, is there a presentation time command + // that will be due before this stream time is presented? + if (m_bRunning && pPresent) { + + // this stream time will appear at... + tStream += m_StreamTimeOffset; + + // due before that? + if (pPresent->GetTime() <= tStream) { + *ppCmd = pPresent; + return S_OK; + } + } + + // no commands due yet + return VFW_E_NOT_FOUND; +} + diff --git a/plugins/gs/gsdx9/baseclasses/ctlutil.h b/plugins/gs/gsdx9/baseclasses/ctlutil.h new file mode 100644 index 0000000000..5df80c0d00 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/ctlutil.h @@ -0,0 +1,919 @@ +//------------------------------------------------------------------------------ +// File: CtlUtil.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + +#ifndef __CTLUTIL__ +#define __CTLUTIL__ + +// OLE Automation has different ideas of TRUE and FALSE + +#define OATRUE (-1) +#define OAFALSE (0) + + +// It's possible that we could replace this class with CreateStdDispatch + +class CBaseDispatch +{ + ITypeInfo * m_pti; + +public: + + CBaseDispatch() : m_pti(NULL) {} + ~CBaseDispatch(); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); +}; + + +class AM_NOVTABLE CMediaControl : + public IMediaControl, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaControl(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaEvent : + public IMediaEventEx, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaEvent(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaPosition : + public IMediaPosition, + public CUnknown +{ + CBaseDispatch m_basedisp; + + +public: + + CMediaPosition(const TCHAR *, LPUNKNOWN); + CMediaPosition(const TCHAR *, LPUNKNOWN, HRESULT *phr); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); + +}; + + +// OA-compatibility means that we must use double as the RefTime value, +// and REFERENCE_TIME (essentially a LONGLONG) within filters. +// this class converts between the two + +class COARefTime : public CRefTime { +public: + + COARefTime() { + }; + + COARefTime(CRefTime t) + : CRefTime(t) + { + }; + + COARefTime(REFERENCE_TIME t) + : CRefTime(t) + { + }; + + COARefTime(double d) { + m_time = (LONGLONG) (d * 10000000); + }; + + operator double() { + return double(m_time) / 10000000; + }; + + operator REFERENCE_TIME() { + return m_time; + }; + + COARefTime& operator=(const double& rd) { + m_time = (LONGLONG) (rd * 10000000); + return *this; + } + + COARefTime& operator=(const REFERENCE_TIME& rt) { + m_time = rt; + return *this; + } + + inline BOOL operator==(const COARefTime& rt) + { + return m_time == rt.m_time; + }; + + inline BOOL operator!=(const COARefTime& rt) + { + return m_time != rt.m_time; + }; + + inline BOOL operator < (const COARefTime& rt) + { + return m_time < rt.m_time; + }; + + inline BOOL operator > (const COARefTime& rt) + { + return m_time > rt.m_time; + }; + + inline BOOL operator >= (const COARefTime& rt) + { + return m_time >= rt.m_time; + }; + + inline BOOL operator <= (const COARefTime& rt) + { + return m_time <= rt.m_time; + }; + + inline COARefTime operator+(const COARefTime& rt) + { + return COARefTime(m_time + rt.m_time); + }; + + inline COARefTime operator-(const COARefTime& rt) + { + return COARefTime(m_time - rt.m_time); + }; + + inline COARefTime operator*(LONG l) + { + return COARefTime(m_time * l); + }; + + inline COARefTime operator/(LONG l) + { + return COARefTime(m_time / l); + }; + +private: + // Prevent bugs from constructing from LONG (which gets + // converted to double and then multiplied by 10000000 + COARefTime(LONG); + int operator=(LONG); +}; + + +// A utility class that handles IMediaPosition and IMediaSeeking on behalf +// of single-input pin renderers, or transform filters. +// +// Renderers will expose this from the filter; transform filters will +// expose it from the output pin and not the renderer. +// +// Create one of these, giving it your IPin* for your input pin, and delegate +// all IMediaPosition methods to it. It will query the input pin for +// IMediaPosition and respond appropriately. +// +// Call ForceRefresh if the pin connection changes. +// +// This class no longer caches the upstream IMediaPosition or IMediaSeeking +// it acquires it on each method call. This means ForceRefresh is not needed. +// The method is kept for source compatibility and to minimise the changes +// if we need to put it back later for performance reasons. + +class CPosPassThru : public IMediaSeeking, public CMediaPosition +{ + IPin *m_pPin; + + HRESULT GetPeer(IMediaPosition **ppMP); + HRESULT GetPeerSeeking(IMediaSeeking **ppMS); + +public: + + CPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); + DECLARE_IUNKNOWN + + HRESULT ForceRefresh() { + return S_OK; + }; + + // override to return an accurate current position + virtual HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) { + return E_FAIL; + } + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(GUID *pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP IsFormatSupported( const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat( GUID *pFormat); + STDMETHODIMP ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ); + STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); + STDMETHODIMP GetCurrentPosition( LONGLONG * pCurrent ); + STDMETHODIMP GetStopPosition( LONGLONG * pStop ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( double * pdRate); + STDMETHODIMP GetDuration( LONGLONG *pDuration); + STDMETHODIMP GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ); + STDMETHODIMP GetPreroll( LONGLONG *pllPreroll ); + + // IMediaPosition properties + STDMETHODIMP get_Duration(REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(REFTIME * pllTime); + STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); + +private: + HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), + LONGLONG * pll ); +}; + + +// Adds the ability to return a current position + +class CRendererPosPassThru : public CPosPassThru +{ + CCritSec m_PositionLock; // Locks access to our position + LONGLONG m_StartMedia; // Start media time last seen + LONGLONG m_EndMedia; // And likewise the end media + BOOL m_bReset; // Have media times been set + +public: + + // Used to help with passing media times through graph + + CRendererPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); + HRESULT RegisterMediaTime(IMediaSample *pMediaSample); + HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); + HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime); + HRESULT ResetMediaTime(); + HRESULT EOS(); +}; + +STDAPI CreatePosPassThru( + LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + IUnknown **ppPassThru +); + +// A class that handles the IDispatch part of IBasicAudio and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBasicAudio(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +// A class that handles the IDispatch part of IBasicVideo and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseBasicVideo(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); + + STDMETHODIMP GetPreferredAspectRatio( + long *plAspectX, + long *plAspectY) + { + return E_NOTIMPL; + } +}; + + +// A class that handles the IDispatch part of IVideoWindow and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseVideoWindow(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +// abstract class to help source filters with their implementation +// of IMediaPosition. Derive from this and set the duration (and stop +// position). Also override NotifyChange to do something when the properties +// change. + +class AM_NOVTABLE CSourcePosition : public CMediaPosition +{ + +public: + CSourcePosition(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); + + // IMediaPosition methods + STDMETHODIMP get_Duration(REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); + + // override if you can return the data you are actually working on + STDMETHODIMP get_CurrentPosition(REFTIME * pllTime) { + return E_NOTIMPL; + }; + +protected: + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + COARefTime m_Duration; + COARefTime m_Start; + COARefTime m_Stop; + double m_Rate; + + CCritSec * m_pLock; +}; + +class AM_NOVTABLE CSourceSeeking : + public IMediaSeeking, + public CUnknown +{ + +public: + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IMediaSeeking methods + + STDMETHODIMP IsFormatSupported(const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat(GUID *pFormat); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(GUID *pFormat); + STDMETHODIMP GetDuration(LONGLONG *pDuration); + STDMETHODIMP GetStopPosition(LONGLONG *pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG *pCurrent); + STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); + STDMETHODIMP ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ); + + STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); + + STDMETHODIMP GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( double * pdRate); + STDMETHODIMP GetPreroll(LONGLONG *pPreroll); + + +protected: + + // ctor + CSourceSeeking(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + CRefTime m_rtDuration; // length of stream + CRefTime m_rtStart; // source will start here + CRefTime m_rtStop; // source will stop here + double m_dRateSeeking; + + // seeking capabilities + DWORD m_dwSeekingCaps; + + CCritSec * m_pLock; +}; + + +// Base classes supporting Deferred commands. + +// Deferred commands are queued by calls to methods on the IQueueCommand +// interface, exposed by the filtergraph and by some filters. A successful +// call to one of these methods will return an IDeferredCommand interface +// representing the queued command. +// +// A CDeferredCommand object represents a single deferred command, and exposes +// the IDeferredCommand interface as well as other methods permitting time +// checks and actual execution. It contains a reference to the CCommandQueue +// object on which it is queued. +// +// CCommandQueue is a base class providing a queue of CDeferredCommand +// objects, and methods to add, remove, check status and invoke the queued +// commands. A CCommandQueue object would be part of an object that +// implemented IQueueCommand. + +class CCmdQueue; + +// take a copy of the params and store them. Release any allocated +// memory in destructor + +class CDispParams : public DISPPARAMS +{ +public: + CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr = NULL); + ~CDispParams(); +}; + + +// CDeferredCommand lifetime is controlled by refcounts. Caller of +// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue +// object also holds a refcount on us. Calling Cancel or Invoke takes +// us off the CCmdQueue and thus reduces the refcount by 1. Once taken +// off the queue we cannot be put back on the queue. + +class CDeferredCommand + : public CUnknown, + public IDeferredCommand +{ +public: + + CDeferredCommand( + CCmdQueue * pQ, + LPUNKNOWN pUnk, // aggregation outer unk + HRESULT * phr, + LPUNKNOWN pUnkExecutor, // object that will execute this cmd + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IDeferredCommand methods + STDMETHODIMP Cancel(); + STDMETHODIMP Confidence( + LONG* pConfidence); + STDMETHODIMP Postpone( + REFTIME newtime); + STDMETHODIMP GetHResult( + HRESULT* phrResult); + + // other public methods + + HRESULT Invoke(); + + // access methods + + // returns TRUE if streamtime, FALSE if presentation time + BOOL IsStreamTime() { + return m_bStream; + }; + + CRefTime GetTime() { + return m_time; + }; + + REFIID GetIID() { + return *m_iid; + }; + + long GetMethod() { + return m_dispidMethod; + }; + + short GetFlags() { + return m_wFlags; + }; + + DISPPARAMS* GetParams() { + return &m_DispParams; + }; + + VARIANT* GetResult() { + return m_pvarResult; + }; + +protected: + + CCmdQueue* m_pQueue; + + // pUnk for the interface that we will execute the command on + LPUNKNOWN m_pUnk; + + // stored command data + REFERENCE_TIME m_time; + GUID* m_iid; + long m_dispidMethod; + short m_wFlags; + VARIANT* m_pvarResult; + BOOL m_bStream; + CDispParams m_DispParams; + DISPID m_DispId; // For get and put + + // we use this for ITypeInfo access + CBaseDispatch m_Dispatch; + + // save retval here + HRESULT m_hrResult; +}; + + +// a list of CDeferredCommand objects. this is a base class providing +// the basics of access to the list. If you want to use CDeferredCommand +// objects then your queue needs to be derived from this class. + +class AM_NOVTABLE CCmdQueue +{ +public: + CCmdQueue(); + virtual ~CCmdQueue(); + + // returns a new CDeferredCommand object that will be initialised with + // the parameters and will be added to the queue during construction. + // returns S_OK if successfully created otherwise an error and + // no object has been queued. + virtual HRESULT New( + CDeferredCommand **ppCmd, + LPUNKNOWN pUnk, + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ); + + // called by the CDeferredCommand object to add and remove itself + // from the queue + virtual HRESULT Insert(CDeferredCommand* pCmd); + virtual HRESULT Remove(CDeferredCommand* pCmd); + + // Command-Due Checking + // + // There are two schemes of synchronisation: coarse and accurate. In + // coarse mode, you wait till the time arrives and then execute the cmd. + // In accurate mode, you wait until you are processing the sample that + // will appear at the time, and then execute the command. It's up to the + // filter which one it will implement. The filtergraph will always + // implement coarse mode for commands queued at the filtergraph. + // + // If you want coarse sync, you probably want to wait until there is a + // command due, and then execute it. You can do this by calling + // GetDueCommand. If you have several things to wait for, get the + // event handle from GetDueHandle() and when this is signalled then call + // GetDueCommand. Stream time will only advance between calls to Run and + // EndRun. Note that to avoid an extra thread there is no guarantee that + // if the handle is set there will be a command ready. Each time the + // event is signalled, call GetDueCommand (probably with a 0 timeout); + // This may return E_ABORT. + // + // If you want accurate sync, you must call GetCommandDueFor, passing + // as a parameter the stream time of the samples you are about to process. + // This will return: + // -- a stream-time command due at or before that stream time + // -- a presentation-time command due at or before the + // time that stream time will be presented (only between Run + // and EndRun calls, since outside of this, the mapping from + // stream time to presentation time is not known. + // -- any presentation-time command due now. + // This means that if you want accurate synchronisation on samples that + // might be processed during Paused mode, you need to use + // stream-time commands. + // + // In all cases, commands remain queued until Invoked or Cancelled. The + // setting and resetting of the event handle is managed entirely by this + // queue object. + + // set the clock used for timing + virtual HRESULT SetSyncSource(IReferenceClock*); + + // switch to run mode. Streamtime to Presentation time mapping known. + virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); + + // switch to Stopped or Paused mode. Time mapping not known. + virtual HRESULT EndRun(); + + // return a pointer to the next due command. Blocks for msTimeout + // milliseconds until there is a due command. + // Stream-time commands will only become due between Run and Endrun calls. + // The command remains queued until invoked or cancelled. + // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). + // Returns an AddRef-ed object + virtual HRESULT GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout); + + // return the event handle that will be signalled whenever + // there are deferred commands due for execution (when GetDueCommand + // will not block). + HANDLE GetDueHandle() { + return HANDLE(m_evDue); + }; + + // return a pointer to a command that will be due for a given time. + // Pass in a stream time here. The stream time offset will be passed + // in via the Run method. + // Commands remain queued until invoked or cancelled. + // This method will not block. It will report VFW_E_NOT_FOUND if there + // are no commands due yet. + // Returns an AddRef-ed object + virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, CDeferredCommand**ppCmd); + + // check if a given time is due (TRUE if it is due yet) + BOOL CheckTime(CRefTime time, BOOL bStream) { + + // if no clock, nothing is due! + if (!m_pClock) { + return FALSE; + } + + // stream time + if (bStream) { + + // not valid if not running + if (!m_bRunning) { + return FALSE; + } + // add on known stream time offset to get presentation time + time += m_StreamTimeOffset; + } + + CRefTime Now; + m_pClock->GetTime((REFERENCE_TIME*)&Now); + return (time <= Now); + }; + +protected: + + // protect access to lists etc + CCritSec m_Lock; + + // commands queued in presentation time are stored here + CGenericList m_listPresentation; + + // commands queued in stream time are stored here + CGenericList m_listStream; + + // set when any commands are due + CAMEvent m_evDue; + + // creates an advise for the earliest time required, if any + void SetTimeAdvise(void); + + // advise id from reference clock (0 if no outstanding advise) + DWORD_PTR m_dwAdvise; + + // advise time is for this presentation time + CRefTime m_tCurrentAdvise; + + // the reference clock we are using (addrefed) + IReferenceClock* m_pClock; + + // true when running + BOOL m_bRunning; + + // contains stream time offset when m_bRunning is true + CRefTime m_StreamTimeOffset; +}; + +#endif // __CTLUTIL__ diff --git a/plugins/gs/gsdx9/baseclasses/ddmm.cpp b/plugins/gs/gsdx9/baseclasses/ddmm.cpp new file mode 100644 index 0000000000..834ce990bb --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/ddmm.cpp @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +// File: DDMM.cpp +// +// Desc: DirectShow base classes - implements routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include +#include "ddmm.h" + +/* + * FindDeviceCallback + */ +typedef struct { + LPSTR szDevice; + GUID* lpGUID; + GUID GUID; + BOOL fFound; +} FindDeviceData; + +BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +/* + * DirectDrawCreateFromDevice + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} + + +/* + * DirectDrawCreateFromDeviceEx + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, + DDENUM_ATTACHEDSECONDARYDEVICES); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} diff --git a/plugins/gs/gsdx9/baseclasses/ddmm.h b/plugins/gs/gsdx9/baseclasses/ddmm.h new file mode 100644 index 0000000000..678bec3f66 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/ddmm.h @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// File: DDMM.h +// +// Desc: DirectShow base classes - efines routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// DDRAW.H might not include these +#ifndef DDENUM_ATTACHEDSECONDARYDEVICES +#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L +#endif + +typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); +typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); + +IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM); +IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/plugins/gs/gsdx9/baseclasses/dllentry.cpp b/plugins/gs/gsdx9/baseclasses/dllentry.cpp new file mode 100644 index 0000000000..be9fd1c32a --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dllentry.cpp @@ -0,0 +1,333 @@ +//------------------------------------------------------------------------------ +// File: DllEntry.cpp +// +// Desc: DirectShow base classes - implements classes used to support dll +// entry points for COM objects. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#include +#include + +#ifdef DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE + +#endif // DEBUG + +extern CFactoryTemplate g_Templates[]; +extern int g_cTemplates; + +HINSTANCE g_hInst; +DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) +OSVERSIONINFO g_osInfo; + +// +// an instance of this is created by the DLLGetClassObject entrypoint +// it uses the CFactoryTemplate object it is given to support the +// IClassFactory interface + +class CClassFactory : public IClassFactory, public CBaseObject +{ + +private: + const CFactoryTemplate *const m_pTemplate; + + ULONG m_cRef; + + static int m_cLocked; +public: + CClassFactory(const CFactoryTemplate *); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); + STDMETHODIMP_(ULONG)AddRef(); + STDMETHODIMP_(ULONG)Release(); + + // IClassFactory + STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv); + STDMETHODIMP LockServer(BOOL fLock); + + // allow DLLGetClassObject to know about global server lock status + static BOOL IsLocked() { + return (m_cLocked > 0); + }; +}; + +// process-wide dll locked state +int CClassFactory::m_cLocked = 0; + +CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) +: CBaseObject(NAME("Class Factory")) +, m_cRef(0) +, m_pTemplate(pTemplate) +{ +} + + +STDMETHODIMP +CClassFactory::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv,E_POINTER) + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + // any interface on this object is the object pointer. + if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { + *ppv = (LPVOID) this; + // AddRef returned interface pointer + ((LPUNKNOWN) *ppv)->AddRef(); + return NOERROR; + } + + return ResultFromScode(E_NOINTERFACE); +} + + +STDMETHODIMP_(ULONG) +CClassFactory::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) +CClassFactory::Release() +{ + if (--m_cRef == 0) { + delete this; + return 0; + } else { + return m_cRef; + } +} + +STDMETHODIMP +CClassFactory::CreateInstance( + LPUNKNOWN pUnkOuter, + REFIID riid, + void **pv) +{ + CheckPointer(pv,E_POINTER) + ValidateReadWritePtr(pv,sizeof(void *)); + + /* Enforce the normal OLE rules regarding interfaces and delegation */ + + if (pUnkOuter != NULL) { + if (IsEqualIID(riid,IID_IUnknown) == FALSE) { + return ResultFromScode(E_NOINTERFACE); + } + } + + /* Create the new object through the derived class's create function */ + + HRESULT hr = NOERROR; + CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); + + if (pObj == NULL) { + if (SUCCEEDED(hr)) { + hr = E_OUTOFMEMORY; + } + return hr; + } + + /* Delete the object if we got a construction error */ + + if (FAILED(hr)) { + delete pObj; + return hr; + } + + /* Get a reference counted interface on the object */ + + /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ + /* This protects any outer object from being prematurely */ + /* released by an inner object that may have to be created */ + /* in order to supply the requested interface. */ + pObj->NonDelegatingAddRef(); + hr = pObj->NonDelegatingQueryInterface(riid, pv); + pObj->NonDelegatingRelease(); + /* Note that if NonDelegatingQueryInterface fails, it will */ + /* not increment the ref count, so the NonDelegatingRelease */ + /* will drop the ref back to zero and the object will "self-*/ + /* destruct". Hence we don't need additional tidy-up code */ + /* to cope with NonDelegatingQueryInterface failing. */ + + if (SUCCEEDED(hr)) { + ASSERT(*pv); + } + + return hr; +} + +STDMETHODIMP +CClassFactory::LockServer(BOOL fLock) +{ + if (fLock) { + m_cLocked++; + } else { + m_cLocked--; + } + return NOERROR; +} + + +// --- COM entrypoints ----------------------------------------- + +//called by COM to get the class factory object for a given class +STDAPI +DllGetClassObject( + REFCLSID rClsID, + REFIID riid, + void **pv) +{ + if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { + return E_NOINTERFACE; + } + + // traverse the array of templates looking for one with this + // class id + for (int i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->IsClassID(rClsID)) { + + // found a template - make a class factory based on this + // template + + *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); + if (*pv == NULL) { + return E_OUTOFMEMORY; + } + ((LPUNKNOWN)*pv)->AddRef(); + return NOERROR; + } + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +// +// Call any initialization routines +// +void +DllInitClasses(BOOL bLoading) +{ + int i; + + // traverse the array of templates calling the init routine + // if they have one + for (i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->m_lpfnInit != NULL) { + (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); + } + } + +} + +// called by COM to determine if this dll can be unloaded +// return ok unless there are outstanding objects or a lock requested +// by IClassFactory::LockServer +// +// CClassFactory has a static function that can tell us about the locks, +// and CCOMObject has a static function that can tell us about the active +// object count +STDAPI +DllCanUnloadNow() +{ + DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), + CClassFactory::IsLocked(), + CBaseObject::ObjectsActive())); + + if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { + return S_FALSE; + } else { + return S_OK; + } +} + + +// --- standard WIN32 entrypoints -------------------------------------- + + +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); + +BOOL WINAPI +DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv) +{ +#ifdef DEBUG + extern bool g_fDbgInDllEntryPoint; + g_fDbgInDllEntryPoint = true; +#endif + + switch (ulReason) + { + + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstance); + DbgInitialise(hInstance); + + { + // The platform identifier is used to work out whether + // full unicode support is available or not. Hence the + // default will be the lowest common denominator - i.e. N/A + g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails + + g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); + if (GetVersionEx(&g_osInfo)) { + g_amPlatform = g_osInfo.dwPlatformId; + } else { + DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); + } + } + + g_hInst = hInstance; + DllInitClasses(TRUE); + break; + + case DLL_PROCESS_DETACH: + DllInitClasses(FALSE); + +#ifdef DEBUG + if (CBaseObject::ObjectsActive()) { + DbgSetModuleLevel(LOG_MEMORY, 2); + TCHAR szInfo[512]; + extern TCHAR m_ModuleName[]; // Cut down module name + + TCHAR FullName[_MAX_PATH]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(NULL,FullName,_MAX_PATH); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), + pName, GetCurrentProcessId(), GetCurrentThreadId()); + DWORD cch = lstrlen(szInfo); + + (void)StringCchPrintf(szInfo+cch, NUMELMS(szInfo) - cch, TEXT("Module %s, %d objects left active!"), + m_ModuleName, CBaseObject::ObjectsActive()); + DbgAssert(szInfo, TEXT(__FILE__),__LINE__); + + // If running remotely wait for the Assert to be acknowledged + // before dumping out the object register + DbgDumpObjectRegister(); + } + DbgTerminate(); +#endif + break; + } + +#ifdef DEBUG + g_fDbgInDllEntryPoint = false; +#endif + return TRUE; +} + + diff --git a/plugins/gs/gsdx9/baseclasses/dllsetup.cpp b/plugins/gs/gsdx9/baseclasses/dllsetup.cpp new file mode 100644 index 0000000000..a6551b89d4 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dllsetup.cpp @@ -0,0 +1,727 @@ +//------------------------------------------------------------------------------ +// File: DllSetup.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +//--------------------------------------------------------------------------- +// defines and constants + +#define MAX_KEY_LEN 260 + +#ifdef UNICODE +static LPCTSTR CLSID_KEY_FORMAT_STRING = TEXT("CLSID\\%s"); +#else +static LPCTSTR CLSID_KEY_FORMAT_STRING = TEXT("CLSID\\%S"); +#endif + +//--------------------------------------------------------------------------- +// externally defined functions/variable + +extern int g_cTemplates; +extern CFactoryTemplate g_Templates[]; + + +//--------------------------------------------------------------------------- +// internally defined functions + +static HRESULT +ConvertUnicodeStringToTCHARString( LPTSTR szDest, size_t cchDest, LPCWSTR szSource ); + +//--------------------------------------------------------------------------- +// +// EliminateSubKey +// +// Try to enumerate all keys under this one. +// if we find anything, delete it completely. +// Otherwise just delete it. +// +// note - this was pinched/duplicated from +// Filgraph\Mapper.cpp - so should it be in +// a lib somewhere? +// +//--------------------------------------------------------------------------- + +STDAPI +EliminateSubKey( HKEY hkey, LPTSTR strSubKey ) +{ + HKEY hk; + if (0 == lstrlen(strSubKey) ) { + // defensive approach + return E_FAIL; + } + + LONG lreturn = RegOpenKeyEx( hkey + , strSubKey + , 0 + , MAXIMUM_ALLOWED + , &hk ); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_FILE_NOT_FOUND + || lreturn == ERROR_INVALID_HANDLE ); + + if( ERROR_SUCCESS == lreturn ) + { + // Keep on enumerating the first (zero-th) + // key and deleting that + + for( ; ; ) + { + TCHAR Buffer[MAX_KEY_LEN]; + DWORD dw = MAX_KEY_LEN; + FILETIME ft; + + lreturn = RegEnumKeyEx( hk + , 0 + , Buffer + , &dw + , NULL + , NULL + , NULL + , &ft); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_NO_MORE_ITEMS ); + + if( ERROR_SUCCESS == lreturn ) + { + EliminateSubKey(hk, Buffer); + } + else + { + break; + } + } + + RegCloseKey(hk); + RegDeleteKey(hkey, strSubKey); + } + + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterServer() +// +// registers specfied file "szFileName" as server for +// CLSID "clsServer". A description is also required. +// The ThreadingModel and ServerType are optional, as +// they default to InprocServer32 (i.e. dll) and Both. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterServer( CLSID clsServer + , LPCWSTR szDescription + , LPCWSTR szFileName + , LPCWSTR szThreadingModel = L"Both" + , LPCWSTR szServerType = L"InprocServer32" ) +{ + // temp buffer + // + TCHAR achTemp[MAX_PATH]; + + // convert CLSID uuid to string and write + // out subkey as string - CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + + // create key + // + HKEY hkey; + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), CLSID_KEY_FORMAT_STRING, szCLSID ); + + LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT + , (LPCTSTR)achTemp + , &hkey ); + if( ERROR_SUCCESS != lreturn ) + { + return AmHresultFromWin32(lreturn); + } + + // set description string + // + + (void)ConvertUnicodeStringToTCHARString( achTemp, NUMELMS(achTemp), szDescription ); + lreturn = RegSetValue( hkey + , (LPCTSTR)NULL + , REG_SZ + , achTemp + , sizeof(achTemp) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // create CLSID\\{"CLSID"}\\"ServerType" key, + // using key to CLSID\\{"CLSID"} passed back by + // last call to RegCreateKey(). + // + HKEY hsubkey; + + (void)ConvertUnicodeStringToTCHARString( achTemp, NUMELMS(achTemp), szServerType ); + lreturn = RegCreateKey( hkey + , achTemp + , &hsubkey ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // set Server string + // + (void)ConvertUnicodeStringToTCHARString( achTemp, NUMELMS(achTemp), szFileName ); + lreturn = RegSetValue( hsubkey + , (LPCTSTR)NULL + , REG_SZ + , (LPCTSTR)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + return AmHresultFromWin32(lreturn); + } + + (void)ConvertUnicodeStringToTCHARString( achTemp, NUMELMS(achTemp), szThreadingModel ); + lreturn = RegSetValueEx( hsubkey + , TEXT("ThreadingModel") + , 0L + , REG_SZ + , (CONST BYTE *)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + + // close hkeys + // + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + + // and return + // + return HRESULT_FROM_WIN32(lreturn); + +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupUnregisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupUnregisterServer( CLSID clsServer ) +{ + // convert CLSID uuid to string and write + // out subkey CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + + TCHAR achBuffer[MAX_KEY_LEN]; + (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), CLSID_KEY_FORMAT_STRING, szCLSID ); + + // delete subkey + // + + hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer ); + ASSERT( SUCCEEDED(hr) ); + + // return + // + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterFilter through IFilterMapper2 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM2->UnregisterFilter( + 0, // default category + 0, // default instance name + *psetupdata->clsID ); + + + if( bRegister ) + { + REGFILTER2 rf2; + rf2.dwVersion = 1; + rf2.dwMerit = psetupdata->dwMerit; + rf2.cPins = psetupdata->nPins; + rf2.rgPins = psetupdata->lpPin; + + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM2->RegisterFilter(*psetupdata->clsID + , psetupdata->strName + , 0 // moniker + , 0 // category + , NULL // instance + , &rf2); + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//--------------------------------------------------------------------------- +// +// RegisterAllServers() +// +//--------------------------------------------------------------------------- + +STDAPI +RegisterAllServers( LPCWSTR szFileName, BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), + (LPCWSTR)pT->m_Name )); + + // register CLSID and InprocServer32 + // + if( bRegister ) + { + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , szFileName ); + } + else + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer2() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllRegisterServer2( BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()"))); + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + // WIN95 doesn't support GetModuleFileNameW + // + { + char achTemp[MAX_PATH]; + + DbgLog((LOG_TRACE, 2, TEXT("- get module file name"))); + + // g_hInst handle is set in our dll entry point. Make sure + // DllEntryPoint in dllentry.cpp is called + ASSERT(g_hInst != 0); + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // + // first registering, register all OLE servers + // + if( bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, TRUE ); + } + + // + // next, register/unregister all filters + // + + if( SUCCEEDED(hr) ) + { + // init is ref counted so call just in case + // we're being called cold. + // + DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize"))); + hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper2 + // + DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2"))); + IFilterMapper2 *pIFM2 = 0; + IFilterMapper *pIFM = 0; + hr = CoCreateInstance( CLSID_FilterMapper2 + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper2 + , (void **)&pIFM2 ); + if(FAILED(hr)) + { + DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead"))); + + hr = CoCreateInstance( + CLSID_FilterMapper, + NULL, + CLSCTX_INPROC_SERVER, + IID_IFilterMapper, + (void **)&pIFM); + } + if( SUCCEEDED(hr) ) + { + // scan through array of CFactoryTemplates + // registering servers and filters. + // + DbgLog((LOG_TRACE, 2, TEXT("- register Filters"))); + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + if( NULL != pT->m_pAMovieSetup_Filter ) + { + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name )); + + if(pIFM2) + { + hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister ); + } + else + { + hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister ); + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + // release interface + // + if(pIFM2) + pIFM2->Release(); + else + pIFM->Release(); + + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + } + + // + // if unregistering, unregister all OLE servers + // + if( SUCCEEDED(hr) && !bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, FALSE ); + } + + DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr)); + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + + +STDAPI +AMovieDllRegisterServer( void ) +{ + HRESULT hr = NOERROR; + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + { + // WIN95 doesn't support GetModuleFileNameW + // + char achTemp[MAX_PATH]; + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // scan through array of CFactoryTemplates + // registering servers and filters. + // + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // register CLSID and InprocServer32 + // + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , achFileName ); + + // instantiate all servers and get hold of + // IAMovieSetup, if implemented, and call + // IAMovieSetup.Register() method + // + if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + if( SUCCEEDED(hr) ) + hr = psetup->Register(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + + } // end-for + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllUnregisterServer() +// +// default ActiveMovie dll uninstall function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it calls the IAMovieSetup.Unregister +// method and then unregisters the Dll +// as the InprocServer32 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllUnregisterServer() +{ + // initialize return code + // + HRESULT hr = NOERROR; + + // scan through CFactory template and unregister + // all OLE servers and filters. + // + for( int i = g_cTemplates; i--; ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // check method exists + // + if( NULL != pT->m_lpfnNew ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // unregister CLSID and InprocServer32 + // + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} + +static HRESULT +ConvertUnicodeStringToTCHARString( LPTSTR szDest, size_t cchDest, LPCWSTR szSource ) +{ + HRESULT hr = NOERROR; + + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%s"); + #else + LPCTSTR FORMAT_STRING = TEXT("%S"); + #endif + + hr = StringCchPrintf( szDest, cchDest, FORMAT_STRING, szSource ); + if( FAILED( hr ) ) + { + return hr; + } + + return S_OK; +} + diff --git a/plugins/gs/gsdx9/baseclasses/dllsetup.h b/plugins/gs/gsdx9/baseclasses/dllsetup.h new file mode 100644 index 0000000000..a43d2fda5c --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dllsetup.h @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// File: DllSetup.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// To be self registering, OLE servers must +// export functions named DllRegisterServer +// and DllUnregisterServer. To allow use of +// custom and default implementations the +// defaults are named AMovieDllRegisterServer +// and AMovieDllUnregisterServer. +// +// To the use the default implementation you +// must provide stub functions. +// +// i.e. STDAPI DllRegisterServer() +// { +// return AMovieDllRegisterServer(); +// } +// +// STDAPI DllUnregisterServer() +// { +// return AMovieDllUnregisterServer(); +// } +// +// +// AMovieDllRegisterServer calls IAMovieSetup.Register(), and +// AMovieDllUnregisterServer calls IAMovieSetup.Unregister(). + +STDAPI AMovieDllRegisterServer2( BOOL ); +STDAPI AMovieDllRegisterServer(); +STDAPI AMovieDllUnregisterServer(); + +// helper functions +STDAPI EliminateSubKey( HKEY, LPTSTR ); + + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ); + diff --git a/plugins/gs/gsdx9/baseclasses/dshow.h b/plugins/gs/gsdx9/baseclasses/dshow.h new file mode 100644 index 0000000000..19115a82f2 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dshow.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// File: DShow.h +// +// Desc: DirectShow top-level include file +// +// Copyright (c) 2000-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#ifndef __DSHOW_INCLUDED__ +#define __DSHOW_INCLUDED__ + +/////////////////////////////////////////////////////////////////////////// +// Set up constants & pragmas for the compiler +/////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// disable some level-4 warnings, use #pragma warning(default:###) to re-enable +#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated +#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated +#pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" + +#if _MSC_VER>=1100 +#define AM_NOVTABLE __declspec(novtable) +#else +#define AM_NOVTABLE +#endif +#endif // MSC_VER + +/////////////////////////////////////////////////////////////////////////// +// Include standard Windows files +/////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + +#ifndef NO_DSHOW_STRSAFE +#define NO_SHLWAPI_STRFCNS +#include +#endif + +#ifndef NUMELMS + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#endif + +/////////////////////////////////////////////////////////////////////////// +// Include DirectShow include files +/////////////////////////////////////////////////////////////////////////// +#include // Generated IDL header file for streams interfaces +#include // ActiveMovie video interfaces and definitions +#include // ActiveMovie audio interfaces and definitions +#include // generated from control.odl +#include // event code definitions +#include // declaration of type GUIDs and well-known clsids +#include // HRESULT status and error definitions +#include // External device control interface defines +#include // audio filter device error event codes +#include // DVD error event codes + +/////////////////////////////////////////////////////////////////////////// +// Define OLE Automation constants +/////////////////////////////////////////////////////////////////////////// +#ifndef OATRUE +#define OATRUE (-1) +#endif // OATRUE +#ifndef OAFALSE +#define OAFALSE (0) +#endif // OAFALSE + +/////////////////////////////////////////////////////////////////////////// +// Define Win64 interfaces if not already defined +/////////////////////////////////////////////////////////////////////////// + +// InterlockedExchangePointer +#ifndef InterlockedExchangePointer +#define InterlockedExchangePointer(Target, Value) \ + (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) +#endif + + +#endif // __DSHOW_INCLUDED__ diff --git a/plugins/gs/gsdx9/baseclasses/dsschedule.h b/plugins/gs/gsdx9/baseclasses/dsschedule.h new file mode 100644 index 0000000000..cc21b1c3ce --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dsschedule.h @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// File: DSSchedule.h (replaces DirectX 8's schedule.h) +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) + {} + + void InsertAfter( CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/plugins/gs/gsdx9/baseclasses/dvdevcod.h b/plugins/gs/gsdx9/baseclasses/dvdevcod.h new file mode 100644 index 0000000000..82f43d0615 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dvdevcod.h @@ -0,0 +1,363 @@ +//------------------------------------------------------------------------------ +// File: DVDevCod.h +// +// Desc: List of standard DVD-Video event codes and the expected params. +// +// Copyright (c) 1992 - 2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#ifndef __DVDEVCOD__ +#define __DVDEVCOD__ + + +#define EC_DVDBASE 0x0100 + +#ifndef EXCLUDE_DVDEVCODE_ENUMS + +typedef enum _tagDVD_ERROR { + DVD_ERROR_Unexpected=1, // Something unexpected happened, perhaps content + // is incorrectly authored. Playback is stopped. + DVD_ERROR_CopyProtectFail=2, // Key exchange for DVD copy protection failed. + // Playback is stopped. + DVD_ERROR_InvalidDVD1_0Disc=3, // DVD-Video disc is incorrectly authored for v1.0 + // of spec. Playback is stopped. + DVD_ERROR_InvalidDiscRegion=4, // The Disc cannot be played because the disc is not + // authored to play in system region. + // The region mismatch may be fixable by + // changing the system region with dvdrgn.exe + DVD_ERROR_LowParentalLevel=5, // Player parental level is lower than the lowest parental + // level available in the DVD content. Playback is stopped. + DVD_ERROR_MacrovisionFail=6, // Macrovision Distribution Failed. + // Playback is stopped. + DVD_ERROR_IncompatibleSystemAndDecoderRegions=7, + // No discs can be played because the system region + // does not match the decoder region. + DVD_ERROR_IncompatibleDiscAndDecoderRegions=8 + // The disc cannot be played because the disc is + // not authored to be played in the decoder's region +} DVD_ERROR; + +typedef enum _tagDVD_WARNING { + DVD_WARNING_InvalidDVD1_0Disc=1,// DVD-Video disc is incorrectly authored. Playback + // can continue, but unexpected behavior may occur. + DVD_WARNING_FormatNotSupported=2,// A decoder would not support the current format. Playback + // of a stream (audio, video of SP) may not function. + // lParam2 contains the stream type (see AM_DVD_STREAM_FLAGS) + DVD_WARNING_IllegalNavCommand=3,// The internal DVD navigation command processor attempted to + // process an illegal command. + DVD_WARNING_Open = 4, // File Open Failed + DVD_WARNING_Seek = 5, // File Seek Failed + DVD_WARNING_Read = 6 // File Read Failed +} DVD_WARNING; + +typedef enum _tagDVD_PB_STOPPED { + DVD_PB_STOPPED_Other=0, // The navigator stopped the playback (no reason available). + DVD_PB_STOPPED_NoBranch=1, // The nav completed the current pgc and there was no more video and + // did not find any other branching instruction for subsequent playback. + DVD_PB_STOPPED_NoFirstPlayDomain =2, // The disc does not contain an initial startup program. + DVD_PB_STOPPED_StopCommand = 3, // The app issued a stop() command or a stop command was authored on the disc. + DVD_PB_STOPPED_Reset=4, // The navigator was reset to the start of the disc (using ResetOnStop). + DVD_PB_STOPPED_DiscEjected=5, // The disc was ejected. + DVD_PB_STOPPED_IllegalNavCommand = 6, // An illegal nav command prevented playback from continuing. + DVD_PB_STOPPED_PlayPeriodAutoStop = 7, // PlayPeriod completed + DVD_PB_STOPPED_PlayChapterAutoStop = 8, // PlayChapter completed + DVD_PB_STOPPED_ParentalFailure = 9, // A parental level failure prevented playback + DVD_PB_STOPPED_RegionFailure = 10, // A region failure prevented playback + DVD_PB_STOPPED_MacrovisionFailure = 11, // A Macrovision failure prevented playback. + DVD_PB_STOPPED_DiscReadError = 12, // A read error prevented playback. + DVD_PB_STOPPED_CopyProtectFailure = 13 // Copy protection failure. +} DVD_PB_STOPPED; + + +#endif + +// DVD-Video event codes +// ====================== +// +// All DVD-Video event are always passed on to the application, and are +// never processed by the filter graph + + +#define EC_DVD_DOMAIN_CHANGE (EC_DVDBASE + 0x01) +// Parameters: ( DWORD, void ) +// lParam1 is enum DVD_DOMAIN, and indicates the player's new domain +// +// Raised from following domains: all +// +// Signaled when ever the DVD player changes domains. + + +#define EC_DVD_TITLE_CHANGE (EC_DVDBASE + 0x02) +// Parameters: ( DWORD, void ) +// lParam1 is the new title number. +// +// Raised from following domains: DVD_DOMAIN_Title +// +// Indicates when the current title number changes. Title numbers +// range 1 to 99. This indicates the TTN, which is the title number +// with respect to the whole disc, not the VTS_TTN which is the title +// number with respect to just a current VTS. + + +#define EC_DVD_CHAPTER_START (EC_DVDBASE + 0x03) +// Parameters: ( DWORD, void ) +// lParam1 is the new chapter number (which is the program number for +// One_Sequential_PGC_Titles). +// +// Raised from following domains: DVD_DOMAIN_Title +// +// Signales that DVD player started playback of a new program in the Title +// domain. This is only signaled for One_Sequential_PGC_Titles. + + +#define EC_DVD_AUDIO_STREAM_CHANGE (EC_DVDBASE + 0x04) +// Parameters: ( DWORD, void ) +// lParam1 is the new user audio stream number. +// +// Raised from following domains: all +// +// Signaled when ever the current user audio stream number changes for the main +// title. This can be changed automatically with a navigation command on disc +// as well as through IDVDAnnexJ. +// Audio stream numbers range from 0 to 7. Stream 0xffffffff +// indicates that no stream is selected. + +#define EC_DVD_SUBPICTURE_STREAM_CHANGE (EC_DVDBASE + 0x05) +// Parameters: ( DWORD, BOOL ) +// lParam1 is the new user subpicture stream number. +// lParam2 is the subpicture's on/off state (TRUE if on) +// +// Raised from following domains: all +// +// Signaled when ever the current user subpicture stream number changes for the main +// title. This can be changed automatically with a navigation command on disc +// as well as through IDVDAnnexJ. +// Subpicture stream numbers range from 0 to 31. Stream 0xffffffff +// indicates that no stream is selected. + +#define EC_DVD_ANGLE_CHANGE (EC_DVDBASE + 0x06) +// Parameters: ( DWORD, DWORD ) +// lParam1 is the number of available angles. +// lParam2 is the current user angle number. +// +// Raised from following domains: all +// +// Signaled when ever either +// a) the number of available angles changes, or +// b) the current user angle number changes. +// Current angle number can be changed automatically with navigation command +// on disc as well as through IDVDAnnexJ. +// When the number of available angles is 1, the current video is not multiangle. +// Angle numbers range from 1 to 9. + + +#define EC_DVD_BUTTON_CHANGE (EC_DVDBASE + 0x07) +// Parameters: ( DWORD, DWORD ) +// lParam1 is the number of available buttons. +// lParam2 is the current selected button number. +// +// Raised from following domains: all +// +// Signaled when ever either +// a) the number of available buttons changes, or +// b) the current selected button number changes. +// The current selected button can be changed automatically with navigation +// commands on disc as well as through IDVDAnnexJ. +// Button numbers range from 1 to 36. Selected button number 0 implies that +// no button is selected. Note that these button numbers enumerate all +// available button numbers, and do not always correspond to button numbers +// used for IDVDAnnexJ::ButtonSelectAndActivate since only a subset of buttons +// may be activated with ButtonSelectAndActivate. + + +#define EC_DVD_VALID_UOPS_CHANGE (EC_DVDBASE + 0x08) +// Parameters: ( DWORD, void ) +// lParam1 is a VALID_UOP_SOMTHING_OR_OTHER bit-field stuct which indicates +// which IDVDAnnexJ commands are explicitly disable by the DVD disc. +// +// Raised from following domains: all +// +// Signaled when ever the available set of IDVDAnnexJ methods changes. This +// only indicates which operations are explicited disabled by the content on +// the DVD disc, and does not guarentee that it is valid to call methods +// which are not disabled. For example, if no buttons are currently present, +// IDVDAnnexJ::ButtonActivate() won't work, even though the buttons are not +// explicitly disabled. + + +#define EC_DVD_STILL_ON (EC_DVDBASE + 0x09) +// Parameters: ( BOOL, DWORD ) +// lParam1 == 0 --> buttons are available, so StillOff won't work +// lParam1 == 1 --> no buttons available, so StillOff will work +// lParam2 indicates the number of seconds the still will last, with 0xffffffff +// indicating an infinite still (wait till button or StillOff selected). +// +// Raised from following domains: all +// +// Signaled at the beginning of any still: PGC still, Cell Still, or VOBU Still. +// Note that all combinations of buttons and still are possible (buttons on with +// still on, buttons on with still off, button off with still on, button off +// with still off). + +#define EC_DVD_STILL_OFF (EC_DVDBASE + 0x0a) +// Parameters: ( void, void ) +// +// Indicating that any still that is currently active +// has been released. +// +// Raised from following domains: all +// +// Signaled at the end of any still: PGC still, Cell Still, or VOBU Still. +// + +#define EC_DVD_CURRENT_TIME (EC_DVDBASE + 0x0b) +// Parameters: ( DWORD, BOOL ) +// lParam1 is a DVD_TIMECODE which indicates the current +// playback time code in a BCD HH:MM:SS:FF format. +// lParam2 == 0 --> time code is 25 frames/sec +// lParam2 == 1 --> time code is 30 frames/sec (non-drop). +// lParam2 == 2 --> time code is invalid (current playback time +// cannot be determined for current title) +// +// Raised from following domains: DVD_DOMAIN_Title +// +// Signaled at the beginning of every VOBU, which occurs every .4 to 1.0 sec. +// This is only signaled for One_Sequential_PGC_Titles. + + +#define EC_DVD_ERROR (EC_DVDBASE + 0x0c) +// Parameters: ( DWORD, void) +// lParam1 is an enum DVD_ERROR which notifies the app of some error condition. +// +// Raised from following domains: all +// + +#define EC_DVD_WARNING (EC_DVDBASE + 0x0d) +// Parameters: ( DWORD, DWORD) +// lParam1 is an enum DVD_WARNING which notifies the app of some warning condition. +// lParam2 contains more specific information about the warning (warning dependent) +// +// Raised from following domains: all +// + +#define EC_DVD_CHAPTER_AUTOSTOP (EC_DVDBASE + 0x0e) +// Parameters: (BOOL, void) +// lParam1 is a BOOL which indicates the reason for the cancellation of ChapterPlayAutoStop +// lParam1 == 0 indicates successful completion of ChapterPlayAutoStop +// lParam1 == 1 indicates that ChapterPlayAutoStop is being cancelled as a result of another +// IDVDControl call or the end of content has been reached & no more chapters +// can be played. +// Indicating that playback is stopped as a result of a call +// to IDVDControl::ChapterPlayAutoStop() +// +// Raised from following domains : DVD_DOMAIN_TITLE +// + +#define EC_DVD_NO_FP_PGC (EC_DVDBASE + 0x0f) +// Parameters : (void, void) +// +// Raised from the following domains : FP_DOM +// +// Indicates that the DVD disc does not have a FP_PGC (First Play Program Chain) +// and the DVD Navigator will not automatically load any PGC and start playback. +// + +#define EC_DVD_PLAYBACK_RATE_CHANGE (EC_DVDBASE + 0x10) +// Parameters : (LONG, void) +// lParam1 is a LONG indicating the new playback rate. +// lParam1 < 0 indicates reverse playback mode. +// lParam1 > 0 indicates forward playback mode +// Value of lParam1 is the actual playback rate multiplied by 10000. +// i.e. lParam1 = rate * 10000 +// +// Raised from the following domains : TT_DOM +// +// Indicates that a rate change in playback has been initiated and the parameter +// lParam1 indicates the new playback rate that is being used. +// + +#define EC_DVD_PARENTAL_LEVEL_CHANGE (EC_DVDBASE + 0x11) +// Parameters : (LONG, void) +// lParam1 is a LONG indicating the new parental level. +// +// Raised from the following domains : VMGM_DOM +// +// Indicates that an authored Nav command has changed the parental level +// setting in the player. +// + +#define EC_DVD_PLAYBACK_STOPPED (EC_DVDBASE + 0x12) +// Parameters : (DWORD, void) +// +// Raised from the following domains : All Domains +// +// Indicates that playback has been stopped as the Navigator has completed +// playback of the pgc and did not find any other branching instruction for +// subsequent playback. +// +// The DWORD returns the reason for the completion of the playback. See +// The DVD_PB_STOPPED enumeration for details. +// + +#define EC_DVD_ANGLES_AVAILABLE (EC_DVDBASE + 0x13) +// Parameters : (BOOL, void) +// lParam1 == 0 indicates that playback is not in an angle block and angles are +// not available +// lParam1 == 1 indicates that an angle block is being played back and angle changes +// can be performed. +// +// Indicates whether an angle block is being played and if angle changes can be +// performed. However, angle changes are not restricted to angle blocks and the +// manifestation of the angle change can be seen only in an angle block. + +#define EC_DVD_PLAYPERIOD_AUTOSTOP (EC_DVDBASE + 0x14) +// Parameters: (void, void) +// Sent when the PlayPeriodInTitle completes or is cancelled +// +// Raised from following domains : DVD_DOMAIN_TITLE +// + +#define EC_DVD_BUTTON_AUTO_ACTIVATED (EC_DVDBASE + 0x15) +// Parameters: (DWORD button, void) +// Sent when a button is automatically activated +// +// Raised from following domains : DVD_DOMAIN_MENU +// + +#define EC_DVD_CMD_START (EC_DVDBASE + 0x16) +// Parameters: (CmdID, HRESULT) +// Sent when a command begins +// + +#define EC_DVD_CMD_END (EC_DVDBASE + 0x17) +// Parameters: (CmdID, HRESULT) +// Sent when a command completes +// + +#define EC_DVD_DISC_EJECTED (EC_DVDBASE + 0x18) +// Parameters: none +// Sent when the nav detects that a disc was ejected and stops the playback +// The app does not need to take any action to stop the playback. +// + +#define EC_DVD_DISC_INSERTED (EC_DVDBASE + 0x19) +// Parameters: none +// Sent when the nav detects that a disc was inserted and the nav begins playback +// The app does not need to take any action to start the playback. +// + +#define EC_DVD_CURRENT_HMSF_TIME (EC_DVDBASE + 0x1a) +// Parameters: ( ULONG, ULONG ) +// lParam2 contains a union of the DVD_TIMECODE_FLAGS +// lParam1 contains a DVD_HMSF_TIMECODE. Assign lParam1 to a ULONG then cast the +// ULONG as a DVD_HMSF_TIMECODE to use its values. +// +// Raised from following domains: DVD_DOMAIN_Title +// +// Signaled at the beginning of every VOBU, which occurs every .4 to 1.0 sec. + +#define EC_DVD_KARAOKE_MODE (EC_DVDBASE + 0x1b) +// Parameters: ( BOOL, reserved ) +// lParam1 is either TRUE (a karaoke track is being played) or FALSE (no karaoke data is being played). +// +#endif // __DVDEVCOD__ diff --git a/plugins/gs/gsdx9/baseclasses/dvdmedia.h b/plugins/gs/gsdx9/baseclasses/dvdmedia.h new file mode 100644 index 0000000000..6be8de0582 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/dvdmedia.h @@ -0,0 +1,427 @@ +//------------------------------------------------------------------------------ +// File: DVDMedia.h +// +// Desc: Contains typedefs and defines necessary for user mode (ring 3) DVD +// filters and applications. +// +// This should be included in the DirectShow SDK for user mode filters. +// The types defined here should be kept in synch with ksmedia.h WDM +// DDK for kernel mode filters. +// +// Copyright (c) 1997 - 2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __DVDMEDIA_H__ +#define __DVDMEDIA_H__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// ----------------------------------------------------------------------- +// AC-3 definition for the AM_KSPROPSETID_AC3 property set +// ----------------------------------------------------------------------- + +typedef enum { + AM_PROPERTY_AC3_ERROR_CONCEALMENT = 1, + AM_PROPERTY_AC3_ALTERNATE_AUDIO = 2, + AM_PROPERTY_AC3_DOWNMIX = 3, + AM_PROPERTY_AC3_BIT_STREAM_MODE = 4, + AM_PROPERTY_AC3_DIALOGUE_LEVEL = 5, + AM_PROPERTY_AC3_LANGUAGE_CODE = 6, + AM_PROPERTY_AC3_ROOM_TYPE = 7 +} AM_PROPERTY_AC3; + +typedef struct { + BOOL fRepeatPreviousBlock; + BOOL fErrorInCurrentBlock; +} AM_AC3_ERROR_CONCEALMENT, *PAM_AC3_ERROR_CONCEALMENT; + +typedef struct { + BOOL fStereo; + ULONG DualMode; +} AM_AC3_ALTERNATE_AUDIO, *PAM_AC3_ALTERNATE_AUDIO; + +#define AM_AC3_ALTERNATE_AUDIO_1 1 +#define AM_AC3_ALTERNATE_AUDIO_2 2 +#define AM_AC3_ALTERNATE_AUDIO_BOTH 3 + +typedef struct { + BOOL fDownMix; + BOOL fDolbySurround; +} AM_AC3_DOWNMIX, *PAM_AC3_DOWNMIX; + +typedef struct { + LONG BitStreamMode; +} AM_AC3_BIT_STREAM_MODE, *PAM_AC3_BIT_STREAM_MODE; + +#define AM_AC3_SERVICE_MAIN_AUDIO 0 +#define AM_AC3_SERVICE_NO_DIALOG 1 +#define AM_AC3_SERVICE_VISUALLY_IMPAIRED 2 +#define AM_AC3_SERVICE_HEARING_IMPAIRED 3 +#define AM_AC3_SERVICE_DIALOG_ONLY 4 +#define AM_AC3_SERVICE_COMMENTARY 5 +#define AM_AC3_SERVICE_EMERGENCY_FLASH 6 +#define AM_AC3_SERVICE_VOICE_OVER 7 + +typedef struct { + ULONG DialogueLevel; +} AM_AC3_DIALOGUE_LEVEL, *PAM_AC3_DIALOGUE_LEVEL; + +typedef struct { + BOOL fLargeRoom; +} AM_AC3_ROOM_TYPE, *PAM_AC3_ROOM_TYPE; + + +// ----------------------------------------------------------------------- +// subpicture definition for the AM_KSPROPSETID_DvdSubPic property set +// ----------------------------------------------------------------------- + +typedef enum { + AM_PROPERTY_DVDSUBPIC_PALETTE = 0, + AM_PROPERTY_DVDSUBPIC_HLI = 1, + AM_PROPERTY_DVDSUBPIC_COMPOSIT_ON = 2 // TRUE for subpicture is displayed +} AM_PROPERTY_DVDSUBPIC; + +typedef struct _AM_DVD_YUV { + UCHAR Reserved; + UCHAR Y; + UCHAR U; + UCHAR V; +} AM_DVD_YUV, *PAM_DVD_YUV; + +typedef struct _AM_PROPERTY_SPPAL { + AM_DVD_YUV sppal[16]; +} AM_PROPERTY_SPPAL, *PAM_PROPERTY_SPPAL; + +typedef struct _AM_COLCON { + UCHAR emph1col:4; + UCHAR emph2col:4; + UCHAR backcol:4; + UCHAR patcol:4; + UCHAR emph1con:4; + UCHAR emph2con:4; + UCHAR backcon:4; + UCHAR patcon:4; + +} AM_COLCON, *PAM_COLCON; + +typedef struct _AM_PROPERTY_SPHLI { + USHORT HLISS; // + USHORT Reserved; + ULONG StartPTM; // start presentation time in x/90000 + ULONG EndPTM; // end PTM in x/90000 + USHORT StartX; + USHORT StartY; + USHORT StopX; + USHORT StopY; + AM_COLCON ColCon; // color contrast description (4 bytes as given in HLI) +} AM_PROPERTY_SPHLI, *PAM_PROPERTY_SPHLI; + +typedef BOOL AM_PROPERTY_COMPOSIT_ON, *PAM_PROPERTY_COMPOSIT_ON; + + + +// ----------------------------------------------------------------------- +// copy protection definitions +// ----------------------------------------------------------------------- + +// AM_UseNewCSSKey for the dwTypeSpecificFlags in IMediaSample2 to indicate +// the exact point in a stream after which to start applying a new CSS key. +// This is typically sent on an empty media sample just before attempting +// to renegotiate a CSS key. +#define AM_UseNewCSSKey 0x1 + +// +// AM_KSPROPSETID_CopyProt property set definitions +// +typedef enum { + AM_PROPERTY_DVDCOPY_CHLG_KEY = 0x01, + AM_PROPERTY_DVDCOPY_DVD_KEY1 = 0x02, + AM_PROPERTY_DVDCOPY_DEC_KEY2 = 0x03, + AM_PROPERTY_DVDCOPY_TITLE_KEY = 0x04, + AM_PROPERTY_COPY_MACROVISION = 0x05, + AM_PROPERTY_DVDCOPY_REGION = 0x06, + AM_PROPERTY_DVDCOPY_SET_COPY_STATE = 0x07, + AM_PROPERTY_DVDCOPY_DISC_KEY = 0x80 +} AM_PROPERTY_DVDCOPYPROT; + +typedef struct _AM_DVDCOPY_CHLGKEY { + BYTE ChlgKey[10]; + BYTE Reserved[2]; +} AM_DVDCOPY_CHLGKEY, *PAM_DVDCOPY_CHLGKEY; + +typedef struct _AM_DVDCOPY_BUSKEY { + BYTE BusKey[5]; + BYTE Reserved[1]; +} AM_DVDCOPY_BUSKEY, *PAM_DVDCOPY_BUSKEY; + +typedef struct _AM_DVDCOPY_DISCKEY { + BYTE DiscKey[2048]; +} AM_DVDCOPY_DISCKEY, *PAM_DVDCOPY_DISCKEY; + +typedef struct AM_DVDCOPY_TITLEKEY { + ULONG KeyFlags; + ULONG Reserved1[2]; + UCHAR TitleKey[6]; + UCHAR Reserved2[2]; +} AM_DVDCOPY_TITLEKEY, *PAM_DVDCOPY_TITLEKEY; + +typedef struct _AM_COPY_MACROVISION { + ULONG MACROVISIONLevel; +} AM_COPY_MACROVISION, *PAM_COPY_MACROVISION; + +typedef struct AM_DVDCOPY_SET_COPY_STATE { + ULONG DVDCopyState; +} AM_DVDCOPY_SET_COPY_STATE, *PAM_DVDCOPY_SET_COPY_STATE; + +typedef enum { + AM_DVDCOPYSTATE_INITIALIZE = 0, + AM_DVDCOPYSTATE_INITIALIZE_TITLE = 1, // indicates we are starting a title + // key copy protection sequence + AM_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED = 2, + AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED = 3, + AM_DVDCOPYSTATE_DONE = 4 +} AM_DVDCOPYSTATE; + +typedef enum { + AM_MACROVISION_DISABLED = 0, + AM_MACROVISION_LEVEL1 = 1, + AM_MACROVISION_LEVEL2 = 2, + AM_MACROVISION_LEVEL3 = 3 +} AM_COPY_MACROVISION_LEVEL, *PAM_COPY_MACROVISION_LEVEL; + + +// CSS region stucture +typedef struct _DVD_REGION { + UCHAR CopySystem; + UCHAR RegionData; + UCHAR SystemRegion; + UCHAR Reserved; +} DVD_REGION, *PDVD_REGION; + +// +// CGMS Copy Protection Flags +// + +#define AM_DVD_CGMS_RESERVED_MASK 0x00000078 + +#define AM_DVD_CGMS_COPY_PROTECT_MASK 0x00000018 +#define AM_DVD_CGMS_COPY_PERMITTED 0x00000000 +#define AM_DVD_CGMS_COPY_ONCE 0x00000010 +#define AM_DVD_CGMS_NO_COPY 0x00000018 + +#define AM_DVD_COPYRIGHT_MASK 0x00000040 +#define AM_DVD_NOT_COPYRIGHTED 0x00000000 +#define AM_DVD_COPYRIGHTED 0x00000040 + +#define AM_DVD_SECTOR_PROTECT_MASK 0x00000020 +#define AM_DVD_SECTOR_NOT_PROTECTED 0x00000000 +#define AM_DVD_SECTOR_PROTECTED 0x00000020 + + +// ----------------------------------------------------------------------- +// video format blocks +// ----------------------------------------------------------------------- + +enum AM_MPEG2Level { + AM_MPEG2Level_Low = 1, + AM_MPEG2Level_Main = 2, + AM_MPEG2Level_High1440 = 3, + AM_MPEG2Level_High = 4 +}; + +enum AM_MPEG2Profile { + AM_MPEG2Profile_Simple = 1, + AM_MPEG2Profile_Main = 2, + AM_MPEG2Profile_SNRScalable = 3, + AM_MPEG2Profile_SpatiallyScalable = 4, + AM_MPEG2Profile_High = 5 +}; + +#define AMINTERLACE_IsInterlaced 0x00000001 // if 0, other interlace bits are irrelevent +#define AMINTERLACE_1FieldPerSample 0x00000002 // else 2 fields per media sample +#define AMINTERLACE_Field1First 0x00000004 // else Field 2 is first; top field in PAL is field 1, top field in NTSC is field 2? +#define AMINTERLACE_UNUSED 0x00000008 // +#define AMINTERLACE_FieldPatternMask 0x00000030 // use this mask with AMINTERLACE_FieldPat* +#define AMINTERLACE_FieldPatField1Only 0x00000000 // stream never contains a Field2 +#define AMINTERLACE_FieldPatField2Only 0x00000010 // stream never contains a Field1 +#define AMINTERLACE_FieldPatBothRegular 0x00000020 // There will be a Field2 for every Field1 (required for Weave?) +#define AMINTERLACE_FieldPatBothIrregular 0x00000030 // Random pattern of Field1s and Field2s +#define AMINTERLACE_DisplayModeMask 0x000000c0 +#define AMINTERLACE_DisplayModeBobOnly 0x00000000 +#define AMINTERLACE_DisplayModeWeaveOnly 0x00000040 +#define AMINTERLACE_DisplayModeBobOrWeave 0x00000080 + +#define AMCOPYPROTECT_RestrictDuplication 0x00000001 // duplication of this stream should be restricted + +#define AMMPEG2_DoPanScan 0x00000001 //if set, the MPEG-2 video decoder should crop output image + // based on pan-scan vectors in picture_display_extension + // and change the picture aspect ratio accordingly. +#define AMMPEG2_DVDLine21Field1 0x00000002 //if set, the MPEG-2 decoder must be able to produce an output + // pin for DVD style closed caption data found in GOP layer of field 1 +#define AMMPEG2_DVDLine21Field2 0x00000004 //if set, the MPEG-2 decoder must be able to produce an output + // pin for DVD style closed caption data found in GOP layer of field 2 +#define AMMPEG2_SourceIsLetterboxed 0x00000008 //if set, indicates that black bars have been encoded in the top + // and bottom of the video. +#define AMMPEG2_FilmCameraMode 0x00000010 //if set, indicates "film mode" used for 625/50 content. If cleared, + // indicates that "camera mode" was used. +#define AMMPEG2_LetterboxAnalogOut 0x00000020 //if set and this stream is sent to an analog output, it should + // be letterboxed. Streams sent to VGA should be letterboxed only by renderers. +#define AMMPEG2_DSS_UserData 0x00000040 //if set, the MPEG-2 decoder must process DSS style user data +#define AMMPEG2_DVB_UserData 0x00000080 //if set, the MPEG-2 decoder must process DVB style user data +#define AMMPEG2_27MhzTimebase 0x00000100 //if set, the PTS,DTS timestamps advance at 27MHz rather than 90KHz + +#define AMMPEG2_WidescreenAnalogOut 0x00000200 //if set and this stream is sent to an analog output, it should + // be in widescreen format (4x3 content should be centered on a 16x9 output). + // Streams sent to VGA should be widescreened only by renderers. + +// PRESENT in dwReserved1 field in VIDEOINFOHEADER2 +#define AMCONTROL_USED 0x00000001 // Used to test if these flags are supported. Set and test for AcceptMediaType. + // If rejected, then you cannot use the AMCONTROL flags (send 0 for dwReserved1) +#define AMCONTROL_PAD_TO_4x3 0x00000002 // if set means display the image in a 4x3 area +#define AMCONTROL_PAD_TO_16x9 0x00000004 // if set means display the image in a 16x9 area + +typedef struct tagVIDEOINFOHEADER2 { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + DWORD dwInterlaceFlags; // use AMINTERLACE_* defines. Reject connection if undefined bits are not 0 + DWORD dwCopyProtectFlags; // use AMCOPYPROTECT_* defines. Reject connection if undefined bits are not 0 + DWORD dwPictAspectRatioX; // X dimension of picture aspect ratio, e.g. 16 for 16x9 display + DWORD dwPictAspectRatioY; // Y dimension of picture aspect ratio, e.g. 9 for 16x9 display + union { + DWORD dwControlFlags; // use AMCONTROL_* defines, use this from now on + DWORD dwReserved1; // for backward compatiblity (was "must be 0"; connection rejected otherwise) + }; + DWORD dwReserved2; // must be 0; reject connection otherwise + BITMAPINFOHEADER bmiHeader; +} VIDEOINFOHEADER2; + +typedef struct tagMPEG2VIDEOINFO { + VIDEOINFOHEADER2 hdr; + DWORD dwStartTimeCode; // ?? not used for DVD ?? + DWORD cbSequenceHeader; // is 0 for DVD (no sequence header) + DWORD dwProfile; // use enum MPEG2Profile + DWORD dwLevel; // use enum MPEG2Level + DWORD dwFlags; // use AMMPEG2_* defines. Reject connection if undefined bits are not 0 + DWORD dwSequenceHeader[1]; // DWORD instead of Byte for alignment purposes + // For MPEG-2, if a sequence_header is included, the sequence_extension + // should also be included +} MPEG2VIDEOINFO; + +#define SIZE_MPEG2VIDEOINFO(pv) (FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader[0]) + (pv)->cbSequenceHeader) + +// do not use +#define MPEG1_SEQUENCE_INFO(pv) ((const BYTE *)(pv)->bSequenceHeader) + +// use this macro instead, the previous only works for MPEG1VIDEOINFO structures +#define MPEG2_SEQUENCE_INFO(pv) ((const BYTE *)(pv)->dwSequenceHeader) + + +//=================================================================================== +// flags for dwTypeSpecificFlags in AM_SAMPLE2_PROPERTIES which define type specific +// data in IMediaSample2 +//=================================================================================== + +#define AM_VIDEO_FLAG_FIELD_MASK 0x0003L // use this mask to check whether the sample is field1 or field2 or frame +#define AM_VIDEO_FLAG_INTERLEAVED_FRAME 0x0000L // the sample is a frame (remember to use AM_VIDEO_FLAG_FIELD_MASK when using this) +#define AM_VIDEO_FLAG_FIELD1 0x0001L // the sample is field1 (remember to use AM_VIDEO_FLAG_FIELD_MASK when using this) +#define AM_VIDEO_FLAG_FIELD2 0x0002L // the sample is the field2 (remember to use AM_VIDEO_FLAG_FIELD_MASK when using this) +#define AM_VIDEO_FLAG_FIELD1FIRST 0x0004L // if set means display field1 first, else display field2 first. + // this bit is irrelavant for 1FieldPerSample mode +#define AM_VIDEO_FLAG_WEAVE 0x0008L // if set use bob display mode else weave +#define AM_VIDEO_FLAG_IPB_MASK 0x0030L // use this mask to check whether the sample is I, P or B +#define AM_VIDEO_FLAG_I_SAMPLE 0x0000L // I Sample (remember to use AM_VIDEO_FLAG_IPB_MASK when using this) +#define AM_VIDEO_FLAG_P_SAMPLE 0x0010L // P Sample (remember to use AM_VIDEO_FLAG_IPB_MASK when using this) +#define AM_VIDEO_FLAG_B_SAMPLE 0x0020L // B Sample (remember to use AM_VIDEO_FLAG_IPB_MASK when using this) +#define AM_VIDEO_FLAG_REPEAT_FIELD 0x0040L // if set means display the field which has been displayed first again after displaying + // both fields first. This bit is irrelavant for 1FieldPerSample mode + +// ----------------------------------------------------------------------- +// AM_KSPROPSETID_DvdKaraoke property set definitions +// ----------------------------------------------------------------------- + +typedef struct tagAM_DvdKaraokeData +{ + DWORD dwDownmix; // bitwise OR of AM_DvdKaraoke_Downmix flags + DWORD dwSpeakerAssignment; // AM_DvdKaraoke_SpeakerAssignment +} AM_DvdKaraokeData; + +typedef enum { + AM_PROPERTY_DVDKARAOKE_ENABLE = 0, // BOOL + AM_PROPERTY_DVDKARAOKE_DATA = 1, +} AM_PROPERTY_DVDKARAOKE; + +// ----------------------------------------------------------------------- +// AM_KSPROPSETID_TSRateChange property set definitions for time stamp +// rate changes. +// ----------------------------------------------------------------------- + +typedef enum { + AM_RATE_SimpleRateChange = 1, // rw, use AM_SimpleRateChange + AM_RATE_ExactRateChange = 2, // rw, use AM_ExactRateChange + AM_RATE_MaxFullDataRate = 3, // r, use AM_MaxFullDataRate + AM_RATE_Step = 4, // w, use AM_Step + AM_RATE_UseRateVersion = 5, // w, use WORD + AM_RATE_QueryFullFrameRate =6, // r, use AM_QueryRate + AM_RATE_QueryLastRateSegPTS =7, // r, use REFERENCE_TIME + AM_RATE_CorrectTS = 8 // w, use LONG +} AM_PROPERTY_TS_RATE_CHANGE; + +// ------------------------------------------------------------------- +// AM_KSPROPSETID_DVD_RateChange property set definitions for new DVD +// rate change scheme. +// ------------------------------------------------------------------- + +typedef enum { + AM_RATE_ChangeRate = 1, // w, use AM_DVD_ChangeRate + AM_RATE_FullDataRateMax = 2, // r, use AM_MaxFullDataRate + AM_RATE_ReverseDecode = 3, // r, use LONG + AM_RATE_DecoderPosition = 4, // r, use AM_DVD_DecoderPosition + AM_RATE_DecoderVersion = 5 // r, use LONG +} AM_PROPERTY_DVD_RATE_CHANGE; + +typedef struct { + // this is the simplest mechanism to set a time stamp rate change on + // a filter (simplest for the person setting the rate change, harder + // for the filter doing the rate change). + REFERENCE_TIME StartTime; //stream time at which to start this rate + LONG Rate; //new rate * 10000 (decimal) +} AM_SimpleRateChange; + +typedef struct { + LONG lMaxForwardFullFrame ; // rate * 10000 + LONG lMaxReverseFullFrame ; // rate * 10000 +} AM_QueryRate ; + +typedef struct { + REFERENCE_TIME OutputZeroTime; //input TS that maps to zero output TS + LONG Rate; //new rate * 10000 (decimal) +} AM_ExactRateChange; + +typedef LONG AM_MaxFullDataRate; //rate * 10000 (decimal) + +typedef DWORD AM_Step; // number of frame to step + +// New rate change property set, structs. enums etc. +typedef struct { + REFERENCE_TIME StartInTime; // stream time (input) at which to start decoding at this rate + REFERENCE_TIME StartOutTime; // reference time (output) at which to start showing at this rate + LONG Rate; // new rate * 10000 (decimal) +} AM_DVD_ChangeRate ; + +typedef LONGLONG AM_DVD_DecoderPosition ; + +typedef enum { + DVD_DIR_FORWARD = 0, + DVD_DIR_BACKWARD = 1 +} DVD_PLAY_DIRECTION ; + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // __DVDMEDIA_H__ diff --git a/plugins/gs/gsdx9/baseclasses/edevdefs.h b/plugins/gs/gsdx9/baseclasses/edevdefs.h new file mode 100644 index 0000000000..e066bbf16c --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/edevdefs.h @@ -0,0 +1,531 @@ +//------------------------------------------------------------------------------ +// File: EDevDefs.h +// +// Desc: External Device (such as a VCR) control interface parameter and +// value definitions. +// +// Note: new constants added: ED_BASE+800L -> ED_BASE+811L +// +// Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __EDEVDEFS__ +#define __EDEVDEFS__ + + +#define ED_BASE 0x1000L + +// this is used to tell the device communications object which +// physical communications port to use. +#define DEV_PORT_SIM 1 +#define DEV_PORT_COM1 2 // standard serial ports +#define DEV_PORT_COM2 3 +#define DEV_PORT_COM3 4 +#define DEV_PORT_COM4 5 +#define DEV_PORT_DIAQ 6 // Diaquest driver +#define DEV_PORT_ARTI 7 // ARTI driver +#define DEV_PORT_1394 8 // IEEE 1394 Bus +#define DEV_PORT_USB 9 // Universal Serial Bus +#define DEV_PORT_MIN DEV_PORT_SIM +#define DEV_PORT_MAX DEV_PORT_USB + + +// IAMExtDevice Capability Items: unless otherwise specified, these items return +// OATRUE or OAFALSE. All return values are in pdwValue unless otherwise specified: + +#define ED_DEVCAP_CAN_RECORD ED_BASE+1L +#define ED_DEVCAP_CAN_RECORD_STROBE ED_BASE+2L // for multitrack devices: + // switches currently recording tracks off + // and selected non-recording tracks into record +#define ED_DEVCAP_HAS_AUDIO ED_BASE+3L +#define ED_DEVCAP_HAS_VIDEO ED_BASE+4L +#define ED_DEVCAP_USES_FILES ED_BASE+5L +#define ED_DEVCAP_CAN_SAVE ED_BASE+6L + +#define ED_DEVCAP_DEVICE_TYPE ED_BASE+7L // returns one of the following: +#define ED_DEVTYPE_VCR ED_BASE+8L +#define ED_DEVTYPE_LASERDISK ED_BASE+9L +#define ED_DEVTYPE_ATR ED_BASE+10L +#define ED_DEVTYPE_DDR ED_BASE+11L +#define ED_DEVTYPE_ROUTER ED_BASE+12L +#define ED_DEVTYPE_KEYER ED_BASE+13L +#define ED_DEVTYPE_MIXER_VIDEO ED_BASE+14L +#define ED_DEVTYPE_DVE ED_BASE+15L +#define ED_DEVTYPE_WIPEGEN ED_BASE+16L +#define ED_DEVTYPE_MIXER_AUDIO ED_BASE+17L +#define ED_DEVTYPE_CG ED_BASE+18L +#define ED_DEVTYPE_TBC ED_BASE+19L +#define ED_DEVTYPE_TCG ED_BASE+20L +#define ED_DEVTYPE_GPI ED_BASE+21L +#define ED_DEVTYPE_JOYSTICK ED_BASE+22L +#define ED_DEVTYPE_KEYBOARD ED_BASE+23L + +// returns mfr-specific ID from external device. +#define ED_DEVCAP_EXTERNAL_DEVICE_ID ED_BASE+24L + +#define ED_DEVCAP_TIMECODE_READ ED_BASE+25L +#define ED_DEVCAP_TIMECODE_WRITE ED_BASE+26L +// used for seekable non-timecode enabled devices +#define ED_DEVCAP_CTLTRK_READ ED_BASE+27L +// used for seekable non-timecode enabled devices +#define ED_DEVCAP_INDEX_READ ED_BASE+28L + +// returns device preroll time in current time format +#define ED_DEVCAP_PREROLL ED_BASE+29L +// returns device postroll time in current time format +#define ED_DEVCAP_POSTROLL ED_BASE+30L + +// returns indication of device’s synchronization accuracy. +#define ED_DEVCAP_SYNC_ACCURACY ED_BASE+31L // returns one of the following: +#define ED_SYNCACC_PRECISE ED_BASE+32L +#define ED_SYNCACC_FRAME ED_BASE+33L +#define ED_SYNCACC_ROUGH ED_BASE+34L + +// returns device’s normal framerate. +#define ED_DEVCAP_NORMAL_RATE ED_BASE+35L // returns one of the following: +#define ED_RATE_24 ED_BASE+36L +#define ED_RATE_25 ED_BASE+37L +#define ED_RATE_2997 ED_BASE+38L +#define ED_RATE_30 ED_BASE+39L + +#define ED_DEVCAP_CAN_PREVIEW ED_BASE+40L +#define ED_DEVCAP_CAN_MONITOR_SOURCES ED_BASE+41L + +// indicates implementation allows testing of methods/parameters by +// setting the hi bit of a parm that makes sense - see individual methods +// for details. +#define ED_DEVCAP_CAN_TEST ED_BASE+42L + +// indicates device accepts video as an input. +#define ED_DEVCAP_VIDEO_INPUTS ED_BASE+43L + +// indicates device accepts audio as an input. +#define ED_DEVCAP_AUDIO_INPUTS ED_BASE+44L + +#define ED_DEVCAP_NEEDS_CALIBRATING ED_BASE+45L + +#define ED_DEVCAP_SEEK_TYPE ED_BASE+46L // returns one of the following: +#define ED_SEEK_PERFECT ED_BASE+47L // indicates device can execute seek + // within 1 video frames without signal + // break (like a DDR) +#define ED_SEEK_FAST ED_BASE+48L // indicates device can move pretty quick + // with short break in signal +#define ED_SEEK_SLOW ED_BASE+49L // seeks like a tape transport + +#define ED_POWER_ON ED_BASE+50L +#define ED_POWER_OFF ED_BASE+51L +#define ED_POWER_STANDBY ED_BASE+52L + +#define ED_ACTIVE ED_BASE+53L +#define ED_INACTIVE ED_BASE+54L +#define ED_ALL ED_BASE+55L +#define ED_TEST ED_BASE+56L + +// IAMExtTransport Capability Items: unless otherwise specified, these items return +// OATRUE or OAFALSE. All return values are in pdwValue unless otherwise specified: + +#define ED_TRANSCAP_CAN_EJECT ED_BASE+100L +#define ED_TRANSCAP_CAN_BUMP_PLAY ED_BASE+101L // variable speed for synchronizing +#define ED_TRANSCAP_CAN_PLAY_BACKWARDS ED_BASE+102L // servo locked for use during an edit +#define ED_TRANSCAP_CAN_SET_EE ED_BASE+103L // show device’s input on its output +#define ED_TRANSCAP_CAN_SET_PB ED_BASE+104L // show media playback on device’s output +#define ED_TRANSCAP_CAN_DELAY_VIDEO_IN ED_BASE+105L // transport can do delayed-in video edits +#define ED_TRANSCAP_CAN_DELAY_VIDEO_OUT ED_BASE+106L // transport can do delayed-out video edits +#define ED_TRANSCAP_CAN_DELAY_AUDIO_IN ED_BASE+107L // transport can do delayed-in audio edits +#define ED_TRANSCAP_CAN_DELAY_AUDIO_OUT ED_BASE+108L // transport can do delayed-out audio edits +#define ED_TRANSCAP_FWD_VARIABLE_MAX ED_BASE+109L // max forward speed (multiple of play speed) + // in pdblValue +#define ED_TRANSCAP_FWD_VARIABLE_MIN ED_BASE+800L // min forward speed (multiple of play speed) + // in pdblValue +#define ED_TRANSCAP_REV_VARIABLE_MAX ED_BASE+110L // max reverse speed (multiple of play speed) in + // pdblValue +#define ED_TRANSCAP_REV_VARIABLE_MIN ED_BASE+801L // min reverse speed (multiple of play speed) + // in pdblValue +#define ED_TRANSCAP_FWD_SHUTTLE_MAX ED_BASE+802L // max forward speed in Shuttle mode (multiple + // of play speed) in pdblValue +#define ED_TRANSCAP_FWD_SHUTTLE_MIN ED_BASE+803L // min forward speed in Shuttle mode (multiple + // of play speed) in pdblValue +#define ED_TRANSCAP_REV_SHUTTLE_MAX ED_BASE+804L // max reverse speed in Shuttle mode (multiple + // of play speed) in pdblValue +#define ED_TRANSCAP_REV_SHUTTLE_MIN ED_BASE+805L // min reverse speed in Shuttle mode (multiple + // of play speed) in pdblValue +#define ED_TRANSCAP_NUM_AUDIO_TRACKS ED_BASE+111L // returns number of audio tracks +#define ED_TRANSCAP_LTC_TRACK ED_BASE+112L // returns track number of LTC timecode track. + // ED_ALL means no dedicated timecode track +#define ED_TRANSCAP_NEEDS_TBC ED_BASE+113L // device’s output not stable +#define ED_TRANSCAP_NEEDS_CUEING ED_BASE+114L // device must be cued prior to performing edit +#define ED_TRANSCAP_CAN_INSERT ED_BASE+115L +#define ED_TRANSCAP_CAN_ASSEMBLE ED_BASE+116L +#define ED_TRANSCAP_FIELD_STEP ED_BASE+117L // device responds to Frame Advance command by + // advancing one field +#define ED_TRANSCAP_CLOCK_INC_RATE ED_BASE+118L // VISCA command - keep for compatibility +#define ED_TRANSCAP_CAN_DETECT_LENGTH ED_BASE+119L +#define ED_TRANSCAP_CAN_FREEZE ED_BASE+120L +#define ED_TRANSCAP_HAS_TUNER ED_BASE+121L +#define ED_TRANSCAP_HAS_TIMER ED_BASE+122L +#define ED_TRANSCAP_HAS_CLOCK ED_BASE+123L +#define ED_TRANSCAP_MULTIPLE_EDITS ED_BASE+806L // OATRUE means device/filter can support + // multiple edit events +#define ED_TRANSCAP_IS_MASTER ED_BASE+807L // OATRUE means device is the master clock + // for synchronizing (this sets timecode-to- + // reference clock offset for editing) +#define ED_TRANSCAP_HAS_DT ED_BASE+814L // OATRUE means device has Dynamic Tracking + +// IAMExtTransport Media States +#define ED_MEDIA_SPIN_UP ED_BASE+130L +#define ED_MEDIA_SPIN_DOWN ED_BASE+131L +#define ED_MEDIA_UNLOAD ED_BASE+132L + +// IAMExtTransport Modes +#define ED_MODE_PLAY ED_BASE+200L +#define ED_MODE_STOP ED_BASE+201L +#define ED_MODE_FREEZE ED_BASE+202L // really "pause" +#define ED_MODE_THAW ED_BASE+203L +#define ED_MODE_FF ED_BASE+204L +#define ED_MODE_REW ED_BASE+205L +#define ED_MODE_RECORD ED_BASE+206L +#define ED_MODE_RECORD_STROBE ED_BASE+207L +#define ED_MODE_RECORD_FREEZE ED_BASE+808L // never "put", only "get" +#define ED_MODE_STEP ED_BASE+208L // same as "jog" +#define ED_MODE_STEP_FWD ED_BASE+208L // same as ED_MODE_STEP +#define ED_MODE_STEP_REV ED_BASE+809L +#define ED_MODE_SHUTTLE ED_BASE+209L +#define ED_MODE_EDIT_CUE ED_BASE+210L +#define ED_MODE_VAR_SPEED ED_BASE+211L +#define ED_MODE_PERFORM ED_BASE+212L // returned status only +#define ED_MODE_LINK_ON ED_BASE+280L +#define ED_MODE_LINK_OFF ED_BASE+281L +#define ED_MODE_NOTIFY_ENABLE ED_BASE+810L +#define ED_MODE_NOTIFY_DISABLE ED_BASE+811L +#define ED_MODE_SHOT_SEARCH ED_BASE+812L + +// IAMTimecodeReader/Generator/Display defines +// +// Timecode Generator Mode params and values: +// +#define ED_TCG_TIMECODE_TYPE ED_BASE+400L // can be one of the following: +#define ED_TCG_SMPTE_LTC ED_BASE+401L +#define ED_TCG_SMPTE_VITC ED_BASE+402L +#define ED_TCG_MIDI_QF ED_BASE+403L +#define ED_TCG_MIDI_FULL ED_BASE+404L + +#define ED_TCG_FRAMERATE ED_BASE+405L // can be one of the following: +#define ED_FORMAT_SMPTE_30 ED_BASE+406L +#define ED_FORMAT_SMPTE_30DROP ED_BASE+407L +#define ED_FORMAT_SMPTE_25 ED_BASE+408L +#define ED_FORMAT_SMPTE_24 ED_BASE+409L + +#define ED_TCG_SYNC_SOURCE ED_BASE+410L // can be one of the following: +#define ED_TCG_VIDEO ED_BASE+411L +#define ED_TCG_READER ED_BASE+412L +#define ED_TCG_FREE ED_BASE+413L + +#define ED_TCG_REFERENCE_SOURCE ED_BASE+414L // can have one these values: + // ED_TCG_FREE || ED_TCG_READER + // (for regen/jamsync) + +// TimeCodeReader Mode params and values: +#define ED_TCR_SOURCE ED_BASE+416L // can be one of the following: +// ED_TCG (already defined) +#define ED_TCR_LTC ED_BASE+417L +#define ED_TCR_VITC ED_BASE+418L +#define ED_TCR_CT ED_BASE+419L // Control Track +#define ED_TCR_FTC ED_BASE+420L // File TimeCode - for file-based devices + // that wish they were transports +// ED_MODE_NOTIFY_ENABLE can be OATRUE or OAFALSE (defined in transport mode +// section of this file). +#define ED_TCR_LAST_VALUE ED_BASE+421L // for notification mode - + // successive calls to GetTimecode + // return the last read value +// TimeCode Display Mode params and values: +// +#define ED_TCD_SOURCE ED_BASE+422L // can be one of the following: +#define ED_TCR ED_BASE+423L +#define ED_TCG ED_BASE+424L + +#define ED_TCD_SIZE ED_BASE+425L // can be one of the following: +#define ED_SMALL ED_BASE+426L +#define ED_MED ED_BASE+427L +#define ED_LARGE ED_BASE+428L + +#define ED_TCD_POSITION ED_BASE+429L // can be one of the following: +#define ED_TOP 0x0001 +#define ED_MIDDLE 0x0002 +#define ED_BOTTOM 0x0004 // OR'd with +#define ED_LEFT 0x0100 +#define ED_CENTER 0x0200 +#define ED_RIGHT 0x0400 + +#define ED_TCD_INTENSITY ED_BASE+436L // can be one of the following: +#define ED_HIGH ED_BASE+437L +#define ED_LOW ED_BASE+438L + +#define ED_TCD_TRANSPARENCY ED_BASE+439L // 0-4, 0 is opaque + +#define ED_TCD_INVERT ED_BASE+440L // OATRUE=black on white + // OAFALSE=white on black +// IAMExtTransport defines +// +// Transport status, params and values +// + +// IAMExtTransport Status items and and values: +#define ED_MODE ED_BASE+500L // see ED_MODE_xxx values above +#define ED_ERROR ED_BASE+501L +#define ED_LOCAL ED_BASE+502L +#define ED_RECORD_INHIBIT ED_BASE+503L +#define ED_SERVO_LOCK ED_BASE+504L +#define ED_MEDIA_PRESENT ED_BASE+505L +#define ED_MEDIA_LENGTH ED_BASE+506L +#define ED_MEDIA_SIZE ED_BASE+507L +#define ED_MEDIA_TRACK_COUNT ED_BASE+508L +#define ED_MEDIA_TRACK_LENGTH ED_BASE+509L +#define ED_MEDIA_SIDE ED_BASE+510L + +#define ED_MEDIA_TYPE ED_BASE+511L // can be one of the following: +#define ED_MEDIA_VHS ED_BASE+512L +#define ED_MEDIA_SVHS ED_BASE+513L +#define ED_MEDIA_HI8 ED_BASE+514L +#define ED_MEDIA_UMATIC ED_BASE+515L +#define ED_MEDIA_DVC ED_BASE+516L +#define ED_MEDIA_1_INCH ED_BASE+517L +#define ED_MEDIA_D1 ED_BASE+518L +#define ED_MEDIA_D2 ED_BASE+519L +#define ED_MEDIA_D3 ED_BASE+520L +#define ED_MEDIA_D5 ED_BASE+521L +#define ED_MEDIA_DBETA ED_BASE+522L +#define ED_MEDIA_BETA ED_BASE+523L +#define ED_MEDIA_8MM ED_BASE+524L +#define ED_MEDIA_DDR ED_BASE+525L +#define ED_MEDIA_SX ED_BASE+813L +#define ED_MEDIA_OTHER ED_BASE+526L +#define ED_MEDIA_CLV ED_BASE+527L +#define ED_MEDIA_CAV ED_BASE+528L +#define ED_MEDIA_POSITION ED_BASE+529L + +#define ED_LINK_MODE ED_BASE+530L // OATRUE if transport controls + // are linked to graph's RUN, + // STOP, and PAUSE methods + +// IAMExtTransport Basic Parms +#define ED_TRANSBASIC_TIME_FORMAT ED_BASE+540L // can be one of the following: +#define ED_FORMAT_MILLISECONDS ED_BASE+541L +#define ED_FORMAT_FRAMES ED_BASE+542L +#define ED_FORMAT_REFERENCE_TIME ED_BASE+543L + +#define ED_FORMAT_HMSF ED_BASE+547L +#define ED_FORMAT_TMSF ED_BASE+548L + +#define ED_TRANSBASIC_TIME_REFERENCE ED_BASE+549L // can be one of the following: +#define ED_TIMEREF_TIMECODE ED_BASE+550L +#define ED_TIMEREF_CONTROL_TRACK ED_BASE+551L +#define ED_TIMEREF_INDEX ED_BASE+552L + +#define ED_TRANSBASIC_SUPERIMPOSE ED_BASE+553L // enable/disable onscreen display +#define ED_TRANSBASIC_END_STOP_ACTION ED_BASE+554L // can be one of: ED_MODE_STOP | + // ED_MODE_REWIND | ED_MODE_FREEZE +#define ED_TRANSBASIC_RECORD_FORMAT ED_BASE+555L // can be one of the following: +#define ED_RECORD_FORMAT_SP ED_BASE+556L +#define ED_RECORD_FORMAT_LP ED_BASE+557L +#define ED_RECORD_FORMAT_EP ED_BASE+558L + +#define ED_TRANSBASIC_STEP_COUNT ED_BASE+559L +#define ED_TRANSBASIC_STEP_UNIT ED_BASE+560L // can be one of the following: +#define ED_STEP_FIELD ED_BASE+561L +#define ED_STEP_FRAME ED_BASE+562L +#define ED_STEP_3_2 ED_BASE+563L + +#define ED_TRANSBASIC_PREROLL ED_BASE+564L +#define ED_TRANSBASIC_RECPREROLL ED_BASE+565L +#define ED_TRANSBASIC_POSTROLL ED_BASE+566L +#define ED_TRANSBASIC_EDIT_DELAY ED_BASE+567L +#define ED_TRANSBASIC_PLAYTC_DELAY ED_BASE+568L +#define ED_TRANSBASIC_RECTC_DELAY ED_BASE+569L +#define ED_TRANSBASIC_EDIT_FIELD ED_BASE+570L +#define ED_TRANSBASIC_FRAME_SERVO ED_BASE+571L +#define ED_TRANSBASIC_CF_SERVO ED_BASE+572L +#define ED_TRANSBASIC_SERVO_REF ED_BASE+573L // can be one of the following: +#define ED_REF_EXTERNAL ED_BASE+574L +#define ED_REF_INPUT ED_BASE+575L +#define ED_REF_INTERNAL ED_BASE+576L +#define ED_REF_AUTO ED_BASE+577L + +#define ED_TRANSBASIC_WARN_GL ED_BASE+578L +#define ED_TRANSBASIC_SET_TRACKING ED_BASE+579L // can be one of the following: +#define ED_TRACKING_PLUS ED_BASE+580L +#define ED_TRACKING_MINUS ED_BASE+581L +#define ED_TRACKING_RESET ED_BASE+582L + +#define ED_TRANSBASIC_SET_FREEZE_TIMEOUT ED_BASE+583L +#define ED_TRANSBASIC_VOLUME_NAME ED_BASE+584L +#define ED_TRANSBASIC_BALLISTIC_1 ED_BASE+585L // space for proprietary data +#define ED_TRANSBASIC_BALLISTIC_2 ED_BASE+586L +#define ED_TRANSBASIC_BALLISTIC_3 ED_BASE+587L +#define ED_TRANSBASIC_BALLISTIC_4 ED_BASE+588L +#define ED_TRANSBASIC_BALLISTIC_5 ED_BASE+589L +#define ED_TRANSBASIC_BALLISTIC_6 ED_BASE+590L +#define ED_TRANSBASIC_BALLISTIC_7 ED_BASE+591L +#define ED_TRANSBASIC_BALLISTIC_8 ED_BASE+592L +#define ED_TRANSBASIC_BALLISTIC_9 ED_BASE+593L +#define ED_TRANSBASIC_BALLISTIC_10 ED_BASE+594L +#define ED_TRANSBASIC_BALLISTIC_11 ED_BASE+595L +#define ED_TRANSBASIC_BALLISTIC_12 ED_BASE+596L +#define ED_TRANSBASIC_BALLISTIC_13 ED_BASE+597L +#define ED_TRANSBASIC_BALLISTIC_14 ED_BASE+598L +#define ED_TRANSBASIC_BALLISTIC_15 ED_BASE+599L +#define ED_TRANSBASIC_BALLISTIC_16 ED_BASE+600L +#define ED_TRANSBASIC_BALLISTIC_17 ED_BASE+601L +#define ED_TRANSBASIC_BALLISTIC_18 ED_BASE+602L +#define ED_TRANSBASIC_BALLISTIC_19 ED_BASE+603L +#define ED_TRANSBASIC_BALLISTIC_20 ED_BASE+604L + +// consumer VCR items +#define ED_TRANSBASIC_SETCLOCK ED_BASE+605L +#define ED_TRANSBASIC_SET_COUNTER_FORMAT ED_BASE+606L // uses time format flags +#define ED_TRANSBASIC_SET_COUNTER_VALUE ED_BASE+607L + +#define ED_TRANSBASIC_SETTUNER_CH_UP ED_BASE+608L +#define ED_TRANSBASIC_SETTUNER_CH_DN ED_BASE+609L +#define ED_TRANSBASIC_SETTUNER_SK_UP ED_BASE+610L +#define ED_TRANSBASIC_SETTUNER_SK_DN ED_BASE+611L +#define ED_TRANSBASIC_SETTUNER_CH ED_BASE+612L +#define ED_TRANSBASIC_SETTUNER_NUM ED_BASE+613L + +#define ED_TRANSBASIC_SETTIMER_EVENT ED_BASE+614L +#define ED_TRANSBASIC_SETTIMER_STARTDAY ED_BASE+615L +#define ED_TRANSBASIC_SETTIMER_STARTTIME ED_BASE+616L +#define ED_TRANSBASIC_SETTIMER_STOPDAY ED_BASE+617L +#define ED_TRANSBASIC_SETTIMER_STOPTIME ED_BASE+618L + +// IAMExtTransport video parameters +#define ED_TRANSVIDEO_SET_OUTPUT ED_BASE+630L // can be one of the following: +#define ED_E2E ED_BASE+631L +#define ED_PLAYBACK ED_BASE+632L +#define ED_OFF ED_BASE+633L + +#define ED_TRANSVIDEO_SET_SOURCE ED_BASE+634L + +// IAMExtTransport audio parameters +#define ED_TRANSAUDIO_ENABLE_OUTPUT ED_BASE+640L // can be the following: +#define ED_AUDIO_ALL 0x10000000 // or any of the following OR'd together +#define ED_AUDIO_1 0x0000001L +#define ED_AUDIO_2 0x0000002L +#define ED_AUDIO_3 0x0000004L +#define ED_AUDIO_4 0x0000008L +#define ED_AUDIO_5 0x0000010L +#define ED_AUDIO_6 0x0000020L +#define ED_AUDIO_7 0x0000040L +#define ED_AUDIO_8 0x0000080L +#define ED_AUDIO_9 0x0000100L +#define ED_AUDIO_10 0x0000200L +#define ED_AUDIO_11 0x0000400L +#define ED_AUDIO_12 0x0000800L +#define ED_AUDIO_13 0x0001000L +#define ED_AUDIO_14 0x0002000L +#define ED_AUDIO_15 0x0004000L +#define ED_AUDIO_16 0x0008000L +#define ED_AUDIO_17 0x0010000L +#define ED_AUDIO_18 0x0020000L +#define ED_AUDIO_19 0x0040000L +#define ED_AUDIO_20 0x0080000L +#define ED_AUDIO_21 0x0100000L +#define ED_AUDIO_22 0x0200000L +#define ED_AUDIO_23 0x0400000L +#define ED_AUDIO_24 0x0800000L +#define ED_VIDEO 0x2000000L // for Edit props below + +#define ED_TRANSAUDIO_ENABLE_RECORD ED_BASE+642L +#define ED_TRANSAUDIO_ENABLE_SELSYNC ED_BASE+643L +#define ED_TRANSAUDIO_SET_SOURCE ED_BASE+644L +#define ED_TRANSAUDIO_SET_MONITOR ED_BASE+645L + + +// Edit Property Set-related defs + +// The following values reflect (and control) the state of an +// edit property set +#define ED_INVALID ED_BASE+652L +#define ED_EXECUTING ED_BASE+653L +#define ED_REGISTER ED_BASE+654L +#define ED_DELETE ED_BASE+655L + +// Edit property set parameters and values +#define ED_EDIT_HEVENT ED_BASE+656L // event handle to signal event + // completion +#define ED_EDIT_TEST ED_BASE+657L // returns OAFALSE if filter thinks + // edit can be done, OATRUE if not +#define ED_EDIT_IMMEDIATE ED_BASE+658L // OATRUE means start put the + // device into edit mode (editing + // "on the fly") immediately upon + // execution of Mode(ED_MODE_EDIT_CUE) +#define ED_EDIT_MODE ED_BASE+659L +// can be one of the following values: +#define ED_EDIT_MODE_ASSEMBLE ED_BASE+660L +#define ED_EDIT_MODE_INSERT ED_BASE+661L +#define ED_EDIT_MODE_CRASH_RECORD ED_BASE+662L +#define ED_EDIT_MODE_BOOKMARK_TIME ED_BASE+663L // these two are for +#define ED_EDIT_MODE_BOOKMARK_CHAPTER ED_BASE+664L // laserdisks + +#define ED_EDIT_MASTER ED_BASE+666L // OATRUE causes device + // not to synchronize + +#define ED_EDIT_TRACK ED_BASE+667L +// can be one of the following possible OR'd values: +// ED_VIDEO, ED_AUDIO_1 thru ED_AUDIO_24 (or ED_AUDIO_ALL) + +#define ED_EDIT_SRC_INPOINT ED_BASE+668L // in current time format +#define ED_EDIT_SRC_OUTPOINT ED_BASE+669L // in current time format +#define ED_EDIT_REC_INPOINT ED_BASE+670L // in current time format +#define ED_EDIT_REC_OUTPOINT ED_BASE+671L // in current time format + +#define ED_EDIT_REHEARSE_MODE ED_BASE+672L +// can be one of the following possible values: +#define ED_EDIT_BVB ED_BASE+673L // means rehearse the edit with + // "black-video-black" +#define ED_EDIT_VBV ED_BASE+674L +#define ED_EDIT_VVV ED_BASE+675L +#define ED_EDIT_PERFORM ED_BASE+676L // means perform the edit with no + // rehearsal. + +// Set this property to OATRUE to kill the edit if in progress +#define ED_EDIT_ABORT ED_BASE+677L +// how long to wait for edit to complete +#define ED_EDIT_TIMEOUT ED_BASE+678L // in current time format + +// This property causes the device to seek to a point specified by +// ED_EDIT_SEEK_MODE (see below). NOTE: Only one event at a time can seek. +#define ED_EDIT_SEEK ED_BASE+679L // OATRUE means do it now. +#define ED_EDIT_SEEK_MODE ED_BASE+680L +//possible values: +#define ED_EDIT_SEEK_EDIT_IN ED_BASE+681L // seek to edit's inpoint +#define ED_EDIT_SEEK_EDIT_OUT ED_BASE+682L // seek to edit's outpoint +#define ED_EDIT_SEEK_PREROLL ED_BASE+683L // seek to edit's + // inpoint-preroll +#define ED_EDIT_SEEK_PREROLL_CT ED_BASE+684L // seek to preroll point + // using control track (used for tapes with + // discontinuoustimecode before edit point: seek + // to inpoint using timecode, then backup to + // preroll point using control track) +#define ED_EDIT_SEEK_BOOKMARK ED_BASE+685L // seek to bookmark (just like + // timecode search) +// This property is used for multiple-VCR systems where each machine must +// cue to a different location relative to the graph's reference clock. The +// basic idea is that an edit event is setup with an ED_EDIT_OFFSET property +// that tells the VCR what offset to maintain between it's timecode (converted +// to reference clock units) and the reference clock. +#define ED_EDIT_OFFSET ED_BASE+686L // in current time format + +#define ED_EDIT_PREREAD ED_BASE+815L // OATRUE means device supports + // pre-read (recorder can also be + // player + +// +// Some error codes: +// +// device could be in local mode +#define ED_ERR_DEVICE_NOT_READY ED_BASE+700L + +#endif // __EDEVDEFS__ + +// eof edevdefs.h diff --git a/plugins/gs/gsdx9/baseclasses/errors.h b/plugins/gs/gsdx9/baseclasses/errors.h new file mode 100644 index 0000000000..c3432278e7 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/errors.h @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// File: Errors.h +// +// Desc: ActiveMovie error defines. +// +// Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __ERRORS__ +#define __ERRORS__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef _AMOVIE_ +#define AMOVIEAPI DECLSPEC_IMPORT +#else +#define AMOVIEAPI +#endif + +// codes 0-01ff are reserved for OLE +#define VFW_FIRST_CODE 0x200 +#define MAX_ERROR_TEXT_LEN 160 + +#include // includes all message definitions + +typedef BOOL (WINAPI* AMGETERRORTEXTPROCA)(HRESULT, char *, DWORD); +typedef BOOL (WINAPI* AMGETERRORTEXTPROCW)(HRESULT, WCHAR *, DWORD); + +AMOVIEAPI DWORD WINAPI AMGetErrorTextA( HRESULT hr , char *pbuffer , DWORD MaxLen); +AMOVIEAPI DWORD WINAPI AMGetErrorTextW( HRESULT hr , WCHAR *pbuffer , DWORD MaxLen); + + +#ifdef UNICODE +#define AMGetErrorText AMGetErrorTextW +typedef AMGETERRORTEXTPROCW AMGETERRORTEXTPROC; +#else +#define AMGetErrorText AMGetErrorTextA +typedef AMGETERRORTEXTPROCA AMGETERRORTEXTPROC; +#endif + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // __ERRORS__ diff --git a/plugins/gs/gsdx9/baseclasses/evcode.h b/plugins/gs/gsdx9/baseclasses/evcode.h new file mode 100644 index 0000000000..62a26b2de7 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/evcode.h @@ -0,0 +1,428 @@ +//------------------------------------------------------------------------------ +// File: EvCode.h +// +// Desc: List of standard Quartz event codes and the expected params. +// +// Copyright (c) 1992 - 2001, Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Event codes are broken into two groups +// -- system event codes +// -- extension event codes +// All system event codes are below EC_USER + +#define EC_SYSTEMBASE 0x00 +#define EC_USER 0x8000 + +// System-defined event codes +// ========================== +// +// There are three types of system-defined event codes: +// +// 1. Those which are always passed through to the application +// (To be collected by calls to GetEvent or within WaitForCompletion.) +// (e.g. EC_ERRORABORT, EC_USERABORT.) +// +// 2. Those which are pure internal and will never be passed to +// the application. (e.g. EC_SHUTDOWN) +// +// 3. Those which have default handling. Default handing implies that +// the event is not passed to the application. However, default +// handling may be canceled by calling +// IMediaEvent::CancelDefaultHandling. If the default handling is +// cancelled in this way, then the message will be delivered to the +// application and the application must action it appropriately. +// Default handling can be restored by calling RestoreDefaultHandling. +// +// We will refer to these events as application, internal and defaulted +// events respectively. +// +// System-defined events may have interface pointers, BSTR's, etc passed +// as parameters. It is therefore essential that, for any message +// retrieved using GetEvent, a matching call to FreeEventParams is made +// to ensure that relevant interfaces are released and storage freed. +// Failure to call FreeEventParams will result in memory leaks, if not +// worse. +// +// Filters sending these messages to the filter graph should not AddRef() +// any interfaces that they may pass as parameters. The filter graph +// manager will AddRef them if required. E.g. if the event is to be queued +// for the application or queued to a worker thread. + +// Each event listed below is immediately followed by a parameter list +// detailing the types of the parameters associated with the message, +// and an indication of whether the message is an application, internal +// or defaulted message. This is then followed by a short description. +// The use of "void" in the parameter list implies that the parameter is not +// used. Such parameters should be zero. + +// Other defined EC_ regions: +// DVD event codes 0x0100 - 0x0150 (dvdevcod.h) +// audio device event codes 0x0200 - 0x0250 (audevcod.h) +// WindowsMedia SDK-originated events 0x0251 - 0x0300 (see below) +// MSVIDCTL 0x0301 - 0x0325 (msvidctl.idl) +// stream buffer engine (PVR) 0x0326 - 0x0350 (sbe.idl) + +#define EC_COMPLETE 0x01 +// ( HRESULT, void ) : defaulted (special) +// Signals the completed playback of a stream within the graph. This message +// is sent by renderers when they receive end-of-stream. The default handling +// of this message results in a _SINGLE_ EC_COMPLETE being sent to the +// application when ALL of the individual renderers have signaled EC_COMPLETE +// to the filter graph. If the default handing is canceled, the application +// will see all of the individual EC_COMPLETEs. + + +#define EC_USERABORT 0x02 +// ( void, void ) : application +// In some sense, the user has requested that playback be terminated. +// This message is typically sent by renderers that render into a +// window if the user closes the window into which it was rendering. +// It is up to the application to decide if playback should actually +// be stopped. + + +#define EC_ERRORABORT 0x03 +// ( HRESULT, void ) : application +// Operation aborted because of error + + +#define EC_TIME 0x04 +// ( DWORD, DWORD ) : application +// The requested reference time occurred. (This event is currently not used). +// lParam1 is low dword of ref time, lParam2 is high dword of reftime. + + +#define EC_REPAINT 0x05 +// ( IPin * (could be NULL), void ) : defaulted +// A repaint is required - lParam1 contains the (IPin *) that needs the data +// to be sent again. Default handling is: if the output pin which the IPin is +// attached to supports the IMediaEventSink interface then it will be called +// with the EC_REPAINT first. If that fails then normal repaint processing is +// done by the filter graph. + + +// Stream error notifications +#define EC_STREAM_ERROR_STOPPED 0x06 +#define EC_STREAM_ERROR_STILLPLAYING 0x07 +// ( HRESULT, DWORD ) : application +// lParam 1 is major code, lParam2 is minor code, either may be zero. + + +#define EC_ERROR_STILLPLAYING 0x08 +// ( HRESULT, void ) : application +// The filter graph manager may issue Run's to the graph asynchronously. +// If such a Run fails, EC_ERROR_STILLPLAYING is issued to notify the +// application of the failure. The state of the underlying filters +// at such a time will be indeterminate - they will all have been asked +// to run, but some are almost certainly not. + + +#define EC_PALETTE_CHANGED 0x09 +// ( void, void ) : application +// notify application that the video palette has changed + + +#define EC_VIDEO_SIZE_CHANGED 0x0A +// ( DWORD, void ) : application +// Sent by video renderers. +// Notifies the application that the native video size has changed. +// LOWORD of the DWORD is the new width, HIWORD is the new height. + + +#define EC_QUALITY_CHANGE 0x0B +// ( void, void ) : application +// Notify application that playback degradation has occurred + + +#define EC_SHUTTING_DOWN 0x0C +// ( void, void ) : internal +// This message is sent by the filter graph manager to any plug-in +// distributors which support IMediaEventSink to notify them that +// the filter graph is starting to shutdown. + + +#define EC_CLOCK_CHANGED 0x0D +// ( void, void ) : application +// Notify application that the clock has changed. +// (i.e. SetSyncSource has been called on the filter graph and has been +// distributed successfully to the filters in the graph.) + + +#define EC_PAUSED 0x0E +// ( HRESULT, void ) : application +// Notify application the previous pause request has completed + + +#define EC_OPENING_FILE 0x10 +#define EC_BUFFERING_DATA 0x11 +// ( BOOL, void ) : application +// lParam1 == 1 --> starting to open file or buffer data +// lParam1 == 0 --> not opening or buffering any more +// (This event does not appear to be used by ActiveMovie.) + + +#define EC_FULLSCREEN_LOST 0x12 +// ( void, IBaseFilter * ) : application +// Sent by full screen renderers when switched away from full screen. +// IBaseFilter may be NULL. + + +#define EC_ACTIVATE 0x13 +// ( BOOL, IBaseFilter * ) : internal +// Sent by video renderers when they lose or gain activation. +// lParam1 is set to 1 if gained or 0 if lost +// lParam2 is the IBaseFilter* for the filter that is sending the message +// Used for sound follows focus and full-screen switching + + +#define EC_NEED_RESTART 0x14 +// ( void, void ) : defaulted +// Sent by renderers when they regain a resource (e.g. audio renderer). +// Causes a restart by Pause/put_Current/Run (if running). + + +#define EC_WINDOW_DESTROYED 0x15 +// ( IBaseFilter *, void ) : internal +// Sent by video renderers when the window has been destroyed. Handled +// by the filter graph / distributor telling the resource manager. +// lParam1 is the IBaseFilter* of the filter whose window is being destroyed + + +#define EC_DISPLAY_CHANGED 0x16 +// ( IPin *, void ) : internal +// Sent by renderers when they detect a display change. the filter graph +// will arrange for the graph to be stopped and the pin send in lParam1 +// to be reconnected. by being reconnected it allows a renderer to reset +// and connect with a more appropriate format for the new display mode +// lParam1 contains an (IPin *) that should be reconnected by the graph + + +#define EC_STARVATION 0x17 +// ( void, void ) : defaulted +// Sent by a filter when it detects starvation. Default handling (only when +// running) is for the graph to be paused until all filters enter the +// paused state and then run. Normally this would be sent by a parser or source +// filter when too little data is arriving. + + +#define EC_OLE_EVENT 0x18 +// ( BSTR, BSTR ) : application +// Sent by a filter to pass a text string to the application. +// Conventionally, the first string is a type, and the second a parameter. + + +#define EC_NOTIFY_WINDOW 0x19 +// ( HWND, void ) : internal +// Pass the window handle around during pin connection. + +#define EC_STREAM_CONTROL_STOPPED 0x1A +// ( IPin * pSender, DWORD dwCookie ) +// Notification that an earlier call to IAMStreamControl::StopAt +// has now take effect. Calls to the method can be marked +// with a cookie which is passed back in the second parameter, +// allowing applications to easily tie together request +// and completion notifications. +// +// NB: IPin will point to the pin that actioned the Stop. This +// may not be the pin that the StopAt was sent to. + +#define EC_STREAM_CONTROL_STARTED 0x1B +// ( IPin * pSender, DWORD dwCookie ) +// Notification that an earlier call to IAMStreamControl::StartAt +// has now take effect. Calls to the method can be marked +// with a cookie which is passed back in the second parameter, +// allowing applications to easily tie together request +// and completion notifications. +// +// NB: IPin will point to the pin that actioned the Start. This +// may not be the pin that the StartAt was sent to. + +#define EC_END_OF_SEGMENT 0x1C +// +// ( const REFERENCE_TIME *pStreamTimeAtEndOfSegment, DWORD dwSegmentNumber ) +// +// pStreamTimeAtEndOfSegment +// pointer to the accumulated stream clock +// time since the start of the segment - this is directly computable +// as the sum of the previous and current segment durations (Stop - Start) +// and the rate applied to each segment +// The source add this time to the time within each segment to get +// a total elapsed time +// +// dwSegmentNumber +// Segment number - starts at 0 +// +// Notifies that a segment end has been reached when the +// AM_SEEKING_Segment flags was set for IMediaSeeking::SetPositions +// Passes in an IMediaSeeking interface to allow the next segment +// to be defined by the application + +#define EC_SEGMENT_STARTED 0x1D +// +// ( const REFERENCE_TIME *pStreamTimeAtStartOfSegment, DWORD dwSegmentNumber) +// +// pStreamTimeAtStartOfSegment +// pointer to the accumulated stream clock +// time since the start of the segment - this is directly computable +// as the sum of the previous segment durations (Stop - Start) +// and the rate applied to each segment +// +// dwSegmentNumber +// Segment number - starts at 0 +// +// Notifies that a new segment has been started. +// This is sent synchronously by any entity that will issue +// EC_END_OF_SEGMENT when a new segment is started +// (See IMediaSeeking::SetPositions - AM_SEEKING_Segment flag) +// It is used to compute how many EC_END_OF_SEGMENT notifications +// to expect at the end of a segment and as a consitency check + + +#define EC_LENGTH_CHANGED 0x1E +// (void, void) +// sent to indicate that the length of the "file" has changed + +#define EC_DEVICE_LOST 0x1f +// (IUnknown, 0) +// +// request window notification when the device is available again +// (through WM_DEVICECHANGED messages registered with +// RegisterDeviceNotification; see IAMDeviceRemoval interface) + +#define EC_STEP_COMPLETE 0x24 +// (BOOL bCacelled, void) +// Step request complete +// if bCancelled is TRUE the step was cancelled. This can happen +// if the application issued some control request or because there +// was a mode change etc etc + +// Event code 25 is reserved for future use. + +#define EC_TIMECODE_AVAILABLE 0x30 +// Sent by filter supporting timecode +// Param1 has a pointer to the sending object +// Param2 has the device ID of the sending object + +#define EC_EXTDEVICE_MODE_CHANGE 0x31 +// Sent by filter supporting IAMExtDevice +// Param1 has the new mode +// Param2 has the device ID of the sending object + +#define EC_STATE_CHANGE 0x32 +// ( FILTER_STATE, BOOL bInternal) +// Used to notify the application of any state changes in the filter graph. +// lParam1 is of type enum FILTER_STATE (defined in strmif.h) and indicates +// the state of the filter graph. +// +// lParam2 == 0 indicates that the previous state change request has completed +// & a change in application state. +// lParam2 == 1 reserved for future use to indicate internal state changes. + + +#define EC_GRAPH_CHANGED 0x50 +// Sent by filter to notify interesting graph changes + +#define EC_CLOCK_UNSET 0x51 +// ( void, void ) : application +// Used to notify the filter graph to unset the current graph clock. +// Has the affect of forcing the filter graph to reestablish the graph clock +// on the next Pause/Run (note that this is only used by ksproxy, when the pin +// of a clock providing filter is disconnected) + +#define EC_VMR_RENDERDEVICE_SET 0x53 +// (Render_Device type, void) +// Identifies the type of rendering mechanism the VMR +// is using to display video. Types used include: +#define VMR_RENDER_DEVICE_OVERLAY 0x01 +#define VMR_RENDER_DEVICE_VIDMEM 0x02 +#define VMR_RENDER_DEVICE_SYSMEM 0x04 + + +#define EC_VMR_SURFACE_FLIPPED 0x54 +// (hr - Flip return code, void) +// Identifies the VMR's allocator-presenter has called the DDraw flip api on +// the surface being presented. This allows the VMR to keep its DX-VA table +// of DDraw surfaces in sync with DDraws flipping chain. + +#define EC_VMR_RECONNECTION_FAILED 0x55 +// (hr - ReceiveConnection return code, void) +// Identifies that an upstream decoder tried to perform a dynamic format +// change and the VMR was unable to accept the new format. + + +#define EC_PREPROCESS_COMPLETE 0x56 +// Sent by the WM ASF writer filter (WMSDK V9 version) to signal the completion +// of a pre-process run when running in multipass encode mode. +// Param1 = 0, Param2 = IBaseFilter ptr of sending filter + +#define EC_CODECAPI_EVENT 0x57 +// Sent by the Codec API when an event is encountered. Both the Data +// must be freed by the recipient using CoTaskMemFree +// Param1 = UserDataPointer, Param2 = VOID* Data + +//------------------------------------------ +// +// BDA events: +// +// Event code 0x80 through 0x8f are reserved for BDA +// + + +//------------------------------------------ +// +// WindowsMedia SDK filter-specific events: +// +// +// Note that for EC_WMT_EVENT events the wmsdk-based filters use the following structure for +// passing event parameters to the app: +#ifndef AM_WMT_EVENT_DATA_DEFINED +#define AM_WMT_EVENT_DATA_DEFINED +typedef struct { + HRESULT hrStatus; // status code + void * pData; // event data +} AM_WMT_EVENT_DATA; +#endif +// +#define EC_WMT_EVENT_BASE 0x0251 +// +#define EC_WMT_INDEX_EVENT EC_WMT_EVENT_BASE +// WindowsMedia SDK-originated file indexing status, sent by WMSDK-based filters +// +// lParam1 is one of the enum WMT_STATUS messages listed below, sent by the WindowsMedia SDK +// lParam2 is specific to the lParam event +// +// the following WMT_STATUS messages are sent for this event: +// WMT_STARTED - lParam2 is 0 +// WMT_CLOSED - lParam2 is 0 +// WMT_INDEX_PROGRESS - lParam2 is a DWORD containing the progress percent complete +// +#define EC_WMT_EVENT EC_WMT_EVENT_BASE+1 +// WindowsMedia SDK-originated event, sent by WMSDK-based filters +// +// lParam1 is one of the enum WMT_STATUS messages listed below, sent by the WindowsMedia SDK +// lParam2 is a pointer an AM_WMT_EVENT_DATA structure where, +// hrStatus is the status code sent by the wmsdk +// pData is specific to the lParam1 event +// +// the following WMT_STATUS messages are sent by the WMSDK Reader filter for this event: +// WMT_NO_RIGHTS - pData is a pointer to a WCHAR string containing a challenge URL +// WMT_ACQUIRE_LICENSE - lParam2 is a pointer to a WM_GET_LICENSE_DATA struct +// WMT_NO_RIGHTS_EX - lParam2 is a pointer to a WM_GET_LICENSE_DATA struct +// WMT_NEEDS_INDIVIDUALIZATION - lParam2 is NULL +// WMT_INDIVIDUALIZE - lParam2 is a pointer to a WM_INDIVIDUALIZE_STATUS struct +// the WMSDK (V9) ASF Writer filter will send this event in response to a wmsdk-signaled error during file +// writing, along with the wmsdk WMT_STATUS error as the lParam1 and hrStatus embedded in the +// AM_WMT_EVENT_DATA struct pointed to by the lParam2 pointer. +// +// end WMSDK-originated events +//----------------------------------------- + + +#define EC_BUILT 0x300 +// Sent to notify transition from unbuilt to built state + + +#define EC_UNBUILT 0x301 +// Sent to notify transtion from built to unbuilt state diff --git a/plugins/gs/gsdx9/baseclasses/fourcc.h b/plugins/gs/gsdx9/baseclasses/fourcc.h new file mode 100644 index 0000000000..dea8171a6b --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/fourcc.h @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// File: FourCC.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// FOURCCMap +// +// provides a mapping between old-style multimedia format DWORDs +// and new-style GUIDs. +// +// A range of 4 billion GUIDs has been allocated to ensure that this +// mapping can be done straightforwardly one-to-one in both directions. +// +// January 95 + + +#ifndef __FOURCC__ +#define __FOURCC__ + + +// Multimedia format types are marked with DWORDs built from four 8-bit +// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include +// a subtype GUID. In order to simplify the mapping, GUIDs in the range: +// XXXXXXXX-0000-0010-8000-00AA00389B71 +// are reserved for FOURCCs. + +class FOURCCMap : public GUID +{ + +public: + FOURCCMap(); + FOURCCMap(DWORD Fourcc); + FOURCCMap(const GUID *); + + + DWORD GetFOURCC(void); + void SetFOURCC(DWORD fourcc); + void SetFOURCC(const GUID *); + +private: + void InitGUID(); +}; + +#define GUID_Data2 0 +#define GUID_Data3 0x10 +#define GUID_Data4_1 0xaa000080 +#define GUID_Data4_2 0x719b3800 + +inline void +FOURCCMap::InitGUID() { + Data2 = GUID_Data2; + Data3 = GUID_Data3; + ((DWORD *)Data4)[0] = GUID_Data4_1; + ((DWORD *)Data4)[1] = GUID_Data4_2; +} + +inline +FOURCCMap::FOURCCMap() { + InitGUID(); + SetFOURCC( DWORD(0)); +} + +inline +FOURCCMap::FOURCCMap(DWORD fourcc) +{ + InitGUID(); + SetFOURCC(fourcc); +} + +inline +FOURCCMap::FOURCCMap(const GUID * pGuid) +{ + InitGUID(); + SetFOURCC(pGuid); +} + +inline void +FOURCCMap::SetFOURCC(const GUID * pGuid) +{ + FOURCCMap * p = (FOURCCMap*) pGuid; + SetFOURCC(p->GetFOURCC()); +} + +inline void +FOURCCMap::SetFOURCC(DWORD fourcc) +{ + Data1 = fourcc; +} + +inline DWORD +FOURCCMap::GetFOURCC(void) +{ + return Data1; +} + +#endif /* __FOURCC__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/measure.h b/plugins/gs/gsdx9/baseclasses/measure.h new file mode 100644 index 0000000000..75365e3a66 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/measure.h @@ -0,0 +1,222 @@ +//------------------------------------------------------------------------------ +// File: Measure.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + The idea is to pepper the source code with interesting measurements and + have the last few thousand of these recorded in a circular buffer that + can be post-processed to give interesting numbers. + + WHAT THE LOG LOOKS LIKE: + + Time (sec) Type Delta Incident_Name + 0.055,41 NOTE -. Incident Nine - Another note + 0.055,42 NOTE 0.000,01 Incident Nine - Another note + 0.055,44 NOTE 0.000,02 Incident Nine - Another note + 0.055,45 STOP -. Incident Eight - Also random + 0.055,47 START -. Incident Seven - Random + 0.055,49 NOTE 0.000,05 Incident Nine - Another note + ------- ---------------- + 0.125,60 STOP 0.000,03 Msr_Stop + 0.125,62 START -. Msr_Start + 0.125,63 START -. Incident Two - Start/Stop + 0.125,65 STOP 0.000,03 Msr_Start + 0.125,66 START -. Msr_Stop + 0.125,68 STOP 0.000,05 Incident Two - Start/Stop + 0.125,70 STOP 0.000,04 Msr_Stop + 0.125,72 START -. Msr_Start + 0.125,73 START -. Incident Two - Start/Stop + 0.125,75 STOP 0.000,03 Msr_Start + 0.125,77 START -. Msr_Stop + 0.125,78 STOP 0.000,05 Incident Two - Start/Stop + 0.125,80 STOP 0.000,03 Msr_Stop + 0.125,81 NOTE -. Incident Three - single Note + 0.125,83 START -. Incident Four - Start, no stop + 0.125,85 START -. Incident Five - Single Start/Stop + 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop + +Number Average StdDev Smallest Largest Incident_Name + 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note + 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop + 1 -. -. -. -. Incident Three - single Note + 0 -. -. -. -. Incident Four - Start, no stop + 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop + 0 -. -. -. -. Incident Six - zero occurrences + 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random + 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random + 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note + 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note + 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start + 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop + + WHAT IT MEANS: + The log shows what happened and when. Each line shows the time at which + something happened (see WHAT YOU CODE below) what it was that happened + and (if approporate) the time since the corresponding previous event + (that's the delta column). + + The statistics show how many times each event occurred, what the average + delta time was, also the standard deviation, largest and smalles delta. + + WHAT YOU CODE: + + Before anything else executes: - register your ids + + int id1 = Msr_Register("Incident One - Note"); + int id2 = Msr_Register("Incident Two - Start/Stop"); + int id3 = Msr_Register("Incident Three - single Note"); + etc. + + At interesting moments: + + // To measure a repetitive event - e.g. end of bitblt to screen + Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" + + or + + // To measure an elapsed time e.g. time taken to decode an MPEG B-frame + Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" + . . . + MsrStop(Id2); // "Finished MPEG decode" + + At the end: + + HANDLE hFile; + hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + Msr_Dump(hFile); // This writes the log out to the file + CloseHandle(hFile); + + or + + Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); + // but if you are writing it out to the debugger + // then the times are probably all garbage because + // the debugger can make things run awfully slow. + + A given id should be used either for start / stop or Note calls. If Notes + are mixed in with Starts and Stops their statistics will be gibberish. + + If you code the calls in upper case i.e. MSR_START(idMunge); then you get + macros which will turn into nothing unless PERF is defined. + + You can reset the statistical counts for a given id by calling Reset(Id). + They are reset by default at the start. + It logs Reset as a special incident, so you can see it in the log. + + The log is a circular buffer in storage (to try to minimise disk I/O). + It overwrites the oldest entries once full. The statistics include ALL + incidents since the last Reset, whether still visible in the log or not. +*/ + +#ifndef __MEASURE__ +#define __MEASURE__ + +#ifdef PERF +#define MSR_INIT() Msr_Init() +#define MSR_TERMINATE() Msr_Terminate() +#define MSR_REGISTER(a) Msr_Register(a) +#define MSR_RESET(a) Msr_Reset(a) +#define MSR_CONTROL(a) Msr_Control(a) +#define MSR_START(a) Msr_Start(a) +#define MSR_STOP(a) Msr_Stop(a) +#define MSR_NOTE(a) Msr_Note(a) +#define MSR_INTEGER(a,b) Msr_Integer(a,b) +#define MSR_DUMP(a) Msr_Dump(a) +#define MSR_DUMPSTATS(a) Msr_DumpStats(a) +#else +#define MSR_INIT() ((void)0) +#define MSR_TERMINATE() ((void)0) +#define MSR_REGISTER(a) 0 +#define MSR_RESET(a) ((void)0) +#define MSR_CONTROL(a) ((void)0) +#define MSR_START(a) ((void)0) +#define MSR_STOP(a) ((void)0) +#define MSR_NOTE(a) ((void)0) +#define MSR_INTEGER(a,b) ((void)0) +#define MSR_DUMP(a) ((void)0) +#define MSR_DUMPSTATS(a) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// This must be called first - (called by the DllEntry) + +void WINAPI Msr_Init(void); + + +// Call this last to clean up (or just let it fall off the end - who cares?) + +void WINAPI Msr_Terminate(void); + + +// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note +// everything that's logged is called an "incident". + +int WINAPI Msr_Register(LPTSTR Incident); + + +// Reset the statistical counts for an incident + +void WINAPI Msr_Reset(int Id); + + +// Reset all the counts for all incidents +#define MSR_RESET_ALL 0 +#define MSR_PAUSE 1 +#define MSR_RUN 2 + +void WINAPI Msr_Control(int iAction); + + +// log the start of an operation + +void WINAPI Msr_Start(int Id); + + +// log the end of an operation + +void WINAPI Msr_Stop(int Id); + + +// log a one-off or repetitive operation + +void WINAPI Msr_Note(int Id); + + +// log an integer (on which we can see statistics later) +void WINAPI Msr_Integer(int Id, int n); + + +// print out all the vaialable log (it may have wrapped) and then the statistics. +// When the log wraps you lose log but the statistics are still complete. +// hFIle==NULL => use DbgLog +// otherwise hFile must have come from CreateFile or OpenFile. + +void WINAPI Msr_Dump(HANDLE hFile); + + +// just dump the statistics - never mind the log + +void WINAPI Msr_DumpStats(HANDLE hFile); + +// Type definitions in case you want to declare a pointer to the dump functions +// (makes it a trifle easier to do dynamic linking +// i.e. LoadModule, GetProcAddress and call that) + +// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever +typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); +typedef void WINAPI MSR_CONTROLPROC(int iAction); + + +#ifdef __cplusplus +} +#endif + +#endif // __MEASURE__ diff --git a/plugins/gs/gsdx9/baseclasses/msgthrd.h b/plugins/gs/gsdx9/baseclasses/msgthrd.h new file mode 100644 index 0000000000..f07d5162ad --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/msgthrd.h @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// File: MsgThrd.h +// +// Desc: DirectShow base classes - provides support for a worker thread +// class to which one can asynchronously post messages. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Message class - really just a structure. +// +class CMsg { +public: + UINT uMsg; + DWORD dwFlags; + LPVOID lpParam; + CAMEvent *pEvent; + + CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt) + : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} + + CMsg() + : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} +}; + +// This is the actual thread class. It exports all the usual thread control +// functions. The created thread is different from a normal WIN32 thread in +// that it is prompted to perform particaular tasks by responding to messages +// posted to its message queue. +// +class AM_NOVTABLE CMsgThread { +private: + static DWORD WINAPI DefaultThreadProc(LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + +protected: + + // if you want to override GetThreadMsg to block on other things + // as well as this queue, you need access to this + CGenericList m_ThreadQueue; + CCritSec m_Lock; + HANDLE m_hSem; + LONG m_lWaiting; + +public: + CMsgThread() + : m_ThreadId(0), + m_hThread(NULL), + m_lWaiting(0), + m_hSem(NULL), + // make a list with a cache of 5 items + m_ThreadQueue(NAME("MsgThread list"), 5) + { + } + + ~CMsgThread(); + // override this if you want to block on other things as well + // as the message loop + void virtual GetThreadMsg(CMsg *msg); + + // override this if you want to do something on thread startup + virtual void OnThreadInit() { + }; + + BOOL CreateThread(); + + BOOL WaitForThreadExit(LPDWORD lpdwExitCode) { + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + return GetExitCodeThread(m_hThread, lpdwExitCode); + } + return FALSE; + } + + DWORD ResumeThread() { + return ::ResumeThread(m_hThread); + } + + DWORD SuspendThread() { + return ::SuspendThread(m_hThread); + } + + int GetThreadPriority() { + return ::GetThreadPriority(m_hThread); + } + + BOOL SetThreadPriority(int nPriority) { + return ::SetThreadPriority(m_hThread, nPriority); + } + + HANDLE GetThreadHandle() { + return m_hThread; + } + + DWORD GetThreadId() { + return m_ThreadId; + } + + + void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, + LPVOID lpMsgParam, CAMEvent *pEvent = NULL) { + CAutoLock lck(&m_Lock); + CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); + m_ThreadQueue.AddTail(pMsg); + if (m_lWaiting != 0) { + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } + } + + // This is the function prototype of the function that the client + // supplies. It is always called on the created thread, never on + // the creator thread. + // + virtual LRESULT ThreadMessageProc( + UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0; +}; + diff --git a/plugins/gs/gsdx9/baseclasses/mtype.cpp b/plugins/gs/gsdx9/baseclasses/mtype.cpp new file mode 100644 index 0000000000..a383f423b2 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/mtype.cpp @@ -0,0 +1,477 @@ +//------------------------------------------------------------------------------ +// File: MType.cpp +// +// Desc: DirectShow base classes - implements a class that holds and +// manages media type information. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// helper class that derived pin objects can use to compare media +// types etc. Has same data members as the struct AM_MEDIA_TYPE defined +// in the streams IDL file, but also has (non-virtual) functions + +#include +#include + +CMediaType::~CMediaType(){ + FreeMediaType(*this); +} + + +CMediaType::CMediaType() +{ + InitMediaType(); +} + + +CMediaType::CMediaType(const GUID * type) +{ + InitMediaType(); + majortype = *type; +} + + +// copy constructor does a deep copy of the format block + +CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate +// the following assignment operator itself, however it could introduce some +// memory conflicts and leaks in the process because the structure contains +// a dynamically allocated block (pbFormat) which it will not copy correctly + +CMediaType& +CMediaType::operator=(const AM_MEDIA_TYPE& rt) +{ + Set(rt); + return *this; +} + +CMediaType& +CMediaType::operator=(const CMediaType& rt) +{ + *this = (AM_MEDIA_TYPE &) rt; + return *this; +} + +BOOL +CMediaType::operator == (const CMediaType& rt) const +{ + // I don't believe we need to check sample size or + // temporal compression flags, since I think these must + // be represented in the type, subtype and format somehow. They + // are pulled out as separate flags so that people who don't understand + // the particular format representation can still see them, but + // they should duplicate information in the format block. + + return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && + (IsEqualGUID(subtype,rt.subtype) == TRUE) && + (IsEqualGUID(formattype,rt.formattype) == TRUE) && + (cbFormat == rt.cbFormat) && + ( (cbFormat == 0) || + (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); +} + + +BOOL +CMediaType::operator != (const CMediaType& rt) const +{ + /* Check to see if they are equal */ + + if (*this == rt) { + return FALSE; + } + return TRUE; +} + + +HRESULT +CMediaType::Set(const CMediaType& rt) +{ + return Set((AM_MEDIA_TYPE &) rt); +} + + +HRESULT +CMediaType::Set(const AM_MEDIA_TYPE& rt) +{ + if (&rt != this) { + FreeMediaType(*this); + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr)) { + return E_OUTOFMEMORY; + } + } + + return S_OK; +} + + +BOOL +CMediaType::IsValid() const +{ + return (!IsEqualGUID(majortype,GUID_NULL)); +} + + +void +CMediaType::SetType(const GUID* ptype) +{ + majortype = *ptype; +} + + +void +CMediaType::SetSubtype(const GUID* ptype) +{ + subtype = *ptype; +} + + +ULONG +CMediaType::GetSampleSize() const { + if (IsFixedSize()) { + return lSampleSize; + } else { + return 0; + } +} + + +void +CMediaType::SetSampleSize(ULONG sz) { + if (sz == 0) { + SetVariableSize(); + } else { + bFixedSizeSamples = TRUE; + lSampleSize = sz; + } +} + + +void +CMediaType::SetVariableSize() { + bFixedSizeSamples = FALSE; +} + + +void +CMediaType::SetTemporalCompression(BOOL bCompressed) { + bTemporalCompression = bCompressed; +} + +BOOL +CMediaType::SetFormat(BYTE * pformat, ULONG cb) +{ + if (NULL == AllocFormatBuffer(cb)) + return(FALSE); + + ASSERT(pbFormat); + memcpy(pbFormat, pformat, cb); + return(TRUE); +} + + +// set the type of the media type format block, this type defines what you +// will actually find in the format pointer. For example FORMAT_VideoInfo or +// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a +// property set. Before sending out media types this should be filled in. + +void +CMediaType::SetFormatType(const GUID *pformattype) +{ + formattype = *pformattype; +} + + +// reset the format buffer + +void CMediaType::ResetFormatBuffer() +{ + if (cbFormat) { + CoTaskMemFree((PVOID)pbFormat); + } + cbFormat = 0; + pbFormat = NULL; +} + + +// allocate length bytes for the format and return a read/write pointer +// If we cannot allocate the new block of memory we return NULL leaving +// the original block of memory untouched (as does ReallocFormatBuffer) + +BYTE* +CMediaType::AllocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // delete the old format + + if (cbFormat != 0) { + ASSERT(pbFormat); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pbFormat; +} + + +// reallocate length bytes for the format and return a read/write pointer +// to it. We keep as much information as we can given the new buffer size +// if this fails the original format buffer is left untouched. The caller +// is responsible for ensuring the size of memory required is non zero + +BYTE* +CMediaType::ReallocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // copy any previous format (or part of if new is smaller) + // delete the old format and replace with the new one + + if (cbFormat != 0) { + ASSERT(pbFormat); + memcpy(pNewFormat,pbFormat,min(length,cbFormat)); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pNewFormat; +} + +// initialise a media type structure + +void CMediaType::InitMediaType() +{ + ZeroMemory((PVOID)this, sizeof(*this)); + lSampleSize = 1; + bFixedSizeSamples = TRUE; +} + + +// a partially specified media type can be passed to IPin::Connect +// as a constraint on the media type used in the connection. +// the type, subtype or format type can be null. +BOOL +CMediaType::IsPartiallySpecified(void) const +{ + if ((majortype == GUID_NULL) || + (formattype == GUID_NULL)) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL +CMediaType::MatchesPartial(const CMediaType* ppartial) const +{ + if ((ppartial->majortype != GUID_NULL) && + (majortype != ppartial->majortype)) { + return FALSE; + } + if ((ppartial->subtype != GUID_NULL) && + (subtype != ppartial->subtype)) { + return FALSE; + } + + if (ppartial->formattype != GUID_NULL) { + // if the format block is specified then it must match exactly + if (formattype != ppartial->formattype) { + return FALSE; + } + if (cbFormat != ppartial->cbFormat) { + return FALSE; + } + if ((cbFormat != 0) && + (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { + return FALSE; + } + } + + return TRUE; + +} + + + +// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure +// which is useful when calling IEnumMediaTypes::Next as the interface +// implementation allocates the structures which you must later delete +// the format block may also be a pointer to an interface to release + +void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt) +{ + // allow NULL pointers for coding simplicity + + if (pmt == NULL) { + return; + } + + FreeMediaType(*pmt); + CoTaskMemFree((PVOID)pmt); +} + + +// this also comes in useful when using the IEnumMediaTypes interface so +// that you can copy a media type, you can do nearly the same by creating +// a CMediaType object but as soon as it goes out of scope the destructor +// will delete the memory it allocated (this takes a copy of the memory) + +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) +{ + ASSERT(pSrc); + + // Allocate a block of memory for the media type + + AM_MEDIA_TYPE *pMediaType = + (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + + if (pMediaType == NULL) { + return NULL; + } + // Copy the variable length format block + + HRESULT hr = CopyMediaType(pMediaType,pSrc); + if (FAILED(hr)) { + CoTaskMemFree((PVOID)pMediaType); + return NULL; + } + + return pMediaType; +} + + +// Copy 1 media type to another + +HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) +{ + // We'll leak if we copy onto one that already exists - there's one + // case we can check like that - copying to itself. + ASSERT(pmtSource != pmtTarget); + *pmtTarget = *pmtSource; + if (pmtSource->cbFormat != 0) { + ASSERT(pmtSource->pbFormat != NULL); + pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); + if (pmtTarget->pbFormat == NULL) { + pmtTarget->cbFormat = 0; + return E_OUTOFMEMORY; + } else { + CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, + pmtTarget->cbFormat); + } + } + if (pmtTarget->pUnk != NULL) { + pmtTarget->pUnk->AddRef(); + } + + return S_OK; +} + +// Free an existing media type (ie free resources it holds) + +void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + + // Strictly unnecessary but tidier + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + AM_MEDIA_TYPE *pmt, + BOOL bSetFormat +) +{ + pmt->majortype = MEDIATYPE_Audio; + if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; + } else { + pmt->subtype = FOURCCMap(pwfx->wFormatTag); + } + pmt->formattype = FORMAT_WaveFormatEx; + pmt->bFixedSizeSamples = TRUE; + pmt->bTemporalCompression = FALSE; + pmt->lSampleSize = pwfx->nBlockAlign; + pmt->pUnk = NULL; + if (bSetFormat) { + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + pmt->cbFormat = sizeof(WAVEFORMATEX); + } else { + pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; + } + pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); + if (pmt->pbFormat == NULL) { + return E_OUTOFMEMORY; + } + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); + ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; + } else { + CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); + } + } + return S_OK; +} + +// eliminate very many spurious warnings from MS compiler +#pragma warning(disable:4514) diff --git a/plugins/gs/gsdx9/baseclasses/mtype.h b/plugins/gs/gsdx9/baseclasses/mtype.h new file mode 100644 index 0000000000..7a8a2395b3 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/mtype.h @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// File: MtType.h +// +// Desc: DirectShow base classes - defines a class that holds and manages +// media type information. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __MTYPE__ +#define __MTYPE__ + +/* Helper class that derived pin objects can use to compare media + types etc. Has same data members as the struct AM_MEDIA_TYPE defined + in the streams IDL file, but also has (non-virtual) functions */ + +class CMediaType : public _AMMediaType { + +public: + + ~CMediaType(); + CMediaType(); + CMediaType(const GUID * majortype); + CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL); + CMediaType(const CMediaType&, HRESULT* phr = NULL); + + CMediaType& operator=(const CMediaType&); + CMediaType& operator=(const AM_MEDIA_TYPE&); + + BOOL operator == (const CMediaType&) const; + BOOL operator != (const CMediaType&) const; + + HRESULT Set(const CMediaType& rt); + HRESULT Set(const AM_MEDIA_TYPE& rt); + + BOOL IsValid() const; + + const GUID *Type() const { return &majortype;} ; + void SetType(const GUID *); + const GUID *Subtype() const { return &subtype;} ; + void SetSubtype(const GUID *); + + BOOL IsFixedSize() const {return bFixedSizeSamples; }; + BOOL IsTemporalCompressed() const {return bTemporalCompression; }; + ULONG GetSampleSize() const; + + void SetSampleSize(ULONG sz); + void SetVariableSize(); + void SetTemporalCompression(BOOL bCompressed); + + // read/write pointer to format - can't change length without + // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer + + BYTE* Format() const {return pbFormat; }; + ULONG FormatLength() const { return cbFormat; }; + + void SetFormatType(const GUID *); + const GUID *FormatType() const {return &formattype; }; + BOOL SetFormat(BYTE *pFormat, ULONG length); + void ResetFormatBuffer(); + BYTE* AllocFormatBuffer(ULONG length); + BYTE* ReallocFormatBuffer(ULONG length); + + void InitMediaType(); + + BOOL MatchesPartial(const CMediaType* ppartial) const; + BOOL IsPartiallySpecified(void) const; +}; + + +/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE + structure which is useful when using the IEnumMediaFormats interface as + the implementation allocates the structures which you must later delete */ + +void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt); +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); +HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); +void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt); + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + AM_MEDIA_TYPE *pmt, + BOOL bSetFormat); + +#endif /* __MTYPE__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/outputq.cpp b/plugins/gs/gsdx9/baseclasses/outputq.cpp new file mode 100644 index 0000000000..0522a94d37 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/outputq.cpp @@ -0,0 +1,794 @@ +//------------------------------------------------------------------------------ +// File: OutputQ.cpp +// +// Desc: DirectShow base classes - implements COutputQueue class used by an +// output pin which may sometimes want to queue output samples on a +// separate thread and sometimes call Receive() directly on the input +// pin. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + + +// +// COutputQueue Constructor : +// +// Determines if a thread is to be created and creates resources +// +// pInputPin - the downstream input pin we're queueing samples to +// +// phr - changed to a failure code if this function fails +// (otherwise unchanges) +// +// bAuto - Ask pInputPin if it can block in Receive by calling +// its ReceiveCanBlock method and create a thread if +// it can block, otherwise not. +// +// bQueue - if bAuto == FALSE then we create a thread if and only +// if bQueue == TRUE +// +// lBatchSize - work in batches of lBatchSize +// +// bBatchEact - Use exact batch sizes so don't send until the +// batch is full or SendAnyway() is called +// +// lListSize - If we create a thread make the list of samples queued +// to the thread have this size cache +// +// dwPriority - If we create a thread set its priority to this +// +COutputQueue::COutputQueue( + IPin *pInputPin, // Pin to send stuff to + HRESULT *phr, // 'Return code' + BOOL bAuto, // Ask pin if queue or not + BOOL bQueue, // Send through queue + LONG lBatchSize, // Batch + BOOL bBatchExact, // Batch exactly to BatchSize + LONG lListSize, + DWORD dwPriority, + bool bFlushingOpt // flushing optimization + ) : m_lBatchSize(lBatchSize), + m_bBatchExact(bBatchExact && (lBatchSize > 1)), + m_hThread(NULL), + m_hSem(NULL), + m_List(NULL), + m_pPin(pInputPin), + m_ppSamples(NULL), + m_lWaiting(0), + m_pInputPin(NULL), + m_bSendAnyway(FALSE), + m_nBatched(0), + m_bFlushing(FALSE), + m_bFlushed(TRUE), + m_bFlushingOpt(bFlushingOpt), + m_bTerminate(FALSE), + m_hEventPop(NULL), + m_hr(S_OK) +{ + ASSERT(m_lBatchSize > 0); + + + if (FAILED(*phr)) { + return; + } + + // Check the input pin is OK and cache its IMemInputPin interface + + *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); + if (FAILED(*phr)) { + return; + } + + // See if we should ask the downstream pin + + if (bAuto) { + HRESULT hr = m_pInputPin->ReceiveCanBlock(); + if (SUCCEEDED(hr)) { + bQueue = hr == S_OK; + } + } + + // Create our sample batch + + m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; + if (m_ppSamples == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + // If we're queueing allocate resources + + if (bQueue) { + DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + m_List = new CSampleList(NAME("Sample Queue List"), + lListSize, + FALSE // No lock + ); + if (m_List == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + + DWORD dwThreadId; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + (LPVOID)this, + 0, + &dwThreadId); + if (m_hThread == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + SetThreadPriority(m_hThread, dwPriority); + } else { + DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); + } +} + +// +// COutputQueuee Destructor : +// +// Free all resources - +// +// Thread, +// Batched samples +// +COutputQueue::~COutputQueue() +{ + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); + /* Free our pointer */ + if (m_pInputPin != NULL) { + m_pInputPin->Release(); + } + if (m_hThread != NULL) { + { + CAutoLock lck(this); + m_bTerminate = TRUE; + m_hr = S_FALSE; + NotifyThread(); + } + DbgWaitForSingleObject(m_hThread); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + + // The thread frees the samples when asked to terminate + + ASSERT(m_List->GetCount() == 0); + delete m_List; + } else { + FreeSamples(); + } + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + delete [] m_ppSamples; +} + +// +// Call the real thread proc as a member function +// +DWORD WINAPI COutputQueue::InitialThreadProc(LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + + COutputQueue *pSampleQueue = (COutputQueue *)pv; + DWORD dwReturn = pSampleQueue->ThreadProc(); + + if(hrCoInit == S_OK) { + CoUninitialize(); + } + + return dwReturn; +} + +// +// Thread sending the samples downstream : +// +// When there is nothing to do the thread sets m_lWaiting (while +// holding the critical section) and then waits for m_hSem to be +// set (not holding the critical section) +// +DWORD COutputQueue::ThreadProc() +{ + while (TRUE) { + BOOL bWait = FALSE; + IMediaSample *pSample; + LONG lNumberToSend; // Local copy + NewSegmentPacket* ppacket; + + // + // Get a batch of samples and send it if possible + // In any case exit the loop if there is a control action + // requested + // + { + CAutoLock lck(this); + while (TRUE) { + + if (m_bTerminate) { + FreeSamples(); + return 0; + } + if (m_bFlushing) { + FreeSamples(); + SetEvent(m_evFlushComplete); + } + + // Get a sample off the list + + pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample != NULL && + !IsSpecialSample(pSample)) { + + // If its just a regular sample just add it to the batch + // and exit the loop if the batch is full + + m_ppSamples[m_nBatched++] = pSample; + if (m_nBatched == m_lBatchSize) { + break; + } + } else { + + // If there was nothing in the queue and there's nothing + // to send (either because there's nothing or the batch + // isn't full) then prepare to wait + + if (pSample == NULL && + (m_bBatchExact || m_nBatched == 0)) { + + // Tell other thread to set the event when there's + // something do to + + ASSERT(m_lWaiting == 0); + m_lWaiting++; + bWait = TRUE; + } else { + + // We break out of the loop on SEND_PACKET unless + // there's nothing to send + + if (pSample == SEND_PACKET && m_nBatched == 0) { + continue; + } + + if (pSample == NEW_SEGMENT) { + // now we need the parameters - we are + // guaranteed that the next packet contains them + ppacket = (NewSegmentPacket *) m_List->RemoveHead(); + // we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket); + } + // EOS_PACKET falls through here and we exit the loop + // In this way it acts like SEND_PACKET + } + break; + } + } + if (!bWait) { + // We look at m_nBatched from the client side so keep + // it up to date inside the critical section + lNumberToSend = m_nBatched; // Local copy + m_nBatched = 0; + } + } + + // Wait for some more data + + if (bWait) { + DbgWaitForSingleObject(m_hSem); + continue; + } + + + + // OK - send it if there's anything to send + // We DON'T check m_bBatchExact here because either we've got + // a full batch or we dropped through because we got + // SEND_PACKET or EOS_PACKET - both of which imply we should + // flush our batch + + if (lNumberToSend != 0) { + long nProcessed; + if (m_hr == S_OK) { + ASSERT(!m_bFlushed); + HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + lNumberToSend, + &nProcessed); + /* Don't overwrite a flushing state HRESULT */ + CAutoLock lck(this); + if (m_hr == S_OK) { + m_hr = hr; + } + ASSERT(!m_bFlushed); + } + while (lNumberToSend != 0) { + m_ppSamples[--lNumberToSend]->Release(); + } + if (m_hr != S_OK) { + + // In any case wait for more data - S_OK just + // means there wasn't an error + + DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), + m_hr)); + } + } + + // Check for end of stream + + if (pSample == EOS_PACKET) { + + // We don't send even end of stream on if we've previously + // returned something other than S_OK + // This is because in that case the pin which returned + // something other than S_OK should have either sent + // EndOfStream() or notified the filter graph + + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } + + // Data from a new source + + if (pSample == RESET_PACKET) { + m_hr = S_OK; + SetEvent(m_evFlushComplete); + } + + if (pSample == NEW_SEGMENT) { + m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); + delete ppacket; + } + } +} + +// Send batched stuff anyway +void COutputQueue::SendAnyway() +{ + if (!IsQueued()) { + + // m_bSendAnyway is a private parameter checked in ReceiveMultiple + + m_bSendAnyway = TRUE; + LONG nProcessed; + ReceiveMultiple(NULL, 0, &nProcessed); + m_bSendAnyway = FALSE; + + } else { + CAutoLock lck(this); + QueueSample(SEND_PACKET); + NotifyThread(); + } +} + +void +COutputQueue::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (!IsQueued()) { + if (S_OK == m_hr) { + if (m_bBatchExact) { + SendAnyway(); + } + m_pPin->NewSegment(tStart, tStop, dRate); + } + } else { + if (m_hr == S_OK) { + // + // we need to queue the new segment to appear in order in the + // data, but we need to pass parameters to it. Rather than + // take the hit of wrapping every single sample so we can tell + // special ones apart, we queue special pointers to indicate + // special packets, and we guarantee (by holding the + // critical section) that the packet immediately following a + // NEW_SEGMENT value is a NewSegmentPacket containing the + // parameters. + NewSegmentPacket * ppack = new NewSegmentPacket; + if (ppack == NULL) { + return; + } + ppack->tStart = tStart; + ppack->tStop = tStop; + ppack->dRate = dRate; + + CAutoLock lck(this); + QueueSample(NEW_SEGMENT); + QueueSample( (IMediaSample*) ppack); + NotifyThread(); + } + } +} + + +// +// End of Stream is queued to output device +// +void COutputQueue::EOS() +{ + CAutoLock lck(this); + if (!IsQueued()) { + if (m_bBatchExact) { + SendAnyway(); + } + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + m_bFlushed = FALSE; + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } else { + if (m_hr == S_OK) { + m_bFlushed = FALSE; + QueueSample(EOS_PACKET); + NotifyThread(); + } + } +} + +// +// Flush all the samples in the queue +// +void COutputQueue::BeginFlush() +{ + if (IsQueued()) { + { + CAutoLock lck(this); + + // block receives -- we assume this is done by the + // filter in which we are a component + + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + + // Optimize so we don't keep calling downstream all the time + + if (m_bFlushed && m_bFlushingOpt) { + return; + } + + // Make sure we really wait for the flush to complete + m_evFlushComplete.Reset(); + + NotifyThread(); + } + + // pass this downstream + + m_pPin->BeginFlush(); + } else { + // pass downstream first to avoid deadlocks + m_pPin->BeginFlush(); + CAutoLock lck(this); + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + } + +} + +// +// leave flush mode - pass this downstream +void COutputQueue::EndFlush() +{ + { + CAutoLock lck(this); + ASSERT(m_bFlushing); + if (m_bFlushingOpt && m_bFlushed && IsQueued()) { + m_bFlushing = FALSE; + m_hr = S_OK; + return; + } + } + + // sync with pushing thread -- done in BeginFlush + // ensure no more data to go downstream -- done in BeginFlush + // + // Because we are synching here there is no need to hold the critical + // section (in fact we'd deadlock if we did!) + + if (IsQueued()) { + m_evFlushComplete.Wait(); + } else { + FreeSamples(); + } + + // Be daring - the caller has guaranteed no samples will arrive + // before EndFlush() returns + + m_bFlushing = FALSE; + m_bFlushed = TRUE; + + // call EndFlush on downstream pins + + m_pPin->EndFlush(); + + m_hr = S_OK; +} + +// COutputQueue::QueueSample +// +// private method to Send a sample to the output queue +// The critical section MUST be held when this is called + +void COutputQueue::QueueSample(IMediaSample *pSample) +{ + if (NULL == m_List->AddTail(pSample)) { + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } + } +} + +// +// COutputQueue::Receive() +// +// Send a single sample by the multiple sample route +// (NOTE - this could be optimized if necessary) +// +// On return the sample will have been Release()'d +// + +HRESULT COutputQueue::Receive(IMediaSample *pSample) +{ + LONG nProcessed; + return ReceiveMultiple(&pSample, 1, &nProcessed); +} + +// +// COutputQueue::ReceiveMultiple() +// +// Send a set of samples to the downstream pin +// +// ppSamples - array of samples +// nSamples - how many +// nSamplesProcessed - How many were processed +// +// On return all samples will have been Release()'d +// + +HRESULT COutputQueue::ReceiveMultiple ( + IMediaSample **ppSamples, + long nSamples, + long *nSamplesProcessed) +{ + CAutoLock lck(this); + // Either call directly or queue up the samples + + if (!IsQueued()) { + + // If we already had a bad return code then just return + + if (S_OK != m_hr) { + + // If we've never received anything since the last Flush() + // and the sticky return code is not S_OK we must be + // flushing + // ((!A || B) is equivalent to A implies B) + ASSERT(!m_bFlushed || m_bFlushing); + + // We're supposed to Release() them anyway! + *nSamplesProcessed = 0; + for (int i = 0; i < nSamples; i++) { + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + ppSamples[i]->Release(); + } + + return m_hr; + } + // + // If we're flushing the sticky return code should be S_FALSE + // + ASSERT(!m_bFlushing); + m_bFlushed = FALSE; + + ASSERT(m_nBatched < m_lBatchSize); + ASSERT(m_nBatched == 0 || m_bBatchExact); + + // Loop processing the samples in batches + + LONG iLost = 0; + long iDone; + for (iDone = 0; + iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); + ) { + +//pragma message (REMIND("Implement threshold scheme")) + ASSERT(m_nBatched < m_lBatchSize); + if (iDone < nSamples) { + m_ppSamples[m_nBatched++] = ppSamples[iDone++]; + } + if (m_nBatched == m_lBatchSize || + nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { + LONG nDone; + DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), + m_nBatched)); + + if (m_hr == S_OK) { + m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + m_nBatched, + &nDone); + } else { + nDone = 0; + } + iLost += m_nBatched - nDone; + for (LONG i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; + } + } + *nSamplesProcessed = iDone - iLost; + if (*nSamplesProcessed < 0) { + *nSamplesProcessed = 0; + } + return m_hr; + } else { + /* We're sending to our thread */ + + if (m_hr != S_OK) { + *nSamplesProcessed = 0; + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + for (int i = 0; i < nSamples; i++) { + ppSamples[i]->Release(); + } + return m_hr; + } + m_bFlushed = FALSE; + for (long i = 0; i < nSamples; i++) { + QueueSample(ppSamples[i]); + } + *nSamplesProcessed = nSamples; + if (!m_bBatchExact || + m_nBatched + m_List->GetCount() >= m_lBatchSize) { + NotifyThread(); + } + return S_OK; + } +} + +// Get ready for new data - cancels sticky m_hr +void COutputQueue::Reset() +{ + if (!IsQueued()) { + m_hr = S_OK; + } else { + CAutoLock lck(this); + QueueSample(RESET_PACKET); + NotifyThread(); + m_evFlushComplete.Wait(); + } +} + +// Remove and Release() all queued and Batched samples +void COutputQueue::FreeSamples() +{ + CAutoLock lck(this); + if (IsQueued()) { + while (TRUE) { + IMediaSample *pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample == NULL) { + break; + } + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } else { + if (pSample == NEW_SEGMENT) { + // Free NEW_SEGMENT packet + NewSegmentPacket *ppacket = + (NewSegmentPacket *) m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket != NULL); + delete ppacket; + } + } + } + } + for (int i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; +} + +// Notify the thread if there is something to do +// +// The critical section MUST be held when this is called +void COutputQueue::NotifyThread() +{ + // Optimize - no need to signal if it's not waiting + ASSERT(IsQueued()); + if (m_lWaiting) { + ReleaseSemaphore(m_hSem, m_lWaiting, NULL); + m_lWaiting = 0; + } +} + +// See if there's any work to do +// Returns +// TRUE if there is nothing on the queue and nothing in the batch +// and all data has been sent +// FALSE otherwise +// +BOOL COutputQueue::IsIdle() +{ + CAutoLock lck(this); + + // We're idle if + // there is no thread (!IsQueued()) OR + // the thread is waiting for more work (m_lWaiting != 0) + // AND + // there's nothing in the current batch (m_nBatched == 0) + + if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { + return FALSE; + } else { + + // If we're idle it shouldn't be possible for there + // to be anything on the work queue + + ASSERT(!IsQueued() || m_List->GetCount() == 0); + return TRUE; + } +} + + +void COutputQueue::SetPopEvent(HANDLE hEvent) +{ + m_hEventPop = hEvent; +} diff --git a/plugins/gs/gsdx9/baseclasses/outputq.h b/plugins/gs/gsdx9/baseclasses/outputq.h new file mode 100644 index 0000000000..d021922a53 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/outputq.h @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// File: OutputQ.h +// +// Desc: DirectShow base classes - defines the COutputQueue class, which +// makes a queue of samples and sends them to an output pin. The +// class will optionally send the samples to the pin directly. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +typedef CGenericList CSampleList; + +class COutputQueue : public CCritSec +{ +public: + // Constructor + COutputQueue(IPin *pInputPin, // Pin to send stuff to + HRESULT *phr, // 'Return code' + BOOL bAuto = TRUE, // Ask pin if blocks + BOOL bQueue = TRUE, // Send through queue (ignored if + // bAuto set) + LONG lBatchSize = 1, // Batch + BOOL bBatchExact = FALSE,// Batch exactly to BatchSize + LONG lListSize = // Likely number in the list + DEFAULTCACHE, + DWORD dwPriority = // Priority of thread to create + THREAD_PRIORITY_NORMAL, + bool bFlushingOpt = false // flushing optimization + ); + ~COutputQueue(); + + // enter flush state - discard all data + void BeginFlush(); // Begin flushing samples + + // re-enable receives (pass this downstream) + void EndFlush(); // Complete flush of samples - downstream + // pin guaranteed not to block at this stage + + void EOS(); // Call this on End of stream + + void SendAnyway(); // Send batched samples anyway (if bBatchExact set) + + void NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + HRESULT Receive(IMediaSample *pSample); + + // do something with these media samples + HRESULT ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed); + + void Reset(); // Reset m_hr ready for more data + + // See if its idle or not + BOOL IsIdle(); + + // give the class an event to fire after everything removed from the queue + void SetPopEvent(HANDLE hEvent); + +protected: + static DWORD WINAPI InitialThreadProc(LPVOID pv); + DWORD ThreadProc(); + BOOL IsQueued() + { + return m_List != NULL; + } + + // The critical section MUST be held when this is called + void QueueSample(IMediaSample *pSample); + + BOOL IsSpecialSample(IMediaSample *pSample) + { + return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); + } + + // Remove and Release() batched and queued samples + void FreeSamples(); + + // Notify the thread there is something to do + void NotifyThread(); + + +protected: + // Queue 'messages' + #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch + #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream + #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr + #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment + + // new segment packet is always followed by one of these + struct NewSegmentPacket { + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + double dRate; + }; + + // Remember input stuff + IPin * const m_pPin; + IMemInputPin * m_pInputPin; + BOOL const m_bBatchExact; + LONG const m_lBatchSize; + + CSampleList * m_List; + HANDLE m_hSem; + CAMEvent m_evFlushComplete; + HANDLE m_hThread; + IMediaSample ** m_ppSamples; + LONG m_nBatched; + + // Wait optimization + LONG m_lWaiting; + // Flush synchronization + BOOL m_bFlushing; + + // flushing optimization. some downstream filters have trouble + // with the queue's flushing optimization. other rely on it + BOOL m_bFlushed; + bool m_bFlushingOpt; + + // Terminate now + BOOL m_bTerminate; + + // Send anyway flag for batching + BOOL m_bSendAnyway; + + // Deferred 'return code' + BOOL volatile m_hr; + + // an event that can be fired after every deliver + HANDLE m_hEventPop; +}; + diff --git a/plugins/gs/gsdx9/baseclasses/pstream.cpp b/plugins/gs/gsdx9/baseclasses/pstream.cpp new file mode 100644 index 0000000000..147c76e394 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/pstream.cpp @@ -0,0 +1,196 @@ +//------------------------------------------------------------------------------ +// File: PStream.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +#ifdef PERF +#include +#endif + + +// +// Constructor +// +CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr) + : mPS_fDirty(FALSE) +{ + mPS_dwFileVersion = GetSoftwareVersion(); +} + + +// +// Destructor +// +CPersistStream::~CPersistStream() { + // Nothing to do +} + +#if 0 +SAMPLE CODE TO COPY - not active at the moment + +// +// NonDelegatingQueryInterface +// +// This object supports IPersist & IPersistStream +STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } + else if (riid == IID_IPersistStream) { + return GetInterface((IPersistStream *) this, ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} +#endif + + +// +// WriteToStream +// +// Writes to the stream (default action is to write nothing) +HRESULT CPersistStream::WriteToStream(IStream *pStream) +{ + // You can override this to do things like + // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + + +HRESULT CPersistStream::ReadFromStream(IStream * pStream) +{ + // You can override this to do things like + // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + +// +// Load +// +// Load all the data from the given stream +STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) +{ + HRESULT hr; + // Load the version number then the data + mPS_dwFileVersion = ReadInt(pStm, hr); + if (FAILED(hr)) { + return hr; + } + + return ReadFromStream(pStm); +} // Load + + + +// +// Save +// +// Save the contents of this Stream. +STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) +{ + + HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); + if (FAILED(hr)) { + return hr; + } + + hr = WriteToStream(pStm); + if (FAILED(hr)) { + return hr; + } + + mPS_fDirty = !fClearDirty; + + return hr; +} // Save + + +// WriteInt +// +// Writes an integer to an IStream as 11 UNICODE characters followed by one space. +// You could use this for shorts or unsigneds or anything (up to 32 bits) +// where the value isn't actually truncated by squeezing it into 32 bits. +// Values such as (unsigned) 0x80000000 would come out as -2147483648 +// but would then load as 0x80000000 through ReadInt. Cast as you please. + +STDAPI WriteInt(IStream *pIStream, int n) +{ + WCHAR Buff[13]; // Allows for trailing null that we don't write + (void)StringCchPrintfW(Buff, NUMELMS(Buff), L"%011d ",n); + return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); +} // WriteInt + + +// ReadInt +// +// Reads an integer from an IStream. +// Read as 4 bytes. You could use this for shorts or unsigneds or anything +// where the value isn't actually truncated by squeezing it into 32 bits +// Striped down subset of what sscanf can do (without dragging in the C runtime) + +STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr) +{ + + int Sign = 1; + unsigned int n = 0; // result wil be n*Sign + WCHAR wch; + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + + if (wch==L'-'){ + Sign = -1; + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + for( ; ; ) { + if (wch>=L'0' && wch<=L'9') { + n = 10*n+(int)(wch-L'0'); + } else if ( wch == L' ' + || wch == L'\t' + || wch == L'\r' + || wch == L'\n' + || wch == L'\0' + ) { + break; + } else { + hr = VFW_E_INVALID_FILE_FORMAT; + return 0; + } + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + if (n==0x80000000 && Sign==-1) { + // This is the negative number that has no positive version! + return (int)n; + } + else return (int)n * Sign; +} // ReadInt + + +// The microsoft C/C++ compile generates level 4 warnings to the effect that +// a particular inline function (from some base class) was not needed. +// This line gets rid of hundreds of such unwanted messages and makes +// -W4 compilation feasible: +#pragma warning(disable: 4514) diff --git a/plugins/gs/gsdx9/baseclasses/pstream.h b/plugins/gs/gsdx9/baseclasses/pstream.h new file mode 100644 index 0000000000..95ec88cdd5 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/pstream.h @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// File: PStream.h +// +// Desc: DirectShow base classes - defines a class for persistent properties +// of filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PSTREAM__ +#define __PSTREAM__ + +// Base class for persistent properties of filters +// (i.e. filter properties in saved graphs) + +// The simplest way to use this is: +// 1. Arrange for your filter to inherit this class +// 2. Implement in your class WriteToStream and ReadFromStream +// These will override the "do nothing" functions here. +// 3. Change your NonDelegatingQueryInterface to handle IPersistStream +// 4. Implement SizeMax to return the number of bytes of data you save. +// If you save UNICODE data, don't forget a char is 2 bytes. +// 5. Whenever your data changes, call SetDirty() +// +// At some point you may decide to alter, or extend the format of your data. +// At that point you will wish that you had a version number in all the old +// saved graphs, so that you can tell, when you read them, whether they +// represent the old or new form. To assist you in this, this class +// writes and reads a version number. +// When it writes, it calls GetSoftwareVersion() to enquire what version +// of the software we have at the moment. (In effect this is a version number +// of the data layout in the file). It writes this as the first thing in the data. +// If you want to change the version, implement (override) GetSoftwareVersion(). +// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, +// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading +// an old version file. +// Normally you should accept files whose version is no newer than the software +// version that's reading them. + + +// CPersistStream +// +// Implements IPersistStream. +// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for +// more implementation information. +class CPersistStream : public IPersistStream { + private: + + // Internal state: + + protected: + DWORD mPS_dwFileVersion; // version number of file (being read) + BOOL mPS_fDirty; + + public: + + // IPersistStream methods + + STDMETHODIMP IsDirty() + {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean + STDMETHODIMP Load(LPSTREAM pStm); + STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); + STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize) + // Allow 24 bytes for version. + { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } + + // implementation + + CPersistStream(IUnknown *punk, HRESULT *phr); + ~CPersistStream(); + + HRESULT SetDirty(BOOL fDirty) + { mPS_fDirty = fDirty; return NOERROR;} + + + // override to reveal IPersist & IPersistStream + // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- IPersist --- + + // You must override this to provide your own class id + STDMETHODIMP GetClassID(CLSID *pClsid) PURE; + + // overrideable if you want + // file version number. Override it if you ever change format + virtual DWORD GetSoftwareVersion(void) { return 0; } + + + //========================================================================= + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + + virtual int SizeMax() {return 0;} + virtual HRESULT WriteToStream(IStream *pStream); + virtual HRESULT ReadFromStream(IStream *pStream); + //========================================================================= + + private: + +}; + + +// --- Useful helpers --- + + +// Writes an int to an IStream as UNICODE. +STDAPI WriteInt(IStream *pIStream, int n); + +// inverse of WriteInt +STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr); + +#endif // __PSTREAM__ diff --git a/plugins/gs/gsdx9/baseclasses/pullpin.cpp b/plugins/gs/gsdx9/baseclasses/pullpin.cpp new file mode 100644 index 0000000000..8a3ae5f3e4 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/pullpin.cpp @@ -0,0 +1,527 @@ +//------------------------------------------------------------------------------ +// File: PullPin.cpp +// +// Desc: DirectShow base classes - implements CPullPin class that pulls data +// from IAsyncReader. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include "pullpin.h" + + + +CPullPin::CPullPin() + : m_pReader(NULL), + m_pAlloc(NULL), + m_State(TM_Exit) +{ +} + +CPullPin::~CPullPin() +{ + Disconnect(); +} + +// returns S_OK if successfully connected to an IAsyncReader interface +// from this object +// Optional allocator should be proposed as a preferred allocator if +// necessary +HRESULT +CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) +{ + CAutoLock lock(&m_AccessLock); + + if (m_pReader) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); + if (FAILED(hr)) { + return(hr); + } + + hr = DecideAllocator(pAlloc, NULL); + if (FAILED(hr)) { + Disconnect(); + return hr; + } + + LONGLONG llTotal, llAvail; + hr = m_pReader->Length(&llTotal, &llAvail); + if (FAILED(hr)) { + Disconnect(); + return hr; + } + + // convert from file position to reference time + m_tDuration = llTotal * UNITS; + m_tStop = m_tDuration; + m_tStart = 0; + + m_bSync = bSync; + + return S_OK; +} + +// disconnect any connection made in Connect +HRESULT +CPullPin::Disconnect() +{ + CAutoLock lock(&m_AccessLock); + + StopThread(); + + if (m_pReader) { + m_pReader->Release(); + m_pReader = NULL; + } + + if (m_pAlloc) { + m_pAlloc->Release(); + m_pAlloc = NULL; + } + + return S_OK; +} + +// agree an allocator using RequestAllocator - optional +// props param specifies your requirements (non-zero fields). +// returns an error code if fail to match requirements. +// optional IMemAllocator interface is offered as a preferred allocator +// but no error occurs if it can't be met. +HRESULT +CPullPin::DecideAllocator( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES * pProps) +{ + ALLOCATOR_PROPERTIES *pRequest; + ALLOCATOR_PROPERTIES Request; + if (pProps == NULL) { + Request.cBuffers = 3; + Request.cbBuffer = 64*1024; + Request.cbAlign = 0; + Request.cbPrefix = 0; + pRequest = &Request; + } else { + pRequest = pProps; + } + HRESULT hr = m_pReader->RequestAllocator( + pAlloc, + pRequest, + &m_pAlloc); + return hr; +} + +// start pulling data +HRESULT +CPullPin::Active(void) +{ + ASSERT(!ThreadExists()); + return StartThread(); +} + +// stop pulling data +HRESULT +CPullPin::Inactive(void) +{ + StopThread(); + + return S_OK; +} + +HRESULT +CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) +{ + CAutoLock lock(&m_AccessLock); + + ThreadMsg AtStart = m_State; + + if (AtStart == TM_Start) { + BeginFlush(); + PauseThread(); + EndFlush(); + } + + m_tStart = tStart; + m_tStop = tStop; + + HRESULT hr = S_OK; + if (AtStart == TM_Start) { + hr = StartThread(); + } + + return hr; +} + +HRESULT +CPullPin::Duration(REFERENCE_TIME* ptDuration) +{ + *ptDuration = m_tDuration; + return S_OK; +} + + +HRESULT +CPullPin::StartThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!m_pAlloc || !m_pReader) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (!ThreadExists()) { + + // commit allocator + hr = m_pAlloc->Commit(); + if (FAILED(hr)) { + return hr; + } + + // start thread + if (!Create()) { + return E_FAIL; + } + } + + m_State = TM_Start; + hr = (HRESULT) CallWorker(m_State); + return hr; +} + +HRESULT +CPullPin::PauseThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return E_UNEXPECTED; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Pause; + hr = CallWorker(TM_Pause); + + m_pReader->EndFlush(); + return hr; +} + +HRESULT +CPullPin::StopThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return S_FALSE; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Exit; + hr = CallWorker(TM_Exit); + + m_pReader->EndFlush(); + + // wait for thread to completely exit + Close(); + + // decommit allocator + if (m_pAlloc) { + m_pAlloc->Decommit(); + } + + return S_OK; +} + + +DWORD +CPullPin::ThreadProc(void) +{ + while(1) { + DWORD cmd = GetRequest(); + switch(cmd) { + case TM_Exit: + Reply(S_OK); + return 0; + + case TM_Pause: + // we are paused already + Reply(S_OK); + break; + + case TM_Start: + Reply(S_OK); + Process(); + break; + } + + // at this point, there should be no outstanding requests on the + // upstream filter. + // We should force begin/endflush to ensure that this is true. + // !!!Note that we may currently be inside a BeginFlush/EndFlush pair + // on another thread, but the premature EndFlush will do no harm now + // that we are idle. + m_pReader->BeginFlush(); + CleanupCancelled(); + m_pReader->EndFlush(); + } +} + +HRESULT +CPullPin::QueueSample( + REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity + ) +{ + IMediaSample* pSample; + + HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + return hr; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + pSample->SetDiscontinuity(bDiscontinuity); + + hr = m_pReader->Request( + pSample, + 0); + if (FAILED(hr)) { + pSample->Release(); + + CleanupCancelled(); + OnError(hr); + } + return hr; +} + +HRESULT +CPullPin::CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop) +{ + IMediaSample* pSample = NULL; // better be sure pSample is set + DWORD_PTR dwUnused; + HRESULT hr = m_pReader->WaitForNext( + INFINITE, + &pSample, + &dwUnused); + if (FAILED(hr)) { + if (pSample) { + pSample->Release(); + } + } else { + hr = DeliverSample(pSample, tStart, tStop); + } + if (FAILED(hr)) { + CleanupCancelled(); + OnError(hr); + } + return hr; + +} + +HRESULT +CPullPin::DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop + ) +{ + // fix up sample if past actual stop (for sector alignment) + REFERENCE_TIME t1, t2; + pSample->GetTime(&t1, &t2); + if (t2 > tStop) { + t2 = tStop; + } + + // adjust times to be relative to (aligned) start time + t1 -= tStart; + t2 -= tStart; + pSample->SetTime(&t1, &t2); + + + HRESULT hr = Receive(pSample); + pSample->Release(); + return hr; +} + +void +CPullPin::Process(void) +{ + // is there anything to do? + if (m_tStop <= m_tStart) { + EndOfStream(); + return; + } + + BOOL bDiscontinuity = TRUE; + + // if there is more than one sample at the allocator, + // then try to queue 2 at once in order to overlap. + // -- get buffer count and required alignment + ALLOCATOR_PROPERTIES Actual; + HRESULT hr = m_pAlloc->GetProperties(&Actual); + + // align the start position downwards + REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; + REFERENCE_TIME tCurrent = tStart; + + REFERENCE_TIME tStop = m_tStop; + if (tStop > m_tDuration) { + tStop = m_tDuration; + } + + // align the stop position - may be past stop, but that + // doesn't matter + REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; + + + DWORD dwRequest; + + if (!m_bSync) { + + // Break out of the loop either if we get to the end or we're asked + // to do something else + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + // queue a first sample + if (Actual.cBuffers > 1) { + + hr = QueueSample(tCurrent, tAlignStop, TRUE); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + } + + + + // loop queueing second and waiting for first.. + while (tCurrent < tAlignStop) { + + hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + + hr = CollectAndDeliver(tStart, tStop); + if (S_OK != hr) { + + // stop if error, or if downstream filter said + // to stop. + return; + } + } + + if (Actual.cBuffers > 1) { + hr = CollectAndDeliver(tStart, tStop); + if (FAILED(hr)) { + return; + } + } + } + } else { + + // sync version of above loop + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + IMediaSample* pSample; + + hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + OnError(hr); + return; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + if (bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + bDiscontinuity = FALSE; + } + + hr = m_pReader->SyncReadAligned(pSample); + + if (FAILED(hr)) { + pSample->Release(); + OnError(hr); + return; + } + + hr = DeliverSample(pSample, tStart, tStop); + if (hr != S_OK) { + if (FAILED(hr)) { + OnError(hr); + } + return; + } + } + } + + EndOfStream(); +} + +// after a flush, cancelled i/o will be waiting for collection +// and release +void +CPullPin::CleanupCancelled(void) +{ + while (1) { + IMediaSample * pSample; + DWORD_PTR dwUnused; + + HRESULT hr = m_pReader->WaitForNext( + 0, // no wait + &pSample, + &dwUnused); + if(pSample) { + pSample->Release(); + } else { + // no more samples + return; + } + } +} diff --git a/plugins/gs/gsdx9/baseclasses/pullpin.h b/plugins/gs/gsdx9/baseclasses/pullpin.h new file mode 100644 index 0000000000..254ffe248a --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/pullpin.h @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// File: PullPin.h +// +// Desc: DirectShow base classes - defines CPullPin class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PULLPIN_H__ +#define __PULLPIN_H__ + +// +// CPullPin +// +// object supporting pulling data from an IAsyncReader interface. +// Given a start/stop position, calls a pure Receive method with each +// IMediaSample received. +// +// This is essentially for use in a MemInputPin when it finds itself +// connected to an IAsyncReader pin instead of a pushing pin. +// + +class CPullPin : public CAMThread +{ + IAsyncReader* m_pReader; + REFERENCE_TIME m_tStart; + REFERENCE_TIME m_tStop; + REFERENCE_TIME m_tDuration; + BOOL m_bSync; + + enum ThreadMsg { + TM_Pause, // stop pulling and wait for next message + TM_Start, // start pulling + TM_Exit, // stop and exit + }; + + ThreadMsg m_State; + + // override pure thread proc from CAMThread + DWORD ThreadProc(void); + + // running pull method (check m_bSync) + void Process(void); + + // clean up any cancelled i/o after a flush + void CleanupCancelled(void); + + // suspend thread from pulling, eg during seek + HRESULT PauseThread(); + + // start thread pulling - create thread if necy + HRESULT StartThread(); + + // stop and close thread + HRESULT StopThread(); + + // called from ProcessAsync to queue and collect requests + HRESULT QueueSample( + REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity); + + HRESULT CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + + HRESULT DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + +protected: + IMemAllocator * m_pAlloc; + +public: + CPullPin(); + virtual ~CPullPin(); + + // returns S_OK if successfully connected to an IAsyncReader interface + // from this object + // Optional allocator should be proposed as a preferred allocator if + // necessary + // bSync is TRUE if we are to use sync reads instead of the + // async methods. + HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); + + // disconnect any connection made in Connect + HRESULT Disconnect(); + + // agree an allocator using RequestAllocator - optional + // props param specifies your requirements (non-zero fields). + // returns an error code if fail to match requirements. + // optional IMemAllocator interface is offered as a preferred allocator + // but no error occurs if it can't be met. + virtual HRESULT DecideAllocator( + IMemAllocator* pAlloc, + ALLOCATOR_PROPERTIES * pProps); + + // set start and stop position. if active, will start immediately at + // the new position. Default is 0 to duration + HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); + + // return the total duration + HRESULT Duration(REFERENCE_TIME* ptDuration); + + // start pulling data + HRESULT Active(void); + + // stop pulling data + HRESULT Inactive(void); + + // helper functions + LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { + // aligning downwards is just truncation + return ll & ~(lAlign-1); + }; + + LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { + // align up: round up to next boundary + return (ll + (lAlign -1)) & ~(lAlign -1); + }; + + // GetReader returns the (addrefed) IAsyncReader interface + // for SyncRead etc + IAsyncReader* GetReader() { + m_pReader->AddRef(); + return m_pReader; + }; + + // -- pure -- + + // override this to handle data arrival + // return value other than S_OK will stop data + virtual HRESULT Receive(IMediaSample*) PURE; + + // override this to handle end-of-stream + virtual HRESULT EndOfStream(void) PURE; + + // called on runtime errors that will have caused pulling + // to stop + // these errors are all returned from the upstream filter, who + // will have already reported any errors to the filtergraph. + virtual void OnError(HRESULT hr) PURE; + + // flush this pin and all downstream + virtual HRESULT BeginFlush() PURE; + virtual HRESULT EndFlush() PURE; + +}; + +#endif //__PULLPIN_H__ diff --git a/plugins/gs/gsdx9/baseclasses/refclock.cpp b/plugins/gs/gsdx9/baseclasses/refclock.cpp new file mode 100644 index 0000000000..d10dedd198 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/refclock.cpp @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------------ +// File: RefClock.cpp +// +// Desc: DirectShow base classes - implements the IReferenceClock interface. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include + + + +// 'this' used in constructor list +#pragma warning(disable:4355) + + +STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + HRESULT hr; + + if (riid == IID_IReferenceClock) + { + hr = GetInterface((IReferenceClock *) this, ppv); + } + else + { + hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + return hr; +} + +CBaseReferenceClock::~CBaseReferenceClock() +{ + + if (m_TimerResolution) timeEndPeriod(m_TimerResolution); + + m_pSchedule->DumpLinkedList(); + + if (m_hThread) + { + m_bAbort = TRUE; + TriggerThread(); + WaitForSingleObject( m_hThread, INFINITE ); + EXECUTE_ASSERT( CloseHandle(m_hThread) ); + m_hThread = 0; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } +} + +// A derived class may supply a hThreadEvent if it has its own thread that will take care +// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() +// to see what such a thread has to do.) +CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed ) +: CUnknown( pName, pUnk ) +, m_rtLastGotTime(0) +, m_TimerResolution(0) +, m_bAbort( FALSE ) +, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) +, m_hThread(0) +{ + + + ASSERT(m_pSchedule); + if (!m_pSchedule) + { + *phr = E_OUTOFMEMORY; + } + else + { + // Set up the highest resolution timer we can manage + TIMECAPS tc; + m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + + timeBeginPeriod(m_TimerResolution); + + /* Initialise our system times - the derived clock should set the right values */ + m_dwPrevSystemTime = timeGetTime(); + m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; + + #ifdef PERF + m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); + #endif + + if ( !pShed ) + { + DWORD ThreadID; + m_hThread = ::CreateThread(NULL, // Security attributes + (DWORD) 0, // Initial stack size + AdviseThreadFunction, // Thread start address + (LPVOID) this, // Thread parameter + (DWORD) 0, // Creation flags + &ThreadID); // Thread identifier + + if (m_hThread) + { + SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); + } + else + { + *phr = E_FAIL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } + } + } +} + +void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) +{ + Lock(); + m_rtLastGotTime = rtMinTime ; + Unlock(); +} + +STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) +{ + HRESULT hr; + if (pTime) + { + REFERENCE_TIME rtNow; + Lock(); + rtNow = GetPrivateTime(); + if (rtNow > m_rtLastGotTime) + { + m_rtLastGotTime = rtNow; + hr = S_OK; + } + else + { + hr = S_FALSE; + } + *pTime = m_rtLastGotTime; + Unlock(); + MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); + } + else hr = E_POINTER; + + return hr; +} + +/* Ask for an async notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + // Check that the event is not already set + ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); + + HRESULT hr; + + const REFERENCE_TIME lRefTime = baseTime + streamTime; + if ( lRefTime <= 0 || lRefTime == MAX_TIME ) + { + hr = E_INVALIDARG; + } + else + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + return hr; +} + + +/* Ask for an asynchronous periodic notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + HRESULT hr; + if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + else hr = E_INVALIDARG; + + return hr; +} + + +STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) +{ + return m_pSchedule->Unadvise(dwAdviseCookie); +} + + +REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + + /* If the clock has wrapped then the current time will be less than + * the last time we were notified so add on the extra milliseconds + * + * The time period is long enough so that the likelihood of + * successive calls spanning the clock cycle is not considered. + */ + + DWORD dwTime = timeGetTime(); + { + m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); + m_dwPrevSystemTime = dwTime; + } + + return m_rtPrivateTime; +} + + +/* Adjust the current time by the input value. This allows an + external time source to work out some of the latency of the clock + system and adjust the "current" time accordingly. The intent is + that the time returned to the user is synchronised to a clock + source and allows drift to be catered for. + + For example: if the clock source detects a drift it can pass a delta + to the current time rather than having to set an explicit time. +*/ + +STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) +{ +#ifdef DEBUG + + // Just break if passed an improper time delta value + LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; + if (llDelta > UNITS * 1000) { + DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); + //DebugBreak(); + } + + // We're going to calculate a "severity" for the time change. Max -1 + // min 8. We'll then use this as the debug logging level for a + // debug log message. + const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs + + DWORD delta = abs(usDelta); // varying delta + // Severity == 8 - ceil(log(abs( micro-secs delta))) + int Severity = 8; + while ( delta > 0 ) + { + delta >>= 3; // div 8 + Severity--; + } + + // Sev == 0 => > 2 second delta! + DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, + TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), + Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), + DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); + + // Don't want the DbgBreak to fire when running stress on debug-builds. + #ifdef BREAK_ON_SEVERE_TIME_DELTA + if (Severity < 0) + DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), + TEXT(__FILE__),__LINE__); + #endif + +#endif + + CAutoLock cObjectLock(this); + m_rtPrivateTime += TimeDelta; + // If time goes forwards, and we have advises, then we need to + // trigger the thread so that it can re-evaluate its wait time. + // Since we don't want the cost of the thread switches if the change + // is really small, only do it if clock goes forward by more than + // 0.5 millisecond. If the time goes backwards, the thread will + // wake up "early" (relativly speaking) and will re-evaluate at + // that time. + if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); + return NOERROR; +} + +// Thread stuff + +DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) +{ + return DWORD(reinterpret_cast(p)->AdviseThread()); +} + +HRESULT CBaseReferenceClock::AdviseThread() +{ + DWORD dwWait = INFINITE; + + // The first thing we do is wait until something interesting happens + // (meaning a first advise or shutdown). This prevents us calling + // GetPrivateTime immediately which is goodness as that is a virtual + // routine and the derived class may not yet be constructed. (This + // thread is created in the base class constructor.) + + while ( !m_bAbort ) + { + // Wait for an interesting event to happen + DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); + WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); + if (m_bAbort) break; + + // There are several reasons why we need to work from the internal + // time, mainly to do with what happens when time goes backwards. + // Mainly, it stop us looping madly if an event is just about to + // expire when the clock goes backward (i.e. GetTime stop for a + // while). + const REFERENCE_TIME rtNow = GetPrivateTime(); + + DbgLog((LOG_TIMING, 3, + TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), + ConvertToMilliseconds(rtNow) )); + + // We must add in a millisecond, since this is the resolution of our + // WaitForSingleObject timer. Failure to do so will cause us to loop + // franticly for (approx) 1 a millisecond. + m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); + LONGLONG llWait = m_rtNextAdvise - rtNow; + + ASSERT( llWait > 0 ); + + llWait = ConvertToMilliseconds(llWait); + // DON'T replace this with a max!! (The type's of these things is VERY important) + dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); + }; + return NOERROR; +} diff --git a/plugins/gs/gsdx9/baseclasses/refclock.h b/plugins/gs/gsdx9/baseclasses/refclock.h new file mode 100644 index 0000000000..a864f72b14 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/refclock.h @@ -0,0 +1,171 @@ +//------------------------------------------------------------------------------ +// File: RefClock.h +// +// Desc: DirectShow base classes - defines the IReferenceClock interface. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __BASEREFCLOCK__ +#define __BASEREFCLOCK__ + +#include "dsschedule.h" + +const UINT RESOLUTION = 1; /* High resolution timer */ +const INT ADVISE_CACHE = 4; /* Default cache size */ +const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ + +inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) +{ + /* This converts an arbitrary value representing a reference time + into a MILLISECONDS value for use in subsequent system calls */ + + return (RT / (UNITS / MILLISECONDS)); +} + +/* This class hierarchy will support an IReferenceClock interface so + that an audio card (or other externally driven clock) can update the + system wide clock that everyone uses. + + The interface will be pretty thin with probably just one update method + This interface has not yet been defined. + */ + +/* This abstract base class implements the IReferenceClock + * interface. Classes that actually provide clock signals (from + * whatever source) have to be derived from this class. + * + * The abstract class provides implementations for: + * CUnknown support + * locking support (CCritSec) + * client advise code (creates a thread) + * + * Question: what can we do about quality? Change the timer + * resolution to lower the system load? Up the priority of the + * timer thread to force more responsive signals? + * + * During class construction we create a worker thread that is destroyed during + * destuction. This thread executes a series of WaitForSingleObject calls, + * waking up when a command is given to the thread or the next wake up point + * is reached. The wakeup points are determined by clients making Advise + * calls. + * + * Each advise call defines a point in time when they wish to be notified. A + * periodic advise is a series of these such events. We maintain a list of + * advise links and calculate when the nearest event notification is due for. + * We then call WaitForSingleObject with a timeout equal to this time. The + * handle we wait on is used by the class to signal that something has changed + * and that we must reschedule the next event. This typically happens when + * someone comes in and asks for an advise link while we are waiting for an + * event to timeout. + * + * While we are modifying the list of advise requests we + * are protected from interference through a critical section. Clients are NOT + * advised through callbacks. One shot clients have an event set, while + * periodic clients have a semaphore released for each event notification. A + * semaphore allows a client to be kept up to date with the number of events + * actually triggered and be assured that they can't miss multiple events being + * set. + * + * Keeping track of advises is taken care of by the CAMSchedule class. + */ + +class CBaseReferenceClock +: public CUnknown, public IReferenceClock, public CCritSec +{ +protected: + virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! +public: + CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 ); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); + + DECLARE_IUNKNOWN + + /* IReferenceClock methods */ + // Derived classes must implement GetPrivateTime(). All our GetTime + // does is call GetPrivateTime and then check so that time does not + // go backwards. A return code of S_FALSE implies that the internal + // clock has gone backwards and GetTime time has halted until internal + // time has caught up. (Don't know if this will be much use to folk, + // but it seems odd not to use the return code for something useful.) + STDMETHODIMP GetTime(REFERENCE_TIME *pTime); + // When this is called, it sets m_rtLastGotTime to the time it returns. + + /* Provide standard mechanisms for scheduling events */ + + /* Ask for an async notification that a time has elapsed */ + STDMETHODIMP AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + DWORD_PTR *pdwAdviseCookie // where your cookie goes + ); + + /* Ask for an asynchronous periodic notification that a time has elapsed */ + STDMETHODIMP AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + DWORD_PTR *pdwAdviseCookie // where your cookie goes + ); + + /* Cancel a request for notification(s) - if the notification was + * a one shot timer then this function doesn't need to be called + * as the advise is automatically cancelled, however it does no + * harm to explicitly cancel a one-shot advise. It is REQUIRED that + * clients call Unadvise to clear a Periodic advise setting. + */ + + STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); + + /* Methods for the benefit of derived classes or outer objects */ + + // GetPrivateTime() is the REAL clock. GetTime is just a cover for + // it. Derived classes will probably override this method but not + // GetTime() itself. + // The important point about GetPrivateTime() is it's allowed to go + // backwards. Our GetTime() will keep returning the LastGotTime + // until GetPrivateTime() catches up. + virtual REFERENCE_TIME GetPrivateTime(); + + /* Provide a method for correcting drift */ + STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); + + CAMSchedule * GetSchedule() const { return m_pSchedule; } + +private: + REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time + DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime + REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime + REFERENCE_TIME m_rtNextAdvise; // Time of next advise + UINT m_TimerResolution; + +#ifdef PERF + int m_idGetSystemTime; +#endif + +// Thread stuff +public: + void TriggerThread() // Wakes thread up. Need to do this if + { // time to next advise needs reevaluating. + EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); + } + + +private: + BOOL m_bAbort; // Flag used for thread shutdown + HANDLE m_hThread; // Thread handle + + HRESULT AdviseThread(); // Method in which the advise thread runs + static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there + +protected: + CAMSchedule * const m_pSchedule; + + void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; +}; + +#endif + diff --git a/plugins/gs/gsdx9/baseclasses/reftime.h b/plugins/gs/gsdx9/baseclasses/reftime.h new file mode 100644 index 0000000000..87c43b9fef --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/reftime.h @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// File: RefTime.h +// +// Desc: DirectShow base classes - defines CRefTime, a class that manages +// reference times. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// CRefTime +// +// Manage reference times. +// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) +// functions providing simple comparison, conversion and arithmetic. +// +// A reference time (at the moment) is a unit of seconds represented in +// 100ns units as is used in the Win32 FILETIME structure. BUT the time +// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it +// will either be stream time or reference time depending upon context +// +// This class provides simple arithmetic operations on reference times +// +// keep non-virtual otherwise the data layout will not be the same as +// REFERENCE_TIME + + +// ----- +// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but +// you will need to do so explicitly +// ----- + + +#ifndef __REFTIME__ +#define __REFTIME__ + + +const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 +const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 +const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 + +/* Unfortunately an inline function here generates a call to __allmul + - even for constants! +*/ +#define MILLISECONDS_TO_100NS_UNITS(lMs) \ + Int32x32To64((lMs), (UNITS / MILLISECONDS)) + +class CRefTime +{ +public: + + // *MUST* be the only data member so that this class is exactly + // equivalent to a REFERENCE_TIME. + // Also, must be *no virtual functions* + + REFERENCE_TIME m_time; + + inline CRefTime() + { + // default to 0 time + m_time = 0; + }; + + inline CRefTime(LONG msecs) + { + m_time = MILLISECONDS_TO_100NS_UNITS(msecs); + }; + + inline CRefTime(REFERENCE_TIME rt) + { + m_time = rt; + }; + + inline operator REFERENCE_TIME() const + { + return m_time; + }; + + inline CRefTime& operator=(const CRefTime& rt) + { + m_time = rt.m_time; + return *this; + }; + + inline CRefTime& operator=(const LONGLONG ll) + { + m_time = ll; + return *this; + }; + + inline CRefTime& operator+=(const CRefTime& rt) + { + return (*this = *this + rt); + }; + + inline CRefTime& operator-=(const CRefTime& rt) + { + return (*this = *this - rt); + }; + + inline LONG Millisecs(void) + { + return (LONG)(m_time / (UNITS / MILLISECONDS)); + }; + + inline LONGLONG GetUnits(void) + { + return m_time; + }; +}; + +const LONGLONG TimeZero = 0; + +#endif /* __REFTIME__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/renbase.cpp b/plugins/gs/gsdx9/baseclasses/renbase.cpp new file mode 100644 index 0000000000..49b20f9bf0 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/renbase.cpp @@ -0,0 +1,2844 @@ +//------------------------------------------------------------------------------ +// File: RenBase.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include // Used for time critical log functions + +#pragma warning(disable:4355) + +// Helper function for clamping time differences +int inline TimeDiff(REFERENCE_TIME rt) +{ + if (rt < - (50 * UNITS)) { + return -(50 * UNITS); + } else + if (rt > 50 * UNITS) { + return 50 * UNITS; + } else return (int)rt; +} + +// Implements the CBaseRenderer class + +CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr) : // General OLE return code + + CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), + m_evComplete(TRUE), + m_bAbort(FALSE), + m_pPosition(NULL), + m_ThreadSignal(TRUE), + m_bStreaming(FALSE), + m_bEOS(FALSE), + m_bEOSDelivered(FALSE), + m_pMediaSample(NULL), + m_dwAdvise(0), + m_pQSink(NULL), + m_pInputPin(NULL), + m_bRepaintStatus(TRUE), + m_SignalTime(0), + m_bInReceive(FALSE), + m_EndOfStreamTimer(0) +{ + Ready(); +#ifdef PERF + m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); + m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); + m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); +#endif +} + + +// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper +// object. The object is created when somebody queries us. These are standard +// control interfaces for seeking and setting start/stop positions and rates. +// We will probably also have made an input pin based on CRendererInputPin +// that has to be deleted, it's created when an enumerator calls our GetPin + +CBaseRenderer::~CBaseRenderer() +{ + ASSERT(m_bStreaming == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + StopStreaming(); + ClearPendingSample(); + + // Delete any IMediaPosition implementation + + if (m_pPosition) { + delete m_pPosition; + m_pPosition = NULL; + } + + // Delete any input pin created + + if (m_pInputPin) { + delete m_pInputPin; + m_pInputPin = NULL; + } + + // Release any Quality sink + + ASSERT(m_pQSink == NULL); +} + + +// This returns the IMediaPosition and IMediaSeeking interfaces + +HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid,void **ppv) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + if (m_pPosition) { + return m_pPosition->NonDelegatingQueryInterface(riid,ppv); + } + + HRESULT hr = NOERROR; + + // Create implementation of this dynamically since sometimes we may + // never try and do a seek. The helper object implements a position + // control interface (IMediaPosition) which in fact simply takes the + // calls normally from the filter graph and passes them upstream + + m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), + CBaseFilter::GetOwner(), + (HRESULT *) &hr, + GetPin(0)); + if (m_pPosition == NULL) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + delete m_pPosition; + m_pPosition = NULL; + return E_NOINTERFACE; + } + return GetMediaPositionInterface(riid,ppv); +} + + +// Overriden to say what interfaces we support and where + +STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid,void **ppv) +{ + // Do we have this interface + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + return GetMediaPositionInterface(riid,ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// This is called whenever we change states, we have a manual reset event that +// is signalled whenever we don't won't the source filter thread to wait in us +// (such as in a stopped state) and likewise is not signalled whenever it can +// wait (during paused and running) this function sets or resets the thread +// event. The event is used to stop source filter threads waiting in Receive + +HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) +{ + if (bCanWait == TRUE) { + m_ThreadSignal.Reset(); + } else { + m_ThreadSignal.Set(); + } + return NOERROR; +} + + +#ifdef DEBUG +// Dump the current renderer state to the debug terminal. The hardest part of +// the renderer is the window where we unlock everything to wait for a clock +// to signal it is time to draw or for the application to cancel everything +// by stopping the filter. If we get things wrong we can leave the thread in +// WaitForRenderTime with no way for it to ever get out and we will deadlock + +void CBaseRenderer::DisplayRendererState() +{ + DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); + + // No way should this be signalled at this point + + BOOL bSignalled = m_ThreadSignal.Check(); + DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); + + // Now output the current renderer state variables + + DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); + + DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); + + DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); + + DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); + + DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); + + DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); + + + // Output the delayed end of stream timer information + + DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); + + DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); + + + // Should never timeout during a flushing state + + BOOL bFlushing = m_pInputPin->IsFlushing(); + DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); + + // Display the time we were told to start at + DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); + + // Have we got a reference clock + if (m_pClock == NULL) return; + + // Get the current time from the wall clock + + CRefTime CurrentTime,StartTime,EndTime; + m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); + CRefTime Offset = CurrentTime - m_tStart; + + // Display the current time from the clock + + DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); + + DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); + + + // Do we have a sample ready to render + if (m_pMediaSample == NULL) return; + + m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); + DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), + StartTime.Millisecs(),EndTime.Millisecs())); + + // Calculate how long it is until it is due for rendering + CRefTime Wait = (m_tStart + StartTime) - CurrentTime; + DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); +} +#endif + + +// Wait until the clock sets the timer event or we're otherwise signalled. We +// set an arbitrary timeout for this wait and if it fires then we display the +// current renderer state on the debugger. It will often fire if the filter's +// left paused in an application however it may also fire during stress tests +// if the synchronisation with application seeks and state changes is faulty + +#define RENDER_TIMEOUT 10000 + +HRESULT CBaseRenderer::WaitForRenderTime() +{ + HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; + DWORD Result = WAIT_TIMEOUT; + + // Wait for either the time to arrive or for us to be stopped + + OnWaitStart(); + while (Result == WAIT_TIMEOUT) { + Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); + +#ifdef DEBUG + if (Result == WAIT_TIMEOUT) DisplayRendererState(); +#endif + + } + OnWaitEnd(); + + // We may have been awoken without the timer firing + + if (Result == WAIT_OBJECT_0) { + return VFW_E_STATE_CHANGED; + } + + SignalTimerFired(); + return NOERROR; +} + + +// Poll waiting for Receive to complete. This really matters when +// Receive may set the palette and cause window messages +// The problem is that if we don't really wait for a renderer to +// stop processing we can deadlock waiting for a transform which +// is calling the renderer's Receive() method because the transform's +// Stop method doesn't know to process window messages to unblock +// the renderer's Receive processing +void CBaseRenderer::WaitForReceiveToComplete() +{ + for (;;) { + if (!m_bInReceive) { + break; + } + + MSG msg; + // Receive all interthread sendmessages + PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); + + Sleep(1); + } + + // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call + // above just cleared the changebit which will cause some messaging + // calls to block (waitMessage, MsgWaitFor...) now. + // Post a dummy message to set the QS_POSTMESSAGE bit again + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + // Send dummy message + PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); + } +} + +// A filter can have four discrete states, namely Stopped, Running, Paused, +// Intermediate. We are in an intermediate state if we are currently trying +// to pause but haven't yet got the first sample (or if we have been flushed +// in paused state and therefore still have to wait for a sample to arrive) + +// This class contains an event called m_evComplete which is signalled when +// the current state is completed and is not signalled when we are waiting to +// complete the last state transition. As mentioned above the only time we +// use this at the moment is when we wait for a media sample in paused state +// If while we are waiting we receive an end of stream notification from the +// source filter then we know no data is imminent so we can reset the event +// This means that when we transition to paused the source filter must call +// end of stream on us or send us an image otherwise we'll hang indefinately + + +// Simple internal way of getting the real state + +FILTER_STATE CBaseRenderer::GetRealState() { + return m_State; +} + + +// The renderer doesn't complete the full transition to paused states until +// it has got one media sample to render. If you ask it for its state while +// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE + +STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) +{ + CheckPointer(State,E_POINTER); + + if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { + *State = m_State; + return VFW_S_STATE_INTERMEDIATE; + } + *State = m_State; + return NOERROR; +} + + +// If we're pausing and we have no samples we don't complete the transition +// to State_Paused and we return S_FALSE. However if the m_bAbort flag has +// been set then all samples are rejected so there is no point waiting for +// one. If we do have a sample then return NOERROR. We will only ever return +// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample +// (calling GetState after either being stopped or Run will NOT return this) + +HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) +{ + // Allow us to be paused when disconnected + + if (m_pInputPin->IsConnected() == FALSE) { + Ready(); + return S_OK; + } + + // Have we run off the end of stream + + if (IsEndOfStream() == TRUE) { + Ready(); + return S_OK; + } + + // Make sure we get fresh data after being stopped + + if (HaveCurrentSample() == TRUE) { + if (OldState != State_Stopped) { + Ready(); + return S_OK; + } + } + NotReady(); + return S_FALSE; +} + + +// When we stop the filter the things we do are:- + +// Decommit the allocator being used in the connection +// Release the source filter if it's waiting in Receive +// Cancel any advise link we set up with the clock +// Any end of stream signalled is now obsolete so reset +// Allow us to be stopped when we are not connected + +STDMETHODIMP CBaseRenderer::Stop() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + + // Make sure there really is a state change + + if (m_State == State_Stopped) { + return NOERROR; + } + + // Is our input pin connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Stopped; + return NOERROR; + } + + CBaseFilter::Stop(); + + // If we are going into a stopped state then we must decommit whatever + // allocator we are using it so that any source filter waiting in the + // GetBuffer can be released and unlock themselves for a state change + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Decommit(); + } + + // Cancel any scheduled rendering + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(FALSE); + ResetEndOfStream(); + CancelNotification(); + + // There should be no outstanding clock advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + + Ready(); + WaitForReceiveToComplete(); + m_bAbort = FALSE; + + return NOERROR; +} + + +// When we pause the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Cancel any clock advise link (we may be running) +// Possibly complete the state change if we have data +// Allow us to be paused when we are not connected + +STDMETHODIMP CBaseRenderer::Pause() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // Make sure there really is a state change + + if (m_State == State_Paused) { + return CompleteStateChange(State_Paused); + } + + // Has our input pin been connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Paused; + return CompleteStateChange(State_Paused); + } + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Pause(); + if (FAILED(hr)) { + NOTE("Pause failed"); + return hr; + } + + // Enable EC_REPAINT events again + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(TRUE); + CancelNotification(); + ResetEndOfStreamTimer(); + + // If we are going into a paused state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return CompleteStateChange(OldState); +} + + +// When we run the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Signal the render event just to get us going +// Start the base class by calling StartStreaming +// Allow us to be run when we are not connected +// Signal EC_COMPLETE if we are not connected + +STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + + // Make sure there really is a state change + + if (m_State == State_Running) { + return NOERROR; + } + + // Send EC_COMPLETE if we're not connected + + if (m_pInputPin->IsConnected() == FALSE) { + NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); + m_State = State_Running; + return NOERROR; + } + + Ready(); + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Run(StartTime); + if (FAILED(hr)) { + NOTE("Run failed"); + return hr; + } + + // Allow the source thread to wait + ASSERT(m_pInputPin->IsFlushing() == FALSE); + SourceThreadCanWait(TRUE); + SetRepaintStatus(FALSE); + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // If we are going into a running state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return StartStreaming(); +} + + +// Return the number of input pins we support + +int CBaseRenderer::GetPinCount() +{ + return 1; +} + + +// We only support one input pin and it is numbered zero + +CBasePin *CBaseRenderer::GetPin(int n) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + + // Should only ever be called with zero + ASSERT(n == 0); + + if (n != 0) { + return NULL; + } + + // Create the input pin if not already done so + + if (m_pInputPin == NULL) { + + // hr must be initialized to NOERROR because + // CRendererInputPin's constructor only changes + // hr's value if an error occurs. + HRESULT hr = NOERROR; + + m_pInputPin = new CRendererInputPin(this,&hr,L"In"); + if (NULL == m_pInputPin) { + return NULL; + } + + if (FAILED(hr)) { + delete m_pInputPin; + m_pInputPin = NULL; + return NULL; + } + } + return m_pInputPin; +} + + +// If "In" then return the IPin for our input pin, otherwise NULL and error + +STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + ASSERT(*ppPin); + (*ppPin)->AddRef(); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + return NOERROR; +} + + +// Called when the input pin receives an EndOfStream notification. If we have +// not got a sample, then notify EC_COMPLETE now. If we have samples, then set +// m_bEOS and check for this on completing samples. If we're waiting to pause +// then complete the transition to paused state by setting the state event + +HRESULT CBaseRenderer::EndOfStream() +{ + // Ignore these calls if we are stopped + + if (m_State == State_Stopped) { + return NOERROR; + } + + // If we have a sample then wait for it to be rendered + + m_bEOS = TRUE; + if (m_pMediaSample) { + return NOERROR; + } + + // If we are waiting for pause then we are now ready since we cannot now + // carry on waiting for a sample to arrive since we are being told there + // won't be any. This sets an event that the GetState function picks up + + Ready(); + + // Only signal completion now if we are running otherwise queue it until + // we do run in StartStreaming. This is used when we seek because a seek + // causes a pause where early notification of completion is misleading + + if (m_bStreaming) { + SendEndOfStream(); + } + return NOERROR; +} + + +// When we are told to flush we should release the source thread + +HRESULT CBaseRenderer::BeginFlush() +{ + // If paused then report state intermediate until we get some data + + if (m_State == State_Paused) { + NotReady(); + } + + SourceThreadCanWait(FALSE); + CancelNotification(); + ClearPendingSample(); + // Wait for Receive to complete + WaitForReceiveToComplete(); + + return NOERROR; +} + + +// After flushing the source thread can wait in Receive again + +HRESULT CBaseRenderer::EndFlush() +{ + // Reset the current sample media time + if (m_pPosition) m_pPosition->ResetMediaTime(); + + // There should be no outstanding advise + + ASSERT(CancelNotification() == S_FALSE); + SourceThreadCanWait(TRUE); + return NOERROR; +} + + +// We can now send EC_REPAINTs if so required + +HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) +{ + // The caller should always hold the interface lock because + // the function uses CBaseFilter::m_State. + ASSERT(CritCheckIn(&m_InterfaceLock)); + + m_bAbort = FALSE; + + if (State_Running == GetRealState()) { + HRESULT hr = StartStreaming(); + if (FAILED(hr)) { + return hr; + } + + SetRepaintStatus(FALSE); + } else { + SetRepaintStatus(TRUE); + } + + return NOERROR; +} + + +// Called when we go paused or running + +HRESULT CBaseRenderer::Active() +{ + return NOERROR; +} + + +// Called when we go into a stopped state + +HRESULT CBaseRenderer::Inactive() +{ + if (m_pPosition) { + m_pPosition->ResetMediaTime(); + } + // People who derive from this may want to override this behaviour + // to keep hold of the sample in some circumstances + ClearPendingSample(); + + return NOERROR; +} + + +// Tell derived classes about the media type agreed + +HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) +{ + return NOERROR; +} + + +// When we break the input pin connection we should reset the EOS flags. When +// we are asked for either IMediaPosition or IMediaSeeking we will create a +// CPosPassThru object to handles media time pass through. When we're handed +// samples we store (by calling CPosPassThru::RegisterMediaTime) their media +// times so we can then return a real current position of data being rendered + +HRESULT CBaseRenderer::BreakConnect() +{ + // Do we have a quality management sink + + if (m_pQSink) { + m_pQSink->Release(); + m_pQSink = NULL; + } + + // Check we have a valid connection + + if (m_pInputPin->IsConnected() == FALSE) { + return S_FALSE; + } + + // Check we are stopped before disconnecting + if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { + return VFW_E_NOT_STOPPED; + } + + SetRepaintStatus(FALSE); + ResetEndOfStream(); + ClearPendingSample(); + m_bAbort = FALSE; + + if (State_Running == m_State) { + StopStreaming(); + } + + return NOERROR; +} + + +// Retrieves the sample times for this samples (note the sample times are +// passed in by reference not value). We return S_FALSE to say schedule this +// sample according to the times on the sample. We also return S_OK in +// which case the object should simply render the sample data immediately + +HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime) +{ + ASSERT(m_dwAdvise == 0); + ASSERT(pMediaSample); + + // If the stop time for this sample is before or the same as start time, + // then just ignore it (release it) and schedule the next one in line + // Source filters should always fill in the start and end times properly! + + if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { + if (*pEndTime < *pStartTime) { + return VFW_E_START_TIME_AFTER_END; + } + } else { + // no time set in the sample... draw it now? + return S_OK; + } + + // Can't synchronise without a clock so we return S_OK which tells the + // caller that the sample should be rendered immediately without going + // through the overhead of setting a timer advise link with the clock + + if (m_pClock == NULL) { + return S_OK; + } + return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); +} + + +// By default all samples are drawn according to their time stamps so we +// return S_FALSE. Returning S_OK means draw immediately, this is used +// by the derived video renderer class in its quality management. + +HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd) +{ + return S_FALSE; +} + + +// We must always reset the current advise time to zero after a timer fires +// because there are several possible ways which lead us not to do any more +// scheduling such as the pending image being cleared after state changes + +void CBaseRenderer::SignalTimerFired() +{ + m_dwAdvise = 0; +} + + +// Cancel any notification currently scheduled. This is called by the owning +// window object when it is told to stop streaming. If there is no timer link +// outstanding then calling this is benign otherwise we go ahead and cancel +// We must always reset the render event as the quality management code can +// signal immediate rendering by setting the event without setting an advise +// link. If we're subsequently stopped and run the first attempt to setup an +// advise link with the reference clock will find the event still signalled + +HRESULT CBaseRenderer::CancelNotification() +{ + ASSERT(m_dwAdvise == 0 || m_pClock); + DWORD_PTR dwAdvise = m_dwAdvise; + + // Have we a live advise link + + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + SignalTimerFired(); + ASSERT(m_dwAdvise == 0); + } + + // Clear the event and return our status + + m_RenderEvent.Reset(); + return (dwAdvise ? S_OK : S_FALSE); +} + + +// Responsible for setting up one shot advise links with the clock +// Return FALSE if the sample is to be dropped (not drawn at all) +// Return TRUE if the sample is to be drawn and in this case also +// arrange for m_RenderEvent to be set at the appropriate time + +BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + REFERENCE_TIME StartSample, EndSample; + + // Is someone pulling our leg + + if (pMediaSample == NULL) { + return FALSE; + } + + // Get the next sample due up for rendering. If there aren't any ready + // then GetNextSampleTimes returns an error. If there is one to be done + // then it succeeds and yields the sample times. If it is due now then + // it returns S_OK other if it's to be done when due it returns S_FALSE + + HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); + if (FAILED(hr)) { + return FALSE; + } + + // If we don't have a reference clock then we cannot set up the advise + // time so we simply set the event indicating an image to render. This + // will cause us to run flat out without any timing or synchronisation + + if (hr == S_OK) { + EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); + return TRUE; + } + + ASSERT(m_dwAdvise == 0); + ASSERT(m_pClock); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + + // We do have a valid reference clock interface so we can ask it to + // set an event when the image comes due for rendering. We pass in + // the reference time we were told to start at and also the current + // stream time which is the offset from the start reference time + + hr = m_pClock->AdviseTime( + (REFERENCE_TIME) m_tStart, // Start run time + StartSample, // Stream time + (HEVENT)(HANDLE) m_RenderEvent, // Render notification + &m_dwAdvise); // Advise cookie + + if (SUCCEEDED(hr)) { + return TRUE; + } + + // We could not schedule the next sample for rendering despite the fact + // we have a valid sample here. This is a fair indication that either + // the system clock is wrong or the time stamp for the sample is duff + + ASSERT(m_dwAdvise == 0); + return FALSE; +} + + +// This is called when a sample comes due for rendering. We pass the sample +// on to the derived class. After rendering we will initialise the timer for +// the next sample, NOTE signal that the last one fired first, if we don't +// do this it thinks there is still one outstanding that hasn't completed + +HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) +{ + // If the media sample is NULL then we will have been notified by the + // clock that another sample is ready but in the mean time someone has + // stopped us streaming which causes the next sample to be released + + if (pMediaSample == NULL) { + return S_FALSE; + } + + // If we have stopped streaming then don't render any more samples, the + // thread that got in and locked us and then reset this flag does not + // clear the pending sample as we can use it to refresh any output device + + if (m_bStreaming == FALSE) { + return S_FALSE; + } + + // Time how long the rendering takes + + OnRenderStart(pMediaSample); + DoRenderSample(pMediaSample); + OnRenderEnd(pMediaSample); + + return NOERROR; +} + + +// Checks if there is a sample waiting at the renderer + +BOOL CBaseRenderer::HaveCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + return (m_pMediaSample == NULL ? FALSE : TRUE); +} + + +// Returns the current sample waiting at the video renderer. We AddRef the +// sample before returning so that should it come due for rendering the +// person who called this method will hold the remaining reference count +// that will stop the sample being added back onto the allocator free list + +IMediaSample *CBaseRenderer::GetCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->AddRef(); + } + return m_pMediaSample; +} + + +// Called when the source delivers us a sample. We go through a few checks to +// make sure the sample can be rendered. If we are running (streaming) then we +// have the sample scheduled with the reference clock, if we are not streaming +// then we have received an sample in paused mode so we can complete any state +// transition. On leaving this function everything will be unlocked so an app +// thread may get in and change our state to stopped (for example) in which +// case it will also signal the thread event so that our wait call is stopped + +HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) +{ + CAutoLock cInterfaceLock(&m_InterfaceLock); + m_bInReceive = TRUE; + + // Check our flushing and filter state + + // This function must hold the interface lock because it calls + // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses + // CBasePin::m_bRunTimeError. + HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); + + if (hr != NOERROR) { + m_bInReceive = FALSE; + return E_FAIL; + } + + // Has the type changed on a media sample. We do all rendering + // synchronously on the source thread, which has a side effect + // that only one buffer is ever outstanding. Therefore when we + // have Receive called we can go ahead and change the format + // Since the format change can cause a SendMessage we just don't + // lock + if (m_pInputPin->SampleProps()->pMediaType) { + hr = m_pInputPin->SetMediaType( + (CMediaType *)m_pInputPin->SampleProps()->pMediaType); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return hr; + } + } + + + CAutoLock cSampleLock(&m_RendererLock); + + ASSERT(IsActive() == TRUE); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + ASSERT(m_pInputPin->IsConnected() == TRUE); + ASSERT(m_pMediaSample == NULL); + + // Return an error if we already have a sample waiting for rendering + // source pins must serialise the Receive calls - we also check that + // no data is being sent after the source signalled an end of stream + + if (m_pMediaSample || m_bEOS || m_bAbort) { + Ready(); + m_bInReceive = FALSE; + return E_UNEXPECTED; + } + + // Store the media times from this sample + if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); + + // Schedule the next sample if we are streaming + + if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + m_bInReceive = FALSE; + return VFW_E_SAMPLE_REJECTED; + } + + // Store the sample end time for EC_COMPLETE handling + m_SignalTime = m_pInputPin->SampleProps()->tStop; + + // BEWARE we sometimes keep the sample even after returning the thread to + // the source filter such as when we go into a stopped state (we keep it + // to refresh the device with) so we must AddRef it to keep it safely. If + // we start flushing the source thread is released and any sample waiting + // will be released otherwise GetBuffer may never return (see BeginFlush) + + m_pMediaSample = pMediaSample; + m_pMediaSample->AddRef(); + + if (m_bStreaming == FALSE) { + SetRepaintStatus(TRUE); + } + return NOERROR; +} + + +// Called by the source filter when we have a sample to render. Under normal +// circumstances we set an advise link with the clock, wait for the time to +// arrive and then render the data using the PURE virtual DoRenderSample that +// the derived class will have overriden. After rendering the sample we may +// also signal EOS if it was the last one sent before EndOfStream was called + +HRESULT CBaseRenderer::Receive(IMediaSample *pSample) +{ + ASSERT(pSample); + + // It may return VFW_E_SAMPLE_REJECTED code to say don't bother + + HRESULT hr = PrepareReceive(pSample); + ASSERT(m_bInReceive == SUCCEEDED(hr)); + if (FAILED(hr)) { + if (hr == VFW_E_SAMPLE_REJECTED) { + return NOERROR; + } + return hr; + } + + // We realize the palette in "PrepareRender()" so we have to give away the + // filter lock here. + if (m_State == State_Paused) { + PrepareRender(); + // no need to use InterlockedExchange + m_bInReceive = FALSE; + { + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + if (m_State == State_Stopped) + return NOERROR; + + m_bInReceive = TRUE; + CAutoLock cSampleLock(&m_RendererLock); + OnReceiveFirstSample(pSample); + } + Ready(); + } + // Having set an advise link with the clock we sit and wait. We may be + // awoken by the clock firing or by a state change. The rendering call + // will lock the critical section and check we can still render the data + + hr = WaitForRenderTime(); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return NOERROR; + } + + PrepareRender(); + + // Set this here and poll it until we work out the locking correctly + // It can't be right that the streaming stuff grabs the interface + // lock - after all we want to be able to wait for this stuff + // to complete + m_bInReceive = FALSE; + + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + + // since we gave away the filter wide lock, the sate of the filter could + // have chnaged to Stopped + if (m_State == State_Stopped) + return NOERROR; + + CAutoLock cSampleLock(&m_RendererLock); + + // Deal with this sample + + Render(m_pMediaSample); + ClearPendingSample(); + SendEndOfStream(); + CancelNotification(); + return NOERROR; +} + + +// This is called when we stop or are inactivated to clear the pending sample +// We release the media sample interface so that they can be allocated to the +// source filter again, unless of course we are changing state to inactive in +// which case GetBuffer will return an error. We must also reset the current +// media sample to NULL so that we know we do not currently have an image + +HRESULT CBaseRenderer::ClearPendingSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->Release(); + m_pMediaSample = NULL; + } + return NOERROR; +} + + +// Used to signal end of stream according to the sample end time + +void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser,// User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2) // is also reserved +{ + CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; + NOTE1("EndOfStreamTimer called (%d)",uID); + pRenderer->TimerCallback(); +} + +// Do the timer callback work +void CBaseRenderer::TimerCallback() +{ + // Lock for synchronization (but don't hold this lock when calling + // timeKillEvent) + CAutoLock cRendererLock(&m_RendererLock); + + // See if we should signal end of stream now + + if (m_EndOfStreamTimer) { + m_EndOfStreamTimer = 0; + SendEndOfStream(); + } +} + + +// If we are at the end of the stream signal the filter graph but do not set +// the state flag back to FALSE. Once we drop off the end of the stream we +// leave the flag set (until a subsequent ResetEndOfStream). Each sample we +// get delivered will update m_SignalTime to be the last sample's end time. +// We must wait this long before signalling end of stream to the filtergraph + +#define TIMEOUT_DELIVERYWAIT 50 +#define TIMEOUT_RESOLUTION 10 + +HRESULT CBaseRenderer::SendEndOfStream() +{ + ASSERT(CritCheckIn(&m_RendererLock)); + if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { + return NOERROR; + } + + // If there is no clock then signal immediately + if (m_pClock == NULL) { + return NotifyEndOfStream(); + } + + // How long into the future is the delivery time + + REFERENCE_TIME Signal = m_tStart + m_SignalTime; + REFERENCE_TIME CurrentTime; + m_pClock->GetTime(&CurrentTime); + LONG Delay = LONG((Signal - CurrentTime) / 10000); + + // Dump the timing information to the debugger + + NOTE1("Delay until end of stream delivery %d",Delay); + NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); + NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); + + // Wait for the delivery time to arrive + + if (Delay < TIMEOUT_DELIVERYWAIT) { + return NotifyEndOfStream(); + } + + // Signal a timer callback on another worker thread + + m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer + TIMEOUT_RESOLUTION, // Timer resolution + EndOfStreamTimer, // Callback function + DWORD_PTR(this), // Used information + TIME_ONESHOT); // Type of callback + if (m_EndOfStreamTimer == 0) { + return NotifyEndOfStream(); + } + return NOERROR; +} + + +// Signals EC_COMPLETE to the filtergraph manager + +HRESULT CBaseRenderer::NotifyEndOfStream() +{ + CAutoLock cRendererLock(&m_RendererLock); + ASSERT(m_bEOSDelivered == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + + // Has the filter changed state + + if (m_bStreaming == FALSE) { + ASSERT(m_EndOfStreamTimer == 0); + return NOERROR; + } + + // Reset the end of stream timer + m_EndOfStreamTimer = 0; + + // If we've been using the IMediaPosition interface, set it's start + // and end media "times" to the stop position by hand. This ensures + // that we actually get to the end, even if the MPEG guestimate has + // been bad or if the quality management dropped the last few frames + + if (m_pPosition) m_pPosition->EOS(); + m_bEOSDelivered = TRUE; + NOTE("Sending EC_COMPLETE..."); + return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); +} + + +// Reset the end of stream flag, this is typically called when we transfer to +// stopped states since that resets the current position back to the start so +// we will receive more samples or another EndOfStream if there aren't any. We +// keep two separate flags one to say we have run off the end of the stream +// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE +// to the filter graph. We need the latter otherwise we can end up sending an +// EC_COMPLETE every time the source changes state and calls our EndOfStream + +HRESULT CBaseRenderer::ResetEndOfStream() +{ + ResetEndOfStreamTimer(); + CAutoLock cRendererLock(&m_RendererLock); + + m_bEOS = FALSE; + m_bEOSDelivered = FALSE; + m_SignalTime = 0; + + return NOERROR; +} + + +// Kills any outstanding end of stream timer + +void CBaseRenderer::ResetEndOfStreamTimer() +{ + ASSERT(CritCheckOut(&m_RendererLock)); + if (m_EndOfStreamTimer) { + timeKillEvent(m_EndOfStreamTimer); + m_EndOfStreamTimer = 0; + } +} + + +// This is called when we start running so that we can schedule any pending +// image we have with the clock and display any timing information. If we +// don't have any sample but we have queued an EOS flag then we send it. If +// we do have a sample then we wait until that has been rendered before we +// signal the filter graph otherwise we may change state before it's done + +HRESULT CBaseRenderer::StartStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_bStreaming == TRUE) { + return NOERROR; + } + + // Reset the streaming times ready for running + + m_bStreaming = TRUE; + + timeBeginPeriod(1); + OnStartStreaming(); + + // There should be no outstanding advise + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + + // If we have an EOS and no data then deliver it now + + if (m_pMediaSample == NULL) { + return SendEndOfStream(); + } + + // Have the data rendered + + ASSERT(m_pMediaSample); + if (!ScheduleSample(m_pMediaSample)) + m_RenderEvent.Set(); + + return NOERROR; +} + + +// This is called when we stop streaming so that we can set our internal flag +// indicating we are not now to schedule any more samples arriving. The state +// change methods in the filter implementation take care of cancelling any +// clock advise link we have set up and clearing any pending sample we have + +HRESULT CBaseRenderer::StopStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + m_bEOSDelivered = FALSE; + + if (m_bStreaming == TRUE) { + m_bStreaming = FALSE; + OnStopStreaming(); + timeEndPeriod(1); + } + return NOERROR; +} + + +// We have a boolean flag that is reset when we have signalled EC_REPAINT to +// the filter graph. We set this when we receive an image so that should any +// conditions arise again we can send another one. By having a flag we ensure +// we don't flood the filter graph with redundant calls. We do not set the +// event when we receive an EndOfStream call since there is no point in us +// sending further EC_REPAINTs. In particular the AutoShowWindow method and +// the DirectDraw object use this method to control the window repainting + +void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) +{ + CAutoLock cSampleLock(&m_RendererLock); + m_bRepaintStatus = bRepaint; +} + + +// Pass the window handle to the upstream filter + +void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) +{ + IMediaEventSink *pSink; + + // Does the pin support IMediaEventSink + HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); + if (SUCCEEDED(hr)) { + pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); + pSink->Release(); + } + NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); +} + + +// Signal an EC_REPAINT to the filter graph. This can be used to have data +// sent to us. For example when a video window is first displayed it may +// not have an image to display, at which point it signals EC_REPAINT. The +// filtergraph will either pause the graph if stopped or if already paused +// it will call put_CurrentPosition of the current position. Setting the +// current position to itself has the stream flushed and the image resent + +#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); + +void CBaseRenderer::SendRepaint() +{ + CAutoLock cSampleLock(&m_RendererLock); + ASSERT(m_pInputPin); + + // We should not send repaint notifications when... + // - An end of stream has been notified + // - Our input pin is being flushed + // - The input pin is not connected + // - We have aborted a video playback + // - There is a repaint already sent + + if (m_bAbort == FALSE) { + if (m_pInputPin->IsConnected() == TRUE) { + if (m_pInputPin->IsFlushing() == FALSE) { + if (IsEndOfStream() == FALSE) { + if (m_bRepaintStatus == TRUE) { + IPin *pPin = (IPin *) m_pInputPin; + NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); + SetRepaintStatus(FALSE); + RLOG("Sending repaint"); + } + } + } + } + } +} + + +// When a video window detects a display change (WM_DISPLAYCHANGE message) it +// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The +// filtergraph will stop everyone and reconnect our input pin. As we're then +// reconnected we can accept the media type that matches the new display mode +// since we may no longer be able to draw the current image type efficiently + +BOOL CBaseRenderer::OnDisplayChange() +{ + // Ignore if we are not connected yet + + CAutoLock cSampleLock(&m_RendererLock); + if (m_pInputPin->IsConnected() == FALSE) { + return FALSE; + } + + RLOG("Notification of EC_DISPLAY_CHANGE"); + + // Pass our input pin as parameter on the event + + IPin *pPin = (IPin *) m_pInputPin; + m_pInputPin->AddRef(); + NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); + SetAbortSignal(TRUE); + ClearPendingSample(); + m_pInputPin->Release(); + + return TRUE; +} + + +// Called just before we start drawing. +// Store the current time in m_trRenderStart to allow the rendering time to be +// logged. Log the time stamp of the sample and how late it is (neg is early) + +void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trStart, trEnd; + pMediaSample->GetTime(&trStart, &trEnd); + + MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits + + m_pClock->GetTime(&m_trRenderStart); + MSR_INTEGER(0, (int)m_trRenderStart); + REFERENCE_TIME trStream; + trStream = m_trRenderStart-m_tStart; // convert reftime to stream time + MSR_INTEGER(0,(int)trStream); + + const int trLate = (int)(trStream - trStart); + MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec +#endif + +} // OnRenderStart + + +// Called directly after drawing an image. +// calculate the time spent drawing and log it. + +void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trNow; + m_pClock->GetTime(&trNow); + MSR_INTEGER(0,(int)trNow); + int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec + MSR_INTEGER(m_idBaseRenderTime, t); +#endif +} // OnRenderEnd + + + + +// Constructor must be passed the base renderer object + +CRendererInputPin::CRendererInputPin(CBaseRenderer *pRenderer, + HRESULT *phr, + LPCWSTR pPinName) : + CBaseInputPin(NAME("Renderer pin"), + pRenderer, + &pRenderer->m_InterfaceLock, + (HRESULT *) phr, + pPinName) +{ + m_pRenderer = pRenderer; + ASSERT(m_pRenderer); +} + + +// Signals end of data stream on the input pin + +STDMETHODIMP CRendererInputPin::EndOfStream() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + // Make sure we're streaming ok + + HRESULT hr = CheckStreaming(); + if (hr != NOERROR) { + return hr; + } + + // Pass it onto the renderer + + hr = m_pRenderer->EndOfStream(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndOfStream(); + } + return hr; +} + + +// Signals start of flushing on the input pin - we do the final reset end of +// stream with the renderer lock unlocked but with the interface lock locked +// We must do this because we call timeKillEvent, our timer callback method +// has to take the renderer lock to serialise our state. Therefore holding a +// renderer lock when calling timeKillEvent could cause a deadlock condition + +STDMETHODIMP CRendererInputPin::BeginFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + { + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + CBaseInputPin::BeginFlush(); + m_pRenderer->BeginFlush(); + } + return m_pRenderer->ResetEndOfStream(); +} + + +// Signals end of flushing on the input pin + +STDMETHODIMP CRendererInputPin::EndFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + HRESULT hr = m_pRenderer->EndFlush(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndFlush(); + } + return hr; +} + + +// Pass the sample straight through to the renderer object + +STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) +{ + HRESULT hr = m_pRenderer->Receive(pSample); + if (FAILED(hr)) { + + // A deadlock could occur if the caller holds the renderer lock and + // attempts to acquire the interface lock. + ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); + + { + // The interface lock must be held when the filter is calling + // IsStopped() or IsFlushing(). The interface lock must also + // be held because the function uses m_bRunTimeError. + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + + // We do not report errors which occur while the filter is stopping, + // flushing or if the m_bAbort flag is set . Errors are expected to + // occur during these operations and the streaming thread correctly + // handles the errors. + if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { + + // EC_ERRORABORT's first parameter is the error which caused + // the event and its' last parameter is 0. See the Direct + // Show SDK documentation for more information. + m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); + + { + CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); + if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { + m_pRenderer->NotifyEndOfStream(); + } + } + + m_bRunTimeError = TRUE; + } + } + } + + return hr; +} + + +// Called when the input pin is disconnected + +HRESULT CRendererInputPin::BreakConnect() +{ + HRESULT hr = m_pRenderer->BreakConnect(); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::BreakConnect(); +} + + +// Called when the input pin is connected + +HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// Give the pin id of our one and only pin + +STDMETHODIMP CRendererInputPin::QueryId(LPWSTR *Id) +{ + CheckPointer(Id,E_POINTER); + + const size_t len = 4; + *Id = (LPWSTR)CoTaskMemAlloc(len * sizeof(WCHAR)); + if (*Id == NULL) { + return E_OUTOFMEMORY; + } + (void)StringCchCopyW(*Id, len, L"In"); + return NOERROR; +} + + +// Will the filter accept this media type + +HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) +{ + return m_pRenderer->CheckMediaType(pmt); +} + + +// Called when we go paused or running + +HRESULT CRendererInputPin::Active() +{ + return m_pRenderer->Active(); +} + + +// Called when we go into a stopped state + +HRESULT CRendererInputPin::Inactive() +{ + // The caller must hold the interface lock because + // this function uses m_bRunTimeError. + ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); + + m_bRunTimeError = FALSE; + + return m_pRenderer->Inactive(); +} + + +// Tell derived classes about the media type agreed + +HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = CBaseInputPin::SetMediaType(pmt); + if (FAILED(hr)) { + return hr; + } + return m_pRenderer->SetMediaType(pmt); +} + + +// We do not keep an event object to use when setting up a timer link with +// the clock but are given a pointer to one by the owning object through the +// SetNotificationObject method - this must be initialised before starting +// We can override the default quality management process to have it always +// draw late frames, this is currently done by having the following registry +// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) + +const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); +const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); + +CBaseVideoRenderer::CBaseVideoRenderer( + REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr) : // General OLE return code + + CBaseRenderer(RenderClass,pName,pUnk,phr), + m_cFramesDropped(0), + m_cFramesDrawn(0), + m_bSupplierHandlingQuality(FALSE) +{ + ResetStreamingTimes(); + +#ifdef PERF + m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); + m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); + m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); + m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); + m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); + m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); + m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); + m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); + // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); + m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); + m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); + //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); + + m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); + m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); + m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); + m_idDuration = MSR_REGISTER(TEXT("Duration")); + m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); + // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); +#endif // PERF +} // Constructor + + +// Destructor is just a placeholder + +CBaseVideoRenderer::~CBaseVideoRenderer() +{ + ASSERT(m_dwAdvise == 0); +} + + +// The timing functions in this class are called by the window object and by +// the renderer's allocator. +// The windows object calls timing functions as it receives media sample +// images for drawing using GDI. +// The allocator calls timing functions when it starts passing DCI/DirectDraw +// surfaces which are not rendered in the same way; The decompressor writes +// directly to the surface with no separate rendering, so those code paths +// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces +// when we have allocated one and only one image we know there cannot be any +// conflict between the two. +// +// We use timeGetTime to return the timing counts we use (since it's relative +// performance we are interested in rather than absolute compared to a clock) +// The window object sets the accuracy of the system clock (normally 1ms) by +// calling timeBeginPeriod/timeEndPeriod when it changes streaming states + + +// Reset all times controlling streaming. +// Set them so that +// 1. Frames will not initially be dropped +// 2. The first frame will definitely be drawn (achieved by saying that there +// has not ben a frame drawn for a long time). + +HRESULT CBaseVideoRenderer::ResetStreamingTimes() +{ + m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago + m_tStreamingStart = timeGetTime(); + m_trRenderAvg = 0; + m_trFrameAvg = -1; // -1000 fps == "unset" + m_trDuration = 0; // 0 - strange value + m_trRenderLast = 0; + m_trWaitAvg = 0; + m_tRenderStart = 0; + m_cFramesDrawn = 0; + m_cFramesDropped = 0; + m_iTotAcc = 0; + m_iSumSqAcc = 0; + m_iSumSqFrameTime = 0; + m_trFrame = 0; // hygiene - not really needed + m_trLate = 0; // hygiene - not really needed + m_iSumFrameTime = 0; + m_nNormal = 0; + m_trEarliness = 0; + m_trTarget = -300000; // 30mSec early + m_trThrottle = 0; + m_trRememberStampForPerf = 0; + +#ifdef PERF + m_trRememberFrameForPerf = 0; +#endif + + return NOERROR; +} // ResetStreamingTimes + + +// Reset all times controlling streaming. Note that we're now streaming. We +// don't need to set the rendering event to have the source filter released +// as it is done during the Run processing. When we are run we immediately +// release the source filter thread and draw any image waiting (that image +// may already have been drawn once as a poster frame while we were paused) + +HRESULT CBaseVideoRenderer::OnStartStreaming() +{ + ResetStreamingTimes(); + return NOERROR; +} // OnStartStreaming + + +// Called at end of streaming. Fixes times for property page report + +HRESULT CBaseVideoRenderer::OnStopStreaming() +{ + m_tStreamingStart = timeGetTime()-m_tStreamingStart; + return NOERROR; +} // OnStopStreaming + + +// Called when we start waiting for a rendering event. +// Used to update times spent waiting and not waiting. + +void CBaseVideoRenderer::OnWaitStart() +{ + MSR_START(m_idWaitReal); +} // OnWaitStart + + +// Called when we are awoken from the wait in the window OR by our allocator +// when it is hanging around until the next sample is due for rendering on a +// DCI/DirectDraw surface. We add the wait time into our rolling average. +// We grab the interface lock so that we're serialised with the application +// thread going through the run code - which in due course ends up calling +// ResetStreaming times - possibly as we run through this section of code + +void CBaseVideoRenderer::OnWaitEnd() +{ +#ifdef PERF + MSR_STOP(m_idWaitReal); + // for a perf build we want to know just exactly how late we REALLY are. + // even if this means that we have to look at the clock again. + + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. +#if 0 + m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! +#else + // We will be discarding overflows like mad here! + // This is wrong really because timeGetTime() can wrap but it's + // only for PERF + REFERENCE_TIME tr = timeGetTime()*10000; + trRealStream = tr + m_llTimeOffset; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + if (m_trRememberStampForPerf==0) { + // This is probably the poster frame at the start, and it is not scheduled + // in the usual way at all. Just count it. The rememberstamp gets set + // in ShouldDrawSampleNow, so this does invalid frame recording until we + // actually start playing. + PreparePerformanceData(0, 0); + } else { + int trLate = (int)(trRealStream - m_trRememberStampForPerf); + int trFrame = (int)(tr - m_trRememberFrameForPerf); + PreparePerformanceData(trLate, trFrame); + } + m_trRememberFrameForPerf = tr; +#endif //PERF +} // OnWaitEnd + + +// Put data on one side that describes the lateness of the current frame. +// We don't yet know whether it will actually be drawn. In direct draw mode, +// this decision is up to the filter upstream, and it could change its mind. +// The rules say that if it did draw it must call Receive(). One way or +// another we eventually get into either OnRenderStart or OnDirectRender and +// these both call RecordFrameLateness to update the statistics. + +void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) +{ + m_trLate = trLate; + m_trFrame = trFrame; +} // PreparePerformanceData + + +// update the statistics: +// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn +// Note that because the properties page reports using these variables, +// 1. We need to be inside a critical section +// 2. They must all be updated together. Updating the sums here and the count +// elsewhere can result in imaginary jitter (i.e. attempts to find square roots +// of negative numbers) in the property page code. + +void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) +{ + // Record how timely we are. + int tLate = trLate/10000; + + // Best estimate of moment of appearing on the screen is average of + // start and end draw times. Here we have only the end time. This may + // tend to show us as spuriously late by up to 1/2 frame rate achieved. + // Decoder probably monitors draw time. We don't bother. + MSR_INTEGER( m_idFrameAccuracy, tLate ); + + // This is a kludge - we can get frames that are very late + // especially (at start-up) and they invalidate the statistics. + // So ignore things that are more than 1 sec off. + if (tLate>1000 || tLate<-1000) { + if (m_cFramesDrawn<=1) { + tLate = 0; + } else if (tLate>0) { + tLate = 1000; + } else { + tLate = -1000; + } + } + // The very first frame often has a invalid time, so don't + // count it into the statistics. (???) + if (m_cFramesDrawn>1) { + m_iTotAcc += tLate; + m_iSumSqAcc += (tLate*tLate); + } + + // calculate inter-frame time. Doesn't make sense for first frame + // second frame suffers from invalid first frame stamp. + if (m_cFramesDrawn>2) { + int tFrame = trFrame/10000; // convert to mSec else it overflows + + // This is a kludge. It can overflow anyway (a pause can cause + // a very long inter-frame time) and it overflows at 2**31/10**7 + // or about 215 seconds i.e. 3min 35sec + if (tFrame>1000||tFrame<0) tFrame = 1000; + m_iSumSqFrameTime += tFrame*tFrame; + ASSERT(m_iSumSqFrameTime>=0); + m_iSumFrameTime += tFrame; + } + ++m_cFramesDrawn; + +} // RecordFrameLateness + + +void CBaseVideoRenderer::ThrottleWait() +{ + if (m_trThrottle>0) { + int iThrottle = m_trThrottle/10000; // convert to mSec + MSR_INTEGER( m_idThrottle, iThrottle); + DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); + Sleep(iThrottle); + } else { + Sleep(0); + } +} // ThrottleWait + + +// Whenever a frame is rendered it goes though either OnRenderStart +// or OnDirectRender. Data that are generated during ShouldDrawSample +// are added to the statistics by calling RecordFrameLateness from both +// these two places. + +// Called in place of OnRenderStart..OnRenderEnd +// When a DirectDraw image is drawn +void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) +{ + m_trRenderAvg = 0; + m_trRenderLast = 5000000; // If we mode switch, we do NOT want this + // to inhibit the new average getting going! + // so we set it to half a second + // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + RecordFrameLateness(m_trLate, m_trFrame); + ThrottleWait(); +} // OnDirectRender + + +// Called just before we start drawing. All we do is to get the current clock +// time (from the system) and return. We have to store the start render time +// in a member variable because it isn't used until we complete the drawing +// The rest is just performance logging. + +void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ + RecordFrameLateness(m_trLate, m_trFrame); + m_tRenderStart = timeGetTime(); +} // OnRenderStart + + +// Called directly after drawing an image. We calculate the time spent in the +// drawing code and if this doesn't appear to have any odd looking spikes in +// it then we add it to the current average draw time. Measurement spikes may +// occur if the drawing thread is interrupted and switched to somewhere else. + +void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ + // The renderer time can vary erratically if we are interrupted so we do + // some smoothing to help get more sensible figures out but even that is + // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 + + int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS + if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { + // DO_MOVING_AVG(m_trRenderAvg, tr); + m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; + } + m_trRenderLast = tr; + ThrottleWait(); +} // OnRenderEnd + + +STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) +{ + + m_pQSink = piqc; + + return NOERROR; +} // SetSink + + +STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) +{ + // NOTE: We are NOT getting any locks here. We could be called + // asynchronously and possibly even on a time critical thread of + // someone else's - so we do the minumum. We only set one state + // variable (an integer) and if that happens to be in the middle + // of another thread reading it they will just get either the new + // or the old value. Locking would achieve no more than this. + + // It might be nice to check that we are being called from m_pGraph, but + // it turns out to be a millisecond or so per throw! + + // This is heuristics, these numbers are aimed at being "what works" + // rather than anything based on some theory. + // We use a hyperbola because it's easy to calculate and it includes + // a panic button asymptote (which we push off just to the left) + // The throttling fits the following table (roughly) + // Proportion Throttle (msec) + // >=1000 0 + // 900 3 + // 800 7 + // 700 11 + // 600 17 + // 500 25 + // 400 35 + // 300 50 + // 200 72 + // 125 100 + // 100 112 + // 50 146 + // 0 200 + + // (some evidence that we could go for a sharper kink - e.g. no throttling + // until below the 750 mark - might give fractionally more frames on a + // P60-ish machine). The easy way to get these coefficients is to use + // Renbase.xls follow the instructions therein using excel solver. + + if (q.Proportion>=1000) { m_trThrottle = 0; } + else { + // The DWORD is to make quite sure I get unsigned arithmetic + // as the constant is between 2**31 and 2**32 + m_trThrottle = -330000 + (388880000/(q.Proportion+167)); + } + return NOERROR; +} // Notify + + +// Send a message to indicate what our supplier should do about quality. +// Theory: +// What a supplier wants to know is "is the frame I'm working on NOW +// going to be late?". +// F1 is the frame at the supplier (as above) +// Tf1 is the due time for F1 +// T1 is the time at that point (NOW!) +// Tr1 is the time that f1 WILL actually be rendered +// L1 is the latency of the graph for frame F1 = Tr1-T1 +// D1 (for delay) is how late F1 will be beyond its due time i.e. +// D1 = (Tr1-Tf1) which is what the supplier really wants to know. +// Unfortunately Tr1 is in the future and is unknown, so is L1 +// +// We could estimate L1 by its value for a previous frame, +// L0 = Tr0-T0 and work off +// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) +// Rearranging terms: +// D1' = (T1-T0) + (Tr0-Tf1) +// adding (Tf0-Tf0) and rearranging again: +// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) +// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) +// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the +// Late field in the quality message that we send. +// The other two terms just state what correction should be applied before +// using the lateness of F0 to predict the lateness of F1. +// (T1-T0) says how much time has actually passed (we have lost this much) +// (Tf1-Tf0) says how much time should have passed if we were keeping pace +// (we have gained this much). +// +// Suppliers should therefore work off: +// Quality.Late + (T1-T0) - (Tf1-Tf0) +// and see if this is "acceptably late" or even early (i.e. negative). +// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from +// the time stamps in the frames. They get Quality.Late from us. +// + +HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, + REFERENCE_TIME trRealStream) +{ + Quality q; + HRESULT hr; + + // If we are the main user of time, then report this as Flood/Dry. + // If our suppliers are, then report it as Famine/Glut. + // + // We need to take action, but avoid hunting. Hunting is caused by + // 1. Taking too much action too soon and overshooting + // 2. Taking too long to react (so averaging can CAUSE hunting). + // + // The reason why we use trLate as well as Wait is to reduce hunting; + // if the wait time is coming down and about to go into the red, we do + // NOT want to rely on some average which is only telling is that it used + // to be OK once. + + q.TimeStamp = (REFERENCE_TIME)trRealStream; + + if (m_trFrameAvg<0) { + q.Type = Famine; // guess + } + // Is the greater part of the time taken bltting or something else + else if (m_trFrameAvg > 2*m_trRenderAvg) { + q.Type = Famine; // mainly other + } else { + q.Type = Flood; // mainly bltting + } + + q.Proportion = 1000; // default + + if (m_trFrameAvg<0) { + // leave it alone - we don't know enough + } + else if ( trLate> 0 ) { + // try to catch up over the next second + // We could be Really, REALLY late, but rendering all the frames + // anyway, just because it's so cheap. + + q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); + if (q.Proportion<500) { + q.Proportion = 500; // don't go daft. (could've been negative!) + } else { + } + + } else if ( m_trWaitAvg>20000 + && trLate<-20000 + ){ + // Go cautiously faster - aim at 2mSec wait. + if (m_trWaitAvg>=m_trFrameAvg) { + // This can happen because of some fudges. + // The waitAvg is how long we originally planned to wait + // The frameAvg is more honest. + // It means that we are spending a LOT of time waiting + q.Proportion = 2000; // double. + } else { + if (m_trFrameAvg+20000 > m_trWaitAvg) { + q.Proportion + = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); + } else { + // We're apparently spending more than the whole frame time waiting. + // Assume that the averages are slightly out of kilter, but that we + // are indeed doing a lot of waiting. (This leg probably never + // happens, but the code avoids any potential divide by zero). + q.Proportion = 2000; + } + } + + if (q.Proportion>2000) { + q.Proportion = 2000; // don't go crazy. + } + } + + // Tell the supplier how late frames are when they get rendered + // That's how late we are now. + // If we are in directdraw mode then the guy upstream can see the drawing + // times and we'll just report on the start time. He can figure out any + // offset to apply. If we are in DIB Section mode then we will apply an + // extra offset which is half of our drawing time. This is usually small + // but can sometimes be the dominant effect. For this we will use the + // average drawing time rather than the last frame. If the last frame took + // a long time to draw and made us late, that's already in the lateness + // figure. We should not add it in again unless we expect the next frame + // to be the same. We don't, we expect the average to be a better shot. + // In direct draw mode the RenderAvg will be zero. + + q.Late = trLate + m_trRenderAvg/2; + + // log what we're doing + MSR_INTEGER(m_idQualityRate, q.Proportion); + MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); + + // A specific sink interface may be set through IPin + + if (m_pQSink==NULL) { + // Get our input pin's peer. We send quality management messages + // to any nominated receiver of these things (set in the IPin + // interface), or else to our source filter. + + IQualityControl *pQC = NULL; + IPin *pOutputPin = m_pInputPin->GetConnected(); + ASSERT(pOutputPin != NULL); + + // And get an AddRef'd quality control interface + + hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); + if (SUCCEEDED(hr)) { + m_pQSink = pQC; + } + } + if (m_pQSink) { + return m_pQSink->Notify(this,q); + } + + return S_FALSE; + +} // SendQuality + + +// We are called with a valid IMediaSample image to decide whether this is to +// be drawn or not. There must be a reference clock in operation. +// Return S_OK if it is to be drawn Now (as soon as possible) +// Return S_FALSE if it is to be drawn when it's due +// Return an error if we want to drop it +// m_nNormal=-1 indicates that we dropped the previous frame and so this +// one should be drawn early. Respect it and update it. +// Use current stream time plus a number of heuristics (detailed below) +// to make the decision + +HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd) +{ + + // Don't call us unless there's a clock interface to synchronise with + ASSERT(m_pClock); + + MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits + MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits + + // We lose a bit of time depending on the monitor type waiting for the next + // screen refresh. On average this might be about 8mSec - so it will be + // later than we think when the picture appears. To compensate a bit + // we bias the media samples by -8mSec i.e. 80000 UNITs. + // We don't ever make a stream time negative (call it paranoia) + if (*ptrStart>=80000) { + *ptrStart -= 80000; + *ptrEnd -= 80000; // bias stop to to retain valid frame duration + } + + // Cache the time stamp now. We will want to compare what we did with what + // we started with (after making the monitor allowance). + m_trRememberStampForPerf = *ptrStart; + + // Get reference times (current and late) + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. + m_pClock->GetTime(&trRealStream); +#ifdef PERF + // While the reference clock is expensive: + // Remember the offset from timeGetTime and use that. + // This overflows all over the place, but when we subtract to get + // differences the overflows all cancel out. + m_llTimeOffset = trRealStream-timeGetTime()*10000; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + // We have to wory about two versions of "lateness". The truth, which we + // try to work out here and the one measured against m_trTarget which + // includes long term feedback. We report statistics against the truth + // but for operational decisions we work to the target. + // We use TimeDiff to make sure we get an integer because we + // may actually be late (or more likely early if there is a big time + // gap) by a very long time. + const int trTrueLate = TimeDiff(trRealStream - *ptrStart); + const int trLate = trTrueLate; + + MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); + + // Send quality control messages upstream, measured against target + HRESULT hr = SendQuality(trLate, trRealStream); + // Note: the filter upstream is allowed to this FAIL meaning "you do it". + m_bSupplierHandlingQuality = (hr==S_OK); + + // Decision time! Do we drop, draw when ready or draw immediately? + + const int trDuration = (int)(*ptrEnd - *ptrStart); + { + // We need to see if the frame rate of the file has just changed. + // This would make comparing our previous frame rate with the current + // frame rate inefficent. Hang on a moment though. I've seen files + // where the frames vary between 33 and 34 mSec so as to average + // 30fps. A minor variation like that won't hurt us. + int t = m_trDuration/32; + if ( trDuration > m_trDuration+t + || trDuration < m_trDuration-t + ) { + // There's a major variation. Reset the average frame rate to + // exactly the current rate to disable decision 9002 for this frame, + // and remember the new rate. + m_trFrameAvg = trDuration; + m_trDuration = trDuration; + } + } + + MSR_INTEGER(m_idEarliness, m_trEarliness/10000); + MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); + MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); + MSR_INTEGER(m_idDuration, trDuration/10000); + +#ifdef PERF + if (S_OK==pMediaSample->IsDiscontinuity()) { + MSR_INTEGER(m_idDecision, 9000); + } +#endif + + // Control the graceful slide back from slow to fast machine mode. + // After a frame drop accept an early frame and set the earliness to here + // If this frame is already later than the earliness then slide it to here + // otherwise do the standard slide (reduce by about 12% per frame). + // Note: earliness is normally NEGATIVE + BOOL bJustDroppedFrame + = ( m_bSupplierHandlingQuality + // Can't use the pin sample properties because we might + // not be in Receive when we call this + && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one + ) + || (m_nNormal==-1); // we just dropped one + + + // Set m_trEarliness (slide back from slow to fast machine mode) + if (trLate>0) { + m_trEarliness = 0; // we are no longer in fast machine mode at all! + } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { + m_trEarliness = trLate; // Things have slipped of their own accord + } else { + m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide + } + + // prepare the new wait average - but don't pollute the old one until + // we have finished with it. + int trWaitAvg; + { + // We never mix in a negative wait. This causes us to believe in fast machines + // slightly more. + int trL = trLate<0 ? -trLate : 0; + trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + } + + + int trFrame; + { + REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! + if (tr>10000000) { + tr = 10000000; // 1 second - arbitrarily. + } + trFrame = int(tr); + } + + // We will DRAW this frame IF... + if ( + // ...the time we are spending drawing is a small fraction of the total + // observed inter-frame time so that dropping it won't help much. + (3*m_trRenderAvg <= m_trFrameAvg) + + // ...or our supplier is NOT handling things and the next frame would + // be less timely than this one or our supplier CLAIMS to be handling + // things, and is now less than a full FOUR frames late. + || ( m_bSupplierHandlingQuality + ? (trLate <= trDuration*4) + : (trLate+trLate < trDuration) + ) + + // ...or we are on average waiting for over eight milliseconds then + // this may be just a glitch. Draw it and we'll hope to catch up. + || (m_trWaitAvg > 80000) + + // ...or we haven't drawn an image for over a second. We will update + // the display, which stops the video looking hung. + // Do this regardless of how late this media sample is. + || ((trRealStream - m_trLastDraw) > UNITS) + + ) { + HRESULT Result; + + // We are going to play this frame. We may want to play it early. + // We will play it early if we think we are in slow machine mode. + // If we think we are NOT in slow machine mode, we will still play + // it early by m_trEarliness as this controls the graceful slide back. + // and in addition we aim at being m_trTarget late rather than "on time". + + BOOL bPlayASAP = FALSE; + + // we will play it AT ONCE (slow machine mode) if... + + // ...we are playing catch-up + if ( bJustDroppedFrame) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9001); + } + + // ...or if we are running below the true frame rate + // exact comparisons are glitchy, for these measurements, + // so add an extra 5% or so + else if ( (m_trFrameAvg > trDuration + trDuration/16) + + // It's possible to get into a state where we are losing ground, but + // are a very long way ahead. To avoid this or recover from it + // we refuse to play early by more than 10 frames. + && (trLate > - trDuration*10) + ){ + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9002); + } +#if 0 + // ...or if we have been late and are less than one frame early + else if ( (trLate + trDuration > 0) + && (m_trWaitAvg<=20000) + ) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9003); + } +#endif + // We will NOT play it at once if we are grossly early. On very slow frame + // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just + // because we got starved (for instance by the net) and dropped one frame + // some time or other. If we are more than 900mSec early, then wait. + if (trLate<-9000000) { + bPlayASAP = FALSE; + } + + if (bPlayASAP) { + + m_nNormal = 0; + MSR_INTEGER(m_idDecision, 0); + // When we are here, we are in slow-machine mode. trLate may well + // oscillate between negative and positive when the supplier is + // dropping frames to keep sync. We should not let that mislead + // us into thinking that we have as much as zero spare time! + // We just update with a zero wait. + m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + + // Assume that we draw it immediately. Update inter-frame stats + m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; +#ifndef PERF + // If this is NOT a perf build, then report what we know so far + // without looking at the clock any more. This assumes that we + // actually wait for exactly the time we hope to. It also reports + // how close we get to the manipulated time stamps that we now have + // rather than the ones we originally started with. It will + // therefore be a little optimistic. However it's fast. + PreparePerformanceData(trTrueLate, trFrame); +#endif + m_trLastDraw = trRealStream; + if (m_trEarliness > trLate) { + m_trEarliness = trLate; // if we are actually early, this is neg + } + Result = S_OK; // Draw it now + + } else { + ++m_nNormal; + // Set the average frame rate to EXACTLY the ideal rate. + // If we are exiting slow-machine mode then we will have caught up + // and be running ahead, so as we slide back to exact timing we will + // have a longer than usual gap at this point. If we record this + // real gap then we'll think that we're running slow and go back + // into slow-machine mode and vever get it straight. + m_trFrameAvg = trDuration; + MSR_INTEGER(m_idDecision, 1); + + // Play it early by m_trEarliness and by m_trTarget + + { + int trE = m_trEarliness; + if (trE < -m_trFrameAvg) { + trE = -m_trFrameAvg; + } + *ptrStart += trE; // N.B. earliness is negative + } + + int Delay = -trTrueLate; + Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait + + m_trWaitAvg = trWaitAvg; + + // Predict when it will actually be drawn and update frame stats + + if (Result==S_FALSE) { // We are going to wait + trFrame = TimeDiff(*ptrStart-m_trLastDraw); + m_trLastDraw = *ptrStart; + } else { + // trFrame is already = trRealStream-m_trLastDraw; + m_trLastDraw = trRealStream; + } +#ifndef PERF + int iAccuracy; + if (Delay>0) { + // Report lateness based on when we intend to play it + iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); + } else { + // Report lateness based on playing it *now*. + iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; + } + PreparePerformanceData(iAccuracy, trFrame); +#endif + } + return Result; + } + + // We are going to drop this frame! + // Of course in DirectDraw mode the guy upstream may draw it anyway. + + // This will probably give a large negative wack to the wait avg. + m_trWaitAvg = trWaitAvg; + +#ifdef PERF + // Respect registry setting - debug only! + if (m_bDrawLateFrames) { + return S_OK; // draw it when it's ready + } // even though it's late. +#endif + + // We are going to drop this frame so draw the next one early + // n.b. if the supplier is doing direct draw then he may draw it anyway + // but he's doing something funny to arrive here in that case. + + MSR_INTEGER(m_idDecision, 2); + m_nNormal = -1; + return E_FAIL; // drop it + +} // ShouldDrawSampleNow + + +// NOTE we're called by both the window thread and the source filter thread +// so we have to be protected by a critical section (locked before called) +// Also, when the window thread gets signalled to render an image, it always +// does so regardless of how late it is. All the degradation is done when we +// are scheduling the next sample to be drawn. Hence when we start an advise +// link to draw a sample, that sample's time will always become the last one +// drawn - unless of course we stop streaming in which case we cancel links + +BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + // We override ShouldDrawSampleNow to add quality management + + BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); + if (bDrawImage == FALSE) { + ++m_cFramesDropped; + return FALSE; + } + + // m_cFramesDrawn must NOT be updated here. It has to be updated + // in RecordFrameLateness at the same time as the other statistics. + return TRUE; +} + + +// Implementation of IQualProp interface needed to support the property page +// This is how the property page gets the data out of the scheduler. We are +// passed into the constructor the owning object in the COM sense, this will +// either be the video renderer or an external IUnknown if we're aggregated. +// We initialise our CUnknown base class with this interface pointer. Then +// all we have to do is to override NonDelegatingQueryInterface to expose +// our IQualProp interface. The AddRef and Release are handled automatically +// by the base class and will be passed on to the appropriate outer object + +STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(int *pcFramesDropped) +{ + CheckPointer(pcFramesDropped,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDropped = m_cFramesDropped; + return NOERROR; +} // get_FramesDroppedInRenderer + + +// Set *pcFramesDrawn to the number of frames drawn since +// streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) +{ + CheckPointer(pcFramesDrawn,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDrawn = m_cFramesDrawn; + return NOERROR; +} // get_FramesDrawn + + +// Set iAvgFrameRate to the frames per hundred secs since +// streaming started. 0 otherwise. + +STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) +{ + CheckPointer(piAvgFrameRate,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + int t; + if (m_bStreaming) { + t = timeGetTime()-m_tStreamingStart; + } else { + t = m_tStreamingStart; + } + + if (t<=0) { + *piAvgFrameRate = 0; + ASSERT(m_cFramesDrawn == 0); + } else { + // i is frames per hundred seconds + *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); + } + return NOERROR; +} // get_AvgFrameRate + + +// Set *piAvg to the average sync offset since streaming started +// in mSec. The sync offset is the time in mSec between when the frame +// should have been drawn and when the frame was actually drawn. + +STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset( int *piAvg) +{ + CheckPointer(piAvg,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piAvg = 0; + return NOERROR; + } + + // Note that we didn't gather the stats on the first frame + // so we use m_cFramesDrawn-1 here + if (m_cFramesDrawn<=1) { + *piAvg = 0; + } else { + *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); + } + return NOERROR; +} // get_AvgSyncOffset + + +// To avoid dragging in the maths library - a cheap +// approximate integer square root. +// We do this by getting a starting guess which is between 1 +// and 2 times too large, followed by THREE iterations of +// Newton Raphson. (That will give accuracy to the nearest mSec +// for the range in question - roughly 0..1000) +// +// It would be faster to use a linear interpolation and ONE NR, but +// who cares. If anyone does - the best linear interpolation is +// to approximates sqrt(x) by +// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) +// 0r y = x*0.41421 + 0.59467 +// This minimises the maximal error in the range in question. +// (error is about +0.008883 and then one NR will give error .0000something +// (Of course these are integers, so you can't just multiply by 0.41421 +// you'd have to do some sort of MulDiv). +// Anyone wanna check my maths? (This is only for a property display!) + +int isqrt(int x) +{ + int s = 1; + // Make s an initial guess for sqrt(x) + if (x > 0x40000000) { + s = 0x8000; // prevent any conceivable closed loop + } else { + while (s*s=0) s = (s*s+x)/(2*s); + if (s>=0) s = (s*s+x)/(2*s); + } + } + return s; +} + +// +// Do estimates for standard deviations for per-frame +// statistics +// +HRESULT CBaseVideoRenderer::GetStdDev( + int nSamples, + int *piResult, + LONGLONG llSumSq, + LONGLONG iTot +) +{ + CheckPointer(piResult,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piResult = 0; + return NOERROR; + } + + // If S is the Sum of the Squares of observations and + // T the Total (i.e. sum) of the observations and there were + // N observations, then an estimate of the standard deviation is + // sqrt( (S - T**2/N) / (N-1) ) + + if (nSamples<=1) { + *piResult = 0; + } else { + LONGLONG x; + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + + // so we use m_cFramesDrawn-1 here + x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); + x = x / (nSamples-1); + ASSERT(x>=0); + *piResult = isqrt((LONG)x); + } + return NOERROR; +} + +// Set *piDev to the standard deviation in mSec of the sync offset +// of each frame since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset( int *piDev) +{ + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + return GetStdDev(m_cFramesDrawn - 1, + piDev, + m_iSumSqAcc, + m_iTotAcc); +} // get_DevSyncOffset + + +// Set *piJitter to the standard deviation in mSec of the inter-frame time +// of frames since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_Jitter( int *piJitter) +{ + // First frames have invalid stamps, so we get no stats for them + // So second frame gives invalid inter-frame time + // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 + return GetStdDev(m_cFramesDrawn - 2, + piJitter, + m_iSumSqFrameTime, + m_iSumFrameTime); +} // get_Jitter + + +// Overidden to return our IQualProp interface + +STDMETHODIMP +CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,VOID **ppv) +{ + // We return IQualProp and delegate everything else + + if (riid == IID_IQualProp) { + return GetInterface( (IQualProp *)this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface( (IQualityControl *)this, ppv); + } + return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); +} + + +// Override JoinFilterGraph so that, just before leaving +// the graph we can send an EC_WINDOW_DESTROYED event + +STDMETHODIMP +CBaseVideoRenderer::JoinFilterGraph(IFilterGraph *pGraph,LPCWSTR pName) +{ + // Since we send EC_ACTIVATE, we also need to ensure + // we send EC_WINDOW_DESTROYED or the resource manager may be + // holding us as a focus object + if (!pGraph && m_pGraph) { + + // We were in a graph and now we're not + // Do this properly in case we are aggregated + IBaseFilter* pFilter; + QueryInterface(IID_IBaseFilter,(void **) &pFilter); + NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); + pFilter->Release(); + } + return CBaseFilter::JoinFilterGraph(pGraph, pName); +} + + +// This removes a large number of level 4 warnings from the +// Microsoft compiler which in this case are not very useful +#pragma warning(disable: 4514) + diff --git a/plugins/gs/gsdx9/baseclasses/renbase.h b/plugins/gs/gsdx9/baseclasses/renbase.h new file mode 100644 index 0000000000..f30a3fad19 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/renbase.h @@ -0,0 +1,478 @@ +//------------------------------------------------------------------------------ +// File: RenBase.h +// +// Desc: DirectShow base classes - defines a generic ActiveX base renderer +// class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __RENBASE__ +#define __RENBASE__ + +// Forward class declarations + +class CBaseRenderer; +class CBaseVideoRenderer; +class CRendererInputPin; + +// This is our input pin class that channels calls to the renderer + +class CRendererInputPin : public CBaseInputPin +{ +protected: + + CBaseRenderer *m_pRenderer; + +public: + + CRendererInputPin(CBaseRenderer *pRenderer, + HRESULT *phr, + LPCWSTR Name); + + // Overriden from the base pin classes + + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + HRESULT SetMediaType(const CMediaType *pmt); + HRESULT CheckMediaType(const CMediaType *pmt); + HRESULT Active(); + HRESULT Inactive(); + + // Add rendering behaviour to interface functions + + STDMETHODIMP QueryId(LPWSTR *Id); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP Receive(IMediaSample *pMediaSample); + + // Helper + IMemAllocator inline *Allocator() const + { + return m_pAllocator; + } +}; + +// Main renderer class that handles synchronisation and state changes + +class CBaseRenderer : public CBaseFilter +{ +protected: + + friend class CRendererInputPin; + + friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser, // User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2); // Is also reserved + + CRendererPosPassThru *m_pPosition; // Media seeking pass by object + CAMEvent m_RenderEvent; // Used to signal timer events + CAMEvent m_ThreadSignal; // Signalled to release worker thread + CAMEvent m_evComplete; // Signalled when state complete + BOOL m_bAbort; // Stop us from rendering more data + BOOL m_bStreaming; // Are we currently streaming + DWORD_PTR m_dwAdvise; // Timer advise cookie + IMediaSample *m_pMediaSample; // Current image media sample + BOOL m_bEOS; // Any more samples in the stream + BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE + CRendererInputPin *m_pInputPin; // Our renderer input pin object + CCritSec m_InterfaceLock; // Critical section for interfaces + CCritSec m_RendererLock; // Controls access to internals + IQualityControl * m_pQSink; // QualityControl sink + BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT + // Avoid some deadlocks by tracking filter during stop + volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive + // And actually processing the sample + REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE + UINT m_EndOfStreamTimer; // Used to signal end of stream + CCritSec m_ObjectCreationLock; // This lock protects the creation and + // of m_pPosition and m_pInputPin. It + // ensures that two threads cannot create + // either object simultaneously. + +public: + + CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr); // General OLE return code + + ~CBaseRenderer(); + + // Overriden to say what interfaces we support and where + + virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv); + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); + + virtual HRESULT SourceThreadCanWait(BOOL bCanWait); + +#ifdef DEBUG + // Debug only dump of the renderer state + void DisplayRendererState(); +#endif + virtual HRESULT WaitForRenderTime(); + virtual HRESULT CompleteStateChange(FILTER_STATE OldState); + + // Return internal information about this filter + + BOOL IsEndOfStream() { return m_bEOS; }; + BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; + BOOL IsStreaming() { return m_bStreaming; }; + void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; + virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; + CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; + + // Permit access to the transition state + + void Ready() { m_evComplete.Set(); }; + void NotReady() { m_evComplete.Reset(); }; + BOOL CheckReady() { return m_evComplete.Check(); }; + + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + FILTER_STATE GetRealState(); + void SendRepaint(); + void SendNotifyWindow(IPin *pPin,HWND hwnd); + BOOL OnDisplayChange(); + void SetRepaintStatus(BOOL bRepaint); + + // Override the filter and pin interface functions + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME StartTime); + STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State); + STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); + + // These are available for a quality management implementation + + virtual void OnRenderStart(IMediaSample *pMediaSample); + virtual void OnRenderEnd(IMediaSample *pMediaSample); + virtual HRESULT OnStartStreaming() { return NOERROR; }; + virtual HRESULT OnStopStreaming() { return NOERROR; }; + virtual void OnWaitStart() { }; + virtual void OnWaitEnd() { }; + virtual void PrepareRender() { }; + +#ifdef PERF + REFERENCE_TIME m_trRenderStart; // Just before we started drawing + // Set in OnRenderStart, Used in OnRenderEnd + int m_idBaseStamp; // MSR_id for frame time stamp + int m_idBaseRenderTime; // MSR_id for true wait time + int m_idBaseAccuracy; // MSR_id for time frame is late (int) +#endif + + // Quality management implementation for scheduling rendering + + virtual BOOL ScheduleSample(IMediaSample *pMediaSample); + virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime); + + virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd); + + // Lots of end of stream complexities + + void TimerCallback(); + void ResetEndOfStreamTimer(); + HRESULT NotifyEndOfStream(); + virtual HRESULT SendEndOfStream(); + virtual HRESULT ResetEndOfStream(); + virtual HRESULT EndOfStream(); + + // Rendering is based around the clock + + void SignalTimerFired(); + virtual HRESULT CancelNotification(); + virtual HRESULT ClearPendingSample(); + + // Called when the filter changes state + + virtual HRESULT Active(); + virtual HRESULT Inactive(); + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + virtual HRESULT BeginFlush(); + virtual HRESULT EndFlush(); + + // Deal with connections and type changes + + virtual HRESULT BreakConnect(); + virtual HRESULT SetMediaType(const CMediaType *pmt); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // These look after the handling of data samples + + virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); + virtual HRESULT Receive(IMediaSample *pMediaSample); + virtual BOOL HaveCurrentSample(); + virtual IMediaSample *GetCurrentSample(); + virtual HRESULT Render(IMediaSample *pMediaSample); + + // Derived classes MUST override these + virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // Helper + void WaitForReceiveToComplete(); +}; + + +// CBaseVideoRenderer is a renderer class (see its ancestor class) and +// it handles scheduling of media samples so that they are drawn at the +// correct time by the reference clock. It implements a degradation +// strategy. Possible degradation modes are: +// Drop frames here (only useful if the drawing takes significant time) +// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. +// Signal supplier to change the frame rate - i.e. ongoing skipping. +// Or any combination of the above. +// In order to determine what's useful to try we need to know what's going +// on. This is done by timing various operations (including the supplier). +// This timing is done by using timeGetTime as it is accurate enough and +// usually cheaper than calling the reference clock. It also tells the +// truth if there is an audio break and the reference clock stops. +// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) +// which the rest of the renderer calls at significant moments. These do +// the timing. + +// the number of frames that the sliding averages are averaged over. +// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD +#define AVGPERIOD 4 +#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) +// Spot the bug in this macro - I can't. but it doesn't work! + +class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class + public IQualProp, // Property page guff + public IQualityControl // Allow throttling +{ +protected: + + // Hungarian: + // tFoo is the time Foo in mSec (beware m_tStart from filter.h) + // trBar is the time Bar by the reference clock + + //****************************************************************** + // State variables to control synchronisation + //****************************************************************** + + // Control of sending Quality messages. We need to know whether + // we are in trouble (e.g. frames being dropped) and where the time + // is being spent. + + // When we drop a frame we play the next one early. + // The frame after that is likely to wait before drawing and counting this + // wait as spare time is unfair, so we count it as a zero wait. + // We therefore need to know whether we are playing frames early or not. + + int m_nNormal; // The number of consecutive frames + // drawn at their normal time (not early) + // -1 means we just dropped a frame. + +#ifdef PERF + BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm + // not keen on people using it!) +#endif + + BOOL m_bSupplierHandlingQuality;// The response to Quality messages says + // our supplier is handling things. + // We will allow things to go extra late + // before dropping frames. We will play + // very early after he has dropped one. + + // Control of scheduling, frame dropping etc. + // We need to know where the time is being spent so as to tell whether + // we should be taking action here, signalling supplier or what. + // The variables are initialised to a mode of NOT dropping frames. + // They will tell the truth after a few frames. + // We typically record a start time for an event, later we get the time + // again and subtract to get the elapsed time, and we average this over + // a few frames. The average is used to tell what mode we are in. + + // Although these are reference times (64 bit) they are all DIFFERENCES + // between times which are small. An int will go up to 214 secs before + // overflow. Avoiding 64 bit multiplications and divisions seems + // worth while. + + + + // Audio-video throttling. If the user has turned up audio quality + // very high (in principle it could be any other stream, not just audio) + // then we can receive cries for help via the graph manager. In this case + // we put in a wait for some time after rendering each frame. + int m_trThrottle; + + // The time taken to render (i.e. BitBlt) frames controls which component + // needs to degrade. If the blt is expensive, the renderer degrades. + // If the blt is cheap it's done anyway and the supplier degrades. + int m_trRenderAvg; // Time frames are taking to blt + int m_trRenderLast; // Time for last frame blt + int m_tRenderStart; // Just before we started drawing (mSec) + // derived from timeGetTime. + + // When frames are dropped we will play the next frame as early as we can. + // If it was a false alarm and the machine is fast we slide gently back to + // normal timing. To do this, we record the offset showing just how early + // we really are. This will normally be negative meaning early or zero. + int m_trEarliness; + + // Target provides slow long-term feedback to try to reduce the + // average sync offset to zero. Whenever a frame is actually rendered + // early we add a msec or two, whenever late we take off a few. + // We add or take off 1/32 of the error time. + // Eventually we should be hovering around zero. For a really bad case + // where we were (say) 300mSec off, it might take 100 odd frames to + // settle down. The rate of change of this is intended to be slower + // than any other mechanism in Quartz, thereby avoiding hunting. + int m_trTarget; + + // The proportion of time spent waiting for the right moment to blt + // controls whether we bother to drop a frame or whether we reckon that + // we're doing well enough that we can stand a one-frame glitch. + int m_trWaitAvg; // Average of last few wait times + // (actually we just average how early + // we were). Negative here means LATE. + + // The average inter-frame time. + // This is used to calculate the proportion of the time used by the + // three operations (supplying us, waiting, rendering) + int m_trFrameAvg; // Average inter-frame time + int m_trDuration; // duration of last frame. + +#ifdef PERF + // Performance logging identifiers + int m_idTimeStamp; // MSR_id for frame time stamp + int m_idEarliness; // MSR_id for earliness fudge + int m_idTarget; // MSR_id for Target fudge + int m_idWaitReal; // MSR_id for true wait time + int m_idWait; // MSR_id for wait time recorded + int m_idFrameAccuracy; // MSR_id for time frame is late (int) + int m_idRenderAvg; // MSR_id for Render time recorded (int) + int m_idSchLateTime; // MSR_id for lateness at scheduler + int m_idQualityRate; // MSR_id for Quality rate requested + int m_idQualityTime; // MSR_id for Quality time requested + int m_idDecision; // MSR_id for decision code + int m_idDuration; // MSR_id for duration of a frame + int m_idThrottle; // MSR_id for audio-video throttling + //int m_idDebug; // MSR_id for trace style debugging + //int m_idSendQuality; // MSR_id for timing the notifications per se +#endif // PERF + REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame + // with no earliness fudges etc. +#ifdef PERF + REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered + + // debug... + int m_idFrameAvg; + int m_idWaitAvg; +#endif + + // PROPERTY PAGE + // This has edit fields that show the user what's happening + // These member variables hold these counts. + + int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER + int m_cFramesDrawn; // Frames since streaming started seen BY THE + // RENDERER (some may be dropped upstream) + + // Next two support average sync offset and standard deviation of sync offset. + LONGLONG m_iTotAcc; // Sum of accuracies in mSec + LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) + + // Next two allow jitter calculation. Jitter is std deviation of frame time. + REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) + LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) + LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec + + // To get performance statistics on frame rate, jitter etc, we need + // to record the lateness and inter-frame time. What we actually need are the + // data above (sum, sum of squares and number of entries for each) but the data + // is generated just ahead of time and only later do we discover whether the + // frame was actually drawn or not. So we have to hang on to the data + int m_trLate; // hold onto frame lateness + int m_trFrame; // hold onto inter-frame time + + int m_tStreamingStart; // if streaming then time streaming started + // else time of last streaming session + // used for property page statistics +#ifdef PERF + LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time +#endif + +public: + + + CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr); // General OLE return code + + ~CBaseVideoRenderer(); + + // IQualityControl methods - Notify allows audio-video throttling + + STDMETHODIMP SetSink( IQualityControl * piqc); + STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); + + // These provide a full video quality management implementation + + void OnRenderStart(IMediaSample *pMediaSample); + void OnRenderEnd(IMediaSample *pMediaSample); + void OnWaitStart(); + void OnWaitEnd(); + HRESULT OnStartStreaming(); + HRESULT OnStopStreaming(); + void ThrottleWait(); + + // Handle the statistics gathering for our quality management + + void PreparePerformanceData(int trLate, int trFrame); + virtual void RecordFrameLateness(int trLate, int trFrame); + virtual void OnDirectRender(IMediaSample *pMediaSample); + virtual HRESULT ResetStreamingTimes(); + BOOL ScheduleSample(IMediaSample *pMediaSample); + HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd); + + virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); + STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName); + + // + // Do estimates for standard deviations for per-frame + // statistics + // + // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / + // (m_cFramesDrawn - 2) + // or 0 if m_cFramesDrawn <= 3 + // + HRESULT GetStdDev( + int nSamples, + int *piResult, + LONGLONG llSumSq, + LONGLONG iTot + ); +public: + + // IQualProp property page support + + STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped); + STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate); + STDMETHODIMP get_Jitter(int *piJitter); + STDMETHODIMP get_AvgSyncOffset(int *piAvg); + STDMETHODIMP get_DevSyncOffset(int *piDev); + + // Implement an IUnknown interface and expose IQualProp + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv); +}; + +#endif // __RENBASE__ + diff --git a/plugins/gs/gsdx9/baseclasses/schedule.cpp b/plugins/gs/gsdx9/baseclasses/schedule.cpp new file mode 100644 index 0000000000..b4d5658b45 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/schedule.cpp @@ -0,0 +1,284 @@ +//------------------------------------------------------------------------------ +// File: Schedule.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +// DbgLog values (all on LOG_TIMING): +// +// 2 for schedulting, firing and shunting of events +// 3 for wait delays and wake-up times of event thread +// 4 for details of whats on the list when the thread awakes + +/* Construct & destructors */ + +CAMSchedule::CAMSchedule( HANDLE ev ) +: CBaseObject(TEXT("CAMSchedule")) +, head(&z, 0), z(0, MAX_TIME) +, m_dwNextCookie(0), m_dwAdviseCount(0) +, m_pAdviseCache(0), m_dwCacheCount(0) +, m_ev( ev ) +{ + head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; +} + +CAMSchedule::~CAMSchedule() +{ + m_Serialize.Lock(); + + // Delete cache + CAdvisePacket * p = m_pAdviseCache; + while (p) + { + CAdvisePacket *const p_next = p->m_next; + delete p; + p = p_next; + } + + ASSERT( m_dwAdviseCount == 0 ); + // Better to be safe than sorry + if ( m_dwAdviseCount > 0 ) + { + DumpLinkedList(); + while ( !head.m_next->IsZ() ) + { + head.DeleteNext(); + --m_dwAdviseCount; + } + } + + // If, in the debug version, we assert twice, it means, not only + // did we have left over advises, but we have also let m_dwAdviseCount + // get out of sync. with the number of advises actually on the list. + ASSERT( m_dwAdviseCount == 0 ); + + m_Serialize.Unlock(); +} + +/* Public methods */ + +DWORD CAMSchedule::GetAdviseCount() +{ + // No need to lock, m_dwAdviseCount is 32bits & declared volatile + return m_dwAdviseCount; +} + +REFERENCE_TIME CAMSchedule::GetNextAdviseTime() +{ + CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing + return head.m_next->m_rtEventTime; +} + +DWORD_PTR CAMSchedule::AddAdvisePacket +( const REFERENCE_TIME & time1 +, const REFERENCE_TIME & time2 +, HANDLE h, BOOL periodic +) +{ + // Since we use MAX_TIME as a sentry, we can't afford to + // schedule a notification at MAX_TIME + ASSERT( time1 < MAX_TIME ); + DWORD_PTR Result; + CAdvisePacket * p; + + m_Serialize.Lock(); + + if (m_pAdviseCache) + { + p = m_pAdviseCache; + m_pAdviseCache = p->m_next; + --m_dwCacheCount; + } + else + { + p = new CAdvisePacket(); + } + if (p) + { + p->m_rtEventTime = time1; p->m_rtPeriod = time2; + p->m_hNotify = h; p->m_bPeriodic = periodic; + Result = AddAdvisePacket( p ); + } + else Result = 0; + + m_Serialize.Unlock(); + + return Result; +} + +HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) +{ + HRESULT hr = S_FALSE; + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + m_Serialize.Lock(); + while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z + { + if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) + { + Delete( p_prev->RemoveNext() ); + --m_dwAdviseCount; + hr = S_OK; + // Having found one cookie that matches, there should be no more + #ifdef DEBUG + while (p_n = p_prev->Next()) + { + ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); + p_prev = p_n; + } + #endif + break; + } + p_prev = p_n; + }; + m_Serialize.Unlock(); + return hr; +} + +REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) +{ + REFERENCE_TIME rtNextTime; + CAdvisePacket * pAdvise; + + DbgLog((LOG_TIMING, 2, + TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); + + CAutoLock lck(&m_Serialize); + + #ifdef DEBUG + if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); + #endif + + // Note - DON'T cache the difference, it might overflow + while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && + !pAdvise->IsZ() ) + { + ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! + + ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); + + if (pAdvise->m_bPeriodic == TRUE) + { + ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); + pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; + ShuntHead(); + } + else + { + ASSERT( pAdvise->m_bPeriodic == FALSE ); + EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); + --m_dwAdviseCount; + Delete( head.RemoveNext() ); + } + + } + + DbgLog((LOG_TIMING, 3, + TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), + DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); + + return rtNextTime; +} + +/* Private methods */ + +DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) +{ + ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); + ASSERT(CritCheckIn(&m_Serialize)); + + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; + } + p_prev->InsertAfter( pPacket ); + ++m_dwAdviseCount; + + DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), + pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + + // If packet added at the head, then clock needs to re-evaluate wait time. + if ( p_prev == &head ) SetEvent( m_ev ); + + return Result; +} + +void CAMSchedule::Delete( CAdvisePacket * pPacket ) +{ + if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; + else + { + m_Serialize.Lock(); + pPacket->m_next = m_pAdviseCache; + m_pAdviseCache = pPacket; + ++m_dwCacheCount; + m_Serialize.Unlock(); + } +} + + +// Takes the head of the list & repositions it +void CAMSchedule::ShuntHead() +{ + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + m_Serialize.Lock(); + CAdvisePacket *const pPacket = head.m_next; + + // This will catch both an empty list, + // and if somehow a MAX_TIME time gets into the list + // (which would also break this method). + ASSERT( pPacket->m_rtEventTime < MAX_TIME ); + + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; + } + // If p_prev == pPacket then we're already in the right place + if (p_prev != pPacket) + { + head.m_next = pPacket->m_next; + (p_prev->m_next = pPacket)->m_next = p_n; + } + #ifdef DEBUG + DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), + pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + #endif + m_Serialize.Unlock(); +} + + +#ifdef DEBUG +void CAMSchedule::DumpLinkedList() +{ + m_Serialize.Lock(); + int i=0; + DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); + for ( CAdvisePacket * p = &head + ; p + ; p = p->m_next , i++ + ) + { + DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), + i, + p->m_dwAdviseCookie, + p->m_rtEventTime / (UNITS / MILLISECONDS) + )); + } + m_Serialize.Unlock(); +} +#endif diff --git a/plugins/gs/gsdx9/baseclasses/schedule.h b/plugins/gs/gsdx9/baseclasses/schedule.h new file mode 100644 index 0000000000..2d01911b31 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/schedule.h @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// File: Schedule.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) + {} + + void InsertAfter( CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/plugins/gs/gsdx9/baseclasses/seekpt.cpp b/plugins/gs/gsdx9/baseclasses/seekpt.cpp new file mode 100644 index 0000000000..bf70e8a5bd --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/seekpt.cpp @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// File: SeekPT.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include "seekpt.h" + +//================================================================== +// CreateInstance +// This goes in the factory template table to create new instances +// If there is already a mapper instance - return that, else make one +// and save it in a static variable so that forever after we can return that. +//================================================================== + +CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) +{ + return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); +} + + +STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + if (riid == IID_ISeekingPassThru) { + return GetInterface((ISeekingPassThru *) this, ppv); + } else { + if (m_pPosPassThru && + (riid == IID_IMediaSeeking || + riid == IID_IMediaPosition)) { + return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + } +} + + +CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr ) + : CUnknown(pName, pUnk, phr), + m_pPosPassThru(NULL) +{ +} + + +CSeekingPassThru::~CSeekingPassThru() +{ + delete m_pPosPassThru; +} + +STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) +{ + HRESULT hr = NOERROR; + if (m_pPosPassThru) { + hr = E_FAIL; + } else { + m_pPosPassThru = + bRendererSeeking ? + new CRendererPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin) : + new CPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin); + if (!m_pPosPassThru) { + hr = E_OUTOFMEMORY; + } else { + if (FAILED(hr)) { + delete m_pPosPassThru; + m_pPosPassThru = NULL; + } + } + } + return hr; +} + diff --git a/plugins/gs/gsdx9/baseclasses/seekpt.h b/plugins/gs/gsdx9/baseclasses/seekpt.h new file mode 100644 index 0000000000..93b7061398 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/seekpt.h @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// File: SeekPT.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __seekpt_h__ +#define __seekpt_h__ + + +class CSeekingPassThru : public ISeekingPassThru, public CUnknown +{ +public: + static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); + ~CSeekingPassThru(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + + STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); + +private: + CPosPassThru *m_pPosPassThru; +}; + +#endif diff --git a/plugins/gs/gsdx9/baseclasses/source.cpp b/plugins/gs/gsdx9/baseclasses/source.cpp new file mode 100644 index 0000000000..cbdc52a810 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/source.cpp @@ -0,0 +1,522 @@ +//------------------------------------------------------------------------------ +// File: Source.cpp +// +// Desc: DirectShow base classes - implements CSource, which is a Quartz +// source filter 'template.' +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Locking Strategy. +// +// Hold the filter critical section (m_pFilter->pStateLock()) to serialise +// access to functions. Note that, in general, this lock may be held +// by a function when the worker thread may want to hold it. Therefore +// if you wish to access shared state from the worker thread you will +// need to add another critical section object. The execption is during +// the threads processing loop, when it is safe to get the filter critical +// section from within FillBuffer(). + +#include + + +// +// CSource::Constructor +// +// Initialise the pin count for the filter. The user will create the pins in +// the derived class. +CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} +#endif + +// +// CSource::Destructor +// +CSource::~CSource() +{ + /* Free our pins and pin array */ + while (m_iPins != 0) { + // deleting the pins causes them to be removed from the array... + delete m_paStreams[m_iPins - 1]; + } + + ASSERT(m_paStreams == NULL); +} + + +// +// Add a new pin +// +HRESULT CSource::AddPin(CSourceStream *pStream) +{ + CAutoLock lock(&m_cStateLock); + + /* Allocate space for this pin and the old ones */ + CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; + if (paStreams == NULL) { + return E_OUTOFMEMORY; + } + if (m_paStreams != NULL) { + CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, + m_iPins * sizeof(m_paStreams[0])); + paStreams[m_iPins] = pStream; + delete [] m_paStreams; + } + m_paStreams = paStreams; + m_paStreams[m_iPins] = pStream; + m_iPins++; + return S_OK; +} + +// +// Remove a pin - pStream is NOT deleted +// +HRESULT CSource::RemovePin(CSourceStream *pStream) +{ + int i; + for (i = 0; i < m_iPins; i++) { + if (m_paStreams[i] == pStream) { + if (m_iPins == 1) { + delete [] m_paStreams; + m_paStreams = NULL; + } else { + /* no need to reallocate */ + while (++i < m_iPins) + m_paStreams[i - 1] = m_paStreams[i]; + } + m_iPins--; + return S_OK; + } + } + return S_FALSE; +} + +// +// FindPin +// +// Set *ppPin to the IPin* that has the id Id. +// or to NULL if the Id cannot be matched. +STDMETHODIMP CSource::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // The -1 undoes the +1 in QueryId and ensures that totally invalid + // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. + int i = WstrToInt(Id) -1; + *ppPin = GetPin(i); + if (*ppPin!=NULL){ + (*ppPin)->AddRef(); + return NOERROR; + } else { + return VFW_E_NOT_FOUND; + } +} + +// +// FindPinNumber +// +// return the number of the pin with this IPin* or -1 if none +int CSource::FindPinNumber(IPin *iPin) { + int i; + for (i=0; in && n>=0 it follows that m_iPins>0 + // which is what used to be checked (i.e. checking that we have a pin) + if ((n >= 0) && (n < m_iPins)) { + + ASSERT(m_paStreams[n]); + return m_paStreams[n]; + } + return NULL; +} + + +// + + +// * +// * --- CSourceStream ---- +// * + +// +// Set Id to point to a CoTaskMemAlloc'd +STDMETHODIMP CSourceStream::QueryId(LPWSTR *Id) { + CheckPointer(Id,E_POINTER); + ValidateReadWritePtr(Id,sizeof(LPWSTR)); + + // We give the pins id's which are 1,2,... + // FindPinNumber returns -1 for an invalid pin + int i = 1+ m_pFilter->FindPinNumber(this); + if (i<1) return VFW_E_NOT_FOUND; + *Id = (LPWSTR)CoTaskMemAlloc(4*sizeof(WCHAR)); + if (*Id==NULL) { + return E_OUTOFMEMORY; + } + IntToWstr(i, *Id, 4); + return NOERROR; +} + + + +// +// CSourceStream::Constructor +// +// increments the number of pins present on the filter +CSourceStream::CSourceStream( + TCHAR *pObjectName, + HRESULT *phr, + CSource *ps, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} + +#ifdef UNICODE +CSourceStream::CSourceStream( + char *pObjectName, + HRESULT *phr, + CSource *ps, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} +#endif +// +// CSourceStream::Destructor +// +// Decrements the number of pins on this filter +CSourceStream::~CSourceStream(void) { + + m_pFilter->RemovePin(this); +} + + +// +// CheckMediaType +// +// Do we support this type? Provides the default support for 1 type. +HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt == *pMediaType) { + return NOERROR; + } + + return E_FAIL; +} + + +// +// GetMediaType/3 +// +// By default we support only one type +// iPosition indexes are 0-n +HRESULT CSourceStream::GetMediaType(int iPosition, CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + if (iPosition<0) { + return E_INVALIDARG; + } + if (iPosition>0) { + return VFW_S_NO_MORE_ITEMS; + } + return GetMediaType(pMediaType); +} + + +// +// Active +// +// The pin is active - start up the worker thread +HRESULT CSourceStream::Active(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + if (m_pFilter->IsActive()) { + return S_FALSE; // succeeded, but did not allocate resources (they already exist...) + } + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + hr = CBaseOutputPin::Active(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!ThreadExists()); + + // start the thread + if (!Create()) { + return E_FAIL; + } + + // Tell thread to initialize. If OnThreadCreate Fails, so does this. + hr = Init(); + if (FAILED(hr)) + return hr; + + return Pause(); +} + + +// +// Inactive +// +// Pin is inactive - shut down the worker thread +// Waits for the worker to exit before returning. +HRESULT CSourceStream::Inactive(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + // !!! need to do this before trying to stop the thread, because + // we may be stuck waiting for our own allocator!!! + + hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + if (FAILED(hr)) { + return hr; + } + + if (ThreadExists()) { + hr = Stop(); + + if (FAILED(hr)) { + return hr; + } + + hr = Exit(); + if (FAILED(hr)) { + return hr; + } + + Close(); // Wait for the thread to exit, then tidy up. + } + + // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + //if (FAILED(hr)) { + // return hr; + //} + + return NOERROR; +} + + +// +// ThreadProc +// +// When this returns the thread exits +// Return codes > 0 indicate an error occured +DWORD CSourceStream::ThreadProc(void) { + + HRESULT hr; // the return code from calls + Command com; + + do { + com = GetRequest(); + if (com != CMD_INIT) { + DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); + Reply((DWORD) E_UNEXPECTED); + } + } while (com != CMD_INIT); + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); + + hr = OnThreadCreate(); // perform set up tasks + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); + OnThreadDestroy(); + Reply(hr); // send failed return code from OnThreadCreate + return 1; + } + + // Initialisation suceeded + Reply(NOERROR); + + Command cmd; + do { + cmd = GetRequest(); + + switch (cmd) { + + case CMD_EXIT: + Reply(NOERROR); + break; + + case CMD_RUN: + DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); + // !!! fall through??? + + case CMD_PAUSE: + Reply(NOERROR); + DoBufferProcessingLoop(); + break; + + case CMD_STOP: + Reply(NOERROR); + break; + + default: + DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); + Reply((DWORD) E_NOTIMPL); + break; + } + } while (cmd != CMD_EXIT); + + hr = OnThreadDestroy(); // tidy up. + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); + return 1; + } + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); + return 0; +} + + +// +// DoBufferProcessingLoop +// +// Grabs a buffer and calls the users processing function. +// Overridable, so that different delivery styles can be catered for. +HRESULT CSourceStream::DoBufferProcessingLoop(void) { + + Command com; + + OnThreadStartPlay(); + + do { + while (!CheckRequest(&com)) { + + IMediaSample *pSample; + + HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); + if (FAILED(hr)) { + Sleep(1); + continue; // go round again. Perhaps the error will go away + // or the allocator is decommited & we will be asked to + // exit soon. + } + + // Virtual function user will override. + hr = FillBuffer(pSample); + + if (hr == S_OK) { + hr = Deliver(pSample); + pSample->Release(); + + // downstream filter returns S_FALSE if it wants us to + // stop or an error if it's reporting an error. + if(hr != S_OK) + { + DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); + return S_OK; + } + + } else if (hr == S_FALSE) { + // derived class wants us to stop pushing data + pSample->Release(); + DeliverEndOfStream(); + return S_OK; + } else { + // derived class encountered an error + pSample->Release(); + DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); + DeliverEndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); + return hr; + } + + // all paths release the sample + } + + // For all commands sent to us there must be a Reply call! + + if (com == CMD_RUN || com == CMD_PAUSE) { + Reply(NOERROR); + } else if (com != CMD_STOP) { + Reply((DWORD) E_UNEXPECTED); + DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); + } + } while (com != CMD_STOP); + + return S_FALSE; +} + diff --git a/plugins/gs/gsdx9/baseclasses/source.h b/plugins/gs/gsdx9/baseclasses/source.h new file mode 100644 index 0000000000..6dff3e7569 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/source.h @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// File: Source.h +// +// Desc: DirectShow base classes - defines classes to simplify creation of +// ActiveX source filters that support continuous generation of data. +// No support is provided for IMediaControl or IMediaPosition. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// Derive your source filter from CSource. +// During construction either: +// Create some CSourceStream objects to manage your pins +// Provide the user with a means of doing so eg, an IPersistFile interface. +// +// CSource provides: +// IBaseFilter interface management +// IMediaFilter interface management, via CBaseFilter +// Pin counting for CBaseFilter +// +// Derive a class from CSourceStream to manage your output pin types +// Implement GetMediaType/1 to return the type you support. If you support multiple +// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. +// Implement Fillbuffer() to put data into one buffer. +// +// CSourceStream provides: +// IPin management via CBaseOutputPin +// Worker thread management + +#ifndef __CSOURCE__ +#define __CSOURCE__ + +class CSourceStream; // The class that will handle each pin + + +// +// CSource +// +// Override construction to provide a means of creating +// CSourceStream derived objects - ie a way of creating pins. +class CSource : public CBaseFilter { +public: + + CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); + CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid); +#ifdef UNICODE + CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); + CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid); +#endif + ~CSource(); + + int GetPinCount(void); + CBasePin *GetPin(int n); + + // -- Utilities -- + + CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section + + HRESULT AddPin(CSourceStream *); + HRESULT RemovePin(CSourceStream *); + + STDMETHODIMP FindPin( + LPCWSTR Id, + IPin ** ppPin + ); + + int FindPinNumber(IPin *iPin); + +protected: + + int m_iPins; // The number of pins on this filter. Updated by CSourceStream + // constructors & destructors. + CSourceStream **m_paStreams; // the pins on this filter. + + CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state + +}; + + +// +// CSourceStream +// +// Use this class to manage a stream of data that comes from a +// pin. +// Uses a worker thread to put data on the pin. +class CSourceStream : public CAMThread, public CBaseOutputPin { +public: + + CSourceStream(TCHAR *pObjectName, + HRESULT *phr, + CSource *pms, + LPCWSTR pName); +#ifdef UNICODE + CSourceStream(CHAR *pObjectName, + HRESULT *phr, + CSource *pms, + LPCWSTR pName); +#endif + virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. + +protected: + + CSource *m_pFilter; // The parent of this stream + + // * + // * Data Source + // * + // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are + // * called from within the ThreadProc. They are used in the creation of + // * the media samples this pin will provide + // * + + // Override this to provide the worker thread a means + // of processing a buffer + virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; + + // Called as the thread is created/destroyed - use to perform + // jobs such as start/stop streaming mode + // If OnThreadCreate returns an error the thread will exit. + virtual HRESULT OnThreadCreate(void) {return NOERROR;}; + virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; + virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; + + // * + // * Worker Thread + // * + + HRESULT Active(void); // Starts up the worker thread + HRESULT Inactive(void); // Exits the worker thread. + +public: + // thread commands + enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; + HRESULT Init(void) { return CallWorker(CMD_INIT); } + HRESULT Exit(void) { return CallWorker(CMD_EXIT); } + HRESULT Run(void) { return CallWorker(CMD_RUN); } + HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } + HRESULT Stop(void) { return CallWorker(CMD_STOP); } + +protected: + Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } + BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } + + // override these if you want to add thread commands + virtual DWORD ThreadProc(void); // the thread function + + virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running + + + // * + // * AM_MEDIA_TYPE support + // * + + // If you support more than one media type then override these 2 functions + virtual HRESULT CheckMediaType(const CMediaType *pMediaType); + virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n + + // If you support only one type then override this fn. + // This will only be called by the default implementations + // of CheckMediaType and GetMediaType(int, CMediaType*) + // You must override this fn. or the above 2! + virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;} + + STDMETHODIMP QueryId( + LPWSTR * Id + ); +}; + +#endif // __CSOURCE__ + diff --git a/plugins/gs/gsdx9/baseclasses/streams.h b/plugins/gs/gsdx9/baseclasses/streams.h new file mode 100644 index 0000000000..736c46756a --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/streams.h @@ -0,0 +1,190 @@ +//------------------------------------------------------------------------------ +// File: Streams.h +// +// Desc: DirectShow base classes - defines overall streams architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __STREAMS__ +#define __STREAMS__ + +#ifdef _MSC_VER +// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable +#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter +#pragma warning(disable:4127) // warning C4127: conditional expression is constant +#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated +#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated +#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed +#pragma warning(disable:4710) // warning C4710: 'function' not inlined + +#if _MSC_VER>=1100 +#define AM_NOVTABLE __declspec(novtable) +#else +#define AM_NOVTABLE +#endif +#endif // MSC_VER + +// Because of differences between Visual C++ and older Microsoft SDKs, +// you may have defined _DEBUG without defining DEBUG. This logic +// ensures that both will be set if Visual C++ sets _DEBUG. +#ifdef _DEBUG +#ifndef DEBUG +#define DEBUG +#endif +#endif + +#include +#include +#include +#include + +// Disable warning message for C4201 - use of nameless struct/union +// Otherwise, strmif.h will generate warnings for Win32 debug builds +#pragma warning( disable : 4201 ) + +#include + +#ifndef NUMELMS + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#endif + +/////////////////////////////////////////////////////////////////////////// +// The following definitions come from the Platform SDK and are required if +// the applicaiton is being compiled with the headers from Visual C++ 6.0. +/////////////////////////////////////////////////////////////////////////// +#ifndef InterlockedExchangePointer + #define InterlockedExchangePointer(Target, Value) \ + (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) + +#ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE +#endif // !GetWindowLongPtr + +#ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE +#endif // !SetWindowLongPtr + +#ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) +#endif +#ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) +#endif +#ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) +#endif +#ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) +#endif +#ifndef GWLP_ID + #define GWLP_ID (-12) +#endif +#ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 +#endif +#ifndef DWLP_DLGPROC + #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#endif +#ifndef DWLP_USER + #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) +#endif +/////////////////////////////////////////////////////////////////////////// +// End Platform SDK definitions +/////////////////////////////////////////////////////////////////////////// + + +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#include // Generated IDL header file for streams interfaces + +#include "reftime.h" // Helper class for REFERENCE_TIME management +#include "wxdebug.h" // Debug support for logging and ASSERTs +#include "amvideo.h" // ActiveMovie video interfaces and definitions +//include amaudio.h explicitly if you need it. it requires the DirectX SDK. +//#include "amaudio.h" // ActiveMovie audio interfaces and definitions +#include "wxutil.h" // General helper classes for threads etc +#include "combase.h" // Base COM classes to support IUnknown +#include "dllsetup.h" // Filter registration support functions +#include "measure.h" // Performance measurement +#include "comlite.h" // Light weight com function prototypes + +#include "cache.h" // Simple cache container class +#include "wxlist.h" // Non MFC generic list class +#include "msgthrd.h" // CMsgThread +#include "mtype.h" // Helper class for managing media types +#include "fourcc.h" // conversions between FOURCCs and GUIDs +#include "control.h" // generated from control.odl +#include "ctlutil.h" // control interface utility classes +#include "evcode.h" // event code definitions +#include "amfilter.h" // Main streams architecture class hierachy +#include "transfrm.h" // Generic transform filter +#include "transip.h" // Generic transform-in-place filter +#include "uuids.h" // declaration of type GUIDs and well-known clsids +#include "source.h" // Generic source filter +#include "outputq.h" // Output pin queueing +#include "errors.h" // HRESULT status and error definitions +#include "renbase.h" // Base class for writing ActiveX renderers +#include "winutil.h" // Helps with filters that manage windows +#include "winctrl.h" // Implements the IVideoWindow interface +#include "videoctl.h" // Specifically video related classes +#include "refclock.h" // Base clock class +#include "sysclock.h" // System clock +#include "pstream.h" // IPersistStream helper class +#include "vtrans.h" // Video Transform Filter base class +#include "amextra.h" +#include "cprop.h" // Base property page class +#include "strmctl.h" // IAMStreamControl support +#include "edevdefs.h" // External device control interface defines +#include "audevcod.h" // audio filter device error event codes + +#include + +#define NO_SHLWAPI_STRFCNS +#include +#include + +#ifndef NUMELMS + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#endif + +#else + #ifdef DEBUG + #pragma message("STREAMS.H included TWICE") + #endif +#endif // __STREAMS__ + diff --git a/plugins/gs/gsdx9/baseclasses/strmctl.cpp b/plugins/gs/gsdx9/baseclasses/strmctl.cpp new file mode 100644 index 0000000000..bc467e64c4 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/strmctl.cpp @@ -0,0 +1,401 @@ +//------------------------------------------------------------------------------ +// File: StrmCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include + +CBaseStreamControl::CBaseStreamControl() +: m_StreamState(STREAM_FLOWING) +, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop +, m_tStartTime(MAX_TIME) +, m_tStopTime(MAX_TIME) +, m_dwStartCookie(0) +, m_dwStopCookie(0) +, m_pRefClock(NULL) +, m_FilterState(State_Stopped) +, m_bIsFlushing(FALSE) +, m_bStopSendExtra(FALSE) +{} + +CBaseStreamControl::~CBaseStreamControl() +{ + // Make sure we release the clock. + SetSyncSource(NULL); + return; +} + + +STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) +{ + CAutoLock lck(&m_CritSec); + m_bStopSendExtra = FALSE; // reset + m_bStopExtraSent = FALSE; + if (ptStop) + { + if (*ptStop == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); + CancelStop(); + // If there's now a command to start in the future, we assume + // they want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { + m_StreamState = STREAM_DISCARDING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), + (int)(*ptStop/10000), bSendExtra)); + // if the first command is to stop in the future, then we assume they + // want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { + m_StreamState = STREAM_FLOWING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + } + m_bStopSendExtra = bSendExtra; + m_tStopTime = *ptStop; + m_dwStopCookie = dwCookie; + m_StreamStateOnStop = STREAM_DISCARDING; + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); + // sending an extra frame when told to stop now would mess people up + m_bStopSendExtra = FALSE; + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamState = STREAM_DISCARDING; + m_StreamStateOnStop = STREAM_FLOWING; // no pending stop + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +STDMETHODIMP CBaseStreamControl::StartAt +( const REFERENCE_TIME *ptStart, DWORD dwCookie ) +{ + CAutoLock lck(&m_CritSec); + if (ptStart) + { + if (*ptStart == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); + CancelStart(); + // If there's now a command to stop in the future, we assume + // they want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + m_StreamState = STREAM_FLOWING; + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); + // if the first command is to start in the future, then we assume they + // want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + m_StreamState = STREAM_DISCARDING; + } + m_tStartTime = *ptStart; + m_dwStartCookie = dwCookie; + // if (m_tStopTime == m_tStartTime) CancelStop(); + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; + m_StreamState = STREAM_FLOWING; + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +// Retrieve information about current settings +STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) +{ + if (pInfo == NULL) + return E_POINTER; + + pInfo->tStart = m_tStartTime; + pInfo->tStop = m_tStopTime; + pInfo->dwStartCookie = m_dwStartCookie; + pInfo->dwStopCookie = m_dwStopCookie; + pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; + pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; + pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; + switch (m_StreamState) { + default: + DbgBreak("Invalid stream state"); + case STREAM_FLOWING: + break; + case STREAM_DISCARDING: + pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; + break; + } + return S_OK; +} + + +void CBaseStreamControl::ExecuteStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = m_StreamStateOnStop; + if (m_dwStopCookie && m_pSink) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), + m_dwStopCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); + } + CancelStop(); // This will do the tidy up +} + +void CBaseStreamControl::ExecuteStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = STREAM_FLOWING; + if (m_dwStartCookie) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), + m_dwStartCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); + } + CancelStart(); // This will do the tidy up +} + +void CBaseStreamControl::CancelStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamStateOnStop = STREAM_FLOWING; +} + +void CBaseStreamControl::CancelStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; +} + + +// This guy will return one of the three StreamControlState's. Here's what the caller +// should do for each one: +// +// STREAM_FLOWING: Proceed as usual (render or pass the sample on) +// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long +// for the event handle (GetStreamEventHandle()). If the +// wait expires, throw the sample away. If the event +// fires, call me back, I've changed my mind. +// I use pSampleStart (not Stop) so that live sources don't +// block for the duration of their samples, since the clock +// will always read approximately pSampleStart when called + + +// All through this code, you'll notice the following rules: +// - When start and stop time are the same, it's as if start was first +// - An event is considered inside the sample when it's >= sample start time +// but < sample stop time +// - if any part of the sample is supposed to be sent, we'll send the whole +// thing since we don't break it into smaller pieces +// - If we skip over a start or stop without doing it, we still signal the event +// and reset ourselves in case somebody's waiting for the event, and to make +// sure we notice that the event is past and should be forgotten +// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): +// +// 1. xo<--> start then stop +// 2. ox<--> stop then start +// 3. x start +// 4. o stop then start +// 5. x<-->o start +// 6. o<-->x stop +// 7. o start +// 8. x no change +// 9. start +// 10. stop then start +// 11. <-->xo no change +// 12. <-->ox no change +// 13. x<--> start +// 14. start +// 15. <-->x no change +// 16. o<--> stop +// 17. no change +// 18. <-->o no change +// 19. <--> no change + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes +( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) +{ + CAutoLock lck(&m_CritSec); + + ASSERT(!m_bIsFlushing); + ASSERT(pSampleStart && pSampleStop); + + // Don't ask me how I came up with the code below to handle all 19 cases + // - DannyMi + + if (m_tStopTime >= *pSampleStart) + { + if (m_tStartTime >= *pSampleStop) + return m_StreamState; // cases 8 11 12 15 17 18 19 + if (m_tStopTime < m_tStartTime) + ExecuteStop(); // case 10 + ExecuteStart(); // cases 3 5 7 9 13 14 + return m_StreamState; + } + + if (m_tStartTime >= *pSampleStop) + { + ExecuteStop(); // cases 6 16 + return m_StreamState; + } + + if (m_tStartTime <= m_tStopTime) + { + ExecuteStart(); + ExecuteStop(); + return m_StreamState; // case 1 + } + else + { + ExecuteStop(); + ExecuteStart(); + return m_StreamState; // cases 2 4 + } +} + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) +{ + + REFERENCE_TIME rtBufferStart, rtBufferStop; + const BOOL bNoBufferTimes = + pSample == NULL || + FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); + + StreamControlState state; + LONG lWait; + + do + { + // something has to break out of the blocking + if (m_bIsFlushing || m_FilterState == State_Stopped) + return STREAM_DISCARDING; + + if (bNoBufferTimes) { + // Can't do anything until we get a time stamp + state = m_StreamState; + break; + } else { + state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); + if (state == STREAM_FLOWING) + break; + + // we aren't supposed to send this, but we've been + // told to send one more than we were supposed to + // (and the stop isn't still pending and we're streaming) + if (m_bStopSendExtra && !m_bStopExtraSent && + m_tStopTime == MAX_TIME && + m_FilterState != State_Stopped) { + m_bStopExtraSent = TRUE; + DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), + m_dwStopCookie)); + state = STREAM_FLOWING; + break; + } + } + + // We're in discarding mode + + // If we've no clock, discard as fast as we can + if (!m_pRefClock) { + break; + + // If we're paused, we can't discard in a timely manner because + // there's no such thing as stream times. We must block until + // we run or stop, or we'll end up throwing the whole stream away + // as quickly as possible + } else if (m_FilterState == State_Paused) { + lWait = INFINITE; + + } else { + // wait until it's time for the sample until we say "discard" + // ("discard in a timely fashion") + REFERENCE_TIME rtNow; + EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); + rtNow -= m_tRunStart; // Into relative ref-time + lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms + if (lWait < 10) break; // Not worth waiting - discard early + } + + } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); + + return state; +} + + +void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) +{ + CAutoLock lck(&m_CritSec); + + // or we will get confused + if (m_FilterState == new_state) + return; + + switch (new_state) + { + case State_Stopped: + + DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); + + // execute any pending starts and stops in the right order, + // to make sure all notifications get sent, and we end up + // in the right state to begin next time (??? why not?) + + if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { + ExecuteStart(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { + ExecuteStop(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { + if (m_tStartTime <= m_tStopTime) { + ExecuteStart(); + ExecuteStop(); + } else { + ExecuteStop(); + ExecuteStart(); + } + } + // always start off flowing when the graph starts streaming + // unless told otherwise + m_StreamState = STREAM_FLOWING; + m_FilterState = new_state; + break; + + case State_Running: + + DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); + + m_tRunStart = tStart; + // fall-through + + default: // case State_Paused: + m_FilterState = new_state; + } + // unblock! + m_StreamEvent.Set(); +} + + +void CBaseStreamControl::Flushing(BOOL bInProgress) +{ + CAutoLock lck(&m_CritSec); + m_bIsFlushing = bInProgress; + m_StreamEvent.Set(); +} diff --git a/plugins/gs/gsdx9/baseclasses/strmctl.h b/plugins/gs/gsdx9/baseclasses/strmctl.h new file mode 100644 index 0000000000..2a1475fe3a --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/strmctl.h @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// File: StrmCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __strmctl_h__ +#define __strmctl_h__ + +class CBaseStreamControl : public IAMStreamControl +{ +public: + // Used by the implementation + enum StreamControlState + { STREAM_FLOWING = 0x1000, + STREAM_DISCARDING + }; + +private: + enum StreamControlState m_StreamState; // Current stream state + enum StreamControlState m_StreamStateOnStop; // State after next stop + // (i.e.Blocking or Discarding) + + REFERENCE_TIME m_tStartTime; // MAX_TIME implies none + REFERENCE_TIME m_tStopTime; // MAX_TIME implies none + DWORD m_dwStartCookie; // Cookie for notification to app + DWORD m_dwStopCookie; // Cookie for notification to app + volatile BOOL m_bIsFlushing; // No optimization pls! + volatile BOOL m_bStopSendExtra; // bSendExtra was set + volatile BOOL m_bStopExtraSent; // the extra one was sent + + CCritSec m_CritSec; // CritSec to guard above attributes + + // Event to fire when we can come + // out of blocking, or to come out of waiting + // to discard if we change our minds. + // + CAMEvent m_StreamEvent; + + // All of these methods execute immediately. Helpers for others. + // + void ExecuteStop(); + void ExecuteStart(); + void CancelStop(); + void CancelStart(); + + // Some things we need to be told by our owning filter + // Your pin must also expose IAMStreamControl when QI'd for it! + // + IReferenceClock * m_pRefClock; // Need it to set advises + // Filter must tell us via + // SetSyncSource + IMediaEventSink * m_pSink; // Event sink + // Filter must tell us after it + // creates it in JoinFilterGraph() + FILTER_STATE m_FilterState; // Just need it! + // Filter must tell us via + // NotifyFilterState + REFERENCE_TIME m_tRunStart; // Per the Run call to the filter + + // This guy will return one of the three StreamControlState's. Here's what + // the caller should do for each one: + // + // STREAM_FLOWING: Proceed as usual (render or pass the sample on) + // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait + // that long for the event handle + // (GetStreamEventHandle()). If the wait + // expires, throw the sample away. If the event + // fires, call me back - I've changed my mind. + // + enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart, + const REFERENCE_TIME * pSampleStop ); + +public: + // You don't have to tell us much when we're created, but there are other + // obligations that must be met. See SetSyncSource & NotifyFilterState + // below. + // + CBaseStreamControl(); + ~CBaseStreamControl(); + + // If you want this class to work properly, there are thing you need to + // (keep) telling it. Filters with pins that use this class + // should ensure that they pass through to this method any calls they + // receive on their SetSyncSource. + + // We need a clock to see what time it is. This is for the + // "discard in a timely fashion" logic. If we discard everything as + // quick as possible, a whole 60 minute file could get discarded in the + // first 10 seconds, and if somebody wants to turn streaming on at 30 + // minutes into the file, and they make the call more than a few seconds + // after the graph is run, it may be too late! + // So we hold every sample until it's time has gone, then we discard it. + // The filter should call this when it gets a SetSyncSource + // + void SetSyncSource( IReferenceClock * pRefClock ) + { + CAutoLock lck(&m_CritSec); + if (m_pRefClock) m_pRefClock->Release(); + m_pRefClock = pRefClock; + if (m_pRefClock) m_pRefClock->AddRef(); + } + + // Set event sink for notifications + // The filter should call this in its JoinFilterGraph after it creates the + // IMediaEventSink + // + void SetFilterGraph( IMediaEventSink *pSink ) { + m_pSink = pSink; + } + + // Since we schedule in stream time, we need the tStart and must track the + // state of our owning filter. + // The app should call this ever state change + // + void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); + + // Filter should call Flushing(TRUE) in BeginFlush, + // and Flushing(FALSE) in EndFlush. + // + void Flushing( BOOL bInProgress ); + + + // The two main methods of IAMStreamControl + + // Class adds default values suitable for immediate + // muting and unmuting of the stream. + + STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, + BOOL bSendExtra = FALSE, + DWORD dwCookie = 0 ); + STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, + DWORD dwCookie = 0 ); + STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo); + + // Helper function for pin's receive method. Call this with + // the sample and we'll tell you what to do with it. We'll do a + // WaitForSingleObject within this call if one is required. This is + // a "What should I do with this sample?" kind of call. We'll tell the + // caller to either flow it or discard it. + // If pSample is NULL we evaluate based on the current state + // settings + enum StreamControlState CheckStreamState( IMediaSample * pSample ); + +private: + // These don't require locking, but we are relying on the fact that + // m_StreamState can be retrieved with integrity, and is a snap shot that + // may have just been, or may be just about to be, changed. + HANDLE GetStreamEventHandle() const { return m_StreamEvent; } + enum StreamControlState GetStreamState() const { return m_StreamState; } + BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } +}; + +#endif diff --git a/plugins/gs/gsdx9/baseclasses/strmiids.lib b/plugins/gs/gsdx9/baseclasses/strmiids.lib new file mode 100644 index 0000000000000000000000000000000000000000..bd8725da07847a878eacb426235e590e3c60e135 GIT binary patch literal 309056 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 z(w221≶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 +#include + + +#ifdef FILTER_DLL + +/* List of class IDs and creator functions for the class factory. This + provides the link between the OLE entry point in the DLL and an object + being created. The class factory will call the static CreateInstance + function when it is asked to create a CLSID_SystemClock object */ + +CFactoryTemplate g_Templates[1] = { + {&CLSID_SystemClock, CSystemClock::CreateInstance} +}; + +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); +#endif + +/* This goes in the factory template table to create new instances */ +CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr) +{ + return new CSystemClock(NAME("System reference clock"),pUnk, phr); +} + + +CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) : + CBaseReferenceClock(pName, pUnk, phr) +{ +} + +STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + if (riid == IID_IPersist) + { + return GetInterface(static_cast(this), ppv); + } + else if (riid == IID_IAMClockAdjust) + { + return GetInterface(static_cast(this), ppv); + } + else + { + return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the clock's clsid */ +STDMETHODIMP +CSystemClock::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = CLSID_SystemClock; + return NOERROR; +} + + +STDMETHODIMP +CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) +{ + return SetTimeDelta(rtDelta); +} diff --git a/plugins/gs/gsdx9/baseclasses/sysclock.h b/plugins/gs/gsdx9/baseclasses/sysclock.h new file mode 100644 index 0000000000..53c8e4cefe --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/sysclock.h @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// File: SysClock.h +// +// Desc: DirectShow base classes - defines a system clock implementation of +// IReferenceClock. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __SYSTEMCLOCK__ +#define __SYSTEMCLOCK__ + +// +// Base clock. Uses timeGetTime ONLY +// Uses most of the code in the base reference clock. +// Provides GetTime +// + +class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist +{ +public: + // We must be able to create an instance of ourselves + static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); + + // Yield up our class id so that we can be persisted + // Implement required Ipersist method + STDMETHODIMP GetClassID(CLSID *pClsID); + + // IAMClockAdjust methods + STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); +}; //CSystemClock + +#endif /* __SYSTEMCLOCK__ */ diff --git a/plugins/gs/gsdx9/baseclasses/transfrm.cpp b/plugins/gs/gsdx9/baseclasses/transfrm.cpp new file mode 100644 index 0000000000..58d1090b18 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/transfrm.cpp @@ -0,0 +1,1016 @@ +//------------------------------------------------------------------------------ +// File: Transfrm.cpp +// +// Desc: DirectShow base classes - implements class for simple transform +// filters such as video decompressors. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include + + +// ================================================================= +// Implements the CTransformFilter class +// ================================================================= + +CTransformFilter::CTransformFilter(TCHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + +#ifdef UNICODE +CTransformFilter::CTransformFilter(char *pName, + LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} +#endif + +// destructor + +CTransformFilter::~CTransformFilter() +{ + // Delete the pins + + delete m_pInput; + delete m_pOutput; +} + + +// Transform place holder - should never be called +HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) +{ + UNREFERENCED_PARAMETER(pIn); + UNREFERENCED_PARAMETER(pOut); + DbgBreak("CTransformFilter::Transform() should never be called"); + return E_UNEXPECTED; +} + + +// return the number of pins we provide + +int CTransformFilter::GetPinCount() +{ + return 2; +} + + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// We return the objects as and when they are needed. If either of these fails +// then we return NULL, the assumption being that the caller will realise the +// whole deal is off and destroy us - which in turn will delete everything. + +CBasePin * +CTransformFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if necessary + + if (m_pInput == NULL) { + + m_pInput = new CTransformInputPin(NAME("Transform input pin"), + this, // Owner filter + &hr, // Result code + L"XForm In"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pInput == NULL) { + return NULL; + } + m_pOutput = (CTransformOutputPin *) + new CTransformOutputPin(NAME("Transform output pin"), + this, // Owner filter + &hr, // Result code + L"XForm Out"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + if (n == 0) { + return m_pInput; + } else + if (n == 1) { + return m_pOutput; + } else { + return NULL; + } +} + + +// +// FindPin +// +// If Id is In or Out then return the IPin* for that pin +// creating the pin if need be. Otherwise return NULL with an error. + +STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + } else if (0==lstrcmpW(Id,L"Out")) { + *ppPin = GetPin(1); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + + HRESULT hr = NOERROR; + // AddRef() returned pointer - but GetPin could fail if memory is low. + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + hr = E_OUTOFMEMORY; // probably. There's no pin anyway. + } + return hr; +} + + +// override these two functions if you want to inform something +// about entry to or exit from streaming state. + +HRESULT +CTransformFilter::StartStreaming() +{ + return NOERROR; +} + + +HRESULT +CTransformFilter::StopStreaming() +{ + return NOERROR; +} + + +// override this to grab extra interfaces on connection + +HRESULT +CTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin) +{ + UNREFERENCED_PARAMETER(dir); + UNREFERENCED_PARAMETER(pPin); + return NOERROR; +} + + +// place holder to allow derived classes to release any extra interfaces + +HRESULT +CTransformFilter::BreakConnect(PIN_DIRECTION dir) +{ + UNREFERENCED_PARAMETER(dir); + return NOERROR; +} + + +// Let derived classes know about connection completion + +HRESULT +CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +// override this to know when the media type is really set + +HRESULT +CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pmt); + return NOERROR; +} + + +// Set up our output sample +HRESULT +CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample) +{ + IMediaSample *pOutSample; + + // default - times are the same + + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + // This will prevent the image renderer from switching us to DirectDraw + // when we can't do it without skipping frames because we're not on a + // keyframe. If it really has to switch us, it still will, but then we + // will have to wait for the next keyframe + if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + ASSERT(m_pOutput->m_pAllocator != NULL); + HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( + &pOutSample + , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? + &pProps->tStart : NULL + , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? + &pProps->tStop : NULL + , dwFlags + ); + *ppOutSample = pOutSample; + if (FAILED(hr)) { + return hr; + } + + ASSERT(pOutSample); + IMediaSample2 *pOutSample2; + if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, + (void **)&pOutSample2))) { + /* Modify it */ + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) + )); + OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + OutProps.tStart = pProps->tStart; + OutProps.tStop = pProps->tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + hr = pOutSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), + (PBYTE)&OutProps + ); + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + pOutSample2->Release(); + } else { + if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&pProps->tStart, + &pProps->tStop); + } + if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + // Copy the media times + + LONGLONG MediaStart, MediaEnd; + if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart,&MediaEnd); + } + } + return S_OK; +} + +// override this to customize the transform process + +HRESULT +CTransformFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->m_pInputPin->Receive(pSample); + } + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output to deliver to then no point sending us data + + ASSERT (m_pOutput != NULL) ; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->m_pInputPin->Receive(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + + +// Return S_FALSE to mean "pass the note on upstream" +// Return NOERROR (Same as S_OK) +// to mean "I've done something about it, don't pass it on" +HRESULT CTransformFilter::AlterQuality(Quality q) +{ + UNREFERENCED_PARAMETER(q); + return S_FALSE; +} + + +// EndOfStream received. Default behaviour is to deliver straight +// downstream, since we have no queued data. If you overrode Receive +// and have queue data, then you need to handle this and deliver EOS after +// all queued data is sent +HRESULT +CTransformFilter::EndOfStream(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + hr = m_pOutput->DeliverEndOfStream(); + } + + return hr; +} + + +// enter flush state. Receives already blocked +// must override this if you have queued data or a worker thread +HRESULT +CTransformFilter::BeginFlush(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + // block receives -- done by caller (CBaseInputPin::BeginFlush) + + // discard queued data -- we have no queued data + + // free anyone blocked on receive - not possible in this filter + + // call downstream + hr = m_pOutput->DeliverBeginFlush(); + } + return hr; +} + + +// leave flush state. must override this if you have queued data +// or a worker thread +HRESULT +CTransformFilter::EndFlush(void) +{ + // sync with pushing thread -- we have no worker thread + + // ensure no more data to go downstream -- we have no queued data + + // call EndFlush on downstream pins + ASSERT (m_pOutput != NULL); + return m_pOutput->DeliverEndFlush(); + + // caller (the input pin's method) will unblock Receives +} + + +// override these so that the derived filter can catch them + +STDMETHODIMP +CTransformFilter::Stop() +{ + CAutoLock lck1(&m_csFilter); + if (m_State == State_Stopped) { + return NOERROR; + } + + // Succeed the Stop if we are not completely connected + + ASSERT(m_pInput == NULL || m_pOutput != NULL); + if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || + m_pOutput->IsConnected() == FALSE) { + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + return NOERROR; + } + + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // decommit the input pin before locking or we can deadlock + m_pInput->Inactive(); + + // synchronize with Receive calls + + CAutoLock lck2(&m_csReceive); + m_pOutput->Inactive(); + + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + + HRESULT hr = StopStreaming(); + if (SUCCEEDED(hr)) { + // complete the state transition + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + } + return hr; +} + + +STDMETHODIMP +CTransformFilter::Pause() +{ + CAutoLock lck(&m_csFilter); + HRESULT hr = NOERROR; + + if (m_State == State_Paused) { + // (This space left deliberately blank) + } + + // If we have no input pin or it isn't yet connected then when we are + // asked to pause we deliver an end of stream to the downstream filter. + // This makes sure that it doesn't sit there forever waiting for + // samples which we cannot ever deliver without an input connection. + + else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { + if (m_pOutput && m_bEOSDelivered == FALSE) { + m_pOutput->DeliverEndOfStream(); + m_bEOSDelivered = TRUE; + } + m_State = State_Paused; + } + + // We may have an input connection but no output connection + // However, if we have an input pin we do have an output pin + + else if (m_pOutput->IsConnected() == FALSE) { + m_State = State_Paused; + } + + else { + if (m_State == State_Stopped) { + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + CAutoLock lck2(&m_csReceive); + hr = StartStreaming(); + } + if (SUCCEEDED(hr)) { + hr = CBaseFilter::Pause(); + } + } + + m_bSampleSkipped = FALSE; + m_bQualityChanged = FALSE; + return hr; +} + +HRESULT +CTransformFilter::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_pOutput != NULL) { + return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); + } + return S_OK; +} + +// Check streaming status +HRESULT +CTransformInputPin::CheckStreaming() +{ + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } else { + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // we're flushing + if (m_bFlushing) { + return S_FALSE; + } + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; + } +} + + +// ================================================================= +// Implements the CTransformInputPin class +// ================================================================= + + +// constructor + +CTransformInputPin::CTransformInputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} + +#ifdef UNICODE +CTransformInputPin::CTransformInputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} +#endif + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformInputPin::CheckConnect(IPin *pPin) +{ + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformInputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_INPUT); + return CBaseInputPin::BreakConnect(); +} + + +// Let derived class know when the input pin is connected + +HRESULT +CTransformInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// check that we can support a given media type + +HRESULT +CTransformInputPin::CheckMediaType(const CMediaType* pmt) +{ + // Check the input type + + HRESULT hr = m_pTransformFilter->CheckInputType(pmt); + if (S_OK != hr) { + return hr; + } + + // if the output pin is still connected, then we have + // to check the transform not just the input format + + if ((m_pTransformFilter->m_pOutput != NULL) && + (m_pTransformFilter->m_pOutput->IsConnected())) { + return m_pTransformFilter->CheckTransform( + pmt, + &m_pTransformFilter->m_pOutput->CurrentMediaType()); + } else { + return hr; + } +} + + +// set the media type for this connection + +HRESULT +CTransformInputPin::SetMediaType(const CMediaType* mtIn) +{ + // Set the base class media type (should always succeed) + HRESULT hr = CBasePin::SetMediaType(mtIn); + if (FAILED(hr)) { + return hr; + } + + // check the transform can be done (should always succeed) + ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); + + return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); +} + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// provide EndOfStream that passes straight downstream +// (there is no queued data) +STDMETHODIMP +CTransformInputPin::EndOfStream(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csReceive); + HRESULT hr = CheckStreaming(); + if (S_OK == hr) { + hr = m_pTransformFilter->EndOfStream(); + } + return hr; +} + + +// enter flushing state. Call default handler to block Receives, then +// pass to overridable method in filter +STDMETHODIMP +CTransformInputPin::BeginFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + HRESULT hr = CBaseInputPin::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->BeginFlush(); +} + + +// leave flushing state. +// Pass to overridable method in filter, then call base class +// to unblock receives (finally) +STDMETHODIMP +CTransformInputPin::EndFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + HRESULT hr = m_pTransformFilter->EndFlush(); + if (FAILED(hr)) { + return hr; + } + + return CBaseInputPin::EndFlush(); +} + + +// here's the next block of data from the stream. +// AddRef it yourself if you need to hold it beyond the end +// of this call. + +HRESULT +CTransformInputPin::Receive(IMediaSample * pSample) +{ + HRESULT hr; + CAutoLock lck(&m_pTransformFilter->m_csReceive); + ASSERT(pSample); + + // check all is well with the base class + hr = CBaseInputPin::Receive(pSample); + if (S_OK == hr) { + hr = m_pTransformFilter->Receive(pSample); + } + return hr; +} + + + + +// override to pass downstream +STDMETHODIMP +CTransformInputPin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + // Save the values in the pin + CBasePin::NewSegment(tStart, tStop, dRate); + return m_pTransformFilter->NewSegment(tStart, tStop, dRate); +} + + + + +// ================================================================= +// Implements the CTransformOutputPin class +// ================================================================= + + +// constructor + +CTransformOutputPin::CTransformOutputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} + +#ifdef UNICODE +CTransformOutputPin::CTransformOutputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} +#endif + +// destructor + +CTransformOutputPin::~CTransformOutputPin() +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); + + if (m_pPosition) m_pPosition->Release(); +} + + +// overriden to expose IMediaPosition and IMediaSeeking control interfaces + +STDMETHODIMP +CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + + // we should have an input pin by now + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + if (m_pPosition == NULL) { + + HRESULT hr = CreatePosPassThru( + GetOwner(), + FALSE, + (IPin *)m_pTransformFilter->m_pInput, + &m_pPosition); + if (FAILED(hr)) { + return hr; + } + } + return m_pPosition->QueryInterface(riid, ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformOutputPin::CheckConnect(IPin *pPin) +{ + // we should have an input connection first + + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_UNEXPECTED; + } + + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformOutputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); + return CBaseOutputPin::BreakConnect(); +} + + +// Let derived class know when the output pin is connected + +HRESULT +CTransformOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CompleteConnect(pReceivePin); +} + + +// check a given transform - must have selected input type first + +HRESULT +CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) +{ + // must have selected input first + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_INVALIDARG; + } + + return m_pTransformFilter->CheckTransform( + &m_pTransformFilter->m_pInput->CurrentMediaType(), + pmtOut); +} + + +// called after we have agreed a media type to actually set it in which case +// we run the CheckTransform function to get the output format type again + +HRESULT +CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) +{ + HRESULT hr = NOERROR; + ASSERT(m_pTransformFilter->m_pInput != NULL); + + ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); + + // Set the base class media type (should always succeed) + hr = CBasePin::SetMediaType(pmtOut); + if (FAILED(hr)) { + return hr; + } + +#ifdef DEBUG + if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> + m_pInput->CurrentMediaType(),pmtOut))) { + DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); + DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); + DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); + } +#endif + + return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); +} + + +// pass the buffer size decision through to the main transform class + +HRESULT +CTransformOutputPin::DecideBufferSize( + IMemAllocator * pAllocator, + ALLOCATOR_PROPERTIES* pProp) +{ + return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); +} + + + +// return a specific media type indexed by iPosition + +HRESULT +CTransformOutputPin::GetMediaType( + int iPosition, + CMediaType *pMediaType) +{ + ASSERT(m_pTransformFilter->m_pInput != NULL); + + // We don't have any media types if our input is not connected + + if (m_pTransformFilter->m_pInput->IsConnected()) { + return m_pTransformFilter->GetMediaType(iPosition,pMediaType); + } else { + return VFW_S_NO_MORE_ITEMS; + } +} + + +// Override this if you can do something constructive to act on the +// quality message. Consider passing it upstream as well + +// Pass the quality mesage on upstream. + +STDMETHODIMP +CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(pSender); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + + // First see if we want to handle this ourselves + HRESULT hr = m_pTransformFilter->AlterQuality(q); + if (hr!=S_FALSE) { + return hr; // either S_OK or a failure + } + + // S_FALSE means we pass the message on. + // Find the quality sink for our input pin and send it there + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + return m_pTransformFilter->m_pInput->PassNotify(q); + +} // Notify + + +// the following removes a very large number of level 4 warnings from the microsoft +// compiler output, which are not useful at all in this case. +#pragma warning(disable:4514) diff --git a/plugins/gs/gsdx9/baseclasses/transfrm.h b/plugins/gs/gsdx9/baseclasses/transfrm.h new file mode 100644 index 0000000000..55a07dcab5 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/transfrm.h @@ -0,0 +1,304 @@ +//------------------------------------------------------------------------------ +// File: Transfrm.h +// +// Desc: DirectShow base classes - defines classes from which simple +// transform codecs may be derived. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// It assumes the codec has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSFRM__ +#define __TRANSFRM__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransformFilter; + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransformInputPin : public CBaseInputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + + +public: + + CTransformInputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#ifdef UNICODE + CTransformInputPin( + char *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#endif + + STDMETHODIMP QueryId(LPWSTR * Id) + { + return AMGetWideString(L"In", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtIn); + + // set the connection media type + HRESULT SetMediaType(const CMediaType* mt); + + // --- IMemInputPin ----- + + // here's the next block of data from the stream. + // AddRef it yourself if you need to hold it beyond the end + // of this call. + STDMETHODIMP Receive(IMediaSample * pSample); + + // provide EndOfStream that passes straight downstream + // (there is no queued data) + STDMETHODIMP EndOfStream(void); + + // passes it to CTransformFilter::BeginFlush + STDMETHODIMP BeginFlush(void); + + // passes it to CTransformFilter::EndFlush + STDMETHODIMP EndFlush(void); + + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + // Check if it's OK to process samples + virtual HRESULT CheckStreaming(); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; + +}; + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransformOutputPin : public CBaseOutputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + +public: + + // implement IMediaPosition by passing upstream + IUnknown * m_pPosition; + + CTransformOutputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#ifdef UNICODE + CTransformOutputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#endif + ~CTransformOutputPin(); + + // override to expose IMediaPosition + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- CBaseOutputPin ------------ + + STDMETHODIMP QueryId(LPWSTR * Id) + { + return AMGetWideString(L"Out", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtOut); + + // set the connection media type + HRESULT SetMediaType(const CMediaType *pmt); + + // called from CBaseOutputPin during connection to ask for + // the count and size of buffers we need. + HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES *pProp); + + // returns the preferred formats for a pin + HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); + + // inherited from IQualityControl via CBasePin + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; +}; + + +class AM_NOVTABLE CTransformFilter : public CBaseFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual int GetPinCount(); + virtual CBasePin * GetPin(int n); + STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); + + // override state changes to allow derived transform filter + // to control streaming start/stop + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + +public: + + CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); +#ifdef UNICODE + CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid); +#endif + ~CTransformFilter(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + + // These must be supplied in a derived class + + virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + + // check if you can support mtIn + virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + + // check if you can support the transform from this input to this output + virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + // call the SetProperties function with appropriate arguments + virtual HRESULT DecideBufferSize( + IMemAllocator * pAllocator, + ALLOCATOR_PROPERTIES *pprop) PURE; + + // override to suggest OUTPUT pin media types + virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + + + + // ================================================================= + // ----- Optional Override Methods ----------------------- + // ================================================================= + + // you can also override these if you want to know about streaming + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + + // override if you can do anything constructive with quality notifications + virtual HRESULT AlterQuality(Quality q); + + // override this to know when the media type is actually set + virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + + // chance to grab extra interfaces on connection + virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + virtual HRESULT BreakConnect(PIN_DIRECTION dir); + virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // Standard setup for output sample + HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample); + + // if you override Receive, you may need to override these three too + virtual HRESULT EndOfStream(void); + virtual HRESULT BeginFlush(void); + virtual HRESULT EndFlush(void); + virtual HRESULT NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransform = MSR_REGISTER(TEXT("Transform"));} +#endif // PERF + + +// implementation details + +protected: + +#ifdef PERF + int m_idTransform; // performance measuring id +#endif + BOOL m_bEOSDelivered; // have we sent EndOfStream + BOOL m_bSampleSkipped; // Did we just skip a frame + BOOL m_bQualityChanged; // Have we degraded? + + // critical section protecting filter state. + + CCritSec m_csFilter; + + // critical section stopping state changes (ie Stop) while we're + // processing a sample. + // + // This critical section is held when processing + // events that occur on the receive thread - Receive() and EndOfStream(). + // + // If you want to hold both m_csReceive and m_csFilter then grab + // m_csFilter FIRST - like CTransformFilter::Stop() does. + + CCritSec m_csReceive; + + // these hold our input and output pins + + friend class CTransformInputPin; + friend class CTransformOutputPin; + CTransformInputPin *m_pInput; + CTransformOutputPin *m_pOutput; +}; + +#endif /* __TRANSFRM__ */ + + diff --git a/plugins/gs/gsdx9/baseclasses/transip.cpp b/plugins/gs/gsdx9/baseclasses/transip.cpp new file mode 100644 index 0000000000..538b018bd4 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/transip.cpp @@ -0,0 +1,966 @@ +//------------------------------------------------------------------------------ +// File: TransIP.cpp +// +// Desc: DirectShow base classes - implements class for simple Transform- +// In-Place filters such as audio. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// How allocators are decided. +// +// An in-place transform tries to do its work in someone else's buffers. +// It tries to persuade the filters on either side to use the same allocator +// (and for that matter the same media type). In desperation, if the downstream +// filter refuses to supply an allocator and the upstream filter offers only +// a read-only one then it will provide an allocator. +// if the upstream filter insists on a read-only allocator then the transform +// filter will (reluctantly) copy the data before transforming it. +// +// In order to pass an allocator through it needs to remember the one it got +// from the first connection to pass it on to the second one. +// +// It is good if we can avoid insisting on a particular order of connection +// (There is a precedent for insisting on the input +// being connected first. Insisting on the output being connected first is +// not allowed. That would break RenderFile.) +// +// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a +// m_pAllocator member which is used in places like +// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. +// To avoid lots of extra overriding, we should keep these happy +// by using these pointers. +// +// When each pin is connected, it will set the corresponding m_pAllocator +// and will have a single ref-count on that allocator. +// +// Refcounts are acquired by GetAllocator calls which return AddReffed +// allocators and are released in one of: +// CBaseInputPin::Disconnect +// CBaseOutputPin::BreakConect +// In each case m_pAllocator is set to NULL after the release, so this +// is the last chance to ever release it. If there should ever be +// multiple refcounts associated with the same pointer, this had better +// be cleared up before that happens. To avoid such problems, we'll +// stick with one per pointer. + + + +// RECONNECTING and STATE CHANGES +// +// Each pin could be disconnected, connected with a read-only allocator, +// connected with an upstream read/write allocator, connected with an +// allocator from downstream or connected with its own allocator. +// Five states for each pin gives a data space of 25 states. +// +// Notation: +// +// R/W == read/write +// R-O == read-only +// +// +// +// 00 means an unconnected pin. +// <- means using a R/W allocator from the upstream filter +// <= means using a R-O allocator from an upstream filter +// || means using our own (R/W) allocator. +// -> means using a R/W allocator from a downstream filter +// (a R-O allocator from downstream is nonsense, it can't ever work). +// +// +// That makes 25 possible states. Some states are nonsense (two different +// allocators from the same place). These are just an artifact of the notation. +// <= <- Nonsense. +// <- <= Nonsense +// Some states are illegal (the output pin never accepts a R-O allocator): +// 00 <= !! Error !! +// <= <= !! Error !! +// || <= !! Error !! +// -> <= !! Error !! +// Three states appears to be inaccessible: +// -> || Inaccessible +// || -> Inaccessible +// || <- Inaccessible +// Some states only ever occur as intermediates with a pending reconnect which +// is guaranteed to finish in another state. +// -> 00 ?? unstable goes to || 00 +// 00 <- ?? unstable goes to 00 || +// -> <- ?? unstable goes to -> -> +// <- || ?? unstable goes to <- <- +// <- -> ?? unstable goes to <- <- +// And that leaves 11 possible resting states: +// 1 00 00 Nothing connected. +// 2 <- 00 Input pin connected. +// 3 <= 00 Input pin connected using R-O allocator. +// 4 || 00 Needs several state changes to get here. +// 5 00 || Output pin connected using our allocator +// 6 00 -> Downstream only connected +// 7 || || Undesirable but can be forced upon us. +// 8 <= || Copy forced. <= -> is preferable +// 9 <= -> OK - forced to copy. +// 10 <- <- Transform in place (ideal) +// 11 -> -> Transform in place (ideal) +// +// The object of the exercise is to ensure that we finish up in states +// 10 or 11 whenever possible. State 10 is only possible if the upstream +// filter has a R/W allocator (the AVI splitter notoriously +// doesn't) and state 11 is only possible if the downstream filter does +// offer an allocator. +// +// The transition table (entries marked * go via a reconnect) +// +// There are 8 possible transitions: +// A: Connect upstream to filter with R-O allocator that insists on using it. +// B: Connect upstream to filter with R-O allocator but chooses not to use it. +// C: Connect upstream to filter with R/W allocator and insists on using it. +// D: Connect upstream to filter with R/W allocator but chooses not to use it. +// E: Connect downstream to a filter that offers an allocator +// F: Connect downstream to a filter that does not offer an allocator +// G: disconnect upstream +// H: Disconnect downstream +// +// A B C D E F G H +// --------------------------------------------------------- +// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 +// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 +// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 +// || 00 4 | . . . . *8 *7 1 . |4 || 00 +// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || +// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> +// || || 7 | . . . . . . 5 4 |7 || || +// <= || 8 | . . . . . . 5 3 |8 <= || +// <= -> 9 | . . . . . . 6 3 |9 <= -> +// <- <- 10| . . . . . . *5/6 2 |10 <- <- +// -> -> 11| . . . . . . 6 *2/3 |11 -> -> +// --------------------------------------------------------- +// A B C D E F G H +// +// All these states are accessible without requiring any filter to +// change its behaviour but not all transitions are accessible, for +// instance a transition from state 4 to anywhere other than +// state 8 requires that the upstream filter first offer a R-O allocator +// and then changes its mind and offer R/W. This is NOT allowable - it +// leads to things like the output pin getting a R/W allocator from +// upstream and then the input pin being told it can only have a R-O one. +// Note that you CAN change (say) the upstream filter for a different one, but +// only as a disconnect / connect, not as a Reconnect. (Exercise for +// the reader is to see how you get into state 4). +// +// The reconnection stuff goes as follows (some of the cases shown here as +// "no reconnect" may get one to finalise media type - an old story). +// If there is a reconnect where it says "no reconnect" here then the +// reconnection must not change the allocator choice. +// +// state 2: <- 00 transition E <- <- case C <- <- (no change) +// case D -> <- and then to -> -> +// +// state 2: <- 00 transition F <- <- (no reconnect) +// +// state 3: <= 00 transition E <= -> case A <= -> (no change) +// case B -> -> +// transition F <= || case A <= || (no change) +// case B || || +// +// state 4: || 00 transition E || || case B -> || and then all cases to -> -> +// F || || case B || || (no change) +// +// state 5: 00 || transition A <= || (no reconnect) +// B || || (no reconnect) +// C <- || all cases <- <- +// D || || (unfortunate, but upstream's choice) +// +// state 6: 00 -> transition A <= -> (no reconnect) +// B -> -> (no reconnect) +// C <- -> all cases <- <- +// D -> -> (no reconnect) +// +// state 10:<- <- transition G 00 <- case E 00 -> +// case F 00 || +// +// state 11:-> -> transition H -> 00 case A <= 00 (schizo) +// case B <= 00 +// case C <- 00 (schizo) +// case D <- 00 +// +// The Rules: +// To sort out media types: +// The input is reconnected +// if the input pin is connected and the output pin connects +// The output is reconnected +// If the output pin is connected +// and the input pin connects to a different media type +// +// To sort out allocators: +// The input is reconnected +// if the output disconnects and the input was using a downstream allocator +// The output pin calls SetAllocator to pass on a new allocator +// if the output is connected and +// if the input disconnects and the output was using an upstream allocator +// if the input acquires an allocator different from the output one +// and that new allocator is not R-O +// +// Data is copied (i.e. call getbuffer and copy the data before transforming it) +// if the two allocators are different. + + + +// CHAINS of filters: +// +// We sit between two filters (call them A and Z). We should finish up +// with the same allocator on both of our pins and that should be the +// same one that A and Z would have agreed on if we hadn't been in the +// way. Furthermore, it should not matter how many in-place transforms +// are in the way. Let B, C, D... be in-place transforms ("us"). +// Here's how it goes: +// +// 1. +// A connects to B. They agree on A's allocator. +// A-a->B +// +// 2. +// B connects to C. Same story. There is no point in a reconnect, but +// B will request an input reconnect anyway. +// A-a->B-a->C +// +// 3. +// C connects to Z. +// C insists on using A's allocator, but compromises by requesting a reconnect. +// of C's input. +// A-a->B-?->C-a->Z +// +// We now have pending reconnects on both A--->B and B--->C +// +// 4. +// The A--->B link is reconnected. +// A asks B for an allocator. B sees that it has a downstream connection so +// asks its downstream input pin i.e. C's input pin for an allocator. C sees +// that it too has a downstream connection so asks Z for an allocator. +// +// Even though Z's input pin is connected, it is being asked for an allocator. +// It could refuse, in which case the chain is done and will use A's allocator +// Alternatively, Z may supply one. A chooses either Z's or A's own one. +// B's input pin gets NotifyAllocator called to tell it the decision and it +// propagates this downstream by calling ReceiveAllocator on its output pin +// which calls NotifyAllocator on the next input pin downstream etc. +// If the choice is Z then it goes: +// A-z->B-a->C-a->Z +// A-z->B-z->C-a->Z +// A-z->B-z->C-z->Z +// +// And that's IT!! Any further (essentially spurious) reconnects peter out +// with no change in the chain. + +#include +#include +#include + + +// ================================================================= +// Implements the CTransInPlaceFilter class +// ================================================================= + +CTransInPlaceFilter::CTransInPlaceFilter + ( TCHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid, + HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor + +#ifdef UNICODE +CTransInPlaceFilter::CTransInPlaceFilter + ( CHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid, + HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor +#endif + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// As soon as any pin is needed we create both (this is different from the +// usual transform filter) because enumerators, allocators etc are passed +// through from one pin to another and it becomes very painful if the other +// pin isn't there. If we fail to create either pin we ensure we fail both. + +CBasePin * +CTransInPlaceFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if not already done + + if (m_pInput == NULL) { + + m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") + , this // Owner filter + , &hr // Result code + , L"Input" // Pin name + ); + + // Constructor for CTransInPlaceInputPin can't fail + ASSERT(SUCCEEDED(hr)); + } + + // Create an output pin if not already done + + if (m_pInput!=NULL && m_pOutput == NULL) { + + m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") + , this // Owner filter + , &hr // Result code + , L"Output" // Pin name + ); + + // a failed return code should delete the object + + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + ASSERT (n>=0 && n<=1); + if (n == 0) { + return m_pInput; + } else if (n==1) { + return m_pOutput; + } else { + return NULL; + } + +} // GetPin + + + +// dir is the direction of our pin. +// pReceivePin is the pin we are connecting to. +HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // if we are not part of a graph, then don't indirect the pointer + // this probably prevents use of the filter without a filtergraph + if (!m_pGraph) { + return VFW_E_NOT_IN_GRAPH; + } + + // Always reconnect the input to account for buffering changes + // + // Because we don't get to suggest a type on ReceiveConnection + // we need another way of making sure the right type gets used. + // + // One way would be to have our EnumMediaTypes return our output + // connection type first but more deterministic and simple is to + // call ReconnectEx passing the type we want to reconnect with + // via the base class ReconeectPin method. + + if (dir == PINDIR_OUTPUT) { + if( m_pInput->IsConnected() ) { + return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); + } + return NOERROR; + } + + ASSERT(dir == PINDIR_INPUT); + + // Reconnect output if necessary + + if( m_pOutput->IsConnected() ) { + + if ( m_pInput->CurrentMediaType() + != m_pOutput->CurrentMediaType() + ) { + return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); + } + } + return NOERROR; + +} // ComnpleteConnect + + +// +// DecideBufferSize +// +// Tell the output pin's allocator what size buffers we require. +// *pAlloc will be the allocator our output pin is using. +// + +HRESULT CTransInPlaceFilter::DecideBufferSize + ( IMemAllocator *pAlloc + , ALLOCATOR_PROPERTIES *pProperties + ) +{ + ALLOCATOR_PROPERTIES Request, Actual; + HRESULT hr; + + // If we are connected upstream, get his views + if (m_pInput->IsConnected()) { + // Get the input pin allocator, and get its size and count. + // we don't care about his alignment and prefix. + + hr = InputPin()->PeekAllocator()->GetProperties(&Request); + if (FAILED(hr)) { + // Input connected but with a secretive allocator - enough! + return hr; + } + } else { + // We're reduced to blind guessing. Let's guess one byte and if + // this isn't enough then when the other pin does get connected + // we can revise it. + ZeroMemory(&Request, sizeof(Request)); + Request.cBuffers = 1; + Request.cbBuffer = 1; + } + + + DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), + Request.cBuffers, Request.cbBuffer)); + + // Pass the allocator requirements to our output side + // but do a little sanity checking first or we'll just hit + // asserts in the allocator. + + pProperties->cBuffers = Request.cBuffers; + pProperties->cbBuffer = Request.cbBuffer; + pProperties->cbAlign = Request.cbAlign; + if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } + if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } + hr = pAlloc->SetProperties(pProperties, &Actual); + + if (FAILED(hr)) { + return hr; + } + + DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), + Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); + + // Make sure we got the right alignment and at least the minimum required + + if ( (Request.cBuffers > Actual.cBuffers) + || (Request.cbBuffer > Actual.cbBuffer) + || (Request.cbAlign > Actual.cbAlign) + ) { + return E_FAIL; + } + return NOERROR; + +} // DecideBufferSize + +// +// Copy +// +// return a pointer to an identical copy of pSample +IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) +{ + IMediaSample * pDest; + + HRESULT hr; + REFERENCE_TIME tStart, tStop; + const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); + + // this may block for an indeterminate amount of time + hr = OutputPin()->PeekAllocator()->GetBuffer( + &pDest + , bTime ? &tStart : NULL + , bTime ? &tStop : NULL + , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 + ); + + if (FAILED(hr)) { + return NULL; + } + + ASSERT(pDest); + IMediaSample2 *pSample2; + if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + HRESULT hr = pSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), + (PBYTE)m_pInput->SampleProps()); + pSample2->Release(); + if (FAILED(hr)) { + pDest->Release(); + return NULL; + } + } else { + if (bTime) { + pDest->SetTime(&tStart, &tStop); + } + + if (S_OK == pSource->IsSyncPoint()) { + pDest->SetSyncPoint(TRUE); + } + if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { + pDest->SetDiscontinuity(TRUE); + } + if (S_OK == pSource->IsPreroll()) { + pDest->SetPreroll(TRUE); + } + + // Copy the media type + AM_MEDIA_TYPE *pMediaType; + if (S_OK == pSource->GetMediaType(&pMediaType)) { + pDest->SetMediaType(pMediaType); + DeleteMediaType( pMediaType ); + } + + } + + m_bSampleSkipped = FALSE; + + // Copy the sample media times + REFERENCE_TIME TimeStart, TimeEnd; + if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { + pDest->SetMediaTime(&TimeStart,&TimeEnd); + } + + // Copy the actual data length and the actual data. + { + const long lDataLength = pSource->GetActualDataLength(); + pDest->SetActualDataLength(lDataLength); + + // Copy the sample data + { + BYTE *pSourceBuffer, *pDestBuffer; + long lSourceSize = pSource->GetSize(); + long lDestSize = pDest->GetSize(); + + ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); + + pSource->GetPointer(&pSourceBuffer); + pDest->GetPointer(&pDestBuffer); + ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); + + CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); + } + } + + return pDest; + +} // Copy + + +// override this to customize the transform process + +HRESULT +CTransInPlaceFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + HRESULT hr; + + // Start timing the TransInPlace (if PERF is defined) + MSR_START(m_idTransInPlace); + + if (UsingDifferentAllocators()) { + + // We have to copy the data. + + pSample = Copy(pSample); + + if (pSample==NULL) { + MSR_STOP(m_idTransInPlace); + return E_UNEXPECTED; + } + } + + // have the derived class transform the data + hr = Transform(pSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransInPlace); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); + if (UsingDifferentAllocators()) { + pSample->Release(); + } + return hr; + } + + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pSample); + } else { + // But it would be an error to return this private workaround + // to the caller ... + if (S_FALSE == hr) { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because + // returning S_FALSE from Receive() means that this is the end + // of the stream and no more data should be sent. + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + hr = NOERROR; + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + if (UsingDifferentAllocators()) { + pSample->Release(); + } + + return hr; + +} // Receive + + + +// ================================================================= +// Implements the CTransInPlaceInputPin class +// ================================================================= + + +// constructor + +CTransInPlaceInputPin::CTransInPlaceInputPin + ( TCHAR *pObjectName + , CTransInPlaceFilter *pFilter + , HRESULT *phr + , LPCWSTR pName + ) + : CTransformInputPin(pObjectName, + pFilter, + phr, + pName) + , m_bReadOnly(FALSE) + , m_pTIPFilter(pFilter) +{ + DbgLog((LOG_TRACE, 2 + , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); + +} // constructor + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// If the downstream filter has one then offer that (even if our own output +// pin is not using it yet. If the upstream filter chooses it then we will +// tell our output pin to ReceiveAllocator). +// Else if our output pin is using an allocator then offer that. +// ( This could mean offering the upstream filter his own allocator, +// it could mean offerring our own +// ) or it could mean offering the one from downstream +// Else fail to offer any allocator at all. + +STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + HRESULT hr; + + if ( m_pTIPFilter->m_pOutput->IsConnected() ) { + // Store the allocator we got + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->GetAllocator( ppAllocator ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); + } + } + else { + // Help upstream filter (eg TIP filter which is having to do a copy) + // by providing a temp allocator here - we'll never use + // this allocator because when our output is connected we'll + // reconnect this pin + hr = CTransformInputPin::GetAllocator( ppAllocator ); + } + return hr; + +} // GetAllocator + + + +/* Get told which allocator the upstream output pin is actually going to use */ + + +STDMETHODIMP +CTransInPlaceInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + HRESULT hr = S_OK; + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + + CAutoLock cObjectLock(m_pLock); + + m_bReadOnly = bReadOnly; + // If we modify data then don't accept the allocator if it's + // the same as the output pin's allocator + + // If our output is not connected just accept the allocator + // We're never going to use this allocator because when our + // output pin is connected we'll reconnect this pin + if (!m_pTIPFilter->OutputPin()->IsConnected()) { + return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); + } + + // If the allocator is read-only and we're modifying data + // and the allocator is the same as the output pin's + // then reject + if (bReadOnly && m_pTIPFilter->m_bModifiesData) { + IMemAllocator *pOutputAllocator = + m_pTIPFilter->OutputPin()->PeekAllocator(); + + // Make sure we have an output allocator + if (pOutputAllocator == NULL) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> + GetAllocator(&pOutputAllocator); + if(FAILED(hr)) { + hr = CreateMemoryAllocator(&pOutputAllocator); + } + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); + pOutputAllocator->Release(); + } + } + if (pAllocator == pOutputAllocator) { + hr = E_FAIL; + } else if(SUCCEEDED(hr)) { + // Must copy so set the allocator properties on the output + ALLOCATOR_PROPERTIES Props, Actual; + hr = pAllocator->GetProperties(&Props); + if (SUCCEEDED(hr)) { + hr = pOutputAllocator->SetProperties(&Props, &Actual); + } + if (SUCCEEDED(hr)) { + if ( (Props.cBuffers > Actual.cBuffers) + || (Props.cbBuffer > Actual.cbBuffer) + || (Props.cbAlign > Actual.cbAlign) + ) { + hr = E_FAIL; + } + } + + // Set the allocator on the output pin + if (SUCCEEDED(hr)) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pOutputAllocator, FALSE ); + } + } + } else { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pAllocator, bReadOnly ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); + } + } + + if (SUCCEEDED(hr)) { + + // It's possible that the old and the new are the same thing. + // AddRef before release ensures that we don't unload it. + pAllocator->AddRef(); + + if( m_pAllocator != NULL ) + m_pAllocator->Release(); + + m_pAllocator = pAllocator; // We have an allocator for the input pin + } + + return hr; + +} // NotifyAllocator + + +// EnumMediaTypes +// - pass through to our downstream filter +STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected + if( !m_pTIPFilter->m_pOutput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the downstream filter. +// This assumes that the filter does not change the media type. + +HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) +{ + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +// If upstream asks us what our requirements are, we will try to ask downstream +// if that doesn't work, we'll just take the defaults. +STDMETHODIMP +CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) +{ + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->OutputPin() + ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); + else + return E_NOTIMPL; + +} // GetAllocatorRequirements + + +// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not +// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. +HRESULT +CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); +} // CompleteConnect + + +// ================================================================= +// Implements the CTransInPlaceOutputPin class +// ================================================================= + + +// constructor + +CTransInPlaceOutputPin::CTransInPlaceOutputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CTransformOutputPin( pObjectName + , pFilter + , phr + , pPinName), + m_pTIPFilter(pFilter) +{ + DbgLog(( LOG_TRACE, 2 + , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); + +} // constructor + + +// EnumMediaTypes +// - pass through to our upstream filter +STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected. + if( ! m_pTIPFilter->m_pInput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the upstream filter. + +HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) +{ + // Don't accept any output pin type changes if we're copying + // between allocators - it's too late to change the input + // allocator size. + if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { + if (*pmt == m_mt) { + return S_OK; + } else { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // Assumes the type does not change. That's why we're calling + // CheckINPUTType here on the OUTPUT pin. + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pInput->IsConnected() ) + return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +/* Save the allocator pointer in the output pin +*/ +void +CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) +{ + pAllocator->AddRef(); + if (m_pAllocator) { + m_pAllocator->Release(); + } + m_pAllocator = pAllocator; +} // SetAllocator + + +// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to +// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. +// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected +// to the Video Mixing Renderer. +HRESULT +CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); +} // CompleteConnect diff --git a/plugins/gs/gsdx9/baseclasses/transip.h b/plugins/gs/gsdx9/baseclasses/transip.h new file mode 100644 index 0000000000..2c1e5114ac --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/transip.h @@ -0,0 +1,250 @@ +//------------------------------------------------------------------------------ +// File: TransIP.h +// +// Desc: DirectShow base classes - defines classes from which simple +// Transform-In-Place filters may be derived. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// The difference between this and Transfrm.h is that Transfrm copies the data. +// +// It assumes the filter has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// Derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSIP__ +#define __TRANSIP__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransInPlaceFilter; + +// Several of the pin functions call filter functions to do the work, +// so you can often use the pin classes unaltered, just overriding the +// functions in CTransInPlaceFilter. If that's not enough and you want +// to derive your own pin class, override GetPin in the filter to supply +// your own pin classes to the filter. + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransInPlaceInputPin : public CTransformInputPin +{ + +protected: + CTransInPlaceFilter * const m_pTIPFilter; // our filter + BOOL m_bReadOnly; // incoming stream is read only + +public: + + CTransInPlaceInputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT *phr, + LPCWSTR pName); + + // --- IMemInputPin ----- + + // Provide an enumerator for media types by getting one from downstream + STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // Return our upstream allocator + STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); + + // get told which allocator the upstream output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, + BOOL bReadOnly); + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + // Pass this on downstream if it ever gets called. + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); + + HRESULT CompleteConnect(IPin *pReceivePin); + + inline const BOOL ReadOnly() { return m_bReadOnly ; } + +}; // CTransInPlaceInputPin + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransInPlaceOutputPin : public CTransformOutputPin +{ + +protected: + // m_pFilter points to our CBaseFilter + CTransInPlaceFilter * const m_pTIPFilter; + +public: + + CTransInPlaceOutputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT *phr, + LPCWSTR pName); + + + // --- CBaseOutputPin ------------ + + // negotiate the allocator and its buffer size/count + // Insists on using our own allocator. (Actually the one upstream of us). + // We don't override this - instead we just agree the default + // then let the upstream filter decide for itself on reconnect + // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // Provide a media type enumerator. Get it from upstream. + STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // This just saves the allocator being used on the output pin + // Also called by input pin's GetAllocator() + void SetAllocator(IMemAllocator * pAllocator); + + IMemInputPin * ConnectedIMemInputPin() + { return m_pInputPin; } + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + HRESULT CompleteConnect(IPin *pReceivePin); + +}; // CTransInPlaceOutputPin + + +class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual CBasePin *GetPin(int n); + +public: + + // Set bModifiesData == false if your derived filter does + // not modify the data samples (for instance it's just copying + // them somewhere else or looking at the timestamps). + + CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, + bool bModifiesData = true); +#ifdef UNICODE + CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, + bool bModifiesData = true); +#endif + // The following are defined to avoid undefined pure virtuals. + // Even if they are never called, they will give linkage warnings/errors + + // We override EnumMediaTypes to bypass the transform class enumerator + // which would otherwise call this. + HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) + { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); + return E_UNEXPECTED; + } + + // This is called when we actually have to provide out own allocator. + HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *); + + // The functions which call this in CTransform are overridden in this + // class to call CheckInputType with the assumption that the type + // does not change. In Debug builds some calls will be made and + // we just ensure that they do not assert. + HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) + { + return S_OK; + }; + + + // ================================================================= + // ----- You may want to override this ----------------------------- + // ================================================================= + + HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // ================================================================= + // ----- You MUST override these ----------------------------------- + // ================================================================= + + virtual HRESULT Transform(IMediaSample *pSample) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} +#endif // PERF + + +// implementation details + +protected: + + IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource); + +#ifdef PERF + int m_idTransInPlace; // performance measuring id +#endif // PERF + bool m_bModifiesData; // Does this filter change the data? + + // these hold our input and output pins + + friend class CTransInPlaceInputPin; + friend class CTransInPlaceOutputPin; + + CTransInPlaceInputPin *InputPin() const + { + return (CTransInPlaceInputPin *)m_pInput; + }; + CTransInPlaceOutputPin *OutputPin() const + { + return (CTransInPlaceOutputPin *)m_pOutput; + }; + + // Helper to see if the input and output types match + BOOL TypesMatch() + { + return InputPin()->CurrentMediaType() == + OutputPin()->CurrentMediaType(); + } + + // Are the input and output allocators different? + BOOL UsingDifferentAllocators() const + { + return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); + } +}; // CTransInPlaceFilter + +#endif /* __TRANSIP__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/vfwmsgs.h b/plugins/gs/gsdx9/baseclasses/vfwmsgs.h new file mode 100644 index 0000000000..a0309f88f7 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/vfwmsgs.h @@ -0,0 +1,1365 @@ + // no longer used - but might get + // our own facility in the future? + // FacilityNames=(FACILITY_VFW=0x4) + // To add a message: + // + // The MessageId is the number of the message. + // Accepted severities are 'Success' and 'Warning'. + // + // Facility should be FACILITY_ITF (was FACILITY_VFW). + // + // The SymbolicName is the name used in the code to identify the message. + // The text of a message starts the line after 'Language=' and + // ends before a line with only a '.' in column one. +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// + + +// +// MessageId: VFW_E_INVALIDMEDIATYPE +// +// MessageText: +// +// An invalid media type was specified.%0 +// +#define VFW_E_INVALIDMEDIATYPE ((HRESULT)0x80040200L) + +// +// MessageId: VFW_E_INVALIDSUBTYPE +// +// MessageText: +// +// An invalid media subtype was specified.%0 +// +#define VFW_E_INVALIDSUBTYPE ((HRESULT)0x80040201L) + +// +// MessageId: VFW_E_NEED_OWNER +// +// MessageText: +// +// This object can only be created as an aggregated object.%0 +// +#define VFW_E_NEED_OWNER ((HRESULT)0x80040202L) + +// +// MessageId: VFW_E_ENUM_OUT_OF_SYNC +// +// MessageText: +// +// The enumerator has become invalid.%0 +// +#define VFW_E_ENUM_OUT_OF_SYNC ((HRESULT)0x80040203L) + +// +// MessageId: VFW_E_ALREADY_CONNECTED +// +// MessageText: +// +// At least one of the pins involved in the operation is already connected.%0 +// +#define VFW_E_ALREADY_CONNECTED ((HRESULT)0x80040204L) + +// +// MessageId: VFW_E_FILTER_ACTIVE +// +// MessageText: +// +// This operation cannot be performed because the filter is active.%0 +// +#define VFW_E_FILTER_ACTIVE ((HRESULT)0x80040205L) + +// +// MessageId: VFW_E_NO_TYPES +// +// MessageText: +// +// One of the specified pins supports no media types.%0 +// +#define VFW_E_NO_TYPES ((HRESULT)0x80040206L) + +// +// MessageId: VFW_E_NO_ACCEPTABLE_TYPES +// +// MessageText: +// +// There is no common media type between these pins.%0 +// +#define VFW_E_NO_ACCEPTABLE_TYPES ((HRESULT)0x80040207L) + +// +// MessageId: VFW_E_INVALID_DIRECTION +// +// MessageText: +// +// Two pins of the same direction cannot be connected together.%0 +// +#define VFW_E_INVALID_DIRECTION ((HRESULT)0x80040208L) + +// +// MessageId: VFW_E_NOT_CONNECTED +// +// MessageText: +// +// The operation cannot be performed because the pins are not connected.%0 +// +#define VFW_E_NOT_CONNECTED ((HRESULT)0x80040209L) + +// +// MessageId: VFW_E_NO_ALLOCATOR +// +// MessageText: +// +// No sample buffer allocator is available.%0 +// +#define VFW_E_NO_ALLOCATOR ((HRESULT)0x8004020AL) + +// +// MessageId: VFW_E_RUNTIME_ERROR +// +// MessageText: +// +// A run-time error occurred.%0 +// +#define VFW_E_RUNTIME_ERROR ((HRESULT)0x8004020BL) + +// +// MessageId: VFW_E_BUFFER_NOTSET +// +// MessageText: +// +// No buffer space has been set.%0 +// +#define VFW_E_BUFFER_NOTSET ((HRESULT)0x8004020CL) + +// +// MessageId: VFW_E_BUFFER_OVERFLOW +// +// MessageText: +// +// The buffer is not big enough.%0 +// +#define VFW_E_BUFFER_OVERFLOW ((HRESULT)0x8004020DL) + +// +// MessageId: VFW_E_BADALIGN +// +// MessageText: +// +// An invalid alignment was specified.%0 +// +#define VFW_E_BADALIGN ((HRESULT)0x8004020EL) + +// +// MessageId: VFW_E_ALREADY_COMMITTED +// +// MessageText: +// +// Cannot change allocated memory while the filter is active.%0 +// +#define VFW_E_ALREADY_COMMITTED ((HRESULT)0x8004020FL) + +// +// MessageId: VFW_E_BUFFERS_OUTSTANDING +// +// MessageText: +// +// One or more buffers are still active.%0 +// +#define VFW_E_BUFFERS_OUTSTANDING ((HRESULT)0x80040210L) + +// +// MessageId: VFW_E_NOT_COMMITTED +// +// MessageText: +// +// Cannot allocate a sample when the allocator is not active.%0 +// +#define VFW_E_NOT_COMMITTED ((HRESULT)0x80040211L) + +// +// MessageId: VFW_E_SIZENOTSET +// +// MessageText: +// +// Cannot allocate memory because no size has been set.%0 +// +#define VFW_E_SIZENOTSET ((HRESULT)0x80040212L) + +// +// MessageId: VFW_E_NO_CLOCK +// +// MessageText: +// +// Cannot lock for synchronization because no clock has been defined.%0 +// +#define VFW_E_NO_CLOCK ((HRESULT)0x80040213L) + +// +// MessageId: VFW_E_NO_SINK +// +// MessageText: +// +// Quality messages could not be sent because no quality sink has been defined.%0 +// +#define VFW_E_NO_SINK ((HRESULT)0x80040214L) + +// +// MessageId: VFW_E_NO_INTERFACE +// +// MessageText: +// +// A required interface has not been implemented.%0 +// +#define VFW_E_NO_INTERFACE ((HRESULT)0x80040215L) + +// +// MessageId: VFW_E_NOT_FOUND +// +// MessageText: +// +// An object or name was not found.%0 +// +#define VFW_E_NOT_FOUND ((HRESULT)0x80040216L) + +// +// MessageId: VFW_E_CANNOT_CONNECT +// +// MessageText: +// +// No combination of intermediate filters could be found to make the connection.%0 +// +#define VFW_E_CANNOT_CONNECT ((HRESULT)0x80040217L) + +// +// MessageId: VFW_E_CANNOT_RENDER +// +// MessageText: +// +// No combination of filters could be found to render the stream.%0 +// +#define VFW_E_CANNOT_RENDER ((HRESULT)0x80040218L) + +// +// MessageId: VFW_E_CHANGING_FORMAT +// +// MessageText: +// +// Could not change formats dynamically.%0 +// +#define VFW_E_CHANGING_FORMAT ((HRESULT)0x80040219L) + +// +// MessageId: VFW_E_NO_COLOR_KEY_SET +// +// MessageText: +// +// No color key has been set.%0 +// +#define VFW_E_NO_COLOR_KEY_SET ((HRESULT)0x8004021AL) + +// +// MessageId: VFW_E_NOT_OVERLAY_CONNECTION +// +// MessageText: +// +// Current pin connection is not using the IOverlay transport.%0 +// +#define VFW_E_NOT_OVERLAY_CONNECTION ((HRESULT)0x8004021BL) + +// +// MessageId: VFW_E_NOT_SAMPLE_CONNECTION +// +// MessageText: +// +// Current pin connection is not using the IMemInputPin transport.%0 +// +#define VFW_E_NOT_SAMPLE_CONNECTION ((HRESULT)0x8004021CL) + +// +// MessageId: VFW_E_PALETTE_SET +// +// MessageText: +// +// Setting a color key would conflict with the palette already set.%0 +// +#define VFW_E_PALETTE_SET ((HRESULT)0x8004021DL) + +// +// MessageId: VFW_E_COLOR_KEY_SET +// +// MessageText: +// +// Setting a palette would conflict with the color key already set.%0 +// +#define VFW_E_COLOR_KEY_SET ((HRESULT)0x8004021EL) + +// +// MessageId: VFW_E_NO_COLOR_KEY_FOUND +// +// MessageText: +// +// No matching color key is available.%0 +// +#define VFW_E_NO_COLOR_KEY_FOUND ((HRESULT)0x8004021FL) + +// +// MessageId: VFW_E_NO_PALETTE_AVAILABLE +// +// MessageText: +// +// No palette is available.%0 +// +#define VFW_E_NO_PALETTE_AVAILABLE ((HRESULT)0x80040220L) + +// +// MessageId: VFW_E_NO_DISPLAY_PALETTE +// +// MessageText: +// +// Display does not use a palette.%0 +// +#define VFW_E_NO_DISPLAY_PALETTE ((HRESULT)0x80040221L) + +// +// MessageId: VFW_E_TOO_MANY_COLORS +// +// MessageText: +// +// Too many colors for the current display settings.%0 +// +#define VFW_E_TOO_MANY_COLORS ((HRESULT)0x80040222L) + +// +// MessageId: VFW_E_STATE_CHANGED +// +// MessageText: +// +// The state changed while waiting to process the sample.%0 +// +#define VFW_E_STATE_CHANGED ((HRESULT)0x80040223L) + +// +// MessageId: VFW_E_NOT_STOPPED +// +// MessageText: +// +// The operation could not be performed because the filter is not stopped.%0 +// +#define VFW_E_NOT_STOPPED ((HRESULT)0x80040224L) + +// +// MessageId: VFW_E_NOT_PAUSED +// +// MessageText: +// +// The operation could not be performed because the filter is not paused.%0 +// +#define VFW_E_NOT_PAUSED ((HRESULT)0x80040225L) + +// +// MessageId: VFW_E_NOT_RUNNING +// +// MessageText: +// +// The operation could not be performed because the filter is not running.%0 +// +#define VFW_E_NOT_RUNNING ((HRESULT)0x80040226L) + +// +// MessageId: VFW_E_WRONG_STATE +// +// MessageText: +// +// The operation could not be performed because the filter is in the wrong state.%0 +// +#define VFW_E_WRONG_STATE ((HRESULT)0x80040227L) + +// +// MessageId: VFW_E_START_TIME_AFTER_END +// +// MessageText: +// +// The sample start time is after the sample end time.%0 +// +#define VFW_E_START_TIME_AFTER_END ((HRESULT)0x80040228L) + +// +// MessageId: VFW_E_INVALID_RECT +// +// MessageText: +// +// The supplied rectangle is invalid.%0 +// +#define VFW_E_INVALID_RECT ((HRESULT)0x80040229L) + +// +// MessageId: VFW_E_TYPE_NOT_ACCEPTED +// +// MessageText: +// +// This pin cannot use the supplied media type.%0 +// +#define VFW_E_TYPE_NOT_ACCEPTED ((HRESULT)0x8004022AL) + +// +// MessageId: VFW_E_SAMPLE_REJECTED +// +// MessageText: +// +// This sample cannot be rendered.%0 +// +#define VFW_E_SAMPLE_REJECTED ((HRESULT)0x8004022BL) + +// +// MessageId: VFW_E_SAMPLE_REJECTED_EOS +// +// MessageText: +// +// This sample cannot be rendered because the end of the stream has been reached.%0 +// +#define VFW_E_SAMPLE_REJECTED_EOS ((HRESULT)0x8004022CL) + +// +// MessageId: VFW_E_DUPLICATE_NAME +// +// MessageText: +// +// An attempt to add a filter with a duplicate name failed.%0 +// +#define VFW_E_DUPLICATE_NAME ((HRESULT)0x8004022DL) + +// +// MessageId: VFW_S_DUPLICATE_NAME +// +// MessageText: +// +// An attempt to add a filter with a duplicate name succeeded with a modified name.%0 +// +#define VFW_S_DUPLICATE_NAME ((HRESULT)0x0004022DL) + +// +// MessageId: VFW_E_TIMEOUT +// +// MessageText: +// +// A time-out has expired.%0 +// +#define VFW_E_TIMEOUT ((HRESULT)0x8004022EL) + +// +// MessageId: VFW_E_INVALID_FILE_FORMAT +// +// MessageText: +// +// The file format is invalid.%0 +// +#define VFW_E_INVALID_FILE_FORMAT ((HRESULT)0x8004022FL) + +// +// MessageId: VFW_E_ENUM_OUT_OF_RANGE +// +// MessageText: +// +// The list has already been exhausted.%0 +// +#define VFW_E_ENUM_OUT_OF_RANGE ((HRESULT)0x80040230L) + +// +// MessageId: VFW_E_CIRCULAR_GRAPH +// +// MessageText: +// +// The filter graph is circular.%0 +// +#define VFW_E_CIRCULAR_GRAPH ((HRESULT)0x80040231L) + +// +// MessageId: VFW_E_NOT_ALLOWED_TO_SAVE +// +// MessageText: +// +// Updates are not allowed in this state.%0 +// +#define VFW_E_NOT_ALLOWED_TO_SAVE ((HRESULT)0x80040232L) + +// +// MessageId: VFW_E_TIME_ALREADY_PASSED +// +// MessageText: +// +// An attempt was made to queue a command for a time in the past.%0 +// +#define VFW_E_TIME_ALREADY_PASSED ((HRESULT)0x80040233L) + +// +// MessageId: VFW_E_ALREADY_CANCELLED +// +// MessageText: +// +// The queued command has already been canceled.%0 +// +#define VFW_E_ALREADY_CANCELLED ((HRESULT)0x80040234L) + +// +// MessageId: VFW_E_CORRUPT_GRAPH_FILE +// +// MessageText: +// +// Cannot render the file because it is corrupt.%0 +// +#define VFW_E_CORRUPT_GRAPH_FILE ((HRESULT)0x80040235L) + +// +// MessageId: VFW_E_ADVISE_ALREADY_SET +// +// MessageText: +// +// An overlay advise link already exists.%0 +// +#define VFW_E_ADVISE_ALREADY_SET ((HRESULT)0x80040236L) + +// +// MessageId: VFW_S_STATE_INTERMEDIATE +// +// MessageText: +// +// The state transition has not completed.%0 +// +#define VFW_S_STATE_INTERMEDIATE ((HRESULT)0x00040237L) + +// +// MessageId: VFW_E_NO_MODEX_AVAILABLE +// +// MessageText: +// +// No full-screen modes are available.%0 +// +#define VFW_E_NO_MODEX_AVAILABLE ((HRESULT)0x80040238L) + +// +// MessageId: VFW_E_NO_ADVISE_SET +// +// MessageText: +// +// This Advise cannot be canceled because it was not successfully set.%0 +// +#define VFW_E_NO_ADVISE_SET ((HRESULT)0x80040239L) + +// +// MessageId: VFW_E_NO_FULLSCREEN +// +// MessageText: +// +// A full-screen mode is not available.%0 +// +#define VFW_E_NO_FULLSCREEN ((HRESULT)0x8004023AL) + +// +// MessageId: VFW_E_IN_FULLSCREEN_MODE +// +// MessageText: +// +// Cannot call IVideoWindow methods while in full-screen mode.%0 +// +#define VFW_E_IN_FULLSCREEN_MODE ((HRESULT)0x8004023BL) + +// +// MessageId: VFW_E_UNKNOWN_FILE_TYPE +// +// MessageText: +// +// The media type of this file is not recognized.%0 +// +#define VFW_E_UNKNOWN_FILE_TYPE ((HRESULT)0x80040240L) + +// +// MessageId: VFW_E_CANNOT_LOAD_SOURCE_FILTER +// +// MessageText: +// +// The source filter for this file could not be loaded.%0 +// +#define VFW_E_CANNOT_LOAD_SOURCE_FILTER ((HRESULT)0x80040241L) + +// +// MessageId: VFW_S_PARTIAL_RENDER +// +// MessageText: +// +// Some of the streams in this movie are in an unsupported format.%0 +// +#define VFW_S_PARTIAL_RENDER ((HRESULT)0x00040242L) + +// +// MessageId: VFW_E_FILE_TOO_SHORT +// +// MessageText: +// +// A file appeared to be incomplete.%0 +// +#define VFW_E_FILE_TOO_SHORT ((HRESULT)0x80040243L) + +// +// MessageId: VFW_E_INVALID_FILE_VERSION +// +// MessageText: +// +// The version number of the file is invalid.%0 +// +#define VFW_E_INVALID_FILE_VERSION ((HRESULT)0x80040244L) + +// +// MessageId: VFW_S_SOME_DATA_IGNORED +// +// MessageText: +// +// The file contained some property settings that were not used.%0 +// +#define VFW_S_SOME_DATA_IGNORED ((HRESULT)0x00040245L) + +// +// MessageId: VFW_S_CONNECTIONS_DEFERRED +// +// MessageText: +// +// Some connections have failed and have been deferred.%0 +// +#define VFW_S_CONNECTIONS_DEFERRED ((HRESULT)0x00040246L) + +// +// MessageId: VFW_E_INVALID_CLSID +// +// MessageText: +// +// This file is corrupt: it contains an invalid class identifier.%0 +// +#define VFW_E_INVALID_CLSID ((HRESULT)0x80040247L) + +// +// MessageId: VFW_E_INVALID_MEDIA_TYPE +// +// MessageText: +// +// This file is corrupt: it contains an invalid media type.%0 +// +#define VFW_E_INVALID_MEDIA_TYPE ((HRESULT)0x80040248L) + + // Message id from WINWarning.H +// +// MessageId: VFW_E_BAD_KEY +// +// MessageText: +// +// A registry entry is corrupt.%0 +// +#define VFW_E_BAD_KEY ((HRESULT)0x800403F2L) + + // Message id from WINWarning.H +// +// MessageId: VFW_S_NO_MORE_ITEMS +// +// MessageText: +// +// The end of the list has been reached.%0 +// +#define VFW_S_NO_MORE_ITEMS ((HRESULT)0x00040103L) + +// +// MessageId: VFW_E_SAMPLE_TIME_NOT_SET +// +// MessageText: +// +// No time stamp has been set for this sample.%0 +// +#define VFW_E_SAMPLE_TIME_NOT_SET ((HRESULT)0x80040249L) + +// +// MessageId: VFW_S_RESOURCE_NOT_NEEDED +// +// MessageText: +// +// The resource specified is no longer needed.%0 +// +#define VFW_S_RESOURCE_NOT_NEEDED ((HRESULT)0x00040250L) + +// +// MessageId: VFW_E_MEDIA_TIME_NOT_SET +// +// MessageText: +// +// No media time stamp has been set for this sample.%0 +// +#define VFW_E_MEDIA_TIME_NOT_SET ((HRESULT)0x80040251L) + +// +// MessageId: VFW_E_NO_TIME_FORMAT_SET +// +// MessageText: +// +// No media time format has been selected.%0 +// +#define VFW_E_NO_TIME_FORMAT_SET ((HRESULT)0x80040252L) + +// +// MessageId: VFW_E_MONO_AUDIO_HW +// +// MessageText: +// +// Cannot change balance because audio device is mono only.%0 +// +#define VFW_E_MONO_AUDIO_HW ((HRESULT)0x80040253L) + +// +// MessageId: VFW_S_MEDIA_TYPE_IGNORED +// +// MessageText: +// +// A connection could not be made with the media type in the persistent graph,%0 +// but has been made with a negotiated media type.%0 +// +#define VFW_S_MEDIA_TYPE_IGNORED ((HRESULT)0x00040254L) + +// +// MessageId: VFW_E_NO_DECOMPRESSOR +// +// MessageText: +// +// Cannot play back the video stream: no suitable decompressor could be found.%0 +// +#define VFW_E_NO_DECOMPRESSOR ((HRESULT)0x80040255L) + +// +// MessageId: VFW_E_NO_AUDIO_HARDWARE +// +// MessageText: +// +// Cannot play back the audio stream: no audio hardware is available, or the hardware is not responding.%0 +// +#define VFW_E_NO_AUDIO_HARDWARE ((HRESULT)0x80040256L) + +// +// MessageId: VFW_S_VIDEO_NOT_RENDERED +// +// MessageText: +// +// Cannot play back the video stream: no suitable decompressor could be found.%0 +// +#define VFW_S_VIDEO_NOT_RENDERED ((HRESULT)0x00040257L) + +// +// MessageId: VFW_S_AUDIO_NOT_RENDERED +// +// MessageText: +// +// Cannot play back the audio stream: no audio hardware is available.%0 +// +#define VFW_S_AUDIO_NOT_RENDERED ((HRESULT)0x00040258L) + +// +// MessageId: VFW_E_RPZA +// +// MessageText: +// +// Cannot play back the video stream: format 'RPZA' is not supported.%0 +// +#define VFW_E_RPZA ((HRESULT)0x80040259L) + +// +// MessageId: VFW_S_RPZA +// +// MessageText: +// +// Cannot play back the video stream: format 'RPZA' is not supported.%0 +// +#define VFW_S_RPZA ((HRESULT)0x0004025AL) + +// +// MessageId: VFW_E_PROCESSOR_NOT_SUITABLE +// +// MessageText: +// +// ActiveMovie cannot play MPEG movies on this processor.%0 +// +#define VFW_E_PROCESSOR_NOT_SUITABLE ((HRESULT)0x8004025BL) + +// +// MessageId: VFW_E_UNSUPPORTED_AUDIO +// +// MessageText: +// +// Cannot play back the audio stream: the audio format is not supported.%0 +// +#define VFW_E_UNSUPPORTED_AUDIO ((HRESULT)0x8004025CL) + +// +// MessageId: VFW_E_UNSUPPORTED_VIDEO +// +// MessageText: +// +// Cannot play back the video stream: the video format is not supported.%0 +// +#define VFW_E_UNSUPPORTED_VIDEO ((HRESULT)0x8004025DL) + +// +// MessageId: VFW_E_MPEG_NOT_CONSTRAINED +// +// MessageText: +// +// ActiveMovie cannot play this video stream because it falls outside the constrained standard.%0 +// +#define VFW_E_MPEG_NOT_CONSTRAINED ((HRESULT)0x8004025EL) + +// +// MessageId: VFW_E_NOT_IN_GRAPH +// +// MessageText: +// +// Cannot perform the requested function on an object that is not in the filter graph.%0 +// +#define VFW_E_NOT_IN_GRAPH ((HRESULT)0x8004025FL) + +// +// MessageId: VFW_S_ESTIMATED +// +// MessageText: +// +// The value returned had to be estimated. It's accuracy can not be guaranteed.%0 +// +#define VFW_S_ESTIMATED ((HRESULT)0x00040260L) + +// +// MessageId: VFW_E_NO_TIME_FORMAT +// +// MessageText: +// +// Cannot get or set time related information on an object that is using a time format of TIME_FORMAT_NONE.%0 +// +#define VFW_E_NO_TIME_FORMAT ((HRESULT)0x80040261L) + +// +// MessageId: VFW_E_READ_ONLY +// +// MessageText: +// +// The connection cannot be made because the stream is read only and the filter alters the data.%0 +// +#define VFW_E_READ_ONLY ((HRESULT)0x80040262L) + +// +// MessageId: VFW_S_RESERVED +// +// MessageText: +// +// This success code is reserved for internal purposes within ActiveMovie.%0 +// +#define VFW_S_RESERVED ((HRESULT)0x00040263L) + +// +// MessageId: VFW_E_BUFFER_UNDERFLOW +// +// MessageText: +// +// The buffer is not full enough.%0 +// +#define VFW_E_BUFFER_UNDERFLOW ((HRESULT)0x80040264L) + +// +// MessageId: VFW_E_UNSUPPORTED_STREAM +// +// MessageText: +// +// Cannot play back the file. The format is not supported.%0 +// +#define VFW_E_UNSUPPORTED_STREAM ((HRESULT)0x80040265L) + +// +// MessageId: VFW_E_NO_TRANSPORT +// +// MessageText: +// +// Pins cannot connect due to not supporting the same transport.%0 +// +#define VFW_E_NO_TRANSPORT ((HRESULT)0x80040266L) + +// +// MessageId: VFW_S_STREAM_OFF +// +// MessageText: +// +// The stream has been turned off.%0 +// +#define VFW_S_STREAM_OFF ((HRESULT)0x00040267L) + +// +// MessageId: VFW_S_CANT_CUE +// +// MessageText: +// +// The graph can't be cued because of lack of or corrupt data.%0 +// +#define VFW_S_CANT_CUE ((HRESULT)0x00040268L) + +// +// MessageId: VFW_E_BAD_VIDEOCD +// +// MessageText: +// +// The Video CD can't be read correctly by the device or is the data is corrupt.%0 +// +#define VFW_E_BAD_VIDEOCD ((HRESULT)0x80040269L) + +// +// MessageId: VFW_S_NO_STOP_TIME +// +// MessageText: +// +// The stop time for the sample was not set.%0 +// +#define VFW_S_NO_STOP_TIME ((HRESULT)0x00040270L) + +// +// MessageId: VFW_E_OUT_OF_VIDEO_MEMORY +// +// MessageText: +// +// There is not enough Video Memory at this display resolution and number of colors. Reducing resolution might help.%0 +// +#define VFW_E_OUT_OF_VIDEO_MEMORY ((HRESULT)0x80040271L) + +// +// MessageId: VFW_E_VP_NEGOTIATION_FAILED +// +// MessageText: +// +// The VideoPort connection negotiation process has failed.%0 +// +#define VFW_E_VP_NEGOTIATION_FAILED ((HRESULT)0x80040272L) + +// +// MessageId: VFW_E_DDRAW_CAPS_NOT_SUITABLE +// +// MessageText: +// +// Either DirectDraw has not been installed or the Video Card capabilities are not suitable. Make sure the display is not in 16 color mode.%0 +// +#define VFW_E_DDRAW_CAPS_NOT_SUITABLE ((HRESULT)0x80040273L) + +// +// MessageId: VFW_E_NO_VP_HARDWARE +// +// MessageText: +// +// No VideoPort hardware is available, or the hardware is not responding.%0 +// +#define VFW_E_NO_VP_HARDWARE ((HRESULT)0x80040274L) + +// +// MessageId: VFW_E_NO_CAPTURE_HARDWARE +// +// MessageText: +// +// No Capture hardware is available, or the hardware is not responding.%0 +// +#define VFW_E_NO_CAPTURE_HARDWARE ((HRESULT)0x80040275L) + +// +// MessageId: VFW_E_DVD_OPERATION_INHIBITED +// +// MessageText: +// +// This User Operation is inhibited by DVD Content at this time.%0 +// +#define VFW_E_DVD_OPERATION_INHIBITED ((HRESULT)0x80040276L) + +// +// MessageId: VFW_E_DVD_INVALIDDOMAIN +// +// MessageText: +// +// This Operation is not permitted in the current domain.%0 +// +#define VFW_E_DVD_INVALIDDOMAIN ((HRESULT)0x80040277L) + +// +// MessageId: VFW_E_DVD_NO_BUTTON +// +// MessageText: +// +// The specified button is invalid or is not present at the current time, or there is no button present at the specified location.%0 +// +#define VFW_E_DVD_NO_BUTTON ((HRESULT)0x80040278L) + +// +// MessageId: VFW_E_DVD_GRAPHNOTREADY +// +// MessageText: +// +// DVD-Video playback graph has not been built yet.%0 +// +#define VFW_E_DVD_GRAPHNOTREADY ((HRESULT)0x80040279L) + +// +// MessageId: VFW_E_DVD_RENDERFAIL +// +// MessageText: +// +// DVD-Video playback graph building failed.%0 +// +#define VFW_E_DVD_RENDERFAIL ((HRESULT)0x8004027AL) + +// +// MessageId: VFW_E_DVD_DECNOTENOUGH +// +// MessageText: +// +// DVD-Video playback graph could not be built due to insufficient decoders.%0 +// +#define VFW_E_DVD_DECNOTENOUGH ((HRESULT)0x8004027BL) + +// +// MessageId: VFW_E_DDRAW_VERSION_NOT_SUITABLE +// +// MessageText: +// +// Version number of DirectDraw not suitable. Make sure to install dx5 or higher version.%0 +// +#define VFW_E_DDRAW_VERSION_NOT_SUITABLE ((HRESULT)0x8004027CL) + +// +// MessageId: VFW_E_COPYPROT_FAILED +// +// MessageText: +// +// Copy protection cannot be enabled. Please make sure any other copy protected content is not being shown now.%0 +// +#define VFW_E_COPYPROT_FAILED ((HRESULT)0x8004027DL) + +// +// MessageId: VFW_S_NOPREVIEWPIN +// +// MessageText: +// +// There was no preview pin available, so the capture pin output is being split to provide both capture and preview.%0 +// +#define VFW_S_NOPREVIEWPIN ((HRESULT)0x0004027EL) + +// +// MessageId: VFW_E_TIME_EXPIRED +// +// MessageText: +// +// This object cannot be used anymore as its time has expired.%0 +// +#define VFW_E_TIME_EXPIRED ((HRESULT)0x8004027FL) + +// +// MessageId: VFW_S_DVD_NON_ONE_SEQUENTIAL +// +// MessageText: +// +// The current title was not a sequential set of chapters (PGC), and the returned timing information might not be continuous.%0 +// +#define VFW_S_DVD_NON_ONE_SEQUENTIAL ((HRESULT)0x00040280L) + +// +// MessageId: VFW_E_DVD_WRONG_SPEED +// +// MessageText: +// +// The operation cannot be performed at the current playback speed.%0 +// +#define VFW_E_DVD_WRONG_SPEED ((HRESULT)0x80040281L) + +// +// MessageId: VFW_E_DVD_MENU_DOES_NOT_EXIST +// +// MessageText: +// +// The specified menu doesn't exist.%0 +// +#define VFW_E_DVD_MENU_DOES_NOT_EXIST ((HRESULT)0x80040282L) + +// +// MessageId: VFW_E_DVD_CMD_CANCELLED +// +// MessageText: +// +// The specified command was either cancelled or no longer exists.%0 +// +#define VFW_E_DVD_CMD_CANCELLED ((HRESULT)0x80040283L) + +// +// MessageId: VFW_E_DVD_STATE_WRONG_VERSION +// +// MessageText: +// +// The data did not contain a recognized version.%0 +// +#define VFW_E_DVD_STATE_WRONG_VERSION ((HRESULT)0x80040284L) + +// +// MessageId: VFW_E_DVD_STATE_CORRUPT +// +// MessageText: +// +// The state data was corrupt.%0 +// +#define VFW_E_DVD_STATE_CORRUPT ((HRESULT)0x80040285L) + +// +// MessageId: VFW_E_DVD_STATE_WRONG_DISC +// +// MessageText: +// +// The state data is from a different disc.%0 +// +#define VFW_E_DVD_STATE_WRONG_DISC ((HRESULT)0x80040286L) + +// +// MessageId: VFW_E_DVD_INCOMPATIBLE_REGION +// +// MessageText: +// +// The region was not compatible with the current drive.%0 +// +#define VFW_E_DVD_INCOMPATIBLE_REGION ((HRESULT)0x80040287L) + +// +// MessageId: VFW_E_DVD_NO_ATTRIBUTES +// +// MessageText: +// +// The requested DVD stream attribute does not exist.%0 +// +#define VFW_E_DVD_NO_ATTRIBUTES ((HRESULT)0x80040288L) + +// +// MessageId: VFW_E_DVD_NO_GOUP_PGC +// +// MessageText: +// +// Currently there is no GoUp (Annex J user function) program chain (PGC).%0 +// +#define VFW_E_DVD_NO_GOUP_PGC ((HRESULT)0x80040289L) + +// +// MessageId: VFW_E_DVD_LOW_PARENTAL_LEVEL +// +// MessageText: +// +// The current parental level was too low.%0 +// +#define VFW_E_DVD_LOW_PARENTAL_LEVEL ((HRESULT)0x8004028AL) + +// +// MessageId: VFW_E_DVD_NOT_IN_KARAOKE_MODE +// +// MessageText: +// +// The current audio is not karaoke content.%0 +// +#define VFW_E_DVD_NOT_IN_KARAOKE_MODE ((HRESULT)0x8004028BL) + +// +// MessageId: VFW_S_DVD_CHANNEL_CONTENTS_NOT_AVAILABLE +// +// MessageText: +// +// The audio stream did not contain sufficient information to determine the contents of each channel.%0 +// +#define VFW_S_DVD_CHANNEL_CONTENTS_NOT_AVAILABLE ((HRESULT)0x0004028CL) + +// +// MessageId: VFW_S_DVD_NOT_ACCURATE +// +// MessageText: +// +// The seek into the movie was not frame accurate.%0 +// +#define VFW_S_DVD_NOT_ACCURATE ((HRESULT)0x0004028DL) + +// +// MessageId: VFW_E_FRAME_STEP_UNSUPPORTED +// +// MessageText: +// +// Frame step is not supported on this configuration.%0 +// +#define VFW_E_FRAME_STEP_UNSUPPORTED ((HRESULT)0x8004028EL) + +// +// MessageId: VFW_E_DVD_STREAM_DISABLED +// +// MessageText: +// +// The specified stream is disabled and cannot be selected.%0 +// +#define VFW_E_DVD_STREAM_DISABLED ((HRESULT)0x8004028FL) + +// +// MessageId: VFW_E_DVD_TITLE_UNKNOWN +// +// MessageText: +// +// The operation depends on the current title number, however the navigator has not yet entered the VTSM or the title domains, +// so the 'current' title index is unknown.%0 +// +#define VFW_E_DVD_TITLE_UNKNOWN ((HRESULT)0x80040290L) + +// +// MessageId: VFW_E_DVD_INVALID_DISC +// +// MessageText: +// +// The specified path does not point to a valid DVD disc.%0 +// +#define VFW_E_DVD_INVALID_DISC ((HRESULT)0x80040291L) + +// +// MessageId: VFW_E_DVD_NO_RESUME_INFORMATION +// +// MessageText: +// +// There is currently no resume information.%0 +// +#define VFW_E_DVD_NO_RESUME_INFORMATION ((HRESULT)0x80040292L) + +// +// MessageId: VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD +// +// MessageText: +// +// This thread has already blocked this output pin. There is no need to call IPinFlowControl::Block() again.%0 +// +#define VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD ((HRESULT)0x80040293L) + +// +// MessageId: VFW_E_PIN_ALREADY_BLOCKED +// +// MessageText: +// +// IPinFlowControl::Block() has been called on another thread. The current thread cannot make any assumptions about this pin's block state.%0 +// +#define VFW_E_PIN_ALREADY_BLOCKED ((HRESULT)0x80040294L) + +// +// MessageId: VFW_E_CERTIFICATION_FAILURE +// +// MessageText: +// +// An operation failed due to a certification failure.%0 +// +#define VFW_E_CERTIFICATION_FAILURE ((HRESULT)0x80040295L) + +// +// MessageId: VFW_E_VMR_NOT_IN_MIXER_MODE +// +// MessageText: +// +// The VMR has not yet created a mixing component. That is, IVMRFilterConfig::SetNumberofStreams has not yet been called.%0 +// +#define VFW_E_VMR_NOT_IN_MIXER_MODE ((HRESULT)0x80040296L) + +// +// MessageId: VFW_E_VMR_NO_AP_SUPPLIED +// +// MessageText: +// +// The application has not yet provided the VMR filter with a valid allocator-presenter object.%0 +// +#define VFW_E_VMR_NO_AP_SUPPLIED ((HRESULT)0x80040297L) +// +// MessageId: VFW_E_VMR_NO_DEINTERLACE_HW +// +// MessageText: +// +// The VMR could not find any de-interlacing hardware on the current display device.%0 +// +#define VFW_E_VMR_NO_DEINTERLACE_HW ((HRESULT)0x80040298L) +// +// MessageId: VFW_E_VMR_NO_PROCAMP_HW +// +// MessageText: +// +// The VMR could not find any ProcAmp hardware on the current display device.%0 +// +#define VFW_E_VMR_NO_PROCAMP_HW ((HRESULT)0x80040299L) +// +// MessageId: VFW_E_DVD_VMR9_INCOMPATIBLEDEC +// +// MessageText: +// +// VMR9 does not work with VPE-based hardware decoders.%0 +// +#define VFW_E_DVD_VMR9_INCOMPATIBLEDEC ((HRESULT)0x8004029AL) +// +// MessageId: VFW_E_NO_COPP_HW +// +// MessageText: +// +// The current display device does not support Content Output Protection Protocol (COPP) H/W.%0 +// +#define VFW_E_NO_COPP_HW ((HRESULT)0x8004029BL) +// +// +// E_PROP_SET_UNSUPPORTED and E_PROP_ID_UNSUPPORTED are added here using +// HRESULT_FROM_WIN32() because VC5 doesn't have WinNT's new error codes +// from winerror.h, and because it is more convienent to have them already +// formed as HRESULTs. These should correspond to: +// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == E_PROP_ID_UNSUPPORTED +// HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND) == E_PROP_SET_UNSUPPORTED +#if !defined(E_PROP_SET_UNSUPPORTED) +// +// MessageId: E_PROP_SET_UNSUPPORTED +// +// MessageText: +// +// The Specified property set is not supported.%0 +// +#define E_PROP_SET_UNSUPPORTED ((HRESULT)0x80070492L) + +#endif //!defined(E_PROP_SET_UNSUPPORTED) +#if !defined(E_PROP_ID_UNSUPPORTED) +// +// MessageId: E_PROP_ID_UNSUPPORTED +// +// MessageText: +// +// The specified property ID is not supported for the specified property set.%0 +// +#define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490L) + +#endif //!defined(E_PROP_ID_UNSUPPORTED) diff --git a/plugins/gs/gsdx9/baseclasses/videoctl.cpp b/plugins/gs/gsdx9/baseclasses/videoctl.cpp new file mode 100644 index 0000000000..6561f2946b --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/videoctl.cpp @@ -0,0 +1,715 @@ +//------------------------------------------------------------------------------ +// File: VideoCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include "ddmm.h" + +// Load a string from the resource file string table. The buffer must be at +// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a +// buffer in the property page class and use it for all string loading. It +// cannot be static as multiple property pages may be active simultaneously + +TCHAR *WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID) +{ + if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return TEXT(""); + } + return pBuffer; +} + +#ifdef UNICODE +char *WINAPI StringFromResource(char *pBuffer, int iResourceID) +{ + if (LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return ""; + } + return pBuffer; +} +#endif + + + +// Property pages typically are called through their OLE interfaces. These +// use UNICODE strings regardless of how the binary is built. So when we +// load strings from the resource file we sometimes want to convert them +// to UNICODE. This method is passed the target UNICODE buffer and does a +// convert after loading the string (if built UNICODE this is not needed) +// On WinNT we can explicitly call LoadStringW which saves two conversions + +#ifndef UNICODE + +WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID) +{ + *pBuffer = 0; + + if (g_amPlatform == VER_PLATFORM_WIN32_NT) { + LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH); + } else { + + CHAR szBuffer[STR_MAX_LENGTH]; + DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH); + // if we loaded a string convert it to wide characters, ensuring + // that we also null terminate the result. + if (dwStringLength++) { + MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH); + } + } + return pBuffer; +} + +#endif + + +// Helper function to calculate the size of the dialog + +BOOL WINAPI GetDialogSize(int iResourceID, + DLGPROC pDlgProc, + LPARAM lParam, + SIZE *pResult) +{ + RECT rc; + HWND hwnd; + + // Create a temporary property page + + hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(iResourceID), + GetDesktopWindow(), + pDlgProc, + lParam); + if (hwnd == NULL) { + return FALSE; + } + + GetWindowRect(hwnd, &rc); + pResult->cx = rc.right - rc.left; + pResult->cy = rc.bottom - rc.top; + + DestroyWindow(hwnd); + return TRUE; +} + + +// Class that aggregates on the IDirectDraw interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ASSERT(m_pDirectDraw); + + // Do we have this interface + + if (riid == IID_IDirectDraw) { + return GetInterface((IDirectDraw *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDirectDraw::Compact() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Compact(); +} + + +STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::FlipToGDISurface() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->FlipToGDISurface(); +} + + +STDMETHODIMP CAggDirectDraw::GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); +} + + +STDMETHODIMP CAggDirectDraw::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDirectDraw::GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); +} + + +STDMETHODIMP CAggDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(LPDWORD lpdwFrequency) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); +} + + +STDMETHODIMP CAggDirectDraw::GetScanLine(LPDWORD lpdwScanLine) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetScanLine(lpdwScanLine); +} + + +STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(LPBOOL lpblsInVB) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); +} + + +STDMETHODIMP CAggDirectDraw::Initialize(GUID *lpGUID) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Initialize(lpGUID); +} + + +STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->RestoreDisplayMode(); +} + + +STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags); +} + + +STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp); +} + + +STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent); +} + + +// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ASSERT(m_pDirectDrawSurface); + + // Do we have this interface + + if (riid == IID_IDirectDrawSurface) { + return GetInterface((IDirectDrawSurface *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDrawSurface::AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(LPRECT lpRect) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); +} + + +STDMETHODIMP CAggDrawSurface::Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); +} + + +STDMETHODIMP CAggDrawSurface::BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); +} + + +STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); +} + + +STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); +} + + +STDMETHODIMP CAggDrawSurface::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetBltStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetCaps(LPDDSCAPS lpDDSCaps) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetCaps(lpDDSCaps); +} + + +STDMETHODIMP CAggDrawSurface::GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetClipper(lplpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::GetDC(HDC *lphDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetDC(lphDC); +} + + +STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetFlipStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); +} + + +STDMETHODIMP CAggDrawSurface::GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPalette(lplpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat); +} + + +// A bit of a warning here: Our media samples in DirectShow aggregate on +// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample +// by QueryInterface). Unfortunately the underlying DirectDraw code cannot +// be aggregated so we have to use these classes. The snag is that when we +// call a different surface and pass in this interface as perhaps the source +// surface the call will fail because DirectDraw dereferences the pointer to +// get at its private data structures. Therefore we supply this workaround to give +// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc +// and we will fill in the lpSurface pointer with the real underlying surface + +STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + + // First call down to the underlying DirectDraw + + HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc); + if (FAILED(hr)) { + return hr; + } + + // Store the real DirectDrawSurface interface + lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface; + return hr; +} + + +STDMETHODIMP CAggDrawSurface::Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDrawSurface::IsLost() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->IsLost(); +} + + +STDMETHODIMP CAggDrawSurface::Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent); +} + + +STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->ReleaseDC(hDC); +} + + +STDMETHODIMP CAggDrawSurface::Restore() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Restore(); +} + + +STDMETHODIMP CAggDrawSurface::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetClipper(lpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY); +} + + +STDMETHODIMP CAggDrawSurface::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetPalette(lpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::Unlock(LPVOID lpSurfaceData) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Unlock(lpSurfaceData); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference); +} + + +// DirectShow must work on multiple platforms. In particular, it also runs on +// Windows NT 3.51 which does not have DirectDraw capabilities. The filters +// cannot therefore link statically to the DirectDraw library. To make their +// lives that little bit easier we provide this class that manages loading +// and unloading the library and creating the initial IDirectDraw interface + +CLoadDirectDraw::CLoadDirectDraw() : + m_pDirectDraw(NULL), + m_hDirectDraw(NULL) +{ +} + + +// Destructor forces unload + +CLoadDirectDraw::~CLoadDirectDraw() +{ + ReleaseDirectDraw(); + + if (m_hDirectDraw) { + NOTE("Unloading library"); + FreeLibrary(m_hDirectDraw); + } +} + + +// We can't be sure that DirectDraw is always available so we can't statically +// link to the library. Therefore we load the library, get the function entry +// point addresses and call them to create the driver objects. We return S_OK +// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE +// We initialise a DirectDraw instance by explicitely loading the library and +// calling GetProcAddress on the DirectDrawCreate entry point that it exports + +// On a multi monitor system, we can get the DirectDraw object for any +// monitor (device) with the optional szDevice parameter + +HRESULT CLoadDirectDraw::LoadDirectDraw(LPSTR szDevice) +{ + PDRAWCREATE pDrawCreate; + PDRAWENUM pDrawEnum; + LPDIRECTDRAWENUMERATEEXA pDrawEnumEx; + HRESULT hr = NOERROR; + + NOTE("Entering DoLoadDirectDraw"); + + // Is DirectDraw already loaded + + if (m_pDirectDraw) { + NOTE("Already loaded"); + ASSERT(m_hDirectDraw); + return NOERROR; + } + + // Make sure the library is available + + if(!m_hDirectDraw) + { + UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); + m_hDirectDraw = LoadLibrary(TEXT("DDRAW.DLL")); + SetErrorMode(ErrorMode); + + if (m_hDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't load DDRAW.DLL"))); + NOTE("No library"); + return E_NOINTERFACE; + } + } + + // Get the DLL address for the creator function + + pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate"); + // force ANSI, we assume it + pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA"); + pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw, + "DirectDrawEnumerateExA"); + + // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff + if (pDrawCreate == NULL || pDrawEnum == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"), + pDrawCreate, pDrawEnum)); + NOTE("No entry point"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + + DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"), + szDevice ? szDevice : "")); + + // Create a DirectDraw display provider for this device, using the fancy + // multimon-aware version, if it exists + if (pDrawEnumEx) + m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate, + pDrawEnumEx); + else + m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate, + pDrawEnum); + + if (m_pDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw"))); + NOTE("No instance"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + return NOERROR; +} + + +// Called to release any DirectDraw provider we previously loaded. We may be +// called at any time especially when something goes horribly wrong and when +// we need to clean up before returning so we can't guarantee that all state +// variables are consistent so free only those really allocated allocated +// This should only be called once all reference counts have been released + +void CLoadDirectDraw::ReleaseDirectDraw() +{ + NOTE("Releasing DirectDraw driver"); + + // Release any DirectDraw provider interface + + if (m_pDirectDraw) { + NOTE("Releasing instance"); + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + +} + + +// Return NOERROR (S_OK) if DirectDraw has been loaded by this object + +HRESULT CLoadDirectDraw::IsDirectDrawLoaded() +{ + NOTE("Entering IsDirectDrawLoaded"); + + if (m_pDirectDraw == NULL) { + NOTE("DirectDraw not loaded"); + return S_FALSE; + } + return NOERROR; +} + + +// Return the IDirectDraw interface we look after + +LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() +{ + NOTE("Entering GetDirectDraw"); + + if (m_pDirectDraw == NULL) { + NOTE("No DirectDraw"); + return NULL; + } + + NOTE("Returning DirectDraw"); + m_pDirectDraw->AddRef(); + return m_pDirectDraw; +} + + +// Are we running on Direct Draw version 1? We need to find out as +// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To +// find out, we simply see if it supports IDirectDraw2. Only version 2 and +// higher support this. + +BOOL CLoadDirectDraw::IsDirectDrawVersion1() +{ + + if (m_pDirectDraw == NULL) + return FALSE; + + IDirectDraw2 *p = NULL; + HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p); + if (p) + p->Release(); + if (hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater"))); + return FALSE; + } else { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1"))); + return TRUE; + } +} diff --git a/plugins/gs/gsdx9/baseclasses/videoctl.h b/plugins/gs/gsdx9/baseclasses/videoctl.h new file mode 100644 index 0000000000..3396daca21 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/videoctl.h @@ -0,0 +1,178 @@ +//------------------------------------------------------------------------------ +// File: VideoCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __VIDEOCTL__ +#define __VIDEOCTL__ + +// These help with property page implementations. The first can be used to +// load any string from a resource file. The buffer to load into is passed +// as an input parameter. The same buffer is the return value if the string +// was found otherwise it returns TEXT(""). The GetDialogSize is passed the +// resource ID of a dialog box and returns the size of it in screen pixels + +#define STR_MAX_LENGTH 256 +TCHAR * WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID); + +#ifdef UNICODE +#define WideStringFromResource StringFromResource +char* WINAPI StringFromResource(char*pBuffer, int iResourceID); +#else +WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID); +#endif + + +BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier + DLGPROC pDlgProc, // Pointer to dialog procedure + LPARAM lParam, // Any user data wanted in pDlgProc + SIZE *pResult); // Returns the size of dialog box + +// Class that aggregates an IDirectDraw interface + +class CAggDirectDraw : public IDirectDraw, public CUnknown +{ +protected: + + LPDIRECTDRAW m_pDirectDraw; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); + + // Constructor and destructor + + CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDraw(NULL) { }; + + virtual CAggDirectDraw::~CAggDirectDraw() { }; + + // Set the object we should be aggregating + void SetDirectDraw(LPDIRECTDRAW pDirectDraw) { + m_pDirectDraw = pDirectDraw; + } + + // IDirectDraw methods + + STDMETHODIMP Compact(); + STDMETHODIMP CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter); + STDMETHODIMP CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter); + STDMETHODIMP CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter); + STDMETHODIMP DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface); + STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback); + STDMETHODIMP EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback); + STDMETHODIMP FlipToGDISurface(); + STDMETHODIMP GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps); + STDMETHODIMP GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes); + STDMETHODIMP GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface); + STDMETHODIMP GetMonitorFrequency(LPDWORD lpdwFrequency); + STDMETHODIMP GetScanLine(LPDWORD lpdwScanLine); + STDMETHODIMP GetVerticalBlankStatus(LPBOOL lpblsInVB); + STDMETHODIMP Initialize(GUID *lpGUID); + STDMETHODIMP RestoreDisplayMode(); + STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags); + STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp); + STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent); +}; + + +// Class that aggregates an IDirectDrawSurface interface + +class CAggDrawSurface : public IDirectDrawSurface, public CUnknown +{ +protected: + + LPDIRECTDRAWSURFACE m_pDirectDrawSurface; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); + + // Constructor and destructor + + CAggDrawSurface(TCHAR *pName,LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDrawSurface(NULL) { }; + + virtual ~CAggDrawSurface() { }; + + // Set the object we should be aggregating + void SetDirectDrawSurface(LPDIRECTDRAWSURFACE pDirectDrawSurface) { + m_pDirectDrawSurface = pDirectDrawSurface; + } + + // IDirectDrawSurface methods + + STDMETHODIMP AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP AddOverlayDirtyRect(LPRECT lpRect); + STDMETHODIMP Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx); + STDMETHODIMP BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags); + STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans); + STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback); + STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback); + STDMETHODIMP Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags); + STDMETHODIMP GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface); + STDMETHODIMP GetBltStatus(DWORD dwFlags); + STDMETHODIMP GetCaps(LPDDSCAPS lpDDSCaps); + STDMETHODIMP GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper); + STDMETHODIMP GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP GetDC(HDC *lphDC); + STDMETHODIMP GetFlipStatus(DWORD dwFlags); + STDMETHODIMP GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY); + STDMETHODIMP GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette); + STDMETHODIMP GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat); + STDMETHODIMP GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP IsLost(); + STDMETHODIMP Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent); + STDMETHODIMP ReleaseDC(HDC hDC); + STDMETHODIMP Restore(); + STDMETHODIMP SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper); + STDMETHODIMP SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY); + STDMETHODIMP SetPalette(LPDIRECTDRAWPALETTE lpDDPalette); + STDMETHODIMP Unlock(LPVOID lpSurfaceData); + STDMETHODIMP UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX); + STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags); + STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference); +}; + + +// DirectShow must work on multiple platforms. In particular, it also runs on +// Windows NT 3.51 which does not have DirectDraw capabilities. The filters +// cannot therefore link statically to the DirectDraw library. To make their +// lives that little bit easier we provide this class that manages loading +// and unloading the library and creating the initial IDirectDraw interface + +typedef DWORD (WINAPI *PGETFILEVERSIONINFOSIZE)(LPTSTR,LPDWORD); +typedef BOOL (WINAPI *PGETFILEVERSIONINFO)(LPTSTR,DWORD,DWORD,LPVOID); +typedef BOOL (WINAPI *PVERQUERYVALUE)(LPVOID,LPTSTR,LPVOID,PUINT); + +class CLoadDirectDraw +{ + LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance + HINSTANCE m_hDirectDraw; // Handle to the loaded library + +public: + + CLoadDirectDraw(); + ~CLoadDirectDraw(); + + HRESULT LoadDirectDraw(LPSTR szDevice); + void ReleaseDirectDraw(); + HRESULT IsDirectDrawLoaded(); + LPDIRECTDRAW GetDirectDraw(); + BOOL IsDirectDrawVersion1(); +}; + +#endif // __VIDEOCTL__ + diff --git a/plugins/gs/gsdx9/baseclasses/vtrans.cpp b/plugins/gs/gsdx9/baseclasses/vtrans.cpp new file mode 100644 index 0000000000..359cd0fbdc --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/vtrans.cpp @@ -0,0 +1,468 @@ +//------------------------------------------------------------------------------ +// File: Vtrans.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include +// #include // now in precomp file streams.h + +CVideoTransformFilter::CVideoTransformFilter + ( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid) + : CTransformFilter(pName, pUnk, clsid) + , m_itrLate(0) + , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames + , m_nFramesSinceKeyFrame(0) + , m_bSkipping(FALSE) + , m_tDecodeStart(0) + , m_itrAvgDecode(300000) // 30mSec - probably allows skipping + , m_bQualityChanged(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + + +CVideoTransformFilter::~CVideoTransformFilter() +{ + // nothing to do +} + + +// Reset our quality management state + +HRESULT CVideoTransformFilter::StartStreaming() +{ + m_itrLate = 0; + m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + m_tDecodeStart = 0; + m_itrAvgDecode = 300000; // 30mSec - probably allows skipping + m_bQualityChanged = FALSE; + m_bSampleSkipped = FALSE; + return NOERROR; +} + + +// Overriden to reset quality management information + +HRESULT CVideoTransformFilter::EndFlush() +{ + { + // Synchronize + CAutoLock lck(&m_csReceive); + + // Reset our stats + // + // Note - we don't want to call derived classes here, + // we only want to reset our internal variables and this + // is a convenient way to do it + CVideoTransformFilter::StartStreaming(); + } + return CTransformFilter::EndFlush(); +} + + +HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) +{ + NotifyEvent(EC_ERRORABORT, hr, 0); + m_pOutput->DeliverEndOfStream(); + return hr; +} + + +// Receive() +// +// Accept a sample from upstream, decide whether to process it +// or drop it. If we process it then get a buffer from the +// allocator of the downstream connection, transform it into the +// new buffer and deliver it to the downstream filter. +// If we decide not to process it then we do not get a buffer. + +// Remember that although this code will notice format changes coming into +// the input pin, it will NOT change its output format if that results +// in the filter needing to make a corresponding output format change. Your +// derived filter will have to take care of that. (eg. a palette change if +// the input and output is an 8 bit format). If the input sample is discarded +// and nothing is sent out for this Receive, please remember to put the format +// change on the first output sample that you actually do send. +// If your filter will produce the same output type even when the input type +// changes, then this base class code will do everything you need. + +HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) +{ + // If the next filter downstream is the video renderer, then it may + // be able to operate in DirectDraw mode which saves copying the data + // and gives higher performance. In that case the buffer which we + // get from GetDeliveryBuffer will be a DirectDraw buffer, and + // drawing into this buffer draws directly onto the display surface. + // This means that any waiting for the correct time to draw occurs + // during GetDeliveryBuffer, and that once the buffer is given to us + // the video renderer will count it in its statistics as a frame drawn. + // This means that any decision to drop the frame must be taken before + // calling GetDeliveryBuffer. + + ASSERT(CritCheckIn(&m_csReceive)); + AM_MEDIA_TYPE *pmtOut, *pmt; +#ifdef DEBUG + FOURCCMap fccOut; +#endif + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output pin to deliver to then no point sending us data + ASSERT (m_pOutput != NULL) ; + + // The source filter may dynamically ask us to start transforming from a + // different media type than the one we're using now. If we don't, we'll + // draw garbage. (typically, this is a palette change in the movie, + // but could be something more sinister like the compression type changing, + // or even the video size changing) + +#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource +#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget + + pSample->GetMediaType(&pmt); + if (pmt != NULL && pmt->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); +#ifdef DEBUG + fccOut.SetFOURCC(&pmt->subtype); + LONG lCompression = HEADER(pmt->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmt->pbFormat)->biHeight, + rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pInput->CurrentMediaType() = *pmt; + DeleteMediaType(pmt); + // if this fails, playback will stop, so signal an error + hr = StartStreaming(); + if (FAILED(hr)) { + return AbortPlayback(hr); + } + } + + // Now that we have noticed any format changes on the input sample, it's + // OK to discard it. + + if (ShouldSkipFrame(pSample)) { + MSR_NOTE(m_idSkip); + m_bSampleSkipped = TRUE; + return NOERROR; + } + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + m_bSampleSkipped = FALSE; + + // The renderer may ask us to on-the-fly to start transforming to a + // different format. If we don't obey it, we'll draw garbage + +#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource +#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget + + pOutSample->GetMediaType(&pmtOut); + if (pmtOut != NULL && pmtOut->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); +#ifdef DEBUG + fccOut.SetFOURCC(&pmtOut->subtype); + LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmtOut->pbFormat)->biHeight, + rcT.left, rcT.top, rcT.right, rcT.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS.left, rcS.top, rcS.right, rcS.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pOutput->CurrentMediaType() = *pmtOut; + DeleteMediaType(pmtOut); + hr = StartStreaming(); + + if (SUCCEEDED(hr)) { + // a new format, means a new empty buffer, so wait for a keyframe + // before passing anything on to the renderer. + // !!! a keyframe may never come, so give up after 30 frames + DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); + m_nWaitForKey = 30; + + // if this fails, playback will stop, so signal an error + } else { + + // Must release the sample before calling AbortPlayback + // because we might be holding the win16 lock or + // ddraw lock + pOutSample->Release(); + AbortPlayback(hr); + return hr; + } + } + + // After a discontinuity, we need to wait for the next key frame + if (pSample->IsDiscontinuity() == S_OK) { + DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); + m_nWaitForKey = 30; + } + + // Start timing the transform (and log it if PERF is defined) + + if (SUCCEEDED(hr)) { + m_tDecodeStart = timeGetTime(); + MSR_START(m_idTransform); + + // have the derived class transform the data + hr = Transform(pSample, pOutSample); + + // Stop the clock (and log it if PERF is defined) + MSR_STOP(m_idTransform); + m_tDecodeStart = timeGetTime()-m_tDecodeStart; + m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); + + // Maybe we're waiting for a keyframe still? + if (m_nWaitForKey) + m_nWaitForKey--; + if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) + m_nWaitForKey = FALSE; + + // if so, then we don't want to pass this on to the renderer + if (m_nWaitForKey && hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); + hr = S_FALSE; + } + } + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + // Try not to return S_FALSE to a direct draw buffer (it's wasteful) + // Try to take the decision earlier - before you get it. + + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this case because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // We must Release() the sample before doing anything + // like calling the filter graph because having the + // sample means we may have the DirectDraw lock + // (== win16 lock on some versions) + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + ASSERT(CritCheckIn(&m_csReceive)); + + return hr; +} + + + +BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) +{ + REFERENCE_TIME trStart, trStopAt; + HRESULT hr = pIn->GetTime(&trStart, &trStopAt); + + // Don't skip frames with no timestamps + if (hr != S_OK) + return FALSE; + + int itrFrame = (int)(trStopAt - trStart); // frame duration + + if(S_OK==pIn->IsSyncPoint()) { + MSR_INTEGER(m_idFrameType, 1); + if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { + // record the max + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + } else { + MSR_INTEGER(m_idFrameType, 2); + if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod + && m_nKeyFramePeriod>0 + ) { + // We haven't seen the key frame yet, but we were clearly being + // overoptimistic about how frequent they are. + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + } + + + // Whatever we might otherwise decide, + // if we are taking only a small fraction of the required frame time to decode + // then any quality problems are actually coming from somewhere else. + // Could be a net problem at the source for instance. In this case there's + // no point in us skipping frames here. + if (m_itrAvgDecode*4>itrFrame) { + + // Don't skip unless we are at least a whole frame late. + // (We would skip B frames if more than 1/2 frame late, but they're safe). + if ( m_itrLate > itrFrame ) { + + // Don't skip unless the anticipated key frame would be no more than + // 1 frame early. If the renderer has not been waiting (we *guess* + // it hasn't because we're late) then it will allow frames to be + // played early by up to a frame. + + // Let T = Stream time from now to anticipated next key frame + // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) + // So we skip if T - Late < one frame i.e. + // (duration) * (freq - FramesSince) - Late < duration + // or (duration) * (freq - FramesSince - 1) < Late + + // We don't dare skip until we have seen some key frames and have + // some idea how often they occur and they are reasonably frequent. + if (m_nKeyFramePeriod>0) { + // It would be crazy - but we could have a stream with key frames + // a very long way apart - and if they are further than about + // 3.5 minutes apart then we could get arithmetic overflow in + // reference time units. Therefore we switch to mSec at this point + int it = (itrFrame/10000) + * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); + MSR_INTEGER(m_idTimeTillKey, it); + + // For debug - might want to see the details - dump them as scratch pad +#ifdef VTRANSPERF + MSR_INTEGER(0, itrFrame); + MSR_INTEGER(0, m_nFramesSinceKeyFrame); + MSR_INTEGER(0, m_nKeyFramePeriod); +#endif + if (m_itrLate/10000 > it) { + m_bSkipping = TRUE; + // Now we are committed. Once we start skipping, we + // cannot stop until we hit a key frame. + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777770); // not near enough to next key +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777771); // Next key not predictable +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777772); // Less than one frame late + MSR_INTEGER(0, m_itrLate); + MSR_INTEGER(0, itrFrame); +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping + MSR_INTEGER(0, m_itrAvgDecode); + MSR_INTEGER(0, itrFrame); +#endif + } + + ++m_nFramesSinceKeyFrame; + + if (m_bSkipping) { + // We will count down the lateness as we skip each frame. + // We re-assess each frame. The key frame might not arrive when expected. + // We reset m_itrLate if we get a new Quality message, but actually that's + // not likely because we're not sending frames on to the Renderer. In + // fact if we DID get another one it would mean that there's a long + // pipe between us and the renderer and we might need an altogether + // better strategy to avoid hunting! + m_itrLate = m_itrLate - itrFrame; + } + + MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are + if (m_bSkipping) { + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + } + return m_bSkipping; +} + + +HRESULT CVideoTransformFilter::AlterQuality(Quality q) +{ + // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. + // +, -, >, == etc are not too bad, but * and / are painful. + if (m_itrLate>300000000) { + // Avoid overflow and silliness - more than 30 secs late is already silly + m_itrLate = 300000000; + } else { + m_itrLate = (int)q.Late; + } + // We ignore the other fields + + // We're actually not very good at handling this. In non-direct draw mode + // most of the time can be spent in the renderer which can skip any frame. + // In that case we'd rather the renderer handled things. + // Nevertheless we will keep an eye on it and if we really start getting + // a very long way behind then we will actually skip - but we'll still tell + // the renderer (or whoever is downstream) that they should handle quality. + + return E_FAIL; // Tell the renderer to do his thing. + +} + + + +// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 +#pragma warning(disable:4514) + diff --git a/plugins/gs/gsdx9/baseclasses/vtrans.h b/plugins/gs/gsdx9/baseclasses/vtrans.h new file mode 100644 index 0000000000..a9c1d6bde1 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/vtrans.h @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// File: VTrans.h +// +// Desc: DirectShow base classes - defines a video transform class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// This class is derived from CTransformFilter, but is specialised to handle +// the requirements of video quality control by frame dropping. +// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. + +class CVideoTransformFilter : public CTransformFilter +{ + public: + + CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); + ~CVideoTransformFilter(); + HRESULT EndFlush(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + // The following methods are in CTransformFilter which is inherited. + // They are mentioned here for completeness + // + // These MUST be supplied in a derived class + // + // NOTE: + // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + // virtual HRESULT CheckTransform + // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + // virtual HRESULT DecideBufferSize + // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; + // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + // + // These MAY also be overridden + // + // virtual HRESULT StopStreaming(); + // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + // virtual HRESULT BreakConnect(PIN_DIRECTION dir); + // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + // virtual HRESULT EndOfStream(void); + // virtual HRESULT BeginFlush(void); + // virtual HRESULT EndFlush(void); + // virtual HRESULT NewSegment + // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); +#ifdef PERF + + // If you override this - ensure that you register all these ids + // as well as any of your own, + virtual void RegisterPerfId() { + m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); + m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); + m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); + m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); + CTransformFilter::RegisterPerfId(); + } +#endif + + protected: + + // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== + // Frames are assumed to come in three types: + // Type 1: an AVI key frame or an MPEG I frame. + // This frame can be decoded with no history. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 1 frames are sync points. + // Type 2: an AVI non-key frame or an MPEG P frame. + // This frame cannot be decoded unless the previous type 1 frame was + // decoded and all type 2 frames since have been decoded. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 3: An MPEG B frame. + // This frame cannot be decoded unless the previous type 1 or 2 frame + // has been decoded AND the subsequent type 1 or 2 frame has also + // been decoded. (This requires decoding the frames out of sequence). + // Dropping this frame affects no other frames. This implementation + // does not allow for these. All non-sync-point frames are treated + // as being type 2. + // + // The spacing of frames of type 1 in a file is not guaranteed. There MUST + // be a type 1 frame at (well, near) the start of the file in order to start + // decoding at all. After that there could be one every half second or so, + // there could be one at the start of each scene (aka "cut", "shot") or + // there could be no more at all. + // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED + // without losing all the rest of the movie. There is no way to tell whether + // this is the case, so we find that we are in the gambling business. + // To try to improve the odds, we record the greatest interval between type 1s + // that we have seen and we bet on things being no worse than this in the + // future. + + // You can tell if it's a type 1 frame by calling IsSyncPoint(). + // there is no architected way to test for a type 3, so you should override + // the quality management here if you have B-frames. + + int m_nKeyFramePeriod; // the largest observed interval between type 1 frames + // 1 means every frame is type 1, 2 means every other. + + int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. + // becomes the new m_nKeyFramePeriod if greater. + + BOOL m_bSkipping; // we are skipping to the next type 1 frame + +#ifdef PERF + int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" + int m_idSkip; // MSR id skipping + int m_idLate; // MSR id lateness + int m_idTimeTillKey; // MSR id for guessed time till next key frame. +#endif + + virtual HRESULT StartStreaming(); + + HRESULT AbortPlayback(HRESULT hr); // if something bad happens + + HRESULT Receive(IMediaSample *pSample); + + HRESULT AlterQuality(Quality q); + + BOOL ShouldSkipFrame(IMediaSample * pIn); + + int m_itrLate; // lateness from last Quality message + // (this overflows at 214 secs late). + int m_tDecodeStart; // timeGetTime when decode started. + int m_itrAvgDecode; // Average decode time in reference units. + + BOOL m_bNoSkip; // debug - no skipping. + + // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. + // We send one when we start degrading, not one for every frame, this means + // we track whether we've sent one yet. + BOOL m_bQualityChanged; + + // When non-zero, don't pass anything to renderer until next keyframe + // If there are few keys, give up and eventually draw something + int m_nWaitForKey; +}; diff --git a/plugins/gs/gsdx9/baseclasses/winctrl.cpp b/plugins/gs/gsdx9/baseclasses/winctrl.cpp new file mode 100644 index 0000000000..d96de70f33 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/winctrl.cpp @@ -0,0 +1,2050 @@ +//------------------------------------------------------------------------------ +// File: WinCtrl.cpp +// +// Desc: DirectShow base classes - implements video control interface class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +// The control interface methods require us to be connected + +#define CheckConnected(pin,code) \ +{ \ + if (pin == NULL) { \ + ASSERT(!TEXT("Pin not set")); \ + } else if (pin->IsConnected() == FALSE) { \ + return (code); \ + } \ +} + +// This checks to see whether the window has a drain. An application can in +// most environments set the owner/parent of windows so that they appear in +// a compound document context (for example). In this case, the application +// would probably like to be told of any keyboard/mouse messages. Therefore +// we pass these messages on untranslated, returning TRUE if we're successful + +BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (hwndDrain != NULL && !InSendMessage()) + { + switch (uMsg) + { + case WM_CHAR: + case WM_DEADCHAR: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEACTIVATE: + case WM_MOUSEMOVE: + // If we pass this on we don't get any mouse clicks + //case WM_NCHITTEST: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMOUSEMOVE: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + + DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain"))); + PostMessage(hwndDrain, uMsg, wParam, lParam); + + return TRUE; + } + } + return FALSE; +} + + +// This class implements the IVideoWindow control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of window related properties such as it's position. +// We also support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlWindow::CBaseControlWindow( + CBaseFilter *pFilter, // Owning filter + CCritSec *pInterfaceLock, // Locking object + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // Normal COM ownership + HRESULT *phr) : // OLE return code + + CBaseVideoWindow(pName,pUnk), + m_pInterfaceLock(pInterfaceLock), + m_hwndOwner(NULL), + m_hwndDrain(NULL), + m_bAutoShow(TRUE), + m_pFilter(pFilter), + m_bCursorHidden(FALSE), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); + m_BorderColour = VIDEO_COLOUR; +} + + +// Set the title caption on the base window, we don't do any field checking +// as we really don't care what title they intend to have. We can always get +// it back again later with GetWindowText. The only other complication is to +// do the necessary string conversions between ANSI and OLE Unicode strings + +STDMETHODIMP CBaseControlWindow::put_Caption(BSTR strCaption) +{ + CheckPointer(strCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); +#ifdef UNICODE + SetWindowText(m_hwnd, strCaption); +#else + CHAR Caption[CAPTION]; + + WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL); + SetWindowText(m_hwnd, Caption); +#endif + return NOERROR; +} + + +// Get the current base window title caption, once again we do no real field +// checking. We allocate a string for the window title to be filled in with +// which ensures the interface doesn't fiddle around with getting memory. A +// BSTR is a normal C string with the length at position (-1), we use the +// WriteBSTR helper function to create the caption to try and avoid OLE32 + +STDMETHODIMP CBaseControlWindow::get_Caption(BSTR *pstrCaption) +{ + CheckPointer(pstrCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + WCHAR WideCaption[CAPTION]; + +#ifdef UNICODE + GetWindowText(m_hwnd,WideCaption,CAPTION); +#else + // Convert the ASCII caption to a UNICODE string + + TCHAR Caption[CAPTION]; + GetWindowText(m_hwnd,Caption,CAPTION); + MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION); +#endif + return WriteBSTR(pstrCaption,WideCaption); +} + + +// Set the window style using GWL_EXSTYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Should we be taking off WS_EX_TOPMOST + + if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) { + if ((WindowStyleEx & WS_EX_TOPMOST) == 0) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0); + } + } + + // Likewise should we be adding WS_EX_TOPMOST + + if (WindowStyleEx & WS_EX_TOPMOST) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0); + WindowStyleEx &= (~WS_EX_TOPMOST); + if (WindowStyleEx == 0) return NOERROR; + } + return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE); +} + + +// Gets the current GWL_EXSTYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(long *pWindowStyleEx) +{ + CheckPointer(pWindowStyleEx,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE); +} + + +// Set the window style using GWL_STYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle) +{ + // These styles cannot be changed dynamically + + if ((WindowStyle & WS_DISABLED) || + (WindowStyle & WS_ICONIC) || + (WindowStyle & WS_MAXIMIZE) || + (WindowStyle & WS_MINIMIZE) || + (WindowStyle & WS_HSCROLL) || + (WindowStyle & WS_VSCROLL)) { + + return E_INVALIDARG; + } + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoSetWindowStyle(WindowStyle,GWL_STYLE); +} + + +// Get the current GWL_STYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyle(long *pWindowStyle) +{ + CheckPointer(pWindowStyle,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyle,GWL_STYLE); +} + + +// Change the base window style or the extended styles depending on whether +// WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have +// the window displayed in it's new style after the change which is a little +// tricky if the window is not currently visible as we realise it offscreen. +// In most cases the client will call get_WindowStyle before they call this +// and then AND and OR in extra bit settings according to the requirements + +HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong) +{ + RECT WindowRect; + + // Get the window's visibility before setting the style + BOOL bVisible = IsWindowVisible(m_hwnd); + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Set the new style flags for the window + SetWindowLong(m_hwnd,WindowLong,Style); + UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE; + WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; + + // Show the window again in the current position + + if (bVisible == TRUE) { + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + return NOERROR; + } + + // Move the window offscreen so the user doesn't see the changes + + MoveWindow((HWND) m_hwnd, // Base window handle + GetSystemMetrics(SM_CXSCREEN), // Current desktop width + GetSystemMetrics(SM_CYSCREEN), // Likewise it's height + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + // Now show the previously hidden window + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + ShowWindow(m_hwnd,SW_HIDE); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + MoveWindow((HWND) m_hwnd, // Base window handle + WindowRect.left, // Existing x coordinate + WindowRect.top, // Existing y coordinate + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + return NOERROR; +} + + +// Get the current base window style (either GWL_STYLE or GWL_EXSTYLE) + +HRESULT CBaseControlWindow::DoGetWindowStyle(long *pStyle,long WindowLong) +{ + *pStyle = GetWindowLong(m_hwnd,WindowLong); + return NOERROR; +} + + +// Change the visibility of the base window, this takes the same parameters +// as the ShowWindow Win32 API does, so the client can have the window hidden +// or shown, minimised to an icon, or maximised to play in full screen mode +// We pass the request on to the base window to actually make the change + +STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + DoShowWindow(WindowState); + return NOERROR; +} + + +// Get the current window state, this function returns a subset of the SW bit +// settings available in ShowWindow, if the window is visible then SW_SHOW is +// set, if it is hidden then the SW_HIDDEN is set, if it is either minimised +// or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The +// other SW bit settings are really set commands not readable output values + +STDMETHODIMP CBaseControlWindow::get_WindowState(long *pWindowState) +{ + CheckPointer(pWindowState,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + ASSERT(pWindowState); + *pWindowState = FALSE; + + // Is the window visible, a window is termed visible if it is somewhere on + // the current desktop even if it is completely obscured by other windows + // so the flag is a style for each window set with the WS_VISIBLE bit + + if (IsWindowVisible(m_hwnd) == TRUE) { + + // Is the base window iconic + if (IsIconic(m_hwnd) == TRUE) { + *pWindowState |= SW_MINIMIZE; + } + + // Has the window been maximised + else if (IsZoomed(m_hwnd) == TRUE) { + *pWindowState |= SW_MAXIMIZE; + } + + // Window is normal + else { + *pWindowState |= SW_SHOW; + } + + } else { + *pWindowState |= SW_HIDE; + } + return NOERROR; +} + + +// This makes sure that any palette we realise in the base window (through a +// media type or through the overlay interface) is done in the background and +// is therefore mapped to existing device entries rather than taking it over +// as it will do when we this window gets the keyboard focus. An application +// uses this to make sure it doesn't have it's palette removed by the window + +STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Check this is a valid automation boolean type + + if (BackgroundPalette != OATRUE) { + if (BackgroundPalette != OAFALSE) { + return E_INVALIDARG; + } + } + + // Make sure the window realises any palette it has again + + m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE); + PostMessage(m_hwnd,m_RealizePalette,0,0); + PaintWindow(FALSE); + + return NOERROR; +} + + +// This returns the current background realisation setting + +STDMETHODIMP +CBaseControlWindow::get_BackgroundPalette(long *pBackgroundPalette) +{ + CheckPointer(pBackgroundPalette,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Get the current background palette setting + + *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the visibility of the base window + +STDMETHODIMP CBaseControlWindow::put_Visible(long Visible) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (Visible != OATRUE) { + if (Visible != OAFALSE) { + return E_INVALIDARG; + } + } + + // Convert the boolean visibility into SW_SHOW and SW_HIDE + + INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE); + DoShowWindow(Mode); + return NOERROR; +} + + +// Return OATRUE if the window is currently visible otherwise OAFALSE + +STDMETHODIMP CBaseControlWindow::get_Visible(long *pVisible) +{ + CheckPointer(pVisible,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // See if the base window has a WS_VISIBLE style - this will return TRUE + // even if the window is completely obscured by other desktop windows, we + // return FALSE if the window is not showing because of earlier calls + + BOOL Mode = IsWindowVisible(m_hwnd); + *pVisible = (Mode == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the left position of the base window. This keeps the window width +// and height properties the same so it effectively shunts the window left or +// right accordingly - there is the Width property to change that dimension + +STDMETHODIMP CBaseControlWindow::put_Left(long Left) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // New left position + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window left position + +STDMETHODIMP CBaseControlWindow::get_Left(long *pLeft) +{ + CheckPointer(pLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pLeft = WindowRect.left; + return NOERROR; +} + + +// Change the current width of the base window. This property complements the +// left position property so we must keep the left edge constant and expand or +// contract to the right, the alternative would be to change the left edge so +// keeping the right edge constant but this is maybe a little more intuitive + +STDMETHODIMP CBaseControlWindow::put_Width(long Width) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + // This seems to have a bug in that calling SetWindowPos on a window with + // just the width changing causes it to ignore the width that you pass in + // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51) + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + Width, // New WIDTH dimension + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window width + +STDMETHODIMP CBaseControlWindow::get_Width(long *pWidth) +{ + CheckPointer(pWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pWidth = WindowRect.right - WindowRect.left; + return NOERROR; +} + + +// This allows the client program to change the top position for the window in +// the same way that changing the left position does not affect the width of +// the image so changing the top position does not affect the window height + +STDMETHODIMP CBaseControlWindow::put_Top(long Top) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + Top, // New top position + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window top position + +STDMETHODIMP CBaseControlWindow::get_Top(long *pTop) +{ + CheckPointer(pTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pTop = WindowRect.top; + return NOERROR; +} + + +// Change the height of the window, this complements the top property so when +// we change this we must keep the top position for the base window, as said +// before we could keep the bottom and grow upwards although this is perhaps +// a little more intuitive since we already have a top position property + +STDMETHODIMP CBaseControlWindow::put_Height(long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + Height, // New height dimension + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window height + +STDMETHODIMP CBaseControlWindow::get_Height(long *pHeight) +{ + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pHeight = WindowRect.bottom - WindowRect.top; + return NOERROR; +} + + +// This can be called to change the owning window. Setting the owner is done +// through this function, however to make the window a true child window the +// style must also be set to WS_CHILD. After resetting the owner to NULL an +// application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN. + +// We cannot lock the object here because the SetParent causes an interthread +// SendMessage to the owner window. If they are in GetState we will sit here +// incomplete with the critical section locked therefore blocking out source +// filter threads from accessing us. Because the source thread can't enter us +// it can't get buffers or call EndOfStream so the GetState will not complete + +STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndOwner = (HWND) Owner; + HWND hwndParent = m_hwndOwner; + + // Add or remove WS_CHILD as appropriate + + LONG Style = GetWindowLong(m_hwnd,GWL_STYLE); + if (Owner == NULL) { + Style &= (~WS_CHILD); + } else { + Style |= (WS_CHILD); + } + SetWindowLong(m_hwnd,GWL_STYLE,Style); + + // Don't call this with the filter locked + + SetParent(m_hwnd,hwndParent); + + PaintWindow(TRUE); + NOTE1("Changed parent %lx",hwndParent); + + return NOERROR; +} + + +// This complements the put_Owner to get the current owning window property +// we always return NOERROR although the returned window handle may be NULL +// to indicate no owning window (the desktop window doesn't qualify as one) +// If an application sets the owner we call SetParent, however that returns +// NULL until the WS_CHILD bit is set on, so we store the owner internally + +STDMETHODIMP CBaseControlWindow::get_Owner(OAHWND *Owner) +{ + CheckPointer(Owner,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Owner = (OAHWND) m_hwndOwner; + return NOERROR; +} + + +// And renderer supporting IVideoWindow may have an HWND set who will get any +// keyboard and mouse messages we receive posted on to them. This is separate +// from setting an owning window. By separating the two, applications may get +// messages sent on even when they have set no owner (perhaps it's maximised) + +STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndDrain = (HWND) Drain; + return NOERROR; +} + + +// Return the current message drain + +STDMETHODIMP CBaseControlWindow::get_MessageDrain(OAHWND *Drain) +{ + CheckPointer(Drain,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Drain = (OAHWND) m_hwndDrain; + return NOERROR; +} + + +// This is called by the filter graph to inform us of a message we should know +// is being sent to our owning window. We have this because as a child window +// we do not get certain messages that are only sent to top level windows. We +// must see the palette changed/changing/query messages so that we know if we +// have the foreground palette or not. We pass the message on to our window +// using SendMessage - this will cause an interthread send message to occur + +STDMETHODIMP +CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle + long uMsg, // Message ID + LONG_PTR wParam, // Parameters + LONG_PTR lParam) // for message +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Only interested in these Windows messages + + switch (uMsg) { + + case WM_SYSCOLORCHANGE: + case WM_PALETTECHANGED: + case WM_PALETTEISCHANGING: + case WM_QUERYNEWPALETTE: + case WM_DEVMODECHANGE: + case WM_DISPLAYCHANGE: + case WM_ACTIVATEAPP: + + // If we do not have an owner then ignore + + if (m_hwndOwner == NULL) { + return NOERROR; + } + SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); + break; + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + PostMessage(m_hwnd,WM_PAINT,0,0); + break; + } + return NOERROR; +} + + +// Allow an application to have us set the base window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. We ask the base window class to do the real work + +STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus) +{ + // Check this is a valid automation boolean type + + if (Focus != OATRUE) { + if (Focus != OAFALSE) { + return E_INVALIDARG; + } + } + + // We shouldn't lock as this sends a message + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE); + DoSetWindowForeground(bFocus); + + return NOERROR; +} + + +// This allows a client to set the complete window size and position in one +// atomic operation. The same affect can be had by changing each dimension +// in turn through their individual properties although some flashing will +// occur as each of them gets updated (they are better set at design time) + +STDMETHODIMP +CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + + // Set the new size and position + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + ASSERT(IsWindow(m_hwnd)); + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // Left position + Top, // Top position + Width, // Window width + Height, // Window height + WindowFlags); // Show window flags + ASSERT(bSuccess); +#ifdef DEBUG + DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError())); +#endif + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// This complements the SetWindowPosition to return the current window place +// in device coordinates. As before the same information can be retrived by +// calling the property get functions individually but this is atomic and is +// therefore more suitable to a live environment rather than design time + +STDMETHODIMP +CBaseControlWindow::GetWindowPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + // Get the current window coordinates + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Convert the RECT into left,top,width and height values + + *pLeft = WindowRect.left; + *pTop = WindowRect.top; + *pWidth = WindowRect.right - WindowRect.left; + *pHeight = WindowRect.bottom - WindowRect.top; + + return NOERROR; +} + + +// When a window is maximised or iconic calling GetWindowPosition will return +// the current window position (likewise for the properties). However if the +// restored size (ie the size we'll return to when normally shown) is needed +// then this should be used. When in a normal position (neither iconic nor +// maximised) then this returns the same coordinates as GetWindowPosition + +STDMETHODIMP +CBaseControlWindow::GetRestorePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Use GetWindowPlacement to find the restore position + + WINDOWPLACEMENT Place; + Place.length = sizeof(WINDOWPLACEMENT); + EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place)); + + RECT WorkArea; + + // We must take into account any task bar present + + if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) { + if (GetParent(m_hwnd) == NULL) { + Place.rcNormalPosition.top += WorkArea.top; + Place.rcNormalPosition.bottom += WorkArea.top; + Place.rcNormalPosition.left += WorkArea.left; + Place.rcNormalPosition.right += WorkArea.left; + } + } + + // Convert the RECT into left,top,width and height values + + *pLeft = Place.rcNormalPosition.left; + *pTop = Place.rcNormalPosition.top; + *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left; + *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top; + + return NOERROR; +} + + +// Return the current border colour, if we are playing something to a subset +// of the base window display there is an outside area exposed. The default +// action is to paint this colour in the Windows background colour (defined +// as value COLOR_WINDOW) We reset to this default when we're disconnected + +STDMETHODIMP CBaseControlWindow::get_BorderColor(long *Color) +{ + CheckPointer(Color,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Color = (long) m_BorderColour; + return NOERROR; +} + + +// This can be called to set the current border colour + +STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Have the window repainted with the new border colour + + m_BorderColour = (COLORREF) Color; + PaintWindow(TRUE); + return NOERROR; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::get_FullScreenMode(long *FullScreenMode) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CheckPointer(FullScreenMode,E_POINTER); + return E_NOTIMPL; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode) +{ + return E_NOTIMPL; +} + + +// This sets the auto show property, this property causes the base window to +// be displayed whenever we change state. This allows an application to have +// to do nothing to have the window appear but still allow them to change the +// default behaviour if for example they want to keep it hidden for longer + +STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (AutoShow != OATRUE) { + if (AutoShow != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// This can be called to get the current auto show flag. The flag is updated +// when we connect and disconnect and through this interface all of which are +// controlled and serialised by means of the main renderer critical section + +STDMETHODIMP CBaseControlWindow::get_AutoShow(long *AutoShow) +{ + CheckPointer(AutoShow,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Return the minimum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a minimum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMinIdealImageSize(long *pWidth,long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Return the maximum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a maximum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMaxIdealImageSize(long *pWidth,long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Allow an application to hide the cursor on our window + +STDMETHODIMP +CBaseControlWindow::HideCursor(long HideCursor) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (HideCursor != OATRUE) { + if (HideCursor != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// Returns whether we have the cursor hidden or not + +STDMETHODIMP CBaseControlWindow::IsCursorHidden(long *CursorHidden) +{ + CheckPointer(CursorHidden,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// This class implements the IBasicVideo control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of video related properties such as the native video +// size. We support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlVideo::CBaseControlVideo( + CBaseFilter *pFilter, // Owning filter + CCritSec *pInterfaceLock, // Locking object + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // Normal COM ownership + HRESULT *phr) : // OLE return code + + CBaseBasicVideo(pName,pUnk), + m_pFilter(pFilter), + m_pInterfaceLock(pInterfaceLock), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); +} + +// Return an approximate average time per frame + +STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(REFTIME *pAvgTimePerFrame) +{ + CheckPointer(pAvgTimePerFrame,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + COARefTime AvgTime(pVideoInfo->AvgTimePerFrame); + *pAvgTimePerFrame = (REFTIME) AvgTime; + + return NOERROR; +} + + +// Return an approximate bit rate for the video + +STDMETHODIMP CBaseControlVideo::get_BitRate(long *pBitRate) +{ + CheckPointer(pBitRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitRate = pVideoInfo->dwBitRate; + return NOERROR; +} + + +// Return an approximate bit error rate + +STDMETHODIMP CBaseControlVideo::get_BitErrorRate(long *pBitErrorRate) +{ + CheckPointer(pBitErrorRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitErrorRate = pVideoInfo->dwBitErrorRate; + return NOERROR; +} + + +// This returns the current video width + +STDMETHODIMP CBaseControlVideo::get_VideoWidth(long *pVideoWidth) +{ + CheckPointer(pVideoWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoWidth = pVideoInfo->bmiHeader.biWidth; + return NOERROR; +} + + +// This returns the current video height + +STDMETHODIMP CBaseControlVideo::get_VideoHeight(long *pVideoHeight) +{ + CheckPointer(pVideoHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// This returns the current palette the video is using as an array allocated +// by the user. To remain consistent we use PALETTEENTRY fields to return the +// colours in rather than RGBQUADs that multimedia decided to use. The memory +// is allocated by the user so we simple copy each in turn. We check that the +// number of entries requested and the start position offset are both valid +// If the number of entries evaluates to zero then we return an S_FALSE code + +STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex, + long Entries, + long *pRetrieved, + long *pPalette) +{ + CheckPointer(pRetrieved,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + CMediaType MediaType; + + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + // Is the current format palettised + + if (PALETTISED(pVideoInfo) == FALSE) { + *pRetrieved = 0; + return VFW_E_NO_PALETTE_AVAILABLE; + } + + // Do they just want to know how many are available + + if (pPalette == NULL) { + *pRetrieved = pHeader->biClrUsed; + return NOERROR; + } + + // Make sure the start position is a valid offset + + if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) { + *pRetrieved = 0; + return E_INVALIDARG; + } + + // Correct the number we can retrieve + + LONG Available = (LONG) pHeader->biClrUsed - StartIndex; + *pRetrieved = max(0,min(Available,Entries)); + if (*pRetrieved == 0) { + return S_FALSE; + } + + // Copy the palette entries to the output buffer + + PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette; + RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex; + + for (LONG Count = 0;Count < *pRetrieved;Count++) { + pEntries[Count].peRed = pColours[Count].rgbRed; + pEntries[Count].peGreen = pColours[Count].rgbGreen; + pEntries[Count].peBlue = pColours[Count].rgbBlue; + pEntries[Count].peFlags = 0; + } + return NOERROR; +} + + +// This returns the current video dimensions as a method rather than a number +// of individual property get calls. For the same reasons as said before we +// cannot access the renderer media type directly as the window object thread +// may be updating it since dynamic format changes may change these values + +STDMETHODIMP CBaseControlVideo::GetVideoSize(long *pWidth,long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + // Get the video format from the derived class + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pWidth = pVideoInfo->bmiHeader.biWidth; + *pHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// Set the source video rectangle as left,top,right and bottom coordinates +// rather than left,top,width and height as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the source + +STDMETHODIMP +CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + SourceRect.left = Left; + SourceRect.top = Top; + SourceRect.right = Left + Width; + SourceRect.bottom = Top + Height; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the source rectangle in left,top,width and height rather than the +// left,top,right and bottom values that RECT uses (and which the window +// object returns through GetSourceRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetSourcePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight) +{ + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT SourceRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetSourceRect(&SourceRect); + + *pLeft = SourceRect.left; + *pTop = SourceRect.top; + *pWidth = WIDTH(&SourceRect); + *pHeight = HEIGHT(&SourceRect); + + return NOERROR; +} + + +// Set the video destination as left,top,right and bottom coordinates rather +// than the left,top,width and height uses as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the destination + +STDMETHODIMP +CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + DestinationRect.left = Left; + DestinationRect.top = Top; + DestinationRect.right = Left + Width; + DestinationRect.bottom = Top + Height; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the destination rectangle in left,top,width and height rather than +// the left,top,right and bottom values that RECT uses (and which the window +// object returns through GetDestinationRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetDestinationPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT DestinationRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetTargetRect(&DestinationRect); + + *pLeft = DestinationRect.left; + *pTop = DestinationRect.top; + *pWidth = WIDTH(&DestinationRect); + *pHeight = HEIGHT(&DestinationRect); + + return NOERROR; +} + + +// Set the source left position, the source rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceLeft + WIDTH(&SourceRect); + SourceRect.left = SourceLeft; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current left source video position + +STDMETHODIMP CBaseControlVideo::get_SourceLeft(long *pSourceLeft) +{ + CheckPointer(pSourceLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceLeft = SourceRect.left; + return NOERROR; +} + + +// Set the source width, we get the current source rectangle and then update +// the right position to be the left position (thereby keeping it constant) +// plus the new source width we are passed in (it expands to the right) + +STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceRect.left + SourceWidth; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source width + +STDMETHODIMP CBaseControlVideo::get_SourceWidth(long *pSourceWidth) +{ + CheckPointer(pSourceWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceWidth = WIDTH(&SourceRect); + return NOERROR; +} + + +// Set the source top position - changing this property does not affect the +// current source height. So changing this shunts the source rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the source height + +STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceTop + HEIGHT(&SourceRect); + SourceRect.top = SourceTop; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current top position + +STDMETHODIMP CBaseControlVideo::get_SourceTop(long *pSourceTop) +{ + CheckPointer(pSourceTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceTop = SourceRect.top; + return NOERROR; +} + + +// Set the source height + +STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceRect.top + SourceHeight; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source height + +STDMETHODIMP CBaseControlVideo::get_SourceHeight(long *pSourceHeight) +{ + CheckPointer(pSourceHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceHeight = HEIGHT(&SourceRect); + return NOERROR; +} + + +// Set the target left position, the target rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect); + DestinationRect.left = DestinationLeft; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the left position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationLeft(long *pDestinationLeft) +{ + CheckPointer(pDestinationLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationLeft = DestinationRect.left; + return NOERROR; +} + + +// Set the destination width + +STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationRect.left + DestinationWidth; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the width for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationWidth(long *pDestinationWidth) +{ + CheckPointer(pDestinationWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationWidth = WIDTH(&DestinationRect); + return NOERROR; +} + + +// Set the target top position - changing this property does not affect the +// current target height. So changing this shunts the target rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the target height + +STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect); + DestinationRect.top = DestinationTop; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the top position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationTop(long *pDestinationTop) +{ + CheckPointer(pDestinationTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationTop = DestinationRect.top; + return NOERROR; +} + + +// Set the destination height + +STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationRect.top + DestinationHeight; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the height for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationHeight(long *pDestinationHeight) +{ + CheckPointer(pDestinationHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationHeight = HEIGHT(&DestinationRect); + return NOERROR; +} + + +// Reset the source rectangle to the full video dimensions + +STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultSourceRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default source otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultSourceRect(); +} + + +// Reset the video renderer to use the entire playback area + +STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultTargetRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default target otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultTargetRect(); +} + + +// Return a copy of the current image in the video renderer + +STDMETHODIMP +CBaseControlVideo::GetCurrentImage(long *pBufferSize,long *pVideoImage) +{ + CheckPointer(pBufferSize,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + FILTER_STATE State; + + // Make sure we are in a paused state + + if (pVideoImage != NULL) { + m_pFilter->GetState(0,&State); + if (State != State_Paused) { + return VFW_E_NOT_PAUSED; + } + return GetStaticImage(pBufferSize,pVideoImage); + } + + // Just return the memory required + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + RECT SourceRect; + GetSourceRect(&SourceRect); + return GetImageSize(pVideoInfo,pBufferSize,&SourceRect); +} + + +// An application has two ways of using GetCurrentImage, one is to pass a real +// buffer which should be filled with the current image. The other is to pass +// a NULL buffer pointer which is interpreted as asking us to return how much +// memory is required for the image. The constraints for when the latter can +// be called are much looser. To calculate the memory required we synthesize +// a VIDEOINFO that takes into account the source rectangle that's being used + +HRESULT CBaseControlVideo::GetImageSize(VIDEOINFOHEADER *pVideoInfo, + LONG *pBufferSize, + RECT *pSourceRect) +{ + NOTE("Entering GetImageSize"); + ASSERT(pSourceRect); + + // Check we have the correct input parameters + + if (pSourceRect == NULL || + pVideoInfo == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + LONG Size = DIBSIZE(bih); + Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + *pBufferSize = Size; + + return NOERROR; +} + + +// Given an IMediaSample containing a linear buffer with an image and a type +// describing the bitmap make a rendering of the image into the output buffer +// This may be called by derived classes who render typical video images to +// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may +// be NULL when passed to GetCurrentImage in which case GetImageSize will be +// called instead, which will just do the calculation of the memory required + +HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample, + VIDEOINFOHEADER *pVideoInfo, + LONG *pBufferSize, + BYTE *pVideoImage, + RECT *pSourceRect) +{ + NOTE("Entering CopyImage"); + ASSERT(pSourceRect); + BYTE *pCurrentImage; + + // Check we have an image to copy + + if (pMediaSample == NULL || pSourceRect == NULL || + pVideoInfo == NULL || pVideoImage == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + LONG Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + LONG Total = Size + DIBSIZE(bih); + + // Make sure we have a large enough buffer + + if (*pBufferSize < Total) { + return E_OUTOFMEMORY; + } + + // Copy the BITMAPINFO + + CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size); + ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih); + BYTE *pImageData = pVideoImage + Size; + + // Get the pointer to it's image data + + HRESULT hr = pMediaSample->GetPointer(&pCurrentImage); + if (FAILED(hr)) { + return hr; + } + + // Now we are ready to start copying the source scan lines + + LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect); + LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight; + LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect); + pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader); + pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8); + + // Even money on this GP faulting sometime... + + for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) { + CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine); + pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage); + pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Called when we change media types either during connection or dynamically +// We inform the filter graph and therefore the application that the video +// size may have changed, we don't bother looking to see if it really has as +// we leave that to the application - the dimensions are the event parameters + +HRESULT CBaseControlVideo::OnVideoSizeChange() +{ + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth; + WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight; + + return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED, + MAKELPARAM(Width,Height), + MAKEWPARAM(0,0)); +} + + +// Set the video source rectangle. We must check the source rectangle against +// the actual video dimensions otherwise when we come to draw the pictures we +// get access violations as GDI tries to touch data outside of the image data +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckSourceRect(RECT *pSourceRect) +{ + CheckPointer(pSourceRect,E_POINTER); + LONG Width,Height; + GetVideoSize(&Width,&Height); + + // Check the coordinates are greater than zero + // and that the rectangle is valid (leftleft >= pSourceRect->right) || + (pSourceRect->left < 0) || + (pSourceRect->top >= pSourceRect->bottom) || + (pSourceRect->top < 0)) { + + return E_INVALIDARG; + } + + // Check the coordinates are less than the extents + + if ((pSourceRect->right > Width) || + (pSourceRect->bottom > Height)) { + + return E_INVALIDARG; + } + return NOERROR; +} + + +// Check the target rectangle has some valid coordinates, which amounts to +// little more than checking the destination rectangle isn't empty. Derived +// classes may call this when they have their SetTargetRect method called to +// check the rectangle validity, we do not update the rectangles passed in +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckTargetRect(RECT *pTargetRect) +{ + // Check the pointer is valid + + if (pTargetRect == NULL) { + return E_POINTER; + } + + // These overflow the WIDTH and HEIGHT checks + + if (pTargetRect->left > pTargetRect->right || + pTargetRect->top > pTargetRect->bottom) { + return E_INVALIDARG; + } + + // Check the rectangle has valid coordinates + + if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) { + return E_INVALIDARG; + } + + ASSERT(IsRectEmpty(pTargetRect) == FALSE); + return NOERROR; +} + diff --git a/plugins/gs/gsdx9/baseclasses/winctrl.h b/plugins/gs/gsdx9/baseclasses/winctrl.h new file mode 100644 index 0000000000..c3e18dae51 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/winctrl.h @@ -0,0 +1,224 @@ +//------------------------------------------------------------------------------ +// File: WinCtrl.h +// +// Desc: DirectShow base classes - defines classes for video control +// interfaces. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WINCTRL__ +#define __WINCTRL__ + +#define ABSOL(x) (x < 0 ? -x : x) +#define NEGAT(x) (x > 0 ? -x : x) + +// Helper +BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + COLORREF m_BorderColour; // Current window border colour + BOOL m_bAutoShow; // What happens when the state changes + HWND m_hwndOwner; // Owner window that we optionally have + HWND m_hwndDrain; // HWND to post any messages received + BOOL m_bCursorHidden; // Should we hide the window cursor + +public: + + // Internal methods for other objects to get information out + + HRESULT DoSetWindowStyle(long Style,long WindowLong); + HRESULT DoGetWindowStyle(long *pStyle,long WindowLong); + BOOL IsAutoShowEnabled() { return m_bAutoShow; }; + COLORREF GetBorderColour() { return m_BorderColour; }; + HWND GetOwnerWindow() { return m_hwndOwner; }; + BOOL IsCursorHidden() { return m_bCursorHidden; }; + + inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam); + } + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlWindowPin(CBasePin *pPin) { + m_pPin = pPin; + } + +public: + + CBaseControlWindow(CBaseFilter *pFilter, // Owning media filter + CCritSec *pInterfaceLock, // Locking object + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // Normal COM ownership + HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP put_Caption(BSTR strCaption); + STDMETHODIMP get_Caption(BSTR *pstrCaption); + STDMETHODIMP put_AutoShow(long AutoShow); + STDMETHODIMP get_AutoShow(long *AutoShow); + STDMETHODIMP put_WindowStyle(long WindowStyle); + STDMETHODIMP get_WindowStyle(long *pWindowStyle); + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); + STDMETHODIMP get_WindowStyleEx(long *pWindowStyleEx); + STDMETHODIMP put_WindowState(long WindowState); + STDMETHODIMP get_WindowState(long *pWindowState); + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); + STDMETHODIMP get_BackgroundPalette(long *pBackgroundPalette); + STDMETHODIMP put_Visible(long Visible); + STDMETHODIMP get_Visible(long *pVisible); + STDMETHODIMP put_Left(long Left); + STDMETHODIMP get_Left(long *pLeft); + STDMETHODIMP put_Width(long Width); + STDMETHODIMP get_Width(long *pWidth); + STDMETHODIMP put_Top(long Top); + STDMETHODIMP get_Top(long *pTop); + STDMETHODIMP put_Height(long Height); + STDMETHODIMP get_Height(long *pHeight); + STDMETHODIMP put_Owner(OAHWND Owner); + STDMETHODIMP get_Owner(OAHWND *Owner); + STDMETHODIMP put_MessageDrain(OAHWND Drain); + STDMETHODIMP get_MessageDrain(OAHWND *Drain); + STDMETHODIMP get_BorderColor(long *Color); + STDMETHODIMP put_BorderColor(long Color); + STDMETHODIMP get_FullScreenMode(long *FullScreenMode); + STDMETHODIMP put_FullScreenMode(long FullScreenMode); + + // And these are the methods + + STDMETHODIMP SetWindowForeground(long Focus); + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam); + STDMETHODIMP GetMinIdealImageSize(long *pWidth,long *pHeight); + STDMETHODIMP GetMaxIdealImageSize(long *pWidth,long *pHeight); + STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetWindowPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight); + STDMETHODIMP GetRestorePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight); + STDMETHODIMP HideCursor(long HideCursor); + STDMETHODIMP IsCursorHidden(long *CursorHidden); +}; + +// This class implements the IBasicVideo interface + +class CBaseControlVideo : public CBaseBasicVideo +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + +public: + + // Derived classes must provide these for the implementation + + virtual HRESULT IsDefaultTargetRect() PURE; + virtual HRESULT SetDefaultTargetRect() PURE; + virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT IsDefaultSourceRect() PURE; + virtual HRESULT SetDefaultSourceRect() PURE; + virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetStaticImage(long *pBufferSize,long *pDIBImage) PURE; + + // Derived classes must override this to return a VIDEOINFO representing + // the video format. We cannot call IPin ConnectionMediaType to get this + // format because various filters dynamically change the type when using + // DirectDraw such that the format shows the position of the logical + // bitmap in a frame buffer surface, so the size might be returned as + // 1024x768 pixels instead of 320x240 which is the real video dimensions + + virtual VIDEOINFOHEADER *GetVideoFormat() PURE; + + // Helper functions for creating memory renderings of a DIB image + + HRESULT GetImageSize(VIDEOINFOHEADER *pVideoInfo, + LONG *pBufferSize, + RECT *pSourceRect); + + HRESULT CopyImage(IMediaSample *pMediaSample, + VIDEOINFOHEADER *pVideoInfo, + LONG *pBufferSize, + BYTE *pVideoImage, + RECT *pSourceRect); + + // Override this if you want notifying when the rectangles change + virtual HRESULT OnUpdateRectangles() { return NOERROR; }; + virtual HRESULT OnVideoSizeChange(); + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlVideoPin(CBasePin *pPin) { + m_pPin = pPin; + } + + // Helper methods for checking rectangles + virtual HRESULT CheckSourceRect(RECT *pSourceRect); + virtual HRESULT CheckTargetRect(RECT *pTargetRect); + +public: + + CBaseControlVideo(CBaseFilter *pFilter, // Owning media filter + CCritSec *pInterfaceLock, // Serialise interface + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // Normal COM ownership + HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP get_AvgTimePerFrame(REFTIME *pAvgTimePerFrame); + STDMETHODIMP get_BitRate(long *pBitRate); + STDMETHODIMP get_BitErrorRate(long *pBitErrorRate); + STDMETHODIMP get_VideoWidth(long *pVideoWidth); + STDMETHODIMP get_VideoHeight(long *pVideoHeight); + STDMETHODIMP put_SourceLeft(long SourceLeft); + STDMETHODIMP get_SourceLeft(long *pSourceLeft); + STDMETHODIMP put_SourceWidth(long SourceWidth); + STDMETHODIMP get_SourceWidth(long *pSourceWidth); + STDMETHODIMP put_SourceTop(long SourceTop); + STDMETHODIMP get_SourceTop(long *pSourceTop); + STDMETHODIMP put_SourceHeight(long SourceHeight); + STDMETHODIMP get_SourceHeight(long *pSourceHeight); + STDMETHODIMP put_DestinationLeft(long DestinationLeft); + STDMETHODIMP get_DestinationLeft(long *pDestinationLeft); + STDMETHODIMP put_DestinationWidth(long DestinationWidth); + STDMETHODIMP get_DestinationWidth(long *pDestinationWidth); + STDMETHODIMP put_DestinationTop(long DestinationTop); + STDMETHODIMP get_DestinationTop(long *pDestinationTop); + STDMETHODIMP put_DestinationHeight(long DestinationHeight); + STDMETHODIMP get_DestinationHeight(long *pDestinationHeight); + + // And these are the methods + + STDMETHODIMP GetVideoSize(long *pWidth,long *pHeight); + STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetSourcePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight); + STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,long *pRetrieved,long *pPalette); + STDMETHODIMP SetDefaultSourcePosition(); + STDMETHODIMP IsUsingDefaultSource(); + STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetDestinationPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight); + STDMETHODIMP SetDefaultDestinationPosition(); + STDMETHODIMP IsUsingDefaultDestination(); + STDMETHODIMP GetCurrentImage(long *pBufferSize,long *pVideoImage); +}; + +#endif // __WINCTRL__ + diff --git a/plugins/gs/gsdx9/baseclasses/winutil.cpp b/plugins/gs/gsdx9/baseclasses/winutil.cpp new file mode 100644 index 0000000000..1526828538 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/winutil.cpp @@ -0,0 +1,2681 @@ +//------------------------------------------------------------------------------ +// File: WinUtil.cpp +// +// Desc: DirectShow base classes - implements generic window handler class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include +#include +#include + +static UINT MsgDestroy; + +// Constructor + +CBaseWindow::CBaseWindow(BOOL bDoGetDC, bool bDoPostToDestroy) : + m_hInstance(g_hInst), + m_hwnd(NULL), + m_hdc(NULL), + m_bActivated(FALSE), + m_pClassName(NULL), + m_ClassStyles(0), + m_WindowStyles(0), + m_WindowStylesEx(0), + m_ShowStageMessage(0), + m_ShowStageTop(0), + m_MemoryDC(NULL), + m_hPalette(NULL), + m_bBackground(FALSE), +#ifdef DEBUG + m_bRealizing(FALSE), +#endif + m_bNoRealize(FALSE), + m_bDoPostToDestroy(bDoPostToDestroy) +{ + m_bDoGetDC = bDoGetDC; +} + + +// Prepare a window by spinning off a worker thread to do the creation and +// also poll the message input queue. We leave this to be called by derived +// classes because they might want to override methods like MessageLoop and +// InitialiseWindow, if we do this during construction they'll ALWAYS call +// this base class methods. We make the worker thread create the window so +// it owns it rather than the filter graph thread which is constructing us + +HRESULT CBaseWindow::PrepareWindow() +{ + if (m_hwnd) return NOERROR; + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); + + // Get the derived object's window and class styles + + m_pClassName = GetClassWindowStyles(&m_ClassStyles, + &m_WindowStyles, + &m_WindowStylesEx); + if (m_pClassName == NULL) { + return E_FAIL; + } + + // Register our special private messages + m_ShowStageMessage = RegisterWindowMessage(SHOWSTAGE); + + // RegisterWindowMessage() returns 0 if an error occurs. + if (0 == m_ShowStageMessage) { + return AmGetLastErrorToHResult(); + } + + m_ShowStageTop = RegisterWindowMessage(SHOWSTAGETOP); + if (0 == m_ShowStageTop) { + return AmGetLastErrorToHResult(); + } + + m_RealizePalette = RegisterWindowMessage(REALIZEPALETTE); + if (0 == m_RealizePalette) { + return AmGetLastErrorToHResult(); + } + + MsgDestroy = RegisterWindowMessage(TEXT("AM_DESTROY")); + if (0 == MsgDestroy) { + return AmGetLastErrorToHResult(); + } + + return DoCreateWindow(); +} + + +// Destructor just a placeholder so that we know it becomes virtual +// Derived classes MUST call DoneWithWindow in their destructors so +// that no messages arrive after the derived class constructor ends + +#ifdef DEBUG +CBaseWindow::~CBaseWindow() +{ + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); +} +#endif + + +// We use the sync worker event to have the window destroyed. All we do is +// signal the event and wait on the window thread handle. Trying to send it +// messages causes too many problems, furthermore to be on the safe side we +// just wait on the thread handle while it returns WAIT_TIMEOUT or there is +// a sent message to process on this thread. If the constructor failed to +// create the thread in the first place then the loop will get terminated + +HRESULT CBaseWindow::DoneWithWindow() +{ + if (!IsWindow(m_hwnd) || (GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId())) { + + if (IsWindow(m_hwnd)) { + + if (m_bDoPostToDestroy) { + + CAMEvent m_evDone; + + // We must post a message to destroy the window + // That way we can't be in the middle of processing a + // message posted to our window when we do go away + // Sending a message gives less synchronization. + PostMessage(m_hwnd, MsgDestroy, (WPARAM)(HANDLE)m_evDone, 0); + WaitDispatchingMessages(m_evDone, INFINITE); + } else { + SendMessage(m_hwnd, MsgDestroy, 0, 0); + } + } + + // + // This is not a leak, the window manager automatically free's + // hdc's that were got via GetDC, which is the case here. + // We set it to NULL so that we don't get any asserts later. + // + m_hdc = NULL; + + // + // We need to free this DC though because USER32 does not know + // anything about it. + // + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; + } + const HWND hwnd = m_hwnd; + if (hwnd == NULL) { + return NOERROR; + } + + InactivateWindow(); + NOTE("Inactivated"); + + // Reset the window styles before destruction + + SetWindowLong(hwnd,GWL_STYLE,m_WindowStyles); + ASSERT(GetParent(hwnd) == NULL); + NOTE1("Reset window styles %d",m_WindowStyles); + + // UnintialiseWindow sets m_hwnd to NULL so save a copy + UninitialiseWindow(); + DbgLog((LOG_TRACE, 2, TEXT("Destroying 0x%8.8X"), hwnd)); + if (!DestroyWindow(hwnd)) { + DbgLog((LOG_TRACE, 0, TEXT("DestroyWindow %8.8X failed code %d"), + hwnd, GetLastError())); + DbgBreak(""); + } + + // Reset our state so we can be prepared again + + m_pClassName = NULL; + m_ClassStyles = 0; + m_WindowStyles = 0; + m_WindowStylesEx = 0; + m_ShowStageMessage = 0; + m_ShowStageTop = 0; + + return NOERROR; +} + + +// Called at the end to put the window in an inactive state. The pending list +// will always have been cleared by this time so event if the worker thread +// gets has been signaled and gets in to render something it will find both +// the state has been changed and that there are no available sample images +// Since we wait on the window thread to complete we don't lock the object + +HRESULT CBaseWindow::InactivateWindow() +{ + // Has the window been activated + if (m_bActivated == FALSE) { + return S_FALSE; + } + + m_bActivated = FALSE; + ShowWindow(m_hwnd,SW_HIDE); + return NOERROR; +} + + +HRESULT CBaseWindow::CompleteConnect() +{ + m_bActivated = FALSE; + return NOERROR; +} + +// This displays a normal window. We ask the base window class for default +// sizes which unless overriden will return DEFWIDTH and DEFHEIGHT. We go +// through a couple of extra hoops to get the client area the right size +// as the object specifies which accounts for the AdjustWindowRectEx calls +// We also DWORD align the left and top coordinates of the window here to +// maximise the chance of being able to use DCI/DirectDraw primary surface + +HRESULT CBaseWindow::ActivateWindow() +{ + // Has the window been sized and positioned already + + if (m_bActivated == TRUE || GetParent(m_hwnd) != NULL) { + + SetWindowPos(m_hwnd, // Our window handle + HWND_TOP, // Put it at the top + 0, 0, 0, 0, // Leave in current position + SWP_NOMOVE | // Don't change it's place + SWP_NOSIZE); // Change Z-order only + + m_bActivated = TRUE; + return S_FALSE; + } + + // Calculate the desired client rectangle + + RECT WindowRect, ClientRect = GetDefaultRect(); + GetWindowRect(m_hwnd,&WindowRect); + AdjustWindowRectEx(&ClientRect,GetWindowLong(m_hwnd,GWL_STYLE), + FALSE,GetWindowLong(m_hwnd,GWL_EXSTYLE)); + + // Align left and top edges on DWORD boundaries + + UINT WindowFlags = (SWP_NOACTIVATE | SWP_FRAMECHANGED); + WindowRect.left -= (WindowRect.left & 3); + WindowRect.top -= (WindowRect.top & 3); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + WIDTH(&ClientRect), // Horizontal size + HEIGHT(&ClientRect), // Vertical size + WindowFlags); // Don't show window + + m_bActivated = TRUE; + return NOERROR; +} + + +// This can be used to DWORD align the window for maximum performance + +HRESULT CBaseWindow::PerformanceAlignWindow() +{ + RECT ClientRect,WindowRect; + GetWindowRect(m_hwnd,&WindowRect); + ASSERT(m_bActivated == TRUE); + + // Don't do this if we're owned + + if (GetParent(m_hwnd)) { + return NOERROR; + } + + // Align left and top edges on DWORD boundaries + + GetClientRect(m_hwnd, &ClientRect); + MapWindowPoints(m_hwnd, HWND_DESKTOP, (LPPOINT) &ClientRect, 2); + WindowRect.left -= (ClientRect.left & 3); + WindowRect.top -= (ClientRect.top & 3); + UINT WindowFlags = (SWP_NOACTIVATE | SWP_NOSIZE); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + (int) 0,(int) 0, // Ignore these sizes + WindowFlags); // Don't show window + + return NOERROR; +} + + +// Install a palette into the base window - we may be called by a different +// thread to the one that owns the window. We have to be careful how we do +// the palette realisation as we could be a different thread to the window +// which would cause an inter thread send message. Therefore we realise the +// palette by sending it a special message but without the window locked + +HRESULT CBaseWindow::SetPalette(HPALETTE hPalette) +{ + // We must own the window lock during the change + { + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + ASSERT(hPalette); + m_hPalette = hPalette; + } + return SetPalette(); +} + + +HRESULT CBaseWindow::SetPalette() +{ + if (!m_bNoRealize) { + SendMessage(m_hwnd, m_RealizePalette, 0, 0); + return S_OK; + } else { + // Just select the palette + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + CAutoLock cPaletteLock(&m_PaletteLock); + SelectPalette(m_hdc,m_hPalette,m_bBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + + return S_OK; + } +} + + +void CBaseWindow::UnsetPalette() +{ + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + + // Get a standard VGA colour palette + + HPALETTE hPalette = (HPALETTE) GetStockObject(DEFAULT_PALETTE); + ASSERT(hPalette); + + SelectPalette(GetWindowHDC(), hPalette, TRUE); + SelectPalette(GetMemoryHDC(), hPalette, TRUE); + + m_hPalette = NULL; +} + + +void CBaseWindow::LockPaletteLock() +{ + m_PaletteLock.Lock(); +} + + +void CBaseWindow::UnlockPaletteLock() +{ + m_PaletteLock.Unlock(); +} + + +// Realise our palettes in the window and device contexts + +HRESULT CBaseWindow::DoRealisePalette(BOOL bForceBackground) +{ + { + CAutoLock cPaletteLock(&m_PaletteLock); + + if (m_hPalette == NULL) { + return NOERROR; + } + + // Realize the palette on the window thread + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + SelectPalette(m_hdc,m_hPalette,m_bBackground || bForceBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + } + + // If we grab a critical section here we can deadlock + // with the window thread because one of the side effects + // of RealizePalette is to send a WM_PALETTECHANGED message + // to every window in the system. In our handling + // of WM_PALETTECHANGED we used to grab this CS too. + // The really bad case is when our renderer calls DoRealisePalette() + // while we're in the middle of processing a palette change + // for another window. + // So don't hold the critical section while actually realising + // the palette. In any case USER is meant to manage palette + // handling - we shouldn't have to serialize everything as well + ASSERT(CritCheckOut(&m_WindowLock)); + ASSERT(CritCheckOut(&m_PaletteLock)); + + EXECUTE_ASSERT(RealizePalette(m_hdc) != GDI_ERROR); + EXECUTE_ASSERT(RealizePalette(m_MemoryDC) != GDI_ERROR); + + return (GdiFlush() == FALSE ? S_FALSE : S_OK); +} + + +// This is the global window procedure + +LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + + // Get the window long that holds our window object pointer + // If it is NULL then we are initialising the window in which + // case the object pointer has been passed in the window creation + // structure. IF we get any messages before WM_NCCREATE we will + // pass them to DefWindowProc. + + CBaseWindow *pBaseWindow = (CBaseWindow *)GetWindowLongPtr(hwnd,0); + if (pBaseWindow == NULL) { + + // Get the structure pointer from the create struct. + // We can only do this for WM_NCCREATE which should be one of + // the first messages we receive. Anything before this will + // have to be passed to DefWindowProc (i.e. WM_GETMINMAXINFO) + + // If the message is WM_NCCREATE we set our pBaseWindow pointer + // and will then place it in the window structure + + // turn off WS_EX_LAYOUTRTL style for quartz windows + if (uMsg == WM_NCCREATE) { + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x400000); + } + + if ((uMsg != WM_NCCREATE) + || (NULL == (pBaseWindow = *(CBaseWindow**) ((LPCREATESTRUCT)lParam)->lpCreateParams))) + { + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + + // Set the window LONG to be the object who created us +#ifdef DEBUG + SetLastError(0); // because of the way SetWindowLong works +#endif + LONG_PTR rc = SetWindowLongPtr(hwnd, (DWORD) 0, (LONG_PTR) pBaseWindow); +#ifdef DEBUG + if (0 == rc) { + // SetWindowLong MIGHT have failed. (Read the docs which admit + // that it is awkward to work out if you have had an error.) + LONG lasterror = GetLastError(); + ASSERT(0 == lasterror); + // If this is not the case we have not set the pBaseWindow pointer + // into the window structure and we will blow up. + } +#endif + + } + // See if this is the packet of death + if (uMsg == MsgDestroy && uMsg != 0) { + pBaseWindow->DoneWithWindow(); + if (pBaseWindow->m_bDoPostToDestroy) { + EXECUTE_ASSERT(SetEvent((HANDLE)wParam)); + } + return 0; + } + return pBaseWindow->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// When the window size changes we adjust our member variables that +// contain the dimensions of the client rectangle for our window so +// that we come to render an image we will know whether to stretch + +BOOL CBaseWindow::OnSize(LONG Width, LONG Height) +{ + m_Width = Width; + m_Height = Height; + return TRUE; +} + + +// This function handles the WM_CLOSE message + +BOOL CBaseWindow::OnClose() +{ + ShowWindow(m_hwnd,SW_HIDE); + return TRUE; +} + + +// This is called by the worker window thread when it receives a terminate +// message from the window object destructor to delete all the resources we +// allocated during initialisation. By the time the worker thread exits all +// processing will have been completed as the source filter disconnection +// flushes the image pending sample, therefore the GdiFlush should succeed + +HRESULT CBaseWindow::UninitialiseWindow() +{ + // Have we already cleaned up + + if (m_hwnd == NULL) { + ASSERT(m_hdc == NULL); + ASSERT(m_MemoryDC == NULL); + return NOERROR; + } + + // Release the window resources + + EXECUTE_ASSERT(GdiFlush()); + + if (m_hdc) + { + EXECUTE_ASSERT(ReleaseDC(m_hwnd,m_hdc)); + m_hdc = NULL; + } + + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; +} + + +// This is called by the worker window thread after it has created the main +// window and it wants to initialise the rest of the owner objects window +// variables such as the device contexts. We execute this function with the +// critical section still locked. Nothing in this function must generate any +// SendMessage calls to the window because this is executing on the window +// thread so the message will never be processed and we will deadlock + +HRESULT CBaseWindow::InitialiseWindow(HWND hwnd) +{ + // Initialise the window variables + + ASSERT(IsWindow(hwnd)); + m_hwnd = hwnd; + + if (m_bDoGetDC) + { + EXECUTE_ASSERT(m_hdc = GetDC(hwnd)); + EXECUTE_ASSERT(m_MemoryDC = CreateCompatibleDC(m_hdc)); + + EXECUTE_ASSERT(SetStretchBltMode(m_hdc,COLORONCOLOR)); + EXECUTE_ASSERT(SetStretchBltMode(m_MemoryDC,COLORONCOLOR)); + } + + return NOERROR; +} + +HRESULT CBaseWindow::DoCreateWindow() +{ + WNDCLASS wndclass; // Used to register classes + BOOL bRegistered; // Is this class registered + HWND hwnd; // Handle to our window + + bRegistered = GetClassInfo(m_hInstance, // Module instance + m_pClassName, // Window class + &wndclass); // Info structure + + // if the window is to be used for drawing puposes and we are getting a DC + // for the entire lifetime of the window then changes the class style to do + // say so. If we don't set this flag then the DC comes from the cache and is + // really bad. + if (m_bDoGetDC) + { + m_ClassStyles |= CS_OWNDC; + } + + if (bRegistered == FALSE) { + + // Register the renderer window class + + wndclass.lpszClassName = m_pClassName; + wndclass.style = m_ClassStyles; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof(CBaseWindow *); + wndclass.hInstance = m_hInstance; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH) NULL; + wndclass.lpszMenuName = NULL; + + RegisterClass(&wndclass); + } + + // Create the frame window. Pass the pBaseWindow information in the + // CreateStruct which allows our message handling loop to get hold of + // the pBaseWindow pointer. + + CBaseWindow *pBaseWindow = this; // The owner window object + hwnd = CreateWindowEx(m_WindowStylesEx, // Extended styles + m_pClassName, // Registered name + TEXT("ActiveMovie Window"), // Window title + m_WindowStyles, // Window styles + CW_USEDEFAULT, // Start x position + CW_USEDEFAULT, // Start y position + DEFWIDTH, // Window width + DEFHEIGHT, // Window height + NULL, // Parent handle + NULL, // Menu handle + m_hInstance, // Instance handle + &pBaseWindow); // Creation data + + // If we failed signal an error to the object constructor (based on the + // last Win32 error on this thread) then signal the constructor thread + // to continue, release the mutex to let others have a go and exit + + if (hwnd == NULL) { + DWORD Error = GetLastError(); + return AmHresultFromWin32(Error); + } + + // Check the window LONG is the object who created us + ASSERT(GetWindowLongPtr(hwnd, 0) == (LONG_PTR)this); + + // Initialise the window and then signal the constructor so that it can + // continue and then finally unlock the object's critical section. The + // window class is left registered even after we terminate the thread + // as we don't know when the last window has been closed. So we allow + // the operating system to free the class resources as appropriate + + InitialiseWindow(hwnd); + + DbgLog((LOG_TRACE, 2, TEXT("Created window class (%s) HWND(%8.8X)"), + m_pClassName, hwnd)); + + return S_OK; +} + + +// The base class provides some default handling and calls DefWindowProc + +LRESULT CBaseWindow::OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + ASSERT(IsWindow(hwnd)); + + if (PossiblyEatMessage(uMsg, wParam, lParam)) + return 0; + + // This is sent by the IVideoWindow SetWindowForeground method. If the + // window is invisible we will show it and make it topmost without the + // foreground focus. If the window is visible it will also be made the + // topmost window without the foreground focus. If wParam is TRUE then + // for both cases the window will be forced into the foreground focus + + if (uMsg == m_ShowStageMessage) { + + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + (bVisible ? SWP_NOACTIVATE : 0)); + + // Should we bring the window to the foreground + if (wParam == TRUE) { + SetForegroundWindow(hwnd); + } + return (LRESULT) 1; + } + + // When we go fullscreen we have to add the WS_EX_TOPMOST style to the + // video window so that it comes out above any task bar (this is more + // relevant to WindowsNT than Windows95). However the SetWindowPos call + // must be on the same thread as that which created the window. The + // wParam parameter can be TRUE or FALSE to set and reset the topmost + + if (uMsg == m_ShowStageTop) { + HWND HwndTop = (wParam == TRUE ? HWND_TOPMOST : HWND_NOTOPMOST); + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HwndTop, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | + (wParam == TRUE ? SWP_SHOWWINDOW : 0) | + (bVisible ? SWP_NOACTIVATE : 0)); + return (LRESULT) 1; + } + + // New palette stuff + if (uMsg == m_RealizePalette) { + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,WM_QUERYNEWPALETTE); + } + + switch (uMsg) { + + // Repaint the window if the system colours change + + case WM_SYSCOLORCHANGE: + + InvalidateRect(hwnd,NULL,FALSE); + return (LRESULT) 1; + + // Somebody has changed the palette + case WM_PALETTECHANGED: + + OnPaletteChange((HWND)wParam,uMsg); + return (LRESULT) 0; + + // We are about to receive the keyboard focus so we ask GDI to realise + // our logical palette again and hopefully it will be fully installed + // without any mapping having to be done during any picture rendering + + case WM_QUERYNEWPALETTE: + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,uMsg); + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + if (IsWindowVisible(m_hwnd)) { + PostMessage(m_hwnd,WM_PAINT,0,0); + } + break; + + // Store the width and height as useful base class members + + case WM_SIZE: + + OnSize(LOWORD(lParam), HIWORD(lParam)); + return (LRESULT) 0; + + // Intercept the WM_CLOSE messages to hide the window + + case WM_CLOSE: + + OnClose(); + return (LRESULT) 0; + } + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + + +// This handles the Windows palette change messages - if we do realise our +// palette then we return TRUE otherwise we return FALSE. If our window is +// foreground application then we should get first choice of colours in the +// system palette entries. We get best performance when our logical palette +// includes the standard VGA colours (at the beginning and end) otherwise +// GDI may have to map from our palette to the device palette while drawing + +LRESULT CBaseWindow::OnPaletteChange(HWND hwnd,UINT Message) +{ + // First check we are not changing the palette during closedown + + if (m_hwnd == NULL || hwnd == NULL) { + return (LRESULT) 0; + } + ASSERT(!m_bRealizing); + + // Should we realise our palette again + + if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) { + // It seems that even if we're invisible that we can get asked + // to realize our palette and this can cause really ugly side-effects + // Seems like there's another bug but this masks it a least for the + // shutting down case. + if (!IsWindowVisible(m_hwnd)) { + DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!"))); + return (LRESULT) 0; + } + + // Avoid recursion with multiple graphs in the same app +#ifdef DEBUG + m_bRealizing = TRUE; +#endif + DoRealisePalette(Message != WM_QUERYNEWPALETTE); +#ifdef DEBUG + m_bRealizing = FALSE; +#endif + + // Should we redraw the window with the new palette + if (Message == WM_PALETTECHANGED) { + InvalidateRect(m_hwnd,NULL,FALSE); + } + } + + return (LRESULT) 1; +} + + +// Determine if the window exists. + +bool CBaseWindow::WindowExists() +{ + return !!IsWindow(m_hwnd); +} + + +// Return the default window rectangle + +RECT CBaseWindow::GetDefaultRect() +{ + RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT}; + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return DefaultRect; +} + + +// Return the current window width + +LONG CBaseWindow::GetWindowWidth() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Width; +} + + +// Return the current window height + +LONG CBaseWindow::GetWindowHeight() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Height; +} + + +// Return the window handle + +HWND CBaseWindow::GetWindowHWND() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_hwnd; +} + + +// Return the window drawing device context + +HDC CBaseWindow::GetWindowHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_hdc); + return m_hdc; +} + + +// Return the offscreen window drawing device context + +HDC CBaseWindow::GetMemoryHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_MemoryDC); + return m_MemoryDC; +} + + +#ifdef DEBUG +HPALETTE CBaseWindow::GetPalette() +{ + // The palette lock should always be held when accessing + // m_hPalette. + ASSERT(CritCheckIn(&m_PaletteLock)); + return m_hPalette; +} +#endif // DEBUG + + +// This is available to clients who want to change the window visiblity. It's +// little more than an indirection to the Win32 ShowWindow although these is +// some benefit in going through here as this function may change sometime + +HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd) +{ + ShowWindow(m_hwnd,ShowCmd); + return NOERROR; +} + + +// Generate a WM_PAINT message for the video window + +void CBaseWindow::PaintWindow(BOOL bErase) +{ + InvalidateRect(m_hwnd,NULL,bErase); +} + + +// Allow an application to have us set the video window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. Rather than expose the message we use to execute +// the inter thread send message we provide the interface function. All we do +// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE + +void CBaseWindow::DoSetWindowForeground(BOOL bFocus) +{ + SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0); +} + + +// Constructor initialises the owning object pointer. Since we are a worker +// class for the main window object we have relatively few state variables to +// look after. We are given device context handles to use later on as well as +// the source and destination rectangles (but reset them here just in case) + +CDrawImage::CDrawImage(CBaseWindow *pBaseWindow) : + m_pBaseWindow(pBaseWindow), + m_hdc(NULL), + m_MemoryDC(NULL), + m_bStretch(FALSE), + m_pMediaType(NULL), + m_bUsingImageAllocator(FALSE) +{ + ASSERT(pBaseWindow); + ResetPaletteVersion(); + SetRectEmpty(&m_TargetRect); + SetRectEmpty(&m_SourceRect); + + m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time")); +} + + +// Overlay the image time stamps on the picture. Access to this method is +// serialised by the caller. We display the sample start and end times on +// top of the video using TextOut on the device context we are handed. If +// there isn't enough room in the window for the times we don't show them + +void CDrawImage::DisplaySampleTimes(IMediaSample *pSample) +{ +#ifdef DEBUG + // + // Only allow the "annoying" time messages if the users has turned the + // logging "way up" + // + BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5); + if (bAccept == FALSE) { + return; + } +#endif + + TCHAR szTimes[TIMELENGTH]; // Time stamp strings + ASSERT(pSample); // Quick sanity check + RECT ClientRect; // Client window size + SIZE Size; // Size of text output + + // Get the time stamps and window size + + pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample); + HWND hwnd = m_pBaseWindow->GetWindowHWND(); + EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect)); + + // Format the sample time stamps + + (void)StringCchPrintf(szTimes, NUMELMS(szTimes), TEXT("%08d : %08d"), + m_StartSample.Millisecs(), + m_EndSample.Millisecs()); + + ASSERT(lstrlen(szTimes) < TIMELENGTH); + + // Put the times in the middle at the bottom of the window + + GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size); + INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2; + INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5; + + // Check the window is big enough to have sample times displayed + + if ((XPos > 0) && (YPos > 0)) { + TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes)); + } +} + + +// This is called when the drawing code sees that the image has a down level +// palette cookie. We simply call the SetDIBColorTable Windows API with the +// palette that is found after the BITMAPINFOHEADER - we return no errors + +void CDrawImage::UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi) +{ + ASSERT(pbmi->biClrUsed); + RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1); + + // Set the new palette in the device context + + UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0, + pbmi->biClrUsed, + pColourTable); + + // Should always succeed but check in debug builds + ASSERT(uiReturn == pbmi->biClrUsed); +} + + +// No source rectangle scaling is done by the base class + +RECT CDrawImage::ScaleSourceRect(const RECT *pSource) +{ + ASSERT(pSource); + return *pSource; +} + + +// This is called when the funky output pin uses our allocator. The samples we +// allocate are special because the memory is shared between us and GDI thus +// removing one copy when we ask for the image to be rendered. The source type +// information is in the main renderer m_mtIn field which is initialised when +// the media type is agreed in SetMediaType, the media type may be changed on +// the fly if, for example, the source filter needs to change the palette + +void CDrawImage::FastRender(IMediaSample *pMediaSample) +{ + BITMAPINFOHEADER *pbmi; // Image format data + DIBDATA *pDibData; // Stores DIB information + BYTE *pImage; // Pointer to image data + HBITMAP hOldBitmap; // Store the old bitmap + CImageSample *pSample; // Pointer to C++ object + + ASSERT(m_pMediaType); + + // From the untyped source format block get the VIDEOINFO and subsequently + // the BITMAPINFOHEADER structure. We can cast the IMediaSample interface + // to a CImageSample object so we can retrieve it's DIBSECTION details + + pbmi = HEADER(m_pMediaType->Format()); + pSample = (CImageSample *) pMediaSample; + pDibData = pSample->GetDIBData(); + hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap); + + // Get a pointer to the real image data + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // Do we need to update the colour table, we increment our palette cookie + // each time we get a dynamic format change. The sample palette cookie is + // stored in the DIBDATA structure so we try to keep the fields in sync + // By the time we get to draw the images the format change will be done + // so all we do is ask the renderer for what it's palette version is + + if (pDibData->PaletteVersion < GetPaletteVersion()) { + ASSERT(pbmi->biBitCount <= iPALETTE); + UpdateColourTable(m_MemoryDC,pbmi); + pDibData->PaletteVersion = GetPaletteVersion(); + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + BitBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device context + SourceRect.left, // X source position + SourceRect.top, // Y source position + SRCCOPY); // Simple copy + + } else { + + // Stretch the image when copying to the window + + StretchBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device HDC + SourceRect.left, // X source position + SourceRect.top, // Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + SRCCOPY); // Simple copy + } + + // This displays the sample times over the top of the image. This used to + // draw the times into the offscreen device context however that actually + // writes the text into the image data buffer which may not be writable + + #ifdef DEBUG + DisplaySampleTimes(pMediaSample); + #endif + + // Put the old bitmap back into the device context so we don't leak + SelectObject(m_MemoryDC,hOldBitmap); +} + + +// This is called when there is a sample ready to be drawn, unfortunately the +// output pin was being rotten and didn't choose our super excellent shared +// memory DIB allocator so we have to do this slow render using boring old GDI +// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI +// functions is that the image data has to be copied across from our address +// space into theirs before going to the screen (although in reality the cost +// is small because all they do is to map the buffer into their address space) + +void CDrawImage::SlowRender(IMediaSample *pMediaSample) +{ + // Get the BITMAPINFOHEADER for the connection + + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + SetDIBitsToDevice( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + (UINT) 0, // Start scan line + pbmi->biHeight, // Scan lines present + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS); // Type of palette + + } else { + + // Stretch the image when copying to the window + + StretchDIBits( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS, // Type of palette + SRCCOPY); // Simple image copy + } + + // This shows the sample reference times over the top of the image which + // looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to + // control the screen updates but it doesn't quite work as expected and + // only partially reduces the flicker. I also tried using a memory context + // and combining the two in that before doing a final BitBlt operation to + // the screen, unfortunately this has considerable performance penalties + // and also means that this code is not executed when compiled retail + + #ifdef DEBUG + DisplaySampleTimes(pMediaSample); + #endif +} + + +// This is called with an IMediaSample interface on the image to be drawn. We +// decide on the drawing mechanism based on who's allocator we are using. We +// may be called when the window wants an image painted by WM_PAINT messages +// We can't realise the palette here because we have the renderer lock, any +// call to realise may cause an interthread send message to the window thread +// which may in turn be waiting to get the renderer lock before servicing it + +BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample) +{ + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + NotifyStartDraw(); + + // If the output pin used our allocator then the samples passed are in + // fact CVideoSample objects that contain CreateDIBSection data that we + // use to do faster image rendering, they may optionally also contain a + // DirectDraw surface pointer in which case we do not do the drawing + + if (m_bUsingImageAllocator == FALSE) { + SlowRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; + } + + // This is a DIBSECTION buffer + + FastRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; +} + + +BOOL CDrawImage::DrawVideoImageHere( + HDC hdc, + IMediaSample *pMediaSample, + LPRECT lprcSrc, + LPRECT lprcDst + ) +{ + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return FALSE; + } + + RECT SourceRect; + RECT TargetRect; + + if (lprcSrc) { + SourceRect = *lprcSrc; + } + else SourceRect = ScaleSourceRect(&m_SourceRect); + + if (lprcDst) { + TargetRect = *lprcDst; + } + else TargetRect = m_TargetRect; + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + + + // Stretch the image when copying to the DC + + BOOL bRet = (0 != StretchDIBits(hdc, + TargetRect.left, + TargetRect.top, + TargetRect.right - TargetRect.left, + TargetRect.bottom - TargetRect.top, + SourceRect.left, + lAdjustedSourceTop, + SourceRect.right - SourceRect.left, + SourceRect.bottom - SourceRect.top, + pImage, + (BITMAPINFO *)pbmi, + DIB_RGB_COLORS, + SRCCOPY)); + return bRet; +} + + +// This is called by the owning window object after it has created the window +// and it's drawing contexts. We are constructed with the base window we'll +// be drawing into so when given the notification we retrive the device HDCs +// to draw with. We cannot call these in our constructor as they are virtual + +void CDrawImage::SetDrawContext() +{ + m_MemoryDC = m_pBaseWindow->GetMemoryHDC(); + m_hdc = m_pBaseWindow->GetWindowHDC(); +} + + +// This is called to set the target rectangle in the video window, it will be +// called whenever a WM_SIZE message is retrieved from the message queue. We +// simply store the rectangle and use it later when we do the drawing calls + +void CDrawImage::SetTargetRect(RECT *pTargetRect) +{ + ASSERT(pTargetRect); + m_TargetRect = *pTargetRect; + SetStretchMode(); +} + + +// Return the current target rectangle + +void CDrawImage::GetTargetRect(RECT *pTargetRect) +{ + ASSERT(pTargetRect); + *pTargetRect = m_TargetRect; +} + + +// This is called when we want to change the section of the image to draw. We +// use this information in the drawing operation calls later on. We must also +// see if the source and destination rectangles have the same dimensions. If +// not we must stretch during the drawing rather than a direct pixel copy + +void CDrawImage::SetSourceRect(RECT *pSourceRect) +{ + ASSERT(pSourceRect); + m_SourceRect = *pSourceRect; + SetStretchMode(); +} + + +// Return the current source rectangle + +void CDrawImage::GetSourceRect(RECT *pSourceRect) +{ + ASSERT(pSourceRect); + *pSourceRect = m_SourceRect; +} + + +// This is called when either the source or destination rectanges change so we +// can update the stretch flag. If the rectangles don't match we stretch the +// video during the drawing otherwise we call the fast pixel copy functions +// NOTE the source and/or the destination rectangle may be completely empty + +void CDrawImage::SetStretchMode() +{ + // Calculate the overall rectangle dimensions + + LONG SourceWidth = m_SourceRect.right - m_SourceRect.left; + LONG SinkWidth = m_TargetRect.right - m_TargetRect.left; + LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top; + LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top; + + m_bStretch = TRUE; + if (SourceWidth == SinkWidth) { + if (SourceHeight == SinkHeight) { + m_bStretch = FALSE; + } + } +} + + +// Tell us whose allocator we are using. This should be called with TRUE if +// the filter agrees to use an allocator based around the CImageAllocator +// SDK base class - whose image buffers are made through CreateDIBSection. +// Otherwise this should be called with FALSE and we will draw the images +// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls +// can handle buffers which have non zero strides (like DirectDraw uses) + +void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator) +{ + m_bUsingImageAllocator = bUsingImageAllocator; +} + + +// Are we using the image DIBSECTION allocator + +BOOL CDrawImage::UsingImageAllocator() +{ + return m_bUsingImageAllocator; +} + + +// We need the media type of the connection so that we can get the BITMAPINFO +// from it. We use that in the calls to draw the image such as StretchDIBits +// and also when updating the colour table held in shared memory DIBSECTIONs + +void CDrawImage::NotifyMediaType(CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// We store in this object a cookie maintaining the current palette version. +// Each time a palettised format is changed we increment this value so that +// when we come to draw the images we look at the colour table value they +// have and if less than the current we know to update it. This version is +// only needed and indeed used when working with shared memory DIBSECTIONs + +LONG CDrawImage::GetPaletteVersion() +{ + return m_PaletteVersion; +} + + +// Resets the current palette version number + +void CDrawImage::ResetPaletteVersion() +{ + m_PaletteVersion = PALETTE_VERSION; +} + + +// Increment the current palette version + +void CDrawImage::IncrementPaletteVersion() +{ + m_PaletteVersion++; +} + + +// Constructor must initialise the base allocator. Each sample we create has a +// palette version cookie on board. When the source filter changes the palette +// during streaming the window object increments an internal cookie counter it +// keeps as well. When it comes to render the samples it looks at the cookie +// values and if they don't match then it knows to update the sample's colour +// table. However we always create samples with a cookie of PALETTE_VERSION +// If there have been multiple format changes and we disconnect and reconnect +// thereby causing the samples to be reallocated we will create them with a +// cookie much lower than the current version, this isn't a problem since it +// will be seen by the window object and the versions will then be updated + +CImageAllocator::CImageAllocator(CBaseFilter *pFilter, + TCHAR *pName, + HRESULT *phr) : + CBaseAllocator(pName,NULL,phr,TRUE,TRUE), + m_pFilter(pFilter) +{ + ASSERT(phr); + ASSERT(pFilter); +} + + +// Check our DIB buffers have been released + +#ifdef DEBUG +CImageAllocator::~CImageAllocator() +{ + ASSERT(m_bCommitted == FALSE); +} +#endif + + +// Called from destructor and also from base class to free resources. We work +// our way through the list of media samples deleting the DIBSECTION created +// for each. All samples should be back in our list so there is no chance a +// filter is still using one to write on the display or hold on a pending list + +void CImageAllocator::Free() +{ + ASSERT(m_lAllocated == m_lFree.GetCount()); + EXECUTE_ASSERT(GdiFlush()); + CImageSample *pSample; + DIBDATA *pDibData; + + while (m_lFree.GetCount() != 0) { + pSample = (CImageSample *) m_lFree.RemoveHead(); + pDibData = pSample->GetDIBData(); + EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap)); + EXECUTE_ASSERT(CloseHandle(pDibData->hMapping)); + delete pSample; + } + + m_lAllocated = 0; +} + + +// Prepare the allocator by checking all the input parameters + +STDMETHODIMP CImageAllocator::CheckSizes(ALLOCATOR_PROPERTIES *pRequest) +{ + // Check we have a valid connection + + if (m_pMediaType == NULL) { + return VFW_E_NOT_CONNECTED; + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format(); + + // When we call CreateDIBSection it implicitly maps only enough memory + // for the image as defined by thee BITMAPINFOHEADER. If the user asks + // for an image smaller than this then we reject the call, if they ask + // for an image larger than this then we return what they can have + + if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) { + return E_INVALIDARG; + } + + // Reject buffer prefixes + + if (pRequest->cbPrefix > 0) { + return E_INVALIDARG; + } + + pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage; + return NOERROR; +} + + +// Agree the number of media sample buffers and their sizes. The base class +// this allocator is derived from allows samples to be aligned only on byte +// boundaries NOTE the buffers are not allocated until the Commit call + +STDMETHODIMP CImageAllocator::SetProperties( + ALLOCATOR_PROPERTIES * pRequest, + ALLOCATOR_PROPERTIES * pActual) +{ + ALLOCATOR_PROPERTIES Adjusted = *pRequest; + + // Check the parameters fit with the current connection + + HRESULT hr = CheckSizes(&Adjusted); + if (FAILED(hr)) { + return hr; + } + return CBaseAllocator::SetProperties(&Adjusted, pActual); +} + + +// Commit the memory by allocating the agreed number of media samples. For +// each sample we are committed to creating we have a CImageSample object +// that we use to manage it's resources. This is initialised with a DIBDATA +// structure that contains amongst other things the GDI DIBSECTION handle +// We will access the renderer media type during this so we must have locked +// (to prevent the format changing for example). The class overrides Commit +// and Decommit to do this locking (base class Commit in turn calls Alloc) + +HRESULT CImageAllocator::Alloc(void) +{ + ASSERT(m_pMediaType); + CImageSample *pSample; + DIBDATA DibData; + + // Check the base allocator says it's ok to continue + + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + // We create a new memory mapped object although we don't map it into our + // address space because GDI does that in CreateDIBSection. It is possible + // that we run out of resources before creating all the samples in which + // case the available sample list is left with those already created + + ASSERT(m_lAllocated == 0); + while (m_lAllocated < m_lCount) { + + // Create and initialise a shared memory GDI buffer + + HRESULT hr = CreateDIB(m_lSize,DibData); + if (FAILED(hr)) { + return hr; + } + + // Create the sample object and pass it the DIBDATA + + pSample = CreateImageSample(DibData.pBase,m_lSize); + if (pSample == NULL) { + EXECUTE_ASSERT(DeleteObject(DibData.hBitmap)); + EXECUTE_ASSERT(CloseHandle(DibData.hMapping)); + return E_OUTOFMEMORY; + } + + // Add the completed sample to the available list + + pSample->SetDIBData(&DibData); + m_lFree.Add(pSample); + m_lAllocated++; + } + return NOERROR; +} + + +// We have a virtual method that allocates the samples so that a derived class +// may override it and allocate more specialised sample objects. So long as it +// derives its samples from CImageSample then all this code will still work ok + +CImageSample *CImageAllocator::CreateImageSample(LPBYTE pData,LONG Length) +{ + HRESULT hr = NOERROR; + CImageSample *pSample; + + // Allocate the new sample and check the return codes + + pSample = new CImageSample((CBaseAllocator *) this, // Base class + NAME("Video sample"), // DEBUG name + (HRESULT *) &hr, // Return code + (LPBYTE) pData, // DIB address + (LONG) Length); // Size of DIB + + if (pSample == NULL || FAILED(hr)) { + delete pSample; + return NULL; + } + return pSample; +} + + +// This function allocates a shared memory block for use by the source filter +// generating DIBs for us to render. The memory block is created in shared +// memory so that GDI doesn't have to copy the memory when we do a BitBlt + +HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData) +{ + BITMAPINFO *pbmi; // Format information for pin + BYTE *pBase; // Pointer to the actual image + HANDLE hMapping; // Handle to mapped object + HBITMAP hBitmap; // DIB section bitmap handle + + // Create a file mapping object and map into our address space + + hMapping = CreateFileMapping(hMEMORY, // Use system page file + NULL, // No security attributes + PAGE_READWRITE, // Full access to memory + (DWORD) 0, // Less than 4Gb in size + InSize, // Size of buffer + NULL); // No name to section + if (hMapping == NULL) { + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + pbmi = (BITMAPINFO *) HEADER(m_pMediaType->Format()); + if (m_pMediaType == NULL) { + DbgBreak("Invalid media type"); + } + + hBitmap = CreateDIBSection((HDC) NULL, // NO device context + pbmi, // Format information + DIB_RGB_COLORS, // Use the palette + (VOID **) &pBase, // Pointer to image data + hMapping, // Mapped memory handle + (DWORD) 0); // Offset into memory + + if (hBitmap == NULL || pBase == NULL) { + EXECUTE_ASSERT(CloseHandle(hMapping)); + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // Initialise the DIB information structure + + DibData.hBitmap = hBitmap; + DibData.hMapping = hMapping; + DibData.pBase = pBase; + DibData.PaletteVersion = PALETTE_VERSION; + GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection); + + return NOERROR; +} + + +// We use the media type during the DIBSECTION creation + +void CImageAllocator::NotifyMediaType(CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// Overriden to increment the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef() +{ + return m_pFilter->AddRef(); +} + + +// Overriden to decrement the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease() +{ + return m_pFilter->Release(); +} + + +// If you derive a class from CMediaSample that has to transport specialised +// member variables and entry points then there are three alternate solutions +// The first is to create a memory buffer larger than actually required by the +// sample and store your information either at the beginning of it or at the +// end, the former being moderately safer allowing for misbehaving transform +// filters. You then adjust the buffer address when you create the base media +// sample. This has the disadvantage of breaking up the memory allocated to +// the samples into separate blocks. The second solution is to implement a +// class derived from CMediaSample and support additional interface(s) that +// convey your private data. This means defining a custom interface. The final +// alternative is to create a class that inherits from CMediaSample and adds +// the private data structures, when you get an IMediaSample in your Receive() +// call check to see if your allocator is being used, and if it is then cast +// the IMediaSample into one of your objects. Additional checks can be made +// to ensure the sample's this pointer is known to be one of your own objects + +CImageSample::CImageSample(CBaseAllocator *pAllocator, + TCHAR *pName, + HRESULT *phr, + LPBYTE pBuffer, + LONG length) : + CMediaSample(pName,pAllocator,phr,pBuffer,length), + m_bInit(FALSE) +{ + ASSERT(pAllocator); + ASSERT(pBuffer); +} + + +// Set the shared memory DIB information + +void CImageSample::SetDIBData(DIBDATA *pDibData) +{ + ASSERT(pDibData); + m_DibData = *pDibData; + m_bInit = TRUE; +} + + +// Retrieve the shared memory DIB data + +DIBDATA *CImageSample::GetDIBData() +{ + ASSERT(m_bInit == TRUE); + return &m_DibData; +} + + +// This class handles the creation of a palette. It is fairly specialist and +// is intended to simplify palette management for video renderer filters. It +// is for this reason that the constructor requires three other objects with +// which it interacts, namely a base media filter, a base window and a base +// drawing object although the base window or the draw object may be NULL to +// ignore that part of us. We try not to create and install palettes unless +// absolutely necessary as they typically require WM_PALETTECHANGED messages +// to be sent to every window thread in the system which is very expensive + +CImagePalette::CImagePalette(CBaseFilter *pBaseFilter, + CBaseWindow *pBaseWindow, + CDrawImage *pDrawImage) : + m_pBaseWindow(pBaseWindow), + m_pFilter(pBaseFilter), + m_pDrawImage(pDrawImage), + m_hPalette(NULL) +{ + ASSERT(m_pFilter); +} + + +// Destructor + +#ifdef DEBUG +CImagePalette::~CImagePalette() +{ + ASSERT(m_hPalette == NULL); +} +#endif + + +// We allow dynamic format changes of the palette but rather than change the +// palette every time we call this to work out whether an update is required. +// If the original type didn't use a palette and the new one does (or vica +// versa) then we return TRUE. If neither formats use a palette we'll return +// FALSE. If both formats use a palette we compare their colours and return +// FALSE if they match. This therefore short circuits palette creation unless +// absolutely necessary since installing palettes is an expensive operation + +BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo, + const VIDEOINFOHEADER *pOldInfo) +{ + // We may not have a current format yet + + if (pOldInfo == NULL) { + return TRUE; + } + + // Do both formats not require a palette + + if (ContainsPalette(pNewInfo) == FALSE) { + if (ContainsPalette(pOldInfo) == FALSE) { + return FALSE; + } + } + + // Compare the colours to see if they match + + DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed; + if (ContainsPalette(pNewInfo) == TRUE) + if (ContainsPalette(pOldInfo) == TRUE) + if (pOldInfo->bmiHeader.biClrUsed == VideoEntries) + if (pOldInfo->bmiHeader.biClrUsed > 0) + if (memcmp((PVOID) GetBitmapPalette(pNewInfo), + (PVOID) GetBitmapPalette(pOldInfo), + VideoEntries * sizeof(RGBQUAD)) == 0) { + + return FALSE; + } + return TRUE; +} + + +// This is normally called when the input pin type is set to install a palette +// We will typically be called from two different places. The first is when we +// have negotiated a palettised media type after connection, the other is when +// we receive a new type during processing with an updated palette in which +// case we must remove and release the resources held by the current palette + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew, + const CMediaType *pmtOld, + LPSTR szDevice) +{ + const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format(); + const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format(); + ASSERT(pNewInfo); + + // This is an performance optimisation, when we get a media type we check + // to see if the format requires a palette change. If either we need one + // when previously we didn't or vica versa then this returns TRUE, if we + // previously needed a palette and we do now it compares their colours + + if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) { + NOTE("No update needed"); + return S_FALSE; + } + + // We must notify the filter graph that the application may have changed + // the palette although in practice we don't bother checking to see if it + // is really different. If it tries to get the palette either the window + // or renderer lock will ensure it doesn't get in until we are finished + + RemovePalette(); + m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0); + + // Do we need a palette for the new format + + if (ContainsPalette(pNewInfo) == FALSE) { + NOTE("New has no palette"); + return S_FALSE; + } + + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // If we're changing the palette on the fly then we increment our palette + // cookie which is compared against the cookie also stored in all of our + // DIBSECTION media samples. If they don't match when we come to draw it + // then we know the sample is out of date and we'll update it's palette + + NOTE("Making new colour palette"); + m_hPalette = MakePalette(pNewInfo, szDevice); + ASSERT(m_hPalette != NULL); + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + // The window in which the new palette is to be realised may be a NULL + // pointer to signal that no window is in use, if so we don't call it + // Some filters just want to use this object to create/manage palettes + + if (m_pBaseWindow) m_pBaseWindow->SetPalette(m_hPalette); + + // This is the only time where we need access to the draw object to say + // to it that a new palette will be arriving on a sample real soon. The + // constructor may take a NULL pointer in which case we don't call this + + if (m_pDrawImage) m_pDrawImage->IncrementPaletteVersion(); + return NOERROR; +} + + +// Helper function to copy a palette out of any kind of VIDEOINFO (ie it may +// be YUV or true colour) into a palettised VIDEOINFO. We use this changing +// palettes on DirectDraw samples as a source filter can attach a palette to +// any buffer (eg YUV) and hand it back. We make a new palette out of that +// format and then copy the palette colours into the current connection type + +HRESULT CImagePalette::CopyPalette(const CMediaType *pSrc,CMediaType *pDest) +{ + // Reset the destination palette before starting + + VIDEOINFOHEADER *pDestInfo = (VIDEOINFOHEADER *) pDest->Format(); + pDestInfo->bmiHeader.biClrUsed = 0; + pDestInfo->bmiHeader.biClrImportant = 0; + + // Does the destination have a palette + + if (PALETTISED(pDestInfo) == FALSE) { + NOTE("No destination palette"); + return S_FALSE; + } + + // Does the source contain a palette + + const VIDEOINFOHEADER *pSrcInfo = (VIDEOINFOHEADER *) pSrc->Format(); + if (ContainsPalette(pSrcInfo) == FALSE) { + NOTE("No source palette"); + return S_FALSE; + } + + // The number of colours may be zero filled + + DWORD PaletteEntries = pSrcInfo->bmiHeader.biClrUsed; + if (PaletteEntries == 0) { + DWORD Maximum = (1 << pSrcInfo->bmiHeader.biBitCount); + NOTE1("Setting maximum colours (%d)",Maximum); + PaletteEntries = Maximum; + } + + // Make sure the destination has enough room for the palette + + ASSERT(pSrcInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + ASSERT(pSrcInfo->bmiHeader.biClrImportant <= PaletteEntries); + ASSERT(COLORS(pDestInfo) == GetBitmapPalette(pDestInfo)); + pDestInfo->bmiHeader.biClrUsed = PaletteEntries; + pDestInfo->bmiHeader.biClrImportant = pSrcInfo->bmiHeader.biClrImportant; + ULONG BitmapSize = GetBitmapFormatSize(HEADER(pSrcInfo)); + + if (pDest->FormatLength() < BitmapSize) { + NOTE("Reallocating destination"); + pDest->ReallocFormatBuffer(BitmapSize); + } + + // Now copy the palette colours across + + CopyMemory((PVOID) COLORS(pDestInfo), + (PVOID) GetBitmapPalette(pSrcInfo), + PaletteEntries * sizeof(RGBQUAD)); + + return NOERROR; +} + + +// This is normally called when the palette is changed (typically during a +// dynamic format change) to remove any palette we previously installed. We +// replace it (if necessary) in the video window with a standard VGA palette +// that should always be available even if this is a true colour display + +HRESULT CImagePalette::RemovePalette() +{ + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // Do we have a palette to remove + + if (m_hPalette != NULL) { + + if (m_pBaseWindow) { + // Make sure that the window's palette handle matches + // our palette handle. + ASSERT(m_hPalette == m_pBaseWindow->GetPalette()); + + m_pBaseWindow->UnsetPalette(); + } + + EXECUTE_ASSERT(DeleteObject(m_hPalette)); + m_hPalette = NULL; + } + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + return NOERROR; +} + + +// Called to create a palette for the object, the data structure used by GDI +// to describe a palette is a LOGPALETTE, this includes a variable number of +// PALETTEENTRY fields which are the colours, we have to convert the RGBQUAD +// colour fields we are handed in a BITMAPINFO from the media type into these +// This handles extraction of palettes from true colour and YUV media formats + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HPALETTE CImagePalette::MakePalette(const VIDEOINFOHEADER *pVideoInfo, LPSTR szDevice) +{ + ASSERT(ContainsPalette(pVideoInfo) == TRUE); + ASSERT(pVideoInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + const RGBQUAD *pColours; // Pointer to the palette + LOGPALETTE *lp; // Used to create a palette + HPALETTE hPalette; // Logical palette object + + lp = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + SIZE_PALETTE]; + if (lp == NULL) { + return NULL; + } + + // Unfortunately for some hare brained reason a GDI palette entry (a + // PALETTEENTRY structure) is different to a palette entry from a DIB + // format (a RGBQUAD structure) so we have to do the field conversion + // The VIDEOINFO containing the palette may be a true colour type so + // we use GetBitmapPalette to skip over any bit fields if they exist + + lp->palVersion = PALVERSION; + lp->palNumEntries = (USHORT) pHeader->biClrUsed; + if (lp->palNumEntries == 0) lp->palNumEntries = (1 << pHeader->biBitCount); + pColours = GetBitmapPalette(pVideoInfo); + + for (DWORD dwCount = 0;dwCount < lp->palNumEntries;dwCount++) { + lp->palPalEntry[dwCount].peRed = pColours[dwCount].rgbRed; + lp->palPalEntry[dwCount].peGreen = pColours[dwCount].rgbGreen; + lp->palPalEntry[dwCount].peBlue = pColours[dwCount].rgbBlue; + lp->palPalEntry[dwCount].peFlags = 0; + } + + MakeIdentityPalette(lp->palPalEntry, lp->palNumEntries, szDevice); + + // Create a logical palette + + hPalette = CreatePalette(lp); + ASSERT(hPalette != NULL); + delete[] lp; + return hPalette; +} + + +// GDI does a fair job of compressing the palette entries you give it, so for +// example if you have five entries with an RGB colour (0,0,0) it will remove +// all but one of them. When you subsequently draw an image it will map from +// your logical palette to the compressed device palette. This function looks +// to see if it is trying to be an identity palette and if so sets the flags +// field in the PALETTEENTRYs so they remain expanded to boost performance + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::MakeIdentityPalette(PALETTEENTRY *pEntry,INT iColours, LPSTR szDevice) +{ + PALETTEENTRY SystemEntries[10]; // System palette entries + BOOL bIdentityPalette = TRUE; // Is an identity palette + ASSERT(iColours <= iPALETTE_COLORS); // Should have a palette + const int PalLoCount = 10; // First ten reserved colours + const int PalHiStart = 246; // Last VGA palette entries + + // Does this have the full colour range + + if (iColours < 10) { + return S_FALSE; + } + + // Apparently some displays have odd numbers of system colours + + // Get a DC on the right monitor - it's ugly, but this is the way you have + // to do it + HDC hdc; + if (szDevice == NULL || lstrcmpiA(szDevice, "DISPLAY") == 0) + hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdc = CreateDCA(NULL, szDevice, NULL, NULL); + if (NULL == hdc) { + return E_OUTOFMEMORY; + } + INT Reserved = GetDeviceCaps(hdc,NUMRESERVED); + if (Reserved != 20) { + DeleteDC(hdc); + return S_FALSE; + } + + // Compare our palette against the first ten system entries. The reason I + // don't do a memory compare between our two arrays of colours is because + // I am not sure what will be in the flags fields for the system entries + + UINT Result = GetSystemPaletteEntries(hdc,0,PalLoCount,SystemEntries); + UINT Count; + for (Count = 0;Count < Result;Count++) { + if (SystemEntries[Count].peRed != pEntry[Count].peRed || + SystemEntries[Count].peGreen != pEntry[Count].peGreen || + SystemEntries[Count].peBlue != pEntry[Count].peBlue) { + bIdentityPalette = FALSE; + } + } + + // And likewise compare against the last ten entries + + Result = GetSystemPaletteEntries(hdc,PalHiStart,PalLoCount,SystemEntries); + for (Count = 0;Count < Result;Count++) { + if (INT(Count) + PalHiStart < iColours) { + if (SystemEntries[Count].peRed != pEntry[PalHiStart + Count].peRed || + SystemEntries[Count].peGreen != pEntry[PalHiStart + Count].peGreen || + SystemEntries[Count].peBlue != pEntry[PalHiStart + Count].peBlue) { + bIdentityPalette = FALSE; + } + } + } + + // If not an identity palette then return S_FALSE + + DeleteDC(hdc); + if (bIdentityPalette == FALSE) { + return S_FALSE; + } + + // Set the non VGA entries so that GDI doesn't map them + + for (Count = PalLoCount;INT(Count) < min(PalHiStart,iColours);Count++) { + pEntry[Count].peFlags = PC_NOCOLLAPSE; + } + return NOERROR; +} + + +// Constructor initialises the VIDEOINFO we keep storing the current display +// format. The format can be changed at any time, to reset the format held +// by us call the RefreshDisplayType directly (it's a public method). Since +// more than one thread will typically call us (ie window threads resetting +// the type and source threads in the type checking methods) we have a lock + +CImageDisplay::CImageDisplay() +{ + RefreshDisplayType(NULL); +} + + + +// This initialises the format we hold which contains the display device type +// We do a conversion on the display device type in here so that when we start +// type checking input formats we can assume that certain fields have been set +// correctly, an example is when we make the 16 bit mask fields explicit. This +// is normally called when we receive WM_DEVMODECHANGED device change messages + +// The optional szDeviceName parameter tells us which monitor we are interested +// in for a multi monitor system + +HRESULT CImageDisplay::RefreshDisplayType(LPSTR szDeviceName) +{ + CAutoLock cDisplayLock(this); + + // Set the preferred format type + + ZeroMemory((PVOID)&m_Display,sizeof(VIDEOINFOHEADER)+sizeof(TRUECOLORINFO)); + m_Display.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_Display.bmiHeader.biBitCount = FALSE; + + // Get the bit depth of a device compatible bitmap + + // get caps of whichever monitor they are interested in (multi monitor) + HDC hdcDisplay; + // it's ugly, but this is the way you have to do it + if (szDeviceName == NULL || lstrcmpiA(szDeviceName, "DISPLAY") == 0) + hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdcDisplay = CreateDCA(NULL, szDeviceName, NULL, NULL); + if (hdcDisplay == NULL) { + ASSERT(FALSE); + DbgLog((LOG_ERROR,1,TEXT("ACK! Can't get a DC for %hs"), + szDeviceName ? szDeviceName : "")); + return E_FAIL; + } else { + DbgLog((LOG_TRACE,3,TEXT("Created a DC for %s"), + szDeviceName ? szDeviceName : "")); + } + HBITMAP hbm = CreateCompatibleBitmap(hdcDisplay,1,1); + if ( hbm ) + { + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + + // This call will get the colour table or the proper bitfields + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + DeleteObject(hbm); + } + DeleteDC(hdcDisplay); + + // Complete the display type initialisation + + ASSERT(CheckHeaderValidity(&m_Display)); + UpdateFormat(&m_Display); + DbgLog((LOG_TRACE,3,TEXT("New DISPLAY bit depth =%d"), + m_Display.bmiHeader.biBitCount)); + return NOERROR; +} + + +// We assume throughout this code that any bitfields masks are allowed no +// more than eight bits to store a colour component. This checks that the +// bit count assumption is enforced and also makes sure that all the bits +// set are contiguous. We return a boolean TRUE if the field checks out ok + +BOOL CImageDisplay::CheckBitFields(const VIDEOINFO *pInput) +{ + DWORD *pBitFields = (DWORD *) BITMASKS(pInput); + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // First of all work out how many bits are set + + DWORD SetBits = CountSetBits(pBitFields[iColour]); + if (SetBits > iMAXBITS || SetBits == 0) { + NOTE1("Bit fields for component %d invalid",iColour); + return FALSE; + } + + // Next work out the number of zero bits prefix + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + + // This is going to see if all the bits set are contiguous (as they + // should be). We know how much to shift them right by from the + // count of prefix bits. The number of bits set defines a mask, we + // invert this (ones complement) and AND it with the shifted bit + // fields. If the result is NON zero then there are bit(s) sticking + // out the left hand end which means they are not contiguous + + DWORD TestField = pBitFields[iColour] >> PrefixBits; + DWORD Mask = ULONG_MAX << SetBits; + if (TestField & Mask) { + NOTE1("Bit fields for component %d not contiguous",iColour); + return FALSE; + } + } + return TRUE; +} + + +// This counts the number of bits set in the input field + +DWORD CImageDisplay::CountSetBits(DWORD Field) +{ + // This is a relatively well known bit counting algorithm + + DWORD Count = 0; + DWORD init = Field; + + // Until the input is exhausted, count the number of bits + + while (init) { + init = init & (init - 1); // Turn off the bottommost bit + Count++; + } + return Count; +} + + +// This counts the number of zero bits upto the first one set NOTE the input +// field should have been previously checked to ensure there is at least one +// set although if we don't find one set we return the impossible value 32 + +DWORD CImageDisplay::CountPrefixBits(DWORD Field) +{ + DWORD Mask = 1; + DWORD Count = 0; + + while (TRUE) { + if (Field & Mask) { + return Count; + } + Count++; + + ASSERT(Mask != 0x80000000); + if (Mask == 0x80000000) { + return Count; + } + Mask <<= 1; + } +} + + +// This is called to check the BITMAPINFOHEADER for the input type. There are +// many implicit dependancies between the fields in a header structure which +// if we validate now make for easier manipulation in subsequent handling. We +// also check that the BITMAPINFOHEADER matches it's specification such that +// fields likes the number of planes is one, that it's structure size is set +// correctly and that the bitmap dimensions have not been set as negative + +BOOL CImageDisplay::CheckHeaderValidity(const VIDEOINFO *pInput) +{ + // Check the bitmap width and height are not negative. + + if (pInput->bmiHeader.biWidth <= 0 || + pInput->bmiHeader.biHeight <= 0) { + NOTE("Invalid bitmap dimensions"); + return FALSE; + } + + // Check the compression is either BI_RGB or BI_BITFIELDS + + if (pInput->bmiHeader.biCompression != BI_RGB) { + if (pInput->bmiHeader.biCompression != BI_BITFIELDS) { + NOTE("Invalid compression format"); + return FALSE; + } + } + + // If BI_BITFIELDS compression format check the colour depth + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (pInput->bmiHeader.biBitCount != 16) { + if (pInput->bmiHeader.biBitCount != 32) { + NOTE("BI_BITFIELDS not 16/32 bit depth"); + return FALSE; + } + } + } + + // Check the assumptions about the layout of the bit fields + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (CheckBitFields(pInput) == FALSE) { + NOTE("Bit fields are not valid"); + return FALSE; + } + } + + // Are the number of planes equal to one + + if (pInput->bmiHeader.biPlanes != 1) { + NOTE("Number of planes not one"); + return FALSE; + } + + // Check the image size is consistent (it can be zero) + + if (pInput->bmiHeader.biSizeImage != GetBitmapSize(&pInput->bmiHeader)) { + if (pInput->bmiHeader.biSizeImage) { + NOTE("Image size incorrectly set"); + return FALSE; + } + } + + // Check the size of the structure + + if (pInput->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { + NOTE("Size of BITMAPINFOHEADER wrong"); + return FALSE; + } + return CheckPaletteHeader(pInput); +} + + +// This runs a few simple tests against the palette fields in the input to +// see if it looks vaguely correct. The tests look at the number of palette +// colours present, the number considered important and the biCompression +// field which should always be BI_RGB as no other formats are meaningful + +BOOL CImageDisplay::CheckPaletteHeader(const VIDEOINFO *pInput) +{ + // The checks here are for palettised videos only + + if (PALETTISED(pInput) == FALSE) { + if (pInput->bmiHeader.biClrUsed) { + NOTE("Invalid palette entries"); + return FALSE; + } + return TRUE; + } + + // Compression type of BI_BITFIELDS is meaningless for palette video + + if (pInput->bmiHeader.biCompression != BI_RGB) { + NOTE("Palettised video must be BI_RGB"); + return FALSE; + } + + // Check the number of palette colours is correct + + if (pInput->bmiHeader.biClrUsed > PALETTE_ENTRIES(pInput)) { + NOTE("Too many colours in palette"); + return FALSE; + } + + // The number of important colours shouldn't exceed the number used + + if (pInput->bmiHeader.biClrImportant > pInput->bmiHeader.biClrUsed) { + NOTE("Too many important colours"); + return FALSE; + } + return TRUE; +} + + +// Return the format of the video display + +const VIDEOINFO *CImageDisplay::GetDisplayFormat() +{ + return &m_Display; +} + + +// Return TRUE if the display uses a palette + +BOOL CImageDisplay::IsPalettised() +{ + return PALETTISED(&m_Display); +} + + +// Return the bit depth of the current display setting + +WORD CImageDisplay::GetDisplayDepth() +{ + return m_Display.bmiHeader.biBitCount; +} + + +// Initialise the optional fields in a VIDEOINFO. These are mainly to do with +// the source and destination rectangles and palette information such as the +// number of colours present. It simplifies our code just a little if we don't +// have to keep checking for all the different valid permutations in a header +// every time we want to do anything with it (an example would be creating a +// palette). We set the base class media type before calling this function so +// that the media types between the pins match after a connection is made + +HRESULT CImageDisplay::UpdateFormat(VIDEOINFO *pVideoInfo) +{ + ASSERT(pVideoInfo); + + BITMAPINFOHEADER *pbmi = HEADER(pVideoInfo); + SetRectEmpty(&pVideoInfo->rcSource); + SetRectEmpty(&pVideoInfo->rcTarget); + + // Set the number of colours explicitly + + if (PALETTISED(pVideoInfo)) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + pVideoInfo->bmiHeader.biClrUsed = PALETTE_ENTRIES(pVideoInfo); + } + } + + // The number of important colours shouldn't exceed the number used, on + // some displays the number of important colours is not initialised when + // retrieving the display type so we set the colours used correctly + + if (pVideoInfo->bmiHeader.biClrImportant > pVideoInfo->bmiHeader.biClrUsed) { + pVideoInfo->bmiHeader.biClrImportant = PALETTE_ENTRIES(pVideoInfo); + } + + // Change the image size field to be explicit + + if (pVideoInfo->bmiHeader.biSizeImage == 0) { + pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Lots of video rendering filters want code to check proposed formats are ok +// This checks the VIDEOINFO we are passed as a media type. If the media type +// is a valid media type then we return NOERROR otherwise E_INVALIDARG. Note +// however we only accept formats that can be easily displayed in the display +// so if we are on a 16 bit device we will not accept 24 bit images. The one +// complexity is that most displays draw 8 bit palettised images efficiently +// Also if the input format is less colour bits per pixel then we also accept + +HRESULT CImageDisplay::CheckVideoType(const VIDEOINFO *pInput) +{ + // First of all check the VIDEOINFOHEADER looks correct + + if (CheckHeaderValidity(pInput) == FALSE) { + return E_INVALIDARG; + } + + // Virtually all devices support palettised images efficiently + + if (m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount) { + if (PALETTISED(pInput) == TRUE) { + ASSERT(PALETTISED(&m_Display) == TRUE); + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; + } + } + + + // Is the display depth greater than the input format + + if (m_Display.bmiHeader.biBitCount > pInput->bmiHeader.biBitCount) { + NOTE("(Video) Mismatch agreed"); + return NOERROR; + } + + // Is the display depth less than the input format + + if (m_Display.bmiHeader.biBitCount < pInput->bmiHeader.biBitCount) { + NOTE("(Video) Format mismatch"); + return E_INVALIDARG; + } + + + // Both input and display formats are either BI_RGB or BI_BITFIELDS + + ASSERT(m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount); + ASSERT(PALETTISED(pInput) == FALSE); + ASSERT(PALETTISED(&m_Display) == FALSE); + + // BI_RGB 16 bit representation is implicitly RGB555, and likewise BI_RGB + // 24 bit representation is RGB888. So we initialise a pointer to the bit + // fields they really mean and check against the display device format + // This is only going to be called when both formats are equal bits pixel + + const DWORD *pInputMask = GetBitMasks(pInput); + const DWORD *pDisplayMask = GetBitMasks((VIDEOINFO *)&m_Display); + + if (pInputMask[iRED] != pDisplayMask[iRED] || + pInputMask[iGREEN] != pDisplayMask[iGREEN] || + pInputMask[iBLUE] != pDisplayMask[iBLUE]) { + + NOTE("(Video) Bit field mismatch"); + return E_INVALIDARG; + } + + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; +} + + +// Return the bit masks for the true colour VIDEOINFO provided + +const DWORD *CImageDisplay::GetBitMasks(const VIDEOINFO *pVideoInfo) +{ + static const DWORD FailMasks[] = {0,0,0}; + + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return BITMASKS(pVideoInfo); + } + + ASSERT(pVideoInfo->bmiHeader.biCompression == BI_RGB); + + switch (pVideoInfo->bmiHeader.biBitCount) { + case 16: return bits555; + case 24: return bits888; + case 32: return bits888; + default: return FailMasks; + } +} + + +// Check to see if we can support media type pmtIn as proposed by the output +// pin - We first check that the major media type is video and also identify +// the media sub type. Then we thoroughly check the VIDEOINFO type provided +// As well as the contained VIDEOINFO being correct the major type must be +// video, the subtype a recognised video format and the type GUID correct + +HRESULT CImageDisplay::CheckMediaType(const CMediaType *pmtIn) +{ + // Does this have a VIDEOINFOHEADER format block + + const GUID *pFormatType = pmtIn->FormatType(); + if (*pFormatType != FORMAT_VideoInfo) { + NOTE("Format GUID not a VIDEOINFOHEADER"); + return E_INVALIDARG; + } + ASSERT(pmtIn->Format()); + + // Check the format looks reasonably ok + + ULONG Length = pmtIn->FormatLength(); + if (Length < SIZE_VIDEOHEADER) { + NOTE("Format smaller than a VIDEOHEADER"); + return E_FAIL; + } + + VIDEOINFO *pInput = (VIDEOINFO *) pmtIn->Format(); + + // Check the major type is MEDIATYPE_Video + + const GUID *pMajorType = pmtIn->Type(); + if (*pMajorType != MEDIATYPE_Video) { + NOTE("Major type not MEDIATYPE_Video"); + return E_INVALIDARG; + } + + // Check we can identify the media subtype + + const GUID *pSubType = pmtIn->Subtype(); + if (GetBitCount(pSubType) == USHRT_MAX) { + NOTE("Invalid video media subtype"); + return E_INVALIDARG; + } + return CheckVideoType(pInput); +} + + +// Given a video format described by a VIDEOINFO structure we return the mask +// that is used to obtain the range of acceptable colours for this type, for +// example, the mask for a 24 bit true colour format is 0xFF in all cases. A +// 16 bit 5:6:5 display format uses 0xF8, 0xFC and 0xF8, therefore given any +// RGB triplets we can AND them with these fields to find one that is valid + +BOOL CImageDisplay::GetColourMask(DWORD *pMaskRed, + DWORD *pMaskGreen, + DWORD *pMaskBlue) +{ + CAutoLock cDisplayLock(this); + *pMaskRed = 0xFF; + *pMaskGreen = 0xFF; + *pMaskBlue = 0xFF; + + // If this format is palettised then it doesn't have bit fields + + if (m_Display.bmiHeader.biBitCount < 16) { + return FALSE; + } + + // If this is a 24 bit true colour display then it can handle all the + // possible colour component ranges described by a byte. It is never + // allowed for a 24 bit colour depth image to have BI_BITFIELDS set + + if (m_Display.bmiHeader.biBitCount == 24) { + ASSERT(m_Display.bmiHeader.biCompression == BI_RGB); + return TRUE; + } + + // Calculate the mask based on the format's bit fields + + const DWORD *pBitFields = (DWORD *) GetBitMasks((VIDEOINFO *)&m_Display); + DWORD *pOutputMask[] = { pMaskRed, pMaskGreen, pMaskBlue }; + + // We know from earlier testing that there are no more than iMAXBITS + // bits set in the mask and that they are all contiguous. All that + // therefore remains is to shift them into the correct position + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // This works out how many bits there are and where they live + + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + DWORD SetBits = CountSetBits(pBitFields[iColour]); + + // The first shift moves the bit field so that it is right justified + // in the DWORD, after which we then shift it back left which then + // puts the leading bit in the bytes most significant bit position + + *(pOutputMask[iColour]) = pBitFields[iColour] >> PrefixBits; + *(pOutputMask[iColour]) <<= (iMAXBITS - SetBits); + } + return TRUE; +} + + +/* Helper to convert to VIDEOINFOHEADER2 +*/ +STDAPI ConvertVideoInfoToVideoInfo2(AM_MEDIA_TYPE *pmt) +{ + ASSERT(pmt->formattype == FORMAT_VideoInfo); + VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat; + PVOID pvNew = CoTaskMemAlloc(pmt->cbFormat + sizeof(VIDEOINFOHEADER2) - + sizeof(VIDEOINFOHEADER)); + if (pvNew == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(pvNew, pmt->pbFormat, FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + ZeroMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER)); + CopyMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader), + pmt->pbFormat + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pvNew; + pVideoInfo2->dwPictAspectRatioX = (DWORD)pVideoInfo2->bmiHeader.biWidth; + pVideoInfo2->dwPictAspectRatioY = (DWORD)pVideoInfo2->bmiHeader.biHeight; + pmt->formattype = FORMAT_VideoInfo2; + CoTaskMemFree(pmt->pbFormat); + pmt->pbFormat = (PBYTE)pvNew; + pmt->cbFormat += sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER); + return S_OK; +} diff --git a/plugins/gs/gsdx9/baseclasses/winutil.h b/plugins/gs/gsdx9/baseclasses/winutil.h new file mode 100644 index 0000000000..ffe3024e1e --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/winutil.h @@ -0,0 +1,413 @@ +//------------------------------------------------------------------------------ +// File: WinUtil.h +// +// Desc: DirectShow base classes - defines generic handler classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Make sure that you call PrepareWindow to initialise the window after +// the object has been constructed. It is a separate method so that +// derived classes can override useful methods like MessageLoop. Also +// any derived class must call DoneWithWindow in its destructor. If it +// doesn't a message may be retrieved and call a derived class member +// function while a thread is executing the base class destructor code + +#ifndef __WINUTIL__ +#define __WINUTIL__ + +const int DEFWIDTH = 320; // Initial window width +const int DEFHEIGHT = 240; // Initial window height +const int CAPTION = 256; // Maximum length of caption +const int TIMELENGTH = 50; // Maximum length of times +const int PROFILESTR = 128; // Normal profile string +const WORD PALVERSION = 0x300; // GDI palette version +const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version +const COLORREF VIDEO_COLOUR = 0; // Defaults to black background +const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file + +#define WIDTH(x) ((*(x)).right - (*(x)).left) +#define HEIGHT(x) ((*(x)).bottom - (*(x)).top) +#define SHOWSTAGE TEXT("WM_SHOWSTAGE") +#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") +#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") + +class AM_NOVTABLE CBaseWindow +{ +protected: + + HINSTANCE m_hInstance; // Global module instance handle + HWND m_hwnd; // Handle for our window + HDC m_hdc; // Device context for the window + LONG m_Width; // Client window width + LONG m_Height; // Client window height + BOOL m_bActivated; // Has the window been activated + LPTSTR m_pClassName; // Static string holding class name + DWORD m_ClassStyles; // Passed in to our constructor + DWORD m_WindowStyles; // Likewise the initial window styles + DWORD m_WindowStylesEx; // And the extended window styles + UINT m_ShowStageMessage; // Have the window shown with focus + UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST + UINT m_RealizePalette; // Makes us realize our new palette + HDC m_MemoryDC; // Used for fast BitBlt operations + HPALETTE m_hPalette; // Handle to any palette we may have + BYTE m_bNoRealize; // Don't realize palette now + BYTE m_bBackground; // Should we realise in background + BYTE m_bRealizing; // already realizing the palette + CCritSec m_WindowLock; // Serialise window object access + BOOL m_bDoGetDC; // Should this window get a DC + bool m_bDoPostToDestroy; // Use PostMessage to destroy + CCritSec m_PaletteLock; // This lock protects m_hPalette. + // It should be held anytime the + // program use the value of m_hPalette. + + // Maps windows message procedure into C++ methods + friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); + +public: + + CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); + +#ifdef DEBUG + virtual ~CBaseWindow(); +#endif + + virtual HRESULT DoneWithWindow(); + virtual HRESULT PrepareWindow(); + virtual HRESULT InactivateWindow(); + virtual HRESULT ActivateWindow(); + virtual BOOL OnSize(LONG Width, LONG Height); + virtual BOOL OnClose(); + virtual RECT GetDefaultRect(); + virtual HRESULT UninitialiseWindow(); + virtual HRESULT InitialiseWindow(HWND hwnd); + + HRESULT CompleteConnect(); + HRESULT DoCreateWindow(); + + HRESULT PerformanceAlignWindow(); + HRESULT DoShowWindow(LONG ShowCmd); + void PaintWindow(BOOL bErase); + void DoSetWindowForeground(BOOL bFocus); + virtual HRESULT SetPalette(HPALETTE hPalette); + void SetRealize(BOOL bRealize) + { + m_bNoRealize = !bRealize; + } + + // Jump over to the window thread to set the current palette + HRESULT SetPalette(); + void UnsetPalette(void); + virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); + + void LockPaletteLock(); + void UnlockPaletteLock(); + + virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { return FALSE; }; + + // Access our window information + + bool WindowExists(); + LONG GetWindowWidth(); + LONG GetWindowHeight(); + HWND GetWindowHWND(); + HDC GetMemoryHDC(); + HDC GetWindowHDC(); + + #ifdef DEBUG + HPALETTE GetPalette(); + #endif // DEBUG + + // This is the window procedure the derived object should override + + virtual LRESULT OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + // Must be overriden to return class and window styles + + virtual LPTSTR GetClassWindowStyles( + DWORD *pClassStyles, // Class styles + DWORD *pWindowStyles, // Window styles + DWORD *pWindowStylesEx) PURE; // Extended styles +}; + + +// This helper class is entirely subservient to the owning CBaseWindow object +// All this object does is to split out the actual drawing operation from the +// main object (because it was becoming too large). We have a number of entry +// points to set things like the draw device contexts, to implement the actual +// drawing and to set the destination rectangle in the client window. We have +// no critical section locking in this class because we are used exclusively +// by the owning window object which looks after serialising calls into us + +// If you want to use this class make sure you call NotifyAllocator once the +// allocate has been agreed, also call NotifyMediaType with a pointer to a +// NON stack based CMediaType once that has been set (we keep a pointer to +// the original rather than taking a copy). When the palette changes call +// IncrementPaletteVersion (easiest thing to do is to also call this method +// in the SetMediaType method most filters implement). Finally before you +// start rendering anything call SetDrawContext so that we can get the HDCs +// for drawing from the CBaseWindow object we are given during construction + +class CDrawImage +{ +protected: + + CBaseWindow *m_pBaseWindow; // Owning video window object + CRefTime m_StartSample; // Start time for the current sample + CRefTime m_EndSample; // And likewise it's end sample time + HDC m_hdc; // Main window device context + HDC m_MemoryDC; // Offscreen draw device context + RECT m_TargetRect; // Target destination rectangle + RECT m_SourceRect; // Source image rectangle + BOOL m_bStretch; // Do we have to stretch the images + BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs + CMediaType *m_pMediaType; // Pointer to the current format + int m_perfidRenderTime; // Time taken to render an image + LONG m_PaletteVersion; // Current palette version cookie + + // Draw the video images in the window + + void SlowRender(IMediaSample *pMediaSample); + void FastRender(IMediaSample *pMediaSample); + void DisplaySampleTimes(IMediaSample *pSample); + void UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi); + void SetStretchMode(); + +public: + + // Used to control the image drawing + + CDrawImage(CBaseWindow *pBaseWindow); + BOOL DrawImage(IMediaSample *pMediaSample); + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, + LPRECT lprcSrc, LPRECT lprcDst); + void SetDrawContext(); + void SetTargetRect(RECT *pTargetRect); + void SetSourceRect(RECT *pSourceRect); + void GetTargetRect(RECT *pTargetRect); + void GetSourceRect(RECT *pSourceRect); + virtual RECT ScaleSourceRect(const RECT *pSource); + + // Handle updating palettes as they change + + LONG GetPaletteVersion(); + void ResetPaletteVersion(); + void IncrementPaletteVersion(); + + // Tell us media types and allocator assignments + + void NotifyAllocator(BOOL bUsingImageAllocator); + void NotifyMediaType(CMediaType *pMediaType); + BOOL UsingImageAllocator(); + + // Called when we are about to draw an image + + void NotifyStartDraw() { + MSR_START(m_perfidRenderTime); + }; + + // Called when we complete an image rendering + + void NotifyEndDraw() { + MSR_STOP(m_perfidRenderTime); + }; +}; + + +// This is the structure used to keep information about each GDI DIB. All the +// samples we create from our allocator will have a DIBSECTION allocated to +// them. When we receive the sample we know we can BitBlt straight to an HDC + +typedef struct tagDIBDATA { + + LONG PaletteVersion; // Current palette version in use + DIBSECTION DibSection; // Details of DIB section allocated + HBITMAP hBitmap; // Handle to bitmap for drawing + HANDLE hMapping; // Handle to shared memory block + BYTE *pBase; // Pointer to base memory address + +} DIBDATA; + + +// This class inherits from CMediaSample and uses all of it's methods but it +// overrides the constructor to initialise itself with the DIBDATA structure +// When we come to render an IMediaSample we will know if we are using our own +// allocator, and if we are, we can cast the IMediaSample to a pointer to one +// of these are retrieve the DIB section information and hence the HBITMAP + +class CImageSample : public CMediaSample +{ +protected: + + DIBDATA m_DibData; // Information about the DIBSECTION + BOOL m_bInit; // Is the DIB information setup + +public: + + // Constructor + + CImageSample(CBaseAllocator *pAllocator, + TCHAR *pName, + HRESULT *phr, + LPBYTE pBuffer, + LONG length); + + // Maintain the DIB/DirectDraw state + + void SetDIBData(DIBDATA *pDibData); + DIBDATA *GetDIBData(); +}; + + +// This is an allocator based on the abstract CBaseAllocator base class that +// allocates sample buffers in shared memory. The number and size of these +// are determined when the output pin calls Prepare on us. The shared memory +// blocks are used in subsequent calls to GDI CreateDIBSection, once that +// has been done the output pin can fill the buffers with data which will +// then be handed to GDI through BitBlt calls and thereby remove one copy + +class CImageAllocator : public CBaseAllocator +{ +protected: + + CBaseFilter *m_pFilter; // Delegate reference counts to + CMediaType *m_pMediaType; // Pointer to the current format + + // Used to create and delete samples + + HRESULT Alloc(); + void Free(); + + // Manage the shared DIBSECTION and DCI/DirectDraw buffers + + HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); + STDMETHODIMP CheckSizes(ALLOCATOR_PROPERTIES *pRequest); + virtual CImageSample *CreateImageSample(LPBYTE pData,LONG Length); + +public: + + // Constructor and destructor + + CImageAllocator(CBaseFilter *pFilter,TCHAR *pName,HRESULT *phr); +#ifdef DEBUG + ~CImageAllocator(); +#endif + + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + void NotifyMediaType(CMediaType *pMediaType); + + // Agree the number of buffers to be used and their size + + STDMETHODIMP SetProperties( + ALLOCATOR_PROPERTIES *pRequest, + ALLOCATOR_PROPERTIES *pActual); +}; + + +// This class is a fairly specialised helper class for image renderers that +// have to create and manage palettes. The CBaseWindow class looks after +// realising palettes once they have been installed. This class can be used +// to create the palette handles from a media format (which must contain a +// VIDEOINFO structure in the format block). We try to make the palette an +// identity palette to maximise performance and also only change palettes +// if actually required to (we compare palette colours before updating). +// All the methods are virtual so that they can be overriden if so required + +class CImagePalette +{ +protected: + + CBaseWindow *m_pBaseWindow; // Window to realise palette in + CBaseFilter *m_pFilter; // Media filter to send events + CDrawImage *m_pDrawImage; // Object who will be drawing + HPALETTE m_hPalette; // The palette handle we own + +public: + + CImagePalette(CBaseFilter *pBaseFilter, + CBaseWindow *pBaseWindow, + CDrawImage *pDrawImage); + +#ifdef DEBUG + virtual ~CImagePalette(); +#endif + + static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, LPSTR szDevice); + HRESULT RemovePalette(); + static HRESULT MakeIdentityPalette(PALETTEENTRY *pEntry,INT iColours, LPSTR szDevice); + HRESULT CopyPalette(const CMediaType *pSrc,CMediaType *pDest); + BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); + HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,LPSTR szDevice); + + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, LPRECT lprcSrc, LPRECT lprcDst) + { + return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); + } +}; + + +// Another helper class really for video based renderers. Most such renderers +// need to know what the display format is to some degree or another. This +// class initialises itself with the display format. The format can be asked +// for through GetDisplayFormat and various other accessor functions. If a +// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE +// message then it can call RefreshDisplayType to reset that format). Also +// many video renderers will want to check formats as they are proposed by +// source filters. This class provides methods to check formats and only +// accept those video formats that can be efficiently drawn using GDI calls + +class CImageDisplay : public CCritSec +{ +protected: + + // This holds the display format; biSize should not be too big, so we can + // safely use the VIDEOINFO structure + VIDEOINFO m_Display; + + static DWORD CountSetBits(const DWORD Field); + static DWORD CountPrefixBits(const DWORD Field); + static BOOL CheckBitFields(const VIDEOINFO *pInput); + +public: + + // Constructor and destructor + + CImageDisplay(); + + // Used to manage BITMAPINFOHEADERs and the display format + + const VIDEOINFO *GetDisplayFormat(); + HRESULT RefreshDisplayType(LPSTR szDeviceName); + static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); + static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); + BOOL IsPalettised(); + WORD GetDisplayDepth(); + + // Provide simple video format type checking + + HRESULT CheckMediaType(const CMediaType *pmtIn); + HRESULT CheckVideoType(const VIDEOINFO *pInput); + HRESULT UpdateFormat(VIDEOINFO *pVideoInfo); + const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); + + BOOL GetColourMask(DWORD *pMaskRed, + DWORD *pMaskGreen, + DWORD *pMaskBlue); +}; + +// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 +STDAPI ConvertVideoInfoToVideoInfo2(AM_MEDIA_TYPE *pmt); + +#endif // __WINUTIL__ + diff --git a/plugins/gs/gsdx9/baseclasses/wxdebug.cpp b/plugins/gs/gsdx9/baseclasses/wxdebug.cpp new file mode 100644 index 0000000000..f730d1c57f --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxdebug.cpp @@ -0,0 +1,1420 @@ +//------------------------------------------------------------------------------ +// File: WXDebug.cpp +// +// Desc: DirectShow base classes - implements ActiveX system debugging +// facilities. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#define _WINDLL + +#include +#include +#include + +#ifdef DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE +#endif // DEBUG + +#ifdef DEBUG + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +/* For every module and executable we store a debugging level for each of + the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy + to isolate and debug individual modules without seeing everybody elses + spurious debug output. The keys are stored in the registry under the + HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values + NOTE these must be in the same order as their enumeration definition */ + +TCHAR *pKeyNames[] = { + TEXT("TIMING"), // Timing and performance measurements + TEXT("TRACE"), // General step point call tracing + TEXT("MEMORY"), // Memory and object allocation/destruction + TEXT("LOCKING"), // Locking/unlocking of critical sections + TEXT("ERROR"), // Debug error notification + TEXT("CUSTOM1"), + TEXT("CUSTOM2"), + TEXT("CUSTOM3"), + TEXT("CUSTOM4"), + TEXT("CUSTOM5") + }; + +const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); +const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); + +const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories + +HINSTANCE m_hInst; // Module instance handle +TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name +DWORD m_Levels[iMAXLEVELS]; // Debug level per category +CRITICAL_SECTION m_CSDebug; // Controls access to list +DWORD m_dwNextCookie; // Next active object ID +ObjectDesc *pListHead = NULL; // First active object +DWORD m_dwObjectCount; // Active object count +BOOL m_bInit = FALSE; // Have we been initialised +HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here +DWORD dwWaitTimeout = INFINITE; // Default timeout value +DWORD dwTimeOffset; // Time of first DbgLog call +bool g_fUseKASSERT = false; // don't create messagebox +bool g_fDbgInDllEntryPoint = false; +bool g_fAutoRefreshLevels = false; + +const TCHAR *pBaseKey = TEXT("SOFTWARE\\Debug"); +const TCHAR *pGlobalKey = TEXT("GLOBAL"); +static CHAR *pUnknownName = "UNKNOWN"; + +TCHAR *TimeoutName = TEXT("TIMEOUT"); + +/* This sets the instance handle that the debug library uses to find + the module's file name from the Win32 GetModuleFileName function */ + +void WINAPI DbgInitialise(HINSTANCE hInst) +{ + InitializeCriticalSection(&m_CSDebug); + m_bInit = TRUE; + + m_hInst = hInst; + DbgInitModuleName(); + if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) + DebugBreak(); + DbgInitModuleSettings(false); + DbgInitGlobalSettings(true); + dwTimeOffset = timeGetTime(); +} + + +/* This is called to clear up any resources the debug library uses - at the + moment we delete our critical section and the object list. The values we + retrieve from the registry are all done during initialisation but we don't + go looking for update notifications while we are running, if the values + are changed then the application has to be restarted to pick them up */ + +void WINAPI DbgTerminate() +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&m_CSDebug); + m_bInit = FALSE; +} + + +/* This is called by DbgInitLogLevels to read the debug settings + for each logging category for this module from the registry */ + +void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) +{ + LONG lReturn; // Create key return value + LONG lKeyPos; // Current key category + DWORD dwKeySize; // Size of the key value + DWORD dwKeyType; // Receives it's type + DWORD dwKeyValue; // This fields value + + /* Try and read a value for each key position in turn */ + for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[lKeyPos], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwKeyValue = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[lKeyPos], // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwKeyValue, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwKeyValue = 0; + } + } + if(fTakeMax) + { + m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]); + } + else + { + if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { + m_Levels[lKeyPos] = dwKeyValue; + } + } + } + + /* Read the timeout value for catching hangs */ + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + TimeoutName, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwWaitTimeout, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwWaitTimeout = INFINITE; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + TimeoutName, // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwWaitTimeout, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),TimeoutName)); + dwWaitTimeout = INFINITE; + } + } +} + +void WINAPI DbgOutString(LPCTSTR psz) +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + UINT cb = lstrlen(psz); + DWORD dw; +#ifdef UNICODE + CHAR szDest[2048]; + WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); + WriteFile (m_hOutput, szDest, cb, &dw, NULL); +#else + WriteFile (m_hOutput, psz, cb, &dw, NULL); +#endif + } else { + OutputDebugString (psz); + } +} + +/* Called by DbgInitGlobalSettings to setup alternate logging destinations + */ + +void WINAPI DbgInitLogTo ( + HKEY hKey) +{ + LONG lReturn; + DWORD dwKeyType; + DWORD dwKeySize; + TCHAR szFile[MAX_PATH] = {0}; + static const TCHAR cszKey[] = TEXT("LogToFile"); + + dwKeySize = MAX_PATH; + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + cszKey, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) szFile, // Returns the field's value + &dwKeySize); // Number of bytes transferred + + // create an empty key if it does not already exist + // + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) + { + dwKeySize = sizeof(TCHAR); + lReturn = RegSetValueEx( + hKey, // Handle of an open key + cszKey, // Address of subkey name + (DWORD) 0, // Reserved field + REG_SZ, // Type of the key field + (PBYTE)szFile, // Value for the field + dwKeySize); // Size of the field buffer + } + + // if an output-to was specified. try to open it. + // + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle (m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + if (szFile[0] != 0) + { + if (!lstrcmpi(szFile, TEXT("Console"))) { + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + if (m_hOutput == INVALID_HANDLE_VALUE) { + AllocConsole (); + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + } + SetConsoleTitle (TEXT("ActiveX Debug Output")); + } else if (szFile[0] && + lstrcmpi(szFile, TEXT("Debug")) && + lstrcmpi(szFile, TEXT("Debugger")) && + lstrcmpi(szFile, TEXT("Deb"))) + { + m_hOutput = CreateFile(szFile, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (INVALID_HANDLE_VALUE != m_hOutput) + { + static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); + SetFilePointer (m_hOutput, 0, NULL, FILE_END); + DbgOutString (cszBar); + } + } + } +} + + + +/* This is called by DbgInitLogLevels to read the global debug settings for + each logging category for this module from the registry. Normally each + module has it's own values set for it's different debug categories but + setting the global SOFTWARE\Debug\Global applies them to ALL modules */ + +void WINAPI DbgInitGlobalSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hGlobalKey; // Global override key + + /* Construct the global base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not access GLOBAL module key"))); + return; + } + + DbgInitKeyLevels(hGlobalKey, fTakeMax); + RegCloseKey(hGlobalKey); +} + + +/* This sets the debugging log levels for the different categories. We start + by opening (or creating if not already available) the SOFTWARE\Debug key + that all these settings live under. We then look at the global values + set under SOFTWARE\Debug\Global which apply on top of the individual + module settings. We then load the individual module registry settings */ + +void WINAPI DbgInitModuleSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hModuleKey; // Module key handle + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo), TEXT("%s\\%s"),pBaseKey,m_ModuleName); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not access module key"))); + return; + } + + DbgInitLogTo(hModuleKey); + DbgInitKeyLevels(hModuleKey, fTakeMax); + RegCloseKey(hModuleKey); +} + + +/* Initialise the module file name */ + +void WINAPI DbgInitModuleName() +{ + TCHAR FullName[iDEBUGINFO]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(m_hInst,FullName,iDEBUGINFO); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); +} + +struct MsgBoxMsg +{ + HWND hwnd; + TCHAR *szTitle; + TCHAR *szMessage; + DWORD dwFlags; + INT iResult; +}; + +// +// create a thread to call MessageBox(). calling MessageBox() on +// random threads at bad times can confuse the host (eg IE). +// +DWORD WINAPI MsgBoxThread( + LPVOID lpParameter // thread data + ) +{ + MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; + pmsg->iResult = MessageBox( + pmsg->hwnd, + pmsg->szTitle, + pmsg->szMessage, + pmsg->dwFlags); + + return 0; +} + +INT MessageBoxOtherThread( + HWND hwnd, + TCHAR *szTitle, + TCHAR *szMessage, + DWORD dwFlags) +{ + if(g_fDbgInDllEntryPoint) + { + // can't wait on another thread because we have the loader + // lock held in the dll entry point. + return MessageBox(hwnd, szTitle, szMessage, dwFlags); + } + else + { + MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; + DWORD dwid; + HANDLE hThread = CreateThread( + 0, // security + 0, // stack size + MsgBoxThread, + (void *)&msg, // arg + 0, // flags + &dwid); + if(hThread) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + return msg.iResult; + } + + // break into debugger on failure. + return IDCANCEL; + } +} + +/* Displays a message box if the condition evaluated to FALSE */ + +void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore assertion continue execution */ + break; + } + } +} + +/* Displays a message box at a break point */ + +void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore break point continue execution */ + break; + } + } +} + +void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...) +{ + // A debug break point message can have at most 2000 characters if + // ANSI or UNICODE characters are being used. A debug break point message + // can have between 1000 and 2000 double byte characters in it. If a + // particular message needs more characters, then the value of this constant + // should be increased. + const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; + + TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; + + const DWORD MAX_CHARS_IN_BREAK_POINT_MESSAGE = sizeof(szBreakPointMessage) / sizeof(TCHAR); + + va_list va; + va_start( va, szFormatString ); + + HRESULT hr = StringCchVPrintf( szBreakPointMessage, MAX_CHARS_IN_BREAK_POINT_MESSAGE, szFormatString, va ); + + va_end(va); + + if( S_OK != hr ) { + DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because _vsnprintf() failed." ); + return; + } + + ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); +} + + +/* When we initialised the library we stored in the m_Levels array the current + debug output level for this module for each of the five categories. When + some debug logging is sent to us it can be sent with a combination of the + categories (if it is applicable to many for example) in which case we map + the type's categories into their current debug levels and see if any of + them can be accepted. The function looks at each bit position in turn from + the input type field and then compares it's debug level with the modules. + + A level of 0 means that output is always sent to the debugger. This is + due to producing output if the input level is <= m_Levels. +*/ + + +BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) +{ + if(g_fAutoRefreshLevels) + { + // re-read the registry every second. We cannot use RegNotify() to + // notice registry changes because it's not available on win9x. + static DWORD g_dwLastRefresh = 0; + DWORD dwTime = timeGetTime(); + if(dwTime - g_dwLastRefresh > 1000) { + g_dwLastRefresh = dwTime; + + // there's a race condition: multiple threads could update the + // values. plus read and write not synchronized. no harm + // though. + DbgInitModuleSettings(false); + } + } + + + DWORD Mask = 0x01; + + // If no valid bits are set return FALSE + if ((Type & ((1<m_szName = szObjectName; + pObject->m_wszName = wszObjectName; + pObject->m_dwCookie = ++m_dwNextCookie; + pObject->m_pNext = pListHead; + + pListHead = pObject; + m_dwObjectCount++; + + DWORD ObjectCookie = pObject->m_dwCookie; + ASSERT(ObjectCookie); + + if(wszObjectName) { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), + pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), + pObject->m_dwCookie, szObjectName, m_dwObjectCount)); + } + + LeaveCriticalSection(&m_CSDebug); + return ObjectCookie; +} + + +/* This is called by the CBaseObject destructor when an object is about to be + destroyed, we are passed the cookie we returned during construction that + identifies this object. We scan the object list for a matching cookie and + remove the object if successful. We also update the active object count */ + +BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) +{ + /* Grab the list critical section */ + EnterCriticalSection(&m_CSDebug); + + ObjectDesc *pObject = pListHead; + ObjectDesc *pPrevious = NULL; + + /* Scan the object list looking for a cookie match */ + + while (pObject) { + if (pObject->m_dwCookie == dwCookie) { + break; + } + pPrevious = pObject; + pObject = pObject->m_pNext; + } + + if (pObject == NULL) { + DbgBreak("Apparently destroying a bogus object"); + LeaveCriticalSection(&m_CSDebug); + return FALSE; + } + + /* Is the object at the head of the list */ + + if (pPrevious == NULL) { + pListHead = pObject->m_pNext; + } else { + pPrevious->m_pNext = pObject->m_pNext; + } + + /* Delete the object and update the housekeeping information */ + + m_dwObjectCount--; + + if(pObject->m_wszName) { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), + pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), + pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); + } + + delete pObject; + LeaveCriticalSection(&m_CSDebug); + return TRUE; +} + + +/* This runs through the active object list displaying their details */ + +void WINAPI DbgDumpObjectRegister() +{ + TCHAR szInfo[iDEBUGINFO]; + + /* Grab the list critical section */ + + EnterCriticalSection(&m_CSDebug); + ObjectDesc *pObject = pListHead; + + /* Scan the object list displaying the name and cookie */ + + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); + DbgLog((LOG_MEMORY,2,TEXT(""))); + + while (pObject) { + if(pObject->m_wszName) { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); + #else + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); + #endif + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo), FORMAT_STRING, pObject->m_dwCookie, &pObject, pObject->m_wszName); + + } else { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); + #else + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); + #endif + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),FORMAT_STRING,pObject->m_dwCookie, &pObject, pObject->m_szName); + } + DbgLog((LOG_MEMORY,2,szInfo)); + pObject = pObject->m_pNext; + } + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,1,szInfo)); + LeaveCriticalSection(&m_CSDebug); +} + +/* Debug infinite wait stuff */ +DWORD WINAPI DbgWaitForSingleObject(HANDLE h) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); + ASSERT(dwWaitResult == WAIT_OBJECT_0); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} +DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForMultipleObjects(nCount, + lpHandles, + bWaitAll, + dwWaitTimeout); + ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} + +void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) +{ + dwWaitTimeout = dwTimeout; +} + +#endif /* DEBUG */ + +#ifdef _OBJBASE_H_ + + /* Stuff for printing out our GUID names */ + + GUID_STRING_ENTRY g_GuidNames[] = { + #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, + #include + }; + + CGuidNameList GuidNames; + int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); + + char *CGuidNameList::operator [] (const GUID &guid) + { + for (int i = 0; i < g_cGuidNames; i++) { + if (g_GuidNames[i].guid == guid) { + return g_GuidNames[i].szName; + } + } + if (guid == GUID_NULL) { + return "GUID_NULL"; + } + + // !!! add something to print FOURCC guids? + + // shouldn't this print the hex CLSID? + return "Unknown GUID Name"; + } + +#endif /* _OBJBASE_H_ */ + +/* CDisp class - display our data types */ + +// clashes with REFERENCE_TIME +CDisp::CDisp(LONGLONG ll, int Format) +{ + // note: this could be combined with CDisp(LONGLONG) by + // introducing a default format of CDISP_REFTIME + LARGE_INTEGER li; + li.QuadPart = ll; + switch (Format) { + case CDISP_DEC: + { + TCHAR temp[20]; + int pos=20; + temp[--pos] = 0; + int digit; + // always output at least one digit + do { + // Get the rightmost digit - we only need the low word + digit = li.LowPart % 10; + li.QuadPart /= 10; + temp[--pos] = (TCHAR) digit+L'0'; + } while (li.QuadPart); + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), temp+pos); + break; + } + case CDISP_HEX: + default: + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); + } +}; + +CDisp::CDisp(REFCLSID clsid) +{ + WCHAR strClass[CHARS_IN_GUID+1]; + StringFromGUID2(clsid, strClass, sizeof(strClass) / sizeof(strClass[0])); + ASSERT(sizeof(m_String)/sizeof(m_String[0]) >= CHARS_IN_GUID+1); + #ifdef UNICODE + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), strClass); + #else + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), strClass); + #endif +}; + +#ifdef __STREAMS__ +/* Display stuff */ +CDisp::CDisp(CRefTime llTime) +{ + LPTSTR lpsz = m_String; + size_t len = NUMELMS(m_String); + LONGLONG llDiv; + if (llTime < 0) { + llTime = -llTime; + (void)StringCchPrintf(lpsz, len, TEXT("-")); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + } + llDiv = (LONGLONG)24 * 3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d days "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d hrs "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)60 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d mins "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + (void)StringCchPrintf(lpsz, len, TEXT("%d.%3.3d sec"), + (LONG)llTime / 10000000, + (LONG)((llTime % 10000000) / 10000)); +}; + +#endif // __STREAMS__ + + +/* Display pin */ +CDisp::CDisp(IPin *pPin) +{ + PIN_INFO pi; + TCHAR str[MAX_PIN_NAME]; + CLSID clsid; + + if (pPin) { + pPin->QueryPinInfo(&pi); + pi.pFilter->GetClassID(&clsid); + QueryPinInfoReleaseFilter(pi); + #ifndef UNICODE + WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, + str, MAX_PIN_NAME, NULL, NULL); + #else + (void)StringCchCopy(str, NUMELMS(str), pi.achName); + #endif + } else { + (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); + } + + size_t len = lstrlen(str)+64; + m_pString = (PTCHAR) new TCHAR[len]; + if (!m_pString) { + return; + } + + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%S(%s)"); + #else + LPCTSTR FORMAT_STRING = TEXT("%s(%s)"); + #endif + + (void)StringCchPrintf(m_pString, len, FORMAT_STRING, GuidNames[clsid], str); +} + +/* Display filter or pin */ +CDisp::CDisp(IUnknown *pUnk) +{ + IBaseFilter *pf; + HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); + if(SUCCEEDED(hr)) + { + FILTER_INFO fi; + hr = pf->QueryFilterInfo(&fi); + if(SUCCEEDED(hr)) + { + QueryFilterInfoReleaseGraph(fi); + + size_t len = lstrlenW(fi.achName) + 1; + m_pString = new TCHAR[len]; + if(m_pString) + { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%s"); + #else + LPCTSTR FORMAT_STRING = TEXT("%S"); + #endif + + (void)StringCchPrintf(m_pString, len, FORMAT_STRING, fi.achName); + } + } + + pf->Release(); + + return; + } + + IPin *pp; + hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); + if(SUCCEEDED(hr)) + { + CDisp::CDisp(pp); + pp->Release(); + return; + } +} + + +CDisp::~CDisp() +{ +} + +CDispBasic::~CDispBasic() +{ + if (m_pString != m_String) { + delete [] m_pString; + } +} + +CDisp::CDisp(double d) +{ +#ifdef DEBUG + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%.16g"), d); +#else + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); +#endif +} + + +/* If built for debug this will display the media type details. We convert the + major and subtypes into strings and also ask the base classes for a string + description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit + We also display the fields in the BITMAPINFOHEADER structure, this should + succeed as we do not accept input types unless the format is big enough */ + +#ifdef DEBUG +void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn) +{ + + /* Dump the GUID types and a short description */ + + DbgLog((LOG_TRACE,5,TEXT(""))); + DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label, + GuidNames[pmtIn->majortype], + GuidNames[pmtIn->subtype])); + DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); + + /* Dump the generic media types */ + + if (pmtIn->bTemporalCompression) { + DbgLog((LOG_TRACE,5,TEXT("Temporally compressed"))); + } else { + DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed"))); + } + + if (pmtIn->bFixedSizeSamples) { + DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize)); + } else { + DbgLog((LOG_TRACE,5,TEXT("Variable size samples"))); + } + + if (pmtIn->formattype == FORMAT_VideoInfo) { + /* Dump the contents of the BITMAPINFOHEADER structure */ + BITMAPINFOHEADER *pbmi = HEADER(pmtIn->pbFormat); + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; + + DbgLog((LOG_TRACE,5,TEXT("Source rectangle (Left %d Top %d Right %d Bottom %d)"), + pVideoInfo->rcSource.left, + pVideoInfo->rcSource.top, + pVideoInfo->rcSource.right, + pVideoInfo->rcSource.bottom)); + + DbgLog((LOG_TRACE,5,TEXT("Target rectangle (Left %d Top %d Right %d Bottom %d)"), + pVideoInfo->rcTarget.left, + pVideoInfo->rcTarget.top, + pVideoInfo->rcTarget.right, + pVideoInfo->rcTarget.bottom)); + + DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); + if (pbmi->biCompression < 256) { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, pbmi->biCompression)); + } else { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, &pbmi->biCompression)); + } + + DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage)); + DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes)); + DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed)); + + } else if (pmtIn->majortype == MEDIATYPE_Audio) { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"), + GuidNames[pmtIn->subtype])); + + if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) + && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) + { + /* Dump the contents of the WAVEFORMATEX type-specific format structure */ + + WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; + DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag)); + DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels)); + DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); + DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); + + /* PCM uses a WAVEFORMAT and does not have the extra size field */ + + if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { + DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize)); + } + } else { + } + + } else { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + // !!!! should add code to dump wave format, others + } +} + + +void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) +{ + if( !pGraph ) + { + return; + } + + IEnumFilters *pFilters; + + DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); + + if (FAILED(pGraph->EnumFilters(&pFilters))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); + } + + IBaseFilter *pFilter; + ULONG n; + while (pFilters->Next(1, &pFilter, &n) == S_OK) { + FILTER_INFO info; + + if (FAILED(pFilter->QueryFilterInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] -- failed QueryFilterInfo"), pFilter)); + } else { + QueryFilterInfoReleaseGraph(info); + + // !!! should QueryVendorInfo here! + + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] '%ls'"), pFilter, info.achName)); + + IEnumPins *pins; + + if (FAILED(pFilter->EnumPins(&pins))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); + } else { + + IPin *pPin; + while (pins->Next(1, &pPin, &n) == S_OK) { + PIN_INFO info; + + if (FAILED(pPin->QueryPinInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); + } else { + QueryPinInfoReleaseFilter(info); + + IPin *pPinConnected = NULL; + + HRESULT hr = pPin->ConnectedTo(&pPinConnected); + + if (pPinConnected) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] '%ls' [%sput]") + TEXT(" Connected to pin [%x]"), + pPin, info.achName, + info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), + pPinConnected)); + + pPinConnected->Release(); + + // perhaps we should really dump the type both ways as a sanity + // check? + if (info.dir == PINDIR_OUTPUT) { + AM_MEDIA_TYPE mt; + + hr = pPin->ConnectionMediaType(&mt); + + if (SUCCEEDED(hr)) { + DisplayType(TEXT("Connection type"), &mt); + + FreeMediaType(mt); + } + } + } else { + DbgLog((LOG_TRACE,dwLevel, + TEXT(" Pin [%x] '%ls' [%sput]"), + pPin, info.achName, + info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); + + } + } + + pPin->Release(); + + } + + pins->Release(); + } + + } + + pFilter->Release(); + } + + pFilters->Release(); + +} + +#endif + diff --git a/plugins/gs/gsdx9/baseclasses/wxdebug.h b/plugins/gs/gsdx9/baseclasses/wxdebug.h new file mode 100644 index 0000000000..4c967addaf --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxdebug.h @@ -0,0 +1,393 @@ +//------------------------------------------------------------------------------ +// File: WXDebug.h +// +// Desc: DirectShow base classes - provides debugging facilities. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +enum { LOG_TIMING = 0x01, // Timing and performance measurements + LOG_TRACE = 0x02, // General step point call tracing + LOG_MEMORY = 0x04, // Memory and object allocation/destruction + LOG_LOCKING = 0x08, // Locking/unlocking of critical sections + LOG_ERROR = 0x10, // Debug error notification + LOG_CUSTOM1 = 0x20, + LOG_CUSTOM2 = 0x40, + LOG_CUSTOM3 = 0x80, + LOG_CUSTOM4 = 0x100, + LOG_CUSTOM5 = 0x200, +}; + +#define LOG_FORCIBLY_SET 0x80000000 + +enum { CDISP_HEX = 0x01, + CDISP_DEC = 0x02}; + +// For each object created derived from CBaseObject (in debug builds) we +// create a descriptor that holds it's name (statically allocated memory) +// and a cookie we assign it. We keep a list of all the active objects +// we have registered so that we can dump a list of remaining objects + +typedef struct tag_ObjectDesc { + const CHAR *m_szName; + const WCHAR *m_wszName; + DWORD m_dwCookie; + tag_ObjectDesc *m_pNext; +} ObjectDesc; + +#define DLLIMPORT __declspec(dllimport) +#define DLLEXPORT __declspec(dllexport) + +#ifdef DEBUG + + #define NAME(x) TEXT(x) + + // These are used internally by the debug library (PRIVATE) + + void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); + void WINAPI DbgInitGlobalSettings(bool fTakeMax); + void WINAPI DbgInitModuleSettings(bool fTakeMax); + void WINAPI DbgInitModuleName(); + DWORD WINAPI DbgRegisterObjectCreation( + const CHAR *szObjectName, const WCHAR *wszObjectName); + + BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); + + // These are the PUBLIC entry points + + BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetAutoRefreshLevels(bool fAuto); + + // Initialise the library with the module handle + + void WINAPI DbgInitialise(HINSTANCE hInst); + void WINAPI DbgTerminate(); + + void WINAPI DbgDumpObjectRegister(); + + // Display error and logging to the user + + void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...); + + void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); +#ifdef UNICODE + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...); + void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine); + void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); +#endif + void WINAPI DbgOutString(LPCTSTR psz); + + // Debug infinite wait stuff + DWORD WINAPI DbgWaitForSingleObject(HANDLE h); + DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll); + void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); + +#ifdef __strmif_h__ + // Display a media type: Terse at level 2, verbose at level 5 + void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn); + + // Dump lots of information about a filter graph + void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); +#endif + + #define KASSERT(_x_) if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Break on the debugger without putting up a message box + // message goes to debugger instead + + #define KDbgBreak(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // We chose a common name for our ASSERT macro, MFC also uses this name + // So long as the implementation evaluates the condition and handles it + // then we will be ok. Rather than override the behaviour expected we + // will leave whatever first defines ASSERT as the handler (i.e. MFC) + #ifndef ASSERT + #define ASSERT(_x_) if (!(_x_)) \ + DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + #endif + + #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) + + // Put up a message box informing the user of a halt + // condition in the program + + #define DbgBreak(_x_) \ + DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define EXECUTE_ASSERT(_x_) ASSERT(_x_) + #define DbgLog(_x_) DbgLogInfo _x_ + // MFC style trace macros + + #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) + #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) + #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) + #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) + #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) + #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) + +#else + + // Retail builds make public debug functions inert - WARNING the source + // files do not define or build any of the entry points in debug builds + // (public entry points compile to nothing) so if you go trying to call + // any of the private entry points in your source they won't compile + + #define NAME(_x_) ((TCHAR *) NULL) + + #define DbgInitialise(hInst) + #define DbgTerminate() + #define DbgLog(_x_) 0 + #define DbgOutString(psz) + #define DbgAssertAligned( _ptr_, _alignment_ ) 0 + + #define DbgRegisterObjectCreation(pObjectName) + #define DbgRegisterObjectDestruction(dwCookie) + #define DbgDumpObjectRegister() + + #define DbgCheckModuleLevel(Type,Level) + #define DbgSetModuleLevel(Type,Level) + #define DbgSetAutoRefreshLevels(fAuto) + + #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) + #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ + WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) + #define DbgSetWaitTimeout(dwTimeout) + + #define KDbgBreak(_x_) + #define DbgBreak(_x_) + + #define KASSERT(_x_) ((void)0) + #ifndef ASSERT + #define ASSERT(_x_) ((void)0) + #endif + #define EXECUTE_ASSERT(_x_) ((void)(_x_)) + + // MFC style trace macros + + #define NOTE(_x_) ((void)0) + #define NOTE1(_x_,a) ((void)0) + #define NOTE2(_x_,a,b) ((void)0) + #define NOTE3(_x_,a,b,c) ((void)0) + #define NOTE4(_x_,a,b,c,d) ((void)0) + #define NOTE5(_x_,a,b,c,d,e) ((void)0) + + #define DisplayType(label, pmtIn) ((void)0) + #define DumpGraph(pGraph, label) ((void)0) +#endif + + +// Checks a pointer which should be non NULL - can be used as follows. + +#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} + +// HRESULT Foo(VOID *pBar) +// { +// CheckPointer(pBar,E_INVALIDARG) +// } +// +// Or if the function returns a boolean +// +// BOOL Foo(VOID *pBar) +// { +// CheckPointer(pBar,FALSE) +// } + +// These validate pointers when symbol VFWROBUST is defined +// This will normally be defined in debug not retail builds + +#ifdef DEBUG + #define VFWROBUST +#endif + +#ifdef VFWROBUST + + #define ValidateReadPtr(p,cb) \ + {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid read pointer");} + + #define ValidateWritePtr(p,cb) \ + {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid write pointer");} + + #define ValidateReadWritePtr(p,cb) \ + {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} + + #define ValidateStringPtr(p) \ + {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid string pointer");} + + #define ValidateStringPtrA(p) \ + {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid ANSI string pointer");} + + #define ValidateStringPtrW(p) \ + {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid UNICODE string pointer");} + +#else + #define ValidateReadPtr(p,cb) 0 + #define ValidateWritePtr(p,cb) 0 + #define ValidateReadWritePtr(p,cb) 0 + #define ValidateStringPtr(p) 0 + #define ValidateStringPtrA(p) 0 + #define ValidateStringPtrW(p) 0 +#endif + + +#ifdef _OBJBASE_H_ + + // Outputting GUID names. If you want to include the name + // associated with a GUID (eg CLSID_...) then + // + // GuidNames[yourGUID] + // + // Returns the name defined in uuids.h as a string + + typedef struct { + CHAR *szName; + GUID guid; + } GUID_STRING_ENTRY; + + class CGuidNameList { + public: + CHAR *operator [] (const GUID& guid); + }; + + extern CGuidNameList GuidNames; + +#endif + +#ifndef REMIND + // REMIND macro - generates warning as reminder to complete coding + // (eg) usage: + // + // #pragma message (REMIND("Add automation support")) + + + #define QUOTE(x) #x + #define QQUOTE(y) QUOTE(y) + #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str +#endif + +// Method to display objects in a useful format +// +// eg If you want to display a LONGLONG ll in a debug string do (eg) +// +// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); + + +class CDispBasic +{ +public: + CDispBasic() { m_pString = m_String; }; + ~CDispBasic(); +protected: + PTCHAR m_pString; // normally points to m_String... unless too much data + TCHAR m_String[50]; +}; +class CDisp : public CDispBasic +{ +public: + CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form + CDisp(REFCLSID clsid); // Display a GUID + CDisp(double d); // Display a floating point number +#ifdef __strmif_h__ +#ifdef __STREAMS__ + CDisp(CRefTime t); // Display a Reference Time +#endif + CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) + CDisp(IUnknown *pUnk); // Display a filter or pin +#endif // __strmif_h__ + ~CDisp(); + + // Implement cast to (LPCTSTR) as parameter to logger + operator LPCTSTR() + { + return (LPCTSTR)m_pString; + }; +}; + + +#if defined(DEBUG) +class CAutoTrace +{ +private: + const TCHAR* _szBlkName; + const int _level; + static const TCHAR _szEntering[]; + static const TCHAR _szLeaving[]; +public: + CAutoTrace(const TCHAR* szBlkName, const int level = 15) + : _szBlkName(szBlkName), _level(level) + {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} + + ~CAutoTrace() + {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} +}; + +#if defined (__FUNCTION__) + +#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) +#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) + +#else + +#define AMTRACE(_x_) CAutoTrace __trace _x_ +#define AMTRACEFN() + +#endif + +#else + +#define AMTRACE(_x_) +#define AMTRACEFN() + +#endif + +#endif // __WXDEBUG__ + + diff --git a/plugins/gs/gsdx9/baseclasses/wxlist.cpp b/plugins/gs/gsdx9/baseclasses/wxlist.cpp new file mode 100644 index 0000000000..e44a813616 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxlist.cpp @@ -0,0 +1,885 @@ +//------------------------------------------------------------------------------ +// File: WXList.cpp +// +// Desc: DirectShow base classes - implements a non-MFC based generic list +// template class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. + + The list name must not conflict with MFC classes as an + application may use both + + The nodes form a doubly linked, NULL terminated chain with an anchor + block (the list object per se) holding pointers to the first and last + nodes and a count of the nodes. + There is a node cache to reduce the allocation and freeing overhead. + It optionally (determined at construction time) has an Event which is + set whenever the list becomes non-empty and reset whenever it becomes + empty. + It optionally (determined at construction time) has a Critical Section + which is entered during the important part of each operation. (About + all you can do outside it is some parameter checking). + + The node cache is a repository of nodes that are NOT in the list to speed + up storage allocation. Each list has its own cache to reduce locking and + serialising. The list accesses are serialised anyway for a given list - a + common cache would mean that we would have to separately serialise access + of all lists within the cache. Because the cache only stores nodes that are + not in the list, releasing the cache does not release any list nodes. This + means that list nodes can be copied or rechained from one list to another + without danger of creating a dangling reference if the original cache goes + away. + + Questionable design decisions: + 1. Retaining the warts for compatibility + 2. Keeping an element count -i.e. counting whenever we do anything + instead of only when we want the count. + 3. Making the chain pointers NULL terminated. If the list object + itself looks just like a node and the list is kept as a ring then + it reduces the number of special cases. All inserts look the same. +*/ + + +#include + +/* set cursor to the position of each element of list in turn */ +#define INTERNALTRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetHeadPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + +/* set cursor to the position of each element of list in turn + in reverse order +*/ +#define INTERNALREVERSETRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetTailPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +/* Constructor calls a separate initialisation function that + creates a node cache, optionally creates a lock object + and optionally creates a signaling object. + + By default we create a locking object, a DEFAULTCACHE sized + cache but no event object so the list cannot be used in calls + to WaitForSingleObject +*/ +CBaseList::CBaseList(TCHAR *pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(TCHAR *pName) : // Descriptive list name +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#ifdef UNICODE +CBaseList::CBaseList(CHAR *pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(CHAR *pName) : // Descriptive list name +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#endif + +/* The destructor enumerates all the node objects in the list and + in the cache deleting each in turn. We do not do any processing + on the objects that the list holds (i.e. points to) so if they + represent interfaces for example the creator of the list should + ensure that each of them is released before deleting us +*/ +CBaseList::~CBaseList() +{ + /* Delete all our list nodes */ + + RemoveAll(); + +} // destructor + +/* Remove all the nodes from the list but don't do anything + with the objects that each node looks after (this is the + responsibility of the creator). + Aa a last act we reset the signalling event + (if available) to indicate to clients that the list + does not have any entries in it. +*/ +void CBaseList::RemoveAll() +{ + /* Free up all the CNode objects NOTE we don't bother putting the + deleted nodes into the cache as this method is only really called + in serious times of change such as when we are being deleted at + which point the cache will be deleted anway */ + + CNode *pn = m_pFirst; + while (pn) { + CNode *op = pn; + pn = pn->Next(); + delete op; + } + + /* Reset the object count and the list pointers */ + + m_Count = 0; + m_pFirst = m_pLast = NULL; + +} // RemoveAll + + + +/* Return a position enumerator for the entire list. + A position enumerator is a pointer to a node object cast to a + transparent type so all we do is return the head/tail node + pointer in the list. + WARNING because the position is a pointer to a node there is + an implicit assumption for users a the list class that after + deleting an object from the list that any other position + enumerators that you have may be invalid (since the node + may be gone). +*/ +WXLIST_POSITION CBaseList::GetHeadPositionI() const +{ + return (WXLIST_POSITION) m_pFirst; +} // GetHeadPosition + + + +WXLIST_POSITION CBaseList::GetTailPositionI() const +{ + return (WXLIST_POSITION) m_pLast; +} // GetTailPosition + + + +/* Get the number of objects in the list, + Get the lock before accessing the count. + Locking may not be entirely necessary but it has the side effect + of making sure that all operations are complete before we get it. + So for example if a list is being added to this list then that + will have completed in full before we continue rather than seeing + an intermediate albeit valid state +*/ +int CBaseList::GetCountI() const +{ + return m_Count; +} // GetCount + + + +/* Return the object at rp, update rp to the next object from + the list or NULL if you have moved over the last object. + You may still call this function once we return NULL but + we will continue to return a NULL position value +*/ +void *CBaseList::GetNextI(WXLIST_POSITION& rp) const +{ + /* have we reached the end of the list */ + + if (rp == NULL) { + return NULL; + } + + /* Lock the object before continuing */ + + void *pObject; + + /* Copy the original position then step on */ + + CNode *pn = (CNode *) rp; + ASSERT(pn != NULL); + rp = (WXLIST_POSITION) pn->Next(); + + /* Get the object at the original position from the list */ + + pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //GetNext + + + +/* Return the object at p. + Asking for the object at NULL ASSERTs then returns NULL + The object is NOT locked. The list is not being changed + in any way. If another thread is busy deleting the object + then locking would only result in a change from one bad + behaviour to another. +*/ +void *CBaseList::GetI(WXLIST_POSITION p) const +{ + if (p == NULL) { + return NULL; + } + + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + + + +/* Return the first position in the list which holds the given pointer. + Return NULL if it's not found. +*/ +WXLIST_POSITION CBaseList::FindI( void * pObj) const +{ + WXLIST_POSITION pn; + INTERNALTRAVERSELIST(*this, pn){ + if (GetI(pn)==pObj) { + return pn; + } + } + return NULL; +} // Find + + + +/* Remove the first node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +void *CBaseList::RemoveHeadI() +{ + /* All we do is get the head position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((WXLIST_POSITION)m_pFirst); +} // RemoveHead + + + +/* Remove the last node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +void *CBaseList::RemoveTailI() +{ + /* All we do is get the tail position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((WXLIST_POSITION)m_pLast); +} // RemoveTail + + + +/* Remove the pointer to the object in this position from the list. + Deal with all the chain pointers + Return a pointer to the object removed from the list. + The node object that is freed as a result + of this operation is added to the node cache where + it can be used again. + Remove(NULL) is a harmless no-op - but probably is a wart. +*/ +void *CBaseList::RemoveI(WXLIST_POSITION pos) +{ + /* Lock the critical section before continuing */ + + // ASSERT (pos!=NULL); // Removing NULL is to be harmless! + if (pos==NULL) return NULL; + + + CNode *pCurrent = (CNode *) pos; + ASSERT(pCurrent != NULL); + + /* Update the previous node */ + + CNode *pNode = pCurrent->Prev(); + if (pNode == NULL) { + m_pFirst = pCurrent->Next(); + } else { + pNode->SetNext(pCurrent->Next()); + } + + /* Update the following node */ + + pNode = pCurrent->Next(); + if (pNode == NULL) { + m_pLast = pCurrent->Prev(); + } else { + pNode->SetPrev(pCurrent->Prev()); + } + + /* Get the object this node was looking after */ + + void *pObject = pCurrent->GetData(); + + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + + /* Try and add the node object to the cache - + a NULL return code from the cache means we ran out of room. + The cache size is fixed by a constructor argument when the + list is created and defaults to DEFAULTCACHE. + This means that the cache will have room for this many + node objects. So if you have a list of media samples + and you know there will never be more than five active at + any given time of them for example then override the default + constructor + */ + + m_Cache.AddToCache(pCurrent); + + /* If the list is empty then reset the list event */ + + --m_Count; + ASSERT(m_Count >= 0); + return pObject; +} // Remove + + + +/* Add this object to the tail end of our list + Return the new tail position. +*/ + +WXLIST_POSITION CBaseList::AddTailI(void *pObject) +{ + /* Lock the critical section before continuing */ + + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + pNode->SetNext(NULL); + pNode->SetPrev(m_pLast); + + if (m_pLast == NULL) { + m_pFirst = pNode; + } else { + m_pLast->SetNext(pNode); + } + + /* Set the new last node pointer and also increment the number + of list entries, the critical section is unlocked when we + exit the function + */ + + m_pLast = pNode; + ++m_Count; + + return (WXLIST_POSITION) pNode; +} // AddTail(object) + + + +/* Add this object to the head end of our list + Return the new head position. +*/ +WXLIST_POSITION CBaseList::AddHeadI(void *pObject) +{ + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + + /* chain it in (set four pointers) */ + pNode->SetPrev(NULL); + pNode->SetNext(m_pFirst); + + if (m_pFirst == NULL) { + m_pLast = pNode; + } else { + m_pFirst->SetPrev(pNode); + } + m_pFirst = pNode; + + ++m_Count; + + return (WXLIST_POSITION) pNode; +} // AddHead(object) + + + +/* Add all the elements in *pList to the tail of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddTail(CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + */ + WXLIST_POSITION pos = pList->GetHeadPositionI(); + + while (pos) { + if (NULL == AddTailI(pList->GetNextI(pos))) { + return FALSE; + } + } + return TRUE; +} // AddTail(list) + + + +/* Add all the elements in *pList to the head of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddHead(CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + + To avoid reversing the list, traverse it backwards. + */ + + WXLIST_POSITION pos; + + INTERNALREVERSETRAVERSELIST(*pList, pos) { + if (NULL== AddHeadI(pList->GetI(pos))){ + return FALSE; + } + } + return TRUE; +} // AddHead(list) + + + +/* Add the object after position p + p is still valid after the operation. + AddAfter(NULL,x) adds x to the start - same as AddHead + Return the position of the new object, NULL if it failed +*/ +WXLIST_POSITION CBaseList::AddAfterI(WXLIST_POSITION pos, void * pObj) +{ + if (pos==NULL) + return AddHeadI(pObj); + + /* As someone else might be furkling with the list - + Lock the critical section before continuing + */ + CNode *pAfter = (CNode *) pos; + ASSERT(pAfter != NULL); + if (pAfter==m_pLast) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + CNode * pBefore = pAfter->Next(); + ASSERT(pBefore != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (WXLIST_POSITION) pNode; + +} // AddAfter(object) + + + +BOOL CBaseList::AddAfter(WXLIST_POSITION p, CBaseList *pList) +{ + WXLIST_POSITION pos; + INTERNALTRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddAfterI(p, pList->GetI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddAfter(list) + + + +/* Mirror images: + Add the element or list after position p. + p is still valid after the operation. + AddBefore(NULL,x) adds x to the end - same as AddTail +*/ +WXLIST_POSITION CBaseList::AddBeforeI(WXLIST_POSITION pos, void * pObj) +{ + if (pos==NULL) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pBefore = (CNode *) pos; + ASSERT(pBefore != NULL); + if (pBefore==m_pFirst) + return AddHeadI(pObj); + + CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + + CNode * pAfter = pBefore->Prev(); + ASSERT(pAfter != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (WXLIST_POSITION) pNode; + +} // Addbefore(object) + + + +BOOL CBaseList::AddBefore(WXLIST_POSITION p, CBaseList *pList) +{ + WXLIST_POSITION pos; + INTERNALREVERSETRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddBeforeI(p, pList->GetI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddBefore(list) + + + +/* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail +*/ +BOOL CBaseList::MoveToTail + (WXLIST_POSITION pos, CBaseList *pList) +{ + /* Algorithm: + Note that the elements (including their order) in the concatenation + of *pList to the head of *this is invariant. + 1. Count elements to be moved + 2. Join *pList onto the head of this to make one long chain + 3. Set first/Last pointers in *this and *pList + 4. Break the chain at the new place + 5. Adjust counts + 6. Set/Reset any events + */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Prev(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pLast!=NULL) + pList->m_pLast->SetNext(m_pFirst); + if (m_pFirst!=NULL) + m_pFirst->SetPrev(pList->m_pLast); + + + /* set first and last pointers */ + p = (CNode *)pos; + + if (pList->m_pFirst==NULL) + pList->m_pFirst = m_pFirst; + m_pFirst = p->Next(); + if (m_pFirst==NULL) + m_pLast = NULL; + pList->m_pLast = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pFirst!=NULL) + m_pFirst->SetPrev(NULL); + p->SetNext(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToTail + + + +/* Mirror image of MoveToTail: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. +*/ +BOOL CBaseList::MoveToHead + (WXLIST_POSITION pos, CBaseList *pList) +{ + + /* See the comments on the algorithm in MoveToTail */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Next(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pFirst!=NULL) + pList->m_pFirst->SetPrev(m_pLast); + if (m_pLast!=NULL) + m_pLast->SetNext(pList->m_pFirst); + + + /* set first and last pointers */ + p = (CNode *)pos; + + + if (pList->m_pLast==NULL) + pList->m_pLast = m_pLast; + + m_pLast = p->Prev(); + if (m_pLast==NULL) + m_pFirst = NULL; + pList->m_pFirst = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pLast!=NULL) + m_pLast->SetNext(NULL); + p->SetPrev(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToHead + + + +/* Reverse the order of the [pointers to] objects in *this +*/ +void CBaseList::Reverse() +{ + /* algorithm: + The obvious booby trap is that you flip pointers around and lose + addressability to the node that you are going to process next. + The easy way to avoid this is do do one chain at a time. + + Run along the forward chain, + For each node, set the reverse pointer to the one ahead of us. + The reverse chain is now a copy of the old forward chain, including + the NULL termination. + + Run along the reverse chain (i.e. old forward chain again) + For each node set the forward pointer of the node ahead to point back + to the one we're standing on. + The first node needs special treatment, + it's new forward pointer is NULL. + Finally set the First/Last pointers + + */ + CNode * p; + + // Yes we COULD use a traverse, but it would look funny! + p = m_pFirst; + while (p!=NULL) { + CNode * q; + q = p->Next(); + p->SetNext(p->Prev()); + p->SetPrev(q); + p = q; + } + + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; + + +#if 0 // old version + + if (m_pFirst==NULL) return; // empty list + if (m_pFirst->Next()==NULL) return; // single node list + + + /* run along forward chain */ + for ( p = m_pFirst + ; p!=NULL + ; p = p->Next() + ){ + p->SetPrev(p->Next()); + } + + + /* special case first element */ + m_pFirst->SetNext(NULL); // fix the old first element + + + /* run along new reverse chain i.e. old forward chain again */ + for ( p = m_pFirst // start at the old first element + ; p->Prev()!=NULL // while there's a node still to be set + ; p = p->Prev() // work in the same direction as before + ){ + p->Prev()->SetNext(p); + } + + + /* fix forward and reverse pointers + - the triple XOR swap would work but all the casts look hideous */ + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; +#endif + +} // Reverse diff --git a/plugins/gs/gsdx9/baseclasses/wxlist.h b/plugins/gs/gsdx9/baseclasses/wxlist.h new file mode 100644 index 0000000000..3c268c3258 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxlist.h @@ -0,0 +1,543 @@ +//------------------------------------------------------------------------------ +// File: WXList.h +// +// Desc: DirectShow base classes - defines a non-MFC generic template list +// class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + No storage management or copying is done on the objects pointed to. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. An application can cause deadlock with operations + which use two lists by simultaneously calling + list1->Operation(list2) and list2->Operation(list1). So don't! + + The names must not conflict with MFC classes as an application + may use both. + */ + +#ifndef __WXLIST__ +#define __WXLIST__ + + /* A POSITION represents (in some fashion that's opaque) a cursor + on the list that can be set to identify any element. NULL is + a valid value and several operations regard NULL as the position + "one step off the end of the list". (In an n element list there + are n+1 places to insert and NULL is that "n+1-th" value). + The POSITION of an element in the list is only invalidated if + that element is deleted. Move operations may mean that what + was a valid POSITION in one list is now a valid POSITION in + a different list. + + Some operations which at first sight are illegal are allowed as + harmless no-ops. For instance RemoveHead is legal on an empty + list and it returns NULL. This allows an atomic way to test if + there is an element there, and if so, get it. The two operations + AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). + + Single element operations return POSITIONs, non-NULL means it worked. + whole list operations return a BOOL. TRUE means it all worked. + + This definition is the same as the POSITION type for MFCs, so we must + avoid defining it twice. + */ +struct __WXLIST_POSITION { int unused; }; +typedef __WXLIST_POSITION* WXLIST_POSITION; + +const int DEFAULTCACHE = 10; /* Default node object cache size */ + +/* A class representing one node in a list. + Each node knows a pointer to it's adjacent nodes and also a pointer + to the object that it looks after. + All of these pointers can be retrieved or set through member functions. +*/ +class CBaseList +#ifdef DEBUG + : public CBaseObject +#endif +{ + /* Making these classes inherit from CBaseObject does nothing + functionally but it allows us to check there are no memory + leaks in debug builds. + */ + +public: + +#ifdef DEBUG + class CNode : public CBaseObject { +#else + class CNode { +#endif + + CNode *m_pPrev; /* Previous node in the list */ + CNode *m_pNext; /* Next node in the list */ + void *m_pObject; /* Pointer to the object */ + + public: + + /* Constructor - initialise the object's pointers */ + CNode() +#ifdef DEBUG + : CBaseObject(NAME("List node")) +#endif + { + }; + + + /* Return the previous node before this one */ + CNode *Prev() const { return m_pPrev; }; + + + /* Return the next node after this one */ + CNode *Next() const { return m_pNext; }; + + + /* Set the previous node before this one */ + void SetPrev(CNode *p) { m_pPrev = p; }; + + + /* Set the next node after this one */ + void SetNext(CNode *p) { m_pNext = p; }; + + + /* Get the pointer to the object for this node */ + void *GetData() const { return m_pObject; }; + + + /* Set the pointer to the object for this node */ + void SetData(void *p) { m_pObject = p; }; + }; + + class CNodeCache + { + public: + CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), + m_pHead(NULL), + m_iUsed(0) + {}; + ~CNodeCache() { + CNode *pNode = m_pHead; + while (pNode) { + CNode *pCurrent = pNode; + pNode = pNode->Next(); + delete pCurrent; + } + }; + void AddToCache(CNode *pNode) + { + if (m_iUsed < m_iCacheSize) { + pNode->SetNext(m_pHead); + m_pHead = pNode; + m_iUsed++; + } else { + delete pNode; + } + }; + CNode *RemoveFromCache() + { + CNode *pNode = m_pHead; + if (pNode != NULL) { + m_pHead = pNode->Next(); + m_iUsed--; + ASSERT(m_iUsed >= 0); + } else { + ASSERT(m_iUsed == 0); + } + return pNode; + }; + private: + INT m_iCacheSize; + INT m_iUsed; + CNode *m_pHead; + }; + +protected: + + CNode* m_pFirst; /* Pointer to first node in the list */ + CNode* m_pLast; /* Pointer to the last node in the list */ + LONG m_Count; /* Number of nodes currently in the list */ + +private: + + CNodeCache m_Cache; /* Cache of unused node pointers */ + +private: + + /* These override the default copy constructor and assignment + operator for all list classes. They are in the private class + declaration section so that anybody trying to pass a list + object by value will generate a compile time error of + "cannot access the private member function". If these were + not here then the compiler will create default constructors + and assignment operators which when executed first take a + copy of all member variables and then during destruction + delete them all. This must not be done for any heap + allocated data. + */ + CBaseList(const CBaseList &refList); + CBaseList &operator=(const CBaseList &refList); + +public: + + CBaseList(TCHAR *pName, + INT iItems); + + CBaseList(TCHAR *pName); +#ifdef UNICODE + CBaseList(CHAR *pName, + INT iItems); + + CBaseList(CHAR *pName); +#endif + ~CBaseList(); + + /* Remove all the nodes from *this i.e. make the list empty */ + void RemoveAll(); + + + /* Return a cursor which identifies the first element of *this */ + WXLIST_POSITION GetHeadPositionI() const; + + + /* Return a cursor which identifies the last element of *this */ + WXLIST_POSITION GetTailPositionI() const; + + + /* Return the number of objects in *this */ + int GetCountI() const; + +protected: + /* Return the pointer to the object at rp, + Update rp to the next node in *this + but make it NULL if it was at the end of *this. + This is a wart retained for backwards compatibility. + GetPrev is not implemented. + Use Next, Prev and Get separately. + */ + void *GetNextI(WXLIST_POSITION& rp) const; + + + /* Return a pointer to the object at p + Asking for the object at NULL will return NULL harmlessly. + */ + void *GetI(WXLIST_POSITION p) const; + +public: + /* return the next / prev position in *this + return NULL when going past the end/start. + Next(NULL) is same as GetHeadPosition() + Prev(NULL) is same as GetTailPosition() + An n element list therefore behaves like a n+1 element + cycle with NULL at the start/end. + + !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. + + Some reasons are: + 1. For a list of n items there are n+1 positions to insert + These are conveniently encoded as the n POSITIONs and NULL. + 2. If you are keeping a list sorted (fairly common) and you + search forward for an element to insert before and don't + find it you finish up with NULL as the element before which + to insert. You then want that NULL to be a valid WXLIST_POSITION + so that you can insert before it and you want that insertion + point to mean the (n+1)-th one that doesn't have a WXLIST_POSITION. + (symmetrically if you are working backwards through the list). + 3. It simplifies the algebra which the methods generate. + e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) + in ALL cases. All the other arguments probably are reflections + of the algebraic point. + */ + WXLIST_POSITION Next(WXLIST_POSITION pos) const + { + if (pos == NULL) { + return (WXLIST_POSITION) m_pFirst; + } + CNode *pn = (CNode *) pos; + return (WXLIST_POSITION) pn->Next(); + } //Next + + // See Next + WXLIST_POSITION Prev(WXLIST_POSITION pos) const + { + if (pos == NULL) { + return (WXLIST_POSITION) m_pLast; + } + CNode *pn = (CNode *) pos; + return (WXLIST_POSITION) pn->Prev(); + } //Prev + + + /* Return the first position in *this which holds the given + pointer. Return NULL if the pointer was not not found. + */ +protected: + WXLIST_POSITION FindI( void * pObj) const; + + /* Remove the first node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + void *RemoveHeadI(); + + + /* Remove the last node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + void *RemoveTailI(); + + + /* Remove the node identified by p from the list (deletes the pointer + to its object from the list, does not free the object itself). + Asking to Remove the object at NULL will harmlessly return NULL. + Return the pointer to the object removed. + */ + void *RemoveI(WXLIST_POSITION p); + + /* Add single object *pObj to become a new last element of the list. + Return the new tail position, NULL if it fails. + If you are adding a COM objects, you might want AddRef it first. + Other existing POSITIONs in *this are still valid + */ + WXLIST_POSITION AddTailI(void * pObj); +public: + + + /* Add all the elements in *pList to the tail of *this. + This duplicates all the nodes in *pList (i.e. duplicates + all its pointers to objects). It does not duplicate the objects. + If you are adding a list of pointers to a COM object into the list + it's a good idea to AddRef them all it when you AddTail it. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. + Existing POSITIONs in *this are still valid + + If you actually want to MOVE the elements, use MoveToTail instead. + */ + BOOL AddTail(CBaseList *pList); + + + /* Mirror images of AddHead: */ + + /* Add single object to become a new first element of the list. + Return the new head position, NULL if it fails. + Existing POSITIONs in *this are still valid + */ +protected: + WXLIST_POSITION AddHeadI(void * pObj); +public: + + /* Add all the elements in *pList to the head of *this. + Same warnings apply as for AddTail. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some of the objects may have been added. + + If you actually want to MOVE the elements, use MoveToHead instead. + */ + BOOL AddHead(CBaseList *pList); + + + /* Add the object *pObj to *this after position p in *this. + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return the position of the object added, NULL if it failed. + Existing POSITIONs in *this are undisturbed, including p. + */ +protected: + WXLIST_POSITION AddAfterI(WXLIST_POSITION p, void * pObj); +public: + + /* Add the list *pList to *this after position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddAfter(WXLIST_POSITION p, CBaseList *pList); + + + /* Mirror images: + Add the object *pObj to this-List after position p in *this. + AddBefore(NULL,x) adds x to the end - equivalent to AddTail + Return the position of the new object, NULL if it fails + Existing POSITIONs in *this are undisturbed, including p. + */ + protected: + WXLIST_POSITION AddBeforeI(WXLIST_POSITION p, void * pObj); + public: + + /* Add the list *pList to *this before position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddBefore(WXLIST_POSITION p, CBaseList *pList); + + + /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) + even in cases where p is NULL or Next(p) is NULL. + Similarly for mirror images etc. + This may make it easier to argue about programs. + */ + + + + /* The following operations do not copy any elements. + They move existing blocks of elements around by switching pointers. + They are fairly efficient for long lists as for short lists. + (Alas, the Count slows things down). + + They split the list into two parts. + One part remains as the original list, the other part + is appended to the second list. There are eight possible + variations: + Split the list {after/before} a given element + keep the {head/tail} portion in the original list + append the rest to the {head/tail} of the new list. + + Since After is strictly equivalent to Before Next + we are not in serious need of the Before/After variants. + That leaves only four. + + If you are processing a list left to right and dumping + the bits that you have processed into another list as + you go, the Tail/Tail variant gives the most natural result. + If you are processing in reverse order, Head/Head is best. + + By using NULL positions and empty lists judiciously either + of the other two can be built up in two operations. + + The definition of NULL (see Next/Prev etc) means that + degenerate cases include + "move all elements to new list" + "Split a list into two lists" + "Concatenate two lists" + (and quite a few no-ops) + + !!WARNING!! The type checking won't buy you much if you get list + positions muddled up - e.g. use a WXLIST_POSITION that's in a different + list and see what a mess you get! + */ + + /* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op, returns NULL + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail + */ + BOOL MoveToTail(WXLIST_POSITION pos, CBaseList *pList); + + + /* Mirror image: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op, returns NULL + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. + */ + BOOL MoveToHead(WXLIST_POSITION pos, CBaseList *pList); + + + /* Reverse the order of the [pointers to] objects in *this + */ + void Reverse(); + + + /* set cursor to the position of each element of list in turn */ + #define TRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetHeadPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + + /* set cursor to the position of each element of list in turn + in reverse order + */ + #define REVERSETRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetTailPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +}; // end of class declaration + +template class CGenericList : public CBaseList +{ +public: + CGenericList(TCHAR *pName, + INT iItems, + BOOL bLock = TRUE, + BOOL bAlert = FALSE) : + CBaseList(pName, iItems) { + UNREFERENCED_PARAMETER(bAlert); + UNREFERENCED_PARAMETER(bLock); + }; + CGenericList(TCHAR *pName) : + CBaseList(pName) { + }; + + WXLIST_POSITION GetHeadPosition() const { return (WXLIST_POSITION)m_pFirst; } + WXLIST_POSITION GetTailPosition() const { return (WXLIST_POSITION)m_pLast; } + int GetCount() const { return m_Count; } + + OBJECT *GetNext(WXLIST_POSITION& rp) const { return (OBJECT *) GetNextI(rp); } + + OBJECT *Get(WXLIST_POSITION p) const { return (OBJECT *) GetI(p); } + OBJECT *GetHead() const { return Get(GetHeadPosition()); } + + OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } + + OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } + + OBJECT *Remove(WXLIST_POSITION p) { return (OBJECT *) RemoveI(p); } + WXLIST_POSITION AddBefore(WXLIST_POSITION p, OBJECT * pObj) { return AddBeforeI(p, pObj); } + WXLIST_POSITION AddAfter(WXLIST_POSITION p, OBJECT * pObj) { return AddAfterI(p, pObj); } + WXLIST_POSITION AddHead(OBJECT * pObj) { return AddHeadI(pObj); } + WXLIST_POSITION AddTail(OBJECT * pObj) { return AddTailI(pObj); } + BOOL AddTail(CGenericList *pList) + { return CBaseList::AddTail((CBaseList *) pList); } + BOOL AddHead(CGenericList *pList) + { return CBaseList::AddHead((CBaseList *) pList); } + BOOL AddAfter(WXLIST_POSITION p, CGenericList *pList) + { return CBaseList::AddAfter(p, (CBaseList *) pList); }; + BOOL AddBefore(WXLIST_POSITION p, CGenericList *pList) + { return CBaseList::AddBefore(p, (CBaseList *) pList); }; + WXLIST_POSITION Find( OBJECT * pObj) const { return FindI(pObj); } +}; // end of class declaration + + + +/* These define the standard list types */ + +typedef CGenericList CBaseObjectList; +typedef CGenericList CBaseInterfaceList; + +#endif /* __WXLIST__ */ + diff --git a/plugins/gs/gsdx9/baseclasses/wxutil.cpp b/plugins/gs/gsdx9/baseclasses/wxutil.cpp new file mode 100644 index 0000000000..fe363fd6d9 --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxutil.cpp @@ -0,0 +1,1240 @@ +//------------------------------------------------------------------------------ +// File: WXUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include + +// +// Declare function from largeint.h we need so that PPC can build +// + +// +// Enlarged integer divide - 64-bits / 32-bits > 32-bits +// + +#ifndef _X86_ + +#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) + +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + // return remainder if necessary + if (Remainder != NULL) + *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); + return (ULONG)(LLtoU64(Dividend) / Divisor); +} + +#else +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + ULONG ulResult; + _asm { + mov eax,Dividend.LowPart + mov edx,Dividend.HighPart + mov ecx,Remainder + div Divisor + or ecx,ecx + jz short label + mov [ecx],edx +label: + mov ulResult,eax + } + return ulResult; +} +#endif + +// --- CAMEvent ----------------------- +CAMEvent::CAMEvent(BOOL fManualReset) +{ + m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); +} + +CAMEvent::~CAMEvent() +{ + if (m_hEvent) { + EXECUTE_ASSERT(CloseHandle(m_hEvent)); + } +} + + +// --- CAMMsgEvent ----------------------- +// One routine. The rest is handled in CAMEvent + +BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) +{ + // wait for the event to be signalled, or for the + // timeout (in MS) to expire. allow SENT messages + // to be processed while we wait + DWORD dwWait; + DWORD dwStartTime; + + // set the waiting period. + DWORD dwWaitTime = dwTimeout; + + // the timeout will eventually run down as we iterate + // processing messages. grab the start time so that + // we can calculate elapsed times. + if (dwWaitTime != INFINITE) { + dwStartTime = timeGetTime(); + } + + do { + dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); + if (dwWait == WAIT_OBJECT_0 + 1) { + MSG Message; + PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); + + // If we have an explicit length of time to wait calculate + // the next wake up point - which might be now. + // If dwTimeout is INFINITE, it stays INFINITE + if (dwWaitTime != INFINITE) { + + DWORD dwElapsed = timeGetTime()-dwStartTime; + + dwWaitTime = + (dwElapsed >= dwTimeout) + ? 0 // wake up with WAIT_TIMEOUT + : dwTimeout-dwElapsed; + } + } + } while (dwWait == WAIT_OBJECT_0 + 1); + + // return TRUE if we woke on the event handle, + // FALSE if we timed out. + return (dwWait == WAIT_OBJECT_0); +} + +// --- CAMThread ---------------------- + + +CAMThread::CAMThread() + : m_EventSend(TRUE) // must be manual-reset for CheckRequest() +{ + m_hThread = NULL; +} + +CAMThread::~CAMThread() { + Close(); +} + + +// when the thread starts, it calls this function. We unwrap the 'this' +//pointer and call ThreadProc. +DWORD WINAPI +CAMThread::InitialThreadProc(LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + if(FAILED(hrCoInit)) { + DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); + } + + CAMThread * pThread = (CAMThread *) pv; + + HRESULT hr = pThread->ThreadProc(); + + if(SUCCEEDED(hrCoInit)) { + CoUninitialize(); + } + + return hr; +} + +BOOL +CAMThread::Create() +{ + DWORD threadid; + + CAutoLock lock(&m_AccessLock); + + if (ThreadExists()) { + return FALSE; + } + + m_hThread = CreateThread( + NULL, + 0, + CAMThread::InitialThreadProc, + this, + 0, + &threadid); + + if (!m_hThread) { + return FALSE; + } + + return TRUE; +} + +DWORD +CAMThread::CallWorker(DWORD dwParam) +{ + // lock access to the worker thread for scope of this object + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return (DWORD) E_FAIL; + } + + // set the parameter + m_dwParam = dwParam; + + // signal the worker thread + m_EventSend.Set(); + + // wait for the completion to be signalled + m_EventComplete.Wait(); + + // done - this is the thread's return value + return m_dwReturnVal; +} + +// Wait for a request from the client +DWORD +CAMThread::GetRequest() +{ + m_EventSend.Wait(); + return m_dwParam; +} + +// is there a request? +BOOL +CAMThread::CheckRequest(DWORD * pParam) +{ + if (!m_EventSend.Check()) { + return FALSE; + } else { + if (pParam) { + *pParam = m_dwParam; + } + return TRUE; + } +} + +// reply to the request +void +CAMThread::Reply(DWORD dw) +{ + m_dwReturnVal = dw; + + // The request is now complete so CheckRequest should fail from + // now on + // + // This event should be reset BEFORE we signal the client or + // the client may Set it before we reset it and we'll then + // reset it (!) + + m_EventSend.Reset(); + + // Tell the client we're finished + + m_EventComplete.Set(); +} + +HRESULT CAMThread::CoInitializeHelper() +{ + // call CoInitializeEx and tell OLE not to create a window (this + // thread probably won't dispatch messages and will hang on + // broadcast msgs o/w). + // + // If CoInitEx is not available, threads that don't call CoCreate + // aren't affected. Threads that do will have to handle the + // failure. Perhaps we should fall back to CoInitialize and risk + // hanging? + // + + // older versions of ole32.dll don't have CoInitializeEx + + HRESULT hr = E_FAIL; + HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); + if(hOle) + { + typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( + LPVOID pvReserved, DWORD dwCoInit); + PCoInitializeEx pCoInitializeEx = + (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); + if(pCoInitializeEx) + { + hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); + } + } + else + { + // caller must load ole32.dll + DbgBreak("couldn't locate ole32.dll"); + } + + return hr; +} + + +// destructor for CMsgThread - cleans up any messages left in the +// queue when the thread exited +CMsgThread::~CMsgThread() +{ + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } + + WXLIST_POSITION pos = m_ThreadQueue.GetHeadPosition(); + while (pos) { + CMsg * pMsg = m_ThreadQueue.GetNext(pos); + delete pMsg; + } + m_ThreadQueue.RemoveAll(); + + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } +} + +BOOL +CMsgThread::CreateThread( + ) +{ + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + return FALSE; + } + + m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, + (LPVOID)this, 0, &m_ThreadId); + return m_hThread != NULL; +} + + +// This is the threads message pump. Here we get and dispatch messages to +// clients thread proc until the client refuses to process a message. +// The client returns a non-zero value to stop the message pump, this +// value becomes the threads exit code. + +DWORD WINAPI +CMsgThread::DefaultThreadProc( + LPVOID lpParam + ) +{ + CMsgThread *lpThis = (CMsgThread *)lpParam; + CMsg msg; + LRESULT lResult; + + // !!! + CoInitialize(NULL); + + // allow a derived class to handle thread startup + lpThis->OnThreadInit(); + + do { + lpThis->GetThreadMsg(&msg); + lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, + msg.lpParam, msg.pEvent); + } while (lResult == 0L); + + // !!! + CoUninitialize(); + + return (DWORD)lResult; +} + + +// Block until the next message is placed on the list m_ThreadQueue. +// copies the message to the message pointed to by *pmsg +void +CMsgThread::GetThreadMsg(CMsg *msg) +{ + CMsg * pmsg = NULL; + + // keep trying until a message appears + while (TRUE) { + { + CAutoLock lck(&m_Lock); + pmsg = m_ThreadQueue.RemoveHead(); + if (pmsg == NULL) { + m_lWaiting++; + } else { + break; + } + } + // the semaphore will be signalled when it is non-empty + WaitForSingleObject(m_hSem, INFINITE); + } + // copy fields to caller's CMsg + *msg = *pmsg; + + // this CMsg was allocated by the 'new' in PutThreadMsg + delete pmsg; + +} + + +// NOTE: as we need to use the same binaries on Win95 as on NT this code should +// be compiled WITHOUT unicode being defined. Otherwise we will not pick up +// these internal routines and the binary will not run on Win95. + +#ifndef UNICODE +// Windows 95 doesn't implement this, so we provide an implementation. +// LPWSTR +// WINAPI +// lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ) +// { +// LPWSTR lpReturn = lpString1; +// while (*lpString1++ = *lpString2++); +// +// return lpReturn; +// } + +// Windows 95 doesn't implement this, so we provide an implementation. +LPWSTR +WINAPI +lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ) +{ + ASSERT(iMaxLength); + LPWSTR lpReturn = lpString1; + if (iMaxLength) { + while (--iMaxLength && (*lpString1++ = *lpString2++)); + + // If we ran out of room (which will be the case if + // iMaxLength is now 0) we still need to terminate the + // string. + if (!iMaxLength) *lpString1 = L'\0'; + } + return lpReturn; +} + +int +WINAPI +lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + do { + WCHAR c1 = *lpString1; + WCHAR c2 = *lpString2; + if (c1 != c2) + return (int) c1 - (int) c2; + } while (*lpString1++ && *lpString2++); + return 0; +} + + +int +WINAPI +lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + do { + WCHAR c1 = *lpString1; + WCHAR c2 = *lpString2; + if (c1 >= L'A' && c1 <= L'Z') + c1 -= (WCHAR) (L'A' - L'a'); + if (c2 >= L'A' && c2 <= L'Z') + c2 -= (WCHAR) (L'A' - L'a'); + + if (c1 != c2) + return (int) c1 - (int) c2; + } while (*lpString1++ && *lpString2++); + + return 0; +} + + +int +WINAPI +lstrlenWInternal( + LPCWSTR lpString + ) +{ + int i = -1; + while (*(lpString+(++i))) + ; + return i; +} + + +// int WINAPIV wsprintfWInternal(LPWSTR wszOut, LPCWSTR pszFmt, ...) +// { +// char fmt[256]; // !!! +// char ach[256]; // !!! +// int i; +// +// va_list va; +// va_start(va, pszFmt); +// WideCharToMultiByte(GetACP(), 0, pszFmt, -1, fmt, 256, NULL, NULL); +// (void)StringCchVPrintf(ach, NUMELMS(ach), fmt, va); +// i = lstrlenA(ach); +// va_end(va); +// +// MultiByteToWideChar(CP_ACP, 0, ach, -1, wszOut, i+1); +// +// return i; +// } +#else + +// need to provide the implementations in unicode for non-unicode +// builds linking with the unicode strmbase.lib +//LPWSTR WINAPI lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ) +//{ +// return lstrcpyW(lpString1, lpString2); +//} + +LPWSTR WINAPI lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ) +{ + return lstrcpynW(lpString1, lpString2, iMaxLength); +} + +int WINAPI lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + return lstrcmpW(lpString1, lpString2); +} + + +int WINAPI lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + return lstrcmpiW(lpString1, lpString2); +} + + +int WINAPI lstrlenWInternal( + LPCWSTR lpString + ) +{ + return lstrlenW(lpString); +} + + +//int WINAPIV wsprintfWInternal( +// LPWSTR wszOut, LPCWSTR pszFmt, ...) +//{ +// va_list va; +// va_start(va, pszFmt); +// int i = wvsprintfW(wszOut, pszFmt, va); +// va_end(va); +// return i; +//} +#endif + + +// Helper function - convert int to WSTR +void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len) +{ +#ifdef UNICODE + (void)StringCchPrintf(wstr, len, L"%d", i); +#else + TCHAR temp[32]; + (void)StringCchPrintf(temp, NUMELMS(temp), "%d", i); + MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, int(len) ); +#endif +} // IntToWstr + + +#if 0 +void * memchrInternal(const void *pv, int c, size_t sz) +{ + BYTE *pb = (BYTE *) pv; + while (sz--) { + if (*pb == c) + return (void *) pb; + pb++; + } + return NULL; +} +#endif + + +#define MEMORY_ALIGNMENT 4 +#define MEMORY_ALIGNMENT_LOG2 2 +#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 + +void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) +{ + void * ret = dst; + +#ifdef _X86_ + if (dst <= src || (char *)dst >= ((char *)src + count)) { + + /* + * Non-Overlapping Buffers + * copy from lower addresses to higher addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + cld + mov edx,ecx + and edx,MEMORY_ALIGNMENT_MASK + shr ecx,MEMORY_ALIGNMENT_LOG2 + rep movsd + or ecx,edx + jz memmove_done + rep movsb +memmove_done: + } + } + else { + + /* + * Overlapping Buffers + * copy from higher addresses to lower addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + std + add esi,ecx + add edi,ecx + dec esi + dec edi + rep movsb + cld + } + } +#else + MoveMemory(dst, src, count); +#endif + + return ret; +} + +/* Arithmetic functions to help with time format conversions +*/ + +#ifdef _M_ALPHA +// work around bug in version 12.00.8385 of the alpha compiler where +// UInt32x32To64 sign-extends its arguments (?) +#undef UInt32x32To64 +#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) +#endif + +/* Compute (a * b + d) / c */ +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) +{ + /* Compute the absolute values to avoid signed arithmetic problems */ + ULARGE_INTEGER ua, ub; + DWORDLONG uc; + + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); + uc = (DWORDLONG)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p[2]; + p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); + + /* This next computation cannot overflow into p[1].HighPart because + the max number we can compute here is: + + (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart + (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 + + == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) + == 2 ** 96 - 2 ** 33 + 1 + < 2 ** 96 + */ + + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + + UInt32x32To64(ua.HighPart, ub.LowPart) + + p[0].HighPart; + p[0].HighPart = x.LowPart; + p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; + + if (d != 0) { + ULARGE_INTEGER ud[2]; + if (bSign) { + ud[0].QuadPart = (DWORDLONG)(-d); + if (d > 0) { + /* -d < 0 */ + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } else { + ud[0].QuadPart = (DWORDLONG)d; + if (d < 0) { + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; + p[0].LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; + p[0].HighPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add MS DWORDLONGs - no carry expected */ + p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p[1].HighPart < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p[0].QuadPart = ~p[0].QuadPart; + p[1].QuadPart = ~p[1].QuadPart; + p[0].QuadPart += 1; + p[1].QuadPart += (p[0].QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p[1].QuadPart) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + DWORDLONG ullResult; + + /* Do the division */ + /* If the dividend is a DWORD_LONG use the compiler */ + if (p[1].QuadPart == 0) { + ullResult = p[0].QuadPart / uc; + return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; + } + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER ulic; + ulic.QuadPart = uc; + if (ulic.HighPart == 0) { + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = (DWORD)uc; + // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); + uliDividend.HighPart = p[1].LowPart; + uliDividend.LowPart = p[0].HighPart; +#ifndef USE_LARGEINT + uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); + p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); + uliResult.LowPart = 0; + uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; +#else + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p[0].HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p[0], + dwDivisor, + NULL); +#endif + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; + } + + + ullResult = 0; + + /* OK - do long division */ + for (int i = 0; i < 64; i++) { + ullResult <<= 1; + + /* Shift 128 bit p left 1 */ + p[1].QuadPart <<= 1; + if ((p[0].HighPart & 0x80000000) != 0) { + p[1].LowPart++; + } + p[0].QuadPart <<= 1; + + /* Compare */ + if (uc <= p[1].QuadPart) { + p[1].QuadPart -= uc; + ullResult += 1; + } + } + + return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; +} + +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) +{ + ULARGE_INTEGER ua; + DWORD ub; + DWORD uc; + + /* Compute the absolute values to avoid signed arithmetic problems */ + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub = (DWORD)(b >= 0 ? b : -b); + uc = (DWORD)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p0; + DWORD p1; + p0.QuadPart = UInt32x32To64(ua.LowPart, ub); + + if (ua.HighPart != 0) { + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; + p0.HighPart = x.LowPart; + p1 = x.HighPart; + } else { + p1 = 0; + } + + if (d != 0) { + ULARGE_INTEGER ud0; + DWORD ud1; + + if (bSign) { + // + // Cast d to LONGLONG first otherwise -0x80000000 sign extends + // incorrectly + // + ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); + if (d > 0) { + /* -d < 0 */ + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } else { + ud0.QuadPart = (DWORDLONG)d; + if (d < 0) { + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; + p0.LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; + p0.HighPart = uliTotal.LowPart; + + /* Add MS DWORDLONGs - no carry expected */ + p1 += ud1 + uliTotal.HighPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p1 < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p0.QuadPart = ~p0.QuadPart; + p1 = ~p1; + p0.QuadPart += 1; + p1 += (p0.QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p1) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + /* Do the division */ + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = uc; + uliDividend.HighPart = p1; + uliDividend.LowPart = p0.HighPart; + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p0.HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p0, + dwDivisor, + NULL); + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; +} + +#ifdef DEBUG +/******************************Public*Routine******************************\ +* Debug CCritSec helpers +* +* We provide debug versions of the Constructor, destructor, Lock and Unlock +* routines. The debug code tracks who owns each critical section by +* maintaining a depth count. +* +* History: +* +\**************************************************************************/ + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_CritSec); + m_currentOwner = m_lockCount = 0; + m_fTrace = FALSE; +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_CritSec); +} + +void CCritSec::Lock() +{ + UINT tracelevel=3; + DWORD us = GetCurrentThreadId(); + DWORD currentOwner = m_currentOwner; + if (currentOwner && (currentOwner != us)) { + // already owned, but not by us + if (m_fTrace) { + DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), + GetCurrentThreadId(), &m_CritSec, currentOwner)); + tracelevel=2; + // if we saw the message about waiting for the critical + // section we ensure we see the message when we get the + // critical section + } + } + EnterCriticalSection(&m_CritSec); + if (0 == m_lockCount++) { + // we now own it for the first time. Set owner information + m_currentOwner = us; + + if (m_fTrace) { + DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); + } + } +} + +void CCritSec::Unlock() { + if (0 == --m_lockCount) { + // about to be unowned + if (m_fTrace) { + DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); + } + + m_currentOwner = 0; + } + LeaveCriticalSection(&m_CritSec); +} + +void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) +{ + pcCrit->m_fTrace = fTrace; +} + +BOOL WINAPI CritCheckIn(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} +#endif + + +STDAPI WriteBSTR(BSTR *pstrDest, LPCWSTR szSrc) +{ + *pstrDest = SysAllocString( szSrc ); + if( !(*pstrDest) ) return E_OUTOFMEMORY; + return NOERROR; +} + + +STDAPI FreeBSTR(BSTR* pstr) +{ + if( *pstr == NULL ) return S_FALSE; + SysFreeString( *pstr ); + return NOERROR; +} + + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR psz, LPWSTR *ppszReturn) +{ + CheckPointer(ppszReturn, E_POINTER); + ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); + DWORD nameLen = sizeof(WCHAR) * (lstrlenW(psz)+1); + *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen); + if (*ppszReturn == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*ppszReturn, psz, nameLen); + return NOERROR; +} + +// Waits for the HANDLE hObject. While waiting messages sent +// to windows on our thread by SendMessage will be processed. +// Using this function to do waits and mutual exclusion +// avoids some deadlocks in objects with windows. +// Return codes are the same as for WaitForSingleObject +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd, + UINT uMsg, + HANDLE hEvent) +{ + BOOL bPeeked = FALSE; + DWORD dwResult; + DWORD dwStart; + DWORD dwThreadPriority; + + static UINT uMsgId = 0; + + HANDLE hObjects[2] = { hObject, hEvent }; + if (dwWait != INFINITE && dwWait != 0) { + dwStart = GetTickCount(); + } + for (; ; ) { + DWORD nCount = NULL != hEvent ? 2 : 1; + + // Minimize the chance of actually dispatching any messages + // by seeing if we can lock immediately. + dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); + if (dwResult < WAIT_OBJECT_0 + nCount) { + break; + } + + DWORD dwTimeOut = dwWait; + if (dwTimeOut > 10) { + dwTimeOut = 10; + } + dwResult = MsgWaitForMultipleObjects( + nCount, + hObjects, + FALSE, + dwTimeOut, + hwnd == NULL ? QS_SENDMESSAGE : + QS_SENDMESSAGE + QS_POSTMESSAGE); + if (dwResult == WAIT_OBJECT_0 + nCount || + dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { + MSG msg; + if (hwnd != NULL) { + while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { + DispatchMessage(&msg); + } + } + // Do this anyway - the previous peek doesn't flush out the + // messages + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + if (dwWait != INFINITE && dwWait != 0) { + DWORD dwNow = GetTickCount(); + + // Working with differences handles wrap-around + DWORD dwDiff = dwNow - dwStart; + if (dwDiff > dwWait) { + dwWait = 0; + } else { + dwWait -= dwDiff; + } + dwStart = dwNow; + } + if (!bPeeked) { + // Raise our priority to prevent our message queue + // building up + dwThreadPriority = GetThreadPriority(GetCurrentThread()); + if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + } + bPeeked = TRUE; + } + } else { + break; + } + } + if (bPeeked) { + SetThreadPriority(GetCurrentThread(), dwThreadPriority); + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + if (uMsgId == 0) { + uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); + } + if (uMsgId != 0) { + MSG msg; + // Remove old ones + while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { + } + } + PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); + } + } + return dwResult; +} + +HRESULT AmGetLastErrorToHResult() +{ + DWORD dwLastError = GetLastError(); + if(dwLastError != 0) + { + return HRESULT_FROM_WIN32(dwLastError); + } + else + { + return E_FAIL; + } +} + +IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp) +{ + if (lp != NULL) + lp->AddRef(); + if (*pp) + (*pp)->Release(); + *pp = lp; + return lp; +} + +/****************************************************************************** + +CompatibleTimeSetEvent + + CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling +timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS +is supported on Windows XP and later operating systems. + +Parameters: +- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +Return Value: +- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +******************************************************************************/ +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) +{ + #if WINVER >= 0x0501 + { + static bool fCheckedVersion = false; + static bool fTimeKillSynchronousFlagAvailable = false; + + if( !fCheckedVersion ) { + fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); + fCheckedVersion = true; + } + + if( fTimeKillSynchronousFlagAvailable ) { + fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; + } + } + #endif // WINVER >= 0x0501 + + return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); +} + +bool TimeKillSynchronousFlagAvailable( void ) +{ + OSVERSIONINFO osverinfo; + + osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); + + if( GetVersionEx( &osverinfo ) ) { + + // Windows XP's major version is 5 and its' minor version is 1. + // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag + // in Windows XP. + if( (osverinfo.dwMajorVersion > 5) || + ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { + return true; + } + } + + return false; +} diff --git a/plugins/gs/gsdx9/baseclasses/wxutil.h b/plugins/gs/gsdx9/baseclasses/wxutil.h new file mode 100644 index 0000000000..9cf4ef5cdd --- /dev/null +++ b/plugins/gs/gsdx9/baseclasses/wxutil.h @@ -0,0 +1,540 @@ +//------------------------------------------------------------------------------ +// File: WXUtil.h +// +// Desc: DirectShow base classes - defines helper classes and functions for +// building multimedia filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXUTIL__ +#define __WXUTIL__ + +// eliminate spurious "statement has no effect" warnings. +#pragma warning(disable: 4705) + +// wrapper for whatever critical section we have +class CCritSec { + + // make copy constructor and assignment operator inaccessible + + CCritSec(const CCritSec &refCritSec); + CCritSec &operator=(const CCritSec &refCritSec); + + CRITICAL_SECTION m_CritSec; + +#ifdef DEBUG +public: + DWORD m_currentOwner; + DWORD m_lockCount; + BOOL m_fTrace; // Trace this one +public: + CCritSec(); + ~CCritSec(); + void Lock(); + void Unlock(); +#else + +public: + CCritSec() { + InitializeCriticalSection(&m_CritSec); + }; + + ~CCritSec() { + DeleteCriticalSection(&m_CritSec); + }; + + void Lock() { + EnterCriticalSection(&m_CritSec); + }; + + void Unlock() { + LeaveCriticalSection(&m_CritSec); + }; +#endif +}; + +// +// To make deadlocks easier to track it is useful to insert in the +// code an assertion that says whether we own a critical section or +// not. We make the routines that do the checking globals to avoid +// having different numbers of member functions in the debug and +// retail class implementations of CCritSec. In addition we provide +// a routine that allows usage of specific critical sections to be +// traced. This is NOT on by default - there are far too many. +// + +#ifdef DEBUG + BOOL WINAPI CritCheckIn(CCritSec * pcCrit); + BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); + void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); +#else + #define CritCheckIn(x) TRUE + #define CritCheckOut(x) TRUE + #define DbgLockTrace(pc, fT) +#endif + + +// locks a critical section, and unlocks it automatically +// when the lock goes out of scope +class CAutoLock { + + // make copy constructor and assignment operator inaccessible + + CAutoLock(const CAutoLock &refAutoLock); + CAutoLock &operator=(const CAutoLock &refAutoLock); + +protected: + CCritSec * m_pLock; + +public: + CAutoLock(CCritSec * plock) + { + m_pLock = plock; + m_pLock->Lock(); + }; + + ~CAutoLock() { + m_pLock->Unlock(); + }; +}; + + + +// wrapper for event objects +class CAMEvent +{ + + // make copy constructor and assignment operator inaccessible + + CAMEvent(const CAMEvent &refEvent); + CAMEvent &operator=(const CAMEvent &refEvent); + +protected: + HANDLE m_hEvent; +public: + CAMEvent(BOOL fManualReset = FALSE); + ~CAMEvent(); + + // Cast to HANDLE - we don't support this as an lvalue + operator HANDLE () const { return m_hEvent; }; + + void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; + BOOL Wait(DWORD dwTimeout = INFINITE) { + return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); + }; + void Reset() { ResetEvent(m_hEvent); }; + BOOL Check() { return Wait(0); }; +}; + + +// wrapper for event objects that do message processing +// This adds ONE method to the CAMEvent object to allow sent +// messages to be processed while waiting + +class CAMMsgEvent : public CAMEvent +{ + +public: + + // Allow SEND messages to be processed while waiting + BOOL WaitMsg(DWORD dwTimeout = INFINITE); +}; + +// old name supported for the time being +#define CTimeoutEvent CAMEvent + +// support for a worker thread + +// simple thread class supports creation of worker thread, synchronization +// and communication. Can be derived to simplify parameter passing +class AM_NOVTABLE CAMThread { + + // make copy constructor and assignment operator inaccessible + + CAMThread(const CAMThread &refThread); + CAMThread &operator=(const CAMThread &refThread); + + CAMEvent m_EventSend; + CAMEvent m_EventComplete; + + DWORD m_dwParam; + DWORD m_dwReturnVal; + +protected: + HANDLE m_hThread; + + // thread will run this function on startup + // must be supplied by derived class + virtual DWORD ThreadProc() = 0; + +public: + CAMThread(); + virtual ~CAMThread(); + + CCritSec m_AccessLock; // locks access by client threads + CCritSec m_WorkerLock; // locks access to shared objects + + // thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + static DWORD WINAPI InitialThreadProc(LPVOID pv); + + // start thread running - error if already running + BOOL Create(); + + // signal the thread, and block for a response + // + DWORD CallWorker(DWORD); + + // accessor thread calls this when done with thread (having told thread + // to exit) + void Close() { + #pragma warning( push ) + // C4312: 'type cast' : conversion from 'LONG' to 'PVOID' of greater size + // + // This code works correctly on 32-bit and 64-bit systems. + #pragma warning( disable : 4312 ) + HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); + #pragma warning( pop ) + + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + }; + + // ThreadExists + // Return TRUE if the thread exists. FALSE otherwise + BOOL ThreadExists(void) const + { + if (m_hThread == 0) { + return FALSE; + } else { + return TRUE; + } + } + + // wait for the next request + DWORD GetRequest(); + + // is there a request? + BOOL CheckRequest(DWORD * pParam); + + // reply to the request + void Reply(DWORD); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + HANDLE GetRequestHandle() const { return m_EventSend; }; + + // Find out what the request was + DWORD GetRequestParam() const { return m_dwParam; }; + + // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if + // available. S_FALSE means it's not available. + static HRESULT CoInitializeHelper(); +}; + + +// CQueue +// +// Implements a simple Queue ADT. The queue contains a finite number of +// objects, access to which is controlled by a semaphore. The semaphore +// is created with an initial count (N). Each time an object is added +// a call to WaitForSingleObject is made on the semaphore's handle. When +// this function returns a slot has been reserved in the queue for the new +// object. If no slots are available the function blocks until one becomes +// available. Each time an object is removed from the queue ReleaseSemaphore +// is called on the semaphore's handle, thus freeing a slot in the queue. +// If no objects are present in the queue the function blocks until an +// object has been added. + +#define DEFAULT_QUEUESIZE 2 + +template class CQueue { +private: + HANDLE hSemPut; // Semaphore controlling queue "putting" + HANDLE hSemGet; // Semaphore controlling queue "getting" + CRITICAL_SECTION CritSect; // Thread seriallization + int nMax; // Max objects allowed in queue + int iNextPut; // Array index of next "PutMsg" + int iNextGet; // Array index of next "GetMsg" + T *QueueObjects; // Array of objects (ptr's to void) + + void Initialize(int n) { + iNextPut = iNextGet = 0; + nMax = n; + InitializeCriticalSection(&CritSect); + hSemPut = CreateSemaphore(NULL, n, n, NULL); + hSemGet = CreateSemaphore(NULL, 0, n, NULL); + QueueObjects = new T[n]; + } + + +public: + CQueue(int n) { + Initialize(n); + } + + CQueue() { + Initialize(DEFAULT_QUEUESIZE); + } + + ~CQueue() { + delete [] QueueObjects; + DeleteCriticalSection(&CritSect); + CloseHandle(hSemPut); + CloseHandle(hSemGet); + } + + T GetQueueObject() { + int iSlot; + T Object; + LONG lPrevious; + + // Wait for someone to put something on our queue, returns straight + // away is there is already an object on the queue. + // + WaitForSingleObject(hSemGet, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextGet++ % nMax; + Object = QueueObjects[iSlot]; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to put an object onto our queue as there + // is now space available in the queue. + // + ReleaseSemaphore(hSemPut, 1L, &lPrevious); + return Object; + } + + void PutQueueObject(T Object) { + int iSlot; + LONG lPrevious; + + // Wait for someone to get something from our queue, returns straight + // away is there is already an empty slot on the queue. + // + WaitForSingleObject(hSemPut, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextPut++ % nMax; + QueueObjects[iSlot] = Object; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to remove an object from our queue as there + // is now an object available to be removed. + // + ReleaseSemaphore(hSemGet, 1L, &lPrevious); + } +}; + +// miscellaneous string conversion functions +// NOTE: as we need to use the same binaries on Win95 as on NT this code should +// be compiled WITHOUT unicode being defined. Otherwise we will not pick up +// these internal routines and the binary will not run on Win95. + +// int WINAPIV wsprintfWInternal(LPWSTR, LPCWSTR, ...); + +//LPWSTR +//WINAPI +//lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ); +LPWSTR +WINAPI +lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ); +int +WINAPI +lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ); +int +WINAPI +lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ); +int +WINAPI +lstrlenWInternal( + LPCWSTR lpString + ); + +#ifndef UNICODE +#define wsprintfW wsprintfWInternal +#define lstrcpyW lstrcpyWInternal +#define lstrcpynW lstrcpynWInternal +#define lstrcmpW lstrcmpWInternal +#define lstrcmpiW lstrcmpiWInternal +#define lstrlenW lstrlenWInternal +#endif + +extern "C" +void * __stdcall memmoveInternal(void *, const void *, size_t); + +inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) +{ +#ifdef _X86_ + void *pRet = NULL; + + _asm { + cld // make sure we get the direction right + mov ecx, cnt // num of bytes to scan + mov edi, buf // pointer byte stream + mov eax, chr // byte to scan for + repne scasb // look for the byte in the byte stream + jnz exit_memchr // Z flag set if byte found + dec edi // scasb always increments edi even when it + // finds the required byte + mov pRet, edi +exit_memchr: + } + return pRet; + +#else + while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return(cnt ? (void *)buf : NULL); +#endif +} + +void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len); + +#define WstrToInt(sz) _wtoi(sz) +#define atoiW(sz) _wtoi(sz) +#define atoiA(sz) atoi(sz) + +// These are available to help managing bitmap VIDEOINFOHEADER media structures + +extern const DWORD bits555[3]; +extern const DWORD bits565[3]; +extern const DWORD bits888[3]; + +// These help convert between VIDEOINFOHEADER and BITMAPINFO structures + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(WORD) GetBitCount(const GUID *pSubtype); + +// strmbase.lib implements this for compatibility with people who +// managed to link to this directly. we don't want to advertise it. +// +// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); + +STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype); +STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype); + +#ifdef UNICODE +#define GetSubtypeName GetSubtypeNameW +#else +#define GetSubtypeName GetSubtypeNameA +#endif + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); + + +// Compares two interfaces and returns TRUE if they are on the same object +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); + +// This is for comparing pins +#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) + + +// Arithmetic helper functions + +// Compute (a * b + rnd) / c +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); + + +// Avoids us dyna-linking to SysAllocString to copy BSTR strings +STDAPI WriteBSTR(BSTR * pstrDest, LPCWSTR szSrc); +STDAPI FreeBSTR(BSTR* pstr); + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR pszString, LPWSTR *ppszReturn); + +// Special wait for objects owning windows +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd = NULL, + UINT uMsg = 0, + HANDLE hEvent = NULL); + +// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in +// our use of HRESULT_FROM_WIN32, it typically means a function failed +// to call SetLastError(), and we still want a failure code. +// +#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) + +// call GetLastError and return an HRESULT value that will fail the +// SUCCEEDED() macro. +HRESULT AmGetLastErrorToHResult(void); + +// duplicate of ATL's CComPtr to avoid linker conflicts. + +IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp); + +template +class QzCComPtr +{ +public: + typedef T _PtrClass; + QzCComPtr() {p=NULL;} + QzCComPtr(T* lp) + { + if ((p = lp) != NULL) + p->AddRef(); + } + QzCComPtr(const QzCComPtr& lp) + { + if ((p = lp.p) != NULL) + p->AddRef(); + } + ~QzCComPtr() {if (p) p->Release();} + void Release() {if (p) p->Release(); p=NULL;} + operator T*() {return (T*)p;} + T& operator*() {ASSERT(p!=NULL); return *p; } + //The assert on operator& usually indicates a bug. If this is really + //what is needed, however, take the address of the p member explicitly. + T** operator&() { ASSERT(p==NULL); return &p; } + T* operator->() { ASSERT(p!=NULL); return p; } + T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} + T* operator=(const QzCComPtr& lp) + { + return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); + } +#if _MSC_VER>1020 + bool operator!(){return (p == NULL);} +#else + BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} +#endif + T* p; +}; + +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); +bool TimeKillSynchronousFlagAvailable( void ); + +#endif /* __WXUTIL__ */ diff --git a/plugins/gs/gsdx9/res/GSdx9.rc2 b/plugins/gs/gsdx9/res/GSdx9.rc2 new file mode 100644 index 0000000000..9e684f60a1 --- /dev/null +++ b/plugins/gs/gsdx9/res/GSdx9.rc2 @@ -0,0 +1,37 @@ +// +// GSdx9.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +IDR_PS11_TFX000 RCDATA "res\\ps11_tfx000.psh" +IDR_PS11_TFX010 RCDATA "res\\ps11_tfx010.psh" +IDR_PS11_TFX011 RCDATA "res\\ps11_tfx011.psh" +IDR_PS11_TFX1x0 RCDATA "res\\ps11_tfx1x0.psh" +IDR_PS11_TFX1x1 RCDATA "res\\ps11_tfx1x1.psh" +IDR_PS11_TFX200 RCDATA "res\\ps11_tfx200.psh" +IDR_PS11_TFX210 RCDATA "res\\ps11_tfx210.psh" +IDR_PS11_TFX211 RCDATA "res\\ps11_tfx211.psh" +IDR_PS11_TFX300 RCDATA "res\\ps11_tfx300.psh" +IDR_PS11_TFX310 RCDATA "res\\ps11_tfx310.psh" +IDR_PS11_TFX311 RCDATA "res\\ps11_tfx311.psh" +IDR_PS11_TFX4xx RCDATA "res\\ps11_tfx4xx.psh" +IDR_PS11_EN11 RCDATA "res\\ps11_en11.psh" +IDR_PS11_EN01 RCDATA "res\\ps11_en01.psh" +IDR_PS11_EN10 RCDATA "res\\ps11_en10.psh" +IDR_PS11_EN00 RCDATA "res\\ps11_en00.psh" +IDR_PS14_EN11 RCDATA "res\\ps14_en11.psh" +IDR_PS14_EN01 RCDATA "res\\ps14_en01.psh" +IDR_PS14_EN10 RCDATA "res\\ps14_en10.psh" +IDR_PS14_EN00 RCDATA "res\\ps14_en00.psh" +IDR_HLSL_TFX RCDATA "res\\hlsl_tfx.fx" +IDR_HLSL_MERGE RCDATA "res\\hlsl_merge.fx" +IDR_HLSL_RB RCDATA "res\\hlsl_rb.fx" + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/gs/gsdx9/res/hlsl_merge.fx b/plugins/gs/gsdx9/res/hlsl_merge.fx new file mode 100644 index 0000000000..bc8cc8c1f1 --- /dev/null +++ b/plugins/gs/gsdx9/res/hlsl_merge.fx @@ -0,0 +1,101 @@ + +sampler RAO1 : register(s0); +sampler RAO2 : register(s1); + +float4 Params1 : register(c0); + +#define BGColor (Params1.rgb) +#define ALP (Params1.a) + +float4 Params2 : register(c1); + +#define AMOD (Params2[0] >= 0) +#define EN1 (Params2[1]) +#define EN2 (Params2[2]) +#define MMOD (Params2[3] >= 0) + +float4 Params3 : register(c2); + +#define AEM (Params3[0]) +#define TA0 (Params3[1]) +#define TA1 (Params3[2]) +#define SLBG (Params3[3] >= 0) + +float4 Merge(float4 Color1 : COLOR, float4 Color2 : COLOR) : COLOR +{ + float a = EN1 * (MMOD ? ALP : Color1.a); + float4 c = lerp(Color2, Color1, a); + // c.a = AMOD ? Color2.a : Color1.a; // not used + c.rgba = c.bgra; + return c; +} + +// 16 + +float4 CorrectTexColor16(float4 TexColor : COLOR) +{ + float A = AEM * !any(TexColor.rgb) * TA0; + TexColor.a = (TexColor.a < 1.0) ? A : TA1; // < 0.5 ? + return TexColor; +} + +float4 Sample16RAO1(float2 Tex : TEXCOORD0) : COLOR +{ + return EN1 * CorrectTexColor16(tex2D(RAO1, Tex)); +} + +float4 Sample16RAO2(float2 Tex : TEXCOORD0) : COLOR +{ + return SLBG ? float4(BGColor, 0) : (EN2 * CorrectTexColor16(tex2D(RAO2, Tex))); +} + +float4 main0(float2 Tex1 : TEXCOORD0, float2 Tex2 : TEXCOORD1) : COLOR +{ + float4 Color1 = Sample16RAO1(Tex1); + float4 Color2 = Sample16RAO2(Tex2); + return Merge(Color1, Color2); +} + +// 24 + +float4 CorrectTexColor24(float4 TexColor : COLOR) +{ + TexColor.a = AEM * !any(TexColor.rgb) * TA0; + return TexColor; +} + +float4 Sample24RAO1(float2 Tex : TEXCOORD0) : COLOR +{ + return EN1 * CorrectTexColor24(tex2D(RAO1, Tex)); +} + +float4 Sample24RAO2(float2 Tex : TEXCOORD0) : COLOR +{ + return SLBG ? float4(BGColor, 0) : (EN2 * CorrectTexColor24(tex2D(RAO2, Tex))); +} + +float4 main1(float2 Tex1 : TEXCOORD0, float2 Tex2 : TEXCOORD1) : COLOR +{ + float4 Color1 = Sample24RAO1(Tex1); + float4 Color2 = Sample24RAO2(Tex2); + return Merge(Color1, Color2); +} + +// 32 + +float4 SampleRAO1(float2 Tex : TEXCOORD0) : COLOR +{ + return EN1 * tex2D(RAO1, Tex); +} + +float4 SampleRAO2(float2 Tex : TEXCOORD0) : COLOR +{ + return SLBG ? float4(BGColor, 0) : (EN2 * tex2D(RAO2, Tex)); +} + +float4 main2(float2 Tex1 : TEXCOORD0, float2 Tex2 : TEXCOORD1) : COLOR +{ + float4 Color1 = SampleRAO1(Tex1); + float4 Color2 = SampleRAO2(Tex2); + return Merge(Color1, Color2); +} diff --git a/plugins/gs/gsdx9/res/hlsl_rb.fx b/plugins/gs/gsdx9/res/hlsl_rb.fx new file mode 100644 index 0000000000..5ea33849ef --- /dev/null +++ b/plugins/gs/gsdx9/res/hlsl_rb.fx @@ -0,0 +1,8 @@ +sampler Texture : register(s0); + +float4 main(float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.rgba = c.bgra; + return c; +} diff --git a/plugins/gs/gsdx9/res/hlsl_tfx.fx b/plugins/gs/gsdx9/res/hlsl_tfx.fx new file mode 100644 index 0000000000..af950de69c --- /dev/null +++ b/plugins/gs/gsdx9/res/hlsl_tfx.fx @@ -0,0 +1,379 @@ + +sampler Texture : register(s0); +sampler1D Palette : register(s1); + +float4 Params0 : register(c0); + +#define bTCC (Params0[0] >= 0) +#define fRT (Params0[1]) +#define TA0 (Params0[2]) +#define TA1 (Params0[3]) + +float2 W_H : register(c1); +float2 RW_RH : register(c2); +float2 RW_ZERO : register(c3); +float2 ZERO_RH : register(c4); + +// +// texture sampling +// + +float4 SampleTexture_32(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.a *= fRT; + return c; +} + +float4 SampleTexture_24(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.a = TA0; + // c.a *= fRT; // premultiplied + return c; +} + +float4 SampleTexture_24AEM(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.a = any(c.rgb) ? TA0 : 0; + // c.a *= fRT; // premultiplied + return c; +} + +float4 SampleTexture_16(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.a = c.a != 0 ? TA1 : TA0; + // c.a *= fRT; // premultiplied + return c; +} + +float4 SampleTexture_16AEM(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex2D(Texture, Tex); + c.a = c.a != 0 ? TA1 : any(c.rgb) ? TA0 : 0; + // c.a *= fRT; // premultiplied + return c; +} + +static const float s_palerr = 0.001/256; + +float4 SampleTexture_8P_pt(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex1D(Palette, tex2D(Texture, Tex).x - s_palerr); + // c.a *= fRT; // premultiplied + return c; +} + +float4 SampleTexture_8P_ln(in float2 Tex : TEXCOORD0) : COLOR +{ + Tex -= 0.5*RW_RH; // ? + float4 c00 = tex1D(Palette, tex2D(Texture, Tex).x - s_palerr); + float4 c01 = tex1D(Palette, tex2D(Texture, Tex + RW_ZERO).x - s_palerr); + float4 c10 = tex1D(Palette, tex2D(Texture, Tex + ZERO_RH).x - s_palerr); + float4 c11 = tex1D(Palette, tex2D(Texture, Tex + RW_RH).x - s_palerr); + float2 dd = frac(Tex * W_H); + float4 c = lerp(lerp(c00, c01, dd.x), lerp(c10, c11, dd.x), dd.y); + c.a *= fRT; + return c; +} + +float4 SampleTexture_8HP_pt(in float2 Tex : TEXCOORD0) : COLOR +{ + float4 c = tex1D(Palette, tex2D(Texture, Tex).a - s_palerr); + c.a *= fRT; + return c; +} + +float4 SampleTexture_8HP_ln(in float2 Tex : TEXCOORD0) : COLOR +{ + Tex -= 0.5*RW_RH; // ? + float4 c00 = tex1D(Palette, tex2D(Texture, Tex).a - s_palerr); + float4 c01 = tex1D(Palette, tex2D(Texture, Tex + RW_ZERO).a - s_palerr); + float4 c10 = tex1D(Palette, tex2D(Texture, Tex + ZERO_RH).a - s_palerr); + float4 c11 = tex1D(Palette, tex2D(Texture, Tex + RW_RH).a - s_palerr); + float2 dd = frac(Tex * W_H); + float4 c = lerp(lerp(c00, c01, dd.x), lerp(c10, c11, dd.x), dd.y); + c.a *= fRT; + return c; +} + +// +// fog +// + +float4 ApplyFog(in float4 Diff : COLOR, in float4 Fog : COLOR) : COLOR +{ + Diff = saturate(Diff); + Diff.rgb = lerp(Fog.rgb, Diff.rgb, Fog.a); + return Diff; +} + +// +// tfx +// + +float4 tfx0(float4 Diff, float4 TexColor) : COLOR +{ + Diff *= 2; + Diff.rgb *= TexColor.rgb; + if(bTCC) Diff.a *= TexColor.a; + return Diff; +} + +float4 tfx1(float4 Diff, float4 TexColor) : COLOR +{ + Diff = TexColor; + return Diff; +} + +float4 tfx2(float4 Diff, float4 TexColor) : COLOR +{ + Diff.rgb *= TexColor.rgb * 2; + Diff.rgb += Diff.a; + if(bTCC) Diff.a = Diff.a * 2 + TexColor.a; + return Diff; +} + +float4 tfx3(float4 Diff, float4 TexColor) : COLOR +{ + Diff.rgb *= TexColor.rgb * 2; + Diff.rgb += Diff.a; + if(bTCC) Diff.a = TexColor.a; + return Diff; +} + +// +// main tfx 32 +// + +float4 main_tfx0_32(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_32(Tex)), Fog); +} + +float4 main_tfx1_32(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_32(Tex)), Fog); +} + +float4 main_tfx2_32(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_32(Tex)), Fog); +} + +float4 main_tfx3_32(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_32(Tex)), Fog); +} + +// +// main tfx 24 +// + +float4 main_tfx0_24(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_24(Tex)), Fog); +} + +float4 main_tfx1_24(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_24(Tex)), Fog); +} + +float4 main_tfx2_24(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_24(Tex)), Fog); +} + +float4 main_tfx3_24(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_24(Tex)), Fog); +} + +// +// main tfx 24 AEM +// + +float4 main_tfx0_24AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_24AEM(Tex)), Fog); +} + +float4 main_tfx1_24AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_24AEM(Tex)), Fog); +} + +float4 main_tfx2_24AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_24AEM(Tex)), Fog); +} + +float4 main_tfx3_24AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_24AEM(Tex)), Fog); +} + +// +// main tfx 16 +// + +float4 main_tfx0_16(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_16(Tex)), Fog); +} + +float4 main_tfx1_16(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_16(Tex)), Fog); +} + +float4 main_tfx2_16(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_16(Tex)), Fog); +} + +float4 main_tfx3_16(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_16(Tex)), Fog); +} + +// +// main tfx 16 AEM +// + +float4 main_tfx0_16AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_16AEM(Tex)), Fog); +} + +float4 main_tfx1_16AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_16AEM(Tex)), Fog); +} + +float4 main_tfx2_16AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_16AEM(Tex)), Fog); +} + +float4 main_tfx3_16AEM(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_16AEM(Tex)), Fog); +} + +// +// main tfx 8P pt +// + +float4 main_tfx0_8P_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_8P_pt(Tex)), Fog); +} + +float4 main_tfx1_8P_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_8P_pt(Tex)), Fog); +} + +float4 main_tfx2_8P_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_8P_pt(Tex)), Fog); +} + +float4 main_tfx3_8P_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_8P_pt(Tex)), Fog); +} + +// +// main tfx 8P ln +// + +float4 main_tfx0_8P_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_8P_ln(Tex)), Fog); +} + +float4 main_tfx1_8P_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_8P_ln(Tex)), Fog); +} + +float4 main_tfx2_8P_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_8P_ln(Tex)), Fog); +} + +float4 main_tfx3_8P_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_8P_ln(Tex)), Fog); +} + +// +// main tfx 8HP pt +// + +float4 main_tfx0_8HP_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_8HP_pt(Tex)), Fog); +} + +float4 main_tfx1_8HP_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_8HP_pt(Tex)), Fog); +} + +float4 main_tfx2_8HP_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_8HP_pt(Tex)), Fog); +} + +float4 main_tfx3_8HP_pt(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_8HP_pt(Tex)), Fog); +} + +// +// main tfx 8HP ln +// + +float4 main_tfx0_8HP_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx0(Diff, SampleTexture_8HP_ln(Tex)), Fog); +} + +float4 main_tfx1_8HP_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx1(Diff, SampleTexture_8HP_ln(Tex)), Fog); +} + +float4 main_tfx2_8HP_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx2(Diff, SampleTexture_8HP_ln(Tex)), Fog); +} + +float4 main_tfx3_8HP_ln(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(tfx3(Diff, SampleTexture_8HP_ln(Tex)), Fog); +} + +// +// main notfx +// + +float4 main_notfx(float4 Diff : COLOR0, float4 Fog : COLOR1, float2 Tex : TEXCOORD0) : COLOR +{ + return ApplyFog(Diff, Fog); +} + +// +// main 8P -> 32 +// + +float4 main_8PTo32(float4 Diff : COLOR0, float2 Tex : TEXCOORD0) : COLOR +{ + return tex1D(Palette, tex2D(Texture, Tex).x - s_palerr); +} diff --git a/plugins/gs/gsdx9/res/logo1.bmp b/plugins/gs/gsdx9/res/logo1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..24cfdbeea83ace39979ef7b57bf4b8ad9f10868b GIT binary patch literal 56002 zcmb5XcYGCBmhXE`<&$)j6AI*<5t5J)l1M@XWk7(0GD#AMC~`2^V4T5ZY``Ws01n^` zcDuW6lfiD=?e6KB>6xCMc{4qC!hJLE@AqB1BpPsg?t6T;%XO-D?b=nfek-r7iL-wG zTaWse$#x+BSzeE)i2r*%iR$>%UFX%0u8pS7%hu!3=`a7f{^$O9X!{dq)a4JKyZ?)w z`}^)#?h&uY>wVpR z)I2hU?)K2&_vd_n=Pyp`FCTR8^3ZsHx#ORY-oNC*tK5Ts?!?~xe)nI-U+C1`OvJq`-60k)76*%2`svg{shh5zuLXk1KS6#z5f7zzP(JvZ4X=` zyWRJDc=wS`kN$k{UXPypKmGpydadgB!0gnx?!~;=u8FHp+Wo;E?d;B^yX%9$x`+Ac zxjsDB!(;sPRX=^EdjvJ%`(z*NJnwUGiADv}}%%p2F?mX4c(HSzCNB^l?jLDS#a>;{tynpL4T`%PRwf86B9?8s5 z^Ss}`yPx~^|M!-eh;D zzwm!~KzAthe)#D=+F$7EzQzYns7t!Olou0DThs7I(J zD=RBAGjrs~k!d}9Dg+4SD@FmT(o<7n(uYA5gs_Vfh&Ldss}pCEjF(2RNM9IJ2%Lw z&JF9zcp1gwvfHHgw&Ko}EHaZu`-7azIYer*p%WEnBuf z_Sn{)k8!ZRwysaV{@q#;n8?Y=8JC+2cj(chhcnl5s!d8r7Qb+)h3beb%y*)m&fYmsBO*#0If&}jMU9e;z*-{=Gy{lTU{s6|?!B^YQ41Q!Ln zTC+dc>~~Lv7CXU3cA(h~H2G*8cTaIGBQTDy!IoC<*b6PI)?{nfnKZM`vg&QK(YBf# zv)Sh?wrIX3HqG7d+AgwviyeE3G;6VKw3uCOk!3Ent);fT%u&sTm8Mm08l|Q&%dm=1kov(X2AVsxYkC(zGhgTj@1RWHf!Iq0P{}#eZ)4G*d6uwP~6@ zRi_z~HMg0CrrV4HJnJEq)sg6=l6K<6rFniZI7 z2TT2dQpcJp4{J^{d1_7>1-hQEX%oEcSQAZ-`)1mK5}$vT-#61|Pq%qdyg)Ob@p)s0 zG2JjrEW5&SDt*2x$1JmqS*E<7>4tZPuFW)z63Z;LIVJR2<2bcGq1Z~>DX}e{qR7Wb zaleI8Wbh7Uz!|2rS+-r~_$qvXIsVYRK*aoDpxSn-ET_V1Y-~(QO6u0Irc9YKapJ@w zLkD9?K>ogJUtpdkJF{(?I$}EuEE}o>4b7&n+4i?Mj-oin#Y7`$u>JK;5YldOLW_J6 zi~W&HgAuBQmIP>lB_UuT_-OWn1G)hSdP-C1ku9(Q9{{4k=hO=V*gADKfPg&B`4-Kt zvF(KpK=C#Cn1*k$Y-vFA(bnt}&@|dcgXK1XQM2W15e(S?XsP40+CJ6%%Pf1TX)U%u z595G2Yk_4|o91jypRJo!I%sezO<%d`D>3aEhBIB44_;*QJ^2EB`K~s}awggagfm&e zrO4ug@I7s=D%Ammj8kPG}*4Dv<9vP3|J&Pttu8O{+kf zP*DD#2~)_k3nIEpyxl(yE6*^;>*hG!C38JP)5qvEW2_COGiI>ZjF{;U&h-1IS>`0K zm8+SVhLK?yW9j2HvP?7Al6y_oAXu8vwF`>^ZmK(le%~~|Rcc#Rwlh26RQRnD2LhD$ zGs$AA%uOLxH}g4So6~eK;V<*koD#>L&eQQ|mR)Gug_ew8EUybXbs+O9i+3(>k8Z^l zTWPZ_Uzu=g0O6|(_-X^exdDH}OChEWMOG600S#5Si(9M2EUR7f*U0j1Rsn2 z(w6wxG8AYKVN>Vlc22D$C~W>0e^ zfo>}S!1v_ci!hj^Td+|@uy8$nvc<>Y1H#m_GTkWCOj@~MOUA4)%re6$)kWl#Xvhgz z;RB7IE=qJ`nwP=#NgC9ra9|qwrk)Sy{ZX4}+!t56+Gnd37~Tn%mSgIW`Doo5t(#+z z0fv#S>*GzRo5%4L+y3H!uPES5wv7Uho}-&%O=FBnH((@~7;hSdUVW0+oTv%ly0OR( zRP0O^VuW}_nV1Lr_9Fw38O{^|t^vaGG;j(2tO7dQg7R6mufk7r%6$kG!Ng?s>J%@5 z2k>^|QvweZ8V6Y;9*g#abG%p%8YE+kD;mOa-8!}{wD>cA`JqOv~Sk=NM zK?6`ki-2_s%`SGFr9RN$0zw1^8V*zp>xauP^#g)%dqm{&a8yT_ZFpHIv^W%O3PJ2p zE>NI9JBWn9A|K5K1UoWRgU?s*cNPK&e*mhl@df7laAq}LiotsD`(tI;%@WNWur#v;pJWLnLp(PHRLCW8Y( z&|u9oY?P(h8oG^HY1!qb4jN$DMF!;KOz|R=Ez}sK^AuQ~@FV1e9Gs+Ug*s%&jy}bp zKi>q20w#=EHncC8D6>>kJ4$i@3jk-7d*}c+^p+Uh4*ao$`r#=yL7otJz6J;^woq1{ zp-m7SNy`;Eq31~hF{o`20=M>{!c7rH3qY6!7Tr8KhMuJX3oXO2vUKRwy@aU>aHsi$ z#Wso)dXYZCKvM!SK*5t`d9rnTyzW5J>PB+Ad>x4B6TDD5KSggWw&2m|7XBJP`UJFw z2Ib5^0*Q2?n@A~IzUW={REJa0JC}sYMN}9wEiXKMqDU0!UucM;I9;a?($tu%(cmSb zkIj&GLgPh+Dtw`8f2bxTfT*?u6+YiA3%JM^Q4P%#KyZWxR=@;66k*1&f;JHth%~$0 zC;Me~ zIS_TIEfBdPBD^vbTonwj4n?kvj9wl_eS-XbO@0Ik;zTS4faOAAvENmkI4CThp&A0N zga8nRhzcQaYzRREQVIkh8yfvKj2?QgGdbdFR`jPQGSto2wV4#;0oU5ZRpW+{gc*B^LvPB`O@Cha+3xUhbfhPS6MW_UdY^WP`2u2^Q z1QW;!OL)47AGr&n2+^p`^dL%6R$x)uTwO00IVutbJ+stuP?NZPjz3uK7fWI`nwSq` z!Vy^_(!y=>{%3YcU({DPlh_mJU9&8N3YYjR14uQISe5pqNt1f_?%j=vapT4%_2{8~ zd65v<6JlL25RIOv6#D>cV5uJ*2stmno9 z27@aCfwo|1aYRH*IAT#Sq9x=uF&ge05XyQG(*Z8;HfSFLM^w~X!G(dq!Z0`pH--=f zA{Eel>IExyt!P&MTF0yvP`W>{|Kaj%{R^zX0!Q#vXZjVS#MWV|%IL8gb;KSxL%QfS z7Az)n-SA)BcEqdQNrt;r6@vFrFCd{{UdGC+vE#MDu};8W!`x-i-l`%n{K7ztsO>vWJ0SYqkZ zZ5nrhQW(%P*$XC+3NTzJR|5)mw$Q1OV~R!u{ldEoO&cA5isG=q7mWxS%rm$OOwa-P zMdRWi05T>BjXUFXUycK{@?0oR;TeIz44-d`BZfkbX=gg3Uu9Y%GjbV6F?vj8cJfVs zz6IJ~2E2{XOgpMF7`Y%6*&K{)5d}L`6F?)fF`lP7ydQ2#<0=sY6CGp{^cYd;kDTp~ ztO_Af{L>wIb)21GBh`3hUL9`(-VLexU{P3LWd{6-7DON+5@;?hSNW9+6!4XWd?f+2 zBWH%A2;UZUuEg<`s)qS8!}9Y%XIP>rP8ah&P#zGCYc7H-t`CIj#We&(z)EO&C~|c;rZXy*wk|qybreT} zt^Nqw5?^?cbdwPl2YrhIC}5(4xki8@bJ1$x=Cz`|h&)*63qs}%4%?9H%c7gYL{QlW zI2r5(=u|e7v}zo4fsTF^T;ONs*c`@uOVC{F_z)Ef4aRgOjrgok!xq@S`6jjkzBRFy z=Gfjj+L%?tuKe=sr(eGIr@y<~xThLXj?M#73lyfna81NImZ5KwBbbO?)wC?r8fSZQ#g(KOt1x1CE4b7qnIbB%Atrj^%h0d401Zm_ zPE{JtWHEFBmOu&(D$}xa9O;Z1563JCiN}WLDlqL_%gV5jh{mH>kOEcM1eoh0 z18BTk@Z>hpR28!kyB#gD$n+N*!5LP>EIXni5TPUu5&-)75hh%O01~JMaub?@5@D>0 zgkkPj47iwl_=}Vo3?MKR!tLQ`bfmT6nDw-X=+20!)!~R0;qcOMn6pa)VJr+KU4RAG ziVh~$xF|wM0%-~d2nHn^{7Mp7fjSE%N65L(EZRPP%ZZNdCs%Acv3&cUq4uo@*{;Z2p2@um zmS%3**S7VU_HEC%ZhTgnmMtD6q3#LZzH?Hx>}%b!f9baUOS${xrCI&vq;1{b-e-0? zNZRpYd*O;)9%oWV_NIfaA|bN%%}+1e^mOZnr(3r?+ivChfZf)kZBsYo!GEW$%Gvf} z`_|`Mw>`78pf1}SV``b+{HCnh4YRSv`&Oj#2IO}8S{rs$pa}J!*K_mXcHTcqL)6Nc zs8vxr-dMT)^%Xl_SrI7rJJWq#+`k(Ta2MYcUvMVsii01N1}*z%IY6gdzcO(>iDh1_ zAyWkta|~mFI98nbqQ2mo6~f1Tg#0cRaf^`f&+`KdksM_rbb$gs5n2}}6d?E%tsyZh3Y~`hSb#5Zod=16ejrX6&4I5MklEcLjKspViFT-?AzA!_#4|lxpMsDPmX={#o7P;yBm`>4Q%W|NXb0zW>n?q;10-=v^ptaNM7wu`k<&4d5&-De+taOA`H4}E{_oiUAr z{YCl*{QT$$t||;>QHNcpQ@J^L%{WGzyebQBsN{#n&ZySG%;)0|k9_#SvG?CQa{TnR zxEbNjXB&Cy_ue~1`+#=&u$_w+NVk>YI&o3ffBo*pm!F;GMzp%kB?U{e|ND2hCbnf^ zVg5gVb7SkiCBS#{^NarTZ>}R?GAc&=@$1h%xFj?D_rJMr75JQ4{{Q~#n_G`8PN|7~ z>9xnc`usGv`0u~Ev1QK^bF|%Odg`&4wmo%t6?a^|v*z0y?|yRm$VczVGxo1apV~H_ z$Dg=8Cw6&k%I1XBEs0ltdE%qbkAHvXok?qR?PAf0oP0}cmkAKNg<|F)Buay5ECL9; zM&EQ!F-Y4y*)J-)2*Y5TA?kEGZjHB&dj}G6^&I<_EB55IO!z z<;5z)V3vkB5yB@BQfyynhCWQzm1)6};ixQfm4xiifZ$EqnuMf_*Cv6=2 zZ@<2pzkZC82jWvAhFG|M%zys+Gn6P4CozK-SOpt0{_VTZCvC{UWdS3=rGOhxEB9>N z-@tJ=^1prm>BfDHFqHQ$KYRJo3#d1Yu<4m*xYeb1_PzhkK5W#&#bf{1cb`pc9=maG z1N{;Ga^%~e#e*@^1QY-M?PrC{Gp!=u2k*Y{-lZ217_^PgHeb5*9PW11dXX5Q-2|NHw-^E*aMsBV_mDD@&m*e7P^DfWtEa+3bPe*I}) z!|3&U8~**ftE1)*5F;Q@^G*=m9E+NLtonjQ8UOnI)k)1+qIeXF+qG~>#(#YGd4Bt7 zB-6is_t~cBn_$76PuBAk_88;+3;RB}@EnTMrpM*Ed{YhLYya`x&$b{gmI1b&RY6^j)J7H{1Hn5P;@%bpA0bYgu3}+8a6X+nr#GR!AjwpVJ zSUw+?BE*J6$85391!9LGo8d_`yc-w*7Z7J;%9(GrNj;2;n!ek3uBU5y^7xeZu|xhsCz z09J*#p_)XM0uZz=D`9~R$rpBJ{OQi6g7u@Y03i8-wWI%Z`|`wfBgJm0Hfe&14I}^M z)+O{ke8$E+)0(5_tseQ$cPkh(GrwijKi|1Lv2_$;7d?lo z@Ld$Nj{eu%mkXDT;#ctvI-oE&R1g??h_?OC1bxi^l z`O8QC%k6gyR*b}pBF@*Dd^7|3uDNk<74`kot@rYqMxY~IdVTlXukTT&gXr?u%o1pu zU}9wCHw|NY`E|pgJ8V=>k(u8*QjRPeg|z#(+n3fpUW3}R;j#IDx_KF!`JJn`bo=dsg=37d9-e*uwi;Zv8+KOH%{A0HxZ&{y_Bh=b z@4fiO?sa?SOPTQB1`a;i?-O1<;xav3UujN&{Rsxt1cM~>0;Rl{kqSIDj z4*q@&1@U4agJC(imc=|8hilo8xIIDAI*SYl(Ked>R=wA#^5UK4p~MS^7Bs^|=>ij? z2cS8tgbQbm563E=3zSuf&?!HmU;;o)!)MrqCow5-vH=T1?(+jM@2GX5nB9@%a@JI&UxC^HMl6nIb^`S%Gr?d(2uxs704E+A!4SVYE@@AE!sBtV+oEGO zMuj_69HO~P^8o~y$24L3NSbbklK5GbjUq+~L2Oq-ppSI}LL&6|i{=Y~BUB334*lm} zzLvjklo-bItnsUd|MQn;^41O|D#U958E8s{YexR_7w1IZ1R_K=E3CW~BmU{jGmr*4 zi8STT<`u5rQ~gh0oP%Hg@r&2iK3N6tc;oDrOXs%1N;uy6M5TX{_15XF7hl;5x5`;K zm_hPthjwn8^M^0bp$HeYjQHc1=L(mNv~X(x2;$htiNzzCQo-U8Xt-~m-TKyl>)bvYC(_z&RZQN>FfX3m{N|}`M6lOxp37N#qJszKAAfmv{ZrMD*oIwm zc;OspyJpL5JJVdZea=7p;&qfCfc1}GoL;x3+R73O{LNRkY}`GsaPw$hX6fnN-mj#l zA4^YqDtX%OEE(a;Gok7D>qOdt2BP{ByT$_Jy`j%kpyUKldqmbwRkpXddr3X4YB7#V78KOL!~}ff2bfDguW?bA%s>qP#|egM~@~lyHJH zap*SLp=QbXaE*4?^(5|Wu^xQr{y2rip`>;!97pq=f;Gec{>l-yZ=PQL51$_U~_%Hcrd!r8TdfA!cOt{(gSr$?9Vnx<77l7>=c@j5585BmEn$NzZs=pU{g{rgXk zcJ3;J>UmGA9xwU*)#E_n51$@hv#XRNZ=PK9#);K%ABI}9Z5HJA#>;EYzqAfjeM0Tv zzq@jDT-}g$Tgn*6nWE>n3}FtrEdybHyl>vLHO%|qFL?Zle5UtWu|h=e7^ zzi?tLaD4OCHRn&Q1)2_?S46+E_w-VG{IY?}?T?=x<`Mqk%8}JO%Fzelr0nqXAFm$& zyQ@c@eZDbfW=P_0Q?%jLy|~eut!3a94PD$m%B?h^jtQJ#syx)2C)T26=QR$dXYRuO z_^B9t<)&GPlhvEcIY?;wjic)>99^r8@vh!j$`Pm)FVH_-J-U8RMPOF2UsVbq2+qY*Yu7$iUbKBIgOt9J*XND2o-d`R>`msv{l}Xp zEgu%1W#h(1WQv5q9g9Fhi=Sbj;D^crm=ThMQAE;|L=O=U*el`!fPV28!R;_3@R!%) zB~h-EN^w#E7ki3iWQkIQ#ZcvU;}c+lEDdZFe0SUe+fG8O+^SyoiT}f6H}i{ zO?@Fb@%h;JJu$JHqH!@1fxs|Ux|UxUy^;+A3k(qq1?&$TRxN(AlJM!0k>}<|i4RI_ zC()z0gbQ8WNqoSn1!~OPj{bl9-t&1K{YSR;%3nDsZ`HuO)%_FdBj;@%_sv_oCUguO zw_;F1>)@E`u=pQf5cucH{JBd8{q3b^n>J3G&@y0L%iv$0+cbQBDlci(wxYki{0y4U z-&}rf_4aA7lGl#3zIM1BN~HhV4bxD@-#E1F+@UtRz&pNf00;AG`>)(M?e8u>3$2ZB z9LVKt39F?itzN2$Gp|_58MZbUVSu?|WZGZb4FSdF|dDpEf=5ZY4#LNJX(D}qn9FxclNEi<; z&%Sc)41yD@*A@TW<>y2;WT}JeiV1AsljiBxK3P($=rr5{x8=%H<`z zbI2K`2;qtsmRpDycD@g#fuI@@5h4>n0ePtaAzNT4l3OK?C~>7=s%&ggz2;iDL!;M4 zraYdQ{z8hNz}1~ZHeg-c_r+o!V!iR4a+81SMe?pG~NvSU;r#zn&_e5;e zrbt{&hzG<8mIpcy4e5e{B-S{N0^GMt{Elh>0w{n9w@J(nnbBe+JS6)_vN0rVCm{r7 zgu5vnc`F9|^@W{T9sR_Fu5skxJj<-c0W$eF7kBzdMyj+WYpB%LNEs?MwG!-DJ8yCS z-@Umrx4FMYV$uwQ5po*(;H>D_G>NO=-M_u?SjWaGu%vVQn@;a<#NWAR_v}wktU9}| z>DIYTr}s61lH7&;=$upAx1)11{pt4JvG&t1G^ba@dx{M4pG>o~V(ZRlGMXIIsw!);=+iq$GQ38?+u`Nzi9 z^aaq+7h&r0)qQ?Azw^?O)|1aSe12lh&rhu3iGF@!^~%*#tdZVx&o-ZZrpYthvwVfT zjlfhNkz`)cnq5WE*PKnc;W2wkzrYnLR<2E7&>@E^$nx0xsA&hQv=RES%*ipPX_P9#}kmBr>6Fby1v1 z#+xmM5rFegcf_P4Nu^jJV=}=c8(iXr6@pN+f{*=_i$vqCnCqEk(|9Ff9=2{~nn z=Io}t#@_JmRU0S#aC#F^SlL;Sy|6F(&z!c=)or7Ae?6;WJ2n)q>MZE!oWMceS?^jW?puVYQY^3?^oHGKl4KH#e<@(18S)9ojBmi*PZ4SOChk?e$-R>y{d z73&KahbEZ>Gql+qqvmvsT(K#imR1`FzheTlocgrCI=4Qvz7J%AdGW)UjX8^Y$B@Yv&8R62_#Erik@5Bvwigh+)AX6jGN!<*Jm~b*;fh)%5}~>F4>q{-BZ$^a=hd< zrA>=jzA}IL%7PUg6DnGUuk4u6u`<7-y+9kSIm3<0IV0xG8Ep;KGRu0eTvdSMCAv2J z-Pw)pPfQFh4CXHy*s*rPidBVk8b=ZwOq&vQ=BXN9U}fV7JKNv0D5iZ?K3A<=TR3Os zXwnmgZ0)`A__W4z6SloMbIF-W>HCw1J=Sy0-iaNL7p~k=NGefamKB&Txd1MmB26V| zQ4~<*sq$sTUDoBM6^2eO3(0yYnN_BnY$m=5Vw&YT?*u7}>=C7F7IK16b}(XgPy!4p zW+#5xS>h7JkpPURB&`;}<5ECWp3MNE%B1fG7c#V%l?TF=(vCHFPmPP+GCgL~7 zCT@>I!%El_pZH8-%Dx`G4y5#aQBt_hsg>M4$}c1bP%=CK1f#h-)$2xFIn=UZ)3}aJ z<5z4P-?1U5_q^E3Wc1&BkcHD~2 zoR42@9$J$OT$ZlO{_f?KuFk`|M}**yLgRwzz=NDw1_~zQK%}Vlsb$g2JI1G$#Y*xW zxzMBl!Ixn=lPvcOvxT$=&r81eT+I{PrY&DH4hV8YK0C}&GS0-eO5;PJFNsNk-)V+{ zmyrzc?E3WYPINrJy|}G&T>JW*PYyPYXh|H|nEb(ujk_M3wwgy) z4!14q7`I}@xILSSEPPmUSptP4z$dXrZ{=<@6QdzEsp*6_5_i0eVjoupfAt%PxYY+25Z7et7Flk)6Vqh^LD>MZ}jPVB(2A;xR_N@ z{+6&a4~sV#D0TQKybU4*zyf9?!T_5i&BWA#s~y5_iTY?M_H~Dyhf*gtUXnsi;iPB_%u=8?z${ zK%g>_zvTJ^f{M$#-XwC!QHn$uEERbG8i-Y(fT4-GDwDea#wW>Keeaq#FM48<9kX+)+F&v8`n=bxx19(C-;=Ryt|a#F4QMn z6Z%YjNKGO~UfEsBmj30-hU0bx0p&{uzw~%1$=(`CM|kzQjy*Pm$L{Qpijb z!e+Clnw z4-Ono5wf<&TG}YxJ5tkzdGz7Bcc|AhR5xg2RW@IV6}2#wv?}i8izT&>j|nUfN=i*x z5Sk)(W{mgYUn;L1a^kU4JXgSr>LYEu<%|cBeyAH_j9MCw-W8qja$?$>J^P>S)%S2} z!V}Svt0GX+gS8QmDtQ~Cwoi8ys}Q4F^cM1BQD88<1=()>hh&K({7C&nItmL>Sz%IQ zGS?s=D=FHlY=!rUkPtb6IjssT#HyGp;XF5vEm8z|Lk60p<5<{XC{AMPE9FhO=2U!p zjx9w(bAq5MqS6Ucn^fU@5Cz@36G3c1f^Ri`M{ME~c$N|o49U+YB|Vpz{8UohV{s9k zk-_#LLL%5Gb~SQBvh&1WD_T&n8HchJT5KZ{$dM&!oY(AY^E<6R-!dQSliOS~Thc^Y zEFZE#RThbB7F7x{Bh^H91g>22m#{5JKb|9Y19`;~)SsntS0vZhmbX$W;Yvx>FEb;` ztsqG|Wj=`kh>@X-BrUed5|BpDw(xF?R5D4%Cj(q6-NaE&g#?LaTtfDdx=K}nO_hKr zAaENx3}&{-ToM4~!;+&QJ`mqzKP-u$0`4a8fi}g*7ul^`eW*|1fczy%Q;?7x>Eb$p zbP57cmi20yBxsrQY*N!Xhz)@PrcZSUL2J{z_^%ifk0yxpDGH+e4e{WE#gEqsQJA?@ zMW{@qakiapk;NpeoU{+N*_J-m)JK}e2u&Mdc!wF@)WADrF}s#f#94f>Ju-=1&6#$e6-51j4`3YEw)I$ z$;vN;`cz@~=9uDYo#U`0B@`S%R7e<31|f19nh60&Vr!^6A~Yw0pfvcCG)B%&6;Xr- zAuz=soEq>?7Hc1q~J4b|ii+z6<;*P~@iukRz}|2uZ?xk}U{Th@LEsJP&2` zj3Yjw@?zD>AKeHMOi04g+He#ZuA8G0w?@Zri;UYE1`y=DlHf!rBBDuzgbGEt&Q}$i zLy2m(CEc&p4lH*71mur+aF$B-k?bf;u!A-QEI4Q_wrFBrv{;nyVO3y5ARDML#f614 zfqV|UW#VS5l$gDkUN|Kr6fC7u5VFv+s#$~e3(>)6rFutHAXn=Y^pM*j#Ap!rk?1#q zc)sSHPgbCW!S!n0Tdk3vFGd~3bj0|`QikbIk!XR0oMbBwMWiszg@X7oa4}Blc4#P< zH@YxjqNyFFg8?r>d*r-!e_qJng#tlF?hZbXQutLQbB&@3Re=hWCF(TOKw8LMCR5ku zm5d79mSm>pS)M$VA5Nm`c(0l3p&8>m#GDDSX=LqX80bsL1{&lK2x!(QgTxLO8AuM2 zHi!z4@Iwd}RUrMfwBB#^O+VQyerE!;!V(Xq{$P@@Z@~oBcB3?Hq{fA)VMrQZmPir! z0fZ*G6u1P*lO~jf6B7SD$qsPJ1(L!oABcDZP#`h8gmgbY6fHc4v~a*JS?HQ-hS)c% zs2iq&Z%}Fy5$AKsRuCR0`?#K_o5UO3*DH46Odqays}evsVrf&zMCqJVQHZNWbOLao z8ejrFf(H1j)QStFkot%mcGTyVY-YiPirGDa36DpR-yS41O}1;?dQ$wNXaGXencAcV zLc-b$gS-j(uoNpuO%X*$K7tV9Yl7a}ZCbF+0UvHf9#Eix5?4;Rm{8)u21$}Es|p(M zxstFX#Dd2edXWSU%c9~>`Q*BosS5&C(u_!zgQ^Y(6$Lty>UAtzsc4fDIfz}OPzxN8 zBsgD^!wL7V^`zMWQE)6Pg>7hy5{sdXiX<;v`ZKXKk@2 z=?jx3H(RRSR5i8G4q;xRby7zpd9mbJm^oevc#Rdxb!C9s%K8IRV45K!0p>2%*BP2N z$|FKzB%Or@o$0=CeN_CO_|$XB{od`<_jIqMCwqk2!?^gsB?deoL%LYQO>>y;9j<#u zcnNGUzLRBPY?F2+MgRm3%PtXOgyVLz7*V!62$@|m-s|i92+zHzMR0G0OwIl zf|SSsf+!OG)U_fjD zkv6J~6lf49s_<0&PUuS#vlHj5_yI^47e(7D-TBQ81l3I$;S;xjLrEk8&Tv z1Jg_RyK*H7Uq+!)ODp&n7)1S{K~xkXqE3z9SSX3dl2E3=2jkWiGm_dmH`)P*n&n0F z5lp!CLfuwHmwDlq(eY(eq5xVG@0HGENulHb5y>Hd0bvay?kN+iHkkl-=XD7jfyEr< zc2^%wK3$mvs^Ehn+px^tG=ET-Z=ks&7=Q&(01#B2@{@EtU;&>sh;|7d7cl^_>nKR0 zG#2D=p};AGhuZ<+p`$f{h7p!A%r-{aaxJPwLnwN8Y|pc4L*5-Y@YQ}PkEcYnMiFsC z33Ny!&%i?kCJfAS+*YD}WoZoPV7}yvwSf^XTfi|k?aMa*dz5E91*6B3hjleqwdS~Wznx@J4VFXkGQ`vwR+ z3RXT6$$X#igG2Y7l07<#Mi)v zNBtvxOVA*-t$`3J^lq!wh?bWnpRKm16yxYCCdcxX0mS zghZcXeN!Gwjam{3jyYv#*+31IN#x2%lS_bzYf{Ma1_M(6MvK_R6woR5Uf+bq!cINUgBs+ z+DSMMHB~V2=Qy^D5UHjh2e4jLLLq;mav*~R2gsyd7LrwIB(Etb+9F=vS}B8YX&FY3 zvq)kLEtVe>VW}xv6N147gtE6m1Ez!Pf)!sA7D)xNw*YW ziyDKCjqXH3ElOIY2C%Sl5#P`|m0xf!mn0Q3RNhWECWLCppHbzfqU0iiCkZ+8;>EVd z!;ZvP#ylhjpn-xYQA`r0u4|bBz`UdBCNaB+ z_F%$O(LE2R^n4*bc~g(bmMAzZStBS&+ywzcY(rMG!NA6_P#T&@rm-gRmmZELEN)k-IuOdP!tbM`GOC1PVL@%l!@+6I9_4AR&_+jgCm}42cZc ztZXn-mhq5rCU(7Kz8a&6PB78Q>Z&4oL{5MS2@EJ$M3U*WM8TphjJqjvStQkSU_wH5 zwLu&UaCSGPL$>HY&3mi@GHQDCx?4R<;FI zV=ye0}Fo_0{PlVI<_2~U%&y+RE(G8Ih8gy!p^HGwmXE|D? zEr3%_C$YCNQ^pu}hHj0~^wEMjbF3H3gInW1V*b1eguP)9fDg4~h>$Ax#iJpDS*TuKEa@OBe2wOVH&@UAubL!_w6U%N%67y`A7u;a zkM&I6o-7%ut3whju8-grqPZ#LiI7ksUD%Z^(F;*TMK}@0P&%+kxco;kLFTwr7)f=u zP1VxEAVx!EV>ohgIC@!ROj|g%Et(x-G*K;~7?jY3!AL{}MSJstH0qxvw}ZHXt3=6? zf3k#)yQ~4RJc;5h7UfFPVO>jtwQQ(iWsL`-)+#?7?LugOfvZ9JMP^{e&vyc4A&ECd zx#<0=tz^7E^v~Lg{?U#z zQmhSdDVWICFf5Gmtoh+XJ@*y(+~zM7Jqn`6q##^D8c=uY9 z35JS;s79{YB+(Zf%o9xF3P3^L=X7O25EDY7Rct9Z#fh2~idqyEw=Huizq$J54C@e~m$YC0=0mwf*KxTEx8wMiKYYT@#jB^* zJ=VccW?!8$Q_K-_y4NoD+P(B1Dao8Vf8{i{U`%(*h1Y(oCj8rv)j00$SO^Tw|}#>D;=)h}Dct50vgn@b(|v z_oJ`gWDZQGbK7z~#_JjE!G>T-0f{|eRAX#sXx@REH%6m_yfp6q?PazyEU)qV_bYf0 zNmf+7FY@WgzDN5EIM_F3YjX7BX#4_Jim`r2`>FH$zWV-y8{dD-q%8?a+Y=JE zNaURLB3ZGOaI~;&98lTlha&dC7V?HbG^#235?a4l065>&N`iPI&?n+oME80owePuJ z{on4>_toBMPo>4Q#bf4nyYGlkh=d?z2j4cHa&BQ1%9^F@$nA*6PO$NzIb$RYgE907 zCLXXZ@I^=rd7&?=F@Uxsm{=BKMFO^wm=}v8$mbv(7Gs|>a}`2VYiXkDpg}DNVt7kx zEQ@4Pgo?hj7@Mc7s!md*lz4FS{v=BZ%iPVFQdWiQcVYqotYy~V8*5gUPrY&Xt!sDQ zx_0;C^}FZU-njer+wUBzZLC~aU$wBIyr!|duCAP&+J=&a4HdQZWpzzu9O38s%}b^K zy$jdwp1*$Y!u2~`E8}Em4wu(6pGdE_zP{qX;m0~REorE)SlGk}GL&i+oT_gqr*$1^ zEai^1_2mtX6*Y~en>H_DCSTsYcXJgrls7p`@ZL| z-+AlG=dUbXQBzk}S=T62t!a?EFuv^Y2pnlF-*@OS2Ba}twSD``J8v~KlzUTI%SOkF zMi}TRT5@XasndJio_qGL5jySd=`x1LdU@9B}6P+l?Z`C~i2`sST$_ujew z%{yOy{r0CnKU3FO8H(`hz0pD?6;VPaIUdk}9S%`r*^rEagdhTJMADl&i+>jbRC-@calIQ<5@((lt)(Awu+con^fO7K2ieA@Ol2!wx$D zOM(DKa9J>IXY$Zj2aR}dSf6)##~+GM+z`c3_~t2Lky=O~NduiU@9`-q6^wX_@y4GLQ2btPHL$+b>iIYz->~)6y@^$WV>)IJs6Y-iJ zvEqs?cCLPM{LVFQ{Tdx^UO#u^+L`jQiDoYYBgWg$%b48G=%=x-_w^cmG)RoI9>;Ux z!gCBOBVRjn+yJxC8_@=&F`z)?D> zv?gm;guDX=_u8^y@%8I(Uc33`jhnB3ar3o{@4PTJbEuK5*(3e9ya=H~U*Ofsc3|-o zC;*7?!Z55fwlhqPGAUJwhvIvk=r!pPinO%o2@iOB5M1_zacsx)!rBSytQAO@> z5E8M#!%FmmNE|!UO>eB{z_Y7wfBw=}pTEpj&G6XG&rb+b!Nte|s2=UsXD6aP9#r5itg>FVWugZigwsZu*_BkFM zmO0D-%_OEKChf_TKIeP)zSuAANUzv6@gzy`5-@SG=OuY?h^9;P0zqJulQrn=H=n-t z%Tu?$eD&HdUb*wd>Gq{_G5C!BUVV&6DPN`;$_-M7h<}N|ZgfX9i@U@>9u>bgCVqch z!twaDS9%V5z5kF4g9n`Jn|wGSdUKSd3bD!)D+Uz!F?3ODX*{VstXj2497Oq;-;!2< zFD}3WSpz4AW8>Dtft!ydYBo-oQlsGmF1z5Ow zCK4Z!OZ+$%#4^BEa2M@R#n=*uU`1GWQCRW>-M=kCv<}5dVFCoOW*-gbs4N7_qEC$` zH118&Ufk1m^XmRvA052$@qt^Pym<4Y7jJ)ZQ1g1kN^g{s3mQhdEE3*qV%vi}iAFTa za^iSJ7FJKW`SE^fAIY`1K0d&H#^`~f>QcOoA6F&gOP=6VKSluW57kw)*Qt{HDzQ^> zj!OcSBwm0U-0L$)7dO1o#(^i>8Sus@FW&m(d8T*m&ia5F@cOR{Y1OK!NQU^{7DH}DqJE*sN@pJRi0FDSU<>9GuuyIy#De2+aDibTRV3$ zcCRGgsr*z58nC5BS`6`8ah|%lQ{^rn?f>-R-pTnR;oTL*A8A@ zVGr^Wb-<+)*BF(&y9d0xH^TSn7Bn1mhiRN*8%8yiot@{2Kv zhvQO@rS?DFXXwQtL*DG4ej+)3S1i6G$ttIGQFJgMXJfN2W%u7dAbwqxQ>W`yCSNBs-GSMlaS4W0_6c7Tb2>257bIH+ z=a{UeDC3KdP62|eBWB~(A;H94 zSxHUB42c{DWFJoyepze`>cYGV~SP$ zm-*0|4?VW{#-(TOUfO%}-MzQmc6l%4W&?sI%Wg8j1bP~2>ii@^hm9f&F5?p;mvEF; zS5DFbL)$PlB8DI7<@5N^-E5%MTahKk?{Pe9$Pr6%9arexT{ZR9W*21v( zR;*~mOh{Y8AQw*yD^+4AhrNe(HZ$g}OS^AfdWsR))>RgYyH|Lqhzj|nM5;3^j|v+Y z30i4!Ca;LAZoIo^eOr~x>fLAVyz}&}_x9Xk%d=nJQ&BX|6X7v>oBm-Y#Sp}bqZUOc zJ(1MsP+I!Yl;oZ9EM*7NByM30H|_q?P!~OebmDyuLAvoe8i)roKE<=KeeUfK_ucy7 z1-92eeBsp>*VulqG0Y~oLU|p$GkSe=@*awud!)UP(&M?rxTj)cpNfiqCI)+=-%GuQ zzCL8|`9Z0#q{Qxu#pMq@Vmh!`tUP{}DcUd5cost#F9|M!39$w=^rG;*P|C)Xey{c$ z`PtBsSBLj|rEeU*Cit}b*H}pSn9?25A#sGzI!c$Dngh!rY(oMVe@-J?7XAnNWQX7d zz(XbBlNtVpV|EYzLh4DYlte?^T2gv}f2k%wNgd!IoCiK+nH%7u}m<* z0SlI}A%xf6)LP8S*v7UH^P<_$7K%oR5*0}PriHBHFZmy&hO{{}-u>Zib+^v%xbx=D z+ZQ&omHqQOuzJ7^3KG)7Zn2RNA|4t|+^bftm+-aN3JYwE%)0Vi`ro;*{nmx;H{aTR z`}{Tr$sW;L79fW2Q?Om6{z^fyCX`N&h+2rrU35m`Ygn6j^>FDSAqcAyN=3gCbHOm9 zwF6t~+$r5WzwIt_yRhAzn<~6OPIzve-+B9@OrBG6mRk?+OPU3r7pEW&OARF_SCj;J zmZ%CjM5+xltf{A#hh>CY7q@Y3eMz34?v+(Bv173+FhsGp(cjeyvgE~j6SYCTl0Q4K z=`MFvx082uVcYFD)veF(*tEC=rz~cZImk3e%QE>ah8ep!I%QW{ZuG^Kt5Lj-J4+HuNM^;Y&w3%m3X?qRTgz|0y9e08Y{1<5wlYtWhM1Aa z*2Zw`^Rc}SC-ym*O6`Bb?gT<0;Vq%K?J+$bPabfv_n=n?3_908^>~k{t$RVF^$FGX%x3AxrOT))}It-OB>Dd@!j@CRsHQv6d zL5p;H76KtLtiU7je*oeBIT%(`CuW22BSR&V+7Y;*fwcA)2SU>&2L)q-IC<7X>pMND zNy+NtvTm~!tV&r3<$dm7IU;6Q8ZTdqC3fvfJGS%2^J zrrT#XW)ABq0+hd^Q|y%l8)QJKVb9h8w50lw_=L-g)NzWAR7Hhg1@C#WgU;&~6p`ca zjnfWqsAkxk=Vbg_XExkD*U3+!Z&-1N0WhI%>P~wTGpA4X(4LYzgxyG9soQcqKKL(C z$np9pj$={$XwTvG3mB8BGQyqH8^1oizJ69Vaso8K?3g@U-b3LVr9L^js-n;x{w`Ol zhi**c_L)t$PH(&`kGxSH`CRA5reYnfzo%vmwsD z$8+D}=1WQdki~OKeeAe007IHcIiA<>f{-+1#sc|UU;z@4ROTXi>u!@(nkfX7m8ksU zmz6XT(V9eYQi-#;W~suHY$%mCPTB{BdoT z#yqi-TYP_%jnG(siu~DvaK|0?9kq@9PoGJ?D~7>HeNZlJTl;~TzOvV|y+*wy|aIOv%)m$QlK*C=Ut} z;RkDsBdIWqPi9P>C94)p_6PWjOjFhJA;nmSvWy2x<4k4j5maiyXz!juWqY*s*0H7cjxB*I5fW%zl3qoK zkiRpb(y*z$Aeme=A6etU!bGf}Hu~%1%kFWxYFy4vX8&~9F>5U%Q4kEM6P0;G4y`J? zd#sIi`^d7}$CuIVuG+H0<+Qsm$@cc~HjaFAv{iPx<|AX?V|vGz&;bldZflX~PG28i z%4jlA<-tr*W*b?Byr4H97 z*qh_!FRidV8*wg_mLcgepT5w-z0@St9c8x5c>ICsao$)jG_DOXQThEt$(Rx?2!0md zDws&yoffk_2JV9ACotUd4DslLJf0yE9=8V>-UN>p7M`HEg|G)NsVW4|`)FFwb7ou3 z?Nh73?%h+X?w#ytnlU!2EPD9)A^lJEqnJN(OC&3RMYcr7ES1F~W41>1*qhk@xt;^} z_wVy`YV3wcaaWQwE`bfn&VrSbIweuR9LLO)_yp;MIE6y2xxCC5y(^;6vGmbrM~pl@ ztmnR-flVrb4fB}v5#=z%bikHI>d2Zk7!YU!D#67!S}b-D1Hv%orLjVn^8WFq$dnap za;o^9eqxOR^6W^j6Ie)IzbXikbwk{W5djA{AcfmE*Uw_kEd0O`a@gr0YvWQOO5wDs z2PMNx!VEC(T1ONc%mu^)C3wh#l}>P_9l$PI;|r|yhg5T6p`=BCzvluzz{If?)9)Q> zzIUjJ?bioo=j+4Gd>#OSwkA1lQ*828#Cc6MFNTxSLon4K9P)D(P95o9`1QdSF8}&) z%bmkb*#lGf6DQc=__#=)t}hzKu(!C&!4?{Q`1#GDmU{=9)Fs?h+Sdn{d~;YPaQ8^_ z*M}By?LE{!&Apd;WSMsT)ZtoBccoZ^&e-I@!jLeThJ+ZH7W<25Yt%et z&fM|#5%sQ^-r*)r4NQ*)YIs$(VN#xr4rWaB5DHFOkYg8TVdZc4<%TGfQW{NW4C+YQj)qB*)u?_Z)A( zy1zNfZ}&gmFXh>kxUF&g-75Km49(%_rBM+p!x38}SOY5knbclS_3W`V5g|d2tUt#u zAwo)?GR2$QtvHc~q1GXvW`|}4!c<7Ciim$9hMe|c=Y|YEK7duq5EABmSv3~@M~ddK z^YCy}GMn$n*Oy#g2J|wZKgZ&a$PlmtIyCXfl1r#CA=@dow29Wkn7F@QEcyf106I0f z|40b=D*`O9CQTMLaE%5qA!dXMPKa8Cfvpw?kSul59NlHkS=$GvGd@~kc~sBww`=e| zp*WEvi-NRDT4UN!k5-Y@eUSwKT4xG02?*4dVtS z;jY6Z!v64>`sYv2`}*KQPBHkMgLUk<-R>Q1q;c@BI?Et*`}%Ohy%%K~cMmqw`B&;J z6O#)MG+f$M?(u8z9Rx9xy!)cu@!NwkdCqb`siW+eecMkdxw{PeWdZ5LrZTTZn=GE35}{tj`Y~p7(6&oDCr7c>)ymp~ zvv|1B#c7|680+lca_N$w54vjU{q4#s;HO0PJqC$w3k#2e<9E+db2^3C6}YV2l&E!}NPI z@2y_1-~9HF1oT_;_sr*ePE{dcPRcD`_zWcjjRHhpR8s-i3o2T(b`+WyX%O+JEvMSx5Telyf-n&~g5-vjc!YXdOq5KRFcg3fijJ_0 zaHOsGAY%y;Ie;A%%^Fcgb9jT%*ij)$FYWJUO7c^Wev+{p{P-C7%sV82?XizDW=8k^ z>?0@s<5G|2GV|r*-ba@--?u!|go1Wx{J1)V$??Cq_{Tc^!AIGP@J8nN4D-v*WzM>P zsdo%%kbH1I+s8lRf&*N0Tvyh;am=pnws2zr51cg%BkCXKnq!xGxxPINVMQinK0gx` zP>wvEx>czkqaggSNQGUxD=k zXGGgVXo!Rx`FeQ$qmNO~{SQ7y<@9TLKplRv}-v7351U!N{L+I_Cion(>||i`Ef?u?dF;fr(LDZT^Q<_gyX83q0W z4Qdk9Tu|;Bu`-jyHV%iraIHON`N1dWRjKD^l?cH}nj{lB36V??870IIGWAu%BqIMn z{q&gTC=A3x?u8*gKrtW$gk@AkyderYT5KbxQ4Ho2n#NQ-s9Yxu!jB24)P^ z4C0r8OaLbk27p;UAXuTK|HklIUDl{B^I3X#tY{O&gw#4L7ldpv45s>%PUQCRDh{yH ztYt&*(tCSoZOV=MrjS?g<4H74E&2Bkwwgty@AUQs0nhKR4?w*JmUGI%skMW3Qx8-T z9`twlVzZ;c>L@p`Z{u9PRjC~GtNCWoi+w9vr-(=A*fcxS z-M({q>#pUkneJITR<^KG_bqSZ5i^D{u%el#7;ihf+c>OcS|NTwbf({~KCJ%1(%}2A zFXe)EP9bxQ+k@+t&6~zuVZU*!yt}<;?sh?Q8TEqWe(q@{=>kw0HFP`1CMcyF44SWv-SK3F>K^t5T`rc|CTp>Yp2HyA})#Npzh zbQNh(O;lKfYPi+}P))i`kUe_OZHX7XQBd`6MeUvG&3|bk2VQfjy7Wv5Rnh7GL;))_ zwMN9>h)jdg!fFCSNKq+RzZGg(NgNknfe@C6+)PR`_hC8aClfJekXwnga&D-eKh$?ht(n-zj4+nn#eV}!5i|D!|~Md1drYk5Bmye-qi!k$FKA}yqbA% zrT@Xzj5ew&?1SEtIX=a$?Fs^D&!)MKBTJ4doF_v^hbn>Wh7Z?BHI(yy1U_UdN%r24SgyRuLF zSGEv$!XCiPz@$vOVdnVg6@4v_uJnv?@YP=K|HjCgbWAoU=DCmhpV?uYgK$FxfGkSo z>cK8nln0jwZVa!kEQz}dovPu=%C{;DHmDMekx7~ z1Q9*Oj98_ylXd>>fV&eE?uc6)G2sdw|lTI9@p8-4${#@Euz75@JF?aXw-Q^*ZU!apla zFg4T|X7xwMP<27M-*0z6#~X3{|NJl8y5~(NAyL?qj=vaZtt2PGk(fsBy}p!bjz(d2 zKfEmK2z{WBwm9s}i^9bmnCA;F0ALzTZB6kRZw#$N?m7NHImMWW{6J+#%ZljwNH^T0 z1!cn}6(eO+Mk>n>m*Q{ZTGL~WFQ2ta=ncdFp)eZ63oLIG>*cfsiX6w0=su-9Fx%IB zTRrPv+UNasPSaO2D$bXaP*MJ@%SC#~Bm$99LgGcoGqvAQ6NbY2vNFL!XuUCxQ9{u0 zoyd=2NFeZO3`aqh^9(u2b}dry*_Rl05=V%JiXC6Rg*BgEHc1QEas>Mko7+<|;UWC_ zIF*%yocpbFnNY0GDt^v5gu<1_-Y>s8Iq0GolE+;J!huBMSYS9s_r^j~LRXG<-@o4T z=!@Qm*E8eSGY>!SAHUv*o-i~UFeAk<*Z^c`&cY^SofuFiV$0AV7_8XW76}J(z_%ND zMg5S;HiG{Emb##=eAHZ%w?OztulMmT11o1TrxY$jZeXpXR2%+2Q?Q*S3lS7q&4T4l zcbjJIf)R*lMn4NCf!a{Z_6KcFG{34SzOc1Q0kIZYbn{!vHP|rQ3tDB)v4@R{(xk5> zaOLO<`+51WqhIjB`*y6JNr78<0hl6ROHI*2b1(wEs5N`yqPEi3>Oz&(&R3B(o&?ep zY4L^X!#L;uYKcXl%IA4uPFd7EWqxZJ7fE@MWOv+I7>&&e_+|*Tj<<1j|4P&kTF0t1 zvUmJbz`9xY~+4;3R5 z*iL1Ki>XWl1flPcG#SpsQWyPX3+srU`a%C;0vT{P-ysn>k!M2tus&9lDX2JCQuB3X z`(K;q{drEy^_KFp<)pP0@I)q_cK|w*yQY#(0jO27rm&i%FuJk>EiUE<5v@Hb5U?(o zB6BqBBp*AA^gty1sUc5+(!Hi|nn)3@Jq8a!q%32rQ4dtut`|`&ya<-16;;8oPt_(2 z4p&~?pgp42;n75*RKoq5gI7VhQHmtQpo;^M97-tnPulKqj6f_yj`#iqdg98^^6{^F z8KXCPMsM_v-rPQRqo0tDltC^L!c1rB(e%&pL2uZJRwgubh737aNCEN(2-!$wh3Ye(9f#D^6k%}$3CddIX zKePpAvb9^;gIA1ifm+9f7Euzpf!x5b0b56n0!x+P8rXjL3Ls^R^{F4+%#423_mI1~ z+4tZ^-@sbw2`uHnQc=tVp=p{WytfFQ;2bapo=_unkte7LKS#52k+|i)dLJ?osS60a zRPT?r2SIGO9ged&?kyD;jJM27%#Lwa?5CK6Sn`!a-O?r3`o}-*`_E5z_OEIVPLsur zoG}C$ny2InmT>vOs)EghJ6EtCd(R zG`FIy0Wq;wK_^@X<)Yyxg_E%>CS)`G16a<`ff%5(eix*T$`Z@BU^(Fo4Ume=P36Zg z%LM+d0;Ld@85#l6!EV>IVj-4uVCJ};@&F^KJ!fQhZV*Sr^;9L@?r$e{uD+>E0|7*V_Ad+ z3-gwk2DX8I5Goy6>0S`_#>U6(BRXC5H!En}BML|Cu`KR(Wtei?OC#M6zR7S)_rKO% zJ@~qBU|oy9j!>dut)Q+L2U09+k)Y`)FDWFlOVI*Zc=Lc%CW8oU!adOJU;xquYXM&1`MU8*>D=D!cJzsEPeB+ZDC&w!h@Tn_6gdU;!{Oa-knnWeogJ$)n!8h zqkv){cPs;iaO~PW&n^7Dh7q0ky;$xYLZ?v z1DOysgjor~?$r>PZAb}3d_%!Dd^h_&gg~LEV~Rd$ARh+sL809H2bVtlw(tI(zVUA| z5AO6mxYNsaRk_PTspXX#d@3v=XT7kiz8ohlw~!Fcdv4x{;!6o>yh z3PELSZ3(mQ;kW%}}MVsvXX2J=J3cc6o6 z0=}Y3?{qcl1t%NA7Uf#&#BQUWM#Pr2eZyq%`ab2-q#W%!j1`(#06pS=*^Kw2YIUQItYy8WBv9Gp2ywP+2 z%ifV4^L>S3E-17IU+-*r!W8}&?k}!+ug+_8FAsK)f7K^lYt-$5EpubfdSxfeD+bFe zkCf1(qGVq|;qH{kA}KeZ8Vz_*mY6R~*@Tf}#o9XCs0~|Lq|zqJAXY@6wWPE&wc9N| zP*8THqGGrTQ6sZWyC0SEz>KrW6T*Y=t$6(c$N|G)9il?)xgbQKf}q=C%#I)#5r!d8 zl$}Y)0QUl!$Y-vtOb~Z6wWrEY!2V4uA)_QzDgk9BtZFRrl9}IMNKFOxCeLsl>M=7=)oH8Ub?&*FTb>0zHTb;9|$CfZB!>-o6+P1bI3+7Q+h1 zx`VjcE^}wY@`n50?HK!^_rVVtJ$~Om{$1wYN1JzTYTL1~b?2tG-i>Yj8}(>6*zVuh znjajH+0Z($sjY8A%f3v?u${Z@Y5%o?|;`b`duH_AN^kM@^4?h zwzp>vml}Afbzps~xiZ((8|6pt9l3ZrcXA-partByI}r<#e2uQ(*JXIiF zw2{Gs;+?`J&YY$Ghca2f8Avb^fLH(rpo&-iM2*jf7u^;%+~9FVcraHem8gsOY9-Jl z9HX`V=Gr1@&6|B=H#6fm2kw2i(HHTvz=*AX7I5xpf@Hupx9C`L&4ubzJj#*MuQxLf zbylW(L3R3-RN3+3Qap(xMWDNh$RZPzrP0_*43^uC1+`f=M4bNdz`O~UQr`2NYEKo~ z0{&!hj)(}DK9OkQB5YJqC&jF=DBzmlrj#BlB&e0zm8O&jXFIV9q?3pd_)c;vS%D83 zoC}3y^btt3(AdrhNs&m0$Q@a!9>iitlIf8oVu4I3M!Vm^xc>V6Rii)ljos@Tz1ur_w`bIB@bv!O-uw4@ z*cktj(VHI}rh|VpgHwLWXwTh#oqM-u{;Vo8?EnnvjX~5IlcRg_^anrnaJ2__^)3uH zcshP>J6AR*nhWaP^Fx=iZ=@rC)B*Q@>{~pmf=nz{km~Y8SS^-Q9%Uop{;kkXnO@Lw zn`V!STyX&H>PW`P^9W*7Q{`~;w`=qf?)E(Vv6t)fS^74$Yl5!~(&&P#F%T@QFL|oO zeeq6B`84)^s685KkH*>+IhHc3^#c(PPYVIO57qkQG_*vBp}L(epbF*7TBD@cVBui| z8hv1A{qYbcD_VK{o8HlHdQnu1+bRMjAs~dTs@_5wjrfI3$%3xJo$FdSX8aD|b{&83 z4;!Ne;R?#@MoI|55|J$-QSoL`@$TZHUl&2Vse1mMDT+7Msl6wOd%@aC7>X={QgtAM zfhrMRBXdBV-QtM%jM5dt1HPd5#R%tIG85$^MKFI<9p&OB$Qk83x(K$@V~SsT)eA$D z3o)r^U+%QwOvG5SP$;XJgbS7jLL zVJQPie#U0k#4OdZ33*miC6FH`EkRt?43ptt+vK-p{`WeOUqwlT0C~b*N)5(EZZe!q z;&Knhl%hD|Fps3oH?`mT-D;-Z=-qxZZ8PI{B@LQ5OnE!Z9!ZSdZzMwpJbs$_kDoHY zc-%daG?1#Jk??SgFc*tOOHJ83gU|i#)>eD)*u6|{WTiwCGkd9tFJ+7vX^-6~jH~fV za6=5bPO+RaOm}V((8BM$P8}u~wq8#pkliwV2~P=@BUIkkc9g z5bn&0vf_jIljzKllE4VWp9nPyGSXaI@VDz*F(y%0V|V)g^oN&75t2d`9R#tp)lPDo z=gjvS>vR}e_CLOtWs9y|*j|xXktjb^UNT%%a-@iGY|*}glD(;tx6*Pc_K~hAEG1)c zpnxnl4y90Va3>MPr=k1vf+yJ;5u!tgh0@ENa_Mu}_0xc{%QB--V9G9hp z6v)nG{AD%16&!>RF9spD6BZPv7xj8J;EFqKWx|3;7WhqGL}4h|Y4ga0`X~9=Icx`( zlqIXg6UK*7nqj?q!XN~85bI)S8-c)S*c4;pGq9KP17Wr!Z$wFFfS#gQL5L|~KE#wp zL<{z(x4hILH+9%aAN2~3#nZ#_g5w@KBQ@f=C*1fc;Q>Lu0*98BN3_@kjE%*Yec*-s zc)Z^nsdIF^>K^pZFJ?%0DCP`1XruJ7o8T?Tj%?4^lC%mcO{j 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 literal 0 HcmV?d00001 diff --git a/plugins/gs/gsdx9/res/ps11_en00.psh b/plugins/gs/gsdx9/res/ps11_en00.psh new file mode 100644 index 0000000000..8de5108833 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_en00.psh @@ -0,0 +1,11 @@ +; FRAME_n +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_1 + +tex t2 + +mov r0, t2 diff --git a/plugins/gs/gsdx9/res/ps11_en01.psh b/plugins/gs/gsdx9/res/ps11_en01.psh new file mode 100644 index 0000000000..d3b2c9230d --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_en01.psh @@ -0,0 +1,12 @@ +; RAO2 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_1 + +tex t1 + +mov r0, c2 +cnd r0, r0.a, c0, t1 diff --git a/plugins/gs/gsdx9/res/ps11_en10.psh b/plugins/gs/gsdx9/res/ps11_en10.psh new file mode 100644 index 0000000000..d60e80f681 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_en10.psh @@ -0,0 +1,17 @@ +; RAO1 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_1 + +tex t0 + +mov r0, c1 +cnd r0.a, r0.a, c0, t0 +mul r0, t0, r0.a + + + + diff --git a/plugins/gs/gsdx9/res/ps11_en11.psh b/plugins/gs/gsdx9/res/ps11_en11.psh new file mode 100644 index 0000000000..7a2c05d8ef --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_en11.psh @@ -0,0 +1,19 @@ +; RAO1 + RAO2 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_1 + +tex t0 +tex t1 + +mov r1, t0 +mov r0, c1 +cnd r1.a, r0.a, c0, r1 + +mov r0, c2 +cnd r0.rgb, r0.a, c0, t1 + +lrp r0, r1.a, r1, r0 diff --git a/plugins/gs/gsdx9/res/ps11_tfx000.psh b/plugins/gs/gsdx9/res/ps11_tfx000.psh new file mode 100644 index 0000000000..4ee69557b2 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx000.psh @@ -0,0 +1,13 @@ +; TFX = 0 (MODULATE) | TCC = 0 +; Rv = Rt * Rf +; Gv = Gt * Gf +; Bv = Bt * Bf +; Av = Af + +ps_1_1 + +tex t0 + +mul_x2 r0.rgb, v0, t0 +mov_x2 r0.a, v0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx010.psh b/plugins/gs/gsdx9/res/ps11_tfx010.psh new file mode 100644 index 0000000000..fac89d175c --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx010.psh @@ -0,0 +1,13 @@ +; TFX = 0 (MODULATE) | TCC = 1 | At = 0.0 - 2.0 +; Rv = Rt * Rf +; Gv = Gt * Gf +; Bv = Bt * Bf +; Av = At * Af + +ps_1_1 + +tex t0 + +mul_x2 r0.rgb, v0, t0 +mul_x4 r0.a, v0, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx011.psh b/plugins/gs/gsdx9/res/ps11_tfx011.psh new file mode 100644 index 0000000000..aaaf8d6a13 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx011.psh @@ -0,0 +1,13 @@ +; TFX = 0 (MODULATE) | TCC = 1 | At = 0.0 - 1.0 +; Rv = Rt * Rf +; Gv = Gt * Gf +; Bv = Bt * Bf +; Av = At * Af + +ps_1_1 + +tex t0 + +mul_x2 r0.rgb, v0, t0 +mul_x2 r0.a, v0, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx1x0.psh b/plugins/gs/gsdx9/res/ps11_tfx1x0.psh new file mode 100644 index 0000000000..4faac00638 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx1x0.psh @@ -0,0 +1,13 @@ +; TFX = 1 (DECAL) | TCC = x | At = 0.0 - 2.0 +; Rv = Rt +; Gv = Gt +; Bv = Bt +; Av = At + +ps_1_1 + +tex t0 + +mov r0.rgb, t0 +mov_x2 r0.a, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx1x1.psh b/plugins/gs/gsdx9/res/ps11_tfx1x1.psh new file mode 100644 index 0000000000..00304947f0 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx1x1.psh @@ -0,0 +1,13 @@ +; TFX = 1 (DECAL) | TCC = x | At = 0.0 - 1.0 +; Rv = Rt +; Gv = Gt +; Bv = Bt +; Av = At + +ps_1_1 + +tex t0 + +mov r0, t0 +lrp r0.rgb, v1.a, r0, v1 + diff --git a/plugins/gs/gsdx9/res/ps11_tfx200.psh b/plugins/gs/gsdx9/res/ps11_tfx200.psh new file mode 100644 index 0000000000..062581c5ec --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx200.psh @@ -0,0 +1,14 @@ +; TFX = 2 (HIGHLIGHT) | TCC = 0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = Af + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +mov_x2 r0.a, v0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx210.psh b/plugins/gs/gsdx9/res/ps11_tfx210.psh new file mode 100644 index 0000000000..b962a8808d --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx210.psh @@ -0,0 +1,14 @@ +; TFX = 2 (HIGHLIGHT) | TCC = 1 | At = 0.0 - 2.0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = At + Af + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +add_x2 r0.a, v0, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx211.psh b/plugins/gs/gsdx9/res/ps11_tfx211.psh new file mode 100644 index 0000000000..61eb5c9cb5 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx211.psh @@ -0,0 +1,15 @@ +; TFX = 2 (HIGHLIGHT) | TCC = 1 | At = 0.0 - 1.0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = At + Af + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +mov_x2 r1, v0 +add r0.a, r1, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx300.psh b/plugins/gs/gsdx9/res/ps11_tfx300.psh new file mode 100644 index 0000000000..1b5f67d375 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx300.psh @@ -0,0 +1,14 @@ +; TFX = 3 (HIGHLIGHT) | TCC = 0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = Af + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +mov_x2 r0.a, v0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx310.psh b/plugins/gs/gsdx9/res/ps11_tfx310.psh new file mode 100644 index 0000000000..c776e7b0e4 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx310.psh @@ -0,0 +1,14 @@ +; TFX = 3 (HIGHLIGHT) | TCC = 1 | At = 0.0 - 2.0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = At + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +mov_x2 r0.a, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx311.psh b/plugins/gs/gsdx9/res/ps11_tfx311.psh new file mode 100644 index 0000000000..4a264aa4c5 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx311.psh @@ -0,0 +1,14 @@ +; TFX = 3 (HIGHLIGHT) | TCC = 1 | At = 0.0 - 1.0 +; Rv = Rt * Rf + Af +; Gv = Gt * Gf + Af +; Bv = Bt * Bf + Af +; Av = At + +ps_1_1 + +tex t0 + +mov_x2 r1, t0 +mad r0.rgb, v0, r1, v0.a +mov r0.a, t0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps11_tfx4xx.psh b/plugins/gs/gsdx9/res/ps11_tfx4xx.psh new file mode 100644 index 0000000000..74ccf1b9fc --- /dev/null +++ b/plugins/gs/gsdx9/res/ps11_tfx4xx.psh @@ -0,0 +1,4 @@ +ps_1_1 + +mov r0, v0 +lrp r0.rgb, v1.a, r0, v1 diff --git a/plugins/gs/gsdx9/res/ps14_en00.psh b/plugins/gs/gsdx9/res/ps14_en00.psh new file mode 100644 index 0000000000..706b67ead3 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps14_en00.psh @@ -0,0 +1,13 @@ +; FRAME_n +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_4 + +texld r2, t2 + +mov r0.ga, r2 +mov r0.b, r2.r +mov r0.r, r2.b diff --git a/plugins/gs/gsdx9/res/ps14_en01.psh b/plugins/gs/gsdx9/res/ps14_en01.psh new file mode 100644 index 0000000000..c23756a12f --- /dev/null +++ b/plugins/gs/gsdx9/res/ps14_en01.psh @@ -0,0 +1,16 @@ +; RAO2 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_4 + +texld r1, t1 + +mov r0, c2 +cnd r1, r0.a, c0, r1 + +mov r0.ga, r1 +mov r0.b, r1.r +mov r0.r, r1.b diff --git a/plugins/gs/gsdx9/res/ps14_en10.psh b/plugins/gs/gsdx9/res/ps14_en10.psh new file mode 100644 index 0000000000..6616208e07 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps14_en10.psh @@ -0,0 +1,20 @@ +; RAO1 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_4 + +texld r0, t0 +mov r1, r0 // FIXME + +mov r0, c1 +cnd r0.a, r0.a, c0, r1 +mul r2, r1, r0.a + +mov r0.ga, r2 +mov r0.b, r2.r +mov r0.r, r2.b + + diff --git a/plugins/gs/gsdx9/res/ps14_en11.psh b/plugins/gs/gsdx9/res/ps14_en11.psh new file mode 100644 index 0000000000..299d47f462 --- /dev/null +++ b/plugins/gs/gsdx9/res/ps14_en11.psh @@ -0,0 +1,23 @@ +; RAO1 + RAO2 +; c0.rgb = BGCOLOR +; c0.a = ALP +; c1.a = MMOD +; c2.a = SLBG + +ps_1_4 + +texld r0, t0 +texld r1, t1 + +mov r2, c1 +cnd r0.a, r2.a, c0, r0 + +mov r2, c2 +cnd r1.rgb, r2.a, c0, r1 + +lrp r2, r0.a, r0, r1 + +mov r0.ga, r2 +mov r0.b, r2.r +mov r0.r, r2.b + diff --git a/plugins/gs/gsdx9/resource.h b/plugins/gs/gsdx9/resource.h new file mode 100644 index 0000000000..a84766a233 --- /dev/null +++ b/plugins/gs/gsdx9/resource.h @@ -0,0 +1,55 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSdx9.rc +// +#define IDC_CHECK1 2001 +#define IDR_PS11_TFX000 2001 +#define IDC_CHECK2 2002 +#define IDR_PS11_TFX010 2002 +#define IDC_CHECK3 2003 +#define IDR_PS11_TFX011 2003 +#define IDD_CONFIG 2004 +#define IDR_PS11_TFX1x0 2004 +#define IDC_CHECK5 2004 +#define IDR_PS11_TFX1x1 2005 +#define IDR_PS11_TFX200 2006 +#define IDC_COMBO1 2006 +#define IDR_PS11_TFX210 2007 +#define IDR_PS11_TFX211 2008 +#define IDC_COMBO3 2008 +#define IDR_PS11_TFX300 2009 +#define IDC_COMBO4 2009 +#define IDR_PS11_TFX310 2010 +#define IDC_EDIT1 2010 +#define IDR_PS11_TFX311 2011 +#define IDC_BUTTON1 2011 +#define IDR_PS11_TFX4xx 2012 +#define IDC_BUTTON2 2012 +#define IDR_PS11_EN11 2013 +#define IDC_CUSTOM1 2013 +#define IDR_PS11_EN01 2014 +#define IDC_CHECK4 2014 +#define IDR_PS11_EN10 2015 +#define IDC_COMBO2 2015 +#define IDR_PS11_EN00 2016 +#define IDR_HLSL_TFX 2017 +#define IDR_HLSL_MERGE 2018 +#define IDD_CAPTURE 2018 +#define IDR_PS14_EN11 2019 +#define IDR_PS14_EN01 2020 +#define IDR_PS14_EN10 2021 +#define IDR_PS14_EN00 2022 +#define IDR_HLSL_RB 2023 +#define IDB_BITMAP1 2024 +#define IDB_LOGO1 2024 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 2025 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 2016 +#define _APS_NEXT_SYMED_VALUE 2000 +#endif +#endif diff --git a/plugins/gs/gsdx9/stdafx.cpp b/plugins/gs/gsdx9/stdafx.cpp new file mode 100644 index 0000000000..35050994b9 --- /dev/null +++ b/plugins/gs/gsdx9/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : source file that includes just the standard includes +// GSdx9.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + diff --git a/plugins/gs/gsdx9/stdafx.h b/plugins/gs/gsdx9/stdafx.h new file mode 100644 index 0000000000..478fe9785e --- /dev/null +++ b/plugins/gs/gsdx9/stdafx.h @@ -0,0 +1,95 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently + +#pragma once + +#pragma warning(disable: 4996) + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#include // MFC core and standard components +#include // MFC extensions +/* +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC OLE classes +#include // MFC OLE dialog classes +#include // MFC Automation classes +#endif // _AFX_NO_OLE_SUPPORT + +#ifndef _AFX_NO_DB_SUPPORT +#include // MFC ODBC database classes +#endif // _AFX_NO_DB_SUPPORT + +#include // MFC support for Internet Explorer 4 Common Controls +*/ +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : + +#define BeginEnumSysDev(clsid, pMoniker) \ + {CComPtr pDevEnum4$##clsid; \ + pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum); \ + CComPtr pClassEnum4$##clsid; \ + if(SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ + && pClassEnum4$##clsid) \ + { \ + for(CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = NULL) \ + { \ + +#define EndEnumSysDev }}} + +#pragma warning(disable : 4995 4324) + +#ifndef RESTRICT + #ifdef __INTEL_COMPILER + #define RESTRICT restrict + #elif _MSC_VER >= 1400 + #define RESTRICT __restrict + #else + #define RESTRICT + #endif +#endif \ No newline at end of file diff --git a/plugins/gs/gsdx9/x86-32.asm b/plugins/gs/gsdx9/x86-32.asm new file mode 100644 index 0000000000..4e945c43e0 --- /dev/null +++ b/plugins/gs/gsdx9/x86-32.asm @@ -0,0 +1,1335 @@ + + .686 + .model flat + .mmx + .xmm + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; memsetd +; + +@memsetd@12 proc public + + push edi + + mov edi, ecx + mov eax, edx + mov ecx, [esp+4+4] + cld + rep stosd + + pop edi + + ret 4 + +@memsetd@12 endp + +; +; SaturateColor +; + +@SaturateColor_sse2@4 proc public + + pxor xmm0, xmm0 + movdqa xmm1, [ecx] + packssdw xmm1, xmm0 + packuswb xmm1, xmm0 + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + movdqa [ecx], xmm1 + + ret + +@SaturateColor_sse2@4 endp + +@SaturateColor_asm@4 proc public + + push esi + + mov esi, ecx + + xor eax, eax + mov edx, 000000ffh + + mov ecx, [esi] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi], ecx + + mov ecx, [esi+4] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+4], ecx + + mov ecx, [esi+8] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+8], ecx + + mov ecx, [esi+12] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+12], ecx + + pop esi + + ret + +@SaturateColor_asm@4 endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknb macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +; +; unSwizzleBlock32 +; + +@unSwizzleBlock32_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + lea eax, [ebx*2] + add eax, ebx + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + lea edx, [edx+ebx*4] + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + pop ebx + + ret 4 + +@unSwizzleBlock32_sse2@12 endp + +; +; unSwizzleBlock16 +; + +@unSwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck dq, 0, 4, 2, 6, 1, 3 + punpck wd, 0, 4, 1, 3, 2, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock16_sse2@12 endp + +; +; unSwizzleBlock8 +; + +@unSwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm5, [ecx+16*3] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm5, [ecx+16*7] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8_sse2@12 endp + +; +; unSwizzleBlock4 +; + +@unSwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4_sse2@12 endp + +; +; unSwizzleBlock8HP +; + +@unSwizzleBlock8HP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8HP_sse2@12 endp + +; +; unSwizzleBlock4HLP +; + +@unSwizzleBlock4HLP_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + pand xmm0, xmm7 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HLP_sse2@12 endp + +; +; unSwizzleBlock4HHP +; + +@unSwizzleBlock4HHP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 28 + psrld xmm2, 28 + psrld xmm4, 28 + psrld xmm6, 28 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HHP_sse2@12 endp + +; +; unSwizzleBlock4P +; + +@unSwizzleBlock4P_sse2@12 proc public + + push esi + push edi + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov esi, [esp+4+8] + lea edi, [esi*2] + add edi, esi + + ; col 0 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 1 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 2 + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 3 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + ; lea edx, [edx+esi*4] + + pop edi + pop esi + + ret 4 + +@unSwizzleBlock4P_sse2@12 endp + +; +; swizzling +; + +; +; SwizzleBlock32 +; + +@SwizzleBlock32_sse2@16 proc public + + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [edi+16*0], xmm0 + movdqa [edi+16*1], xmm2 + movdqa [edi+16*2], xmm4 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32_sse2@16 endp + +; +; SwizzleBlock16 +; + +@SwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [edx] + movdqa xmm1, [edx+16] + movdqa xmm2, [edx+ebx] + movdqa xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm1 + movdqa [ecx+16*2], xmm4 + movdqa [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16_sse2@12 endp + +; +; SwizzleBlock8 +; + +@SwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + pshufd xmm1, [edx], 0b1h + pshufd xmm3, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm4 + movdqa [ecx+16*2], xmm1 + movdqa [ecx+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [edx], 0b1h + pshufd xmm2, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [ecx+16*4], xmm0 + movdqa [ecx+16*5], xmm4 + movdqa [ecx+16*6], xmm1 + movdqa [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8_sse2@12 endp + +; +; SwizzleBlock4 +; + +@SwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm1 + movdqa [ecx+16*2], xmm4 + movdqa [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [ecx+16*4], xmm0 + movdqa [ecx+16*5], xmm1 + movdqa [ecx+16*6], xmm4 + movdqa [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4_sse2@12 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u +; + +@SwizzleBlock32u_sse2@16 proc public + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [edi+16*0], xmm0 + movdqa [edi+16*1], xmm2 + movdqa [edi+16*2], xmm4 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32u_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32u_sse2@16 endp + +; +; SwizzleBlock16u +; + +@SwizzleBlock16u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqu xmm0, [edx] + movdqu xmm1, [edx+16] + movdqu xmm2, [edx+ebx] + movdqu xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm1 + movdqa [ecx+16*2], xmm4 + movdqa [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16u_sse2@12 endp + +; +; SwizzleBlock8u +; + +@SwizzleBlock8u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm4 + movdqa [ecx+16*2], xmm1 + movdqa [ecx+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [ecx+16*4], xmm0 + movdqa [ecx+16*5], xmm4 + movdqa [ecx+16*6], xmm1 + movdqa [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8u_sse2@12 endp + +; +; SwizzleBlock4u +; + +@SwizzleBlock4u_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [ecx+16*0], xmm0 + movdqa [ecx+16*1], xmm1 + movdqa [ecx+16*2], xmm4 + movdqa [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [ecx+16*4], xmm0 + movdqa [ecx+16*5], xmm1 + movdqa [ecx+16*6], xmm4 + movdqa [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4u_sse2@12 endp + + end \ No newline at end of file diff --git a/plugins/gs/gsdx9/x86-64.asm b/plugins/gs/gsdx9/x86-64.asm new file mode 100644 index 0000000000..ed4a9ea6fb --- /dev/null +++ b/plugins/gs/gsdx9/x86-64.asm @@ -0,0 +1,1418 @@ + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; memsetd +; + +memsetd proc public + + push rdi + + mov rdi, rcx + mov eax, edx + mov rcx, r8 + cld + rep stosd + + pop rdi + + ret + +memsetd endp + +; +; SaturateColor +; + +SaturateColor_amd64 proc public + + pxor xmm0, xmm0 + movdqa xmm1, [rcx] + packssdw xmm1, xmm0 + packuswb xmm1, xmm0 + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + movdqa [rcx], xmm1 + + ret + +SaturateColor_amd64 endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpck2 macro op, sd0, sd2, sd4, sd6, s1, s3, s5, s7, d1, d3, d5, d7 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + movdqa @CatStr(xmm, %d5), @CatStr(xmm, %sd4) + pshufd @CatStr(xmm, %d7), @CatStr(xmm, %sd6), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + @CatStr(punpckl, op) @CatStr(xmm, %sd4), @CatStr(xmm, %s5) + @CatStr(punpckh, op) @CatStr(xmm, %d5), @CatStr(xmm, %s5) + @CatStr(punpckl, op) @CatStr(xmm, %sd6), @CatStr(xmm, %s7) + @CatStr(punpckh, op) @CatStr(xmm, %d7), @CatStr(xmm, %s7) + + endm + +punpcknbl macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +punpcknbh macro + + movdqa xmm12, xmm8 + pshufd xmm13, xmm9, 0e4h + + psllq xmm9, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm8, xmm15 + pandn xmm14, xmm9 + por xmm8, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm9, xmm12 + + movdqa xmm12, xmm10 + pshufd xmm13, xmm11, 0e4h + + psllq xmm11, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm10, xmm15 + pandn xmm14, xmm11 + por xmm10, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm11, xmm12 + + punpck bw, 8, 10, 9, 11, 12, 14 + + endm + +; +; unSwizzleBlock32 +; + +unSwizzleBlock32_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [rdi], xmm0 + movdqa [rdi+16], xmm2 + movdqa [rdi+r8], xmm4 + movdqa [rdi+r8+16], xmm6 + + add rsi, 64 + lea rdi, [rdi+r8*2] + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock32_amd64 endp + +; +; unSwizzleBlock32_2 (TODO: test me) +; + +unSwizzleBlock32_2_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 2 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + movdqa xmm4, [rsi+16*4] + movdqa xmm5, [rsi+16*5] + movdqa xmm6, [rsi+16*6] + movdqa xmm7, [rsi+16*7] + + punpck2 qdq, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14 + + movdqa [rdi], xmm0 + movdqa [rdi+16], xmm2 + movdqa [rdi+r8], xmm4 + movdqa [rdi+r8+16], xmm6 + lea rdi, [rdi+r8*2] + + movdqa [rdi], xmm8 + movdqa [rdi+16], xmm10 + movdqa [rdi+r8], xmm12 + movdqa [rdi+r8+16], xmm14 + lea rdi, [rdi+r8*2] + + add rsi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock32_2_amd64 endp + +; +; unSwizzleBlock16 +; + +unSwizzleBlock16_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck dq, 0, 4, 2, 6, 1, 3 + punpck wd, 0, 4, 1, 3, 2, 6 + + movdqa [rdi], xmm0 + movdqa [rdi+16], xmm2 + movdqa [rdi+r8], xmm4 + movdqa [rdi+r8+16], xmm6 + + add rsi, 64 + lea rdi, [rdi+r8*2] + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock16_amd64 endp + +; +; unSwizzleBlock8 +; + +unSwizzleBlock8_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 2 + + ; r9 = r8*3 + lea r9, [r8*2] + add r9, r8 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm4, [rsi+16*2] + movdqa xmm5, [rsi+16*3] + + ; col 1, 3 + + movdqa xmm8, [rsi+16*4] + movdqa xmm9, [rsi+16*5] + movdqa xmm12, [rsi+16*6] + movdqa xmm13, [rsi+16*7] + + ; col 0, 2 + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + + ; col 1, 3 + + punpck bw, 8, 12, 9, 13, 10, 14 + punpck wd, 8, 10, 12, 14, 9, 11 + punpck bw, 8, 10, 9, 11, 12, 14 + punpck qdq, 8, 10, 12, 14, 9, 11 + + pshufd xmm8, xmm8, 0b1h + pshufd xmm10, xmm10, 0b1h + + ; col 0, 2 + + movdqa [rdi], xmm0 + movdqa [rdi+r8], xmm2 + movdqa [rdi+r8*2], xmm1 + movdqa [rdi+r9], xmm3 + lea rdi, [rdi+r8*4] + + ; col 1, 3 + + movdqa [rdi], xmm8 + movdqa [rdi+r8], xmm10 + movdqa [rdi+r8*2], xmm9 + movdqa [rdi+r9], xmm11 + lea rdi, [rdi+r8*4] + + add rsi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock8_amd64 endp + +; +; unSwizzleBlock4 +; + +unSwizzleBlock4_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 2 + + ; r9 = r8*3 + lea r9, [r8*2] + add r9, r8 + + mov eax, 0f0f0f0fh + movd xmm7, rax + pshufd xmm7, xmm7, 0 + movdqa xmm15, xmm7 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm4, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + ; col 1, 3 + + movdqa xmm8, [rsi+16*4] + movdqa xmm9, [rsi+16*5] + movdqa xmm12, [rsi+16*6] + movdqa xmm11, [rsi+16*7] + + ; col 0, 2 + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + ; col 1, 3 + + punpck dq, 8, 12, 9, 11, 10, 14 + punpck dq, 8, 10, 12, 14, 9, 11 + punpcknbh + punpck bw, 8, 10, 12, 14, 9, 11 + punpck wd, 8, 10, 9, 11, 12, 14 + + ; col 0, 2 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + ; col 1, 3 + + pshufd xmm8, xmm8, 0d8h + pshufd xmm10, xmm10, 0d8h + pshufd xmm12, xmm12, 0d8h + pshufd xmm14, xmm14, 0d8h + + ; col 0, 2 + + punpck qdq, 0, 2, 4, 6, 1, 3 + + ; col 1, 3 + + punpck qdq, 8, 10, 12, 14, 9, 11 + + ; col 0, 2 + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + ; col 1, 3 + + pshuflw xmm8, xmm8, 0b1h + pshuflw xmm10, xmm10, 0b1h + pshufhw xmm8, xmm8, 0b1h + pshufhw xmm10, xmm10, 0b1h + + ; col 0, 2 + + movdqa [rdi], xmm0 + movdqa [rdi+r8], xmm2 + movdqa [rdi+r8*2], xmm1 + movdqa [rdi+r9], xmm3 + lea rdi, [rdi+r8*4] + + ; col 1, 3 + + movdqa [rdi], xmm8 + movdqa [rdi+r8], xmm10 + movdqa [rdi+r8*2], xmm9 + movdqa [rdi+r9], xmm11 + lea rdi, [rdi+r8*4] + + add rsi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock4_amd64 endp + +; +; unSwizzleBlock8HP +; + +unSwizzleBlock8HP_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [rdi], xmm0 + movhps qword ptr [rdi+r8], xmm0 + + add rsi, 64 + lea rdi, [rdi+r8*2] + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock8HP_amd64 endp + +; +; unSwizzleBlock4HLP +; + +unSwizzleBlock4HLP_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 4 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + pand xmm0, xmm7 + + movlps qword ptr [rdi], xmm0 + movhps qword ptr [rdi+r8], xmm0 + + add rsi, 64 + lea rdi, [rdi+r8*2] + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock4HLP_amd64 endp + +; +; unSwizzleBlock4HHP +; + +unSwizzleBlock4HHP_amd64 proc public + + push rsi + push rdi + + mov rsi, rcx + mov rdi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi+16*0] + movdqa xmm1, [rsi+16*1] + movdqa xmm2, [rsi+16*2] + movdqa xmm3, [rsi+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 28 + psrld xmm2, 28 + psrld xmm4, 28 + psrld xmm6, 28 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [rdi], xmm0 + movhps qword ptr [rdi+r8], xmm0 + + add rsi, 64 + lea rdi, [rdi+r8*2] + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +unSwizzleBlock4HHP_amd64 endp + +; +; unSwizzleBlock4P +; + +unSwizzleBlock4P_amd64 proc public + + mov eax, 0f0f0f0fh + movd xmm8, eax + pshufd xmm8, xmm8, 0 + + ; r9 = r8*3 + lea r9, [r8*2] + add r9, r8 + + ; col 0 + + movdqa xmm0, [rcx+16*0] + movdqa xmm1, [rcx+16*1] + movdqa xmm2, [rcx+16*2] + movdqa xmm3, [rcx+16*3] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm8 + pandn xmm1, xmm0 + pand xmm0, xmm8 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm8 + pandn xmm3, xmm2 + pand xmm2, xmm8 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa xmm5, xmm8 + pandn xmm5, xmm4 + pand xmm4, xmm8 + pshufd xmm5, xmm5, 0b1h + psrlq xmm5, 4 + + movdqa xmm7, xmm8 + pandn xmm7, xmm6 + pand xmm6, xmm8 + pshufd xmm7, xmm7, 0b1h + psrlq xmm7, 4 + + movdqa [rdx], xmm0 + movdqa [rdx+16], xmm2 + movdqa [rdx+r8], xmm4 + movdqa [rdx+r8+16], xmm6 + + movdqa [rdx+r8*2], xmm1 + movdqa [rdx+r8*2+16], xmm3 + movdqa [rdx+r9], xmm5 + movdqa [rdx+r9+16], xmm7 + + lea rdx, [rdx+r8*4] + + ; col 1 + + movdqa xmm0, [rcx+16*4] + movdqa xmm1, [rcx+16*5] + movdqa xmm2, [rcx+16*6] + movdqa xmm3, [rcx+16*7] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm8 + pandn xmm1, xmm0 + pand xmm0, xmm8 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm8 + pandn xmm3, xmm2 + pand xmm2, xmm8 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa xmm5, xmm8 + pandn xmm5, xmm4 + pand xmm4, xmm8 + pshufd xmm4, xmm4, 0b1h + psrlq xmm5, 4 + + movdqa xmm7, xmm8 + pandn xmm7, xmm6 + pand xmm6, xmm8 + pshufd xmm6, xmm6, 0b1h + psrlq xmm7, 4 + + movdqa [rdx], xmm0 + movdqa [rdx+16], xmm2 + movdqa [rdx+r8], xmm4 + movdqa [rdx+r8+16], xmm6 + + movdqa [rdx+r8*2], xmm1 + movdqa [rdx+r8*2+16], xmm3 + movdqa [rdx+r9], xmm5 + movdqa [rdx+r9+16], xmm7 + + lea rdx, [rdx+r8*4] + + ; col 2 + + movdqa xmm0, [rcx+16*8] + movdqa xmm1, [rcx+16*9] + movdqa xmm2, [rcx+16*10] + movdqa xmm3, [rcx+16*11] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm8 + pandn xmm1, xmm0 + pand xmm0, xmm8 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm8 + pandn xmm3, xmm2 + pand xmm2, xmm8 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa xmm5, xmm8 + pandn xmm5, xmm4 + pand xmm4, xmm8 + pshufd xmm5, xmm5, 0b1h + psrlq xmm5, 4 + + movdqa xmm7, xmm8 + pandn xmm7, xmm6 + pand xmm6, xmm8 + pshufd xmm7, xmm7, 0b1h + psrlq xmm7, 4 + + movdqa [rdx], xmm0 + movdqa [rdx+16], xmm2 + movdqa [rdx+r8], xmm4 + movdqa [rdx+r8+16], xmm6 + + movdqa [rdx+r8*2], xmm1 + movdqa [rdx+r8*2+16], xmm3 + movdqa [rdx+r9], xmm5 + movdqa [rdx+r9+16], xmm7 + + lea rdx, [rdx+r8*4] + + ; col 3 + + movdqa xmm0, [rcx+16*12] + movdqa xmm1, [rcx+16*13] + movdqa xmm2, [rcx+16*14] + movdqa xmm3, [rcx+16*15] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm8 + pandn xmm1, xmm0 + pand xmm0, xmm8 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm8 + pandn xmm3, xmm2 + pand xmm2, xmm8 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa xmm5, xmm8 + pandn xmm5, xmm4 + pand xmm4, xmm8 + pshufd xmm4, xmm4, 0b1h + psrlq xmm5, 4 + + movdqa xmm7, xmm8 + pandn xmm7, xmm6 + pand xmm6, xmm8 + pshufd xmm6, xmm6, 0b1h + psrlq xmm7, 4 + + movdqa [rdx], xmm0 + movdqa [rdx+16], xmm2 + movdqa [rdx+r8], xmm4 + movdqa [rdx+r8+16], xmm6 + + movdqa [rdx+r8*2], xmm1 + movdqa [rdx+r8*2+16], xmm3 + movdqa [rdx+r9], xmm5 + movdqa [rdx+r9+16], xmm7 + + ; lea rdx, [rdx+r8*4] + + ret + +unSwizzleBlock4P_amd64 endp + +; +; swizzling +; + +; +; SwizzleBlock32_amd64 +; + +SwizzleBlock32_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jnz SwizzleBlock32_amd64@WM + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_amd64@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_amd64 endp + +; +; SwizzleBlock16_amd64 +; + +SwizzleBlock16_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm1, [rsi+16] + movdqa xmm2, [rsi+r8] + movdqa xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16_amd64 endp + +; +; SwizzleBlock8 +; + +SwizzleBlock8_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8_amd64 endp + +; +; SwizzleBlock4 +; + +SwizzleBlock4_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4_amd64 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u_amd64 +; + +SwizzleBlock32u_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jnz SwizzleBlock32u_amd64@WM + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_amd64@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_amd64 endp + +; +; SwizzleBlock16u_amd64 +; + +SwizzleBlock16u_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm1, [rsi+16] + movdqu xmm2, [rsi+r8] + movdqu xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16u_amd64 endp + +; +; SwizzleBlock8u +; + +SwizzleBlock8u_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8u_amd64 endp + +; +; SwizzleBlock4u +; + +SwizzleBlock4u_amd64 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4u_amd64 endp + + end + \ No newline at end of file diff --git a/plugins/gs/gsdx9/x86.cpp b/plugins/gs/gsdx9/x86.cpp new file mode 100644 index 0000000000..4633b10167 --- /dev/null +++ b/plugins/gs/gsdx9/x86.cpp @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTables.h" +#include "x86.h" + +// unswizzling + +void __fastcall unSwizzleBlock32_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)dst)[i] = ((DWORD*)src)[s[i]]; +} + +void __fastcall unSwizzleBlock16_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable16[0][0]; + + for(int j = 0; j < 8; j++, s += 16, dst += dstpitch) + for(int i = 0; i < 16; i++) + ((WORD*)dst)[i] = ((WORD*)src)[s[i]]; +} + +void __fastcall unSwizzleBlock8_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable8[0][0]; + + for(int j = 0; j < 16; j++, s += 16, dst += dstpitch) + for(int i = 0; i < 16; i++) + dst[i] = src[s[i]]; +} + +void __fastcall unSwizzleBlock4_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = s[i]; + BYTE c = (src[addr>>1] >> ((addr&1) << 2)) & 0x0f; + int shift = (i&1) << 2; + dst[i >> 1] = (dst[i >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +void __fastcall unSwizzleBlock8HP_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + for(int i = 0; i < 8; i++) + dst[i] = (BYTE)(((DWORD*)src)[s[i]]>>24); +} + +void __fastcall unSwizzleBlock4HLP_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + for(int i = 0; i < 8; i++) + dst[i] = (BYTE)(((DWORD*)src)[s[i]]>>24)&0xf; +} + +void __fastcall unSwizzleBlock4HHP_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + for(int i = 0; i < 8; i++) + dst[i] = (BYTE)(((DWORD*)src)[s[i]]>>28); +} + +void __fastcall unSwizzleBlock4P_c(BYTE* src, BYTE* dst, int dstpitch) +{ + DWORD* s = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = s[i]; + dst[i] = (src[addr>>1] >> ((addr&1) << 2)) & 0x0f; + } + } +} + +// swizzling + +void __fastcall SwizzleBlock32_c(BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask) +{ + DWORD* d = &columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~WriteMask) | (((DWORD*)src)[i] & WriteMask); + } +} + +void __fastcall SwizzleBlock16_c(BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; +} + +void __fastcall SwizzleBlock8_c(BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void __fastcall SwizzleBlock4_c(BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = d[i]; + BYTE c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + DWORD shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +// column swizzling (TODO: sse2) + +void __fastcall SwizzleColumn32_c(int y, BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask) +{ + DWORD* d = &columnTable32[((y/2)&3)*2][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 2; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; + } + else + { + for(int j = 0; j < 2; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~WriteMask) | (((DWORD*)src)[i] & WriteMask); + } +} + +void __fastcall SwizzleColumn16_c(int y, BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable16[((y/2)&3)*2][0]; + + for(int j = 0; j < 2; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; +} + +void __fastcall SwizzleColumn8_c(int y, BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable8[((y/4)&3)*4][0]; + + for(int j = 0; j < 4; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void __fastcall SwizzleColumn4_c(int y, BYTE* dst, BYTE* src, int srcpitch) +{ + DWORD* d = &columnTable4[y&(3<<2)][0]; // ((y/4)&3)*4 + + for(int j = 0; j < 4; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = d[i]; + BYTE c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + DWORD shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +// + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 + +static __m128i s_zero = _mm_setzero_si128(); +static __m128i s_bgrm = _mm_set1_epi32(0x00ffffff); +static __m128i s_am = _mm_set1_epi32(0x00008000); +static __m128i s_bm = _mm_set1_epi32(0x00007c00); +static __m128i s_gm = _mm_set1_epi32(0x000003e0); +static __m128i s_rm = _mm_set1_epi32(0x0000001f); + +void __fastcall ExpandBlock24_sse2(DWORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA) +{ + __m128i TA0 = _mm_set1_epi32((DWORD)pTEXA->TA0 << 24); + + if(!pTEXA->AEM) + { + for(int j = 0; j < 8; j++, src += 8, dst += dstpitch>>2) + { + for(int i = 0; i < 8; i += 4) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + c = _mm_and_si128(c, s_bgrm); + c = _mm_or_si128(c, TA0); + _mm_store_si128((__m128i*)&dst[i], c); + } + } + } + else + { + for(int j = 0; j < 8; j++, src += 8, dst += dstpitch>>2) + { + for(int i = 0; i < 8; i += 4) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + c = _mm_and_si128(c, s_bgrm); + __m128i a = _mm_andnot_si128(_mm_cmpeq_epi32(c, s_zero), TA0); + c = _mm_or_si128(c, a); + _mm_store_si128((__m128i*)&dst[i], c); + } + } + } +} + +void __fastcall ExpandBlock16_sse2(WORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA) +{ + __m128i TA0 = _mm_set1_epi32((DWORD)pTEXA->TA0 << 24); + __m128i TA1 = _mm_set1_epi32((DWORD)pTEXA->TA1 << 24); + __m128i a, b, g, r; + + if(!pTEXA->AEM) + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch>>2) + { + for(int i = 0; i < 16; i += 8) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + + __m128i cl = _mm_unpacklo_epi16(c, s_zero); + __m128i ch = _mm_unpackhi_epi16(c, s_zero); + + __m128i alm = _mm_cmplt_epi32(cl, s_am); + __m128i ahm = _mm_cmplt_epi32(ch, s_am); + + // lo + + b = _mm_slli_epi32(_mm_and_si128(cl, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(cl, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(cl, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(alm, TA0), _mm_andnot_si128(alm, TA1)); + + cl = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i], cl); + + // hi + + b = _mm_slli_epi32(_mm_and_si128(ch, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(ch, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(ch, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(ahm, TA0), _mm_andnot_si128(ahm, TA1)); + + ch = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i+4], ch); + } + } + } + else + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch>>2) + { + for(int i = 0; i < 16; i += 8) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + + __m128i cl = _mm_unpacklo_epi16(c, s_zero); + __m128i ch = _mm_unpackhi_epi16(c, s_zero); + + __m128i alm = _mm_cmplt_epi32(cl, s_am); + __m128i ahm = _mm_cmplt_epi32(ch, s_am); + + __m128i trm = _mm_cmpeq_epi16(c, s_zero); + __m128i trlm = _mm_unpacklo_epi16(trm, trm); + __m128i trhm = _mm_unpackhi_epi16(trm, trm); + + // lo + + b = _mm_slli_epi32(_mm_and_si128(cl, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(cl, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(cl, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(alm, TA0), _mm_andnot_si128(alm, TA1)); + a = _mm_andnot_si128(trlm, a); + + cl = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i], cl); + + // hi + + b = _mm_slli_epi32(_mm_and_si128(ch, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(ch, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(ch, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(ahm, TA0), _mm_andnot_si128(ahm, TA1)); + a = _mm_andnot_si128(trhm, a); + + ch = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i+4], ch); + } + } + } +} + +void __fastcall Expand16_sse2(WORD* src, DWORD* dst, int w, GIFRegTEXA* pTEXA) +{ + ASSERT(!(w&7)); + + __m128i TA0 = _mm_set1_epi32((DWORD)pTEXA->TA0 << 24); + __m128i TA1 = _mm_set1_epi32((DWORD)pTEXA->TA1 << 24); + __m128i a, b, g, r; + + if(!pTEXA->AEM) + { + for(int i = 0; i < w; i += 8) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + + __m128i cl = _mm_unpacklo_epi16(c, s_zero); + __m128i ch = _mm_unpackhi_epi16(c, s_zero); + + __m128i alm = _mm_cmplt_epi32(cl, s_am); + __m128i ahm = _mm_cmplt_epi32(ch, s_am); + + // lo + + b = _mm_slli_epi32(_mm_and_si128(cl, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(cl, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(cl, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(alm, TA0), _mm_andnot_si128(alm, TA1)); + + cl = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i], cl); + + // hi + + b = _mm_slli_epi32(_mm_and_si128(ch, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(ch, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(ch, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(ahm, TA0), _mm_andnot_si128(ahm, TA1)); + + ch = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i+4], ch); + } + } + else + { + for(int i = 0; i < w; i += 8) + { + __m128i c = _mm_load_si128((__m128i*)&src[i]); + + __m128i cl = _mm_unpacklo_epi16(c, s_zero); + __m128i ch = _mm_unpackhi_epi16(c, s_zero); + + __m128i alm = _mm_cmplt_epi32(cl, s_am); + __m128i ahm = _mm_cmplt_epi32(ch, s_am); + + __m128i trm = _mm_cmpeq_epi16(c, s_zero); + __m128i trlm = _mm_unpacklo_epi16(trm, trm); + __m128i trhm = _mm_unpackhi_epi16(trm, trm); + + // lo + + b = _mm_slli_epi32(_mm_and_si128(cl, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(cl, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(cl, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(alm, TA0), _mm_andnot_si128(alm, TA1)); + a = _mm_andnot_si128(trlm, a); + + cl = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i], cl); + + // hi + + b = _mm_slli_epi32(_mm_and_si128(ch, s_bm), 9); + g = _mm_slli_epi32(_mm_and_si128(ch, s_gm), 6); + r = _mm_slli_epi32(_mm_and_si128(ch, s_rm), 3); + a = _mm_or_si128(_mm_and_si128(ahm, TA0), _mm_andnot_si128(ahm, TA1)); + a = _mm_andnot_si128(trhm, a); + + ch = _mm_or_si128(_mm_or_si128(a, b), _mm_or_si128(g, r)); + + _mm_store_si128((__m128i*)&dst[i+4], ch); + } + } +} + +#endif + +void __fastcall ExpandBlock24_c(DWORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA) +{ + DWORD TA0 = (DWORD)pTEXA->TA0 << 24; + + if(!pTEXA->AEM) + { + for(int j = 0; j < 8; j++, src += 8, dst += dstpitch>>2) + for(int i = 0; i < 8; i++) + dst[i] = TA0 | (src[i]&0xffffff); + } + else + { + for(int j = 0; j < 8; j++, src += 8, dst += dstpitch>>2) + for(int i = 0; i < 8; i++) + dst[i] = ((src[i]&0xffffff) ? TA0 : 0) | (src[i]&0xffffff); + } +} + +void __fastcall ExpandBlock16_c(WORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA) +{ + DWORD TA0 = (DWORD)pTEXA->TA0 << 24; + DWORD TA1 = (DWORD)pTEXA->TA1 << 24; + + if(!pTEXA->AEM) + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch>>2) + for(int i = 0; i < 16; i++) + dst[i] = ((src[i]&0x8000) ? TA1 : TA0) + | ((src[i]&0x7c00) << 9) | ((src[i]&0x03e0) << 6) | ((src[i]&0x001f) << 3); + } + else + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch>>2) + for(int i = 0; i < 16; i++) + dst[i] = ((src[i]&0x8000) ? TA1 : src[i] ? TA0 : 0) + | ((src[i]&0x7c00) << 9) | ((src[i]&0x03e0) << 6) | ((src[i]&0x001f) << 3); + } +} + +void __fastcall Expand16_c(WORD* src, DWORD* dst, int w, GIFRegTEXA* pTEXA) +{ + DWORD TA0 = (DWORD)pTEXA->TA0 << 24; + DWORD TA1 = (DWORD)pTEXA->TA1 << 24; + + if(!pTEXA->AEM) + { + for(int i = 0; i < w; i++) + dst[i] = ((src[i]&0x8000) ? TA1 : TA0) + | ((src[i]&0x7c00) << 9) | ((src[i]&0x03e0) << 6) | ((src[i]&0x001f) << 3); + } + else + { + for(int i = 0; i < w; i++) + dst[i] = ((src[i]&0x8000) ? TA1 : src[i] ? TA0 : 0) + | ((src[i]&0x7c00) << 9) | ((src[i]&0x03e0) << 6) | ((src[i]&0x001f) << 3); + } +} + +// + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 + +static __m128 s_uvmin = _mm_set1_ps(+1e10); +static __m128 s_uvmax = _mm_set1_ps(-1e10); + +void __fastcall UVMinMax_sse2(int nVertices, vertex_t* pVertices, uvmm_t* uv) +{ + __m128 uvmin = s_uvmin; + __m128 uvmax = s_uvmax; + + __m128* p = (__m128*)pVertices + 1; + + int i = 0; + + nVertices -= 5; + + for(; i < nVertices; i += 6) // 6 regs for loading, 2 regs for min/max + { + uvmin = _mm_min_ps(uvmin, p[(i+0)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+0)*2]); + uvmin = _mm_min_ps(uvmin, p[(i+1)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+1)*2]); + uvmin = _mm_min_ps(uvmin, p[(i+2)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+2)*2]); + uvmin = _mm_min_ps(uvmin, p[(i+3)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+3)*2]); + uvmin = _mm_min_ps(uvmin, p[(i+4)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+4)*2]); + uvmin = _mm_min_ps(uvmin, p[(i+5)*2]); + uvmax = _mm_max_ps(uvmax, p[(i+5)*2]); + } + + nVertices += 5; + + for(; i < nVertices; i++) + { + uvmin = _mm_min_ps(uvmin, p[i*2]); + uvmax = _mm_max_ps(uvmax, p[i*2]); + } + + _mm_storeh_pi((__m64*)uv, uvmin); + _mm_storeh_pi((__m64*)uv + 1, uvmax); +} + +#endif + +void __fastcall UVMinMax_c(int nVertices, vertex_t* pVertices, uvmm_t* uv) +{ + uv->umin = uv->vmin = +1e10; + uv->umax = uv->vmax = -1e10; + + for(; nVertices-- > 0; pVertices++) + { + float u = pVertices->u; + if(uv->umax < u) uv->umax = u; + if(uv->umin > u) uv->umin = u; + float v = pVertices->v; + if(uv->vmax < v) uv->vmax = v; + if(uv->vmin > v) uv->vmin = v; + } +} + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 + +static __m128i s_clut[64]; + +void __fastcall WriteCLUT_T16_I8_CSM1_sse2(WORD* vm, WORD* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int i = 0; i < 32; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + __m128i r4 = _mm_unpacklo_epi16(r0, r1); + __m128i r5 = _mm_unpackhi_epi16(r0, r1); + __m128i r6 = _mm_unpacklo_epi16(r2, r3); + __m128i r7 = _mm_unpackhi_epi16(r2, r3); + + r0 = _mm_unpacklo_epi32(r4, r6); + r1 = _mm_unpackhi_epi32(r4, r6); + r2 = _mm_unpacklo_epi32(r5, r7); + r3 = _mm_unpackhi_epi32(r5, r7); + + r4 = _mm_unpacklo_epi16(r0, r1); + r5 = _mm_unpackhi_epi16(r0, r1); + r6 = _mm_unpacklo_epi16(r2, r3); + r7 = _mm_unpackhi_epi16(r2, r3); + + _mm_store_si128(&dst[i+0], r4); + _mm_store_si128(&dst[i+1], r6); + _mm_store_si128(&dst[i+2], r5); + _mm_store_si128(&dst[i+3], r7); + } +} + +void __fastcall WriteCLUT_T32_I8_CSM1_sse2(DWORD* vm, WORD* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = s_clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } + + for(int i = 0; i < 32; i++) + { + __m128i r0 = s_clut[i*2]; + __m128i r1 = s_clut[i*2+1]; + __m128i r2 = _mm_unpacklo_epi16(r0, r1); + __m128i r3 = _mm_unpackhi_epi16(r0, r1); + r0 = _mm_unpacklo_epi16(r2, r3); + r1 = _mm_unpackhi_epi16(r2, r3); + r2 = _mm_unpacklo_epi16(r0, r1); + r3 = _mm_unpackhi_epi16(r0, r1); + _mm_store_si128(&((__m128i*)clut)[i], r2); + _mm_store_si128(&((__m128i*)clut)[i+32], r3); + } +} + +void __fastcall WriteCLUT_T16_I4_CSM1_sse2(WORD* vm, WORD* clut) +{ + // TODO (probably not worth, _c is going to be just as fast) + WriteCLUT_T16_I4_CSM1_c(vm, clut); +} + +void __fastcall WriteCLUT_T32_I4_CSM1_sse2(DWORD* vm, WORD* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = s_clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); + + for(int i = 0; i < 2; i++) + { + __m128i r0 = s_clut[i*2]; + __m128i r1 = s_clut[i*2+1]; + __m128i r2 = _mm_unpacklo_epi16(r0, r1); + __m128i r3 = _mm_unpackhi_epi16(r0, r1); + r0 = _mm_unpacklo_epi16(r2, r3); + r1 = _mm_unpackhi_epi16(r2, r3); + r2 = _mm_unpacklo_epi16(r0, r1); + r3 = _mm_unpackhi_epi16(r0, r1); + _mm_store_si128(&((__m128i*)clut)[i], r2); + _mm_store_si128(&((__m128i*)clut)[i+32], r3); + } +} + +#endif + +void __fastcall WriteCLUT_T16_I8_CSM1_c(WORD* vm, WORD* clut) +{ + const static DWORD map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + for(int j = 0; j < 8; j++, vm += 32, clut += 32) + { + for(int i = 0; i < 32; i++) + { + clut[i] = vm[map[i]]; + } + } +} + +void __fastcall WriteCLUT_T32_I8_CSM1_c(DWORD* vm, WORD* clut) +{ + const static DWORD map[] = + { + 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15, + 64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79, + 16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31, + 80, 81, 84, 85, 88, 89, 92, 93, 82, 83, 86, 87, 90, 91, 94, 95, + 32, 33, 36, 37, 40, 41, 44, 45, 34, 35, 38, 39, 42, 43, 46, 47, + 96, 97, 100, 101, 104, 105, 108, 109, 98, 99, 102, 103, 106, 107, 110, 111, + 48, 49, 52, 53, 56, 57, 60, 61, 50, 51, 54, 55, 58, 59, 62, 63, + 112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127 + }; + + for(int j = 0; j < 2; j++, vm += 128, clut += 128) + { + for(int i = 0; i < 128; i++) + { + DWORD dw = vm[map[i]]; + clut[i] = (WORD)(dw & 0xffff); + clut[i+256] = (WORD)(dw >> 16); + } + } +} + +void __fastcall WriteCLUT_T16_I4_CSM1_c(WORD* vm, WORD* clut) +{ + const static DWORD map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30 + }; + + for(int i = 0; i < 16; i++) + { + clut[i] = vm[map[i]]; + } +} + +void __fastcall WriteCLUT_T32_I4_CSM1_c(DWORD* vm, WORD* clut) +{ + const static DWORD map[] = + { + 0, 1, 4, 5, 8, 9, 12, 13, + 2, 3, 6, 7, 10, 11, 14, 15 + }; + + for(int i = 0; i < 16; i++) + { + DWORD dw = vm[map[i]]; + clut[i] = (WORD)(dw & 0xffff); + clut[i+256] = (WORD)(dw >> 16); + } +} + +// + +#if defined(_M_AMD64) || _M_IX86_FP >= 2 + +extern "C" void __fastcall ReadCLUT32_T32_I8_sse2(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 256; i += 16) + { + ReadCLUT32_T32_I4_sse2(&src[i], &dst[i]); // going to be inlined nicely + } +} + +extern "C" void __fastcall ReadCLUT32_T32_I4_sse2(WORD* src, DWORD* dst) +{ + __m128i r0 = ((__m128i*)src)[0]; + __m128i r1 = ((__m128i*)src)[1]; + __m128i r2 = ((__m128i*)src)[0+32]; + __m128i r3 = ((__m128i*)src)[1+32]; + _mm_store_si128(&((__m128i*)dst)[0], _mm_unpacklo_epi16(r0, r2)); + _mm_store_si128(&((__m128i*)dst)[1], _mm_unpackhi_epi16(r0, r2)); + _mm_store_si128(&((__m128i*)dst)[2], _mm_unpacklo_epi16(r1, r3)); + _mm_store_si128(&((__m128i*)dst)[3], _mm_unpackhi_epi16(r1, r3)); +} + +extern "C" void __fastcall ReadCLUT32_T16_I8_sse2(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 256; i += 16) + { + ReadCLUT32_T16_I4_sse2(&src[i], &dst[i]); + } +} + +extern "C" void __fastcall ReadCLUT32_T16_I4_sse2(WORD* src, DWORD* dst) +{ + __m128i r0 = ((__m128i*)src)[0]; + __m128i r1 = ((__m128i*)src)[1]; + _mm_store_si128(&((__m128i*)dst)[0], _mm_unpacklo_epi16(r0, s_zero)); + _mm_store_si128(&((__m128i*)dst)[1], _mm_unpackhi_epi16(r0, s_zero)); + _mm_store_si128(&((__m128i*)dst)[2], _mm_unpacklo_epi16(r1, s_zero)); + _mm_store_si128(&((__m128i*)dst)[3], _mm_unpackhi_epi16(r1, s_zero)); +} + +#endif + +void __fastcall ReadCLUT32_T32_I8_c(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 256; i++) + { + dst[i] = ((DWORD)src[i+256] << 16) | src[i]; + } +} + +void __fastcall ReadCLUT32_T32_I4_c(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 16; i++) + { + dst[i] = ((DWORD)src[i+256] << 16) | src[i]; + } +} + +void __fastcall ReadCLUT32_T16_I8_c(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 256; i++) + { + dst[i] = (DWORD)src[i]; + } +} + +void __fastcall ReadCLUT32_T16_I4_c(WORD* src, DWORD* dst) +{ + for(int i = 0; i < 16; i++) + { + dst[i] = (DWORD)src[i]; + } +} + +// \ No newline at end of file diff --git a/plugins/gs/gsdx9/x86.h b/plugins/gs/gsdx9/x86.h new file mode 100644 index 0000000000..c4622dacd8 --- /dev/null +++ b/plugins/gs/gsdx9/x86.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2003-2005 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" + +extern "C" void __fastcall memsetd(void* dst, unsigned int c, size_t len); + +extern "C" void unSwizzleBlock32_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock16_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock8_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock4_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock8HP_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock4HLP_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock4HHP_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void unSwizzleBlock4P_amd64(BYTE* src, BYTE* dst, __int64 dstpitch); +extern "C" void SwizzleBlock32_amd64(BYTE* dst, BYTE* src, __int64 srcpitch, DWORD WriteMask = 0xffffffff); +extern "C" void SwizzleBlock16_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void SwizzleBlock8_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void SwizzleBlock4_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void SwizzleBlock32u_amd64(BYTE* dst, BYTE* src, __int64 srcpitch, DWORD WriteMask = 0xffffffff); +extern "C" void SwizzleBlock16u_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void SwizzleBlock8u_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void SwizzleBlock4u_amd64(BYTE* dst, BYTE* src, __int64 srcpitch); +extern "C" void __fastcall unSwizzleBlock32_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock16_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock8_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock4_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock8HP_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock4HLP_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock4HHP_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall unSwizzleBlock4P_sse2(BYTE* src, BYTE* dst, int dstpitch); +extern "C" void __fastcall SwizzleBlock32_sse2(BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock32u_sse2(BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16u_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8u_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4u_sse2(BYTE* dst, BYTE* src, int srcpitch); +extern void __fastcall unSwizzleBlock32_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock16_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock8_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock4_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock8HP_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock4HLP_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock4HHP_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall unSwizzleBlock4P_c(BYTE* src, BYTE* dst, int dstpitch); +extern void __fastcall SwizzleBlock32_c(BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask = 0xffffffff); +extern void __fastcall SwizzleBlock16_c(BYTE* dst, BYTE* src, int srcpitch); +extern void __fastcall SwizzleBlock8_c(BYTE* dst, BYTE* src, int srcpitch); +extern void __fastcall SwizzleBlock4_c(BYTE* dst, BYTE* src, int srcpitch); + +extern void __fastcall SwizzleColumn32_c(int y, BYTE* dst, BYTE* src, int srcpitch, DWORD WriteMask = 0xffffffff); +extern void __fastcall SwizzleColumn16_c(int y, BYTE* dst, BYTE* src, int srcpitch); +extern void __fastcall SwizzleColumn8_c(int y, BYTE* dst, BYTE* src, int srcpitch); +extern void __fastcall SwizzleColumn4_c(int y, BYTE* dst, BYTE* src, int srcpitch); + +extern void __fastcall ExpandBlock24_sse2(DWORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA); +extern void __fastcall ExpandBlock16_sse2(WORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA); +extern void __fastcall Expand16_sse2(WORD* src, DWORD* dst, int w, GIFRegTEXA* pTEXA); +extern void __fastcall ExpandBlock24_c(DWORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA); +extern void __fastcall ExpandBlock16_c(WORD* src, DWORD* dst, int dstpitch, GIFRegTEXA* pTEXA); +extern void __fastcall Expand16_c(WORD* src, DWORD* dst, int w, GIFRegTEXA* pTEXA); + +extern "C" void SaturateColor_amd64(int* c); +extern "C" void __fastcall SaturateColor_sse2(int* c); +extern "C" void __fastcall SaturateColor_asm(int* c); + +struct uvmm_t {float umin, vmin, umax, vmax;}; +struct vertex_t {float xyzw[4]; DWORD color[2]; float u, v;}; +extern "C" void __fastcall UVMinMax_sse2(int nVertices, vertex_t* pVertices, uvmm_t* uv); +extern "C" void __fastcall UVMinMax_c(int nVertices, vertex_t* pVertices, uvmm_t* uv); + +extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(WORD* vm, WORD* clut); +extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(DWORD* vm, WORD* clut); +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(WORD* vm, WORD* clut); +extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(DWORD* vm, WORD* clut); +extern void __fastcall WriteCLUT_T16_I8_CSM1_c(WORD* vm, WORD* clut); +extern void __fastcall WriteCLUT_T32_I8_CSM1_c(DWORD* vm, WORD* clut); +extern void __fastcall WriteCLUT_T16_I4_CSM1_c(WORD* vm, WORD* clut); +extern void __fastcall WriteCLUT_T32_I4_CSM1_c(DWORD* vm, WORD* clut); + +extern "C" void __fastcall ReadCLUT32_T32_I8_sse2(WORD* src, DWORD* dst); +extern "C" void __fastcall ReadCLUT32_T32_I4_sse2(WORD* src, DWORD* dst); +extern "C" void __fastcall ReadCLUT32_T16_I8_sse2(WORD* src, DWORD* dst); +extern "C" void __fastcall ReadCLUT32_T16_I4_sse2(WORD* src, DWORD* dst); +extern void __fastcall ReadCLUT32_T32_I8_c(WORD* src, DWORD* dst); +extern void __fastcall ReadCLUT32_T32_I4_c(WORD* src, DWORD* dst); +extern void __fastcall ReadCLUT32_T16_I8_c(WORD* src, DWORD* dst); +extern void __fastcall ReadCLUT32_T16_I4_c(WORD* src, DWORD* dst); + +#ifdef _M_AMD64 + +#define SaturateColor SaturateColor_amd64 + +#define unSwizzleBlock32 unSwizzleBlock32_amd64 +#define unSwizzleBlock16 unSwizzleBlock16_amd64 +#define unSwizzleBlock8 unSwizzleBlock8_amd64 +#define unSwizzleBlock4 unSwizzleBlock4_amd64 +#define unSwizzleBlock8HP unSwizzleBlock8HP_amd64 +#define unSwizzleBlock4HLP unSwizzleBlock4HLP_amd64 +#define unSwizzleBlock4HHP unSwizzleBlock4HHP_amd64 +#define unSwizzleBlock4P unSwizzleBlock4P_amd64 +#define SwizzleBlock32 SwizzleBlock32_amd64 +#define SwizzleBlock16 SwizzleBlock16_amd64 +#define SwizzleBlock8 SwizzleBlock8_amd64 +#define SwizzleBlock4 SwizzleBlock4_amd64 +#define SwizzleBlock32u SwizzleBlock32u_amd64 +#define SwizzleBlock16u SwizzleBlock16u_amd64 +#define SwizzleBlock8u SwizzleBlock8u_amd64 +#define SwizzleBlock4u SwizzleBlock4u_amd64 + +#define SwizzleColumn32 SwizzleColumn32_c +#define SwizzleColumn16 SwizzleColumn16_c +#define SwizzleColumn8 SwizzleColumn8_c +#define SwizzleColumn4 SwizzleColumn4_c + +#define ExpandBlock24 ExpandBlock24_sse2 +#define ExpandBlock16 ExpandBlock16_sse2 +#define Expand16 Expand16_sse2 + +#define UVMinMax UVMinMax_sse2 + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#define ReadCLUT32_T32_I8 ReadCLUT32_T32_I8_sse2 +#define ReadCLUT32_T32_I4 ReadCLUT32_T32_I4_sse2 +#define ReadCLUT32_T16_I8 ReadCLUT32_T16_I8_sse2 +#define ReadCLUT32_T16_I4 ReadCLUT32_T16_I4_sse2 + +#elif _M_IX86_FP >= 2 + +#define SaturateColor SaturateColor_sse2 + +#define unSwizzleBlock32 unSwizzleBlock32_sse2 +#define unSwizzleBlock16 unSwizzleBlock16_sse2 +#define unSwizzleBlock8 unSwizzleBlock8_sse2 +#define unSwizzleBlock4 unSwizzleBlock4_sse2 +#define unSwizzleBlock8HP unSwizzleBlock8HP_sse2 +#define unSwizzleBlock4HLP unSwizzleBlock4HLP_sse2 +#define unSwizzleBlock4HHP unSwizzleBlock4HHP_sse2 +#define unSwizzleBlock4P unSwizzleBlock4P_sse2 +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define SwizzleColumn32 SwizzleColumn32_c +#define SwizzleColumn16 SwizzleColumn16_c +#define SwizzleColumn8 SwizzleColumn8_c +#define SwizzleColumn4 SwizzleColumn4_c + +#define ExpandBlock24 ExpandBlock24_sse2 +#define ExpandBlock16 ExpandBlock16_sse2 +#define Expand16 Expand16_sse2 + +#define UVMinMax UVMinMax_sse2 + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#define ReadCLUT32_T32_I8 ReadCLUT32_T32_I8_sse2 +#define ReadCLUT32_T32_I4 ReadCLUT32_T32_I4_sse2 +#define ReadCLUT32_T16_I8 ReadCLUT32_T16_I8_sse2 +#define ReadCLUT32_T16_I4 ReadCLUT32_T16_I4_sse2 + +#else + +#define SaturateColor SaturateColor_asm + +#define unSwizzleBlock32 unSwizzleBlock32_c +#define unSwizzleBlock16 unSwizzleBlock16_c +#define unSwizzleBlock8 unSwizzleBlock8_c +#define unSwizzleBlock4 unSwizzleBlock4_c +#define unSwizzleBlock8HP unSwizzleBlock8HP_c +#define unSwizzleBlock4HLP unSwizzleBlock4HLP_c +#define unSwizzleBlock4HHP unSwizzleBlock4HHP_c +#define unSwizzleBlock4P unSwizzleBlock4P_c +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define SwizzleColumn32 SwizzleColumn32_c +#define SwizzleColumn16 SwizzleColumn16_c +#define SwizzleColumn8 SwizzleColumn8_c +#define SwizzleColumn4 SwizzleColumn4_c + +#define ExpandBlock24 ExpandBlock24_c +#define ExpandBlock16 ExpandBlock16_c +#define Expand16 Expand16_c + +#define UVMinMax UVMinMax_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#define ReadCLUT32_T32_I8 ReadCLUT32_T32_I8_c +#define ReadCLUT32_T32_I4 ReadCLUT32_T32_I4_c +#define ReadCLUT32_T16_I8 ReadCLUT32_T16_I8_c +#define ReadCLUT32_T16_I4 ReadCLUT32_T16_I4_c + +#endif diff --git a/plugins/gs/zerogs/build.sh b/plugins/gs/zerogs/build.sh new file mode 100644 index 0000000000..6f73b174d1 --- /dev/null +++ b/plugins/gs/zerogs/build.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +curdir=`pwd` + +echo ---------------------- +echo Building ZeroGS OpenGL +echo ---------------------- + +cd ${curdir}/opengl + +if [ $# -gt 0 ] && [ $1 = "all" ] +then + +aclocal +automake +autoconf +chmod +x configure +./configure --enable-sse2 --prefix=${PCSX2PLUGINS} +make clean +make install + +else +make $@ +fi + +if [ $? -ne 0 ] +then +exit 1 +fi + +#cp libZeroGSogl*.so* ${PCSX2PLUGINS}/ +cp Win32/ps2hw.dat ${PCSX2PLUGINS}/ \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/GS.h b/plugins/gs/zerogs/dx/GS.h new file mode 100644 index 0000000000..c3b85a0398 --- /dev/null +++ b/plugins/gs/zerogs/dx/GS.h @@ -0,0 +1,745 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GS_H__ +#define __GS_H__ + +#include +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" +} + +#ifdef __WIN32__ + +#include +#include + +extern HWND GShwnd; + +#else + +#include +#include +#include +#include + +#define __inline inline + +typedef int BOOL; + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#endif + +#if defined(_MSC_VER) +#define FASTCALL(fn) __fastcall fn +#else + +#ifdef __x86_64 +#define FASTCALL(fn) fn +#else +#define FASTCALL(fn) __attribute__((fastcall)) fn +#endif +#endif + +struct Vector_16F +{ + u16 x, y, z, w; +}; + + +///////////////////// +// define when releasing +#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC + +#if !defined(_RELEASE) +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + UINT32 NLOOP:15; + UINT32 EOP:1; + UINT32 _PAD1:16; + UINT32 _PAD2:14; + UINT32 PRE:1; + UINT32 PRIM:11; + UINT32 FLG:2; // enum GIF_FLG + UINT32 NREG:4; + UINT64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_BMPSNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x70 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 +#define GSOPTION_WIN960W 0x40 +#define GSOPTION_WIN1280W 0x50 +#define GSOPTION_WIN1920W 0x60 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_WIDESCREEN 0x200 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + u8 mrtdepth; // write color in render target + u8 interlace; + u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + u8 bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +#define VERTEXGPU \ + union \ + { \ + struct \ + { \ + u16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; \ + u32 z; \ + }; \ + }; \ + \ + float s, t, q; \ + +typedef struct { + s16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; + u32 z; + float s, t, q; +} VertexGPU; + +typedef struct { + VERTEXGPU + u16 u, v; +} Vertex; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // word address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(char *fmt, ...); +void ERROR_LOG(char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +__forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +__forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +#endif diff --git a/plugins/gs/zerogs/dx/GSmain.cpp b/plugins/gs/zerogs/dx/GSmain.cpp new file mode 100644 index 0000000000..d14184151a --- /dev/null +++ b/plugins/gs/zerogs/dx/GSmain.cpp @@ -0,0 +1,1078 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) || defined(_WIN32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "Win32.h" + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "zerogsshaders/zerogsshaders.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +int g_GameSettings = 0; + +static LARGE_INTEGER luPerfFreq; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 97 +const unsigned char version = PS2E_GS_VERSION; +unsigned char revision = 0; // revision and build gives plugin version +unsigned char build = VER; +unsigned char minor = 1; + +#ifdef _DEBUG +char *libraryName = "ZeroGS (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) + +#ifdef ZEROGS_SSE2 +char *libraryName = "ZeroGS KOSMOS"; +#else +char *libraryName = "ZeroGS KOSMOS (no SSE2)"; +#endif + +#else +char *libraryName = "ZeroGS (Dev) "; +#endif + +static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x", "AA 16x" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +const char* pbilinear[] = { "off", "normal", "forced" }; + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build | (minor << 24); +} + +#ifdef _WIN32 + +HWND GShwnd; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} + +#endif + +#ifdef GS_LOG +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} +#endif + +void ERROR_LOG(char *fmt, ...) { + va_list list; + + printf("ZeroGS: "); + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = !(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + //g_GameSettings |= GAME_PARTIALDEPTH; + +// g_GameSettings |= GAME_DOPARALLELCTX|GAME_XENOSPECHACK; +// VALIDATE_THRESH = 64; +// TEXDESTROY_THRESH = 32; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + if( pd3dDevice != NULL ) { + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, 0.9f/256.0f, 0,1/255.0f), 1); // g_fExactColor + } + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } + + printf("ZeroGS: Set game options: 0x%8.8x\n", g_GameSettings); +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(int mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + + GSreset(); + +#ifdef GS_LOG + GS_LOG("GSinit ok\n"); +#endif + + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //printf("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + +#ifdef GS_LOG + GS_LOG("GSopen\n"); +#endif + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + g_GameSettings = 0; + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(int*)pDsp = (int)GShwnd; + + printf("creating zerogs\n"); + //if (conf.record) recOpen(); + if( FAILED(ZeroGS::Create(conf.width, conf.height)) ) + return -1; + + printf("init zerogs\n"); + + if( FAILED(ZeroGS::InitDeviceObjects()) ) + return -1; + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("forced bilinear filtering - on", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("normal bilinear filtering - on", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + if( conf.options & GSOPTION_WIDESCREEN ) { + ZeroGS::AddMessage("16:9 widescreen - on", 1000); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + +#ifdef _WIN32 + QueryPerformanceFrequency(&luPerfFreq); +#else + luPerfFreq.QuadPart = 1; +#endif + +#ifdef GS_LOG + GS_LOG("GSopen ok\n"); +#endif + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + + //if (conf.record) recClose(); + +#ifdef _WIN32 + DestroyWindow(GShwnd); +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_BMPSNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; +static BOOL g_bHidden = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ +#ifdef GS_LOG + GS_LOG("\nGSvsync\n\n"); +#endif + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + + char strtitle[512]; + + g_nRealFrame++; + + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + if( g_nPixelShaderVer == SHADER_20 ) { + conf.bilinear = 0; + sprintf(strtitle, "ps 2.0 doesn't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F6 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.aa--; // -1 + if( conf.aa < 0 ) conf.aa = 4; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F7 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + SETRS(D3DRS_FILLMODE, (conf.options&GSOPTION_WIREFRAME)?D3DFILL_WIREFRAME:D3DFILL_SOLID); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); +// conf.options ^= GSOPTION_CAPTUREAVI; +// if( conf.options & GSOPTION_CAPTUREAVI ) ZeroGS::StartCapture(); +// else ZeroGS::StopCapture(); +// +// sprintf(strtitle, "capture avi (zerogs_dump.avi) - %s", (conf.options&GSOPTION_CAPTUREAVI) ? "on" : "off"); +// ZeroGS::AddMessage(strtitle); +// SaveConfig(); + } + } + else if( msg.wParam == VK_F9 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.options ^= GSOPTION_WIDESCREEN; + sprintf(strtitle, "16:9 widescreen - %s", (conf.options&GSOPTION_WIDESCREEN)?"on":"off"); + } + else { + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + } + ZeroGS::AddMessage(strtitle); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 + + ZeroGS::RenderCRTC(!interlace); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "ps 2.0", "ps 2.0a", "ps 2.0b", "ps 3.0" }; + + _snprintf(strtitle, 512, "%s 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", libraryName, build, minor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + _snprintf(strtitle, 512, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +#ifdef GS_LOG +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); +#endif + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +//static pathInfo* s_pLastPath = &gs.path3; +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ +// int mode = s_pLastPath->mode > 0 ? s_pLastPath->mode-1 : 0; +// *(u32*)ptag = s_pLastPath->tag.nloop|(s_pLastPath->tag.eop<<15); +// *((u32*)ptag+1) = (mode<<26)|(s_pLastPath->regn<<28); + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _DEBUG + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + + //s_pLastPath = path; + //BOOL bAfter0Tag = 0; + +// if( conf.log & 0x20 ) { +// __Log("%d: %x:%x\n", (path==&gs.path3)?3:(path==&gs.path2?2:1), pMem, size); +// for(int i = 0; i < size; i++) { +// __Log("%x %x %x %x\n", pMem[4*i+0], pMem[4*i+1], pMem[4*i+2], pMem[4*i+3]); +// } +// } + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if(path->tag.nloop == 0) { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if( (g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop ) + nPath3Hack = 1; + + if( path == &gs.path1 ) { + + // if too much data, just ignore + if( path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if( path->mode == 1 ) { + + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) { + if( ((path->regs >> i)&0xf) == 11 ) { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) { + //bAfter0Tag = 1; + if( path == &gs.path1 ) { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) { + //printf("contuing from eop\n"); + continue; + } + + break; + } +// else { +// if( bAfter0Tag ) { +// // hack!! if all 0s, then break +// if( pMem[-3] == 0 && pMem[-2] == 0 ) { +// path->tag.nloop = 0; +// return; +// } +// } +// } + } + + switch(path->mode) { + case 1: // PACKED + { +// if( path->tag.nreg == 9 && gs.regs == 0x412412412L && gs.primC == 0) { +// // draw 3 points +// } + + //__Log("%8.8x%8.8x %d\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //__Log("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + case 4: + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) { + if( gs.imageTransfer ) ZeroGS::TransferLocalHost(pMem, process); + else ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: // GIF_IMAGE + GS_LOG(_T("*** WARNING **** Unexpected GIFTag flag\n")); + assert(0); +// ZeroGS::TransferLocalHost(pMem, size); +// pMem+= size*4; path->tag.nloop-= size; +// size = 0; path->mode = 0; + path->tag.nloop = 0; + break; + + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ +#ifdef GS_LOG + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); +#endif + +// if(!g_GSMultiThreaded) +// CSR->FINISH = 0; + //DVProfileFunc _pf("Transf2"); + + //assert( ((u32)pMem & 0xf) == 0 ); + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ +#ifdef GS_LOG + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); +#endif + +// if(!g_GSMultiThreaded) +// CSR->FINISH = 0; + //DVProfileFunc _pf("Transf3"); + + //assert( ((u32)pMem & 0xf) == 0 ); + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int count = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + +#ifdef GS_LOG + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); +#endif + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count: %d\n", count); + count++; + +// for(int i = addr; i < 0x4000; i += 16 ) { +// u32* mem = (u32*)((u8*)pMem+i); +// PRIM_LOG("%x: %x %x %x %x\n", i, mem[0], mem[1], mem[2], mem[3]); +// } +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + //_GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+0x4000-addr), addr/16); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ +#ifdef GS_LOG + //GS_LOG("GSreadFIFO\n"); +#endif + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ +#ifdef GS_LOG + //GS_LOG("GSreadFIFO2\n"); +#endif + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + if( !ZeroGS::StartCapture() ) + return 0; + conf.options |= GSOPTION_CAPTUREAVI; + printf("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + printf("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) { + if (mode == FREEZE_LOAD) { + if( !ZeroGS::Load(data->data) ) + printf("GS: Bad load format!"); + g_nRealFrame += 100; + + } else if (mode == FREEZE_SAVE) { + ZeroGS::Save(data->data); + } + if (mode == FREEZE_SIZE) { + data->size = ZeroGS::Save(NULL); + } + + return 0; +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; +} diff --git a/plugins/gs/zerogs/dx/Mem.cpp b/plugins/gs/zerogs/dx/Mem.cpp new file mode 100644 index 0000000000..19902a09ee --- /dev/null +++ b/plugins/gs/zerogs/dx/Mem.cpp @@ -0,0 +1,902 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static __declspec(align(16)) u32 tempblock[64]; + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = ZeroGS::g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { \ + /* don't transfer */ \ + /*printf("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + int pitch = gs.imageEndX-gs.trxpos.dx; \ + int area = pitch*blockheight; \ + int fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*printf("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = D3DXVECTOR2(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh); \ + b.vTexBlock = D3DXVECTOR4((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(float); \ + psrcw = (WORD*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(WORD); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( format == D3DFMT_R32F ) { \ + psrcf[i*pBlockTexture->Pitch/sizeof(float)+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*pBlockTexture->Pitch/sizeof(WORD)+j] = u; \ + } \ + } \ + } \ + \ + if( pBilinearTexture != NULL ) { \ + assert( format == D3DFMT_R32F ); \ + psrcv = (DXVEC4*)pBilinearTexture->pBits + ox + oy * pBilinearTexture->Pitch/sizeof(DXVEC4); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + DXVEC4* pv = &psrcv[i*pBilinearTexture->Pitch/sizeof(DXVEC4)+j]; \ + pv->x = psrcf[i*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->y = psrcf[i*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->w = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format) +{ + assert( pBlockTexture != NULL ); + assert( format == D3DFMT_R32F || format == D3DFMT_G16R16 ); + + int i, j; + BLOCK b; + float* psrcf = NULL; + WORD* psrcw = NULL; + DXVEC4* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/gs/zerogs/dx/Mem.h b/plugins/gs/zerogs/dx/Mem.h new file mode 100644 index 0000000000..f4d36571fb --- /dev/null +++ b/plugins/gs/zerogs/dx/Mem.h @@ -0,0 +1,486 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __MEM_H__ +#define __MEM_H__ + +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + D3DXVECTOR4 vTexBlock; + D3DXVECTOR2 vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +__forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +__forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +__forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +__forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +__forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +__forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +__forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +__forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +__forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +__forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +__forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +__forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +__forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +__forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +__forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +__forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +__forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +__forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +__forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +__forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +__forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +__forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +__forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +__forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +__forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +__forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +__forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +__forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +__forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +__forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +__forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +__forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +__forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +__forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +__forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +__forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +__forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +__forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +__forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +__forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +__forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +__forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +__forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +__forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/gs/zerogs/dx/PS2Edefs.h b/plugins/gs/zerogs/dx/PS2Edefs.h new file mode 100644 index 0000000000..b2f76c96de --- /dev/null +++ b/plugins/gs/zerogs/dx/PS2Edefs.h @@ -0,0 +1,848 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/gs/zerogs/dx/PS2Etypes.h b/plugins/gs/zerogs/dx/PS2Etypes.h new file mode 100644 index 0000000000..1ad73e273d --- /dev/null +++ b/plugins/gs/zerogs/dx/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/gs/zerogs/dx/README.txt b/plugins/gs/zerogs/dx/README.txt new file mode 100644 index 0000000000..e54d8a1b31 --- /dev/null +++ b/plugins/gs/zerogs/dx/README.txt @@ -0,0 +1,13 @@ +ZeroGS DirectX +-------------- +author: zerofrog (@gmail.com) + +ZeroGS heavily uses GPU shaders. All the shaders are written in Microsoft's HLSL language and can be found in ps2hw.fx, ps2hw_ctx0.fx and ps2hw_ctx1.fx. + +'Dev' versions of ZeroGS directly read ps2hw.fx +'Release' versions of ZeroGS read a precompiled version of ps2hw.fx from ps2hw.dat. In order to build ps2hw.dat, compile ZeroGSShaders and execute: + +./ZeroGSShaders ps2hw.fx ps2hw.dat + +For Windows users, once ZeroGSShaders is built, run buildshaders.bat directly. It will update all necessary resource files. +Note that ZeroGSShaders has only been tested in Windows so far, but the Windows ps2hw.dat can be used in linux builds. diff --git a/plugins/gs/zerogs/dx/Regs.cpp b/plugins/gs/zerogs/dx/Regs.cpp new file mode 100644 index 0000000000..30928d1fed --- /dev/null +++ b/plugins/gs/zerogs/dx/Regs.cpp @@ -0,0 +1,1113 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void __fastcall GIFPackedRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + printf("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +#endif +} + +void __fastcall GIFPackedRegHandlerRGBA(u32* data) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void __fastcall GIFPackedRegHandlerSTQ(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void __fastcall GIFPackedRegHandlerUV(u32* data) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +#define KICK_VERTEX2() { \ + if( ++gs.primC >= (int)g_primmult[prim->prim]) { \ + if( !(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk ) \ + (*ZeroGS::drawfn[prim->prim])(); \ + gs.primC -= g_primsub[prim->prim]; \ + } \ +} \ + +#define KICK_VERTEX3() { \ + if( ++gs.primC >= (int)g_primmult[prim->prim] ) { \ + gs.primC -= g_primsub[prim->prim]; \ + if( prim->prim == 5 ) { \ + /* tri fans need special processing */ \ + if( gs.nTriFanVert == gs.primIndex ) \ + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); \ + } \ + } \ +} \ + +void __fastcall GIFPackedRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerFOG(u32* data) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void __fastcall GIFPackedRegHandlerA_D(u32* data) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void __fastcall GIFPackedRegHandlerNOP(u32* data) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + printf("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void __fastcall GIFRegHandlerPRIM(u32 *data) { + if (data[0] & ~0x3ff) { +#ifdef WARN_LOG + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerRGBAQ(u32* data) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void __fastcall GIFRegHandlerST(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void __fastcall GIFRegHandlerUV(u32* data) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void __fastcall GIFRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerTEX0_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void __fastcall GIFRegHandlerTEX0_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void __fastcall GIFRegHandlerCLAMP_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void __fastcall GIFRegHandlerCLAMP_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void __fastcall GIFRegHandlerFOG(u32* data) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void __fastcall GIFRegHandlerXYZF3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerXYZ3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerNOP(u32* data) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void __fastcall GIFRegHandlerTEX1_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void __fastcall GIFRegHandlerTEX1_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void __fastcall GIFRegHandlerTEX2_1(u32* data) +{ + tex2Write(0, data); +} + +void __fastcall GIFRegHandlerTEX2_2(u32* data) +{ + tex2Write(1, data); +} + +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerPRMODECONT(u32* data) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerPRMODE(u32* data) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerTEXCLUT(u32* data) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void __fastcall GIFRegHandlerSCANMSK(u32* data) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerTEXA(u32* data) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerFOGCOL(u32* data) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void __fastcall GIFRegHandlerTEXFLUSH(u32* data) +{ + ZeroGS::SetTexFlush(); +} + +void __fastcall GIFRegHandlerSCISSOR_1(u32* data) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerSCISSOR_2(u32* data) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerALPHA_1(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[0].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerALPHA_2(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[1].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerDIMX(u32* data) +{ +} + +void __fastcall GIFRegHandlerDTHE(u32* data) +{ + gs.dthe = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerCOLCLAMP(u32* data) +{ + gs.colclamp = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerTEST_1(u32* data) +{ + testWrite(0, data); +} + +void __fastcall GIFRegHandlerTEST_2(u32* data) +{ + testWrite(1, data); +} + +void __fastcall GIFRegHandlerPABE(u32* data) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_1(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_2(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFRAME_1(u32* data) +{ + frameWrite(0, data); +} + +void __fastcall GIFRegHandlerFRAME_2(u32* data) +{ + frameWrite(1, data); +} + +void __fastcall GIFRegHandlerZBUF_1(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void __fastcall GIFRegHandlerZBUF_2(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void __fastcall GIFRegHandlerBITBLTBUF(u32* data) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void __fastcall GIFRegHandlerTRXPOS(u32* data) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void __fastcall GIFRegHandlerTRXREG(u32* data) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void __fastcall GIFRegHandlerTRXDIR(u32* data) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + //WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void __fastcall GIFRegHandlerHWREG(u32* data) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void __fastcall GIFRegHandlerSIGNAL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void __fastcall GIFRegHandlerFINISH(u32* data) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void __fastcall GIFRegHandlerLABEL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} + + +// special execute buffers +//ExecuteBufferXeno g_ebXeno; +// +//ExecuteBufferXeno::ExecuteBufferXeno() +//{ +// clampdata[0] = clampdata[1] = 0; +// tex0data[0] = tex0data[1] = 0; +// tex1data[0] = tex1data[1] = 0; +// bCanExecute = true; +// curprim._val = 0; +//} +// +//void ExecuteBufferXeno::Execute() +//{ +// if( vertices.size() == 0 || !bCanExecute) +// return; +// +// bCanExecute = false; +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// +// int oldC = gs.primC; +// int ctx = curprim.ctxt; +// +// Vertex oldverts[3]; +// oldverts[0] = gs.gsvertex[0]; +// oldverts[1] = gs.gsvertex[1]; +// oldverts[2] = gs.gsvertex[2]; +// +// u32 oldtex0[2]; +// tex1Info oldtex1 = ZeroGS::vb[ctx].tex1; +// clampInfo oldclamp = ZeroGS::vb[ctx].clamp; +// oldtex0[0] = ZeroGS::vb[ctx].uNextTex0Data[0]; +// oldtex0[1] = ZeroGS::vb[ctx].uNextTex0Data[1]; +// +// int oldmask = ZeroGS::vb[ctx].zbuf.zmsk; +// ZeroGS::vb[ctx].zbuf.zmsk = 1; +// tex0Write(0, tex0data); +// tex1Write(0, tex1data); +// clampWrite(0, clampdata); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// gs.primC = 3; +// u32 oldprim = prim->_val; +// prim->_val = curprim._val; +// for(int i = 0; i < (int)vertices.size(); i += 3) { +// gs.gsvertex[0] = vertices[i]; +// gs.gsvertex[1] = vertices[i+1]; +// gs.gsvertex[2] = vertices[i+2]; +// (*ZeroGS::drawfn[4])(); // draw a triangle +// } +// vertices.resize(0); +// +// ZeroGS::Flush(ctx); +// +// ZeroGS::vb[ctx].zbuf.zmsk = oldmask; +// gs.primC = oldC; +// gs.gsvertex[0] = oldverts[0]; +// gs.gsvertex[1] = oldverts[1]; +// gs.gsvertex[2] = oldverts[2]; +// ZeroGS::vb[ctx].clamp = oldclamp; +// ZeroGS::vb[ctx].tex1 = oldtex1; +// tex0Write(0, oldtex0); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// prim->_val = oldprim; +// bCanExecute = true; +//} +// +//void ExecuteBufferXeno::SetTex0(u32* data) +//{ +// if( data[0] != tex0data[0] || (data[1]&0x1fffffff) != (tex0data[1]&0x1fffffff) ) +// Execute(); +// +// tex0data[0] = data[0]; +// tex0data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetTex1(u32* data) +//{ +// if( data[0] != tex1data[0] ) +// Execute(); +// +// tex1data[0] = data[0]; +// tex1data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetClamp(u32* data) +//{ +// if( data[0] != clampdata[0] || (data[1]&0xfff) != clampdata[1] ) +// Execute(); +// +// clampdata[0] = data[0]; +// clampdata[1] = data[1]&0xfff; +//} +// +//void ExecuteBufferXeno::SetTri() +//{ +// if( prim->_val != curprim._val ) +// Execute(); +// curprim._val = prim->_val; +// vertices.push_back(gs.gsvertex[0]); +// vertices.push_back(gs.gsvertex[1]); +// vertices.push_back(gs.gsvertex[2]); +//} diff --git a/plugins/gs/zerogs/dx/Regs.h b/plugins/gs/zerogs/dx/Regs.h new file mode 100644 index 0000000000..af446b5af5 --- /dev/null +++ b/plugins/gs/zerogs/dx/Regs.h @@ -0,0 +1,122 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GSREGS_H__ +#define __GSREGS_H__ + +typedef void (__fastcall *GIFRegHandler)(u32* data); + +void __fastcall GIFPackedRegHandlerNull(u32* data); +void __fastcall GIFPackedRegHandlerRGBA(u32* data); +void __fastcall GIFPackedRegHandlerSTQ(u32* data); +void __fastcall GIFPackedRegHandlerUV(u32* data); +void __fastcall GIFPackedRegHandlerXYZF2(u32* data); +void __fastcall GIFPackedRegHandlerXYZ2(u32* data); +void __fastcall GIFPackedRegHandlerFOG(u32* data); +void __fastcall GIFPackedRegHandlerA_D(u32* data); +void __fastcall GIFPackedRegHandlerNOP(u32* data); + +void __fastcall GIFRegHandlerNull(u32* data); +void __fastcall GIFRegHandlerPRIM(u32* data); +void __fastcall GIFRegHandlerRGBAQ(u32* data); +void __fastcall GIFRegHandlerST(u32* data); +void __fastcall GIFRegHandlerUV(u32* data); +void __fastcall GIFRegHandlerXYZF2(u32* data); +void __fastcall GIFRegHandlerXYZ2(u32* data); +void __fastcall GIFRegHandlerTEX0_1(u32* data); +void __fastcall GIFRegHandlerTEX0_2(u32* data); +void __fastcall GIFRegHandlerCLAMP_1(u32* data); +void __fastcall GIFRegHandlerCLAMP_2(u32* data); +void __fastcall GIFRegHandlerFOG(u32* data); +void __fastcall GIFRegHandlerXYZF3(u32* data); +void __fastcall GIFRegHandlerXYZ3(u32* data); +void __fastcall GIFRegHandlerNOP(u32* data); +void __fastcall GIFRegHandlerTEX1_1(u32* data); +void __fastcall GIFRegHandlerTEX1_2(u32* data); +void __fastcall GIFRegHandlerTEX2_1(u32* data); +void __fastcall GIFRegHandlerTEX2_2(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); +void __fastcall GIFRegHandlerPRMODECONT(u32* data); +void __fastcall GIFRegHandlerPRMODE(u32* data); +void __fastcall GIFRegHandlerTEXCLUT(u32* data); +void __fastcall GIFRegHandlerSCANMSK(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); +void __fastcall GIFRegHandlerTEXA(u32* data); +void __fastcall GIFRegHandlerFOGCOL(u32* data); +void __fastcall GIFRegHandlerTEXFLUSH(u32* data); +void __fastcall GIFRegHandlerSCISSOR_1(u32* data); +void __fastcall GIFRegHandlerSCISSOR_2(u32* data); +void __fastcall GIFRegHandlerALPHA_1(u32* data); +void __fastcall GIFRegHandlerALPHA_2(u32* data); +void __fastcall GIFRegHandlerDIMX(u32* data); +void __fastcall GIFRegHandlerDTHE(u32* data); +void __fastcall GIFRegHandlerCOLCLAMP(u32* data); +void __fastcall GIFRegHandlerTEST_1(u32* data); +void __fastcall GIFRegHandlerTEST_2(u32* data); +void __fastcall GIFRegHandlerPABE(u32* data); +void __fastcall GIFRegHandlerFBA_1(u32* data); +void __fastcall GIFRegHandlerFBA_2(u32* data); +void __fastcall GIFRegHandlerFRAME_1(u32* data); +void __fastcall GIFRegHandlerFRAME_2(u32* data); +void __fastcall GIFRegHandlerZBUF_1(u32* data); +void __fastcall GIFRegHandlerZBUF_2(u32* data); +void __fastcall GIFRegHandlerBITBLTBUF(u32* data); +void __fastcall GIFRegHandlerTRXPOS(u32* data); +void __fastcall GIFRegHandlerTRXREG(u32* data); +void __fastcall GIFRegHandlerTRXDIR(u32* data); +void __fastcall GIFRegHandlerHWREG(u32* data); +void __fastcall GIFRegHandlerSIGNAL(u32* data); +void __fastcall GIFRegHandlerFINISH(u32* data); +void __fastcall GIFRegHandlerLABEL(u32* data); + +// special buffers that delay executing some insturctions +//#include +// +//class ExecuteBuffer +//{ +//public: +// virtual void Execute()=0; +//}; +// +//class ExecuteBufferXeno : public ExecuteBuffer +//{ +//public: +// ExecuteBufferXeno(); +// virtual void Execute(); +// +// void SetTex0(u32* data); +// void SetTex1(u32* data); +// void SetClamp(u32* data); +// void SetTri(); +// +// u32 clampdata[2]; +// u32 tex0data[2]; +// u32 tex1data[2]; +// primInfo curprim; +// +// std::vector vertices; +// bool bCanExecute; +//}; +// +//extern ExecuteBufferXeno g_ebXeno; + +#endif diff --git a/plugins/gs/zerogs/dx/Win32/Conf.cpp b/plugins/gs/zerogs/dx/Win32/Conf.cpp new file mode 100644 index 0000000000..e887ad3e81 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/Conf.cpp @@ -0,0 +1,117 @@ +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 4 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + case GSOPTION_WIN960W: + conf.width = 960; + conf.height = 540; + break; + case GSOPTION_WIN1280W: + conf.width = 1280; + conf.height = 720; + break; + case GSOPTION_WIN1920W: + conf.width = 1920; + conf.height = 1080; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/gs/zerogs/dx/Win32/GSsoftdx.def b/plugins/gs/zerogs/dx/Win32/GSsoftdx.def new file mode 100644 index 0000000000..2ea65fb832 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/GSsoftdx.def @@ -0,0 +1,36 @@ +; Declares the module parameters for the DLL. + +LIBRARY "ZeroGS" +DESCRIPTION 'ZeroGS dll' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + GSinit @5 + GSshutdown @6 + GSopen @7 + GSclose @8 + GSgifTransfer1 @13 + GSgifTransfer2 @14 + GSgifTransfer3 @15 + GSreadFIFO @16 + GSvsync @17 + GSmakeSnapshot @18 + GSkeyEvent @19 + GSfreeze @20 + GSconfigure @21 + GStest @22 + GSabout @23 + GSreadFIFO2 @28 + GSirqCallback @29 + GSsetBaseMem @30 + GSwriteCSR @31 + GSchangeSaveState @32 + GSreset @33 + GSgifSoftReset @34 + GSsetFrameSkip @35 + GSsetGameCRC @36 + GSgetLastTag @37 + GSsetupRecording @38 \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/Win32/Win32.cpp b/plugins/gs/zerogs/dx/Win32/Win32.cpp new file mode 100644 index 0000000000..25bc1f68d1 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/Win32.cpp @@ -0,0 +1,269 @@ +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +HINSTANCE hInst=NULL; +static int prevbilinearfilter = 0; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, !!conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA16, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_BMPSNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1920W, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + PUT_CONF(08000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_BMPSNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN960W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN960W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1920W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1920W; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + case IDC_CONFOPT_COMPUTEOR: + { + int value = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + value|= it->second; + } + char str[20]; + sprintf(str, "%.8x", value); + SetWindowText(GetDlgItem(hW, IDC_CONFOPT_IDS), str); + break; + } + case IDC_CONF_DEFAULT: + { + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, 0); + } + break; + } + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/gs/zerogs/dx/Win32/Win32.h b/plugins/gs/zerogs/dx/Win32/Win32.h new file mode 100644 index 0000000000..45322b3d01 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/Win32.h @@ -0,0 +1,9 @@ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/gs/zerogs/dx/Win32/aviUtil.h b/plugins/gs/zerogs/dx/Win32/aviUtil.h new file mode 100644 index 0000000000..f8fcb1c1ea --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/aviUtil.h @@ -0,0 +1,484 @@ +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((stricmp(value, "CVID") == 0) + || (stricmp(value, "IV32") == 0) + || (stricmp(value, "MSVC") == 0) + || (stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/gs/zerogs/dx/Win32/copytopcsx2.bat b/plugins/gs/zerogs/dx/Win32/copytopcsx2.bat new file mode 100644 index 0000000000..43e96d7484 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/copytopcsx2.bat @@ -0,0 +1,4 @@ +copy .\Debug\ZeroGS.pdb ..\..\..\..\..\bin\plugins +copy .\Debug\ZeroGSd.dll ..\..\..\..\..\bin\plugins +copy .\Release\ZeroGS.dll ..\..\..\..\..\bin\plugins +copy ".\Release (to Public)\ZeroGSr.dll" ..\..\..\..\..\bin\plugins \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/Win32/plugin.def b/plugins/gs/zerogs/dx/Win32/plugin.def new file mode 100644 index 0000000000..49ad02b7dc --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/plugin.def @@ -0,0 +1,31 @@ +EXPORTS + GSabout = GSabout@0 @90 + GSclose = GSclose@0 @91 + GSconfigure = GSconfigure@0 @92 + GSfreeze = GSfreeze@8 @93 + GSgetDriverInfo = GSgetDriverInfo@4 @94 + GSgifTransfer1 = GSgifTransfer1@8 @95 + GSgifTransfer2 = GSgifTransfer2@8 @96 + GSgifTransfer3 = GSgifTransfer3@8 @97 + GSinit = GSinit@0 @99 + GSirqCallback = GSirqCallback@4 @101 + GSkeyEvent = GSkeyEvent@4 @102 + GSmakeSnapshot = GSmakeSnapshot@4 @103 + GSopen = GSopen@8 @104 + GSprintf = GSprintf@0 @105 + GSread16 = GSread16@4 @106 + GSread32 = GSread32@4 @107 + GSread64 = GSread64@4 @108 + GSread8 = GSread8@4 @109 + GSreadFIFO = GSreadFIFO@4 @110 + GSreset @111 + GSshutdown = GSshutdown@0 @112 + GStest = GStest@0 @113 + GSvsync = GSvsync@0 @115 + GSwrite16 = GSwrite16@8 @117 + GSwrite32 = GSwrite32@8 @118 + GSwrite64 = GSwrite64@12 @119 + GSwrite8 = GSwrite8@8 @120 + PS2EgetLibName = PS2EgetLibName@0 @128 + PS2EgetLibType = PS2EgetLibType@0 @129 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @130 diff --git a/plugins/gs/zerogs/dx/Win32/ps2fx.dat b/plugins/gs/zerogs/dx/Win32/ps2fx.dat new file mode 100644 index 0000000000000000000000000000000000000000..8189b0692c56b3fcd900b8f3f7e2e376b08eb8ba GIT binary patch literal 3457692 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 z z_CQ%X*2DIfu>}oRsJydrN5ft!uJCu|8qTDJr*eWpBvz?@j%J{+z5|+ z5h$?-DPv{YsqK6dY~M{AnHRUgwx6&k_qrXf{WVb5h&H(F55@rF`3|^nPoV7C?}WSE zf+YX55uP&#N&cq;&a(!|*uEE5p+S=WxeqRj3X=TK{cvwwkmP?l;g;keS&JWlOEZIH zjy??6kmMY;!1>1oiT;nmZKd27`)q}$P7M-2 z_9Q%95hVGarwsW@uBBa1!#yjgpZV1bcT}Sr{0v-oevssUo`>`5f}}5AfJ-h7lKf9U zJlzl^Yb)t;)z*mq*l;`Cw;@Qz_Dk^K4MEahgYfXJK@#tgMpsqsK@tzV1~=UsBx~{O z@YV-|B>yu6mu(J`{LdTk(c<75D$^U!`w|^ZZvBx+(ITa*h=`%R& z2iizIU%`%FbYFaJ$o~-}`JYL+ZBLLg@;^I`a#x$=f4+gk%r@!YU2vnXP5NsZ9<|vd z|3m6u^+nnw|MLUvh_gxl=SR3B$tLr025w2WN&e?2xH``!KJr(%>rj2K-(bg4Hp&0Y z!OmlBve*6{E;!C6`JX@Fp;DWSr9X}GQ@AhfG9KvfJ_Fs*-vypuZqv{I!y{ET*?03Z zgBn?7leNhNSJl|WU%A6sYi;Ccs0J>tw@EDF1J5+rxh*z{5BYgR zbw6oS#+-|Ri(jzGS{VyZzhu+r2w>|gHrYeP!IiJk7qmSdE_%}@{yD)YAF-)!^ht)z zW7LmK3fwntllX_9Nq8RHCjL1MF8Z4OLdFT_O<@z-l@3>YkIktk2OgQViNED%6*c%f z<;=}IIR7tnh7W+pI3*AHlMRS_>z?ifz&PLfElG_uV?U{GDJmK)dSUu#c!8nM>h`PlF}?xeQMJ zB3Q-%KU1lWuYzTrZGgLWX`5dGPfiCbBZqo5Tss>q{`MNU;djazGflAhFLZ`CzyqAD zF@8h87PfeV$n!z`+@)H5LZrW1;HIDuiOKotOF1G!#OL1(7sQ6>^AvESBSdV{3Kyq^ zC>uK53RmQWD8mQb$)~bFU&~Krs{V)&ea-^5E(+1-Ea1`N5P8n_ZrFK3h&)ep58S^b zL~>D`@X)dl@d*#Wos}UH|2zoKt_YDhd=p%|Dn!=eE_k3OMAo2(;K{YfpxYL>^3o8Q zzmLKVS89EFVB6Ip`dkJ)x*#6LUW{@vJ(et#2g`yoW~;lps@ zY>2EuZ@~k<(~s!+9^C8_D)aY!Sb2u(b06@mcc?!10bBh;CAa*cArl-bIns~d!H7`F zjg7-|@uAY*&kUK=P`TIVaARhu=aD{ukG&%cfN!U+}CW#ycR04 ziWfZpR;aR4pC4=)3l-nX&#tQEvrv5w1vY;fDzR$-JUtmI&!7duUAseNtq+2;W3;npl3YX92Ta}t-xV1 zVfx$(?1&H3=T_kIq%g@XC&87@FnL~V0bGz1CjI4vn-_*jd(+|WBlNv8;KF0H4*XQC zOvi`G^UPUrOIeu2D%tSdvM^<=3H)rV%2tNyb1v}Ad13mT3v8|plf3=GaB*FjJmPWb?HB9#1N5TEKhsoMq1aEB* zlXYYf+ZymHt5xS?VUpiC9=1Lirt;C@1i1LwFd2s@!c8yG z7udNBu6qTWuwE~PEj!R3`BPx~JJ=jP6?TqdD`d*ynNP4Yd>TCbWthZt{OqlUzYCLm z#aZykOqk?*E8())F!8I)jq=~Z#OI$4+x`lZ{MZV(!Zlo(u}?Kza8_Kn{N}^Y>dKU&%h$o>8I)t6I@p;LF8=T$ zcW|!e7_!UZwwdzd;^?+ZMgg{ z$xr@j{6^Y>efY^=WwoI{{^wSBzMcB1=Qg;wBV6L%+u@e`!=>-q;Px(UPaY9a-J7W& zJ?}Q;pVZ~|z~#?sJM-v(n%buAd@o%4qPFvW@W9L3p7+DHA>ChHaMVb+#C{LK!ykrA zO!zQ7_i4DSn~xYWUxv$=={CxDh07j!Gd%r6xH4ku$6?d&;j*4S0o(V4%btBJ-0u=0 ze)UPX)ICD>q))*;-VxFlPs0{#1kab_%VB3&gsg+x;Iill*-JhT&)Xv;?tKC7a72iI z?uSjO5fb;l2-jvtsA=r;GF)+xE`J3cDxe%Y^B9EcEsPL<_$u696d`NSYjDxx2(^{@ z@;W?wVubV;k4mWG@(78C-!f#*ijXz&ZMeTGLe(Pw4(wcw&fJ&BDOB0o2#HbOh1=>Q zm=EM*;km2zwLDs(YMUcu&prlMw?v3v{TME9jS&C*32ePHLVlP06dt~ZwqTzLIKL}G ze8QJ-?dAyC+kOQ*9@Dn^+K}I>+cF6^JR2c%ZKqNGLWJxKcEjDTM9A~w-@%SIv_8{t z)LYtC-^1p2BjmU8AK>{9=||f8BiuS3p^DIl$2-*MWQ63Veu1aI(=xxpjXy=m`tloW z`7J`89hie#_C&~YCBMT1?vWDX^EimIStC_5_3wo{f+Ll&M>YPDX|L*{jKrk-rLbeQ`x zFL+!AKM*N#Z!SFkexy80o(Fe*94T{+$7q!0i%8iQEQHlAZRbPawrOqW0z-aA+xbwq zdsf?-M{QK^AKK1`!<8yZ`l|@;H%G~HNsHiV|0wB;qv7`8DDj`izy*;}JTHrF;L-Rf zRRSLi+f$=d4fZ(!Zpn+1@o*ySTo@%WDv$4|;=`h344ed)9~mXN?vvr#;wYJGJl3O< zPl%G=`pV&sQ?w4J!NnC(5?h{b$XDt*m%%MnQIZd@fVZxWl30kxfK**=6wg-j{14n) zA0^{q1>AKddNO{hVCywe(s$>;wbw<-GqWqQ+#V(URRcG7M9H4zeAv_# zCC_Q_IFXv)tm|I`Pd^c*jAt2Y;gRRGt=7WTFVRNq!(&Fuz9UM;!zFOkNR<3OUJtj8 zYTYh{)yLR@@pBnm_eGS%LYKqMJEPP9?P`RJe~6N~z#~dL9~h<2|H8GuL`nYV8iVJe zB>&R{oBoQD^=<<^;u0->@&z}?npSqE=|r-PzpuXi&%7#1yY z1&=_f(dcN&|FpqXiP4h(;c+O{nHDXv*`07%Rh9Gx8Gy@Qh?e#4A8^^r(USjp4K5tk*S>D>yV3fbGCVLEt{tRvlh!Hz~4mX9wh@HQHdm>|`zb4_bgc!;H z?1Z~hVq~m-1J`B5NZh^)uE~v&{Ld6Tb#RR2I=+Rs7RE^a=LfiYag06(4LeSZ(dVGy z%9CRx|ML?(v@}NYKR?5Rr^iU&{S%%$D@O7^b8z1(>Zk3$!;LjDlK=Sw9$FJ4W8hD? zU|o#lf9Bz$`WUhKUvSeEF_Qmr`xXz>cmM$^ZDmgIi)G|KkUbKM|wPQ^WRWv`wt=)C)0^{|SKSUyhOd zPYA5u($|KUUv;Nj0>WdFz`da7cQw%~v4aP@SI_=GsP z@F)6?w#372v-Aaw7b9z&1FrllM&j5+xXCqEd?}CgvG0kM`I`nu`N!&W*>G=Q ztgM4P>Zj^LVkMTyfXz{{vJPg#wQ;eM|H*^PQ)2abZP=C-D}Bo2fU5X_Scz{Bg1Z;S zO8zGw9zG&g@*xMqqs6h3|2fPkKRH&$=i%_|sj>PTH{8A~R@Uev;HtA?WsN%$Hk}hI z`5zuDRQ0Q4QILBYe4*CiSh(ksSjkK9h@q;uJXZE8$H945#mYKc0#7u>N>1i@xblWr z$^V=TC*Kw;^LGi{xiMCs`-a=@!ETIC9#2$T?~j!=?i54jp;%c5Plc-*O{<=KCyTLs2s2ZnZWsO@6H~btc`JeOPlDSyPC-5jF?{=|^Pgn~#yW92oad_5jmwn1Q zqugSbzOI930_?Kyz6f@PB7^_o(MdHBW0$_Z9G*?Ei=7+bt_60n^A&JInqBOCC7hgX z7d!K)rRqM=F8$SH@L_g+-rSI1WY_svcxbU*?0+3xSc(qZx7m<6)h_vv>*0~-_!Sc9G>_{>+l5J^_gAr zKU-nvPWlvEJqfo@+a>?=EIj+GU7vG@TjyynI`EjO>gEkmh440b$`mIt&-3uScbw#Z zUVta9agzVx@l#bC9w#xzKMa}ZILZIK3}?l~N&e>*xWW-9Yxf{rni41L$g6O1Mx5x$ z7=d1P@omN&aUHZaptf_VPRet7{^tw0c72@W ze_FRpg9qQmR*au{SbY*F`Jcbw$%#1e$$Q|UZ{lRF*$a1kht7-{<%bP_j*}SG z1s?r9PVzrI&a3REc)8XSZuE+m{Er!~^o^JK&SSnRKOkQGvo|~z5-^lK%;Wr=0N;_Xfevta#}=8=QYYyx21sE?!9e=ow+iAEC>6Tv*K= z9WQo{f}0n|i=Crk>k08<=NPzh2|8e(Sh%-5Ui!-c_gBVCJe&yEtcsVIkjINvdriEo zn+pt?wed1$l8y5Ec**~yz%5tBOa3PV?z%o+)>9rqRs%Q3Oa3PduDC5;{AxBlb4R@7 ze{$fGd$c`s;hxTT$^YcT!`<<+4jv58J{B+eA0A&;9Z%AB#=s$P!87sVp9|ow=i?>r z<*{aE9f+6w&yn!_>$?0XxcV*1xwZ%{dpBPEA&)z&{14*weiNSj1Uq1#W8k(4-Crf} z)Kt90!^aykKgNqsJ^`-yC0_DBC&I&jpfmka3eUPENQ`&GpR?h? zLleYSD-8J~5~M9vaMUpgG6v2u%1aVtU$7c3E=!R7&w23RX<8p1*H-;!B#5ofhr5?2 zNdD&nxMNj<%(XRe*7*sN|EYuPE=rL6&qZ)cgO<4%wqKnf>&qo@&vgls)2N4?wn*y_GyCTe{O^OzfO?+ z&+SI}x9EvJZHD~!36lT01J3#x+p=H26KhAM~Te|q7f z)ef0!&%ixv9I`KX9`3xvA>-i%IPVIF*ty@3U+<8 ze;$M@?s7=}hsWquOQ)834bFeqA^!7qc>Ga^tJn(r zzXK2Na7c_g0#CiIb$b_{d(R>HpZ8$v#}1im@54i%J0$-z1{dtoI(!UIO*yWmDgqV(4^oSdF0dzSCvuDnFa|NH=VEY$V?2)7g_O8#dCt}RX!Tm1x^ zOA{sk^D8`XdZLVn-{AhrM9Kfm!FlIs-F}BV&rOv4&mXX@Hc?`sKjGwy6D9wncqD!5 z%0xBJm~nvzuSS3N@2;?O13JTQ@aT1kvOb#N-WwB@gSo@81kSG|>h%$>zavq`j1Sy= zSEB0RS_|yxpnjO+3QFCN4qWR8+cqW2Gu8fZ%_E5to7v#9$IzL64~B=H!anH6kp?yJ zY@(di3WevMPn6g@46Yx*Cdh}wS+6CkLHu?MJo{FnjG0*2`kro!9qt?DUg*Pd2-W#f zB5?rwO?cqbL{$YRz>bMT@k_}Df1~f40$1#&ey&Z0?cXQL8Ll)#W+qY2#5v*0S#+bG zba-Mek@Jw`W8vXFx?ea}!Sl08@@#M(oaK=u&(j_NS9>MNbHWG0W4=iemmUPS1SY9G z{89lt5SAqG5jhlYj7gHSX@|js@kw$Hg5w#gctMgH=DvlnEj>w@xb_G*EH_D6nWsm? z$%iD#m^lXSJRBM9Tnu*|NuBVq@YJFtd8U0aT(y|{(yrrR$B9Yu40b78yEIAmk|!B5 zrzOcd1y6=2mm!a>mcU(S(q8H;gFDVn5?d{W$5tlk^$~8ZNs_s_4DPF??Oe-o5mmE} z`r$L+%8Qfa{NR~z%VpYDXTkGVCP{x)8Qhd4>lDXJRPznA7oAta?KdaMS*=y@)NM%; zTUNu3?Mbq)JQps#FGZSVw$(a# zv@c2gQawDqUElXoxZoA)r!AMkVXr008LrFWyf>1>=X0z@HNS;!)OiJLe^2+_)v#ks z_bwQ%b$#sKwjBt}(C>;7tiyMIoSb?PR#aV|;D zrg1!m_gW;$d4yZwdY1*VHnqYPo(ohIYG zFOYoQU2wO3f#i+vh6@rGNS@~&*p|9L^0%FEebxf;pAW!ec?)E2a{NXO9JD}kwwvI| zg<7TyE;@XHj7g5=aL#vu#4}sq-edK>9)*if(E9YiRVOV_<>j$=Qn{wnUv z{Mrt;UAI7*uK7gQ`5D|Zu|Upxd=A&{#3uNhFW|b}3nY%3 zfCpz7547b=*#6rBRgHZ(!lat_E|A>mF1X2*Ec??b*lbRgxaC`T$R}B3cEf|#WXV;2 z2ag9Q%k#rCaAQ=m^wCf7oIP3Q=FbKvBumcrpK#s+Ei()Eq$SIk`~@z|N|tzrBT}m5 zz+}l${|V16OqM*rJnTFyS@!RL!5v3vnLTjv(aDn6-3wcfOP2mJSs4!}={nuvx>J*7 zj&Qt6nJSXytd=J{TA3_!$_&q}OjgO*#|sWSpZj7TKe*(gWEpS%u<5d7IgiG1ELC(x zvh3dj;DJUh6A0IDNS3oOL2$_p=uDkqaDS^V4~JXtNS3)70Z+FlOO7-WZtBo7QE>SK z$udr&;o^sNyW-)_o@B{UbHt11Y-tzc#{uU*lPoc3B5c~GWs+da_GG=^gtK1J{pEy5 z-_UiY!_JXpIqSjkFlGJ#n=pPdVaF%Q5=UjhEfdKS!(_v1SF&ovJ_o{$KPF3V! z;E}u(85<|Ul?SKDZx&^6@8KzuH(Ls~E=rM@

=J*c6EkPKB#ZNRhar94;+Ok+}3U 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šy&l~ZSM&KdGv=5E1Hc~o2(X%s)lZ=5He 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 SdnNM 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

C?IwZ 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 literal 0 HcmV?d00001 diff --git a/plugins/gs/zerogs/dx/Win32/zerogs.rc b/plugins/gs/zerogs/dx/Win32/zerogs.rc new file mode 100644 index 0000000000..e91d4d21c4 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs.rc @@ -0,0 +1,235 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_ZEROGSLOGO BITMAP "zerogs.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// RCDATA +// + +IDR_SHADERS RCDATA "ps2fx.dat" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 427, 385 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Interlace Enable (toggle with F5)\n there are 2 modes + interlace off",IDC_CONFIG_INTERLACE, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,7,134,18 + CONTROL "Bilinear Filtering (Shift+F5)\n Best quality is on, turn off for speed.",IDC_CONFIG_BILINEAR, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,31,135,18 + CONTROL "None",IDC_CONFIG_AANONE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,19,92,34,11 + CONTROL "2X",IDC_CONFIG_AA2,"Button",BS_AUTORADIOBUTTON,69,92,26,11 + CONTROL "4X",IDC_CONFIG_AA4,"Button",BS_AUTORADIOBUTTON,111,92,28,11 + CONTROL "8X",IDC_CONFIG_AA8,"Button",BS_AUTORADIOBUTTON,69,108,26,11 + CONTROL "16X",IDC_CONFIG_AA16,"Button",BS_AUTORADIOBUTTON,111,108,28,11 + CONTROL "Wireframe rendering (F7)",IDC_CONFIG_WIREFRAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,129,93,10 + CONTROL "Capture Avi (zerogs.avi) (F12)",IDC_CONFIG_CAPTUREAVI, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,109,10 + CONTROL "Save Snapshots as BMPs (default is JPG)",IDC_CONFIG_BMPSS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,162,147,10 + CONTROL "Fullscreen (Alt+Enter)\n to get out press Alt+Enter again",IDC_CONFIG_FULLSCREEN, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,178,146,17 + CONTROL "640 x 480",IDC_CONF_WIN640,"Button",BS_AUTORADIOBUTTON | WS_GROUP,15,233,59,8 + CONTROL "800 x 600",IDC_CONF_WIN800,"Button",BS_AUTORADIOBUTTON,78,233,59,8 + CONTROL "1024 x 768",IDC_CONF_WIN1024,"Button",BS_AUTORADIOBUTTON,15,246,59,8 + CONTROL "1280 x 960",IDC_CONF_WIN1280,"Button",BS_AUTORADIOBUTTON,78,246,59,8 + CONTROL "960 x 540",IDC_CONF_WIN960W,"Button",BS_AUTORADIOBUTTON,14,270,53,8 + CONTROL "1280 x 720",IDC_CONF_WIN1280W,"Button",BS_AUTORADIOBUTTON,77,270,53,8 + CONTROL "1920 x 1080",IDC_CONF_WIN1920W,"Button",BS_AUTORADIOBUTTON,14,283,53,8 + DEFPUSHBUTTON "OK",IDOK,7,364,50,14 + PUSHBUTTON "Cancel",IDCANCEL,94,364,50,14 + GROUPBOX "Anti-aliasing for sharper graphics",IDC_STATIC,7,57,136,66 + GROUPBOX "Default Window Size (no speed impact)",IDC_STATIC,7,223,141,76 + LTEXT "Show Frames Per Second (Shift+F7)",IDC_STATIC,7,314,140,10 + GROUPBOX "Advanced Options",IDC_STATIC,152,7,268,371 + LTEXT "Each option is presented with a unique ID in hex. In order to preserve options across games, go into the game's patch (.pnach) file and type\n zerogs=IDS\nwhere IDS is the OR all of the values in hex for every option you want enabled. ",IDC_STATIC,161,16,252,33 + PUSHBUTTON "Use Defaults (recommended)",IDC_CONF_DEFAULT,159,76,151,14 + CONTROL "Disable alpha testing - 00080000",IDC_CONFOPT_00080000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,159,104,119,10 + CONTROL "Disable stencil buffer - 00002000\nusually safe to do for simple scenes",IDC_CONFOPT_00002000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,159,114,118,22 + CONTROL "No target CLUT - 00001000\n(use on RE4, or foggy scenes)",IDC_CONFOPT_00001000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,169,120,24 + CONTROL "Disable depth updates - 00000200",IDC_CONFOPT_00000200, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,161,125,10 + CONTROL "FFX hack - 00000080\nshows missing geometry",IDC_CONFOPT_00000080, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,190,121,17 + CONTROL "Exact color testing - 00000020\nfixes overbright or shadow/black artifacts (crash n burn)",IDC_CONFOPT_00000020, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,209,119,25 + CONTROL "Tex Target checking - 00000001\nlego racers",IDC_CONFOPT_00000001, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,233,123,22 + CONTROL "Interlace 2X - 00000004\nfixes 2x bigger screen (gradius3)",IDC_CONFOPT_00000004, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,254,119,20 + CONTROL "32 bit render targets - 00200000",IDC_CONFOPT_00200000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,285,93,117,10 + CONTROL "No Vertical Stripes - 00004000\n try when there's a lot of garbage on screen",IDC_CONFOPT_00004000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,138,111,28 + CONTROL "No depth resolve - 00008000\nmight give z buffer artifacts",IDC_CONFOPT_00008000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,164,121,19 + CONTROL "full 16 bit resolution - 00010000\nuse when half the screen is missing, etc",IDC_CONFOPT_00010000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,185,125,23 + CONTROL "Auto Reset Targs - 00000002\nshadow hearts, samurai warriors (use when game is slow and toggling AA fixes it)",IDC_CONFOPT_00000002, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,283,212,124,32 + CONTROL "Tex Alpha Hack - 00000008\nnightmare before christmas",IDC_CONFOPT_00000008, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,286,252,125,17 + EDITTEXT IDC_CONFOPT_IDS,372,364,48,14,ES_AUTOHSCROLL | ES_READONLY + CONTROL "Resolve Hack #1 - 00000400\nspeeds some games (kingdom hearts)",IDC_CONFOPT_00000400, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,270,135,19 + CONTROL "Resolve Hack #2 - 00000800\nshadow hearts, urbz",IDC_CONFOPT_00000800, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,276,117,17 + CONTROL "Resolve Hack #3 - 00020000\nneopets",IDC_CONFOPT_00020000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,292,125,17 + CONTROL "Fast Update - 00040000\nspeeds some games (okami)",IDC_CONFOPT_00040000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,297,125,17 + PUSHBUTTON "Compute OR of IDS",IDC_CONFOPT_COMPUTEOR,287,364,73,14 + LTEXT "Important options are listed first. Note, setting option here means that they will be ADDED to whatever options are set in each pnach file.",IDC_STATIC,159,50,252,23 + CONTROL "No target resolves - 00000010\nStops all resolving of targets (try this first for really slow games)",IDC_CONFOPT_00000010, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,104,111,33 + CONTROL "Disable Multiple RTs - 00100000",IDC_CONFOPT_00100000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,159,91,119,10 + CONTROL "No color clamping - 00000040\nSpeeds games up but might be too bright or too dim",IDC_CONFOPT_00000040, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,157,137,123,22 + CONTROL "Specular Highlights - 01000000\nMakes xenosaga graphics faster by removing highlights",IDC_CONFOPT_01000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,313,125,25 + CONTROL "Partial Targets - 02000000\nReduces artifacts and speeds up some games (mgs3)",IDC_CONFOPT_02000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,319,125,24 + CONTROL "Partial Depth - 04000000\nTries to save the depth target as much as possible (mgs3)",IDC_CONFOPT_04000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,159,347,125,24 + LTEXT "shortcuts: F6 - next, Shift+F6 - prev",IDC_STATIC,24,71,116,11 + CONTROL "16:9 widescreen (Shift+F9)",IDC_CONFIG_WIDESCREEN, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,199,146,17 + LTEXT "Widescreen:",IDC_STATIC,14,257,89,11 + CONTROL "Relaxed Depth - 08000000\nMight show hidden sprites (xenosaga text)",IDC_CONFOPT_08000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,338,125,25 +END + +IDD_ABOUT DIALOGEX 0, 0, 182, 78 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About ZeroGS KSOMOS...." +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,57,50,14 + LTEXT "ZeroGS v0.97.1",IDC_STATIC,7,7,160,11 + LTEXT "Thanks to Gabest for some SSE optimizations",IDC_ABOUTTEXT,7,39,152,12 + LTEXT "Author: zerofrog(@gmail.com)",IDC_STATIC,8,23,144,14 +END + +IDD_LOGGING DIALOG 0, 0, 152, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,40,35,50,14 + PUSHBUTTON "Cancel",IDCANCEL,95,35,50,14 + CONTROL "Log",IDC_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,60,15,28,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 420 + TOPMARGIN, 7 + BOTTOMMARGIN, 378 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 71 + END + + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 145 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/gs/zerogs/dx/Win32/zerogs.sln b/plugins/gs/zerogs/dx/Win32/zerogs.sln new file mode 100644 index 0000000000..57da4ac540 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGS", "zerogs.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + Release (to Public) = Release (to Public) + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public).Build.0 = Release (to Public)|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/gs/zerogs/dx/Win32/zerogs.vcproj b/plugins/gs/zerogs/dx/Win32/zerogs.vcproj new file mode 100644 index 0000000000..f2db5cbf2c --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs.vcproj @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/dx/Win32/zerogs_2005.sln b/plugins/gs/zerogs/dx/Win32/zerogs_2005.sln new file mode 100644 index 0000000000..912c89bc53 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs_2005.sln @@ -0,0 +1,22 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zerogs", "zerogs_2005.vcproj", "{5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.ActiveCfg = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/gs/zerogs/dx/Win32/zerogs_2005.vcproj b/plugins/gs/zerogs/dx/Win32/zerogs_2005.vcproj new file mode 100644 index 0000000000..42e2316283 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs_2005.vcproj @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/dx/Win32/zerogs_2005_x64.vcproj b/plugins/gs/zerogs/dx/Win32/zerogs_2005_x64.vcproj new file mode 100644 index 0000000000..ec6fe123e6 --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs_2005_x64.vcproj @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/dx/Win32/zerogs_2008.vcproj b/plugins/gs/zerogs/dx/Win32/zerogs_2008.vcproj new file mode 100644 index 0000000000..fdb07c383f --- /dev/null +++ b/plugins/gs/zerogs/dx/Win32/zerogs_2008.vcproj @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj b/plugins/gs/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj new file mode 100644 index 0000000000..e4e6d14f9a --- /dev/null +++ b/plugins/gs/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/dx/ZeroGSShaders/copytozerogs.bat b/plugins/gs/zerogs/dx/ZeroGSShaders/copytozerogs.bat new file mode 100644 index 0000000000..0e871997fa --- /dev/null +++ b/plugins/gs/zerogs/dx/ZeroGSShaders/copytozerogs.bat @@ -0,0 +1 @@ +copy .\Release\ZeroGSShaders.exe ..\ZeroGS\ \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp b/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp new file mode 100644 index 0000000000..99a631081f --- /dev/null +++ b/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp @@ -0,0 +1,407 @@ +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include + +#include +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; +DWORD dwFlags = 0; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + DWORD type; // 1 - ps, 0 - vs + LPD3DXBUFFER pbuf; +}; + +map mapShaders; + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + int ps2x; // if 0, ps20 only + char* pEffectDir; + + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", pEffectDir, context); + pfilename = strfile; + } +// else if( strstr(pFileName, "ps2hw_ps2x") != NULL ) { +// _snprintf(strfile, 255, "%sps2hw_ps2%c.fx", pEffectDir, ps2x?'x':'0'); +// pfilename = strfile; +// } + else if( strstr(pFileName, "ps2hw.fx") != NULL ) { + _snprintf(strfile, 255, "%s%s", pEffectDir, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +void LoadShader(int index, const char* name, const char* pshader, D3DXMACRO* pmacros, ID3DXInclude* pInclude) +{ + LPD3DXBUFFER pShader = NULL, pError = NULL; + + HRESULT hr = D3DXCompileShaderFromFile(srcfilename, pmacros, pInclude, name, pshader, dwFlags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", name, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return; + } + + SAFE_RELEASE(pError); + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("two shaders share the same index %d\n", index); + exit(0); + } + + SHADERINFO info; + info.type = name[0] == 'p' ? 0x80000000 : 0; + info.pbuf = pShader; + mapShaders[index] = info; +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + if( argc >= 4 ) { + dwFlags = atoi(argv[3]); + } + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + LoadShader(SH_BITBLTVS, "BitBltVS", "vs_2_0", NULL, NULL); + LoadShader(SH_BITBLTVS|SH_30, "BitBltVS", "vs_3_0", NULL, NULL); + LoadShader(SH_BITBLTPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXPS, "BitBltDepthTexPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXMRTPS, "BitBltDepthTexMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCPS, "CRTCPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24PS, "CRTC24PS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS, "ZeroPS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS|SH_30, "ZeroPS", "ps_3_0", NULL, NULL); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTAAPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", "ps_2_0", NULL, NULL); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + ZeroGSShaderInclude inc; + inc.pEffectDir = strdir; + + D3DXMACRO macros[10]; + memset(macros, 0, sizeof(macros)); + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int vs30 = 0; vs30 < 2; ++vs30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + inc.context = 0; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + inc.context = 1; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + } + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int ps30 = 0; ps30 < 2; ++ps30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + LoadShader(psshaders[i]|(ps30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], ps30 ? "ps_3_0" : "ps_2_0", writedepth ? macros : NULL, NULL); + } + } + } + + printf("creating shaders, note that ps2hw_ctx0.fx, and ps2hw_ctx1.fx are required\n"); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + int macroindex = 0; + memset(macros, 0, sizeof(macros)); + + if( g_pPsTexWrap[texwrap] != NULL ) { + macros[0].Name = g_pPsTexWrap[texwrap]; + macros[0].Definition = "1"; + macroindex++; + } + + for(int context = 0; context < 2; ++context) { + inc.context = context; + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) { + macros[macroindex].Name = "WRITE_DEPTH"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) { + macros[macroindex].Name = "TEST_AEM"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) { + macros[macroindex].Name = "EXACT_COLOR"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + if( macros[macroindex].Name != NULL ) + printf("error[%d] %s: %d %d %d %d!\n", macroindex, macros[macroindex].Name, texfilter, fog, writedepth, testaem); + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + } + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + } + } + } + + // create the database + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + DWORD num = (DWORD)mapShaders.size(); + fwrite(&num, 4, 1, fdst); + + i = 0; + DWORD totaloffset = 4+sizeof(SHADERHEADER)*num; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = totaloffset; + h.size = it->second.pbuf->GetBufferSize(); + + fseek(fdst, 4+i*sizeof(SHADERHEADER), SEEK_SET); + fwrite(&h, sizeof(SHADERHEADER), 1, fdst); + + fseek(fdst, totaloffset, SEEK_SET); + fwrite(it->second.pbuf->GetBufferPointer(), it->second.pbuf->GetBufferSize(), 1, fdst); + + totaloffset += it->second.pbuf->GetBufferSize(); + it->second.pbuf->Release(); + } + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + return 0; +} diff --git a/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.h b/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.h new file mode 100644 index 0000000000..a3742f6931 --- /dev/null +++ b/plugins/gs/zerogs/dx/ZeroGSShaders/zerogsshaders.h @@ -0,0 +1,118 @@ +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +#define SHADER_20 0 +#define SHADER_20a 1 +#define SHADER_20b 2 +#define SHADER_30 3 + +// ps == 0, 2.0 +// ps == 1, 2.0a, nvidia +// ps == 2, 2.0b, ati +const static char* g_pShaders[4] = { "ps_2_0", "ps_2_a", "ps_2_b", "ps_3_0" }; +const static char* g_pPsTexWrap[] = { "REPEAT", "CLAMP", "REGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +static HRESULT LoadShaderFromType(const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, DWORD flags, + IDirect3DDevice9* pd3dDevice, ID3DXInclude* pInclude, IDirect3DPixelShader9** pps) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + + LPD3DXBUFFER pShader = NULL, pError = NULL; + SAFE_RELEASE(*pps); + + vector macros; + D3DXMACRO dummy; dummy.Definition = NULL; dummy.Name = NULL; + if( g_pPsTexWrap[texwrap] != NULL ) { + D3DXMACRO m; + m.Name = g_pPsTexWrap[texwrap]; + m.Definition = "1"; + macros.push_back(m); + } + if( writedepth ) { + D3DXMACRO m; + m.Name = "WRITE_DEPTH"; + m.Definition = "1"; + macros.push_back(m); + } + if( testaem ) { + D3DXMACRO m; + m.Name = "TEST_AEM"; + m.Definition = "1"; + macros.push_back(m); + } + if( exactcolor ) { + D3DXMACRO m; + m.Name = "EXACT_COLOR"; + m.Definition = "1"; + macros.push_back(m); + } + + macros.push_back(dummy); + HRESULT hr = D3DXCompileShaderFromFile(srcfile, ¯os[0], pInclude, str, g_pShaders[ps], flags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", str, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return hr; + } + + DWORD* ptr = (DWORD*)pShader->GetBufferPointer(); + hr = pd3dDevice->CreatePixelShader(ptr, pps); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + + return hr; +} + +struct SHADERHEADER +{ + DWORD index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_30 0x4000 // or for vs3.0 shaders +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_BITBLTDEPTHTEXPS 0x8017 +#define SH_BITBLTDEPTHTEXMRTPS 0x8018 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 diff --git a/plugins/gs/zerogs/dx/backup.bat b/plugins/gs/zerogs/dx/backup.bat new file mode 100644 index 0000000000..9da64b07d0 --- /dev/null +++ b/plugins/gs/zerogs/dx/backup.bat @@ -0,0 +1,4 @@ +@echo off +call parsedate +set TIMESTAMP=%month%%day%%year:~2,3% +winrar u ZeroGS%TIMESTAMP%.zip *.h *.cpp Win32\*.sln Win32\*.vcproj Win32\*.suo Win32\*.bat Win32\*.cpp Win32\*.h Win32\*.def *.asm *.fx *.bat zerogs.psd ZeroGSShaders.exe x86\*.* Win32\*.rc Win32\*.bmp Win32\*.dat ..\ZeroGSShaders\*.h ..\ZeroGSShaders\*.cpp \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/buildshaders.bat b/plugins/gs/zerogs/dx/buildshaders.bat new file mode 100644 index 0000000000..401b5f258d --- /dev/null +++ b/plugins/gs/zerogs/dx/buildshaders.bat @@ -0,0 +1,3 @@ +ZeroGSShaders.exe ps2hw.fx ps2fx.dat +del Win32\ps2fx.dat Win32\Release\*.res Win32\Debug\*.res +move /y ps2fx.dat Win32\ps2fx.dat \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/common.h b/plugins/gs/zerogs/dx/common.h new file mode 100644 index 0000000000..1f815f537d --- /dev/null +++ b/plugins/gs/zerogs/dx/common.h @@ -0,0 +1,1142 @@ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // printf("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //printf("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + printf("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + printf(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + printf("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + printf("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + printf("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/gs/zerogs/dx/memcpy_amd.cpp b/plugins/gs/zerogs/dx/memcpy_amd.cpp new file mode 100644 index 0000000000..9d22f60f36 --- /dev/null +++ b/plugins/gs/zerogs/dx/memcpy_amd.cpp @@ -0,0 +1,479 @@ +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/gs/zerogs/dx/ps2hw.fx b/plugins/gs/zerogs/dx/ps2hw.fx new file mode 100644 index 0000000000..1bccf1b7a9 --- /dev/null +++ b/plugins/gs/zerogs/dx/ps2hw.fx @@ -0,0 +1,993 @@ +// Cg Shaders for PS2 GS emulation + +// divides by z for every pixel, instead of in vertex shader +// fixes kh textures +#define PERSPECTIVE_CORRECT_TEX + +//#define TEST_AEM // tests AEM for black pixels +//#define REGION_REPEAT // set if texture wrapping mode is region repeat +//#define WRITE_DEPTH // set if depth is also written in a MRT +//#define ACCURATE_DECOMPRESSION // set for less capable hardware ATI Radeon 9000 series +//#define EXACT_COLOR // make sure the output color is clamped to 1/255 boundaries (for alpha testing) + +#ifdef PERSPECTIVE_CORRECT_TEX +#define TEX_XY tex.xy/tex.z +#define TEX_DECL float3 +#else +#define TEX_XY tex.xy +#define TEX_DECL float2 +#endif + +#ifdef WRITE_DEPTH +#define DOZWRITE(x) x +#else +#define DOZWRITE(x) +#endif + +#include "ps2hw_ctx0.fx" + +// used to get the tiled offset into a page given the linear offset +texture g_txBlocks; +texture g_txBilinearBlocks; +texture g_txSrc; + +texture g_txConv16to32; +texture g_txConv32to16; + +// for region_repeat mode +texture g_txBitwiseANDX; +texture g_txBitwiseANDY; +texture g_txCLUT; + +sampler g_sSrcFinal : register(s2) = sampler_state { + Texture = ; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = Clamp; + AddressV = Clamp; +}; + +sampler g_sBlocks : register(s3) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBilinearBlocks : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sConv16to32 : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler3D g_sConv32to16 : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBitwiseANDX : register(s5) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBitwiseANDY : register(s6) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +// used only on rare cases where the render target is PSMT8H +sampler g_sCLUT : register(s2) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +// global pixel shader constants +float4 g_fInvTexDims : register(c22); // similar to g_fClutOff +float3 g_fFogColor : register(c23); + +// used for rectblitting +float4 g_fBitBltZ : register(c24); + +half4 g_fOneColor : register(c25); // col*.xxxy+.zzzw + +// vertex shader constants +float4 g_fBitBltPos : register(c4); +float4 g_fZ : register(c5); // transforms d3dcolor z into float z +float2 g_fZNorm : register(c6); +float4 g_fBitBltTex : register(c7); + +// pixel shader consts +// .z is used for the addressing fn +half4 g_fExactColor : register(c27) = half4(0.5,0.5/256.0f,0,1/255.0f); +float3 g_fBilinear : register(c28) = float3(-0.7f, -0.65f, 0.9); +float4 g_fZBias : register(c29) = half4(1.0f/256.0f, 1.0004f, 1, 0.5); +float4 g_fc0 : register(c30) = float4(0,1, 0.001, 0.5f); // also for vs +float4 g_fMult : register(c31) = float4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f); + +// vertex shader consts +float4 g_fBitBltTrans : register(c31) = float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f); + +// given a local tex coord, returns the coord in the memory +float2 ps2memcoord(float2 realtex) +{ + float4 off; + + // block off + realtex.xy = realtex.xy * g_fTexDims.xy + g_fTexDims.zw; + realtex.xy = (realtex.xy - frac(realtex.xy)) * g_fMult.zw; + float2 fblock = frac(realtex.xy); + off.xy = realtex.xy-fblock.xy; + +#ifdef ACCURATE_DECOMPRESSION + off.zw = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).xw; + off.x = dot(off.xyw, g_fTexOffset.xyw); + float f = frac(off.x); + float fadd = g_fTexOffset.z * off.z; + off.w = off.x + fadd; + off.x = frac(f + fadd); + off.w -= off.x; +#else + off.z = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).r; + + // combine the two + off.x = dot(off.xyz, g_fTexOffset.xyz)+g_fTexOffset.w; + off.x = modf(off.x, off.w); +#endif + + off.y = off.w * g_fPageOffset.y + g_fPageOffset.x; + return off.xy; +} + +// find all texcoords for bilinear filtering +// assume that orgtex are already on boundaries +void ps2memcoord4(float4 orgtex, out float4 off0, out float4 off1) +{ + //float4 off0, off1, off2, off3; + float4 realtex; + + // block off + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float4 ftransblock = g_fTexBlock.xyxy*fblock + g_fTexBlock.zwzw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors;// = tex2D(g_sBilinearBlocks, ftransblock.xy); + + // this is faster on ffx ingame + colors.x = tex2D(g_sBlocks, ftransblock.xy).r; + colors.y = tex2D(g_sBlocks, ftransblock.zy).r; + colors.z = tex2D(g_sBlocks, ftransblock.xw).r; + colors.w = tex2D(g_sBlocks, ftransblock.zw).r; + + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + + // combine + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +void ps2memcoord4_fast(float4 orgtex, out float4 off0, out float4 off1) +{ + float4 realtex; + + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float2 ftransblock = g_fTexBlock.xy*fblock.xy + g_fTexBlock.zw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors = tex2D(g_sBilinearBlocks, ftransblock.xy); + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +// Wrapping modes +#if defined(REPEAT) + +float2 ps2addr(float2 coord) +{ + return frac(coord.xy); +} + +#elif defined(CLAMP) + +float2 ps2addr(float2 coord) +{ + return clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw); +} + +#elif defined(REGION_REPEAT) + +// computes the local tex coord along with addressing modes +float2 ps2addr(float2 coord) +{ + float2 final = frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); + + if( TexWrapMode.x > g_fBilinear.z ) // region repeat mode for x (umsk&x)|ufix + final.x = tex2D(g_sBitwiseANDX, abs(coord.x)*TexWrapMode.z).x * g_fClampExts.x + g_fClampExts.z; + if( TexWrapMode.y > g_fBilinear.z ) // region repeat mode for x (vmsk&x)|vfix + final.y = tex2D(g_sBitwiseANDY, abs(coord.y)*TexWrapMode.w).x * g_fClampExts.y + g_fClampExts.w; + + return final; +} + +#else + +float2 ps2addr(float2 coord) +{ + return frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); +} + +#endif + +half4 tex2DPS_32(float2 tex0) +{ + return tex2D(g_sMemory, ps2memcoord(tex0).xy); +} + +// use when texture is not tiled +half4 tex2DPS_tex32(float2 tex0) +{ + return tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; +} + +// use when texture is not tiled +half4 tex2DPS_clut32(float2 tex0) +{ + float index = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw).a+g_fPageOffset.w; + return tex1D(g_sCLUT, index*g_fExactColor.x+g_fExactColor.y); +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 tex2DPS_tex32to16(float2 tex0) +{ + bool upper = false; + tex0.y += g_fPageOffset.z; + float2 ffrac = fmod(tex0, g_fTexOffset.xy); + //tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + tex0.y += ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.y; + tex0.x += g_fTexOffset.z; + } + + half4 color = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv+g_fPageOffset.xy).zyxw; +} + +// used when a 16 bit texture is used an 8h +half4 tex2DPS_tex16to8h(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + //tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + tex0.y += g_fPageOffset.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float4 upper = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + // only need alpha + float index = tex3D(g_sConv32to16, upper.zyx-g_fc0.z).y + upper.w*g_fc0.w*g_fc0.w; + return tex1D(g_sCLUT, index+g_fExactColor.y); +} + +// used when a 16 bit texture is used a 32bit one +half4 tex2DPS_tex16to32(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + //tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + tex0.y += g_fPageOffset.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float fconst = g_fc0.w*g_fc0.w; + float4 lower = tex2D(g_sSrcFinal, g_fTexDims.xy*tex0); + float4 upper = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*fconst; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*fconst; + return final; +} + +//half4 f; +//f.w = old.y > (127.2f/255.0f) ? 1 : 0; +//old.y -= 0.5f * f.w; +//f.xyz = frac(old.yyx*half3(2.002*255.0f/256.0f, 64.025f*255.0f/256.0f, 8.002*255.0f/256.0f)); +//f.y += old.x * (0.25f*255.0f/256.0f); + +//////////////////////////////// +// calculates the texture color +//////////////////////////////// + +#define decl_ps2shade(num) \ +decl_ps2shade_##num(_32); \ +decl_ps2shade_##num(_tex32); \ +decl_ps2shade_##num(_clut32); \ +decl_ps2shade_##num(_tex32to16); \ +decl_ps2shade_##num(_tex16to8h); \ + +// nearest +#define decl_ps2shade_0(bit) \ +half4 ps2shade0##bit( TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// do fast memcoord4 calcs when textures behave well +#ifdef REPEAT +#define PS2MEMCOORD4 ps2memcoord4 +#else +#define PS2MEMCOORD4 ps2memcoord4 +#endif + +#define decl_BilinearFilter(bit, addrfn) \ +half4 BilinearFilter##bit(float2 tex0) \ +{ \ + float4 off0, off1; \ + float4 ftex; \ + float2 ffrac; \ + ftex.xy = tex0 + g_fBilinear.xy * g_fRealTexDims.zw; \ + ffrac = frac(ftex.xy*g_fRealTexDims.xy); \ + ftex.xy -= ffrac.xy * g_fRealTexDims.zw; \ + \ + ftex.zw = ps2addr(ftex.xy + g_fRealTexDims.zw); \ + ftex.xy = ps2addr(ftex.xy); \ + \ + PS2MEMCOORD4(ftex, off0, off1); \ + half4 c0 = tex2D(g_sMemory, off0.xy); \ + half4 c1 = tex2D(g_sMemory, off0.zw); \ + half4 c2 = tex2D(g_sMemory, off1.xy); \ + half4 c3 = tex2D(g_sMemory, off1.zw); \ + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); \ +} \ + +decl_BilinearFilter(_32, ps2addr); +decl_BilinearFilter(_tex32, ps2addr); +decl_BilinearFilter(_clut32, ps2addr); +decl_BilinearFilter(_tex32to16, ps2addr); +decl_BilinearFilter(_tex16to8h, ps2addr); + +//TODO! For mip maps, only apply when LOD >= 0 +// lcm == 0, LOD = log(1/Q)*L + K, lcm == 1, LOD = K + +// bilinear +#define decl_ps2shade_1(bit) \ +half4 ps2shade1##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// nearest, mip nearest +#define decl_ps2shade_2(bit) \ +half4 ps2shade2##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// nearest, mip linear +#define decl_ps2shade_3(bit) \ +half4 ps2shade3##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit(ps2addr(TEX_XY)); \ +} \ + +// linear, mip nearest +#define decl_ps2shade_4(bit) \ +half4 ps2shade4##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// linear, mip linear +#define decl_ps2shade_5(bit) \ +half4 ps2shade5##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +decl_ps2shade(0); +decl_ps2shade(1); +decl_ps2shade(2); +decl_ps2shade(3); +decl_ps2shade(4); +decl_ps2shade(5); + +half4 ps2CalcShade(half4 texcol, half4 color) +{ +#ifdef TEST_AEM + if( dot(texcol.xyzw, g_fTestBlack.xyzw) <= g_fc0.z ) + texcol.w = g_fc0.x; + else +#endif + texcol.w = texcol.w * fTexAlpha.y + fTexAlpha.x; + + texcol = texcol * (fTexAlpha2.zzzw * color + fTexAlpha2.xxxy) + fTexAlpha.zzzw * color.wwww; + + return texcol; +} + +// final ops on the color +#ifdef EXACT_COLOR + +half4 ps2FinalColor(half4 col) +{ + // g_fOneColor has to scale by 255 + half4 temp = col * g_fOneColor.xxxy + g_fOneColor.zzzw; + temp.w = floor(temp.w)*g_fExactColor.w; + return temp; +} + +#else +half4 ps2FinalColor(half4 col) +{ + return col * g_fOneColor.xxxy + g_fOneColor.zzzw; +} +#endif + +//////////////// +// Techniques // +//////////////// + +// technique to copy a rectangle from source to target +struct VSOUT_ +{ + float4 pos : POSITION; + half4 color : COLOR0; + DOZWRITE(float4 z : TEXCOORD0;) +}; + +struct VSOUT_T +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_F +{ + float4 pos : POSITION; + half4 color : COLOR0; + float fog : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_TF +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + half fog : TEXCOORD1; + DOZWRITE(float4 z : TEXCOORD2;) +}; + +// just smooth shadering +VSOUT_ RegularVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : TEXCOORD0 + ) +{ + VSOUT_ o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; // 1 + o.color = color; + + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + return o; +} + +void RegularPS(VSOUT_ i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + // whenever outputting depth, make sure to mult by 255/256 and 1 + c0 = ps2FinalColor(i.color); + DOZWRITE(c1 = i.z;) +} + +technique Regular { + pass p0 { + VertexShader = compile vs_3_0 RegularVS(); + PixelShader = compile ps_3_0 RegularPS(); + } +}; + +// diffuse texture mapping +VSOUT_T TextureVS(float4 pos : POSITION, + half4 color : COLOR0, + float3 tex0 : TEXCOORD1, + float4 z : TEXCOORD0) +{ + VSOUT_T o; + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x + g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0, out float4 c1 : COLOR1) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ +} \ + +#endif + +#define DECL_TEXPS_(num) \ +DECL_TEXPS(num, _32); \ +DECL_TEXPS(num, _tex32); \ +DECL_TEXPS(num, _clut32); \ +DECL_TEXPS(num, _tex32to16); \ +DECL_TEXPS(num, _tex16to8h); \ + +DECL_TEXPS_(0); +DECL_TEXPS_(1); +DECL_TEXPS_(2); +DECL_TEXPS_(3); +DECL_TEXPS_(4); +DECL_TEXPS_(5); + +// special functions for limitations on ps20 +technique Texture { + pass p0 { + VertexShader = compile vs_2_0 TextureVS(); + PixelShader = compile ps_2_a Texture0_32PS(); + } +} + +VSOUT_F RegularFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : TEXCOORD0) +{ + VSOUT_F o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + o.color = color; + o.fog = pos.z; + return o; +} + +void RegularFogPS(VSOUT_F i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + half4 c; + c.xyz = lerp(g_fFogColor.xyz, i.color.xyz, i.fog); \ + c.w = i.color.w; + c0 = ps2FinalColor(c); + DOZWRITE(c1 = i.z;) +} + +technique RegularFog { + pass p0 { + VertexShader = compile vs_2_0 RegularFogVS(); + PixelShader = compile ps_2_a RegularFogPS(); + } +}; + +VSOUT_TF TextureFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float3 tex0 : TEXCOORD1, + float4 z : TEXCOORD0) +{ + VSOUT_TF o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + o.fog = pos.z; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0, out float4 c1 : COLOR1 ) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ +} \ + +#endif + +#define DECL_TEXFOGPS_(num) \ +DECL_TEXFOGPS(num, _32); \ +DECL_TEXFOGPS(num, _tex32); \ +DECL_TEXFOGPS(num, _clut32); \ +DECL_TEXFOGPS(num, _tex32to16); \ +DECL_TEXFOGPS(num, _tex16to8h); \ + +DECL_TEXFOGPS_(0); +DECL_TEXFOGPS_(1); +DECL_TEXFOGPS_(2); +DECL_TEXFOGPS_(3); +DECL_TEXFOGPS_(4); +DECL_TEXFOGPS_(5); + +technique TextureFog { + pass p0 { + VertexShader = compile vs_2_0 TextureFogVS(); + PixelShader = compile ps_2_a TextureFog0_32PS(); + } +}; + +//------------------------------------------------------- +// Techniques not related to the main primitive commands +half4 BilinearBitBlt(float2 tex0) +{ + float4 ftex; + float2 ffrac; + + ffrac.xy = frac(tex0*g_fRealTexDims.xy); + ftex.xy = tex0 - ffrac.xy * g_fRealTexDims.zw; + ftex.zw = ftex.xy + g_fRealTexDims.zw; + + float4 off0, off1; + ps2memcoord4_fast(ftex, off0, off1); + half4 c0 = tex2D(g_sMemory, off0.xy); + half4 c1 = tex2D(g_sMemory, off0.zw); + half4 c2 = tex2D(g_sMemory, off1.xy); + half4 c3 = tex2D(g_sMemory, off1.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); +} + +void BitBltVS(in float4 pos : POSITION, + in half4 tex0 : TEXCOORD0, + in float3 tex : TEXCOORD1, + out float4 opos : POSITION, + out float2 otex0 : TEXCOORD0, + out float2 ointerpos : TEXCOORD1) +{ + opos.xy = pos.xy * g_fBitBltPos.xy + g_fBitBltPos.zw; + ointerpos = opos.xy * g_fBitBltTrans.xy + g_fBitBltTrans.zw; + opos.zw = g_fc0.xy; + otex0 = tex * g_fBitBltTex.xy + g_fBitBltTex.zw; +} + +half4 BitBltPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return tex2D(g_sMemory, ps2memcoord(tex0).xy)*g_fOneColor.xxxy; +} + +// used when AA +half4 BitBltAAPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return BilinearBitBlt(tex0)*g_fOneColor.xxxy; +} + +void BitBltDepthPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = tex2D(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c, g_fBitBltZ))*g_fOneColor.w; + c += g_fZBias.y; +} + +void BitBltDepthMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = tex2D(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c1, g_fBitBltZ))*g_fOneColor.w; + c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +// no swizzling +void BitBltDepthTexPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = tex2D(g_sSrcFinal, tex0); + + depth = log(g_fc0.y+dot(c-g_fZBias.y, g_fBitBltZ))*g_fOneColor.w; + //c += g_fZBias.y; +} + +// no swizzling +void BitBltDepthTexMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = tex2D(g_sSrcFinal, tex0); + + depth = log(g_fc0.y+dot(c1-g_fZBias.y, g_fBitBltZ))*g_fOneColor.w; + //c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +technique BitBlt { + pass p0 { + VertexShader = compile vs_1_1 BitBltVS(); + PixelShader = compile ps_2_0 BitBltDepthMRTPS(); + } +} + +/*static const float BlurKernel[9] = { + 0.027601, + 0.066213, + 0.123701, + 0.179952, + 0.205065, + 0.179952, + 0.123701, + 0.066213, + 0.027601 +};*/ + +half4 BilinearFloat16(float2 tex0) +{ + /*float4 ffrac, ftex; + ffrac.xy = frac(tex0); + ftex.xy = (tex0 - ffrac.xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + ftex.zw = ftex.xy + g_fInvTexDims.xy; + + half4 c0 = tex2D(g_sSrcFinal, ftex.xy); + half4 c1 = tex2D(g_sSrcFinal, ftex.zy); + half4 c2 = tex2D(g_sSrcFinal, ftex.xw); + half4 c3 = tex2D(g_sSrcFinal, ftex.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y );*/ + return tex2D(g_sSrcFinal, tex0.xy); +// return 0.55f * tex2D(g_sSrcFinal, tex0.xy) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.xz) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.zy) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.xy); +} + +half4 CRTCTargInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c.zyxw; +} + +half4 CRTCTargPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c.zyxw; +} + +half4 CRTCInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTCPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0/*-frac(tex0)*/)*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTC24InterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = tex2D(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTC24PS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = tex2D(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +technique CRTC { + pass p0 { + VertexShader = compile vs_1_1 BitBltVS(); + PixelShader = compile ps_2_0 CRTCTargInterPS(); + } +} + +half4 ZeroPS() : COLOR +{ + return g_fOneColor.x; +} + +half4 BaseTexturePS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return tex2D(g_sSrcFinal, tex0) * g_fOneColor; +} + +// inverse of 32->16bit conversion +half4 Convert16to32PS(float2 tex0 : TEXCOORD0) : COLOR +{ + float4 final; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.y += g_fTexDims.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float4 lower = tex2D(g_sSrcFinal, tex0); + float4 upper = tex2D(g_sSrcFinal, tex0+g_fPageOffset.xy); + + //return half4(frac(32*tex0.x),frac(7*tex0.y),0,1); + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*g_fPageOffset.zw; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*g_fPageOffset.zw; + return final; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// one condition is that the converted texture has to keep the same block configuration +// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. +// the first row is the first 8 pixels, the second row is the last 8 pixels +// the last 8 columns are the upper bits +half4 Convert32to16PS(float2 tex0 : TEXCOORD0) : COLOR +{ + bool upper = false; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + //tex0 += g_fTexDims.xy * ffrac; + //tex0.y += g_fTexDims.y * ffrac.y; + tex0.y += ffrac.y; + //tex0.x -= g_fc0.w*ffrac.x; + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.y; + tex0.x += g_fTexOffset.z; + } + + //return half4(frac(32*tex0.x),frac(7*tex0.y),0,1); + half4 color = tex2D(g_sSrcFinal, tex0)*g_fc0.yyyw; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv*g_fPageOffset.xy+g_fPageOffset.zw).zyxw*g_fOneColor; +} diff --git a/plugins/gs/zerogs/dx/ps2hw_ctx0.fx b/plugins/gs/zerogs/dx/ps2hw_ctx0.fx new file mode 100644 index 0000000000..0e2b100f20 --- /dev/null +++ b/plugins/gs/zerogs/dx/ps2hw_ctx0.fx @@ -0,0 +1,33 @@ +// main ps2 memory, each pixel is stored in 32bit color +texture g_txMem0; + +sampler g_sMemory : register(s0) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Clamp; + AddressV = Clamp; +}; + +// per context pixel shader constants +half4 fTexAlpha2 : register(c2); + +float4 g_fTexOffset : register(c4); // converts the page and block offsets into the mem addr/1024 +float4 g_fTexDims : register(c6); // mult by tex dims when accessing the block texture +float4 g_fTexBlock : register(c8); + +float4 g_fClampExts : register(c10); // if clamping the texture, use (minu, minv, maxu, maxv) +float4 TexWrapMode : register(c12); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +float4 g_fRealTexDims : register(c14); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +half4 g_fTestBlack : register(c16); // used for aem bit + +float4 g_fPageOffset : register(c18); + +half4 fTexAlpha : register(c20); + +// vertex shader constants +float4 g_fPosXY : register(c2); \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/ps2hw_ctx1.fx b/plugins/gs/zerogs/dx/ps2hw_ctx1.fx new file mode 100644 index 0000000000..f9423a9019 --- /dev/null +++ b/plugins/gs/zerogs/dx/ps2hw_ctx1.fx @@ -0,0 +1,32 @@ +texture g_txMem1; + +sampler g_sMemory : register(s1) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Clamp; + AddressV = Clamp; +}; + +// per context pixel shader constants +half4 fTexAlpha2 : register(c3); + +float4 g_fTexOffset : register(c5); // converts the page and block offsets into the mem addr/1024 +float4 g_fTexDims : register(c7); // mult by tex dims when accessing the block texture +float4 g_fTexBlock : register(c9); + +float4 g_fClampExts : register(c11); // if clamping the texture, use (minu, minv, maxu, maxv) +float4 TexWrapMode : register(c13); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +float4 g_fRealTexDims : register(c15); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +half4 g_fTestBlack : register(c17); // used for aem bit + +float4 g_fPageOffset : register(c19); + +half4 fTexAlpha : register(c21); + +// vertex shader constants +float4 g_fPosXY : register(c3); \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/targets.cpp b/plugins/gs/zerogs/dx/targets.cpp new file mode 100644 index 0000000000..032bba49bd --- /dev/null +++ b/plugins/gs/zerogs/dx/targets.cpp @@ -0,0 +1,3729 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern LPD3DTEX ptexConv16to32; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern BYTE s_AAx, s_AAy; + extern BYTE bIndepWriteMasks; + extern BOOL s_bBeginScene; + extern D3DFORMAT g_RenderFormat; + extern DXVEC4 g_vdepth; + extern int icurctx; + + extern LPD3DVS pvsBitBlt; + extern LPD3DPS ppsBitBlt[2], ppsBitBltDepth[2], ppsBitBltDepthTex[2], ppsOne; + extern LPD3DPS ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern LPD3DVB pvbRect; +} + +extern LPD3DTEX s_ptexCurSet[2]; +extern LPD3DTEX ptexBilinearBlocks; +extern IDirect3DVolumeTexture9* ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : psurf(NULL), psys(NULL), ptex(NULL), ptexFeedback(NULL), psurfFeedback(NULL) +{ + nUpdateTarg = 0; + targoffx = targoffy = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +CRenderTarget::CRenderTarget(const frameInfo& frame, CRenderTarget& r) +{ + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + // find the xy offset + int blockheight = (frame.psm&2) ? 64 : 32; + int scanlinewidth = 0x2000*(fbw>>6); + + // round down to nearest block and scanline + int startheight = ((256*(fbp-r.fbp))/scanlinewidth) * blockheight; + int offset = ((256*(fbp-r.fbp))%scanlinewidth) / 0x2000; + + targoffx = offset*64; + targoffy = startheight; + targheight = r.targheight; + + pmimicparent = &r; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)targheight; + vposxy.z = -1+(2.0f*(float)targoffx-0.5f)/fbw; + vposxy.w = 1+(-2.0f*(float)targoffy+0.5f)/(float)targheight; + status = 0; + + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + ptex = r.ptex; + if( ptex != NULL ) ptex->AddRef(); + psurf = r.psurf; + if( psurf != NULL ) psurf->AddRef(); + psys = r.psys; + if( psys != NULL ) psys->AddRef(); + + nUpdateTarg = 0; + ptexFeedback = NULL; + psurfFeedback = NULL; +} + +BOOL ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + pmimicparent = NULL; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.z = -1+((float)targoffx-0.5f)/fbw; + vposxy.w = 1+((float)targoffy+0.5f)/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<CreateOffscreenPlainSurface(fbw<GetSurfaceLevel(0, &psurf)); + } + + if( FAILED(hr) ) { + Destroy(); + return FALSE; + } + + targheight = fbh; + status = TS_NeedUpdate; + } + else { + start = end = 0; + } + + return TRUE; +} + +void ZeroGS::CRenderTarget::Destroy() +{ + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); +} + +void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) +{ + int dy = 0; + + if( fbplocal != fbp ) { + DXVEC4 v; + + // will be rendering to a subregion + u32 bpp = (psm&2) ? 2 : 4; + assert( ((256/bpp)*(fbplocal-fbp)) % fbw == 0 ); + assert( fbplocal >= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + SETCONSTF(GPU_POSXY0+context, v); + } + else + SETCONSTF(GPU_POSXY0+context, vposxy); + + RECT rc; + + // set render states + rc.left = scissor.x0>>3; + rc.top = (scissor.y0>>3) + dy; + rc.right = (scissor.x1>>3)+1; + rc.bottom = (scissor.y1>>3)+1+dy; + rc.right = min(rc.right, fbw); + rc.bottom = min(rc.bottom, fbh); + + rc.left += targoffx; rc.right += targoffx; + rc.top += targoffy; rc.bottom += targoffy; + rc.left <<= s_AAx; + rc.top <<= s_AAy; + rc.right <<= s_AAx; + rc.bottom <<= s_AAy; +// rc.right--; +// rc.bottom--; + + scissorrect = rc; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + D3DVIEWPORT9 view; + view.Width = fbw<SetViewport(&view); +} + +static int g_bSaveResolved = 0; +extern int s_nResolved; + +void ZeroGS::CRenderTarget::Resolve() +{ + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( (IsDepth() && !ZeroGS::IsWriteDepth()) || s_nResolved > 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + _Resolve(locksrc, fbp, fbw, fbh, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) +{ + assert( startrange < end && endrange > start ); // make sure it at least intersects + + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + if((g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + status = TS_Resolved; + return; + } + + int blockheight = (psm&2) ? 64 : 32; + int resolvefbp = fbp, resolveheight = fbh; + + int scanlinewidth = 0x2000*(fbw>>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + + if( fbp != resolvefbp ) + locksrc.pBits = (u8*)locksrc.pBits + ((resolvefbp-fbp)*256/scanlinewidth)*blockheight*locksrc.Pitch; + + _Resolve(locksrc, resolvefbp, fbw, resolveheight, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) +{ + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + assert( targoffx == 0 && targoffy == 0 ); + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set + //pd3dDevice->SetDepthStencilSurface(psurfDepth); +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetRenderTarget(0, psurf); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<second == this ) { + printf("zerogs: updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + printf("zerogs: updating self"); + nUpdateTarg = 0; + } + } + + if( nUpdateTarg ) { + + pd3dDevice->SetTexture(SAMP_FINAL, ittarg->second->ptex); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)targheight / ittarg->second->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / ittarg->second->fbh + 0.25f / (ittarg->second->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = v.w = 1; + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetPixelShader(ppsBaseTexture); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, 1); + + v = DXVEC4(1,1,0,0); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = 1; + v.y = 2; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, 0xff); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBitBlt[s_AAx]); + } + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL) ) { + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILREF, 1); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); +// else + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, pdepth->psurf); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 64.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 8.0f / (float)fbw; + v.y = 0; + v.z = 0; + v.w = 0.25f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_TEXDIMS0, v); + + v.x = 0; + SETCONSTF(GPU_TEXBLOCK0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh /= 2; // have 16 bit surfaces are usually 2x higher + targheight /= 2; + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert16to32); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + //D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + if( g_bSaveZUpdate ) { + // buggy + D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + + //LPD3DTEX ptemp; + //pd3dDevice->CreateTexture(fbw, fbh, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptemp, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<GetRenderTargetData(psurf, psys); + + psys->LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD cols[2]; + float tempf[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = 2*j - (j%16); + if( (j%16) >=8 ) jj += 8; + int ii = 2*i - (i%8); + if( j >= fbw/2 ) { ii += 8; jj -= fbw; } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + cols[0] = Float16ToARGB(psrc[0]); + cols[1] = Float16ToARGB(psrc[8]); + //cols[0] = (cols[0]&0xff00ff00)|((cols[0]&0xff)<<16)|((cols[0]&0xff0000)>>16); + //cols[1] = (cols[1]&0xff00ff00)|((cols[1]&0xff)<<16)|((cols[1]&0xff0000)>>16); + DWORD col = RGBA32to16(cols[0])|(RGBA32to16(cols[1])<<16); + tempf[2] = (col&0xff)/255.0f; + tempf[1] = ((col>>8)&0xff)/255.0f; + tempf[0] = ((col>>16)&0xff)/255.0f; + tempf[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, tempf, 4); + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + +// SAFE_RELEASE(psys); +// psys = ptempsys; +// +// pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// one condition is that the converted texture has to keep the same block configuration +// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. +// the first row is the first 8 pixels, the second row is the last 8 pixels +// the last 8 columns are the upper bits +void ZeroGS::CRenderTarget::ConvertTo16() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 2; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 32.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 256.0f / 255.0f; + v.y = 256.0f / 255.0f; + v.z = 0.05f / 256.0f; + v.w = -0.001f / 256.0f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = -0.5f; + v.y = 1; + v.z = 0; + v.w = -0.1f/fbh; + SETCONSTF(GPU_TEXDIMS0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh *= 2; // have 16 bit surfaces are usually 2x higher + targheight *= 2; + + // need to set a dummy target! +// CRenderTargetMngr::MAPTARGETS::iterator itdepth = s_DepthRTs.mapDummyTargs.find( (fbw<<16)|fbh ); +// CDepthTarget* pnewdepth = NULL; +// if( itdepth == s_DepthRTs.mapDummyTargs.end() ) { +// frameInfo frame; +// frame.fbh = fbh; +// frame.fbw = fbw; +// frame.psm = 0x30; //? +// frame.fbw = fbw; +// frame.fbm = 0; +// pnewdepth = new CDepthTarget(); +// pnewdepth->Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert32to16); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + pd3dDevice->GetRenderTargetData(psurf, psys); + + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD col; + float temp[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = j; + int upper = 0; + if( (j%16) >=8 ) { + jj -= 8; + upper = 1; + } + int ii = (i - (i%64))/2 + (i%64); + if( (i%64) >= 32 ) { + ii -= 32; + jj += 8; + } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + col = Float16ToARGB(psrc[0]); + if( upper ) col >>= 16; + else col &= 0xffff; + col = RGBA16to32(col); + temp[2] = (col&0xff)/255.0f; + temp[1] = ((col>>8)&0xff)/255.0f; + temp[0] = ((col>>16)&0xff)/255.0f; + temp[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, temp, 4); + + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + + SAFE_RELEASE(psys); + psys = ptempsys; + + pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == NULL ) { + // create + assert( pmimicparent == NULL ); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfFeedback)); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // assume depth already set +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + pd3dDevice->SetRenderTarget(0, psurfFeedback); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + if( s_ptexCurSet[0] == ptexFeedback ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptexFeedback ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBaseTexture); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + swap(ptex, ptexFeedback); + swap(psurf, psurfFeedback); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + status |= TS_FeedbackReady; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(NULL) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +BOOL ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) return FALSE; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + HRESULT hr; + V(pd3dDevice->CreateDepthStencilSurface(fbw<CreateDepthStencilSurface(fbw, fbh, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &pdepth, NULL)); + } + + if( FAILED(hr) ) + return FALSE; + + status = TS_NeedUpdate; + + return TRUE; +} + +void ZeroGS::CDepthTarget::Destroy() +{ + if( pd3dDevice != NULL ) { + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(NULL); + vb[0].bVarsSetTarg = 0; + vb[1].bVarsSetTarg = 0; + } + + CRenderTarget::Destroy(); + SAFE_RELEASE(pdepth); +} + +extern int g_nDepthUsed; // > 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) || targoffx != 0 || targoffy != 0 ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + CRenderTarget* pusetarg = NULL; + if( nUpdateTarg ) { + CRenderTargetMngr::MAPTARGETS::iterator ittarg = s_DepthRTs.mapTargets.find(nUpdateTarg); + if( ittarg == s_DepthRTs.mapTargets.end() || ittarg->second == this) { + printf("zerogs: updating self"); + nUpdateTarg = 0; + } + else pusetarg = ittarg->second; + } + + tex0Info texframe; + CMemoryTarget* pmemtarg = NULL; + if( pusetarg == NULL ) { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ZWRITEENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_ZFUNC, D3DCMP_ALWAYS); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<SetTexture(SAMP_FINAL, pusetarg->ptex); + + //assert( pusetarg->fbw == fbw ); + int offset = (fbp-pusetarg->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)fbh / pusetarg->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / pusetarg->fbh + 0.25f / (pusetarg->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + } + else { + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, 1); + + DXVEC4 v = DXVEC4(1,1,0.5f/(float)fbw,0.5f/(float)fbh); + SETCONSTF(GPU_BITBLTTEX, v); + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + DXVEC4 vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + SETCONSTF(GPU_BITBLTZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != NULL ); + + if( ZeroGS::IsWriteDepth() && conf.mrtdepth && bIndepWriteMasks) { + // write in MRT1 + pd3dDevice->SetRenderTarget(1, psurf); + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + } + else { + // turn off writes? + if( bIndepWriteMasks ) { + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + else pd3dDevice->SetRenderTarget(0, psurf); + } + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( pusetarg != NULL ) { + pd3dDevice->SetPixelShader(ppsBitBltDepthTex[conf.mrtdepth]); + } + else { + pd3dDevice->SetPixelShader(ppsBitBltDepth[conf.mrtdepth]); + } + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + status = TS_Resolved; + + if( conf.mrtdepth && bIndepWriteMasks ) { + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + if( !ZeroGS::IsWriteDepth() ) { + pd3dDevice->SetRenderTarget(1, NULL); + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + if( pusetarg != NULL ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pusetarg->ptex, NULL); + else + SaveTex(&texframe, 1); + D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + } + //pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 0, 0); +#endif +} + +void ZeroGS::CDepthTarget::SetDepthTarget() +{ + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( conf.mrtdepth && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, psurf); +} + +void ZeroGS::CRenderTargetMngr::Destroy() +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) + delete it->second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, DWORD opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + + if( (g_GameSettings&GAME_PARTIALDEPTH) && !bfound ) { + MAPTARGETS::iterator itnew = mapTargets.find(key+1); + if( itnew != mapTargets.end() && itnew->second->fbh == frame.fbh ) { + // found! delete the previous and restore + delete it->second; + mapTargets.erase(it); + + it = mapTargets.insert(MAPTARGETS::value_type(key, itnew->second)).first; // readd + mapTargets.erase(itnew); // delete old + + bfound = true; + } + } + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound && (frame.psm&2) && !(it->second->psm&2) && (g_GameSettings&GAME_FULL16BITRES) ) { + // mgs3 + if( frame.fbh > it->second->fbh ) { + bfound = false; + } + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif + if( !(opts&TO_StrictHeight) ) { + if( !(g_GameSettings & GAME_VSSHACKOFF) ) { + if( it->second->psm & 2 ) { + it->second->status |= CRenderTarget::TS_NeedConvert32; + it->second->fbh /= 2; + it->second->targheight /= 2; + } + else { + it->second->status |= CRenderTarget::TS_NeedConvert16; + it->second->fbh *= 2; + it->second->targheight *= 2; + } + } + } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + // only update if target isn't mirrored + bool bCheckHalfCovering = (g_GameSettings&GAME_FULL16BITRES) && (it->second->psm&2) && it->second->fbh +32 < frame.fbh; + + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->ptex != it->second->ptex && itnew->second->ptexFeedback != it->second->ptex && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + // if new target totally encompasses the current one + if( itnew->second->start <= it->second->start && itnew->second->end >= it->second->end ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + + // if 16bit, then check for half encompassing targets + if( bCheckHalfCovering && itnew->second->start > it->second->start && itnew->second->start < it->second->end && itnew->second->end <= it->second->end+0x2000 ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // first search for the target + CRenderTarget* ptarg = NULL; + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + if( g_GameSettings&GAME_PARTIALPOINTERS ) { + // if there is a render target that wholly encompasses this one, then use the pointer directly + // this render target also has to be small (mgs3) + if( frame.fbh <= 0x40 ) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end && (it->second->psm&~1) == (frame.psm&~1) && (it->second->fbp&0xff) == 0 ) { + ptarg = new CRenderTarget(frame, *it->second); + besttarg = it->first; + break; + } + } + } + } + } + + CRenderTarget* pbesttarg = NULL; + + if( besttarg == 0 ) { + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbw == frame.fbw && + // check depth targets only if partialdepth option + (it->second->fbp != frame.fbp|| ((g_GameSettings&GAME_PARTIALDEPTH)&&(opts&CRenderTargetMngr::TO_DepthBuffer))) ) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + pbesttarg = it->second; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAll(start, end, frame.fbw); + } + else if( key == besttarg && pbesttarg != NULL ) { + // add one and store in a different location until best targ is processed + mapTargets.erase(besttarg); + besttarg++; + mapTargets[besttarg] = pbesttarg; + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( it->second != vb[0].prndr && it->second != vb[1].prndr && it->second != vb[0].pdepth && it->second != vb[1].pdepth && + timeGetTime()-it->second->lastused > 5000 ) { + DestroyChildren(it->second); + delete it->second; + mapTargets.erase(it); + } + } + + if( ptarg == NULL ) { + // not found yet, so create + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + DestroyChildren(it->second); + delete it->second; + mapDummyTargs.erase(it); + } + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +void CRenderTargetMngr::DestroyChildren(CRenderTarget* ptarg) +{ + if(ptarg == NULL) + return; + + MAPTARGETS::iterator ittarg = mapTargets.begin(); + while(ittarg != mapTargets.end()) { + if( ittarg->second->pmimicparent == ptarg ) { + assert( ittarg->second != ptarg ); + delete ittarg->second; + ittarg = mapTargets.erase(ittarg); + } + else ++ittarg; + } +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)pClutBuffer & 2) ? 0 : (((u32)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + // memcmp_mmx doesn't work on x86-64 +#ifdef __x86_64__ + if( memcmp(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#else + if( memcmp_mmx(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#endif + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + D3DLOCKED_RECT lock; + assert( ptex != NULL ); + + if( memory != NULL ) { + assert( memory->ptr != NULL ); + lock.pBits = memory->ptr; + } + else { + assert( ptexsys != NULL ); + ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + } + + // memcmp_mmx doesn't work on x86_64 +#ifdef __x86_64__ + int result = memcmp((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#else + int result = memcmp_mmx((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#endif + + if( memory == NULL ) + ptexsys->UnlockRect(0); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end();) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + list::iterator itprev = it; + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { +#ifdef __x86_64__ + if( memcmp(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#else + if( memcmp_mmx(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#endif + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + ++it; + } + +#ifdef _DEBUG + PRIM_LOG("memtarget: tbp: %x tbw: %x th: %x psm: %x\n", tex0.tbp0, tex0.tbw, tex0.th, tex0.psm); +#endif + + // couldn't find so create + HRESULT hr; + CMemoryTarget* targ; + + D3DFORMAT fmt = D3DFMT_A8R8G8B8; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = D3DFMT_A1R5G5B5; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult ) { + + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + + // alloc the mem + while( FAILED(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_DEFAULT, &targ->ptex, NULL)) ) { + + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + printf("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult); + channels = 1; + } + DestroyOldest(); + } + } + + // lock + V(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_SYSTEMMEM, &targ->ptexsys, NULL)); + assert( targ->ptexsys != NULL ); + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + D3DLOCKED_RECT lock; + targ->ptexsys->LockRect(0, &lock, NULL, 0); + + // fill with data + if( PSMT_ISCLUT(tex0.psm) ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + u8* psrc = (u8*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)lock.pBits; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)lock.pBits; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)lock.pBits; + u16* src = (u16*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif + } + else { + if( targ->memory != NULL ) { + // release + if( targ->memory->ref > 0 && --targ->memory->ref <= 0 ) { + SAFE_DELETE(targ->memory); + } + targ->memory = NULL; + } + + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height ); + } + } + + targ->ptexsys->UnlockRect(0); + + V(pd3dDevice->UpdateTexture(targ->ptexsys, targ->ptex)); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + it->second->Release(); + mapTextures.clear(); +} + +LPD3DTEX ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + it->second->Release(); + it = mapTextures.erase(it); + } + else ++it; + } + } + + // create a new tex + LPD3DTEX ptex; + HRESULT hr = S_OK; + V(pd3dDevice->CreateTexture(GPU_TEXMASKWIDTH, 1, 1, 0, D3DFMT_L16, D3DPOOL_MANAGED, &ptex, NULL)); + + D3DLOCKED_RECT lock; + ptex->LockRect(0, &lock, NULL, 0); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) ((u16*)lock.pBits)[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + ptex->UnlockRect(0); + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + // flushes can delete targets! + Flush(0); + Flush(1); + + listTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) || ptarg->targoffx != 0 || ptarg->targoffy != 0) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +// need to take into account left over data of 24bit transfers (always <= 5) +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].dwCount > 0 ) + Flush(0); + if( vb[1].dwCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].dwCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].dwCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //printf("zerogs: resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) printf("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// printf("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + if( (gs.imageWnew&widthlimit)!=0 ) break; \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)locksrc.pBits; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = locksrc.Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + ##frame##SwizzleBlock##blockbits##(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + LPD3DTEX pTexture; + pd3dDevice->CreateTexture(ptex->tw, ptex->th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTexture, NULL); + + D3DLOCKED_RECT lockdst; + pTexture->LockRect(0, &lockdst, NULL, 0); + + DWORD* dst = (DWORD*)lockdst.pBits; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 1); + assert( pmemtarg != NULL ); + D3DLOCKED_RECT lock; + HRESULT hr = pmemtarg->ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + if( FAILED(hr) ) + return; + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = (u8*)lock.pBits - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + + dst += lockdst.Pitch/4 - ptex->tw; + } + + pTexture->UnlockRect(0); + + if( usevid ) { + pmemtarg->ptexsys->UnlockRect(0); + } + + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pTexture, NULL); + + SAFE_RELEASE(pTexture); + +} + +} diff --git a/plugins/gs/zerogs/dx/targets.h b/plugins/gs/zerogs/dx/targets.h new file mode 100644 index 0000000000..522019d914 --- /dev/null +++ b/plugins/gs/zerogs/dx/targets.h @@ -0,0 +1,232 @@ +#define TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS +{ + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, DWORD Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + virtual void DestroyChildren(CRenderTarget* ptarg); + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyTarg(CRenderTarget* ptarg) { + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + DestroyChildren(ptarg); + delete ptarg; + } + + inline void DestroyAll(int start, int end, int fbw) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + it = mapTargets.erase(it); + } + else ++it; + } + } + + inline void DestroyIntersecting(CRenderTarget* prndr) + { + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + + it = mapTargets.erase(it); + } + else ++it; + } + } + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline LPD3DTEX GetTex(u32 bitvalue, LPD3DTEX ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + LPD3DTEX GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/gs/zerogs/dx/x86-32.asm b/plugins/gs/zerogs/dx/x86-32.asm new file mode 100644 index 0000000000..1c55682057 --- /dev/null +++ b/plugins/gs/zerogs/dx/x86-32.asm @@ -0,0 +1,1353 @@ +; Copyright (C) 2003-2005 Gabest +; http://www.gabest.org +; +; This Program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2, or (at your option) +; any later version. +; +; This Program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http://www.gnu.org/copyleft/gpl.html +; +; + .686 + .model flat + .mmx + .xmm + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; memsetd +; + +@memsetd@12 proc public + + push edi + + mov edi, ecx + mov eax, edx + mov ecx, [esp+4+4] + cld + rep stosd + + pop edi + + ret 4 + +@memsetd@12 endp + +; +; SaturateColor +; + +@SaturateColor_sse2@4 proc public + + pxor xmm0, xmm0 + movdqa xmm1, [ecx] + packssdw xmm1, xmm0 + packuswb xmm1, xmm0 + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + movdqa [ecx], xmm1 + + ret + +@SaturateColor_sse2@4 endp + +@SaturateColor_asm@4 proc public + + push esi + + mov esi, ecx + + xor eax, eax + mov edx, 000000ffh + + mov ecx, [esi] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi], ecx + + mov ecx, [esi+4] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+4], ecx + + mov ecx, [esi+8] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+8], ecx + + mov ecx, [esi+12] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+12], ecx + + pop esi + + ret + +@SaturateColor_asm@4 endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknb macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +; +; unSwizzleBlock32 +; + +@unSwizzleBlock32_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + lea eax, [ebx*2] + add eax, ebx + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + lea edx, [edx+ebx*4] + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + pop ebx + + ret 4 + +@unSwizzleBlock32_sse2@12 endp + +; +; unSwizzleBlock16 +; + +@unSwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck dq, 0, 4, 2, 6, 1, 3 + punpck wd, 0, 4, 1, 3, 2, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock16_sse2@12 endp + +; +; unSwizzleBlock8 +; + +@unSwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm5, [ecx+16*3] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm5, [ecx+16*7] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8_sse2@12 endp + +; +; unSwizzleBlock4 +; + +@unSwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4_sse2@12 endp + +; +; unSwizzleBlock8HP +; + +@unSwizzleBlock8HP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8HP_sse2@12 endp + +; +; unSwizzleBlock4HLP +; + +@unSwizzleBlock4HLP_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + pand xmm0, xmm7 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HLP_sse2@12 endp + +; +; unSwizzleBlock4HHP +; + +@unSwizzleBlock4HHP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 28 + psrld xmm2, 28 + psrld xmm4, 28 + psrld xmm6, 28 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HHP_sse2@12 endp + +; +; unSwizzleBlock4P +; + +@unSwizzleBlock4P_sse2@12 proc public + + push esi + push edi + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov esi, [esp+4+8] + lea edi, [esi*2] + add edi, esi + + ; col 0 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 1 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 2 + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 3 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + ; lea edx, [edx+esi*4] + + pop edi + pop esi + + ret 4 + +@unSwizzleBlock4P_sse2@12 endp + +; +; swizzling +; + +; +; SwizzleBlock32 +; + +@SwizzleBlock32_sse2@16 proc public + + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movntps [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movntps [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movntps [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32_sse2@16 endp + +; +; SwizzleBlock16 +; + +@SwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [edx] + movdqa xmm1, [edx+16] + movdqa xmm2, [edx+ebx] + movdqa xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16_sse2@12 endp + +; +; SwizzleBlock8 +; + +@SwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + pshufd xmm1, [edx], 0b1h + pshufd xmm3, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [edx], 0b1h + pshufd xmm2, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8_sse2@12 endp + +; +; SwizzleBlock4 +; + +@SwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4_sse2@12 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u +; + +@SwizzleBlock32u_sse2@16 proc public + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32u_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32u_sse2@16 endp + +; +; SwizzleBlock16u +; + +@SwizzleBlock16u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqu xmm0, [edx] + movdqu xmm1, [edx+16] + movdqu xmm2, [edx+ebx] + movdqu xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16u_sse2@12 endp + +; +; SwizzleBlock8u +; + +@SwizzleBlock8u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8u_sse2@12 endp + +; +; SwizzleBlock4u +; + +@SwizzleBlock4u_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4u_sse2@12 endp + + end \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/x86-64.asm b/plugins/gs/zerogs/dx/x86-64.asm new file mode 100644 index 0000000000..430960809f --- /dev/null +++ b/plugins/gs/zerogs/dx/x86-64.asm @@ -0,0 +1,1090 @@ +; Copyright (C) 2003-2005 Gabest/zerofrog +; http:;;www.gabest.org +; +; This Program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2, or (at your option) +; any later version. +; +; This Program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http:;;www.gnu.org/copyleft/gpl.html +; +; +extern s_clut16mask:ptr + + .code + +; mmx memcpy implementation, size has to be a multiple of 8 +; returns 0 is equal, nonzero value if not equal +; ~10 times faster than standard memcmp +; (zerofrog) +; u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +; rcx - src1 +; rdx - src2 +; r8d - cmpsize +memcmp_mmx proc public + cmp r8d, 32 + jl Done4 + + ; custom test first 8 to make sure things are ok + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + movq mm2, [rdx+16] + pmovmskb eax, mm0 + movq mm3, [rdx+24] + + ; check if eq + cmp eax, 0ffh + je NextComp + mov eax, 1 + jmp Finish + +NextComp: + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je ContinueTest + mov eax, 1 + jmp Finish + + cmp r8d, 64 + jl Done8 + +Cmp8: + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pcmpeqd mm4, [rcx+32] + pand mm0, mm2 + pcmpeqd mm5, [rcx+40] + pand mm0, mm3 + pcmpeqd mm6, [rcx+48] + pand mm0, mm4 + pcmpeqd mm7, [rcx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Continue + mov eax, 1 + jmp Finish + +Continue: + sub r8d, 64 + add rdx, 64 + add rcx, 64 +ContinueTest: + cmp r8d, 64 + jge Cmp8 + +Done8: + test r8d, 020h + jz Done4 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je Done4 + mov eax, 1 + jmp Finish + +Done4: + cmp r8d, 24 + jne Done2 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done2: + cmp r8d, 16 + jne Done1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done1: + cmp r8d, 8 + jne Done + + mov eax, [rdx] + mov rdx, [rdx+4] + cmp eax, [rcx] + je Next + mov eax, 1 + jmp Finish + +Next: + cmp rdx, [rcx+4] + je Done + mov eax, 1 + jmp Finish + +Done: + xor eax, eax + +Finish: + emms + ret + +memcmp_mmx endp + +; TestClutChangeMMX +; mov rdx, dst +; mov rcx, src +; mov r8d, entries +TestClutChangeMMX proc public + +Start: + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+16] + + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm2, [rcx+32] + pcmpeqd mm3, [rcx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [rdx+32] + movq mm5, [rdx+40] + pcmpeqd mm4, [rcx+8] + pcmpeqd mm5, [rcx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm6, [rcx+40] + pcmpeqd mm7, [rcx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0ffh + je Continue + mov byte ptr [r9], 1 + jmp Return + +Continue: + cmp r8d, 16 + jle Return + + test r8d, 010h + jz AddRcx + sub rcx, 448 ; go back and down one column, +AddRcx: + add rcx, 256 ; go to the right block + + + jne Continue1 + add rcx, 256 ; skip whole block +Continue1: + add rdx, 64 + sub r8d, 16 + jmp Start + +Return: + emms + ret + +TestClutChangeMMX endp + +UnswizzleZ16Target proc public + pxor xmm7, xmm7 + +Z16Loop: + ;; unpack 64 bytes at a time + movdqa xmm0, [rdx] + movdqa xmm2, [rdx+16] + movdqa xmm4, [rdx+32] + movdqa xmm6, [rdx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + ;; start saving + movdqa [rcx], xmm0 + movdqa [rcx+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [rcx+32], xmm2 + movdqa [rcx+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [rcx+64], xmm4 + movdqa [rcx+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [rcx+96], xmm6 + movdqa [rcx+112], xmm0 + + add rdx, 64 + add rcx, 128 + sub r9d, 1 + jne Z16Loop + + ret +UnswizzleZ16Target endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknbl macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +punpcknbh macro + + movdqa xmm12, xmm8 + pshufd xmm13, xmm9, 0e4h + + psllq xmm9, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm8, xmm15 + pandn xmm14, xmm9 + por xmm8, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm9, xmm12 + + movdqa xmm12, xmm10 + pshufd xmm13, xmm11, 0e4h + + psllq xmm11, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm10, xmm15 + pandn xmm14, xmm11 + por xmm10, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm11, xmm12 + + punpck bw, 8, 10, 9, 11, 12, 14 + + endm + +; +; SwizzleBlock32_sse2 +; + +SwizzleBlock32_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2 endp + +; +; SwizzleBlock16_sse2 +; + +SwizzleBlock16_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm1, [rsi+16] + movdqa xmm2, [rsi+r8] + movdqa xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16_sse2 endp + +; +; SwizzleBlock8 +; + +SwizzleBlock8_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8_sse2 endp + +; +; SwizzleBlock4 +; + +SwizzleBlock4_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4_sse2 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u_sse2 +; + +SwizzleBlock32u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2 endp + +; +; SwizzleBlock16u_sse2 +; + +SwizzleBlock16u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm1, [rsi+16] + movdqu xmm2, [rsi+r8] + movdqu xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16u_sse2 endp + +; +; SwizzleBlock8u +; + +SwizzleBlock8u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, xmm0, 0b1h + pshufd xmm3, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8u_sse2 endp + +; +; SwizzleBlock4u +; + +SwizzleBlock4u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4u_sse2 endp + +WriteCLUT_T16_I4_CSM1_sse2 proc public + movdqa xmm0, XMMWORD PTR [rcx] + movdqa xmm1, XMMWORD PTR [rcx+16] + movdqa xmm2, XMMWORD PTR [rcx+32] + movdqa xmm3, XMMWORD PTR [rcx+48] + + ;; rearrange + pshuflw xmm0, xmm0, 088h + pshufhw xmm0, xmm0, 088h + pshuflw xmm1, xmm1, 088h + pshufhw xmm1, xmm1, 088h + pshuflw xmm2, xmm2, 088h + pshufhw xmm2, xmm2, 088h + pshuflw xmm3, xmm3, 088h + pshufhw xmm3, xmm3, 088h + + shufps xmm0, xmm1, 088h + shufps xmm2, xmm3, 088h + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + + pxor xmm6, xmm6 + mov rax, offset s_clut16mask + + test rdx, 15 + jnz WriteUnaligned + + movdqa xmm7, XMMWORD PTR [rax] ;; saves upper 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + ;; rdx is offset by 2 + sub rdx, 2 + + movdqa xmm7, XMMWORD PTR [rax+16] ;; saves lower 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +WriteCLUT_T16_I4_CSM1_sse2 endp + +end \ No newline at end of file diff --git a/plugins/gs/zerogs/dx/x86.cpp b/plugins/gs/zerogs/dx/x86.cpp new file mode 100644 index 0000000000..b99578715f --- /dev/null +++ b/plugins/gs/zerogs/dx/x86.cpp @@ -0,0 +1,573 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask)) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void FASTCALL(FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void FASTCALL(FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void FASTCALL(Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void FASTCALL(Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void FASTCALL(Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void FASTCALL(Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut)) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut)) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/gs/zerogs/dx/x86.h b/plugins/gs/zerogs/dx/x86.h new file mode 100644 index 0000000000..6859c1a313 --- /dev/null +++ b/plugins/gs/zerogs/dx/x86.h @@ -0,0 +1,184 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include +#include +#include "GS.h" + +extern "C" void FASTCALL(SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch)); + +// frame swizzling + +// no AA +extern "C" void FASTCALL(FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern "C" void FASTCALL(FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern "C" void FASTCALL(FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)); + +// no AA +extern void FASTCALL(FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern void FASTCALL(FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern void FASTCALL(FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch)); + +extern "C" void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)); + +extern void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/gs/zerogs/dx/zerogs.cpp b/plugins/gs/zerogs/dx/zerogs.cpp new file mode 100644 index 0000000000..9cd662ceed --- /dev/null +++ b/plugins/gs/zerogs/dx/zerogs.cpp @@ -0,0 +1,5064 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "zerogsshaders/zerogsshaders.h" +#include "targets.h" + +#define DEBUG_PS2 0 + +#define POINT_BUFFERFLUSH 512 +#define POINT_BUFFERSIZE (1<<18) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +static LPDIRECT3D9 pD3D = NULL; // Used to create the D3DDevice +LPDIRECT3DDEVICE9 pd3dDevice = NULL; +static DXVEC4 s_vznorm; +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char revision, build, minor; + +BOOL g_bDisplayMsg = 1; + +extern HINSTANCE hInst; + +BOOL g_bSaveFlushedFrame = 1; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; +int g_MaxRenderedHeight = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bWriteProfile 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bUpdateStencil 1 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bWriteProfile = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) +BOOL g_bSaveResolved = 0; + +#endif + +#define DRAW() pd3dDevice->DrawPrimitive(primtype[curvb.curprim.prim], 0, curvb.dwCount) + +extern int s_frameskipping; + +//inline void SetRenderTarget_(int index, LPD3DSURF psurf, int counter, const char* pname) +//{ +// static LPD3DSURF ptargs[4] = {NULL}; +// static int counters[4] = {0}; +// static const char* pnames[4] = {NULL}; +// +// if( ptargs[index] == psurf && psurf != NULL ) +// printf("duplicate targets\n"); +// pd3dDevice->SetRenderTarget(index, psurf); +// ptargs[index] = psurf; +// counters[index] = counter; +// pnames[index] = pname; +//} +// +//#define SetRenderTarget(index, psurf) SetRenderTarget_(index, psurf, __COUNTER__, __FUNCTION__) + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; + +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; +static LPD3DSURF s_ptexAVICapture = NULL; // system memory texture + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +inline DWORD FtoDW(float f) { return (*((DWORD*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// Consts +static const D3DPRIMITIVETYPE primtype[8] = { D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_FORCE_DWORD }; +static const DWORD blendalpha[3] = { D3DBLEND_SRCALPHA, D3DBLEND_DESTALPHA, D3DBLEND_BLENDFACTOR }; +static const DWORD blendinvalpha[3] = { D3DBLEND_INVSRCALPHA, D3DBLEND_INVDESTALPHA, D3DBLEND_INVBLENDFACTOR }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const DWORD g_dwAlphaCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_LESSEQUAL, + D3DCMP_EQUAL, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL }; + +// used for afail case +static const DWORD g_dwReverseAlphaCmp[] = { D3DCMP_ALWAYS, D3DCMP_NEVER, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, + D3DCMP_NOTEQUAL, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL }; + +static const DWORD g_dwZCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_GREATEREQUAL, D3DCMP_GREATER }; + +///////////////////// +// graphics resources +static LPD3DDECL pdecl = NULL; +static LPD3DVS pvs[16] = {NULL}; +static LPD3DPS ppsRegular[4] = {NULL}, ppsTexture[NUM_SHADERS] = {NULL}; +static LPD3DPS ppsCRTC[2] = {NULL}, ppsCRTC24[2] = {NULL}, ppsCRTCTarg[2] = {NULL}; + +int g_nPixelShaderVer = SHADER_30; // default + +static BYTE* s_lpShaderResources = NULL; +static map mapShaderResources; + +LPD3DTEX s_ptexCurSet[2] = {NULL}; + +#define s_bForceTexFlush 1 +static LPD3DTEX s_ptexNextSet[2] = {NULL}; + +static ID3DXFont* pFont = NULL; +static ID3DXSprite* pSprite = NULL; + +static LPD3DSURF psurfOrgTarg = NULL, psurfOrgDepth = NULL; + +LPD3DTEX ptexBlocks = NULL, ptexConv16to32 = NULL; // holds information on block tiling +LPD3DTEX ptexBilinearBlocks = NULL; +IDirect3DVolumeTexture9* ptexConv32to16 = NULL; +static LPD3DTEX s_ptexInterlace = NULL; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static list s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static LPD3DTEX ptexLogo = NULL; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static DWORD dwStencilRef, dwStencilMask; + +static DXVEC4 vAlphaBlendColor; // used for GPU_COLOR + +static BYTE bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static DWORD s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + BYTE _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + BYTE _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + BYTE _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + BYTE _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static BOOL s_bAlphaSet = FALSE; +static alphaInfo s_alphaInfo; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + LONG width, height; + u8* g_pbyGSMemory = NULL; // 4Mb GS system mem + u8* g_pbyGSClut = NULL; + + D3DPRESENT_PARAMETERS d3dpp; + + BYTE s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + BYTE bIndepWriteMasks = 1; + BOOL s_bBeginScene = FALSE; + D3DFORMAT g_RenderFormat = D3DFMT_A16B16G16R16F; + int icurctx = -1; + + LPD3DVB pvbRect = NULL; + + DXVEC4 g_vdepth = DXVEC4(65536.0f, 256.0f, 1.0f, 65536.0f*256.0f); + + LPD3DVS pvsBitBlt = NULL, pvsBitBlt30 = NULL; + LPD3DPS ppsBitBlt[2] = {NULL}, ppsBitBltDepth[2] = {NULL}, ppsBitBltDepthTex[2] = {NULL}, ppsOne = NULL; + LPD3DPS ppsBaseTexture = NULL, ppsConvert16to32 = NULL, ppsConvert32to16 = NULL; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + HRESULT LoadEffects(); + HRESULT LoadExtraEffects(); + LPD3DPS LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, DWORD dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + DWORD dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + inline void SetContextTarget(int context); + + // use to update the d3d state + void SetTexVariables(int context); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb); + __forceinline void RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb); + __forceinline void ProcessFBA(const VB& curvb); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + inline LPD3DTEX CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != NULL ) return s_ptexInterlace; + + SAFE_RELEASE(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + HRESULT hr; + V(pd3dDevice->CreateTexture(width, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_ptexInterlace, NULL)); + + D3DLOCKED_RECT lock; + s_ptexInterlace->LockRect(0, &lock, NULL, 0); + for(int i = 0; i < width; ++i) ((u32*)lock.pBits)[i] = (i&1) ? 0xffffffff : 0; + s_ptexInterlace->UnlockRect(0); + + return s_ptexInterlace; + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, sizeof(VB)); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + Unlock(); + SAFE_RELEASE(pvb); + + prndr = NULL; + pdepth = NULL; +} + +void ZeroGS::VB::Lock() +{ + assert(pvb != NULL); + if( pbuf == NULL ) + { + if( dwCurOff+POINT_BUFFERFLUSH > POINT_BUFFERSIZE ) dwCurOff = 0; + + pvb->Lock(dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)*POINT_BUFFERFLUSH, (void**)&pbuf, dwCurOff ? D3DLOCK_NOOVERWRITE|D3DLOCK_NOSYSLOCK : D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK); + dwCount = 0; + assert( pbuf != NULL ); + } +} + +bool ZeroGS::VB::CheckPrim() +{ + Lock(); + + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return dwCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + // invalid bpp + if( m_Blocks[gsfb.psm].bpp == 0 ) { + ERROR_LOG("CheckFrame invalid bpp %d\n", gsfb.psm); + return; + } + + bChanged = 0; + + if( gsfb.fbw <= 0 ) { + return; + } + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) + maxpos *= 2; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? alteir aris crashes without it + if( maxpos > 256 ) + maxpos &= ~0x1f; + } + else { + ERROR_LOG("render target null, ignoring\n"); + //prndr = NULL; + //pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; + if( frame.fbw > 1024 ) + frame.fbw = 1024; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback + if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { + int considerheight = (g_MaxRenderedHeight/8+31)&~31; + if( frame.fbh > considerheight ) + frame.fbh = considerheight; + else if( frame.fbh <= 32 ) + frame.fbh = considerheight; + + if( frame.fbh == considerheight ) { + // stops bad resolves (mgs3) + if( !curprim.abe && (!test.ate || test.atst == 0) ) + s_nResolved |= 0x100; + } + } + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAll(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->targheight; + if( zbuf.psm == 0x31 ) tempfb.fbm = 0xff000000; + else tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// printf("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + prndr->targheight);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->targheight ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh *= 2; + prndr->targheight *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh /= 2; + prndr->targheight /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), prndr->fbh);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + s_nResolved &= 0xff; // restore + + if( prndr != NULL ) + SetContextTarget(ictx); + + //if( prndr != NULL && ictx == icurctx) + //else bVarsSetTarg = 0; + +// if( prndr != NULL && bChanged ) { +// if( ictx == icurctx ) SetContextTarget(icurctx); +// else +// bVarsSetTarg = 0; +// } +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +HRESULT ZeroGS::Create(LONG _width, LONG _height) +{ + Destroy(1); + GSStateReset(); + + width = _width; + height = _height; + fiRendWidth = 1.0f / width; + fiRendHeight = 1.0f / height; + + HRESULT hr; + + if( NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) { + ERROR_LOG(_T("Failed to create the direct3d interface.")); + return E_FAIL; + } + + D3DDISPLAYMODE d3ddm; + if( FAILED( hr = pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) { + ERROR_LOG(_T("Error geting default adapter.")); + return hr; + } + + if( conf.options & GSOPTION_FULLSCREEN ) { + // choose best mode +// RECT rcdesktop; +// GetWindowRect(GetDesktopWindow(), &rcdesktop); +// width = rcdesktop.right - rcdesktop.left; +// height = rcdesktop.bottom - rcdesktop.top; + +// width = height = 0; +// D3DDISPLAYMODE d3ddmtemp; +// +// int modes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, d3ddm.Format); +// for(int i= 0; i < modes; ++i) { +// pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, d3ddm.Format, i, &d3ddmtemp); +// +// if( abs(1024-(int)d3ddmtemp.Width) <= abs(1280-width) && abs(768-(int)d3ddmtemp.Height) <= abs(1024-height) ) { +// width = d3ddmtemp.Width; +// height = d3ddmtemp.Height; +// } +// } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + // Set up the structure used to create the D3DDevice. Since we are now + // using more complex geometry, we will create a device with a zbuffer. + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = !(conf.options & GSOPTION_FULLSCREEN); + d3dpp.hDeviceWindow = GShwnd; + d3dpp.SwapEffect = (conf.options & GSOPTION_FULLSCREEN) ? D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//(conf.options & GSOPTION_FULLSCREEN) ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Flags = DEBUG_PS2 ? D3DPRESENTFLAG_LOCKABLE_BACKBUFFER : 0; + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + + // Create the D3DDevice + UINT adapter = D3DADAPTER_DEFAULT; + D3DDEVTYPE devtype = !DEBUG_PS2 ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; + +#ifndef _DEBUG + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE; +#else + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING; +#endif + +#ifndef RELEASE_TO_PUBLIC + for(UINT i = 0; i < pD3D->GetAdapterCount(); ++i) { + D3DADAPTER_IDENTIFIER9 id; + HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &id); + if( strcmp(id.Description, "NVIDIA NVPerfHUD") == 0 ) { + printf("Using %s adapter\n", id.Description); + adapter = i; + devtype = D3DDEVTYPE_REF; + break; + } + } +#endif + + if( FAILED( hr = pD3D->CreateDevice( adapter, devtype, GShwnd, + !DEBUG_PS2 ? hwoptions : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create hardware device, creating software.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create software device, switching to reference rasterizer.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + return hr; + } + } + + // get caps and check if gfx card is ok + D3DCAPS9 caps; + pd3dDevice->GetDeviceCaps(&caps); + + if( caps.VertexShaderVersion < D3DVS_VERSION(2,0) ) { + ERROR_LOG("*********\nGS ERROR: Need at least vs2.0\n*********\n"); + Destroy(1); + return E_FAIL; + } + + conf.mrtdepth = 1; + + if( caps.NumSimultaneousRTs == 1 ) { + ERROR_LOG("*********\nGS WARNING: Need at least 2 simultaneous render targets. Some zbuffer effects will look wrong\n*********\n"); + conf.mrtdepth = 0; + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) ) { + ERROR_LOG("*********\nGS ERROR: Need separate alpha blending! Some effects will look bad\n*********\n"); + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) ) { + ERROR_LOG("******\nGS WARNING: Need independent write masks! Some z buffer effects might look bad\n*********\n"); + bIndepWriteMasks = 0; + } + + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) ) { + ERROR_LOG("******\nGS WARNING: Need MRT Post Pixel Shader Blending for some effects\n*********\n"); + } + + hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, + D3DUSAGE_RENDERTARGET|D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, g_RenderFormat); + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormat = D3DFMT_A8R8G8B8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else if( FAILED(hr) ) { + ERROR_LOG("******\nGS ERROR: Device doesn't support alpha blending for 16bit floating point targets.\nQuality will reduce.\n*********\n"); + g_RenderFormat = D3DFMT_A8R8G8B8; + } + +// hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_G32R32F); +// +// if( FAILED(hr) ) { +// ERROR_LOG("******\nGS ERROR: Device doesn't support G32R32F textures.\nTextures will look bad.\n*********\n"); +// } + + g_MaxTexWidth = caps.MaxTextureWidth; + g_MaxTexHeight = caps.MaxTextureHeight; + GPU_TEXWIDTH = caps.MaxTextureWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + + //g_RenderFormat = D3DFMT_A8R8G8B8; + + pd3dDevice->GetRenderTarget(0, &psurfOrgTarg); + pd3dDevice->GetDepthStencilSurface(&psurfOrgDepth); + + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_LIGHTING, FALSE); + SETRS(D3DRS_SPECULARENABLE, FALSE); + + V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + "Arial", &pFont ) ); + + // create the vertex decl + const D3DVERTEXELEMENT9 Decl[] = { + { 0, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() }; + V_RETURN(pd3dDevice->CreateVertexDeclaration(Decl, &pdecl)); + +#ifdef RELEASE_TO_PUBLIC + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (BYTE*)LockResource(hShaderGlob); +#endif + + // load the effect + ERROR_LOG("Creating effects\n"); + V_RETURN(LoadEffects()); + + g_bDisplayMsg = 0; + if( caps.VertexShaderVersion >= D3DVS_VERSION(3,0) && caps.PixelShaderVersion >= D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_30; + else if( caps.PixelShaderVersion == D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_20; + else + g_nPixelShaderVer = SHADER_20a; + +#ifdef RELEASE_TO_PUBLIC + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + if( g_nPixelShaderVer != SHADER_30 ) { + // test more + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + g_nPixelShaderVer = SHADER_20b; + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + + g_nPixelShaderVer = SHADER_20; + if( LoadShadeEffect(0, 0, 1, 1, 0, temp, 0) == NULL ) { + + ERROR_LOG("*********\nGS ERROR: Need at least ps2.0 (ps2.0a+ recommended)\n*********\n"); + Destroy(1); + return E_FAIL; + } + } + } + } +#endif + + // set global shader constants + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f), 1); // g_fExactColor + pd3dDevice->SetPixelShaderConstantF(28, DXVEC4(-0.7f, -0.65f, 0.9f,0), 1); // g_fBilinear + pd3dDevice->SetPixelShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetPixelShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetPixelShaderConstantF(31, DXVEC4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f), 1); // g_fMult + + pd3dDevice->SetVertexShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetVertexShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetVertexShaderConstantF(31, DXVEC4(0.5f, -0.5f, 0.5f, 0.5f + 0.4f/416.0f), 1); // g_fBitBltTrans + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + V_RETURN(LoadExtraEffects()); + + ERROR_LOG("GS Using pixel shaders %s\n", g_pShaders[g_nPixelShaderVer]); + + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0, 1, 0); + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + + return S_OK; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + DeleteDeviceObjects(); + + vb[0].Destroy(); + vb[1].Destroy(); + + for(int i = 0; i < ARRAYSIZE(pvs); ++i) { + SAFE_RELEASE(pvs[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsRegular); ++i) { + SAFE_RELEASE(ppsRegular[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + + SAFE_RELEASE(pvsBitBlt); + SAFE_RELEASE(pvsBitBlt30); + SAFE_RELEASE(ppsBitBlt[0]); SAFE_RELEASE(ppsBitBlt[1]); + SAFE_RELEASE(ppsBitBltDepth[0]); SAFE_RELEASE(ppsBitBltDepth[1]); + SAFE_RELEASE(ppsBitBltDepthTex[0]); SAFE_RELEASE(ppsBitBltDepthTex[1]); + SAFE_RELEASE(ppsCRTCTarg[0]); SAFE_RELEASE(ppsCRTCTarg[1]); + SAFE_RELEASE(ppsCRTC[0]); SAFE_RELEASE(ppsCRTC[1]); + SAFE_RELEASE(ppsCRTC24[0]); SAFE_RELEASE(ppsCRTC24[1]); + SAFE_RELEASE(ppsOne); + + SAFE_RELEASE(pdecl); + SAFE_RELEASE(pFont); + SAFE_RELEASE(psurfOrgTarg); + SAFE_RELEASE(psurfOrgDepth); + + if( bD3D ) { + SAFE_RELEASE(pd3dDevice); + SAFE_RELEASE(pD3D); + } +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + LPD3DVB pvb = vb[i].pvb; + if( pvb != NULL ) pvb->AddRef(); + vb[i].Destroy(); + memset(&vb[i], 0, sizeof(VB)); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].pvb = pvb; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; + s_bAlphaSet = FALSE; +} + +void ZeroGS::AddMessage(const char* pstr, DWORD ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + width = nNewWidth > 16 ? nNewWidth : 16; + height = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = width, oldheight = height; + if( FAILED(Create(nNewWidth&~7, nNewHeight&~7)) ) { + printf("Failed to recreate, changing to old\n"); + if( FAILED(Create(oldwidth, oldheight)) ) { + MessageBox(NULL, "failed to create dev, exiting...\n", "Error", MB_OK); + exit(0); + } + } + + if( FAILED(InitDeviceObjects()) ) { + MessageBox(NULL, "failed to init dev objs, exiting...\n", "Error", MB_OK); + exit(0); + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); + } + + vb[0].Lock(); + vb[1].Lock(); + + assert( vb[0].pbuf != NULL && vb[1].pbuf != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = s_AAy = 0; + if( mode > 0 ) { + s_AAx = (mode+1) / 2; + s_AAy = mode / 2; + } + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + float f = mode > 0 ? 2.0f : 1.0f; + SETRS(D3DRS_POINTSIZE, FtoDW(f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, ptr) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + hr = pd3dDevice->CreateVertexShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + printf("errors 0x%x for %d, failed.. try updating your drivers or dx\n", hr, Index); \ + return E_FAIL; \ + } \ +} \ + +#define LOAD_PS(index, ptr) { \ + assert( mapShaderResources.find(index) != mapShaderResources.end() ); \ + header = mapShaderResources[index]; \ + hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + printf("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, index); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + DWORD num = *(DWORD*)s_lpShaderResources; + SHADERHEADER* header = (SHADERHEADER*)((BYTE*)s_lpShaderResources + 4); + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +// called +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + + SHADERHEADER* header; + + DWORD mask = g_nPixelShaderVer == SHADER_30 ? SH_30 : 0; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i]|mask, pvs[2*i]); + LOAD_VS(vsshaders[i]|mask|SH_CONTEXT1, pvs[2*i+1]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt); + //LOAD_VS(SH_BITBLTVS|SH_30, pvsBitBlt30); + + LOAD_PS(SH_REGULARPS|mask, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS|mask, ppsRegular[1]); + LOAD_PS(SH_REGULARPS|SH_WRITEDEPTH|mask, ppsRegular[2]); + LOAD_PS(SH_REGULARFOGPS|SH_WRITEDEPTH|mask, ppsRegular[3]); + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth[0]); LOAD_PS(SH_BITBLTDEPTHMRTPS, ppsBitBltDepth[1]); + LOAD_PS(SH_BITBLTDEPTHTEXPS, ppsBitBltDepthTex[0]); LOAD_PS(SH_BITBLTDEPTHTEXMRTPS, ppsBitBltDepthTex[1]); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS|mask, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer == SHADER_20 ) + texfilter = 0; + if(g_nPixelShaderVer == SHADER_20 ) + exactcolor = 0; + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAYSIZE(ppsTexture) ); + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + index += NUM_SHADERS*g_nPixelShaderVer; + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) printf("%d %d\n", index%NUM_SHADERS, g_nPixelShaderVer); + assert( header != NULL ); + HRESULT hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + header->offset), pps); + + if( SUCCEEDED(hr) ) + return *pps; + + if( g_bDisplayMsg ) + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", 3, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +//#define EFFECT_NAME "f:\\ps2dev\\pcsx2\\zerogs\\dx\\" +#define EFFECT_NAME ".\\" +#define COMPILE_SHADER(name, type, flags) + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", EFFECT_NAME, context); + pfilename = strfile; + } + else if( strstr(pFileName, "\\") == NULL ) { + _snprintf(strfile, 255, "%s%s", EFFECT_NAME, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +#define LOAD_VS(name, ptr, shaderver) { \ + LPD3DXBUFFER pShader, pError; \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shaderver, ShaderFlagsVS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + printf("Failed to load vs %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreateVertexShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ +} \ + +#define LOAD_PS(name, ptr, shmodel) { \ + LPD3DXBUFFER pShader, pError; \ + SAFE_RELEASE(ptr); \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shmodel, ShaderFlagsPS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + printf("Failed to load ps %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreatePixelShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + if( FAILED(hr) || ptr == NULL ) { \ + printf("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, name); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +#define VS_VER (g_nPixelShaderVer == SHADER_20?"vs_2_0":"vs_3_0") +#define PS_VER (g_nPixelShaderVer == SHADER_20?"ps_2_0":"ps_3_0") + +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + DWORD ShaderFlagsPS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + DWORD ShaderFlagsVS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + + ZeroGSShaderInclude inc; + inc.context = 0; + ZeroGSShaderInclude* pInclude = &inc; + + //assert( g_nPixelShaderVer == SHADER_30) ; + const char* pstrps = g_nPixelShaderVer == SHADER_20 ? "ps_2_0" : "ps_2_a"; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + D3DXMACRO macros[2] = {0}; + D3DXMACRO* pmacros = NULL; + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(int i = 0; i < 4; ++i) { + pmacros = NULL; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], VS_VER); + + pmacros = macros; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i+8], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], VS_VER); + } + + inc.context = 0; + pmacros = NULL; + LOAD_PS("RegularPS", ppsRegular[0], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[1], PS_VER); + + pmacros = macros; + LOAD_PS("RegularPS", ppsRegular[2], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[3], PS_VER); + + pmacros = NULL; + LOAD_VS("BitBltVS", pvsBitBlt, "vs_2_0"); + LOAD_PS("BitBltPS", ppsBitBlt[0], pstrps); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], pstrps); + LOAD_PS("BitBltDepthPS", ppsBitBltDepth[0], pstrps); + LOAD_PS("BitBltDepthMRTPS", ppsBitBltDepth[1], pstrps); + LOAD_PS("BitBltDepthTexPS", ppsBitBltDepthTex[0], pstrps); + LOAD_PS("BitBltDepthTexMRTPS", ppsBitBltDepthTex[1], pstrps); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], pstrps); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], pstrps); + LOAD_PS("CRTCPS", ppsCRTC[0], pstrps); LOAD_PS("CRTCInterPS", ppsCRTC[1], pstrps); + LOAD_PS("CRTC24PS", ppsCRTC24[0], pstrps); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], pstrps); + LOAD_PS("ZeroPS", ppsOne, PS_VER); + LOAD_PS("BaseTexturePS", ppsBaseTexture, pstrps); + LOAD_PS("Convert16to32PS", ppsConvert16to32, pstrps); + LOAD_PS("Convert32to16PS", ppsConvert32to16, pstrps); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + ZeroGSShaderInclude inc; + inc.context = context; + + HRESULT hr = LoadShaderFromType(EFFECT_NAME"ps2hw.fx", type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, 0, pd3dDevice, &inc, pps); + + if( SUCCEEDED(hr) ) + return *pps; + + printf("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +HRESULT ZeroGS::InitDeviceObjects() +{ + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + DeleteDeviceObjects(); + + int i; + HRESULT hr; + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + + if( pFont ) V_RETURN( pFont->OnResetDevice() ); + V_RETURN( D3DXCreateSprite( pd3dDevice, &pSprite ) ); + + V(D3DXCreateTextureFromResource(pd3dDevice, hInst, MAKEINTRESOURCE( IDB_ZEROGSLOGO ), &ptexLogo)); + + for(i = 0; i < 2; ++i) + { + V_RETURN(pd3dDevice->CreateVertexBuffer( sizeof(VertexGPU) * POINT_BUFFERSIZE, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vb[i].pvb, NULL)); + } + + // create the blocks texture + D3DFORMAT blockfmt = D3DFMT_R32F; + g_fBlockMult = 1; + + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)) ) { + blockfmt = D3DFMT_G16R16; + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + V_RETURN(pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)); + } + + if( blockfmt == D3DFMT_R32F ) { + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &ptexBilinearBlocks, NULL)) ) { + printf("Failed to create bilinear block texture, fmt = D3DFMT_A32B32G32R32F\n"); + } + } + else ptexBilinearBlocks = NULL; + + // fill a simple rect + V_RETURN(pd3dDevice->CreateVertexBuffer( 4 * sizeof(VertexGPU), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &pvbRect, NULL)); + VertexGPU* pvert; + + pvbRect->Lock(0, 0, (void**)&pvert, 0); + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + pvbRect->Unlock(); + + D3DLOCKED_RECT lock, lockbilinear; + ptexBlocks->LockRect(0, &lock, NULL, 0); + + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->LockRect(0, &lockbilinear, NULL, 0); + + BLOCK::FillBlocks(&lock, ptexBilinearBlocks != NULL ? &lockbilinear : NULL, blockfmt); + + ptexBlocks->UnlockRect(0); + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->UnlockRect(0); + + // create the conversion textures + V_RETURN(pd3dDevice->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv16to32, NULL)); + ptexConv16to32->LockRect(0, &lock, NULL, 0); + assert(lock.Pitch == 256*4); + u32* dst = (u32*)lock.pBits; + for(i = 0; i < 256*256; ++i) { + DWORD tempcol = RGBA16to32(i); + // have to flip r and b + *dst++ = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + ptexConv16to32->UnlockRect(0); + + V_RETURN(pd3dDevice->CreateVolumeTexture(32, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv32to16, NULL)); + D3DLOCKED_BOX lockbox; + ptexConv32to16->LockBox(0, &lockbox, NULL, 0); + dst = (u32*)lockbox.pBits; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + ptexConv32to16->UnlockBox(0); + + // set samplers + for(i = 0; i < 8; ++i) { + pd3dDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); // can be used as a 3d texture + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->SetTexture(SAMP_BLOCKS, ptexBlocks); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + pd3dDevice->SetVertexDeclaration(pdecl); + + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_SCISSORTESTENABLE, 1); + SETRS(D3DRS_SEPARATEALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_CULLMODE, D3DCULL_NONE); + SETRS(D3DRS_BLENDFACTOR, 0x80000000); + SETRS(D3DRS_COLORWRITEENABLE1, 0); + + // points + SETRS(D3DRS_POINTSCALEENABLE, FALSE); + SETRS(D3DRS_POINTSIZE, FtoDW(1.0f)); + + g_nDepthBias = 0; + SETRS(D3DRS_DEPTHBIAS, FtoDW(0.000015f)); + + SETCONSTF(GPU_Z, g_vdepth);//vb[icurctx].zbuf.psm&3]); + + s_vznorm = DXVEC4(g_filog32, 0, 0,0); + SETCONSTF(GPU_ZNORM, s_vznorm); + + return S_OK; +} + +void ZeroGS::DeleteDeviceObjects() +{ + if( s_aviinit ) { + StopCapture(); + STOP_AVI(); + printf("zerogs.avi stopped"); + s_aviinit = 0; + } + + SAFE_RELEASE(s_ptexAVICapture); + + if( pFont ) pFont->OnLostDevice(); + SAFE_RELEASE(pSprite); + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE(s_ptexInterlace); + SAFE_RELEASE(pvbRect); + SAFE_RELEASE(ptexBlocks); + SAFE_RELEASE(ptexBilinearBlocks); + SAFE_RELEASE(ptexConv16to32); + SAFE_RELEASE(ptexConv32to16); + s_bAlphaSet = FALSE; + + vb[0].Unlock(); + SAFE_RELEASE(vb[0].pvb); + + vb[1].Unlock(); + SAFE_RELEASE(vb[1].pvb); +} + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].dwCount > 0 ) +// { +// assert( vb[prim->ctxt].dwCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; + vb[prim->ctxt].Lock(); +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != NULL ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +static int s_PSM8Resolve = 0; +void ZeroGS::Flush(int context) +{ + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.dwCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.dwCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.dwCount = prevcount; + //if( curvb.dwCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.dwCount == 0 ) + return; + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + curvb.Unlock(); + + LPD3DTEX ptexRenderTargetCached = NULL; + int cachedtbp0, cachedtbw, cachedtbh; + + //s_bWriteDepth = TRUE; + + //static int lasttime = 0; + //fprintf(gsLog, "%d: %d\n", g_SaveFrameNum, timeGetTime()-lasttime); + //lasttime = timeGetTime(); + + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + + int tpsm = curvb.tex0.psm; + if( curvb.bNeedTexCheck ) + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + + if( tpsm == PSMT8H && (g_GameSettings&GAME_NOTARGETCLUT) ) { + curvb.dwCount = 0; + return; + } + + // check for the texture before checking the frame (since things could get destroyed) + if( (g_GameSettings&GAME_PARTIALPOINTERS) &&curvb.curprim.tme ) { + +// if( (curvb.gsfb.fbp&0xff) != 0 ) { +// curvb.dwCount = 0; +// return; +// } + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + } + + if( (tpsm&~1) == 0 ) { + CRenderTarget* ptemptarg = s_RTs.GetTarg(tbp0, tbw); + if( ptemptarg != NULL && (ptemptarg->psm&~1) == (tpsm&~1) ) { + ptexRenderTargetCached = ptemptarg->ptex; + ptexRenderTargetCached->AddRef(); + cachedtbp0 = ptemptarg->fbp; + cachedtbw = ptemptarg->fbw; + cachedtbh = ptemptarg->fbh; + } + } + } + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + +// if( g_SaveFrameNum == 976 ) { +// curvb.prndr->ConvertTo32(); +// } + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.dwCount = 0; + SAFE_RELEASE(ptexRenderTargetCached); + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].dwCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + CMemoryTarget* pmemtarg = NULL; + CRenderTarget* ptextarg = NULL; + + // kh2 hack +// if( curvb.dwCount == 2 && curvb.curprim.tme == 0 && curvb.curprim.abe == 0 && (curvb.tex0.tbp0 == 0x2a00 || curvb.tex0.tbp0==0x1d00) ) { +// // skip +// printf("skipping\n"); +// g_SaveFrameNum++; +// curvb.dwCount = 0; +// return; +// } + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme && ptexRenderTargetCached == NULL ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( ptextarg == NULL && tpsm == PSMT8 ) { + // check for targets with half the width + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); + if( ptextarg == NULL ) { + tbp0 &= ~0x7ff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + + if( ptextarg == NULL ) { + // check the next level (mgs3) + tbp0 &= ~0xfff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + } + + if( ptextarg != NULL && ptextarg->start > tbp0*256 ) { + // target beyond range, so ignore + ptextarg = NULL; + } + } + +// if( ptextarg != NULL ) { +// // make sure target isn't invalidated by the ranges +// for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { +// +// int start = itrange->start; +// int end = itrange->end; +// +// // if start and end are in the range or there's a range that is between tbp0 and start, then remove +// if( (start <= tbp0*256 && end > tbp0*256) || (start >= ptextarg->fbp*256 && start <= tbp0*256) ) { +// ptextarg = NULL; +// break; +// } +// } +// } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + // find the equivalent memtarg + if( s_PSM8Resolve == 0 ) { //|| (s_PSM8Resolve > 0 && s_PSM8Resolve+128 < g_SaveFrameNum) ) { + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + if( ptextarg->pmimicparent != NULL ) + ptextarg->pmimicparent->Resolve(); + else + ptextarg->Resolve(); + curvb.dwCount = prevcount; + s_PSM8Resolve = g_SaveFrameNum; // stop from resolving again (once per frame) + } + + tex0Info mytex0 = curvb.tex0; + mytex0.tbp0 = tbp0; + if( ptextarg->pmimicparent != NULL ) { + mytex0.tbp0 = ptextarg->pmimicparent->fbp; + } + pmemtarg = g_MemTargs.GetMemoryTarget(mytex0, 1); + + // have to add an offset to all texture reads + mytex0.tbp0 = tbp0; // change so that SetTexVariablesInt can set the right offsets + + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), mytex0, pmemtarg, s_bForceTexFlush); + curvb.bVarsTexSync = TRUE; + + ptextarg = NULL; // won't be needing this anymore + } + } + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H && tpsm != PSMT8 ) { // handle 8h cluts + // don't support clut targets, read from mem + // 4hl - kh2 check + if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) { // xenosaga requires 2 resolves + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.dwCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + if( ptextarg->pmimicparent != NULL ) { + // if the target is mimic, create the feedback of the parent + assert( ptextarg->pmimicparent->ptex == ptextarg->ptex || ptextarg->pmimicparent->ptexFeedback == ptextarg->ptex ); + SAFE_RELEASE(ptextarg->ptexFeedback); + SAFE_RELEASE(ptextarg->psurfFeedback); + ptextarg->pmimicparent->CreateFeedback(); + ptextarg->ptex = ptextarg->pmimicparent->ptex; + ptextarg->ptexFeedback = ptextarg->pmimicparent->ptexFeedback; ptextarg->ptexFeedback->AddRef(); + ptextarg->psurf = ptextarg->pmimicparent->psurf; + ptextarg->psurfFeedback = ptextarg->pmimicparent->psurfFeedback; ptextarg->psurfFeedback->AddRef(); + } + else + curvb.prndr->CreateFeedback(); + + pd3dDevice->SetRenderTarget(1, (s_bWriteDepth && curvb.pdepth != NULL) ? curvb.pdepth->psurf : NULL); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + D3DXSaveSurfaceToFile(str, D3DXIFF_TGA, curvb.prndr->psurf, NULL, NULL); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + SetTexVariables(context); + if( ptextarg == NULL && pmemtarg == NULL ) { + pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + + icurctx = context; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_ALPHA; + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); // need to always set it since something in this code resets it + + // set the shaders + pd3dDevice->SetVertexShader(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + pd3dDevice->SetStreamSource(0, curvb.pvb, curvb.dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)); + + DWORD dwUsingSpecialTesting = 0; + DWORD dwFilterOpts = 0; + + IDirect3DPixelShader9* pps; + + // need exact if equal or notequal + int exactcolor = 0; + if( g_nPixelShaderVer != SHADER_20 ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + if( curvb.ptexClamp[0] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDX, curvb.ptexClamp[0]); + if( curvb.ptexClamp[1] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDY, curvb.ptexClamp[1]); + + if( ptexRenderTargetCached != NULL ) { + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + assert( !PSMT_ISCLUT(curvb.tex0.psm)); + + pps = LoadShadeEffect(1, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexRenderTargetCached); + s_ptexCurSet[context] = ptexRenderTargetCached; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)cachedtbw; + vTexDims.y = curvb.tex0.th / (float)cachedtbh; + +// u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page +// int blockheight = 32; +// int ycoord = ((curvb.tex0.tbp0-cachedtbp0)/(32*(cachedtbw>>6))) * blockheight; +// int xcoord = (((curvb.tex0.tbp0-cachedtbp0)%(32*(cachedtbw>>6)))) * 2; +//// xcoord += ptextarg->targoffx; +//// ycoord += ptextarg->targoffy; +// vTexDims.z = (float)xcoord / (float)cachedtbw; +// vTexDims.w = (float)ycoord / (float)cachedtbh; + vTexDims.z = vTexDims.w = 0; + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptexRenderTargetCached, NULL); + } + else if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + shadertype = 1; + if( (curvb.tex0.psm == PSMT8 || curvb.tex0.psm == PSMT8H) && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + LPD3DTEX ptexclut = NULL; + pd3dDevice->CreateTexture(256, 1, 1, 0, (curvb.tex0.cpsm&2) ? D3DFMT_A1R5G5B5 : D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexclut, NULL); + if( ptexclut != NULL ) { + + D3DLOCKED_RECT lock; + ptexclut->LockRect(0, &lock, NULL, D3DLOCK_NOSYSLOCK); + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)lock.pBits; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + ptexclut->UnlockRect(0); + + s_vecTempTextures.push_back(ptexclut); + pd3dDevice->SetTexture(SAMP_FINAL, ptexclut); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("clut.tga", D3DXIFF_TGA, ptexclut, NULL); + } + + if( g_nPixelShaderVer != SHADER_20 && (ptextarg->psm & 2) ) { + // 16 bit texture + shadertype = 4; + + DXVEC4 v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 64.0f / (float)ptextarg->fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (g_nPixelShaderVer != SHADER_20 || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + + DXVEC4 v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 64.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0+context, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + LPD3DTEX ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexset); + s_ptexCurSet[context] = ptexset; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)ptextarg->fbw; + vTexDims.y = curvb.tex0.th / (float)ptextarg->targheight; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + xcoord += ptextarg->targoffx; + ycoord += ptextarg->targoffy; + vTexDims.z = (float)xcoord / (float)ptextarg->fbw; + vTexDims.w = (float)ycoord / (float)ptextarg->targheight; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f / (float)ptextarg->fbw; + } + + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// DXVEC4 valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, NULL); + } + else { + // save the texture +#ifdef _DEBUG +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// assert( curvb.pmemtarg == pmemtarg ); +// if( PSMT_ISCLUT(curvb.tex0.psm) ) +// assert( curvb.pmemtarg->ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) SaveTex(&curvb.tex0, 1); + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + } + } + else pps = ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + + pd3dDevice->SetPixelShader(pps); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest) { + SETRS(D3DRS_STENCILENABLE, bCanRenderStencil); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + else SETRS(D3DRS_STENCILENABLE, 0); + + SETRS(D3DRS_ZWRITEENABLE, !curvb.zbuf.zmsk); + SETRS(D3DRS_ZENABLE, curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + if( g_GameSettings & GAME_RELAXEDDEPTH ) + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.00003f):FtoDW(0.0001f)); + else + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + SETRS(D3DRS_ZFUNC, g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + SETRS(D3DRS_ALPHATESTENABLE, curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + + if( curtest.atst == 7 && curtest.aref == 255 ) { + // when it is at the very top, do a less than rather than not equal (gekibo2) + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESS); + SETRS(D3DRS_ALPHAREF, 255); + } + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curtest.aref) : curtest.aref); + } + } + + if( s_bWriteDepth ) { + //pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + if( bIndepWriteMasks ) + SETRS(D3DRS_COLORWRITEENABLE1, !curvb.zbuf.zmsk?0xf:0); + else + pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + SETRS(D3DRS_ALPHABLENDENABLE, 0); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + } + + if( curvb.curprim.abe && bNeedAlphaColor ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + DXVEC4 v = vAlphaBlendColor;// + DXVEC4(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + } + else { + // not using blending so set to defaults + DXVEC4 v = exactcolor ? DXVEC4(1, 510*255.0f/256.0f, 0, 0) : DXVEC4(1,2*255.0f/256.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + dwStencilRef = STENCIL_SPECIAL; + dwStencilMask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + SETRS(D3DRS_ALPHAFUNC, g_dwReverseAlphaCmp[curtest.atst]); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + } + else { + // zbuffer update only + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + DXVEC4 v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + + if( !s_bDestAlphaTest || !bCanRenderStencil ) { + SETRS(D3DRS_STENCILENABLE, FALSE); + } + } + +// IDirect3DQuery9* pOcclusionQuery; +// DWORD numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(DWORD), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_ALPHABLENDENABLE, oldabe); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + //SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + } + + if( dwUsingSpecialTesting ) { + // render the real alpha + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + + DXVEC4 v = DXVEC4(0,exactcolor ? 510.0f : 2.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + DRAW(); + + // don't need to restore + } + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { + char str[255]; + sprintf(str, "frames\\frame%.4d.jpg", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) + D3DXSaveSurfaceToFile(str, D3DXIFF_JPG, curvb.prndr->psurf, NULL, NULL); + } +#endif + + // clamp the final colors, when enabled ffx2 credits mess up + if( curvb.curprim.abe && bAlphaClamping && g_RenderFormat != D3DFMT_A8R8G8B8 && !(g_GameSettings&GAME_NOCOLORCLAMP) ) { // if !colclamp, skip + + ResetAlphaVariables(); + + // if processing the clamping case, make sure can write to the front buffer + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ALPHABLENDENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + pd3dDevice->SetPixelShader(ppsOne); + + // (dest&0x7f)+0x80, blend factor for alpha is always 0x80 + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + + float f; + + if( bAlphaClamping & 1 ) { // min + f = 0; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MAX); + DRAW(); + } + + // bios shows white screen + if( bAlphaClamping & 2 ) { // max + f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MIN); + DRAW(); + } + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + SETRS(D3DRS_ZENABLE, curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes + if( dwFilterOpts & 1 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + if( dwFilterOpts & 2 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } + + // reset used textures + if( shadertype > 2 ) { + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + } + + SETRS(D3DRS_CLIPPLANEENABLE, 0); +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.dwCount+0x100000; +//#endif + curvb.dwCurOff += POINT_BUFFERFLUSH; + SAFE_RELEASE(ptexRenderTargetCached); + + g_MaxRenderedHeight = 0; + curvb.dwCount = 0; + //curvb.Lock(); + curvb.curprim.abe = oldabe; + //if( oldabe ) SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + --s_nWireframeCount; + } + } +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + + RECT rctext; + rctext.left = 25; rctext.top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffffff30); + rctext.top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + + pSprite->End(); + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + if( !s_bBeginScene ) + pd3dDevice->BeginScene(); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + + if( s_bWriteDepth ) + pd3dDevice->SetRenderTarget(1, NULL); + + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + + // play custom animation + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1, 0); + + // tex coords + DXVEC4 v = DXVEC4(1, 1, 0, 0); + SETCONSTF(GPU_BITBLTTEX, v); + SETCONSTF(GPU_BITBLTPOS, v); + + v.x = v.y = v.z = v.w = fAlpha; + SETCONSTF(GPU_ONECOLOR, v); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + pd3dDevice->SetPixelShader(ppsBaseTexture); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptexLogo); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + ProcessMessages(); + + pd3dDevice->EndScene(); + s_bBeginScene = FALSE; + + pd3dDevice->Present(NULL, NULL, NULL, NULL); + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, 1); + + if( icurctx >= 0 ) vb[icurctx].bSyncVars = 0; +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight) +{ + float temp, f; + if( dispwidth * height > dispheight * width ) { + // limited by width + + // change in ratio + f = ((float)width / (float)dispwidth) / ((float)height / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-modf(v.y*height/2+0.05f, &temp))*2.0f/(float)height; + v.w += (1-modf(v.w*height/2+0.05f, &temp))*2.0f/(float)height; + } + else { + // limited by height + f = ((float)height / (float)dispheight) / ((float)width / (float)dispwidth); + f -= modf(f*width, &temp)/(float)width; + v.x *= f; + v.z *= f; + } +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(width, height); + } +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( pd3dDevice == NULL ) { + return; + } + + if( g_bIsLost ) return; + +#ifdef RELEASE_TO_PUBLIC + if( g_nRealFrame < 80 ) { + RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); + + if( g_nRealFrame == 79 ) + SAFE_RELEASE(ptexLogo); + return; + } +#endif + + Flush(0); + Flush(1); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, vb[0].prndr->psurf, NULL, NULL); + + if( vb[1].prndr != NULL && vb[0].prndr != vb[1].prndr ) D3DXSaveSurfaceToFile("frame2.tga", D3DXIFF_TGA, vb[1].prndr->psurf, NULL, NULL); + else DeleteFile("frame2.tga"); + } + + if( s_RangeMngr.ranges.size() > 0 ) + FlushTransferRanges(NULL); + + if( icurctx >= 0 && vb[icurctx].bVarsSetTarg ) { // check if anything rendered + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + } + + D3DVIEWPORT9 view; + view.Width = width; + view.Height = height; + view.X = 0; + view.Y = 0; + view.MinZ = 0; + view.MaxZ = 1.0f; + pd3dDevice->SetViewport(&view); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; +// static int counter = 0; +// counter++; + // reset fba after every frame + //if( !(g_GameSettings&GAME_NOFBARESET) ) { + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + //} + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = D3DCOLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL, color, 1, 0); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + SETRS(D3DRS_ZENABLE, 0); + SETRS(D3DRS_ZWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + SETRS(D3DRS_STENCILENABLE, 0); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + DXVEC4 v, valpha; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + pd3dDevice->SetTexture(SAMP_INTERLACE, CreateInterlaceTex(2*texframe.th)); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + if( PMODE->MMOD ) { + SETRS(D3DRS_BLENDFACTOR, D3DCOLOR_ARGB(0x80, PMODE->ALP, PMODE->ALP, PMODE->ALP)); + SETRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR); + } + else { + SETRS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + + SETRS(D3DRS_SRCBLENDALPHA, PMODE->AMOD ? D3DBLEND_ZERO : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, PMODE->AMOD? D3DBLEND_ONE : D3DBLEND_ZERO); + } + + if( bUsingStencil ) { + SETRS(D3DRS_STENCILWRITEMASK, 1<SetPixelShader(ppsCRTC24[bInterlace]); + valpha.x = 0; + valpha.y = 1; + SETCONSTF(GPU_ONECOLOR, valpha); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + continue; + } + + // first render the current render targets, then from ptexMem + if( texframe.psm == 1 ) { + valpha.x = 0; + valpha.y = 1; + } + else { + valpha.x = 1; + valpha.y = 0; + } + + SETCONSTF(GPU_ONECOLOR, valpha); + + BOOL bSkip = 0; + BOOL bResolveTargs = 1; + + //s_mapFrameHeights[s_nCurFrameMap][texframe.tbp0] = texframe.th; + list listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + static int sindex = 0; + char strtemp[25]; + sprintf(strtemp, "frames/frame%d.jpg", sindex++); +// D3DXSaveSurfaceToFile(strtemp, D3DXIFF_JPG, ptarg->psurf, NULL, NULL); +// if( g_bSaveFinalFrame ) +// D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, ptarg->psurf, NULL, NULL); + + int dby = pfb->DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1, 0); + } + bUsingStencil = 1; + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); + SETRS(D3DRS_STENCILREF, 3); + SETRS(D3DRS_STENCILWRITEMASK, 1<fbh; + + // tex coords + v = DXVEC4(fiw*(float)texframe.tw, fih*(float)(dh), fiw*(float)(pfb->DBX), fih*((float)dby-0.5f)); + SETCONSTF(GPU_BITBLTTEX, v); + + // dest rect + v.x = 1; + v.y = dh/(float)texframe.th; + v.z = 0; + v.w = 1-v.y; + + if( movy > 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = fiw; + v.y = fih; + v.z = 0; + SETCONSTF(GPU_INVTEXDIMS, v); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptarg->ptex); + pd3dDevice->SetPixelShader(ppsCRTCTarg[bInterlace]); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + SetTexVariablesInt(0, 2, texframe, g_MemTargs.GetMemoryTarget(texframe, 1), 1); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = DXVEC4(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + v = DXVEC4(texframe.tw,texframe.th,-0.5f,-0.5f); + SETCONSTF(GPU_BITBLTTEX, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = 1.0f / (float)texframe.tw; + v.y = 1.0f / (float)texframe.th; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * v.y; + SETCONSTF(GPU_INVTEXDIMS, v); + + pd3dDevice->SetPixelShader(ppsCRTC[bInterlace]); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } + } + + if(1) {// || !bInterlace) { + s_bBeginScene = FALSE; + + ProcessMessages(); + + if( g_bMakeSnapshot ) { + RECT rctext; + char str[64]; + rctext.left = 200; rctext.top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", revision, build, minor, fFPS, s_frameskipping?" - frameskipping":""); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + if( g_bDisplayFPS ) { + RECT rctext; + char str[64]; + rctext.left = 10; rctext.top = 10; + sprintf(str, "%.1f fps", fFPS); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + pd3dDevice->EndScene(); + if( pd3dDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST ) { + // device is lost, need to recreate + printf("device lost\n"); + g_bIsLost = TRUE; + Reset(); + return; + } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SUCCEEDED(D3DXSaveSurfaceToFile(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", (conf.options&GSOPTION_BMPSNAP)?D3DXIFF_BMP:D3DXIFF_JPG, psurfOrgTarg, NULL, NULL)) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); // d3d debug complains if not + g_MemTargs.DestroyCleared(); + + for(list::iterator it = s_vecTempTextures.begin(); it != s_vecTempTextures.end(); ++it) + (*it)->Release(); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAYSIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAYSIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAYSIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + printf("ZeroGS: video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + s_PSM8Resolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + +#define MOVZ(p, gsz) p.z = curvb.zprimmask==0xffff?min(0xffff, gsz):gsz; +#define MOVFOG(p, gsf) p.f = ((s16)(gsf).f<<7)|0x7f; + +#define SET_VERTEX(p, Index) { \ + int index = Index; \ + p.x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; \ + p.y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; \ + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); \ + y = ((int)gs.gsvertex[index].y - curvb.offset.y); \ + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); \ + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ \ + p.f = ((s16)gs.gsvertex[index].f<<7)|0x7f; \ + MOVZ(p, gs.gsvertex[index].z); \ + p.rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; \ + if( (g_GameSettings & GAME_TEXAHACK) && !(p.rgba&0xffffff) ) \ + p.rgba = 0; \ + if( prim->tme ) { \ + if( prim->fst ) { \ + p.s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; \ + p.t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; \ + p.q = 1; \ + } \ + else { \ + p.s = gs.gsvertex[index].s; \ + p.t = gs.gsvertex[index].t; \ + p.q = gs.gsvertex[index].q; \ + } \ + } \ +} \ + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + +//#define OUTPUT_VERT(fn, vert, id) { \ +// fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128); \ +//} \ + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH) + Flush(prim->ctxt); + + curvb.Lock(); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount; + SET_VERTEX(p[0], last); + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/2 ) + Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount*2; + SET_VERTEX(p[0], next); + SET_VERTEX(p[1], last); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(p[0], 0); + SET_VERTEX(p[1], 1); + SET_VERTEX(p[2], 2); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(p[0], 0); + SET_VERTEX(p[1], 1); + SET_VERTEX(p[2], 2); + + curvb.dwCount++; + + // add 1 to skip the first vertex + if( gs.primIndex == gs.nTriFanVert ) + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if( s_AAx ) { + gs.gsvertex[last].x += 4; + if( s_AAy ) + gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + // return; + + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + + SET_VERTEX(p[0], next); MOVZ(p[0], gs.gsvertex[last].z); MOVFOG(p[0], gs.gsvertex[last]); + SET_VERTEX(p[3], next); MOVZ(p[3], gs.gsvertex[last].z); MOVFOG(p[3], gs.gsvertex[last]); + + SET_VERTEX(p[1], last); MOVZ(p[1], gs.gsvertex[last].z); MOVFOG(p[1], gs.gsvertex[last]); + SET_VERTEX(p[4], last); MOVZ(p[4], gs.gsvertex[last].z); MOVFOG(p[4], gs.gsvertex[last]); + + if( g_MaxRenderedHeight < p[0].y ) + g_MaxRenderedHeight = p[0].y; + if( g_MaxRenderedHeight < p[1].y ) + g_MaxRenderedHeight = p[1].y; + + SET_VERTEX(p[2], next); MOVZ(p[2], gs.gsvertex[last].z); MOVFOG(p[2], gs.gsvertex[last]); + p[2].s = p[1].s; + p[2].x = p[1].x; + + SET_VERTEX(p[5], last); MOVZ(p[5], gs.gsvertex[last].z); MOVFOG(p[5], gs.gsvertex[last]); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.dwCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb) +{ + // add fba to all pixels + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, STENCIL_FBA); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + if( !curvb.test.ate ) + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) { + if( curvb.test.afail == 1 ) SETRS(D3DRS_ALPHATESTENABLE, FALSE); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + // or a 1 to the stencil buffer wherever alpha passes + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + + SETRS(D3DRS_STENCILENABLE, TRUE); + + if( !s_bDestAlphaTest ) { + // clear everything + SETRS(D3DRS_STENCILREF, 0); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHAREF, curvb.test.aref); + } + + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_SPECIAL); + SETRS(D3DRS_ZENABLE, FALSE); + + DRAW(); + + if( curvb.test.zte ) SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + // set rt next level + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + + dwStencilMask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, dwStencilMask ? D3DCMP_EQUAL : D3DCMP_ALWAYS); + + dwStencilRef = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILREF, dwStencilRef); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_ALPHATESTENABLE, 0); + + pd3dDevice->SetPixelShader(ppsOne); + DRAW(); + + // process when alpha >= 0xff + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + // restore state + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_ZENABLE, curvb.test.zte); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + // processes the pixels with ALPHA < 0x80*2 + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + // add 1 to dest + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + float f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + pd3dDevice->SetPixelShader(ppsOne); + + DRAW(); + + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + + // reset bits + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_GREATER); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // restore (SetAlphaVariables) + if( !bNeedAlphaColor ) SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);//(bNeedBlendFactorInAlpha ? D3DBLEND_ZERO : D3DBLEND_ONE)); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);//bNeedBlendFactorInAlpha ? D3DBLEND_ONE : D3DBLEND_ZERO); + if(bNeedAlphaColor && vAlphaBlendColor.y<0) SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_REVSUBTRACT); + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->targheight ); + +// if( curvb.pdepth->fbh != curvb.prndr->fbh ) { +// +// s_DepthRTs.DestroyTarg(curvb.pdepth); +// ERROR_LOG("ZeroGS: render and depth heights different: %x %x\n", curvb.prndr->fbh, curvb.pdepth->fbh); +// frameInfo f; +// f.fbp = curvb.zbuf.zbp; +// f.fbw = curvb.frame.fbw; +// f.fbh = curvb.prndr->fbh; +// f.psm = curvb.zbuf.psm; +// f.fbm = 0; +// curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| +// (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); +// } + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + + if( s_bWriteDepth ) { + if( bSetTarg ) { + pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + } + } + else if( bSetTarg ) + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + + curvb.prndr->Update(context, curvb.pdepth); + // note, targ already set + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthTarget(); + + if( s_ptexCurSet[0] == curvb.prndr->ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == curvb.prndr->ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) { + WARN_LOG("frame and zbuf not aligned\n"); + } + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) + vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); +} + +void ZeroGS::SetTexVariables(int context) +{ + if( !vb[context].curprim.tme ) { + return; + } + + assert( !vb[context].bNeedTexCheck ); + + DXVEC4 v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + DXVEC4 valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + DXVEC4 vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + default: __assume(0); + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + SETCONSTF(GPU_TEXALPHA0+context, &valpha); + SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + SETCONSTF(GPU_TESTBLACK0+context, &vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + DXVEC4 v, v2; + v.x = v.y = 0; + LPD3DTEX* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = NULL; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, NULL); + } + break; + + default: __assume(0); + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + + default: __assume(0); + } + + SETCONSTF(GPU_TEXWRAPMODE0+context, v); + SETCONSTF(GPU_CLAMPEXTS0+context, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, int force) +{ + DXVEC4 v; + assert( pmemtarg != NULL ); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( bilinear > 1 || (bilinear && conf.bilinear)) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + SETCONSTF(GPU_REALTEXDIMS0+context, v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + v.x = b.vTexDims.x * fw; + v.y = b.vTexDims.y * fh; + v.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + v.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bilinear > 1 || (conf.bilinear && bilinear) ) { + v.x *= 1/128.0f; + v.y *= 1/512.0f; + v.z *= 1/128.0f; + v.w *= 1/512.0f; + } + SETCONSTF(GPU_TEXDIMS0+context, v); + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + SETCONSTF(GPU_TEXBLOCK0+context, &b.vTexBlock.x); + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + SETCONSTF(GPU_TEXOFFSET0+context, v); + + v.y = (float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f)*v.y; + + SETCONSTF(GPU_PAGEOFFSET0+context, v); + + if( force ) { + pd3dDevice->SetTexture(SAMP_MEMORY0+context, pmemtarg->ptex); + s_ptexCurSet[context] = pmemtarg->ptex; + } + else s_ptexNextSet[context] = pmemtarg->ptex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} + +// assumes texture factor is unused +#define SET_ALPHA_COLOR_FACTOR(sign) { \ + switch(a.c) { \ + case 0: \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); \ + SETRS(D3DRS_BLENDOPALPHA, (sign) ? D3DBLENDOP_ADD : D3DBLENDOP_REVSUBTRACT); \ + break; \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// printf("bfactor: %8.8x\n", dwTemp); \ +// SETRS(D3DRS_BLENDFACTOR, dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ + s_bAlphaSet = FALSE; +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); // always set + + if( s_bAlphaSet && a.abcd == s_alphaInfo.abcd && a.fix == s_alphaInfo.fix ) { + return; + } + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + DWORD dwTemp = 0xffffffff; + + // default + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + s_alphaInfo = a; + + vAlphaBlendColor = DXVEC4(1,2*255.0f/256.0f,0,0); + DWORD usec = a.c; + + if( a.a == a.b ) { // just d remains + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( a.d == 0 ) { + SETRS(D3DRS_ALPHABLENDENABLE, 0); + } + else { + SETRS(D3DRS_DESTBLEND, a.d == 1 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) { // zero + + if( a.a == 2 ) { + // zero all color + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ZERO); + goto EndSetAlpha; + } + else if( a.b == 2 ) { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) { + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_ONE); + } + else { + if( bNeedAlphaColor ) bAlphaClamping = 2; + + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendalpha[usec]); + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + SETRS(D3DRS_BLENDOP, a.a == 0 ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_REVSUBTRACT); + SETRS(D3DRS_SRCBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + } + else if( a.a == 2 ) { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) { + // can get away with 1-A + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2) ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + else { + SETRS(D3DRS_BLENDOP, a.b==0 ? D3DBLENDOP_REVSUBTRACT : D3DBLENDOP_SUBTRACT); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2 ) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else if( a.b == 2 ) { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.a == 0 || bDestAlphaColor == 2) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + else { + assert(a.b == a.d); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + } + +EndSetAlpha: + //b2XAlphaTest = b2XAlphaTest && bNeedAlphaColor && !bNeedBlendFactorInAlpha; + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + DXVEC4 v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + SETCONSTF(GPU_FOGCOLOR, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + // do a fast test with MMX + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + cmp ebx, 0x90 + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + } + +Return: + __asm { + emms + mov ebx, storeebx + } +#endif + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // note sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + } + + Flush(!ctx); + + int entries = (tex0.psm&3)==3 ? 256 : 16; + + if( tex0.csm ) { + // 16bit psm + // eggomania uses non16bit textures for csm2 + if( tex0.cpsm == PSMCT16 ) { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for(int i = 0; i < entries; ++i) { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + // check for wrapping + if( ((u32)dst & 0x3ff) == 0 ) + dst = (u16*)(g_pbyGSClut+2); + } + } + else if( tex0.cpsm == PSMCT16S ) { + + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for(int i = 0; i < entries; ++i) { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + // check for wrapping + if( ((u32)dst & 0x3ff) == 0 ) + dst = (u16*)(g_pbyGSClut+2); + } + } + else if( tex0.cpsm == PSMCT32 || tex0.cpsm == PSMCT24 ) { + + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + // check if address exceeds src + if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) { + ERROR_LOG("texClutWrite out of bounds\n"); + } + else { + for(int i = 0; i < entries; ++i) { + *dst++ = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + } + } + } + else { +#ifndef RELEASE_TO_PUBLIC + //printf("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + } + } + else { + if( tex0.cpsm <= 1 ) { + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + } + else { + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else if(entries == 256) { + // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + } + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) { + if( s_ptexCurSet[0] != s_ptexNextSet[0] ) { + s_ptexCurSet[0] = s_ptexNextSet[0]; + pd3dDevice->SetTexture(SAMP_MEMORY0, s_ptexNextSet[0]); + } + if( s_ptexCurSet[1] != s_ptexNextSet[1] ) { + s_ptexCurSet[1] = s_ptexNextSet[1]; + pd3dDevice->SetTexture(SAMP_MEMORY1, s_ptexNextSet[1]); + } + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + vb[0].Lock(); + vb[1].Lock(); + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + LPD3DVB pvb = vb[0].pvb; + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pvb = pvb; + + pvb = vb[1].pvb; + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pvb = pvb; + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + SetFogColor(gs.fogcol); + + vb[0].Lock(); + vb[1].Lock(); + + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +// AVI capture stuff +bool ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + START_AVI("zerogs.avi"); + + assert( s_ptexAVICapture == NULL ); + if( FAILED(pd3dDevice->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_ptexAVICapture, NULL)) ) { + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return false; + } + + s_aviinit = 1; + } + else { + printf("ZeroGS: Continuing from previous capture"); + } + + s_avicapturing = 1; + return true; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit && s_ptexAVICapture != NULL ); + + vector mem; + + pd3dDevice->GetRenderTargetData(psurfOrgTarg, s_ptexAVICapture); + + D3DLOCKED_RECT lock; + mem.resize(width * height * 4); + + s_ptexAVICapture->LockRect(&lock, NULL, D3DLOCK_READONLY); + assert( lock.Pitch == width*4 ); + + BYTE* pend = (BYTE*)lock.pBits + (conf.height-1)*width*4; + for(int i = 0; i < conf.height; ++i) { + memcpy_amd(&mem[width*4*i], pend - width*4*i, width * 4); + } + s_ptexAVICapture->UnlockRect(); + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, width, height, 32, &mem[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + s_aviinit = 0; + ZeroGS::AddMessage("Failed to create avi"); + return; + } +} diff --git a/plugins/gs/zerogs/dx/zerogs.h b/plugins/gs/zerogs/dx/zerogs.h new file mode 100644 index 0000000000..026dbdd54c --- /dev/null +++ b/plugins/gs/zerogs/dx/zerogs.h @@ -0,0 +1,512 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#include +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +typedef D3DXVECTOR2 DXVEC2; +typedef D3DXVECTOR3 DXVEC3; +typedef D3DXVECTOR4 DXVEC4; +typedef D3DXMATRIX DXMAT; + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { GS_LOG(#x"\n"); action; } } + +#ifndef RELEASE_TO_PUBLIC + #ifndef V +#define V(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); } } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); return hr; } } + #endif +#else + #ifndef V + #define V(x) { hr = x; } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } } + #endif +#endif + +#define SETRS(state, val) pd3dDevice->SetRenderState(state, val) +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +// set these shader constants +#define GPU_TEXALPHA20 (2|0x8000) +#define GPU_TEXOFFSET0 (4|0x8000) +#define GPU_TEXDIMS0 (6|0x8000) +#define GPU_TEXBLOCK0 (8|0x8000) +#define GPU_CLAMPEXTS0 (10|0x8000) +#define GPU_TEXWRAPMODE0 (12|0x8000) +#define GPU_REALTEXDIMS0 (14|0x8000) +#define GPU_TESTBLACK0 (16|0x8000) +#define GPU_PAGEOFFSET0 (18|0x8000) +#define GPU_TEXALPHA0 (20|0x8000) + +#define GPU_INVTEXDIMS (22|0x8000) +#define GPU_FOGCOLOR (23|0x8000) +#define GPU_BITBLTZ (24|0x8000) +#define GPU_ONECOLOR (25|0x8000) + +#define GPU_CLIPPLANE0 (24|0x8000) +#define GPU_CLIPPLANE1 (26|0x8000) + +#define GPU_POSXY0 2 + +#define GPU_BITBLTPOS 4 +#define GPU_Z 5 +#define GPU_ZNORM 6 +#define GPU_BITBLTTEX 7 + +#define SETCONSTF(id, ptr) { if( id & 0x8000 ) pd3dDevice->SetPixelShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); \ + else pd3dDevice->SetVertexShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); } + +#define SAMP_MEMORY0 0 +#define SAMP_MEMORY1 1 +#define SAMP_FINAL 2 +#define SAMP_BLOCKS 3 +#define SAMP_BILINEARBLOCKS 4 +#define SAMP_INTERLACE 5 +#define SAMP_BITWISEANDX 5 +#define SAMP_BITWISEANDY 6 + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes +#define GAME_RELAXEDDEPTH 0x08000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHABLENDING 1//(!(g_GameSettings&GAME_NOALPHABLEND)) +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +typedef IDirect3DDevice9* LPD3DDEV; +typedef IDirect3DVertexBuffer9* LPD3DVB; +typedef IDirect3DIndexBuffer9* LPD3DIB; +typedef IDirect3DBaseTexture9* LPD3DBASETEX; +typedef IDirect3DTexture9* LPD3DTEX; +typedef IDirect3DCubeTexture9* LPD3DCUBETEX; +typedef IDirect3DVolumeTexture9* LPD3DVOLUMETEX; +typedef IDirect3DSurface9* LPD3DSURF; +typedef IDirect3DVertexDeclaration9* LPD3DDECL; +typedef IDirect3DVertexShader9* LPD3DVS; +typedef IDirect3DPixelShader9* LPD3DPS; +typedef ID3DXAnimationController* LPD3DXAC; + +namespace ZeroGS +{ + typedef void (*DrawFn)(); + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + CRenderTarget(const frameInfo& frame, CRenderTarget& r); // virtualized a target + virtual ~CRenderTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == NULL || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + + LPD3DSURF psurf, psys; + LPD3DTEX ptex; + + int targoffx, targoffy; // the offset from the target that the real fbp starts at (in pixels) + int targheight; // height of ptex + CRenderTarget* pmimicparent; // if not NULL, this target is a subtarget of pmimicparent + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + DXVEC4 vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + RECT scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + LPD3DTEX ptexFeedback; + LPD3DSURF psurfFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthTarget(); + + LPD3DSURF pdepth; + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct MEMORY + { + inline MEMORY() : ptr(NULL), ref(0) {} + inline ~MEMORY() { _aligned_free(ptr); } + + BYTE* ptr; + int ref; + }; + + inline CMemoryTarget() : ptex(NULL), ptexsys(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), + cpsm(0), memory(NULL), clearminy(0), clearmaxy(0), validatecount(0) {} + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + ptexsys = r.ptexsys; + if( ptex != NULL ) ptex->AddRef(); + if( ptexsys != NULL ) ptexsys->AddRef(); + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + memory = r.memory; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + validatecount = r.validatecount; + fmt = r.fmt; + if( memory != NULL ) memory->ref++; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexsys); + + if( memory != NULL && memory->ref > 0 ) { + if( --memory->ref <= 0 ) { + SAFE_DELETE(memory); + } + } + memory = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + LPD3DTEX ptex; // can be 16bit if + LPD3DTEX ptexsys; + D3DFORMAT fmt; + + int widthmult; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + MEMORY* memory; // system memory used to compare for changes + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + inline bool IsLocked() { return pbuf != NULL; } + inline void Lock(); + inline void Unlock() { + if( pbuf != NULL ) { + pvb->Unlock(); + pbuf = NULL; + } + } + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + LPD3DTEX ptexClamp[2]; // textures for x and y dir region clamping + + public: + + void FlushTexData(); + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pbuf; + DWORD dwCurOff; + DWORD dwCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + LPD3DVB pvb; + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + extern LONG width, height; + extern u8* g_pbyGSMemory; + extern u8* g_pbyGSClut; // the temporary clut buffer + + void AddMessage(const char* pstr, DWORD ms = 5000); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + + HRESULT Create(LONG width, LONG height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + HRESULT InitDeviceObjects(); + void DeleteDeviceObjects(); + + void GSStateReset(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, int force); + + void ResetAlphaVariables(); + + bool StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +extern LPDIRECT3DDEVICE9 pd3dDevice; +extern const u32 g_primmult[8]; +extern const u32 g_primsub[8]; + +#endif diff --git a/plugins/gs/zerogs/opengl/GS.h b/plugins/gs/zerogs/opengl/GS.h new file mode 100644 index 0000000000..04011c4551 --- /dev/null +++ b/plugins/gs/zerogs/opengl/GS.h @@ -0,0 +1,844 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GS_H__ +#define __GS_H__ + +#include +#include +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" +} + +#ifdef _WIN32 + +#include +#include + +extern HWND GShwnd; + +#else // linux basic definitions + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __inline inline + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +// declare linux equivalents +extern __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +extern __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free + +#endif + +#include // ftime(), struct timeb + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +struct RECT +{ + int left, top; + int right, bottom; +}; + +typedef struct { + Display *dpy; + int screen; + Window win; + GLXContext ctx; + XSetWindowAttributes attr; + Bool fs; + Bool doubleBuffered; + XF86VidModeModeInfo deskMode; + int x, y; + unsigned int width, height; + unsigned int depth; +} GLWindow; + +extern GLWindow GLWin; + +#endif // linux basic definitions + +#include +#include + +#include +#include +using namespace std; + +#include "zerogsmath.h" + +#if defined(_MSC_VER) +#define FASTCALL(fn) __fastcall fn +#else + +#ifdef __x86_64 +#define FASTCALL(fn) fn +#else +#define FASTCALL(fn) __attribute__((fastcall)) fn +#endif + +#endif + +struct Vector_16F +{ + u16 x, y, z, w; +}; + +///////////////////// +// define when releasing +#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC + +#if !defined(_RELEASE) +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; + +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + u32 NLOOP:15; + u32 EOP:1; + u32 _PAD1:16; + u32 _PAD2:14; + u32 PRE:1; + u32 PRIM:11; + u32 FLG:2; // enum GIF_FLG + u32 NREG:4; + u64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_TGASNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x30 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + int interlace; + int aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + int bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen + int mrtdepth; // write color in render target +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +struct VertexGPU +{ + s16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; +}; + +struct Vertex +{ + u16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; + u16 u, v; +}; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // u16 address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(char *fmt, ...); +void ERROR_LOG(char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +__forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +__forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +// IMPORTANT: For every Reigster there must be an End +void DVProfRegister(char* pname); // first checks if this profiler exists in g_listProfilers +void DVProfEnd(u32 dwUserData); +void DVProfWrite(char* pfilename, u32 frames = 0); +void DVProfClear(); // clears all the profilers + +#define DVPROFILE +#ifdef DVPROFILE + +class DVProfileFunc +{ +public: + u32 dwUserData; + DVProfileFunc(char* pname) { DVProfRegister(pname); dwUserData = 0; } + DVProfileFunc(char* pname, u32 dwUserData) : dwUserData(dwUserData) { DVProfRegister(pname); } + ~DVProfileFunc() { DVProfEnd(dwUserData); } +}; + +#else + +class DVProfileFunc +{ +public: + u32 dwUserData; + __forceinline DVProfileFunc(char* pname) {} + __forceinline DVProfileFunc(char* pname, u32 dwUserData) { } + ~DVProfileFunc() {} +}; + +#endif + +#endif diff --git a/plugins/gs/zerogs/opengl/GSmain.cpp b/plugins/gs/zerogs/opengl/GSmain.cpp new file mode 100644 index 0000000000..0d96e7817e --- /dev/null +++ b/plugins/gs/zerogs/opengl/GSmain.cpp @@ -0,0 +1,1443 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) +#include +#include "Win32.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "ZeroGSShaders/zerogsshaders.h" + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +string s_strIniPath="inis/zerogs.ini"; + +static BOOL g_bHidden = 0; +int g_GameSettings = 0; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 96 +const unsigned char zgsversion = PS2E_GS_VERSION; +unsigned char zgsrevision = 0; // revision and build gives plugin version +unsigned char zgsbuild = VER; +unsigned char zgsminor = 7; + +#ifdef _DEBUG +char *libraryName = "ZeroGS OpenGL (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) +char *libraryName = "ZeroGS KOSMOS OpenGL "; +#else +char *libraryName = "ZeroGS OpenGL (Dev) "; +#endif + +static const char* s_aa[3] = { "AA none |", "AA 2x |", "AA 4x |" }; +static const char* pbilinear[] = { "off", "normal", "forced" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +#ifdef RELEASE_TO_PUBLIC +#define g_bWriteProfile 0 +#else +BOOL g_bWriteProfile = 0; +#endif + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (zgsversion<<16) | (zgsrevision<<8) | zgsbuild | (zgsminor << 24); +} + +static u64 luPerfFreq; + +#ifdef _WIN32 + +HWND GShwnd = NULL; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} +#else + +GLWindow GLWin; + +#endif + +#ifdef GS_LOG +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} +#endif + +void ERROR_LOG(char *fmt, ...) { + va_list list; + + va_start(list, fmt); + fprintf(gsLog, "ZeroGS: "); + vfprintf(gsLog, fmt, list); + va_end(list); + + va_start(list, fmt); + printf("ZeroGS: "); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = 0;//!(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + if( !conf.mrtdepth ) { + ERROR_LOG("Disabling MRT depth writing\n"); + } + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(int mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + +#ifdef __LINUX__ + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerogs.ini"; +#endif + + GSreset(); + +#ifdef GS_LOG + GS_LOG("GSinit ok\n"); +#endif + + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +// keyboard functions +void OnKeyboardF5(int shift) +{ + char strtitle[256]; + if( shift ) { + if( g_nPixelShaderVer == SHADER_REDUCED ) { + conf.bilinear = 0; + sprintf(strtitle, "reduced shaders don't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF6(int shift) +{ + char strtitle[256]; + if( shift ) { + conf.aa--; // -1 + if( conf.aa < 0 ) conf.aa = 4; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF7(int shift) +{ + char strtitle[256]; + if( shift ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + glPolygonMode(GL_FRONT_AND_BACK, (conf.options&GSOPTION_WIREFRAME)?GL_LINE:GL_FILL); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); + } +} + +void OnKeyboardF9(int shift) +{ + char strtitle[256]; + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + ZeroGS::AddMessage(strtitle); + //SaveConfig(); +} + +#ifdef _WIN32 + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //printf("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_REDUCED ) + conf.bilinear = 0; +} + + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + +#ifdef GS_LOG + GS_LOG("GSopen\n"); +#endif + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(HWND*)pDsp = GShwnd; + + ERROR_LOG("creating\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("bilinear filtering - forced", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("bilinear filtering - normal", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + //SetForegroundWindow(GShwnd); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + +#ifdef GS_LOG + GS_LOG("GSopen ok\n"); +#endif + + LARGE_INTEGER temp; + QueryPerformanceFrequency(&temp); + luPerfFreq = temp.QuadPart; + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void ProcessMessages() +{ + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + OnKeyboardF5(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F6 ) { + OnKeyboardF6(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F7 ) { + OnKeyboardF7(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F9 ) { + OnKeyboardF9(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 +} + +#else // linux + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) +{ +#ifdef GS_LOG + GS_LOG("GSopen\n"); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + GLWin.dpy = XOpenDisplay(0); + GLWin.screen = DefaultScreen(GLWin.dpy); + + if( pDsp != NULL ) + *(Display**)pDsp = GLWin.dpy; + + ERROR_LOG("creating\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("bilinear filtering - forced", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("bilinear filtering - normal", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + +#ifdef GS_LOG + GS_LOG("GSopen ok\n"); +#endif + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + luPerfFreq = 1; + + return 0; +} + +void ProcessMessages() +{ + XEvent event; +// KeySym key; +// vector keyevents; + + // check resizing + while(XCheckTypedEvent(GLWin.dpy, ConfigureNotify, &event)) { + if ((event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height)) { + ZeroGS::ChangeWindowSize(event.xconfigure.width, event.xconfigure.height); + GLWin.width = event.xconfigure.width; + GLWin.height = event.xconfigure.height; + } + } + +// while (XPending(GLWin.dpy) > 0) { +// XNextEvent(GLWin.dpy, &event); +// keyevents.push_back(event); +// +// switch (event.type) { +// case ConfigureNotify: +// if ((event.xconfigure.width != GLWin.width) || +// (event.xconfigure.height != GLWin.height)) +// { +// ZeroGS::ChangeWindowSize(event.xconfigure.width, event.xconfigure.height); +// GLWin.width = event.xconfigure.width; +// GLWin.height = event.xconfigure.height; +// } +// break; +// default: +// break; +// } +// } +// +// // push back all the key events for the PAD plugins, etc +// for(vector::iterator it = keyevents.begin(); it != keyevents.end(); ++it) +// XPutBackEvent(GLWin.dpy, &(*it)); +} + +#endif // linux + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + +#ifdef _WIN32 + if( GShwnd != NULL ) { + DestroyWindow(GShwnd); + GShwnd = NULL; + } +#else + if( GLWin.dpy != NULL ) { + XCloseDisplay(GLWin.dpy); + GLWin.dpy = NULL; + } +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_TGASNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + +#ifdef _WIN32 + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); +#else + sprintf(strdir, "mkdir %s", path); + system(strdir); +#endif + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ +#ifdef GS_LOG + GS_LOG("\nGSvsync\n\n"); +#endif + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + char strtitle[256]; + + GL_REPORT_ERRORD(); + + g_nRealFrame++; + + ZeroGS::RenderCRTC(!interlace); + +#ifndef _WIN32 + //XLockDisplay(GLWin.dpy); +#endif + + ProcessMessages(); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; + + sprintf(strtitle, "ZeroGS KOSMOS 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", zgsbuild, zgsminor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + sprintf(strtitle, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + +// if( g_nFrame > 100 && fFPS > 60.0f ) { +// printf("set profile\n"); +// g_bWriteProfile = 1; +// } + +#ifdef _WIN32 + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); +#else // linux + XTextProperty prop; + memset(&prop, 0, sizeof(prop)); + char* ptitle = strtitle; + if( XStringListToTextProperty(&ptitle, 1, &prop) ) + XSetWMName(GLWin.dpy, GLWin.win, &prop); + XFree(prop.value); +#endif + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } + +#ifndef RELEASE_TO_PUBLIC + if( g_bWriteProfile ) { + //g_bWriteProfile = 0; + DVProfWrite("prof.txt", UPDATE_FRAMES); + DVProfClear(); + } +#endif + GL_REPORT_ERRORD(); + +#ifndef _WIN32 + //XUnlockDisplay(GLWin.dpy); +#endif +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +#ifdef GS_LOG +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); +#endif + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ +// int mode = s_pLastPath->mode > 0 ? s_pLastPath->mode-1 : 0; +// *(u32*)ptag = s_pLastPath->tag.nloop|(s_pLastPath->tag.eop<<15); +// *((u32*)ptag+1) = (mode<<26)|(s_pLastPath->regn<<28); + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _WIN32 + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + +#ifdef _DEBUG + if( conf.log & 0x20 ) { + static int nSaveIndex=0; + __Log("%d: p:%d %x\n", nSaveIndex++, (path==&gs.path3)?3:(path==&gs.path2?2:1), size); + int vals[4] = {0}; + for(int i = 0; i < size; i++) { + for(int j = 0; j < 4; ++j ) + vals[j] ^= pMem[4*i+j]; + } + __Log("%x %x %x %x\n", vals[0], vals[1], vals[2], vals[3]); + } +#endif + //s_pLastPath = path; +#ifdef _DEBUG + if( conf.log & 0x20 ) { + static int nSaveIndex=0; + __Log("%d: p:%d %x\n", nSaveIndex++, (path==&gs.path3)?3:(path==&gs.path2?2:1), size); + int vals[4] = {0}; + for(int i = 0; i < size; ++i) { + for(int j = 0; j < 4; ++j ) + vals[j] ^= pMem[4*i+j]; + } + + __Log("%x %x %x %x\n", vals[0], vals[1], vals[2], vals[3]); + } +#endif + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if(path->tag.nloop == 0) { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if( (g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop ) + nPath3Hack = 1; + + if( path == &gs.path1 ) { + + // if too much data, just ignore + if( path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if( path->mode == 1 ) { + + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) { + if( ((path->regs >> i)&0xf) == 11 ) { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) { + + if( path == &gs.path1 ) { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) { + //printf("contuing from eop\n"); + continue; + } + + break; + } + } + + switch(path->mode) { + case 1: // PACKED + { + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //__Log("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) { + if( gs.imageTransfer ) ZeroGS::TransferLocalHost(pMem, process); + else ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: + GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); + assert(0); +// ZeroGS::TransferLocalHost(pMem, size); +// pMem+= size*4; path->tag.nloop-= size; +// size = 0; path->mode = 0; + path->tag.nloop = 0; + break; + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ +#ifdef GS_LOG + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); +#endif + + // if(!g_GSMultiThreaded) +// CSR->FINISH = 0; + //DVProfileFunc _pf("Transf2"); + + //assert( ((u32)pMem & 0xf) == 0 ); + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ +#ifdef GS_LOG + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); +#endif + + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int s_trcount = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + +#ifdef GS_LOG + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); +#endif + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count :%d\n", s_trcount); + s_trcount++; + +// for(int i = addr; i < 0x4000; i += 16 ) { +// u32* mem = (u32*)((u8*)pMem+i); +// PRIM_LOG("%x: %x %x %x %x\n", i, mem[0], mem[1], mem[2], mem[3]); +// } +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + //_GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+0x4000-addr), addr/16); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ +#ifdef GS_LOG + //GS_LOG("GSreadFIFO\n"); +#endif + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ +#ifdef GS_LOG + //GS_LOG("GSreadFIFO2\n"); +#endif + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + ZeroGS::StartCapture(); + conf.options |= GSOPTION_CAPTUREAVI; + printf("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + printf("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) { + if (mode == FREEZE_LOAD) { + if( !ZeroGS::Load(data->data) ) + ERROR_LOG("Bad load format!"); + g_nRealFrame += 100; + + } else if (mode == FREEZE_SAVE) { + ZeroGS::Save(data->data); + } + if (mode == FREEZE_SIZE) { + data->size = ZeroGS::Save(NULL); + } + + return 0; +} + +//////////////////// +// Small profiler // +//////////////////// +#include +#include +#include +using namespace std; + +#ifdef _WIN32 + +inline u64 GET_PROFILE_TIME() +{ + LARGE_INTEGER lu; + QueryPerformanceCounter(&lu); + return lu.QuadPart; +} +#else +#define GET_PROFILE_TIME() //GetCpuTick() +#endif + + +struct DVPROFSTRUCT; + +struct DVPROFSTRUCT +{ + struct DATA + { + DATA(u64 time, u32 user = 0) : dwTime(time), dwUserData(user) {} + DATA() : dwTime(0), dwUserData(0) {} + + u64 dwTime; + u32 dwUserData; + }; + + ~DVPROFSTRUCT() { + list::iterator it = listpChild.begin(); + while(it != listpChild.end() ) { + SAFE_DELETE(*it); + ++it; + } + } + + list listTimes; // before DVProfEnd is called, contains the global time it started + // after DVProfEnd is called, contains the time it lasted + // the list contains all the tracked times + char pname[256]; + + list listpChild; // other profilers called during this profiler period +}; + +struct DVPROFTRACK +{ + u32 dwUserData; + DVPROFSTRUCT::DATA* pdwTime; + DVPROFSTRUCT* pprof; +}; + +list g_listCurTracking; // the current profiling functions, the back element is the + // one that will first get popped off the list when DVProfEnd is called + // the pointer is an element in DVPROFSTRUCT::listTimes +list g_listProfilers; // the current profilers, note that these are the parents + // any profiler started during the time of another is held in + // DVPROFSTRUCT::listpChild +list g_listAllProfilers; // ignores the hierarchy, pointer to elements in g_listProfilers + +void DVProfRegister(char* pname) +{ + if( !g_bWriteProfile ) + return; + + list::iterator it = g_listAllProfilers.begin(); + +// while(it != g_listAllProfilers.end() ) { +// +// if( _tcscmp(pname, (*it)->pname) == 0 ) { +// (*it)->listTimes.push_back(timeGetTime()); +// DVPROFTRACK dvtrack; +// dvtrack.pdwTime = &(*it)->listTimes.back(); +// dvtrack.pprof = *it; +// g_listCurTracking.push_back(dvtrack); +// return; +// } +// +// ++it; +// } + + // else add in a new profiler to the appropriate parent profiler + DVPROFSTRUCT* pprof = NULL; + + if( g_listCurTracking.size() > 0 ) { + assert( g_listCurTracking.back().pprof != NULL ); + g_listCurTracking.back().pprof->listpChild.push_back(new DVPROFSTRUCT()); + pprof = g_listCurTracking.back().pprof->listpChild.back(); + } + else { + g_listProfilers.push_back(DVPROFSTRUCT()); + pprof = &g_listProfilers.back(); + } + + strncpy(pprof->pname, pname, 256); + + // setup the profiler for tracking + pprof->listTimes.push_back(DVPROFSTRUCT::DATA(GET_PROFILE_TIME())); + + DVPROFTRACK dvtrack; + dvtrack.pdwTime = &pprof->listTimes.back(); + dvtrack.pprof = pprof; + dvtrack.dwUserData = 0; + + g_listCurTracking.push_back(dvtrack); + + // add to all profiler list + g_listAllProfilers.push_back(pprof); +} + +void DVProfEnd(u32 dwUserData) +{ + if( !g_bWriteProfile ) + return; + B_RETURN( g_listCurTracking.size() > 0 ); + + DVPROFTRACK dvtrack = g_listCurTracking.back(); + + assert( dvtrack.pdwTime != NULL && dvtrack.pprof != NULL ); + + dvtrack.pdwTime->dwTime = 1000000 * (GET_PROFILE_TIME()- dvtrack.pdwTime->dwTime) / luPerfFreq; + dvtrack.pdwTime->dwUserData= dwUserData; + + g_listCurTracking.pop_back(); +} + +struct DVTIMEINFO +{ + DVTIMEINFO() : uInclusive(0), uExclusive(0) {} + u64 uInclusive, uExclusive; +}; + +map mapAggregateTimes; + +u64 DVProfWriteStruct(FILE* f, DVPROFSTRUCT* p, int ident) +{ + fprintf(f, "%*s%s - ", ident, "", p->pname); + + list::iterator ittime = p->listTimes.begin(); + + u32 utime = 0; + + while(ittime != p->listTimes.end() ) { + utime += (u32)ittime->dwTime; + + if( ittime->dwUserData ) + fprintf(f, "time: %d, user: 0x%8.8x", (u32)ittime->dwTime, ittime->dwUserData); + else + fprintf(f, "time: %d", (u32)ittime->dwTime); + ++ittime; + } + + mapAggregateTimes[p->pname].uInclusive += utime; + + fprintf(f, "\n"); + + list::iterator itprof = p->listpChild.begin(); + + u32 uex = utime; + while(itprof != p->listpChild.end() ) { + + uex -= DVProfWriteStruct(f, *itprof, ident+4); + ++itprof; + } + + mapAggregateTimes[p->pname].uExclusive += uex; + return utime; +} + +void DVProfWrite(char* pfilename, u32 frames) +{ + assert( pfilename != NULL ); + FILE* f = fopen(pfilename, "wb"); + + mapAggregateTimes.clear(); + list::iterator it = g_listProfilers.begin(); + + while(it != g_listProfilers.end() ) { + DVProfWriteStruct(f, &(*it), 0); + ++it; + } + + { + map::iterator it; + fprintf(f, "\n\n-------------------------------------------------------------------\n\n"); + + u64 uTotal[2] = {0}; + double fiTotalTime[2]; + + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + uTotal[0] += it->second.uExclusive; + uTotal[1] += it->second.uInclusive; + } + + fprintf(f, "total times (%d): ex: %Lu ", frames, uTotal[0]/frames); + fprintf(f, "inc: %Lu\n", uTotal[1]/frames); + + fiTotalTime[0] = 1.0 / (double)uTotal[0]; + fiTotalTime[1] = 1.0 / (double)uTotal[1]; + + // output the combined times + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + fprintf(f, "%s - ex: %f inc: %f\n", it->first.c_str(), (double)it->second.uExclusive * fiTotalTime[0], + (double)it->second.uInclusive * fiTotalTime[1]); + } + } + + + fclose(f); +} + +void DVProfClear() +{ + g_listCurTracking.clear(); + g_listProfilers.clear(); + g_listAllProfilers.clear(); +} diff --git a/plugins/gs/zerogs/opengl/Linux/Conf.cpp b/plugins/gs/zerogs/opengl/Linux/Conf.cpp new file mode 100644 index 0000000000..3d75acd3bf --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/Conf.cpp @@ -0,0 +1,104 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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 +#include +#include +#include +#include +#include +#include "GS.h" + +extern string s_strIniPath; + +void SaveConfig() { + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("failed to open %s\n", s_strIniPath.c_str()); + return; + } + fprintf(f, "interlace = %x\n", conf.interlace); + fprintf(f, "aliasing = %x\n", conf.aa); + fprintf(f, "bilinear = %x\n", conf.bilinear); + fprintf(f, "options = %x\n", conf.options); + fprintf(f, "gamesettings = %x\n", conf.gamesettings); + fclose(f); +} + +void LoadConfig() { + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg, "r"); + if (f == NULL) { + printf("failed to open %s\n", s_strIniPath.c_str()); + SaveConfig();//save and return + return; + } + fscanf(f, "interlace = %x\n", &conf.interlace); + fscanf(f, "aliasing = %x\n", &conf.aa); + fscanf(f, "bilinear = %x\n", &conf.bilinear); + fscanf(f, "options = %x\n", &conf.options); + fscanf(f, "gamesettings = %x\n", &conf.gamesettings); + fclose(f); + + // filter bad files + if( conf.aa < 0 || conf.aa > 2 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} + diff --git a/plugins/gs/zerogs/opengl/Linux/Linux.cpp b/plugins/gs/zerogs/opengl/Linux/Linux.cpp new file mode 100644 index 0000000000..394ad9c687 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/Linux.cpp @@ -0,0 +1,425 @@ +/* ZeroGS + * Copyright (C) 2002-2004 GSsoft 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 +#include +#include +#include +#include + +#include "GS.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +#include "Linux.h" + +#include + +static int prevbilinearfilter; +//static map mapConfOpts; +struct confOptsStruct{ + int value; + char *desc; +}confOpts; +static map mapConfOpts; + +extern void OnKeyboardF5(int); +extern void OnKeyboardF6(int); +extern void OnKeyboardF7(int); +extern void OnKeyboardF9(int); + +void CALLBACK GSkeyEvent(keyEvent *ev) +{ + static bool bShift = false; + static bool bAlt = false; + + switch(ev->event) { + case KEYPRESS: + switch(ev->key) { + case XK_F5: + OnKeyboardF5(bShift); + break; + case XK_F6: + OnKeyboardF6(bShift); + break; + case XK_F7: + OnKeyboardF7(bShift); + break; + case XK_F9: + OnKeyboardF9(bShift); + break; + case XK_Escape: + break; + case XK_Shift_L: + case XK_Shift_R: + bShift = true; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = true; + break; + } + break; + case KEYRELEASE: + switch(ev->key) { + case XK_Shift_L: + case XK_Shift_R: + bShift = false; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = false; + break; + } + } +} + +GtkWidget *Conf; +GtkWidget *Logging; +GList *fresl; +GList *wresl; +GList *cachesizel; +GList *codecl; +GList *filtersl; + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ + GtkWidget *Btn; + GtkWidget *treeview; + GtkTreeModel *treemodel; + GtkTreeIter treeiter; + gboolean treeoptval; + gchar *gbuf; + char *str; + int i; + + u32 newinterlace = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkInterlace"))); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkBilinear"))); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioAANone"))) ) { + conf.aa = 0; + } + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioAA2X"))) ) { + conf.aa = 1; + } + else conf.aa = 2; + + conf.options = 0; + conf.options |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkAVI"))) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkWireframe"))) ? GSOPTION_WIREFRAME : 0; + conf.options |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton6"))) ? GSOPTION_FULLSCREEN : 0; + conf.options |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkTGA"))) ? GSOPTION_TGASNAP : 0; + + //------- get advanced options from the treeview model -------// + treeview = lookup_widget(Conf,"treeview1"); + treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + gtk_tree_model_get_iter_first(treemodel, &treeiter); + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + treeoptval = FALSE; + gtk_tree_model_get(treemodel, &treeiter, + 0, &treeoptval, + -1); + if(treeoptval){ + conf.gamesettings |= it->second.value; + } + gtk_tree_model_iter_next(treemodel,&treeiter); + } + GSsetGameCRC(0, conf.gamesettings); + //---------- done getting advanced options ---------// + + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize640"))) ) + conf.options |= GSOPTION_WIN640; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize800"))) ) + conf.options |= GSOPTION_WIN800; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize1024"))) ) + conf.options |= GSOPTION_WIN1024; + else if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize1280"))) ) + conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CALLBACK GSconfigure() +{ + char name[32]; + char descbuf[255]; + int nmodes, i; + bool itval; + GtkWidget *treeview; + GtkCellRenderer *treerend; + GtkListStore *treestore;//Gets typecast as GtkTreeModel as needed. + GtkTreeIter treeiter; + GtkTreeViewColumn *treecol; + + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + Conf = create_Config(); + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkBilinear")), !!conf.bilinear); + //gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton6")), conf.mrtdepth); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioAANone")), conf.aa==0); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioAA2X")), conf.aa==1); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioAA4X")), conf.aa==2); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkWireframe")), (conf.options&GSOPTION_WIREFRAME)?1:0); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkAVI")), (conf.options&GSOPTION_CAPTUREAVI)?1:0); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton6")), (conf.options&GSOPTION_FULLSCREEN)?1:0); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkTGA")), (conf.options&GSOPTION_TGASNAP)?1:0); + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize640")), ((conf.options&GSOPTION_WINDIMS)>>4)==0); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize800")), ((conf.options&GSOPTION_WINDIMS)>>4)==1); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize1024")), ((conf.options&GSOPTION_WINDIMS)>>4)==2); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "radioSize1280")), ((conf.options&GSOPTION_WINDIMS)>>4)==3); + + prevbilinearfilter = conf.bilinear; + + //--------- Let's build a treeview for our advanced options! --------// + treeview = lookup_widget(Conf,"treeview1"); + treestore = gtk_list_store_new(2,G_TYPE_BOOLEAN, G_TYPE_STRING); + + //setup columns in treeview + //COLUMN 0 is the checkboxes + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Select"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "active", 0);//link 'active' attrib to first column of model + g_object_set(treerend, "activatable", TRUE, NULL);//set 'activatable' attrib true by default for all rows regardless of model. + g_signal_connect(treerend, "toggled", (GCallback) OnToggle_advopts, treestore);//set a global callback, we also pass a reference to our treestore. + + //COLUMN 1 is the text descriptions + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Description"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "text", 1);//link 'text' attrib to second column of model + + //setup the model with all our rows of option data + mapConfOpts.clear(); + confOpts.value = 0x00000001; + confOpts.desc = "Tex Target checking - 00000001\nLego Racers"; + mapConfOpts["00000001"] = confOpts; + confOpts.value = 0x00000002; + confOpts.desc = "Auto reset targs - 00000002\nShadow Hearts, Samurai Warriors. Use when game is slow and toggling AA fixes it."; + mapConfOpts["00000002"] = confOpts; + confOpts.value = 0x00000004; + confOpts.desc = "Interlace 2X - 00000004\nFixes 2x bigger screen (Gradius 3)."; + mapConfOpts["00000004"] = confOpts; + confOpts.value = 0x00000008; + confOpts.desc = "Text Alpha hack - 00000008\nNightmare Before Christmas."; + mapConfOpts["00000008"] = confOpts; + confOpts.value = 0x00000010; + confOpts.desc = "No target resolves - 00000010\nStops all resolving of targets. Try this first for really slow games."; + mapConfOpts["00000010"] = confOpts; + confOpts.value = 0x00000020; + confOpts.desc = "Exact color testing - 00000020\nFixes overbright or shadow/black artifacts (Crash 'n Burn)."; + mapConfOpts["00000020"] = confOpts; + confOpts.value = 0x00000040; + confOpts.desc = "No color clamping - 00000040\nSpeeds up games, but might be too bright or too dim."; + mapConfOpts["00000040"] = confOpts; + confOpts.value = 0x00000080; + confOpts.desc = "FFX hack - 00000080\nShows missing geometry."; + mapConfOpts["00000080"] = confOpts; + confOpts.value = 0x00000200; + confOpts.desc = "Disable depth updates - 00000200"; + mapConfOpts["00000200"] = confOpts; + confOpts.value = 0x00000400; + confOpts.desc = "Resolve Hack #1 - 00000400\nKingdom Hearts. Speeds some games."; + mapConfOpts["00000400"] = confOpts; + confOpts.value = 0x00000800; + confOpts.desc = "Resolve Hack #2 - 00000800\nShadow Hearts, Urbz."; + mapConfOpts["00000800"] = confOpts; + confOpts.value = 0x00001000; + confOpts.desc = "No target CLUT - 00001000\nResident Evil 4, or foggy scenes."; + mapConfOpts["00001000"] = confOpts; + confOpts.value = 0x00002000; + confOpts.desc = "Disable stencil buffer - 00002000\nUsually safe to do for simple scenes."; + mapConfOpts["00002000"] = confOpts; + confOpts.value = 0x00004000; + confOpts.desc = "No vertical stripes - 00004000\nTry when there's a lot of garbage on screen."; + mapConfOpts["00004000"] = confOpts; + confOpts.value = 0x00008000; + confOpts.desc = "No depth resolve - 00008000\nMight give z buffer artifacts."; + mapConfOpts["00008000"] = confOpts; + confOpts.value = 0x00010000; + confOpts.desc = "Full 16 bit resolution - 00010000\nUse when half the screen is missing."; + mapConfOpts["00010000"] = confOpts; + confOpts.value = 0x00020000; + confOpts.desc = "Resolve Hack #3 - 00020000\nNeopets"; + mapConfOpts["00020000"] = confOpts; + confOpts.value = 0x00040000; + confOpts.desc = "Fast Update - 00040000\nOkami. Speeds some games."; + mapConfOpts["00040000"] = confOpts; + confOpts.value = 0x00080000; + confOpts.desc = "Disable alpha testing - 00080000"; + mapConfOpts["00080000"] = confOpts; + confOpts.value = 0x00100000; + confOpts.desc = "Disable Multiple RTs - 00100000"; + mapConfOpts["00100000"] = confOpts; + confOpts.value = 0x00200000; + confOpts.desc = "32 bit render targets - 00200000"; + mapConfOpts["00200000"] = confOpts; + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + gtk_list_store_append(treestore, &treeiter);//new row + itval = (conf.gamesettings&it->second.value)?TRUE:FALSE; + snprintf(descbuf, 254, "%s", it->second.desc); + gtk_list_store_set(treestore, &treeiter, + 0, itval, + 1, descbuf, + -1); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));//NB: store is cast as tree model. + g_object_unref(treestore);//allow model to be destroyed when the tree is destroyed. + + //don't select/highlight rows + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_NONE); + //------treeview done -------// + + //Let's do it! + gtk_widget_show_all(Conf); + gtk_main(); +} + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data){ + GtkTreeIter treeiter; + gboolean val; + + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &treeiter, path); + gtk_tree_model_get(GTK_TREE_MODEL(user_data), &treeiter, + 0, &val, + -1); + val = !val; + gtk_list_store_set(GTK_LIST_STORE(user_data), &treeiter, + 0, val, + -1); + +} + + + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK GSabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK GStest() { + return 0; +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void *SysLoadLibrary(char *lib) { + return dlopen(lib, RTLD_NOW | RTLD_GLOBAL); +} + +void *SysLoadSym(void *lib, char *sym) { + void *ret = dlsym(lib, sym); + if (ret == NULL) printf("null: %s\n", sym); + return dlsym(lib, sym); +} + +char *SysLibError() { + return dlerror(); +} + +void SysCloseLibrary(void *lib) { + dlclose(lib); +} diff --git a/plugins/gs/zerogs/opengl/Linux/Linux.h b/plugins/gs/zerogs/opengl/Linux/Linux.h new file mode 100644 index 0000000000..baf4053d95 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/Linux.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2002-2004 GSsoft 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 + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ +#endif + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data); diff --git a/plugins/gs/zerogs/opengl/Linux/Makefile.am b/plugins/gs/zerogs/opengl/Linux/Makefile.am new file mode 100644 index 0000000000..43f3fcb6d2 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/Makefile.am @@ -0,0 +1,6 @@ +noinst_LIBRARIES = libZeroGSLinux.a +libZeroGSLinux_a_CPPFLAGS = -fPIC +libZeroGSLinux_a_CXXFLAGS = -fPIC +libZeroGSLinux_a_CFLAGS = -fPIC +INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I../ +libZeroGSLinux_a_SOURCES = callbacks.c Conf.cpp interface.c Linux.cpp support.c diff --git a/plugins/gs/zerogs/opengl/Linux/buildgui.sh b/plugins/gs/zerogs/opengl/Linux/buildgui.sh new file mode 100644 index 0000000000..9f0d1fcefb --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/buildgui.sh @@ -0,0 +1,9 @@ +# builds the GUI C classes +mkdir temp +cp zerogs.glade temp/ +cd temp +glade-2 --write-source zerogs.glade +rm src/main.c +cp src/*.h src/*.c ../ +cd .. +/bin/rm -rf temp diff --git a/plugins/gs/zerogs/opengl/Linux/callbacks.c b/plugins/gs/zerogs/opengl/Linux/callbacks.c new file mode 100644 index 0000000000..e87ed8be2d --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/gs/zerogs/opengl/Linux/callbacks.h b/plugins/gs/zerogs/opengl/Linux/callbacks.h new file mode 100644 index 0000000000..e606c242f0 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/gs/zerogs/opengl/Linux/interface.c b/plugins/gs/zerogs/opengl/Linux/interface.c new file mode 100644 index 0000000000..1519602b1b --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/interface.c @@ -0,0 +1,325 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox4; + GtkWidget *checkInterlace; + GtkWidget *checkBilinear; + GtkWidget *frame4; + GtkWidget *alignment1; + GtkWidget *hbox6; + GtkWidget *radioAANone; + GSList *radioAANone_group = NULL; + GtkWidget *radioAA2X; + GtkWidget *radioAA4X; + GtkWidget *label9; + GtkWidget *checkWireframe; + GtkWidget *checkAVI; + GtkWidget *checkTGA; + GtkWidget *checkbutton6; + GtkWidget *frame5; + GtkWidget *alignment2; + GtkWidget *hbox7; + GtkWidget *radioSize640; + GSList *radioSize640_group = NULL; + GtkWidget *radioSize800; + GtkWidget *radioSize1024; + GtkWidget *radioSize1280; + GtkWidget *label10; + GtkWidget *frame6; + GtkWidget *alignment3; + GtkWidget *scrolledwindow1; + GtkWidget *treeview1; + GtkWidget *label12; + GtkWidget *label11; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), _("ZeroOGS Configuration")); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (Config), vbox4); + + checkInterlace = gtk_check_button_new_with_mnemonic (_("Interlace Enable (toggle with F5)\n there are 2 modes + interlace off")); + gtk_widget_show (checkInterlace); + gtk_box_pack_start (GTK_BOX (vbox4), checkInterlace, FALSE, FALSE, 0); + + checkBilinear = gtk_check_button_new_with_mnemonic (_("Bilinear Filtering (Shift+F5)\n Best quality is on, turn off for speed")); + gtk_widget_show (checkBilinear); + gtk_box_pack_start (GTK_BOX (vbox4), checkBilinear, FALSE, FALSE, 0); + + frame4 = gtk_frame_new (NULL); + gtk_widget_show (frame4); + gtk_box_pack_start (GTK_BOX (vbox4), frame4, TRUE, TRUE, 0); + + alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (frame4), alignment1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1), 0, 0, 12, 0); + + hbox6 = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox6); + gtk_container_add (GTK_CONTAINER (alignment1), hbox6); + + radioAANone = gtk_radio_button_new_with_mnemonic (NULL, _("None")); + gtk_widget_show (radioAANone); + gtk_box_pack_start (GTK_BOX (hbox6), radioAANone, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAANone), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAANone)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radioAANone), TRUE); + + radioAA2X = gtk_radio_button_new_with_mnemonic (NULL, _("2X")); + gtk_widget_show (radioAA2X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA2X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA2X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA2X)); + + radioAA4X = gtk_radio_button_new_with_mnemonic (NULL, _("4X")); + gtk_widget_show (radioAA4X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA4X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA4X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA4X)); + + label9 = gtk_label_new (_("Anti-aliasing for higher quality (F6)")); + gtk_widget_show (label9); + gtk_frame_set_label_widget (GTK_FRAME (frame4), label9); + gtk_label_set_use_markup (GTK_LABEL (label9), TRUE); + + checkWireframe = gtk_check_button_new_with_mnemonic (_("Wireframe rendering (Shift+F6)")); + gtk_widget_show (checkWireframe); + gtk_box_pack_start (GTK_BOX (vbox4), checkWireframe, FALSE, FALSE, 0); + + checkAVI = gtk_check_button_new_with_mnemonic (_("Capture Avi (zerogs.avi)(F7)")); + gtk_widget_show (checkAVI); + gtk_box_pack_start (GTK_BOX (vbox4), checkAVI, FALSE, FALSE, 0); + + checkTGA = gtk_check_button_new_with_mnemonic (_("Save Snapshots as TGAs (default is JPG)")); + gtk_widget_show (checkTGA); + gtk_box_pack_start (GTK_BOX (vbox4), checkTGA, FALSE, FALSE, 0); + + checkbutton6 = gtk_check_button_new_with_mnemonic (_("Fullscreen (Alt+Enter)\n to get out press Alt+Enter again (or ESC)")); + gtk_widget_show (checkbutton6); + gtk_box_pack_start (GTK_BOX (vbox4), checkbutton6, FALSE, FALSE, 0); + + frame5 = gtk_frame_new (NULL); + gtk_widget_show (frame5); + gtk_box_pack_start (GTK_BOX (vbox4), frame5, TRUE, TRUE, 0); + + alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (frame5), alignment2); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment2), 0, 0, 12, 0); + + hbox7 = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox7); + gtk_container_add (GTK_CONTAINER (alignment2), hbox7); + + radioSize640 = gtk_radio_button_new_with_mnemonic (NULL, _("640x480")); + gtk_widget_show (radioSize640); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize640, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize640), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize640)); + + radioSize800 = gtk_radio_button_new_with_mnemonic (NULL, _("800x600")); + gtk_widget_show (radioSize800); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize800, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize800), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize800)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radioSize800), TRUE); + + radioSize1024 = gtk_radio_button_new_with_mnemonic (NULL, _("1024x768")); + gtk_widget_show (radioSize1024); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize1024, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize1024), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize1024)); + + radioSize1280 = gtk_radio_button_new_with_mnemonic (NULL, _("1280x960")); + gtk_widget_show (radioSize1280); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize1280, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize1280), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize1280)); + + label10 = gtk_label_new (_("Default Window Size (no speed impact)")); + gtk_widget_show (label10); + gtk_frame_set_label_widget (GTK_FRAME (frame5), label10); + gtk_label_set_use_markup (GTK_LABEL (label10), TRUE); + + frame6 = gtk_frame_new (NULL); + gtk_widget_show (frame6); + gtk_box_pack_start (GTK_BOX (vbox4), frame6, TRUE, TRUE, 0); + + alignment3 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (frame6), alignment3); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3), 0, 0, 12, 0); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_container_add (GTK_CONTAINER (alignment3), scrolledwindow1); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN); + + treeview1 = gtk_tree_view_new (); + gtk_widget_show (treeview1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), treeview1); + + label12 = gtk_label_new (_("Advanced Options")); + gtk_widget_show (label12); + gtk_frame_set_label_widget (GTK_FRAME (frame6), label12); + gtk_label_set_use_markup (GTK_LABEL (label12), TRUE); + + label11 = gtk_label_new (_("Show Frames Per Second (Shift+F7)\n (value is the average over 4-16 PS2 frames)")); + gtk_widget_show (label11); + gtk_box_pack_start (GTK_BOX (vbox4), label11, FALSE, FALSE, 0); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox4), hbuttonbox1, TRUE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 30); + + button1 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button1, "clicked", + G_CALLBACK (OnConf_Ok), + NULL); + g_signal_connect ((gpointer) button2, "clicked", + G_CALLBACK (OnConf_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Config, Config, "Config"); + GLADE_HOOKUP_OBJECT (Config, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (Config, checkInterlace, "checkInterlace"); + GLADE_HOOKUP_OBJECT (Config, checkBilinear, "checkBilinear"); + GLADE_HOOKUP_OBJECT (Config, frame4, "frame4"); + GLADE_HOOKUP_OBJECT (Config, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (Config, hbox6, "hbox6"); + GLADE_HOOKUP_OBJECT (Config, radioAANone, "radioAANone"); + GLADE_HOOKUP_OBJECT (Config, radioAA2X, "radioAA2X"); + GLADE_HOOKUP_OBJECT (Config, radioAA4X, "radioAA4X"); + GLADE_HOOKUP_OBJECT (Config, label9, "label9"); + GLADE_HOOKUP_OBJECT (Config, checkWireframe, "checkWireframe"); + GLADE_HOOKUP_OBJECT (Config, checkAVI, "checkAVI"); + GLADE_HOOKUP_OBJECT (Config, checkTGA, "checkTGA"); + GLADE_HOOKUP_OBJECT (Config, checkbutton6, "checkbutton6"); + GLADE_HOOKUP_OBJECT (Config, frame5, "frame5"); + GLADE_HOOKUP_OBJECT (Config, alignment2, "alignment2"); + GLADE_HOOKUP_OBJECT (Config, hbox7, "hbox7"); + GLADE_HOOKUP_OBJECT (Config, radioSize640, "radioSize640"); + GLADE_HOOKUP_OBJECT (Config, radioSize800, "radioSize800"); + GLADE_HOOKUP_OBJECT (Config, radioSize1024, "radioSize1024"); + GLADE_HOOKUP_OBJECT (Config, radioSize1280, "radioSize1280"); + GLADE_HOOKUP_OBJECT (Config, label10, "label10"); + GLADE_HOOKUP_OBJECT (Config, frame6, "frame6"); + GLADE_HOOKUP_OBJECT (Config, alignment3, "alignment3"); + GLADE_HOOKUP_OBJECT (Config, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (Config, treeview1, "treeview1"); + GLADE_HOOKUP_OBJECT (Config, label12, "label12"); + GLADE_HOOKUP_OBJECT (Config, label11, "label11"); + GLADE_HOOKUP_OBJECT (Config, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (Config, button1, "button1"); + GLADE_HOOKUP_OBJECT (Config, button2, "button2"); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *label4; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), _("ZeroGS KOSMOS About")); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new (_("OpenGL version")); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER); + + label3 = gtk_label_new (_("Author: zerofrog(@gmail.com)")); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + + label4 = gtk_label_new (_("Many thanks to the Pcsx2 testing team")); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (vbox2), label4, FALSE, FALSE, 0); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox2), 30); + + button3 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button3, "clicked", + G_CALLBACK (OnAbout_Ok), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (About, About, "About"); + GLADE_HOOKUP_OBJECT (About, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (About, label2, "label2"); + GLADE_HOOKUP_OBJECT (About, label3, "label3"); + GLADE_HOOKUP_OBJECT (About, label4, "label4"); + GLADE_HOOKUP_OBJECT (About, hbuttonbox2, "hbuttonbox2"); + GLADE_HOOKUP_OBJECT (About, button3, "button3"); + + return About; +} + diff --git a/plugins/gs/zerogs/opengl/Linux/interface.h b/plugins/gs/zerogs/opengl/Linux/interface.h new file mode 100644 index 0000000000..69c303ba3b --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/gs/zerogs/opengl/Linux/support.c b/plugins/gs/zerogs/opengl/Linux/support.c new file mode 100644 index 0000000000..00aff29822 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/gs/zerogs/opengl/Linux/support.h b/plugins/gs/zerogs/opengl/Linux/support.h new file mode 100644 index 0000000000..a32649e53c --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/gs/zerogs/opengl/Linux/zerogs.glade b/plugins/gs/zerogs/opengl/Linux/zerogs.glade new file mode 100644 index 0000000000..3718afcca9 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Linux/zerogs.glade @@ -0,0 +1,674 @@ + + + + + + + 5 + True + ZeroOGS Configuration + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + True + Interlace Enable (toggle with F5) + there are 2 modes + interlace off + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Bilinear Filtering (Shift+F5) + Best quality is on, turn off for speed + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + 0 + + + + True + True + None + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + + True + True + 2X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + True + True + 4X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + + + + + True + <b>Anti-aliasing for higher quality (F6)</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + True + Wireframe rendering (Shift+F6) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Capture Avi (zerogs.avi)(F7) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Save Snapshots as TGAs (default is JPG) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Fullscreen (Alt+Enter) + to get out press Alt+Enter again (or ESC) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + 0 + + + + True + True + 640x480 + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + 800x600 + True + GTK_RELIEF_NORMAL + True + True + False + True + radioSize640 + + + 0 + False + False + + + + + + True + True + 1024x768 + True + GTK_RELIEF_NORMAL + True + False + False + True + radioSize640 + + + 0 + False + False + + + + + + True + True + 1280x960 + True + GTK_RELIEF_NORMAL + True + False + False + True + radioSize640 + + + 0 + False + False + + + + + + + + + + True + <b>Default Window Size (no speed impact)</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + + + + + + True + <b>Advanced Options</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + Show Frames Per Second (Shift+F7) + (value is the average over 4-16 PS2 frames) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_SPREAD + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + ZeroGS KOSMOS About + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + OpenGL version + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Author: zerofrog(@gmail.com) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Many thanks to the Pcsx2 testing team + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + diff --git a/plugins/gs/zerogs/opengl/Makefile.am b/plugins/gs/zerogs/opengl/Makefile.am new file mode 100644 index 0000000000..f0bc0d754c --- /dev/null +++ b/plugins/gs/zerogs/opengl/Makefile.am @@ -0,0 +1,48 @@ +# Create a shared library libZeroGSogl +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroGSogl.a + +libZeroGSogl_a_CPPFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroGSogl_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroGSogl_a_CPPFLAGS += -fPIC +libZeroGSogl_a_CXXFLAGS += -fPIC +CCASFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + + +if RELEASE_TO_PUBLIC +preext=r +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroGSogl +libZeroGSogl_SOURCES= +libZeroGSogl_DEPENDENCIES = libZeroGSogl.a +libZeroGSogl_LDFLAGS= @SHARED_LDFLAGS@ +libZeroGSogl_LDFLAGS+=-Wl,-soname,@ZEROGS_SONAME@ +libZeroGSogl_LDADD=$(libZeroGSogl_a_OBJECTS) + +libZeroGSogl_a_SOURCES = \ +GSmain.cpp memcpy_amd.cpp Regs.cpp x86.cpp zpipe.cpp \ +Mem.cpp rasterfont.cpp targets.cpp zerogs.cpp + +if X86_64 +libZeroGSogl_a_SOURCES += x86-64.S +else +libZeroGSogl_a_SOURCES += x86-32.S +endif + +if SSE2 +CCASFLAGS+= -DZEROGS_SSE2 +endif + +libZeroGSogl_a_DEPENDENCIES = Linux/libZeroGSLinux.a +libZeroGSogl_LDADD += Linux/libZeroGSLinux.a + +SUBDIRS = Linux . diff --git a/plugins/gs/zerogs/opengl/Mem.cpp b/plugins/gs/zerogs/opengl/Mem.cpp new file mode 100644 index 0000000000..1c5b49fbc5 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Mem.cpp @@ -0,0 +1,903 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static PCSX2_ALIGNED16(u32 tempblock[64]); + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int pitch, area, fracX; \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ + if( testwidth <= widthlimit && testwidth >= -widthlimit ) { \ + /* don't transfer */ \ + /*printf("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + pitch = gs.imageEndX-gs.trxpos.dx; \ + area = pitch*blockheight; \ + fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*printf("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = Vector(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh, 0, 0); \ + b.vTexBlock = Vector((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + psrcw = (u16*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( floatfmt ) { \ + psrcf[i*BLOCK_TEXWIDTH+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*BLOCK_TEXWIDTH+j] = u; \ + } \ + } \ + } \ + \ + if( floatfmt ) { \ + assert( floatfmt ); \ + psrcv = (Vector*)&vBilinearData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + Vector* pv = &psrcv[i*BLOCK_TEXWIDTH+j]; \ + pv->x = psrcf[i*BLOCK_TEXWIDTH+j]; \ + pv->y = psrcf[i*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+j]; \ + pv->w = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(vector& vBlockData, vector& vBilinearData, int floatfmt) +{ + vBlockData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * (floatfmt ? 4 : 2)); + if( floatfmt ) + vBilinearData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * sizeof(Vector)); + + int i, j; + BLOCK b; + float* psrcf = NULL; + u16* psrcw = NULL; + Vector* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/gs/zerogs/opengl/Mem.h b/plugins/gs/zerogs/opengl/Mem.h new file mode 100644 index 0000000000..88d1d98fbd --- /dev/null +++ b/plugins/gs/zerogs/opengl/Mem.h @@ -0,0 +1,487 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __MEM_H__ +#define __MEM_H__ + +#include +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + Vector vTexBlock; + Vector vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(std::vector& vBlockData, std::vector& vBilinearData, int floatfmt); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +__forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +__forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +__forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +__forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +__forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +__forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +__forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +__forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +__forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +__forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +__forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +__forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +__forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +__forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +__forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +__forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +__forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +__forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +__forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +__forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +__forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +__forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +__forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +__forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +__forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +__forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +__forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +__forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +__forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +__forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +__forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +__forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +__forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +__forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +__forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +__forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +__forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +__forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +__forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +__forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +__forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +__forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +__forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +__forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +__forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +__forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +__forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +__forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/gs/zerogs/opengl/PS2Edefs.h b/plugins/gs/zerogs/opengl/PS2Edefs.h new file mode 100644 index 0000000000..223a03410f --- /dev/null +++ b/plugins/gs/zerogs/opengl/PS2Edefs.h @@ -0,0 +1,855 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBasync USBasync; + +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/gs/zerogs/opengl/PS2Etypes.h b/plugins/gs/zerogs/opengl/PS2Etypes.h new file mode 100644 index 0000000000..101dba9491 --- /dev/null +++ b/plugins/gs/zerogs/opengl/PS2Etypes.h @@ -0,0 +1,88 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifdef _WIN32 +#include +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#define PCSX2_ALIGNED16_DECL(x) x + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/gs/zerogs/opengl/README.txt b/plugins/gs/zerogs/opengl/README.txt new file mode 100644 index 0000000000..edeb776031 --- /dev/null +++ b/plugins/gs/zerogs/opengl/README.txt @@ -0,0 +1,13 @@ +ZeroGS OpenGL +------------- +author: zerofrog (@gmail.com) + +ZeroGS heavily uses GPU shaders. All the shaders are written in nVidia's Cg language and can be found in ps2hw.fx. + +'Dev' versions of ZeroGS directly read ps2hw.fx +'Release' versions of ZeroGS read a precompiled version of ps2hw.fx from ps2hw.dat. In order to build ps2hw.dat, compile ZeroGSShaders and execute: + +./ZeroGSShaders ps2hw.fx ps2hw.dat + +For Windows users, once ZeroGSShaders is built, run buildshaders.bat directly. It will update all necessary resource files. +Note that ZeroGSShaders has only been tested in Windows so far, but the Windows ps2hw.dat can be used in linux builds. \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/Regs.cpp b/plugins/gs/zerogs/opengl/Regs.cpp new file mode 100644 index 0000000000..96e4c13f74 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Regs.cpp @@ -0,0 +1,1007 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerorog@gmail.com + * + * 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 +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +#ifdef __MSCW32__ +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void FASTCALL(GIFPackedRegHandlerNull(u32* data)) +{ +#ifdef _DEBUG + printf("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +#endif +} + +void FASTCALL(GIFPackedRegHandlerRGBA(u32* data)) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void FASTCALL(GIFPackedRegHandlerSTQ(u32* data)) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void FASTCALL(GIFPackedRegHandlerUV(u32* data)) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +#define KICK_VERTEX2() { \ + if( ++gs.primC >= (int)g_primmult[prim->prim]) { \ + if( !(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk ) \ + (*ZeroGS::drawfn[prim->prim])(); \ + gs.primC -= g_primsub[prim->prim]; \ + } \ +} \ + +#define KICK_VERTEX3() { \ + if( ++gs.primC >= (int)g_primmult[prim->prim] ) { \ + gs.primC -= g_primsub[prim->prim]; \ + if( prim->prim == 5 ) { \ + /* tri fans need special processing */ \ + if( gs.nTriFanVert == gs.primIndex ) \ + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); \ + } \ + } \ +} \ + +void FASTCALL(GIFPackedRegHandlerXYZF2(u32* data)) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void FASTCALL(GIFPackedRegHandlerXYZ2(u32* data)) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void FASTCALL(GIFPackedRegHandlerFOG(u32* data)) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void FASTCALL(GIFPackedRegHandlerA_D(u32* data)) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void FASTCALL(GIFPackedRegHandlerNOP(u32* data)) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void FASTCALL(GIFRegHandlerNull(u32* data)) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + printf("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void FASTCALL(GIFRegHandlerPRIM(u32 *data)) +{ + if (data[0] & ~0x3ff) { +#ifdef WARN_LOG + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); +#endif + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void FASTCALL(GIFRegHandlerRGBAQ(u32* data)) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void FASTCALL(GIFRegHandlerST(u32* data)) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void FASTCALL(GIFRegHandlerUV(u32* data)) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void FASTCALL(GIFRegHandlerXYZF2(u32* data)) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void FASTCALL(GIFRegHandlerXYZ2(u32* data)) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void FASTCALL(GIFRegHandlerTEX0_1(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void FASTCALL(GIFRegHandlerTEX0_2(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void FASTCALL(GIFRegHandlerCLAMP_1(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void FASTCALL(GIFRegHandlerCLAMP_2(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void FASTCALL(GIFRegHandlerFOG(u32* data)) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void FASTCALL(GIFRegHandlerXYZF3(u32* data)) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void FASTCALL(GIFRegHandlerXYZ3(u32* data)) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void FASTCALL(GIFRegHandlerNOP(u32* data)) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void FASTCALL(GIFRegHandlerTEX1_1(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void FASTCALL(GIFRegHandlerTEX1_2(u32* data)) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void FASTCALL(GIFRegHandlerTEX2_1(u32* data)) +{ + tex2Write(0, data); +} + +void FASTCALL(GIFRegHandlerTEX2_2(u32* data)) +{ + tex2Write(1, data); +} + +void FASTCALL(GIFRegHandlerXYOFFSET_1(u32* data)) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void FASTCALL(GIFRegHandlerXYOFFSET_2(u32* data)) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void FASTCALL(GIFRegHandlerPRMODECONT(u32* data)) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void FASTCALL(GIFRegHandlerPRMODE(u32* data)) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void FASTCALL(GIFRegHandlerTEXCLUT(u32* data)) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void FASTCALL(GIFRegHandlerSCANMSK(u32* data)) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void FASTCALL(GIFRegHandlerMIPTBP1_1(u32* data)) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void FASTCALL(GIFRegHandlerMIPTBP1_2(u32* data)) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void FASTCALL(GIFRegHandlerMIPTBP2_1(u32* data)) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void FASTCALL(GIFRegHandlerMIPTBP2_2(u32* data)) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void FASTCALL(GIFRegHandlerTEXA(u32* data)) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void FASTCALL(GIFRegHandlerFOGCOL(u32* data)) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void FASTCALL(GIFRegHandlerTEXFLUSH(u32* data)) +{ + ZeroGS::SetTexFlush(); +} + +void FASTCALL(GIFRegHandlerSCISSOR_1(u32* data)) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void FASTCALL(GIFRegHandlerSCISSOR_2(u32* data)) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void FASTCALL(GIFRegHandlerALPHA_1(u32* data)) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[0].alpha = *(u16*)&newalpha; + } +} + +void FASTCALL(GIFRegHandlerALPHA_2(u32* data)) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[1].alpha = *(u16*)&newalpha; + } +} + +void FASTCALL(GIFRegHandlerDIMX(u32* data)) +{ +} + +void FASTCALL(GIFRegHandlerDTHE(u32* data)) +{ + gs.dthe = data[0] & 0x1; +} + +void FASTCALL(GIFRegHandlerCOLCLAMP(u32* data)) +{ + gs.colclamp = data[0] & 0x1; +} + +void FASTCALL(GIFRegHandlerTEST_1(u32* data)) +{ + testWrite(0, data); +} + +void FASTCALL(GIFRegHandlerTEST_2(u32* data)) +{ + testWrite(1, data); +} + +void FASTCALL(GIFRegHandlerPABE(u32* data)) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void FASTCALL(GIFRegHandlerFBA_1(u32* data)) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void FASTCALL(GIFRegHandlerFBA_2(u32* data)) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void FASTCALL(GIFRegHandlerFRAME_1(u32* data)) +{ + frameWrite(0, data); +} + +void FASTCALL(GIFRegHandlerFRAME_2(u32* data)) +{ + frameWrite(1, data); +} + +void FASTCALL(GIFRegHandlerZBUF_1(u32* data)) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void FASTCALL(GIFRegHandlerZBUF_2(u32* data)) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void FASTCALL(GIFRegHandlerBITBLTBUF(u32* data)) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void FASTCALL(GIFRegHandlerTRXPOS(u32* data)) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void FASTCALL(GIFRegHandlerTRXREG(u32* data)) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void FASTCALL(GIFRegHandlerTRXDIR(u32* data)) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void FASTCALL(GIFRegHandlerHWREG(u32* data)) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void FASTCALL(GIFRegHandlerSIGNAL(u32* data)) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void FASTCALL(GIFRegHandlerFINISH(u32* data)) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void FASTCALL(GIFRegHandlerLABEL(u32* data)) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} diff --git a/plugins/gs/zerogs/opengl/Regs.h b/plugins/gs/zerogs/opengl/Regs.h new file mode 100644 index 0000000000..fc5f250059 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Regs.h @@ -0,0 +1,101 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GSREGS_H__ +#define __GSREGS_H__ + +#ifdef _MSC_VER +typedef void (__fastcall *GIFRegHandler)(u32* data); +#else + +#ifdef __x86_64__ +typedef void (*GIFRegHandler)(u32* data); +#else +typedef void (__attribute__((fastcall)) *GIFRegHandler)(u32* data); +#endif + +#endif + +void FASTCALL(GIFPackedRegHandlerNull(u32* data)); +void FASTCALL(GIFPackedRegHandlerRGBA(u32* data)); +void FASTCALL(GIFPackedRegHandlerSTQ(u32* data)); +void FASTCALL(GIFPackedRegHandlerUV(u32* data)); +void FASTCALL(GIFPackedRegHandlerXYZF2(u32* data)); +void FASTCALL(GIFPackedRegHandlerXYZ2(u32* data)); +void FASTCALL(GIFPackedRegHandlerFOG(u32* data)); +void FASTCALL(GIFPackedRegHandlerA_D(u32* data)); +void FASTCALL(GIFPackedRegHandlerNOP(u32* data)); + +void FASTCALL(GIFRegHandlerNull(u32* data)); +void FASTCALL(GIFRegHandlerPRIM(u32* data)); +void FASTCALL(GIFRegHandlerRGBAQ(u32* data)); +void FASTCALL(GIFRegHandlerST(u32* data)); +void FASTCALL(GIFRegHandlerUV(u32* data)); +void FASTCALL(GIFRegHandlerXYZF2(u32* data)); +void FASTCALL(GIFRegHandlerXYZ2(u32* data)); +void FASTCALL(GIFRegHandlerTEX0_1(u32* data)); +void FASTCALL(GIFRegHandlerTEX0_2(u32* data)); +void FASTCALL(GIFRegHandlerCLAMP_1(u32* data)); +void FASTCALL(GIFRegHandlerCLAMP_2(u32* data)); +void FASTCALL(GIFRegHandlerFOG(u32* data)); +void FASTCALL(GIFRegHandlerXYZF3(u32* data)); +void FASTCALL(GIFRegHandlerXYZ3(u32* data)); +void FASTCALL(GIFRegHandlerNOP(u32* data)); +void FASTCALL(GIFRegHandlerTEX1_1(u32* data)); +void FASTCALL(GIFRegHandlerTEX1_2(u32* data)); +void FASTCALL(GIFRegHandlerTEX2_1(u32* data)); +void FASTCALL(GIFRegHandlerTEX2_2(u32* data)); +void FASTCALL(GIFRegHandlerXYOFFSET_1(u32* data)); +void FASTCALL(GIFRegHandlerXYOFFSET_2(u32* data)); +void FASTCALL(GIFRegHandlerPRMODECONT(u32* data)); +void FASTCALL(GIFRegHandlerPRMODE(u32* data)); +void FASTCALL(GIFRegHandlerTEXCLUT(u32* data)); +void FASTCALL(GIFRegHandlerSCANMSK(u32* data)); +void FASTCALL(GIFRegHandlerMIPTBP1_1(u32* data)); +void FASTCALL(GIFRegHandlerMIPTBP1_2(u32* data)); +void FASTCALL(GIFRegHandlerMIPTBP2_1(u32* data)); +void FASTCALL(GIFRegHandlerMIPTBP2_2(u32* data)); +void FASTCALL(GIFRegHandlerTEXA(u32* data)); +void FASTCALL(GIFRegHandlerFOGCOL(u32* data)); +void FASTCALL(GIFRegHandlerTEXFLUSH(u32* data)); +void FASTCALL(GIFRegHandlerSCISSOR_1(u32* data)); +void FASTCALL(GIFRegHandlerSCISSOR_2(u32* data)); +void FASTCALL(GIFRegHandlerALPHA_1(u32* data)); +void FASTCALL(GIFRegHandlerALPHA_2(u32* data)); +void FASTCALL(GIFRegHandlerDIMX(u32* data)); +void FASTCALL(GIFRegHandlerDTHE(u32* data)); +void FASTCALL(GIFRegHandlerCOLCLAMP(u32* data)); +void FASTCALL(GIFRegHandlerTEST_1(u32* data)); +void FASTCALL(GIFRegHandlerTEST_2(u32* data)); +void FASTCALL(GIFRegHandlerPABE(u32* data)); +void FASTCALL(GIFRegHandlerFBA_1(u32* data)); +void FASTCALL(GIFRegHandlerFBA_2(u32* data)); +void FASTCALL(GIFRegHandlerFRAME_1(u32* data)); +void FASTCALL(GIFRegHandlerFRAME_2(u32* data)); +void FASTCALL(GIFRegHandlerZBUF_1(u32* data)); +void FASTCALL(GIFRegHandlerZBUF_2(u32* data)); +void FASTCALL(GIFRegHandlerBITBLTBUF(u32* data)); +void FASTCALL(GIFRegHandlerTRXPOS(u32* data)); +void FASTCALL(GIFRegHandlerTRXREG(u32* data)); +void FASTCALL(GIFRegHandlerTRXDIR(u32* data)); +void FASTCALL(GIFRegHandlerHWREG(u32* data)); +void FASTCALL(GIFRegHandlerSIGNAL(u32* data)); +void FASTCALL(GIFRegHandlerFINISH(u32* data)); +void FASTCALL(GIFRegHandlerLABEL(u32* data)); + +#endif diff --git a/plugins/gs/zerogs/opengl/Win32/Conf.cpp b/plugins/gs/zerogs/opengl/Win32/Conf.cpp new file mode 100644 index 0000000000..17d10beb1a --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/Conf.cpp @@ -0,0 +1,100 @@ +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 2 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/gs/zerogs/opengl/Win32/Win32.cpp b/plugins/gs/zerogs/opengl/Win32/Win32.cpp new file mode 100644 index 0000000000..aed4385e41 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/Win32.cpp @@ -0,0 +1,246 @@ +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +static int prevbilinearfilter; +HINSTANCE hInst=NULL; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA4, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_CACHEFBP, (conf.options&GSOPTION_ALPHACLAMP)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_TGASNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1280, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(00800000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + //conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FFX) ? GSOPTION_FFXHACK : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_TGASNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/gs/zerogs/opengl/Win32/Win32.h b/plugins/gs/zerogs/opengl/Win32/Win32.h new file mode 100644 index 0000000000..45322b3d01 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/Win32.h @@ -0,0 +1,9 @@ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/gs/zerogs/opengl/Win32/aviUtil.h b/plugins/gs/zerogs/opengl/Win32/aviUtil.h new file mode 100644 index 0000000000..a6f7f464f1 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/aviUtil.h @@ -0,0 +1,484 @@ +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(_stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((_stricmp(value, "CVID") == 0) + || (_stricmp(value, "IV32") == 0) + || (_stricmp(value, "MSVC") == 0) + || (_stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", (int)opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", (int)opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = (int)strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/gs/zerogs/opengl/Win32/copytopcsx2.bat b/plugins/gs/zerogs/opengl/Win32/copytopcsx2.bat new file mode 100644 index 0000000000..9c20d00601 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/copytopcsx2.bat @@ -0,0 +1,4 @@ +copy .\Debug\ZeroGSogl.pdb ..\..\..\..\..\bin\plugins +copy .\Debug\ZeroGSogld.dll ..\..\..\..\..\bin\plugins +copy .\Release\ZeroGSogl.dll ..\..\..\..\..\bin\plugins +copy ".\Release (to Public)\ZeroGSoglr.dll" ..\..\..\..\..\bin\plugins \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/Win32/jconfig.h b/plugins/gs/zerogs/opengl/Win32/jconfig.h new file mode 100644 index 0000000000..1f43a6e119 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/jconfig.h @@ -0,0 +1,52 @@ +/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +//#define NEED_FAR_POINTERS /* for small or medium memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +//#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ + +#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ + +//#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */ + +#define NEED_FHEAPMIN /* far heap management routines are broken */ + +#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */ +/* Note: the above define is known to improve the code with Microsoft C 6.00A. + * I do not know whether it is good for later compiler versions. + * Please report any info on this point to jpeg-info@uunet.uu.net. + */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define USE_SETMODE /* Microsoft has setmode() */ +#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/plugins/gs/zerogs/opengl/Win32/jmorecfg.h b/plugins/gs/zerogs/opengl/Win32/jmorecfg.h new file mode 100644 index 0000000000..c856e2260c --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/plugins/gs/zerogs/opengl/Win32/jpeglib.h b/plugins/gs/zerogs/opengl/Win32/jpeglib.h new file mode 100644 index 0000000000..a893130b38 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/jpeglib.h @@ -0,0 +1,1099 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +#undef FAR +#define FAR + +typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/plugins/gs/zerogs/opengl/Win32/libjpeg.lib b/plugins/gs/zerogs/opengl/Win32/libjpeg.lib new file mode 100644 index 0000000000000000000000000000000000000000..ae22f9c400f4473bd6e6e5038c4da14713f501f8 GIT binary patch literal 470518 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

H{y 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�*8S-ao#yR+JgG6&&XhH(aQ@%?wIb{vCe6Vovc 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 z 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%0A)B%-q?>`HWKQwJa@+6w$uH2Pp+2IS%z z4K@ZviFfHr#F$Z6B5kUFSG2|Wt!T0VK6XYPS|~+do!o%V{mYhoZidcB1D}SI0oz8G zZ_f_L%Ro?V6n%IIn|oWw=E)%q?5e>RijU1x4XLdQqClV_Tu-m9jc}GYLfAoUItMIk zo@E`J|17+s*T=ytXon{tD0ZM}a%np|rZfWsT&cY@>1IoXb^-n~Th=Q9@{iYEb`Bt6 zZh?&wI0;W*J>>_h`o`n1sS@J|c_Z5k92_>|)m(Wd6Ps&qh+CNtUpE*q+uLfR%|Fw? z>gx=w(ey_Q)mB#l`+~L>NLhRaI1z|;8a)p90&oWKMIgoS_rS}6uK=$F{sFiG_$rY8 zhvQLgnYIib;HPQVXj_I{W6w01W*jW4Eh`&am0CINuUSlFNm@M0mI+!2kJ=;4w425& zTr{jiTV~${?J@a}5&~KwDjVCf3Y$zOC+%KgD^6dx4%ktv&M06zR%uS&iOQbjzqu2Y z6aG$P-#^AC@AsK3joDfQOwuYfp0*>X|wNx%@CeX@ZT(-PKgqm0xC@>gzVgL$98Mw z>)f`f>nvZj;zzY@XTI1jti4aCUYq;2<%`e9(=Jsqhx1%l>rfO*SnOAW6yTC zM7^hx8KxWR-MP1?2dGy0?B2G0q~)ud_9Z-yy67psR0-g-Y*~D{yHqY`!4PYAKam3XJR4ZT4%y{Q8%U84ZB|MI}Wc1`S zTmQkGHoai^YSq4kM`B%}DTcvP;h@)l zlU>{+bsfa8+$0CJi0$DZU0yDBZ@32i`Yurq2jwG)-(3B7g<~H>x&|sbwfVVjx=L&^ zUB!&+O=VI$G2pSTJ$2C)znj}!O?NU27gj9Jm|I;LX{dya+Zec_KKyXCL@xh#w4y$I zL_XHlX}F@^OIFl3L#B(g#CWZ!o2vDi1?@iD(b1D$j5osDe2>~pAy(S#FGD&F#`7tRNy&=3l$ns^A3ODY@EooAm;|pCaK6+|(mdkP?F zs0H5(nwKrhD}9?le+@hjvtNg4FMaQV=VQ&6Dt&C~oW!>quNCGtFmM=ri{@o`Ug_g& zcMW*%)dTeQ(#MtjKWo1B(&xiFBS#PG6MP=^aVU63y7^oyxa=s82hVA4K9BG&0MFHK zK38~@gU2)vtYW;%uNp4vz=ytDOsewx9Ij))Go1ZBOnc>bGI(ZbzC^jW(#PsDSNkPE z{7bcBeT5Dy!S`QTv94+U58OBRJ<6lEUY0&UtypuJtMa%>r4=PVYGFEgSugd)a?ac1 zcwgNs5O?WOYtWC@&#j8oW8IUB#OC_rjD`ki#m$wqCd<9 z{38~Yf8r%%&-G$1wH|L3mRFVS;*v3!PnVeD&|F3YI#&L-`v0Wd+(? zfxatnbnlECiu{>xP5$QmtFQd@mlfzErtR`F=r1eKySRlQafR6~7yZw<0?pyb&$|L$ zI2lv;0Xet?E3~#1S*($5C`#wNOQ^L7M>P8}l^!@Tu~0o1eVzNptHGdgp6?($qtUl& zBOlzhA&AV42Ta!_H0Q?IJD2&?HXrLW;Q|{!B@ta?FERykfHd-#V za~h#(U|r(FD<9ffwT9=^HDP=S=c#y1!#G(LESj(;PC}8hz$OFnF=8AGM0FU)0mlN5 z2bKd*08R%^19D;FBp|Dk9|)?dXv^Rtq^2#`HdR%O+ce}^sOoRzdR884=6S3gAAlI}gGs0X(YWX;T{y6pdVpMt@9;X#%jQidVLD{N7(^{qdiMqDaHi3gA(vrzu+|eh(EI zxfr%-0tIb49>;=ZNAbn?2Gf4P(?@=hoC}8O_ie&|GZ)sOGh;xd+0g+vR0g(uvCE@j0XrA= zC`Zl(OUqXay}$^MF>@aD1#1P18hb|gI;zUY0c<%{w`!zpOz;;0O*e3DMMU4Q4~ zA1q(5(F=?ke%TKRl30Ab;l{l09a%Zo^7T2rz^Ihik3Pu()ymhvzGeGZzA{*JFv8=I zI(Bl(7u{Fiz3vXn7ms_c2dq4O+`)BX#UMT6&y%Tg}OqukqR!+nG}`drDj^H=3(99rl^!%REpC)tNiY?6cf{i+k1L{465lh-lU)J6EJaw8cRr*+dSb}vJuk@V-j_bhJhaO;%49_(`_Ivw*ryF`kn)cE+ z5!Zj5+MG0rSCe>TU>lz<;Tq*-SElTi$hMB_R@DWc*bkKRO#b5q+at# zfcWQ?zAr#O4SX~DDK3WRmA)v_7bOqcE=_ys%LC6a&DUP~CTSiOqE25;?TnUFaw|+) zIV>l*`Th%QevQ!VtNHO-s@GvG+Dotb^;Bzqql3kjlPiK)@-x*}`)G$LW5$#~HL~=C z5`5(=_0_YL`f5d4S>=Q&MWM>#U`0?g{cV_IjB>g)Jm0aps?MjJW zm2s|NQl*zVE3+gT+bWHF{gTUkFPTZBW@-IgEbB0dvvK-{Wb9eX*?nFvmx6wx)z2NT zbh0oWGSjB3g_{zQY>&k`X7nDDySia^Lz5KE+|z5DFg|dp=CZ=>a5A6PQZ+XMto-(F#0u_u&;`gjgFL-BEfmzMXW&|~rjSbjGU=t+9@2MKR6;bhZ$Dzdk z-n#78-%a`B#NO|q4P%vid?~4-W-04og#~rE zb>bp$K-DsS0a-_u&2OG07uP~fD;v7Hk)G7CikD@_$IfpJW(pP8V`4>ODK2I);@8tx zxNRu`SMEX=46fzrI<)5_GZ11E?$uUNi(5E;y`&?)F}S^(N}+a_1TAUe4Y&mj$KQvm zb1z-DXx)nly0t-WX$$GgaOG}X`;EB#!1)4C10J_}FDDgDcbj^z?btM&(H6m(UOTr? znxtU;CE{F($25#DfQJ)p4{G9cyreiKTm|HJSv7C~um;HG3e5IKhXOHYD9fc>ZJUnY zSPc~YE#ynod>etMgMJ$D93bq`>wxosw*%?#Zs1wK$AJrg8-Qm6-vurKegHfV*a2x= z3gi^%eBdC^nZ})2IcFYCqo%r9!pg>vSL?#(7y@r(kPv5NO-8<1vxcqWMjSU`WKUAuPZatid`xMEY5XG;VN#Jzk_lx(L$zJViQ2kq);N z=LU+Yy7(FwfAIss;==lL++Y%rV11GRSKtW=1M>*i;@PX9(VaDNB4>Ycud1|Q<6D-4@nYp6(oguffk`iFr+Vf6nm0U>gup8@&t&sf|7iya%`uNPm>b?s)7Q1lZFl+RNIe7U-B(({Lt5 zEzl_&B@(kWl*m0h8hb`M8$D_=jO<~ZjIdggo93>G9SNMI(mN7jaZa1*YY7S(N(ygvb z6qR?1X(32%F--_01SDaYHVR}{;5C~11O$cYeF``L_%x6Lxe`c$Tm`HGt_D&d-vCk| z*8`(KbdMsC&j2Zq&jML4=$)iXg#J}jzwm5tRqRA|1O4n_{DH&bsIP&@TlvGF&LgajIq zjz_X%YUvX_W2zD9W{&L2(>D~!^{`v^J(B%kq_6e548=Rei*n^{$?Z#gVKQkWVr((z zAmo@?G~*39wQz( zM5QBe3VwG6GB26HrNAuU`M_-8g}@vj-%VYB%ol&N)(h|`8K6z=T~f4V+EvK_(`cHb zVNo)mY?Ohcgl6t9RCSLx(Q_bk+fRSUByw~XDn83qBl!6|+)&R)64f={iJA=TC0=Es}n}%^x;Q9eS(ZmC^z~uqEf(BuW_5uzB?gcy; zmT zU&7WjH>=BpcdeAfv-_Gb*~kF3+Xy){uP{64(A6Zx|C zCH2>F?Pw3wnp-oDuzU^EzBo1GwFiolPs2TimamE07u%xbYY6&nG0cTCU+n$;KE5m1 zUtId@SHDlr7o`H%HrevkD^XwdI<8)ZTMqk(FSC8U+I>~N<%`FV(g=@34&}4gv3Jt) zb&d9=K8@*L_P^62vGWR&!SajC;F43@dVgO~ymouNf>4v^*7U|D4+p((M3OPbca#gn;s5MdBYCKM67&3Iozp;yKNdE8<>SzX@%y595%rNgjb-p6S$?If> zL3~x&jmOCh3n2U_y7&scPG*1vzK%|)qkgThSM=H?GaY<~g69Hu2QcJIwTtW#@T}2% zY}v9q$E6w1cKyEQfmMvxE*`$izXjjFG%u3jnZ5@>Pe-Toq#gt$(r0_`F%pLNA$UI0 ze5t~_4}4#N=O#90m{j3~FeC81=24v9>AM7c+y!+Thr}?6@N9dENoSw65j<~ezEtJM zx5~GghyG~1%8ze^P8eQy*<11OJ?d4zoHV-sG%@Eq>u^9XMWc&gldF8O0QpQCwH%--cU1&(nSpI7<40lrP(dvsqF zT6^`o2|S-@zEt_;+cjf96_)wmtA3fjt}Z^W^t}VVQ@~f0t3qopeW!wFp5|*WeV1yU z_R_Zzj@N>3_5j7@19+uxFdR+?&#n6_zBE88`FjaGZ)v{v(zi|Xs1UvD_ewhA)AUL_ zG-#%t>FbU3-3^{~dBWCi`~4I=-)g>8>0|rtg?`>{q<(Fq2D+8wIl#^LU)d!%r+)5_ z-zE6R8-DF}Wy+qw%vf_ijR;GwH}QN+D9ik2p{q6x>3PmnrjwxaRayVOzcB;bY{TuM+nIgFbaNF0fX5kYZj zMF{&6$4tf!IkhWs4{Il5xO8;ou_cq_@cxt=9Zi3|EPsXH%P+exv6&YY_tW3Y z^1rtGa=^&_n=)_x!_wHAZ)VQfe=25)e%XDw%SX2Szja#9FS{>y>2{!#?u zFD|7}7gun~1wS?v4x$5Wty94&7g?O#n}_Nv@=JQ7=TV!%4>tTposo)s}FDu~ZJ>0e_*rWj8DkL%-08d*0e6D_BSzJYTPa|w9s`yJ9 zdE!Le+?TmwOs>QwXZdrp(|HJiljUg!KTf$ofZZbqgo_YqTz?m}ZEHu#ji9?1efc@f zPiQ8ifk7xE)1XBd5k_i@p{S%Zh<0IDiFpu31i_a1sB40g6fy6uwkL6*J%1ah7qL{Ac!cw$qdXK$f7W22BJmyjW7CW7?=l~ z3mgh;0_FpM1v~^9lvF1%J7}r$v77~SbAfF(jM5L)Jbnp z`iNc`0#_HTifzF!9F4?!PnZq~8|G+OLdrg?OjY}D+qOsMfOzKe_`Bg#}O40V1=1731pG;+2uI zQM*M7%)PtVD#9j*pIHyb$CNQ@7ulxWX~otttH zdvV-|ho;9bTnSQ;yKuV3zTK_m;MjNmmb})Hu0Qc%uwam6Rj>^WWra5Z6v|ZNW)n-!dB~$%2 zH+!3g@v>Q^Vk3|7FmN#N5g__z_M6cH;0?ea@J1l|T)AS05`8Cr zbK(BCz;l5Q0G9%91G4f-zf{w&0^W?@2utX>5`#`5ik^c!zUkO}@-_HWi0lo~x zJ0kiz@H*f-z$pIy0$c?A2e1{mr_V6(PKmNTkUtMd{)2&dM@QLoNaqnFq*E?pK(;c{ zxfD+NWZ(tBlYkJC=yc#kz?r~{fu{p60iFS*KQ6`4-$Eer96cX+8Sql=evNj&4v0P^ zx(0}mLi9Q9{(J5I2jCf?zXd!K_&)Gy;9r0%fgb@^0Y3q*1%3{E5%>*oBk+45$||}Y z_ircU--`qAsIHzi)zvE+awx9qy+~Ox4c*myQQ6Y*d!W#K-8&fF@m}ntcXm29 z?8e{hPyj8L*tU$Ur6@MTJjUya_$7<*(+K&0zx@N-jy<`vEDxGRvM1sx$l!GcX0dP9tAXH5W%lSaKOziIf*UI@~Yw3n45Q@XR5Pt3tT zWn@4CCC28KIkoE6wjB&JyBL|4Z>mx7xJxmznaTP4FqeD2>-SI$DsyrM!+X-u=1UOS zW0;2N58&wv!Zn(R-%;i%7dRAn0Ptwwfk4*DLBL~x=n3S2#zTPh_>EDZoZmMTI3K@D zfQx}+fUWvBTD<&5%QXr?M-L~z?*SI!_e((fds)-j+J@j!t&O$}o+~I4(OGsEQ#LYW zr+G;D*pJedL5(Gmjn2HEPHY)G%uS@EvvIYyWw4i(n(oYgSZo=*?MlZ>SyS;c4=gX! zjE6(zC|f3IMR@!Mxfr%-yuv*aj{1f=^b|B^*o@T*QQ5LV zQ(@aVY4-|Sar!d--h0cRfwu*{jzr&QoCD3LMFDhbzbfpn_IbCnmt1!j304-u7kEy? z<5qi`0^06)_)>Il2{%s)pc*;OI^$3`05)%vQt;J_yxiuCaZ>a<0*f`h45G($Oak(2 zqym@=oB})uh?iNEodW4hE9n$bhO0!BHZ>?#wB_100|ce;tAcb^1?jAcX?Rps(5BwaiguxPO|FV+xTva7Hde(9p?OvXh6xF6 zi{aF^Xc-(2&L6Reomz92Y7$JEn!Jg}473=&5JeS(?P$wT(ZOlyv>}))zxS2q)vjuW zZcfy{Y1tb)_C+;=p=M*_{sA`E$e-1jpNJ20Lh21Km)zRaGoC;q0(h)X&dB7up z^MPZ57(zzb>dpkRO<^b*oen%3cnT1EA7yxbE|9_y19I5B6!-|R708$TuYjw7ao`5v zVj#tUYj z3Pmj@pdCdmv!>%O$3Di#XzV**OF`k{?Y47<4?_U>^rQBw5{gGTI(2GonL|FAqBDnq zqrt{EV494;0%9|Jkze80aF^I%G%jNzy3J=jDkEbe*=<>;4z&6Am8kdB>RbVYSmtZ0 zJ*}m_3FE6dRj1fz**Nwv4bwt#$^_2VM2K9J>Hiuy0Qe2?DB!oiF~IMElYj=Qn_}bx z)&qA3^5wM$Fbbp&&=UO{Uoi5U;=!h*#Dg}a_oZkzYgg3+F>R(f3l=3F%0}_PR|{xv zy)UNxfAOGLZn<T(3_@K ziFkJElnKA@LHsvM!%~2_2vnMm ziS*o|2>8#~?RC)!v>nAo33cB5Y2Cqy*$pwB5^=qtDamnlhKt{4eg|K={XPi2J6{wW zzmHo)&3su35U=Zyschj?h3O)`#4l{8J@dCYmaosXFX3@)a^FLIWo!4IS@ju~uWTj^ zMtF?MnX@A;&9ya(X1K~Q3uL8mK<*2sT!GHRoiE1X_i;XhJT#U9#1I|Vj+8BqE}#6K z<*Qix%0XC8d1g0j-37X!L*M%?U(>ZO;c>K`ZsN-^`a>$7|@-891ED8ufc;_g=d z$8+}fTf1AnuF$@etG%7}5MO3o7k(B_w|qUQeF={vuAT{Buoy#rms@4|dP(~d9=0#O zqpCuOLeGK4|%OHk?^h{<3bJMGfChYX_? zM#W`salJtG`^;V>t?Mxeir($5ySMN#4zm?l>KFgeaqURe?`8Swq`InqQ`I9^ z`(ocIDlBGqXexHtwv_jkG@JR#yP@&yYGquDb#WGHKdQSZD!s}e3{b1 zd|AG@wn-yA4r$pNROj*Emalo*m+(+F68T~-oW1cr63#~aXTdL9c-XAud7}nFDx100=p1$nbR?Yw`D@*wiFuJO_Ru!LFJ$ll}Ufpgd zd#Elq$(F~&hdnqiXM2zy?h@*`OQl=!B6!}^eC&TjC&8sV!|v)E@O1103rvE~_WB~7FRuaM z8RF*i2(Ju0m2N(d@XiKLtDDai9*17Hf#(S~pGSCag6A)8K3911LcnO?0R1)9UVcl! zbBvqM6&}m4LG!>W#!I(nGF;Aa@p;v6I_mco@V&+NI835`Z37k3ufnq%M6;9mO3l|^`p(uoDny+=+W?RBay)HrzFpS^n}^^=VRnr{;~?5G z-p7k#Gw!tc!-q|qREwLDn`@`d!U=d)bDMvhDwr&TZNrq0dHOrFzDg!dstn?S=uqXv zvWn6P<>7=97L>Z^I2y;vA{%G<4ZmNS&bc$jn1q~OHymBl5K zEAZ``p5r*O-gOlH|D|K+|E)WysjI;G=@;t4ZCr8SuAdy*Y zp*9c3|M?Hsr*hPE%ueDedAH#Agwx7I5jV6nRo6N$x=(Ry`YxQiPsJ^d3(pzSgKR6h z*Bl*|CUHMWA#~!E6`-_t<3T&&x(?BAM|CVk>HMTxWxQ)7Y^xQ@w8uIBl%uOyL#Nkc zC-aP|rlzVhIe4ws>_qs-f&Gp~Ei-4aPQ4FK-2OWj)U#ji3rwP+aZqFpk-wWt90QLROzHlsNk!T7PG z%xx|u@$0ynQQG$Kqi`v1Juwu_dicCqAcfk_n!YUNhwXR#h{ZXmv7?O0!J*jEMoVYY zd#JTzD2{s)vVxCB!6dBy21#_{6F5HiXAM)P?fej{}N>muX9 zf-QcAucgQOSPxoQJJ{T3EQ|HTfBveLU%lklBj;hGpE0vF#ySmVJ#yYm^^@ufVNoK) zrt|686*+ZHEh5G|1tus?!+*|dq)|gcG@jD9=U?{UTU+2bK~v<~%fv}$%0?ydY%ZWH zqdvHJ<5@K>;H}3XomwVUxNHi_fU-q(s>zy!)E=A;s@j{~+*HlsJ&uLR$-$dn_I;Q6 zYMLWL6?L>PK`uo0Ov5x$P&m&uOw)rHP%xb#Am>a=fvolMKrxOj0%YkR&H#IxX0^ST<0K5lyHt-YjKH z$8WCjV?VZLIYJ|Az~WK1Owcf!2X3aHVVg#|JN@(!PKL`csar$iUOJ^D(vq97cW7qripP z`71Y!?#B{o9o@Zkbni9sMVwTPZT5{Ajopun3h<*jD;~zX1k-p8;8jp92ek3^Qztwod#yv5?zwNvbc3@ zcI*jVYZog)#>9*% zr`1In-2R4OI#|n;h%gywu)UON!}ui1rK2<;YlGWR^MM_K(|}n2idO00m+If-8;(cS z8f_V}n_AIUXjjx4Y>eA9bXQ%SvN1iQgw|iPWNKu}EFNW}8$*O5iM9d6c!fI}E>4ve zGi=6cg{W+la}_oNG&yPa3R`j7Ra!zAnWTr}YeS1Z*#=L=@z$x7pNl9|q1LIrL#=gz zQ2Y*&#MZ`bK`1L@BXy{C{^$8$7sK!1){5L=BkrffhFhm^#^o6cPYcJVr-$06;o_i0 z8z_x4q2y*hp*V((Q!vb`K(y7Nv|@I=*)&*m$edAgy);4B6 zl1}!Str?}URq5ni@HPu7wgy446p^gur(+<>WEGl4sfrQzGqI}}6-3En;EI6Or5BHU z#43m7UEmQno@_#KgxV@NSmj-1R7kffgP|ZcTd|&d$G^63M@1E2P#lV_Oy5w##X(k) zR1It6?0$&=KC08)ttWLKy0Udb?=2Ovl5Ah>X{G}&v&$)r3p?o^amxYmrOqC3DJw|# zfZ85H=eJ?BM7m*gZ^nI}FAOQ7bcEwdV8U@NK=GS%H-XNg*(~^AF5VRQeOGR8<~x2( zZZ>hzTDF*kGWG-b;qFJdHq0RrCuUYz{iu1yhW$PdhUIP8k5b&-{U~KpT?3@H=gerC ziCwAc%Bo|!v3~_+Chm0M2^@_Gdx8-89@Y+tVRQgNnTBcR@BSck*K`bJqs#}sCZauo zeSsW^pW=HUf_TLL0>h z0v7{E0XZB#61W0*6z~CHDR3ol9B>VAJn&Uu7|0E%43ER!V}Km8GCeK88N;56WGfKbYgZUa);>IjraC2$b(H35%$chHt$P<|Bc1#RQUD@H%?V;Z`v zcZag2z4?fBj^icfsQ0vl1!5C`8PqOcxu$>$T zwT?*-$IH<1;|9TF(jQk|o(aX@pv1#B6jD>c+Q5t9pJrjkJ- zh(+nxIiBMxpjUZ9x+Sz zZ^*yM+*H_=%+aPk%@pk}{8ltr5;v;QPO6eQWuwfUEHvLf9gTgUD$Cojx(w@Rq>V<3 zLu>Gu7&pJpzeG#U2I5!qP~n1*ShXxKks zRu~4?ZRCc(eSvr2_dwupfJXxF1aj5_6(0=&F}e`NzTW~T;r9c;6M&BZYk`jeS$0nX z=L1&*mjl-T2LWsFDAA%#iI$=v260v08PjSSx+~FAHj36Pq51acVC>;KuOW7Zn$=8* z7QcJk7gJi-s`2tuQ%rCP5~U;nfk9^>=QdC-pWjgQ^T{QyR~6CR5Mx!*;7o{90M_@{ z2>dz|Pa5Zhw9K}_reyYV*k+6Cjrgx*7PaY;*$Y5%>m2`8e90wycA1qKHd%&~-fU)l zbv+i|clH>Uf3qvALmEuO^so>p5&XQO!K_0x4VVYq6L=sn9|)Nhc|9077QYVxQa%R* zp9c;F{t*aXnLQf@q&zm`QSwMz2G4WRwA-~!$s^NZ8qADoc~mya;~7Ge*$~KM7kz#R zQ~E!tA=m{8a~Qjh3`Y`vpE=(;W6bln@(Y;Th-+uGoRT}49+@-0j~fhWqp`I1EQ(u~ zgyRBB=i-AGmUpmxvG<`79*1ti?x0#4Rmb0Q!rhjyQt_i+cTTOej^Znm|M3(}e&#gG z7YC3u!sCdGb!o-bv+>FimM^v}8sTwhZ*>CI%GYlu#fDhEo)SN5M$@S&M#-|Yw{HDc z?F`G;U$igbam3Zx5!ZKDy%e>4aYG=D@Hp}%<>1SO8%twhR`D#$7lz7WR9V?I#V96L zz8)&;0#y*!56ubMm+&~^;`>FFA^G;5KYFa?i$iT1;St*{nu4~@ksQpENtBlz6lio- zH?qNrp)YE5vR9;G{+zlt{EYDXL~Lp6nTE#90PXUO!4-J;ePc?mrQP;{j-48Us6pFi zX1+Q7zN_$`=F|n39FrV!SGf3nTk+ovIVVwu=3H@(3fZ=8xSRMgrT6gqLzh{;e5#mI z>H|t%;QyxW+x~9(+Ee@DC#kcg^l-%W<|R$rEnobkp%ETOE%T$ylHMCTl#I80g|#o? zaY%13@nz<#tjE2_S-xtuFX3^-)jQz}7STPld@azvgvU`keZ-gfVRZeB1M%`;Rod&F z?+|A{)+bRr)PtqzlTSs(F+H{?=YnHbzwdMWH)U+EL@xfIL*6SX7yF1WGZ%*pKIc`- z*Js+7@HpxsAigL?G#kr)b+_fKE0YKlz@x0gHAS^jPOgSiVluzJ$k-FXHNP0Yp@?sL@eFw!}8Uql5-^Wn~-*zq6|M~aHrLn*8u#Y!uc|f8xw&{=u zpfsFX`4D=9Y?j7f2R&V4`O4M-36G;RD5X{({;$Rli!5J~~>+aa6uwz&m67upWlRA`6qTxdIF zQ=tvtxzKjVrb636;o6nas#C3}OBhwNu^G1Vw3e#5k;+KbjM-Yz52q~P17UVUQ*&cg zwT-4#9GeZ-s+@aiM_2FA+$0B6w=u~J1kiLAZ5>FrGf z>7d$W(ZROIGwaOSriRLyRZWJSD`{%MBerB7kLZ$^9J;l7Z>FNvVdl5e+=;D7jUF^^ z8E?kk42X&-?5Z~J@p-9}oa*b-p&9JqUHmn-G-4At)(%BXn~e-;RvtbqV3{3hRt_Cf zkUvD&sabi9XjXPVN-i9ip36(K@=5l!cH^O0xfSF3EiOJU%}Vy_?{Pe2GhUiN_rd)G z@co*jAQ<+?qFHGhtdhO}&*R`3&an{;-X)%zMO?Bk1kW^%k6;qvN&8VW{$~~zgXcoc z$MlLulWo{TKE77(0nbxzK9BI;0ncVPpGSDRV}#X{qb!(2ydL2V15crw&lMhv?PTzr z?&k9d?-KB=aPxVD_Y`A99sqYK`uTodBG}) zu?2j6IdX()uYQZbQ>OV+rH}PH2RvuH`8@J_HF$1w^SScN`d9~^Ke_ol!uuXP9XU>g zNtM0;+y-bK^3iyeUoQ-MOTag+zv4kLdA5%QaF_|64>&@FX|McvdtOgGG^x_Zq0}(V zBaHaxmA<<`p9a44T*bvvx>x=3L$)7yayhPqX)k?Y@J!WwsnW;#<*j(-LdY91A$cl{1Rz0CvPO_&d+Nmak2 z;BYs1J{qL>+N<9j%qj1Mho-&y7zv*7Za$Cv)`O?T&F9K5<>g}V+~nr-2yYd5UUc)h z!ejf`0-o(|K9BJB!rb|RcxY1Pm*I^C&xvk6kMPa_&k{GED}4ckca!FURg72r%|e3K zfbW$diYHb5Vx`k~2R!BZim$!;oe!SHnlDv;*=%prJSs$Q`THm0eGYu<4{JYtSAg$j z@YEf?z^R$<~j}h+&;Cn&OmU5!l>-}*T_>MRN{qx8jr*Dr@*rkDo zCRO?cwTbzxx(v*@IC=gI@dg568Z25 zZ-4L%b@REx3m}Yg@HD#lJimPr=XhdV&@@sr!XZyCkG;7VmYu2B4 zV_{jBvrYF%qr2V)hro@oy~Ygx;Aw3i@-EVnr5O^WWBXzC#T7rjNHkY4zhh~ zTw-6mo*)umj5C0Kn6rHRLZJzxcP35*a`K`R9<_muHgyAnqAl01N+Yaf;4@TQ#@@#F zOO`yl@MP}n9-RO7l2_CY-0JTZ2IX2*+2kFJe;$l~q|{CDzcilqPB^|U>*0#sw};v? zci)VVv4t1v9V6dcfGe*=tHZoTRCX^?{BlR5sP0QWvSLtvN;AIb$y(lM{#{rP{$@Sa~>7nNMybsH~}qRAKvyQUZ&> zvCKEOWe)WMn}xp+q!uBYM~=>JhI(X9PAK8f&=P5Ek;P5D=~}eL=x!ROpEb2R5TB7^ zjzcqG3ub9%ah}jWPS>rVN(7X}rSal8g$MVd@Fgl;LtR)-PPhU&45W8-Odq z%}6scutU59t|PUF&onAus8emDy9(dV38Hp)=2da_-y==73U|O&r!@3QlPY{wF61yd zY4=LM;uHUxKF) zk7<}UHe*aXAm7R$j3|2~G`r|@;6mUjz;l340v7=(0z>hr=1W@!Red#WtF~oGnK2I2 zkW)2ZWn=R#5L$oDf;l)b6lse`*(kcjc$989>%%l&;T{D?G_y?H+`P4ek@lf#24?sS zOZm!9*eLiad{`X%;9lV?PTzno#(-C$@Ub@C=!>1u-D)z7tcuP?XXuA_T#eTk)b9de zsNeMtL5(w8wUqhA@e}%mt1sg0y`$0S1|!V{Eh4@s4;2KWpv#^_;zSq1iu@wI{OT-N14r-vDb2 zBw~J}MpvA`EX2{v86orILi4SB^Kib|5l2BISuY|AS?|_1wON{8Kj!$WdvU{f zw-BLiH?|4;8v;*+n!^4UqBtB|voB}Ywe8>)_V386Pr^yc&B?HeYLH**AaO<#?O!DY zJ%cag-xT(L_@g6V<=1}d3$2PY1y)qys3l-f`I3-89$I80LxR2pF%XdgefhIZ{sQjL zgCgf+Cm?>0fwCLR$D_J2+ER=^#NBpiTM8(qTHvt^k*XV0wq*P+5;xylU5&T)Bpc^J z9mU9<9gK6J@?uDJN8{|WPDX#Ir06%Si_!froJ@Y4ZHAy*2uH#S%^hr~=Jl#OkQ&3$ zk<-^qjFo5`S!le!M>7R3xRxjI!2d>RPMRA7pRl{Eh=a61#p^t^F-rM!M#<4+~aZev(jYXVz3! z@=|(t)y)Rn+py~9!pmKCqi}0pbtk~pv+7QXdo-`QpTjRP0*pIrZW1VK2hFpnDg504 znhUxa6tz#T?j@!ekE%hmrSR%r?Y2|fQsg2S%C-!Vss3rV||e1-J&Z*TP9($46E z+TMxBfo5z3>e4QMDd zzbY_4M=hR`U$>xVwDd7n?fkkW!K|hzhK%g|y4k6Pb)`qc=I(rRFNd(G+36eC;DrPD zSfw3bx<^m=WSS@a@6z;&2*$yYS9Dr7u3!L$BWe~%It@1lqk%4sV!jc0Vw5lN z1kUw0V7zDy)qaM-XHy&h3$J3-_z0s$w5jI35Ep_Na3VQZbXxk1Yo5t2egeAq=;kV9 zm$Qq10xs_3>&M{M9?u>;35}&<=+#5q4TaU-+pwXq`nwwnYku>FG7YYt4W%OP;oVSH z!QV2BHya8U2-X7aO*D)Ee!mUc2NeCBTy}`G#n$8Z2cY+W{tc83=tEF+*Hmm4L$@sc zzXJUTzZ*dJgKh!+7!t2;=-ZyTd*o#6HZL9fJr%C?O1ck(QPr&>T#=6DTtVr;p~1x*xXTgFQ+X5^Hc zoMa?p)|rIaW}_BgU zrQ$Wcbq^A1{Lr7(ly829dEf;F=11sA(1jGBqj;;J^e!1v%}=3bZrLz&J1-QPd&4-l zZzk<8G`B**TXEZ_{Q82nO1EAVv&8(IkC*P|1a6UDJ7U=w8hLG}W#3nG=9z0FE1+Pm zdx7aMFvlf_o<<*w?8QWCz0z0nS&8gJr7s|P|)6#XiXOVp-IW*pU-Fh_w|NDImGl8Yn0o2*Y z40ZQ0>;k-v*AkZV$VGrR?_*+c_3UHVhqN@0`8k5@sO*Md82&VVW- z>``Gmid#{k#yx1>`^@~zhB*N;9LH5VmE&D5wlB{dv)q79xNg=QK^uV{S~&bd8dhY}MiY^sk! zC0apxM&OC4kJB3e3xOxbv?-{+rcL09No}wiE~u|+<8O>YX;4N%{em{qQ?<{p-GZK~ zA>@BO=}m#5Vs&g_&K@>YjaGnV2vEhuiXl3;0Zr8BWX8o zyDRIM~&Ij9M_TfEXxq=o1#Km>LG2C^Q&iUQ;}~$ckUgr>J?W z+A={_2A*iA^2;iJKejv@lbLbIKW-whQY7Rds>xcoFq(}R9Fo#=#zN~{7>dA@M_~1# zW7KkrL4kwR1P)hIIN!xC17^8#6{m}+M=1tL(4)kfznS*4@!0Psp2e?oUF$b~bI1w9 zd#HWx;bOs@s;cS=_ozYP-iD(F)8d|)-T}AfqsDr;dX5^*pq54rc{f2$%P{^NHoC&$ zR_%BOy7>&)sXgfe(4nBWgJQ=ZwgEH(%8q^v=uS{-KjN@45tPFPwHL9?LX(mx8O34n z*joIa4SEk~CFq&RFX9G)V#gu&dr*8gA8U{JECb~*^D8`Rn4wL*^H6SYY2Or3)CTZa zhW=`pQMP3Kep1|g*(Vs;hdLO;_M{k@J3AT~TRIu(n6d?-0JC>-!00(F6$4*aHKp>} zq}Th6R`(~}9=kx@_3aD~c$M8DdOmb^Sf4G6hRhZ04>6Hh(GV>?ij4;Ivyl0bbbs+? z-g-9}g&ML&A@irq&(PB`q$KM=c)+`je{F|t&JH85>J(UW3cYH#97l(c9L6@tJX^b+ zTDOfqnr{xzH*|08hE|F;JK9%h_CUXcW;q6vsjb)^Wb+HbzKwP?J70a$2?Ma3 zx5*bV_p;?;pEU5uX1n)_tk@G;HL9t4s+!M175YHg359e0Z|M(Oa`Fl zdT#_Cd0lrmA@dD{h1QG|q1PGJRPzW0hS6Z>VO%i=G;-bvU2y(QOmDLog;qg9bvS)d zPDQ7{YMUXXD-OE5PAx{tdH5Y4;5Y z!7~kP_b0(^qjvuR+FcO#deAJ;b)dI^{v32Y=mt=>d$eI`_xFLa-9HG5<*M-u&`yx~ zOHfQLq0`QYodo(ADBA%vrHR(Hji6!t{taj$=x;&M<_#Z z_Ozb@s!xEn@ok}uUa(_p1uy8DPT)2qhNcA&iq#a}4unUR76jIC`puW|6?~zPNyX!s zhnxpKjQLwTMeDEaSx|ote-_ktR)i&sU#F6=d4|o=-ig8r$_F5JBHQ_VopI7wlUDnpfY=$a%Hqgg87oG8Atp1N*Dt+ShF7Z^#irH9agb z9SZ7tP|W^`1$C!k<=BXqFGp9rR?}OF_|cK`@gtz~2Ew4YegBzpJzgAlM30weI?ySw zdy*HI;T+`4>N6ZoT!wTV5xu9SUnfkdJ|(jJK+Q>zElQoBZM|FvH6dAEdfJ;&%t!9~ zC86c37hg#-HWrK9-T2Qsl*HY0S+XZ_e_TeZBpGWs1y7=`KiMx&GUmfpDQ=5lHw|%R%5<=QxXNx+jwnx+252vwq+O|dxg{C z&|AB|idM%syba1l1Ow9JRFsNP4}lJWZ$aZBU(JLq+2y32p1LP+5{ z!A03pVfz~%zrnaszGaj@OGw!$o3k>t0H(|v@X$Chb_l!S=NA-ZTgFT7JAzCLU=s>G zW(s=DwwOUBhQW9$&TesAPuOIEeA?Y zINj17uD05djXz$KWplBO(Fn$&c7!$CR=;)L8~255t}()++Kw|U_T+Y0y;cusu(@Vv zF2Oj$VwT%s1uyDsQ7h@;f;6V#V+o&82E-VlTn37X3cH@h9ZuZyPUaUOMav(31dQm5#04 z>UAyo?X`S3S-*0naE+9rQj=ql5WWVoW{6|8J z4KLomsd*~+n$D>P&Q@*}AREl7M$lEqPJ^pm?rH6Yth2fLYA(SzQV|p`)jAC0#j)M* zwYhRNmtY*_p5_Rv?@d1}vbiqTT!L|gb-Hj_{m-sh8=kkhuF+hAafH>^5mvwTq24yv zI?W{*M_B2?#nwR+nfGp{&GjqIB^dF4MY}Zb6Z*m5?>mP7EYcN4y*_PTUS|k~r}eE` z*Dqe5cWcT040m~*DO^_Dxv}=KWSi@t<`Rq}T^Yhpr!)I0g zjZoz)XV_eGG?!o;VQ~+|4y)hVp@VF$m6}U1j<5zf!s=f$cYw|HbIm0fM_7X$VZ9K| zxX9*uQgaE$5mshAELe<}FaGT>ZLaN_OE8XJVu)~Yb-`NqhrJJe+q~9sZRGczn^5b9 z#B1G$TJn%)wJuAztXel{+SpY#*AdMn7)L6G371t9R;Jy1kaUxMU>so$cZAh7b=p9iYn0{^j3cZOj<9Y&`0*^8>oUzH7)Myy!llMgtTcmX zJZy7SYc9b!!W!ua>)6*LZnL?tbtpzKjSWk{;3_- zbDB#qj|C)nhmrV9L=`I z?oYJSdCh9w1;S<3x*^Fg?6tYtYIeamQjsfM?9FJB+s1H^-3qI(w&cPG<8s0*E<_jK zw}>JBj9Wf>>7M4P7$ulH0I*UKic21)C5MclYlO`cE-Mv}rTn^!&2_ov5{x4iVd1h; z@yw7n&$GF%(_Dgaq#`0*T-$RVU(&GlQ1eub7Rmto17)My+g)7Mac-H;yg*2P%`kD=rH@B5mI|FYZg>24 ze2$iw4Ni}QY;bxcWP{Vgs^cw$A*uD^@bFM!3}-fYad>#dv%!hCv%%pma+|+y)w$7< zZ=$f~%<+2I+)K-C4dJfL&4o07c@r-@4==0uJiM#|^zgEZ(8Eh{LC5f{xw8^a#>_Xg zYGh9@#Wk#DE>ADTT)155N=ls3l7AAOySe$8V7zo@VVY_&ukHks-aXxVZrgMEbrGw#&M07bN>~PVYv#@hDhQDdNbfVn=_X6Nv z(O67MJ#~6@g2!9H?BNz9Ol$G$gbl}@cxYOS-*8|?yKx@rEdyqr8|O+dqrV224Q`x= zyar(Y;KsS+aYy4LjbS=yyz=jU?D(|7R_TM>=7iw}kXQM3g2(TG`8_uzVOq<-&w)9v zaV_OvI%M?5^f#ANV3;`0BfVDubCnzCN-yinDq!w#<2>X&0n8>h&LxlW+YL+-H%?(% zi{I(M407XK@>sqF8Y2Sn&#OFm6~Z*&dIc4#rShnN$6#RAovv`LmB(|yyrgmQbhzTj z{M!f2S8kj~{`Kf<7=7{3v?P!9F9ggbZk&g_g}~Ihajy6UA@44YfmMuG{@sXn-UwW@ zpTe}%A8?UA5txZ*C|qm#cMUKrHO>#XgzJhQ^Y0#DHo9>h>3t2DKe=%(dCb3Wf$4Up zieEfj4|zj@Ip2+Q$qPcvRE<#*z3bl*crFEQf!;V^zIgQq{Lbdbz-;FBElg|qw;z}z z8W&H8D}Kzsld!4V4-ZWo=aJq#V2a#0mpta*9AH+saUSyS2Idhr&LxlWds$-`KN_hA z9y$o$cjNy3ItZcoeO_txch^CP_ttS8gt#IyGI3(bs8G0M)a22lBNIysi^36{6mBmX z1hF>)=aLDbNs~&7qZ22?1Nz~RZ&zJCYkqaf47s;a^mP5dp-1rlRfU27Vzq$(0`-5? zOgRVhQfPE!yO28gAC-W}loj~$KwTA4I(;s5gUqZF9epl+pe<+#q_(}Pgk05ET2$f! z6>w-Dz4E=_`m5bqd8ZW$v5?r3SaBfJ!#XF@e6A|ebbQpRa1R?X8rKqhZ>gk-+tqB!8ZaO z4~wD#$T|PXm8Ctltb6a0?a$;tm^Bt}7(Wv^4TnD8SryJ-IH$AkgA0zdEyWcV2sqVu zPfq3Yg&U3^e&LoOLq;!|Iz=wOh5MmrC%-Yi=dPN^r#{^0?LkG4$*0e7U)MBp)tdV% zo}N&fcEJ~UX}8Kpjc`BOuI7)Ytg3qN?3G=caz;F~66Y`4Q2yR)N-wUzsQa#sdpjN& zR5SN>DEtujU9aD0Zkm5*+NaaDzfm%F59YqD>k-`f<(z}hzWC*s>wG76-1kJ*y8q}A z{4NUdrdNJPm3miC$E`&RzN3%@3+K(pX6?*Dv*uP(!QaeTmE{Yj&RZ~aDtnx>htD{B z!TeIO1NB|Q`i~w#cfOYD8Q{NJk01^aWKgS~eYy2hkD@E$EyRJS>BCp)TqwZSlxpS; zs~a;dtD$a8S>2cl_3=EvQP1_msghs1M@5Go8Q9IOz~fe!z}+eO^IhJp7|gUuctON$ zkgvz}dd7kzP<}n0iQkFG(x{Is8*Us5i+rNta86ZOxsjmb2EA$AFdjjqGZ~a`?P&0B zEXKG^1m$J}F!Fu*MW93Q8~m~1pqGR4t$hh7-@;7?9SGV1kNOUqwiM$hakur_mIA7F z=){75M5^zwm5uQUh?_69t&xgDu^sj0ywo`p$!XLjCF)_IYeuxpK>1&twa*_uhhN#Qvq(1xLJf@H$819z{f28sRdsdM99uaei_F6y8>r7H7hd{A z;hgDLLidcN95D(H&NP&AL|o&hlp{`nQ?)oN<%ps+k@}BV^vXl)#t@(QiG##gF#gOK z)&!O+O(ja0zpFrVLB9`rE$9MJVlZCnlBZ3b3si1zY2Or?C{VU#=&wp%*;w-ORicrm zA^kOF$TmjVI>C(_5`JDOEwVwxc*zaI2VdXg;6U3lRR=BE4AqvXY+N}j*|3OwQW`JW z3hC?B!RWQ6ozcCzqtO*QYAhWxVW$E$r5IvSWMs0^2LUY)=3VS>sNDgzx1jEx^cVud zk;OnQFLQ+kut)hDnj;F#hvld(HAp0CmWX6Eg+@k<05rT{2g~eY-pJ3PLOA?1Ae>$n z!2#*A0dMDQj@EbkeSUpqdTL-4+R2SC0E5HcXbsfM)-)kG4vnn&^{d{x8wIjmyrA^9TTHV%= zxif0M62_q{uV(jdfvHj*!cjz?Bn;;)ELeK4m0qMz;;qtEU~ZJ-#UUIjFVjgK32RMO z$i%5G_^wAp3(R#pB!RC$J6qIzgULjD4>e6pj^LzLS*SK*`1U7T@KEj2^l3(5#T#JN zIj*wwC7tL3bK#W08g}S7b{TC`he+vGKn;JB&eLE&@}k7;VGdGe@k|} z_uLJfWtcDQJ^6BCr*=fOi7~HMgU$oRo3I#qPAZ0oT@QLI=!2lQf&K#YcFKN1XALOh&0e058sBM45oIFU4N{aF`IrZmp{wfUm5u%F zP;pCx1mjS9WD`byoGCJjJ41zF7hxPD|M5->RPk{>qHICf!g%~r_ZXgKl)p7@`DJdC zEyy$tvE({2imwweN-j~X*Ou{;D_{2+X}wd7-iUio#JwBho{ID&F+DI=Sgofa5lOpO zSSnV&f$fcfdynq%6gI5BF}?)T*!T(%=5N71*Sx2!5y z`m2aJ5!Y%)^~0%|D4f9GgW-F!3z*V1=HSw^(B zAvwfz|I+azh@~5>gt!tR1@TNeBUcwGQ*o^+rYaXb2CkMVMA(c}MC&KBV636A*6&j} z=!;a0tf^Sqep{phQjC!`Wwe*kt^oc>SzV+Om4qV*`%OzjNZ^LOqRa!@JG3$nQR^Xk z>snRj@hya$i6_bUJ#tvt*epN8!@KsNHoGRzweI_YrWbd2T& zblS`>%wS@DK~d9X@YxQ!6u(~sy$yW3;H+E2q?p&3IXCKfD*?8AH+=oCGK+2y`Wcu?gw1}`Z4HQ&`&^lxSGE) zU#DK?*omNrKzo561-$_DE6`D(-++z-MSY4*06hkJG3as7sh~}urJx256aN|%$NXdL zWb^T;!HhO2AVHYQZJ4$}V;1ntTg%X24Q9%gjNe7#mZl+BYRZ~yW0b8E+%Ci87j>kR zZ5c1QlLaYS^7h~`>=tq>MW&?urMOb#HZD$-d{`t5QW`J$3h68EViX_hV2pzLmGg0M z_LAol z?KMLMzXbvl@O{)vk`yZ_ZOEsB*QTz8X3dnW1EG;~3ZPa&?lXvDm9yq+pu_c@E{oPF z#l_U55REqe*`Ht9NQEL%aLYIstv`1NJKK!;i^DR_9c46pMqfmu4Hfmz+h4s}d2)1ps z@h?dQW<%8fO4R>)!GM=Ug^HT-Q$rS1-Zeto!6q!=l1`?Q1gO%?uifj5)`gDN><(kK z70jlCc zC(an{od^DM-+93=3EIPbI%tA!g3|fr)2qwn0&nz=C7Aur#2XJz%qsx)HtZzl!7H(o zjL&x$CGapzc0H_+mD;@%ni%78GH3y4Z_v9z`+>d)iXw`kdoj)eW!EwQ^fXXZEzu7^ zJoN$$0_CZl!Js#Q4gnnqzG-+=)1^(_p`qMXTl;+D&Nz-~k5B%?E$R&upk9$E4`!B=sy=_(tWu96Q+ zJSMbH!{e5(kiH?EjUnh7&PLNc9o<8pvQ*;~G~EE^p;X<@jm_nJMJ5W`%A2vnW&l>`xwc%Uv+wJ*5PPf zGonU=GlVCg2c+lnP{w!Y6q$7k~}#HRzEByM9$&zB^9;WTlZi~p=bc0;-q zzs_?h`QRrdtOf`0{KQ_|s*fW})hpSAmxpXh8Gw2lug%(1(Y&$&58}ZVUU_+02|r=A z+9q4t=kSW*u?*wHhK5Cw?BvlMjU&c*hCo@FMuDCNii6U!VH*V5gJKv^v@F3Z&>mx8Xx?-EdkPk-hX8@y_8w53pKxpsS4+frm3m2tF;35%+@%Ekt_ zOx)5mWTmD|fsIi%Hj*FU@f$?##bX&Sxy#{+2FEK&syje21v?*G4=rUWF6NQ4vB4?% zut*rBG+y!*(zmd!v9K%|8`ACM+7QP3f1`2=ekkiSiJ!>&;pO*D(tvj!-i9d)sue!V zEuT?yWx9AUWq#iw{HKkkMdcI;A1AdX&d1zl82t`C@UG3p{H76%TGxT>T3^j~<< z@J5?!0G(h2<2dxi688IUz<mto17)L6Y<+cKXn{Sz0Vso*(rV)%Itd4NC!}{vdbI00TYlMgG4j4yR zlEXgcDDye#^&OjRt_L-jDuu*!vEQ)6x_0r%zu8<{HJ4xqHCzu*xeCFR#ulT$n(!@?!UFr|WmG zC2g>|xL%Lw7DuZmnzM~@;b>8R=>BO{>2#ec{cDl|xmT|kywO(@x#*wZb zj<62BG^MZ2B?B@11>*>dwZbp;5EkRbNQYH6*K0Z~!8lqj*Q9SD{ij`v3?n$P z|2ai46$v%LRv58gOa6PxDehcmZn3$bN=i&GN_M28w}fSt&iK5=r8ZY@MiE9ZjvPA` zu6C_E{mg^+*<2$vmtY)W^${+WCx%g8|KQJTE^ffm2*wc>M|3-^4G#=@$L6xODFx#Q zD=1w2Pjk-M1>I~eZtBtm@i>nJr_sg7i8C|os_@ImFxnDJ=XAl)*=nb0@pk&4mYik; zDLG+u=qp@S+u5<`V7<-Npt%I&NQJb}c-!$^^yV;|YnSFytvE5PevYu#l^*`9&2?OJ z3C0oD8Ny|i&P@XbRoh&rvYUVrj3ZrV!qqOF1J7KakgjtzmtY)WWe8Ug|7kj3v~h;|MD=o-SC7)fXSTz~&mNxdg*Q z!b64<1jEvC9ugh`7q3IY6CuO>4TwI3*34NS)pEOgd|;p@#83Ywete+MmU;V0JxGtA z|MlSW_EUUbG0~Cs@M?adwAo9<_;I}EKGtcx<~}Me+3C%Fth0E{eH71#7J0mU6i;(m zI>pUA5*@4^Yn?!6WaFM*@r`?WMLF)NIGwSMdp3`F+{+{GmY?@-Qak}Icw0$m!P`ni z3*J^TTJTofEqLmrc>A`rqSwi>j!-sV^6S>q3P43FOP|kdQ9>&KC85PA>V&oA&vTnY zvxBzzd*?Q@vNF#ZA#k4CTrB4{|8}`yOvAuI<8^NHTh5UajmNpof z{^oj|+vJA#W{n|^#_Jr<4!HNkd}lA`JTUBiTROLy8pPxc4-H3zmd-(aFGz%Kyv}J= zARopCZ47N*@#Bu=uhQ@$<8*~>Eq>kmLgx$~n%3f%3(N#JPU?r^<$q4C<^pq#8|OL~ z!~ydTU>2>M zX}r=)ZH=RlIiopSfQifVD37_oT%&O4+~)z8$yp{0!}ZEP1Nk=|nDLxf!nBruR|9i{ z#>La&iXZcDJur{DaUSV?1(_WhwCBlEMSJaaV~kCAfs4gL?Hfo z<=>0QmubND=WG^+`Qnv-c-vxJ2+SPLUtwCyzuSPhOXK3{aK(@L_Z%?W-8hf*9suSm zH_j!G{Z$Xln+J353=aW#>La&iXZFCwZPo$#(AXo5n!Hn<6QEX-nW6-=f-)+Yd;*fp5mct zDSq4x83Ih98|NW!HZTj_I9L4AA@4R|o^s7 z<45CFzG*18kAUkKQW!K-&+_F*DJKClXOzOVR=&3ZbC<@&^TicEmdA6zYm#}*gwAu%olE)hrF&~ z9L~l=x+V8wJ_y`G@;zET>5_!-Y;}O55 zz^u}^mg2{7?gQotH_k)ePGEMsajx`I-f>{Mj92lChwCA4ATZf(oJ$_t??u2|<;Ho) zTLsLmZk$UV+wZS{dB=_OkarZAq#{>3T=H1Hr)!KtdY3O>-V6e+V1h!i+`P*7J-Al` zGvPuT*V1}$5irX&E}qY>_^~`T0P`z1&Lh1$fO*f2bID_Qd<{&Oi7I~aa6RM=1SZ>! z^N@Fu#wdy2`B#tpy9&4?lN1Wg#WVk=0@uG7r`0AaTx;#)7r;EFaq)Dx;>Y~^BQPJj zaUSVydl6pF;h||s9{ZQUz>IO@Jmi%F^L;nY6+g~jZqgWrOXJnQ97Vo71l-+I6o&H( zullzWxG#XiTFbvrf%!(`T1qeT@8ru+CU|J#IFIy>0cMgL=aJs;15@wDdB}SR znBTZ@9`fGM7!^bB{F?>O&w#shszM=~JoE1@xR(KQ?&S*CTK<&*Gf(5<`QnNn%V~|q zD2Y0L9(qr1cjNwfy(bG1*0}~gnS{aN;n6J~9-g{r_^_!H%PY&LFDRdSRq4D6e2@3t z)Sk#U)6b)QpJsIK+6h~2%7~tXxznp_=1;FIshVGgkN!?E+IM{j6|B9j7$uxnT#{E5 z86EdKMfv50#ut}NnmlPjWPBKc72jFPFA8NUC58EuCgqPG17@gH>7@a~6kvQ&iC~ID zqY5Hk8X8*Ev_j1nHzS5)M->$1jSEej7`ntrh1+9vQ!+;t;9N*@*G_P$tSX&eSxz+& zB@3$O*OXRc7c99e%V4aei7FOe!%xYIvhoGhvydONs^*r=xpF=()ky9d1awAK6$)c6 z-ts1QU54C~5-BO4TRp#O-eS;F9HX6&YuS>!Vt3P+S6zYcDa+=}C>8A!)E$CrBUA{b z_{g$+rhI8Rzp9dYCCIfMToQru`SYvhOVIz(v{HU$N%KAN0CFqX4uv-^{{@;>{!Lm{x*;JqqHdLzpf1h28sGa>(=e92wYPy;9Dk1xiO zn(9M%Xh4#mUl{v`bY}lCwxlpJX%Zr+TEBPdT5nJPgvJ%N?Gun0$gQlQl3O+S zm7r{;RgEex9ZoFxn3Z$3E?(7S`PuVTXvcH#vJNL1=ixvgo9s2sdI$P2B}*(xbEeOq zT|U2L;rvx7*Vv-G;z+TST{1FL_b8~{(xU)y2+tiDFF9oXM;FWA z)5S9Q%zESFS1$<{t~)UQr8}QTrhSDaU#f4|h^C5Ljuy3v-123QGq3%25MBjg&XDTs z-S7FN&ZBofIC|yGygOewge`&##JzjT?QI*@k3I0p&*t2A+3!BaHy5Sio;~WxfrC$* z+3uoi_O&_T;DxVax`%SP5q_;`3Bl{qnX|6^?pi{i*W^12DV<;auTYNi9~~{z=LAJ1 zOfX|n_VE5w=gcadU$vlWW_9rDSqo~WR|XeU*Obkw3T98ex^(KSxuumgW#v;BRF_rG znxRUt1${CyEBKCOTsdpbtm^Nq|E3!1Z*-MyA+Dt|S*>WT-mCfSzgLONt!Rpy@N_ip z(6$sg{-AV)m~ThT{A^y;ic>d>Gny{$xxAsK2hKm>=s@bWQ5mOz2Zt5#OYVwoAFay^ zM$Iue=0J|RybMbNNXBNaO+Ldj8_y8eiFht|>Cf%F7zPS$%4+7!v%c$Z<)8poE!}V^ zAQN01Wr}=y{%OQd-Au3~f-)?ArpnKt!`gj2g5}=I4p4q%`5I^t6#Z3<+u?73a@+Jx zP|Erv=s?g8c+|)Jw8;(g+HJY^O#xM5iUt3OR3G;%8`oR`ar2$j);I|t;de;X+Jd{b zm3|#)S7ABG^}HEjbJnnsdDQ$I$5U#0;v(Pd0y8;;%Xjh84+VlEV}Zn$^u#G#z9bF% zKQ*^M2aECghfnncsr}R!8t`)8UYH4=%7a-qK^Vt&A*C(-=IkNqKY z%aOMt^_9;XGuN8iaFcc5iGwKqVD2g$VaW^Pa7kW9Q_XNy2WDk7O-`sF$%v1uff4m7{)}U(T1-ByJw!m|g!0%@?UDUe3c1qr8k=OVkj*ETl3#^zZN5zm7 zDtd_4Ey)bm%^pTA52%k+>p)dCR?Wi6}2@A*BU%UKCY24BkS6gHLF^jIAyhKFB_(17$4T&R5+~Gj(cw8t)77gdJOQNvMu8!HwaICrmVPw(H5F!Xe{}ZrMQ@<%EtdnJ}hx0?OyT~ zQnc9YY^$``l%>SA*yK*aX|mvNuLCn0D~^k;+Dk!^tarn8m!V=_HVkLMf|qS(<)U=^ zc-2+-mFcRF8E|9#PsfwcQ_ifcSx{kD$RK<@3^KWuj#7?Iydeh$;_I1&j8?pi(`F21E7o(&Lm3D$PW)xouEzijLK~}ek(Uvz8EdtRGk_%S2wcu=9liMO}g2)IcgR(&dV=t2nT+*JQ=xYnBA_= zH(z8$me@P<_BOb>MV~~ z!`iiEZk0jDo^eMlUB)Zi1r7HJcr3$sxks#1kk9n*1^WZX%CKuE#+Fc-{O~gDJSb;-wMr1`p zVEK8lSSOmJb&G;>su{0ah!vVbwXOtP|fuQUw2ZQE;W`a`f0naAqgAN5<0tzJpQde_;QFWEJ6k{X) zE4L@LEk*KyVOoa%st-{%Hph^-rD@1uO*yXE7-i#Fz*mlb%mY*&gNX5xI|e=&SGuJb z-EgOOD(?601T_H3&}oxY+)=o!uzKQ`lEAj9Y(dymSg=TVq%>Y(DWtDQd!q;LDnD@# z?kvYW-|cVUtm)$nGgPeS=wGo_{v1MN)|mC~t4FK*LP6iFM{B;S{ie$@Ox;768**l* zW{O2>rWh?9Gr@cvr}tym^)#xxqHo={mO@HjW8b>JH#*mC^U&=kcCOF}u$R$Y@ose& z^Wx&Li7r^Vgv~LSV_l3IzJ1%6Vqyd+Gp=o8Si#W8aDjkB(3`KtFV#2S6t~?68*{-P z3uoh(yT5J_1l}ftCX9vBUzb&{(qh%a*8Ysc=)W6Opug$yP{TC+HEt$|z}6LVf3{bu3e`I_1&% z16(MfPRSq@SY8i#uO2mzq4sZ6wZF-u_FD_r(!2@gA5r^rvuF2|+P~Rd`!_eQ{V(lh zq*pYd_D@3X--g5Y;u1FVQ2QsL_P2B$z>0^!p{Ih>9H6FxT>jL}&cqUB ztI^ba5#(BSd#tMLWw)%ju{w)=lIdKb=>^q4E(`sGEdG(lBky007Em*E8XDz*!?&sJBPD`->@&Q@kax{?_s^N2>Q?^H8Qw{%>xEm`d zHx5?f8S0u2^FvMg^Q7fXuHg{d&(+iCE0snWz<3+)K7e{Zv%$coUgXn~O6JzgQLD0M z8U`2-clUsg1EhPPMu6Wy&UDa5&>5hwfno_23xcle(+MV44mvX9mpiQZcRc`CGZ;C;=jH6}fuet|iOUCaiaZA$>Y|4va?%Eh- zWB0HGj~~lcd=&h5dqQZqTI1WxTe{=^TSzuyRq~b?(81tg$W4q~wJ_8kXUqRjIAmIh( z*9B%S=DedbYM<)FlvQ`FT~=Y#bTlu5n&MZaIdhj}LL_TXc;vm)012!)0$c&NOajkA zJI~VeMFsW0K(WFN&4yY`XRa+QjTmFi<F911+xm3>+JO~+;3qN1_$W$0Mu)QZ2b-?I!e zc2U+-n%k|q3r6v+?8j=8p7QO7zMX=t^EiG7*ka6XPg$wq_>I9kMD@NZeN@B~s@(zw zn$IUGouVq8t4GMb3eqGRGubmNikgMkR2d!QL>8M+qB#>e9ZSd9ZZeIt>=!&LC!NtO<-7;k}hbxwMl5qxjRsX=;Q#RHC_6n=; zxb>ZF0*d}mg8tm9XgD-1ucJ%ml-87l^GasUn!iAG4l*GDyt%O^zKN=QI7hAklyBOL ze1&>m8S4fFxfJ3!f6{s{DO(4T-l3Hnpe--7-O^cm2*KpQ~s1>FLAALtIy z{{sCZ=>4GYg8l+@H|Q@x4}m@g3ME6vW-fo=wc3}Y)Oc#LhJ?7d=mRPRNb>b;cPdig=sRFmzIgaqIxf7 zV~@hofs>my=uo@BuGDi|GzN=OMWk#fJL6~K#xzmBWn!?nWv>>uH2h~s-^W9fgeQha zDLYa&_GWj88&Q;PnHVf?xjz)Qw3FKzC+|r%I#)vnz)mPVf~yq<;~5haYrV4dgiVE! zh=il|Pm0^(T=kmOh-m8bY!TFrbWroKK?cfCD!zLd}TQb1zGE z%WKD$Cfy%+?%dFdrkZ5zO6 zhM8B)#THjBS%+nvwN=eDkIPJxuSo25R^m+aO|G-BHUE#!G!N^U=2k1=)=U$6qcGQ8 zpy!$krqmt_EE``RIoP;23B9X%@W@+@yOaET8Dl^SY*0;YG61JIx!}SMI zd(4~ZY6TL-U{tf^)h0A>42D5$YrNWo#pLmnW!>`4r1X6A4|)vZFKEI-0F56c`9E=| z@QwINl5^?johwOe<_vAu7=^52MP_Fmz#!za$}I;w_<=Qf*icz zzU!A1H(`%8uwpICqv^?}3*hdU`nOylocg6 z2jkHHvB5Zo)LDk{;9z_<9ICbZs~ChBw|79#1BLQTQTFvG&?)%63zVx{bX_s#>t8{y z2Hgj`9`qy7he7v)a^?Op=tj^lK%WHt67)IHBcRWN9tGV7`W5IOK)(jv4tfmqb29e3kVgFJ0&kXLT&wQq_+`79&L&|eKO%ErNr6CV!p%2>M$ zEI}KiY#iDe@%Rm(N{GB{3J0+Jg@6=Ey#+LiEpoyYv%XrD<#0+w|GlBs=Q8rU! zOH?)v_DXgllJdP|D`Z+pC!++DhD$M^_rl=b9fN#VP9*ds$jT!Q=}Jm4ZcB$vx$D;Wu1jJ78X=$gy)tFG?}NCt-AX;^x3ROe5% zyvoZ6)jrD(&Zs`6mR(ynGjTvKPOm_hIgRV5%t+SZ$jHa10UKCz3I21eU&O&(-iJrI z7|Z4KA%k6bU_}#TLe*&4Trw>1975UVd;OSt`|ttYJZyjcgO0QD!n+ACyt%~?F+WUr z^KkAqYq>>gJ}>XPkFw*=U6tK@XXYP#J$-!>VX%(mNY+JBRuzHOZ_B#~dF6myi*M~r;L2=KzAWW9Nbz+<9R?&W?eGl; z7H}c8f|K_c|Bc~Dt>7jjxoS9KQ{n(ohv$2)J)AT&q7HEH0qQ+KV6`^CeCDjV<+7j4 zj@jG%gUdAt;fjqNwPhF=4iX#)*|F1LIE-;caUSTYpt+!ZLGwU|f`&oQ2OR?%1&xA^ z2h9h)60`u6ladQTcR+SACdRg4kG~^^rS#mZ;+1R;$ zfX8nzJ(O)3FS#7pROd>W3pKPQxw`~S6lGh+OYYn7gxr%;jFa(7q}!HcBY^#-6uf$G z3stU(Vf6%3NnkgqY(dymScynDYJX?^6fzB}h9=_GOIy6|p|SFa`Jtq;3s*MQAeBe3 z#F4Zsf2Vwf^mXwYU7&)t!v^+p1?gD*Y>8g~@gigdUc~m)JuKe02BW19sP)slqj>Fl z&{{XmdrPgG&;fp4V1AakkZOGiRapA7)eOaK7s-0DAm{ypx`)%JNU*ZO4*k!C=Ie## z<^uD;brTBAw+iadVNz6YDKBfsl_sqW1)l4cx8k+MZH~Ny71Y(7G z3y}~ui3@U`U$&F?(8M4;VoIpyk|~9yUlc%xb(BH+mrTnqeKG3*ZVSk2$U0n@^Cg#w zL1sv1;HJxwalGk=<3VC)J=!eWm>XHKCk($;@T=*>bptxUeT9AqtvwzHtVx5r+)#zi zy)frc;HG3a=w%#-^QrT%PeXxnI>7wJdvCY-1I4ig)lA>V#bAPzx6Ha9*XVZ>ucm-gDVJ#HKv*} zbU?DXw8v+4vxh;=y1nAW9>JqCM-B|h1R^)^)93N+LhT1WJ&E8~bB)N-W}h$ElZS(9 z@{rkl^6(E1_J8+VxqnceWAb2q9+!;?1Sb+fsX5j%T-O)wsGurl9pkwJd6j;tpM=r?GuEM@0Q_kb6yt?!COQt-4b{JU6cRk!TxefIHV0*(B6iT|= z^;SW*{F*MyU6XLN6FVmsTmdxAOP^$p#k_T6`UJT1!YSz*;a4HJjp_4*KAe6BDR;j4 z;pw{g0lR^XVFXkSb# zw3`nZu2%FX#%&p}DUKO&w;NznVXQ!=Dc^BzE#AxHw)wCrU%+HK$Jn{2bH{)R!2JNI z_jC^H{e!f#qTCJ{!}i6Y;wev=8WfQ0^5#O{jbWybzSrJM1IIib1hnj$IDA6toodTF|+m zD?uLx#qCP5r$ASOJ_}k8`W)yQ(9NK0LAl1i1N0NnJ3)_u-UXV8IQ`3ury)^PoQj-3od?=!>Awg8m+K3+PLrFM#dSwP~6fq4UD&6Nlkd zzHcxlW*?)gWyKlIq1@S(?; zU|m&aUDdFtIUdQDBxAIoeGDG!Lkljrv7ei<`5`1w_2BG5lx+uWsu$iDcViXe^12Go z2-otu4>FPd9YGUrHo4J&`=<$-D9W~smt4jbZIt_b`22vzlFd+U ziOR+{s$?f3Y4?(?kiJve8>e7-dqNpr6yh_7q)})ZwI4@W`LPeiJHyauD)#rnX0?gK7A|PjGBpNwA+5a8SNP@{VKNf+@MjD z3ruxNw0`3^F#vE)DQxRui`Jfxk2tL9V6?7Xp}G8+q{{4Wxo!=g8}woF&wGb*9%5XU z*6WXU5x8uN$p#o(Y6Y7w7H8H+yEh{Y)j;ow+qko&n(7G1Vk(l1Lj32iBx#h^OOx|m zjkaD8XwaZ7G}dF~Y*{m{|E3q**;IRzj z!FZnphmDq_--vNX1=CBpF{J}&1AgPhfxOH}1$`C2PXML7ZlK?Qo&<_l!$uF#_MkmM zx$-(0lyl@>pxr@n(lmz8+Kp2|`-1iX?FV`q=-Hq_&@9k2(DOl02gN6oMqf})4bK2& zr;!f3>NIFmFCCQIdhMGc`O7p~hW@J4P&PJSeg&ZhcB1~Qq3kqljIy!Q7%pg{Saz22 zlFLaRY4!+|HhuIZ)U%j!Ff z(DI^z2yPkAOWr?{&9JlOPnR>JwM(X1Z{UfkISJ#sx<@JW*cv0Kh<4H?V2^`) znv%jfDs8Jn`UG1pzlWM8eT{uoKsupqdBu#$wmcbpx8-H3UyL*^o@9fPZVGRVx8+sR z(eA6l_;oj)Bx4-@$HZ2K|J<2OGWdd%leZ*Zk}E?}lCc3c*0CghoyZTAVY>nUCx{J6 zl<5ciZ1-iyM+G6@6(!yWm8gN82V-US@sIUjyoQ)*58^5E>FyA6t7k!1NvXB=V-LiZ zW*NqZ^`tKxm?E0l26`e;WK)bi-S4JdCJc@p$( z(5FE^1bqe+udWSDHYL61!LE8x+SI{5<%SUX`8(Y3y%=9>#|>Ro52|d*@W~UmG>zG; zX%eW7QMOKSD-twOlx-O=xm*^b2knllMu&FR8+d|Ur z6^26k9_eU2f*v#*ZyGYto1TQ8)apgm0l$R4>`{oqvY$1n((w`p<4-~5Cc!(^js4;t3eu(uFnJk9~-T66^H0MH!JA)vV6 zBUS=>J}Bb~MG{i!E`l6Y>1b0o6e_pXKq)s^WPgm5=5ioarBgOmx~bx3og8Fk``>us z7&W}NVG`md@rn{ZT>ZYu+HdNdmvt5F4P1M@R%?$gB zk`2eUVzxy$8a5gl!8oq+V0qdXj@^962y7=>Tz!Q{)jj9MIIIp<26B z!4mWP*qK>zwlB*XA$+V|L02l+Y1^r&{^cDLZLW~!5{x4iDZ<56GJk)*bk&b-u42t4 z7)Oqwpc2B`d;Plso9jx=B^XCo?9lu^b~y~|_h%ja)aJr4B1SNdusXxtPS=9lcb#r? z)oU)nIKt{8Tnvk5O4o*~Z7vKUVg%#328VmKeqRRuvrKNiID2#R(viIKHNf909s9bf zN8w5nXjVGxmh4pgb@44{*<2WM#0bWbiW7v3^?~N@``6|89Rw}ZduKBag^{D0&j3X66;j;RcKfTs}yUq2y<`Rq}$I={OO?vm_ z3Y!bxCW;Y^BdpVfOKLT2JAXCpJe%uN%_SH|Sbc@dO4rcrWmnr=NqQ&}j3X?m13q%m z9O$*+6Pt@4?$D@ulGrNy!PW135piM8-*WQ9bDEdV8G_-SwpBX);-xb{OYUd5OXp1C zvQp7w@yBayu58UE7)L7D%h^{=Uh?kf4mQ_#%_SH|j`eqh70cKew7JSOmtY)Woh4kV zC1UQ;ZSYMt*EO0;FpjV|L$cfH<3qYWYIE`J4UJ$NVGV?mJP|7)RSV zTevnM=h=4d{A4JaGJZJv%t3Jv z9hyrpj#@WTxcH?n>&N<=pPt^l)_qSfy;0^?ts5DybsuZVBb(K_9O1HRoo~&JlWZtf9%7)Mwa zIKnz}+tdj*SGDF6j3caE;j&s&zo89&b~==xv;4O;=!d zUjG<@i{HnOB7Ly^;nY7*Z(a{a3x-=OIyy!qUJr+A$q^&ynmLRSE~_4H42(V9<{G29 z1mj3oRJg2qc=sEf>TRxa%_SH|9_Bm3`swcLZ?U;*HJ4xp9IO7)MwI!j;bdc-~*U`g5D>ea$5pM_7f9u*%yE8ftTWqqzj* z2y47>Sz~VCi~Bd&TsUPXMlg=BiX34TU2xejn`?yT5{x6P32`opJ+Swg!#39>%_SH| z?{}ea@f!t}^w6d@KWbjv0^0@_+gx{RF2Oi*j5`u`Si6dbylQhbYA(Sz!n(*2)?E#~UbDG&X)eJy!n)WI z))%!^b8W6;noBT_u%-x?)%%_NNbm-mt5 z%j*4hthxEH&2_Qn5{x6P%N$|-_3R}FY_1y3B^XCoQ{!B)7~h^+*umzyS#t@-QR^-j zF6&Exv-_>av<{t`W2Se7VBW)jtFOB}Uh96TC12jG)|CjC)z>vlI0&`yx_KH6noBT_ zR7?{ttJeKxaHNmT^{(a;j3dXUJHndOuBf}sby#x=#u3&G;j(H%#VPB~w7I$_!xKg@ zj<8DMYS)A=&!6yLHrGJSB^XCoWx~aA)D(% z%_SH|Sk>{cU@62xWT3(Dy!hAxRESOZtTZx;Tu+$u7Y zUT9u|R}1DX{I^Q5CSHP>I;SCxxc2FLw%c4`%_SH|N*4*2ZUC|iYIBun zF2Oi1&1Nc`mu4>(ITP^TX_i1nqIz9@Yp=se-;$f?X6rrG48zkCoYY;z4kx)NB^@_q z#}%g9muK5f3YCD-LEA0~3NCfXi7pzR;3S+{t)h~Gm(1n!E#-JxMz)TZ)6cqaxn;f) zt?+sKC8p3Bnj@(WF9}~OGSd+rssgqgRZLxuDySh|NS9+mq%4VvvC(c44NIAljt8zV zXX(XVRYcsbN`96n*6o@Qm$=l#$XJeEN?dfLMy7jus<^e_se(m4@X!sTYibLgiW8;X zGG_~(iW8aDGG_~(I+MKkti1B@O9&@^)ZQ!0Y)_9Yvpqes%=T2Ajx4i1J+jR9RGf}1 zvpp3jdKNo*wx{B3!LwPG*?i5jEbixV|4%~D_IXsVY)tU=$j1ac1YgCAUc=7J1YgD5l5ex@OyF#upSEX0Sjc33{KG5v5_~;!FTvL%_Y!SMj=Qo0THP+mdgy+)I$#JojwR<{xY8tQ(f@;icl>>7^o&)iRf-m*VmW zNyoXlPoj(CLscE`5snx*5mxs9JsHFQu8h_Y&C}$Jg-6mH0O=vFET3CaHLrTs9NZFC zJ$*)Hxw@=sdL=HTDdA^r+O^r&ZaN#X)0_LKnpEYU%7fd$6D4Zk)F3Q{siF`0=JJZ&0)BC<`usvaQ*r~ z;pAxolQnHi@p~4S7d5V>_yr;6Lyb`qbvhEhvY>k=p7uf7Y~vNbgYX^^#1|833dhx$ z#Lp#fEZmEL`H{vkeqQo|Nbhfe`Qz!W%ljPOO~8ECSK+uT;3bb=C$~+DL(8-+1js_+ku7|t`Fc-RUE_rOaRlt~ToQJ#zfO*`FbID_R zUkBzxH_k&|TQoX3*OizKmpsbWL(^-t%l`|!-uKuyN*;L^V;G3Nd>s$wKp7j zr)Y}0I(SqloOpMzb@OmX+c$qaZXGQsnmB1fC@*64(d?aUz}Q6p9@@XV?LVnFR2;$G zvMSu($|J9+a6-}e2yRQwE1EpM7^>uycbf7JUx@gQ4@agTUCCXq>Wa)O88sQVAoKR) z7H>0l-8ssiLFT)<0Q7(GuH*mQW~?q}3+CSBfP%T}Q)Pl>8syis-o3R~UZ?79+~ zw-euKdH%n2n=$Kg8tU=?HTM>K7w(Bj2D_uNP^Dgs8;y&jMe0Unk1LMVi;EOhbzy%d8NG9Qx)w;c022*f7J)IQ@1C5>=La)4eku%CUI4f{x(H#zTM13NWLF{s%midoi8~ zc=%y7w+iUT9WLUrIy2_r;YUnZxrofZpbRS)&xLr<9m{>we^WXL=%m#jX$YvyY|T)Qdm7;{0fHu>bL&i4A;iz_qR#%w{1&B3BLc2y*Gi6 zsyg4t?=TYx0ZalYsHg)*jfw~aFf5h~2{Msj!lIyJLkK~lNMbTkkZoXyX1*heTh(eS zt!u5;eMM~$OrUi^w5@xob%CN*tqZv2|2*$GckVJb5zudc{r&zupSkm%d(QK|XJ78Q z=e}pD0}O{w_^dZOt!Musq0YS~S9BS0e(#|xuJ~2@;p6UGzyFjMKhDXUUAMAp#sPi$ z9(d3ZM;?`X^fAMRk2oQJzSi4jRAU!i9@2 zimhtA_>!jh|6F<1)z|#&+Uu_W`LA!j<<{G7zvDM|-v7XZ4?X5 z7n;sUKz1Ol|B%i-LzBByoZoA}&=u*u$6fKO`_^|oJa5X!`_Ha>G2?)oVShW~6DC1Y zuxANaxlbubCLkGqDiMk;%9$hQ1tzs{4W=rP+)!dixbmyw1e9358o>cVJ}AXt>q~@k zN)p+j_&6xWfV!Z@HfYXh6U`ZZsL}zbKS1GxKfVwEKfZ&HE%|zu!Q(TuO38T9*R!BO zq$H5&Al3k2n=`=9Hh` zP_ZDQU;6RvLG~veCY`-Vs!kqiF`NN-1Xro=!g`w=SQa1WqIjso&c=UeU z4+C8XIvlhW6#aDc@1R)Cj8gH}7|?;ZXCJDR0MM2pO8b=CXWEw|kb31N7W{F%P)Y!l z4VjEgpqsB>SEFAf&FC|yv(XdEvwHA=^_4965Aq##AL_KARzC3$)OV<9`8cJ{cMZiu zs?Litn}+UIjV_$UCWF)2aq4(p8}-%XmaI-g@J8qf*6)(U3!x`j#YT4AMOoJa#j*9BCXIfY_1yQ}lKbdf(DY~&fy5T) z%!%Ms7r$>L<4_#!F@M8JNQG*T9EZE$3dks}Y-xz1^38&c zB^@yOByFs*pWyl$*NLtc%$K0_uLJ!Vrzpxu3&#G?ayE~OIyU6_)saOAq-PcfYY&4^ z*@z3^Wml}lCK-lXJ590-UO`-?K39`G(&(OjbuvPj@|IW5tE)M$dO^hkv|Qb>pfkux z!Od?-MI}}9*(1-i2X*?{%4jB_#W6oHvxvS1idj(fT43ga5;FjoYKgREP&bU^cQ-jY zf;pcddd^uc-HaXhr!50dYbGyWrzl={@SL)wLGPhktg=yBuDJQid*E1$G-Jlb&c@V8 zH?-UgwA`+$<)T6~ZeG6MqfN-I$0+XlFL!Tvl-;4@*UqysFie&N zd$F0?y#_f>>-nIJ?_y9!CyF2Em35%(*_ML#*Y3>Mi*SDwDDg}~6hD?6`eI#jv?)a@ z%I#9^n_)C=ElT`h`2mtoA(fY*FLx)lupAAQrCXL|79}=?n5o)5_SMj(|5RCPfe!=& zV-t`$wz9DeD;v|p7Wpe&BU~-=WVq3c$K}-`&3t526kzHfGM!D4d2eruEDy3c%Yy@B zU$_QwrL;n6H)?#hmlxycF0cQQtj0DHP|k`j2c_IKpe!f4Gr#H1@}@h+J#pt4N_VE2 z?kul7T&ktfrWD*Nwz~A5G2rnGc6> zBJKKs{}tH2De`Xu`L@X44Dy|SOL6QUzJ@o(tqybw`PchjiGA%`lD^_=1NC}Y&!iSL zR&k|2EwNuo<%Z(K%Mh3?(JM(D%CR75(|pP!V?!;mY{=leEO!I;0f?5efbj>|N^n^- zwA*nv%%wT;Q$ax4CFu3&AhhA+%(fw`<8z@|msn!%y2QTpAjmBB&BL^;Hd2S@K{Wt0 zWy#E}I#Q2ETh;$7C+MM;$(GC*7n-pFWjtAjKj=VE#$VMi+A^r`OS?5|TZTOG zGH#|JQq8KAEgkoK5~oH)*f%1+P)lk+EvcbZpAtdS8<*ngo3!S78xh#)@{YuoRLyT(oLcw6n*eL`&1b zjIg2mc6A%0b2xF85NAW=%nud1Wc3k*KFL~~__7#hx$zb%QHv5UgyWs)!1#m{&xO$v zG1Xj^g9>D@5&lJHUgO}@pFGm|K9<{Wp%M@+Q0zFb0rqCG!`kNG5{~W8TDA#oF(c$} z_J2J3b2P>8%%-Rx%Q7TPK9D66QQ9#Tg(<0Qu{FsX=o4yM$0isaxo$1)8gQV3`Q#R( z1NceIgeATV^Ryt9C>%J!^McGYA<<1C1o#}1u6h;DEPp`yq_6q@^hq>5(?=gGeNDJ? zq>m0rAIX1m`Xrj3=~D^7;fPiu?{FuQ4oDRVMDRG71$Nd6OSDvZxyQ(>+Uz*j!4>u zC2a*s+r*^pO4!)11&m+9rqaRjjWfaXk)GkMvAY>4`tziaaoMma!)GCD?5>wdc&_Q0 zLcIp>L-5S>i{xYgV{&;#WqI&3vHRkJP)EQy2EY0c7M!J^N=q=PlemJpwEEv zz6-FsK}Unq{Z@TX{h@f?jvkEqLia{c-ao7F*CCwma6b@oCgW1`5ZW^ML?iXRo3TRM zl(uHp?QX_e`6uov*w{k48Bc3lhVd3`Y|Gt@x3w*U;YhvfW>AYNYhZ>bTxX5$W>BXz zZ5c)gHn!z%#&~VZFlNEVyy#}k(Kb9e!KUKOHmc&h0O?`gnTD=vo}_H)xSuX=awawB zNH9msznYCG9K%vJ#OpGRgGly4d@*=Gr|zk&9m=U|jQNV7PlDt^w#s)dUvhG7~n z`IYd*+$+1Ykq!A7h<_U9c=j+DUrVyGaUQ0^up=3cR~QN@YV-Acj$Aa%J;mWniOL@$ zOeF1IvK7*o?KiS9cQog8w$(n483@dCBV7i&w4FD`3|v4b~SV*N-mFQG;x zJ#|W4`ZyyH_Wz*`PhN#H6x7#RSVCyt=2nBWwSa4@Al!*(#KT$faPK&D)~f>_u<#{M zI*OlRke|ihYD`Jt&f9F`FPza@Fl&Nf=BW_os}O4A;Rw~sB1)~%W&p+!6y1b>!O7{f z0&Us?w|LXb^8X6{J!8cTuwo@53UDHcq=_UoR?5>JtJVT;lteCY@B>*$V#QDr>=DCO zIj&wEH5kU^w ztk zn$9YU7j;_OTGZ(d$&R8Z zpbvvy1NsQ)U$y@`pikg_f7D<+y+=;~eF_wZgBiaE<*b=_ zO}2v8fNlbffc^pWLQrU4kFElJ4wN(8=Ruo6UjY3UlyW;Ep)Y|R3d;L|h<^hvHCv)B zL-sqY6u0y7Pg{n(8CfB2tdX>3$XUBlaa)al+A`#5Yu3tcTw{{@nZeZ~sh`kru5B4| z3^i+NH{rKax_g07FFYwjbr;_ar5;|GkRiX zA@AeHVW|Y?jJC>#f%xP=Jk$^OIL|oLJ01##SBG+n;>CTFEBVckfEsJoXxyn?cch2o zx+ytTHs)5($Aq72_zU)M0sjz)E%lLsi+q`=!Kl1?8M(4r95~a7;41Y^trv%&BQEbryWa(t(LUaiXIA0yjk z?RB0lHcSKaozDU@wfl$2S6V*?Wxjt3+7A@xBSeFspMkQxJ_pSO{Q{J&^-EBe-EL6k z$yeH)ZBUgDZ5akjMY+A9Z5hV+ysfdX0-?my%kvwz#MJb`QCZp6sD6wK`A{$V^$69SG}zC%JGK!`>|(E@&+%Vk%k-!pglw-OW^Y zv&IT)PHVwDsdQ^Ni>HAiBU?Put98u_(wQo^kb8GY!-1u=VJ1D$*4cqkGHAV3ZOjrY< z*m`8pc3;Ck<4w%&c+&^?Z;gJ2e-#*Wy*2uczHg1vSp|^=8!@d>4zMZ$oG{TX-o(cP z^_;=`)+jSu+4x+cY|M7WH%7a~n+jlSjTR;ESp=vvUvypmrTOcTK#EbxA!lt4HK`*sMv!j(%y$8-g9G z`!^fDwSXCf>eN@&FY+-9HQ&p^H_#peIHWoh^kq_2NGTkHT^u?L$(#ZzC`O1uI_hw? zFi%d@4dyWBh@=0u+6$_~$0|Qs3s{VZ0LEPAhr~3OZ1%8KemJpKet@$#@gFn)3ON z`Rsi(Xc_1+pr?XDqkMEa=s?h)f{p;K1sw%?9cTgQ-Jpe_PwM*?eb2TFE%8wd@#1fw z_<4UEXc=e~=wwj#&Qn2gvaK--bQ|b&&}rx%W`JG_dOGM+pl5=928t7VqjQk3pMu^7 zN~rPl6EiI3h6r_%{V|F64a@e`naXa z&={=U#df7-Uc!$<^ifNRt5;B3*#BbN+uy$jj;mvZWhhN^ZEx?E?_xZZX-`8z98*J~ zV{(ZQwFI3>caqcvD&^@l7XG-)X?v9>Rv*XWD3=K7_*qjHmG|n!WRFE zhWU|l+Zq%1`2+#?Hm(IS=W5ppuGOs(uKQuG`#jhEP|wvcbJ45G79*yK;~Zc4F4692 z=~1S$8uVz;b3x;v_`olEIp_k=v%tgqO3(->KhEPl#vbEB&_c*v2pR^xi2k7TpANbd zlzGT|jx${PQR5748S=pl%e0%6Cv6!LH8P9+~C|Sk(BYY#eDG5;ya-H*S+N zAG`|qil^P@E$ri-VellCcrSHq@hro!nOgROhp`z* z?EuH#@8qs;Jepe@tMOoP?&fyBa@c>xSKK$gJRKAyfQYaA82<%L>kL$O5Uvt}@cr(xE-f)q9Hfo_*7;$LuM5aOXOr=DTu6?u zVvT@XyU>0ppsa?I^G* z-{G*a!UPOHZ7JJY*d~h`W{Xm%1MpXUTn*?6t_`u&>p}mqpzc17Thw(ww=WwZWTwq! z$0l5+VR%8r(cb^`K)=8^U>BHdKJE#64DOLr(IKEXX)JmYXn)XazW)m!` zA5gY*+_#FG@8UG$V%x$pQ}Um9`Xe>aIgMTS9J@TfkJ{&GZi;P~p=|tTif9BQHZESF z?%G@~q6_lN!rTUjz7Cfc;X-{(7KXh{fx~4Wq~iI;hM57ET8B#vE;!KJhPe+egOe_H zU3rW<&JBV;en$Tp-{Ap|Hv3t9?2Y_#>Yka>fGmr{*}#&x7|uMP#oMOEh9jn>wcnR@ zWrM|qgA+YgT7863}wuK`&TbSoRYm7_s5WQ5%NNH)+H5J!1;(+cqsxtdV}- zjR={cF1+_&c%)=B>?!Rkm@u4)ror}BW#Ln%m~_LP(hRs;Db2WZ29)KSTzIAwBN#_Y zS>61;p!nj&)7Y#n7MFP@nP8Z%JhpQh#><(m?r`z@2GbMfoof&NM{2ryz{l@nuWgnf z4ml?r=I1(w-Br45ImSN7?>m|QxSB5+{d}tAOu+<^W2R)x+~7uYkCwb&ie!#6ejocj zLMrE%A`pmhlts2+xOQer&Pqyd){?Uz*{P$yr*KK0z_#Ja!1Wf_3z|zXjgI5mq1JGVAh-BcI8%xW;QP!3h6M?P5rIK}UaO?II;vx!7A%UyPF4#hhx3tFLZOf^me^ zU%1RXysXpe$1JWPnoBT_um(87TDoZDdluKpnoBT_untdh!D3u^{->{6Tosy2F!VMS zX&2g^XGP?|1!on*pS8Tp#!8Q#b!mYIubamy!y{R?nsO4 zdd(#mN4ky@F7|IU-_^cTXmLHLxdg*r{RCq8Or8VUnJ)Qs;f98!%SgJs`I*XcU*db?3s>@1r}-qUTSoN^RY2_h@m5 z2ZV~rP3Gzr?UajLb)F4;jBrUZVJrXrgYTtEK2|UVHp#~%CBLC1ACn@PGgrTFA^vH8 zU322gsgjR_55`KH4bohKakNvGwiVWuW$!<1ag}N= z!8pR=dcM`K4jOjE#THks<`Rq}tYMC@zB=RAg%;NpnoBT_usCh zp@knYS}xMJu#F}$Lk7c*Yk_o;9$?5|>0L~Wy$2XYjE_%v>{ss`df~gNc{o}ye4^JC z9G~;*OfZhp=^B-ihhr2M|8ZUU?u~fmZ*q;)T!L}r;fca!mQ}`vTkf*Brf4p~Fb{|8 zs)6`O-LUDxq842j{8%C4xpx3TeLbrYr%U47SZ-^F1|WTb;%Dm2_wrQI()q zp5u0}oL5o30B1nC-Q~eOXIP56!l$|`yjzM+ip$xSU)HBXhO2@bI?5w(q=NGkBYpIb zhlh&9@b)-7Jj`Ua6UMMqQHo^Rw@>6ua6SCf4LuF;$CFcMa$;^K#k+sKj>wP?<3F`y_M#P!igWfg|my zNf17dmr(ZX^zycg_3&5Gv9J5u1+wUp3&J^eQ4SxRxsg9OXqoRjb7S~$6V5X?ddZm^ zf5lKJLp+8tuQNCJfuO^9oVl?J3u&WWxB{NJVOs;DjPbbgT&ttOtg>15l{4brz_k## zXnMI_0aLAU9mVewjd8@!HeaKA8LrFSxPQOy@|yE1YO8+)-R1R|RD0;u z-Bab;Kd!dz{h(7fi2R*hQ!~E`d-B^+s7>b=Pz2KdRn^ti)Rmuib{*F9(z7?3&gQ-| z@nHgwh0n=TLzBuvQ=o<&4_fKjYv?qtq_lA26sSyR;QbN!g&0oi$|I614-zr?)DRSy zPa9W)ZN%x>mU8P%+yyaH7pas$)zz1RBQme9s$vdKdVIHLa>LYaxl@STj5ASm2 zgCM9Y`4G6AgE98J^J*59^P>XBgNJ!vPyv-w^%2p7ehonvRM$ny>nrN&Di$Sy%qaot3 zB20(K+GM6MN3csCh$tS`@PkIE|LRG;674X{*Pfo_Bh&LH#6B7suYI-VtpV>nRQ+E) z$)jdU3$HjYh*@M+eK2=n{)nSzo>yI2S5sdzHxj&{x*m$!g3#&-4Z*?unHN;ftX@z# zzhO?*%=(J?KTu`xfAu6Y&u7-w51q+A__z_XkE^e%oOzD)#Xm4_=U3zW*!mwR1U)X4 zvMC`_KT_k09+xBNzgthT-lUocrDOL|xUo5M+~e#5+seYx#X%#|x3w^56Yj&UF)jzv z$WFWsaG#UB;aukvT=Q@ZcI^@2{FqBnV{sjZj#nEQD=TK#)J5b=x1i~sLd|X19GCD_ zru5e4-n3aZG{XrZid@y4rrj}ji!$s1pglpc;wK+wVx>D8#Qh*pzHh+FuBflV+Fz6_ zlvqNHGQPYY2uhi1&j)R4f0=TNYTpb{^(-J3{4uF&&xf*crI6D|DEY*fJ)MVk8k~~# zz1zyl#^=3W5FtWn*Gk?hHQ(8OHF7L7Cxr-xTHR+KHfiO;-XM1f2wWq;^MPh&$se-GMphPy_Eq^t*`~>bMdh2av7)M%a1I?~I^VFpO7acctz7w5 z4~Nkm-?GEEo3+y)@!{-35(}j?XTwu(-@8Y{58QZm>Ubz96!=Shr~eBQL(pmm5rl z^Tihv?f02IM%U;U<5JVbGW7el;onR}mt?wF$~0XJce*$fSm~N`M*8IzS4eo&5Q3Mz zwnZGaL}$7zu2VIaVC1EZc90F7&UA6@$?r2;^oU#T-JF^($#Y*bkY>8NCDVmAAf{VN zx_ZFfO4osh52?1eR%kB4IMT)S87p1fR%3D9q`3scbg{vRVJe*IlEE^Wu7v}h{W3LO zGPF9<1yvDR;!~PtrlczyKF)MmTrX=b!8p>ze#4nAi|Z53B^XD#mu1lWFVHQ$^Z6 z?Qu&viTd~%$FOFbvl#|8Bv;#Bg9Bf1;+y8J(0ddi^mtL0dSYW2RaUSv-fLYaLI%*&DfQe|FA6T#U!6E%hjiEdmuln~7 zg!^;gR^=*8ClIgr@iF*1VA79KxQ^mC7??2{*IxYCKF$E<95>FRJeq*H+KqFS2j$%l z%+qe1hrDgTeBj2pM ztwm!PKN_#{eHrDp6}a0tn}_L)%d32!1@3KNes{dUI;?+x2Ig&zOXiC!ek>23GGaGg z@#Dlb%Z2lbUo&ta;Cy6&>8So44UDGeN5G|L?HgW;K0#~5t>FtfbY`=BDygmH;lq$SmtFM}QPUU$O^^vN&ANC^g z6NLFswC{rqb-Hh+bt>?r!c)tq7N0R5=j|xJY|F1~%J{}B^Xolrit za7uC6w4~hLmN#GIl@y;cA<4SG&95+Yipgq9Zs$DW19iXy6!-W^Wz$YCFP;>dU`6;? zd|G(QshDLd4;(m6kHRUTQzn)djh{MA3Wh8=c$z*_L#K@| z51mpZy#GCexxF{aJi_?*$TfKklbud@g}dN_syZ|#d2{S~-OTstkDGX$?{i^A-5jWC zRxgG3`aLvXfZvJ2KW`CV9M_hsMlA22A20){gexi$Vue-c`STGi=i6)V(|iAWG&7GY z=B@@dE*w9NHdr26R9hvl<%4Wk()FagZRgwc1;~5xRz1k~y?|#aHk!r79dYIIvSp9n z%O3>ZyD?Pj`gdM!&4MbNFDC*zkn1{Pok)*knZ1(VPLaA>MV5(iQ zqf-NOyr_86_)}z{VD&uA%raJesun8O`z!w4M?L>{55r!a^}KXPOTqOE^Oh{lIB8>i z!--L7fyXmnmM`_J=R+~~^E&H!oVa_R^*opJMNE9!ecQWWZnb_Pyzd(aB6F~z@&~?} zuB?kd$Pa$O{og$d`?U2VGUxxPv!34nGdWiCEs`oGztDv`s zBMzwyCsl&CWyKbk?5WOhIS?)HL(!c%@?2BV=HeNxv0OZv;%BtR25MX4^JTMeG-db1 zgl`&~mu1Cv1(tV9bb%E*$^$&POlv~oGpIx~QTk0n3X!m+Y0V}$fF~Xs zjF5N??qGROe-7@rC>k(UCT-UyZFePYTaq>|L41PiTwHFgv0S#NKbMDWDom;uR7a|D zatXGkH`F4yo>{p7c^mVEzFn7iQhmu58xO+@;^G^EjoN*%q25gAgXX|(BxoKeKG%|y z)P4e5f%^%dXM=`8xfC-Iv4EmLEi+$V|?^)pr?ZF0zC~h17Xep?F)JaC{&#A z-0)}_C}c(#fSv<-G3Wx&8$izoy%)3|bOY#O&>f&lKnFrD--y_^#6**BtF$e{mYod(L5j(ffz;|XmTdZ7k|=0W*apVlcHmoStKGfX@nl7lG9H;wXVNh%vA71~r&j0#tN&K#yDA+?!GJA_g{+1EV zytF4KG+}t%E0KCIXQ9w1a%w?~D+lH@eu!S_+rY8`$zF+#6gTmCND;bIo-@FE9K-!# zIPqOc;#=tomrV;LB2NSwzgU>Y{s@P6>rPE&h`&hj<0!bswq=KfMh|;pc?XzSt1mqI z+a-5J*D<|DC{dErySNhhG#;9R`;F%rj`5P5VCE{;_1NyQ7alZv_mTr*Z3RoSL$U8N zF6=hG@tuX8L$Pl%mK~Ce2_6m@@nlROG}ySg;qb<`NT@^5&H=G+eUXj@O=@flSH2id z{4*S%mQ#><+1ZE~&H=~4-#nK%4#o1KLYA6p)fKKZ!t1xCH*OBEjs(gghsSzVVC5xOUlg9#u5@XEACn6xLFGc)0R}=o78CvByv9Wn_l)M+0 z`@A#0oMm%9hiJ}#l)+b~)pIH$RZy;8S6!=iaxx?jgIb+ojLK#wSnBg(MI$?VE$sF& zlgHh%7~jDz3ZB1VE+W)pB>@YD>J<80PytJQ^RY@?jxS8I&rnUIuLd{S)X_+I=nPUvPgr=&PW2 zfxZU%4Cw2it)Q4SM0v*6Tc96-ZUa3Mo&7tYREzZ1om4@xCCJ3#rN{7%rNpdWz# z67)mRJ3yIV_koiCVSWE0DDp7cIe;$(K(j%=20Z}u8_*L#G1-oe1V!FPCxD`sM5&_{ z8uOwnLDN77!n;2%`yR)QNjH`jeKQP(!#ZFZx~iFnvZdqxC~@OG%_)i)WU?^I)*WtR zarq6VgR)Jd{GB|<36egPiCh-r#8`4!L;ZrHY}0tj%@bt*zMYM}pPk~%dZ*NvKJ7H0 zJ&Y_M6es5~%GMV)6^0!NNA2&7mqPZxC}3Rla+xoE<76L^X5KI#lvHO(DsSva+7;3% zUm*`XCEYkBGR2oOXSy#q>{MTdZ>ogD&Vey6z~wj8_UMwt3eI~lQJU1)oVjYX*jKCt zK3rKguw-@jt$AAu6M?4qieYdo9ND{R*{G7$SLEZSboI<8OR4#q;!3~h|9?6?yt;b< z&!)h9CoSxsIHNdz@~*K%_=N>Q-(jmOq#YrlAm`b+2NV!8OKpJO=k);GLLp9H^}eug9CWN_@t} z<=)zgx{C9v@WwzXYzzYJZQ6U{`4sSG8w;^JWZpmwLeM#cjhh-C|IZ_r%aL&2r! zKR*zZ@u%L#<)BbGAN?QDLqM+qJrr~;=wQ&>KrzpY-UWIj=!>97fxZli$JXfI_5H`7 z)bGem%g2IJnI;}zqy0gVA5riagFu-#l*?`=j7xPhw5ct@%I#9^i`ojqG@6F~s+&=^ zblkJ?SbP4tRFROXst#-B2^u(e4Ar}#234K40lU)^1^wbHX21?xFur1@*uvd;_vI&{ z)&f=_1C(&1aVu=p;YpVQ2ANs(BCJJp%KIV|FT=+hvv9-v_yco5b{vmCa~UDmS$U;) zde>iB3P{*i0%Q$9J+#MTjPG^?fiOotz!=73jClM3hMjrY6Yx=o!LR-;<1HtQtSL!M zk^~p0k57cUuMS|)W2$$B;>E*4@lZi15$ZQS9?H+WXE#!w2n9p&MPnMbGKKNUMaZfz zKSug9i?-l4oRDO$?%pM~JHxg*lF5+exuXrsJe2~%j5PjWjCm1LdDGao{2f^wc_w|d z#6I)VS$rf?3RbZUkw|1Q);xfuar3f1nfD}^U_44;9c5Ey$@+M#yZD>S6d2z1GR3x} z&1|3Z;o?3Ho(f2^-f-(p3d?P1> zECA&~#QC6*Y1Dz94q6X-7U%__=Yn1cx)gLF=nBw9puYg6JbtPKHk-gt?_8Izv%;LU|^VcCWZAq%YHNWZI5IWsg~)4<>qSEwUB8W}*~N z;+d=7hM?FEU!-4bw=Xg&`LH?^&eHOCu&qMtvh+_TjjiK&YBVg5t>ZvyL@tPmwq~Q@ zyx4>sU+aV*X2V8QR5u$9I2qo_j_!tSRkYK$WtAjucocV!lLg37Td&yifks0Qpqk+h zr?xVDVrSiCwM^)1>}VFa2)dtYp}hnN5Kk#735bf0X`=x>cx;mngb`sgP;tP`y||G$ zB1*u$V&Y(D^fMp63KMLJpP2@n?X^7D_b8{Mkdj%t1)LCchfR>ql+3G}nv4~PjD^3HNrL1c^N4BKLcv-N$aXG!Ko_8ZU?nxWgk~{1U0eHio`&__TG#2Ixq zng;rF&>o;z`i<@ndLt-iS_XRB=rN$b1jPtp+yr_O=&wMhfc_e^3iMXcDCljVmxJC8 z3K@L(j@}LW7f__pK=nf-!^0@(3!txq4n%w|z@>U=+LTsp<<_Kq)ohD-Z5sNkURv4G zalb^|eEX#t`=QtCIxJldR5rh~T(K7H=rvjj`hu)z#vNKE>Naht>oTP;ZmY~PtJgUY zhvP@HL6T+&Y@KoC;<8sS?#!rnBl)hfSqV4#*WT&jjW9 zf3rcc1{CFB%k%%(MG&_XlsK02rMOf%)25n^a$`)D8!QInY8tw#a#l8$^OfS}>z8Kq zL(|F9O~?FZmW7S=Tg-klAO2M49x@UatsZwg8WdLN(RvcQ!tt2YhSloDN4!f|*;*zX zi0U!{54PH4Le_T1B^;A86O2d(_{C*swt7{8=UmQMS#k6lYs5S~A#ZEJsxM?B9_f|& zu$-vy#VZGIj;-$$FAeVW$EOG5(+9?<=j6-C7C9&(lKjo_2^c7KjZ??MDIdOC%ujmq zQ{a4r%049^OQS2qHW~lStN>r3$?Kqi9O2ks+{{XO1@7D*4}UHQSuith%*Kr}=kOh4 zIk&}e$E&$9ZXez?a@~|M4&o~HMe1;rX=Tlvs`8oz^A{QNB2slMn^d^+&o~8x0lEkjM-R(bH42nDG#Zp+)lWcg z0xbZ&7qkfUe$bOZ9|8@7J_?G{6)=;*zADfSpc6s=2#Ql;ErSb>+U+iF%P<%|(`uSKVNn%d+0t?U3vsi*g6yH;^i{a-Nm~|dzrp2)ejAL3 zxJ=_E`(}9J6=ctV93O1Hf;8njr7C`Q=}JE3nn>Ec~O4)JzxEJ%Dom>Pm!X+ zbbg%60p8N=+wZ!@42$b%%_SH|SX~@pUH!~v%_SJeho!7#>Qo0#xlfHh59R98 zP2z64<`Rq}tggbvOeNP@uRJlu;^M5BMlg=BGT>@y5&p}|ndKH&OnBImluX08Uc0bw zacUOtCUUsM&d^64H~qlW@{+juZs}x|m-Qj=?OJj-NOqPNYrIun;WKvbZ*e`Mxdh`# z7YATV>vP_yf<}vLi{=uHBM&njVO>?cYpKPxLvsnn5f*y@E3EK4b)zjVnd!h^FpjX; z@muM7VO_6)#dR?1G>u>!VX=n#ef{{4>ztSREwH$TX)eJy!s;blX5F}Dzav&!T$41H zU>sqw=dtQxbi!+4iwmnQVg%y|Ykx;rf8Ek&jK#HFa|y-~7RMcxE<$Dv=yjIG^)t;S z7zy=v+C|kvI{iNB!cPup@MNV8>nhG?z=E0G#opWWfrsChr#a4=dwDRm_VTIC@8ffx z*|+pbw#prvvyTyU)m}6MaG5!OO!@G;EiN5VQ6l2(Z4MGHws9Kjz_z#!RmsC=9FXid zvxTd7ejnGZ2+0`r)2~xgAvH%dd7G&?IGKtQwd8|SQgMh#Hd8S(^PNX6t`f~97)P1% zA;fAI1-mYsWpT~XT!L}bpTitseK>OSjTYAu%_SH|SV2cv@753KZ*g6%xdh_~tG^?x z7r*(o#Ny(sQ5wNG!WsZqt6gLtKlRTR*GA1H7)Mx#3zwOPU9WGr&f)Qb)LNG-7_3Po+s;wRS~pTlKFSEX+78E6tL;pw59U~0Cu=UjI8t$p zaIwFo*}DDM7c8#XnoBT_R2&Pe-~5Eq`1*tqZ>OeWpkSKuZ?>Idlc`v&B_ErTisOXK zEcd@pJ-gWAGS3DSj3X6;gv;IoSX?*iums~s#qq+m68|(UXJ6Hnnu@{jL9W`$;`n4L z_?n*P_>@!(fvZ&(x34@j+v3`&xdh`##Zcig%cAC{zH2S6w=|bv9I40?F3!?9>#6T+XK6 zbeFSy;hK}@jZSe^XqO1BQpD+c&YbEC%Ij(x7R)KfW?uKEB^}9;IVm10njRi1==}CL zJUkS~3GH!scqoox?QwW`D2|j==qz!&mzPhN8m?F{2Vde9&a0|C*C@wk=gNk<>IgsL zt2wv2%HcwY>E6zs0iBWU`RaJIxSdA)pe*dAW( ztYm3f(1XwBn7Y!Xk1lB6U*#dR;CIO1zQ5vck6Wjw9q$b2AIi%MTIT!o59N(GVdzkS zQ~%JlqJOA#uDt1CHwqO{b=YWgL6zL#k7M^;d=Rl45B)=PFnqlZ+}Ioi(I;=nZh`7vP-bX^jy^ z6X(*C&soYJTsW`zZ33^^@fcW#uzXiy!A{Wjp|B8@*_v6vv3r_T5I?BI8F}XZOPc++$ zAM-B^%nUcqBfS>@v(k-o!(3UOFC{`tiXDrla(Z0_G$)&O_cD zjZqT4>mS2e=)!r`zgvJ?4BTOSM1x7zKi7D~b1F-+_=%@EJ~6VLB?`UBCp26%OJ(=g%zP z0l*A(<2=$^2Fy%1&Xr!4$3?(g=Eix*y9<~{-8h##=HH(+239d%`8NUyeA|Wd%D;ig zzrK?&mpDbq>L~x_1G7-$+RMLmi20euD2d+fw->_wr3>d3zg-Y=Un$r0)+D2d+n zF0;bdHN?sD@k=`IM1Kl`}{5u(#pSp1#@|FP8CFeG$c=N!WBJb37!im+ul9@Ae#Qde&O1|~_%_h1eQ-YX z8(^NBsc;>Y@8`hy&QiE!I$ZH%`#21k292dybFQ3#EtWicPlXWxp6Le zEZ-M^dEbrmkeBvT?D@b&(_VU6zQ+So=*D@-s{rOaH_jD5=3hc%7%q)h`7VI_4KAEl z`926-*K+8w#zoUn`MwLxCmPpYdf7i`&Y~pCc*T$XMxR;O>RX|3l;;({0B~0TbIojp z>nMIt0<&4;+KV6a?|optbmKhAWB*F*C%{G1o;=oXw0JFl4bCqvD$h!%c zb#9!8yjOvF*Nt<@V}IbEgFl<`DvyQm&jjugjqQSaukv^W?#}^pYn2ih0BLXi`8i-- z)i}T41{c_m(4Yj?moGJj_cRhe5B;`nZruL~{kC=I{uugg-$Z{){j4XTK0;M$;nece z3uhPBVGEgZOVe(J6OF@+9@*V{shrUo8W&VV8tS0lsHScX6me1+E7dOcP+DNeg^J2c z#-B1_S~#gY_8{d0MYhw*r=B{sZ2T!j_;^rpc`BqeJ%^b}XUo+Qj-hcl7}C@_J0j_+ zkF*qDQ)}-e9Afo3`sgXtsL<2 zhGyBU97bZVzLK#K4n^T<$@^CXP@KGf75C#yt^3!+e`?bIb@ETP_}}FHl;UK7+i)K$ zE5mtcI>3*V!;oR3kkzGJ^51p9DRpTw2Tv{=KcRe5Xv)O#Q$!JKHtNU8g{9+9Lb;}A zZ^f;s^5l^r)u=7iI1H3$n(pC=s62UeqbZ{j?~SYGnj74y`IX8$_v*mZ|Fi0CnVSFq z>9M^JwFC-%&#PdERem8h2B73vO)pOttWDSN9-k7+GiFDkvpKoEsBl{Or18_J;MS~G z|JN$B_10e8fj(Pz8)U|M=J-BnwEfW()iPE0IH~~;1ZJwJw?|G1RvK^V%!n>FtA?}I zIFI0^9^xRoo6^E*IydnWHCd!^5|?}vBZa`Cm{pFRHf6W)5K*Qvk$uRh!V zp2@pc#}G$wGVu>oCS3pjoIYEbt^b?#*{(z9$kn=T#_zQ)BdHB3gl`yMElwCsS;aBK zR~#!yZ)-Rx)K=DaRkKZ9+(F!L^I5S-yJOuU%J|fP z@;jgNK@R|}13d(^9`p!M2#+$(7k~}~?TSl%4MP{3FLj^D}F<6wC!05B&MRsIu$hGlhaO6csnj#DV1q}#^FD(b*4rPN0;Qhc96 zc)l3|D8pviF?{Af4dNK({Zi0zpvypEHEj!$OaKZS5-#J z#xi2{rqWntSW9RavV~DLu3j98OMR_L*{1Q58-yq1rgbvX@Ch`HDVw2M5|s^;SS{O* zq}@xliiP@8Q)wmOr`08iVpX@G53D%h3$5RkuD+{oGKyn9wC_-Qn^ZS8^2zO1mLI2z zv8dctEDkqjEQ&Ctdl<_8LFo$1g|~-kr;4%DU|ovfk`AJw%HBoTs~N+0SF=V`C&uYw z&|=U_Kv#h_fwG$M;|^8LXv;9JPP$#EZ5akvy(rr>@i&iBV`) zvl9hPlwMI2yq8>dTh3}`%4VpRL}g<&Q?e=0MAGghTOnQ53?J@`>YNC){Z@WTwWfoi z^z@Ti=*A{BzSE#J5RZUJhX&#$IWzLw9zz?4bE{HP$N$iZF-2`g=7im0|N3xjSHY4G zL(wO4qJSBhjZXj`R$U%?$gnR%dc5!J?4G?elss!=P4X+-~Y${oOoPm5& zSxWuCokN+A3@nNaXU-*_gYfk`e#As{YYpY9838l^{jsfQIMxy<9{u@}#*zf%guig8 zWmQfTG4oLw?qDicD5F}0fJ1*%z z2=so}=rreir7hOp)B&{__7MfRw`+){TNrMt->6|OXa9;%aASk=3akx}BMVlH8l^Z)O<;J{YT1-P% zH5w`#I}GNC)lL0HLz(jyM%ma+O%pUxlx-U2@8scT3CMjYU_A748Z?M?6|gCvvJ@9P zC}ryno03nciKN|2zC!v=>}s4C>1G_Tv9qz?oD8M2XEst5`yhY(s%G7Dp^9=`#4!c0 zhAY2{K&{qYyVpW)tTk(AI&Y%52{(Rd_GQC(3vKEPl{WS0lT;mr?g`b!-aYMkqeq); zF*fdLF9AI%WqDsnlV5#WpeXTCQKF?N@qAI@&*9aRI*Hoq%!fm5;n?~>k$*d^-xT?` zfP7oz-vshqk-s?%1v(9{u|p_a9Y~ixJLG>FXvAdv>Z)F$#IyU*(-k!ZlWCBq{{7t@ z!n03aJ7$pYvXxqH#60ui0JOtoG-2AiXT2*GiO1TqmOWiu`K{`lp!B`aCa-7^)Qatm zKq%QB{pFIUrAKRNWGxW2L#RlsQhJu1zkxNM{n%x=-2E7LKGXjU(4X~!MH!i8&zbjQ z^<(VY${;z2tJGIrUtUpZ>)Y1C)ijI``!+rbT&*1+N1wttJ_ULxC>|W6oN+dT9u2x4 zl+%T$LGwVL0cGFY0y+tF6X+SBn?ZpUWz^4u{t5TZ2n+pQ6bg;x9*T@a>GV|4SKwX^ z`Wh(vG|EtY8f_WuE43SXNwH-}J~9oaAyV~e%EmrzmbmrDKg|=07*Yzb`{k{lLbD%Q zC2out%g8ida_0(?aw&6zhPEdc&o2n88tJBN(|F09FG$Lz%>BSY)1KUg@be3bvQ6V9 zm*b9}Dx!b1%VsWFIiPIpiIr?SlJdP|E2KQ_pntdLM|-kWe%O)i$yP{_jXs^mEW`F> zt1`4BY4?h^Li!HqVjO^RBOBvVcPguzEw!6j&W6l_b~j`{+)QKB4yGD1nj3Y3nf@+{ zShImL^7aXdTG!y@BiF{jaM(auXZmUPx6wdog|aq$TmfJ`7;? zp-8lObvz!KJ-oG!;#Dy?n`6Z(1WlG9ZFsE6)qyQ7nA6|Jo4h-j$QM0t1PezO9`DFA^tGqJT zD#UzdFQ!J|Nh}`rzn>I&rd^C@%Kz;=V?db?vy}EG7jX0$wHiWcd3{OdWe=gI@t_?g ztIOVq%6zyK6+^mFEDdxj?Y_rL11hiyS$h+j=qhiWg>zssFDP~ zSjf+J*yyuC-Al*yHFNi&%X6+9Qv;!%zly@#CWK`ghRtqpKR7JWj(yP0F+Na*6|Dz7 z1auo{e^8FE13)>g!gkW=IM5?Ne+zmfXm1R(xu8%eDC+%ZfeyqyPeC~j^f}N$ph1K? z7?cy$TXCuGls5J7t=!l_DmSV+Vq8r_SJj;=8#^{U^qbw@9NuGb2V69~Q#f{{%EoT* zK3qzuiG+jpXAW4h71Gx;O_T?k3jXY~0<@}qnH9XYhhug^4g-)%%`SHJ5~K6Ks~PK% z_o5~1R;-lwU-k#&r2V)7b$XVZ7bR_UDKua2RrA(bNE4;K6BGJI`kTtb56EjCDJO$O z_REiP&wE4Xyv;j1gDzM9DYOI(l8~afu+m57sFWCy&|Mq}!JNjtz z)t;FrOur>n*?PlG0Um$W$i7) z$$QIi(%v!@?=8b#hp;!f1m)7yg}*l)rtYW@*f%yzg7!KzdHBhEWF5at{WlHHkE}cB zM+$6@p5XU&Wn#~Z+P&9eJ{r3Fd>(!u%x>;(Q1>8p&fMy`+41Yc-2dV|2&w zlgD5dJsWf(=&PWMKqn&Hi$IrvE(X0HbP4D{$bS`=8klHP#|bF6RoXYhI39S$-8A%9 z1Cz3`EB~vw_1BPd5i$)^W?__#9rI3HeuF5=HjS6ucLgZ}h+cm%WiwPuqOvh(m2Ap1 zk+gfsR!IB$gL$F^7U%Y|pWj3>WExz|^Z@11r(jF%DOO&I7#$ zln;{Ef_@E(XP+n*7L4mb&jS59=w+Zcfbz}fjiCL}SMk)G7${H8c^C91(Cwgj5Qu&Q zdI#utptpef5Dz>kME#(6fRH0s?*wI^`!O!n=hCK*_E2t3+E=|>VOmT>f7RzI8+*Sm z#Ld2^F|=aWw_H6;p6Vgfh{UJp&2akO1)1thK<<8njfYYd=3;@>vF8!TTH~0jb~m2N zQ#Rfl?6qj+Z^9y0v!tG3GIQG_~NFCiYF1d@3C2+Qve~5geYnf;MEsqKteH zV}2boud0F{((V1BGQIHbARhuFxYTA#i0KW-0yyxwqtu53mMi90Es(`Du7rhgnTBy= zC1#}^qa7bbq zv@JIUCy~zh^iZ-h0!9X8o5ypQ@)=J{sV+A-=-0Xc@IAOjr<)URc@mMn; z=u*(P?d|K+SCXAq$Ng681U6zEW78W!AuNO&!OH-3q)~Jo7m^Ii!FnmV2JW1228>_f z|6{SS263ef8{kt4nMz6M&oyG(AgKy@ZuR`C@_p`!Mcnb0_RYH@@X*v3%b$f5A{} zDQKP*#`&2I+Z#WO3@BLD7Qx`|ms2Bgto0-$2DiZBu)Lk5$-uBQ9qID;W&n2fPaf0t z_|v@4rkE~|H`AW>_<9gTTrXbhMd2NA6iw>mKm*3N_-DlqNFlNb)Z%g<@y20>h5Qk& z)F!|KtbbS=U=w%+muVOtn?PSUJgXi5iK@IG>|cVi0_+CO)%SxzzruYOv=dIMssiN^ zZhWbQ4-2Hp@F=&HxbF(usQoVo?S}j7K=%W^AJh-}5Gap|+W?9eUC~XT`-5^`dI0E4 zpgaohHPF7Ge7?pauAIGl5a@fjKNxfu=pmqNf}@Zg)dXo%O;EWtY2OUlYs9phhW@Gv zDqA`{3dGHRa#mLjr?0}X@hKZ~YKCx}1{>338ZX%=Ib>6AFAZ-`HqWE<3yShh<0Tu5 z_H5#|Vc#y_8DquIVPDC&BN>L5e1$X@vx(ZXe6b^G_mZu0(AU+EowC+qbM!GOE6(Q! zbFXNyB=M_eq!PVHX5-BeCH+ZW+sMa;!8P-;ggEhS@#_2XiNo&neA$maca3hy;lv=E z;;7HaJy4&K+b||^YVYxR&1NUGb711szM*@0bnSM=cxOMSztdN?cebRDUdKo*xmG$W zZp6gekNgK!6%LK=n8rSiyj;028?gU&20HpD-1BI?H$hJUWu{IB^VQwjj&QMgIP@ajT-7D@2 z>Dxce*neXH&mXF@_@N7zukPWD7?0Jq1)o~P(LIo}zVg9f9qJA?DGeH@Tvvhrr0;lRbZK}R2wUC?8fN*U2HY3slJw85N&|PvkHWp6k^erbf7fp|S7g&O?m$(8g zPhPSc$+>5B&o-6raV<;kFJSMcrjcyZs_*}E(#BTT-ZRxqB%1ylv{UL~q+<5`s(N*l z>fW#JB%i6GkZ&4>7sSP9g@|^<7JBLDu_GYLRUd4RmkDAGC~I6T=r2L*LGJ>MfIa}) z0QxxS1)!~<7lJ+qx)78Tza^m45!O=Bfw)h=uIe>ys$MHMhN9fk;KMkYhOVk!D;w)I zUo2T`J?CmDbJ4;m8+)&t1vLm}Ru=k2x8RO&*Ig zlUK|0A`VS%hI=@U-I8FDoci_=6h^EEVm-!hO@5Ieqgkn4RPdtKmPIvW9f|(NR zinJ-k=eX$iaS4y6YWjB^M(ecQAR1UZpL0z*FoB>yPTF*+#kHUCs4el%Lor#NexK?A(Ee~Jrp0xb<`Rq}6|5D0A0Mu1?)`mTUTP{R z)9>4ae>2XQ+Yt^kL=n`kpeq&Vk8G(p=9-#Zi_6S4!8i_GWBsuX#XPZX$^eUNiVjOK zjvVXe2vPiZuQafEdUT&=LumcP>7;<`k03C0oDp~A(mXwEPE$*(Lf&VXnHBQ}mlrg0v^ z&0f&&Ge4yaoF1N=T3$iH6hVerUWZ9*N`Acx|HBM-dG!}Av%I?B@zxuP3(m$m9Us9s z(ltQ1%<>8xyO7F)###u3($j^v0AF{ZP(p-XZ zgq15?W*^??z3XRMTv+uHBN#_moa4<`Rq}tYaKuO*?o^gT;j>VKIVn zgmtVVtox=t*JyF!c}0w19AOO`;<{OL3C7X;9WPuQIcWxsJNC-d)-)JCe%~$lH(S&3w$_ACNMVjQ zg6#clGb_$1{66du7c+PH)n%!YhYIEi{F{=8*d*f{M3^B;vQ3dQCO5WnA3J2zV~UID z2X#sX!UNyD(&BnWa|y-~)(GJ;%e`jqS%0>; z{-L=9;|Pl{imm#*@`6YHU~zq;xdh_~D?iBvi_A$ZF7p^{!8l51q;Q$v`Sfjg{F&6! z86_C?JVe=i65@$_(|1CAg3IvmbI&aqJvGyFRhqo~{r9Ov*%j`36UHkeeii_ykIzEDNq+*K5xWI>(9b+P6Wj3cZfM_2=@m;ce?x=wQm#u3(dM_6Zl`_@Mm z*PWV6FpjWJ5-zhQoVe@8<1DTxG?!o;VNGy^^?WSXmagYDmtY)Wg@wzU{}_kwe%A_X zo8}UXBdlUaSfAZ=?>iRPrww+#D^2C%{H%Yk6TKC)cZ#>lE8lbrZ<4DCR!e!RF+zG`uTU?_wmtY(@ zR_X|A?ZG{>EUqb-K(X=}Z$0H&ALZ#?)l#+@qbQrj*X9!ey4u*##%# z^d7T6Y}QvEK4y@nDU0XD}cl5m{H5D`96Sb?lt;|3CKL1wN|kTp!*;0)%jx1OcO>Omx&J2!TWh1|^eBUt9?=RGDB*ak`g?Y zur3i&y0$s#lI;G5)GbO%@L0m)=%n$E8$SB+W<%;BB_(()Va<(8!J@6c^4ejB)C)>V z@K|a>nULZelg4>8Y#v;!<49%kn(%@0xvW!7C>K(CP2gylA@#MA59 z_ktsg;IX8l64V42DzW&YA3El)_dC~Tc3u)(Z{ojRpDW|37^Qr!?39Z6LP}4C?@w!o z7*akZC3q~Us1{OsedcJGAvH%y2_8$iv-4||`xQUVy~B`NqND_mC9F$@lwO}X8fHk{ zprizkB`gd`nZn{|m?8CRB_(()Vb#W^U=cdgklLoC1dpY3778g&y0J^U{> zmP@kmbz|z~UIwaBIyoEbPB)~6D=EQa39CU!>0zaX?j2`HO;%EZ#}XF1jYe2STVLE~ zNR=xo!D9(4ETnX8Q(HdpBtz;dB_(()VKrI8x~Shz>kKIjkqRStEMYAcQhK^}&;2UT zka|=}2_8#WODtgxKcRS-A@z!q5fiog2$4IW+A2PgtxBVlw?Sq zt)v8xCC9F`gf(y0vg-_~5+x;gEMYCTg!SBjgLQ_~0wpDQEMZ+`32UU*?>$56Y9%Fj zEMY~2lwRw8bV{#t4XL}8l;E+1wZamXXYU_gGo+qSQi8`4){lggUhCd&ZvM3)^(Q4I zcr0PHSi%}pd&_SPsZW%Y;IV|&Dx_FmG&@gw;?IUu-#(Hmcr3MUB^)qTDV?>lEpMS3 z+H2j_g6CoU*WW}ddJFZ!;WgAj=C@H~XDfc!@Si!Fs+-OMsUP%caOIX(lDZM^VJa6FyL+T|ZC3q}h zU2h3%>p3UiYe?-^Qi8`4)*2x-l>hN$T|4_6L#kIYNHBuO64sAFHQo*fpIFgmNTn+& z!D9*QhPV`c<=3bob&iq}JeHbpqmZI@rJ~(@%R9Gqt_e2@p56Gb*MuA6HDQMG`9{

&xTZsk`g?cH#9X1%)&4gz4ZRZ43cie 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%0Dlh&j3%6ozKC)1>jj? z=d;C+(Yjgj$dFY!Z28Q5_;n|~yiWOiGrp~VZ{u^y=RL^hDfj?7lLN>w?2&er&(pwj ziQ?-jUzpF$;8|_wbI6zb!Sjfn&z3LzHroZBLv}s~{{~=y`*;p=!*mrtet+dC9>Iuz zPB+1nqF);V-vg&fE@YGAO(whH@O$vIWk|m6^6&TH*`)ZoiXZduZSZ_#=W|GJe+=3l zhli#s|FYpW4m=C&d=CCa!E>{n&sH8u@b4kT!*FRt{@Lm&^WkwPKGS>zWnaXz5q#Hi zC>e&IBu@2o1oC+od7#s1y36Mb@MJ5#uJVQXJWcTk5Ajc=!{Nr5d3L^Ue`Cy21cOtM zg`&hE?US6Z9LLAVoTX#4=S-`ttt@M-oO5Y84scpHzu~*x8S^p1eg~@j7_E2ec%~nh z6W}74;B?;Bq7z+;ILSACMx59~5^=4IZ$|u9m@)dbExb#ns3aIF^kc?L-WW4hcPqVM zCU1?IA?}m;SMGGN-AM3Xd&LW{7J20uyd3KqmXtMAlrkF@R)(wVDoT0j2k(p6i6Roc z5G<_^*WhEMrfyLwiXeW?#=N>Z6wV^?JB+-9AB7>@YsI@0@E+Cb!_^IyWfcqOmDen) zsuQ=RY|;JX9$4$eyp(zoQX)uk^128t4dg94xxS%pzPu0|(O?`m#{IM1w#(Zqb|ZZY zmz7qb<{&iQtx}7RSj=E2{r6rL!@T|PycUKvVW%l=EHGZZfxO_=8@SViG5A+5jv;?H zcf{Cozvi-+V-R7grYWLH78TA26#GSsdO#3y`POt?Q6sO9>ZX!^i`!e+ zo?fL&sI4mt+Z6&EO_R`}Ier*f2MiO#H=^A`430;Gj9>#MUUYYp& z{-zf6`LOG?o10obf4IW^+8eh%wc&=oY2W;GHim4E2>wq`$Q>{#p~u#`$9{RMR^B%v-ecd!hs9+Tl~s-3(UZm{^$j(P!c`+{ z7S(ohUkJKj;QFp%g)3_6zPlg)mu_l7cSL4L7q`ynJ>CD|n_9HIt+Vf%o`1fU7aa5R zlh>tgot=Kg*NyY4x6a;J*f(=|+FjGXZuBjjG4HPF5BYp&4Lmmg{CU+g<}II{e|~!I zA2K!%vdag@Y%F}pm!2CO^P|(pov^3>&rj}~={xHW89zUH+zA^8Ue{+`>hiRK$8H|9 zE_F};>-xOSuNjy_6F({o{I+ED=M$f)EBf(o{(gAk{i(Gd&3oySiMo64#{1f9yzftZ z+_U|P%P)9m;twBacx&dmmnQ~dTX^zLAUZoK5Us{uvtRMUG!&hCRNUB7eaJt)EEI~> z%*L{E_jNyk77In|_l2TM_f)yBs^9U6JLPN!5s22OVedyusEw-uc&^Tm1a&EPL|>`3 zbR;ZE!mgFC=4w3RUTu5f`V9PtE|t4lVlgi43B-7aeZ#)>d&zQyPpS4+(^2S z2mLc0xRD~6dB}?|E!;T{+=tz(W854htIPW-EHsp5S~q2x7K-^l!yc{+6GLtNQTAG} zr9CNd7s_8@J-VTA2C8}g|n_kZkIv5DXQo4)Aliw5?Q z=_r^!w>cbeKbn6Oj-i1^Z7zpMJq9xQUz%Nta$kUdhnu7OXZ_QdvlgahJ#E?l?|w9~ z81<~jracK!|F!VmU;GX1ftD}w@cZlLx7Dtyx&GYpkbCuSzV7I#a@UDtp>QG;4<LB5u=|ZCu=8Z70_4-lcoH>EsB@?!QJh*LZ6D${YigqQS=^R} zqL4IPMxbn$#BEFBw$*XlFXA?CMv<~Ord8R#h}#CB(4_0>aodErjVFgl*GuEJRj|pJ zJ{h-B@qLWv7kKP@NjX$Z{^xW`on&I2~;@MC+I8M|WSEva&^u zl!rEw)sQ4D3I~YLB5;-`(8yKr)d!`RYz+P8&sgcBW3uV z2do65BqI$#Kk!;$0Qei=y}))L@wp{u>yJlnq@gWYi{L-YsIS;kLz_Hkj%DAMu@to+S$hIDDci1W$)a4Dce~GbVCnSPu@JL%f&@f&LZgR2C=*G!kj*P?KQOUS~$E_V#F+l5&~b(gCn*3Xvc3!#zr%4{_3aozK1e2o;-PC z%xsixDE4E%yaVO=DLBd^0;{|f4wu2jnx9IGwR+cphJ#~v7sckK;L13>(p$%%ko9}x zctD2WSnyIHwy&tIc1H@%p=!g?N&eUiMX{|u9!P-GP%Ih@=LH`Mw)J!2ezHVYOFOP@ z!Vw+9lAj1$50dhEY)68y^@A-@*l<6MucxpLf~}XZrNP!)*oMO2qZWVjJ#dsBdts9v zXTT;s9s!&5I1@JMaW-ty;~dze#}k4$@7NsQeB2tR{KW=g2C-&>2C>a(%%`d zNq=XMtmP^GJpfH$p8+)CIdJOn+)J6Yz!cX zql%;XU%OYX#tTy%dE)EXRhaeXHMr^RPR}HqVuORWhWcVVUjAbE4xE0|oE+P9yYI-+ zBfIw>pVf~4xMc`#37dSm?ajUDvcE@GdsTik@drVi6c%jxDzEwBK+FCJcJ2mR4!Ybc z6U4UN_1+BDDO8O-f$O~iAkR$66u+PFQibtM&JyB^Ev$)~+0dw-2jPePrYO!ZCBv-= z_-HCD(wN3nrCx@pvk`h3uI4@dgRr-@8ni-mqIkE@!g`MH@qqGrP=^a@W7)!b-0dso zAL+6bE^8D&Mpebl2aj@G zK?K1&up8^k%H?fvpMbsrk8YSJ%twqkh*NDze+;UV`SduD+4M)?VBjVoCrCB}=K`Mw z^40KnAYL`xi78Gj`3lG$(m#NMfZqUlVo3)u9f&TnIK7wjQx%=BWYW(7x`5othuve5 zbAgG#HeeEvDm?>_ROz%OYZ-{Yq;bwg(pbh!n{G&zs#@BT@Oz}7r7M;Kg{(makF-%$ zV~hnpkc)onM!H*Nvf&6-eM~Rym|dr8Nfo#(W(M<3yhH_}U{n~)cj*V!whV(TdTeNS z3PWvrpThs75%DAoyi~J9;1i;O`gyoD ze&Z|cVbM}QRbOhMwptuo(AJFO@Y=#&Zva0tLTwc|ogF{318o;1g@(T$82&|I_{V|a z?}vuJ6NujAy$wDE+b&AP5hUUr5*q&T`LV>8e6c?T+WJA?CsL<<>OPa7Lw>KWr{e@& zUB?N!){YZ&?7>#?nPZF3T&Q$Q1S>$WOFY*}nkAm=CCw7g z2PMrC&xa+=5>F~>TRb!3@ni?p7SDFcZ;9s?NwdUrhoo8J`JAL#;`x%KS>m}%(k$`Z zEotULM@v`v`KEBR#A%P@x6t-VnkAn5B+U}f1CnNm=OIb6#PhJES>kzA(#-M9iO2J6 z;b@7I2JK_7pLiLOW{D?WOr%-j*-z3e@l264OFY?8fvhE-X_D4k^tOzq)#~N$AYaET zI4wnJM)bm})_j`pPC-WueJOOGHe=9Xljl?SMZVpix@T|u)IFkIx+hkhrR7yc3l7lj z&A1yx-FuYNhjiLwb{e2N9ir1-v(p*6(i*(rs8;V~Pi#RPR3?`p(}gwyXkdraqa0$2f9=+sy6f zu5vL>KX7rexpP;uRLt9n4k!I}HtcXRG4>88UyGePoXisE4(B?!ICnT7gp0XjsdqRx z*ywtPvpr6C=y1L=kUdvxhZEy^NEqwA|8WB z+L(HbZNLZqrr)}e?p7JOF)00lf!YPt$7p$n&(L!Ao~dQ-8m?t*8KHT?XW@dXkvQ9R zl$Mm8DLkStG#PlLk9s;2#1(QfY;x$Fy4{{8$?59XL+j@njfNJPgn|5w_+cVc(eRu5vx&)(!1p1sLkjH=E! zK>0;Z0hR&J1fsc!!{{r30sLMHycoC)I0x7WoDU2G8-Pu~FmNI8D&QjE)xbL7D&TzJ zjlgQ)&wrBhr-Pk=0Y$lJJ{lh7)g2 z=qc`z9f&Wa#C)0CQ?$W@|C)Qz{`}#|MK>JwOFleHRg5734*6x zG0ffB(Pr?n>}Uj!unoumNStC`$4uS?7l$tS9sk-$o)pM9n&ZQ^mEc+rGINn8Q4{SA zwhP5?QantlX(cA}&)DPD8h!EW3 zu`m-{{F0}6U{=F=L+Y?3qK?x~b192ZTzamLshs^cjD09>H;V~|JUujY8p2JDl@)>{ zDCSb8&Ps6UqaOD?@i4N|UdjUm&mNFjCund`qO|bkDolUPV=HAh=tj=pzW4G$hE$f4 z5W4~7@L0lPXTmt$lhSW7mN)G6o&wm;u!s36L+)Hz&8&Y>DDZyjeXUUeA;9`e? zEEm0qLt8qP&Je-F7o}c0gX5*6pA0uxvzHD$GL_EWWy>-Qsdg0~!DGoW)>5Mlp8LQb z-ZiBDtfT~wCC84lgymiM#n*<^=SoWOSi(A9NM-Xsp2x17vwlR(1v4q9xDWlfC z>^nHekQ$++1dk=Gp+ZV;O>Z6-d)AODR8oS+(gsfyQhKhxKIEHU7;TWJD$|h1y0iHt zP!e2xyHZ>IX#KCD8kh-Yy*f?a6R) z+Ht!VeoTzdSmsR}J8@#?Dbc*V@p6m~wU# zIq$V>zp}|WyGc2xm~`H5rF&S4i%-jH^RhF?WSWh6ZMU8f?0GX5d}}HNHlmCIcCvNm zv=Jqzg-_qmW|B3zt8dhJt~xmBnd;!A=c$8}zT3^gsZ%8NNOX>>a?$g1Y))n-HkWCg zd(oB+ZF-pOUhCUcJBx^A?JTjy8?-tKC-1!E>$Rqn__-SKB(p0~TSNb~EwgeS?k9DSox!>x0*36JKyJ-No;x z;Q5u}>n?uV!Sg3OpQx8I4F0EP{tP^NXRj;&Jm4FK*XTsmDU9G zjpBh-7^nQ>JLxVPpHu$LLH;em3;P+qeqp-HzfZvPjpB=^!xlfjdxqkrJc2J~m^hz9 zdZ&PAmYvV$AFDtZJge+{4*vZTJioK^+5F?1|0Tu4_|Z7!-@V9}12#UV{KHqUwgw%8 zM84)>y34;2;L&&T#q-4$Kjz;o@Kq`Q;(QM2Z3WL7JD<%zFZ}xrcy`+P9Q->3p0DkE zHvd>2$9wS4WSsKv2Dp#(n3!O7%D)-Nzjp8qV&?&-yZoB~o`B+u=Zh_VtnyWgM|g;T zPVxI4=*w+ngph&sQlP z;UWHs@^IL-c)gwP+wWRjf?y_mi(QKt=C1pWn-;~O-=FYJJp@||$07aLpja@ybn-Oc zMbis>p+aozmUQe<1by1%e2j!kN`jzVR4}ig0o&drEm6=4iY_`oPU@-H3eLxxF1dZN zuiUD1yG!J?87 zLQP7&6d&AEO7mwfJ_NyUfmoBbp2$#+)YiKB2CiWq6`_}bvn35kVM(qAu zw?zI+dmjHC_Bj5p-^lp?n{A5RjrS%xz1WQ^6au%SF0O0{V>jvmIC-F4rcC#taTKDF zC#AljSQS^iC8UGzf6Ye5K}ZO-mC_ESQhl)9bg`4Miwyb}I~lndmY*Wn44XAZ=o`*R zPVxWewk}c`MWCPL-sid{i{xs%2C)m1Gb5Lx_!icSeaKvz#|U1b^DiuGSWwwex&+5# zp>P=yk1DhrA@8(T@h~_d=oa8lOL2YmLgfjMRrel0=**wKwd+61t8u}WpkMS=+w`KH zCk;t_YWCD6Eg!umuUtrR?X9`t7Z0>AKjXz~HhNxl_x)TGHx{M1&f9Qx`LSDWeetPu33GCNOA4Ey!^tpSwr4_cwgUxBbyf8B5o%J{q0w-i9OYD zNBT!|UwpN6%3kybyWgpJ_ZwsG=zIQ6Ln|M9arg(r&UjQ@ga&_xp1L)$|D-+lPrACQ z;Eo-K&%^K<`Vc9uA*HwUY+pO&;0r%nc=HdQJg^M2`huR5zhT6vVO70mUH*QLfrl=5 z1&6XAe=6DU=z9JJEwZX+{&(NchFyH$(UbCq@PEZt!0&e?ew%HWjp2&_OFI(FWiR!A zdc&bU%P%JQ1F_q8K!0$@4X%IDJe-!tG;s7U0JRFGGemFR%FG zVHkcXumo5Egk7ryRsr!u76K9XNF%TgcsZ~h_zbWCI08sN<(xWga`TI%wJKMB2U_RU z=`QEgr45B4E}+Aly0<4*8u!uqt2uRU0KvUyf!GRGg;+3?+c^TU>Xcx#aUZvZwS4F* ziY|DmDB8HAD7G&Y`y?9jmK2r0>|XT+Jk|Gzh-Hx{}q4I}Z{dhD;8&Y)MG)->hvqnu2>=Pw2=e3#v{+>&>i!2x#a%sFhM1Y8S*CJ=WR-U>vAN9-|s z4fqTEW-sAaz!MM_{Rsir1KB)Kf~tAYmMr$dN!mW;nk@30an%joW%H1>B>d)>sIlj3 zqGDwOHh82B6-qlzaFdH=sT(JMJ#d7-DM?z&VVBl#OQMz(?x`iB`O)a%P*O^xDk>X? zIb}Go#5rkq3P*CfM)c7}V6HA>SAuq8MK5jejNV%BA5n)M$Wd*asvnD`uyQ|E18nxD zp;FI9)#p`(sM2#&ct2rMAod1YIhy>^FdH?mD)q>H&S>9j(2TJPvoD*qXvbK!nzZs@ z7(2p06PJ>rtp>4~7VE+bvA)?CyJ@xFVzIF{!IyATtA?yCNEp<*=}Rnk{m|uGHNB(h zX~bgLy=+h(HZ9TS#L_P`GQ^h+FB6R{C*H`YcgJ?2_gRT-jch*0ILxgqhq>u!*vj(Y zVsB*u(Eh*nz6Cz2;_Uk@8%PLX!c78#ED#k16-m^@c*&9tZg4{)1cag{n1qW0Ns|qt z0xre~=^={sUa(T@UF)UQsuaf6^ZozN%-M6vNwoTYZ`5$QY1I4pffSrt6uc)X*GgNy^iGS=L}ZnsD~K8nuI zuGtQxOu`l*2iaC2bMhn*^N(ov)BrJ`Bo+X-0Xe##1#*{aJMdN@!*R~}J&=P6^RXUO zw5dU*+;(c;bc6NFyjh0+YEUU#8s3i*w^5oTtdTjlX_SqnI{{D7AQj`bj9hb+et~gU)+i^FtLv@@uh%qD7Mo_#Df?}J&nxVUPj7U zRF|Q44i7#^&YB!YxY84yGy<9A1fu5so}n;w;V@-J&2r3gdogoXl~%tNZ5@=IvF79e zms_|7m_reQjL^mA0Gv>=>D?f&9L=%^8>A>p%@Zjcjwv*_H)@`&r_d5JF0Y7ukyx@~ zh!G>QCWs03apWRu9-kc>_il9DU!&u8N6go(!I}DS2Yka1@qc7oJ4WisfnV`u+zYh# zz<3To6A;#5ta>}HOdsA6tA47a`bo^Jm#Lw=EoD;h;%f|4e=y}T%${myy^PE$2pTk~ z_@naa899*i?q!(U#1};33vMS9@9w~w$heM-mbo(Bq70mA>oE&gu?jO<|1Ro;s1;7b zm~BOKo%IHmP|mqn7zQ{5ngJYQR+2-!fHHXnySXpKbrGeq9UP*1@ptixj&mWR`D1{^Ndj_+Y4vy6WN zq6v)MKyru=fy~Iqz@LA~G@`Rf96@$LZ6oKX zz!Nk`#keiw7w=Sff^&>WH%5FKGzM+KRl_y7YPh1e(G&M#(pYJsYw8p@5v#aDu&K0Q zNmA18mzJUo9F}Sv_Ff9E8}4aj#Z!&mH_CJjMp41Re>zr`-~d@+sOUzk7v_-@WRjhv zndeO?F|iiMJp9_S$>a;kRdE#e0(15yN2tKa=j_`NA09KeDH6=NIJhDZ4L(}}$?P?g zI+{LY{O4`s0KwQ|5^C+rPxyc*OB|rc{m>_Ib;&JRC25fHm3?OUneyI2xD(90@E0 zW&pN0#^aQTelO{^Q`=OpW1cL- zFlsy~8~b{txCIXCZ5)K{>QGG&V_-$l*e^FlB%}GWK308d%~u~bMjYyY*tDR^H8q{7S3 zfTck8HTGrI*Jw*Ob|l@{>y#TT2J>VYx~jgWZ0u`ii(4Sn8%ihv;{f!v0qAS}bYFX1 zH4d4@LOfmteSXZfjN`M5G@d%`RHjvnq%)FDFc(fX;Wz_jtRn=|V&(P#l1bCdL}d_X z=}M`CT~!Kg>hp1eeQR}EFvKYKT2_^=gV0^NV&qVkHR`47vb)&l-CW}7t0iAu! z>E-5c<#a2~!D1O@S)M_X;(}k!a`07t!Sv&s(#)c~{Gym6GOh+BYsoU2g)q-kPx# znAkg0c$9(+-V~z%w%+0f79mTH6sqKC-}a>MZ($oGbQKsHD#V$vjT5(vVB^GssRREx zjyZ7^c+{IHY(jrtiRl=}O3Ko^qspU@oC6c#9L8_rPpUZWL0&DxG&!CN;P9SypNnzK ze9Qxm0nP^=2E+yNqT&SM!Ne(ePXJE^t^!sAF9OyA&j+3Zya2cYxEy#Pum#uxyaad+ za5az<4ppCS08;hoKA;JF2e=jZXW%yAS3q!s1T-Fvr-50(hk?{$#Mku11mGh;ejEBV z5RBb;6nGkt^c2|p4X_sY7!Y|Bckce(i+AMBxDR*@@aMqw!25yM1F>*U{1kXI@B!d0 zK*Vj_3Pj$F+knpj8Sk4wruPTn?LgM)oxoi{#F_XQxB(bIy(8{KA0X0{13egy0{U%0 z9`kc4Fao>`I0cA>b|MD69C#}5hrl_&D}ePthUXz0R{}2tUIn~NyN^fxah<04GHvPd zT~WEM)xK(B#6Dq}3t&-`m9lY~;3xC{991!j_PUKzsF(AZQbi!mE7yOrOYKlQRS`HA zf`J|QPaBPW!ME)af~!*%f!x_v!=NgH9cqBYf(cjRaw^I6l2Do2KmY2V&9p-uqFsf? zr6iLop{(z%1s7eqzH=$qa=`!vf2};HCKW19&@rbP-cpd0*`;`Se)*s6P^CJQ(6|&T z*pJ*wGIpqWI+W13YK#qKr`7v|KVEHzBLAQf8dqAJ4uXLY|KnMI@UR>0P}jnRMrd4V z^@FRO7L{b|P~<^0LgPw{U)OC#wda?woneQ1Qo^V&^XLf`>p=p@hcOIzuEBc)XYgUo66R7``|;06$Cw16Y|S$Ig&s z>-<269Abn#9AKz~vRdcB$3`7whr%2nMrd56kX@00^aoHJmeb<6ru;!2O6{CDYwQ45 zTGu2PJaQ0xyh%gfi?XQwq!hY}iBDaL>{82Gt_ z0f*>2_|eX#kX8tkJ4!JoS&D>?c}%BL93(MYrFi|t-(6{k;^AL3LgOmM!Em+t*k>PY zdCU&=6CFxuT&3Xr6AZAY&>S&o9GV5$b+rYTq`|;#_;0nvA<0r$*RLOp@fE)X&yZR)HE!GTea_SxcI5|4MZhcThK}>LhD+29JTV6+tqrrKAG#F zdD)#jEPb&~9wL>F+crCSs1QCLDnuuGPX?_lkr0DihN&5MyG>`5wjGvF4 zPj@PgjJiBJ??5E0)5puIP#-U=N`1VnO7-zlp?o}aemnax_wG-?I>SC5I+D&luJ3v} zyxUC&bvZgeDEa>=)lqffspItbg(hJBgph5%RueEM_n3SkrzYS*q6v67c*NNpi7t)FH{8aU)stifh-MFm6V<)>*f94uia zXnw?X4Gg)AUwrL|?{3g6;kpGT8J~0|<;MSHc~^txMomYyEgB>q%^x!Cc1;7T7(dM) zP9{4&bbk4}7Wr$!`lO#;hjo{~qd^nablv5zQqy#ozps$L)u3zPiUEf4`Q`5gBBz!RYPy_e3XJ^l)s4lkXjJwk|Y#Atk>#zT`#*C)O?pqcNb z^TfxcN{gnE2=ULaeZPeJ^`N_MjH2qQ{`eE+LC_53ssg6F_ALO-$(k-%4p08l5J#=1 zkqGh6FMnKoF9zKoxGsU|Dt{br9iT~N$A;-He@B9*K+|=VKeq2|&@A-Q`LxGs&|KlA z^OTqI-3OXYUOJ!nct7B7FP$eowr_8&JVtT#0h26;PkbkV<`gfTCq6FF7lLMmm(C}? z^`N=cOXrD?`FldsFn=`CzCN04Z+Ypyy(Zf-B=c?V-{XC4xVfb6th2EvyMKS9iu<$t z*?-7Z^}lpsbwgca-Mn~c?6gBeW%coeix-~1aLN2o5ws<6%U^@~zI%309( zJZ)O#BxspI7i@CzG)o;URW!t~yF?YS^6>QOl@-xxGawqNJfP`DkD_Vesi#y%ig8ch z0on%|Z}gcSo>^QOo*I#`_*|iNY|3y$T?M2s)B4|s-ZmwQG%G76#Sm{=|Gsd+^-(wj zpEpQBB)6fdI*!Rg-K#dGsH}K0Qu!yY#oMPMrW9a)iHeOCRhC4s4dAB|#7eyp>i~7} zAFt`FKd;id1^E9f6|uMRl}J>?+&3e7RmA?|?zHpK`0PdxtczOs7J6Vl>GJNxn4_Ah zz(ukqFfxaNSeFW^?5zLtOYi)y0%e8zDVNDTcnM7X_=7goKJBvZwaZ?7`=scRf8J2{ z;JYvNx%^i>@Y(H)9;~;{+GPh~J>jQaHc8z5waeyl4YE(W?3>@1x9`3?|Lc+Ee%$Y< zLAVI(v-o$uOE8YB1hqnB7iV5VyG&M&|I6xS%@602>qX7W9|Eq-%xT{?X*ii+>!d-g zld?9Ot0v$L5{dbfAXBr7+vANHX0&fkd+U_p7EKiAyxOn)#l+2{MR;;Oa$@}IK{E}H zLqtKH=Nd+?4buuCzg%}O*KSh`BSGt_K>m{Y9*`dg z<^cJ_|8!soSOMe*+8Mw+An6K$q$>iFE&@CacruXwW!j%*qd&v<#-p~(Y4g_vi?&u! zwsQ+EkGK{@5%Y3ZId15~xw#8M=IyiOtsX+;_pyy4=2Unr+k-p%a4+A29T3{1plGCE z>Tq1u_bRUHdm(1N9y9+=A@vC2E{wFU&EANZGul$YrPrA&2NnDSf>N=J)vqJIbvaKJ z=X@B>zl0yE_H{Bj)tN zoDYl59U1q$l7CJfQY_E7lyVj3DY=w9jO5SEEUErS!;DF7k$y%&QFQq!(drkYX6&m_ zbkiSGcQSe$sUFFnlbdnr9ZajO;wy*ZO4N*e1#Ob_Fa+E)9)w=Z<7x9+QQkSZ%ir6* zB350LQev)t73swoWto|>IRYul3CIT|#C}&|J|BUQeyF27En?2eEiU-$ijtD*t;OTs zjt2LZRO3*0XFehYjk(3<+ba&%d7$D<)SQI6_e=hLl#n995gZJ^5gDg^aA6E5m*0k$ z<|hJ?;4WO}mR4|1UdGzbL{bTr2nqQJWVYn)HV9xsRWdDHkgR;EXRFdP)~-V+lx_z~ z7j2svLSayji`#MWuy2yv0=i`{IRpX2h<@8-*)e19NOps@pZ^1LRg*K(ZyuA;Ut(Uv zp0#qA9{aoVaa#!s)Vgv|>*TD7?Yr~B=4zV}H1sjDsyhkVj4<7r@vC3oL*9qR0{gB{>?0bo;ws0(L=6Z}DG*gTj=l-Mmb6KpL?CwoQS^zi`x~;Cjqq{`Gg4WPZK`COZ8f5#NYq&5 z&N9pc`OauK2rC7mj0xuJO5l;e^}u@I^}qxWktbO0JAs>kcLBEm?*_i6-**5(BdT@n zz!anb+C+aK-08a$o4}{p2@c^&^h&oQJ1wIUfc#phq1pW%|5PveB0KNs> z3JjqR8P9AW^LqyHCE!xvE5P%CuL8O4_8f3M@OdCN0AB#!to`2rq6~>asF&A)f4RQc+*F)#&*aQ-$FxFlDqJFp8&*$-p#N5k z?+w|EdHHWjs%L_EtG-U%qh;ZOnPA%(Be->EBMK8WAJ1sx*}k|S?7WpV<{r@oY#SbkZu+lOiCw7(26MI-x3nYeUMmkjr7iMu2+sEPZ_(B?Mg=tm zXb}qMiZ<^`gbQ9+{ys`f3G#5k?7Zah;1YC6n*DiuYX9<|g4wSG& z7}_(6q18wj+$0f57Vx5xAjV}$8&N1pZc|!VvoqG3Rbi~3jJ1CdekVLlr4=YaP~mFe zNiqy~pQyQ7G1yvI@wI|5+#HOpA2Vlhwm$aD{{_}&v9TYacwVhzZkBKWOa=O}F{S-0 z>!kk~Mm7)(E)NNwiXZ)D0q7ym!-q&E!p&tByP9Q~H?o>xaClQYQi7ZB)xbhv4X_Bf z0C*8_F|Zv-3C-<5u%ZOxZ3KP>YyvXQr9h}@80P|y(C>x7Wq6+hBpu?C@RtBr;2qMN z68|P3q%afj05MsJ?3qsDefK?Mv$;MIh3>gZ=XcW-?nUzWJI2d z(66+5$?#%xX&Ts*`2-hav%-J-tYy3T!OEUt^P_PefOEAx6{~(f<5J8`SUJVBBT$`k zvm2~&+Tj^B55!fvR2r1~F56Q60Y@BCfs4(yMY6~81sMxrotRw}Gr_-~1`mdA^GaO( z_(X~MQgqXfRIW6m!B-)!FMYY?!$`)1a}q0um6%(S>~CJA^#I<87{$+>roRaPBJchx zV{HRC5wkc8ml0<#gRs3;XGC42W-?lCM;2n$HQA9!@IxtZN%dzaF4sNf#RcL9-ut_oV<(Rp()O;RV+^HqVyk^1Cme0Z& z4^|wPSUE6iZjPGI&1;1s_DcUs$d6yw<24d5boq{?cUX!pRTKTdN9YLpuosc6VC)8di=`u*fG_V7-QmL4B57 zh-YatckhY<5=SLkys*dna57P3lF8l^-`}RY5N?#m!rv+dvC>C zzUN0Jw{E!**bemLmh%=iG{!6I=QcJ9$7G8BhD*P8czKt8EUoX-Pu;S^k!cy`g`8{* z9I~}LIGp^*+zX^cPXJsd0qh0D!b&b!ybahJ@Am=IfxiIu1wIb!2jq{i4B(5vOd!_= z1Au=7LZ&^zUOfo-AutO_?g~zth$9ckPa*+CeiD!g7yo;KhvOYG?Z#2SJ-~^;Pk~r| zB=!Q21_n_coO~sV!93tmc+Ur(2rK}Gfmm>gd^zKpk9U@D36SM&(C^O!C&T?Oz>|UG zvIpT&T$Z+UV`I|oCT&YM7>;#n8B!`Pt88g_SMpb*G|4QDoL_AkW$O#KWAOwHQZa7J z_{Dn^JfV0xG|d?LX@6tzO9PFxErW2W84-?G^K7x%u0BoMn zf;aC9>Pxuw!o$_YmG%!o$C2^;-X{DY1QLHkelP)EUVe}VH=fN|79dlpTwGV9Zh3_> z$6Y%f%P=1pf5O?gcA%-nxM1Gq0s8?L0EYk<0{PME93bpGlss`Ba1{`b+}XVv7{~i{ zz$V~EU>%SnhIIUXvJ6Nri?G5!&IdlF>BvV&_dDQXAbyw`OMttzKkJMB9G}PIQR9=g zbh$N5xoyv<{^HomI<9&q;Ao+~ zv9@#TsZ3k7E^Hp39mWq5Tyq7Lx>v|3jWFiDFX@jZnj}U8Bq+oGu`Q4mACvXK&#iI?7Iu8=!{7MDwS#rJs21FDyba9## z2`6>+8LpOGW3X_oWw^a@4H-48xFB&2SFW%Y(p6cb zbj43%xZUW)iwabY}itUkNFj4e7*e*}n z5J*1QUI{$Gqf^HDgZ?k#*Tfun%Hic4Pb1()1{uNwCGgtX zn#y_98g~2!;h3tzV;McC$;Z_S?RYij6y}pUQvATO5qJvlHefyQ9^m^x{7OiC0K~_R zL@i8F#JU`~DK2KY^+@Po2?$W;LQWwmFW#+@8`nP>XYil(Y#G0J$saH$;XmU%Lz8wDZ>3O^ig8=UFW%YkM7#r1@Qb9c(eu4t zuK1Zp6)H1n8w8t*-=)qDRPuOOqKsM|PoelW5j`OVg*3GScrUszYc=G0qY4F>~h zaHfsM*7dSoLU47)+>>+xepmxfF_xaa`L@n6b9M>_+8r_XOv=g+gda^$Lt=J_b)~}9 z*6aBDiC+%0LyeL!>MS+n$06j!_74WeYX3cR#(!*wI!3z+jo4$_#X#!rOM!aBCm67P zk#Cv#)nT2>#VQX5u62|PhluDHXKL)-sa$;|6vqHtW%R0_RNA4)OKF70RW6}VmTTrI zN4#o>TA>12dSwnx2CfH!0j_wNR!i`0O!mmGtKIh#nim|UurI>83Vt;GI+Y>=u6FBu zvTJmz9qM)oqduLxTZiM_q3hM-%9HF+TXiU*acTH)qOj8{T(D$6JJh>6l+d_pY=DFc z@jsqFU0YvohmuNwtI)X8Vt=&LYTUW`5)01zRp^)p8zIEt)W72T&n`vJz?R$WP&GP~(6~yG zC80PvXnuOzYoFSoF3_Qb##M@;pjFyvEX6AWpPSaX6!Hzr#ao6ZN6HmC=AkHsTU&;| zjOfsN2v=GI-yM2`9qL0JN@!eZ zK~x1fw9*>9;NZLMQ2UV~!U&Bkt&woG%k`t)Z(U}GI#P!c8dq8&38m^E{rQfy3+zzk zI+W13(i-JT>+ctRe~2CG`#O}+xY8Oep;V6rx2WHKk{yb&JTyY%N^1;U?Q*^I!jR+b zP`}WjgvOOtwuEB2Xr6oP(>Zo1euJSA8nN*gzcTDC(07_>adq}Xx4zRsaPiZ3`Vw(? zWCYw>dRlSB<7g?tSm%(-?%&zx*EZBu&YRm{B&qf1bZ;bKyXe?m~9qDO0e2IB(V+33`7D>#TQj)=_xfyZQx?tbr~GtXk-jK$Yj%>@Eo` zg{UqGR1C*_T@2k2s2Fm;E{1LhR195aQCDkM{%1GTH7%*BY^pcXk38z=qmB*P=Ib<@ zjy)a6z1Wx0l*%Zg>slY>5=%d+m4dS^6>zK)0r@(Oh z`)ShfbJh1ivy>|n7%o}6y5sD}pt(cSF$$V@|^$@S9t#5WBzXL{*8`D41vH4W3H@zYfKBiz?`==|!BOALO6+R8N%On3G7 z5okWwblsIV%Ua#5D1Gx6M7rZWbbk4(2i=jV#2dJ3g6S@Q+d%U>P1jZaIN^MvX(U4Y z>q--Zchfly`zgl6k&)ub;Tf@tSjnX0M&n;mX~k%_V_7URHC$ReeRPP~{RGc4Jl{qW zWN!UJ9Dx7bH9vDi_ah5akx^$twMd`i8psa&rlND9rvC#+hhd zc#l!qce{{Q1=5;8!%$g2v#ODcpt>csOK_Vfl!d^c)A|SDSE&?;D&zQFmezj+sqrCk z@#4BAa)%GK3NEwjdvSf`VqEB)Z^2{(z%t3Ft#u%()wS;&~hJEqkSJ1qs@oM zl*&j^MP+GmMYJp;p+gwU))hkkarz3E*$(@U0Sp6uAgsJZU2wm z^`lpB|I6AKJk_-MyzCn8jTXvbrWwEd9Os$Fhepi+cILUNHN%h{4}@C_ar|hYBeU>g z2;|@h(0F>zc1wy#oru{{j*Z4SW8oO?m<~YzCHWLH*KfqaTwDiI>^^TjzpX}E*M|V% zjH@<7&b~I%ItMaN)}f+BNS2?{Qe?x2pW^Jz_jP#7_iP&S7a*6G)ZJ!yEBfMtyi>%_$o{?DEH~+VCS4w+Cq4G>V#~Qy*7J#keiw7cYNE zAzt3cfV+igthkw~9iy^k!cE2Pq@>+1ZbcdB#}kOttkbUZ(6MXTv7_9V$4S@AxmS*h z7G4XRd%Nl2W>Ic_Gh44A3;p_6*v&?Ve;R{f1ybi}xY$!SPsxn7JQW{q3SldR3*dr) zt>L~=vxt44CjvKbL@bGASw>WD$9cvBf6=qWp2V}m{^cwyHr0V~BF~aV3zwk(atEE= z+uv|N6vE57gHGjyDBRS6>~>6aXU}cIqmEZsDGY*pDCrJ;tIBGq_fpuG<7OQm%P`-p zdG^7JwPP8okY$+$91WZfEC5yjCj(~y&jii_a3LNxQ8$38lN2mI%;qZUTZ52TOo>C{Jihg-vn39EirP?XznL|1(@ zr(Mg8im-^f6=y6&L{!h+{~PyNnH9`O#-mv_{V7=Rx5fdA+haiRdpZXMySj+Wh+HXp z?#1m*DLL)C(*lpMHBGrvAnKPLRu#W_Y{27X>iq0O|Bvzf(YF&f%ssaws_L zeLaw!@&@2e;6~tAK&HozeIy>$v1wDX=E{w+DmPfLFT(%I90O1tTiMvLj~2JUoxP1a z!O(})q(KTI6`dOw;7n32_wOhL!H>#rGMtrrLPTyKY3t3wHmD=jvH3PqB- zvy4S{s9SX?p%MFL?Se5U?IP-3+Knze)6gPe?P8D5A>p8;DJ(Yq#H=fy?A)f(F0RvT z`y_XtvE?qNkEHJ0L+1jv2S&EF(dOf)H{Yz?SpAt%<-4g~-CeDJR`{;fbW#2NoauTO zd5#dtNwafgwpZu4l7847%+0ko2SZ=CJ9yMl6OLB&+#MVvyMq;@MEIEP4?&}b+Uoey zT6w`gPC#qP37y7gckq7jhetege!GJQqubPB99+d73q!{4w|hjPm)k+pPcJn%V7l5J zJQ_4%O-F{~w>!vzP^oEP72~)2#v+^xy5*V{+3?NZy>Q3os&UL9iAn~v-?@y8?@Z8C zYr5{@TMU{JgS(G!7QBl!jiU6=UltO&9&``v-+g>zK=&4DG^gk)e^Gd(gJv36nK0e8 z$N8YSMALQE9%O|#f#!ZMozL#-cF?@-rSt5rvU4lE0gw69NmM}X!yFP$eo zPC>IY4dbKn>o0e}y~ac5*PppS+3x`S65;0)nC|Lt8febcbjfmf^2g>{u4yDf{PWA- zxp2SIL+6*jJ)r9|0uvw}n(p#9=0NZTJTzV9kL^*aX@n5}{PM?%bgqZaFMn7i7>huc zOF1i;Wd0mW3%Xa~IUO{=)^uI<=l4Lj6*PB*V1Y@-=hI)dhtU7<&~#N^F2%kKk-|1o zUY~OcQ%2b|wEb&#rx!0=^4)i*CxE|M=M?T|?@nWHy>e#pwCN>fQ@h^0w!#gu!%eT4 zHUnFBvVlEJ?`;oL-bLZ5@R%{Zym)FPnPjo@NVU(+?`>imf1 zaBiIi(q7yIIWr4qaXh4)pObx)sCnW}(1Q%`Nc_yK!Zk}m+6kNJ+|I++&yq|$WAV(w zQ-ufGv`gyoEQ_|@onZLZyEiIWqu@3L>lECp;93O_DcC95T!g)tEbPVXhrO8IdM{=d!!ibb(y$x15pUirJ^A&>GLG{y zrEzO&QS)`@QRYuRRZ8<(#GR4bZp@o=>sU^BVuPWglZI)s!7%$GN@ZrFf@qtgD=G_i zRZ+C5t00xzTD&W_WHI?m+%D$#@#gKr-4%20S#?+qf7e2)lNr9Qn63wR-ry@BqB0xtqi05${j zffoZ$0=57#W@Qhy6i7Ojbq#PlFdL6*7uwXxG0N>G?VFB@|MOVLN-0q)^R?!^wedrm z_s)xtZr(dT9#QiQzk5c_-eys@?Bw${XWaXI2+p|6U&S&tW+=L1p@X!Q79tVx5$h$f zY^agZvYI52X~7(VIC47jADMs%mR3ZYFUU0FBPfQ_x(st1ovrMBzs zO?`e^ludn{M^zwkHr&-!F5=B13I^|XL?@ZdvPHl`a7fB@$>8MnmV0oL$$C2*zYwRu zeK63=gXS$C-_F14RpdeK4oarU2H=P8`?dR(Xnf}5S|B;+^*|26 z9|H@3KLUc`%ZB?5;0C;(1>6Wkhm;L>bUfomytB1_3cM7EE|a(lcry@w#w|cjDtHpV z0p10C19&&^bKreIP9i@C;s_?@FEI@G0Fa%N9b0uy+7#1JZfmt~y1{r@M#~%zi<(4~ zEe-G7d9fwGI6Kg=25cH->kBv5Kv1rQX55zXi}z@Fx+TA?xS6UQqq1@Ms<;`aMM=9~ z+=?;)b+W#;Kt1 zThDPQUcz1;F*j4p<++aXu`O@J%pcRO#5`w0e26;NE#sF%==*z|#~Ene+|l&09wH*y zi|00+gYQ@5w*TA!u#R4gBg(RXj)v>5 zLO4(ltSmrz7+%3Z*C>zpkb(~gg$f3gfu0#5`!1;o5= zJPkYt_$)91d=9t<_&g9}f=7}_zYfE$`ZaCo#uofnZirEA=|Fr@m;dTt6rlRGvZdjj zj2(-kk-d$PSR4(*;%G1yN11wYBvM#*f6+2n>?)S5;MeyP7dzM7Fk)^qUltB1JX)In zbS%cPgE9@vRKTJdRN2^|)5R?? zEY%o>1|5tB&CE?zVxQ)!c4Q6}Jb@Wv1+T*69bJ9kMw5zXSr-+2)_L*TZ?VG7)N7eI zqQ(!Hxr?037%n|5!#uDegTQR<_%14n*7tzS+xxoWIBHbI(WXu>R&MM*%1s^HCc@m1 z--hU_Lw-AI_HUh}BnOr79z?aVKo~1CHW*t{Qd=rd$kMnIi`9RMDJ z*AyUIpeOJ+Am-G>Bp{DLEC==hGT&K1cGolMMmcP;rHe$Wa$A#hgT)mbM>3At6!9zj|ZY01wra_Bb|^04X@tflY{d4pk5hRk{pcs`P&pDt^+Vfv?{W$iR*|WbcEjFDyE&J%7W)&?)2xF$XM!TrmaJDjeQZQi6>%GPwc5LTz zaqWkiN5QRf+2U(A>X@~toTC)|BotSm_=C*Pm!mCP?O9Fpv&qr1na7wZ_hH3sACdDQ z31E24kXu+S1Fm-ei7&{#&<^#Cgt0!4I1ho!lu+^?wi}kOS#O8>K!;MkPJus86?R&e z%(?IcJ5(AA1|u}CzB&M|wqWItFFE=|JCyZdM`&Dvl>;S|)HZC5SHCmb4i(X935_eQ zLCH|C7)L#tJ=YFZr9%mg2;t?E2!^fW?%{*s5)9lyPnf4RpIz9wz4&9+EeLBL284sM z#SAvQ?KMO~S>=j+(N8dtf<3GDHH>xh5su|wUaLkW#bxR9lAmuslRb1weV z?7HSwB*oxPJ~j;R!N4B;xB8)d+|1)Tt*<+ZsP)>bZm~nXtV12Zm|f)>E@`nvXm;Mz zxZDo)i4G++EZ5PBN`1$3mum#Pf&pt?^QY3b<(BL z@b`K!P=)`@&PQ(@ensb)L+}X(-ot+@X8V%)kvis)DrSeY%P0wD^@K+@?tZ}z#bbYI zgvM24qv47}=)_kYL1l-UqC*LdP}FD_LsCZ_=IVg*9RhXekd_%EF_&8eN#qsoeqXnp z0+gN)-!36gkDn3(b!bQXe_VCCs^mQ%CWS!Uv{OBG@>OB|^W>B^^+qcp)XGu+RCQLn+rt@;%f}gs^~=d8nxvOcM3$c` jD*27zaM5eq&QV()og=oyeeqo@4&fC3rmvK|HyHm15?^c& literal 0 HcmV?d00001 diff --git a/plugins/gs/zerogs/opengl/Win32/ps2hw.dat b/plugins/gs/zerogs/opengl/Win32/ps2hw.dat new file mode 100644 index 0000000000000000000000000000000000000000..ad70207b37a824b305c8fb7967c70dd84f037e8a GIT binary patch literal 106682 zcmXtdc|6qL_rFj?mXcIrDn*4P`!XhEDLWI{i)?RO_N-$`vJ2T6OSU0oJSOu>bb7e0sgsbD5t%{Hsufk?G2J0z<`B>~lh|SiaVhp~BnBsAr zB;s7mhMqF-nU<+@u|#k!j7(cYajN)Sh}e;jNdpKCZ|$B=f=(!J~7Wxx8T(AXcnA)MFjYt2kYQiU1!X8ntcT`-@yYeFEMdc|%H1Zm>`3ktIHw1E_R z!Jc`o%vEfuBc^l%2?G^d(tk!|5nScCfur21mK^M>Ve=WSx?z@6a)7(hktCYCltQR% zsbOodVSxMB9|={ z1nfEf^7r}a%(|iY6B(kf)R7b-KG$!dXMP%PFW09_-X5Nxen&j1hUx^AaQg>Og5$70 zIk?{Td}8rw8gf1spF8C)kH%3dxk;Z=AR*WWqL*Fv1|43k{q*C`k{HPY0fYX@-l!WY zg<2X+WIN{)#SuQ#ARq51V4O&a3%E{>bO(+6M#L{S*RJNBioIN0J>6LfqzEE(nk(e| zlaE3kpL4=NfTHV-*&28S9dA4Gdeg`fV!7%gqqc@}pZ_RdOksY9!q!UsNxN@PQ7qeAOTuPHnKYIhR~2#WG8=9-Pi z!t?`=q}rz4{iv<|@h7}(##|;8VG1Q{E|dJ_XwkVHQrI@r2Ss*S4lXThy)s!fN3hA| zN|B_{xIM!7QdrTi1>4>-{%*tlscoZ3e~I)aWad?!gzTerp{Vsn>|SkUJDgtvSf zKVTa8w0#99aWqEHTyHi4pHJ{GB7UvS&0~{G4O)oB8r>vS;l?Ce49q_$f!qSu74gGs zM{glTYuhipj++&>-XZ+;0{hwmr@wdx5cSL{`XEEiK|-lIpYHT6-hAO^HB5f{Riu(vnfHjQlhs5RbQUbeNBX zP9guKW-H_GAu!ZN5xJ1bY)yPzMN74%0XQ5R)a7k0FzU@zq99n8c|7!~q`k;p>WJRC zHUSGlgbyn>=)rAjN&AKj?fJplOoTE*6r9L`dF_2%qU$@!Z$55 zRMFYX&7QawG4Hq4W%EEW%^zqSbG^7vL@};3a+%m{sAY=-O-sxqI1BsrP=jiQ$Set3 z`+aUp>CZ@fslsB-x$*=H+~w1(1=(P*>g?%7bl+%Cm6$N>9=fkhJlLynC4LDP!NyRv z0|jZ}OS2hj!0TiWd2}i(=odwEGv^upj@X5oFb9zKH{wQA$QCU^C!aX_CuGZ~ZaArw zx7zl0OB&YTcKIc$TI%cvEB03X$*f+!pg?C_F8`$1S zjWyc=@;DZ<^$3B=C-M`mkL~KR4@z|Ib+F5`}OI z&4*8uZ3$S3m6lqylJ?J7haWAq0`_vL2IQ5HmRbqVfS@jTgPYHhu=4>hr;4I=E(^o% zL-^OWM)K=UT}#_HGvG*MbKvvM1w}lY z6pIyy0}1wTE&Q=`9aBpZ7D5hS&s4&jLy^9FwjtFx2FU?Gz%M>6`lP& z>4bFJqgbASWjH2b=M~H2fSZLeM!7On_dp@t7!5kYn?ZZIc>TbRf8cJrBheso)(-}f zsPlmv0$DO2Hm{E7fLb=$vUziCQFBv199*tO9juYB#@QO9)}PJUF3pEbUh@b>ig!?}*U``G+Bow8CZ->s)dBgzd{= zJ*0FOz3G!;7F)H6W}E?-xYQA&z`sS;KEx6><7z+8R_fC3`lKZr8(%UBF95a+g#u!e z4@2#P?X@*1;l%q1DY*XRJj@agx?90UU4)14DR@v7g1yNXXFh+z!fyWKiaHZQgO1OYxokc zi-?zv2-042yoydWmrI`ShC%e(P+;YmJ9WdNP|U%hu3O-B4X>_Dt%llnNZA!pHC#Sa~x&SBCb5W ztNP$D>|);~>y{w|#7V)+m@|`=6$mVm20~sGxLLrKDy}tb2R1-gB z6j7}LRXgzrl#LmijUUb@e&p@yAvJ|!ai7@i-kSJGS_bvLug}5CK;bg}(q+Y7Yx?A) zsKq7RPhV)InFgeIdsO&wORKN6e|C_C7CsWfJu*`4{P>&Sl1f(({_SNn93yQOPy{s6 zEesK2#I&lLi1+}2{V@*Z9&}0to6TXq=MooP_+CHU?t0nos;pWyd>WL5RW6Eq!!YWB z)+4{^VXTkEww1(HT<-`{C)Gw_qbFnEpvJwA3Yx1O=t(l)TOjCc?VERkKs-M&Mr*Ne zq{f>uYlCJ|q2Oou{}6*Xo{sf`Zq_Bz?kVHZc`8{QPi>P6HCNlLDDXR&;+uAaPB_b( zj=A3RkD8o+hHu>Co5_T_err~{NY1LSO~-Pj#$AQa2t$o-NhikU+SKc}5#qiq5vyWB zUCU}uiO03dr9qS_z8QDbHFMgEx+Q$NW&}-rb>?S9YvBvR zsab=Sblhsp)TRUxShxKmglmuZd#n@oxQN)veCGZL>e^HVFc}+&;}zb)JuYb8Ed>Zc zgAhm8vpSrR5$X+~t`D?wQ&jaBg@(dqJ!5v^jwL~F{#!2mT1T%3FMt zh4x5n$|uoIm`f3{uB(@k+7ymWjpOAzT{A@R*~ML+ikLmduSEfb9bglZJ0nC}Zt`*i z1nRM=Z@X@EA1#MFo16 zH{yamL8dTgffQ^GJO=oRE7Vq>iEdm+>WRPgXa3VQ*HbU8v5(Z&PLyjYVB(-gkH@<4 zi?0wkN;`i=L#096-zQqfC~jz_tTqSbfFA~df4@lejkcs#{sz*t@DOSVU`HS;1jH91 zp#A0DBL0On(B9_1)Qnwtd}%v!O?nXm*KM;uKEwUZgBZ6Z$`0m~2=U3iklQJcV0qx-xdR|Z7mUkr>x9Yrn4Zzc^ zPabhx{z&yKApSu0UZiel<6FSJ(VNO_2+U1Ui(?(j_S2!gC9xK6Gz4)|2T?e0B#vh3xm6a-Nj{pv!A;rh*T$zfHfclWv049SzcROnR>Sf;XW3f;%BDL{KCM$^mhV%D9J#=_!z}cF~JHjQ%~-oBb>8@PS@Be7XM`f zsEgRt&IIrY0`|TiNS`g`rIPxW2xF`WwFN2TV;w$p7#twj383jP=|ZQ)U$JY*bfEd#&2s&gBPRe&QpeXbpAo)dhZ{6G zC?4DpE;b!tWiqr=MF0ixkb_mWO96@ibocw)z>Jx-Y!F(fBIEJtT2RpN$)cy5L2xY0s1#_i_W8)vE0~9?3yxFaJ z7v6U)agwtE=v{F$Rcs=hDzAt?lmcq{e!||j)Z(HX2%#_IYWP+S;h$$bV4xkW8 zk59XBF5vw0-x;2Gy@B88gi%HyBBr*CRNt>yIoMNx2q|e_`h6C7fv4jdVW%931Zlgb z-PyreEKjA7&X}1H+<_RNY+VHEHb7ihA)R8*aCvIl;yi%Gesd+XZlJw$=(TItfLW0Y zT01$vgxiK01Ud$W?7~sUqL!AoPuDyUmGi~`G9!#~UIPd@75iWT#4AtmR3a^)XuBSM zu7K@Ys<4`VX6pscWddJt%#|V#^y>D`D>=Qu|Bwm0aG;TseRyvt)n7MI-9i0WM+X77 zxO#;$5sg(g3jatwEb{BVbH@!f6@itDW4uVc@eDsXq1*|(px?H(a%U0JVi34I3}9Hv z0wDw_2QJwmE2$r&-XL84r0$*C(W4LAnSrzyUhm%I?ZWk-7)XWgG0GmH6M2=1dP5nX zfmK?BSeNG1BLMev1ai*o!KvL9*g^qQI90RA4>!RK;9}pueSl^F99`JLJ7Gn7 ztRsVlm;i_pLckh5igw{lK^Ad98t~8**Z=@q1~{k;YXS;aN;%E}@(?91A8Y~tc_`?p z7x1H@7-A2A%%wXsa=^;Jj22Xj2&ewm4^+G-q)sCsYRDv4kO3C;<`+0Z)X9M^CMfu$Dv#Z|lTR{@xuOMo!NV;!kCfH(v_4`GWY zwa^_mt(P)Wfnzl!X0iv<#sURN8vrw(9qoexW^eh*VC8QB3Wz;no{Nyp6Gu#Gw0}Pc zIDoup{r~|f;ZKm0;Z&z0ze5RN@(Tx~%XuwAOiNvYl(;ChvHy`R0k0|oPC7G_unKK_ zfGDov%D!B73$$N?hj)HH)|4>#J{-?Tby!>rgn!OwJOz~K0m2m` z44^%N4Ji%abwnTLDxh3KXsX|Bz8s9rzyM&+yKKrr@7b~TBdH`5kl5?7LcM)P|V16(NATpm= zGI*AtgSTnm0%Ro^8^|jN^m}*EgjSP#6>MC4Qxu0Uji9D9tW-1CS;K}+QoROXC~_g+ z$_?goA2|XA{3pT?e$rLIA7!a53B*r$&>{_IybSDO@fn6-n+K!9&-Ck61Hd~0!z{tC zg@Qoy&+${Jv%=}vbQ~vu;gG3@9-uqRC4N-Y+Y6%bp)p!fOw^_%5zCu^l5(N#9>+0J zPap`4!tF;C)>95@fO9kuhhqoh0rU;Fv>S;8FaaBBq}GF91l|N71s^FGu=%WzY4iX= zEF%7D$Opu0t&iGL(unjA#YQls0Lqexn?1e)#8;-amjKk!Bmd1mLjxXg?(<_5Gt|=4 zJ`&KbQWyDpz}A5J$d)}nRq#tkR#rR!_9dzIA)fo4FpI^hpM4s@SVZHx9M9|mBDMW2 zE{o3ePXT^d7?zXoWjM9<1-`LUe-YxUH*XzOx(g?qtodN{_tMG1*r?&cPME?!_#U4I z@DK0>UD6Q&_6|`r%F-CvY&a0bm{$NYBN`y4k9KerWqf^uMmRN~KmNc7NTg_ZA=_<$ zojsrUy&6D@8eU8Vzz@qK*%CHekAkS`cp`alI;2k16#<&o@8!*d6N-s-@Z{>j^)-K8 z9+|e7ucHU7#l*jZgVXO9T$S--KFQU{eUb!XlcLXm`t}hz&_dYSz#gU)FdsiSjoDcH zvT*8SCu2HTTq{|b{5O~TkB7+5oUa+YCK1M+0I@zz=^C=A=XZ@dLLCGjEHjAf(2 zFCbK7R~Nt9X%oL#+0{LJ)!C0{m0nCuWwm<2Q|$T!Uvz6`Ek@TVe^^y5=%Xq0R*>xB}v* zai)3^YJlE+K|OGCgur63YDPw%NpZl9X>AK_>!;>?Yu;^STD$}+AclE7>c)-2j#eqU z9r>puKZ+l&j2+3mu-vyj!vxHPG;E@e;566a0jl)zadW8oAX2B8*mJISMwddkjt0fU zhZTz8KHJK$u#^$ozVRb}y*BR+r}_{WMhg#T%NXu`4=*Nu@0}@^qf#=kY}y&aH#gP_ zN?oL3l9?UI_#&d6)QGL!9@4Ia*N5s<4`_xa-a%xb*)w{9}|#J_>GJ%g#v=J1X^GuyQ^Xqv!-tjm5N{~n)(rn?QvXV6hRa>e{*1! z%kY1SZpapo_`Zy3&OCd5&a^wJJ^pt{Bgw`@9;%E_5 zJM`9W6qQ-BaEQNEpAG{aztqyL*5K?(Y6j$?k4;;ab>wB>amu8bH!n3%4L|UwY3n+L z%!k(Dkxn)5g~9aNJV<7X*VpvO-FqH0~e-u&-IP#-k_}4Jola@;? zK6K=4J)i`#pxG8$1q2IL?0^?&Vg65JVN@l28gje;Q4^P5+iDkhCbf=i9N3fztqEIS z1A5xP_xHC!acx=$Y496U`^l_TBr5P3W5?|YM(1WMGLli`>MQ>6apsmGL$}MeHFP$wJcHacKO;!fxN);cmV{e5W1zZ3?QVI@J^ZC zub@`y2QIug3&=t~aY2C$IVctX>5&_mnt=5HApj=uQs}hj%#nyKfRq3Z*JBxS#Y;1) z98PuiX5BM0s=qFI|J(T`A|@4EW+%)(MGb)xOxuA#gswRJ-p}HSn?JCT7&Kl1cB% zYg5!7sFYR(fHqLn<1zqc5ma4M;R-5AKX8!^0o*GRv~ocYaIiovVF5oHDXxDj38DYF zks%+kNDE6K0KCoZA)}Xw$Rz9m{H%l_!g1jYf%Eik<{2{%`?W>n>J&ApB*<@E32=PH z?#nO(wJ#wE=GD4pRMaA=)+MizV)+wJ*bN8n`a`rOyaotVej}!GJqA)8ODH=7Wk)6*EAfq5%h04H!DlGl!PfR8Dj^o_Y>}yj8DmMg`>&YeH2320g^k;~Fp!VyE~Z z*Ds9}q&hy?>x_wm!pEBdrey(fz~GEAdrE#kb{80#VCNUQ2b3R@8|_D|0e5fX~^ zWr^;=!-UZ0-a^2AiG*4PbXoyJp^8sh69ybg2+I~XAcIRUa6S-VB4efqOP zh06df)e9WWGVunr>9pv99UO#bHD@=q@gjsWoA|wDEj$}*g$>tuGw__Gxisbb5||r0 z1%ExLI`K5HL}6>o#9KJKvK<2>Q5K$kK8w@A>+qJ?;Pk=4*f4mUvxg6& z1!*{VK^OcPdj~#QBiQ(zrw3=0T0OPi^a*$e_t$1i0U^^T*imsN(#NEaB7s*rQR)L1E*EXGJYYN|P$~qqu zec$}?X`9<;Xk016Ay2u%b+*bujM}ewc*(?`JlVS~Y(gfk_GZscMNC~)G2AH(zxMl8 zWqC#Ul#+xacjk%q)^xoG=@0&nz2hLE)L7S`^p*2$ z(0ctgOKe^7=^ckuX8h6uM;1zm(&pyhb|_HUu@ z?SANmK}T%Yco(<5k)RaF@4fOz-pVLx!+-JLr>oxf5mhO#-R7*BC7owFKo2AR-%(bb z9oZJyzRG|Qf99%IMzO1^)fta*4BzW;N1v2aolP4o+gMauv>sPEwmHigZgat)-djHcw>z~=xg}>Ae*XymfS22fh&E$$ zUBcyk+TQ8Os&r68*ME=LydOIob@v6=!zgi=35_d{pTZ2RCyIDB1ye;{+lX*z)eQw5 zJsk;aEUY>?)k#asxNNpY26BXKrMpKpwo`S?W9v zq@;F4c-^z{oTgK=Wh!lk1qSPTlbqZh!bs}A^K8S1)^zLHyuh`18Oyy-*ws%zVvl%} zo2O#3ZTHePJ*uduS}fIkdOHDcoYSavzwp{-^&Yh!aMw0+PS$jotTw!2HpS-9LpuO(mGDM&?_3Zj5~!|$5p>9uNCOK0~XI0doSK3cE+c8s;s z+S=*vYS?!2bjlI26KM%kILMrGtt_iR5L$2Qy+E~iY!<2RUAhC_aWLb0NUZ$9@Z8W} zgxhE4iUyZ}`Jd*5NE?mB$BveNx;t$mxxCG{x|jT>O%%3XE9?-tOyv{bxK(OcImIq@ zJ2qA%R;?=@6Ej541ZpMJq4pdf#=g7#AA%5mk6FRM80jr>q~%lNM^IK@!N zeH-r4^W5k^2fCjAoSB203r7Pg%vUVt4FYX(o9%Vp;y-?@U>L{$-0#;(nQ~=z*dG7Z zH+15Eum43oMq|fPq}m6X$QFMfrR}tr-yJO%bg?Hzdtb(bVi6_Gt97dQo`P^UuUL}g zC9T{~iQ+dNAbPDff4l#|VO2!B+S6gFa2~mDCGxnRX#^8m-7}cD)j*CGt#|TWvKhvF zwd%-!&SltFiJH#$GhI_6#$qkPB-_1bCwXEI4g7j#0+=@^UG4v({>saH)V+V3Oi?Cq zt&H8xUSN2;SDC;6nU^J1&ajqs{Fd<5$3iRASDjPBQ&CJ^dTm08O1AJWy*}A$K8e0* z+s2PM&x)x90$xI@43R09*+z4^!9uKBPJD~|!qCLlzhxiaVbA$>zyst*1lE!$S2gaIrdx;UWmT> znL*G`q`d4Y*D|WE+&zShqTMTvB>TK|G;rh)wlH0LJr|TXy;Qfhnpn-!AlZ{sTG-U{ z$8XE-{E`U6o_hH|5m!!_d_5CJ^Bi(#ujLnAls)7w^ODb-9tA7o>I>k_(61`JZjoR` zQRg4-9kf#@rfs8fD_%zH(&-fY8Ftv{aW$`LlkS#%nxyf4?U*L_kRKm^+*rOpYJ1ES zK^6w&x7>G(rZ@1M_J?=~vqrgv1WbVNp= z-6!7cu$x@G&4CjspSFd=wN}Tg4+JDj1WZhXG@|Q!j}iw~ZAq87E5A&x>NtR_0?Dkz z)^5pn+jiph2;&1`!@~-T_FMwJuztRC{@~D2w&Mwz8b?c1E__@UNLHm}mz_}E*Kc}W zdB&Z~GJ3(Dt}c(s`NQ0<-6zQ<$xDBBIh;RW7Q-aPfspd~KcD4XZsf*3SL1u=9Q<@V zH|BlJ)2z_TkA?mT7;1IcFH4%p7khb_xGW^}x@@j+9~Qk?@R+dVcV6&VJF55JUd@he z#PtSB?XOQr>=lwrP(>TAMFZWA zlXOj4#26jaT$vJ^EJN{nR(cH46^{`>By_p$*iLygL!B6_xE zU8dYx;%2?(D$3kia(-N!luK_m&&J{MiGQRa;acsFg%1?|g757;#200INw$t`-$H15 zJ$7T$AwIEO@4s_8R&gma#z^}0O)6EJ{x{2R^6eb`Lf6&K&}+Ab$oz14{Dmj9eR`aKnC z=%g0&zDh@HD<)0t$Bgtvt7l=Gmu_$$Ep#o>3~K3#OEmS%EbJox46t5Upm7bB`pNy5 zW%t4dy4HTB%5cIE$GKkaLlgU`rC6r6Ycsvvx>`gi$CTq2j~ut#pWOtV*|o}EJQbC= zESJw!-L67Y^=y7S1Fbx*w?T{ikO7vg|}%(jMygF=DJOgv3y$(B&u8Y5a|#VFxw znsjg@(X&&<3c_OH7StaeN^k_rvuR6CvD5%zZ$=~idv?*IQ0iufL%=V zmVJ9PqSE}YZPtJ3y|%5q zxqG;2`2wx+yoXOMm|)n?ZuT}EQE3d%GeUn$(^vP!ICJ(;cpMKzg~u|kzG`4ZH5pI+ zE~?nxH!wB3&8q2`w4(i#9LaD}>Ir_m;UfQ^SNw$uYha&wWm4Pp^LVSG=IBYzxD~^~ z^1J4`@4r4oo>slYJwGYDu463Z{M!KMB&5Sy#YopL!z0{MeDImOtnpad(E=BJvb9RYCNsuoU$)13>HhTs8t}}HPm>$hs2Y7 z=TOT*yo7_McDRwPx8eV+G1=pMurA@?QNUQ7Jp@HR%unF*;Z*;`2Xcgq0+Ei_-zLA?yL?c-C&xYuLw; z%ffzd_MG8LB>T5ZK*WJrk^M@FqSV6!WA*D>^xm{`A=y8*q17BnZ2=a!i#6H*o(K&^ zc!yrNqNOLNmls0+_U$9bm%y7P8&$(AwJLKl!_^Vxi-Jq!$84aB>5#SeW8*F_+)#4a zaW?7&rY4ECdeWlY{do@c7Ig!3E=oriGQmE2Pm7M5ien#|By@hdD*3I-=8Y}9idgI2 zVle&F?yuPHjpIuJ7Zm8=A*idG)(3asd3be$WE9jMtaLNe?{&(sxMUsgNg4jvVCE(N z=;49v^zIhv01e32$eix44E?zidfp9h;VV`>T93Y&)-r_)Wq911zfn2jXYi6?hPHBA zFl>N!LkF7|Z0HNI71s!i=*_E5;@)&tQT&eXDaJ6YSlPZ^5Cxwg8st$JcBwtYv_ z{v|hT`&ffB@-{RLpu;uOo<%VkZ@rzKV{C+p+B(3;M-}6nk;}U&@*i?M@>xaqlN9J) ztL&b9aalbZjU@~Au)`Gmn3<7-c?z-um9LGxY_q$ezYRW|5uHUph0EqHSu>ecj1G-~>o+&KTyHUmc5bsQ_Um;HOmN-wNK0Prn)M6Vu6XEYTG=_Z zqyEz1L={<(G+q-pA;R#t|IPu| ztwuYe@*<$SY<^PWDqqyX7g+xJma56l3>{!^_qw5;n$+n<-gw^PI1MOD9t4!b;^6i_53N z|2>4)YDW^w3#^-UKd{O(eQHr8{tMZFie>V=&!&s1oIh<8g zZQSfLhwKpDrs7+I=J3lEARlt$Cfl^QY~!XY&K$`!vHrKhGP@;+^KL?d{Z;k{>Y~>l zuIZ0H=;J%b9DM#K?VEE|KOohkdWVSz8%BxSY)R zlKy_^l~PExAZ_lGYR4yE8HZIe@?R#~dR(T>-G|1q)4clHPxGK#tcgoeo?|JU9re%p zT1>ORgMD@10pEkP#gJD&z8*TzF@(}}g#3N>{zBsv%6UcIpyX@kLvx?93f;(h#&|Cw}0<6w) z+U}iWF6p9ubWg=5@_fSm!kl~G6wuMMEEfz@u8N<_pwSBEf5st>bO?RwL95J>d+~Fk zQj%h>xMDaz-SZcvTg(WR7lqC&jG0Q)S38TKs)hMakwc&@*33}Bj<0`TzQ5m?c){rG z8u(6QgLVC}{r<1eb$!LjWWT87!Sd3hfy?71398}ZkEr&EuK9yrLki5Qw0t37eyYE@ zw_*oZxz1?|XW{3|1HUjx{xa^QqjddMPR*6hlBYLSZPe4jZq81lhM7UDKsP`ywMg@X z-eks9C6|--JG*^hy^!jB7>JX#4pC+St+hJ2`EL%;#^_v?(YyB51@@vY2kW{M&!TVS z_WUC|JCEfP>~7UDnhf0#E)tEu68b&#mQ#;w5SU9e;yTm2NS3Egl1+Wb4R3=c>z(YQ zrvo+gza{lE>DdW>LF?K4%|0LSN$^Iz%D^pQpM8&+Z)hjlq7$?Gs~)~xR#sro*l%@x zH$RnU$Nus)_+G7M!c@+8hmGc|Q50@yTx(;rYoD=~pYPV7sxd*_z}A4Lvx}W~)nn<= zobS8NI>Gvhs4j&@7aeH_#E5pe7qHnHDbRYPNg*+t(N(ufL%CAo%J zdP}r`*J%09{|I^W?8)ux?3WlX(9?yU>j-}1uJk00Ny8xd&3G1*;8d*Y?KCHb`mX|a z)1CsPBH>WQ2RZKlDNmU~J}oJ_+?Gn<{>AdIx50gR>c!9GX><25+vTMw_;X8K)7uZ1_YYmZ-cazd7yL?zht8NSGV{;hcb_v4#;gYtVjzZHM-{AGR5 z&`39TZimJvSWd#EB5}f$W|39cC?o%UvC`nH`bAdFVngC>lZsQc`^tUuPsEYXGFJSA5TpG_1t1UzA!EnG9uRmLDSHRY}CvxJm z4pABA*D|-0MdgP2;!66;RlwL%;4@O9rt{^uwfXC9DW%KLQqxuvZ{`~@3MNyo2UExLlbn zxxk_&DcvOTT6Uwl=tYo%Q?Tbfe?KJMKNr1uS*;m|11Gm1zRiA&u?C~}oH;u3j|?vh zMZM9Zk49|I*tnn!rCwis&(e6ojIQF`RPd%#mseJG?hKU9%#NlasdE0BnLk|Ur^H`b z&c-;5D}Cez?h3i5>f$nDru&a#Z+~?uHtGSt>o5CyXGWF8^Hk)E?}k+13pZkWRy@sx zpEPf1p3q#UiNVnHhTRVk{li5QHr5U}G#6+!2PO^+&po-m%^e&wXeOs|!R~(8rF+Te zh{Ef&(yHq;o;0#FJi)Bb7;@=G&#lv}(hj=vsCzuFGHbAV#!$n9e4V1s@RF{GPMrzL zcJ(DW?J6Ub<`E5NFw?X1)Z9=@f$I#9=x=alfjDz%O;}GOnI6^Mx_v{}#&&)E-A|{a zuv-asv5L=fc=opv?211NbABb+=sOwZ@O-$~N^e0c5|a8;K zPAxqP{XDz#CtldM`jQ8mvWy9H2PUcCD}F(LXY|XpWHi_^C8fvl8z)U2_;y#OL-08* z$~jiAQZwHVK_xtHUOo7dAaU@1dPA$)=I|ZE>zYE_=zCF1pL>HEM?_1d6DRj?eH}Or zeJRUd63(xfl>1`z9!o~D{i2!Ul|=LtMdv3H7l&VFa;YxP7t#@_Z zm-1Dh5lE<&yfIuIDk17}<*f%^L*_!{or{ADj}ogAK8D{D`q3teJ?fQAsxmAuuQaYU zD}YrRH?-wB3cWW3R;;(yIiesS{O5Bc(b zP`1$LrBI27R$7ldYi>trfQ<)iu5u;*NGK0~Ck$EF|J~R8&05v8>dNbj<@AQMf;I_X zlQYMzrJJRVNv4&5yvDDkXZW%<{9?M9?||m7e~5v1{9IRR=b~?mGDjM#59!ZcF4&1o zk=L*OP4`^zN*SU)QQ_UL^6{Nh_8>;cN6>#f>k%U>V<{Ja>rS?VK{gL?$CWG9`!biy zwuk(Us=!ZcH6N(hroglKm$XF)=C;>LRO!&c|2>nqS;FsH(o6TmT`ZIxT5uJ8{DJ;X z$pt7!07CIy3dlh<<}dz$|QEV3k95fE$KCFCQZ&v-K6-@T>+auq{rFAt zg&11Za|PmWu0CP9em-X3PUMn)Q?Optn`EZ8C+aKu@j3441855uB^NIDmW0{DYmgHe zPK&;}miGdU9CH_U=zW-W>smfsl)Rt<+EJBK~EcDN2W2`AB!2FM5PDO_&M{{YoUCY;0iER?}R=d+lQM zN0rXIZ@*Nje-(ZTv=bo{Z@%29`t^^;)7khN&`tn^p>&lZQP9=9KSOVw>&2x2?Sz^F z)7Qw@Kqtw-U&jq0AAxovJ$gD@PyhJq2D_eJZ6dnX#vXn@^uqK1wG&!_Ks#|^(kZI= z|F;tw@2p%rS$69fH2>F5^qc)(I}xvO)=rSewQi1e?N<%(^QjIQnh`vWZD)C{CfRFO z={N-Aj={DpLKm*lMThkKwDSFB#ryhSbY9*Y(Mv4n0oQ&?4|~I^+J(*FMu~MJ8oXc_ z$LE!%snJ(bG+(@*aHp{hU9hFA4Vn4r^hWXtH$0uC=wSS+M5cK0!GM<_#}NPQnD% zxZn5i&-D1C_;#ilZl|L;mB{X;Vqd8uE+qxN{Tp9U)77>58wxqMG1(}_?XV+7Qf}a= zf<35??N4#=(YC&|k$WX`?onQ~h5?iWwci@3Kk7L8J>c-%Iu&`drS-#5Zs#=pae9Ae zOl{|(^^;+i@bVc_w$9%#{xf&eP3JzoZkFIP{FV4z?LyHWwp^;vGeH<0&GY;u*;h+{ z<==C@?QzmC)9Nd{Z_{cl?p_kpDHqwY-kcD<3{GJC#qf`A|J=#b_<#Ye=eTOZGX>4( zAew*58t|eA`!>~uIye4xJwIgZ88UfLlmmQrF7+JV(*#epp@X1T^#UV#L>|ie;br_r zF1g||U3_H!NdLLFSi*5DQ|P_sp^|1~EJNSt^HxV8<2K01SsvvPlWbJBd$Cp7|6}Vb z9zwcHxX@0Qxde*bnKI~B>eyU>BKUST#Hl}T{Ugo7#q|+R>Y<(LbQB#7{T#HGcs4Uda zWfa)Yk{Ah8*XjYBrN*ofL7%e+F+p9dr2>k}3Akq*XY)SZGRjx3n|=e~uKc*%)MP(d zj=Zha8F7NG9B|gYmgfFF9d$q2_Z7p&kDo~+3zljDN{S6E0Zs|d6*Bd+zpraLW4LPC zXNA@rPvu0}W@QYvbM-6f^;2Ca>V36iaRwpQ$j#x)+u_TB!qGesIyqNf5IL|kYTB$4 z)ZGUggdii35s+M$?9t6}=O9gtXE1c2)tgQ@YaH9i^0sEhkr*F3>^`_a(ImLp>lR${JE zDPS@-o|+yuc6cieKNv51HYLL_#a;WcUef+PU!)-6R(T}XTjWT-W|{w43$kl?hP!5} zwbEjc?W{>7R*vs&nRbPwAse;8x$`FLDbbAzvQ&7H|I4C`yc|+;-|U>n*}oz)*)()Q zRa==c$$f*ybViD6&nAlne%h{%6#KXeSW%hfojjCJ1i~1jUEM8IHcJR{dk^9qs}XED zd*hRE{sV~WQ`_j7r>_iMjmdsSA}L_Ml!4A2%)TsZo3F}4Zn;(Ga->^+f&5w!MH=-V-NFWvK>Kl|D_%|p3A^!nLa z;`7zIA%REIscqIH^9sd^oQc@DDF3UHrN+f@(R9bcL&UoYfo05h$n+n^Q%=gH6UlW) zf8jvcqw}g=pt^(P2qa~2IY<}89tM@h{BDE^n5kjw`a&fOdoS=0iXezd?CddQ=$?l#Fyd;LgX2L8VGKChC~Uf+SANo| zy4u@Y&3R!A(mJOl=mcJ&k@TnxU-?gD$n$?;!e^S(>pA1ebYrQYauL?je8prGP~>>< zP#BQItI4v%RrU1w^s~b;<4cmQs}S^A%tO*+`Hf!~FP-9{FH;ni#;8u^kV8RIVYCzg zYAE@2vDS;Xi6*-{-A};wOS>eh%*KHODdtAZ_K_Qf3^uj(9=;qYJ~AiA^>6)+6EacW zYzPE7BD@dAOGbu`4S}5FMI7tmA+B8|!1lZsAg6f#Y)lF16?@*|toOQmt61hE)pDBD z-Umo=Pwn0f^H38>$h|GL(B`Qko#%`>s92Yu0xG}De)%b|HV^EDQ+$n4?!;5C;eNb> zsJKD`y;sKS1>oQ-s+nej5I6548&sEf`;lc}0zU^2Vx554Zn=4LOFGyA4aVVc)tl}E zg*G*pgBl}4qeVGc`Vxe;G8+?=kb(^(X-ymub}2hTm|#KImZpRUzsX}FWo3O>N}R^Q znVV+Pvd9EM!`~MG2r-<8Nfe(X>?Y(lcJo>$1Aq{uiOc3zy32XhbUF@YnG22f#$`LH zkcht!0w)Q85J*d|&uagH5MqwjN4_|JDvIFMoDCJ56;nZWkaohngA%;i zr!=x4V^-Skps%P_9^kgu*qT&m++!osi=LhgRP>7YjIjiR=+-EFa59-hIz<^$M)j>q zb`C`+&8^Hsp+~Vg9c5G>iQ;s~ftThp$><-=Esd0;aXuoNMsY;?hm)$LN+v}C(p4Od z$rQ|DjCz&(NEYHJ>7xF-u<7*G=A0a>s=*ILkC|T_(Yru%0^ffu>y+J{>N;y{%PUy# zL)!06fsNELcQr>5QRY$6I_qiGil1=XdNi&0kTN3@@JM+pU&_+3pDCv*9Xz&8B)OGL z>nl*gbcht_C;yV@sVK~tPcXTsE;m0QS(wQK3eF7 zU|UdMet1UnNYuFP`w#4Pcg>Bv(XxgXk>?oV-WH}z#|e2T8n5kTuuP)&M?wTG3Mene zhh_cg>O#hPSXg|XRivIAJm0RTBT6|nTG1f5$8=IxqF{WNrAR%4M)%LpSQSp@qm?+O zKpS`@5lb+G2BuSN<9CiHEW?~Zqh1?B_m)R@g~(Z6&dXZ*IiT0E79TXzyuM1WjIC6! zi&Yt&t9?HwkkI?-@y5w%n^T8MsR?UmN!qyRT#m8sR*J9CY?V?3u zJGc{ubL`xXFa1Tow$FWdQ!;wR_t-*>Rbnx1Y%1osA{ns82ZXIB)SA9x7t?6tZeV$0 z6jSMinOpA0;Jy5bgCT}MByr?R?`d#O-sj(BBG?Wwtph7xjy(N^gFW*lk|U?bYWr3M zHjhS^+&`|o)gsBKo-B-S9sd59Av)sth?<-)-)xAREi;-(E#Ob>SDKdMWz{UVvMvIr zPUQg{UXlvo%kom=dB=(`{Rx{2rwoAvJ?IwDd@iCug6PlzU@7QOfnAF)Cz{l1F90;_ z;WHsip09(4NW~bLR*N8-#~cUQg9O6Jd$BDcyvW($adZlMOByi^opEI!nm1;T--85N zsK=jVq6?@ZN0X1>U$(!39*F<2!iB7%kz#QXIVaFyEUwX?@4N zz2&%$Vg_f2XnRxT?LBoDY0R`oslIXLYJYT$y_T=fr{1JLDzTd8btHpfQ$TPcqGbkt z6TWeurZla~|{LT{uRZ$`13y=i87;}pX*%}gG;>P7E6k|BT_IVG?|Qpc5<`+bmB zi1_XG6MZ*9(fH^tBqbx8a0%-L5##yL61SYBA2qq<&E=UDI~KmPW!dvKJKnLJNrvuJ zA*k<=o`yH}8tI=A%RNC1x`98zEM4Wt}wCxwtw%y*~5r*W54}BERZH`I?b+s1hmUn`n`w<+r z|GH6ka{38^U0IoLk89}|)i90xFVO*F0TJoLtoQq57DkA0S%$7FOz;F6O9O^U4H&2vW zhzKA`V+cm#SG@8H7^-R3z0xYhOxlEO7#S$4NX+4BEsI(38*c41hK!7W=j>$lgmp6< zBdfBDnWZMCWE&au>Z*+HoDSLLHku}Egiwrl6ooNP1zmT|66OWSza(Ca7bN7-RJ&L zA|VDrK*(WWfPsV}k>O>IOl(Sm5_LgaTYb+T_{USQ;zUp>Z|Bsvh@bqpyvKQo=vD@p z<9zjs#>C4YSC9~hG7P5|Vu{=YUIzIfq2}Y9xogs0xZQ+2+vjQq&({5Vgu|{$m3|08 z<($A=1-XR@J?OkJog(-J@a2FEy;U|{wz!S{doHvX=e80j_Koa1@z(}8w#E>9B3!3G zx4e_{FG+;r@*ihZZeG&Lyt$YWP{2)wpYDNdjfja7=i0VHHOuQia7j;&^XOBzWZ@;s zW-rQC>5B6ph>42xh!|CObee_QRl-bj@nc>Nk4FmEjeoErx3r(ip``r2z)~h+*tGju zL)afX^$EcIR!1pw%R8fDkd>WyrK>7B18hZ&NppzCKd>F0F_NGk-71n-mMlPlY)dFb zQ3$6$8*HWi39^*Q`|QOB`b2z1DRjotb|l*RArGa8)(0D=OB{}_tIz__`jB}601c0X zWpj1is*GwZ9inuO`X4VpB)#Jm|9D#`^L&EEUlk`1z#1(JuA={TKYm(U%ljq`wkZky z#Ttpz6v5>cy`qF?Al;yf8%ges3=9db6be`VuU)Qrep>o=9n19Zuz%PEF`ExDOUCga z`-9(vnfE@j%z`iP$Vk5V4leEdBS02ORId0EUOW3`|PL8GZHyNA(u^aigj^w zsll=9a@#a_I%lQq*hP9s=jH2imNdM0*=Xa)yWsP%pkDFzbG+xVL5_2?(4n3lm$`mr z(Zq7OJVVG@TaW9wXa6$vB4;!^F{1xsi}`_?xIKTMCRm*`+T8;ZRbG9_eam6XSITHQ z8|b%~rz<)_(l>-#`T#02yq}b&GVBAO!V)b7p_226fIqGz%W2l4`L6Ai4M$)$jXGW> z+T2H_IX!odz?8Q!`&Jw`pllk73z&k&l!IPhnaorp&a-gbym>vWy!isF^g`b1;njv! zttbX0p5{sB3i-xGg{iKUM}7Mb=12N{6!Ip^FI3NK;zo+lGi-E zP#-6>0Q_F_oxf@5@$;6=rPD+GU!tM!3G66*-=A!<&26u`g6m+P^t=1aiLVi;O@{Gy zloNr<8}bMCO$012F+e^Nx3p9cT;!PWfnF)1hTcVeAi(0jo{kphI3~&5M}k zzW5ZJ$@YOZk7xlDS$jR)3vXIfSy{Ydv}xo$@CE1@NFt0z8ZV7TV4Q3Bsf4nReY07B zmnF3HsS^F2Iv&Dc&&RV^%JJ7r1N8rOM^LBx8s~D5so{yZBI7I<^rFRfGI~(zvj#ix z9^%^`ozjI#85yD~MqYyH0Cg}gUXP5T3`ImG?in2`f@lO|8^s$*Bs^bQ)0uhi7Lh;w zt(09=Gid1>T!%kMQdP0={zK{Y^6+~6m}uPm9$QY|&9M5A zjqnIxf$}{14eX4Un06I3X_+=-vwR+W*jUl118}RprZnUN;RO|FsX=0_9w{G^^0EfV& z6nTC$Ci4C~Qo{TEsJ4wv28c>(uF3iB6fEiYh``(vPwIx|RJTuNs z3325RfiI|W9?BsRe$1^6u}|yNhPTJ0AJLH_uttaj(7@Zef!=m0Z_&K1ymvr!q`9vF zjS}a?ZhfcC7qM;Ga}uP_P>c|P&dI_o5ut_#jX|F}%ZVTPo{2QFTSxT_Fx(O^^dw}D z4?pbVfNfC6yL{Wu(mo6yAQ&1-N900oW{mZ{BjU2~l%b<$fn z>b>e90_ZYr88f}yTg}QjWw+X)kJc7)H53GkY6n9ed2FbwXEzWuUS&@s+FJ?8`JULM zv_XxPWNE568=;@eD)Szd#_Xh4YAAvVxCc)5N5-#YQ7-6<@g^6Oh5GrQqF#irO1l*c zX;W5lpX?6C%&@F_|a0_0n#;vyz(3%(`)yvs#*@P ziUl!%2*S{%QRw1-9#R4U2_GEGTS5`WHj|*&MT+%z<(4=WUmQb^uo8M{cgkdj(SY(- zy7Kkj@w$Zb)~__QQx{=A3V;I6k{=^Q4H*GRN@QEF0zr26X6$^cgA@L=!6OtG%%8rW z71tteeI|vtkNugh^MCIvC&O6km_>4!shs_aqB2f(WBfA>sOLATsmsk4uX6V{Z`M$`X_isJAH!7VXT+&e*GzVQ<@C9bD`1~Hz@G+9Kte~l81+lmXU?;iw zNd}C$W!6_pJ_+GC_8oM2l@uVCUT@)^mZ|xyt}&ws&s2tbzw6U?P*;iJYfU|WQ7cok zf~E!`wJj)2WlcV?@vTARHA4^Sm$%ZF!umWuW!?Q>-cI}MiCj=U!F6 z{td)z5k6~H;#E)F31*&?24VgKYDt^0mQjz80F2w4=-reM$)mZ0O9HHv${is&6^^nyRg7V!{hBLgYhUzSuZWN2hq@Bl5&cDO&zi!`NA?Jkzn$zS*LR#@;vB4;V2 z;N!}+iVOn$MQ*j7%RG8--Uu-EnQn5Qk_2M)pngK~2!HMUX(l~H^9poEBKi!b5QIf7 zv04A?U@!HRaaN@pkEwZTwXhsfk-y;F^aYPVxON(EXms zc2UH38R=cDkDK%ctUvCJ;x;iooyatY4uR8tdluMChLn?+7SwKy){gLOSJ>R!8I#sw zEutR6{eq0Myw7=pk0k1_&Uw&!yQjy1BgNdQ!+VGt>oai2a2LWN`^SZB>&&a93t50x zfM9eu1p%}|P*FN>QEkOIUoxJP4?rsj#k7f(Pk<%1rdtP-3f(Fv>WxjFwpw>7{;_Cv z50;zDjqrD0ZVLUG9FJ?S%^A_~|It1;LSdK`s7Vln;=kGla>4&c`@rk$t?2iuzswFl z5mV71Qio`df{d8Y-*P@|Xqo=yB%pn$z@j0pa1j6XmWk(i*t=EJw7TssXeCT<22N4W zE9!|aj827ui-fkrjuu3x;;x8*M`V1ZqfMbhMGKFBPsuoIBBBY(C23{i1G__zuVeZ7>BFonkNn%((rv6W)LVFn%saZL2p)xPm#pqk{7|%8UHNxs4TorQS#UvL3={v67P(C7 zqmONkO)1A}!xt0MJjJBbSbL}!W4O=QA3qn+J>`Aw!#jg@Y>`{K_tO3isqX0+*;@oW zYXvH9I}a!+6{-0T5ISh%iNoVn!Ji(bP>Ehb=P*kiJQl5JgDBQWeBs&B>U8$W_;X$2 zqSs-6C!zHA4Pw^_nXGGa-v?NcyIB77>;YC(;IjMmmd@)P#Q!SPMdN{!_C4@~rN1s1 z@DxTTl(hm=buG5HQVRj1QgXi7 zU+n}E6*zgDHJMFdDE!(XcP= zR(7&TWr?*mUlo}?Hb*8gv7URf6HwU2TP5#molz!VI)CZd}kkOi^a02%xYiZLb- zGF4b8DsK;hQ=z2V3;FB8WxmpWl9G$G|*y^*dEjMmt#1X`Hy38v<5haN5UJCPzf#oQS!rox~lqXwb%>s zGA!fwMTd2vB*j;R;t54g^zB;uG>I&mg|6kt7~fi>^SI*51zPzub@jB12s*qTz_%ER zIqly?a`ZXQi^Qc*i+9x3arWu2MpxC1Ws=7zMbUw?$z;%};xoq*%8$M;ja2ypQ&3=^ zQ2FA$aUAufF_iiq6L^KbNgxHkMwl(U;P3B*iH{mP<`H}5A_}JC7{TB9RRt=YUftG; z9ecCLBCT&Bt#7>(m-kf)5LV)90K!TyOF&q;9`s}tN9&{*?z^W%QMs6Aw$dN>QUjN_ zz4?^^jR!Nr9RYD%m9jjJu(+ZgnOb#+glb$BP&6?f5nQ1M zM@sYqHI(zp)+50_=A{A9Dr4>@OyQXCd+sK09pM1S3`$lXi!jfafU!X46(Z+iMR-YF zDsU0-Tg2CRN`@=V*1dGLyxw}C9D=xQt6wqtE&fY6WRiXOhjNhfnSGVYa|lol*u*I} zCMHh^q!PS3SJFqSQkZp>4&V?tiVU1i20=H1qJ}2m*Jtxx2BB<@4w5PTt)rJg_dK&Z z>`LiK8W(4m_pb4tD2G?`A zhn*qAcW#vR$s=0|G(6*MNu!(wurfu?6jDH?KKoa(u4B=h`gBgWSCNbj_d&SMO<66X z!VHP$l++eqa-Dy-a*Iz~i|#v3%MXr?NA(AZ!7PCr%9p`MApgL(Pk>xb<*2tVFt>C$ zb+<0C>m;=gq5mFN<&xZ=ZU~kVB9EsU&z^{)SlS2Zu6fgX_zB;$p!F)lU73LXS|SP# z{XHzL#|1q+b-OEdG|+A<*=>_~z#5@HnuzBA!5V_}hzeeR<#Hv=^2=@nQXIX%iC{}? zN|O38Y`&Lolgtxa7((@tEt&l>PW$jDg1B=*wrcI zTF+soajVMDeE~59$R_XR8z6?b7mdT}UR|b&z)772y14AmmG|XTpB8dB#hI!+Pn}hI zL24@V{GVM3`9 z{f*SWy0-@nobCV{Ug_uro3UkvF4@kOPE#+NrT!_O>O|02Ud+XBWtOSP=#naVTDplu z`bOI2+A{c<=%|rMvfz?1ZD}?-D88yBzG??6A#zDumNsuH89Fl_Iy3%0TssTbAPXvo zxnP&2sH9K-uhBr-f{sUoMg^wnBJ@8b0Nj#D9!}0zb$NosG z=urWz3Ibzb++lU+%+l7v_u7;A#Sv_-sIq{G5k)72)=W%Vp$7IAgm;c54;)EZ?g$k?LIcJb=?v=;E==O323N$OoR3;Tr!e(<(?!LQ=;dXpT=o z7*M4{ypg-Y*P--}cPi1ZmxB?MmFRdtHPEb~m$5$U>Y5-%@{aK_tb;yOC-p`llChgq zMwp?WfFK!Nb%LTIv(v%he8gCPLAySC2oOj-;|$Z5`P+Fw7d#;$jI3cR5zSIsV))yd znBb9}@LRHm`+#L9iZX`m1V5VN1gBxv#RsDUolGkf1HV9A8yJ~L;xvaNaU13n)OxsK zMY#b@bb20N$23Pp+t{#;Yl*>h&8ExCT!9s<#QG`VA^@{me&HwzMT5IVBi$5i?F{4c zVns5nMAQ#RHsQ^^#+F>XBxGtdWLUd=b5KE&aT^G*tPD?e%qK~s>f?9MRC(UQsbF3? zle&$b3!VtGmlh}{pH_EAa|s91<4SU%I)Fu7k-nH!|J458vMF;af@-dkTwa3VU}oc0 zWR((`83oZK>Ce#qpn!QsGF)u5Xyk$LFTI|Y!o2xfrWKwIcESY=6=TIgha$V)3huRSe{p?sd^5e$+V{TiHgxCh@Xxr6+DrQ$7HW+PYS5LX)_s`OjWR9*Hdr znM;$w<2fJNbQ+<9Xvsn7BZ4?1oF}bf`{v^D3ZtN9{kEv&KN8tgF9a3I#;R zp`My;KT9?me;Uug=Z3bmbd?~8W4;3B4K6!Qk%1HO49z6L_ZB0B zhDr@BKMvN{9VJOx|6w*aDA*v2(yC)b9^tZco(2eJxW6X zf`TwXs9{LbFOjA@qkM3R0rmo<(4qtaL6Zt|OF;*%ws^2-ckMF*(=s2QIm>+P7I0kA z^SU&qwESsqF!-LOa=iTHU;*inyxj_rTR!evm0V}KZJIO7)&G@SG8ULlKgcatcfJiMnkqGP0CG!rqs0fgrQ{ZgQBiYk z+`>O{%R@I0;^t4Wmx^_d-ytu*{0 z_!TzD(Q5tjE3_g$-k|KIFisoN6DMiTV&Z8`N8&+wnquPUJ>>c@!=MC1XHA88`n!0% znJK|1cAgfB*tl2Rt<#O=y^-`0fI^L;3UwaI8T_wWZBrM^UTz**kqL8<8~1yG4?LWu zpNHpL?5TH)>Ot%BEzofy6(gpl9qC~Bxpcb*(vEO07=SP$Arrj!(A*xE=sxsELq0*R z+%RwPdckaTrxxXOgOenjfS?HzOs1rn2R(9neULCa{*RZ43=@rXT&PqAqdXPks(oOZP-gok( z?a^+(F7Ws`OprB(pBBT!XE~-IkknLB%Rh{{%B7>Kf^G86QOqIL59o-9LTmo4tkF?$ z$sFH;h$AixEf;wreAipeXH3KIr1`p7MBR@Dlq*-3U&%I6vBE|gz!jq8oe9WO>2mj7%tY_)?PJLz-9JkOO?YY+aNCE_M&vl6Um@< zX);{2{ik`$QDbCaxX?&I0}4fb4}aR%DD!0r>IdE2$0(f4b3=Vbu$74xh$MbaC{83y z);mY~Hr5NvUT}?IePz;iczsxup<+fDUsB7-70bd~gH!Xvc_#i=hVoXc9cikC>Ha~W z5Z}Uw+^hPYW6cgKLX|RNcXU7+@Q+epC}VH{*IU4vNVPO0?Iv)L1rQDphA^uH-M7Iq z%FW%Zv{PaFOjLRVtkIFcB{XpcL~{JXDJ1Tn&0l|i=B%f%bBb$$IWfR3?*7FKE5$T$ zy?=|u;@|1_B9$yptj1055FrX`PpqOH(?H<<5|1yy{UuRT1~pVCcN+n}nX5IV(hqq~ z>Uo9MZ?`6C1MWM|hYQ|Y2i%XTzfKf;v3|?=3;XG(tx2hYr=M&zNndhHx1S2w=Fops zf6FBRLSTi(kLeb^5Pl6|QV0WlaR1rj${+IBb=hk)>?+1?sTMbB{Gy8?)`p*q-^L;m zxomB#GgDD-y*_GH-<_4&*z5hP-5z~>rsHlu=UbM4mKVa?TK!@K%}weF?+7bMN0YAD zU+6d85W5e%=7_O34?L0CmaDp`8D-0d{OP~EN6R#>cpa~rj(48%)0UI$_&DpVVeB?!dv8C3bESp52o8As-bw?{dqHa2CegS!cFWY2~?*R4bwNOhL7LMqR z0go~|#8C-6YVZ?JT4NvcVv|9zk)y!_RinJ21w)kBM7GhRR`YpyMQw z!;}dtAumMbwf$2}lm2fb>@bUhyf+U*%h-|!O@zF+b789T9zak8f>U~BO^6AMvtQ$q z>U{pMM#+#o{G=^HqbXWIdmozEAN3)owthaF%To{WnO3`+(hZj-h#~yB zDHofvPUa?OpT;~{l{W?j*v)c)*Pd7J`HFN3B;)2H4=RvM9z>TjYDVzm^SFKv+D!R& z!>=Ce--KRwl7mjEIqFb~D8&*TMhDwcU1o>;W5)k?vbz%Y{d z-=M*(;cb${EyHP@Th1{R57A23wn=A|(_36_D3|$S{p}}h(J*F=Q*BopO=Xwz>vvSb z@z38XtE>NU4*4AQ#zwzui?5rY(kN!nl*In>Bq>E{_-9qax=0f(J26ml)+JXJ=##z%GGfqJ(`TM=B$`r)GA7sprDE8hh}ym z&;EX7(9}xq(Sab}cd)&HD_Rz6y80&*u5QgMlYP+{ztTe{0=y-98r1{Q<3FwQ!#`X8&{BST{667%Q4Q^tjn7Hw#7qOYx@skScLAl0 zmm(2T*5}BZJDejYy+$e|d=#X9s2mMQ77XTmrk_2qS+{VscX}{X?}@e!4(O%!jG5n% z8LzPcCUglyn@A_TXPZbST%&~a+zARh@ngVgqSo52sq}HZqJx-I$B*$E%{;!A#%>>@0TNgdrL=gsShUsmC!_xPjcQf@Y zzsh43<~!5h0c$e#V4|`ST0H%r9!Ri^`CZmBp_e4QUN_2%`jJn(Z?`?IQ?1jFkKa>% z(i+$jn8=f)DgdEJpXB#Xfw5>VhJ+DolNRA?LRM9C=B)1fn>%i@@7@j5?;pFD?kIf3 z>igj^n5ojq2=;myRVcg|+W4k|9GG9iTkJT=?&14`+GkyMp~I!Wm~JGSg{pf3a0XEBY(tZj&2+x z;JvbRw(ONhRRq;(aWXAxfEEH&)+T?Zs$Z^TlJWRBOkYF}d=QIARX{?LozfxP?9YYgAgT zic8)6Yfx)&=Vc_N3jfbKrcvdzRHlz)>`PzvHTzUrzD;;M{qyVUJm|bFC`5)`M>T`6 zLY`e`%!L#9l4nj{t@ao}MoaKPgBJUi)D|1Fsz{!0VUtfh%w*E3Wx&t(;?W)UPRtUO zmd-mTk(xhmcjeB_7LPLhbI0Pmol1;DrY z5jS`4m542l0CKTGnu#1fIto&_G#x%05sIo`fH-=F0Me}#2OU161l@EOqr}q2JSx`c zBxSOk{PF#)@l2nP1kuXj|xXmV+FeDiWMuMl1C0-;` zt4&6-!0WP~*y8tAR-0ru_{bjb+;y9RC~pMynl`N6@Rvjw4$X32c&yvvFX>AMMT+{qdP5pS^MA(*WJc^*iWqA~?J&8CRQq!`Q6&r50Q2TdfxwC{7?}fJyVx8RKIs#& zlPr;PzqeGGOI-wi%BNd}3X<19wJB-Q`hQ)BP z5$ZCPD`z9?Z9LLjQ2?yhsT}2))v`5+e*%;GtS=A2ly*&adG%O&O@+$x@+h669VG|7lff9AtaLXWNemE1z1!t4C{oNkNMa~jJlf&fc%-l3fWc$uAj z(aTJ7Zhu{Eq!zehedlAl#gE}s#v{fwULkPe?Bu3+ie`BP2nrOt2O z3U+zR6hB$3QV=d$j9Z0#5GJ})su?M|EAkBEAXc^@GQ|QeTC90rCCAOJFi4=S#u%De zDs=S6==)%NH<_nru0t&H*Dzr^+`mB|7!l>d>Ti!Qyztp@^%7I*a8YgNs)}F2p+(X4 zd#P2>MvGtARUnQq%wnV}Hd2m3*9r(QxpPWX1Q9c)C{AmotCP;&Ic-mml%&di9IZ9P zi!f5fV&;4WhnUD1B8Y8KAA$j@NgRD`g1rlRwT$6y`oiW4g{<>gnDZop!W`D^=sVLA zQ}Z*jM73F-tVFg7pCb~pgu@|@S3xin{TsVJwt+zqI`;8^Y8GFD^TlNUn`yDK z0LAZI4ryjFSk(*~0zo8BaQmmBFV_D=%BE^FK`|77upI*3|6F7x!bTV$$?&ms1o$e% zi~whs!`1MTM;|E1N9E63FQOrVcn8$9DUR`FRwHq_=i0RMXqPh2;|+>pqsD#Y2`>pM zBr#}H<)3R8{aT3GG>IQ$qze=hJxT23#Z1l)S?iQf^-Oa_pfG_|qzV5E@@Y(cifjbHX;FBWJ`j zLa3*^QqHD1v5KMT2$nj_FQh^0*YY9*3}SQy)v@OK+jzPE4Sbb;GrqVQg6fuCrxxrQoj(6RdAO>|u7fcuy5^?vpqMPBkb6W529 z8gcZ5y(cB*3chahdr#_p{Z-C>6q_|}1mW>wWtrk_5V*HasdgrLQhwb zzv{Vl`|~VR(xXr)g{O(74#TBC7YI4HE<%Ncqdl05RN;bezTMp!3)~Cf0?%5TcQJxn z(K~mjJjKicmA;pz_=SR|epr6XtE{~H?BW5NvP<=F`qrNBo5PaSE+uQnGU_Z0>om?Y ze7<(}iBiz_edbQv<-)5c``aAeckuNrBZ_w_;{|jlmw1!0n zJ3pqN$cCp=^H%*aLib%UFE)!L@9FQei^;fs;-pFys|cJUDM}QFYISO`&UMQ27e@Z* z$Rv?b$R|FBVx3tiA2TI*elRwZQ zuSxH>0TC-2V%c4M>W4yN*MTejl3z?Om_@r6*BhQTT9-Dcn5TE!Q&@Mt)96&eUlf#) zo5qKs;QSkgO1>zR*>4i>q&gH^}11GWkv0<&UD!1`I~i$ zH?BXE9OvCucV?G!pOR>q4#gK^k8oOJefGPYnigj< zR&K;@F~B9~K0d+A{V0DP{him=G<=t_I0!hxr-36pe7E=(9|j!Z@UEb;TfvB~jX}5h zC6V?+v$2OGe154-H~0gt)0J4N=Jt4w+t?Jq zQC{3vg<9-&QZ?k4r6)txf|af36GI7yeUsc1nsqB*%Z_*1sEH(PirG+f#9D=S6mvV) zdcF9YrsXc|f66bUcjK$od#Pj^;o!Fi8;hu87fUkgul0<%`<*gn!;C7(ZN5r8-(A5O zmh3b1&Vosx>V@FD+9C6Awd-FP&GF`4JTADgT6gX~yl&WfuD?Wi)VY}FRc{axb2Ksa z2`M-p9%lI1af1o_Nxa>NGD%vLExn2I;&K|ZJ2^k9OeSy(o zP)1wp`vnx`?Kjt?+e^Yip!A6BlDmeB@O`(W8G8J)4*Hqxolc0_y6AV=L-o>|jz3za zM9+giiM!D}1!?sXouY`Vfu?>V-`{PPd9caT>Gu0XWAxJTcA89D!6)L{{iUO_nu z-3iN@pSK3S-<}*3%|cLH*-E3-d#5*WZ~9| z9~r$YH%d>7$e?3Z#?Xal&{g!6L&GzJl2c?=OO@HbY?UDh%QK|d2};yb5h(I|j$_2G z)W~zb-dzJ2|A(rt49lX6)|Lk8knV2jZt3ol?(XjH?(Xgm3F+6S)XM7}|N&pF=@ z_dW9r>UE7iv*wPq_QDRH8`P%1>-K*T>^8h`+Hi&7zsWcV4Zo=%uok0;C+vU{4+pn7 z%9^0|(Gx1Mhm-+E8Wez=T$TU{y@bZ}AU%9TA_kb=&R;vinhdeO@m{!px|(Tx8kZe8 z4u@o>D1idFiyxLAs{(%YkBLgI08ghYZI=dY@*Rre~Tp@Jb(IknsZq#U^noyDVuCSI@OWYipCv7lri zhvu;vwY!+o*)k;Xt^V`n9(b40_Ob>rqr7@uZZH8u(&{m=8EjWMkeQWQ88dlxvpP1R zj*MqF;d(WME~qrtt?FUC@DFRIWUAs-aq2`R9t?{eS7o*l^?d**e@?yqOUXf01Xbie zC_|`_Aih&^6kHsdXHHi4uOP{@c#t+Es2K7c0BHGTO)tGpV#5b&`truo&ZqI&9WG8@aS6->2GTZmE4?2| z`1;~rh+F*+SG)kw6o>j<+Mi$o=Mi^Zy`H~huXttgOp(HZu9=KFkyFn=(LceUhDIVHGMe>tUL4uZ9-@A$wE{k#g_HgDH)&Q!ZXYwW9HpqY3N zzyNO8Kovt}k!!m-gi%g%eH6<GQEJ zzu)ZhYQTqkTvo0z=Qql22U$kp;9O8W9a5 z?gu~VpHM{AfhGYWsS%WhpuZrUOZySK@lP_&bGTpn;QRYpApxuk4RK^83lpakB)rUjf^(>91E5AOJ6%?An&YUGjE;w z8&*)*bNNpBY=335zodzGFO#YN=*l}-oN>tJ(WH(*H6zmuS1m|3E9R)ST6edpj_UMi zO4t>K)ExCQ4px1SRVVy$^f4ywTBV<a` zY#EjeGnNG3xL?omKa`?GKi$Xi8X>L%;9X<1HA4m&MKj_9-f-#TM6f!{PdkF&Kp=EK zxhzA%L}hFEFmO{#HyXI%hSpb-R6yin!X`?|9X%hV}XIuD`JPN z1^x!{F=tn%jds5SkwQYV#de^{Y+n6)=6Dw_dW}>w1*0S zxnZhua zYriU09b^@VWe@frsE&QNG|;yu;wZWC{F6C|^)RX8ho1FS*4#oJWZ|eqqE7f!-{i{! zKVNL}>_VNhxs=kk40>IzG4yAT_@jSvK z#0&+h$NFc1hga{cdan$tV}nIWj@C)JiO2LRcHJ3-Frb~^xrWj~GCOR>i&KZ*Yn0uEx zE%^ntD8MQYuMD<0Qk(&;H{oc2T7fLW3X{7MWRaKgt6cPux(UZ*64j4IO!uS;Q)fz$g-ZKJdWX{91HR$!<0keT%`KKe-&@jUimB@f`(k#2~8 z8I}5CzbgtVkS*_=xty0}g##HZs4tI+_7B>dEKmXs*h;9U^U|V6C-Q`+hGs+yqsg11 zhxC%5Q?YZzGAE1CB0WK<1m4Gi7F9S1O0Ms2Ds>nd2LhkYgHVMORPYE;2VP))QfPz| zK_-CBNo2t^XPDEYD(S`aOMDmYx}#bqj%W3oWhHfs;DG?A2buvi>KzFHEntPdzT}(l zME#KUXkjsra@-2xRK2jyVr#bo^gkYDJbCVsujx1S`(;V3>7NR(>8m6B)yHDg$HSqA zc}g+raTQV$ufB`WLXD4ZIT+c@?A{vemSTvtW+AJw+v~^#@WE;A(~;1J0P5;Lk@XMM z@s|q`4#*|~pAN8q3VK(WHDR_HnO@YxC=r0s`@wF5w!Nbt=nGC8obG|J6ZDFjh1n)P zn1zYyCB-M;#-bldjHiG#)f!0zMDff|-wnx{z9|I~HUFHE7?0k!c3r*9%pReW0=b7Cf3-ugxJ>Z%_qD?NuYGA81wg z$A>0U7w=6lPzhpd?;_r$_WiayN?aHgKx&^6&x;r6r*;OV&+4$lcG?ZPbE{-jka_v~CHgzFn8+oQt6u*QILq=1+s~VxhW;1J4dVAD63V{S z+%L_$%Bw)0xmVHi)=uGqth!30u+ zlT1#H$jdqQNlF2?RZB3%FEjW}Q0Ic4{{ty;`Mi4;u@fZOW{7Kn_Y;M@Mre_c1swxS z5roL%;3)pWgz;{qlFmxJ;z`UXZ}K`ai6Ef@3W*?YF=~zyE>!p$L`nU{3sA>D-vM(aApU`LxmtQ2C=<16a;aZbgmDS5Fj6n!eu&K1gpV5L zecfXb#OZVMKu`usxbS{JPU?x_OU*-u9V4`%BA^SzD3-jUmp2iIcKL~24ch_Bhz58XPG8AgHH5UYt ziB!EekjX8MNN_i=a9D7$j-%|yUY^39^4E)B>CH-u*CZM%2;SM$SU9;+^gVC197M9R z^s|_pcl z{*^stXFi+sn5z6EG}`9NG2i=GUv+s7G`^s|%-YObs|z%rgIgT+ep>#RsslBq6quL2fwp?bcV5Q~LVzt*-MOs408b6xt_ifaOH3M{nC4Kaqf;jh(9h8cT+_4}&JOTW3$p?J+y(obWz8Jggf7iB zUr*Aa^!zn&WqQEkshq_CDxf+{dxN= z2Sb;S%NA|H@tS{G4HJC)^~iAl%6!zh*Rg^a`cvPRWNM>UT=vnL-ZM0d^d6qRNU<_(>nt=qog<6(s_tocC^D*kn2edpd5ALIWPOH_2SVt&y;+dZGE0z>|c4` z+4f~#k$1w_ven@2Oy0Q9f90R|`SU@_V5XzoGeEGfOgLFP-v~D3Mi$NeWpw88!R&Zo z{Gn;lVrh|wyEsZh5Gj#_xFTNy+I6z~R5YPQhh!}})$}t- zYYOGB1@O-afU!(4mZ8n99BU*`4>hlUa|kkqGsHvtlu~aNyc535|A`?GQioCV7f3e8 zzEe1mRtBDp!h;-W!pQ?1XrY+F6vD$q6)vyl!jLiS=}OiFTbCE*4Z*+f0^fDz$|&kn z@1UVMAar%PK7W(x_}WgTGA_XVfV=rm6<1%LAX|SN`IMQ=Mq{n|?gyz~XNLqC6LO0N zqc|K&-~i!22#y_frZEVC98J?w$q{5CPfZ7w;WRBrX?jr)R$Kg2lszXqoNjjy&^HEM z#0ZpM^UaKifb5kw20d-9e>;D=1u*D1P=G<>48Jkx2v%LL(>ZH^K~JWLLoa_&6KaE# zC^1bs4ONa(RB$irk+4I_0;lL5O?fU+au4hDuuB;G1j#Y#X9OWT)*}H)3bPx7KcLbd z&^Cs+D;liw^5y2}PL_2#R@#)C*(Jlw%84aIyAG(oI|`PqpNDO{5jU_At%3SWY2$G` z=avoBUm9MZ{`POa)!$HlS8S%}f&Z<)pqgdh-s-Q*n=G!}_1pff{@(nlzkCn8Y18l_ z{D153lks!ae(LDQMBSmI;k&2jnInj!RDUZwJAE+#`bulBg#g{Vqgc`#CRj6wR5c4A~Ra+L_DMoYRJ-;3yDsLa``Uk;|}}F75J6l^p$3 z{|=Sv(-?IT9I(bQ6;%O$U0g#FbuNq~mZPYOyW&umf{9|va8`WB>gH;S@9W-;x}fB_ zda5cFYw`DxqCkuKT8wbz6WwUr8G8(N8dp2XR*E|&V(;<3Gv=??`sZ#0i+7ORVfQAO zMvHZno;QuD)Oli~aT*35E~ybYR7*PjCUsa=keR(ET~_2a=g#|!{U%jiQ+|_}43$6h z8izI#4VfV)j^$!Da~Jl+cwZzgIX^4KbL5 z*41U>e{FI1cw$fbU@W4cuymGucSYv1^YT$l)m!&qOAYVR^U-(wef&APhAtSUkuVUU zA|n0<>KtZe6BtF83qkx@HY~12??rUx!-QOR&4|bj-K*S7SY(Ph6oUFId3>^tj4YCd zP)Zz`5extZ7?h59@ggb0ql$fEM)71uRK6Ms?b0zM4dDdwWDH@!a7}T=*iMoP#GxG8 zf;`}ey`Qd-00@7fV89OuZQ?~jME*{sR14St3EU%WqA}J@JRD!h97zaElyY1@GKUm< ztP%q=NI?$`6GGHqK`$xAv!9Y-tTSr&wXBCSD!GSJA}ZNVkLp^KXjCvEkQC~=0k-Sx z-sQ@`Dc|TY36h9;1db_if{=Nn>R>Yt%P8e)U%`u4VaRA`UqJ;wozXoBD?L1mr+~Li zCiI^0ToCh|SoAa5gjodM>Z3+*?vCjrmXGRg%o!k>Pp`yh`{yz`0HV36GA!&pb4Bo; zDy;eY5Z8PvaizEtLVB)-$jxA!N#YFwcS4H-|2N6p_tuRPKO%HD9{}pUPe4>nF6`~h zOaq_mfk%Jb)IT(39`4uPX{%n+RQtdyAemPXstB%smsIKPSf~v6BU$}Xu1L+o`EE%g za!~lj-UC|J(|qE@xh<}-%rDB*<6D;9HAaMwhCV5sS)7$B%ULG(mJ4&C)|T1aHb8aiF{L{kBc+q4|806?$R#{kDhFj&&P8jASR zJJQO#8hwe`!FEJDeRct1c0_qg9roVYS3`FUT4Ck-7HQZeA%B58`7)(>6}Y~>xBU-f{A<#)#u0Yx0uB zVCKNc0@L~buh+do-4ao4PzgXrQ8mD!cLv{o#_Lt>5F>cDV*Sk=16-q8u>kIV^&zSR zk5<^5)xG6IIe-1`BJ=)D7QY2#@nU;(isdYxJeTBVlO{1omp1Yk#4eUTjsCyN_!mGK zXYFFAYx}E=r!Kni!OLQOb8LH4#_99UVp=<24K`sO?3$kQ4y|(L$O~=O=exdfHJPb! zY4Mj1Q^P2r6bw9)Gj!j{oDfN-Asz-k>G1&|^|kihjlC!qa2{dIm+tw>QAqnMifJO1 z=q9?YA=a@gym#S*KJ=J^147ncX&dc7NQRZI7pSF1EH%oxgm{x6E%395>mp3yZ>r?l z!BrXm3nNI=yikIdBsZD^EIJJxOf5|n1xzig5)EGyZ@6i#w@g8mW77y>&D-m12h;}o z&t*iTTb~yFVDB&`v{BB`hfR1F_H(@>NYiSZ^Yuc1*ykYI+0^4>oknE)y-FmA&+l8% ztdPeKXJTtrVdNk@?;EF0a>7%io4k;p^gc#;0L-*3U;P} zEa7`dTSO_r+V~xR&)0hqhMfny{wh!eXElfHLOugfY1uEqJBqa^S^$;iUI3`H&~+r?ctZHZJK)Sb9r`5kYIYpdJJt}cB|^P zVB8C@<6-x;{v&;erAp!9uVCwf2F83P=Hz}`fiT;8olU=?Tc#XQ%3G!-i!#Jn<1GYU zoo2ow3i4NrvpU4ClRQ}4!u&ypgKmH62_m(T7ifnqfJwIlOnQXZfnWFnVA7P%7Y@D$ zl+LYQjdwQ(MEd9GZQ@R;W%XUsh+J(+Zq!?9SNYrL007CLl`AB$ z!6Oo{fE=$%mB6Uh)~JNr4#mz9dKt1SmIEX^BlGI(M=3~i-F0yGUYWH`ls{;P3PAh? zxfN2?m?Q91v9U*8H}cDr&koiMQ5d(TU({%Wu<`#4{5XJA{+|`$*?Q>HOaiUNdkh zA=Bt&^EH>KnsF4M3zpJM#-f()(oF5Azp{mU-fV4SZdNbtwTp%O5~<9XzBgO@pd7HZ zAx1V-tJh~~wT~BIlizIZftR7ww!gM^*|$uERu!;Xz}D8u^|zofv;u9n&Sq$(a`E1? z;=q{-Y22|QJO3He>5&z!y@kbrLt>?ZKeg26=`b|}jgvezOOx%Y`* zF!1p9@CGoW=G;vw%Bj~(iz~!c;wy-^J-FI7gSRt;RqS607Rjsr*6h5RGMbZ!FX$yT z&rrYarhS7DkBye0=a;rN$B$q1*Jv24<-nsp0YRc_q!R0RT9A^gXoI8}q_#a5S zV>92)v9gHf4UO=?MGPgCF)k2-WL1Jr^^_H9^}659CHxDl0YGw6h6%*hvZ6Tvz7W zOZx&;E$)&UCNS=JCAB1)W=e&cA}yF*34zWX5b5%;(v^vrO_gIjkI>CvM1f1voQ!g8T)hzloQ!Y%vO>-D$+cOO{Pv*cc~vK`*aE#>C~PWHVu)=OvMgW zFvfpKxOdP{LA@C*b|e7i7FE8!CRDTPEa=g6Qiex4#a2(WGb;{U>Aqes=uyaAJy$?3 zjZ8)|qfAZlr1{HqVG)cMh;9$Y6$AjLJ!(OLhn&K2Uf}_?L5Rp;x;<*YugDxv2|~kA z`GtA7yrSD|Vhjt76(_G01Ldpj6*KMNwZN8pSpNeVd#(Pd)(W1Qcy|l58h=YOdt#nO z*y*c5J)!WUMN9hv9!kWqz#n-$l(9wgX27vy%a2EXYD&aUoRo4XpE$EbrFaJ28-5_2 zk}hG%$|0Wy-PAN6y(<0i{N1lkQ4o4e-HpD09INI;3=-&`$Suc-;^;10VXJdOT6w8p=&o{+vw?e-82affQg4MS7oxD+lD=Yrq7cfRjPLKbyh;hnF)f z#RT`>{MF(s!T-k@!Z5;E6>*8z27vC93y$3Mwn^|=3}MHHVXk)r&MTIfOZ*0!QR_jY zfXfX`AU-A`z{anh`rBf}a<`gV05+aj=}v!|CB@x*M9SEFQpLKq7bn^)alLHs75ja+)h-msV zJ|`aiFDH(XG$N*$wu*SvMdOB*6TaLTIu^)iLBknL7IeOMf4^*1nAnE)1}gZ`qdXe$ zZ`W3MSVWaEWjZQKc=tbi5dANZ&<90mfg;;PY!SA$T5$MUMrZ+-Nn{}bmuX+1;-=+> zt6+IlAv(PW=;6DMZ@xC8)|;=r2>9CQsuHq{v`66kp6nQ#O^*3E8Z8#hj)=ze|9tJp zNv6?gTSeu}ayBLFA*s?IbKJ>Z(_~d_pGxAWjNYdUmF$2KDvh8q$z(`>#1=XeorW7t zA{waRVKRnhWCoUaqJcvs18G9bXxKzY+6gn;++MR|NnuhgAZIIrsh> zF&DFRUDJlg<^G?%nul)K^&2rK3@Lvcv z9v&dC5hK5{Z(qWP{OS_CaYi+mez}CN!8N#4^#R+OYIlJ`?`F4Qy0XSz=j|_L={FAv z)D5_@+~!itf4sBE*m=bG9qilOMfL~b+w-K2pg?{PB7pvaeWhOdYE)xw4CQ}?2k!X1 z9L7z{`Jz>_a^`#6Fsf0=Rt9e|f1i@~hJkAU$hcVaAC6S;G{?KIVKoa{Lzcl88|NKW z%s8g1nPZ)Sc=qJ9w1WS^k;Qokcv8S6p(jT@vz>v`RhAs zM&L8>>Us2(ZQfS6dggj{5}$#9c>=#@`99^{8$tnpltj;_h?3UEVmO?BEESOPSuu>D zVO|+Gj2Mp==g^OM>l2e)v~cNYQmZ_WTQa8-yq*&~NVMAx&A&)iVwivb zj82Ycx5vHxH;_JYIaxMYA!rH&(re!fm8T$gd(~em{a7hoVTk>a??p*47WzX%kz_8y7a%}ifCpq*7>qSo155{h>beCJEYW#~6s`)p=JN#Tl8hEBPdPCVk8U}5a zt4J2yYfyzNq7;+9f0!ETawU4WPZ6#iZ!bar`G=z8Hmgq7G*cfY6WrFlM_%v`ao%I| z=KWD_A1N60uF#9gPFL(0td|CcG4I-7o#u7>4m|Y8R|BUaVX02ut$M-khWjFRk z;qX@3i9q7E-00p5Hv{Rfz?(-@Tn4W9vCG>x17g>+?%qwolUK7k1kpS% zi=~7(u31ez;W0U@TUq?wtF6fw^Rauc*(JqKdPJA{2`PtMb8}jew&r{sbd#YqDJ2bJ zv7bs6*31_qPzpn&CdMQuD%1=R*xPDmqpA8+XD5%bYstZ3tOampAe%s}CuDKrVSn43 z6(0FfG!bR8q3~_LU3;1z+Mcwgm>JS2)RiBCNwRk=g41QN@p-ws>K#Li${9b_$LYjh zcl6ZIcC0+en>S?Eap9)oujy#NIQ)`%YV&pwvz7bz0N-tc_s)QH73SuA#Q0KPTIwYH8M&9bd;-cd2pwhoU#D)$I7XuZWF-l~#>o`_utf>Zw-E zv`;(VD$G0j<#sLpXNQefg&l|NujFz!4%&UXiH$@eKOj1rdNg!v&+=DkK0|diI2Wq5 z$QG#`nv5>l)K0*sS3}*7Wr;OCjAfC)aC=wi<;#%?M;f#LR&%jYm=fKzl;)A1p=~_k z`=#cVS-)Pj6sUGP70E7Z2m8N<$L<4^ZNyM!qzT<_CI!29l}c&De#Yk~ ztwQz2@cC^P4tUwbuk&G_8&?yF`pnfE)63==jFe!UGf+dVm`0Fx*i2(qq;&~3BWaMZ zp0U&kH4!P1s^!kWycK?!+AH&d!kh&I_OWarFQc#NNyhX1-ECxI>H=eh0{-%pGLXS@!K5? zultVLtZ`{gJMvE7@hsnHO;3CCel+2xc{@y8+WENF_$4Rx3gdiv<7e*&pEdLB#M=At zOQbELZf30Ws*8PFNBBMNV}vh(7kU3dlWW@2h=MDrw54=4x4Nw6dA8$A2p6I={t3@O zQWqEE+Z}nkF^P2hVc#II-R}etIs};gaEF|z^Wz+M(`5I$#6cWZASAQI)U!%ks5?Y& z-Mq@w>N=s)l8dUv;-P=7n37$6+79iRR`$=m!ps@znZ7w}t@ZVJmT<>e2Ycw@wL@Hw z-1>^~fGszjqzZ8n?dQ3{tmEB=@rniY(9^YQcNvt;1xST$sUpWmc28Jck$h+Oy|}}B zHn!MWC%(0dlRT-#HObi<_9*N>`+Ux0=hMmyGN$3`7aNqeTh)!yq zOTVgS-LJjSbIhAgkI+p-YPY{+{}({O7jXgt2(pT6*a)wBN8>Hdv?C2>Z4TmyDacC1 zB`g?B8x_I^k{qa0LCibS9EoVAK=&Q<)PT7_7K|zNQaa?Nhk!gKtr{IY zTi7HTYp|*O?VCN#1IJ(oWOp`x$Glt<1I^&eN2Ky^UEE=d>eNLOs`S z#W&q2Z}*%5Rh`%aB-!@!rU1MvK1P2>Z^>O6y(v>sEUKe9^x9*sJ&%+M&5$ zy>xew{JP+@;@ncn1%29LZ)sLk_o_woYR!ivgDo?lm8H*Ui}D~qeD7cZt@-Bb{kF!J z>=Jgv(5XnBAswfejk@N2RFA5ge1fAMgxpXvfm$cbR|LCK^5mzq5-e9Q#38&ujW0h* zR=B1m%x3v$@6G>Cd1s4@@3`#QDED|yfPIVN1*8b z7e`WeMf49Ni3^&}5+Xzr{|(OMW{h)s0TDm^A;Z^EYB=m$xkD$LTI=`y?`?cXKeJ99 zYo^=zYX2VJJO;M&nNlccEFV!^1Z8*%`=8#FJ32jBFCPIN_3RkC&xWte9wJ0idnUe$LWh@yk{>V`zJ_w zyg&Zbx$PQ4%2}j%qKOFX#ux$n;m1RWIHKhLwxar8sd(zZ5F<9?B+Ku|GjuSr{t)15 z@X%2+$g&&1>Id|c;!>6dt+m{_sX|MIn8yJ?PZ28y^pxRVZMX7ueKhU#IU2?{Jq7BX z9KBNwNE9OD7cWb%FsKyq82jiZm7^`Pr$WqE zxFIgo`8kfeGjGqVUPpBdNpp*axul%^V=5V-86VsGB)Cd_v1`69pq=Ql4aJ!7xhlz@ z5=;RyL;TlL{-Xpn*!k=Dk0F;sn2CO$I)bxQ)aP@8t7ZOIWIh2rf;?ix9+;2zLa*4# z?H{v{DA0C;=#oNF6F&68+yGn8!&GcRQwt_)hVe_>UjydJ@X*ubrNLI|N$AVU#71ct z{A3MvEf*(v)jOJ=_jRCEq|h|THfcu!cy+|@RZ;llp@0id{bSqJ5)?h}p-$e1eVD~Z zaU0}k&}VrT`3jF^zc{VJulAyK=lH(|xvSWCH9x1jPEzYcLo0na)m~6g#L=Re`~&>; zi&l%b7bi*lA@o4h-=X_Kz!>V5*R};XkPw2vb_6)&^$>IN8ULI?IBu^;hHLV{a@2)QDfxcn4J%Lzn7fdGp~i4o zeHF}9gn92Ss1t{=58+;}n3x(SHsPp+=#EVG5r$y-lTKXfuLI+&lv33F;5`qBpgd8i z6l4r&K~NGaKlH?ifd6hH^`Bd*nez@^FH%kg1y+1z7Yuep9|WejEL`0$C5cA@v-?D( z$IstfA|J*KG{cWP4@SiT*bIz<0XU9JFc=}Ek%?n4vfHr!_$ahSRi0Swzk*gzWuTOx zVD6kd_IsOwEtqCUvJIssh(_hl+ROt|O;w^?k)S2fmo&Ce6GU9Rn8BqMQ>LI$SRk4l zLr#`RuV$4S9Ir=;2_qU1KVX{+++NJ^^F}NNls$=Lc~LHVo^s&!_J~{Ml8KVhimFJZ zYioJ(G%cQ*0uBhu`VyEPc=cH$N)xe}$c$tQZB2iFY(SvubmkV&{CZB2?P-Rr8HAoM zVs@?BwBqJLzCdke53YHZV|!XS_&Ckc1Wh+38cA`cVDUtoH%Qy38XCC;qzIAw5sf(U znY`xLm0mrqeSj2UQ}x+;LZZ`LRo%T<_=K=Zv@7JJg<6FzH)Sca!;uf2l%_2l&TEam5%buxT+D zhn|FmA|py=wb`gi4ED>@C&3;FwaeESCDSZg?@(eKF(}X{RjMCgcWy;m?*u5HzDH(c zp!qa`ZU2P+%fY;Xjz51@EV>0^Zh8G=fy)Td72^<8byN+XZdnGK~&Q8b}OAfVaw)bwD{Af$wKFABzs!Nk6s8 z?Q<|1z8vA{=Nv2ULOmQhKn8BR4e9l5AwN8AT;)$ zF>p`Nr+dFCrK|O^ykL!nD>Wzr+<7-n)}Zq@OC-du zbZ2^`_Atn(+jbOUgux^pf&!dM0Oiq8$m!X;HhPZ za7X&;NTp-ILVMP4pf_No(p>yLYHPN$$UQxy8%}GB{TW8@9i$(K9Z2}EGkOm(liy#o$W$M3lO5c0tO2ReGjmi$p& z{U>>I{1K$Hbvte6{pHfXzbh7S&%2@;R3!YbH#-i2y6B4@uJQ=hhhGFAr&NddBQVgW1B9_w*B6zr5p>%?O?3MZl%#&44wvAJ9 zsc9PJK|d0L(v!>GVWbllYdcT~gFUMWe7x{!noHb|<~B3X$+g8CtEleph@V(rDz7*2 zE+SM85O$6$GIRn9Y&Fs*``NqM@h%I$Z0ZfCY{E%YVGA4D`rM~PC~4B*CSNECk_`rE zvcSj)CC(JRm$B%$ScA_ z;GCz%EPz15XcJloaih3N#3-o_2qgLneFZ^e-*A@m+3!>8etUU5{XA;5c)jF*J=J}! ze|gG%eO}gmeW`tY@-p^c@UHsG`=@{T+4u4JW;u0o`m1%0&Tsf+VKM~?WhRVd9F3_g$$>XG#Id&7c~%;knW>EjmIP< z_YKGDe2lPO3)mMCu#9wCk`}IejZH)CUo}YTL2vwDyZs$`*aiV$zzZ|=F2F|V1vsV) z^nsG32_T?~huO@|NQ$G|gjQ$Ai^JC1aKUN|V9Y=`foM}oVhmJ?i2^4lpW%p%ieXVg zkZORYA6xN`ZWSl#%GC*rYAfgArYteIF!S$;6qnwd)i|#-+^v)yFClrVDKkx9xG6^H zM>DL%VE<3bt7PS+zJ!HbWB0QXQwuq{26g@tu$z#vg{4r+oTR^h?InuLx?G3n!6|ejtWWH7KN$q1Tt8kI>lB zrZiEQC`cn)M_%43C>H-9g-@74y7bm6z;E=XE@{(gkB6Q$Ow`{ z5@MB?`K`?C_IVLTxgVwvG(n>A2KyAh*;0R)ean&2u4f~ zRbh+3g3K0}WW3K25LB`x93$XtiSL2gRwG)#+v%}L_n03*unqOLM(jW_M#k+xJ^CM` z8^UQ^2L>^QoZ3`@kj}-}WJjSIwU0Q&A0!YeRLa48ltpON(o_BuPWii{VJ08aN_#m< z4Pg$_N|T`#l1}tVM=Q)IX{rEnQn(Gq2K^W9hDWLc>P~}m`img$9oaV2i=^wd4IpHa zt=^I8&&>#~0^?kY8k&cFDf0eeU`@M0yRSi;wR$zWYq-&^Tr}?_g34qBxqCz)Xs)wpBOk?4? z=Ar7({gNgol}mgi0j$D{t$6ASSSOA^5TcHqF6UnmV#LJ;4#8~=ED;DosM(}j{^z6| zDFRN4>DQ!^cpzN*y~{cqxiJE#W_-@j(`X6UPFT;Nb$o%@vJR6LGP2j8PTik2`s7J9&tg5@J`yr0{+C` zW2yxIRSe=ppNB%`B%UG1aRXj+JN7JUn*(W~hBo@(csO%Hqa^my^?`O)==Eo>#^!WL zuHE1>)$J~>v&W@sO{U9%gJT5xXP1lbmBHS9t;bSM;#KX3T{<6ybL06)yoXM0iWOl# zjvziqnGvjo-sgM&1JI_+g5DaN+Hv`3%(IFhi`<~zn(}7EZ;6ZMMs+mRy)~Gzi^^_V ze*Chqjrzf*rVMwebQAYJudu>jQZHlLSebbWr+f2Y%Y1wD1iQd&D8`gFOlG#o2o8TLQg;`;naOU??{?{_>@ofX_}7(nikjpUW$*vC zTyj=aI5=A!Sjfj=1JBX&BHA>-)@yGrFww0rc9%IcUVdP8?$4~B29`880&Am?WrQ_8%7ys>7V#;iI9mAcVczUIf>wv-l`~7 zr0NoNQ;6FSM1G~odLm!qZHjQdivmzTw;_Nvq(M{U3I6@U$0^qd=oSPn;S+BF-GUCR zw%@x=9Gbrs!!L4$YG$8a0_kbE#f&wRX+HvI`I9`9c9Riop>VAmi<7)Cc!R(dLbfm& z5Q9Vu4bb|XcTB(sXf$kr%kYXRNTe)kW&Ts}%p^9dG+8M3ukeY2Z78ySsDFo>{RN~c zm^0?n=TCI;-X@NSemyWsq12b(IChjwvILau@%`Jzi_61=@{lOO-}?)poujwcg5+^_KE=PU1z?Jjwc_=oU&Irqes!D8B^S!) zqNq|1nry!J3CP_peOu`dDC{%c0n^0CfY}!E*MPV(SyHYnZn#A!2Gtd6raQ3R-csJY zBNHz?7m#~&wClQfdxU{s5Vq@4k8^j3GEeZ)OfqEXv-BTAjX6UnNwDOhVWF*C{L7iU-OgYhdr+mx*jMl05HeR@YMy})=PlaT}R@#4UU9U(3> zRG&Wpl)+tl9C4ITl8;Vg0B1e86bNMZsdv?idxjoKQy`PVp@bZo+{X@1FdXwXTjyXlw^m-2EpaXl-o(AucWKB z(o{8(*)yzIR?Qkd7=7-aw^6i~s{e$w0NN}-Cr|U^oqXjw-WU+Wv#9^X3ASM1REZLy zNfBeix*3TkABi_sv=dak1Kk?zO0+Ht44L_i71556YAN#5R`F?$bo-BDA1?B77RVlU z34a9IfP=d+yKXP1#qmADbqZ3AzaOkiH3MA#wjm63oj~_1grP+YsF&@!FiDK4)~saH zYav^tD6YKnpQezvHU9DZR3M&`Qu6VP9Ox1`KokjNPpbFUMuLM8ABesXB%%K*#8A^= zrA=wTfy{|kD8wia_iqIo6aeN4!m-KUz2vL@fTTwI6k{N6HX>7mseG6KOhT}X2pSu% zR7(frr@jLF_3qD#^wkFkI1HO$?2G^4BaXS#c2PpiL3%#2KFT5#5(9^a^+g)a>MrhA z#RbDBs6Z74OgPAYYp>pSh7}QJfop4CEM`n*fn<5eL}^qk9?gnj1$&EkMPg8xbAml7?C;5@*hLKQs2_k49Jh{VRKDVej_Nz8&a8`2j9xxSLLFP{H5Jn?U+5&)Bu zLO^)pmu_%S3}ODpe4sZ9HV~c=il12}y$!;t)Vs5WN^*w8-l#Q(xRCLz{H^Kw({d26 z36DF_u=#%bdtc{D^5=qYc((4ZgPo`s=6Vl;lkM!q`iEDDE)MpeO>e4*LTTo1M~F29 z8v+i(*3Yf+H3a1mlE4lGH~}~nYgfj&33R|6gE$aqH&C#-vf)C%ffZ__*@viag*&$% z7_>K=rG(P3{UO0YEE-+=rfyhW-k?#YiLa0V^Hq6 zW>Nh?V9QiG!q>gEp`-=-atd|e&YzjxSJy*zwTH{(dCAt2>0;=3lb_<@a?#%UujmWZ zU}2OkOU{xMi%G_^uo`LACde@b@hWB^n+{;vi~fZnwCw8w{}vmni5V;`v&tZ@!XW>a z@@!<4q(w60Ji2QC7R-r7ad&C@sCgf2%7gE#YHx|i$SWWbdGqtaOxF-5gX!}O`Vd3c zq2)^ltf1UhOP!$l14$$u`At_tO~=rdJ1SH7fUY(>+3yIJ9OCHl{bGf9KEJ926E3Nnup7yg^bNU)u#G$-X$a%K&s0HoCux4>;TVvJ;Ly7d~^J zBC2m6>JxbkZ?b36{eckyvTm9g8(b`>jz>#&roe~*Zo5S8)R4Wm5dplwh=8?om$wlC z`R((v=6Q?%Ga_JVSg6wl7!e?T0*naIIbrpE8xcTT^EM*jQ`2QHk~KrV#-9-Z5(vPE z08VL#w0%3aUp@psJR?T+v+zuZSM6N@m>yomAswK!4Q`CxJ_EWN9Pfc)x{Z5hpR&51 zzDU3wou4gB!?{+r`5PQ@)H~h*bHoz;4U|&Pv22P$q~O^NX|dZp6e-cWGO+1&f-rVO z+>ik{m}lyZ`mn?c{}=q5DZAFP;2y3DL^S!8!x3+)$b;MWz-{o zIR|zf(50(YQ&aG`!Vc{VBus%_2Y3!(*WoPN@e4kqd!O7L&J6-7u(&Cwd>)M&*md~QnF~V+!|hT#DRBu?vIMQ~Z@7VbuL-)gZjI^{+zPf9wl&9p{~bbsG_k3$V#j0&7{(f&`wNm-U;| zu0w_G(O-`)OAj~x)%zaHPmiOMgX5%dbPy4K6nQOh2cmg>M1^|?hGz(P&9)U}dtrQU zpfgMnrHo_buJ@H#2U8{kwoA3>r(B6d+6{tYO7wn7Q+-c*{5D(7;d6IE%ANZ%+4=IB zEii@@(z(+^J-TxVv+~(k^^x#|BlD+wlj}qRfqbT+i&A0QrcMjKv|+c_ zIksE}g+)JK2gQgMhVWEa?FQq+W5n2v0gr-fw!nN-=Zt{wCtGGid`I}XG76(bnPgfB z$VWSl0zXV631}5?4KQrce=wltU%p6`53ye%3U3>e);eT;=&qK`A&oc?5agfV&@zaq zFpLCpj)h_cSBMLOH*up01jPK%Y|=>eJwaR2NL@i+S@WyNv>P7hbrFtG0{CJNPy(b7 z4M%i{zRp@owVE0aHjsv1F;@6fP)>$Q!t$>!5=F%*B*OK^OFI>P1DDZ|R7pq#4@}6T zqJw`O@CP#Nn5jF4s7zm*Fc)LImg^rccF?7+on>hJZ1oQQ-8;utYbphP@-JM3H1uvG z1+u@*`ml>-x7z*2D*pkqyVgP)#S<6{w|9uZ#xv|<{4saBMwvu&) z2so+BcWYJa=OQW15@1|oOB0QQ{m*QH63&Q%iEVOI7)%LF;FI_WvA$r2wM6$V$}9K5%vGtShWJOC?vbdl zaxnrrmEUp|u{iFqWzi_^JmkJAJhh?Mgb{>lqJ*z!VVtyfYKHW8krcl`Ds_i_qM>yU z<}y~)##{*c1Cl2Z!zp9c<;}x5D1Aw8WFaItLQG!T>9(`cKJV0+I)c-UXwu*<7{b&0 zUUdMofVA-bFZisOl#0nJ7W|Gyz$}1jP$7ylz852*x1xLObWAAc?#J)O+Kc_sGFyT! zU~Fm=KSxoXjLBNl>zqiDsQY&ouz$5@eRUteN)ZJ|*%JmpDxB%|A--89+5mb`oi|dA zG9F;w3w)Lq!1~z-2hLR3y1IAQ3g`fYZG|=wq0)C)-;}?!mxut~z2DxrMGS|(w$|6S zRq*26XFNjuh1$z8VTp3nZhhF?RjIXq~QGw{$_-HgJbG^RzeRmk~1N)`9l-%NpKE(t3C&Xijwl3yR@?>ts zt+7PMTXQr^&~Dg~`s_SGjyCG|<%*veC64*u$K#eaw;WxXs5zn`OF~YIa{dP*n-It| zFmY|ig<|`{2Q`!h#evUsI_5MjleJS&m&M%Th|OS^(dh&dvpFT);<6je2LZc3H@prx zb+-t@4l%cgxNJ9W>tkY|?H@w|YWvIhg4+HLK-+&O=-aGv9oD|tj5p8QwZ?|zO!`Kz zdS_Jmf3`q+o?Wk!rAr< z*}hfcgrK*7Hv84av7R)MX$NrXI{%*}sMrr@sN>~g402?>zg$`? z*CCM1_Fl6JDbz~Nf{OiFpx9T4)jY>fBZ2fvR+*Kz!xn_}Dn~gmC(hL9HAx(aRg^YX zBOa`oDD8=bGH9D{RWq@3VQbA?>)e`h~;q@auv3vDD%^^4lXNas&a=pN=b+=bqZ3*DD1VXJGDtV}7i4 z#>3Q|kuWEoaFs|v^;K4p;z>gSH}$*ME1a|o9jH2Q%~r5F2Wl^Dp9lb$yghP-I_&|!-jbHbn`HHpwG}(C1-|z`^fo>MW`AG{8cg0H7iIQp zYh#4QAxvOd-Vdapt!>cqHf6uDnj-H8YZmf=u|t{(vGiVn$OH_c2%+GY-mEX1QDi$w zPM=T+ONVO|`J#_1u z#zWuP!MY)%9fEfX$odOr*w+|Tw0n9C`8yh`S%{@(2qM(mHJxs6Y($>!1>YPi22K_C z^So1Qo!mRnI6jhsaQLaU{V2YAQZqulI<3#s?j^Ne&nh4L-Y1{`yNqjlw?%n`F>+== zWaIa-v&aR)(h4ORT58g4tTxAKnnw6{;+e0fXdK%d0g8WT!ebA!(&wj6t&yojgQ{(W|I-px;>FTo#OKcA~qqTtede#+_~VF1<`z-?jJ_+sMG!a8jS5+hCb2Eac2=sw@{g z8h<$>j5H_!G}0s=Lp6*s(j;d_(^$iu6$8u_(j>uY;-w^z2Ab2@LP~}#+@rKuWMRxj z@l{}wz|E-?@l9@DO8__Y90QE?1yNfAjJ$%09wSu;>^dBx3mHsD%!z!V_N}94r?{t; zvE?aoI!}G$F3zmkNRpvdPz|m6DBO(jcDs_}MvO}cp987^s0gTD5h+6WOc6Q&r4(=1 z4~1fvd<})-%JIWuZalAwJc&y%ft$me{uakn8xJQW*w|QGKZM%;z2nZjsrK=!iLOt0 z?G-@;3*m)YK-ZqH*W@~4C?jr&0KV~@`L72JjdH`VYx5?9np)WO`zo#ZGkU`k(KC9#2s~*e;LDo(^dPgx%^IUg^RddwbS6I^twcSUodJit+!L33dwX|mTUx9dg;wEyoy zOt5Ve@ITc^O-AGAQ0PbEljt#C;gdwXColk+QTDdBR@tUUxYDOE2I`UF4naF{)sTrY zcaJ6mUx*!(7AKgY{_{7~SS?CK-$7ppa@^jxQ0qZZ>ozqF-s!RXKfKTm-V;=dlRlg9_ms3?Knd9C<;F(Ap>B*me=fo!Y&&aXt z!f^e!Hw(BVlLlni%17q}%evnNkFT-A;FL{Xla@3pu?vR(lUQ&)7Yd1KWgJJ50(y(= zlh?p*QBB{5YDSI5>IS;yQxGiOpkuLHqqSWdXkh;V#N44ZzX$eLA3swD3p^^v6YVQ3 zdGlld1N(Hstwy&7=h*Up1ADvi_Fp_5V=A{r$8yUJf?RsOuZ!K#QiS{^HqdyXQ2cub zH1Qqah#*3pQHxw>4MQA;M0KgLQ1E3Tfq$lCCr|#3X}$9_o?}E&>Z_k?5N>p8u~QUg(JLM zf}cE65tta9Aj2pM!ssX>!nVLvL56;+fT5pc{HiES!4RDZwFVaEC^BnA+7CLD1wKtK zrqYV1ESn^$c}JBKpR%Vg!O!1}Xw3#fI13+NK=M0<*?^-3a4k}{FEDK1K2qwsXNI+K z4p{*5yGsQ?en;>HB)?-D&0dh{E&Z?j?gw^4BS?Pt8Z|dmQ>8YC5Rl)&+JNMD=|LY* zX^aEeM*qm~zAg$gUKnh(_j!xmz*MY1v%q{Q$hDC`lab4!CELEJ-5q z3Luz^Z5ZwaZ2ScA7G)C!BM28aree;2?#=CNO4E%$pl8H$Qd&!=*uDMorM$`wH8cJk z=PUI4?zexTLHXL{%xp65OWFZ2ugAd@I)9^sDRdg)YWeOFB(&Q_;u6+h;hcLeMhuDx z0xd2&g8X=~2iC}{R?(^TndcDQKten1$AQI9e-;;q7BlN2H6i0be!LStHX%{Y`ng}< zl*gr-ys$3>yBh0j<1S#=F*`n{0uQSrlNTqLg?>6M>bX`WqFvC#N(Z-4Zw^tW7Wao( zZjM(zz~1ED2BRR0ePMT2LsqrD?CnBs%iQD@q9#5Y=R8YDp)>L8Tz)^zMxRNapPz2budd!_mZtg!{s})CkCR3< zG{OD;;)Fkcr}_M0{-PuF(oW1l7%O*a4kgBl;dDKdQEh_`Q03KIE6tQOO&*;3@ zsifH17J{K?)WEp@%w8cu!PCC$HAgtkwT+330~!$&Y`2($N7`TZa9vRF(h$k~qXoo@UCWTQl335J|`@mIOG`T7w*v$1dSdsK=0xbaTReRbYd_4T3w8gPA#LKeB@n zspqncPIs$CYE6^bB5{>7$ux0QB+fxn!=YCxDvImiaSW_KN@%)9uY+_>M|jL=b1fg< z7`bsOqW2mKZ!Oi^jw~nQ%U~aJ!y(*1kc#%uYW0J*BZ$`Y!Q@9N27_V0;x7jm`r1PI z#$&7H>H6M|#t&;$c7_o*<9WCT&|dxqd5fF})b<~ocjf~Ps@_k4wd37Y1QjfXZySIP z0M{m~kq9|)2qe+1=ggcxtmdZ6AUQJAT2SuXr1)Jfv1TO?es}V(MHSF6`=Hpw6wsV$ z`hYh64oMiiNkE!8`QB=xH&Bs>=_m!Bf?WRcx%OM10EsMvtHzJ6g3aVs%^%79U*TAK zBF`zlmMO4cG^`V|VC+i4=U(?ko)rHMk0E9C@3O&WEr?k^d8Ef&`9D`e^g!!>db*GG?IUN zcfZ%~wD%!r(+DG2AV$&#(g-VpX0#ohC9+}|PF%2x1z&q6U3RfWn=%*^sUN3F_p7jJ zAYn`N)2OmJ3X}lfEo{?47Z`?tE^TU!ekCG2p!qdijt6NPbQu(MX|vvNR301p;x!K( z1aw^2yyD`Paz4B<@$S0~JHh^u@4iXC(rDrhl-uo0+f zz}J^X8@zzh&+0DDm^2LV^#yF{IHA$rJurby`xJPGR_+7pJ3~iaFDIf5nbF0%3B!dl5~1>EBLxdl;YKSh!R3$Fsi##e@~1De5ABgQrDL$_k?@ z2%;l@9ft7_l4|JcuxidwnNQQn3L znZ*8u`s0fN@@9LXu_+S#fXbj1Q%4C0qRJg@Y6%BQl`fQ%%u+0la7r>Q>ofGi&?XUw}iI9_J zKQ1J{xopVl%~qmVgqJTWXjKu5L!*L%7ZZHBjdsYJ2mFG<|w=zVUrujE{O@n&C&#gwJ>*?viv1`+w&!&GcT zRp?}IeYqBKj4y1n#McoYg;|C54%pc*-By;r(CxDKsl4oRlMmRYO$!Et8J<3rom)%A zZn`zM2Ydsr#P-U5-w4_J`rbo-iS0T8y7t>Z*B<&y?}eOeiM){V;&Mbm!?qA5!QW-Ce zJu+ZT6lhwNKLIv~2UKNSOX1t5AaWow^@;kieK0R0^my-af8}n;fzditqOHJVlrp=>-Fc(NX4?V-?2J>J=Df?Uf-eKALYKlkxp3` zqra{0Y)_qjG_BOC*L-Qs>6Wm=ev55V`RXaWI^n+e4Tt=b>M;~?9fI}H(q0XBW##FKITi%`F|7aVTTh4f8a{~qhJp=lS5MqH9xq4@EZ1-RRd^D4*uoE|~v?WQ#%tQgn zWfkruWOIo>Ag{U1obf)QR(C{uIqiK#5Ch?rBHi1WE5$#JL&@*bDPJ}pB+D;Lw9!#O zdS#Go8J_&hK=wY(7hvUnRU17AyoGJ)4LtQ1OxSOLSj=f>z=-fciu^%pD-19jqy)L- zz!fV=m%DGeeU>#N}ZknNy!M8f0WjKc8b9inYv3{krUj9J&h}j2o4|Y+yI^KNgC}`7eZC0FrPz+{j z9IFF}^N!hiwOLc}qk|JDnVcC$kqq6a=gbY-6DT<$$3;1&kN_C-)<(?mx0oow2Oj$w z#!u9W8T9r~!M(cSp+w3h_-e65B)xppYO#2$@QC~G6AgJuOGu1)@lZknH;w)PhIw-& zP0`j-4!Z>}O%X#r(qIr4QtCqx)+^Z)$wo43F>zLi+S#$Xl2VVPA&xL{^Fn1kntO|C zmyp;v`C2I6KWhgh(UbrAN21qN=fFgSIM`F?U{^!*&BIHYijmh1 zD&~ab)A9BaAlC;zE9t5O4qZf<%5N?mPC%o2+$V7L!Nl(O8AHIRK6_3uwSPD{JJvZM zBEw`s_dCgW{+_PX+=WS}^z_Qsk8ddK$5C#rhNJ8onbL;8noh45BTVhunqdZWPrx^W zJ?j`3_5PEtXY&n6*Mm^89^iZGU9cqL5%RoRCbi=1%`6g-bMFb5MX?s%i9eNui5D|N z!v~-{(TsKeD-`?CrZw;e(;FD`Q`VjH#`E6UA)^p>-mRZvC`7cjI+d=%=^BEFlRXXR zOn;#2KJcQ7Nhs3X@AtSA$>CIv=l3USH%tkQXiMc#ZmC)cI52_TM!&@t-AX2(hEaTa zj98bJkpR1cE~6;d;$fryXjjJ#b&m`;A{bkq5^3!%fcC*beg`>SAlj#!eOx}q-eXhp zr``A4@cweK)<~F}dC)Z1=sd~v*Y5x_U|ez_8dZ+d*ZO(p37StJ&iO;Gk2aOv^Hvrw z?L@fqUl<_GigKPu%!y1zm`FfQ|_(`LeYrnAe{BTVMboxWlfKES}xee&n?`GGQyNdAv-FhWus!zui z%>L#fLj3{J$(j5Q_wsBsTe)&X4BJtcco)W?$Oa*(&~gD#)q=~;Bj>S>3z*x(;9&B zqo);}^$9Q=0mkPl2N+*)6~y>xM@pvU(+2-#{31l?HGuKe+W^Kds9u~0G5+=li1Ekp zJ7Jv%y3uU^F#gfI+~g`Ao%i+MpNPAtePJC)pNT~yblwAdS+!lD?JU?w=f39w7Dq$?G>TP(*Cw>bN) z`)u^;2$~Bt%Cy@vwm7Yzbv5&_fvf);J{(U`#+ZY^H+h>C)zYh@ zLz^3B>45M{Zn-ZmAE&H1KsOJk4BEyY1k{E$#)Kxob0^$RBFkGC4tTdl{FRH>bh^5$ zMY2{YZoZfmLl6vbMav-a#)eaz5Z?xTHaL-bi|9G~k$Zv2T#rBq=0?ub0?+b$hO#KG7|-(8Wdm$1!2`)$ zEV~OxS>in)(hpW@O4ipEnAa=)R)n$&BK?mQ0O?N;=`U2Tg0rr1&X4AUNWb@aV6g2^ z7eI6^Ge1SMw+&=ploK#P-|JKme9G;auU^F;`X?GGaBr`;1z?Pl7JxDKv|V$+$Jyw# z;EP)@VRu1{!8w>mq(3{|R^k;^QEK}GurV@eOeFzqjIfW08Ss&gJwy2qRR9|!3AxY& z6l!Vj@agZt(%-)2f34}xSOA`6z<{y-C3O65kcCA=L=fy_u;HfGJs0jr;<7?NODw@( zk?+78!lEA`bNnphHFI3;6Brk2YLjFyx!&#}(8#YO((Tk}7yM9SIm4v5c zv-9Uh%%q*FI#!JxDC`!#im+I6p3Y~ldn0p`p)l{pW*=1M_4!YlsvHL00@H%bn=L{6 z7&-DDpcl2xzhB?Gq%b?evz%jmj1Yrm-URAz5x^}#{$9DBWplq`#BrX~;073EiE!K* zu4dv9YCY>cIPXp-i)cOf)I9Z9z1=dh6GC|2wJhQr80b zN{d!Lc0Y#hbCJ=4hkzT4;-SF=0e}r$<5x|7LPE9ad<3uxA zM>FlvCgmz$?#k3HV_o|DkdY3Ra$cf;S>^=PJEYv17NWvYzcf7Kl($dm<4`jdW$=II zZ*dy*hYzTE;1bAlrtI*fuy%CaFKnvi%C=ZN+fDx#>FY0%d=5P^_67iVDaY4$pyiX0 z9qKp6(c3+Pz1d40BX22<$e)ONVkKEM@zM&d($<6{&&uPRt_NJ!2JO=xyUp31u7*Y1c+qfzZqsP|JTI z@jv80F$0jl#cS)&yibAIUf&kVX&I|FZD@o}r4b^r-Xs{fdS}WaAl3&|kueS-)F;Tj zDX$p~sp36_1F|Fg6XrLvwW~&PBsH{TO~}>pN9Mv1D?cT1)Nh&8n|dJR1e9*j{|Al= z&$03;MLkC59_m85m0JeY&y$3e$uDSvjWkTcdGKID{Edz9@T6&ai(2~$Lx$6h0ev1` zNF5H|-fCUSk-Z&+g<0wM0kI4>aBHR!;qPV>`#wOgf8P|;>xa4g$UPEt)S+yQzJEXA z{Y7-G5iu$AYXe%nvohA-TEACwJbC?wpOC+UX-Z-f@TNxz{tKAv zGx92%cp()d>bz{;vur#%uY^MKX9z+f>NFKS2Bi+RuMr4C+`TGPfC0UoBWOUccz>#` zZTgVF{w)V35Q~}WhNCE^9x1UHk&h()+Boruok>6lKcw|Dl!NS)nGmiklg zhjaO4vGD(RaXh)DW;nC~mHJbC5bEq3^NonPTe?LxZ*92!Ir7`Z5%8Jt)J z;b-)Ktl%y{3<8G-BMLV`4AXoXKsqMswr_7E;^6$=VlJ1T(3Sg#U4!`a31H1IWt@%7 z*c0)Iq6+R0SOr)ooVrfn>!Qz6X?nil^vE!?VH6KBoBtbdANv0{;C=z%_>iTk3~*#N zX^mYm2_W1}RKm`x7?WFvR$(&r+NI~~zMZ1mO$O-cg#S5kG(e8#j0s1d_OZ$(`v8c! zPY4S=LPMo?&Axrnv6)f&GnfnrBclj|Gsy{P{wu!+bM^6y5Cn7j8btJKRKH}JOlC+G zj_-3B*-ly?=L&pVG$8dJstcpT0-`{p^Da2)EAOw~k)Dk{``Tr#KQZ5asQ9=PJKplh zCDR5|RA2#{p@kXMWA!)aUX6!NJX|aah&fuff_V>&H5$nh(c>}-h>{6O zkdRcyPhpip5JbVyz@Wgu|3MliT8RN46d4>;5PgUsSP%rno9i;x&~BZ|<>}4&$hVt+ zw{B6&+XB-x2Z0q_QJlzb=vCvL?%<=-1~H162@}S3OZsqwL;LJK=6URNpw@uy8pA4<@7{Bwr0IRcHBnBayHhZ3;3U8VG2~R zEXlK3K-$$6{-G7$50g?^lVoGA*&AV_Pgozrpa;VM>T^#U+7iVlDWggaW4+MPEFfun zS!TsX_v!L+`&kBC=WpD-Bo0fm)XQ^JJvk7~SFfGIG|}Ey4*1~VMAEtb0+s6DclGjt zp_$}pWD0J;_GH+rL>o_kUTnaM(GR#La&Cn!_aSeEiDv~(QU>snDLsdAcu?YGHbdwC zZ)D!rwBf^6$O^!?vA>N&q{NkGW_p|3s##w34#n9RP4l+|@b?v4a{ifI6AinG)xwgj z!ZG~y*rkOiL$&Tw3!Id4R1Tg{owyN0dQ7{?A_AvlYitXpuqb-x%aizNztX2_BG=4GAbjdnQ7=)2Np!n*uRVJv%7InJ z;xP(Ex8|6b?^3z>Pv;ri^dmg4WNtbaeXMduGuB3w)cI7IUt!t$b`6ht&ZAgWeWI!O z`57{eKhO_I61f- zMw%a(P%<+}IF-a_{qmhFN?DQkZ{j^C?6{aSlog6?FEDr+RdFuC^A&e4Q92cBw4M+G z0#~oCQFMC8z^szZ7SR6W-ortSK>5=MK*B=!i&|2~0T!*==p6+lv!NY>KhlsZPyb zCH<$W7OM^eQ%Rl#d#bgeYjB5lC37L)rRe{Wdyj+$nZygXQ0;+FKo)4E=?Oz;@m6Gu zwvu$1Oj|e5h>f!n{G$1zZI% zr-D2$QU*d#g9J}V_p#_*2+x@85OA;I$=YEUmmz!rptkCBE zE26Iv*9M8`>GlB;eac~z4oF0gR0$H%_m-Y@pIfsoYyT0^_X2T}$nrpjuiXIWN79+* z4Nj)tx%YUy02t195$g5A*#-N@8f^gWc#d;GMDK69A%XN25Ycz264Toc zt8z96wd2L~)WJ{i5sGwQH#O1?;Wz(qxTT!<8}EgklGwOgw9?e)nSYsA;DJF$@* z;_?b=c^sRe*g0`LjBr&n#5&ISWu3Vkn#&(_ng=8B`wJoXdH(IzKvT#Z4p|*38Vp$- zmhs5n|p-R}2CB!Un1vYWbU2t{a!3Cy%3|$h!R8y!H59`u}@6pJt6<`G1?vL-K-ywim}RdH+u5*XRDnbiQlK z9_faqFMS45qFaR=Z^gvS$O=QVynxvVv zT0ky%$zf${CGtbMiV~~9&Vjp*ND;HikBJehmL;A~%L8u>le)sNz?+7*koBRf$Wwky zDd0YS(K_pkXvK4I$gup)T7a1_h`cm_Yg`epLi;hiBN`owdQ?0a3bfg5SzdAgR&Gf3 zL3|ljt-%x0KcfXYT!ucoVi*QLgrC+?(qPz>vC?|(52!BjZX(e{1bm!MR(ziGKa9^` zTj!hYYE1pEX#N&96=aNTX0FqAiau=$17`hpikc)k$T`*N8C75vjp8;g(+369Qllgl zrC!8ogt_qi@FD}(@?3CW{>8 zbUEOyVZ#qF?{7?gHIwb4qX`lcyG!fgLCYv~ywfX?<(1=!Wra&aO- zYR<1G_8C~U<{R4yKfCG2K~aIrnaN>Pt+*V7>iSb%V2~qFu?2)%u}ET!DU7PH!7!gB zQkXuSTa=LF%fcl1n~~ucCP$eqDKXmyLxO@}q%;?|nhkPPqfH_+$|ADdFuQuhTUe4kIzHsJ59-B0F5A^Boaf zWO59CYs%6TSG9|M{LWgi6YR;vw=U-9Rqtuyz;COC?9I{L?~v?A^|)|1p-VlH?Y*0Q zzX;_FhCWW-Rn~q2Md|cp0FaJq>qe5p{vN_M$DixY{X?iW$1{E?m+^RI-5&ap#Z4BX zc0(Ar{W$K~f&Q3z_N((_=3^iBxgy`%_G#f1iH??|roIDq2?9is{Cev25Q)ghmB#CL z(VrsbR8B`7R}#C`8)}P}wTQSLciEf0=JnV4nqUP|o#(mR-Y(Q0Gm^8kCKI|wa+)U< zKLpz%*a|^S_&YRLrG>-eCk)1Yo$)-eh<}U|3_>=RSVH3tdUxHEax`)cN4VHQVF&lk zD)`;GmwlB&Zd{qZkv2)(8?vHo$2zWqef-793Je&G9+7j@C&-tsf1q=PDxXXIGye_Q z%U4Mw=$Eh8Mm; z)li`oefx`Dl=n8?pIE%@8JgY>uKH!@hl_!) zblxLLA@LL!Ut&pQT@ez^srf8BTNY9w@;(bEYb)_2um2;)>QQRlC3`DgrvUfviu`_6 zlf#>JW?S3T56XRc_KVDnwzj9iY6$`Sp@r!7+h^Vm0xfI@R`VJ}F4zKAzwFD1-GVV* zDg9)|c{dT-tNcFT-4ihxqmH@q?C4JQ5!rj>6}b-xHWz6~Q?9WiVEQlz?4mr*@}0=9 zglfTC^Z2Y#fOBA;=l*k^XNJ}H3u20I@KzsTIM+LG$T?$knWl(1NdxxQwk?e8m#sby z`?oxXf2*i%w$buQera+})HD=eyb*O9veU9?!=V+CNU>E={rGWdxn=|P9`e~wWJ7uX zxp-T-rdP0wwB{3xZ&&X0*5rmcKK@=j+O3{Z%28AFepKaDK1OL}Q0pt>V>)(!1v1Pb zDE8?Vkv}gbN7%bp-iLlH!=}Szi7zI@WD&Bs{;W)6fJ=j^&^Lz0@jZzh9rIs4_rYqX z%aljmksXlMy=^viF2djkQx2WyXk+8J++R)>(@1O7!RbCE7I)iUH!ZC*b)O2v^eCUIy`S zWAxZ+_wor{`6Fg3f%{6|ntD&sk1}$nL$4WBf!8Q%0ZC-kvhV=FB&xB?w@bX1i&q;+ zjTL_#r}j|9>0!>9;-wrGhk++PsL+D`cCc&O<Ju>VYGL|H zDR$-&9t3lS*KH+0GcQIZgFf8l?|w)yjQakVSOFrji;5K<0KJ#jlz{l3FJ0~_7C}KA z2O=>mBUsPv70m|KnZM^)r|C2C)!9^iObRiZG>bJWX74rFfA&5>TcGSP4VJD_7n;Ec zFdVG~!}ncG>HVXdbzcY0*)(Izy%gpHheOzw&o_O_+0#u9ZG4bOdk4?ie3))O9PkUL ztj^5G7Y+_;x3+?jQqpB6ZJK7c?QfVe>5n^f_JusMd9i#&EWE>OA3P8ey(SA|?g<{E zzcH!S-Zu?%FNn`r2>{NytOT8F66e<=S?nFW*v>s!BRr+ul`VA# zAH)Zey5c$;W@qqm5g;XMV#s?Jo0aDz`tU^m8?p&5Ndt(x*%8o;n`$IP<`AIbQ^Op< z;?WhreaO*_l{T!9iwQc4)CIHl3@AiP*`O;8 zp-$DGhu0bQR@j&x=^+z?foGRRQ+j-%;nBQhED8;TLg$i1R+ac;h@VMjvmCL~Fj90s zA`Kl$U_N8!Q;;&oe|WEB;0&eA#X*D2ZXG8V$g6u`#o#TYUR8_yuj-(Nw8|DRB%Gp< zLCve{a0B;~PT;18oZ@$%1fSA2%oGa@M<$q)K1kX7u3zAxg3^wB%)Z{9D!^VfCB)E+ zfd6Lblej_?+q}6)`TLk&1k%&>cc_OKo6lFjelV6HR0LGyF_aN3gK4~i))YWhPUZ#I zob;=B%p3qthc8iq6?s4ARc^v=X1pe#%XIsudiHF6ubKA(R#H;kQs;#64`w&y}USc%&1iH%bq}w=eVXS zdnGV?R3{*F?bVUiZE{?yz-V+UR}TBY>{HK8QWJ^K0WZIv(nL@aQivHVRWlD$nvec~ zk*p8udhgx25CDXuf>1uOl`$7WKJOblcsz(j_Q(g{O`lZKnw9n56wopDTZLq}i=NMq@y_SyR1+lKFl*wef5z|3_M&4-UKM~+Pf zO52@z4z~nny#+QrpEeAxMAZdKde_Cw)M~R2HX=kEZH^-x)kpKc&l&tW7ANHVqPQk& z=s98%+5B)_zJE1f=qVsV!``8V!L;oyHX50~OX1z9p^zoY2zXy$R7)}@&W=oE*H$OT z7s@cE^Q!v2!O&Kk8j*yMzfNH5uq4{942izbe8yWZ>jw@2MC@4wg(nWvALCXlOY44c z@U_@z+ zAa4A~GZ(WW4vS0s0e6IZzjwNlr-|xf+&qk@1ifYph?wFLNb!`{&6I48cFogrncGm4SmDwbWMJC&9-#Q z&SPKRN-S;21wSq$WDqocf92O?W_+TPt>!ad7+@T&WX&$DEpO4}i}$K}xd^wQ!D08A zXZ?GQZB&VW_5Q>R=VuEVLj?246Bc&e*{8*O0wE`KYwBJ`4z^h)cQgC+m8N;ij>ePI z!rS&P@%bF4fiVHzUHgyc12n8sm`ZJMrJBpm87A=dM94C|(+-?OCqH5qTCSRiUpZa# z639E?ZdgItB(f7#0~HNXG<9=&#)FAEhhmG1kxj{6T00~YDn!8-fBm1{v9DmFv)tvV z)KS(7*>~gULlyWWbqTHYLuR}jMmEi<=atxfnqPc6f42VWUwmXSB-Og>^eZ=FNJA(| z2``7N#_Wi?EPk2i^GEuG71hKm0F`jp+8SP5K> z?9D*%+5=9J;~kMQm~5MA;rHn3#$-w`(KI=}nAgC}w~84UEH9Np^Y7ZQzz;1CG=oJgXPBMs?T+ zhKO$kJe`5S+}tn)wv7-8CWv$G{Q6dj(9|58Vg~ z4_w->juh|Lqxx6yC@{({US^}OZa}IYGuXg|0?h9d!Y#&ny6?$q-!ZF2C^+9_I`QWr zGdH}HK%kcgwD=OMcBvZbc~TOScFlZlD1f(<-t$@4|k{pp7MZ4{U=9b!DZRtAA2;v%=3CL%*e21 zq1F5~{(=H+VNJT9#vB)!CYvkr)o4@!YiHDhd6y<`&E8>evWcs4A3~jY6pu^IBxg zp$I6a@cctGGtjLz&GY19M1cmt-Sh0=-wptq!3#bO(ck;^9GC0IPcueoA!UEw>7t*Q^0j8ReSVDu&Y@Dr z%G^|+8fn8}#W$6ZpTh9r?RE(TV$!3N?5&yX+_A0oEq3Y1$51@6h7v0YEQBI!DhaJaes?I$WEU0sLbAR2aZ)Fp5E~U z_Xa)O4};^)OxVDk^pS;iP4<9!dAMOpL?-rug{9tYlsun$T+RbU;q*r<)Rn;7JfZ(U zWL&<`{(KH6%b}$A6iMSg|4J`jzbfQ3djneppu2#=0OS{{m$E>`KLfm)9+m|veo=}9 zvN*a(sxbLO4AN2$5~?4#X%kLo0M9pRf_VNLC&2S;X*a`kSj@VaB8JCh2)@lhNA$LFa4954UwVWF(_BZ%XLDA}of?zkhr>~5FLVvG&Xu3DB>Wd*5Dh9mLMmMKNoNU}?o+T+tMF=vi=Ci|8 znIpjQPZlTIu68mww-W0H$x*wB)6nN@b@aF@{6f{iIX@|M-o_t$Q-s*GQRwKfIkO}s zEX?o`DcTbHt_MO6MdwS}=5OUyE{PqvOPs(lUYk44xc6H+3lmv;H5hH5fu*-HcxM=t zsOrN;+n|a5P*;f@G{dU)){vfNk4RB%gloaM{H8LLNF;>_2q7@(h!8@1^3ShSJY?R{ znbWG=52ywl0tG-NoL zx>|Zd#J-@db)PLuB;27We;i5?8xv;R>4WVqpz&$}7E zZ7&Bsw{!?`yBC*XOFvpPa7l%KOQUdP5Mf5x++-9jpP|CQD3~G8$5M!z^v5_dUxfpX zG?-5ion0(ySCP1F+%Ui^rCUUxq%cHN+rZTc!qOv5yk{Cty+!0xn>HxvhLWTqV+VKi zQE_dM^?i5c073C4SX1#6Llr`0PXz!Bo8h7Oy4cm@Wi5o;|{rf@|XWCx_S@+)=;R=5@brU<@)n^_&=DaH# zQ!;fUXqZJ)c$GG)!m6H;{rMMS9dYj8N`4@S%~%1i!DC?6{`}Y7dJpoPJtX!r*qu*| z_s{hf_*)0%RSxvK<9xZ*hDM{>eZ7sGZTznTL|nhbS!JpPzg=AQ+?v_Fq+!V5G%(HXyqm^8`y_@hH=D$%lU4-H11M)0-(C?{+2(1lXVBbf@^Q1k5gz4G2 ztj^2rgz|`@V2eqqpld*3)5}UF=u8j-w|GJ_*ZvVZL?0YnRrU(^)2Ifi_-KZ^4Ov?9 z?#}&P=;6}-4`p8&mDLutOLup7cXy|hAl+S3(o)i0(kUS&-QC?Gok~cjh=2;n-S3N@ z@0>fnG48ly{&?ov?->4&z2}kzO6C)xivJ80ih+OvnzHITMh;Mf8~s2(q;86;R8gN7Na*Lz2j0 z@G*uA0M%mr075@Oa{6e7Ncc+FYqLmF=~Du8csJt&!SroA(?mTlotoc`uRg!gb=-vh zO4o__sz3Xy^+5-9r?=3nU$-A_Lio2;yxa^sz0cNw|MTALFPY)D6L)VV59zw=9@pBU zyuBwULK3TIo?R{LO-)EACD70yDo7=bCl*;QCCeuzB^AZi5X&Yd6n&#*oJyTg`? zk(*&turaKUVTMJnf4e;~LeH&+{y%Ijn7e&8Ag;@Q@)5lW>VbL+8TJzWJ|xOFVQeB{ z?CVe})-$=&LD3Z$z91D-?3E%CKJPl@1i;(1xX@oiM}D6r9v<^ z@~pe|!iT>7?^7ol-@I_gb5P#&FG0TjuE?tD80J2fLfkyrs= z#DNu!RqUyfrDa~4cnitRd4FFB*`cFp`qFt9LSkLO`3u6kkrnab-;~8RWOw++f!SYI zdLr&#Ux>f)d&*~#Ql*O37&SqlQ#3a{kc{^{e~w%2=r_kDM(VKm7vQ%n=+v8c$fb?% zE(4}+j{%mxshXAOtlIMpmtS!}4eGpDTF5}#$@t)w@Bj^Rp*gef`)WMoraP+YK6T;D z?y46Ci8AAF1Pgq*DC}>Vc`X9J5LKOig$Jt%+In%$1ZkaLq-M!!BYiPWx=m zkozriFm?|GK@+pu*>vj$DgG?puJYCLYFxu0s1@<2BLRZBdOEy3;qTH_684H$=KA2D zsx4Gv(ZW9D&Ss(LEgH)Tv&lsp;aix7O;y{jFT!5`D6!0Mj-B4iuxtgVu-yu{Y`G z1<@^y?-;O49wW4qe!FIT%nf>(Q%DkIun7}-Y|?c7tCgVX+kb{|0}y57dWTyl5kixk z9XmrYwu{95j7yNK&4~`5T68MA;|S{@Gi3d8>Wlmqh@77#0LXdnS7$h|I;T+@7Rzqg z`VZgtH;--b)$`jNkHf!=Yv37}Po+N>J>vU4zMjdNDA}rRNEoU_lbQE|?engAN;D%n zwlmf{82Ua1=lX;0pUU2mB%%UiDG^Z4NfNG5&r5=mVUkb=MeigGc^xRKzrpXwg=sx_ zf4TJ;$+8hHX~-kI&9Y@7jf*#O9w{*tIX-R1^E~mjbrfy9h$3J(_p!C=n(k6lR8&21 z<~en|e}f(`&JV{`H5eUIZ4O_xiP{9+sMa#1u(?=0_0u{3cuG9J2ikJK;`F6Yrr2xJ z?`@LzWvY^_WXYEk!28`Z`NL|M{ma$C_0RQ>2iRmiD1*?K*c4=u@H;_2m?iy2VoO8m zCGH6+{DDoILd?HD(2K$!VG!7~T_%d9@54q|FKpbH$9B}MFI66ZOihXx2mLr*jYNX0_fVxIKw-TJFRcHtgAh8!1C z2{td*NQvfv_+7q6Jh&i9It~OBsE}R?j?tiGo*+q64DHPj$>|A-m&RL2z+-5FQ19~5 zv8z4H#61zM?=Yg7`Sgc~K1p4Vg z8z{mOf3EA~vOJE}C}qzpp>*8qfwH`3gz9{f;|W|vD2&qMXzz*;)zjuvW>AV_r){~! z7z??Xl*h*pV|T}I%$x4Pg*ZjAOXb1yVxAOh>t{%sphCQ84k*Ntgj~0+X$Kg&edk!@ zK!y1Aq>WhRQy~sDo68b1DU1gy#N}`~-X@K*aElu37uZBw)tGUwpzwuEnKpztfC}+d z7T52!gcHX2z1A?+$y_UyZnvi^vAwZBlWp?EUw$iuzM}6MIVFYlPJji7Mb~xTK@NmZ zoyfSE_=jYv-a(Vdmc|tRKE~ok;r>3(##@& z?`!s=Ndt!bTzs>p+bQ6(CF0iPg8b3-@#l%j3+)tKD_Ol5oh57h?61FPm4D?5VnjK^H5{1gLI^Ul%gIPCM$S5JE-(XDx z8=F;F*tz%HE5>?&tbdN7CzX~!Yl#Sexrth}M-)qaN(zgWAAq4Osq9KG+2}@S>oZNL zCITf{Ec3%09@V*bnTBu#WhQY4rN3f`z@Ya@e@$313A)4(DS9O>LZg80eMCF(H33GH zX3C!YGJ(?vAsLP`#Vk}E)!>j(R{G~QDnaNAQ_vZ}AV6iF>pQ@}G44S)1e^$Bu%zWs z#M48>XR#71Oh^ogC9&M4FuqY{?`R|JTrZUkeFfZ|)%J|oY=}!$;+)3OecywG%37Ns$Mj4Ew%97SdI|VkLvsSGIdX`S6 zJ`{ElaG?EPRg^3`V&}aV0|0c}?|(lWAzrG9;GmPHM;Ld|p9A{r>jbB4IA7 z=0}gGlX*FX2CT~mWEEV)eK9QzpWs~ZcM_b7r7uJ7qZpmb)t!P1JRSe=fk!9ci~7@DqLT13vnMFFwVSa^-%+B$b+BtxO1{h_I#V|*NqgBb zXek{crp#wqPdR0kkH2(I5Dh>^YVAsl4vleq!`F6%Tf z&Ni+uJPL(xLGy44V$*2C3j+iAetdSimSwp}W&vUzlQ4eNS;qD{bUSjJx6d0@-tXV- z`4y(-=qmFH0J4g!fcCtXOK??gpZ4vCw-FA!zX?aQ>lR5Inhp$2EA~(n9J(XrFU;9` z98+JuhCENcWP9+9%e|?4$1`ozMmG#iq@zb5XRvA?!RylK^D<0hAgjB|%ox)M*z@Oo zxq_ee{0TepJUAV~juU6lo{y#Wch6^!2lo7R5i8{qV9(EvB`G=#9-*kP#Gnmf;Oxfd z=pJIZl}zCvpM<~a^8+CL(GND`t$m7_SjMZy$@Km90K>v}KX}JEOoAp~57XYYR`YXb zWU(s|`~p##TQ~x+e<3wkgC!r#hYF0@c65GpwEOKVEq9WP z%KQ%9C6+4cvyZttuU^W$N8x|m%44|rn2rv;_OR9Y*wz7W$8!{?;i82 zmlNp2YlLByRQibZ1YA~)ojWw^D6>fzueih-X$F~5SP?G~F54-MCn1_5&gJah+2}jN z%e*DWaUip`I|%wA9H|V~Tu5z*&G0j(2I_(hpvSfv6hLk>dgf>Q5nPCF(!gZxZex~wScf=mlCM@&HJ7$LSnz0x<0#=71O=9sPRdazpjRl`WTdzR9_xxEiqR-+pxdZpO#dKsS_OOa zD^TA+;>?#yF0CU_UvCRko%1XRlCTDWs`IP4xI|T@mVc`ALDpSopgI?IbQ62m>!VQs zROf_P%%JKV!WbUbIU)V2I)B#Ws~N7zU6e(+82I}#KY%#c-&ndl(RY`u?ZQ_f0feeL z=fa~h5h9Z3GZeRXEn+mcm&sup)VI>R-M$+r#cW3B>>?>XJq-pvcse>UH8((1ssHY9 zfJu(Pk(oDnZ~5a$eZr??R8{=+-V!vDKL3|77Jx({5_>{Pa6vnYUZ7Q#L~)xRy-q*9 zKka=J>~X9;p)0DBwRQbNa&h2ncPpY(aQ62u8Zd6r0g%+5T^qdhp4<+$T_J0EV~4JF z41(Y6m}P-0R^Lf6QwX`Gm(^KmQwa({i>);L4mBjFAcN=octE1rl2F#ms%Ob$$dLLY zWi@>tPtak}xM9FS)4Gt07*}Wgiyi+&>CX6b9P$$3gTvlZ0!N9ql{| z_xpL4QqZn1yJ6Ek_=kS~lv~+8CF}*-_4m0snv!E#C7lc`Cmo}kx?T9*q1p_rIyZAx zU6Ts>yo+nm(P4`R&uY;l7&DRLP38O}5AQgo1@ z$o+Fuva*)@+i^|V5+*J!OlMIt!*t44Yfdd-e2<;5?w@wzaddk@b?M3If=5T+?PdTn z|H?!)X365K3nrg{j2kKC6KqI98sHPA>u(fILYhxYlLqRR3{Mei!pz!I69hVzH2D|) zovXRAXXI`>xSNA*qoSBDw<$6eLUw8v?WNZP@%DpF&a8&W%l%ExRT_rOnL)6v+UnJ* zmsZ`t%rvcT`{K4>vh<(U{+aA<#EBUbij%#UZ;#Al3812e^Equ%o^CJ)L9D8UvCk|o z51nM3!j-uik99230M9dsgMvVA=Tgh|;Hv>*RzyJ6_eb2PV8jFmtmvuZA74PaJhPK{ z$C5+$vGCQ(8z{bC2X!~HD^i>rw!#9NNNhd0{H}~ke)N;)jJdFxG0{Q zI?0zoq>EZ+rs7$%$c*Oy*lb&Q!ix)d-1<&iTM?` z9h2i@+W2E$u5O>iPE5J19txCM|0oKVX_AXw3$@=OYK5x~`U`R+yp=yaL7i8_j~Ecb6qP}rmHv+L1ko5>HXa6-#dSz{qU}{< zKV;rIRdCEsG_IRxeW0W-@#dPs-cyqNnYPNDXa3X63;lD*?N*mFv==+<=aY?}Yn}Ll zK3;G4z94Uj26rhCb}j>7OQ(G82*->}xVK%YJM+v%HI?XSI`FCB-hF0PCqy_VOAX3L zfw7`ssP*j%%HLjG5k!M|1KQk+{xI*OZ1pjxR2={aqphBah-~k}tcr%5p3jJ(k2&3Q z#{<6!jylb>Nq9~WqO5U90R8sU8#HZ)JdWk}m?0W-seY!w1P}fIo19d%IPd~n5NH`4gekB25PylH~@6~1oSVC3LDcAfQ~0)t7zF)wR z?iBRpe!YOR`SCjB!GQeN>yRH~JDaG$it^Fvqo@;HUHb0}IDE3fZj+y^elaI&uq^j$ zZDai{Iel*^#H_3ZxCi=bLciK?xmHK*ETao^lRWnKe68tDhXEs{2`;x@2*jf~D%3sl zBT-dAahn6PJqArTTwl|}NvyrD>-CkukoDaxv-LY(yO6bfzBlZMU<5`%hOFUy;HxC@ z2ECSc$@`1bz%y<-ePEZ3mf@vU15&ssQ}x&n)3?zT94pL)J4wKs=*K`l9`WtHA0wj)u(fD+16zwYtaz;N4gA+1E^_s<6gRrKmFAbCwxKtHCpA4ApEPPe z=kQBuG{(neFuHlv@=G<~#%9B1+x0b6w{^G-6Hd=A$T4rtqs^kwyPj9$of}?kIBbb8 z-#9N+5yX3Uyb{=-G*Tkzk9m=KETEr>`XP0ER?#CtJBye`^K?0J+XAK<4j1X~A%YAD z+%buvpnl}12Rm76iB{XNnk1WU9`AQT!zWZ*oRXAUoI2f4tX11RsPpi>a?K&1vej*4JHGt%_NW_m{sEsd z;#H;8LwjW0A8S;UCJmGyKSeCwyoK^YH4a(c;sxO3py>f$Z4R=}{wqIh>JfMlNr8h~mx!cZx&nxBRR@QRh--haH3 zet%A++HgpuO8L=?_<2 z2wl~kC+K)u!sCu!n5>}vhYd-2$Z@rthm1Vpi%+lxh5IKq-`RX1w%N*F;!!tST%KMm z)8)**-GixcZMbpp_|mjA7z}-oqGLFwH5|sZci2 zr%6|Y4nVv9N5alP$V>J0NzCqGC$p8BK!oY#y;&RqYdntLS+G+aEA-Az%`tCoM$9*k z2_x@@Zl-kCls}F|h`79{c(H%ZFR#2x^;#4Y`n6GBd8}#_zM=xe5lOsuW?auJMD86e z44Oli>=aIyk6Nes*B$Tq*4>+4ymMbnbDR39rXFeC2T$P#-*~{Zvh($>pF%s(8Q#5C z)SmkeiNQC7jxA>?YJ`UV$wY9&O*Z!vu%Y@SzQQ2D1qYc@WbjS|ZiNB_-u7Y9L}nBC;X$Cv|2xu2&rd{D4xhDcoroC*!Lvl zY*s9`#O44}9Q$k+Zzd4^>{Teyc?P!`@W{F$amJ^Xh^p3eP@4A`mmG_DE&YJ?qK7O) z`e8Ift>=`BuAHX4DA{?Slk6nUGwTK&@p6~Hjz9O;e)aFh*8x$jN8`!`e};1dKx08i z86OOq)=gsucuYA8k%hVB@`-FuR$K#662c`|lAi#w?a>hOwpY{{eFOSdX!BifS7?o2 zQ4kd95xdz&VGtAPEtYM5yzzLHVzeTYw|rSYZxwcRkuwenEFeb(fL2_dGN~WznE@Wt zrx%e$uDX)ZAD@f~mV%^yL6hnI;=n`4ZJwBzD=)1Y0uK1du$Kn|ApGcCgkcbY#u?80 zp~es!Fbq`IU+vVMIj3Ua7*n*`b>GWf)N9b^U_aasxtKTx^zf}F__G|?Xmud7Dz*!_ zR@QQuHrA)A`?5Q_E}c2xU0Z%t4>fl+p=#k`dkJnQ`I?C%!ReT_bJ^LUH{0p$REr|U zp{qCwHQn5Et&BzmZJey#7c`^m@vl!A#x3eyE4iV*Abw%sW9^}_hu!p#{xUko7q;^g}=wPwp}V`&Ux=7Ir|IA3GJbPl#g|GB zsQi@wFk`W|RtK<=I z#*8EY{5Xm zfFhJ}`B$u#P9c^pST9K9KzslQu{#sYAlZA7zb0`2UMd>9rLG`Li|qK5dDNwx(4C~5 zZ2$gr<3-lii~aX>`f1y1wE7iqucT_kdM`M=SnRbEm@7PcCpo_Lq?unn3?>@gvVr~}t(n`4W#+c}m<@@T_<1yP0 z&t`YKWjZOctRWgW@u zotm@TK36ojX5Nt23)Z)tP%Oud3uQyMNw6g#??SanRC7|{|0DtCx(69rNV9!w3r&de zo4z|1XUWs>7sH1YvP#(1^DkagvV&Cfpf}Fy94F15d!bExRD<{Zz)jy#unOqu z*_^uSTM4Lisww)Y06je_pr@xKk5vZ!#+NDc$IDZbap#94C{9VT>A-7(b=r%wo@~NoE-a1#;`+r$FxF;F1ot z-jSE%US2p?r>Q0XUZ`{$2DIDfI70*bJ*B8LXyd162RvpYk7qNvdAXS3Plg+oC>`Ei z5}nA$*>P99_IouHberwdrMBMsG!qGCpp~F?Oc4k3Cn{`)$#~=NShzU2Dw>ZfB=ySr<++U7ioO7wAkS7c z#OtDBh`l_>JF=UV6G3m2y_IF-JoN*c{5b1!MxZ*%-gt_4Y!%CO3VGLI>h<-Zk>|4# zi>kaHft<=SARif@d%M?KWB2+!r1Gudb4k467VTz8`-@`4S+2sk>D<_+XcX0Rr9p@A z7f<=f=TrX4tt7+c98f+|Rj|=S|9-o&40V2qtObr(a4W&rDBEP=hVsO^Bh&tq5cASY zBPv1~!pW=^r+rwO5Del$xH?G(41-okz)3`tasWR`L@SYTC<-AHK~aKF%|ny(RwFDB z#64a6R<=2M6KvdT@oBq)j@1nautei zIh2&v0tv7D6!21m5n0`BNl#{~ZHtVTU2#g!rp}#r#wABq?r}~HuTp$HFXJbF$|3r% zkl(;d4aQjg09(3Q^6&5u3c7%&v`n5gMv`V=S;7%V44A=-@wQgcW|s~Y>u6Z~YpX4j ziypr>hMyjTZFVxf=yLTsZP0e*U^tl~f43~d{Hm+Iq>Mz^u?!7ffmT8=$9q`84E9nN zzv)@8p%!m`^jO-;=*LlI9{(-8>QA4e^7~>@HQ-nBMa*%52VtFVLEVap*yhSZ&)S2^ z-kGY&=TGZaRKyNzwp{B*#;oi=w0?ORH{~sm_C``pb_r3l@8J37eK6x6c|Y;h_|z`8 z;BQ+Khk#Z=PLOXf_^HuJIVcqT!g}i5H08^D<>T|_%|}i0!i1No(~Xg(AWMoWoh}a; zh8QUgkPcrn7B6TAzLf57TjYOl;z%FX%HYuiuW4fgcr?EZ^b8V}7wQ}q)ECq{7ndt6*Ndfk!V`+!?faOE>YLS^J4e-1wUeb65aL98WqnX z@`<1Ni|0}?$!uvP!Yn8ZRStVau=%{gCq8@?K3uJgQrvCqiS~poJa_t8Z-zwc$WcQo zM2z%!o8S!;OjiEzZIi9La?`SV#>)WRri#a{Kl{^#Mt5{pNe&g0UpBNV%}X+@Qw! zO3L$UCdM~S31TKQb`>@N>r-p4Gs9G9vlFJSt_ZL`Q?_3&4C)iTaA9(r^+&h1YOH94;Ex3V;OvK5O3vWQp<6Mi0t^~1`KL(V$?(?i-phDnA=wOm^>yz1|{&Sv4?@b)|rPBnIXx0B{xaF&p!$2BIY(OfhVLmxMfL)z;icKW%H&Ti>7@8;L3Di?0H6Q3rIL>`@6d)h3fAXf}bkZjBGFFn$o1-hHY1- zvUWC#H=5gO&C*$^hHJ}O(%;gm^A?s^nhHtxe+BJKp{e5Hfb+786RN7P}xNi6@-^k+C}PP7RV7qf;=L?$w(;0 zgu4j~veP9fz31R44;qi0EE8MyRC%CjUcP`rJ&Bj)-Odo^D|Ty86tZA_H`~&&wq~@6 z%~`tI)G@x2GHknXDo&4!qG2ntl(lU4x2_`H+H6l^XAX zw1Q|hEP3Ep(vP_nrZEE-$k2X}YGeuXHVz0F*DcIqm=K8O$z~o=KX@qs6B$`kS7-4c<+37Hxlss^7hvy zki`FfFbTN7I}2;lV5upsfqGmYxYHIC4|re(-!2I-mQeZyfqWe+p|=5IfmwGSsl!-B1weD-z+`mD&A9*7s2)YI&#^?(ip)KjI6Yb370; z|K(P~;Qnr(=K{<7;_=1ijU6ETB-Nu7u9)Sm1eU)+FkyORF8FWu6K^W|mgH7cqEc(X5Enbg5@$ z9=0|c(=uB-TN{@iw!b|T~SJk)Dwy7Bz6_vBpa`xAxc`MuEErzp<5IJ2mrS!svNoX4E=6SnwLdX)8B_+PudFMK=Y&h zM47+zIZ^l4>d&S-ZO*EzHHpz zH`(Jby1ekXRH!^20KE#K6On>r!;f#v@r#cuuLQ)jX5Qq;%i+(P7D!vKj(9Jj(g}s4 zy_Y`303c2|!j^58(j9?RQ5Wz=K1lPVx3S)iDq9i>0@jAfe5k&+GV1u4#=I1=%j7PD zgDERB!dkG7+Wq+3pta8!D-NUF-&be$PP!DIO7rnVIEWOOUqUBUDmsq%9&1Ii)CT$V z2J?6iO4z53^Sf*DvqV9}leo0zn;F*2=vO;9ySb5FcdLD6LQEY>i|=s$9vTLn9k%q% znExnh@jOH0R9;_yU#6K~%#CVY_*JvK=99svilr+?px8Z6RdmdK4ZP8Bm??^%F{($W zP!&IWd80o5?KOB6ucugcHB4U|wdgI+9w6T%-vh5G+Omlp!L++_5u~1v!vL!Y2H9?S zkfV9SAluC^mO`~T;kYP@CGlj9*R{=Pdb#Xcj=0R}ClWkBi+ z^;~V4yVM?t=~~M`O!tsAa#Pb$@7>Yp-B)@8#Pt68_Xg7V!_Pr69dQka>9LhSOwXNX zeaD>@HrtYVcEFR~*!vQ50nS%dE?Bmo;g(iPBBT=>(*?S3knNr8n(S{tF+Ga&Z%hx$ z-xyVhe2VFBZ1#ovrWK>sx<^^ZSRs2YAiwT62X0{fd!k*v($j>yUT#Q=RoYc6q19rd zG$SVQj@X@Iu0VGt`sPL5o~^UJVTg-%=wy|&gLsvrjG81CePq1rvbyGlm0OwEKF_i` zt_22T23ox`Hvys*zTe%&bx}H!ht>2Sump!Bb?QQvF2dIw=EE#p=CqLQ0A>;E?!U~U zm*rL&e16McW^qZ8v@?2y<{K^8hJM@W63ZKz^j0SB%5) zP@tT5EjnWJtF7i@tkvn4hQo0uAFm0{$2@b56&$`W6*G+$%?o@Khv?5Z+5IK8Webkc zpWXfVWM5^ibLCA!en2k*Y|u2X3*qp7MeJ++0u$b^1^geIkL~SuzgGM^-Ule#sEjSXgQ=3x$%?;4sdIyG6(u3^i{72 z7VldN12(YB@fJBtK8+QB-^H(Okr&;rs;>!;6&ElqE>>Jke6>$I`_Av(A4HBo=kyN{ z)FT!sJ)V&QKwyJcBPx-4s2{1POXRqJ&ocS0^j#^cVDx6h9PR<@>FQ(94ahX% zRJ%&~U@sQ%iVG2bs-wlIBuYG)5oZt)$Kd5J#D%|1K$rYZmdjnsM5Jos2UvMQz*Yb!SCKOmtST9GwO~< ze;IWNMWE6X&t$ZuuYE%!UMY+E7#Hq4j6O(XWDrb6wWFkc<#9c zG(&wuC`9z>D0O1_^R9(laR0#;@`iej}|LOpQ^Dme+!5?K+&uQxaMav+kgTna%D4ehG{3o0b z4?xWbL&W_P&eM*zR7L0#sloO|EB2@M9)_U#cm`L=#%+=*2=7@mtl#h}XDVfK?iDC! zUVl>L-y>OmZDC0JU_{1O|FE4d830^SLcQ{AQz;mPqhXGrpV5f>74v5V8wQUG3%jsrDvP8Lqg7m0WlzEeG5U<`9Ik?#HC>1VSqPnH53NqpbSLa z$PWma9VQ6Qj@D@HXzgPfdd`{=H16h^t_Nu;k)JB3aUZ(dCJcr?VJlTvv#=q#NE*^b zBJTvZh7wb-wM8S3;Q>Ac8)6LdnD)_*RQ>h6WlVlF*vg$5fD`E4sXQm37dis#c_j8u zr~oAZ-5J>Rr?}v?g{RbbP=ayZvWyX$gYH6wvnF^70q;&@7~a0J}bB24dGall@ubT>y4HPNO}< zRjQ8Trm_A^)0ch9Hx0tE^4gL_bJreV*P*xvpV;+ziyn5k^vrf+dl0)G_61R#6M;C*lH?(?5xMk(hh+sPW7RjlE^9_-kgVci!=lU^pVymnBGFie%{)6dUG zcWer41`hVa)FV5l2Ju}=F)|7Q2m3o4FK=1H6grXm`9%3s2I>Ev?YGWm%Z^U2UQ4SJ zBv({lX88dTdJ%YI2x~y%Z$c1<%yS9h)@ZA4t3;D|onA|55M7})}$?L_Q zm21R20|WqIRM^2!#CE4zGn9$9rDs{IJke>lJ!q{ar`CUoE>Fw7-ji!NPe#Q(io!L2 zn?wOZZUsYYThv65+FC&u@RZUC^#@4OZY^$@9SH!_-G*v=N4g#kBH0tW|2LAoM4^r* zznkC}h-7~YBH5j34H0$vQ>njFL`XrIz(9u<->kIMRpm?7d4$f zby~np#6?t}4090t9qaQq@nZwSh}b!Y05P)D!8vLo*ni&}eN89>x<{H38}(Z6NJje2 z&Hb-fz9*}M&@&93XQz75@u|1{QqzH6ah50BOI3@&0u=*51_ev~76Eu=5iYw{GiSyb zbaQeDJ5oAOI`EDEowpaNiLnR4|6D^7yX+h}z(IlnKcKJzc#8ZaJGCTfbkrPAHUUMC zU(nL$2C1XtnI4*s(bfI>x`|@`e<%Eak$@faePVdtg8`TpSw|T zB{@g~b9C%Y)Z}DFDOl0ul=?tHX!!Fuy0%PorJOdgXLU+tiIW^Svi0ZW*0z<*8}JdXxT%TAUs&I`3dB?~ z!)4!$zx`FP^dYw8UHL1=hno;>^E%|8bY`gMN~^tm~S#GswRQfsC1f9 zW<~5Is5SZvXpP>K0*xJ|rz^Cl#=T!FLy7HLHd6{1 z62-(&HpxlD*{1vuQMh3&s!4zP*S*7^u7AaxC+V0M3t%y4=atmwqkv^PqXFT|X_?N3 z2%5|1bG)709qw^haadNWL7AdZi3{5Ot^pnSaw9RDYdH&9NU_`9h2e&nv(?yYKauO79)-})BFMZ`+gI*HP~qD1H&JRrBz z=MtlD95VZRA$1Q_(jt5UWYlL=fGN_QL1AeG4pLe~)#Q1Cz7194_(YDuM;g^TF>F=&9bRl9RWQ;Qn(3cZLFRLM7HASRuEM z=8LLdsRD2;HG_sOGejXN5jQW9*TlQ<^(tg~d{GwrjT|1RSdDrQ6szSR0ve7+Khz`gCW03c25ZQ?1|g99AeK?@q+H)FX( zX{U_ht1)xAT%E2=%}qludS0CkwFWk~f00s|+XHG6(H0n_5U~2+ZyG^!4v!w>YGJK zm4Hx>K?^q0w}G2%ZU{1%uLg-P%^-F!C zuQ+L1bfd@j@#qURJ{0xSoz+wYN71$i+X{ztk%xpbJiiAcqHO^cHgKi2U?c;g(IukM zRhY0(I%&<3M5P(*mn=}e5^DOZjs!>hjEyJfD17qgSpVqCxTj4Pm%d-4#7pTG`oc!4 zhvYjf$Q(%Br|GA1ch}slfh$c;8osrup-F%1&f4cryD3snb>|J2+Z!VrE3q?m%V^8! zt&J-eC(a3a4VZ&oL1(mg&^HkIo^+a#t>KHGZRR+5seL&b zWi?e*zdRh-Vc}|*NFD55`GCMK@0?0Ap`TDZ6WCKyRJNdJCT@#Luj|nW!e!jk{;J&c?8_{}jq| z!shRfbEe)v007CET1W-#VR=#uOuQ|M*b#9mL4CN=KvznzqJ`{i)Dk_O|_`db ztUwqr?2&<;ObD#K&p#ldTrWEJ$c#vz?A$xcmu(=EBhiyh^tN$(10-o&7|5-qKSlKI z&#kptI~|jH4PM1(iXQC`kK{&qxXH7-%j?POMR4S3FNNvY>}xGiDkD7I^8)~mxKAje znN$WwiDqb2t&?BBjBfgRlGmX3lYM;o>Ya`i=>hPzuanJCFVjhbMnHomLDOQ{9c)K^ zr^7fVMBoKpb}Tz!*bner5Q8bv_%hM>3RTo6J!j+yrpg5Y`aS4nFR})ba~9xbZ)`eJ zoC=!gS6drTb6gYCuWBrKsnJe9&`!mca)%X_i)jFU*$vh2+IU(^R)H%fftNic_3z8> zuIjWaqxvFrnn%HnZW#9<7S z&(a_X`NxB9I=X=mjM70R4J?UmlkF(5S%Gxa^&#> zk>%t;)%nbaNbSMZ`SxaqL}h2d3M}qTFf-Jg z{J`rDd$kP$SB@ukV^-ayVj{_Vg^9c0EJbNX^<>U>b7nh%#V8tK26b869cPrH zu37@XAg(|2xQ5AcC0wAkav`086og?5NI`%xUD?oESPXdN418i3K*0&^;lIofX|@8& z&AEghbfc`}>1d8#9VmRuy8b>{Y4ys!fF3$&yx>+T(AcL}tDI9HD7_&?Poh zIalll3QooLY3tV$zf#}OS~fHAyOvVjw)6FrzG2F0^QmhnFS6#LQlnC1xhzO)RfCnu z*QH8}q&1JyHMc}&!BnDw8^WrS0XtK(SW%L9=4!kwa9aK-L>_8ZEXSIe4hGHsC>zY_ zLC~J^#@V_b0p2jmj5e$Zum8Bh%5kwC;0>qG%B`#x)B)ZQN$bG5aS_x8s>ZGf4m3wM zD^CAc8_516z#A^@X8{UE;_3e=7~f9?TBB#U{1v{S<_QhpzE$v12HT`Ke&>cb{zf+= zh3I}B{Eq|3-`;@%WLqFNi1YCZ!v6iY8R$yfK5=xMYrqK;>JA_qeZ#5=SFJJBZ-~gb zeBT_%gts5uX3Ca<3&Ne%tztwNfLu^)tzfQupBy zaqm1VZE)Aor~AI2+Nr${M9PN(sr#c5)e=!ONe-L-Jg7#*)w|J`7`pV(#%IbkvSdwS zuE&$d(~E(WUD_EnK5jZmGe*BC#(UGXU~bEPJ$!bn@}g^jYEFsOxG~+w!l#U1{#N~! zGW+$uepianhEmxVA4ZSXbani*V#V)G)4j>hkli0J4nY*EJY*+a4OndtS95)}_IrZz zC=jf~XU<+e3{*U5f)UC;PYq&f<@(qWr5>q%D691TYk3Kc66OCesjcmn7)an*`iZrG zmkN^N&!C63EAf{d&Z&U4_iUg3zqR+5^kON;J9#dpXyqM5ib|A%r4N!3OWwmsCEGeuYz8&&68@0AlBJF~xU#mK)*qbboR1HU$Wud*L zO`@g_c@jOWTsIgxv*uTX05!+K|3iJR5Q1oiZ?;Uhcxas_y%I(Q42;LL3k6`T6f+1P z>{)0~L)C;XMD|YHv5B&LRrlY*#bviz*wzfOyG!xES+&;;`q9YmEoTKq0jkEO-Cn+I zs^!`IV0WScsCasfmOn6k(EwCDSQ3DWN6Q*e@$|<6Djr0i4LU33f2nvJaR3$1o*}S{ z;ZWiFLG-_t@U0GJMeAWlF^5HXEdjsYz}HX{SkG^}GxsvbOW9QlZ2cN$Kdv3o1Sv64 zU{nK5DF^@ozFq?g!gGS)wmEzR>nSb@fpx#Hr@&0_(}cM*SEY=u>G$r?JP>h+e>C?> z>5xx%q^LE=q46-RyXv;bGDfF70~vc;?JCta*2}wP$+~93^bf&a!2B0}q`~$7%=fzX zjsNv?Q(!DZO?-hJ^ZF!6aN#YW#GhcZC{Qd=6hh>mJgNI^`{Ctd0tPUe+xN>^wbJ6u z=*9!>P6;!26j*K#Ll>lAniQKED)4{Gd#j+j)}~PxcPChaYj6qf?(XjH?(V_ef(L>_ zfZ!wq3r=u%4Nf3PAiy4Tvex&lwNIV;Pu1CXyE>KbF}R|t>Cyf6)BPfWt#H7qbO#W8 z-#|i%c5$$zeK|!XILVTQ@c_PB4{opkcn{|9kNn-BZm_;wB*P(rUVRRCNrbC(Uy&;e z;q|4Zp`)d%*dZ!Kn*XHO`i$Fy`TMj#gb~t6AQC?Sc5pULnCzLq-<&P_2!Lo>z`AP`We|u~!~&d@B8Bu+iI8<`h$?%B zY*hZfcm;g8^4t}FUE&P{fRZtDF(4T$7+W^5R+;KgHj9XWe4k#Ew&Z7%+URK2SWXj` zN&W(;JlfJ-WWdST3i7=QODocJx(bktU1m_7E~QS~PRx8zv-{2*7N3hh__=nB+4erk zqj7a~Ry$9li+vuW3A3rxN|Q@NP~{bP^)Yw@@~)j`p99#6AFGaD#$u!2;yioz=VPnF zZx_9p&i@&z*rl6K7Uv-1_?xwH+R{A)tdH@fD&cKfHGtB;L(fQ}y0@Bg+ejVzZL(tRh zccDi^p~r2Z^{%I*#GtOvA8BGNPJcD^1o?Tdr)=%l1@+^zO2%QDF|6UgGqCTu7b?IX z3rG(#YU*&h44Q>WTscdA^fI|%;>Svq@1yX`LQ14O>!D~I=_qe1Z&EbP-0m#lF}YYf z!H%zpV{FKXimm>oFR@A2It&Al_W*!z5mzg^9|1}TWqSZiqrGavN1*GnxaV19!=Uki zOCqIh(uv`hMh`(DeE{*9yaxgJ)I}i-#StJ5ehqoQ&H?R$DCX-hB%fQd-&NkIg0!U!B>U?1Sc zY<*p*i|&pns{Nb;OgpzExXkB=!=-)T9M|>RAh6#lR0mfe%Td+uPAqG04y*M)1Vq^< z*q`zadc1EK-}{@rXG*e*8yKchq5rNi@yKj4gD&>kA0Gc^#b)%XVL zbh?D^wf=qEg2VuV>ho<2(mrG*zq&}V--e`-T98XGZby?+CF4tH8&FDKN?dxR^k>bR zeV(kIc_bst|3jU?c&cjbchi`v=%LP=QF-_pAnvmZd4X>_wqx*NA#aHlV1^y;lmb?1 z723h#<@B2#7O;FQW^o;ym{(_=qPFxR(OedK_feVwE4GikUYdbTDb}2T4g54kLVsUaLX|iy#FuhMuqt)L(0rllE^!-=CkLX}UX$>}Zh6E|COB>Mi|bcH=sZcF)fg(mK5=`Cf(sH5XeP=E3@7= z(wNnd_X2^O^__`2IFRRZ-J`x~rJVP$0tIqS6;L2|o|}oZu}jnoizjscXCQBK%)>eQ z#FUJZf?}y)&vglvA`*>i8n!^n8O^u?0T|NoWSrnP((r2JoKqs`#F3?8!%Fb)`O8rz zbCEn9e$P0W`-w1b)SsSfq-KE1YUy`!|NrUxiVbLtFVIVFIQA~L0VaLS7$eYWOZiRN z0kCPGMf?gAIQz}8DxYQV{g0N)U}YSDy;r#ed=#uhXL3DoRe*)vQe&|o5FfaI!cE^Q zd9sT=4fg2!HI3yXDiy%q7YYHeBv`+nBgv5g*n5#6EWjF?x{9)7i`vD_rj_581Vl5< zmB}&DVTCC++q7FEfZ+D;-QgP`_WrFE?pZc;8>UDcQt{IXM@S%W0W<=6C^tb7>GfBv z&@2fd&v4TGnZ$>)>!ZQMlb}2f?hh>e(=iPo242Q0^~vvQy5Mo=zPR1mK$0QDn&CS0 zJD2BEooA4m&;4|!*NtcPAly67oKeqAtr6tFbisVB6B-ZT@7yWML(;I1@p`R&;p$|M z+nr!7)*xQxMI039K5HaEQ4YNxh|~s~Utfo7OR)@BFA~MM`sZA&4_)6E9GbmgtLe_h z#l!(bgAEgys{4+=fq&&RsJwh6r4IU2(IWouy+~87NU4!Xpy#gepNWyS{x^WWKF54Ny8amlNG@*pQ`INF(D+CIxJe6$#D zXM14z)!(zTHHef@Z-vQ|5GcQpQUcuqV>>9yd`K)%sZI%$>cCI3peeEJaY*br*42P+ zK}Fhla*oq>Bs8d7Fq8l!??&%{sl9Nw0Oqfb_3wKAuGYU%ak(R_hmTMby~sG?D=c0Yw6A9*x1J<}#AfYb4zb zl~t2e>U>c6cjd^O(n3DCysB>Y1;RfHz2{Xmn=dH*mzKD3FU0}jpXwD5{)0=SLZ(js z5&oN$LE&EjL@amxJN#ql35UZUH~by`;kfgtfbie{ETb_sPWwD1Spa$uCh)IdJ_zyw z&^@vI7{>~Whl>1|uFtmF;mZ85nJ{g-@#0Fu!?G+~Iw^qOg9&`L5Iw97+)CkASb)IC z+QY5<`qKqj!`M-7kM(z2Oe`Q(?3()HShcOqL1H*|hc26}eFy-7Z$|O$U&FI3L;G1J zPXSplC_rZjn{|kovyW2dE6Y$LmGQm&g)1Vy#5{gXt?G~d-0&;OX^s2+4DWufdawIa zHme8!u~j2-ln%D7*BJ19kS@Z6fLiog_s59(hyr@f4abc7Xzw2_rtP`*G441PEXaOw zOWR2<)fF)2Adj8~;r0_00ClfeIKW?LQ%VvB!tq&6d`n1PkqA)FB@%rO$B!V0AQ;AG z9PLS8!)6-&Yt0OxXzX^$Sj0ekXJ||S>s7%8M%He#D?##0uq;{sb{)jBst~vRJCXNj zV4;pfH0#M?v6PKl^zk-rLX7i)`v#gRj3ao8>jmDU#mQ7_`d82S%K-z0R;IlDwhUj5 z%|VpUPNPUa{Raq7vu~A7&%{bD9wD7OIe+wCwK&0{hbeB|sq)(1GO;fAWuKvQi{c zO4tr5k2D&f5J`FLC_{Jj1<+IQB6g~ixdkb|2gHj$(B|zADiTHiz9><-puP${o)8S=BLddS?M#&9X=gkk z>?^P=N7uVzqS3rnw>>Z^RhR)a(5%p_`snIqtFZv3)+meX)C+oY9o3X6;uNfsuU6*s z{mJ=~6KLf(Oz?Mlv(`nT;)a5ldjvp94vSJg1Nl^=fVFK#hSj{1;X@JjEc8o!cuo!D z8-Jzsa$YV3%%B z5i&UfI(#i=deBaQ-Uqs8Ne9HEv_n0&^TV9xFBxVWMLfomICcHlaOv3u+n6zX2`o9l z1698p*SW*w0u5R?L6-*-HY~0-1X>s&5)2K+6K)TKOIRaq%i8p#>a4P>w>wEY&f+j$ zjibCge=+xA8>Fqt*n|gUF!0?X&KQITCZaG>z6+Vel_m#87t_73N$AA5%R&wH6t7+_ z8J;8GR`Zq4mDm8zkG8ajMQsO}DtJAMdk;9j$^_H32HZX1{FKLl^JC8g&ach{IKR== zu`1j9e>lH8$oZ=p_WWNDInezJZ^J|pzl3P|4;Eoq{$A;4R(S2Rl+xXwD9jbngXw!P zgl|;?aQD%bZX!aJhG~_Jr*TEvcvLYCJi^$|K8jc&Xas%q9}F~2f+BLJ7aI{o%{g`-)qf2 zu{;4RXmkNg>1YHqxpe7E{NQWDG=*i8RZCvbO2{Tp9hauy;+&@=|?*P%;=X_b-Epg=0dA01>=9IM3mJNW|?e&%weA7${fSRa`< z5H;`{RW8wK{&*g!&5<-v(VD>lKzpgmTA)&e%`L38Ql1AY)yi6+QU%cby~5g(;Qq4U zvCKQ5Obss+Yl&ov%L9*BJQ5GN<^fOrj^R6qL|)f#ux8YrDf_mhY6eVI z!7Z158&-Y~OjVhe0#jAS%fM9CH)=!JqK^Dr*`0q(RpBK7Q&o)Rpd95`?O!G8|BVDb z$L$N=XcPQi;@RL*^g2soB!Il9&VmOxd}HFbIRo_obPqDK24Kf1Mlz5uxxcI&=D;`2 zZRo~k!~jBLEII*>ThXulbgqv0`DtfhuK2?4`T<(`DmLhwiqOoN?V%J>deWT% zX@u>UAz&8>1trlPJ3Z^Gjw;Xy`43>F4U0W+HuJv`_?jIO@fvCDN@xZjNA) zGzrel2f6|`k(oT*$EHBJc`f7Tzhk*H5X()UV|h^9VfIl8FTI709~l<~mmF-NV~<8p z>gX86YY3!Zs6s%|sRWbrL4zz?dk6{73=HAqJRhTxC=09M@8iYZA5e^Qhjkn{rkSPv z+UUQ&Kg|_Sr2>_)mN{}6Rj?z!XEgK<5BLXvq{G z;%Lo=fvOa&zq47)dG)5Xr4gtx4X5d>*SM>Vy9983)0kS{HKAB02_*RCwSd4G8V?MS zgSGyG+lH^ z&@He0pB`GAp_`V4B{(543ZSDOGqnKh9#dEz2E#87U6>N!@f%~StV^v+6&y@nhyAx`ZzpIrNR21mBtd=o09361cdW@9IehQ}_vS^v_4_M)dzYYF}DW zdiOYQTl~fvdr3Z=)2|PCiIO*rvoUtudeC}M5i1vYO3qvEp03}0@b%dB{&u$_gFvwg z1}Yf42P@?Q5q7{xWt&tkNLOT^vHD*3-MaT#kdpc(xF5);f=X#(IUhkw4jy%2p80za zhL6}oj+_7qqVc&cwM!o8h;Xs3yAlkY<9OqE8G?GVqvp?dHKI(o@zI_!{Bdv8C~lPA zZfBOpEIw8?IJnh{n(u8pm=~K2iXMJ&pCNb0|{jqy^#SXC?|K4*#Yf!Qc!SU zYrZ}PCQq`TvCO~rIz`Os>?){XvXZbGMH+g#rFx7;{g=S^CQx}M^35*Uiob++#+83p z3pY_IxOo4i{EBv)vFuQ9ner-Z-Y^fjx{9xHM%)Or=AeI171ORL`pf97<{prjla17l zYDn&Z^702DFZY`P@^VUAATLL`DpbiS{6}6sP6y=Wc0)j3Ze#ZEy!;FD?a$!Y|K#PZ zWp1)RvnWfRr6Tp#A>Bh1DMV}ogBu17Q1_>K&>@YSWH93%Cm7x;Fyl+%rP$sHcGzr# z8SVAl!;6ovN7@|2T?+|c!w-kJ7Ul-rFr~Vd6BL1-WwHQEu8h$38)3$4b5W)%0zh;i z&4Dpzvw-G@`*Q8xq}cjRxm&C+gaStYNzNbGw(`Kqd7_u$Am78;Qi+{6&02P}*L4!* znoN77mt|(HO0i0DULWt?)xzS)bz4i2bTm!Z+v(VjIh_>&Dx%5+q$O2Ya#-NTD&R8! z16Cr0U_$~DQ$+tjSRCW#4{3saJXlcY`7Q08Dr;?eTfm{*{_lHQEL$O~vnlKv%wK^o zXEC!>Xm6R)c@uJa@`Gym_4ey+3`(_c5mndw+TX~e5wJqTNx@1SKMG{1B8H0NYqgVN ze%t-1O6Woamenk4_rVm`im7sKjnmcZB;qzteDVlsGS%o8* z>b(8uI915J&Z?3a4jBd6ws+I1rH=4m^jwjLHIZ%EbrNK7yu=LxZpuT@T&@Sb$2m1b@SwOqA-*=Q&LiHbg|6S1bj#6t7y~gwJ zb}2F3t&gz9f7+$GGqe@n@)tT_SxgT8bD{wGn*jp-EA%-8KcEuPHgr<4f~_PVA-=p0 zwo(|Lf)pI!pe0z72jKfF1{EIW!ef|}U`kR%5PMHa`ZmQ43Iye={xb9dkbJ9yB=Mo_ z-l;VCh!36b0fClB&0?CZ-(9sZP-jrAsB?SrecC1S@`rF648?o= zgCI=BLfa!(GJHfyMak%70ZCX%OO+;~kYpMSho_DQ*9)_IBdc}KQ+TEPskR5Nh6k() z>ZhB-GNFf|GFgwwz4&m($?y~A0;l6gqm#!E7uRLXXQwAAIq`Z9pT3;bl4NSJ(+BX^ zEh!zI2IWOvizRl-8XSM7YCd{10sCO--S5eftn%NRpi)By3ExGLJ>LzL1Q^UDaVK~L zTlL*P@on$`(PFc~OUim|XYo}ix7`!q!$Ckf9p$479C;)?31HdX2Liv=q z>f5;L-@^b)fY$0xIqP4~)c_9pC_u%|e$L7i<1!5Pv^~ z?(dp)o2@OGLi4$1JsKG0u*}0*`h=2vn0y$YGvMgxCVjQR>WxAiHUKDw0Ah+ou!RB` za?u0Q*LNub91M$Ufem=20v6u8>h^ZA?*rGDVqG8|JO(0iN=AT^m25%3*o1LnBC2&s zR39i=MHeGlhlO*2l2tqtC|LtRi$I`&MIa^x`Sh|-|0r2AH9#dR7pP=K`gh6te+p)b=)Jk5_pZ-uE-E%3$Yy{Wq!yuBupe-a%kF1@qFAke(|zs!G67phcQnYT zL9rT}R(38VYX4it7+r(3torBgH-Sc*2H`6+nFRbNVP2T7&}|_r!j7a|N$*aRUvPSsd`l9sh z59tz7%XJ04Xrdk%Z_zf!1~wFobj{?UokF?zLb>b^D7~@GUV6J3e`EKzydAw0a~V}o zE-%G@|7Xp$_Ll9+QOjrL&cAApsIiJD3m(xMgCBty20awMJ1lZA>|;lF*oMe?A=)MB zvE%l($iix~omX#MBmwH1mzL}-dnULuCowfA{mc9Peh@K;{o$sftVLPMqau_iTee}~ z2ci#ItxMmeSo!vB^*UBwe&O9yl)0% z!zO+22q-bM3|q|j7AlZsGi*ly6c2G;d*8G2b%ftcgb(Y@;z-HGyhQqM_RO9S(F&N{ zH{RS{ya$PZ1)mE&4!Ixf_O%VNhvzuvE6)a@Ga7f4LA{tWT8C+#fy$>wdZhK*EST7y zuXze81@3yY(@l~u@PnJYP4vvHs=iTwLUcSNA889?2teU(!T)$FjzSX8YV62T=vEXS z>tDQSecSXa@#KPepN@NH_I(ahusd8{860q-m)kT=Wc#=R9+qeNjaVzGA`EC<4(XZ3 zgxS@7&&Qr%kJ{jm7qtqVb4M%PrrFP% ztFn&7%Oj&N>uYN(0e;O^&WCBmGd8C|9sU%U2mP~l#&j$=SxE9k%<_!r^(f0i`K39{ zJx=uM%NJVtkcRKNtC;Utk0A{q>xdxhIQY@dV@%M`d0BdiANl@xJ#5PP!H8|*`q-%+ z5BnZlRtb2nLQ6vh!w5r>LMA~-Lr_9sjSE0vK_CXtUK&vD;uom_6sg$Z=$8!LUJS-?JCbU2nN;scvJmd9_M9Q_v> z&AzlXA+K&$_v*l#ERE{mSz29>0A?tQNEWF)1~me9IIVy$@IPV?jL9LANsl&{U{82` ztrOKxmVJ})-rOi2ba!35@ex0V@ecnhHP(DP*Hn>mQgsYE1e|bQ@$i=?#HogGqN`A% z3I*PJ;W>|SVag)q0m9{3zu=sv=y7}--fp=pg=)GYK#T5QpGDN?90X{XyU?K*>Adr- z(D=GLQ}}6rZt=rnl(NS$$K)r?cK9$4BDW$xhJj+M=o+56Y#z;=lDX|E(y}(!X`#BDj*$aY+-Mp6pK7pXMc{t%=#u zbKu9q_NaUT{9g{3ffKzf^qJtdCXO6Lo8(7H_K1|89LJ#b7c);0M-mI;vBy9v&YiV^O8wC!JQn=7up?bxis9D9*%n~~!YSWFZ#k?(C5r-Yi3 zM{}z-3U$%L+WV#m-1A?43gjA9D9D21<1&!u)m%g0OyR=>(UZZQS|W+Fz|tr@XzupV zrQr_FdM)7v)RzLb^p%ZD$1Mv^_3NfxunRQ755H3lmz^MgLHI%l1QQFR7m{EUmQhm& z=f}W8+=)Q?+L|VyPuzT_rjAwGMuBB_C>7t+smm)0rWVF7M4W)JhGLI@$-W5#%MO_X zp+E$uz%4QWpW_^QUBgaYrMtb-+ZN@9Uf52cEb#7XvQ0}qId3VuWD!~`r0T22hVAV8 zAI|qzZVN@pwba(tfqwf#*Aoi@liCF^#`j_0M9ug_&Fq3{*>RUi*gcJ#h4lSfZ||V< zfLL!{{&%cLjjY6W$?C#GLto{?CCiGFT2(E(m;OJmeSQi;wL=+%)Cy}A(oc98Po%4c zJe#8vINvvJ3+)E@!|XDV`ZS`eFur&wYnilWNRSvroHO3y`XhgVT@Q8YZehXcY1z!qli4^f^=?yaGs`F!`=7*%mnB|IFdjx!S#2)dLbv6WM6Du*u0+pqR)7t z?ZMB)-qY6zXFhjW%zCPf$QS37hlBL2&Ev}Eg8YT@1pn+30tt$`XI%PeJ)vLmX8)eH z)t81(D}cy zP6Atq;?`AItDQ*zp!`kImBiNYZQEWgsgY4E@n7991d|I?%{0@ zbUoLaGVB(Ni1xMaFlv0G_0 z)0801?F*6-UfuL|WxJ+Pg2^wZE%&RR`$LP<6;DS&k8+Xt5*gg5+e7j zmy0vfcdfp-*;T7(%#4LUQoPKw%qif%pI$DwK+@IiQ{&*f$9Qr|!DxKMPxGByj&0e@ zR9%oEFVxF^l5zPX^1#ksxYT&U<0Yw|FWnkoGib-N(U6=nWa3zGu5t0WThGZsmY6&+ zXtwhcVYl9s4`&@RmBGQYp{|Ue_@zpGxuiNpWg{=q+w!&8@@DLtD+!O;ro3{`FH}{v z-(Kl^%4daP?jT%fgmx|ko-tB4d}7Rd@)G}w=T?wF>m5HBQ->qYPfm=P7)??XEtNnq zki0$Uvg56^>&=|%uqE7-8{tH_r}=sQ#crTgYDg@DRK^XP;;HtW038OZFqK5(*HiAZExcwX+4vf9LvKB6Tw?O4rLUwZM85B7ItJ# zx_m>G6u`sJ!$T{C@pO^)UbFa0VquDE;!_;5`U>Udv|xBReg2zrZgoOBG@N-2oJ_;P zB9mQsbCL%1#raRr=0?mGBzBCX_elZ3KTf2>x#3#1z>`BOrQ*9qTg*tG)daPz#)`RS ztei$P--OwkZl}0$ajW7tHy_?`oxkcxFt#HcPqTOLN-Oo^)-xeOLmg;5wrjMpd+9#d zSm!Csp;@J~vMcvn(E~m0TszOQHAkhZL$&Kbur$N) zC>y@iYn_tS8JROURpZ0nh*n3(VRr}IdRMX@YpQ1Tn@zgE87xejj@A|W;U7kHn&}Rv z6tdlC>Acr;y=5ozIgyqg;1#b@BMWIwaarGyS>BLaUVhM@C53C3(QmXt{XIb2@quGU z%QBXOwgbm*5M6nZqlRp~qm|lj5PQDbK~cX^O4TL4)zX01c^O8V@8)_%z(UF9ly%^o zO$zhftG8oMRYuN+GYs5au0L-s!ipNnS7*nob|*dP%IRqp8PDqo3I&-k^iE``PI5&Jx4r`SdW}~ zTKVcIWH|Vu&p^u8~({tD$^$cJ}CZn8A6#7W2A5y`5VWJx5fs zm7N`$R?;wE(YVptAD1U|N?t6Yw+Z5Bh2mVCyY@|TI#KV0(v{ek|Lj)9R?YVt^`E(3 zHyZBR^a*W|{7k$(E4@t=yp4V`h<^If?m(v4nS6Uw%5PCf%y^ins~#%4;iR)Me{`!c z6{H1aqmlIlg4->C4o=57;aC7Px>!$=vDQXW;!#YA_$ z6xubka|B+d7ISTkq%dqDlrm)bgh;ut;H7YB5Io^(GMzk~_eFN{W8Z@x(?f>|=8YeB zW@J-=xGS_}Rf7?$HmmN-Eq;HM_Nv)WR?z2@s9P@+wq z=hBRa*7d&0@9@+vO)U*`n`2(@xBa%5ib?NuC-0X!^wW}xx1jv3J|LB+ZXS@kJ)$;k z7!jApV&ADW-K1MT=y(;j(i7`ELiD!yz_eCukUE!fCUUn|)k(Q%Yu6RnI_mI=H||${ z(1eP!hcQkahlw^$nPNnM6)*m2fvgW?!cLy6lJMypu6uXW$+iUXeW`RjJz z8$Y8rzN!8PIi|~;xy`N`R+>GcJ7gCaKGB^hG$#`h#EQD&#N_D7^G3-7vf6p`e%0aq zvf2WMh$Azjsq4|v?&7@UM9FI+$+dj`52|ZBLOUFnzKFAOiq>pfEn=D1eNM^OiK*8^ zyw1{oB>{=HIc?ZCmJvpte{R;h9s@5kb*`PB?sr?(Ymp`R>+^QHhP!?_x$z5sRYbB_ zp0d&_&#D;~Pw(Mei%$Z!mnP)j@*!nd>ei}_9y~15zrkvIXGRoR%Y5;xz-diZL5NG1 zo8cx+yX!#N7oRZ>R}%Ss#AHu+Tcebn$)TUx`YXoV$Jd3xD^x8rBF0WNBKhFX#-{ET zm4q18%`~Jkb#HY#embOlCepPAb#Eh)S^FjBtUtkNbOqfN8|uz<+&H;Nis>HfjjXQ~ zC3xX-D?Oi_D~Vky1wNSFPJ2pg%uC})Om-C9Pxcr8c=aCDgSc1}S1y*}SJI1*+}Tcb z7wwRQoHSHIdJg?A7y})#Ra|F*<1t-zLaPC}Mo$+H*VlWe%Z(3nsop-90}n!vM;Azc zARi%uf`!^+ge({9W=j;te^Gl@;wjMv;RNaxEoF3F6#ittR~LkGxX-L(sx`z5!s!|r z+F?(TgTM(!0%8YS>mBYSJV{{#av_#M3nP9IClsCF)@%1af2A)(uX++F{7_@h@NKnG z^2}yb;xh5x@WoJEMPI=&SO45uELeL?TMo(;lOy2RGt@!h(bIS&ji8%J7=Gv|*$V1| z_xn>OlVKvjn_-mOEJMW`F84l5cx7d^3K0Puw;rlP7+=mFo2`)^{7U_PG>w$)*b=njCLsH!sOXYFX%E5UI&^67&~MTKEjX4#T= zucRXE0w$gkZk(icbY73nX5C78HbW_{=b^89nLqN5#-mlLEU0qanmm zpv05-lOf5a^8p(juvx2ZUyP&VQi<|uYlZ%b*<`?6YPYrsaFJy^pkbtZ5Xn>&nWH#L zz8bt6ANE}hnMxyIDSV{1_zGbx+#;(61+AI;lEv5zA474CRvA$mUqE_6A}`We1K-CX zV;uN4ca%$=G!SVR3^yGq3bvjXRr2bT`mk%{y|7b8R?*0i= z85#<{wkE3CSa03dUoVlTTm3iFGWA7xhUX4=%+K9bvBxu<%}UXn3yiDwuEBLnmOnhG zZkbU?eGgw?yXKrR*{FPF&98R$vwVpw*WtELo#=3!+dG=hVQRy%HovO-LB30G%9%pW z_SpBsuicm!CBm$C(H6F+REpn)fjR9Mv-u9++uoR#?G>#$nuJrb%zb`h#~ALx8@|sR&_a4m`rp#T zp5Ni(<-+_l%3nnZFg1~vAg+EUp}zd~{;s(Fa7j^}Z#_k0-p^-QeIT3*T_l0jh-$Fv zo!EyO_WfF$bJ!Bg6yJdt+tFG4QOM9#D=SE+DyNhrcSrxU! zL|^}N81Ej)t%p=y*7~u~00nbn3y&)L49piER-H|u0ZEX95axxk=Eg+#0qhrONg)Dz zpJ+Om-W2~qxT_KWeFPK0vP5xJG{do#PnWl9xVKL-^Sx&H4|}@v&9ve)3HuqbNMfPX z1jP?2#vfj$7!c6Gkig#>1PcT{>2j$^;gQbmQ13ScNF@ja6Xtvf=GW_fJESRtWM?m3 z&yit;i3-t_;ej=U70`bm0wIKgNxq`{4x`V>u>2qw`k}KJ+-??zC5*W2N%0FE)n2{L z*iN_zx*ydTi3K(bO5S8f9+C!{5(*3QZLoN?Z@Vx#uQ>TPjl)96AFP8D=(Q^cD8TP_ zJb|5z4(VTA+nm&{?t|qozZ{aNhbXvaFc_ur|2Sz@BX@n(#=vwPA?Dakwt?Y{z}@$5 z#-FF6^wn-1exyH7y*mZ#f$Y~*8Q0Lv($=B69;d3Ip*zF4Ex)b%Go#ZteCRL{=IMEv zJy(t~7G7k`i4Dsgi3LwO(Y3k~H8|}KWof@iyo?@g+<(~=sge*MAMLu@j6g(AUd!}+ zS*PvS;jhBTi&hk;DQ+YwZnSo?4$zy;R<1x>kt!`#wOf9#s#5V@y@Ep&D?LV5qSR5N zbP1sekvCIih4;#bL8wHwPSOGTsWnEZY7aPz%K3iexuQ!STcSB9WjoPdM&w?^r8!{L zB%rx0_DCKiWiDd1%0D+IXFYu$Xi7aGzm^wFV|lTe*8iUOQJV6nvct-KZ9-S7#5tTU z5y{{FMES!jMGXz^KOQCAjE&+f;o*wsr2;mXT8yC&{6@3H# z9QqdWPhr`g!ZVJ8@&t5Q2r3j9RAnNP4-jg>v|nF*8-3x-CQMF>nS>xM4)=D@SB$*2 fJVD9BUsw{JACs>pp^N#ve*N(F30-ZNpXGl6;PWa8 literal 0 HcmV?d00001 diff --git a/plugins/gs/zerogs/opengl/Win32/resource.h b/plugins/gs/zerogs/opengl/Win32/resource.h new file mode 100644 index 0000000000..053ec92e01 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/resource.h @@ -0,0 +1,45 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSsoftdx.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_LOGGING 106 +#define IDB_ZEROGSLOGO 108 +#define IDR_REALPS2_FX 109 +#define IDR_SHADERS 110 +#define IDC_CHECK1 1000 +#define IDC_FULLSCREEN 1000 +#define IDC_NAME 1000 +#define IDC_LOG 1000 +#define IDC_CHECK2 1001 +#define IDC_FPSCOUNT 1001 +#define IDC_CHECK5 1002 +#define IDC_FRAMESKIP 1002 +#define IDC_STRETCH 1003 +#define IDC_LOGGING 1004 +#define IDC_COMBO1 1005 +#define IDC_CACHE 1005 +#define IDC_CACHESIZE 1006 +#define IDC_CHECK3 1007 +#define IDC_RECORD 1007 +#define IDC_COMBO2 1008 +#define IDC_DSPRES 1008 +#define IDC_WRES 1008 +#define IDC_COMBO3 1009 +#define IDC_DDDRV 1009 +#define IDC_FRES 1009 +#define IDC_COMBO4 1012 +#define IDC_CODEC 1012 +#define IDC_FILTERS 1014 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/gs/zerogs/opengl/Win32/resrc1.h b/plugins/gs/zerogs/opengl/Win32/resrc1.h new file mode 100644 index 0000000000..6c2956f489 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/resrc1.h @@ -0,0 +1,79 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by zerogs.rc +// +#define IDC_CONF_DEFAULT 3 +#define IDR_DATA1 112 +#define IDC_ABOUTTEXT 1015 +#define IDC_CONFIG_AA 1016 +#define IDC_CONFIG_INTERLACE 1017 +#define IDC_CONFIG_AA3 1018 +#define IDC_CONFIG_CAPTUREAVI 1018 +#define IDC_CONFIG_CAPTUREAVI2 1019 +#define IDC_CONFIG_FULLSCREEN 1019 +#define IDC_CONFIG_FULLSCREEN2 1020 +#define IDC_CONFIG_FFX 1020 +#define IDC_CONFIG_INTERLACE2 1021 +#define IDC_CONFIG_DEPTHWRITE 1021 +#define IDC_CONFIG_FFX2 1021 +#define IDC_CONFIG_BMPSS 1021 +#define IDC_CONFIG_AANONE 1022 +#define IDC_CONFIG_AA2 1023 +#define IDC_RADIO3 1024 +#define IDC_CONFIG_AA4 1024 +#define IDC_CONFIG_INTERLACE3 1025 +#define IDC_CONFIG_BILINEAR 1025 +#define IDC_CONF_WIN640 1026 +#define IDC_CONF_WIN800 1027 +#define IDC_CONF_WIN1024 1028 +#define IDC_RADIO5 1029 +#define IDC_CONF_WIN1280 1029 +#define IDC_CONFIG_CAPTUREAVI3 1030 +#define IDC_CONFIG_WIREFRAME 1030 +#define IDC_CONFIG_CAPTUREAVI4 1031 +#define IDC_CONFIG_CACHEFBP 1031 +#define IDC_CONFIG_SHOWFPS 1031 +#define IDC_CONFOPT_00100000 1031 +#define IDC_CONFOPT_00080000 1032 +#define IDC_CONFOPT_00002000 1033 +#define IDC_CONFOPT_00001000 1035 +#define IDC_CONFOPT_00000200 1037 +#define IDC_CONFOPT_00000080 1038 +#define IDC_CONFOPT_201 1039 +#define IDC_CONFOPT_00000040 1039 +#define IDC_CONFOPT_00000020 1040 +#define IDC_CONFOPT_00000001 1042 +#define IDC_CONFOPT_00000004 1044 +#define IDC_CONFOPT_IDS 1045 +#define IDC_CONFOPT_00200000 1046 +#define IDC_CONFOPT_00004000 1047 +#define IDC_BUTTON1 1048 +#define IDC_CONFOPT_COMPUTEOR 1048 +#define IDC_CONFOPT_4001 1049 +#define IDC_CONFOPT_00000010 1049 +#define IDC_CONFOPT_00008000 1050 +#define IDC_CONFOPT_00010000 1052 +#define IDC_CONFOPT_00020000 1054 +#define IDC_CONFOPT_00000002 1055 +#define IDC_CONFOPT_01000000 1056 +#define IDC_CONFOPT_00800000 1057 +#define IDC_CONFOPT_00000008 1058 +#define IDC_CONFOPT_00000400 1060 +#define IDC_CONFOPT_00000800 1061 +#define IDC_CONFOPT_NOALPHABLEND30 1062 +#define IDC_CONFOPT_00040000 1063 +#define IDC_CONFOPT_02000000 1064 +#define IDC_CONFOPT_04000000 1065 +#define IDC_CONFIG_AA8 2003 +#define IDC_CONFIG_AA16 2004 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1049 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/gs/zerogs/opengl/Win32/zerogs.bmp b/plugins/gs/zerogs/opengl/Win32/zerogs.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5cf24cf9e09d94de6bb9bc1c0099f1d3d6946632 GIT binary patch literal 921654 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 z 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005.vcproj b/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005.vcproj new file mode 100644 index 0000000000..87557d8809 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005.vcproj @@ -0,0 +1,583 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005_x64.vcproj b/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005_x64.vcproj new file mode 100644 index 0000000000..8e038d73e5 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zerogsogl_2005_x64.vcproj @@ -0,0 +1,874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/adler32.c b/plugins/gs/zerogs/opengl/Win32/zlib/adler32.c new file mode 100644 index 0000000000..bc0842f01b --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/compress.c b/plugins/gs/zerogs/opengl/Win32/zlib/compress.c new file mode 100644 index 0000000000..e7ea2c518b --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/crc32.c b/plugins/gs/zerogs/opengl/Win32/zlib/crc32.c new file mode 100644 index 0000000000..aa8b984a34 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/crc32.c @@ -0,0 +1,311 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/crc32.h b/plugins/gs/zerogs/opengl/Win32/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/deflate.c b/plugins/gs/zerogs/opengl/Win32/zlib/deflate.c new file mode 100644 index 0000000000..efe7b63aba --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/deflate.h b/plugins/gs/zerogs/opengl/Win32/zlib/deflate.h new file mode 100644 index 0000000000..26775e9d12 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/gzio.c b/plugins/gs/zerogs/opengl/Win32/zlib/gzio.c new file mode 100644 index 0000000000..4cfd64fc45 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/infback.c b/plugins/gs/zerogs/opengl/Win32/zlib/infback.c new file mode 100644 index 0000000000..5cf5d22cf9 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inffast.c b/plugins/gs/zerogs/opengl/Win32/zlib/inffast.c new file mode 100644 index 0000000000..63aa4402fc --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inffast.h b/plugins/gs/zerogs/opengl/Win32/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inffixed.h b/plugins/gs/zerogs/opengl/Win32/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inflate.c b/plugins/gs/zerogs/opengl/Win32/zlib/inflate.c new file mode 100644 index 0000000000..71fe3ccd0e --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inflate.h b/plugins/gs/zerogs/opengl/Win32/zlib/inflate.h new file mode 100644 index 0000000000..b6965127b9 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.c b/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.c new file mode 100644 index 0000000000..55fd27b601 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.h b/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.h new file mode 100644 index 0000000000..1dbfe53a6a --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/trees.c b/plugins/gs/zerogs/opengl/Win32/zlib/trees.c new file mode 100644 index 0000000000..d0bce9f2f1 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/trees.h b/plugins/gs/zerogs/opengl/Win32/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/uncompr.c b/plugins/gs/zerogs/opengl/Win32/zlib/uncompr.c new file mode 100644 index 0000000000..82ebef75f8 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/zconf.h b/plugins/gs/zerogs/opengl/Win32/zlib/zconf.h new file mode 100644 index 0000000000..b073c9e60d --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/zlib.h b/plugins/gs/zerogs/opengl/Win32/zlib/zlib.h new file mode 100644 index 0000000000..d54ac9433f --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/zutil.c b/plugins/gs/zerogs/opengl/Win32/zlib/zutil.c new file mode 100644 index 0000000000..db137f8a48 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/gs/zerogs/opengl/Win32/zlib/zutil.h b/plugins/gs/zerogs/opengl/Win32/zlib/zutil.h new file mode 100644 index 0000000000..e300f7c767 --- /dev/null +++ b/plugins/gs/zerogs/opengl/Win32/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/Makefile.am b/plugins/gs/zerogs/opengl/ZeroGSShaders/Makefile.am new file mode 100644 index 0000000000..6d409c54d0 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/Makefile.am @@ -0,0 +1,2 @@ +noinst_PROGRAMS = zgsbuild +zgsbuild_SOURCES = zpipe.cpp zerogsshaders.cpp diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/ZLib.lib b/plugins/gs/zerogs/opengl/ZeroGSShaders/ZLib.lib new file mode 100644 index 0000000000000000000000000000000000000000..7f4cf9ba6ed5cffb6d54b7d1cac4876a65cda678 GIT binary patch literal 101154 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%0A2!I2ly#qCEz6BGQhV03jx0a+yMAFU=!doz!>CU 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

sSdPO@+xFslc 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln b/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln new file mode 100644 index 0000000000..45a5aa122b --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGSShaders", "ZeroGSShaders_2005.vcproj", "{811D47CC-E5F0-456A-918E-5908005E8FC0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug|Win32.ActiveCfg = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug|Win32.Build.0 = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release|Win32.ActiveCfg = Release|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj b/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj new file mode 100644 index 0000000000..0dfc9ad0c1 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/copytozerogs.bat b/plugins/gs/zerogs/opengl/ZeroGSShaders/copytozerogs.bat new file mode 100644 index 0000000000..32c9820600 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/copytozerogs.bat @@ -0,0 +1 @@ +copy .\Release\ZeroGSShaders.exe ..\ \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp b/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp new file mode 100644 index 0000000000..4659f743ba --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp @@ -0,0 +1,337 @@ +#define _CRT_SECURE_NO_DEPRECATE + +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include +#include + +#include +#include "zpipe.h" + +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + int type; + vector buf; +}; + +map mapShaders; +CGcontext g_cgcontext; + +void LoadShader(int index, const char* pshader, CGprofile prof, vector& vargs, int context) +{ + vector realargs; + realargs.reserve(16); + realargs.resize(vargs.size()); + if( vargs.size() > 0 ) + memcpy(&realargs[0], &vargs[0], realargs.size() * sizeof(realargs[0])); + realargs.push_back(context ? "-Ictx1" : "-Ictx0"); + realargs.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfilename, prof, pshader, &realargs[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", pshader, cgGetLastListing(g_cgcontext)); + return; + } + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("error: two shaders share the same index %d\n", index); + exit(0); + } + + if( !cgIsProgramCompiled(prog) ) + cgCompileProgram(prog); + + const char* pstr = cgGetProgramString(prog, CG_COMPILED_PROGRAM); + + const char* pprog = strstr(pstr, "#program"); + if( pprog == NULL ) { + printf("program field not found!\n"); + return; + } + pprog += 9; + const char* progend = strchr(pprog, '\r'); + if( progend == NULL ) progend = strchr(pprog, '\n'); + + if( progend == NULL ) { + printf("prog end not found!\n"); + return; + } + + const char* defname = "main"; + + SHADERINFO info; + info.type = 0; + info.buf.resize(strlen(pstr)+1); + + // change the program name to main + memset(&info.buf[0], 0, info.buf.size()); + memcpy(&info.buf[0], pstr, pprog-pstr); + memcpy(&info.buf[pprog-pstr], defname, 4); + memcpy(&info.buf[pprog-pstr+4], progend, strlen(pstr)-(progend-pstr)); + + if( mapShaders.find(index) != mapShaders.end() ) + printf("same shader\n"); + assert( mapShaders.find(index) == mapShaders.end() ); + mapShaders[index] = info; + + cgDestroyProgram(prog); +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + g_cgcontext = cgCreateContext(); + if( !cgIsContext(g_cgcontext) ) { + printf("failed to create cg context\n"); + return -1; + } + + CGprofile cgvProf = CG_PROFILE_ARBVP1; + CGprofile cgfProf = CG_PROFILE_ARBFP1; + if( !cgGLIsProfileSupported(cgvProf) != CG_TRUE ) { + printf("arbvp1 not supported\n"); + return 0; + } + if( !cgGLIsProfileSupported(cgfProf) != CG_TRUE ) { + printf("arbfp1 not supported\n"); + return 0; + } + + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + vector vmacros; + + LoadShader(SH_BITBLTVS, "BitBltVS", cgvProf, vmacros, 0); + LoadShader(SH_BITBLTPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCPS, "CRTCPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTC_NEARESTPS, "CRTCPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24PS, "CRTC24PS", cgfProf, vmacros, 0); + LoadShader(SH_ZEROPS, "ZeroPS", cgfProf, vmacros, 0); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTAAPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTER_NEARESTPS, "CRTCInterPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", cgfProf, vmacros, 0); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], cgvProf, vmacros, 0); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], cgvProf, vmacros, 1); + if( writedepth ) vmacros.pop_back(); + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(psshaders[i]|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], cgfProf, vmacros, 0); + if( writedepth ) vmacros.pop_back(); + } + } + + printf("creating shaders, note that ctx0/ps2hw_ctx.fx, and ctx1/ps2hw_ctx.fx are required\n"); + vmacros.resize(0); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.push_back(g_pPsTexWrap[texwrap]); + + for(int context = 0; context < 2; ++context) { + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) + vmacros.push_back("-DWRITE_DEPTH"); + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) + vmacros.push_back("-DTEST_AEM"); + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) + vmacros.push_back("-DEXACT_COLOR"); + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + + vmacros.push_back("-DACCURATE_DECOMPRESSION"); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); + vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + } + + if( exactcolor ) + vmacros.pop_back(); + } + + if( testaem ) + vmacros.pop_back(); + } + + if( writedepth ) + vmacros.pop_back(); + } + } + } + } + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.pop_back(); + } + + if( vmacros.size() != 0 ) + printf("error with macros!\n"); + + // create the database + + int num = (int)mapShaders.size(); + + // first compress + vector buffer; + buffer.reserve(10000000); // 10mb + buffer.resize(sizeof(SHADERHEADER)*num); + + i = 0; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = (int)buffer.size(); + h.size = (int)it->second.buf.size(); + + memcpy(&buffer[0] + i*sizeof(SHADERHEADER), &h, sizeof(SHADERHEADER)); + + size_t cur = buffer.size(); + buffer.resize(cur + it->second.buf.size()); + memcpy(&buffer[cur], &it->second.buf[0], it->second.buf.size()); + } + + int compressed_size; + int real_size = (int)buffer.size(); + vector dst; + dst.resize(buffer.size()); + def(&buffer[0], &dst[0], (int)buffer.size(), &compressed_size); + + // write to file + // fmt: num shaders, size of compressed, compressed data + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + fwrite(&num, 4, 1, fdst); + fwrite(&compressed_size, 4, 1, fdst); + fwrite(&real_size, 4, 1, fdst); + fwrite(&dst[0], compressed_size, 1, fdst); + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + cgDestroyContext(g_cgcontext); + + return 0; +} diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.h new file mode 100644 index 0000000000..ae3f1d032a --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zerogsshaders.h @@ -0,0 +1,89 @@ +#include +#include + +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define SHADER_REDUCED 1 // equivalent to ps2.0 +#define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +const static char* g_pShaders[] = { "full", "reduced", "accurate", "accurate-reduced" }; +const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +extern CGcontext g_cgcontext; + +static CGprogram LoadShaderFromType(const char* srcdir, const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, int context) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255], strctx[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + sprintf(strctx, "-I%s%s", srcdir, context?"ctx1":"ctx0"); + + vector macros; + macros.push_back(strctx); +#ifdef _DEBUG + macros.push_back("-bestprecision"); +#endif + if( g_pPsTexWrap[texwrap] != NULL ) macros.push_back(g_pPsTexWrap[texwrap]); + if( writedepth ) macros.push_back("-DWRITE_DEPTH"); + if( testaem ) macros.push_back("-DTEST_AEM"); + if( exactcolor ) macros.push_back("-DEXACT_COLOR"); + if( ps & SHADER_ACCURATE ) macros.push_back("-DACCURATE_DECOMPRESSION"); + macros.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfile, CG_PROFILE_ARBFP1, str, ¯os[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", str, cgGetLastListing(g_cgcontext)); + return NULL; + } + + return prog; +} + +struct SHADERHEADER +{ + unsigned int index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 +#define SH_CRTC_NEARESTPS 0x8022 +#define SH_CRTCINTER_NEARESTPS 0x8023 diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/crc32.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/deflate.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/deflate.h new file mode 100644 index 0000000000..0b5dd9bb49 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffast.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inflate.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inflate.h new file mode 100644 index 0000000000..fbbc871432 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h new file mode 100644 index 0000000000..dc0fd567ea --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/trees.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.h new file mode 100644 index 0000000000..a5248c8b65 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h new file mode 100644 index 0000000000..48200f8d72 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.in.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zlib.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zutil.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zutil.h new file mode 100644 index 0000000000..b691f27c26 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.cpp b/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.cpp new file mode 100644 index 0000000000..e8c7b47f49 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.cpp @@ -0,0 +1,115 @@ +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.h b/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.h new file mode 100644 index 0000000000..cb96229553 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ZeroGSShaders/zpipe.h @@ -0,0 +1,7 @@ +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/gs/zerogs/opengl/buildshaders.bat b/plugins/gs/zerogs/opengl/buildshaders.bat new file mode 100644 index 0000000000..c7698558ae --- /dev/null +++ b/plugins/gs/zerogs/opengl/buildshaders.bat @@ -0,0 +1,3 @@ +ZeroGSShaders.exe ps2hw.fx ps2hw.dat +del Win32\ps2hw.dat Win32\Release\*.res Win32\Debug\*.res +move /y ps2hw.dat Win32\ps2hw.dat \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/common.h b/plugins/gs/zerogs/opengl/common.h new file mode 100644 index 0000000000..1f815f537d --- /dev/null +++ b/plugins/gs/zerogs/opengl/common.h @@ -0,0 +1,1142 @@ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // printf("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //printf("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) printf("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + printf("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + printf(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + printf("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + printf("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + printf("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/gs/zerogs/opengl/compile b/plugins/gs/zerogs/opengl/compile new file mode 100644 index 0000000000..973c773214 --- /dev/null +++ b/plugins/gs/zerogs/opengl/compile @@ -0,0 +1 @@ +link /usr/share/automake-1.9/compile \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/configure b/plugins/gs/zerogs/opengl/configure new file mode 100644 index 0000000000..82aff9d204 --- /dev/null +++ b/plugins/gs/zerogs/opengl/configure @@ -0,0 +1,6353 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for ZeroGSogl 0.96.2. +# +# Report bugs to . +# +# 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='ZeroGSogl' +PACKAGE_TARNAME='zerogsogl' +PACKAGE_VERSION='0.96.2' +PACKAGE_STRING='ZeroGSogl 0.96.2' +PACKAGE_BUGREPORT='zerofrog@gmail.com' + +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 +am__isrc +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 +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CCDEPMODE +am__fastdepCC_TRUE +am__fastdepCC_FALSE +CXX +CXXFLAGS +ac_ct_CXX +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +CPP +RANLIB +CCAS +CCASFLAGS +CCASDEPMODE +am__fastdepCCAS_TRUE +am__fastdepCCAS_FALSE +ZEROGS_CURRENT +ZEROGS_REVISION +ZEROGS_AGE +ZEROGS_RELEASE +ZEROGS_SONAME +RELEASE_TO_PUBLIC_TRUE +RELEASE_TO_PUBLIC_FALSE +SSE2_TRUE +SSE2_FALSE +X86_64_TRUE +X86_64_FALSE +GTK_CONFIG +so_ext +SHARED_LDFLAGS +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CCAS +CCASFLAGS' + + +# 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_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_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 ZeroGSogl 0.96.2 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/zerogsogl] + --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 + case $ac_init_help in + short | recursive ) echo "Configuration of ZeroGSogl 0.96.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --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 debug build + --enable-devbuild Special Build for developers that simplifies testing + and adds extra checks + --enable-sse2 Enable sse2 instructions + +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 C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CCAS assembler compiler command (defaults to CC) + CCASFLAGS assembler compiler flags (defaults to CFLAGS) + +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" || 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 +ZeroGSogl configure 0.96.2 +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 ZeroGSogl $as_me 0.96.2, 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.10' + +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 + +{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 + + 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. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +echo "${ECHO_T}$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 +{ 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 + +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 + { { 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 +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=ZeroGSogl + VERSION=0.96.2 + + +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-"\$(SHELL) $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="\$(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 -' + + + + + + +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 + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ + 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_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ +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_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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" + 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_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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:) +{ 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 + CC=$ac_ct_CC + fi +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# 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_c_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_c_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_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 >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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + 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_c_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_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_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_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$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 +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +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 +/* 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" + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +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) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +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 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="$CC" 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_CC_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_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 + 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/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + 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_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$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 gcc g++ cl KCC CC cxx cc++ xlC aCC c++ + 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 gcc g++ cl KCC CC cxx cc++ xlC aCC c++ +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); } + +{ 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=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= + +{ 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/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + 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 + + +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 +{ 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; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_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_c_preproc_warn_flag$ac_c_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_c_preproc_warn_flag$ac_c_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_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_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_c_preproc_warn_flag$ac_c_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_c_preproc_warn_flag$ac_c_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 \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&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 + + +# 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' + +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 + + +# By default we simply use the C compiler to build assembly code. + +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS + + + +depcc="$CCAS" 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_CCAS_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_CCAS_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/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + 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_CCAS_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CCAS_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CCAS_dependencies_compiler_type" >&6; } +CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then + am__fastdepCCAS_TRUE= + am__fastdepCCAS_FALSE='#' +else + am__fastdepCCAS_TRUE='#' + am__fastdepCCAS_FALSE= +fi + + + +ZEROGS_CURRENT=0 +ZEROGS_REVISION=96 +ZEROGS_AGE=2 +ZEROGS_SONAME=libZeroGSogl.so.$ZEROGS_CURRENT.$ZEROGS_REVISION.$ZEROGS_AGE +ZEROGS_RELEASE=$ZEROGS_CURRENT.$ZEROGS_REVISION.$ZEROGS_AGE + + + + + + + +CFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CPPFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CXXFLAGS=" -I/opt/cg/include -L/opt/cg/lib " + +{ echo "$as_me:$LINENO: checking debug build" >&5 +echo $ECHO_N "checking debug build... $ECHO_C" >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then + enableval=$enable_debug; debug=$enableval +else + debug=no +fi + +if test "x$debug" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define _DEBUG 1 +_ACEOF + + CFLAGS+="-g " + CPPFLAGS+="-g " + CXXFLAGS+="-g " +else + +cat >>confdefs.h <<\_ACEOF +#define NDEBUG 1 +_ACEOF + + CFLAGS+="-O3 -fomit-frame-pointer " + CPPFLAGS+="-O3 -fomit-frame-pointer " + CXXFLAGS+="-O3 -fomit-frame-pointer " +fi +{ echo "$as_me:$LINENO: result: $debug" >&5 +echo "${ECHO_T}$debug" >&6; } + + + + +for ac_func in _aligned_malloc _aligned_free +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_c_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 + cat >>confdefs.h <<\_ACEOF +#define HAVE_ALIGNED_MALLOC 1 +_ACEOF + +fi +done + + +{ echo "$as_me:$LINENO: checking for development build..." >&5 +echo $ECHO_N "checking for development build...... $ECHO_C" >&6; } +# Check whether --enable-devbuild was given. +if test "${enable_devbuild+set}" = set; then + enableval=$enable_devbuild; devbuild=$enableval +else + devbuild=no +fi + +if test "x$devbuild" == xno +then + +cat >>confdefs.h <<\_ACEOF +#define RELEASE_TO_PUBLIC 1 +_ACEOF + +fi +{ echo "$as_me:$LINENO: result: $devbuild" >&5 +echo "${ECHO_T}$devbuild" >&6; } + if test x$devbuild = xno; then + RELEASE_TO_PUBLIC_TRUE= + RELEASE_TO_PUBLIC_FALSE='#' +else + RELEASE_TO_PUBLIC_TRUE='#' + RELEASE_TO_PUBLIC_FALSE= +fi + + +{ echo "$as_me:$LINENO: checking check for sse2..." >&5 +echo $ECHO_N "checking check for sse2...... $ECHO_C" >&6; } +# Check whether --enable-sse2 was given. +if test "${enable_sse2+set}" = set; then + enableval=$enable_sse2; sse2=$enableval +else + sse2=no +fi + +if test "x$sse2" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define ZEROGS_SSE2 1 +_ACEOF + +fi +{ echo "$as_me:$LINENO: result: $sse2" >&5 +echo "${ECHO_T}$sse2" >&6; } + if test x$sse2 = xyes; then + SSE2_TRUE= + SSE2_FALSE='#' +else + SSE2_TRUE='#' + SSE2_FALSE= +fi + + +{ echo "$as_me:$LINENO: checking for a x86-64 CPU" >&5 +echo $ECHO_N "checking for a x86-64 CPU... $ECHO_C" >&6; } +if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +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() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +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 + cpu64=yes +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 ) +cpu64=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +if test "x$cpu64" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define __x86_64__ 1 +_ACEOF + +fi +{ echo "$as_me:$LINENO: result: $cpu64" >&5 +echo "${ECHO_T}$cpu64" >&6; } + if test x$cpu64 = xyes; then + X86_64_TRUE= + X86_64_FALSE='#' +else + X86_64_TRUE='#' + X86_64_FALSE= +fi + + +{ echo "$as_me:$LINENO: checking gtk2+" >&5 +echo $ECHO_N "checking gtk2+... $ECHO_C" >&6; } +# Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; 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_GTK_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$GTK_CONFIG"; then + ac_cv_prog_GTK_CONFIG="$GTK_CONFIG" # 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_GTK_CONFIG="pkg-config" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +GTK_CONFIG=$ac_cv_prog_GTK_CONFIG +if test -n "$GTK_CONFIG"; then + { echo "$as_me:$LINENO: result: $GTK_CONFIG" >&5 +echo "${ECHO_T}$GTK_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +LIBS+=$(pkg-config --libs gtk+-2.0) + + +so_ext=".so.$ZEROGS_RELEASE" +SHARED_LDFLAGS="-shared" + + + +{ echo "$as_me:$LINENO: checking OpenGL" >&5 +echo $ECHO_N "checking OpenGL... $ECHO_C" >&6; } + + + +for ac_header in GL/gl.h GL/glu.h GL/glext.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. */ +#if HAVE_GL_GL_H + #include + #endif + #if HAVE_GL_GLU_H + #include + #endif + + +#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_c_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 main in -lGL" >&5 +echo $ECHO_N "checking for main in -lGL... $ECHO_C" >&6; } +if test "${ac_cv_lib_GL_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGL $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_GL_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GL_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_GL_main" >&5 +echo "${ECHO_T}$ac_cv_lib_GL_main" >&6; } +if test $ac_cv_lib_GL_main = yes; then + LIBS="$LIBS -lGL" +fi + +{ echo "$as_me:$LINENO: checking for main in -lGLU" >&5 +echo $ECHO_N "checking for main in -lGLU... $ECHO_C" >&6; } +if test "${ac_cv_lib_GLU_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGLU $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_GLU_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GLU_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_GLU_main" >&5 +echo "${ECHO_T}$ac_cv_lib_GLU_main" >&6; } +if test $ac_cv_lib_GLU_main = yes; then + LIBS="$LIBS -lGLU" +fi + +{ echo "$as_me:$LINENO: checking for main in -lGLEW" >&5 +echo $ECHO_N "checking for main in -lGLEW... $ECHO_C" >&6; } +if test "${ac_cv_lib_GLEW_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGLEW $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_GLEW_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GLEW_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_GLEW_main" >&5 +echo "${ECHO_T}$ac_cv_lib_GLEW_main" >&6; } +if test $ac_cv_lib_GLEW_main = yes; then + LIBS="$LIBS -lGLEW" +fi + +{ echo "$as_me:$LINENO: checking Cg" >&5 +echo $ECHO_N "checking Cg... $ECHO_C" >&6; } +#AC_CHECK_HEADERS([Cg/cg.h Cg/cgGL.h]) + +{ echo "$as_me:$LINENO: checking for main in -ljpeg" >&5 +echo $ECHO_N "checking for main in -ljpeg... $ECHO_C" >&6; } +if test "${ac_cv_lib_jpeg_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ljpeg $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_jpeg_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_jpeg_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_jpeg_main" >&5 +echo "${ECHO_T}$ac_cv_lib_jpeg_main" >&6; } +if test $ac_cv_lib_jpeg_main = yes; then + LIBS="$LIBS -ljpeg" +fi + +{ echo "$as_me:$LINENO: checking for main in -lpthread" >&5 +echo $ECHO_N "checking for main in -lpthread... $ECHO_C" >&6; } +if test "${ac_cv_lib_pthread_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_pthread_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pthread_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_main" >&5 +echo "${ECHO_T}$ac_cv_lib_pthread_main" >&6; } +if test $ac_cv_lib_pthread_main = yes; then + LIBS="$LIBS -lpthread" +fi + +{ echo "$as_me:$LINENO: checking for main in -lstdc++" >&5 +echo $ECHO_N "checking for main in -lstdc++... $ECHO_C" >&6; } +if test "${ac_cv_lib_stdcpp_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lstdc++ $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_stdcpp_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_stdcpp_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_stdcpp_main" >&5 +echo "${ECHO_T}$ac_cv_lib_stdcpp_main" >&6; } +if test $ac_cv_lib_stdcpp_main = yes; then + LIBS="$LIBS -lstdc++" +fi + +{ echo "$as_me:$LINENO: checking for main in -lz" >&5 +echo $ECHO_N "checking for main in -lz... $ECHO_C" >&6; } +if test "${ac_cv_lib_z_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_z_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_z_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_z_main" >&5 +echo "${ECHO_T}$ac_cv_lib_z_main" >&6; } +if test $ac_cv_lib_z_main = yes; then + LIBS="$LIBS -lz" +fi + +{ echo "$as_me:$LINENO: checking for main in -ldl" >&5 +echo $ECHO_N "checking for main in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_main" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_main" >&6; } +if test $ac_cv_lib_dl_main = yes; then + LIBS="$LIBS -ldl" +fi + +{ echo "$as_me:$LINENO: checking for main in -lXxf86vm" >&5 +echo $ECHO_N "checking for main in -lXxf86vm... $ECHO_C" >&6; } +if test "${ac_cv_lib_Xxf86vm_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXxf86vm $LIBS" +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 main (); + ; + 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_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_Xxf86vm_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_Xxf86vm_main=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_Xxf86vm_main" >&5 +echo "${ECHO_T}$ac_cv_lib_Xxf86vm_main" >&6; } +if test $ac_cv_lib_Xxf86vm_main = yes; then + LIBS="$LIBS -lXxf86vm" +fi + + +LIBS+=" -lCg -lCgGL" + +ac_config_files="$ac_config_files Makefile Linux/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_*) { 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__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" 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 "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${RELEASE_TO_PUBLIC_TRUE}" && test -z "${RELEASE_TO_PUBLIC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"RELEASE_TO_PUBLIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"RELEASE_TO_PUBLIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SSE2_TRUE}" && test -z "${SSE2_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"SSE2\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"SSE2\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${X86_64_TRUE}" && test -z "${X86_64_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"X86_64\" 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 ZeroGSogl $as_me 0.96.2, 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="\\ +ZeroGSogl config.status 0.96.2 +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' +MKDIR_P='$MKDIR_P' +_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" ;; + "Linux/Makefile") CONFIG_FILES="$CONFIG_FILES Linux/Makefile" ;; + + *) { { 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 +am__isrc!$am__isrc$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 +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$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 +CCDEPMODE!$CCDEPMODE$ac_delim +am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim +am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +CPP!$CPP$ac_delim +RANLIB!$RANLIB$ac_delim +CCAS!$CCAS$ac_delim +CCASFLAGS!$CCASFLAGS$ac_delim +CCASDEPMODE!$CCASDEPMODE$ac_delim +am__fastdepCCAS_TRUE!$am__fastdepCCAS_TRUE$ac_delim +am__fastdepCCAS_FALSE!$am__fastdepCCAS_FALSE$ac_delim +ZEROGS_CURRENT!$ZEROGS_CURRENT$ac_delim +ZEROGS_REVISION!$ZEROGS_REVISION$ac_delim +ZEROGS_AGE!$ZEROGS_AGE$ac_delim +ZEROGS_RELEASE!$ZEROGS_RELEASE$ac_delim +ZEROGS_SONAME!$ZEROGS_SONAME$ac_delim +RELEASE_TO_PUBLIC_TRUE!$RELEASE_TO_PUBLIC_TRUE$ac_delim +RELEASE_TO_PUBLIC_FALSE!$RELEASE_TO_PUBLIC_FALSE$ac_delim +SSE2_TRUE!$SSE2_TRUE$ac_delim +SSE2_FALSE!$SSE2_FALSE$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; 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 +_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 +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +X86_64_TRUE!$X86_64_TRUE$ac_delim +X86_64_FALSE!$X86_64_FALSE$ac_delim +GTK_CONFIG!$GTK_CONFIG$ac_delim +so_ext!$so_ext$ac_delim +SHARED_LDFLAGS!$SHARED_LDFLAGS$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` = 7; 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-2.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 + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + 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 +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.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. + # 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 || +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 + + +echo "Configuration:" +echo " Target system type: $target" +echo " x86-64 build? $cpu64" +echo " Debug build? $debug" +echo " Dev build? $devbuild" +echo " SSE2 enabled? $sse2" diff --git a/plugins/gs/zerogs/opengl/configure.ac b/plugins/gs/zerogs/opengl/configure.ac new file mode 100644 index 0000000000..f71904478f --- /dev/null +++ b/plugins/gs/zerogs/opengl/configure.ac @@ -0,0 +1,149 @@ +AC_INIT(ZeroGSogl,0.96.2,zerofrog@gmail.com) + +AM_INIT_AUTOMAKE(ZeroGSogl,0.96.2) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) + +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +ZEROGS_CURRENT=0 +ZEROGS_REVISION=96 +ZEROGS_AGE=2 +ZEROGS_SONAME=libZeroGSogl.so.[$ZEROGS_CURRENT].[$ZEROGS_REVISION].[$ZEROGS_AGE] +ZEROGS_RELEASE=[$ZEROGS_CURRENT].[$ZEROGS_REVISION].[$ZEROGS_AGE] + +AC_SUBST(ZEROGS_CURRENT) +AC_SUBST(ZEROGS_REVISION) +AC_SUBST(ZEROGS_AGE) +AC_SUBST(ZEROGS_RELEASE) +AC_SUBST(ZEROGS_SONAME) + +CFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CPPFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CXXFLAGS=" -I/opt/cg/include -L/opt/cg/lib " + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), + debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+="-g " + CPPFLAGS+="-g " + CXXFLAGS+="-g " +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+="-O3 -fomit-frame-pointer " + CPPFLAGS+="-O3 -fomit-frame-pointer " + CXXFLAGS+="-O3 -fomit-frame-pointer " +fi +AC_MSG_RESULT($debug) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl Check for dev build +AC_MSG_CHECKING(for development build...) +AC_ARG_ENABLE(devbuild, AC_HELP_STRING([--enable-devbuild], [Special Build for developers that simplifies testing and adds extra checks]), + devbuild=$enableval,devbuild=no) +if test "x$devbuild" == xno +then + AC_DEFINE(RELEASE_TO_PUBLIC,1,[RELEASE_TO_PUBLIC]) +fi +AC_MSG_RESULT($devbuild) +AM_CONDITIONAL(RELEASE_TO_PUBLIC, test x$devbuild = xno) + +dnl Check for recompilation +AC_MSG_CHECKING(check for sse2...) +AC_ARG_ENABLE(sse2, AC_HELP_STRING([--enable-sse2], [Enable sse2 instructions]), + sse2=$enableval,sse2=no) +if test "x$sse2" == xyes +then + AC_DEFINE(ZEROGS_SSE2,1,[ZEROGS_SSE2]) +fi +AC_MSG_RESULT($sse2) +AM_CONDITIONAL(SSE2, test x$sse2 = xyes) + +dnl Check for 64bit CPU +AC_MSG_CHECKING(for a x86-64 CPU) +dnl if test "$build_os" == "target_os" +dnl then +AC_TRY_RUN([ +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} +],cpu64=yes,cpu64=no,) +dnl else +dnl cpu64=no +dnl fi +if test "x$cpu64" == xyes +then +AC_DEFINE(__x86_64__,1,[__x86_64__]) +fi +AC_MSG_RESULT($cpu64) +AM_CONDITIONAL(X86_64, test x$cpu64 = xyes) + +dnl gtk +AC_MSG_CHECKING(gtk2+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0) + +dnl bindir = pcsx2exe + +dnl assuming linux environment +so_ext=".so.$ZEROGS_RELEASE" +SHARED_LDFLAGS="-shared" +AC_SUBST(so_ext) +AC_SUBST(SHARED_LDFLAGS) + +AC_MSG_CHECKING(OpenGL) +AC_CHECK_HEADERS([GL/gl.h GL/glu.h GL/glext.h],,, + [[#if HAVE_GL_GL_H + #include + #endif + #if HAVE_GL_GLU_H + #include + #endif + ]]) +AC_CHECK_LIB(GL,main,[LIBS="$LIBS -lGL"]) +AC_CHECK_LIB(GLU,main,[LIBS="$LIBS -lGLU"]) +AC_CHECK_LIB(GLEW,main,[LIBS="$LIBS -lGLEW"]) +AC_MSG_CHECKING(Cg) +#AC_CHECK_HEADERS([Cg/cg.h Cg/cgGL.h]) + +AC_CHECK_LIB(jpeg,main,[LIBS="$LIBS -ljpeg"]) +AC_CHECK_LIB(pthread,main,[LIBS="$LIBS -lpthread"]) +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) +AC_CHECK_LIB(z,main,[LIBS="$LIBS -lz"]) +AC_CHECK_LIB(dl,main,[LIBS="$LIBS -ldl"]) +AC_CHECK_LIB(Xxf86vm,main,[LIBS="$LIBS -lXxf86vm"]) + +dnl AC_CHECK_LIB(Cg,cgCreateContext,[LIBS="$LIBS -lCg"]) +dnl AC_CHECK_LIB(CgGL,cgGLEnableProfile,[LIBS="$LIBS -lCgGL"]) +LIBS+=" -lCg -lCgGL" + +AC_OUTPUT([ + Makefile + Linux/Makefile + ]) + +echo "Configuration:" +echo " Target system type: $target" +echo " x86-64 build? $cpu64" +echo " Debug build? $debug" +echo " Dev build? $devbuild" +echo " SSE2 enabled? $sse2" diff --git a/plugins/gs/zerogs/opengl/ctx0/ps2hw_ctx.fx b/plugins/gs/zerogs/opengl/ctx0/ps2hw_ctx.fx new file mode 100644 index 0000000000..7988a22bb7 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ctx0/ps2hw_ctx.fx @@ -0,0 +1,24 @@ +// main ps2 memory, each pixel is stored in 32bit color +uniform samplerRECT g_sMemory : register(s0); + +// per context pixel shader constants +uniform half4 fTexAlpha2 : register(c2); + +uniform float4 g_fTexOffset : register(c4); // converts the page and block offsets into the mem addr/1024 +uniform float4 g_fTexDims : register(c6); // mult by tex dims when accessing the block texture +uniform float4 g_fTexBlock : register(c8); + +uniform float4 g_fClampExts : register(c10); // if clamping the texture, use (minu, minv, maxu, maxv) +uniform float4 TexWrapMode : register(c12); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +uniform float4 g_fRealTexDims : register(c14); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +uniform half4 g_fTestBlack : register(c16); // used for aem bit + +uniform float4 g_fPageOffset : register(c18); + +uniform half4 fTexAlpha : register(c20); + +// vertex shader constants +uniform float4 g_fPosXY : register(c2); \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/ctx1/ps2hw_ctx.fx b/plugins/gs/zerogs/opengl/ctx1/ps2hw_ctx.fx new file mode 100644 index 0000000000..c6332c1a59 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ctx1/ps2hw_ctx.fx @@ -0,0 +1,23 @@ +uniform samplerRECT g_sMemory : register(s1); + +// per context pixel shader constants +uniform half4 fTexAlpha2 : register(c3); + +uniform float4 g_fTexOffset : register(c5); // converts the page and block offsets into the mem addr/1024 +uniform float4 g_fTexDims : register(c7); // mult by tex dims when accessing the block texture +uniform float4 g_fTexBlock : register(c9); + +uniform float4 g_fClampExts : register(c11); // if clamping the texture, use (minu, minv, maxu, maxv) +uniform float4 TexWrapMode : register(c13); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +uniform float4 g_fRealTexDims : register(c15); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +uniform half4 g_fTestBlack : register(c17); // used for aem bit + +uniform float4 g_fPageOffset : register(c19); + +uniform half4 fTexAlpha : register(c21); + +// vertex shader constants +uniform float4 g_fPosXY : register(c3); \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/depcomp b/plugins/gs/zerogs/opengl/depcomp new file mode 100644 index 0000000000..88b3a13969 --- /dev/null +++ b/plugins/gs/zerogs/opengl/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/gs/zerogs/opengl/glprocs.c b/plugins/gs/zerogs/opengl/glprocs.c new file mode 100644 index 0000000000..da82208f15 --- /dev/null +++ b/plugins/gs/zerogs/opengl/glprocs.c @@ -0,0 +1,17864 @@ +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#include +#include + +#ifdef _WIN32 + #include + #include //"gl.h" /* Include local "gl.h". Don't include vc32 . */ + #include "glprocs.h" +#else /* GLX */ + #include + #include + #include +#include "glprocs.h"// +// #define wglGetProcAddress glXGetProcAddress +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} + +#endif + +#define _ASSERT(a) assert(a) + +static void APIENTRY InitBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColor"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColor = extproc; + + glBlendColor(red, green, blue, alpha); +} + +static void APIENTRY InitBlendEquation (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquation"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquation = extproc; + + glBlendEquation(mode); +} + +static void APIENTRY InitDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElements = extproc; + + glDrawRangeElements(mode, start, end, count, type, indices); +} + +static void APIENTRY InitColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTable = extproc; + + glColorTable(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfv = extproc; + + glColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitColorTableParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameteriv = extproc; + + glColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTable = extproc; + + glCopyColorTable(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTable = extproc; + + glGetColorTable(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfv = extproc; + + glGetColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameteriv = extproc; + + glGetColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTable = extproc; + + glColorSubTable(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTable = extproc; + + glCopyColorSubTable(target, start, x, y, width); +} + +static void APIENTRY InitConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1D = extproc; + + glConvolutionFilter1D(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2D = extproc; + + glConvolutionFilter2D(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterf (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterf = extproc; + + glConvolutionParameterf(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfv = extproc; + + glConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteri (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteri = extproc; + + glConvolutionParameteri(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriv = extproc; + + glConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1D = extproc; + + glCopyConvolutionFilter1D(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2D = extproc; + + glCopyConvolutionFilter2D(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilter = extproc; + + glGetConvolutionFilter(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfv = extproc; + + glGetConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameteriv = extproc; + + glGetConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilter = extproc; + + glGetSeparableFilter(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2D = extproc; + + glSeparableFilter2D(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogram = extproc; + + glGetHistogram(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfv = extproc; + + glGetHistogramParameterfv(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameteriv = extproc; + + glGetHistogramParameteriv(target, pname, params); +} + +static void APIENTRY InitGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmax = extproc; + + glGetMinmax(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfv = extproc; + + glGetMinmaxParameterfv(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameteriv = extproc; + + glGetMinmaxParameteriv(target, pname, params); +} + +static void APIENTRY InitHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogram = extproc; + + glHistogram(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmax (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmax = extproc; + + glMinmax(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogram (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogram = extproc; + + glResetHistogram(target); +} + +static void APIENTRY InitResetMinmax (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmax = extproc; + + glResetMinmax(target); +} + +static void APIENTRY InitTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3D = extproc; + + glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3D = extproc; + + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3D = extproc; + + glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTexture = extproc; + + glActiveTexture(texture); +} + +static void APIENTRY InitClientActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTexture = extproc; + + glClientActiveTexture(texture); +} + +static void APIENTRY InitMultiTexCoord1d (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1d = extproc; + + glMultiTexCoord1d(target, s); +} + +static void APIENTRY InitMultiTexCoord1dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dv = extproc; + + glMultiTexCoord1dv(target, v); +} + +static void APIENTRY InitMultiTexCoord1f (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1f = extproc; + + glMultiTexCoord1f(target, s); +} + +static void APIENTRY InitMultiTexCoord1fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fv = extproc; + + glMultiTexCoord1fv(target, v); +} + +static void APIENTRY InitMultiTexCoord1i (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1i = extproc; + + glMultiTexCoord1i(target, s); +} + +static void APIENTRY InitMultiTexCoord1iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iv = extproc; + + glMultiTexCoord1iv(target, v); +} + +static void APIENTRY InitMultiTexCoord1s (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1s = extproc; + + glMultiTexCoord1s(target, s); +} + +static void APIENTRY InitMultiTexCoord1sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sv = extproc; + + glMultiTexCoord1sv(target, v); +} + +static void APIENTRY InitMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2d = extproc; + + glMultiTexCoord2d(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dv = extproc; + + glMultiTexCoord2dv(target, v); +} + +static void APIENTRY InitMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2f = extproc; + + glMultiTexCoord2f(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fv = extproc; + + glMultiTexCoord2fv(target, v); +} + +static void APIENTRY InitMultiTexCoord2i (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2i = extproc; + + glMultiTexCoord2i(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iv = extproc; + + glMultiTexCoord2iv(target, v); +} + +static void APIENTRY InitMultiTexCoord2s (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2s = extproc; + + glMultiTexCoord2s(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sv = extproc; + + glMultiTexCoord2sv(target, v); +} + +static void APIENTRY InitMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3d = extproc; + + glMultiTexCoord3d(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dv = extproc; + + glMultiTexCoord3dv(target, v); +} + +static void APIENTRY InitMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3f = extproc; + + glMultiTexCoord3f(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fv = extproc; + + glMultiTexCoord3fv(target, v); +} + +static void APIENTRY InitMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3i = extproc; + + glMultiTexCoord3i(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iv = extproc; + + glMultiTexCoord3iv(target, v); +} + +static void APIENTRY InitMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3s = extproc; + + glMultiTexCoord3s(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sv = extproc; + + glMultiTexCoord3sv(target, v); +} + +static void APIENTRY InitMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4d = extproc; + + glMultiTexCoord4d(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dv = extproc; + + glMultiTexCoord4dv(target, v); +} + +static void APIENTRY InitMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4f = extproc; + + glMultiTexCoord4f(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fv = extproc; + + glMultiTexCoord4fv(target, v); +} + +static void APIENTRY InitMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4i = extproc; + + glMultiTexCoord4i(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iv = extproc; + + glMultiTexCoord4iv(target, v); +} + +static void APIENTRY InitMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4s = extproc; + + glMultiTexCoord4s(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sv = extproc; + + glMultiTexCoord4sv(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixf = extproc; + + glLoadTransposeMatrixf(m); +} + +static void APIENTRY InitLoadTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixd = extproc; + + glLoadTransposeMatrixd(m); +} + +static void APIENTRY InitMultTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixf = extproc; + + glMultTransposeMatrixf(m); +} + +static void APIENTRY InitMultTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixd = extproc; + + glMultTransposeMatrixd(m); +} + +static void APIENTRY InitSampleCoverage (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverage = extproc; + + glSampleCoverage(value, invert); +} + +static void APIENTRY InitCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3D = extproc; + + glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2D = extproc; + + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1D = extproc; + + glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3D = extproc; + + glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2D = extproc; + + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1D = extproc; + + glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImage (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImage = extproc; + + glGetCompressedTexImage(target, level, img); +} + +static void APIENTRY InitBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparate"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparate = extproc; + + glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitFogCoordf (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordf = extproc; + + glFogCoordf(coord); +} + +static void APIENTRY InitFogCoordfv (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfv = extproc; + + glFogCoordfv(coord); +} + +static void APIENTRY InitFogCoordd (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordd = extproc; + + glFogCoordd(coord); +} + +static void APIENTRY InitFogCoorddv (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddv = extproc; + + glFogCoorddv(coord); +} + +static void APIENTRY InitFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointer = extproc; + + glFogCoordPointer(type, stride, pointer); +} + +static void APIENTRY InitMultiDrawArrays (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArrays"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArrays = extproc; + + glMultiDrawArrays(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElements = extproc; + + glMultiDrawElements(mode, count, type, indices, primcount); +} + +static void APIENTRY InitPointParameterf (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterf = extproc; + + glPointParameterf(pname, param); +} + +static void APIENTRY InitPointParameterfv (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfv = extproc; + + glPointParameterfv(pname, params); +} + +static void APIENTRY InitPointParameteri (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteri = extproc; + + glPointParameteri(pname, param); +} + +static void APIENTRY InitPointParameteriv (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriv = extproc; + + glPointParameteriv(pname, params); +} + +static void APIENTRY InitSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3b"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3b = extproc; + + glSecondaryColor3b(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bv (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bv = extproc; + + glSecondaryColor3bv(v); +} + +static void APIENTRY InitSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3d = extproc; + + glSecondaryColor3d(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dv = extproc; + + glSecondaryColor3dv(v); +} + +static void APIENTRY InitSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3f = extproc; + + glSecondaryColor3f(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fv = extproc; + + glSecondaryColor3fv(v); +} + +static void APIENTRY InitSecondaryColor3i (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3i = extproc; + + glSecondaryColor3i(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iv = extproc; + + glSecondaryColor3iv(v); +} + +static void APIENTRY InitSecondaryColor3s (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3s = extproc; + + glSecondaryColor3s(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sv = extproc; + + glSecondaryColor3sv(v); +} + +static void APIENTRY InitSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ub"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ub = extproc; + + glSecondaryColor3ub(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubv (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubv = extproc; + + glSecondaryColor3ubv(v); +} + +static void APIENTRY InitSecondaryColor3ui (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ui"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ui = extproc; + + glSecondaryColor3ui(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uiv (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiv = extproc; + + glSecondaryColor3uiv(v); +} + +static void APIENTRY InitSecondaryColor3us (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3us"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3us = extproc; + + glSecondaryColor3us(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usv (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usv = extproc; + + glSecondaryColor3usv(v); +} + +static void APIENTRY InitSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointer = extproc; + + glSecondaryColorPointer(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2d (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2d = extproc; + + glWindowPos2d(x, y); +} + +static void APIENTRY InitWindowPos2dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dv = extproc; + + glWindowPos2dv(v); +} + +static void APIENTRY InitWindowPos2f (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2f = extproc; + + glWindowPos2f(x, y); +} + +static void APIENTRY InitWindowPos2fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fv = extproc; + + glWindowPos2fv(v); +} + +static void APIENTRY InitWindowPos2i (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2i = extproc; + + glWindowPos2i(x, y); +} + +static void APIENTRY InitWindowPos2iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iv = extproc; + + glWindowPos2iv(v); +} + +static void APIENTRY InitWindowPos2s (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2s = extproc; + + glWindowPos2s(x, y); +} + +static void APIENTRY InitWindowPos2sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sv = extproc; + + glWindowPos2sv(v); +} + +static void APIENTRY InitWindowPos3d (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3d = extproc; + + glWindowPos3d(x, y, z); +} + +static void APIENTRY InitWindowPos3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dv = extproc; + + glWindowPos3dv(v); +} + +static void APIENTRY InitWindowPos3f (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3f = extproc; + + glWindowPos3f(x, y, z); +} + +static void APIENTRY InitWindowPos3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fv = extproc; + + glWindowPos3fv(v); +} + +static void APIENTRY InitWindowPos3i (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3i = extproc; + + glWindowPos3i(x, y, z); +} + +static void APIENTRY InitWindowPos3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iv = extproc; + + glWindowPos3iv(v); +} + +static void APIENTRY InitWindowPos3s (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3s = extproc; + + glWindowPos3s(x, y, z); +} + +static void APIENTRY InitWindowPos3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sv = extproc; + + glWindowPos3sv(v); +} + +static void APIENTRY InitGenQueries (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueries = extproc; + + glGenQueries(n, ids); +} + +static void APIENTRY InitDeleteQueries (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueries = extproc; + + glDeleteQueries(n, ids); +} + +static GLboolean APIENTRY InitIsQuery (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQuery = extproc; + + return glIsQuery(id); +} + +static void APIENTRY InitBeginQuery (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQuery = extproc; + + glBeginQuery(target, id); +} + +static void APIENTRY InitEndQuery (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQuery = extproc; + + glEndQuery(target); +} + +static void APIENTRY InitGetQueryiv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryiv = extproc; + + glGetQueryiv(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectiv (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectiv = extproc; + + glGetQueryObjectiv(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuiv = extproc; + + glGetQueryObjectuiv(id, pname, params); +} + +static void APIENTRY InitBindBuffer (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBuffer = extproc; + + glBindBuffer(target, buffer); +} + +static void APIENTRY InitDeleteBuffers (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffers = extproc; + + glDeleteBuffers(n, buffers); +} + +static void APIENTRY InitGenBuffers (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffers = extproc; + + glGenBuffers(n, buffers); +} + +static GLboolean APIENTRY InitIsBuffer (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBuffer = extproc; + + return glIsBuffer(buffer); +} + +static void APIENTRY InitBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferData = extproc; + + glBufferData(target, size, data, usage); +} + +static void APIENTRY InitBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubData = extproc; + + glBufferSubData(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubData = extproc; + + glGetBufferSubData(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBuffer (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBuffer = extproc; + + return glMapBuffer(target, access); +} + +static GLboolean APIENTRY InitUnmapBuffer (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBuffer = extproc; + + return glUnmapBuffer(target); +} + +static void APIENTRY InitGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameteriv = extproc; + + glGetBufferParameteriv(target, pname, params); +} + +static void APIENTRY InitGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointerv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointerv = extproc; + + glGetBufferPointerv(target, pname, params); +} + +static void APIENTRY InitActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTextureARB = extproc; + + glActiveTextureARB(texture); +} + +static void APIENTRY InitClientActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTextureARB = extproc; + + glClientActiveTextureARB(texture); +} + +static void APIENTRY InitMultiTexCoord1dARB (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dARB = extproc; + + glMultiTexCoord1dARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dvARB = extproc; + + glMultiTexCoord1dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1fARB (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fARB = extproc; + + glMultiTexCoord1fARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fvARB = extproc; + + glMultiTexCoord1fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1iARB (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iARB = extproc; + + glMultiTexCoord1iARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1ivARB = extproc; + + glMultiTexCoord1ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1sARB (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sARB = extproc; + + glMultiTexCoord1sARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1svARB = extproc; + + glMultiTexCoord1svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dARB = extproc; + + glMultiTexCoord2dARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dvARB = extproc; + + glMultiTexCoord2dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fARB = extproc; + + glMultiTexCoord2fARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fvARB = extproc; + + glMultiTexCoord2fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2iARB (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iARB = extproc; + + glMultiTexCoord2iARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2ivARB = extproc; + + glMultiTexCoord2ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sARB = extproc; + + glMultiTexCoord2sARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2svARB = extproc; + + glMultiTexCoord2svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dARB = extproc; + + glMultiTexCoord3dARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dvARB = extproc; + + glMultiTexCoord3dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fARB = extproc; + + glMultiTexCoord3fARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fvARB = extproc; + + glMultiTexCoord3fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iARB = extproc; + + glMultiTexCoord3iARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3ivARB = extproc; + + glMultiTexCoord3ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sARB = extproc; + + glMultiTexCoord3sARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3svARB = extproc; + + glMultiTexCoord3svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dARB = extproc; + + glMultiTexCoord4dARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dvARB = extproc; + + glMultiTexCoord4dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fARB = extproc; + + glMultiTexCoord4fARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fvARB = extproc; + + glMultiTexCoord4fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iARB = extproc; + + glMultiTexCoord4iARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4ivARB = extproc; + + glMultiTexCoord4ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sARB = extproc; + + glMultiTexCoord4sARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4svARB = extproc; + + glMultiTexCoord4svARB(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixfARB = extproc; + + glLoadTransposeMatrixfARB(m); +} + +static void APIENTRY InitLoadTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixdARB = extproc; + + glLoadTransposeMatrixdARB(m); +} + +static void APIENTRY InitMultTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixfARB = extproc; + + glMultTransposeMatrixfARB(m); +} + +static void APIENTRY InitMultTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixdARB = extproc; + + glMultTransposeMatrixdARB(m); +} + +static void APIENTRY InitSampleCoverageARB (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverageARB = extproc; + + glSampleCoverageARB(value, invert); +} + +static void APIENTRY InitCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3DARB = extproc; + + glCompressedTexImage3DARB(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2DARB = extproc; + + glCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1DARB = extproc; + + glCompressedTexImage1DARB(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3DARB = extproc; + + glCompressedTexSubImage3DARB(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2DARB = extproc; + + glCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1DARB = extproc; + + glCompressedTexSubImage1DARB(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImageARB = extproc; + + glGetCompressedTexImageARB(target, level, img); +} + +static void APIENTRY InitPointParameterfARB (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfARB = extproc; + + glPointParameterfARB(pname, param); +} + +static void APIENTRY InitPointParameterfvARB (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvARB = extproc; + + glPointParameterfvARB(pname, params); +} + +static void APIENTRY InitWeightbvARB (GLint size, const GLbyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightbvARB = extproc; + + glWeightbvARB(size, weights); +} + +static void APIENTRY InitWeightsvARB (GLint size, const GLshort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightsvARB = extproc; + + glWeightsvARB(size, weights); +} + +static void APIENTRY InitWeightivARB (GLint size, const GLint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightivARB = extproc; + + glWeightivARB(size, weights); +} + +static void APIENTRY InitWeightfvARB (GLint size, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightfvARB = extproc; + + glWeightfvARB(size, weights); +} + +static void APIENTRY InitWeightdvARB (GLint size, const GLdouble *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightdvARB = extproc; + + glWeightdvARB(size, weights); +} + +static void APIENTRY InitWeightubvARB (GLint size, const GLubyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightubvARB = extproc; + + glWeightubvARB(size, weights); +} + +static void APIENTRY InitWeightusvARB (GLint size, const GLushort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightusvARB = extproc; + + glWeightusvARB(size, weights); +} + +static void APIENTRY InitWeightuivARB (GLint size, const GLuint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightuivARB = extproc; + + glWeightuivARB(size, weights); +} + +static void APIENTRY InitWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightPointerARB = extproc; + + glWeightPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitVertexBlendARB (GLint count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendARB = extproc; + + glVertexBlendARB(count); +} + +static void APIENTRY InitCurrentPaletteMatrixARB (GLint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCurrentPaletteMatrixARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCurrentPaletteMatrixARB = extproc; + + glCurrentPaletteMatrixARB(index); +} + +static void APIENTRY InitMatrixIndexubvARB (GLint size, const GLubyte *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexubvARB = extproc; + + glMatrixIndexubvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexusvARB (GLint size, const GLushort *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexusvARB = extproc; + + glMatrixIndexusvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexuivARB (GLint size, const GLuint *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexuivARB = extproc; + + glMatrixIndexuivARB(size, indices); +} + +static void APIENTRY InitMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexPointerARB = extproc; + + glMatrixIndexPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2dARB (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dARB = extproc; + + glWindowPos2dARB(x, y); +} + +static void APIENTRY InitWindowPos2dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvARB = extproc; + + glWindowPos2dvARB(v); +} + +static void APIENTRY InitWindowPos2fARB (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fARB = extproc; + + glWindowPos2fARB(x, y); +} + +static void APIENTRY InitWindowPos2fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvARB = extproc; + + glWindowPos2fvARB(v); +} + +static void APIENTRY InitWindowPos2iARB (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iARB = extproc; + + glWindowPos2iARB(x, y); +} + +static void APIENTRY InitWindowPos2ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivARB = extproc; + + glWindowPos2ivARB(v); +} + +static void APIENTRY InitWindowPos2sARB (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sARB = extproc; + + glWindowPos2sARB(x, y); +} + +static void APIENTRY InitWindowPos2svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svARB = extproc; + + glWindowPos2svARB(v); +} + +static void APIENTRY InitWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dARB = extproc; + + glWindowPos3dARB(x, y, z); +} + +static void APIENTRY InitWindowPos3dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvARB = extproc; + + glWindowPos3dvARB(v); +} + +static void APIENTRY InitWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fARB = extproc; + + glWindowPos3fARB(x, y, z); +} + +static void APIENTRY InitWindowPos3fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvARB = extproc; + + glWindowPos3fvARB(v); +} + +static void APIENTRY InitWindowPos3iARB (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iARB = extproc; + + glWindowPos3iARB(x, y, z); +} + +static void APIENTRY InitWindowPos3ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivARB = extproc; + + glWindowPos3ivARB(v); +} + +static void APIENTRY InitWindowPos3sARB (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sARB = extproc; + + glWindowPos3sARB(x, y, z); +} + +static void APIENTRY InitWindowPos3svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svARB = extproc; + + glWindowPos3svARB(v); +} + +static void APIENTRY InitVertexAttrib1dARB (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dARB = extproc; + + glVertexAttrib1dARB(index, x); +} + +static void APIENTRY InitVertexAttrib1dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvARB = extproc; + + glVertexAttrib1dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1fARB (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fARB = extproc; + + glVertexAttrib1fARB(index, x); +} + +static void APIENTRY InitVertexAttrib1fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvARB = extproc; + + glVertexAttrib1fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1sARB (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sARB = extproc; + + glVertexAttrib1sARB(index, x); +} + +static void APIENTRY InitVertexAttrib1svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svARB = extproc; + + glVertexAttrib1svARB(index, v); +} + +static void APIENTRY InitVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dARB = extproc; + + glVertexAttrib2dARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvARB = extproc; + + glVertexAttrib2dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fARB = extproc; + + glVertexAttrib2fARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvARB = extproc; + + glVertexAttrib2fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2sARB (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sARB = extproc; + + glVertexAttrib2sARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svARB = extproc; + + glVertexAttrib2svARB(index, v); +} + +static void APIENTRY InitVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dARB = extproc; + + glVertexAttrib3dARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvARB = extproc; + + glVertexAttrib3dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fARB = extproc; + + glVertexAttrib3fARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvARB = extproc; + + glVertexAttrib3fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sARB = extproc; + + glVertexAttrib3sARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svARB = extproc; + + glVertexAttrib3svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NbvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NbvARB = extproc; + + glVertexAttrib4NbvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NivARB = extproc; + + glVertexAttrib4NivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NsvARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NsvARB = extproc; + + glVertexAttrib4NsvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubARB = extproc; + + glVertexAttrib4NubARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4NubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubvARB = extproc; + + glVertexAttrib4NubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NuivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NuivARB = extproc; + + glVertexAttrib4NuivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NusvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NusvARB = extproc; + + glVertexAttrib4NusvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4bvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4bvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4bvARB = extproc; + + glVertexAttrib4bvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dARB = extproc; + + glVertexAttrib4dARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvARB = extproc; + + glVertexAttrib4dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fARB = extproc; + + glVertexAttrib4fARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvARB = extproc; + + glVertexAttrib4fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ivARB = extproc; + + glVertexAttrib4ivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sARB = extproc; + + glVertexAttrib4sARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svARB = extproc; + + glVertexAttrib4svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvARB = extproc; + + glVertexAttrib4ubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4uivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4uivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4uivARB = extproc; + + glVertexAttrib4uivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4usvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4usvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4usvARB = extproc; + + glVertexAttrib4usvARB(index, v); +} + +static void APIENTRY InitVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerARB = extproc; + + glVertexAttribPointerARB(index, size, type, normalized, stride, pointer); +} + +static void APIENTRY InitEnableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVertexAttribArrayARB = extproc; + + glEnableVertexAttribArrayARB(index); +} + +static void APIENTRY InitDisableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVertexAttribArrayARB = extproc; + + glDisableVertexAttribArrayARB(index); +} + +static void APIENTRY InitProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramStringARB = extproc; + + glProgramStringARB(target, format, len, string); +} + +static void APIENTRY InitBindProgramARB (GLenum target, GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramARB = extproc; + + glBindProgramARB(target, program); +} + +static void APIENTRY InitDeleteProgramsARB (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsARB = extproc; + + glDeleteProgramsARB(n, programs); +} + +static void APIENTRY InitGenProgramsARB (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsARB = extproc; + + glGenProgramsARB(n, programs); +} + +static void APIENTRY InitProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dARB = extproc; + + glProgramEnvParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dvARB = extproc; + + glProgramEnvParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fARB = extproc; + + glProgramEnvParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fvARB = extproc; + + glProgramEnvParameter4fvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dARB = extproc; + + glProgramLocalParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dvARB = extproc; + + glProgramLocalParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fARB = extproc; + + glProgramLocalParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fvARB = extproc; + + glProgramLocalParameter4fvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterdvARB = extproc; + + glGetProgramEnvParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterfvARB = extproc; + + glGetProgramEnvParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterdvARB = extproc; + + glGetProgramLocalParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterfvARB = extproc; + + glGetProgramLocalParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivARB = extproc; + + glGetProgramivARB(target, pname, params); +} + +static void APIENTRY InitGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringARB = extproc; + + glGetProgramStringARB(target, pname, string); +} + +static void APIENTRY InitGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvARB = extproc; + + glGetVertexAttribdvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvARB = extproc; + + glGetVertexAttribfvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivARB = extproc; + + glGetVertexAttribivARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervARB = extproc; + + glGetVertexAttribPointervARB(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramARB (GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramARB = extproc; + + return glIsProgramARB(program); +} + +static void APIENTRY InitBindBufferARB (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBufferARB = extproc; + + glBindBufferARB(target, buffer); +} + +static void APIENTRY InitDeleteBuffersARB (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffersARB = extproc; + + glDeleteBuffersARB(n, buffers); +} + +static void APIENTRY InitGenBuffersARB (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffersARB = extproc; + + glGenBuffersARB(n, buffers); +} + +static GLboolean APIENTRY InitIsBufferARB (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBufferARB = extproc; + + return glIsBufferARB(buffer); +} + +static void APIENTRY InitBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferDataARB = extproc; + + glBufferDataARB(target, size, data, usage); +} + +static void APIENTRY InitBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubDataARB = extproc; + + glBufferSubDataARB(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubDataARB = extproc; + + glGetBufferSubDataARB(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBufferARB (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBufferARB = extproc; + + return glMapBufferARB(target, access); +} + +static GLboolean APIENTRY InitUnmapBufferARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBufferARB = extproc; + + return glUnmapBufferARB(target); +} + +static void APIENTRY InitGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameterivARB = extproc; + + glGetBufferParameterivARB(target, pname, params); +} + +static void APIENTRY InitGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointervARB = extproc; + + glGetBufferPointervARB(target, pname, params); +} + +static void APIENTRY InitGenQueriesARB (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueriesARB = extproc; + + glGenQueriesARB(n, ids); +} + +static void APIENTRY InitDeleteQueriesARB (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueriesARB = extproc; + + glDeleteQueriesARB(n, ids); +} + +static GLboolean APIENTRY InitIsQueryARB (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQueryARB = extproc; + + return glIsQueryARB(id); +} + +static void APIENTRY InitBeginQueryARB (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQueryARB = extproc; + + glBeginQueryARB(target, id); +} + +static void APIENTRY InitEndQueryARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQueryARB = extproc; + + glEndQueryARB(target); +} + +static void APIENTRY InitGetQueryivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryivARB = extproc; + + glGetQueryivARB(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectivARB = extproc; + + glGetQueryObjectivARB(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuivARB = extproc; + + glGetQueryObjectuivARB(id, pname, params); +} + +static void APIENTRY InitDeleteObjectARB (GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteObjectARB = extproc; + + glDeleteObjectARB(obj); +} + +static GLhandleARB APIENTRY InitGetHandleARB (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHandleARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetHandleARB = extproc; + + return glGetHandleARB(pname); +} + +static void APIENTRY InitDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetachObjectARB = extproc; + + glDetachObjectARB(containerObj, attachedObj); +} + +static GLhandleARB APIENTRY InitCreateShaderObjectARB (GLenum shaderType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateShaderObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateShaderObjectARB = extproc; + + return glCreateShaderObjectARB(shaderType); +} + +static void APIENTRY InitShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderSourceARB = extproc; + + glShaderSourceARB(shaderObj, count, string, length); +} + +static void APIENTRY InitCompileShaderARB (GLhandleARB shaderObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompileShaderARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompileShaderARB = extproc; + + glCompileShaderARB(shaderObj); +} + +static GLhandleARB APIENTRY InitCreateProgramObjectARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateProgramObjectARB = extproc; + + return glCreateProgramObjectARB(); +} + +static void APIENTRY InitAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAttachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAttachObjectARB = extproc; + + glAttachObjectARB(containerObj, obj); +} + +static void APIENTRY InitLinkProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLinkProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLinkProgramARB = extproc; + + glLinkProgramARB(programObj); +} + +static void APIENTRY InitUseProgramObjectARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUseProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUseProgramObjectARB = extproc; + + glUseProgramObjectARB(programObj); +} + +static void APIENTRY InitValidateProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glValidateProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glValidateProgramARB = extproc; + + glValidateProgramARB(programObj); +} + +static void APIENTRY InitUniform1fARB (GLint location, GLfloat v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fARB = extproc; + + glUniform1fARB(location, v0); +} + +static void APIENTRY InitUniform2fARB (GLint location, GLfloat v0, GLfloat v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fARB = extproc; + + glUniform2fARB(location, v0, v1); +} + +static void APIENTRY InitUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fARB = extproc; + + glUniform3fARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fARB = extproc; + + glUniform4fARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1iARB (GLint location, GLint v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1iARB = extproc; + + glUniform1iARB(location, v0); +} + +static void APIENTRY InitUniform2iARB (GLint location, GLint v0, GLint v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2iARB = extproc; + + glUniform2iARB(location, v0, v1); +} + +static void APIENTRY InitUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3iARB = extproc; + + glUniform3iARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4iARB = extproc; + + glUniform4iARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fvARB = extproc; + + glUniform1fvARB(location, count, value); +} + +static void APIENTRY InitUniform2fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fvARB = extproc; + + glUniform2fvARB(location, count, value); +} + +static void APIENTRY InitUniform3fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fvARB = extproc; + + glUniform3fvARB(location, count, value); +} + +static void APIENTRY InitUniform4fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fvARB = extproc; + + glUniform4fvARB(location, count, value); +} + +static void APIENTRY InitUniform1ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1ivARB = extproc; + + glUniform1ivARB(location, count, value); +} + +static void APIENTRY InitUniform2ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2ivARB = extproc; + + glUniform2ivARB(location, count, value); +} + +static void APIENTRY InitUniform3ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3ivARB = extproc; + + glUniform3ivARB(location, count, value); +} + +static void APIENTRY InitUniform4ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4ivARB = extproc; + + glUniform4ivARB(location, count, value); +} + +static void APIENTRY InitUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix2fvARB = extproc; + + glUniformMatrix2fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix3fvARB = extproc; + + glUniformMatrix3fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix4fvARB = extproc; + + glUniformMatrix4fvARB(location, count, transpose, value); +} + +static void APIENTRY InitGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterfvARB = extproc; + + glGetObjectParameterfvARB(obj, pname, params); +} + +static void APIENTRY InitGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterivARB = extproc; + + glGetObjectParameterivARB(obj, pname, params); +} + +static void APIENTRY InitGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInfoLogARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInfoLogARB = extproc; + + glGetInfoLogARB(obj, maxLength, length, infoLog); +} + +static void APIENTRY InitGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttachedObjectsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetAttachedObjectsARB = extproc; + + glGetAttachedObjectsARB(containerObj, maxCount, count, obj); +} + +static GLint APIENTRY InitGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetUniformLocationARB = extproc; + + return glGetUniformLocationARB(programObj, name); +} + +static void APIENTRY InitGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveUniformARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveUniformARB = extproc; + + glGetActiveUniformARB(programObj, index, maxLength, length, size, type, name); +} + +static void APIENTRY InitGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformfvARB = extproc; + + glGetUniformfvARB(programObj, location, params); +} + +static void APIENTRY InitGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformivARB = extproc; + + glGetUniformivARB(programObj, location, params); +} + +static void APIENTRY InitGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetShaderSourceARB = extproc; + + glGetShaderSourceARB(obj, maxLength, length, source); +} + +static void APIENTRY InitBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindAttribLocationARB = extproc; + + glBindAttribLocationARB(programObj, index, name); +} + +static void APIENTRY InitGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveAttribARB = extproc; + + glGetActiveAttribARB(programObj, index, maxLength, length, size, type, name); +} + +static GLint APIENTRY InitGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetAttribLocationARB = extproc; + + return glGetAttribLocationARB(programObj, name); +} + +static void APIENTRY InitBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColorEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColorEXT = extproc; + + glBlendColorEXT(red, green, blue, alpha); +} + +static void APIENTRY InitPolygonOffsetEXT (GLfloat factor, GLfloat bias) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPolygonOffsetEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPolygonOffsetEXT = extproc; + + glPolygonOffsetEXT(factor, bias); +} + +static void APIENTRY InitTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3DEXT = extproc; + + glTexImage3DEXT(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3DEXT = extproc; + + glTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexFilterFuncSGIS = extproc; + + glGetTexFilterFuncSGIS(target, filter, weights); +} + +static void APIENTRY InitTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexFilterFuncSGIS = extproc; + + glTexFilterFuncSGIS(target, filter, n, weights); +} + +static void APIENTRY InitTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage1DEXT = extproc; + + glTexSubImage1DEXT(target, level, xoffset, width, format, type, pixels); +} + +static void APIENTRY InitTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage2DEXT = extproc; + + glTexSubImage2DEXT(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +static void APIENTRY InitCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage1DEXT = extproc; + + glCopyTexImage1DEXT(target, level, internalformat, x, y, width, border); +} + +static void APIENTRY InitCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage2DEXT = extproc; + + glCopyTexImage2DEXT(target, level, internalformat, x, y, width, height, border); +} + +static void APIENTRY InitCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage1DEXT = extproc; + + glCopyTexSubImage1DEXT(target, level, xoffset, x, y, width); +} + +static void APIENTRY InitCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage2DEXT = extproc; + + glCopyTexSubImage2DEXT(target, level, xoffset, yoffset, x, y, width, height); +} + +static void APIENTRY InitCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3DEXT = extproc; + + glCopyTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramEXT = extproc; + + glGetHistogramEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfvEXT = extproc; + + glGetHistogramParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterivEXT = extproc; + + glGetHistogramParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxEXT = extproc; + + glGetMinmaxEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfvEXT = extproc; + + glGetMinmaxParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterivEXT = extproc; + + glGetMinmaxParameterivEXT(target, pname, params); +} + +static void APIENTRY InitHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogramEXT = extproc; + + glHistogramEXT(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmaxEXT = extproc; + + glMinmaxEXT(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogramEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogramEXT = extproc; + + glResetHistogramEXT(target); +} + +static void APIENTRY InitResetMinmaxEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmaxEXT = extproc; + + glResetMinmaxEXT(target); +} + +static void APIENTRY InitConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1DEXT = extproc; + + glConvolutionFilter1DEXT(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2DEXT = extproc; + + glConvolutionFilter2DEXT(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfEXT = extproc; + + glConvolutionParameterfEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfvEXT = extproc; + + glConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriEXT = extproc; + + glConvolutionParameteriEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterivEXT = extproc; + + glConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1DEXT = extproc; + + glCopyConvolutionFilter1DEXT(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2DEXT = extproc; + + glCopyConvolutionFilter2DEXT(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilterEXT = extproc; + + glGetConvolutionFilterEXT(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfvEXT = extproc; + + glGetConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterivEXT = extproc; + + glGetConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilterEXT = extproc; + + glGetSeparableFilterEXT(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2DEXT = extproc; + + glSeparableFilter2DEXT(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableSGI = extproc; + + glColorTableSGI(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfvSGI = extproc; + + glColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterivSGI = extproc; + + glColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTableSGI = extproc; + + glCopyColorTableSGI(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableSGI = extproc; + + glGetColorTableSGI(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvSGI = extproc; + + glGetColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivSGI = extproc; + + glGetColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitPixelTexGenSGIX (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenSGIX = extproc; + + glPixelTexGenSGIX(mode); +} + +static void APIENTRY InitPixelTexGenParameteriSGIS (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameteriSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameteriSGIS = extproc; + + glPixelTexGenParameteriSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterivSGIS (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterivSGIS = extproc; + + glPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitPixelTexGenParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfSGIS = extproc; + + glPixelTexGenParameterfSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfvSGIS = extproc; + + glPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterivSGIS = extproc; + + glGetPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterfvSGIS = extproc; + + glGetPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage4DSGIS = extproc; + + glTexImage4DSGIS(target, level, internalformat, width, height, depth, size4d, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage4DSGIS = extproc; + + glTexSubImage4DSGIS(target, level, xoffset, yoffset, zoffset, woffset, width, height, depth, size4d, format, type, pixels); +} + +static GLboolean APIENTRY InitAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreTexturesResidentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreTexturesResidentEXT = extproc; + + return glAreTexturesResidentEXT(n, textures, residences); +} + +static void APIENTRY InitBindTextureEXT (GLenum target, GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindTextureEXT = extproc; + + glBindTextureEXT(target, texture); +} + +static void APIENTRY InitDeleteTexturesEXT (GLsizei n, const GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteTexturesEXT = extproc; + + glDeleteTexturesEXT(n, textures); +} + +static void APIENTRY InitGenTexturesEXT (GLsizei n, GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenTexturesEXT = extproc; + + glGenTexturesEXT(n, textures); +} + +static GLboolean APIENTRY InitIsTextureEXT (GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsTextureEXT = extproc; + + return glIsTextureEXT(texture); +} + +static void APIENTRY InitPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrioritizeTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrioritizeTexturesEXT = extproc; + + glPrioritizeTexturesEXT(n, textures, priorities); +} + +static void APIENTRY InitDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetailTexFuncSGIS = extproc; + + glDetailTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetDetailTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetDetailTexFuncSGIS = extproc; + + glGetDetailTexFuncSGIS(target, points); +} + +static void APIENTRY InitSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSharpenTexFuncSGIS = extproc; + + glSharpenTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetSharpenTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSharpenTexFuncSGIS = extproc; + + glGetSharpenTexFuncSGIS(target, points); +} + +static void APIENTRY InitSampleMaskSGIS (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskSGIS = extproc; + + glSampleMaskSGIS(value, invert); +} + +static void APIENTRY InitSamplePatternSGIS (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternSGIS = extproc; + + glSamplePatternSGIS(pattern); +} + +static void APIENTRY InitArrayElementEXT (GLint i) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayElementEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayElementEXT = extproc; + + glArrayElementEXT(i); +} + +static void APIENTRY InitColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerEXT = extproc; + + glColorPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitDrawArraysEXT (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawArraysEXT = extproc; + + glDrawArraysEXT(mode, first, count); +} + +static void APIENTRY InitEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerEXT = extproc; + + glEdgeFlagPointerEXT(stride, count, pointer); +} + +static void APIENTRY InitGetPointervEXT (GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPointervEXT = extproc; + + glGetPointervEXT(pname, params); +} + +static void APIENTRY InitIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerEXT = extproc; + + glIndexPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerEXT = extproc; + + glNormalPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerEXT = extproc; + + glTexCoordPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerEXT = extproc; + + glVertexPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitBlendEquationEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationEXT = extproc; + + glBlendEquationEXT(mode); +} + +static void APIENTRY InitSpriteParameterfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfSGIX = extproc; + + glSpriteParameterfSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfvSGIX = extproc; + + glSpriteParameterfvSGIX(pname, params); +} + +static void APIENTRY InitSpriteParameteriSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameteriSGIX = extproc; + + glSpriteParameteriSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterivSGIX = extproc; + + glSpriteParameterivSGIX(pname, params); +} + +static void APIENTRY InitPointParameterfEXT (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfEXT = extproc; + + glPointParameterfEXT(pname, param); +} + +static void APIENTRY InitPointParameterfvEXT (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvEXT = extproc; + + glPointParameterfvEXT(pname, params); +} + +static void APIENTRY InitPointParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfSGIS = extproc; + + glPointParameterfSGIS(pname, param); +} + +static void APIENTRY InitPointParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvSGIS = extproc; + + glPointParameterfvSGIS(pname, params); +} + +static GLint APIENTRY InitGetInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetInstrumentsSGIX = extproc; + + return glGetInstrumentsSGIX(); +} + +static void APIENTRY InitInstrumentsBufferSGIX (GLsizei size, GLint *buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInstrumentsBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInstrumentsBufferSGIX = extproc; + + glInstrumentsBufferSGIX(size, buffer); +} + +static GLint APIENTRY InitPollInstrumentsSGIX (GLint *marker_p) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollInstrumentsSGIX = extproc; + + return glPollInstrumentsSGIX(marker_p); +} + +static void APIENTRY InitReadInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReadInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReadInstrumentsSGIX = extproc; + + glReadInstrumentsSGIX(marker); +} + +static void APIENTRY InitStartInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStartInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStartInstrumentsSGIX = extproc; + + glStartInstrumentsSGIX(); +} + +static void APIENTRY InitStopInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStopInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStopInstrumentsSGIX = extproc; + + glStopInstrumentsSGIX(marker); +} + +static void APIENTRY InitFrameZoomSGIX (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFrameZoomSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFrameZoomSGIX = extproc; + + glFrameZoomSGIX(factor); +} + +static void APIENTRY InitTagSampleBufferSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTagSampleBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTagSampleBufferSGIX = extproc; + + glTagSampleBufferSGIX(); +} + +static void APIENTRY InitDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3dSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3dSGIX = extproc; + + glDeformationMap3dSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3fSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3fSGIX = extproc; + + glDeformationMap3fSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformSGIX = extproc; + + glDeformSGIX(mask); +} + +static void APIENTRY InitLoadIdentityDeformationMapSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadIdentityDeformationMapSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadIdentityDeformationMapSGIX = extproc; + + glLoadIdentityDeformationMapSGIX(mask); +} + +static void APIENTRY InitReferencePlaneSGIX (const GLdouble *equation) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReferencePlaneSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReferencePlaneSGIX = extproc; + + glReferencePlaneSGIX(equation); +} + +static void APIENTRY InitFlushRasterSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushRasterSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushRasterSGIX = extproc; + + glFlushRasterSGIX(); +} + +static void APIENTRY InitFogFuncSGIS (GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogFuncSGIS = extproc; + + glFogFuncSGIS(n, points); +} + +static void APIENTRY InitGetFogFuncSGIS (GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFogFuncSGIS = extproc; + + glGetFogFuncSGIS(points); +} + +static void APIENTRY InitImageTransformParameteriHP (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameteriHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameteriHP = extproc; + + glImageTransformParameteriHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfHP = extproc; + + glImageTransformParameterfHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterivHP = extproc; + + glImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfvHP = extproc; + + glImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterivHP = extproc; + + glGetImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterfvHP = extproc; + + glGetImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTableEXT = extproc; + + glColorSubTableEXT(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTableEXT = extproc; + + glCopyColorSubTableEXT(target, start, x, y, width); +} + +static void APIENTRY InitHintPGI (GLenum target, GLint mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHintPGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHintPGI = extproc; + + glHintPGI(target, mode); +} + +static void APIENTRY InitColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableEXT = extproc; + + glColorTableEXT(target, internalFormat, width, format, type, table); +} + +static void APIENTRY InitGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableEXT = extproc; + + glGetColorTableEXT(target, format, type, data); +} + +static void APIENTRY InitGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivEXT = extproc; + + glGetColorTableParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvEXT = extproc; + + glGetColorTableParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterfvSGIX = extproc; + + glGetListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterivSGIX = extproc; + + glGetListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitListParameterfSGIX (GLuint list, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfSGIX = extproc; + + glListParameterfSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfvSGIX = extproc; + + glListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitListParameteriSGIX (GLuint list, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameteriSGIX = extproc; + + glListParameteriSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterivSGIX (GLuint list, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterivSGIX = extproc; + + glListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitIndexMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexMaterialEXT = extproc; + + glIndexMaterialEXT(face, mode); +} + +static void APIENTRY InitIndexFuncEXT (GLenum func, GLclampf ref) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexFuncEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexFuncEXT = extproc; + + glIndexFuncEXT(func, ref); +} + +static void APIENTRY InitLockArraysEXT (GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLockArraysEXT = extproc; + + glLockArraysEXT(first, count); +} + +static void APIENTRY InitUnlockArraysEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnlockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnlockArraysEXT = extproc; + + glUnlockArraysEXT(); +} + +static void APIENTRY InitCullParameterdvEXT (GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterdvEXT = extproc; + + glCullParameterdvEXT(pname, params); +} + +static void APIENTRY InitCullParameterfvEXT (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterfvEXT = extproc; + + glCullParameterfvEXT(pname, params); +} + +static void APIENTRY InitFragmentColorMaterialSGIX (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentColorMaterialSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentColorMaterialSGIX = extproc; + + glFragmentColorMaterialSGIX(face, mode); +} + +static void APIENTRY InitFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfSGIX = extproc; + + glFragmentLightfSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfvSGIX = extproc; + + glFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightiSGIX (GLenum light, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightiSGIX = extproc; + + glFragmentLightiSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightivSGIX = extproc; + + glFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightModelfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfSGIX = extproc; + + glFragmentLightModelfSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfvSGIX = extproc; + + glFragmentLightModelfvSGIX(pname, params); +} + +static void APIENTRY InitFragmentLightModeliSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModeliSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModeliSGIX = extproc; + + glFragmentLightModeliSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelivSGIX = extproc; + + glFragmentLightModelivSGIX(pname, params); +} + +static void APIENTRY InitFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfSGIX = extproc; + + glFragmentMaterialfSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfvSGIX = extproc; + + glFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialiSGIX = extproc; + + glFragmentMaterialiSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialivSGIX = extproc; + + glFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightfvSGIX = extproc; + + glGetFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightivSGIX = extproc; + + glGetFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialfvSGIX = extproc; + + glGetFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialivSGIX = extproc; + + glGetFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitLightEnviSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLightEnviSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLightEnviSGIX = extproc; + + glLightEnviSGIX(pname, param); +} + +static void APIENTRY InitDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementsEXT = extproc; + + glDrawRangeElementsEXT(mode, start, end, count, type, indices); +} + +static void APIENTRY InitApplyTextureEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glApplyTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glApplyTextureEXT = extproc; + + glApplyTextureEXT(mode); +} + +static void APIENTRY InitTextureLightEXT (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureLightEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureLightEXT = extproc; + + glTextureLightEXT(pname); +} + +static void APIENTRY InitTextureMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureMaterialEXT = extproc; + + glTextureMaterialEXT(face, mode); +} + +static void APIENTRY InitAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAsyncMarkerSGIX = extproc; + + glAsyncMarkerSGIX(marker); +} + +static GLint APIENTRY InitFinishAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glFinishAsyncSGIX = extproc; + + return glFinishAsyncSGIX(markerp); +} + +static GLint APIENTRY InitPollAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollAsyncSGIX = extproc; + + return glPollAsyncSGIX(markerp); +} + +static GLuint APIENTRY InitGenAsyncMarkersSGIX (GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenAsyncMarkersSGIX = extproc; + + return glGenAsyncMarkersSGIX(range); +} + +static void APIENTRY InitDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteAsyncMarkersSGIX = extproc; + + glDeleteAsyncMarkersSGIX(marker, range); +} + +static GLboolean APIENTRY InitIsAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsAsyncMarkerSGIX = extproc; + + return glIsAsyncMarkerSGIX(marker); +} + +static void APIENTRY InitVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointervINTEL = extproc; + + glVertexPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitNormalPointervINTEL (GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointervINTEL = extproc; + + glNormalPointervINTEL(type, pointer); +} + +static void APIENTRY InitColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointervINTEL = extproc; + + glColorPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointervINTEL = extproc; + + glTexCoordPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameteriEXT = extproc; + + glPixelTransformParameteriEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfEXT = extproc; + + glPixelTransformParameterfEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterivEXT = extproc; + + glPixelTransformParameterivEXT(target, pname, params); +} + +static void APIENTRY InitPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfvEXT = extproc; + + glPixelTransformParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bEXT = extproc; + + glSecondaryColor3bEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bvEXT = extproc; + + glSecondaryColor3bvEXT(v); +} + +static void APIENTRY InitSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dEXT = extproc; + + glSecondaryColor3dEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dvEXT = extproc; + + glSecondaryColor3dvEXT(v); +} + +static void APIENTRY InitSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fEXT = extproc; + + glSecondaryColor3fEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fvEXT = extproc; + + glSecondaryColor3fvEXT(v); +} + +static void APIENTRY InitSecondaryColor3iEXT (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iEXT = extproc; + + glSecondaryColor3iEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ivEXT = extproc; + + glSecondaryColor3ivEXT(v); +} + +static void APIENTRY InitSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sEXT = extproc; + + glSecondaryColor3sEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3svEXT = extproc; + + glSecondaryColor3svEXT(v); +} + +static void APIENTRY InitSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubEXT = extproc; + + glSecondaryColor3ubEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubvEXT (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubvEXT = extproc; + + glSecondaryColor3ubvEXT(v); +} + +static void APIENTRY InitSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiEXT = extproc; + + glSecondaryColor3uiEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uivEXT (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uivEXT = extproc; + + glSecondaryColor3uivEXT(v); +} + +static void APIENTRY InitSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usEXT = extproc; + + glSecondaryColor3usEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usvEXT (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usvEXT = extproc; + + glSecondaryColor3usvEXT(v); +} + +static void APIENTRY InitSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerEXT = extproc; + + glSecondaryColorPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitTextureNormalEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureNormalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureNormalEXT = extproc; + + glTextureNormalEXT(mode); +} + +static void APIENTRY InitMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArraysEXT = extproc; + + glMultiDrawArraysEXT(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementsEXT = extproc; + + glMultiDrawElementsEXT(mode, count, type, indices, primcount); +} + +static void APIENTRY InitFogCoordfEXT (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfEXT = extproc; + + glFogCoordfEXT(coord); +} + +static void APIENTRY InitFogCoordfvEXT (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfvEXT = extproc; + + glFogCoordfvEXT(coord); +} + +static void APIENTRY InitFogCoorddEXT (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddEXT = extproc; + + glFogCoorddEXT(coord); +} + +static void APIENTRY InitFogCoorddvEXT (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddvEXT = extproc; + + glFogCoorddvEXT(coord); +} + +static void APIENTRY InitFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerEXT = extproc; + + glFogCoordPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bEXT = extproc; + + glTangent3bEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bvEXT = extproc; + + glTangent3bvEXT(v); +} + +static void APIENTRY InitTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dEXT = extproc; + + glTangent3dEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dvEXT = extproc; + + glTangent3dvEXT(v); +} + +static void APIENTRY InitTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fEXT = extproc; + + glTangent3fEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fvEXT = extproc; + + glTangent3fvEXT(v); +} + +static void APIENTRY InitTangent3iEXT (GLint tx, GLint ty, GLint tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3iEXT = extproc; + + glTangent3iEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3ivEXT = extproc; + + glTangent3ivEXT(v); +} + +static void APIENTRY InitTangent3sEXT (GLshort tx, GLshort ty, GLshort tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3sEXT = extproc; + + glTangent3sEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3svEXT = extproc; + + glTangent3svEXT(v); +} + +static void APIENTRY InitBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bEXT = extproc; + + glBinormal3bEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bvEXT = extproc; + + glBinormal3bvEXT(v); +} + +static void APIENTRY InitBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dEXT = extproc; + + glBinormal3dEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dvEXT = extproc; + + glBinormal3dvEXT(v); +} + +static void APIENTRY InitBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fEXT = extproc; + + glBinormal3fEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fvEXT = extproc; + + glBinormal3fvEXT(v); +} + +static void APIENTRY InitBinormal3iEXT (GLint bx, GLint by, GLint bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3iEXT = extproc; + + glBinormal3iEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3ivEXT = extproc; + + glBinormal3ivEXT(v); +} + +static void APIENTRY InitBinormal3sEXT (GLshort bx, GLshort by, GLshort bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3sEXT = extproc; + + glBinormal3sEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3svEXT = extproc; + + glBinormal3svEXT(v); +} + +static void APIENTRY InitTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangentPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangentPointerEXT = extproc; + + glTangentPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormalPointerEXT = extproc; + + glBinormalPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitFinishTextureSUNX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishTextureSUNX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishTextureSUNX = extproc; + + glFinishTextureSUNX(); +} + +static void APIENTRY InitGlobalAlphaFactorbSUN (GLbyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorbSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorbSUN = extproc; + + glGlobalAlphaFactorbSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorsSUN (GLshort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorsSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorsSUN = extproc; + + glGlobalAlphaFactorsSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoriSUN (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoriSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoriSUN = extproc; + + glGlobalAlphaFactoriSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorfSUN (GLfloat factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorfSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorfSUN = extproc; + + glGlobalAlphaFactorfSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactordSUN (GLdouble factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactordSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactordSUN = extproc; + + glGlobalAlphaFactordSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorubSUN (GLubyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorubSUN = extproc; + + glGlobalAlphaFactorubSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorusSUN (GLushort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorusSUN = extproc; + + glGlobalAlphaFactorusSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoruiSUN (GLuint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoruiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoruiSUN = extproc; + + glGlobalAlphaFactoruiSUN(factor); +} + +static void APIENTRY InitReplacementCodeuiSUN (GLuint code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiSUN = extproc; + + glReplacementCodeuiSUN(code); +} + +static void APIENTRY InitReplacementCodeusSUN (GLushort code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusSUN = extproc; + + glReplacementCodeusSUN(code); +} + +static void APIENTRY InitReplacementCodeubSUN (GLubyte code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubSUN = extproc; + + glReplacementCodeubSUN(code); +} + +static void APIENTRY InitReplacementCodeuivSUN (const GLuint *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuivSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuivSUN = extproc; + + glReplacementCodeuivSUN(code); +} + +static void APIENTRY InitReplacementCodeusvSUN (const GLushort *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusvSUN = extproc; + + glReplacementCodeusvSUN(code); +} + +static void APIENTRY InitReplacementCodeubvSUN (const GLubyte *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubvSUN = extproc; + + glReplacementCodeubvSUN(code); +} + +static void APIENTRY InitReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodePointerSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodePointerSUN = extproc; + + glReplacementCodePointerSUN(type, stride, pointer); +} + +static void APIENTRY InitColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fSUN = extproc; + + glColor4ubVertex2fSUN(r, g, b, a, x, y); +} + +static void APIENTRY InitColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fvSUN = extproc; + + glColor4ubVertex2fvSUN(c, v); +} + +static void APIENTRY InitColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fSUN = extproc; + + glColor4ubVertex3fSUN(r, g, b, a, x, y, z); +} + +static void APIENTRY InitColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fvSUN = extproc; + + glColor4ubVertex3fvSUN(c, v); +} + +static void APIENTRY InitColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fSUN = extproc; + + glColor3fVertex3fSUN(r, g, b, x, y, z); +} + +static void APIENTRY InitColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fvSUN = extproc; + + glColor3fVertex3fvSUN(c, v); +} + +static void APIENTRY InitNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fSUN = extproc; + + glNormal3fVertex3fSUN(nx, ny, nz, x, y, z); +} + +static void APIENTRY InitNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fvSUN = extproc; + + glNormal3fVertex3fvSUN(n, v); +} + +static void APIENTRY InitColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fSUN = extproc; + + glColor4fNormal3fVertex3fSUN(r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fvSUN = extproc; + + glColor4fNormal3fVertex3fvSUN(c, n, v); +} + +static void APIENTRY InitTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fSUN = extproc; + + glTexCoord2fVertex3fSUN(s, t, x, y, z); +} + +static void APIENTRY InitTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fvSUN = extproc; + + glTexCoord2fVertex3fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fSUN = extproc; + + glTexCoord4fVertex4fSUN(s, t, p, q, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fvSUN = extproc; + + glTexCoord4fVertex4fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fSUN = extproc; + + glTexCoord2fColor4ubVertex3fSUN(s, t, r, g, b, a, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fvSUN = extproc; + + glTexCoord2fColor4ubVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fSUN = extproc; + + glTexCoord2fColor3fVertex3fSUN(s, t, r, g, b, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fvSUN = extproc; + + glTexCoord2fColor3fVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fSUN = extproc; + + glTexCoord2fNormal3fVertex3fSUN(s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fNormal3fVertex3fvSUN(tc, n, v); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fSUN(s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fvSUN(tc, c, n, v); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fSUN(s, t, p, q, r, g, b, a, nx, ny, nz, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fvSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fvSUN(tc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fSUN = extproc; + + glReplacementCodeuiVertex3fSUN(rc, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fvSUN = extproc; + + glReplacementCodeuiVertex3fvSUN(rc, v); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fSUN(rc, r, g, b, a, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fvSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fSUN = extproc; + + glReplacementCodeuiColor3fVertex3fSUN(rc, r, g, b, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor3fVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fSUN(rc, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fvSUN(rc, n, v); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fSUN(rc, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN(rc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fSUN(rc, s, t, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fvSUN(rc, tc, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN(rc, s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN(rc, tc, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN(rc, s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN(rc, tc, c, n, v); +} + +static void APIENTRY InitBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateEXT = extproc; + + glBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateINGR"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateINGR = extproc; + + glBlendFuncSeparateINGR(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitVertexWeightfEXT (GLfloat weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfEXT = extproc; + + glVertexWeightfEXT(weight); +} + +static void APIENTRY InitVertexWeightfvEXT (const GLfloat *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfvEXT = extproc; + + glVertexWeightfvEXT(weight); +} + +static void APIENTRY InitVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightPointerEXT = extproc; + + glVertexWeightPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeNV = extproc; + + glFlushVertexArrayRangeNV(); +} + +static void APIENTRY InitVertexArrayRangeNV (GLsizei length, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeNV = extproc; + + glVertexArrayRangeNV(length, pointer); +} + +static void APIENTRY InitCombinerParameterfvNV (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfvNV = extproc; + + glCombinerParameterfvNV(pname, params); +} + +static void APIENTRY InitCombinerParameterfNV (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfNV = extproc; + + glCombinerParameterfNV(pname, param); +} + +static void APIENTRY InitCombinerParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterivNV = extproc; + + glCombinerParameterivNV(pname, params); +} + +static void APIENTRY InitCombinerParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameteriNV = extproc; + + glCombinerParameteriNV(pname, param); +} + +static void APIENTRY InitCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerInputNV = extproc; + + glCombinerInputNV(stage, portion, variable, input, mapping, componentUsage); +} + +static void APIENTRY InitCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerOutputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerOutputNV = extproc; + + glCombinerOutputNV(stage, portion, abOutput, cdOutput, sumOutput, scale, bias, abDotProduct, cdDotProduct, muxSum); +} + +static void APIENTRY InitFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinalCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinalCombinerInputNV = extproc; + + glFinalCombinerInputNV(variable, input, mapping, componentUsage); +} + +static void APIENTRY InitGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterfvNV = extproc; + + glGetCombinerInputParameterfvNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterivNV = extproc; + + glGetCombinerInputParameterivNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterfvNV = extproc; + + glGetCombinerOutputParameterfvNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterivNV = extproc; + + glGetCombinerOutputParameterivNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterfvNV = extproc; + + glGetFinalCombinerInputParameterfvNV(variable, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterivNV = extproc; + + glGetFinalCombinerInputParameterivNV(variable, pname, params); +} + +static void APIENTRY InitResizeBuffersMESA (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResizeBuffersMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResizeBuffersMESA = extproc; + + glResizeBuffersMESA(); +} + +static void APIENTRY InitWindowPos2dMESA (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dMESA = extproc; + + glWindowPos2dMESA(x, y); +} + +static void APIENTRY InitWindowPos2dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvMESA = extproc; + + glWindowPos2dvMESA(v); +} + +static void APIENTRY InitWindowPos2fMESA (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fMESA = extproc; + + glWindowPos2fMESA(x, y); +} + +static void APIENTRY InitWindowPos2fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvMESA = extproc; + + glWindowPos2fvMESA(v); +} + +static void APIENTRY InitWindowPos2iMESA (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iMESA = extproc; + + glWindowPos2iMESA(x, y); +} + +static void APIENTRY InitWindowPos2ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivMESA = extproc; + + glWindowPos2ivMESA(v); +} + +static void APIENTRY InitWindowPos2sMESA (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sMESA = extproc; + + glWindowPos2sMESA(x, y); +} + +static void APIENTRY InitWindowPos2svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svMESA = extproc; + + glWindowPos2svMESA(v); +} + +static void APIENTRY InitWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dMESA = extproc; + + glWindowPos3dMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvMESA = extproc; + + glWindowPos3dvMESA(v); +} + +static void APIENTRY InitWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fMESA = extproc; + + glWindowPos3fMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvMESA = extproc; + + glWindowPos3fvMESA(v); +} + +static void APIENTRY InitWindowPos3iMESA (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iMESA = extproc; + + glWindowPos3iMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivMESA = extproc; + + glWindowPos3ivMESA(v); +} + +static void APIENTRY InitWindowPos3sMESA (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sMESA = extproc; + + glWindowPos3sMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svMESA = extproc; + + glWindowPos3svMESA(v); +} + +static void APIENTRY InitWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dMESA = extproc; + + glWindowPos4dMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dvMESA = extproc; + + glWindowPos4dvMESA(v); +} + +static void APIENTRY InitWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fMESA = extproc; + + glWindowPos4fMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fvMESA = extproc; + + glWindowPos4fvMESA(v); +} + +static void APIENTRY InitWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4iMESA = extproc; + + glWindowPos4iMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4ivMESA = extproc; + + glWindowPos4ivMESA(v); +} + +static void APIENTRY InitWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4sMESA = extproc; + + glWindowPos4sMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4svMESA = extproc; + + glWindowPos4svMESA(v); +} + +static void APIENTRY InitMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawArraysIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawArraysIBM = extproc; + + glMultiModeDrawArraysIBM(mode, first, count, primcount, modestride); +} + +static void APIENTRY InitMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawElementsIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawElementsIBM = extproc; + + glMultiModeDrawElementsIBM(mode, count, type, indices, primcount, modestride); +} + +static void APIENTRY InitColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerListIBM = extproc; + + glColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerListIBM = extproc; + + glSecondaryColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerListIBM = extproc; + + glEdgeFlagPointerListIBM(stride, pointer, ptrstride); +} + +static void APIENTRY InitFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerListIBM = extproc; + + glFogCoordPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerListIBM = extproc; + + glIndexPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerListIBM = extproc; + + glNormalPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerListIBM = extproc; + + glTexCoordPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerListIBM = extproc; + + glVertexPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTbufferMask3DFX (GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTbufferMask3DFX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTbufferMask3DFX = extproc; + + glTbufferMask3DFX(mask); +} + +static void APIENTRY InitSampleMaskEXT (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskEXT = extproc; + + glSampleMaskEXT(value, invert); +} + +static void APIENTRY InitSamplePatternEXT (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternEXT = extproc; + + glSamplePatternEXT(pattern); +} + +static void APIENTRY InitTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureColorMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureColorMaskSGIS = extproc; + + glTextureColorMaskSGIS(red, green, blue, alpha); +} + +static void APIENTRY InitIglooInterfaceSGIX (GLenum pname, const GLvoid *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIglooInterfaceSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIglooInterfaceSGIX = extproc; + + glIglooInterfaceSGIX(pname, params); +} + +static void APIENTRY InitDeleteFencesNV (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesNV = extproc; + + glDeleteFencesNV(n, fences); +} + +static void APIENTRY InitGenFencesNV (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesNV = extproc; + + glGenFencesNV(n, fences); +} + +static GLboolean APIENTRY InitIsFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceNV = extproc; + + return glIsFenceNV(fence); +} + +static GLboolean APIENTRY InitTestFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceNV = extproc; + + return glTestFenceNV(fence); +} + +static void APIENTRY InitGetFenceivNV (GLuint fence, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFenceivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFenceivNV = extproc; + + glGetFenceivNV(fence, pname, params); +} + +static void APIENTRY InitFinishFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceNV = extproc; + + glFinishFenceNV(fence); +} + +static void APIENTRY InitSetFenceNV (GLuint fence, GLenum condition) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceNV = extproc; + + glSetFenceNV(fence, condition); +} + +static void APIENTRY InitMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapControlPointsNV = extproc; + + glMapControlPointsNV(target, index, type, ustride, vstride, uorder, vorder, packed, points); +} + +static void APIENTRY InitMapParameterivNV (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterivNV = extproc; + + glMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterfvNV = extproc; + + glMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapControlPointsNV = extproc; + + glGetMapControlPointsNV(target, index, type, ustride, vstride, packed, points); +} + +static void APIENTRY InitGetMapParameterivNV (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterivNV = extproc; + + glGetMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterfvNV = extproc; + + glGetMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterivNV = extproc; + + glGetMapAttribParameterivNV(target, index, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterfvNV = extproc; + + glGetMapAttribParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitEvalMapsNV (GLenum target, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEvalMapsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEvalMapsNV = extproc; + + glEvalMapsNV(target, mode); +} + +static void APIENTRY InitCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerStageParameterfvNV = extproc; + + glCombinerStageParameterfvNV(stage, pname, params); +} + +static void APIENTRY InitGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerStageParameterfvNV = extproc; + + glGetCombinerStageParameterfvNV(stage, pname, params); +} + +static GLboolean APIENTRY InitAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreProgramsResidentNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreProgramsResidentNV = extproc; + + return glAreProgramsResidentNV(n, programs, residences); +} + +static void APIENTRY InitBindProgramNV (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramNV = extproc; + + glBindProgramNV(target, id); +} + +static void APIENTRY InitDeleteProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsNV = extproc; + + glDeleteProgramsNV(n, programs); +} + +static void APIENTRY InitExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExecuteProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExecuteProgramNV = extproc; + + glExecuteProgramNV(target, id, params); +} + +static void APIENTRY InitGenProgramsNV (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsNV = extproc; + + glGenProgramsNV(n, programs); +} + +static void APIENTRY InitGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterdvNV = extproc; + + glGetProgramParameterdvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterfvNV = extproc; + + glGetProgramParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivNV = extproc; + + glGetProgramivNV(id, pname, params); +} + +static void APIENTRY InitGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringNV = extproc; + + glGetProgramStringNV(id, pname, program); +} + +static void APIENTRY InitGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTrackMatrixivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTrackMatrixivNV = extproc; + + glGetTrackMatrixivNV(target, address, pname, params); +} + +static void APIENTRY InitGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvNV = extproc; + + glGetVertexAttribdvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvNV = extproc; + + glGetVertexAttribfvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivNV = extproc; + + glGetVertexAttribivNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervNV = extproc; + + glGetVertexAttribPointervNV(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramNV = extproc; + + return glIsProgramNV(id); +} + +static void APIENTRY InitLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadProgramNV = extproc; + + glLoadProgramNV(target, id, len, program); +} + +static void APIENTRY InitProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dNV = extproc; + + glProgramParameter4dNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dvNV = extproc; + + glProgramParameter4dvNV(target, index, v); +} + +static void APIENTRY InitProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fNV = extproc; + + glProgramParameter4fNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fvNV = extproc; + + glProgramParameter4fvNV(target, index, v); +} + +static void APIENTRY InitProgramParameters4dvNV (GLenum target, GLuint index, GLuint count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4dvNV = extproc; + + glProgramParameters4dvNV(target, index, count, v); +} + +static void APIENTRY InitProgramParameters4fvNV (GLenum target, GLuint index, GLuint count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4fvNV = extproc; + + glProgramParameters4fvNV(target, index, count, v); +} + +static void APIENTRY InitRequestResidentProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glRequestResidentProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glRequestResidentProgramsNV = extproc; + + glRequestResidentProgramsNV(n, programs); +} + +static void APIENTRY InitTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTrackMatrixNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTrackMatrixNV = extproc; + + glTrackMatrixNV(target, address, matrix, transform); +} + +static void APIENTRY InitVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerNV = extproc; + + glVertexAttribPointerNV(index, fsize, type, stride, pointer); +} + +static void APIENTRY InitVertexAttrib1dNV (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dNV = extproc; + + glVertexAttrib1dNV(index, x); +} + +static void APIENTRY InitVertexAttrib1dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvNV = extproc; + + glVertexAttrib1dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1fNV (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fNV = extproc; + + glVertexAttrib1fNV(index, x); +} + +static void APIENTRY InitVertexAttrib1fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvNV = extproc; + + glVertexAttrib1fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1sNV (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sNV = extproc; + + glVertexAttrib1sNV(index, x); +} + +static void APIENTRY InitVertexAttrib1svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svNV = extproc; + + glVertexAttrib1svNV(index, v); +} + +static void APIENTRY InitVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dNV = extproc; + + glVertexAttrib2dNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvNV = extproc; + + glVertexAttrib2dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fNV = extproc; + + glVertexAttrib2fNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvNV = extproc; + + glVertexAttrib2fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2sNV (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sNV = extproc; + + glVertexAttrib2sNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svNV = extproc; + + glVertexAttrib2svNV(index, v); +} + +static void APIENTRY InitVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dNV = extproc; + + glVertexAttrib3dNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvNV = extproc; + + glVertexAttrib3dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fNV = extproc; + + glVertexAttrib3fNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvNV = extproc; + + glVertexAttrib3fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sNV = extproc; + + glVertexAttrib3sNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svNV = extproc; + + glVertexAttrib3svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dNV = extproc; + + glVertexAttrib4dNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvNV = extproc; + + glVertexAttrib4dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fNV = extproc; + + glVertexAttrib4fNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvNV = extproc; + + glVertexAttrib4fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sNV = extproc; + + glVertexAttrib4sNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svNV = extproc; + + glVertexAttrib4svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubNV = extproc; + + glVertexAttrib4ubNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4ubvNV (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvNV = extproc; + + glVertexAttrib4ubvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1dvNV = extproc; + + glVertexAttribs1dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1fvNV = extproc; + + glVertexAttribs1fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1svNV = extproc; + + glVertexAttribs1svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2dvNV = extproc; + + glVertexAttribs2dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2fvNV = extproc; + + glVertexAttribs2fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2svNV = extproc; + + glVertexAttribs2svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3dvNV = extproc; + + glVertexAttribs3dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3fvNV = extproc; + + glVertexAttribs3fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3svNV = extproc; + + glVertexAttribs3svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4dvNV = extproc; + + glVertexAttribs4dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4fvNV = extproc; + + glVertexAttribs4fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4svNV = extproc; + + glVertexAttribs4svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4ubvNV = extproc; + + glVertexAttribs4ubvNV(index, count, v); +} + +static void APIENTRY InitTexBumpParameterivATI (GLenum pname, const GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterivATI = extproc; + + glTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitTexBumpParameterfvATI (GLenum pname, const GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterfvATI = extproc; + + glTexBumpParameterfvATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterivATI (GLenum pname, GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterivATI = extproc; + + glGetTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterfvATI (GLenum pname, GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterfvATI = extproc; + + glGetTexBumpParameterfvATI(pname, param); +} + +static GLuint APIENTRY InitGenFragmentShadersATI (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFragmentShadersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenFragmentShadersATI = extproc; + + return glGenFragmentShadersATI(range); +} + +static void APIENTRY InitBindFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindFragmentShaderATI = extproc; + + glBindFragmentShaderATI(id); +} + +static void APIENTRY InitDeleteFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFragmentShaderATI = extproc; + + glDeleteFragmentShaderATI(id); +} + +static void APIENTRY InitBeginFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginFragmentShaderATI = extproc; + + glBeginFragmentShaderATI(); +} + +static void APIENTRY InitEndFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndFragmentShaderATI = extproc; + + glEndFragmentShaderATI(); +} + +static void APIENTRY InitPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPassTexCoordATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPassTexCoordATI = extproc; + + glPassTexCoordATI(dst, coord, swizzle); +} + +static void APIENTRY InitSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMapATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMapATI = extproc; + + glSampleMapATI(dst, interp, swizzle); +} + +static void APIENTRY InitColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp1ATI = extproc; + + glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp2ATI = extproc; + + glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp3ATI = extproc; + + glColorFragmentOp3ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp1ATI = extproc; + + glAlphaFragmentOp1ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp2ATI = extproc; + + glAlphaFragmentOp2ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp3ATI = extproc; + + glAlphaFragmentOp3ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFragmentShaderConstantATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFragmentShaderConstantATI = extproc; + + glSetFragmentShaderConstantATI(dst, value); +} + +static void APIENTRY InitPNTrianglesiATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesiATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesiATI = extproc; + + glPNTrianglesiATI(pname, param); +} + +static void APIENTRY InitPNTrianglesfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesfATI = extproc; + + glPNTrianglesfATI(pname, param); +} + +static GLuint APIENTRY InitNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNewObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glNewObjectBufferATI = extproc; + + return glNewObjectBufferATI(size, pointer, usage); +} + +static GLboolean APIENTRY InitIsObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsObjectBufferATI = extproc; + + return glIsObjectBufferATI(buffer); +} + +static void APIENTRY InitUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUpdateObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUpdateObjectBufferATI = extproc; + + glUpdateObjectBufferATI(buffer, offset, size, pointer, preserve); +} + +static void APIENTRY InitGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferfvATI = extproc; + + glGetObjectBufferfvATI(buffer, pname, params); +} + +static void APIENTRY InitGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferivATI = extproc; + + glGetObjectBufferivATI(buffer, pname, params); +} + +static void APIENTRY InitFreeObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFreeObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFreeObjectBufferATI = extproc; + + glFreeObjectBufferATI(buffer); +} + +static void APIENTRY InitArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayObjectATI = extproc; + + glArrayObjectATI(array, size, type, stride, buffer, offset); +} + +static void APIENTRY InitGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectfvATI = extproc; + + glGetArrayObjectfvATI(array, pname, params); +} + +static void APIENTRY InitGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectivATI = extproc; + + glGetArrayObjectivATI(array, pname, params); +} + +static void APIENTRY InitVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantArrayObjectATI = extproc; + + glVariantArrayObjectATI(id, type, stride, buffer, offset); +} + +static void APIENTRY InitGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectfvATI = extproc; + + glGetVariantArrayObjectfvATI(id, pname, params); +} + +static void APIENTRY InitGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectivATI = extproc; + + glGetVariantArrayObjectivATI(id, pname, params); +} + +static void APIENTRY InitBeginVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginVertexShaderEXT = extproc; + + glBeginVertexShaderEXT(); +} + +static void APIENTRY InitEndVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndVertexShaderEXT = extproc; + + glEndVertexShaderEXT(); +} + +static void APIENTRY InitBindVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexShaderEXT = extproc; + + glBindVertexShaderEXT(id); +} + +static GLuint APIENTRY InitGenVertexShadersEXT (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexShadersEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenVertexShadersEXT = extproc; + + return glGenVertexShadersEXT(range); +} + +static void APIENTRY InitDeleteVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexShaderEXT = extproc; + + glDeleteVertexShaderEXT(id); +} + +static void APIENTRY InitShaderOp1EXT (GLenum op, GLuint res, GLuint arg1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp1EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp1EXT = extproc; + + glShaderOp1EXT(op, res, arg1); +} + +static void APIENTRY InitShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp2EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp2EXT = extproc; + + glShaderOp2EXT(op, res, arg1, arg2); +} + +static void APIENTRY InitShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp3EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp3EXT = extproc; + + glShaderOp3EXT(op, res, arg1, arg2, arg3); +} + +static void APIENTRY InitSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSwizzleEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSwizzleEXT = extproc; + + glSwizzleEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWriteMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWriteMaskEXT = extproc; + + glWriteMaskEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitInsertComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInsertComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInsertComponentEXT = extproc; + + glInsertComponentEXT(res, src, num); +} + +static void APIENTRY InitExtractComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExtractComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExtractComponentEXT = extproc; + + glExtractComponentEXT(res, src, num); +} + +static GLuint APIENTRY InitGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenSymbolsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenSymbolsEXT = extproc; + + return glGenSymbolsEXT(datatype, storagetype, range, components); +} + +static void APIENTRY InitSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetInvariantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetInvariantEXT = extproc; + + glSetInvariantEXT(id, type, addr); +} + +static void APIENTRY InitSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetLocalConstantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetLocalConstantEXT = extproc; + + glSetLocalConstantEXT(id, type, addr); +} + +static void APIENTRY InitVariantbvEXT (GLuint id, const GLbyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantbvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantbvEXT = extproc; + + glVariantbvEXT(id, addr); +} + +static void APIENTRY InitVariantsvEXT (GLuint id, const GLshort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantsvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantsvEXT = extproc; + + glVariantsvEXT(id, addr); +} + +static void APIENTRY InitVariantivEXT (GLuint id, const GLint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantivEXT = extproc; + + glVariantivEXT(id, addr); +} + +static void APIENTRY InitVariantfvEXT (GLuint id, const GLfloat *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantfvEXT = extproc; + + glVariantfvEXT(id, addr); +} + +static void APIENTRY InitVariantdvEXT (GLuint id, const GLdouble *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantdvEXT = extproc; + + glVariantdvEXT(id, addr); +} + +static void APIENTRY InitVariantubvEXT (GLuint id, const GLubyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantubvEXT = extproc; + + glVariantubvEXT(id, addr); +} + +static void APIENTRY InitVariantusvEXT (GLuint id, const GLushort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantusvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantusvEXT = extproc; + + glVariantusvEXT(id, addr); +} + +static void APIENTRY InitVariantuivEXT (GLuint id, const GLuint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantuivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantuivEXT = extproc; + + glVariantuivEXT(id, addr); +} + +static void APIENTRY InitVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantPointerEXT = extproc; + + glVariantPointerEXT(id, type, stride, addr); +} + +static void APIENTRY InitEnableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVariantClientStateEXT = extproc; + + glEnableVariantClientStateEXT(id); +} + +static void APIENTRY InitDisableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVariantClientStateEXT = extproc; + + glDisableVariantClientStateEXT(id); +} + +static GLuint APIENTRY InitBindLightParameterEXT (GLenum light, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindLightParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindLightParameterEXT = extproc; + + return glBindLightParameterEXT(light, value); +} + +static GLuint APIENTRY InitBindMaterialParameterEXT (GLenum face, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindMaterialParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindMaterialParameterEXT = extproc; + + return glBindMaterialParameterEXT(face, value); +} + +static GLuint APIENTRY InitBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTexGenParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTexGenParameterEXT = extproc; + + return glBindTexGenParameterEXT(unit, coord, value); +} + +static GLuint APIENTRY InitBindTextureUnitParameterEXT (GLenum unit, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureUnitParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTextureUnitParameterEXT = extproc; + + return glBindTextureUnitParameterEXT(unit, value); +} + +static GLuint APIENTRY InitBindParameterEXT (GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindParameterEXT = extproc; + + return glBindParameterEXT(value); +} + +static GLboolean APIENTRY InitIsVariantEnabledEXT (GLuint id, GLenum cap) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVariantEnabledEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVariantEnabledEXT = extproc; + + return glIsVariantEnabledEXT(id, cap); +} + +static void APIENTRY InitGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantBooleanvEXT = extproc; + + glGetVariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantIntegervEXT = extproc; + + glGetVariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantFloatvEXT = extproc; + + glGetVariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantPointervEXT = extproc; + + glGetVariantPointervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantBooleanvEXT = extproc; + + glGetInvariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantIntegervEXT = extproc; + + glGetInvariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantFloatvEXT = extproc; + + glGetInvariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantBooleanvEXT = extproc; + + glGetLocalConstantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantIntegervEXT = extproc; + + glGetLocalConstantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantFloatvEXT = extproc; + + glGetLocalConstantFloatvEXT(id, value, data); +} + +static void APIENTRY InitVertexStream1sATI (GLenum stream, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1sATI = extproc; + + glVertexStream1sATI(stream, x); +} + +static void APIENTRY InitVertexStream1svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1svATI = extproc; + + glVertexStream1svATI(stream, coords); +} + +static void APIENTRY InitVertexStream1iATI (GLenum stream, GLint x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1iATI = extproc; + + glVertexStream1iATI(stream, x); +} + +static void APIENTRY InitVertexStream1ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1ivATI = extproc; + + glVertexStream1ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream1fATI (GLenum stream, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fATI = extproc; + + glVertexStream1fATI(stream, x); +} + +static void APIENTRY InitVertexStream1fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fvATI = extproc; + + glVertexStream1fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream1dATI (GLenum stream, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dATI = extproc; + + glVertexStream1dATI(stream, x); +} + +static void APIENTRY InitVertexStream1dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dvATI = extproc; + + glVertexStream1dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2sATI (GLenum stream, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2sATI = extproc; + + glVertexStream2sATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2svATI = extproc; + + glVertexStream2svATI(stream, coords); +} + +static void APIENTRY InitVertexStream2iATI (GLenum stream, GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2iATI = extproc; + + glVertexStream2iATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2ivATI = extproc; + + glVertexStream2ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fATI = extproc; + + glVertexStream2fATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fvATI = extproc; + + glVertexStream2fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dATI = extproc; + + glVertexStream2dATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dvATI = extproc; + + glVertexStream2dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3sATI = extproc; + + glVertexStream3sATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3svATI = extproc; + + glVertexStream3svATI(stream, coords); +} + +static void APIENTRY InitVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3iATI = extproc; + + glVertexStream3iATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3ivATI = extproc; + + glVertexStream3ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fATI = extproc; + + glVertexStream3fATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fvATI = extproc; + + glVertexStream3fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dATI = extproc; + + glVertexStream3dATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dvATI = extproc; + + glVertexStream3dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4sATI = extproc; + + glVertexStream4sATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4svATI = extproc; + + glVertexStream4svATI(stream, coords); +} + +static void APIENTRY InitVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4iATI = extproc; + + glVertexStream4iATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4ivATI = extproc; + + glVertexStream4ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fATI = extproc; + + glVertexStream4fATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fvATI = extproc; + + glVertexStream4fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dATI = extproc; + + glVertexStream4dATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dvATI = extproc; + + glVertexStream4dvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bATI = extproc; + + glNormalStream3bATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3bvATI (GLenum stream, const GLbyte *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bvATI = extproc; + + glNormalStream3bvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3sATI = extproc; + + glNormalStream3sATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3svATI = extproc; + + glNormalStream3svATI(stream, coords); +} + +static void APIENTRY InitNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3iATI = extproc; + + glNormalStream3iATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3ivATI = extproc; + + glNormalStream3ivATI(stream, coords); +} + +static void APIENTRY InitNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fATI = extproc; + + glNormalStream3fATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fvATI = extproc; + + glNormalStream3fvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dATI = extproc; + + glNormalStream3dATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dvATI = extproc; + + glNormalStream3dvATI(stream, coords); +} + +static void APIENTRY InitClientActiveVertexStreamATI (GLenum stream) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveVertexStreamATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveVertexStreamATI = extproc; + + glClientActiveVertexStreamATI(stream); +} + +static void APIENTRY InitVertexBlendEnviATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnviATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnviATI = extproc; + + glVertexBlendEnviATI(pname, param); +} + +static void APIENTRY InitVertexBlendEnvfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnvfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnvfATI = extproc; + + glVertexBlendEnvfATI(pname, param); +} + +static void APIENTRY InitElementPointerATI (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerATI = extproc; + + glElementPointerATI(type, pointer); +} + +static void APIENTRY InitDrawElementArrayATI (GLenum mode, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayATI = extproc; + + glDrawElementArrayATI(mode, count); +} + +static void APIENTRY InitDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayATI = extproc; + + glDrawRangeElementArrayATI(mode, start, end, count); +} + +static void APIENTRY InitDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawMeshArraysSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawMeshArraysSUN = extproc; + + glDrawMeshArraysSUN(mode, first, count, width); +} + +static void APIENTRY InitGenOcclusionQueriesNV (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenOcclusionQueriesNV = extproc; + + glGenOcclusionQueriesNV(n, ids); +} + +static void APIENTRY InitDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteOcclusionQueriesNV = extproc; + + glDeleteOcclusionQueriesNV(n, ids); +} + +static GLboolean APIENTRY InitIsOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsOcclusionQueryNV = extproc; + + return glIsOcclusionQueryNV(id); +} + +static void APIENTRY InitBeginOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginOcclusionQueryNV = extproc; + + glBeginOcclusionQueryNV(id); +} + +static void APIENTRY InitEndOcclusionQueryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndOcclusionQueryNV = extproc; + + glEndOcclusionQueryNV(); +} + +static void APIENTRY InitGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryivNV = extproc; + + glGetOcclusionQueryivNV(id, pname, params); +} + +static void APIENTRY InitGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryuivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryuivNV = extproc; + + glGetOcclusionQueryuivNV(id, pname, params); +} + +static void APIENTRY InitPointParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriNV = extproc; + + glPointParameteriNV(pname, param); +} + +static void APIENTRY InitPointParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterivNV = extproc; + + glPointParameterivNV(pname, params); +} + +static void APIENTRY InitActiveStencilFaceEXT (GLenum face) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveStencilFaceEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveStencilFaceEXT = extproc; + + glActiveStencilFaceEXT(face); +} + +static void APIENTRY InitElementPointerAPPLE (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerAPPLE = extproc; + + glElementPointerAPPLE(type, pointer); +} + +static void APIENTRY InitDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayAPPLE = extproc; + + glDrawElementArrayAPPLE(mode, first, count); +} + +static void APIENTRY InitDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayAPPLE = extproc; + + glDrawRangeElementArrayAPPLE(mode, start, end, first, count); +} + +static void APIENTRY InitMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementArrayAPPLE = extproc; + + glMultiDrawElementArrayAPPLE(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawRangeElementArrayAPPLE = extproc; + + glMultiDrawRangeElementArrayAPPLE(mode, start, end, first, count, primcount); +} + +static void APIENTRY InitGenFencesAPPLE (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesAPPLE = extproc; + + glGenFencesAPPLE(n, fences); +} + +static void APIENTRY InitDeleteFencesAPPLE (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesAPPLE = extproc; + + glDeleteFencesAPPLE(n, fences); +} + +static void APIENTRY InitSetFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceAPPLE = extproc; + + glSetFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitIsFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceAPPLE = extproc; + + return glIsFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceAPPLE = extproc; + + return glTestFenceAPPLE(fence); +} + +static void APIENTRY InitFinishFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceAPPLE = extproc; + + glFinishFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestObjectAPPLE (GLenum object, GLuint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestObjectAPPLE = extproc; + + return glTestObjectAPPLE(object, name); +} + +static void APIENTRY InitFinishObjectAPPLE (GLenum object, GLint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishObjectAPPLE = extproc; + + glFinishObjectAPPLE(object, name); +} + +static void APIENTRY InitBindVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexArrayAPPLE = extproc; + + glBindVertexArrayAPPLE(array); +} + +static void APIENTRY InitDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexArraysAPPLE = extproc; + + glDeleteVertexArraysAPPLE(n, arrays); +} + +static void APIENTRY InitGenVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenVertexArraysAPPLE = extproc; + + glGenVertexArraysAPPLE(n, arrays); +} + +static GLboolean APIENTRY InitIsVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVertexArrayAPPLE = extproc; + + return glIsVertexArrayAPPLE(array); +} + +static void APIENTRY InitVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeAPPLE = extproc; + + glVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeAPPLE = extproc; + + glFlushVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitVertexArrayParameteriAPPLE (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayParameteriAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayParameteriAPPLE = extproc; + + glVertexArrayParameteriAPPLE(pname, param); +} + +static void APIENTRY InitDrawBuffersATI (GLsizei n, const GLenum *bufs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawBuffersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawBuffersATI = extproc; + + glDrawBuffersATI(n, bufs); +} + +static void APIENTRY InitProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fNV = extproc; + + glProgramNamedParameter4fNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dNV = extproc; + + glProgramNamedParameter4dNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fvNV = extproc; + + glProgramNamedParameter4fvNV(id, len, name, v); +} + +static void APIENTRY InitProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dvNV = extproc; + + glProgramNamedParameter4dvNV(id, len, name, v); +} + +static void APIENTRY InitGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterfvNV = extproc; + + glGetProgramNamedParameterfvNV(id, len, name, params); +} + +static void APIENTRY InitGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterdvNV = extproc; + + glGetProgramNamedParameterdvNV(id, len, name, params); +} + +static void APIENTRY InitVertex2hNV (GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hNV = extproc; + + glVertex2hNV(x, y); +} + +static void APIENTRY InitVertex2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hvNV = extproc; + + glVertex2hvNV(v); +} + +static void APIENTRY InitVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hNV = extproc; + + glVertex3hNV(x, y, z); +} + +static void APIENTRY InitVertex3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hvNV = extproc; + + glVertex3hvNV(v); +} + +static void APIENTRY InitVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hNV = extproc; + + glVertex4hNV(x, y, z, w); +} + +static void APIENTRY InitVertex4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hvNV = extproc; + + glVertex4hvNV(v); +} + +static void APIENTRY InitNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hNV = extproc; + + glNormal3hNV(nx, ny, nz); +} + +static void APIENTRY InitNormal3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hvNV = extproc; + + glNormal3hvNV(v); +} + +static void APIENTRY InitColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hNV = extproc; + + glColor3hNV(red, green, blue); +} + +static void APIENTRY InitColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hvNV = extproc; + + glColor3hvNV(v); +} + +static void APIENTRY InitColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hNV = extproc; + + glColor4hNV(red, green, blue, alpha); +} + +static void APIENTRY InitColor4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hvNV = extproc; + + glColor4hvNV(v); +} + +static void APIENTRY InitTexCoord1hNV (GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hNV = extproc; + + glTexCoord1hNV(s); +} + +static void APIENTRY InitTexCoord1hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hvNV = extproc; + + glTexCoord1hvNV(v); +} + +static void APIENTRY InitTexCoord2hNV (GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hNV = extproc; + + glTexCoord2hNV(s, t); +} + +static void APIENTRY InitTexCoord2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hvNV = extproc; + + glTexCoord2hvNV(v); +} + +static void APIENTRY InitTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hNV = extproc; + + glTexCoord3hNV(s, t, r); +} + +static void APIENTRY InitTexCoord3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hvNV = extproc; + + glTexCoord3hvNV(v); +} + +static void APIENTRY InitTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hNV = extproc; + + glTexCoord4hNV(s, t, r, q); +} + +static void APIENTRY InitTexCoord4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hvNV = extproc; + + glTexCoord4hvNV(v); +} + +static void APIENTRY InitMultiTexCoord1hNV (GLenum target, GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hNV = extproc; + + glMultiTexCoord1hNV(target, s); +} + +static void APIENTRY InitMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hvNV = extproc; + + glMultiTexCoord1hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hNV = extproc; + + glMultiTexCoord2hNV(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hvNV = extproc; + + glMultiTexCoord2hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hNV = extproc; + + glMultiTexCoord3hNV(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hvNV = extproc; + + glMultiTexCoord3hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hNV = extproc; + + glMultiTexCoord4hNV(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hvNV = extproc; + + glMultiTexCoord4hvNV(target, v); +} + +static void APIENTRY InitFogCoordhNV (GLhalfNV fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhNV = extproc; + + glFogCoordhNV(fog); +} + +static void APIENTRY InitFogCoordhvNV (const GLhalfNV *fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhvNV = extproc; + + glFogCoordhvNV(fog); +} + +static void APIENTRY InitSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hNV = extproc; + + glSecondaryColor3hNV(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hvNV = extproc; + + glSecondaryColor3hvNV(v); +} + +static void APIENTRY InitVertexWeighthNV (GLhalfNV weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthNV = extproc; + + glVertexWeighthNV(weight); +} + +static void APIENTRY InitVertexWeighthvNV (const GLhalfNV *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthvNV = extproc; + + glVertexWeighthvNV(weight); +} + +static void APIENTRY InitVertexAttrib1hNV (GLuint index, GLhalfNV x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hNV = extproc; + + glVertexAttrib1hNV(index, x); +} + +static void APIENTRY InitVertexAttrib1hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hvNV = extproc; + + glVertexAttrib1hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hNV = extproc; + + glVertexAttrib2hNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hvNV = extproc; + + glVertexAttrib2hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hNV = extproc; + + glVertexAttrib3hNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hvNV = extproc; + + glVertexAttrib3hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hNV = extproc; + + glVertexAttrib4hNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hvNV = extproc; + + glVertexAttrib4hvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1hvNV = extproc; + + glVertexAttribs1hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2hvNV = extproc; + + glVertexAttribs2hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3hvNV = extproc; + + glVertexAttribs3hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4hvNV = extproc; + + glVertexAttribs4hvNV(index, n, v); +} + +static void APIENTRY InitPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelDataRangeNV = extproc; + + glPixelDataRangeNV(target, length, pointer); +} + +static void APIENTRY InitFlushPixelDataRangeNV (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushPixelDataRangeNV = extproc; + + glFlushPixelDataRangeNV(target); +} + +static void APIENTRY InitPrimitiveRestartNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartNV = extproc; + + glPrimitiveRestartNV(); +} + +static void APIENTRY InitPrimitiveRestartIndexNV (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartIndexNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartIndexNV = extproc; + + glPrimitiveRestartIndexNV(index); +} + +static GLvoid* APIENTRY InitMapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapObjectBufferATI = extproc; + + return glMapObjectBufferATI(buffer); +} + +static void APIENTRY InitUnmapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnmapObjectBufferATI = extproc; + + glUnmapObjectBufferATI(buffer); +} + +static void APIENTRY InitStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilOpSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilOpSeparateATI = extproc; + + glStencilOpSeparateATI(face, sfail, dpfail, dppass); +} + +static void APIENTRY InitStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilFuncSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilFuncSeparateATI = extproc; + + glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); +} + +static void APIENTRY InitVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribArrayObjectATI = extproc; + + glVertexAttribArrayObjectATI(index, size, type, normalized, stride, buffer, offset); +} + +static void APIENTRY InitGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectfvATI = extproc; + + glGetVertexAttribArrayObjectfvATI(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectivATI = extproc; + + glGetVertexAttribArrayObjectivATI(index, pname, params); +} + +static void APIENTRY InitDepthBoundsEXT (GLclampd zmin, GLclampd zmax) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDepthBoundsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDepthBoundsEXT = extproc; + + glDepthBoundsEXT(zmin, zmax); +} + +static void APIENTRY InitBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationSeparateEXT = extproc; + + glBlendEquationSeparateEXT(modeRGB, modeAlpha); +} + +static void APIENTRY InitAddSwapHintRectWIN (GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAddSwapHintRectWIN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAddSwapHintRectWIN = extproc; + + glAddSwapHintRectWIN(x, y, width, height); +} + +#ifdef _WIN32 + +static HANDLE WINAPI InitCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateBufferRegionARB = extproc; + + return wglCreateBufferRegionARB(hDC, iLayerPlane, uType); +} + +static VOID WINAPI InitDeleteBufferRegionARB (HANDLE hRegion) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDeleteBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDeleteBufferRegionARB = extproc; + + wglDeleteBufferRegionARB(hRegion); +} + +static BOOL WINAPI InitSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSaveBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSaveBufferRegionARB = extproc; + + return wglSaveBufferRegionARB(hRegion, x, y, width, height); +} + +static BOOL WINAPI InitRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglRestoreBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglRestoreBufferRegionARB = extproc; + + return wglRestoreBufferRegionARB(hRegion, x, y, width, height, xSrc, ySrc); +} + +static const WINAPI InitGetExtensionsStringARB (HDC hdc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringARB = extproc; + + return wglGetExtensionsStringARB(hdc); +} + +static BOOL WINAPI InitGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivARB = extproc; + + return wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvARB = extproc; + + return wglGetPixelFormatAttribfvARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatARB = extproc; + + return wglChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentARB = extproc; + + return wglMakeContextCurrentARB(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCARB = extproc; + + return wglGetCurrentReadDCARB(); +} + +static HPBUFFERARB WINAPI InitCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferARB = extproc; + + return wglCreatePbufferARB(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCARB = extproc; + + return wglGetPbufferDCARB(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCARB = extproc; + + return wglReleasePbufferDCARB(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferARB = extproc; + + return wglDestroyPbufferARB(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferARB = extproc; + + return wglQueryPbufferARB(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindTexImageARB = extproc; + + return wglBindTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseTexImageARB = extproc; + + return wglReleaseTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetPbufferAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetPbufferAttribARB = extproc; + + return wglSetPbufferAttribARB(hPbuffer, piAttribList); +} + +static GLboolean WINAPI InitCreateDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateDisplayColorTableEXT = extproc; + + return wglCreateDisplayColorTableEXT(id); +} + +static GLboolean WINAPI InitLoadDisplayColorTableEXT (const GLushort *table, GLuint length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglLoadDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglLoadDisplayColorTableEXT = extproc; + + return wglLoadDisplayColorTableEXT(table, length); +} + +static GLboolean WINAPI InitBindDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindDisplayColorTableEXT = extproc; + + return wglBindDisplayColorTableEXT(id); +} + +static VOID WINAPI InitDestroyDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDestroyDisplayColorTableEXT = extproc; + + wglDestroyDisplayColorTableEXT(id); +} + +static const WINAPI InitGetExtensionsStringEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringEXT = extproc; + + return wglGetExtensionsStringEXT(); +} + +static BOOL WINAPI InitMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentEXT = extproc; + + return wglMakeContextCurrentEXT(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCEXT = extproc; + + return wglGetCurrentReadDCEXT(); +} + +static HPBUFFEREXT WINAPI InitCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferEXT = extproc; + + return wglCreatePbufferEXT(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCEXT = extproc; + + return wglGetPbufferDCEXT(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCEXT = extproc; + + return wglReleasePbufferDCEXT(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferEXT = extproc; + + return wglDestroyPbufferEXT(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferEXT = extproc; + + return wglQueryPbufferEXT(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivEXT = extproc; + + return wglGetPixelFormatAttribivEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvEXT = extproc; + + return wglGetPixelFormatAttribfvEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatEXT = extproc; + + return wglChoosePixelFormatEXT(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitSwapIntervalEXT (int interval) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapIntervalEXT = extproc; + + return wglSwapIntervalEXT(interval); +} + +static int WINAPI InitGetSwapIntervalEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSwapIntervalEXT = extproc; + + return wglGetSwapIntervalEXT(); +} + +static void* WINAPI InitAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAllocateMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAllocateMemoryNV = extproc; + + return wglAllocateMemoryNV(size, readfreq, writefreq, priority); +} + +static void WINAPI InitFreeMemoryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglFreeMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglFreeMemoryNV = extproc; + + wglFreeMemoryNV(); +} + +static BOOL WINAPI InitGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSyncValuesOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSyncValuesOML = extproc; + + return wglGetSyncValuesOML(hdc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetMscRateOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetMscRateOML = extproc; + + return wglGetMscRateOML(hdc, numerator, denominator); +} + +static INT64 WINAPI InitSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapBuffersMscOML = extproc; + + return wglSwapBuffersMscOML(hdc, target_msc, divisor, remainder); +} + +static INT64 WINAPI InitSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapLayerBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapLayerBuffersMscOML = extproc; + + return wglSwapLayerBuffersMscOML(hdc, fuPlanes, target_msc, divisor, remainder); +} + +static BOOL WINAPI InitWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForMscOML = extproc; + + return wglWaitForMscOML(hdc, target_msc, divisor, remainder, ust, msc, sbc); +} + +static BOOL WINAPI InitWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForSbcOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForSbcOML = extproc; + + return wglWaitForSbcOML(hdc, target_sbc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetDigitalVideoParametersI3D = extproc; + + return wglGetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetDigitalVideoParametersI3D = extproc; + + return wglSetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableParametersI3D = extproc; + + return wglGetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableParametersI3D = extproc; + + return wglSetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableI3D = extproc; + + return wglGetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableI3D = extproc; + + return wglSetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitEnableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableGenlockI3D = extproc; + + return wglEnableGenlockI3D(hDC); +} + +static BOOL WINAPI InitDisableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableGenlockI3D = extproc; + + return wglDisableGenlockI3D(hDC); +} + +static BOOL WINAPI InitIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledGenlockI3D = extproc; + + return wglIsEnabledGenlockI3D(hDC, pFlag); +} + +static BOOL WINAPI InitGenlockSourceI3D (HDC hDC, UINT uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceI3D = extproc; + + return wglGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGetGenlockSourceI3D (HDC hDC, UINT *uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceI3D = extproc; + + return wglGetGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGenlockSourceEdgeI3D (HDC hDC, UINT uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceEdgeI3D = extproc; + + return wglGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceEdgeI3D = extproc; + + return wglGetGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGenlockSampleRateI3D (HDC hDC, UINT uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSampleRateI3D = extproc; + + return wglGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGetGenlockSampleRateI3D (HDC hDC, UINT *uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSampleRateI3D = extproc; + + return wglGetGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGenlockSourceDelayI3D (HDC hDC, UINT uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceDelayI3D = extproc; + + return wglGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceDelayI3D = extproc; + + return wglGetGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryGenlockMaxSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryGenlockMaxSourceDelayI3D = extproc; + + return wglQueryGenlockMaxSourceDelayI3D(hDC, uMaxLineDelay, uMaxPixelDelay); +} + +static LPVOID WINAPI InitCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateImageBufferI3D = extproc; + + return wglCreateImageBufferI3D(hDC, dwSize, uFlags); +} + +static BOOL WINAPI InitDestroyImageBufferI3D (HDC hDC, LPVOID pAddress) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyImageBufferI3D = extproc; + + return wglDestroyImageBufferI3D(hDC, pAddress); +} + +static BOOL WINAPI InitAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAssociateImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAssociateImageBufferEventsI3D = extproc; + + return wglAssociateImageBufferEventsI3D(hDC, pEvent, pAddress, pSize, count); +} + +static BOOL WINAPI InitReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseImageBufferEventsI3D = extproc; + + return wglReleaseImageBufferEventsI3D(hDC, pAddress, count); +} + +static BOOL WINAPI InitEnableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableFrameLockI3D = extproc; + + return wglEnableFrameLockI3D(); +} + +static BOOL WINAPI InitDisableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableFrameLockI3D = extproc; + + return wglDisableFrameLockI3D(); +} + +static BOOL WINAPI InitIsEnabledFrameLockI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledFrameLockI3D = extproc; + + return wglIsEnabledFrameLockI3D(pFlag); +} + +static BOOL WINAPI InitQueryFrameLockMasterI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameLockMasterI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameLockMasterI3D = extproc; + + return wglQueryFrameLockMasterI3D(pFlag); +} + +static BOOL WINAPI InitGetFrameUsageI3D (float *pUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetFrameUsageI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetFrameUsageI3D = extproc; + + return wglGetFrameUsageI3D(pUsage); +} + +static BOOL WINAPI InitBeginFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBeginFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBeginFrameTrackingI3D = extproc; + + return wglBeginFrameTrackingI3D(); +} + +static BOOL WINAPI InitEndFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEndFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEndFrameTrackingI3D = extproc; + + return wglEndFrameTrackingI3D(); +} + +static BOOL WINAPI InitQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameTrackingI3D = extproc; + + return wglQueryFrameTrackingI3D(pFrameCount, pMissedFrames, pLastMissedUsage); +} + +#endif /* _WIN32 */ + +_GLextensionProcs _extensionProcs = { + InitBlendColor, + InitBlendEquation, + InitDrawRangeElements, + InitColorTable, + InitColorTableParameterfv, + InitColorTableParameteriv, + InitCopyColorTable, + InitGetColorTable, + InitGetColorTableParameterfv, + InitGetColorTableParameteriv, + InitColorSubTable, + InitCopyColorSubTable, + InitConvolutionFilter1D, + InitConvolutionFilter2D, + InitConvolutionParameterf, + InitConvolutionParameterfv, + InitConvolutionParameteri, + InitConvolutionParameteriv, + InitCopyConvolutionFilter1D, + InitCopyConvolutionFilter2D, + InitGetConvolutionFilter, + InitGetConvolutionParameterfv, + InitGetConvolutionParameteriv, + InitGetSeparableFilter, + InitSeparableFilter2D, + InitGetHistogram, + InitGetHistogramParameterfv, + InitGetHistogramParameteriv, + InitGetMinmax, + InitGetMinmaxParameterfv, + InitGetMinmaxParameteriv, + InitHistogram, + InitMinmax, + InitResetHistogram, + InitResetMinmax, + InitTexImage3D, + InitTexSubImage3D, + InitCopyTexSubImage3D, + InitActiveTexture, + InitClientActiveTexture, + InitMultiTexCoord1d, + InitMultiTexCoord1dv, + InitMultiTexCoord1f, + InitMultiTexCoord1fv, + InitMultiTexCoord1i, + InitMultiTexCoord1iv, + InitMultiTexCoord1s, + InitMultiTexCoord1sv, + InitMultiTexCoord2d, + InitMultiTexCoord2dv, + InitMultiTexCoord2f, + InitMultiTexCoord2fv, + InitMultiTexCoord2i, + InitMultiTexCoord2iv, + InitMultiTexCoord2s, + InitMultiTexCoord2sv, + InitMultiTexCoord3d, + InitMultiTexCoord3dv, + InitMultiTexCoord3f, + InitMultiTexCoord3fv, + InitMultiTexCoord3i, + InitMultiTexCoord3iv, + InitMultiTexCoord3s, + InitMultiTexCoord3sv, + InitMultiTexCoord4d, + InitMultiTexCoord4dv, + InitMultiTexCoord4f, + InitMultiTexCoord4fv, + InitMultiTexCoord4i, + InitMultiTexCoord4iv, + InitMultiTexCoord4s, + InitMultiTexCoord4sv, + InitLoadTransposeMatrixf, + InitLoadTransposeMatrixd, + InitMultTransposeMatrixf, + InitMultTransposeMatrixd, + InitSampleCoverage, + InitCompressedTexImage3D, + InitCompressedTexImage2D, + InitCompressedTexImage1D, + InitCompressedTexSubImage3D, + InitCompressedTexSubImage2D, + InitCompressedTexSubImage1D, + InitGetCompressedTexImage, + InitBlendFuncSeparate, + InitFogCoordf, + InitFogCoordfv, + InitFogCoordd, + InitFogCoorddv, + InitFogCoordPointer, + InitMultiDrawArrays, + InitMultiDrawElements, + InitPointParameterf, + InitPointParameterfv, + InitPointParameteri, + InitPointParameteriv, + InitSecondaryColor3b, + InitSecondaryColor3bv, + InitSecondaryColor3d, + InitSecondaryColor3dv, + InitSecondaryColor3f, + InitSecondaryColor3fv, + InitSecondaryColor3i, + InitSecondaryColor3iv, + InitSecondaryColor3s, + InitSecondaryColor3sv, + InitSecondaryColor3ub, + InitSecondaryColor3ubv, + InitSecondaryColor3ui, + InitSecondaryColor3uiv, + InitSecondaryColor3us, + InitSecondaryColor3usv, + InitSecondaryColorPointer, + InitWindowPos2d, + InitWindowPos2dv, + InitWindowPos2f, + InitWindowPos2fv, + InitWindowPos2i, + InitWindowPos2iv, + InitWindowPos2s, + InitWindowPos2sv, + InitWindowPos3d, + InitWindowPos3dv, + InitWindowPos3f, + InitWindowPos3fv, + InitWindowPos3i, + InitWindowPos3iv, + InitWindowPos3s, + InitWindowPos3sv, + InitGenQueries, + InitDeleteQueries, + InitIsQuery, + InitBeginQuery, + InitEndQuery, + InitGetQueryiv, + InitGetQueryObjectiv, + InitGetQueryObjectuiv, + InitBindBuffer, + InitDeleteBuffers, + InitGenBuffers, + InitIsBuffer, + InitBufferData, + InitBufferSubData, + InitGetBufferSubData, + InitMapBuffer, + InitUnmapBuffer, + InitGetBufferParameteriv, + InitGetBufferPointerv, + InitActiveTextureARB, + InitClientActiveTextureARB, + InitMultiTexCoord1dARB, + InitMultiTexCoord1dvARB, + InitMultiTexCoord1fARB, + InitMultiTexCoord1fvARB, + InitMultiTexCoord1iARB, + InitMultiTexCoord1ivARB, + InitMultiTexCoord1sARB, + InitMultiTexCoord1svARB, + InitMultiTexCoord2dARB, + InitMultiTexCoord2dvARB, + InitMultiTexCoord2fARB, + InitMultiTexCoord2fvARB, + InitMultiTexCoord2iARB, + InitMultiTexCoord2ivARB, + InitMultiTexCoord2sARB, + InitMultiTexCoord2svARB, + InitMultiTexCoord3dARB, + InitMultiTexCoord3dvARB, + InitMultiTexCoord3fARB, + InitMultiTexCoord3fvARB, + InitMultiTexCoord3iARB, + InitMultiTexCoord3ivARB, + InitMultiTexCoord3sARB, + InitMultiTexCoord3svARB, + InitMultiTexCoord4dARB, + InitMultiTexCoord4dvARB, + InitMultiTexCoord4fARB, + InitMultiTexCoord4fvARB, + InitMultiTexCoord4iARB, + InitMultiTexCoord4ivARB, + InitMultiTexCoord4sARB, + InitMultiTexCoord4svARB, + InitLoadTransposeMatrixfARB, + InitLoadTransposeMatrixdARB, + InitMultTransposeMatrixfARB, + InitMultTransposeMatrixdARB, + InitSampleCoverageARB, + InitCompressedTexImage3DARB, + InitCompressedTexImage2DARB, + InitCompressedTexImage1DARB, + InitCompressedTexSubImage3DARB, + InitCompressedTexSubImage2DARB, + InitCompressedTexSubImage1DARB, + InitGetCompressedTexImageARB, + InitPointParameterfARB, + InitPointParameterfvARB, + InitWeightbvARB, + InitWeightsvARB, + InitWeightivARB, + InitWeightfvARB, + InitWeightdvARB, + InitWeightubvARB, + InitWeightusvARB, + InitWeightuivARB, + InitWeightPointerARB, + InitVertexBlendARB, + InitCurrentPaletteMatrixARB, + InitMatrixIndexubvARB, + InitMatrixIndexusvARB, + InitMatrixIndexuivARB, + InitMatrixIndexPointerARB, + InitWindowPos2dARB, + InitWindowPos2dvARB, + InitWindowPos2fARB, + InitWindowPos2fvARB, + InitWindowPos2iARB, + InitWindowPos2ivARB, + InitWindowPos2sARB, + InitWindowPos2svARB, + InitWindowPos3dARB, + InitWindowPos3dvARB, + InitWindowPos3fARB, + InitWindowPos3fvARB, + InitWindowPos3iARB, + InitWindowPos3ivARB, + InitWindowPos3sARB, + InitWindowPos3svARB, + InitVertexAttrib1dARB, + InitVertexAttrib1dvARB, + InitVertexAttrib1fARB, + InitVertexAttrib1fvARB, + InitVertexAttrib1sARB, + InitVertexAttrib1svARB, + InitVertexAttrib2dARB, + InitVertexAttrib2dvARB, + InitVertexAttrib2fARB, + InitVertexAttrib2fvARB, + InitVertexAttrib2sARB, + InitVertexAttrib2svARB, + InitVertexAttrib3dARB, + InitVertexAttrib3dvARB, + InitVertexAttrib3fARB, + InitVertexAttrib3fvARB, + InitVertexAttrib3sARB, + InitVertexAttrib3svARB, + InitVertexAttrib4NbvARB, + InitVertexAttrib4NivARB, + InitVertexAttrib4NsvARB, + InitVertexAttrib4NubARB, + InitVertexAttrib4NubvARB, + InitVertexAttrib4NuivARB, + InitVertexAttrib4NusvARB, + InitVertexAttrib4bvARB, + InitVertexAttrib4dARB, + InitVertexAttrib4dvARB, + InitVertexAttrib4fARB, + InitVertexAttrib4fvARB, + InitVertexAttrib4ivARB, + InitVertexAttrib4sARB, + InitVertexAttrib4svARB, + InitVertexAttrib4ubvARB, + InitVertexAttrib4uivARB, + InitVertexAttrib4usvARB, + InitVertexAttribPointerARB, + InitEnableVertexAttribArrayARB, + InitDisableVertexAttribArrayARB, + InitProgramStringARB, + InitBindProgramARB, + InitDeleteProgramsARB, + InitGenProgramsARB, + InitProgramEnvParameter4dARB, + InitProgramEnvParameter4dvARB, + InitProgramEnvParameter4fARB, + InitProgramEnvParameter4fvARB, + InitProgramLocalParameter4dARB, + InitProgramLocalParameter4dvARB, + InitProgramLocalParameter4fARB, + InitProgramLocalParameter4fvARB, + InitGetProgramEnvParameterdvARB, + InitGetProgramEnvParameterfvARB, + InitGetProgramLocalParameterdvARB, + InitGetProgramLocalParameterfvARB, + InitGetProgramivARB, + InitGetProgramStringARB, + InitGetVertexAttribdvARB, + InitGetVertexAttribfvARB, + InitGetVertexAttribivARB, + InitGetVertexAttribPointervARB, + InitIsProgramARB, + InitBindBufferARB, + InitDeleteBuffersARB, + InitGenBuffersARB, + InitIsBufferARB, + InitBufferDataARB, + InitBufferSubDataARB, + InitGetBufferSubDataARB, + InitMapBufferARB, + InitUnmapBufferARB, + InitGetBufferParameterivARB, + InitGetBufferPointervARB, + InitGenQueriesARB, + InitDeleteQueriesARB, + InitIsQueryARB, + InitBeginQueryARB, + InitEndQueryARB, + InitGetQueryivARB, + InitGetQueryObjectivARB, + InitGetQueryObjectuivARB, + InitDeleteObjectARB, + InitGetHandleARB, + InitDetachObjectARB, + InitCreateShaderObjectARB, + InitShaderSourceARB, + InitCompileShaderARB, + InitCreateProgramObjectARB, + InitAttachObjectARB, + InitLinkProgramARB, + InitUseProgramObjectARB, + InitValidateProgramARB, + InitUniform1fARB, + InitUniform2fARB, + InitUniform3fARB, + InitUniform4fARB, + InitUniform1iARB, + InitUniform2iARB, + InitUniform3iARB, + InitUniform4iARB, + InitUniform1fvARB, + InitUniform2fvARB, + InitUniform3fvARB, + InitUniform4fvARB, + InitUniform1ivARB, + InitUniform2ivARB, + InitUniform3ivARB, + InitUniform4ivARB, + InitUniformMatrix2fvARB, + InitUniformMatrix3fvARB, + InitUniformMatrix4fvARB, + InitGetObjectParameterfvARB, + InitGetObjectParameterivARB, + InitGetInfoLogARB, + InitGetAttachedObjectsARB, + InitGetUniformLocationARB, + InitGetActiveUniformARB, + InitGetUniformfvARB, + InitGetUniformivARB, + InitGetShaderSourceARB, + InitBindAttribLocationARB, + InitGetActiveAttribARB, + InitGetAttribLocationARB, + InitBlendColorEXT, + InitPolygonOffsetEXT, + InitTexImage3DEXT, + InitTexSubImage3DEXT, + InitGetTexFilterFuncSGIS, + InitTexFilterFuncSGIS, + InitTexSubImage1DEXT, + InitTexSubImage2DEXT, + InitCopyTexImage1DEXT, + InitCopyTexImage2DEXT, + InitCopyTexSubImage1DEXT, + InitCopyTexSubImage2DEXT, + InitCopyTexSubImage3DEXT, + InitGetHistogramEXT, + InitGetHistogramParameterfvEXT, + InitGetHistogramParameterivEXT, + InitGetMinmaxEXT, + InitGetMinmaxParameterfvEXT, + InitGetMinmaxParameterivEXT, + InitHistogramEXT, + InitMinmaxEXT, + InitResetHistogramEXT, + InitResetMinmaxEXT, + InitConvolutionFilter1DEXT, + InitConvolutionFilter2DEXT, + InitConvolutionParameterfEXT, + InitConvolutionParameterfvEXT, + InitConvolutionParameteriEXT, + InitConvolutionParameterivEXT, + InitCopyConvolutionFilter1DEXT, + InitCopyConvolutionFilter2DEXT, + InitGetConvolutionFilterEXT, + InitGetConvolutionParameterfvEXT, + InitGetConvolutionParameterivEXT, + InitGetSeparableFilterEXT, + InitSeparableFilter2DEXT, + InitColorTableSGI, + InitColorTableParameterfvSGI, + InitColorTableParameterivSGI, + InitCopyColorTableSGI, + InitGetColorTableSGI, + InitGetColorTableParameterfvSGI, + InitGetColorTableParameterivSGI, + InitPixelTexGenSGIX, + InitPixelTexGenParameteriSGIS, + InitPixelTexGenParameterivSGIS, + InitPixelTexGenParameterfSGIS, + InitPixelTexGenParameterfvSGIS, + InitGetPixelTexGenParameterivSGIS, + InitGetPixelTexGenParameterfvSGIS, + InitTexImage4DSGIS, + InitTexSubImage4DSGIS, + InitAreTexturesResidentEXT, + InitBindTextureEXT, + InitDeleteTexturesEXT, + InitGenTexturesEXT, + InitIsTextureEXT, + InitPrioritizeTexturesEXT, + InitDetailTexFuncSGIS, + InitGetDetailTexFuncSGIS, + InitSharpenTexFuncSGIS, + InitGetSharpenTexFuncSGIS, + InitSampleMaskSGIS, + InitSamplePatternSGIS, + InitArrayElementEXT, + InitColorPointerEXT, + InitDrawArraysEXT, + InitEdgeFlagPointerEXT, + InitGetPointervEXT, + InitIndexPointerEXT, + InitNormalPointerEXT, + InitTexCoordPointerEXT, + InitVertexPointerEXT, + InitBlendEquationEXT, + InitSpriteParameterfSGIX, + InitSpriteParameterfvSGIX, + InitSpriteParameteriSGIX, + InitSpriteParameterivSGIX, + InitPointParameterfEXT, + InitPointParameterfvEXT, + InitPointParameterfSGIS, + InitPointParameterfvSGIS, + InitGetInstrumentsSGIX, + InitInstrumentsBufferSGIX, + InitPollInstrumentsSGIX, + InitReadInstrumentsSGIX, + InitStartInstrumentsSGIX, + InitStopInstrumentsSGIX, + InitFrameZoomSGIX, + InitTagSampleBufferSGIX, + InitDeformationMap3dSGIX, + InitDeformationMap3fSGIX, + InitDeformSGIX, + InitLoadIdentityDeformationMapSGIX, + InitReferencePlaneSGIX, + InitFlushRasterSGIX, + InitFogFuncSGIS, + InitGetFogFuncSGIS, + InitImageTransformParameteriHP, + InitImageTransformParameterfHP, + InitImageTransformParameterivHP, + InitImageTransformParameterfvHP, + InitGetImageTransformParameterivHP, + InitGetImageTransformParameterfvHP, + InitColorSubTableEXT, + InitCopyColorSubTableEXT, + InitHintPGI, + InitColorTableEXT, + InitGetColorTableEXT, + InitGetColorTableParameterivEXT, + InitGetColorTableParameterfvEXT, + InitGetListParameterfvSGIX, + InitGetListParameterivSGIX, + InitListParameterfSGIX, + InitListParameterfvSGIX, + InitListParameteriSGIX, + InitListParameterivSGIX, + InitIndexMaterialEXT, + InitIndexFuncEXT, + InitLockArraysEXT, + InitUnlockArraysEXT, + InitCullParameterdvEXT, + InitCullParameterfvEXT, + InitFragmentColorMaterialSGIX, + InitFragmentLightfSGIX, + InitFragmentLightfvSGIX, + InitFragmentLightiSGIX, + InitFragmentLightivSGIX, + InitFragmentLightModelfSGIX, + InitFragmentLightModelfvSGIX, + InitFragmentLightModeliSGIX, + InitFragmentLightModelivSGIX, + InitFragmentMaterialfSGIX, + InitFragmentMaterialfvSGIX, + InitFragmentMaterialiSGIX, + InitFragmentMaterialivSGIX, + InitGetFragmentLightfvSGIX, + InitGetFragmentLightivSGIX, + InitGetFragmentMaterialfvSGIX, + InitGetFragmentMaterialivSGIX, + InitLightEnviSGIX, + InitDrawRangeElementsEXT, + InitApplyTextureEXT, + InitTextureLightEXT, + InitTextureMaterialEXT, + InitAsyncMarkerSGIX, + InitFinishAsyncSGIX, + InitPollAsyncSGIX, + InitGenAsyncMarkersSGIX, + InitDeleteAsyncMarkersSGIX, + InitIsAsyncMarkerSGIX, + InitVertexPointervINTEL, + InitNormalPointervINTEL, + InitColorPointervINTEL, + InitTexCoordPointervINTEL, + InitPixelTransformParameteriEXT, + InitPixelTransformParameterfEXT, + InitPixelTransformParameterivEXT, + InitPixelTransformParameterfvEXT, + InitSecondaryColor3bEXT, + InitSecondaryColor3bvEXT, + InitSecondaryColor3dEXT, + InitSecondaryColor3dvEXT, + InitSecondaryColor3fEXT, + InitSecondaryColor3fvEXT, + InitSecondaryColor3iEXT, + InitSecondaryColor3ivEXT, + InitSecondaryColor3sEXT, + InitSecondaryColor3svEXT, + InitSecondaryColor3ubEXT, + InitSecondaryColor3ubvEXT, + InitSecondaryColor3uiEXT, + InitSecondaryColor3uivEXT, + InitSecondaryColor3usEXT, + InitSecondaryColor3usvEXT, + InitSecondaryColorPointerEXT, + InitTextureNormalEXT, + InitMultiDrawArraysEXT, + InitMultiDrawElementsEXT, + InitFogCoordfEXT, + InitFogCoordfvEXT, + InitFogCoorddEXT, + InitFogCoorddvEXT, + InitFogCoordPointerEXT, + InitTangent3bEXT, + InitTangent3bvEXT, + InitTangent3dEXT, + InitTangent3dvEXT, + InitTangent3fEXT, + InitTangent3fvEXT, + InitTangent3iEXT, + InitTangent3ivEXT, + InitTangent3sEXT, + InitTangent3svEXT, + InitBinormal3bEXT, + InitBinormal3bvEXT, + InitBinormal3dEXT, + InitBinormal3dvEXT, + InitBinormal3fEXT, + InitBinormal3fvEXT, + InitBinormal3iEXT, + InitBinormal3ivEXT, + InitBinormal3sEXT, + InitBinormal3svEXT, + InitTangentPointerEXT, + InitBinormalPointerEXT, + InitFinishTextureSUNX, + InitGlobalAlphaFactorbSUN, + InitGlobalAlphaFactorsSUN, + InitGlobalAlphaFactoriSUN, + InitGlobalAlphaFactorfSUN, + InitGlobalAlphaFactordSUN, + InitGlobalAlphaFactorubSUN, + InitGlobalAlphaFactorusSUN, + InitGlobalAlphaFactoruiSUN, + InitReplacementCodeuiSUN, + InitReplacementCodeusSUN, + InitReplacementCodeubSUN, + InitReplacementCodeuivSUN, + InitReplacementCodeusvSUN, + InitReplacementCodeubvSUN, + InitReplacementCodePointerSUN, + InitColor4ubVertex2fSUN, + InitColor4ubVertex2fvSUN, + InitColor4ubVertex3fSUN, + InitColor4ubVertex3fvSUN, + InitColor3fVertex3fSUN, + InitColor3fVertex3fvSUN, + InitNormal3fVertex3fSUN, + InitNormal3fVertex3fvSUN, + InitColor4fNormal3fVertex3fSUN, + InitColor4fNormal3fVertex3fvSUN, + InitTexCoord2fVertex3fSUN, + InitTexCoord2fVertex3fvSUN, + InitTexCoord4fVertex4fSUN, + InitTexCoord4fVertex4fvSUN, + InitTexCoord2fColor4ubVertex3fSUN, + InitTexCoord2fColor4ubVertex3fvSUN, + InitTexCoord2fColor3fVertex3fSUN, + InitTexCoord2fColor3fVertex3fvSUN, + InitTexCoord2fNormal3fVertex3fSUN, + InitTexCoord2fNormal3fVertex3fvSUN, + InitTexCoord2fColor4fNormal3fVertex3fSUN, + InitTexCoord2fColor4fNormal3fVertex3fvSUN, + InitTexCoord4fColor4fNormal3fVertex4fSUN, + InitTexCoord4fColor4fNormal3fVertex4fvSUN, + InitReplacementCodeuiVertex3fSUN, + InitReplacementCodeuiVertex3fvSUN, + InitReplacementCodeuiColor4ubVertex3fSUN, + InitReplacementCodeuiColor4ubVertex3fvSUN, + InitReplacementCodeuiColor3fVertex3fSUN, + InitReplacementCodeuiColor3fVertex3fvSUN, + InitReplacementCodeuiNormal3fVertex3fSUN, + InitReplacementCodeuiNormal3fVertex3fvSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fVertex3fSUN, + InitReplacementCodeuiTexCoord2fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, + InitBlendFuncSeparateEXT, + InitBlendFuncSeparateINGR, + InitVertexWeightfEXT, + InitVertexWeightfvEXT, + InitVertexWeightPointerEXT, + InitFlushVertexArrayRangeNV, + InitVertexArrayRangeNV, + InitCombinerParameterfvNV, + InitCombinerParameterfNV, + InitCombinerParameterivNV, + InitCombinerParameteriNV, + InitCombinerInputNV, + InitCombinerOutputNV, + InitFinalCombinerInputNV, + InitGetCombinerInputParameterfvNV, + InitGetCombinerInputParameterivNV, + InitGetCombinerOutputParameterfvNV, + InitGetCombinerOutputParameterivNV, + InitGetFinalCombinerInputParameterfvNV, + InitGetFinalCombinerInputParameterivNV, + InitResizeBuffersMESA, + InitWindowPos2dMESA, + InitWindowPos2dvMESA, + InitWindowPos2fMESA, + InitWindowPos2fvMESA, + InitWindowPos2iMESA, + InitWindowPos2ivMESA, + InitWindowPos2sMESA, + InitWindowPos2svMESA, + InitWindowPos3dMESA, + InitWindowPos3dvMESA, + InitWindowPos3fMESA, + InitWindowPos3fvMESA, + InitWindowPos3iMESA, + InitWindowPos3ivMESA, + InitWindowPos3sMESA, + InitWindowPos3svMESA, + InitWindowPos4dMESA, + InitWindowPos4dvMESA, + InitWindowPos4fMESA, + InitWindowPos4fvMESA, + InitWindowPos4iMESA, + InitWindowPos4ivMESA, + InitWindowPos4sMESA, + InitWindowPos4svMESA, + InitMultiModeDrawArraysIBM, + InitMultiModeDrawElementsIBM, + InitColorPointerListIBM, + InitSecondaryColorPointerListIBM, + InitEdgeFlagPointerListIBM, + InitFogCoordPointerListIBM, + InitIndexPointerListIBM, + InitNormalPointerListIBM, + InitTexCoordPointerListIBM, + InitVertexPointerListIBM, + InitTbufferMask3DFX, + InitSampleMaskEXT, + InitSamplePatternEXT, + InitTextureColorMaskSGIS, + InitIglooInterfaceSGIX, + InitDeleteFencesNV, + InitGenFencesNV, + InitIsFenceNV, + InitTestFenceNV, + InitGetFenceivNV, + InitFinishFenceNV, + InitSetFenceNV, + InitMapControlPointsNV, + InitMapParameterivNV, + InitMapParameterfvNV, + InitGetMapControlPointsNV, + InitGetMapParameterivNV, + InitGetMapParameterfvNV, + InitGetMapAttribParameterivNV, + InitGetMapAttribParameterfvNV, + InitEvalMapsNV, + InitCombinerStageParameterfvNV, + InitGetCombinerStageParameterfvNV, + InitAreProgramsResidentNV, + InitBindProgramNV, + InitDeleteProgramsNV, + InitExecuteProgramNV, + InitGenProgramsNV, + InitGetProgramParameterdvNV, + InitGetProgramParameterfvNV, + InitGetProgramivNV, + InitGetProgramStringNV, + InitGetTrackMatrixivNV, + InitGetVertexAttribdvNV, + InitGetVertexAttribfvNV, + InitGetVertexAttribivNV, + InitGetVertexAttribPointervNV, + InitIsProgramNV, + InitLoadProgramNV, + InitProgramParameter4dNV, + InitProgramParameter4dvNV, + InitProgramParameter4fNV, + InitProgramParameter4fvNV, + InitProgramParameters4dvNV, + InitProgramParameters4fvNV, + InitRequestResidentProgramsNV, + InitTrackMatrixNV, + InitVertexAttribPointerNV, + InitVertexAttrib1dNV, + InitVertexAttrib1dvNV, + InitVertexAttrib1fNV, + InitVertexAttrib1fvNV, + InitVertexAttrib1sNV, + InitVertexAttrib1svNV, + InitVertexAttrib2dNV, + InitVertexAttrib2dvNV, + InitVertexAttrib2fNV, + InitVertexAttrib2fvNV, + InitVertexAttrib2sNV, + InitVertexAttrib2svNV, + InitVertexAttrib3dNV, + InitVertexAttrib3dvNV, + InitVertexAttrib3fNV, + InitVertexAttrib3fvNV, + InitVertexAttrib3sNV, + InitVertexAttrib3svNV, + InitVertexAttrib4dNV, + InitVertexAttrib4dvNV, + InitVertexAttrib4fNV, + InitVertexAttrib4fvNV, + InitVertexAttrib4sNV, + InitVertexAttrib4svNV, + InitVertexAttrib4ubNV, + InitVertexAttrib4ubvNV, + InitVertexAttribs1dvNV, + InitVertexAttribs1fvNV, + InitVertexAttribs1svNV, + InitVertexAttribs2dvNV, + InitVertexAttribs2fvNV, + InitVertexAttribs2svNV, + InitVertexAttribs3dvNV, + InitVertexAttribs3fvNV, + InitVertexAttribs3svNV, + InitVertexAttribs4dvNV, + InitVertexAttribs4fvNV, + InitVertexAttribs4svNV, + InitVertexAttribs4ubvNV, + InitTexBumpParameterivATI, + InitTexBumpParameterfvATI, + InitGetTexBumpParameterivATI, + InitGetTexBumpParameterfvATI, + InitGenFragmentShadersATI, + InitBindFragmentShaderATI, + InitDeleteFragmentShaderATI, + InitBeginFragmentShaderATI, + InitEndFragmentShaderATI, + InitPassTexCoordATI, + InitSampleMapATI, + InitColorFragmentOp1ATI, + InitColorFragmentOp2ATI, + InitColorFragmentOp3ATI, + InitAlphaFragmentOp1ATI, + InitAlphaFragmentOp2ATI, + InitAlphaFragmentOp3ATI, + InitSetFragmentShaderConstantATI, + InitPNTrianglesiATI, + InitPNTrianglesfATI, + InitNewObjectBufferATI, + InitIsObjectBufferATI, + InitUpdateObjectBufferATI, + InitGetObjectBufferfvATI, + InitGetObjectBufferivATI, + InitFreeObjectBufferATI, + InitArrayObjectATI, + InitGetArrayObjectfvATI, + InitGetArrayObjectivATI, + InitVariantArrayObjectATI, + InitGetVariantArrayObjectfvATI, + InitGetVariantArrayObjectivATI, + InitBeginVertexShaderEXT, + InitEndVertexShaderEXT, + InitBindVertexShaderEXT, + InitGenVertexShadersEXT, + InitDeleteVertexShaderEXT, + InitShaderOp1EXT, + InitShaderOp2EXT, + InitShaderOp3EXT, + InitSwizzleEXT, + InitWriteMaskEXT, + InitInsertComponentEXT, + InitExtractComponentEXT, + InitGenSymbolsEXT, + InitSetInvariantEXT, + InitSetLocalConstantEXT, + InitVariantbvEXT, + InitVariantsvEXT, + InitVariantivEXT, + InitVariantfvEXT, + InitVariantdvEXT, + InitVariantubvEXT, + InitVariantusvEXT, + InitVariantuivEXT, + InitVariantPointerEXT, + InitEnableVariantClientStateEXT, + InitDisableVariantClientStateEXT, + InitBindLightParameterEXT, + InitBindMaterialParameterEXT, + InitBindTexGenParameterEXT, + InitBindTextureUnitParameterEXT, + InitBindParameterEXT, + InitIsVariantEnabledEXT, + InitGetVariantBooleanvEXT, + InitGetVariantIntegervEXT, + InitGetVariantFloatvEXT, + InitGetVariantPointervEXT, + InitGetInvariantBooleanvEXT, + InitGetInvariantIntegervEXT, + InitGetInvariantFloatvEXT, + InitGetLocalConstantBooleanvEXT, + InitGetLocalConstantIntegervEXT, + InitGetLocalConstantFloatvEXT, + InitVertexStream1sATI, + InitVertexStream1svATI, + InitVertexStream1iATI, + InitVertexStream1ivATI, + InitVertexStream1fATI, + InitVertexStream1fvATI, + InitVertexStream1dATI, + InitVertexStream1dvATI, + InitVertexStream2sATI, + InitVertexStream2svATI, + InitVertexStream2iATI, + InitVertexStream2ivATI, + InitVertexStream2fATI, + InitVertexStream2fvATI, + InitVertexStream2dATI, + InitVertexStream2dvATI, + InitVertexStream3sATI, + InitVertexStream3svATI, + InitVertexStream3iATI, + InitVertexStream3ivATI, + InitVertexStream3fATI, + InitVertexStream3fvATI, + InitVertexStream3dATI, + InitVertexStream3dvATI, + InitVertexStream4sATI, + InitVertexStream4svATI, + InitVertexStream4iATI, + InitVertexStream4ivATI, + InitVertexStream4fATI, + InitVertexStream4fvATI, + InitVertexStream4dATI, + InitVertexStream4dvATI, + InitNormalStream3bATI, + InitNormalStream3bvATI, + InitNormalStream3sATI, + InitNormalStream3svATI, + InitNormalStream3iATI, + InitNormalStream3ivATI, + InitNormalStream3fATI, + InitNormalStream3fvATI, + InitNormalStream3dATI, + InitNormalStream3dvATI, + InitClientActiveVertexStreamATI, + InitVertexBlendEnviATI, + InitVertexBlendEnvfATI, + InitElementPointerATI, + InitDrawElementArrayATI, + InitDrawRangeElementArrayATI, + InitDrawMeshArraysSUN, + InitGenOcclusionQueriesNV, + InitDeleteOcclusionQueriesNV, + InitIsOcclusionQueryNV, + InitBeginOcclusionQueryNV, + InitEndOcclusionQueryNV, + InitGetOcclusionQueryivNV, + InitGetOcclusionQueryuivNV, + InitPointParameteriNV, + InitPointParameterivNV, + InitActiveStencilFaceEXT, + InitElementPointerAPPLE, + InitDrawElementArrayAPPLE, + InitDrawRangeElementArrayAPPLE, + InitMultiDrawElementArrayAPPLE, + InitMultiDrawRangeElementArrayAPPLE, + InitGenFencesAPPLE, + InitDeleteFencesAPPLE, + InitSetFenceAPPLE, + InitIsFenceAPPLE, + InitTestFenceAPPLE, + InitFinishFenceAPPLE, + InitTestObjectAPPLE, + InitFinishObjectAPPLE, + InitBindVertexArrayAPPLE, + InitDeleteVertexArraysAPPLE, + InitGenVertexArraysAPPLE, + InitIsVertexArrayAPPLE, + InitVertexArrayRangeAPPLE, + InitFlushVertexArrayRangeAPPLE, + InitVertexArrayParameteriAPPLE, + InitDrawBuffersATI, + InitProgramNamedParameter4fNV, + InitProgramNamedParameter4dNV, + InitProgramNamedParameter4fvNV, + InitProgramNamedParameter4dvNV, + InitGetProgramNamedParameterfvNV, + InitGetProgramNamedParameterdvNV, + InitVertex2hNV, + InitVertex2hvNV, + InitVertex3hNV, + InitVertex3hvNV, + InitVertex4hNV, + InitVertex4hvNV, + InitNormal3hNV, + InitNormal3hvNV, + InitColor3hNV, + InitColor3hvNV, + InitColor4hNV, + InitColor4hvNV, + InitTexCoord1hNV, + InitTexCoord1hvNV, + InitTexCoord2hNV, + InitTexCoord2hvNV, + InitTexCoord3hNV, + InitTexCoord3hvNV, + InitTexCoord4hNV, + InitTexCoord4hvNV, + InitMultiTexCoord1hNV, + InitMultiTexCoord1hvNV, + InitMultiTexCoord2hNV, + InitMultiTexCoord2hvNV, + InitMultiTexCoord3hNV, + InitMultiTexCoord3hvNV, + InitMultiTexCoord4hNV, + InitMultiTexCoord4hvNV, + InitFogCoordhNV, + InitFogCoordhvNV, + InitSecondaryColor3hNV, + InitSecondaryColor3hvNV, + InitVertexWeighthNV, + InitVertexWeighthvNV, + InitVertexAttrib1hNV, + InitVertexAttrib1hvNV, + InitVertexAttrib2hNV, + InitVertexAttrib2hvNV, + InitVertexAttrib3hNV, + InitVertexAttrib3hvNV, + InitVertexAttrib4hNV, + InitVertexAttrib4hvNV, + InitVertexAttribs1hvNV, + InitVertexAttribs2hvNV, + InitVertexAttribs3hvNV, + InitVertexAttribs4hvNV, + InitPixelDataRangeNV, + InitFlushPixelDataRangeNV, + InitPrimitiveRestartNV, + InitPrimitiveRestartIndexNV, + InitMapObjectBufferATI, + InitUnmapObjectBufferATI, + InitStencilOpSeparateATI, + InitStencilFuncSeparateATI, + InitVertexAttribArrayObjectATI, + InitGetVertexAttribArrayObjectfvATI, + InitGetVertexAttribArrayObjectivATI, + InitDepthBoundsEXT, + InitBlendEquationSeparateEXT, + InitAddSwapHintRectWIN, +#ifdef _WIN32 + InitCreateBufferRegionARB, + InitDeleteBufferRegionARB, + InitSaveBufferRegionARB, + InitRestoreBufferRegionARB, + InitGetExtensionsStringARB, + InitGetPixelFormatAttribivARB, + InitGetPixelFormatAttribfvARB, + InitChoosePixelFormatARB, + InitMakeContextCurrentARB, + InitGetCurrentReadDCARB, + InitCreatePbufferARB, + InitGetPbufferDCARB, + InitReleasePbufferDCARB, + InitDestroyPbufferARB, + InitQueryPbufferARB, + InitBindTexImageARB, + InitReleaseTexImageARB, + InitSetPbufferAttribARB, + InitCreateDisplayColorTableEXT, + InitLoadDisplayColorTableEXT, + InitBindDisplayColorTableEXT, + InitDestroyDisplayColorTableEXT, + InitGetExtensionsStringEXT, + InitMakeContextCurrentEXT, + InitGetCurrentReadDCEXT, + InitCreatePbufferEXT, + InitGetPbufferDCEXT, + InitReleasePbufferDCEXT, + InitDestroyPbufferEXT, + InitQueryPbufferEXT, + InitGetPixelFormatAttribivEXT, + InitGetPixelFormatAttribfvEXT, + InitChoosePixelFormatEXT, + InitSwapIntervalEXT, + InitGetSwapIntervalEXT, + InitAllocateMemoryNV, + InitFreeMemoryNV, + InitGetSyncValuesOML, + InitGetMscRateOML, + InitSwapBuffersMscOML, + InitSwapLayerBuffersMscOML, + InitWaitForMscOML, + InitWaitForSbcOML, + InitGetDigitalVideoParametersI3D, + InitSetDigitalVideoParametersI3D, + InitGetGammaTableParametersI3D, + InitSetGammaTableParametersI3D, + InitGetGammaTableI3D, + InitSetGammaTableI3D, + InitEnableGenlockI3D, + InitDisableGenlockI3D, + InitIsEnabledGenlockI3D, + InitGenlockSourceI3D, + InitGetGenlockSourceI3D, + InitGenlockSourceEdgeI3D, + InitGetGenlockSourceEdgeI3D, + InitGenlockSampleRateI3D, + InitGetGenlockSampleRateI3D, + InitGenlockSourceDelayI3D, + InitGetGenlockSourceDelayI3D, + InitQueryGenlockMaxSourceDelayI3D, + InitCreateImageBufferI3D, + InitDestroyImageBufferI3D, + InitAssociateImageBufferEventsI3D, + InitReleaseImageBufferEventsI3D, + InitEnableFrameLockI3D, + InitDisableFrameLockI3D, + InitIsEnabledFrameLockI3D, + InitQueryFrameLockMasterI3D, + InitGetFrameUsageI3D, + InitBeginFrameTrackingI3D, + InitEndFrameTrackingI3D, + InitQueryFrameTrackingI3D, +#endif /* _WIN32 */ +}; diff --git a/plugins/gs/zerogs/opengl/glprocs.h b/plugins/gs/zerogs/opengl/glprocs.h new file mode 100644 index 0000000000..c40e5bdc0f --- /dev/null +++ b/plugins/gs/zerogs/opengl/glprocs.h @@ -0,0 +1,2213 @@ +#ifndef _GLPROCS_H_ +#define _GLPROCS_H_ + +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#ifdef _WIN32 + #include + #include +#else + #include +#endif + +#ifndef _WIN32 /* non-Windows environment */ + #ifndef APIENTRY + #define APIENTRY + #endif + #ifdef __GNUC__ + #define _inline __inline__ + #else + #define _inline + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure of all OpenGL {1.2, 1.3, 1.4, 1.5}, GL extension procs.*/ + +typedef struct { + void (APIENTRY *BlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *BlendEquation) (GLenum mode); + void (APIENTRY *DrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ColorTable) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTable) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTable) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *ColorSubTable) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTable) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *ConvolutionFilter1D) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterf) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteri) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilter) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilter) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *GetHistogram) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmax) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *Histogram) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *Minmax) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogram) (GLenum target); + void (APIENTRY *ResetMinmax) (GLenum target); + void (APIENTRY *TexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *ActiveTexture) (GLenum texture); + void (APIENTRY *ClientActiveTexture) (GLenum texture); + void (APIENTRY *MultiTexCoord1d) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1f) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1i) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1s) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2d) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2f) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2i) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2s) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3d) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3f) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3i) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3s) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4d) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4f) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4i) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4s) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4sv) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *SampleCoverage) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImage) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *BlendFuncSeparate) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *FogCoordf) (GLfloat coord); + void (APIENTRY *FogCoordfv) (const GLfloat *coord); + void (APIENTRY *FogCoordd) (GLdouble coord); + void (APIENTRY *FogCoorddv) (const GLdouble *coord); + void (APIENTRY *FogCoordPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *MultiDrawArrays) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElements) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *PointParameterf) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfv) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameteri) (GLenum pname, GLint param); + void (APIENTRY *PointParameteriv) (GLenum pname, const GLint *params); + void (APIENTRY *SecondaryColor3b) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bv) (const GLbyte *v); + void (APIENTRY *SecondaryColor3d) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dv) (const GLdouble *v); + void (APIENTRY *SecondaryColor3f) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fv) (const GLfloat *v); + void (APIENTRY *SecondaryColor3i) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3iv) (const GLint *v); + void (APIENTRY *SecondaryColor3s) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3sv) (const GLshort *v); + void (APIENTRY *SecondaryColor3ub) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubv) (const GLubyte *v); + void (APIENTRY *SecondaryColor3ui) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uiv) (const GLuint *v); + void (APIENTRY *SecondaryColor3us) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usv) (const GLushort *v); + void (APIENTRY *SecondaryColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2d) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dv) (const GLdouble *v); + void (APIENTRY *WindowPos2f) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fv) (const GLfloat *v); + void (APIENTRY *WindowPos2i) (GLint x, GLint y); + void (APIENTRY *WindowPos2iv) (const GLint *v); + void (APIENTRY *WindowPos2s) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2sv) (const GLshort *v); + void (APIENTRY *WindowPos3d) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dv) (const GLdouble *v); + void (APIENTRY *WindowPos3f) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fv) (const GLfloat *v); + void (APIENTRY *WindowPos3i) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3iv) (const GLint *v); + void (APIENTRY *WindowPos3s) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3sv) (const GLshort *v); + void (APIENTRY *GenQueries) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueries) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQuery) (GLuint id); + void (APIENTRY *BeginQuery) (GLenum target, GLuint id); + void (APIENTRY *EndQuery) (GLenum target); + void (APIENTRY *GetQueryiv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectiv) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuiv) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *BindBuffer) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffers) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffers) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBuffer) (GLuint buffer); + void (APIENTRY *BufferData) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); + void (APIENTRY *GetBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); + GLvoid* (APIENTRY *MapBuffer) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBuffer) (GLenum target); + void (APIENTRY *GetBufferParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointerv) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *ActiveTextureARB) (GLenum texture); + void (APIENTRY *ClientActiveTextureARB) (GLenum texture); + void (APIENTRY *MultiTexCoord1dARB) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1fARB) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1iARB) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1sARB) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2dARB) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2iARB) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2sARB) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3iARB) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3sARB) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4iARB) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4sARB) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4svARB) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *SampleCoverageARB) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1DARB) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImageARB) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *PointParameterfARB) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvARB) (GLenum pname, const GLfloat *params); + void (APIENTRY *WeightbvARB) (GLint size, const GLbyte *weights); + void (APIENTRY *WeightsvARB) (GLint size, const GLshort *weights); + void (APIENTRY *WeightivARB) (GLint size, const GLint *weights); + void (APIENTRY *WeightfvARB) (GLint size, const GLfloat *weights); + void (APIENTRY *WeightdvARB) (GLint size, const GLdouble *weights); + void (APIENTRY *WeightubvARB) (GLint size, const GLubyte *weights); + void (APIENTRY *WeightusvARB) (GLint size, const GLushort *weights); + void (APIENTRY *WeightuivARB) (GLint size, const GLuint *weights); + void (APIENTRY *WeightPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexBlendARB) (GLint count); + void (APIENTRY *CurrentPaletteMatrixARB) (GLint index); + void (APIENTRY *MatrixIndexubvARB) (GLint size, const GLubyte *indices); + void (APIENTRY *MatrixIndexusvARB) (GLint size, const GLushort *indices); + void (APIENTRY *MatrixIndexuivARB) (GLint size, const GLuint *indices); + void (APIENTRY *MatrixIndexPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2dARB) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos2fARB) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos2iARB) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivARB) (const GLint *v); + void (APIENTRY *WindowPos2sARB) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svARB) (const GLshort *v); + void (APIENTRY *WindowPos3dARB) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos3fARB) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos3iARB) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivARB) (const GLint *v); + void (APIENTRY *WindowPos3sARB) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svARB) (const GLshort *v); + void (APIENTRY *VertexAttrib1dARB) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fARB) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sARB) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dARB) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fARB) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sARB) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sARB) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NbvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4NivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4NsvARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NubARB) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4NubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4NuivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4NusvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttrib4bvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4ivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4sARB) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4uivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4usvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *EnableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *DisableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *ProgramStringARB) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); + void (APIENTRY *BindProgramARB) (GLenum target, GLuint program); + void (APIENTRY *DeleteProgramsARB) (GLsizei n, const GLuint *programs); + void (APIENTRY *GenProgramsARB) (GLsizei n, GLuint *programs); + void (APIENTRY *ProgramEnvParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramEnvParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramEnvParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramEnvParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *ProgramLocalParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramLocalParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramLocalParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramLocalParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *GetProgramEnvParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramEnvParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramLocalParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramLocalParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringARB) (GLenum target, GLenum pname, GLvoid *string); + void (APIENTRY *GetVertexAttribdvARB) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvARB) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivARB) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervARB) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramARB) (GLuint program); + void (APIENTRY *BindBufferARB) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffersARB) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffersARB) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBufferARB) (GLuint buffer); + void (APIENTRY *BufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + void (APIENTRY *GetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); + GLvoid* (APIENTRY *MapBufferARB) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBufferARB) (GLenum target); + void (APIENTRY *GetBufferParameterivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointervARB) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *GenQueriesARB) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueriesARB) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQueryARB) (GLuint id); + void (APIENTRY *BeginQueryARB) (GLenum target, GLuint id); + void (APIENTRY *EndQueryARB) (GLenum target); + void (APIENTRY *GetQueryivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *DeleteObjectARB) (GLhandleARB obj); + GLhandleARB (APIENTRY *GetHandleARB) (GLenum pname); + void (APIENTRY *DetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); + GLhandleARB (APIENTRY *CreateShaderObjectARB) (GLenum shaderType); + void (APIENTRY *ShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); + void (APIENTRY *CompileShaderARB) (GLhandleARB shaderObj); + GLhandleARB (APIENTRY *CreateProgramObjectARB) (void); + void (APIENTRY *AttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); + void (APIENTRY *LinkProgramARB) (GLhandleARB programObj); + void (APIENTRY *UseProgramObjectARB) (GLhandleARB programObj); + void (APIENTRY *ValidateProgramARB) (GLhandleARB programObj); + void (APIENTRY *Uniform1fARB) (GLint location, GLfloat v0); + void (APIENTRY *Uniform2fARB) (GLint location, GLfloat v0, GLfloat v1); + void (APIENTRY *Uniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void (APIENTRY *Uniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + void (APIENTRY *Uniform1iARB) (GLint location, GLint v0); + void (APIENTRY *Uniform2iARB) (GLint location, GLint v0, GLint v1); + void (APIENTRY *Uniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); + void (APIENTRY *Uniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void (APIENTRY *Uniform1fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform2fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform3fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform4fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform1ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform2ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform3ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform4ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *UniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *GetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint *params); + void (APIENTRY *GetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); + void (APIENTRY *GetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); + GLint (APIENTRY *GetUniformLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *GetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + void (APIENTRY *GetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat *params); + void (APIENTRY *GetUniformivARB) (GLhandleARB programObj, GLint location, GLint *params); + void (APIENTRY *GetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); + void (APIENTRY *BindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB *name); + void (APIENTRY *GetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + GLint (APIENTRY *GetAttribLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *BlendColorEXT) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *PolygonOffsetEXT) (GLfloat factor, GLfloat bias); + void (APIENTRY *TexImage3DEXT) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *GetTexFilterFuncSGIS) (GLenum target, GLenum filter, GLfloat *weights); + void (APIENTRY *TexFilterFuncSGIS) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); + void (APIENTRY *TexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexImage1DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); + void (APIENTRY *CopyTexImage2DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY *CopyTexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyTexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *CopyTexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetHistogramEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmaxEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *HistogramEXT) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *MinmaxEXT) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogramEXT) (GLenum target); + void (APIENTRY *ResetMinmaxEXT) (GLenum target); + void (APIENTRY *ConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterfEXT) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteriEXT) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *ColorTableSGI) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfvSGI) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameterivSGI) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTableSGI) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTableSGI) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfvSGI) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameterivSGI) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *PixelTexGenSGIX) (GLenum mode); + void (APIENTRY *PixelTexGenParameteriSGIS) (GLenum pname, GLint param); + void (APIENTRY *PixelTexGenParameterivSGIS) (GLenum pname, const GLint *params); + void (APIENTRY *PixelTexGenParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PixelTexGenParameterfvSGIS) (GLenum pname, const GLfloat *params); + void (APIENTRY *GetPixelTexGenParameterivSGIS) (GLenum pname, GLint *params); + void (APIENTRY *GetPixelTexGenParameterfvSGIS) (GLenum pname, GLfloat *params); + void (APIENTRY *TexImage4DSGIS) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage4DSGIS) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); + GLboolean (APIENTRY *AreTexturesResidentEXT) (GLsizei n, const GLuint *textures, GLboolean *residences); + void (APIENTRY *BindTextureEXT) (GLenum target, GLuint texture); + void (APIENTRY *DeleteTexturesEXT) (GLsizei n, const GLuint *textures); + void (APIENTRY *GenTexturesEXT) (GLsizei n, GLuint *textures); + GLboolean (APIENTRY *IsTextureEXT) (GLuint texture); + void (APIENTRY *PrioritizeTexturesEXT) (GLsizei n, const GLuint *textures, const GLclampf *priorities); + void (APIENTRY *DetailTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetDetailTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SharpenTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetSharpenTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SampleMaskSGIS) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternSGIS) (GLenum pattern); + void (APIENTRY *ArrayElementEXT) (GLint i); + void (APIENTRY *ColorPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *DrawArraysEXT) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *EdgeFlagPointerEXT) (GLsizei stride, GLsizei count, const GLboolean *pointer); + void (APIENTRY *GetPointervEXT) (GLenum pname, GLvoid* *params); + void (APIENTRY *IndexPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *NormalPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *TexCoordPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *VertexPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *BlendEquationEXT) (GLenum mode); + void (APIENTRY *SpriteParameterfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *SpriteParameterfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *SpriteParameteriSGIX) (GLenum pname, GLint param); + void (APIENTRY *SpriteParameterivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *PointParameterfEXT) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvEXT) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvSGIS) (GLenum pname, const GLfloat *params); + GLint (APIENTRY *GetInstrumentsSGIX) (void); + void (APIENTRY *InstrumentsBufferSGIX) (GLsizei size, GLint *buffer); + GLint (APIENTRY *PollInstrumentsSGIX) (GLint *marker_p); + void (APIENTRY *ReadInstrumentsSGIX) (GLint marker); + void (APIENTRY *StartInstrumentsSGIX) (void); + void (APIENTRY *StopInstrumentsSGIX) (GLint marker); + void (APIENTRY *FrameZoomSGIX) (GLint factor); + void (APIENTRY *TagSampleBufferSGIX) (void); + void (APIENTRY *DeformationMap3dSGIX) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); + void (APIENTRY *DeformationMap3fSGIX) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); + void (APIENTRY *DeformSGIX) (GLbitfield mask); + void (APIENTRY *LoadIdentityDeformationMapSGIX) (GLbitfield mask); + void (APIENTRY *ReferencePlaneSGIX) (const GLdouble *equation); + void (APIENTRY *FlushRasterSGIX) (void); + void (APIENTRY *FogFuncSGIS) (GLsizei n, const GLfloat *points); + void (APIENTRY *GetFogFuncSGIS) (GLfloat *points); + void (APIENTRY *ImageTransformParameteriHP) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *ImageTransformParameterfHP) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *ImageTransformParameterivHP) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *ImageTransformParameterfvHP) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetImageTransformParameterivHP) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetImageTransformParameterfvHP) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *ColorSubTableEXT) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTableEXT) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *HintPGI) (GLenum target, GLint mode); + void (APIENTRY *ColorTableEXT) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *GetColorTableEXT) (GLenum target, GLenum format, GLenum type, GLvoid *data); + void (APIENTRY *GetColorTableParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetColorTableParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterfvSGIX) (GLuint list, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterivSGIX) (GLuint list, GLenum pname, GLint *params); + void (APIENTRY *ListParameterfSGIX) (GLuint list, GLenum pname, GLfloat param); + void (APIENTRY *ListParameterfvSGIX) (GLuint list, GLenum pname, const GLfloat *params); + void (APIENTRY *ListParameteriSGIX) (GLuint list, GLenum pname, GLint param); + void (APIENTRY *ListParameterivSGIX) (GLuint list, GLenum pname, const GLint *params); + void (APIENTRY *IndexMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *IndexFuncEXT) (GLenum func, GLclampf ref); + void (APIENTRY *LockArraysEXT) (GLint first, GLsizei count); + void (APIENTRY *UnlockArraysEXT) (void); + void (APIENTRY *CullParameterdvEXT) (GLenum pname, GLdouble *params); + void (APIENTRY *CullParameterfvEXT) (GLenum pname, GLfloat *params); + void (APIENTRY *FragmentColorMaterialSGIX) (GLenum face, GLenum mode); + void (APIENTRY *FragmentLightfSGIX) (GLenum light, GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightfvSGIX) (GLenum light, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightiSGIX) (GLenum light, GLenum pname, GLint param); + void (APIENTRY *FragmentLightivSGIX) (GLenum light, GLenum pname, const GLint *params); + void (APIENTRY *FragmentLightModelfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightModelfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightModeliSGIX) (GLenum pname, GLint param); + void (APIENTRY *FragmentLightModelivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *FragmentMaterialfSGIX) (GLenum face, GLenum pname, GLfloat param); + void (APIENTRY *FragmentMaterialfvSGIX) (GLenum face, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentMaterialiSGIX) (GLenum face, GLenum pname, GLint param); + void (APIENTRY *FragmentMaterialivSGIX) (GLenum face, GLenum pname, const GLint *params); + void (APIENTRY *GetFragmentLightfvSGIX) (GLenum light, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentLightivSGIX) (GLenum light, GLenum pname, GLint *params); + void (APIENTRY *GetFragmentMaterialfvSGIX) (GLenum face, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentMaterialivSGIX) (GLenum face, GLenum pname, GLint *params); + void (APIENTRY *LightEnviSGIX) (GLenum pname, GLint param); + void (APIENTRY *DrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ApplyTextureEXT) (GLenum mode); + void (APIENTRY *TextureLightEXT) (GLenum pname); + void (APIENTRY *TextureMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *AsyncMarkerSGIX) (GLuint marker); + GLint (APIENTRY *FinishAsyncSGIX) (GLuint *markerp); + GLint (APIENTRY *PollAsyncSGIX) (GLuint *markerp); + GLuint (APIENTRY *GenAsyncMarkersSGIX) (GLsizei range); + void (APIENTRY *DeleteAsyncMarkersSGIX) (GLuint marker, GLsizei range); + GLboolean (APIENTRY *IsAsyncMarkerSGIX) (GLuint marker); + void (APIENTRY *VertexPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *NormalPointervINTEL) (GLenum type, const GLvoid* *pointer); + void (APIENTRY *ColorPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *TexCoordPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *PixelTransformParameteriEXT) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *PixelTransformParameterfEXT) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *PixelTransformParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *PixelTransformParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *SecondaryColor3bEXT) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bvEXT) (const GLbyte *v); + void (APIENTRY *SecondaryColor3dEXT) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dvEXT) (const GLdouble *v); + void (APIENTRY *SecondaryColor3fEXT) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fvEXT) (const GLfloat *v); + void (APIENTRY *SecondaryColor3iEXT) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3ivEXT) (const GLint *v); + void (APIENTRY *SecondaryColor3sEXT) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3svEXT) (const GLshort *v); + void (APIENTRY *SecondaryColor3ubEXT) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubvEXT) (const GLubyte *v); + void (APIENTRY *SecondaryColor3uiEXT) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uivEXT) (const GLuint *v); + void (APIENTRY *SecondaryColor3usEXT) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usvEXT) (const GLushort *v); + void (APIENTRY *SecondaryColorPointerEXT) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *TextureNormalEXT) (GLenum mode); + void (APIENTRY *MultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *FogCoordfEXT) (GLfloat coord); + void (APIENTRY *FogCoordfvEXT) (const GLfloat *coord); + void (APIENTRY *FogCoorddEXT) (GLdouble coord); + void (APIENTRY *FogCoorddvEXT) (const GLdouble *coord); + void (APIENTRY *FogCoordPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *Tangent3bEXT) (GLbyte tx, GLbyte ty, GLbyte tz); + void (APIENTRY *Tangent3bvEXT) (const GLbyte *v); + void (APIENTRY *Tangent3dEXT) (GLdouble tx, GLdouble ty, GLdouble tz); + void (APIENTRY *Tangent3dvEXT) (const GLdouble *v); + void (APIENTRY *Tangent3fEXT) (GLfloat tx, GLfloat ty, GLfloat tz); + void (APIENTRY *Tangent3fvEXT) (const GLfloat *v); + void (APIENTRY *Tangent3iEXT) (GLint tx, GLint ty, GLint tz); + void (APIENTRY *Tangent3ivEXT) (const GLint *v); + void (APIENTRY *Tangent3sEXT) (GLshort tx, GLshort ty, GLshort tz); + void (APIENTRY *Tangent3svEXT) (const GLshort *v); + void (APIENTRY *Binormal3bEXT) (GLbyte bx, GLbyte by, GLbyte bz); + void (APIENTRY *Binormal3bvEXT) (const GLbyte *v); + void (APIENTRY *Binormal3dEXT) (GLdouble bx, GLdouble by, GLdouble bz); + void (APIENTRY *Binormal3dvEXT) (const GLdouble *v); + void (APIENTRY *Binormal3fEXT) (GLfloat bx, GLfloat by, GLfloat bz); + void (APIENTRY *Binormal3fvEXT) (const GLfloat *v); + void (APIENTRY *Binormal3iEXT) (GLint bx, GLint by, GLint bz); + void (APIENTRY *Binormal3ivEXT) (const GLint *v); + void (APIENTRY *Binormal3sEXT) (GLshort bx, GLshort by, GLshort bz); + void (APIENTRY *Binormal3svEXT) (const GLshort *v); + void (APIENTRY *TangentPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *BinormalPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FinishTextureSUNX) (void); + void (APIENTRY *GlobalAlphaFactorbSUN) (GLbyte factor); + void (APIENTRY *GlobalAlphaFactorsSUN) (GLshort factor); + void (APIENTRY *GlobalAlphaFactoriSUN) (GLint factor); + void (APIENTRY *GlobalAlphaFactorfSUN) (GLfloat factor); + void (APIENTRY *GlobalAlphaFactordSUN) (GLdouble factor); + void (APIENTRY *GlobalAlphaFactorubSUN) (GLubyte factor); + void (APIENTRY *GlobalAlphaFactorusSUN) (GLushort factor); + void (APIENTRY *GlobalAlphaFactoruiSUN) (GLuint factor); + void (APIENTRY *ReplacementCodeuiSUN) (GLuint code); + void (APIENTRY *ReplacementCodeusSUN) (GLushort code); + void (APIENTRY *ReplacementCodeubSUN) (GLubyte code); + void (APIENTRY *ReplacementCodeuivSUN) (const GLuint *code); + void (APIENTRY *ReplacementCodeusvSUN) (const GLushort *code); + void (APIENTRY *ReplacementCodeubvSUN) (const GLubyte *code); + void (APIENTRY *ReplacementCodePointerSUN) (GLenum type, GLsizei stride, const GLvoid* *pointer); + void (APIENTRY *Color4ubVertex2fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); + void (APIENTRY *Color4ubVertex2fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color4ubVertex3fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4ubVertex3fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color3fVertex3fvSUN) (const GLfloat *c, const GLfloat *v); + void (APIENTRY *Normal3fVertex3fSUN) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Normal3fVertex3fvSUN) (const GLfloat *n, const GLfloat *v); + void (APIENTRY *Color4fNormal3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4fNormal3fVertex3fvSUN) (const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fVertex3fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord4fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *TexCoord4fVertex4fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4ubVertex3fSUN) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4ubVertex3fvSUN) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *TexCoord2fColor3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *TexCoord2fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiVertex3fSUN) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiVertex3fvSUN) (const GLuint *rc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fSUN) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fvSUN) (const GLuint *rc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fSUN) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *BlendFuncSeparateEXT) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *BlendFuncSeparateINGR) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *VertexWeightfEXT) (GLfloat weight); + void (APIENTRY *VertexWeightfvEXT) (const GLfloat *weight); + void (APIENTRY *VertexWeightPointerEXT) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeNV) (void); + void (APIENTRY *VertexArrayRangeNV) (GLsizei length, const GLvoid *pointer); + void (APIENTRY *CombinerParameterfvNV) (GLenum pname, const GLfloat *params); + void (APIENTRY *CombinerParameterfNV) (GLenum pname, GLfloat param); + void (APIENTRY *CombinerParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *CombinerParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *CombinerInputNV) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *CombinerOutputNV) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); + void (APIENTRY *FinalCombinerInputNV) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *GetCombinerInputParameterfvNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerInputParameterivNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *GetCombinerOutputParameterfvNV) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerOutputParameterivNV) (GLenum stage, GLenum portion, GLenum pname, GLint *params); + void (APIENTRY *GetFinalCombinerInputParameterfvNV) (GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetFinalCombinerInputParameterivNV) (GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *ResizeBuffersMESA) (void); + void (APIENTRY *WindowPos2dMESA) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos2fMESA) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos2iMESA) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivMESA) (const GLint *v); + void (APIENTRY *WindowPos2sMESA) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svMESA) (const GLshort *v); + void (APIENTRY *WindowPos3dMESA) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos3fMESA) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos3iMESA) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivMESA) (const GLint *v); + void (APIENTRY *WindowPos3sMESA) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svMESA) (const GLshort *v); + void (APIENTRY *WindowPos4dMESA) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *WindowPos4dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos4fMESA) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *WindowPos4fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos4iMESA) (GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *WindowPos4ivMESA) (const GLint *v); + void (APIENTRY *WindowPos4sMESA) (GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *WindowPos4svMESA) (const GLshort *v); + void (APIENTRY *MultiModeDrawArraysIBM) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); + void (APIENTRY *MultiModeDrawElementsIBM) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); + void (APIENTRY *ColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *SecondaryColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *EdgeFlagPointerListIBM) (GLint stride, const GLboolean* *pointer, GLint ptrstride); + void (APIENTRY *FogCoordPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *IndexPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *NormalPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TexCoordPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *VertexPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TbufferMask3DFX) (GLuint mask); + void (APIENTRY *SampleMaskEXT) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternEXT) (GLenum pattern); + void (APIENTRY *TextureColorMaskSGIS) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY *IglooInterfaceSGIX) (GLenum pname, const GLvoid *params); + void (APIENTRY *DeleteFencesNV) (GLsizei n, const GLuint *fences); + void (APIENTRY *GenFencesNV) (GLsizei n, GLuint *fences); + GLboolean (APIENTRY *IsFenceNV) (GLuint fence); + GLboolean (APIENTRY *TestFenceNV) (GLuint fence); + void (APIENTRY *GetFenceivNV) (GLuint fence, GLenum pname, GLint *params); + void (APIENTRY *FinishFenceNV) (GLuint fence); + void (APIENTRY *SetFenceNV) (GLuint fence, GLenum condition); + void (APIENTRY *MapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); + void (APIENTRY *MapParameterivNV) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *MapParameterfvNV) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetMapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); + void (APIENTRY *GetMapParameterivNV) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMapParameterfvNV) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMapAttribParameterivNV) (GLenum target, GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetMapAttribParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *EvalMapsNV) (GLenum target, GLenum mode); + void (APIENTRY *CombinerStageParameterfvNV) (GLenum stage, GLenum pname, const GLfloat *params); + void (APIENTRY *GetCombinerStageParameterfvNV) (GLenum stage, GLenum pname, GLfloat *params); + GLboolean (APIENTRY *AreProgramsResidentNV) (GLsizei n, const GLuint *programs, GLboolean *residences); + void (APIENTRY *BindProgramNV) (GLenum target, GLuint id); + void (APIENTRY *DeleteProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *ExecuteProgramNV) (GLenum target, GLuint id, const GLfloat *params); + void (APIENTRY *GenProgramsNV) (GLsizei n, GLuint *programs); + void (APIENTRY *GetProgramParameterdvNV) (GLenum target, GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetProgramParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetProgramivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringNV) (GLuint id, GLenum pname, GLubyte *program); + void (APIENTRY *GetTrackMatrixivNV) (GLenum target, GLuint address, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribdvNV) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvNV) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivNV) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervNV) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramNV) (GLuint id); + void (APIENTRY *LoadProgramNV) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); + void (APIENTRY *ProgramParameter4dNV) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramParameter4dvNV) (GLenum target, GLuint index, const GLdouble *v); + void (APIENTRY *ProgramParameter4fNV) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramParameter4fvNV) (GLenum target, GLuint index, const GLfloat *v); + void (APIENTRY *ProgramParameters4dvNV) (GLenum target, GLuint index, GLuint count, const GLdouble *v); + void (APIENTRY *ProgramParameters4fvNV) (GLenum target, GLuint index, GLuint count, const GLfloat *v); + void (APIENTRY *RequestResidentProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *TrackMatrixNV) (GLenum target, GLuint address, GLenum matrix, GLenum transform); + void (APIENTRY *VertexAttribPointerNV) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexAttrib1dNV) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fNV) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sNV) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dNV) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fNV) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sNV) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sNV) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4sNV) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubNV) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4ubvNV) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttribs1dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs1fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs1svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs2dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs2fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs2svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs3dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs3fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs3svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs4fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs4svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4ubvNV) (GLuint index, GLsizei count, const GLubyte *v); + void (APIENTRY *TexBumpParameterivATI) (GLenum pname, const GLint *param); + void (APIENTRY *TexBumpParameterfvATI) (GLenum pname, const GLfloat *param); + void (APIENTRY *GetTexBumpParameterivATI) (GLenum pname, GLint *param); + void (APIENTRY *GetTexBumpParameterfvATI) (GLenum pname, GLfloat *param); + GLuint (APIENTRY *GenFragmentShadersATI) (GLuint range); + void (APIENTRY *BindFragmentShaderATI) (GLuint id); + void (APIENTRY *DeleteFragmentShaderATI) (GLuint id); + void (APIENTRY *BeginFragmentShaderATI) (void); + void (APIENTRY *EndFragmentShaderATI) (void); + void (APIENTRY *PassTexCoordATI) (GLuint dst, GLuint coord, GLenum swizzle); + void (APIENTRY *SampleMapATI) (GLuint dst, GLuint interp, GLenum swizzle); + void (APIENTRY *ColorFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *ColorFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *ColorFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); + void (APIENTRY *AlphaFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *AlphaFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *AlphaFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); + void (APIENTRY *SetFragmentShaderConstantATI) (GLuint dst, const GLfloat *value); + void (APIENTRY *PNTrianglesiATI) (GLenum pname, GLint param); + void (APIENTRY *PNTrianglesfATI) (GLenum pname, GLfloat param); + GLuint (APIENTRY *NewObjectBufferATI) (GLsizei size, const GLvoid *pointer, GLenum usage); + GLboolean (APIENTRY *IsObjectBufferATI) (GLuint buffer); + void (APIENTRY *UpdateObjectBufferATI) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); + void (APIENTRY *GetObjectBufferfvATI) (GLuint buffer, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectBufferivATI) (GLuint buffer, GLenum pname, GLint *params); + void (APIENTRY *FreeObjectBufferATI) (GLuint buffer); + void (APIENTRY *ArrayObjectATI) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetArrayObjectfvATI) (GLenum array, GLenum pname, GLfloat *params); + void (APIENTRY *GetArrayObjectivATI) (GLenum array, GLenum pname, GLint *params); + void (APIENTRY *VariantArrayObjectATI) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVariantArrayObjectfvATI) (GLuint id, GLenum pname, GLfloat *params); + void (APIENTRY *GetVariantArrayObjectivATI) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *BeginVertexShaderEXT) (void); + void (APIENTRY *EndVertexShaderEXT) (void); + void (APIENTRY *BindVertexShaderEXT) (GLuint id); + GLuint (APIENTRY *GenVertexShadersEXT) (GLuint range); + void (APIENTRY *DeleteVertexShaderEXT) (GLuint id); + void (APIENTRY *ShaderOp1EXT) (GLenum op, GLuint res, GLuint arg1); + void (APIENTRY *ShaderOp2EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); + void (APIENTRY *ShaderOp3EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); + void (APIENTRY *SwizzleEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *WriteMaskEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *InsertComponentEXT) (GLuint res, GLuint src, GLuint num); + void (APIENTRY *ExtractComponentEXT) (GLuint res, GLuint src, GLuint num); + GLuint (APIENTRY *GenSymbolsEXT) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); + void (APIENTRY *SetInvariantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *SetLocalConstantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *VariantbvEXT) (GLuint id, const GLbyte *addr); + void (APIENTRY *VariantsvEXT) (GLuint id, const GLshort *addr); + void (APIENTRY *VariantivEXT) (GLuint id, const GLint *addr); + void (APIENTRY *VariantfvEXT) (GLuint id, const GLfloat *addr); + void (APIENTRY *VariantdvEXT) (GLuint id, const GLdouble *addr); + void (APIENTRY *VariantubvEXT) (GLuint id, const GLubyte *addr); + void (APIENTRY *VariantusvEXT) (GLuint id, const GLushort *addr); + void (APIENTRY *VariantuivEXT) (GLuint id, const GLuint *addr); + void (APIENTRY *VariantPointerEXT) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); + void (APIENTRY *EnableVariantClientStateEXT) (GLuint id); + void (APIENTRY *DisableVariantClientStateEXT) (GLuint id); + GLuint (APIENTRY *BindLightParameterEXT) (GLenum light, GLenum value); + GLuint (APIENTRY *BindMaterialParameterEXT) (GLenum face, GLenum value); + GLuint (APIENTRY *BindTexGenParameterEXT) (GLenum unit, GLenum coord, GLenum value); + GLuint (APIENTRY *BindTextureUnitParameterEXT) (GLenum unit, GLenum value); + GLuint (APIENTRY *BindParameterEXT) (GLenum value); + GLboolean (APIENTRY *IsVariantEnabledEXT) (GLuint id, GLenum cap); + void (APIENTRY *GetVariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetVariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetVariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetVariantPointervEXT) (GLuint id, GLenum value, GLvoid* *data); + void (APIENTRY *GetInvariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetInvariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetInvariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetLocalConstantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetLocalConstantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetLocalConstantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *VertexStream1sATI) (GLenum stream, GLshort x); + void (APIENTRY *VertexStream1svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream1iATI) (GLenum stream, GLint x); + void (APIENTRY *VertexStream1ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream1fATI) (GLenum stream, GLfloat x); + void (APIENTRY *VertexStream1fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream1dATI) (GLenum stream, GLdouble x); + void (APIENTRY *VertexStream1dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream2sATI) (GLenum stream, GLshort x, GLshort y); + void (APIENTRY *VertexStream2svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream2iATI) (GLenum stream, GLint x, GLint y); + void (APIENTRY *VertexStream2ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream2fATI) (GLenum stream, GLfloat x, GLfloat y); + void (APIENTRY *VertexStream2fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream2dATI) (GLenum stream, GLdouble x, GLdouble y); + void (APIENTRY *VertexStream2dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream3sATI) (GLenum stream, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream3iATI) (GLenum stream, GLint x, GLint y, GLint z); + void (APIENTRY *VertexStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream3fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream3dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream4sATI) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexStream4svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream4iATI) (GLenum stream, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *VertexStream4ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream4fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexStream4fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream4dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexStream4dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *NormalStream3bATI) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); + void (APIENTRY *NormalStream3bvATI) (GLenum stream, const GLbyte *coords); + void (APIENTRY *NormalStream3sATI) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); + void (APIENTRY *NormalStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *NormalStream3iATI) (GLenum stream, GLint nx, GLint ny, GLint nz); + void (APIENTRY *NormalStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *NormalStream3fATI) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); + void (APIENTRY *NormalStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *NormalStream3dATI) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); + void (APIENTRY *NormalStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *ClientActiveVertexStreamATI) (GLenum stream); + void (APIENTRY *VertexBlendEnviATI) (GLenum pname, GLint param); + void (APIENTRY *VertexBlendEnvfATI) (GLenum pname, GLfloat param); + void (APIENTRY *ElementPointerATI) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayATI) (GLenum mode, GLsizei count); + void (APIENTRY *DrawRangeElementArrayATI) (GLenum mode, GLuint start, GLuint end, GLsizei count); + void (APIENTRY *DrawMeshArraysSUN) (GLenum mode, GLint first, GLsizei count, GLsizei width); + void (APIENTRY *GenOcclusionQueriesNV) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteOcclusionQueriesNV) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsOcclusionQueryNV) (GLuint id); + void (APIENTRY *BeginOcclusionQueryNV) (GLuint id); + void (APIENTRY *EndOcclusionQueryNV) (void); + void (APIENTRY *GetOcclusionQueryivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetOcclusionQueryuivNV) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *PointParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *PointParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *ActiveStencilFaceEXT) (GLenum face); + void (APIENTRY *ElementPointerAPPLE) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayAPPLE) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *DrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); + void (APIENTRY *MultiDrawElementArrayAPPLE) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *GenFencesAPPLE) (GLsizei n, GLuint *fences); + void (APIENTRY *DeleteFencesAPPLE) (GLsizei n, const GLuint *fences); + void (APIENTRY *SetFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *IsFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestFenceAPPLE) (GLuint fence); + void (APIENTRY *FinishFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestObjectAPPLE) (GLenum object, GLuint name); + void (APIENTRY *FinishObjectAPPLE) (GLenum object, GLint name); + void (APIENTRY *BindVertexArrayAPPLE) (GLuint array); + void (APIENTRY *DeleteVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + void (APIENTRY *GenVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + GLboolean (APIENTRY *IsVertexArrayAPPLE) (GLuint array); + void (APIENTRY *VertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *VertexArrayParameteriAPPLE) (GLenum pname, GLint param); + void (APIENTRY *DrawBuffersATI) (GLsizei n, const GLenum *bufs); + void (APIENTRY *ProgramNamedParameter4fNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramNamedParameter4dNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramNamedParameter4fvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); + void (APIENTRY *ProgramNamedParameter4dvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); + void (APIENTRY *GetProgramNamedParameterfvNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); + void (APIENTRY *GetProgramNamedParameterdvNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); + void (APIENTRY *Vertex2hNV) (GLhalfNV x, GLhalfNV y); + void (APIENTRY *Vertex2hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex3hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *Vertex3hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex4hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *Vertex4hvNV) (const GLhalfNV *v); + void (APIENTRY *Normal3hNV) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); + void (APIENTRY *Normal3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *Color3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color4hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); + void (APIENTRY *Color4hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord1hNV) (GLhalfNV s); + void (APIENTRY *TexCoord1hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord2hNV) (GLhalfNV s, GLhalfNV t); + void (APIENTRY *TexCoord2hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord3hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *TexCoord3hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord4hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *TexCoord4hvNV) (const GLhalfNV *v); + void (APIENTRY *MultiTexCoord1hNV) (GLenum target, GLhalfNV s); + void (APIENTRY *MultiTexCoord1hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord2hNV) (GLenum target, GLhalfNV s, GLhalfNV t); + void (APIENTRY *MultiTexCoord2hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord3hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *MultiTexCoord3hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord4hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *MultiTexCoord4hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *FogCoordhNV) (GLhalfNV fog); + void (APIENTRY *FogCoordhvNV) (const GLhalfNV *fog); + void (APIENTRY *SecondaryColor3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *SecondaryColor3hvNV) (const GLhalfNV *v); + void (APIENTRY *VertexWeighthNV) (GLhalfNV weight); + void (APIENTRY *VertexWeighthvNV) (const GLhalfNV *weight); + void (APIENTRY *VertexAttrib1hNV) (GLuint index, GLhalfNV x); + void (APIENTRY *VertexAttrib1hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib2hNV) (GLuint index, GLhalfNV x, GLhalfNV y); + void (APIENTRY *VertexAttrib2hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib3hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *VertexAttrib3hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib4hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *VertexAttrib4hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttribs1hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs2hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs3hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs4hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *PixelDataRangeNV) (GLenum target, GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushPixelDataRangeNV) (GLenum target); + void (APIENTRY *PrimitiveRestartNV) (void); + void (APIENTRY *PrimitiveRestartIndexNV) (GLuint index); + GLvoid* (APIENTRY *MapObjectBufferATI) (GLuint buffer); + void (APIENTRY *UnmapObjectBufferATI) (GLuint buffer); + void (APIENTRY *StencilOpSeparateATI) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); + void (APIENTRY *StencilFuncSeparateATI) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); + void (APIENTRY *VertexAttribArrayObjectATI) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVertexAttribArrayObjectfvATI) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribArrayObjectivATI) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *DepthBoundsEXT) (GLclampd zmin, GLclampd zmax); + void (APIENTRY *BlendEquationSeparateEXT) (GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY *AddSwapHintRectWIN) (GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef _WIN32 + HANDLE (WINAPI *CreateBufferRegionARB) (HDC hDC, int iLayerPlane, UINT uType); + VOID (WINAPI *DeleteBufferRegionARB) (HANDLE hRegion); + BOOL (WINAPI *SaveBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height); + BOOL (WINAPI *RestoreBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); + const int (WINAPI *GetExtensionsStringARB) (HDC hdc); + BOOL (WINAPI *GetPixelFormatAttribivARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatARB) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *MakeContextCurrentARB) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCARB) (void); + HPBUFFERARB (WINAPI *CreatePbufferARB) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCARB) (HPBUFFERARB hPbuffer); + int (WINAPI *ReleasePbufferDCARB) (HPBUFFERARB hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferARB) (HPBUFFERARB hPbuffer); + BOOL (WINAPI *QueryPbufferARB) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *BindTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *ReleaseTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *SetPbufferAttribARB) (HPBUFFERARB hPbuffer, const int *piAttribList); + GLboolean (WINAPI *CreateDisplayColorTableEXT) (GLushort id); + GLboolean (WINAPI *LoadDisplayColorTableEXT) (const GLushort *table, GLuint length); + GLboolean (WINAPI *BindDisplayColorTableEXT) (GLushort id); + VOID (WINAPI *DestroyDisplayColorTableEXT) (GLushort id); + const int (WINAPI *GetExtensionsStringEXT) (void); + BOOL (WINAPI *MakeContextCurrentEXT) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCEXT) (void); + HPBUFFEREXT (WINAPI *CreatePbufferEXT) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCEXT) (HPBUFFEREXT hPbuffer); + int (WINAPI *ReleasePbufferDCEXT) (HPBUFFEREXT hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferEXT) (HPBUFFEREXT hPbuffer); + BOOL (WINAPI *QueryPbufferEXT) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *GetPixelFormatAttribivEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatEXT) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *SwapIntervalEXT) (int interval); + int (WINAPI *GetSwapIntervalEXT) (void); + void* (WINAPI *AllocateMemoryNV) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); + void (WINAPI *FreeMemoryNV) (void); + BOOL (WINAPI *GetSyncValuesOML) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetMscRateOML) (HDC hdc, INT32 *numerator, INT32 *denominator); + INT64 (WINAPI *SwapBuffersMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); + INT64 (WINAPI *SwapLayerBuffersMscOML) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); + BOOL (WINAPI *WaitForMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *WaitForSbcOML) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetGammaTableParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableI3D) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); + BOOL (WINAPI *SetGammaTableI3D) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); + BOOL (WINAPI *EnableGenlockI3D) (HDC hDC); + BOOL (WINAPI *DisableGenlockI3D) (HDC hDC); + BOOL (WINAPI *IsEnabledGenlockI3D) (HDC hDC, BOOL *pFlag); + BOOL (WINAPI *GenlockSourceI3D) (HDC hDC, UINT uSource); + BOOL (WINAPI *GetGenlockSourceI3D) (HDC hDC, UINT *uSource); + BOOL (WINAPI *GenlockSourceEdgeI3D) (HDC hDC, UINT uEdge); + BOOL (WINAPI *GetGenlockSourceEdgeI3D) (HDC hDC, UINT *uEdge); + BOOL (WINAPI *GenlockSampleRateI3D) (HDC hDC, UINT uRate); + BOOL (WINAPI *GetGenlockSampleRateI3D) (HDC hDC, UINT *uRate); + BOOL (WINAPI *GenlockSourceDelayI3D) (HDC hDC, UINT uDelay); + BOOL (WINAPI *GetGenlockSourceDelayI3D) (HDC hDC, UINT *uDelay); + BOOL (WINAPI *QueryGenlockMaxSourceDelayI3D) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); + LPVOID (WINAPI *CreateImageBufferI3D) (HDC hDC, DWORD dwSize, UINT uFlags); + BOOL (WINAPI *DestroyImageBufferI3D) (HDC hDC, LPVOID pAddress); + BOOL (WINAPI *AssociateImageBufferEventsI3D) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); + BOOL (WINAPI *ReleaseImageBufferEventsI3D) (HDC hDC, const LPVOID *pAddress, UINT count); + BOOL (WINAPI *EnableFrameLockI3D) (void); + BOOL (WINAPI *DisableFrameLockI3D) (void); + BOOL (WINAPI *IsEnabledFrameLockI3D) (BOOL *pFlag); + BOOL (WINAPI *QueryFrameLockMasterI3D) (BOOL *pFlag); + BOOL (WINAPI *GetFrameUsageI3D) (float *pUsage); + BOOL (WINAPI *BeginFrameTrackingI3D) (void); + BOOL (WINAPI *EndFrameTrackingI3D) (void); + BOOL (WINAPI *QueryFrameTrackingI3D) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif /* _WIN32 */ +} _GLextensionProcs; + +#define glBlendColor (_GET_TLS_PROCTABLE()->BlendColor) +#define glBlendEquation (_GET_TLS_PROCTABLE()->BlendEquation) +#define glDrawRangeElements (_GET_TLS_PROCTABLE()->DrawRangeElements) +#define glColorTable (_GET_TLS_PROCTABLE()->ColorTable) +#define glColorTableParameterfv (_GET_TLS_PROCTABLE()->ColorTableParameterfv) +#define glColorTableParameteriv (_GET_TLS_PROCTABLE()->ColorTableParameteriv) +#define glCopyColorTable (_GET_TLS_PROCTABLE()->CopyColorTable) +#define glGetColorTable (_GET_TLS_PROCTABLE()->GetColorTable) +#define glGetColorTableParameterfv (_GET_TLS_PROCTABLE()->GetColorTableParameterfv) +#define glGetColorTableParameteriv (_GET_TLS_PROCTABLE()->GetColorTableParameteriv) +#define glColorSubTable (_GET_TLS_PROCTABLE()->ColorSubTable) +#define glCopyColorSubTable (_GET_TLS_PROCTABLE()->CopyColorSubTable) +#define glConvolutionFilter1D (_GET_TLS_PROCTABLE()->ConvolutionFilter1D) +#define glConvolutionFilter2D (_GET_TLS_PROCTABLE()->ConvolutionFilter2D) +#define glConvolutionParameterf (_GET_TLS_PROCTABLE()->ConvolutionParameterf) +#define glConvolutionParameterfv (_GET_TLS_PROCTABLE()->ConvolutionParameterfv) +#define glConvolutionParameteri (_GET_TLS_PROCTABLE()->ConvolutionParameteri) +#define glConvolutionParameteriv (_GET_TLS_PROCTABLE()->ConvolutionParameteriv) +#define glCopyConvolutionFilter1D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1D) +#define glCopyConvolutionFilter2D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2D) +#define glGetConvolutionFilter (_GET_TLS_PROCTABLE()->GetConvolutionFilter) +#define glGetConvolutionParameterfv (_GET_TLS_PROCTABLE()->GetConvolutionParameterfv) +#define glGetConvolutionParameteriv (_GET_TLS_PROCTABLE()->GetConvolutionParameteriv) +#define glGetSeparableFilter (_GET_TLS_PROCTABLE()->GetSeparableFilter) +#define glSeparableFilter2D (_GET_TLS_PROCTABLE()->SeparableFilter2D) +#define glGetHistogram (_GET_TLS_PROCTABLE()->GetHistogram) +#define glGetHistogramParameterfv (_GET_TLS_PROCTABLE()->GetHistogramParameterfv) +#define glGetHistogramParameteriv (_GET_TLS_PROCTABLE()->GetHistogramParameteriv) +#define glGetMinmax (_GET_TLS_PROCTABLE()->GetMinmax) +#define glGetMinmaxParameterfv (_GET_TLS_PROCTABLE()->GetMinmaxParameterfv) +#define glGetMinmaxParameteriv (_GET_TLS_PROCTABLE()->GetMinmaxParameteriv) +#define glHistogram (_GET_TLS_PROCTABLE()->Histogram) +#define glMinmax (_GET_TLS_PROCTABLE()->Minmax) +#define glResetHistogram (_GET_TLS_PROCTABLE()->ResetHistogram) +#define glResetMinmax (_GET_TLS_PROCTABLE()->ResetMinmax) +#define glTexImage3D (_GET_TLS_PROCTABLE()->TexImage3D) +#define glTexSubImage3D (_GET_TLS_PROCTABLE()->TexSubImage3D) +#define glCopyTexSubImage3D (_GET_TLS_PROCTABLE()->CopyTexSubImage3D) +#define glActiveTexture (_GET_TLS_PROCTABLE()->ActiveTexture) +#define glClientActiveTexture (_GET_TLS_PROCTABLE()->ClientActiveTexture) +#define glMultiTexCoord1d (_GET_TLS_PROCTABLE()->MultiTexCoord1d) +#define glMultiTexCoord1dv (_GET_TLS_PROCTABLE()->MultiTexCoord1dv) +#define glMultiTexCoord1f (_GET_TLS_PROCTABLE()->MultiTexCoord1f) +#define glMultiTexCoord1fv (_GET_TLS_PROCTABLE()->MultiTexCoord1fv) +#define glMultiTexCoord1i (_GET_TLS_PROCTABLE()->MultiTexCoord1i) +#define glMultiTexCoord1iv (_GET_TLS_PROCTABLE()->MultiTexCoord1iv) +#define glMultiTexCoord1s (_GET_TLS_PROCTABLE()->MultiTexCoord1s) +#define glMultiTexCoord1sv (_GET_TLS_PROCTABLE()->MultiTexCoord1sv) +#define glMultiTexCoord2d (_GET_TLS_PROCTABLE()->MultiTexCoord2d) +#define glMultiTexCoord2dv (_GET_TLS_PROCTABLE()->MultiTexCoord2dv) +#define glMultiTexCoord2f (_GET_TLS_PROCTABLE()->MultiTexCoord2f) +#define glMultiTexCoord2fv (_GET_TLS_PROCTABLE()->MultiTexCoord2fv) +#define glMultiTexCoord2i (_GET_TLS_PROCTABLE()->MultiTexCoord2i) +#define glMultiTexCoord2iv (_GET_TLS_PROCTABLE()->MultiTexCoord2iv) +#define glMultiTexCoord2s (_GET_TLS_PROCTABLE()->MultiTexCoord2s) +#define glMultiTexCoord2sv (_GET_TLS_PROCTABLE()->MultiTexCoord2sv) +#define glMultiTexCoord3d (_GET_TLS_PROCTABLE()->MultiTexCoord3d) +#define glMultiTexCoord3dv (_GET_TLS_PROCTABLE()->MultiTexCoord3dv) +#define glMultiTexCoord3f (_GET_TLS_PROCTABLE()->MultiTexCoord3f) +#define glMultiTexCoord3fv (_GET_TLS_PROCTABLE()->MultiTexCoord3fv) +#define glMultiTexCoord3i (_GET_TLS_PROCTABLE()->MultiTexCoord3i) +#define glMultiTexCoord3iv (_GET_TLS_PROCTABLE()->MultiTexCoord3iv) +#define glMultiTexCoord3s (_GET_TLS_PROCTABLE()->MultiTexCoord3s) +#define glMultiTexCoord3sv (_GET_TLS_PROCTABLE()->MultiTexCoord3sv) +#define glMultiTexCoord4d (_GET_TLS_PROCTABLE()->MultiTexCoord4d) +#define glMultiTexCoord4dv (_GET_TLS_PROCTABLE()->MultiTexCoord4dv) +#define glMultiTexCoord4f (_GET_TLS_PROCTABLE()->MultiTexCoord4f) +#define glMultiTexCoord4fv (_GET_TLS_PROCTABLE()->MultiTexCoord4fv) +#define glMultiTexCoord4i (_GET_TLS_PROCTABLE()->MultiTexCoord4i) +#define glMultiTexCoord4iv (_GET_TLS_PROCTABLE()->MultiTexCoord4iv) +#define glMultiTexCoord4s (_GET_TLS_PROCTABLE()->MultiTexCoord4s) +#define glMultiTexCoord4sv (_GET_TLS_PROCTABLE()->MultiTexCoord4sv) +#define glLoadTransposeMatrixf (_GET_TLS_PROCTABLE()->LoadTransposeMatrixf) +#define glLoadTransposeMatrixd (_GET_TLS_PROCTABLE()->LoadTransposeMatrixd) +#define glMultTransposeMatrixf (_GET_TLS_PROCTABLE()->MultTransposeMatrixf) +#define glMultTransposeMatrixd (_GET_TLS_PROCTABLE()->MultTransposeMatrixd) +#define glSampleCoverage (_GET_TLS_PROCTABLE()->SampleCoverage) +#define glCompressedTexImage3D (_GET_TLS_PROCTABLE()->CompressedTexImage3D) +#define glCompressedTexImage2D (_GET_TLS_PROCTABLE()->CompressedTexImage2D) +#define glCompressedTexImage1D (_GET_TLS_PROCTABLE()->CompressedTexImage1D) +#define glCompressedTexSubImage3D (_GET_TLS_PROCTABLE()->CompressedTexSubImage3D) +#define glCompressedTexSubImage2D (_GET_TLS_PROCTABLE()->CompressedTexSubImage2D) +#define glCompressedTexSubImage1D (_GET_TLS_PROCTABLE()->CompressedTexSubImage1D) +#define glGetCompressedTexImage (_GET_TLS_PROCTABLE()->GetCompressedTexImage) +#define glBlendFuncSeparate (_GET_TLS_PROCTABLE()->BlendFuncSeparate) +#define glFogCoordf (_GET_TLS_PROCTABLE()->FogCoordf) +#define glFogCoordfv (_GET_TLS_PROCTABLE()->FogCoordfv) +#define glFogCoordd (_GET_TLS_PROCTABLE()->FogCoordd) +#define glFogCoorddv (_GET_TLS_PROCTABLE()->FogCoorddv) +#define glFogCoordPointer (_GET_TLS_PROCTABLE()->FogCoordPointer) +#define glMultiDrawArrays (_GET_TLS_PROCTABLE()->MultiDrawArrays) +#define glMultiDrawElements (_GET_TLS_PROCTABLE()->MultiDrawElements) +#define glPointParameterf (_GET_TLS_PROCTABLE()->PointParameterf) +#define glPointParameterfv (_GET_TLS_PROCTABLE()->PointParameterfv) +#define glPointParameteri (_GET_TLS_PROCTABLE()->PointParameteri) +#define glPointParameteriv (_GET_TLS_PROCTABLE()->PointParameteriv) +#define glSecondaryColor3b (_GET_TLS_PROCTABLE()->SecondaryColor3b) +#define glSecondaryColor3bv (_GET_TLS_PROCTABLE()->SecondaryColor3bv) +#define glSecondaryColor3d (_GET_TLS_PROCTABLE()->SecondaryColor3d) +#define glSecondaryColor3dv (_GET_TLS_PROCTABLE()->SecondaryColor3dv) +#define glSecondaryColor3f (_GET_TLS_PROCTABLE()->SecondaryColor3f) +#define glSecondaryColor3fv (_GET_TLS_PROCTABLE()->SecondaryColor3fv) +#define glSecondaryColor3i (_GET_TLS_PROCTABLE()->SecondaryColor3i) +#define glSecondaryColor3iv (_GET_TLS_PROCTABLE()->SecondaryColor3iv) +#define glSecondaryColor3s (_GET_TLS_PROCTABLE()->SecondaryColor3s) +#define glSecondaryColor3sv (_GET_TLS_PROCTABLE()->SecondaryColor3sv) +#define glSecondaryColor3ub (_GET_TLS_PROCTABLE()->SecondaryColor3ub) +#define glSecondaryColor3ubv (_GET_TLS_PROCTABLE()->SecondaryColor3ubv) +#define glSecondaryColor3ui (_GET_TLS_PROCTABLE()->SecondaryColor3ui) +#define glSecondaryColor3uiv (_GET_TLS_PROCTABLE()->SecondaryColor3uiv) +#define glSecondaryColor3us (_GET_TLS_PROCTABLE()->SecondaryColor3us) +#define glSecondaryColor3usv (_GET_TLS_PROCTABLE()->SecondaryColor3usv) +#define glSecondaryColorPointer (_GET_TLS_PROCTABLE()->SecondaryColorPointer) +#define glWindowPos2d (_GET_TLS_PROCTABLE()->WindowPos2d) +#define glWindowPos2dv (_GET_TLS_PROCTABLE()->WindowPos2dv) +#define glWindowPos2f (_GET_TLS_PROCTABLE()->WindowPos2f) +#define glWindowPos2fv (_GET_TLS_PROCTABLE()->WindowPos2fv) +#define glWindowPos2i (_GET_TLS_PROCTABLE()->WindowPos2i) +#define glWindowPos2iv (_GET_TLS_PROCTABLE()->WindowPos2iv) +#define glWindowPos2s (_GET_TLS_PROCTABLE()->WindowPos2s) +#define glWindowPos2sv (_GET_TLS_PROCTABLE()->WindowPos2sv) +#define glWindowPos3d (_GET_TLS_PROCTABLE()->WindowPos3d) +#define glWindowPos3dv (_GET_TLS_PROCTABLE()->WindowPos3dv) +#define glWindowPos3f (_GET_TLS_PROCTABLE()->WindowPos3f) +#define glWindowPos3fv (_GET_TLS_PROCTABLE()->WindowPos3fv) +#define glWindowPos3i (_GET_TLS_PROCTABLE()->WindowPos3i) +#define glWindowPos3iv (_GET_TLS_PROCTABLE()->WindowPos3iv) +#define glWindowPos3s (_GET_TLS_PROCTABLE()->WindowPos3s) +#define glWindowPos3sv (_GET_TLS_PROCTABLE()->WindowPos3sv) +#define glGenQueries (_GET_TLS_PROCTABLE()->GenQueries) +#define glDeleteQueries (_GET_TLS_PROCTABLE()->DeleteQueries) +#define glIsQuery (_GET_TLS_PROCTABLE()->IsQuery) +#define glBeginQuery (_GET_TLS_PROCTABLE()->BeginQuery) +#define glEndQuery (_GET_TLS_PROCTABLE()->EndQuery) +#define glGetQueryiv (_GET_TLS_PROCTABLE()->GetQueryiv) +#define glGetQueryObjectiv (_GET_TLS_PROCTABLE()->GetQueryObjectiv) +#define glGetQueryObjectuiv (_GET_TLS_PROCTABLE()->GetQueryObjectuiv) +#define glBindBuffer (_GET_TLS_PROCTABLE()->BindBuffer) +#define glDeleteBuffers (_GET_TLS_PROCTABLE()->DeleteBuffers) +#define glGenBuffers (_GET_TLS_PROCTABLE()->GenBuffers) +#define glIsBuffer (_GET_TLS_PROCTABLE()->IsBuffer) +#define glBufferData (_GET_TLS_PROCTABLE()->BufferData) +#define glBufferSubData (_GET_TLS_PROCTABLE()->BufferSubData) +#define glGetBufferSubData (_GET_TLS_PROCTABLE()->GetBufferSubData) +#define glMapBuffer (_GET_TLS_PROCTABLE()->MapBuffer) +#define glUnmapBuffer (_GET_TLS_PROCTABLE()->UnmapBuffer) +#define glGetBufferParameteriv (_GET_TLS_PROCTABLE()->GetBufferParameteriv) +#define glGetBufferPointerv (_GET_TLS_PROCTABLE()->GetBufferPointerv) +#define glActiveTextureARB (_GET_TLS_PROCTABLE()->ActiveTextureARB) +#define glClientActiveTextureARB (_GET_TLS_PROCTABLE()->ClientActiveTextureARB) +#define glMultiTexCoord1dARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dARB) +#define glMultiTexCoord1dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dvARB) +#define glMultiTexCoord1fARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fARB) +#define glMultiTexCoord1fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fvARB) +#define glMultiTexCoord1iARB (_GET_TLS_PROCTABLE()->MultiTexCoord1iARB) +#define glMultiTexCoord1ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord1ivARB) +#define glMultiTexCoord1sARB (_GET_TLS_PROCTABLE()->MultiTexCoord1sARB) +#define glMultiTexCoord1svARB (_GET_TLS_PROCTABLE()->MultiTexCoord1svARB) +#define glMultiTexCoord2dARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dARB) +#define glMultiTexCoord2dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dvARB) +#define glMultiTexCoord2fARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fARB) +#define glMultiTexCoord2fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fvARB) +#define glMultiTexCoord2iARB (_GET_TLS_PROCTABLE()->MultiTexCoord2iARB) +#define glMultiTexCoord2ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord2ivARB) +#define glMultiTexCoord2sARB (_GET_TLS_PROCTABLE()->MultiTexCoord2sARB) +#define glMultiTexCoord2svARB (_GET_TLS_PROCTABLE()->MultiTexCoord2svARB) +#define glMultiTexCoord3dARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dARB) +#define glMultiTexCoord3dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dvARB) +#define glMultiTexCoord3fARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fARB) +#define glMultiTexCoord3fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fvARB) +#define glMultiTexCoord3iARB (_GET_TLS_PROCTABLE()->MultiTexCoord3iARB) +#define glMultiTexCoord3ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord3ivARB) +#define glMultiTexCoord3sARB (_GET_TLS_PROCTABLE()->MultiTexCoord3sARB) +#define glMultiTexCoord3svARB (_GET_TLS_PROCTABLE()->MultiTexCoord3svARB) +#define glMultiTexCoord4dARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dARB) +#define glMultiTexCoord4dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dvARB) +#define glMultiTexCoord4fARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fARB) +#define glMultiTexCoord4fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fvARB) +#define glMultiTexCoord4iARB (_GET_TLS_PROCTABLE()->MultiTexCoord4iARB) +#define glMultiTexCoord4ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord4ivARB) +#define glMultiTexCoord4sARB (_GET_TLS_PROCTABLE()->MultiTexCoord4sARB) +#define glMultiTexCoord4svARB (_GET_TLS_PROCTABLE()->MultiTexCoord4svARB) +#define glLoadTransposeMatrixfARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixfARB) +#define glLoadTransposeMatrixdARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixdARB) +#define glMultTransposeMatrixfARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixfARB) +#define glMultTransposeMatrixdARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixdARB) +#define glSampleCoverageARB (_GET_TLS_PROCTABLE()->SampleCoverageARB) +#define glCompressedTexImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexImage3DARB) +#define glCompressedTexImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexImage2DARB) +#define glCompressedTexImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexImage1DARB) +#define glCompressedTexSubImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage3DARB) +#define glCompressedTexSubImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage2DARB) +#define glCompressedTexSubImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage1DARB) +#define glGetCompressedTexImageARB (_GET_TLS_PROCTABLE()->GetCompressedTexImageARB) +#define glPointParameterfARB (_GET_TLS_PROCTABLE()->PointParameterfARB) +#define glPointParameterfvARB (_GET_TLS_PROCTABLE()->PointParameterfvARB) +#define glWeightbvARB (_GET_TLS_PROCTABLE()->WeightbvARB) +#define glWeightsvARB (_GET_TLS_PROCTABLE()->WeightsvARB) +#define glWeightivARB (_GET_TLS_PROCTABLE()->WeightivARB) +#define glWeightfvARB (_GET_TLS_PROCTABLE()->WeightfvARB) +#define glWeightdvARB (_GET_TLS_PROCTABLE()->WeightdvARB) +#define glWeightubvARB (_GET_TLS_PROCTABLE()->WeightubvARB) +#define glWeightusvARB (_GET_TLS_PROCTABLE()->WeightusvARB) +#define glWeightuivARB (_GET_TLS_PROCTABLE()->WeightuivARB) +#define glWeightPointerARB (_GET_TLS_PROCTABLE()->WeightPointerARB) +#define glVertexBlendARB (_GET_TLS_PROCTABLE()->VertexBlendARB) +#define glCurrentPaletteMatrixARB (_GET_TLS_PROCTABLE()->CurrentPaletteMatrixARB) +#define glMatrixIndexubvARB (_GET_TLS_PROCTABLE()->MatrixIndexubvARB) +#define glMatrixIndexusvARB (_GET_TLS_PROCTABLE()->MatrixIndexusvARB) +#define glMatrixIndexuivARB (_GET_TLS_PROCTABLE()->MatrixIndexuivARB) +#define glMatrixIndexPointerARB (_GET_TLS_PROCTABLE()->MatrixIndexPointerARB) +#define glWindowPos2dARB (_GET_TLS_PROCTABLE()->WindowPos2dARB) +#define glWindowPos2dvARB (_GET_TLS_PROCTABLE()->WindowPos2dvARB) +#define glWindowPos2fARB (_GET_TLS_PROCTABLE()->WindowPos2fARB) +#define glWindowPos2fvARB (_GET_TLS_PROCTABLE()->WindowPos2fvARB) +#define glWindowPos2iARB (_GET_TLS_PROCTABLE()->WindowPos2iARB) +#define glWindowPos2ivARB (_GET_TLS_PROCTABLE()->WindowPos2ivARB) +#define glWindowPos2sARB (_GET_TLS_PROCTABLE()->WindowPos2sARB) +#define glWindowPos2svARB (_GET_TLS_PROCTABLE()->WindowPos2svARB) +#define glWindowPos3dARB (_GET_TLS_PROCTABLE()->WindowPos3dARB) +#define glWindowPos3dvARB (_GET_TLS_PROCTABLE()->WindowPos3dvARB) +#define glWindowPos3fARB (_GET_TLS_PROCTABLE()->WindowPos3fARB) +#define glWindowPos3fvARB (_GET_TLS_PROCTABLE()->WindowPos3fvARB) +#define glWindowPos3iARB (_GET_TLS_PROCTABLE()->WindowPos3iARB) +#define glWindowPos3ivARB (_GET_TLS_PROCTABLE()->WindowPos3ivARB) +#define glWindowPos3sARB (_GET_TLS_PROCTABLE()->WindowPos3sARB) +#define glWindowPos3svARB (_GET_TLS_PROCTABLE()->WindowPos3svARB) +#define glVertexAttrib1dARB (_GET_TLS_PROCTABLE()->VertexAttrib1dARB) +#define glVertexAttrib1dvARB (_GET_TLS_PROCTABLE()->VertexAttrib1dvARB) +#define glVertexAttrib1fARB (_GET_TLS_PROCTABLE()->VertexAttrib1fARB) +#define glVertexAttrib1fvARB (_GET_TLS_PROCTABLE()->VertexAttrib1fvARB) +#define glVertexAttrib1sARB (_GET_TLS_PROCTABLE()->VertexAttrib1sARB) +#define glVertexAttrib1svARB (_GET_TLS_PROCTABLE()->VertexAttrib1svARB) +#define glVertexAttrib2dARB (_GET_TLS_PROCTABLE()->VertexAttrib2dARB) +#define glVertexAttrib2dvARB (_GET_TLS_PROCTABLE()->VertexAttrib2dvARB) +#define glVertexAttrib2fARB (_GET_TLS_PROCTABLE()->VertexAttrib2fARB) +#define glVertexAttrib2fvARB (_GET_TLS_PROCTABLE()->VertexAttrib2fvARB) +#define glVertexAttrib2sARB (_GET_TLS_PROCTABLE()->VertexAttrib2sARB) +#define glVertexAttrib2svARB (_GET_TLS_PROCTABLE()->VertexAttrib2svARB) +#define glVertexAttrib3dARB (_GET_TLS_PROCTABLE()->VertexAttrib3dARB) +#define glVertexAttrib3dvARB (_GET_TLS_PROCTABLE()->VertexAttrib3dvARB) +#define glVertexAttrib3fARB (_GET_TLS_PROCTABLE()->VertexAttrib3fARB) +#define glVertexAttrib3fvARB (_GET_TLS_PROCTABLE()->VertexAttrib3fvARB) +#define glVertexAttrib3sARB (_GET_TLS_PROCTABLE()->VertexAttrib3sARB) +#define glVertexAttrib3svARB (_GET_TLS_PROCTABLE()->VertexAttrib3svARB) +#define glVertexAttrib4NbvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NbvARB) +#define glVertexAttrib4NivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NivARB) +#define glVertexAttrib4NsvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NsvARB) +#define glVertexAttrib4NubARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubARB) +#define glVertexAttrib4NubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubvARB) +#define glVertexAttrib4NuivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NuivARB) +#define glVertexAttrib4NusvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NusvARB) +#define glVertexAttrib4bvARB (_GET_TLS_PROCTABLE()->VertexAttrib4bvARB) +#define glVertexAttrib4dARB (_GET_TLS_PROCTABLE()->VertexAttrib4dARB) +#define glVertexAttrib4dvARB (_GET_TLS_PROCTABLE()->VertexAttrib4dvARB) +#define glVertexAttrib4fARB (_GET_TLS_PROCTABLE()->VertexAttrib4fARB) +#define glVertexAttrib4fvARB (_GET_TLS_PROCTABLE()->VertexAttrib4fvARB) +#define glVertexAttrib4ivARB (_GET_TLS_PROCTABLE()->VertexAttrib4ivARB) +#define glVertexAttrib4sARB (_GET_TLS_PROCTABLE()->VertexAttrib4sARB) +#define glVertexAttrib4svARB (_GET_TLS_PROCTABLE()->VertexAttrib4svARB) +#define glVertexAttrib4ubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4ubvARB) +#define glVertexAttrib4uivARB (_GET_TLS_PROCTABLE()->VertexAttrib4uivARB) +#define glVertexAttrib4usvARB (_GET_TLS_PROCTABLE()->VertexAttrib4usvARB) +#define glVertexAttribPointerARB (_GET_TLS_PROCTABLE()->VertexAttribPointerARB) +#define glEnableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->EnableVertexAttribArrayARB) +#define glDisableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->DisableVertexAttribArrayARB) +#define glProgramStringARB (_GET_TLS_PROCTABLE()->ProgramStringARB) +#define glBindProgramARB (_GET_TLS_PROCTABLE()->BindProgramARB) +#define glDeleteProgramsARB (_GET_TLS_PROCTABLE()->DeleteProgramsARB) +#define glGenProgramsARB (_GET_TLS_PROCTABLE()->GenProgramsARB) +#define glProgramEnvParameter4dARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dARB) +#define glProgramEnvParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dvARB) +#define glProgramEnvParameter4fARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fARB) +#define glProgramEnvParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fvARB) +#define glProgramLocalParameter4dARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dARB) +#define glProgramLocalParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dvARB) +#define glProgramLocalParameter4fARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fARB) +#define glProgramLocalParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fvARB) +#define glGetProgramEnvParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterdvARB) +#define glGetProgramEnvParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterfvARB) +#define glGetProgramLocalParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterdvARB) +#define glGetProgramLocalParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterfvARB) +#define glGetProgramivARB (_GET_TLS_PROCTABLE()->GetProgramivARB) +#define glGetProgramStringARB (_GET_TLS_PROCTABLE()->GetProgramStringARB) +#define glGetVertexAttribdvARB (_GET_TLS_PROCTABLE()->GetVertexAttribdvARB) +#define glGetVertexAttribfvARB (_GET_TLS_PROCTABLE()->GetVertexAttribfvARB) +#define glGetVertexAttribivARB (_GET_TLS_PROCTABLE()->GetVertexAttribivARB) +#define glGetVertexAttribPointervARB (_GET_TLS_PROCTABLE()->GetVertexAttribPointervARB) +#define glIsProgramARB (_GET_TLS_PROCTABLE()->IsProgramARB) +#define glBindBufferARB (_GET_TLS_PROCTABLE()->BindBufferARB) +#define glDeleteBuffersARB (_GET_TLS_PROCTABLE()->DeleteBuffersARB) +#define glGenBuffersARB (_GET_TLS_PROCTABLE()->GenBuffersARB) +#define glIsBufferARB (_GET_TLS_PROCTABLE()->IsBufferARB) +#define glBufferDataARB (_GET_TLS_PROCTABLE()->BufferDataARB) +#define glBufferSubDataARB (_GET_TLS_PROCTABLE()->BufferSubDataARB) +#define glGetBufferSubDataARB (_GET_TLS_PROCTABLE()->GetBufferSubDataARB) +#define glMapBufferARB (_GET_TLS_PROCTABLE()->MapBufferARB) +#define glUnmapBufferARB (_GET_TLS_PROCTABLE()->UnmapBufferARB) +#define glGetBufferParameterivARB (_GET_TLS_PROCTABLE()->GetBufferParameterivARB) +#define glGetBufferPointervARB (_GET_TLS_PROCTABLE()->GetBufferPointervARB) +#define glGenQueriesARB (_GET_TLS_PROCTABLE()->GenQueriesARB) +#define glDeleteQueriesARB (_GET_TLS_PROCTABLE()->DeleteQueriesARB) +#define glIsQueryARB (_GET_TLS_PROCTABLE()->IsQueryARB) +#define glBeginQueryARB (_GET_TLS_PROCTABLE()->BeginQueryARB) +#define glEndQueryARB (_GET_TLS_PROCTABLE()->EndQueryARB) +#define glGetQueryivARB (_GET_TLS_PROCTABLE()->GetQueryivARB) +#define glGetQueryObjectivARB (_GET_TLS_PROCTABLE()->GetQueryObjectivARB) +#define glGetQueryObjectuivARB (_GET_TLS_PROCTABLE()->GetQueryObjectuivARB) +#define glDeleteObjectARB (_GET_TLS_PROCTABLE()->DeleteObjectARB) +#define glGetHandleARB (_GET_TLS_PROCTABLE()->GetHandleARB) +#define glDetachObjectARB (_GET_TLS_PROCTABLE()->DetachObjectARB) +#define glCreateShaderObjectARB (_GET_TLS_PROCTABLE()->CreateShaderObjectARB) +#define glShaderSourceARB (_GET_TLS_PROCTABLE()->ShaderSourceARB) +#define glCompileShaderARB (_GET_TLS_PROCTABLE()->CompileShaderARB) +#define glCreateProgramObjectARB (_GET_TLS_PROCTABLE()->CreateProgramObjectARB) +#define glAttachObjectARB (_GET_TLS_PROCTABLE()->AttachObjectARB) +#define glLinkProgramARB (_GET_TLS_PROCTABLE()->LinkProgramARB) +#define glUseProgramObjectARB (_GET_TLS_PROCTABLE()->UseProgramObjectARB) +#define glValidateProgramARB (_GET_TLS_PROCTABLE()->ValidateProgramARB) +#define glUniform1fARB (_GET_TLS_PROCTABLE()->Uniform1fARB) +#define glUniform2fARB (_GET_TLS_PROCTABLE()->Uniform2fARB) +#define glUniform3fARB (_GET_TLS_PROCTABLE()->Uniform3fARB) +#define glUniform4fARB (_GET_TLS_PROCTABLE()->Uniform4fARB) +#define glUniform1iARB (_GET_TLS_PROCTABLE()->Uniform1iARB) +#define glUniform2iARB (_GET_TLS_PROCTABLE()->Uniform2iARB) +#define glUniform3iARB (_GET_TLS_PROCTABLE()->Uniform3iARB) +#define glUniform4iARB (_GET_TLS_PROCTABLE()->Uniform4iARB) +#define glUniform1fvARB (_GET_TLS_PROCTABLE()->Uniform1fvARB) +#define glUniform2fvARB (_GET_TLS_PROCTABLE()->Uniform2fvARB) +#define glUniform3fvARB (_GET_TLS_PROCTABLE()->Uniform3fvARB) +#define glUniform4fvARB (_GET_TLS_PROCTABLE()->Uniform4fvARB) +#define glUniform1ivARB (_GET_TLS_PROCTABLE()->Uniform1ivARB) +#define glUniform2ivARB (_GET_TLS_PROCTABLE()->Uniform2ivARB) +#define glUniform3ivARB (_GET_TLS_PROCTABLE()->Uniform3ivARB) +#define glUniform4ivARB (_GET_TLS_PROCTABLE()->Uniform4ivARB) +#define glUniformMatrix2fvARB (_GET_TLS_PROCTABLE()->UniformMatrix2fvARB) +#define glUniformMatrix3fvARB (_GET_TLS_PROCTABLE()->UniformMatrix3fvARB) +#define glUniformMatrix4fvARB (_GET_TLS_PROCTABLE()->UniformMatrix4fvARB) +#define glGetObjectParameterfvARB (_GET_TLS_PROCTABLE()->GetObjectParameterfvARB) +#define glGetObjectParameterivARB (_GET_TLS_PROCTABLE()->GetObjectParameterivARB) +#define glGetInfoLogARB (_GET_TLS_PROCTABLE()->GetInfoLogARB) +#define glGetAttachedObjectsARB (_GET_TLS_PROCTABLE()->GetAttachedObjectsARB) +#define glGetUniformLocationARB (_GET_TLS_PROCTABLE()->GetUniformLocationARB) +#define glGetActiveUniformARB (_GET_TLS_PROCTABLE()->GetActiveUniformARB) +#define glGetUniformfvARB (_GET_TLS_PROCTABLE()->GetUniformfvARB) +#define glGetUniformivARB (_GET_TLS_PROCTABLE()->GetUniformivARB) +#define glGetShaderSourceARB (_GET_TLS_PROCTABLE()->GetShaderSourceARB) +#define glBindAttribLocationARB (_GET_TLS_PROCTABLE()->BindAttribLocationARB) +#define glGetActiveAttribARB (_GET_TLS_PROCTABLE()->GetActiveAttribARB) +#define glGetAttribLocationARB (_GET_TLS_PROCTABLE()->GetAttribLocationARB) +#define glBlendColorEXT (_GET_TLS_PROCTABLE()->BlendColorEXT) +#define glPolygonOffsetEXT (_GET_TLS_PROCTABLE()->PolygonOffsetEXT) +#define glTexImage3DEXT (_GET_TLS_PROCTABLE()->TexImage3DEXT) +#define glTexSubImage3DEXT (_GET_TLS_PROCTABLE()->TexSubImage3DEXT) +#define glGetTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->GetTexFilterFuncSGIS) +#define glTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->TexFilterFuncSGIS) +#define glTexSubImage1DEXT (_GET_TLS_PROCTABLE()->TexSubImage1DEXT) +#define glTexSubImage2DEXT (_GET_TLS_PROCTABLE()->TexSubImage2DEXT) +#define glCopyTexImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexImage1DEXT) +#define glCopyTexImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexImage2DEXT) +#define glCopyTexSubImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage1DEXT) +#define glCopyTexSubImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage2DEXT) +#define glCopyTexSubImage3DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage3DEXT) +#define glGetHistogramEXT (_GET_TLS_PROCTABLE()->GetHistogramEXT) +#define glGetHistogramParameterfvEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterfvEXT) +#define glGetHistogramParameterivEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterivEXT) +#define glGetMinmaxEXT (_GET_TLS_PROCTABLE()->GetMinmaxEXT) +#define glGetMinmaxParameterfvEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterfvEXT) +#define glGetMinmaxParameterivEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterivEXT) +#define glHistogramEXT (_GET_TLS_PROCTABLE()->HistogramEXT) +#define glMinmaxEXT (_GET_TLS_PROCTABLE()->MinmaxEXT) +#define glResetHistogramEXT (_GET_TLS_PROCTABLE()->ResetHistogramEXT) +#define glResetMinmaxEXT (_GET_TLS_PROCTABLE()->ResetMinmaxEXT) +#define glConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter1DEXT) +#define glConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter2DEXT) +#define glConvolutionParameterfEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfEXT) +#define glConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfvEXT) +#define glConvolutionParameteriEXT (_GET_TLS_PROCTABLE()->ConvolutionParameteriEXT) +#define glConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterivEXT) +#define glCopyConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1DEXT) +#define glCopyConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2DEXT) +#define glGetConvolutionFilterEXT (_GET_TLS_PROCTABLE()->GetConvolutionFilterEXT) +#define glGetConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterfvEXT) +#define glGetConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterivEXT) +#define glGetSeparableFilterEXT (_GET_TLS_PROCTABLE()->GetSeparableFilterEXT) +#define glSeparableFilter2DEXT (_GET_TLS_PROCTABLE()->SeparableFilter2DEXT) +#define glColorTableSGI (_GET_TLS_PROCTABLE()->ColorTableSGI) +#define glColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->ColorTableParameterfvSGI) +#define glColorTableParameterivSGI (_GET_TLS_PROCTABLE()->ColorTableParameterivSGI) +#define glCopyColorTableSGI (_GET_TLS_PROCTABLE()->CopyColorTableSGI) +#define glGetColorTableSGI (_GET_TLS_PROCTABLE()->GetColorTableSGI) +#define glGetColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterfvSGI) +#define glGetColorTableParameterivSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterivSGI) +#define glPixelTexGenSGIX (_GET_TLS_PROCTABLE()->PixelTexGenSGIX) +#define glPixelTexGenParameteriSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameteriSGIS) +#define glPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterivSGIS) +#define glPixelTexGenParameterfSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfSGIS) +#define glPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfvSGIS) +#define glGetPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterivSGIS) +#define glGetPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterfvSGIS) +#define glTexImage4DSGIS (_GET_TLS_PROCTABLE()->TexImage4DSGIS) +#define glTexSubImage4DSGIS (_GET_TLS_PROCTABLE()->TexSubImage4DSGIS) +#define glAreTexturesResidentEXT (_GET_TLS_PROCTABLE()->AreTexturesResidentEXT) +#define glBindTextureEXT (_GET_TLS_PROCTABLE()->BindTextureEXT) +#define glDeleteTexturesEXT (_GET_TLS_PROCTABLE()->DeleteTexturesEXT) +#define glGenTexturesEXT (_GET_TLS_PROCTABLE()->GenTexturesEXT) +#define glIsTextureEXT (_GET_TLS_PROCTABLE()->IsTextureEXT) +#define glPrioritizeTexturesEXT (_GET_TLS_PROCTABLE()->PrioritizeTexturesEXT) +#define glDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->DetailTexFuncSGIS) +#define glGetDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->GetDetailTexFuncSGIS) +#define glSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->SharpenTexFuncSGIS) +#define glGetSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->GetSharpenTexFuncSGIS) +#define glSampleMaskSGIS (_GET_TLS_PROCTABLE()->SampleMaskSGIS) +#define glSamplePatternSGIS (_GET_TLS_PROCTABLE()->SamplePatternSGIS) +#define glArrayElementEXT (_GET_TLS_PROCTABLE()->ArrayElementEXT) +#define glColorPointerEXT (_GET_TLS_PROCTABLE()->ColorPointerEXT) +#define glDrawArraysEXT (_GET_TLS_PROCTABLE()->DrawArraysEXT) +#define glEdgeFlagPointerEXT (_GET_TLS_PROCTABLE()->EdgeFlagPointerEXT) +#define glGetPointervEXT (_GET_TLS_PROCTABLE()->GetPointervEXT) +#define glIndexPointerEXT (_GET_TLS_PROCTABLE()->IndexPointerEXT) +#define glNormalPointerEXT (_GET_TLS_PROCTABLE()->NormalPointerEXT) +#define glTexCoordPointerEXT (_GET_TLS_PROCTABLE()->TexCoordPointerEXT) +#define glVertexPointerEXT (_GET_TLS_PROCTABLE()->VertexPointerEXT) +#define glBlendEquationEXT (_GET_TLS_PROCTABLE()->BlendEquationEXT) +#define glSpriteParameterfSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfSGIX) +#define glSpriteParameterfvSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfvSGIX) +#define glSpriteParameteriSGIX (_GET_TLS_PROCTABLE()->SpriteParameteriSGIX) +#define glSpriteParameterivSGIX (_GET_TLS_PROCTABLE()->SpriteParameterivSGIX) +#define glPointParameterfEXT (_GET_TLS_PROCTABLE()->PointParameterfEXT) +#define glPointParameterfvEXT (_GET_TLS_PROCTABLE()->PointParameterfvEXT) +#define glPointParameterfSGIS (_GET_TLS_PROCTABLE()->PointParameterfSGIS) +#define glPointParameterfvSGIS (_GET_TLS_PROCTABLE()->PointParameterfvSGIS) +#define glGetInstrumentsSGIX (_GET_TLS_PROCTABLE()->GetInstrumentsSGIX) +#define glInstrumentsBufferSGIX (_GET_TLS_PROCTABLE()->InstrumentsBufferSGIX) +#define glPollInstrumentsSGIX (_GET_TLS_PROCTABLE()->PollInstrumentsSGIX) +#define glReadInstrumentsSGIX (_GET_TLS_PROCTABLE()->ReadInstrumentsSGIX) +#define glStartInstrumentsSGIX (_GET_TLS_PROCTABLE()->StartInstrumentsSGIX) +#define glStopInstrumentsSGIX (_GET_TLS_PROCTABLE()->StopInstrumentsSGIX) +#define glFrameZoomSGIX (_GET_TLS_PROCTABLE()->FrameZoomSGIX) +#define glTagSampleBufferSGIX (_GET_TLS_PROCTABLE()->TagSampleBufferSGIX) +#define glDeformationMap3dSGIX (_GET_TLS_PROCTABLE()->DeformationMap3dSGIX) +#define glDeformationMap3fSGIX (_GET_TLS_PROCTABLE()->DeformationMap3fSGIX) +#define glDeformSGIX (_GET_TLS_PROCTABLE()->DeformSGIX) +#define glLoadIdentityDeformationMapSGIX (_GET_TLS_PROCTABLE()->LoadIdentityDeformationMapSGIX) +#define glReferencePlaneSGIX (_GET_TLS_PROCTABLE()->ReferencePlaneSGIX) +#define glFlushRasterSGIX (_GET_TLS_PROCTABLE()->FlushRasterSGIX) +#define glFogFuncSGIS (_GET_TLS_PROCTABLE()->FogFuncSGIS) +#define glGetFogFuncSGIS (_GET_TLS_PROCTABLE()->GetFogFuncSGIS) +#define glImageTransformParameteriHP (_GET_TLS_PROCTABLE()->ImageTransformParameteriHP) +#define glImageTransformParameterfHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfHP) +#define glImageTransformParameterivHP (_GET_TLS_PROCTABLE()->ImageTransformParameterivHP) +#define glImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfvHP) +#define glGetImageTransformParameterivHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterivHP) +#define glGetImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterfvHP) +#define glColorSubTableEXT (_GET_TLS_PROCTABLE()->ColorSubTableEXT) +#define glCopyColorSubTableEXT (_GET_TLS_PROCTABLE()->CopyColorSubTableEXT) +#define glHintPGI (_GET_TLS_PROCTABLE()->HintPGI) +#define glColorTableEXT (_GET_TLS_PROCTABLE()->ColorTableEXT) +#define glGetColorTableEXT (_GET_TLS_PROCTABLE()->GetColorTableEXT) +#define glGetColorTableParameterivEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterivEXT) +#define glGetColorTableParameterfvEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterfvEXT) +#define glGetListParameterfvSGIX (_GET_TLS_PROCTABLE()->GetListParameterfvSGIX) +#define glGetListParameterivSGIX (_GET_TLS_PROCTABLE()->GetListParameterivSGIX) +#define glListParameterfSGIX (_GET_TLS_PROCTABLE()->ListParameterfSGIX) +#define glListParameterfvSGIX (_GET_TLS_PROCTABLE()->ListParameterfvSGIX) +#define glListParameteriSGIX (_GET_TLS_PROCTABLE()->ListParameteriSGIX) +#define glListParameterivSGIX (_GET_TLS_PROCTABLE()->ListParameterivSGIX) +#define glIndexMaterialEXT (_GET_TLS_PROCTABLE()->IndexMaterialEXT) +#define glIndexFuncEXT (_GET_TLS_PROCTABLE()->IndexFuncEXT) +#define glLockArraysEXT (_GET_TLS_PROCTABLE()->LockArraysEXT) +#define glUnlockArraysEXT (_GET_TLS_PROCTABLE()->UnlockArraysEXT) +#define glCullParameterdvEXT (_GET_TLS_PROCTABLE()->CullParameterdvEXT) +#define glCullParameterfvEXT (_GET_TLS_PROCTABLE()->CullParameterfvEXT) +#define glFragmentColorMaterialSGIX (_GET_TLS_PROCTABLE()->FragmentColorMaterialSGIX) +#define glFragmentLightfSGIX (_GET_TLS_PROCTABLE()->FragmentLightfSGIX) +#define glFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightfvSGIX) +#define glFragmentLightiSGIX (_GET_TLS_PROCTABLE()->FragmentLightiSGIX) +#define glFragmentLightivSGIX (_GET_TLS_PROCTABLE()->FragmentLightivSGIX) +#define glFragmentLightModelfSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfSGIX) +#define glFragmentLightModelfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfvSGIX) +#define glFragmentLightModeliSGIX (_GET_TLS_PROCTABLE()->FragmentLightModeliSGIX) +#define glFragmentLightModelivSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelivSGIX) +#define glFragmentMaterialfSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfSGIX) +#define glFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfvSGIX) +#define glFragmentMaterialiSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialiSGIX) +#define glFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialivSGIX) +#define glGetFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightfvSGIX) +#define glGetFragmentLightivSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightivSGIX) +#define glGetFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialfvSGIX) +#define glGetFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialivSGIX) +#define glLightEnviSGIX (_GET_TLS_PROCTABLE()->LightEnviSGIX) +#define glDrawRangeElementsEXT (_GET_TLS_PROCTABLE()->DrawRangeElementsEXT) +#define glApplyTextureEXT (_GET_TLS_PROCTABLE()->ApplyTextureEXT) +#define glTextureLightEXT (_GET_TLS_PROCTABLE()->TextureLightEXT) +#define glTextureMaterialEXT (_GET_TLS_PROCTABLE()->TextureMaterialEXT) +#define glAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->AsyncMarkerSGIX) +#define glFinishAsyncSGIX (_GET_TLS_PROCTABLE()->FinishAsyncSGIX) +#define glPollAsyncSGIX (_GET_TLS_PROCTABLE()->PollAsyncSGIX) +#define glGenAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->GenAsyncMarkersSGIX) +#define glDeleteAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->DeleteAsyncMarkersSGIX) +#define glIsAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->IsAsyncMarkerSGIX) +#define glVertexPointervINTEL (_GET_TLS_PROCTABLE()->VertexPointervINTEL) +#define glNormalPointervINTEL (_GET_TLS_PROCTABLE()->NormalPointervINTEL) +#define glColorPointervINTEL (_GET_TLS_PROCTABLE()->ColorPointervINTEL) +#define glTexCoordPointervINTEL (_GET_TLS_PROCTABLE()->TexCoordPointervINTEL) +#define glPixelTransformParameteriEXT (_GET_TLS_PROCTABLE()->PixelTransformParameteriEXT) +#define glPixelTransformParameterfEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfEXT) +#define glPixelTransformParameterivEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterivEXT) +#define glPixelTransformParameterfvEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfvEXT) +#define glSecondaryColor3bEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bEXT) +#define glSecondaryColor3bvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bvEXT) +#define glSecondaryColor3dEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dEXT) +#define glSecondaryColor3dvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dvEXT) +#define glSecondaryColor3fEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fEXT) +#define glSecondaryColor3fvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fvEXT) +#define glSecondaryColor3iEXT (_GET_TLS_PROCTABLE()->SecondaryColor3iEXT) +#define glSecondaryColor3ivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ivEXT) +#define glSecondaryColor3sEXT (_GET_TLS_PROCTABLE()->SecondaryColor3sEXT) +#define glSecondaryColor3svEXT (_GET_TLS_PROCTABLE()->SecondaryColor3svEXT) +#define glSecondaryColor3ubEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubEXT) +#define glSecondaryColor3ubvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubvEXT) +#define glSecondaryColor3uiEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uiEXT) +#define glSecondaryColor3uivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uivEXT) +#define glSecondaryColor3usEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usEXT) +#define glSecondaryColor3usvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usvEXT) +#define glSecondaryColorPointerEXT (_GET_TLS_PROCTABLE()->SecondaryColorPointerEXT) +#define glTextureNormalEXT (_GET_TLS_PROCTABLE()->TextureNormalEXT) +#define glMultiDrawArraysEXT (_GET_TLS_PROCTABLE()->MultiDrawArraysEXT) +#define glMultiDrawElementsEXT (_GET_TLS_PROCTABLE()->MultiDrawElementsEXT) +#define glFogCoordfEXT (_GET_TLS_PROCTABLE()->FogCoordfEXT) +#define glFogCoordfvEXT (_GET_TLS_PROCTABLE()->FogCoordfvEXT) +#define glFogCoorddEXT (_GET_TLS_PROCTABLE()->FogCoorddEXT) +#define glFogCoorddvEXT (_GET_TLS_PROCTABLE()->FogCoorddvEXT) +#define glFogCoordPointerEXT (_GET_TLS_PROCTABLE()->FogCoordPointerEXT) +#define glTangent3bEXT (_GET_TLS_PROCTABLE()->Tangent3bEXT) +#define glTangent3bvEXT (_GET_TLS_PROCTABLE()->Tangent3bvEXT) +#define glTangent3dEXT (_GET_TLS_PROCTABLE()->Tangent3dEXT) +#define glTangent3dvEXT (_GET_TLS_PROCTABLE()->Tangent3dvEXT) +#define glTangent3fEXT (_GET_TLS_PROCTABLE()->Tangent3fEXT) +#define glTangent3fvEXT (_GET_TLS_PROCTABLE()->Tangent3fvEXT) +#define glTangent3iEXT (_GET_TLS_PROCTABLE()->Tangent3iEXT) +#define glTangent3ivEXT (_GET_TLS_PROCTABLE()->Tangent3ivEXT) +#define glTangent3sEXT (_GET_TLS_PROCTABLE()->Tangent3sEXT) +#define glTangent3svEXT (_GET_TLS_PROCTABLE()->Tangent3svEXT) +#define glBinormal3bEXT (_GET_TLS_PROCTABLE()->Binormal3bEXT) +#define glBinormal3bvEXT (_GET_TLS_PROCTABLE()->Binormal3bvEXT) +#define glBinormal3dEXT (_GET_TLS_PROCTABLE()->Binormal3dEXT) +#define glBinormal3dvEXT (_GET_TLS_PROCTABLE()->Binormal3dvEXT) +#define glBinormal3fEXT (_GET_TLS_PROCTABLE()->Binormal3fEXT) +#define glBinormal3fvEXT (_GET_TLS_PROCTABLE()->Binormal3fvEXT) +#define glBinormal3iEXT (_GET_TLS_PROCTABLE()->Binormal3iEXT) +#define glBinormal3ivEXT (_GET_TLS_PROCTABLE()->Binormal3ivEXT) +#define glBinormal3sEXT (_GET_TLS_PROCTABLE()->Binormal3sEXT) +#define glBinormal3svEXT (_GET_TLS_PROCTABLE()->Binormal3svEXT) +#define glTangentPointerEXT (_GET_TLS_PROCTABLE()->TangentPointerEXT) +#define glBinormalPointerEXT (_GET_TLS_PROCTABLE()->BinormalPointerEXT) +#define glFinishTextureSUNX (_GET_TLS_PROCTABLE()->FinishTextureSUNX) +#define glGlobalAlphaFactorbSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorbSUN) +#define glGlobalAlphaFactorsSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorsSUN) +#define glGlobalAlphaFactoriSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoriSUN) +#define glGlobalAlphaFactorfSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorfSUN) +#define glGlobalAlphaFactordSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactordSUN) +#define glGlobalAlphaFactorubSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorubSUN) +#define glGlobalAlphaFactorusSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorusSUN) +#define glGlobalAlphaFactoruiSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoruiSUN) +#define glReplacementCodeuiSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiSUN) +#define glReplacementCodeusSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusSUN) +#define glReplacementCodeubSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubSUN) +#define glReplacementCodeuivSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuivSUN) +#define glReplacementCodeusvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusvSUN) +#define glReplacementCodeubvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubvSUN) +#define glReplacementCodePointerSUN (_GET_TLS_PROCTABLE()->ReplacementCodePointerSUN) +#define glColor4ubVertex2fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fSUN) +#define glColor4ubVertex2fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fvSUN) +#define glColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fSUN) +#define glColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fvSUN) +#define glColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fSUN) +#define glColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fvSUN) +#define glNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fSUN) +#define glNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fvSUN) +#define glColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fSUN) +#define glColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fvSUN) +#define glTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fSUN) +#define glTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fvSUN) +#define glTexCoord4fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fSUN) +#define glTexCoord4fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fvSUN) +#define glTexCoord2fColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fSUN) +#define glTexCoord2fColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fvSUN) +#define glTexCoord2fColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fSUN) +#define glTexCoord2fColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fvSUN) +#define glTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fSUN) +#define glTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fvSUN) +#define glTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fSUN) +#define glTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fvSUN) +#define glTexCoord4fColor4fNormal3fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fSUN) +#define glTexCoord4fColor4fNormal3fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fvSUN) +#define glReplacementCodeuiVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fSUN) +#define glReplacementCodeuiVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fvSUN) +#define glReplacementCodeuiColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fSUN) +#define glReplacementCodeuiColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fvSUN) +#define glReplacementCodeuiColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fSUN) +#define glReplacementCodeuiColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fvSUN) +#define glReplacementCodeuiNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fSUN) +#define glReplacementCodeuiNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fvSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) +#define glBlendFuncSeparateEXT (_GET_TLS_PROCTABLE()->BlendFuncSeparateEXT) +#define glBlendFuncSeparateINGR (_GET_TLS_PROCTABLE()->BlendFuncSeparateINGR) +#define glVertexWeightfEXT (_GET_TLS_PROCTABLE()->VertexWeightfEXT) +#define glVertexWeightfvEXT (_GET_TLS_PROCTABLE()->VertexWeightfvEXT) +#define glVertexWeightPointerEXT (_GET_TLS_PROCTABLE()->VertexWeightPointerEXT) +#define glFlushVertexArrayRangeNV (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeNV) +#define glVertexArrayRangeNV (_GET_TLS_PROCTABLE()->VertexArrayRangeNV) +#define glCombinerParameterfvNV (_GET_TLS_PROCTABLE()->CombinerParameterfvNV) +#define glCombinerParameterfNV (_GET_TLS_PROCTABLE()->CombinerParameterfNV) +#define glCombinerParameterivNV (_GET_TLS_PROCTABLE()->CombinerParameterivNV) +#define glCombinerParameteriNV (_GET_TLS_PROCTABLE()->CombinerParameteriNV) +#define glCombinerInputNV (_GET_TLS_PROCTABLE()->CombinerInputNV) +#define glCombinerOutputNV (_GET_TLS_PROCTABLE()->CombinerOutputNV) +#define glFinalCombinerInputNV (_GET_TLS_PROCTABLE()->FinalCombinerInputNV) +#define glGetCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterfvNV) +#define glGetCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterivNV) +#define glGetCombinerOutputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterfvNV) +#define glGetCombinerOutputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterivNV) +#define glGetFinalCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterfvNV) +#define glGetFinalCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterivNV) +#define glResizeBuffersMESA (_GET_TLS_PROCTABLE()->ResizeBuffersMESA) +#define glWindowPos2dMESA (_GET_TLS_PROCTABLE()->WindowPos2dMESA) +#define glWindowPos2dvMESA (_GET_TLS_PROCTABLE()->WindowPos2dvMESA) +#define glWindowPos2fMESA (_GET_TLS_PROCTABLE()->WindowPos2fMESA) +#define glWindowPos2fvMESA (_GET_TLS_PROCTABLE()->WindowPos2fvMESA) +#define glWindowPos2iMESA (_GET_TLS_PROCTABLE()->WindowPos2iMESA) +#define glWindowPos2ivMESA (_GET_TLS_PROCTABLE()->WindowPos2ivMESA) +#define glWindowPos2sMESA (_GET_TLS_PROCTABLE()->WindowPos2sMESA) +#define glWindowPos2svMESA (_GET_TLS_PROCTABLE()->WindowPos2svMESA) +#define glWindowPos3dMESA (_GET_TLS_PROCTABLE()->WindowPos3dMESA) +#define glWindowPos3dvMESA (_GET_TLS_PROCTABLE()->WindowPos3dvMESA) +#define glWindowPos3fMESA (_GET_TLS_PROCTABLE()->WindowPos3fMESA) +#define glWindowPos3fvMESA (_GET_TLS_PROCTABLE()->WindowPos3fvMESA) +#define glWindowPos3iMESA (_GET_TLS_PROCTABLE()->WindowPos3iMESA) +#define glWindowPos3ivMESA (_GET_TLS_PROCTABLE()->WindowPos3ivMESA) +#define glWindowPos3sMESA (_GET_TLS_PROCTABLE()->WindowPos3sMESA) +#define glWindowPos3svMESA (_GET_TLS_PROCTABLE()->WindowPos3svMESA) +#define glWindowPos4dMESA (_GET_TLS_PROCTABLE()->WindowPos4dMESA) +#define glWindowPos4dvMESA (_GET_TLS_PROCTABLE()->WindowPos4dvMESA) +#define glWindowPos4fMESA (_GET_TLS_PROCTABLE()->WindowPos4fMESA) +#define glWindowPos4fvMESA (_GET_TLS_PROCTABLE()->WindowPos4fvMESA) +#define glWindowPos4iMESA (_GET_TLS_PROCTABLE()->WindowPos4iMESA) +#define glWindowPos4ivMESA (_GET_TLS_PROCTABLE()->WindowPos4ivMESA) +#define glWindowPos4sMESA (_GET_TLS_PROCTABLE()->WindowPos4sMESA) +#define glWindowPos4svMESA (_GET_TLS_PROCTABLE()->WindowPos4svMESA) +#define glMultiModeDrawArraysIBM (_GET_TLS_PROCTABLE()->MultiModeDrawArraysIBM) +#define glMultiModeDrawElementsIBM (_GET_TLS_PROCTABLE()->MultiModeDrawElementsIBM) +#define glColorPointerListIBM (_GET_TLS_PROCTABLE()->ColorPointerListIBM) +#define glSecondaryColorPointerListIBM (_GET_TLS_PROCTABLE()->SecondaryColorPointerListIBM) +#define glEdgeFlagPointerListIBM (_GET_TLS_PROCTABLE()->EdgeFlagPointerListIBM) +#define glFogCoordPointerListIBM (_GET_TLS_PROCTABLE()->FogCoordPointerListIBM) +#define glIndexPointerListIBM (_GET_TLS_PROCTABLE()->IndexPointerListIBM) +#define glNormalPointerListIBM (_GET_TLS_PROCTABLE()->NormalPointerListIBM) +#define glTexCoordPointerListIBM (_GET_TLS_PROCTABLE()->TexCoordPointerListIBM) +#define glVertexPointerListIBM (_GET_TLS_PROCTABLE()->VertexPointerListIBM) +#define glTbufferMask3DFX (_GET_TLS_PROCTABLE()->TbufferMask3DFX) +#define glSampleMaskEXT (_GET_TLS_PROCTABLE()->SampleMaskEXT) +#define glSamplePatternEXT (_GET_TLS_PROCTABLE()->SamplePatternEXT) +#define glTextureColorMaskSGIS (_GET_TLS_PROCTABLE()->TextureColorMaskSGIS) +#define glIglooInterfaceSGIX (_GET_TLS_PROCTABLE()->IglooInterfaceSGIX) +#define glDeleteFencesNV (_GET_TLS_PROCTABLE()->DeleteFencesNV) +#define glGenFencesNV (_GET_TLS_PROCTABLE()->GenFencesNV) +#define glIsFenceNV (_GET_TLS_PROCTABLE()->IsFenceNV) +#define glTestFenceNV (_GET_TLS_PROCTABLE()->TestFenceNV) +#define glGetFenceivNV (_GET_TLS_PROCTABLE()->GetFenceivNV) +#define glFinishFenceNV (_GET_TLS_PROCTABLE()->FinishFenceNV) +#define glSetFenceNV (_GET_TLS_PROCTABLE()->SetFenceNV) +#define glMapControlPointsNV (_GET_TLS_PROCTABLE()->MapControlPointsNV) +#define glMapParameterivNV (_GET_TLS_PROCTABLE()->MapParameterivNV) +#define glMapParameterfvNV (_GET_TLS_PROCTABLE()->MapParameterfvNV) +#define glGetMapControlPointsNV (_GET_TLS_PROCTABLE()->GetMapControlPointsNV) +#define glGetMapParameterivNV (_GET_TLS_PROCTABLE()->GetMapParameterivNV) +#define glGetMapParameterfvNV (_GET_TLS_PROCTABLE()->GetMapParameterfvNV) +#define glGetMapAttribParameterivNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterivNV) +#define glGetMapAttribParameterfvNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterfvNV) +#define glEvalMapsNV (_GET_TLS_PROCTABLE()->EvalMapsNV) +#define glCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->CombinerStageParameterfvNV) +#define glGetCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerStageParameterfvNV) +#define glAreProgramsResidentNV (_GET_TLS_PROCTABLE()->AreProgramsResidentNV) +#define glBindProgramNV (_GET_TLS_PROCTABLE()->BindProgramNV) +#define glDeleteProgramsNV (_GET_TLS_PROCTABLE()->DeleteProgramsNV) +#define glExecuteProgramNV (_GET_TLS_PROCTABLE()->ExecuteProgramNV) +#define glGenProgramsNV (_GET_TLS_PROCTABLE()->GenProgramsNV) +#define glGetProgramParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramParameterdvNV) +#define glGetProgramParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramParameterfvNV) +#define glGetProgramivNV (_GET_TLS_PROCTABLE()->GetProgramivNV) +#define glGetProgramStringNV (_GET_TLS_PROCTABLE()->GetProgramStringNV) +#define glGetTrackMatrixivNV (_GET_TLS_PROCTABLE()->GetTrackMatrixivNV) +#define glGetVertexAttribdvNV (_GET_TLS_PROCTABLE()->GetVertexAttribdvNV) +#define glGetVertexAttribfvNV (_GET_TLS_PROCTABLE()->GetVertexAttribfvNV) +#define glGetVertexAttribivNV (_GET_TLS_PROCTABLE()->GetVertexAttribivNV) +#define glGetVertexAttribPointervNV (_GET_TLS_PROCTABLE()->GetVertexAttribPointervNV) +#define glIsProgramNV (_GET_TLS_PROCTABLE()->IsProgramNV) +#define glLoadProgramNV (_GET_TLS_PROCTABLE()->LoadProgramNV) +#define glProgramParameter4dNV (_GET_TLS_PROCTABLE()->ProgramParameter4dNV) +#define glProgramParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramParameter4dvNV) +#define glProgramParameter4fNV (_GET_TLS_PROCTABLE()->ProgramParameter4fNV) +#define glProgramParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramParameter4fvNV) +#define glProgramParameters4dvNV (_GET_TLS_PROCTABLE()->ProgramParameters4dvNV) +#define glProgramParameters4fvNV (_GET_TLS_PROCTABLE()->ProgramParameters4fvNV) +#define glRequestResidentProgramsNV (_GET_TLS_PROCTABLE()->RequestResidentProgramsNV) +#define glTrackMatrixNV (_GET_TLS_PROCTABLE()->TrackMatrixNV) +#define glVertexAttribPointerNV (_GET_TLS_PROCTABLE()->VertexAttribPointerNV) +#define glVertexAttrib1dNV (_GET_TLS_PROCTABLE()->VertexAttrib1dNV) +#define glVertexAttrib1dvNV (_GET_TLS_PROCTABLE()->VertexAttrib1dvNV) +#define glVertexAttrib1fNV (_GET_TLS_PROCTABLE()->VertexAttrib1fNV) +#define glVertexAttrib1fvNV (_GET_TLS_PROCTABLE()->VertexAttrib1fvNV) +#define glVertexAttrib1sNV (_GET_TLS_PROCTABLE()->VertexAttrib1sNV) +#define glVertexAttrib1svNV (_GET_TLS_PROCTABLE()->VertexAttrib1svNV) +#define glVertexAttrib2dNV (_GET_TLS_PROCTABLE()->VertexAttrib2dNV) +#define glVertexAttrib2dvNV (_GET_TLS_PROCTABLE()->VertexAttrib2dvNV) +#define glVertexAttrib2fNV (_GET_TLS_PROCTABLE()->VertexAttrib2fNV) +#define glVertexAttrib2fvNV (_GET_TLS_PROCTABLE()->VertexAttrib2fvNV) +#define glVertexAttrib2sNV (_GET_TLS_PROCTABLE()->VertexAttrib2sNV) +#define glVertexAttrib2svNV (_GET_TLS_PROCTABLE()->VertexAttrib2svNV) +#define glVertexAttrib3dNV (_GET_TLS_PROCTABLE()->VertexAttrib3dNV) +#define glVertexAttrib3dvNV (_GET_TLS_PROCTABLE()->VertexAttrib3dvNV) +#define glVertexAttrib3fNV (_GET_TLS_PROCTABLE()->VertexAttrib3fNV) +#define glVertexAttrib3fvNV (_GET_TLS_PROCTABLE()->VertexAttrib3fvNV) +#define glVertexAttrib3sNV (_GET_TLS_PROCTABLE()->VertexAttrib3sNV) +#define glVertexAttrib3svNV (_GET_TLS_PROCTABLE()->VertexAttrib3svNV) +#define glVertexAttrib4dNV (_GET_TLS_PROCTABLE()->VertexAttrib4dNV) +#define glVertexAttrib4dvNV (_GET_TLS_PROCTABLE()->VertexAttrib4dvNV) +#define glVertexAttrib4fNV (_GET_TLS_PROCTABLE()->VertexAttrib4fNV) +#define glVertexAttrib4fvNV (_GET_TLS_PROCTABLE()->VertexAttrib4fvNV) +#define glVertexAttrib4sNV (_GET_TLS_PROCTABLE()->VertexAttrib4sNV) +#define glVertexAttrib4svNV (_GET_TLS_PROCTABLE()->VertexAttrib4svNV) +#define glVertexAttrib4ubNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubNV) +#define glVertexAttrib4ubvNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubvNV) +#define glVertexAttribs1dvNV (_GET_TLS_PROCTABLE()->VertexAttribs1dvNV) +#define glVertexAttribs1fvNV (_GET_TLS_PROCTABLE()->VertexAttribs1fvNV) +#define glVertexAttribs1svNV (_GET_TLS_PROCTABLE()->VertexAttribs1svNV) +#define glVertexAttribs2dvNV (_GET_TLS_PROCTABLE()->VertexAttribs2dvNV) +#define glVertexAttribs2fvNV (_GET_TLS_PROCTABLE()->VertexAttribs2fvNV) +#define glVertexAttribs2svNV (_GET_TLS_PROCTABLE()->VertexAttribs2svNV) +#define glVertexAttribs3dvNV (_GET_TLS_PROCTABLE()->VertexAttribs3dvNV) +#define glVertexAttribs3fvNV (_GET_TLS_PROCTABLE()->VertexAttribs3fvNV) +#define glVertexAttribs3svNV (_GET_TLS_PROCTABLE()->VertexAttribs3svNV) +#define glVertexAttribs4dvNV (_GET_TLS_PROCTABLE()->VertexAttribs4dvNV) +#define glVertexAttribs4fvNV (_GET_TLS_PROCTABLE()->VertexAttribs4fvNV) +#define glVertexAttribs4svNV (_GET_TLS_PROCTABLE()->VertexAttribs4svNV) +#define glVertexAttribs4ubvNV (_GET_TLS_PROCTABLE()->VertexAttribs4ubvNV) +#define glTexBumpParameterivATI (_GET_TLS_PROCTABLE()->TexBumpParameterivATI) +#define glTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->TexBumpParameterfvATI) +#define glGetTexBumpParameterivATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterivATI) +#define glGetTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterfvATI) +#define glGenFragmentShadersATI (_GET_TLS_PROCTABLE()->GenFragmentShadersATI) +#define glBindFragmentShaderATI (_GET_TLS_PROCTABLE()->BindFragmentShaderATI) +#define glDeleteFragmentShaderATI (_GET_TLS_PROCTABLE()->DeleteFragmentShaderATI) +#define glBeginFragmentShaderATI (_GET_TLS_PROCTABLE()->BeginFragmentShaderATI) +#define glEndFragmentShaderATI (_GET_TLS_PROCTABLE()->EndFragmentShaderATI) +#define glPassTexCoordATI (_GET_TLS_PROCTABLE()->PassTexCoordATI) +#define glSampleMapATI (_GET_TLS_PROCTABLE()->SampleMapATI) +#define glColorFragmentOp1ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp1ATI) +#define glColorFragmentOp2ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp2ATI) +#define glColorFragmentOp3ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp3ATI) +#define glAlphaFragmentOp1ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp1ATI) +#define glAlphaFragmentOp2ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp2ATI) +#define glAlphaFragmentOp3ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp3ATI) +#define glSetFragmentShaderConstantATI (_GET_TLS_PROCTABLE()->SetFragmentShaderConstantATI) +#define glPNTrianglesiATI (_GET_TLS_PROCTABLE()->PNTrianglesiATI) +#define glPNTrianglesfATI (_GET_TLS_PROCTABLE()->PNTrianglesfATI) +#define glNewObjectBufferATI (_GET_TLS_PROCTABLE()->NewObjectBufferATI) +#define glIsObjectBufferATI (_GET_TLS_PROCTABLE()->IsObjectBufferATI) +#define glUpdateObjectBufferATI (_GET_TLS_PROCTABLE()->UpdateObjectBufferATI) +#define glGetObjectBufferfvATI (_GET_TLS_PROCTABLE()->GetObjectBufferfvATI) +#define glGetObjectBufferivATI (_GET_TLS_PROCTABLE()->GetObjectBufferivATI) +#define glFreeObjectBufferATI (_GET_TLS_PROCTABLE()->FreeObjectBufferATI) +#define glArrayObjectATI (_GET_TLS_PROCTABLE()->ArrayObjectATI) +#define glGetArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetArrayObjectfvATI) +#define glGetArrayObjectivATI (_GET_TLS_PROCTABLE()->GetArrayObjectivATI) +#define glVariantArrayObjectATI (_GET_TLS_PROCTABLE()->VariantArrayObjectATI) +#define glGetVariantArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectfvATI) +#define glGetVariantArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectivATI) +#define glBeginVertexShaderEXT (_GET_TLS_PROCTABLE()->BeginVertexShaderEXT) +#define glEndVertexShaderEXT (_GET_TLS_PROCTABLE()->EndVertexShaderEXT) +#define glBindVertexShaderEXT (_GET_TLS_PROCTABLE()->BindVertexShaderEXT) +#define glGenVertexShadersEXT (_GET_TLS_PROCTABLE()->GenVertexShadersEXT) +#define glDeleteVertexShaderEXT (_GET_TLS_PROCTABLE()->DeleteVertexShaderEXT) +#define glShaderOp1EXT (_GET_TLS_PROCTABLE()->ShaderOp1EXT) +#define glShaderOp2EXT (_GET_TLS_PROCTABLE()->ShaderOp2EXT) +#define glShaderOp3EXT (_GET_TLS_PROCTABLE()->ShaderOp3EXT) +#define glSwizzleEXT (_GET_TLS_PROCTABLE()->SwizzleEXT) +#define glWriteMaskEXT (_GET_TLS_PROCTABLE()->WriteMaskEXT) +#define glInsertComponentEXT (_GET_TLS_PROCTABLE()->InsertComponentEXT) +#define glExtractComponentEXT (_GET_TLS_PROCTABLE()->ExtractComponentEXT) +#define glGenSymbolsEXT (_GET_TLS_PROCTABLE()->GenSymbolsEXT) +#define glSetInvariantEXT (_GET_TLS_PROCTABLE()->SetInvariantEXT) +#define glSetLocalConstantEXT (_GET_TLS_PROCTABLE()->SetLocalConstantEXT) +#define glVariantbvEXT (_GET_TLS_PROCTABLE()->VariantbvEXT) +#define glVariantsvEXT (_GET_TLS_PROCTABLE()->VariantsvEXT) +#define glVariantivEXT (_GET_TLS_PROCTABLE()->VariantivEXT) +#define glVariantfvEXT (_GET_TLS_PROCTABLE()->VariantfvEXT) +#define glVariantdvEXT (_GET_TLS_PROCTABLE()->VariantdvEXT) +#define glVariantubvEXT (_GET_TLS_PROCTABLE()->VariantubvEXT) +#define glVariantusvEXT (_GET_TLS_PROCTABLE()->VariantusvEXT) +#define glVariantuivEXT (_GET_TLS_PROCTABLE()->VariantuivEXT) +#define glVariantPointerEXT (_GET_TLS_PROCTABLE()->VariantPointerEXT) +#define glEnableVariantClientStateEXT (_GET_TLS_PROCTABLE()->EnableVariantClientStateEXT) +#define glDisableVariantClientStateEXT (_GET_TLS_PROCTABLE()->DisableVariantClientStateEXT) +#define glBindLightParameterEXT (_GET_TLS_PROCTABLE()->BindLightParameterEXT) +#define glBindMaterialParameterEXT (_GET_TLS_PROCTABLE()->BindMaterialParameterEXT) +#define glBindTexGenParameterEXT (_GET_TLS_PROCTABLE()->BindTexGenParameterEXT) +#define glBindTextureUnitParameterEXT (_GET_TLS_PROCTABLE()->BindTextureUnitParameterEXT) +#define glBindParameterEXT (_GET_TLS_PROCTABLE()->BindParameterEXT) +#define glIsVariantEnabledEXT (_GET_TLS_PROCTABLE()->IsVariantEnabledEXT) +#define glGetVariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetVariantBooleanvEXT) +#define glGetVariantIntegervEXT (_GET_TLS_PROCTABLE()->GetVariantIntegervEXT) +#define glGetVariantFloatvEXT (_GET_TLS_PROCTABLE()->GetVariantFloatvEXT) +#define glGetVariantPointervEXT (_GET_TLS_PROCTABLE()->GetVariantPointervEXT) +#define glGetInvariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetInvariantBooleanvEXT) +#define glGetInvariantIntegervEXT (_GET_TLS_PROCTABLE()->GetInvariantIntegervEXT) +#define glGetInvariantFloatvEXT (_GET_TLS_PROCTABLE()->GetInvariantFloatvEXT) +#define glGetLocalConstantBooleanvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantBooleanvEXT) +#define glGetLocalConstantIntegervEXT (_GET_TLS_PROCTABLE()->GetLocalConstantIntegervEXT) +#define glGetLocalConstantFloatvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantFloatvEXT) +#define glVertexStream1sATI (_GET_TLS_PROCTABLE()->VertexStream1sATI) +#define glVertexStream1svATI (_GET_TLS_PROCTABLE()->VertexStream1svATI) +#define glVertexStream1iATI (_GET_TLS_PROCTABLE()->VertexStream1iATI) +#define glVertexStream1ivATI (_GET_TLS_PROCTABLE()->VertexStream1ivATI) +#define glVertexStream1fATI (_GET_TLS_PROCTABLE()->VertexStream1fATI) +#define glVertexStream1fvATI (_GET_TLS_PROCTABLE()->VertexStream1fvATI) +#define glVertexStream1dATI (_GET_TLS_PROCTABLE()->VertexStream1dATI) +#define glVertexStream1dvATI (_GET_TLS_PROCTABLE()->VertexStream1dvATI) +#define glVertexStream2sATI (_GET_TLS_PROCTABLE()->VertexStream2sATI) +#define glVertexStream2svATI (_GET_TLS_PROCTABLE()->VertexStream2svATI) +#define glVertexStream2iATI (_GET_TLS_PROCTABLE()->VertexStream2iATI) +#define glVertexStream2ivATI (_GET_TLS_PROCTABLE()->VertexStream2ivATI) +#define glVertexStream2fATI (_GET_TLS_PROCTABLE()->VertexStream2fATI) +#define glVertexStream2fvATI (_GET_TLS_PROCTABLE()->VertexStream2fvATI) +#define glVertexStream2dATI (_GET_TLS_PROCTABLE()->VertexStream2dATI) +#define glVertexStream2dvATI (_GET_TLS_PROCTABLE()->VertexStream2dvATI) +#define glVertexStream3sATI (_GET_TLS_PROCTABLE()->VertexStream3sATI) +#define glVertexStream3svATI (_GET_TLS_PROCTABLE()->VertexStream3svATI) +#define glVertexStream3iATI (_GET_TLS_PROCTABLE()->VertexStream3iATI) +#define glVertexStream3ivATI (_GET_TLS_PROCTABLE()->VertexStream3ivATI) +#define glVertexStream3fATI (_GET_TLS_PROCTABLE()->VertexStream3fATI) +#define glVertexStream3fvATI (_GET_TLS_PROCTABLE()->VertexStream3fvATI) +#define glVertexStream3dATI (_GET_TLS_PROCTABLE()->VertexStream3dATI) +#define glVertexStream3dvATI (_GET_TLS_PROCTABLE()->VertexStream3dvATI) +#define glVertexStream4sATI (_GET_TLS_PROCTABLE()->VertexStream4sATI) +#define glVertexStream4svATI (_GET_TLS_PROCTABLE()->VertexStream4svATI) +#define glVertexStream4iATI (_GET_TLS_PROCTABLE()->VertexStream4iATI) +#define glVertexStream4ivATI (_GET_TLS_PROCTABLE()->VertexStream4ivATI) +#define glVertexStream4fATI (_GET_TLS_PROCTABLE()->VertexStream4fATI) +#define glVertexStream4fvATI (_GET_TLS_PROCTABLE()->VertexStream4fvATI) +#define glVertexStream4dATI (_GET_TLS_PROCTABLE()->VertexStream4dATI) +#define glVertexStream4dvATI (_GET_TLS_PROCTABLE()->VertexStream4dvATI) +#define glNormalStream3bATI (_GET_TLS_PROCTABLE()->NormalStream3bATI) +#define glNormalStream3bvATI (_GET_TLS_PROCTABLE()->NormalStream3bvATI) +#define glNormalStream3sATI (_GET_TLS_PROCTABLE()->NormalStream3sATI) +#define glNormalStream3svATI (_GET_TLS_PROCTABLE()->NormalStream3svATI) +#define glNormalStream3iATI (_GET_TLS_PROCTABLE()->NormalStream3iATI) +#define glNormalStream3ivATI (_GET_TLS_PROCTABLE()->NormalStream3ivATI) +#define glNormalStream3fATI (_GET_TLS_PROCTABLE()->NormalStream3fATI) +#define glNormalStream3fvATI (_GET_TLS_PROCTABLE()->NormalStream3fvATI) +#define glNormalStream3dATI (_GET_TLS_PROCTABLE()->NormalStream3dATI) +#define glNormalStream3dvATI (_GET_TLS_PROCTABLE()->NormalStream3dvATI) +#define glClientActiveVertexStreamATI (_GET_TLS_PROCTABLE()->ClientActiveVertexStreamATI) +#define glVertexBlendEnviATI (_GET_TLS_PROCTABLE()->VertexBlendEnviATI) +#define glVertexBlendEnvfATI (_GET_TLS_PROCTABLE()->VertexBlendEnvfATI) +#define glElementPointerATI (_GET_TLS_PROCTABLE()->ElementPointerATI) +#define glDrawElementArrayATI (_GET_TLS_PROCTABLE()->DrawElementArrayATI) +#define glDrawRangeElementArrayATI (_GET_TLS_PROCTABLE()->DrawRangeElementArrayATI) +#define glDrawMeshArraysSUN (_GET_TLS_PROCTABLE()->DrawMeshArraysSUN) +#define glGenOcclusionQueriesNV (_GET_TLS_PROCTABLE()->GenOcclusionQueriesNV) +#define glDeleteOcclusionQueriesNV (_GET_TLS_PROCTABLE()->DeleteOcclusionQueriesNV) +#define glIsOcclusionQueryNV (_GET_TLS_PROCTABLE()->IsOcclusionQueryNV) +#define glBeginOcclusionQueryNV (_GET_TLS_PROCTABLE()->BeginOcclusionQueryNV) +#define glEndOcclusionQueryNV (_GET_TLS_PROCTABLE()->EndOcclusionQueryNV) +#define glGetOcclusionQueryivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryivNV) +#define glGetOcclusionQueryuivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryuivNV) +#define glPointParameteriNV (_GET_TLS_PROCTABLE()->PointParameteriNV) +#define glPointParameterivNV (_GET_TLS_PROCTABLE()->PointParameterivNV) +#define glActiveStencilFaceEXT (_GET_TLS_PROCTABLE()->ActiveStencilFaceEXT) +#define glElementPointerAPPLE (_GET_TLS_PROCTABLE()->ElementPointerAPPLE) +#define glDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawElementArrayAPPLE) +#define glDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawRangeElementArrayAPPLE) +#define glMultiDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawElementArrayAPPLE) +#define glMultiDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawRangeElementArrayAPPLE) +#define glGenFencesAPPLE (_GET_TLS_PROCTABLE()->GenFencesAPPLE) +#define glDeleteFencesAPPLE (_GET_TLS_PROCTABLE()->DeleteFencesAPPLE) +#define glSetFenceAPPLE (_GET_TLS_PROCTABLE()->SetFenceAPPLE) +#define glIsFenceAPPLE (_GET_TLS_PROCTABLE()->IsFenceAPPLE) +#define glTestFenceAPPLE (_GET_TLS_PROCTABLE()->TestFenceAPPLE) +#define glFinishFenceAPPLE (_GET_TLS_PROCTABLE()->FinishFenceAPPLE) +#define glTestObjectAPPLE (_GET_TLS_PROCTABLE()->TestObjectAPPLE) +#define glFinishObjectAPPLE (_GET_TLS_PROCTABLE()->FinishObjectAPPLE) +#define glBindVertexArrayAPPLE (_GET_TLS_PROCTABLE()->BindVertexArrayAPPLE) +#define glDeleteVertexArraysAPPLE (_GET_TLS_PROCTABLE()->DeleteVertexArraysAPPLE) +#define glGenVertexArraysAPPLE (_GET_TLS_PROCTABLE()->GenVertexArraysAPPLE) +#define glIsVertexArrayAPPLE (_GET_TLS_PROCTABLE()->IsVertexArrayAPPLE) +#define glVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->VertexArrayRangeAPPLE) +#define glFlushVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeAPPLE) +#define glVertexArrayParameteriAPPLE (_GET_TLS_PROCTABLE()->VertexArrayParameteriAPPLE) +#define glDrawBuffersATI (_GET_TLS_PROCTABLE()->DrawBuffersATI) +#define glProgramNamedParameter4fNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fNV) +#define glProgramNamedParameter4dNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dNV) +#define glProgramNamedParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fvNV) +#define glProgramNamedParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dvNV) +#define glGetProgramNamedParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterfvNV) +#define glGetProgramNamedParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterdvNV) +#define glVertex2hNV (_GET_TLS_PROCTABLE()->Vertex2hNV) +#define glVertex2hvNV (_GET_TLS_PROCTABLE()->Vertex2hvNV) +#define glVertex3hNV (_GET_TLS_PROCTABLE()->Vertex3hNV) +#define glVertex3hvNV (_GET_TLS_PROCTABLE()->Vertex3hvNV) +#define glVertex4hNV (_GET_TLS_PROCTABLE()->Vertex4hNV) +#define glVertex4hvNV (_GET_TLS_PROCTABLE()->Vertex4hvNV) +#define glNormal3hNV (_GET_TLS_PROCTABLE()->Normal3hNV) +#define glNormal3hvNV (_GET_TLS_PROCTABLE()->Normal3hvNV) +#define glColor3hNV (_GET_TLS_PROCTABLE()->Color3hNV) +#define glColor3hvNV (_GET_TLS_PROCTABLE()->Color3hvNV) +#define glColor4hNV (_GET_TLS_PROCTABLE()->Color4hNV) +#define glColor4hvNV (_GET_TLS_PROCTABLE()->Color4hvNV) +#define glTexCoord1hNV (_GET_TLS_PROCTABLE()->TexCoord1hNV) +#define glTexCoord1hvNV (_GET_TLS_PROCTABLE()->TexCoord1hvNV) +#define glTexCoord2hNV (_GET_TLS_PROCTABLE()->TexCoord2hNV) +#define glTexCoord2hvNV (_GET_TLS_PROCTABLE()->TexCoord2hvNV) +#define glTexCoord3hNV (_GET_TLS_PROCTABLE()->TexCoord3hNV) +#define glTexCoord3hvNV (_GET_TLS_PROCTABLE()->TexCoord3hvNV) +#define glTexCoord4hNV (_GET_TLS_PROCTABLE()->TexCoord4hNV) +#define glTexCoord4hvNV (_GET_TLS_PROCTABLE()->TexCoord4hvNV) +#define glMultiTexCoord1hNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hNV) +#define glMultiTexCoord1hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hvNV) +#define glMultiTexCoord2hNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hNV) +#define glMultiTexCoord2hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hvNV) +#define glMultiTexCoord3hNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hNV) +#define glMultiTexCoord3hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hvNV) +#define glMultiTexCoord4hNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hNV) +#define glMultiTexCoord4hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hvNV) +#define glFogCoordhNV (_GET_TLS_PROCTABLE()->FogCoordhNV) +#define glFogCoordhvNV (_GET_TLS_PROCTABLE()->FogCoordhvNV) +#define glSecondaryColor3hNV (_GET_TLS_PROCTABLE()->SecondaryColor3hNV) +#define glSecondaryColor3hvNV (_GET_TLS_PROCTABLE()->SecondaryColor3hvNV) +#define glVertexWeighthNV (_GET_TLS_PROCTABLE()->VertexWeighthNV) +#define glVertexWeighthvNV (_GET_TLS_PROCTABLE()->VertexWeighthvNV) +#define glVertexAttrib1hNV (_GET_TLS_PROCTABLE()->VertexAttrib1hNV) +#define glVertexAttrib1hvNV (_GET_TLS_PROCTABLE()->VertexAttrib1hvNV) +#define glVertexAttrib2hNV (_GET_TLS_PROCTABLE()->VertexAttrib2hNV) +#define glVertexAttrib2hvNV (_GET_TLS_PROCTABLE()->VertexAttrib2hvNV) +#define glVertexAttrib3hNV (_GET_TLS_PROCTABLE()->VertexAttrib3hNV) +#define glVertexAttrib3hvNV (_GET_TLS_PROCTABLE()->VertexAttrib3hvNV) +#define glVertexAttrib4hNV (_GET_TLS_PROCTABLE()->VertexAttrib4hNV) +#define glVertexAttrib4hvNV (_GET_TLS_PROCTABLE()->VertexAttrib4hvNV) +#define glVertexAttribs1hvNV (_GET_TLS_PROCTABLE()->VertexAttribs1hvNV) +#define glVertexAttribs2hvNV (_GET_TLS_PROCTABLE()->VertexAttribs2hvNV) +#define glVertexAttribs3hvNV (_GET_TLS_PROCTABLE()->VertexAttribs3hvNV) +#define glVertexAttribs4hvNV (_GET_TLS_PROCTABLE()->VertexAttribs4hvNV) +#define glPixelDataRangeNV (_GET_TLS_PROCTABLE()->PixelDataRangeNV) +#define glFlushPixelDataRangeNV (_GET_TLS_PROCTABLE()->FlushPixelDataRangeNV) +#define glPrimitiveRestartNV (_GET_TLS_PROCTABLE()->PrimitiveRestartNV) +#define glPrimitiveRestartIndexNV (_GET_TLS_PROCTABLE()->PrimitiveRestartIndexNV) +#define glMapObjectBufferATI (_GET_TLS_PROCTABLE()->MapObjectBufferATI) +#define glUnmapObjectBufferATI (_GET_TLS_PROCTABLE()->UnmapObjectBufferATI) +#define glStencilOpSeparateATI (_GET_TLS_PROCTABLE()->StencilOpSeparateATI) +#define glStencilFuncSeparateATI (_GET_TLS_PROCTABLE()->StencilFuncSeparateATI) +#define glVertexAttribArrayObjectATI (_GET_TLS_PROCTABLE()->VertexAttribArrayObjectATI) +#define glGetVertexAttribArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectfvATI) +#define glGetVertexAttribArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectivATI) +#define glDepthBoundsEXT (_GET_TLS_PROCTABLE()->DepthBoundsEXT) +#define glBlendEquationSeparateEXT (_GET_TLS_PROCTABLE()->BlendEquationSeparateEXT) +#define glAddSwapHintRectWIN (_GET_TLS_PROCTABLE()->AddSwapHintRectWIN) +#ifdef _WIN32 +#define wglCreateBufferRegionARB (_GET_TLS_PROCTABLE()->CreateBufferRegionARB) +#define wglDeleteBufferRegionARB (_GET_TLS_PROCTABLE()->DeleteBufferRegionARB) +#define wglSaveBufferRegionARB (_GET_TLS_PROCTABLE()->SaveBufferRegionARB) +#define wglRestoreBufferRegionARB (_GET_TLS_PROCTABLE()->RestoreBufferRegionARB) +#define wglGetExtensionsStringARB (_GET_TLS_PROCTABLE()->GetExtensionsStringARB) +#define wglGetPixelFormatAttribivARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivARB) +#define wglGetPixelFormatAttribfvARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvARB) +#define wglChoosePixelFormatARB (_GET_TLS_PROCTABLE()->ChoosePixelFormatARB) +#define wglMakeContextCurrentARB (_GET_TLS_PROCTABLE()->MakeContextCurrentARB) +#define wglGetCurrentReadDCARB (_GET_TLS_PROCTABLE()->GetCurrentReadDCARB) +#define wglCreatePbufferARB (_GET_TLS_PROCTABLE()->CreatePbufferARB) +#define wglGetPbufferDCARB (_GET_TLS_PROCTABLE()->GetPbufferDCARB) +#define wglReleasePbufferDCARB (_GET_TLS_PROCTABLE()->ReleasePbufferDCARB) +#define wglDestroyPbufferARB (_GET_TLS_PROCTABLE()->DestroyPbufferARB) +#define wglQueryPbufferARB (_GET_TLS_PROCTABLE()->QueryPbufferARB) +#define wglBindTexImageARB (_GET_TLS_PROCTABLE()->BindTexImageARB) +#define wglReleaseTexImageARB (_GET_TLS_PROCTABLE()->ReleaseTexImageARB) +#define wglSetPbufferAttribARB (_GET_TLS_PROCTABLE()->SetPbufferAttribARB) +#define wglCreateDisplayColorTableEXT (_GET_TLS_PROCTABLE()->CreateDisplayColorTableEXT) +#define wglLoadDisplayColorTableEXT (_GET_TLS_PROCTABLE()->LoadDisplayColorTableEXT) +#define wglBindDisplayColorTableEXT (_GET_TLS_PROCTABLE()->BindDisplayColorTableEXT) +#define wglDestroyDisplayColorTableEXT (_GET_TLS_PROCTABLE()->DestroyDisplayColorTableEXT) +#define wglGetExtensionsStringEXT (_GET_TLS_PROCTABLE()->GetExtensionsStringEXT) +#define wglMakeContextCurrentEXT (_GET_TLS_PROCTABLE()->MakeContextCurrentEXT) +#define wglGetCurrentReadDCEXT (_GET_TLS_PROCTABLE()->GetCurrentReadDCEXT) +#define wglCreatePbufferEXT (_GET_TLS_PROCTABLE()->CreatePbufferEXT) +#define wglGetPbufferDCEXT (_GET_TLS_PROCTABLE()->GetPbufferDCEXT) +#define wglReleasePbufferDCEXT (_GET_TLS_PROCTABLE()->ReleasePbufferDCEXT) +#define wglDestroyPbufferEXT (_GET_TLS_PROCTABLE()->DestroyPbufferEXT) +#define wglQueryPbufferEXT (_GET_TLS_PROCTABLE()->QueryPbufferEXT) +#define wglGetPixelFormatAttribivEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivEXT) +#define wglGetPixelFormatAttribfvEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvEXT) +#define wglChoosePixelFormatEXT (_GET_TLS_PROCTABLE()->ChoosePixelFormatEXT) +#define wglSwapIntervalEXT (_GET_TLS_PROCTABLE()->SwapIntervalEXT) +#define wglGetSwapIntervalEXT (_GET_TLS_PROCTABLE()->GetSwapIntervalEXT) +#define wglAllocateMemoryNV (_GET_TLS_PROCTABLE()->AllocateMemoryNV) +#define wglFreeMemoryNV (_GET_TLS_PROCTABLE()->FreeMemoryNV) +#define wglGetSyncValuesOML (_GET_TLS_PROCTABLE()->GetSyncValuesOML) +#define wglGetMscRateOML (_GET_TLS_PROCTABLE()->GetMscRateOML) +#define wglSwapBuffersMscOML (_GET_TLS_PROCTABLE()->SwapBuffersMscOML) +#define wglSwapLayerBuffersMscOML (_GET_TLS_PROCTABLE()->SwapLayerBuffersMscOML) +#define wglWaitForMscOML (_GET_TLS_PROCTABLE()->WaitForMscOML) +#define wglWaitForSbcOML (_GET_TLS_PROCTABLE()->WaitForSbcOML) +#define wglGetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->GetDigitalVideoParametersI3D) +#define wglSetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->SetDigitalVideoParametersI3D) +#define wglGetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->GetGammaTableParametersI3D) +#define wglSetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->SetGammaTableParametersI3D) +#define wglGetGammaTableI3D (_GET_TLS_PROCTABLE()->GetGammaTableI3D) +#define wglSetGammaTableI3D (_GET_TLS_PROCTABLE()->SetGammaTableI3D) +#define wglEnableGenlockI3D (_GET_TLS_PROCTABLE()->EnableGenlockI3D) +#define wglDisableGenlockI3D (_GET_TLS_PROCTABLE()->DisableGenlockI3D) +#define wglIsEnabledGenlockI3D (_GET_TLS_PROCTABLE()->IsEnabledGenlockI3D) +#define wglGenlockSourceI3D (_GET_TLS_PROCTABLE()->GenlockSourceI3D) +#define wglGetGenlockSourceI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceI3D) +#define wglGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GenlockSourceEdgeI3D) +#define wglGetGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceEdgeI3D) +#define wglGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GenlockSampleRateI3D) +#define wglGetGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GetGenlockSampleRateI3D) +#define wglGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GenlockSourceDelayI3D) +#define wglGetGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceDelayI3D) +#define wglQueryGenlockMaxSourceDelayI3D (_GET_TLS_PROCTABLE()->QueryGenlockMaxSourceDelayI3D) +#define wglCreateImageBufferI3D (_GET_TLS_PROCTABLE()->CreateImageBufferI3D) +#define wglDestroyImageBufferI3D (_GET_TLS_PROCTABLE()->DestroyImageBufferI3D) +#define wglAssociateImageBufferEventsI3D (_GET_TLS_PROCTABLE()->AssociateImageBufferEventsI3D) +#define wglReleaseImageBufferEventsI3D (_GET_TLS_PROCTABLE()->ReleaseImageBufferEventsI3D) +#define wglEnableFrameLockI3D (_GET_TLS_PROCTABLE()->EnableFrameLockI3D) +#define wglDisableFrameLockI3D (_GET_TLS_PROCTABLE()->DisableFrameLockI3D) +#define wglIsEnabledFrameLockI3D (_GET_TLS_PROCTABLE()->IsEnabledFrameLockI3D) +#define wglQueryFrameLockMasterI3D (_GET_TLS_PROCTABLE()->QueryFrameLockMasterI3D) +#define wglGetFrameUsageI3D (_GET_TLS_PROCTABLE()->GetFrameUsageI3D) +#define wglBeginFrameTrackingI3D (_GET_TLS_PROCTABLE()->BeginFrameTrackingI3D) +#define wglEndFrameTrackingI3D (_GET_TLS_PROCTABLE()->EndFrameTrackingI3D) +#define wglQueryFrameTrackingI3D (_GET_TLS_PROCTABLE()->QueryFrameTrackingI3D) +#endif /* _WIN32 */ + +#ifndef _APP_PROCTABLE + +/* + * Applications can replace the following function with its own function + * for accessing thread local proc/context dependent proc table. + * The following default function works for most applications which + * are using the same device for all their contexts - even if + * the contexts are on different threads. + */ + +static _inline _GLextensionProcs *_GET_TLS_PROCTABLE(void) + +{ + extern _GLextensionProcs _extensionProcs; + + return (&_extensionProcs); +} + +#else + +/* + * Application should replace this compiled function with + * an inlined function for maximum performance. + */ + +extern _GLextensionProcs *_GET_TLS_PROCTABLE(void); + +#endif + +/* + * Provide an initialization function for the application + * to initialize its own proc tables in case the application + * needs to use multiple proc tables. + */ + +static _inline void _InitExtensionProcs(_GLextensionProcs *appProcs) +{ + extern _GLextensionProcs _extensionProcs; + + *appProcs = _extensionProcs; +} + +#ifdef __cplusplus +} +#endif + + +#endif /* _GLPROCS_H_ */ diff --git a/plugins/gs/zerogs/opengl/install-sh b/plugins/gs/zerogs/opengl/install-sh new file mode 100644 index 0000000000..4d4a9519ea --- /dev/null +++ b/plugins/gs/zerogs/opengl/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/gs/zerogs/opengl/memcpy_amd.cpp b/plugins/gs/zerogs/opengl/memcpy_amd.cpp new file mode 100644 index 0000000000..9d22f60f36 --- /dev/null +++ b/plugins/gs/zerogs/opengl/memcpy_amd.cpp @@ -0,0 +1,479 @@ +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/gs/zerogs/opengl/missing b/plugins/gs/zerogs/opengl/missing new file mode 100644 index 0000000000..894e786e16 --- /dev/null +++ b/plugins/gs/zerogs/opengl/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, 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. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/gs/zerogs/opengl/mkinstalldirs b/plugins/gs/zerogs/opengl/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/gs/zerogs/opengl/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec 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. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/gs/zerogs/opengl/ps2hw.fx b/plugins/gs/zerogs/opengl/ps2hw.fx new file mode 100644 index 0000000000..a4b1ba3474 --- /dev/null +++ b/plugins/gs/zerogs/opengl/ps2hw.fx @@ -0,0 +1,841 @@ +// Cg Shaders for PS2 GS emulation + +// divides by z for every pixel, instead of in vertex shader +// fixes kh textures +#define PERSPECTIVE_CORRECT_TEX + +//#define TEST_AEM // tests AEM for black pixels +//#define REGION_REPEAT // set if texture wrapping mode is region repeat +//#define WRITE_DEPTH // set if depth is also written in a MRT +//#define ACCURATE_DECOMPRESSION // set for less capable hardware ATI Radeon 9000 series +//#define EXACT_COLOR // make sure the output color is clamped to 1/255 boundaries (for alpha testing) + +#ifdef PERSPECTIVE_CORRECT_TEX +#define TEX_XY tex.xy/tex.z +#define TEX_DECL float3 +#else +#define TEX_XY tex.xy +#define TEX_DECL float2 +#endif + +#ifdef WRITE_DEPTH +#define DOZWRITE(x) x +#else +#define DOZWRITE(x) +#endif + +#include "ps2hw_ctx.fx" + +// used to get the tiled offset into a page given the linear offset +uniform samplerRECT g_sSrcFinal : register(s2); +uniform sampler2D g_sBlocks : register(s3); +uniform sampler2D g_sBilinearBlocks : register(s4); +uniform sampler2D g_sConv16to32 : register(s4); +uniform sampler3D g_sConv32to16 : register(s4); +uniform sampler2D g_sBitwiseANDX : register(s5); +uniform sampler2D g_sBitwiseANDY : register(s6); +uniform samplerRECT g_sInterlace : register(s7); + +// used only on rare cases where the render target is PSMT8H +uniform sampler2D g_sCLUT : register(s2); + +// global pixel shader constants +uniform float4 g_fInvTexDims : register(c22); // similar to g_fClutOff +uniform float4 g_fFogColor : register(c23); + +// used for rectblitting +uniform float4 g_fBitBltZ : register(c24); + +uniform half4 g_fOneColor : register(c25); // col*.xxxy+.zzzw + +// vertex shader constants +uniform float4 g_fBitBltPos : register(c4); +uniform float4 g_fZ : register(c5); // transforms d3dcolor z into float z +uniform float4 g_fZNorm : register(c6); +uniform float4 g_fBitBltTex : register(c7); + +// pixel shader consts +// .z is used for the addressing fn +uniform half4 g_fExactColor : register(c27) = half4(0.5,0.5/256.0f,0,1/255.0f); +uniform float4 g_fBilinear : register(c28) = float4(-0.7f, -0.65f, 0.9,1/32767.0f); +uniform float4 g_fZBias : register(c29) = half4(1.0f/256.0f, 1.0004f, 1, 0.5); // also for vs +uniform float4 g_fc0 : register(c30) = float4(0,1, 0.001, 0.5f); // also for vs +uniform float4 g_fMult : register(c31) = float4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f); + +// vertex shader consts +uniform float4 g_fBitBltTrans : register(c31) = float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f); + +// given a local tex coord, returns the coord in the memory +float2 ps2memcoord(float2 realtex) +{ + float4 off; + + // block off + realtex.xy = realtex.xy * g_fTexDims.xy + g_fTexDims.zw; + realtex.xy = (realtex.xy - frac(realtex.xy)) * g_fMult.zw; + float2 fblock = frac(realtex.xy); + off.xy = realtex.xy-fblock.xy; + +#ifdef ACCURATE_DECOMPRESSION + off.zw = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).ar; + off.x = dot(off.xyw, g_fTexOffset.xyw); + float f = frac(off.x); + float fadd = g_fTexOffset.z * off.z; + off.w = off.x + fadd; + off.x = frac(f + fadd); + off.w -= off.x; +#else + off.z = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).a; + + // combine the two + off.x = dot(off.xyz, g_fTexOffset.xyz)+g_fTexOffset.w; + off.x = modf(off.x, off.w); +#endif + + off.xy = off.xw * g_fPageOffset.zy + g_fPageOffset.wx; + //off.y = off.w * g_fPageOffset.y + g_fPageOffset.x; + return off.xy; +} + +// find all texcoords for bilinear filtering +// assume that orgtex are already on boundaries +void ps2memcoord4(float4 orgtex, out float4 off0, out float4 off1) +{ + //float4 off0, off1, off2, off3; + float4 realtex; + + // block off + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float4 ftransblock = g_fTexBlock.xyxy*fblock + g_fTexBlock.zwzw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors;// = tex2D(g_sBilinearBlocks, ftransblock.xy); + + // this is faster on ffx ingame + colors.x = tex2D(g_sBlocks, ftransblock.xy).a; + colors.y = tex2D(g_sBlocks, ftransblock.zy).a; + colors.z = tex2D(g_sBlocks, ftransblock.xw).a; + colors.w = tex2D(g_sBlocks, ftransblock.zw).a; + + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z + g_fPageOffset.w; + + // combine + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +void ps2memcoord4_fast(float4 orgtex, out float4 off0, out float4 off1) +{ + float4 realtex; + + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float2 ftransblock = g_fTexBlock.xy*fblock.xy + g_fTexBlock.zw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors = tex2D(g_sBilinearBlocks, ftransblock.xy); + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z; + + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +// Wrapping modes +#if defined(REPEAT) + +float2 ps2addr(float2 coord) +{ + return frac(coord.xy); +} + +#elif defined(CLAMP) + +float2 ps2addr(float2 coord) +{ + return clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw); +} + +#elif defined(REGION_REPEAT) + +// computes the local tex coord along with addressing modes +float2 ps2addr(float2 coord) +{ + float2 final = frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); + + if( TexWrapMode.x > g_fBilinear.z ) // region repeat mode for x (umsk&x)|ufix + final.x = tex2D(g_sBitwiseANDX, abs(coord.x)*TexWrapMode.zz).x * g_fClampExts.x + g_fClampExts.z; + if( TexWrapMode.y > g_fBilinear.z ) // region repeat mode for x (vmsk&x)|vfix + final.y = tex2D(g_sBitwiseANDY, abs(coord.y)*TexWrapMode.ww).x * g_fClampExts.y + g_fClampExts.w; + + return final; +} + +#else + +float2 ps2addr(float2 coord) +{ + return frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); +} + +#endif + +half4 tex2DPS_32(float2 tex0) +{ + return texRECT(g_sMemory, ps2memcoord(tex0).xy); +} + +// use when texture is not tiled +half4 tex2DPS_tex32(float2 tex0) +{ + return texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; +} + +// use when texture is not tiled +half4 tex2DPS_clut32(float2 tex0) +{ + float index = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw).a+g_fPageOffset.w; + return tex2D(g_sCLUT, index*g_fExactColor.xz+g_fExactColor.yz); +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 tex2DPS_tex32to16(float2 tex0) +{ + bool upper = false; + tex0.y += g_fPageOffset.z; + float2 ffrac = fmod(tex0, g_fTexOffset.xy); + tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv+g_fPageOffset.xy); +} + +// used when a 16 bit texture is used an 8h +half4 tex2DPS_tex16to8h(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + + if( ffrac.x > g_fTexOffset.x*g_fc0.w ) + tex0.x += g_fTexOffset.x*g_fc0.w; + if( tex0.x >= g_fc0.y ) tex0 += g_fTexOffset.zw; + + float4 upper = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + // only need alpha + float index = tex3D(g_sConv32to16, upper.zyx-g_fc0.z).y + upper.w*g_fc0.w*g_fc0.w; + return tex2D(g_sCLUT, index+g_fExactColor.yz); +} + +//half4 f; +//f.w = old.y > (127.2f/255.0f) ? 1 : 0; +//old.y -= 0.5f * f.w; +//f.xyz = frac(old.yyx*half3(2.002*255.0f/256.0f, 64.025f*255.0f/256.0f, 8.002*255.0f/256.0f)); +//f.y += old.x * (0.25f*255.0f/256.0f); + +//////////////////////////////// +// calculates the texture color +//////////////////////////////// + +#define decl_ps2shade(num) \ +decl_ps2shade_##num(_32) \ +decl_ps2shade_##num(_tex32) \ +decl_ps2shade_##num(_clut32) \ +decl_ps2shade_##num(_tex32to16) \ +decl_ps2shade_##num(_tex16to8h) \ + +// nearest +#define decl_ps2shade_0(bit) \ +half4 ps2shade0##bit( TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// do fast memcoord4 calcs when textures behave well +#ifdef REPEAT +#define PS2MEMCOORD4 ps2memcoord4 +#else +#define PS2MEMCOORD4 ps2memcoord4 +#endif + +#define decl_BilinearFilter(bit, addrfn) \ +half4 BilinearFilter##bit(float2 tex0) \ +{ \ + float4 off0, off1; \ + float4 ftex; \ + float2 ffrac; \ + ftex.xy = tex0 + g_fBilinear.xy * g_fRealTexDims.zw; \ + ffrac = frac(ftex.xy*g_fRealTexDims.xy); \ + ftex.xy -= ffrac.xy * g_fRealTexDims.zw; \ + \ + ftex.zw = ps2addr(ftex.xy + g_fRealTexDims.zw); \ + ftex.xy = ps2addr(ftex.xy); \ + \ + PS2MEMCOORD4(ftex, off0, off1); \ + half4 c0 = texRECT(g_sMemory, off0.xy); \ + half4 c1 = texRECT(g_sMemory, off0.zw); \ + half4 c2 = texRECT(g_sMemory, off1.xy); \ + half4 c3 = texRECT(g_sMemory, off1.zw); \ + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); \ +} \ + +decl_BilinearFilter(_32, ps2addr) +decl_BilinearFilter(_tex32, ps2addr) +decl_BilinearFilter(_clut32, ps2addr) +decl_BilinearFilter(_tex32to16, ps2addr) +decl_BilinearFilter(_tex16to8h, ps2addr) + +//TODO! For mip maps, only apply when LOD >= 0 +// lcm == 0, LOD = log(1/Q)*L + K, lcm == 1, LOD = K + +// bilinear +#define decl_ps2shade_1(bit) \ +half4 ps2shade1##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// nearest, mip nearest +#define decl_ps2shade_2(bit) \ +half4 ps2shade2##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// nearest, mip linear +#define decl_ps2shade_3(bit) \ +half4 ps2shade3##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit(ps2addr(TEX_XY)); \ +} \ + +// linear, mip nearest +#define decl_ps2shade_4(bit) \ +half4 ps2shade4##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// linear, mip linear +#define decl_ps2shade_5(bit) \ +half4 ps2shade5##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +decl_ps2shade(0) +decl_ps2shade(1) +decl_ps2shade(2) +decl_ps2shade(3) +decl_ps2shade(4) +decl_ps2shade(5) + +half4 ps2CalcShade(half4 texcol, half4 color) +{ +#ifdef TEST_AEM + if( dot(texcol.xyzw, g_fTestBlack.xyzw) <= g_fc0.z ) + texcol.w = g_fc0.x; + else +#endif + texcol.w = texcol.w * fTexAlpha.y + fTexAlpha.x; + + texcol = texcol * (fTexAlpha2.zzzw * color + fTexAlpha2.xxxy) + fTexAlpha.zzzw * color.wwww; + + return texcol; +} + +// final ops on the color +#ifdef EXACT_COLOR + +half4 ps2FinalColor(half4 col) +{ + // g_fOneColor has to scale by 255 + half4 temp = col * g_fOneColor.xxxy + g_fOneColor.zzzw; + temp.w = floor(temp.w)*g_fExactColor.w; + return temp; +} + +#else +half4 ps2FinalColor(half4 col) +{ + return col * g_fOneColor.xxxy + g_fOneColor.zzzw; +} +#endif + +//////////////// +// Techniques // +//////////////// + +// technique to copy a rectangle from source to target +struct VSOUT_ +{ + float4 pos : POSITION; + half4 color : COLOR0; + DOZWRITE(float4 z : TEXCOORD0;) +}; + +struct VSOUT_T +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_F +{ + float4 pos : POSITION; + half4 color : COLOR0; + float fog : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_TF +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + half fog : TEXCOORD1; + DOZWRITE(float4 z : TEXCOORD2;) +}; + +// just smooth shadering +VSOUT_ RegularVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1 + ) +{ + VSOUT_ o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; // 1 + o.color = color; + + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + return o; +} + +void RegularPS(VSOUT_ i, out float4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + // whenever outputting depth, make sure to mult by 255/256 and 1 + c0 = ps2FinalColor(i.color); + DOZWRITE(c1 = i.z;) +} + +// diffuse texture mapping +VSOUT_T TextureVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1, + float3 tex0 : TEXCOORD0) +{ + VSOUT_T o; + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x + g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0, out float4 c1 : COLOR1) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ +} \ + +#endif + +#define DECL_TEXPS_(num) \ +DECL_TEXPS(num, _32) \ +DECL_TEXPS(num, _tex32) \ +DECL_TEXPS(num, _clut32) \ +DECL_TEXPS(num, _tex32to16) \ +DECL_TEXPS(num, _tex16to8h) \ + +DECL_TEXPS_(0) +DECL_TEXPS_(1) +DECL_TEXPS_(2) +DECL_TEXPS_(3) +DECL_TEXPS_(4) +DECL_TEXPS_(5) + +VSOUT_F RegularFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1) +{ + VSOUT_F o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + o.color = color; + o.fog = pos.z*g_fBilinear.w; + return o; +} + +void RegularFogPS(VSOUT_F i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + half4 c; + c.xyz = lerp(g_fFogColor.xyz, i.color.xyz, i.fog); + c.w = i.color.w; + c0 = ps2FinalColor(c); + DOZWRITE(c1 = i.z;) +} + +VSOUT_TF TextureFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1, + float3 tex0 : TEXCOORD0) +{ + VSOUT_TF o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + o.fog = pos.z*g_fBilinear.w; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0, out float4 c1 : COLOR1 ) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ +} \ + +#endif + +#define DECL_TEXFOGPS_(num) \ +DECL_TEXFOGPS(num, _32) \ +DECL_TEXFOGPS(num, _tex32) \ +DECL_TEXFOGPS(num, _clut32) \ +DECL_TEXFOGPS(num, _tex32to16) \ +DECL_TEXFOGPS(num, _tex16to8h) \ + +DECL_TEXFOGPS_(0) +DECL_TEXFOGPS_(1) +DECL_TEXFOGPS_(2) +DECL_TEXFOGPS_(3) +DECL_TEXFOGPS_(4) +DECL_TEXFOGPS_(5) + +//------------------------------------------------------- +// Techniques not related to the main primitive commands +half4 BilinearBitBlt(float2 tex0) +{ + float4 ftex; + float2 ffrac; + + ffrac.xy = frac(tex0*g_fRealTexDims.xy); + ftex.xy = tex0 - ffrac.xy * g_fRealTexDims.zw; + ftex.zw = ftex.xy + g_fRealTexDims.zw; + + float4 off0, off1; + ps2memcoord4_fast(ftex, off0, off1); + half4 c0 = texRECT(g_sMemory, off0.xy); + half4 c1 = texRECT(g_sMemory, off0.zw); + half4 c2 = texRECT(g_sMemory, off1.xy); + half4 c3 = texRECT(g_sMemory, off1.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); +} + +void BitBltVS(in float4 pos : POSITION, + in half4 tex0 : COLOR1, + in float3 tex : TEXCOORD0, + out float4 opos : POSITION, + out float2 otex0 : TEXCOORD0, + out float2 ointerpos : TEXCOORD1) +{ + opos.xy = pos.xy * g_fBitBltPos.xy + g_fBitBltPos.zw; + ointerpos = opos.xy * g_fBitBltTrans.xy + g_fBitBltTrans.zw; + opos.zw = g_fc0.xy; + otex0 = tex.xy * g_fBitBltTex.xy + g_fBitBltTex.zw; +} + +half4 BitBltPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return texRECT(g_sMemory, ps2memcoord(tex0).xy)*g_fOneColor.xxxy; +} + +// used when AA +half4 BitBltAAPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return BilinearBitBlt(tex0)*g_fOneColor.xxxy; +} + +void BitBltDepthPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = texRECT(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c, g_fBitBltZ))*g_fOneColor.w; + c += g_fZBias.y; +} + +void BitBltDepthMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = texRECT(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c1, g_fBitBltZ))*g_fOneColor.w; + c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +/*static const float BlurKernel[9] = { + 0.027601, + 0.066213, + 0.123701, + 0.179952, + 0.205065, + 0.179952, + 0.123701, + 0.066213, + 0.027601 +};*/ + +half4 BilinearFloat16(float2 tex0) +{ + /*float4 ffrac, ftex; + ffrac.xy = frac(tex0); + ftex.xy = (tex0 - ffrac.xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + ftex.zw = ftex.xy + g_fInvTexDims.xy; + + half4 c0 = texRECT(g_sSrcFinal, ftex.xy); + half4 c1 = texRECT(g_sSrcFinal, ftex.zy); + half4 c2 = texRECT(g_sSrcFinal, ftex.xw); + half4 c3 = texRECT(g_sSrcFinal, ftex.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y );*/ + return texRECT(g_sSrcFinal, tex0.xy); +// return 0.55f * texRECT(g_sSrcFinal, tex0.xy) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.xz) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.zy) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.xy); +} + +half4 CRTCTargInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCTargPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +// simpler +half4 CRTCInterPS_Nearest(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = texRECT(g_sMemory, ps2memcoord(tex0).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0/*-frac(tex0)*/)*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +// simpler +half4 CRTCPS_Nearest(in float2 tex0 : TEXCOORD0) : COLOR +{ + half4 c = texRECT(g_sMemory, ps2memcoord(tex0).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTC24InterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = texRECT(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +half4 CRTC24PS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = texRECT(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +half4 ZeroPS() : COLOR +{ + return g_fOneColor.x; +} + +half4 BaseTexturePS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return texRECT(g_sSrcFinal, tex0) * g_fOneColor; +} + +half4 Convert16to32PS(float2 tex0 : TEXCOORD0) : COLOR +{ + float4 final; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.xy = g_fTexDims.xy * tex0.xy - ffrac * g_fc0.yw; + + if( ffrac.x > g_fTexOffset.x*g_fc0.w ) + tex0.x += g_fTexOffset.x*g_fc0.w; + if( tex0.x >= g_fc0.y ) tex0 += g_fTexOffset.zw; + + float4 lower = texRECT(g_sSrcFinal, tex0); + float4 upper = texRECT(g_sSrcFinal, tex0+g_fPageOffset.xy); + + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*g_fPageOffset.zw; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*g_fPageOffset.zw; + + return final; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 Convert32to16PS(float2 tex0 : TEXCOORD0) : COLOR +{ + bool upper = false; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texRECT(g_sSrcFinal, tex0*g_fTexDims.xy)*g_fc0.yyyw; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv*g_fPageOffset.xy+g_fPageOffset.zw)*g_fTexDims.xxxy; +} diff --git a/plugins/gs/zerogs/opengl/rasterfont.cpp b/plugins/gs/zerogs/opengl/rasterfont.cpp new file mode 100644 index 0000000000..787ee47b5f --- /dev/null +++ b/plugins/gs/zerogs/opengl/rasterfont.cpp @@ -0,0 +1,147 @@ + +#ifdef _WIN32 +#include +#endif + +#include +#include + +#include "rasterfont.h" +// globals + +GLubyte rasters[][13] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} +}; + +RasterFont::RasterFont() +{ + // set GL modes + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // create the raster font + fontOffset = glGenLists (128); + for (int i = 32; i < 127; i++) { + glNewList(i+fontOffset, GL_COMPILE); + glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i-32]); + glEndList(); + } +} + +RasterFont::~RasterFont() +{ + glDeleteLists(fontOffset, 128); +} + +void RasterFont::printString(const char *s, double x, double y, double z) +{ + // go to the right spot + glRasterPos3d(x, y, z); + + glPushAttrib (GL_LIST_BIT); + glListBase(fontOffset); + glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); + glPopAttrib (); +} + +void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) +{ + int length = strlen(s); + int x = int(screen_width/2.0 - (length/2.0)*char_width); + + printString(s, x, y, z); +} + diff --git a/plugins/gs/zerogs/opengl/rasterfont.h b/plugins/gs/zerogs/opengl/rasterfont.h new file mode 100644 index 0000000000..a0c7118e5b --- /dev/null +++ b/plugins/gs/zerogs/opengl/rasterfont.h @@ -0,0 +1,22 @@ +#ifndef RasterFont_Header +#define RasterFont_Header + +class RasterFont { +protected: + int fontOffset; + +public: + RasterFont(); + ~RasterFont(void); + static int debug; + + // some useful constants + enum {char_width = 10}; + enum {char_height = 15}; + + // and the happy helper functions + void printString(const char *s, double x, double y, double z=0.0); + void printCenteredString(const char *s, double y, int screen_width, double z=0.0); +}; + +#endif diff --git a/plugins/gs/zerogs/opengl/targets.cpp b/plugins/gs/zerogs/opengl/targets.cpp new file mode 100644 index 0000000000..14729e00a1 --- /dev/null +++ b/plugins/gs/zerogs/opengl/targets.cpp @@ -0,0 +1,3544 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include +#include + +#include + +#include +#include +#include +#include + +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern BOOL g_bUpdateStencil; +extern u32 s_uFramebuffer; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern u8 s_AAx, s_AAy; + extern Vector g_vdepth; + extern int icurctx; + + extern VERTEXSHADER pvsBitBlt; + extern FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + extern FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern GLuint vboRect; +} + +extern u32 s_ptexCurSet[2]; +extern u32 ptexBilinearBlocks; +extern u32 ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) +{ + nUpdateTarg = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + vposxy.x = 2.0f * (1.0f / 8.0f) / (float)fbw; + vposxy.y = 2.0f * (1.0f / 8.0f) / (float)fbh; + vposxy.z = -1-0.5f/fbw; + vposxy.w = -1+0.5f/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + psys = _aligned_malloc( (fbh<= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + cgGLSetParameter4fv(g_vparamPosXY[context], v); + } + else + cgGLSetParameter4fv(g_vparamPosXY[context], vposxy); + + // set render states + scissorrect.x = scissor.x0>>3; + scissorrect.y = (scissor.y0>>3) + dy; + scissorrect.w = (scissor.x1>>3)+1; + scissorrect.h = (scissor.y1>>3)+1+dy; + scissorrect.w = min(scissorrect.w, fbw) - scissorrect.x; + scissorrect.h = min(scissorrect.h, fbh) - scissorrect.y; + + scissorrect.x <<= s_AAx; + scissorrect.y <<= s_AAy; + scissorrect.w <<= s_AAx; + scissorrect.h <<= s_AAy; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + glViewport(0, 0, fbw< 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) ) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + GL_REPORT_ERRORD(); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw< start ); // make sure it at least intersects + + if( ptex != 0 && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + + u8* pbits = (u8*)psys; + u32 Pitch = (fbw<SetDepthStencilSurface(psurfDepth); + ResetRenderTarget(1); + SetRenderTarget(0); + assert( pdepth != NULL ); + ((CDepthTarget*)pdepth)->SetDepthStencilSurface(); + + Vector v = Vector(1,-1,-0.5f/(float)(fbw<second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + + SetViewport(); + + if( nUpdateTarg ) { + + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ittarg->second->ptex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = (float)(fbw << s_AAx); + v.y = (float)(fbh << s_AAy); + v.z = 0.25f; + v.w = (float)(offset << s_AAy) + 0.25f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = 1; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + SETPIXELSHADER(ppsBaseTexture.prog); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, &ppsBitBlt[s_AAx], 1); + cgGLSetTextureParameter(ppsBitBlt[s_AAx].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBitBlt[s_AAx].sMemory); + + v = Vector(1,1,0,0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.x = 1; + v.y = 2; + cgGLSetParameter4fv(ppsBitBlt[s_AAx].sOneColor, v); + + assert( ptex != 0 ); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0xff); + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + //cgGLLoadProgram(ppsBitBlt[s_AAx].prog); + SETPIXELSHADER(ppsBitBlt[s_AAx].prog); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL)) { + glColorMask(0,0,0,0); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, 0xff); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glColorMask(1,1,1,1); + } + + glEnable(GL_SCISSOR_TEST); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pdepth->SetRenderTarget(1); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::ConvertTo16() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // render with an AA shader if possible (bilinearly interpolates data) + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsConvert32to16.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + SaveTexture("tex1.tga", GL_TEXTURE_RECTANGLE_NV, ptexConv, fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == 0 ) { + // create + glGenTextures(1, &ptexFeedback); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexFeedback); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +void ZeroGS::CRenderTarget::SetRenderTarget(int targ) +{ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+targ, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) + return false; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + assert( glGetError() == GL_NO_ERROR ); + + glGenRenderbuffersEXT( 1, &pdepth ); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, pdepth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, fbw< 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); + glDepthMask(1); + glDisable(GL_STENCIL_TEST); + glDepthFunc(GL_ALWAYS); + + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, &ppsBitBltDepth, 1); + cgGLSetTextureParameter(ppsBitBltDepth.sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + Vector v = Vector(1,-1,0.5f/(float)fbw,-0.5f/(float)fbh); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.z = v.w = 0; + v *= 1/32767.0f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + cgGLSetParameter4fv(ppsBitBltDepth.sOneColor, v); + + Vector vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + assert( ppsBitBltDepth.sBitBltZ != 0 ); + cgGLSetParameter4fv(ppsBitBltDepth.sBitBltZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != 0 ); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + SetDepthStencilSurface(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum buffer = GL_COLOR_ATTACHMENT0_EXT; + if( glDrawBuffers != NULL ) + glDrawBuffers(1, &buffer); + int stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBitBltDepth.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + status = TS_Resolved; + + if( !ZeroGS::IsWriteDepth() ) { + ResetRenderTarget(1); + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + SaveTex(&texframe, 1); + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + mapTargets.erase(it++); + } + else ++it; + } +} + +void ZeroGS::CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) +{ + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + delete ptarg; +} + +void ZeroGS::CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) +{ + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + + mapTargets.erase(it++); + } + else ++it; + } +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + GL_REPORT_ERRORD(); + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif +// if( g_GameSettings & GAME_VSSHACK ) { +// if( it->second->psm & 2 ) { +// it->second->status |= CRenderTarget::TS_NeedConvert32; +// it->second->fbh /= 2; +// } +// else { +// it->second->status |= CRenderTarget::TS_NeedConvert16; +// it->second->fbh *= 2; +// } +// } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->start <= it->second->start && itnew->second->end >= it->second->end && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbp != frame.fbp && it->second->fbw == frame.fbw) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAllTargs(start, end, frame.fbw); + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( timeGetTime()-it->second->lastused > 5000 ) { + delete it->second; + mapTargets.erase(it); + } + } + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + delete it->second; + mapDummyTargs.erase(it); + } + + // first search for the target + CRenderTarget* ptarg = NULL; + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)(uptr)pClutBuffer & 2) ? 0 : (((u32)(uptr)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + if( memcmp_mmx(&clut[0], g_pbyGSClut+nClutOffset, clutsize) ) + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + assert( ptex != NULL && ptex->memptr != NULL); + + int result = memcmp_mmx(ptex->memptr + (checkstarty-realy)*4*GPU_TEXWIDTH, g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + DVProfileFunc _pf("GetMemoryTarget"); + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { + if( memcmp_mmx(&it->clut[0], g_pbyGSClut+nClutOffset, clutsize) ) { + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + + ++it; + } + + // couldn't find so create + DVProfileFunc _pf1("GetMemoryTarget:Create"); + + CMemoryTarget* targ; + + u32 fmt = GL_UNSIGNED_BYTE; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult && itbest->channels == channels ) { + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + targ->channels = channels; + + // alloc the mem + targ->ptex = new CMemoryTarget::TEXTURE(); + targ->ptex->ref = 1; + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + // fill with data + if( targ->ptex->memptr == NULL ) { + targ->ptex->memptr = (u8*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + assert(targ->ptex->ref > 0 ); + } + + memcpy_amd(targ->ptex->memptr, g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + vector texdata; + u8* ptexdata = NULL; + + if( PSMT_ISCLUT(tex0.psm) ) { + + texdata.resize( (tex0.cpsm <= 1?4:2) *GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + + u8* psrc = (u8*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)ptexdata; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)ptexdata; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + texdata.resize(4*GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)ptexdata; + u16* src = (u16*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)(uptr)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(_MSC_VER) + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else // _MSC_VER + + __asm__(".intel_syntax\n" + "pxor %%xmm7, %%xmm7\n" + + "Z16Loop:\n" + // unpack 64 bytes at a time + "movdqa %%xmm0, [%0]\n" + "movdqa %%xmm2, [%0+16]\n" + "movdqa %%xmm4, [%0+32]\n" + "movdqa %%xmm6, [%0+48]\n" + + "movdqa %%xmm1, %%xmm0\n" + "movdqa %%xmm3, %%xmm2\n" + "movdqa %%xmm5, %%xmm4\n" + + "punpcklwd %%xmm0, %%xmm7\n" + "punpckhwd %%xmm1, %%xmm7\n" + "punpcklwd %%xmm2, %%xmm7\n" + "punpckhwd %%xmm3, %%xmm7\n" + + // start saving + "movdqa [%1], %%xmm0\n" + "movdqa [%1+16], %%xmm1\n" + + "punpcklwd %%xmm4, %%xmm7\n" + "punpckhwd %%xmm5, %%xmm7\n" + + "movdqa [%1+32], %%xmm2\n" + "movdqa [%1+48], %%xmm3\n" + + "movdqa %%xmm0, %%xmm6\n" + "punpcklwd %%xmm6, %%xmm7\n" + + "movdqa [%1+64], %%xmm4\n" + "movdqa [%1+80], %%xmm5\n" + + "punpckhwd %%xmm0, %%xmm7\n" + + "movdqa [%1+96], %%xmm6\n" + "movdqa [%1+112], %%xmm0\n" + + "add %0, 64\n" + "add %1, 128\n" + "sub %2, 1\n" + "jne Z16Loop\n" + ".att_syntax\n" : "=r"(src), "=r"(dst), "=r"(iters) : "0"(src), "1"(dst), "2"(iters)); + +#endif // _MSC_VER +#else // ZEROGS_SSE2 + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif // ZEROGS_SSE2 + } + else { + ptexdata = targ->ptex->memptr; + } + } + + // create the texture + GL_REPORT_ERRORD(); + assert(ptexdata != NULL); + if( targ->ptex->tex == 0 ) + glGenTextures(1, &targ->ptex->tex); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, targ->ptex->tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, fmt==GL_UNSIGNED_BYTE?4:GL_RGB5_A1, GPU_TEXWIDTH*channels*widthmult, + (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + + int realheight = targ->realheight; + while( glGetError() != GL_NO_ERROR ) { + + // release resources until can create + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + ERROR_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (realheight+widthmult-1)/widthmult); + channels = 1; + return NULL; + } + DestroyOldest(); + } + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + } + + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + glDeleteTextures(1, &it->second); + mapTextures.clear(); +} + +u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + glDeleteTextures(1, &it->second); + mapTextures.erase(it++); + } + else ++it; + } + } + + // create a new tex + u32 ptex; + glGenTextures(1, &ptex); + + vector data(GPU_TEXMASKWIDTH); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) + data[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + + glBindTexture(GL_TEXTURE_2D, ptex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, GPU_TEXMASKWIDTH, 1, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, &data[0]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + ERROR_LOG("Failed to create bitmask texture\n"); + return 0; + } + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + Flush(0); + Flush(1); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].nCount > 0 ) + Flush(0); + if( vb[1].nCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].nCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].nCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + DVProfileFunc _pf("TransferHostLocal"); + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //ERROR_LOG("resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) ERROR_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// ERROR_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + int Pitch; + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)psrc; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + frame##SwizzleBlock##blockbits(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { // float16 + + Pitch = fbw * 8; + + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + vector data(ptex->tw*ptex->th); + vector srcdata; + + u32* dst = &data[0]; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 0); + assert( pmemtarg != NULL ); + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex); + srcdata.resize(pmemtarg->realheight*GPU_TEXWIDTH*pmemtarg->widthmult*4*8); // max of 8 cannels + + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, pmemtarg->fmt, &srcdata[0]); + + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = &srcdata[0] - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + } + + SaveTGA("tex.tga", ptex->tw, ptex->th, &data[0]); +} + +} diff --git a/plugins/gs/zerogs/opengl/targets.h b/plugins/gs/zerogs/opengl/targets.h new file mode 100644 index 0000000000..6c7bfdf6a1 --- /dev/null +++ b/plugins/gs/zerogs/opengl/targets.h @@ -0,0 +1,160 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS { + + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, u32 Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyAllTargs(int start, int end, int fbw); + void DestroyIntersecting(CRenderTarget* prndr); + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + static void DestroyTarg(CRenderTarget* ptarg); + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline u32 GetTex(u32 bitvalue, u32 ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + u32 GetTexInt(u32 bitvalue, u32 ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/gs/zerogs/opengl/x86-32.S b/plugins/gs/zerogs/opengl/x86-32.S new file mode 100644 index 0000000000..73b11f11d6 --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86-32.S @@ -0,0 +1,1002 @@ +# Copyright (C) 2005-2006 zerofrog(@gmail.com) +# +# 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 ve%rsion 2, or (at your option) +# any later ve%rsion. +# +# 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 GNU Make see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +# +# +.intel_syntax + +## mmx memcpy implementation, size has to be a multiple of 8 +## returns 0 is equal, nonzero value if not equal +## ~10 times faster than standard memcmp +## (zerofrog) +#u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +.globl memcmp_mmx + .type memcmp_mmx, @function +memcmp_mmx: + push %esi + mov %ecx, dword ptr [%esp+16] + mov %edx, dword ptr [%esp+8] + mov %esi, dword ptr [%esp+12] + + cmp %ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq %mm0, [%esi] + movq %mm1, [%esi+8] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pand %mm0, %mm1 + movq %mm2, [%esi+16] + pmovmskb %eax, %mm0 + movq %mm3, [%esi+24] + + // check if eq + cmp %eax, 0xff + je NextComp + mov %eax, 1 + jmp End + +NextComp: + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm2, %mm3 + pmovmskb %eax, %mm2 + + sub %ecx, 32 + add %esi, 32 + add %edx, 32 + + // check if eq + cmp %eax, 0xff + je ContinueTest + mov %eax, 1 + jmp End + + cmp %ecx, 64 + jl Done8 + +Cmp8: + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + movq %mm3, [%esi+24] + movq %mm4, [%esi+32] + movq %mm5, [%esi+40] + movq %mm6, [%esi+48] + movq %mm7, [%esi+56] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm0, %mm1 + pcmpeqd %mm4, [%edx+32] + pand %mm0, %mm2 + pcmpeqd %mm5, [%edx+40] + pand %mm0, %mm3 + pcmpeqd %mm6, [%edx+48] + pand %mm0, %mm4 + pcmpeqd %mm7, [%edx+56] + pand %mm0, %mm5 + pand %mm0, %mm6 + pand %mm0, %mm7 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Continue + mov %eax, 1 + jmp End + +Continue: + sub %ecx, 64 + add %esi, 64 + add %edx, 64 +ContinueTest: + cmp %ecx, 64 + jge Cmp8 + +Done8: + test %ecx, 0x20 + jz Done4 + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + movq %mm3, [%esi+24] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm0, %mm1 + pand %mm0, %mm2 + pand %mm0, %mm3 + pmovmskb %eax, %mm0 + sub %ecx, 32 + add %esi, 32 + add %edx, 32 + + // check if eq + cmp %eax, 0xff + je Done4 + mov %eax, 1 + jmp End + +Done4: + cmp %ecx, 24 + jne Done2 + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pand %mm0, %mm1 + pand %mm0, %mm2 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + setne %al + jmp End + +Done2: + cmp %ecx, 16 + jne Done1 + + movq %mm0, [%esi] + movq %mm1, [%esi+8] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pand %mm0, %mm1 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + setne %al + jmp End + +Done1: + cmp %ecx, 8 + jne Done + + mov %eax, [%esi] + mov %esi, [%esi+4] + cmp %eax, [%edx] + je Next + mov %eax, 1 + jmp End + +Next: + cmp %esi, [%edx+4] + setne %al + jmp End + +Done: + xor %eax, %eax + +End: + pop %esi + emms + ret + + +#ifdef ZEROGS_SSE2 +// SSE2 extensions +#define punpck(op, sd0, sd2, s1, s3, d1, d3) \ + movdqa %xmm##d1, %xmm##sd0; \ + pshufd %xmm##d3, %xmm##sd2, 0xe4; \ + punpckl##op %xmm##sd0, %xmm##s1; \ + punpckh##op %xmm##d1, %xmm##s1; \ + punpckl##op %xmm##sd2, %xmm##s3; \ + punpckh##op %xmm##d3, %xmm##s3; \ + + +#define punpcknb \ + movdqa %xmm4, %xmm0; \ + pshufd %xmm5, %xmm1, 0xe4; \ + \ + psllq %xmm1, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm0, %xmm7; \ + pandn %xmm6, %xmm1; \ + por %xmm0, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm1, %xmm4; \ + \ + movdqa %xmm4, %xmm2; \ + pshufd %xmm5, %xmm3, 0xe4; \ + \ + psllq %xmm3, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm2, %xmm7; \ + pandn %xmm6, %xmm3; \ + por %xmm2, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm3, %xmm4; \ + \ + punpck(bw, 0, 2, 1, 3, 4, 6); \ + + +// +// swizzling +// + +// +// SwizzleBlock32 +// + +.globl SwizzleBlock32_sse2 + .type SwizzleBlock32_sse2, @function +SwizzleBlock32_sse2: + + push %esi + push %edi + + mov %edi, %ecx + mov %esi, %edx + mov %edx, [%esp+4+8] + mov %ecx, 4 + + mov %eax, [%esp+8+8] + cmp %eax, 0xffffffff + jne SwizzleBlock32_sse2_2 + + .align 16 +SwizzleBlock32_sse2_1: + movdqa %xmm0, [%esi] + movdqa %xmm4, [%esi+16] + movdqa %xmm1, [%esi+%edx] + movdqa %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movntps [%edi+16*0], %xmm0 + movntps [%edi+16*1], %xmm2 + movntps [%edi+16*2], %xmm4 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32_sse2_1 + + pop %edi + pop %esi + + ret 8 + +SwizzleBlock32_sse2_2: + + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32_sse2_3: + movdqa %xmm0, [%esi] + movdqa %xmm4, [%esi+16] + movdqa %xmm1, [%esi+%edx] + movdqa %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movntps [%edi+16*0], %xmm0 + + pandn %xmm5, [%edi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movntps [%edi+16*1], %xmm2 + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm3 + movntps [%edi+16*2], %xmm4 + + pandn %xmm5, [%edi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm5 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32_sse2_3 + + pop %edi + pop %esi + + ret 8 + +// +// SwizzleBlock16 +// + +.globl SwizzleBlock16_sse2 + .type SwizzleBlock16_sse2, @function +SwizzleBlock16_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 4 + + .align 16 +SwizzleBlock16_sse2_1: + movdqa %xmm0, [%edx] + movdqa %xmm1, [%edx+16] + movdqa %xmm2, [%edx+%ebx] + movdqa %xmm3, [%edx+%ebx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm5 + + lea %edx, [%edx+%ebx*2] + add %ecx, 64 + + dec %eax + jnz SwizzleBlock16_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock8 +// + +.globl SwizzleBlock8_sse2 + .type SwizzleBlock8_sse2, @function +SwizzleBlock8_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock8_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshufd %xmm1, [%edx], 0xb1 + pshufd %xmm3, [%edx+%ebx], 0xb1 + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm4 + movntps [%ecx+16*2], %xmm1 + movntps [%ecx+16*3], %xmm5 + + // col 1, 3 + + pshufd %xmm0, [%edx], 0xb1 + pshufd %xmm2, [%edx+%ebx], 0xb1 + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm4 + movntps [%ecx+16*6], %xmm1 + movntps [%ecx+16*7], %xmm5 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock8_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock4 +// + +.globl SwizzleBlock4_sse2 + .type SwizzleBlock4_sse2, @function +SwizzleBlock4_sse2: + + push %ebx + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock4_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm3 + + // col 1, 3 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm1 + movntps [%ecx+16*6], %xmm4 + movntps [%ecx+16*7], %xmm3 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock4_sse2_1 + + pop %ebx + + ret 4 + +// +// swizzling with unaligned reads +// + +// +// SwizzleBlock32u +// + +.globl SwizzleBlock32u_sse2 + .type SwizzleBlock32u_sse2, @function +SwizzleBlock32u_sse2: + + push %esi + push %edi + + mov %edi, %ecx + mov %esi, %edx + mov %edx, [%esp+4+8] + mov %ecx, 4 + + mov %eax, [%esp+8+8] + cmp %eax, 0xffffffff + jne SwizzleBlock32u_sse2_2 + + .align 16 +SwizzleBlock32u_sse2_1: + movdqu %xmm0, [%esi] + movdqu %xmm4, [%esi+16] + movdqu %xmm1, [%esi+%edx] + movdqu %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movntps [%edi+16*0], %xmm0 + movntps [%edi+16*1], %xmm2 + movntps [%edi+16*2], %xmm4 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32u_sse2_1 + + pop %edi + pop %esi + + ret 8 + +SwizzleBlock32u_sse2_2: + + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32u_sse2_3: + movdqu %xmm0, [%esi] + movdqu %xmm4, [%esi+16] + movdqu %xmm1, [%esi+%edx] + movdqu %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%edi+16*0], %xmm0 + + pandn %xmm5, [%edi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%edi+16*1], %xmm2 + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm3 + movdqa [%edi+16*2], %xmm4 + + pandn %xmm5, [%edi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm5 + movdqa [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32u_sse2_3 + + pop %edi + pop %esi + + ret 8 + +// +// SwizzleBlock16u +// + +.globl SwizzleBlock16u_sse2 + .type SwizzleBlock16u_sse2, @function +SwizzleBlock16u_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 4 + + .align 16 +SwizzleBlock16u_sse2_1: + movdqu %xmm0, [%edx] + movdqu %xmm1, [%edx+16] + movdqu %xmm2, [%edx+%ebx] + movdqu %xmm3, [%edx+%ebx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm5 + + lea %edx, [%edx+%ebx*2] + add %ecx, 64 + + dec %eax + jnz SwizzleBlock16u_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock8u +// + +.globl SwizzleBlock8u_sse2 + .type SwizzleBlock8u_sse2, @function +SwizzleBlock8u_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock8u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + pshufd %xmm1, %xmm1, 0xb1 + pshufd %xmm3, %xmm3, 0xb1 + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm4 + movntps [%ecx+16*2], %xmm1 + movntps [%ecx+16*3], %xmm5 + + // col 1, 3 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + pshufd %xmm0, %xmm0, 0xb1 + pshufd %xmm2, %xmm2, 0xb1 + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm4 + movntps [%ecx+16*6], %xmm1 + movntps [%ecx+16*7], %xmm5 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock8u_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock4u +// + +.globl SwizzleBlock4u_sse2 + .type SwizzleBlock4u_sse2, @function +SwizzleBlock4u_sse2: + + push %ebx + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock4u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm3 + + // col 1, 3 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm1 + movntps [%ecx+16*6], %xmm4 + movntps [%ecx+16*7], %xmm3 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock4u_sse2_1 + + pop %ebx + + ret 4 + + + .align 16 +s_clut16mask: + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + + .align 16 +s_clut16mask2: + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + +.globl WriteCLUT_T16_I4_CSM1_sse2 + .type WriteCLUT_T16_I4_CSM1_sse2, @function +WriteCLUT_T16_I4_CSM1_sse2: + movdqa %xmm0, xmmword ptr [%ecx] + movdqa %xmm1, xmmword ptr [%ecx+16] + movdqa %xmm2, xmmword ptr [%ecx+32] + movdqa %xmm3, xmmword ptr [%ecx+48] + + // rearrange + pshuflw %xmm0, %xmm0, 0x88 + pshufhw %xmm0, %xmm0, 0x88 + pshuflw %xmm1, %xmm1, 0x88 + pshufhw %xmm1, %xmm1, 0x88 + pshuflw %xmm2, %xmm2, 0x88 + pshufhw %xmm2, %xmm2, 0x88 + pshuflw %xmm3, %xmm3, 0x88 + pshufhw %xmm3, %xmm3, 0x88 + + shufps %xmm0, %xmm1, 0x88 + shufps %xmm2, %xmm3, 0x88 + + pshufd %xmm0, %xmm0, 0xd8 + pshufd %xmm2, %xmm2, 0xd8 + + pxor %xmm6, %xmm6 + + test %edx, 15 + jnz WriteUnaligned + + movdqa %xmm7, [s_clut16mask] // saves upper 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%edx] + movdqa %xmm5, [%edx+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + + movdqa [%edx], %xmm0 + movdqa [%edx+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%edx+16] + pand %xmm5, [%edx+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%edx+16], %xmm2 + movdqa [%edx+48], %xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + // %edx is offset by 2 + sub %edx, 2 + + movdqa %xmm7, [s_clut16mask2] // saves lower 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%edx] + movdqa %xmm5, [%edx+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + pslld %xmm0, 16 + pslld %xmm1, 16 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + pslld %xmm2, 16 + pslld %xmm3, 16 + + movdqa [%edx], %xmm0 + movdqa [%edx+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%edx+16] + pand %xmm5, [%edx+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%edx+16], %xmm2 + movdqa [%edx+48], %xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + + +.globl WriteCLUT_T32_I8_CSM1_sse2 + .type WriteCLUT_T32_I8_CSM1_sse2, @function +WriteCLUT_T32_I8_CSM1_sse2: + push %ebx + xor %ebx, %ebx +.L231: + xor %eax, %eax + .align 16 +.L232: + movdqa %xmm3, XMMWORD PTR [%eax+16+%ecx] + movdqa %xmm4, XMMWORD PTR [%eax+48+%ecx] + movdqa %xmm1, XMMWORD PTR [%eax+%ecx] + movdqa %xmm2, XMMWORD PTR [%eax+32+%ecx] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+32+%eax*2], %xmm1 + movdqa XMMWORD PTR [%edx+%eax*2], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+48+%eax*2], %xmm2 + movdqa XMMWORD PTR [%edx+16+%eax*2], %xmm0 + movdqa %xmm1, XMMWORD PTR [%eax+256+%ecx] + movdqa %xmm3, XMMWORD PTR [%eax+272+%ecx] + movdqa %xmm2, XMMWORD PTR [%eax+288+%ecx] + movdqa %xmm4, XMMWORD PTR [%eax+304+%ecx] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+96+%eax*2], %xmm1 + movdqa XMMWORD PTR [%edx+64+%eax*2], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+112+%eax*2], %xmm2 + movdqa XMMWORD PTR [%edx+80+%eax*2], %xmm0 + add %eax, 64 + cmp %eax, 256 + jne .L232 + add %edx, 512 + add %ecx, 512 + add %ebx, 512 + cmp %ebx, 1024 + jne .L231 + pop %ebx + ret + +.globl WriteCLUT_T32_I4_CSM1_sse2 + .type WriteCLUT_T32_I4_CSM1_sse2, @function +WriteCLUT_T32_I4_CSM1_sse2: + movdqa %xmm1, XMMWORD PTR [%ecx] + movdqa %xmm3, XMMWORD PTR [%ecx+16] + movdqa %xmm2, XMMWORD PTR [%ecx+32] + movdqa %xmm4, XMMWORD PTR [%ecx+48] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+32], %xmm1 + movdqa XMMWORD PTR [%edx], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+48], %xmm2 + movdqa XMMWORD PTR [%edx+16], %xmm0 + ret + +#endif diff --git a/plugins/gs/zerogs/opengl/x86-32.asm b/plugins/gs/zerogs/opengl/x86-32.asm new file mode 100644 index 0000000000..1507d2192d --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86-32.asm @@ -0,0 +1,652 @@ +; Copyright (C) 2003-2005 Gabest +; http://www.gabest.org +; +; This Program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2, or (at your option) +; any later version. +; +; This Program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http://www.gnu.org/copyleft/gpl.html +; +; + .686 + .model flat + .mmx + .xmm + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknb macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + + +; +; swizzling +; + +; +; SwizzleBlock32 +; + +@SwizzleBlock32_sse2@16 proc public + + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movntps [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movntps [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movntps [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32_sse2@16 endp + +; +; SwizzleBlock16 +; + +@SwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [edx] + movdqa xmm1, [edx+16] + movdqa xmm2, [edx+ebx] + movdqa xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16_sse2@12 endp + +; +; SwizzleBlock8 +; + +@SwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + pshufd xmm1, [edx], 0b1h + pshufd xmm3, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [edx], 0b1h + pshufd xmm2, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8_sse2@12 endp + +; +; SwizzleBlock4 +; + +@SwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4_sse2@12 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u +; + +@SwizzleBlock32u_sse2@16 proc public + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32u_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32u_sse2@16 endp + +; +; SwizzleBlock16u +; + +@SwizzleBlock16u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqu xmm0, [edx] + movdqu xmm1, [edx+16] + movdqu xmm2, [edx+ebx] + movdqu xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16u_sse2@12 endp + +; +; SwizzleBlock8u +; + +@SwizzleBlock8u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8u_sse2@12 endp + +; +; SwizzleBlock4u +; + +@SwizzleBlock4u_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4u_sse2@12 endp + + end \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/x86-64.S b/plugins/gs/zerogs/opengl/x86-64.S new file mode 100644 index 0000000000..6f221e7b33 --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86-64.S @@ -0,0 +1,906 @@ +## Copyright (C) 2005-2006 zerofrog(@gmail.com) +# +# 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 ve%rsion 2, or (at your option) +# any later ve%rsion. +# +# 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 GNU Make see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +# +# +.intel_syntax + +## mmx memcpy implementation, size has to be a multiple of 8 +## returns 0 is equal, nonzero value if not equal +## ~10 times faster than standard memcmp +## (zerofrog) +## u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +## %rdi - src1 +## %rsi - src2 +## edx - cmpsize +.globl memcmp_mmx + .type memcmp_mmx, @function +memcmp_mmx: + cmp %edx, 32 + jl Done4 + + ## custom test first 8 to make sure things are ok + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pand %mm0, %mm1 + movq %mm2, [%rsi+16] + pmovmskb %eax, %mm0 + movq %mm3, [%rsi+24] + + // check if eq + cmp %eax, 0xff + je NextComp + mov %eax, 1 + jmp End + +NextComp: + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm2, %mm3 + pmovmskb %eax, %mm2 + + sub %edx, 32 + add %rsi, 32 + add %rdi, 32 + + // check if eq + cmp %eax, 0xff + je ContinueTest + mov %eax, 1 + jmp End + + cmp %edx, 64 + jl Done8 + +Cmp8: + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + movq %mm3, [%rsi+24] + movq %mm4, [%rsi+32] + movq %mm5, [%rsi+40] + movq %mm6, [%rsi+48] + movq %mm7, [%rsi+56] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm0, %mm1 + pcmpeqd %mm4, [%rdi+32] + pand %mm0, %mm2 + pcmpeqd %mm5, [%rdi+40] + pand %mm0, %mm3 + pcmpeqd %mm6, [%rdi+48] + pand %mm0, %mm4 + pcmpeqd %mm7, [%rdi+56] + pand %mm0, %mm5 + pand %mm0, %mm6 + pand %mm0, %mm7 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Continue + mov %eax, 1 + jmp End + +Continue: + sub %edx, 64 + add %rsi, 64 + add %rdi, 64 +ContinueTest: + cmp %edx, 64 + jge Cmp8 + +Done8: + test %edx, 0x20 + jz Done4 + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + movq %mm3, [%rsi+24] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm0, %mm1 + pand %mm0, %mm2 + pand %mm0, %mm3 + pmovmskb %eax, %mm0 + sub %edx, 32 + add %rsi, 32 + add %rdi, 32 + + // check if eq + cmp %eax, 0xff + je Done4 + mov %eax, 1 + jmp End + +Done4: + cmp %edx, 24 + jne Done2 + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pand %mm0, %mm1 + pand %mm0, %mm2 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Done + mov %eax, 1 + jmp End + +Done2: + cmp %edx, 16 + jne Done1 + + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pand %mm0, %mm1 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Done + mov %eax, 1 + jmp End + +Done1: + cmp %edx, 8 + jne Done + + mov %eax, [%rsi] + mov %rsi, [%rsi+4] + cmp %eax, [%rdi] + je Next + mov %eax, 1 + jmp End + +Next: + cmp %rsi, [%rdi+4] + je Done + mov %eax, 1 + jmp End + +Done: + xor %eax, %eax + +End: + emms + ret + +#ifdef ZEROGS_SSE2 +// SSE2 extensions + +#define punpck(op, sd0, sd2, s1, s3, d1, d3) \ + movdqa %xmm##d1, %xmm##sd0; \ + pshufd %xmm##d3, %xmm##sd2, 0xe4; \ + punpckl##op %xmm##sd0, %xmm##s1; \ + punpckh##op %xmm##d1, %xmm##s1; \ + punpckl##op %xmm##sd2, %xmm##s3; \ + punpckh##op %xmm##d3, %xmm##s3; \ + +#define punpcknbl \ + movdqa %xmm4, %xmm0; \ + pshufd %xmm5, %xmm1, 0xe4; \ + \ + psllq %xmm1, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm0, %xmm7; \ + pandn %xmm6, %xmm1; \ + por %xmm0, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm1, %xmm4; \ + \ + movdqa %xmm4, %xmm2; \ + pshufd %xmm5, %xmm3, 0xe4; \ + \ + psllq %xmm3, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm2, %xmm7; \ + pandn %xmm6, %xmm3; \ + por %xmm2, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm3, %xmm4; \ + \ + punpck(bw, 0, 2, 1, 3, 4, 6); \ + +#define punpcknbh \ + movdqa %xmm12, %xmm8; \ + pshufd %xmm13, %xmm9, 0xe4; \ + \ + psllq %xmm9, 4; \ + psrlq %xmm12, 4; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm8, %xmm15; \ + pandn %xmm14, %xmm9; \ + por %xmm8, %xmm14; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm12, %xmm15; \ + pandn %xmm14, %xmm13; \ + por %xmm12, %xmm14; \ + \ + movdqa %xmm9, %xmm12; \ + \ + movdqa %xmm12, %xmm10; \ + pshufd %xmm13, %xmm11, 0xe4; \ + \ + psllq %xmm11, 4; \ + psrlq %xmm12, 4; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm10, %xmm15; \ + pandn %xmm14, %xmm11; \ + por %xmm10, %xmm14; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm12, %xmm15; \ + pandn %xmm14, %xmm13; \ + por %xmm12, %xmm14; \ + \ + movdqa %xmm11, %xmm12; \ + \ + punpck(bw, 8, 10, 9, 11, 12, 14); \ + +// +// SwizzleBlock32_sse2 +// + +.globl SwizzleBlock32_sse2 + .type SwizzleBlock32_sse2, @function +SwizzleBlock32_sse2: + + mov %eax, 4 + + cmp %ecx, 0xffffffff + jne SwizzleBlock32_sse2_2 + + .align 16 +SwizzleBlock32_sse2_1: + movdqa %xmm0, [%rsi] + movdqa %xmm4, [%rsi+16] + movdqa %xmm1, [%rsi+%rdx] + movdqa %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm2 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32_sse2_1 + + ret + +SwizzleBlock32_sse2_2: + + movd %xmm7, %rcx + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32_sse2_3: + movdqa %xmm0, [%rsi] + movdqa %xmm4, [%rsi+16] + movdqa %xmm1, [%rsi+%rdx] + movdqa %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + movdqa %xmm9, %xmm7 + pshufd %xmm11, %xmm7, 0xe4 + + pandn %xmm3, [%rdi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%rdi+16*0], %xmm0 + + pandn %xmm5, [%rdi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%rdi+16*1], %xmm2 + + pandn %xmm9, [%rdi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm9 + movdqa [%rdi+16*2], %xmm4 + + pandn %xmm11, [%rdi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm11 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32_sse2_3 + + ret + +// +// SwizzleBlock16_sse2 +// + +.globl SwizzleBlock16_sse2 + .type SwizzleBlock16_sse2, @function +SwizzleBlock16_sse2: + + mov %eax, 4 + + .align 16 +SwizzleBlock16_sse2_1: + movdqa %xmm0, [%rsi] + movdqa %xmm1, [%rsi+16] + movdqa %xmm2, [%rsi+%rdx] + movdqa %xmm3, [%rsi+%rdx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm5 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock16_sse2_1 + + ret + +// +// SwizzleBlock8 +// + +.globl SwizzleBlock8_sse2 + .type SwizzleBlock8_sse2, @function +SwizzleBlock8_sse2: + + mov %ecx, 2 + + .align 16 +SwizzleBlock8_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshufd %xmm1, [%rsi], 0xb1 + pshufd %xmm3, [%rsi+%rdx], 0xb1 + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm4 + movdqa [%rdi+16*2], %xmm1 + movdqa [%rdi+16*3], %xmm5 + + // col 1, 3 + + pshufd %xmm0, [%rsi], 0xb1 + pshufd %xmm2, [%rsi+%rdx], 0xb1 + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm4 + movdqa [%rdi+16*6], %xmm1 + movdqa [%rdi+16*7], %xmm5 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock8_sse2_1 + + ret + +// +// SwizzleBlock4 +// + +.globl SwizzleBlock4_sse2 + .type SwizzleBlock4_sse2, @function +SwizzleBlock4_sse2: + + mov %ecx, 2 + + mov %eax, 0x0f0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock4_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm3 + + // col 1, 3 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm1 + movdqa [%rdi+16*6], %xmm4 + movdqa [%rdi+16*7], %xmm3 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock4_sse2_1 + + ret + +// +// swizzling with unaligned reads +// + +// +// SwizzleBlock32u_sse2 +// + +.globl SwizzleBlock32u_sse2 + .type SwizzleBlock32u_sse2, @function +SwizzleBlock32u_sse2: + + mov %eax, 4 + + cmp %ecx, 0xffffffff + jne SwizzleBlock32u_sse2_2 + + .align 16 +SwizzleBlock32u_sse2_1: + movdqu %xmm0, [%rsi] + movdqu %xmm4, [%rsi+16] + movdqu %xmm1, [%rsi+%rdx] + movdqu %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm2 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32u_sse2_1 + + ret + +SwizzleBlock32u_sse2_2: + + movd %xmm7, %rcx + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32u_sse2_3: + movdqu %xmm0, [%rsi] + movdqu %xmm4, [%rsi+16] + movdqu %xmm1, [%rsi+%rdx] + movdqu %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + movdqa %xmm9, %xmm7 + pshufd %xmm11, %xmm7, 0xe4 + + pandn %xmm3, [%rdi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%rdi+16*0], %xmm0 + + pandn %xmm5, [%rdi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%rdi+16*1], %xmm2 + + pandn %xmm9, [%rdi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm9 + movdqa [%rdi+16*2], %xmm4 + + pandn %xmm11, [%rdi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm11 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32u_sse2_3 + + ret + +// +// SwizzleBlock16u_sse2 +// + +.globl SwizzleBlock16u_sse2 + .type SwizzleBlock16u_sse2, @function +SwizzleBlock16u_sse2: + mov %eax, 4 + + .align 16 +SwizzleBlock16u_sse2_1: + movdqu %xmm0, [%rsi] + movdqu %xmm1, [%rsi+16] + movdqu %xmm2, [%rsi+%rdx] + movdqu %xmm3, [%rsi+%rdx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm5 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock16u_sse2_1 + + ret + +// +// SwizzleBlock8u +// + +.globl SwizzleBlock8u_sse2 + .type SwizzleBlock8u_sse2, @function +SwizzleBlock8u_sse2: + mov %ecx, 2 + + .align 16 +SwizzleBlock8u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshufd %xmm1, %xmm0, 0xb1 + pshufd %xmm3, %xmm2, 0xb1 + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm4 + movdqa [%rdi+16*2], %xmm1 + movdqa [%rdi+16*3], %xmm5 + + // col 1, 3 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + pshufd %xmm0, %xmm0, 0xb1 + pshufd %xmm2, %xmm2, 0xb1 + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm4 + movdqa [%rdi+16*6], %xmm1 + movdqa [%rdi+16*7], %xmm5 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock8u_sse2_1 + + ret + +// +// SwizzleBlock4u +// + +.globl SwizzleBlock4u_sse2 + .type SwizzleBlock4u_sse2, @function +SwizzleBlock4u_sse2: + + mov %ecx, 2 + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock4u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm3 + + // col 1, 3 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm1 + movdqa [%rdi+16*6], %xmm4 + movdqa [%rdi+16*7], %xmm3 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock4u_sse2_1 + + ret + + + .align 16 +s_clut16mask: + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + + .align 16 +s_clut16mask2: + + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + +.globl WriteCLUT_T16_I4_CSM1_sse2 + .type WriteCLUT_T16_I4_CSM1_sse2, @function +WriteCLUT_T16_I4_CSM1_sse2: + movdqa %xmm0, xmmword ptr [%rdi] + movdqa %xmm1, xmmword ptr [%rdi+16] + movdqa %xmm2, xmmword ptr [%rdi+32] + movdqa %xmm3, xmmword ptr [%rdi+48] + + // rearrange + pshuflw %xmm0, %xmm0, 0x88 + pshufhw %xmm0, %xmm0, 0x88 + pshuflw %xmm1, %xmm1, 0x88 + pshufhw %xmm1, %xmm1, 0x88 + pshuflw %xmm2, %xmm2, 0x88 + pshufhw %xmm2, %xmm2, 0x88 + pshuflw %xmm3, %xmm3, 0x88 + pshufhw %xmm3, %xmm3, 0x88 + + shufps %xmm0, %xmm1, 0x88 + shufps %xmm2, %xmm3, 0x88 + + pshufd %xmm0, %xmm0, 0xd8 + pshufd %xmm2, %xmm2, 0xd8 + + pxor %xmm6, %xmm6 + + test %rsi, 15 + jnz WriteUnaligned + + movdqa %xmm7, [%rip+s_clut16mask] // saves upper 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%rsi] + movdqa %xmm5, [%rsi+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + + movdqa [%rsi], %xmm0 + movdqa [%rsi+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%rsi+16] + pand %xmm5, [%rsi+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%rsi+16], %xmm2 + movdqa [%rsi+48], %xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + // %rsi is offset by 2 + sub %rsi, 2 + + movdqa %xmm7, [%rip+s_clut16mask2] // saves lower 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%rsi] + movdqa %xmm5, [%rsi+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + pslld %xmm0, 16 + pslld %xmm1, 16 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + pslld %xmm2, 16 + pslld %xmm3, 16 + + movdqa [%rsi], %xmm0 + movdqa [%rsi+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%rsi+16] + pand %xmm5, [%rsi+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%rsi+16], %xmm2 + movdqa [%rsi+48], %xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +#endif diff --git a/plugins/gs/zerogs/opengl/x86-64.asm b/plugins/gs/zerogs/opengl/x86-64.asm new file mode 100644 index 0000000000..6d476dfc6d --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86-64.asm @@ -0,0 +1,1091 @@ +; Copyright (C) 2003-2005 Gabest/zerofrog +; http:;;www.gabest.org +; +; This Program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2, or (at your option) +; any later version. +; +; This Program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http:;;www.gnu.org/copyleft/gpl.html +; +; + +extern s_clut16mask:ptr + + .code + +; mmx memcpy implementation, size has to be a multiple of 8 +; returns 0 is equal, nonzero value if not equal +; ~10 times faster than standard memcmp +; (zerofrog) +; u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +; rcx - src1 +; rdx - src2 +; r8d - cmpsize +memcmp_mmx proc public + cmp r8d, 32 + jl Done4 + + ; custom test first 8 to make sure things are ok + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + movq mm2, [rdx+16] + pmovmskb eax, mm0 + movq mm3, [rdx+24] + + ; check if eq + cmp eax, 0ffh + je NextComp + mov eax, 1 + jmp Finish + +NextComp: + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je ContinueTest + mov eax, 1 + jmp Finish + + cmp r8d, 64 + jl Done8 + +Cmp8: + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pcmpeqd mm4, [rcx+32] + pand mm0, mm2 + pcmpeqd mm5, [rcx+40] + pand mm0, mm3 + pcmpeqd mm6, [rcx+48] + pand mm0, mm4 + pcmpeqd mm7, [rcx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Continue + mov eax, 1 + jmp Finish + +Continue: + sub r8d, 64 + add rdx, 64 + add rcx, 64 +ContinueTest: + cmp r8d, 64 + jge Cmp8 + +Done8: + test r8d, 020h + jz Done4 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je Done4 + mov eax, 1 + jmp Finish + +Done4: + cmp r8d, 24 + jne Done2 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done2: + cmp r8d, 16 + jne Done1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done1: + cmp r8d, 8 + jne Done + + mov eax, [rdx] + mov rdx, [rdx+4] + cmp eax, [rcx] + je Next + mov eax, 1 + jmp Finish + +Next: + cmp rdx, [rcx+4] + je Done + mov eax, 1 + jmp Finish + +Done: + xor eax, eax + +Finish: + emms + ret + +memcmp_mmx endp + +; TestClutChangeMMX +; mov rdx, dst +; mov rcx, src +; mov r8d, entries +TestClutChangeMMX proc public + +Start: + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+16] + + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm2, [rcx+32] + pcmpeqd mm3, [rcx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [rdx+32] + movq mm5, [rdx+40] + pcmpeqd mm4, [rcx+8] + pcmpeqd mm5, [rcx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm6, [rcx+40] + pcmpeqd mm7, [rcx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0ffh + je Continue + mov byte ptr [r9], 1 + jmp Return + +Continue: + cmp r8d, 16 + jle Return + + test r8d, 010h + jz AddRcx + sub rcx, 448 ; go back and down one column, +AddRcx: + add rcx, 256 ; go to the right block + + + jne Continue1 + add rcx, 256 ; skip whole block +Continue1: + add rdx, 64 + sub r8d, 16 + jmp Start + +Return: + emms + ret + +TestClutChangeMMX endp + +UnswizzleZ16Target proc public + pxor xmm7, xmm7 + +Z16Loop: + ;; unpack 64 bytes at a time + movdqa xmm0, [rdx] + movdqa xmm2, [rdx+16] + movdqa xmm4, [rdx+32] + movdqa xmm6, [rdx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + ;; start saving + movdqa [rcx], xmm0 + movdqa [rcx+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [rcx+32], xmm2 + movdqa [rcx+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [rcx+64], xmm4 + movdqa [rcx+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [rcx+96], xmm6 + movdqa [rcx+112], xmm0 + + add rdx, 64 + add rcx, 128 + sub r9d, 1 + jne Z16Loop + + ret +UnswizzleZ16Target endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknbl macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +punpcknbh macro + + movdqa xmm12, xmm8 + pshufd xmm13, xmm9, 0e4h + + psllq xmm9, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm8, xmm15 + pandn xmm14, xmm9 + por xmm8, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm9, xmm12 + + movdqa xmm12, xmm10 + pshufd xmm13, xmm11, 0e4h + + psllq xmm11, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm10, xmm15 + pandn xmm14, xmm11 + por xmm10, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm11, xmm12 + + punpck bw, 8, 10, 9, 11, 12, 14 + + endm + +; +; SwizzleBlock32_sse2 +; + +SwizzleBlock32_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2 endp + +; +; SwizzleBlock16_sse2 +; + +SwizzleBlock16_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm1, [rsi+16] + movdqa xmm2, [rsi+r8] + movdqa xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16_sse2 endp + +; +; SwizzleBlock8 +; + +SwizzleBlock8_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8_sse2 endp + +; +; SwizzleBlock4 +; + +SwizzleBlock4_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4_sse2 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u_sse2 +; + +SwizzleBlock32u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2 endp + +; +; SwizzleBlock16u_sse2 +; + +SwizzleBlock16u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm1, [rsi+16] + movdqu xmm2, [rsi+r8] + movdqu xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16u_sse2 endp + +; +; SwizzleBlock8u +; + +SwizzleBlock8u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, xmm0, 0b1h + pshufd xmm3, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8u_sse2 endp + +; +; SwizzleBlock4u +; + +SwizzleBlock4u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4u_sse2 endp + +WriteCLUT_T16_I4_CSM1_sse2 proc public + movdqa xmm0, XMMWORD PTR [rcx] + movdqa xmm1, XMMWORD PTR [rcx+16] + movdqa xmm2, XMMWORD PTR [rcx+32] + movdqa xmm3, XMMWORD PTR [rcx+48] + + ;; rearrange + pshuflw xmm0, xmm0, 088h + pshufhw xmm0, xmm0, 088h + pshuflw xmm1, xmm1, 088h + pshufhw xmm1, xmm1, 088h + pshuflw xmm2, xmm2, 088h + pshufhw xmm2, xmm2, 088h + pshuflw xmm3, xmm3, 088h + pshufhw xmm3, xmm3, 088h + + shufps xmm0, xmm1, 088h + shufps xmm2, xmm3, 088h + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + + pxor xmm6, xmm6 + mov rax, offset s_clut16mask + + test rdx, 15 + jnz WriteUnaligned + + movdqa xmm7, XMMWORD PTR [rax] ;; saves upper 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + ;; rdx is offset by 2 + sub rdx, 2 + + movdqa xmm7, XMMWORD PTR [rax+16] ;; saves lower 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +WriteCLUT_T16_I4_CSM1_sse2 endp + +end \ No newline at end of file diff --git a/plugins/gs/zerogs/opengl/x86.cpp b/plugins/gs/zerogs/opengl/x86.cpp new file mode 100644 index 0000000000..7152cf78fe --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86.cpp @@ -0,0 +1,571 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask)) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void FASTCALL(FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void FASTCALL(FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void FASTCALL(Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void FASTCALL(Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void FASTCALL(Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void FASTCALL(Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut)) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut)) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/gs/zerogs/opengl/x86.h b/plugins/gs/zerogs/opengl/x86.h new file mode 100644 index 0000000000..a9eb717a87 --- /dev/null +++ b/plugins/gs/zerogs/opengl/x86.h @@ -0,0 +1,182 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include "GS.h" + +extern "C" void FASTCALL(SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch)); + +// frame swizzling + +// no AA +extern "C" void FASTCALL(FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern "C" void FASTCALL(FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern "C" void FASTCALL(FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)); + +// no AA +extern void FASTCALL(FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern void FASTCALL(FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern void FASTCALL(FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch)); + +extern "C" void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)); + +extern void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/gs/zerogs/opengl/zerogs.cpp b/plugins/gs/zerogs/opengl/zerogs.cpp new file mode 100644 index 0000000000..8cedebd72f --- /dev/null +++ b/plugins/gs/zerogs/opengl/zerogs.cpp @@ -0,0 +1,5946 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) +#include +#include + +#include "resource.h" +#endif + +#include + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" +#include "zpipe.h" + +#include "ZeroGSShaders/zerogsshaders.h" +#include "targets.h" +#include "rasterfont.h" // simple font + +#define VB_BUFFERSIZE 0x400 +#define VB_NUMBUFFERS 512 +#define SIZEOF_VB sizeof(ZeroGS::VB)//((u32)((u8*)&vb[0].buffers-(u8*)&vb[0])) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char zgsrevision, zgsbuild, zgsminor; + +BOOL g_bDisplayMsg = 1; + +#ifdef _WIN32 +HDC hDC=NULL; // Private GDI Device Context +HGLRC hRC=NULL; // Permanent Rendering Context +#endif + +BOOL g_bCRTCBilinear = TRUE; +BOOL g_bSaveFlushedFrame = 0; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bSaveResolved = 0; + +#ifdef _WIN32 +//#define EFFECT_NAME "f:\\ps2dev\\svn\\pcsx2\\ZeroGS\\opengl\\" +char* EFFECT_DIR = "C:\\programming\\ps2dev\\zerogs\\opengl\\"; +char* EFFECT_NAME = "C:\\programming\\ps2dev\\zerogs\\opengl\\ps2hw.fx"; +#else +char EFFECT_DIR[255] = "~/pcsx2/plugins/gs/zerogs/opengl/"; +char EFFECT_NAME[255] = "~/pcsx2/plugins/gs/zerogs/opengl/ps2hw.fx"; +#endif + +#endif + +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) + +#define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount) + +#define GL_BLEND_RGB(src, dst) { \ + s_srcrgb = src; \ + s_dstrgb = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALPHA(src, dst) { \ + s_srcalpha = src; \ + s_dstalpha = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \ + s_srcrgb = srcrgb; \ + s_dstrgb = dstrgb; \ + s_srcalpha = srcalpha; \ + s_dstalpha = dstalpha; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_SET() zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha) + +#define GL_ZTEST(enable) { \ + if( enable ) glEnable(GL_DEPTH_TEST); \ + else glDisable(GL_DEPTH_TEST); \ +} + +#define GL_ALPHATEST(enable) { \ + if( enable ) glEnable(GL_ALPHA_TEST); \ + else glDisable(GL_ALPHA_TEST); \ +} + +#define GL_BLENDEQ_RGB(eq) { \ + s_rgbeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_BLENDEQ_ALPHA(eq) { \ + s_alphaeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_STENCILFUNC(func, ref, mask) { \ + s_stencilfunc = func; \ + s_stencilref = ref; \ + s_stencilmask = mask; \ + glStencilFunc(func, ref, mask); \ +} + +#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) + +#define COLORMASK_RED 1 +#define COLORMASK_GREEN 2 +#define COLORMASK_BLUE 4 +#define COLORMASK_ALPHA 8 +#define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA)) + +typedef void (APIENTRYP _PFNSWAPINTERVAL) (int); + +extern int s_frameskipping; + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; +CGprogram g_vsprog = 0, g_psprog = 0; +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; + +inline u32 FtoDW(float f) { return (*((u32*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// local alpha blending settings +static GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT +static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT +static u32 s_stencilfunc, s_stencilref, s_stencilmask; +static GLenum s_drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; + +#ifdef _WIN32 +extern HINSTANCE hInst; + +void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#else +void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#endif + +GLenum g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; +GLenum g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; +GLenum g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + +// Consts +static const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; +static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; +static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; + +// used for afail case +static const u32 g_dwReverseAlphaCmp[] = { GL_ALWAYS, GL_NEVER, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_EQUAL }; + +static const u32 g_dwZCmp[] = { GL_NEVER, GL_ALWAYS, GL_GEQUAL, GL_GREATER }; + +PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; +PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; + +///////////////////// +// graphics resources +static map mapGLExtensions; +RasterFont* font_p = NULL; +CGprofile cgvProf, cgfProf; +static CGprogram pvs[16] = {NULL}; +static FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; +static FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; +CGparameter g_vparamPosXY[2] = {0}, g_fparamFogColor = 0; + +int g_nPixelShaderVer = 0; // default + +static u8* s_lpShaderResources = NULL; +static map mapShaderResources; + +u32 s_uFramebuffer = 0; +u32 s_ptexCurSet[2] = {0}; + +#define s_bForceTexFlush 1 +static u32 s_ptexNextSet[2] = {0}; + +u32 ptexBlocks = 0, ptexConv16to32 = 0; // holds information on block tiling +u32 ptexBilinearBlocks = 0; +u32 ptexConv32to16 = 0; +static u32 s_ptexInterlace = 0; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static vector s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static u32 ptexLogo = 0; +static int nLogoWidth, nLogoHeight; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static Vector vAlphaBlendColor; // used for GPU_COLOR + +static u8 bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static u32 s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + u8 _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + u8 _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + u8 _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + u8 _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +//#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static alphaInfo s_alphaInfo; + +CGcontext g_cgcontext; +static int nBackbufferWidth, nBackbufferHeight; + +u8* g_pbyGSMemory = NULL; // 4Mb GS system mem +u8* g_pbyGSClut = NULL; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + GLuint vboRect = 0; + vector g_vboBuffers; // VBOs for all drawing commands + int g_nCurVBOIndex = 0; + + u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + RenderFormatType g_RenderFormatType = RFT_float16; + int icurctx = -1; + + Vector g_vdepth = Vector(256.0f*65536.0f, 65536.0f, 256.0f, 65536.0f*65536.0f); + + VERTEXSHADER pvsBitBlt; + FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + RenderFormatType GetRenderFormat() { return g_RenderFormatType; } + GLenum GetRenderTargetFormat() { return GetRenderFormat()==RFT_byte8?4:g_internalRGBAFloat16Fmt; } + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + bool LoadEffects(); + bool LoadExtraEffects(); + FRAGMENTSHADER* LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + u32 dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(Vector& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + inline void SetContextTarget(int context); + + // use to update the state + void SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor); + __forceinline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb, CGparameter sOneColor); + __forceinline void ProcessFBA(const VB& curvb, CGparameter sOneColor); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + inline u32 CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != 0 ) return s_ptexInterlace; + + SAFE_RELEASE_TEX(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + vector data(width); + for(int i = 0; i < width; ++i) data[i] = (i&1) ? 0xffffffff : 0; + + glGenTextures(1, &s_ptexInterlace); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, s_ptexInterlace); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GL_REPORT_ERRORD(); + return s_ptexInterlace; + } + + void ResetRenderTarget(int index) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+index, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, SIZEOF_VB); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + _aligned_free(pBufferData); pBufferData = NULL; nNumVertices = 0; + + prndr = NULL; + pdepth = NULL; +} + +bool ZeroGS::VB::CheckPrim() +{ + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return nCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + bChanged = 0; + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) + maxpos *= 2; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? alteir aris crashes without it + if( maxpos > 256 ) + maxpos &= ~0x1f; + } + else { + prndr = NULL; + pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAllTargs(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->fbh; + if( zbuf.psm == 0x31 ) tempfb.fbm = 0xff000000; + else tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// printf("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + GL_REPORT_ERRORD(); + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + if( prndr != NULL ) + SetContextTarget(ictx); + + //if( prndr != NULL && ictx == icurctx) + //else bVarsSetTarg = 0; + +// if( prndr != NULL && bChanged ) { +// if( ictx == icurctx ) SetContextTarget(icurctx); +// else +// bVarsSetTarg = 0; +// } +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + +#ifndef _WIN32 + memset(&GLWin, 0, sizeof(GLWin)); +#endif + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +#ifdef _WIN32 +void __stdcall glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#else +void APIENTRY glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#endif +{ + glBlendFunc(e1, e2); +} + +#ifdef _WIN32 +void __stdcall glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#else +void APIENTRY glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#endif +{ + glBlendEquation(e1); +} + +void HandleCgError(CGcontext ctx, CGerror err, void* appdata) +{ + ERROR_LOG("Cg error: %s\n", cgGetErrorString(err)); + const char* listing = cgGetLastListing(g_cgcontext); + if( listing != NULL ) { + printf(" last listing: %s\n", listing); + } +// int loc; +// const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); +// if( pstr != NULL ) printf("error at: %s\n"); +// glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); +// printf("pos: %d\n", loc); +} + +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 +#endif + +void ZeroGS::HandleGLError() +{ + // check the error status of this framebuffer */ + GLenum error = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + // if error != GL_FRAMEBUFFER_COMPLETE_EXT, there's an error of some sort + if( error != 0 ) { + int w, h; + GLint fmt; + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_INTERNAL_FORMAT_EXT, &fmt); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_WIDTH_EXT, &w); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &h); + + switch(error) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + ERROR_LOG("Error! missing a required image/buffer attachment!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + ERROR_LOG("Error! has no images/buffers attached!\n"); + break; +// case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: +// ERROR_LOG("Error! has an image/buffer attached in multiple locations!\n"); +// break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + ERROR_LOG("Error! has mismatched image/buffer dimensions!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + ERROR_LOG("Error! colorbuffer attachments have different types!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + ERROR_LOG("Error! trying to draw to non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + ERROR_LOG("Error! trying to read from a non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + ERROR_LOG("Error! format is not supported by current graphics card/driver!\n"); + break; + default: + ERROR_LOG("*UNKNOWN ERROR* reported from glCheckFramebufferStatusEXT() for %s!\n"); + break; + } + } +} + +#ifdef _WIN32 +#define GL_LOADFN(name) { \ + if( (*(void**)&name = (void*)wglGetProcAddress(#name)) == NULL ) { \ + ERROR_LOG("Failed to find %s, exiting\n", #name); \ + } \ +} +#else +// let GLEW take care of it +#define GL_LOADFN(name) +#endif + +bool ZeroGS::IsGLExt( const char* szTargetExtension ) +{ + return mapGLExtensions.find(string(szTargetExtension)) != mapGLExtensions.end(); +} + +bool ZeroGS::Create(int _width, int _height) +{ + GLenum err = GL_NO_ERROR; + bool bSuccess = true; + int i; + + Destroy(1); + GSStateReset(); + + cgSetErrorHandler(HandleCgError, NULL); + g_RenderFormatType = RFT_float16; + + nBackbufferWidth = _width; + nBackbufferHeight = _height; + fiRendWidth = 1.0f / nBackbufferWidth; + fiRendHeight = 1.0f / nBackbufferHeight; + +#ifdef _WIN32 + GLuint PixelFormat; // Holds The Results After Searching For A Match + DWORD dwExStyle; // Window Extended Style + DWORD dwStyle; // Window Style + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + if (conf.options & GSOPTION_FULLSCREEN) { + nBackbufferWidth = rcdesktop.right - rcdesktop.left; + nBackbufferHeight = rcdesktop.bottom - rcdesktop.top; + + DEVMODE dmScreenSettings; + memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); + dmScreenSettings.dmSize=sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = nBackbufferWidth; + dmScreenSettings.dmPelsHeight = nBackbufferHeight; + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; + + // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. + if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) + { + if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) + conf.options &= ~GSOPTION_FULLSCREEN; + else + return false; + } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + if( conf.options & GSOPTION_FULLSCREEN) { + dwExStyle=WS_EX_APPWINDOW; + dwStyle=WS_POPUP; + ShowCursor(FALSE); + } + else { + dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwStyle=WS_OVERLAPPEDWINDOW; + } + + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = nBackbufferWidth; rc.bottom = nBackbufferHeight; + AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); + int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + SetWindowPos(GShwnd, NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION|SWP_NOZORDER); + + PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24Bit Z-Buffer (Depth Buffer) + 8, // 8bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + if (!(hDC=GetDC(GShwnd))) { + MessageBox(NULL,"(1) Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) { + MessageBox(NULL,"(2) Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!SetPixelFormat(hDC,PixelFormat,&pfd)) { + MessageBox(NULL,"(3) Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(hRC=wglCreateContext(hDC))) { + MessageBox(NULL,"(4) Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!wglMakeCurrent(hDC,hRC)) { + MessageBox(NULL,"(5) Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + +#else + XVisualInfo *vi; + Colormap cmap; + int dpyWidth, dpyHeight; + int glxMajorVersion, glxMinorVersion; + int vidModeMajorVersion, vidModeMinorVersion; + Atom wmDelete; + Window winDummy; + unsigned int borderDummy; + + // attributes for a single buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None}; + + // attributes for a double buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None }; + + GLWin.fs = !!(conf.options & GSOPTION_FULLSCREEN); + + /* get an appropriate visual */ + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); + if (vi == NULL) { + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); + GLWin.doubleBuffered = False; + ERROR_LOG("Only Singlebuffered Visual!\n"); + } + else { + GLWin.doubleBuffered = True; + ERROR_LOG("Got Doublebuffered Visual!\n"); + } + + glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); + ERROR_LOG("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); + /* create a GLX context */ + GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE); + /* create a color map */ + cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + vi->visual, AllocNone); + GLWin.attr.colormap = cmap; + GLWin.attr.border_pixel = 0; + + // get a connection + XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion); + + if (GLWin.fs) { + + XF86VidModeModeInfo **modes = NULL; + int modeNum = 0; + int bestMode = 0; + + // set best mode to current + bestMode = 0; + ERROR_LOG("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); + XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes); + + if( modeNum > 0 && modes != NULL ) { + /* save desktop-resolution before switching modes */ + GLWin.deskMode = *modes[0]; + /* look for mode with requested resolution */ + for (i = 0; i < modeNum; i++) { + if ((modes[i]->hdisplay == _width) && (modes[i]->vdisplay == _height)) { + bestMode = i; + } + } + + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + dpyWidth = modes[bestMode]->hdisplay; + dpyHeight = modes[bestMode]->vdisplay; + ERROR_LOG("Resolution %dx%d\n", dpyWidth, dpyHeight); + XFree(modes); + + /* create a fullscreen window */ + GLWin.attr.override_redirect = True; + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, + &GLWin.attr); + XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0); + XMapRaised(GLWin.dpy, GLWin.win); + XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask, + GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime); + } + else { + ERROR_LOG("Failed to start fullscreen. If you received the \n" + "\"XFree86-VidModeExtension\" extension is missing, add\n" + "Load \"extmod\"\n" + "to your X configuration file (under the Module Section)\n"); + GLWin.fs = 0; + } + } + + + if( !GLWin.fs ) { + + //XRootWindow(dpy,screen) + //int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + //int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + // create a window in window mode + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr); + // only set window title and handle wm_delete_events if in windowed mode + wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1); + XSetStandardProperties(GLWin.dpy, GLWin.win, "ZeroGS", + "ZeroGS", None, NULL, 0, NULL); + XMapRaised(GLWin.dpy, GLWin.win); + } + + // connect the glx-context to the window + glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); + XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); + ERROR_LOG("Depth %d\n", GLWin.depth); + if (glXIsDirect(GLWin.dpy, GLWin.ctx)) + ERROR_LOG("you have Direct Rendering!\n"); + else + ERROR_LOG("no Direct Rendering possible!\n"); + + // better for pad plugin key input (thc) + XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | + FocusChangeMask ); + +#endif + + // fill the opengl extension map + const char* ptoken = (const char*)glGetString( GL_EXTENSIONS ); + if( ptoken == NULL ) return false; + + int prevlog = conf.log; + conf.log = 1; + __Log("Supported OpenGL Extensions:\n%s\n", ptoken); // write to the log file + conf.log = prevlog; + + // insert all exts into mapGLExtensions + + const char* pend = NULL; + + while(ptoken != NULL ) { + pend = strchr(ptoken, ' '); + + if( pend != NULL ) { + mapGLExtensions[string(ptoken, pend-ptoken)]; + } + else { + mapGLExtensions[string(ptoken)]; + break; + } + + ptoken = pend; + while(*ptoken == ' ') ++ptoken; + } + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + conf.mrtdepth = 0; // for now + +#ifndef _WIN32 + int const glew_ok = glewInit(); + if( glew_ok != GLEW_OK ) { + ERROR_LOG("glewInit() is not ok!\n"); + return false; + } +#endif + + if( !IsGLExt("GL_EXT_framebuffer_object") ) { + ERROR_LOG("*********\nZeroGS: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nZeroGS: *********\n"); + bSuccess = false; + } + if( !IsGLExt("GL_EXT_blend_equation_separate") || glBlendEquationSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_equation_separate\nZeroGS: *********\n"); + zgsBlendEquationSeparateEXT = glBlendEquationSeparateDummy; + } + else { + zgsBlendEquationSeparateEXT = glBlendEquationSeparateEXT; + } + + if( !IsGLExt("GL_EXT_blend_func_separate") || glBlendFuncSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_func_separate\nZeroGS: *********\n"); + zgsBlendFuncSeparateEXT = glBlendFuncSeparateDummy; + } + else { + zgsBlendFuncSeparateEXT = glBlendFuncSeparateEXT; + } + + if( !IsGLExt("GL_EXT_secondary_color") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_secondary_color\nZeroGS: *********\n"); + bSuccess = false; + } + + if( !IsGLExt("GL_ARB_draw_buffers") && !IsGLExt("GL_ATI_draw_buffers") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: multiple render targets not supported, some effects might look bad\nZeroGS: *********\n"); + conf.mrtdepth = 0; + } + + if( !bSuccess ) + return false; + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormatType = RFT_byte8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else { + if( !IsGLExt("GL_NV_float_buffer") && !IsGLExt("GL_ARB_color_buffer_float") && !IsGLExt("ATI_pixel_format_float") ) { + ERROR_LOG("******\nZeroGS: GS WARNING: Floating point render targets not supported, switching to 32bit\nZeroGS: *********\n"); + g_RenderFormatType = RFT_byte8; + } + } + g_RenderFormatType = RFT_byte8; + +#ifdef _WIN32 + if( IsGLExt("WGL_EXT_swap_control") || IsGLExt("EXT_swap_control") ) + wglSwapIntervalEXT(0); +#else + if( IsGLExt("GLX_SGI_swap_control") ) { + _PFNSWAPINTERVAL swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapInterval"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalSGI"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalEXT"); + + if( swapinterval ) + swapinterval(0); + else + ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); + } +#endif + + // check the max texture width and height + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_MaxTexWidth); + g_MaxTexHeight = g_MaxTexWidth; + GPU_TEXWIDTH = g_MaxTexWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + +#ifdef RELEASE_TO_PUBLIC +#ifdef _WIN32 + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (u8*)LockResource(hShaderGlob); +#else + FILE* fres = fopen("ps2hw.dat", "rb"); + if( fres == NULL ) { + fres = fopen("plugins/ps2hw.dat", "rb"); + if( fres == NULL ) { + ERROR_LOG("Cannot find ps2hw.dat in working directory. Exiting\n"); + return false; + } + } + fseek(fres, 0, SEEK_END); + size_t s = ftell(fres); + s_lpShaderResources = new u8[s+1]; + fseek(fres, 0, SEEK_SET); + fread(s_lpShaderResources, s, 1, fres); + s_lpShaderResources[s] = 0; +#endif + +#else + +#ifndef _WIN32 + // test if ps2hw.fx exists + char tempstr[255]; + char curwd[255]; + getcwd(curwd, ARRAY_SIZE(curwd)); + + strcpy(tempstr, "../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + FILE* f = fopen(EFFECT_NAME, "r"); + if( f == NULL ) { + + strcpy(tempstr, "../../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + f = fopen(EFFECT_NAME, "r"); + + if( f == NULL ) { + ERROR_LOG("Failed to find %s, try compiling a non-devbuild\n", EFFECT_NAME); + return false; + } + } + + fclose(f); + + sprintf(EFFECT_DIR, "%s/%s", curwd, tempstr); + sprintf(EFFECT_NAME, "%sps2hw.fx", EFFECT_DIR); +#endif + +#endif // RELEASE_TO_PUBLIC + + // load the effect, find the best profiles (if any) + if( cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE ) { + ERROR_LOG("arbvp1 not supported\n"); + return false; + } + if( cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE ) { + ERROR_LOG("arbfp1 not supported\n"); + return false; + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + s_srcrgb = s_dstrgb = s_srcalpha = s_dstalpha = GL_ONE; + + GL_LOADFN(glIsRenderbufferEXT); + GL_LOADFN(glBindRenderbufferEXT); + GL_LOADFN(glDeleteRenderbuffersEXT); + GL_LOADFN(glGenRenderbuffersEXT); + GL_LOADFN(glRenderbufferStorageEXT); + GL_LOADFN(glGetRenderbufferParameterivEXT); + GL_LOADFN(glIsFramebufferEXT); + GL_LOADFN(glBindFramebufferEXT); + GL_LOADFN(glDeleteFramebuffersEXT); + GL_LOADFN(glGenFramebuffersEXT); + GL_LOADFN(glCheckFramebufferStatusEXT); + GL_LOADFN(glFramebufferTexture1DEXT); + GL_LOADFN(glFramebufferTexture2DEXT); + GL_LOADFN(glFramebufferTexture3DEXT); + GL_LOADFN(glFramebufferRenderbufferEXT); + GL_LOADFN(glGetFramebufferAttachmentParameterivEXT); + GL_LOADFN(glGenerateMipmapEXT); + + if( IsGLExt("GL_ARB_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffers"); + else if( IsGLExt("GL_ATI_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffersATI"); + + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glGenFramebuffersEXT( 1, &s_uFramebuffer); + if( s_uFramebuffer == 0 ) { + ERROR_LOG("failed to create the renderbuffer\n"); + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + if( glDrawBuffers != NULL ) + glDrawBuffers(1, s_drawbuffers); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + font_p = new RasterFont(); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + + GL_BLEND_ALL(GL_ONE, GL_ONE, GL_ONE, GL_ONE); + + glViewport(0,0,nBackbufferWidth,nBackbufferHeight); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations + + glGenTextures(1, &ptexLogo); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexLogo); + +#ifdef _WIN32 + HRSRC hBitmapSrc = FindResource(hInst, MAKEINTRESOURCE(IDB_ZEROGSLOGO), RT_BITMAP); + assert( hBitmapSrc != NULL ); + HGLOBAL hBitmapGlob = LoadResource(hInst, hBitmapSrc); + assert( hBitmapGlob != NULL ); + PBITMAPINFO pinfo = (PBITMAPINFO)LockResource(hBitmapGlob); + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight, 0, pinfo->bmiHeader.biBitCount==32?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, (u8*)pinfo+pinfo->bmiHeader.biSize); + nLogoWidth = pinfo->bmiHeader.biWidth; + nLogoHeight = pinfo->bmiHeader.biHeight; + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#else +#endif + + GL_REPORT_ERROR(); + + g_nCurVBOIndex = 0; + g_vboBuffers.resize(VB_NUMBUFFERS); + glGenBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + for(i = 0; i < (int)g_vboBuffers.size(); ++i) { + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[i]); + glBufferData(GL_ARRAY_BUFFER, 0x100*sizeof(VertexGPU), NULL, GL_STREAM_DRAW); + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // create the blocks texture + g_fBlockMult = 1; + + vector vBlockData, vBilinearData; + BLOCK::FillBlocks(vBlockData, vBilinearData, 1); + + glGenTextures(1, &ptexBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBlocks); + + g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; + g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; + g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_ALPHA, GL_FLOAT, &vBlockData[0]); + + if( glGetError() != GL_NO_ERROR ) { + // try different internal format + g_internalFloatFmt = GL_FLOAT_R32_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RED, GL_FLOAT, &vBlockData[0]); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + + // error, resort to 16bit + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + + BLOCK::FillBlocks(vBlockData, vBilinearData, 0); + glTexImage2D(GL_TEXTURE_2D, 0, 2, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_R, GL_UNSIGNED_SHORT, &vBlockData[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + } + else { + // fill in the bilinear blocks + glGenTextures(1, &ptexBilinearBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBilinearBlocks); + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + + if( glGetError() != GL_NO_ERROR ) { + g_internalRGBAFloatFmt = GL_FLOAT_RGBA32_NV; + g_internalRGBAFloat16Fmt = GL_FLOAT_RGBA16_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + B_G(glGetError() == GL_NO_ERROR, return false); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + float fpri = 1; + glPrioritizeTextures(1, &ptexBlocks, &fpri); + if( ptexBilinearBlocks != 0 ) + glPrioritizeTextures(1, &ptexBilinearBlocks, &fpri); + + GL_REPORT_ERROR(); + + // fill a simple rect + glGenBuffers(1, &vboRect); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + + vector verts(4); + VertexGPU* pvert = &verts[0]; + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + glBufferDataARB(GL_ARRAY_BUFFER, 4*sizeof(VertexGPU), &verts[0], GL_STATIC_DRAW); + + // setup the default vertex declaration + glEnableClientState(GL_VERTEX_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_SECONDARY_COLOR_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + GL_REPORT_ERROR(); + + // some cards don't support this +// glClientActiveTexture(GL_TEXTURE0); +// glEnableClientState(GL_TEXTURE_COORD_ARRAY); +// glTexCoordPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); + + // create the conversion textures + glGenTextures(1, &ptexConv16to32); + glBindTexture(GL_TEXTURE_2D, ptexConv16to32); + + vector conv16to32data(256*256); + for(i = 0; i < 256*256; ++i) { + u32 tempcol = RGBA16to32(i); + // have to flip r and b + conv16to32data[i] = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv16to32data[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + vector conv32to16data(32*32*32); + + glGenTextures(1, &ptexConv32to16); + glBindTexture(GL_TEXTURE_3D, ptexConv32to16); + u32* dst = &conv32to16data[0]; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + glTexImage3D(GL_TEXTURE_3D, 0, 4, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv32to16data[0]); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + g_cgcontext = cgCreateContext(); + + cgvProf = CG_PROFILE_ARBVP1; + cgfProf = CG_PROFILE_ARBFP1; + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + cgGLSetManageTextureParameters(g_cgcontext, CG_FALSE); + //cgSetAutoCompile(g_cgcontext, CG_COMPILE_IMMEDIATE); + + g_fparamFogColor = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[0] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[1] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + + ERROR_LOG("Creating effects\n"); + B_G(LoadEffects(), return false); + + g_bDisplayMsg = 0; + + + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + g_nPixelShaderVer = SHADER_ACCURATE; + // test + bool bFailed; + FRAGMENTSHADER* pfrag = LoadShadeEffect(0, 1, 1, 1, 1, temp, 0, &bFailed); + if( bFailed || pfrag == NULL ) { + g_nPixelShaderVer = SHADER_ACCURATE|SHADER_REDUCED; + + pfrag = LoadShadeEffect(0, 0, 1, 1, 0, temp, 0, &bFailed); + if( pfrag != NULL ) + cgGLLoadProgram(pfrag->prog); + if( bFailed || pfrag == NULL || cgGetError() != CG_NO_ERROR ) { + g_nPixelShaderVer = SHADER_REDUCED; + ERROR_LOG("Basic shader test failed\n"); + } + } + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer & SHADER_REDUCED ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + B_G(LoadExtraEffects(), return false); + + ERROR_LOG("using %s shaders\n", g_pShaders[g_nPixelShaderVer]); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + glBlendColorEXT(0, 0, 0, 0.5f); + + glDisable(GL_CULL_FACE); + + // points + glPointSize(1.0f); + g_nDepthBias = 0; + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 1); + + vb[0].Init(VB_BUFFERSIZE); + vb[1].Init(VB_BUFFERSIZE); + g_bSaveFlushedFrame = 1; + + g_vsprog = g_psprog = 0; + + return glGetError() == GL_NO_ERROR && bSuccess; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + if( s_aviinit ) { + StopCapture(); + +#ifdef _WIN32 + STOP_AVI(); +#else // linux + //TODO +#endif + ERROR_LOG("zerogs.avi stopped"); + s_aviinit = 0; + } + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE_TEX(s_ptexInterlace); + SAFE_RELEASE_TEX(ptexBlocks); + SAFE_RELEASE_TEX(ptexBilinearBlocks); + SAFE_RELEASE_TEX(ptexConv16to32); + SAFE_RELEASE_TEX(ptexConv32to16); + + vb[0].Destroy(); + vb[1].Destroy(); + + if( g_vboBuffers.size() > 0 ) { + glDeleteBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + g_vboBuffers.clear(); + } + g_nCurVBOIndex = 0; + + for(int i = 0; i < ARRAY_SIZE(pvs); ++i) { + SAFE_RELEASE_PROG(pvs[i]); + } + for(int i = 0; i < ARRAY_SIZE(ppsRegular); ++i) { + SAFE_RELEASE_PROG(ppsRegular[i].prog); + } + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + + SAFE_RELEASE_PROG(pvsBitBlt.prog); + SAFE_RELEASE_PROG(ppsBitBlt[0].prog); SAFE_RELEASE_PROG(ppsBitBlt[1].prog); + SAFE_RELEASE_PROG(ppsBitBltDepth.prog); + SAFE_RELEASE_PROG(ppsCRTCTarg[0].prog); SAFE_RELEASE_PROG(ppsCRTCTarg[1].prog); + SAFE_RELEASE_PROG(ppsCRTC[0].prog); SAFE_RELEASE_PROG(ppsCRTC[1].prog); + SAFE_RELEASE_PROG(ppsCRTC24[0].prog); SAFE_RELEASE_PROG(ppsCRTC24[1].prog); + SAFE_RELEASE_PROG(ppsOne.prog); + + SAFE_DELETE(font_p); + +#ifdef _WIN32 + if (hRC) // Do We Have A Rendering Context? + { + if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? + { + MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + + if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? + { + MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + hRC=NULL; // Set RC To NULL + } + + if (hDC && !ReleaseDC(GShwnd,hDC)) // Are We Able To Release The DC + { + MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + hDC=NULL; // Set DC To NULL + } +#else // linux + if (GLWin.ctx) + { + if (!glXMakeCurrent(GLWin.dpy, None, NULL)) + { + ERROR_LOG("Could not release drawing context.\n"); + } + glXDestroyContext(GLWin.dpy, GLWin.ctx); + GLWin.ctx = NULL; + } + /* switch back to original desktop resolution if we were in fs */ + if( GLWin.dpy != NULL ) { + if (GLWin.fs) { + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + } + } +#endif + + mapGLExtensions.clear(); +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + vb[i].Destroy(); + memset(&vb[i], 0, SIZEOF_VB); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + vb[i].Init(VB_BUFFERSIZE); + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; +} + +void ZeroGS::AddMessage(const char* pstr, u32 ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::DrawText(const char* pstr, int left, int top, u32 color) +{ + cgGLDisableProfile(cgvProf); + cgGLDisableProfile(cgfProf); + + glColor3f(((color>>16)&0xff)/255.0f, ((color>>8)&0xff)/255.0f, (color&0xff)/255.0f); + + font_p->printString(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight,0); + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + nBackbufferWidth = nNewWidth > 16 ? nNewWidth : 16; + nBackbufferHeight = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].nCount = 0; + vb[1].nCount = 0; + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + g_vsprog = g_psprog = 0; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = nBackbufferWidth, oldheight = nBackbufferHeight; + if( !Create(nNewWidth&~7, nNewHeight&~7) ) { + ERROR_LOG("Failed to recreate, changing to old\n"); + if( !Create(oldwidth, oldheight) ) { + SysMessage("failed to create dev, exiting...\n"); + exit(0); + } + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + +#ifdef _WIN32 + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); +#else // linux +#endif + } + + assert( vb[0].pBufferData != NULL && vb[1].pBufferData != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = mode > 0; + s_AAy = mode > 1; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + float f = mode > 0 ? 2.0f : 1.0f; + glPointSize(f); +} + +#define SET_UNIFORMPARAM(var, name) { \ + p = cgGetNamedParameter(pf->prog, name); \ + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) \ + pf->var = p; \ +} \ + +void SetupFragmentProgramParameters(FRAGMENTSHADER* pf, int context, int type) +{ + // uniform parameters + CGparameter p; + + p = cgGetNamedParameter(pf->prog, "g_fFogColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgConnectParameter(g_fparamFogColor, p); + } + + SET_UNIFORMPARAM(sOneColor, "g_fOneColor"); + SET_UNIFORMPARAM(sBitBltZ, "g_fBitBltZ"); + SET_UNIFORMPARAM(sInvTexDims, "g_fInvTexDims"); + SET_UNIFORMPARAM(fTexAlpha2, "fTexAlpha2"); + SET_UNIFORMPARAM(fTexOffset, "g_fTexOffset"); + SET_UNIFORMPARAM(fTexDims, "g_fTexDims"); + SET_UNIFORMPARAM(fTexBlock, "g_fTexBlock"); + SET_UNIFORMPARAM(fClampExts, "g_fClampExts"); + SET_UNIFORMPARAM(fTexWrapMode, "TexWrapMode"); + SET_UNIFORMPARAM(fRealTexDims, "g_fRealTexDims"); + SET_UNIFORMPARAM(fTestBlack, "g_fTestBlack"); + SET_UNIFORMPARAM(fPageOffset, "g_fPageOffset"); + SET_UNIFORMPARAM(fTexAlpha, "fTexAlpha"); + + // textures + p = cgGetNamedParameter(pf->prog, "g_sBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBlocks); + cgGLEnableTextureParameter(p); + } + + // cg parameter usage is wrong, so do it manually + if( type == 3 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv16to32"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv16to32); + cgGLEnableTextureParameter(p); + } + } + else if( type == 4 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv32to16"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv32to16); + cgGLEnableTextureParameter(p); + } + } + else { + p = cgGetNamedParameter(pf->prog, "g_sBilinearBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBilinearBlocks); + cgGLEnableTextureParameter(p); + } + } + + p = cgGetNamedParameter(pf->prog, "g_sMemory"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sMemory = p; + } + p = cgGetNamedParameter(pf->prog, "g_sSrcFinal"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sFinal = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDX"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDX = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDY"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDY = p; + } + p = cgGetNamedParameter(pf->prog, "g_sCLUT"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sCLUT = p; + } + p = cgGetNamedParameter(pf->prog, "g_sInterlace"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sInterlace = p; + } + + // set global shader constants + p = cgGetNamedParameter(pf->prog, "g_fExactColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetParameter4fv(p, Vector(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f)); + } + + p = cgGetNamedParameter(pf->prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(pf->prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fMult"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f)); +} + +void SetupVertexProgramParameters(CGprogram prog, int context) +{ + CGparameter p; + + p = cgGetNamedParameter(prog, "g_fPosXY"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgConnectParameter(g_vparamPosXY[context], p); + + p = cgGetNamedParameter(prog, "g_fZ"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, g_vdepth); + + Vector vnorm = Vector(g_filog32, 0, 0,0); + p = cgGetNamedParameter(prog, "g_fZNorm"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, vnorm); + + p = cgGetNamedParameter(prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, prog) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgvProf, NULL, NULL); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %d\n", Index); \ + SetupVertexProgramParameters(prog, !!(Index&SH_CONTEXT1)); \ +} \ + +#define LOAD_PS(Index, fragment) { \ + bLoadSuccess = true; \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + fragment.prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %d\n", Index); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, !!(Index&SH_CONTEXT1), 0); \ +} \ + +bool ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + u32 num = *(u32*)s_lpShaderResources; + int compressed_size = *(int*)(s_lpShaderResources+4); + int real_size = *(int*)(s_lpShaderResources+8); + int out; + + char* pbuffer = (char*)malloc(real_size); + inf((char*)s_lpShaderResources+12, &pbuffer[0], compressed_size, real_size, &out); + assert(out == real_size); + + s_lpShaderResources = (u8*)pbuffer; + SHADERHEADER* header = (SHADERHEADER*)s_lpShaderResources; + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + ppsTexture[i].prog = NULL; + } +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +// called +bool ZeroGS::LoadExtraEffects() +{ + SHADERHEADER* header; + bool bLoadSuccess = true; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i], pvs[2*i]); + LOAD_VS(vsshaders[i]|SH_CONTEXT1, pvs[2*i+1]); + //if( conf.mrtdepth ) { + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt.prog); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS(SH_REGULARPS, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS, ppsRegular[1]); + + if( conf.mrtdepth ) { + LOAD_PS(SH_REGULARPS, ppsRegular[2]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS(SH_REGULARFOGPS, ppsRegular[3]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[1]); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS(SH_BITBLTPS, ppsBitBlt[1]); + } + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); + LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + + g_bCRTCBilinear = TRUE; + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS(SH_CRTC_NEARESTPS, ppsCRTC[0]); + LOAD_PS(SH_CRTCINTER_NEARESTPS, ppsCRTC[0]); + } + else { + LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); + LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer&SHADER_REDUCED) + texfilter = 0; + assert(!(g_nPixelShaderVer&SHADER_REDUCED) || !exactcolor); + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAY_SIZE(ppsTexture) ); + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pbFailed != NULL ) *pbFailed = false; + + if( pf->prog != NULL ) + return pf; + + if( (g_nPixelShaderVer & SHADER_ACCURATE) && mapShaderResources.find(index+NUM_SHADERS*SHADER_ACCURATE) != mapShaderResources.end() ) + index += NUM_SHADERS*SHADER_ACCURATE; + + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) + ERROR_LOG("%d %d\n", index, g_nPixelShaderVer); + assert( header != NULL ); + + //printf("shader:\n%s\n", (char*)(s_lpShaderResources + (header)->offset)); + pf->prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); + if( pf->prog != NULL && cgIsProgram(pf->prog) && cgGetError() == CG_NO_ERROR ) { + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +#define LOAD_VS(name, prog, shaderver) { \ + prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %s\n", name); \ + SetupVertexProgramParameters(prog, args[0]==context1); \ +} \ + +#ifdef _DEBUG +#define SET_PSFILENAME(frag, name) frag.filename = name +#else +#define SET_PSFILENAME(frag, name) +#endif + +#define LOAD_PS(name, fragment, shaderver) { \ + bLoadSuccess = true; \ + fragment.prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %s\n", name); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, args[0]==context1, 0); \ + SET_PSFILENAME(fragment, name); \ +} \ + +bool ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +bool ZeroGS::LoadExtraEffects() +{ + const char* args[] = { NULL , NULL, NULL, NULL }; + char context0[255], context1[255]; + sprintf(context0, "-I%sctx0", EFFECT_DIR); + sprintf(context1, "-I%sctx1", EFFECT_DIR); + char* write_depth = "-DWRITE_DEPTH"; + bool bLoadSuccess = true; + + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + for(int i = 0; i < 4; ++i) { + args[0] = context0; + args[1] = NULL; + LOAD_VS(pvsshaders[i], pvs[2*i], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], cgvProf); + + //if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_VS(pvsshaders[i], pvs[2*i+8], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], cgvProf); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + args[0] = context0; + args[1] = NULL; + LOAD_VS("BitBltVS", pvsBitBlt.prog, cgvProf); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS("RegularPS", ppsRegular[0], cgfProf); + LOAD_PS("RegularFogPS", ppsRegular[1], cgfProf); + + if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_PS("RegularPS", ppsRegular[2], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS("RegularFogPS", ppsRegular[3], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS("BitBltPS", ppsBitBlt[0], cgfProf); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], cgfProf); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS("BitBltPS", ppsBitBlt[1], cgfProf); + } + + LOAD_PS("BitBltDepthPS", ppsBitBltDepth, cgfProf); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], cgfProf); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], cgfProf); + + g_bCRTCBilinear = TRUE; + LOAD_PS("CRTCPS", ppsCRTC[0], cgfProf); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS("CRTCPS_Nearest", ppsCRTC[0], cgfProf); + LOAD_PS("CRTCInterPS_Nearest", ppsCRTC[0], cgfProf); + } + else { + LOAD_PS("CRTCInterPS", ppsCRTC[1], cgfProf); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS("CRTC24PS", ppsCRTC24[0], cgfProf); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], cgfProf); + LOAD_PS("ZeroPS", ppsOne, cgfProf); + LOAD_PS("BaseTexturePS", ppsBaseTexture, cgfProf); + LOAD_PS("Convert16to32PS", ppsConvert16to32, cgfProf); + LOAD_PS("Convert32to16PS", ppsConvert32to16, cgfProf); + +// if( !conf.mrtdepth ) { +// ERROR_LOG("Disabling MRT depth writing\n"); +// s_bWriteDepth = FALSE; +// } + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + if( pbFailed != NULL ) *pbFailed = false; + + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pf->prog != NULL ) + return pf; + + pf->prog = LoadShaderFromType(EFFECT_DIR, EFFECT_NAME, type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, context); + + if( pf->prog != NULL ) { +#ifdef _DEBUG + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + pf->filename = str; +#endif + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { + // try again +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + //assert(0); + // NULL makes things crash + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].nCount > 0 ) +// { +// assert( vb[prim->ctxt].nCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != 0 ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +void ZeroGS::Flush(int context) +{ + GL_REPORT_ERRORD(); + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.nCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.nCount = prevcount; + //if( curvb.nCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.nCount == 0 ) + return; + } + + DVProfileFunc _pf("Flush"); + + GL_REPORT_ERRORD(); + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.nCount = 0; + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].nCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + GL_REPORT_ERRORD(); + CRenderTarget* ptextarg = NULL; + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H ) { // handle 8h cluts + // don't support clut targets, read from mem + if( s_ClutResolve <= 1 ) { // xenosaga requires 2 resolves + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.nCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + curvb.prndr->CreateFeedback(); + + if(s_bWriteDepth && curvb.pdepth != NULL) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + icurctx = context; + + DVProfileFunc _pf5("Flush:after texvars"); + + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[g_nCurVBOIndex]); + g_nCurVBOIndex = (g_nCurVBOIndex+1)%g_vboBuffers.size(); + glBufferData(GL_ARRAY_BUFFER, curvb.nCount * sizeof(VertexGPU), curvb.pBufferData, GL_STREAM_DRAW); +// void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); +// memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU)); +// glUnmapBuffer(GL_ARRAY_BUFFER); + SET_STREAM(); + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + +#ifdef _DEBUG + //curvb.prndr->SetRenderTarget(0); + //curvb.pdepth->SetDepthStencilSurface(); + //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +#endif + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (COLORMASK_BLUE|COLORMASK_GREEN|COLORMASK_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_ALPHA; + + GL_COLORMASK(s_dwColorWrite); + + Rect& scissor = curvb.prndr->scissorrect; + glScissor(scissor.x, scissor.y, scissor.w, scissor.h); + + u32 dwUsingSpecialTesting = 0; + u32 dwFilterOpts = 0; + + FRAGMENTSHADER* pfragment = NULL; + + // need exact if equal or notequal + int exactcolor = 0; + if( !(g_nPixelShaderVer&SHADER_REDUCED) ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + u32 ptexclut = 0; + if( curvb.curprim.tme ) { + + if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + Vector vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + shadertype = 1; + if( curvb.tex0.psm == PSMT8H && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + glGenTextures(1, &ptexclut); + glBindTexture(GL_TEXTURE_2D, ptexclut); + vector data((curvb.tex0.cpsm&2) ? 512 : 1024); + + if( ptexclut != 0 ) { + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&data[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&data[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 1, 0, GL_RGBA, (curvb.tex0.cpsm&2)?GL_UNSIGNED_SHORT_5_5_5_1:GL_UNSIGNED_BYTE, &data[0]); + s_vecTempTextures.push_back(ptexclut); + + if( g_bSaveTex ) + SaveTexture("clut.tga", GL_TEXTURE_2D, ptexclut, 256, 1); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + if( !(g_nPixelShaderVer&SHADER_REDUCED) && (ptextarg->psm & 2) ) { + shadertype = 4; + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + + if( shadertype == 3 ) { + Vector v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 16.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + } + else if( shadertype == 4 ) { + Vector v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 16.0f / (float)ptextarg->fbh; + v.z = -1; + v.w = 8.0f / (float)ptextarg->fbh; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = 2; + vpageoffset.y = 1; + vpageoffset.z = 0; + vpageoffset.w = 0.0001f; + } + + u32 ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + s_ptexCurSet[context] = ptexset; + + if( !curvb.tex1.mmag ) { + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + dwFilterOpts |= 1; + } + + if( !curvb.tex1.mmin ) { + if( curvb.tex1.mmag ) + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + dwFilterOpts |= 2; + } + + Vector vTexDims; + vTexDims.x = curvb.tex0.tw; + vTexDims.y = curvb.tex0.th; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + vTexDims.z = (float)xcoord; + vTexDims.w = (float)ycoord; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f; + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// Vector valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + cgGLSetParameter4fv(pfragment->fPageOffset, vpageoffset); + + if( g_bSaveTex ) + SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV, + ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, ptextarg->fbw<fbh<ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) { + SaveTex(&curvb.tex0, 1); +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; +// int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; +// SaveTexture("real.tga", GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex, texwidth, texheight); + } + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + } + + if( pfragment->prog != g_psprog ) { + // programs changed, so reset the texture variables + vb[context].bTexConstsSync = 0; + vb[context].bVarsTexSync = 0; + } + + SetTexVariables(context, pfragment, ptextarg == NULL); + } + else { + pfragment = &ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + } + + assert(pfragment != 0 ); + if( curvb.curprim.tme ) { + // have to enable the texture parameters + if( curvb.ptexClamp[0] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDX); + } + if( curvb.ptexClamp[1] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDY); + } + if( pfragment->sMemory != NULL && s_ptexCurSet[context] != 0) { + cgGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context]); + cgGLEnableTextureParameter(pfragment->sMemory); + } + if( pfragment->sCLUT != NULL && ptexclut != 0 ) { + cgGLSetTextureParameter(pfragment->sCLUT, ptexclut); + cgGLEnableTextureParameter(pfragment->sCLUT); + } + } + + DVProfileFunc _pf4("Flush:before bind"); + GL_REPORT_ERRORD(); + + // set the shaders + SETVERTEXSHADER(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + + if( pfragment->prog != g_psprog ) { + cgGLBindProgram(pfragment->prog); + g_psprog = pfragment->prog; + } + + GL_REPORT_ERRORD(); + + DVProfileFunc _pf1("Flush:after bind"); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest && bCanRenderStencil) { + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + } + else glDisable(GL_STENCIL_TEST); + + glDepthMask(!curvb.zbuf.zmsk); + GL_ZTEST(curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + //SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + glDepthFunc(g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + GL_ALPHATEST(curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + glAlphaFunc(g_dwAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + } + + if( s_bWriteDepth ) { + if(!curvb.zbuf.zmsk) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + glDisable(GL_BLEND); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb, pfragment->sOneColor); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + glEnable(GL_BLEND); + } + + if( curvb.curprim.abe ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb, pfragment->sOneColor); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + Vector v = vAlphaBlendColor;// + Vector(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + else { + // not using blending so set to defaults + Vector v = exactcolor ? Vector(1, 510*255.0f/256.0f, 0, 0) : Vector(1,2*255.0f/256.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + s_stencilref = STENCIL_SPECIAL; + s_stencilmask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + glEnable(GL_STENCIL_TEST); + glStencilMask(STENCIL_PIXELWRITE); + GL_STENCILFUNC(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// glEnable(GL_SCISSOR_TEST); + + GL_REPORT_ERRORD(); + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + GL_REPORT_ERRORD(); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + GL_REPORT_ERRORD(); + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + glColorMask(1,1,1,0); + + glDepthMask(0); + + if( s_bWriteDepth ) + ResetRenderTarget(1); + } + else { + // zbuffer update only + glColorMask(0,0,0,0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + Vector v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + glEnable(GL_BLEND); + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// IDirect3DQuery9* pOcclusionQuery; +// u32 numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + GL_REPORT_ERRORD(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(u32), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( oldabe ) glEnable(GL_BLEND); + + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_COLORMASK(s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + } + + GL_REPORT_ERRORD(); + + if( dwUsingSpecialTesting ) { + // render the real alpha + glDisable(GL_ALPHA_TEST); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + glDepthMask(0); + + glStencilFunc(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + Vector v = Vector(0,exactcolor ? 510.0f : 2.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + DRAW(); + + // don't need to restore + } + + GL_REPORT_ERRORD(); + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&COLORMASK_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&COLORMASK_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { +#ifdef _WIN32 + CreateDirectory("frames", NULL); +#else + mkdir("frames", 0755); +#endif + char str[255]; + sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) { + //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + //glFlush(); + //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, curvb.prndr->fbw<fbh<fbw<fbh<SetRenderTarget(1); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + + GL_ZTEST(curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes (binding didn't change) + if( dwFilterOpts & 1 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if( dwFilterOpts & 2 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.nCount+0x100000; +//#endif + + curvb.nCount = 0; + curvb.curprim.abe = oldabe; + //if( oldabe ) glEnable(GL_BLEND); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + --s_nWireframeCount; + } + } + + GL_REPORT_ERRORD(); +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + int left = 25, top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + DrawText(it->str, left+1, top+1, 0xff000000); + DrawText(it->str, left, top, 0xffffff30); + top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + GLenum err = GL_NO_ERROR; + + GL_REPORT_ERROR(); + + fAlpha = 1; + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // play custom animation + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + // tex coords + Vector v = Vector(1/32767.0f, 1/32767.0f, 0, 0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + v.x = (float)nLogoWidth; + v.y = (float)nLogoHeight; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = fAlpha; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ptexLogo); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBaseTexture.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // restore + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + ProcessMessages(); + +#ifdef _WIN32 + SwapBuffers(hDC); +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + + glEnable(GL_SCISSOR_TEST); + glEnable(GL_STENCIL_TEST); + + vb[0].bSyncVars = 0; + vb[1].bSyncVars = 0; + + GL_REPORT_ERROR(); + GLint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( status == GL_FRAMEBUFFER_COMPLETE_EXT || status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ); +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(Vector& v, int dispwidth, int dispheight) +{ + double temp; + float f; + if( dispwidth * nBackbufferHeight > dispheight * nBackbufferWidth) { + // limited by width + + // change in ratio + f = ((float)nBackbufferWidth / (float)dispwidth) / ((float)nBackbufferHeight / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-(float)modf(v.y*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + v.w += (1-(float)modf(v.w*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + } + else { + // limited by height + f = ((float)nBackbufferHeight / (float)dispheight) / ((float)nBackbufferWidth / (float)dispwidth); + f -= (float)modf(f*nBackbufferWidth, &temp)/(float)nBackbufferWidth; + v.x *= f; + v.z *= f; + } + +// v.y *= -1; +// v.w *= -1; + v *= 1/32767.0f; +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + //if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(nBackbufferWidth, nBackbufferHeight); + //} +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( g_bIsLost ) return; + +//#ifdef RELEASE_TO_PUBLIC +// if(g_nRealFrame < 80 ) { +// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); +// +// if( g_nRealFrame == 79 ) +// SAFE_RELEASE_TEX(ptexLogo); +// return; +// } +//#endif + + if( conf.mrtdepth && pvs[8] == NULL ) { + conf.mrtdepth = 0; + s_bWriteDepth = FALSE; + ERROR_LOG("Disabling MRT depth writing\n"); + } + + Flush(0); + Flush(1); + GL_REPORT_ERRORD(); + + DVProfileFunc _pf("RenderCRTC"); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) { + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, vb[0].prndr->ptex, vb[0].prndr->fbw<fbh<ptex, vb[1].prndr->fbw<fbh< 0 ) + FlushTransferRanges(NULL); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; + + // reset fba after every frame + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + +// static int counter = 0; +// counter++; + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = COLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + GL_REPORT_ERRORD(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + + GL_REPORT_ERRORD(); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + Vector v, valpha; + u32 interlacetex = 0; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + interlacetex = CreateInterlaceTex(2*texframe.th); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + glEnable(GL_BLEND); + zgsBlendEquationSeparateEXT(GL_FUNC_ADD, GL_FUNC_ADD); + + if( PMODE->MMOD ) { + glBlendColorEXT(PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), 0.5f); + s_srcrgb = GL_CONSTANT_COLOR_EXT; + s_dstrgb = GL_ONE_MINUS_CONSTANT_COLOR_EXT; + } + else { + s_srcrgb = GL_SRC_ALPHA; + s_dstrgb = GL_ONE_MINUS_SRC_ALPHA; + } + + s_srcalpha = PMODE->AMOD ? GL_ZERO : GL_ONE; + s_dstalpha = PMODE->AMOD? GL_ONE : GL_ZERO; + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); + } + + if( bUsingStencil ) { + glStencilMask(1< listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + if( g_bSaveFinalFrame ) + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptarg->ptex, ptarg->fbw<fbh<DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + glClear(GL_STENCIL_BUFFER_BIT); + } + bUsingStencil = 1; + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_NOTEQUAL, 3, 1<fbh; + + // tex coords + v = Vector((float)(texframe.tw << s_AAx), (float)(dh << s_AAy), (float)(pfb->DBX << s_AAx), (float)(dby< 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTCTarg[bInterlace].sInvTexDims ) { + v.x = fiw; + v.y = fih; + v.z = 0; + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sInvTexDims, v); + } + + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sOneColor, valpha); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sFinal, ptarg->ptex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sFinal); + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTCTarg[bInterlace].prog); + GL_REPORT_ERRORD(); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + //SaveRenderTarget("temp.tga", nBackbufferWidth, nBackbufferHeight, 0); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + SetTexVariablesInt(0, g_bCRTCBilinear?2:0, texframe, pmemtarg, &ppsCRTC[bInterlace], 1); + cgGLSetTextureParameter(ppsCRTC[bInterlace].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sMemory); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = Vector(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + cgGLSetParameter4fv(ppsCRTC[bInterlace].sOneColor, valpha); + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + float fih = 1.0f / (float)texframe.th; + if( g_bCRTCBilinear ) + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(texframe.tw,texframe.th,-0.5f,-0.5f)); + else + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(1,1,-0.5f/(float)texframe.tw,-0.5f/(float)texframe.th)); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTC[bInterlace].sInvTexDims ) { + v.x = 1.0f / (float)texframe.tw; + v.y = fih; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * fih; + cgGLSetParameter4fv(ppsCRTC[bInterlace].sInvTexDims, v); + } + + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTC[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTC[bInterlace].prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + GL_REPORT_ERRORD(); + if(1) {// || !bInterlace) { + glDisable(GL_BLEND); + ProcessMessages(); + + if( g_bMakeSnapshot ) { + char str[64]; + int left = 200, top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", zgsrevision, zgsbuild, zgsminor, fFPS, s_frameskipping?" - frameskipping":""); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if( g_bDisplayFPS ) { + char str[64]; + int left = 10, top = 15; + sprintf(str, "%.1f fps", fFPS); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if( glGetError() != GL_NO_ERROR ) { + printf("glerror before swap!\n"); + } + +#ifdef _WIN32 + static u32 lastswaptime = 0; + //if( timeGetTime() - lastswaptime > 14 ) { + SwapBuffers(hDC); + lastswaptime = timeGetTime(); + //} +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + +// if( glGetError() != GL_NO_ERROR) { +// // device is lost, need to recreate +// ERROR_LOG("device lost\n"); +// g_bIsLost = TRUE; +// Reset(); +// return; +// } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SaveRenderTarget(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", nBackbufferWidth, -nBackbufferHeight, 0)) {//(conf.options&GSOPTION_TGASNAP)?0:1) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + // switch back to rendering to textures + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + g_MemTargs.DestroyCleared(); + + if( s_vecTempTextures.size() > 0 ) + glDeleteTextures((GLsizei)s_vecTempTextures.size(), &s_vecTempTextures[0]); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAY_SIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAY_SIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAY_SIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + ERROR_LOG("video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + +#define MOVZ(p, gsz) p.z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; +#define MOVFOG(p, gsf) p.f = ((s16)(gsf).f<<7)|0x7f; + +#define SET_VERTEX(p, Index) { \ + int index = Index; \ + p.x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; \ + p.y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; \ + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); \ + y = ((int)gs.gsvertex[index].y - curvb.offset.y); \ + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); \ + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ \ + p.f = ((s16)gs.gsvertex[index].f<<7)|0x7f; \ + MOVZ(p, gs.gsvertex[index].z); \ + p.rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; \ + if( (g_GameSettings & GAME_TEXAHACK) && !(p.rgba&0xffffff) ) \ + p.rgba = 0; \ + if( prim->tme ) { \ + if( prim->fst ) { \ + p.s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; \ + p.t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; \ + p.q = 1; \ + } \ + else { \ + p.s = gs.gsvertex[index].s; \ + p.t = gs.gsvertex[index].t; \ + p.q = gs.gsvertex[index].q; \ + } \ + } \ +} \ + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + +//#define OUTPUT_VERT(fn, vert, id) { \ +// fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128); \ +//} \ + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(1); + + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(p[0], last); + curvb.nCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(2); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(p[0], next); + SET_VERTEX(p[1], last); + + curvb.nCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(p[0], 0); + SET_VERTEX(p[1], 1); + SET_VERTEX(p[2], 2); + + curvb.nCount += 3; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(p[0], 0); + SET_VERTEX(p[1], 1); + SET_VERTEX(p[2], 2); + + curvb.nCount += 3; + + // add 1 to skip the first vertex + if( gs.primIndex == gs.nTriFanVert ) + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(6); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if( s_AAx ) { + gs.gsvertex[last].x += 4; + if( s_AAy ) + gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + // return; + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + + SET_VERTEX(p[0], next); MOVZ(p[0], gs.gsvertex[last].z); MOVFOG(p[0], gs.gsvertex[last]); + SET_VERTEX(p[3], next); MOVZ(p[3], gs.gsvertex[last].z); MOVFOG(p[3], gs.gsvertex[last]); + + SET_VERTEX(p[1], last); MOVZ(p[1], gs.gsvertex[last].z); MOVFOG(p[1], gs.gsvertex[last]); + SET_VERTEX(p[4], last); MOVZ(p[4], gs.gsvertex[last].z); MOVFOG(p[4], gs.gsvertex[last]); + + SET_VERTEX(p[2], next); MOVZ(p[2], gs.gsvertex[last].z); MOVFOG(p[2], gs.gsvertex[last]); + p[2].s = p[1].s; + p[2].x = p[1].x; + + SET_VERTEX(p[5], last); MOVZ(p[5], gs.gsvertex[last].z); MOVFOG(p[5], gs.gsvertex[last]); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.nCount += 6; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb, CGparameter sOneColor) +{ + // add fba to all pixels + GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); + glStencilMask(STENCIL_CLEAR); + glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + DRAW(); + + if( !curvb.test.ate ) + glDisable(GL_ALPHA_TEST); + else { + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + } + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) { + curvb.pdepth->SetRenderTarget(1); + } + } + GL_ZTEST(curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, CGparameter sOneColor) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) { + if( curvb.test.afail == 1 ) glDisable(GL_ALPHA_TEST); + } + + glDepthMask(0); + glColorMask(0,0,0,0); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + // or a 1 to the stencil buffer wherever alpha passes + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + s_stencilfunc = GL_ALWAYS; + + glEnable(GL_STENCIL_TEST); + + if( !s_bDestAlphaTest ) { + // clear everything + s_stencilref = 0; + glStencilMask(STENCIL_CLEAR); + glDisable(GL_ALPHA_TEST); + GL_STENCILFUNC_SET(); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], curvb.test.aref*(1/255.0f)); + } + + s_stencilref = STENCIL_SPECIAL; + glStencilMask(STENCIL_SPECIAL); + GL_STENCILFUNC_SET(); + glDisable(GL_DEPTH_TEST); + + DRAW(); + + if( curvb.test.zte ) + glEnable(GL_DEPTH_TEST); + GL_ALPHATEST(0); + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + // set rt next level + if( s_bWriteDepth ) { + curvb.pdepth->SetRenderTarget(1); + } + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + glStencilMask(STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + s_stencilmask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS; + s_stencilref = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + GL_STENCILFUNC_SET(); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + glStencilMask(STENCIL_ALPHABIT); + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + GL_ALPHATEST(0); + + SETPIXELSHADER(ppsOne.prog); + DRAW(); + + // process when alpha >= 0xff + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_ALWAYS, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + + DRAW(); + + // restore state + GL_COLORMASK(s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + glEnable(GL_ALPHA_TEST); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_ZTEST(curvb.test.zte); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb, CGparameter sOneColor) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + glStencilMask(STENCIL_ALPHABIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + GL_STENCILFUNC(GL_EQUAL, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + // processes the pixels with ALPHA < 0x80*2 + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_LEQUAL, 1); + + // add 1 to dest + GL_BLEND_ALPHA(GL_ONE, GL_ONE); + GL_BLENDEQ_ALPHA(GL_FUNC_ADD); + + float f = 1; + cgGLSetParameter4fv(sOneColor, &f); + SETPIXELSHADER(ppsOne.prog); + + DRAW(); + + glDisable(GL_ALPHA_TEST); + + // reset bits + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_GREATER, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + } + + // restore (SetAlphaVariables) + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + if(vAlphaBlendColor.y<0) GL_BLENDEQ_ALPHA(GL_FUNC_REVERSE_SUBTRACT); + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + curvb.pdepth->SetRenderTarget(1); + } + } + GL_ZTEST(curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + GL_REPORT_ERRORD(); + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->fbh ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + GL_REPORT_ERRORD(); + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + +// if( s_bWriteDepth ) { +// if( bSetTarg ) { +// curvb.pdepth->SetRenderTarget(1); +// curvb.pdepth->SetDepthStencilSurface(); +// } +// } +// else if( bSetTarg ) +// curvb.pdepth->SetDepthStencilSurface(); + + curvb.prndr->Update(context, curvb.pdepth); + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + curvb.prndr->SetRenderTarget(0); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthStencilSurface(); + if( conf.mrtdepth && ZeroGS::IsWriteDepth() ) + curvb.pdepth->SetRenderTarget(1); + + if( s_ptexCurSet[0] == curvb.prndr->ptex ) { + s_ptexCurSet[0] = 0; + } + if( s_ptexCurSet[1] == curvb.prndr->ptex ) { + s_ptexCurSet[1] = 0; + } + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) { + WARN_LOG("frame and zbuf not aligned\n"); + } + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) + vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + GL_REPORT_ERRORD(); +} + +void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint) +{ + if( !vb[context].curprim.tme ) { + return; + } + + DVProfileFunc _pf("SetTexVariables"); + + assert( !vb[context].bNeedTexCheck ); + + Vector v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + Vector valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + Vector vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + cgGLSetParameter4fv(pfragment->fTexAlpha, valpha); + cgGLSetParameter4fv(pfragment->fTexAlpha2, valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + cgGLSetParameter4fv(pfragment->fTestBlack, vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + Vector v, v2; + v.x = v.y = 0; + u32* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = 0; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, 0); + } + break; + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + } + + if( pfragment->fTexWrapMode != 0 ) + cgGLSetParameter4fv(pfragment->fTexWrapMode, v); + if( pfragment->fClampExts != 0 ) + cgGLSetParameter4fv(pfragment->fClampExts, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } + + if( settexint ) { + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + else { + vb[context].bVarsTexSync = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force) +{ + DVProfileFunc _pf("SetTexVariablesInt"); + + Vector v; + assert( pmemtarg != NULL && pfragment != NULL); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + bool bUseBilinear = bilinear > 1 || (bilinear && conf.bilinear); + if( bUseBilinear ) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + cgGLSetParameter4fv(pfragment->fRealTexDims, v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + Vector vTexDims; + vTexDims.x = b.vTexDims.x * fw; + vTexDims.y = b.vTexDims.y * fh; + vTexDims.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + vTexDims.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bUseBilinear ) { + vTexDims.x *= 1/128.0f; + vTexDims.y *= 1/512.0f; + vTexDims.z *= 1/128.0f; + vTexDims.w *= 1/512.0f; + } + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + cgGLSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x); + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + // get hardware texture dims + int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; + int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; + + v.y = 1;//(float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f);//*v.y; + +// v.x *= (float)texheight; +// v.y *= (float)texheight; + v.z = (float)texwidth; + if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) + v.w = 0.25f; + else + v.w = 0.5f; + + cgGLSetParameter4fv(pfragment->fPageOffset, v); + + if( force ) s_ptexCurSet[context] = pmemtarg->ptex->tex; + else s_ptexNextSet[context] = pmemtarg->ptex->tex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} + +// assumes texture factor is unused +#define SET_ALPHA_COLOR_FACTOR(sign) { \ + switch(a.c) { \ + case 0: \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + s_srcalpha = GL_ONE; \ + s_alphaeq = (sign) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT; \ + break; \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// printf("bfactor: %8.8x\n", dwTemp); \ +// glBlendColorEXT(dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + bool alphaenable = true; + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + u32 dwTemp = 0xffffffff; + + // default + s_srcalpha = GL_ONE; + s_dstalpha = GL_ZERO; + s_alphaeq = GL_FUNC_ADD; + + s_alphaInfo = a; + + vAlphaBlendColor = Vector(1,2*255.0f/256.0f,0,0); + u32 usec = a.c; + + if( a.a == a.b ) { // just d remains + if( a.d == 0 ) { + alphaenable = false; + } + else { + s_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO; + s_srcrgb = GL_ZERO; + s_rgbeq = GL_FUNC_ADD; + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) { // zero + + if( a.a == 2 ) { + // zero all color + s_srcrgb = GL_ZERO; + s_dstrgb = GL_ZERO; + goto EndSetAlpha; + } + else if( a.b == 2 ) { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) { + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE; + } + else { + bAlphaClamping = 2; + + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec]; + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + s_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT; + s_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + s_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + } + else if( a.a == 2 ) { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) { + // can get away with 1-A + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]; + } + else { + s_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec]; + } + } + else if( a.b == 2 ) { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + s_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA; + } + else { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec]; + } + } + else { + //b2XAlphaTest = 1; + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]; + } + } + else { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + s_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + else { + assert(a.b == a.d); + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + s_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else { + //b2XAlphaTest = 1; + s_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + } + +EndSetAlpha: + + GL_BLEND_SET(); + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); + if( alphaenable ) glEnable(GL_BLEND); // always set + else glDisable(GL_BLEND); + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + Vector v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + cgGLSetParameter4fv(g_fparamFogColor, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + + // do a fast test with MMX +#ifdef _MSC_VER + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + +Return: + emms + mov ebx, storeebx + } +#endif // __x86_64__ + +#else // linux + +#ifdef __x86_64__ + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%rcx]\n" + "movq %%mm1, [%%rcx+8]\n" + "pcmpeqd %%mm0, [%%rdx]\n" + "pcmpeqd %%mm1, [%%rdx+16]\n" + "movq %%mm2, [%%rcx+16]\n" + "movq %%mm3, [%%rcx+24]\n" + "pcmpeqd %%mm2, [%%rdx+32]\n" + "pcmpeqd %%mm3, [%%rdx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%rcx+32]\n" + "movq %%mm5, [%%rcx+40]\n" + "pcmpeqd %%mm4, [%%rdx+8]\n" + "pcmpeqd %%mm5, [%%rdx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%rcx+48]\n" + "movq %%mm7, [%%rcx+56]\n" + "pcmpeqd %%mm6, [%%rdx+40]\n" + "pcmpeqd %%mm7, [%%rdx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%rbx, 16\n" + "jle Return\n" + "test %%rbx, 0x10\n" + "jz AddRcx\n" + "sub %%rdx, 448\n" // go back and down one column +"AddRcx:\n" + "add %%rdx, 256\n" // go to the right block + "cmp %%rbx, 0x90\n" + "jne Continue1\n" + "add %%rdx, 256\n" // skip whole block +"Continue1:\n" + "add %%rcx, 64\n" + "sub %%rbx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "rax", "memory"); +#else + // do a fast test with MMX + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%ecx]\n" + "movq %%mm1, [%%ecx+8]\n" + "pcmpeqd %%mm0, [%%edx]\n" + "pcmpeqd %%mm1, [%%edx+16]\n" + "movq %%mm2, [%%ecx+16]\n" + "movq %%mm3, [%%ecx+24]\n" + "pcmpeqd %%mm2, [%%edx+32]\n" + "pcmpeqd %%mm3, [%%edx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%ecx+32]\n" + "movq %%mm5, [%%ecx+40]\n" + "pcmpeqd %%mm4, [%%edx+8]\n" + "pcmpeqd %%mm5, [%%edx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%ecx+48]\n" + "movq %%mm7, [%%ecx+56]\n" + "pcmpeqd %%mm6, [%%edx+40]\n" + "pcmpeqd %%mm7, [%%edx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%ebx, 16\n" + "jle Return\n" + "test %%ebx, 0x10\n" + "jz AddEcx\n" + "sub %%edx, 448\n" // go back and down one column +"AddEcx:\n" + "add %%edx, 256\n" // go to the right block + "cmp %%ebx, 0x90\n" + "jne Continue1\n" + "add %%edx, 256\n" // skip whole block +"Continue1:\n" + "add %%ecx, 64\n" + "sub %%ebx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "eax", "memory"); +#endif // __x86_64__ + +#endif // _WIN32 + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // note sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + } + + Flush(!ctx); + + int entries = (tex0.psm&3)==3 ? 256 : 16; + + if( tex0.csm ) { + // 16bit psm + // eggomania uses non16bit textures for csm2 + if( tex0.cpsm == PSMCT16 ) { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for(int i = 0; i < entries; ++i) { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + // check for wrapping + if( ((u32)(uptr)dst & 0x3ff) == 0 ) + dst = (u16*)(g_pbyGSClut+2); + } + } + else if( tex0.cpsm == PSMCT16S ) { + + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for(int i = 0; i < entries; ++i) { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + // check for wrapping + if( ((u32)(uptr)dst & 0x3ff) == 0 ) + dst = (u16*)(g_pbyGSClut+2); + } + } + else if( tex0.cpsm == PSMCT32 || tex0.cpsm == PSMCT24 ) { + + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + for(int i = 0; i < entries; ++i) { + *dst++ = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + } + } + else { +#ifndef RELEASE_TO_PUBLIC + //printf("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + } + } + else { + if( tex0.cpsm <= 1 ) { + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + } + else { + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else if(entries == 256) { + // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + } + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) { + if( s_ptexCurSet[0] != s_ptexNextSet[0] ) { + s_ptexCurSet[0] = s_ptexNextSet[0]; + } + if( s_ptexCurSet[1] != s_ptexNextSet[1] ) { + s_ptexCurSet[1] = s_ptexNextSet[1]; + } + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + g_nCurVBOIndex = 0; + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + vb[0].Destroy(); + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pBufferData = NULL; + + vb[1].Destroy(); + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pBufferData = NULL; + + for(int i = 0; i < 2; ++i) { + vb[i].Init(VB_BUFFERSIZE); + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); // switch to the backbuffer + SetFogColor(gs.fogcol); + + GL_REPORT_ERRORD(); + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int jpeg) +{ + bool bflip = height < 0; + height = abs(height); + vector data(width*height); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + + if( bflip ) { + // swap scanlines + vector scanline(width); + for(int i = 0; i < height/2; ++i) { + memcpy(&scanline[0], &data[i*width], width*4); + memcpy(&data[i*width], &data[(height-i-1)*width], width*4); + memcpy(&data[(height-i-1)*width], &scanline[0], width*4); + } + } + + if( jpeg ) return SaveJPEG(filename, width, height, &data[0], 70); + + return SaveTGA(filename, width, height, &data[0]); +} + +bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +{ + vector data(width*height); + glBindTexture(textarget, tex); + glGetTexImage(textarget, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) { + return false; + } + + return SaveTGA(filename, width, height, &data[0]);//SaveJPEG(filename, width, height, &data[0], 70); +} + +extern "C" { +#ifdef _WIN32 +#define XMD_H +#undef FAR +#define HAVE_BOOLEAN +#endif + +#include "jpeglib.h" +} + +bool ZeroGS::SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) +{ + u8* image_buffer = new u8[image_width * image_height * 3]; + u8* psrc = (u8*)pdata; + + // input data is rgba format, so convert to rgb + u8* p = image_buffer; + for(int i = 0; i < image_height; ++i) { + for(int j = 0; j < image_width; ++j) { + p[0] = psrc[0]; + p[1] = psrc[1]; + p[2] = psrc[2]; + p += 3; + psrc += 4; + } + } + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + delete image_buffer; + /* And we're done! */ + return true; +} + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +struct TGA_HEADER +{ + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header + +#if defined(_MSC_VER) +}; +#pragma pack(pop) +#else +} __attribute__((packed)); +#endif + +bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) +{ + TGA_HEADER hdr; + FILE* f = fopen(filename, "wb"); + if( f == NULL ) + return false; + + assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); + + memset(&hdr, 0, sizeof(hdr)); + hdr.imagetype = 2; + hdr.bits = 32; + hdr.width = width; + hdr.height = height; + hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical + + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(pdata, width*height*4, 1, f); + fclose(f); + return true; +} + +// AVI capture stuff +void ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + +#ifdef _WIN32 + START_AVI("zerogs.avi"); +#else // linux + //TODO +#endif + s_aviinit = 1; + } + else { + ERROR_LOG("Continuing from previous capture"); + } + + s_avicapturing = 1; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit ); + + //vector mem(nBackbufferWidth*nBackbufferHeight); + vector data(nBackbufferWidth*nBackbufferHeight); + glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return; + +// u8* pend = (u8*)&data[0] + (nBackbufferHeight-1)*nBackbufferWidth*4; +// for(int i = 0; i < conf.height; ++i) { +// memcpy_amd(&mem[nBackbufferWidth*4*i], pend - nBackbufferWidth*4*i, nBackbufferWidth * 4); +// } + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + +#ifdef _WIN32 + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, nBackbufferWidth, nBackbufferHeight, 32, &data[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return; + } +#else // linux + //TODO +#endif +} + diff --git a/plugins/gs/zerogs/opengl/zerogs.h b/plugins/gs/zerogs/opengl/zerogs.h new file mode 100644 index 0000000000..d3ea7fb755 --- /dev/null +++ b/plugins/gs/zerogs/opengl/zerogs.h @@ -0,0 +1,555 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#ifndef _WIN32 +// adding glew support instead of glXGetProcAddress (thanks to scaught) +#include +#endif + +#include +#include + +#ifndef _WIN32 +#include +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} +#else +#include "glprocs.h" +#endif + +#include +#include + +#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define SAFE_RELEASE_PROG(x) { if( (x) != NULL ) { cgDestroyProgram(x); x = NULL; } } +#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_#x"\n"); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); action; } } + +#define GL_REPORT_ERROR() { err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } + +#ifdef _DEBUG +#define GL_REPORT_ERRORD() { GLenum err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } +#else +#define GL_REPORT_ERRORD() +#endif + +// sets the data stream +#define SET_STREAM() { \ + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ + glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ + glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ + glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ +} + +#define SETVERTEXSHADER(prog) { \ + if( (prog) != g_vsprog ) { \ + cgGLBindProgram(prog); \ + g_vsprog = prog; \ + } \ +} \ + +#define SETPIXELSHADER(prog) { \ + if( (prog) != g_psprog ) { \ + cgGLBindProgram(prog); \ + g_psprog = prog; \ + } \ +} \ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +extern CGprogram g_vsprog, g_psprog; + +struct FRAGMENTSHADER +{ + FRAGMENTSHADER() : prog(0), sMemory(0), sFinal(0), sBitwiseANDX(0), sBitwiseANDY(0), sInterlace(0), sCLUT(0), sOneColor(0), sBitBltZ(0), + fTexAlpha2(0), fTexOffset(0), fTexDims(0), fTexBlock(0), fClampExts(0), fTexWrapMode(0), + fRealTexDims(0), fTestBlack(0), fPageOffset(0), fTexAlpha(0) {} + + CGprogram prog; + CGparameter sMemory, sFinal, sBitwiseANDX, sBitwiseANDY, sCLUT, sInterlace; + CGparameter sOneColor, sBitBltZ, sInvTexDims; + CGparameter fTexAlpha2, fTexOffset, fTexDims, fTexBlock, fClampExts, fTexWrapMode, fRealTexDims, fTestBlack, fPageOffset, fTexAlpha; + +#ifdef _DEBUG + string filename; +#endif +}; + +struct VERTEXSHADER +{ + VERTEXSHADER() : prog(0), sBitBltPos(0), sBitBltTex(0) {} + CGprogram prog; + CGparameter sBitBltPos, sBitBltTex, fBitBltTrans; // vertex shader constants +}; + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +extern u8* g_pbyGSMemory; +extern u8* g_pbyGSClut; // the temporary clut buffer +extern CGparameter g_vparamPosXY[2], g_fparamFogColor; + +namespace ZeroGS { + + typedef void (*DrawFn)(); + + enum RenderFormatType + { + RFT_byte8 = 0, // A8R8G8B8 + RFT_float16 = 1, // A32R32B32G32 + }; + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + virtual ~CRenderTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == 0 || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + void SetRenderTarget(int targ); + + void* psys; // system data used for comparison + u32 ptex; + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + Vector vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + Rect scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + u32 ptexFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthStencilSurface(); + + u32 pdepth; // 24 bit, will contain the stencil buffer if possible + u32 pstencil; // if not 0, contains the stencil buffer + int icount; // internal counter + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct TEXTURE + { + inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} + inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } + u32 tex; + int ref; + u8* memptr; // GPU memory used for comparison + }; + + inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), channels(0),cpsm(0), clearminy(0), clearmaxy(0), validatecount(0) {} + + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + if( ptex != NULL ) ptex->ref++; + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + channels = r.channels; + validatecount = r.validatecount; + fmt = r.fmt; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + if( ptex != NULL && ptex->ref > 0 ) { + if( --ptex->ref <= 0 ) + delete ptex; + } + + ptex = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + TEXTURE* ptex; // can be 16bit + u32 fmt; + + int widthmult; + int channels; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + u32 ptexClamp[2]; // textures for x and y dir region clamping + + public: + void FlushTexData(); + + // notify VB that nVerts need to be written to pbuf + inline void NotifyWrite(int nVerts) { + assert( pBufferData != NULL && nCount <= nNumVertices && nVerts > 0 ); + + if( nCount + nVerts > nNumVertices ) { + // recreate except with a bigger count + VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nNumVertices*2, 256); + memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); + nNumVertices *= 2; + assert( nCount + nVerts <= nNumVertices ); + _aligned_free(pBufferData); + pBufferData = ptemp; + } + } + + void Init(int nVerts) { + if( pBufferData == NULL && nVerts > 0 ) { + pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nVerts, 256); + nNumVertices = nVerts; + } + + nCount = 0; + } + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pBufferData; // current allocated data + + int nNumVertices; // size of pBufferData in terms of VertexGPU objects + int nCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + void AddMessage(const char* pstr, u32 ms = 5000); + void DrawText(const char* pstr, int left, int top, u32 color); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + bool IsGLExt( const char* szTargetExtension ); ///< returns true if the the opengl extension is supported + bool Create(int width, int height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + void GSStateReset(); + void HandleGLError(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + void ResetRenderTarget(int index); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + RenderFormatType GetRenderFormat(); + GLenum GetRenderTargetFormat(); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); + bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); + bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); + bool SaveTGA(const char* filename, int width, int height, void* pdata); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force); + + void ResetAlphaVariables(); + + void StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +// GL prototypes +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +extern PFNGLDRAWBUFFERSPROC glDrawBuffers; + +#endif diff --git a/plugins/gs/zerogs/opengl/zerogsmath.h b/plugins/gs/zerogs/opengl/zerogsmath.h new file mode 100644 index 0000000000..1504769808 --- /dev/null +++ b/plugins/gs/zerogs/opengl/zerogsmath.h @@ -0,0 +1,902 @@ +#ifndef ZEROGS_MATH_H +#define ZEROGS_MATH_H + +#ifndef _WIN32 +#include +#endif + +#include + +#ifndef PI +#define PI ((dReal)3.141592654) +#endif + +#define rswap(x, y) *(int*)&(x) ^= *(int*)&(y) ^= *(int*)&(x) ^= *(int*)&(y); + +template inline T RAD_2_DEG(T radians) { return (radians * (T)57.29577951); } + +class Transform; +class TransformMatrix; + +typedef float dReal; +typedef dReal dMatrix3[3*4]; + +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2); + +// multiplies 3x3 matrices +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult3(double* pfres, const double* pf1, const double* pf2); + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride); +inline dReal* inv4(const dReal* pf, dReal* pfres); + +// class used for 3 and 4 dim vectors and quaternions +// It is better to use this for a 3 dim vector because it is 16byte aligned and SIMD instructions can be used +class Vector +{ +public: + dReal x, y, z, w; + + Vector() : x(0), y(0), z(0), w(0) {} + Vector(dReal x, dReal y, dReal z) : x(x), y(y), z(z), w(0) {} + Vector(dReal x, dReal y, dReal z, dReal w) : x(x), y(y), z(z), w(w) {} + Vector(const Vector &vec) : x(vec.x), y(vec.y), z(vec.z), w(vec.w) {} + Vector(const dReal* pf) { assert(pf != NULL); x = pf[0]; y = pf[1]; z = pf[2]; w = 0; } + + dReal operator[](int i) const { return (&x)[i]; } + dReal& operator[](int i) { return (&x)[i]; } + + // casting operators + operator dReal* () { return &x; } + operator const dReal* () const { return (const dReal*)&x; } + + // SCALAR FUNCTIONS + inline dReal dot(const Vector &v) const { return x*v.x + y*v.y + z*v.z + w*v.w; } + inline void normalize() { normalize4(&x, &x); } + + inline void Set3(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; } + inline void Set4(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; w = pvals[3]; } + + // 3 dim cross product, w is not touched + /// this = this x v + inline void Cross(const Vector &v) { cross3(&x, &x, v); } + + /// this = u x v + inline void Cross(const Vector &u, const Vector &v) { cross3(&x, u, v); } + + inline Vector operator-() const { Vector v; v.x = -x; v.y = -y; v.z = -z; v.w = -w; return v; } + inline Vector operator+(const Vector &r) const { Vector v; v.x = x+r.x; v.y = y+r.y; v.z = z+r.z; v.w = w+r.w; return v; } + inline Vector operator-(const Vector &r) const { Vector v; v.x = x-r.x; v.y = y-r.y; v.z = z-r.z; v.w = w-r.w; return v; } + inline Vector operator*(const Vector &r) const { Vector v; v.x = r.x*x; v.y = r.y*y; v.z = r.z*z; v.w = r.w*w; return v; } + inline Vector operator*(dReal k) const { Vector v; v.x = k*x; v.y = k*y; v.z = k*z; v.w = k*w; return v; } + + inline Vector& operator += (const Vector& r) { x += r.x; y += r.y; z += r.z; w += r.w; return *this; } + inline Vector& operator -= (const Vector& r) { x -= r.x; y -= r.y; z -= r.z; w -= r.w; return *this; } + inline Vector& operator *= (const Vector& r) { x *= r.x; y *= r.y; z *= r.z; w *= r.w; return *this; } + + inline Vector& operator *= (const dReal k) { x *= k; y *= k; z *= k; w *= k; return *this; } + inline Vector& operator /= (const dReal _k) { dReal k=1/_k; x *= k; y *= k; z *= k; w *= k; return *this; } + + friend Vector operator* (float f, const Vector& v); + //friend ostream& operator<<(ostream& O, const Vector& v); + //friend istream& operator>>(istream& I, Vector& v); +}; + +inline Vector operator* (float f, const Vector& left) +{ + Vector v; + v.x = f * left.x; + v.y = f * left.y; + v.z = f * left.z; + return v; +} + +struct AABB +{ + Vector pos, extents; +}; + +struct OBB +{ + Vector right, up, dir, pos, extents; +}; + +struct TRIANGLE +{ + TRIANGLE() {} + TRIANGLE(const Vector& v1, const Vector& v2, const Vector& v3) : v1(v1), v2(v2), v3(v3) {} + ~TRIANGLE() {} + + Vector v1, v2, v3; //!< the vertices of the triangle + + const Vector& operator[](int i) const { return (&v1)[i]; } + Vector& operator[](int i) { return (&v1)[i]; } + + /// assumes CCW ordering of vertices + inline Vector ComputeNormal() { + Vector normal; + cross3(normal, v2-v1, v3-v1); + return normal; + } +}; + +// Routines made for 3D graphics that deal with 3 or 4 dim algebra structures +// Functions with postfix 3 are for 3x3 operations, etc + +// all fns return pfout on success or NULL on failure +// results and arguments can share pointers + + +// multiplies 4x4 matrices +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult4(double* pfres, const double* pf1, const double* pf2); + +// pf1^T * pf2 +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2); +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2); + +inline dReal* transpose3(const dReal* pf, dReal* pfres); +inline double* transpose3(const double* pf, double* pfres); +inline dReal* transpose4(const dReal* pf, dReal* pfres); +inline double* transpose4(const double* pf, double* pfres); + +inline dReal dot2(const dReal* pf1, const dReal* pf2); +inline dReal dot3(const dReal* pf1, const dReal* pf2); +inline dReal dot4(const dReal* pf1, const dReal* pf2); + +inline dReal lengthsqr2(const dReal* pf); +inline dReal lengthsqr3(const dReal* pf); +inline dReal lengthsqr4(const dReal* pf); + +inline dReal* normalize2(dReal* pfout, const dReal* pf); +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); + +//// +// More complex ops that deal with arbitrary matrices // +//// + +// extract eigen values and vectors from a 2x2 matrix and returns true if all values are real +// returned eigen vectors are normalized +inline bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y); + +// Simple routines for linear algebra algorithms // +int CubicRoots (double c0, double c1, double c2, double *r0, double *r1, double *r2); +bool QLAlgorithm3 (dReal* m_aafEntry, dReal* afDiag, dReal* afSubDiag); + +void EigenSymmetric3(dReal* fCovariance, dReal* eval, dReal* fAxes); + +void GetCovarBasisVectors(dReal fCovariance[3][3], Vector* vRight, Vector* vUp, Vector* vDir); + +// first root returned is always >= second, roots are defined if the quadratic doesn't have real solutions +void QuadraticSolver(dReal* pfQuadratic, dReal* pfRoots); + +int insideQuadrilateral(const Vector* p0,const Vector* p1, const Vector* p2,const Vector* p3); +int insideTriangle(const Vector* p0, const Vector* p1, const Vector* p2); + +// multiplies a matrix by a scalar +template inline void mult(T* pf, T fa, int r); + +// multiplies a r1xc1 by c1xc2 matrix into pfres, if badd is true adds the result to pfres +// does not handle cases where pfres is equal to pf1 or pf2, use multtox for those cases +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf1 is transposed before mult +// rows of pf2 must equal rows of pf1 +// pfres will be c1xc2 matrix +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf2 is transposed before mult +// the columns of both matrices must be the same and equal to c1 +// r2 is the number of rows in pf2 +// pfres must be an r1xr2 matrix +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd = false); + +// multiplies rxc matrix pf1 and cxc matrix pf2 and stores the result in pf1, +// the function needs a temporary buffer the size of c doubles, if pftemp == NULL, +// the function will allocate the necessary memory, otherwise pftemp should be big +// enough to store all the entries +template inline T* multto1(T* pf1, T* pf2, int r1, int c1, T* pftemp = NULL); + +// same as multto1 except stores the result in pf2, pf1 has to be an r2xr2 matrix +// pftemp must be of size r2 if not NULL +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp = NULL); + +// add pf1 + pf2 and store in pf1 +template inline void sub(T* pf1, T* pf2, int r); +template inline T normsqr(T* pf1, int r); +template inline T lengthsqr(T* pf1, T* pf2, int length); +template inline T dot(T* pf1, T* pf2, int length); + +template inline T sum(T* pf, int length); + +// takes the inverse of the 3x3 matrix pf and stores it into pfres, returns true if matrix is invertible +template inline bool inv2(T* pf, T* pfres); + +/////////////////////// +// Function Definitions +/////////////////////// +bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y) +{ + // x^2 + bx + c + dReal a, b, c, d; + b = -(pfmat[0] + pfmat[3]); + c = pfmat[0] * pfmat[3] - pfmat[1] * pfmat[2]; + d = b * b - 4.0f * c + 1e-16f; + + if( d < 0 ) return false; + if( d < 1e-16f ) { + a = -0.5f * b; + peigs[0] = a; peigs[1] = a; + fv1x = pfmat[1]; fv1y = a - pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + fv2x = -fv1y; fv2y = fv1x; + return true; + } + + // two roots + d = sqrtf(d); + a = -0.5f * (b + d); + peigs[0] = a; + fv1x = pfmat[1]; fv1y = a-pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + + a += d; + peigs[1] = a; + fv2x = pfmat[1]; fv2y = a-pfmat[0]; + c = 1 / sqrtf(fv2x*fv2x + fv2y*fv2y); + fv2x *= c; fv2y *= c; + return true; +} + +//#ifndef TI_USING_IPP + +// Functions that are replacable by ipp library funcs +template inline T* _mult3(T* pfres, const T* pf1, const T* pf2) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL ); + + T* pfres2; + if( pfres == pf1 || pfres == pf2 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = pf1[0*4+0]*pf2[0*4+0]+pf1[0*4+1]*pf2[1*4+0]+pf1[0*4+2]*pf2[2*4+0]; + pfres2[0*4+1] = pf1[0*4+0]*pf2[0*4+1]+pf1[0*4+1]*pf2[1*4+1]+pf1[0*4+2]*pf2[2*4+1]; + pfres2[0*4+2] = pf1[0*4+0]*pf2[0*4+2]+pf1[0*4+1]*pf2[1*4+2]+pf1[0*4+2]*pf2[2*4+2]; + + pfres2[1*4+0] = pf1[1*4+0]*pf2[0*4+0]+pf1[1*4+1]*pf2[1*4+0]+pf1[1*4+2]*pf2[2*4+0]; + pfres2[1*4+1] = pf1[1*4+0]*pf2[0*4+1]+pf1[1*4+1]*pf2[1*4+1]+pf1[1*4+2]*pf2[2*4+1]; + pfres2[1*4+2] = pf1[1*4+0]*pf2[0*4+2]+pf1[1*4+1]*pf2[1*4+2]+pf1[1*4+2]*pf2[2*4+2]; + + pfres2[2*4+0] = pf1[2*4+0]*pf2[0*4+0]+pf1[2*4+1]*pf2[1*4+0]+pf1[2*4+2]*pf2[2*4+0]; + pfres2[2*4+1] = pf1[2*4+0]*pf2[0*4+1]+pf1[2*4+1]*pf2[1*4+1]+pf1[2*4+2]*pf2[2*4+1]; + pfres2[2*4+2] = pf1[2*4+0]*pf2[0*4+2]+pf1[2*4+1]*pf2[1*4+2]+pf1[2*4+2]*pf2[2*4+2]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult3(pfres, pf1, pf2); } +inline double* mult3(double* pfres, const double* pf1, const double* pf2) { return _mult3(pfres, pf1, pf2); } + +template +inline T* _mult4(T* pfres, const T* p1, const T* p2) +{ + assert( pfres != NULL && p1 != NULL && p2 != NULL ); + + T* pfres2; + if( pfres == p1 || pfres == p2 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = p1[0*4+0]*p2[0*4+0] + p1[0*4+1]*p2[1*4+0] + p1[0*4+2]*p2[2*4+0] + p1[0*4+3]*p2[3*4+0]; + pfres2[0*4+1] = p1[0*4+0]*p2[0*4+1] + p1[0*4+1]*p2[1*4+1] + p1[0*4+2]*p2[2*4+1] + p1[0*4+3]*p2[3*4+1]; + pfres2[0*4+2] = p1[0*4+0]*p2[0*4+2] + p1[0*4+1]*p2[1*4+2] + p1[0*4+2]*p2[2*4+2] + p1[0*4+3]*p2[3*4+2]; + pfres2[0*4+3] = p1[0*4+0]*p2[0*4+3] + p1[0*4+1]*p2[1*4+3] + p1[0*4+2]*p2[2*4+3] + p1[0*4+3]*p2[3*4+3]; + + pfres2[1*4+0] = p1[1*4+0]*p2[0*4+0] + p1[1*4+1]*p2[1*4+0] + p1[1*4+2]*p2[2*4+0] + p1[1*4+3]*p2[3*4+0]; + pfres2[1*4+1] = p1[1*4+0]*p2[0*4+1] + p1[1*4+1]*p2[1*4+1] + p1[1*4+2]*p2[2*4+1] + p1[1*4+3]*p2[3*4+1]; + pfres2[1*4+2] = p1[1*4+0]*p2[0*4+2] + p1[1*4+1]*p2[1*4+2] + p1[1*4+2]*p2[2*4+2] + p1[1*4+3]*p2[3*4+2]; + pfres2[1*4+3] = p1[1*4+0]*p2[0*4+3] + p1[1*4+1]*p2[1*4+3] + p1[1*4+2]*p2[2*4+3] + p1[1*4+3]*p2[3*4+3]; + + pfres2[2*4+0] = p1[2*4+0]*p2[0*4+0] + p1[2*4+1]*p2[1*4+0] + p1[2*4+2]*p2[2*4+0] + p1[2*4+3]*p2[3*4+0]; + pfres2[2*4+1] = p1[2*4+0]*p2[0*4+1] + p1[2*4+1]*p2[1*4+1] + p1[2*4+2]*p2[2*4+1] + p1[2*4+3]*p2[3*4+1]; + pfres2[2*4+2] = p1[2*4+0]*p2[0*4+2] + p1[2*4+1]*p2[1*4+2] + p1[2*4+2]*p2[2*4+2] + p1[2*4+3]*p2[3*4+2]; + pfres2[2*4+3] = p1[2*4+0]*p2[0*4+3] + p1[2*4+1]*p2[1*4+3] + p1[2*4+2]*p2[2*4+3] + p1[2*4+3]*p2[3*4+3]; + + pfres2[3*4+0] = p1[3*4+0]*p2[0*4+0] + p1[3*4+1]*p2[1*4+0] + p1[3*4+2]*p2[2*4+0] + p1[3*4+3]*p2[3*4+0]; + pfres2[3*4+1] = p1[3*4+0]*p2[0*4+1] + p1[3*4+1]*p2[1*4+1] + p1[3*4+2]*p2[2*4+1] + p1[3*4+3]*p2[3*4+1]; + pfres2[3*4+2] = p1[3*4+0]*p2[0*4+2] + p1[3*4+1]*p2[1*4+2] + p1[3*4+2]*p2[2*4+2] + p1[3*4+3]*p2[3*4+2]; + pfres2[3*4+3] = p1[3*4+0]*p2[0*4+3] + p1[3*4+1]*p2[1*4+3] + p1[3*4+2]*p2[2*4+3] + p1[3*4+3]*p2[3*4+3]; + + if( pfres != pfres2 ) memcpy(pfres, pfres2, sizeof(T)*16); + return pfres; +} + +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult4(pfres, pf1, pf2); } +inline double* mult4(double* pfres, const double* pf1, const double* pf2) { return _mult4(pfres, pf1, pf2); } + +template +inline T* _multtrans3(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0] = pf1[0]*pf2[0]+pf1[3]*pf2[3]+pf1[6]*pf2[6]; + pfres2[1] = pf1[0]*pf2[1]+pf1[3]*pf2[4]+pf1[6]*pf2[7]; + pfres2[2] = pf1[0]*pf2[2]+pf1[3]*pf2[5]+pf1[6]*pf2[8]; + + pfres2[3] = pf1[1]*pf2[0]+pf1[4]*pf2[3]+pf1[7]*pf2[6]; + pfres2[4] = pf1[1]*pf2[1]+pf1[4]*pf2[4]+pf1[7]*pf2[7]; + pfres2[5] = pf1[1]*pf2[2]+pf1[4]*pf2[5]+pf1[7]*pf2[8]; + + pfres2[6] = pf1[2]*pf2[0]+pf1[5]*pf2[3]+pf1[8]*pf2[6]; + pfres2[7] = pf1[2]*pf2[1]+pf1[5]*pf2[4]+pf1[8]*pf2[7]; + pfres2[8] = pf1[2]*pf2[2]+pf1[5]*pf2[5]+pf1[8]*pf2[8]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +template +inline T* _multtrans4(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + pfres[4*i+j] = pf1[i] * pf2[j] + pf1[i+4] * pf2[j+4] + pf1[i+8] * pf2[j+8] + pf1[i+12] * pf2[j+12]; + } + } + + return pfres; +} + +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans4(pfres, pf1, pf2); } +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2) { return _multtrans4(pfres, pf1, pf2); } + +// stride is in T +template inline T* _inv3(const T* pf, T* pfres, int stride) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(3 * stride * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + pfres2[0*stride + 0] = pf[1*stride + 1] * pf[2*stride + 2] - pf[1*stride + 2] * pf[2*stride + 1]; + pfres2[0*stride + 1] = pf[0*stride + 2] * pf[2*stride + 1] - pf[0*stride + 1] * pf[2*stride + 2]; + pfres2[0*stride + 2] = pf[0*stride + 1] * pf[1*stride + 2] - pf[0*stride + 2] * pf[1*stride + 1]; + pfres2[1*stride + 0] = pf[1*stride + 2] * pf[2*stride + 0] - pf[1*stride + 0] * pf[2*stride + 2]; + pfres2[1*stride + 1] = pf[0*stride + 0] * pf[2*stride + 2] - pf[0*stride + 2] * pf[2*stride + 0]; + pfres2[1*stride + 2] = pf[0*stride + 2] * pf[1*stride + 0] - pf[0*stride + 0] * pf[1*stride + 2]; + pfres2[2*stride + 0] = pf[1*stride + 0] * pf[2*stride + 1] - pf[1*stride + 1] * pf[2*stride + 0]; + pfres2[2*stride + 1] = pf[0*stride + 1] * pf[2*stride + 0] - pf[0*stride + 0] * pf[2*stride + 1]; + pfres2[2*stride + 2] = pf[0*stride + 0] * pf[1*stride + 1] - pf[0*stride + 1] * pf[1*stride + 0]; + + T fdet = pf[0*stride + 2] * pfres2[2*stride + 0] + pf[1*stride + 2] * pfres2[2*stride + 1] + + pf[2*stride + 2] * pfres2[2*stride + 2]; + + if( fabs(fdet) < 1e-6 ) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0*stride+0] *= fdet; pfres[0*stride+1] *= fdet; pfres[0*stride+2] *= fdet; + pfres[1*stride+0] *= fdet; pfres[1*stride+1] *= fdet; pfres[1*stride+2] *= fdet; + pfres[2*stride+0] *= fdet; pfres[2*stride+1] *= fdet; pfres[2*stride+2] *= fdet; + return pfres; + } + + pfres[0*stride+0] = pfres2[0*stride+0] * fdet; + pfres[0*stride+1] = pfres2[0*stride+1] * fdet; + pfres[0*stride+2] = pfres2[0*stride+2] * fdet; + pfres[1*stride+0] = pfres2[1*stride+0] * fdet; + pfres[1*stride+1] = pfres2[1*stride+1] * fdet; + pfres[1*stride+2] = pfres2[1*stride+2] * fdet; + pfres[2*stride+0] = pfres2[2*stride+0] * fdet; + pfres[2*stride+1] = pfres2[2*stride+1] * fdet; + pfres[2*stride+2] = pfres2[2*stride+2] * fdet; + return pfres; +} + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride) { return _inv3(pf, pfres, stride); } + +// inverse if 92 mults and 39 adds +template inline T* _inv4(const T* pf, T* pfres) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + + // determinants of all possibel 2x2 submatrices formed by last two rows + T fd0, fd1, fd2; + T f1, f2, f3; + fd0 = pf[2*4 + 0] * pf[3*4 + 1] - pf[2*4 + 1] * pf[3*4 + 0]; + fd1 = pf[2*4 + 1] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 1]; + fd2 = pf[2*4 + 2] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 2]; + + f1 = pf[2*4 + 1] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 1]; + f2 = pf[2*4 + 0] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 0]; + f3 = pf[2*4 + 0] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 0]; + + pfres2[0*4 + 0] = pf[1*4 + 1] * fd2 - pf[1*4 + 2] * f1 + pf[1*4 + 3] * fd1; + pfres2[0*4 + 1] = -(pf[0*4 + 1] * fd2 - pf[0*4 + 2] * f1 + pf[0*4 + 3] * fd1); + + pfres2[1*4 + 0] = -(pf[1*4 + 0] * fd2 - pf[1*4 + 2] * f2 + pf[1*4 + 3] * f3); + pfres2[1*4 + 1] = pf[0*4 + 0] * fd2 - pf[0*4 + 2] * f2 + pf[0*4 + 3] * f3; + + pfres2[2*4 + 0] = pf[1*4 + 0] * f1 - pf[1*4 + 1] * f2 + pf[1*4 + 3] * fd0; + pfres2[2*4 + 1] = -(pf[0*4 + 0] * f1 - pf[0*4 + 1] * f2 + pf[0*4 + 3] * fd0); + + pfres2[3*4 + 0] = -(pf[1*4 + 0] * fd1 - pf[1*4 + 1] * f3 + pf[1*4 + 2] * fd0); + pfres2[3*4 + 1] = pf[0*4 + 0] * fd1 - pf[0*4 + 1] * f3 + pf[0*4 + 2] * fd0; + + // determinants of first 2 rows of 4x4 matrix + fd0 = pf[0*4 + 0] * pf[1*4 + 1] - pf[0*4 + 1] * pf[1*4 + 0]; + fd1 = pf[0*4 + 1] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 1]; + fd2 = pf[0*4 + 2] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 2]; + + f1 = pf[0*4 + 1] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 1]; + f2 = pf[0*4 + 0] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 0]; + f3 = pf[0*4 + 0] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 0]; + + pfres2[0*4 + 2] = pf[3*4 + 1] * fd2 - pf[3*4 + 2] * f1 + pf[3*4 + 3] * fd1; + pfres2[0*4 + 3] = -(pf[2*4 + 1] * fd2 - pf[2*4 + 2] * f1 + pf[2*4 + 3] * fd1); + + pfres2[1*4 + 2] = -(pf[3*4 + 0] * fd2 - pf[3*4 + 2] * f2 + pf[3*4 + 3] * f3); + pfres2[1*4 + 3] = pf[2*4 + 0] * fd2 - pf[2*4 + 2] * f2 + pf[2*4 + 3] * f3; + + pfres2[2*4 + 2] = pf[3*4 + 0] * f1 - pf[3*4 + 1] * f2 + pf[3*4 + 3] * fd0; + pfres2[2*4 + 3] = -(pf[2*4 + 0] * f1 - pf[2*4 + 1] * f2 + pf[2*4 + 3] * fd0); + + pfres2[3*4 + 2] = -(pf[3*4 + 0] * fd1 - pf[3*4 + 1] * f3 + pf[3*4 + 2] * fd0); + pfres2[3*4 + 3] = pf[2*4 + 0] * fd1 - pf[2*4 + 1] * f3 + pf[2*4 + 2] * fd0; + + T fdet = pf[0*4 + 3] * pfres2[3*4 + 0] + pf[1*4 + 3] * pfres2[3*4 + 1] + + pf[2*4 + 3] * pfres2[3*4 + 2] + pf[3*4 + 3] * pfres2[3*4 + 3]; + + if( fabs(fdet) < 1e-6) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres2 == pfres ) { + mult(pfres, fdet, 16); + return pfres; + } + + int i = 0; + while(i < 16) { + pfres[i] = pfres2[i] * fdet; + ++i; + } + + return pfres; +} + +inline dReal* inv4(const dReal* pf, dReal* pfres) { return _inv4(pf, pfres); } + +template inline T* _transpose3(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[3]); + rswap(pfres[2], pfres[6]); + rswap(pfres[5], pfres[7]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[3]; pfres[2] = pf[6]; + pfres[3] = pf[1]; pfres[4] = pf[4]; pfres[5] = pf[7]; + pfres[6] = pf[2]; pfres[7] = pf[5]; pfres[8] = pf[8]; + + return pfres; +} + +inline dReal* transpose3(const dReal* pf, dReal* pfres) { return _transpose3(pf, pfres); } +inline double* transpose3(const double* pf, double* pfres) { return _transpose3(pf, pfres); } + +template inline T* _transpose4(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[4]); + rswap(pfres[2], pfres[8]); + rswap(pfres[3], pfres[12]); + rswap(pfres[6], pfres[9]); + rswap(pfres[7], pfres[13]); + rswap(pfres[11], pfres[15]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[4]; pfres[2] = pf[8]; pfres[3] = pf[12]; + pfres[4] = pf[1]; pfres[5] = pf[5]; pfres[6] = pf[9]; pfres[7] = pf[13]; + pfres[8] = pf[2]; pfres[9] = pf[6]; pfres[10] = pf[10]; pfres[11] = pf[14]; + pfres[12] = pf[3]; pfres[13] = pf[7]; pfres[14] = pf[11]; pfres[15] = pf[15]; + return pfres; +} + +inline dReal* transpose4(const dReal* pf, dReal* pfres) { return _transpose4(pf, pfres); } +inline double* transpose4(const double* pf, double* pfres) { return _transpose4(pf, pfres); } + +inline dReal dot2(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1]; +} + +inline dReal dot3(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2]; +} + +inline dReal dot4(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2] + pf1[3] * pf2[3]; +} + +inline dReal lengthsqr2(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1]; +} + +inline dReal lengthsqr3(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2]; +} + +inline dReal lengthsqr4(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2] + pf[3] * pf[3]; +} + +inline dReal* normalize2(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1]; + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + + return pfout; +} + +inline dReal* normalize3(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + + return pfout; +} + +inline dReal* normalize4(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2] + pf[3]*pf[3]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + pfout[3] = pf[3] * f; + + return pfout; +} + +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2) +{ + assert( pfout != NULL && pf1 != NULL && pf2 != NULL ); + + dReal temp[3]; + temp[0] = pf1[1] * pf2[2] - pf1[2] * pf2[1]; + temp[1] = pf1[2] * pf2[0] - pf1[0] * pf2[2]; + temp[2] = pf1[0] * pf2[1] - pf1[1] * pf2[0]; + + pfout[0] = temp[0]; pfout[1] = temp[1]; pfout[2] = temp[2]; + return pfout; +} + +template inline void mult(T* pf, T fa, int r) +{ + assert( pf != NULL ); + + while(r > 0) { + --r; + pf[r] *= fa; + } +} + +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * c2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < c2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += c2; + } + + return pfres; +} + +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int i, j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * c1 * c2); + + i = 0; + while(i < c1) { + + j = 0; + while(j < c2) { + + k = 0; + while(k < r1) { + pfres[j] += pf1[k*c1] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pfres += c2; + ++pf1; + + ++i; + } + + return pfres; +} + +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * r2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < r2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[j*c1 + k]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += r2; + } + + return pfres; +} + +template inline T* multto1(T* pf1, T* pf2, int r, int c, T* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new T[c]; + bdel = true; + } + + while(r > 0) { + --r; + + j = 0; + while(j < c) { + + pftemp[j] = 0.0; + + k = 0; + while(k < c) { + pftemp[j] += pf1[k] * pf2[k*c + j]; + ++k; + } + ++j; + } + + memcpy(pf1, pftemp, c * sizeof(T)); + pf1 += c; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int i, j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new S[r2]; + bdel = true; + } + + // do columns first + j = 0; + while(j < c2) { + i = 0; + while(i < r2) { + + pftemp[i] = 0.0; + + k = 0; + while(k < r2) { + pftemp[i] += pf1[i*r2 + k] * pf2[k*c2 + j]; + ++k; + } + ++i; + } + + i = 0; + while(i < r2) { + *(pf2+i*c2+j) = pftemp[i]; + ++i; + } + + ++j; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline void add(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] += pf2[r]; + } +} + +template inline void sub(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] -= pf2[r]; + } +} + +template inline T normsqr(T* pf1, int r) +{ + assert( pf1 != NULL ); + + T d = 0.0; + while(r > 0) { + --r; + d += pf1[r] * pf1[r]; + } + + return d; +} + +template inline T lengthsqr(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += sqr(pf1[length] - pf2[length]); + } + + return d; +} + +template inline T dot(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf1[length] * pf2[length]; + } + + return d; +} + +template inline T sum(T* pf, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf[length]; + } + + return d; +} + +template inline bool inv2(T* pf, T* pfres) +{ + T fdet = pf[0] * pf[3] - pf[1] * pf[2]; + + if( fabs(fdet) < 1e-16 ) return false; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0] = fdet * pf[3]; pfres[1] = -fdet * pf[1]; + pfres[2] = -fdet * pf[2]; pfres[3] = fdet * pf[0]; + return true; + } + + dReal ftemp = pf[0]; + pfres[0] = pf[3] * fdet; + pfres[1] *= -fdet; + pfres[2] *= -fdet; + pfres[3] = ftemp * pf[0]; + + return true; +} + +#endif diff --git a/plugins/gs/zerogs/opengl/zpipe.cpp b/plugins/gs/zerogs/opengl/zpipe.cpp new file mode 100644 index 0000000000..fef5f686c3 --- /dev/null +++ b/plugins/gs/zerogs/opengl/zpipe.cpp @@ -0,0 +1,115 @@ +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include "zlib.h" + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/gs/zerogs/opengl/zpipe.h b/plugins/gs/zerogs/opengl/zpipe.h new file mode 100644 index 0000000000..cb96229553 --- /dev/null +++ b/plugins/gs/zerogs/opengl/zpipe.h @@ -0,0 +1,7 @@ +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/pad/PADwin/ReadMe.txt b/plugins/pad/PADwin/ReadMe.txt new file mode 100644 index 0000000000..43a9a5f982 --- /dev/null +++ b/plugins/pad/PADwin/ReadMe.txt @@ -0,0 +1,89 @@ +PADwin v1.0 +-------------------- + + This is an extension to use with play station2 emulators + such as PCSX2. + The plugin is free open source code. + +Usage: +----- + Place the file "PADwin.dll" (Windows) or "libPADwin.so" (Linux) + at the Plugins directory of the Emulator to use it. + Make sure you calibrated the joystick/gamepad with Control Panel's utility!!! + +Thanks +------ + My cousin Bogdan for giving me the gamepad;) (Florin) + Dr. Hell for his WinMM PAD Driver & joyinfo tool:) + Bositman for helping me fixing bugz;) + Raziel for PS2 controller info + +Changes: +------- + v1.0 + * Commented out the joystic code that was causing troubles in win32 + * Added Devc++ (4.9.9.2) project files to compile with mingw32 easy :) + * Moved some of the PADopen code to PADinit + + v0.9 + * Added vsnet2005 beta1 files. 64bit dll should now work (not tested!) + * Fixed bug in PADclose + + v0.8 + * Configure back to INI + * Some fixes + + v0.7 + * Rewritten by asadr. Analog mode with mouse + + v0.6 + * Analog mode. + * better compatibility + + v0.5: + * Merged with PADxwin + * Bugfixed PAD2 + * Rewrote PADpoll/PADstartPoll, now it has more pad commands + + v0.43: + * Added POV support + * I considered 0 for axis value as disabled. That was wrong. While it worked + with analog sticks, it didn't with "more precise" digital ones:P + * dwButtonNumber is not usable; with my gamepad it gives me the number of + the last button pressed. this is correct according to docs. I don't have + a driver for it so it is handeled by windows default driver. But some dudes, + at Gravis for example, did not understood the meaning of dwButtonNumber; + their driver returns the number of the buttons that are pressed in the same + time, hence the J0_1 assign bug. + * corrected back/fwrd for Z. + + v0.42: + * added joystick/gamepad support + 2 joys; 32 buttons/joy; 6 axis; no POV + + v0.41: + * add a pic in configuration window + + v0.4: + * fixed key repeating + * updated to v0.4.0 specs + + v0.31: + * fixed silly bug after exit + + v0.3: + * Changed old PADreadStatus for PADstartPoll/PADpoll + + v0.2: + * Config and About dialogs added + * Now pads works + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + linuzappz + florin diff --git a/plugins/pad/PADwin/Src/Conf.c b/plugins/pad/PADwin/Src/Conf.c new file mode 100644 index 0000000000..6d54fecbfb --- /dev/null +++ b/plugins/pad/PADwin/Src/Conf.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include "PAD.h" + + + +#include +#include +#include +#ifndef __WIN32__ +#include +#endif + +void SaveConfig() { + FILE *f; + char cfg[255]; + int i, j; +#ifdef __WIN32__ + CreateDirectory("inis",NULL); + sprintf(cfg,"inis/padwinkeyb.ini"); +#else + sprintf(cfg,"%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf (cfg,"%s/.PS2E/PADwin.cfg",getenv("HOME")); +#endif + f = fopen(cfg,"w"); + if (f == NULL) { + printf("PADwin: Error writing to '%s'\n", cfg); + return; + } + for (j=0; j<2; j++) { + for (i=0; i<16; i++) { + fprintf(f, "[%d][%d] = 0x%lx\n", j, i, conf.keys[j][i]); + } + } + fprintf(f, "logging = %d\n", conf.log); + fclose(f); +} + +void LoadConfig() { + FILE *f; + char str[256]; + char cfg[255]; + int i, j; + + memset(&conf, 0, sizeof(conf)); +#ifdef __WIN32__ + conf.keys[0][0] = '1'; // L2 + conf.keys[0][1] = '3'; // R2 + conf.keys[0][2] = 'Q'; // L1 + conf.keys[0][3] = 'E'; // R1 + conf.keys[0][4] = 'W'; // TRIANGLE + conf.keys[0][5] = 'D'; // CIRCLE + conf.keys[0][6] = 'X'; // CROSS + conf.keys[0][7] = 'A'; // SQUARE + conf.keys[0][8] = VK_DECIMAL; // SELECT + conf.keys[0][11] = VK_NUMPAD0; // START + conf.keys[0][12] = VK_NUMPAD8; // UP + conf.keys[0][13] = VK_NUMPAD6; // RIGHT + conf.keys[0][14] = VK_NUMPAD2; // DOWN + conf.keys[0][15] = VK_NUMPAD4; // LEFT +#else + conf.keys[0][0] = XK_1; // L2 + conf.keys[0][1] = XK_3; // R2 + conf.keys[0][2] = XK_q; // L1 + conf.keys[0][3] = XK_e; // R1 + conf.keys[0][4] = XK_w; // TRIANGLE + conf.keys[0][5] = XK_d; // CIRCLE + conf.keys[0][6] = XK_x; // CROSS + conf.keys[0][7] = XK_a; // SQUARE + conf.keys[0][8] = XK_KP_Delete; // SELECT + conf.keys[0][11] = XK_KP_Insert;// START + conf.keys[0][12] = XK_KP_Up; // UP + conf.keys[0][13] = XK_KP_Right; // RIGHT + conf.keys[0][14] = XK_KP_Down; // DOWN + conf.keys[0][15] = XK_KP_Left; // LEFT +#endif + conf.log = 0; +#ifdef __WIN32__ + sprintf(cfg,"inis/padwinkeyb.ini"); +#else + sprintf (cfg,"%s/.PS2E/PADwin.cfg", getenv("HOME")); +#endif + f = fopen(cfg,"r"); + if (f == NULL) return; + + for (j=0; j<2; j++) { + for (i=0; i<16; i++) { + sprintf(str, "[%d][%d] = 0x%%x\n", j, i); + fscanf(f, str, &conf.keys[j][i]); + } + } + fscanf(f, "logging = %d\n", &conf.log); + fclose(f); +} + + diff --git a/plugins/pad/PADwin/Src/Linux.c b/plugins/pad/PADwin/Src/Linux.c new file mode 100644 index 0000000000..b49784f6f2 --- /dev/null +++ b/plugins/pad/PADwin/Src/Linux.c @@ -0,0 +1,210 @@ +#include +#include + +#include "PAD.h" +#include "interface.h" +#include "support.h" + +Display *GSdsp; +XEvent E; + + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void _PADupdate() { + int key; + + XLockDisplay(GSdsp); + while (XPending(GSdsp) > 0) { + XNextEvent(GSdsp, &E); + switch (E.type) { + case KeyPress: + key = XLookupKeysym((XKeyEvent *)&E, 0); + _KeyPress(key); + break; + + case KeyRelease: + key = XLookupKeysym((XKeyEvent *)&E, 0); + _KeyRelease(key); + break; + + case FocusIn: + XAutoRepeatOff(GSdsp); + break; + + case FocusOut: + XAutoRepeatOn(GSdsp); + break; + } + } + XUnlockDisplay(GSdsp); +} + +s32 _PADopen(void *pDsp) { + GSdsp = *(Display**)pDsp; + XAutoRepeatOff(GSdsp); + + return 0; +} + +void _PADclose() { + XAutoRepeatOn(GSdsp); +} + + +GtkWidget *Conf; +GtkWidget *Btn; +//GtkWidget *Analog; +char name[32]; + +int padn; + +void UpdateConf() { + int i; + + for (i=0; i<24; i++) { + char *tmp; + + sprintf(name, "Key%d", i); + Btn = lookup_widget(Conf, name); + tmp = XKeysymToString(conf.keys[padn][i]); + if (tmp != NULL) + gtk_label_set_text(GTK_LABEL(GTK_BIN(Btn)->child), tmp); + else + gtk_label_set_text(GTK_LABEL(GTK_BIN(Btn)->child), "Unknown"); + gtk_object_set_user_data(GTK_OBJECT(Btn), &conf.keys[padn][i]); + } +} + +void OnConf_Key(GtkButton *Btn) { + GdkEvent *ev; + unsigned long *key = (unsigned long*)gtk_object_get_user_data(GTK_OBJECT(Btn)); + char *tmp; + + for (;;) { + ev = gdk_event_get(); + if (ev != NULL) { + if (ev->type == GDK_KEY_PRESS) { + *key = ev->key.keyval; + tmp = XKeysymToString(*key); + if (tmp != NULL) + gtk_label_set_text(GTK_LABEL(GTK_BIN(Btn)->child), tmp); + else + gtk_label_set_text(GTK_LABEL(GTK_BIN(Btn)->child), "Unknown"); + return; + } + } + } +} + +void OnConf_Pad1() { + padn = 0; + UpdateConf(); +} + +void OnConf_Pad2() { + padn = 1; + UpdateConf(); +} + +void OnConf_Ok() { +// conf.analog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Analog)); + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel() { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CALLBACK PADconfigure() { + LoadConfig(); + + Conf = create_Config(); + +// Analog = lookup_widget(Conf, "GtkCheckButton_Analog"); +// gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Analog), conf.analog); + + padn = 0; + UpdateConf(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok() { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK PADabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK PADtest() { + return 0; +} +/* +PADdriver PADx11 = { + "x11", + _PADopen, + _PADclose, + _PADupdate, +}; +*/ diff --git a/plugins/pad/PADwin/Src/Makefile b/plugins/pad/PADwin/Src/Makefile new file mode 100644 index 0000000000..89423e8fe8 --- /dev/null +++ b/plugins/pad/PADwin/Src/Makefile @@ -0,0 +1,25 @@ + +PLUGIN = libPADwin.so +CFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ +OBJS = PAD.o Conf.o Linux.o +OBJS += interface.o support.o +LIBS = $(shell pkg-config --libs gtk+-2.0) +CFLAGS += $(shell pkg-config --cflags gtk+-2.0) + +DEPS:= $(OBJS:.o=.d) + +all: plugin +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +.PHONY: clear plugin + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} + +-include ${DEPS} + diff --git a/plugins/pad/PADwin/Src/Makefile.mingw b/plugins/pad/PADwin/Src/Makefile.mingw new file mode 100644 index 0000000000..c125aa2ad6 --- /dev/null +++ b/plugins/pad/PADwin/Src/Makefile.mingw @@ -0,0 +1,29 @@ + +RC = windres + +PLUGIN = PADwin.dll +CFLAGS = -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32__ +LIBS = -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = PADwnKeyb.o +OBJS = PAD.o Conf.o Win32.o ${RESOBJ} +STRIP = strip + +DEPS:= $(OBJS:.o=.d) + +all: plugin + +plugin: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clear plugin + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} + +${RESOBJ}: PADwnKeyb.rc + ${RC} -D__MINGW32__ -J rc -Imingw -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/pad/PADwin/Src/PAD.c b/plugins/pad/PADwin/Src/PAD.c new file mode 100644 index 0000000000..1c9da16c01 --- /dev/null +++ b/plugins/pad/PADwin/Src/PAD.c @@ -0,0 +1,528 @@ +/* PADwin + * Copyright (C) 2002-2004 PADwin 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 +#include + +#include "PAD.h" + +char *libraryName = "PADwinKeyb Driver"; + +const unsigned char version = PS2E_PAD_VERSION; +const unsigned char revision = 1; +const unsigned char build = 0; // increase that with each version + + +u32 pads=0; +u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; +u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; +u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; +u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, + {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; +u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; +u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; +u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 +u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 stdmodel[2][8] = { {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}, + {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}}; + +u8 *buf; +int padID[2]; +int padMode[2]; +int curPad; +int curByte; +int curCmd; +int cmdLen; +int ds2mode = 0; // DS Mode at start +FILE *padLog = NULL; + +int POV(u32 direction, u32 angle){ + if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward + if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right + if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward + if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left + if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward + return 0; +} + +void _KeyPressNE(u32 key) { + int i; + + if (pads & 0x1) { + for (i=0; i<16; i++) { + if (key == conf.keys[0][i]) { + status[0]&=~(1<> 8; + stdpar[3] = status[curPad-1] & 0xff; + cmdLen = 4; + buf = stdpar; + return 0x41; + } + + if (curByte >= cmdLen) return 0; + return buf[curByte++]; +}*/ + +u8 _PADpoll(u8 value) { + u8 button_check = 0, button_check2 = 0; + + if (curByte == 0) { + curByte++; +#ifdef PAD_LOG + PAD_LOG("PADpoll: cmd: %x\n", value); +#endif + + curCmd = value; + switch (value) { + case 0x40: // DUALSHOCK2 ENABLER + cmdLen = 8; + buf = cmd40[curPad]; + return 0xf3; + + case 0x41: // QUERY_DS2_ANALOG_MODE + cmdLen = 8; + buf = cmd41[curPad]; + return 0xf3; + + case 0x42: // READ_DATA + if(lanalog.button) status[curPad] &= ~(1<<9); + else status[curPad] |= (1<<9); + if(ranalog.button) status[curPad] &= ~(1<<10); + else status[curPad] |= (1<<10); + + lanalog.button = 0; // reset them :p (l3) + ranalog.button = 0; // reset them :P (r3) + + stdpar[curPad][2] = status[curPad] >> 8; + stdpar[curPad][3] = status[curPad] & 0xff; + stdpar[curPad][4] = ranalog.x; + stdpar[curPad][5] = ranalog.y; + stdpar[curPad][6] = lanalog.x; + stdpar[curPad][7] = lanalog.y; + if (padMode[curPad] == 1) cmdLen = 20; + else cmdLen = 4; + button_check2 = stdpar[curPad][2] >> 4; + switch(stdpar[curPad][3]) + { + case 0xBF: // X + stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); + break; + case 0xDF: // Circle + stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); + break; + case 0xEF: // Triangle + stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); + break; + case 0x7F: // Square + stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); + break; + case 0xFB: // L1 + stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); + break; + case 0xF7: // R1 + stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); + break; + case 0xFE: // L2 + stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); + break; + case 0xFD: // R2 + stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); + break; + default: + stdpar[curPad][14] = 0x00; // Not pressed + stdpar[curPad][13] = 0x00; // Not pressed + stdpar[curPad][12] = 0x00; // Not pressed + stdpar[curPad][15] = 0x00; // Not pressed + stdpar[curPad][16] = 0x00; // Not pressed + stdpar[curPad][17] = 0x00; // Not pressed + stdpar[curPad][18] = 0x00; // Not pressed + stdpar[curPad][19] = 0x00; // Not pressed + break; + } + switch(button_check2) + { + case 0xE: // UP + stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); + break; + case 0xB: // DOWN + stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); + break; + case 0x7: // LEFT + stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); + break; + case 0xD: // RIGHT + stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); + break; + default: + stdpar[curPad][8] = 0x00; // Not pressed + stdpar[curPad][9] = 0x00; // Not pressed + stdpar[curPad][10] = 0x00; // Not pressed + stdpar[curPad][11] = 0x00; // Not pressed + break; + } + buf = stdpar[curPad]; + return padID[curPad]; + + case 0x43: // CONFIG_MODE + cmdLen = 8; + buf = stdcfg[curPad]; + if (stdcfg[curPad][3] == 0xff) return 0xf3; + else return padID[curPad]; + + case 0x44: // SET_MODE_AND_LOCK + cmdLen = 8; + buf = stdmode[curPad]; + return 0xf3; + + case 0x45: // QUERY_MODEL_AND_MODE + cmdLen = 8; + buf = stdmodel[curPad]; + buf[4] = padMode[curPad]; + return 0xf3; + + case 0x46: // ?? + cmdLen = 8; + buf = unk46[curPad]; + return 0xf3; + + case 0x47: // ?? + cmdLen = 8; + buf = unk47[curPad]; + return 0xf3; + + case 0x4c: // QUERY_MODE ?? + cmdLen = 8; + buf = unk4c[curPad]; + return 0xf3; + + case 0x4d: + cmdLen = 8; + buf = unk4d[curPad]; + return 0xf3; + + case 0x4f: // SET_DS2_NATIVE_MODE + cmdLen = 8; + padID[curPad] = 0x79; // setting ds2 mode + ds2mode = 1; // Set DS2 Mode + buf = cmd4f[curPad]; + return 0xf3; + + default: +#ifdef PAD_LOG + PAD_LOG("*PADpoll*: unknown cmd %x\n", value); +#endif + break; + } + } + + switch (curCmd) { + case 0x43: + if(curByte == 2) + { + switch(value){ + case 0: + buf[2] = 0; + buf[3] = 0; + break; + case 1: + buf[2] = 0xff; + buf[3] = 0xff; + break; + } + } + break; + + case 0x44: + if (curByte == 2) { + PADsetMode(curPad, value); + } + break; + + case 0x46: + if(curByte == 2) { + switch(value) { + case 0: // default + buf[5] = 0x2; + buf[6] = 0x0; + buf[7] = 0xA; + break; + case 1: // Param std conf change + buf[5] = 0x1; + buf[6] = 0x1; + buf[7] = 0x14; + break; + } + } + break; + + case 0x4c: + if (curByte == 2) { + switch (value) { + case 0: // mode 0 - digital mode + buf[5] = 0x4; + break; + + case 1: // mode 1 - analog mode + buf[5] = 0x7; + break; + } + } + break; + } + + if (curByte >= cmdLen) return 0; + return buf[curByte++]; +} + +u8 CALLBACK PADpoll(u8 value) { + u8 ret; +/* if (conf.analog) { + ret = PADpollAnalog(value); + } else { + ret = PADpollDigital(value); + }*/ + ret = _PADpoll(value); +#ifdef PAD_LOG + PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); +#endif + return ret; +} +/* +u32 CALLBACK PADgetType() { + if (conf.analog) return PAD_TYPE_ANALOG; + else return PAD_TYPE_DIGITAL; +}*/ + +keyEvent ev; + +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent() { + +#ifdef __LINUX__ + _PADupdate(); +#endif + + if (event.event != 0) { + memcpy(&ev, &event, sizeof(ev)); + event.event = 0; + return &ev; + } + + return NULL; +} + + diff --git a/plugins/pad/PADwin/Src/PAD.h b/plugins/pad/PADwin/Src/PAD.h new file mode 100644 index 0000000000..f5b854e8a1 --- /dev/null +++ b/plugins/pad/PADwin/Src/PAD.h @@ -0,0 +1,107 @@ +/* PADwin + * Copyright (C) 2002-2004 PADwin 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 + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#include + +#ifdef __WIN32__ +#include +#include + +#else + +#include +#include +#include + +#endif + +#define PADdefs +#include "PS2Edefs.h" +#include "resource.h" + +char *libraryName; + +typedef struct { + unsigned long keys[2][16]; + int log; +} PADconf; + +typedef struct { + u8 x,y; + u8 button; +} Analog; + +Analog lanalog, ranalog; +PADconf conf; + +extern FILE *padLog; +#define PAD_LOG __Log + + +/* from pad.h */ + +/* + * Button bits + */ +#define PAD_LEFT 0x8000 +#define PAD_DOWN 0x4000 +#define PAD_RIGHT 0x2000 +#define PAD_UP 0x1000 +#define PAD_START 0x0800 +#define PAD_R3 0x0400 +#define PAD_L3 0x0200 +#define PAD_SELECT 0x0100 +#define PAD_SQUARE 0x0080 +#define PAD_CROSS 0x0040 +#define PAD_CIRCLE 0x0020 +#define PAD_TRIANGLE 0x0010 +#define PAD_R1 0x0008 +#define PAD_L1 0x0004 +#define PAD_R2 0x0002 +#define PAD_L2 0x0001 + +/* end of pad.h */ + +keyEvent event; + +u16 status[2]; +int pressure; +extern u32 pads; + +int POV(u32 direction, u32 angle); +s32 _PADopen(void *pDsp); +void _PADclose(); +void _KeyPressNE(u32 key); +void _KeyPress(u32 key); +void _KeyReleaseNE(u32 key); +void _KeyRelease(u32 key); +void PADsetMode(int pad, int mode); +void _PADupdate(); + +void __Log(char *fmt, ...); +void LoadConfig(); +void SaveConfig(); + +void SysMessage(char *fmt, ...); + +#endif + + diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.def b/plugins/pad/PADwin/Src/PADwinKeyb.def new file mode 100644 index 0000000000..7230a0ff74 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb.def @@ -0,0 +1,22 @@ +; PADdinput.def : Declares the module parameters for the DLL. + +LIBRARY "PADwinKeyb" +DESCRIPTION 'PAD Plugin Using Windows Keyboard' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + PADinit @5 + PADshutdown @6 + PADopen @7 + PADclose @8 + PADkeyEvent @9 + PADstartPoll @10 + PADpoll @11 + PADquery @12 + + PADconfigure @13 + PADtest @14 + PADabout @15 \ No newline at end of file diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.dsp b/plugins/pad/PADwin/Src/PADwinKeyb.dsp new file mode 100644 index 0000000000..7d13f57ed1 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="PADwinKeyb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=PADwinKeyb - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PADwinKeyb.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PADwinKeyb.mak" CFG="PADwinKeyb - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PADwinKeyb - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PADDINPUT_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PADDINPUT_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=5 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 +# Begin Target + +# Name "PADwinKeyb - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Conf.c +# End Source File +# Begin Source File + +SOURCE=.\PAD.c +# End Source File +# Begin Source File + +SOURCE=.\PADwinKeyb.def +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\PAD.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=.\PS2Etypes.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\controller.bmp +# End Source File +# Begin Source File + +SOURCE=.\PADwnKeyb.rc +# End Source File +# Begin Source File + +SOURCE=.\ps2pad.bmp +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.dsw b/plugins/pad/PADwin/Src/PADwinKeyb.dsw new file mode 100644 index 0000000000..6388bde222 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "PADwinKeyb"=".\PADwinKeyb.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.sln b/plugins/pad/PADwin/Src/PADwinKeyb.sln new file mode 100644 index 0000000000..5fff7a5716 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PADwinKeyb", "PADwinKeyb.vcproj", "{79D9E8A9-C764-4082-826C-B715341FB1E9}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release.ActiveCfg = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.suo b/plugins/pad/PADwin/Src/PADwinKeyb.suo new file mode 100644 index 0000000000000000000000000000000000000000..fa80235f0d1243403ff3d6ef8ae7a13cf0549798 GIT binary patch literal 9216 zcmeHMNo*WN6#X8@#Li-8516fqorMrPj+d+u$jsPD6gvsFvm7kM*wc0h;t4TQ27iR?)|RjXrNzAT$X6kEm7og znZT@iPs^kx<@41gKGR;lY%FNMTt&VwX*@{#A<>khvK!JzQR5t8Q_kAto(`V_MUgc-vHOnN<32}fJ;MTbq;64)r=>L>OeN%@VyZe4g zMtM2P4}u;7HG&=nJp$?i`9Y6^G|&^E6`&?iGiW7= z1E?L;;ncByBg&gVn?YMZTS41EPlKKTZ3jIIdJeP$9+t^iODD0R6|fd5gF07fEl&orlDM}ArPNPSRq5}*JEbfQgyR}AuB{t za}M|QY6Bxj^l|k#KNtxa=9tzUj#y@#3=8_q;fSGYhxB2s$Bd7w&+D?D<^;^~m>Jch zcH8q0MWSKzWFpNzYu8|3FB_{57?Iep8H$Is{z!C;RkL^MQ9T|qSe{y{n%d_o{yK*? z0?5dGvsR)(%BK!}Ag}U?m&7Wj zT=_&@9ep?^G3bN3q81CMHIPrtq->_boar}QE6zKQx$?RGQS&i1QzqmWlPj^v804CeJ_H)U^C_S!ZO6hKjp7R` zR2mxse;i*AIb$rAaqcRSxPH9^vi-o0D#p-@5PU(C9`wsl;~TGP@h!+DG`*Ag@;wS+7Q~u9Yz^nanPw{ybZb*gYPhd>Mq~aj!+COD8*{v48 z6RQgOe;=%598wtvA98eI!mbN>;X23vZ0X+QFNXXR)s2jG%&P^v zCKix084WiS}&Mj_ssj9*q@uGQkUD-bUxRJTE4TUMXV`|mB`6OI*8i3n{5Z4dWXa^|uAT(~nlON?4=|t@Y zylp`M+=IGKlsW)oe$;NnwF%_Mb09Zj$h7(Wu(qSMC|_!I{Eu;@SNV^E_ps9#an1nJxns2bY!o9NQ}{>8_UQ9T=bpsJ2~+zb zuks%Q|Mw35?E}Ug#hS#ms*sQ8mu%NQHVOP$g->5_8|{*_awco}-UE=CK(|^E2998X zw>Ri#P@Y_fIlUo<9eA{&cV}>&RvyuTd%Hs|uyiim?eKsNxPqV-yxR;PXhVrhI_=daKPTVWx`hbtKnB*{4w`{rlAlrhRv{df)vw5;t zC-T-J7OiaGwy9luWk=f&iSt^&ci@MM*XQ-Uy7Jr?zPFa%P_f3ZOIBX}sHth^r@ve~ zyLx!MQ`u1c*Nw)lx~6?^Bwx94<koi;_n*pzUTPl0mM_3%3X{O za{FUPU4^2)be~pC0)Ml|pWZj6CobK7sS?gV)ws*i|9UjK)fxZun#gCE^Zzci+j~k^ zH`$Al{r_nu_n-6In6=x=+^zDhof>5q?9;Z=xTJYFjXYP)MxRVvv)`xpS-Iyx;;b#y zWv%?q!&RhO`6E^O(<#lB8>&<-e<3GwRmk)jD_Upq}i0e~I zc1$jEq*5`tTA1%qOy>UQaQ}Y{VC^FY^9+traavRPbwvDkvBxX^GKO)_pYpd_UTwMZ z%WJ(f_l%ZLV5s!5UuIA>J#l$QXBYnRWW?rc^2FwtIoCH&%tYT*hhvqVn|zTXHvu}r d*~;&rN;^*uhr2h*sV?|f3ZDvoc>jgcz`x?AjHdtq literal 0 HcmV?d00001 diff --git a/plugins/pad/PADwin/Src/PADwinKeyb.vcproj b/plugins/pad/PADwin/Src/PADwinKeyb.vcproj new file mode 100644 index 0000000000..9e2d34c21f --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb.vcproj @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.sln b/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.sln new file mode 100644 index 0000000000..4383d1f33c --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PADwinKeyb", "PADwinKeyb_vsnet2005beta1.vcproj", "{79D9E8A9-C764-4082-826C-B715341FB1E9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + amd64|Win32 = amd64|Win32 + amd64|Win64 (AMD64) = amd64|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {79D9E8A9-C764-4082-826C-B715341FB1E9}.amd64|Win32.ActiveCfg = amd64|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.amd64|Win32.Build.0 = amd64|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.amd64|Win64 (AMD64).ActiveCfg = amd64|Win64 (AMD64) + {79D9E8A9-C764-4082-826C-B715341FB1E9}.amd64|Win64 (AMD64).Build.0 = amd64|Win64 (AMD64) + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.ActiveCfg = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.Build.0 = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.vcproj b/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.vcproj new file mode 100644 index 0000000000..705b13b8e6 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwinKeyb_vsnet2005beta1.vcproj @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/PADwin/Src/PADwnKeyb.rc b/plugins/pad/PADwin/Src/PADwnKeyb.rc new file mode 100644 index 0000000000..706d8a3d97 --- /dev/null +++ b/plugins/pad/PADwin/Src/PADwnKeyb.rc @@ -0,0 +1,150 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Modern) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 3, 1, 443, 266 +STYLE WS_CAPTION | WS_SYSMENU +CAPTION "Pad Settings" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK",IDOK,320,244,56,18,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,384,244,56,17,NOT WS_TABSTOP + EDITTEXT IDC_ERIGHT,219,31,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Start",IDC_START,219,17,86,15,NOT WS_TABSTOP, + WS_EX_TRANSPARENT + EDITTEXT IDC_ER2,129,31,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Select",IDC_SELECT,129,17,86,15,NOT WS_TABSTOP, + WS_EX_TRANSPARENT + EDITTEXT IDC_ECIRCLE,340,214,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Cross",IDC2_CROSS,340,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ETRIANGLE,340,185,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Square",IDC_SQUARE,340,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESQUARE,340,155,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Circle",IDC_CIRCLE,340,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ECROSS,340,125,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Triangle",IDC_TRI,340,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ER3,340,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "R2",IDC_R2,340,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESELECT,340,67,86,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "R1",IDC_R1,340,52,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL2,5,214,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "Down",IDC_DOWN,5,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EUP,5,185,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "Right",IDC_RIGHT,5,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL1,5,155,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "Left",IDC_LEFT,5,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ELEFT,5,125,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "Up",IDC_UP,5,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL3,5,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "L2",IDC_L2,5,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESTART,5,67,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "L1",IDC_L1,5,52,86,15,NOT WS_TABSTOP + CONTROL 112,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,94,47,242, + 183,WS_EX_TRANSPARENT + CONTROL "Enable logging(for developer use only!)",IDC_LOG,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,245,141,13 + CONTROL "Tab1",IDC_TABC,"SysTabControl32",0x0,0,0,431,240 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP MOVEABLE PURE "ps2pad.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO MOVEABLE PURE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + BOTTOMMARGIN, 265 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Modern) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/pad/PADwin/Src/PS2Edefs.h b/plugins/pad/PADwin/Src/PS2Edefs.h new file mode 100644 index 0000000000..709407dd8e --- /dev/null +++ b/plugins/pad/PADwin/Src/PS2Edefs.h @@ -0,0 +1,812 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/pad/PADwin/Src/PS2Etypes.h b/plugins/pad/PADwin/Src/PS2Etypes.h new file mode 100644 index 0000000000..194f6558f1 --- /dev/null +++ b/plugins/pad/PADwin/Src/PS2Etypes.h @@ -0,0 +1,75 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_WIN32) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/pad/PADwin/Src/Win32.c b/plugins/pad/PADwin/Src/Win32.c new file mode 100644 index 0000000000..6a4d34e1cf --- /dev/null +++ b/plugins/pad/PADwin/Src/Win32.c @@ -0,0 +1,549 @@ +/* PADwin + * Copyright (C) 2002-2004 PADwin 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 +#include +#include +#include + +#include "PAD.h" +//#define JOY_TEST//not fully working joystic code +HWND GShwnd; +HINSTANCE hInst=NULL; + +WNDPROC GSwndProc; + +int timer; +#ifdef JOY_TEST +int axis[4][7];//4 joys X (6 axis + 1 POV) +#endif +extern char *libraryName; + +#define WM_MOUSEWHEEL 0x020A +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "PADwinKeyb Msg", 0); +} + +int lbutton = 0; +int rbutton = 0; +int keydown = 0; +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { +#ifdef JOY_TEST + int i; u32 j; + JOYINFOEX ji={sizeof(JOYINFOEX), JOY_RETURNALL}; +#endif + switch (msg) { +#ifdef JOY_TEST + case WM_TIMER: + + for (i=0; i<4; i++) { + if (JOYERR_NOERROR == joyGetPosEx(i, &ji)) { + for (j=0; j<32; j++) { + if ((1<0xC000 && axis[i][j]){ + _KeyPressNE(0x100+0x10*i+j*2+1); + } else { + _KeyReleaseNE(0x100+0x10*i+j*2+1); + } + } + + if ((axis[i][6] && (ji.dwPOV>= 0) && (ji.dwPOV< 4500)) || + (axis[i][6] && (ji.dwPOV>=31500) && (ji.dwPOV<36000))) { + _KeyPressNE(0x10c+0x10*i); //forward + } else { + _KeyReleaseNE(0x10c+0x10*i); + } + if (axis[i][6] && (ji.dwPOV>= 4500) && (ji.dwPOV<13500)) { + _KeyPressNE((0x10e)+0x10*i); //right + } else { + _KeyReleaseNE((0x10e)+0x10*i); + } + if (axis[i][6] && (ji.dwPOV>=13500) && (ji.dwPOV<22500)) { + _KeyPressNE(0x10d+0x10*i); //backward + } else { + _KeyReleaseNE(0x10d+0x10*i); + } + if (axis[i][6] && (ji.dwPOV>=22500) && (ji.dwPOV<31500)) { + _KeyPressNE(0x10f+0x10*i); //left + } else { + _KeyReleaseNE(0x10f+0x10*i); + } + } + } + return TRUE; +#endif + case WM_KEYDOWN: + if (lParam & 0x40000000) + return TRUE; + _KeyPress(wParam); + keydown = 1; + return TRUE; + + case WM_KEYUP: + _KeyRelease(wParam); + keydown = 0; + pressure = 5; // reset it + return TRUE; + + case WM_MOUSEWHEEL: + if(keydown) + { + pressure += ((short)HIWORD(wParam)/120)*5; + if(pressure >= 100) pressure = 100; + if(pressure <= 0) pressure = 0; + } + return TRUE; + + case WM_LBUTTONDBLCLK: + lanalog.button = 1; + return TRUE; + + case WM_LBUTTONDOWN: + lbutton = 1; + return TRUE; + + case WM_LBUTTONUP: + lanalog.x = 0x80; + lanalog.y = 0x80; + lbutton = 0; + return TRUE; + + case WM_RBUTTONDBLCLK: + ranalog.button = 1; + return TRUE; + + case WM_RBUTTONDOWN: + rbutton = 1; + return TRUE; + + case WM_RBUTTONUP: + ranalog.x = 0x80; + ranalog.y = 0x80; + rbutton = 0; + return TRUE; + + case WM_MOUSEMOVE: + if(lbutton) + { + lanalog.x = LOWORD(lParam) & 254; + lanalog.y = HIWORD(lParam) & 254; + } + if(rbutton) + { + ranalog.x = LOWORD(lParam) & 254; + ranalog.y = HIWORD(lParam) & 254; + } + return TRUE; + + case WM_DESTROY: + case WM_QUIT: + KillTimer(hWnd, 0x80); + // fake escape :) + event.event = KEYPRESS; + event.key = VK_ESCAPE; +// exit(0); + return TRUE; + + default: + if (!timer){SetTimer(hWnd, 0x80, 50, NULL); timer=1;} + return GSwndProc(hWnd, msg, wParam, lParam); + } + + return FALSE; +} + +int padopen=0; + +s32 _PADopen(void *pDsp) { +#ifdef JOY_TEST + JOYCAPS jc; + int i, j; +#endif + memset(&event, 0, sizeof(event)); + + if (padopen == 1) return 0; + LoadConfig(); + + GShwnd = (HWND)*(long*)pDsp; + +#ifdef PAD_LOG + PAD_LOG("SubclassWindow\n"); +#endif + GSwndProc = SubclassWindow(GShwnd, PADwndProc); +#ifdef PAD_LOG + PAD_LOG("SubclassWindowk\n"); +#endif + + timer=0; +#ifdef JOY_TEST + axis[0][0]=axis[0][1]=axis[1][0]=axis[1][1]=1;//all joys have X & Y + for (i=JOYSTICKID1; i<=JOYSTICKID2; i++) + if (JOYERR_NOERROR == joyGetDevCaps(i, &jc, sizeof(jc))){ + for (j=0; j<5; j++) + if ((1<0xC000 && axis[i][j]){ + key=0x100+0x10*i+j*2+1; + break; + } + } + if (j!=6) break; + + if ((axis[i][6] && (ji.dwPOV>= 0) && (ji.dwPOV< 4500)) || + (axis[i][6] && (ji.dwPOV>=31500) && (ji.dwPOV<36000))){ + key=0x10c+0x10*i; break; }//forward + if (axis[i][6] && (ji.dwPOV>= 4500) && (ji.dwPOV<13500)){ + key=(0x10e)+0x10*i; break; }//right + if (axis[i][6] && (ji.dwPOV>=13500) && (ji.dwPOV<22500)){ + key=0x10d+0x10*i; break; }//backward + if (axis[i][6] && (ji.dwPOV>=22500) && (ji.dwPOV<31500)){ + key=0x10f+0x10*i; break; }//left + } + } +#endif + if ((key<256) && (key!=1/*mouse left*/) && (key!=2/*mouse right*/)){ + int i; + KillTimer(hW, 0x80); + for(i = IDC_L2; i <= IDC_LEFT; i+=2) + { + if(i == disabled) + { + HWND temp; + temp = GetDlgItem(hW, disabled-1); + hWC = GetDlgItem(hW, disabled); + switch(disabled) + { + case IDC_L2: + Button_SetText(temp, keyNames[conf.keys[padn][0] = key]); + break; + case IDC_R2: + Button_SetText(temp, keyNames[conf.keys[padn][1] = key]); + break; + case IDC_L1: + Button_SetText(temp, keyNames[conf.keys[padn][2] = key]); + break; + case IDC_R1: + Button_SetText(temp, keyNames[conf.keys[padn][3] = key]); + break; + case IDC_CIRCLE: + Button_SetText(temp, keyNames[conf.keys[padn][5] = key]); + break; + case IDC_TRI: + Button_SetText(temp, keyNames[conf.keys[padn][4] = key]); + break; + case IDC_SQUARE: + Button_SetText(temp, keyNames[conf.keys[padn][7] = key]); + break; + case IDC2_CROSS: + Button_SetText(temp, keyNames[conf.keys[padn][6] = key]); + break; + case IDC_START: + Button_SetText(temp, keyNames[conf.keys[padn][11] = key]); + break; + case IDC_SELECT: + Button_SetText(temp, keyNames[conf.keys[padn][8] = key]); + break; + case IDC_UP: + Button_SetText(temp, keyNames[conf.keys[padn][12] = key]); + break; + case IDC_DOWN: + Button_SetText(temp, keyNames[conf.keys[padn][14] = key]); + break; + case IDC_LEFT: + Button_SetText(temp, keyNames[conf.keys[padn][15] = key]); + break; + case IDC_RIGHT: + Button_SetText(temp, keyNames[conf.keys[padn][13] = key]); + break; + } + EnableWindow(hWC, TRUE); + disabled=0; + return TRUE; + } + } + return TRUE; + } + } + return TRUE; + + case WM_COMMAND: + for(i = IDC_L2; i <= IDC_LEFT; i+=2) + { + if(LOWORD(wParam) == i) + { + if (disabled)//change selection + EnableWindow(GetDlgItem(hW, disabled), TRUE); + + EnableWindow(GetDlgItem(hW, disabled=wParam), FALSE); + + SetTimer(hW, 0x80, 250, NULL); + + return TRUE; + } + } + + switch(LOWORD(wParam)) { + case IDCANCEL: + KillTimer(hW, 0x80); + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + KillTimer(hW, 0x80); + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + case WM_NOTIFY: + switch (wParam) { + case IDC_TABC: + hWC = GetDlgItem(hW, IDC_TABC); + padn = TabCtrl_GetCurSel(hWC); + + for (i=0; i<16; i++) { + if( i != 9 && i!=10) + { + hWC = GetDlgItem(hW, IDC_EL3 + i*2); + strcpy(str, keyNames[conf.keys[padn][i]]); + + Button_SetText(hWC, str); + } + } + + return TRUE; + } + return FALSE; + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK PADconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_DIALOG1), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK PADabout() { + SysMessage("Made By Linuzappz - Redone by Asadr. 2004"); + /*DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc);*/ +} + +s32 CALLBACK PADtest() { + return 0; +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/pad/PADwin/Src/afxresmw.h b/plugins/pad/PADwin/Src/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/pad/PADwin/Src/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/pad/PADwin/Src/callbacks.c b/plugins/pad/PADwin/Src/callbacks.c new file mode 100644 index 0000000000..e1998f89a9 --- /dev/null +++ b/plugins/pad/PADwin/Src/callbacks.c @@ -0,0 +1,58 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Pad1 (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Pad2 (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Key (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/pad/PADwin/Src/callbacks.h b/plugins/pad/PADwin/Src/callbacks.h new file mode 100644 index 0000000000..941cb37a5e --- /dev/null +++ b/plugins/pad/PADwin/Src/callbacks.h @@ -0,0 +1,26 @@ +#include + + +void +OnConf_Pad1 (GtkButton *button, + gpointer user_data); + +void +OnConf_Pad2 (GtkButton *button, + gpointer user_data); + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnConf_Key (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/pad/PADwin/Src/controller.bmp b/plugins/pad/PADwin/Src/controller.bmp new file mode 100644 index 0000000000000000000000000000000000000000..943c8cbc28e30ae44918c14cb44a00b81f78f8d6 GIT binary patch literal 490056 zcmdqKXVhI)-R?clr}xAA?H%Ks=Nv_(DvINv z;{Pf9+gxcKrTzb#r~g(~Q_cVVfB$bOr2MyN-POzXN{iNA!;+U<-TUd&xaa#=#ZTT9-+Pl}QW1hd7Jx|uB=d0;{ncDpq z*z2hMdERGr%1R4rTD>gLwU(ZzvL)}|PGd6Vc&|UZY`2b*^^*_l^Hra}j;__1`H}i^ zwvlg3dajQn-*%l<%Y1T6t16#N^VH^vao*qB)c2fK%Qnw>mXeq0qwHStY_*fNUhA2bW-Irkc8!_6<}=Gy zN`0C7R%>+0>d(-)XOvmdH%tAV)V6vn&s<&gHJ(vss%@rnFH;|;Em!|vwT*J7nX5gc zY`L21q->A+4CN&HvOMG2|Fdkdnv!zbysZ4$ee!Dm8LHjg&)&DCZ(?J92; zZJVw7A7wM@jKV7$}UB|Wmqim|QiLSMLmCV&f zc@^?u+F13Cb&ciGx9Kyv57+v0Zm#FuLhqYBubw%dbrZYpzn4uke&c8U_p*`F#wwG0 z+4HPF-E(;B%oJN+;CzLb$>D5+ou26PRIiJ^Y2D#E%yxe zF~()}k8`f6?A3i+|CqZ`hohCr&R4GK`D#psy&ZFtv*eAv&#t`Q4zALdc`XNz#Zzak z^ViB618b)-82(ls8%vYDu(&IW$MY-&k6~-n;q5pjd!4&t?{i^naMpP1^|`v%`RjZ& z&IW&zx$qd~X5IK}jD@qoV)3-HS#8E%V{vl0&&6F>EN+q~XW?#3&f%;Zf8lJfw&upu z#@fnXSRCAiw^@e2mU{NmraG*eNrG3@l~>-XJsE55>Z`o9vREt5z&+z^Z43U2g~nx# zsmz6?k&?l1E8Co$9x`bDIW67Tx0iv zoyOi|urn9#T6^{fV|xy7x{4SYyyxfTzW({9*I)Bldc9T3Og#&2GxWOl*`e_;dlOw- zxtit7gTuA|X<9c%zQ8$~Z1pzrk9H;3tI1`xi;c-<)27B@+PtsvnR>9(#`Le#+VlR- z@qE4LhrxLd^m5dVt7D^$k#=}%&vGF(=Jmf9cIb$<-wpts^g|l!N%^PKOuqU_+YlFL$(bQYtfWM6I zm<)HRJAcL9wY>~iP5;7MOKMkNayIiZd#m1sxzjjo+P3E{tflUH7w*Db80~xw2G@Ge z;b1P@CBfCqD|^wjYES0sZ{B&Uzkh3Qn%A_i@ithyy0g~#D-MelUQVXL-KKws%nb$y zcdajUr*T+Ja@GceN9?69_2?iECRhDyIyc8UbGdd)eMazpY`qr$XV2FECBKiW>vzr5 zcKUnR<~h&S=i;iyVcs9-ulOzQqHWQu6Rd^FJ%bq+W9>QhGxGk<7GvT2+_hKJ@8@dz zeO0d4qs(i#XZd4sp6fz|$W=WRZJYSUz`>08si!B%6hGu6j92OD>j z!7$p(jh}Ef(;CL>zAt&2W0Kd|?qj(QW+s2zeUiC$UG4X=wa<9#Ty2^-H8454H@G{< z#a4K0%uUuZ)|s0uhLy?Op+NRQU@-Qx_+X)#e)5`>NKpvG7)Y1Lfc<44w~r zsjD50+dPKkt+x;KFU;+^tMXU_&kNofheHF;H5Tjdmp(Ku98LyXnYyQ{byZIdoL+pzzvv>~bYudLjcg)q_ulo+^HMqvBEH(x^e~rzxuD0Z`{{CSq32t~f zxtlrdl#{#CiYmjaUiUhG-B+;o(0=}X-^Zu-Fz_9uf8lBBT<7vo|C*K!ZR$LRwQ#pF zmuKhwGuDc)i(ar+*?EI?$}StNTXx&{1!bwyl8v8V7OQR13)VIs&lMBVzI%UW8pQG=G zYZ~|AFR!^-Fy8$Jv39I=$MvV7=5_9hmoPJQ?+%tHFUh0dbZ(ASK5ozc$W6y~3{PDP zXOpqXTz?LKt>L)jtzXk$3y&A-wJN7OJ={3$9L_Nd*LBuT)5GI7ING?Za@JvOuYvn= za5x#<=Z(SWjiDBvuj}0VZCbba4y`RYY`RyRb-&m3@7Vu!1}A%iv+!A(7B-vKCC@Ti zS7nmxURaFQbtb#+&9>0M!C2>S@HRMG`J3D&7Xw`Tk~>?o&3)hGZRBWP<8I@udk>*? z=`$X8>`l!(&c)w#A0! zfZ3asL+8ybhtJ=t9KP*V<a|`tZUF&vCPTppoW8yWOyNqwF zZM+SpSEhR1b#LRWGq~e&Xj^A)jH6Ajom#i@c%*INYmRaL!rWvuoOMmyYhb*JA%9&v zk6BASncJ7E?#+I&IOpA%lY_C1y-<`@xz+j8fw*PXe^-=W?$?yl~v-7=XAXM?rL zW7ymCH}!3wr~a)u+7|Xkjwj3f8-A+m+-K?Ybq&*$dv3a3IcU!2<(Nft%jvsrU(Q{& zOSy3QZso%Lb}#4dy-PWL>7sJX_H)ZYbGImaZoYomQTlXSI4FMd8s_&Jd);p^4IJ}p zK5zCvH0D35&gJ)Pr}dv(_S|f}a>(2n<+w%Llrwf+WUqC>K1<8_%XTd<-hHQX^3Ds& zk>dY;TW(^^NBho^AHsWz$FZ?q!0KSO>t(;TGMK)e zw^naVb*-CBRSuIGZ)rRZe!|im<9V_gwsKuE*7yobvn}&+Tkv$Obz42z3wJ~Frl!@k zaM%4}_Zw^uPHjDVv)ua+3(&i873PjShGcE#&R-ut<}G#edX2ZqX7?PNxt%7~821`H z-_|^~rh}8Uu7A-y5>!fAw1q>apiD$4bg5ML-H5CQmz~h-bR1&)^a$TN!K}Z zL*E*AQ}afi%oSU0-Y6LBzC-9?V==nc89ZQb>RE+-h+}cR(*}N(H6S4wTGrP&U!hu?iR35_n4*k&2+BVx0g72*xW74sk-CNrF2r(7jzWl(w%Il6fti1KqW6Dh{PAG3b z{rK{x6OSxc9ezMLPYgbOhk50|tv4&X%KzBz`D>P~q|?#s=3QirgI;gKb9fqh3_W*~ zv&P-zFC6U3$z$WM_}7n3?&f&UUCZWpAH#PZ?yJ7I|DYWFbl)Kv>-TZ4x{e+4IhpHR zZVcx7)>c^zYlFj$udZi@^<-}3%*Pq0oxf;c*T2fePxB#QGVNn6oUDekS?;|CV$Mh% zgN?Ui-K%S-vR6#4?Z#ldgk&xphOgA!W3WE+8`KuL@iz6ZF}HaP?lri#(3gpKusJsK zBbv8s9>a6cyRFSxn=uaQIlxom%(70bL&Q4-Ya5H18*=WN*N~c5f9o07z<1-OdsR;M z!elEm$CTWimcv_^?ChPDoDBw#`D@G-Z=AW(nPNqj;jHUj&z-x$WMgpZUi<~vi{}7$ z-D5xtH`aPNwJzm!DVOCKg_K*nVY&#^OWp{eOWN$p6jE`rV%xGBj`KUc3hB zQl5pMZ;pN+@QHWdY<>9{v&u{MSX^Fx@{%ZEF7j!$=Xz}eP~*1&m7*;4{M#d$=%epR!`llv2eKZR_$5tbIP7v2OD=o7kfFl z{IC3nV6d^(=G>CM!Cf?R@Ym**(Y^Y6@v=AybA!LGf$<&Od+@n7*Sybso@$|3F*zn+6sutd1rQ=4NiZwKi#4@zyA}mSZBHnlzVhYe+c&+r{Nls!F2Dce?UsIZ`+LfFZ@!^? z<~5g=n_qmg@%hvx3(EewcJYSKvwOi^bTr@nnMcd`hU)9;S<$F?x;yKdgXe5v-o;f% z99Z6U&gsV6@89~?^6NX^SN_23e*8n_XYaqY-1C-e%11A|uv~xg(dDK4?N*Lju(j#) z?blsf|F6=#dY?`6!d&An`O}}hkH=DHYH$|@kCO8>nGGXzY|GQfFpV4RwEI-1CR;n! zM&Cdu!{hLRdxm@2`?fb8H{SLhgfUh3ZOmmJGi&d z^zN|k{KZqC-Mxk6t@#WvIlYIfcSHBWVR1ECo4M=UXNJ!!2J7#>*SzUHO!y6AD{XM1 z#W*ybo7^?7_KdA%nCU6wU7O$Q`ZqOhGPci+#k$v)tN%~?zOYa_b+=7kP>#^N*|~c! zDQ`OI$nx>aFDl=A=MCkLcivGR`1+U1gWtKQJoMdfmIvy718S6))C zm+yf8ibt?VXkL6?UXOJZ=It7P!(#|v7hQ}#-b)_EF$?FEi}&BNy#0(5q^)0Be)8U% z%Y9$?bb0WbU$fVI@Y~-g4}9$l<@cZXaQW8Tt}_k(+7}&M&e&y<&HM400mFGe@r`qS z4egurY1x+br&DfPHh8(?h^yWQ50j&l?9D!B@MM3syKaSvjjuh6Z5+JKei%A_9_z=a zK)d=_XK~auJ~gm2H??iH>l#}#=hr4zD~rWju5%7Mdtq+Xz*c6CHrrq@+;#msU@xqV zb{k{tRa@%gU^TiJwx&)_&Q{N%`VP)j`eCrIeZyPmcw1T9JcsK2!d-MO$yl4d?j&!` zZ!rDaaX0vz`nR%Ib7`q}$(^y@R@tleIi%3Ju4!|u+R?eDWj&`3YkRFbt!~~gTGvu? z*L{cqZ+rIk{I&M*6U<~K}Z?&_25ZJM{!y7&xmx7WDh zsCy3SJ-7x=y=&aH@$wlgm;Tmg$sEP#@?C$~mK&LGiq^gD+|$a}-uznQ9PIns&wo-L z`NMCOepmkXi=UPU@BMoD!>2w{zVVhfly{%EqFgS&;rJcrm3_C|*zUEp{-5z%eLY2s zZ7`2PT;%;B2AKJ{{iKuel3#tqf#pLNpHsdgef`(FK4HB5`>%gtuldODepCMT(;piD ze|7tN%NO2or7@a0x5MYnvRE@>-}rxUuff?1Yb|yBeLC?rpEWfs%$>^J^^&{E)HQwF zdOeFNXTRruuWa``**ezPd2O;e>*UGabil&OY(hIoo(UQ8x|j{Z0GoI`PtUG2Dg6!Q1WNZ?bsI-(+r%tsby@!HvC*vsLp3 zW4-RoZE&9N=aQMICY2z^Ek>-WRB;)QdPv+L#bZ+pMvaU(J zJLa&jt8l#wXBpRPVA?V<-(%h{Iv3uO<0BAPrZRuuu76=Ib>+t0R)#IcV&khb*kgFn zxS7zL_`IH*2SGU!dN;Li=B|O!y20UKFZCMR8(eLy?fqSN+~&3T-oc#MzKYR0Wy!*F z)sY93554Rh)4KP4@iXP&AAPSp`sY8EfBfy?@{hm&tvvddKbMDp@`G~!m+vY+yzOn} zBbT0Eu9o&ZRX*>2vo^7N%@I@KE)4WF#6Fisd>L)LXT<#y8%*59nY-;+-gx{Grk{WI z{#(iecYjfQ|4DiD{=b%gJo5MQ*uxJQ_aFM+y{5JAdCRrp{Tb!u2QDi|FWg%G@C!88 zv4+K%z;7``x8`D_`^@c{VPE5G^(Nr4IO$AI-a3Ebsx#QfxCh}{x9a7NwW)8(owJj< z_a%>e?!wu=UFD9iV?QFbuj$>&TQo7=ZkN;tcWHOct1;?t+zlNpp4z&K(7DE5E2Dj# zxv76s8|VBRd}YpU%v`JY+zrk;d&OKhY%KO1-Zm}l+(rLRcn)aX@E2fgYGB{np?M5L z{)(*{Ys?+YuQeXSS?6z?XEVRoSnJGfYukdy$zJ8Aag)RFHOkIf_joDWd>UMZyIEJ+ z*sDC5o8z)>yfwY6F*d(O?i#nx2U=Jxg2AS9qs)EyeA!0-=fuM<-%7euJ}vPJcW6%Q zhwplOx&N!5FMs>lkIG~B-&g+mkH^YC|M}1I*aP<)6Cb$y3+4xWTz>286?<@oV#^ND zJr*lA0WHgC3=Bl$+Ps=HCq6IhH26$HpR)b}Z}-K!FSdAv&uH%KmmhwQyo|4wzyIc! z#(G}!pN~Bz-v7xy1Md6co#o!Qzscs}RxnABf?t9&hLO zJ`H0UQsWw52mE!WR*u%b#^0X9lp9~2yUEgg4eJ-jlk?NZ!`ALzFxNQW?g>kcubCTT zV_cM72R9yDJ^OT>>s{w@>R=xOe>15c{_47(y;(N~CyVQPjGnQsZIjjJC7^X{3V$Iy z2V<`3-_CdFHLsPOuQl$WvN!qbY;OGRSZoYdojiH0+_)QDPLH?p7EfZtUYmD|wyJYg zuiP~b!`xWcMqTV3>s|MBrES$`dY9bF&Ro;Fs;Ax^=IC43xb8Q^TpK=b^?Li*2JsY~ zYbn}|yRLUr^ETZZJWk&B`GC9V+~lllUUXsOZtyrbJVRqs=b8pq-MDL7*EO$s3*q&` zT1#kOW3ltL`43t5YiEgne77Ku%k=Kz1?8$E(7WeK@4ltn_oc_vyPtKv`-=0+YmYjl zoF=`yJoGLan&EN5-e-HSfXN(sS^_OB zO&_@Vyy^F5-f=hdaIQ73es9NI*S`IH8=6>}H`$wI>aaHI6U+?`!vNE|D`D?|#rV9H zy_DgvxEp@MQ0GeHilOQ8y2s#NueDW;n_3s<;x%}^c@4p0vDEf3gQ=7wrN2u~ToXJ^ z55mi0uJ!f&g~QHb^BctB)VRi4@r!!nE#>eT;A~~Em+=}*>nfk%Em}7cV|W(6@3S6w znbw~X7klZ!`-o}yyH~rv`>o#J{cZDiKaIb8O?l7x@^=+;cEXO^+8VY+@+{ong}a(d zlg72VHR)aV8UDjGeR6kSt$|=Y#H(L)kog*UpgNG(h*cEaN}=Qf?Yu(tZV@HXe$ zQukUO8aUbpegmBC*{ibeWtMtZxwMh{46b*by&msidpU@~W4|~3h2}kUnm2p|_kdTX zf8lU=5s@2XtM+aDonS8-IJK|*Ue~;|rS}`G4ZhBjrkvIBca|7x>{S~qPUcSd4Z+*W zUgPVKzx3G}itOt(F5Fdn^L$eSle@pmYqHmj$1|*_n1oqco3^XPGkoHe7nbkc@|NJI@cK-{0;V^Yfblt4_sNR_Vjsa zV-C#{?N)}nL*D`Z8gKjD%C2{Pel7h5a`6}5CU=9qrh9|Ac)69mrgPD{-q!Qh_$o$P zo{Y5|Z5u2``>O1$4IcL#?#lSQ=v|(VxL4NrvhNJ*5Ki1_zG+_8r+xY=#qUag;<^6* zQ;MTi8pQ9Oby9idA^Vh*74y5lyj@~(=RIe2{Y>l^CO_G?iL>fc(PrhA>k z#@FDmGq-Dp!rK52 zdq@05>vp_#uUC8x4cxqjU@!dbQqSGgx|thu#Z&Wq$%D0)uZ+9NU-K8>ZSdDPn;N(I zy6OAQklz5ud2aT5+@2U-#ow|yRO!Hwd<}{dX4GPkG%Z+@^-D?z4C?2 z%L>h>9ja^4y69KlV}1_UUOfi+y2f2NEWd$g;63s6YR@TqNb|B@4WIX_!w)R)5YPMd zYG1zA*Q>q%rDv5lpLCS1QD(gw>pWPi0l!)M$7}k2XTB$-XZS`gW8@(ey_1G z__x#gLmnoBSC*&0ko}db9ZzW+_BWlI*Vku&z3AbZ!^~iEv{wzSdTQLvt1h-{lDBOQ z9z2GxsdbzFO&y$h=w9jKWUPC_u3=O2W}X^%;5~#M&NlNQjL**1Uh~qIb8S8c=bUa{ zuj^iCaB{ch>GwAO0T#pE@Ezc=xIA^PEi|w3mU3#}0gIi>9>)+GSRC#B2G_dDS7)qo zSzLAIHqD!UZ!*{F$zti)s()dx>EGt{4mhj+;apo^cYSNxcjPtX+*ia(XPU3t=HaK^%4m<4xT_rl>-7 zDE4PqDld7St(UO<8T8y}cC@}}T`|`7BeWw6FrUq8m$h74vd&gbP^_crEgobH`0PER7ehvazc zcRnYJ>p1f!lE3K>M?E|Q)5gJ9V{f#l2hn@JliU@7F~D9W*TK$RI5oqVJjvaOy~~2V=t^TSOjbFyuC!K6PA)?Q=BE@EFW_9I(j-|H`2zK88iwqmy()Hm10?77AI=C8tS z_R8S(EN)lag@exB#$0Ey$2BmP&pOsA@3aAX@@!D|BZI%^@Vfi%R+v9KTYER0qBu9( zk4&+~yJ`*n6R$z97UhhZ&De(G~}{29=*by!|Y?>(GUZcO%iV{5dd zkwYglHv5P78ZteZ%NS>D>(4&-8t4y3!`_;lm5sX{XN|c{BR9_a7}L9*R?fQd7S>u{ z?%k8T9p^*-!rZETZ9N=J#hVDW29Hh4s_dFpIpw}?ybbN!^A;X67iVq3V%2-*_6*Ll zvpD!0{zHp<2yZu-Yg#z8Zt7x>=XKuNUJucqy4TkiH~+zT8+$pxUpqUf^B2NvXkKsn z3_d1xZlAm7D-CSA*I8_P=%l|Jp2WmnI{Mppzc(4oyc^sdGS_$uXN|St_on7GzV_Zi zmNReqw=q|26^E&N4uhSu#$9o#dJU9Q?`q5plG;3Ve8q35o`YY{SadC8GdB)LTb@P4 zo{HOvy*ntrfj!RmmX5`HeWCWfIb#0oa>RC9mBY5#($+fcv!(Xm)gI{VQ4Vui8_dta zYoK+Fx60wHuNO}CW}9=L&!pLUUDo+-uh&JxF3bIQ=Wc21kJ*Fw5Pc5dE9{||F=B){ z1A{q1-Y0xyj}cC7>%KzjTUcwn#c!w{Z_~VE&OO!Y#z*68FqZQA&Qxb;au)_t&OYTf zHm-xAQMc>jp8Y-g_R8F3uky*Z@EjPEI@rd0JDSyf34X7Vy^PIv=Wpu^ZEIt5eBb8x zG4=+7dym)3x_4!)%Ipb|b8h5~!O7h?p_j7INUiyu>k*D9A`qz0p)VRIg9qgl1J>KN3a{L9g zr{^$cF8bE>ZfIQNtm|BhF%yp`n2Y}q+;#RkbJ4_2=eDx@4z7Pat|9mvJofoD`~}*> zXAm2j{%vLBEzF&ooWZ`9t@9T&w)Yt-M}xK2$Nj`;7|!#${~@26&j#vxuDplM%b|Jg zS@pT2_sq_l(E2aDgC!fSV|$>pR~dUaELGZ>{m#YP1=0)flJ}IKmwVx{!okf}m8Tor z9co_ZuB~HJziDo<8qa}sZu6xZh(%-11@=|v^>)=~0CRTuAnfUYpUb{F?&+{$ zhe!H1nVT^V#@$}~y3Y03-p=z)-#7gR_E3*9K7@M@p@EIL;x2iXM}9-?i!s$>K<}F7 z^|-Q?`M$(3Se$QVaq8bGJ_D={)=ubOF|40&gK5cNbZyVz>CAOF2_f*ME+oEr~wAk31Tn)B{ zeywZ{{u-B~uj$|5XXs|c&}K%dcr|L%vRMxYxha%GQQ{g~MX3?(gd}lEpoD zDYtqumurp3$=a+NZ=+Altz#Hx$$ba&f5qj>U};y=y|hIdcnV_zt)6ekSh(9_%=r7ugbq{c znLFaH>s{v6(72JZZ0rr~t1?XL`I}{rBkMG9u-M|tgq zlNJsB!c}kMEp?*r>=&Cd`!x5V=`-n(AsejXbFtDkMh`dXPy&JgR|E07SdlZ&Z2cm z;WISN+xUw&koz}qjr-C5dBgqLkDX_mMN*mfAY_jYTUcC@fqkSVOqrNx6Hh(PjC`zlJ+92Pu77tozG@uvYCVIU9l_gRacbS3yUy93x6a+ucAIpI7#hAG%Cl?7lNMww$>u_9$Pn(etDM)++O)Us3vdr=`%lS$FojzV&#r#@?*MU)XF( z_i>&x7wEBY8JEVK9oN+J+Qd+_E<34>`^0bbLv8|o!hnhJ1dal-a zxf=fvJ_CM3aMR}J;BaLwea_+<3oL%pR_g=po0>OuZp)p!&fcN^4gVJ=iE>k?%!CP;kwP3T$@r$-8C+)PY&S==S9J~D-+dGkUUVAAPVX@)} zh$qKW;Aes7%#Fc2i#3z}wRkkzq8;|RzD?G8tZvWQ%HOGa*BOl7H73K+WT~}zziDJK zI5o2|8qRhp&-Q71@8rEbPp-QM;p>Mzroox}RQDL*Z?Y98W;ye!Q^m#PaJIP~MZ-oP zTr|c~&-S>d^|iJ-uDd4h*X|$p3*K6L=waup_fv+=o(G3vXk~Kv3c+1xY0R1Fq$8YVvj#tW`RC*>1Mym+isDK3tLR`^#U-+pm3nS)h3(^AyBC)1qQ9_uyw? zuF2vMG!MmIGwhGZ9$_!tZ>iRl?OR@T`2OXJ!(Z0K^ zRa+qMVUF0#^TB)D#{s`K6S`LG%&MP2eS*K8-bK46GlQ==m*y-Co{FK)-k!l;PL?K< z{k%5kuAN;0f8*Y)ea3rWo(?TOQ=e_cMUe{kNyUe~(xHBFpt$yl#9_Bvy`dg@_#t8#MJ*((hbab}B*v(X=I&ez~B zo=hEN2hF%B5-`qQ= zdcIZPI)8~BXuboC>@=^Howx2iJhL3N67D8{Kl$Mgh6Z+?u=ftn0CSo5TB^9N17~ku zPS|Ol#k{iSfiu$ByXJ!zpItt1;Y-S`XP>5Xa*nd~XvD;#hxeT+_Dc6!46fcQ{9V(w z;#kJ~8h<;^CVw+ef1u{U++G8xwoMJ1{DrHv&p6y`+K9{TH8EpI-ShD|L@XOIX=s1e z;LTNRFJoWyDSN^8w8{R`>@KcDp8?04!?pT^-%hl(M6+dfvINtkn+!M)R zr1Lbdbw-Q5@HUw%{w2G;P0wKc?fPV^Yh^ge_0H0!cfD?7lD(P7SmQ3dMH8!UsC|3( z4$C?JX1V@G`g%Q+DD|)9u6vu`E8cec*1QJlUCQ-t={-~i<27hpdb$?h3!`b9;x{CF z$um{Yx9VKyuXztEVXkT6(7Cz3xUI8D-@)_BU^H*=x6P^1=K7YtoL_SWN8L1T)4!>M z?QD3MEKO)_cnWYhbgbpZ<*J67q5Xf@vdrL@y|I72U{7=CU-M_%NVP_ z{i=1tTbLy#>^6Iga?RzhDAy{H!`WnR=1VmOcFYtTc};$n`O>PyS+Vc z>rObby#K&xBOzfR|-U1I!&%P-k;v8_em40Zh8xnlTM z@X0h{=w0|$^{#si7KfmAxLQ4j(6~K&$9}_D+h*O_3x9*T#$xnrt5<))`q1AVgTXu> z`Piq`S^4N0vG9|P7dMm@>0ee*+YT(ejFd6pJuT*0o zjK|_GZDMGjlDF{M8SJ{(#^5akb8BvX0}PH7I@dMvkh{rc)4=9Az+2~QuZ#OQvt)4c z)#@E@jlss+(7B<9nP0sKp zzd7fYy4Tr@$6yKlYh};z9jL$m=9>oWJ!mnv-H`*zG!@Y;5$4Ob#6YBaTU%g z?VP-gvNLw=0hd$v($~f-CffMv_o-#ZWc$C!-8*o;=Jizv$FAm>1!C7f$;c zI&yEDs(*v6-q(DFZS-3#nab$hY~Wpr<9U2?n#cuXIk2ixjB z-)RG#Q>J)@6Qp%tanRo7mY1AdzI4s2w2#=k%l%*ZoSjwn@K3&P=QTWd@7;E0U3^};+a!z|amL+P2O5enOHlh z2ag+HJs#J%n~W6`Q|CIH_4r_Pkory)p5=n`}(|C9t!8euUNWc zIeDk~rs?;ewVAEMSjhTf@p`7>(};ny`&&$d$DqNxr;`3%ygpow1aHNuJ{f1D-P!Dn zI?j07^l!Gq+bok;Cetof_WiIp=k^BLm+N9|wkLay%k)Lc z_L_(0^>rAbZ#C9+aA@A}e!0fAZ|1Irjk~FfgSU+HcKN%MD}QMp#z0ihLD#0PtzLt8 zoNbw#w;LXV&$&5c={MgYn420HUF*#CJ=J}VEx4;bUr#|D&cfW_t~74X-vN7VzD=Bk z$)SaP4@uX+#$DLkCu3_ec+B7C?PlzQpIaR5!QZ-`E&YaG?*@ab-i5oy-q5@%dt5_u zHuJ{W%3D|~t}>t2G_Tj)=XE_>nF~wdt;UmQn$BHcU&dz%p6n8RpFU9W3CyG69o&8i z=SAFLe0}H#-!6~*?$_nfzy8I}%K5wY66bv0KWIpF+sYY2})yd8KBx~6hheJ~vlgtZmh$s=Pe z8=98AB+lM*=kiMJ!Tvh!sq-f7qr={1*Btl4a>Wbx*JsPpa+2aXSZ~bv6s!T6t=|dW z=gp+yIU6X?s7RgpRLOUSk*04W59S#!gP++CPo2|f-Q+Lj#%g1+>dEAOd>u!>jp_K> z*RAY4-h0-@zG$x zQC@l0spc^lhr@F?Xu%vC^A`1!PS+f=`4nR39{L`1{;`K!yZ2wN^5y0e!`jQvJk{#7 zS$i@T?go3|EbKi`_qjpiEL|0OS3mcd!(A7Pr^(z`tT?6IaMdf7G+w#2oBz97dBuv8 z%k^r@l=?RLd&I6gc;BmH40)tCM}E=)dshx$a>hx8_DnE1V|x2?YFy{8v$k?q4A@6H z=1s4&n|(WxhtH)>3#)Voik_lAJWdt zdF)X;Bl6Kd>zuM5f4|)S#m|)Q-h6}k5yUzWXU6;*alf3oHd|V-a<^*Tj=|YRuH^m# zZg*%?V0aP z4R(s9$=I5U!^URvT6R6_?B$wdcIw~ghv8yqeGRMU*v4G?8>jsmIJ);%82e!15RFc-Jleay-}FFRcKdQ}gD%$iM!D&pCI|z35zNTR7W~c`IC1`yMkl zEI+t+`ZK2g!2SAbUF*VG*Syqs*O@Foxc8fbas4%YnQ^-*mNPZ+-CwwCa9!^?-2M4s zUwXgjTUgxRcV*=_Yny6Pvz83*#%`K|~(fmNpm+doMZtq$l*cImdR` z&f6E_u2%MZeftM*c}MkjVQ$}dtT=4GZ>M>``nk^z#$-%yf8AF!X5cf3yT|Oa`{249 zgSI_rrv;DuywkWlOWfr(_?g)wVd*B%H}1Yf++{xP&Z}NtelB14fp2`N{QZ|dD~~<+ zfWJQHL+W?g&jbE!`Ti|$wX=0NQ|+Xk=4)PVWAi}y4C7~myXNsq>k_9mh-pCoilLs| zcc|rLZ_Qcj0FPa-PIwOLGv11Q2mh%IeNj?wr3go_V!E8 zD_?ulYt6rAul8SmVG}TZ=RbSG&&qXY9(jl~?<&&8L++w~$6oJL?ut+S zbHG&B!Rh}#vmCo@3U|e0wC<;FpNv`P?}zs7>-f8TH^#p}?=E=Wn%WoadF7z3x3Kfj znN$0i&gfz83~v|4at=FZp~K%te*c^D(D&~xf4S=u<=(elSKg<+#EI)YL3)=tDPjSd z&%nA|F*miXu{IeCcl!iao9?Z1Xs{RNMl$9aM`;sJ)t?$SbBoE9&aIl4abhxBm-h^B zg_vXJ&hT>C5BNhDon7wHd2heD-OpJzr^0&Q8g7-$`y~o9F3C zxNcTk_{Hu)tZkaK|NT5po_b}o?%$WuyJM}3Rz7&)9F4;hUb7smbv?iN#qe)meJGwF@J;%%-u{`H70x8L?o zY1$2K{*5`f(+(W!Z8R@>m$B!7Cx`dyG5D#wtcqQaxk9v z`l^?nWAkdchZ(*@|9^1vb#E}f{%>F^zio&isRrtdCz$(Y#qr7J8WzFO|pkCacF#o!1>;5=*!8# ze@EUJEADOR%!PxrH*RJbUQXjO{VgSxsSe9Vb7%|NXt|W49Y; zO(S!yl3&;6<-Y#K;rIC!2k-0tgT}&TIQs4zt{dF<492Lve=X;3%*%!Do#3wNU2#|Z z?XNxkVEMkfrk`sYbGO&K#$9RN{vMR^9n6Oa-xu$9>_ar4Vfb_R^KWClYw-?Z^4McI zSsrdOH*;sNm}~QF9{(`OUFWRvS6m(FUU3uFwzO)2v;EKdLY;w7V;scW%3WPceAx;6 z?Kv3#y>H!Pn$Vf+aSnLD{XNmJkEeHg%{$h+zK6pkcRiL&b8gaRq-j0_x{Wx8{#hv7 zJX>%V_D<8gJ{RYD8b4+SY1F;9SYO|{XO|21U25whK5@lG=HC)GcK=sDS023QD|S95 z@nn4ehCv_FT8h^nb4WRB_Z@8ybJkthSv~T+dA*?l=i<%=gz-f-tS9w?)<@ap2mLihKWBTwgINw-e%!7JXM$r=Z&M{t#LEBYhFVw zcbv60*T>C|fW^t<%;SD)Z~Uh0{XL_-9QS~^!Ecz^|Nh>1^%cQtjfJ_Pjd|_Vy<_fX zd!OS;^!GhOIu=dax4}vC7#>gW!d+cA*1N`Can$GBoWEo4T3mz1qz?gm``5o)uWzwr z;X!0v?^wGUcXjQw_MCGY_nF?6|8TwL;QH5uyYMyV+nl`_-w=9NT6X2!4gLma&F8Hi zZ+Z}u*E?q;z89Tqyd|!|)0n$xTl@!K*Vf`1`kw`s63=^`=Gyx9-e>T6wP%$H?uPf< zU)S_*aCasCE?mRg?XUgrH}5gt8I#3a@@d?K$9R%F*Eaf|Y-gj%<2`uJ7Uk5%+m*}o z_we>Jj<-3bd*1Sf^5gg1BrW)^@{14NR=$7hTgzA8_?mM2%g(j4b1vL(H`}v;IINwt zUm0uP@OEvV1~E0)t5uyFZO+}s+rFOhWzO7A19#dt{o2N1_i#<$ny--jm9Gnb#cF&8 zer7c4-dk*FXU8)q_#vGy{5`D;;WNd26?xeI{KsSV-ojrz?gzg9CCxS7Dxddd@F^|Zem#jr$4$t>)cxrhKOJHfw*jf%2R;I#VXJ?K_AHzvw>xMbLak?=#d8+Hh z%zBO8JFcTWliF7tGKITphoQz=_^fi($|`?jq<4+CaZR#!%w1w3@F4oX75JSVL*`TU z?#j4Jj2W7jBrjr;yQzoUyjuVI&RzO4woGvkQ~ZRccZYLlFgG>tn7g)*&Puood&gwYbGMH#TcsSkl6kdbrun|XTbMgjvHerI ztGOk-2*$AfV_U_e?5KGr_POD_Gnj%7yk2wo?|tc+1?~IU*IZie)EqzOMY3Mv+T#z` z`DuIDeA+>C6xXUf#+jpoLEP8o)Y#+EIO}_Y<=mRJp?T4|%(tOwt(^WYI@dMvK<|dX zfcF4LGxsuVZS1Z5)mV=!!)Nfb;LzlIYp$3$2E6I_U-)8Mi+A4_J}n>RyXI&A(vsgdb!}sC>xZWk+|?YLak*o!#~lZ^)jpNG zu(?ZP?xJ_;@Bhx=WX3sIu71Y#V{Be+8h10kOnvBKbnoMFH~onI-i*g%*ul8#^KNKf zc-)V(H5JC=>Fo=(x7j3jJ^qY%v;JQ2wy*bPV$qDf(!*o!*7#oat<>ukKhtX%U*BSR zL-U5-g~9COFxI=qT`{++fke_mMXKEpJ+$3DEh)}1Jen*;8Ov<9jk(U=>hA_; z)9dX$1sh|YZfe}{7^HJEmY3_`E#BIK6&wct+m)hdSz|>%+InlBBpnP zyL`WYDlnJl7_t_QMiL`;fv;8%22-wWQO-K~IOX_hV>*4DJWjuY`ievL8~pB@&!Bc2 zD-QbDq4phfH$4c`#kvN*j=77UF~ME*Zmxfe93Qyand{vlU(JhH33ttBn4*z0#*A3s{xu(uyNp||`3~4S=4RXDA$*3>{F?c_ z(z+REHohJ&lLVI=gPYGgox6AttSgRO+P42$R<3vVH0IV=GF>;7yHoV8@1KL_b=^Ca zyW;CK-

K_irD^XAl=*qs5cyHOy}id+|MY#_Qc&=b|aTfj!Aik?(Mp&Y?V8oMl}B zYb#Dv?7|WHKU%K+95}m&{m{2ni~w4feRl9VD|f5r?dI3ewpH&o&6~Wf^K2c1=}X@s zwQe%GXRw#iy)YQ=dd^t%Hr_esU2p~v=f|JD*OGGGiAPAsUTkr3#A!Tm&sP<*@$K^P z557|#y!Y$oKj1NZ?zNZO9Nfh^pYx~%TkG>?ePcL#=4`R*|B8LeT<=a>L-Ft8aI!UX zI9to&+%Cb+T{hIYOg%?CmNF*CRW8%tjY%e_zV$lXY&scE(oR09cjfQWCtufm;*Py= z6ShwHyP=Kg&os&1DSB7jwf%#|RgVi^bE@8j%~QD>I@h?X@^roHS~xx4o*UI?kjBk9 zIQTo(yR=R9A0E$VusDa+Y>h?#nkOHyOdi9sa*BBk%L?%gegD-LojaYo;WMPaFfE6v z&fQ6$!FlWKt=tt)tt_@q^%;!0v2Hln+dpgL?kJ8-b9A|Xj?Jx2<*s|I{r#%X!2UU= zcUR8Wm2Y*uwt*4 zD^8brDdHf|x%0#^&J*T7wlBl#u?Mg8WjzbN)4$GFc$>@(4u{Tl#=8DZwl?m%zu+1d zO)Rb|QLjFO>bbw8>s@Crnj7zhm|J{V_FW(rm-P@gzxZTZC-FVSB>(24?=OG(>?g`! zKle%7kK)Jgxw(Al+N&&<;ngoX$b1++mzHesJYzWLS-|;>BlCSCo6qp?_I$^jb$u(g zRhBm14%iA)Nw7G_M%miBzFP0E$?`bYJ>ct^Q}u4+ax&Pw2jlMA6F!6KT(P(6U6m)f zJ6-P@r!}vZ`?li)_kW8k)4TW)sdH^^Z7O%syUAVGy#2l5bjCTD-VOdva+m!arp&7u zTYayG37c)t@8-I; zUhmqvHrT85_sPh5gFPE2;>hIh+FoYTLgw#I<*xItzh9eIYuuftcUKrKbraz`NEfE(VBD>`x6QG+-vEo9s~Oi@b1}|2o2-pG z>>cG!Iib!)mG&ox^=r>_@zfoa~;b=Ev8k#jh)0|1Gjw{_JO}aB8SK6TyzMpcBzMziK;wq)6*H2( z)AcU?!Z7vE+Vt+w-#xz9yINNPd!LBUz!=-J%rxlA{av*1Snu*&9`g%F-RB+qyB6OY ze00qlb8KQI+?=hwckrZPDeHYXlM?^I&ZLwtO1?n<=j?Ni$8Ow}PtJJ!3cL~9PePiP zeRzj!)<#}~>D_1(6Mc@Y_j%LnZ61Sr4as9?DOxl2FKl&>AsOtR1F^OA;WeO7S=+(6 z!|;=H-kD3p>wSZ~?6X zLyOy-+A7V{{dai^J#VwzSc_NCxar&t#&$Z^{RSVmB*yoQrY*0{`!!B?ene$=yhbpY zvD5T!<8FA(@HrTq?49QC(wBQg5c@EW-(7L=epCJ3JYU2834Dep?(f3f^cW~l_zV&6 z;QO4p?(MnZ+(ieA%ldmFhr#3cUHo0z$C@_%hiOdC{d>oH7k|NHdwreTQvL4t&xG$V zmAh~j_A1ez`l$Zc{>}KSzaQEr^zN%JYcamY-e;A?n~vglKd(44 z)4OBtqIcW=4b$e;();aycH^#?%HCz^GfdUH8Ux?@Ybm>Sb>^aZ+1H^TlRg8wbbRg^ zelOR+U-m!qy)J{ndXIRoSnCCAS#QDolyMjqt4y1ncd2n`XJfGL=h|0iwD(?b>RjdM z-}H2=pP;s3JXvF{u@}~gqvkWD{x!Yp3~stNxGO!%`Ziw2G_QDxuY#uEL%)B-&>g>M zUO98=4u#mbmmj#drHk~vh5g-6+Ht<^SH}5Ai}f9VpOZBh#010nJc}(^H{h;#O#7gX z`M3X~lx$oXe<%BstBuiITUjd>I-5s~4bIx@1TXU%2<9vTTT1R)Z*1Yx1owi=hJqXsT4Rx@^`|59Qng@~lsK55&^9Mfnl8#Y-N4}%!RKL+_iS%9Wo_@J!k)%{{MzG!#iu< zJM}JWD~NIE$J~6~H5Oksjw3U@EByz1@f!}=dEwwX?vZg0{rz~&exDrX*rs#Wb!C4o zJY@DT@Z9^ShJqUSJ z={KCIz2ExZU*j$@YsqKssj_Qc*T7f2__V<_{q@tztRqGP<3~*Ef4sJ1S+gv*j+r{X z2L2wb-xc=Z8TVx!_OiY>>rW(q*Y$7oIk##4gW5dSVNwgDf#K`^^246U>*N@ZXJB84 zt;&6m^RxKb#Ia}ONblk~OmJ5mFy`7C3uiBLYRO?Z@t@tF;jAMMHBWTR-TYZrmVf&8 z4@pl>`n%)tuwfc^%}-F@zuKQ+d_U8>(zDDj8E-3pX$$7c1D&NZ2~CZ5MH_CX|4YtU zv2%u{5t&~*XzR_ir_Sc(P|dp$Q?`8OCidNZ7x}=PkvUJgkk1}I2aLVays$MrUemf_ z7dqDx{0*L_22NdDwQ%&O)-|7D(B>Mq_Z#p5%!?2cIVXZ=zz0FIvfd1>&gaF>8{%QF zt9{^KV0*z6ufhJjtV?6eHfu}g>V4;2AUuoSU*HV*jNL`sn!fG4hswmzzqS4(Ga0V# zD)y3+i?DcCV`OqS7`%~d*c|6$ywBU5tGkTGrLJvbVjQm#{B)jX``YEKDcm((Z44K4 z$9XXLb6QV4{=J@7hl9uMxmetWyK6t8Yw|wq17UFv;`P`s&M}$inQzBv@3XO{tz)E# z*_U$cBV_+LXWZ`E@5J=3`3yt7YyN}S>psJ<&wO9~t&)$uhVkoU{lnU`$IlLO|ChZZ z$NNd-SbPRsM}hAk&XOM2-&MbJH}YVvvDdywuUc43{GZv6EZ0(ub#Ol8w4D1NvUs8K z4BvO!m~6vqU~jXmlQZ`Q59!-|&W!S_pZ#>u-;W)akJeg?WUA+Q3(s(ko7xxtO3RsM z)@z`3@ey{C*5eF!_N#r7K1=Ha{oN z#rF!Hko`JXT%2^yJsM7H-TOYU940a$iqoE0@+auA*l(<^;`A_P?K>``AZZ z>#Dzv8|vm{@$veddz;o3->A7bPks5yf-YXBJtp0MaPG4A88N~wpWN>k#+uF*Z`1c3 za~CF~fivZLH+%)W-qYn1d*9`@w*zJR>^vdm?BmNGlkC%*dG6awe*UpXRGn+Suj$?4 zdNt?n^mqnaYXNs7y=b=`jlVFs?cqz=6Kf`Ht}XlrpLdhaikOGo*Ee(Xcsu4&@40*D zC_e4*T^8v(BKkJDOP*zqX@J4(WA?JsPilMh%IAfveL8f>_U=F6BglWiS3vU)llJ4) zK4sQ+h5D2(I_-qAqrRJ)cPbq@<}Us&{sSB^k5@h~d-?X>1AFws-As#Y|6T3vdwJWV zm-)1o*pt`y<=uVu4C8Lbk@=coxI0XEz09%Uk-*Kx(tCSuwm~^$n=OpD=kK#ixk7s7 z^;$E_dJ6VYWG^%J)j5CJF5<8D2$u%lW7GBY`=;;a`aX~6fQK<7G_Nr?IV%R*zGc)c z!PPA1yqdGtd|&t(?5#OmRq}YUu0QU_>%vUe-4S~MccoqV`R!Z}>0kB^CZUCAX`KaY zsx3xC>x|L3ynfZWcnYu=&eptfcUm0p^tLC@?{%M{<7hI~G^h>pzotHE+t*xp z-r)1}&O1Kj+=acSeS^8Gr{93rK)EK(r}b-!bHB)z$9f9le1pO6>Ei45i8X66&nB)? z<~%m?{xct+1I}7(fW{HqaO^&ldN=3X$lY^*!|n@YEQ7U6%c9XT!P!|bCVd9$59ShE zX8o>#w-$4@mHuN5F*=vM(NEcVyK>0^dlu&SneYGTD_?4RgtJdL`$uy2@SDY9=A}+u zvOw2}z4{!peafVpVHxb}eFiIwWzJo6uJbeb>vb3$eaYJxXFAt-o1U&;&z`u+Sz;K> zGttjv>r(8!^|?R#>~lx_g~^_XgTuci`ToDT4#Q$2(6mz$Om)5MK7;cZ?>AD_zE2)! z$Noj~bl1?eP0OM`gQM`&%E4#jD=dbS!@i#5$=Bp|9c!A^@10{j_j{!;fv4O5{;#ae zIP~&>!5xc}!`?5h;w{wFJYs8u$32sc!|iO1H3^wOXfP0ecsK> z!D6_pScl|tHMsYH?%hSP{g3Al_y5PvSus~^z>6@}W*%{5L;hxL8T0*JO4h0^ zxy$+q${ELNISjV6N@3r#{#p7m{GH}A7;mMCZO<~X*XyBy#aUzUfVuEDQfOPN!(d~r z*sI)hpW0wH&xxnGWTSPoeqv*-3*M%@Z2!FqXD{6Giu23YbnfL3Z+n~Vm-7ql3(20n zoHzW@OJ7>vdfKt&62)b)ANv0C9Cpz?hylQ_Hob|y?UKcisqVf59zZ7NZED|StmRYq zyE$##R~*KJ<>%l`AB#)Y>*JR&FUYxSl<^esY;#`;K99_EhUvOj^@ycqEoQ;;(6**; zd%lLhn>;qgy0_pSM9h*2#AK2XWUlulHBxR$U86UBf!xgVVVM~_m5sZ}S@JB0{%t(Ybr($s(`Q^x-iF>yF5A3Y>gCY8 zrianLN@MQ&x?|S4g}ybd8~Qifq+yfA$=J$YW3Thq)>fd2lgFuhi9-wa!s2l}L;Aa} zcZVKC<1B1W?(%z2@;SH0Ue%c^H;;ibj1_}T7e4|0+w)gU&i!*PIpgGi`G3m)Gk!zU zyiMa){))l2e;IjjxaRWy+L>%(Y{%Ss9vj*=nGAzX^Sa(WQ*(1G^OW%#rp>FNgITLE z(7m1aVBT!#T-U!HcWDpaGQVd2ZZOxlYpl{-_{~oP-#JpMM9C^5$h4YbDoL9c} zwl~_kF5e?udqirVNcKu(kAr))j{*DVaCXIc@*EDIA7@^Qb-pKhuX$Zhn%0H8rh8$o zmp!J}89Zcf=RLq$7%5iz^_nv?<|>{<|F6U!FIJod`@8S4`Fdq9%?WbW1m&fgL*ty_ z?e%PUyL>LdUS2=%$v%=9v*7G)S~pp29s|4;YpceEyTN8ODD7h{`d?A6`WAlvXA&&# zcnmkEULWIXe~dFmqnoWicx-)H#@}!bU-^>L<=0-h(sY*Awxvey^Ce>qJe9*}U+1v1 zw%5B}M%yyRa^tgm4vb%M$iBv2_)B7M_1tIObg!|RShQgAh`q^M@?`KJ7guv%Gx(bx zL*|_Kec73(49;&${{jA9sy@zY!y6{Atd*{?cr#cVDS5lSaTVT1GWNpTV6O2uxEpP$ zdtLj6&tTlmGP*bC*j6k1Zo5@Iqb<*BYx!mByG-0o-?#a_rhC!6Bs6U>7Z$_Z%!o%%$z4{h5znv`u;WLE1y+C8v}xYt8Jh?|5H%AomE@e(1I*`j5YF zd-VSHV;?XreA~IFX%C%!Y~QbCx(91>VH<3pK|+^WlJ6kiy074EUUrVUzo33Ju*R9c zYkBwyXj7Og_HsY`T0D~Z@|0Ou$LGd=inBO$?hK0$;|xyrB0FaLx#fl1%(QdcVK8yI z3-mLieYpp(YkD^|u3{qKE37r%rl(-MRbS}a)V9W7V{h{qe2nw?zsl#`bt9coA1s{8 zP5Q;hrIpEEx3R{|jQv0b-SDKfE_Ztj`uRU-3 zvirLoi;cNxUpS239VS?ti9Ta5UW3Z8)?B2f}%~i?s*C{yK{SU-zmbv{&uR&S`rlYTuYg{_s2BBV7B`KJusE z+gT0lWBY?!ZKX2Jm+r#|G?Y6QQ-6h&D zho7785_~?ubJx3KW%>sb`gi0zpm8-ewQSYE#^u(Y{ZDqjbYo}gQt>s}O77*>W_*tJ z?CW`)*Ct~v502LI1eb%!8kZdAGr-E?p|LjWHpaQ?{oOcYZC4j3oxij-4i9*n+$A^m zCX4YR(vNVRTXnG7$KJ2axrwKYan`mxW6j*_RlD)n*=#!3Slrl~+_hYs9qZn@u6V@U z^c;+}U0-7@yv+n_JI;#9wT|wc!rjW+(7ky^Te8-2vDf*V`ZoMs*lWITW3TzX<~ub0 zI&-CK(Zpi0vlqSFaTwkPbB(j1Z->lH&msNY*rOM1o6H^Ocnqn1^|wvg6Q0A6xyjy| zCwDc@8SK1G9;0q_>MN%Qg` zzz4|rwYHCgbgvj|v0Z#F=vnM@AR~eHGPMr&LVKvXbjpDxW4)#|3;}P4x#84fw6Eg<=Aj&;?~nWHyh=W6h#lkn9`;J#WL3qW z8B069hVFGwA==YRU~DqhSdG8%@9`L5`mP&0Tb;kGb?NkLa+WsZv$SsXCujRS%ayZZ z?yjs}d7K>1oM#FC!rk5%HXbL3GtaejS#P;l^Ip75jd@!#Fe3wV`ueVw#Z z(74WBbZ_r9z};Z5m|_~Z_Z%vFdykiLB;&2eH=unhXW??sVz?W1W39?f_YRrMe4BX= z#5hn^@;E8V&Q{~EaaMJ5rQ|N38_cP3{^NnOH?!D;tB*Rk+#%og2bxR6%l+F=f2i|? z|E%-fAF(~cAHDA{zDM|1KVN?Q-glIbE53o)vK6~6(mgiUy`F39DA->(^{z2j9EHKg z{&?2edjH@vF}1{fu$K)#GhAi81B~5Vd+cP4Loyegj-R``Vki!ihrk&`uRii1^G7~; z<;Awo?zeBc-ZVRB6>(Pk`z|=sp7VU2S4r$K-Y@&=vTqsBX+E!U7tPz|*Szf7*7R-V zZEI^=KW!%u@@R3%`w%3fWgwR zXyC|A`v!xJ$>MU;!0zv&d427%>)iAn(sQ6M%Y9xMZ0vQux)tz^A*;rf4&RlPMeCBdSkb4j4-q5^g;F{8V z2>lChLkq)KIP6|88ke%TD_&HuVO%zrz!TOGJBLm0!dU8-tDjuS85~{%bur7@O#8y! z#$NmeXKgY!cniydzpiy#d)8C$T3xS!2Vy>hyn*GjHnMnJ_Uz*PVCK~R{F#rIhrV-< zop;F@WRL#k&&Bo#|K7LkoU(7f<9gpCTxYzWy30a~X&?rexU^jF1#3yXCZ7v@<}mNZ z*+Z-|CfWWE;=ivuX6>8Kh}W~37KXp(JrI}cS{MJ=y^&3|H~9kd6mB{DwDS4aU2d@# zzyHLC%Y9$`bh%Gn$e-@~sLt-WrF`|et99nYS>?4yAEGmrcd)%0cG3Q8_N;5T<|QUL zeO;ep3ym9kwlWyaYy5TgT3ng6bsq14y-&Ulc78f@(`#6o8rawif8j0M&2gE-(#Bom za*T0)`ZZZLmRDByeZkh`Zszb+DShAcAnbn0W6Q-<<1M~IrpDdmZF0EPV|_DBP5wrn zXBfd$XR>p)l{+mQy4Q4WaJTNo)3LYm*8E-f9cVMpcR~Z>1&7xl*5-Ng%(124kSuo1 z3yV|lX6{Tj_J-%%{08@W-TRgQYx8VyxM|(o%K_e|@0%>Ho^Nn9nVU@RxtsjWeH`*k zcwbM^V$8hWdkxOq^nZJgcR0T`^dD@lO`dP_d7Zff{=(i-YW{*VxbfEg-i+<-wXdH; zAzhn1hPlKwR0gXo?=-!J%wcY_4ZT=XXkGJpQ}?2UjqQrvl}E~c1n58ZK)-PL?&Zca zjx&w;)A!v{?*HOv%0u7&MtS(h-&6X&ahUjqpMBs~oi%)goi%*P0eh8W7S7Q*7NH^e z{vQ5ru8HG0;qA81^}}FvFsz2ZFxTeN z(7IwYYkQe5J9pWV^5&C|wtXCbs2I1ue*RPC!EfDd9<)90cfYAK+wUsG!128AIO{~k zChK_@%~j092Bw=~JaN3XCQiIG=4yV8e5ieWuB+H>Vh^(8gHJv-=?YItyL;F_lCVw+`4x83B4Xk?dR~%2@x9Qzp`=WV0S-*J)8uqhxH+M)8lQ-4Q(s7**;^&T{xVY*O~0!@l{@3To%i?o;Wf; z^HOUj=4??`Xie~Ijy%xTMtteoSLwXVca%ST>UQbJJMBz{Ki+vq`Kf$e&b>qz<4c^S zwZrV)z@9QN(aw0+Yp`xD`Obcm3!f)%OuXGoaRtQt9=gqz@@8k-_x>a1&n}0}-O}3k z6o+@#`aGVC=X1ZBXU3D(^J>2y&Xb3ouh2PIx1DpUVv1j1IEVegZ-3p+sC@L#f0RG+ zm-6@D{@Tu!xKBL(uJk$QTfSO9-ziHL%IEbneBe9223~`&QA^#Mdbjr-;3@o#KKP2S zOPg_a$lB@w8;_s7`8MODc)OeU!lvt zg{978Z=1&6oO82Wykv~WIyiex%T_HM-h()5-hydf+Jd!KcWpb4bEtKgJ5BS-_ibLU zbJo1w^dbHgcky=_)9c>kZ|3SV%?o$4tQ@vlY?*nzcn_mAU@ojp_BQXKvNn8%-ec(X zZsji;SFBF0%b4DOaDP{AVy$}&jkWGExZluoww=9(=MWx)u7{J&bD%7)8fzn0xoKWl z>-Cn?rg70t^U;MX5>sGYsQ8nv(A@OnG%{ku2cP`>dN{L)Ly zd(U5C^J(Yrv#VmY=4hX<4ecJRoA9;5{@T0--xpx$t{Z!-*WvTGve=22?6J7Kbf2ZB zu`k?jX?clahl#0R&++|cZmjX^>N@RHqyHz)OyhG34zst-vKbrMSwyT^<~+3T+en$C;I%)I1=5G<#0$ztv`@yYYB=PmH@_r|DeNyRLn! zz774`>dx9)hppnTY26WLpKSi_mRi*~2`gc6@H5#-TQXER{nU3;d(*>ljg1S2+kIjT zET>P`z{+GS*C#_;TVrju<(SOf+YN0T%x!(?G0@)_>^?=-GY_pBOg3K_zUrRFWGgox z!p{K><{EoPenT=hIGp~kc@XML9o)F<%=J09RO9$sCqZo4@Zvn?f7f)y`hJD?iy>w-^`Q2Xx&!E%XN0R*DL<2KiLa+ zo7Wp2FU+kmX3p8bJ!D~_J4 z{Y+jZ-}Z)6kJkR+rm`ocVV?HK*-VV|vxe~!@IkmgKa+7% zzQV4XtZUpj1$VuXPs1TT5+Q7|G=5+=V|VX*jvAEvRCWP^xhN4 zu!B70eS*7oM!VwPzW2@>+%wv_ z*|FDHoZO||%RXnvYbA4AUmHVT*GvvX^|6 zGTwo9*T9iW2Pbolwc@bpV7M$DYx))rN3s|OmD7K4-&fqVHs>zo0ejKE)pKBdaq`z$ zoLbjB2IFtAxaV%Kfx~}r4;UTnzHa8`GvGl~4J@xAS*zUE5gT(Ghm*UhbF1&0@x9Wz zrg^7mUGsIT#+{~hle?YQ5S$${7skf?8gp!xn&wT`W}f^_z1wneH|E*KF%GVO`}wtA z>-yZ<1aHy1RsV{ugL$^bVi=rrZ1|@bj}XzG(P>RmzVcmutGdOT>FymZcJZ3Ycq?tu>BeNztEf-`QLF;z_5As+kC%ru=l96(ep4QM@c#1H!w;GE#plK2{o!plTCB!vk2*wWw7cHj zalPm2nVZjG+zoGcIJcI5Z?G078*@7jhsHJEA+L-H{!>~8?Y~}+VCx0WadRW)N(;;)c%{fas zlGr(9Z>M`x4+nSCe{k-Om}?9U?!r~oQ|BgoowuoVHKuwE&RXMgoojOsBKMTc`8LZ< z>o(3-uUG9JbLO6JdJMLv0`87e#F@F*i_Q(Lo9q>9P4`yjCV%mHUE>;$;c$2lRrgvO z?cq1n9N$5DHrP9rzwlU$>GiMq4HoB++;t|W=a7sw-`6;t+=abL;#Tz+RIYKolq03a z_4tPL9NfpX`8H|8-fQsn!OXg))<^W7Q- z<7@ED#x${)eRY@3(D@8oZ&8lec9!vtJs8*%@&xJIqr_XzzGN;AoeOjMP65AWnXjwY zmR3hc^8E{EG>&i#Gc>BlRU;R>5OyI=8b4{5E(-+uWsi^F*M zCqJ+L$Tqg~1a{ zP6l^Au(4NTTiiqX41KP0$KGk{-MCMUeF(lLdwsoydl3DZ$Hv<59n1p`PuSVpH1BXN zvHQGs##`mD`wyvklfUK#gudCBfFnVe#1G zH6Fv=U@tu9GlKXA;<|Ry?-c$j>u*^@yr0fv+?Sl6 zXTD+*I5QKk7H(gD*naXXPPaL^U)}y*)1aK8jz)b@F%vNJ*E;7HKl!~EoK^4;@O$^y zYjdtKF}uWlF?UDo1N*V#7hL_KgUbgldWl`feVGG%;Ok$m`$_!%6CYA6@0-iVF1t{B ztQ{c_Wl1@F-YkoWKu7bLW*!6cYT{>$W0+PB_NLxV-p1UTa}=+^{e~fHpF9tuXX$^Y zoV-oG_H0e2X5Pl4UppObymjXK_1^Cq+RMJK!}YK+7H%7VJ3g<3$L2#AYh5dwuBD#( z)^zZQyJ~AXI2apkJ_naxLm$`B+R|$R^8t33FHcukj zlDV#ZUH4jB@-}>k^c+m@248DTFZF0!)ahQEZ!?|Sv~P_q!*3uNhhZ<}#$aP@=wNj3 zcrCHVl)+sw7rhH_#pBA`Q5}ujYhGh;jqUAxhV*yI(Y7l~(t62W*SOPt2fl~XZ~j8& zVwC#~%(;ceC5O3vuCnP~am_pi%VWMxo~rXUx$CTL%nkNNEQ9OdXZRdj=wI%gb64nB z_VU7e;QWc5G*8Uj8)yHphX;MGarMl)ZdROKOsp5LiN0U34s&VGx4k7_thEhqJmCnN z*ZR?WZZhUREL}=GFzb*X`Q5KA_Ui$yk^8CQZSTD574mzJDrfJt*w#jH*6~7KQ+gNn z;x(YRk6JjpT%dKp*XiEq=r3RU>hk?t-&%hDf!j>~{z&WY;5hqNzV*~&3u}l^*lC`v zS!2E1HfyhL?}6{rAk7-wP5wHAJ8cVR(Y(Q1i)-j~aL--FQGc>M23`Z+k#^sB9py@! zq|T+DeadTl_D9>4_GD{bZ*y?y-QXn`MtX3-($JT5{J}n!ba_J22PQ&BKYS?&~VIxU-BsOAg1JTgE(?=OC_D9?O5A zZIr6VD-BE87;Kz%zrneSz9qGD+?==R^ZHyGZNu0y_juE9a1O6t&n#~9YR+0)+or#t z)VF;OYpM5Ix0d_4HnBB5hH;+0uf>?b-lohL+3Z>dprK7dk**tu$DG2H@_iSJJh<3zv1!1+;JRl@OPkj#XR>KTz5KOLx&n) zy^J4VT9=&m(7xzo?uTBTtMA`p+yZgIUwp%rw#V6n_ug&HeeA&pY%QG4e~G>5-rs-n!={Pfapp;ib=bqMC%%{a z;Y0J;x1DtM62+R~FEaP??1HP^!PHSAB>UE>`ZcOE9*VY)U>%_#ItFxGis)y0Gsc$n!!}jfy{%>V( z^&Mi2)qB=99`{UJ2}T@T3CIRxs>5;UPV=VTO|O@F&be(P&bs#? zz8ZJo?6B`^KDHYGC&zCb^8? z0Gq4-pmOS9f)z{u*~HkI}y3Zg6%m=hm^;^l-5D|EKLudN)0;v%lw4Sc5flY?7iVaURu8 zHfK^KC2?w!qBu#iESi!?$%45r86 z+TQTD{of6Dhp!;kmiD#oE&l;*wZ8zyg411BM*gOzH@erkjn7-mmG%W+y|-qK+dl8s zZ;4n!eE-K^U4`Doxn!R6<+%*$UGSRqygZ*q zz03cb`9EV^qsD)O_lvy>-}&8#@6#S2??(H3yg$f$8-9g8eT5%Ba(~rc;9U&t(XF>D z@t+&gy35T3-4IUldV95#C^hc&H- z%~I7t;CI5_*1oPoi}$O1_$$sv`%XPP+1q`34&H~O|FGw8>)pj%`3tRg#ac4B{M{9c z!S)zR2a~&GvG_ZAyYm^u-0;>OgLoSjpS9<uJ@Iu|T;%$^(A zEA4CMs!s-s!_()bpUW1XA$m7{@0PdHxzxH??|!p(@|OJ`7jMO0^Eb>=l-@0!Tb!l7 z6?hVu*FS=K2JXf2-S>~4y{Pvv|CitX7rLY7KmG6j ztIjzb)ieAb|C`SIc0I#mdfWI}c)7lB2lq?jZ{U3m^f*|r#`-nZRPbFN)|m0%(Y(>SD{{?$ z0C&N#W~+H94}ok{8(MhrG&yTxt`ke^n`mfh;QT(h%D!5$SUK}LJPvmgqkXAolgs{` zG%kL_9FFHuW2~o^jmHqyI&SConm1!}*ZQ{m$8CW}nTm{N37LJIUO5ykNAwU48@3s^-jIFPR(PSAH+qTeS`GdsEx{Wa(UM zV6!>CgS9W2Ywo6&mtKP#{f5%NSQGwQ`$qSAe=WN9O3|z}Z{s&e^Rli?-h#Dm`bXTw z8fs#Cyo%wj*jqYRx#loA)#ure7hl8P@YZ^l?6v1g_HOyRxJ%E0Z86v54R_@wSnHCv zTjoN$mIe-Y9ZU0)zhIYgjMeVr{WbWGXVxyTewSw)u(!rKT;5^x-+%A})gAobRlm!+ zTGj6&^4^D4zxy-P@4oUJYIIS*i~DOH2T$o4^Y7<>7U<4&-hqyPS2_H9yjPNE+Q?Tn z?*B1zf73eIcd_%mVBWb)&fZykJ&U=Mx6NELmSZ<-S^K!i4V^1}n{|u5e?FZX-y-@o z?A3U~Tr$>8JPnJ*;P5v*WpvJ(*19)L)xROulG9jM+%>m39_zDi#4xze!;!V-v3-VS zuK0>?H*s)ye~++Oi}^5@k*rO$-&>sBb2mCS5sVdo$9U=D?7NA>)VyS{b*}s6JH&gy zeCyqKzK-&M!P4kldb!lXj^VN6#`l%}MV=bB>doXSMDs@PVr=GutzdBW*A|E4Gth&8 z29DpbiP&RP9WS|y_3jU!0qhlXS=Wm-tI=<$=6$yI7`&He&XUQ^-P!kE+rGYmT$S&j z|M%V=uf1OGsbN0cEx#eY0&5yn#|w^1_c9`9<{ssWa^9J>J1gc(i2fkH6NSLTsImyDW;B`#?;UL*1EMAi(J-AA5%N)H+FIGcj;bo zm5uC0OW!e`Z}RjctbfVk4QJ07FTa8FV5s)o5T$+h>;*gJL9otDeRA75*EsAnFSu&& zA==ktvNUxN?e~szZKz`qhrw6#nBGIRBkz}Ntwukh7)w2C&$qcNja!^udRLk^y4OB$ z{9Wl=@z%_Z&(O?`=C#h%-8rRi#a{L`4ukDAQ2&a(WUltsFh<{+xA)i9z8XA+W-mS7 z*1f86pwE!{2C>%l4A#E%9L!$xxIKr(-Y}SarN))cE#8W`t$R=Hu~Fw*?@n*m92RTI zRkY2W=#|^v&%5O=nHvt1v#oupZ_Qw9+x8vgGhi-Sm-EYOK%W2Ez#26EcYoGxeINHB zeDDPBXMm37nTY@4=YMthpKw3J|NIXhsn&t-#{W0S=Y9s>#jd+?s*ZtwhwnlUKmFdC z?nQ@Ja3}6amk!1~3p{@|-*e;M8GT%P3udj~5iaJ2wS%`|uee*9l{s@ZTrC!d!R0TA zxutK}|Bqnp{LKwB$;C}8Rz~C2oH=b?r+@q%zqS6g2jSn24vxOIh7NnV-rvb1z6@(8 zd()4Hz_Hk?NZ!tIdkn4#K7+y3y3xDht~r|eU+dq>6^nD9`r<9QTRdL%Wujp$Dq1i`nuM+@^|Ai z#A_gX(dU0BceMAr@g0h<$GSJ(LVSfSdlz@3cd3o>Tl{zI^YZ_{Un_>bfw$s+^ymZd zdmlag26bQm{MvU8zsH@w|BSkY-{3y7U*de)k1sx``yj(ydbjuEe>eKe<|-M>ws%^STtJ%(Ms&av@)@$`DBZKZX^TxebL zm+V#CY2T%FsdtOH(z^B?QpdY$9mv-Wb2Bz`m$y4udrI$$yS;yJI{FD_Z8m1 z``{gVi;^{ByzhbWy$koE{@@P1!Oq$P)`+oQfp@4|>-L*JJl87?8}=rGrR3+*wbHp& zpIdX`Zu<(D2P1F)Tx!VLW1!bCd7HlZ8toefGrG}hn0j=>U+Q44`!o8z_-pQd8)Nb|YZ7NpJTBh4 zAJ2gtF3pSIAd}#?4u-SQzwsBu-DqCK9+%fZu7a~< zAo=V1hUTt)h~e{c-wW&LZ?FbKH3#r%seQ@cZ=<%C=h=A2&3DmwZ#rucI8Q&9|99d4 zPW;aR>0J7=dULI{?$W&EaPig=o&uQ5w|k;-Q>Sb0lC7nArGc$mt$PP|<0}mQHhYV= zT4RoCZ*7iOpV~Jp?s|sKW$u&3#awWb%zg3pa}~k6m8&_;o5A5TIqB~zKR6!7p2g;E z-rAVV^xj-?7rz&8!aOx=H`;e`xY--#%6llDinr`*Z0(!7*B4`#7B2o4lgU@ImW&OT zJvMv$ym9u_SaasOvz#qHVlntjjXS-D=b~*Fcf(ajv3RkTIqP1r7Wq|UhW!2vari5} z3-7?pjnCk?_S(SC_`HeDU20zZzsKn{h_}|dVlKuVdrz%v8cO??$Gi5^%HP#Jz17$K z4PdG7E}PtSU%Hn%S1r0XdYArg*ENK@;;=OE-s3fYb!Ir4cdvWF%y8HY24At3d`+!c zSZi%d{%*DIUh~T1EpH)xou6Qi>|JLm$XByiy0&z#G%pzINXCY<E2F&sZjYC|wXYENroOE8Z+Q(j zgRSNJlEG@xxAGXMb6f8&%`2^2-mdo6TKDP=crbYS4fb{8FJKOO)(kEdi?8h4*NygF z-Yz`f)H%dwSa&tZi)hVje;1wunM{vC`)$qJz0U1%)t1R)h}U4vORdYAhNXX_dl|`C zaujZZNp&t2+_le;4fqQyPv9kw65Vb zpRHf*E3jXl!|)KKeWP*3;98g5pD{|Sf}byeY3VN(i?hYzV(exOzsYxqi@)JeQdjxkzUHtkjheyyZ zs*m?tYy8O9*}rmo7;BE&ZOEZrz}yAK)owz6w6AfF<6499`LEq{c=%S-AwgGdIc&X~ zd&}ltTf7GO4MX=n45pvQJ=qW4dQR<|6*E4LH)35HzhVE};lZ!ocy;ZT8xId$rrm$b z4Vu4SYi>Aj>~`a}e>3u%cKvRA!{I*6-*@x%)n-4r>ks#0o-OM#zV{~Q@2SYK`W5fF z>AD(UH-3YED}U?w-^%y*oWpl$caO;a72A#19qvNAo9*1STF-HE={sJl{GB&md$?0; zICgW6`Pr_i@im7#aF^Nb;J)>5`3&+E%vb7I`3O@BlfQpP-sZPnDi)fj_85{=T=T7k zSN@K3ht&^TXJj9~g%~@SOI9yNqyLPUOMZr->0fSqf~#V4^7*z{yP5MEGFXjl9jpy= zlM8#p-?N!Zwvx$aZ2IKu<6$blllfS z_sXm_lbgY2?L%KRZyy44*{;Z5u=GJTuC4yr3=VG@Cv$h>#a{4E%rp1Mi^JlsnL7E(-y>JaQuFn?;^@pL zH+jo`n45gDcW_l27wq-}Q>ao^Y2duvaLw|EESTaO$*c7lk{l8({%wBjA3nT~IY;*0eu8^Eeu6%uavZOA0sS=G{m=f>7Zln5YxFtK zsPQxBtIxG)$upw;xZ3Rh`04Y?{}p1lUi(-0hIxMLe$73FF&pwfVteX58slhBGUxU~ z^pDz8-$c&s2Z*aZ@y)|~93!T2%(Y%~e#Q5=7WY$eo{>DJ?p=D9KCiro(!4kBd#_FD*)Dqgy+Ac?mxWF{%Efu_u9h`pdlik{w0o;yZ@km)*)WPI_56nJNEgF$6l-ch5HY$ zs@->Z6>DF;z=)PyBIl~T!W{aqWSofnEBv;;=ek$$ducC^K65XhN5dLL^__bOeKzJ_ zI)88R`r6XFb6PtX`!~q3%{A=zZ#J97+i-WWw-{WE z&F}pU#^P|eOUAMld*6Q+{A6GGaJC}nkQZMO|N7~{(=Zp@Gj~1rW9GSb#p-h%8W}1k zS3f)^gUL~k&06!;{U6nQ`1@C2>gv~AI6EVG%kdA{!r$2kGk*YPim8mNU;M>4KUj_I z^&0cGn2X;ad&yk3{a)LnW8(BNre*R6&ZI~PWf|q12nYy3<-o^fgEEadcTlW#cR<<`5d(B*OS8cKvxp0`Q zd|fPUzKX%jk*nk@xX0G{&Sj44GA|C-Hi@1Yp)?& zxju}Y95#E&UvrkRnd`p&hig`y+0wT18qDA6HITz+@hyJACyi!pxEr0DadXnFZC@dO z&v(E3-NU=@zI*uTPk(y&;DZkiZ@>Na;rZvEUw^N3E;(CGK5}t4Y!-KMru&2EijRn9 zWpQ(aKx-($w|yEDGUZ;R3RcEe$g$y)K4%nf6ycg^NzZssn4yXJ2=YpokS zJa|lQimAwj!^kb|n|`ecV<(H7wc%_c7+XC3F|_Mh>zcQ%gQNEUp&ja;(1Ndn*t2mhL@I&$qa1pMg4;HNE7n_uIr@j+HZynVYS-YmFPt zn<)Jo4J_`GxzW1j?pxHYgSBDs%8|QRqjlu8I9xHDt?$X$a5Q~!S1iRGH89t#b)zp% zley5irF+fZFqo10xAbiy*$Y;Rx#&ydCPw#?o#bg4x{J)@;9 z+b8Gl^bo+^J6qdI-XrcQ4vwU|-{A?_R@31Ft-INakAaw(i|? zc&#tylC8{zyYBn@aM!GD{!;sHJO}C7;xGDPa`V@EH=5U8!_c$gFe94uZgONV*z9ko z&V6{ZE`EdbEx8H(8vfc(C?8_5xY=vnOOJs$c@2ph{+{+6egMCLT9*u#<_%9Vo_@o7 zPd-%K4Wq4f$>(?t7r5Uxdmo}8V1YTxtN6QjRtpMiSU?d|d%-T@=y zJ+$8t?pn(-Z*QTZxO|50C12NiXjyWYIW+M#kqoWAIE-=TIbMCNnGAk|V}1*!lCNU0 z`rs}3O4im~bZ&bLVXygWkD>bDTR56Xc1}M*eev3So$DrV!&>H+$AEsA8s;`{&EOuJ z(c!G)B|5=TF<~aAuU;a`W_|m0IVlRJRensitRVR!*xl7GUK8m$s zZt<77YUE)Uy7e16zdQzN(&;&@ap%d-J%bm2xnAECkHn<+-h;SnrZQ&+?^%pII2+wd&1>Cj_GaIWS~nhV-ou>UgE%V= zZ*^|!8D=%(aWR*y#qZ18MHFv2exw;3ovTRplEX(W%tb7QlArVq;^AtX9O7hZSgZA# zv(HOrW?l2Mcsg{fmfyVK3*XVZ-0Bl{xiKNAIl_Z?P`CP5j}L@Eye6-d7`o?K?PztF3>*TJbi_^*ZU{ zp^K$=;WdQ0WNkCJb#Hu!sdLq5Z3FbKxQo3t^7Wl3(3ajMe}}(I7K6LdyxMz{t}PFt zG^`j5-mSeg_BHmpaM>(o&YCwI-9&O1e0($BLUEXD$kq72Vy)H{cQF?~fsA#Zxzf5v ztZn|1we2}r&&GcUH^bI7CX>NL=i>vDw`t96dc0h_VJ~tT7jM@dTJdwRe)gH=4WZ zGl#kw{9V8P^{)@V``zyj|N5{0x;RVb@_$bKZS)=9fB*fZd0i)LuVMMS)VpXueeUAn zXW!cC-1rUh9EzRQ7bnpVFPqW!Cd5tgHEYacGnctj9!5CpZ=|0WXE7HJOVe`P-a~Y7 zm}`w2Zx`AaY)st){fCWqE&aNwb)dEd^A?Zw&EPKP$l&N!u1$X*gqRvVlRs~4B++vwV@77lN%bzgzcyJ{KO$M0|U*)(o{H}3$g zGZgR^Si>;+_NPDnX~VNQW}l7Pa`Nrta5wt)R1A|D`8U1x+H2Ce|MqYHw*Dp)*ZsqQoS+ogFq$KMr$!P@$Uj17Bx@6G-L*}Aka`erWo-lpe}J{dY1 znJTV!bd5teJh-iWx#n-QZ`dncTbyNXGB|#&@|>$?e;3{azXMy-!rP^L7k{aH&1Cb| zEOuQ3SUc()j`eS`7;ES^O&PovKOws9=>%4;xd!`0;N^V(BbbNE*M(!8m-F+R^l6J*kUSKyJ0l*X~k>m*$s0sZx)-c+Ec?C$FsfPsduN(z&C*C?e6(D zIZLi(oS596Z&%A+a!`B)TaV(HaDSHXMfEyO`{6?KMREBI4U{cJ`;I>)HnIpNXgSO=`>Xz1a&L3tzXH z&2ekqjSms_io5m@%wYD-V|fl?FV

w)V9r!SOfOnKr*wF+B$B-sSOvxzxJrt{gCV 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⋐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 F{{d_4lH33Q literal 0 HcmV?d00001 diff --git a/plugins/pad/PADwin/Src/interface.c b/plugins/pad/PADwin/Src/interface.c new file mode 100644 index 0000000000..d011ef3313 --- /dev/null +++ b/plugins/pad/PADwin/Src/interface.c @@ -0,0 +1,483 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *hbox1; + GSList *hbox1_group = NULL; + GtkWidget *radiobutton1; + GtkWidget *radiobutton2; + GtkWidget *fixed2; + GtkWidget *Key6; + GtkWidget *Key2; + GtkWidget *Key9; + GtkWidget *Key1; + GtkWidget *Key10; + GtkWidget *Key3; + GtkWidget *Key4; + GtkWidget *Key7; + GtkWidget *Key5; + GtkWidget *Key0; + GtkWidget *Key12; + GtkWidget *Key15; + GtkWidget *Key13; + GtkWidget *Key14; + GtkWidget *Key11; + GtkWidget *Key8; + GtkWidget *Key16; + GtkWidget *Key19; + GtkWidget *Key21; + GtkWidget *Key17; + GtkWidget *Key18; + GtkWidget *Key22; + GtkWidget *Key20; + GtkWidget *Key23; + GtkWidget *vbox3; + GtkWidget *GtkCheckButton_Analog; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "PADconfig"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0); + + radiobutton1 = gtk_radio_button_new_with_label (hbox1_group, "Pad1"); + hbox1_group = gtk_radio_button_group (GTK_RADIO_BUTTON (radiobutton1)); + gtk_widget_ref (radiobutton1); + gtk_object_set_data_full (GTK_OBJECT (Config), "radiobutton1", radiobutton1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (radiobutton1); + gtk_box_pack_start (GTK_BOX (hbox1), radiobutton1, TRUE, FALSE, 0); + + radiobutton2 = gtk_radio_button_new_with_label (hbox1_group, "Pad2"); + hbox1_group = gtk_radio_button_group (GTK_RADIO_BUTTON (radiobutton2)); + gtk_widget_ref (radiobutton2); + gtk_object_set_data_full (GTK_OBJECT (Config), "radiobutton2", radiobutton2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (radiobutton2); + gtk_box_pack_start (GTK_BOX (hbox1), radiobutton2, TRUE, FALSE, 0); + + fixed2 = gtk_fixed_new (); + gtk_widget_ref (fixed2); + gtk_object_set_data_full (GTK_OBJECT (Config), "fixed2", fixed2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixed2); + gtk_box_pack_start (GTK_BOX (vbox1), fixed2, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (fixed2), 5); + + Key6 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key6); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key6", Key6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key6); + gtk_fixed_put (GTK_FIXED (fixed2), Key6, 48, 136); + gtk_widget_set_uposition (Key6, 48, 136); + gtk_widget_set_usize (Key6, 65, 22); + + Key2 = gtk_button_new_with_label ("button7"); + gtk_widget_ref (Key2); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key2", Key2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key2); + gtk_fixed_put (GTK_FIXED (fixed2), Key2, 48, 40); + gtk_widget_set_uposition (Key2, 48, 40); + gtk_widget_set_usize (Key2, 65, 22); + + Key9 = gtk_button_new_with_label ("button8"); + gtk_widget_ref (Key9); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key9", Key9, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key9); + gtk_fixed_put (GTK_FIXED (fixed2), Key9, 88, 8); + gtk_widget_set_uposition (Key9, 88, 8); + gtk_widget_set_usize (Key9, 65, 22); + + Key1 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key1); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key1", Key1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key1); + gtk_fixed_put (GTK_FIXED (fixed2), Key1, 168, 8); + gtk_widget_set_uposition (Key1, 168, 8); + gtk_widget_set_usize (Key1, 65, 22); + + Key10 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key10); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key10", Key10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key10); + gtk_fixed_put (GTK_FIXED (fixed2), Key10, 248, 8); + gtk_widget_set_uposition (Key10, 248, 8); + gtk_widget_set_usize (Key10, 65, 22); + + Key3 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key3); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key3", Key3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key3); + gtk_fixed_put (GTK_FIXED (fixed2), Key3, 208, 40); + gtk_widget_set_uposition (Key3, 208, 40); + gtk_widget_set_usize (Key3, 65, 22); + + Key4 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key4); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key4", Key4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key4); + gtk_fixed_put (GTK_FIXED (fixed2), Key4, 48, 72); + gtk_widget_set_uposition (Key4, 48, 72); + gtk_widget_set_usize (Key4, 65, 22); + + Key7 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key7); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key7", Key7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key7); + gtk_fixed_put (GTK_FIXED (fixed2), Key7, 8, 104); + gtk_widget_set_uposition (Key7, 8, 104); + gtk_widget_set_usize (Key7, 65, 22); + + Key5 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key5); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key5", Key5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key5); + gtk_fixed_put (GTK_FIXED (fixed2), Key5, 88, 104); + gtk_widget_set_uposition (Key5, 88, 104); + gtk_widget_set_usize (Key5, 65, 22); + + Key0 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key0); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key0", Key0, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key0); + gtk_fixed_put (GTK_FIXED (fixed2), Key0, 8, 8); + gtk_widget_set_uposition (Key0, 8, 8); + gtk_widget_set_usize (Key0, 65, 22); + + Key12 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key12); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key12", Key12, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key12); + gtk_fixed_put (GTK_FIXED (fixed2), Key12, 208, 72); + gtk_widget_set_uposition (Key12, 208, 72); + gtk_widget_set_usize (Key12, 65, 22); + + Key15 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key15); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key15", Key15, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key15); + gtk_fixed_put (GTK_FIXED (fixed2), Key15, 168, 104); + gtk_widget_set_uposition (Key15, 168, 104); + gtk_widget_set_usize (Key15, 65, 22); + + Key13 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key13); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key13", Key13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key13); + gtk_fixed_put (GTK_FIXED (fixed2), Key13, 248, 104); + gtk_widget_set_uposition (Key13, 248, 104); + gtk_widget_set_usize (Key13, 65, 22); + + Key14 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key14); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key14", Key14, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key14); + gtk_fixed_put (GTK_FIXED (fixed2), Key14, 208, 136); + gtk_widget_set_uposition (Key14, 208, 136); + gtk_widget_set_usize (Key14, 65, 22); + + Key11 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key11); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key11", Key11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key11); + gtk_fixed_put (GTK_FIXED (fixed2), Key11, 80, 168); + gtk_widget_set_uposition (Key11, 80, 168); + gtk_widget_set_usize (Key11, 65, 22); + + Key8 = gtk_button_new_with_label ("button5"); + gtk_widget_ref (Key8); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key8", Key8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key8); + gtk_fixed_put (GTK_FIXED (fixed2), Key8, 176, 168); + gtk_widget_set_uposition (Key8, 176, 168); + gtk_widget_set_usize (Key8, 65, 22); + + Key16 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key16); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key16", Key16, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key16); + gtk_fixed_put (GTK_FIXED (fixed2), Key16, 360, 8); + gtk_widget_set_uposition (Key16, 360, 8); + gtk_widget_set_usize (Key16, 65, 22); + + Key19 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key19); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key19", Key19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key19); + gtk_fixed_put (GTK_FIXED (fixed2), Key19, 320, 40); + gtk_widget_set_uposition (Key19, 320, 40); + gtk_widget_set_usize (Key19, 65, 22); + + Key21 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key21); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key21", Key21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key21); + gtk_fixed_put (GTK_FIXED (fixed2), Key21, 400, 136); + gtk_widget_set_uposition (Key21, 400, 136); + gtk_widget_set_usize (Key21, 65, 22); + + Key17 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key17); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key17", Key17, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key17); + gtk_fixed_put (GTK_FIXED (fixed2), Key17, 400, 40); + gtk_widget_set_uposition (Key17, 400, 40); + gtk_widget_set_usize (Key17, 65, 22); + + Key18 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key18); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key18", Key18, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key18); + gtk_fixed_put (GTK_FIXED (fixed2), Key18, 360, 72); + gtk_widget_set_uposition (Key18, 360, 72); + gtk_widget_set_usize (Key18, 65, 22); + + Key22 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key22); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key22", Key22, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key22); + gtk_fixed_put (GTK_FIXED (fixed2), Key22, 360, 168); + gtk_widget_set_uposition (Key22, 360, 168); + gtk_widget_set_usize (Key22, 65, 22); + + Key20 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key20); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key20", Key20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key20); + gtk_fixed_put (GTK_FIXED (fixed2), Key20, 360, 104); + gtk_widget_set_uposition (Key20, 360, 104); + gtk_widget_set_usize (Key20, 65, 22); + + Key23 = gtk_button_new_with_label ("button4"); + gtk_widget_ref (Key23); + gtk_object_set_data_full (GTK_OBJECT (Config), "Key23", Key23, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (Key23); + gtk_fixed_put (GTK_FIXED (fixed2), Key23, 320, 136); + gtk_widget_set_uposition (Key23, 320, 136); + gtk_widget_set_usize (Key23, 65, 22); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox3); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox3", vbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox3); + gtk_box_pack_start (GTK_BOX (vbox1), vbox3, TRUE, TRUE, 0); + + GtkCheckButton_Analog = gtk_check_button_new_with_label ("Analog Support"); + gtk_widget_ref (GtkCheckButton_Analog); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCheckButton_Analog", GtkCheckButton_Analog, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCheckButton_Analog); + gtk_box_pack_start (GTK_BOX (vbox3), GtkCheckButton_Analog, FALSE, FALSE, 0); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (radiobutton1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Pad1), + NULL); + gtk_signal_connect (GTK_OBJECT (radiobutton2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Pad2), + NULL); + gtk_signal_connect (GTK_OBJECT (Key6), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key9), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key10), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key3), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key4), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key7), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key5), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key0), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key12), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key15), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key13), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key14), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key11), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (Key8), "clicked", + GTK_SIGNAL_FUNC (OnConf_Key), + NULL); + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label1; + GtkWidget *label2; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "PADabout"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + gtk_window_set_modal (GTK_WINDOW (About), TRUE); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label1 = gtk_label_new ("PADwin Plugin"); + gtk_widget_ref (label1); + gtk_object_set_data_full (GTK_OBJECT (About), "label1", label1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label1); + gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, FALSE, 0); + + label2 = gtk_label_new ("Authors:\nlinuzappz \nflorin sasu "); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/pad/PADwin/Src/interface.h b/plugins/pad/PADwin/Src/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/pad/PADwin/Src/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/pad/PADwin/Src/mingw/Makefile.win b/plugins/pad/PADwin/Src/mingw/Makefile.win new file mode 100644 index 0000000000..8b5d68c0f2 --- /dev/null +++ b/plugins/pad/PADwin/Src/mingw/Makefile.win @@ -0,0 +1,43 @@ +# Project: PADwinKeyb +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//PADwinKeyb_private.res +OBJ = Obj//Win32.o Obj//Conf.o Obj//PAD.o $(RES) +LINKOBJ = Obj//Win32.o Obj//Conf.o Obj//PAD.o $(RES) +LIBS = -L"C:/Develop/Dev-Cpp/lib" --def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +INCS = -I"C:/Develop/Dev-Cpp/include" -I"../" +CXXINCS = -I"C:/Develop/Dev-Cpp/include" -I"../" +BIN = PADwin.dll +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32__ +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before PADwin.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libPADwin.def +STATICLIB=libPADwin.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Obj//Win32.o: ../Win32.c + $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) + +Obj//Conf.o: ../Conf.c + $(CC) -c ../Conf.c -o Obj//Conf.o $(CFLAGS) + +Obj//PAD.o: ../PAD.c + $(CC) -c ../PAD.c -o Obj//PAD.o $(CFLAGS) + +Obj//PADwinKeyb_private.res: PADwinKeyb_private.rc ../PADwnKeyb.rc + $(WINDRES) -i PADwinKeyb_private.rc --input-format=rc -o Obj//PADwinKeyb_private.res -O coff --include-dir ../ --include-dir ../mingw diff --git a/plugins/pad/PADwin/Src/mingw/PADwinKeyb.dev b/plugins/pad/PADwin/Src/mingw/PADwinKeyb.dev new file mode 100644 index 0000000000..9aa2d71272 --- /dev/null +++ b/plugins/pad/PADwin/Src/mingw/PADwinKeyb.dev @@ -0,0 +1,156 @@ +[Project] +FileName=PADwinKeyb.dev +Name=PADwinKeyb +UnitCount=11 +Type=3 +Ver=1 +ObjFiles= +Includes=../ +Libs= +PrivateResource=PADwinKeyb_private.rc +ResourceIncludes=../;..\mingw +MakeIncludes= +Compiler=-Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32___@@__@@_ +CppCompiler=_@@_ +Linker=--def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32_@@_ _@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput=Obj/ +OverrideOutput=1 +OverrideOutputName=PADwin.dll +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\Win32.c +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\Conf.c +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\PAD.c +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\PAD.h +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\PADwnKeyb.rc +Folder=PADwinKeyb +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\PS2Edefs.h +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\PS2Etypes.h +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\resource.h +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit9] +FileName=..\ps2pad.bmp +Folder=PADwinKeyb +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\plugin.def +Folder=PADwinKeyb +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=afxres.h +CompileCpp=0 +Folder=PADwinKeyb +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/plugins/pad/PADwin/Src/mingw/PADwinKeyb.layout b/plugins/pad/PADwin/Src/mingw/PADwinKeyb.layout new file mode 100644 index 0000000000..44f2cb5155 --- /dev/null +++ b/plugins/pad/PADwin/Src/mingw/PADwinKeyb.layout @@ -0,0 +1,56 @@ +[Editor_10] +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editor_0] +CursorCol=1 +CursorRow=20 +TopLine=20 +LeftChar=1 +Open=0 +Top=0 +[Editor_2] +CursorCol=1 +CursorRow=1 +TopLine=136 +LeftChar=1 +Open=0 +Top=0 +[Editors] +Order= +Focused=10 +[Editor_1] +Open=0 +Top=0 +[Editor_3] +Open=0 +Top=0 +[Editor_4] +Open=0 +Top=0 +CursorCol=1 +CursorRow=10 +TopLine=1 +LeftChar=1 +[Editor_5] +Open=0 +Top=0 +[Editor_6] +Open=0 +Top=0 +[Editor_7] +Open=0 +Top=0 +[Editor_8] +Open=0 +Top=0 +[Editor_9] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 diff --git a/plugins/pad/PADwin/Src/mingw/afxres.h b/plugins/pad/PADwin/Src/mingw/afxres.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/pad/PADwin/Src/mingw/afxres.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/pad/PADwin/Src/plugin.def b/plugins/pad/PADwin/Src/plugin.def new file mode 100644 index 0000000000..c7c47c8c82 --- /dev/null +++ b/plugins/pad/PADwin/Src/plugin.def @@ -0,0 +1,17 @@ +EXPORTS + PADabout = PADabout@0 @6 + PADclose = PADclose@0 @7 + PADconfigure = PADconfigure@0 @8 + PADinit = PADinit@4 @9 + PADkeyEvent = PADkeyEvent@0 @10 + PADopen = PADopen@4 @11 + PADpoll = PADpoll@4 @12 + PADquery = PADquery@0 @13 + PADsetMode @14 + PADshutdown = PADshutdown@0 @15 + PADstartPoll = PADstartPoll@4 @16 + PADtest = PADtest@0 @17 + PADwndProc = PADwndProc@16 @18 + PS2EgetLibName = PS2EgetLibName@0 @20 + PS2EgetLibType = PS2EgetLibType@0 @21 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @22 diff --git a/plugins/pad/PADwin/Src/ps2pad.bmp b/plugins/pad/PADwin/Src/ps2pad.bmp new file mode 100644 index 0000000000000000000000000000000000000000..26d304da4e26ef55223072c46fb5941dd00ada3e GIT binary patch literal 320918 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 z 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%0Drhe$sQAS1>M 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 Xzy>5RhaEOBNpnM-lYkXU;Gh0K3eU$E literal 0 HcmV?d00001 diff --git a/plugins/pad/PADwin/Src/resource.h b/plugins/pad/PADwin/Src/resource.h new file mode 100644 index 0000000000..0ea747c6c4 --- /dev/null +++ b/plugins/pad/PADwin/Src/resource.h @@ -0,0 +1,70 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PadDialog.rc +// +#define IDD_DIALOG1 110 +#define IDB_BITMAP1 112 +#define IDC_EL3 1012 +#define IDC_L2 1013 +#define IDC_ER3 1014 +#define IDC_R2 1015 +#define IDC_ESTART 1016 +#define IDC_L1 1017 +#define IDC_ESELECT 1018 +#define IDC_R1 1019 +#define IDC_ECROSS 1020 +#define IDC_TRI 1021 +#define IDC_ESQUARE 1022 +#define IDC_CIRCLE 1023 +#define IDC_ECIRCLE 1024 +#define IDC2_CROSS 1025 +#define IDC_ETRIANGLE 1026 +#define IDC_SQUARE 1027 +#define IDC_ER2 1028 +#define IDC_SELECT 1029 +#define IDC_ER1 1030 +#define IDC_L3 1031 +#define IDC_EDOWN 1032 +#define IDC_R3 1033 +#define IDC_ERIGHT 1034 +#define IDC_START 1035 +#define IDC_ELEFT 1036 +#define IDC_UP 1037 +#define IDC_EUP 1038 +#define IDC_RIGHT 1039 +#define IDC_EL2 1040 +#define IDC_DOWN 1041 +#define IDC_EL1 1042 +#define IDC_LEFT 1043 +#define IDC_TABC 1044 +#define IDC_LAX 1045 +#define IDC_LAY 1046 +#define IDC_RAX 1047 +#define IDC_RAY 1048 +#define IDC_SCROSS 1049 +#define IDC_CHECK1 1050 +#define IDC_LOG 1050 +#define IDC_SCIRCLE 1051 +#define IDC_SSQUARE 1052 +#define IDC_STRIANGLE 1053 +#define IDC_SL3 1054 +#define IDC_SUP 1055 +#define IDC_SDOWN 1056 +#define IDC_SLEFT 1057 +#define IDC_SRIGHT 1058 +#define IDC_SR3 1059 +#define IDC_SL1 1060 +#define IDC_SL2 1061 +#define IDC_SR1 1062 +#define IDC_SR2 1063 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1051 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/pad/PADwin/Src/support.c b/plugins/pad/PADwin/Src/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/pad/PADwin/Src/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/pad/PADwin/Src/support.h b/plugins/pad/PADwin/Src/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/pad/PADwin/Src/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/pad/PADwin/build.sh b/plugins/pad/PADwin/build.sh new file mode 100644 index 0000000000..bf9a915f33 --- /dev/null +++ b/plugins/pad/PADwin/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo --------------- +echo Building PADwin +echo --------------- + +curdir=`pwd` + +cd ${curdir}/Src +make $@ + +if [ -s libPADwin.so ] +then +cp libPADwin.so ${PCSX2PLUGINS} +fi diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX.cpp b/plugins/pad/SSSPSXPAD/PadSSSPSX.cpp new file mode 100644 index 0000000000..9a26c3d398 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX.cpp @@ -0,0 +1,1041 @@ +#define WINVER 0x0500 +#define _WIN32_WINNT WINVER +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include +#include +#include + +#include "PadSSSPSX.h" + +static const char* LibraryName = "SSSPSX PAD Plugin Pressure Mod"; +static const unsigned char version = 0x0002; +static const unsigned char revision = 1; +static const unsigned char build = 6; + +HMODULE hInstance; +HWND hTargetWnd; + +static struct +{ + Config config; + int devcnt; + LPDIRECTINPUT8 pDInput; + LPDIRECTINPUTDEVICE8 pDKeyboard; + LPDIRECTINPUTDEVICE8 pDDevice[4]; + LPDIRECTINPUTEFFECT pDEffect[4][2]; /* for Small & Big Motor */ + DIJOYSTATE JoyState[4]; + u16 padStat[2]; + int padID[2]; + int padMode1[2]; + int padMode2[2]; + int padModeE[2]; + int padModeC[2]; + int padModeF[2]; + int padVib0[2]; + int padVib1[2]; + int padVibF[2][4]; + int padVibC[2]; + DWORD padPress[2][16]; + int curPad; + int curByte; + int curCmd; + int cmdLen; +} global; + +static BOOL CALLBACK EnumAxesCallback (LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + LPDIRECTINPUTDEVICE8 pDDevice = (LPDIRECTINPUTDEVICE8)pvRef; + DIPROPRANGE diprg; + diprg.diph.dwSize = sizeof (diprg); + diprg.diph.dwHeaderSize = sizeof (diprg.diph); + diprg.diph.dwObj = lpddoi->dwType; + diprg.diph.dwHow = DIPH_BYID; + diprg.lMin = -128; + diprg.lMax = 127; + pDDevice->SetProperty (DIPROP_RANGE, &diprg.diph); + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK EnumJoysticksCallback (const DIDEVICEINSTANCE* instance, VOID* pContext) +{ + const int devno = global.devcnt; + if (devno >= 4) + return DIENUM_STOP; + HRESULT result = global.pDInput->CreateDevice (instance->guidInstance, &global.pDDevice[devno], NULL); + if (FAILED (result)) + return DIENUM_CONTINUE; + global.devcnt++; + return DIENUM_CONTINUE; +} + +static bool ReleaseDirectInput (void) +{ + int index = 4; + while (index--) + { + if (global.pDEffect[index][0]) + { + global.pDEffect[index][0]->Unload(); + global.pDEffect[index][0]->Release(); + global.pDEffect[index][0] = NULL; + } + if (global.pDEffect[index][1]) + { + global.pDEffect[index][1]->Unload(); + global.pDEffect[index][1]->Release(); + global.pDEffect[index][1] = NULL; + } + if (global.pDDevice[index]) + { + global.pDDevice[index]->Unacquire(); + global.pDDevice[index]->Release(); + global.pDDevice[index] = NULL; + } + } + if (global.pDKeyboard) + { + global.pDKeyboard->Unacquire(); + global.pDKeyboard->Release(); + global.pDKeyboard = NULL; + } + if (global.pDInput) + { + global.pDInput->Release(); + global.pDInput = NULL; + } + global.devcnt = 0; + return FALSE; +} + +static bool InitDirectInput (void) +{ + if (global.pDInput) + return TRUE; + HRESULT result = DirectInput8Create (hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&global.pDInput, NULL); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDInput->CreateDevice (GUID_SysKeyboard, &global.pDKeyboard, NULL); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDInput->EnumDevices (DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDKeyboard->SetDataFormat (&c_dfDIKeyboard); + if (FAILED (result)) + return ReleaseDirectInput(); + if (hTargetWnd) + { + global.pDKeyboard->Unacquire(); + result = global.pDKeyboard->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); + if (FAILED (result)) + return ReleaseDirectInput(); + } + int index = global.devcnt; + while (index--) + { + const LPDIRECTINPUTDEVICE8 pDDevice = global.pDDevice[index]; + result = pDDevice->SetDataFormat (&c_dfDIJoystick); + if (FAILED (result)) + return ReleaseDirectInput(); + if (hTargetWnd) + { + pDDevice->Unacquire(); + result = pDDevice->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); + if (FAILED (result)) + return ReleaseDirectInput(); + } + struct + { + DIPROPDWORD dipdw; + DWORD rgdwAxes[2]; + LONG rglDirection[2]; + DIPERIODIC per; + DICONSTANTFORCE cf; + DIEFFECT eff; + } local; + memset (&local, 0, sizeof (local)); + local.dipdw.diph.dwSize = sizeof (DIPROPDWORD); + local.dipdw.diph.dwHeaderSize = sizeof (DIPROPHEADER); + local.dipdw.diph.dwHow = DIPH_DEVICE; + local.dipdw.dwData = DIPROPAUTOCENTER_OFF; + pDDevice->SetProperty (DIPROP_AUTOCENTER, &local.dipdw.diph); + result = pDDevice->EnumObjects (EnumAxesCallback, pDDevice, DIDFT_AXIS); + if (FAILED (result)) + return ReleaseDirectInput(); + + local.rgdwAxes[0] = DIJOFS_X; + local.rgdwAxes[1] = DIJOFS_Y; + local.eff.dwSize = sizeof (DIEFFECT); + local.eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + local.eff.dwDuration = INFINITE; + local.eff.dwGain = DI_FFNOMINALMAX; + local.eff.dwTriggerButton = DIEB_NOTRIGGER; + local.eff.cAxes = 2; + local.eff.rgdwAxes = local.rgdwAxes; + local.eff.rglDirection = local.rglDirection; + + /* Small Motor */ + local.eff.cbTypeSpecificParams = sizeof (DIPERIODIC); + local.eff.lpvTypeSpecificParams = &local.per; + result = pDDevice->CreateEffect (GUID_Square , &local.eff, &global.pDEffect[index][0], NULL); + if (FAILED (result)) + global.pDEffect[index][0] = NULL; + + /* Big Motor */ + local.eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); + local.eff.lpvTypeSpecificParams = &local.cf; + result = pDDevice->CreateEffect (GUID_ConstantForce , &local.eff, &global.pDEffect[index][1], NULL); + if (FAILED (result)) + global.pDEffect[index][1] = NULL; + } + return TRUE; +} + +static bool AcquireDevice (LPDIRECTINPUTDEVICE8 lpDirectInputDevice) +{ + if (FAILED (lpDirectInputDevice->Acquire())) + { + HRESULT result = lpDirectInputDevice->Acquire(); + if (result == DIERR_OTHERAPPHASPRIO) + return FALSE; + if (FAILED (result)) + return ReleaseDirectInput(); + } + return TRUE; +} + +/* Small Motor */ +static bool SetDeviceForceS (int pad, DWORD force) +{ + InitDirectInput(); + if (global.pDEffect[pad][0]) + { + if ( force == 0) { + if (FAILED (global.pDEffect[pad][0]->Stop())) { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][0]->Stop())) + return ReleaseDirectInput(); + } + return TRUE; + } + LONG rglDirection[2] = { 0, 0 }; + DIPERIODIC per; + rglDirection[0] = force; + rglDirection[1] = force; + per.dwMagnitude = force; + per.dwPeriod = (DWORD) (0.01 * DI_SECONDS); + per.lOffset = 0; + per.dwPhase = 0; + DIEFFECT eff; + eff.dwSize = sizeof (DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.cAxes = 2; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof (DIPERIODIC); + eff.lpvTypeSpecificParams = &per; + if (FAILED (global.pDEffect[pad][0]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) + return ReleaseDirectInput(); + if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) + { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) + return ReleaseDirectInput(); + } + } + return TRUE; +} + +/* Big Motor */ +static bool SetDeviceForceB (int pad, DWORD force) +{ + InitDirectInput(); + if (global.pDEffect[pad][1]) + { + if ( force == 0) { + if (FAILED (global.pDEffect[pad][1]->Stop())) { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][1]->Stop())) + return ReleaseDirectInput(); + } + return TRUE; + } + LONG rglDirection[2] = { 0, 0 }; + DICONSTANTFORCE cf; + rglDirection[0] = force; + rglDirection[1] = force; + cf.lMagnitude = force; + DIEFFECT eff; + eff.dwSize = sizeof (DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.cAxes = 2; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &cf; + if (FAILED (global.pDEffect[pad][1]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) + return ReleaseDirectInput(); + if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) + { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) + return ReleaseDirectInput(); + } + } + return TRUE; +} + +static bool GetJoyState (const int devno) +{ + InitDirectInput(); + if (global.pDDevice[devno] == NULL) + return FALSE; + global.pDDevice[devno]->Poll(); + if (FAILED (global.pDDevice[devno]->GetDeviceState (sizeof (DIJOYSTATE), &global.JoyState[devno]))) + { + AcquireDevice (global.pDDevice[devno]); + return FALSE; + } + return TRUE; +} + +static bool GetKeyState (u8* keyboard) +{ + InitDirectInput(); + if (global.pDKeyboard == NULL) + return FALSE; + global.pDKeyboard->Poll(); + if (FAILED (global.pDKeyboard->GetDeviceState (256, keyboard))) + { + AcquireDevice (global.pDKeyboard); + return FALSE; + } + return TRUE; +} + +static void MakeConfigFileName (char* fname) +{ + GetModuleFileName (hInstance, fname, 256); + strcpy (fname + strlen (fname) - 3, "cfg"); +} + +static void SaveConfig (void) +{ + char fname[256]; + MakeConfigFileName (fname); + HANDLE hFile = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD number_of_bytes; + WriteFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); + CloseHandle (hFile); + } +} + +static void LoadConfig (void) +{ + char fname[256]; + MakeConfigFileName (fname); + HANDLE hFile = CreateFile (fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD number_of_bytes; + ReadFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); + CloseHandle (hFile); + } + global.padVibC[0] = global.padVibC[1] = -1; + for (int cnt = 21; cnt--; ) + { + const int key0 = global.config.keys[0][cnt]; + if (key0 >= 0x1000) + global.padVibC[0] = (key0 & 0xfff) / 0x100; + const int key1 = global.config.keys[1][cnt]; + if (key1 >= 0x1000) + global.padVibC[1] = (key1 & 0xfff) / 0x100; + } +} + +static void PADsetMode (const int pad, const int mode) +{ + static const u8 padID[] = { 0x41, 0x73, 0x41, 0x79 }; + global.padMode1[pad] = mode; + global.padVib0[pad] = 0; + global.padVib1[pad] = 0; + global.padVibF[pad][0] = 0; + global.padVibF[pad][1] = 0; + global.padID[pad] = padID[global.padMode2[pad] * 2 + mode]; +} + +static void KeyPress (const int pad, const int index, const bool press) +{ + if (index < 16) + { + if (press) + { + global.padStat[pad] &= ~(1 << index); + if (global.padPress[pad][index] == 0) + global.padPress[pad][index] = GetTickCount(); + } + else + { + global.padStat[pad] |= 1 << index; + global.padPress[pad][index] = 0; + } + } + else + { + static bool prev[2] = { FALSE, FALSE }; + if ((prev[pad] != press) && (global.padModeF[pad] == 0)) + { + prev[pad] = press; + if (press) PADsetMode (pad, !global.padMode1[pad]); + } + } +} + +static void UpdateState (const int pad) +{ + static int flag_keyboard; + static int flag_joypad[4]; + if (pad == 0) + { + flag_keyboard = 0; + flag_joypad[0] = 0; + flag_joypad[1] = 0; + flag_joypad[2] = 0; + flag_joypad[3] = 0; + } + static u8 keystate[256]; + for (int index = 17; index--; ) + { + const int key = global.config.keys[pad][index]; + if (key == 0) + continue; + else if (key < 0x100) + { + if (flag_keyboard == FALSE) + { + flag_keyboard = TRUE; + if (GetKeyState (keystate) == FALSE) + return; + } + KeyPress (pad, index, keystate[key] & 0x80); + } + else + { + const int joypad = ((key & 0xfff) / 100); + if (flag_joypad[joypad] == FALSE) + { + flag_joypad[joypad] = TRUE; + if (GetJoyState (joypad) == FALSE) + return; + } + if (key < 0x2000) + { + KeyPress (pad, index, global.JoyState[joypad].rgbButtons[key & 0xff]); + } + else if (key < 0x3000) + { + const int state = ((int*)&global.JoyState[joypad].lX)[(key & 0xff) /2]; + switch (key & 1) + { + case 0: KeyPress (pad, index, state < -64); break; + case 1: KeyPress (pad, index, state >= 64); break; + } + } + else + { + const u32 state = global.JoyState[joypad].rgdwPOV[(key & 0xff) /4]; + switch (key & 3) + { + case 0: KeyPress (pad, index, (state >= 0 && state <= 4500) || (state >= 31500 && state <= 36000)); break; + case 1: KeyPress (pad, index, state >= 4500 && state <= 13500); break; + case 2: KeyPress (pad, index, state >= 13500 && state <= 22500); break; + case 3: KeyPress (pad, index, state >= 22500 && state <= 31500); break; + } + } + } + } + + /* Small Motor */ + const int vib0 = global.padVibF[pad][0] ? 10000 : 0; + if ((global.padVibF[pad][2] != vib0) && (global.padVibC[pad] >= 0)) + { + global.padVibF[pad][2] = vib0; + SetDeviceForceS (global.padVibC[pad], vib0); + } + /* Big Motor */ + const int vib1 = global.padVibF[pad][1] ? 500 + 37*global.padVibF[pad][1] : 0; + if ((global.padVibF[pad][3] != vib1) && (global.padVibC[pad] >= 0)) + { + global.padVibF[pad][3] = vib1; + SetDeviceForceB (global.padVibC[pad], vib1); + } +} + +static void set_label (const HWND hWnd, const int pad, const int index) +{ + const int key = global.config.keys[pad][index]; + char buff[64]; + if (key < 0x100) + { + if (key == 0) + strcpy (buff, "NONE"); + else if (GetKeyNameText (key << 16, buff, sizeof (buff)) == 0) + wsprintf (buff, "Keyboard 0x%02X", key); + } + else if (key >= 0x1000 && key < 0x2000) + { + wsprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); + } + else if (key >= 0x2000 && key < 0x3000) + { + static const char name[][4] = { "MIN", "MAX" }; + const int axis = (key & 0xff); + wsprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); + if (index >= 17 && index <= 20) + buff[strlen (buff) -4] = '\0'; + } + else if (key >= 0x3000 && key < 0x4000) + { + static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; + const int pov = (key & 0xff); + wsprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); + } + Button_SetText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); +} + +static BOOL CALLBACK ConfigureDlgProc (const HWND hWnd, const UINT msg, const WPARAM wParam, const LPARAM lParam) +{ + static BYTE keymaps[2][256]; + static DWORD countdown; + static int disabled; + static HWND hTabWnd; + static int pad; + int cnt1; + int cnt2; + int key; + switch (msg) + { + case WM_INITDIALOG: + hTargetWnd = hWnd; + pad = disabled = 0; + LoadConfig(); + for (cnt1 = 21; cnt1--; ) + set_label (hWnd, pad, cnt1); + hTabWnd = GetDlgItem (hWnd, IDC_TABC); + TCITEM tcI; + tcI.mask = TCIF_TEXT; + tcI.pszText = "PAD1"; + TabCtrl_InsertItem (hTabWnd, 0, &tcI); + tcI.mask = TCIF_TEXT; + tcI.pszText = "PAD2"; + TabCtrl_InsertItem (hTabWnd, 1, &tcI); + SetTimer (hWnd, 0x80, 50, NULL); + return TRUE; + case WM_DESTROY: + break; + case WM_NOTIFY: + if (wParam == IDC_TABC) + { + if (disabled) + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + pad = TabCtrl_GetCurSel (hTabWnd); + for (cnt1 = 21; cnt1--; ) + set_label (hWnd, pad, cnt1); + } + break; + case WM_COMMAND: + for (cnt1 = 21; cnt1--; ) + { + if (LOWORD (wParam) == IDC_BSELECT + cnt1) + { + if (disabled) + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + EnableWindow (GetDlgItem (hWnd, disabled = wParam), FALSE); + countdown = GetTickCount(); + GetKeyState (keymaps[0]); + return TRUE; + } + } + if (LOWORD (wParam) == IDOK) + EndDialog (hWnd, IDOK); + else if (LOWORD (wParam) == IDCANCEL) + EndDialog (hWnd, IDCANCEL); + break; + case WM_TIMER: + if (disabled) + { + const int index = disabled - IDC_BSELECT; + int analog = FALSE; + if ((GetTickCount() - countdown) / 1000 != 10) + { + char buff[64]; + wsprintf (buff, "Timeout: %d", 10 - (GetTickCount() - countdown) / 1000); + SetWindowText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); + } + else + { + global.config.keys[pad][index] = 0; + set_label (hWnd, pad, index); + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + break; + } + if (GetKeyState (keymaps[1]) == FALSE) + break; + for (key = 0x100; key--; ) + { + if (~keymaps[0][key] & keymaps[1][key] & 0x80) + break; + } + for (cnt1 = global.devcnt; cnt1--;) + { + if (GetJoyState (cnt1) == FALSE) + break; + + for (cnt2 = 32; cnt2--; ) + { + if (global.JoyState[cnt1].rgbButtons[cnt2]) + key = 0x1000 + 0x100 * cnt1 + cnt2; + } + for (cnt2 = 8; cnt2--; ) + { + const int now = ((u32*)&global.JoyState[cnt1].lX)[cnt2]; + if (now < -64) + { + key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +0; + analog = TRUE; + } + else if (now >= 64) + { + key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +1; + analog = TRUE; + } + } + for (cnt2 = 4; cnt2--; ) + { + const u32 now = global.JoyState[cnt1].rgdwPOV[cnt2]; + if ((now >= 0 && now < 4500) || (now >= 31500 && now < 36000)) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +0; + if (now >= 4500 && now < 13500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +1; + if (now >= 13500 && now < 22500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +2; + if (now >= 22500 && now < 31500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +3; + } + } + if (index >= 17 && index <= 20 && analog == 0) + key = 0; + else if (key > 0) + { + if (key != 1) + global.config.keys[pad][index] = key; + set_label (hWnd, pad, index); + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + } + } + } + return FALSE; +} + +u32 CALLBACK PS2EgetLibType (void) +{ + return 0x02; +} + +const char* CALLBACK PS2EgetLibName (void) +{ + return LibraryName; +} + +u32 CALLBACK PS2EgetLibVersion2 (u32 type) +{ + return (version << 16) | (revision << 8) | build; +} + +u32 CALLBACK PSEgetLibType (void) +{ + return 8; +} + +const char* CALLBACK PSEgetLibName (void) +{ + return LibraryName; +} + +u32 CALLBACK PSEgetLibVersion (void) +{ + return (version << 16) | (revision << 8) | build; +} + +s32 CALLBACK PADinit (u32 flags) +{ + return 0; +} + +void CALLBACK PADshutdown (void) +{ +} + +static int n_open = 0; +s32 CALLBACK PADopen (HWND hWnd) +{ + if (!IsWindow (hWnd) && !IsBadReadPtr ((u32*)hWnd, 4)) + hWnd = *(HWND*)hWnd; + if (!IsWindow (hWnd)) + hWnd = NULL; + else + { + while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD) + hWnd = GetParent (hWnd); + } + hTargetWnd = hWnd; + if (n_open++ == FALSE) + { + memset (&global, 0, sizeof (global)); + global.padStat[0] = 0xffff; + global.padStat[1] = 0xffff; + LoadConfig(); + PADsetMode (0, 0); + PADsetMode (1, 0); + } + return 0; +} + +void CALLBACK PADclose (void) +{ + if (--n_open == 0) + ReleaseDirectInput(); +} + +u32 CALLBACK PADquery (void) +{ + return 3; +} + +u8 CALLBACK PADstartPoll (int pad) +{ + global.curPad = pad -1; + global.curByte = 0; + return 0xff; +} + +static const u8 cmd40[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a +}; +static const u8 cmd41[8] = +{ + 0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a, +}; +static const u8 cmd44[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd45[8] = +{ + 0xff, 0x5a, 0x03, 0x02, 0x01, 0x02, 0x01, 0x00, +}; +static const u8 cmd46[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0a, +}; +static const u8 cmd47[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, +}; +static const u8 cmd4c[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd4d[8] = +{ + 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +static const u8 cmd4f[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, +}; + +static u8 get_analog (const int key) +{ + const int pad = ((key & 0xf00) / 0x100); + const int pos = ((key & 0x0ff) /2); + return (u8)(((int*)&global.JoyState[pad].lX)[pos] + 128); +} + +static u8 get_pressure (const DWORD now, const DWORD press) +{ + /*if (press == 0) + return 0; + return (u8)((now - press > 2550) ? 255 : (now - press) / 10);*/ + return 255; +} + +u8 CALLBACK PADpoll (const u8 value) +{ + const int pad = global.curPad; + const int cur = global.curByte; + static u8 buf[20]; + if (cur == 0) + { + global.curByte++; + global.curCmd = value; + switch (value) + { + case 0x40: + global.cmdLen = sizeof (cmd40); + memcpy (buf, cmd40, sizeof (cmd40)); + return 0xf3; + case 0x41: + global.cmdLen = sizeof (cmd41); + memcpy (buf, cmd41, sizeof (cmd41)); + return 0xf3; + case 0x42: + case 0x43: + if (value == 0x42) UpdateState (pad); + global.cmdLen = 2 + 2 * (global.padID[pad] & 0x0f); + buf[1] = global.padModeC[pad] ? 0x00 : 0x5a; + *(u16*)&buf[2] = global.padStat[pad]; + if (value == 0x43 && global.padModeE[pad]) + { + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + return 0xf3; + } + else + { + buf[ 4] = get_analog (global.config.keys[pad][19]); + buf[ 5] = get_analog (global.config.keys[pad][20]); + buf[ 6] = get_analog (global.config.keys[pad][17]); + buf[ 7] = get_analog (global.config.keys[pad][18]); + if (global.padID[pad] == 0x79) + { + const DWORD now = GetTickCount(); + buf[ 8] = get_pressure (now, global.padPress[pad][2]); + buf[ 9] = get_pressure (now, global.padPress[pad][0]); + buf[10] = get_pressure (now, global.padPress[pad][3]); + buf[11] = get_pressure (now, global.padPress[pad][1]); + buf[12] = get_pressure (now, global.padPress[pad][11]); + buf[13] = get_pressure (now, global.padPress[pad][10]); + buf[14] = get_pressure (now, global.padPress[pad][9]); + buf[15] = get_pressure (now, global.padPress[pad][8]); + buf[16] = get_pressure (now, global.padPress[pad][13]); + buf[17] = get_pressure (now, global.padPress[pad][12]); + buf[18] = get_pressure (now, global.padPress[pad][15]); + buf[19] = get_pressure (now, global.padPress[pad][14]); + } + return (u8)global.padID[pad]; + } + break; + case 0x44: + global.cmdLen = sizeof (cmd44); + memcpy (buf, cmd44, sizeof (cmd44)); + return 0xf3; + case 0x45: + global.cmdLen = sizeof (cmd45); + memcpy (buf, cmd45, sizeof (cmd45)); + buf[4] = (u8)global.padMode1[pad]; + return 0xf3; + case 0x46: + global.cmdLen = sizeof (cmd46); + memcpy (buf, cmd46, sizeof (cmd46)); + return 0xf3; + case 0x47: + global.cmdLen = sizeof (cmd47); + memcpy (buf, cmd47, sizeof (cmd47)); + return 0xf3; + case 0x4c: + global.cmdLen = sizeof (cmd4c); + memcpy (buf, cmd4c, sizeof (cmd4c)); + return 0xf3; + case 0x4d: + global.cmdLen = sizeof (cmd4d); + memcpy (buf, cmd4d, sizeof (cmd4d)); + return 0xf3; + case 0x4f: + global.padID[pad] = 0x79; + global.padMode2[pad] = 1; + global.cmdLen = sizeof (cmd4f); + memcpy (buf, cmd4f, sizeof (cmd4f)); + return 0xf3; + } + } + switch (global.curCmd) + { + case 0x42: + if (cur == global.padVib0[pad]) + global.padVibF[pad][0] = value; + if (cur == global.padVib1[pad]) + global.padVibF[pad][1] = value; + break; + case 0x43: + if (cur == 2) + { + global.padModeE[pad] = value; + global.padModeC[pad] = 0; + } + break; + case 0x44: + if (cur == 2) + PADsetMode (pad, value); + if (cur == 3) + global.padModeF[pad] = (value == 3); + break; + case 0x46: + if (cur == 2) + { + switch(value) + { + case 0: + buf[5] = 0x02; + buf[6] = 0x00; + buf[7] = 0x0A; + break; + case 1: + buf[5] = 0x01; + buf[6] = 0x01; + buf[7] = 0x14; + break; + } + } + break; + case 0x4c: + if (cur == 2) + { + static const u8 buf5[] = { 0x04, 0x07, 0x02, 0x05 }; + buf[5] = buf5[value & 3]; + } + break; + case 0x4d: + if (cur >= 2) + { + if (cur == global.padVib0[pad]) + buf[cur] = 0x00; + if (cur == global.padVib1[pad]) + buf[cur] = 0x01; + if (value == 0x00) + { + global.padVib0[pad] = cur; + if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) + global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; + } + else if (value == 0x01) + { + global.padVib1[pad] = cur; + if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) + global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; + } + } + break; + } + if (cur >= global.cmdLen) + return 0; + return buf[global.curByte++]; +} + +typedef struct +{ + unsigned char controllerType; + unsigned short buttonStatus; + unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY; + unsigned char moveX, moveY; + unsigned char reserved[91]; +} PadDataS; + +long PADreadPort1 (PadDataS* pads) +{ + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[0] & 0xf0) == 0x40) + pads->controllerType = 4; + else + pads->controllerType = 7; + pads->buttonStatus = global.padStat[0]; + pads->leftJoyX = get_analog (global.config.keys[0][17]); + pads->leftJoyY = get_analog (global.config.keys[0][18]); + pads->rightJoyX = get_analog (global.config.keys[0][19]); + pads->rightJoyY = get_analog (global.config.keys[0][20]); + pads->moveX = 0; + pads->moveY = 0; + return 0; +} + +long PADreadPort2 (PadDataS* pads) +{ + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[1] & 0xf0) == 0x40) + pads->controllerType = 4; + else + pads->controllerType = 7; + pads->buttonStatus = global.padStat[1]; + pads->leftJoyX = get_analog (global.config.keys[1][17]); + pads->leftJoyY = get_analog (global.config.keys[1][18]); + pads->rightJoyX = get_analog (global.config.keys[1][19]); + pads->rightJoyY = get_analog (global.config.keys[1][20]); + pads->moveX = 0; + pads->moveY = 0; + return 0; +} + +keyEvent* CALLBACK PADkeyEvent (void) +{ + static keyEvent ev; + static u8 state[2][256]; + if (n_open) + { + memcpy (state[0], state[1], sizeof (state[0])); + GetKeyState (state[1]); + for (int cnt = 0; cnt < 256; cnt++) + { + if (~state[0][cnt] & state[1][cnt] & 0x80) + { + ev.event = (state[1][cnt] & 0x80) ? 1 : 2; + ev.key = MapVirtualKey (cnt, 1); + return &ev; + } + } + } + return NULL; +} + +void CALLBACK PADconfigure (void) +{ + if (n_open == 0) + { + memset (&global, 0, sizeof (global)); + if (DialogBox (hInstance, MAKEINTRESOURCE (IDD_DIALOG1), GetActiveWindow(), (DLGPROC)ConfigureDlgProc) == IDOK) + SaveConfig(); + ReleaseDirectInput(); + } +} + +void CALLBACK PADabout (void) +{ + MessageBox (0, "Copyright (C) 2004-2005 Nagisa", "SSSPSX PAD plugin", 0); +} + +s32 CALLBACK PADtest (void) +{ + return 0; +} +//#ifdef _WIN64 +BOOL APIENTRY DllMain(HMODULE hInst, DWORD dwReason, LPVOID lpReserved) +{ + hInstance = hInst; + return TRUE; +} +//#else +BOOL APIENTRY EntryPoint (HMODULE hInst, DWORD dwReason, LPVOID lpReserved) +{ + hInstance = hInst; + return TRUE; +} +//#endif diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX.def b/plugins/pad/SSSPSXPAD/PadSSSPSX.def new file mode 100644 index 0000000000..a791c60dd7 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX.def @@ -0,0 +1,22 @@ +LIBRARY "PadSSSPSX" + +EXPORTS + PSEgetLibType @1 + PSEgetLibName @2 + PSEgetLibVersion @3 + PS2EgetLibType @4 + PS2EgetLibName @5 + PS2EgetLibVersion2 @6 + PADinit @7 + PADshutdown @8 + PADopen @9 + PADclose @10 + PADkeyEvent @11 + PADstartPoll @12 + PADpoll @13 + PADreadPort1 @14 + PADreadPort2 @15 + PADquery @16 + PADconfigure @17 + PADtest @18 + PADabout @19 diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX.h b/plugins/pad/SSSPSXPAD/PadSSSPSX.h new file mode 100644 index 0000000000..facd78303a --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX.h @@ -0,0 +1,45 @@ +/* PADwin + * Copyright (C) 2002-2004 PADwin 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 + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#include "PadSSSPSXres.h" + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef struct +{ + u32 key; + u32 event; +} keyEvent; + +typedef struct +{ + u32 keys[2][21]; +} Config; + +#endif diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX.rc b/plugins/pad/SSSPSXPAD/PadSSSPSX.rc new file mode 100644 index 0000000000..6837be08fe --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX.rc @@ -0,0 +1,152 @@ +// Microsoft Visual C++ generated resource script. +// +#include "PadSSSPSXres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// “ú–{Œê resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) +#ifdef _WIN32 +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT +#pragma code_page(932) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "PadSSSPSXres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 442, 239 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "PAD Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_TABC,"SysTabControl32",0x0,6,6,432,210 + PUSHBUTTON "L2",IDC_BL2,54,24,72,12,NOT WS_TABSTOP + EDITTEXT IDC_EL2,54,36,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "L1",IDC_BL1,54,48,72,12,NOT WS_TABSTOP + EDITTEXT IDC_EL1,54,60,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Up",IDC_BUP,54,78,72,12,NOT WS_TABSTOP + EDITTEXT IDC_EUP,54,90,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Left",IDC_BLEFT,12,102,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ELEFT,12,114,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Right",IDC_BRIGHT,96,102,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ERIGHT,96,114,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Down",IDC_BDOWN,54,126,72,12,NOT WS_TABSTOP + EDITTEXT IDC_EDOWN,54,138,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Select",IDC_BSELECT,144,36,72,12,NOT WS_TABSTOP, + WS_EX_TRANSPARENT + EDITTEXT IDC_ESELECT,144,48,72,12,ES_READONLY | NOT WS_TABSTOP, + WS_EX_TRANSPARENT + PUSHBUTTON "Start",IDC_BSTART,228,36,72,12,NOT WS_TABSTOP, + WS_EX_TRANSPARENT + EDITTEXT IDC_ESTART,228,48,72,12,ES_READONLY | NOT WS_TABSTOP, + WS_EX_TRANSPARENT + PUSHBUTTON "Analog",IDC_BMODE,186,66,72,12,NOT WS_TABSTOP, + WS_EX_TRANSPARENT + EDITTEXT IDC_EMODE,186,78,72,12,ES_READONLY | NOT WS_TABSTOP, + WS_EX_TRANSPARENT + PUSHBUTTON "R2",IDC_BR2,318,24,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ER2,318,36,72,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "R1",IDC_BR1,318,48,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ER1,318,60,72,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_TABSTOP + PUSHBUTTON "Triangle",IDC_BTRIANGLE,318,78,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ETRIANGLE,318,90,72,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Square",IDC_BSQUARE,276,102,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ESQUARE,276,114,72,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Circle",IDC_BCIRCLE,360,102,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ECIRCLE,360,114,72,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "Cross",IDC_BCROSS,318,126,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ECROSS,318,138,72,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_TABSTOP + PUSHBUTTON "L3",IDC_BL3,144,132,72,12,NOT WS_TABSTOP + EDITTEXT IDC_EL3,144,144,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "LX",IDC_BLAX,144,162,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ELAX,144,174,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "LY",IDC_BLAY,144,186,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ELAY,144,198,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "R3",IDC_BR3,228,132,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ER3,228,144,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "RX",IDC_BRAX,228,162,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ERAX,228,174,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "RY",IDC_BRAY,228,186,72,12,NOT WS_TABSTOP + EDITTEXT IDC_ERAY,228,198,72,12,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "OK",IDOK,330,222,48,12,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,390,222,48,12,NOT WS_TABSTOP + CTEXT "",IDC_STATIC,318,174,108,30,0,WS_EX_STATICEDGE + LTEXT "DUALSHOCK2 INSIDE",IDC_STATIC,331,186,84,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + RIGHTMARGIN, 432 + BOTTOMMARGIN, 233 + END +END +#endif // APSTUDIO_INVOKED + +#endif // “ú–{Œê resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX.vcproj b/plugins/pad/SSSPSXPAD/PadSSSPSX.vcproj new file mode 100644 index 0000000000..ffdcde1e62 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX_2005_x64.vcproj b/plugins/pad/SSSPSXPAD/PadSSSPSX_2005_x64.vcproj new file mode 100644 index 0000000000..10e14a5680 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX_2005_x64.vcproj @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.sln b/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.sln new file mode 100644 index 0000000000..498a495cc1 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PadSSSPSX_vc2005beta2", "PadSSSPSX_vc2005beta2.vcproj", "{79D9E8A9-C764-4082-826C-B715341FB1E9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|Win32.ActiveCfg = Debug|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|Win32.Build.0 = Debug|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|x64.ActiveCfg = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Debug|x64.Build.0 = Debug|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.ActiveCfg = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|Win32.Build.0 = Release|Win32 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|x64.ActiveCfg = Release|x64 + {79D9E8A9-C764-4082-826C-B715341FB1E9}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.vcproj b/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.vcproj new file mode 100644 index 0000000000..6cbdcc850f --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSX_vc2005beta2.vcproj @@ -0,0 +1,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/SSSPSXPAD/PadSSSPSXres.h b/plugins/pad/SSSPSXPAD/PadSSSPSXres.h new file mode 100644 index 0000000000..bcfbc8f0b2 --- /dev/null +++ b/plugins/pad/SSSPSXPAD/PadSSSPSXres.h @@ -0,0 +1,59 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PadSSSPSX.rc +// +#define IDD_DIALOG1 100 +#define IDC_BSELECT 1000 +#define IDC_BL3 1001 +#define IDC_BR3 1002 +#define IDC_BSTART 1003 +#define IDC_BUP 1004 +#define IDC_BRIGHT 1005 +#define IDC_BDOWN 1006 +#define IDC_BLEFT 1007 +#define IDC_BL2 1008 +#define IDC_BR2 1009 +#define IDC_BL1 1010 +#define IDC_BR1 1011 +#define IDC_BTRIANGLE 1012 +#define IDC_BCIRCLE 1013 +#define IDC_BCROSS 1014 +#define IDC_BSQUARE 1015 +#define IDC_BMODE 1016 +#define IDC_BLAX 1017 +#define IDC_BLAY 1018 +#define IDC_BRAX 1019 +#define IDC_BRAY 1020 +#define IDC_ESELECT 1030 +#define IDC_EL3 1031 +#define IDC_ER3 1032 +#define IDC_ESTART 1033 +#define IDC_EUP 1034 +#define IDC_ERIGHT 1035 +#define IDC_EDOWN 1036 +#define IDC_ELEFT 1037 +#define IDC_EL2 1038 +#define IDC_ER2 1039 +#define IDC_EL1 1040 +#define IDC_ER1 1041 +#define IDC_ETRIANGLE 1042 +#define IDC_ECIRCLE 1043 +#define IDC_ECROSS 1044 +#define IDC_ESQUARE 1045 +#define IDC_EMODE 1046 +#define IDC_ELAX 1047 +#define IDC_ELAY 1048 +#define IDC_ERAX 1049 +#define IDC_ERAY 1050 +#define IDC_TABC 1060 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1061 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/pad/SSSPSXPAD/licence.txt b/plugins/pad/SSSPSXPAD/licence.txt new file mode 100644 index 0000000000..b3143dc8ee --- /dev/null +++ b/plugins/pad/SSSPSXPAD/licence.txt @@ -0,0 +1 @@ +see http://www.gnu.org/copyleft/gpl.html diff --git a/plugins/pad/SSSPSXPAD/readmewip.txt b/plugins/pad/SSSPSXPAD/readmewip.txt new file mode 100644 index 0000000000..144433621d --- /dev/null +++ b/plugins/pad/SSSPSXPAD/readmewip.txt @@ -0,0 +1,48 @@ +SSSPSX Pad - An Open Source Pad plugin for PSX and PS2 emulators +Author: Nagisa +Homepage: http://www.asahi-net.or.jp/~bz7t-skmt/ + +Overview: +-Small executable program +-Source code under 1000 step,20kb binary +-Open Source,under the GPL Licence + + +Features: + +For PS1 emulators +- Force feedback support (PCSX only) + Delete the following PCSX sorce code. + File: sio.c Line: 138 +@--------------------- +@if (buf[parp] == 0x41) { +@@switch (value) { +@@@case 0x43: +@@@@buf[1] = 0x43; +@@@@break; +@@@case 0x45: +@@@@buf[1] = 0xf3; +@@@@break; +@@} +@} +@--------------------- + +For PCSX2 +-Force feedback support (maybe) +-PADKeyEvent API support +-Using DirectInput 9 (game controller and keyboard) + +Thanks to: +http://www.hm5.aitai.ne.jp/~takuya/index.html#ds2_analisys for the valuable info +PCSX2 team for the PadWinKeyb source code +bositman for some report + +Version History: +v1.0: -Initial Release +v1.1: -Changed to DirectInput 9 +v1.2: -PADKeyEvent API support added +v1.3: -DirectInput collision problem fixed +v1.4: -Added timeout on settings dialog.If the countdown ends, the key will be set to "NONE". + -Changed "ESC" key action on settings dialog.If you press the "ESC" key, the setting will keep the previous one. + -Fixed silly bug. (dont ask me about it). +v1.5: -Fixed 0x4D packet. diff --git a/plugins/pad/build.sh b/plugins/pad/build.sh new file mode 100644 index 0000000000..cfafa5db1d --- /dev/null +++ b/plugins/pad/build.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +echo ----------------------- +echo Building PAD plugins... +echo ----------------------- + +curdir=`pwd` + +# disable PADwin for linux builds +#cd ${curdir}/PADwin +#sh build.sh $@ + +#if [ $? -ne 0 ] +#then +#exit 1 +#fi + +cd ${curdir}/zeropad +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/plugins/pad/zeropad/Linux/callbacks.h b/plugins/pad/zeropad/Linux/callbacks.h new file mode 100644 index 0000000000..cb64e16292 --- /dev/null +++ b/plugins/pad/zeropad/Linux/callbacks.h @@ -0,0 +1,46 @@ +#include + + +void +OnConf_Pad1 (GtkButton *button, + gpointer user_data); + +void +OnConf_Pad2 (GtkButton *button, + gpointer user_data); + +void +OnConf_Key (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +on_joydevicescombo_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_checkbutton_reverselx_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reversely_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reverserx_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reversery_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_forcefeedback_toggled (GtkToggleButton *togglebutton, + gpointer user_data); diff --git a/plugins/pad/zeropad/Linux/interface.c b/plugins/pad/zeropad/Linux/interface.c new file mode 100644 index 0000000000..ffd4261e65 --- /dev/null +++ b/plugins/pad/zeropad/Linux/interface.c @@ -0,0 +1,640 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + const gchar *authors[] = { + "Author: zerofrog(@gmail.com)", + "Thanks to:", + " linuzappz ", + "florin sasu ", + "and SSSPSXPad, TwinPad authors", + NULL + }; + /* TRANSLATORS: Replace this string with your names, one name per line. */ + gchar *translators = _("translator-credits"); + + About = gtk_about_dialog_new (); + gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (About), VERSION); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (About), _("ZeroPAD")); + gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (About), authors); + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (About), translators); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (About, About, "About"); + + return About; +} + +GtkWidget* +create_Conf (void) +{ + GtkWidget *Conf; + GtkWidget *dialog_vbox1; + GtkWidget *vbox1; + GtkWidget *frame1; + GtkWidget *alignment1; + GtkWidget *hbox1; + GtkWidget *PAD1; + GSList *PAD1_group = NULL; + GtkWidget *PAD2; + GtkWidget *label2; + GtkWidget *vbox2; + GtkWidget *label5; + GtkWidget *joydevicescombo; + GtkWidget *fixed1; + GtkWidget *eL2; + GtkWidget *eL1; + GtkWidget *eSelect; + GtkWidget *eStart; + GtkWidget *eUp; + GtkWidget *eRight; + GtkWidget *eLeft; + GtkWidget *eDown; + GtkWidget *eR2; + GtkWidget *eR1; + GtkWidget *eAnalog; + GtkWidget *eSquare; + GtkWidget *eTriangle; + GtkWidget *eCircle; + GtkWidget *eCross; + GtkWidget *eR3; + GtkWidget *eL3; + GtkWidget *eRx; + GtkWidget *eLx; + GtkWidget *eRy; + GtkWidget *eLy; + GtkWidget *Select; + GtkWidget *L1; + GtkWidget *Left; + GtkWidget *Down; + GtkWidget *Analog; + GtkWidget *R2; + GtkWidget *Start; + GtkWidget *R1; + GtkWidget *Cross; + GtkWidget *Triangle; + GtkWidget *Circle; + GtkWidget *Square; + GtkWidget *L3; + GtkWidget *Up; + GtkWidget *L2; + GtkWidget *Lx; + GtkWidget *Ly; + GtkWidget *Rx; + GtkWidget *Ry; + GtkWidget *Right; + GtkWidget *label3; + GtkWidget *R3; + GtkWidget *checkbutton_reverselx; + GtkWidget *checkbutton_reversely; + GtkWidget *checkbutton_reverserx; + GtkWidget *checkbutton_reversery; + GtkWidget *forcefeedback; + GtkWidget *dialog_action_area1; + GtkWidget *cancelbutton1; + GtkWidget *okbutton1; + + Conf = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (Conf), _("ZeroPAD Configuration Dialog")); + gtk_window_set_type_hint (GTK_WINDOW (Conf), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox1 = GTK_DIALOG (Conf)->vbox; + gtk_widget_show (dialog_vbox1); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); + + frame1 = gtk_frame_new (NULL); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox1), frame1, FALSE, FALSE, 0); + + alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (frame1), alignment1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1), 0, 0, 12, 0); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (alignment1), hbox1); + + PAD1 = gtk_radio_button_new_with_mnemonic (NULL, _("PAD1")); + gtk_widget_show (PAD1); + gtk_box_pack_start (GTK_BOX (hbox1), PAD1, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (PAD1), PAD1_group); + PAD1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (PAD1)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PAD1), TRUE); + + PAD2 = gtk_radio_button_new_with_mnemonic (NULL, _("PAD2")); + gtk_widget_show (PAD2); + gtk_box_pack_start (GTK_BOX (hbox1), PAD2, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (PAD2), PAD1_group); + PAD1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (PAD2)); + + label2 = gtk_label_new (_("Choose PAD to modify")); + gtk_widget_show (label2); + gtk_frame_set_label_widget (GTK_FRAME (frame1), label2); + gtk_label_set_use_markup (GTK_LABEL (label2), TRUE); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0); + + label5 = gtk_label_new (_("Joystick to use for this PAD")); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (vbox2), label5, FALSE, FALSE, 0); + + joydevicescombo = gtk_combo_box_entry_new_text (); + gtk_widget_show (joydevicescombo); + gtk_box_pack_start (GTK_BOX (vbox2), joydevicescombo, TRUE, TRUE, 0); + + fixed1 = gtk_fixed_new (); + gtk_widget_show (fixed1); + gtk_box_pack_start (GTK_BOX (vbox1), fixed1, TRUE, TRUE, 0); + + eL2 = gtk_entry_new (); + gtk_widget_show (eL2); + gtk_fixed_put (GTK_FIXED (fixed1), eL2, 64, 40); + gtk_widget_set_size_request (eL2, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eL2), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eL2), 8226); + + eL1 = gtk_entry_new (); + gtk_widget_show (eL1); + gtk_fixed_put (GTK_FIXED (fixed1), eL1, 64, 104); + gtk_widget_set_size_request (eL1, 64, 24); + gtk_entry_set_invisible_char (GTK_ENTRY (eL1), 8226); + + eSelect = gtk_entry_new (); + gtk_widget_show (eSelect); + gtk_fixed_put (GTK_FIXED (fixed1), eSelect, 168, 64); + gtk_widget_set_size_request (eSelect, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eSelect), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eSelect), 8226); + + eStart = gtk_entry_new (); + gtk_widget_show (eStart); + gtk_fixed_put (GTK_FIXED (fixed1), eStart, 280, 64); + gtk_widget_set_size_request (eStart, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eStart), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eStart), 8226); + + eUp = gtk_entry_new (); + gtk_widget_show (eUp); + gtk_fixed_put (GTK_FIXED (fixed1), eUp, 64, 168); + gtk_widget_set_size_request (eUp, 64, 24); + gtk_entry_set_invisible_char (GTK_ENTRY (eUp), 8226); + + eRight = gtk_entry_new (); + gtk_widget_show (eRight); + gtk_fixed_put (GTK_FIXED (fixed1), eRight, 128, 208); + gtk_widget_set_size_request (eRight, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRight), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRight), 8226); + + eLeft = gtk_entry_new (); + gtk_widget_show (eLeft); + gtk_fixed_put (GTK_FIXED (fixed1), eLeft, 0, 208); + gtk_widget_set_size_request (eLeft, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLeft), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLeft), 8226); + + eDown = gtk_entry_new (); + gtk_widget_show (eDown); + gtk_fixed_put (GTK_FIXED (fixed1), eDown, 64, 256); + gtk_widget_set_size_request (eDown, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eDown), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eDown), 8226); + + eR2 = gtk_entry_new (); + gtk_widget_show (eR2); + gtk_fixed_put (GTK_FIXED (fixed1), eR2, 368, 32); + gtk_widget_set_size_request (eR2, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR2), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR2), 8226); + + eR1 = gtk_entry_new (); + gtk_widget_show (eR1); + gtk_fixed_put (GTK_FIXED (fixed1), eR1, 368, 104); + gtk_widget_set_size_request (eR1, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR1), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR1), 8226); + + eAnalog = gtk_entry_new (); + gtk_widget_show (eAnalog); + gtk_fixed_put (GTK_FIXED (fixed1), eAnalog, 224, 128); + gtk_widget_set_size_request (eAnalog, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eAnalog), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eAnalog), 8226); + + eSquare = gtk_entry_new (); + gtk_widget_show (eSquare); + gtk_fixed_put (GTK_FIXED (fixed1), eSquare, 304, 208); + gtk_widget_set_size_request (eSquare, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eSquare), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eSquare), 8226); + + eTriangle = gtk_entry_new (); + gtk_widget_show (eTriangle); + gtk_fixed_put (GTK_FIXED (fixed1), eTriangle, 368, 168); + gtk_widget_set_size_request (eTriangle, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eTriangle), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eTriangle), 8226); + + eCircle = gtk_entry_new (); + gtk_widget_show (eCircle); + gtk_fixed_put (GTK_FIXED (fixed1), eCircle, 432, 208); + gtk_widget_set_size_request (eCircle, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eCircle), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eCircle), 8226); + + eCross = gtk_entry_new (); + gtk_widget_show (eCross); + gtk_fixed_put (GTK_FIXED (fixed1), eCross, 368, 256); + gtk_widget_set_size_request (eCross, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eCross), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eCross), 8226); + + eR3 = gtk_entry_new (); + gtk_widget_show (eR3); + gtk_fixed_put (GTK_FIXED (fixed1), eR3, 272, 272); + gtk_widget_set_size_request (eR3, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR3), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR3), 8226); + + eL3 = gtk_entry_new (); + gtk_widget_show (eL3); + gtk_fixed_put (GTK_FIXED (fixed1), eL3, 176, 272); + gtk_widget_set_size_request (eL3, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eL3), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eL3), 8226); + + eRx = gtk_entry_new (); + gtk_widget_show (eRx); + gtk_fixed_put (GTK_FIXED (fixed1), eRx, 272, 352); + gtk_widget_set_size_request (eRx, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRx), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRx), 8226); + + eLx = gtk_entry_new (); + gtk_widget_show (eLx); + gtk_fixed_put (GTK_FIXED (fixed1), eLx, 160, 352); + gtk_widget_set_size_request (eLx, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLx), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLx), 8226); + + eRy = gtk_entry_new (); + gtk_widget_show (eRy); + gtk_fixed_put (GTK_FIXED (fixed1), eRy, 272, 416); + gtk_widget_set_size_request (eRy, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRy), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRy), 8226); + + eLy = gtk_entry_new (); + gtk_widget_show (eLy); + gtk_fixed_put (GTK_FIXED (fixed1), eLy, 160, 416); + gtk_widget_set_size_request (eLy, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLy), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLy), 8226); + + Select = gtk_button_new_with_mnemonic (_("Select")); + gtk_widget_show (Select); + gtk_fixed_put (GTK_FIXED (fixed1), Select, 168, 32); + gtk_widget_set_size_request (Select, 64, 32); + + L1 = gtk_button_new_with_mnemonic (_("L1")); + gtk_widget_show (L1); + gtk_fixed_put (GTK_FIXED (fixed1), L1, 64, 72); + gtk_widget_set_size_request (L1, 64, 32); + + Left = gtk_button_new_with_mnemonic (_("Left")); + gtk_widget_show (Left); + gtk_fixed_put (GTK_FIXED (fixed1), Left, 0, 176); + gtk_widget_set_size_request (Left, 64, 32); + + Down = gtk_button_new_with_mnemonic (_("Down")); + gtk_widget_show (Down); + gtk_fixed_put (GTK_FIXED (fixed1), Down, 64, 224); + gtk_widget_set_size_request (Down, 64, 32); + + Analog = gtk_button_new_with_mnemonic (_("Analog")); + gtk_widget_show (Analog); + gtk_fixed_put (GTK_FIXED (fixed1), Analog, 224, 96); + gtk_widget_set_size_request (Analog, 64, 32); + + R2 = gtk_button_new_with_mnemonic (_("R2")); + gtk_widget_show (R2); + gtk_fixed_put (GTK_FIXED (fixed1), R2, 368, 0); + gtk_widget_set_size_request (R2, 64, 32); + + Start = gtk_button_new_with_mnemonic (_("Start")); + gtk_widget_show (Start); + gtk_fixed_put (GTK_FIXED (fixed1), Start, 280, 32); + gtk_widget_set_size_request (Start, 64, 32); + + R1 = gtk_button_new_with_mnemonic (_("R1")); + gtk_widget_show (R1); + gtk_fixed_put (GTK_FIXED (fixed1), R1, 368, 72); + gtk_widget_set_size_request (R1, 64, 32); + + Cross = gtk_button_new_with_mnemonic (_("Cross")); + gtk_widget_show (Cross); + gtk_fixed_put (GTK_FIXED (fixed1), Cross, 368, 224); + gtk_widget_set_size_request (Cross, 64, 32); + + Triangle = gtk_button_new_with_mnemonic (_("Triangle")); + gtk_widget_show (Triangle); + gtk_fixed_put (GTK_FIXED (fixed1), Triangle, 368, 136); + gtk_widget_set_size_request (Triangle, 64, 32); + + Circle = gtk_button_new_with_mnemonic (_("Circle")); + gtk_widget_show (Circle); + gtk_fixed_put (GTK_FIXED (fixed1), Circle, 432, 176); + gtk_widget_set_size_request (Circle, 64, 32); + + Square = gtk_button_new_with_mnemonic (_("Square")); + gtk_widget_show (Square); + gtk_fixed_put (GTK_FIXED (fixed1), Square, 304, 176); + gtk_widget_set_size_request (Square, 64, 32); + + L3 = gtk_button_new_with_mnemonic (_("L3")); + gtk_widget_show (L3); + gtk_fixed_put (GTK_FIXED (fixed1), L3, 176, 240); + gtk_widget_set_size_request (L3, 64, 32); + + Up = gtk_button_new_with_mnemonic (_("Up")); + gtk_widget_show (Up); + gtk_fixed_put (GTK_FIXED (fixed1), Up, 64, 136); + gtk_widget_set_size_request (Up, 64, 32); + + L2 = gtk_button_new_with_mnemonic (_("L2")); + gtk_widget_show (L2); + gtk_fixed_put (GTK_FIXED (fixed1), L2, 64, 8); + gtk_widget_set_size_request (L2, 64, 32); + + Lx = gtk_button_new_with_mnemonic (_("Lx")); + gtk_widget_show (Lx); + gtk_fixed_put (GTK_FIXED (fixed1), Lx, 160, 320); + gtk_widget_set_size_request (Lx, 80, 32); + + Ly = gtk_button_new_with_mnemonic (_("Ly")); + gtk_widget_show (Ly); + gtk_fixed_put (GTK_FIXED (fixed1), Ly, 160, 384); + gtk_widget_set_size_request (Ly, 80, 32); + + Rx = gtk_button_new_with_mnemonic (_("Rx")); + gtk_widget_show (Rx); + gtk_fixed_put (GTK_FIXED (fixed1), Rx, 272, 320); + gtk_widget_set_size_request (Rx, 80, 32); + + Ry = gtk_button_new_with_mnemonic (_("Ry")); + gtk_widget_show (Ry); + gtk_fixed_put (GTK_FIXED (fixed1), Ry, 272, 384); + gtk_widget_set_size_request (Ry, 80, 32); + + Right = gtk_button_new_with_mnemonic (_("Right")); + gtk_widget_show (Right); + gtk_fixed_put (GTK_FIXED (fixed1), Right, 128, 176); + gtk_widget_set_size_request (Right, 64, 32); + + label3 = gtk_label_new (_("Analog Controls (move mouse or analog joystick to select)")); + gtk_widget_show (label3); + gtk_fixed_put (GTK_FIXED (fixed1), label3, 48, 296); + gtk_widget_set_size_request (label3, 408, 16); + gtk_label_set_single_line_mode (GTK_LABEL (label3), TRUE); + + R3 = gtk_button_new_with_mnemonic (_("R3")); + gtk_widget_show (R3); + gtk_fixed_put (GTK_FIXED (fixed1), R3, 272, 240); + gtk_widget_set_size_request (R3, 64, 32); + + checkbutton_reverselx = gtk_check_button_new_with_mnemonic (_("Reverse LX")); + gtk_widget_show (checkbutton_reverselx); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reverselx, 16, 328); + gtk_widget_set_size_request (checkbutton_reverselx, 111, 22); + + checkbutton_reversely = gtk_check_button_new_with_mnemonic (_("Reverse LY")); + gtk_widget_show (checkbutton_reversely); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reversely, 16, 352); + gtk_widget_set_size_request (checkbutton_reversely, 111, 22); + + checkbutton_reverserx = gtk_check_button_new_with_mnemonic (_("Reverse RX")); + gtk_widget_show (checkbutton_reverserx); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reverserx, 16, 376); + gtk_widget_set_size_request (checkbutton_reverserx, 111, 22); + + checkbutton_reversery = gtk_check_button_new_with_mnemonic (_("Reverse RY")); + gtk_widget_show (checkbutton_reversery); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reversery, 16, 400); + gtk_widget_set_size_request (checkbutton_reversery, 111, 22); + + forcefeedback = gtk_check_button_new_with_mnemonic (_("Enable Force\nFeedback")); + gtk_widget_show (forcefeedback); + gtk_fixed_put (GTK_FIXED (fixed1), forcefeedback, 384, 320); + gtk_widget_set_size_request (forcefeedback, 112, 48); + + dialog_action_area1 = GTK_DIALOG (Conf)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + + cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (Conf), cancelbutton1, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT); + + okbutton1 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (Conf), okbutton1, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) PAD1, "clicked", + G_CALLBACK (OnConf_Pad1), + NULL); + g_signal_connect ((gpointer) PAD2, "clicked", + G_CALLBACK (OnConf_Pad2), + NULL); + g_signal_connect ((gpointer) joydevicescombo, "changed", + G_CALLBACK (on_joydevicescombo_changed), + NULL); + g_signal_connect ((gpointer) Select, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L1, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Left, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Down, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Analog, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R2, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Start, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R1, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Cross, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Triangle, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Circle, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Square, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L3, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Up, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L2, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Lx, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Ly, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Rx, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Ry, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Right, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R3, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) checkbutton_reverselx, "toggled", + G_CALLBACK (on_checkbutton_reverselx_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reversely, "toggled", + G_CALLBACK (on_checkbutton_reversely_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reverserx, "toggled", + G_CALLBACK (on_checkbutton_reverserx_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reversery, "toggled", + G_CALLBACK (on_checkbutton_reversery_toggled), + NULL); + g_signal_connect ((gpointer) forcefeedback, "toggled", + G_CALLBACK (on_forcefeedback_toggled), + NULL); + g_signal_connect ((gpointer) cancelbutton1, "clicked", + G_CALLBACK (OnConf_Cancel), + NULL); + g_signal_connect ((gpointer) okbutton1, "clicked", + G_CALLBACK (OnConf_Ok), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Conf, Conf, "Conf"); + GLADE_HOOKUP_OBJECT_NO_REF (Conf, dialog_vbox1, "dialog_vbox1"); + GLADE_HOOKUP_OBJECT (Conf, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (Conf, frame1, "frame1"); + GLADE_HOOKUP_OBJECT (Conf, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (Conf, hbox1, "hbox1"); + GLADE_HOOKUP_OBJECT (Conf, PAD1, "PAD1"); + GLADE_HOOKUP_OBJECT (Conf, PAD2, "PAD2"); + GLADE_HOOKUP_OBJECT (Conf, label2, "label2"); + GLADE_HOOKUP_OBJECT (Conf, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (Conf, label5, "label5"); + GLADE_HOOKUP_OBJECT (Conf, joydevicescombo, "joydevicescombo"); + GLADE_HOOKUP_OBJECT (Conf, fixed1, "fixed1"); + GLADE_HOOKUP_OBJECT (Conf, eL2, "eL2"); + GLADE_HOOKUP_OBJECT (Conf, eL1, "eL1"); + GLADE_HOOKUP_OBJECT (Conf, eSelect, "eSelect"); + GLADE_HOOKUP_OBJECT (Conf, eStart, "eStart"); + GLADE_HOOKUP_OBJECT (Conf, eUp, "eUp"); + GLADE_HOOKUP_OBJECT (Conf, eRight, "eRight"); + GLADE_HOOKUP_OBJECT (Conf, eLeft, "eLeft"); + GLADE_HOOKUP_OBJECT (Conf, eDown, "eDown"); + GLADE_HOOKUP_OBJECT (Conf, eR2, "eR2"); + GLADE_HOOKUP_OBJECT (Conf, eR1, "eR1"); + GLADE_HOOKUP_OBJECT (Conf, eAnalog, "eAnalog"); + GLADE_HOOKUP_OBJECT (Conf, eSquare, "eSquare"); + GLADE_HOOKUP_OBJECT (Conf, eTriangle, "eTriangle"); + GLADE_HOOKUP_OBJECT (Conf, eCircle, "eCircle"); + GLADE_HOOKUP_OBJECT (Conf, eCross, "eCross"); + GLADE_HOOKUP_OBJECT (Conf, eR3, "eR3"); + GLADE_HOOKUP_OBJECT (Conf, eL3, "eL3"); + GLADE_HOOKUP_OBJECT (Conf, eRx, "eRx"); + GLADE_HOOKUP_OBJECT (Conf, eLx, "eLx"); + GLADE_HOOKUP_OBJECT (Conf, eRy, "eRy"); + GLADE_HOOKUP_OBJECT (Conf, eLy, "eLy"); + GLADE_HOOKUP_OBJECT (Conf, Select, "Select"); + GLADE_HOOKUP_OBJECT (Conf, L1, "L1"); + GLADE_HOOKUP_OBJECT (Conf, Left, "Left"); + GLADE_HOOKUP_OBJECT (Conf, Down, "Down"); + GLADE_HOOKUP_OBJECT (Conf, Analog, "Analog"); + GLADE_HOOKUP_OBJECT (Conf, R2, "R2"); + GLADE_HOOKUP_OBJECT (Conf, Start, "Start"); + GLADE_HOOKUP_OBJECT (Conf, R1, "R1"); + GLADE_HOOKUP_OBJECT (Conf, Cross, "Cross"); + GLADE_HOOKUP_OBJECT (Conf, Triangle, "Triangle"); + GLADE_HOOKUP_OBJECT (Conf, Circle, "Circle"); + GLADE_HOOKUP_OBJECT (Conf, Square, "Square"); + GLADE_HOOKUP_OBJECT (Conf, L3, "L3"); + GLADE_HOOKUP_OBJECT (Conf, Up, "Up"); + GLADE_HOOKUP_OBJECT (Conf, L2, "L2"); + GLADE_HOOKUP_OBJECT (Conf, Lx, "Lx"); + GLADE_HOOKUP_OBJECT (Conf, Ly, "Ly"); + GLADE_HOOKUP_OBJECT (Conf, Rx, "Rx"); + GLADE_HOOKUP_OBJECT (Conf, Ry, "Ry"); + GLADE_HOOKUP_OBJECT (Conf, Right, "Right"); + GLADE_HOOKUP_OBJECT (Conf, label3, "label3"); + GLADE_HOOKUP_OBJECT (Conf, R3, "R3"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reverselx, "checkbutton_reverselx"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reversely, "checkbutton_reversely"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reverserx, "checkbutton_reverserx"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reversery, "checkbutton_reversery"); + GLADE_HOOKUP_OBJECT (Conf, forcefeedback, "forcefeedback"); + GLADE_HOOKUP_OBJECT_NO_REF (Conf, dialog_action_area1, "dialog_action_area1"); + GLADE_HOOKUP_OBJECT (Conf, cancelbutton1, "cancelbutton1"); + GLADE_HOOKUP_OBJECT (Conf, okbutton1, "okbutton1"); + + return Conf; +} + diff --git a/plugins/pad/zeropad/Linux/interface.h b/plugins/pad/zeropad/Linux/interface.h new file mode 100644 index 0000000000..3672165062 --- /dev/null +++ b/plugins/pad/zeropad/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_About (void); +GtkWidget* create_Conf (void); diff --git a/plugins/pad/zeropad/Linux/linux.cpp b/plugins/pad/zeropad/Linux/linux.cpp new file mode 100644 index 0000000000..64df9abbde --- /dev/null +++ b/plugins/pad/zeropad/Linux/linux.cpp @@ -0,0 +1,829 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 +#include + +#define JOYSTICK_SUPPORT +#ifdef JOYSTICK_SUPPORT +#include +#endif + +#include "zeropad.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +Display *GSdsp; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; // thread safe +static u32 s_bSDLInit = false; + +// holds all joystick info +class JoystickInfo +{ +public: + JoystickInfo(); + ~JoystickInfo() { Destroy(); } + + void Destroy(); + // opens handles to all possible joysticks + static void EnumerateJoysticks(vector& vjoysticks); + + bool Init(int id, bool bStartThread=true); // opens a handle and gets information + void Assign(int pad); // assigns a joystick to a pad + + void TestForce(); + + const string& GetName() { return devname; } + int GetNumButtons() { return numbuttons; } + int GetNumAxes() { return numaxes; } + int GetNumPOV() { return numpov; } + int GetId() { return _id; } + int GetPAD() { return pad; } + int GetDeadzone(int axis) { return deadzone; } + + void SaveState(); + int GetButtonState(int i) { return vbutstate[i]; } + int GetAxisState(int i) { return vaxisstate[i]; } + void SetButtonState(int i, int state) { vbutstate[i] = state; } + void SetAxisState(int i, int value) { vaxisstate[i] = value; } +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* GetJoy() { return joy; } +#endif + +private: + + string devname; // pretty device name + int _id; + int numbuttons, numaxes, numpov; + int axisrange, deadzone; + int pad; + + vector vbutstate, vaxisstate; + +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* joy; +#endif +}; + +static vector s_vjoysticks; + +extern string s_strIniPath; + +void SaveConfig() +{ + int i, j; + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("ZeroPAD: failed to save ini %s\n", s_strIniPath.c_str()); + return; + } + + for (j=0; j<2; j++) { + for (i=0; i::iterator it; + FORIT(it, s_vjoysticks) delete *it; + s_vjoysticks.clear(); +} + +void _PADupdate(int pad) +{ + pthread_spin_lock(&s_mutexStatus); + status[pad] |= s_keyRelease[pad]; + status[pad] &= ~s_keyPress[pad]; + s_keyRelease[pad] = 0; + s_keyPress[pad] = 0; + pthread_spin_unlock(&s_mutexStatus); +} + +int _GetJoystickIdFromPAD(int pad) +{ + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + return joyid; +} + +void CALLBACK PADupdate(int pad) +{ + int i; + XEvent E; + int keyPress=0,keyRelease=0; + KeySym key; + + // keyboard input + while (XPending(GSdsp) > 0) { + XNextEvent(GSdsp, &E); + switch (E.type) { + case KeyPress: + //_KeyPress(pad, XLookupKeysym((XKeyEvent *)&E, 0)); break; + key = XLookupKeysym((XKeyEvent *)&E, 0); + for (i=0; i= 0 && joyid < (int)s_vjoysticks.size()) { + pjoy = s_vjoysticks[joyid]; + if( SDL_JoystickGetButton((pjoy)->GetJoy(), PAD_GETJOYBUTTON(key)) ) { + status[(pjoy)->GetPAD()] &= ~(1<GetPAD()] |= (1<= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + switch(i) { + case PAD_LX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].x = -g_lanalog[pad].x; + g_lanalog[pad].x += 0x80; + } + else g_lanalog[pad].x = 0x80; + break; + case PAD_LY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].y = -g_lanalog[pad].y; + g_lanalog[pad].y += 0x80; + } + else g_lanalog[pad].y = 0x80; + break; + case PAD_RX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].x = -g_ranalog[pad].x; + g_ranalog[pad].x += 0x80; + } + else g_ranalog[pad].x = 0x80; + break; + case PAD_RY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].y = -g_ranalog[pad].y; + g_ranalog[pad].y += 0x80; + } + else g_ranalog[pad].y = 0x80; + break; + } + } + } + else if( IS_POV(key) ) { + int joyid = PAD_GETJOYID(key); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + if( PAD_GETPOVSIGN(key) && (value<-2048) ) + status[pad] &= ~(1<2048) ) + status[pad] &= ~(1< 0) { + gtk_entry_set_text(GTK_ENTRY(Btn), tmp.c_str()); + } + else + gtk_entry_set_text(GTK_ENTRY(Btn), "Unknown"); + + gtk_object_set_user_data(GTK_OBJECT(Btn), (void*)(PADKEYS*pad+i)); + } + + // check bounds + int joyid = _GetJoystickIdFromPAD(pad); + if( joyid < 0 || joyid >= (int)s_vjoysticks.size() ) { + // get first unused joystick + for(joyid = 0; joyid < s_vjoysticks.size(); ++joyid) { + if( s_vjoysticks[joyid]->GetPAD() < 0 ) + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) { + // select the combo + gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), joyid); + } + else gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), s_vjoysticks.size()); // no gamepad + + int padopts = conf.options>>(16*pad); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverselx")), padopts&PADOPTION_REVERTLX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversely")), padopts&PADOPTION_REVERTLY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverserx")), padopts&PADOPTION_REVERTRX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversery")), padopts&PADOPTION_REVERTRY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "forcefeedback")), padopts&PADOPTION_FORCEFEEDBACK); +} + +void OnConf_Key(GtkButton *button, gpointer user_data) +{ + GdkEvent *ev; + GtkWidget* label = lookup_widget(Conf, GetLabelFromButton(gtk_button_get_label(button)).c_str()); + if( label == NULL ) { + printf("couldn't find correct label\n"); + return; + } + + int id = (int)(uptr)gtk_object_get_user_data(GTK_OBJECT(label)); + int pad = id/PADKEYS; + int key = id%PADKEYS; + unsigned long *pkey = &conf.keys[pad][key]; + + vector::iterator itjoy; + + // save the states +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) (*itjoy)->SaveState(); +#endif + + for (;;) { + ev = gdk_event_get(); + if (ev != NULL) { + if (ev->type == GDK_KEY_PRESS) { + *pkey = ev->key.keyval; + + char* tmp = XKeysymToString(*pkey); + if (tmp != NULL) + gtk_entry_set_text(GTK_ENTRY(label), tmp); + else + gtk_entry_set_text(GTK_ENTRY(label), "Unknown"); + return; + } + } + +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) { + + // MAKE sure to look for changes in the state!! + + for(int i = 0; i < (*itjoy)->GetNumButtons(); ++i) { + int but = SDL_JoystickGetButton((*itjoy)->GetJoy(), i); + if( but != (*itjoy)->GetButtonState(i) ) { + + if( !but ) { // released, we don't really want this + (*itjoy)->SetButtonState(i, 0); + break; + } + + *pkey = PAD_JOYBUTTON((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JBut %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + + for(int i = 0; i < (*itjoy)->GetNumAxes(); ++i) { + int value = SDL_JoystickGetAxis((*itjoy)->GetJoy(), i); + + if( value != (*itjoy)->GetAxisState(i) ) { + + if( abs(value) <= (*itjoy)->GetAxisState(i)) {// we don't want this + // released, we don't really want this + (*itjoy)->SetButtonState(i, value); + break; + } + + + if( abs(value) > 0x3fff ) { + if( key < 16 ) { // POV + *pkey = PAD_POV((*itjoy)->GetId(), value<0, i); + char str[32]; + sprintf(str, "JPOV %d%s", i, value<0?"-":"+"); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + else { // axis + *pkey = PAD_JOYSTICK((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JAxis %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + } + } + } +#endif + } +} + +void OnConf_Pad1(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(0); +} + +void OnConf_Pad2(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(1); +} + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ +// conf.analog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Analog)); + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(Conf); + gtk_main_quit(); + LoadConfig(); // load previous config +} + +void CALLBACK PADconfigure() +{ + LoadConfig(); + + Conf = create_Conf(); + + // recreate + JoystickInfo::EnumerateJoysticks(s_vjoysticks); + + s_devicecombo = lookup_widget(Conf, "joydevicescombo"); + + // fill the combo + char str[255]; + vector::iterator it; + FORIT(it, s_vjoysticks) { + sprintf(str, "%d: %s - but: %d, axes: %d, pov: %d", (*it)->GetId(), (*it)->GetName().c_str(), + (*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumPOV()); + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), str); + } + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), "No Gamepad"); + + UpdateConf(0); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +// GUI event handlers +void on_joydevicescombo_changed(GtkComboBox *combobox, gpointer user_data) +{ + int joyid = gtk_combo_box_get_active(combobox); + + // unassign every joystick with this pad + for(int i = 0; i < (int)s_vjoysticks.size(); ++i) { + if( s_vjoysticks[i]->GetPAD() == s_selectedpad ) + s_vjoysticks[i]->Assign(-1); + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(s_selectedpad); +} + +void on_checkbutton_reverselx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversely_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reverserx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversery_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) { + conf.options |= mask; + + int joyid = gtk_combo_box_get_active(GTK_COMBO_BOX(s_devicecombo)); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->TestForce(); + } + else conf.options &= ~mask; +} + +GtkWidget *About = NULL; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK PADabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK PADtest() { + return 0; +} + +////////////////////////// +// Joystick definitions // +////////////////////////// + +// opens handles to all possible joysticks +void JoystickInfo::EnumerateJoysticks(vector& vjoysticks) +{ +#ifdef JOYSTICK_SUPPORT + + if( !s_bSDLInit ) { + if( SDL_Init(SDL_INIT_JOYSTICK) < 0 ) + return; + SDL_JoystickEventState(SDL_QUERY); + s_bSDLInit = true; + } + + vector::iterator it; + FORIT(it, vjoysticks) delete *it; + + vjoysticks.resize(SDL_NumJoysticks()); + for(int i = 0; i < (int)vjoysticks.size(); ++i) { + vjoysticks[i] = new JoystickInfo(); + vjoysticks[i]->Init(i, true); + } + + // set the pads + for(int pad = 0; pad < 2; ++pad) { + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(pad); + } + +#endif +} + +JoystickInfo::JoystickInfo() +{ +#ifdef JOYSTICK_SUPPORT + joy = NULL; +#endif + _id = -1; + pad = -1; + axisrange = 0x7fff; + deadzone = 2000; +} + +void JoystickInfo::Destroy() +{ +#ifdef JOYSTICK_SUPPORT + if( joy != NULL ) { + if( SDL_JoystickOpened(_id) ) + SDL_JoystickClose(joy); + joy = NULL; + } +#endif +} + +bool JoystickInfo::Init(int id, bool bStartThread) +{ +#ifdef JOYSTICK_SUPPORT + Destroy(); + _id = id; + + joy = SDL_JoystickOpen(id); + if( joy == NULL ) { + printf("failed to open joystick %d\n", id); + return false; + } + + numaxes = SDL_JoystickNumAxes(joy); + numbuttons = SDL_JoystickNumButtons(joy); + numpov = SDL_JoystickNumHats(joy); + devname = SDL_JoystickName(id); + vbutstate.resize(numbuttons); + vaxisstate.resize(numbuttons); + + return true; +#else + return false; +#endif +} + +// assigns a joystick to a pad +void JoystickInfo::Assign(int newpad) +{ + if( pad == newpad ) + return; + + pad = newpad; + + if( pad >= 0 ) { + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYBUTTONS(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYBUTTON(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + else if( IS_JOYSTICK(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYSTICK(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + } + } +} + +void JoystickInfo::SaveState() +{ +#ifdef JOYSTICK_SUPPORT + for(int i = 0; i < numbuttons; ++i) + vbutstate[i] = SDL_JoystickGetButton(joy, i); + for(int i = 0; i < numaxes; ++i) + vaxisstate[i] = SDL_JoystickGetAxis(joy, i); +#endif +} + +void JoystickInfo::TestForce() +{ +} diff --git a/plugins/pad/zeropad/Linux/support.c b/plugins/pad/zeropad/Linux/support.c new file mode 100644 index 0000000000..00aff29822 --- /dev/null +++ b/plugins/pad/zeropad/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/pad/zeropad/Linux/support.h b/plugins/pad/zeropad/Linux/support.h new file mode 100644 index 0000000000..a32649e53c --- /dev/null +++ b/plugins/pad/zeropad/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/pad/zeropad/Linux/zeropad.glade b/plugins/pad/zeropad/Linux/zeropad.glade new file mode 100644 index 0000000000..08c54d6205 --- /dev/null +++ b/plugins/pad/zeropad/Linux/zeropad.glade @@ -0,0 +1,1194 @@ + + + + + + + True + False + ZeroPAD + False + Author: zerofrog(@gmail.com) +Thanks to: + linuzappz <linuzappz@hotmail.com> +florin sasu <florinsasu@hotmail.com> +and SSSPSXPad, TwinPad authors + translator-credits + + + + True + ZeroPAD Configuration Dialog + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + True + PAD1 + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + 0 + False + False + + + + + + True + True + PAD2 + True + GTK_RELIEF_NORMAL + True + False + False + True + PAD1 + + + + 0 + False + False + + + + + + + + + + True + <b>Choose PAD to modify</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Joystick to use for this PAD + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + False + True + True + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 64 + 40 + + + + + + 64 + 24 + True + True + True + True + 0 + + True + • + False + + + 64 + 104 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 168 + 64 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 280 + 64 + + + + + + 64 + 24 + True + True + True + True + 0 + + True + • + False + + + 64 + 168 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 128 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 0 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 64 + 256 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 32 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 104 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 224 + 128 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 304 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 168 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 432 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 256 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 272 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 176 + 272 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 352 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 160 + 352 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 416 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 160 + 416 + + + + + + 64 + 32 + True + True + Select + True + GTK_RELIEF_NORMAL + True + + + + 168 + 32 + + + + + + 64 + 32 + True + True + L1 + True + GTK_RELIEF_NORMAL + True + + + + 64 + 72 + + + + + + 64 + 32 + True + True + Left + True + GTK_RELIEF_NORMAL + True + + + + 0 + 176 + + + + + + 64 + 32 + True + True + Down + True + GTK_RELIEF_NORMAL + True + + + + 64 + 224 + + + + + + 64 + 32 + True + True + Analog + True + GTK_RELIEF_NORMAL + True + + + + 224 + 96 + + + + + + 64 + 32 + True + True + R2 + True + GTK_RELIEF_NORMAL + True + + + + 368 + 0 + + + + + + 64 + 32 + True + True + Start + True + GTK_RELIEF_NORMAL + True + + + + 280 + 32 + + + + + + 64 + 32 + True + True + R1 + True + GTK_RELIEF_NORMAL + True + + + + 368 + 72 + + + + + + 64 + 32 + True + True + Cross + True + GTK_RELIEF_NORMAL + True + + + + 368 + 224 + + + + + + 64 + 32 + True + True + Triangle + True + GTK_RELIEF_NORMAL + True + + + + 368 + 136 + + + + + + 64 + 32 + True + True + Circle + True + GTK_RELIEF_NORMAL + True + + + + 432 + 176 + + + + + + 64 + 32 + True + True + Square + True + GTK_RELIEF_NORMAL + True + + + + 304 + 176 + + + + + + 64 + 32 + True + True + L3 + True + GTK_RELIEF_NORMAL + True + + + + 176 + 240 + + + + + + 64 + 32 + True + True + Up + True + GTK_RELIEF_NORMAL + True + + + + 64 + 136 + + + + + + 64 + 32 + True + True + L2 + True + GTK_RELIEF_NORMAL + True + + + + 64 + 8 + + + + + + 80 + 32 + True + True + Lx + True + GTK_RELIEF_NORMAL + True + + + + 160 + 320 + + + + + + 80 + 32 + True + True + Ly + True + GTK_RELIEF_NORMAL + True + + + + 160 + 384 + + + + + + 80 + 32 + True + True + Rx + True + GTK_RELIEF_NORMAL + True + + + + 272 + 320 + + + + + + 80 + 32 + True + True + Ry + True + GTK_RELIEF_NORMAL + True + + + + 272 + 384 + + + + + + 64 + 32 + True + True + Right + True + GTK_RELIEF_NORMAL + True + + + + 128 + 176 + + + + + + 408 + 16 + True + Analog Controls (move mouse or analog joystick to select) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + True + 0 + + + 48 + 296 + + + + + + 64 + 32 + True + True + R3 + True + GTK_RELIEF_NORMAL + True + + + + 272 + 240 + + + + + + 111 + 22 + True + True + Reverse LX + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 328 + + + + + + 111 + 22 + True + True + Reverse LY + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 352 + + + + + + 111 + 22 + True + True + Reverse RX + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 376 + + + + + + 111 + 22 + True + True + Reverse RY + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 400 + + + + + + 112 + 48 + True + True + Enable Force +Feedback + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 384 + 320 + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/pad/zeropad/Makefile.am b/plugins/pad/zeropad/Makefile.am new file mode 100644 index 0000000000..3ee4bd56cc --- /dev/null +++ b/plugins/pad/zeropad/Makefile.am @@ -0,0 +1,29 @@ +# Create a shared library libZeroPAD +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroPAD.a + +libZeroPAD_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroPAD_a_CFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroPAD_a_CXXFLAGS += -fPIC +libZeroPAD_a_CFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + +if DEBUGBUILD +preext=d +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroPAD +libZeroPAD_SOURCES= +libZeroPAD_DEPENDENCIES = libZeroPAD.a +libZeroPAD_LDFLAGS= @SHARED_LDFLAGS@ +libZeroPAD_LDFLAGS+=-Wl,-soname,@ZEROPAD_SONAME@ +libZeroPAD_LDADD=$(libZeroPAD_a_OBJECTS) + +libZeroPAD_a_SOURCES = zeropad.cpp Linux/linux.cpp Linux/support.c Linux/interface.c diff --git a/plugins/pad/zeropad/PS2Edefs.h b/plugins/pad/zeropad/PS2Edefs.h new file mode 100644 index 0000000000..223a03410f --- /dev/null +++ b/plugins/pad/zeropad/PS2Edefs.h @@ -0,0 +1,855 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBasync USBasync; + +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/pad/zeropad/PS2Etypes.h b/plugins/pad/zeropad/PS2Etypes.h new file mode 100644 index 0000000000..101dba9491 --- /dev/null +++ b/plugins/pad/zeropad/PS2Etypes.h @@ -0,0 +1,88 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifdef _WIN32 +#include +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#define PCSX2_ALIGNED16_DECL(x) x + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/pad/zeropad/Windows/ZeroPAD.def b/plugins/pad/zeropad/Windows/ZeroPAD.def new file mode 100644 index 0000000000..b7428bf63f --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD.def @@ -0,0 +1,18 @@ +LIBRARY "ZeroPAD" + +EXPORTS + PS2EgetLibType @1 + PS2EgetLibName @2 + PS2EgetLibVersion2 @3 + PADinit @7 + PADshutdown @8 + PADopen @9 + PADclose @10 + PADkeyEvent @11 + PADstartPoll @12 + PADpoll @13 + PADquery @16 + PADconfigure @17 + PADtest @18 + PADabout @19 + PADupdate @20 \ No newline at end of file diff --git a/plugins/pad/zeropad/Windows/ZeroPAD.rc b/plugins/pad/zeropad/Windows/ZeroPAD.rc new file mode 100644 index 0000000000..65146382bc --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD.rc @@ -0,0 +1,136 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 3, 1, 443, 266 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Pad Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + PUSHBUTTON "OK",IDOK,320,244,56,18,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,384,244,56,17,NOT WS_TABSTOP + EDITTEXT IDC_ERIGHT,219,31,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Start",IDC_START,219,17,86,15,NOT WS_TABSTOP,WS_EX_TRANSPARENT + EDITTEXT IDC_ER2,129,31,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Select",IDC_SELECT,129,17,86,15,NOT WS_TABSTOP,WS_EX_TRANSPARENT + EDITTEXT IDC_ECIRCLE,340,214,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Cross",IDC2_CROSS,340,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ETRIANGLE,340,185,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Square",IDC_SQUARE,340,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESQUARE,340,155,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Circle",IDC_CIRCLE,340,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ECROSS,340,125,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Triangle",IDC_TRI,340,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ER3,340,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "R2",IDC_R2,340,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESELECT,340,67,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "R1",IDC_R1,340,52,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL2,5,214,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Down",IDC_DOWN,5,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EUP,5,185,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Right",IDC_RIGHT,5,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL1,5,155,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Left",IDC_LEFT,5,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ELEFT,5,125,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Up",IDC_UP,5,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL3,5,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "L2",IDC_L2,5,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESTART,5,67,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "L1",IDC_L1,5,52,86,15,NOT WS_TABSTOP + CONTROL 112,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,94,47,242,183,WS_EX_TRANSPARENT + CONTROL "Tab1",IDC_TABC,"SysTabControl32",0x0,0,0,431,240 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + BOTTOMMARGIN, 265 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Spanish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Spanish resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/pad/zeropad/Windows/ZeroPAD.vcproj b/plugins/pad/zeropad/Windows/ZeroPAD.vcproj new file mode 100644 index 0000000000..effead3529 --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/zeropad/Windows/ZeroPAD_2005.vcproj b/plugins/pad/zeropad/Windows/ZeroPAD_2005.vcproj new file mode 100644 index 0000000000..1accd34282 --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD_2005.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/zeropad/Windows/ZeroPAD_2005_x64.vcproj b/plugins/pad/zeropad/Windows/ZeroPAD_2005_x64.vcproj new file mode 100644 index 0000000000..cbbbef5032 --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD_2005_x64.vcproj @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/zeropad/Windows/ZeroPAD_2008.vcproj b/plugins/pad/zeropad/Windows/ZeroPAD_2008.vcproj new file mode 100644 index 0000000000..ef7a6d7c3f --- /dev/null +++ b/plugins/pad/zeropad/Windows/ZeroPAD_2008.vcproj @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/pad/zeropad/Windows/libs/pthread.h b/plugins/pad/zeropad/Windows/libs/pthread.h new file mode 100644 index 0000000000..a0add29f5c --- /dev/null +++ b/plugins/pad/zeropad/Windows/libs/pthread.h @@ -0,0 +1,1368 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,7,0,0 +#define PTW32_VERSION_STRING "2, 7, 0, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#ifndef RC_INVOKED + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifndef NEED_FTIME +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include +#endif /* HAVE_SIGNAL_H */ + +#include +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#ifndef ENOSYS +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#ifndef EDEADLK +# ifdef EDEADLOCK +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200112L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200112L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200112L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200112L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/plugins/pad/zeropad/Windows/libs/pthreadVC2.lib b/plugins/pad/zeropad/Windows/libs/pthreadVC2.lib new file mode 100644 index 0000000000000000000000000000000000000000..b447a8b71ec31903598669991dac05f24ace9f25 GIT binary patch literal 29280 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 literal 0 HcmV?d00001 diff --git a/plugins/pad/zeropad/Windows/libs/sched.h b/plugins/pad/zeropad/Windows/libs/sched.h new file mode 100644 index 0000000000..10ecb5d7ea --- /dev/null +++ b/plugins/pad/zeropad/Windows/libs/sched.h @@ -0,0 +1,178 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/plugins/pad/zeropad/Windows/libs/semaphore.h b/plugins/pad/zeropad/Windows/libs/semaphore.h new file mode 100644 index 0000000000..ea42ce3703 --- /dev/null +++ b/plugins/pad/zeropad/Windows/libs/semaphore.h @@ -0,0 +1,166 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * 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 in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/plugins/pad/zeropad/Windows/resource.h b/plugins/pad/zeropad/Windows/resource.h new file mode 100644 index 0000000000..eec9db5935 --- /dev/null +++ b/plugins/pad/zeropad/Windows/resource.h @@ -0,0 +1,70 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroPAD.rc +// +#define IDD_DIALOG1 110 +#define IDB_BITMAP1 112 +#define IDC_EL3 1012 +#define IDC_L2 1013 +#define IDC_ER3 1014 +#define IDC_R2 1015 +#define IDC_ESTART 1016 +#define IDC_L1 1017 +#define IDC_ESELECT 1018 +#define IDC_R1 1019 +#define IDC_ECROSS 1020 +#define IDC_TRI 1021 +#define IDC_ESQUARE 1022 +#define IDC_CIRCLE 1023 +#define IDC_ECIRCLE 1024 +#define IDC2_CROSS 1025 +#define IDC_ETRIANGLE 1026 +#define IDC_SQUARE 1027 +#define IDC_ER2 1028 +#define IDC_SELECT 1029 +#define IDC_ER1 1030 +#define IDC_L3 1031 +#define IDC_EDOWN 1032 +#define IDC_R3 1033 +#define IDC_ERIGHT 1034 +#define IDC_START 1035 +#define IDC_ELEFT 1036 +#define IDC_UP 1037 +#define IDC_EUP 1038 +#define IDC_RIGHT 1039 +#define IDC_EL2 1040 +#define IDC_DOWN 1041 +#define IDC_EL1 1042 +#define IDC_LEFT 1043 +#define IDC_TABC 1044 +#define IDC_LAX 1045 +#define IDC_LAY 1046 +#define IDC_RAX 1047 +#define IDC_RAY 1048 +#define IDC_SCROSS 1049 +#define IDC_CHECK1 1050 +#define IDC_LOG 1050 +#define IDC_SCIRCLE 1051 +#define IDC_SSQUARE 1052 +#define IDC_STRIANGLE 1053 +#define IDC_SL3 1054 +#define IDC_SUP 1055 +#define IDC_SDOWN 1056 +#define IDC_SLEFT 1057 +#define IDC_SRIGHT 1058 +#define IDC_SR3 1059 +#define IDC_SL1 1060 +#define IDC_SL2 1061 +#define IDC_SR1 1062 +#define IDC_SR2 1063 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1051 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/pad/zeropad/Windows/win.cpp b/plugins/pad/zeropad/Windows/win.cpp new file mode 100644 index 0000000000..6d7bba56a6 --- /dev/null +++ b/plugins/pad/zeropad/Windows/win.cpp @@ -0,0 +1,454 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 +#include +#include + +#include "resource.h" +#include "../zeropad.h" + +#include +#include + +using namespace std; + +HINSTANCE hInst=NULL; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; +extern u16 status[2]; + +extern string s_strIniPath; +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +WNDPROC GSwndProc=NULL; +HWND GShwnd=NULL; + +void SaveConfig() +{ + char *szTemp; + char szIniFile[256], szValue[256], szProf[256]; + int i, j; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zeropad.ini"); + + for (j=0; j<2; j++) { + for (i=0; i=0x60 && key<=0x69) { + sprintf(buff, "NumPad %c", '0' + key - 0x60); + } + else sprintf(buff, "%c", key); + } + } + else if (key >= 0x1000 && key < 0x2000) + { + sprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); + } + else if (key >= 0x2000 && key < 0x3000) + { + static const char name[][4] = { "MIN", "MAX" }; + const int axis = (key & 0xff); + sprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); + if (index >= 17 && index <= 20) + buff[strlen (buff) -4] = '\0'; + } + else if (key >= 0x3000 && key < 0x4000) + { + static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; + const int pov = (key & 0xff); + sprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); + } + + return buff; +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + HWND hWC; + TCITEM tcI; + int i,key, numkeys; + u8* pkeyboard; + static int disabled=0; + static int padn=0; + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + padn = 0; + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + + for (i=0; i. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/pad/zeropad/mkinstalldirs b/plugins/pad/zeropad/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/pad/zeropad/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec 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. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/pad/zeropad/zeropad.cpp b/plugins/pad/zeropad/zeropad.cpp new file mode 100644 index 0000000000..c9de92c74c --- /dev/null +++ b/plugins/pad/zeropad/zeropad.cpp @@ -0,0 +1,482 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 + +#include "zeropad.h" + +#include +#include +#include +#ifndef _WIN32 +#include +#endif + +#ifdef _DEBUG +char *libraryName = "ZeroPAD (Debug) "; +#else +char *libraryName = "ZeroPAD "; +#endif + +PADAnalog g_lanalog[2], g_ranalog[2]; +PADconf conf; + +keyEvent event; + +u16 status[2]; +int pressure; +string s_strIniPath="inis/zeropad.ini"; + +const unsigned char version = PS2E_PAD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 2; // increase that with each version + + +u32 pads=0; +u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; +u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; +u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; +u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, + {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; +u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; +u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; +u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 +u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 stdmodel[2][8] = { {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}, + {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}}; + +u8 *buf; +int padID[2]; +int padMode[2]; +int curPad; +int curByte; +int curCmd; +int cmdLen; +int ds2mode = 0; // DS Mode at start +FILE *padLog = NULL; + +int POV(u32 direction, u32 angle){ + if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward + if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right + if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward + if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left + if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward + return 0; +} + +void _KeyPress(int pad, u32 key) +{ + int i; + + for (i=0; i> 8; + stdpar[curPad][3] = status[curPad] & 0xff; + stdpar[curPad][4] = g_ranalog[curPad].x; + stdpar[curPad][5] = g_ranalog[curPad].y; + stdpar[curPad][6] = g_lanalog[curPad].x; + stdpar[curPad][7] = g_lanalog[curPad].y; + if (padMode[curPad] == 1) cmdLen = 20; + else cmdLen = 4; + button_check2 = stdpar[curPad][2] >> 4; + switch(stdpar[curPad][3]) + { + case 0xBF: // X + stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); + break; + case 0xDF: // Circle + stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); + break; + case 0xEF: // Triangle + stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); + break; + case 0x7F: // Square + stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); + break; + case 0xFB: // L1 + stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); + break; + case 0xF7: // R1 + stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); + break; + case 0xFE: // L2 + stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); + break; + case 0xFD: // R2 + stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); + break; + default: + stdpar[curPad][14] = 0x00; // Not pressed + stdpar[curPad][13] = 0x00; // Not pressed + stdpar[curPad][12] = 0x00; // Not pressed + stdpar[curPad][15] = 0x00; // Not pressed + stdpar[curPad][16] = 0x00; // Not pressed + stdpar[curPad][17] = 0x00; // Not pressed + stdpar[curPad][18] = 0x00; // Not pressed + stdpar[curPad][19] = 0x00; // Not pressed + break; + } + switch(button_check2) + { + case 0xE: // UP + stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); + break; + case 0xB: // DOWN + stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); + break; + case 0x7: // LEFT + stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); + break; + case 0xD: // RIGHT + stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); + break; + default: + stdpar[curPad][8] = 0x00; // Not pressed + stdpar[curPad][9] = 0x00; // Not pressed + stdpar[curPad][10] = 0x00; // Not pressed + stdpar[curPad][11] = 0x00; // Not pressed + break; + } + buf = stdpar[curPad]; + return padID[curPad]; + + case 0x43: // CONFIG_MODE + cmdLen = 8; + buf = stdcfg[curPad]; + if (stdcfg[curPad][3] == 0xff) return 0xf3; + else return padID[curPad]; + + case 0x44: // SET_MODE_AND_LOCK + cmdLen = 8; + buf = stdmode[curPad]; + return 0xf3; + + case 0x45: // QUERY_MODEL_AND_MODE + cmdLen = 8; + buf = stdmodel[curPad]; + buf[4] = padMode[curPad]; + return 0xf3; + + case 0x46: // ?? + cmdLen = 8; + buf = unk46[curPad]; + return 0xf3; + + case 0x47: // ?? + cmdLen = 8; + buf = unk47[curPad]; + return 0xf3; + + case 0x4c: // QUERY_MODE ?? + cmdLen = 8; + buf = unk4c[curPad]; + return 0xf3; + + case 0x4d: + cmdLen = 8; + buf = unk4d[curPad]; + return 0xf3; + + case 0x4f: // SET_DS2_NATIVE_MODE + cmdLen = 8; + padID[curPad] = 0x79; // setting ds2 mode + ds2mode = 1; // Set DS2 Mode + buf = cmd4f[curPad]; + return 0xf3; + + default: +#ifdef PAD_LOG + PAD_LOG("*PADpoll*: unknown cmd %x\n", value); +#endif + break; + } + } + + switch (curCmd) { + case 0x43: + if(curByte == 2) + { + switch(value){ + case 0: + buf[2] = 0; + buf[3] = 0; + break; + case 1: + buf[2] = 0xff; + buf[3] = 0xff; + break; + } + } + break; + + case 0x44: + if (curByte == 2) { + PADsetMode(curPad, value); + } + break; + + case 0x46: + if(curByte == 2) { + switch(value) { + case 0: // default + buf[5] = 0x2; + buf[6] = 0x0; + buf[7] = 0xA; + break; + case 1: // Param std conf change + buf[5] = 0x1; + buf[6] = 0x1; + buf[7] = 0x14; + break; + } + } + break; + + case 0x4c: + if (curByte == 2) { + switch (value) { + case 0: // mode 0 - digital mode + buf[5] = 0x4; + break; + + case 1: // mode 1 - analog mode + buf[5] = 0x7; + break; + } + } + break; + } + + if (curByte >= cmdLen) return 0; + return buf[curByte++]; +} + +u8 CALLBACK PADpoll(u8 value) +{ + u8 ret; + ret = _PADpoll(value); +#ifdef PAD_LOG + PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); +#endif + return ret; +} + +// PADkeyEvent is called every vsync (return NULL if no event) +static keyEvent s_event; +keyEvent* CALLBACK PADkeyEvent() +{ + s_event = event; + event.event = 0; + return &s_event; +} diff --git a/plugins/pad/zeropad/zeropad.h b/plugins/pad/zeropad/zeropad.h new file mode 100644 index 0000000000..d749ba2a3a --- /dev/null +++ b/plugins/pad/zeropad/zeropad.h @@ -0,0 +1,135 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 __PAD_H__ +#define __PAD_H__ + +#define _CRT_SECURE_NO_DEPRECATE +#include +#include + +#ifdef _WIN32 +#include +#include + +#else + +#include +#include +#include + +#endif + +#include +#include +#include +using namespace std; + +#define PADdefs +extern "C" { +#include "PS2Edefs.h" +} + +extern char *libraryName; + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) + +#define IS_KEYBOARD(key) (key<0x10000) +#define IS_JOYBUTTONS(key) (key>=0x10000 && key<0x20000) // buttons +#define IS_JOYSTICK(key) (key>=0x20000&&key<0x30000) // analog +#define IS_POV(key) (key>=0x30000&&key<0x40000) // uses analog as buttons (cares about sign) +#define IS_MOUSE(key) (key>=0x40000&&key<0x50000) // mouse + +#define PAD_GETKEY(key) ((key)&0xffff) +#define PAD_GETJOYID(key) (((key)&0xf000)>>12) +#define PAD_GETJOYBUTTON(key) ((key)&0xff) +#define PAD_GETJOYSTICK_AXIS(key) ((key)&0xff) +#define PAD_JOYBUTTON(joyid, buttonid) (0x10000|((joyid)<<12)|(buttonid)) +#define PAD_JOYSTICK(joyid, axisid) (0x20000|((joyid)<<12)|(axisid)) +#define PAD_POV(joyid, sign, axisid) (0x30000|((joyid)<<12)|((sign)<<8)|(axisid)) +#define PAD_GETPOVSIGN(key) (((key)&0x100)>>8) + +#define PADKEYS 20 + +#define PADOPTION_FORCEFEEDBACK 1 +#define PADOPTION_REVERTLX 0x2 +#define PADOPTION_REVERTLY 0x4 +#define PADOPTION_REVERTRX 0x8 +#define PADOPTION_REVERTRY 0x10 + +typedef struct { + unsigned long keys[2][PADKEYS]; + int log; + int options; // upper 16 bits are for pad2 +} PADconf; + +typedef struct { + u8 x,y; +} PADAnalog; + +extern PADconf conf; + +extern PADAnalog g_lanalog[2], g_ranalog[2]; +extern FILE *padLog; +#define PAD_LOG __Log + +#define PAD_RY 19 +#define PAD_LY 18 +#define PAD_RX 17 +#define PAD_LX 16 +#define PAD_LEFT 15 +#define PAD_DOWN 14 +#define PAD_RIGHT 13 +#define PAD_UP 12 +#define PAD_START 11 +#define PAD_R3 10 +#define PAD_L3 9 +#define PAD_SELECT 8 +#define PAD_SQUARE 7 +#define PAD_CROSS 6 +#define PAD_CIRCLE 5 +#define PAD_TRIANGLE 4 +#define PAD_R1 3 +#define PAD_L1 2 +#define PAD_R2 1 +#define PAD_L2 0 + +/* end of pad.h */ + +extern keyEvent event; + +extern u16 status[2]; +extern u32 pads; + +int POV(u32 direction, u32 angle); +s32 _PADopen(void *pDsp); +void _PADclose(); +void _KeyPress(int pad, u32 key); +void _KeyRelease(int pad, u32 key); +void PADsetMode(int pad, int mode); +void _PADupdate(int pad); + +void __Log(char *fmt, ...); +void LoadConfig(); +void SaveConfig(); + +void SysMessage(char *fmt, ...); + +#endif + + diff --git a/plugins/spu2/PeopsSPU2/Filemap.txt b/plugins/spu2/PeopsSPU2/Filemap.txt new file mode 100644 index 0000000000..da779e097b --- /dev/null +++ b/plugins/spu2/PeopsSPU2/Filemap.txt @@ -0,0 +1,49 @@ +######################################################################### + +- spu.c / spu.h + main spu handler - generic init and exit funcs + +- adsr.c / adsr.h + adsr handlers + +- dma.c / dma.h + memory transfer funcs + +- registers.c / registers.h / regs.h + spu register handling + +- reverb.c / reverb.h + simple reverb handlers + +- xa.c / xa.h + xa sound handlers + +- cfg.c / cfg.h + configuration dialogs/file reading funcs + +- dsound.c / oss.c / dsoundoss.h + Windows/Linux sound interfaces + +- freeze.c + save state laoding/saving + +- spu2PeopsSound.* + Windows dll related files (including msvc project files) + +- Makefile + Linux makefile... just do a "make" command to build the plugin + +- stdafx.h + main include file + +- externals.h + generic defines/external vars + +- psemuxa.h + psemu pro xa definitions + +- resource.h + Windows resource header + +######################################################################### + diff --git a/plugins/spu2/PeopsSPU2/Makefile b/plugins/spu2/PeopsSPU2/Makefile new file mode 100644 index 0000000000..0b5a12f97e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/Makefile @@ -0,0 +1,75 @@ +############################################################################## +# MAKEFILE FOR THE PEOPS OSS SPU2... just run "make" +############################################################################## + +############################################################################## +# 1. SETS (CCFLAGS3 is used) +############################################################################## +all: spu2PeopsOSS +install: all + +# Set to TRUE to build the ALSA support +USEALSA = FALSE +# Set to TRUE to disable the thread library support - helpful for some Linux distros +NOTHREADLIB = FALSE + +############################################################################## + +CC = gcc +CCFLAGS1 = -fPIC -c -Wall -O3 +CCFLAGS2 = -fPIC -c -Wall -O2 -ffast-math +CCFLAGS3 = -fPIC -c -Wall -O3 -ffast-math -fomit-frame-pointer + +INCLUDE = +LINK = gcc +OBJ = spu.o dma.o freeze.o registers.o +LIB = -lc -lm + +ifeq ($(USEALSA), TRUE) + OBJ+= alsa.o + LIB+= -lasound + LINKFLAGS = -shared -Wl,-soname,libspu2PeopsALSA.so -o libspu2PeopsALSA.so.1.0.3 + CCFLAGS3+= -DUSEALSA +else + OBJ+= oss.o + LINKFLAGS = -shared -Wl,-soname,libspu2PeopsOSS.so.1.6 -fPIC -fomit-frame-pointer -o libspu2PeopsOSS.so.1.6 +endif + +ifeq ($(NOTHREADLIB), TRUE) + CCFLAGS3+= -DNOTHREADLIB +else + LIB+= -lpthread +endif + + + +############################################################################## +# 2. MAIN RULE +############################################################################## + +spu2PeopsOSS : $(OBJ) + $(LINK) $(LINKFLAGS) $(OBJ) $(LIB) + +############################################################################## +# 3. GENERAL RULES +############################################################################## + +%.o : %.c + $(CC) $(CCFLAGS3) $(INCLUDE) $< + +############################################################################## +# 4. SPECIFIC RULES +############################################################################## + +spu.o : spu.c stdafx.h externals.h cfg.h dsoundoss.h regs.h debug.h xa.c reverb.c adsr.c +cfg.o : stdafx.h externals.h +dma.o : dma.c stdafx.h externals.h +freeze.o : freeze.c stdafx.h externals.h registers.h spu.h regs.h +oss.o : oss.c stdafx.h externals.h +alsa.o : alsa.h stdafx.h externals.h +registers.o : registers.c stdafx.h externals.h registers.h regs.h reverb.h + +.PHONY: clean spu2PeopsOSS + +clean: + rm -f *.o *.so.* diff --git a/plugins/spu2/PeopsSPU2/Makefile.win b/plugins/spu2/PeopsSPU2/Makefile.win new file mode 100644 index 0000000000..56ef33daff --- /dev/null +++ b/plugins/spu2/PeopsSPU2/Makefile.win @@ -0,0 +1,79 @@ +# Project: spu2PeopsSound +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = Release/spu2PeopsSound_private.res +OBJ = Release/adsr.o Release/alsa.o Release/cfg.o Release/debug.o Release/dma.o Release/dsound.o Release/freeze.o Release/oss.o Release/record.o Release/registers.o Release/reverb.o Release/spu.o Release/spu2PeopsSound.o Release/StdAfx.o Release/xa.o $(RES) +LINKOBJ = Release/adsr.o Release/alsa.o Release/cfg.o Release/debug.o Release/dma.o Release/dsound.o Release/freeze.o Release/oss.o Release/record.o Release/registers.o Release/reverb.o Release/spu.o Release/spu2PeopsSound.o Release/StdAfx.o Release/xa.o $(RES) +LIBS = -L"lib" -ldsound -lwinmm -luser32 -lgdi32 -ladvapi32 --add-stdcall-alias +INCS = -I"include" -I"D:/Archivos de programa/Microsoft Visual Studio .NET 2003/SDK/v1.1/include" +CXXINCS = -I"lib/gcc/mingw32/3.4.2/include" -I"include/c++/3.4.2/backward" -I"include/c++/3.4.2/mingw32" -I"include/c++/3.4.2" -I"include" +BIN = ../SPU2PeopsDSound.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -O3 +CFLAGS = $(INCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -O3 +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before ../SPU2PeopsDSound.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=../libSPU2PeopsDSound.def +STATICLIB=../libSPU2PeopsDSound.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Release/adsr.o: adsr.c + $(CC) -c adsr.c -o Release/adsr.o $(CFLAGS) + +Release/alsa.o: alsa.c + $(CC) -c alsa.c -o Release/alsa.o $(CFLAGS) + +Release/cfg.o: cfg.c + $(CC) -c cfg.c -o Release/cfg.o $(CFLAGS) + +Release/debug.o: debug.c + $(CC) -c debug.c -o Release/debug.o $(CFLAGS) + +Release/dma.o: dma.c + $(CC) -c dma.c -o Release/dma.o $(CFLAGS) + +Release/dsound.o: dsound.c + $(CC) -c dsound.c -o Release/dsound.o $(CFLAGS) + +Release/freeze.o: freeze.c + $(CC) -c freeze.c -o Release/freeze.o $(CFLAGS) + +Release/oss.o: oss.c + $(CC) -c oss.c -o Release/oss.o $(CFLAGS) + +Release/record.o: record.c + $(CC) -c record.c -o Release/record.o $(CFLAGS) + +Release/registers.o: registers.c + $(CC) -c registers.c -o Release/registers.o $(CFLAGS) + +Release/reverb.o: reverb.c + $(CC) -c reverb.c -o Release/reverb.o $(CFLAGS) + +Release/spu.o: spu.c + $(CC) -c spu.c -o Release/spu.o $(CFLAGS) + +Release/spu2PeopsSound.o: spu2PeopsSound.c + $(CC) -c spu2PeopsSound.c -o Release/spu2PeopsSound.o $(CFLAGS) + +Release/StdAfx.o: StdAfx.c + $(CC) -c StdAfx.c -o Release/StdAfx.o $(CFLAGS) + +Release/xa.o: xa.c + $(CC) -c xa.c -o Release/xa.o $(CFLAGS) + +Release/spu2PeopsSound_private.res: spu2PeopsSound_private.rc + $(WINDRES) -i spu2PeopsSound_private.rc --input-format=rc -o Release/spu2PeopsSound_private.res -O coff diff --git a/plugins/spu2/PeopsSPU2/_bsc.txt b/plugins/spu2/PeopsSPU2/_bsc.txt new file mode 100644 index 0000000000..eadb98a94d --- /dev/null +++ b/plugins/spu2/PeopsSPU2/_bsc.txt @@ -0,0 +1,17 @@ +/nologo /o"Release/spu2PeopsSound.bsc" +".\Release\adsr.sbr" +".\Release\alsa.sbr" +".\Release\cfg.sbr" +".\Release\debug.sbr" +".\Release\dma.sbr" +".\Release\dsound.sbr" +".\Release\freeze.sbr" +".\Release\oss.sbr" +".\Release\psemu.sbr" +".\Release\record.sbr" +".\Release\registers.sbr" +".\Release\reverb.sbr" +".\Release\spu.sbr" +".\Release\spu2PeopsSound.sbr" +".\Release\StdAfx.sbr" +".\Release\xa.sbr" diff --git a/plugins/spu2/PeopsSPU2/adsr.c b/plugins/spu2/PeopsSPU2/adsr.c new file mode 100644 index 0000000000..dabeb4296e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/adsr.c @@ -0,0 +1,668 @@ +/*************************************************************************** + adsr.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/05/14 - xodnizel +// - removed stopping of reverb on sample end +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_ADSR + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// ADSR func +//////////////////////////////////////////////////////////////////////// + +unsigned long RateTable[160]; + +void InitADSR(void) // INIT ADSR +{ + unsigned long r,rs,rd;int i; + + memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++;if(rd==5) {rd=1;rs*=2;} + } + if(r>0x3FFFFFFF) r=0x3FFFFFFF; + + RateTable[i]=r; + } +} + +//////////////////////////////////////////////////////////////////////// + +INLINE void StartADSR(int ch) // MIX ADSR +{ + s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars + s_chan[ch].ADSRX.State=0; + s_chan[ch].ADSRX.EnvelopeVol=0; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixADSR(int ch) // MIX ADSR +{ + if(s_chan[ch].bStop) // should be stopped: + { + if(s_chan[ch].bIgnoreLoop==0){ + s_chan[ch].ADSRX.EnvelopeVol=0; + s_chan[ch].bOn=0; + s_chan[ch].pStart= NULL; //FFX U and E need this else the speech never ends + s_chan[ch].pLoop= s_chan[ch].pCurr; //FFX J needs this else speech never plays :P + s_chan[ch].bStop=1; + s_chan[ch].bIgnoreLoop=0; + return 0; + } + if(s_chan[ch].ADSRX.ReleaseModeExp)// do release + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; + } + } + else + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + s_chan[ch].bOn=0; + s_chan[ch].bStop=1; + s_chan[ch].bIgnoreLoop=0; + //s_chan[ch].bReverb=0; + //s_chan[ch].bNoise=0; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + else // not stopped yet? + { + if(s_chan[ch].ADSRX.State==0) // -> attack + { + if(s_chan[ch].ADSRX.AttackModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + s_chan[ch].ADSRX.State=1; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==1) // -> decay + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0; + if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel) + { + s_chan[ch].ADSRX.State=2; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==2) // -> sustain + { + if(s_chan[ch].ADSRX.SustainIncrease) + { + if(s_chan[ch].ADSRX.SustainModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + } + } + else + { + if(s_chan[ch].ADSRX.SustainModeExp) + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; + } + } + else + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + } + } + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + } + return 0; +} + +#endif + +/* +James Higgs ADSR investigations: + +PSX SPU Envelope Timings +~~~~~~~~~~~~~~~~~~~~~~~~ + +First, here is an extract from doomed's SPU doc, which explains the basics +of the SPU "volume envelope": + +*** doomed doc extract start *** + +-------------------------------------------------------------------------- +Voices. +-------------------------------------------------------------------------- +The SPU has 24 hardware voices. These voices can be used to reproduce sample +data, noise or can be used as frequency modulator on the next voice. +Each voice has it's own programmable ADSR envelope filter. The main volume +can be programmed independently for left and right output. + +The ADSR envelope filter works as follows: +Ar = Attack rate, which specifies the speed at which the volume increases + from zero to it's maximum value, as soon as the note on is given. The + slope can be set to lineair or exponential. +Dr = Decay rate specifies the speed at which the volume decreases to the + sustain level. Decay is always decreasing exponentially. +Sl = Sustain level, base level from which sustain starts. +Sr = Sustain rate is the rate at which the volume of the sustained note + increases or decreases. This can be either lineair or exponential. +Rr = Release rate is the rate at which the volume of the note decreases + as soon as the note off is given. + + lvl | + ^ | /\Dr __ + Sl _| _ / _ \__--- \ + | / ---__ \ Rr + | /Ar Sr \ \ + | / \\ + |/___________________\________ + ->time + +The overal volume can also be set to sweep up or down lineairly or +exponentially from it's current value. This can be done seperately +for left and right. + +Relevant SPU registers: +------------------------------------------------------------- +$1f801xx8 Attack/Decay/Sustain level +bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00| +desc.|Am| Ar |Dr |Sl | + +Am 0 Attack mode Linear + 1 Exponential + +Ar 0-7f attack rate +Dr 0-f decay rate +Sl 0-f sustain level +------------------------------------------------------------- +$1f801xxa Sustain rate, Release Rate. +bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00| +desc.|Sm|Sd| 0| Sr |Rm|Rr | + +Sm 0 sustain rate mode linear + 1 exponential +Sd 0 sustain rate mode increase + 1 decrease +Sr 0-7f Sustain Rate +Rm 0 Linear decrease + 1 Exponential decrease +Rr 0-1f Release Rate + +Note: decay mode is always Expontial decrease, and thus cannot +be set. +------------------------------------------------------------- +$1f801xxc Current ADSR volume +bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00| +desc.|ADSRvol | + +ADSRvol Returns the current envelope volume when + read. +-- James' Note: return range: 0 -> 32767 + +*** doomed doc extract end *** + +By using a small PSX proggie to visualise the envelope as it was played, +the following results for envelope timing were obtained: + +1. Attack rate value (linear mode) + + Attack value range: 0 -> 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 | + ----------------------------------------------------------------- + Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890| + + Note: frames is no. of PAL frames to reach full volume (100% + amplitude) + + Hmm, noticing that the time taken to reach full volume doubles + every time we add 4 to our attack value, we know the equation is + of form: + frames = k * 2 ^ (value / 4) + + (You may ponder about envelope generator hardware at this point, + or maybe not... :) + + By substituting some stuff and running some checks, we get: + + k = 0.00257 (close enuf) + + therefore, + frames = 0.00257 * 2 ^ (value / 4) + If you just happen to be writing an emulator, then you can probably + use an equation like: + + %volume_increase_per_tick = 1 / frames + + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*514)/10000 + ------------------------------------ + +2. Decay rate value (only has log mode) + + Decay value range: 0 -> 15 + + Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | + ------------------------------------------------ + frames | | | | | 6 | 12 | 24 | 47 | + + Note: frames here is no. of PAL frames to decay to 50% volume. + + formula: frames = k * 2 ^ (value) + + Substituting, we get: k = 0.00146 + + Further info on logarithmic nature: + frames to decay to sustain level 3 = 3 * frames to decay to + sustain level 9 + + Also no. of frames to 25% volume = roughly 1.85 * no. of frames to + 50% volume. + + Frag it - just use linear approx. + + ------------------------------------ + Pete: + ms=((1< 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | + ------------------------------------------- + frames | 9 | 19 | 37 | 74 | 147| 293| 587| + + Here, frames = no. of PAL frames for volume amplitude to go from 100% + to 0% (or vice-versa). + + Same formula as for attack value, just a different value for k: + + k = 0.00225 + + ie: frames = 0.00225 * 2 ^ (value / 4) + + For emulation purposes: + + %volume_increase_or_decrease_per_tick = 1 / frames + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*450)/10000 + ------------------------------------ + + +4. Release rate (linear mode) + + Release rate range: 0 -> 31 + + Value | 13 | 14 | 15 | 16 | 17 | + --------------------------------------------------------------- + frames | 18 | 36 | 73 | 146| 292| + + Here, frames = no. of PAL frames to decay from 100% vol to 0% vol + after "note-off" is triggered. + + Formula: frames = k * 2 ^ (value) + + And so: k = 0.00223 + + ------------------------------------ + Pete: + ms=((1< release phase + { + if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now) + { + if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff + { + s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime; + s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume; + s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level + (s_chan[ch].ADSR.ReleaseTime* + s_chan[ch].ADSR.ReleaseVol)/1024; + } + // -> NO release exp mode used (yet) + v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume + lT=s_chan[ch].ADSR.lTime- // -> how much time is past? + s_chan[ch].ADSR.ReleaseStartTime; + l1=s_chan[ch].ADSR.ReleaseTime; + + if(lT we still have to release + { + v=v-((v*lT)/l1); // --> calc new volume + } + else // -> release is over: now really stop that sample + {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + } + else // -> release IS 0: release at once + { + v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0; + } + } + else + {//--------------------------------------------------// not in release phase: + v=1024; + lT=s_chan[ch].ADSR.lTime; + l1=s_chan[ch].ADSR.AttackTime; + + if(lT0) + { + if(l3!=0) v2+=((v-v2)*lT)/l3; + else v2=v; + } + else + { + if(l3!=0) v2-=(v2*lT)/l3; + else v2=v; + } + + if(v2>v) v2=v; + if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + + v=v2; + } + } + } + + //----------------------------------------------------// + // ok, done for this channel, so increase time + + s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms; + + if(v>1024) v=1024; // adjust volume + if(v<0) v=0; + s_chan[ch].ADSR.lVolume=v; // store act volume + + return v; // return the volume factor +*/ + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +/* +----------------------------------------------------------------------------- +Neill Corlett +Playstation SPU envelope timing notes +----------------------------------------------------------------------------- + +This is preliminary. This may be wrong. But the model described herein fits +all of my experimental data, and it's just simple enough to sound right. + +ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally. +The value returned by channel reg 0xC is (envelope_level>>16). + +Each sample, an increment or decrement value will be added to or +subtracted from this envelope level. + +Create the rate log table. The values double every 4 entries. + entry #0 = 4 + + 4, 5, 6, 7, + 8,10,12,14, + 16,20,24,28, ... + + entry #40 = 4096... + entry #44 = 8192... + entry #48 = 16384... + entry #52 = 32768... + entry #56 = 65536... + +increments and decrements are in terms of ratelogtable[n] +n may exceed the table bounds (plan on n being between -32 and 127). +table values are all clipped between 0x00000000 and 0x3FFFFFFF + +when you "voice on", the envelope is always fully reset. +(yes, it may click. the real thing does this too.) + +envelope level begins at zero. + +each state happens for at least 1 cycle +(transitions are not instantaneous) +this may result in some oddness: if the decay rate is uberfast, it will cut +the envelope from full down to half in one sample, potentially skipping over +the sustain level + +ATTACK +------ +- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and + proceed to DECAY. + +Linear attack mode: +- line extends upward to 0x7FFFFFFF +- increment per sample is ratelogtable[(Ar^0x7F)-0x10] + +Logarithmic attack mode: +if envelope_level < 0x60000000: + - line extends upward to 0x60000000 + - increment per sample is ratelogtable[(Ar^0x7F)-0x10] +else: + - line extends upward to 0x7FFFFFFF + - increment per sample is ratelogtable[(Ar^0x7F)-0x18] + +DECAY +----- +- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN. + Do not clip to the sustain level. +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Dr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Dr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Dr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Dr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Dr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Dr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Dr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Dr^0x1F))-0x18+12] + (note that this is the same as the release rate formula, except that + decay rates 10-1F aren't possible... those would be slower in theory) + +SUSTAIN +------- +- no terminating condition except for voice off +- Sd=0 (increase) behavior is identical to ATTACK for both log and linear. +- Sd=1 (decrease) behavior: +Linear sustain decrease: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F] +Logarithmic sustain decrease: +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(Sr^0x7F)-0x1B+0] + 1: ratelogtable[(Sr^0x7F)-0x1B+4] + 2: ratelogtable[(Sr^0x7F)-0x1B+6] + 3: ratelogtable[(Sr^0x7F)-0x1B+8] + 4: ratelogtable[(Sr^0x7F)-0x1B+9] + 5: ratelogtable[(Sr^0x7F)-0x1B+10] + 6: ratelogtable[(Sr^0x7F)-0x1B+11] + 7: ratelogtable[(Sr^0x7F)-0x1B+12] + +RELEASE +------- +- if the envelope level has overflowed to negative, clip to 0 and QUIT. + +Linear release mode: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C] + +Logarithmic release mode: +- line extends to (envelope_level & 0x0FFFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Rr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Rr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Rr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Rr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Rr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Rr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Rr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Rr^0x1F))-0x18+12] + +----------------------------------------------------------------------------- +*/ + diff --git a/plugins/spu2/PeopsSPU2/adsr.h b/plugins/spu2/PeopsSPU2/adsr.h new file mode 100644 index 0000000000..777a0d84c0 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/adsr.h @@ -0,0 +1,28 @@ +/*************************************************************************** + adsr.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +INLINE void StartADSR(int ch); +INLINE int MixADSR(int ch); diff --git a/plugins/spu2/PeopsSPU2/alsa.c b/plugins/spu2/PeopsSPU2/alsa.c new file mode 100644 index 0000000000..de731b8daf --- /dev/null +++ b/plugins/spu2/PeopsSPU2/alsa.c @@ -0,0 +1,206 @@ +/*************************************************************************** + alsa.c - description + ------------------- + begin : Sat Mar 01 2003 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/03/02 - linuzappz +// - fixed XRUN behavior +// +// 2003/03/01 - linuzappz +// - created +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_OSS + +#include "externals.h" + +#ifndef _WINDOWS + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API +#include + +//////////////////////////////////////////////////////////////////////// +// small linux time helper... only used for watchdog +//////////////////////////////////////////////////////////////////////// + +unsigned long timeGetTime() +{ + struct timeval tv; + gettimeofday(&tv, 0); // well, maybe there are better ways + return tv.tv_sec * 1000 + tv.tv_usec/1000; // to do that, but at least it works +} + +//////////////////////////////////////////////////////////////////////// +// oss globals +//////////////////////////////////////////////////////////////////////// + +#define ALSA_MEM_DEF +#include "alsa.h" +static snd_pcm_t *handle = NULL; +static snd_pcm_uframes_t buffer_size; + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_status_t *status; + int pspeed; + int pchannels; + int format; + int buffer_time; + int period_time; + int err; + + if(iDisStereo) pchannels=1; + else pchannels=2; + + pspeed=48000; + format=SND_PCM_FORMAT_S16_LE; + buffer_time=500000; + period_time=buffer_time/4; + + if((err=snd_pcm_open(&handle, "default", + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0) + { + printf("Audio open error: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_nonblock(handle, 0))<0) + { + printf("Can't set blocking moded: %s\n", snd_strerror(err)); + return; + } + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + if((err=snd_pcm_hw_params_any(handle, hwparams))<0) + { + printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0) + { + printf("Access type not available: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0) + { + printf("Sample format not available: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0) + { + printf("Channels count not available: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0) + { + printf("Rate not available: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0) + { + printf("Buffer time error: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0) + { + printf("Period time error: %s\n", snd_strerror(err)); + return; + } + + if((err=snd_pcm_hw_params(handle, hwparams))<0) + { + printf("Unable to install hw params: %s\n", snd_strerror(err)); + return; + } + + snd_pcm_status_alloca(&status); + if((err=snd_pcm_status(handle, status))<0) + { + printf("Unable to get status: %s\n", snd_strerror(err)); + return; + } + + buffer_size=snd_pcm_status_get_avail(status); +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + if(handle != NULL) + { + snd_pcm_drop(handle); + snd_pcm_close(handle); + handle = NULL; + } +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + unsigned long l; + + if(handle == NULL) // failed to open? + return SOUNDSIZE; + l = snd_pcm_avail_update(handle); + if(l<0) return 0; + if(l no? wait + else l=0; // -> else go on + + return l; +} + +//////////////////////////////////////////////////////////////////////// +// FEED SOUND DATA +//////////////////////////////////////////////////////////////////////// + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(handle == NULL) return; + + if(snd_pcm_state(handle) == SND_PCM_STATE_XRUN) + snd_pcm_prepare(handle); + snd_pcm_writei(handle,pSound, + iDisStereo == 1 ? lBytes/2 : lBytes/4); +} + +#endif diff --git a/plugins/spu2/PeopsSPU2/alsa.h b/plugins/spu2/PeopsSPU2/alsa.h new file mode 100644 index 0000000000..4ea9e2140b --- /dev/null +++ b/plugins/spu2/PeopsSPU2/alsa.h @@ -0,0 +1,30 @@ +/*************************************************************************** + alsa.h - description + ------------------- + begin : Sat Mar 01 2003 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef _ALSA_SOUND_H +#define _ALSA_SOUND_H + +#ifdef ALSA_MEM_DEF +#define ALSA_MEM_EXTERN +#else +#define ALSA_MEM_EXTERN extern +#endif + +ALSA_MEM_EXTERN int sound_buffer_size; + +#endif // _ALSA_SOUND_H diff --git a/plugins/spu2/PeopsSPU2/build.sh b/plugins/spu2/PeopsSPU2/build.sh new file mode 100644 index 0000000000..c228930205 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +curdir=`pwd` + +echo ------------------ +echo Building PeopsSPU2 +echo ------------------ + +make $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +if [ -s libspu2Peops*.so* ] +then +cp libspu2Peops*.so* ${PCSX2PLUGINS} +fi + diff --git a/plugins/spu2/PeopsSPU2/cfg.c b/plugins/spu2/PeopsSPU2/cfg.c new file mode 100644 index 0000000000..2ccefbede4 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/cfg.c @@ -0,0 +1,256 @@ +/*************************************************************************** + cfg.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/06/07 - Pete +// - added Linux NOTHREADLIB define +// +// 2003/02/28 - Pete +// - added option for kode54's interpolation and linuzappz's mono mode +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2002/08/04 - Pete +// - small linux bug fix: now the cfg file can be in the main emu directory as well +// +// 2002/06/08 - linuzappz +// - Added combo str for SPUasync, and MAXMODE is now defined as 2 +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_CFG + +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// +// WINDOWS CONFIG/ABOUT HANDLING +//////////////////////////////////////////////////////////////////////// + +#include "resource.h" + +//////////////////////////////////////////////////////////////////////// +// simple about dlg handler +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_COMMAND: + { + switch(LOWORD(wParam)) + {case IDOK: EndDialog(hW,TRUE);return TRUE;} + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +// READ CONFIG: from win registry +//////////////////////////////////////////////////////////////////////// + +// timer mode 2 (spuupdate sync mode) can be enabled for windows +// by setting MAXMODE to 2. +// Attention: that mode is not much tested, maybe the dsound buffers +// need to get adjusted to use that mode safely. Also please note: +// sync sound updates will _always_ cause glitches, if the system is +// busy by, for example, long lasting cdrom accesses. OK, you have +// be warned :) + +#define MAXMODE 2 +//#define MAXMODE 1 + +void ReadConfig(void) +{ + HKEY myKey; + DWORD temp; + DWORD type; + DWORD size; + // init vars + iVolume=3; + iDebugMode=0; + iRecordMode=0; + iUseReverb=0; + iUseInterpolation=2; + iUseTimer = 2; + + if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"Volume",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iVolume=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"DebugMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iDebugMode=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"RecordMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iRecordMode=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseReverb",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseReverb=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseInterpolation",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseInterpolation=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseTimer",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseTimer=(int)temp; + + + RegCloseKey(myKey); + } + + if(iVolume<1) iVolume=1; + if(iVolume>5) iVolume=5; +} + +//////////////////////////////////////////////////////////////////////// +// WRITE CONFIG: in win registry +//////////////////////////////////////////////////////////////////////// + +void WriteConfig(void) +{ + HKEY myKey; + DWORD myDisp; + DWORD temp; + + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); + temp=iVolume; + RegSetValueEx(myKey,"Volume",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iDebugMode; + RegSetValueEx(myKey,"DebugMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iRecordMode; + RegSetValueEx(myKey,"RecordMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseReverb; + RegSetValueEx(myKey,"UseReverb",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseInterpolation; + RegSetValueEx(myKey,"UseInterpolation",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseTimer; + RegSetValueEx(myKey,"UseTimer",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + RegCloseKey(myKey); +} + +//////////////////////////////////////////////////////////////////////// +// INIT WIN CFG DIALOG +//////////////////////////////////////////////////////////////////////// + +BOOL OnInitDSoundDialog(HWND hW) +{ + HWND hWC; + + ReadConfig(); + + hWC=GetDlgItem(hW,IDC_VOLUME); + ComboBox_AddString(hWC, "0: Mute"); + ComboBox_AddString(hWC, "1: low"); + ComboBox_AddString(hWC, "2: medium"); + ComboBox_AddString(hWC, "3: loud"); + ComboBox_AddString(hWC, "4: loudest"); + ComboBox_SetCurSel(hWC,5-iVolume); + if(iDebugMode) CheckDlgButton(hW,IDC_DEBUGMODE,TRUE); + if(iRecordMode) CheckDlgButton(hW,IDC_RECORDMODE,TRUE); + if(iUseTimer==0) CheckDlgButton(hW,IDC_TIMER,TRUE); + + hWC=GetDlgItem(hW,IDC_USEREVERB); + ComboBox_AddString(hWC, "0: No reverb (fastest)"); + ComboBox_AddString(hWC, "1: SPU2 reverb (may be buggy, not tested yet)"); + ComboBox_SetCurSel(hWC,iUseReverb); + + hWC=GetDlgItem(hW,IDC_INTERPOL); + ComboBox_AddString(hWC, "0: None (fastest)"); + ComboBox_AddString(hWC, "1: Simple interpolation"); + ComboBox_AddString(hWC, "2: Gaussian interpolation (good quality)"); + ComboBox_AddString(hWC, "3: Cubic interpolation (better treble)"); + ComboBox_SetCurSel(hWC,iUseInterpolation); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG DLG OK +//////////////////////////////////////////////////////////////////////// + +void OnDSoundOK(HWND hW) +{ + HWND hWC; + + if(IsDlgButtonChecked(hW,IDC_TIMER)) + iUseTimer=0; else iUseTimer=2; + + hWC=GetDlgItem(hW,IDC_VOLUME); + iVolume=5-ComboBox_GetCurSel(hWC); + + hWC=GetDlgItem(hW,IDC_USEREVERB); + iUseReverb=ComboBox_GetCurSel(hWC); + + hWC=GetDlgItem(hW,IDC_INTERPOL); + iUseInterpolation=ComboBox_GetCurSel(hWC); + + if(IsDlgButtonChecked(hW,IDC_DEBUGMODE)) + iDebugMode=1; else iDebugMode=0; + + if(IsDlgButtonChecked(hW,IDC_RECORDMODE)) + iRecordMode=1; else iRecordMode=0; + + WriteConfig(); // write registry + + EndDialog(hW,TRUE); +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG DLG CANCEL +//////////////////////////////////////////////////////////////////////// + +void OnDSoundCancel(HWND hW) +{ + EndDialog(hW,FALSE); +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG PROC +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return OnInitDSoundDialog(hW); + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDCANCEL: OnDSoundCancel(hW);return TRUE; + case IDOK: OnDSoundOK(hW); return TRUE; + } + } + } + return FALSE; +} + diff --git a/plugins/spu2/PeopsSPU2/cfg.h b/plugins/spu2/PeopsSPU2/cfg.h new file mode 100644 index 0000000000..a5af817369 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/cfg.h @@ -0,0 +1,36 @@ +/*************************************************************************** + cfg.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void ReadConfig(void); + + +#ifdef _WINDOWS +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +#else +void StartCfgTool(char * pCmdLine); +#endif diff --git a/plugins/spu2/PeopsSPU2/clean.bat b/plugins/spu2/PeopsSPU2/clean.bat new file mode 100644 index 0000000000..cbeb91c994 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/clean.bat @@ -0,0 +1,3 @@ +del *.o +del *.c~ +del *.h~ \ No newline at end of file diff --git a/plugins/spu2/PeopsSPU2/debug.c b/plugins/spu2/PeopsSPU2/debug.c new file mode 100644 index 0000000000..1aa65b3958 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/debug.c @@ -0,0 +1,442 @@ +/*************************************************************************** + debug.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - update mute checkboxes if core selection changes +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/01/06 - Pete +// - added Neil's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_DEBUG + +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// +// WINDOWS DEBUG DIALOG HANDLING +//////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS + +#include "resource.h" + +//#define SMALLDEBUG +//#include + +//////////////////////////////////////////////////////////////////////// +// display debug infos + +const COLORREF crStreamCol[]={ + RGB( 0, 0, 0), + RGB(255,255,255), + RGB(128, 0,128), + RGB( 0,128, 0), + RGB( 0, 0,255), + RGB(255, 0, 0) + }; + +const COLORREF crAdsrCol[] ={ + RGB( 0, 0, 0), + RGB(255, 0, 0), + RGB( 0,255, 0), + RGB(255, 0,255), + RGB( 0, 0,255), + RGB( 0, 0, 0), + }; + +HBRUSH hBStream[6]; // brushes for stream lines +HPEN hPAdsr[6]; // pens for adsr lines +int iSelChannel=0; // user selected channel +int iCoreOffset=0; + +//////////////////////////////////////////////////////////////////////// +// display the sound data waves: no subclassing used, so the +// area will not be redrawn... but faster that way, and good enuff +// for debugging purposes + +void DisplayStreamInfos(HWND hW) +{ + HWND hWS=GetDlgItem(hW,IDC_SAREA); + HDC hdc;RECT r;HBRUSH hBO;int ch,dy,i,j,id; + + //----------------------------------------------------// + + GetClientRect(hWS,&r); // get size of stream display + hdc=GetDC(hWS); // device context + r.right--; // leave the right border intact + ScrollDC(hdc,-1,0,&r,&r,NULL,NULL); // scroll one pixel to the left + + //----------------------------------------------------// + + hBO=SelectObject(hdc,hBStream[0]); // clean the right border + PatBlt(hdc,r.right-1,0,1,r.bottom,PATCOPY); + + //----------------------------------------------------// + + dy=r.bottom/HLFCHAN; // size of one channel area + + for(ch=0;ch get one channel data (-32k ... 32k) + j=(dy*j)/33768; if(j==0) j=1; // -> adjust to display coords + i=(dy/2)+(ch*r.bottom/HLFCHAN)-j/2; // -> position where to paint it + + + + if (s_chan[ch+iCoreOffset].iMute) id=1; // -> get color id + else if(s_chan[ch+iCoreOffset].bNoise) id=2; + else if(s_chan[ch+iCoreOffset].bFMod==2) id=3; + else if(s_chan[ch+iCoreOffset].bFMod==1) id=4; + else id=5; + + SelectObject(hdc,hBStream[id]); // -> select the brush + PatBlt(hdc,r.right-1,i,1,j,PATCOPY); // -> paint the value line + } + + if(ch) SetPixel(hdc,r.right-1, // -> not first line? + ch*r.bottom/HLFCHAN,RGB(0,0,0)); // --> draw the line (one dot scrolled to the left) + } + + //----------------------------------------------------// + + SelectObject(hdc,hBO); // repair brush + + ReleaseDC(hWS,hdc); // release context +} + +//////////////////////////////////////////////////////////////////////// +// display adsr lines: also no subclassing for repainting used + +void DisplayADSRInfos(HWND hW) +{ + HWND hWS=GetDlgItem(hW,IDC_ADSR); + HDC hdc;RECT r;HBRUSH hBO;char szB[16]; + int ch=iSelChannel+iCoreOffset,dx,dy,dm,dn,ia,id,is,ir; + + //----------------------------------------------------// get display size + + GetClientRect(hWS,&r); + hdc=GetDC(hWS); + + //----------------------------------------------------// clean the area + + hBO=SelectObject(hdc,hBStream[0]); + PatBlt(hdc,0,0,r.right,r.bottom,PATCOPY); + r.left++;r.right-=2;r.top++;r.bottom-=2; // shrink the display rect for better optics + + //----------------------------------------------------// + + ia=min(s_chan[ch].ADSR.AttackTime,10000); // get adsr, but limit it for drawing + id=min(s_chan[ch].ADSR.DecayTime,10000); + is=min(s_chan[ch].ADSR.SustainTime,10000); + ir=min(s_chan[ch].ADSR.ReleaseTime,10000); + + dx=ia+id+is+ir; // get the dx in (limited) adsr units + + // set the real values to the info statics + SetDlgItemInt(hW,IDC_SADSR1,s_chan[ch].ADSRX.AttackRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR2,s_chan[ch].ADSRX.DecayRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR3,s_chan[ch].ADSRX.SustainRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR4,s_chan[ch].ADSRX.ReleaseRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR5,s_chan[ch].ADSRX.SustainLevel,FALSE); + SetDlgItemInt(hW,IDC_SADSR6,s_chan[ch].ADSRX.SustainIncrease,TRUE); + SetDlgItemInt(hW,IDC_SADSR7,s_chan[ch].ADSRX.lVolume,TRUE); + wsprintf(szB,"%08lX",s_chan[ch].ADSRX.EnvelopeVol); + SetDlgItemText(hW,IDC_SADSR8,szB); + + if(dx) // something to draw? + { + HPEN hPO=SelectObject(hdc,hPAdsr[1]); // sel A pen + dn=r.left; + MoveToEx(hdc,dn,r.bottom,NULL); // move to bottom left corner + + dn+=(ia*r.right)/dx; // calc A x line pos + LineTo(hdc,dn,r.top); // line to AxPos,top + + SelectObject(hdc,hPAdsr[2]); // sel D pen + dn+=(id*r.right)/dx; // calc D x line pos + dy=r.top+((1024-s_chan[ch].ADSR.SustainLevel)* // calc the D y pos + r.bottom)/1024; // (our S level is ranged from 0 to 1024) + LineTo(hdc,dn,dy); // line to DxPos,SLevel + + SelectObject(hdc,hPAdsr[3]); // sel S pen + if(s_chan[ch].ADSR.SustainTime>10000) + dm=1; // we have to fake the S values... S will + else // inc/decrease until channel stop... + if(s_chan[ch].ADSR.SustainTime==0) + dm=0; // we dunno here when this will happen, + else + dm=21-(((s_chan[ch].ADSR.SustainTime/500))); // so we do some more or less angled line, + dy=dy-(s_chan[ch].ADSR.SustainModeDec*dm); // roughly depending on the S time + if(dy>r.bottom) dy=r.bottom; + if(dy>1); + SetDlgItemText(hW,IDC_CI10,szB); + if(s_chan[ch].pCurr==(unsigned char *)-1) + SetDlgItemText(hW,IDC_CI11,"FFFFFFFF"); + else + { + wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pCurr-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_CI11,szB); + } + + wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pLoop-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_CI12,szB); + SetDlgItemInt(hW,IDC_CI13,s_chan[ch].iRightVolume,TRUE); + SetDlgItemInt(hW,IDC_CI14,s_chan[ch].iLeftVolume,TRUE); + SetDlgItemInt(hW,IDC_CI15,s_chan[ch].iActFreq,TRUE); + SetDlgItemInt(hW,IDC_CI16,s_chan[ch].iUsedFreq,TRUE); + +// wsprintf(szB,"%04x",s_chan[ch].iRightVolRaw); + wsprintf(szB,"R%d",s_chan[ch].bVolumeR); + SetDlgItemText(hW,IDC_CI17,szB); +// wsprintf(szB,"%04x",s_chan[ch].iLeftVolRaw); + wsprintf(szB,"L%d",s_chan[ch].bVolumeL); + SetDlgItemText(hW,IDC_CI18,szB); + + wsprintf(szB,"%08lX",s_chan[ch].iNextAdr); + SetDlgItemText(hW,IDC_CI19,szB); + + // generic infos + /*if(pSpuIrq[ch]==0) + SetDlgItemText(hW,IDC_STA1,"FFFFFFFF"); + else + {*/ + wsprintf(szB,"%08lX",((unsigned long)pSpuIrq[ch/24]-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_STA1,szB); + /*}*/ + + wsprintf(szB,"%04X",spuCtrl2[ch/24]); + SetDlgItemText(hW,IDC_STA2,szB); + wsprintf(szB,"%04X",spuStat2[ch/24]); + SetDlgItemText(hW,IDC_STA3,szB); + + wsprintf(szB,"%08lX",spuAddr2[ch/24]); + SetDlgItemText(hW,IDC_STA4,szB); + } + +//////////////////////////////////////////////////////////////////////// +// display everything (called in dialog timer for value refreshing) + +void DisplayDebugInfos(HWND hW) +{ + DisplayStreamInfos(hW); + DisplayADSRInfos(hW); + DisplayChannelInfos(hW); +} + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); +EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg); + +//////////////////////////////////////////////////////////////////////// +// main debug dlg handler + +char old_buffer[128]; +int iBuffRepeats=0; + +BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + //--------------------------------------------------// init + case WM_INITDIALOG: + { + int i; + ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts + iSelChannel=0; // sel first channel + iCoreOffset=0; + CheckRadioButton(hW,IDC_CHAN1,IDC_CHAN24,IDC_CHAN1); + CheckRadioButton(hW,IDC_CORE1,IDC_CORE2,IDC_CORE1); + + memset(old_buffer,0,128); + // create brushes/pens + hBStream[0]=CreateSolidBrush(GetSysColor(COLOR_3DFACE)); + hPAdsr[0]=CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DFACE)); + for(i=1;i<6;i++) + { + hBStream[i]=CreateSolidBrush(crStreamCol[i]); + hPAdsr[i]=CreatePen(PS_SOLID,0,crAdsrCol[i]); + } + SetTimer(hW,999,50,NULL); // now create update timer + return TRUE; + } + //--------------------------------------------------// destroy + case WM_DESTROY: + { + int i; + KillTimer(hW,999); // first kill timer + for(i=0;i<6;i++) // then kill brushes/pens + { + DeleteObject(hBStream[i]); + DeleteObject(hPAdsr[i]); + } + }break; + //--------------------------------------------------// timer + case WM_TIMER: + { + if(wParam==999) DisplayDebugInfos(hW); // update all values + }break; + //--------------------------------------------------// command + case WM_COMMAND: + { + if(wParam==IDCANCEL) iDebugMode=2; // cancel? raise flag for destroying the dialog + + if(wParam>=IDC_CORE1 && wParam<=IDC_CORE2) // core clicked? + { + int i; + + if(IsDlgButtonChecked(hW,IDC_CORE1)) // -> sel correct half of channels + iCoreOffset=0; + else iCoreOffset=24; + + for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) + { + if(s_chan[i-IDC_MUTE1+iCoreOffset].iMute) + CheckDlgButton(hW,i,TRUE); + else CheckDlgButton(hW,i,FALSE); + } + + InvalidateRect(hW,NULL,TRUE); + UpdateWindow(hW); + } + + if(wParam>=IDC_MUTE1 && wParam<=IDC_MUTE24) // mute clicked? + { + if(IsDlgButtonChecked(hW,wParam)) // -> mute/unmute it + s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=1; + else + s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=0; + } + // all mute/unmute + if(wParam==IDC_MUTEOFF) SendMessage(hW,WM_MUTE,0,0); + if(wParam==IDC_MUTEON) SendMessage(hW,WM_MUTE,1,0); + + if(wParam>=IDC_CHAN1 && wParam<=IDC_CHAN24) // sel channel + { + if(IsDlgButtonChecked(hW,wParam)) + { + iSelChannel=wParam-IDC_CHAN1; + SetDlgItemInt(hW,IDC_CHANNUM,iSelChannel+1,FALSE); + } + } + }break; + //--------------------------------------------------// mute + case WM_MUTE: + { // will be called by the mute/unmute all button and on savestate load + int i; + for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) + { + CheckDlgButton(hW,i,wParam); + if(wParam) + s_chan[i-IDC_MUTE1+iCoreOffset].iMute=1; + else + s_chan[i-IDC_MUTE1+iCoreOffset].iMute=0; + } + }break; + //--------------------------------------------------// size + case WM_SIZE: + if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window + break; + //--------------------------------------------------// setcursor + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow + return TRUE; + } + //--------------------------------------------------// + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +#include +extern FILE * LogFile; +void logprintf(LPCTSTR pFormat, ...) +{ + if(iDebugMode!=1) return; + if(!IsWindow(hWDebug)) return; + else + { + va_list list; + + va_start(list,pFormat); + vfprintf(LogFile, pFormat, list); + va_end(list); + } + +} + +#endif + diff --git a/plugins/spu2/PeopsSPU2/debug.h b/plugins/spu2/PeopsSPU2/debug.h new file mode 100644 index 0000000000..4999b42d2b --- /dev/null +++ b/plugins/spu2/PeopsSPU2/debug.h @@ -0,0 +1,34 @@ +/*************************************************************************** + debug.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifdef _WIN32 +BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +void logprintf(LPCTSTR pFormat, ...); +#else + +#define logprintf 0&& + +#endif diff --git a/plugins/spu2/PeopsSPU2/dma.c b/plugins/spu2/PeopsSPU2/dma.c new file mode 100644 index 0000000000..0bebed05e1 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/dma.c @@ -0,0 +1,414 @@ +/*************************************************************************** + dma.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" +#include "externals.h" +#include "registers.h" +#include "debug.h" +extern void (CALLBACK *irqCallbackDMA4)(); // func of main emu, called on spu irq +extern void (CALLBACK *irqCallbackDMA7)(); // func of main emu, called on spu irq +extern void (CALLBACK *irqCallbackSPU2)(); // func of main emu, called on spu irq +unsigned short interrupt; +extern unsigned long SPUCycles; +unsigned long SPUStartCycle[2]; +unsigned long SPUTargetCycle[2]; + +unsigned long MemAddr[2]; + +ADMA Adma4; +ADMA Adma7; + +//////////////////////////////////////////////////////////////////////// +// READ DMA (many values) +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2readDMA4Mem(unsigned short * pusPSXMem,int iSize) +{ + int i; +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("READDMA4 %X - %X\r\n",spuAddr2[0],iSize); + + if(spuAddr2[0]<=0x1fff) + logprintf("# OUTPUT AREA ACCESS #############\r\n"); + } + +#endif + + for(i=0;i0xfffff) spuAddr2[0]=0; // wrap + } + + spuAddr2[0]+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + + + iSpuAsyncWait=0; + + // got from J.F. and Kanodin... is it needed? + spuStat2[0]&=~0x80; // DMA complete + //if(regArea[(PS2_C0_ADMAS)>>1] != 1) { + // if((regArea[(PS2_C0_ATTR)>>1] & 0x30)) { + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = iSize; + interrupt |= (1<<1); + // } +//} + //regArea[(PS2_C0_ADMAS)>>1] = 0; +} + +EXPORT_GCC void CALLBACK SPU2readDMA7Mem(unsigned short * pusPSXMem,int iSize) +{ + int i; +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("READDMA7 %X - %X\r\n",spuAddr2[1],iSize); + + if(spuAddr2[1]<=0x1fff) + logprintf("# OUTPUT AREA ACCESS #############\r\n"); + } +#endif + + for(i=0;i0xfffff) spuAddr2[1]=0; // wrap + } + +spuAddr2[1]+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + + iSpuAsyncWait=0; + + // got from J.F. and Kanodin... is it needed? + spuStat2[1]&=~0x80; // DMA complete + // if(regArea[(PS2_C1_ADMAS)>>1] != 2) { + // if((regArea[(PS2_C1_ATTR)>>1] & 0x30)) { + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = iSize; + interrupt |= (1<<2); + // } + //} + //regArea[(PS2_C1_ADMAS)>>1] = 0; +} + +//////////////////////////////////////////////////////////////////////// +// WRITE DMA (many values) +//////////////////////////////////////////////////////////////////////// + + +// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory +// Left and Right channels are always interleaved together in the transfer so +// the AutoDMA's deinterleaves them and transfers them. An interrupt is +// generated when half of the buffer (256 short-words for left and 256 +// short-words for right ) has been transferred. Another interrupt occurs at +// the end of the transfer. + +int ADMAS4Write() +{ + if(interrupt & 0x2) return 0; + if(Adma4.AmountLeft <= 0) { + if(Adma4.TempAmount == 0) return 1; + Adma4.AmountLeft = Adma4.TempAmount; + Adma4.MemAddr = Adma4.TempMem; + Adma4.TempMem = NULL; + Adma4.TempAmount = 0; + } + Adma4.TransferAmount = min(512, Adma4.AmountLeft); + if(Adma4.ADMAPos == 512) Adma4.ADMAPos = 0; + +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("ADMAWRITE4 %X - %X\r\n",spuAddr2[0],Adma4.AmountLeft); + if(Adma4.AmountLeft<512) logprintf("FUCK YOU %X\r\n",Adma4.AmountLeft); + } +#endif + + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spuMem + Adma4.ADMAPos + 0x2000),(short*)Adma4.MemAddr,Adma4.TransferAmount); + Adma4.MemAddr += Adma4.TransferAmount / 2; + memcpy((short*)(spuMem + Adma4.ADMAPos + 0x2200),(short*)Adma4.MemAddr,Adma4.TransferAmount); + Adma4.MemAddr += Adma4.TransferAmount / 2; + + Adma4.ADMAPos += Adma4.TransferAmount / 2; + MemAddr[0] += Adma4.TransferAmount * 2; + //MemAddr[0] += 1024; + Adma4.AmountLeft-= Adma4.TransferAmount; + spuStat2[0]&=~0x80; + + if(Adma4.AmountLeft == 0) + { + if(Adma4.IRQ == 0){ + Adma4.IRQ = 1; + irqCallbackDMA4(); + } + } + return 0; +} + + +int ADMAS7Write() +{ + if(interrupt & 0x4) return 0; + if(Adma7.AmountLeft <= 0) { + if(Adma7.TempAmount == 0) return 1; + Adma7.AmountLeft = Adma7.TempAmount; + Adma7.MemAddr = Adma7.TempMem; + Adma7.TempMem = NULL; + Adma7.TempAmount = 0; + } + Adma7.TransferAmount = min(512, Adma7.AmountLeft); + if(Adma7.ADMAPos == 512) Adma7.ADMAPos = 0; + +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("ADMAWRITE7 %X - %X\r\n",spuAddr2[1],Adma7.AmountLeft); + if(Adma7.AmountLeft<512) logprintf("FUCK YOU %X\r\n",Adma7.AmountLeft); + } +#endif + + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spuMem + Adma7.ADMAPos + 0x2400),(short*)Adma7.MemAddr,Adma7.TransferAmount); + Adma7.MemAddr += Adma7.TransferAmount / 2; + memcpy((short*)(spuMem + Adma7.ADMAPos + 0x2600),(short*)Adma7.MemAddr,Adma7.TransferAmount); + Adma7.MemAddr += Adma7.TransferAmount / 2; + + Adma7.ADMAPos += Adma7.TransferAmount / 2; + MemAddr[1] += Adma7.TransferAmount * 2; + //MemAddr[1] += 1024; + Adma7.AmountLeft-=Adma7.TransferAmount; + spuStat2[1]&=~0x80; + + if(Adma7.AmountLeft == 0) + { + if(Adma7.IRQ == 0){ + Adma7.IRQ = 1; + irqCallbackDMA7(); + } + } + return 0; +} + +#include +extern FILE * LogFile; +EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(short * pMem,unsigned int iSize) +{ + //if(Adma4.AmountLeft > 0) return; + if(regArea[PS2_C0_ADMAS] & 0x1 && (spuCtrl2[0] & 0x30) == 0 && iSize) + { + //fwrite(pMem,iSize<<1,1,LogFile); + // memset(&Adma4,0,sizeof(ADMA)); + //if( !Adma4.Enabled ) + // Adma4.Index = 0; + //Adma4.ADMAPos = 0; + if((Adma4.ADMAPos == 512 && Adma4.Index <= 256) || (Adma4.ADMAPos == 256 && Adma4.Index >= 256) || Adma4.AmountLeft >= 512) { + Adma4.TempMem = pMem; + Adma4.TempAmount = iSize; + } else { + Adma4.MemAddr = pMem; + Adma4.AmountLeft += iSize; + ADMAS4Write(); + } + return; + } + +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("WRITEDMA4 %X - %X\r\n",spuAddr2[0],iSize); + } +#endif + + memcpy((unsigned char*)(spuMem+spuAddr2[0]),(unsigned char*)pMem,iSize<<1); + if(spuCtrl2[0]&0x40 && (spuIrq2[0] >= spuAddr2[0] && spuIrq2[0] <= (spuAddr2[0] + iSize))){ + regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 0x4; + irqCallbackSPU2(); + } + spuAddr2[0] += iSize; + + if(spuAddr2[0]>0x23FF) spuAddr2[0] = 0x2000; + + MemAddr[0] += iSize<<1; + spuStat2[0]&=~0x80; + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = 1;//iSize; + interrupt |= (1<<1); +} + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) +{ +#ifdef _DEBUG + static FILE* g_fLogSound = NULL; + + char* left = (char*)pleft; + char* right = (char*)pright; + unsigned short* tempbuf; + int i; + + if( g_fLogSound == NULL ) { + g_fLogSound = fopen("rawsndbuf.pcm", "wb"); + if( g_fLogSound == NULL ) + return; + } + + tempbuf = (unsigned short*)malloc(4*numsamples); + + for(i = 0; i < numsamples; ++i) { + tempbuf[2*i+0] = *(unsigned short*)left; + tempbuf[2*i+1] = *(unsigned short*)right; + left += leftstride; + right += rightstride; + } + + fwrite(&tempbuf[0], 4*numsamples, 1, g_fLogSound); + free(tempbuf); +#endif +} + +EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(unsigned short * pMem,int iSize) +{ + // For AutoDMA, the ATTR register's bit 5 and 6 are cleared. + // bit 5 means Data Input Thru Register + // bit 6 means Data Input Thru DMA + //if(Adma7.AmountLeft > 0) return; + + if((regArea[PS2_C1_ADMAS] & 0x2) && (spuCtrl2[1] & 0x30) == 0 && iSize) + { + //fwrite(pMem,iSize<<1,1,LogFile); + // memset(&Adma7,0,sizeof(ADMA)); + //if( !Adma7.Enabled ) + // Adma7.Index = 0; + //Adma7.ADMAPos = 0; + if((Adma7.ADMAPos == 512 && Adma7.Index <= 256) || (Adma7.ADMAPos == 256 && Adma7.Index >= 256) || Adma7.AmountLeft >= 512) { + Adma7.TempMem = pMem; + Adma7.TempAmount = iSize; + } else { + Adma7.MemAddr = pMem; + Adma7.AmountLeft += iSize; + ADMAS7Write(); + } + return; + } +#ifdef _WINDOWS + if(iDebugMode==1) + { + logprintf("WRITEDMA7 %X - %X\r\n",spuAddr2[1],iSize); + } +#endif + + memcpy((short*)(spuMem+spuAddr2[1]),(short*)pMem,iSize<<1); + if(spuCtrl2[1]&0x40 && (spuIrq2[1] >= spuAddr2[1] && spuIrq2[1] <= (spuAddr2[1] + iSize))){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + spuAddr2[1] += iSize; + + if(spuAddr2[1]>0x27FF) spuAddr2[1] = 0x2400; + + MemAddr[1] += iSize<<1; + spuStat2[1]&=~0x80; + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = 1;//iSize; + interrupt |= (1<<2); +} + + +//////////////////////////////////////////////////////////////////////// +// INTERRUPTS +//////////////////////////////////////////////////////////////////////// + +void InterruptDMA4(void) +{ +// taken from linuzappz NULL spu2 +// spu2Rs16(CORE0_ATTR)&= ~0x30; +// spu2Rs16(REG__1B0) = 0; +// spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80; + +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("IRQDMA4\r\n"); +#endif + Adma4.IRQ = 0; + spuCtrl2[0]&=~0x30; + spuStat2[0]|=0x80; +} + +EXPORT_GCC void CALLBACK SPU2interruptDMA4(void) +{ + InterruptDMA4(); +} + +void InterruptDMA7(void) +{ +// taken from linuzappz NULL spu2 +// spu2Rs16(CORE1_ATTR)&= ~0x30; +// spu2Rs16(REG__5B0) = 0; +// spu2Rs16(SPU2_STATX_DREQ)|= 0x80; + +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("IRQDMA7\r\n"); +#endif + Adma7.IRQ = 0; + spuStat2[1]|=0x80; + spuCtrl2[1]&=~0x30; +} + +EXPORT_GCC void CALLBACK SPU2interruptDMA7(void) +{ + InterruptDMA7(); +} + +EXPORT_GCC void CALLBACK SPU2WriteMemAddr(int core, unsigned long value) +{ + MemAddr[core] = value; +} + +EXPORT_GCC unsigned long CALLBACK SPU2ReadMemAddr(int core) +{ + return MemAddr[core]; +} \ No newline at end of file diff --git a/plugins/spu2/PeopsSPU2/dma.h b/plugins/spu2/PeopsSPU2/dma.h new file mode 100644 index 0000000000..4314b60a35 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/dma.h @@ -0,0 +1,28 @@ +/*************************************************************************** + dma.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void InterruptDMA4(void); +void InterruptDMA7(void); diff --git a/plugins/spu2/PeopsSPU2/dsound.c b/plugins/spu2/PeopsSPU2/dsound.c new file mode 100644 index 0000000000..a35b2d8b43 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/dsound.c @@ -0,0 +1,268 @@ +/*************************************************************************** + dsound.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/01/12 - Pete +// - added recording funcs +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_DSOUND + +#include "externals.h" + +#ifdef _WINDOWS +#define _LPCWAVEFORMATEX_DEFINED +#include "dsound.h" + +#include "record.h" + +//////////////////////////////////////////////////////////////////////// +// dsound globals +//////////////////////////////////////////////////////////////////////// + +LPDIRECTSOUND lpDS; +LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; +DSBUFFERDESC dsbd; +DSBUFFERDESC dsbdesc; +DSCAPS dscaps; +DSBCAPS dsbcaps; + +unsigned long LastWrite=0xffffffff; +unsigned long LastWriteS=0xffffffff; +unsigned long LastPlay=0; + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + HRESULT dsval;WAVEFORMATEX pcmwf; + + dsval = DirectSoundCreate(NULL,&lpDS,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"DirectSoundCreate!","Error",MB_OK); + return; + } + + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) + { + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) + { + MessageBox(hWMain,"SetCooperativeLevel!","Error",MB_OK); + return; + } + } + + memset(&dsbd,0,sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain, "CreateSoundBuffer (Primary)", "Error",MB_OK); + return; + } + + memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = 48000; + + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + dsval=IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); + if(dsval!=DS_OK) + { + MessageBox(hWMain, "SetFormat!", "Error",MB_OK); + return; + } + + dscaps.dwSize = sizeof(DSCAPS); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSound_GetCaps(lpDS,&dscaps); + IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbdesc.dwBufferBytes = SOUNDSIZE; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) + { + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); + return; + } + } + + + + dsval=IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"Play (Primary)","Error",MB_OK); + return; + } + + dsval=IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"Play (Secondary1)","Error",MB_OK); + return; + } + +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + int iRes; + + if(iDoRecord) RecordStop(); + + if(lpDSBSECONDARY1!=NULL) + { + IDirectSoundBuffer_Stop(lpDSBSECONDARY1); + iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + lpDSBSECONDARY1=NULL; + } + + if(lpDSBPRIMARY!=NULL) + { + IDirectSoundBuffer_Stop(lpDSBPRIMARY); + iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + lpDSBPRIMARY=NULL; + } + + if(lpDS!=NULL) + { + iRes=IDirectSound_Release(lpDS); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSound_Release(lpDS); + lpDS=NULL; + } + +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + unsigned long cplay,cwrite; + + if(LastWrite==0xffffffff) return 0; + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(cplay>SOUNDSIZE) return SOUNDSIZE; + + if(cplay>2; + + lpSS=(unsigned long *)pSound; + while(dw) {*lpSD++=*lpSS++;dw--;} + + if(lpvPtr2) + { + lpSD=(unsigned long *)lpvPtr2; + dw=dwBytes2>>2; + while(dw) {*lpSD++=*lpSS++;dw--;} + } + + IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); + LastWrite+=lBytes; + if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE; + LastPlay=cplay; +} +#endif + + + diff --git a/plugins/spu2/PeopsSPU2/dsound.h b/plugins/spu2/PeopsSPU2/dsound.h new file mode 100644 index 0000000000..f03fff1da9 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/dsound.h @@ -0,0 +1,2357 @@ +/*==========================================================================; + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * File: dsound.h + * Content: DirectSound include file + * + **************************************************************************/ + +#define COM_NO_WINDOWS_H +#include +#include + +#ifndef DIRECTSOUND_VERSION +#define DIRECTSOUND_VERSION 0x0900 /* Version 9.0 */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef __DSOUND_INCLUDED__ +#define __DSOUND_INCLUDED__ + +/* Type definitions shared with Direct3D */ + +#ifndef DX_SHARED_DEFINES + +typedef float D3DVALUE, *LPD3DVALUE; + +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +#ifndef LPD3DCOLOR_DEFINED +typedef DWORD *LPD3DCOLOR; +#define LPD3DCOLOR_DEFINED +#endif + +#ifndef D3DVECTOR_DEFINED +typedef struct _D3DVECTOR { + float x; + float y; + float z; +} D3DVECTOR; +#define D3DVECTOR_DEFINED +#endif + +#ifndef LPD3DVECTOR_DEFINED +typedef D3DVECTOR *LPD3DVECTOR; +#define LPD3DVECTOR_DEFINED +#endif + +#define DX_SHARED_DEFINES +#endif // DX_SHARED_DEFINES + +#define _FACDS 0x878 /* DirectSound's facility code */ +#define MAKE_DSHRESULT(code) MAKE_HRESULT(1, _FACDS, code) + +// DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000} +DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); + +// DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B} +DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b); + +// DirectSound Capture Component GUID {B0210780-89CD-11D0-AF08-00A0C925CD16} +DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +// DirectSound 8.0 Capture Component GUID {E4BCAC13-7F99-4908-9A8E-74E3BF24B6E1} +DEFINE_GUID(CLSID_DirectSoundCapture8, 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1); + +// DirectSound Full Duplex Component GUID {FEA4300C-7959-4147-B26A-2377B9E7A91D} +DEFINE_GUID(CLSID_DirectSoundFullDuplex, 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d); + + +// DirectSound default playback device GUID {DEF00000-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default capture device GUID {DEF00001-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default device for voice playback {DEF00002-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultVoicePlayback, 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default device for voice capture {DEF00003-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultVoiceCapture, 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + + +// +// Forward declarations for interfaces. +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +// + +#ifdef __cplusplus +struct IDirectSound; +struct IDirectSoundBuffer; +struct IDirectSound3DListener; +struct IDirectSound3DBuffer; +struct IDirectSoundCapture; +struct IDirectSoundCaptureBuffer; +struct IDirectSoundNotify; +#endif // __cplusplus + + +// +// DirectSound 8.0 interfaces. +// + +#if DIRECTSOUND_VERSION >= 0x0800 + +#ifdef __cplusplus +struct IDirectSound8; +struct IDirectSoundBuffer8; +struct IDirectSoundCaptureBuffer8; +struct IDirectSoundFXGargle; +struct IDirectSoundFXChorus; +struct IDirectSoundFXFlanger; +struct IDirectSoundFXEcho; +struct IDirectSoundFXDistortion; +struct IDirectSoundFXCompressor; +struct IDirectSoundFXParamEq; +struct IDirectSoundFXWavesReverb; +struct IDirectSoundFXI3DL2Reverb; +struct IDirectSoundCaptureFXAec; +struct IDirectSoundCaptureFXNoiseSuppress; +struct IDirectSoundFullDuplex; +#endif // __cplusplus + +// IDirectSound8, IDirectSoundBuffer8 and IDirectSoundCaptureBuffer8 are the +// only DirectSound 7.0 interfaces with changed functionality in version 8.0. +// The other level 8 interfaces as equivalent to their level 7 counterparts: + +#define IDirectSoundCapture8 IDirectSoundCapture +#define IDirectSound3DListener8 IDirectSound3DListener +#define IDirectSound3DBuffer8 IDirectSound3DBuffer +#define IDirectSoundNotify8 IDirectSoundNotify +#define IDirectSoundFXGargle8 IDirectSoundFXGargle +#define IDirectSoundFXChorus8 IDirectSoundFXChorus +#define IDirectSoundFXFlanger8 IDirectSoundFXFlanger +#define IDirectSoundFXEcho8 IDirectSoundFXEcho +#define IDirectSoundFXDistortion8 IDirectSoundFXDistortion +#define IDirectSoundFXCompressor8 IDirectSoundFXCompressor +#define IDirectSoundFXParamEq8 IDirectSoundFXParamEq +#define IDirectSoundFXWavesReverb8 IDirectSoundFXWavesReverb +#define IDirectSoundFXI3DL2Reverb8 IDirectSoundFXI3DL2Reverb +#define IDirectSoundCaptureFXAec8 IDirectSoundCaptureFXAec +#define IDirectSoundCaptureFXNoiseSuppress8 IDirectSoundCaptureFXNoiseSuppress +#define IDirectSoundFullDuplex8 IDirectSoundFullDuplex + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +typedef struct IDirectSound *LPDIRECTSOUND; +typedef struct IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; +typedef struct IDirectSound3DListener *LPDIRECTSOUND3DLISTENER; +typedef struct IDirectSound3DBuffer *LPDIRECTSOUND3DBUFFER; +typedef struct IDirectSoundCapture *LPDIRECTSOUNDCAPTURE; +typedef struct IDirectSoundCaptureBuffer *LPDIRECTSOUNDCAPTUREBUFFER; +typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY; + + +#if DIRECTSOUND_VERSION >= 0x0800 + +typedef struct IDirectSoundFXGargle *LPDIRECTSOUNDFXGARGLE; +typedef struct IDirectSoundFXChorus *LPDIRECTSOUNDFXCHORUS; +typedef struct IDirectSoundFXFlanger *LPDIRECTSOUNDFXFLANGER; +typedef struct IDirectSoundFXEcho *LPDIRECTSOUNDFXECHO; +typedef struct IDirectSoundFXDistortion *LPDIRECTSOUNDFXDISTORTION; +typedef struct IDirectSoundFXCompressor *LPDIRECTSOUNDFXCOMPRESSOR; +typedef struct IDirectSoundFXParamEq *LPDIRECTSOUNDFXPARAMEQ; +typedef struct IDirectSoundFXWavesReverb *LPDIRECTSOUNDFXWAVESREVERB; +typedef struct IDirectSoundFXI3DL2Reverb *LPDIRECTSOUNDFXI3DL2REVERB; +typedef struct IDirectSoundCaptureFXAec *LPDIRECTSOUNDCAPTUREFXAEC; +typedef struct IDirectSoundCaptureFXNoiseSuppress *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS; +typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX; + +typedef struct IDirectSound8 *LPDIRECTSOUND8; +typedef struct IDirectSoundBuffer8 *LPDIRECTSOUNDBUFFER8; +typedef struct IDirectSound3DListener8 *LPDIRECTSOUND3DLISTENER8; +typedef struct IDirectSound3DBuffer8 *LPDIRECTSOUND3DBUFFER8; +typedef struct IDirectSoundCapture8 *LPDIRECTSOUNDCAPTURE8; +typedef struct IDirectSoundCaptureBuffer8 *LPDIRECTSOUNDCAPTUREBUFFER8; +typedef struct IDirectSoundNotify8 *LPDIRECTSOUNDNOTIFY8; +typedef struct IDirectSoundFXGargle8 *LPDIRECTSOUNDFXGARGLE8; +typedef struct IDirectSoundFXChorus8 *LPDIRECTSOUNDFXCHORUS8; +typedef struct IDirectSoundFXFlanger8 *LPDIRECTSOUNDFXFLANGER8; +typedef struct IDirectSoundFXEcho8 *LPDIRECTSOUNDFXECHO8; +typedef struct IDirectSoundFXDistortion8 *LPDIRECTSOUNDFXDISTORTION8; +typedef struct IDirectSoundFXCompressor8 *LPDIRECTSOUNDFXCOMPRESSOR8; +typedef struct IDirectSoundFXParamEq8 *LPDIRECTSOUNDFXPARAMEQ8; +typedef struct IDirectSoundFXWavesReverb8 *LPDIRECTSOUNDFXWAVESREVERB8; +typedef struct IDirectSoundFXI3DL2Reverb8 *LPDIRECTSOUNDFXI3DL2REVERB8; +typedef struct IDirectSoundCaptureFXAec8 *LPDIRECTSOUNDCAPTUREFXAEC8; +typedef struct IDirectSoundCaptureFXNoiseSuppress8 *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS8; +typedef struct IDirectSoundFullDuplex8 *LPDIRECTSOUNDFULLDUPLEX8; + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IID definitions for the unchanged DirectSound 8.0 interfaces +// + +#if DIRECTSOUND_VERSION >= 0x0800 + +#define IID_IDirectSoundCapture8 IID_IDirectSoundCapture +#define IID_IDirectSound3DListener8 IID_IDirectSound3DListener +#define IID_IDirectSound3DBuffer8 IID_IDirectSound3DBuffer +#define IID_IDirectSoundNotify8 IID_IDirectSoundNotify +#define IID_IDirectSoundFXGargle8 IID_IDirectSoundFXGargle +#define IID_IDirectSoundFXChorus8 IID_IDirectSoundFXChorus +#define IID_IDirectSoundFXFlanger8 IID_IDirectSoundFXFlanger +#define IID_IDirectSoundFXEcho8 IID_IDirectSoundFXEcho +#define IID_IDirectSoundFXDistortion8 IID_IDirectSoundFXDistortion +#define IID_IDirectSoundFXCompressor8 IID_IDirectSoundFXCompressor +#define IID_IDirectSoundFXParamEq8 IID_IDirectSoundFXParamEq +#define IID_IDirectSoundFXWavesReverb8 IID_IDirectSoundFXWavesReverb +#define IID_IDirectSoundFXI3DL2Reverb8 IID_IDirectSoundFXI3DL2Reverb +#define IID_IDirectSoundCaptureFXAec8 IID_IDirectSoundCaptureFXAec +#define IID_IDirectSoundCaptureFXNoiseSuppress8 IID_IDirectSoundCaptureFXNoiseSuppress +#define IID_IDirectSoundFullDuplex8 IID_IDirectSoundFullDuplex + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Compatibility typedefs +// + +#ifndef _LPCWAVEFORMATEX_DEFINED +#define _LPCWAVEFORMATEX_DEFINED +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +#endif // _LPCWAVEFORMATEX_DEFINED + +#ifndef __LPCGUID_DEFINED__ +#define __LPCGUID_DEFINED__ +typedef const GUID *LPCGUID; +#endif // __LPCGUID_DEFINED__ + +typedef LPDIRECTSOUND *LPLPDIRECTSOUND; +typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER; +typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER; +typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER; +typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE; +typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER; +typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY; + +#if DIRECTSOUND_VERSION >= 0x0800 +typedef LPDIRECTSOUND8 *LPLPDIRECTSOUND8; +typedef LPDIRECTSOUNDBUFFER8 *LPLPDIRECTSOUNDBUFFER8; +typedef LPDIRECTSOUNDCAPTURE8 *LPLPDIRECTSOUNDCAPTURE8; +typedef LPDIRECTSOUNDCAPTUREBUFFER8 *LPLPDIRECTSOUNDCAPTUREBUFFER8; +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Structures +// + +typedef struct _DSCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwMinSecondarySampleRate; + DWORD dwMaxSecondarySampleRate; + DWORD dwPrimaryBuffers; + DWORD dwMaxHwMixingAllBuffers; + DWORD dwMaxHwMixingStaticBuffers; + DWORD dwMaxHwMixingStreamingBuffers; + DWORD dwFreeHwMixingAllBuffers; + DWORD dwFreeHwMixingStaticBuffers; + DWORD dwFreeHwMixingStreamingBuffers; + DWORD dwMaxHw3DAllBuffers; + DWORD dwMaxHw3DStaticBuffers; + DWORD dwMaxHw3DStreamingBuffers; + DWORD dwFreeHw3DAllBuffers; + DWORD dwFreeHw3DStaticBuffers; + DWORD dwFreeHw3DStreamingBuffers; + DWORD dwTotalHwMemBytes; + DWORD dwFreeHwMemBytes; + DWORD dwMaxContigFreeHwMemBytes; + DWORD dwUnlockTransferRateHwBuffers; + DWORD dwPlayCpuOverheadSwBuffers; + DWORD dwReserved1; + DWORD dwReserved2; +} DSCAPS, *LPDSCAPS; + +typedef const DSCAPS *LPCDSCAPS; + +typedef struct _DSBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwUnlockTransferRate; + DWORD dwPlayCpuOverhead; +} DSBCAPS, *LPDSBCAPS; + +typedef const DSBCAPS *LPCDSBCAPS; + +#if DIRECTSOUND_VERSION >= 0x0800 + + typedef struct _DSEFFECTDESC + { + DWORD dwSize; + DWORD dwFlags; + GUID guidDSFXClass; + DWORD_PTR dwReserved1; + DWORD_PTR dwReserved2; + } DSEFFECTDESC, *LPDSEFFECTDESC; + typedef const DSEFFECTDESC *LPCDSEFFECTDESC; + + #define DSFX_LOCHARDWARE 0x00000001 + #define DSFX_LOCSOFTWARE 0x00000002 + + enum + { + DSFXR_PRESENT, // 0 + DSFXR_LOCHARDWARE, // 1 + DSFXR_LOCSOFTWARE, // 2 + DSFXR_UNALLOCATED, // 3 + DSFXR_FAILED, // 4 + DSFXR_UNKNOWN, // 5 + DSFXR_SENDLOOP // 6 + }; + + typedef struct _DSCEFFECTDESC + { + DWORD dwSize; + DWORD dwFlags; + GUID guidDSCFXClass; + GUID guidDSCFXInstance; + DWORD dwReserved1; + DWORD dwReserved2; + } DSCEFFECTDESC, *LPDSCEFFECTDESC; + typedef const DSCEFFECTDESC *LPCDSCEFFECTDESC; + + #define DSCFX_LOCHARDWARE 0x00000001 + #define DSCFX_LOCSOFTWARE 0x00000002 + + #define DSCFXR_LOCHARDWARE 0x00000010 + #define DSCFXR_LOCSOFTWARE 0x00000020 + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +typedef struct _DSBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +#if DIRECTSOUND_VERSION >= 0x0700 + GUID guid3DAlgorithm; +#endif +} DSBUFFERDESC, *LPDSBUFFERDESC; + +typedef const DSBUFFERDESC *LPCDSBUFFERDESC; + +// Older version of this structure: + +typedef struct _DSBUFFERDESC1 +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSBUFFERDESC1, *LPDSBUFFERDESC1; + +typedef const DSBUFFERDESC1 *LPCDSBUFFERDESC1; + +typedef struct _DS3DBUFFER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + DWORD dwInsideConeAngle; + DWORD dwOutsideConeAngle; + D3DVECTOR vConeOrientation; + LONG lConeOutsideVolume; + D3DVALUE flMinDistance; + D3DVALUE flMaxDistance; + DWORD dwMode; +} DS3DBUFFER, *LPDS3DBUFFER; + +typedef const DS3DBUFFER *LPCDS3DBUFFER; + +typedef struct _DS3DLISTENER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + D3DVECTOR vOrientFront; + D3DVECTOR vOrientTop; + D3DVALUE flDistanceFactor; + D3DVALUE flRolloffFactor; + D3DVALUE flDopplerFactor; +} DS3DLISTENER, *LPDS3DLISTENER; + +typedef const DS3DLISTENER *LPCDS3DLISTENER; + +typedef struct _DSCCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFormats; + DWORD dwChannels; +} DSCCAPS, *LPDSCCAPS; + +typedef const DSCCAPS *LPCDSCCAPS; + +typedef struct _DSCBUFFERDESC1 +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSCBUFFERDESC1, *LPDSCBUFFERDESC1; + +typedef struct _DSCBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +#if DIRECTSOUND_VERSION >= 0x0800 + DWORD dwFXCount; + LPDSCEFFECTDESC lpDSCFXDesc; +#endif +} DSCBUFFERDESC, *LPDSCBUFFERDESC; + +typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC; + +typedef struct _DSCBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; +} DSCBCAPS, *LPDSCBCAPS; + +typedef const DSCBCAPS *LPCDSCBCAPS; + +typedef struct _DSBPOSITIONNOTIFY +{ + DWORD dwOffset; + HANDLE hEventNotify; +} DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY; + +typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY; + +// +// DirectSound API +// + +typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); +typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID); + +extern HRESULT WINAPI DirectSoundCreate(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); + +extern HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); + +#if DIRECTSOUND_VERSION >= 0x0800 +extern HRESULT WINAPI DirectSoundCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundCaptureCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundFullDuplexCreate(LPCGUID pcGuidCaptureDevice, LPCGUID pcGuidRenderDevice, + LPCDSCBUFFERDESC pcDSCBufferDesc, LPCDSBUFFERDESC pcDSBufferDesc, HWND hWnd, + DWORD dwLevel, LPDIRECTSOUNDFULLDUPLEX* ppDSFD, LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, + LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, LPUNKNOWN pUnkOuter); +#define DirectSoundFullDuplexCreate8 DirectSoundFullDuplexCreate + +extern HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest); +#endif // DIRECTSOUND_VERSION >= 0x0800 + +#ifdef UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKW +#define DirectSoundEnumerate DirectSoundEnumerateW +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW +#else // UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKA +#define DirectSoundEnumerate DirectSoundEnumerateA +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA +#endif // UNICODE + +// +// IUnknown +// + +#if !defined(__cplusplus) || defined(CINTERFACE) +#ifndef IUnknown_QueryInterface +#define IUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#endif // IUnknown_QueryInterface +#ifndef IUnknown_AddRef +#define IUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) +#endif // IUnknown_AddRef +#ifndef IUnknown_Release +#define IUnknown_Release(p) (p)->lpVtbl->Release(p) +#endif // IUnknown_Release +#else // !defined(__cplusplus) || defined(CINTERFACE) +#ifndef IUnknown_QueryInterface +#define IUnknown_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#endif // IUnknown_QueryInterface +#ifndef IUnknown_AddRef +#define IUnknown_AddRef(p) (p)->AddRef() +#endif // IUnknown_AddRef +#ifndef IUnknown_Release +#define IUnknown_Release(p) (p)->Release() +#endif // IUnknown_Release +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#ifndef __IReferenceClock_INTERFACE_DEFINED__ +#define __IReferenceClock_INTERFACE_DEFINED__ + +typedef LONGLONG REFERENCE_TIME; +typedef REFERENCE_TIME *LPREFERENCE_TIME; + +DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); + +#undef INTERFACE +#define INTERFACE IReferenceClock + +DECLARE_INTERFACE_(IReferenceClock, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IReferenceClock methods + STDMETHOD(GetTime) (THIS_ REFERENCE_TIME *pTime) PURE; + STDMETHOD(AdviseTime) (THIS_ REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, + HANDLE hEvent, LPDWORD pdwAdviseCookie) PURE; + STDMETHOD(AdvisePeriodic) (THIS_ REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, + HANDLE hSemaphore, LPDWORD pdwAdviseCookie) PURE; + STDMETHOD(Unadvise) (THIS_ DWORD dwAdviseCookie) PURE; +}; + +#endif // __IReferenceClock_INTERFACE_DEFINED__ + +#ifndef IReferenceClock_QueryInterface + +#define IReferenceClock_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IReferenceClock_AddRef(p) IUnknown_AddRef(p) +#define IReferenceClock_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IReferenceClock_GetTime(p,a) (p)->lpVtbl->GetTime(p,a) +#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->lpVtbl->AdviseTime(p,a,b,c,d) +#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d) +#define IReferenceClock_Unadvise(p,a) (p)->lpVtbl->Unadvise(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IReferenceClock_GetTime(p,a) (p)->GetTime(a) +#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->AdviseTime(a,b,c,d) +#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->AdvisePeriodic(a,b,c,d) +#define IReferenceClock_Unadvise(p,a) (p)->Unadvise(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // IReferenceClock_QueryInterface + +// +// IDirectSound +// + +DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound + +DECLARE_INTERFACE_(IDirectSound, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound methods + STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; + STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; + STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; + STDMETHOD(Compact) (THIS) PURE; + STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; + STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; +}; + +#define IDirectSound_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->lpVtbl->CreateSoundBuffer(p,a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectSound_Compact(p) (p)->lpVtbl->Compact(p) +#define IDirectSound_GetSpeakerConfig(p,a) (p)->lpVtbl->GetSpeakerConfig(p,a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->lpVtbl->SetSpeakerConfig(p,b) +#define IDirectSound_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->CreateSoundBuffer(a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectSound_Compact(p) (p)->Compact() +#define IDirectSound_GetSpeakerConfig(p,a) (p)->GetSpeakerConfig(a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->SetSpeakerConfig(b) +#define IDirectSound_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSound8 +// + +DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66); + +#undef INTERFACE +#define INTERFACE IDirectSound8 + +DECLARE_INTERFACE_(IDirectSound8, IDirectSound) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound methods + STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; + STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; + STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; + STDMETHOD(Compact) (THIS) PURE; + STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; + STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; + + // IDirectSound8 methods + STDMETHOD(VerifyCertification) (THIS_ LPDWORD pdwCertified) PURE; +}; + +#define IDirectSound8_QueryInterface(p,a,b) IDirectSound_QueryInterface(p,a,b) +#define IDirectSound8_AddRef(p) IDirectSound_AddRef(p) +#define IDirectSound8_Release(p) IDirectSound_Release(p) +#define IDirectSound8_CreateSoundBuffer(p,a,b,c) IDirectSound_CreateSoundBuffer(p,a,b,c) +#define IDirectSound8_GetCaps(p,a) IDirectSound_GetCaps(p,a) +#define IDirectSound8_DuplicateSoundBuffer(p,a,b) IDirectSound_DuplicateSoundBuffer(p,a,b) +#define IDirectSound8_SetCooperativeLevel(p,a,b) IDirectSound_SetCooperativeLevel(p,a,b) +#define IDirectSound8_Compact(p) IDirectSound_Compact(p) +#define IDirectSound8_GetSpeakerConfig(p,a) IDirectSound_GetSpeakerConfig(p,a) +#define IDirectSound8_SetSpeakerConfig(p,a) IDirectSound_SetSpeakerConfig(p,a) +#define IDirectSound8_Initialize(p,a) IDirectSound_Initialize(p,a) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound8_VerifyCertification(p,a) (p)->lpVtbl->VerifyCertification(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound8_VerifyCertification(p,a) (p)->VerifyCertification(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundBuffer +// + +DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSoundBuffer + +DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; + STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; + STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; + STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; + STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; + STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; + STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; + STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + STDMETHOD(Restore) (THIS) PURE; +}; + +#define IDirectSoundBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->lpVtbl->GetVolume(p,a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->lpVtbl->GetPan(p,a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->lpVtbl->GetFrequency(p,a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->lpVtbl->Play(p,a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->lpVtbl->SetCurrentPosition(p,a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->lpVtbl->SetVolume(p,a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->lpVtbl->SetPan(p,a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->lpVtbl->SetFrequency(p,a) +#define IDirectSoundBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->lpVtbl->Restore(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->GetVolume(a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->GetPan(a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->GetFrequency(a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->Play(a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->SetCurrentPosition(a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->SetFormat(a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->SetVolume(a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->SetPan(a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->SetFrequency(a) +#define IDirectSoundBuffer_Stop(p) (p)->Stop() +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->Restore() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundBuffer8 +// + +DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e); + +#undef INTERFACE +#define INTERFACE IDirectSoundBuffer8 + +DECLARE_INTERFACE_(IDirectSoundBuffer8, IDirectSoundBuffer) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; + STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; + STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; + STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; + STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; + STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; + STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; + STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + STDMETHOD(Restore) (THIS) PURE; + + // IDirectSoundBuffer8 methods + STDMETHOD(SetFX) (THIS_ DWORD dwEffectsCount, LPDSEFFECTDESC pDSFXDesc, LPDWORD pdwResultCodes) PURE; + STDMETHOD(AcquireResources) (THIS_ DWORD dwFlags, DWORD dwEffectsCount, LPDWORD pdwResultCodes) PURE; + STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; +}; + +// Special GUID meaning "select all objects" for use in GetObjectInPath() +DEFINE_GUID(GUID_All_Objects, 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5); + +#define IDirectSoundBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundBuffer8_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundBuffer8_Release(p) IUnknown_Release(p) + +#define IDirectSoundBuffer8_GetCaps(p,a) IDirectSoundBuffer_GetCaps(p,a) +#define IDirectSoundBuffer8_GetCurrentPosition(p,a,b) IDirectSoundBuffer_GetCurrentPosition(p,a,b) +#define IDirectSoundBuffer8_GetFormat(p,a,b,c) IDirectSoundBuffer_GetFormat(p,a,b,c) +#define IDirectSoundBuffer8_GetVolume(p,a) IDirectSoundBuffer_GetVolume(p,a) +#define IDirectSoundBuffer8_GetPan(p,a) IDirectSoundBuffer_GetPan(p,a) +#define IDirectSoundBuffer8_GetFrequency(p,a) IDirectSoundBuffer_GetFrequency(p,a) +#define IDirectSoundBuffer8_GetStatus(p,a) IDirectSoundBuffer_GetStatus(p,a) +#define IDirectSoundBuffer8_Initialize(p,a,b) IDirectSoundBuffer_Initialize(p,a,b) +#define IDirectSoundBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundBuffer8_Play(p,a,b,c) IDirectSoundBuffer_Play(p,a,b,c) +#define IDirectSoundBuffer8_SetCurrentPosition(p,a) IDirectSoundBuffer_SetCurrentPosition(p,a) +#define IDirectSoundBuffer8_SetFormat(p,a) IDirectSoundBuffer_SetFormat(p,a) +#define IDirectSoundBuffer8_SetVolume(p,a) IDirectSoundBuffer_SetVolume(p,a) +#define IDirectSoundBuffer8_SetPan(p,a) IDirectSoundBuffer_SetPan(p,a) +#define IDirectSoundBuffer8_SetFrequency(p,a) IDirectSoundBuffer_SetFrequency(p,a) +#define IDirectSoundBuffer8_Stop(p) IDirectSoundBuffer_Stop(p) +#define IDirectSoundBuffer8_Unlock(p,a,b,c,d) IDirectSoundBuffer_Unlock(p,a,b,c,d) +#define IDirectSoundBuffer8_Restore(p) IDirectSoundBuffer_Restore(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->lpVtbl->SetFX(p,a,b,c) +#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->lpVtbl->AcquireResources(p,a,b,c) +#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->SetFX(a,b,c) +#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->AcquireResources(a,b,c) +#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSound3DListener +// + +DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DListener + +DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound3DListener methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DLISTENER pListener) PURE; + STDMETHOD(GetDistanceFactor) (THIS_ D3DVALUE* pflDistanceFactor) PURE; + STDMETHOD(GetDopplerFactor) (THIS_ D3DVALUE* pflDopplerFactor) PURE; + STDMETHOD(GetOrientation) (THIS_ D3DVECTOR* pvOrientFront, D3DVECTOR* pvOrientTop) PURE; + STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; + STDMETHOD(GetRolloffFactor) (THIS_ D3DVALUE* pflRolloffFactor) PURE; + STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DLISTENER pcListener, DWORD dwApply) PURE; + STDMETHOD(SetDistanceFactor) (THIS_ D3DVALUE flDistanceFactor, DWORD dwApply) PURE; + STDMETHOD(SetDopplerFactor) (THIS_ D3DVALUE flDopplerFactor, DWORD dwApply) PURE; + STDMETHOD(SetOrientation) (THIS_ D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, + D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD dwApply) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetRolloffFactor) (THIS_ D3DVALUE flRolloffFactor, DWORD dwApply) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(CommitDeferredSettings) (THIS) PURE; +}; + +#define IDirectSound3DListener_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound3DListener_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound3DListener_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->lpVtbl->GetDistanceFactor(p,a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->lpVtbl->GetDopplerFactor(p,a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->lpVtbl->GetOrientation(p,a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->lpVtbl->GetRolloffFactor(p,a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->lpVtbl->SetDistanceFactor(p,a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->lpVtbl->SetDopplerFactor(p,a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->lpVtbl->SetRolloffFactor(p,a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->lpVtbl->CommitDeferredSettings(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->GetDistanceFactor(a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->GetDopplerFactor(a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->GetOrientation(a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->GetRolloffFactor(a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->SetDistanceFactor(a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->SetDopplerFactor(a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->SetOrientation(a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->SetRolloffFactor(a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->CommitDeferredSettings() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSound3DBuffer +// + +DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DBuffer + +DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound3DBuffer methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DBUFFER pDs3dBuffer) PURE; + STDMETHOD(GetConeAngles) (THIS_ LPDWORD pdwInsideConeAngle, LPDWORD pdwOutsideConeAngle) PURE; + STDMETHOD(GetConeOrientation) (THIS_ D3DVECTOR* pvOrientation) PURE; + STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG plConeOutsideVolume) PURE; + STDMETHOD(GetMaxDistance) (THIS_ D3DVALUE* pflMaxDistance) PURE; + STDMETHOD(GetMinDistance) (THIS_ D3DVALUE* pflMinDistance) PURE; + STDMETHOD(GetMode) (THIS_ LPDWORD pdwMode) PURE; + STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; + STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DBUFFER pcDs3dBuffer, DWORD dwApply) PURE; + STDMETHOD(SetConeAngles) (THIS_ DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD dwApply) PURE; + STDMETHOD(SetConeOrientation) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetConeOutsideVolume) (THIS_ LONG lConeOutsideVolume, DWORD dwApply) PURE; + STDMETHOD(SetMaxDistance) (THIS_ D3DVALUE flMaxDistance, DWORD dwApply) PURE; + STDMETHOD(SetMinDistance) (THIS_ D3DVALUE flMinDistance, DWORD dwApply) PURE; + STDMETHOD(SetMode) (THIS_ DWORD dwMode, DWORD dwApply) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; +}; + +#define IDirectSound3DBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound3DBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound3DBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->lpVtbl->GetConeAngles(p,a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->lpVtbl->GetConeOrientation(p,a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->lpVtbl->GetConeOutsideVolume(p,a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->lpVtbl->GetMinDistance(p,a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->lpVtbl->GetMaxDistance(p,a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->lpVtbl->GetMode(p,a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->lpVtbl->SetConeOutsideVolume(p,a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->lpVtbl->SetMinDistance(p,a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->lpVtbl->SetMode(p,a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->GetConeAngles(a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->GetConeOrientation(a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->GetConeOutsideVolume(a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->GetMinDistance(a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->GetMaxDistance(a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->GetMode(a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->SetConeAngles(a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->SetConeOrientation(a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->SetConeOutsideVolume(a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->SetMinDistance(a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->SetMaxDistance(a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->SetMode(a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCapture +// + +DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCapture + +DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCapture methods + STDMETHOD(CreateCaptureBuffer) (THIS_ LPCDSCBUFFERDESC pcDSCBufferDesc, LPDIRECTSOUNDCAPTUREBUFFER *ppDSCBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCCAPS pDSCCaps) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; +}; + +#define IDirectSoundCapture_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCapture_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCapture_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCapture_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->CreateCaptureBuffer(a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCapture_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCaptureBuffer +// + +DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureBuffer + +DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; +}; + +#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->lpVtbl->Start(p,a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->Start(a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->Stop() +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundCaptureBuffer8 +// + +DEFINE_GUID(IID_IDirectSoundCaptureBuffer8, 0x990df4, 0xdbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6); + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureBuffer8 + +DECLARE_INTERFACE_(IDirectSoundCaptureBuffer8, IDirectSoundCaptureBuffer) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + + // IDirectSoundCaptureBuffer8 methods + STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; + STDMETHOD(GetFXStatus) (DWORD dwFXCount, LPDWORD pdwFXStatus) PURE; +}; + +#define IDirectSoundCaptureBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureBuffer8_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureBuffer8_Release(p) IUnknown_Release(p) + +#define IDirectSoundCaptureBuffer8_GetCaps(p,a) IDirectSoundCaptureBuffer_GetCaps(p,a) +#define IDirectSoundCaptureBuffer8_GetCurrentPosition(p,a,b) IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) +#define IDirectSoundCaptureBuffer8_GetFormat(p,a,b,c) IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) +#define IDirectSoundCaptureBuffer8_GetStatus(p,a) IDirectSoundCaptureBuffer_GetStatus(p,a) +#define IDirectSoundCaptureBuffer8_Initialize(p,a,b) IDirectSoundCaptureBuffer_Initialize(p,a,b) +#define IDirectSoundCaptureBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer8_Start(p,a) IDirectSoundCaptureBuffer_Start(p,a) +#define IDirectSoundCaptureBuffer8_Stop(p) IDirectSoundCaptureBuffer_Stop(p)) +#define IDirectSoundCaptureBuffer8_Unlock(p,a,b,c,d) IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) +#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->lpVtbl->GetFXStatus(p,a,b) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) +#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->GetFXStatus(a,b) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundNotify +// + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundNotify + +DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundNotify methods + STDMETHOD(SetNotificationPositions) (THIS_ DWORD dwPositionNotifies, LPCDSBPOSITIONNOTIFY pcPositionNotifies) PURE; +}; + +#define IDirectSoundNotify_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundNotify_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundNotify_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->lpVtbl->SetNotificationPositions(p,a,b) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->SetNotificationPositions(a,b) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IKsPropertySet +// + +#ifndef _IKsPropertySet_ +#define _IKsPropertySet_ + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IKsPropertySet; +#endif // __cplusplus + +typedef struct IKsPropertySet *LPKSPROPERTYSET; + +#define KSPROPERTY_SUPPORT_GET 0x00000001 +#define KSPROPERTY_SUPPORT_SET 0x00000002 + +DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); + +#undef INTERFACE +#define INTERFACE IKsPropertySet + +DECLARE_INTERFACE_(IKsPropertySet, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IKsPropertySet methods + STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; + STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength) PURE; + STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; +}; + +#define IKsPropertySet_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IKsPropertySet_AddRef(p) IUnknown_AddRef(p) +#define IKsPropertySet_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->lpVtbl->Get(p,a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->lpVtbl->Set(p,a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->lpVtbl->QuerySupport(p,a,b,c) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->Get(a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->Set(a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->QuerySupport(a,b,c) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // _IKsPropertySet_ + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundFXGargle +// + +DEFINE_GUID(IID_IDirectSoundFXGargle, 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3); + +typedef struct _DSFXGargle +{ + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // DSFXGARGLE_WAVE_xxx +} DSFXGargle, *LPDSFXGargle; + +#define DSFXGARGLE_WAVE_TRIANGLE 0 +#define DSFXGARGLE_WAVE_SQUARE 1 + +typedef const DSFXGargle *LPCDSFXGargle; + +#define DSFXGARGLE_RATEHZ_MIN 1 +#define DSFXGARGLE_RATEHZ_MAX 1000 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXGargle + +DECLARE_INTERFACE_(IDirectSoundFXGargle, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXGargle methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXGargle pcDsFxGargle) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXGargle pDsFxGargle) PURE; +}; + +#define IDirectSoundFXGargle_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXGargle_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXGargle_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXChorus +// + +DEFINE_GUID(IID_IDirectSoundFXChorus, 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47); + +typedef struct _DSFXChorus +{ + FLOAT fWetDryMix; + FLOAT fDepth; + FLOAT fFeedback; + FLOAT fFrequency; + LONG lWaveform; // LFO shape; DSFXCHORUS_WAVE_xxx + FLOAT fDelay; + LONG lPhase; +} DSFXChorus, *LPDSFXChorus; + +typedef const DSFXChorus *LPCDSFXChorus; + +#define DSFXCHORUS_WAVE_TRIANGLE 0 +#define DSFXCHORUS_WAVE_SIN 1 + +#define DSFXCHORUS_WETDRYMIX_MIN 0.0f +#define DSFXCHORUS_WETDRYMIX_MAX 100.0f +#define DSFXCHORUS_DEPTH_MIN 0.0f +#define DSFXCHORUS_DEPTH_MAX 100.0f +#define DSFXCHORUS_FEEDBACK_MIN -99.0f +#define DSFXCHORUS_FEEDBACK_MAX 99.0f +#define DSFXCHORUS_FREQUENCY_MIN 0.0f +#define DSFXCHORUS_FREQUENCY_MAX 10.0f +#define DSFXCHORUS_DELAY_MIN 0.0f +#define DSFXCHORUS_DELAY_MAX 20.0f +#define DSFXCHORUS_PHASE_MIN 0 +#define DSFXCHORUS_PHASE_MAX 4 + +#define DSFXCHORUS_PHASE_NEG_180 0 +#define DSFXCHORUS_PHASE_NEG_90 1 +#define DSFXCHORUS_PHASE_ZERO 2 +#define DSFXCHORUS_PHASE_90 3 +#define DSFXCHORUS_PHASE_180 4 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXChorus + +DECLARE_INTERFACE_(IDirectSoundFXChorus, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXChorus methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXChorus pcDsFxChorus) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXChorus pDsFxChorus) PURE; +}; + +#define IDirectSoundFXChorus_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXChorus_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXChorus_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXFlanger +// + +DEFINE_GUID(IID_IDirectSoundFXFlanger, 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83); + +typedef struct _DSFXFlanger +{ + FLOAT fWetDryMix; + FLOAT fDepth; + FLOAT fFeedback; + FLOAT fFrequency; + LONG lWaveform; + FLOAT fDelay; + LONG lPhase; +} DSFXFlanger, *LPDSFXFlanger; + +typedef const DSFXFlanger *LPCDSFXFlanger; + +#define DSFXFLANGER_WAVE_TRIANGLE 0 +#define DSFXFLANGER_WAVE_SIN 1 + +#define DSFXFLANGER_WETDRYMIX_MIN 0.0f +#define DSFXFLANGER_WETDRYMIX_MAX 100.0f +#define DSFXFLANGER_FREQUENCY_MIN 0.0f +#define DSFXFLANGER_FREQUENCY_MAX 10.0f +#define DSFXFLANGER_DEPTH_MIN 0.0f +#define DSFXFLANGER_DEPTH_MAX 100.0f +#define DSFXFLANGER_PHASE_MIN 0 +#define DSFXFLANGER_PHASE_MAX 4 +#define DSFXFLANGER_FEEDBACK_MIN -99.0f +#define DSFXFLANGER_FEEDBACK_MAX 99.0f +#define DSFXFLANGER_DELAY_MIN 0.0f +#define DSFXFLANGER_DELAY_MAX 4.0f + +#define DSFXFLANGER_PHASE_NEG_180 0 +#define DSFXFLANGER_PHASE_NEG_90 1 +#define DSFXFLANGER_PHASE_ZERO 2 +#define DSFXFLANGER_PHASE_90 3 +#define DSFXFLANGER_PHASE_180 4 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXFlanger + +DECLARE_INTERFACE_(IDirectSoundFXFlanger, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXFlanger methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXFlanger pcDsFxFlanger) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXFlanger pDsFxFlanger) PURE; +}; + +#define IDirectSoundFXFlanger_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXFlanger_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXFlanger_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXEcho +// + +DEFINE_GUID(IID_IDirectSoundFXEcho, 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42); + +typedef struct _DSFXEcho +{ + FLOAT fWetDryMix; + FLOAT fFeedback; + FLOAT fLeftDelay; + FLOAT fRightDelay; + LONG lPanDelay; +} DSFXEcho, *LPDSFXEcho; + +typedef const DSFXEcho *LPCDSFXEcho; + +#define DSFXECHO_WETDRYMIX_MIN 0.0f +#define DSFXECHO_WETDRYMIX_MAX 100.0f +#define DSFXECHO_FEEDBACK_MIN 0.0f +#define DSFXECHO_FEEDBACK_MAX 100.0f +#define DSFXECHO_LEFTDELAY_MIN 1.0f +#define DSFXECHO_LEFTDELAY_MAX 2000.0f +#define DSFXECHO_RIGHTDELAY_MIN 1.0f +#define DSFXECHO_RIGHTDELAY_MAX 2000.0f +#define DSFXECHO_PANDELAY_MIN 0 +#define DSFXECHO_PANDELAY_MAX 1 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXEcho + +DECLARE_INTERFACE_(IDirectSoundFXEcho, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXEcho methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXEcho pcDsFxEcho) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXEcho pDsFxEcho) PURE; +}; + +#define IDirectSoundFXEcho_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXEcho_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXEcho_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXDistortion +// + +DEFINE_GUID(IID_IDirectSoundFXDistortion, 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b); + +typedef struct _DSFXDistortion +{ + FLOAT fGain; + FLOAT fEdge; + FLOAT fPostEQCenterFrequency; + FLOAT fPostEQBandwidth; + FLOAT fPreLowpassCutoff; +} DSFXDistortion, *LPDSFXDistortion; + +typedef const DSFXDistortion *LPCDSFXDistortion; + +#define DSFXDISTORTION_GAIN_MIN -60.0f +#define DSFXDISTORTION_GAIN_MAX 0.0f +#define DSFXDISTORTION_EDGE_MIN 0.0f +#define DSFXDISTORTION_EDGE_MAX 100.0f +#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN 100.0f +#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX 8000.0f +#define DSFXDISTORTION_POSTEQBANDWIDTH_MIN 100.0f +#define DSFXDISTORTION_POSTEQBANDWIDTH_MAX 8000.0f +#define DSFXDISTORTION_PRELOWPASSCUTOFF_MIN 100.0f +#define DSFXDISTORTION_PRELOWPASSCUTOFF_MAX 8000.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXDistortion + +DECLARE_INTERFACE_(IDirectSoundFXDistortion, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXDistortion methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXDistortion pcDsFxDistortion) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXDistortion pDsFxDistortion) PURE; +}; + +#define IDirectSoundFXDistortion_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXDistortion_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXDistortion_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXCompressor +// + +DEFINE_GUID(IID_IDirectSoundFXCompressor, 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0); + +typedef struct _DSFXCompressor +{ + FLOAT fGain; + FLOAT fAttack; + FLOAT fRelease; + FLOAT fThreshold; + FLOAT fRatio; + FLOAT fPredelay; +} DSFXCompressor, *LPDSFXCompressor; + +typedef const DSFXCompressor *LPCDSFXCompressor; + +#define DSFXCOMPRESSOR_GAIN_MIN -60.0f +#define DSFXCOMPRESSOR_GAIN_MAX 60.0f +#define DSFXCOMPRESSOR_ATTACK_MIN 0.01f +#define DSFXCOMPRESSOR_ATTACK_MAX 500.0f +#define DSFXCOMPRESSOR_RELEASE_MIN 50.0f +#define DSFXCOMPRESSOR_RELEASE_MAX 3000.0f +#define DSFXCOMPRESSOR_THRESHOLD_MIN -60.0f +#define DSFXCOMPRESSOR_THRESHOLD_MAX 0.0f +#define DSFXCOMPRESSOR_RATIO_MIN 1.0f +#define DSFXCOMPRESSOR_RATIO_MAX 100.0f +#define DSFXCOMPRESSOR_PREDELAY_MIN 0.0f +#define DSFXCOMPRESSOR_PREDELAY_MAX 4.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXCompressor + +DECLARE_INTERFACE_(IDirectSoundFXCompressor, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXCompressor methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXCompressor pcDsFxCompressor) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXCompressor pDsFxCompressor) PURE; +}; + +#define IDirectSoundFXCompressor_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXCompressor_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXCompressor_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXParamEq +// + +DEFINE_GUID(IID_IDirectSoundFXParamEq, 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda); + +typedef struct _DSFXParamEq +{ + FLOAT fCenter; + FLOAT fBandwidth; + FLOAT fGain; +} DSFXParamEq, *LPDSFXParamEq; + +typedef const DSFXParamEq *LPCDSFXParamEq; + +#define DSFXPARAMEQ_CENTER_MIN 80.0f +#define DSFXPARAMEQ_CENTER_MAX 16000.0f +#define DSFXPARAMEQ_BANDWIDTH_MIN 1.0f +#define DSFXPARAMEQ_BANDWIDTH_MAX 36.0f +#define DSFXPARAMEQ_GAIN_MIN -15.0f +#define DSFXPARAMEQ_GAIN_MAX 15.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXParamEq + +DECLARE_INTERFACE_(IDirectSoundFXParamEq, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXParamEq methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXParamEq pcDsFxParamEq) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXParamEq pDsFxParamEq) PURE; +}; + +#define IDirectSoundFXParamEq_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXParamEq_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXParamEq_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXI3DL2Reverb +// + +DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4); + +typedef struct _DSFXI3DL2Reverb +{ + LONG lRoom; // [-10000, 0] default: -1000 mB + LONG lRoomHF; // [-10000, 0] default: 0 mB + FLOAT flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + FLOAT flDecayTime; // [0.1, 20.0] default: 1.49s + FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.83 + LONG lReflections; // [-10000, 1000] default: -2602 mB + FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + LONG lReverb; // [-10000, 2000] default: 200 mB + FLOAT flReverbDelay; // [0.0, 0.1] default: 0.011 s + FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % + FLOAT flDensity; // [0.0, 100.0] default: 100.0 % + FLOAT flHFReference; // [20.0, 20000.0] default: 5000.0 Hz +} DSFXI3DL2Reverb, *LPDSFXI3DL2Reverb; + +typedef const DSFXI3DL2Reverb *LPCDSFXI3DL2Reverb; + +#define DSFX_I3DL2REVERB_ROOM_MIN (-10000) +#define DSFX_I3DL2REVERB_ROOM_MAX 0 +#define DSFX_I3DL2REVERB_ROOM_DEFAULT (-1000) + +#define DSFX_I3DL2REVERB_ROOMHF_MIN (-10000) +#define DSFX_I3DL2REVERB_ROOMHF_MAX 0 +#define DSFX_I3DL2REVERB_ROOMHF_DEFAULT (-100) + +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN 0.0f +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX 10.0f +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT 0.0f + +#define DSFX_I3DL2REVERB_DECAYTIME_MIN 0.1f +#define DSFX_I3DL2REVERB_DECAYTIME_MAX 20.0f +#define DSFX_I3DL2REVERB_DECAYTIME_DEFAULT 1.49f + +#define DSFX_I3DL2REVERB_DECAYHFRATIO_MIN 0.1f +#define DSFX_I3DL2REVERB_DECAYHFRATIO_MAX 2.0f +#define DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT 0.83f + +#define DSFX_I3DL2REVERB_REFLECTIONS_MIN (-10000) +#define DSFX_I3DL2REVERB_REFLECTIONS_MAX 1000 +#define DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT (-2602) + +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN 0.0f +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX 0.3f +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT 0.007f + +#define DSFX_I3DL2REVERB_REVERB_MIN (-10000) +#define DSFX_I3DL2REVERB_REVERB_MAX 2000 +#define DSFX_I3DL2REVERB_REVERB_DEFAULT (200) + +#define DSFX_I3DL2REVERB_REVERBDELAY_MIN 0.0f +#define DSFX_I3DL2REVERB_REVERBDELAY_MAX 0.1f +#define DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT 0.011f + +#define DSFX_I3DL2REVERB_DIFFUSION_MIN 0.0f +#define DSFX_I3DL2REVERB_DIFFUSION_MAX 100.0f +#define DSFX_I3DL2REVERB_DIFFUSION_DEFAULT 100.0f + +#define DSFX_I3DL2REVERB_DENSITY_MIN 0.0f +#define DSFX_I3DL2REVERB_DENSITY_MAX 100.0f +#define DSFX_I3DL2REVERB_DENSITY_DEFAULT 100.0f + +#define DSFX_I3DL2REVERB_HFREFERENCE_MIN 20.0f +#define DSFX_I3DL2REVERB_HFREFERENCE_MAX 20000.0f +#define DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT 5000.0f + +#define DSFX_I3DL2REVERB_QUALITY_MIN 0 +#define DSFX_I3DL2REVERB_QUALITY_MAX 3 +#define DSFX_I3DL2REVERB_QUALITY_DEFAULT 2 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXI3DL2Reverb + +DECLARE_INTERFACE_(IDirectSoundFXI3DL2Reverb, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXI3DL2Reverb methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXI3DL2Reverb pcDsFxI3DL2Reverb) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXI3DL2Reverb pDsFxI3DL2Reverb) PURE; + STDMETHOD(SetPreset) (THIS_ DWORD dwPreset) PURE; + STDMETHOD(GetPreset) (THIS_ LPDWORD pdwPreset) PURE; + STDMETHOD(SetQuality) (THIS_ LONG lQuality) PURE; + STDMETHOD(GetQuality) (THIS_ LONG *plQuality) PURE; +}; + +#define IDirectSoundFXI3DL2Reverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXI3DL2Reverb_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXI3DL2Reverb_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->lpVtbl->SetPreset(p,a) +#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->lpVtbl->GetPreset(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->SetPreset(a) +#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->GetPreset(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXWavesReverb +// + +DEFINE_GUID(IID_IDirectSoundFXWavesReverb,0x46858c3a,0x0dc6,0x45e3,0xb7,0x60,0xd4,0xee,0xf1,0x6c,0xb3,0x25); + +typedef struct _DSFXWavesReverb +{ + FLOAT fInGain; // [-96.0,0.0] default: 0.0 dB + FLOAT fReverbMix; // [-96.0,0.0] default: 0.0 db + FLOAT fReverbTime; // [0.001,3000.0] default: 1000.0 ms + FLOAT fHighFreqRTRatio; // [0.001,0.999] default: 0.001 +} DSFXWavesReverb, *LPDSFXWavesReverb; + +typedef const DSFXWavesReverb *LPCDSFXWavesReverb; + +#define DSFX_WAVESREVERB_INGAIN_MIN -96.0f +#define DSFX_WAVESREVERB_INGAIN_MAX 0.0f +#define DSFX_WAVESREVERB_INGAIN_DEFAULT 0.0f +#define DSFX_WAVESREVERB_REVERBMIX_MIN -96.0f +#define DSFX_WAVESREVERB_REVERBMIX_MAX 0.0f +#define DSFX_WAVESREVERB_REVERBMIX_DEFAULT 0.0f +#define DSFX_WAVESREVERB_REVERBTIME_MIN 0.001f +#define DSFX_WAVESREVERB_REVERBTIME_MAX 3000.0f +#define DSFX_WAVESREVERB_REVERBTIME_DEFAULT 1000.0f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN 0.001f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX 0.999f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT 0.001f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXWavesReverb + +DECLARE_INTERFACE_(IDirectSoundFXWavesReverb, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXWavesReverb methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXWavesReverb pcDsFxWavesReverb) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXWavesReverb pDsFxWavesReverb) PURE; +}; + +#define IDirectSoundFXWavesReverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXWavesReverb_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXWavesReverb_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCaptureFXAec +// + +DEFINE_GUID(IID_IDirectSoundCaptureFXAec, 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65); + +typedef struct _DSCFXAec +{ + BOOL fEnable; + BOOL fNoiseFill; + DWORD dwMode; +} DSCFXAec, *LPDSCFXAec; + +typedef const DSCFXAec *LPCDSCFXAec; + +// These match the AEC_MODE_* constants in the DDK's ksmedia.h file +#define DSCFX_AEC_MODE_PASS_THROUGH 0x0 +#define DSCFX_AEC_MODE_HALF_DUPLEX 0x1 +#define DSCFX_AEC_MODE_FULL_DUPLEX 0x2 + +// These match the AEC_STATUS_* constants in ksmedia.h +#define DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED 0x0 +#define DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED 0x1 +#define DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED 0x2 +#define DSCFX_AEC_STATUS_CURRENTLY_CONVERGED 0x8 + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureFXAec + +DECLARE_INTERFACE_(IDirectSoundCaptureFXAec, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureFXAec methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXAec pDscFxAec) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSCFXAec pDscFxAec) PURE; + STDMETHOD(GetStatus) (THIS_ PDWORD pdwStatus) PURE; + STDMETHOD(Reset) (THIS) PURE; +}; + +#define IDirectSoundCaptureFXAec_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureFXAec_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureFXAec_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +// +// IDirectSoundCaptureFXNoiseSuppress +// + +DEFINE_GUID(IID_IDirectSoundCaptureFXNoiseSuppress, 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x8, 0x54, 0xf6, 0x93, 0xca); + +typedef struct _DSCFXNoiseSuppress +{ + BOOL fEnable; +} DSCFXNoiseSuppress, *LPDSCFXNoiseSuppress; + +typedef const DSCFXNoiseSuppress *LPCDSCFXNoiseSuppress; + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureFXNoiseSuppress + +DECLARE_INTERFACE_(IDirectSoundCaptureFXNoiseSuppress, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureFXNoiseSuppress methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXNoiseSuppress pcDscFxNoiseSuppress) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSCFXNoiseSuppress pDscFxNoiseSuppress) PURE; + STDMETHOD(Reset) (THIS) PURE; +}; + +#define IDirectSoundCaptureFXNoiseSuppress_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureFXNoiseSuppress_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureFXNoiseSuppress_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +// +// IDirectSoundFullDuplex +// + +#ifndef _IDirectSoundFullDuplex_ +#define _IDirectSoundFullDuplex_ + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IDirectSoundFullDuplex; +#endif // __cplusplus + + +DEFINE_GUID(IID_IDirectSoundFullDuplex, 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d); + +#undef INTERFACE +#define INTERFACE IDirectSoundFullDuplex + +DECLARE_INTERFACE_(IDirectSoundFullDuplex, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFullDuplex methods + STDMETHOD(Initialize) (THIS_ LPCGUID pCaptureGuid, LPCGUID pRenderGuid, LPCDSCBUFFERDESC lpDscBufferDesc, LPCDSBUFFERDESC lpDsBufferDesc, HWND hWnd, DWORD dwLevel, LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8) PURE; +}; + +#define IDirectSoundFullDuplex_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFullDuplex_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFullDuplex_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f,g,h) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->Initialize(a,b,c,d,e,f,g,h) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // _IDirectSoundFullDuplex_ + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Return Codes +// + +// The function completed successfully +#define DS_OK S_OK + +// The call succeeded, but we had to substitute the 3D algorithm +#define DS_NO_VIRTUALIZATION MAKE_HRESULT(0, _FACDS, 10) + +// The call failed because resources (such as a priority level) +// were already being used by another caller +#define DSERR_ALLOCATED MAKE_DSHRESULT(10) + +// The control (vol, pan, etc.) requested by the caller is not available +#define DSERR_CONTROLUNAVAIL MAKE_DSHRESULT(30) + +// An invalid parameter was passed to the returning function +#define DSERR_INVALIDPARAM E_INVALIDARG + +// This call is not valid for the current state of this object +#define DSERR_INVALIDCALL MAKE_DSHRESULT(50) + +// An undetermined error occurred inside the DirectSound subsystem +#define DSERR_GENERIC E_FAIL + +// The caller does not have the priority level required for the function to +// succeed +#define DSERR_PRIOLEVELNEEDED MAKE_DSHRESULT(70) + +// Not enough free memory is available to complete the operation +#define DSERR_OUTOFMEMORY E_OUTOFMEMORY + +// The specified WAVE format is not supported +#define DSERR_BADFORMAT MAKE_DSHRESULT(100) + +// The function called is not supported at this time +#define DSERR_UNSUPPORTED E_NOTIMPL + +// No sound driver is available for use +#define DSERR_NODRIVER MAKE_DSHRESULT(120) + +// This object is already initialized +#define DSERR_ALREADYINITIALIZED MAKE_DSHRESULT(130) + +// This object does not support aggregation +#define DSERR_NOAGGREGATION CLASS_E_NOAGGREGATION + +// The buffer memory has been lost, and must be restored +#define DSERR_BUFFERLOST MAKE_DSHRESULT(150) + +// Another app has a higher priority level, preventing this call from +// succeeding +#define DSERR_OTHERAPPHASPRIO MAKE_DSHRESULT(160) + +// This object has not been initialized +#define DSERR_UNINITIALIZED MAKE_DSHRESULT(170) + +// The requested COM interface is not available +#define DSERR_NOINTERFACE E_NOINTERFACE + +// Access is denied +#define DSERR_ACCESSDENIED E_ACCESSDENIED + +// Tried to create a DSBCAPS_CTRLFX buffer shorter than DSBSIZE_FX_MIN milliseconds +#define DSERR_BUFFERTOOSMALL MAKE_DSHRESULT(180) + +// Attempt to use DirectSound 8 functionality on an older DirectSound object +#define DSERR_DS8_REQUIRED MAKE_DSHRESULT(190) + +// A circular loop of send effects was detected +#define DSERR_SENDLOOP MAKE_DSHRESULT(200) + +// The GUID specified in an audiopath file does not match a valid MIXIN buffer +#define DSERR_BADSENDBUFFERGUID MAKE_DSHRESULT(210) + +// The object requested was not found (numerically equal to DMUS_E_NOT_FOUND) +#define DSERR_OBJECTNOTFOUND MAKE_DSHRESULT(4449) + +// The effects requested could not be found on the system, or they were found +// but in the wrong order, or in the wrong hardware/software locations. +#define DSERR_FXUNAVAILABLE MAKE_DSHRESULT(220) + +// +// Flags +// + +#define DSCAPS_PRIMARYMONO 0x00000001 +#define DSCAPS_PRIMARYSTEREO 0x00000002 +#define DSCAPS_PRIMARY8BIT 0x00000004 +#define DSCAPS_PRIMARY16BIT 0x00000008 +#define DSCAPS_CONTINUOUSRATE 0x00000010 +#define DSCAPS_EMULDRIVER 0x00000020 +#define DSCAPS_CERTIFIED 0x00000040 +#define DSCAPS_SECONDARYMONO 0x00000100 +#define DSCAPS_SECONDARYSTEREO 0x00000200 +#define DSCAPS_SECONDARY8BIT 0x00000400 +#define DSCAPS_SECONDARY16BIT 0x00000800 + +#define DSSCL_NORMAL 0x00000001 +#define DSSCL_PRIORITY 0x00000002 +#define DSSCL_EXCLUSIVE 0x00000003 +#define DSSCL_WRITEPRIMARY 0x00000004 + +#define DSSPEAKER_DIRECTOUT 0x00000000 +#define DSSPEAKER_HEADPHONE 0x00000001 +#define DSSPEAKER_MONO 0x00000002 +#define DSSPEAKER_QUAD 0x00000003 +#define DSSPEAKER_STEREO 0x00000004 +#define DSSPEAKER_SURROUND 0x00000005 +#define DSSPEAKER_5POINT1 0x00000006 +#define DSSPEAKER_7POINT1 0x00000007 + +#define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees +#define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees +#define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees +#define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees + +#define DSSPEAKER_COMBINED(c, g) ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16)) +#define DSSPEAKER_CONFIG(a) ((BYTE)(a)) +#define DSSPEAKER_GEOMETRY(a) ((BYTE)(((DWORD)(a) >> 16) & 0x00FF)) + +#define DSBCAPS_PRIMARYBUFFER 0x00000001 +#define DSBCAPS_STATIC 0x00000002 +#define DSBCAPS_LOCHARDWARE 0x00000004 +#define DSBCAPS_LOCSOFTWARE 0x00000008 +#define DSBCAPS_CTRL3D 0x00000010 +#define DSBCAPS_CTRLFREQUENCY 0x00000020 +#define DSBCAPS_CTRLPAN 0x00000040 +#define DSBCAPS_CTRLVOLUME 0x00000080 +#define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 +#define DSBCAPS_CTRLFX 0x00000200 +#define DSBCAPS_STICKYFOCUS 0x00004000 +#define DSBCAPS_GLOBALFOCUS 0x00008000 +#define DSBCAPS_GETCURRENTPOSITION2 0x00010000 +#define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 +#define DSBCAPS_LOCDEFER 0x00040000 + +#define DSBPLAY_LOOPING 0x00000001 +#define DSBPLAY_LOCHARDWARE 0x00000002 +#define DSBPLAY_LOCSOFTWARE 0x00000004 +#define DSBPLAY_TERMINATEBY_TIME 0x00000008 +#define DSBPLAY_TERMINATEBY_DISTANCE 0x000000010 +#define DSBPLAY_TERMINATEBY_PRIORITY 0x000000020 + +#define DSBSTATUS_PLAYING 0x00000001 +#define DSBSTATUS_BUFFERLOST 0x00000002 +#define DSBSTATUS_LOOPING 0x00000004 +#define DSBSTATUS_LOCHARDWARE 0x00000008 +#define DSBSTATUS_LOCSOFTWARE 0x00000010 +#define DSBSTATUS_TERMINATED 0x00000020 + +#define DSBLOCK_FROMWRITECURSOR 0x00000001 +#define DSBLOCK_ENTIREBUFFER 0x00000002 + +#define DSBFREQUENCY_ORIGINAL 0 +#define DSBFREQUENCY_MIN 100 +#if DIRECTSOUND_VERSION >= 0x0900 +#define DSBFREQUENCY_MAX 200000 +#else +#define DSBFREQUENCY_MAX 100000 +#endif + +#define DSBPAN_LEFT -10000 +#define DSBPAN_CENTER 0 +#define DSBPAN_RIGHT 10000 + +#define DSBVOLUME_MIN -10000 +#define DSBVOLUME_MAX 0 + +#define DSBSIZE_MIN 4 +#define DSBSIZE_MAX 0x0FFFFFFF +#define DSBSIZE_FX_MIN 150 // NOTE: Milliseconds, not bytes + +#define DS3DMODE_NORMAL 0x00000000 +#define DS3DMODE_HEADRELATIVE 0x00000001 +#define DS3DMODE_DISABLE 0x00000002 + +#define DS3D_IMMEDIATE 0x00000000 +#define DS3D_DEFERRED 0x00000001 + +#define DS3D_MINDISTANCEFACTOR FLT_MIN +#define DS3D_MAXDISTANCEFACTOR FLT_MAX +#define DS3D_DEFAULTDISTANCEFACTOR 1.0f + +#define DS3D_MINROLLOFFFACTOR 0.0f +#define DS3D_MAXROLLOFFFACTOR 10.0f +#define DS3D_DEFAULTROLLOFFFACTOR 1.0f + +#define DS3D_MINDOPPLERFACTOR 0.0f +#define DS3D_MAXDOPPLERFACTOR 10.0f +#define DS3D_DEFAULTDOPPLERFACTOR 1.0f + +#define DS3D_DEFAULTMINDISTANCE 1.0f +#define DS3D_DEFAULTMAXDISTANCE 1000000000.0f + +#define DS3D_MINCONEANGLE 0 +#define DS3D_MAXCONEANGLE 360 +#define DS3D_DEFAULTCONEANGLE 360 + +#define DS3D_DEFAULTCONEOUTSIDEVOLUME DSBVOLUME_MAX + +// IDirectSoundCapture attributes + +#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER +#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED +#define DSCCAPS_MULTIPLECAPTURE 0x00000001 + +// IDirectSoundCaptureBuffer attributes + +#define DSCBCAPS_WAVEMAPPED 0x80000000 + +#if DIRECTSOUND_VERSION >= 0x0800 +#define DSCBCAPS_CTRLFX 0x00000200 +#endif + + +#define DSCBLOCK_ENTIREBUFFER 0x00000001 + +#define DSCBSTATUS_CAPTURING 0x00000001 +#define DSCBSTATUS_LOOPING 0x00000002 + +#define DSCBSTART_LOOPING 0x00000001 + +#define DSBPN_OFFSETSTOP 0xFFFFFFFF + +#define DS_CERTIFIED 0x00000000 +#define DS_UNCERTIFIED 0x00000001 + + +// +// Flags for the I3DL2 effects +// + +// +// I3DL2 Material Presets +// + +enum +{ + DSFX_I3DL2_MATERIAL_PRESET_SINGLEWINDOW, + DSFX_I3DL2_MATERIAL_PRESET_DOUBLEWINDOW, + DSFX_I3DL2_MATERIAL_PRESET_THINDOOR, + DSFX_I3DL2_MATERIAL_PRESET_THICKDOOR, + DSFX_I3DL2_MATERIAL_PRESET_WOODWALL, + DSFX_I3DL2_MATERIAL_PRESET_BRICKWALL, + DSFX_I3DL2_MATERIAL_PRESET_STONEWALL, + DSFX_I3DL2_MATERIAL_PRESET_CURTAIN +}; + +#define I3DL2_MATERIAL_PRESET_SINGLEWINDOW -2800,0.71f +#define I3DL2_MATERIAL_PRESET_DOUBLEWINDOW -5000,0.40f +#define I3DL2_MATERIAL_PRESET_THINDOOR -1800,0.66f +#define I3DL2_MATERIAL_PRESET_THICKDOOR -4400,0.64f +#define I3DL2_MATERIAL_PRESET_WOODWALL -4000,0.50f +#define I3DL2_MATERIAL_PRESET_BRICKWALL -5000,0.60f +#define I3DL2_MATERIAL_PRESET_STONEWALL -6000,0.68f +#define I3DL2_MATERIAL_PRESET_CURTAIN -1200,0.15f + +enum +{ + DSFX_I3DL2_ENVIRONMENT_PRESET_DEFAULT, + DSFX_I3DL2_ENVIRONMENT_PRESET_GENERIC, + DSFX_I3DL2_ENVIRONMENT_PRESET_PADDEDCELL, + DSFX_I3DL2_ENVIRONMENT_PRESET_ROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_BATHROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_LIVINGROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_STONEROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_AUDITORIUM, + DSFX_I3DL2_ENVIRONMENT_PRESET_CONCERTHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_CAVE, + DSFX_I3DL2_ENVIRONMENT_PRESET_ARENA, + DSFX_I3DL2_ENVIRONMENT_PRESET_HANGAR, + DSFX_I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY, + DSFX_I3DL2_ENVIRONMENT_PRESET_HALLWAY, + DSFX_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR, + DSFX_I3DL2_ENVIRONMENT_PRESET_ALLEY, + DSFX_I3DL2_ENVIRONMENT_PRESET_FOREST, + DSFX_I3DL2_ENVIRONMENT_PRESET_CITY, + DSFX_I3DL2_ENVIRONMENT_PRESET_MOUNTAINS, + DSFX_I3DL2_ENVIRONMENT_PRESET_QUARRY, + DSFX_I3DL2_ENVIRONMENT_PRESET_PLAIN, + DSFX_I3DL2_ENVIRONMENT_PRESET_PARKINGLOT, + DSFX_I3DL2_ENVIRONMENT_PRESET_SEWERPIPE, + DSFX_I3DL2_ENVIRONMENT_PRESET_UNDERWATER, + DSFX_I3DL2_ENVIRONMENT_PRESET_SMALLROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_PLATE +}; + +// +// I3DL2 Reverberation Presets Values +// + +#define I3DL2_ENVIRONMENT_PRESET_DEFAULT -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_GENERIC -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PADDEDCELL -1000,-6000, 0.0f, 0.17f, 0.10f, -1204, 0.001f, 207, 0.002f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ROOM -1000, -454, 0.0f, 0.40f, 0.83f, -1646, 0.002f, 53, 0.003f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_BATHROOM -1000,-1200, 0.0f, 1.49f, 0.54f, -370, 0.007f, 1030, 0.011f, 100.0f, 60.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LIVINGROOM -1000,-6000, 0.0f, 0.50f, 0.10f, -1376, 0.003f, -1104, 0.004f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_STONEROOM -1000, -300, 0.0f, 2.31f, 0.64f, -711, 0.012f, 83, 0.017f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_AUDITORIUM -1000, -476, 0.0f, 4.32f, 0.59f, -789, 0.020f, -289, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CONCERTHALL -1000, -500, 0.0f, 3.92f, 0.70f, -1230, 0.020f, -2, 0.029f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CAVE -1000, 0, 0.0f, 2.91f, 1.30f, -602, 0.015f, -302, 0.022f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ARENA -1000, -698, 0.0f, 7.24f, 0.33f, -1166, 0.020f, 16, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_HANGAR -1000,-1000, 0.0f,10.05f, 0.23f, -602, 0.020f, 198, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY -1000,-4000, 0.0f, 0.30f, 0.10f, -1831, 0.002f, -1630, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_HALLWAY -1000, -300, 0.0f, 1.49f, 0.59f, -1219, 0.007f, 441, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR -1000, -237, 0.0f, 2.70f, 0.79f, -1214, 0.013f, 395, 0.020f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ALLEY -1000, -270, 0.0f, 1.49f, 0.86f, -1204, 0.007f, -4, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_FOREST -1000,-3300, 0.0f, 1.49f, 0.54f, -2560, 0.162f, -613, 0.088f, 79.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CITY -1000, -800, 0.0f, 1.49f, 0.67f, -2273, 0.007f, -2217, 0.011f, 50.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MOUNTAINS -1000,-2500, 0.0f, 1.49f, 0.21f, -2780, 0.300f, -2014, 0.100f, 27.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_QUARRY -1000,-1000, 0.0f, 1.49f, 0.83f,-10000, 0.061f, 500, 0.025f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PLAIN -1000,-2000, 0.0f, 1.49f, 0.50f, -2466, 0.179f, -2514, 0.100f, 21.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PARKINGLOT -1000, 0, 0.0f, 1.65f, 1.50f, -1363, 0.008f, -1153, 0.012f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_SEWERPIPE -1000,-1000, 0.0f, 2.81f, 0.14f, 429, 0.014f, 648, 0.021f, 80.0f, 60.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_UNDERWATER -1000,-4000, 0.0f, 1.49f, 0.10f, -449, 0.007f, 1700, 0.011f, 100.0f, 100.0f, 5000.0f + +// +// Examples simulating 'musical' reverb presets +// +// Name Decay time Description +// Small Room 1.1s A small size room with a length of 5m or so. +// Medium Room 1.3s A medium size room with a length of 10m or so. +// Large Room 1.5s A large size room suitable for live performances. +// Medium Hall 1.8s A medium size concert hall. +// Large Hall 1.8s A large size concert hall suitable for a full orchestra. +// Plate 1.3s A plate reverb simulation. +// + +#define I3DL2_ENVIRONMENT_PRESET_SMALLROOM -1000, -600, 0.0f, 1.10f, 0.83f, -400, 0.005f, 500, 0.010f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM -1000, -600, 0.0f, 1.30f, 0.83f, -1000, 0.010f, -200, 0.020f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LARGEROOM -1000, -600, 0.0f, 1.50f, 0.83f, -1600, 0.020f, -1000, 0.040f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL -1000, -600, 0.0f, 1.80f, 0.70f, -1300, 0.015f, -800, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LARGEHALL -1000, -600, 0.0f, 1.80f, 0.70f, -2000, 0.030f, -1400, 0.060f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PLATE -1000, -200, 0.0f, 1.30f, 0.90f, 0, 0.002f, 0, 0.010f, 100.0f, 75.0f, 5000.0f + +// +// DirectSound3D Algorithms +// + +// Default DirectSound3D algorithm {00000000-0000-0000-0000-000000000000} +#define DS3DALG_DEFAULT GUID_NULL + +// No virtualization (Pan3D) {C241333F-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_NO_VIRTUALIZATION, 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +// High-quality HRTF algorithm {C2413340-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_HRTF_FULL, 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +// Lower-quality HRTF algorithm {C2413342-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_HRTF_LIGHT, 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// DirectSound Internal Effect Algorithms +// + + +// Gargle {DAFD8210-5711-4B91-9FE3-F75B7AE279BF} +DEFINE_GUID(GUID_DSFX_STANDARD_GARGLE, 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf); + +// Chorus {EFE6629C-81F7-4281-BD91-C9D604A95AF6} +DEFINE_GUID(GUID_DSFX_STANDARD_CHORUS, 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6); + +// Flanger {EFCA3D92-DFD8-4672-A603-7420894BAD98} +DEFINE_GUID(GUID_DSFX_STANDARD_FLANGER, 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98); + +// Echo/Delay {EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D} +DEFINE_GUID(GUID_DSFX_STANDARD_ECHO, 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d); + +// Distortion {EF114C90-CD1D-484E-96E5-09CFAF912A21} +DEFINE_GUID(GUID_DSFX_STANDARD_DISTORTION, 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21); + +// Compressor/Limiter {EF011F79-4000-406D-87AF-BFFB3FC39D57} +DEFINE_GUID(GUID_DSFX_STANDARD_COMPRESSOR, 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57); + +// Parametric Equalization {120CED89-3BF4-4173-A132-3CB406CF3231} +DEFINE_GUID(GUID_DSFX_STANDARD_PARAMEQ, 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31); + +// I3DL2 Environmental Reverberation: Reverb (Listener) Effect {EF985E71-D5C7-42D4-BA4D-2D073E2E96F4} +DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4); + +// Waves Reverberation {87FC0268-9A55-4360-95AA-004A1D9DE26C} +DEFINE_GUID(GUID_DSFX_WAVES_REVERB, 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c); + +// +// DirectSound Capture Effect Algorithms +// + + +// Acoustic Echo Canceller {BF963D80-C559-11D0-8A2B-00A0C9255AC1} +// Matches KSNODETYPE_ACOUSTIC_ECHO_CANCEL in ksmedia.h +DEFINE_GUID(GUID_DSCFX_CLASS_AEC, 0xBF963D80L, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1); + +// Microsoft AEC {CDEBB919-379A-488a-8765-F53CFD36DE40} +DEFINE_GUID(GUID_DSCFX_MS_AEC, 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40); + +// System AEC {1C22C56D-9879-4f5b-A389-27996DDC2810} +DEFINE_GUID(GUID_DSCFX_SYSTEM_AEC, 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10); + +// Noise Supression {E07F903F-62FD-4e60-8CDD-DEA7236665B5} +// Matches KSNODETYPE_NOISE_SUPPRESS in post Windows ME DDK's ksmedia.h +DEFINE_GUID(GUID_DSCFX_CLASS_NS, 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5); + +// Microsoft Noise Suppresion {11C5C73B-66E9-4ba1-A0BA-E814C6EED92D} +DEFINE_GUID(GUID_DSCFX_MS_NS, 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d); + +// System Noise Suppresion {5AB0882E-7274-4516-877D-4EEE99BA4FD0} +DEFINE_GUID(GUID_DSCFX_SYSTEM_NS, 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0); + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +#endif // __DSOUND_INCLUDED__ + + + +#ifdef __cplusplus +}; +#endif // __cplusplus + + diff --git a/plugins/spu2/PeopsSPU2/dsoundoss.h b/plugins/spu2/PeopsSPU2/dsoundoss.h new file mode 100644 index 0000000000..65c22eeaa5 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/dsoundoss.h @@ -0,0 +1,36 @@ +/*************************************************************************** + dsoundoss.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SetupSound(void); +void RemoveSound(void); +unsigned long SoundGetBytesBuffered(void); +void SoundFeedStreamData(unsigned char* pSound,long lBytes); + +#ifndef _WINDOWS +unsigned long timeGetTime(); +#endif + diff --git a/plugins/spu2/PeopsSPU2/externals.h b/plugins/spu2/PeopsSPU2/externals.h new file mode 100644 index 0000000000..af68ea6791 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/externals.h @@ -0,0 +1,364 @@ +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/04/04 - Pete +// - increased channel struct for interpolation +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +///////////////////////////////////////////////////////// +// generic defines +///////////////////////////////////////////////////////// + +//#define PSE_LT_SPU 4 +//#define PSE_SPU_ERR_SUCCESS 0 +//#define PSE_SPU_ERR -60 +//#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1 +//#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2 + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +//////////////////////////////////////////////////////////////////////// +// spu defines +//////////////////////////////////////////////////////////////////////// + +// sound buffer sizes +// 500 ms complete sound buffer +#define SOUNDSIZE 76800 + +// 200 ms test buffer... if less than that is buffered, a new upload will happen +#define TESTSIZE 26304//13152 + +// num of channels +#define MAXCHAN 48 +#define HLFCHAN 24 + +// ~ 1 ms of data +#define NSSIZE 48 + +/////////////////////////////////////////////////////////// +// struct defines +/////////////////////////////////////////////////////////// +// ADMA Channels +extern EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle); +typedef struct +{ + unsigned short * MemAddr; + unsigned short * TempMem; + unsigned int Index; + unsigned int AmountLeft; + unsigned int ADMAPos; + unsigned int TransferAmount; + int IRQ; + int TempAmount; +} ADMA; + +typedef struct +{ + int Left; + int Right; +} DINPUT; + +// ADSR INFOS PER CHANNEL +typedef struct +{ + int AttackModeExp; + long AttackTime; + long DecayTime; + long SustainLevel; + int SustainModeExp; + long SustainModeDec; + long SustainTime; + int ReleaseModeExp; + unsigned long ReleaseVal; + long ReleaseTime; + long ReleaseStartTime; + long ReleaseVol; + long lTime; + long lVolume; +} ADSRInfo; + +typedef struct +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; + long lDummy1; + long lDummy2; +} ADSRInfoEx; + +/////////////////////////////////////////////////////////// + +// Tmp Flags + +// used for debug channel muting +#define FLAG_MUTE 1 + +// used for simple interpolation +#define FLAG_IPOL0 2 +#define FLAG_IPOL1 4 + +/////////////////////////////////////////////////////////// + +// MAIN CHANNEL STRUCT +typedef struct +{ + // no mutexes used anymore... don't need them to sync access + //HANDLE hMutex; + + int bNew; // start flag + + int iSBPos; // mixing stuff + int spos; + int sinc; + int SB[32+32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :) + int sval; + + unsigned char * pStart; // start ptr into sound mem + unsigned char * pCurr; // current pos in sound mem + unsigned char * pLoop; // loop ptr in sound mem + + int iStartAdr; + int iLoopAdr; + int iNextAdr; + + int bOn; // is channel active (sample playing?) + int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase) + int bEndPoint; // end point reached + int bReverbL; // can we do reverb on this channel? must have ctrl register bit, to get active + int bReverbR; + + int bVolumeL; // Volume on/off + int bVolumeR; + + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + int iLeftVolume; // left volume + int iLeftVolRaw; // left psx volume value + int bIgnoreLoop; // ignore loop bit, if an external loop address is used + int iMute; // mute mode + int iRightVolume; // right volume + int iRightVolRaw; // right psx volume value + int iRawPitch; // raw pitch (0...3fff) + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int bRVBActive; // reverb active flag + int bNoise; // noise active flag + int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel) + int iOldNoise; // old noise val for this channel + ADSRInfo ADSR; // active ADSR settings + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + +} SPUCHAN; + +/////////////////////////////////////////////////////////// + +typedef struct +{ + int StartAddr; // reverb area start addr in samples + int EndAddr; // reverb area end addr in samples + int CurrAddr; // reverb area curr addr in samples + + int VolLeft; + int VolRight; + int iLastRVBLeft; + int iLastRVBRight; + int iRVBLeft; + int iRVBRight; + int iCnt; + + int FB_SRC_A; // (offset) + int FB_SRC_B; // (offset) + int IIR_ALPHA; // (coef.) + int ACC_COEF_A; // (coef.) + int ACC_COEF_B; // (coef.) + int ACC_COEF_C; // (coef.) + int ACC_COEF_D; // (coef.) + int IIR_COEF; // (coef.) + int FB_ALPHA; // (coef.) + int FB_X; // (coef.) + int IIR_DEST_A0; // (offset) + int IIR_DEST_A1; // (offset) + int ACC_SRC_A0; // (offset) + int ACC_SRC_A1; // (offset) + int ACC_SRC_B0; // (offset) + int ACC_SRC_B1; // (offset) + int IIR_SRC_A0; // (offset) + int IIR_SRC_A1; // (offset) + int IIR_DEST_B0; // (offset) + int IIR_DEST_B1; // (offset) + int ACC_SRC_C0; // (offset) + int ACC_SRC_C1; // (offset) + int ACC_SRC_D0; // (offset) + int ACC_SRC_D1; // (offset) + int IIR_SRC_B1; // (offset) + int IIR_SRC_B0; // (offset) + int MIX_DEST_A0; // (offset) + int MIX_DEST_A1; // (offset) + int MIX_DEST_B0; // (offset) + int MIX_DEST_B1; // (offset) + int IN_COEF_L; // (coef.) + int IN_COEF_R; // (coef.) +} REVERBInfo; + +#ifdef _WINDOWS +extern HINSTANCE hInst; +#define WM_MUTE (WM_USER+543) +#endif + +/////////////////////////////////////////////////////////// +// SPU.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_SPU + +// psx buffers / addresses + +extern unsigned short regArea[]; +extern unsigned short spuMem[]; +extern unsigned char * spuMemC; +extern unsigned char * pSpuIrq[]; +extern unsigned char * pSpuBuffer; + +// user settings + +extern int iUseXA; +extern int iVolume; +extern int iXAPitch; +extern int iUseTimer; +extern int iDebugMode; +extern int iRecordMode; +extern int iUseReverb; +extern int iUseInterpolation; +extern int iDisStereo; +extern int aSync; +// MISC + +extern SPUCHAN s_chan[]; +extern REVERBInfo rvb[]; + +extern unsigned long dwNoiseVal; +extern unsigned short spuCtrl2[]; +extern unsigned short spuStat2[]; +extern unsigned long spuIrq2[]; +extern unsigned long spuAddr2[]; +extern unsigned long spuRvbAddr2[]; +extern unsigned long spuRvbAEnd2[]; + +extern int bEndThread; +extern int bThreadEnded; +extern int bSpuInit; + +extern int SSumR[]; +extern int SSumL[]; +extern int iCycle; +extern short * pS; +extern unsigned long dwNewChannel2[]; +extern unsigned long dwEndChannel2[]; + +extern int iSpuAsyncWait; + +#ifdef _WINDOWS +extern HWND hWMain; // window handle +extern HWND hWDebug; +#endif + +extern void (CALLBACK *cddavCallback)(unsigned short,unsigned short); + +#endif + +/////////////////////////////////////////////////////////// +// DSOUND.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_DSOUND + +#ifdef _WINDOWS +extern unsigned long LastWrite; +extern unsigned long LastPlay; +#endif + +#endif + +/////////////////////////////////////////////////////////// +// RECORD.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_RECORD + +#ifdef _WINDOWS +extern int iDoRecord; +#endif + +#endif + +/////////////////////////////////////////////////////////// +// XA.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_XA + +extern xa_decode_t * xapGlobal; + +extern unsigned long * XAFeed; +extern unsigned long * XAPlay; +extern unsigned long * XAStart; +extern unsigned long * XAEnd; + +extern unsigned long XARepeat; +extern unsigned long XALastVal; + +extern int iLeftXAVol; +extern int iRightXAVol; + +#endif + +/////////////////////////////////////////////////////////// +// REVERB.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_REVERB + +extern int * sRVBPlay[]; +extern int * sRVBEnd[]; +extern int * sRVBStart[]; + +#endif diff --git a/plugins/spu2/PeopsSPU2/freeze.c b/plugins/spu2/PeopsSPU2/freeze.c new file mode 100644 index 0000000000..d7459449d6 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/freeze.c @@ -0,0 +1,246 @@ +/*************************************************************************** + freeze.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/24 - Pete +// - freeze functions adapted to pcsx2-0.7 +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/03/20 - Pete +// - fix to prevent the new interpolations from crashing when loading a save state +// +// 2003/01/06 - Pete +// - small changes for version 1.3 adsr save state loading +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_FREEZE + +#include "externals.h" +#include "registers.h" +#include "spu.h" +#include "regs.h" +#include "debug.h" +#include "resource.h" + +//////////////////////////////////////////////////////////////////////// +// freeze structs +//////////////////////////////////////////////////////////////////////// + +typedef struct { + int size; + char *data; +} SPUFreeze_t; + +typedef struct +{ + char szSPUName[8]; + unsigned long ulFreezeVersion; + unsigned long ulFreezeSize; + unsigned char cSPUPort[64*1024]; + unsigned char cSPURam[2*1024*1024]; +} SPUFreeze_Ex_t; + +typedef struct +{ + unsigned long spuIrq0; + unsigned long spuIrq1; + unsigned long pSpuIrq0; + unsigned long pSpuIrq1; + unsigned long dummy0; + unsigned long dummy1; + unsigned long dummy2; + unsigned long dummy3; + + SPUCHAN s_chan[MAXCHAN]; + +} SPUOSSFreeze_t; + +//////////////////////////////////////////////////////////////////////// + +void LoadStateV1(SPUFreeze_Ex_t * pF); // newest version +void LoadStateUnknown(SPUFreeze_Ex_t * pF); // unknown format + +//////////////////////////////////////////////////////////////////////// +// SPUFREEZE: called by main emu on savestate load/save +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK SPU2freeze(unsigned long ulFreezeMode,SPUFreeze_t * pFt) +{ + int i;SPUOSSFreeze_t * pFO;SPUFreeze_Ex_t * pF; + + if(!pFt) return 0; // first check + + if(ulFreezeMode) // save? + {//--------------------------------------------------// + pFt->size=sizeof(SPUFreeze_Ex_t)+sizeof(SPUOSSFreeze_t); + + if(ulFreezeMode==2) return 0; // emu just asking for size? bye + + if(!pFt->data) return 0; + + pF=(SPUFreeze_Ex_t *)pFt->data; + + memset(pF,0,pFt->size); + + strcpy(pF->szSPUName,"PBOSS2"); + pF->ulFreezeVersion=1; + pF->ulFreezeSize=pFt->size; + // save mode: + RemoveTimer(); // stop timer + + memcpy(pF->cSPURam,spuMem,2*1024*1024); // copy common infos + memcpy(pF->cSPUPort,regArea,64*1024); + + pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff + + pFO->spuIrq0=spuIrq2[0]; + if(pSpuIrq[0]) pFO->pSpuIrq0 = (unsigned long)pSpuIrq[0]-(unsigned long)spuMemC; + pFO->spuIrq1=spuIrq2[1]; + if(pSpuIrq[1]) pFO->pSpuIrq1 = (unsigned long)pSpuIrq[1]-(unsigned long)spuMemC; + + for(i=0;is_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN)); + if(pFO->s_chan[i].pStart) + pFO->s_chan[i].pStart-=(unsigned long)spuMemC; + if(pFO->s_chan[i].pCurr) + pFO->s_chan[i].pCurr-=(unsigned long)spuMemC; + if(pFO->s_chan[i].pLoop) + pFO->s_chan[i].pLoop-=(unsigned long)spuMemC; + } + + SetupTimer(); // sound processing on again + + return 1; + //--------------------------------------------------// + } + + // load state: +#ifdef _WINDOWS + if(iDebugMode==1 && IsWindow(hWDebug)) // we have to disbale the debug window, if active + DestroyWindow(hWDebug); + hWDebug=0; + + if(IsBadReadPtr(pFt,sizeof(SPUFreeze_t))) // check bad emu stuff + return 0; +#endif + + if(pFt->size!=sizeof(SPUFreeze_Ex_t)+ // not our stuff? bye + sizeof(SPUOSSFreeze_t)) return 0; + if(!pFt->data) return 0; + + pF=(SPUFreeze_Ex_t *)pFt->data; + + RemoveTimer(); // we stop processing while doing the save! + + memcpy(spuMem,pF->cSPURam,2*1024*1024); // get ram + memcpy(regArea,pF->cSPUPort,64*1024); + + if(!strcmp(pF->szSPUName,"PBOSS2") && + pF->ulFreezeVersion==1) + LoadStateV1(pF); + else LoadStateUnknown(pF); + + // repair some globals + for(i=0x7FFE;i>=0x0000;i-=2) + { + SPU2write(i,regArea[i]); + } + + // fix to prevent new interpolations from crashing + for(i=0;ispuIrq0; + if(pFO->pSpuIrq0) pSpuIrq[0] = pFO->pSpuIrq0+spuMemC; else pSpuIrq[0]=0; + spuIrq2[1] = pFO->spuIrq1; + if(pFO->pSpuIrq1) pSpuIrq[1] = pFO->pSpuIrq1+spuMemC; else pSpuIrq[1]=0; + + for(i=0;is_chan[i],sizeof(SPUCHAN)); + + s_chan[i].pStart+=(unsigned long)spuMemC; + s_chan[i].pCurr+=(unsigned long)spuMemC; + s_chan[i].pLoop+=(unsigned long)spuMemC; + s_chan[i].iMute=0; + s_chan[i].iIrqDone=0; + } +} + +//////////////////////////////////////////////////////////////////////// + +void LoadStateUnknown(SPUFreeze_Ex_t * pF) +{ + int i; + + for(i=0;i +#define IDC_STATIC -1 diff --git a/plugins/spu2/PeopsSPU2/oss.c b/plugins/spu2/PeopsSPU2/oss.c new file mode 100644 index 0000000000..e8360ac17e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/oss.c @@ -0,0 +1,190 @@ +/*************************************************************************** + oss.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/03/01 - linuzappz +// - added checkings for oss_audio_fd == -1 +// +// 2003/02/08 - linuzappz +// - added iDisStereo stuff +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_OSS + +#include "externals.h" + +#ifndef _WIN32 + +//////////////////////////////////////////////////////////////////////// +// small linux time helper... only used for watchdog +//////////////////////////////////////////////////////////////////////// +#include + +extern unsigned int timeGetTime() +{ + struct timeb t; + ftime(&t); + return (unsigned int)(t.time*1000+t.millitm); +} + +//////////////////////////////////////////////////////////////////////// +// oss globals +//////////////////////////////////////////////////////////////////////// + +#define OSS_MEM_DEF +#include "oss.h" +static int oss_audio_fd = -1; +extern int errno; + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + int pspeed=48000; + int pstereo; + int format; + int fragsize = 0; + int myfrag; + int oss_speed, oss_stereo; + + if(iDisStereo) pstereo=OSS_MODE_MONO; + else pstereo=OSS_MODE_STEREO; + + oss_speed = pspeed; + oss_stereo = pstereo; + + if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) + { + printf("Sound device not available!\n"); + return; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1) + { + printf("Sound reset failed\n"); + return; + } + + // we use 64 fragments with 1024 bytes each + + fragsize=10; + myfrag=(63<<16)|fragsize; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1) + { + printf("Sound set fragment failed!\n"); + return; + } + + format = AFMT_S16_LE; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1) + { + printf("Sound format not supported!\n"); + return; + } + + if(format!=AFMT_S16_LE) + { + printf("Sound format not supported!\n"); + return; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1) + { + printf("Stereo mode not supported!\n"); + return; + } + + if(oss_stereo!=1) + { + iDisStereo=1; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1) + { + printf("Sound frequency not supported\n"); + return; + } + + if(oss_speed!=pspeed) + { + printf("Sound frequency not supported\n"); + return; + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + if(oss_audio_fd != -1 ) + { + close(oss_audio_fd); + oss_audio_fd = -1; + } +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + audio_buf_info info; + unsigned long l; + + if(oss_audio_fd == -1) return SOUNDSIZE; + if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) + l=0; + else + { + if(info.fragments<(info.fragstotal>>1)) // can we write in at least the half of fragments? + l=SOUNDSIZE; // -> no? wait + else l=0; // -> else go on + } + + return l; +} + +//////////////////////////////////////////////////////////////////////// +// FEED SOUND DATA +//////////////////////////////////////////////////////////////////////// + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(oss_audio_fd == -1) return; + write(oss_audio_fd,pSound,lBytes); +} + +#endif diff --git a/plugins/spu2/PeopsSPU2/oss.h b/plugins/spu2/PeopsSPU2/oss.h new file mode 100644 index 0000000000..d70b68b61a --- /dev/null +++ b/plugins/spu2/PeopsSPU2/oss.h @@ -0,0 +1,37 @@ +/*************************************************************************** + oss_sound.h - description + ------------------- + begin : Wed Dec 8 1999 + copyright : (C) 1999 by Marcin "Duddie" Dudar + email : duddie@psemu.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef _OSS_SOUND_H +#define _OSS_SOUND_H + +#ifdef OSS_MEM_DEF +#define OSS_MEM_EXTERN +#else +#define OSS_MEM_EXTERN extern +#endif + +OSS_MEM_EXTERN int sound_buffer_size; + +#define OSS_MODE_STEREO 1 +#define OSS_MODE_MONO 0 + +#define OSS_SPEED_44100 44100 + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes); + +#endif // _OSS_SOUND_H diff --git a/plugins/spu2/PeopsSPU2/psemu.c b/plugins/spu2/PeopsSPU2/psemu.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/spu2/PeopsSPU2/psemuxa.h b/plugins/spu2/PeopsSPU2/psemuxa.h new file mode 100644 index 0000000000..84c626043f --- /dev/null +++ b/plugins/spu2/PeopsSPU2/psemuxa.h @@ -0,0 +1,28 @@ +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ + +#ifndef DECODEXA_H +#define DECODEXA_H + +typedef struct +{ + long y0, y1; +} ADPCM_Decode_t; + +typedef struct +{ + int freq; + int nbits; + int stereo; + int nsamples; + ADPCM_Decode_t left, right; + short pcm[16384]; +} xa_decode_t; + +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, + int is_first_sector ); + +#endif diff --git a/plugins/spu2/PeopsSPU2/record.c b/plugins/spu2/PeopsSPU2/record.c new file mode 100644 index 0000000000..2206d388c1 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/record.c @@ -0,0 +1,184 @@ +/*************************************************************************** + spu.c - description + ------------------- + begin : Sun Jan 12 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/03/01 - Pete +// - added mono mode +// +// 2003/01/12 - Pete +// - added recording funcs (win version only) +// +//*************************************************************************// + +#include "stdafx.h" + +#ifdef _WINDOWS + +#include +#include "resource.h" +#include "externals.h" + +#define _IN_RECORD + +#include "record.h" + +//////////////////////////////////////////////////////////////////////// + +int iDoRecord=0; +HMMIO hWaveFile=NULL; +MMCKINFO mmckMain; +MMCKINFO mmckData; +char szFileName[256]={"C:\\PEOPS.WAV"}; + +//////////////////////////////////////////////////////////////////////// + +void RecordStart() +{ + WAVEFORMATEX pcmwf; + + // setup header in the same format as our directsound stream + memset(&pcmwf,0,sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = 48000; + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + // create file + hWaveFile=mmioOpen(szFileName,NULL,MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF); + if(!hWaveFile) return; + + // setup WAVE, fmt and data chunks + memset(&mmckMain,0,sizeof(MMCKINFO)); + mmckMain.fccType = mmioFOURCC('W','A','V','E'); + + mmioCreateChunk(hWaveFile,&mmckMain,MMIO_CREATERIFF); + + memset(&mmckData,0,sizeof(MMCKINFO)); + mmckData.ckid = mmioFOURCC('f','m','t',' '); + mmckData.cksize = sizeof(WAVEFORMATEX); + + mmioCreateChunk(hWaveFile,&mmckData,0); + mmioWrite(hWaveFile,(char*)&pcmwf,sizeof(WAVEFORMATEX)); + mmioAscend(hWaveFile,&mmckData,0); + + mmckData.ckid = mmioFOURCC('d','a','t','a'); + mmioCreateChunk(hWaveFile,&mmckData,0); +} + +//////////////////////////////////////////////////////////////////////// + +void RecordStop() +{ + // first some check, if recording is running + iDoRecord=0; + if(!hWaveFile) return; + + // now finish writing & close the wave file + mmioAscend(hWaveFile,&mmckData,0); + mmioAscend(hWaveFile,&mmckMain,0); + mmioClose(hWaveFile,0); + + // init var + hWaveFile=NULL; +} + +//////////////////////////////////////////////////////////////////////// + +void RecordBuffer(unsigned char* pSound,long lBytes) +{ + // write the samples + if(hWaveFile) mmioWrite(hWaveFile,pSound,lBytes); +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + //--------------------------------------------------// init + case WM_INITDIALOG: + { + SetDlgItemText(hW,IDC_WAVFILE,szFileName); // init filename edit + ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts + return TRUE; + } + //--------------------------------------------------// destroy + case WM_DESTROY: + { + RecordStop(); + }break; + //--------------------------------------------------// command + case WM_COMMAND: + { + if(wParam==IDCANCEL) iRecordMode=2; // cancel? raise flag for destroying the dialog + + if(wParam==IDC_RECORD) // record start/stop? + { + if(IsWindowEnabled(GetDlgItem(hW,IDC_WAVFILE))) // not started yet (edit is not disabled): + { + GetDlgItemText(hW,IDC_WAVFILE,szFileName,255);// get filename + + RecordStart(); // start recording + + if(hWaveFile) // start was ok? + { // -> disable filename edit, change text, raise flag + EnableWindow(GetDlgItem(hW,IDC_WAVFILE),FALSE); + SetDlgItemText(hW,IDC_RECORD,"Stop recording"); + iDoRecord=1; + } + else MessageBeep(0xFFFFFFFF); // error starting recording? BEEP + } + else // stop recording? + { + RecordStop(); // -> just do it + EnableWindow(GetDlgItem(hW,IDC_WAVFILE),TRUE);// -> enable filename edit again + SetDlgItemText(hW,IDC_RECORD,"Start recording"); + } + SetFocus(hWMain); + } + + }break; + //--------------------------------------------------// size + case WM_SIZE: + if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window + break; + //--------------------------------------------------// setcursor + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow + return TRUE; + } + //--------------------------------------------------// + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +#endif diff --git a/plugins/spu2/PeopsSPU2/record.h b/plugins/spu2/PeopsSPU2/record.h new file mode 100644 index 0000000000..24fd34cd4f --- /dev/null +++ b/plugins/spu2/PeopsSPU2/record.h @@ -0,0 +1,12 @@ +#ifndef _RECORD_H_ +#define _RECORD_H_ + +#ifdef _WINDOWS +void RecordStart(); +void RecordBuffer(unsigned char* pSound,long lBytes); +void RecordStop(); +BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +#endif + +#endif + diff --git a/plugins/spu2/PeopsSPU2/registers.c b/plugins/spu2/PeopsSPU2/registers.c new file mode 100644 index 0000000000..cf4cae09f3 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/registers.c @@ -0,0 +1,2095 @@ +/*************************************************************************** + registers.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/02/09 - kode54 +// - removed &0x3fff from reverb volume registers, fixes a few games, +// hopefully won't be breaking anything +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_REGISTERS + +#include "externals.h" +#include "registers.h" +#include "regs.h" +#include "reverb.h" +#include "debug.h" + +int MMIXC0 = 0, MMIXC1 = 0; +/* +// adsr time values (in ms) by James Higgs ... see the end of +// the adsr.c source for details + +#define ATTACK_MS 514L +#define DECAYHALF_MS 292L +#define DECAY_MS 584L +#define SUSTAIN_MS 450L +#define RELEASE_MS 446L +*/ + +// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +extern void (CALLBACK *irqCallbackSPU2)(); // func of main emu, called on spu irq + + +//////////////////////////////////////////////////////////////////////// +// WRITE REGISTERS: called by main emu +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val) +{ + long r=reg&0xffff; + + + + regArea[r] = val; + + if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ + //regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ + //regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int rx=0; + int ch=0; + if(r>=0x400) { + rx= r - 0x400; + ch=(rx>>4)+24; + } else { + rx= r; + ch=(rx>>4); + } + + switch(rx&0x0f) + { + //------------------------------------------------// r volume + case 0: + SetVolumeL((unsigned char)ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// l volume + case 2: + SetVolumeR((unsigned char)ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// pitch + case 4: + SetPitch(ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// level with pre-calcs + case 6: + { + const unsigned long lval=val;unsigned long lx; + //---------------------------------------------// + s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; + s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; + s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; + //---------------------------------------------// + if(!iDebugMode) break; + //---------------------------------------------// stuff below is only for debug mode + + s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0; //0x007f + + lx=(((lval>>8) & 0x007f)>>2); // attack time to run from 0 to 100% volume + lx=min(31,lx); // no overflow on shift! + if(lx) + { + lx = (1<>4) & 0x000f; // decay: + if(lx) // our const decay value is time it takes from 100% to 0% of volume + { + lx = ((1<<(lx))*DECAY_MS)/10000L; + if(!lx) lx=1; + } + s_chan[ch].ADSR.DecayTime = // so calc how long does it take to run from 100% to the wanted sus level + (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024; + } +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADSR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// adsr times with pre-calcs + case 8: + { + const unsigned long lval=val;unsigned long lx; + + //----------------------------------------------// + s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; + s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; + //----------------------------------------------// + if(!iDebugMode) break; + //----------------------------------------------// stuff below is only for debug mode + + s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0; + + lx=((((lval>>6) & 0x007f)>>2)); // sustain time... often very high + lx=min(31,lx); // values are used to hold the volume + if(lx) // until a sound stop occurs + { // the highest value we reach (due to + lx = (1< 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + default: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Unknown Mixing reg - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + } + + return; + } + + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0;unsigned long rx=r; + + ch=((rx & 0x3ff)-0x1c0) / 0xC; + + rx-=ch*0xC; + if(rx>=0x400) {ch+=24;rx-=0x400;} + + switch(rx) + { + //------------------------------------------------// + case 0x1C0: + s_chan[ch].iStartAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iStartAdr&0xFFFF); + s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1C2: + s_chan[ch].iStartAdr=(s_chan[ch].iStartAdr & 0x3f0000) | (val & 0xFFFF); + s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + case 0x1C4: + s_chan[ch].iLoopAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iLoopAdr&0xFFFF); + s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); + if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; + else s_chan[ch].bIgnoreLoop=0; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1C6: + s_chan[ch].iLoopAdr=(s_chan[ch].iLoopAdr & 0x3f0000) | (val & 0xFFFF); + s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); + if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; + else s_chan[ch].bIgnoreLoop=0; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + case 0x1C8: + // unused... check if it gets written as well + s_chan[ch].iNextAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iNextAdr&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1CA: + // unused... check if it gets written as well + s_chan[ch].iNextAdr=(s_chan[ch].iNextAdr & 0x3f0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + } + + return; + } + + switch(r) + { + //-------------------------------------------------// + case PS2_C0_SPUaddr_Hi: + spuAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[0]&0xFFFF); // 6bits +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUaddr_Lo: + spuAddr2[0] = (spuAddr2[0] & 0x3F0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUaddr_Hi: + spuAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[1]&0xFFFF); // 6bits +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUaddr_Lo: + spuAddr2[1] = (spuAddr2[1] & 0x3F0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUdata: + spuMem[spuAddr2[0]] = val; + if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ + regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + spuAddr2[0]++; + if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; + spuStat2[0]|=0x80; + spuCtrl2[0]&=~0x30; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU Data - Core 0 Addr %X Val %X\r\n", spuAddr2[0]-1, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUdata: + spuMem[spuAddr2[1]] = val; + + if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + spuAddr2[1]++; + if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; + spuStat2[1]|=0x80; + spuCtrl2[1]&=~0x30; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU Data - Core 1 Addr %X Val %X\r\n", spuAddr2[1]-1, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ATTR: + spuCtrl2[0]=val; + if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x4; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ATTR - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ADMAS: + regArea[(PS2_C0_ADMAS)]=val; + ///regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_ADMAS: + regArea[(PS2_C1_ADMAS)]=val; + //regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_ATTR: + spuCtrl2[1]=val; + if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x8; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ATTR - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUstat: + spuStat2[0]=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUstat: + spuStat2[1]=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAddr_Hi: + spuRvbAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[0]&0xFFFF); + SetReverbAddr(0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAddr_Lo: + spuRvbAddr2[0] = (spuRvbAddr2[0] & 0x3f0000) | (val & 0xFFFF); + SetReverbAddr(0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAEnd_Hi: + spuRvbAEnd2[0] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[0]&0xFFFF)*/; + rvb[0].EndAddr=spuRvbAEnd2[0]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAEnd_Hi: + spuRvbAEnd2[1] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[1]&0xFFFF)*/; + rvb[1].EndAddr=spuRvbAEnd2[1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAddr_Hi: + spuRvbAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[1]&0xFFFF); + SetReverbAddr(1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAddr_Lo: + spuRvbAddr2[1] = (spuRvbAddr2[1] & 0x3f0000) | (val & 0xFFFF); + SetReverbAddr(1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUirqAddr_Hi: + spuIrq2[0] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[0]&0xFFFF); // 6bits + pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUirqAddr_Lo: + spuIrq2[0] = (spuIrq2[0] & 0x3F0000) | (val & 0xFFFF); + pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUirqAddr_Hi: + spuIrq2[1] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[1]&0xFFFF); // 6bits + pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUirqAddr_Lo: + spuIrq2[1] = (spuIrq2[1] & 0x3F0000) | (val & 0xFFFF); + pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_IRQINFO: + // regArea[PS2_IRQINFO] = 0; // clear +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQINFO - Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_AVOLL: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_AVOLR: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_AVOLL: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_AVOLR: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_SPUrvolL: + rvb[0].VolLeft=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUrvolR: + rvb[0].VolRight=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolL: + rvb[1].VolLeft=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolR: + rvb[1].VolRight=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon1: + SoundOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon2: + SoundOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon1: + SoundOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon2: + SoundOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff1: + SoundOff(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff2: + SoundOff(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff1: + SoundOff(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff2: + SoundOff(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUend1: + dwEndChannel2[0] &= 0xff0000; // According to manual all bits are cleared by writing an arbitary value +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_SPUend2: + dwEndChannel2[0] &= 0xffff; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUend1: + dwEndChannel2[1] &= 0xff0000; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_SPUend2: + dwEndChannel2[1] &= 0xffff; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod1: + FModOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod2: + FModOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod1: + FModOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod2: + FModOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise1: + NoiseOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise2: + NoiseOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise1: + NoiseOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise2: + NoiseOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_MVOLL: + regArea[PS2_C0_MVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_MVOLR: + regArea[PS2_C0_MVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MVOLL: + regArea[PS2_C0_MVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MVOLR: + regArea[PS2_C0_MVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + + case PS2_C0_BVOLL: + regArea[PS2_C0_BVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_BVOLR: + regArea[PS2_C0_BVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_BVOLL: + regArea[PS2_C1_BVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_BVOLR: + regArea[PS2_C1_BVOLR] = val; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_MMIX: + regArea[PS2_C0_MMIX] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MMIX: + regArea[PS2_C1_MMIX] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_DryL1: + VolumeOn(0,16,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryL2: + VolumeOn(16,24,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL1: + VolumeOn(24,40,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL2: + VolumeOn(40,48,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR1: + VolumeOn(0,16,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR2: + VolumeOn(16,24,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR1: + VolumeOn(24,40,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR2: + VolumeOn(40,48,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_L: + ReverbOn(0,16,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_L: + ReverbOn(16,24,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_L: + ReverbOn(24,40,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_L: + ReverbOn(40,48,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_R: + ReverbOn(0,16,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_R: + ReverbOn(16,24,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_R: + ReverbOn(24,40,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_R: + ReverbOn(40,48,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Reverb+0: + rvb[0].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_A&0xFFFF); + break; + case PS2_C0_Reverb+2: + rvb[0].FB_SRC_A=(rvb[0].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+4: + rvb[0].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_B&0xFFFF); + break; + case PS2_C0_Reverb+6: + rvb[0].FB_SRC_B=(rvb[0].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+8: + rvb[0].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A0&0xFFFF); + break; + case PS2_C0_Reverb+10: + rvb[0].IIR_DEST_A0=(rvb[0].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+12: + rvb[0].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A1&0xFFFF); + break; + case PS2_C0_Reverb+14: + rvb[0].IIR_DEST_A1=(rvb[0].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+16: + rvb[0].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A0&0xFFFF); + break; + case PS2_C0_Reverb+18: + rvb[0].ACC_SRC_A0=(rvb[0].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+20: + rvb[0].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A1&0xFFFF); + break; + case PS2_C0_Reverb+22: + rvb[0].ACC_SRC_A1=(rvb[0].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+24: + rvb[0].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B0&0xFFFF); + break; + case PS2_C0_Reverb+26: + rvb[0].ACC_SRC_B0=(rvb[0].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+28: + rvb[0].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B1&0xFFFF); + break; + case PS2_C0_Reverb+30: + rvb[0].ACC_SRC_B1=(rvb[0].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+32: + rvb[0].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A0&0xFFFF); + break; + case PS2_C0_Reverb+34: + rvb[0].IIR_SRC_A0=(rvb[0].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+36: + rvb[0].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A1&0xFFFF); + break; + case PS2_C0_Reverb+38: + rvb[0].IIR_SRC_A1=(rvb[0].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+40: + rvb[0].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B0&0xFFFF); + break; + case PS2_C0_Reverb+42: + rvb[0].IIR_DEST_B0=(rvb[0].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+44: + rvb[0].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B1&0xFFFF); + break; + case PS2_C0_Reverb+46: + rvb[0].IIR_DEST_B1=(rvb[0].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+48: + rvb[0].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C0&0xFFFF); + break; + case PS2_C0_Reverb+50: + rvb[0].ACC_SRC_C0=(rvb[0].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+52: + rvb[0].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C1&0xFFFF); + break; + case PS2_C0_Reverb+54: + rvb[0].ACC_SRC_C1=(rvb[0].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+56: + rvb[0].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D0&0xFFFF); + break; + case PS2_C0_Reverb+58: + rvb[0].ACC_SRC_D0=(rvb[0].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+60: + rvb[0].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D1&0xFFFF); + break; + case PS2_C0_Reverb+62: + rvb[0].ACC_SRC_D1=(rvb[0].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+64: + rvb[0].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B1&0xFFFF); + break; + case PS2_C0_Reverb+66: + rvb[0].IIR_SRC_B1=(rvb[0].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+68: + rvb[0].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B0&0xFFFF); + break; + case PS2_C0_Reverb+70: + rvb[0].IIR_SRC_B0=(rvb[0].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+72: + rvb[0].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A0&0xFFFF); + break; + case PS2_C0_Reverb+74: + rvb[0].MIX_DEST_A0=(rvb[0].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+76: + rvb[0].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A1&0xFFFF); + break; + case PS2_C0_Reverb+78: + rvb[0].MIX_DEST_A1=(rvb[0].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+80: + rvb[0].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B0&0xFFFF); + break; + case PS2_C0_Reverb+82: + rvb[0].MIX_DEST_B0=(rvb[0].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+84: + rvb[0].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B1&0xFFFF); + break; + case PS2_C0_Reverb+86: + rvb[0].MIX_DEST_B1=(rvb[0].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_ReverbX+0: rvb[0].IIR_ALPHA=(short)val; break; + case PS2_C0_ReverbX+2: rvb[0].ACC_COEF_A=(short)val; break; + case PS2_C0_ReverbX+4: rvb[0].ACC_COEF_B=(short)val; break; + case PS2_C0_ReverbX+6: rvb[0].ACC_COEF_C=(short)val; break; + case PS2_C0_ReverbX+8: rvb[0].ACC_COEF_D=(short)val; break; + case PS2_C0_ReverbX+10: rvb[0].IIR_COEF=(short)val; break; + case PS2_C0_ReverbX+12: rvb[0].FB_ALPHA=(short)val; break; + case PS2_C0_ReverbX+14: rvb[0].FB_X=(short)val; break; + case PS2_C0_ReverbX+16: rvb[0].IN_COEF_L=(short)val; break; + case PS2_C0_ReverbX+18: rvb[0].IN_COEF_R=(short)val; break; + //-------------------------------------------------// + case PS2_C1_Reverb+0: + rvb[1].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_A&0xFFFF); + break; + case PS2_C1_Reverb+2: + rvb[1].FB_SRC_A=(rvb[1].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+4: + rvb[1].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_B&0xFFFF); + break; + case PS2_C1_Reverb+6: + rvb[1].FB_SRC_B=(rvb[1].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+8: + rvb[1].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A0&0xFFFF); + break; + case PS2_C1_Reverb+10: + rvb[1].IIR_DEST_A0=(rvb[1].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+12: + rvb[1].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A1&0xFFFF); + break; + case PS2_C1_Reverb+14: + rvb[1].IIR_DEST_A1=(rvb[1].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+16: + rvb[1].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A0&0xFFFF); + break; + case PS2_C1_Reverb+18: + rvb[1].ACC_SRC_A0=(rvb[1].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+20: + rvb[1].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A1&0xFFFF); + break; + case PS2_C1_Reverb+22: + rvb[1].ACC_SRC_A1=(rvb[1].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+24: + rvb[1].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B0&0xFFFF); + break; + case PS2_C1_Reverb+26: + rvb[1].ACC_SRC_B0=(rvb[1].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+28: + rvb[1].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B1&0xFFFF); + break; + case PS2_C1_Reverb+30: + rvb[1].ACC_SRC_B1=(rvb[1].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+32: + rvb[1].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A0&0xFFFF); + break; + case PS2_C1_Reverb+34: + rvb[1].IIR_SRC_A0=(rvb[1].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+36: + rvb[1].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A1&0xFFFF); + break; + case PS2_C1_Reverb+38: + rvb[1].IIR_SRC_A1=(rvb[1].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+40: + rvb[1].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B0&0xFFFF); + break; + case PS2_C1_Reverb+42: + rvb[1].IIR_DEST_B0=(rvb[1].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+44: + rvb[1].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B1&0xFFFF); + break; + case PS2_C1_Reverb+46: + rvb[1].IIR_DEST_B1=(rvb[1].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+48: + rvb[1].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C0&0xFFFF); + break; + case PS2_C1_Reverb+50: + rvb[1].ACC_SRC_C0=(rvb[1].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+52: + rvb[1].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C1&0xFFFF); + break; + case PS2_C1_Reverb+54: + rvb[1].ACC_SRC_C1=(rvb[1].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+56: + rvb[1].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D0&0xFFFF); + break; + case PS2_C1_Reverb+58: + rvb[1].ACC_SRC_D0=(rvb[1].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+60: + rvb[1].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D1&0xFFFF); + break; + case PS2_C1_Reverb+62: + rvb[1].ACC_SRC_D1=(rvb[1].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+64: + rvb[1].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B1&0xFFFF); + break; + case PS2_C1_Reverb+66: + rvb[1].IIR_SRC_B1=(rvb[1].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+68: + rvb[1].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B0&0xFFFF); + break; + case PS2_C1_Reverb+70: + rvb[1].IIR_SRC_B0=(rvb[1].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+72: + rvb[1].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A0&0xFFFF); + break; + case PS2_C1_Reverb+74: + rvb[1].MIX_DEST_A0=(rvb[1].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+76: + rvb[1].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A1&0xFFFF); + break; + case PS2_C1_Reverb+78: + rvb[1].MIX_DEST_A1=(rvb[1].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+80: + rvb[1].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B0&0xFFFF); + break; + case PS2_C1_Reverb+82: + rvb[1].MIX_DEST_B0=(rvb[1].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+84: + rvb[1].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B1&0xFFFF); + break; + case PS2_C1_Reverb+86: + rvb[1].MIX_DEST_B1=(rvb[1].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_ReverbX+0: rvb[1].IIR_ALPHA=(short)val; break; + case PS2_C1_ReverbX+2: rvb[1].ACC_COEF_A=(short)val; break; + case PS2_C1_ReverbX+4: rvb[1].ACC_COEF_B=(short)val; break; + case PS2_C1_ReverbX+6: rvb[1].ACC_COEF_C=(short)val; break; + case PS2_C1_ReverbX+8: rvb[1].ACC_COEF_D=(short)val; break; + case PS2_C1_ReverbX+10: rvb[1].IIR_COEF=(short)val; break; + case PS2_C1_ReverbX+12: rvb[1].FB_ALPHA=(short)val; break; + case PS2_C1_ReverbX+14: rvb[1].FB_X=(short)val; break; + case PS2_C1_ReverbX+16: rvb[1].IN_COEF_L=(short)val; break; + case PS2_C1_ReverbX+18: rvb[1].IN_COEF_R=(short)val; break; + case PS2_SPDIF_OUT: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_MODE: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_MEDIA: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_COPY: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + default: //All other writes +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Unknown Register Addr %X Value %X\r\n",reg&0xFFFF,val); +#endif + break; + } + + iSpuAsyncWait=0; + +} + +//////////////////////////////////////////////////////////////////////// +// READ REGISTER: called by main emu +//////////////////////////////////////////////////////////////////////// +EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg) +{ + long r=reg&0xffff; + unsigned int ret = 0; + +if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ + //regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } +if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ + //regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int addr=0; + int ch=((r & 0x3ff)>>4); + if(r>=0x400) ch+=24; + + switch(r&0x0f) + { + case 0: //Left Volume + ret = s_chan[ch].iLeftVolRaw; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 2: //Right Volume + ret = s_chan[ch].iRightVolRaw; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 4: //Pitch + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 6: //ASDR1 + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ASDR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 8: //ASDR2 + ret = regArea[r]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ASDR2 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 10: //Envelope (current) + ret = (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Envelope - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + + } + + }else + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0;unsigned long rx=r; + + ch=((rx & 0x3ff)-0x1c0) / 0xC; + + rx-=ch*0xC; + if(rx>=0x400) {ch+=24;rx-=0x400;} + + switch(rx) + { + case 0x1C0: + ret = (((s_chan[ch].pStart-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1C2: + ret = (((s_chan[ch].pStart-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + //------------------------------------------------// + case 0x1C4: + ret = (((s_chan[ch].pLoop-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1C6: + ret = (((s_chan[ch].pLoop-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + //------------------------------------------------// + case 0x1C8: + ret = ((((s_chan[ch].pCurr)-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1CA: + ret = ((((s_chan[ch].pCurr)-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + default: + ret = regArea[rx]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Channel Addr Unknown - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + + //------------------------------------------------// + } + }else{ + switch(r) + { + //--------------------------------------------------// + case PS2_C0_SPUend1: + ret = (unsigned short)((dwEndChannel2[0]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_SPUend2: + ret = (unsigned short)((dwEndChannel2[0]>>16)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUend1: + ret = (unsigned short)((dwEndChannel2[1]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_SPUend2: + ret = (unsigned short)((dwEndChannel2[1]>>16)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_ATTR: + ret = spuCtrl2[0]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Core Attr - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_ATTR: + ret = spuCtrl2[1]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Core Attr - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUstat: + ret = spuStat2[0]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Status - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUstat: + ret = spuStat2[1]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Status - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUdata: + { + unsigned short s=spuMem[spuAddr2[0]]; + + if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ + regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + spuAddr2[0]++; + if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; + spuStat2[0]|=0x80; + spuCtrl2[0]&=~0x30; + ret = s; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Data - Core 0 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[0]-1, ret); +#endif + } + break; + //--------------------------------------------------// + case PS2_C1_SPUdata: + { + unsigned short s=spuMem[spuAddr2[1]]; + + if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + spuAddr2[1]++; + if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; + spuStat2[1]|=0x80; + spuCtrl2[1]&=~0x30; + ret = s; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Data - Core 1 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[1]-1, ret); +#endif + } + break; + //--------------------------------------------------// + case PS2_C0_SPUaddr_Hi: + ret = (unsigned short)((spuAddr2[0]>>16)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_SPUaddr_Lo: + ret = (unsigned short)((spuAddr2[0]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUaddr_Hi: + ret = (unsigned short)((spuAddr2[1]>>16)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_SPUaddr_Lo: + ret = (unsigned short)((spuAddr2[1]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ReverbAEnd_Hi: + ret = regArea[PS2_C0_ReverbAEnd_Hi]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAEnd_Hi: + ret = regArea[PS2_C1_ReverbAEnd_Hi]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ReverbAddr_Lo: + ret = regArea[PS2_C0_ReverbAddr_Lo]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + + case PS2_C1_ReverbAddr_Lo: + ret = regArea[PS2_C1_ReverbAddr_Lo]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_IRQINFO: + ret = regArea[PS2_IRQINFO]; + // regArea[PS2_IRQINFO] = 0; // clear +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG IRQINFO - Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ADMAS: + ret = regArea[(PS2_C0_ADMAS)]; + ///regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_ADMAS: + ret = regArea[(PS2_C1_ADMAS)]; + //regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUrvolL: + ret = rvb[0].VolLeft; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUrvolR: + ret = rvb[0].VolRight; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolL: + ret = rvb[1].VolLeft; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolR: + ret = rvb[1].VolRight; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon1: + ret = regArea[PS2_C0_SPUon1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon2: + ret = regArea[PS2_C0_SPUon2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon1: + ret = regArea[PS2_C1_SPUon1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon2: + ret = regArea[PS2_C1_SPUon2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff1: + ret = regArea[PS2_C0_SPUoff1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff2: + ret = regArea[PS2_C0_SPUoff2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff1: + ret = regArea[PS2_C1_SPUoff1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff2: + ret = regArea[PS2_C1_SPUoff2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod1: + ret = regArea[PS2_C0_FMod1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod2: + ret = regArea[PS2_C0_FMod2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod1: + ret = regArea[PS2_C1_FMod1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod2: + ret = regArea[PS2_C1_FMod2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise1: + ret = regArea[PS2_C0_Noise1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise2: + ret = regArea[PS2_C0_Noise2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise1: + ret = regArea[PS2_C1_Noise1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise2: + ret = regArea[PS2_C1_Noise2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_AVOLL: + ret = regArea[PS2_C0_AVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_AVOLR: + ret = regArea[PS2_C0_AVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_AVOLL: + ret = regArea[PS2_C1_AVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_AVOLR: + ret = regArea[PS2_C1_AVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MVOLL: + ret = regArea[PS2_C0_MVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MVOLR: + ret = regArea[PS2_C0_MVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MVOLL: + regArea[PS2_C0_MVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MVOLR: + ret = regArea[PS2_C0_MVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + + case PS2_C0_BVOLL: + ret = regArea[PS2_C0_BVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_BVOLR: + ret = regArea[PS2_C0_BVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_BVOLL: + ret = regArea[PS2_C1_BVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_BVOLR: + ret = regArea[PS2_C1_BVOLR]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MMIX: + ret = regArea[PS2_C0_MMIX]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MMIX: + ret = regArea[PS2_C1_MMIX]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_DryL1: + ret = regArea[PS2_C0_DryL1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryL2: + ret = regArea[PS2_C0_DryL2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL1: + ret = regArea[PS2_C1_DryL1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL2: + ret = regArea[PS2_C1_DryL2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR1: + ret = regArea[PS2_C0_DryR1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR2: + ret = regArea[PS2_C0_DryR2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR1: + ret = regArea[PS2_C1_DryR1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR2: + ret = regArea[PS2_C1_DryR2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_L: + ret = regArea[PS2_C0_RVBon1_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_L: + ret = regArea[PS2_C0_RVBon2_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_L: + ret = regArea[PS2_C1_RVBon1_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_L: + ret = regArea[PS2_C1_RVBon2_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_R: + ret = regArea[PS2_C0_RVBon1_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_R: + ret = regArea[PS2_C0_RVBon2_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_R: + ret = regArea[PS2_C1_RVBon1_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_R: + ret = regArea[PS2_C1_RVBon2_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_SPDIF_OUT: + ret = regArea[PS2_SPDIF_OUT]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_MODE: + ret = regArea[PS2_SPDIF_MODE]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_MEDIA: + ret = regArea[PS2_SPDIF_MEDIA]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_COPY: + ret = regArea[PS2_SPDIF_COPY]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + default: + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Unknown Register - Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + } + /*#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG %X Val %X\r\n",reg&0xFFFF, ret); +#endif*/ + } + + + return ret; +} + +//////////////////////////////////////////////////////////////////////// +// SOUND ON register write +//////////////////////////////////////////////////////////////////////// + +void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! + { + //s_chan[ch].bStop = 0; + if(ch > 24){ + int tempchan = ch-24; + if(tempchan > 15) { + regArea[PS2_C1_SPUoff2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C1_SPUoff1] &= ~(1< 15) { + regArea[PS2_C0_SPUoff2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C0_SPUoff1] &= ~(1<>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + { + if(ch > 24){ + int tempchan = ch-24; + if(tempchan > 15) { + regArea[PS2_C1_SPUon2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C1_SPUon1] &= ~(1< 15) { + regArea[PS2_C0_SPUon2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C0_SPUon1] &= ~(1<>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) + { + s_chan[ch].bFMod=1; // --> sound channel + s_chan[ch-1].bFMod=2; // --> freq channel + } + } + else + { + s_chan[ch].bFMod=0; // --> turn off fmod + } + } +} + +//////////////////////////////////////////////////////////////////////// +// NOISE register write +//////////////////////////////////////////////////////////////////////// + +void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> noise on/off + { + s_chan[ch].bNoise=1; + } + else + { + s_chan[ch].bNoise=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// LEFT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +// please note: sweep and phase invert are wrong... but I've never seen +// them used + +void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME +{ + s_chan[ch].iLeftVolRaw=vol; + + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + //vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + s_chan[ch].iLeftVolume=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// RIGHT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME +{ + s_chan[ch].iRightVolRaw=vol; + + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) //vol=vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + + s_chan[ch].iRightVolume=vol; +} + +//////////////////////////////////////////////////////////////////////// +// PITCH register write +//////////////////////////////////////////////////////////////////////// + +void SetPitch(int ch,unsigned short val) // SET PITCH +{ + int NP; + if(val>0x3fff) NP=0x3fff; // get pitch val + else NP=val; + + s_chan[ch].iRawPitch=NP; + + NP=(48000L*NP)/4096L; // calc frequency(48000Hz) + if(NP<1) NP=1; // some security + s_chan[ch].iActFreq=NP; // store frequency +} + +//////////////////////////////////////////////////////////////////////// +// REVERB register write +//////////////////////////////////////////////////////////////////////// + +void ReverbOn(int start,int end,unsigned short val,int iRight) // REVERB ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> reverb on/off + { + if(iRight) s_chan[ch].bReverbR=1; + else s_chan[ch].bReverbL=1; + } + else + { + if(iRight) s_chan[ch].bReverbR=0; + else s_chan[ch].bReverbL=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// REVERB START register write +//////////////////////////////////////////////////////////////////////// + +void SetReverbAddr(int core) +{ + long val=spuRvbAddr2[core]; + + if(rvb[core].StartAddr!=val) + { + if(val<=0x27ff) + { + rvb[core].StartAddr=rvb[core].CurrAddr=0; + } + else + { + rvb[core].StartAddr=val; + rvb[core].CurrAddr=rvb[core].StartAddr; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// DRY LEFT/RIGHT per voice switches +//////////////////////////////////////////////////////////////////////// + +void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> reverb on/off + { + if(iRight) s_chan[ch].bVolumeR=1; + else s_chan[ch].bVolumeL=1; + } + else + { + if(iRight) s_chan[ch].bVolumeR=0; + else s_chan[ch].bVolumeL=0; + } + } +} + + diff --git a/plugins/spu2/PeopsSPU2/registers.h b/plugins/spu2/PeopsSPU2/registers.h new file mode 100644 index 0000000000..6a83201784 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/registers.h @@ -0,0 +1,820 @@ +/*************************************************************************** + registers.h - description + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - generic cleanup for the Peops release... register values by Kanodin & +// his team +// +//*************************************************************************// + +//########################################################################### + +#define PS2_C0_SPUaddr_Hi (0x1A8) +#define PS2_C0_SPUaddr_Lo (0x1AA) +#define PS2_C1_SPUaddr_Hi (0x5A8) +#define PS2_C1_SPUaddr_Lo (0x5AA) +#define PS2_C0_SPUdata (0x1AC) +#define PS2_C1_SPUdata (0x5AC) + +#define PS2_C0_SPUDMActrl (0x1AE) +#define PS2_C1_SPUDMActrl (0x5AE) + +#define PS2_C0_SPUstat (0x344) +#define PS2_C1_SPUstat (0x744) +#define PS2_IRQINFO (0x7C2) +#define PS2_C0_ReverbAddr_Hi (0x2E0) +#define PS2_C0_ReverbAddr_Lo (0x2E2) +#define PS2_C1_ReverbAddr_Hi (0x6E0) +#define PS2_C1_ReverbAddr_Lo (0x6E2) + +#define PS2_C0_ReverbAEnd_Hi (0x33C) +#define PS2_C0_ReverbAEnd_Lo (0x33E) +#define PS2_C1_ReverbAEnd_Hi (0x73C) +#define PS2_C1_ReverbAEnd_Lo (0x73E) + +#define PS2_C0_DryL1 (0x188) +#define PS2_C1_DryL1 (0x588) +#define PS2_C0_DryL2 (0x18A) +#define PS2_C1_DryL2 (0x58A) + +#define PS2_C0_DryR1 (0x190) +#define PS2_C1_DryR1 (0x590) +#define PS2_C0_DryR2 (0x192) +#define PS2_C1_DryR2 (0x592) + +#define PS2_C0_ATTR (0x19A) +#define PS2_C1_ATTR (0x59A) +#define PS2_C0_ADMAS (0x1B0) +#define PS2_C1_ADMAS (0x5B0) + +#define PS2_C0_SPUirqAddr_Hi (0x19C) +#define PS2_C0_SPUirqAddr_Lo (0x19E) +#define PS2_C1_SPUirqAddr_Hi (0x59C) +#define PS2_C1_SPUirqAddr_Lo (0x59E) +#define PS2_C0_SPUrvolL (0x764) +#define PS2_C0_SPUrvolR (0x766) +#define PS2_C1_SPUrvolL (0x028 + 0x764) +#define PS2_C1_SPUrvolR (0x028 + 0x766) +#define PS2_C0_SPUon1 (0x1A0) +#define PS2_C0_SPUon2 (0x1A2) +#define PS2_C1_SPUon1 (0x5A0) +#define PS2_C1_SPUon2 (0x5A2) +#define PS2_C0_SPUoff1 (0x1A4) +#define PS2_C0_SPUoff2 (0x1A6) +#define PS2_C1_SPUoff1 (0x5A4) +#define PS2_C1_SPUoff2 (0x5A6) +#define PS2_C0_FMod1 (0x180) +#define PS2_C0_FMod2 (0x182) +#define PS2_C1_FMod1 (0x580) +#define PS2_C1_FMod2 (0x582) +#define PS2_C0_Noise1 (0x184) +#define PS2_C0_Noise2 (0x186) +#define PS2_C1_Noise1 (0x584) +#define PS2_C1_Noise2 (0x586) + +#define PS2_C0_RVBon1_L (0x18C) +#define PS2_C0_RVBon2_L (0x18E) +#define PS2_C0_RVBon1_R (0x194) +#define PS2_C0_RVBon2_R (0x196) + +#define PS2_C1_RVBon1_L (0x58C) +#define PS2_C1_RVBon2_L (0x58E) +#define PS2_C1_RVBon1_R (0x594) +#define PS2_C1_RVBon2_R (0x596) +#define PS2_C0_Reverb (0x2E4) +#define PS2_C1_Reverb (0x6E4) +#define PS2_C0_ReverbX (0x774) +#define PS2_C1_ReverbX (0x028 + 0x774) +#define PS2_C0_SPUend1 (0x340) +#define PS2_C0_SPUend2 (0x342) +#define PS2_C1_SPUend1 (0x740) +#define PS2_C1_SPUend2 (0x742) +#define PS2_C0_AVOLL (0x768) // Disabled really, but games read it +#define PS2_C0_AVOLR (0x76A) // In for logging purposes +#define PS2_C1_AVOLL (0x790) // core external input volume (left) core 1 +#define PS2_C1_AVOLR (0x792) // core external input volume (right) core 1 +#define PS2_C0_BVOLL (0x76C) +#define PS2_C0_BVOLR (0x76E) +#define PS2_C1_BVOLL (0x794) +#define PS2_C1_BVOLR (0x796) +#define PS2_C0_MMIX (0x198) +#define PS2_C1_MMIX (0x598) + +#define PS2_C0_MVOLL (0x760) +#define PS2_C0_MVOLR (0x762) +#define PS2_C1_MVOLL (0x788) +#define PS2_C1_MVOLR (0x78A) + +// CORE 1 only + +#define PS2_SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define PS2_SPDIF_MODE 0x7C6 +#define PS2_SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define PS2_SPDIF_COPY 0x7CA // SPDIF Copy Protection + +//########################################################################### + +/* + Included the info received in Regs.txt list by Neill Corlett - Kanodin + + Voice parameters: + SD_VP_VOLL, SD_VP_VOLR - Volume left/right per voice. Assuming identical to PS1. + SD_VP_PITCH - Pitch scaler 0000-3FFF. Assuming identical to PS1. + SD_VP_ADSR1, SD_VP_ADSR1 - Envelope data. Bitfields are documented as identical to PS1. + SD_VP_ENVX - Current envelope value. Assuming identical to PS1. + SD_VP_VOLXL, SD_VP_VOLXR - Current voice volume left/right. Does not exist on the PS1. + Guessing that this is handy for the increase/decrease modes. + + Voice addresses: + + SD_VA_SSA - Sample start address; assuming identical to PS1 + SD_VA_LSAX - Loop start address; assuming identical to PS1 + SD_VA_NAX - Seems to be documented as the current playing address. + Does not exist on PS1. + + Switches: + + SD_S_PMON - Pitch mod; assuming identical to PS1 + SD_S_NON - Noise; assuming identical to PS1 + SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version + of the "voice enable" bits on the PS1. + SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R + version of the "voice reverb enable" bits on the PS1. + SD_S_KON, SD_S_KOFF - Key on/off; assuming identical to PS1 + + + Addresses: + + SD_A_TSA - Transfer start address; assuming identical to PS1 + SD_A_ESA - Effect start address - this is probably analogous to the + PS1's reverb work area start address + SD_A_EEA - Effect end address - this would've been fixed to 0x7FFFF on + the PS1; settable in 128K increments on the PS2. + SD_A_IRQA - IRQ address; assuming identical to PS1 + + Volume parameters: + + SD_P_MVOLL, SD_P_MVOLR - Master volume L/R; assuming identical to PS1 + SD_P_EVOLL, SD_P_EVOLR - Effect volume L/R; assuming analogous to RVOL on the PS1 + SD_P_AVOLL, SD_P_AVOLR - External input volume L/R + This is probably where CORE0 connects to CORE1 + SD_P_BVOLL, SD_P_BVOLR - Sound data input volume - perhaps this is the volume of + the raw PCM auto-DMA input? analogous to CD input volume? + SD_P_MVOLXL, SD_P_MVOLXR - Current master volume L/R; seems self-explanatory + + SD_P_MMIX - Mixer / effect enable bits. + bit 11 = MSNDL = voice output dry L + 10 = MSNDR = voice output dry R + 9 = MSNDEL = voice output wet L + 8 = MSNDER = voice output wet R + 7 = MINL = sound data input dry L + 6 = MINR = sound data input dry R + 5 = MINEL = sound data input wet L + 4 = MINER = sound data input wet R + 3 = SINL = core external input dry L + 2 = SINR = core external input dry R + 1 = SINEL = core external input wet L + 0 = SINER = core external input wet R + +Core attributes (SD_C) + + bit 4..5 - DMA related + bit 6 - IRQ enable + bit 7 - effect enable (reverb enable) + bit 13..8 - noise clock + bit 14 - mute + + - if you READ the two DMA related bits, if either are set, the channel is + considered "busy" by sceSdVoiceTrans + + + +Reverb parameters: + + Same as PS1 reverb (I used the names from my reverb doc). + + +Other PS2 IOP notes + + There's two DMA controllers: + The original one at 1F801080-1F8010FF (channels 0-6) + A new one at 1F801500-1F80157F (channels 7-13) + + They appear to function the same way - 7 channels each. + + SPU CORE0's DMA channel is 4 as per usual + SPU CORE1's DMA channel is 7 + +DMA channel 10 is SIF + + Original INTR controller at 1F801000-1F80107F + + All interrupt handling seems to be done using the old INTR, but + with some new bits defined: + + + + Reading from 1F801078 masks interrupts and returns 1 if they weren't + masked before. Writing 1 to 1F801078 re-enables interrupts. + Writing 0 doesn't. Maybe it was like that on the original PS1 too. + +Six root counters: + + RTC# address sources size prescale interrupt# +0 0x1F801100 sysclock,pixel 16 bit 1 only 4 +1 0x1F801110 sysclock,hline 16 bit 1 only 5 +2 0x1F801120 sysclock 16 bit 1,8 6 +3 0x1F801480 sysclock,hline 32 bit 1 only 14 +4 0x1F801490 sysclock 32 bit 1,8,16,256 15 +5 0x1F8014A0 sysclock 32 bit 1,8,16,256 16 + +Count (0x0) and Compare (0x8) registers work as before, only with more bits +in the new counters. + +Mode (0x4) works like this when written: + + bits 0..2 gate + bit 3 reset on target + bit 4 target interrupt enable + bit 5 overflow interrupt enable + bit 6 master enable (?) + bit 7 ? + bit 8 clock select + bit 9 prescale (OLD) + bit 10..12 ? + bit 13..14 prescale (NEW) + bit 15 ? always set to 1 + +Gate: + TM_NO_GATE 000 + TM_GATE_ON_Count 001 + TM_GATE_ON_ClearStart 011 + TM_GATE_ON_Clear_OFF_Start 101 + TM_GATE_ON_Start 111 + + V-blank ----+ +----------------------------+ +------ + | | | | + | | | | + +----+ +----+ + TM_NO_GATE: + + 0================================>============ + + TM_GATE_ON_Count: + + <---->0==========================><---->0===== + + TM_GATE_ON_ClearStart: + + 0====>0================================>0===== + + TM_GATE_ON_Clear_OFF_Start: + + 0====><-------------------------->0====><----- + + TM_GATE_ON_Start: + + <---->0==========================>============ + + reset on target: if set, counter resets to 0 when Compare value is reached + + target interrupt enable: if set, interrupt when Compare value is reached + overflow interrupt enable: if set, interrupt when counter overflows + + master enable: if this bit is clear, the timer should do nothing. + + clock select: for counters 0, 1, and 3, setting this will select the alternate + counter (pixel or hline) + + prescale (OLD): for counter 2 only. set this to prescale (divide) by 8. + + prescale (NEW): for counters 4 and 5 only: + + 00 = prescale by 1 + 01 = prescale by 8 + 10 = prescale by 16 + 11 = prescale by 256 + +Writing 0x4 also clears the counter. (I think.) + +When 0x4 is read, it becomes Status: + + bit 0..10 ? + bit 11 compare value was reached + bit 12 count overflowed + bit 13..15 ? + +Reading probably clears these bits. + + + + 1F8014B0 (word) - timer-related but otherwise unknown + 1F8014C0 (word) - timer-related but otherwise unknown + + + don't currently know how the interrupts work for DMA ch7 yet + + 1F801060 (word) - address of some kind. + + 1F801450 (word) - + if bit 3 is SET, we're in PS1 mode. + if bit 3 is CLEAR, we're in PS2 IOP mode. + + 1F802070 (byte) - unknown. status byte of some kind? visible to EE? + + 1D000000-1D00007F (?) - SIF related + + 1D000020 (word) - read counter of some sort? + sceSifInit waits for bit 0x10000 of this to be set. + 1D000030 (word) - read counter of some sort? + 1D000040 (word) - read bits 0x20, 0x40 mean something + 1D000060 (word) - used to detect whether the SIF interface exists + read must be 0x1D000060, or the top 20 bits must be zero +*/ + +/* + +// DirectX Audio SPU2 Driver for PCSX2 +// audio.c by J.F. and Kanodin (hooper1@cox.net) +// +// Copyright 2003 J.F. and Kanodin, and distributed under the +// terms of the GNU General Public License, v2 or later. +// http://www.gnu.org/copyleft/gpl.html. + +Included these just in case you need them J.F. - Kanodin + +// Core Start Addresses +#define CORE0 0x1f900000 +#define CORE1 0x1f900400 + + + #define IOP_INT_VBLANK (1<<0) + #define IOP_INT_GM (1<<1) + #define IOP_INT_CDROM (1<<2) + #define IOP_INT_DMA (1<<3) + #define IOP_INT_RTC0 (1<<4) + #define IOP_INT_RTC1 (1<<5) + #define IOP_INT_RTC2 (1<<6) + #define IOP_INT_SIO0 (1<<7) + #define IOP_INT_SIO1 (1<<8) + #define IOP_INT_SPU (1<<9) + #define IOP_INT_PIO (1<<10) + #define IOP_INT_EVBLANK (1<<11) + #define IOP_INT_DVD (1<<12) + #define IOP_INT_PCMCIA (1<<13) + #define IOP_INT_RTC3 (1<<14) + #define IOP_INT_RTC4 (1<<15) + #define IOP_INT_RTC5 (1<<16) + #define IOP_INT_SIO2 (1<<17) + #define IOP_INT_HTR0 (1<<18) + #define IOP_INT_HTR1 (1<<19) + #define IOP_INT_HTR2 (1<<20) + #define IOP_INT_HTR3 (1<<21) + #define IOP_INT_USB (1<<22) + #define IOP_INT_EXTR (1<<23) + #define IOP_INT_FWRE (1<<24) + #define IOP_INT_FDMA (1<<25) + +// CORE0 => +0x000, CORE1 => +0x400 + +// individual voice parameter regs + +#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) +#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) +#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch +#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) +#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) +#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) +#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) +#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) + +#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address +#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address +#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address + +// common settings + +#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on +#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on +#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) +#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) +#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) +#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) +#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) +#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) +#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address +#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) +#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) +#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address +#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register +#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register +#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status + +#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address + +#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) +#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) +#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) +#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) +#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) +#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) +#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) + +#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) +#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) +#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) +#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) +#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) +#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) +#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) + +#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) +#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) +#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) +#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) +#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) +#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) +#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) +#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) + +#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address + +#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status +#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register +#define P_ENDS(cr) (0x400 * cr + 0x346) // ? + +// CORE0 => +0x400, CORE1 => +0x428 + +#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) +#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) +#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) +#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) +#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) +#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) +#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) +#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) +#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) +#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) + +#define IIR_ALPHA(cr) (0x28 * cr + 0x774) +#define ACC_COEF_A(cr) (0x28 * cr + 0x776) +#define ACC_COEF_B(cr) (0x28 * cr + 0x778) +#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) +#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) +#define IIR_COEF(cr) (0x28 * cr + 0x77E) +#define FB_ALPHA(cr) (0x28 * cr + 0x780) +#define FB_X(cr) (0x28 * cr + 0x782) +#define IN_COEF_L(cr) (0x28 * cr + 0x784) +#define IN_COEF_R(cr) (0x28 * cr + 0x786) + +// CORE1 only => +0x400 + +#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define SPDIF_MODE 0x7C6 +#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x7CA // SPDIF Copy Protection + +// PS1 SPU CORE + +// individual voice settings + +#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch +#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address +#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope +#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address + +// common settings + +#define SPU_P_MVOLL 0xD80 // master volume (left) +#define SPU_P_MVOLR 0xD82 // master volume (right) +#define SPU_P_RVOLL 0xD84 // effect return volume (left) +#define SPU_P_RVOLR 0xD86 // effect return volume (right) +#define SPU_S_KON1 0xD88 // key on +#define SPU_S_KON2 0xD8A // +#define SPU_S_KOFF1 0xD8C // key off +#define SPU_S_KOFF2 0xD8E // +#define SPU_S_PMON1 0xD90 // pitch modulation on +#define SPU_S_PMON2 0xD92 // +#define SPU_S_NON1 0xD94 // noise generator on +#define SPU_S_NON2 0xD96 // +#define SPU_S_RVBON1 0xD98 // effects on +#define SPU_S_RVBON2 0xD9A // +#define SPU_S_MUTE1 0xD9C // voice mute +#define SPU_S_MUTE2 0xD9E // + +#define SPU_A_ESA 0xDA2 // effects work area start +#define SPU_A_IRQA 0xDA4 // IRQ address +#define SPU_A_TSA 0xDA6 // DMA transfer start address +#define SPU_P_DATA 0xDA8 // DMA data register +#define SPU_P_CTRL 0xDAA // DMA control register +#define SPU_P_STAT 0xDAE // DMA status register + +#define SPU_P_CDL 0xDB0 // sound data input volume (left) +#define SPU_P_CDR 0xDB2 // sound data input volume (right) +#define SPU_P_EXTL 0xDB4 // external input volume (left) +#define SPU_P_EXTR 0xDB6 // external input volume (right) + +#define SPU_P_REVERB 0xDC0 // effects control + + +// Individual voice parameter regs CORE 0 +// Only + + +#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) +#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) +#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch +#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) +#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) +#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) +#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) +#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) + +#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address +#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address +#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address + + +// CORE 0 Common Settings + + +#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on +#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on +#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) +#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) +#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) +#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) +#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) +#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) +#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address +#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) +#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) +#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address +#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register +#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register +#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status + +#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address + + +// Core 0 Reverb Addresses + + +#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) +#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) +#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) +#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) +#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) +#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) +#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) + +#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) +#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) +#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) +#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) +#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) +#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) +#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) + +#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) +#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) +#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) +#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) +#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) +#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) +#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) +#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) + +#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address + +#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status +#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register +#define P_ENDS(cr) (0x400 * cr + 0x346) // ? + + +// CORE 0 Specific + + +#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) +#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) +#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) +#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) +#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) +#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) +#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) +#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) +#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) +#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) + + +// More CORE 0 Reverb + + +#define IIR_ALPHA(cr) (0x28 * cr + 0x774) +#define ACC_COEF_A(cr) (0x28 * cr + 0x776) +#define ACC_COEF_B(cr) (0x28 * cr + 0x778) +#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) +#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) +#define IIR_COEF(cr) (0x28 * cr + 0x77E) +#define FB_ALPHA(cr) (0x28 * cr + 0x780) +#define FB_X(cr) (0x28 * cr + 0x782) +#define IN_COEF_L(cr) (0x28 * cr + 0x784) +#define IN_COEF_R(cr) (0x28 * cr + 0x786) + + +// CORE 1 only + +#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define SPDIF_MODE 0x7C6 +#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x7CA // SPDIF Copy Protection +*/ + +/* PS1 SPU CORE + +*** The below really isn't needed, only if you *** +*** want to add SPU support to the plugin *** +*** which I see no need to add at this time. *** +*** individual voice settings *** + +#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch +#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address +#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope +#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address + +// common settings + +#define SPU_P_MVOLL 0xD80 // master volume (left) +#define SPU_P_MVOLR 0xD82 // master volume (right) +#define SPU_P_RVOLL 0xD84 // effect return volume (left) +#define SPU_P_RVOLR 0xD86 // effect return volume (right) +#define SPU_S_KON1 0xD88 // key on +#define SPU_S_KON2 0xD8A // +#define SPU_S_KOFF1 0xD8C // key off +#define SPU_S_KOFF2 0xD8E // +#define SPU_S_PMON1 0xD90 // pitch modulation on +#define SPU_S_PMON2 0xD92 // +#define SPU_S_NON1 0xD94 // noise generator on +#define SPU_S_NON2 0xD96 // +#define SPU_S_RVBON1 0xD98 // effects on +#define SPU_S_RVBON2 0xD9A // +#define SPU_S_MUTE1 0xD9C // voice mute +#define SPU_S_MUTE2 0xD9E // + +#define SPU_A_ESA 0xDA2 // effects work area start +#define SPU_A_IRQA 0xDA4 // IRQ address +#define SPU_A_TSA 0xDA6 // DMA transfer start address +#define SPU_P_DATA 0xDA8 // DMA data register +#define SPU_P_CTRL 0xDAA // DMA control register +#define SPU_P_STAT 0xDAE // DMA status register + +#define SPU_P_CDL 0xDB0 // sound data input volume (left) +#define SPU_P_CDR 0xDB2 // sound data input volume (right) +#define SPU_P_EXTL 0xDB4 // external input volume (left) +#define SPU_P_EXTR 0xDB6 // external input volume (right) + +#define SPU_P_REVERB 0xDC0 // effects control +*/ + +/* +#define H_SPUReverbAddr 0x0da2 +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUmvolL 0x0d80 +#define H_SPUmvolR 0x0d82 +#define H_SPUrvolL 0x0d84 +#define H_SPUrvolR 0x0d86 +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e +#define H_FMod1 0x0d90 +#define H_FMod2 0x0d92 +#define H_Noise1 0x0d94 +#define H_Noise2 0x0d96 +#define H_RVBon1 0x0d98 +#define H_RVBon2 0x0d9a +#define H_SPUMute1 0x0d9c +#define H_SPUMute2 0x0d9e +#define H_CDLeft 0x0db0 +#define H_CDRight 0x0db2 +#define H_ExtLeft 0x0db4 +#define H_ExtRight 0x0db6 +#define H_Reverb 0x0dc0 +#define H_SPUPitch0 0x0c04 +#define H_SPUPitch1 0x0c14 +#define H_SPUPitch2 0x0c24 +#define H_SPUPitch3 0x0c34 +#define H_SPUPitch4 0x0c44 +#define H_SPUPitch5 0x0c54 +#define H_SPUPitch6 0x0c64 +#define H_SPUPitch7 0x0c74 +#define H_SPUPitch8 0x0c84 +#define H_SPUPitch9 0x0c94 +#define H_SPUPitch10 0x0ca4 +#define H_SPUPitch11 0x0cb4 +#define H_SPUPitch12 0x0cc4 +#define H_SPUPitch13 0x0cd4 +#define H_SPUPitch14 0x0ce4 +#define H_SPUPitch15 0x0cf4 +#define H_SPUPitch16 0x0d04 +#define H_SPUPitch17 0x0d14 +#define H_SPUPitch18 0x0d24 +#define H_SPUPitch19 0x0d34 +#define H_SPUPitch20 0x0d44 +#define H_SPUPitch21 0x0d54 +#define H_SPUPitch22 0x0d64 +#define H_SPUPitch23 0x0d74 + +#define H_SPUStartAdr0 0x0c06 +#define H_SPUStartAdr1 0x0c16 +#define H_SPUStartAdr2 0x0c26 +#define H_SPUStartAdr3 0x0c36 +#define H_SPUStartAdr4 0x0c46 +#define H_SPUStartAdr5 0x0c56 +#define H_SPUStartAdr6 0x0c66 +#define H_SPUStartAdr7 0x0c76 +#define H_SPUStartAdr8 0x0c86 +#define H_SPUStartAdr9 0x0c96 +#define H_SPUStartAdr10 0x0ca6 +#define H_SPUStartAdr11 0x0cb6 +#define H_SPUStartAdr12 0x0cc6 +#define H_SPUStartAdr13 0x0cd6 +#define H_SPUStartAdr14 0x0ce6 +#define H_SPUStartAdr15 0x0cf6 +#define H_SPUStartAdr16 0x0d06 +#define H_SPUStartAdr17 0x0d16 +#define H_SPUStartAdr18 0x0d26 +#define H_SPUStartAdr19 0x0d36 +#define H_SPUStartAdr20 0x0d46 +#define H_SPUStartAdr21 0x0d56 +#define H_SPUStartAdr22 0x0d66 +#define H_SPUStartAdr23 0x0d76 + +#define H_SPULoopAdr0 0x0c0e +#define H_SPULoopAdr1 0x0c1e +#define H_SPULoopAdr2 0x0c2e +#define H_SPULoopAdr3 0x0c3e +#define H_SPULoopAdr4 0x0c4e +#define H_SPULoopAdr5 0x0c5e +#define H_SPULoopAdr6 0x0c6e +#define H_SPULoopAdr7 0x0c7e +#define H_SPULoopAdr8 0x0c8e +#define H_SPULoopAdr9 0x0c9e +#define H_SPULoopAdr10 0x0cae +#define H_SPULoopAdr11 0x0cbe +#define H_SPULoopAdr12 0x0cce +#define H_SPULoopAdr13 0x0cde +#define H_SPULoopAdr14 0x0cee +#define H_SPULoopAdr15 0x0cfe +#define H_SPULoopAdr16 0x0d0e +#define H_SPULoopAdr17 0x0d1e +#define H_SPULoopAdr18 0x0d2e +#define H_SPULoopAdr19 0x0d3e +#define H_SPULoopAdr20 0x0d4e +#define H_SPULoopAdr21 0x0d5e +#define H_SPULoopAdr22 0x0d6e +#define H_SPULoopAdr23 0x0d7e + +#define H_SPU_ADSRLevel0 0x0c08 +#define H_SPU_ADSRLevel1 0x0c18 +#define H_SPU_ADSRLevel2 0x0c28 +#define H_SPU_ADSRLevel3 0x0c38 +#define H_SPU_ADSRLevel4 0x0c48 +#define H_SPU_ADSRLevel5 0x0c58 +#define H_SPU_ADSRLevel6 0x0c68 +#define H_SPU_ADSRLevel7 0x0c78 +#define H_SPU_ADSRLevel8 0x0c88 +#define H_SPU_ADSRLevel9 0x0c98 +#define H_SPU_ADSRLevel10 0x0ca8 +#define H_SPU_ADSRLevel11 0x0cb8 +#define H_SPU_ADSRLevel12 0x0cc8 +#define H_SPU_ADSRLevel13 0x0cd8 +#define H_SPU_ADSRLevel14 0x0ce8 +#define H_SPU_ADSRLevel15 0x0cf8 +#define H_SPU_ADSRLevel16 0x0d08 +#define H_SPU_ADSRLevel17 0x0d18 +#define H_SPU_ADSRLevel18 0x0d28 +#define H_SPU_ADSRLevel19 0x0d38 +#define H_SPU_ADSRLevel20 0x0d48 +#define H_SPU_ADSRLevel21 0x0d58 +#define H_SPU_ADSRLevel22 0x0d68 +#define H_SPU_ADSRLevel23 0x0d78 +*/ diff --git a/plugins/spu2/PeopsSPU2/regs.h b/plugins/spu2/PeopsSPU2/regs.h new file mode 100644 index 0000000000..2cacafe1aa --- /dev/null +++ b/plugins/spu2/PeopsSPU2/regs.h @@ -0,0 +1,43 @@ +/*************************************************************************** + regs.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SoundOn(int start,int end,unsigned short val); +void SoundOff(int start,int end,unsigned short val); +void VolumeOn(int start,int end,unsigned short val,int iRight); +void FModOn(int start,int end,unsigned short val); +void NoiseOn(int start,int end,unsigned short val); +void SetVolumeL(unsigned char ch,short vol); +void SetVolumeR(unsigned char ch,short vol); +void SetPitch(int ch,unsigned short val); +void ReverbOn(int start,int end,unsigned short val,int iRight); +void SetReverbAddr(int core); + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); + diff --git a/plugins/spu2/PeopsSPU2/res/spu2PeopsSound.rc2 b/plugins/spu2/PeopsSPU2/res/spu2PeopsSound.rc2 new file mode 100644 index 0000000000..7bfe5d1234 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/res/spu2PeopsSound.rc2 @@ -0,0 +1,13 @@ +// +// SPU2PEOPSSOUND.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/spu2/PeopsSPU2/resource.h b/plugins/spu2/PeopsSPU2/resource.h new file mode 100644 index 0000000000..5d94c180ea --- /dev/null +++ b/plugins/spu2/PeopsSPU2/resource.h @@ -0,0 +1,161 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by spu2PeopsSound.rc +// +#define IDC_SETS1 3 +#define IDC_SETS2 4 +#define IDOK2 5 +#define IDD_DIALOG1 130 +#define IDD_ABOUT 130 +#define IDD_CFGDLG 131 +#define IDD_DEBUG 135 +#define IDB_BITMAP1 136 +#define IDB_BITMAP2 137 +#define IDB_BITMAP3 138 +#define IDB_BITMAP4 139 +#define IDB_BITMAP5 140 +#define IDD_RECORD 141 +#define IDC_XAVOLUME 1004 +#define IDC_ENABXA 1005 +#define IDC_XAPITCH 1006 +#define IDC_XABLOCK 1007 +#define IDC_USETIMER 1007 +#define IDC_TIMER 1007 +#define IDC_CMIXRATE 1008 +#define IDC_USEIRQ 1008 +#define IDC_USEREVERB 1008 +#define IDC_CMODE 1009 +#define IDC_VOLUME 1009 +#define IDC_CFILTER 1010 +#define IDC_IRQWAIT 1010 +#define IDC_CQUALITY 1011 +#define IDC_DEBUGMODE 1011 +#define IDC_CDSOUND 1012 +#define IDC_INTERPOL 1012 +#define IDC_PLAYALWAYS 1013 +#define IDC_RECORDMODE 1013 +#define IDC_IGNOREPITCH 1014 +#define IDC_DISSTEREO 1014 +#define IDC_AMPLIF 1015 +#define IDC_VENVELOPE 1016 +#define IDC_VOL1 1016 +#define IDC_REVERB 1017 +#define IDC_VOL2 1017 +#define IDC_VOL3 1018 +#define IDC_VOL4 1019 +#define IDC_SAREA 1022 +#define IDC_ADSR 1023 +#define IDC_MUTE1 1047 +#define IDC_MUTE2 1048 +#define IDC_MUTE3 1049 +#define IDC_MUTE4 1050 +#define IDC_MUTE5 1051 +#define IDC_MUTE6 1052 +#define IDC_MUTE7 1053 +#define IDC_MUTE8 1054 +#define IDC_MUTE9 1055 +#define IDC_MUTE10 1056 +#define IDC_MUTE11 1057 +#define IDC_MUTE12 1058 +#define IDC_MUTE13 1059 +#define IDC_MUTE14 1060 +#define IDC_MUTE15 1061 +#define IDC_MUTE16 1062 +#define IDC_MUTE17 1063 +#define IDC_MUTE18 1064 +#define IDC_MUTE19 1065 +#define IDC_MUTE20 1066 +#define IDC_MUTE21 1067 +#define IDC_MUTE22 1068 +#define IDC_MUTE23 1069 +#define IDC_MUTE24 1070 +#define IDC_CHAN1 1071 +#define IDC_CHAN2 1072 +#define IDC_CHAN3 1073 +#define IDC_CHAN4 1074 +#define IDC_CHAN5 1075 +#define IDC_CHAN6 1076 +#define IDC_CHAN7 1077 +#define IDC_CHAN8 1078 +#define IDC_CHAN9 1079 +#define IDC_CHAN10 1080 +#define IDC_CHAN11 1081 +#define IDC_CHAN12 1082 +#define IDC_CHAN13 1083 +#define IDC_CHAN14 1084 +#define IDC_CHAN15 1085 +#define IDC_CHAN16 1086 +#define IDC_CHAN17 1087 +#define IDC_CHAN18 1088 +#define IDC_CHAN19 1089 +#define IDC_CHAN20 1090 +#define IDC_CHAN21 1091 +#define IDC_CHAN22 1092 +#define IDC_CHAN23 1093 +#define IDC_CHAN24 1094 +#define IDC_SADSR1 1096 +#define IDC_SADSR2 1097 +#define IDC_SADSR3 1098 +#define IDC_SADSR4 1099 +#define IDC_SADSR5 1100 +#define IDC_SADSR6 1101 +#define IDC_CHANNUM 1102 +#define IDC_MUTEOFF 1103 +#define IDC_MUTEON 1104 +#define IDC_SADSR7 1105 +#define IDC_CI1 1106 +#define IDC_CI2 1107 +#define IDC_CI3 1108 +#define IDC_CI4 1109 +#define IDC_CI5 1110 +#define IDC_CI6 1111 +#define IDC_CI7 1112 +#define IDC_CI8 1113 +#define IDC_CI9 1114 +#define IDC_CI10 1115 +#define IDC_CI11 1116 +#define IDC_CI12 1117 +#define IDC_CI13 1118 +#define IDC_CI14 1119 +#define IDC_CI15 1120 +#define IDC_CI16 1121 +#define IDC_STA1 1122 +#define IDC_SADSR8 1123 +#define IDC_STA2 1124 +#define IDC_STA3 1125 +#define IDC_STA4 1126 +#define IDC_XA1 1127 +#define IDC_XA2 1128 +#define IDC_XA3 1129 +#define IDC_XA4 1130 +#define IDC_CI17 1131 +#define IDC_CI18 1132 +#define IDC_XA 1133 +#define IDC_WAVFILE 1134 +#define IDC_CI19 1134 +#define IDC_XA5 1135 +#define IDC_RECORD 1135 +#define IDC_XA6 1136 +#define IDC_CORE1 1137 +#define IDC_CORE2 1138 +#define IDC_REGWRITE 1139 +#define IDC_REGREAD 1140 +#define IDC_CLEAR 1141 +#define IDC_LOG 1142 +#define IDC_NOLOG 1143 +#define IDC_REGEDIT 1144 +#define IDC_VALEDIT 1145 +#define IDC_COPY 1146 +#define IDC_ASYNC 1147 +#define IDC_SPU2IRQ 1148 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1149 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/spu2/PeopsSPU2/reverb.c b/plugins/spu2/PeopsSPU2/reverb.c new file mode 100644 index 0000000000..c8a23ff769 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/reverb.c @@ -0,0 +1,420 @@ +/*************************************************************************** + reverb.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed to SPU2 functionality +// +// 2003/01/19 - Pete +// - added Neill's reverb (see at the end of file) +// +// 2002/12/26 - Pete +// - adjusted reverb handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_REVERB + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// REVERB info and timing vars... + +int * sRVBPlay[2]; +int * sRVBEnd[2]; +int * sRVBStart[2]; + +//////////////////////////////////////////////////////////////////////// +// START REVERB +//////////////////////////////////////////////////////////////////////// + +INLINE void StartREVERB(int ch) +{ + int core=ch/24; + + if((s_chan[ch].bReverbL || s_chan[ch].bReverbR) && (spuCtrl2[core]&0x80)) // reverb possible? + { + if(iUseReverb==1) s_chan[ch].bRVBActive=1; + } + else s_chan[ch].bRVBActive=0; // else -> no reverb +} + +//////////////////////////////////////////////////////////////////////// +// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf +//////////////////////////////////////////////////////////////////////// + +INLINE void InitREVERB(void) +{ + if(iUseReverb==1) + { + memset(sRVBStart[0],0,NSSIZE*2*4); + memset(sRVBStart[1],0,NSSIZE*2*4); + } +} + +//////////////////////////////////////////////////////////////////////// +// STORE REVERB +//////////////////////////////////////////////////////////////////////// + +INLINE void StoreREVERB(int ch,int ns) +{ + int core=ch/24; + + if(iUseReverb==0) return; + else + if(iUseReverb==1) // -------------------------------- // Neil's reverb + { + const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume*s_chan[ch].bReverbL)/0x4000; + const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume*s_chan[ch].bReverbR)/0x4000; + + ns<<=1; + + *(sRVBStart[core]+ns) +=iRxl; // -> we mix all active reverb channels into an extra buffer + *(sRVBStart[core]+ns+1)+=iRxr; + } +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int g_buffer(int iOff,int core) // get_buffer content helper: takes care about wraps +{ + short * p=(short *)spuMem; + iOff=(iOff)+rvb[core].CurrAddr; + while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOffrvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOff33768L) iVal=33768L; + *(p+iOff)=(short)iVal; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE void s_buffer1(int iOff,int iVal,int core) // set_buffer (+1 sample) content helper: takes care about wraps and clipping +{ + short * p=(short *)spuMem; + iOff=(iOff)+rvb[core].CurrAddr+1; + while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOff33768L) iVal=33768L; + *(p+iOff)=(short)iVal; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixREVERBLeft(int ns,int core) +{ + if(iUseReverb==1) + { + if(!rvb[core].StartAddr || !rvb[core].EndAddr || + rvb[core].StartAddr>=rvb[core].EndAddr) // reverb is off + { + rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; + return 0; + } + + rvb[core].iCnt++; + + if(rvb[core].iCnt&1) // we work on every second left value: downsample to 22 khz + { + if((spuCtrl2[core]&0x80)) // -> reverb on? oki + { + int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1; + + const int INPUT_SAMPLE_L=*(sRVBStart[core]+(ns<<1)); + const int INPUT_SAMPLE_R=*(sRVBStart[core]+(ns<<1)+1); + + const int IIR_INPUT_A0 = (g_buffer(rvb[core].IIR_SRC_A0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; + const int IIR_INPUT_A1 = (g_buffer(rvb[core].IIR_SRC_A1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; + const int IIR_INPUT_B0 = (g_buffer(rvb[core].IIR_SRC_B0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; + const int IIR_INPUT_B1 = (g_buffer(rvb[core].IIR_SRC_B1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; + + const int IIR_A0 = (IIR_INPUT_A0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_A1 = (IIR_INPUT_A1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_B0 = (IIR_INPUT_B0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_B1 = (IIR_INPUT_B1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + + s_buffer1(rvb[core].IIR_DEST_A0, IIR_A0,core); + s_buffer1(rvb[core].IIR_DEST_A1, IIR_A1,core); + s_buffer1(rvb[core].IIR_DEST_B0, IIR_B0,core); + s_buffer1(rvb[core].IIR_DEST_B1, IIR_B1,core); + + ACC0 = (g_buffer(rvb[core].ACC_SRC_A0,core) * rvb[core].ACC_COEF_A)/33768L + + (g_buffer(rvb[core].ACC_SRC_B0,core) * rvb[core].ACC_COEF_B)/33768L + + (g_buffer(rvb[core].ACC_SRC_C0,core) * rvb[core].ACC_COEF_C)/33768L + + (g_buffer(rvb[core].ACC_SRC_D0,core) * rvb[core].ACC_COEF_D)/33768L; + ACC1 = (g_buffer(rvb[core].ACC_SRC_A1,core) * rvb[core].ACC_COEF_A)/33768L + + (g_buffer(rvb[core].ACC_SRC_B1,core) * rvb[core].ACC_COEF_B)/33768L + + (g_buffer(rvb[core].ACC_SRC_C1,core) * rvb[core].ACC_COEF_C)/33768L + + (g_buffer(rvb[core].ACC_SRC_D1,core) * rvb[core].ACC_COEF_D)/33768L; + + FB_A0 = g_buffer(rvb[core].MIX_DEST_A0 - rvb[core].FB_SRC_A,core); + FB_A1 = g_buffer(rvb[core].MIX_DEST_A1 - rvb[core].FB_SRC_A,core); + FB_B0 = g_buffer(rvb[core].MIX_DEST_B0 - rvb[core].FB_SRC_B,core); + FB_B1 = g_buffer(rvb[core].MIX_DEST_B1 - rvb[core].FB_SRC_B,core); + + s_buffer(rvb[core].MIX_DEST_A0, ACC0 - (FB_A0 * rvb[core].FB_ALPHA)/33768L,core); + s_buffer(rvb[core].MIX_DEST_A1, ACC1 - (FB_A1 * rvb[core].FB_ALPHA)/33768L,core); + + s_buffer(rvb[core].MIX_DEST_B0, (rvb[core].FB_ALPHA * ACC0)/33768L - (FB_A0 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B0 * rvb[core].FB_X)/33768L,core); + s_buffer(rvb[core].MIX_DEST_B1, (rvb[core].FB_ALPHA * ACC1)/33768L - (FB_A1 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B1 * rvb[core].FB_X)/33768L,core); + + rvb[core].iLastRVBLeft = rvb[core].iRVBLeft; + rvb[core].iLastRVBRight = rvb[core].iRVBRight; + + rvb[core].iRVBLeft = (g_buffer(rvb[core].MIX_DEST_A0,core)+g_buffer(rvb[core].MIX_DEST_B0,core))/3; + rvb[core].iRVBRight = (g_buffer(rvb[core].MIX_DEST_A1,core)+g_buffer(rvb[core].MIX_DEST_B1,core))/3; + + rvb[core].iRVBLeft = (rvb[core].iRVBLeft * rvb[core].VolLeft) / 0x4000; + rvb[core].iRVBRight = (rvb[core].iRVBRight * rvb[core].VolRight) / 0x4000; + + rvb[core].CurrAddr++; + if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; + + return rvb[core].iLastRVBLeft+(rvb[core].iRVBLeft-rvb[core].iLastRVBLeft)/2; + } + else // -> reverb off + { + rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; + } + + rvb[core].CurrAddr++; + if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; + } + + return rvb[core].iLastRVBLeft; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixREVERBRight(int core) +{ + if(iUseReverb==1) // Neill's reverb: + { + int i=rvb[core].iLastRVBRight+(rvb[core].iRVBRight-rvb[core].iLastRVBRight)/2; + rvb[core].iLastRVBRight=rvb[core].iRVBRight; + return i; // -> just return the last right reverb val (little bit scaled by the previous right val) + } + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +#endif + +/* +----------------------------------------------------------------------------- +PSX reverb hardware notes +by Neill Corlett +----------------------------------------------------------------------------- + +Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway +yadda yadda. + +----------------------------------------------------------------------------- + +Basics +------ + +- The reverb buffer is 22khz 16-bit mono PCM. +- It starts at the reverb address given by 1DA2, extends to + the end of sound RAM, and wraps back to the 1DA2 address. + +Setting the address at 1DA2 resets the current reverb work address. + +This work address ALWAYS increments every 1/22050 sec., regardless of +whether reverb is enabled (bit 7 of 1DAA set). + +And the contents of the reverb buffer ALWAYS play, scaled by the +"reverberation depth left/right" volumes (1D84/1D86). +(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) + +----------------------------------------------------------------------------- + +Register names +-------------- + +These are probably not their real names. +These are probably not even correct names. +We will use them anyway, because we can. + +1DC0: FB_SRC_A (offset) +1DC2: FB_SRC_B (offset) +1DC4: IIR_ALPHA (coef.) +1DC6: ACC_COEF_A (coef.) +1DC8: ACC_COEF_B (coef.) +1DCA: ACC_COEF_C (coef.) +1DCC: ACC_COEF_D (coef.) +1DCE: IIR_COEF (coef.) +1DD0: FB_ALPHA (coef.) +1DD2: FB_X (coef.) +1DD4: IIR_DEST_A0 (offset) +1DD6: IIR_DEST_A1 (offset) +1DD8: ACC_SRC_A0 (offset) +1DDA: ACC_SRC_A1 (offset) +1DDC: ACC_SRC_B0 (offset) +1DDE: ACC_SRC_B1 (offset) +1DE0: IIR_SRC_A0 (offset) +1DE2: IIR_SRC_A1 (offset) +1DE4: IIR_DEST_B0 (offset) +1DE6: IIR_DEST_B1 (offset) +1DE8: ACC_SRC_C0 (offset) +1DEA: ACC_SRC_C1 (offset) +1DEC: ACC_SRC_D0 (offset) +1DEE: ACC_SRC_D1 (offset) +1DF0: IIR_SRC_B1 (offset) +1DF2: IIR_SRC_B0 (offset) +1DF4: MIX_DEST_A0 (offset) +1DF6: MIX_DEST_A1 (offset) +1DF8: MIX_DEST_B0 (offset) +1DFA: MIX_DEST_B1 (offset) +1DFC: IN_COEF_L (coef.) +1DFE: IN_COEF_R (coef.) + +The coefficients are signed fractional values. +-32768 would be -1.0 + 32768 would be 1.0 (if it were possible... the highest is of course 32767) + +The offsets are (byte/8) offsets into the reverb buffer. +i.e. you multiply them by 8, you get byte offsets. +You can also think of them as (samples/4) offsets. +They appear to be signed. They can be negative. +None of the documented presets make them negative, though. + +Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. + +----------------------------------------------------------------------------- + +What it does +------------ + +We take all reverb sources: +- regular channels that have the reverb bit on +- cd and external sources, if their reverb bits are on +and mix them into one stereo 44100hz signal. + +Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting +algorithm here, but I haven't figured out the hysterically exact specifics. +I use an 8-tap filter with these coefficients, which are nice but probably +not the real ones: + +0.037828187894 +0.157538631280 +0.321159685278 +0.449322115345 +0.449322115345 +0.321159685278 +0.157538631280 +0.037828187894 + +So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. + +* IN MY EMULATION, I divide these by 2 to make it clip less. + (and of course the L/R output coefficients are adjusted to compensate) + The real thing appears to not do this. + +At every 22050hz tick: +- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb + steady-state algorithm described below +- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer + (This part may not be exactly right and I guessed at the coefs. TODO: check later.) + L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) + R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) +- Advance the current buffer position by 1 sample + +The wet out L and R are then upsampled to 44100hz and played at the +"reverberation depth left/right" (1D84/1D86) volume, independent of the main +volume. + +----------------------------------------------------------------------------- + +Reverb steady-state +------------------- + +The reverb steady-state algorithm is fairly clever, and of course by +"clever" I mean "batshit insane". + +buffer[x] is relative to the current buffer position, not the beginning of +the buffer. Note that all buffer offsets must wrap around so they're +contained within the reverb work area. + +Clipping is performed at the end... maybe also sooner, but definitely at +the end. + +IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; +IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; + +IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); +IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); +IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); +IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); + +buffer[IIR_DEST_A0 + 1sample] = IIR_A0; +buffer[IIR_DEST_A1 + 1sample] = IIR_A1; +buffer[IIR_DEST_B0 + 1sample] = IIR_B0; +buffer[IIR_DEST_B1 + 1sample] = IIR_B1; + +ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + + buffer[ACC_SRC_B0] * ACC_COEF_B + + buffer[ACC_SRC_C0] * ACC_COEF_C + + buffer[ACC_SRC_D0] * ACC_COEF_D; +ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + + buffer[ACC_SRC_B1] * ACC_COEF_B + + buffer[ACC_SRC_C1] * ACC_COEF_C + + buffer[ACC_SRC_D1] * ACC_COEF_D; + +FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; +FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; +FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; +FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; + +buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; +buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; +buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; +buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; + +----------------------------------------------------------------------------- +*/ + diff --git a/plugins/spu2/PeopsSPU2/reverb.h b/plugins/spu2/PeopsSPU2/reverb.h new file mode 100644 index 0000000000..5305030c1f --- /dev/null +++ b/plugins/spu2/PeopsSPU2/reverb.h @@ -0,0 +1,33 @@ +/*************************************************************************** + reverb.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +INLINE void StartREVERB(int ch); +INLINE void StoreREVERB(int ch,int ns); + diff --git a/plugins/spu2/PeopsSPU2/spu.c b/plugins/spu2/PeopsSPU2/spu.c new file mode 100644 index 0000000000..3e1ef1637e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu.c @@ -0,0 +1,1311 @@ +/*************************************************************************** + spu.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2004/12/25 - Pete +// - inc'd version for pcsx2-0.7 +// +// 2004/04/18 - Pete +// - changed all kind of things in the plugin +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/04/07 - Eric +// - adjusted cubic interpolation algorithm +// +// 2003/03/16 - Eric +// - added cubic interpolation +// +// 2003/03/01 - linuzappz +// - libraryName changes using ALSA +// +// 2003/02/28 - Pete +// - added option for type of interpolation +// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile) +// - added MONO support for MSWindows DirectSound +// +// 2003/02/20 - kode54 +// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault +// +// 2003/02/19 - kode54 +// - moved SPU IRQ handler and changed sample flag processing +// +// 2003/02/18 - kode54 +// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that +// ADSR timing is relative to the frequency at which a sample is played... I guess +// this remains to be seen, and I don't know whether ADSR is applied to noise channels... +// +// 2003/02/09 - kode54 +// - one-shot samples now process the end block before stopping +// - in light of removing fmod hack, now processing ADSR on frequency channel as well +// +// 2003/02/08 - kode54 +// - replaced easy interpolation with gaussian +// - removed fmod averaging hack +// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :) +// +// 2003/02/08 - linuzappz +// - small bugfix for one usleep that was 1 instead of 1000 +// - added iDisStereo for no stereo (Linux) +// +// 2003/01/22 - Pete +// - added easy interpolation & small noise adjustments +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/12 - Pete +// - added recording window handlers +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/12/28 - Pete +// - adjusted spu irq handling, fmod handling and loop handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/06/08 - linuzappz +// - SPUupdate changed for SPUasync +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_SPU + +#include "externals.h" +#include "cfg.h" +#include "dsoundoss.h" +#include "regs.h" +#include "debug.h" +#include "record.h" +#include "resource.h" +#include "dma.h" +#include "registers.h" + +#if !defined(_WIN32) + +#include + +#if !defined(CALLBACK) +#define CALLBACK +#endif + +#define Sleep(x) sleep((x)*1000) +#endif + +//////////////////////////////////////////////////////////////////////// +// spu version infos/name +//////////////////////////////////////////////////////////////////////// + +const unsigned char version = 5; +const unsigned char revision = 1; +const unsigned char build = 9; +#ifdef _DEBUG +static char * libraryName = "P.E.Op.S. SPU2 (Debug) "; +#else +static char * libraryName = "P.E.Op.S. SPU2 "; +#endif +static char * libraryInfo = "P.E.Op.S. SPU2 Driver V1.6\nCoded by Pete Bernert, Saqib and the P.E.Op.S. team\n"; + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// psx buffer / addresses + +unsigned short regArea[32*1024]; + short spuMem[2*1024*1024]; + char * spuMemC; +unsigned char * pSpuIrq[2]; +unsigned char * pSpuBuffer; +unsigned char * pSpuStreamBuffer[2]; + +// user settings + +int iVolume=3; +int iDebugMode=0; +int iRecordMode=0; +int iUseReverb=0; +int iUseInterpolation=2; + +// MAIN infos struct for each channel +int iDisStereo; + +SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) +REVERBInfo rvb[2]; + +unsigned long dwNoiseVal=1; // global noise generator +unsigned short spuCtrl2[2]; // some vars to store psx reg infos +unsigned short spuStat2[2]; +unsigned long spuIrq2[2]; +unsigned long spuAddr2[2]; // address into spu mem +unsigned long spuRvbAddr2[2]; +unsigned long spuRvbAEnd2[2]; +int bEndThread=0; // thread handlers +int bSpuInit=0; +int bSPUIsOpen=0; +int bThreadEnded=0; +int iUseTimer=2; +int aSyncMode=0; +unsigned long aSyncCounter=0; +unsigned long aSyncWait=0; +DWORD aSyncTimerNew; +DWORD aSyncTimerOld; + +#ifdef _WIN32 +HWND hWMain=0; // window handle +HWND hWDebug=0; +HWND hWRecord=0; + +static HANDLE hMainThread; +#else +#include +static pthread_t hMainThread; +#endif + +unsigned long dwNewChannel2[2]; // flags for faster testing, if new channel starts +unsigned long dwEndChannel2[2]; + +void (CALLBACK *irqCallbackDMA4)()=0; // func of main emu, called on spu irq +void (CALLBACK *irqCallbackDMA7)()=0; // func of main emu, called on spu irq +void (CALLBACK *irqCallbackSPU2)()=0; // func of main emu, called on spu irq + +// certain globals (were local before, but with the new timeproc I need em global) + +const int f[5][2] = { { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; +int SSumR[NSSIZE]; +int SSumL[NSSIZE]; + +extern ADMA Adma4; +extern ADMA Adma7; +DINPUT DirectInputC0, DirectInputC1; + +extern unsigned short interrupt; +unsigned long SPUCycles; +extern unsigned long SPUStartCycle[2]; +extern unsigned long SPUTargetCycle[2]; + +int iCycle=0; +short * pS; +short * pS1; + +static int lastch=-1; // last channel processed on spu irq in timer mode +static int lastns=0; // last ns pos +static int iSecureStart=0; // secure start counter + +//////////////////////////////////////////////////////////////////////// +// CODE AREA +//////////////////////////////////////////////////////////////////////// + +// dirty inline func includes + +#include "reverb.c" +#include "adsr.c" + +//////////////////////////////////////////////////////////////////////// +// helpers for simple interpolation + +// +// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm +// +// instead of having n equal sample values in a row like: +// ____ +// |____ +// +// we compare the current delta change with the next delta change. +// +// if curr_delta is positive, +// +// - and next delta is smaller (or changing direction): +// \. +// -__ +// +// - and next delta significant (at least twice) bigger: +// --_ +// \. +// +// - and next delta is nearly same: +// \. +// \. +// +// +// if curr_delta is negative, +// +// - and next delta is smaller (or changing direction): +// _-- +// / +// +// - and next delta significant (at least twice) bigger: +// / +// __- +// +// - and next delta is nearly same: +// / +// / +// + + +INLINE void InterpolateUp(int ch) +{ + if(s_chan[ch].SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass + { + const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29]; // curr delta to next val + const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30]; // and next delta to next-next val :) + + s_chan[ch].SB[32]=0; + + if(id1>0) // curr delta positive + { + if(id2id1) + {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;} + else + if(id2>(id1<<1)) + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L; + else + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; + } + } + else + if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass + { + s_chan[ch].SB[32]=0; + + s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L; + if(s_chan[ch].sinc<=0x8000) + s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); + else s_chan[ch].SB[29]+=s_chan[ch].SB[28]; + } + else // no flags? add bigger val (if possible), calc smaller step, set flag1 + s_chan[ch].SB[29]+=s_chan[ch].SB[28]; +} + +// +// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm +// + +INLINE void InterpolateDown(int ch) +{ + if(s_chan[ch].sinc>=0x20000) // we would skip at least one val? + { + s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight + if(s_chan[ch].sinc>=0x30000) // we would skip even more vals? + s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight + } +} + +//////////////////////////////////////////////////////////////////////// +// helpers for gauss interpolation + +#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos]) +#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) + +#include "gauss_i.h" + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// START SOUND... called by main thread to setup a new sound on a channel +//////////////////////////////////////////////////////////////////////// + +INLINE void StartSound(int ch) +{ + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear new channel bit + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + + StartADSR(ch); + StartREVERB(ch); + + s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start + + s_chan[ch].s_1=0; // init mixing vars + s_chan[ch].s_2=0; + s_chan[ch].iSBPos=28; + + s_chan[ch].bNew=0; // init channel flags + s_chan[ch].bStop=0; + s_chan[ch].bOn=1; + + s_chan[ch].SB[29]=0; // init our interpolation helpers + s_chan[ch].SB[30]=0; + + if(iUseInterpolation>=2) // gauss interpolation? + {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding + else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding +} + + +void UpdateMainVolL() // LEFT VOLUME +{ + short vol = regArea[PS2_C0_MVOLL]; + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + //vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + regArea[PS2_C0_MVOLL]=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// RIGHT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +void UpdateMainVolR() // RIGHT VOLUME +{ + short vol = regArea[PS2_C0_MVOLR]; + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) //vol=vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + + regArea[PS2_C0_MVOLR]=vol; +} +//////////////////////////////////////////////////////////////////////// +// MAIN SPU FUNCTION +// here is the main job handler... thread, timer or direct func call +// basically the whole sound processing is done in this fat func! +//////////////////////////////////////////////////////////////////////// + +// 5 ms waiting phase, if buffer is full and no new sound has to get started +// .. can be made smaller (smallest val: 1 ms), but bigger waits give +// better performance + +#define PAUSE_W 5 +#define PAUSE_L 5000 +extern unsigned long MemAddr[2]; +//////////////////////////////////////////////////////////////////////// + +int iSpuAsyncWait=0; +extern int MMIXC0, MMIXC1; +extern int ADMAS4Write(); +extern int ADMAS7Write(); + +extern void SoundFeedVoiceData(); + +void CALLBACK MainSPU2Proc(unsigned int nTimerId, unsigned int msg, unsigned int dwUser, + unsigned int dwParam1, unsigned int dwParam2) +{ + int s_1,s_2,fa,ns; + int core = 0; + unsigned char * start; + unsigned int nSample; + int d; + int ch,predict_nr,shift_factor,flags,s; + int gpos; + + while(!bEndThread) // until we are shutting down + { + //--------------------------------------------------// + // ok, at the beginning we are looking if there is + // enuff free place in the dsound/oss buffer to + // fill in new data, or if there is a new channel to start. + // if not, we wait (thread) or return (timer/spuasync) + // until enuff free place is available/a new channel gets + // started + if (aSyncMode==1) // Async supported? and enabled? + { + if (aSyncCounter<=737280) // If we have 10ms in the buffer, don't wait + { + if (aSyncWait<1000) Sleep(aSyncWait); // Wait a little to be more Synced (No more than 1 sec) + else Sleep (1000); + } + + while (aSyncCounter<=368640 && !bEndThread && aSyncMode==1) + Sleep (1); // bEndThread/aSyncMode are needed, to avoid close problems + + aSyncCounter -= 36864; // 1ms more done (48Hz*768cycles/Hz) + } + else + if(dwNewChannel2[0] || dwNewChannel2[1]) // new channel should start immedately? + { // (at least one bit 0 ... MAXCHANNEL is set?) + iSecureStart++; // -> set iSecure + if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance) + } + else iSecureStart=0; // 0: no new channel should start + + while(!iSecureStart && !bEndThread && // no new start? no thread end? + (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? + { + iSecureStart=0; // reset secure + + if(iUseTimer) // no-thread mode? + { + return; // -> and done this time (timer mode 1 or 2) + } + // win thread mode: + Sleep(PAUSE_W); // sleep for x ms (win) + + if(dwNewChannel2[0] || dwNewChannel2[1]) + iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop + } + //--------------------------------------------------// continue from irq handling in timer mode? + + if(lastch>=0) // will be -1 if no continue is pending + { + ch=lastch; ns=lastns; lastch=-1; // -> setup all kind of vars to continue + if( s_chan[ch].iSBPos < 28 ) { + goto GOON; // -> directly jump to the continue point + } + } + + //--------------------------------------------------// + //- main channel loop -// + //--------------------------------------------------// + { + for(ch=0;ch take it and calc steps + s_chan[ch].sinc = s_chan[ch].iRawPitch<<4; + if(!s_chan[ch].sinc) s_chan[ch].sinc=1; + if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag + } + + ns=0; + while(ns=0x10000L) + { + if(s_chan[ch].iSBPos==28) // 28 reached? + { + start=s_chan[ch].pCurr; // set up the current pos + + if (s_chan[ch].bOn==0) goto ENDX; // special "stop" sign + + s_chan[ch].iSBPos=0; + + s_1=s_chan[ch].s_1; + s_2=s_chan[ch].s_2; + + predict_nr = (int)*start; + start++; + flags = (int)*start; + start++; + + shift_factor = predict_nr&0xf; + predict_nr >>= 4; + // -------------------------------------- // + + for (nSample=0;nSample<28;nSample+=2,start++) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + s=((d & 0xf0) << 8); + + s_chan[ch].SB[nSample]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + + s_chan[ch].SB[nSample+1]=fa; + } + + //////////////////////////////////////////// irq check + + if(spuCtrl2[core]&0x40) // some irq active? + { + if(iDebugMode==1) logprintf("IRQ Active ch %x, C%x\r\n", ch, ch/24); + + if( pSpuIrq[core] >= start-16 && // irq address reached? + pSpuIrq[core] <= start) + { + s_chan[ch].iIrqDone=1; // -> debug flag + + if(iDebugMode==1) logprintf("Sample End ch %x, C%x\r\n", ch, ch/24); + + regArea[0x7C0] |= 0x4< let's see what is happening if we call our irqs instead ;) + + } + } + + //////////////////////////////////////////// flag handler + if(flags & 0x2) s_chan[ch].bIgnoreLoop=1; // LOOP bit + + if(flags&0x4) s_chan[ch].pLoop=start-16; // LOOP/START bit + + if(flags&0x1) // 1: LOOP/END bit + { + dwEndChannel2[core]|=(1<<(ch%24)); + + if((flags&0xF) != 0x3 || s_chan[ch].pLoop == NULL) // Check if no loop is present + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bStop = 1; + logprintf("Stopping\r\n"); + } + else start = s_chan[ch].pLoop; + } + + s_chan[ch].pCurr=start; // store values for next cycle + s_chan[ch].s_1=s_1; + s_chan[ch].s_2=s_2; + + + //////////////////////////////////////////// + +GOON: ; + } + + fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data + + if((spuCtrl2[core]&0x4000)==0) fa=0; // muted? + else // else adjust + { + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + } + + if(iUseInterpolation>=2) // gauss/cubic interpolation + { + gpos = s_chan[ch].SB[28]; + gval0 = fa; + gpos = (gpos+1) & 3; + s_chan[ch].SB[28] = gpos; + } + else + if(iUseInterpolation==1) // simple interpolation + { + s_chan[ch].SB[28] = 0; + s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' + s_chan[ch].SB[30] = s_chan[ch].SB[31]; + s_chan[ch].SB[31] = fa; + s_chan[ch].SB[32] = 1; // -> flag: calc new interolation + } + else s_chan[ch].SB[29]=fa; // no interpolation + + s_chan[ch].spos -= 0x10000L; + } + + //////////////////////////////////////////////// + // noise handler... just produces some noise data + // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... + // and sometimes the noise will be used as fmod modulation... pfff + + if(s_chan[ch].bNoise) + { + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[core]&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + s_chan[ch].iOldNoise=fa; + + if(iUseInterpolation<2) // no gauss/cubic interpolation? + s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot + } //---------------------------------------- + else // NO NOISE (NORMAL SAMPLE DATA) HERE + {//------------------------------------------// + if(iUseInterpolation==3) // cubic interpolation + { + long xd; + xd = ((s_chan[ch].spos) >> 1)+1; + gpos = s_chan[ch].SB[28]; + + fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; + fa *= (xd - (2<<15)) / 6; + fa >>= 15; + fa += gval(2) - gval(1) - gval(1) + gval0; + fa *= (xd - (1<<15)) >> 1; + fa >>= 15; + fa += gval(1) - gval0; + fa *= xd; + fa >>= 15; + fa = fa + gval0; + } + //------------------------------------------// + else + if(iUseInterpolation==2) // gauss interpolation + { + int vl, vr; + vl = (s_chan[ch].spos >> 6) & ~3; + gpos = s_chan[ch].SB[28]; + vr=(gauss[vl]*gval0)&~2047; + vr+=(gauss[vl+1]*gval(1))&~2047; + vr+=(gauss[vl+2]*gval(2))&~2047; + vr+=(gauss[vl+3]*gval(3))&~2047; + fa = vr>>11; + } + //------------------------------------------// + else + if(iUseInterpolation==1) // simple interpolation + { + if(s_chan[ch].sinc<0x10000L) // -> upsampling? + InterpolateUp(ch); // --> interpolate up + else InterpolateDown(ch); // --> else down + fa=s_chan[ch].SB[29]; + } + //------------------------------------------// + else fa=s_chan[ch].SB[29]; // no interpolation + } + + s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // add adsr + + if(s_chan[ch].bFMod==2) // fmod freq channel + { + int NP=((32768L+s_chan[ch].sval)*s_chan[ch+1].iRawPitch)>>14; + + if(NP>0x3fff) NP=0x3fff; + else if(NP<0x1) NP=0x1; + + NP=(48000L*NP)>>12; // calc frequency ( 48hz ) + + s_chan[ch+1].iActFreq=NP; + s_chan[ch+1].iUsedFreq=NP; + s_chan[ch+1].sinc=(((NP/10)<<16)/48000); // check , was 4800 + if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; + if(iUseInterpolation==1) // freq change in sipmle interpolation mode + s_chan[ch+1].SB[32]=1; + + } + else + { + ////////////////////////////////////////////// + // ok, left/right sound volume (ps2 volume goes from 0 ... 0x3fff) + + if(s_chan[ch].iMute) s_chan[ch].sval=0; // debug mute + else + { + if(s_chan[ch].bVolumeL) + SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; + + if(s_chan[ch].bVolumeR) + SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; + } + + ////////////////////////////////////////////// + // now let us store sound data for reverb + + if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns); + } + + //////////////////////////////////////////////// + // ok, go on until 1 ms data of this channel is collected + + ns++; + s_chan[ch].spos += s_chan[ch].sinc; + } +ENDX: ; + } + } + + //---------------------------------------------------// + //- here we have another 1 ms of sound data + //---------------------------------------------------// + /////////////////////////////////////////////////////// + // mix all channels (including reverb) into one buffer + for(ns=0;ns Adma4.Index)) + { + if(ADMAS4Write()) + { + //if( Adma4.AmountLeft == 0 ) + if(Adma4.IRQ == 0 && (spuCtrl2[0] & 0x30)){ + Adma4.IRQ = 1; + irqCallbackDMA4(); + } + } + } + if(Adma4.Index == 512) { + Adma4.Index = 0; + } + + + } + + if((regArea[PS2_C1_MMIX] & 0xF0) && regArea[PS2_C1_ADMAS] & 0x2 /*&& !(spuCtrl2[1] & 0x30)*/) + { + DirectInputC1.Left = ((short*)spuMem)[0x2400+Adma7.Index]; + DirectInputC1.Right = ((short*)spuMem)[0x2600+Adma7.Index]; + if(spuCtrl2[1]&0x40 && (spuIrq2[1] == (0x2400+Adma7.Index) || spuIrq2[1] == (0x2600+Adma7.Index))){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 0x8; + irqCallbackSPU2(); + } + Adma7.Index +=1; + + if((Adma7.ADMAPos - (Adma7.Index + 255)) <= 0 && (Adma7.ADMAPos > Adma7.Index)) + { + if(ADMAS7Write()) + { + //if( Adma4.AmountLeft == 0 ) + if(Adma7.IRQ == 0 && (spuCtrl2[1] & 0x30)){ + Adma7.IRQ = 1; + irqCallbackDMA7(); + } + } + } + if(Adma7.Index == 512) { + Adma7.Index = 0; + } + + } + + SSumL[ns]+=MixREVERBLeft(ns,0); + SSumL[ns]+=MixREVERBLeft(ns,1); + + if((regArea[PS2_C0_MMIX] & 0x80)) SSumL[ns] += (DirectInputC0.Left*(int)regArea[PS2_C0_BVOLL])>>16; + if((regArea[PS2_C1_MMIX] & 0x80)) SSumL[ns] += (DirectInputC1.Left*(int)regArea[PS2_C1_BVOLL])>>16; + + UpdateMainVolL(); + + if(iVolume == 5) d = 0; + else d=SSumL[ns]/iVolume; + SSumL[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + + SSumR[ns]+=MixREVERBRight(0); + SSumR[ns]+=MixREVERBRight(1); + + if((regArea[PS2_C0_MMIX] & 0x40)) SSumR[ns] += (DirectInputC0.Right*(int)regArea[PS2_C0_BVOLR])>>16; + if((regArea[PS2_C1_MMIX] & 0x40)) SSumR[ns] += (DirectInputC1.Right*(int)regArea[PS2_C1_BVOLR])>>16; + + UpdateMainVolR(); + if(iVolume == 5) d = 0; + else d=SSumR[ns]/iVolume; + SSumR[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + } + InitREVERB(); + + ////////////////////////////////////////////////////// + // feed the sound + // wanna have around 1/60 sec (16.666 ms) updates + + if(iCycle++>16) + { + SoundFeedVoiceData((unsigned char*)pSpuBuffer, + ((unsigned char *)pS)- + ((unsigned char *)pSpuBuffer)); + pS=(short *)pSpuBuffer; + iCycle=0; + } +} + // end of big main loop... + bThreadEnded=1; + return; +} + + +//////////////////////////////////////////////////////////////////////// +// SPU ASYNC... even newer epsxe func +// 1 time every 'cycle' cycles... harhar +//////////////////////////////////////////////////////////////////////// +EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle) +{ + SPUCycles += cycle; + if(interrupt & (1<<2)){ + if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if(interrupt & (1<<1)){ + if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + /*if(iSpuAsyncWait) + { + iSpuAsyncWait++; + if(iSpuAsyncWait<=64) return; + iSpuAsyncWait=0; + }*/ + + if(iDebugMode==2) + { +#ifdef _WIN32 + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0; +#endif + iDebugMode=0; + } + if(iRecordMode==2) + { +#ifdef _WIN32 + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0; +#endif + iRecordMode=0; + } + + if(iUseTimer==0) // does the emu support SPUAsync, is it in thread mode, and in Thread Sync ON? + { + aSyncMode=1; // Ten, activate main function Sync system flag + + aSyncTimerOld = aSyncTimerNew; // Recalculate, AsyncWait (ms) + aSyncTimerNew = timeGetTime(); + + aSyncWait =(unsigned int)((aSyncTimerNew - aSyncTimerOld)/2); + + aSyncCounter += cycle ; + + return; + } + if(iUseTimer==2) // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode) + { + //printf("spu2async: calling mainspu2proc\n"); + aSyncMode = 0; + if(!bSpuInit) return; // -> no init, no call + MainSPU2Proc(0,0,0,0,0); // -> experimental win mode... not really tested... don't like the drawbacks + } +} + + +//////////////////////////////////////////////////////////////////////// +// INIT/EXIT STUFF +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUINIT: this func will be called first by the main emu +//////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 +static HINSTANCE hIRE = NULL; +#endif + +EXPORT_GCC long CALLBACK SPU2init(void) +{ + spuMemC=(unsigned char *)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset(rvb,0,2*sizeof(REVERBInfo)); + + InitADSR(); + +#ifdef _WIN32 + if(hIRE==NULL) hIRE=LoadLibrary("Riched32.dll "); // needed for debug output +#endif + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SETUPTIMER: init of certain buffers and threads/timers +//////////////////////////////////////////////////////////////////////// +#ifdef _WIN32 +DWORD WINAPI MAINThreadEx(LPVOID lpParameter) +{ + MainSPU2Proc(0,0,0,0,0); + return 0; +} +#else +void* MAINThreadEx(void* param) +{ + MainSPU2Proc(0,0,0,0,0); + return NULL; +} +#endif + +void SetupTimer(void) +{ + memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers + memset(SSumL,0,NSSIZE*sizeof(int)); + pS=(short *)pSpuBuffer; // setup soundbuffer pointer + pS1=(short *)pSpuStreamBuffer[0]; // setup soundbuffer pointer + + bEndThread=0; // init thread vars + bSpuInit=1; // flag: we are inited + + bSpuInit=1; // flag: we are inited + +#ifdef _WIN32 + + if(iUseTimer==0) // windows: use thread + { + //_beginthread(MAINThread,0,NULL); + DWORD dw; + hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw); + SetThreadPriority(hMainThread, + //THREAD_PRIORITY_TIME_CRITICAL); + THREAD_PRIORITY_HIGHEST); + } +#else + if( pthread_create(&hMainThread, NULL, MAINThreadEx, NULL) != 0 ) { + printf("Failed to create spu2thread\n"); + return; + } +#endif +} + +//////////////////////////////////////////////////////////////////////// +// REMOVETIMER: kill threads/timers +//////////////////////////////////////////////////////////////////////// + +void RemoveTimer(void) +{ + bEndThread=1; // raise flag to end thread + + if(iUseTimer!=2) // windows thread? + { + while(!bThreadEnded) {Sleep(5L);} // -> wait till thread has ended + Sleep(5L); + } + + bSpuInit=0; + + bThreadEnded=0; // no more spu is running +} + +//////////////////////////////////////////////////////////////////////// +// SETUPSTREAMS: init most of the spu buffers +//////////////////////////////////////////////////////////////////////// + +void SetupStreams(void) +{ + int i; + + pSpuBuffer=(unsigned char *)malloc(38400); // alloc mixing buffer + i=NSSIZE*2; + + sRVBStart[0] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[0],0,i*4); + sRVBEnd[0] = sRVBStart[0] + i; + sRVBPlay[0] = sRVBStart[0]; + sRVBStart[1] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[1],0,i*4); + sRVBEnd[1] = sRVBStart[1] + i; + sRVBPlay[1] = sRVBStart[1]; + + for(i=0;i init sustain + s_chan[i].iMute=0; + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pStart=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pCurr=spuMemC+(s_chan[i].iStartAdr<<1); + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVESTREAMS: free most buffer +//////////////////////////////////////////////////////////////////////// + +void RemoveStreams(void) +{ + free(pSpuBuffer); // free mixing buffer + pSpuBuffer=NULL; + free(sRVBStart[0]); // free reverb buffer + sRVBStart[0]=0; + free(sRVBStart[1]); // free reverb buffer + sRVBStart[1]=0; +} + + +//////////////////////////////////////////////////////////////////////// +// SPUOPEN: called by main emu after init +//////////////////////////////////////////////////////////////////////// +#include +FILE * LogFile; +EXPORT_GCC long CALLBACK SPU2open(void* pWindow) +{ +#ifdef _WIN32 + HWND hW= pWindow == NULL ? NULL : *(HWND*)pWindow; +#else + Display* dsp = *(Display**)pWindow; +#endif + + if(bSPUIsOpen) return 0; // security for some stupid main emus + LogFile = fopen("logs/spu2.txt","wb"); + iVolume=3; + bEndThread=0; + bThreadEnded=0; + spuMemC=(unsigned char *)spuMem; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + pSpuIrq[0]=spuMemC; + pSpuIrq[1]=spuMemC; + dwNewChannel2[0]=0; + dwNewChannel2[1]=0; + dwEndChannel2[0]=0; + dwEndChannel2[1]=0; + spuCtrl2[0]=0; + spuCtrl2[1]=0; + spuStat2[0]=0; + spuStat2[1]=0; + spuIrq2[0]=0; + spuIrq2[1]=0; + spuAddr2[0]=0x0; + spuAddr2[1]=0x0; + spuRvbAddr2[0]=0; + spuRvbAddr2[1]=0; + spuRvbAEnd2[0]=0; + spuRvbAEnd2[1]=0; + + memset(&Adma4,0,sizeof(ADMA)); + memset(&Adma7,0,sizeof(ADMA)); + + memset(&DirectInputC0,0,sizeof(DINPUT)); + memset(&DirectInputC1,0,sizeof(DINPUT)); + + +#ifdef _WIN32 + LastWrite=0x00000000;LastPlay=0; // init some play vars + + if(!IsWindow(hW)) hW=GetActiveWindow(); + hWMain = hW; // store hwnd + + ReadConfig(); // read user stuff +#endif + + + SetupSound(); // setup midas (before init!) + + SetupStreams(); // prepare streaming + + SetupTimer(); // timer for feeding data + + bSPUIsOpen=1; + +#ifdef _WIN32 + if(iDebugMode) // windows debug dialog + { + hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG), + NULL,(DLGPROC)DebugDlgProc); + SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWDebug); + SetFocus(hWMain); + } + + if(iRecordMode) // windows recording dialog + { + hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD), + NULL,(DLGPROC)RecordDlgProc); + SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWRecord); + SetFocus(hWMain); + } +#endif + + return 0; +} + + +//////////////////////////////////////////////////////////////////////// +// SPUCLOSE: called before shutdown +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2close(void) +{ + if(!bSPUIsOpen) return; // some security + + bSPUIsOpen=0; // no more open + //fclose(LogFile); +#ifdef _WIN32 + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0; + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0; +#endif + + RemoveTimer(); // no more feeding + + RemoveSound(); // no more sound handling + + RemoveStreams(); // no more streaming +} + +//////////////////////////////////////////////////////////////////////// +// SPUSHUTDOWN: called by main emu on final exit +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2shutdown(void) +{ +#ifdef _WIN32 + if(hIRE!=NULL) {FreeLibrary(hIRE);hIRE=NULL;} +#endif + + return; +} + +//////////////////////////////////////////////////////////////////////// +// SPUTEST: we don't test, we are always fine ;) +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK SPU2test(void) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPUCONFIGURE: call config dialog +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2configure(void) +{ +#ifdef _WIN32 + DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG), + GetActiveWindow(),(DLGPROC)DSoundDlgProc); +#else + //StartCfgTool("CFG"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SPUABOUT: show about window +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2about(void) +{ +#ifdef _WIN32 + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +#else + //StartCfgTool("ABOUT"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SETUP CALLBACKS +// this functions will be called once, +// passes a callback that should be called on SPU-IRQ/cdda volume change +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *SPU2callback)(int), + void (CALLBACK *DMA4callback)(int), + void (CALLBACK *DMA7callback)(int)) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +//////////////////////////////////////////////////////////////////////// +// COMMON PLUGIN INFO FUNCS +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC char * CALLBACK PS2EgetLibName(void) +{ + return libraryName; +} + +#define PS2E_LT_SPU2 0x4 + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(void) +{ + return PS2E_LT_SPU2; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + unsigned char v=version; + + // key hack to fake a lower version: + //if(GetAsyncKeyState(VK_SHIFT)&0x8000) v--; + + // compile hack to set lib version to PCSX2 0.6 standards + //v=2; + + return v<<16|revision<<8|build; +} + +//////////////////////////////////////////////////////////////////////// + diff --git a/plugins/spu2/PeopsSPU2/spu.h b/plugins/spu2/PeopsSPU2/spu.h new file mode 100644 index 0000000000..48ee32bcf6 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu.h @@ -0,0 +1,33 @@ +/*************************************************************************** + spu.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SetupTimer(void); +void RemoveTimer(void); +EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap); diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.aps b/plugins/spu2/PeopsSPU2/spu2PeopsSound.aps new file mode 100644 index 0000000000000000000000000000000000000000..ca140bb3d2496743299a5dadb0312b731a5326d5 GIT binary patch literal 51420 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⪙N+TIq5KG{kj*MYmbnY=|fJ6 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

iF>gu(L|M>9%U#?d?#-XY^fFf)#3 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 literal 0 HcmV?d00001 diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.c b/plugins/spu2/PeopsSPU2/spu2PeopsSound.c new file mode 100644 index 0000000000..8704dee69b --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.c @@ -0,0 +1,44 @@ +/*************************************************************************** + spu2PeopsSound.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/03/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// spu2PeopsSound.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" + +HINSTANCE hInst=NULL; + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD dwReason, + LPVOID lpReserved + ) +{ + + hInst=(HINSTANCE)hModule; + + return TRUE; +} + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.def b/plugins/spu2/PeopsSPU2/spu2PeopsSound.def new file mode 100644 index 0000000000..f577ea5033 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.def @@ -0,0 +1,34 @@ +; Declares the module parameters for the DLL. + +LIBRARY "spu2PeopsSound" +DESCRIPTION 'SPU2 PEOPS SOUND' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + SPU2configure @5 + SPU2about @6 + SPU2init @7 + SPU2shutdown @8 + SPU2test @9 + SPU2open @10 + SPU2close @11 + + SPU2write @13 + SPU2read @14 + + SPU2readDMA4Mem @16 + SPU2readDMA7Mem @17 + SPU2writeDMA4Mem @18 + SPU2writeDMA7Mem @19 + SPU2interruptDMA4 @20 + SPU2interruptDMA7 @21 + + SPU2freeze @33 + SPU2async @34 + SPU2irqCallback @36 + + SPU2ReadMemAddr @37 + SPU2WriteMemAddr @38 diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.dev b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dev new file mode 100644 index 0000000000..903f2df708 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dev @@ -0,0 +1,478 @@ +[Project] +FileName=spu2PeopsSound.dev +Name=spu2PeopsSound +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC_@@_ +CppCompiler=-D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC_@@_ +Includes=d:\vs\vc98\MFC\include +Linker=-ldsound -lwinmm -luser32 -lgdi32 -ladvapi32 --add-stdcall-alias_@@_ +Libs= +UnitCount=35 +Folders="Documentation Files","Header Files","Resource Files","Source Files" +ObjFiles= +PrivateResource=spu2PeopsSound_private.rc +ResourceIncludes= +MakeIncludes= +Icon= +ExeOutput=.. +ObjectOutput=Release +OverrideOutput=1 +OverrideOutputName=SPU2PeopsDSound.dll +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000001000000000 + +[Unit1] +FileName=adsr.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=alsa.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=cfg.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=debug.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=dma.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=dsound.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=freeze.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=oss.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=registers.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=reverb.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=spu.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=spu2PeopsSound.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=spu2PeopsSound.def +Folder=Source Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=spu2PeopsSound.rc +Folder=Resource Files +Compile=1 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=StdAfx.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=xa.c +Folder=Source Files +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=adsr.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=alsa.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=cfg.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=debug.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=dma.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=dsoundoss.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=externals.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=gauss_i.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=psemuxa.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=record.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=registers.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=regs.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=resource.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=reverb.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=spu.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=StdAfx.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=xa.h +Folder=Header Files +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=Filemap.txt +Folder=Documentation Files +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=License.txt +Folder=Documentation Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=License.txt +Folder=Documentation Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=bitmap4.bmp +Folder="Resource Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=bitmap5.bmp +Folder="Resource Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=changelog.txt +Folder="Documentation Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=Filemap.txt +Folder="Documentation Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit43] +FileName=License.txt +Folder="Documentation Files" +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=spu2PeopsSound.exe +ProductName=spu2PeopsSound +ProductVersion=0.1 +AutoIncBuildNr=0 + +[Unit36] +FileName=Filemap.txt +Folder=Documentation Files +Compile=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=record.c +CompileCpp=0 +Folder=Source Files +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsp b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsp new file mode 100644 index 0000000000..d6c71d4860 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsp @@ -0,0 +1,282 @@ +# Microsoft Developer Studio Project File - Name="spu2PeopsSound" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=spu2PeopsSound - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "spu2PeopsSound.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "spu2PeopsSound.mak" CFG="spu2PeopsSound - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "spu2PeopsSound - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "spu2PeopsSound - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "spu2PeopsSound - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 dsound.lib winmm.lib user32.lib gdi32.lib advapi32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=rem copy release\spu2PeopsSound.dll D:\pcsx2\plugins\spu2PeopsDSound.dll +# End Special Build Tool + +!ELSEIF "$(CFG)" == "spu2PeopsSound - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "spu2PeopsSound - Win32 Release" +# Name "spu2PeopsSound - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\adsr.c +# End Source File +# Begin Source File + +SOURCE=.\alsa.c +# End Source File +# Begin Source File + +SOURCE=.\cfg.c +# End Source File +# Begin Source File + +SOURCE=.\debug.c +# End Source File +# Begin Source File + +SOURCE=.\dma.c +# End Source File +# Begin Source File + +SOURCE=.\dsound.c +# End Source File +# Begin Source File + +SOURCE=.\freeze.c +# End Source File +# Begin Source File + +SOURCE=.\oss.c +# End Source File +# Begin Source File + +SOURCE=.\psemu.c +# End Source File +# Begin Source File + +SOURCE=.\record.c +# End Source File +# Begin Source File + +SOURCE=.\registers.c +# End Source File +# Begin Source File + +SOURCE=.\reverb.c +# End Source File +# Begin Source File + +SOURCE=.\spu.c +# End Source File +# Begin Source File + +SOURCE=.\spu2PeopsSound.c +# End Source File +# Begin Source File + +SOURCE=.\spu2PeopsSound.def +# End Source File +# Begin Source File + +SOURCE=.\spu2PeopsSound.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.c +# End Source File +# Begin Source File + +SOURCE=.\xa.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\adsr.h +# End Source File +# Begin Source File + +SOURCE=.\alsa.h +# End Source File +# Begin Source File + +SOURCE=.\cfg.h +# End Source File +# Begin Source File + +SOURCE=.\debug.h +# End Source File +# Begin Source File + +SOURCE=.\dma.h +# End Source File +# Begin Source File + +SOURCE=.\dsoundoss.h +# End Source File +# Begin Source File + +SOURCE=.\externals.h +# End Source File +# Begin Source File + +SOURCE=.\gauss_i.h +# End Source File +# Begin Source File + +SOURCE=.\psemuxa.h +# End Source File +# Begin Source File + +SOURCE=.\record.h +# End Source File +# Begin Source File + +SOURCE=.\registers.h +# End Source File +# Begin Source File + +SOURCE=.\regs.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\reverb.h +# End Source File +# Begin Source File + +SOURCE=.\spu.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\xa.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\bitmap1.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmap2.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmap3.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmap4.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmap5.bmp +# End Source File +# End Group +# Begin Group "Documentation Files" + +# PROP Default_Filter "txt" +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# Begin Source File + +SOURCE=.\Filemap.txt +# End Source File +# Begin Source File + +SOURCE=.\License.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsw b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsw new file mode 100644 index 0000000000..fe93e6f06e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "spu2PeopsSound"=.\spu2PeopsSound.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.layout b/plugins/spu2/PeopsSPU2/spu2PeopsSound.layout new file mode 100644 index 0000000000..0b3a784f5a --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.layout @@ -0,0 +1,284 @@ +[Editor_0] +CursorCol=5 +CursorRow=443 +TopLine=431 +LeftChar=1 +Open=1 +Top=0 +[Editor_3] +CursorCol=27 +CursorRow=232 +TopLine=223 +LeftChar=1 +Open=1 +Top=0 +[Editors] +Order=11,9,4,34,2,14,23,29,5,0,3,19,6,7,8,10,12,13 +Focused=14 +[Editor_1] +Open=0 +Top=0 +CursorCol=9 +CursorRow=81 +TopLine=81 +LeftChar=1 +[Editor_2] +Open=1 +Top=0 +CursorCol=1 +CursorRow=312 +TopLine=284 +LeftChar=1 +[Editor_4] +Open=1 +Top=0 +CursorCol=1 +CursorRow=204 +TopLine=186 +LeftChar=1 +[Editor_5] +Open=1 +Top=0 +CursorCol=1 +CursorRow=41 +TopLine=35 +LeftChar=1 +[Editor_6] +Open=1 +Top=0 +CursorCol=27 +CursorRow=90 +TopLine=66 +LeftChar=1 +[Editor_7] +Open=1 +Top=0 +CursorCol=1 +CursorRow=175 +TopLine=151 +LeftChar=1 +[Editor_8] +Open=1 +Top=0 +CursorCol=2 +CursorRow=188 +TopLine=153 +LeftChar=1 +[Editor_9] +Open=1 +Top=0 +CursorCol=6 +CursorRow=989 +TopLine=978 +LeftChar=1 +[Editor_10] +Open=1 +Top=0 +CursorCol=11 +CursorRow=99 +TopLine=88 +LeftChar=1 +[Editor_11] +Open=1 +Top=0 +CursorCol=33 +CursorRow=514 +TopLine=531 +LeftChar=1 +[Editor_12] +Open=1 +Top=0 +CursorCol=15 +CursorRow=36 +TopLine=9 +LeftChar=1 +[Editor_13] +Open=1 +Top=0 +CursorCol=7 +CursorRow=26 +TopLine=1 +LeftChar=1 +[Editor_14] +Open=1 +Top=1 +CursorCol=31 +CursorRow=139 +TopLine=121 +LeftChar=1 +[Editor_15] +Open=0 +Top=0 +CursorCol=7 +CursorRow=251 +TopLine=234 +LeftChar=1 +[Editor_16] +Open=0 +Top=0 +CursorCol=14 +CursorRow=32 +TopLine=154 +LeftChar=1 +[Editor_17] +Open=0 +Top=0 +CursorCol=1 +CursorRow=28 +TopLine=1 +LeftChar=1 +[Editor_18] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_19] +Open=1 +Top=0 +CursorCol=15 +CursorRow=33 +TopLine=8 +LeftChar=1 +[Editor_20] +Open=0 +Top=0 +CursorCol=13 +CursorRow=20 +TopLine=1 +LeftChar=1 +[Editor_21] +Open=0 +Top=0 +CursorCol=1 +CursorRow=29 +TopLine=1 +LeftChar=1 +[Editor_22] +Open=0 +Top=0 +CursorCol=20 +CursorRow=21 +TopLine=1 +LeftChar=1 +[Editor_23] +Open=1 +Top=0 +CursorCol=20 +CursorRow=144 +TopLine=126 +LeftChar=1 +[Editor_24] +Open=0 +Top=0 +CursorCol=3 +CursorRow=344 +TopLine=309 +LeftChar=1 +[Editor_25] +Open=0 +Top=0 +CursorCol=5 +CursorRow=25 +TopLine=1 +LeftChar=1 +[Editor_26] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_27] +Open=0 +Top=0 +CursorCol=1 +CursorRow=57 +TopLine=41 +LeftChar=1 +[Editor_28] +Open=0 +Top=0 +CursorCol=62 +CursorRow=43 +TopLine=8 +LeftChar=1 +[Editor_29] +Open=1 +Top=0 +CursorCol=9 +CursorRow=22 +TopLine=1 +LeftChar=1 +[Editor_30] +Open=0 +Top=0 +CursorCol=1 +CursorRow=25 +TopLine=1 +LeftChar=1 +[Editor_31] +Open=0 +Top=0 +CursorCol=1 +CursorRow=25 +TopLine=1 +LeftChar=1 +[Editor_32] +Open=0 +Top=0 +CursorCol=3 +CursorRow=48 +TopLine=26 +LeftChar=1 +[Editor_33] +Open=0 +Top=0 +CursorCol=16 +CursorRow=29 +TopLine=1 +LeftChar=1 +[Editor_34] +Open=1 +Top=0 +CursorCol=5 +CursorRow=13 +TopLine=1 +LeftChar=1 +[Editor_35] +Open=0 +Top=0 +CursorCol=19 +CursorRow=16 +TopLine=1 +LeftChar=1 +[Editor_36] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_37] +Open=0 +Top=0 +CursorCol=27 +CursorRow=19 +TopLine=1 +LeftChar=1 +[Editor_38] +Open=0 +Top=0 +[Editor_39] +Open=0 +Top=0 +[Editor_40] +Open=0 +Top=0 +[Editor_41] +Open=0 +Top=0 +[Editor_42] +Open=0 +Top=0 diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.opt b/plugins/spu2/PeopsSPU2/spu2PeopsSound.opt new file mode 100644 index 0000000000000000000000000000000000000000..542785eafa1f933aadec54535891a7b4c95a477e GIT binary patch literal 54784 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 J%zo`E@PGV!?63d; literal 0 HcmV?d00001 diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.plg b/plugins/spu2/PeopsSPU2/spu2PeopsSound.plg new file mode 100644 index 0000000000..1860a27e48 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.plg @@ -0,0 +1,81 @@ + + +

+

Build Log

+

+--------------------Configuration: spu2PeopsSound - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3A5.tmp" with contents +[ +/nologo /G5 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR"Release/" /Fp"Release/spu2PeopsSound.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"C:\Documents and Settings\SAQIB\Desktop\PeopsSpu2_103\src\dma.c" +] +Creating command line "snCl.exe @C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3A5.tmp" +Creating temporary file "C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3A6.tmp" with contents +[ +dsound.lib winmm.lib user32.lib gdi32.lib advapi32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"Release/spu2PeopsSound.pdb" /machine:I386 /def:".\spu2PeopsSound.def" /out:"Release/spu2PeopsSound.dll" /implib:"Release/spu2PeopsSound.lib" +".\Release\adsr.obj" +".\Release\alsa.obj" +".\Release\cfg.obj" +".\Release\debug.obj" +".\Release\dma.obj" +".\Release\dsound.obj" +".\Release\freeze.obj" +".\Release\oss.obj" +".\Release\psemu.obj" +".\Release\record.obj" +".\Release\registers.obj" +".\Release\reverb.obj" +".\Release\spu.obj" +".\Release\spu2PeopsSound.obj" +".\Release\StdAfx.obj" +".\Release\xa.obj" +".\Release\spu2PeopsSound.res" +] +Creating command line "snLink.exe @C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3A6.tmp" +

Output Window

+Compiling... +snCL -- Detected win32 build...passing to cl.exe +dma.c +Linking... +snCL -- Detected win32 build...passing to link.exe + Creating library Release/spu2PeopsSound.lib and object Release/spu2PeopsSound.exp +Creating temporary file "C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3AA.tmp" with contents +[ +/nologo /o"Release/spu2PeopsSound.bsc" +".\Release\adsr.sbr" +".\Release\alsa.sbr" +".\Release\cfg.sbr" +".\Release\debug.sbr" +".\Release\dma.sbr" +".\Release\dsound.sbr" +".\Release\freeze.sbr" +".\Release\oss.sbr" +".\Release\psemu.sbr" +".\Release\record.sbr" +".\Release\registers.sbr" +".\Release\reverb.sbr" +".\Release\spu.sbr" +".\Release\spu2PeopsSound.sbr" +".\Release\StdAfx.sbr" +".\Release\xa.sbr"] +Creating command line "snBsc.exe @C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3AA.tmp" +Creating browse info file... +snCL -- Detected win32 build...passing to bscmake.exe +

Output Window

+Creating temporary file "C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3AB.bat" with contents +[ +@echo off +rem copy release\spu2PeopsSound.dll D:\pcsx2\plugins\spu2PeopsDSound.dll +] +Creating command line "C:\DOCUME~1\SAQIB\LOCALS~1\Temp\RSP3AB.bat" + + + + +

Results

+spu2PeopsSound.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.rc b/plugins/spu2/PeopsSPU2/spu2PeopsSound.rc new file mode 100644 index 0000000000..bcdad6b000 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.rc @@ -0,0 +1,372 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Polish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK) +#ifdef _WIN32 +LANGUAGE LANG_POLISH, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif\r\n" + "#include ""res\\spu2PeopsSound.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Polish resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOGEX 0, 0, 239, 198 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About the P.E.Op.S. SPU2 DSound Audio Driver..." +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,98,178,44,14 + RTEXT "Version:",IDC_STATIC,5,7,74,9 + RTEXT "Release date :",IDC_STATIC,5,16,74,9 + RTEXT "Coded by :",IDC_STATIC,5,27,74,9 + RTEXT "Pete's EMail :",IDC_STATIC,5,40,74,9 + RTEXT "Pete's homepage :",IDC_STATIC,5,51,74,9 + LTEXT "1.9.0",IDC_STATIC,81,7,155,9 + LTEXT "11.11.2007",IDC_STATIC,81,16,154,9 + LTEXT "Pete Bernert and the P.E.Op.S. team",IDC_STATIC,81,27,154,9 + LTEXT "BlackDove@addcom.de",IDC_STATIC,81,40,154,9 + LTEXT "http://www.pbernert.com",IDC_STATIC,81,51,154,9 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,132,218,41,WS_EX_DLGMODALFRAME + RTEXT "Greetings to:",IDC_STATIC,12,137,41,9 + LTEXT "- Kanodin, Elly and zenogais (I wouldn't have started without their sources).\n- Neill Corlett (for his always excellent work)",IDC_STATIC,56,137,153,27 + RTEXT "P.E.Op.S. homepage :",IDC_STATIC,5,87,74,9 + LTEXT "https://sourceforge.net/projects/peops/",IDC_STATIC,82,87,154,9 + RTEXT "linuzappz :",IDC_STATIC,10,63,69,10 + LTEXT "http://www.pcsx.net",IDC_STATIC,81,63,142,10 + RTEXT "kode54 :",IDC_STATIC,10,75,69,10 + LTEXT "http://home.earthlink.net/~kode54/",IDC_STATIC,81,75,142,10 + LTEXT "Additional changes by Refraction of PCSX2 team",IDC_STATIC,12,103,198,14 +END + +IDD_CFGDLG DIALOGEX 0, 0, 258, 150 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "P.E.Op.S SPU2 Plugin Configuration" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + COMBOBOX IDC_VOLUME,55,19,186,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_USEREVERB,55,35,186,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_INTERPOL,55,51,186,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Enable developer debug mode",IDC_DEBUGMODE,"Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,12,97,229,10 + CONTROL "Enable sound recording window",IDC_RECORDMODE,"Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,12,84,229,10 + DEFPUSHBUTTON "OK",IDOK,51,127,45,14 + PUSHBUTTON "Cancel",IDCANCEL,157,127,45,14 + RTEXT "Volume:",IDC_STATIC,23,22,29,10,SS_CENTERIMAGE + GROUPBOX "General settings",IDC_STATIC,7,7,245,63 + GROUPBOX "Misc",IDC_STATIC,7,74,245,51 + RTEXT "Reverb:",IDC_STATIC,23,38,29,10,SS_CENTERIMAGE + RTEXT "Interpolation:",IDC_STATIC,9,54,43,10,SS_CENTERIMAGE + CONTROL "Enable Thread Mode",IDC_TIMER,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,12,111,194,11 +END + +IDD_DEBUG DIALOGEX 0, 0, 398, 314 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "P.E.Op.S. SPU2 sound debug screen" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Core 0",IDC_CORE1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,44,2,49,8 + CONTROL "Core 1",IDC_CORE2,"Button",BS_AUTORADIOBUTTON,101,2,49,8 + LTEXT "",IDC_SAREA,4,14,150,288,WS_BORDER + CONTROL "",IDC_MUTE1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,14,9,9 + CONTROL "1",IDC_CHAN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,168,14,22,9 + CONTROL "",IDC_MUTE2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,26,9,9 + CONTROL "2",IDC_CHAN2,"Button",BS_AUTORADIOBUTTON,168,26,22,9 + CONTROL "",IDC_MUTE3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,38,9,9 + CONTROL "3",IDC_CHAN3,"Button",BS_AUTORADIOBUTTON,168,38,22,9 + CONTROL "",IDC_MUTE4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,50,9,9 + CONTROL "4",IDC_CHAN4,"Button",BS_AUTORADIOBUTTON,168,50,22,9 + CONTROL "",IDC_MUTE5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,62,9,9 + CONTROL "5",IDC_CHAN5,"Button",BS_AUTORADIOBUTTON,168,62,22,9 + CONTROL "",IDC_MUTE6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,74,9,9 + CONTROL "6",IDC_CHAN6,"Button",BS_AUTORADIOBUTTON,168,74,22,9 + CONTROL "",IDC_MUTE7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,86,9,9 + CONTROL "7",IDC_CHAN7,"Button",BS_AUTORADIOBUTTON,168,86,22,9 + CONTROL "",IDC_MUTE8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,98,9,9 + CONTROL "8",IDC_CHAN8,"Button",BS_AUTORADIOBUTTON,168,98,22,9 + CONTROL "",IDC_MUTE9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,110,9,9 + CONTROL "9",IDC_CHAN9,"Button",BS_AUTORADIOBUTTON,168,110,22,9 + CONTROL "",IDC_MUTE10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,122,9,9 + CONTROL "10",IDC_CHAN10,"Button",BS_AUTORADIOBUTTON,168,122,22,9 + CONTROL "",IDC_MUTE11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,134,9,9 + CONTROL "11",IDC_CHAN11,"Button",BS_AUTORADIOBUTTON,168,134,22,9 + CONTROL "",IDC_MUTE12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,146,9,9 + CONTROL "12",IDC_CHAN12,"Button",BS_AUTORADIOBUTTON,168,146,22,9 + CONTROL "",IDC_MUTE13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,158,9,9 + CONTROL "13",IDC_CHAN13,"Button",BS_AUTORADIOBUTTON,168,158,22,9 + CONTROL "",IDC_MUTE14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,170,9,9 + CONTROL "14",IDC_CHAN14,"Button",BS_AUTORADIOBUTTON,168,170,22,9 + CONTROL "",IDC_MUTE15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,182,9,9 + CONTROL "15",IDC_CHAN15,"Button",BS_AUTORADIOBUTTON,168,182,22,9 + CONTROL "",IDC_MUTE16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,194,9,9 + CONTROL "16",IDC_CHAN16,"Button",BS_AUTORADIOBUTTON,168,194,22,9 + CONTROL "",IDC_MUTE17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,206,9,9 + CONTROL "17",IDC_CHAN17,"Button",BS_AUTORADIOBUTTON,168,206,22,9 + CONTROL "",IDC_MUTE18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,218,9,9 + CONTROL "18",IDC_CHAN18,"Button",BS_AUTORADIOBUTTON,168,218,22,9 + CONTROL "",IDC_MUTE19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,230,9,9 + CONTROL "19",IDC_CHAN19,"Button",BS_AUTORADIOBUTTON,168,230,22,9 + CONTROL "",IDC_MUTE20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,242,9,9 + CONTROL "20",IDC_CHAN20,"Button",BS_AUTORADIOBUTTON,168,242,22,9 + CONTROL "",IDC_MUTE21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,254,9,9 + CONTROL "21",IDC_CHAN21,"Button",BS_AUTORADIOBUTTON,168,254,22,9 + CONTROL "",IDC_MUTE22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,266,9,9 + CONTROL "22",IDC_CHAN22,"Button",BS_AUTORADIOBUTTON,168,266,22,9 + CONTROL "",IDC_MUTE23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,278,9,9 + CONTROL "23",IDC_CHAN23,"Button",BS_AUTORADIOBUTTON,168,278,22,9 + CONTROL "",IDC_MUTE24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,290,9,9 + CONTROL "24",IDC_CHAN24,"Button",BS_AUTORADIOBUTTON,168,290,22,9 + LTEXT "Streams",IDC_STATIC,6,2,29,8 + CTEXT "Mute/Select",IDC_STATIC,144,2,55,8 + LTEXT "",IDC_ADSR,208,22,176,55,WS_BORDER + RTEXT "Attack:",IDC_STATIC,221,81,30,9 + RTEXT "Decay:",IDC_STATIC,221,92,30,9 + RTEXT "Sustain:",IDC_STATIC,221,103,30,9 + RTEXT "Release:",IDC_STATIC,221,114,30,9 + LTEXT "---",IDC_SADSR1,254,81,44,9 + LTEXT "---",IDC_SADSR2,254,92,44,9 + LTEXT "---",IDC_SADSR3,254,103,44,9 + LTEXT "---",IDC_SADSR4,254,114,42,9 + RTEXT "Sustain level:",IDC_STATIC,302,81,44,9 + LTEXT "---",IDC_SADSR5,349,81,38,9 + RTEXT "Sustain inc.:",IDC_STATIC,302,92,44,9 + LTEXT "---",IDC_SADSR6,349,92,38,9 + RTEXT "Channel:",IDC_STATIC,204,2,30,8 + GROUPBOX "ADSR channel info",IDC_STATIC,201,11,190,119 + LTEXT "1",IDC_CHANNUM,238,2,33,8 + PUSHBUTTON "M0",IDC_MUTEOFF,157,300,15,10 + PUSHBUTTON "M1",IDC_MUTEON,174,300,15,10 + GROUPBOX "Generic channel info",IDC_STATIC,201,131,190,114 + RTEXT "On:",IDC_STATIC,210,143,41,9 + RTEXT "Stop:",IDC_STATIC,210,154,41,9 + RTEXT "Reverb:",IDC_STATIC,210,187,41,9 + RTEXT "Start pos:",IDC_STATIC,301,143,35,9 + RTEXT "Curr pos:",IDC_STATIC,301,154,35,9 + RTEXT "Loop pos:",IDC_STATIC,301,165,35,9 + RTEXT "Act freq:",IDC_STATIC,300,220,35,9 + RTEXT "Used freq:",IDC_STATIC,300,231,35,9 + RTEXT "Right vol:",IDC_STATIC,300,192,35,9 + RTEXT "Left vol:",IDC_STATIC,300,203,35,9 + RTEXT "Rvb active:",IDC_STATIC,210,198,41,9 + RTEXT "Rvb end:",IDC_STATIC,210,220,41,9 + RTEXT "Rvb cur:",IDC_STATIC,210,231,41,9 + RTEXT "Noise:",IDC_STATIC,210,165,41,9 + RTEXT "FMod:",IDC_STATIC,210,176,41,9 + RTEXT "Rvb start:",IDC_STATIC,210,209,41,9 + RTEXT "Irq addr.:",IDC_STATIC,207,259,35,9 + RTEXT "Curr adsr vol.:",IDC_STATIC,302,103,44,9 + LTEXT "---",IDC_SADSR7,349,103,38,9 + LTEXT "---",IDC_CI1,254,143,39,9 + LTEXT "---",IDC_CI2,254,154,39,9 + LTEXT "---",IDC_CI3,254,165,39,9 + LTEXT "---",IDC_CI4,254,176,39,9 + LTEXT "---",IDC_CI5,254,187,39,9 + LTEXT "---",IDC_CI6,254,198,39,9 + LTEXT "---",IDC_CI7,254,209,39,9 + LTEXT "---",IDC_CI8,254,220,39,9 + LTEXT "---",IDC_CI9,254,231,39,9 + LTEXT "---",IDC_CI10,339,143,46,9 + GROUPBOX "Spu states",IDC_STATIC,202,246,189,61 + LTEXT "---",IDC_CI11,339,154,46,9 + LTEXT "---",IDC_CI12,339,165,46,9 + LTEXT "---",IDC_CI13,339,192,23,9 + LTEXT "---",IDC_CI14,339,203,22,9 + LTEXT "---",IDC_CI15,339,220,46,9 + LTEXT "---",IDC_CI16,339,231,46,9 + LTEXT "---",IDC_STA1,246,259,46,9 + RTEXT "Raw envelope:",IDC_STATIC,296,114,50,9 + LTEXT "---",IDC_SADSR8,349,114,38,9 + RTEXT "Ctrl:",IDC_STATIC,207,270,35,9 + LTEXT "---",IDC_STA2,247,270,46,9 + RTEXT "Stat:",IDC_STATIC,207,281,35,9 + LTEXT "---",IDC_STA3,247,281,46,9 + RTEXT "Spu mem:",IDC_STATIC,207,292,35,9 + LTEXT "---",IDC_STA4,247,292,46,9 + LTEXT "---",IDC_CI17,367,192,18,9 + LTEXT "---",IDC_CI18,367,203,18,9 + RTEXT "Dbg addr:",IDC_STATIC,301,176,35,9 + LTEXT "---",IDC_CI19,339,176,46,9 +END + +IDD_RECORD DIALOGEX 0, 0, 248, 25 +STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "P.E.Op.S. SPU2 sound recording" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + RTEXT "Filename:",IDC_STATIC,3,5,33,9 + EDITTEXT IDC_WAVFILE,41,3,134,12,ES_AUTOHSCROLL + PUSHBUTTON "Start recording",IDC_RECORD,180,3,61,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 236 + TOPMARGIN, 7 + BOTTOMMARGIN, 192 + END + + IDD_CFGDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 251 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_DEBUG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 391 + TOPMARGIN, 7 + BOTTOMMARGIN, 307 + END + + IDD_RECORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 241 + TOPMARGIN, 7 + BOTTOMMARGIN, 18 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,6,0,0 + PRODUCTVERSION 1,6,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "P.E.Op.S. Sound PS2 SPU Audio driver - coded by Pete Bernert and the P.E.Op.S. team" + VALUE "FileDescription", "spu2PeopsSound" + VALUE "FileVersion", "1, 6, 0, 0" + VALUE "InternalName", "spu2PeopsSound" + VALUE "LegalCopyright", "GPL 2004" + VALUE "LegalTrademarks", "GPL 2004" + VALUE "OriginalFilename", "spu2PeopsSound.DLL" + VALUE "ProductName", "spu2PeopsSound" + VALUE "ProductVersion", "1, 6, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif +#include "res\spu2PeopsSound.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.sln b/plugins/spu2/PeopsSPU2/spu2PeopsSound.sln new file mode 100644 index 0000000000..8c8be52b5f --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "spu2PeopsSound.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound.vcproj b/plugins/spu2/PeopsSPU2/spu2PeopsSound.vcproj new file mode 100644 index 0000000000..5643ad1d5b --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound.vcproj @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.sln b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.sln new file mode 100644 index 0000000000..0dcb9f7446 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "spu2PeopsSound_2005.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.ActiveCfg = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|Win32.Build.0 = Debug|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.ActiveCfg = Release|Win32 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.vcproj b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.vcproj new file mode 100644 index 0000000000..7056cc3cb9 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005.vcproj @@ -0,0 +1,620 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.sln b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.sln new file mode 100644 index 0000000000..222c18f7b5 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spu2PeopsSound", "spu2PeopsSound_2005_x64.vcproj", "{F9E64144-301B-48BC-8D35-A2686DBB1982}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|x64.ActiveCfg = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Debug|x64.Build.0 = Debug|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|x64.ActiveCfg = Release|x64 + {F9E64144-301B-48BC-8D35-A2686DBB1982}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.vcproj b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.vcproj new file mode 100644 index 0000000000..bae1fe5f77 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2005_x64.vcproj @@ -0,0 +1,1074 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_2008.vcproj b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2008.vcproj new file mode 100644 index 0000000000..b524a4397e --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_2008.vcproj @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.h b/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.h new file mode 100644 index 0000000000..1571415d63 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.h @@ -0,0 +1,23 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ +/* DO NOT EDIT ! */ + +#ifndef SPU2PEOPSSOUND_PRIVATE_H +#define SPU2PEOPSSOUND_PRIVATE_H + +/* VERSION DEFINITIONS */ +#define VER_STRING "0.1.1.1" +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_RELEASE 1 +#define VER_BUILD 1 +#define COMPANY_NAME "" +#define FILE_VERSION "0.1" +#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" +#define INTERNAL_NAME "" +#define LEGAL_COPYRIGHT "" +#define LEGAL_TRADEMARKS "" +#define ORIGINAL_FILENAME "spu2PeopsSound.exe" +#define PRODUCT_NAME "spu2PeopsSound" +#define PRODUCT_VERSION "0.1" + +#endif /*SPU2PEOPSSOUND_PRIVATE_H*/ diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.rc b/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.rc new file mode 100644 index 0000000000..d59c33befb --- /dev/null +++ b/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.rc @@ -0,0 +1,5 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ +/* DO NOT EDIT! */ + +#include "spu2PeopsSound.rc" + diff --git a/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.res b/plugins/spu2/PeopsSPU2/spu2PeopsSound_private.res new file mode 100644 index 0000000000000000000000000000000000000000..2542852aa2f4ca5be72aba770dfa14cf1378a7b6 GIT binary patch literal 10492 zcmbtaU2Gl26+U}y2sRK>K%pcg+=M`E@ZWVpfD{6WlaP?V8#^&j5~%-U;@IY1J5Hji zxDvJk1ON2`LMpKDOE$K@MrGWa-+brHnKLtIW_M>436GB(MC`0qT1w?opWd~vW02jA)7SCK;}ZPeCo+v6`P)^0 zz$uTM-p`9v7UAkNe({r#*UD44F5>>v_&tQ*@8h?EzvuA#vYsaKX3a;C@$h=={-<_( z*8R8=v+gglVyXMQ^=^jVJcModfBn)}5q|!%K%|$IkB@CvimYAiu0+0llgQ`(QpQ(_ zTvqFEL^3nuuBPSP%C&lNL4KjX8>LsqWKt$1kN-n5fZw9D$QJzXk#T%?;XjY>qU@J; zoNdNAON>fCt~TPVUxsmqk`m62f}?~o{J;`wiFTn3IeJj4tY^dw%b?m|Uy($`Uiq;! z$wGDK%uEFq>_{Nk+PUH-Xz>T6PHQzY^OSU}zOvdd3hwo(60XdmRGChc8Nq)KtYMA& zaWC&ceX{u}o>e>%1Yu_u!XKA!D4XH9k;K{#QYrjQyLEkVe2(7iUYvw6?2-=T; zX&ekg_zf9Y`CPFRK6)kLqXOEZO$woBihE^IfV)ePYw_KV5^b_}jxtMAWnA6zvI+K- z(8By?Jh8RurTOBDUg<%N!XpRU8d7>T!CyVnCx;PdV;W`m;kqB6KJ`fp&IUpn_+qcD zN%0(lJrnTXdTGVS`LhN0n!z&)EyG#|0{O4Gpp#@+sV#1hya2)!@#5*d? z2x57+gc=Xvyb+O956|XhH?A4;jC%H=63*yPYHGkpz&q4wHuXR{1)ay$!T~v^d@N1t zS%&tO;OoY~vDSwk3Hs3N5zV!Hc28pLJThnOl;h}0*41jjKG^~bS+iC|SqWA?j;lUg zm-Ws7?u_es+Hl%kFZZIw>Z@&Pu{bFw;E8d3PN3d%#ll{cdp=Pv9ph8*)fB86hZSXb z(%Cnc{v9d(hhZyw)$JGuW^1N@cFd#KdAJ1(7Cnd1evHh+RU2C6JGk;%TGc4dQ#`pw zul_CP^p{aHibxqo>@vbQ`pq}C{O@zteDhU}tUx*;vJUgquhGXY)XdC$Pwf-&vgMF% zkblf6YteF_&MDiV~UZaroYR|~aLzt2CXlag> z$JN(E&bBJg5&1KCJ_&d_w7+xIp!m|8#{kW!T=d*Gic77JvX|0;anAItJ!NIYGBZb-J z#*q%qS2*gi=P^H_uXuR=m*ubE|1#j;rC8R(dbiDCtOxB(j#XuN+1I6rQH?!3S*j2E zODM;2Fs=Kis{5aT?sQvHAG0ZHVLQ-cyw?jq4&mI{q|}LeomTEI=H*UW$@bwKN=t3t zp+|Yvuk|y2=4U)xgY30gbF?r+Gx<+qc@Cpk1wP@t!?|F@Xe5_I)8JT)8Z3kVXK*l! z8v|lea~m7skoGFB7FpjHXlddqazB_DH6`$JCSm@@zF>BjV;#Qiew5{0%(52KN1%n- zVjoI3;CxiCErOYo4xt|~b~#5*Y1|*j86%gi$qaJ>SIl!
    Eg4_4#X>#jierdanb zFqgq#hxb8S!UvtGi)GKf@hI=U)=@yv1q z_Ov#_ki}XY48-_SCf@Q}=l|czmvTVviT$rs7@sXh--m25bRP-07$J64;@G=Fekl3q zBF1B`BY8NEljs9=_*@ro5aa6jDlm(2)f!-2ChobGDA(5moN-zGUzH`w)fQmd3BuvI zZc(o50~|5Vm#@k#%2fz3YY4*Ox!RR$Nq{59bG0j1dw_8(2hX)Zxt0dFG}i{@S`%Py zCkTh<;tH@%ZU}J1c)K1@uC)PX9YHueSGRI43vk4Eu5RVJJ;2;S5Dw4Pt6a+i95J4& zSGm>&m^%r=;kibY>&5^_jOQ9vt~&zET?FCqTql$(AK-}bTql(4&Hz)0`=RH0M!8l5 zxHQ)@%5_(ODa30~&-IdWtqgE!u9uW+eSj%oh04Qoom8%y0$iHwq;h>Dz!Wg6rMX^H zu2lgp&Gnjc-5p>G@tWD&^@eiY9N^MiZz$J20j7Y=J8jq7%5_VCOLM)gTpI#R0U2wW z>wV=~9pKVj?`8xu8)!vCO@m!rtG6 zW(eHtu`Df$^MDtDyQ7NRh1`mHODjs)9v$;{J8Vw=Jv@9GC1w(HGS|+;{0VvDa`?=2 za)*Tb7Thz6bEPWoKmxZJnwZ-iudb~<-%tYArI{ibnQgi}%416jEOR-(!|1Twx1pUE zVP_NU+*V89H0y`=z5Ia6w`a8&H!r=`hn2r$HD4Tz4k+iY49+u%kLA_)aH~|V0Y<7!KIgk!euJ!?`YXug zxL4hYOtLRt+gd5+?c7HgGndD0@(J{;fS%oIhs)61nx-kb3c2+j$STNgZDe3^lmA>y zUX10gw72VN*j0+{@@p7dg?xo|v3+Od1*|b#Z11T?plj2!*s1bz_BXB?&DS3DW&$(E zdL!1=9K9enRdtce_HS(U&fPCN9B*^m#mKxz=}Rk3E&Z?gWB%&W&w~&LyxL z(T-f14eChpL{PV;=zIdZA9`&~mqw$9#dU0orW5$i#LDj|Eb_7C@$V(@JHbAv)+Esm zdsf~_`S~c;?0zqTeJgC2b93Oin(CkB>$BJu@$KA+6(hO()aPNloRw1v>~7SHt5B!i z`{FD{RL{8;5zZB6XyXS7jMHo526u)--Az$V`XL^h_`*x_S{ zd;DdT$fKrgmqbY&OAn$P$E3Z%_~FOW7qFjQC!Lw{S5)4WDL9NDL<$3hco5pRsPKkc^CS63;gp)Aa`R|WAvpwT3ttXp|5f;#M+%R zwcB%X{_et9K)wS3pO>Ff`N2&2v|NYsk7ml>(;VxuO!+zG|5m2_yvlnrg0TR zM(QGuq0QW};uDe(cTEb%ERuWAjJ~Ru;&J_qEK6Xyx5V8!<8@=2tHTA@NS_V`b@1}K z=xdN4%9LNDJ{ZoFFH`yB8S*jAL05zSaHjk{m5*e|FUV@m#m6$_^^wWP1G)GA>V&Um z@4-4;b96c}_ie_E!~JJ_`dacWpfT13EPXl}=yX1PF3KS{b^E@|z1@Dc%gTJ4eph~} zoXK&;)=VHu+VptEhlRFGk zmy7UhtzIS-(;+*NCEH>0&+&c^a|mvwxX zhC7+vKt6`=E$~zqB5x0#XFrDD-Le(uJl?9ka1lE6!)u=LxL3bL_)1PLK6gKZ>PSW> zTawS-T)npA%2p_w6vH<$+OWI9-(FpROe6Xu^aZ{TLJx4ipL6ltt--jrCs{?<-;Unv zo}(q-;9+Lw-r%t(Yiup<^!vA6+*=U;@B1Dr)k9`KpTUn}{k$QE-<-=CWY9q6+3$4zvWmsz)+P9fX(0l1S=Lz4#L{@3pq@z3I0APmA2W0) // curr delta positive + { + if(id2id1) + {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;} + else + if(id2>(id1<<1)) + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L; + else + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; + } + } + else + if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass + { + s_chan[ch].SB[32]=0; + + s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L; + if(s_chan[ch].sinc<=0x8000) + s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); + else s_chan[ch].SB[29]+=s_chan[ch].SB[28]; + } + else // no flags? add bigger val (if possible), calc smaller step, set flag1 + s_chan[ch].SB[29]+=s_chan[ch].SB[28]; +} + +// +// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm +// + +INLINE void InterpolateDown(int ch) +{ + if(s_chan[ch].sinc>=0x20000) // we would skip at least one val? + { + s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight + if(s_chan[ch].sinc>=0x30000) // we would skip even more vals? + s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight + } +} + +//////////////////////////////////////////////////////////////////////// +// helpers for gauss interpolation + +#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos]) +#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) + +#include "gauss_i.h" + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// START SOUND... called by main thread to setup a new sound on a channel +//////////////////////////////////////////////////////////////////////// + +INLINE void StartSound(int ch) +{ + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear new channel bit + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + + StartADSR(ch); + StartREVERB(ch); + + s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start + + s_chan[ch].s_1=0; // init mixing vars + s_chan[ch].s_2=0; + s_chan[ch].iSBPos=28; + + s_chan[ch].bNew=0; // init channel flags + s_chan[ch].bStop=0; + s_chan[ch].bOn=1; + + s_chan[ch].SB[29]=0; // init our interpolation helpers + s_chan[ch].SB[30]=0; + + if(iUseInterpolation>=2) // gauss interpolation? + {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding + else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding +} + + +void UpdateMainVolL() // LEFT VOLUME +{ + short vol = regArea[PS2_C0_MVOLL]; + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + //vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + regArea[PS2_C0_MVOLL]=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// RIGHT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +void UpdateMainVolR() // RIGHT VOLUME +{ + short vol = regArea[PS2_C0_MVOLR]; + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) //vol=vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + + regArea[PS2_C0_MVOLR]=vol; +} +//////////////////////////////////////////////////////////////////////// +// MAIN SPU FUNCTION +// here is the main job handler... thread, timer or direct func call +// basically the whole sound processing is done in this fat func! +//////////////////////////////////////////////////////////////////////// + +// 5 ms waiting phase, if buffer is full and no new sound has to get started +// .. can be made smaller (smallest val: 1 ms), but bigger waits give +// better performance + +#define PAUSE_W 5 +#define PAUSE_L 5000 +extern unsigned long MemAddr[2]; +//////////////////////////////////////////////////////////////////////// + +int iSpuAsyncWait=0; +extern int MMIXC0, MMIXC1; + +VOID CALLBACK MAINProc(UINT nTimerId,UINT msg,DWORD dwUser,DWORD dwParam1, DWORD dwParam2) +{ + int s_1,s_2,fa,ns; + int core = 0; + unsigned char * start; + unsigned int nSample; + int d; + int ch,predict_nr,shift_factor,flags,s; + int gpos,bIRQReturn=0; + + while(!bEndThread) // until we are shutting down + { + //--------------------------------------------------// + // ok, at the beginning we are looking if there is + // enuff free place in the dsound/oss buffer to + // fill in new data, or if there is a new channel to start. + // if not, we wait (thread) or return (timer/spuasync) + // until enuff free place is available/a new channel gets + // started + if (aSyncMode==1) // Async supported? and enabled? + { + if (aSyncCounter<=737280) // If we have 10ms in the buffer, don't wait + { + if (aSyncWait<1000) Sleep(aSyncWait); // Wait a little to be more Synced (No more than 1 sec) + else Sleep (1000); + } + + while (aSyncCounter<=368640 && !bEndThread && aSyncMode==1) + Sleep (1); // bEndThread/aSyncMode are needed, to avoid close problems + + aSyncCounter -= 36864; // 1ms more done (48Hz*768cycles/Hz) + } + else + if(dwNewChannel2[0] || dwNewChannel2[1]) // new channel should start immedately? + { // (at least one bit 0 ... MAXCHANNEL is set?) + iSecureStart++; // -> set iSecure + if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance) + } + else iSecureStart=0; // 0: no new channel should start + + while(!iSecureStart && !bEndThread && // no new start? no thread end? + (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? + { + iSecureStart=0; // reset secure + + if(iUseTimer) // no-thread mode? + { + return; // -> and done this time (timer mode 1 or 2) + } + // win thread mode: + Sleep(PAUSE_W); // sleep for x ms (win) + + if(dwNewChannel2[0] || dwNewChannel2[1]) + iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop + } + //--------------------------------------------------// continue from irq handling in timer mode? + + if(lastch>=0) // will be -1 if no continue is pending + { + ch=lastch; ns=lastns; lastch=-1; // -> setup all kind of vars to continue + if( s_chan[ch].iSBPos < 28 ) { + goto GOON; // -> directly jump to the continue point + } + } + + //--------------------------------------------------// + //- main channel loop -// + //--------------------------------------------------// + { + for(ch=0;ch take it and calc steps + s_chan[ch].sinc = s_chan[ch].iRawPitch<<4; + if(!s_chan[ch].sinc) s_chan[ch].sinc=1; + if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag + } + + ns=0; + while(ns=0x10000L) + { + if(s_chan[ch].iSBPos==28) // 28 reached? + { + start=s_chan[ch].pCurr; // set up the current pos + + if (s_chan[ch].bOn==0) goto ENDX; // special "stop" sign + + s_chan[ch].iSBPos=0; + + s_1=s_chan[ch].s_1; + s_2=s_chan[ch].s_2; + + predict_nr = (int)*start; + start++; + flags = (int)*start; + start++; + + shift_factor = predict_nr&0xf; + predict_nr >>= 4; + // -------------------------------------- // + + for (nSample=0;nSample<28;nSample+=2,start++) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + s=((d & 0xf0) << 8); + + s_chan[ch].SB[nSample]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + + s_chan[ch].SB[nSample+1]=fa; + } + + //////////////////////////////////////////// irq check + + if(spuCtrl2[core]&0x40) // some irq active? + { + if(iDebugMode==1) logprintf("IRQ Active ch %x, C%x\r\n", ch, ch/24); + + if((pSpuIrq[core] >= start-16 && // irq address reached? + pSpuIrq[core] <= start) || + ((flags&1) && // special: irq on looping addr, when stop/loop flag is set + (pSpuIrq[core] >= s_chan[ch].pLoop-16 && + pSpuIrq[core] <= s_chan[ch].pLoop))) + { + s_chan[ch].iIrqDone=1; // -> debug flag + + if(iDebugMode==1) logprintf("Sample End ch %x, C%x\r\n", ch, ch/24); + + regArea[0x7C0] |= 0x4< let's see what is happening if we call our irqs instead ;) + + if(iSPUIRQWait) // -> option: wait after irq for main emu + { + iSpuAsyncWait=1; + bIRQReturn=1; + } + } + } + + //////////////////////////////////////////// flag handler + if(flags & 0x2) s_chan[ch].bIgnoreLoop=1; // LOOP bit + + if(flags&0x4) s_chan[ch].pLoop=start-16; // LOOP/START bit + + if(flags&0x1) // 1: LOOP/END bit + { + dwEndChannel2[core]|=(1<<(ch%24)); + + if((flags&0xF) != 0x3) // Check if no loop is present + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bStop = 1; + logprintf("Stopping\r\n"); + } + else start = s_chan[ch].pLoop; + } + + s_chan[ch].pCurr=start; // store values for next cycle + s_chan[ch].s_1=s_1; + s_chan[ch].s_2=s_2; + + + //////////////////////////////////////////// + + if(bIRQReturn) // special return for "spu irq - wait for cpu action" + { + bIRQReturn=0; + if(iUseTimer!=2) + { + DWORD dwWatchTime=timeGetTime()+2500; + + while(iSpuAsyncWait && !bEndThread && + timeGetTime()32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + } + + if(iUseInterpolation>=2) // gauss/cubic interpolation + { + gpos = s_chan[ch].SB[28]; + gval0 = fa; + gpos = (gpos+1) & 3; + s_chan[ch].SB[28] = gpos; + } + else + if(iUseInterpolation==1) // simple interpolation + { + s_chan[ch].SB[28] = 0; + s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' + s_chan[ch].SB[30] = s_chan[ch].SB[31]; + s_chan[ch].SB[31] = fa; + s_chan[ch].SB[32] = 1; // -> flag: calc new interolation + } + else s_chan[ch].SB[29]=fa; // no interpolation + + s_chan[ch].spos -= 0x10000L; + } + + //////////////////////////////////////////////// + // noise handler... just produces some noise data + // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... + // and sometimes the noise will be used as fmod modulation... pfff + + if(s_chan[ch].bNoise) + { + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[core]&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + s_chan[ch].iOldNoise=fa; + + if(iUseInterpolation<2) // no gauss/cubic interpolation? + s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot + } //---------------------------------------- + else // NO NOISE (NORMAL SAMPLE DATA) HERE + {//------------------------------------------// + if(iUseInterpolation==3) // cubic interpolation + { + long xd; + xd = ((s_chan[ch].spos) >> 1)+1; + gpos = s_chan[ch].SB[28]; + + fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; + fa *= (xd - (2<<15)) / 6; + fa >>= 15; + fa += gval(2) - gval(1) - gval(1) + gval0; + fa *= (xd - (1<<15)) >> 1; + fa >>= 15; + fa += gval(1) - gval0; + fa *= xd; + fa >>= 15; + fa = fa + gval0; + } + //------------------------------------------// + else + if(iUseInterpolation==2) // gauss interpolation + { + int vl, vr; + vl = (s_chan[ch].spos >> 6) & ~3; + gpos = s_chan[ch].SB[28]; + vr=(gauss[vl]*gval0)&~2047; + vr+=(gauss[vl+1]*gval(1))&~2047; + vr+=(gauss[vl+2]*gval(2))&~2047; + vr+=(gauss[vl+3]*gval(3))&~2047; + fa = vr>>11; + } + //------------------------------------------// + else + if(iUseInterpolation==1) // simple interpolation + { + if(s_chan[ch].sinc<0x10000L) // -> upsampling? + InterpolateUp(ch); // --> interpolate up + else InterpolateDown(ch); // --> else down + fa=s_chan[ch].SB[29]; + } + //------------------------------------------// + else fa=s_chan[ch].SB[29]; // no interpolation + } + + s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // add adsr + + if(s_chan[ch].bFMod==2) // fmod freq channel + { + int NP=((32768L+s_chan[ch].sval)*s_chan[ch+1].iRawPitch)>>14; + + if(NP>0x3fff) NP=0x3fff; + else if(NP<0x1) NP=0x1; + + NP=(48000L*NP)>>12; // calc frequency ( 48hz ) + + s_chan[ch+1].iActFreq=NP; + s_chan[ch+1].iUsedFreq=NP; + s_chan[ch+1].sinc=(((NP/10)<<16)/48000); // check , was 4800 + if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; + if(iUseInterpolation==1) // freq change in sipmle interpolation mode + s_chan[ch+1].SB[32]=1; + + } + else + { + ////////////////////////////////////////////// + // ok, left/right sound volume (ps2 volume goes from 0 ... 0x3fff) + + if(s_chan[ch].iMute) s_chan[ch].sval=0; // debug mute + else + { + if(s_chan[ch].bVolumeL) + SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; + + if(s_chan[ch].bVolumeR) + SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; + } + + ////////////////////////////////////////////// + // now let us store sound data for reverb + + if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns); + } + + //////////////////////////////////////////////// + // ok, go on until 1 ms data of this channel is collected + + ns++; + s_chan[ch].spos += s_chan[ch].sinc; + } +ENDX: ; + } + } + + //---------------------------------------------------// + //- here we have another 1 ms of sound data + //---------------------------------------------------// + /////////////////////////////////////////////////////// + // mix all channels (including reverb) into one buffer + for(ns=0;ns>16; + if((regArea[PS2_C1_MMIX] & 0x80)) SSumL[ns] += (DirectInputC1.Left*(int)regArea[PS2_C1_BVOLL])>>16; + + UpdateMainVolL(); + + d=SSumL[ns]/iVolume; + SSumL[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + + SSumR[ns]+=MixREVERBRight(0); + SSumR[ns]+=MixREVERBRight(1); + + if((regArea[PS2_C0_MMIX] & 0x40)) SSumR[ns] += (DirectInputC0.Right*(int)regArea[PS2_C0_BVOLR])>>16; + if((regArea[PS2_C1_MMIX] & 0x40)) SSumR[ns] += (DirectInputC1.Right*(int)regArea[PS2_C1_BVOLR])>>16; + + UpdateMainVolR(); + d=SSumR[ns]/iVolume; + SSumR[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + } + InitREVERB(); + + ////////////////////////////////////////////////////// + // feed the sound + // wanna have around 1/60 sec (16.666 ms) updates + + if(iCycle++>16) + { + SoundFeedVoiceData((unsigned char*)pSpuBuffer, + ((unsigned char *)pS)- + ((unsigned char *)pSpuBuffer)); + pS=(short *)pSpuBuffer; + iCycle=0; + } +} + // end of big main loop... + bThreadEnded=1; + return; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +DWORD WINAPI MAINThreadEx(LPVOID lpParameter) +{ + MAINProc(0,0,0,0,0); + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPU ASYNC... even newer epsxe func +// 1 time every 'cycle' cycles... harhar +//////////////////////////////////////////////////////////////////////// +EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle) +{ + SPUCycles += cycle; + if(interrupt & (1<<2)){ + if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if(interrupt & (1<<1)){ + if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if(iSpuAsyncWait) + { + iSpuAsyncWait++; + if(iSpuAsyncWait<=64) return; + iSpuAsyncWait=0; + } + + if(iDebugMode==2) + { + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0;iDebugMode=0; + } + if(iRecordMode==2) + { + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0;iRecordMode=0; + } + + if(iUseTimer==0) // does the emu support SPUAsync, is it in thread mode, and in Thread Sync ON? + { + aSyncMode=1; // Ten, activate main function Sync system flag + + aSyncTimerOld = aSyncTimerNew; // Recalculate, AsyncWait (ms) + aSyncTimerNew = timeGetTime(); + + aSyncWait =(unsigned int)((aSyncTimerNew - aSyncTimerOld)/2); + + aSyncCounter += cycle ; + + return; + } + if(iUseTimer==2) // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode) + { + aSyncMode = 0; + if(!bSpuInit) return; // -> no init, no call + MAINProc(0,0,0,0,0); // -> experimental win mode... not really tested... don't like the drawbacks + } +} + + +//////////////////////////////////////////////////////////////////////// +// INIT/EXIT STUFF +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUINIT: this func will be called first by the main emu +//////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS +static HINSTANCE hIRE = NULL; +#endif + +EXPORT_GCC long CALLBACK SPU2init(void) +{ + spuMemC=(unsigned char *)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset(rvb,0,2*sizeof(REVERBInfo)); + + InitADSR(); + + if(hIRE==NULL) hIRE=LoadLibrary("Riched32.dll "); // needed for debug output + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SETUPTIMER: init of certain buffers and threads/timers +//////////////////////////////////////////////////////////////////////// + +void SetupTimer(void) +{ + memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers + memset(SSumL,0,NSSIZE*sizeof(int)); + pS=(short *)pSpuBuffer; // setup soundbuffer pointer + pS1=(short *)pSpuStreamBuffer[0]; // setup soundbuffer pointer + + bEndThread=0; // init thread vars + bSpuInit=1; // flag: we are inited + + bSpuInit=1; // flag: we are inited + +#ifdef _WINDOWS + + if(iUseTimer==0) // windows: use thread + { + //_beginthread(MAINThread,0,NULL); + DWORD dw; + hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw); + SetThreadPriority(hMainThread, + //THREAD_PRIORITY_TIME_CRITICAL); + THREAD_PRIORITY_HIGHEST); + } +#endif +} + +//////////////////////////////////////////////////////////////////////// +// REMOVETIMER: kill threads/timers +//////////////////////////////////////////////////////////////////////// + +void RemoveTimer(void) +{ + bEndThread=1; // raise flag to end thread + + if(iUseTimer!=2) // windows thread? + { + while(!bThreadEnded) {Sleep(5L);} // -> wait till thread has ended + Sleep(5L); + } + + bSpuInit=0; + + bThreadEnded=0; // no more spu is running +} + +//////////////////////////////////////////////////////////////////////// +// SETUPSTREAMS: init most of the spu buffers +//////////////////////////////////////////////////////////////////////// + +void SetupStreams(void) +{ + int i; + + pSpuBuffer=(unsigned char *)malloc(38400); // alloc mixing buffer + i=NSSIZE*2; + + sRVBStart[0] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[0],0,i*4); + sRVBEnd[0] = sRVBStart[0] + i; + sRVBPlay[0] = sRVBStart[0]; + sRVBStart[1] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[1],0,i*4); + sRVBEnd[1] = sRVBStart[1] + i; + sRVBPlay[1] = sRVBStart[1]; + + for(i=0;i init sustain + s_chan[i].iMute=0; + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pStart=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pCurr=spuMemC+(s_chan[i].iStartAdr<<1); + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVESTREAMS: free most buffer +//////////////////////////////////////////////////////////////////////// + +void RemoveStreams(void) +{ + free(pSpuBuffer); // free mixing buffer + pSpuBuffer=NULL; + free(sRVBStart[0]); // free reverb buffer + sRVBStart[0]=0; + free(sRVBStart[1]); // free reverb buffer + sRVBStart[1]=0; +} + + +//////////////////////////////////////////////////////////////////////// +// SPUOPEN: called by main emu after init +//////////////////////////////////////////////////////////////////////// +#include +FILE * LogFile; +EXPORT_GCC long CALLBACK SPU2open(void* pWindow) +{ +#ifdef _WINDOWS + HWND hW= pWindow == NULL ? NULL : *(HWND*)pWindow; +#endif + + if(bSPUIsOpen) return 0; // security for some stupid main emus + LogFile = fopen("Logs/spu2.txt","wb"); + iVolume=3; + bEndThread=0; + bThreadEnded=0; + spuMemC=(unsigned char *)spuMem; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + pSpuIrq[0]=spuMemC; + pSpuIrq[1]=spuMemC; + dwNewChannel2[0]=0; + dwNewChannel2[1]=0; + dwEndChannel2[0]=0; + dwEndChannel2[1]=0; + spuCtrl2[0]=0; + spuCtrl2[1]=0; + spuStat2[0]=0; + spuStat2[1]=0; + spuIrq2[0]=0; + spuIrq2[1]=0; + spuAddr2[0]=0x0; + spuAddr2[1]=0x0; + spuRvbAddr2[0]=0; + spuRvbAddr2[1]=0; + spuRvbAEnd2[0]=0; + spuRvbAEnd2[1]=0; + + memset(&Adma4,0,sizeof(ADMA)); + memset(&Adma7,0,sizeof(ADMA)); + + memset(&DirectInputC0,0,sizeof(DINPUT)); + memset(&DirectInputC1,0,sizeof(DINPUT)); + + LastWrite=0x00000000;LastPlay=0; // init some play vars + if(!IsWindow(hW)) hW=GetActiveWindow(); + hWMain = hW; // store hwnd + + ReadConfig(); // read user stuff + + SetupSound(); // setup midas (before init!) + + SetupStreams(); // prepare streaming + + SetupTimer(); // timer for feeding data + + bSPUIsOpen=1; + + if(iDebugMode) // windows debug dialog + { + hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG), + NULL,(DLGPROC)DebugDlgProc); + SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWDebug); + SetFocus(hWMain); + } + + if(iRecordMode) // windows recording dialog + { + hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD), + NULL,(DLGPROC)RecordDlgProc); + SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWRecord); + SetFocus(hWMain); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +// not used yet +#ifndef _WINDOWS +void SPU2setConfigFile(char * pCfg) +{ + pConfigFile=pCfg; +} +#endif + +//////////////////////////////////////////////////////////////////////// +// SPUCLOSE: called before shutdown +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2close(void) +{ + if(!bSPUIsOpen) return; // some security + + bSPUIsOpen=0; // no more open + //fclose(LogFile); +#ifdef _WINDOWS + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0; + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0; +#endif + + RemoveTimer(); // no more feeding + + RemoveSound(); // no more sound handling + + RemoveStreams(); // no more streaming +} + +//////////////////////////////////////////////////////////////////////// +// SPUSHUTDOWN: called by main emu on final exit +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2shutdown(void) +{ +#ifdef _WINDOWS + if(hIRE!=NULL) {FreeLibrary(hIRE);hIRE=NULL;} +#endif + + return; +} + +//////////////////////////////////////////////////////////////////////// +// SPUTEST: we don't test, we are always fine ;) +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK SPU2test(void) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPUCONFIGURE: call config dialog +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2configure(void) +{ +#ifdef _WINDOWS + DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG), + GetActiveWindow(),(DLGPROC)DSoundDlgProc); +#else + StartCfgTool("CFG"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SPUABOUT: show about window +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2about(void) +{ +#ifdef _WINDOWS + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +#else + StartCfgTool("ABOUT"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SETUP CALLBACKS +// this functions will be called once, +// passes a callback that should be called on SPU-IRQ/cdda volume change +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *SPU2callback)(int), + void (CALLBACK *DMA4callback)(int), + void (CALLBACK *DMA7callback)(int)) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +//////////////////////////////////////////////////////////////////////// +// COMMON PLUGIN INFO FUNCS +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC char * CALLBACK PS2EgetLibName(void) +{ + return libraryName; +} + +#define PS2E_LT_SPU2 0x4 + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(void) +{ + return PS2E_LT_SPU2; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + unsigned char v=version; + + // key hack to fake a lower version: + //if(GetAsyncKeyState(VK_SHIFT)&0x8000) v--; + + // compile hack to set lib version to PCSX2 0.6 standards + //v=2; + + return v<<16|revision<<8|build; +} + +//////////////////////////////////////////////////////////////////////// + diff --git a/plugins/spu2/PeopsSPU2/stdafx.c b/plugins/spu2/PeopsSPU2/stdafx.c new file mode 100644 index 0000000000..58a16807c0 --- /dev/null +++ b/plugins/spu2/PeopsSPU2/stdafx.c @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// spuPeopsSound.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/spu2/PeopsSPU2/stdafx.h b/plugins/spu2/PeopsSPU2/stdafx.h new file mode 100644 index 0000000000..c6c643857a --- /dev/null +++ b/plugins/spu2/PeopsSPU2/stdafx.h @@ -0,0 +1,86 @@ +/*************************************************************************** + StdAfx.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +////////////////////////////////////////////////////////// +// WINDOWS +////////////////////////////////////////////////////////// + +#ifdef _WINDOWS + +#ifdef _GCC +#define EXPORT_GCC __declspec (dllexport) +#else +#define EXPORT_GCC +#endif + +#define WIN32_LEAN_AND_MEAN +#define STRICT +#include +#include +#include "mmsystem.h" +#include +#include + +// enable that for auxprintf(); +//#define SMALLDEBUG +//#include +//void auxprintf (LPCTSTR pFormat, ...); + +#define INLINE __inline + +////////////////////////////////////////////////////////// +// LINUX +////////////////////////////////////////////////////////// +#else + +#define EXPORT_GCC + +#include +#include +#include +#include +#include +#include +#include +#ifndef NOTHREADLIB +#include +#endif +#define RRand(range) (random()%range) +#include +#include +#include + +#undef CALLBACK +#define CALLBACK +#define DWORD unsigned long +#define LOWORD(l) ((unsigned short)(l)) +#define HIWORD(l) ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF)) + +#define INLINE inline + +#endif + +#include "psemuxa.h" diff --git a/plugins/spu2/PeopsSPU2/xa.c b/plugins/spu2/PeopsSPU2/xa.c new file mode 100644 index 0000000000..fb63ad407f --- /dev/null +++ b/plugins/spu2/PeopsSPU2/xa.c @@ -0,0 +1,363 @@ +/*************************************************************************** + xa.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/02/18 - kode54 +// - added gaussian interpolation +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_XA + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// XA GLOBALS +//////////////////////////////////////////////////////////////////////// + +xa_decode_t * xapGlobal=0; + +unsigned long * XAFeed = NULL; +unsigned long * XAPlay = NULL; +unsigned long * XAStart = NULL; +unsigned long * XAEnd = NULL; + +unsigned long XARepeat = 0; +unsigned long XALastVal = 0; + +int iLeftXAVol = 32767; +int iRightXAVol = 32767; + +static int gauss_ptr = 0; +static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + +#define gvall0 gauss_window[gauss_ptr] +#define gvall(x) gauss_window[(gauss_ptr+x)&3] +#define gvalr0 gauss_window[4+gauss_ptr] +#define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)] + +//////////////////////////////////////////////////////////////////////// +// MIX XA +//////////////////////////////////////////////////////////////////////// + +INLINE void MixXA(void) +{ + int ns; + + for(ns=0;ns>16)&0xffff)) * iRightXAVol)/32767; + } + + if(XAPlay==XAFeed && XARepeat) + { + XARepeat--; + for(;ns>16)&0xffff)) * iRightXAVol)/32767; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// FEED XA +//////////////////////////////////////////////////////////////////////// + +INLINE void FeedXA(xa_decode_t *xap) +{ + int sinc,spos,i,iSize,iPlace,vl,vr; + + if(!bSPUIsOpen) return; + + xapGlobal = xap; // store info for save states + XARepeat = 100; // set up repeat + + iSize=((44100*xap->nsamples)/xap->freq); // get size + if(!iSize) return; // none? bye + + if(XAFeed=10) + { + if(!dwFPS) dwFPS=1; + dw1=1000000/dwFPS; + if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1; + else dwL1=dw1; + dw2=(xap->freq*100/xap->nsamples); + if((!dw1)||((dw2+100)>=dw1)) iLastSize=0; + else + { + iLastSize=iSize*dw2/dw1; + if(iLastSize>iPlace) iLastSize=iPlace; + iSize=iLastSize; + } + iFPSCnt=0;dwFPS=0; + } + else + { + if(iLastSize) iSize=iLastSize; + } + } + //----------------------------------------------------// + + spos=0x10000L; + sinc = (xap->nsamples << 16) / iSize; // calc freq by num / size + + if(xap->stereo) + { + unsigned long * pS=(unsigned long *)xap->pcm; + unsigned long l=0; + + if(iXAPitch) + { + long l1,l2;short s; + for(i=0;i=0x10000L) + { + l = *pS++; + gauss_window[gauss_ptr] = (short)LOWORD(l); + gauss_window[4+gauss_ptr] = (short)HIWORD(l); + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l= (vr >> 11) & 0xffff; + vr=(gauss[vl]*gvalr0)&~2047; + vr+=(gauss[vl+1]*gvalr(1))&~2047; + vr+=(gauss[vl+2]*gvalr(2))&~2047; + vr+=(gauss[vl+3]*gvalr(3))&~2047; + l |= vr << 5; + } + else + { + while(spos>=0x10000L) + { + l = *pS++; + spos -= 0x10000L; + } + } + + s=(short)LOWORD(l); + l1=s; + l1=(l1*iPlace)/iSize; + if(l1<-32767) l1=-32767; + if(l1> 32767) l1=32767; + s=(short)HIWORD(l); + l2=s; + l2=(l2*iPlace)/iSize; + if(l2<-32767) l2=-32767; + if(l2> 32767) l2=32767; + l=(l1&0xffff)|(l2<<16); + + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + else + { + for(i=0;i=0x10000L) + { + l = *pS++; + gauss_window[gauss_ptr] = (short)LOWORD(l); + gauss_window[4+gauss_ptr] = (short)HIWORD(l); + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l= (vr >> 11) & 0xffff; + vr=(gauss[vl]*gvalr0)&~2047; + vr+=(gauss[vl+1]*gvalr(1))&~2047; + vr+=(gauss[vl+2]*gvalr(2))&~2047; + vr+=(gauss[vl+3]*gvalr(3))&~2047; + l |= vr << 5; + } + else + { + while(spos>=0x10000L) + { + l = *pS++; + spos -= 0x10000L; + } + } + + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + } + else + { + unsigned short * pS=(unsigned short *)xap->pcm; + unsigned long l;short s=0; + + if(iXAPitch) + { + long l1; + for(i=0;i=0x10000L) + { + gauss_window[gauss_ptr] = (short)*pS++; + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l1=s= vr >> 11; + l1 &= 0xffff; + } + else + { + while(spos>=0x10000L) + { + s = *pS++; + spos -= 0x10000L; + } + l1=s; + } + + l1=(l1*iPlace)/iSize; + if(l1<-32767) l1=-32767; + if(l1> 32767) l1=32767; + l=(l1&0xffff)|(l1<<16); + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + else + { + for(i=0;i=0x10000L) + { + gauss_window[gauss_ptr] = (short)*pS++; + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l=s= vr >> 11; + l &= 0xffff; + } + else + { + while(spos>=0x10000L) + { + s = *pS++; + spos -= 0x10000L; + } + l=s; + } + + *XAFeed++=(l|(l<<16)); + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + } +} + +#endif + diff --git a/plugins/spu2/PeopsSPU2/xa.h b/plugins/spu2/PeopsSPU2/xa.h new file mode 100644 index 0000000000..0430552aad --- /dev/null +++ b/plugins/spu2/PeopsSPU2/xa.h @@ -0,0 +1,29 @@ +/*************************************************************************** + xa.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +INLINE void MixXA(void); +INLINE void FeedXA(xa_decode_t *xap); diff --git a/plugins/spu2/SPU2null/License.txt b/plugins/spu2/SPU2null/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/spu2/SPU2null/License.txt @@ -0,0 +1,342 @@ + 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/plugins/spu2/SPU2null/ReadMe.txt b/plugins/spu2/SPU2null/ReadMe.txt new file mode 100644 index 0000000000..05077648bf --- /dev/null +++ b/plugins/spu2/SPU2null/ReadMe.txt @@ -0,0 +1,39 @@ +SPU2null v0.4 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "SPU2null.dll" (Windows) or "libSPU2null.so" (Linux) + at the Plugins directory of the Emulator to use it. + +Changes: +------- + v0.5 + * added debug logging dialog + about dialog + * linuz did some reg fixes + * Added DEVC++ (4.9.9.2) project files for compiling with mingw32 + v0.4 + * added vsnet2005beta1 project files. 64bit dll should work fine now (not tested!) + * Fixed one more bug in regs stuff + + v0.21 + * more work on regs + + v0.2: + * New functions & regs + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + linuzappz + shadow + + diff --git a/plugins/spu2/SPU2null/Src/Changelog.txt b/plugins/spu2/SPU2null/Src/Changelog.txt new file mode 100644 index 0000000000..6751a30252 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/Changelog.txt @@ -0,0 +1,30 @@ +[ Legend: ] +[ + Added feature ] +[ * Improved/changed feature ] +[ - Bug fixed (we hope) ] +[ ! Attention (Notes) ] + +ChangeLog: + +v0.5 + [+] Added Seperate IRQ Callbacks with AutoDMA check (refraction) + [-] Updated Specs to 0.9 (refraction) + +v0.4 + [+] added vsnet2005beta1 project files. 64bit dll should work fine now (not tested!!) + +v0.2 + +15/06/03 + [*] clear some stuff,made code more readable (shadow) + + +9/06/03 + [+] Added some work on CoRE1_ATTR to get bios work (linuzappz) + +9/06/03 + + [+] Added new SPU2 functions to PS2Edefs.h 0.3.2 version + [+] Added loggin system . IT can be enable in SPU2.H + [*] Update Ps2edefs to 0.3.1 (shadow) + diff --git a/plugins/spu2/SPU2null/Src/Config.cpp b/plugins/spu2/SPU2null/Src/Config.cpp new file mode 100644 index 0000000000..46a55c303a --- /dev/null +++ b/plugins/spu2/SPU2null/Src/Config.cpp @@ -0,0 +1,51 @@ +#include + +#include "SPU2.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\spu2null.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\spu2null.ini"); + fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/spu2/SPU2null/Src/Makefile b/plugins/spu2/SPU2null/Src/Makefile new file mode 100644 index 0000000000..fc6bebeb31 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/Makefile @@ -0,0 +1,25 @@ + +CC = gcc + +PLUGIN = libSPU2null.so +CFLAGS+= -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ +OBJS = SPU2.o +DEPS:= $(OBJS:.o=.d) +LIBS = $(shell pkg-config --libs gtk+-2.0) +CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) + +all: plugin +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +clean: + rm -f ${OBJS} ${DEPS} + +%.o: %.cpp + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +#-include ${DEPS} diff --git a/plugins/spu2/SPU2null/Src/Makefile.mingw b/plugins/spu2/SPU2null/Src/Makefile.mingw new file mode 100644 index 0000000000..bf3cef415a --- /dev/null +++ b/plugins/spu2/SPU2null/Src/Makefile.mingw @@ -0,0 +1,51 @@ +# +# Makefile for MINGW32 +# + + +all: spu2null + +PLUGIN = SPU2null.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwinmm -lgdi32 -lcomdlg32 #-lintl -lwsock32 +RESOBJ = spu2nullrc.o + +OBJS = SPU2.o Config.o Win32.o + + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} + +spu2null: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean spu2null + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: SPU2null.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + + \ No newline at end of file diff --git a/plugins/spu2/SPU2null/Src/PS2Edefs.h b/plugins/spu2/SPU2null/Src/PS2Edefs.h new file mode 100644 index 0000000000..9b5bcfcbeb --- /dev/null +++ b/plugins/spu2/SPU2null/Src/PS2Edefs.h @@ -0,0 +1,812 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/spu2/SPU2null/Src/PS2Etypes.h b/plugins/spu2/SPU2null/Src/PS2Etypes.h new file mode 100644 index 0000000000..34ab5c2c54 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/spu2/SPU2null/Src/SPU2.cpp b/plugins/spu2/SPU2null/Src/SPU2.cpp new file mode 100644 index 0000000000..761d5cd4f1 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2.cpp @@ -0,0 +1,1213 @@ +/* SPU2null + * Copyright (C) 2002-2005 SPU2null 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 "SPU2.h" + +#include +#include + +const unsigned char version = PS2E_SPU2_VERSION; +const unsigned char revision = 0; +const unsigned char build = 7; // increase that with each version +const unsigned int minor = 1; // increase that with each version + +// ADSR constants +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +#ifdef _DEBUG +static char *libraryName = "SPU2null (Debug)"; +#else +static char *libraryName = "SPU2null "; +#endif + +FILE *spu2Log; +Config conf; + +ADMA Adma4; +ADMA Adma7; + +u32 MemAddr[2]; +u32 g_nSpuInit = 0; +unsigned short interrupt = 0; +s8 *spu2regs = NULL; +u16* spu2mem = NULL; +u16* pSpuIrq[2] = {NULL}; +u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended +unsigned long dwNoiseVal=1; // global noise generator + +int SPUCycles = 0, SPUWorkerCycles = 0; +int SPUStartCycle[2]; +int SPUTargetCycle[2]; + +int ADMAS4Write(); +int ADMAS7Write(); + +void InitADSR(); + +void (*irqCallbackSPU2)(); // func of main emu, called on spu irq +void (*irqCallbackDMA4)()=0; // func of main emu, called on spu irq +void (*irqCallbackDMA7)()=0; // func of main emu, called on spu irq + +const int f[5][2] = { { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; + +u32 RateTable[160]; + +// channels and voices +VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_SPU2; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16)|(revision<<8)|build|(minor<<24); +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || spu2Log == NULL) return; + + va_start(list, fmt); + vfprintf(spu2Log, fmt, list); + va_end(list); +} + +s32 CALLBACK SPU2init() { +#ifdef SPU2_LOG + spu2Log = fopen("logs/spu2.txt", "w"); + if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); + SPU2_LOG("Spu2 null version %d,%d\n",revision,build); + SPU2_LOG("SPU2init\n"); +#endif + spu2regs = (s8*)malloc(0x10000); + if (spu2regs == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + memset(spu2regs, 0, 0x10000); + + spu2mem = (u16*)malloc(0x200000); // 2Mb + if (spu2mem == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + memset(spu2mem, 0, 0x200000); + memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); + + InitADSR(); + + memset(voices, 0, sizeof(voices)); + // last 24 channels have higher mem offset + for(int i = 0; i < 24; ++i) + voices[i+24].memoffset = 0x400; + + // init each channel + for(u32 i = 0; i < ARRAYSIZE(voices); ++i) { + + voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; + + voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); + voices[i].ADSRX.SustainLevel = 1024; // -> init sustain + } + + return 0; +} + +s32 CALLBACK SPU2open(void *pDsp) { + LoadConfig(); + SPUCycles = SPUWorkerCycles = 0; + interrupt = 0; + SPUStartCycle[0] = SPUStartCycle[1] = 0; + SPUTargetCycle[0] = SPUTargetCycle[1] = 0; + g_nSpuInit = 1; + return 0; +} + +void CALLBACK SPU2close() { + g_nSpuInit = 0; +} + +void CALLBACK SPU2shutdown() { + free(spu2regs); spu2regs = NULL; + free(spu2mem); spu2mem = NULL; +#ifdef SPU2_LOG + if (spu2Log) fclose(spu2Log); +#endif +} + +// simulate SPU2 for 1ms +void SPU2Worker(); + +#define CYCLES_PER_MS (36864000/1000) + +void CALLBACK SPU2async(u32 cycle) +{ + SPUCycles += cycle; + if(interrupt & (1<<2)){ + if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if(interrupt & (1<<1)){ + if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if( g_nSpuInit ) { + + while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) { + SPU2Worker(); + SPUWorkerCycles += CYCLES_PER_MS; + } + } +} + +void InitADSR() // INIT ADSR +{ + unsigned long r,rs,rd; + int i; + memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++;if(rd==5) {rd=1;rs*=2;} + } + if(r>0x3FFFFFFF) r=0x3FFFFFFF; + + RateTable[i]=r; + } +} + +int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR +{ + if(pvoice->bStop) // should be stopped: + { + if(pvoice->bIgnoreLoop==0){ + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop=true; + pvoice->bIgnoreLoop=false; + return 0; + } + if(pvoice->ADSRX.ReleaseModeExp)// do release + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop=true; + pvoice->bIgnoreLoop=false; + //pvoice->bReverb=0; + //pvoice->bNoise=0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + else // not stopped yet? + { + if(pvoice->ADSRX.State==0) // -> attack + { + if(pvoice->ADSRX.AttackModeExp) + { + if(pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + pvoice->ADSRX.State=1; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if(pvoice->ADSRX.State==1) // -> decay + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; + } + + if(pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + if(((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) + { + pvoice->ADSRX.State=2; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if(pvoice->ADSRX.State==2) // -> sustain + { + if(pvoice->ADSRX.SustainIncrease) + { + if(pvoice->ADSRX.SustainModeExp) + { + if(pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + } + } + else + { + if(pvoice->ADSRX.SustainModeExp) + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x0F + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0; + } + } + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + } + return 0; +} + +// simulate SPU2 for 1ms +void SPU2Worker() +{ + u8* start; + int ch,flags; + + VOICE_PROCESSED* pChannel=voices; + for(ch=0;chbNew) { + pChannel->StartSound(); // start new sound + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + } + + if(!pChannel->bOn) + { + // fill buffer with empty data + continue; + } + + if(pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? + pChannel->VoiceChangeFrequency(); + + // loop until 1 ms of data is reached + int ns = 0; + while(nsspos >= 0x10000 ) + { + if(pChannel->iSBPos==28) // 28 reached? + { + start=pChannel->pCurr; // set up the current pos + + // special "stop" sign + if( start == (u8*)-1 ) //!pChannel->bOn + { + pChannel->bOn=false; // -> turn everything off + pChannel->ADSRX.lVolume=0; + pChannel->ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + pChannel->iSBPos=0; + + // decode the 16 byte packet + + flags=(int)start[1]; + start += 16; + + // some callback and irq active? + if(pChannel->GetCtrl()->irq) { + // if irq address reached or irq on looping addr, when stop/loop flag is set + u8* pirq = (u8*)pSpuIrq[ch>=24]; + if( (pirq > start-16 && pirq <= start) + || ((flags&1) && (pirq > pChannel->pLoop-16 && pirq <= pChannel->pLoop))) + { + IRQINFO |= 4<<(int)(ch>=24); + irqCallbackSPU2(); + } + } + + // flag handler + if((flags&4) && (!pChannel->bIgnoreLoop)) + pChannel->pLoop=start-16; // loop adress + + if(flags&1) // 1: stop/loop + { + // We play this block out first... + dwEndChannel2[ch/24]|=(1<<(ch%24)); + //if(!(flags&2)) // 1+2: do loop... otherwise: stop + if(flags!=3 || pChannel->pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + pChannel->bStop = true; + pChannel->bIgnoreLoop = false; + } + else + { + start = pChannel->pLoop; + } + } + + pChannel->pCurr=start; // store values for next cycle + } + + pChannel->iSBPos++; // get sample data + pChannel->spos -= 0x10000; + } + + MixADSR(pChannel); + + // go to the next packet + ns++; + pChannel->spos += pChannel->sinc; + } +ENDX: + ; + } + + // mix all channels + if( (spu2Ru16(REG_C0_MMIX) & 0xC0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) && !(spu2Ru16(REG_C0_CTRL) & 0x30)) { + for(int ns=0;ns0x0fffff) // wrap at 2Mb + spuaddr=0; // wrap + } + + spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C0_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C0_SPUSTAT) &=~0x80; // DMA complete + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = size; + interrupt |= (1<<1); +} + +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr = C1_SPUADDR; + int i; + +#ifdef SPU2_LOG + SPU2_LOG("SPU2 readDMA7Mem size %x, addr: %x\n", size, pMem); +#endif + + for(i=0;i0x0fffff) // wrap at 2Mb + spuaddr=0; // wrap + } + + spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C1_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; // DMA complete + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = size; + interrupt |= (1<<2); +} + +// WRITE + +// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory +// Left and Right channels are always interleaved together in the transfer so +// the AutoDMA's deinterleaves them and transfers them. An interrupt is +// generated when half of the buffer (256 short-words for left and 256 +// short-words for right ) has been transferred. Another interrupt occurs at +// the end of the transfer. +int ADMAS4Write() +{ + u32 spuaddr; + if(interrupt & 0x2) return 0; + if(Adma4.AmountLeft <= 0) return 1; + + spuaddr = C0_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2000),(short*)Adma4.MemAddr,512); + Adma4.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2200),(short*)Adma4.MemAddr,512); + Adma4.MemAddr += 256; + spuaddr = (spuaddr + 256) & 511; + C0_SPUADDR_SET(spuaddr); + + Adma4.AmountLeft-=512; + if(Adma4.AmountLeft == 0) + { + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = 1;//512*48000; + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + interrupt |= (1<<1); + } + return 0; +} + +int ADMAS7Write() +{ + u32 spuaddr; + if(interrupt & 0x4) return 0; + if(Adma7.AmountLeft <= 0) return 1; + + spuaddr = C1_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2400),(short*)Adma7.MemAddr,512); + Adma7.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2600),(short*)Adma7.MemAddr,512); + Adma7.MemAddr += 256; + spuaddr = (spuaddr + 256) & 511; + C1_SPUADDR_SET(spuaddr); + + Adma7.AmountLeft-=512; + if(Adma7.AmountLeft == 0) + { + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = 1;//512*48000; + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + interrupt |= (1<<2); + } + return 0; +} + +void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) +{ + u32 spuaddr; + +#ifdef SPU2_LOG + SPU2_LOG("SPU2 writeDMA4Mem size %x, addr: %x\n", size, pMem); +#endif + if((spu2Ru16(REG_C0_ADMAS) & 0x1) && (spu2Ru16(REG_C0_CTRL) & 0x30) == 0 && size) + { + //fwrite(pMem,iSize<<1,1,LogFile); + memset(&Adma4,0,sizeof(ADMA)); + C0_SPUADDR_SET(0); + Adma4.MemAddr = pMem; + Adma4.AmountLeft = size; + ADMAS4Write(); + return; + } + + spuaddr = C0_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); + spuaddr += size; + C0_SPUADDR_SET(spuaddr); + + if( (spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr){ + spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + + MemAddr[0] += size<<1; + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = 1;//iSize; + interrupt |= (1<<1); +} + +void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr; + +#ifdef SPU2_LOG + SPU2_LOG("SPU2 writeDMA7Mem size %x, addr: %x\n", size, pMem); +#endif + if((spu2Ru16(REG_C1_ADMAS) & 0x2) && (spu2Ru16(REG_C1_CTRL) & 0x30) == 0 && size) + { + //fwrite(pMem,iSize<<1,1,LogFile); + memset(&Adma7,0,sizeof(ADMA)); + C1_SPUADDR_SET(0); + Adma7.MemAddr = pMem; + Adma7.AmountLeft = size; + ADMAS7Write(); + return; + } + + spuaddr = C1_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); + spuaddr += size; + C1_SPUADDR_SET(spuaddr); + + if( (spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr){ + spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + + MemAddr[1] += size<<1; + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = 1;//iSize; + interrupt |= (1<<2); +} + +void CALLBACK SPU2interruptDMA4() +{ +#ifdef SPU2_LOG + SPU2_LOG("SPU2 interruptDMA4\n"); +#endif +// spu2Rs16(REG_C0_CTRL)&= ~0x30; +// spu2Rs16(REG__1B0) = 0; +// spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80; + spu2Rs16(REG_C0_CTRL)&=~0x30; + spu2Ru16(REG_C0_SPUSTAT)|=0x80; +} + +void CALLBACK SPU2interruptDMA7() +{ +#ifdef SPU2_LOG + SPU2_LOG("SPU2 interruptDMA7\n"); +#endif +// spu2Rs16(REG_C1_CTRL)&= ~0x30; +// //spu2Rs16(REG__5B0) = 0; +// spu2Rs16(SPU2_STATX_DREQ)|= 0x80; + spu2Rs16(REG_C1_CTRL)&=~0x30; + spu2Ru16(REG_C1_SPUSTAT)|=0x80; +} + +// turn channels on +void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND +{ + for(int ch=start;ch>=1) // loop channels + { + if((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! + { + voices[ch].bNew=true; + voices[ch].bIgnoreLoop = false; + } + } +} + +// turn channels off +void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND +{ + for(int ch=start;ch>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + voices[ch].bStop=true; + } +} + +void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) { + } + } + else { + // turn fmod off + } + } +} + +void CALLBACK SPU2write(u32 mem, u16 value) +{ + u32 spuaddr; +#ifdef SPU2_LOG + SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); +#endif + + assert( C0_SPUADDR < 0x100000); + assert( C1_SPUADDR < 0x100000); + + spu2Ru16(mem) = value; + u32 r = mem&0xffff; + + // channel info + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int ch=0; + if(r>=0x400) ch=((r-0x400)>>4)+24; + else ch=(r>>4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r&0x0f) + { + case 0: + case 2: + pvoice->SetVolume(mem&0x2); + break; + case 4: + { + int NP; + if(value>0x3fff) NP=0x3fff; // get pitch val + else NP=value; + + pvoice->pvoice->pitch = NP; + + NP=(44100L*NP)/4096L; // calc frequency + if(NP<1) NP=1; // some security + pvoice->iActFreq=NP; // store frequency + break; + } + case 6: + { + pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; + pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); + pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); + pvoice->ADSRX.SustainLevel = (value & 0x000f); + break; + } + case 8: + pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; + pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; + pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); + pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; + pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); + break; + } + + return; + } + + // more channel info + if((r>=0x01c0 && r<=0x02E0)||(r>=0x05c0 && r<=0x06E0)) + { + int ch=0; + unsigned long rx=r; + if(rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) + { + case 0x1C0: + pvoice->iStartAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C2: + pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C4: + pvoice->iLoopAddr =(((unsigned long)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C6: + pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C8: + // unused... check if it gets written as well + pvoice->iNextAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); + break; + case 0x1CA: + // unused... check if it gets written as well + pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); + break; + } + + return; + } + + // process non-channel data + switch(mem&0xffff) { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if( (spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr){ + spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + spu2Ru16(REG_C0_CTRL)&=~0x30; + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if( (spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr){ + spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + spu2Ru16(REG_C1_CTRL)&=~0x30; + break; + case REG_C0_IRQA_HI: + case REG_C0_IRQA_LO: + pSpuIrq[0]=spu2mem+(C0_IRQA<<1); + break; + case REG_C1_IRQA_HI: + case REG_C1_IRQA_LO: + pSpuIrq[1]=spu2mem+(C1_IRQA<<1); + break; + + case REG_C0_SPUADDR_HI: + case REG_C1_SPUADDR_HI: + spu2Ru16(mem) = value&0xf; + break; + + case REG_C0_SPUON1: SoundOn(0,16,value); break; + case REG_C0_SPUON2: SoundOn(16,24,value); break; + case REG_C1_SPUON1: SoundOn(24,40,value); break; + case REG_C1_SPUON2: SoundOn(40,48,value); break; + case REG_C0_SPUOFF1: SoundOff(0,16,value); break; + case REG_C0_SPUOFF2: SoundOff(16,24,value); break; + case REG_C1_SPUOFF1: SoundOff(24,40,value); break; + case REG_C1_SPUOFF2: SoundOff(40,48,value); break; + + // According to manual all bits are cleared by writing an arbitary value + case REG_C0_END1: dwEndChannel2[0] = 0; break; + case REG_C0_END2: dwEndChannel2[0] = 0; break; + case REG_C1_END1: dwEndChannel2[1] = 0; break; + case REG_C1_END2: dwEndChannel2[1] = 0; break; + case REG_C0_FMOD1: FModOn(0,16,value); break; + case REG_C0_FMOD2: FModOn(16,24,value); break; + case REG_C1_FMOD1: FModOn(24,40,value); break; + case REG_C1_FMOD2: FModOn(40,48,value); break; + } + + assert( C0_SPUADDR < 0x100000); + assert( C1_SPUADDR < 0x100000); +} + +u16 CALLBACK SPU2read(u32 mem) +{ + u32 spuaddr; + u16 ret; + u32 r = mem&0xffff; + + if((r>=0x0000 && r<=0x0180)||(r>=0x0400 && r<=0x0580)) // some channel info? + { + int ch=0; + if(r>=0x400) ch=((r-0x400)>>4)+24; + else ch=(r>>4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r&0x0f) { + case 10: return (unsigned short)(pvoice->ADSRX.EnvelopeVol>>16); + } + } + + if((r>0x01c0 && r<=0x02E0)||(r>0x05c0 && r<=0x06E0)) // some channel info? + { + int ch=0; + unsigned long rx=r; + if(rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) { + case 0x1C0: return (u16)(((pvoice->pStart-(u8*)spu2mem)>>17)&0x3F); + case 0x1C2: return (u16)(((pvoice->pStart-(u8*)spu2mem)>>1)&0xFFFF); + case 0x1C4: return (u16)(((pvoice->pLoop-(u8*)spu2mem)>>17)&0x3F); + case 0x1C6: return (u16)(((pvoice->pLoop-(u8*)spu2mem)>>1)&0xFFFF); + case 0x1C8: return (u16)(((pvoice->pCurr-(u8*)spu2mem)>>17)&0x3F); + case 0x1CA: return (u16)(((pvoice->pCurr-(u8*)spu2mem)>>1)&0xFFFF); + } + } + + switch(mem&0xffff) { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + ret =spu2mem[spuaddr]; + spuaddr++; + if(spuaddr>0xfffff) + spuaddr=0; + C0_SPUADDR_SET(spuaddr); + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + ret = spu2mem[spuaddr]; + spuaddr++; + if(spuaddr>0xfffff) + spuaddr=0; + C1_SPUADDR_SET(spuaddr); + break; + + case REG_C0_END1: return (dwEndChannel2[0]&0xffff); + case REG_C0_END2: return (dwEndChannel2[0]>>16); + case REG_C1_END1: return (dwEndChannel2[1]&0xffff); + case REG_C1_END2: return (dwEndChannel2[1]>>16); + + case REG_IRQINFO: + ret = IRQINFO; + IRQINFO = 0; + break; + default: + ret = spu2Ru16(mem); + } +#ifdef SPU2_LOG + SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); +#endif + + return ret; +} + +void CALLBACK SPU2WriteMemAddr(int core, u32 value) +{ + MemAddr[core] = value; +} + +u32 CALLBACK SPU2ReadMemAddr(int core) +{ + return MemAddr[core]; +} + +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +// VOICE_PROCESSED definitions +SPU_CONTROL_* VOICE_PROCESSED::GetCtrl() +{ + return ((SPU_CONTROL_*)(spu2regs+memoffset+REG_C0_CTRL)); +} + +void VOICE_PROCESSED::SetVolume(int iProcessRight) +{ + u16 vol = iProcessRight ? pvoice->right.word : pvoice->left.word; + + if(vol&0x8000) // sweep not working + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + // set volume + //if( iProcessRight ) right = vol; + //else left = vol; +} + +void VOICE_PROCESSED::StartSound() +{ + ADSRX.lVolume=1; // and init some adsr vars + ADSRX.State=0; + ADSRX.EnvelopeVol=0; + + if(bReverb && GetCtrl()->reverb ) + { + // setup the reverb effects + } + + pCurr=pStart; // set sample start + iSBPos=28; + + bNew=false; // init channel flags + bStop=false; + bOn=true; + spos=0x10000L; +} + +void VOICE_PROCESSED::VoiceChangeFrequency() +{ + iUsedFreq=iActFreq; // -> take it and calc steps + sinc=(u32)pvoice->pitch<<4; + if(!sinc) + sinc=1; +} + +void VOICE_PROCESSED::Stop() +{ +} + +// GUI Routines +s32 CALLBACK SPU2test() { + return 0; +} + +typedef struct { + u32 version; + u8 spu2regs[0x10000]; +} SPU2freezeData; + +s32 CALLBACK SPU2freeze(int mode, freezeData *data){ + SPU2freezeData *spud; + + if (mode == FREEZE_LOAD) { + spud = (SPU2freezeData*)data->data; + if( spud->version == 0x11223344 ) { + memcpy(spu2regs, spud->spu2regs, 0x10000); + } + else printf("SPU2null wrong format\n"); + } else + if (mode == FREEZE_SAVE) { + spud = (SPU2freezeData*)data->data; + spud->version = 0x11223344; + memcpy(spud->spu2regs, spu2regs, 0x10000); + } else + if (mode == FREEZE_SIZE) { + data->size = sizeof(SPU2freezeData); + } + + return 0; +} + +#ifndef _WIN32 + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void CALLBACK SPU2configure() { + SysMessage("Nothing to Configure"); +} + +void CALLBACK SPU2about() { + SysMessage("%s %d.%d", libraryName, version, build); +} + +void LoadConfig() +{ +} + +#endif diff --git a/plugins/spu2/SPU2null/Src/SPU2.h b/plugins/spu2/SPU2null/Src/SPU2.h new file mode 100644 index 0000000000..9ea1180a2e --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2.h @@ -0,0 +1,280 @@ +/* SPU2null + * Copyright (C) 2002-2005 SPU2null 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 + */ + +#ifndef __SPU2_H__ +#define __SPU2_H__ + +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include + +extern "C" { +#define SPU2defs +#include "PS2Edefs.h" +} + +#ifdef __LINUX__ +#include +#else +#include +#include +#endif + +extern FILE *spu2Log; +#define SPU2_LOG __Log //debug mode + + +typedef struct { + int Log; +} Config; + +extern Config conf; + +void __Log(char *fmt, ...); +void SaveConfig(); +void LoadConfig(); +void SysMessage(char *fmt, ...); + +//////////////////// +// SPU2 Registers // +//////////////////// +#define REG_VP_VOLL 0x0000 +#define REG_VP_VOLR 0x0002 +#define REG_VP_PITCH 0x0004 +#define REG_VP_ADSR1 0x0006 +#define REG_VP_ADSR2 0x0008 +#define REG_VP_ENVX 0x000A +#define REG_VP_VOLXL 0x000C +#define REG_VP_VOLXR 0x000E +#define REG_C0_FMOD1 0x0180 +#define REG_C0_FMOD2 0x0182 +#define REG_C1_FMOD1 0x0580 +#define REG_C1_FMOD2 0x0582 +#define REG_S_NON 0x0184 +#define REG_S_VMIXL 0x0188 +#define REG_S_VMIXEL 0x018C +#define REG_S_VMIXR 0x0190 +#define REG_S_VMIXER 0x0194 +#define REG_C0_MMIX 0x0198 +#define REG_C1_MMIX 0x0598 +#define REG_C0_CTRL 0x019A +#define REG_C0_IRQA_HI 0x019C +#define REG_C0_IRQA_LO 0x019D +#define REG_C1_IRQA_HI 0x059C +#define REG_C1_IRQA_LO 0x059D +#define REG_C0_SPUON1 0x1A0 +#define REG_C0_SPUON2 0x1A2 +#define REG_C1_SPUON1 0x5A0 +#define REG_C1_SPUON2 0x5A2 +#define REG_C0_SPUOFF1 0x1A4 +#define REG_C0_SPUOFF2 0x1A6 +#define REG_C1_SPUOFF1 0x5A4 +#define REG_C1_SPUOFF2 0x5A6 +#define REG_C0_SPUADDR_HI 0x01A8 +#define REG_C0_SPUADDR_LO 0x01AA +#define REG_C1_SPUADDR_HI 0x05A8 +#define REG_C1_SPUADDR_LO 0x05AA +#define REG_C0_SPUDATA 0x01AC +#define REG_C1_SPUDATA 0x05AC +#define REG_C0_DMACTRL 0x01AE +#define REG_C1_DMACTRL 0x05AE +#define REG_C0_ADMAS 0x01B0 +#define REG_VA_SSA 0x01C0 +#define REG_VA_LSAX 0x01C4 +#define REG_VA_NAX 0x01C8 +#define REG_A_ESA 0x02E0 +#define REG_A_EEA 0x033C +#define REG_C0_END1 0x0340 +#define REG_C0_END2 0x0342 +#define REG_C1_END1 0x0740 +#define REG_C1_END2 0x0742 +#define REG_C0_SPUSTAT 0x0344 //not sure! +#define REG_C1_CTRL 0x059A +#define REG_C1_ADMAS 0x05B0 +#define REG_C1_SPUSTAT 0x0744 //not sure! +#define REG_P_MVOLL 0x0760 +#define REG_P_MVOLR 0x0762 +#define REG_P_EVOLL 0x0764 +#define REG_P_EVOLR 0x0766 +#define REG_P_AVOLL 0x0768 +#define REG_P_AVOLR 0x076A +#define REG_P_BVOLL 0x076C +#define REG_P_BVOLR 0x076E +#define REG_P_MVOLXL 0x0770 +#define REG_P_MVOLXR 0x0772 +#define SPDIF_OUT 0x07C0 +#define REG_IRQINFO 0x07C2 +#define SPDIF_MODE 0x07C6 +#define SPDIF_MEDIA 0x07C8 + +#define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) +#define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) +//#define spu2Rs32(mem) (*(s32*)&spu2regs[(mem) & 0xffff]) +//#define spu2Ru32(mem) (*(u32*)&spu2regs[(mem) & 0xffff]) + +#define IRQINFO spu2Ru16(REG_IRQINFO) + +#define SPU2_GET32BIT(lo,hi) (((u32)(spu2Ru16(hi)&0x3f)<<16)|(u32)spu2Ru16(lo)) +#define SPU2_SET32BIT(value, lo, hi) { \ + spu2Ru16(hi) = ((value)>>16)&0x3f; \ + spu2Ru16(lo) = (value)&0xffff; \ + } \ + +#define C0_IRQA SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI) +#define C1_IRQA SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI) + +#define C0_SPUADDR SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI) +#define C1_SPUADDR SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI) + +#define C0_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C0_IRQA_LO, REG_C0_IRQA_HI) +#define C1_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C1_IRQA_LO, REG_C1_IRQA_HI) + +#define SPU_NUMBER_VOICES 48 + +struct SPU_CONTROL_ +{ + u16 spuon : 1; + u16 spuUnmute : 1; + u16 noiseFreq : 6; + u16 reverb : 1; + u16 irq : 1; + u16 dma : 2; // 1 - no dma, 2 - write, 3 - read + u16 extr : 1; // external reverb + u16 cdreverb : 1; + u16 extAudio : 1; + u16 extCd : 1; +}; + +// the layout of each voice in wSpuRegs +struct _SPU_VOICE +{ + union + { + struct { + u16 Vol : 14; + u16 Inverted : 1; + u16 Sweep0 : 1; + } vol; + struct { + u16 Vol : 7; + u16 res1 : 5; + u16 Inverted : 1; + u16 Decrease : 1; // if 0, increase + u16 ExpSlope : 1; // if 0, linear slope + u16 Sweep1 : 1; // always one + } sweep; + u16 word; + } left, right; + + u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc + u16 res0 : 2; + + u16 SustainLvl : 4; + u16 DecayRate : 4; + u16 AttackRate : 7; + u16 AttackExp : 1; // if 0, linear + + u16 ReleaseRate : 5; + u16 ReleaseExp : 1; // if 0, linear + u16 SustainRate : 7; + u16 res1 : 1; + u16 SustainDec : 1; // if 0, inc + u16 SustainExp : 1; // if 0, linear + + u16 AdsrVol; + u16 Address; // add / 8 + u16 RepeatAddr; // gets reset when sample starts +}; + +// ADSR INFOS PER CHANNEL +struct ADSRInfoEx +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; +}; + +#define NSSIZE 48 // ~ 1 ms of data +#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting +#define NSPACKETS 4 +#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED)-4*sizeof(void*)) + +struct VOICE_PROCESSED +{ + VOICE_PROCESSED() + { + memset(this, 0, sizeof(VOICE_PROCESSED)); + } + ~VOICE_PROCESSED() + { + } + + void SetVolume(int right); + void StartSound(); + void VoiceChangeFrequency(); + void FModChangeFrequency(int ns); + void Stop(); + + SPU_CONTROL_* GetCtrl(); + + // start save state + + int iSBPos; // mixing stuff + int spos; + int sinc; + + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + + int iStartAddr, iLoopAddr, iNextAddr; + + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged; + int memoffset; // if first core, 0, if second, 0x400 + + // end save state + + /////////////////// + // Sound Buffers // + /////////////////// + u8* pStart; // start and end addresses + u8* pLoop, *pCurr; + + _SPU_VOICE* pvoice; +}; + +struct ADMA +{ + unsigned short * MemAddr; + long IntPointer; + int Index; + int AmountLeft; + int Enabled; +}; + +#endif /* __SPU2_H__ */ diff --git a/plugins/spu2/SPU2null/Src/SPU2null.def b/plugins/spu2/SPU2null/Src/SPU2null.def new file mode 100644 index 0000000000..dd0b459f85 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null.def @@ -0,0 +1,31 @@ +; SPU2null.def : Declares the module parameters for the DLL. + +LIBRARY "SPU2null" +DESCRIPTION 'SPU2 Null Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + SPU2init @5 + SPU2shutdown @6 + SPU2open @7 + SPU2close @8 + SPU2write @9 + SPU2read @10 + SPU2readDMA4Mem @11 + SPU2writeDMA4Mem @12 + SPU2readDMA7Mem @13 + SPU2writeDMA7Mem @14 + SPU2async @15 + SPU2interruptDMA4 @16 + SPU2interruptDMA7 @17 + SPU2freeze @18 + SPU2configure @21 + SPU2test @22 + SPU2about @23 + + SPU2ReadMemAddr @24 + SPU2WriteMemAddr @25 + SPU2irqCallback @26 \ No newline at end of file diff --git a/plugins/spu2/SPU2null/Src/SPU2null.ncb b/plugins/spu2/SPU2null/Src/SPU2null.ncb new file mode 100644 index 0000000000000000000000000000000000000000..ac4d6174ff7ae70305c9cbf87b7b9cef866d78aa GIT binary patch literal 142336 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/SPU2null/Src/SPU2null_2005.sln b/plugins/spu2/SPU2null/Src/SPU2null_2005.sln new file mode 100644 index 0000000000..15d0cf751b --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null_2005.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2null", "SPU2null_2005.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/spu2/SPU2null/Src/SPU2null_2005.vcproj b/plugins/spu2/SPU2null/Src/SPU2null_2005.vcproj new file mode 100644 index 0000000000..e68a2a063c --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null_2005.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.sln b/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.sln new file mode 100644 index 0000000000..0894e2818a --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2null", "SPU2null_2005_x64.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|x64.ActiveCfg = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|x64.Build.0 = Debug|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|x64.ActiveCfg = Release|x64 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.vcproj b/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.vcproj new file mode 100644 index 0000000000..47881a790f --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null_2005_x64.vcproj @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/SPU2null/Src/SPU2null_2008.vcproj b/plugins/spu2/SPU2null/Src/SPU2null_2008.vcproj new file mode 100644 index 0000000000..1a8b6daea3 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/SPU2null_2008.vcproj @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/SPU2null/Src/Win32.cpp b/plugins/spu2/SPU2null/Src/Win32.cpp new file mode 100644 index 0000000000..95f36c4ad0 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/Win32.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "SPU2.h" +#include "resource.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "SPU2NULL Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK SPU2configure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK SPU2about() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/spu2/SPU2null/Src/mingw/Makefile.win b/plugins/spu2/SPU2null/Src/mingw/Makefile.win new file mode 100644 index 0000000000..0b88810012 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/mingw/Makefile.win @@ -0,0 +1,43 @@ +# Project: SPU2null +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//SPU2null_private.res +OBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) +LINKOBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) +LIBS = -L"C:/Develop/Dev-Cpp/lib" --def plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +INCS = -I"C:/Develop/Dev-Cpp/include" +CXXINCS = -I"C:/Develop/Dev-Cpp/include" +BIN = SPU2null.dll +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32___ +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before SPU2null.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libSPU2null.def +STATICLIB=libSPU2null.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Obj//Win32.o: ../Win32.c + $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) + +Obj//Config.o: ../Config.c + $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) + +Obj//SPU2.o: ../SPU2.c + $(CC) -c ../SPU2.c -o Obj//SPU2.o $(CFLAGS) + +Obj//SPU2null_private.res: SPU2null_private.rc ../SPU2null.rc + $(WINDRES) -i SPU2null_private.rc --input-format=rc -o Obj//SPU2null_private.res -O coff --include-dir ../mingw --include-dir ../ diff --git a/plugins/spu2/SPU2null/Src/mingw/SPU2null.dev b/plugins/spu2/SPU2null/Src/mingw/SPU2null.dev new file mode 100644 index 0000000000..2a811e60ac --- /dev/null +++ b/plugins/spu2/SPU2null/Src/mingw/SPU2null.dev @@ -0,0 +1,148 @@ +[Project] +FileName=SPU2null.dev +Name=SPU2null +UnitCount=10 +Type=3 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource=SPU2null_private.rc +ResourceIncludes=..\mingw;../ +MakeIncludes= +Compiler=-Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32____@@_ +CppCompiler= +Linker=--def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput=Obj/ +OverrideOutput=0 +OverrideOutputName=SPU2null.dll +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=afxres.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\Win32.c +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\Config.c +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\PS2Edefs.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\PS2Etypes.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\regs.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\resource.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\SPU2.c +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\SPU2.h +CompileCpp=0 +Folder=SPU2null +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\SPU2null.rc +Folder=SPU2null +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/plugins/spu2/SPU2null/Src/mingw/afxres.h b/plugins/spu2/SPU2null/Src/mingw/afxres.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/spu2/SPU2null/Src/mingw/afxres.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/spu2/SPU2null/Src/mingw/plugin.def b/plugins/spu2/SPU2null/Src/mingw/plugin.def new file mode 100644 index 0000000000..4bf46055f9 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/mingw/plugin.def @@ -0,0 +1,22 @@ +EXPORTS + PS2EgetLibName = PS2EgetLibName@0 @2 + PS2EgetLibType = PS2EgetLibType@0 @3 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @4 + SPU2about = SPU2about@0 @5 + SPU2async = SPU2async@4 @6 + SPU2close = SPU2close@0 @7 + SPU2configure = SPU2configure@0 @8 + SPU2freeze = SPU2freeze@8 @9 + SPU2init = SPU2init@0 @10 + SPU2interruptDMA4 = SPU2interruptDMA4@0 @11 + SPU2interruptDMA7 = SPU2interruptDMA7@0 @12 + SPU2irqCallback = SPU2irqCallback@4 @13 + SPU2open = SPU2open@4 @14 + SPU2read = SPU2read@4 @15 + SPU2readDMA4Mem = SPU2readDMA4Mem@8 @16 + SPU2readDMA7Mem = SPU2readDMA7Mem@8 @17 + SPU2shutdown = SPU2shutdown@0 @18 + SPU2test = SPU2test@0 @19 + SPU2write = SPU2write@8 @20 + SPU2writeDMA4Mem = SPU2writeDMA4Mem@8 @21 + SPU2writeDMA7Mem = SPU2writeDMA7Mem@8 @22 diff --git a/plugins/spu2/SPU2null/Src/resource.h b/plugins/spu2/SPU2null/Src/resource.h new file mode 100644 index 0000000000..150ca1f844 --- /dev/null +++ b/plugins/spu2/SPU2null/Src/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SPU2null.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/spu2/SPU2null/build.sh b/plugins/spu2/SPU2null/build.sh new file mode 100644 index 0000000000..5360bcdfe6 --- /dev/null +++ b/plugins/spu2/SPU2null/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +curdir=`pwd` + +echo ----------------- +echo Building SPU2null +echo ----------------- + +cd ${curdir}/Src +make $@ + +cp libSPU2null.so ${PCSX2PLUGINS} diff --git a/plugins/spu2/build.sh b/plugins/spu2/build.sh new file mode 100644 index 0000000000..ad595f5d11 --- /dev/null +++ b/plugins/spu2/build.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +curdir=`pwd` + +echo ------------------------ +echo Building SPU2 plugins... +echo ------------------------ + +cd ${curdir}/zerospu2 +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/PeopsSPU2 +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +cd ${curdir}/SPU2null +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi \ No newline at end of file diff --git a/plugins/spu2/zerospu2/Linux.cpp b/plugins/spu2/zerospu2/Linux.cpp new file mode 100644 index 0000000000..2e67ebe5ef --- /dev/null +++ b/plugins/spu2/zerospu2/Linux.cpp @@ -0,0 +1,362 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 "zerospu2.h" + +#include +#include + +#include +#include +#include +#include + +#ifdef ZEROSPU2_OSS + +static int oss_audio_fd = -1; +extern int errno; + +#define OSS_MODE_STEREO 1 + +// use OSS for sound +int SetupSound() +{ + int pspeed=48000; + int pstereo; + int format; + int fragsize = 0; + int myfrag; + int oss_speed, oss_stereo; + + pstereo=OSS_MODE_STEREO; + + oss_speed = pspeed; + oss_stereo = pstereo; + + if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) { + printf("Sound device not available!\n"); + return -1; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1) { + printf("Sound reset failed\n"); + return -1; + } + + // we use 64 fragments with 1024 bytes each + fragsize=10; + myfrag=(63<<16)|fragsize; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1) { + printf("Sound set fragment failed!\n"); + return -1; + } + + format = AFMT_S16_LE; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1) { + printf("Sound format not supported!\n"); + return -1; + } + + if(format!=AFMT_S16_LE) { + printf("Sound format not supported!\n"); + return -1; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1) { + printf("Stereo mode not supported!\n"); + return -1; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1) { + printf("Sound frequency not supported\n"); + return -1; + } + + if(oss_speed!=pspeed) { + printf("Sound frequency not supported\n"); + return -1; + } + + return 0; +} + +// REMOVE SOUND +void RemoveSound() +{ + if(oss_audio_fd != -1 ) { + close(oss_audio_fd); + oss_audio_fd = -1; + } +} + +#define SOUNDSIZE 76800 +int SoundGetBytesBuffered() +{ + audio_buf_info info; + unsigned long l; + + if(oss_audio_fd == -1) + return SOUNDSIZE; + if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) + return 0; + else { + // can we write in at least the half of fragments? + if(info.fragments<(info.fragstotal>>1)) + return SOUNDSIZE; + } + + return 0; +} + +// FEED SOUND DATA +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(oss_audio_fd == -1) return; + write(oss_audio_fd,pSound,lBytes); +} + +#else +// ALSA +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API +#include + +#define ALSA_MEM_DEF + +#ifdef ALSA_MEM_DEF +#define ALSA_MEM_EXTERN +#else +#define ALSA_MEM_EXTERN extern +#endif + +static snd_pcm_t *handle = NULL; +static snd_pcm_uframes_t buffer_size; + +#define SOUNDSIZE 500000 + +int SetupSound(void) +{ + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_status_t *status; + unsigned int pspeed; + int pchannels; + snd_pcm_format_t format; + unsigned int buffer_time, period_time; + int err; + + pchannels=2; + + pspeed=48000; + format=SND_PCM_FORMAT_S16_LE; + buffer_time=SOUNDSIZE; + period_time=buffer_time/4; + + if((err=snd_pcm_open(&handle, "default", + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0) { + printf("Audio open error: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_nonblock(handle, 0))<0) { + printf("Can't set blocking moded: %s\n", snd_strerror(err)); + return -1; + } + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + if((err=snd_pcm_hw_params_any(handle, hwparams))<0) { + printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0) { + printf("Access type not available: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0) { + printf("Sample format not available: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0) { + printf("Channels count not available: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0) { + printf("Rate not available: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0) { + printf("Buffer time error: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0) { + printf("Period time error: %s\n", snd_strerror(err)); + return -1; + } + + if((err=snd_pcm_hw_params(handle, hwparams))<0) { + printf("Unable to install hw params: %s\n", snd_strerror(err)); + return -1; + } + + snd_pcm_status_alloca(&status); + if((err=snd_pcm_status(handle, status))<0) { + printf("Unable to get status: %s\n", snd_strerror(err)); + return -1; + } + + buffer_size=snd_pcm_status_get_avail(status); + + return 0; +} + +void RemoveSound() +{ + if(handle != NULL) { + snd_pcm_drop(handle); + snd_pcm_close(handle); + handle = NULL; + } +} + +int SoundGetBytesBuffered() +{ + int l; + + if(handle == NULL) // failed to open? + return SOUNDSIZE; + l = snd_pcm_avail_update(handle); + if(l<0) return 0; + if(l no? wait + else l=0; // -> else go on + + return l; +} + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(handle == NULL) return; + + if(snd_pcm_state(handle) == SND_PCM_STATE_XRUN) + snd_pcm_prepare(handle); + snd_pcm_writei(handle,pSound, lBytes/4); +} + +#endif + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void CALLBACK SPU2configure() { + SysMessage("Nothing to Configure"); +} + +extern char* libraryName; +extern string s_strIniPath; + +void CALLBACK SPU2about() { + SysMessage("%s %d.%d\ndeveloper: zerofrog", libraryName, SPU2_VERSION, SPU2_BUILD); +} + +void SaveConfig() { + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("Failed to open %s\n", s_strIniPath.c_str()); + return; + } + fprintf(f, "log = %d\n", conf.Log); + fprintf(f, "options = %d\n", conf.options); + fclose(f); +} + +void LoadConfig() { + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg, "r"); + if (f == NULL) { + printf("Failed to open %s\n", s_strIniPath.c_str()); + conf.Log = 0;//default value + conf.options = 0;//OPTION_TIMESTRETCH; + SaveConfig();//save and return + return; + } + fscanf(f, "log = %d\n", &conf.Log); + fscanf(f, "options = %d\n", &conf.options); + fclose(f); +} diff --git a/plugins/spu2/zerospu2/Makefile.am b/plugins/spu2/zerospu2/Makefile.am new file mode 100644 index 0000000000..c75066e224 --- /dev/null +++ b/plugins/spu2/zerospu2/Makefile.am @@ -0,0 +1,31 @@ +# Create a shared library libZeroSPU2 +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroSPU2.a + +libZeroSPU2_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroSPU2_a_CFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroSPU2_a_CXXFLAGS += -fPIC +libZeroSPU2_a_CFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + +if DEBUGBUILD +preext=d +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroSPU2 +libZeroSPU2_SOURCES= +libZeroSPU2_DEPENDENCIES = libZeroSPU2.a SoundTouch/libSoundTouch.a +libZeroSPU2_LDFLAGS= @SHARED_LDFLAGS@ +libZeroSPU2_LDFLAGS+=-Wl,-soname,@ZEROSPU2_SONAME@ +libZeroSPU2_LDADD=$(libZeroSPU2_a_OBJECTS) SoundTouch/libSoundTouch.a + +libZeroSPU2_a_SOURCES = zerospu2.cpp Linux.cpp + +SUBDIRS = SoundTouch . \ No newline at end of file diff --git a/plugins/spu2/zerospu2/PS2Edefs.h b/plugins/spu2/zerospu2/PS2Edefs.h new file mode 100644 index 0000000000..223a03410f --- /dev/null +++ b/plugins/spu2/zerospu2/PS2Edefs.h @@ -0,0 +1,855 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBasync USBasync; + +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/spu2/zerospu2/PS2Etypes.h b/plugins/spu2/zerospu2/PS2Etypes.h new file mode 100644 index 0000000000..101dba9491 --- /dev/null +++ b/plugins/spu2/zerospu2/PS2Etypes.h @@ -0,0 +1,88 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifdef _WIN32 +#include +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#define PCSX2_ALIGNED16_DECL(x) x + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/spu2/zerospu2/SoundTouch/3dnow_win.cpp b/plugins/spu2/zerospu2/SoundTouch/3dnow_win.cpp new file mode 100644 index 0000000000..2e369904ec --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/3dnow_win.cpp @@ -0,0 +1,350 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/plugins/spu2/zerospu2/SoundTouch/AAFilter.cpp b/plugins/spu2/zerospu2/SoundTouch/AAFilter.cpp new file mode 100644 index 0000000000..9a5cf539c0 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/AAFilter.cpp @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/plugins/spu2/zerospu2/SoundTouch/AAFilter.h b/plugins/spu2/zerospu2/SoundTouch/AAFilter.h new file mode 100644 index 0000000000..4c85dcdbe7 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/AAFilter.h @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/BPMDetect.h b/plugins/spu2/zerospu2/SoundTouch/BPMDetect.h new file mode 100644 index 0000000000..ac616e7e2b --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/BPMDetect.h @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.cpp b/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.cpp new file mode 100644 index 0000000000..2bf965b763 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.cpp @@ -0,0 +1,252 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.h b/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.h new file mode 100644 index 0000000000..09f74c9a65 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/FIFOSampleBuffer.h @@ -0,0 +1,174 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/FIFOSamplePipe.h b/plugins/spu2/zerospu2/SoundTouch/FIFOSamplePipe.h new file mode 100644 index 0000000000..33e33c7e36 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/FIFOSamplePipe.h @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/FIRFilter.cpp b/plugins/spu2/zerospu2/SoundTouch/FIRFilter.cpp new file mode 100644 index 0000000000..557bd704f6 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/FIRFilter.cpp @@ -0,0 +1,272 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/plugins/spu2/zerospu2/SoundTouch/FIRFilter.h b/plugins/spu2/zerospu2/SoundTouch/FIRFilter.h new file mode 100644 index 0000000000..be5cdd2943 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/FIRFilter.h @@ -0,0 +1,163 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/plugins/spu2/zerospu2/SoundTouch/Makefile.am b/plugins/spu2/zerospu2/SoundTouch/Makefile.am new file mode 100644 index 0000000000..aba43633f6 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to create Makefile.in +## +## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ +## +## Copyright (C) 2003 - David W. Durham +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch 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. +## +## SoundTouch is distributed in the hope that 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 + +AUTOMAKE_OPTIONS = foreign + +noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86_gcc.cpp FIRFilter.h RateTransposer.h TDStretch.h +noinst_LIBRARIES = libSoundTouch.a + +if X86_64 +libSoundTouch_a_CXXFLAGS = -fPIC +libSoundTouch_a_CFLAGS = -fPIC +else +libSoundTouch_a_CXXFLAGS = -msse -mmmx +libSoundTouch_a_CFLAGS = -msse -mmmx +endif + +#lib_LTLIBRARIES=libSoundTouch.la +# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac +libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86_gcc.cpp WavFile.cpp + +# ??? test for -fcheck-new in configure.ac +# other compiler flags to add +AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include + +# other linking flags to add +#libSoundTouch_la_LIBADD= + diff --git a/plugins/spu2/zerospu2/SoundTouch/RateTransposer.cpp b/plugins/spu2/zerospu2/SoundTouch/RateTransposer.cpp new file mode 100644 index 0000000000..b7414b90a6 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/RateTransposer.cpp @@ -0,0 +1,626 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/plugins/spu2/zerospu2/SoundTouch/RateTransposer.h b/plugins/spu2/zerospu2/SoundTouch/RateTransposer.h new file mode 100644 index 0000000000..f73978e639 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/RateTransposer.h @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/STTypes.h b/plugins/spu2/zerospu2/SoundTouch/STTypes.h new file mode 100644 index 0000000000..9490cb720d --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/STTypes.h @@ -0,0 +1,197 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + + #define FALSE 0 + #define TRUE 1 + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/SoundTouch.cpp b/plugins/spu2/zerospu2/SoundTouch/SoundTouch.cpp new file mode 100644 index 0000000000..d20fd326ba --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/SoundTouch.cpp @@ -0,0 +1,474 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/plugins/spu2/zerospu2/SoundTouch/SoundTouch.h b/plugins/spu2/zerospu2/SoundTouch/SoundTouch.h new file mode 100644 index 0000000000..fab3bb9845 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/SoundTouch.h @@ -0,0 +1,252 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/TDStretch.cpp b/plugins/spu2/zerospu2/SoundTouch/TDStretch.cpp new file mode 100644 index 0000000000..d809623689 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/TDStretch.cpp @@ -0,0 +1,940 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/plugins/spu2/zerospu2/SoundTouch/TDStretch.h b/plugins/spu2/zerospu2/SoundTouch/TDStretch.h new file mode 100644 index 0000000000..85e2cc4386 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/TDStretch.h @@ -0,0 +1,256 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 40 + +/// Seeking window default length in milliseconds for algorithm that finds the best possible +/// overlapping location. This determines from how wide window the algorithm may look for an +/// optimal joining location when mixing the sound sequences back together. +/// +/// The bigger this window setting is, the higher the possibility to find a better mixing +/// position will become, but at the same time large values may cause a "drifting" artifact +/// because consequent sequences will be taken at more uneven intervals. +/// +/// If there's a disturbing artifact that sounds as if a constant frequency was drifting +/// around, try reducing this setting. +/// +/// Increasing this value increases computational burden & vice versa. +#define DEFAULT_SEEKWINDOW_MS 10 + +/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, +/// to form a continuous sound stream, this parameter defines over how long period the two +/// consecutive sequences are let to overlap each other. +/// +/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting +/// by a large amount, you might wish to try a smaller value on this. +/// +/// Increasing this value increases computational burden & vice versa. +#define DEFAULT_OVERLAP_MS 5 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +#ifdef ALLOW_MMX + /// Class that implements MMX optimized routines for 16bit integer samples type. + class TDStretchMMX : public TDStretch + { + protected: + long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; + virtual void overlapStereo(short *output, const short *input) const; + virtual void clearCrossCorrState(); + }; +#endif /// ALLOW_MMX + + +#ifdef ALLOW_3DNOW + /// Class that implements 3DNow! optimized routines for floating point samples type. + class TDStretch3DNow : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; +#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/plugins/spu2/zerospu2/SoundTouch/WavFile.cpp b/plugins/spu2/zerospu2/SoundTouch/WavFile.cpp new file mode 100644 index 0000000000..8e8983249c --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/WavFile.cpp @@ -0,0 +1,712 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/plugins/spu2/zerospu2/SoundTouch/WavFile.h b/plugins/spu2/zerospu2/SoundTouch/WavFile.h new file mode 100644 index 0000000000..dd239034d2 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/WavFile.h @@ -0,0 +1,253 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/plugins/spu2/zerospu2/SoundTouch/cpu_detect.h b/plugins/spu2/zerospu2/SoundTouch/cpu_detect.h new file mode 100644 index 0000000000..568817f17b --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/cpu_detect.h @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_gcc.cpp new file mode 100644 index 0000000000..75bd771099 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_gcc.cpp @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_win.cpp b/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_win.cpp new file mode 100644 index 0000000000..d8f9e58dd0 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/cpu_detect_x86_win.cpp @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/plugins/spu2/zerospu2/SoundTouch/mmx_optimized.cpp b/plugins/spu2/zerospu2/SoundTouch/mmx_optimized.cpp new file mode 100644 index 0000000000..f5afb595a5 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/mmx_optimized.cpp @@ -0,0 +1,305 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/plugins/spu2/zerospu2/SoundTouch/sse_optimized.cpp b/plugins/spu2/zerospu2/SoundTouch/sse_optimized.cpp new file mode 100644 index 0000000000..57598d78d7 --- /dev/null +++ b/plugins/spu2/zerospu2/SoundTouch/sse_optimized.cpp @@ -0,0 +1,484 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/plugins/spu2/zerospu2/Win32.cpp b/plugins/spu2/zerospu2/Win32.cpp new file mode 100644 index 0000000000..e703cd4b29 --- /dev/null +++ b/plugins/spu2/zerospu2/Win32.cpp @@ -0,0 +1,343 @@ +#include +#include +#include + +#include "zerospu2.h" +#include "resource.h" + +///////////////////////////////////// +// use DirectSound for the sound +#include + +#define SOUNDSIZE 76800//4*48*73 +HWND hWMain; + +LPDIRECTSOUND lpDS; +LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; +DSBUFFERDESC dsbd; +DSBUFFERDESC dsbdesc; +DSCAPS dscaps; +DSBCAPS dsbcaps; + +unsigned long LastWrite=0xffffffff; +unsigned long LastWriteS=0xffffffff; +unsigned long LastPlay=0; + +int SetupSound() +{ + HRESULT dsval;WAVEFORMATEX pcmwf; + + dsval = DirectSoundCreate(NULL,&lpDS,NULL); + if(dsval!=DS_OK) { + MessageBox(NULL,"DirectSoundCreate!","Error",MB_OK); + return -1; + } + + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) { + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) { + MessageBox(NULL,"SetCooperativeLevel!","Error",MB_OK); + return -1; + } + } + + memset(&dsbd,0,sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); + if(dsval!=DS_OK) { + MessageBox(NULL, "CreateSoundBuffer (Primary)", "Error",MB_OK); + return -1; + } + + memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = 48000; + + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + dsval=IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); + if(dsval!=DS_OK) { + MessageBox(NULL, "SetFormat!", "Error",MB_OK); + return -1; + } + + dscaps.dwSize = sizeof(DSCAPS); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSound_GetCaps(lpDS,&dscaps); + IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbdesc.dwBufferBytes = SOUNDSIZE; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) { + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) { + MessageBox(NULL,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); + return -1; + } + } + + dsval=IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) { + MessageBox(NULL,"Play (Primary)","Error",MB_OK); + return -1; + } + + dsval=IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) { + MessageBox(NULL,"Play (Secondary1)","Error",MB_OK); + return -1; + } + + LastWrite=0x00000000;LastPlay=0; // init some play vars + return 0; +} + +void RemoveSound() +{ + int iRes; + + if(lpDSBSECONDARY1!=NULL) { + IDirectSoundBuffer_Stop(lpDSBSECONDARY1); + iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + lpDSBSECONDARY1=NULL; + } + + if(lpDSBPRIMARY!=NULL) { + IDirectSoundBuffer_Stop(lpDSBPRIMARY); + iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + lpDSBPRIMARY=NULL; + } + + if(lpDS!=NULL) { + iRes=IDirectSound_Release(lpDS); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSound_Release(lpDS); + lpDS=NULL; + } + +} + +int SoundGetBytesBuffered() +{ + unsigned long cplay,cwrite; + + if(LastWrite==0xffffffff) return 0; + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(cplay>SOUNDSIZE) return SOUNDSIZE; + + if(cplay>2; + + lpSS=(unsigned long *)pSound; + while(dw) { + *lpSD++=*lpSS++; + dw--; + } + + if(lpvPtr2) { + lpSD=(unsigned long *)lpvPtr2; + dw=dwBytes2>>2; + while(dw) { + *lpSD++=*lpSS++; + dw--; + } + } + + IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); + LastWrite+=lBytes; + if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE; + LastPlay=cplay; +} + +///////// +// GUI // +///////// +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "SPU2NULL Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + //if( conf.options & OPTION_FFXHACK) CheckDlgButton(hW, IDC_FFXHACK, TRUE); + if( conf.options & OPTION_REALTIME) CheckDlgButton(hW, IDC_REALTIME, TRUE); + if( conf.options & OPTION_TIMESTRETCH) CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); + if( conf.options & OPTION_MUTE) CheckDlgButton(hW, IDC_MUTESOUND, TRUE); + if( conf.options & OPTION_RECORDING) CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + conf.options = 0; + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; +// if( IsDlgButtonChecked(hW, IDC_FFXHACK) ) +// conf.options |= OPTION_FFXHACK; + if( IsDlgButtonChecked(hW, IDC_REALTIME) ) + conf.options |= OPTION_REALTIME; + if( IsDlgButtonChecked(hW, IDC_TIMESTRETCH) ) + conf.options |= OPTION_TIMESTRETCH; + if( IsDlgButtonChecked(hW, IDC_MUTESOUND) ) + conf.options |= OPTION_MUTE; + if( IsDlgButtonChecked(hW, IDC_SNDRECORDING) ) + conf.options |= OPTION_RECORDING; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK SPU2configure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK SPU2about() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +extern HINSTANCE hInst; +void SaveConfig() +{ + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerospu2.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + sprintf(szValue,"%u",Conf1->options); + WritePrivateProfileString("Interface", "Options",szValue,szIniFile); + +} + +void LoadConfig() +{ + FILE *fp; + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerospu2.ini"); + fp=fopen("inis\\zerospu2.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + conf.options = OPTION_TIMESTRETCH; + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); + Conf1->options = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/spu2/zerospu2/ZeroSPU2.def b/plugins/spu2/zerospu2/ZeroSPU2.def new file mode 100644 index 0000000000..cfd610e766 --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2.def @@ -0,0 +1,33 @@ +; SPU2null.def : Declares the module parameters for the DLL. + +LIBRARY "SPU2null" +DESCRIPTION 'SPU2 Null Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + SPU2init @5 + SPU2shutdown @6 + SPU2open @7 + SPU2close @8 + SPU2write @9 + SPU2read @10 + SPU2readDMA4Mem @11 + SPU2writeDMA4Mem @12 + SPU2readDMA7Mem @13 + SPU2writeDMA7Mem @14 + SPU2async @15 + SPU2interruptDMA4 @16 + SPU2interruptDMA7 @17 + SPU2freeze @18 + SPU2configure @21 + SPU2test @22 + SPU2about @23 + + SPU2ReadMemAddr @24 + SPU2WriteMemAddr @25 + SPU2irqCallback @26 + SPU2setDMABaseAddr @27 + SPU2setupRecording @28 \ No newline at end of file diff --git a/plugins/spu2/zerospu2/ZeroSPU2.rc b/plugins/spu2/zerospu2/ZeroSPU2.rc new file mode 100644 index 0000000000..0624af3bd5 --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2.rc @@ -0,0 +1,136 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Greek resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ELL) +#ifdef _WIN32 +LANGUAGE LANG_GREEK, SUBLANG_DEFAULT +#pragma code_page(1253) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 175 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Time Scaling (recommended) - Slows down or speeds up sound with respect to game's real speed. Enabling this produces higher quality sound with less cracking, but can reduce speed.",IDC_TIMESTRETCH, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,7,198,37 + CONTROL "Real Time mode - tries to reduce delays in music as much possible. Use when game is already fast and need sound tightly synchronized (like in DDR, Guitar Hero, Guitaroo Man)",IDC_REALTIME, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,43,198,37 + CONTROL "Recording - Saves the raw 16bit stereo wav data to zerospu2.wav. Timed to ps2 time.",IDC_SNDRECORDING, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,87,198,15 + CONTROL "Mute - ZeroSPU2 will not output any sound (fast).",IDC_MUTESOUND, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,101,168,24 + CONTROL "Enable logging(for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,127,159,15 + DEFPUSHBUTTON "OK",IDOK,48,154,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,154,50,14 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About ZeroSPU2..." +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "ZeroSPU2 driver v0.4.6",IDC_NAME,51,7,79,15 + LTEXT "Author: Zerofrog Additional coding: Refraction Based on SPU2 Null driver by Shadow and Linuzappz",IDC_STATIC,7,23,141,54 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Greek resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/spu2/zerospu2/ZeroSPU2.vcproj b/plugins/spu2/zerospu2/ZeroSPU2.vcproj new file mode 100644 index 0000000000..0c070c479e --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/zerospu2/ZeroSPU2_2005.vcproj b/plugins/spu2/zerospu2/ZeroSPU2_2005.vcproj new file mode 100644 index 0000000000..3b6b37d854 --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2_2005.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/zerospu2/ZeroSPU2_2005_x64.vcproj b/plugins/spu2/zerospu2/ZeroSPU2_2005_x64.vcproj new file mode 100644 index 0000000000..5f36e3811d --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2_2005_x64.vcproj @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/zerospu2/ZeroSPU2_2008.vcproj b/plugins/spu2/zerospu2/ZeroSPU2_2008.vcproj new file mode 100644 index 0000000000..c5fef069cd --- /dev/null +++ b/plugins/spu2/zerospu2/ZeroSPU2_2008.vcproj @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2/zerospu2/build.sh b/plugins/spu2/zerospu2/build.sh new file mode 100644 index 0000000000..39a9ef1384 --- /dev/null +++ b/plugins/spu2/zerospu2/build.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +curdir=`pwd` + +echo ----------------- +echo Building ZeroSPU2 +echo ----------------- + +if [ $# -gt 0 ] && [ $1 = "all" ] +then + +aclocal +automake -a +autoconf +./configure --prefix=${PCSX2PLUGINS} +make clean +make install + +else +make $@ +fi + +if [ $? -ne 0 ] +then +exit 1 +fi + +#cp libZeroSPU2*.so* ${PCSX2PLUGINS} diff --git a/plugins/spu2/zerospu2/compile b/plugins/spu2/zerospu2/compile new file mode 100644 index 0000000000..973c773214 --- /dev/null +++ b/plugins/spu2/zerospu2/compile @@ -0,0 +1 @@ +link /usr/share/automake-1.9/compile \ No newline at end of file diff --git a/plugins/spu2/zerospu2/configure.ac b/plugins/spu2/zerospu2/configure.ac new file mode 100644 index 0000000000..a7fe5ce962 --- /dev/null +++ b/plugins/spu2/zerospu2/configure.ac @@ -0,0 +1,103 @@ +AC_INIT(ZeroSPU2,0.1,zerofrog@gmail.com) + +AM_INIT_AUTOMAKE(ZeroSPU2,0.1) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) + +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +ZEROSPU2_CURRENT=0 +ZEROSPU2_REVISION=1 +ZEROSPU2_AGE=0 +ZEROSPU2_SONAME=libZeroSPU2.so.[$ZEROSPU2_CURRENT].[$ZEROSPU2_REVISION].[$ZEROSPU2_AGE] +ZEROSPU2_RELEASE=[$ZEROSPU2_CURRENT].[$ZEROSPU2_REVISION].[$ZEROSPU2_AGE] + +AC_SUBST(ZEROSPU2_CURRENT) +AC_SUBST(ZEROSPU2_REVISION) +AC_SUBST(ZEROSPU2_AGE) +AC_SUBST(ZEROSPU2_RELEASE) +AC_SUBST(ZEROSPU2_SONAME) + +CFLAGS= +CPPFLAGS= +CXXFLAGS= + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), + debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+="-g " + CPPFLAGS+="-g " + CXXFLAGS+="-g " +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+="-O3 -fomit-frame-pointer " + CPPFLAGS+="-O3 -fomit-frame-pointer " + CXXFLAGS+="-O3 -fomit-frame-pointer " +fi +AM_CONDITIONAL(DEBUGBUILD, test x$debug = xyes) +AC_MSG_RESULT($debug) + +dnl Check for 64bit CPU +AC_MSG_CHECKING(for a x86-64 CPU) +dnl if test "$build_os" == "target_os" +dnl then +AC_TRY_RUN([ +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} +],cpu64=yes,cpu64=no,) +dnl else +dnl cpu64=no +dnl fi +if test "x$cpu64" == xyes +then +AC_DEFINE(__x86_64__,1,[__x86_64__]) +fi +AC_MSG_RESULT($cpu64) +AM_CONDITIONAL(X86_64, test x$cpu64 = xyes) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl gtk +AC_MSG_CHECKING(gtk2+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0) + +dnl bindir = pcsx2exe + +dnl assuming linux environment +so_ext=".so.$ZEROSPU2_RELEASE" +SHARED_LDFLAGS="-shared" +AC_SUBST(so_ext) +AC_SUBST(SHARED_LDFLAGS) + +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) +AC_CHECK_LIB(dl,main,[LIBS="$LIBS -ldl"]) +AC_CHECK_LIB(asound,main,[LIBS="$LIBS -lasound"]) + +AC_OUTPUT([ + SoundTouch/Makefile + Makefile + ]) + +echo "Configuration:" +echo " Debug build? $debug" +echo " x86-64 build? $cpu64" \ No newline at end of file diff --git a/plugins/spu2/zerospu2/depcomp b/plugins/spu2/zerospu2/depcomp new file mode 100644 index 0000000000..88b3a13969 --- /dev/null +++ b/plugins/spu2/zerospu2/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/spu2/zerospu2/install-sh b/plugins/spu2/zerospu2/install-sh new file mode 100644 index 0000000000..4d4a9519ea --- /dev/null +++ b/plugins/spu2/zerospu2/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/spu2/zerospu2/missing b/plugins/spu2/zerospu2/missing new file mode 100644 index 0000000000..894e786e16 --- /dev/null +++ b/plugins/spu2/zerospu2/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, 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. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/spu2/zerospu2/mkinstalldirs b/plugins/spu2/zerospu2/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/spu2/zerospu2/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec 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. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/spu2/zerospu2/resource.h b/plugins/spu2/zerospu2/resource.h new file mode 100644 index 0000000000..0e2681687e --- /dev/null +++ b/plugins/spu2/zerospu2/resource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroSPU2.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 +#define IDC_FFXHAC 1008 +#define IDC_FFXHACK 1008 +#define IDC_SNDRECORDING 1008 +#define IDC_RECORDING 1008 +#define IDC_REALTIME 1009 +#define IDC_TIMESTRETCH 1010 +#define IDC_MUTESOUND 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/spu2/zerospu2/zerospu2.cpp b/plugins/spu2/zerospu2/zerospu2.cpp new file mode 100644 index 0000000000..4c3f421a1c --- /dev/null +++ b/plugins/spu2/zerospu2/zerospu2.cpp @@ -0,0 +1,2151 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 "zerospu2.h" + +#include +#include + +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +// ADSR constants +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +#define AUDIO_BUFFER 2048 + +#define NSSIZE 48 // ~ 1 ms of data +#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting +#define NSPACKETS 24 + +#ifdef _DEBUG +char *libraryName = "ZeroSPU2 (Debug)"; +#else +char *libraryName = "ZeroSPU2 "; +#endif + +FILE *spu2Log; +Config conf; + +ADMA Adma4; +ADMA Adma7; + +u32 MemAddr[2]; +u32 g_nSpuInit = 0; +u16 interrupt = 0; +s8 *spu2regs = NULL; +u16* spu2mem = NULL; +u16* pSpuIrq[2] = {NULL}; +u32 dwNewChannel2[2] = {0}; // keeps track of what channels that have been turned on +u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended +unsigned long dwNoiseVal=1; // global noise generator +bool g_bPlaySound = true; // if true, will output sound, otherwise no +static int iFMod[NSSIZE]; +int s_buffers[NSSIZE][2]; // left and right buffers + +// mixer thread variables +static bool s_bThreadExit = true; +static int s_nDropPacket = 0; +string s_strIniPath="inis/zerospu2.ini"; + +#ifdef _WIN32 +LARGE_INTEGER g_counterfreq; +extern HWND hWMain; +HANDLE s_threadSPU2 = NULL; +DWORD WINAPI SPU2ThreadProc(LPVOID); +#else +#include +pthread_t s_threadSPU2; +void* SPU2ThreadProc(void*); +#endif + +struct AUDIOBUFFER +{ + u8* pbuf; + u32 len; + + // 1 if new channels started in this packet + // Variable used to smooth out sound by concentrating on new voices + u32 timestamp; // in microseconds, only used for time stretching + u32 avgtime; + int newchannels; +}; + +static AUDIOBUFFER s_pAudioBuffers[NSPACKETS]; +static int s_nCurBuffer = 0, s_nQueuedBuffers = 0; +static s16* s_pCurOutput = NULL; +static u32 g_startcount=0xffffffff; +static u32 g_packetcount=0; + +// time stretch variables +soundtouch::SoundTouch* pSoundTouch=NULL; +WavOutFile* g_pWavRecord=NULL; // used for recording + +static u64 s_GlobalTimeStamp = 0; +static int s_nDurations[64]={0}; +static int s_nCurDuration=0; +static int s_nTotalDuration=0; + +int SPUCycles = 0, SPUWorkerCycles = 0; +int SPUStartCycle[2]; +int SPUTargetCycle[2]; + +//#ifdef _DEBUG +int g_logsound=0; +//FILE* g_fLogSound=NULL; +//#endif + +int ADMAS4Write(); +int ADMAS7Write(); + +void InitADSR(); + +void (*irqCallbackSPU2)()=0; // func of main emu, called on spu irq +void (*irqCallbackDMA4)()=0; // func of main emu, called on spu irq +void (*irqCallbackDMA7)()=0; // func of main emu, called on spu irq +uptr g_pDMABaseAddr=0; + +const int f[5][2] = { { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; + +u32 RateTable[160]; + + +// Atomic Operations +#if defined (_WIN32) + +#ifndef __x86_64__ +extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); +#endif + +#pragma intrinsic (_InterlockedExchangeAdd) +#define InterlockedExchangeAdd _InterlockedExchangeAdd + +#else + +typedef void* PVOID; + +__forceinline long InterlockedExchangeAdd(long volatile* Addend, long Value) +{ + __asm__ __volatile__(".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory" ); +} + +#endif + +// channels and voices +VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_SPU2; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (SPU2_MINOR<<24)|(SPU2_VERSION<<16)|(SPU2_REVISION<<8)|SPU2_BUILD; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || spu2Log == NULL) return; + + va_start(list, fmt); + vfprintf(spu2Log, fmt, list); + va_end(list); + + //fprintf(spu2Log, "c0: %x %x, c1: %x %x\n", C0_SPUADDR, C0_IRQA, C1_SPUADDR, C1_IRQA); +} + +s32 CALLBACK SPU2init() +{ + spu2Log = fopen("logs/spu2.txt", "w"); + if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); + SPU2_LOG("Spu2 null version %d,%d\n",SPU2_REVISION,SPU2_BUILD); + SPU2_LOG("SPU2init\n"); + +#ifdef _WIN32 + QueryPerformanceFrequency(&g_counterfreq); +#else + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerospu2.ini"; +#endif + + spu2regs = (s8*)malloc(0x10000); + if (spu2regs == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + memset(spu2regs, 0, 0x10000); + + spu2mem = (u16*)malloc(0x200000); // 2Mb + if (spu2mem == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + memset(spu2mem, 0, 0x200000); + memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); + memset(dwNewChannel2, 0, sizeof(dwNewChannel2)); + memset(iFMod, 0, sizeof(iFMod)); + memset(s_buffers, 0, sizeof(s_buffers)); + + InitADSR(); + + memset(voices, 0, sizeof(voices)); + // last 24 channels have higher mem offset + for(int i = 0; i < 24; ++i) + voices[i+24].memoffset = 0x400; + + // init each channel + for(u32 i = 0; i < ARRAYSIZE(voices); ++i) { + + voices[i].chanid = i; + voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; + + voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); + voices[i].ADSRX.SustainLevel = 1024; // -> init sustain + } + + return 0; +} + +s32 CALLBACK SPU2open(void *pDsp) { +#ifdef _WIN32 + hWMain = pDsp == NULL ? NULL : *(HWND*)pDsp; + if(!IsWindow(hWMain)) + hWMain=GetActiveWindow(); +#endif + + LoadConfig(); + + SPUCycles = SPUWorkerCycles = 0; + interrupt = 0; + SPUStartCycle[0] = SPUStartCycle[1] = 0; + SPUTargetCycle[0] = SPUTargetCycle[1] = 0; + s_nDropPacket = 0; + + if( conf.options & OPTION_TIMESTRETCH ) { + pSoundTouch = new soundtouch::SoundTouch(); + pSoundTouch->setSampleRate(48000); + pSoundTouch->setChannels(2); + pSoundTouch->setTempoChange(0); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 1); + } + + //conf.Log = 1; + + g_bPlaySound = !(conf.options&OPTION_MUTE); +// if( conf.options & OPTION_REALTIME ) +// SPUWorkerCycles = timeGetTime(); + + if( g_bPlaySound && SetupSound() != 0 ) { + SysMessage("ZeroSPU2: Failed to initialize sound"); + g_bPlaySound = false; + } + + if( g_bPlaySound ) { + // initialize the audio buffers + for(u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) { + s_pAudioBuffers[i].pbuf = (u8*)_aligned_malloc(4*NSSIZE*NSFRAMES, 16); // 4 bytes for each sample + s_pAudioBuffers[i].len = 0; + } + + s_nCurBuffer = 0; + s_nQueuedBuffers = 0; + s_pCurOutput = (s16*)s_pAudioBuffers[0].pbuf; + assert( s_pCurOutput != NULL); + + for(int i = 0; i < ARRAYSIZE(s_nDurations); ++i) { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + // launch the thread + s_bThreadExit = false; +#ifdef _WIN32 + s_threadSPU2 = CreateThread(NULL, 0, SPU2ThreadProc, NULL, 0, NULL); + if( s_threadSPU2 == NULL ) { + return -1; + } +#else + if( pthread_create(&s_threadSPU2, NULL, SPU2ThreadProc, NULL) != 0 ) { + SysMessage("ZeroSPU2: Failed to create spu2thread\n"); + return -1; + } +#endif + } + + g_nSpuInit = 1; + return 0; +} + +void CALLBACK SPU2close() { + g_nSpuInit = 0; + + if( g_bPlaySound && !s_bThreadExit ) { + s_bThreadExit = true; + printf("ZeroSPU2: Waiting for thread... "); +#ifdef _WIN32 + WaitForSingleObject(s_threadSPU2, INFINITE); + CloseHandle(s_threadSPU2); s_threadSPU2 = NULL; +#else + pthread_join(s_threadSPU2, NULL); +#endif + printf("done\n"); + } + + RemoveSound(); + + delete g_pWavRecord; g_pWavRecord = NULL; + delete pSoundTouch; pSoundTouch = NULL; + + for(u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) { + _aligned_free(s_pAudioBuffers[i].pbuf); + } + memset(s_pAudioBuffers, 0, sizeof(s_pAudioBuffers)); +} + +void CALLBACK SPU2shutdown() +{ + free(spu2regs); spu2regs = NULL; + free(spu2mem); spu2mem = NULL; + + if (spu2Log) fclose(spu2Log); +} + +// simulate SPU2 for 1ms +void SPU2Worker(); + +#define CYCLES_PER_MS (36864000/1000) + +void CALLBACK SPU2async(u32 cycle) +{ + SPUCycles += cycle; + if(interrupt & (1<<2)){ + if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if(interrupt & (1<<1)){ + if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if( g_nSpuInit ) { + +// if( (conf.options & OPTION_REALTIME) ) { +// u32 iter = 0; +// while(SPUWorkerCycles < timeGetTime()) { +// SPU2Worker(); +// SPUWorkerCycles++; +// if( iter++ > 1 ) +// break; +// //if( SPUTargetCycle[0] >= CYCLES_PER_MS ) SPUTargetCycle[0] -= CYCLES_PER_MS; +// //if( SPUTargetCycle[1] >= CYCLES_PER_MS ) SPUTargetCycle[1] -= CYCLES_PER_MS; +// } +// } +// else { + while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) { + SPU2Worker(); + SPUWorkerCycles += CYCLES_PER_MS; + } +// } + } + else SPUWorkerCycles = SPUCycles; +} + +void InitADSR() // INIT ADSR +{ + unsigned long r,rs,rd; + int i; + memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++;if(rd==5) {rd=1;rs*=2;} + } + if(r>0x3FFFFFFF) r=0x3FFFFFFF; + + RateTable[i]=r; + } +} + +int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR +{ + if(pvoice->bStop) // should be stopped: + { + if(pvoice->bIgnoreLoop==0){ + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop=true; + pvoice->bIgnoreLoop=false; + return 0; + } + if(pvoice->ADSRX.ReleaseModeExp)// do release + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop=true; + pvoice->bIgnoreLoop=false; + //pvoice->bReverb=0; + //pvoice->bNoise=0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + else // not stopped yet? + { + if(pvoice->ADSRX.State==0) // -> attack + { + if(pvoice->ADSRX.AttackModeExp) + { + if(pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + pvoice->ADSRX.State=1; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if(pvoice->ADSRX.State==1) // -> decay + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; + } + + if(pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + if(((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) + { + pvoice->ADSRX.State=2; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if(pvoice->ADSRX.State==2) // -> sustain + { + if(pvoice->ADSRX.SustainIncrease) + { + if(pvoice->ADSRX.SustainModeExp) + { + if(pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + } + } + else + { + if(pvoice->ADSRX.SustainModeExp) + { + switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; + case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; + case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; + case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; + case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; + case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; + case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; + case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x0F + 32]; + } + + if(pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0; + } + } + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + } + return 0; +} + +// simulate SPU2 for 1ms +void SPU2Worker() +{ + int s_1,s_2,fa; + u8* start; + unsigned int nSample; + int ch,predict_nr,shift_factor,flags,d,s; + //int bIRQReturn=0; + + // assume s_buffers are zeroed out + if( dwNewChannel2[0] || dwNewChannel2[1] ) + s_pAudioBuffers[s_nCurBuffer].newchannels++; + + VOICE_PROCESSED* pChannel=voices; + for(ch=0;chbNew) { + pChannel->StartSound(); // start new sound + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear channel bit + } + + if(!pChannel->bOn) + continue; + + if(pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? + pChannel->VoiceChangeFrequency(); + + // loop until 1 ms of data is reached + int ns = 0; + while(nsbFMod==1 && iFMod[ns]) // fmod freq channel + pChannel->FModChangeFrequency(ns); + + while(pChannel->spos >= 0x10000 ) + { + if(pChannel->iSBPos==28) // 28 reached? + { + start=pChannel->pCurr; // set up the current pos + + // special "stop" sign + if( start == (u8*)-1 ) //!pChannel->bOn + { + pChannel->bOn=false; // -> turn everything off + pChannel->ADSRX.lVolume=0; + pChannel->ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + pChannel->iSBPos=0; + + // decode the 16byte packet + s_1=pChannel->s_1; + s_2=pChannel->s_2; + + predict_nr=(int)start[0]; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(int)start[1]; + start += 2; + + for(nSample=0;nSample<28; ++start) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + s=((d & 0xf0) << 8); + + pChannel->SB[nSample++]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + pChannel->SB[nSample++]=fa; + } + +// if(pChannel->GetCtrl()->irq) // some callback and irq active? +// { +// // if irq address reached or irq on looping addr, when stop/loop flag is set +// u8* pirq = (u8*)pSpuIrq[ch>=24]; +// if( (pirq > start-16 && pirq <= start) +// || ((flags&1) && (pirq > pChannel->pLoop-16 && pirq <= pChannel->pLoop))) +// { +// IRQINFO |= 4<<(int)(ch>=24); +// SPU2_LOG("SPU2Worker:interrupt\n"); +// irqCallbackSPU2(); +// } +// } + // irq occurs no matter what core access the address + for(int core = 0; core < 2; ++core) { + if(((SPU_CONTROL_*)(spu2regs+0x400*core+REG_C0_CTRL))->irq) // some callback and irq active? + { + // if irq address reached or irq on looping addr, when stop/loop flag is set + u8* pirq = (u8*)pSpuIrq[core]; + if( (pirq > start-16 && pirq <= start) + || ((flags&1) && (pirq > pChannel->pLoop-16 && pirq <= pChannel->pLoop))) + { + IRQINFO |= 4<bIgnoreLoop)) + pChannel->pLoop=start-16; // loop adress + + if(flags&1) // 1: stop/loop + { + // We play this block out first... + dwEndChannel2[ch/24]|=(1<<(ch%24)); + //if(!(flags&2)) // 1+2: do loop... otherwise: stop + if(flags!=3 || pChannel->pLoop==NULL) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + pChannel->bStop = true; + pChannel->bIgnoreLoop = false; + } + else + { + start = pChannel->pLoop; +// if(conf.options&OPTION_FFXHACK) +// start += 16; + } + } + + pChannel->pCurr=start; // store values for next cycle + pChannel->s_1=s_1; + pChannel->s_2=s_2; + +// if(bIRQReturn) // special return for "spu irq - wait for cpu action" +// { +// bIRQReturn=0; +// DWORD dwWatchTime=GetTickCount()+1500; +// +// while(iSpuAsyncWait && !bEndThread && GetTickCount()SB[pChannel->iSBPos++]; // get sample data + pChannel->StoreInterpolationVal(fa); + pChannel->spos -= 0x10000; + } + + if(pChannel->bNoise) + fa=pChannel->iGetNoiseVal(); // get noise val + else + fa=pChannel->iGetInterpolationVal(); // get sample val + + int sval = (MixADSR(pChannel)*fa)/1023; // mix adsr + + if(pChannel->bFMod==2) // fmod freq channel + { + iFMod[ns]=sval; // -> store 1T sample data, use that to do fmod on next channel + } + else { + if(pChannel->bVolumeL) + s_buffers[ns][0]+=(sval*pChannel->leftvol)>>14; + + if(pChannel->bVolumeR) + s_buffers[ns][1]+=(sval*pChannel->rightvol)>>14; + } + + // go to the next packet + ns++; + pChannel->spos += pChannel->sinc; + } +ENDX: + ; + } + + // mix all channels + if( (spu2Ru16(REG_C0_MMIX) & 0xF0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) /*&& !(spu2Ru16(REG_C0_CTRL) & 0x30)*/) { + for(int ns=0;ns>16; + if((spu2Ru16(REG_C0_MMIX) & 0x40)) s_buffers[ns][1] += (((short*)spu2mem)[0x2200+Adma4.Index]*(int)spu2Ru16(REG_C0_BVOLR))>>16; + + Adma4.Index +=1; + // just add after every sample, it is better than adding 1024 all at once (games like Genji don't like it) + MemAddr[0] += 4; + + if(Adma4.Index == 128 || Adma4.Index == 384) + { + if(ADMAS4Write()) + { + //if( Adma4.AmountLeft == 0 ) + //spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + //printf("ADMA4 end spu cycle %x\n", SPUCycles); + if(interrupt & 0x2){ + interrupt &= ~0x2; + printf("Stopping double interrupt DMA4\n"); + } + irqCallbackDMA4(); + + } + //else { + Adma4.Enabled = 2; +// if( Adma4.AmountLeft > 0 ) +// MemAddr[0] += 1024; + // } + } + + if(Adma4.Index == 512) { + if( Adma4.Enabled == 2 ) { +// if( Adma4.AmountLeft == 0 ) +// MemAddr[0] += 1024; + Adma4.Enabled = 0; + } + Adma4.Index = 0; + } + } + + //LogRawSound(s_buffers, 4, &s_buffers[0][1], 4, NSSIZE); + } + + if( (spu2Ru16(REG_C1_MMIX) & 0xF0) && (spu2Ru16(REG_C1_ADMAS) & 0x2) /*&& !(spu2Ru16(REG_C1_CTRL) & 0x30)*/) { + + for(int ns=0;ns>16; + if((spu2Ru16(REG_C1_MMIX) & 0x40)) s_buffers[ns][1] += (((short*)spu2mem)[0x2600+Adma7.Index]*(int)spu2Ru16(REG_C1_BVOLR))>>16; + + Adma7.Index +=1; + MemAddr[1] += 4; + + if(Adma7.Index == 128 || Adma7.Index == 384) + { + if(ADMAS7Write()) + { + // spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + //printf("ADMA7 end spu cycle %x\n", SPUCycles); + if(interrupt & 0x4){ + interrupt &= ~0x4; + printf("Stopping double interrupt DMA7\n"); + } + irqCallbackDMA7(); + + } + //else { + Adma7.Enabled = 2; + //MemAddr[1] += 1024; + // } + } + + if(Adma7.Index == 512) { + if( Adma7.Enabled == 2 ) + Adma7.Enabled = 0; + Adma7.Index = 0; + } + } + } + + if( g_bPlaySound ) { + + assert( s_pCurOutput != NULL); + + for(int ns=0;ns 32767 ) s_pCurOutput[0] = 32767; + else s_pCurOutput[0] = (s16)s_buffers[ns][0]; + + if( s_buffers[ns][1] < -32767 ) s_pCurOutput[1] = -32767; + else if( s_buffers[ns][1] > 32767 ) s_pCurOutput[1] = 32767; + else s_pCurOutput[1] = (s16)s_buffers[ns][1]; + s_pCurOutput += 2; + + + s_buffers[ns][0] = 0; + s_buffers[ns][1] = 0; + } + // check if end reached + + if( (uptr)s_pCurOutput - (uptr)s_pAudioBuffers[s_nCurBuffer].pbuf >= 4 * NSSIZE * NSFRAMES ) { + + if( conf.options & OPTION_RECORDING ) { + static int lastrectime=0; + if( timeGetTime()-lastrectime > 5000 ) { + printf("ZeroSPU2: recording\n"); + lastrectime = timeGetTime(); + } + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); + } + + if( s_nQueuedBuffers >= ARRAYSIZE(s_pAudioBuffers)-1 ) { + s_nDropPacket += NSFRAMES; + s_GlobalTimeStamp = GetMicroTime(); +//#ifdef _DEBUG + //printf("ZeroSPU2: dropping packets! game too fast\n"); +//#endif + } + else { + // submit to final mixer +#ifdef _DEBUG + if( g_logsound ) { + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); + } +#endif + if( g_startcount == 0xffffffff ) { + g_startcount = timeGetTime(); + g_packetcount = 0; + } + + if( conf.options & OPTION_TIMESTRETCH ) { + u64 newtime = GetMicroTime(); + if( s_GlobalTimeStamp == 0 ) + s_GlobalTimeStamp = newtime-NSFRAMES*1000; + u32 newtotal = s_nTotalDuration-s_nDurations[s_nCurDuration]; + u32 duration = (u32)(newtime-s_GlobalTimeStamp); + s_nDurations[s_nCurDuration] = duration; + s_nTotalDuration = newtotal + duration; + s_nCurDuration = (s_nCurDuration+1)%ARRAYSIZE(s_nDurations); + s_GlobalTimeStamp = newtime; + s_pAudioBuffers[s_nCurBuffer].timestamp = timeGetTime(); + s_pAudioBuffers[s_nCurBuffer].avgtime = s_nTotalDuration/ARRAYSIZE(s_nDurations); + //fprintf(spu2Log, "%d %d\n", duration, s_pAudioBuffers[s_nCurBuffer].avgtime); + } + + s_pAudioBuffers[s_nCurBuffer].len = 4*NSSIZE*NSFRAMES; + InterlockedExchangeAdd((long*)&s_nQueuedBuffers, 1); + + s_nCurBuffer = (s_nCurBuffer+1)%ARRAYSIZE(s_pAudioBuffers); + s_pAudioBuffers[s_nCurBuffer].newchannels = 0; // reset + } + + // restart + s_pCurOutput = (s16*)s_pAudioBuffers[s_nCurBuffer].pbuf; + } + } +} + +// resamples pStereoSamples +void ResampleLinear(s16* pStereoSamples, int oldsamples, s16* pNewSamples, int newsamples) +{ + for(int i = 0; i < newsamples; ++i) { + int io = i * oldsamples; + int old = io / newsamples; + int rem = io - old * newsamples; + + // newsamp = [old] * (1-rem/newsamp) + [old+1] * (rem/newsamp) + old *= 2; + int newsampL = pStereoSamples[old] * (newsamples - rem) + pStereoSamples[old+2] * rem; + int newsampR = pStereoSamples[old+1] * (newsamples - rem) + pStereoSamples[old+3] * rem; + pNewSamples[2*i] = newsampL / newsamples; + pNewSamples[2*i+1] = newsampR / newsamples; + } +} + +static PCSX2_ALIGNED16(s16 s_ThreadBuffer[NSSIZE*NSFRAMES*2*5]); + +// communicates with the audio hardware +#ifdef _WIN32 +DWORD WINAPI SPU2ThreadProc(LPVOID) +#else +void* SPU2ThreadProc(void* lpParam) +#endif +{ + int nReadBuf = 0; + + while(!s_bThreadExit) { + + if( !(conf.options&OPTION_REALTIME) ) { + while(s_nQueuedBuffers< 3 && !s_bThreadExit) { + //printf("sleeping!!!!\n"); + Sleep(1); + if( s_bThreadExit ) + return NULL; + } + + while( SoundGetBytesBuffered() > 72000 ) { + //printf("bytes buffered\n"); + Sleep(1); + + if( s_bThreadExit ) + return NULL; + } + } + else { + while(s_nQueuedBuffers< 1 && !s_bThreadExit) { + //printf("sleeping!!!!\n"); + Sleep(1); + } + } + + + int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; + int NewSamples = s_pAudioBuffers[nReadBuf].avgtime; + + if( (conf.options & OPTION_TIMESTRETCH) ) { + + int bytesbuf = SoundGetBytesBuffered(); + if( bytesbuf < 8000 ) + NewSamples += 1000; + // check the current timestamp, if too far apart, speed up audio + else if( bytesbuf > 40000 ) { + //printf("making faster %d\n", timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp); + NewSamples -= (bytesbuf-40000)/10;//*(ps2delay-NewSamples*8/1000); + } + + if( s_nDropPacket > 0 ) { + s_nDropPacket--; + NewSamples -= 1000; + } + + NewSamples *= NSSIZE; + NewSamples /= 1000; + + NewSamples = min(NewSamples, NSFRAMES*NSSIZE*3); + + //ResampleTimeStretch((s16*)s_pAudioBuffers[nReadBuf].pbuf, s_pAudioBuffers[nReadBuf].len/4, s_ThreadBuffer, NewSamples); + + int oldsamples = s_pAudioBuffers[nReadBuf].len/4; + + /*if( NewSamples < oldsamples/2 ) + NewSamples = oldsamples/2;*/ + + if( (nReadBuf&3)==0 ) { // wow, this if statement makes the whole difference + pSoundTouch->setTempoChange(100.0f*(float)oldsamples/(float)NewSamples - 100.0f); + } + + pSoundTouch->putSamples((s16*)s_pAudioBuffers[nReadBuf].pbuf, oldsamples); + + // extract 2*NSFRAMES ms at a time + int nOutSamples; + do + { + nOutSamples = pSoundTouch->receiveSamples(s_ThreadBuffer, NSSIZE*NSFRAMES*5); + if( nOutSamples > 0 ) { + //LogRawSound(s_ThreadBuffer, 4, s_ThreadBuffer+1, 4, nOutSamples); + //printf("%d %d\n", timeGetTime(), nOutSamples); + SoundFeedVoiceData((u8*)s_ThreadBuffer, nOutSamples*4); + //g_packetcount += nOutSamples; + } + } while (nOutSamples != 0); + + + //printf("ave: %d %d, played: %d, queued: %d, delay: %d, proc: %d\n", NewSamples, s_pAudioBuffers[nReadBuf].avgtime, SoundGetBytesBuffered(), s_nQueuedBuffers, ps2delay, GetMicroTime()-starttime); + } + else { + SoundFeedVoiceData(s_pAudioBuffers[nReadBuf].pbuf, s_pAudioBuffers[nReadBuf].len); + } + + // don't go to the next buffer unless there is more data buffered + nReadBuf = (nReadBuf+1)%ARRAYSIZE(s_pAudioBuffers); + InterlockedExchangeAdd((long*)&s_nQueuedBuffers, -1); + + if( s_bThreadExit ) + break; + } + + return NULL; +} + +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size) +{ + u32 spuaddr = C0_SPUADDR; + int i; + + SPU2_LOG("SPU2 readDMA4Mem size %x, addr: %x\n", size, pMem); + + for(i=0;i0x0fffff) // wrap at 2Mb + spuaddr=0; // wrap + } + + spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C0_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C0_SPUSTAT) &=~0x80; // DMA complete + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = size; + interrupt |= (1<<1); +} + +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr = C1_SPUADDR; + int i; + + SPU2_LOG("SPU2 readDMA7Mem size %x, addr: %x\n", size, pMem); + + for(i=0;i0x0fffff) // wrap at 2Mb + spuaddr=0; // wrap + } + + spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C1_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; // DMA complete + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = size; + interrupt |= (1<<2); +} + +// WRITE + +// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory +// Left and Right channels are always interleaved together in the transfer so +// the AutoDMA's deinterleaves them and transfers them. An interrupt is +// generated when half of the buffer (256 short-words for left and 256 +// short-words for right ) has been transferred. Another interrupt occurs at +// the end of the transfer. +int ADMAS4Write() +{ + u32 spuaddr; + if(interrupt & 0x2){ + printf("4 returning for interrupt\n"); + return 0; + } + if(Adma4.AmountLeft <= 0){ + printf("4 amount left is 0\n"); + return 1; + } + + assert( Adma4.AmountLeft >= 512 ); + spuaddr = C0_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2000),(short*)Adma4.MemAddr,512); + Adma4.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2200),(short*)Adma4.MemAddr,512); + Adma4.MemAddr += 256; + if( (spu2Ru16(REG_C0_CTRL)&0x40) && ((spuaddr + 0x2400) <= C0_IRQA && (spuaddr + 0x2400 + 256) >= C0_IRQA)){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + printf("ADMA 4 Mem access:interrupt\n"); + irqCallbackSPU2(); + } + if( (spu2Ru16(REG_C0_CTRL)&0x40) && ((spuaddr + 0x2600) <= C0_IRQA && (spuaddr + 0x2600 + 256) >= C0_IRQA)){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + printf("ADMA 4 Mem access:interrupt\n"); + irqCallbackSPU2(); + } + + spuaddr = (spuaddr + 256) & 511; + C0_SPUADDR_SET(spuaddr); + + Adma4.AmountLeft-=512; + + + + if(Adma4.AmountLeft > 0) return 0; + else return 1; +} + +int ADMAS7Write() +{ + u32 spuaddr; + if(interrupt & 0x4){ + printf("7 returning for interrupt\n"); + return 0; + } + if(Adma7.AmountLeft <= 0){ + printf("7 amount left is 0\n"); + return 1; + } + + assert( Adma7.AmountLeft >= 512 ); + spuaddr = C1_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2400),(short*)Adma7.MemAddr,512); + Adma7.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2600),(short*)Adma7.MemAddr,512); + Adma7.MemAddr += 256; + if( (spu2Ru16(REG_C1_CTRL)&0x40) && ((spuaddr + 0x2400) <= C1_IRQA && (spuaddr + 0x2400 + 256) >= C1_IRQA)){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 8; + printf("ADMA 7 Mem access:interrupt\n"); + irqCallbackSPU2(); + } + if( (spu2Ru16(REG_C1_CTRL)&0x40) && ((spuaddr + 0x2600) <= C1_IRQA && (spuaddr + 0x2600 + 256) >= C1_IRQA)){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 8; + printf("ADMA 7 Mem access:interrupt\n"); + irqCallbackSPU2(); + } + spuaddr = (spuaddr + 256) & 511; + C1_SPUADDR_SET(spuaddr); + + Adma7.AmountLeft-=512; + + assert( Adma7.AmountLeft >= 0 ); + + if(Adma7.AmountLeft > 0) return 0; + else return 1; +} + +void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) +{ + u32 spuaddr; + + SPU2_LOG("SPU2 writeDMA4Mem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", size, pMem, C0_SPUADDR, spu2Ru16(REG_C0_CTRL), spu2Ru16(REG_C0_ADMAS)); + + if((spu2Ru16(REG_C0_ADMAS) & 0x1) && (spu2Ru16(REG_C0_CTRL) & 0x30) == 0 && size) + { +// u16* ptempmem = pMem; +// for(int i = 0; i < size/512; ++i) { +// LogRawSound(ptempmem, 2, ptempmem+256, 2, 256); +// ptempmem += 512; +// } + + //printf("ADMA4 size %x\n", size); + // if still active, don't destroy adma4 + if( !Adma4.Enabled ) + Adma4.Index = 0; + + //memset(&Adma4,0,sizeof(ADMA)); + Adma4.MemAddr = pMem; + Adma4.AmountLeft = size; + SPUTargetCycle[0] = size; + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + if( !Adma4.Enabled || Adma4.Index > 384 ) { + C0_SPUADDR_SET(0); + if(ADMAS4Write()){ + SPUStartCycle[0] = SPUCycles; + // SPUTargetCycle[0] = 512;//512*48000; + //spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + interrupt |= (1<<1); + } + } + + //if(interrupt & 0x2) printf("start ADMA4 interrupt target cycle %x start cycle %x spu cycle %x\n", SPUTargetCycle[0], SPUStartCycle[0], SPUCycles); + Adma4.Enabled = 1; + return; + } + + spuaddr = C0_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); + spuaddr += size; + C0_SPUADDR_SET(spuaddr); + + if( (spu2Ru16(REG_C0_CTRL)&0x40) && (spuaddr < C0_IRQA && C0_IRQA <= spuaddr+0x20)){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + SPU2_LOG("SPU2writeDMA4Mem:interrupt\n"); + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + + MemAddr[0] += size<<1; + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = size; + interrupt |= (1<<1); +} + +void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr; + + SPU2_LOG("SPU2 writeDMA7Mem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", size, pMem, C1_SPUADDR, spu2Ru16(REG_C1_CTRL), spu2Ru16(REG_C1_ADMAS)); + + if((spu2Ru16(REG_C1_ADMAS) & 0x2) && (spu2Ru16(REG_C1_CTRL) & 0x30) == 0 && size) + { +// u16* ptempmem = pMem; +// for(int i = 0; i < size/512; ++i) { +// LogRawSound(ptempmem, 2, ptempmem+256, 2, 256); +// ptempmem += 512; +// } + + //printf("ADMA7 size %x\n", size); + if( !Adma7.Enabled ) + Adma7.Index = 0; + + //memset(&Adma7,0,sizeof(ADMA)); + Adma7.MemAddr = pMem; + Adma7.AmountLeft = size; + SPUTargetCycle[1] = size; + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + if( !Adma7.Enabled || Adma7.Index > 384 ) { + C1_SPUADDR_SET(0); + if(ADMAS7Write()){ + SPUStartCycle[1] = SPUCycles; + // SPUTargetCycle[0] = 512;//512*48000; + interrupt |= (1<<2); + } + } + //if(interrupt & 0x4) printf("start ADMA7 interrupt target cycle %x start cycle %x spu cycle %x\n", SPUTargetCycle[1], SPUStartCycle[1], SPUCycles); + Adma7.Enabled = 1; + + return; + } + +#ifdef _DEBUG + if( conf.Log && conf.options & OPTION_RECORDING ) + LogPacketSound(pMem, 0x8000); +#endif + + spuaddr = C1_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); + spuaddr += size; + C1_SPUADDR_SET(spuaddr); + + if( (spu2Ru16(REG_C1_CTRL)&0x40) && (spuaddr < C1_IRQA && C1_IRQA <= spuaddr+0x20)){ + //spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + SPU2_LOG("SPU2writeDMA7Mem:interrupt\n"); + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + + MemAddr[1] += size<<1; + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = size; + interrupt |= (1<<2); +} + +void CALLBACK SPU2interruptDMA4() +{ + SPU2_LOG("SPU2 interruptDMA4\n"); + +// spu2Rs16(REG_C0_CTRL)&= ~0x30; +// spu2Rs16(REG__1B0) = 0; +// spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80; + spu2Rs16(REG_C0_CTRL)&=~0x30; + spu2Ru16(REG_C0_SPUSTAT)|=0x80; +} + +void CALLBACK SPU2interruptDMA7() +{ + SPU2_LOG("SPU2 interruptDMA7\n"); + +// spu2Rs16(REG_C1_CTRL)&= ~0x30; +// //spu2Rs16(REG__5B0) = 0; +// spu2Rs16(SPU2_STATX_DREQ)|= 0x80; + spu2Rs16(REG_C1_CTRL)&=~0x30; + spu2Ru16(REG_C1_SPUSTAT)|=0x80; +} + +// turn channels on +void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND +{ + for(int ch=start;ch>=1) // loop channels + { + if((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! + { + voices[ch].bNew=true; + voices[ch].bIgnoreLoop = false; + dwNewChannel2[ch/24]|=(1<<(ch%24)); // clear end channel bit + } + } +} + +// turn channels off +void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND +{ + for(int ch=start;ch>=1) { // loop channels + if(val&1) // && s_chan[i].bOn) mmm... + voices[ch].bStop=true; + } +} + +void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) { // loop channels + if(val&1) { // -> fmod on/off + if(ch>0) { + voices[ch].bFMod=1; // --> sound channel + voices[ch-1].bFMod=2; // --> freq channel + } + } + else + voices[ch].bFMod=0; // --> turn off fmod + } +} + +void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) { // loop channels + if(val&1) { // -> reverb on/off + + if(iRight) voices[ch].bVolumeR=1; + else voices[ch].bVolumeL=1; + } + else { + if(iRight) voices[ch].bVolumeR=0; + else voices[ch].bVolumeL=0; + } + } +} + +void CALLBACK SPU2write(u32 mem, u16 value) +{ + u32 spuaddr; + SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); + + assert( C0_SPUADDR < 0x100000); + assert( C1_SPUADDR < 0x100000); + + spu2Ru16(mem) = value; + u32 r = mem&0xffff; + + // channel info + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int ch=0; + if(r>=0x400) ch=((r-0x400)>>4)+24; + else ch=(r>>4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r&0x0f) + { + case 0: + case 2: + pvoice->SetVolume(mem&0x2); + break; + case 4: + { + int NP; + if(value>0x3fff) NP=0x3fff; // get pitch val + else NP=value; + + pvoice->pvoice->pitch = NP; + + NP=(48000L*NP)/4096L; // calc frequency + if(NP<1) NP=1; // some security + pvoice->iActFreq=NP; // store frequency + break; + } + case 6: + { + pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; + pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); + pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); + pvoice->ADSRX.SustainLevel = (value & 0x000f); + break; + } + case 8: + pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; + pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; + pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); + pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; + pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); + break; + } + + return; + } + + // more channel info + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) + { + int ch=0; + unsigned long rx=r; + if(rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) + { + case 0x1C0: + pvoice->iStartAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C2: + pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C4: + pvoice->iLoopAddr =(((unsigned long)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C6: + pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C8: + // unused... check if it gets written as well + pvoice->iNextAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); + break; + case 0x1CA: + // unused... check if it gets written as well + pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); + break; + } + + return; + } + + // process non-channel data + switch(mem&0xffff) { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if( (spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr){ + //spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + SPU2_LOG("SPU2write:C0_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + spu2Ru16(REG_C0_CTRL)&=~0x30; + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if( (spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr){ + //spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + SPU2_LOG("SPU2write:C1_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + if(spuaddr>0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + spu2Ru16(REG_C1_CTRL)&=~0x30; + break; + case REG_C0_IRQA_HI: + case REG_C0_IRQA_LO: + pSpuIrq[0]=spu2mem+C0_IRQA; + break; + case REG_C1_IRQA_HI: + case REG_C1_IRQA_LO: + pSpuIrq[1]=spu2mem+C1_IRQA; + break; + + case REG_C0_SPUADDR_HI: + case REG_C1_SPUADDR_HI: + spu2Ru16(mem) = value&0xf; + break; + + case REG_C0_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if( !(value & 0x40) ) + IRQINFO &= ~0x4; + break; + case REG_C1_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if( !(value & 0x40) ) + IRQINFO &= ~0x8; + break; + case REG_C0_SPUON1: SoundOn(0,16,value); break; + case REG_C0_SPUON2: SoundOn(16,24,value); break; + case REG_C1_SPUON1: SoundOn(24,40,value); break; + case REG_C1_SPUON2: SoundOn(40,48,value); break; + case REG_C0_SPUOFF1: SoundOff(0,16,value); break; + case REG_C0_SPUOFF2: SoundOff(16,24,value); break; + case REG_C1_SPUOFF1: SoundOff(24,40,value); break; + case REG_C1_SPUOFF2: SoundOff(40,48,value); break; + + // According to manual all bits are cleared by writing an arbitary value + case REG_C0_END1: dwEndChannel2[0] &= 0x00ff0000; break; + case REG_C0_END2: dwEndChannel2[0] &= 0x0000ffff; break; + case REG_C1_END1: dwEndChannel2[1] &= 0x00ff0000; break; + case REG_C1_END2: dwEndChannel2[1] &= 0x0000ffff; break; + case REG_C0_FMOD1: FModOn(0,16,value); break; + case REG_C0_FMOD2: FModOn(16,24,value); break; + case REG_C1_FMOD1: FModOn(24,40,value); break; + case REG_C1_FMOD2: FModOn(40,48,value); break; + case REG_C0_VMIXL1: VolumeOn(0,16,value,0); break; + case REG_C0_VMIXL2: VolumeOn(16,24,value,0); break; + case REG_C1_VMIXL1: VolumeOn(24,40,value,0); break; + case REG_C1_VMIXL2: VolumeOn(40,48,value,0); break; + case REG_C0_VMIXR1: VolumeOn(0,16,value,1); break; + case REG_C0_VMIXR2: VolumeOn(16,24,value,1); break; + case REG_C1_VMIXR1: VolumeOn(24,40,value,1); break; + case REG_C1_VMIXR2: VolumeOn(40,48,value,1); break; + } + + assert( C0_SPUADDR < 0x100000); + assert( C1_SPUADDR < 0x100000); +} + +u16 CALLBACK SPU2read(u32 mem) +{ + u32 spuaddr; + u16 ret; + u32 r = mem&0xffff; + + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int ch=0; + if(r>=0x400) ch=((r-0x400)>>4)+24; + else ch=(r>>4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r&0x0f) { + case 10: +// if( pvoice->bNew ) return 1; +// if( pvoice->ADSRX.lVolume && !pvoice->ADSRX.EnvelopeVol ) return 1; + return (unsigned short)(pvoice->ADSRX.EnvelopeVol>>16); + } + } + + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0; + unsigned long rx=r; + if(rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) { + case 0x1C0: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C2: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>1)&0xFFFF); + break; + case 0x1C4: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C6: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>1)&0xFFFF); + break; + case 0x1C8: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1CA: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>1)&0xFFFF); + break; + } + + SPU2_LOG("SPU2 channel read mem %x: %x\n", mem, ret); + return ret; + } + + switch(mem&0xffff) { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + ret =spu2mem[spuaddr]; + spuaddr++; + if(spuaddr>0xfffff) + spuaddr=0; + C0_SPUADDR_SET(spuaddr); + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + ret = spu2mem[spuaddr]; + spuaddr++; + if(spuaddr>0xfffff) + spuaddr=0; + C1_SPUADDR_SET(spuaddr); + break; + + case REG_C0_END1: ret = (dwEndChannel2[0]&0xffff); break; + case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; + case REG_C1_END1: ret = (dwEndChannel2[1]&0xffff); break; + case REG_C1_END2: ret = (dwEndChannel2[1]>>16); break; + + case REG_IRQINFO: + ret = IRQINFO; + //IRQINFO = 0; // clear once done + break; + + default: + ret = spu2Ru16(mem); + } + + SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); + + return ret; +} + +void CALLBACK SPU2WriteMemAddr(int core, u32 value) +{ + MemAddr[core] = g_pDMABaseAddr+value; +} + +u32 CALLBACK SPU2ReadMemAddr(int core) +{ + return MemAddr[core]-g_pDMABaseAddr; +} + +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr) +{ + g_pDMABaseAddr = baseaddr; +} + +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +// VOICE_PROCESSED definitions +SPU_CONTROL_* VOICE_PROCESSED::GetCtrl() +{ + return ((SPU_CONTROL_*)(spu2regs+memoffset+REG_C0_CTRL)); +} + +void VOICE_PROCESSED::SetVolume(int iProcessRight) +{ + u16 vol = iProcessRight ? pvoice->right.word : pvoice->left.word; + + if(vol&0x8000) // sweep not working + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + vol=0x3fff-(vol&0x3fff); + } + + if( iProcessRight ) + rightvol = vol&0x3fff; + else + leftvol = vol&0x3fff; + + bVolChanged = true; +} + +void VOICE_PROCESSED::StartSound() +{ + ADSRX.lVolume=1; // and init some adsr vars + ADSRX.State=0; + ADSRX.EnvelopeVol=0; + + if(bReverb && GetCtrl()->reverb ) + { + // setup the reverb effects + } + + pCurr=pStart; // set sample start + + s_1=0; // init mixing vars + s_2=0; + iSBPos=28; + + bNew=false; // init channel flags + bStop=false; + bOn=true; + SB[29]=0; // init our interpolation helpers + SB[30]=0; + + spos=0x10000L; + SB[31]=0; +} + +void VOICE_PROCESSED::VoiceChangeFrequency() +{ + iUsedFreq=iActFreq; // -> take it and calc steps + sinc=(u32)pvoice->pitch<<4; + if(!sinc) + sinc=1; + + // -> freq change in simle imterpolation mode: set flag + SB[32]=1; +} + +void VOICE_PROCESSED::InterpolateUp() +{ + if(SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass + { + const int id1=SB[30]-SB[29]; // curr delta to next val + const int id2=SB[31]-SB[30]; // and next delta to next-next val :) + + SB[32]=0; + + if(id1>0) // curr delta positive + { + if(id2id1) + {SB[28]=id1;SB[32]=2;} + else + if(id2>(id1<<1)) + SB[28]=(id1*sinc)/0x10000L; + else + SB[28]=(id1*sinc)/0x20000L; + } + } + else if(SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass + { + SB[32]=0; + + SB[28]=(SB[28]*sinc)/0x20000L; + if(sinc<=0x8000) + SB[29]=SB[30]-(SB[28]*((0x10000/sinc)-1)); + else + SB[29]+=SB[28]; + } + else // no flags? add bigger val (if possible), calc smaller step, set flag1 + SB[29]+=SB[28]; +} + +// +// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm +// + +void VOICE_PROCESSED::InterpolateDown() +{ + if(sinc>=0x20000L) // we would skip at least one val? + { + SB[29]+=(SB[30]-SB[29])/2; // add easy weight + if(sinc>=0x30000L) // we would skip even more vals? + SB[29]+=(SB[31]-SB[30])/2; // add additional next weight + } +} + +void VOICE_PROCESSED::FModChangeFrequency(int ns) +{ + int NP=pvoice->pitch; + + NP=((32768L+iFMod[ns])*NP)/32768L; + + if(NP>0x3fff) NP=0x3fff; + if(NP<0x1) NP=0x1; + + NP=(48000L*NP)/(4096L); // calc frequency + + iActFreq=NP; + iUsedFreq=NP; + sinc=(((NP/10)<<16)/4800); + if(!sinc) + sinc=1; + + // freq change in simple interpolation mode + SB[32]=1; + + iFMod[ns]=0; +} + +// noise handler... just produces some noise data +// surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... +// and sometimes the noise will be used as fmod modulation... pfff +int VOICE_PROCESSED::iGetNoiseVal() +{ + int fa; + + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else + fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=iOldNoise+((fa-iOldNoise)/((0x001f-(GetCtrl()->noiseFreq))+1)); + if(fa>32767L) + fa=32767L; + if(fa<-32767L) + fa=-32767L; + + iOldNoise=fa; + SB[29] = fa; // -> store noise val in "current sample" slot + return fa; +} + +void VOICE_PROCESSED::StoreInterpolationVal(int fa) +{ + if(bFMod==2) // fmod freq channel + SB[29]=fa; + else + { + if(!GetCtrl()->spuUnmute) + fa=0; // muted? + else // else adjust + { + if(fa>32767L) + fa=32767L; + if(fa<-32767L) + fa=-32767L; + } + + SB[28] = 0; + SB[29] = SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' + SB[30] = SB[31]; + SB[31] = fa; + SB[32] = 1; // -> flag: calc new interolation + } +} + +int VOICE_PROCESSED::iGetInterpolationVal() +{ + int fa; + if(bFMod==2) + return SB[29]; + + if(sinc<0x10000L) // -> upsampling? + InterpolateUp(); // --> interpolate up + else InterpolateDown(); // --> else down + fa=SB[29]; + + return fa; +} + +void VOICE_PROCESSED::Stop() +{ +} + + +s32 CALLBACK SPU2test() +{ + return 0; +} + +// size is in bytes +void LogPacketSound(void* packet, int memsize) +{ + u16 buf[28]; + + u8* pstart = (u8*)packet; + int s_1 = 0; + int s_2=0; + for(int i = 0; i < memsize; i += 16) { + int predict_nr=(int)pstart[0]; + int shift_factor=predict_nr&0xf; + predict_nr >>= 4; + int flags=(int)pstart[1]; + pstart += 2; + + for(int nSample=0;nSample<28; ++pstart) + { + int d=(int)*pstart; + int s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + int fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + s=((d & 0xf0) << 8); + + buf[nSample++]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + buf[nSample++]=fa; + } + + LogRawSound(buf, 2, buf, 2, 28); + } +} + +#define RECORD_FILENAME "zerospu2.wav" + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) +{ +//#ifdef _DEBUG +// if( g_fLogSound == NULL ) { +// g_fLogSound = fopen("rawsndbuf.pcm", "wb"); +// if( g_fLogSound == NULL ) +// return; +// } + if( g_pWavRecord == NULL ) { + g_pWavRecord = new WavOutFile(RECORD_FILENAME, 48000, 16, 2); + } + + u8* left = (u8*)pleft; + u8* right = (u8*)pright; + static vector tempbuf; + + tempbuf.resize(2*numsamples); + + for(int i = 0; i < numsamples; ++i) { + tempbuf[2*i+0] = *(s16*)left; + tempbuf[2*i+1] = *(s16*)right; + left += leftstride; + right += rightstride; + } + + g_pWavRecord->write(&tempbuf[0], numsamples*2); + + //fwrite(&tempbuf[0], 4*numsamples, 1, g_fLogSound); +//#endif +} + +int CALLBACK SPU2setupRecording(int start, void* pData) +{ + if( start ) { + conf.options |= OPTION_RECORDING; + printf("ZeroSPU2: started recording at %s\n", RECORD_FILENAME); + } + else { + conf.options &= ~OPTION_RECORDING; + printf("ZeroSPU2: stopped recording\n"); + } + + return 1; +} + +struct SPU2freezeData +{ + u32 version; + u8 spu2regs[0x10000]; + u8 spu2mem[0x200000]; + u16 interrupt; + int nSpuIrq[2]; + u32 dwNewChannel2[2], dwEndChannel2[2]; + u32 dwNoiseVal; + int iFMod[NSSIZE]; + u32 MemAddr[2]; + ADMA adma[2]; + u32 Adma4MemAddr, Adma7MemAddr; + + int SPUCycles, SPUWorkerCycles; + int SPUStartCycle[2]; + int SPUTargetCycle[2]; + + int voicesize; + VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; +}; + +s32 CALLBACK SPU2freeze(int mode, freezeData *data) +{ + SPU2freezeData *spud; + int i; + assert( g_pDMABaseAddr != 0 ); + + if (mode == FREEZE_LOAD) { + spud = (SPU2freezeData*)data->data; + if( spud->version != 0x70000001 ) { + printf("zerospu2: data wrong format\n"); + return 0; + } + + memcpy(spu2regs, spud->spu2regs, 0x10000); + memcpy(spu2mem, spud->spu2mem, 0x200000); + pSpuIrq[0] = spu2mem + spud->nSpuIrq[0]; + pSpuIrq[1] = spu2mem + spud->nSpuIrq[1]; + memcpy(dwNewChannel2, spud->dwNewChannel2, 4*2); + memcpy(dwEndChannel2, spud->dwEndChannel2, 4*2); + dwNoiseVal = spud->dwNoiseVal; + memcpy(iFMod, spud->iFMod, sizeof(iFMod)); + interrupt = spud->interrupt; + memcpy(MemAddr, spud->MemAddr, sizeof(MemAddr)); + Adma4 = spud->adma[0]; + Adma4.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma4MemAddr); + Adma7 = spud->adma[1]; + Adma7.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma7MemAddr); + + SPUCycles = spud->SPUCycles; + SPUWorkerCycles = spud->SPUWorkerCycles; + memcpy(SPUStartCycle, spud->SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(SPUTargetCycle, spud->SPUTargetCycle, sizeof(SPUTargetCycle)); + + for(i = 0; i < ARRAYSIZE(voices); ++i) { + memcpy(&voices[i], &spud->voices[i], min((int)SPU_VOICE_STATE_SIZE, spud->voicesize)); + voices[i].pStart = (u8*)((uptr)spud->voices[i].pStart+(uptr)spu2mem); + voices[i].pLoop = (u8*)((uptr)spud->voices[i].pLoop+(uptr)spu2mem); + voices[i].pCurr = (u8*)((uptr)spud->voices[i].pCurr+(uptr)spu2mem); + } + + //conf.Log = 1; + s_GlobalTimeStamp = 0; + g_startcount=0xffffffff; + for(int i = 0; i < ARRAYSIZE(s_nDurations); ++i) { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + s_nQueuedBuffers = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SAVE) { + spud = (SPU2freezeData*)data->data; + spud->version = 0x70000001; + + memcpy(spud->spu2regs, spu2regs, 0x10000); + memcpy(spud->spu2mem, spu2mem, 0x200000); + spud->nSpuIrq[0] = (int)(pSpuIrq[0] - spu2mem); + spud->nSpuIrq[1] = (int)(pSpuIrq[1] - spu2mem); + memcpy(spud->dwNewChannel2, dwNewChannel2, 4*2); + memcpy(spud->dwEndChannel2, dwEndChannel2, 4*2); + spud->dwNoiseVal = dwNoiseVal; + memcpy(spud->iFMod, iFMod, sizeof(iFMod)); + spud->interrupt = interrupt; + memcpy(spud->MemAddr, MemAddr, sizeof(MemAddr)); + + spud->adma[0] = Adma4; + spud->Adma4MemAddr = (u32)((uptr)Adma4.MemAddr - g_pDMABaseAddr); + spud->adma[1] = Adma7; + spud->Adma7MemAddr = (u32)((uptr)Adma7.MemAddr - g_pDMABaseAddr); + + spud->SPUCycles = SPUCycles; + +// if( conf.options & OPTION_REALTIME ) +// SPUWorkerCycles = SPUCycles; +// else + spud->SPUWorkerCycles = SPUWorkerCycles; + memcpy(spud->SPUStartCycle, SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(spud->SPUTargetCycle, SPUTargetCycle, sizeof(SPUTargetCycle)); + + for(i = 0; i < ARRAYSIZE(s_nDurations); ++i) { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + spud->voicesize = SPU_VOICE_STATE_SIZE; + for(i = 0; i < ARRAYSIZE(voices); ++i) { + memcpy(&spud->voices[i], &voices[i], SPU_VOICE_STATE_SIZE); + spud->voices[i].pStart = (u8*)((uptr)voices[i].pStart-(uptr)spu2mem); + spud->voices[i].pLoop = (u8*)((uptr)voices[i].pLoop-(uptr)spu2mem); + spud->voices[i].pCurr = (u8*)((uptr)voices[i].pCurr-(uptr)spu2mem); + } + + g_startcount=0xffffffff; + s_GlobalTimeStamp = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SIZE) { + data->size = sizeof(SPU2freezeData); + } + +// if( conf.options & OPTION_REALTIME ) +// SPUWorkerCycles = timeGetTime(); + + return 0; +} diff --git a/plugins/spu2/zerospu2/zerospu2.h b/plugins/spu2/zerospu2/zerospu2.h new file mode 100644 index 0000000000..777d7a9dbc --- /dev/null +++ b/plugins/spu2/zerospu2/zerospu2.h @@ -0,0 +1,465 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 __SPU2_H__ +#define __SPU2_H__ + +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include + +extern "C" { +#define SPU2defs +#include "PS2Edefs.h" +} + +#ifdef __LINUX__ +#include +#include +#include // ftime(), struct timeb + +#define Sleep(ms) usleep(1000*ms) + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#include + +#else +#include +#include + +#include // ftime(), struct timeb +#endif + + +inline u64 GetMicroTime() +{ +#ifdef _WIN32 + extern LARGE_INTEGER g_counterfreq; + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart * 1000000 / g_counterfreq.QuadPart; +#else + timeval t; + gettimeofday(&t, NULL); + return t.tv_sec*1000000+t.tv_usec; +#endif +} + +#include +#include +using namespace std; + +extern FILE *spu2Log; + +#ifdef _DEBUG +#define SPU2_LOG __Log //debug mode +#else +#define SPU2_LOG 0&& +#endif + +#define SPU2_VERSION PS2E_SPU2_VERSION +#define SPU2_REVISION 0 +#define SPU2_BUILD 4 // increase that with each version +#define SPU2_MINOR 6 + +#define OPTION_TIMESTRETCH 1 // stretches samples without changing pitch to reduce cracking +#define OPTION_REALTIME 2 // sync to real time instead of ps2 time +#define OPTION_MUTE 4 // don't output anything +#define OPTION_RECORDING 8 + +typedef struct { + int Log; + int options; +} Config; + +extern Config conf; + +void __Log(char *fmt, ...); +void SaveConfig(); +void LoadConfig(); +void SysMessage(char *fmt, ...); + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples); +void LogPacketSound(void* packet, int memsize); + +// hardware sound functions +int SetupSound(); // if successful, returns 0 +void RemoveSound(); +int SoundGetBytesBuffered(); +// returns 0 is successful, else nonzero +void SoundFeedVoiceData(unsigned char* pSound,long lBytes); + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +#include + +// declare linux equivalents +extern __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +extern __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free + +#endif + +//////////////////// +// SPU2 Registers // +//////////////////// +#define REG_VP_VOLL 0x0000 +#define REG_VP_VOLR 0x0002 +#define REG_VP_PITCH 0x0004 +#define REG_VP_ADSR1 0x0006 +#define REG_VP_ADSR2 0x0008 +#define REG_VP_ENVX 0x000A +#define REG_VP_VOLXL 0x000C +#define REG_VP_VOLXR 0x000E +#define REG_C0_FMOD1 0x0180 +#define REG_C0_FMOD2 0x0182 +#define REG_C0_VMIXL1 0x0188 +#define REG_C0_VMIXL2 0x018A +#define REG_C0_VMIXR1 0x0190 +#define REG_C0_VMIXR2 0x0192 +#define REG_C0_MMIX 0x0198 +#define REG_C0_CTRL 0x019A +#define REG_C0_IRQA_HI 0x019C +#define REG_C0_IRQA_LO 0x019E +#define REG_C0_SPUON1 0x1A0 +#define REG_C0_SPUON2 0x1A2 +#define REG_C0_SPUOFF1 0x1A4 +#define REG_C0_SPUOFF2 0x1A6 +#define REG_C0_SPUADDR_HI 0x01A8 +#define REG_C0_SPUADDR_LO 0x01AA +#define REG_C0_SPUDATA 0x01AC +#define REG_C0_DMACTRL 0x01AE +#define REG_C0_ADMAS 0x01B0 +#define REG_C0_END1 0x0340 +#define REG_C0_END2 0x0342 +#define REG_C0_SPUSTAT 0x0344 +#define REG_C0_BVOLL 0x076C +#define REG_C0_BVOLR 0x076E + +//#define SPU2_TRANS_BY_DMA (0x0<<3) +//#define SPU2_TRANS_BY_IO (0x1<<3) +// +//#define SPU2_BLOCK_ONESHOT (0<<4) +//#define SPU2_BLOCK_LOOP (1<<4) +//#define SPU2_BLOCK_HANDLER (1<<7) +//#define SPU2_BLOCK_C0_VOICE1 ( 0x0<<8 ) +//#define SPU2_BLOCK_C0_VOICE3 ( 0x1<<8 ) +//#define SPU2_BLOCK_C1_SINL ( 0x2<<8 ) +//#define SPU2_BLOCK_C1_SINR ( 0x3<<8 ) +//#define SPU2_BLOCK_C1_VOICE1 ( 0x4<<8 ) +//#define SPU2_BLOCK_C1_VOICE3 ( 0x5<<8 ) +//#define SPU2_BLOCK_C0_MEMOUTL ( 0x6<<8 ) +//#define SPU2_BLOCK_C0_MEMOUTR ( 0x7<<8 ) +//#define SPU2_BLOCK_C0_MEMOUTEL ( 0x8<<8 ) +//#define SPU2_BLOCK_C0_MEMOUTER ( 0x9<<8 ) +//#define SPU2_BLOCK_C1_MEMOUTL ( 0xa<<8 ) +//#define SPU2_BLOCK_C1_MEMOUTR ( 0xb<<8 ) +//#define SPU2_BLOCK_C1_MEMOUTEL ( 0xc<<8 ) +//#define SPU2_BLOCK_C1_MEMOUTER ( 0xd<<8 ) + +//#define SPU2_BLOCK_COUNT(x) ( (x)<<12 ) +// +//#define SPU2_TRANS_STATUS_WAIT 1 +//#define SPU2_TRANS_STATUS_CHECK 0 +// +//#define SPU2_REV_MODE_OFF 0 +//#define SPU2_REV_MODE_ROOM 1 +//#define SPU2_REV_MODE_STUDIO_A 2 +//#define SPU2_REV_MODE_STUDIO_B 3 +//#define SPU2_REV_MODE_STUDIO_C 4 +//#define SPU2_REV_MODE_HALL 5 +//#define SPU2_REV_MODE_SPACE 6 +//#define SPU2_REV_MODE_ECHO 7 +//#define SPU2_REV_MODE_DELAY 8 +//#define SPU2_REV_MODE_PIPE 9 +//#define SPU2_REV_MODE_MAX 10 +//#define SPU2_REV_MODE_CLEAR_WA 0x100 +//#define SPU2_REV_MODE_CLEAR_CH0 0x000 +//#define SPU2_REV_MODE_CLEAR_CH1 0x200 +//#define SPU2_REV_MODE_CLEAR_CH_MASK 0x200 +// +//#define SPU2_REV_SIZE_OFF 0x80 +//#define SPU2_REV_SIZE_ROOM 0x26c0 +//#define SPU2_REV_SIZE_STUDIO_A 0x1f40 +//#define SPU2_REV_SIZE_STUDIO_B 0x4840 +//#define SPU2_REV_SIZE_STUDIO_C 0x6fe0 +//#define SPU2_REV_SIZE_HALL 0xade0 +//#define SPU2_REV_SIZE_SPACE 0xf6c0 +//#define SPU2_REV_SIZE_ECHO 0x18040 +//#define SPU2_REV_SIZE_DELAY 0x18040 +//#define SPU2_REV_SIZE_PIPE 0x3c00 +// +//#define SPU2_SOUNDOUT_TOPADDR 0x0 +//#define SPU2_SOUNDIN_TOPADDR 0x4000 +//#define SPU2_USERAREA_TOPADDR 0x5010 +// +//#define SPU2_INIT_COLD 0 +//#define SPU2_INIT_HOT 1 + +#define REG_C1_FMOD1 0x0580 +#define REG_C1_FMOD2 0x0582 +#define REG_S_NON 0x0184 +#define REG_C1_VMIXL1 0x0588 +#define REG_C1_VMIXL2 0x058A +#define REG_S_VMIXEL 0x018C +#define REG_C1_VMIXR1 0x0590 +#define REG_C1_VMIXR2 0x0592 +#define REG_S_VMIXER 0x0194 +#define REG_C1_MMIX 0x0598 +#define REG_C1_IRQA_HI 0x059C +#define REG_C1_IRQA_LO 0x059E +#define REG_C1_SPUON1 0x5A0 +#define REG_C1_SPUON2 0x5A2 +#define REG_C1_SPUOFF1 0x5A4 +#define REG_C1_SPUOFF2 0x5A6 +#define REG_C1_SPUADDR_HI 0x05A8 +#define REG_C1_SPUADDR_LO 0x05AA +#define REG_C1_SPUDATA 0x05AC +#define REG_C1_DMACTRL 0x05AE +#define REG_VA_SSA 0x01C0 +#define REG_VA_LSAX 0x01C4 +#define REG_VA_NAX 0x01C8 +#define REG_A_ESA 0x02E0 +#define REG_A_EEA 0x033C +#define REG_C1_END1 0x0740 +#define REG_C1_END2 0x0742 +#define REG_C1_CTRL 0x059A +#define REG_C1_ADMAS 0x05B0 +#define REG_C1_SPUSTAT 0x0744 +#define REG_P_MVOLL 0x0760 +#define REG_P_MVOLR 0x0762 +#define REG_P_EVOLL 0x0764 +#define REG_P_EVOLR 0x0766 +#define REG_P_AVOLL 0x0768 +#define REG_P_AVOLR 0x076A +#define REG_C1_BVOLL 0x0794 +#define REG_C1_BVOLR 0x0796 +#define REG_P_MVOLXL 0x0770 +#define REG_P_MVOLXR 0x0772 +#define SPDIF_OUT 0x07C0 +#define REG_IRQINFO 0x07C2 +#define SPDIF_MODE 0x07C6 +#define SPDIF_MEDIA 0x07C8 + +#define SPU_AUTODMA_ONESHOT 0 //spu2 +#define SPU_AUTODMA_LOOP 1 //spu2 +#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 + +#define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) +#define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) +//#define spu2Rs32(mem) (*(s32*)&spu2regs[(mem) & 0xffff]) +//#define spu2Ru32(mem) (*(u32*)&spu2regs[(mem) & 0xffff]) + +#define IRQINFO spu2Ru16(REG_IRQINFO) + +#define SPU2_GET32BIT(lo,hi) (((u32)(spu2Ru16(hi)&0x3f)<<16)|(u32)spu2Ru16(lo)) +#define SPU2_SET32BIT(value, lo, hi) { \ + spu2Ru16(hi) = ((value)>>16)&0x3f; \ + spu2Ru16(lo) = (value)&0xffff; \ + } \ + +#define C0_IRQA SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI) +#define C1_IRQA SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI) + +#define C0_SPUADDR SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI) +#define C1_SPUADDR SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI) + +#define C0_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI) +#define C1_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI) + +#define SPU_NUMBER_VOICES 48 + +struct SPU_CONTROL_ +{ + u16 extCd : 1; + u16 extAudio : 1; + u16 cdreverb : 1; + u16 extr : 1; // external reverb + u16 dma : 2; // 1 - no dma, 2 - write, 3 - read + u16 irq : 1; + u16 reverb : 1; + u16 noiseFreq : 6; + u16 spuUnmute : 1; + u16 spuon : 1; +}; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif +// the layout of each voice in wSpuRegs +struct _SPU_VOICE +{ + union + { + struct { + u16 Vol : 14; + u16 Inverted : 1; + u16 Sweep0 : 1; + } vol; + struct { + u16 Vol : 7; + u16 res1 : 5; + u16 Inverted : 1; + u16 Decrease : 1; // if 0, increase + u16 ExpSlope : 1; // if 0, linear slope + u16 Sweep1 : 1; // always one + } sweep; + u16 word; + } left, right; + + u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc + u16 res0 : 2; + + u16 SustainLvl : 4; + u16 DecayRate : 4; + u16 AttackRate : 7; + u16 AttackExp : 1; // if 0, linear + + u16 ReleaseRate : 5; + u16 ReleaseExp : 1; // if 0, linear + u16 SustainRate : 7; + u16 res1 : 1; + u16 SustainDec : 1; // if 0, inc + u16 SustainExp : 1; // if 0, linear + + u16 AdsrVol; + u16 Address; // add / 8 + u16 RepeatAddr; // gets reset when sample starts +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +// ADSR INFOS PER CHANNEL +struct ADSRInfoEx +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; +}; + +#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED)-4*sizeof(void*)) + +struct VOICE_PROCESSED +{ + VOICE_PROCESSED() + { + memset(this, 0, sizeof(VOICE_PROCESSED)); + } + + void SetVolume(int right); + void StartSound(); + void VoiceChangeFrequency(); + void InterpolateUp(); + void InterpolateDown(); + void FModChangeFrequency(int ns); + int iGetNoiseVal(); + void StoreInterpolationVal(int fa); + int iGetInterpolationVal(); + void Stop(); + + SPU_CONTROL_* GetCtrl(); + + // start save state + int leftvol, rightvol; // left right volumes + + int iSBPos; // mixing stuff + int SB[32+32]; + int spos; + int sinc; + + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int iOldNoise; // old noise val for this channel + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + + int iStartAddr, iLoopAddr, iNextAddr; + int bFMod; + + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + int memoffset; // if first core, 0, if second, 0x400 + int chanid; // channel id + + bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged; + bool bVolumeR, bVolumeL; + + // end save state + + /////////////////// + // Sound Buffers // + /////////////////// + u8* pStart; // start and end addresses + u8* pLoop, *pCurr; + + _SPU_VOICE* pvoice; +}; + +struct ADMA +{ + unsigned short * MemAddr; + int Index; + int AmountLeft; + int Enabled; // used to make sure that ADMA doesn't get interrupted with a writeDMA call +}; + +#endif /* __SPU2_H__ */ diff --git a/plugins/usb/USBlinuz/License.txt b/plugins/usb/USBlinuz/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/usb/USBlinuz/License.txt @@ -0,0 +1,342 @@ + 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/plugins/usb/USBlinuz/Linux/Config.c b/plugins/usb/USBlinuz/Linux/Config.c new file mode 100644 index 0000000000..b94952f291 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/Config.c @@ -0,0 +1,51 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include +#include +#include + +#include "USB.h" + +void LoadConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/USBlinuz.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + return; + } + fclose(f); +} + +void SaveConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/USBlinuz.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fclose(f); +} + diff --git a/plugins/usb/USBlinuz/Linux/Config.h b/plugins/usb/USBlinuz/Linux/Config.h new file mode 100644 index 0000000000..9eb36474fd --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/Config.h @@ -0,0 +1,20 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/usb/USBlinuz/Linux/Linux.c b/plugins/usb/USBlinuz/Linux/Linux.c new file mode 100644 index 0000000000..3c8388ec7b --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/Linux.c @@ -0,0 +1,75 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include +#include +#include +#include +#include + +#include "USB.h" + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgUSBlinuz"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgUSBlinuz"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgUSBlinuz", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgUSBlinuz file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void USBconfigure() { + ExecCfg("configure"); +} + +void USBabout() { + ExecCfg("about"); +} + diff --git a/plugins/usb/USBlinuz/Linux/Makefile b/plugins/usb/USBlinuz/Linux/Makefile new file mode 100644 index 0000000000..8c0ca594ea --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/Makefile @@ -0,0 +1,33 @@ + +PLUGIN = libUSBlinuz.so +CFG = cfgUSBlinuz +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../USB.o +OBJS+= Linux.o Config.o +CFGOBJS = conf.o interface.o support.o Config.o +DEPS:= $(OBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell gtk-config --cflags) -D__LINUX__ +CFGLIBS = $(shell gtk-config --libs) + +CC = gcc + +all: plugin cfg + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/usb/USBlinuz/Linux/callbacks.c b/plugins/usb/USBlinuz/Linux/callbacks.c new file mode 100644 index 0000000000..fa070a7842 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/usb/USBlinuz/Linux/callbacks.h b/plugins/usb/USBlinuz/Linux/callbacks.h new file mode 100644 index 0000000000..22cf74a988 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/usb/USBlinuz/Linux/conf.c b/plugins/usb/USBlinuz/Linux/conf.c new file mode 100644 index 0000000000..6eb4191bd2 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/conf.c @@ -0,0 +1,136 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" +#include "USB.h" +#include "Config.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "USB Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gchar *str; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CFGconfigure() { + Conf = create_Config(); + + LoadConfig(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/usb/USBlinuz/Linux/interface.c b/plugins/usb/USBlinuz/Linux/interface.c new file mode 100644 index 0000000000..a73c0861ed --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/interface.c @@ -0,0 +1,219 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/usb/USBlinuz/Linux/interface.h b/plugins/usb/USBlinuz/Linux/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/usb/USBlinuz/Linux/support.c b/plugins/usb/USBlinuz/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/usb/USBlinuz/Linux/support.h b/plugins/usb/USBlinuz/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/usb/USBlinuz/Linux/usblinuz.glade b/plugins/usb/USBlinuz/Linux/usblinuz.glade new file mode 100644 index 0000000000..715af05ed6 --- /dev/null +++ b/plugins/usb/USBlinuz/Linux/usblinuz.glade @@ -0,0 +1,300 @@ + + + + + DEV9linuz + dev9linuz + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + DEV9config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox1 + 5 + True + 5 + + + GtkLabel + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Eth + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + + GtkFrame + frame3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox2 + 5 + True + 5 + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Hdd + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + True + True + 0 + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + DEV9about + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/usb/USBlinuz/PS2Edefs.h b/plugins/usb/USBlinuz/PS2Edefs.h new file mode 100644 index 0000000000..a52d86afe8 --- /dev/null +++ b/plugins/usb/USBlinuz/PS2Edefs.h @@ -0,0 +1,684 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.5.5 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || \ + defined(SPU2defs)|| defined(CDVDdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FIREWIRE 0x40 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0005 +#define PS2E_PAD_VERSION 0x0002 +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0003 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FIREWIRE_VERSION 0x0002 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +typedef struct { // NOT bcd coded + u8 minute; + u8 second; + u8 frame; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usualy 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdLoc:track type +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif +/* Firewire plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FIREWIREdefs +// basic funcs + +s32 CALLBACK FireWireinit(); +s32 CALLBACK FireWireopen(void *pDsp); +void CALLBACK FireWireclose(); +void CALLBACK FireWireshutdown(); +u32 CALLBACK FireWireread32(u32 addr); +void CALLBACK FireWirewrite32(u32 addr, u32 value); +void CALLBACK FireWireirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FireWirefreeze(int mode, freezeData *data); +void CALLBACK FireWireconfigure(); +void CALLBACK FireWireabout(); +s32 CALLBACK FireWiretest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FireWire +typedef s32 (CALLBACK* _FireWireinit)(); +typedef s32 (CALLBACK* _FireWireopen)(void *pDsp); +typedef void (CALLBACK* _FireWireclose)(); +typedef void (CALLBACK* _FireWireshutdown)(); +typedef u32 (CALLBACK* _FireWireread32)(u32 mem); +typedef void (CALLBACK* _FireWirewrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FireWireirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FireWirefreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FireWireconfigure)(); +typedef s32 (CALLBACK* _FireWiretest)(); +typedef void (CALLBACK* _FireWireabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetType CDVDgetType; +_CDVDgetTrayStatus CDVDgetTrayStatus; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FireWire +_FireWireinit FireWireinit; +_FireWireopen FireWireopen; +_FireWireclose FireWireclose; +_FireWireshutdown FireWireshutdown; +_FireWireread32 FireWireread32; +_FireWirewrite32 FireWirewrite32; +_FireWireirqCallback FireWireirqCallback; + +_FireWireconfigure FireWireconfigure; +_FireWirefreeze FireWirefreeze; +_FireWiretest FireWiretest; +_FireWireabout FireWireabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/usb/USBlinuz/PS2Etypes.h b/plugins/usb/USBlinuz/PS2Etypes.h new file mode 100644 index 0000000000..443ad4599a --- /dev/null +++ b/plugins/usb/USBlinuz/PS2Etypes.h @@ -0,0 +1,31 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__WIN32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#elif defined(__LINUX__) + +typedef char s8; +typedef short s16; +typedef long s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/usb/USBlinuz/ReadMe.txt b/plugins/usb/USBlinuz/ReadMe.txt new file mode 100644 index 0000000000..826f2c8187 --- /dev/null +++ b/plugins/usb/USBlinuz/ReadMe.txt @@ -0,0 +1,36 @@ +USBlinuz v0.4 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "usblinuz.so" (linux) or "usblinuz.dll" (win32) or usblinuz.dll (win64) + at the Plugin directory of the Emulator to use it. + +Changes: +------- +v0.4 (shadow) +*project files for vs2005 beta1 .64bit dll should work okay (not tested!) + + v0.3: (shadow) + *Up to specifications 0.5.5 + *Added Logging option and ini saving + + v0.2: + *Added partial emulation of Usb + + v0.1: + * First Release + * Tested with Pcsx2 + +Authors: +------- + + linuzappz + shadow + + + diff --git a/plugins/usb/USBlinuz/USB.c b/plugins/usb/USBlinuz/USB.c new file mode 100644 index 0000000000..1d4ac34b3a --- /dev/null +++ b/plugins/usb/USBlinuz/USB.c @@ -0,0 +1,446 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include + +#include "USB.h" + + +const unsigned char version = PS2E_USB_VERSION; +const unsigned char revision = 0; +const unsigned char build = 4; // increase that with each version + +static char *libraryName = "USBlinuz Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_USB; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log) return; + + va_start(list, fmt); + vfprintf(usbLog, fmt, list); + va_end(list); +} + +s32 CALLBACK USBinit() { + LoadConfig(); +#ifdef USB_LOG + usbLog = fopen("logs/usbLog.txt", "w"); + setvbuf(usbLog, NULL, _IONBF, 0); + USB_LOG("usblinuz plugin version %d,%d\n",revision,build); + USB_LOG("USBinit\n"); +#endif + + + usbR = (s8*)malloc(0x10000); + if (usbR == NULL) { + SysMessage("Error allocating memory"); return -1; + } + memset(usbR, 0, 0x10000); + ohci = (struct ohci_regs*)usbR; + ohci->revision = 0x10; + ohci->roothub.a = 0x2; + + return 0; +} + +void CALLBACK USBshutdown() { + free(usbR); +#ifdef USB_LOG + fclose(usbLog); +#endif +} + +s32 CALLBACK USBopen(void *pDsp) { +#ifdef USB_LOG + USB_LOG("USBopen\n"); +#endif + + return 0; +} + +void CALLBACK USBclose() { +} + +u8 CALLBACK USBread8(u32 addr) { + u8 hard; + + switch (addr) { + default: + hard = usbRu8(addr); +#ifdef USB_LOG + USB_LOG("*Unknown 8bit read at address %lx value %x\n", addr, hard); +#endif + return hard; + } + +#ifdef USB_LOG + USB_LOG("*Known 8bit read at address %lx value %x\n", addr, hard); +#endif + return hard; +} + +u16 CALLBACK USBread16(u32 addr) { + u16 hard; + + switch (addr) { + default: + hard = usbRu16(addr); +#ifdef USB_LOG + USB_LOG("*Unknown 16bit read at address %lx value %x\n", addr, hard); +#endif + return hard; + } + +#ifdef USB_LOG + USB_LOG("*Known 16bit read at address %lx value %x\n", addr, hard); +#endif + return hard; +} + +u32 CALLBACK USBread32(u32 addr) { + u32 hard; + int i; + + if (addr >= 0x1f801654 && + addr < 0x1f801690) { + i = (addr - 0x1f801654) / 4; + hard = ohci->roothub.portstatus[i]; +#ifdef USB_LOG + USB_LOG("ohci->roothub.portstatus[%d] read32 %x\n", i, hard); +#endif + return hard; + } + + switch (addr) { +#ifdef USB_LOG + case 0x1f801600: + hard = ohci->revision; + USB_LOG("ohci->revision read32 %x\n", hard); + return hard; +#endif + +#ifdef USB_LOG + case 0x1f801604: + hard = ohci->control; + USB_LOG("ohci->control read32 %x\n", hard); + return hard; +#endif + + case 0x1f801608: + hard = 0; +#ifdef USB_LOG + USB_LOG("ohci->cmdstatus read32 %x\n", hard); +#endif + return hard; + +#ifdef USB_LOG + case 0x1f80160c: + hard = ohci->intrstatus; + USB_LOG("ohci->intrstatus read32 %x\n", hard); + return hard; + + case 0x1f801610: + hard = ohci->intrenable; + USB_LOG("ohci->intrenable read32 %x\n", hard); + return hard; + + case 0x1f801648: + hard = ohci->roothub.a; + USB_LOG("ohci->roothub.a read32 %x\n", hard); + return hard; + + case 0x1f80164C: + hard = ohci->roothub.b; + USB_LOG("ohci->roothub.b read32 %x\n", hard); + return hard; + + case 0x1f801650: + hard = ohci->roothub.status; + USB_LOG("ohci->roothub.status read32 %x\n", hard); + return hard; +#endif + + default: + hard = usbRu32(addr); +#ifdef USB_LOG + USB_LOG("*Unkwnown 32bit read at address %lx: %lx\n", addr, hard); +#endif + return hard; + } + +#ifdef USB_LOG + USB_LOG("*Known 32bit read at address %lx: %lx\n", addr, hard); +#endif + return hard; +} + +void CALLBACK USBwrite8(u32 addr, u8 value) { + switch (addr) { + default: + usbRu8(addr) = value; +#ifdef USB_LOG + USB_LOG("*Unknown 8bit write at address %lx value %x\n", addr, value); +#endif + return; + } + usbRu8(addr) = value; +#ifdef USB_LOG + USB_LOG("*Known 8bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite16(u32 addr, u16 value) { + switch (addr) { + default: + usbRu16(addr) = value; +#ifdef USB_LOG + USB_LOG("*Unknown 16bit write at address %lx value %x\n", addr, value); +#endif + return; + } + usbRu16(addr) = value; +#ifdef USB_LOG + USB_LOG("*Known 16bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite32(u32 addr, u32 value) { + int i; + + if (addr >= 0x1f801654 && + addr < 0x1f801690) { + i = (addr - 0x1f801654) / 4; +// ohci->roothub.portstatus[i] = value; + ohci->intrstatus|= OHCI_INTR_SF; +#ifdef USB_LOG + USB_LOG("ohci->roothub.portstatus[%d] write32 %x\n", i, value); +#endif + return; + } + + switch (addr) { + case 0x1f801600: // ohci->revision (read only) + return; + case 0x1f801604: +#ifdef USB_LOG + USB_LOG("ohci->control write32 %x\n", value); +#endif + ohci->control = value; + if ((ohci->control & OHCI_CTRL_HCFS) == OHCI_USB_OPER) { + USBirq(PSXCLK / 1000000); + ohci->roothub.portstatus[0] = 0x1; + ohci->intrstatus|= OHCI_INTR_RHSC; + } + return; + + case 0x1f80160c: +#ifdef USB_LOG + USB_LOG("ohci->intrstatus write32 %x\n", value); +#endif + ohci->intrstatus&= ~value; + return; + + case 0x1f801610: +#ifdef USB_LOG + USB_LOG("ohci->intrenable write32 %x\n", value); +#endif + for (i=0; i<32; i++) { + if (value & (1<intrenable|= 1<intrdisable write32 %x\n", value); +#endif + for (i=0; i<32; i++) { + if (value & (1<intrenable&= ~(1<hcca = value; + hcca = (struct ohci_hcca*)&ram[ohci->hcca]; + ohci->intrstatus|= OHCI_INTR_SF; +#ifdef USB_LOG + USB_LOG("ohci->hcca write32 %x\n", value); +#endif + return; + +#ifdef USB_LOG + case 0x1f801608: + ohci->cmdstatus = value; + USB_LOG("ohci->cmdstatus write32 %x\n", value); + return; + + case 0x1f801630: + ohci->donehead = value; + USB_LOG("ohci->donehead write32 %x\n", value); + return; + + case 0x1f801634: + ohci->fminterval = value; + USB_LOG("ohci->fminterval write32 %x\n", value); + return; + + case 0x1f801640: + ohci->periodicstart = value; + USB_LOG("ohci->periodicstart write32 %x\n", value); + return; + + case 0x1f801644: + ohci->lsthresh = value; + USB_LOG("ohci->lsthresh write32 %x\n", value); + return; + + case 0x1f801648: + ohci->roothub.a = value; + USB_LOG("ohci->roothub.a write32 %x\n", value); + return; + + case 0x1f80164C: + ohci->roothub.b = value; + USB_LOG("ohci->roothub.b write32 %x\n", value); + return; + + case 0x1f801650: + ohci->roothub.status = value; + USB_LOG("ohci->roothub.status write32 %x\n", value); + return; +#endif + default: + usbRu32(addr) = value; +#ifdef USB_LOG + USB_LOG("*Unknown 32bit write at address %lx write %x\n", addr, value); +#endif + return; + } + usbRu32(addr) = value; +#ifdef USB_LOG + USB_LOG("*Known 32bit write at address %lx value %lx\n", addr, value); +#endif +} + +void CALLBACK USBirqCallback(USBcallback callback) { + USBirq = callback; +} + +int CALLBACK _USBirqHandler(void) { + if ((ohci->control & OHCI_CTRL_HCFS) == OHCI_USB_OPER) { + USBirq(PSXCLK / 1000000); + } + +#ifdef USB_LOG +// USB_LOG("_USBirqHandler: %x\n", ohci->intrenable); +#endif + + if (ohci->fmnumber == 0xffff) { + ohci->fmnumber = 0; + ohci->intrstatus|= OHCI_INTR_FNO; + } else { + ohci->fmnumber++; + } + + if (ohci->intrenable & OHCI_INTR_MIE && + ohci->intrenable & OHCI_INTR_SF && + ohci->intrstatus & OHCI_INTR_SF) { +#ifdef USB_LOG + USB_LOG("_USBirqHandler: SOF\n"); +#endif + + return 1; + } + + if (ohci->intrenable & OHCI_INTR_MIE && + ohci->intrenable & OHCI_INTR_FNO && + ohci->intrstatus & OHCI_INTR_FNO) { +#ifdef USB_LOG + USB_LOG("_USBirqHandler: FNO\n"); +#endif + + return 1; + } + + return 0; +} + +USBhandler CALLBACK USBirqHandler(void) { + return (USBhandler)_USBirqHandler; +} + +void CALLBACK USBsetRAM(void *mem) { + ram = mem; +} + +// extended funcs + +char USBfreezeID[] = "USB STv0"; + +typedef struct { + u8 id[32]; + u8 usbR[0x10000]; + usbStruct usb; +} USBfreezeData; + +s32 CALLBACK USBfreeze(int mode, freezeData *data) { + USBfreezeData *usbd; + + if (mode == FREEZE_LOAD) { + usbd = (USBfreezeData*)data->data; + if (data->size != sizeof(USBfreezeData)) return -1; + if (strcmp(usbd->id, USBfreezeID)) return -1; + memcpy(usbR, usbd->usbR, 0x10000); + memcpy(&usb, &usbd->usb, sizeof(usbStruct)); + } else + if (mode == FREEZE_SAVE) { + data->size = sizeof(USBfreezeData); + data->data = malloc(data->size); + if (data->data == NULL) return -1; + usbd = (USBfreezeData*)data->data; + strcpy(usbd->id, USBfreezeID); + memcpy(usbd->usbR, usbR, 0x10000); + memcpy(&usbd->usb, &usb, sizeof(usbStruct)); + } + + return 0; +} + + +s32 CALLBACK USBtest() { + return 0; +} + diff --git a/plugins/usb/USBlinuz/USB.h b/plugins/usb/USBlinuz/USB.h new file mode 100644 index 0000000000..4dd5d93210 --- /dev/null +++ b/plugins/usb/USBlinuz/USB.h @@ -0,0 +1,197 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + + +#ifndef __USB_H__ +#define __USB_H__ + +#include + +#define USBdefs +#include "PS2Edefs.h" + +#ifdef __WIN32__ + +#define usleep(x) Sleep(x / 1000) +#include +#include + +#else + +#include + +#define __inline inline + +#endif + +#define USB_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; + +u8 *usbR; +u8 *ram; + +typedef struct { + int unused; +} usbStruct; + +usbStruct usb; + +#define usbRs8(mem) usbR[(mem) & 0xffff] +#define usbRs16(mem) (*(s16*)&usbR[(mem) & 0xffff]) +#define usbRs32(mem) (*(s32*)&usbR[(mem) & 0xffff]) +#define usbRu8(mem) (*(u8*) &usbR[(mem) & 0xffff]) +#define usbRu16(mem) (*(u16*)&usbR[(mem) & 0xffff]) +#define usbRu32(mem) (*(u32*)&usbR[(mem) & 0xffff]) + + +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2001 David Brownell + * + * usb-ohci.h + */ + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ + + +#define NUM_INTS 32 /* part of the OHCI standard */ +struct ohci_hcca { + u32 int_table[NUM_INTS]; /* Interrupt ED table */ + u16 frame_no; /* current frame number */ + u16 pad1; /* set to 0 on each frame_no change */ + u32 done_head; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +}; + +/* + * Maximum number of root hub ports. + */ +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region. This is Memory Mapped I/O. You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { + /* control and status registers */ + u32 revision; + u32 control; + u32 cmdstatus; + u32 intrstatus; + u32 intrenable; + u32 intrdisable; + /* memory pointers */ + u32 hcca; + u32 ed_periodcurrent; + u32 ed_controlhead; + u32 ed_controlcurrent; + u32 ed_bulkhead; + u32 ed_bulkcurrent; + u32 donehead; + /* frame counters */ + u32 fminterval; + u32 fmremaining; + u32 fmnumber; + u32 periodicstart; + u32 lsthresh; + /* Root hub ports */ + struct ohci_roothub_regs { + u32 a; + u32 b; + u32 status; + u32 portstatus[MAX_ROOT_PORTS]; + } roothub; +}; + + +/* OHCI CONTROL AND STATUS REGISTER MASKS */ + +/* + * HcControl (control) register masks + */ +#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ +#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ +#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ +#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ + +/* pre-shifted values for HCFS */ +# define OHCI_USB_RESET (0 << 6) +# define OHCI_USB_RESUME (1 << 6) +# define OHCI_USB_OPER (2 << 6) +# define OHCI_USB_SUSPEND (3 << 6) + +/* + * HcCommandStatus (cmdstatus) register masks + */ +#define OHCI_HCR (1 << 0) /* host controller reset */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ + +/* + * masks used with interrupt registers: + * HcInterruptStatus (intrstatus) + * HcInterruptEnable (intrenable) + * HcInterruptDisable (intrdisable) + */ +#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ +#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ +#define OHCI_INTR_SF (1 << 2) /* start frame */ +#define OHCI_INTR_RD (1 << 3) /* resume detect */ +#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ +#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ +#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ +#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ + +/**********************/ + +struct ohci_hcca *hcca; +struct ohci_regs *ohci; + +#define PSXCLK 36864000 /* 36.864 Mhz */ + +USBcallback USBirq; + +void SaveConfig(); +void LoadConfig(); + +FILE *usbLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/usb/USBlinuz/Win32/Config.c b/plugins/usb/USBlinuz/Win32/Config.c new file mode 100644 index 0000000000..c46552a4a6 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/Config.c @@ -0,0 +1,51 @@ +#include + +#include "USB.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\usblinuz.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\usblinuz.ini"); + fp=fopen("inis\\usblinuz.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.def b/plugins/usb/USBlinuz/Win32/USBlinuz.def new file mode 100644 index 0000000000..7de3002776 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.def @@ -0,0 +1,27 @@ +; USBlinuz.def : Declares the module parameters for the DLL. + +LIBRARY "USBlinuz" +DESCRIPTION 'USBlinuz Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + USBinit @5 + USBshutdown @6 + USBopen @7 + USBclose @8 + USBread8 @9 + USBread16 @10 + USBread32 @11 + USBwrite8 @12 + USBwrite16 @13 + USBwrite32 @14 + USBirqCallback @15 + USBirqHandler @16 + USBsetRAM @17 + + USBconfigure @18 + USBtest @19 + USBabout @20 diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.dsp b/plugins/usb/USBlinuz/Win32/USBlinuz.dsp new file mode 100644 index 0000000000..293a975c5c --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.dsp @@ -0,0 +1,99 @@ +# Microsoft Developer Studio Project File - Name="USBlinuz" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=USBlinuz - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "USBlinuz.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "USBlinuz.mak" CFG="USBlinuz - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "USBlinuz - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cwcl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USBlinuz_EXPORTS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "./" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USBlinuz_EXPORTS" /D "__WIN32__" /D VERSION=0 /D BUILD=2 /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x408 /d "NDEBUG" +# ADD RSC /l 0x408 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=cwlink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" +# SUBTRACT LINK32 /nodefaultlib +# Begin Target + +# Name "USBlinuz - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Config.c +# End Source File +# Begin Source File + +SOURCE=..\USB.c +# End Source File +# Begin Source File + +SOURCE=.\USBlinuz.def +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\PS2Edefs.h +# End Source File +# Begin Source File + +SOURCE=..\USB.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\USBlinuz.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.dsw b/plugins/usb/USBlinuz/Win32/USBlinuz.dsw new file mode 100644 index 0000000000..4a0da3b6c9 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "USBlinuz"=".\USBlinuz.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.rc b/plugins/usb/USBlinuz/Win32/USBlinuz.rc new file mode 100644 index 0000000000..d6255e6131 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.rc @@ -0,0 +1,120 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "USBconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,48,100,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,100,50,14 + CONTROL "Enable Logging (for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,144,15 +END + +IDD_ABOUT DIALOG 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "USBabout" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "USBlinuz Driver",IDC_NAME,70,10,50,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Author: linuzappz ",IDC_STATIC, + 20,20,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.sln b/plugins/usb/USBlinuz/Win32/USBlinuz.sln new file mode 100644 index 0000000000..d2ff64b2b6 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz.vcproj", "{F7181922-7377-4F67-9F50-10997B4613D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.ActiveCfg = Release|Win32 + {F7181922-7377-4F67-9F50-10997B4613D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.suo b/plugins/usb/USBlinuz/Win32/USBlinuz.suo new file mode 100644 index 0000000000000000000000000000000000000000..3e859b804e8d71250e233ed6a5ed1df6e13a30d2 GIT binary patch literal 8704 zcmeHMNo*WN6#ZkzB+g=I4}`6WZ5%?zalFM&SQL+)Mc7I3m^eZ{Fdny^NygKonX$7= z+>nq!9K(r4NJuOqNQe^(QpABAP(qFfA#y-ST*84RkY#wUs%y4*#%;$&80C+CcXd^D z{pw%;zyGV|@}(6&zVqq&t5QJENV(ijSIT`k^*)rzik6F%p}^2z9GilBIp=8*<& zVXh0@HLSp$>%9=X2wVwX3SJCe0$v8L23LW(=Hz=czctV&4t^=Iq+4RRC*%ZH*E_A1 zij2?GMoQ6vi?98%qUkGNIXlsiKnEbvkt4Df(nnD0mgBm?<8`f+`BtGXhvQ0kd`$pf ziuxraNjWM#62UzsFW_opPNqIN#elUyLCU4yc$H7gq<@k2%0UTAuXMSZh%4zStU{;K z%rSR9y7!&eP56GwrB8a5pNrSVkGUqqfo3r4hyg8b+4w)PfEYko)VFzeWlnhw%4@;v z!1se60IvtPg4zFJ+#dly3bw$Hfj59_z-+H`@AbHE1U~`Z1bz~{8N37B0Nw&_1aAeK zd6;_}>b8N~!5!f3VADn&-J`4qu6^+CmK(RK1MgosyXD+V`#yuJrbWL77$s&-w5jSY zdm<9Ht$-6tC7h^ox#~dTL^2hMT77ohNu*TWg04_1L{WF*~NmUN#Vk4Liq@+3pMW^!N5~ zu&O{b5+8CxiD9cR5*uaJ!rgYvPK2U4`4FpTKt8KlG65-Jv`<8R>aaM~1j6h4#lf;!O~`A6Hr}jRLSgm47e_ zc(p(F{lcebQC$8B=#-cQkS#&R{wbSOqHCs!SW(RXdts$xkjgxGz}1B#%)%z8&947x z>E7h8z)=0}aP)T~aROSW^=CcBWX3k^Dh0nH7Of986{XgXfW zF?bG8NOx0LIM!6pcO$DpRQMQHGS*3F`L{l#yXka&S>~wY+;g>MU-#6O(P9_5dK>he z!cuKR`q>Wd05mm;AJ5I;Z78*%wM~^eP-+Ei`O&WtJv&g_iS{-;H^cqf<&2!hwj+qz zs4}>5ISJ64z_Q0-7Tg@2MtP3XgTjm>*X9pEcoI`$&QUB9HNyUg{nN2O`d$rR0+o_) z_F`S|j1+h>YM6olJ&1vxat9;MF`k)k)P6RCFCJC+N6Gr@CzH-SNf`}B?Te^`$$RD3 zK7_~bT>RS)j5~su$XHp-$MfILe|lsF-(QO%UNpm$P7lXn07D3@h4yJ`8eo~H@jC@O z?u0$J!w)q3Vc`te^oyQ8yL#@+oft+QQLt&P4EV6>YBKL%=qHQ624f0 z@23ZIf60Abo%>zieAu$`+WC)vVB4Fh<37@mX~P1aBo_Cg5LN5U%p-)AVEz%$oK1*4 zjnh!l4z(wqP1kQgtUabOo~+#cD*MZo%H8(lbJNj*eHS4Y6fDH-!O{+Sc9utMkUm5( zW`aC*v0*qGZaZZ(+_2%wc*vj@j%5sNsO^9x%SrE_jtuNQEb$d3?E!@Xz8|3&tSn_W? z+yX6<-!r8@+|m-cu1e+dC+@V|a``LM>+ekIMy7N#Q@Z7rmPpzyZN~e%VR=#Ii%GQy zvw=m^i$Xa6^f4!5O!pf9cov85icFTvJeWI6X5Q4UMmy%arOBMXQZ}h{Z{13qysZ40 zjvG@_LqHoFZ04hJwOH1lm9k+5@i+JT?*xwQ*j`F2XCU8?fw#Ng&;11T&Amr%?sKP= zYCArNUY)@1Frp?;N$kw|5ogO2TmFwQoHv%%sX5t>;2r8!p9mbfL|oT2lQRguc{l#& z4FUE1Ci6e2|9`U=KoB;EFOwY=7FU%v;s%6moeOp$uj@v>w-aeu0C}Ka<%X>Yh};=< zgP99= literal 0 HcmV?d00001 diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz.vcproj b/plugins/usb/USBlinuz/Win32/USBlinuz.vcproj new file mode 100644 index 0000000000..f655f04b07 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz.vcproj @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.sln b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.sln new file mode 100644 index 0000000000..4b301cc738 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2002.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.vcproj b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.vcproj new file mode 100644 index 0000000000..aa11eec111 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2002.vcproj @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.ncb b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.ncb new file mode 100644 index 0000000000000000000000000000000000000000..d3382ad9d93b41163206e3449e55193ccc912c9c GIT binary patch literal 52224 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 HlfeH2*Qqz? literal 0 HcmV?d00001 diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.sln b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.sln new file mode 100644 index 0000000000..4299974456 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2003.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.suo b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.suo new file mode 100644 index 0000000000000000000000000000000000000000..ed9bc2f7b89c18175ad4b2f9b511123dc58b85a7 GIT binary patch literal 8704 zcmeHMOKg-?6h6~ZX+a7UM68M<A2D%dT(~f@Fc1@28d(^ZxbT7U7{BlS|DE^a?*n3!p61Md|9kI$&$;)W z^PO{VuU%dL%ST_d-jE_XBK2}F(6?NM5jkJs9dxhEP2SVs)dZQB2d1;haQKi6Bgx8#){L3tDSQSfH) zW8hZsycOIA-Ui+d-T~eT-UWUJ%)Zas&vraL;OD@5?Yd4pyTIMx z9`HW!esC}N0QewS%gbM@<#Hx7+}85?PYq)O?|m?I#XK>56H7HG`rXSYF@IuQS?e=q zBO$}>jmOf-xT#!jg)fi}aM)ERM@QWL&?zITUf1{{0W&`B9tcO$@gzH}8;u7ers1A2 zg6_e1GO9jrDtKGvjYkvlm=Q~>#x)a>SU7$*mFvFZ#qrS*4%X~7BZ*)>m6RO-L zohUDahJkd904C(bfxUi(KeHG;gi>vC+xSBapg-0A!pa*zwLAJCC8*{+tt3wXkJFHS z3U6w&Y79vETti})Q~AtuHrnGB%O~m@(BTaBBCggrT~&`=kk42`jC3lWaq^`K@)`fQ z@(HX$1RBr|s?iQ);gqYXT3_A9*rVgmLhVUt3}P;(+R;hG zI@%VaehNH=dAbn;8GUEa+r*n6bu$uH^LGR7UqMzdj`~g@{$3#cB>IPd@RMqsG@dDp z7gC<^&I8wh_G)65Q%VD^iGCOPzi4FXS&SCN_RpP)VeS3cn;EsL)lmTU=VGqFC_o#; zqb9NM*DkADW%=i@ro^NQz-vpHkNwkMEBXH@tTYO#%!4hA4dabjSb5rm`P2598#$dn z^Tly{IQn}UGLu+!T7S+{bY^V8uF~);VgY;dH>b@($k)E_RQ?9YCSEQU@gAU<7E)I{ z*8O~M5EVYcO2%f{Q2(V1P@c)`tjk_?eE#xv*Y_jWRlg?gGpNyZ9szj}Ak>dEvqSoj zc(wzkx{!qSqSUS0yeRb{9X)`zc2(1jjqF7~{`Dd0-w!~$C>Kfs{A)6cZP$S3QEv$t z36Dw_&@#7V!Ac)I`0fJ!&O?KKXxfYMdwm!(1W%9JmX&Yw$IzAn9#o4&dl7$lCSV@t z)c)vu@7o4aO};*h`QRC8a5?h8{+n&tPUSy^{?FTk5$Bk5={Z_{HicPFEBvEmD-M^F zE&~5o^VU9CzE@$b8?Qlo{zrjvrx6nwD=YbU;n#(4Tjn8uH-;F{!@ve$oBNclb)wXP zKOeXq^}WhI+f~?Q=p9rwJ*Yi^KAo^!k&e!;?jD@D@_c7kHQ%X|)+OaT`H6PEag_BY zdenkfQ}2wUX9M=1$mF-xyD(Q@#W+mRoQR8RNgj}*UgHK?AxgB4Hi?kL-GRTF6M|H z83WET6Xvax0Wi*)mj@YSzd|~met6nrP|B_R;YHUamwU}c51w@T5HpC2vzUVydh?*n z9bhI{IKxAzsYZms-!^Xl@w2wJp|5_uadBrb+O15v`AVyKr>X7eyP3CdUH$gs0cFTM zWfq@>MQ&FUP^0Ztw*Y?^a{4aTr&{Q?{$KJS<#GD01=)Q5X^iJJQ`urloxu$F;@qMT z?muw@Y@O+y#$VpWQ7@9ta+wG7_Jf%>vti5IneSF7-oH{Va|);O_n>d1jhDxfPg80D z-e!QcJ{GRz^6W}lY@J8^&7Xg<^;D8mslH_%@;fk?SuR1ZB&13`hv7YMc`UK+d~j7FUo^@e9!pT8{FyENWtUdVEmf+QzwzW(_3}@)*T31)?QH2zwshAn zt(J^kq6G{=ml&9L6sB$UR^C^tr8SQe=+zIcLx`BXAu_UeXVjaw)%+hyxL_>Hp7gDL z1mAGhya_MF$$SJ}UbXV8hD9r(lUEs!mTA5#p#RUM|NrGj?m-OZ9V|~pwGfc_Pu$hy aL=WZ!`u@>L|5|;tY(8uCy&vsMS^j_FZ8-G+ literal 0 HcmV?d00001 diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.vcproj b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.vcproj new file mode 100644 index 0000000000..c35bec4568 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2003.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.sln b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.sln new file mode 100644 index 0000000000..411b3fd51a --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2005beta1.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + amd64|Win32 = amd64|Win32 + amd64|Win64 (AMD64) = amd64|Win64 (AMD64) + Debug|Win32 = Debug|Win32 + Debug|Win64 (AMD64) = Debug|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win32.ActiveCfg = amd64|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win32.Build.0 = amd64|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win64 (AMD64).ActiveCfg = amd64|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win64 (AMD64).Build.0 = amd64|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win64 (AMD64).ActiveCfg = Debug|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win64 (AMD64).Build.0 = Debug|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.Build.0 = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.vcproj b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.vcproj new file mode 100644 index 0000000000..c2d54ab8ce --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/USBlinuz_vc2005beta1.vcproj @@ -0,0 +1,566 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBlinuz/Win32/Win32.c b/plugins/usb/USBlinuz/Win32/Win32.c new file mode 100644 index 0000000000..8cee4787db --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/Win32.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "USB.h" +#include "resource.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "USBlinuz Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK USBconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK USBabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/usb/USBlinuz/Win32/resource.h b/plugins/usb/USBlinuz/Win32/resource.h new file mode 100644 index 0000000000..bf37b53354 --- /dev/null +++ b/plugins/usb/USBlinuz/Win32/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by USBlinuz.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/usb/USBnull/License.txt b/plugins/usb/USBnull/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/usb/USBnull/License.txt @@ -0,0 +1,342 @@ + 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/plugins/usb/USBnull/Linux/Config.c b/plugins/usb/USBnull/Linux/Config.c new file mode 100644 index 0000000000..c4abd824fc --- /dev/null +++ b/plugins/usb/USBnull/Linux/Config.c @@ -0,0 +1,59 @@ +/* USBnull + * Copyright (C) 2002-2004 USBnull 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 +#include +#include +#include +#include + +#include "USB.h" + +void LoadConfig() { +/* FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + strcpy(IsoFile, DEV_DEF); + strcpy(CdDev, CDDEV_DEF); + return; + } + fscanf(f, "IsoFile = %[^\n]\n", IsoFile); + fscanf(f, "CdDev = %[^\n]\n", CdDev); + if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix + if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); + fclose(f);*/ +} + +void SaveConfig() { +/* FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fprintf(f, "IsoFile = %s\n", IsoFile); + fprintf(f, "CdDev = %s\n", CdDev); + fclose(f);*/ +} + diff --git a/plugins/usb/USBnull/Linux/Config.h b/plugins/usb/USBnull/Linux/Config.h new file mode 100644 index 0000000000..8382b720c5 --- /dev/null +++ b/plugins/usb/USBnull/Linux/Config.h @@ -0,0 +1,20 @@ +/* USBnull + * Copyright (C) 2002-2004 USBnull 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 + */ + +void SaveConfig(); +void LoadConfig(); diff --git a/plugins/usb/USBnull/Linux/Linux.c b/plugins/usb/USBnull/Linux/Linux.c new file mode 100644 index 0000000000..1a07ba1500 --- /dev/null +++ b/plugins/usb/USBnull/Linux/Linux.c @@ -0,0 +1,74 @@ +/* USBnull + * Copyright (C) 2002-2004 USBnull 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 +#include +#include +#include +#include +#include +#include + + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgUSBnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgUSBnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgUSBnull", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgUSBnull file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void USBconfigure() { + ExecCfg("configure"); +} + +void USBabout() { + ExecCfg("about"); +} + diff --git a/plugins/usb/USBnull/Linux/Makefile b/plugins/usb/USBnull/Linux/Makefile new file mode 100644 index 0000000000..bcf7a489a3 --- /dev/null +++ b/plugins/usb/USBnull/Linux/Makefile @@ -0,0 +1,35 @@ + +PLUGIN = libUSBnull.so +CFG = cfgUSBnull +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../USB.o +OBJS+= Config.o Linux.o +CFGOBJS = conf.o interface.o support.o +DEPS:= $(OBJS:.o=.d) +CFGDEPS:= $(CFGOBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) + +CC = gcc + +all: plugin cfg +install: all + +plugin: ${OBJS} +# rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} +# rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +#-include ${DEPS} diff --git a/plugins/usb/USBnull/Linux/callbacks.c b/plugins/usb/USBnull/Linux/callbacks.c new file mode 100644 index 0000000000..fa070a7842 --- /dev/null +++ b/plugins/usb/USBnull/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/usb/USBnull/Linux/callbacks.h b/plugins/usb/USBnull/Linux/callbacks.h new file mode 100644 index 0000000000..22cf74a988 --- /dev/null +++ b/plugins/usb/USBnull/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/usb/USBnull/Linux/conf.c b/plugins/usb/USBnull/Linux/conf.c new file mode 100644 index 0000000000..74d444b96e --- /dev/null +++ b/plugins/usb/USBnull/Linux/conf.c @@ -0,0 +1,128 @@ +/* USBnull + * Copyright (C) 2002-2004 USBnull 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 +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "USBnull Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CFGconfigure() { + Conf = create_Config(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/usb/USBnull/Linux/interface.c b/plugins/usb/USBnull/Linux/interface.c new file mode 100644 index 0000000000..a73c0861ed --- /dev/null +++ b/plugins/usb/USBnull/Linux/interface.c @@ -0,0 +1,219 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/usb/USBnull/Linux/interface.h b/plugins/usb/USBnull/Linux/interface.h new file mode 100644 index 0000000000..ab0cb1a886 --- /dev/null +++ b/plugins/usb/USBnull/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/usb/USBnull/Linux/support.c b/plugins/usb/USBnull/Linux/support.c new file mode 100644 index 0000000000..b053ba6f6d --- /dev/null +++ b/plugins/usb/USBnull/Linux/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/usb/USBnull/Linux/support.h b/plugins/usb/USBnull/Linux/support.h new file mode 100644 index 0000000000..886615901b --- /dev/null +++ b/plugins/usb/USBnull/Linux/support.h @@ -0,0 +1,38 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/usb/USBnull/Linux/usbnull.glade b/plugins/usb/USBnull/Linux/usbnull.glade new file mode 100644 index 0000000000..6644e52247 --- /dev/null +++ b/plugins/usb/USBnull/Linux/usbnull.glade @@ -0,0 +1,300 @@ + + + + + FireWire + dev9linuz + + + pixmaps + C + False + False + False + False + False + + + + GtkWindow + Config + 5 + DEV9config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox1 + 5 + False + 5 + + + GtkFrame + frame2 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox1 + 5 + True + 5 + + + GtkLabel + label4 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Eth + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + + + + + + + + GtkFrame + frame3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox2 + 5 + True + 5 + + + GtkLabel + label5 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkCombo + GtkCombo_Hdd + 130 + False + True + False + True + False + + + 0 + False + False + + + + GtkEntry + GtkCombo:entry + entry1 + True + True + True + 0 + + + + + + + + GtkHButtonBox + hbuttonbox1 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button1 + True + True + + clicked + OnConf_Ok + Sat, 06 Apr 2002 17:07:56 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + button2 + True + True + + clicked + OnConf_Cancel + Sat, 06 Apr 2002 17:08:08 GMT + + + GTK_RELIEF_NORMAL + + + + + + + GtkWindow + About + 5 + DEV9about + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + True + False + + + GtkVBox + vbox2 + 5 + False + 5 + + + GtkLabel + label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + label3 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox2 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + button3 + True + True + + clicked + OnAbout_Ok + Sun, 07 Apr 2002 03:43:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + diff --git a/plugins/usb/USBnull/PS2Edefs.h b/plugins/usb/USBnull/PS2Edefs.h new file mode 100644 index 0000000000..b2f76c96de --- /dev/null +++ b/plugins/usb/USBnull/PS2Edefs.h @@ -0,0 +1,848 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/usb/USBnull/PS2Etypes.h b/plugins/usb/USBnull/PS2Etypes.h new file mode 100644 index 0000000000..1ad73e273d --- /dev/null +++ b/plugins/usb/USBnull/PS2Etypes.h @@ -0,0 +1,76 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif // _MSC_VER + +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/usb/USBnull/ReadMe.txt b/plugins/usb/USBnull/ReadMe.txt new file mode 100644 index 0000000000..f916e59126 --- /dev/null +++ b/plugins/usb/USBnull/ReadMe.txt @@ -0,0 +1,34 @@ +USBnull v0.4 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "usbnull.dll" (win32) or usbnull.dll (win64) + at the Plugin directory of the Emulator to use it. + +Changes: +------- + v0.4: +*project files for vs2005 beta1 .64bit dll should work okay (not tested!) + + v0.3: + *up to pcsx2 specs 0.5.5 + *added ini and option for logging + *small adds around.. + + v0.2: + * First Release + * Tested with Pcsx2 + +Authors: +------- + +shadow + + + + diff --git a/plugins/usb/USBnull/USB.c b/plugins/usb/USBnull/USB.c new file mode 100644 index 0000000000..1f176961aa --- /dev/null +++ b/plugins/usb/USBnull/USB.c @@ -0,0 +1,170 @@ +/* USBlinuz + * Copyright (C) 2002-2005 USBlinuz 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 +#include +#include + +#include "USB.h" + + + +const unsigned char version = PS2E_USB_VERSION; +const unsigned char revision = 0; +const unsigned char build = 5; // increase that with each version + +static char *libraryName = "USBnull Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_USB; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || usbLog == NULL) return; + + va_start(list, fmt); + vfprintf(usbLog, fmt, list); + va_end(list); +} + +s32 CALLBACK USBinit() { + LoadConfig(); + +#ifdef USB_LOG + usbLog = fopen("logs/usbLog.txt", "w"); + if (usbLog) setvbuf(usbLog, NULL, _IONBF, 0); + USB_LOG("usbnull plugin version %d,%d\n",revision,build); + USB_LOG("USBinit\n"); +#endif + + return 0; +} + +void CALLBACK USBshutdown() { +#ifdef USB_LOG + if (usbLog) fclose(usbLog); +#endif +} + +s32 CALLBACK USBopen(void *pDsp) { +#ifdef USB_LOG + USB_LOG("USBopen\n"); +#endif + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + + return 0; +} + +void CALLBACK USBclose() { +} + +u8 CALLBACK USBread8(u32 addr) { + + + +#ifdef USB_LOG + USB_LOG("*UnKnown 8bit read at address %lx ", addr); +#endif + return 0; +} + +u16 CALLBACK USBread16(u32 addr) { + + + +#ifdef USB_LOG + USB_LOG("*UnKnown 16bit read at address %lx", addr); +#endif + return 0; +} + +u32 CALLBACK USBread32(u32 addr) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 32bit read at address %lx", addr); +#endif + return 0; +} + +void CALLBACK USBwrite8(u32 addr, u8 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 8bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite16(u32 addr, u16 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 16bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite32(u32 addr, u32 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 32bit write at address %lx value %lx\n", addr, value); +#endif +} + +void CALLBACK USBirqCallback(USBcallback callback) { + USBirq = callback; +} + +int CALLBACK _USBirqHandler(void) { + + return 0; +} + +USBhandler CALLBACK USBirqHandler(void) { + return (USBhandler)_USBirqHandler; +} + +void CALLBACK USBsetRAM(void *mem) { + +} + +// extended funcs + + + +s32 CALLBACK USBfreeze(int mode, freezeData *data) { + + + return 0; +} + + +s32 CALLBACK USBtest() { + return 0; +} + diff --git a/plugins/usb/USBnull/USB.h b/plugins/usb/USBnull/USB.h new file mode 100644 index 0000000000..486959ffd0 --- /dev/null +++ b/plugins/usb/USBnull/USB.h @@ -0,0 +1,66 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + + +#ifndef __USB_H__ +#define __USB_H__ + +#include + +#define USBdefs +#include "PS2Edefs.h" + +#ifdef _WIN32 + +#define usleep(x) Sleep(x / 1000) +#include +#include + +#else + +#include +#include + +#define __inline inline + +#endif + +#define USB_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; + + + + +#define PSXCLK 36864000 /* 36.864 Mhz */ + +USBcallback USBirq; + +void SaveConfig(); +void LoadConfig(); + +FILE *usbLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/usb/USBnull/Win32/Config.c b/plugins/usb/USBnull/Win32/Config.c new file mode 100644 index 0000000000..ed953cf2eb --- /dev/null +++ b/plugins/usb/USBnull/Win32/Config.c @@ -0,0 +1,51 @@ +#include + +#include "USB.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\usbnull.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\usbnull.ini"); + fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/usb/USBnull/Win32/Makefile b/plugins/usb/USBnull/Win32/Makefile new file mode 100644 index 0000000000..f4ea1258cc --- /dev/null +++ b/plugins/usb/USBnull/Win32/Makefile @@ -0,0 +1,53 @@ +# +# USBnull Makefile for MINGW32 +# + + +all: plugin + +CPU = ix86 +PLUGIN = USBnull.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = res.o + +OBJS = ../USB.o +OBJS+= Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +plugin: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} +# ${CC} -shared -Wl,--kill-at ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean plugin + +clean: + ${RM} ${OBJS} ${DEPS} ${PLUGIN} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: USBnull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/usb/USBnull/Win32/USBnull.def b/plugins/usb/USBnull/Win32/USBnull.def new file mode 100644 index 0000000000..9acbd1190b --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull.def @@ -0,0 +1,27 @@ +; USBlinuz.def : Declares the module parameters for the DLL. + +LIBRARY "USBnull" +DESCRIPTION 'USBnull Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + USBinit @5 + USBshutdown @6 + USBopen @7 + USBclose @8 + USBread8 @9 + USBread16 @10 + USBread32 @11 + USBwrite8 @12 + USBwrite16 @13 + USBwrite32 @14 + USBirqCallback @15 + USBirqHandler @16 + USBsetRAM @17 + + USBconfigure @18 + USBtest @19 + USBabout @20 diff --git a/plugins/usb/USBnull/Win32/USBnull.dsp b/plugins/usb/USBnull/Win32/USBnull.dsp new file mode 100644 index 0000000000..b40466a510 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull.dsp @@ -0,0 +1,85 @@ +# Microsoft Developer Studio Project File - Name="USBnull" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=USBnull - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "USBnull.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "USBnull.mak" CFG="USBnull - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "USBnull - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USBnull_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USBnull_EXPORTS" /D "__WIN32__" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# Begin Target + +# Name "USBnull - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Config.c +# End Source File +# Begin Source File + +SOURCE=..\USB.c +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\USBnull.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/usb/USBnull/Win32/USBnull.dsw b/plugins/usb/USBnull/Win32/USBnull.dsw new file mode 100644 index 0000000000..bf79c966b8 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "USBnull"=".\USBnull.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/usb/USBnull/Win32/USBnull.rc b/plugins/usb/USBnull/Win32/USBnull.rc new file mode 100644 index 0000000000..3f817c9877 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// + +#include "afxres.h" + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "USBconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,48,100,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,100,50,14 + CONTROL "Enable logging(for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,159,15 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "USBabout" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "USBnull Driver",IDC_NAME,70,10,47,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Author: shadow@pcsx2.net",IDC_STATIC,20,20,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/usb/USBnull/Win32/USBnull_2005_x64.vcproj b/plugins/usb/USBnull/Win32/USBnull_2005_x64.vcproj new file mode 100644 index 0000000000..92b1829a92 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull_2005_x64.vcproj @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBnull/Win32/USBnull_vc2003.sln b/plugins/usb/USBnull/Win32/USBnull_vc2003.sln new file mode 100644 index 0000000000..490038a06e --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull_vc2003.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBnull", "USBnull_vc2003.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBnull/Win32/USBnull_vc2003.vcproj b/plugins/usb/USBnull/Win32/USBnull_vc2003.vcproj new file mode 100644 index 0000000000..b1cdf5bdc5 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull_vc2003.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.sln b/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.sln new file mode 100644 index 0000000000..48ee6e28a4 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBnull", "USBnull_vc2005beta1.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + amd64|Win32 = amd64|Win32 + amd64|Win64 (AMD64) = amd64|Win64 (AMD64) + Debug|Win32 = Debug|Win32 + Debug|Win64 (AMD64) = Debug|Win64 (AMD64) + Release|Win32 = Release|Win32 + Release|Win64 (AMD64) = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win32.ActiveCfg = amd64|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win32.Build.0 = amd64|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win64 (AMD64).ActiveCfg = amd64|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.amd64|Win64 (AMD64).Build.0 = amd64|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win64 (AMD64).ActiveCfg = Debug|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win64 (AMD64).Build.0 = Debug|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.Build.0 = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win64 (AMD64).ActiveCfg = Release|Win64 (AMD64) + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win64 (AMD64).Build.0 = Release|Win64 (AMD64) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.vcproj b/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.vcproj new file mode 100644 index 0000000000..d1de3fefd0 --- /dev/null +++ b/plugins/usb/USBnull/Win32/USBnull_vc2005beta1.vcproj @@ -0,0 +1,530 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBnull/Win32/Win32.c b/plugins/usb/USBnull/Win32/Win32.c new file mode 100644 index 0000000000..a290a7782a --- /dev/null +++ b/plugins/usb/USBnull/Win32/Win32.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "USB.h" +#include "resource.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "USBnull Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK USBconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK USBabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/usb/USBnull/Win32/afxresmw.h b/plugins/usb/USBnull/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/usb/USBnull/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/usb/USBnull/Win32/mingw/Makefile.win b/plugins/usb/USBnull/Win32/mingw/Makefile.win new file mode 100644 index 0000000000..2fb5ec8792 --- /dev/null +++ b/plugins/usb/USBnull/Win32/mingw/Makefile.win @@ -0,0 +1,43 @@ +# Project: USBnull +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//USBnull_private.res +OBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) +LINKOBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) +LIBS = -L"C:/Develop/Dev-Cpp/lib" --def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +INCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." +CXXINCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." +BIN = USBnull.dll +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32__ +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before USBnull.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libUSBnull.def +STATICLIB=libUSBnull.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Obj//Win32.o: ../Win32.c + $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) + +Obj//Config.o: ../Config.c + $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) + +Obj//USB.o: ../../USB.c + $(CC) -c ../../USB.c -o Obj//USB.o $(CFLAGS) + +Obj//USBnull_private.res: USBnull_private.rc ../USBnull.rc + $(WINDRES) -i USBnull_private.rc --input-format=rc -o Obj//USBnull_private.res -O coff --include-dir ../mingw --include-dir ../ diff --git a/plugins/usb/USBnull/Win32/mingw/USBnull.dev b/plugins/usb/USBnull/Win32/mingw/USBnull.dev new file mode 100644 index 0000000000..9a0830cfd9 --- /dev/null +++ b/plugins/usb/USBnull/Win32/mingw/USBnull.dev @@ -0,0 +1,138 @@ +[Project] +FileName=USBnull.dev +Name=USBnull +UnitCount=9 +Type=3 +Ver=1 +ObjFiles= +Includes=../;../../;../.. +Libs= +PrivateResource=USBnull_private.rc +ResourceIncludes=..\mingw;../ +MakeIncludes= +Compiler=-Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32___@@_ +CppCompiler= +Linker=--def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput=Obj/ +OverrideOutput=0 +OverrideOutputName=USBnull.dll +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=afxres.h +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\Win32.c +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\Config.c +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\resource.h +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\USBnull.rc +Folder=USBnull +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\USB.h +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\..\PS2Edefs.h +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\PS2Etypes.h +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\USB.c +CompileCpp=0 +Folder=USBnull +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/plugins/usb/USBnull/Win32/mingw/USBnull.layout b/plugins/usb/USBnull/Win32/mingw/USBnull.layout new file mode 100644 index 0000000000..c30ca06382 --- /dev/null +++ b/plugins/usb/USBnull/Win32/mingw/USBnull.layout @@ -0,0 +1,50 @@ +[Editor_4] +CursorCol=1 +CursorRow=12 +TopLine=1 +LeftChar=1 +Open=0 +Top=0 +[Editors] +Focused=-1 +Order=-1,0 +[Editor_0] +Open=1 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=1 +LeftChar=1 +[Editor_1] +Open=1 +Top=1 +CursorCol=1 +CursorRow=5 +TopLine=1 +LeftChar=1 +[Editor_2] +Open=0 +Top=0 +[Editor_3] +Open=0 +Top=0 +[Editor_5] +Open=0 +Top=0 +CursorCol=1 +CursorRow=1 +TopLine=27 +LeftChar=1 +[Editor_6] +Open=0 +Top=0 +[Editor_7] +Open=0 +Top=0 +[Editor_8] +Open=0 +Top=0 +CursorCol=1 +CursorRow=24 +TopLine=4 +LeftChar=1 diff --git a/plugins/usb/USBnull/Win32/mingw/afxres.h b/plugins/usb/USBnull/Win32/mingw/afxres.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/usb/USBnull/Win32/mingw/afxres.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/usb/USBnull/Win32/resource.h b/plugins/usb/USBnull/Win32/resource.h new file mode 100644 index 0000000000..510a606c4c --- /dev/null +++ b/plugins/usb/USBnull/Win32/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by USBnull.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/usb/USBnull/build.sh b/plugins/usb/USBnull/build.sh new file mode 100644 index 0000000000..98f56bb2ef --- /dev/null +++ b/plugins/usb/USBnull/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +echo ---------------- +echo Building USBnull +echo ---------------- + +curdir=`pwd` + +cd ${curdir}/Linux +make $@ + +if [ $? -ne 0 ] +then +exit 1 +fi + +if [ -s cfgUSBnull ] && [ -s libUSBnull.so ] +then +cp cfgUSBnull libUSBnull.so ${PCSX2PLUGINS} +fi diff --git a/plugins/usb/USBqemu/License-qemu.txt b/plugins/usb/USBqemu/License-qemu.txt new file mode 100644 index 0000000000..bf51c07090 --- /dev/null +++ b/plugins/usb/USBqemu/License-qemu.txt @@ -0,0 +1,23 @@ +/* + * QEMU USB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/plugins/usb/USBqemu/License.txt b/plugins/usb/USBqemu/License.txt new file mode 100644 index 0000000000..bb0a0ce0eb --- /dev/null +++ b/plugins/usb/USBqemu/License.txt @@ -0,0 +1,342 @@ + 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/plugins/usb/USBqemu/PS2Edefs.h b/plugins/usb/USBqemu/PS2Edefs.h new file mode 100644 index 0000000000..fbb0c2eb06 --- /dev/null +++ b/plugins/usb/USBqemu/PS2Edefs.h @@ -0,0 +1,809 @@ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); +typedef void (CALLBACK* _USBasync)(u32 cycles); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; +_USBasync USBasync; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/usb/USBqemu/PS2Etypes.h b/plugins/usb/USBqemu/PS2Etypes.h new file mode 100644 index 0000000000..194f6558f1 --- /dev/null +++ b/plugins/usb/USBqemu/PS2Etypes.h @@ -0,0 +1,75 @@ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined (__linux__) // some distributions are lower case +#define __LINUX__ +#endif + +// Basic types +#if defined(_WIN32) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x + +#else + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#ifdef __LINUX__ +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; +#endif + +#if defined(__MINGW32__) +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#else +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) +#endif + +#ifndef __forceinline +#define __forceinline inline +#endif + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/usb/USBqemu/ReadMe.txt b/plugins/usb/USBqemu/ReadMe.txt new file mode 100644 index 0000000000..8a5e6cfe51 --- /dev/null +++ b/plugins/usb/USBqemu/ReadMe.txt @@ -0,0 +1,26 @@ +USBlinuz v0.1 +------------- + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Usage: +----- + Place the file "usblinuz.dll" (win32) or usblinuz_64.dll (win64) + at the Plugin directory of the Emulator to use it. + +Changes: +------- +v0.1 (gigaherz) + * First Release + * Tested with Pcsx2 32 and 64bit + +Authors: +------- + + linuzappz + shadow + + + diff --git a/plugins/usb/USBqemu/USB.cpp b/plugins/usb/USBqemu/USB.cpp new file mode 100644 index 0000000000..b02285939d --- /dev/null +++ b/plugins/usb/USBqemu/USB.cpp @@ -0,0 +1,252 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 +#include +#include + +#include "qemu-usb/vl.h" +#include "USB.h" + +const unsigned char version = PS2E_USB_VERSION; +const unsigned char revision = 0; +const unsigned char build = 1; // increase that with each version + +static char *libraryName = "Qemu USB Driver by Gigaherz" +#ifdef _DEBUG +" (debug)" +#endif +; + +OHCIState *qemu_ohci; + +Config conf; + +HWND gsWnd=NULL; + +u8 *usbR; +u8 *ram; +usbStruct usb; +USBcallback _USBirq; +FILE *usbLog; +int64_t usb_frame_time; +int64_t usb_bit_time; + +s64 clocks; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_USB; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log) return; + + va_start(list, fmt); + vfprintf(usbLog, fmt, list); + va_end(list); +} + +void USBirq(int cycles) +{ + USB_LOG("USBirq.\n"); + + _USBirq(cycles); +} + +s32 CALLBACK USBinit() { + LoadConfig(); + if (conf.Log) + { + usbLog = fopen("logs/usbLog.txt", "w"); + setvbuf(usbLog, NULL, _IONBF, 0); + USB_LOG("usblinuz plugin version %d,%d\n",revision,build); + USB_LOG("USBinit\n"); + } + + qemu_ohci = ohci_create(0x1f801600,2); + qemu_ohci->rhport[0].port.attach(&(qemu_ohci->rhport[0].port),usb_keyboard_init()); + + return 0; +} + +void CALLBACK USBshutdown() { + + qemu_ohci->rhport[0].port.dev->handle_destroy(qemu_ohci->rhport[0].port.dev); + + free(qemu_ohci); + +#ifdef _DEBUG + fclose(usbLog); +#endif +} + +s32 CALLBACK USBopen(void *pDsp) { + USB_LOG("USBopen\n"); + + HWND hWnd=(HWND)pDsp; + + if (!IsWindow (hWnd) && !IsBadReadPtr ((u32*)hWnd, 4)) + hWnd = *(HWND*)hWnd; + if (!IsWindow (hWnd)) + hWnd = NULL; + else + { + while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD) + hWnd = GetParent (hWnd); + } + gsWnd = hWnd; + + return 0; +} + +void CALLBACK USBclose() { +} + +u8 CALLBACK USBread8(u32 addr) { + USB_LOG("* Invalid 8bit read at address %lx\n", addr); + return 0; +} + +u16 CALLBACK USBread16(u32 addr) { + USB_LOG("* Invalid 16bit read at address %lx\n", addr); + return 0; +} + +u32 CALLBACK USBread32(u32 addr) { + u32 hard; + + hard=ohci_mem_read(qemu_ohci,addr); + + USB_LOG("* Known 32bit read at address %lx: %lx\n", addr, hard); + + return hard; +} + +void CALLBACK USBwrite8(u32 addr, u8 value) { + USB_LOG("* Invalid 8bit write at address %lx value %x\n", addr, value); +} + +void CALLBACK USBwrite16(u32 addr, u16 value) { + USB_LOG("* Invalid 16bit write at address %lx value %x\n", addr, value); +} + +void CALLBACK USBwrite32(u32 addr, u32 value) { + USB_LOG("* Known 32bit write at address %lx value %lx\n", addr, value); + ohci_mem_write(qemu_ohci,addr,value); +} + +void CALLBACK USBirqCallback(USBcallback callback) { + _USBirq = callback; +} + +extern u32 bits; + +int CALLBACK _USBirqHandler(void) +{ + //fprintf(stderr," * USB: IRQ Acknowledged.\n"); + //qemu_ohci->intr_status&=~bits; + return 1; +} + +USBhandler CALLBACK USBirqHandler(void) { + return (USBhandler)_USBirqHandler; +} + +void CALLBACK USBsetRAM(void *mem) { + ram = (u8*)mem; +} + +// extended funcs + +char USBfreezeID[] = "USB STv0"; + +typedef struct { + OHCIState t; +} USBfreezeData; + +s32 CALLBACK USBfreeze(int mode, freezeData *data) { + USBfreezeData *usbd; + + if (mode == FREEZE_LOAD) { + usbd = (USBfreezeData*)data->data; + if (data->size != sizeof(USBfreezeData)) return -1; + + memcpy(qemu_ohci, usbd, sizeof(OHCIState)); + } else + if (mode == FREEZE_SAVE) { + data->size = sizeof(USBfreezeData); + data->data = (s8*)malloc(data->size); + if (data->data == NULL) return -1; + usbd = (USBfreezeData*)data->data; + memcpy(usbd, qemu_ohci, sizeof(OHCIState)); + } + + return 0; +} + +void CALLBACK USBasync(u32 cycles) +{ + clocks+=cycles; + if(qemu_ohci->eof_timer>0) + { + while(cycles>=qemu_ohci->eof_timer) + { + cycles-=qemu_ohci->eof_timer; + qemu_ohci->eof_timer=0; + ohci_frame_boundary(qemu_ohci); + } + if((cycles>0)&&(qemu_ohci->eof_timer>0)) + qemu_ohci->eof_timer-=cycles; + } +} + +s32 CALLBACK USBtest() { + return 0; +} + +void cpu_physical_memory_rw(u32 addr, u8 *buf, + int len, int is_write) +{ + if(is_write) + memcpy(&(ram[addr]),buf,len); + else + memcpy(buf,&(ram[addr]),len); +} + +s64 get_clock() +{ + return clocks; +} + +void *qemu_mallocz(uint32_t size) +{ + void *m=malloc(size); + if(!m) return NULL; + memset(m,0,size); + return m; +} diff --git a/plugins/usb/USBqemu/USB.h b/plugins/usb/USBqemu/USB.h new file mode 100644 index 0000000000..a83f6f3e08 --- /dev/null +++ b/plugins/usb/USBqemu/USB.h @@ -0,0 +1,313 @@ +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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 + */ + +#pragma once + +#ifndef __USB_H__ +#define __USB_H__ + +#include + +#define USBdefs +#include "PS2Edefs.h" + +#ifdef __WIN32__ + +#define usleep(x) Sleep(x / 1000) +#include +#include + +#else + +#include + +#define __inline inline + +#endif + +#define USB_LOG __Log + +typedef struct { + int Log; +} Config; + +extern Config conf; + +extern u8 *usbR; +extern u8 *ram; + +typedef struct { + int unused; +} usbStruct; + +extern usbStruct usb; + +#define usbRs8(mem) usbR[(mem) & 0xffff] +#define usbRs16(mem) (*(s16*)&usbR[(mem) & 0xffff]) +#define usbRs32(mem) (*(s32*)&usbR[(mem) & 0xffff]) +#define usbRu8(mem) (*(u8*) &usbR[(mem) & 0xffff]) +#define usbRu16(mem) (*(u16*)&usbR[(mem) & 0xffff]) +#define usbRu32(mem) (*(u32*)&usbR[(mem) & 0xffff]) + +#define PSXCLK 36864000 /* 36.864 Mhz */ + +extern USBcallback _USBirq; +void USBirq(int); + +void SaveConfig(); +void LoadConfig(); + +extern FILE *usbLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#include "qemu-usb/vl.h" + +#define DEBUG_OHCI +/* Dump packet contents. */ +//#define DEBUG_PACKET +/* This causes frames to occur 1000x slower */ +//#define OHCI_TIME_WARP 1 + +/* Number of Downstream Ports on the root hub. */ + +#define OHCI_MAX_PORTS 15 + +extern int64_t usb_frame_time; +extern int64_t usb_bit_time; + +typedef struct OHCIPort { + USBPort port; + uint32_t ctrl; +} OHCIPort; + +typedef uint32_t target_phys_addr_t; + +typedef struct { + target_phys_addr_t mem_base; + int mem; + int num_ports; + + uint64_t eof_timer; + int64_t sof_time; + + /* OHCI state */ + /* Control partition */ + uint32_t ctl, status; + uint32_t intr_status; + uint32_t intr; + + /* memory pointer partition */ + uint32_t hcca; + uint32_t ctrl_head, ctrl_cur; + uint32_t bulk_head, bulk_cur; + uint32_t per_cur; + uint32_t done; + int done_count; + + /* Frame counter partition */ + uint32_t fsmps:15; + uint32_t fit:1; + uint32_t fi:14; + uint32_t frt:1; + uint16_t frame_number; + uint16_t padding; + uint32_t pstart; + uint32_t lst; + + /* Root Hub partition */ + uint32_t rhdesc_a, rhdesc_b; + uint32_t rhstatus; + OHCIPort rhport[OHCI_MAX_PORTS]; +} OHCIState; + +/* Host Controller Communications Area */ +struct ohci_hcca { + uint32_t intr[32]; + uint16_t frame, pad; + uint32_t done; +}; + +/* Bitfields for the first word of an Endpoint Desciptor. */ +#define OHCI_ED_FA_SHIFT 0 +#define OHCI_ED_FA_MASK (0x7f<> OHCI_##field##_SHIFT) + +#define OHCI_SET_BM(val, field, newval) do { \ + val &= ~OHCI_##field##_MASK; \ + val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ + } while(0) + +/* endpoint descriptor */ +struct ohci_ed { + uint32_t flags; + uint32_t tail; + uint32_t head; + uint32_t next; +}; + +/* General transfer descriptor */ +struct ohci_td { + uint32_t flags; + uint32_t cbp; + uint32_t next; + uint32_t be; +}; + +#define USB_HZ 12000000 + +/* OHCI Local stuff */ +#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) +#define OHCI_CTL_PLE (1<<2) +#define OHCI_CTL_IE (1<<3) +#define OHCI_CTL_CLE (1<<4) +#define OHCI_CTL_BLE (1<<5) +#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) +#define OHCI_USB_RESET 0x00 +#define OHCI_USB_RESUME 0x40 +#define OHCI_USB_OPERATIONAL 0x80 +#define OHCI_USB_SUSPEND 0xc0 +#define OHCI_CTL_IR (1<<8) +#define OHCI_CTL_RWC (1<<9) +#define OHCI_CTL_RWE (1<<10) + +#define OHCI_STATUS_HCR (1<<0) +#define OHCI_STATUS_CLF (1<<1) +#define OHCI_STATUS_BLF (1<<2) +#define OHCI_STATUS_OCR (1<<3) +#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) + +#define OHCI_INTR_SO (1<<0) /* Scheduling overrun */ +#define OHCI_INTR_WD (1<<1) /* HcDoneHead writeback */ +#define OHCI_INTR_SF (1<<2) /* Start of frame */ +#define OHCI_INTR_RD (1<<3) /* Resume detect */ +#define OHCI_INTR_UE (1<<4) /* Unrecoverable error */ +#define OHCI_INTR_FNO (1<<5) /* Frame number overflow */ +#define OHCI_INTR_RHSC (1<<6) /* Root hub status change */ +#define OHCI_INTR_OC (1<<30) /* Ownership change */ +#define OHCI_INTR_MIE (1<<31) /* Master Interrupt Enable */ + +#define OHCI_HCCA_SIZE 0x100 +#define OHCI_HCCA_MASK 0xffffff00 + +#define OHCI_EDPTR_MASK 0xfffffff0 + +#define OHCI_FMI_FI 0x00003fff +#define OHCI_FMI_FSMPS 0xffff0000 +#define OHCI_FMI_FIT 0x80000000 + +#define OHCI_FR_RT (1<<31) + +#define OHCI_LS_THRESH 0x628 + +#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ +#define OHCI_RHA_PSM (1<<8) +#define OHCI_RHA_NPS (1<<9) +#define OHCI_RHA_DT (1<<10) +#define OHCI_RHA_OCPM (1<<11) +#define OHCI_RHA_NOCP (1<<12) +#define OHCI_RHA_POTPGT_MASK 0xff000000 + +#define OHCI_RHS_LPS (1<<0) +#define OHCI_RHS_OCI (1<<1) +#define OHCI_RHS_DRWE (1<<15) +#define OHCI_RHS_LPSC (1<<16) +#define OHCI_RHS_OCIC (1<<17) +#define OHCI_RHS_CRWE (1<<31) + +#define OHCI_PORT_CCS (1<<0) +#define OHCI_PORT_PES (1<<1) +#define OHCI_PORT_PSS (1<<2) +#define OHCI_PORT_POCI (1<<3) +#define OHCI_PORT_PRS (1<<4) +#define OHCI_PORT_PPS (1<<8) +#define OHCI_PORT_LSDA (1<<9) +#define OHCI_PORT_CSC (1<<16) +#define OHCI_PORT_PESC (1<<17) +#define OHCI_PORT_PSSC (1<<18) +#define OHCI_PORT_OCIC (1<<19) +#define OHCI_PORT_PRSC (1<<20) +#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ + |OHCI_PORT_OCIC|OHCI_PORT_PRSC) + +#define OHCI_TD_DIR_SETUP 0x0 +#define OHCI_TD_DIR_OUT 0x1 +#define OHCI_TD_DIR_IN 0x2 +#define OHCI_TD_DIR_RESERVED 0x3 + +#define OHCI_CC_NOERROR 0x0 +#define OHCI_CC_CRC 0x1 +#define OHCI_CC_BITSTUFFING 0x2 +#define OHCI_CC_DATATOGGLEMISMATCH 0x3 +#define OHCI_CC_STALL 0x4 +#define OHCI_CC_DEVICENOTRESPONDING 0x5 +#define OHCI_CC_PIDCHECKFAILURE 0x6 +#define OHCI_CC_UNDEXPETEDPID 0x7 +#define OHCI_CC_DATAOVERRUN 0x8 +#define OHCI_CC_DATAUNDERRUN 0x9 +#define OHCI_CC_BUFFEROVERRUN 0xc +#define OHCI_CC_BUFFERUNDERRUN 0xd + +int64_t get_clock(); + +OHCIState *ohci_create(uint32_t base, int ports); + +uint32_t ohci_mem_read(OHCIState *ohci, uint32_t addr ); +void ohci_mem_write(OHCIState *ohci, uint32_t addr, uint32_t value ); +void ohci_frame_boundary(void *opaque); + +int ohci_bus_start(OHCIState *ohci); +void ohci_bus_stop(OHCIState *ohci); + +USBDevice *usb_hub_init(int nb_ports); +USBDevice *usb_msd_init(const char *filename); +USBDevice *eyetoy_init(void); +USBDevice *usb_mouse_init(void); + +#endif diff --git a/plugins/usb/USBqemu/Win32/Config.cpp b/plugins/usb/USBqemu/Win32/Config.cpp new file mode 100644 index 0000000000..c46552a4a6 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/Config.cpp @@ -0,0 +1,51 @@ +#include + +#include "USB.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\usblinuz.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\usblinuz.ini"); + fp=fopen("inis\\usblinuz.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/usb/USBqemu/Win32/USBlinuz.aps b/plugins/usb/USBqemu/Win32/USBlinuz.aps new file mode 100644 index 0000000000000000000000000000000000000000..c56328c8c94d7759696d2314be17afbfe8fc7c12 GIT binary patch literal 35272 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 IvFsc8zl;LwVE_OC literal 0 HcmV?d00001 diff --git a/plugins/usb/USBqemu/Win32/USBlinuz.def b/plugins/usb/USBqemu/Win32/USBlinuz.def new file mode 100644 index 0000000000..187d81a501 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz.def @@ -0,0 +1,28 @@ +; USBlinuz.def : Declares the module parameters for the DLL. + +LIBRARY "USBqemu" +DESCRIPTION 'USBqemu Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + USBinit @5 + USBshutdown @6 + USBopen @7 + USBclose @8 + USBread8 @9 + USBread16 @10 + USBread32 @11 + USBwrite8 @12 + USBwrite16 @13 + USBwrite32 @14 + USBirqCallback @15 + USBirqHandler @16 + USBsetRAM @17 + USBasync @18 + + USBconfigure @19 + USBtest @20 + USBabout @21 diff --git a/plugins/usb/USBqemu/Win32/USBlinuz.rc b/plugins/usb/USBqemu/Win32/USBlinuz.rc new file mode 100644 index 0000000000..ac4e99e066 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz.rc @@ -0,0 +1,156 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 121 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "USBconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,48,100,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,100,50,14 + CONTROL "Enable Logging (for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,144,15 + COMBOBOX IDC_COMBO1,7,38,138,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Device in Port 1:",IDC_STATIC,8,30,54,8 + COMBOBOX IDC_COMBO2,7,63,138,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Device in Port 2:",IDC_STATIC,8,55,54,8 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "USBabout" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "USBqemu Driver",IDC_NAME,70,10,54,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Author: gigaherz ",IDC_STATIC,20,20,141,10 + LTEXT "Parts of this code were originally from the QEMU project.",IDC_STATIC,14,44,149,26 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_CONFIG DLGINIT +BEGIN + IDC_COMBO1, 0x403, 10, 0 +0x6f4e, 0x4420, 0x7665, 0x6369, 0x0065, + IDC_COMBO1, 0x403, 9, 0 +0x654b, 0x6279, 0x616f, 0x6472, "\000" + IDC_COMBO1, 0x403, 6, 0 +0x6f4d, 0x7375, 0x0065, + IDC_COMBO1, 0x403, 14, 0 +0x7945, 0x7465, 0x796f, 0x4320, 0x6d61, 0x7265, 0x0061, + IDC_COMBO1, 0x403, 20, 0 +0x6953, 0x676e, 0x7473, 0x7261, 0x4d20, 0x6369, 0x6f72, 0x6870, 0x6e6f, +0x0065, + IDC_COMBO2, 0x403, 10, 0 +0x6f4e, 0x4420, 0x7665, 0x6369, 0x0065, + IDC_COMBO2, 0x403, 9, 0 +0x654b, 0x6279, 0x616f, 0x6472, "\000" + IDC_COMBO2, 0x403, 6, 0 +0x6f4d, 0x7375, 0x0065, + IDC_COMBO2, 0x403, 14, 0 +0x7945, 0x7465, 0x796f, 0x4320, 0x6d61, 0x7265, 0x0061, + IDC_COMBO2, 0x403, 20, 0 +0x6953, 0x676e, 0x7473, 0x7261, 0x4d20, 0x6369, 0x6f72, 0x6870, 0x6e6f, +0x0065, + 0 +END + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.sln b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.sln new file mode 100644 index 0000000000..9fb2025f86 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2005.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.ActiveCfg = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.Build.0 = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.Build.0 = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.ActiveCfg = Release|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.vcproj b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.vcproj new file mode 100644 index 0000000000..c89a2f65c0 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005.vcproj @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.sln b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.sln new file mode 100644 index 0000000000..41cf887a29 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2005_x64.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.ActiveCfg = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.Build.0 = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.Build.0 = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.ActiveCfg = Release|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.vcproj b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.vcproj new file mode 100644 index 0000000000..c89a2f65c0 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2005_x64.vcproj @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.sln b/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.sln new file mode 100644 index 0000000000..e13082a8b5 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USBlinuz", "USBlinuz_vc2008b2.vcproj", "{BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|Win32.Build.0 = Debug|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.ActiveCfg = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Debug|x64.Build.0 = Debug|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.ActiveCfg = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|Win32.Build.0 = Release|Win32 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.ActiveCfg = Release|x64 + {BF7B81A5-E348-4F7C-A69F-F74C8EEEAD70}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.vcproj b/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.vcproj new file mode 100644 index 0000000000..09bd52e717 --- /dev/null +++ b/plugins/usb/USBqemu/Win32/USBlinuz_vc2008b2.vcproj @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/usb/USBqemu/Win32/Win32.cpp b/plugins/usb/USBqemu/Win32/Win32.cpp new file mode 100644 index 0000000000..7647d9702b --- /dev/null +++ b/plugins/usb/USBqemu/Win32/Win32.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "USB.h" +#include "resource.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "USBlinuz Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK USBconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK USBabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} diff --git a/plugins/usb/USBqemu/Win32/resource.h b/plugins/usb/USBqemu/Win32/resource.h new file mode 100644 index 0000000000..ad8f21c11d --- /dev/null +++ b/plugins/usb/USBqemu/Win32/resource.h @@ -0,0 +1,23 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by USBlinuz.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 +#define IDC_COMBO1 1008 +#define IDC_COMBO2 1009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/usb/USBqemu/qemu-usb/usb-base.cpp b/plugins/usb/USBqemu/qemu-usb/usb-base.cpp new file mode 100644 index 0000000000..34aac5fa9b --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-base.cpp @@ -0,0 +1,193 @@ +/* + * QEMU USB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +void usb_attach(USBPort *port, USBDevice *dev) +{ + port->attach(port, dev); +} + +/**********************/ +/* generic USB device helpers (you are not forced to use them when + writing your USB device driver, but they help handling the + protocol) +*/ + +#define SETUP_STATE_IDLE 0 +#define SETUP_STATE_DATA 1 +#define SETUP_STATE_ACK 2 + +int usb_generic_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + int l, ret = 0; + + switch(pid) { + case USB_MSG_ATTACH: + s->state = USB_STATE_ATTACHED; + break; + case USB_MSG_DETACH: + s->state = USB_STATE_NOTATTACHED; + break; + case USB_MSG_RESET: + s->remote_wakeup = 0; + s->addr = 0; + s->state = USB_STATE_DEFAULT; + s->handle_reset(s); + break; + case USB_TOKEN_SETUP: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + if (len != 8) + goto fail; + memcpy(s->setup_buf, data, 8); + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; + s->setup_index = 0; + if (s->setup_buf[0] & USB_DIR_IN) { + ret = s->handle_control(s, + (s->setup_buf[0] << 8) | s->setup_buf[1], + (s->setup_buf[3] << 8) | s->setup_buf[2], + (s->setup_buf[5] << 8) | s->setup_buf[4], + s->setup_len, + s->data_buf); + if (ret < 0) + return ret; + if (ret < s->setup_len) + s->setup_len = ret; + s->setup_state = SETUP_STATE_DATA; + } else { + if (s->setup_len == 0) + s->setup_state = SETUP_STATE_ACK; + else + s->setup_state = SETUP_STATE_DATA; + } + break; + case USB_TOKEN_IN: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + switch(devep) { + case 0: + switch(s->setup_state) { + case SETUP_STATE_ACK: + if (!(s->setup_buf[0] & USB_DIR_IN)) { + s->setup_state = SETUP_STATE_IDLE; + ret = s->handle_control(s, + (s->setup_buf[0] << 8) | s->setup_buf[1], + (s->setup_buf[3] << 8) | s->setup_buf[2], + (s->setup_buf[5] << 8) | s->setup_buf[4], + s->setup_len, + s->data_buf); + if (ret > 0) + ret = 0; + } else { + /* return 0 byte */ + } + break; + case SETUP_STATE_DATA: + if (s->setup_buf[0] & USB_DIR_IN) { + l = s->setup_len - s->setup_index; + if (l > len) + l = len; + memcpy(data, s->data_buf + s->setup_index, l); + s->setup_index += l; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + ret = l; + } else { + s->setup_state = SETUP_STATE_IDLE; + goto fail; + } + break; + default: + goto fail; + } + break; + default: + ret = s->handle_data(s, pid, devep, data, len); + break; + } + break; + case USB_TOKEN_OUT: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + switch(devep) { + case 0: + switch(s->setup_state) { + case SETUP_STATE_ACK: + if (s->setup_buf[0] & USB_DIR_IN) { + s->setup_state = SETUP_STATE_IDLE; + /* transfer OK */ + } else { + /* ignore additionnal output */ + } + break; + case SETUP_STATE_DATA: + if (!(s->setup_buf[0] & USB_DIR_IN)) { + l = s->setup_len - s->setup_index; + if (l > len) + l = len; + memcpy(s->data_buf + s->setup_index, data, l); + s->setup_index += l; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + ret = l; + } else { + s->setup_state = SETUP_STATE_IDLE; + goto fail; + } + break; + default: + goto fail; + } + break; + default: + ret = s->handle_data(s, pid, devep, data, len); + break; + } + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +/* XXX: fix overflow */ +int set_usb_string(uint8_t *buf, const char *str) +{ + int len, i; + uint8_t *q; + + q = buf; + len = strlen(str); + *q++ = 2 * len + 2; + *q++ = 3; + for(i = 0; i < len; i++) { + *q++ = str[i]; + *q++ = 0; + } + return q - buf; +} diff --git a/plugins/usb/USBqemu/qemu-usb/usb-hid.cpp b/plugins/usb/USBqemu/qemu-usb/usb-hid.cpp new file mode 100644 index 0000000000..04b78fc0f0 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-hid.cpp @@ -0,0 +1,551 @@ +/* + * QEMU USB HID devices + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +#define USB_MOUSE 1 +#define USB_TABLET 2 + +typedef struct USBMouseState { + USBDevice dev; + int dx, dy, dz, buttons_state; + int x, y; + int kind; + int mouse_grabbed; +} USBMouseState; + +/* mostly the same values as the Bochs USB Mouse device */ +static const uint8_t qemu_mouse_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x27, 0x06, /* u16 idVendor; */ + 0x01, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_mouse_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 50, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_tablet_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 74, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_mouse_hid_report_descriptor[] = { + 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, + 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, + 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, + 0xC0, 0xC0, +}; + +static const uint8_t qemu_tablet_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x01, /* Usage Mouse */ + 0xA1, 0x01, /* Collection Application */ + 0x09, 0x01, /* Usage Pointer */ + 0xA1, 0x00, /* Collection Physical */ + 0x05, 0x09, /* Usage Page Button */ + 0x19, 0x01, /* Usage Minimum Button 1 */ + 0x29, 0x03, /* Usage Maximum Button 3 */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x25, 0x01, /* Logical Maximum 1 */ + 0x95, 0x03, /* Report Count 3 */ + 0x75, 0x01, /* Report Size 1 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x01, /* Report Count 1 */ + 0x75, 0x05, /* Report Size 5 */ + 0x81, 0x01, /* Input (Cnst, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x30, /* Usage X */ + 0x09, 0x31, /* Usage Y */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */ + 0x35, 0x00, /* Physical Minimum 0 */ + 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */ + 0x75, 0x10, /* Report Size 16 */ + 0x95, 0x02, /* Report Count 2 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x38, /* Usage Wheel */ + 0x15, 0x81, /* Logical Minimum -127 */ + 0x25, 0x7F, /* Logical Maximum 127 */ + 0x35, 0x00, /* Physical Minimum 0 (same as logical) */ + 0x45, 0x00, /* Physical Maximum 0 (same as logical) */ + 0x75, 0x08, /* Report Size 8 */ + 0x95, 0x01, /* Report Count 1 */ + 0x81, 0x02, /* Input (Data, Var, Rel) */ + 0xC0, /* End Collection */ + 0xC0, /* End Collection */ +}; + +static void usb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + USBMouseState *s = opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + +static void usb_tablet_event(void *opaque, + int x, int y, int dz, int buttons_state) +{ + USBMouseState *s = opaque; + + s->x = x; + s->y = y; + s->dz += dz; + s->buttons_state = buttons_state; +} + +static inline int int_clamp(int val, int vmin, int vmax) +{ + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; +} + +static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dx, dy, dz, b, l; + + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_mouse_event, s, 0); + s->mouse_grabbed = 1; + } + + dx = int_clamp(s->dx, -128, 127); + dy = int_clamp(s->dy, -128, 127); + dz = int_clamp(s->dz, -128, 127); + + s->dx -= dx; + s->dy -= dy; + s->dz -= dz; + + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = dx; + buf[2] = dy; + l = 3; + if (len >= 4) { + buf[3] = dz; + l = 4; + } + return l; +} + +static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dz, b, l; + + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_tablet_event, s, 1); + s->mouse_grabbed = 1; + } + + dz = int_clamp(s->dz, -128, 127); + s->dz -= dz; + + /* Appears we have to invert the wheel direction */ + dz = 0 - dz; + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = s->x & 0xff; + buf[2] = s->x >> 8; + buf[3] = s->y & 0xff; + buf[4] = s->y >> 8; + buf[5] = dz; + l = 6; + + return l; +} + +static void usb_mouse_handle_reset(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + s->dx = 0; + s->dy = 0; + s->dz = 0; + s->x = 0; + s->y = 0; + s->buttons_state = 0; +} + +static int usb_mouse_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_mouse_dev_descriptor, + sizeof(qemu_mouse_dev_descriptor)); + ret = sizeof(qemu_mouse_dev_descriptor); + break; + case USB_DT_CONFIG: + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_config_descriptor, + sizeof(qemu_mouse_config_descriptor)); + ret = sizeof(qemu_mouse_config_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_config_descriptor, + sizeof(qemu_tablet_config_descriptor)); + ret = sizeof(qemu_tablet_config_descriptor); + } + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + case 2: + /* product description */ + if (s->kind == USB_MOUSE) + ret = set_usb_string(data, "QEMU USB Mouse"); + else if (s->kind == USB_TABLET) + ret = set_usb_string(data, "QEMU USB Tablet"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + case 4: + ret = set_usb_string(data, "HID Mouse"); + break; + case 5: + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case 0x22: + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_hid_report_descriptor, + sizeof(qemu_mouse_hid_report_descriptor)); + ret = sizeof(qemu_mouse_hid_report_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_hid_report_descriptor, + sizeof(qemu_tablet_hid_report_descriptor)); + ret = sizeof(qemu_tablet_hid_report_descriptor); + } + break; + default: + goto fail; + } + break; + case GET_REPORT: + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, length); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, length); + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_mouse_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret = 0; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, len); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, len); + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static void usb_mouse_handle_destroy(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + qemu_add_mouse_event_handler(NULL, NULL, 0); + free(s); +} + +USBDevice *usb_tablet_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_TABLET; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + + return (USBDevice *)s; +} + +USBDevice *usb_mouse_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_MOUSE; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + + return (USBDevice *)s; +} diff --git a/plugins/usb/USBqemu/qemu-usb/usb-hub.cpp b/plugins/usb/USBqemu/qemu-usb/usb-hub.cpp new file mode 100644 index 0000000000..4654863870 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-hub.cpp @@ -0,0 +1,565 @@ +/* + * QEMU USB HUB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG + +#define MAX_PORTS 8 + +typedef struct USBHubPort { + USBPort port; + uint16_t wPortStatus; + uint16_t wPortChange; +} USBHubPort; + +typedef struct USBHubState { + USBDevice dev; + int nb_ports; + USBHubPort ports[MAX_PORTS]; +} USBHubState; + +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + +#define PORT_STAT_CONNECTION 0x0001 +#define PORT_STAT_ENABLE 0x0002 +#define PORT_STAT_SUSPEND 0x0004 +#define PORT_STAT_OVERCURRENT 0x0008 +#define PORT_STAT_RESET 0x0010 +#define PORT_STAT_POWER 0x0100 +#define PORT_STAT_LOW_SPEED 0x0200 +#define PORT_STAT_HIGH_SPEED 0x0400 +#define PORT_STAT_TEST 0x0800 +#define PORT_STAT_INDICATOR 0x1000 + +#define PORT_STAT_C_CONNECTION 0x0001 +#define PORT_STAT_C_ENABLE 0x0002 +#define PORT_STAT_C_SUSPEND 0x0004 +#define PORT_STAT_C_OVERCURRENT 0x0008 +#define PORT_STAT_C_RESET 0x0010 + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVERCURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOWSPEED 9 +#define PORT_HIGHSPEED 10 +#define PORT_C_CONNECTION 16 +#define PORT_C_ENABLE 17 +#define PORT_C_SUSPEND 18 +#define PORT_C_OVERCURRENT 19 +#define PORT_C_RESET 20 +#define PORT_TEST 21 +#define PORT_INDICATOR 22 + +/* same as Linux kernel root hubs */ + +static const uint8_t qemu_hub_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ + + 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x01, 0x01, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +/* XXX: patch interrupt size */ +static const uint8_t qemu_hub_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* u8 if_bInterfaceSubClass; */ + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_hub_hub_descriptor[] = +{ + 0x00, /* u8 bLength; patched in later */ + 0x29, /* u8 bDescriptorType; Hub-descriptor */ + 0x00, /* u8 bNbrPorts; (patched later) */ + 0x0a, /* u16 wHubCharacteristics; */ + 0x00, /* (per-port OC, no power switching) */ + 0x01, /* u8 bPwrOn2pwrGood; 2ms */ + 0x00 /* u8 bHubContrCurrent; 0 mA */ + + /* DeviceRemovable and PortPwrCtrlMask patched in later */ +}; + +static void usb_hub_attach(USBPort *port1, USBDevice *dev) +{ + USBHubState *s =(USBHubState *) port1->opaque; + USBHubPort *port = (USBHubPort *)&s->ports[port1->index]; + + if (dev) { + if (port->port.dev) + usb_attach(port1, NULL); + + port->wPortStatus |= PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (dev->speed == USB_SPEED_LOW) + port->wPortStatus |= PORT_STAT_LOW_SPEED; + else + port->wPortStatus &= ~PORT_STAT_LOW_SPEED; + port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); + } else { + dev = port->port.dev; + if (dev) { + port->wPortStatus &= ~PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->wPortStatus & PORT_STAT_ENABLE) { + port->wPortStatus &= ~PORT_STAT_ENABLE; + port->wPortChange |= PORT_STAT_C_ENABLE; + } + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); + port->port.dev = NULL; + } + } +} + +static void usb_hub_handle_reset(USBDevice *dev) +{ + /* XXX: do it */ +} + +static int usb_hub_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0 && index != 0x81) { /* clear ep halt */ + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_hub_dev_descriptor, + sizeof(qemu_hub_dev_descriptor)); + ret = sizeof(qemu_hub_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_hub_config_descriptor, + sizeof(qemu_hub_config_descriptor)); + + /* status change endpoint size based on number + * of ports */ + data[22] = (s->nb_ports + 1 + 7) / 8; + + ret = sizeof(qemu_hub_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "314159"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB Hub"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* usb specific requests */ + case GetHubStatus: + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + ret = 4; + break; + case GetPortStatus: + { + unsigned int n = index - 1; + USBHubPort *port; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + data[0] = port->wPortStatus; + data[1] = port->wPortStatus >> 8; + data[2] = port->wPortChange; + data[3] = port->wPortChange >> 8; + ret = 4; + } + break; + case SetHubFeature: + case ClearHubFeature: + if (value == 0 || value == 1) { + } else { + goto fail; + } + ret = 0; + break; + case SetPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->port.dev; + switch(value) { + case PORT_SUSPEND: + port->wPortStatus |= PORT_STAT_SUSPEND; + break; + case PORT_RESET: + if (dev) { + dev->handle_packet(dev, + USB_MSG_RESET, 0, 0, NULL, 0); + port->wPortChange |= PORT_STAT_C_RESET; + /* set enable bit */ + port->wPortStatus |= PORT_STAT_ENABLE; + } + break; + case PORT_POWER: + break; + default: + goto fail; + } + ret = 0; + } + break; + case ClearPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->port.dev; + switch(value) { + case PORT_ENABLE: + port->wPortStatus &= ~PORT_STAT_ENABLE; + break; + case PORT_C_ENABLE: + port->wPortChange &= ~PORT_STAT_C_ENABLE; + break; + case PORT_SUSPEND: + port->wPortStatus &= ~PORT_STAT_SUSPEND; + break; + case PORT_C_SUSPEND: + port->wPortChange &= ~PORT_STAT_C_SUSPEND; + break; + case PORT_C_CONNECTION: + port->wPortChange &= ~PORT_STAT_C_CONNECTION; + break; + case PORT_C_OVERCURRENT: + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; + break; + case PORT_C_RESET: + port->wPortChange &= ~PORT_STAT_C_RESET; + break; + default: + goto fail; + } + ret = 0; + } + break; + case GetHubDescriptor: + { + unsigned int n, limit, var_hub_size = 0; + memcpy(data, qemu_hub_hub_descriptor, + sizeof(qemu_hub_hub_descriptor)); + data[2] = s->nb_ports; + + /* fill DeviceRemovable bits */ + limit = ((s->nb_ports + 1 + 7) / 8) + 7; + for (n = 7; n < limit; n++) { + data[n] = 0x00; + var_hub_size++; + } + + /* fill PortPwrCtrlMask bits */ + limit = limit + ((s->nb_ports + 7) / 8); + for (;n < limit; n++) { + data[n] = 0xff; + var_hub_size++; + } + + ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = ret; + break; + } + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_hub_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + USBHubPort *port; + unsigned int status; + int i, n; + n = (s->nb_ports + 1 + 7) / 8; + if (len == 1) { /* FreeBSD workaround */ + n = 1; + } else if (n > len) { + return USB_RET_BABBLE; + } + status = 0; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + if (port->wPortChange) + status |= (1 << (i + 1)); + } + if (status != 0) { + for(i = 0; i < n; i++) { + data[i] = status >> (8 * i); + } + ret = n; + } else { + ret = USB_RET_NAK; /* usb11 11.13.1 */ + } + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_hub_broadcast_packet(USBHubState *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubPort *port; + USBDevice *dev; + int i, ret; + + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + dev = port->port.dev; + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { + ret = dev->handle_packet(dev, pid, + devaddr, devep, + data, len); + if (ret != USB_RET_NODEV) { + return ret; + } + } + } + return USB_RET_NODEV; +} + +static int usb_hub_handle_packet(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + +#if defined(DEBUG) && 0 + printf("usb_hub: pid=0x%x\n", pid); +#endif + if (dev->state == USB_STATE_DEFAULT && + dev->addr != 0 && + devaddr != dev->addr && + (pid == USB_TOKEN_SETUP || + pid == USB_TOKEN_OUT || + pid == USB_TOKEN_IN)) { + /* broadcast the packet to the devices */ + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); + } + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); +} + +static void usb_hub_handle_destroy(USBDevice *dev) +{ + USBHubState *s = (USBHubState *)dev; + + free(s); +} + +USBDevice *usb_hub_init(int nb_ports) +{ + USBHubState *s; + USBHubPort *port; + int i; + + if (nb_ports > MAX_PORTS) + return NULL; + s = (USBHubState *)qemu_mallocz(sizeof(USBHubState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_hub_handle_packet; + + /* generic USB device init */ + s->dev.handle_reset = usb_hub_handle_reset; + s->dev.handle_control = usb_hub_handle_control; + s->dev.handle_data = usb_hub_handle_data; + s->dev.handle_destroy = usb_hub_handle_destroy; + + strncpy(s->dev.devname, "QEMU USB Hub", sizeof(s->dev.devname)); + + s->nb_ports = nb_ports; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + port->port.opaque = s; + port->port.index = i; + port->port.attach = usb_hub_attach; + port->wPortStatus = PORT_STAT_POWER; + port->wPortChange = 0; + } + return (USBDevice *)s; +} diff --git a/plugins/usb/USBqemu/qemu-usb/usb-kbd.cpp b/plugins/usb/USBqemu/qemu-usb/usb-kbd.cpp new file mode 100644 index 0000000000..e4aa6b5f46 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-kbd.cpp @@ -0,0 +1,2115 @@ +/* + * QEMU USB HID devices + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +#define USB_MOUSE 1 +#define USB_TABLET 2 + +typedef struct USBKeyboardState { + USBDevice dev; + int keyboard_grabbed; +} USBKeyboardState; + +extern HWND gsWnd; + +#define VK_BASED + +#ifdef VK_BASED +static const uint8_t vk_to_key_code[] = { +0x00, //FAIL: 0x00 +0x00, //FAIL: LMOUSE +0x00, //FAIL: RMOUSE +0x00, //FAIL: Break +0x00, //FAIL: MMOUSE +0x00, //FAIL: X1MOUSE +0x00, //FAIL: X2MOUSE +0x00, //FAIL: 0x00 +0x2A, //OK: Backspace +0x2B, //OK: Tab +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x9C, //OK: Clear +0x28, //FAIL: ENTER +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: SHIFT +0x00, //FAIL: CTRL +0x00, //FAIL: ALT +0x48, //OK: Pause +0x39, //OK: Caps Lock +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +//0x00, //FAIL: 0x00 +//0x00, //FAIL: 0x00 +//0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x29, //FAIL: ESC +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x2C, //OK: Spacebar +#ifdef ENABLE_KEYPAD_Fx +0x4B, //FAIL: PAGE UP +0x4E, //FAIL: PAGE DOWN +0x4D, //OK: End +0x4A, //OK: Home +0x50, //FAIL: LEFT ARROW +0x52, //FAIL: UP ARROW +0x4F, //FAIL: RIGHT ARROW +0x51, //FAIL: DOWN ARROW +0x77, //OK: Select +0x00, //FAIL: PRINT +0x74, //OK: Execute +0x46, //FAIL: PRINT SCREEN +0x49, //FAIL: INS +0x4C, //FAIL: DEL +0x75, //OK: Help VK_HOME +#else +0x00, //FAIL: PAGE UP +0x00, //FAIL: PAGE DOWN +0x00, //OK: End +0x00, //OK: Home +0x00, //FAIL: LEFT ARROW +0x00, //FAIL: UP ARROW +0x00, //FAIL: RIGHT ARROW +0x00, //FAIL: DOWN ARROW +0x00, //OK: Select +0x00, //FAIL: PRINT +0x00, //OK: Execute +0x00, //FAIL: PRINT SCREEN +0x00, //FAIL: INS +0x00, //FAIL: DEL +0x00, //OK: Help VK_HOME +#endif +0x27, //OK: 0 +0x1E, //OK: 1 +0x1F, //OK: 2 +0x20, //OK: 3 +0x21, //OK: 4 +0x22, //OK: 5 +0x23, //OK: 6 +0x24, //OK: 7 +0x25, //OK: 8 +0x26, //OK: 9 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: not found +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x04, //OK: A +0x05, //OK: B +0x06, //OK: C +0x07, //OK: D +0x08, //OK: E +0x09, //OK: F +0x0A, //OK: G +0x0B, //OK: H +0x0C, //OK: I +0x0D, //OK: J +0x0E, //OK: K +0x0F, //OK: L +0x10, //OK: M +0x11, //OK: N +0x12, //OK: O +0x13, //OK: P +0x14, //OK: Q +0x15, //OK: R +0x16, //OK: S +0x17, //OK: T +0x18, //OK: U +0x19, //OK: V +0x1A, //OK: W +0x1B, //OK: X +0x1C, //OK: Y +0x1D, //OK: Z +#ifdef ENABLE_KEYPAD_Fx +0xE3, //OK: LGUI +0xE7, //OK: RGUI +0x65, //OK: Application +0x00, //FAIL: 0x00 +0x00, //FAIL: SLEEP +0x62, //OK: Keypad 0 +0x59, //OK: Keypad 1 +0x5A, //OK: Keypad 2 +0x5B, //OK: Keypad 3 +0x5C, //OK: Keypad 4 +0x5D, //OK: Keypad 5 +0x5E, //OK: Keypad 6 +0x5F, //OK: Keypad 7 +0x60, //OK: Keypad 8 +0x61, //OK: Keypad 9 +0x55, //OK: Keypad * +0x57, //OK: Keypad + +0x9F, //OK: Separator +0x56, //OK: Keypad - +0x63, //OK: Keypad . +0x54, //OK: Keypad / +0x3A, //OK: F1 +0x3B, //OK: F2 +0x3C, //OK: F3 +0x3D, //OK: F4 +0x3E, //OK: F5 +0x3F, //OK: F6 +0x40, //OK: F7 +0x41, //OK: F8 +0x42, //OK: F9 +0x43, //OK: F10 +0x44, //OK: F11 +0x45, //OK: F12 +0x68, //OK: F13 +0x69, //OK: F14 +0x6A, //OK: F15 +0x6B, //OK: F16 +0x6C, //OK: F17 +0x6D, //OK: F18 +0x6E, //OK: F19 +0x6F, //OK: F20 +0x70, //OK: F21 +0x71, //OK: F22 +0x72, //OK: F23 +0x73, //OK: F24 +#else +0x00, //OK: LGUI +0x00, //OK: RGUI +0x00, //OK: Application +0x00, //FAIL: 0x00 +0x00, //FAIL: SLEEP +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +#endif +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x83, //OK: NUM LOCK +0x47, //OK: Scroll Lock +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0xE1, //OK: LSHIFT +0xE5, //OK: RSHIFT +0xE0, //OK: LCONTROL +0xE4, //OK: RCONTROL +0xE3, //OK: LGUI +0xE7, //OK: RGUI +0x00, //FAIL: Windows 2000/XP: Browser Back +0x00, //FAIL: Windows 2000/XP: Browser Forward +0x00, //FAIL: Windows 2000/XP: Browser Refresh +0x00, //FAIL: Windows 2000/XP: Browser Stop +0x00, //FAIL: Windows 2000/XP: Browser Search +0x00, //FAIL: Windows 2000/XP: Browser Favorites +0x00, //FAIL: Windows 2000/XP: Browser Start and Home +0x00, //FAIL: Windows 2000/XP: Volume Mute +0x00, //FAIL: Windows 2000/XP: Volume Down +0x00, //FAIL: Windows 2000/XP: Volume Up +0x00, //FAIL: Windows 2000/XP: Next Track +0x00, //FAIL: Windows 2000/XP: Previous Track +0x00, //FAIL: Windows 2000/XP: Stop Media +0x00, //FAIL: Windows 2000/XP: Play/Pause Media +0x00, //FAIL: Windows 2000/XP: Start Mail +0x00, //FAIL: Windows 2000/XP: Select Media +0x00, //FAIL: Windows 2000/XP: Start Application 1 +0x00, //FAIL: Windows 2000/XP: Start Application 2 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x33, //FAIL: Windows 2000/XP: For the US standard keyboard, the ';:' key +0x2E, //FAIL: Windows 2000/XP: For any country/region, the '+' +0x36, //FAIL: Windows 2000/XP: For any country/region, the ',' +0x2D, //FAIL: Windows 2000/XP: For any country/region, the '-' +0x37, //FAIL: Windows 2000/XP: For any country/region, the '.' +0x38, //FAIL: Windows 2000/XP: For the US standard keyboard, the '/?' key +0x35, //FAIL: Windows 2000/XP: For the US standard keyboard, the '`~' key +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: not found +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x2F, //FAIL: Windows 2000/XP: For the US standard keyboard, the '[{' key +0x31, //FAIL: Windows 2000/XP: For the US standard keyboard, the '\|' key +0x30, //FAIL: Windows 2000/XP: For the US standard keyboard, the ']}' key +0x34, //FAIL: Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key +0x00, //FAIL: Used for miscellaneous characters; it can vary byboard. +0x00, //FAIL: Reserved +0x00, //FAIL: OEM specific +0x32, //FAIL: Windows 2000/XP: Either the angle bracket or the backslash key on the RT 102-key keyboard +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCEE6 +0x00, //FAIL: OEM specific +0x00, //FAIL: Windows 2000/XP: Used to pass Unicode characters as if they E8 +0x00, //FAIL: Unassigned +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: 0x00 +0x00, //FAIL: Attn +0xA3, //OK: CrSel +0xA4, //OK: ExSel +0x00, //FAIL: Erase EOF +0x00, //FAIL: Play +0x00, //FAIL: Zoom +0x00, //FAIL: Reserved +0x00, //FAIL: PA1 +0x9C, //OK: Clear +0x00, //FAIL: 0x00 +}; +#else +# ifdef ENABLE_KEYPAD_Fx +static const unsigned char scan_to_usb[] = { +0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, +0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, +0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, +0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x55,0xe3,0x2c,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, +0x3f,0x40,0x41,0x42,0x43,0x83,0x47,0x5f,0x60,0x61,0x56,0x5c,0x5d,0x5e,0x57,0x59, +0x5a,0x5b,0x62,0x63,0x46,0x00,0x32,0x44,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x75,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +# else +static const unsigned char scan_to_usb[] = { +0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, +0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, +0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, +0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x00,0xe3,0x2c,0x39,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x83,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x46,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +# endif +#endif + +/* mostly the same values as the Bochs USB Keyboard device */ +static const uint8_t qemu_keyboard_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x27, 0x06, /* u16 idVendor; */ + 0x01, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_keyboard_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x01, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 50, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_tablet_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x03, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 74, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_keyboard_hid_report_descriptor[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard Left Control) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; + +static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) +{ + static unsigned char keys[256]; + int i,l; + + if (!s->keyboard_grabbed) { + //qemu_add_keyboard_event_handler(usb_keyboard_event, s, 0); + s->keyboard_grabbed = 1; + } + + if(gsWnd != GetForegroundWindow()) + { + for(int i=0;i<256;i++) + { + keys[i] = 0; + } + } + else + { + for(int i=0;i<256;i++) + { + keys[i] = GetAsyncKeyState(i)>>8; + } + } + + l=1; + l=2; + buf[0] = 0; + if(keys[VK_LCONTROL]>>7) buf[0]|=(1<<0); + if(keys[VK_LSHIFT]>>7) buf[0]|=(1<<1); + if(keys[VK_LMENU]>>7) buf[0]|=(1<<2); //ALT key + if(keys[VK_LWIN]>>7) buf[0]|=(1<<3); + if(keys[VK_RCONTROL]>>7) buf[0]|=(1<<4); + if(keys[VK_RSHIFT]>>7) buf[0]|=(1<<5); + if(keys[VK_RMENU]>>7) buf[0]|=(1<<6); + if(keys[VK_RWIN]>>7) buf[0]|=(1<<7); + + buf[1] = 0; //reserved byte + + int k=0; + for(int i=0;i<256;i++) + { + if(keys[i]>>7) //if pressed + { + if(l==8) + { + buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=1; + } +#ifdef VK_BASED + int uc = vk_to_key_code[i]; +#else + int sc = MapVirtualKey(i,MAPVK_VK_TO_VSC_EX); + if((sc>>8)!=0) + sc=(sc&0x1FF)+256; + int uc = scan_to_usb[sc]; + printf("// %08x->%02x ",i,sc); + k++; +#endif + if((uc>0)&&(uc<=0x65)) // + buf[l++]=uc; + } + + } + if(k) printf("\n"); + + /*if(l>=1) + { + while(l<8) + buf[l++]=0; + printf("KEYS: %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + l=l; + }*/ + + while(l<7) + buf[l++]=0; + + return l; +} + +static void usb_keyboard_handle_reset(USBDevice *dev) +{ + USBKeyboardState *s = (USBKeyboardState *)dev; +} + +static int usb_keyboard_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBKeyboardState *s = (USBKeyboardState *)dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_keyboard_dev_descriptor, + sizeof(qemu_keyboard_dev_descriptor)); + ret = sizeof(qemu_keyboard_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_keyboard_config_descriptor, + sizeof(qemu_keyboard_config_descriptor)); + ret = sizeof(qemu_keyboard_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "Generic USB Keyboard"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + case 4: + ret = set_usb_string(data, "HID Keyboard"); + break; + case 5: + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case 0x22: + memcpy(data, qemu_keyboard_hid_report_descriptor, + sizeof(qemu_keyboard_hid_report_descriptor)); + ret = sizeof(qemu_keyboard_hid_report_descriptor); + break; + default: + goto fail; + } + break; + case GET_REPORT: + ret = usb_keyboard_poll(s, data, length); + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_keyboard_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBKeyboardState *s = (USBKeyboardState *)dev; + int ret = 0; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + ret = usb_keyboard_poll(s, data, len); + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static void usb_keyboard_handle_destroy(USBDevice *dev) +{ + USBKeyboardState *s = (USBKeyboardState *)dev; + + //qemu_add_keyboard_event_handler(NULL, NULL, 0); + free(s); +} + +USBDevice *usb_keyboard_init(void) +{ + USBKeyboardState *s; + + s = (USBKeyboardState *)malloc(sizeof(USBKeyboardState)); + if (!s) + return NULL; + memset(s,0,sizeof(USBKeyboardState)); + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_keyboard_handle_reset; + s->dev.handle_control = usb_keyboard_handle_control; + s->dev.handle_data = usb_keyboard_handle_data; + s->dev.handle_destroy = usb_keyboard_handle_destroy; + + strncpy(s->dev.devname, "Generic USB Keyboard", sizeof(s->dev.devname)); + + return (USBDevice *)s; +} + +#if 0 +#define PS2KBD_VERSION 0x100 + +#define USB_SUBCLASS_BOOT 1 +#define USB_HIDPROTO_KEYBOARD 1 + +#define PS2KBD_MAXDEV 2 +#define PS2KBD_MAXKEYS 6 + +#define PS2KBD_DEFLINELEN 4096 +#define PS2KBD_DEFREPEATRATE 100 +/* Default repeat rate in milliseconds */ +#define PS2KBD_REPEATWAIT 1000 +/* Number of milliseconds to wait before starting key repeat */ +#define USB_KEYB_NUMLOCK 0x53 +#define USB_KEYB_CAPSLOCK 0x39 +#define USB_KEYB_SCRLOCK 0x47 + +#define USB_KEYB_NUMPAD_START 0x54 +#define USB_KEYB_NUMPAD_END 0x63 + +#define SEMA_ZERO -419 +#define SEMA_DELETED -425 + +int ps2kbd_init(); +void ps2kbd_config_set(int resultCode, int bytes, void *arg); +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg); +void ps2kbd_data_recv(int resultCode, int bytes, void *arg); +int ps2kbd_probe(int devId); +int ps2kbd_connect(int devId); +int ps2kbd_disconnect(int devId); +void usb_getstring(int endp, int index, char *desc); + +typedef struct _kbd_data_recv + +{ + u8 mod_keys; + u8 reserved; + u8 keycodes[PS2KBD_MAXKEYS]; +} kbd_data_recv; + +typedef struct _keyb_dev + +{ + int configEndp; + int dataEndp; + int packetSize; + int devId; + int interfaceNo; /* Holds the interface number selected on this device */ + char repeatkeys[2]; + u32 eventmask; + u8 ledStatus; /* Maintains state on the led status */ + kbd_data_recv oldData; + kbd_data_recv data; /* Holds the data for the transfers */ +} kbd_dev; + +/* Global Variables */ + +int kbd_readmode; +int kbd_blocking; +u32 kbd_repeatrate; +kbd_dev *devices[PS2KBD_MAXDEV]; /* Holds a list of current devices */ +int dev_count; +UsbDriver kbd_driver = { NULL, NULL, "PS2Kbd", ps2kbd_probe, ps2kbd_connect, ps2kbd_disconnect }; +u8 *lineBuffer; +u32 lineStartP, lineEndP; +int lineSema; +int bufferSema; +u32 lineSize; +u8 keymap[PS2KBD_KEYMAP_SIZE]; /* Normal key map */ +u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; /* Shifted key map */ +u8 keycap[PS2KBD_KEYMAP_SIZE]; /* Does this key get shifted by capslock ? */ +u8 special_keys[PS2KBD_KEYMAP_SIZE]; +u8 control_map[PS2KBD_KEYMAP_SIZE]; +u8 alt_map[PS2KBD_KEYMAP_SIZE]; +//static struct fileio_driver kbd_fdriver; +iop_device_t kbd_filedrv; +u8 keyModValue[8] = { 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7 }; +int repeat_tid; +int eventid; /* Id of the repeat event */ + +int _start () +{ + FlushDcache(); + + ps2kbd_init(); + + printf("PS2KBD - USB Keyboard Library\n"); + + return 0; + +} + +int ps2kbd_probe(int devId) + +{ + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + //UsbStringDescriptor *str; + + if(dev_count >= PS2KBD_MAXDEV) + { + printf("ERROR: Maximum keyboard devices reached\n"); + return 0; + } + + //printf("PS2Kbd_probe devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 0; + } + + //printf("Device class %d, Size %d, Man %d, Product %d Cpnfigurations %d\n", dev->bDeviceClass, dev->bMaxPacketSize0, dev->iManufacturer, dev->iProduct, dev->bNumConfigurations); + /* Check that the device class is specified in the interfaces and it has at least one configuration */ + if((dev->bDeviceClass != USB_CLASS_PER_INTERFACE) || (dev->bNumConfigurations < 1)) + { + //printf("This is not the droid you're looking for\n"); + return 0; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 0; + } + //printf("Config Length %d Total %d Interfaces %d\n", conf->bLength, conf->wTotalLength, conf->bNumInterfaces); + + if((conf->bNumInterfaces < 1) || (conf->wTotalLength < (sizeof(UsbConfigDescriptor) + sizeof(UsbInterfaceDescriptor)))) + { + printf("ERROR: No interfaces available\n"); + return 0; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ +/* printf("Interface Length %d Endpoints %d Class %d Sub %d Proto %d\n", intf->bLength, */ +/* intf->bNumEndpoints, intf->bInterfaceClass, intf->bInterfaceSubClass, */ +/* intf->bInterfaceProtocol); */ + + if((intf->bInterfaceClass != USB_CLASS_HID) || (intf->bInterfaceSubClass != USB_SUBCLASS_BOOT) || + (intf->bInterfaceProtocol != USB_HIDPROTO_KEYBOARD) || (intf->bNumEndpoints < 1)) + + { + //printf("We came, we saw, we told it to fuck off\n"); + return 0; + } + + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + //printf("Endpoint 1 Addr %d, Attr %d, MaxPacket %d\n", endp->bEndpointAddress, endp->bmAttributes, endp->wMaxPacketSizeLB); + + if(((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) || + ((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)) + { + printf("ERROR: Endpoint not interrupt type and/or an input\n"); + return 0; + } + + printf("PS2KBD: Found a keyboard device\n"); + + return 1; +} + +int ps2kbd_connect(int devId) + +{ + /* Assume we can only get here if we have already checked the device is kosher */ + + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + kbd_dev *currDev; + int devLoop; + + //printf("PS2Kbd_connect devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 1; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 1; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if(devices[devLoop] == NULL) + { + break; + } + } + + if(devLoop == PS2KBD_MAXDEV) + { + /* How the f*** did we end up here ??? */ + printf("ERROR: Device Weirdness!!\n"); + return 1; + } + + currDev = (kbd_dev *) AllocSysMemory(0, sizeof(kbd_dev), NULL); + if(!currDev) + { + printf("ERROR: Couldn't allocate a device point for the kbd\n"); + return 1; + } + + devices[devLoop] = currDev; + memset(currDev, 0, sizeof(kbd_dev)); + currDev->configEndp = UsbOpenEndpoint(devId, NULL); + currDev->dataEndp = UsbOpenEndpoint(devId, endp); + currDev->packetSize = endp->wMaxPacketSizeLB | ((int) endp->wMaxPacketSizeHB << 8); + currDev->eventmask = (1 << devLoop); + if(currDev->packetSize > sizeof(kbd_data_recv)) + { + currDev->packetSize = sizeof(kbd_data_recv); + } + + if(dev->iManufacturer != 0) + { + usb_getstring(currDev->configEndp, dev->iManufacturer, "Keyboard Manufacturer"); + } + + if(dev->iProduct != 0) + { + usb_getstring(currDev->configEndp, dev->iProduct, "Keyboard Product"); + } + + currDev->devId = devId; + currDev->interfaceNo = intf->bInterfaceNumber; + currDev->ledStatus = 0; + + UsbSetDevicePrivateData(devId, currDev); /* Set the index for the device data */ + + //printf("Configuration value %d\n", conf->bConfigurationValue); + UsbSetDeviceConfiguration(currDev->configEndp, conf->bConfigurationValue, ps2kbd_config_set, currDev); + + dev_count++; /* Increment device count */ + printf("PS2KBD: Connected device\n"); + + return 0; +} + +int ps2kbd_disconnect(int devId) + +{ + int devLoop; + //printf("PS2Kbd_disconnect devId %d\n", devId); + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((devices[devLoop]) && (devices[devLoop]->devId == devId)) + { + dev_count--; + FreeSysMemory(devices[devLoop]); + devices[devLoop] = NULL; + printf("PS2KBD: Disconnected device\n"); + break; + } + } + + return 0; +} + +typedef struct _string_descriptor + +{ + u8 buf[200]; + char *desc; +} string_descriptor; + +void ps2kbd_getstring_set(int resultCode, int bytes, void *arg) + +{ + UsbStringDescriptor *str = (UsbStringDescriptor *) arg; + string_descriptor *strBuf = (string_descriptor *) arg; + char string[50]; + int strLoop; + +/* printf("=========getstring=========\n"); */ + +/* printf("PS2KEYBOARD: GET_DESCRIPTOR res %d, bytes %d, arg %p\n", resultCode, bytes, arg); */ + + if(resultCode == USB_RC_OK) + { + memset(string, 0, 50); + for(strLoop = 0; strLoop < ((bytes - 2) / 2); strLoop++) + { + string[strLoop] = str->wData[strLoop] & 0xFF; + } + printf("PS2KBD %s: %s\n", strBuf->desc, string); + } + + FreeSysMemory(arg); +} + +void usb_getstring(int endp, int index, char *desc) + +{ + u8 *data; + string_descriptor *str; + int ret; + + data = (u8 *) AllocSysMemory(0, sizeof(string_descriptor), NULL); + str = (string_descriptor *) data; + + if(data != NULL) + { + str->desc = desc; + ret = UsbControlTransfer(endp, 0x80, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | index, + 0, sizeof(string_descriptor) - 4, data, ps2kbd_getstring_set, data); + if(ret != USB_RC_OK) + { + printf("PS2KBD: Error sending string descriptor request\n"); + FreeSysMemory(data); + } + } +} + +void ps2kbd_config_set(int resultCode, int bytes, void *arg) + /* Called when we have finished choosing our configuration */ + +{ + kbd_dev *dev; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Configuration set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KEYBOARD: Configuration set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + /* Do a interrupt data transfer */ + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_IDLE, 0, dev->interfaceNo, 0, NULL, ps2kbd_idlemode_set, arg); + } +} + +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + + + + if(resultCode != USB_RC_OK) + { + printf("PS2KBD: Idlemode set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); + } +} + +void ps2kbd_led_set(int resultCode, int bytes, void *arg) + +{ + //printf("LED Set\n"); +} + +void ps2kbd_build_uniquekeys(u8 *res, const u8 *new, const u8 *old) + + /* Builds a list of unique keys */ + +{ + int loopNew, loopOld; + int loopRes = 0; + int foundKey; + + for(loopNew = 0; loopNew < PS2KBD_MAXKEYS; loopNew++) + { + if(new[loopNew] != 0) + { + foundKey = 0; + for(loopOld = 0; loopOld < PS2KBD_MAXKEYS; loopOld++) + { + if(new[loopNew] == old[loopOld]) + { + foundKey = 1; + break; + } + } + if(!foundKey) + { + res[loopRes++] = new[loopNew]; + } + } + } +} + +u32 ps2kbd_repeathandler(void *arg) + +{ + kbd_dev *dev = arg; + iop_sys_clock_t t; + //printf("Repeat handler\n"); + + iSetEventFlag(eventid, dev->eventmask); + + USec2SysClock(kbd_repeatrate * 1000, &t); + iSetAlarm(&t, (void *)ps2kbd_repeathandler, arg); + + return t.hi; +} + +void ps2kbd_getkeys(u8 keyMods, u8 ledStatus, const u8 *keys, kbd_dev *dev) + +{ + int loopKey; + int tempPos = 0; + int byteCount = 0; + u8 currChars[2]; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + u8 currKey = keys[loopKey]; + + currChars[0] = 0; + currChars[1] = 0; + + if(lineEndP == (tempPos - 1)) + { + break; + } + + if(currKey) /* If this is a valid key */ + { + if((currKey >= USB_KEYB_NUMPAD_START) && (currKey <= USB_KEYB_NUMPAD_END)) + /* Handle numpad specially */ + { + if(ledStatus & PS2KBD_LED_NUMLOCK) + { + if(keymap[currKey]) + { + currChars[0] = keymap[currKey]; + } + } + else + { + if(special_keys[currKey]) + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keymap[currKey] != '5') /* Make sure this isnt a 5 key :) */ + { + currChars[0] = keymap[currKey]; + } + } + } + else if(special_keys[currKey]) /* This is a special key */ + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keyMods & PS2KBD_CTRL) /* CTRL */ + { + if(control_map[currKey]) + { + currChars[0] = control_map[currKey]; + } + } + else if(keyMods & PS2KBD_ALT) /* ALT */ + { + if(alt_map[currKey]) + { + currChars[0] = alt_map[currKey]; + } + } + else if(keyMods & PS2KBD_SHIFT) /* SHIFT */ + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = keymap[currKey]; + } + else + { + currChars[0] = shiftkeymap[currKey]; + } + } + else /* Normal key */ + { + if(keymap[keys[loopKey]]) + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = shiftkeymap[currKey]; + } + else + { + currChars[0] = keymap[currKey]; + } + } + } + } + + if((currChars[0] == PS2KBD_ESCAPE_KEY) && (currChars[1] != 0)) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currChars[1]; + lineEndP %= lineSize; + byteCount += 2; + } + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = currChars[1]; + } + else if(currChars[0] != 0) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + byteCount++; + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = 0; + } + } + + if(byteCount > 0) + { + iop_sys_clock_t t; + /* Set alarm to do repeat rate */ + //printf("repeatkeys %d %d\n", kbd_repeatkeys[0], kbd_repeatkeys[1]); + USec2SysClock(PS2KBD_REPEATWAIT * 1000, &t); + SetAlarm(&t, (void *)ps2kbd_repeathandler, dev); + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema to indicate data */ + { + SignalSema(bufferSema); + } + +/* lineBuffer[PS2KBD_DEFLINELEN - 1] = 0; */ +/* printf(lineBuffer); */ + //printf("lineStart %d, lineEnd %d\n", lineStartP, lineEndP); +} + + +void ps2kbd_getkeys_raw(u8 newKeyMods, u8 oldKeyMods, u8 *new, const u8 *old) + +{ + int loopKey; + u8 currKey; + u8 keyMods = newKeyMods ^ oldKeyMods; + u8 keyModsMap = newKeyMods & keyMods; + int tempPos = 0; + int byteCount = 0; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < 8; loopKey++) + { + int currMod = (1 << loopKey); + if(keyMods & currMod) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + currKey = keyModValue[loopKey]; + + if(keyModsMap & currMod) /* If key pressed */ + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + //printf("Key down\n"); + } + else + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + //printf("Key up\n"); + } + + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currKey; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key %d\n", currKey); + } + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(new[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = new[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key down\nKey %d\n", new[loopKey]); + } + + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(old[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = old[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key up\nKey %d\n", old[loopKey]); + } + + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema for the number of bytes read */ + { + SignalSema(bufferSema); + } +} + +void ps2kbd_data_recv(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + int ret; + int phantom; + int loop; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KBD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + + dev = (kbd_dev *) arg; + if(dev == NULL) + { + printf("PS2KBD: dev == NULL\n"); + return; + } + +/* printf("PS2KBD Modifiers %02X, Keys ", dev->data.mod_keys); */ +/* for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) */ +/* { */ +/* printf("%02X ", dev->data.keycodes[loop]); */ +/* } */ +/* printf("\n"); */ + + CancelAlarm((void *)ps2kbd_repeathandler, dev); /* Make sure repeat alarm is cancelled */ + + /* Check for phantom states */ + phantom = 1; + for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) + { + if(dev->data.keycodes[loop] != 1) + { + phantom = 0; + break; + } + } + + if(!phantom) /* If not in a phantom state */ + { + u8 uniqueKeys[PS2KBD_MAXKEYS]; + u8 missingKeys[PS2KBD_MAXKEYS]; + int loopKey; + + memset(uniqueKeys, 0, PS2KBD_MAXKEYS); + memset(missingKeys, 0, PS2KBD_MAXKEYS); + ps2kbd_build_uniquekeys(uniqueKeys, dev->data.keycodes, dev->oldData.keycodes); + ps2kbd_build_uniquekeys(missingKeys, dev->oldData.keycodes, dev->data.keycodes); + /* Build new and missing key lists */ + +/* printf("Unique keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", uniqueKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + +/* printf("Missing keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", missingKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + + if(kbd_readmode == PS2KBD_READMODE_NORMAL) + { + u8 ledStatus; + + ledStatus = dev->ledStatus; + //printf("ledStatus %02X\n", ledStatus); + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) /* Process key codes */ + { + switch(uniqueKeys[loopKey]) + { + case USB_KEYB_NUMLOCK : + ledStatus ^= PS2KBD_LED_NUMLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_CAPSLOCK : + ledStatus ^= PS2KBD_LED_CAPSLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_SCRLOCK : + ledStatus ^= PS2KBD_LED_SCRLOCK; + uniqueKeys[loopKey] = 0; + break; + } + } + + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + //printf("LEDS %02X\n", dev->ledStatus); + /* Call Set LEDS */ + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, arg); + } + + WaitSema(lineSema); /* Make sure no other thread is going to manipulate the buffer */ + ps2kbd_getkeys(dev->data.mod_keys, dev->ledStatus, uniqueKeys, dev); /* read in remaining keys */ + SignalSema(lineSema); + } + else /* RAW Mode */ + { + WaitSema(lineSema); + ps2kbd_getkeys_raw(dev->data.mod_keys, dev->oldData.mod_keys, uniqueKeys, missingKeys); + SignalSema(lineSema); + } + + memcpy(&dev->oldData, &dev->data, sizeof(kbd_data_recv)); + } + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); +} + +void flushbuffer() + +{ + iop_sema_t s; + + lineStartP = 0; + lineEndP = 0; + memset(lineBuffer, 0, lineSize); + + DeleteSema(bufferSema); + s.initial = 0; + s.max = lineSize; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + + if(bufferSema <= 0) + { + printf("PS2KBD: Error creating buffer sema\n"); + } +} + +void ps2kbd_ioctl_setreadmode(u32 readmode) + +{ + int devLoop; + + if(readmode == kbd_readmode) return; + + if((readmode == PS2KBD_READMODE_NORMAL) || (readmode == PS2KBD_READMODE_RAW)) + { + /* Reset line buffer */ + //printf("ioctl_setreadmode %d\n", readmode); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + CancelAlarm((void *)ps2kbd_repeathandler, devices[devLoop]); + } + + WaitSema(lineSema); + kbd_readmode = readmode; + flushbuffer(); + SignalSema(lineSema); + } +} + +void ps2kbd_ioctl_setkeymap(kbd_keymap *keymaps) + +{ + //printf("ioctl_setkeymap %p\n", keymaps); + WaitSema(lineSema); /* Lock the input so you dont end up with weird results */ + memcpy(keymap, keymaps->keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, keymaps->shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, keymaps->keycap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_setctrlmap(u8 *ctrlmap) + +{ + //printf("ioctl_setctrlmap %p\n", ctrlmap); + WaitSema(lineSema); + memcpy(control_map, ctrlmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_setaltmap(u8 *altmap) + +{ + //printf("ioctl_setaltmap %p\n", altmap); + WaitSema(lineSema); + memcpy(alt_map, altmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_setspecialmap(u8 *special) + +{ + //printf("ioctl_setspecialmap %p\n", special); + WaitSema(lineSema); + memcpy(special_keys, special, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_resetkeymap() + /* Reset keymap to default US variety */ + +{ + //printf("ioctl_resetkeymap()\n"); + WaitSema(lineSema); + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_flushbuffer() + /* Flush the internal buffer */ + +{ + //printf("ioctl_flushbuffer()\n"); + WaitSema(lineSema); + flushbuffer(); + SignalSema(lineSema); +} + +void ps2kbd_ioctl_setleds(u8 ledStatus) + +{ + int devLoop; + kbd_dev *dev; + + //printf("ioctl_setleds %d\n", ledStatus); + ledStatus &= PS2KBD_LED_MASK; + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + dev = devices[devLoop]; + if(dev) + { + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, dev); + } + } + } +} + +void ps2kbd_ioctl_setblockmode(u32 blockmode) + +{ + if((blockmode == PS2KBD_BLOCKING) || (blockmode == PS2KBD_NONBLOCKING)) + { + kbd_blocking = blockmode; + //printf("ioctl_setblockmode %d\n", blockmode); + } +} + +void ps2kbd_ioctl_setrepeatrate(u32 rate) + +{ + kbd_repeatrate = rate; +} + +int fio_dummy() +{ + //printf("fio_dummy()\n"); + return -5; +} + +int fio_init(iop_device_t *driver) +{ + //printf("fio_init()\n"); + return 0; +} + +int fio_format(iop_file_t *f) +{ + //printf("fio_format()\n"); + return 0; +} + +int fio_open(iop_file_t *f, const char *name, int mode) +{ + //printf("fio_open() %s %d\n", name, mode); + if(strcmp(name, PS2KBD_KBDFILE)) /* If not the keyboard file */ + { + return -1; + } + + return 0; +} + +int fio_read(iop_file_t *f, void *buf, int size) + +{ + int count = 0; + char *data = (char *) buf; + int ret; + + //printf("fio_read() %p %d\n", buf, size); + + if(kbd_readmode == PS2KBD_READMODE_RAW) + { + size &= ~1; /* Ensure size of a multiple of 2 */ + } + + ret = PollSema(bufferSema); + if(ret < 0) + { + if((ret == SEMA_ZERO) && (kbd_blocking == PS2KBD_BLOCKING)) + { + //printf("Blocking\n"); + ret = WaitSema(bufferSema); + if(ret < 0) /* Means either an error or the sema was deleted from under us */ + { + return 0; + } + } + else + { + return 0; + } + } + + SignalSema(bufferSema); + ret = WaitSema(lineSema); + if(ret < 0) return 0; + + while((count < size) && (lineStartP != lineEndP)) + { + data[count] = lineBuffer[lineStartP++]; + lineStartP %= lineSize; + count++; + PollSema(bufferSema); /* Take off one count from the sema */ + } + + SignalSema(lineSema); +/* //printf("read %d bytes\n", count); */ +/* { */ +/* struct t_sema_status s; */ + +/* ReferSemaStatus(bufferSema, &s); */ +/* //printf("Sema count %d\n", s.curr_count); */ +/* } */ + + return count; +} + +int fio_ioctl(iop_file_t *f, unsigned long arg, void *param) + +{ + //printf("fio_ioctl() %ld %d\n", arg, *((u32 *) param)); + switch(arg) + { + case PS2KBD_IOCTL_SETREADMODE: ps2kbd_ioctl_setreadmode(*((u32 *) param)); + break; + case PS2KBD_IOCTL_SETKEYMAP: ps2kbd_ioctl_setkeymap((kbd_keymap *) param); + break; + case PS2KBD_IOCTL_SETALTMAP: ps2kbd_ioctl_setaltmap((u8 *) param); + break; + case PS2KBD_IOCTL_SETCTRLMAP: ps2kbd_ioctl_setctrlmap((u8 *) param); + break; + case PS2KBD_IOCTL_SETSPECIALMAP: ps2kbd_ioctl_setspecialmap((u8 *) param); + break; + case PS2KBD_IOCTL_FLUSHBUFFER: ps2kbd_ioctl_flushbuffer(); + break; + case PS2KBD_IOCTL_SETLEDS: ps2kbd_ioctl_setleds(*(u8*) param); + break; + case PS2KBD_IOCTL_SETBLOCKMODE: ps2kbd_ioctl_setblockmode(*(u32 *) param); + break; + case PS2KBD_IOCTL_RESETKEYMAP: ps2kbd_ioctl_resetkeymap(); + break; + case PS2KBD_IOCTL_SETREPEATRATE: ps2kbd_ioctl_setrepeatrate(*(u32 *) param); + break; + default : return -1; + } + + return 0; +} + +int fio_close(iop_file_t *f) + +{ + //printf("fio_close()\n"); + return 0; +} + +iop_device_ops_t fio_ops = + + { + fio_init, + fio_dummy, + fio_format, + fio_open, + fio_close, + fio_read, + fio_dummy, + fio_dummy, + fio_ioctl, + fio_dummy, + fio_dummy, + fio_dummy, + fio_dummy, + fio_dummy, + fio_dummy, + fio_dummy, + fio_dummy + }; + +int init_fio() + +{ + kbd_filedrv.name = PS2KBD_FSNAME; + kbd_filedrv.type = IOP_DT_CHAR; + kbd_filedrv.version = 0; + kbd_filedrv.desc = "USB Keyboard FIO driver"; + kbd_filedrv.ops = &fio_ops; + return AddDrv(&kbd_filedrv); +} + +void repeat_thread(void *arg) + +{ + u32 eventmask; + int devLoop; + + for(;;) + { + WaitEventFlag(eventid, 0xFFFFFFFF, 0x01 | 0x10, &eventmask); + //printf("Recieved event %08X\n", eventmask); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((eventmask & (1 << devLoop)) && (devices[devLoop])) + { + int tempPos = 0; + + WaitSema(lineSema); + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + if((devices[devLoop]->repeatkeys[0]) && (devices[devLoop]->repeatkeys[1])) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[1]; + lineEndP %= lineSize; + SignalSema(bufferSema); + SignalSema(bufferSema); + } + } + else if(devices[devLoop]->repeatkeys[0]) + { + if(lineEndP != (tempPos - 1)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + SignalSema(bufferSema); + } + } + + SignalSema(lineSema); + } + } + } +} + +int init_repeatthread() + /* Creates a thread to handle key repeats */ + +{ + iop_thread_t param; + iop_event_t event; + + event.attr = 0; + event.option = 0; + event.bits = 0; + eventid = CreateEventFlag(&event); + + param.attr = TH_C; + param.thread = repeat_thread; + param.priority = 40; + param.stacksize = 0x800; + param.option = 0; + + repeat_tid = CreateThread(¶m); + if (repeat_tid > 0) { + StartThread(repeat_tid, 0); + return 0; + } + else + { + return 1; + } +} + +int ps2kbd_init() + +{ + int ret; + iop_sema_t s; + + s.initial = 1; + s.max = 1; + s.option = 0; + s.attr = 0; + lineSema = CreateSema(&s); + if(lineSema <= 0) + { + printf("PS2KBD: Error creating sema\n"); + return 1; + } + + s.initial = 0; + s.max = PS2KBD_DEFLINELEN; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + if(bufferSema <= 0) + { + printf("PS2KBD: Error creating buffer sema\n"); + return 1; + } + + lineBuffer = (u8 *) AllocSysMemory(0, PS2KBD_DEFLINELEN, NULL); + if(lineBuffer == NULL) + { + printf("PS2KBD: Error allocating line buffer\n"); + return 1; + } + lineStartP = 0; + lineEndP = 0; + lineSize = PS2KBD_DEFLINELEN; + memset(lineBuffer, 0, PS2KBD_DEFLINELEN); + + memset(devices, 0, sizeof(kbd_dev *) * PS2KBD_MAXDEV); + dev_count = 0; + kbd_blocking = PS2KBD_NONBLOCKING; + kbd_readmode = PS2KBD_READMODE_NORMAL; + kbd_repeatrate = PS2KBD_DEFREPEATRATE; + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + + ret = init_fio(); + //printf("ps2kbd AddDrv [%d]\n", ret); + init_repeatthread(); + + ret = UsbRegisterDriver(&kbd_driver); + if(ret != USB_RC_OK) + { + printf("PS2KBD: Error registering USB devices\n"); + return 1; + } + + //printf("UsbRegisterDriver %d\n", ret); + + return 0; +} +#endif \ No newline at end of file diff --git a/plugins/usb/USBqemu/qemu-usb/usb-msd.c b/plugins/usb/USBqemu/qemu-usb/usb-msd.c new file mode 100644 index 0000000000..ff2047d4b2 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-msd.c @@ -0,0 +1,402 @@ +/* + * USB Mass Storage Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +//#define DEBUG_MSD + +#ifdef DEBUG_MSD +#define DPRINTF(fmt, args...) \ +do { printf("usb-msd: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +/* USB requests. */ +#define MassStorageReset 0xff +#define GetMaxLun 0xfe + +enum USBMSDMode { + USB_MSDM_CBW, /* Command Block. */ + USB_MSDM_DATAOUT, /* Tranfer data to device. */ + USB_MSDM_DATAIN, /* Transfer data from device. */ + USB_MSDM_CSW /* Command Status. */ +}; + +typedef struct { + USBDevice dev; + enum USBMSDMode mode; + uint32_t data_len; + uint32_t tag; + SCSIDevice *scsi_dev; + int result; +} MSDState; + +static const uint8_t qemu_msd_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + /* Vendor and product id are arbitrary. */ + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_msd_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x20, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */ + 0x06, /* u8 if_bInterfaceSubClass; SCSI */ + 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ + 0x00, /* u8 if_iInterface; */ + + /* Bulk-In endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + + /* Bulk-Out endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00 /* u8 ep_bInterval; */ +}; + +static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) +{ + MSDState *s = (MSDState *)opaque; + + DPRINTF("Command complete\n"); + s->result = fail; + s->mode = USB_MSDM_CSW; +} + +static void usb_msd_handle_reset(USBDevice *dev) +{ + MSDState *s = (MSDState *)dev; + + DPRINTF("Reset\n"); + s->mode = USB_MSDM_CBW; +} + +static int usb_msd_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_msd_dev_descriptor, + sizeof(qemu_msd_dev_descriptor)); + ret = sizeof(qemu_msd_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_msd_config_descriptor, + sizeof(qemu_msd_config_descriptor)); + ret = sizeof(qemu_msd_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB HARDDRIVE"); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0 && index != 0x81) { /* clear ep halt */ + goto fail; + } + ret = 0; + break; + /* Class specific requests. */ + case MassStorageReset: + /* Reset state ready for the next CBW. */ + s->mode = USB_MSDM_CBW; + ret = 0; + break; + case GetMaxLun: + data[0] = 0; + ret = 1; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +struct usb_msd_cbw { + uint32_t sig; + uint32_t tag; + uint32_t data_len; + uint8_t flags; + uint8_t lun; + uint8_t cmd_len; + uint8_t cmd[16]; +}; + +struct usb_msd_csw { + uint32_t sig; + uint32_t tag; + uint32_t residue; + uint8_t status; +}; + +static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, + uint8_t *data, int len) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + struct usb_msd_cbw cbw; + struct usb_msd_csw csw; + + switch (pid) { + case USB_TOKEN_OUT: + if (devep != 2) + goto fail; + + switch (s->mode) { + case USB_MSDM_CBW: + if (len != 31) { + fprintf(stderr, "usb-msd: Bad CBW size"); + goto fail; + } + memcpy(&cbw, data, 31); + if (le32_to_cpu(cbw.sig) != 0x43425355) { + fprintf(stderr, "usb-msd: Bad signature %08x\n", + le32_to_cpu(cbw.sig)); + goto fail; + } + DPRINTF("Command on LUN %d\n", cbw.lun); + if (cbw.lun != 0) { + fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); + goto fail; + } + s->tag = le32_to_cpu(cbw.tag); + s->data_len = le32_to_cpu(cbw.data_len); + if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } else if (cbw.flags & 0x80) { + s->mode = USB_MSDM_DATAIN; + } else { + s->mode = USB_MSDM_DATAOUT; + } + DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", + s->tag, cbw.flags, cbw.cmd_len, s->data_len); + scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + ret = len; + break; + + case USB_MSDM_DATAOUT: + DPRINTF("Data out %d/%d\n", len, s->data_len); + if (len > s->data_len) + goto fail; + + if (scsi_write_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected write (len %d)\n", len); + goto fail; + } + break; + + case USB_TOKEN_IN: + if (devep != 1) + goto fail; + + switch (s->mode) { + case USB_MSDM_CSW: + DPRINTF("Command status %d tag 0x%x, len %d\n", + s->result, s->tag, len); + if (len < 13) + goto fail; + + csw.sig = cpu_to_le32(0x53425355); + csw.tag = cpu_to_le32(s->tag); + csw.residue = 0; + csw.status = s->result; + memcpy(data, &csw, 13); + ret = 13; + s->mode = USB_MSDM_CBW; + break; + + case USB_MSDM_DATAIN: + DPRINTF("Data in %d/%d\n", len, s->data_len); + if (len > s->data_len) + len = s->data_len; + + if (scsi_read_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected read (len %d)\n", len); + goto fail; + } + break; + + default: + DPRINTF("Bad token\n"); + fail: + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void usb_msd_handle_destroy(USBDevice *dev) +{ + MSDState *s = (MSDState *)dev; + + scsi_disk_destroy(s->scsi_dev); + qemu_free(s); +} + +USBDevice *usb_msd_init(const char *filename) +{ + MSDState *s; + BlockDriverState *bdrv; + + s = qemu_mallocz(sizeof(MSDState)); + if (!s) + return NULL; + + bdrv = bdrv_new("usb"); + bdrv_open(bdrv, filename, 0); + + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_msd_handle_reset; + s->dev.handle_control = usb_msd_handle_control; + s->dev.handle_data = usb_msd_handle_data; + s->dev.handle_destroy = usb_msd_handle_destroy; + + snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", + filename); + + s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); + usb_msd_handle_reset((USBDevice *)s); + return (USBDevice *)s; +} diff --git a/plugins/usb/USBqemu/qemu-usb/usb-ohci.cpp b/plugins/usb/USBqemu/qemu-usb/usb-ohci.cpp new file mode 100644 index 0000000000..0432149a35 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb-ohci.cpp @@ -0,0 +1,985 @@ +/* + * QEMU USB OHCI Emulation + * Copyright (c) 2004 Gianni Tedesco + * Copyright (c) 2006 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * o Isochronous transfers + * o Allocate bandwidth in frames properly + * o Disable timers when nothing needs to be done, or remove timer usage + * all together. + * o Handle unrecoverable errors properly + * o BIOS work to boot from USB storage +*/ + +//typedef CPUReadMemoryFunc + +#include "vl.h" +#include "../USB.h" + +uint32_t bits = 0; +uint32_t need_interrupt = 0; + +extern FILE* usbLog; + +int dprintf(const char *fmt,...) +{ +#ifdef DEBUG_OHCI + int t; + va_list list; + + va_start(list, fmt); + t=vfprintf(stderr, fmt, list); + va_end(list); + + if(usbLog) + { + va_start(list, fmt); + vfprintf(usbLog, fmt, list); + va_end(list); + } + + return t; +#else + return 0; +#endif +} + +/* Update IRQ levels */ +static inline void ohci_intr_update(OHCIState *ohci) +{ + bits = (ohci->intr_status & ohci->intr) & 0x7fffffff; + + if ((ohci->intr & OHCI_INTR_MIE) && (bits!=0)) // && (ohci->ctl & OHCI_CTL_HCFS)) + { + /* + static char reasons[1024]; + int first=1; + + reasons[0]=0; + +#define reason_add(p,t) if(bits&(p)) { if(!first) strcat_s(reasons,1024,", "); first=0; strcat_s(reasons,1024,t); } + reason_add(OHCI_INTR_SO,"Scheduling overrun"); + reason_add(OHCI_INTR_WD,"HcDoneHead writeback"); + reason_add(OHCI_INTR_SF,"Start of frame"); + reason_add(OHCI_INTR_RD,"Resume detect"); + reason_add(OHCI_INTR_UE,"Unrecoverable error"); + reason_add(OHCI_INTR_FNO,"Frame number overflow"); + reason_add(OHCI_INTR_RHSC,"Root hub status change"); + reason_add(OHCI_INTR_OC,"Ownership change"); + */ + if((ohci->ctl & OHCI_CTL_HCFS)==OHCI_USB_OPERATIONAL) + { + USBirq(1); + //dprintf("usb-ohci: Interrupt Called. Reason(s): %s\n",reasons); + } + } +} + +/* Set an interrupt */ +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) +{ + ohci->intr_status |= intr; + ohci_intr_update(ohci); +} + +//static void usb_attach(USBPort *port, USBDevice *dev) +//{ +// port->attach(port,dev); +//} + +/* Attach or detach a device on a root hub port. */ +static void ohci_attach(USBPort *port1, USBDevice *dev) +{ + OHCIState *s = (OHCIState *)port1->opaque; + OHCIPort *port = (OHCIPort *)&s->rhport[port1->index]; + uint32_t old_state = port->ctrl; + + if (dev) { + if (port->port.dev) { + usb_attach(port1, NULL); + } + /* set connect status */ + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + + /* update speed */ + if (dev->speed == USB_SPEED_LOW) + port->ctrl |= OHCI_PORT_LSDA; + else + port->ctrl &= ~OHCI_PORT_LSDA; + port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); + dprintf("usb-ohci: Attached port %d\n", port1->index); + } else { + /* set connect status */ + if (port->ctrl & OHCI_PORT_CCS) { + port->ctrl &= ~OHCI_PORT_CCS; + port->ctrl |= OHCI_PORT_CSC; + } + /* disable port */ + if (port->ctrl & OHCI_PORT_PES) { + port->ctrl &= ~OHCI_PORT_PES; + port->ctrl |= OHCI_PORT_PESC; + } + dev = port->port.dev; + if (dev) { + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); + } + port->port.dev = NULL; + dprintf("usb-ohci: Detached port %d\n", port1->index); + } + + if (old_state != port->ctrl) + ohci_set_interrupt(s, OHCI_INTR_RHSC); +} + +/* Reset the controller */ +static void ohci_reset(OHCIState *ohci) +{ + OHCIPort *port; + int i; + + ohci->ctl = 0; + ohci->status = 0; + ohci->intr_status = 0; + ohci->intr = OHCI_INTR_MIE; + + + + ohci->hcca = 0; + ohci->ctrl_head = ohci->ctrl_cur = 0; + ohci->bulk_head = ohci->bulk_cur = 0; + ohci->per_cur = 0; + ohci->done = 0; + ohci->done_count = 7; + + /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? + * I took the value linux sets ... + */ + ohci->fsmps = 0x2778; + ohci->fi = 0x2edf; + ohci->fit = 0; + ohci->frt = 0; + ohci->frame_number = 0; + ohci->pstart = 0; + ohci->lst = OHCI_LS_THRESH; + + ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; + ohci->rhdesc_b = 0x0; /* Impl. specific */ + ohci->rhstatus = 0; + + for (i = 0; i < ohci->num_ports; i++) + { + port = &ohci->rhport[i]; + port->ctrl = 0; + if (port->port.dev) + ohci_attach(&port->port, port->port.dev); + } + dprintf("usb-ohci: Reset.\n"); +} + +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +/* Get an array of dwords from main memory */ +static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + *buf = le32_to_cpu(*buf); + } + + return 1; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + } + + return 1; +} + +static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed) +{ + return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_read_td(uint32_t addr, struct ohci_td *td) +{ + return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed) +{ + return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_put_td(uint32_t addr, struct ohci_td *td) +{ + return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +/* Read/Write the contents of a TD from/to main memory. */ +static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) +{ + uint32_t ptr; + uint32_t n; + + ptr = td->cbp; + n = 0x1000 - (ptr & 0xfff); + if (n > len) + n = len; + cpu_physical_memory_rw(ptr, buf, n, write); + if (n == len) + return; + ptr = td->be & ~0xfffu; + buf += n; + cpu_physical_memory_rw(ptr, buf, len - n, write); +} + +/* Service a transport descriptor. + Returns nonzero to terminate processing of this endpoint. */ + +static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) +{ + int dir; + size_t len = 0; + uint8_t buf[8192]; + char *str = NULL; + int pid; + int ret; + int i; + USBDevice *dev; + struct ohci_td td; + uint32_t addr; + int flag_r; + + addr = ed->head & OHCI_DPTR_MASK; + if (!ohci_read_td(addr, &td)) { + fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + return 0; + } + + dir = OHCI_BM(ed->flags, ED_D); + switch (dir) { + case OHCI_TD_DIR_OUT: + case OHCI_TD_DIR_IN: + /* Same value. */ + break; + default: + dir = OHCI_BM(td.flags, TD_DP); + break; + } + + switch (dir) { + case OHCI_TD_DIR_IN: + str = "in"; + pid = USB_TOKEN_IN; + break; + case OHCI_TD_DIR_OUT: + str = "out"; + pid = USB_TOKEN_OUT; + break; + case OHCI_TD_DIR_SETUP: + str = "setup"; + pid = USB_TOKEN_SETUP; + break; + default: + fprintf(stderr, "usb-ohci: Bad direction\n"); + return 1; + } + if (td.cbp && td.be) { + if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { + len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); + } else { + len = (td.be - td.cbp) + 1; + } + + if (len && dir != OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, len, 0); + } + } + + flag_r = (td.flags & OHCI_TD_R) != 0; +#ifdef DEBUG_PACKET + dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", + addr, len, str, flag_r, td.cbp, td.be); + + if (len >= 0 && dir != OHCI_TD_DIR_IN) { + dprintf(" data:"); + for (i = 0; i < len; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); + } +#endif + ret = USB_RET_NODEV; + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) + continue; + + ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), + OHCI_BM(ed->flags, ED_EN), buf, len); + if (ret != USB_RET_NODEV) + break; + } +#ifdef DEBUG_PACKET + dprintf("ret=%d\n", ret); +#endif + if (ret >= 0) { + if (dir == OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, ret, 1); +#ifdef DEBUG_PACKET + dprintf(" data:"); + for (i = 0; i < ret; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); +#endif + } else { + ret = len; + } + } + + /* Writeback */ + if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { + /* Transmission succeeded. */ + if (ret == len) { + td.cbp = 0; + } else { + td.cbp += ret; + if ((td.cbp & 0xfff) + ret > 0xfff) { + td.cbp &= 0xfff; + td.cbp |= td.be & ~0xfff; + } + } + td.flags |= OHCI_TD_T1; + td.flags ^= OHCI_TD_T0; + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); + OHCI_SET_BM(td.flags, TD_EC, 0); + + ed->head &= ~OHCI_ED_C; + if (td.flags & OHCI_TD_T0) + ed->head |= OHCI_ED_C; + } else { + if (ret >= 0) { + dprintf("usb-ohci: Underrun\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { + case USB_RET_NODEV: + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); + case USB_RET_NAK: + dprintf("usb-ohci: got NAK\n"); + return 1; + case USB_RET_STALL: + dprintf("usb-ohci: got STALL\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); + break; + case USB_RET_BABBLE: + dprintf("usb-ohci: got BABBLE\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); + break; + default: + fprintf(stderr, "usb-ohci: Bad device response %d\n", ret); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); + OHCI_SET_BM(td.flags, TD_EC, 3); + break; + } + } + ed->head |= OHCI_ED_H; + } + + /* Retire this TD */ + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= td.next & OHCI_DPTR_MASK; + td.next = ohci->done; + ohci->done = addr; + i = OHCI_BM(td.flags, TD_DI); + if (i < ohci->done_count) + ohci->done_count = i; + ohci_put_td(addr, &td); + return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; +} + +/* Service an endpoint list. Returns nonzero if active TD were found. */ +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) +{ + struct ohci_ed ed; + uint32_t next_ed; + uint32_t cur; + int active; + + active = 0; + + if (head == 0) + return 0; + + for (cur = head; cur; cur = next_ed) { + if (!ohci_read_ed(cur, &ed)) { + fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + return 0; + } + + next_ed = ed.next & OHCI_DPTR_MASK; + + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) + continue; + + /* Skip isochronous endpoints. */ + if (ed.flags & OHCI_ED_F) + continue; + + while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { +#ifdef DEBUG_PACKET + dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " + "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur, + OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), + OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, + (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, + OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0, + (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, + ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); +#endif + active = 1; + + if (ohci_service_td(ohci, &ed)) + break; + } + + ohci_put_ed(cur, &ed); + } + + return active; +} + +/* Generate a SOF event, and set a timer for EOF */ +static void ohci_sof(OHCIState *ohci) +{ + ohci->sof_time = get_clock(); + ohci->eof_timer = usb_frame_time; + ohci_set_interrupt(ohci, OHCI_INTR_SF); +} + +/* Do frame processing on frame boundary */ +void ohci_frame_boundary(void *opaque) +{ + OHCIState *ohci = (OHCIState *)opaque; + struct ohci_hcca hcca; + + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0); + + /* Process all the lists at the end of the frame */ + if (ohci->ctl & OHCI_CTL_PLE) { + int n; + + n = ohci->frame_number & 0x1f; + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); + } + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { + ohci->ctrl_cur = 0; + ohci->status &= ~OHCI_STATUS_CLF; + } + } + + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { + ohci->bulk_cur = 0; + ohci->status &= ~OHCI_STATUS_BLF; + } + } + + /* Frame boundary, so do EOF stuf here */ + ohci->frt = ohci->fit; + + /* XXX: endianness */ + ohci->frame_number = (ohci->frame_number + 1) & 0xffff; + hcca.frame = cpu_to_le32(ohci->frame_number); + + if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { + if (!ohci->done) + abort(); + if (ohci->intr & ohci->intr_status) + ohci->done |= 1; + hcca.done = cpu_to_le32(ohci->done); + ohci->done = 0; + ohci->done_count = 7; + ohci_set_interrupt(ohci, OHCI_INTR_WD); + } + + if (ohci->done_count != 7 && ohci->done_count != 0) + ohci->done_count--; + + /* Do SOF stuff here */ + ohci_sof(ohci); + + /* Writeback HCCA */ + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1); +} + +/* Start sending SOF tokens across the USB bus, lists are processed in + * next frame + */ +int ohci_bus_start(OHCIState *ohci) +{ + ohci->eof_timer = 0; + + dprintf("usb-ohci: USB Operational\n"); + + ohci_sof(ohci); + + return 1; +} + +/* Stop sending SOF tokens on the bus */ +void ohci_bus_stop(OHCIState *ohci) +{ + if (ohci->eof_timer) + ohci->eof_timer=0; +} + +/* Sets a flag in a port status register but only set it if the port is + * connected, if not set ConnectStatusChange flag. If flag is enabled + * return 1. + */ +static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) +{ + int ret = 1; + + /* writing a 0 has no effect */ + if (val == 0) + return 0; + + /* If CurrentConnectStatus is cleared we set + * ConnectStatusChange + */ + if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { + ohci->rhport[i].ctrl |= OHCI_PORT_CSC; + if (ohci->rhstatus & OHCI_RHS_DRWE) { + /* TODO: CSC is a wakeup event */ + } + return 0; + } + + if (ohci->rhport[i].ctrl & val) + ret = 0; + + /* set the bit */ + ohci->rhport[i].ctrl |= val; + + return ret; +} + +/* Set the frame interval - frame interval toggle is manipulated by the hcd only */ +static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) +{ + val &= OHCI_FMI_FI; + + if (val != ohci->fi) { + dprintf("usb-ohci: FrameInterval = 0x%x (%u)\n", ohci->fi, ohci->fi); + } + + ohci->fi = val; +} + +static void ohci_port_power(OHCIState *ohci, int i, int p) +{ + if (p) { + ohci->rhport[i].ctrl |= OHCI_PORT_PPS; + } else { + ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| + OHCI_PORT_CCS| + OHCI_PORT_PSS| + OHCI_PORT_PRS); + } +} + +/* Set HcControlRegister */ +static void ohci_set_ctl(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + uint32_t new_state; + + old_state = ohci->ctl & OHCI_CTL_HCFS; + ohci->ctl = val; + new_state = ohci->ctl & OHCI_CTL_HCFS; + + /* no state change */ + if (old_state == new_state) + return; + + switch (new_state) { + case OHCI_USB_OPERATIONAL: + ohci_bus_start(ohci); + break; + case OHCI_USB_SUSPEND: + ohci_bus_stop(ohci); + dprintf("usb-ohci: USB Suspended\n"); + break; + case OHCI_USB_RESUME: + dprintf("usb-ohci: USB Resume\n"); + break; + case OHCI_USB_RESET: + dprintf("usb-ohci: USB Reset\n"); + break; + } + ohci_intr_update(ohci); +} + +static uint32_t ohci_get_frame_remaining(OHCIState *ohci) +{ + uint16_t fr; + int64_t tks; + + if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) + return (ohci->frt << 31); + + /* Being in USB operational state guarnatees sof_time was + * set already. + */ + tks = get_clock() - ohci->sof_time; + + /* avoid muldiv if possible */ + if (tks >= usb_frame_time) + return (ohci->frt << 31); + + tks = muldiv64(1, tks, usb_bit_time); + fr = (uint16_t)(ohci->fi - tks); + + return (ohci->frt << 31) | fr; +} + + +/* Set root hub status */ +static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + + old_state = ohci->rhstatus; + + /* write 1 to clear OCIC */ + if (val & OHCI_RHS_OCIC) + ohci->rhstatus &= ~OHCI_RHS_OCIC; + + if (val & OHCI_RHS_LPS) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 0); + dprintf("usb-ohci: powered down all ports\n"); + } + + if (val & OHCI_RHS_LPSC) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 1); + dprintf("usb-ohci: powered up all ports\n"); + } + + if (val & OHCI_RHS_DRWE) + ohci->rhstatus |= OHCI_RHS_DRWE; + + if (val & OHCI_RHS_CRWE) + ohci->rhstatus &= ~OHCI_RHS_DRWE; + + if (old_state != ohci->rhstatus) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); +} + +/* Set root hub port status */ +static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) +{ + uint32_t old_state; + OHCIPort *port; + + port = &ohci->rhport[portnum]; + old_state = port->ctrl; + + /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ + if (val & OHCI_PORT_WTC) + port->ctrl &= ~(val & OHCI_PORT_WTC); + + if (val & OHCI_PORT_CCS) + port->ctrl &= ~OHCI_PORT_PES; + + ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) + dprintf("usb-ohci: port %d: SUSPEND\n", portnum); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { + dprintf("usb-ohci: port %d: RESET\n", portnum); + port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, + 0, 0, NULL, 0); + port->ctrl &= ~OHCI_PORT_PRS; + /* ??? Should this also set OHCI_PORT_PESC. */ + port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; + } + + /* Invert order here to ensure in ambiguous case, device is + * powered up... + */ + if (val & OHCI_PORT_LSDA) + ohci_port_power(ohci, portnum, 0); + if (val & OHCI_PORT_PPS) + ohci_port_power(ohci, portnum, 1); + + if (old_state != port->ctrl) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); + + return; +} + +uint32_t ohci_mem_read(OHCIState *ptr, uint32_t addr) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned read\n"); + return 0xffffffff; + } + + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { + /* HcRhPortStatus */ + return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; + } + + switch (addr >> 2) { + case 0: /* HcRevision */ + return 0x10; + + case 1: /* HcControl */ + return ohci->ctl; + + case 2: /* HcCommandStatus */ + return ohci->status; + + case 3: /* HcInterruptStatus */ + return ohci->intr_status; + + case 4: /* HcInterruptEnable */ + case 5: /* HcInterruptDisable */ + return ohci->intr; + + case 6: /* HcHCCA */ + return ohci->hcca; + + case 7: /* HcPeriodCurrentED */ + return ohci->per_cur; + + case 8: /* HcControlHeadED */ + return ohci->ctrl_head; + + case 9: /* HcControlCurrentED */ + return ohci->ctrl_cur; + + case 10: /* HcBulkHeadED */ + return ohci->bulk_head; + + case 11: /* HcBulkCurrentED */ + return ohci->bulk_cur; + + case 12: /* HcDoneHead */ + return ohci->done; + + case 13: /* HcFmInterval */ + return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); + + case 14: /* HcFmRemaining */ + return ohci_get_frame_remaining(ohci); + + case 15: /* HcFmNumber */ + return ohci->frame_number; + + case 16: /* HcPeriodicStart */ + return ohci->pstart; + + case 17: /* HcLSThreshold */ + return ohci->lst; + + case 18: /* HcRhDescriptorA */ + return ohci->rhdesc_a; + + case 19: /* HcRhDescriptorB */ + return ohci->rhdesc_b; + + case 20: /* HcRhStatus */ + return ohci->rhstatus; + + default: + fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); + return 0xffffffff; + } +} + +void ohci_mem_write(OHCIState *ptr,uint32_t addr, uint32_t val) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned write\n"); + return; + } + + if ((addr >= 0x54) && (addr < (0x54 + ohci->num_ports * 4))) { + /* HcRhPortStatus */ + ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); + return; + } + + switch (addr >> 2) { + case 1: /* HcControl */ + ohci_set_ctl(ohci, val); + break; + + case 2: /* HcCommandStatus */ + /* SOC is read-only */ + val = (val & ~OHCI_STATUS_SOC); + + /* Bits written as '0' remain unchanged in the register */ + ohci->status |= val; + + if (ohci->status & OHCI_STATUS_HCR) + ohci_reset(ohci); + break; + + case 3: /* HcInterruptStatus */ + ohci->intr_status &= ~val; + ohci_intr_update(ohci); + break; + + case 4: /* HcInterruptEnable */ + ohci->intr |= val; + ohci_intr_update(ohci); + break; + + case 5: /* HcInterruptDisable */ + ohci->intr &= ~val; + ohci_intr_update(ohci); + break; + + case 6: /* HcHCCA */ + ohci->hcca = val & OHCI_HCCA_MASK; + break; + + case 8: /* HcControlHeadED */ + ohci->ctrl_head = val & OHCI_EDPTR_MASK; + break; + + case 9: /* HcControlCurrentED */ + ohci->ctrl_cur = val & OHCI_EDPTR_MASK; + break; + + case 10: /* HcBulkHeadED */ + ohci->bulk_head = val & OHCI_EDPTR_MASK; + break; + + case 11: /* HcBulkCurrentED */ + ohci->bulk_cur = val & OHCI_EDPTR_MASK; + break; + + case 13: /* HcFmInterval */ + ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; + ohci->fit = (val & OHCI_FMI_FIT) >> 31; + ohci_set_frame_interval(ohci, val); + break; + + case 16: /* HcPeriodicStart */ + ohci->pstart = val & 0xffff; + break; + + case 17: /* HcLSThreshold */ + ohci->lst = val & 0xffff; + break; + + case 18: /* HcRhDescriptorA */ + ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; + ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; + break; + + case 19: /* HcRhDescriptorB */ + break; + + case 20: /* HcRhStatus */ + ohci_set_hub_status(ohci, val); + break; + + default: + fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); + break; + } +} + +OHCIState *ohci_create(uint32_t base, int ports) +{ + OHCIState *ohci=(OHCIState*)malloc(sizeof(OHCIState)); + int i; + + const int ticks_per_sec = PSXCLK; + + memset(ohci,0,sizeof(OHCIState)); + + ohci->mem_base=base; + + if (usb_frame_time == 0) { +#if OHCI_TIME_WARP + usb_frame_time = ticks_per_sec; + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000); +#else + usb_frame_time = muldiv64(1, ticks_per_sec, 1000); + if (ticks_per_sec >= USB_HZ) { + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); + } else { + usb_bit_time = 1; + } +#endif + dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n", + usb_frame_time, usb_bit_time); + } + + ohci->num_ports = ports; + for (i = 0; i < ports; i++) { + ohci->rhport[i].port.opaque = ohci; + ohci->rhport[i].port.index = i; + ohci->rhport[i].port.attach = ohci_attach; + } + + ohci_reset(ohci); + + return ohci; +} diff --git a/plugins/usb/USBqemu/qemu-usb/usb.h b/plugins/usb/USBqemu/qemu-usb/usb.h new file mode 100644 index 0000000000..bfbd5d3824 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/usb.h @@ -0,0 +1,175 @@ +/* + * QEMU USB API + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define USB_TOKEN_SETUP 0x2d +#define USB_TOKEN_IN 0x69 /* device -> host */ +#define USB_TOKEN_OUT 0xe1 /* host -> device */ + +/* specific usb messages, also sent in the 'pid' parameter */ +#define USB_MSG_ATTACH 0x100 +#define USB_MSG_DETACH 0x101 +#define USB_MSG_RESET 0x102 + +#define USB_RET_NODEV (-1) +#define USB_RET_NAK (-2) +#define USB_RET_STALL (-3) +#define USB_RET_BABBLE (-4) + +#define USB_SPEED_LOW 0 +#define USB_SPEED_FULL 1 +#define USB_SPEED_HIGH 2 + +#define USB_STATE_NOTATTACHED 0 +#define USB_STATE_ATTACHED 1 +//#define USB_STATE_POWERED 2 +#define USB_STATE_DEFAULT 3 +//#define USB_STATE_ADDRESS 4 +//#define USB_STATE_CONFIGURED 5 +#define USB_STATE_SUSPENDED 6 + +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b +#define USB_CLASS_CONTENT_SEC 0x0d +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 + +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define InterfaceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define InterfaceOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) +#define EndpointOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DEVICE_SELF_POWERED 0 +#define USB_DEVICE_REMOTE_WAKEUP 1 + +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_CLASS 0x24 + +typedef struct USBPort USBPort; +typedef struct USBDevice USBDevice; + +/* definition of a USB device */ +struct USBDevice { + void *opaque; + int (*handle_packet)(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len); + void (*handle_destroy)(USBDevice *dev); + + int speed; + + /* The following fields are used by the generic USB device + layer. They are here just to avoid creating a new structure for + them. */ + void (*handle_reset)(USBDevice *dev); + int (*handle_control)(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data); + int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, + uint8_t *data, int len); + uint8_t addr; + char devname[32]; + + int state; + uint8_t setup_buf[8]; + uint8_t data_buf[1024]; + int remote_wakeup; + int setup_state; + int setup_len; + int setup_index; +}; + +typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); + +/* USB port on which a device can be connected */ +struct USBPort { + USBDevice *dev; + usb_attachfn attach; + void *opaque; + int index; /* internal port index, may be used with the opaque */ + struct USBPort *next; /* Used internally by qemu. */ +}; + +void usb_attach(USBPort *port, USBDevice *dev); +int usb_generic_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len); +int set_usb_string(uint8_t *buf, const char *str); + +/* usb hub */ +USBDevice *usb_hub_init(int nb_ports); + +/* usb-ohci.c */ +void usb_ohci_init(void *bus, int num_ports, int devfn); + +/* usb-hid.c */ +USBDevice *usb_mouse_init(void); + +/* usb-kbd.c */ +USBDevice *usb_keyboard_init(void); + +/* usb-msd.c */ +USBDevice *usb_msd_init(const char *filename); diff --git a/plugins/usb/USBqemu/qemu-usb/vl.cpp b/plugins/usb/USBqemu/qemu-usb/vl.cpp new file mode 100644 index 0000000000..965fd6ebdb --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/vl.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include "vl.h" + +void cpu_physical_memory_rw(uint32_t addr, uint8_t *buf, + int len, int is_write); + +static inline void cpu_physical_memory_read(uint32_t addr, + uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, buf, len, 0); +} +static inline void cpu_physical_memory_write(uint32_t addr, + const uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); +} + +/* compute with 96 bit intermediate result: (a*b)/c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { +#ifdef WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} diff --git a/plugins/usb/USBqemu/qemu-usb/vl.h b/plugins/usb/USBqemu/qemu-usb/vl.h new file mode 100644 index 0000000000..a4b0a51e30 --- /dev/null +++ b/plugins/usb/USBqemu/qemu-usb/vl.h @@ -0,0 +1,102 @@ +/* + * QEMU System Emulator header + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef VL_H +#define VL_H + +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include + +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#include +#include +#include +#include +#include +#include + +#define inline __inline + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef _WIN32 +#include +#define fsync _commit +#define lseek _lseeki64 +#define ENOTSUP 4096 +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" +#endif + +#include "usb.h" + +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/* vl.c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); +void cpu_physical_memory_rw(uint32_t addr, uint8_t *buf, int len, int is_write); +static inline void cpu_physical_memory_read(uint32_t addr, uint8_t *buf, int len); +static inline void cpu_physical_memory_write(uint32_t addr, const uint8_t *buf, int len); +void *qemu_mallocz(uint32_t size); + +#endif /* VL_H */ diff --git a/plugins/usb/USBqemu/usb-eyetoy/usb-eyetoy.cpp b/plugins/usb/USBqemu/usb-eyetoy/usb-eyetoy.cpp new file mode 100644 index 0000000000..8910deb070 --- /dev/null +++ b/plugins/usb/USBqemu/usb-eyetoy/usb-eyetoy.cpp @@ -0,0 +1,7873 @@ +/* + * QEMU USB HUB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//#define DEBUG + +#define MAX_PORTS 8 + +#include "../qemu-usb/vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +typedef struct EYETOYState { + USBDevice dev; + //nothing yet +} EYETOYState; + +/* same as Linux kernel root hubs */ + +/* mostly the same values as the Bochs USB Mouse device */ +static const uint8_t eyetoy_dev_descriptor[] = { + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0x4c, 0x05, /* idVendor */ + 0x55, 0x01, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ +}; + +/* XXX: patch interrupt size */ +static const uint8_t eyetoy_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0xb4, 0x00, /* u16 wTotalLength; */ + 0x03, /* u8 bNumInterfaces; (3) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0x90, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0xfa, /* u8 MaxPower; */ + + /* interface #0 alternate setting #0 */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ + 0x00, /* u8 if_bInterfaceSubClass; */ + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ + + /* interface #0 alternate setting #0 endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x01, /* u8 ep_bmAttributes; */ + 0x00, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x01, /* u8 ep_bInterval; */ + + /* interface #0 alternate setting #1 */ + 0x09, 0x04, 0x00, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x01, 0x80, 0x01, 0x01, + + /* interface #0 alternate setting #2*/ + 0x09, 0x04, 0x00, 0x02, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x01, 0x00, 0x02, 0x01, + + /* interface #0 alternate setting #3 */ + 0x09, 0x04, 0x00, 0x03, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x01, 0x00, 0x03, 0x01, + + /* interface #0 alternate setting #4 */ + 0x09, 0x04, 0x00, 0x04, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x01, 0x80, 0x03, 0x01, + + /* interface #1 alternate setting #0 */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x00, /* u8 if_bNumEndpoints; */ + 0x01, /* u8 if_bInterfaceClass; AUDIO */ + 0x01, /* u8 if_bInterfaceSubClass; AUDIOCONTROL*/ + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ + + /* interface #1 alternate setting #0 classes */ + 0x09, 0x24, 0x01, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x02, + 0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x24, 0x03, 0x02, 0x01, 0x01, 0x00, 0x01, 0x00, + + /* interface #2 alternate setting #0 (AUDIO class, AUDIOSTREAMING subclass) */ + 0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, + + /* interface #2 alternate setting #1 (AUDIO class, AUDIOSTREAMING subclass) */ + 0x09, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, + + /* interface #1 class-specific interface (HEADER) */ + 0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00, + + /* interface #1 class-specific interface (INPUT TERMINAL) */ + 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01, 0x80, 0x3e, 0x00, + + /* interface #1 alternate setting #1 endpoint */ + 0x09, 0x05, 0x82, 0x05, 0x28, 0x00, 0x01, 0x00, 0x00, + + /* interface #1 class-specific endpoint */ + 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00 +}; + +static void eyetoy_handle_reset(USBDevice *dev) +{ + /* XXX: do it */ + return; +} + +static int eyetoy_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + EYETOYState *s = (EYETOYState *)dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, eyetoy_dev_descriptor, + sizeof(eyetoy_dev_descriptor)); + ret = sizeof(eyetoy_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, eyetoy_config_descriptor, + sizeof(eyetoy_config_descriptor)); + ret = sizeof(eyetoy_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "3X0420811"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "EyeToy USB camera Namtai"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + //switch(value >> 8) { + //((case 0x22: + // memcpy(data, qemu_mouse_hid_report_descriptor, + // sizeof(qemu_mouse_hid_report_descriptor)); + // ret = sizeof(qemu_mouse_hid_report_descriptor); + // break; + //default: + goto fail; + //} + break; + case GET_REPORT: + ret = 0; + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int eyetoy_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + EYETOYState *s = (EYETOYState *)dev; + int ret = 0; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + + +static void eyetoy_handle_destroy(USBDevice *dev) +{ + EYETOYState *s = (EYETOYState *)dev; + + free(s); +} + +int eyetoy_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + fprintf(stderr,"usb-eyetoy: packet received with pid=%x, devaddr=%x, devep=%x and len=%x\n",pid,devaddr,devep,len); + usb_generic_handle_packet(s,pid,devaddr,devep,data,len); +} + +USBDevice *eyetoy_init() +{ + EYETOYState *s; + + s = qemu_mallocz(sizeof(EYETOYState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = eyetoy_handle_packet; + + s->dev.handle_reset = eyetoy_handle_reset; + s->dev.handle_control = eyetoy_handle_control; + s->dev.handle_data = eyetoy_handle_data; + s->dev.handle_destroy = eyetoy_handle_destroy; + + strncpy(s->dev.devname, "EyeToy USB camera Namtai", sizeof(s->dev.devname)); + + return (USBDevice *)s; + +} + +#ifdef X_DRIVER +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// + +/* Video-to-USB Bridge Driver for OmniVision OV511/OV511+/OV518/OV518+/OV519 + * + * Copyright (c) 1999-2005 Mark W. McClelland + * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach + * + * Original decompression code Copyright 1998-2000 OmniVision Technologies + * Many improvements by Bret Wallach + * Color fixes by by Orion Sky Lawlor (2/26/2000) + * Snapshot code by Kevin Moore + * OV7620 fixes by Charl P. Botha + * Changes by Claudio Matsuoka + * Original SAA7111A code by Dave Perks + * URB error messages from pwc driver by Nemosoft + * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox + * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others + * OV7x3x/7x4x detection by Franz Reinhardt + * 2004/01/25: Added OV7640 and EyeToy support (Mark McClelland) + * + * Based on the Linux CPiA driver written by Peter Pregler, + * Scott J. Bertin and Johannes Erdfelt. + * + * Please see the file: doc/ov51x.txt + * and the website at: http://alpha.dyndns.org/ov511 + * for more info. + * For Questions on OV519 or OV8610 please contact + * + * 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. + */ + +#ifdef OV511_ALLOW_CONVERSION + /* Pixel count * 3 bytes for RGB */ + #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3) +#else + /* Pixel count * bytes per YUV420 pixel (1.5) */ + #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2) +#endif + +#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) + +/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ +#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) + +#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) + +/* URB error codes: */ +static struct symbolic_list urb_errlist[] = { + { -ENOSR, "Buffer error (overrun)" }, + { -EPIPE, "Stalled (device not responding)" }, + { -EOVERFLOW, "Babble (bad cable?)" }, + { -EPROTO, "Bit-stuff error (bad cable?)" }, + { -EILSEQ, "CRC/Timeout" }, + { -ETIMEDOUT, "NAK (device does not respond)" }, + { -1, NULL } +}; + + +/********************************************************************** + * /proc interface + * Based on the CPiA driver version 0.7.4 -claudio + **********************************************************************/ + +#if defined(CONFIG_VIDEO_PROC_FS) + +static struct proc_dir_entry *ov511_proc_entry = NULL; +extern struct proc_dir_entry *video_proc_entry; + +/* Prototypes */ +static void ov51x_clear_snapshot(struct usb_ov511 *); +static int sensor_get_picture(struct usb_ov511 *, struct video_picture *); +static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); +static int ov51x_check_snapshot(struct usb_ov511 *); +static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); + +static struct file_operations ov511_control_fops = { + .ioctl = ov51x_control_ioctl, +}; + +#define YES_NO(x) ((x) ? "yes" : "no") + + +/********************************************************************** + * + * Register I/O + * + **********************************************************************/ + +/* Write an OV51x register + + +ov->cbuf[0] = value; + +usb_control_msg: +pipe: ((PIPE_CONTROL << 30) | (dev->devnum << 8) | (0 << 15)), +request: 1, +requesttype: USB_TYPE_VENDOR | USB_RECIP_DEVICE, +value: 0, +index: (__u16)reg, +bytes: &ov->cbuf[0], +size: 1, +timeout: 1000 + +*/ + +/* Read from an OV51x register + +usb_control_msg: +pipe: ((PIPE_CONTROL << 30) | (dev->devnum << 8) | (0 << 15)), +request: 1, +requesttype: USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +value: 0, +index: (__u16)reg, +bytes: &ov->cbuf[0], +size: 1, +timeout: 1000 + +if result<0 then error +else value = ov->cbuf[0]; + +*/ + +/* + * Writes a multbyte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + + ov->cbuf = value (in le order) + + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0) + 1 // REG_IO + USB_TYPE_VENDOR | USB_RECIP_DEVICE + 0 + (__u16)reg + ov->cbuf + n + 1000 + + */ + +static int +ov511_upload_quan_tables(struct usb_ov511 *ov) +{ + unsigned char *pYTable = yQuanTable511; + unsigned char *pUVTable = uvQuanTable511; + unsigned char val0, val1; + int i, rc, reg = R511_COMP_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { + if (ENABLE_Y_QUANTABLE) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +/* OV518 quantization tables are 8x4 (instead of 8x8) */ +static int +ov518_upload_quan_tables(struct usb_ov511 *ov) +{ + unsigned char *pYTable = yQuanTable518; + unsigned char *pUVTable = uvQuanTable518; + unsigned char val0, val1; + int i, rc, reg = R511_COMP_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { + if (ENABLE_Y_QUANTABLE) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +static int +ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) +{ + int rc = -1; + + if (ov->bclass == BCL_OV519) { + //~~~ + PDEBUG(1, "Reset: type=0x0f"); + switch (reset_type) { + case OV511_RESET_NOREGS: + rc = reg_w(ov, OV519_SYS_RESET1, 0x0f); +// rc = reg_w(ov, OV519_SYS_RESET0, 0xdc); +// rc = reg_w(ov, OV519_SYS_RESET0, 0); + rc = reg_w(ov, OV519_SYS_RESET1, 0); + break; + } + } else { + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov->bclass == BCL_OV518) + reset_type &= 0xfe; + + PDEBUG(4, "Reset: type=0x%02X", reset_type); + + rc = reg_w(ov, R51x_SYS_RESET, reset_type); + rc = reg_w(ov, R51x_SYS_RESET, 0); + } + if (rc < 0) + err("reset: command failed"); + + return rc; +} + +/********************************************************************** + * + * Low-level I2C I/O functions + * + **********************************************************************/ + +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_w(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_write_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value) +{ + int rc; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); + if (rc < 0) return rc; + + /* Write "value" to I2C data port of OV511 */ + rc = reg_w(ov, R51x_I2C_DATA, value); + if (rc < 0) return rc; + + /* Initiate 3-byte write cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x01); + if (rc < 0) return rc; + + return 0; +} + +/* NOTE: Do not call this function directly! */ +static int +ov511_i2c_write_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value) +{ + int rc, retries; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* Three byte write cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); + if (rc < 0) return rc; + + /* Write "value" to I2C data port of OV511 */ + rc = reg_w(ov, R51x_I2C_DATA, value); + if (rc < 0) return rc; + + /* Initiate 3-byte write cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x01); + if (rc < 0) return rc; + + do rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if ((rc&2) == 0) /* Ack? */ + break; +#if 0 + /* I2C abort */ + reg_w(ov, R511_I2C_CTL, 0x10); +#endif + if (--retries < 0) { + PDEBUG(5, "i2c write retries exhausted"); + return -1; + } + } + + return 0; +} + +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_r(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) +{ + int rc, value; + + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); + if (rc < 0) return rc; + + /* Initiate 2-byte write cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x03); + if (rc < 0) return rc; + + /* Initiate 2-byte read cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x05); + if (rc < 0) return rc; + + value = reg_r(ov, R51x_I2C_DATA); + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + return value; +} + +/* NOTE: Do not call this function directly! + * returns: negative is error, pos or zero is data */ +static int +ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) +{ + int rc, value, retries; + + /* Two byte write cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); + if (rc < 0) return rc; + + /* Initiate 2-byte write cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x03); + if (rc < 0) return rc; + + do rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if ((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + reg_w(ov, R511_I2C_CTL, 0x10); + + if (--retries < 0) { + PDEBUG(5, "i2c write retries exhausted"); + return -1; + } + } + + /* Two byte read cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Initiate 2-byte read cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); + if (rc < 0) return rc; + + do rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if ((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = reg_w(ov, R511_I2C_CTL, 0x10); + if (rc < 0) return rc; + + if (--retries < 0) { + PDEBUG(5, "i2c read retries exhausted"); + return -1; + } + } + + value = reg_r(ov, R51x_I2C_DATA); + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* This is needed to make i2c_w() work */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + return value; +} + +/* returns: negative is error, pos or zero is data */ +static int +i2c_r(struct usb_ov511 *ov, unsigned char reg) +{ + int rc; + + down(&ov->i2c_lock); + + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_i2c_read_internal(ov, reg); + break; + case BCL_OV518: + case BCL_OV519: + rc = ov518_i2c_read_internal(ov, reg); + break; + default: + err("i2c_r: Invalid bridge class"); + rc = -EINVAL; + } + up(&ov->i2c_lock); + + return rc; +} + +static int +i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) +{ + int rc; + + down(&ov->i2c_lock); + + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_i2c_write_internal(ov, reg, value); + break; + case BCL_OV518: + case BCL_OV519: + rc = ov518_i2c_write_internal(ov, reg, value); + break; + default: + err("ic2_w: Invalid bridge class"); + rc = -EINVAL; + } + + up(&ov->i2c_lock); + + return rc; +} + +/* Do not call this function directly! */ +static int +ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + unsigned char oldval, newval; + + if (mask == 0xff) { + newval = value; + } else { + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_i2c_read_internal(ov, reg); + break; + case BCL_OV518: + case BCL_OV519: + rc = ov518_i2c_read_internal(ov, reg); + break; + default: + err("ov51x_i2c_write_mask_internal: Invalid bridge class"); + rc = -EINVAL; + } + if (rc < 0) + return rc; + + oldval = (unsigned char) rc; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + } + + switch (ov->bclass) { + case BCL_OV511: + return (ov511_i2c_write_internal(ov, reg, newval)); + break; + case BCL_OV518: + case BCL_OV519: + return (ov518_i2c_write_internal(ov, reg, newval)); + break; + default: + return -EINVAL; + } +} + +/* Writes bits at positions specified by mask to an I2C reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int +i2c_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + + down(&ov->i2c_lock); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + up(&ov->i2c_lock); + + return rc; +} + +/* Do not call this function directly! */ +static int +ov51x_i2c_setbit_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char bitaddr) +{ + int rc; + unsigned char newval; + + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_i2c_read_internal(ov, reg); + break; + case BCL_OV518: + case BCL_OV519: + rc = ov518_i2c_read_internal(ov, reg); + break; + default: + err("ov51x_i2c_setbit_internal: Invalid bridge class"); + rc = -EINVAL; + } + if (rc < 0) + return rc; + + newval = ((unsigned char)rc & ~(1 << bitaddr)) | (value ? (1 << bitaddr) : 0); /* Set the desired bit */ + + switch (ov->bclass) { + case BCL_OV511: + return (ov511_i2c_write_internal(ov, reg, newval)); + break; + case BCL_OV518: + case BCL_OV519: + return (ov518_i2c_write_internal(ov, reg, newval)); + break; + default: + return -EINVAL; + } +} + +/* Writes bits at positions specified by bitaddr to an I2C reg. Bits are cleared + * if value = 0 and set if value = 1. + */ +static int +i2c_setbit(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char bitaddr) +{ + int rc; + + down(&ov->i2c_lock); + rc = ov51x_i2c_setbit_internal(ov, reg, value, bitaddr); + up(&ov->i2c_lock); + + return rc; +} + +/* Set the read and write slave IDs. The "slave" argument is the write slave, + * and the read slave will be set to (slave + 1). ov->i2c_lock should be held + * when calling this. This should not be called from outside the i2c I/O + * functions. + */ +static int +i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) +{ + int rc; + + rc = reg_w(ov, R51x_I2C_W_SID, slave); + if (rc < 0) return rc; + + rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); + if (rc < 0) return rc; + + return 0; +} + +/* Write to a specific I2C slave ID and register, using the specified mask */ +static int +i2c_w_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc = 0; + + down(&ov->i2c_lock); + + /* Set new slave IDs */ + rc = i2c_set_slave_internal(ov, slave); + if (rc < 0) goto out; + + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + +out: + /* Restore primary IDs */ + if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) + err("Couldn't restore primary I2C slave"); + + up(&ov->i2c_lock); + return rc; +} + +/* Read from a specific I2C slave ID and register */ +static int +i2c_r_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg) +{ + int rc; + + down(&ov->i2c_lock); + + /* Set new slave IDs */ + rc = i2c_set_slave_internal(ov, slave); + if (rc < 0) goto out; + + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_i2c_read_internal(ov, reg); + break; + case BCL_OV518: + case BCL_OV519: + rc = ov518_i2c_read_internal(ov, reg); + break; + default: + err("i2c_r_slave: Invalid bridge class"); + rc = -EINVAL; + } +out: + /* Restore primary IDs */ + if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) + err("Couldn't restore primary I2C slave"); + + up(&ov->i2c_lock); + return rc; +} + +/* Sets I2C read and write slave IDs. Returns <0 for error */ +static int +ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) +{ + int rc; + + down(&ov->i2c_lock); + + rc = i2c_set_slave_internal(ov, sid); + if (rc < 0) goto out; + + // FIXME: Is this actually necessary? + if (ov->bclass != BCL_OV519) + rc = ov51x_reset(ov, OV511_RESET_NOREGS); + if (rc < 0) goto out; + +out: + up(&ov->i2c_lock); + return rc; +} + +static int +write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) +{ + int rc; + + while (pRegvals->bus != OV511_DONE_BUS) { + if (pRegvals->bus == OV511_REG_BUS) { + if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) + return rc; + } else if (pRegvals->bus == OV511_I2C_BUS) { + if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) + return rc; + } else { + err("Bad regval array"); + return -1; + } + pRegvals++; + } + return 0; +} + +#ifdef OV511_DEBUG +static void +dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) +{ + int i, rc; + + for (i = reg1; i <= regn; i++) { + rc = i2c_r(ov, i); + info("Sensor[0x%02X] = 0x%02X", i, rc); + } +} + +static void +dump_i2c_regs(struct usb_ov511 *ov) +{ + info("I2C REGS"); + dump_i2c_range(ov, 0x00, 0x7C); +} + +static void +dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) +{ + int i, rc; + + for (i = reg1; i <= regn; i++) { + rc = reg_r(ov, i); + info("OV511[0x%02X] = 0x%02X", i, rc); + } +} + +static void +ov511_dump_regs(struct usb_ov511 *ov) +{ + info("CAMERA INTERFACE REGS"); + dump_reg_range(ov, 0x10, 0x1f); + info("DRAM INTERFACE REGS"); + dump_reg_range(ov, 0x20, 0x23); + info("ISO FIFO REGS"); + dump_reg_range(ov, 0x30, 0x31); + info("PIO REGS"); + dump_reg_range(ov, 0x38, 0x39); + dump_reg_range(ov, 0x3e, 0x3e); + info("I2C REGS"); + dump_reg_range(ov, 0x40, 0x49); + info("SYSTEM CONTROL REGS"); + dump_reg_range(ov, 0x50, 0x55); + dump_reg_range(ov, 0x5e, 0x5f); + info("OmniCE REGS"); + dump_reg_range(ov, 0x70, 0x79); + /* NOTE: Quantization tables are not readable. You will get the value + * in reg. 0x79 for every table register */ + dump_reg_range(ov, 0x80, 0x9f); + dump_reg_range(ov, 0xa0, 0xbf); + +} + +static void +ov518_dump_regs(struct usb_ov511 *ov) +{ + info("VIDEO MODE REGS"); + dump_reg_range(ov, 0x20, 0x2f); + info("DATA PUMP AND SNAPSHOT REGS"); + dump_reg_range(ov, 0x30, 0x3f); + info("I2C REGS"); + dump_reg_range(ov, 0x40, 0x4f); + info("SYSTEM CONTROL AND VENDOR REGS"); + dump_reg_range(ov, 0x50, 0x5f); + info("60 - 6F"); + dump_reg_range(ov, 0x60, 0x6f); + info("70 - 7F"); + dump_reg_range(ov, 0x70, 0x7f); + info("Y QUANTIZATION TABLE"); + dump_reg_range(ov, 0x80, 0x8f); + info("UV QUANTIZATION TABLE"); + dump_reg_range(ov, 0x90, 0x9f); + info("A0 - BF"); + dump_reg_range(ov, 0xa0, 0xbf); + info("CBR"); + dump_reg_range(ov, 0xc0, 0xcf); +} +#endif + +/*****************************************************************************/ + +/* Temporarily stops OV511 from functioning. Must do this before changing + * registers while the camera is streaming */ +static inline int +ov51x_stop(struct usb_ov511 *ov) +{ + PDEBUG(4, "stopping"); + ov->stopped = 1; + switch (ov->bclass) { + case BCL_OV511: + return (reg_w(ov, R51x_SYS_RESET, 0x3d)); + break; + case BCL_OV518: + return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); + break; + case BCL_OV519: + return (reg_w(ov, OV519_SYS_RESET1, 0x0f)); + break; + default: + err("ov51x_stop: invalid bridge type"); + } + return -1; +} + +/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not + * actually stopped (for performance). */ +static inline int +ov51x_restart(struct usb_ov511 *ov) +{ + int rc = 0; + + if (ov->stopped) { + PDEBUG(4, "restarting"); + ov->stopped = 0; + + /* Reinitialize the stream */ + switch (ov->bclass) { + case BCL_OV511: + rc = reg_w(ov, R51x_SYS_RESET, 0x00); + break; + case BCL_OV518: + rc = reg_w(ov, 0x2f, 0x80); + rc = reg_w(ov, R51x_SYS_RESET, 0x00); + break; + case BCL_OV519: + rc = reg_w(ov, OV519_SYS_RESET1, 0x00); + break; + default: + err("ov51x_restart: invalid bridge type"); + rc = -EINVAL; + } + } + + return rc; +} + +/* Sleeps until no frames are active. Returns !0 if got signal */ +static int +ov51x_wait_frames_inactive(struct usb_ov511 *ov) +{ + return wait_event_interruptible(ov->wq, ov->curframe < 0); +} + +/* Resets the hardware snapshot button */ +static void +ov51x_clear_snapshot(struct usb_ov511 *ov) +{ + if (ov->bclass == BCL_OV511) { + reg_w(ov, R51x_SYS_SNAP, 0x00); + reg_w(ov, R51x_SYS_SNAP, 0x02); + reg_w(ov, R51x_SYS_SNAP, 0x00); + } else if (ov->bclass == BCL_OV518) { + warn("snapshot reset not supported yet on OV518(+)"); + } else { + err("clear snap: invalid bridge type"); + } +} + +#if defined(CONFIG_VIDEO_PROC_FS) +/* Checks the status of the snapshot button. Returns 1 if it was pressed since + * it was last cleared, and zero in all other cases (including errors) */ +static int +ov51x_check_snapshot(struct usb_ov511 *ov) +{ + int ret, status = 0; + + if (ov->bclass == BCL_OV511) { + ret = reg_r(ov, R51x_SYS_SNAP); + if (ret < 0) { + err("Error checking snspshot status (%d)", ret); + } else if (ret & 0x08) { + status = 1; + } + } else if (ov->bclass == BCL_OV518) { + warn("snapshot check not supported yet on OV518(+)"); + } else { + err("check snap: invalid bridge type"); + } + + return status; +} +#endif + +/* This does an initial reset of an OmniVision sensor and ensures that I2C + * is synchronized. Returns <0 for failure. + */ +static int +init_ov_sensor(struct usb_ov511 *ov) +{ + int i, success; + + /* Reset the sensor */ + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; + + /* Wait for it to initialize */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1 + 150 * HZ / 1000); +#else + msleep(150); +#endif + + for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + continue; + } + + /* Reset the sensor */ + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; + /* Wait for it to initialize */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1 + 150 * HZ / 1000); +#else + msleep(150); +#endif + /* Dummy read to sync I2C */ + if (i2c_r(ov, 0x00) < 0) return -EIO; + } + + if (!success) + return -EIO; + + PDEBUG(1, "I2C synced in %d attempt(s)", i); + + return 0; +} + +static int +ov511_set_packet_size(struct usb_ov511 *ov, int size) +{ + int alt, mult; + + if (ov51x_stop(ov) < 0) + return -EIO; + + mult = size >> 5; + + if (ov->bridge == BRG_OV511) { + if (size == 0) alt = OV511_ALT_SIZE_0; + else if (size == 257) alt = OV511_ALT_SIZE_257; + else if (size == 513) alt = OV511_ALT_SIZE_513; + else if (size == 769) alt = OV511_ALT_SIZE_769; + else if (size == 993) alt = OV511_ALT_SIZE_993; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else if (ov->bridge == BRG_OV511PLUS) { + if (size == 0) alt = OV511PLUS_ALT_SIZE_0; + else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; + else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; + else if (size == 257) alt = OV511PLUS_ALT_SIZE_257; + else if (size == 385) alt = OV511PLUS_ALT_SIZE_385; + else if (size == 513) alt = OV511PLUS_ALT_SIZE_513; + else if (size == 769) alt = OV511PLUS_ALT_SIZE_769; + else if (size == 961) alt = OV511PLUS_ALT_SIZE_961; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else { + err("Set packet size: Invalid bridge type"); + return -EINVAL; + } + + PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); + + if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) + return -EIO; + + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { + err("Set packet size: set interface error"); + return -EBUSY; + } + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + ov->packet_size = size; + + if (ov51x_restart(ov) < 0) + return -EIO; + + return 0; +} + +/* Note: Unlike the OV511/OV511+, the size argument does NOT include the + * optional packet number byte. The actual size *is* stored in ov->packet_size, + * though. */ +static int +ov518_set_packet_size(struct usb_ov511 *ov, int size) +{ + int alt; + + if (ov51x_stop(ov) < 0) + return -EIO; + + if (ov->bclass == BCL_OV518) { + if (size == 0) alt = OV518_ALT_SIZE_0; + else if (size == 128) alt = OV518_ALT_SIZE_128; + else if (size == 256) alt = OV518_ALT_SIZE_256; + else if (size == 384) alt = OV518_ALT_SIZE_384; + else if (size == 512) alt = OV518_ALT_SIZE_512; + else if (size == 640) alt = OV518_ALT_SIZE_640; + else if (size == 768) alt = OV518_ALT_SIZE_768; + else if (size == 896) alt = OV518_ALT_SIZE_896; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else { + err("Set packet size: Invalid bridge type"); + return -EINVAL; + } + + PDEBUG(3, "%d, alt=%d", size, alt); + + ov->packet_size = size; + if (size > 0) { + /* Program ISO FIFO size reg (packet number isn't included) */ + ov518_reg_w32(ov, 0x30, size, 2); + + if (ov->packet_numbering) + ++ov->packet_size; + } + + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { + err("Set packet size: set interface error"); + return -EBUSY; + } + + /* Initialize the stream */ + if (reg_w(ov, 0x2f, 0x80) < 0) + return -EIO; + + if (ov51x_restart(ov) < 0) + return -EIO; + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* Note: Unlike the OV511/OV511+, the size argument does NOT include the + * optional packet number byte. The actual size *is* stored in ov->packet_size, + * though. */ +static int +ov519_set_packet_size(struct usb_ov511 *ov, int size) +{ + int alt; + + if (ov51x_stop(ov) < 0) + return -EIO; + + if (ov->bclass == BCL_OV519) { + if (size == 0) alt = OV519_ALT_SIZE_0; + else if (size == 384) alt = OV519_ALT_SIZE_384; + else if (size == 512) alt = OV519_ALT_SIZE_512; + else if (size == 768) alt = OV519_ALT_SIZE_768; + else if (size == 896) alt = OV519_ALT_SIZE_896; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else { + err("Set packet size: Invalid bridge class"); + return -EINVAL; + } + + PDEBUG(3, "%d, alt=%d", size, alt); + + ov->packet_size = size; + if (size > 0) { + /* Program ISO FIFO size reg (packet number isn't included) */ + //~~~ is this nessecary? ov518_reg_w32(ov, 0x30, size, 2); + + if (ov->packet_numbering) + ++ov->packet_size; + } + + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { + err("Set packet size: set interface error"); + return -EBUSY; + } + + /* Initialize the stream */ + + if (size > 0) { + if (ov51x_restart(ov) < 0) + return -EIO; + } + +// if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) +// return -EIO; + + return 0; +} + +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov511_init_compression(struct usb_ov511 *ov) +{ + int rc = 0; + + if (!ov->compress_inited) { + reg_w(ov, 0x70, phy); + reg_w(ov, 0x71, phuv); + reg_w(ov, 0x72, pvy); + reg_w(ov, 0x73, pvuv); + reg_w(ov, 0x74, qhy); + reg_w(ov, 0x75, qhuv); + reg_w(ov, 0x76, qvy); + reg_w(ov, 0x77, qvuv); + + if (ov511_upload_quan_tables(ov) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } + + ov->compress_inited = 1; +out: + return rc; +} + +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov518_init_compression(struct usb_ov511 *ov) +{ + int rc = 0; + + if (!ov->compress_inited) { + if (ov518_upload_quan_tables(ov) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } + + ov->compress_inited = 1; +out: + return rc; +} + +/* Switch on standard JPEG compression. Returns 0 for success. */ +static int +ov519_init_compression(struct usb_ov511 *ov) +{ + int rc = 0; + + if (!ov->compress_inited) { + if (reg_setbit(ov, OV519_SYS_EN_CLK1, 1, 2 ) < 0) { + err("Error switching to compressed mode"); + rc = -EIO; + goto out; + } + } + + ov->compress_inited = 1; +out: + return rc; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's contrast setting to "val" */ +static int +sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + { + rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); + if (rc < 0) + goto out; + break; + } + case SEN_OV6630: + { + rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); + if (rc < 0) + goto out; + break; + } + case SEN_OV8610: + { + static unsigned char ctab[] = { + 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + rc = i2c_w(ov, 0x64, ctab[val>>13]); + if (rc < 0) + goto out; + break; + } + case SEN_OV7620: + { + static unsigned char ctab[] = { + 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, + 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + rc = i2c_w(ov, 0x64, ctab[val>>12]); + if (rc < 0) + goto out; + break; + } + case SEN_OV7640: + { + /* Use gain control instead. */ + rc = i2c_w(ov, OV7610_REG_GAIN, val>>10); + if (rc < 0) + goto out; + break; + } + case SEN_SAA7111A: + { + rc = i2c_w(ov, 0x0b, val >> 9); + if (rc < 0) + goto out; + break; + } + default: + { + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + } + + rc = 0; /* Success */ + ov->contrast = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's contrast setting */ +static int +sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + rc = i2c_r(ov, OV7610_REG_CNT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_CNT); + if (rc < 0) + return rc; + else + *val = rc << 12; + break; + case SEN_OV8610: + { + static unsigned char ctab[] = { + 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f + }; + static int cidx = 0; + + /* Use Y gamma control instead. Bit 0 enables it. */ + rc = i2c_r(ov, 0x64); + if (rc < 0) { + return rc; + } else { + for (cidx = 0; cidx < 8; cidx++) { + if (ctab[cidx] == rc) { + *val = cidx << 13; + break; + } + } + if (cidx == 8) // could not find value in table + return -EINVAL; + } + break; + } + case SEN_OV7620: + /* Use Y gamma reg instead. Bit 0 is the enable bit. */ + rc = i2c_r(ov, 0x64); + if (rc < 0) + return rc; + else + *val = (rc & 0xfe) << 8; + break; + case SEN_OV7640: + /* Use gain control instead. */ + rc = i2c_r(ov, OV7610_REG_GAIN); + if (rc < 0) + return rc; + else + *val = rc << 10; + break; + + case SEN_SAA7111A: + *val = ov->contrast; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->contrast = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's brightness setting to "val" */ +static int +sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(4, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7640: + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: + /* 7620 doesn't like manual changes when in auto mode */ + if (!ov->auto_brt) { + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + } + break; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0a, val >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->brightness = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's brightness setting */ +static int +sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV7620: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7640: + rc = i2c_r(ov, OV7610_REG_BRT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->brightness; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->brightness = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's saturation (color intensity) setting to "val" */ +static int +sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ +// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); +// if (rc < 0) +// goto out; + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7640: + rc = i2c_w(ov, OV7610_REG_SAT, (val >> 8) & 0xf0); + if (rc < 0) + goto out; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0c, val >> 9); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->colour = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's saturation (color intensity) setting */ +static int +sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7640: + rc = i2c_r(ov, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: +// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ +// rc = i2c_r(ov, 0x62); +// if (rc < 0) +// return rc; +// else +// *val = (rc & 0x7e) << 9; + rc = i2c_r(ov, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->colour; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->colour = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's hue (red/blue balance) setting to "val" */ +static int +sensor_set_hue(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); + if (rc < 0) + goto out; + + rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV8610: + case SEN_OV7640: + rc = i2c_w(ov, OV8610_REG_HUE, (val >> 11) | 0x20); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// Hue control is causing problems. I will enable it once it's fixed. +#if 0 + rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; + + rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; +#endif + break; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->hue = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's hue (red/blue balance) setting */ +static int +sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_BLUE); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV8610: + case SEN_OV7640: + rc = i2c_r(ov, OV8610_REG_HUE); + if (rc < 0) + return rc; + else + *val = (rc & 0x1f) << 11; + break; + case SEN_OV7620: + rc = i2c_r(ov, 0x7a); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->hue; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->hue = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static int +sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) +{ + int rc; + + PDEBUG(4, "sensor_set_picture"); + + ov->whiteness = p->whiteness; + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_set_contrast(ov, p->contrast); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_brightness(ov, p->brightness); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_saturation(ov, p->colour); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_hue(ov, p->hue); + if (FATAL_ERROR(rc)) + return rc; + + return 0; +} + +static int +sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) +{ + int rc; + + PDEBUG(4, "sensor_get_picture"); + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_get_contrast(ov, &(p->contrast)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_brightness(ov, &(p->brightness)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_saturation(ov, &(p->colour)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_hue(ov, &(p->hue)); + if (FATAL_ERROR(rc)) + return rc; + + p->whiteness = 105 << 8; + + return 0; +} + +#if defined(CONFIG_VIDEO_PROC_FS) +// FIXME: Exposure range is only 0x00-0x7f in interlace mode +/* Sets current exposure for sensor. This only has an effect if auto-exposure + * is off */ +static inline int +sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV7640: + case SEN_OV76BE: + case SEN_OV8600: + case SEN_OV8610: + rc = i2c_w(ov, 0x10, val); + if (rc < 0) + goto out; + + break; + case SEN_SAA7111A: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_exposure"); + return -EINVAL; + } + + rc = 0; /* Success */ + ov->exposure = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets current exposure level from sensor, regardless of whether it is under + * manual control. */ +static int +sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7620: + case SEN_OV7640: + case SEN_OV76BE: + case SEN_OV8600: + case SEN_OV8610: + rc = i2c_r(ov, 0x10); + if (rc < 0) + return rc; + else + *val = rc; + break; + case SEN_SAA7111A: + val = 0; + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for get_exposure"); + return -EINVAL; + } + + PDEBUG(3, "%d", *val); + ov->exposure = *val; + + return 0; +} +#endif /* CONFIG_VIDEO_PROC_FS */ + +/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ +static void +ov51x_led_control(struct usb_ov511 *ov, int on) +{ + PDEBUG(4, " (%s)", on ? "turn on" : "turn off"); + + if (ov->bridge == BRG_OV511PLUS) + reg_w(ov, R511_SYS_LED_CTL, on ? 1 : 0); + else if (ov->bridge == BRG_OV519) + reg_w_mask(ov, OV519_GPIO_DATA_OUT0, on ? 0x01 : 0x00, 0x01); + else if (ov->bclass == BCL_OV518) + reg_w_mask(ov, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); + + return; +} + +/* Matches the sensor's internal frame rate to the lighting frequency. + * Valid frequencies are: + * 50 - 50Hz, for European and Asian lighting + * 60 - 60Hz, for American lighting + * + * Tested with: OV7610, OV7620, OV76BE, OV6620 + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_light_freq(struct usb_ov511 *ov, int freq) +{ + int sixty; + + PDEBUG(4, "%d Hz", freq); + + if (freq == 60) + sixty = 1; + else if (freq == 50) + sixty = 0; + else { + err("Invalid light freq (%d Hz)", freq); + return -EINVAL; + } + + switch (ov->sensor) { + case SEN_OV8610: + i2c_w(ov, 0x2b, sixty?0xcc:0xc0); + i2c_w(ov, 0x2a, sixty?0x80:0xa0); + break; + case SEN_OV7610: + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x13, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x10); + break; + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x76, 0x01, 0x01); + break; + case SEN_OV7640: + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + case SEN_OV6620: + case SEN_OV6630: + i2c_w(ov, 0x2b, sixty?0xa8:0x28); + i2c_w(ov, 0x2a, sixty?0x84:0xa4); + break; + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_light_freq"); + return -EINVAL; + } + + ov->lightfreq = freq; + + return 0; +} + +/* If enable is true, turn on the sensor's banding filter, otherwise turn it + * off. This filter tries to reduce the pattern of horizontal light/dark bands + * caused by some (usually fluorescent) lighting. The light frequency must be + * set either before or after enabling it with ov51x_set_light_freq(). + * + * Tested with: OV7610, OV7620, OV76BE, OV6620. + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_banding_filter(struct usb_ov511 *ov, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); + if (rc < 0) + return rc; + + ov->bandfilt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto brightness control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A, OV7640 + * Returns: 0 for success + */ +static int +sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A || ov->sensor == SEN_OV7640) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); + if (rc < 0) + return rc; + + ov->auto_brt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto exposure control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV7610: + i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); + break; + case SEN_OV6620: + case SEN_OV7620: + case SEN_OV7640: + case SEN_OV76BE: + case SEN_OV8600: + i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); + break; + case SEN_OV6630: + case SEN_OV8610: + i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); + break; + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_auto_exposure"); + return -EINVAL; + } + + ov->auto_exp = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto gain control, otherwise + * turn it off. + * + * Returns: 0 for success + */ +static int +sensor_set_auto_gain(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV7640: + i2c_w_mask(ov, 0x13, enable?0x02:0x00, 0x02); + break; + default: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; +// default: +// err("Sensor not supported for set_auto_gain"); +// return -EINVAL; + } + + ov->auto_gain = enable; + + return 0; +} + +/* Modifies the sensor's exposure algorithm to allow proper exposure of objects + * that are illuminated from behind. + * + * Tested with: OV6620, OV7620 + * Unsupported: OV7610, OV7640, OV76BE, KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_backlight(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV8610: + // change AEC/AGC Reference level + i2c_w_mask(ov, 0x68, enable?0xef:0xcf, 0xff); + // select central 1/4 image to calculate AEC/AGC + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + // increase gain 3dB + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV7620: + case SEN_OV8600: + // change AEC/AGC Reference level + i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); + // select central 1/4 image to calculate AEC/AGC + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + // increase gain 3dB + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV6620: + i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); + break; + case SEN_OV6630: + i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV7610: + case SEN_OV7640: + case SEN_OV76BE: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_backlight"); + return -EINVAL; + } + + ov->backlight = enable; + + return 0; +} + +static int +sensor_set_mirror(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV7640: + case SEN_OV8600: + case SEN_OV8610: + i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); + break; + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_mirror"); + return -EINVAL; + } + + ov->mirror = enable; + + return 0; +} + +/* Returns number of bits per pixel (regardless of where they are located; + * planar or not), or zero for unsupported format. + */ +static inline int +get_depth(int palette) +{ + switch (palette) { + case VIDEO_PALETTE_GREY: return 8; + case VIDEO_PALETTE_YUV420: return 12; + case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ +#ifdef OV511_ALLOW_CONVERSION + case VIDEO_PALETTE_RGB565: return 16; + case VIDEO_PALETTE_RGB24: return 24; + case VIDEO_PALETTE_YUV422: return 16; + case VIDEO_PALETTE_YUYV: return 16; + case VIDEO_PALETTE_YUV422P: return 16; /* Planar */ +#endif + default: return 0; /* Invalid format */ + } +} + +/* Bytes per frame. Used by read(). Return of 0 indicates error */ +static inline long int +get_frame_length(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + if (!frame) { + return 0; + } else { + if (ov->bclass == BCL_OV519) { + return (frame->bytes_recvd); + } else { + return ((frame->width * frame->height + * get_depth(frame->format)) >> 3); + } + } +} + +static int +mode_init_ov_sensor_regs(struct usb_ov511 *ov, struct ovsensor_window *win) +{ + int qvga = win->quarter; + + /******** Mode (VGA/QVGA) and sensor specific regs ********/ + + switch (ov->sensor) { + case SEN_OV8610: + // For OV8610 qvga means qsvga + i2c_setbit(ov, OV7610_REG_COM_C, qvga?1:0, 5); + // FIXME: Does this improve the image quality or frame rate? +#if 0 + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); +#endif + break; + case SEN_OV7610: + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); +// FIXME: Does this improve the image quality or frame rate? +#if 0 + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); +#endif + break; + case SEN_OV7620: +// i2c_w(ov, 0x2b, 0x00); + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); + break; + case SEN_OV76BE: +// i2c_w(ov, 0x2b, 0x00); + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); +// FIXME: Enable this once 7620AE uses 7620 initial settings +#if 0 + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); +#endif + break; + case SEN_OV7640: +// i2c_w(ov, 0x2b, 0x00); + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); +// i2c_w(ov, 0x24, qvga?0x20:0x3a); +// i2c_w(ov, 0x25, qvga?0x30:0x60); +// i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); +// i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); +// i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); + break; + case SEN_OV6620: + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); + break; + case SEN_OV6630: + i2c_w_mask(ov, 0x14, qvga?0x20:0x00, 0x20); + break; + default: + return -EINVAL; + } + + /******** Palette-specific regs ********/ + + if (win->format == VIDEO_PALETTE_GREY) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + /* these aren't valid on the OV6620/OV7620/6630? */ + i2c_w_mask(ov, 0x0e, 0x40, 0x40); + } + + /* OV6630 default reg 0x13 value is always right */ + /* OV7640 is 8-bit only */ + if (ov->sensor != SEN_OV6630 && ov->sensor != SEN_OV7640) + i2c_w_mask(ov, 0x13, 0x20, 0x20); + else + return -EINVAL; /* No OV6630 greyscale support yet */ + } else { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + /* not valid on the OV6620/OV7620/6630? */ + i2c_w_mask(ov, 0x0e, 0x00, 0x40); + } + + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ + + /* OV7640 is 8-bit only */ + + if (ov->sensor != SEN_OV6630 && ov->sensor != SEN_OV7640) + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } + + /******** Clock programming ********/ + + /* The OV6620 needs special handling. This prevents the + * severe banding that normally occurs */ + if (ov->sensor == SEN_OV6620) { + /* Clock down */ + + i2c_w(ov, 0x2a, 0x04); + i2c_w(ov, 0x11, win->clockdiv); + i2c_w(ov, 0x2a, 0x84); + /* This next setting is critical. It seems to improve + * the gain or the contrast. The "reserved" bits seem + * to have some effect in this case. */ + i2c_w(ov, 0x2d, 0x85); + } else if (win->clockdiv >= 0) { + i2c_w(ov, 0x11, win->clockdiv); + } + + /******** Special Features ********/ + + if (framedrop >= 0 && ov->sensor != SEN_OV7640) + i2c_w(ov, 0x16, framedrop); + + /* Test Pattern */ + if (ov->sensor != SEN_OV7640) + i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); + + /* Enable auto white balance */ + i2c_w_mask(ov, 0x12, 0x04, 0x04); + + // This will go away as soon as ov51x_mode_init_sensor_regs() + // is fully tested. + /* 7620/6620/6630? don't have register 0x35, so play it safe */ + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + if (win->width == 640 && win->height == 480) + i2c_w(ov, 0x35, 0x9e); + else + i2c_w(ov, 0x35, 0x1e); + } + + return 0; +} + +static int +set_ov_sensor_window(struct usb_ov511 *ov, struct ovsensor_window *win) +{ + int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale, ret; + + /* The different sensor ICs handle setting up of window differently. + * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ + switch (ov->sensor) { + case SEN_OV8610: + hwsbase = 0x1e; + hwebase = 0x1e; + vwsbase = 0x02; + vwebase = 0x02; + break; + case SEN_OV7610: + case SEN_OV76BE: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + case SEN_OV6630: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = 0x05; + vwebase = 0x06; + break; + case SEN_OV7620: + hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ + hwebase = 0x2f; + vwsbase = vwebase = 0x05; + break; + case SEN_OV7640: + hwsbase = 0x1a; + hwebase = 0x1a; + vwsbase = vwebase = 0x03; + break; + default: + return -EINVAL; + } + + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + if (win->quarter) { /* QCIF */ + hwscale = 0; + vwscale = 0; + } else { /* CIF */ + hwscale = 1; + vwscale = 1; /* The datasheet says 0; it's wrong */ + } + break; + case SEN_OV8610: + if (win->quarter) { /* QSVGA */ + hwscale = 1; + vwscale = 1; + } else { /* SVGA */ + hwscale = 2; + vwscale = 2; + } + break; + default: //SEN_OV7xx0 + if (win->quarter) { /* QVGA */ + hwscale = 1; + vwscale = 0; + } else { /* VGA */ + hwscale = 2; + vwscale = 1; + } + } + + ret = mode_init_ov_sensor_regs(ov, win); + if (ret < 0) + return ret; + + if (ov->sensor == SEN_OV8610) { + i2c_w_mask(ov, 0x2d, 0x05, 0x40); /* old 0x95, new 0x05 from windrv 090403 *//* bits 5-7: reserved */ + i2c_w_mask(ov, 0x28, 0x20, 0x20); /* bit 5: progressive mode on */ + } + + i2c_w(ov, 0x17, hwsbase + (win->x >> hwscale)); + i2c_w(ov, 0x18, hwebase + ((win->x + win->width) >> hwscale)); + i2c_w(ov, 0x19, vwsbase + (win->y >> vwscale)); + i2c_w(ov, 0x1a, vwebase + ((win->y + win->height) >> vwscale)); + +#ifdef OV511_DEBUG + if (dump_sensor) + dump_i2c_regs(ov); +#endif + + return 0; +} + +static int +ov_sensor_mode_setup(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + struct ovsensor_window win; + int half_w = ov->maxwidth / 2; + int half_h = ov->maxheight / 2; + + win.format = mode; + + /* Unless subcapture is enabled, center the image window and downsample + * if possible to increase the field of view */ + if (sub_flag) { + win.x = ov->subx; + win.y = ov->suby; + win.width = ov->subw; + win.height = ov->subh; + win.quarter = 0; + } else { + /* NOTE: OV518(+) and OV519 does downsampling on its own */ + if ((width > half_w && height > half_h) + || (ov->bclass == BCL_OV518) + || (ov->bclass == BCL_OV519)) { + win.width = ov->maxwidth; + win.height = ov->maxheight; + win.quarter = 0; + } else if (width > half_w || height > half_h) { + err("Illegal dimensions"); + return -EINVAL; + } else { + win.width = half_w; + win.height = half_h; + win.quarter = 1; + } + + /* Center it */ + win.x = (win.width - width) / 2; + win.y = (win.height - height) / 2; + } + + if (clockdiv >= 0) { + /* Manual override */ + win.clockdiv = clockdiv; + } else if (ov->bridge == BRG_OV518) { + /* OV518 controls the clock externally */ + win.clockdiv = 0; + } else if (ov->bridge == BRG_OV518PLUS) { + /* OV518+ controls the clock externally */ + win.clockdiv = 1; + } else if (ov->bridge == BRG_OV519) { + /* Clock is determined by OV519 frame rate code */ + win.clockdiv = ov->clockdiv; + } else if (ov->compress) { + /* Use the highest possible rate, to maximize FPS */ + switch (ov->sensor) { + case SEN_OV6620: + /* ...except with this sensor, which doesn't like + * higher rates yet */ + win.clockdiv = 3; + break; + case SEN_OV6630: + win.clockdiv = 0; + break; + case SEN_OV76BE: + case SEN_OV7610: + case SEN_OV7620: + win.clockdiv = 1; + break; + case SEN_OV8610: + win.clockdiv = 0; + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + } else { + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + win.clockdiv = 3; + break; + case SEN_OV76BE: + case SEN_OV7610: + case SEN_OV7620: + /* Use slowest possible clock without sacrificing + * frame rate */ + win.clockdiv = ((sub_flag ? ov->subw * ov->subh + : width * height) + * (win.format == VIDEO_PALETTE_GREY ? 2 : 3) / 2) + / 66000; + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + } + + PDEBUG(4, "Setting clock divider to %d", win.clockdiv); + + return set_ov_sensor_window(ov, &win); +} + +/* Set up the OV511/OV511+ with the given image parameters. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov511_mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int hsegs, vsegs; + + if (sub_flag) { + width = ov->subw; + height = ov->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + // FIXME: This should be moved to a 7111a-specific function once + // subcapture is dealt with properly + if (ov->sensor == SEN_SAA7111A) { + if (width == 320 && height == 240) { + /* No need to do anything special */ + } else if (width == 640 && height == 480) { + /* Set the OV511 up as 320x480, but keep the + * V4L resolution as 640x480 */ + width = 320; + } else { + err("SAA7111A only allows 320x240 or 640x480"); + return -EINVAL; + } + } + + /* Make sure width and height are a multiple of 8 */ + if (width % 8 || height % 8) { + err("Invalid size (%d, %d) (mode = %d)", width, height, mode); + return -EINVAL; + } + + if (width < ov->minwidth || height < ov->minheight) { + err("Requested dimensions are too small"); + return -EINVAL; + } + + if (ov51x_stop(ov) < 0) + return -EIO; + + if (mode == VIDEO_PALETTE_GREY) { + reg_w(ov, R511_CAM_UV_EN, 0x00); + reg_w(ov, R511_SNAP_UV_EN, 0x00); + reg_w(ov, R511_SNAP_OPTS, 0x01); + } else { + reg_w(ov, R511_CAM_UV_EN, 0x01); + reg_w(ov, R511_SNAP_UV_EN, 0x01); + reg_w(ov, R511_SNAP_OPTS, 0x03); + } + + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + hsegs = (width >> 3) - 1; + vsegs = (height >> 3) - 1; + + reg_w(ov, R511_CAM_PXCNT, hsegs); + reg_w(ov, R511_CAM_LNCNT, vsegs); + reg_w(ov, R511_CAM_PXDIV, 0x00); + reg_w(ov, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filter on */ + reg_w(ov, R511_CAM_OPTS, 0x03); + + /* Snapshot additions */ + reg_w(ov, R511_SNAP_PXCNT, hsegs); + reg_w(ov, R511_SNAP_LNCNT, vsegs); + reg_w(ov, R511_SNAP_PXDIV, 0x00); + reg_w(ov, R511_SNAP_LNDIV, 0x00); + + if (ov->compress) { + /* Enable Y and UV quantization and compression */ + reg_w(ov, R511_COMP_EN, 0x07); + reg_w(ov, R511_COMP_LUT_EN, 0x03); + ov51x_reset(ov, OV511_RESET_OMNICE); + } + + if (ov51x_restart(ov) < 0) + return -EIO; + + return 0; +} + +/* Sets up the OV518/OV518+ with the given image parameters + * + * OV518 needs a completely different approach, until we can figure out what + * the individual registers do. Also, only 15 FPS is supported now. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov518_mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int hsegs, vsegs, hi_res; + + if (sub_flag) { + width = ov->subw; + height = ov->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + if (width % 16 || height % 8) { + err("Invalid size (%d, %d)", width, height); + return -EINVAL; + } + + if (width < ov->minwidth || height < ov->minheight) { + err("Requested dimensions are too small"); + return -EINVAL; + } + + if (width >= 320 && height >= 240) { + hi_res = 1; + } else if (width >= 320 || height >= 240) { + err("Invalid width/height combination (%d, %d)", width, height); + return -EINVAL; + } else { + hi_res = 0; + } + + if (ov51x_stop(ov) < 0) + return -EIO; + + /******** Set the mode ********/ + + reg_w(ov, 0x2b, 0); + reg_w(ov, 0x2c, 0); + reg_w(ov, 0x2d, 0); + reg_w(ov, 0x2e, 0); + reg_w(ov, 0x3b, 0); + reg_w(ov, 0x3c, 0); + reg_w(ov, 0x3d, 0); + reg_w(ov, 0x3e, 0); + + if (ov->bridge == BRG_OV518 && ov518_color) { + if (mode == VIDEO_PALETTE_GREY) { + /* Set 16-bit input format (UV data are ignored) */ + reg_w_mask(ov, 0x20, 0x00, 0x08); + + /* Set 8-bit (4:0:0) output format */ + reg_w_mask(ov, 0x28, 0x00, 0xf0); + reg_w_mask(ov, 0x38, 0x00, 0xf0); + } else { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(ov, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(ov, 0x28, 0x80, 0xf0); + reg_w_mask(ov, 0x38, 0x80, 0xf0); + } + } else { + reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + } + + hsegs = width / 16; + vsegs = height / 4; + + reg_w(ov, 0x29, hsegs); + reg_w(ov, 0x2a, vsegs); + + reg_w(ov, 0x39, hsegs); + reg_w(ov, 0x3a, vsegs); + + /* Windows driver does this here; who knows why */ + reg_w(ov, 0x2f, 0x80); + + /******** Set the framerate (to 30 FPS) ********/ + + /* Mode independent, but framerate dependent, regs */ + reg_w(ov, 0x51, 0x04); /* Clock divider; lower==faster */ + reg_w(ov, 0x22, 0x18); + reg_w(ov, 0x23, 0xff); + + if (ov->bridge == BRG_OV518PLUS) + reg_w(ov, 0x21, 0x19); + else + reg_w(ov, 0x71, 0x17); /* Compression-related? */ + + // FIXME: Sensor-specific + /* Bit 5 is what matters here. Of course, it is "reserved" */ + i2c_w(ov, 0x54, 0x23); + + reg_w(ov, 0x2f, 0x80); + + if (ov->bridge == BRG_OV518PLUS) { + reg_w(ov, 0x24, 0x94); + reg_w(ov, 0x25, 0x90); + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ + ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ + ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ + } else { + reg_w(ov, 0x24, 0x9f); + reg_w(ov, 0x25, 0x90); + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 381, 2); /* 17dh */ + ov518_reg_w32(ov, 0xc7, 381, 2); /* 17dh */ + ov518_reg_w32(ov, 0xc8, 128, 2); /* 80h */ + ov518_reg_w32(ov, 0xca, 183331, 3); /* 2cc23h */ + ov518_reg_w32(ov, 0xcb, 746, 2); /* 2eah */ + ov518_reg_w32(ov, 0xcc, 1750, 2); /* 6d6h */ + ov518_reg_w32(ov, 0xcd, 45, 2); /* 2dh */ + ov518_reg_w32(ov, 0xce, 851, 2); /* 353h */ + } + + reg_w(ov, 0x2f, 0x80); + + if (ov51x_restart(ov) < 0) + return -EIO; + + /* Reset it just for good measure */ + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* Sets up the OV519 with the given image parameters + * + * OV519 needs a completely different approach, until we can figure out what + * the individual registers do. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov519_mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + static struct ov511_regvals regvals_mode_init_519[] = { + { OV511_REG_BUS, 0x5d, 0x03 }, /* Turn off suspend mode */ + { OV511_REG_BUS, 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ + { OV511_REG_BUS, 0x54, 0x0f }, /* bit2 (jpeg enable) */ + { OV511_REG_BUS, 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { OV511_REG_BUS, 0xa3, 0x18 }, + { OV511_REG_BUS, 0xa4, 0x04 }, + { OV511_REG_BUS, 0xa5, 0x28 }, + { OV511_REG_BUS, 0x37, 0x00 }, /* SetUsbInit */ + { OV511_REG_BUS, 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { OV511_REG_BUS, 0x22, 0x1d }, + { OV511_REG_BUS, 0x17, 0x50 }, /* undocumented */ + { OV511_REG_BUS, 0x37, 0x00 }, /* undocumented */ + { OV511_REG_BUS, 0x40, 0xff }, /* I2C timeout counter */ + { OV511_REG_BUS, 0x46, 0x00 }, /* I2C clock prescaler */ + { OV511_REG_BUS, 0x59, 0x04 }, /* new from windrv 090403 */ + { OV511_REG_BUS, 0xff, 0x00 }, /* undocumented */ + /* windows reads 0x55 at this point, why? */ + { OV511_DONE_BUS, 0x0, 0x00}, + }; + +// int hi_res; + + if (sub_flag) { + width = ov->subw; + height = ov->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + if ((width % 16) || (height % 8)) { + err("Invalid size (%d, %d)", width, height); + return -EINVAL; + } + + if (width < ov->minwidth || height < ov->minheight) { + err("Requested dimensions are too small %dx%d", width, height); + return -EINVAL; + } + +// if (width >= 800 && height >= 600) { +// hi_res = 1; +// } else + if (width > ov->maxwidth || height > ov->maxheight) { + err("Requested dimensions are too big %dx%d", width, height); + return -EINVAL; + } +// else { +// hi_res = 0; +// } + + if (ov51x_stop(ov) < 0) + return -EIO; + + /******** Set the mode ********/ + + if (write_regvals(ov, regvals_mode_init_519)) + return -EIO; + + if (ov->sensor == SEN_OV7640) { + /* Select 8-bit input mode */ + reg_w_mask(ov, OV519_CAM_DFR, 0x10, 0x10); + } + + reg_w(ov, OV519_CAM_H_SIZE, width>>4); + reg_w(ov, OV519_CAM_V_SIZE, height>>3); + reg_w(ov, OV519_CAM_X_OFFSETL, 0x00); + reg_w(ov, OV519_CAM_X_OFFSETH, 0x00); + reg_w(ov, OV519_CAM_Y_OFFSETL, 0x00); + reg_w(ov, OV519_CAM_Y_OFFSETH, 0x00); + reg_w(ov, OV519_CAM_DIVIDER, 0x00); + reg_w(ov, OV519_CAM_FORMAT, 0x03); /* YUV422 */ + reg_w(ov, 0x26, 0x00); /* Undocumented */ + + + /******** Set the framerate ********/ + if (framerate > 0) { + ov->framerate = framerate; + } + +// FIXME: These are only valid at the max resolution. + if (ov->sensor == SEN_OV7640) { + switch (ov->framerate) { + case 30: + reg_w(ov, 0xa4, 0x0c); + reg_w(ov, 0x23, 0xff); + ov->clockdiv = 0; + break; + case 25: + reg_w(ov, 0xa4, 0x0c); + reg_w(ov, 0x23, 0x1f); + ov->clockdiv = 0; + break; + case 20: + reg_w(ov, 0xa4, 0x0c); + reg_w(ov, 0x23, 0x1b); + ov->clockdiv = 0; + break; + case 15: + reg_w(ov, 0xa4, 0x04); + reg_w(ov, 0x23, 0xff); + ov->clockdiv = 1; + break; + case 10: + reg_w(ov, 0xa4, 0x04); + reg_w(ov, 0x23, 0x1f); + ov->clockdiv = 1; + break; + case 5: + reg_w(ov, 0xa4, 0x04); + reg_w(ov, 0x23, 0x1b); + ov->clockdiv = 1; + break; + default: // 30 fps + reg_w(ov, 0xa4, 0x0c); + reg_w(ov, 0x23, 0xff); + ov->clockdiv = 0; + } + } else if (ov->sensor == SEN_OV8610) { + switch (ov->framerate) { + case 15: + reg_w(ov, 0xa4, 0x06); + reg_w(ov, 0x23, 0xff); + break; + case 10: + reg_w(ov, 0xa4, 0x06); + reg_w(ov, 0x23, 0x1f); + break; + case 5: + reg_w(ov, 0xa4, 0x06); + reg_w(ov, 0x23, 0x1b); + break; + default: // 15 fps + reg_w(ov, 0xa4, 0x06); + reg_w(ov, 0x23, 0xff); + } + + ov->clockdiv = 0; + } else { + err("Sensor not supported for OV519!"); + return -EINVAL; + } + + if (ov51x_restart(ov) < 0) + return -EIO; + + /* Reset it just for good measure */ + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* This is a wrapper around the OV511, OV518, and sensor specific functions */ +static int +mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int rc = 0; + + if (!ov || !ov->dev) + return -EFAULT; + + switch (ov->bclass) { + case BCL_OV511: + rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); + break; + case BCL_OV518: + rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); + break; + case BCL_OV519: + rc = ov519_mode_init_regs(ov, width, height, mode, sub_flag); + break; + default: + err("mode_init_regs: Invalid bridge class"); + rc = -EINVAL; + } + + if (FATAL_ERROR(rc)) + return rc; + + switch (ov->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV7640: + case SEN_OV8600: + case SEN_OV6620: + case SEN_OV6630: + rc = ov_sensor_mode_setup(ov, width, height, mode, sub_flag); + break; + + case SEN_SAA7111A: +// rc = mode_init_saa_sensor_regs(ov, width, height, mode, +// sub_flag); + + PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); + break; + default: + rc = -EINVAL; + } + + if (FATAL_ERROR(rc)) + return rc; + + /* Sensor-independent settings */ + rc = sensor_set_auto_brightness(ov, ov->auto_brt); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_auto_exposure(ov, ov->auto_exp); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_auto_gain(ov, ov->auto_gain); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_banding_filter(ov, bandingfilter); + if (FATAL_ERROR(rc)) + return rc; + + if (ov->lightfreq) { + rc = sensor_set_light_freq(ov, lightfreq); + if (FATAL_ERROR(rc)) + return rc; + } + + rc = sensor_set_backlight(ov, ov->backlight); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_mirror(ov, ov->mirror); + if (FATAL_ERROR(rc)) + return rc; + + return 0; +} + +/* This sets the default image parameters. This is useful for apps that use + * read() and do not set these. + */ +static int +ov51x_set_default_params(struct usb_ov511 *ov) +{ + int i; + + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used + * (using read() instead). */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].width = ov->maxwidth; + ov->frame[i].height = ov->maxheight; + ov->frame[i].bytes_read = 0; + if (force_palette) + ov->frame[i].format = force_palette; + else +#ifdef OV511_ALLOW_CONVERSION + ov->frame[i].format = VIDEO_PALETTE_RGB24; +#else + ov->frame[i].format = VIDEO_PALETTE_YUV420; +#endif + ov->frame[i].depth = get_depth(ov->frame[i].format); + } + + PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, + symbolic(v4l1_plist, ov->frame[0].format)); + + /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ + if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, + ov->frame[0].format, 0) < 0) + return -EINVAL; + + return 0; +} + +/********************************************************************** + * + * Video decoder stuff + * + **********************************************************************/ + +/* Set analog input port of decoder */ +static int +decoder_set_input(struct usb_ov511 *ov, int input) +{ + PDEBUG(4, "port %d", input); + + switch (ov->sensor) { + case SEN_SAA7111A: + { + /* Select mode */ + i2c_w_mask(ov, 0x02, input, 0x07); + /* Bypass chrominance trap for modes 4..7 */ + i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); + break; + } + default: + return -EINVAL; + } + + return 0; +} + +/* Get ASCII name of video input */ +static int +decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) +{ + switch (ov->sensor) { + case SEN_SAA7111A: + { + if (input < 0 || input > 7) + return -EINVAL; + else if (input < 4) + sprintf(name, "CVBS-%d", input); + else // if (input < 8) + sprintf(name, "S-Video-%d", input - 4); + break; + } + default: + sprintf(name, "%s", "Camera"); + } + + return 0; +} + +/* Set norm (NTSC, PAL, SECAM, AUTO) */ +static int +decoder_set_norm(struct usb_ov511 *ov, int norm) +{ + PDEBUG(4, "%d", norm); + + switch (ov->sensor) { + case SEN_SAA7111A: + { + int reg_8, reg_e; + + if (norm == VIDEO_MODE_NTSC) { + reg_8 = 0x40; /* 60 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_PAL) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_AUTO) { + reg_8 = 0x80; /* Auto field detect */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_SECAM) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x50; /* SECAM / PAL 4.43 */ + } else { + return -EINVAL; + } + + i2c_w_mask(ov, 0x08, reg_8, 0xc0); + i2c_w_mask(ov, 0x0e, reg_e, 0x70); + break; + } + default: + return -EINVAL; + } + + return 0; +} + +#ifdef OV511_ALLOW_CONVERSION +/********************************************************************** + * + * Color correction functions + * + **********************************************************************/ + +/* + * Turn a YUV4:2:0 block into an RGB block + * + * Video4Linux seems to use the blue, green, red channel + * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red. + * + * Color space conversion coefficients taken from the excellent + * http://www.inforamp.net/~poynton/ColorFAQ.html + * In his terminology, this is a CCIR 601.1 YCbCr -> RGB. + * Y values are given for all 4 pixels, but the U (Pb) + * and V (Pr) are assumed constant over the 2x2 block. + * + * To avoid floating point arithmetic, the color conversion + * coefficients are scaled into 16.16 fixed-point integers. + * They were determined as follows: + * + * double brightness = 1.0; (0->black; 1->full scale) + * double saturation = 1.0; (0->greyscale; 1->full color) + * double fixScale = brightness * 256 * 256; + * int rvScale = (int)(1.402 * saturation * fixScale); + * int guScale = (int)(-0.344136 * saturation * fixScale); + * int gvScale = (int)(-0.714136 * saturation * fixScale); + * int buScale = (int)(1.772 * saturation * fixScale); + * int yScale = (int)(fixScale); + */ + +/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */ +#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16))) + +static inline void +move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb, int bits) +{ + const int rvScale = 91881; + const int guScale = -22553; + const int gvScale = -46801; + const int buScale = 116129; + const int yScale = 65536; + int r, g, b; + + g = guScale * u + gvScale * v; + if (force_rgb) { + r = buScale * u; + b = rvScale * v; + } else { + r = rvScale * v; + b = buScale * u; + } + + yTL *= yScale; yTR *= yScale; + yBL *= yScale; yBR *= yScale; + + if (bits == 24) { + /* Write out top two pixels */ + rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); + rgb[2] = LIMIT(r+yTL); + + rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); + rgb[5] = LIMIT(r+yTR); + + /* Skip down to next line to write out bottom two pixels */ + rgb += 3 * rowPixels; + rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); + rgb[2] = LIMIT(r+yBL); + + rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); + rgb[5] = LIMIT(r+yBR); + } else if (bits == 16) { + /* Write out top two pixels */ + rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) + | ((LIMIT(g+yTL) << 3) & 0xE0); + rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) + | (LIMIT(r+yTL) & 0xF8); + + rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) + | ((LIMIT(g+yTR) << 3) & 0xE0); + rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) + | (LIMIT(r+yTR) & 0xF8); + + /* Skip down to next line to write out bottom two pixels */ + rgb += 2 * rowPixels; + + rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) + | ((LIMIT(g+yBL) << 3) & 0xE0); + rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) + | (LIMIT(r+yBL) & 0xF8); + + rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) + | ((LIMIT(g+yBR) << 3) & 0xE0); + rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) + | (LIMIT(r+yBR) & 0xF8); + } +} + +#endif /* OV511_ALLOW_CONVERSION */ + +/********************************************************************** + * + * Raw data parsing + * + **********************************************************************/ + +/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the + * image at pOut is specified by w. + */ +static inline void +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +{ + unsigned char *pOut1 = pOut; + int x, y; + + for (y = 0; y < 8; y++) { + pOut1 = pOut; + for (x = 0; x < 8; x++) { + *pOut1++ = *pIn++; + } + pOut += w; + } +} + +/* + * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. + * The segments represent 4 squares of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 248 249 ... 255 + * + */ +static void +yuv400raw_to_yuv400p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int x, y; + unsigned char *pIn, *pOut, *pOutLine; + + /* Copy Y */ + pIn = pIn0; + pOutLine = pOut0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + } + pOutLine += 8 * frame->rawwidth; + } +} + +/* + * For YUV 4:2:0 images, the data show up in 384 byte segments. + * The first 64 bytes of each segment are U, the next 64 are V. The U and + * V are arranged as follows: + * + * 0 1 ... 7 + * 8 9 ... 15 + * ... + * 56 57 ... 63 + * + * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). + * + * The next 256 bytes are full resolution Y data and represent 4 squares + * of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 + * + * Note that the U and V data in one segment represent a 16 x 16 pixel + * area, but the Y data represent a 32 x 8 pixel area. If the width is not an + * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the + * next horizontal stripe. + * + * If dumppix module param is set, _parse_data just dumps the incoming segments, + * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 + * this puts the data on the standard output and can be analyzed with the + * parseppm.c utility I wrote. That's a much faster way for figuring out how + * these data are scrambled. + */ + +/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. + * + * FIXME: Currently only handles width and height that are multiples of 16 + */ +static void +yuv420raw_to_yuv420p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int k, x, y; + unsigned char *pIn, *pOut, *pOutLine; + const unsigned int a = frame->rawwidth * frame->rawheight; + const unsigned int w = frame->rawwidth / 2; + + /* Copy U and V */ + pIn = pIn0; + pOutLine = pOut0 + a; + for (y = 0; y < frame->rawheight - 1; y += 16) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 16) { + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); + pIn += 384; + pOut += 8; + } + pOutLine += 8 * w; + } + + /* Copy Y */ + pIn = pIn0 + 128; + pOutLine = pOut0; + k = 0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + if ((++k) > 3) { + k = 0; + pIn += 128; + } + } + pOutLine += 8 * frame->rawwidth; + } +} + +#ifdef OV511_ALLOW_CONVERSION +/* + * fixFrameRGBoffset-- + * My camera seems to return the red channel about 1 pixel + * low, and the blue channel about 1 pixel high. After YUV->RGB + * conversion, we can correct this easily. OSL 2/24/2000. + */ +static void +fixFrameRGBoffset(struct ov511_frame *frame) +{ + int x, y; + int rowBytes = frame->width*3, w = frame->width; + unsigned char *rgb = frame->data; + const int shift = 1; /* Distance to shift pixels by, vertically */ + + /* Don't bother with little images */ + if (frame->width < 400) + return; + + /* This only works with RGB24 */ + if (frame->format != VIDEO_PALETTE_RGB24) + return; + + /* Shift red channel up */ + for (y = shift; y < frame->height; y++) { + int lp = (y-shift)*rowBytes; /* Previous line offset */ + int lc = y*rowBytes; /* Current line offset */ + for (x = 0; x < w; x++) + rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */ + } + + /* Shift blue channel down */ + for (y = frame->height-shift-1; y >= 0; y--) { + int ln = (y + shift) * rowBytes; /* Next line offset */ + int lc = y * rowBytes; /* Current line offset */ + for (x = 0; x < w; x++) + rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */ + } +} +#endif + +/********************************************************************** + * + * Decompression + * + **********************************************************************/ + +/* Chooses a decompression module, locks it, and sets ov->decomp_ops + * accordingly. Returns -ENXIO if decompressor is not available, otherwise + * returns 0 if no other error. + */ +static int +request_decompressor(struct usb_ov511 *ov) +{ + if (!ov) + return -ENODEV; + + if (ov->decomp_ops) { + err("ERROR: Decompressor already requested!"); + return -EINVAL; + } + + lock_kernel(); + + /* Try to get MMX, and fall back on no-MMX if necessary */ + if (ov->bclass == BCL_OV511) { + if (ov511_mmx_decomp_ops) { + PDEBUG(3, "Using OV511 MMX decompressor"); + ov->decomp_ops = ov511_mmx_decomp_ops; + } else if (ov511_decomp_ops) { + PDEBUG(3, "Using OV511 decompressor"); + ov->decomp_ops = ov511_decomp_ops; + } else { + err("No decompressor available"); + } + } else if (ov->bclass == BCL_OV518) { + if (ov518_mmx_decomp_ops) { + PDEBUG(3, "Using OV518 MMX decompressor"); + ov->decomp_ops = ov518_mmx_decomp_ops; + } else if (ov518_decomp_ops) { + PDEBUG(3, "Using OV518 decompressor"); + ov->decomp_ops = ov518_decomp_ops; + } else { + err("No decompressor available"); + } + } else if (ov->bclass == BCL_OV519) { + info("OV519 doesn't need proprietary decompressor. It uses standard JPEG"); + } else { + err("Decompressor: Unknown bridge"); + } + + if (ov->decomp_ops) { + if (!ov->decomp_ops->owner) { + ov->decomp_ops = NULL; + unlock_kernel(); + return -ENOSYS; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + if (! try_module_get (ov->decomp_ops->owner)) { + ov->decomp_ops = NULL; + unlock_kernel(); + return -ENOSYS; + } +#else + __MOD_INC_USE_COUNT(ov->decomp_ops->owner); +#endif + unlock_kernel(); + return 0; + } else { + unlock_kernel(); + if (ov->bclass == BCL_OV519) + return 0; + else + return -ENOSYS; + } +} + +/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even + * if ov->decomp_ops is NULL. + */ +static void +release_decompressor(struct usb_ov511 *ov) +{ + int released = 0; /* Did we actually do anything? */ + + if (!ov) + return; + + if (ov->bclass == BCL_OV519) { + ov->compress_inited = 0; + return; + } + + lock_kernel(); + + if (ov->decomp_ops && ov->decomp_ops->owner) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + module_put(ov->decomp_ops->owner); +#else + __MOD_DEC_USE_COUNT(ov->decomp_ops->owner); +#endif + released = 1; + } + + ov->decomp_ops = NULL; + + unlock_kernel(); + + if (released) + PDEBUG(3, "Decompressor released"); +} + +static void +decompress(struct usb_ov511 *ov, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + if (!ov->decomp_ops) + if (request_decompressor(ov)) + return; + + PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); + + if (frame->format == VIDEO_PALETTE_GREY + && ov->decomp_ops->decomp_400) { + int ret = ov->decomp_ops->decomp_400( + pIn0, + pOut0, + frame->compbuf, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); + } else if (frame->format != VIDEO_PALETTE_GREY + && ov->decomp_ops->decomp_420) { + int ret = ov->decomp_ops->decomp_420( + pIn0, + pOut0, + frame->compbuf, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_420 returned %d", ret); + } else { + err("Decompressor does not support this format"); + } +} + +/********************************************************************** + * + * Format conversion + * + **********************************************************************/ + +#ifdef OV511_ALLOW_CONVERSION + +/* Converts from planar YUV420 to RGB24. */ +static void +yuv420p_to_rgb(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0, int bits) +{ + const int numpix = frame->width * frame->height; + const int bytes = bits >> 3; + int i, j, y00, y01, y10, y11, u, v; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (j = 0; j <= frame->height - 2; j += 2) { + for (i = 0; i <= frame->width - 2; i += 2) { + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + frame->width); + y11 = *(pY + frame->width + 1); + u = (*pU++) - 128; + v = (*pV++) - 128; + + move_420_block(y00, y01, y10, y11, u, v, + frame->width, pOut, bits); + + pY += 2; + pOut += 2 * bytes; + } + pY += frame->width; + pOut += frame->width * bytes; + } +} + +/* Converts from planar YUV420 to YUV422 (YUYV). */ +static void +yuv420p_to_yuv422(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int numpix = frame->width * frame->height; + int i, j; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (i = 0; i < numpix; i++) { + *pOut = *(pY + i); + pOut += 2; + } + + pOut = pOut0 + 1; + for (j = 0; j <= frame->height - 2 ; j += 2) { + for (i = 0; i <= frame->width - 2; i += 2) { + int u = *pU++; + int v = *pV++; + + *pOut = u; + *(pOut+2) = v; + *(pOut+frame->width*2) = u; + *(pOut+frame->width*2+2) = v; + pOut += 4; + } + pOut += (frame->width * 2); + } +} + +/* Converts pData from planar YUV420 to planar YUV422 **in place**. */ +static void +yuv420p_to_yuv422p(struct ov511_frame *frame, unsigned char *pData) +{ + const int numpix = frame->width * frame->height; + const int w = frame->width; + int j; + unsigned char *pIn, *pOut; + + /* Clear U and V */ + memset(pData + numpix + numpix / 2, 127, numpix / 2); + + /* Convert V starting from beginning and working forward */ + pIn = pData + numpix + numpix / 4; + pOut = pData + numpix +numpix / 2; + for (j = 0; j <= frame->height - 2; j += 2) { + memmove(pOut, pIn, w/2); + memmove(pOut + w/2, pIn, w/2); + pIn += w/2; + pOut += w; + } + + /* Convert U, starting from end and working backward */ + pIn = pData + numpix + numpix / 4; + pOut = pData + numpix + numpix / 2; + for (j = 0; j <= frame->height - 2; j += 2) { + pIn -= w/2; + pOut -= w; + memmove(pOut, pIn, w/2); + memmove(pOut + w/2, pIn, w/2); + } +} + +#endif /* OV511_ALLOW_CONVERSION */ + +/* Fuses even and odd fields together, and doubles width. + * INPUT: an odd field followed by an even field at pIn0, in YUV planar format + * OUTPUT: a normal YUV planar image, with correct aspect ratio + */ +static void +deinterlace(struct ov511_frame *frame, int rawformat, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int fieldheight = frame->rawheight / 2; + const int fieldpix = fieldheight * frame->rawwidth; + const int w = frame->width; + int x, y; + unsigned char *pInEven, *pInOdd, *pOut; + + PDEBUG(5, "fieldheight=%d", fieldheight); + + if (frame->rawheight != frame->height) { + err("invalid height"); + return; + } + + if ((frame->rawwidth * 2) != frame->width) { + err("invalid width"); + return; + } + + /* Y */ + pInOdd = pIn0; + pInEven = pInOdd + fieldpix; + pOut = pOut0; + for (y = 0; y < fieldheight; y++) { + for (x = 0; x < frame->rawwidth; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w) = *pInOdd; + *(pOut+w+1) = *pInOdd++; + pOut += 2; + } + pOut += w; + } + + if (rawformat == RAWFMT_YUV420) { + /* U */ + pInOdd = pIn0 + fieldpix * 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; + } + pOut += w/2; + } + /* V */ + pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; + } + pOut += w/2; + } + } +} + +static void +ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + /* Deinterlace frame, if necessary */ + if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, + frame->tempdata); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->tempdata); + + deinterlace(frame, RAWFMT_YUV400, frame->tempdata, + frame->data); + } else { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, + frame->data); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->data); + } +} + +#ifdef OV511_ALLOW_CONVERSION +/* Process raw YUV420 data into the format requested by the app. Conversion + * between V4L formats is allowed. + */ +static void +ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + /* Process frame->rawdata to frame->tempdata */ + if (frame->compressed) + decompress(ov, frame, frame->rawdata, frame->tempdata); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata); + + /* Deinterlace frame, if necessary */ + if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { + memcpy(frame->rawdata, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + deinterlace(frame, RAWFMT_YUV420, frame->rawdata, + frame->tempdata); + } + + /* Frame should be (width x height) and not (rawwidth x rawheight) at + * this point. */ + + /* Process frame->tempdata to frame->data */ + switch (frame->format) { + case VIDEO_PALETTE_RGB565: + yuv420p_to_rgb(frame, frame->tempdata, frame->data, 16); + break; + case VIDEO_PALETTE_RGB24: + yuv420p_to_rgb(frame, frame->tempdata, frame->data, 24); + break; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + yuv420p_to_yuv422(frame, frame->tempdata, frame->data); + break; + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV420P: + memcpy(frame->data, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + break; + case VIDEO_PALETTE_YUV422P: + /* Data is converted in place, so copy it in advance */ + memcpy(frame->data, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + + yuv420p_to_yuv422p(frame, frame->data); + break; + default: + err("Cannot convert YUV420 to %s", + symbolic(v4l1_plist, frame->format)); + } + + if (fix_rgb_offset) + fixFrameRGBoffset(frame); +} + +#else /* if conversion not allowed */ + +/* Process raw YUV420 data into standard YUV420P */ +static void +ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + /* Deinterlace frame, if necessary */ + if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, frame->tempdata); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, + frame->tempdata); + + deinterlace(frame, RAWFMT_YUV420, frame->tempdata, + frame->data); + } else { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, frame->data); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, + frame->data); + } +} +#endif /* OV511_ALLOW_CONVERSION */ + +/* Post-processes the specified frame. This consists of: + * 1. Decompress frame, if necessary + * 2. Deinterlace frame and scale to proper size, if necessary + * 3. Convert from YUV planar to destination format, if necessary + * 4. Fix the RGB offset, if necessary + */ +static void +ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + if (dumppix) { + memset(frame->data, 0, + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); + memcpy(frame->data, frame->rawdata, frame->bytes_recvd); + } else { + switch (frame->format) { + case VIDEO_PALETTE_GREY: + ov51x_postprocess_grey(ov, frame); + break; + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV420P: +#ifdef OV511_ALLOW_CONVERSION + case VIDEO_PALETTE_RGB565: + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_YUV422P: +#endif + ov51x_postprocess_yuv420(ov, frame); + break; + default: + err("Cannot convert data to %s", + symbolic(v4l1_plist, frame->format)); + } + } +} + +/********************************************************************** + * + * OV51x data transfer, IRQ handler + * + **********************************************************************/ + +static inline void +ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) +{ + int num, offset; + int pnum = in[ov->packet_size - 1]; /* Get packet number */ + int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); + struct ov511_frame *frame = &ov->frame[ov->curframe]; + struct timeval *ts; + + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th + * byte non-zero. The EOF packet has image width/height in the + * 10th and 11th bytes. The 9th byte is given as follows: + * + * bit 7: EOF + * 6: compression enabled + * 5: 422/420/400 modes + * 4: 422/420/400 modes + * 3: 1 + * 2: snapshot button on + * 1: snapshot frame + * 0: even/odd field + */ + + if (printph) { + info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", + pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], + in[7], in[8], in[9], in[10], in[11]); + } + + /* Check for SOF/EOF packet */ + if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || + (~in[8] & 0x08)) + goto check_middle; + + /* Frame end */ + if (in[8] & 0x80) { + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + do_gettimeofday(ts); + + /* Get the actual frame size from the EOF header */ + frame->rawwidth = ((int)(in[9]) + 1) * 8; + frame->rawheight = ((int)(in[10]) + 1) * 8; + + PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", + ov->curframe, pnum, frame->rawwidth, frame->rawheight, + frame->bytes_recvd); + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, + ov->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); + + if (frame->scanstate == STATE_LINES) { + int nextf; + + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + + /* If next frame is ready or grabbing, + * point to it */ + nextf = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[nextf].grabstate == FRAME_READY + || ov->frame[nextf].grabstate == FRAME_GRABBING) { + ov->curframe = nextf; + ov->frame[nextf].scanstate = STATE_SCANNING; + } else { + if (ov->frame[nextf].grabstate == FRAME_DONE) { + PDEBUG(4, "No empty frames left"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov->frame[nextf].grabstate); + } + + ov->curframe = -1; + } + } else { + PDEBUG(5, "Frame done, but not scanning"); + } + /* Image corruption caused by misplaced frame->segment = 0 + * fixed by carlosf@conectiva.com.br + */ + } else { + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); + + /* Check to see if it's a snapshot frame */ + /* FIXME?? Should the snapshot reset go here? Performance? */ + if (in[8] & 0x02) { + frame->snapshot = 1; + PDEBUG(3, "snapshot detected"); + } + + frame->scanstate = STATE_LINES; + frame->bytes_recvd = 0; + frame->compressed = in[8] & 0x40; + } + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(5, "Not in a frame; packet skipped"); + return; + } + + /* If frame start, skip header */ + if (frame->bytes_recvd == 0) + offset = 9; + else + offset = 0; + + num = n - offset - 1; + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n - 1; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), + in, n - 1); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else if (!frame->compressed && !remove_zeros) { + frame->bytes_recvd += num; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - num, + in + offset, num); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ + int b, read = 0, allzero, copied = 0; + if (offset) { + frame->bytes_recvd += 32 - offset; // Bytes out + memcpy(frame->rawdata, in + offset, 32 - offset); + read += 32; + } + + while (read < n - 1) { + allzero = 1; + for (b = 0; b < 32; b++) { + if (in[read + b]) { + allzero = 0; + break; + } + } + + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 32 <= max_raw) + { + memcpy(frame->rawdata + + frame->bytes_recvd + copied, + in + read, 32); + copied += 32; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + read += 32; + } + + frame->bytes_recvd += copied; + } +} + +static inline void +ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) +{ + int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); + struct ov511_frame *frame = &ov->frame[ov->curframe]; + struct timeval *ts; + + /* Don't copy the packet number byte */ + if (ov->packet_numbering) + --n; + + /* A false positive here is likely, until OVT gives me + * the definitive SOF/EOF format */ + if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { + if (printph) { + info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], + in[1], in[2], in[3], in[4], in[5], in[6], in[7]); + } + + if (frame->scanstate == STATE_LINES) { + PDEBUG(4, "Detected frame end/start"); + goto eof; + } else { //scanstate == STATE_SCANNING + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); + goto sof; + } + } else { + goto check_middle; + } + +eof: + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + do_gettimeofday(ts); + + PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", + ov->curframe, + (int)(in[9]), (int)(in[10]), frame->bytes_recvd); + + // FIXME: Since we don't know the header formats yet, + // there is no way to know what the actual image size is + frame->rawwidth = frame->width; + frame->rawheight = frame->height; + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); + + if (frame->scanstate == STATE_LINES) { + int nextf; + + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + + /* If next frame is ready or grabbing, + * point to it */ + nextf = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[nextf].grabstate == FRAME_READY + || ov->frame[nextf].grabstate == FRAME_GRABBING) { + ov->curframe = nextf; + ov->frame[nextf].scanstate = STATE_SCANNING; + frame = &ov->frame[nextf]; + } else { + if (ov->frame[nextf].grabstate == FRAME_DONE) { + PDEBUG(4, "No empty frames left"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov->frame[nextf].grabstate); + } + + ov->curframe = -1; + PDEBUG(4, "SOF dropped (no active frame)"); + return; /* Nowhere to store this frame */ + } + } +sof: + PDEBUG(4, "Starting capture on frame %d", frame->framenum); + +// Snapshot not reverse-engineered yet. +#if 0 + /* Check to see if it's a snapshot frame */ + /* FIXME?? Should the snapshot reset go here? Performance? */ + if (in[8] & 0x02) { + frame->snapshot = 1; + PDEBUG(3, "snapshot detected"); + } +#endif + frame->scanstate = STATE_LINES; + frame->bytes_recvd = 0; + frame->compressed = 1; + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(4, "scanstate: no SOF yet"); + return; + } + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else { + /* All incoming data are divided into 8-byte segments. If the + * segment contains all zero bytes, it must be skipped. These + * zero-segments allow the OV518 to mainain a constant data rate + * regardless of the effectiveness of the compression. Segments + * are aligned relative to the beginning of each isochronous + * packet. The first segment in each image is a header (the + * decompressor skips it later). + */ + + int b, read = 0, allzero, copied = 0; + + while (read < n) { + allzero = 1; + for (b = 0; b < 8; b++) { + if (in[read + b]) { + allzero = 0; + break; + } + } + + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 8 <= max_raw) + { + memcpy(frame->rawdata + + frame->bytes_recvd + copied, + in + read, 8); + copied += 8; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + read += 8; + } + frame->bytes_recvd += copied; + } +} + +static inline void +ov519_move_data(struct usb_ov511 *ov, unsigned char *in, int n) +{ + int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); + struct ov511_frame *frame = &ov->frame[ov->curframe]; + struct timeval *ts; + + /* Don't copy the packet number byte */ +// if (ov->packet_numbering) +// --n; +/* Header of ov519 is 16 bytes: + * Byte Value Description + * 0 0xff magic + * 1 0xff magic + * 2 0xff magic + * 3 0xXX 0x50 = SOF, 0x51 = EOF + * 9 0xXX 0x01 initial frame without data, 0x00 standard frame with image + * 14 Lo in EOF: length of image data / 8 + * 15 Hi + */ + + // Start Of Frame + if ((in[0]==0xff) && (in[1]==0xff) && (in[2]==0xff)) { + + if (printph) { + info("ph: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", + in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7], + in[8], in[9], in[10], in[11], in[12], in[13], in[14], in[15]); + } + + if (in[3]==0x50) { + PDEBUG(4, "Start Of Frame, framenum = %d", ov->curframe); + goto sof; + } else if (in[3]==0x51) { + PDEBUG(4, "End Of Frame"); + goto eof; + } else { + goto check_middle; + } + } else { + goto check_middle; + } + +eof: + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + do_gettimeofday(ts); + PDEBUG(4, "Frame end, curframe=%d, length=%d, recvd=%d", + ov->curframe, (int)((in[14]) + ((int)(in[15])<<8))<<3, frame->bytes_recvd - (jpeginfo?2:0)); + + + if (in[9]) { + PDEBUG(1, "initial frame"); + frame->scanstate = STATE_SCANNING; + return; + } + + // FIXME: Since we don't know the header formats yet, + // there is no way to know what the actual image size is + frame->rawwidth = frame->width; + frame->rawheight = frame->height; + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); + + /* Don't allow byte count to exceed buffer size */ + //RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); + + if (frame->scanstate == STATE_LINES) { + int nextf; + + if (((int)((in[14]) + ((int)(in[15])<<8))<<3) != (frame->bytes_recvd - (jpeginfo?2:0))) { + info("Data length in header and number of received bytes differ"); + frame->scanstate = STATE_SCANNING; + return; + } + + if (jpeginfo) { + frame->data[0] = in[14]; + frame->data[1] = in[15]; + } + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + + /* If next frame is ready or grabbing, + * point to it */ + nextf = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[nextf].grabstate == FRAME_READY + || ov->frame[nextf].grabstate == FRAME_GRABBING) { + ov->curframe = nextf; + ov->frame[nextf].scanstate = STATE_SCANNING; + } else { + ov->curframe = -1; + } + } else { + info("EOF without SOF"); // This happens if there was no active frame when SOF arrived + } + return; + +sof: + PDEBUG(4, "Starting capture on frame %d", frame->framenum); + + // Skip SOF Header: + in += 16; + n -= 16; + + frame->scanstate = STATE_LINES; + if (jpeginfo) { + frame->bytes_recvd = 2; // Space for length bytes. Will be written at EOF + frame->data[0] = 0; + frame->data[1] = 0; + } else { + frame->bytes_recvd = 0; + } + frame->compressed = 1; + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(4, "scanstate: no SOF yet"); + return; + } + + /* Dump all data exactly as received. It is standard JPEG */ + frame->bytes_recvd += n; + if (frame->bytes_recvd <= max_raw) { + memcpy(frame->data + frame->bytes_recvd - n, in, n); + } else { + PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - max_raw); + } +} + +static void +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 51) +ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) +#else +ov51x_isoc_irq(struct urb *urb) +#endif +{ + int i; + struct usb_ov511 *ov; + struct ov511_sbuf *sbuf; + + if (!urb->context) { + PDEBUG(4, "no context"); + return; + } + + sbuf = urb->context; + ov = sbuf->ov; + + if (!ov || !ov->dev || !ov->user) { + PDEBUG(4, "no device, or not open"); + return; + } + + if (!ov->streaming) { + PDEBUG(4, "hmmm... not streaming, but got interrupt"); + return; + } + + if (urb->status == -ENOENT || urb->status == -ECONNRESET) { + PDEBUG(4, "URB unlinked"); + return; + } + + if (urb->status != -EINPROGRESS && urb->status != 0) { + err("ERROR: urb->status=%d: %s", urb->status, + symbolic(urb_errlist, urb->status)); + } + + /* Copy the data received into our frame buffer */ + PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, + urb->number_of_packets); + for (i = 0; i < urb->number_of_packets; i++) { + /* Warning: Don't call *_move_data() if no frame active! */ + if (ov->curframe >= 0) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + unsigned char *cdata; + + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = 0; + + cdata = urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + + if (!n) { + PDEBUG(4, "Zero-length packet"); + continue; + } + + if (st) + PDEBUG(2, "data error: [%d] len=%d, status=%d", + i, n, st); + + switch (ov->bclass) { + case BCL_OV511: + ov511_move_data(ov, cdata, n); + break; + case BCL_OV518: + ov518_move_data(ov, cdata, n); + break; + case BCL_OV519: + ov519_move_data(ov, cdata, n); + break; + default: + err("Unknown bridge device (%d)", ov->bridge); + } + } else if (waitqueue_active(&ov->wq)) { + wake_up_interruptible(&ov->wq); + } + } + + /* Resubmit this URB */ + urb->dev = ov->dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4) + if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) +#else + if ((i = usb_submit_urb(urb)) != 0) +#endif + err("usb_submit_urb() ret %d", i); + + return; +} + +/**************************************************************************** + * + * Stream initialization and termination + * + ***************************************************************************/ + +static int +ov51x_init_isoc(struct usb_ov511 *ov) +{ + struct urb *urb; + int fx, err, n, size; + + PDEBUG(3, "*** Initializing capture ***"); + + ov->curframe = -1; + + switch (ov->bridge) { + case BRG_OV511: + if (cams == 1) size = 993; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else { + err("\"cams\" parameter too high!"); + return -1; + } + break; + case BRG_OV511PLUS: + if (cams == 1) size = 961; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else if (cams >= 5 && cams <= 8) size = 129; + else if (cams >= 9 && cams <= 31) size = 33; + else { + err("\"cams\" parameter too high!"); + return -1; + } + break; + case BRG_OV518: + case BRG_OV518PLUS: + if (cams == 1) size = 896; + else if (cams == 2) size = 512; + else if (cams == 3 || cams == 4) size = 256; + else if (cams >= 5 && cams <= 8) size = 128; + else { + err("\"cams\" parameter too high!"); + return -1; + } + break; + case BRG_OV519: + if (cams == 1) size = 896; + else if (cams == 2) size = 512; + else { + err("\"cams\" parameter too high!"); + return -1; + } + break; + default: + err("invalid bridge type"); + return -1; + } + + // FIXME: OV518+ is hardcoded to 15 FPS (alternate 5) for now + if (ov->bridge == BRG_OV518PLUS) { + if (packetsize == -1) { + ov518_set_packet_size(ov, 640); + } else { + info("Forcing packet size to %d", packetsize); + ov518_set_packet_size(ov, packetsize); + } + } else if (ov->bridge == BRG_OV518) { + if (packetsize == -1) { + ov518_set_packet_size(ov, 896); + } else { + info("Forcing packet size to %d", packetsize); + ov518_set_packet_size(ov, packetsize); + } + } else if (ov->bridge == BRG_OV519) { + if (packetsize == -1) { + ov519_set_packet_size(ov, size); + } else { + info("Forcing packet size to %d", packetsize); + ov519_set_packet_size(ov, packetsize); + } + } else { + if (packetsize == -1) { + ov511_set_packet_size(ov, size); + } else { + info("Forcing packet size to %d", packetsize); + ov511_set_packet_size(ov, packetsize); + } + } + + for (n = 0; n < OV511_NUMSBUF; n++) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) + urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); +#else + urb = usb_alloc_urb(FRAMES_PER_DESC); +#endif + if (!urb) { + err("init isoc: usb_alloc_urb ret. NULL"); + return -ENOMEM; + } + ov->sbuf[n].urb = urb; + urb->dev = ov->dev; + urb->context = &ov->sbuf[n]; + urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 45) + urb->transfer_flags = URB_ISO_ASAP; +#else + urb->transfer_flags = USB_ISO_ASAP; +#endif + urb->transfer_buffer = ov->sbuf[n].data; + urb->complete = ov51x_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; + urb->interval = 1; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = ov->packet_size * fx; + urb->iso_frame_desc[fx].length = ov->packet_size; + } + } + + ov->streaming = 1; + + for (n = 0; n < OV511_NUMSBUF; n++) { + ov->sbuf[n].urb->dev = ov->dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4) + err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); +#else + err = usb_submit_urb(ov->sbuf[n].urb); +#endif + if (err) { + err("init isoc: usb_submit_urb(%d) ret %d", n, err); + return err; + } + } + + return 0; +} + +static void +ov51x_unlink_isoc(struct usb_ov511 *ov) +{ + int n; + + /* Unschedule all of the iso td's */ + for (n = OV511_NUMSBUF - 1; n >= 0; n--) { + if (ov->sbuf[n].urb) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) + usb_unlink_urb(ov->sbuf[n].urb); +#else + usb_kill_urb(ov->sbuf[n].urb); +#endif + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; + } + } +} + +static void +ov51x_stop_isoc(struct usb_ov511 *ov) +{ + if (!ov->streaming || !ov->dev) + return; + + PDEBUG(3, "*** Stopping capture ***"); + + switch (ov->bclass) { + case BCL_OV511: + ov511_set_packet_size(ov, 0); + break; + case BCL_OV518: + ov518_set_packet_size(ov, 0); + break; + case BCL_OV519: + ov519_set_packet_size(ov, 0); + break; + } + ov->streaming = 0; + + ov51x_unlink_isoc(ov); +} + +static int +ov51x_new_frame(struct usb_ov511 *ov, int framenum) +{ + struct ov511_frame *frame; + int newnum; + + PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); + + if (!ov->dev) + return -1; + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (ov->curframe == -1) { + newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + if (ov->frame[newnum].grabstate == FRAME_READY) + framenum = newnum; + } else + return 0; + + frame = &ov->frame[framenum]; + + PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, + frame->width, frame->height); + + frame->grabstate = FRAME_GRABBING; + frame->scanstate = STATE_SCANNING; + frame->snapshot = 0; + + ov->curframe = framenum; + + /* Make sure it's not too big */ + if (frame->width > ov->maxwidth) + frame->width = ov->maxwidth; + + frame->width &= ~7L; /* Multiple of 8 */ + + if (frame->height > ov->maxheight) + frame->height = ov->maxheight; + + frame->height &= ~3L; /* Multiple of 4 */ + + return 0; +} + +/**************************************************************************** + * + * Buffer management + * + ***************************************************************************/ + +/* + * - You must acquire buf_lock before entering this function. + * - Because this code will free any non-null pointer, you must be sure to null + * them if you explicitly free them somewhere else! + */ +static void +ov51x_do_dealloc(struct usb_ov511 *ov) +{ + int i; + PDEBUG(4, "entered"); + + if (ov->fbuf) { + rvfree(ov->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + ov->fbuf = NULL; + } + + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; + + for (i = 0; i < OV511_NUMSBUF; i++) { + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].data = NULL; + ov->frame[i].rawdata = NULL; + ov->frame[i].tempdata = NULL; + if (ov->frame[i].compbuf) { + free_page((unsigned long) ov->frame[i].compbuf); + ov->frame[i].compbuf = NULL; + } + } + + PDEBUG(4, "buffer memory deallocated"); + ov->buf_state = BUF_NOT_ALLOCATED; + PDEBUG(4, "leaving"); +} + +static int +ov51x_alloc(struct usb_ov511 *ov) +{ + int i; + const int w = ov->maxwidth; + const int h = ov->maxheight; + const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); + const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); + + PDEBUG(4, "entered"); + down(&ov->buf_lock); + + if (ov->buf_state == BUF_ALLOCATED) + goto out; + + ov->fbuf = rvmalloc(data_bufsize); + if (!ov->fbuf) + goto error; + + ov->rawfbuf = vmalloc(raw_bufsize); + if (!ov->rawfbuf) + goto error; + + memset(ov->rawfbuf, 0, raw_bufsize); + + ov->tempfbuf = vmalloc(raw_bufsize); + if (!ov->tempfbuf) + goto error; + + memset(ov->tempfbuf, 0, raw_bufsize); + + for (i = 0; i < OV511_NUMSBUF; i++) { + ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * + MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov->sbuf[i].data) + goto error; + + PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); + ov->frame[i].rawdata = ov->rawfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + ov->frame[i].tempdata = ov->tempfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + + ov->frame[i].compbuf = + (unsigned char *) __get_free_page(GFP_KERNEL); + if (!ov->frame[i].compbuf) + goto error; + + PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); + } + + ov->buf_state = BUF_ALLOCATED; +out: + up(&ov->buf_lock); + PDEBUG(4, "leaving"); + return 0; +error: + ov51x_do_dealloc(ov); + up(&ov->buf_lock); + PDEBUG(4, "errored"); + return -ENOMEM; +} + +static void +ov51x_dealloc(struct usb_ov511 *ov) +{ + PDEBUG(4, "entered"); + down(&ov->buf_lock); + ov51x_do_dealloc(ov); + up(&ov->buf_lock); + PDEBUG(4, "leaving"); +} + +/**************************************************************************** + * + * V4L 1 API + * + ***************************************************************************/ + +#ifdef OV511_OLD_V4L +static int +ov51x_v4l1_open(struct video_device *vdev, int flags) +{ +#else +static int +ov51x_v4l1_open(struct inode *inode, struct file *file) +{ + struct video_device *vdev = video_devdata(file); +#endif + struct usb_ov511 *ov = video_get_drvdata(vdev); + int err, i; + +/* 2.2.x needs explicit module-locking */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 17) + MOD_INC_USE_COUNT; +#endif + + PDEBUG(4, "opening"); + + down(&ov->lock); + + err = -EBUSY; + if (ov->user) + goto out; + + ov->sub_flag = 0; + + /* In case app doesn't set them... */ + err = ov51x_set_default_params(ov); + if (err < 0) + goto out; + + /* Make sure frames are reset */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].grabstate = FRAME_UNUSED; + ov->frame[i].bytes_read = 0; + } + + /* If compression is on, make sure now that a + * decompressor can be loaded */ + if (ov->compress && !ov->decomp_ops) { + err = request_decompressor(ov); + if (err && !dumppix) + goto out; + } + + err = ov51x_alloc(ov); + if (err < 0) + goto out; + + err = ov51x_init_isoc(ov); + if (err) { + ov51x_dealloc(ov); + goto out; + } + + ov->user++; +// If using _NEW_ V4L... +#if !defined(OV511_OLD_V4L) + file->private_data = vdev; +#endif + + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 1); + +out: + up(&ov->lock); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 17) + if (err) + MOD_DEC_USE_COUNT; +#endif + + return err; +} + +#ifdef OV511_OLD_V4L +static void +ov51x_v4l1_close(struct video_device *vdev) +{ +#else +static int +ov51x_v4l1_close(struct inode *inode, struct file *file) +{ + struct video_device *vdev = file->private_data; +#endif + struct usb_ov511 *ov = video_get_drvdata(vdev); + + PDEBUG(4, "ov511_close"); + + down(&ov->lock); + + ov->user--; + ov51x_stop_isoc(ov); + + release_decompressor(ov); + + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + + if (ov->dev) + ov51x_dealloc(ov); + + up(&ov->lock); + + /* Device unplugged while open. Only a minimum of unregistration is done + * here; the disconnect callback already did the rest. */ + if (!ov->dev) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov); +#ifdef OV511_OLD_V4L + video_unregister_device(&ov->vdev); +#endif + kfree(ov); + ov = NULL; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 17) + MOD_DEC_USE_COUNT; +#endif + +#ifdef OV511_OLD_V4L + return; +#else + file->private_data = NULL; + return 0; +#endif +} + +/* Do not call this function directly! */ +static int +#ifdef OV511_OLD_V4L +ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd, + void *arg) +{ +#else +ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vdev = file->private_data; + struct usb_ov511 *ov = video_get_drvdata(vdev); +#endif + PDEBUG(5, "IOCtl: 0x%X", cmd); + + if (!ov->dev) + return -EIO; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability *b = arg; + + PDEBUG(4, "VIDIOCGCAP"); + + memset(b, 0, sizeof(struct video_capability)); + sprintf(b->name, "%s USB Camera", + symbolic(brglist, ov->bridge)); + b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; + b->channels = ov->num_inputs; + b->audios = 0; + b->maxwidth = ov->maxwidth; + b->maxheight = ov->maxheight; + b->minwidth = ov->minwidth; + b->minheight = ov->minheight; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + + PDEBUG(4, "VIDIOCGCHAN"); + + if ((unsigned)(v->channel) >= ov->num_inputs) { + err("Invalid channel (%d)", v->channel); + return -EINVAL; + } + + v->norm = ov->norm; + v->type = VIDEO_TYPE_CAMERA; + v->flags = 0; +// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; + v->tuners = 0; + decoder_get_input_name(ov, v->channel, v->name); + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel *v = arg; + int err; + + PDEBUG(4, "VIDIOCSCHAN"); + + /* Make sure it's not a camera */ + if (!ov->has_decoder) { + if (v->channel == 0) + return 0; + else + return -EINVAL; + } + + if (v->norm != VIDEO_MODE_PAL && + v->norm != VIDEO_MODE_NTSC && + v->norm != VIDEO_MODE_SECAM && + v->norm != VIDEO_MODE_AUTO) { + err("Invalid norm (%d)", v->norm); + return -EINVAL; + } + + if ((unsigned)(v->channel) >= ov->num_inputs) { + err("Invalid channel (%d)", v->channel); + return -EINVAL; + } + + err = decoder_set_input(ov, v->channel); + if (err) + return err; + + err = decoder_set_norm(ov, v->norm); + if (err) + return err; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture *p = arg; + + PDEBUG(4, "VIDIOCGPICT"); + + memset(p, 0, sizeof(struct video_picture)); + if (sensor_get_picture(ov, p)) + return -EIO; + + /* Can we get these from frame[0]? -claudio? */ + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture *p = arg; + int i, rc; + + PDEBUG(4, "VIDIOCSPICT"); + + if (!get_depth(p->palette)) + return -EINVAL; + + if (sensor_set_picture(ov, p)) + return -EIO; + + if (force_palette && p->palette != force_palette) { + info("Palette rejected (%s)", + symbolic(v4l1_plist, p->palette)); + return -EINVAL; + } + + // FIXME: Format should be independent of frames + if (p->palette != ov->frame[0].format) { + PDEBUG(4, "Detected format change"); + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + mode_init_regs(ov, ov->frame[0].width, + ov->frame[0].height, p->palette, ov->sub_flag); + } + + PDEBUG(4, "Setting depth=%d, palette=%s", + p->depth, symbolic(v4l1_plist, p->palette)); + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].depth = p->depth; + ov->frame[i].format = p->palette; + } + + return 0; + } + case VIDIOCGCAPTURE: + { + int *vf = arg; + + PDEBUG(4, "VIDIOCGCAPTURE"); + + ov->sub_flag = *vf; + return 0; + } + case VIDIOCSCAPTURE: + { + struct video_capture *vc = arg; + + PDEBUG(4, "VIDIOCSCAPTURE"); + + if (vc->flags) + return -EINVAL; + if (vc->decimation) + return -EINVAL; + + vc->x &= ~3L; + vc->y &= ~1L; + vc->y &= ~31L; + + if (vc->width == 0) + vc->width = 32; + + vc->height /= 16; + vc->height *= 16; + if (vc->height == 0) + vc->height = 16; + + ov->subx = vc->x; + ov->suby = vc->y; + ov->subw = vc->width; + ov->subh = vc->height; + + return 0; + } + case VIDIOCSWIN: + { + struct video_window *vw = arg; + int i, rc; + + PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); + +#if 0 + if (vw->flags) + return -EINVAL; + if (vw->clipcount) + return -EINVAL; + if (vw->height != ov->maxheight) + return -EINVAL; + if (vw->width != ov->maxwidth) + return -EINVAL; +#endif + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + rc = mode_init_regs(ov, vw->width, vw->height, + ov->frame[0].format, ov->sub_flag); + if (rc < 0) + return rc; + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].width = vw->width; + ov->frame[i].height = vw->height; + } + + return 0; + } + case VIDIOCGWIN: + { + struct video_window *vw = arg; + + memset(vw, 0, sizeof(struct video_window)); + vw->x = 0; /* FIXME */ + vw->y = 0; + vw->width = ov->frame[0].width; + vw->height = ov->frame[0].height; + vw->flags = 30; + + PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf *vm = arg; + int i; + + PDEBUG(4, "VIDIOCGMBUF"); + + memset(vm, 0, sizeof(struct video_mbuf)); + vm->size = OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); + vm->frames = OV511_NUMFRAMES; + + vm->offsets[0] = 0; + for (i = 1; i < OV511_NUMFRAMES; i++) { + vm->offsets[i] = vm->offsets[i-1] + + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); + } + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap *vm = arg; + int rc, depth; + unsigned int f = vm->frame; + + PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, + vm->height, symbolic(v4l1_plist, vm->format)); + + depth = get_depth(vm->format); + if (!depth) { + PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", + symbolic(v4l1_plist, vm->format)); + return -EINVAL; + } + + if (f >= OV511_NUMFRAMES) { + err("VIDIOCMCAPTURE: invalid frame (%d)", f); + return -EINVAL; + } + + if (vm->width > ov->maxwidth + || vm->height > ov->maxheight) { + err("VIDIOCMCAPTURE: requested dimensions too big"); + return -EINVAL; + } + + if (ov->frame[f].grabstate == FRAME_GRABBING) { + PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); + return -EBUSY; + } + + if (force_palette && (vm->format != force_palette)) { + PDEBUG(2, "palette rejected (%s)", + symbolic(v4l1_plist, vm->format)); + return -EINVAL; + } + + if ((ov->frame[f].width != vm->width) || + (ov->frame[f].height != vm->height) || + (ov->frame[f].format != vm->format) || + (ov->frame[f].sub_flag != ov->sub_flag) || + (ov->frame[f].depth != depth)) { + PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + rc = mode_init_regs(ov, vm->width, vm->height, + vm->format, ov->sub_flag); +#if 0 + if (rc < 0) { + PDEBUG(1, "Got error while initializing regs "); + return ret; + } +#endif + ov->frame[f].width = vm->width; + ov->frame[f].height = vm->height; + ov->frame[f].format = vm->format; + ov->frame[f].sub_flag = ov->sub_flag; + ov->frame[f].depth = depth; + } + + /* Mark it as ready */ + ov->frame[f].grabstate = FRAME_READY; + + PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); + + return ov51x_new_frame(ov, f); + } + case VIDIOCSYNC: + { + unsigned int fnum = *((unsigned int *) arg); + struct ov511_frame *frame; + int rc; + + if (fnum >= OV511_NUMFRAMES) { + err("VIDIOCSYNC: invalid frame (%d)", fnum); + return -EINVAL; + } + + frame = &ov->frame[fnum]; + + PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, + frame->grabstate); + + switch (frame->grabstate) { + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + case FRAME_ERROR: +redo: + if (!ov->dev) + return -EIO; + + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + return rc; + + if (frame->grabstate == FRAME_ERROR) { + if ((rc = ov51x_new_frame(ov, fnum)) < 0) + return rc; + goto redo; + } + /* Fall through */ + case FRAME_DONE: + if (ov->snap_enabled && !frame->snapshot) { + if ((rc = ov51x_new_frame(ov, fnum)) < 0) + return rc; + goto redo; + } + + frame->grabstate = FRAME_UNUSED; + + /* Reset the hardware snapshot button */ + /* FIXME - Is this the best place for this? */ + if ((ov->snap_enabled) && (frame->snapshot)) { + frame->snapshot = 0; + ov51x_clear_snapshot(ov); + } + + /* Decompression, format conversion, etc... */ + if (ov->bclass != BCL_OV519) { + ov51x_postprocess(ov, frame); + } + + break; + } /* end switch */ + + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer *vb = arg; + + PDEBUG(4, "VIDIOCGFBUF"); + + memset(vb, 0, sizeof(struct video_buffer)); + + return 0; + } + case VIDIOCGUNIT: + { + struct video_unit *vu = arg; + + PDEBUG(4, "VIDIOCGUNIT"); + + memset(vu, 0, sizeof(struct video_unit)); + + vu->video = ov->vdev->minor; + vu->vbi = VIDEO_NO_UNIT; + vu->radio = VIDEO_NO_UNIT; + vu->audio = VIDEO_NO_UNIT; + vu->teletext = VIDEO_NO_UNIT; + + return 0; + } + case OV511IOC_WI2C: + { + struct ov511_i2c_struct *w = arg; + + return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); + } + case OV511IOC_RI2C: + { + struct ov511_i2c_struct *r = arg; + int rc; + + rc = i2c_r_slave(ov, r->slave, r->reg); + if (rc < 0) + return rc; + + r->value = rc; + return 0; + } + default: + PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); + return -ENOIOCTLCMD; + } /* end switch */ + + return 0; +} + +#ifdef OV511_OLD_V4L +/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */ +static int +ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = arg; + break; + case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (copy_from_user(parg, arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user(arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + if (mbuf) + kfree(mbuf); + return err; +} + +static int +ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct usb_ov511 *ov = vdev->priv; + int rc; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg); + + up(&ov->lock); + return rc; +} + +#else /* If new V4L API */ + +static int +ov51x_v4l1_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = file->private_data; + struct usb_ov511 *ov = video_get_drvdata(vdev); + int rc; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); + + up(&ov->lock); + return rc; +} +#endif /* OV511_OLD_V4L */ + +#ifdef OV511_OLD_V4L +static long +ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, + int noblock) +{ +#else +static ssize_t +ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos) +{ + struct video_device *vdev = file->private_data; + int noblock = file->f_flags&O_NONBLOCK; + unsigned long count = cnt; +#endif + struct usb_ov511 *ov = video_get_drvdata(vdev); + int i, rc = 0, frmx = -1; + struct ov511_frame *frame; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); + + if (!vdev || !buf) { + rc = -EFAULT; + goto error; + } + + if (!ov->dev) { + rc = -EIO; + goto error; + } + +// FIXME: Only supports two frames + /* See if a frame is completed, then use it. */ + if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + frmx = 0; + else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + frmx = 1; + + /* If nonblocking we return immediately */ + if (noblock && (frmx == -1)) { + rc = -EAGAIN; + goto error; + } + + /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ + /* See if a frame is in process (grabbing), then use it. */ + if (frmx == -1) { + if (ov->frame[0].grabstate == FRAME_GRABBING) + frmx = 0; + else if (ov->frame[1].grabstate == FRAME_GRABBING) + frmx = 1; + } + + /* If no frame is active, start one. */ + if (frmx == -1) { + if ((rc = ov51x_new_frame(ov, frmx = 0))) { + err("read: ov51x_new_frame error"); + goto error; + } + } + + frame = &ov->frame[frmx]; + +restart: + if (!ov->dev) { + rc = -EIO; + goto error; + } + + /* Wait while we're grabbing the image */ + PDEBUG(4, "Waiting image grabbing"); + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + goto error; + + PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); + PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); + + if (frame->grabstate == FRAME_ERROR) { + frame->bytes_read = 0; + err("** ick! ** Errored frame %d", ov->curframe); + if (ov51x_new_frame(ov, frmx)) { + err("read: ov51x_new_frame error"); + goto error; + } + goto restart; + } + + + /* Repeat until we get a snapshot frame */ + if (ov->snap_enabled) + PDEBUG(4, "Waiting snapshot frame"); + if (ov->snap_enabled && !frame->snapshot) { + frame->bytes_read = 0; + if ((rc = ov51x_new_frame(ov, frmx))) { + err("read: ov51x_new_frame error"); + goto error; + } + goto restart; + } + + /* Clear the snapshot */ + if (ov->snap_enabled && frame->snapshot) { + frame->snapshot = 0; + ov51x_clear_snapshot(ov); + } + + /* Decompression, format conversion, etc... */ + if (ov->bclass != BCL_OV519) { + ov51x_postprocess(ov, frame); + } + + PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, + frame->bytes_read, + get_frame_length(ov, frame)); + + /* copy bytes to user space; we allow for partials reads */ + if ((count + frame->bytes_read) > get_frame_length(ov, (struct ov511_frame *)frame)) { + count = frame->bytes_recvd - frame->bytes_read; + PDEBUG(4, "set count to %d", (int)count); + } + + /* FIXME - count hardwired to be one frame... */ + //count = get_frame_length(ov, frame); + + PDEBUG(4, "Copy to user space: %ld bytes", count); + if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { + PDEBUG(4, "Copy failed! %d bytes not copied", i); + rc = -EFAULT; + goto error; + } + + frame->bytes_read += count; + PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", + count, frame->bytes_read); + + /* If all data have been read... */ + if (frame->bytes_read >= get_frame_length(ov, frame)) { + frame->bytes_read = 0; + +// FIXME: Only supports two frames + /* Mark it as available to be used again. */ + ov->frame[frmx].grabstate = FRAME_UNUSED; + if ((rc = ov51x_new_frame(ov, !frmx))) { + err("ov51x_new_frame returned error"); + goto error; + } + } + + PDEBUG(4, "read finished, returning %ld (sweet)", count); + + up(&ov->lock); + return count; + +error: + up(&ov->lock); + return rc; +} + +static int +#ifdef OV511_OLD_V4L + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3) +ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, + const char *adr, unsigned long size) + #else +ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size) + #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3) */ +{ + unsigned long start = (unsigned long)adr; + +#else /* New V4L API */ + +ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = file->private_data; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; +#endif /* OV511_OLD_V4L */ + + struct usb_ov511 *ov = video_get_drvdata(vdev); + unsigned long page, pos; + + if (ov->dev == NULL) + return -EIO; + + PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); + + if (size > (((OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) + + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) + return -EINVAL; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + pos = (unsigned long)ov->fbuf; + while (size > 0) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3) || defined(RH9_REMAP) + page = kvirt_to_pa(pos); + if (remap_page_range(vma, start, page, PAGE_SIZE, + PAGE_SHARED)) { +#else + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { +#endif + up(&ov->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + up(&ov->lock); + return 0; +} + +#ifdef OV511_OLD_V4L +static struct video_device vdev_template = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 17) + .owner = THIS_MODULE, +#endif + .name = "OV511 USB Camera", + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_OV511, + .open = ov51x_v4l1_open, + .close = ov51x_v4l1_close, + .read = ov51x_v4l1_read, + .ioctl = ov51x_v4l1_ioctl, + .mmap = ov51x_v4l1_mmap, +}; + +#else /* New V4L API */ + +static struct file_operations ov511_fops = { + .owner = THIS_MODULE, + .open = ov51x_v4l1_open, + .release = ov51x_v4l1_close, + .read = ov51x_v4l1_read, + .mmap = ov51x_v4l1_mmap, + .ioctl = ov51x_v4l1_ioctl, + .llseek = no_llseek, +}; + +static struct video_device vdev_template = { + .owner = THIS_MODULE, + .name = "OV51x USB Camera", + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_OV511, + .fops = &ov511_fops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + .release = video_device_release, +#endif + .minor = -1, +}; +#endif /* OV511_OLD_V4L */ + +#if defined(CONFIG_VIDEO_PROC_FS) +static int +ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long ularg) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) + struct proc_dir_entry *pde = PDE(inode); +#else + struct proc_dir_entry *pde = inode->u.generic_ip; +#endif + struct usb_ov511 *ov; + void *arg = (void *) ularg; + int rc; + + if (!pde) + return -ENOENT; + + ov = pde->data; + if (!ov) + return -ENODEV; + + if (!ov->dev) + return -EIO; + + /* Should we pass through standard V4L IOCTLs? */ + + switch (cmd) { + case OV511IOC_GINTVER: + { + return OV511_INTERFACE_VER; + } + case OV511IOC_GUSHORT: + { + struct ov511_ushort_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_USOPT_BRIGHT: + rc = sensor_get_brightness(ov, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_SAT: + rc = sensor_get_saturation(ov, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_HUE: + rc = sensor_get_hue(ov, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_CONTRAST: + rc = sensor_get_contrast(ov, &(opt.val)); + if (rc) return rc; + break; + default: + err("Invalid get short option number"); + return -EINVAL; + } + + if (copy_to_user(arg, &opt, sizeof(opt))) + return -EFAULT; + + return 0; + } + case OV511IOC_SUSHORT: + { + struct ov511_ushort_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_USOPT_BRIGHT: + rc = sensor_set_brightness(ov, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_SAT: + rc = sensor_set_saturation(ov, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_HUE: + rc = sensor_set_hue(ov, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_CONTRAST: + rc = sensor_set_contrast(ov, opt.val); + if (rc) return rc; + break; + default: + err("Invalid set short option number"); + return -EINVAL; + } + + return 0; + } + case OV511IOC_GUINT: + { + struct ov511_uint_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_UIOPT_POWER_FREQ: + opt.val = ov->lightfreq; + break; + case OV511_UIOPT_BFILTER: + opt.val = ov->bandfilt; + break; + case OV511_UIOPT_LED: + opt.val = ov->led_policy; + break; + case OV511_UIOPT_LED2: + opt.val = ov->led2_policy; + break; + case OV511_UIOPT_DEBUG: + opt.val = debug; + break; + case OV511_UIOPT_COMPRESS: + opt.val = ov->compress; + break; + default: + err("Invalid get int option number"); + return -EINVAL; + } + + if (copy_to_user(arg, &opt, sizeof(opt))) + return -EFAULT; + + return 0; + } + case OV511IOC_SUINT: + { + struct ov511_uint_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_UIOPT_POWER_FREQ: + rc = sensor_set_light_freq(ov, opt.val); + if (rc) return rc; + break; + case OV511_UIOPT_BFILTER: + rc = sensor_set_banding_filter(ov, opt.val); + if (rc) return rc; + break; + case OV511_UIOPT_LED: + if (opt.val <= 2) { + ov->led_policy = opt.val; + if (ov->led_policy == LED_OFF) + ov51x_led_control(ov, 0); + else if (ov->led_policy == LED_ON) + ov51x_led_control(ov, 1); + } else { + return -EINVAL; + } + break; + case OV511_UIOPT_LED2: + if (opt.val <= 2) { + ov->led2_policy = opt.val; + if (ov->led2_policy == LED_OFF) + ov51x_led_control(ov, 0); + else if (ov->led2_policy == LED_ON) + ov51x_led_control(ov, 1); + } else { + return -EINVAL; + } + break; + case OV511_UIOPT_DEBUG: + if (opt.val <= 5) + debug = opt.val; + else + return -EINVAL; + break; + case OV511_UIOPT_COMPRESS: + ov->compress = opt.val; + if (ov->compress) { + if (ov->bclass == BCL_OV511) + ov511_init_compression(ov); + else if (ov->bclass == BCL_OV518) + ov518_init_compression(ov); + else if (ov->bclass == BCL_OV519) + ov519_init_compression(ov); + } + break; + default: + err("Invalid get int option number"); + return -EINVAL; + } + + return 0; + } + case OV511IOC_WI2C: + { + struct ov511_i2c_struct w; + + if (copy_from_user(&w, arg, sizeof(w))) + return -EFAULT; + + return i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask); + } + case OV511IOC_RI2C: + { + struct ov511_i2c_struct r; + + if (copy_from_user(&r, arg, sizeof(r))) + return -EFAULT; + + rc = i2c_r_slave(ov, r.slave, r.reg); + if (rc < 0) + return rc; + + r.value = rc; + + if (copy_to_user(arg, &r, sizeof(r))) + return -EFAULT; + + return 0; + } + default: + return -EINVAL; + } + + return 0; +} +#endif + +/**************************************************************************** + * + * OV511 and sensor configuration + * + ***************************************************************************/ + +/* This initializes the OV8110, OV8610 sensor. The OV8110 uses + * the same register settings as the OV8610, since they are very similar. + */ +static int +ov8xx0_configure(struct usb_ov511 *ov) +{ + int rc; + + static struct ov511_regvals regvals_norm_8610[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x80 }, + { OV511_I2C_BUS, 0x02, 0x80 }, + { OV511_I2C_BUS, 0x03, 0xc0 }, + { OV511_I2C_BUS, 0x04, 0x30 }, + { OV511_I2C_BUS, 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ + { OV511_I2C_BUS, 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ + { OV511_I2C_BUS, 0x0a, 0x86 }, + { OV511_I2C_BUS, 0x0b, 0xb0 }, + { OV511_I2C_BUS, 0x0c, 0x20 }, + { OV511_I2C_BUS, 0x0d, 0x20 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x12, 0x25 }, + { OV511_I2C_BUS, 0x13, 0x01 }, + { OV511_I2C_BUS, 0x14, 0x04 }, + { OV511_I2C_BUS, 0x15, 0x01 }, /* Lin and Win think different about UV order */ + { OV511_I2C_BUS, 0x16, 0x03 }, + { OV511_I2C_BUS, 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ + { OV511_I2C_BUS, 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ + { OV511_I2C_BUS, 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ + { OV511_I2C_BUS, 0x1a, 0xf5 }, + { OV511_I2C_BUS, 0x1b, 0x00 }, + { OV511_I2C_BUS, 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ + { OV511_I2C_BUS, 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ + { OV511_I2C_BUS, 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ + { OV511_I2C_BUS, 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xea }, + { OV511_I2C_BUS, 0x28, 0x00 }, + { OV511_I2C_BUS, 0x29, 0x00 }, + { OV511_I2C_BUS, 0x2a, 0x80 }, + { OV511_I2C_BUS, 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ + { OV511_I2C_BUS, 0x2c, 0xac }, + { OV511_I2C_BUS, 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ + { OV511_I2C_BUS, 0x2e, 0x80 }, + { OV511_I2C_BUS, 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ + { OV511_I2C_BUS, 0x4c, 0x00 }, + { OV511_I2C_BUS, 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ + { OV511_I2C_BUS, 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ + { OV511_I2C_BUS, 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ + { OV511_I2C_BUS, 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ + { OV511_I2C_BUS, 0x63, 0xff }, + { OV511_I2C_BUS, 0x64, 0x53 }, /* new windrv 090403 says 0x57, maybe thats wrong */ + { OV511_I2C_BUS, 0x65, 0x00 }, + { OV511_I2C_BUS, 0x66, 0x55 }, + { OV511_I2C_BUS, 0x67, 0xb0 }, + { OV511_I2C_BUS, 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ + { OV511_I2C_BUS, 0x69, 0x02 }, + { OV511_I2C_BUS, 0x6a, 0x22 }, + { OV511_I2C_BUS, 0x6b, 0x00 }, + { OV511_I2C_BUS, 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but deleting bit7 colors the first images red */ + { OV511_I2C_BUS, 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ + { OV511_I2C_BUS, 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ + { OV511_I2C_BUS, 0x6f, 0x01 }, + { OV511_I2C_BUS, 0x70, 0x8b }, + { OV511_I2C_BUS, 0x71, 0x00 }, + { OV511_I2C_BUS, 0x72, 0x14 }, + { OV511_I2C_BUS, 0x73, 0x54 }, + { OV511_I2C_BUS, 0x74, 0x00 },//0x60? /* was 0x00, new from windrv 090403 */ + { OV511_I2C_BUS, 0x75, 0x0e }, + { OV511_I2C_BUS, 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ + { OV511_I2C_BUS, 0x77, 0xff }, + { OV511_I2C_BUS, 0x78, 0x80 }, + { OV511_I2C_BUS, 0x79, 0x80 }, + { OV511_I2C_BUS, 0x7a, 0x80 }, + { OV511_I2C_BUS, 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ + { OV511_I2C_BUS, 0x7c, 0x00 }, + { OV511_I2C_BUS, 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ + { OV511_I2C_BUS, 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ + { OV511_I2C_BUS, 0x7f, 0xfb }, + { OV511_I2C_BUS, 0x80, 0x28 }, + { OV511_I2C_BUS, 0x81, 0x00 }, + { OV511_I2C_BUS, 0x82, 0x23 }, + { OV511_I2C_BUS, 0x83, 0x0b }, + { OV511_I2C_BUS, 0x84, 0x00 }, + { OV511_I2C_BUS, 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ + { OV511_I2C_BUS, 0x86, 0xc9 }, + { OV511_I2C_BUS, 0x87, 0x00 }, + { OV511_I2C_BUS, 0x88, 0x00 }, + { OV511_I2C_BUS, 0x89, 0x01 }, + { OV511_I2C_BUS, 0x12, 0x20 }, + { OV511_I2C_BUS, 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, "starting configuration"); + + if (init_ov_sensor(ov) < 0) { + err("Failed to read sensor ID. You might not have an"); + err("OV8600/10, or it might not be responding. Report"); + err("this to sensor = SEN_OV8610; + } else { + err("Unknown image sensor version: %d", rc & 3); + return -1; + } + + PDEBUG(4, "Writing 8610 registers"); + if (write_regvals(ov, regvals_norm_8610)) + return -1; + + /* Set sensor-specific vars */ + ov->maxwidth = 800; + ov->maxheight = 600; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + return 0; +} + +/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses + * the same register settings as the OV7610, since they are very similar. + */ +static int +ov7xx0_configure(struct usb_ov511 *ov) +{ + int rc, high, low; + + /* Lawrence Glaister reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ + static struct ov511_regvals regvals_norm_7610[] = { + { OV511_I2C_BUS, 0x10, 0xff }, + { OV511_I2C_BUS, 0x16, 0x06 }, + { OV511_I2C_BUS, 0x28, 0x24 }, + { OV511_I2C_BUS, 0x2b, 0xac }, + { OV511_I2C_BUS, 0x12, 0x00 }, + { OV511_I2C_BUS, 0x38, 0x81 }, + { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ + { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x20, 0x1c }, + { OV511_I2C_BUS, 0x23, 0x2a }, + { OV511_I2C_BUS, 0x24, 0x10 }, + { OV511_I2C_BUS, 0x25, 0x8a }, + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xc2 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, + { OV511_I2C_BUS, 0x2c, 0xfe }, + { OV511_I2C_BUS, 0x2d, 0x93 }, + { OV511_I2C_BUS, 0x30, 0x71 }, + { OV511_I2C_BUS, 0x31, 0x60 }, + { OV511_I2C_BUS, 0x32, 0x26 }, + { OV511_I2C_BUS, 0x33, 0x20 }, + { OV511_I2C_BUS, 0x34, 0x48 }, + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals regvals_norm_7620[] = { + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x80 }, + { OV511_I2C_BUS, 0x02, 0x80 }, + { OV511_I2C_BUS, 0x03, 0xc0 }, + { OV511_I2C_BUS, 0x06, 0x60 }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_I2C_BUS, 0x13, 0x01 }, + { OV511_I2C_BUS, 0x14, 0x84 }, + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x16, 0x03 }, + { OV511_I2C_BUS, 0x17, 0x2f }, + { OV511_I2C_BUS, 0x18, 0xcf }, + { OV511_I2C_BUS, 0x19, 0x06 }, + { OV511_I2C_BUS, 0x1a, 0xf5 }, + { OV511_I2C_BUS, 0x1b, 0x00 }, + { OV511_I2C_BUS, 0x20, 0x18 }, + { OV511_I2C_BUS, 0x21, 0x80 }, + { OV511_I2C_BUS, 0x22, 0x80 }, + { OV511_I2C_BUS, 0x23, 0x00 }, + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xea }, + { OV511_I2C_BUS, 0x28, 0x20 }, + { OV511_I2C_BUS, 0x29, 0x00 }, + { OV511_I2C_BUS, 0x2a, 0x10 }, + { OV511_I2C_BUS, 0x2b, 0x00 }, + { OV511_I2C_BUS, 0x2c, 0x88 }, + { OV511_I2C_BUS, 0x2d, 0x91 }, + { OV511_I2C_BUS, 0x2e, 0x80 }, + { OV511_I2C_BUS, 0x2f, 0x44 }, + { OV511_I2C_BUS, 0x60, 0x27 }, + { OV511_I2C_BUS, 0x61, 0x02 }, + { OV511_I2C_BUS, 0x62, 0x5f }, + { OV511_I2C_BUS, 0x63, 0xd5 }, + { OV511_I2C_BUS, 0x64, 0x57 }, + { OV511_I2C_BUS, 0x65, 0x83 }, + { OV511_I2C_BUS, 0x66, 0x55 }, + { OV511_I2C_BUS, 0x67, 0x92 }, + { OV511_I2C_BUS, 0x68, 0xcf }, + { OV511_I2C_BUS, 0x69, 0x76 }, + { OV511_I2C_BUS, 0x6a, 0x22 }, + { OV511_I2C_BUS, 0x6b, 0x00 }, + { OV511_I2C_BUS, 0x6c, 0x02 }, + { OV511_I2C_BUS, 0x6d, 0x44 }, + { OV511_I2C_BUS, 0x6e, 0x80 }, + { OV511_I2C_BUS, 0x6f, 0x1d }, + { OV511_I2C_BUS, 0x70, 0x8b }, + { OV511_I2C_BUS, 0x71, 0x00 }, + { OV511_I2C_BUS, 0x72, 0x14 }, + { OV511_I2C_BUS, 0x73, 0x54 }, + { OV511_I2C_BUS, 0x74, 0x00 }, + { OV511_I2C_BUS, 0x75, 0x8e }, + { OV511_I2C_BUS, 0x76, 0x00 }, + { OV511_I2C_BUS, 0x77, 0xff }, + { OV511_I2C_BUS, 0x78, 0x80 }, + { OV511_I2C_BUS, 0x79, 0x80 }, + { OV511_I2C_BUS, 0x7a, 0x80 }, + { OV511_I2C_BUS, 0x7b, 0xe2 }, + { OV511_I2C_BUS, 0x7c, 0x00 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + /* 7640 and 7648. The defaults should be OK for most registers. */ + static struct ov511_regvals regvals_norm_7640[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, + { OV511_I2C_BUS, 0x12, 0x14 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, "starting configuration"); + + if (init_ov_sensor(ov) < 0) { + err("Failed to read sensor ID. You might not have an"); + err("OV76xx, or it might not be responding. Report"); + err("this to " EMAIL); + err("This is only a warning. You can attempt to use"); + err("your camera anyway"); + } else { + PDEBUG(1, "OV7xx0 initialized"); + } + + /* Detect sensor (sub)type */ + rc = i2c_r(ov, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 3) == 3) { + info("Sensor is an OV7610"); + ov->sensor = SEN_OV7610; + } else if ((rc & 3) == 1) { + /* I don't know what's different about the 76BE yet. */ + if (i2c_r(ov, 0x15) & 1) + info("Sensor is an OV7620AE"); + else + info("Sensor is an OV76BE"); + + /* OV511+ will return all zero isoc data unless we + * configure the sensor as a 7620. Someone needs to + * find the exact reg. setting that causes this. */ + if (ov->bridge == BRG_OV511PLUS) + ov->sensor = SEN_OV7620; + else + ov->sensor = SEN_OV76BE; + } else if ((rc & 3) == 0) { + /* try to read product id registers */ + high = i2c_r(ov, 0x0a); + if (high < 0) { + err("Error detecting camera chip PID"); + return high; + } + low = i2c_r(ov, 0x0b); + if (low < 0) { + err("Error detecting camera chip VER"); + return low; + } + if (high == 0x76) { + if (low == 0x30) { + info("Sensor is an OV7630/OV7635"); + ov->sensor = SEN_OV7630; + } + else if (low == 0x40) { + info("Sensor is an OV7645"); + ov->sensor = SEN_OV7640; // FIXME + } + else if (low == 0x45) { + info("Sensor is an OV7645B"); + ov->sensor = SEN_OV7640; // FIXME + } + else if (low == 0x48) { + info("Sensor is an OV7648"); + ov->sensor = SEN_OV7640; // FIXME + } + else { + err("Unknown sensor: 0x76%X", low); + return -1; + } + } else { + info("Sensor is an OV7620"); + ov->sensor = SEN_OV7620; + } + } else { + err("Unknown image sensor version: %d", rc & 3); + return -1; + } + + if (ov->sensor == SEN_OV7620) { + PDEBUG(4, "Writing 7620 registers"); + if (write_regvals(ov, regvals_norm_7620)) + return -1; + } else if (ov->sensor == SEN_OV7630) { + PDEBUG(4, "7630 is not supported by this driver version"); + return -1; + } else if (ov->sensor == SEN_OV7640) { + PDEBUG(4, "Writing 7640 registers"); + if (write_regvals(ov, regvals_norm_7640)) + return -1; + } else { + PDEBUG(4, "Writing 7610 registers"); + if (write_regvals(ov, regvals_norm_7610)) + return -1; + } + + /* Set sensor-specific vars */ + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + return 0; +} + +/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ +static int +ov6xx0_configure(struct usb_ov511 *ov) +{ + int rc; + + static struct ov511_regvals regvals_norm_6x20[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x03, 0x60 }, + { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ + { OV511_I2C_BUS, 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ + { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ + { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ + { OV511_I2C_BUS, 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { OV511_I2C_BUS, 0x16, 0x06 }, +// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { OV511_I2C_BUS, 0x28, 0x05 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ + { OV511_I2C_BUS, 0x2d, 0x99 }, + { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */ + { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ + { OV511_I2C_BUS, 0x38, 0x8b }, + { OV511_I2C_BUS, 0x39, 0x40 }, + + { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ + { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ + { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { OV511_I2C_BUS, 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ + { OV511_I2C_BUS, 0x4a, 0x80 }, + { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ + { OV511_I2C_BUS, 0x4e, 0xc1 }, + { OV511_I2C_BUS, 0x4f, 0x04 }, +// Do 50-53 have any effect? +// Toggle 0x12[2] off and on here? + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ + }; + + static struct ov511_regvals regvals_norm_6x30[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, /* Reset */ + { OV511_I2C_BUS, 0x00, 0x1f }, /* Gain */ + { OV511_I2C_BUS, 0x01, 0x99 }, /* Blue gain */ + { OV511_I2C_BUS, 0x02, 0x7c }, /* Red gain */ + { OV511_I2C_BUS, 0x03, 0xc0 }, /* Saturation */ + { OV511_I2C_BUS, 0x05, 0x0a }, /* Contrast */ + { OV511_I2C_BUS, 0x06, 0x95 }, /* Brightness */ + { OV511_I2C_BUS, 0x07, 0x2d }, /* Sharpness */ + { OV511_I2C_BUS, 0x0c, 0x20 }, + { OV511_I2C_BUS, 0x0d, 0x20 }, + { OV511_I2C_BUS, 0x0e, 0x20 }, + { OV511_I2C_BUS, 0x0f, 0x05 }, + { OV511_I2C_BUS, 0x10, 0x9a }, + { OV511_I2C_BUS, 0x11, 0x00 }, /* Pixel clock = fastest */ + { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC and AWB */ + { OV511_I2C_BUS, 0x13, 0x21 }, + { OV511_I2C_BUS, 0x14, 0x80 }, + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x16, 0x03 }, + { OV511_I2C_BUS, 0x17, 0x38 }, + { OV511_I2C_BUS, 0x18, 0xea }, + { OV511_I2C_BUS, 0x19, 0x04 }, + { OV511_I2C_BUS, 0x1a, 0x93 }, + { OV511_I2C_BUS, 0x1b, 0x00 }, + { OV511_I2C_BUS, 0x1e, 0xc4 }, + { OV511_I2C_BUS, 0x1f, 0x04 }, + { OV511_I2C_BUS, 0x20, 0x20 }, + { OV511_I2C_BUS, 0x21, 0x10 }, + { OV511_I2C_BUS, 0x22, 0x88 }, + { OV511_I2C_BUS, 0x23, 0xc0 }, /* Crystal circuit power level */ + { OV511_I2C_BUS, 0x25, 0x9a }, /* Increase AEC black ratio */ + { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + { OV511_I2C_BUS, 0x27, 0xa2 }, + { OV511_I2C_BUS, 0x28, 0x00 }, + { OV511_I2C_BUS, 0x29, 0x00 }, + { OV511_I2C_BUS, 0x2a, 0x84 }, /* 60 Hz power */ + { OV511_I2C_BUS, 0x2b, 0xa8 }, /* 60 Hz power */ + { OV511_I2C_BUS, 0x2c, 0xa0 }, + { OV511_I2C_BUS, 0x2d, 0x95 }, /* Enable auto-brightness */ + { OV511_I2C_BUS, 0x2e, 0x88 }, + { OV511_I2C_BUS, 0x33, 0x26 }, + { OV511_I2C_BUS, 0x34, 0x03 }, + { OV511_I2C_BUS, 0x36, 0x8f }, + { OV511_I2C_BUS, 0x37, 0x80 }, + { OV511_I2C_BUS, 0x38, 0x83 }, + { OV511_I2C_BUS, 0x39, 0x80 }, + { OV511_I2C_BUS, 0x3a, 0x0f }, + { OV511_I2C_BUS, 0x3b, 0x3c }, + { OV511_I2C_BUS, 0x3c, 0x1a }, + { OV511_I2C_BUS, 0x3d, 0x80 }, + { OV511_I2C_BUS, 0x3e, 0x80 }, + { OV511_I2C_BUS, 0x3f, 0x0e }, + { OV511_I2C_BUS, 0x40, 0x00 }, /* White bal */ + { OV511_I2C_BUS, 0x41, 0x00 }, /* White bal */ + { OV511_I2C_BUS, 0x42, 0x80 }, + { OV511_I2C_BUS, 0x43, 0x3f }, /* White bal */ + { OV511_I2C_BUS, 0x44, 0x80 }, + { OV511_I2C_BUS, 0x45, 0x20 }, + { OV511_I2C_BUS, 0x46, 0x20 }, + { OV511_I2C_BUS, 0x47, 0x80 }, + { OV511_I2C_BUS, 0x48, 0x7f }, + { OV511_I2C_BUS, 0x49, 0x00 }, + { OV511_I2C_BUS, 0x4a, 0x00 }, + { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4c, 0xd0 }, + { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { OV511_I2C_BUS, 0x4e, 0x40 }, + { OV511_I2C_BUS, 0x4f, 0x07 }, /* UV avg., col. killer: max */ + { OV511_I2C_BUS, 0x50, 0xff }, + { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { OV511_I2C_BUS, 0x55, 0xff }, + { OV511_I2C_BUS, 0x56, 0x12 }, + { OV511_I2C_BUS, 0x57, 0x81 }, + { OV511_I2C_BUS, 0x58, 0x75 }, + { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp.: +1 */ + { OV511_I2C_BUS, 0x5a, 0x2c }, + { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ + { OV511_I2C_BUS, 0x5c, 0x10 }, + { OV511_I2C_BUS, 0x3d, 0x80 }, + { OV511_I2C_BUS, 0x27, 0xa6 }, + { OV511_I2C_BUS, 0x12, 0x20 }, /* Toggle AWB */ + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ + }; + + PDEBUG(4, "starting sensor configuration"); + + if (init_ov_sensor(ov) < 0) { + err("Failed to read sensor ID. You might not have an OV6xx0,"); + err("or it may be not responding. Report this to " EMAIL); + return -1; + } else { + PDEBUG(1, "OV6xx0 sensor detected"); + } + + /* Detect sensor (sub)type */ + rc = i2c_r(ov, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } + + /* Ugh. The first two bits are the version bits, but the entire register + * value must be used. I guess OVT underestimated how many variants + * they would make. */ + if (rc == 0x00) { + ov->sensor = SEN_OV6630; + info("WARNING: Sensor is an OV66308. Your camera may have"); + info("been misdetected in previous driver versions. Please"); + info("report this to Mark."); + } else if (rc == 0x01) { + ov->sensor = SEN_OV6620; + info("Sensor is an OV6620"); + } else if (rc == 0x02) { + ov->sensor = SEN_OV6630; + info("Sensor is an OV66308AE"); + } else if (rc == 0x03) { + ov->sensor = SEN_OV6630; + info("Sensor is an OV66308AF"); + } else if (rc == 0x90) { + ov->sensor = SEN_OV6630; + info("WARNING: Sensor is an OV66307. Your camera may have"); + info("been misdetected in previous driver versions. Please"); + info("report this to Mark."); + } else { + err("FATAL: Unknown sensor version: 0x%02x", rc); + return -1; + } + + /* Set sensor-specific vars */ + ov->maxwidth = 352; + ov->maxheight = 288; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + if (ov->sensor == SEN_OV6620) { + PDEBUG(4, "Writing 6x20 registers"); + if (write_regvals(ov, regvals_norm_6x20)) + return -1; + } else { + PDEBUG(4, "Writing 6x30 registers"); + if (write_regvals(ov, regvals_norm_6x30)) + return -1; + } + + return 0; +} + +/* This initializes the KS0127 and KS0127B video decoders. */ +static int +ks0127_configure(struct usb_ov511 *ov) +{ + int rc; + + /* Detect decoder subtype */ + rc = i2c_r(ov, 0x00); + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if (rc & 0x08) { + rc = i2c_r(ov, 0x3d); + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 0x0f) == 0) { + info("Sensor is a KS0127"); + } else if ((rc & 0x0f) == 9) { + info("Sensor is a KS0127B Rev. A"); + } + } else { + info("Sensor is a KS0122"); + } + + /* This device is not supported yet. Bail out now... */ + err("This sensor is not supported yet."); + return -1; +} + +/* This initializes the SAA7111A video decoder. */ +static int +saa7111a_configure(struct usb_ov511 *ov) +{ + int rc; + + /* Since there is no register reset command, all registers must be + * written, otherwise gives erratic results */ + static struct ov511_regvals regvals_norm_SAA7111A[] = { + { OV511_I2C_BUS, 0x06, 0xce }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ + { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x00 }, + { OV511_I2C_BUS, 0x03, 0x23 }, + { OV511_I2C_BUS, 0x04, 0x00 }, + { OV511_I2C_BUS, 0x05, 0x00 }, + { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ + { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ + { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ + { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ + { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ + { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ + { OV511_I2C_BUS, 0x0f, 0x00 }, + { OV511_I2C_BUS, 0x11, 0x0c }, + { OV511_I2C_BUS, 0x12, 0x00 }, + { OV511_I2C_BUS, 0x13, 0x00 }, + { OV511_I2C_BUS, 0x14, 0x00 }, + { OV511_I2C_BUS, 0x15, 0x00 }, + { OV511_I2C_BUS, 0x16, 0x00 }, + { OV511_I2C_BUS, 0x17, 0x00 }, + { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + /* 640x480 not supported with PAL */ + if (ov->pal) { + ov->maxwidth = 320; + ov->maxheight = 240; /* Even field only */ + } else { + ov->maxwidth = 640; + ov->maxheight = 480; /* Even/Odd fields */ + } + + ov->minwidth = 320; + ov->minheight = 240; /* Even field only */ + + ov->has_decoder = 1; + ov->num_inputs = 8; + ov->norm = VIDEO_MODE_AUTO; + ov->stop_during_set = 0; /* Decoder guarantees stable image */ + + /* Decoder doesn't change these values, so we use these instead of + * acutally reading the registers (which doesn't work) */ + ov->brightness = 0x80 << 8; + ov->contrast = 0x40 << 9; + ov->colour = 0x40 << 9; + ov->hue = 32768; + + PDEBUG(4, "Writing SAA7111A registers"); + if (write_regvals(ov, regvals_norm_SAA7111A)) + return -1; + + /* Detect version of decoder. This must be done after writing the + * initial regs or the decoder will lock up. */ + rc = i2c_r(ov, 0x00); + + if (rc < 0) { + err("Error detecting sensor version"); + return -1; + } else { + info("Sensor is an SAA7111A (version 0x%x)", rc); + ov->sensor = SEN_SAA7111A; + } + + /* Latch to negative edge of clock. Otherwise, we get incorrect + * colors and jitter in the digital signal. */ + if (ov->bclass == BCL_OV511) + reg_w(ov, 0x11, 0x00); + else + warn("SAA7111A not yet supported with OV518/OV518+"); + + return 0; +} + +/* This initializes the OV511/OV511+ and the sensor */ +static int +ov511_configure(struct usb_ov511 *ov) +{ + static struct ov511_regvals regvals_init_511[] = { + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, + { OV511_DONE_BUS, 0x0, 0x00}, + }; + + static struct ov511_regvals regvals_norm_511[] = { + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals regvals_norm_511_plus[] = { + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, ""); + + ov->customid = reg_r(ov, R511_SYS_CUST_ID); + if (ov->customid < 0) { + err("Unable to read camera bridge registers"); + goto error; + } + + PDEBUG (1, "CustomID = %d", ov->customid); + ov->desc = symbolic(camlist, ov->customid); + info("model: %s", ov->desc); + + if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { + err("Camera type (%d) not recognized", ov->customid); + err("Please notify " EMAIL " of the name,"); + err("manufacturer, model, and this number of your camera."); + err("Also include the output of the detection process."); + } + + if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ + ov->pal = 1; + + if (write_regvals(ov, regvals_init_511)) goto error; + + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + + /* The OV511+ has undocumented bits in the flow control register. + * Setting it to 0xff fixes the corruption with moving objects. */ + if (ov->bridge == BRG_OV511) { + if (write_regvals(ov, regvals_norm_511)) goto error; + } else if (ov->bridge == BRG_OV511PLUS) { + if (write_regvals(ov, regvals_norm_511_plus)) goto error; + } else { + err("Invalid bridge"); + } + + if (ov511_init_compression(ov)) goto error; + + ov->packet_numbering = 1; + ov511_set_packet_size(ov, 0); + + ov->snap_enabled = snapshot; + + /* Test for 7xx0 */ + PDEBUG(3, "Testing for 0V7xx0"); + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for 6xx0 */ + PDEBUG(3, "Testing for 0V6xx0"); + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for 8xx0 */ + PDEBUG(3, "Testing for 0V8xx0"); + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for SAA7111A */ + PDEBUG(3, "Testing for SAA7111A"); + ov->primary_i2c_slave = SAA7111A_SID; + if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) + goto error; + + if (i2c_w(ov, 0x0d, 0x00) < 0) { + /* Test for KS0127 */ + PDEBUG(3, "Testing for KS0127"); + ov->primary_i2c_slave = KS0127_SID; + if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) + goto error; + + if (i2c_w(ov, 0x10, 0x00) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + if (ks0127_configure(ov) < 0) { + err("Failed to configure KS0127"); + goto error; + } + } + } else { + if (saa7111a_configure(ov) < 0) { + err("Failed to configure SAA7111A"); + goto error; + } + } + } else { + if (ov8xx0_configure(ov) < 0) { + err("Failed to configure OV8xx0 sensor"); + goto error; + } + } + } else { + if (ov6xx0_configure(ov) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(ov) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } + } + + return 0; + +error: + err("OV511 Config failed"); + + return -EBUSY; +} + +/* This initializes the OV518/OV518+ and the sensor */ +static int +ov518_configure(struct usb_ov511 *ov) +{ + /* For 518 and 518+ */ + static struct ov511_regvals regvals_init_518[] = { + { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00}, + }; + + static struct ov511_regvals regvals_norm_518[] = { + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, 0x2f, 0x80 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals regvals_norm_518_plus[] = { + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x60 }, + { OV511_REG_BUS, 0x51, 0x02 }, + { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, 0x40, 0xff }, + { OV511_REG_BUS, 0x41, 0x42 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x33, 0x04 }, + { OV511_REG_BUS, 0x21, 0x19 }, + { OV511_REG_BUS, 0x3f, 0x10 }, + { OV511_REG_BUS, 0x2f, 0x80 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, ""); + + /* First 5 bits of custom ID reg are a revision ID on OV518 */ + info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); + + /* Give it the default description */ + ov->desc = symbolic(camlist, 0); + + if (write_regvals(ov, regvals_init_518)) goto error; + + /* Set LED GPIO pin to output mode */ + if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error; + + /* LED is off by default with OV518; have to explicitly turn it on */ + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + else + ov51x_led_control(ov, 1); + + /* Don't require compression if dumppix is enabled; otherwise it's + * required. OV518 has no uncompressed mode, to save RAM. */ + if (!dumppix && !ov->compress) { + ov->compress = 1; + warn("Compression required with OV518...enabling"); + } + + if (ov->bridge == BRG_OV518) { + if (write_regvals(ov, regvals_norm_518)) goto error; + } else if (ov->bridge == BRG_OV518PLUS) { + if (write_regvals(ov, regvals_norm_518_plus)) goto error; + } else { + err("Invalid bridge"); + } + + if (ov518_init_compression(ov)) goto error; + + if (ov->bridge == BRG_OV518) + { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7) + struct usb_interface *ifp; + struct usb_host_interface *alt; + __u16 mxps = 0; + + ifp = usb_ifnum_to_if(ov->dev, 0); + if (ifp) { + alt = usb_altnum_to_altsetting(ifp, 7); + if (alt) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); +# else + mxps = alt->endpoint[0].desc.wMaxPacketSize; +# endif + } +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + struct usb_interface *ifp = ov->dev->config[0].interface[0]; + __u16 mxps = ifp->altsetting[7].endpoint[0].desc.wMaxPacketSize; +#else + struct usb_interface *ifp = &ov->dev->config[0].interface[0]; + __u16 mxps = ifp->altsetting[7].endpoint[0].wMaxPacketSize; +#endif + /* Some OV518s have packet numbering by default, some don't */ + if (mxps == 897) + ov->packet_numbering = 1; + else + ov->packet_numbering = 0; + } else { + /* OV518+ has packet numbering turned on by default */ + ov->packet_numbering = 1; + } + + ov518_set_packet_size(ov, 0); + + ov->snap_enabled = snapshot; + + /* Test for 76xx */ + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + goto error; + + /* The OV518 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ + + if (init_ov_sensor(ov) < 0) { + /* Test for 6xx0 */ + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + /* Test for 8xx0 */ + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + if (ov8xx0_configure(ov) < 0) { + err("Failed to configure OV8xx0 sensor"); + goto error; + } + } + } else { + if (ov6xx0_configure(ov) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(ov) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } + } + + ov->maxwidth = 352; + ov->maxheight = 288; + + // The OV518 cannot go as low as the sensor can + ov->minwidth = 160; + ov->minheight = 120; + + return 0; + +error: + err("OV518 Config failed"); + + return -EBUSY; +} + +/* This initializes the OV518/OV518+ and the sensor */ +static int +ov519_configure(struct usb_ov511 *ov) +{ + + static struct ov511_regvals regvals_init_519[] = { + { OV511_REG_BUS, 0x5a, 0x6d }, /* EnableSystem */ + /* windows reads 0x53 at this point*/ + { OV511_REG_BUS, 0x53, 0x9b }, + { OV511_REG_BUS, 0x54, 0x0f }, // set bit2 to enable jpeg + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x49, 0x01 }, + { OV511_REG_BUS, 0x48, 0x00 }, + + /* Set LED pin to output mode. Bit 4 must be cleared or sensor + * detection will fail. This deserves further investigation. */ + { OV511_REG_BUS, OV519_GPIO_IO_CTRL0, 0xee }, + + { OV511_REG_BUS, 0x51, 0x0f }, /* SetUsbInit */ + { OV511_REG_BUS, 0x51, 0x00 }, + { OV511_REG_BUS, 0x22, 0x00 }, + /* windows reads 0x55 at this point*/ + { OV511_DONE_BUS, 0x0, 0x00}, + }; + + PDEBUG(4, ""); + + /* Give it the default description */ + ov->desc = symbolic(camlist, 0); + + if (write_regvals(ov, regvals_init_519)) + goto error; + + if (ov519_init_compression(ov)) + goto error; + + if (ov->imp == IMP_EYETOY) { + /* LED is annoyingly bright. Only turn it on if requested to. */ + if (ov->led2_policy == LED_ON) + ov51x_led_control(ov, 1); + else + ov51x_led_control(ov, 0); + } else { + /* LED might be off by default */ + if (ov->led_policy == LED_ON) + ov51x_led_control(ov, 1); + else + ov51x_led_control(ov, 0); + } + + /* Don't require compression if dumppix is enabled; otherwise it's + * required. OV519 probably has no uncompressed mode, to save RAM. */ + if (!dumppix && !ov->compress) + ov->compress = 1; + + ov->packet_numbering = 0; + + ov519_set_packet_size(ov, 0); + + ov->snap_enabled = snapshot; + + /* Test for 76xx */ + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + goto error; + + /* The OV519 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ + + if (init_ov_sensor(ov) < 0) { + /* Test for 6xx0 */ + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + /* Test for 8xx0 */ + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + if (ov8xx0_configure(ov) < 0) { + err("Failed to configure OV8xx0 sensor"); + goto error; + } + } + } else { + if (ov6xx0_configure(ov) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(ov) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } + } + + return 0; + +error: + err("OV519 Config failed"); + + return -EBUSY; +} + +/**************************************************************************** + * + * USB routines + * + ***************************************************************************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) +static int +ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +static void * +ov51x_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ +#else +static void * +ov51x_probe(struct usb_device *dev, unsigned int ifnum) +{ +#endif + struct usb_interface_descriptor *idesc; + struct usb_ov511 *ov; + int i; + u16 vendor, product; + + PDEBUG(1, "probing for device..."); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return -ENODEV; +#else + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return NULL; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7) + idesc = &intf->cur_altsetting->desc; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) + idesc = &intf->altsetting[0].desc; +#else + idesc = &dev->actconfig->interface[ifnum].altsetting[0]; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + vendor = le16_to_cpu(dev->descriptor.idVendor); + product = le16_to_cpu(dev->descriptor.idProduct); +#else + vendor = dev->descriptor.idVendor; + product = dev->descriptor.idProduct; +#endif + +/* 2.2.x compatibility */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + /* Is it an OV511/OV511+? */ + if (vendor != VEND_OMNIVISION + && vendor != VEND_MATTEL + && vendor != VEND_SONY) + return NULL; + + if (vendor == VEND_OMNIVISION + && product != PROD_OV511 + && product != PROD_OV518 + && product != PROD_OV511PLUS + && product != PROD_OV518PLUS + && product != PROD_OV519 + && product != PROD_OV1519 + && product != PROD_OV2519 + && product != PROD_OV3519 + && product != PROD_OV4519 + && product != PROD_OV5519 + && product != PROD_OV6519 + && product != PROD_OV7519 + && product != PROD_OV8519 + && product != PROD_OV9519 + && product != PROD_OVA519 + && product != PROD_OVB519 + && product != PROD_OVC519 + && product != PROD_OVD519 + && product != PROD_OVE519 + && product != PROD_OVF519 + && product != PROD_OV530) + return NULL; + + if (vendor == VEND_MATTEL + && product != PROD_ME2CAM) + return NULL; + + if (vendor == VEND_SONY + && product != PROD_EYETOY4 + && product != PROD_EYETOY5) + return NULL; + + if (vendor == VEND_MICROSOFT + && product != PROD_XBOX_CAM) + return NULL; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) + if (idesc->bInterfaceClass != 0xFF) + return -ENODEV; + if (idesc->bInterfaceSubClass != 0x00) + return -ENODEV; +#else + if (idesc->bInterfaceClass != 0xFF) + return NULL; + if (idesc->bInterfaceSubClass != 0x00) + return NULL; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) + /* Since code below may sleep, we use this as a lock */ + MOD_INC_USE_COUNT; +#endif + + if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc ov struct"); + goto error_out; + } + + memset(ov, 0, sizeof(*ov)); + + ov->dev = dev; + ov->iface = idesc->bInterfaceNumber; + ov->led_policy = led; + ov->led2_policy = led2; + ov->compress = compress; + ov->lightfreq = lightfreq; + ov->num_inputs = 1; /* Video decoder init functs. change this */ + ov->stop_during_set = !fastset; + ov->backlight = backlight; + ov->mirror = mirror; + ov->auto_brt = autobright; + ov->auto_gain = autogain; + ov->auto_exp = autoexp; + ov->imp = IMP_GENERIC; + + switch (product) { + case PROD_OV511: + ov->bridge = BRG_OV511; + ov->bclass = BCL_OV511; + break; + case PROD_OV511PLUS: + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; + break; + case PROD_OV518: + ov->bridge = BRG_OV518; + ov->bclass = BCL_OV518; + break; + case PROD_OV518PLUS: + ov->bridge = BRG_OV518PLUS; + ov->bclass = BCL_OV518; + break; + case PROD_OV519: + case PROD_OV4519: + case PROD_OV8519: + case PROD_OV530: + case PROD_XBOX_CAM: + ov->bridge = BRG_OV519; + ov->bclass = BCL_OV519; + break; + case PROD_OV1519: + case PROD_OV2519: + case PROD_OV3519: + case PROD_OV5519: + case PROD_OV6519: + case PROD_OV7519: + case PROD_OV9519: + case PROD_OVA519: + case PROD_OVB519: + case PROD_OVC519: + case PROD_OVD519: + case PROD_OVE519: + case PROD_OVF519: + info("Device has Product ID that hasn't been seen yet. It"); + info("will probably work anyway, but please send"); + info("/proc/bus/usb/devices, your dmesg log, and any info you"); + info("have about this device to mark@alpha.dyndns.org"); + ov->bridge = BRG_OV519; + ov->bclass = BCL_OV519; + break; + case PROD_EYETOY4: + case PROD_EYETOY5: + /* These two should work, but they are untested */ +// case PROD_EYETOY6: +// case PROD_EYETOY7: + ov->bridge = BRG_OV519; + ov->bclass = BCL_OV519; + ov->imp = IMP_EYETOY; + break; + case PROD_ME2CAM: + if (vendor != VEND_MATTEL) + goto error; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; + break; + default: + err("Unknown product ID 0x%04x", product); + goto error; + } + + info("USB %s video device found", symbolic(brglist, ov->bridge)); + +#ifdef OV511_ALLOW_CONVERSION + /* Workaround for some applications that want data in RGB + * instead of BGR. */ + if (force_rgb) + info("data format set to RGB"); +#endif + + init_waitqueue_head(&ov->wq); + + init_MUTEX(&ov->lock); /* to 1 == available */ + init_MUTEX(&ov->buf_lock); + init_MUTEX(&ov->param_lock); + init_MUTEX(&ov->i2c_lock); + init_MUTEX(&ov->cbuf_lock); + + ov->buf_state = BUF_NOT_ALLOCATED; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20) + if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { + err("usb_make_path error"); + goto error; + } +#endif + + /* Allocate control transfer buffer. */ + /* Must be kmalloc()'ed, for DMA compatibility */ + ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); + if (!ov->cbuf) + goto error; + + switch (ov->bclass) { + case BCL_OV511: + if (ov511_configure(ov) < 0) + goto error; + break; + case BCL_OV518: + if (ov518_configure(ov) < 0) + goto error; + break; + case BCL_OV519: + if (ov519_configure(ov) < 0) + goto error; + break; + default: + goto error; + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].framenum = i; + init_waitqueue_head(&ov->frame[i].wq); + } + + for (i = 0; i < OV511_NUMSBUF; i++) { + ov->sbuf[i].ov = ov; + spin_lock_init(&ov->sbuf[i].lock); + ov->sbuf[i].n = i; + } + + /* Unnecessary? (This is done on open(). Need to make sure variables + * are properly initialized without this before removing it, though). */ + if (ov51x_set_default_params(ov) < 0) + goto error; + +#ifdef OV511_DEBUG + if (dump_bridge) { + if (ov->bclass == BCL_OV511) + ov511_dump_regs(ov); + else + ov518_dump_regs(ov); + } +#endif + + ov->vdev = video_device_alloc(); + if (!ov->vdev) + goto error; + + memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + ov->vdev->dev = &dev->dev; +#endif + video_set_drvdata(ov->vdev, ov); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 5) + for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { + /* Minor 0 cannot be specified; assume user wants autodetect */ + if (unit_video[i] == 0) + break; + + if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, + unit_video[i]) >= 0) { + break; + } + } + + /* Use the next available one */ + if ((ov->vdev->minor == -1) && + video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { +#else + if (video_register_device(ov->vdev, VFL_TYPE_GRABBER) < 0) { +#endif + err("video_register_device failed"); + goto error; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20) + info("Device at %s registered to minor %d", ov->usb_path, + ov->vdev->minor); +#else + info("Device %d on bus %d registered to minor %d", dev->devnum, + dev->bus->busnum, ov->vdev->minor); +#endif + + create_proc_ov511_cam(ov); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) + MOD_DEC_USE_COUNT; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) + usb_set_intfdata(intf, ov); + return 0; +#else + return ov; +#endif + +error: + destroy_proc_ov511_cam(ov); + + if (ov->vdev) { + if (-1 == ov->vdev->minor) + video_device_release(ov->vdev); + else + video_unregister_device(ov->vdev); + ov->vdev = NULL; + } + + if (ov->cbuf) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + } + + kfree(ov); + ov = NULL; + +error_out: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) + MOD_DEC_USE_COUNT; +#endif + err("Camera initialization failed"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 36) + return -EIO; +#else + return NULL; +#endif +} + +static void +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +ov51x_disconnect(struct usb_interface *intf) +{ + struct usb_ov511 *ov = usb_get_intfdata(intf); +#else +ov51x_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_ov511 *ov = (struct usb_ov511 *) ptr; +#endif + int n; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) + MOD_INC_USE_COUNT; +#endif + + PDEBUG(3, ""); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + usb_set_intfdata(intf, NULL); +#endif + if (!ov) + return; + +#ifdef OV511_OLD_V4L + /* We don't want people trying to open up the device */ + if (!ov->user) + video_unregister_device(ov->vdev); + else + PDEBUG(3, "Device open...deferring video_unregister_device"); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + if (ov->vdev) + video_unregister_device(ov->vdev); +#else + video_unregister_device(ov->vdev); + if (ov->user) + PDEBUG(3, "Device open...deferring video_unregister_device"); +#endif + + for (n = 0; n < OV511_NUMFRAMES; n++) + ov->frame[n].grabstate = FRAME_ERROR; + + ov->curframe = -1; + + /* This will cause the process to request another frame */ + for (n = 0; n < OV511_NUMFRAMES; n++) + wake_up_interruptible(&ov->frame[n].wq); + + wake_up_interruptible(&ov->wq); + + ov->streaming = 0; + ov51x_unlink_isoc(ov); + + destroy_proc_ov511_cam(ov); + + ov->dev = NULL; + + /* Free the memory */ + if (ov && !ov->user) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + if (ov->vdev) + video_device_release(ov->vdev); +#endif + kfree(ov); + ov = NULL; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) + MOD_DEC_USE_COUNT; +#endif + PDEBUG(3, "Disconnect complete"); +} + +static struct usb_driver ov511_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20) + .owner = THIS_MODULE, +#endif + .name = "ov51x", +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + .id_table = device_table, +#endif + .probe = ov51x_probe, + .disconnect = ov51x_disconnect +}; + + + +module_init(usb_ov511_init); +module_exit(usb_ov511_exit); +#endif +#endif diff --git a/plugins/usb/USBqemu/usb-mic/adcuser.h b/plugins/usb/USBqemu/usb-mic/adcuser.h new file mode 100644 index 0000000000..6dfb92d440 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/adcuser.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: ADCUSER.H + * Purpose: Audio Device Class Custom User Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __ADCUSER_H__ +#define __ADCUSER_H__ + + +/* Audio Device Class Requests Callback Functions */ +extern BOOL ADC_IF_GetRequest (void); +extern BOOL ADC_IF_SetRequest (void); +extern BOOL ADC_EP_GetRequest (void); +extern BOOL ADC_EP_SetRequest (void); + + +#endif /* __ADCUSER_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/audio.h b/plugins/usb/USBqemu/usb-mic/audio.h new file mode 100644 index 0000000000..69083fe9b8 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/audio.h @@ -0,0 +1,372 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: AUDIO.H + * Purpose: USB Audio Device Class Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + + +/* Audio Interface Subclass Codes */ +#define AUDIO_SUBCLASS_UNDEFINED 0x00 +#define AUDIO_SUBCLASS_AUDIOCONTROL 0x01 +#define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02 +#define AUDIO_SUBCLASS_MIDISTREAMING 0x03 + +/* Audio Interface Protocol Codes */ +#define AUDIO_PROTOCOL_UNDEFINED 0x00 + + +/* Audio Descriptor Types */ +#define AUDIO_UNDEFINED_DESCRIPTOR_TYPE 0x20 +#define AUDIO_DEVICE_DESCRIPTOR_TYPE 0x21 +#define AUDIO_CONFIGURATION_DESCRIPTOR_TYPE 0x22 +#define AUDIO_STRING_DESCRIPTOR_TYPE 0x23 +#define AUDIO_INTERFACE_DESCRIPTOR_TYPE 0x24 +#define AUDIO_ENDPOINT_DESCRIPTOR_TYPE 0x25 + + +/* Audio Control Interface Descriptor Subtypes */ +#define AUDIO_CONTROL_UNDEFINED 0x00 +#define AUDIO_CONTROL_HEADER 0x01 +#define AUDIO_CONTROL_INPUT_TERMINAL 0x02 +#define AUDIO_CONTROL_OUTPUT_TERMINAL 0x03 +#define AUDIO_CONTROL_MIXER_UNIT 0x04 +#define AUDIO_CONTROL_SELECTOR_UNIT 0x05 +#define AUDIO_CONTROL_FEATURE_UNIT 0x06 +#define AUDIO_CONTROL_PROCESSING_UNIT 0x07 +#define AUDIO_CONTROL_EXTENSION_UNIT 0x08 + +/* Audio Streaming Interface Descriptor Subtypes */ +#define AUDIO_STREAMING_UNDEFINED 0x00 +#define AUDIO_STREAMING_GENERAL 0x01 +#define AUDIO_STREAMING_FORMAT_TYPE 0x02 +#define AUDIO_STREAMING_FORMAT_SPECIFIC 0x03 + +/* Audio Endpoint Descriptor Subtypes */ +#define AUDIO_ENDPOINT_UNDEFINED 0x00 +#define AUDIO_ENDPOINT_GENERAL 0x01 + + +/* Audio Descriptor Sizes */ +#define AUDIO_CONTROL_INTERFACE_DESC_SZ(n) 0x08+n +#define AUDIO_STREAMING_INTERFACE_DESC_SIZE 0x07 +#define AUDIO_INPUT_TERMINAL_DESC_SIZE 0x0C +#define AUDIO_OUTPUT_TERMINAL_DESC_SIZE 0x09 +#define AUDIO_MIXER_UNIT_DESC_SZ(p,n) 0x0A+p+n +#define AUDIO_SELECTOR_UNIT_DESC_SZ(p) 0x06+p +#define AUDIO_FEATURE_UNIT_DESC_SZ(ch,n) 0x07+(ch+1)*n +#define AUDIO_PROCESSING_UNIT_DESC_SZ(p,n,x) 0x0D+p+n+x +#define AUDIO_EXTENSION_UNIT_DESC_SZ(p,n) 0x0D+p+n +#define AUDIO_STANDARD_ENDPOINT_DESC_SIZE 0x09 +#define AUDIO_STREAMING_ENDPOINT_DESC_SIZE 0x07 + + +/* Audio Processing Unit Process Types */ +#define AUDIO_UNDEFINED_PROCESS 0x00 +#define AUDIO_UP_DOWN_MIX_PROCESS 0x01 +#define AUDIO_DOLBY_PROLOGIC_PROCESS 0x02 +#define AUDIO_3D_STEREO_PROCESS 0x03 +#define AUDIO_REVERBERATION_PROCESS 0x04 +#define AUDIO_CHORUS_PROCESS 0x05 +#define AUDIO_DYN_RANGE_COMP_PROCESS 0x06 + + +/* Audio Request Codes */ +#define AUDIO_REQUEST_UNDEFINED 0x00 +#define AUDIO_REQUEST_SET_CUR 0x01 +#define AUDIO_REQUEST_GET_CUR 0x81 +#define AUDIO_REQUEST_SET_MIN 0x02 +#define AUDIO_REQUEST_GET_MIN 0x82 +#define AUDIO_REQUEST_SET_MAX 0x03 +#define AUDIO_REQUEST_GET_MAX 0x83 +#define AUDIO_REQUEST_SET_RES 0x04 +#define AUDIO_REQUEST_GET_RES 0x84 +#define AUDIO_REQUEST_SET_MEM 0x05 +#define AUDIO_REQUEST_GET_MEM 0x85 +#define AUDIO_REQUEST_GET_STAT 0xFF + + +/* Audio Control Selector Codes */ +#define AUDIO_CONTROL_UNDEFINED 0x00 /* Common Selector */ + +/* Terminal Control Selectors */ +#define AUDIO_COPY_PROTECT_CONTROL 0x01 + +/* Feature Unit Control Selectors */ +#define AUDIO_MUTE_CONTROL 0x01 +#define AUDIO_VOLUME_CONTROL 0x02 +#define AUDIO_BASS_CONTROL 0x03 +#define AUDIO_MID_CONTROL 0x04 +#define AUDIO_TREBLE_CONTROL 0x05 +#define AUDIO_GRAPHIC_EQUALIZER_CONTROL 0x06 +#define AUDIO_AUTOMATIC_GAIN_CONTROL 0x07 +#define AUDIO_DELAY_CONTROL 0x08 +#define AUDIO_BASS_BOOST_CONTROL 0x09 +#define AUDIO_LOUDNESS_CONTROL 0x0A + +/* Processing Unit Control Selectors: */ +#define AUDIO_ENABLE_CONTROL 0x01 /* Common Selector */ +#define AUDIO_MODE_SELECT_CONTROL 0x02 /* Common Selector */ + +/* - Up/Down-mix Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +/* AUDIO_MODE_SELECT_CONTROL 0x02 Common Selector */ + +/* - Dolby Prologic Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +/* AUDIO_MODE_SELECT_CONTROL 0x02 Common Selector */ + +/* - 3D Stereo Extender Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +#define AUDIO_SPACIOUSNESS_CONTROL 0x02 + +/* - Reverberation Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +#define AUDIO_REVERB_LEVEL_CONTROL 0x02 +#define AUDIO_REVERB_TIME_CONTROL 0x03 +#define AUDIO_REVERB_FEEDBACK_CONTROL 0x04 + +/* - Chorus Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +#define AUDIO_CHORUS_LEVEL_CONTROL 0x02 +#define AUDIO_SHORUS_RATE_CONTROL 0x03 +#define AUDIO_CHORUS_DEPTH_CONTROL 0x04 + +/* - Dynamic Range Compressor Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ +#define AUDIO_COMPRESSION_RATE_CONTROL 0x02 +#define AUDIO_MAX_AMPL_CONTROL 0x03 +#define AUDIO_THRESHOLD_CONTROL 0x04 +#define AUDIO_ATTACK_TIME_CONTROL 0x05 +#define AUDIO_RELEASE_TIME_CONTROL 0x06 + +/* Extension Unit Control Selectors */ +/* AUDIO_ENABLE_CONTROL 0x01 Common Selector */ + +/* Endpoint Control Selectors */ +#define AUDIO_SAMPLING_FREQ_CONTROL 0x01 +#define AUDIO_PITCH_CONTROL 0x02 + + +/* Audio Format Specific Control Selectors */ + +/* MPEG Control Selectors */ +#define AUDIO_MPEG_CONTROL_UNDEFINED 0x00 +#define AUDIO_MPEG_DUAL_CHANNEL_CONTROL 0x01 +#define AUDIO_MPEG_SECOND_STEREO_CONTROL 0x02 +#define AUDIO_MPEG_MULTILINGUAL_CONTROL 0x03 +#define AUDIO_MPEG_DYN_RANGE_CONTROL 0x04 +#define AUDIO_MPEG_SCALING_CONTROL 0x05 +#define AUDIO_MPEG_HILO_SCALING_CONTROL 0x06 + +/* AC-3 Control Selectors */ +#define AUDIO_AC3_CONTROL_UNDEFINED 0x00 +#define AUDIO_AC3_MODE_CONTROL 0x01 +#define AUDIO_AC3_DYN_RANGE_CONTROL 0x02 +#define AUDIO_AC3_SCALING_CONTROL 0x03 +#define AUDIO_AC3_HILO_SCALING_CONTROL 0x04 + + +/* Audio Format Types */ +#define AUDIO_FORMAT_TYPE_UNDEFINED 0x00 +#define AUDIO_FORMAT_TYPE_I 0x01 +#define AUDIO_FORMAT_TYPE_II 0x02 +#define AUDIO_FORMAT_TYPE_III 0x03 + + +/* Audio Format Type Descriptor Sizes */ +#define AUDIO_FORMAT_TYPE_I_DESC_SZ(n) 0x08+(n*3) +#define AUDIO_FORMAT_TYPE_II_DESC_SZ(n) 0x09+(n*3) +#define AUDIO_FORMAT_TYPE_III_DESC_SZ(n) 0x08+(n*3) +#define AUDIO_FORMAT_MPEG_DESC_SIZE 0x09 +#define AUDIO_FORMAT_AC3_DESC_SIZE 0x0A + + +/* Audio Data Format Codes */ + +/* Audio Data Format Type I Codes */ +#define AUDIO_FORMAT_TYPE_I_UNDEFINED 0x0000 +#define AUDIO_FORMAT_PCM 0x0001 +#define AUDIO_FORMAT_PCM8 0x0002 +#define AUDIO_FORMAT_IEEE_FLOAT 0x0003 +#define AUDIO_FORMAT_ALAW 0x0004 +#define AUDIO_FORMAT_MULAW 0x0005 + +/* Audio Data Format Type II Codes */ +#define AUDIO_FORMAT_TYPE_II_UNDEFINED 0x1000 +#define AUDIO_FORMAT_MPEG 0x1001 +#define AUDIO_FORMAT_AC3 0x1002 + +/* Audio Data Format Type III Codes */ +#define AUDIO_FORMAT_TYPE_III_UNDEFINED 0x2000 +#define AUDIO_FORMAT_IEC1937_AC3 0x2001 +#define AUDIO_FORMAT_IEC1937_MPEG1_L1 0x2002 +#define AUDIO_FORMAT_IEC1937_MPEG1_L2_3 0x2003 +#define AUDIO_FORMAT_IEC1937_MPEG2_NOEXT 0x2003 +#define AUDIO_FORMAT_IEC1937_MPEG2_EXT 0x2004 +#define AUDIO_FORMAT_IEC1937_MPEG2_L1_LS 0x2005 +#define AUDIO_FORMAT_IEC1937_MPEG2_L2_3 0x2006 + + +/* Predefined Audio Channel Configuration Bits */ +#define AUDIO_CHANNEL_M 0x0000 /* Mono */ +#define AUDIO_CHANNEL_L 0x0001 /* Left Front */ +#define AUDIO_CHANNEL_R 0x0002 /* Right Front */ +#define AUDIO_CHANNEL_C 0x0004 /* Center Front */ +#define AUDIO_CHANNEL_LFE 0x0008 /* Low Freq. Enhance. */ +#define AUDIO_CHANNEL_LS 0x0010 /* Left Surround */ +#define AUDIO_CHANNEL_RS 0x0020 /* Right Surround */ +#define AUDIO_CHANNEL_LC 0x0040 /* Left of Center */ +#define AUDIO_CHANNEL_RC 0x0080 /* Right of Center */ +#define AUDIO_CHANNEL_S 0x0100 /* Surround */ +#define AUDIO_CHANNEL_SL 0x0200 /* Side Left */ +#define AUDIO_CHANNEL_SR 0x0400 /* Side Right */ +#define AUDIO_CHANNEL_T 0x0800 /* Top */ + + +/* Feature Unit Control Bits */ +#define AUDIO_CONTROL_MUTE 0x0001 +#define AUDIO_CONTROL_VOLUME 0x0002 +#define AUDIO_CONTROL_BASS 0x0004 +#define AUDIO_CONTROL_MID 0x0008 +#define AUDIO_CONTROL_TREBLE 0x0010 +#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020 +#define AUDIO_CONTROL_AUTOMATIC_GAIN 0x0040 +#define AUDIO_CONTROL_DEALY 0x0080 +#define AUDIO_CONTROL_BASS_BOOST 0x0100 +#define AUDIO_CONTROL_LOUDNESS 0x0200 + +/* Processing Unit Control Bits: */ +#define AUDIO_CONTROL_ENABLE 0x0001 /* Common Bit */ +#define AUDIO_CONTROL_MODE_SELECT 0x0002 /* Common Bit */ + +/* - Up/Down-mix Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +/* AUDIO_CONTROL_MODE_SELECT 0x0002 Common Bit */ + +/* - Dolby Prologic Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +/* AUDIO_CONTROL_MODE_SELECT 0x0002 Common Bit */ + +/* - 3D Stereo Extender Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +#define AUDIO_CONTROL_SPACIOUSNESS 0x0002 + +/* - Reverberation Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +#define AUDIO_CONTROL_REVERB_TYPE 0x0002 +#define AUDIO_CONTROL_REVERB_LEVEL 0x0004 +#define AUDIO_CONTROL_REVERB_TIME 0x0008 +#define AUDIO_CONTROL_REVERB_FEEDBACK 0x0010 + +/* - Chorus Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +#define AUDIO_CONTROL_CHORUS_LEVEL 0x0002 +#define AUDIO_CONTROL_SHORUS_RATE 0x0004 +#define AUDIO_CONTROL_CHORUS_DEPTH 0x0008 + +/* - Dynamic Range Compressor Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ +#define AUDIO_CONTROL_COMPRESSION_RATE 0x0002 +#define AUDIO_CONTROL_MAX_AMPL 0x0004 +#define AUDIO_CONTROL_THRESHOLD 0x0008 +#define AUDIO_CONTROL_ATTACK_TIME 0x0010 +#define AUDIO_CONTROL_RELEASE_TIME 0x0020 + +/* Extension Unit Control Bits */ +/* AUDIO_CONTROL_ENABLE 0x0001 Common Bit */ + +/* Endpoint Control Bits */ +#define AUDIO_CONTROL_SAMPLING_FREQ 0x01 +#define AUDIO_CONTROL_PITCH 0x02 +#define AUDIO_MAX_PACKETS_ONLY 0x80 + + +/* Audio Terminal Types */ + +/* USB Terminal Types */ +#define AUDIO_TERMINAL_USB_UNDEFINED 0x0100 +#define AUDIO_TERMINAL_USB_STREAMING 0x0101 +#define AUDIO_TERMINAL_USB_VENDOR_SPECIFIC 0x01FF + +/* Input Terminal Types */ +#define AUDIO_TERMINAL_INPUT_UNDEFINED 0x0200 +#define AUDIO_TERMINAL_MICROPHONE 0x0201 +#define AUDIO_TERMINAL_DESKTOP_MICROPHONE 0x0202 +#define AUDIO_TERMINAL_PERSONAL_MICROPHONE 0x0203 +#define AUDIO_TERMINAL_OMNI_DIR_MICROPHONE 0x0204 +#define AUDIO_TERMINAL_MICROPHONE_ARRAY 0x0205 +#define AUDIO_TERMINAL_PROCESSING_MIC_ARRAY 0x0206 + +/* Output Terminal Types */ +#define AUDIO_TERMINAL_OUTPUT_UNDEFINED 0x0300 +#define AUDIO_TERMINAL_SPEAKER 0x0301 +#define AUDIO_TERMINAL_HEADPHONES 0x0302 +#define AUDIO_TERMINAL_HEAD_MOUNTED_AUDIO 0x0303 +#define AUDIO_TERMINAL_DESKTOP_SPEAKER 0x0304 +#define AUDIO_TERMINAL_ROOM_SPEAKER 0x0305 +#define AUDIO_TERMINAL_COMMUNICATION_SPEAKER 0x0306 +#define AUDIO_TERMINAL_LOW_FREQ_SPEAKER 0x0307 + +/* Bi-directional Terminal Types */ +#define AUDIO_TERMINAL_BIDIRECTIONAL_UNDEFINED 0x0400 +#define AUDIO_TERMINAL_HANDSET 0x0401 +#define AUDIO_TERMINAL_HEAD_MOUNTED_HANDSET 0x0402 +#define AUDIO_TERMINAL_SPEAKERPHONE 0x0403 +#define AUDIO_TERMINAL_SPEAKERPHONE_ECHOSUPRESS 0x0404 +#define AUDIO_TERMINAL_SPEAKERPHONE_ECHOCANCEL 0x0405 + +/* Telephony Terminal Types */ +#define AUDIO_TERMINAL_TELEPHONY_UNDEFINED 0x0500 +#define AUDIO_TERMINAL_PHONE_LINE 0x0501 +#define AUDIO_TERMINAL_TELEPHONE 0x0502 +#define AUDIO_TERMINAL_DOWN_LINE_PHONE 0x0503 + +/* External Terminal Types */ +#define AUDIO_TERMINAL_EXTERNAL_UNDEFINED 0x0600 +#define AUDIO_TERMINAL_ANALOG_CONNECTOR 0x0601 +#define AUDIO_TERMINAL_DIGITAL_AUDIO_INTERFACE 0x0602 +#define AUDIO_TERMINAL_LINE_CONNECTOR 0x0603 +#define AUDIO_TERMINAL_LEGACY_AUDIO_CONNECTOR 0x0604 +#define AUDIO_TERMINAL_SPDIF_INTERFACE 0x0605 +#define AUDIO_TERMINAL_1394_DA_STREAM 0x0606 +#define AUDIO_TERMINAL_1394_DA_STREAM_TRACK 0x0607 + +/* Embedded Function Terminal Types */ +#define AUDIO_TERMINAL_EMBEDDED_UNDEFINED 0x0700 +#define AUDIO_TERMINAL_CALIBRATION_NOISE 0x0701 +#define AUDIO_TERMINAL_EQUALIZATION_NOISE 0x0702 +#define AUDIO_TERMINAL_CD_PLAYER 0x0703 +#define AUDIO_TERMINAL_DAT 0x0704 +#define AUDIO_TERMINAL_DCC 0x0705 +#define AUDIO_TERMINAL_MINI_DISK 0x0706 +#define AUDIO_TERMINAL_ANALOG_TAPE 0x0707 +#define AUDIO_TERMINAL_PHONOGRAPH 0x0708 +#define AUDIO_TERMINAL_VCR_AUDIO 0x0709 +#define AUDIO_TERMINAL_VIDEO_DISC_AUDIO 0x070A +#define AUDIO_TERMINAL_DVD_AUDIO 0x070B +#define AUDIO_TERMINAL_TV_TUNER_AUDIO 0x070C +#define AUDIO_TERMINAL_SATELLITE_RECEIVER_AUDIO 0x070D +#define AUDIO_TERMINAL_CABLE_TUNER_AUDIO 0x070E +#define AUDIO_TERMINAL_DSS_AUDIO 0x070F +#define AUDIO_TERMINAL_RADIO_RECEIVER 0x0710 +#define AUDIO_TERMINAL_RADIO_TRANSMITTER 0x0711 +#define AUDIO_TERMINAL_MULTI_TRACK_RECORDER 0x0712 +#define AUDIO_TERMINAL_SYNTHESIZER 0x0713 + + +#endif /* __AUDIO_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/demo.h b/plugins/usb/USBqemu/usb-mic/demo.h new file mode 100644 index 0000000000..f9293a49b2 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/demo.h @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------- + * Name: DEMO.H + * Purpose: USB Audio Demo Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +/* Clock Definitions */ +#define CPU_CLOCK 60000000 /* CPU Clock */ +#define VPB_CLOCK (CPU_CLOCK/1) /* VPB Clock */ + +/* Audio Definitions */ +#define DATA_FREQ 32000 /* Audio Data Frequency */ +#define P_S 32 /* Packet Size */ +#if USB_DMA +#define P_C 4 /* Packet Count */ +#else +#define P_C 1 /* Packet Count */ +#endif +#define B_S (8*P_C*P_S) /* Buffer Size */ + +/* Push Button Definitions */ +#define PBINT 0x00004000 /* P0.14 */ + +/* LED Definitions */ +#define LEDMSK 0x00FF0000 /* P1.16..23 */ + +/* Audio Demo Variables */ +extern BYTE Mute; /* Mute State */ +extern DWORD Volume; /* Volume Level */ +extern WORD VolCur; /* Volume Current Value */ +extern DWORD InfoBuf[P_C]; /* Packet Info Buffer */ +extern short DataBuf[B_S]; /* Data Buffer */ +extern WORD DataOut; /* Data Out Index */ +extern WORD DataIn; /* Data In Index */ +extern BYTE DataRun; /* Data Stream Run State */ diff --git a/plugins/usb/USBqemu/usb-mic/type.h b/plugins/usb/USBqemu/usb-mic/type.h new file mode 100644 index 0000000000..4e6e17afcc --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/type.h @@ -0,0 +1,22 @@ + +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +//typedef unsigned int BOOL; + +#endif /* __TYPE_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usb-mic-dummy.cpp b/plugins/usb/USBqemu/usb-mic/usb-mic-dummy.cpp new file mode 100644 index 0000000000..5c95ebfdfd --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usb-mic-dummy.cpp @@ -0,0 +1,431 @@ +/* + * QEMU USB HID devices + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../qemu-usb/vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +#define USB_MOUSE 1 +#define USB_TABLET 2 + +#include "type.h" + +#include "usb.h" +#include "audio.h" +#include "usbcfg.h" +#include "usbdesc.h" + +typedef struct SINGSTARMICState { + USBDevice dev; + //nothing yet +} SINGSTARMICState; + +/* descriptor dumped from a real singstar MIC adapter */ +static const uint8_t singstar_mic_dev_descriptor[] = { + /* bLength */ 0x12, //(18) + /* bDescriptorType */ 0x01, //(1) + /* bcdUSB */ WBVAL(0x0110), //(272) + /* bDeviceClass */ 0x00, //(0) + /* bDeviceSubClass */ 0x00, //(0) + /* bDeviceProtocol */ 0x00, //(0) + /* bMaxPacketSize0 */ 0x08, //(8) + /* idVendor */ WBVAL(0x1415), //(5141) + /* idProduct */ WBVAL(0x0000), //(0) + /* bcdDevice */ WBVAL(0x0001), //(1) + /* iManufacturer */ 0x01, //(1) + /* iProduct */ 0x02, //(2) + /* iSerialNumber */ 0x00, //(0) + /* bNumConfigurations */ 0x01, //(1) + +}; + +static const uint8_t singstar_mic_config_descriptor[] = { + +/* Configuration 1 */ + 0x09, /* bLength */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ + WBVAL(0x00b1), /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + USB_CONFIG_BUS_POWERED, /* bmAttributes */ + USB_CONFIG_POWER_MA(90), /* bMaxPower */ + +/* Interface 0, Alternate Setting 0, Audio Control */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +/* Audio Control Interface */ + AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ + WBVAL(0x0100), /* 1.00 */ /* bcdADC */ + WBVAL(0x0028), /* wTotalLength */ + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr */ + +/* Audio Input Terminal */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x01, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */ + 0x02, /* bAssocTerminal */ + 0x02, /* bNrChannels */ + WBVAL(AUDIO_CHANNEL_L + |AUDIO_CHANNEL_R), /* wChannelConfig */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ + +/* Audio Output Terminal */ + AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ + 0x01, /* bAssocTerminal */ + 0x03, /* bSourceID */ + 0x00, /* iTerminal */ + +/* Audio Feature Unit */ + AUDIO_FEATURE_UNIT_DESC_SZ(2,1), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x03, /* bUnitID */ + 0x01, /* bSourceID */ + 0x01, /* bControlSize */ + 0x01, /* bmaControls(0) */ + 0x02, /* bmaControls(1) */ + 0x02, /* bmaControls(2) */ + 0x00, /* iTerminal */ + +/* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +/* Interface 1, Alternate Setting 1, Audio Streaming - Operational */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +/* Audio Streaming Interface */ + AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + +/* Audio Type I Format */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x01, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ + +/* Endpoint - Standard Descriptor */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_OUT(0x81), /* bEndpointAddress */ + USB_ENDPOINT_TYPE_ISOCHRONOUS + | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */ + WBVAL(0x0064), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ + +/* Endpoint - Audio Streaming */ + AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ + +/* Interface 1, Alternate Setting 2, Audio Streaming - ? */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x02, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +/* Audio Streaming Interface */ + AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + +/* Audio Type I Format */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x02, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ + +/* Endpoint - Standard Descriptor */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_OUT(0x81), /* bEndpointAddress */ + USB_ENDPOINT_TYPE_ISOCHRONOUS + | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */ + WBVAL(0x00c8), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ + +/* Endpoint - Audio Streaming */ + AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ + +/* Terminator */ + 0 /* bLength */ +}; + + +static void singstar_mic_handle_reset(USBDevice *dev) +{ + /* XXX: do it */ + return; +} + +static int singstar_mic_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + SINGSTARMICState *s = (SINGSTARMICState *)dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, singstar_mic_dev_descriptor, + sizeof(singstar_mic_dev_descriptor)); + ret = sizeof(singstar_mic_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, singstar_mic_config_descriptor, + sizeof(singstar_mic_config_descriptor)); + ret = sizeof(singstar_mic_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "3X0420811"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "EyeToy USB camera Namtai"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + //switch(value >> 8) { + //((case 0x22: + // memcpy(data, qemu_mouse_hid_report_descriptor, + // sizeof(qemu_mouse_hid_report_descriptor)); + // ret = sizeof(qemu_mouse_hid_report_descriptor); + // break; + //default: + goto fail; + //} + break; + case GET_REPORT: + ret = 0; + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int singstar_mic_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + SINGSTARMICState *s = (SINGSTARMICState *)dev; + int ret = 0; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + + +static void singstar_mic_handle_destroy(USBDevice *dev) +{ + SINGSTARMICState *s = (SINGSTARMICState *)dev; + + free(s); +} + +int singstar_mic_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + fprintf(stderr,"usb-singstar_mic: packet received with pid=%x, devaddr=%x, devep=%x and len=%x\n",pid,devaddr,devep,len); + return usb_generic_handle_packet(s,pid,devaddr,devep,data,len); +} + +USBDevice *singstar_mic_init() +{ + SINGSTARMICState *s; + + s = (SINGSTARMICState *)qemu_mallocz(sizeof(SINGSTARMICState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = singstar_mic_handle_packet; + s->dev.handle_reset = singstar_mic_handle_reset; + s->dev.handle_control = singstar_mic_handle_control; + s->dev.handle_data = singstar_mic_handle_data; + s->dev.handle_destroy = singstar_mic_handle_destroy; + + strncpy(s->dev.devname, "EyeToy USB camera Namtai", sizeof(s->dev.devname)); + + return (USBDevice *)s; + +} diff --git a/plugins/usb/USBqemu/usb-mic/usb-mic.c b/plugins/usb/USBqemu/usb-mic/usb-mic.c new file mode 100644 index 0000000000..80c69815c0 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usb-mic.c @@ -0,0 +1,626 @@ +/* + * QEMU USB HID devices + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +#define USB_MOUSE 1 +#define USB_TABLET 2 + +#include "type.h" + +#include "usb.h" +#include "audio.h" +#include "usbcfg.h" +#include "usbdesc.h" + +/* mostly the same values as the Bochs USB Mouse device */ +static const uint8_t qemu_mic_dev_descriptor[] = { + sizeof(qemu_mic_dev_descriptor), /* bLength */ + 1, /* bDescriptorType */ + WBVAL(0x0110), /* 1.10 */ /* bcdUSB */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + USB_MAX_PACKET0, /* bMaxPacketSize0 */ + WBVAL(0xC251), /* idVendor */ + WBVAL(0x1304), /* idProduct */ + WBVAL(0x0100), /* 1.00 */ /* bcdDevice */ + 0x04, /* iManufacturer */ + 0x20, /* iProduct */ + 0x4A, /* iSerialNumber */ + 0x01 /* bNumConfigurations */ +}; + +static const uint8_t qemu_mic_config_descriptor[] = { +/* Configuration 1 */ + sizeof(qemu_mic_config_descriptor), /* bLength */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ + WBVAL( /* wTotalLength */ + USB_CONFIGUARTION_DESC_SIZE + + USB_INTERFACE_DESC_SIZE + + AUDIO_CONTROL_INTERFACE_DESC_SZ(1) + + AUDIO_INPUT_TERMINAL_DESC_SIZE + + AUDIO_FEATURE_UNIT_DESC_SZ(1,1) + + AUDIO_OUTPUT_TERMINAL_DESC_SIZE + + USB_INTERFACE_DESC_SIZE + + USB_INTERFACE_DESC_SIZE + + AUDIO_STREAMING_INTERFACE_DESC_SIZE + + AUDIO_FORMAT_TYPE_I_DESC_SZ(1) + + AUDIO_STANDARD_ENDPOINT_DESC_SIZE + + AUDIO_STREAMING_ENDPOINT_DESC_SIZE + ), + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + USB_CONFIG_BUS_POWERED, /* bmAttributes */ + USB_CONFIG_POWER_MA(100), /* bMaxPower */ +/* Interface 0, Alternate Setting 0, Audio Control */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ +/* Audio Control Interface */ + AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ + WBVAL(0x0100), /* 1.00 */ /* bcdADC */ + WBVAL( /* wTotalLength */ + AUDIO_CONTROL_INTERFACE_DESC_SZ(1) + + AUDIO_INPUT_TERMINAL_DESC_SIZE + + AUDIO_FEATURE_UNIT_DESC_SZ(1,1) + + AUDIO_OUTPUT_TERMINAL_DESC_SIZE + ), + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr */ +/* Audio Input Terminal */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x01, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ + 0x00, /* bAssocTerminal */ + 0x01, /* bNrChannels */ + WBVAL(AUDIO_CHANNEL_M), /* wChannelConfig */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ +/* Audio Feature Unit */ + AUDIO_FEATURE_UNIT_DESC_SZ(1,1), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x02, /* bUnitID */ + 0x01, /* bSourceID */ + 0x01, /* bControlSize */ + AUDIO_CONTROL_MUTE | + AUDIO_CONTROL_VOLUME, /* bmaControls(0) */ + 0x00, /* bmaControls(1) */ + 0x00, /* iTerminal */ +/* Audio Output Terminal */ + AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ + 0x03, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_SPEAKER), /* wTerminalType */ + 0x00, /* bAssocTerminal */ + 0x02, /* bSourceID */ + 0x00, /* iTerminal */ +/* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ +/* Interface 1, Alternate Setting 1, Audio Streaming - Operational */ + USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ +/* Audio Streaming Interface */ + AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x01, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ +/* Audio Type I Format */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(1), /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x01, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 16, /* bBitResolution */ + 0x01, /* bSamFreqType */ + B3VAL(32000), /* tSamFreq */ +/* Endpoint - Standard Descriptor */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_OUT(3), /* bEndpointAddress */ + USB_ENDPOINT_TYPE_ISOCHRONOUS, /* bmAttributes */ + WBVAL(64), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ +/* Endpoint - Audio Streaming */ + AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x00, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ +/* Terminator */ + 0 /* bLength */ +}; + +static const uint8_t qemu_tablet_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 74, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_mouse_hid_report_descriptor[] = { + 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, + 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, + 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, + 0xC0, 0xC0, +}; + +static const uint8_t qemu_tablet_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x01, /* Usage Mouse */ + 0xA1, 0x01, /* Collection Application */ + 0x09, 0x01, /* Usage Pointer */ + 0xA1, 0x00, /* Collection Physical */ + 0x05, 0x09, /* Usage Page Button */ + 0x19, 0x01, /* Usage Minimum Button 1 */ + 0x29, 0x03, /* Usage Maximum Button 3 */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x25, 0x01, /* Logical Maximum 1 */ + 0x95, 0x03, /* Report Count 3 */ + 0x75, 0x01, /* Report Size 1 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x01, /* Report Count 1 */ + 0x75, 0x05, /* Report Size 5 */ + 0x81, 0x01, /* Input (Cnst, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x30, /* Usage X */ + 0x09, 0x31, /* Usage Y */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */ + 0x35, 0x00, /* Physical Minimum 0 */ + 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */ + 0x75, 0x10, /* Report Size 16 */ + 0x95, 0x02, /* Report Count 2 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x38, /* Usage Wheel */ + 0x15, 0x81, /* Logical Minimum -127 */ + 0x25, 0x7F, /* Logical Maximum 127 */ + 0x35, 0x00, /* Physical Minimum 0 (same as logical) */ + 0x45, 0x00, /* Physical Maximum 0 (same as logical) */ + 0x75, 0x08, /* Report Size 8 */ + 0x95, 0x01, /* Report Count 1 */ + 0x81, 0x02, /* Input (Data, Var, Rel) */ + 0xC0, /* End Collection */ + 0xC0, /* End Collection */ +}; + +static void usb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + USBMouseState *s = opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + +static void usb_tablet_event(void *opaque, + int x, int y, int dz, int buttons_state) +{ + USBMouseState *s = opaque; + + s->x = x; + s->y = y; + s->dz += dz; + s->buttons_state = buttons_state; +} + +static inline int int_clamp(int val, int vmin, int vmax) +{ + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; +} + +static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dx, dy, dz, b, l; + + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_mouse_event, s, 0); + s->mouse_grabbed = 1; + } + + dx = int_clamp(s->dx, -128, 127); + dy = int_clamp(s->dy, -128, 127); + dz = int_clamp(s->dz, -128, 127); + + s->dx -= dx; + s->dy -= dy; + s->dz -= dz; + + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = dx; + buf[2] = dy; + l = 3; + if (len >= 4) { + buf[3] = dz; + l = 4; + } + return l; +} + +static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dz, b, l; + + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_tablet_event, s, 1); + s->mouse_grabbed = 1; + } + + dz = int_clamp(s->dz, -128, 127); + s->dz -= dz; + + /* Appears we have to invert the wheel direction */ + dz = 0 - dz; + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = s->x & 0xff; + buf[2] = s->x >> 8; + buf[3] = s->y & 0xff; + buf[4] = s->y >> 8; + buf[5] = dz; + l = 6; + + return l; +} + +static void usb_mouse_handle_reset(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + s->dx = 0; + s->dy = 0; + s->dz = 0; + s->x = 0; + s->y = 0; + s->buttons_state = 0; +} + +static int usb_mouse_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_mouse_dev_descriptor, + sizeof(qemu_mouse_dev_descriptor)); + ret = sizeof(qemu_mouse_dev_descriptor); + break; + case USB_DT_CONFIG: + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_config_descriptor, + sizeof(qemu_mouse_config_descriptor)); + ret = sizeof(qemu_mouse_config_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_config_descriptor, + sizeof(qemu_tablet_config_descriptor)); + ret = sizeof(qemu_tablet_config_descriptor); + } + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + case 2: + /* product description */ + if (s->kind == USB_MOUSE) + ret = set_usb_string(data, "QEMU USB Mouse"); + else if (s->kind == USB_TABLET) + ret = set_usb_string(data, "QEMU USB Tablet"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "PCSX2/QEMU"); + break; + case 4: + ret = set_usb_string(data, "HID Mouse"); + break; + case 5: + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case 0x22: + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_hid_report_descriptor, + sizeof(qemu_mouse_hid_report_descriptor)); + ret = sizeof(qemu_mouse_hid_report_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_hid_report_descriptor, + sizeof(qemu_tablet_hid_report_descriptor)); + ret = sizeof(qemu_tablet_hid_report_descriptor); + } + break; + default: + goto fail; + } + break; + case GET_REPORT: + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, length); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, length); + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_mouse_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret = 0; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, len); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, len); + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static void usb_mouse_handle_destroy(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + qemu_add_mouse_event_handler(NULL, NULL, 0); + free(s); +} + +USBDevice *usb_tablet_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_TABLET; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + + return (USBDevice *)s; +} + +USBDevice *usb_mouse_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_MOUSE; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + + return (USBDevice *)s; +} diff --git a/plugins/usb/USBqemu/usb-mic/usb.h b/plugins/usb/USBqemu/usb-mic/usb.h new file mode 100644 index 0000000000..727a14c696 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usb.h @@ -0,0 +1,230 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USB.H + * Purpose: USB Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USB_H__ +#define __USB_H__ + + +#pragma pack(1) + + +typedef union { + WORD W; + struct { + BYTE L; + BYTE H; + } WB; +} WORD_BYTE; + + +/* bmRequestType.Dir */ +#define REQUEST_HOST_TO_DEVICE 0 +#define REQUEST_DEVICE_TO_HOST 1 + +/* bmRequestType.Type */ +#define REQUEST_STANDARD 0 +#define REQUEST_CLASS 1 +#define REQUEST_VENDOR 2 +#define REQUEST_RESERVED 3 + +/* bmRequestType.Recipient */ +#define REQUEST_TO_DEVICE 0 +#define REQUEST_TO_INTERFACE 1 +#define REQUEST_TO_ENDPOINT 2 +#define REQUEST_TO_OTHER 3 + +/* bmRequestType Definition */ +typedef union _REQUEST_TYPE { + struct _BM { + BYTE Recipient : 5; + BYTE Type : 2; + BYTE Dir : 1; + } BM; + BYTE B; +} REQUEST_TYPE; + +/* USB Standard Request Codes */ +#define USB_REQUEST_GET_STATUS 0 +#define USB_REQUEST_CLEAR_FEATURE 1 +#define USB_REQUEST_SET_FEATURE 3 +#define USB_REQUEST_SET_ADDRESS 5 +#define USB_REQUEST_GET_DESCRIPTOR 6 +#define USB_REQUEST_SET_DESCRIPTOR 7 +#define USB_REQUEST_GET_CONFIGURATION 8 +#define USB_REQUEST_SET_CONFIGURATION 9 +#define USB_REQUEST_GET_INTERFACE 10 +#define USB_REQUEST_SET_INTERFACE 11 +#define USB_REQUEST_SYNC_FRAME 12 + +/* USB GET_STATUS Bit Values */ +#define USB_GETSTATUS_SELF_POWERED 0x01 +#define USB_GETSTATUS_REMOTE_WAKEUP 0x02 +#define USB_GETSTATUS_ENDPOINT_STALL 0x01 + +/* USB Standard Feature selectors */ +#define USB_FEATURE_ENDPOINT_STALL 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 + +/* USB Default Control Pipe Setup Packet */ +typedef struct _USB_SETUP_PACKET { + REQUEST_TYPE bmRequestType; + BYTE bRequest; + WORD_BYTE wValue; + WORD_BYTE wIndex; + WORD wLength; +} USB_SETUP_PACKET; + + +/* USB Descriptor Types */ +#define USB_DEVICE_DESCRIPTOR_TYPE 1 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 +#define USB_STRING_DESCRIPTOR_TYPE 3 +#define USB_INTERFACE_DESCRIPTOR_TYPE 4 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 +#define USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE 6 +#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE 7 +#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 8 + +/* USB Device Classes */ +#define USB_DEVICE_CLASS_RESERVED 0x00 +#define USB_DEVICE_CLASS_AUDIO 0x01 +#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 +#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 +#define USB_DEVICE_CLASS_MONITOR 0x04 +#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05 +#define USB_DEVICE_CLASS_POWER 0x06 +#define USB_DEVICE_CLASS_PRINTER 0x07 +#define USB_DEVICE_CLASS_STORAGE 0x08 +#define USB_DEVICE_CLASS_HUB 0x09 +#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF + +/* bmAttributes in Configuration Descriptor */ +#define USB_CONFIG_POWERED_MASK 0xC0 +#define USB_CONFIG_BUS_POWERED 0x80 +#define USB_CONFIG_SELF_POWERED 0x40 +#define USB_CONFIG_REMOTE_WAKEUP 0x20 + +/* bMaxPower in Configuration Descriptor */ +#define USB_CONFIG_POWER_MA(mA) ((mA)/2) + +/* bEndpointAddress in Endpoint Descriptor */ +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) + +/* bmAttributes in Endpoint Descriptor */ +#define USB_ENDPOINT_TYPE_MASK 0x03 +#define USB_ENDPOINT_TYPE_CONTROL 0x00 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_TYPE_BULK 0x02 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 +#define USB_ENDPOINT_SYNC_MASK 0x0C +#define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION 0x00 +#define USB_ENDPOINT_SYNC_ASYNCHRONOUS 0x04 +#define USB_ENDPOINT_SYNC_ADAPTIVE 0x08 +#define USB_ENDPOINT_SYNC_SYNCHRONOUS 0x0C +#define USB_ENDPOINT_USAGE_MASK 0x30 +#define USB_ENDPOINT_USAGE_DATA 0x00 +#define USB_ENDPOINT_USAGE_FEEDBACK 0x10 +#define USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK 0x20 +#define USB_ENDPOINT_USAGE_RESERVED 0x30 + +/* USB Standard Device Descriptor */ +typedef struct _USB_DEVICE_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + WORD bcdUSB; + BYTE bDeviceClass; + BYTE bDeviceSubClass; + BYTE bDeviceProtocol; + BYTE bMaxPacketSize0; + WORD idVendor; + WORD idProduct; + WORD bcdDevice; + BYTE iManufacturer; + BYTE iProduct; + BYTE iSerialNumber; + BYTE bNumConfigurations; +} USB_DEVICE_DESCRIPTOR; + +/* USB 2.0 Device Qualifier Descriptor */ +typedef struct _USB_DEVICE_QUALIFIER_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + WORD bcdUSB; + BYTE bDeviceClass; + BYTE bDeviceSubClass; + BYTE bDeviceProtocol; + BYTE bMaxPacketSize0; + BYTE bNumConfigurations; + BYTE bReserved; +} USB_DEVICE_QUALIFIER_DESCRIPTOR; + +/* USB Standard Configuration Descriptor */ +typedef struct _USB_CONFIGURATION_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + WORD wTotalLength; + BYTE bNumInterfaces; + BYTE bConfigurationValue; + BYTE iConfiguration; + BYTE bmAttributes; + BYTE MaxPower; +} USB_CONFIGURATION_DESCRIPTOR; + +/* USB Standard Interface Descriptor */ +typedef struct _USB_INTERFACE_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + BYTE bInterfaceNumber; + BYTE bAlternateSetting; + BYTE bNumEndpoints; + BYTE bInterfaceClass; + BYTE bInterfaceSubClass; + BYTE bInterfaceProtocol; + BYTE iInterface; +} USB_INTERFACE_DESCRIPTOR; + +/* USB Standard Endpoint Descriptor */ +typedef struct _USB_ENDPOINT_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + BYTE bEndpointAddress; + BYTE bmAttributes; + WORD wMaxPacketSize; + BYTE bInterval; +} USB_ENDPOINT_DESCRIPTOR; + +/* USB String Descriptor */ +typedef struct _USB_STRING_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; + WORD bString/*[]*/; +} USB_STRING_DESCRIPTOR; + +/* USB Common Descriptor */ +typedef struct _USB_COMMON_DESCRIPTOR { + BYTE bLength; + BYTE bDescriptorType; +} USB_COMMON_DESCRIPTOR; + + +#pragma pack() + + +#endif /* __USB_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usbcfg.h b/plugins/usb/USBqemu/usb-mic/usbcfg.h new file mode 100644 index 0000000000..fb425bcc0d --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbcfg.h @@ -0,0 +1,161 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USBCFG.H + * Purpose: USB Custom Configuration + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USBCFG_H__ +#define __USBCFG_H__ + + +/* +//*** <<< Use Configuration Wizard in Context Menu >>> *** +*/ + + +/* +// USB Configuration +// USB Power +// Default Power Setting +// <0=> Bus-powered +// <1=> Self-powered +// Max Number of Interfaces <1-256> +// Max Number of Endpoints <1-32> +// Max Endpoint 0 Packet Size +// <8=> 8 Bytes <16=> 16 Bytes <32=> 32 Bytes <64=> 64 Bytes +// DMA Transfer +// Use DMA for selected Endpoints +// Endpoint 0 Out +// Endpoint 0 In +// Endpoint 1 Out +// Endpoint 1 In +// Endpoint 2 Out +// Endpoint 2 In +// Endpoint 3 Out +// Endpoint 3 In +// Endpoint 4 Out +// Endpoint 4 In +// Endpoint 5 Out +// Endpoint 5 In +// Endpoint 6 Out +// Endpoint 6 In +// Endpoint 7 Out +// Endpoint 7 In +// Endpoint 8 Out +// Endpoint 8 In +// Endpoint 9 Out +// Endpoint 9 In +// Endpoint 10 Out +// Endpoint 10 In +// Endpoint 11 Out +// Endpoint 11 In +// Endpoint 12 Out +// Endpoint 12 In +// Endpoint 13 Out +// Endpoint 13 In +// Endpoint 14 Out +// Endpoint 14 In +// Endpoint 15 Out +// Endpoint 15 In +// +// +*/ + +#define USB_POWER 0 +#define USB_IF_NUM 4 +#define USB_EP_NUM 32 +#define USB_MAX_PACKET0 64 +#define USB_DMA 0 +#define USB_DMA_EP 0x00000040 + + +/* +// USB Event Handlers +// Device Events +// Power Event +// Reset Event +// Suspend Event +// Resume Event +// Remote Wakeup Event +// Start of Frame Event +// Error Event +// +// Endpoint Events +// Endpoint 0 Event +// Endpoint 1 Event +// Endpoint 2 Event +// Endpoint 3 Event +// Endpoint 4 Event +// Endpoint 5 Event +// Endpoint 6 Event +// Endpoint 7 Event +// Endpoint 8 Event +// Endpoint 9 Event +// Endpoint 10 Event +// Endpoint 11 Event +// Endpoint 12 Event +// Endpoint 13 Event +// Endpoint 14 Event +// Endpoint 15 Event +// +// USB Core Events +// Set Configuration Event +// Set Interface Event +// Set/Clear Feature Event +// +// +*/ + +#define USB_POWER_EVENT 0 +#define USB_RESET_EVENT 1 +#define USB_SUSPEND_EVENT 0 +#define USB_RESUME_EVENT 0 +#define USB_WAKEUP_EVENT 0 +#define USB_SOF_EVENT 1 +#define USB_ERROR_EVENT 0 +#define USB_EP_EVENT 0x0009 +#define USB_CONFIGURE_EVENT 0 +#define USB_INTERFACE_EVENT 0 +#define USB_FEATURE_EVENT 0 + + +/* +// USB Class Support +// Human Interface Device (HID) +// Interface Number <0-255> +// +// Mass Storage +// Interface Number <0-255> +// +// Audio Device +// Control Interface Number <0-255> +// Streaming Interface 1 Number <0-255> +// Streaming Interface 2 Number <0-255> +// +// +*/ + +#define USB_CLASS 1 +#define USB_HID 0 +#define USB_HID_IF_NUM 0 +#define USB_MSC 0 +#define USB_MSC_IF_NUM 0 +#define USB_AUDIO 1 +#define USB_ADC_CIF_NUM 0 +#define USB_ADC_SIF1_NUM 1 +#define USB_ADC_SIF2_NUM 2 + + +#endif /* __USBCFG_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usbcore.h b/plugins/usb/USBqemu/usb-mic/usbcore.h new file mode 100644 index 0000000000..980afdfe16 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbcore.h @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USBCORE.H + * Purpose: USB Core Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USBCORE_H__ +#define __USBCORE_H__ + + +/* USB Endpoint Data Structure */ +typedef struct _USB_EP_DATA { + BYTE *pData; + WORD Count; +} USB_EP_DATA; + +/* USB Core Global Variables */ +extern WORD USB_DeviceStatus; +extern BYTE USB_DeviceAddress; +extern BYTE USB_Configuration; +extern DWORD USB_EndPointMask; +extern DWORD USB_EndPointHalt; +extern BYTE USB_AltSetting[USB_IF_NUM]; + +/* USB Endpoint 0 Buffer */ +extern BYTE EP0Buf[USB_MAX_PACKET0]; + +/* USB Endpoint 0 Data Info */ +extern USB_EP_DATA EP0Data; + +/* USB Setup Packet */ +extern USB_SETUP_PACKET SetupPacket; + +/* USB Core Functions */ +extern void USB_ResetCore (void); + + +#endif /* __USBCORE_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usbdesc.h b/plugins/usb/USBqemu/usb-mic/usbdesc.h new file mode 100644 index 0000000000..a896e86d2b --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbdesc.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USBDESC.C + * Purpose: USB Descriptors Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USBDESC_H__ +#define __USBDESC_H__ + + +#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF) +#define B3VAL(x) (x & 0xFF),((x >> 8) & 0xFF),((x >> 16) & 0xFF) + +#define USB_DEVICE_DESC_SIZE (sizeof(USB_DEVICE_DESCRIPTOR)) +#define USB_CONFIGUARTION_DESC_SIZE (sizeof(USB_CONFIGURATION_DESCRIPTOR)) +#define USB_INTERFACE_DESC_SIZE (sizeof(USB_INTERFACE_DESCRIPTOR)) +#define USB_ENDPOINT_DESC_SIZE (sizeof(USB_ENDPOINT_DESCRIPTOR)) + +extern const BYTE USB_DeviceDescriptor[]; +extern const BYTE USB_ConfigDescriptor[]; +extern const BYTE USB_StringDescriptor[]; + + +#endif /* __USBDESC_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usbhw.h b/plugins/usb/USBqemu/usb-mic/usbhw.h new file mode 100644 index 0000000000..e2a3aa9cf4 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbhw.h @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USBHW.H + * Purpose: USB Hardware Layer Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USBHW_H__ +#define __USBHW_H__ + + +/* USB RAM Definitions */ +#define USB_RAM_ADR 0x7FD00000 /* USB RAM Start Address */ +#define USB_RAM_SZ 0x00002000 /* USB RAM Size (8kB) */ + +/* DMA Endpoint Descriptors */ +#define DD_NISO_CNT 16 /* Non-Iso EP DMA Descr. Count (max. 32) */ +#define DD_ISO_CNT 8 /* Iso EP DMA Descriptor Count (max. 32) */ +#define DD_NISO_SZ (DD_NISO_CNT * 16) /* Non-Iso DMA Descr. Size */ +#define DD_ISO_SZ (DD_ISO_CNT * 20) /* Iso DMA Descriptor Size */ +#define DD_NISO_ADR (USB_RAM_ADR + 128) /* Non-Iso DMA Descr. Address */ +#define DD_ISO_ADR (DD_NISO_ADR + DD_NISO_SZ) /* Iso DMA Descr. Address */ +#define DD_SZ (128 + DD_NISO_SZ + DD_ISO_SZ) /* Descr. Size */ + +/* DMA Buffer Memory Definitions */ +#define DMA_BUF_ADR (USB_RAM_ADR + DD_SZ) /* DMA Buffer Start Address */ +#define DMA_BUF_SZ (USB_RAM_SZ - DD_SZ) /* DMA Buffer Size */ + +/* USB Error Codes */ +#define USB_ERR_PID 0x0001 /* PID Error */ +#define USB_ERR_UEPKT 0x0002 /* Unexpected Packet */ +#define USB_ERR_DCRC 0x0004 /* Data CRC Error */ +#define USB_ERR_TIMOUT 0x0008 /* Bus Time-out Error */ +#define USB_ERR_EOP 0x0010 /* End of Packet Error */ +#define USB_ERR_B_OVRN 0x0020 /* Buffer Overrun */ +#define USB_ERR_BTSTF 0x0040 /* Bit Stuff Error */ +#define USB_ERR_TGL 0x0080 /* Toggle Bit Error */ + +/* USB DMA Status Codes */ +#define USB_DMA_INVALID 0x0000 /* DMA Invalid - Not Configured */ +#define USB_DMA_IDLE 0x0001 /* DMA Idle - Waiting for Trigger */ +#define USB_DMA_BUSY 0x0002 /* DMA Busy - Transfer in progress */ +#define USB_DMA_DONE 0x0003 /* DMA Transfer Done (no Errors)*/ +#define USB_DMA_OVER_RUN 0x0004 /* Data Over Run */ +#define USB_DMA_UNDER_RUN 0x0005 /* Data Under Run (Short Packet) */ +#define USB_DMA_ERROR 0x0006 /* Error */ +#define USB_DMA_UNKNOWN 0xFFFF /* Unknown State */ + +/* USB DMA Descriptor */ +typedef struct _USB_DMA_DESCRIPTOR { + DWORD BufAdr; /* DMA Buffer Address */ + WORD BufLen; /* DMA Buffer Length */ + WORD MaxSize; /* Maximum Packet Size */ + DWORD InfoAdr; /* Packet Info Memory Address */ + union { /* DMA Configuration */ + struct { + DWORD Link : 1; /* Link to existing Descriptors */ + DWORD IsoEP : 1; /* Isonchronous Endpoint */ + DWORD ATLE : 1; /* ATLE (Auto Transfer Length Extract) */ + DWORD Rsrvd : 5; /* Reserved */ + DWORD LenPos : 8; /* Length Position (ATLE) */ + } Type; + DWORD Val; + } Cfg; +} USB_DMA_DESCRIPTOR; + +/* USB Hardware Functions */ +extern void USB_Init (void); +extern void USB_Connect (BOOL con); +extern void USB_Reset (void); +extern void USB_Suspend (void); +extern void USB_Resume (void); +extern void USB_WakeUp (void); +extern void USB_WakeUpCfg (BOOL cfg); +extern void USB_SetAddress (DWORD adr); +extern void USB_Configure (BOOL cfg); +extern void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD); +extern void USB_DirCtrlEP (DWORD dir); +extern void USB_EnableEP (DWORD EPNum); +extern void USB_DisableEP (DWORD EPNum); +extern void USB_ResetEP (DWORD EPNum); +extern void USB_SetStallEP (DWORD EPNum); +extern void USB_ClrStallEP (DWORD EPNum); +extern DWORD USB_ReadEP (DWORD EPNum, BYTE *pData); +extern DWORD USB_WriteEP (DWORD EPNum, BYTE *pData, DWORD cnt); +extern BOOL USB_DMA_Setup (DWORD EPNum, USB_DMA_DESCRIPTOR *pDD); +extern void USB_DMA_Enable (DWORD EPNum); +extern void USB_DMA_Disable(DWORD EPNum); +extern DWORD USB_DMA_Status (DWORD EPNum); +extern DWORD USB_DMA_BufAdr (DWORD EPNum); +extern DWORD USB_DMA_BufCnt (DWORD EPNum); +extern DWORD USB_GetFrame (void); +extern void USB_ISR (void) __irq; + + +#endif /* __USBHW_H__ */ diff --git a/plugins/usb/USBqemu/usb-mic/usbreg.h b/plugins/usb/USBqemu/usb-mic/usbreg.h new file mode 100644 index 0000000000..6dd2ff8b3c --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbreg.h @@ -0,0 +1,195 @@ +/***********************************************************************/ +/* This file is part of the uVision/ARM development tools */ +/* Copyright KEIL ELEKTRONIK GmbH 2002-2006 */ +/***********************************************************************/ +/* */ +/* USBREG.H: Header file for Philips LPC214X USB */ +/* */ +/***********************************************************************/ + +#ifndef __USBREG_H +#define __USBREG_H + + +#define SCB_BASE_ADDR 0xE01FC000 /* System Control Block */ + +/* PLL48 Registers */ +#define PLL48CON (*(volatile unsigned int*)(SCB_BASE_ADDR + 0xA0)) +#define PLL48CFG (*(volatile unsigned int*)(SCB_BASE_ADDR + 0xA4)) +#define PLL48STAT (*(volatile unsigned int*)(SCB_BASE_ADDR + 0xA8)) +#define PLL48FEED (*(volatile unsigned int*)(SCB_BASE_ADDR + 0xAC)) + +/* PLL48 Bit Definitions */ +#define PLLCON_PLLE (1<<0) /* PLL Enable */ +#define PLLCON_PLLC (1<<1) /* PLL Connect */ +#define PLLCFG_MSEL (0x1F<<0) /* PLL Multiplier */ +#define PLLCFG_PSEL (0x03<<5) /* PLL Divider */ +#define PLLSTAT_PLOCK (1<<10) /* PLL Lock Status */ + + +#define USB_BASE_ADDR 0xE0090000 /* USB Base Address */ + +/* Device Interrupt Registers */ +#define DEV_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0x00)) +#define DEV_INT_EN (*(volatile unsigned int*)(USB_BASE_ADDR + 0x04)) +#define DEV_INT_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0x08)) +#define DEV_INT_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0x0C)) +#define DEV_INT_PRIO (*(volatile unsigned int*)(USB_BASE_ADDR + 0x2C)) + +/* Endpoint Interrupt Registers */ +#define EP_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0x30)) +#define EP_INT_EN (*(volatile unsigned int*)(USB_BASE_ADDR + 0x34)) +#define EP_INT_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0x38)) +#define EP_INT_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0x3C)) +#define EP_INT_PRIO (*(volatile unsigned int*)(USB_BASE_ADDR + 0x40)) + +/* Endpoint Realization Registers */ +#define REALIZE_EP (*(volatile unsigned int*)(USB_BASE_ADDR + 0x44)) +#define EP_INDEX (*(volatile unsigned int*)(USB_BASE_ADDR + 0x48)) +#define MAXPACKET_SIZE (*(volatile unsigned int*)(USB_BASE_ADDR + 0x4C)) + +/* Command Reagisters */ +#define CMD_CODE (*(volatile unsigned int*)(USB_BASE_ADDR + 0x10)) +#define CMD_DATA (*(volatile unsigned int*)(USB_BASE_ADDR + 0x14)) + +/* Data Transfer Registers */ +#define RX_DATA (*(volatile unsigned int*)(USB_BASE_ADDR + 0x18)) +#define TX_DATA (*(volatile unsigned int*)(USB_BASE_ADDR + 0x1C)) +#define RX_PLENGTH (*(volatile unsigned int*)(USB_BASE_ADDR + 0x20)) +#define TX_PLENGTH (*(volatile unsigned int*)(USB_BASE_ADDR + 0x24)) +#define USB_CTRL (*(volatile unsigned int*)(USB_BASE_ADDR + 0x28)) + +/* System Register */ +#define DC_REVISION (*(volatile unsigned int*)(USB_BASE_ADDR + 0x7C)) + +/* DMA Registers */ +#define DMA_REQ_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0x50)) +#define DMA_REQ_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0x54)) +#define DMA_REQ_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0x58)) +#define UDCA_HEAD (*(volatile unsigned int*)(USB_BASE_ADDR + 0x80)) +#define EP_DMA_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0x84)) +#define EP_DMA_EN (*(volatile unsigned int*)(USB_BASE_ADDR + 0x88)) +#define EP_DMA_DIS (*(volatile unsigned int*)(USB_BASE_ADDR + 0x8C)) +#define DMA_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0x90)) +#define DMA_INT_EN (*(volatile unsigned int*)(USB_BASE_ADDR + 0x94)) +#define EOT_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0xA0)) +#define EOT_INT_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0xA4)) +#define EOT_INT_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0xA8)) +#define NDD_REQ_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0xAC)) +#define NDD_REQ_INT_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0xB0)) +#define NDD_REQ_INT_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0xB4)) +#define SYS_ERR_INT_STAT (*(volatile unsigned int*)(USB_BASE_ADDR + 0xB8)) +#define SYS_ERR_INT_CLR (*(volatile unsigned int*)(USB_BASE_ADDR + 0xBC)) +#define SYS_ERR_INT_SET (*(volatile unsigned int*)(USB_BASE_ADDR + 0xC0)) +#define MODULE_ID (*(volatile unsigned int*)(USB_BASE_ADDR + 0xFC)) + + +/* Device Interrupt Bit Definitions */ +#define FRAME_INT 0x00000001 +#define EP_FAST_INT 0x00000002 +#define EP_SLOW_INT 0x00000004 +#define DEV_STAT_INT 0x00000008 +#define CCEMTY_INT 0x00000010 +#define CDFULL_INT 0x00000020 +#define RxENDPKT_INT 0x00000040 +#define TxENDPKT_INT 0x00000080 +#define EP_RLZED_INT 0x00000100 +#define ERR_INT 0x00000200 + +/* Rx & Tx Packet Length Definitions */ +#define PKT_LNGTH_MASK 0x000003FF +#define PKT_DV 0x00000400 +#define PKT_RDY 0x00000800 + +/* USB Control Definitions */ +#define CTRL_RD_EN 0x00000001 +#define CTRL_WR_EN 0x00000002 + +/* Command Codes */ +#define CMD_SET_ADDR 0x00D00500 +#define CMD_CFG_DEV 0x00D80500 +#define CMD_SET_MODE 0x00F30500 +#define CMD_RD_FRAME 0x00F50500 +#define DAT_RD_FRAME 0x00F50200 +#define CMD_RD_TEST 0x00FD0500 +#define DAT_RD_TEST 0x00FD0200 +#define CMD_SET_DEV_STAT 0x00FE0500 +#define CMD_GET_DEV_STAT 0x00FE0500 +#define DAT_GET_DEV_STAT 0x00FE0200 +#define CMD_GET_ERR_CODE 0x00FF0500 +#define DAT_GET_ERR_CODE 0x00FF0200 +#define CMD_RD_ERR_STAT 0x00FB0500 +#define DAT_RD_ERR_STAT 0x00FB0200 +#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) +#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) +#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) +#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) +#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) +#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) +#define CMD_CLR_BUF 0x00F20500 +#define DAT_CLR_BUF 0x00F20200 +#define CMD_VALID_BUF 0x00FA0500 + +/* Device Address Register Definitions */ +#define DEV_ADDR_MASK 0x7F +#define DEV_EN 0x80 + +/* Device Configure Register Definitions */ +#define CONF_DVICE 0x01 + +/* Device Mode Register Definitions */ +#define AP_CLK 0x01 +#define INAK_CI 0x02 +#define INAK_CO 0x04 +#define INAK_II 0x08 +#define INAK_IO 0x10 +#define INAK_BI 0x20 +#define INAK_BO 0x40 + +/* Device Status Register Definitions */ +#define DEV_CON 0x01 +#define DEV_CON_CH 0x02 +#define DEV_SUS 0x04 +#define DEV_SUS_CH 0x08 +#define DEV_RST 0x10 + +/* Error Code Register Definitions */ +#define ERR_EC_MASK 0x0F +#define ERR_EA 0x10 + +/* Error Status Register Definitions */ +#define ERR_PID 0x01 +#define ERR_UEPKT 0x02 +#define ERR_DCRC 0x04 +#define ERR_TIMOUT 0x08 +#define ERR_EOP 0x10 +#define ERR_B_OVRN 0x20 +#define ERR_BTSTF 0x40 +#define ERR_TGL 0x80 + +/* Endpoint Select Register Definitions */ +#define EP_SEL_F 0x01 +#define EP_SEL_ST 0x02 +#define EP_SEL_STP 0x04 +#define EP_SEL_PO 0x08 +#define EP_SEL_EPN 0x10 +#define EP_SEL_B_1_FULL 0x20 +#define EP_SEL_B_2_FULL 0x40 + +/* Endpoint Status Register Definitions */ +#define EP_STAT_ST 0x01 +#define EP_STAT_DA 0x20 +#define EP_STAT_RF_MO 0x40 +#define EP_STAT_CND_ST 0x80 + +/* Clear Buffer Register Definitions */ +#define CLR_BUF_PO 0x01 + + +/* DMA Interrupt Bit Definitions */ +#define EOT_INT 0x01 +#define NDD_REQ_INT 0x02 +#define SYS_ERR_INT 0x04 + + +#endif /* __USBREG_H */ diff --git a/plugins/usb/USBqemu/usb-mic/usbuser.h b/plugins/usb/USBqemu/usb-mic/usbuser.h new file mode 100644 index 0000000000..2307625934 --- /dev/null +++ b/plugins/usb/USBqemu/usb-mic/usbuser.h @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------- + * U S B - K e r n e l + *---------------------------------------------------------------------------- + * Name: USBUSER.H + * Purpose: USB Custom User Definitions + * Version: V1.10 + *---------------------------------------------------------------------------- + * This software is supplied "AS IS" without any warranties, express, + * implied or statutory, including but not limited to the implied + * warranties of fitness for purpose, satisfactory quality and + * noninfringement. Keil extends you a royalty-free right to reproduce + * and distribute executable files created using this software for use + * on Philips LPC2xxx microcontroller devices only. Nothing else gives + * you the right to use this software. + * + * Copyright (c) 2005-2006 Keil Software. + *---------------------------------------------------------------------------*/ + +#ifndef __USBUSER_H__ +#define __USBUSER_H__ + + +/* USB Device Events Callback Functions */ +extern void USB_Power_Event (BOOL power); +extern void USB_Reset_Event (void); +extern void USB_Suspend_Event (void); +extern void USB_Resume_Event (void); +extern void USB_WakeUp_Event (void); +extern void USB_SOF_Event (void); +extern void USB_Error_Event (DWORD error); + +/* USB Endpoint Callback Events */ +#define USB_EVT_SETUP 1 /* Setup Packet */ +#define USB_EVT_OUT 2 /* OUT Packet */ +#define USB_EVT_IN 3 /* IN Packet */ +#define USB_EVT_OUT_NAK 4 /* OUT Packet - Not Acknowledged */ +#define USB_EVT_IN_NAK 5 /* IN Packet - Not Acknowledged */ +#define USB_EVT_OUT_STALL 6 /* OUT Packet - Stalled */ +#define USB_EVT_IN_STALL 7 /* IN Packet - Stalled */ +#define USB_EVT_OUT_DMA_EOT 8 /* DMA OUT EP - End of Transfer */ +#define USB_EVT_IN_DMA_EOT 9 /* DMA IN EP - End of Transfer */ +#define USB_EVT_OUT_DMA_NDR 10 /* DMA OUT EP - New Descriptor Request */ +#define USB_EVT_IN_DMA_NDR 11 /* DMA IN EP - New Descriptor Request */ +#define USB_EVT_OUT_DMA_ERR 12 /* DMA OUT EP - Error */ +#define USB_EVT_IN_DMA_ERR 13 /* DMA IN EP - Error */ + +/* USB Endpoint Events Callback Pointers */ +extern void (* const USB_P_EP[16])(DWORD event); + +/* USB Endpoint Events Callback Functions */ +extern void USB_EndPoint0 (DWORD event); +extern void USB_EndPoint1 (DWORD event); +extern void USB_EndPoint2 (DWORD event); +extern void USB_EndPoint3 (DWORD event); +extern void USB_EndPoint4 (DWORD event); +extern void USB_EndPoint5 (DWORD event); +extern void USB_EndPoint6 (DWORD event); +extern void USB_EndPoint7 (DWORD event); +extern void USB_EndPoint8 (DWORD event); +extern void USB_EndPoint9 (DWORD event); +extern void USB_EndPoint10 (DWORD event); +extern void USB_EndPoint11 (DWORD event); +extern void USB_EndPoint12 (DWORD event); +extern void USB_EndPoint13 (DWORD event); +extern void USB_EndPoint14 (DWORD event); +extern void USB_EndPoint15 (DWORD event); + +/* USB Core Events Callback Functions */ +extern void USB_Configure_Event (void); +extern void USB_Interface_Event (void); +extern void USB_Feature_Event (void); + + +#endif /* __USBUSER_H__ */ diff --git a/plugins/usb/build.sh b/plugins/usb/build.sh new file mode 100644 index 0000000000..a87cf0bfef --- /dev/null +++ b/plugins/usb/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo ----------------------- +echo Building USB plugins... +echo ----------------------- + +curdir=`pwd` + +cd ${curdir}/USBnull +sh build.sh $@ + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/test.bat b/test.bat new file mode 100644 index 0000000000..d830449dda --- /dev/null +++ b/test.bat @@ -0,0 +1,3 @@ +set PATH=./testtools;%PATH% +bash --noprofile --norc --login -i test.sh +pause \ No newline at end of file diff --git a/test.cfg b/test.cfg new file mode 100644 index 0000000000..eae4c145a5 --- /dev/null +++ b/test.cfg @@ -0,0 +1,2 @@ +gameid -frame 100 -numimages 15 -loadini type1.ini +somegame2 -frame 100 -numimages 10 -loadini type2.ini diff --git a/test.sh b/test.sh new file mode 100644 index 0000000000..e402a85ee5 --- /dev/null +++ b/test.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# main settings +runexe='./pcsx2.exe' + +results=results`date +'%Y%m%d%H%M'` + +echo "Creating results directory ${results}/..." +mkdir $results + +exec 0

qdRT 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%0A!zhP{X5B*&SK!H)ACjgC3kB|YhQ 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 literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.lib b/plugins/dev9/dev9ghzdrk/Win32/wpcap_32/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..3c08265db78e8cbb17ae83e70a6fffcd459b8cc4 GIT binary patch literal 17658 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 o{khiWdHyG literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.dll b/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.dll new file mode 100644 index 0000000000000000000000000000000000000000..102954e96abc488efff5373e45f66a9c7673c4eb GIT binary patch literal 80384 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 literal 0 HcmV?d00001 diff --git a/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.lib b/plugins/dev9/dev9ghzdrk/Win32/wpcap_64/Packet.lib new file mode 100644 index 0000000000000000000000000000000000000000..8529e0f0a7f75a55372eec44ae50c2e639b111a4 GIT binary patch literal 8286 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